From bf26f3a9c120c08f2ef18c0b6befcb61103bc4e0 Mon Sep 17 00:00:00 2001 From: Teddy Wang Date: Mon, 28 Jul 2025 16:36:19 +0800 Subject: [PATCH] Add SMI drm graphic driver Signed-off-by: Teddy Wang --- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/smidrm/Kconfig | 16 + drivers/gpu/drm/smidrm/Makefile | 48 + drivers/gpu/drm/smidrm/ddk750/ddk750_2d.c | 2944 ++++++++++++ drivers/gpu/drm/smidrm/ddk750/ddk750_2d.h | 480 ++ drivers/gpu/drm/smidrm/ddk750/ddk750_chip.c | 234 + drivers/gpu/drm/smidrm/ddk750/ddk750_chip.h | 194 + drivers/gpu/drm/smidrm/ddk750/ddk750_clock.c | 564 +++ drivers/gpu/drm/smidrm/ddk750/ddk750_clock.h | 178 + drivers/gpu/drm/smidrm/ddk750/ddk750_cursor.c | 104 + drivers/gpu/drm/smidrm/ddk750/ddk750_cursor.h | 48 + drivers/gpu/drm/smidrm/ddk750/ddk750_defs.h | 83 + .../gpu/drm/smidrm/ddk750/ddk750_display.c | 1702 +++++++ .../gpu/drm/smidrm/ddk750/ddk750_display.h | 213 + drivers/gpu/drm/smidrm/ddk750/ddk750_edid.c | 2240 ++++++++++ drivers/gpu/drm/smidrm/ddk750/ddk750_edid.h | 762 ++++ .../gpu/drm/smidrm/ddk750/ddk750_hardware.h | 191 + drivers/gpu/drm/smidrm/ddk750/ddk750_help.c | 18 + drivers/gpu/drm/smidrm/ddk750/ddk750_help.h | 33 + drivers/gpu/drm/smidrm/ddk750/ddk750_helper.c | 35 + drivers/gpu/drm/smidrm/ddk750/ddk750_helper.h | 18 + drivers/gpu/drm/smidrm/ddk750/ddk750_hwi2c.c | 489 ++ drivers/gpu/drm/smidrm/ddk750/ddk750_hwi2c.h | 76 + drivers/gpu/drm/smidrm/ddk750/ddk750_mode.c | 1189 +++++ drivers/gpu/drm/smidrm/ddk750/ddk750_mode.h | 450 ++ drivers/gpu/drm/smidrm/ddk750/ddk750_power.c | 495 ++ drivers/gpu/drm/smidrm/ddk750/ddk750_power.h | 121 + drivers/gpu/drm/smidrm/ddk750/ddk750_regdc.h | 960 ++++ drivers/gpu/drm/smidrm/ddk750/ddk750_regde.h | 359 ++ .../gpu/drm/smidrm/ddk750/ddk750_reggpio.h | 239 + drivers/gpu/drm/smidrm/ddk750/ddk750_regi2c.h | 69 + drivers/gpu/drm/smidrm/ddk750/ddk750_regsc.h | 900 ++++ .../gpu/drm/smidrm/ddk750/ddk750_sii9022.c | 91 + .../gpu/drm/smidrm/ddk750/ddk750_sii9022.h | 7 + drivers/gpu/drm/smidrm/ddk750/ddk750_sw2d.h | 200 + drivers/gpu/drm/smidrm/ddk750/ddk750_swi2c.c | 822 ++++ drivers/gpu/drm/smidrm/ddk750/ddk750_swi2c.h | 111 + drivers/gpu/drm/smidrm/ddk750/ddkdebug.h | 141 + .../gpu/drm/smidrm/ddk750/siHdmiTx_902x_TPI.c | 3522 +++++++++++++++ .../gpu/drm/smidrm/ddk750/siHdmiTx_902x_TPI.h | 1131 +++++ drivers/gpu/drm/smidrm/ddk750/vdif.h | 63 + drivers/gpu/drm/smidrm/ddk768/ddk768.h | 23 + drivers/gpu/drm/smidrm/ddk768/ddk768_2d.c | 1198 +++++ drivers/gpu/drm/smidrm/ddk768/ddk768_2d.h | 492 ++ drivers/gpu/drm/smidrm/ddk768/ddk768_chip.c | 220 + drivers/gpu/drm/smidrm/ddk768/ddk768_chip.h | 90 + drivers/gpu/drm/smidrm/ddk768/ddk768_clock.c | 171 + drivers/gpu/drm/smidrm/ddk768/ddk768_clock.h | 66 + drivers/gpu/drm/smidrm/ddk768/ddk768_cursor.c | 100 + drivers/gpu/drm/smidrm/ddk768/ddk768_cursor.h | 54 + .../gpu/drm/smidrm/ddk768/ddk768_display.c | 850 ++++ .../gpu/drm/smidrm/ddk768/ddk768_display.h | 216 + drivers/gpu/drm/smidrm/ddk768/ddk768_edid.c | 2145 +++++++++ drivers/gpu/drm/smidrm/ddk768/ddk768_edid.h | 793 ++++ drivers/gpu/drm/smidrm/ddk768/ddk768_ep952.c | 911 ++++ drivers/gpu/drm/smidrm/ddk768/ddk768_ep952.h | 62 + drivers/gpu/drm/smidrm/ddk768/ddk768_hdmi.c | 1654 +++++++ drivers/gpu/drm/smidrm/ddk768/ddk768_hdmi.h | 490 ++ drivers/gpu/drm/smidrm/ddk768/ddk768_help.c | 12 + drivers/gpu/drm/smidrm/ddk768/ddk768_help.h | 36 + drivers/gpu/drm/smidrm/ddk768/ddk768_helper.c | 84 + drivers/gpu/drm/smidrm/ddk768/ddk768_helper.h | 44 + drivers/gpu/drm/smidrm/ddk768/ddk768_hwi2c.c | 418 ++ drivers/gpu/drm/smidrm/ddk768/ddk768_hwi2c.h | 70 + drivers/gpu/drm/smidrm/ddk768/ddk768_iis.c | 274 ++ drivers/gpu/drm/smidrm/ddk768/ddk768_iis.h | 109 + drivers/gpu/drm/smidrm/ddk768/ddk768_intr.c | 62 + drivers/gpu/drm/smidrm/ddk768/ddk768_intr.h | 116 + drivers/gpu/drm/smidrm/ddk768/ddk768_mode.c | 1148 +++++ drivers/gpu/drm/smidrm/ddk768/ddk768_mode.h | 268 ++ drivers/gpu/drm/smidrm/ddk768/ddk768_power.c | 269 ++ drivers/gpu/drm/smidrm/ddk768/ddk768_power.h | 62 + drivers/gpu/drm/smidrm/ddk768/ddk768_pwm.c | 287 ++ drivers/gpu/drm/smidrm/ddk768/ddk768_pwm.h | 117 + drivers/gpu/drm/smidrm/ddk768/ddk768_reg.h | 2813 ++++++++++++ drivers/gpu/drm/smidrm/ddk768/ddk768_swi2c.c | 714 +++ drivers/gpu/drm/smidrm/ddk768/ddk768_swi2c.h | 62 + drivers/gpu/drm/smidrm/ddk768/ddk768_timer.c | 343 ++ drivers/gpu/drm/smidrm/ddk768/ddk768_timer.h | 150 + drivers/gpu/drm/smidrm/ddk768/ddk768_video.c | 1153 +++++ drivers/gpu/drm/smidrm/ddk768/ddk768_video.h | 606 +++ drivers/gpu/drm/smidrm/ddk768/ddkdebug.c | 227 + drivers/gpu/drm/smidrm/ddk768/ddkdebug.h | 141 + drivers/gpu/drm/smidrm/ddk768/ep952_if.h | 147 + drivers/gpu/drm/smidrm/ddk768/ep952api.h | 113 + .../gpu/drm/smidrm/ddk768/ep952controller.h | 82 + drivers/gpu/drm/smidrm/ddk768/ep952regdef.h | 159 + .../gpu/drm/smidrm/ddk768/ep952settingsdata.h | 101 + drivers/gpu/drm/smidrm/ddk768/hdmiregs.h | 945 ++++ drivers/gpu/drm/smidrm/ddk768/l3.c | 65 + drivers/gpu/drm/smidrm/ddk768/l3.h | 22 + drivers/gpu/drm/smidrm/ddk768/uda1345.c | 368 ++ drivers/gpu/drm/smidrm/ddk768/uda1345.h | 131 + drivers/gpu/drm/smidrm/ddk768/vdif.h | 63 + drivers/gpu/drm/smidrm/ddk768/wm8978.c | 231 + drivers/gpu/drm/smidrm/ddk768/wm8978.h | 23 + drivers/gpu/drm/smidrm/ddk770/ddk770_chip.c | 192 + drivers/gpu/drm/smidrm/ddk770/ddk770_chip.h | 85 + drivers/gpu/drm/smidrm/ddk770/ddk770_clock.c | 589 +++ drivers/gpu/drm/smidrm/ddk770/ddk770_clock.h | 84 + drivers/gpu/drm/smidrm/ddk770/ddk770_cursor.c | 185 + drivers/gpu/drm/smidrm/ddk770/ddk770_cursor.h | 73 + .../gpu/drm/smidrm/ddk770/ddk770_ddkdebug.c | 227 + .../gpu/drm/smidrm/ddk770/ddk770_ddkdebug.h | 141 + .../gpu/drm/smidrm/ddk770/ddk770_display.c | 782 ++++ .../gpu/drm/smidrm/ddk770/ddk770_display.h | 191 + drivers/gpu/drm/smidrm/ddk770/ddk770_dp.c | 1686 +++++++ drivers/gpu/drm/smidrm/ddk770/ddk770_dp.h | 432 ++ drivers/gpu/drm/smidrm/ddk770/ddk770_edid.c | 1959 ++++++++ drivers/gpu/drm/smidrm/ddk770/ddk770_edid.h | 657 +++ drivers/gpu/drm/smidrm/ddk770/ddk770_gpio.c | 89 + drivers/gpu/drm/smidrm/ddk770/ddk770_gpio.h | 11 + .../gpu/drm/smidrm/ddk770/ddk770_hardware.c | 275 ++ .../gpu/drm/smidrm/ddk770/ddk770_hardware.h | 205 + drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi.c | 1349 ++++++ drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi.h | 101 + .../gpu/drm/smidrm/ddk770/ddk770_hdmi_audio.c | 391 ++ .../gpu/drm/smidrm/ddk770/ddk770_hdmi_audio.h | 22 + .../gpu/drm/smidrm/ddk770/ddk770_hdmi_ddc.c | 382 ++ .../gpu/drm/smidrm/ddk770/ddk770_hdmi_ddc.h | 60 + .../gpu/drm/smidrm/ddk770/ddk770_hdmi_phy.c | 1148 +++++ .../gpu/drm/smidrm/ddk770/ddk770_hdmi_phy.h | 148 + drivers/gpu/drm/smidrm/ddk770/ddk770_help.c | 44 + drivers/gpu/drm/smidrm/ddk770/ddk770_help.h | 44 + drivers/gpu/drm/smidrm/ddk770/ddk770_helper.c | 85 + drivers/gpu/drm/smidrm/ddk770/ddk770_helper.h | 44 + drivers/gpu/drm/smidrm/ddk770/ddk770_hwi2c.c | 354 ++ drivers/gpu/drm/smidrm/ddk770/ddk770_hwi2c.h | 143 + drivers/gpu/drm/smidrm/ddk770/ddk770_iis.c | 283 ++ drivers/gpu/drm/smidrm/ddk770/ddk770_iis.h | 102 + drivers/gpu/drm/smidrm/ddk770/ddk770_intr.c | 51 + drivers/gpu/drm/smidrm/ddk770/ddk770_intr.h | 54 + drivers/gpu/drm/smidrm/ddk770/ddk770_linux.c | 544 +++ drivers/gpu/drm/smidrm/ddk770/ddk770_mode.c | 1106 +++++ drivers/gpu/drm/smidrm/ddk770/ddk770_mode.h | 392 ++ drivers/gpu/drm/smidrm/ddk770/ddk770_os.c | 41 + drivers/gpu/drm/smidrm/ddk770/ddk770_os.h | 325 ++ drivers/gpu/drm/smidrm/ddk770/ddk770_power.c | 303 ++ drivers/gpu/drm/smidrm/ddk770/ddk770_power.h | 99 + drivers/gpu/drm/smidrm/ddk770/ddk770_pwm.c | 283 ++ drivers/gpu/drm/smidrm/ddk770/ddk770_pwm.h | 119 + drivers/gpu/drm/smidrm/ddk770/ddk770_reg.h | 3971 +++++++++++++++++ drivers/gpu/drm/smidrm/ddk770/ddk770_swi2c.c | 424 ++ drivers/gpu/drm/smidrm/ddk770/ddk770_swi2c.h | 97 + drivers/gpu/drm/smidrm/ddk770/ddk770_timer.c | 300 ++ drivers/gpu/drm/smidrm/ddk770/ddk770_timer.h | 141 + drivers/gpu/drm/smidrm/ddk770/ddk770_video.c | 1098 +++++ drivers/gpu/drm/smidrm/ddk770/ddk770_video.h | 601 +++ drivers/gpu/drm/smidrm/ddk770/ddk770_wm8978.c | 196 + drivers/gpu/drm/smidrm/ddk770/ddk770_wm8978.h | 13 + drivers/gpu/drm/smidrm/hw750.c | 373 ++ drivers/gpu/drm/smidrm/hw750.h | 161 + drivers/gpu/drm/smidrm/hw768.c | 490 ++ drivers/gpu/drm/smidrm/hw768.h | 170 + drivers/gpu/drm/smidrm/hw770.c | 641 +++ drivers/gpu/drm/smidrm/hw770.h | 189 + drivers/gpu/drm/smidrm/hw_com.h | 472 ++ drivers/gpu/drm/smidrm/smi_drv.c | 846 ++++ drivers/gpu/drm/smidrm/smi_drv.h | 559 +++ drivers/gpu/drm/smidrm/smi_fbdev.c | 414 ++ drivers/gpu/drm/smidrm/smi_main.c | 751 ++++ drivers/gpu/drm/smidrm/smi_mode.c | 2241 ++++++++++ drivers/gpu/drm/smidrm/smi_plane.c | 677 +++ drivers/gpu/drm/smidrm/smi_prime.c | 109 + drivers/gpu/drm/smidrm/smi_snd.c | 955 ++++ drivers/gpu/drm/smidrm/smi_snd.h | 81 + drivers/gpu/drm/smidrm/smi_ttm.c | 581 +++ drivers/gpu/drm/smidrm/smi_ver.h | 27 + 169 files changed, 75571 insertions(+) create mode 100644 drivers/gpu/drm/smidrm/Kconfig create mode 100644 drivers/gpu/drm/smidrm/Makefile create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_2d.c create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_2d.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_chip.c create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_chip.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_clock.c create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_clock.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_cursor.c create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_cursor.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_defs.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_display.c create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_display.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_edid.c create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_edid.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_hardware.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_help.c create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_help.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_helper.c create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_helper.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_hwi2c.c create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_hwi2c.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_mode.c create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_mode.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_power.c create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_power.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_regdc.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_regde.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_reggpio.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_regi2c.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_regsc.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_sii9022.c create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_sii9022.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_sw2d.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_swi2c.c create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddk750_swi2c.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/ddkdebug.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/siHdmiTx_902x_TPI.c create mode 100644 drivers/gpu/drm/smidrm/ddk750/siHdmiTx_902x_TPI.h create mode 100644 drivers/gpu/drm/smidrm/ddk750/vdif.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_2d.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_2d.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_chip.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_chip.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_clock.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_clock.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_cursor.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_cursor.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_display.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_display.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_edid.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_edid.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_ep952.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_ep952.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_hdmi.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_hdmi.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_help.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_help.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_helper.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_helper.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_hwi2c.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_hwi2c.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_iis.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_iis.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_intr.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_intr.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_mode.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_mode.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_power.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_power.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_pwm.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_pwm.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_reg.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_swi2c.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_swi2c.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_timer.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_timer.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_video.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddk768_video.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddkdebug.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/ddkdebug.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ep952_if.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ep952api.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ep952controller.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ep952regdef.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/ep952settingsdata.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/hdmiregs.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/l3.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/l3.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/uda1345.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/uda1345.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/vdif.h create mode 100644 drivers/gpu/drm/smidrm/ddk768/wm8978.c create mode 100644 drivers/gpu/drm/smidrm/ddk768/wm8978.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_chip.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_chip.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_clock.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_clock.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_cursor.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_cursor.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_ddkdebug.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_ddkdebug.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_display.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_display.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_dp.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_dp.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_edid.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_edid.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_gpio.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_gpio.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_hardware.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_hardware.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_audio.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_audio.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_ddc.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_ddc.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_phy.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_phy.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_help.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_help.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_helper.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_helper.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_hwi2c.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_hwi2c.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_iis.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_iis.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_intr.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_intr.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_linux.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_mode.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_mode.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_os.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_os.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_power.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_power.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_pwm.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_pwm.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_reg.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_swi2c.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_swi2c.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_timer.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_timer.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_video.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_video.h create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_wm8978.c create mode 100644 drivers/gpu/drm/smidrm/ddk770/ddk770_wm8978.h create mode 100644 drivers/gpu/drm/smidrm/hw750.c create mode 100644 drivers/gpu/drm/smidrm/hw750.h create mode 100644 drivers/gpu/drm/smidrm/hw768.c create mode 100644 drivers/gpu/drm/smidrm/hw768.h create mode 100644 drivers/gpu/drm/smidrm/hw770.c create mode 100644 drivers/gpu/drm/smidrm/hw770.h create mode 100644 drivers/gpu/drm/smidrm/hw_com.h create mode 100644 drivers/gpu/drm/smidrm/smi_drv.c create mode 100644 drivers/gpu/drm/smidrm/smi_drv.h create mode 100644 drivers/gpu/drm/smidrm/smi_fbdev.c create mode 100644 drivers/gpu/drm/smidrm/smi_main.c create mode 100644 drivers/gpu/drm/smidrm/smi_mode.c create mode 100644 drivers/gpu/drm/smidrm/smi_plane.c create mode 100644 drivers/gpu/drm/smidrm/smi_prime.c create mode 100644 drivers/gpu/drm/smidrm/smi_snd.c create mode 100644 drivers/gpu/drm/smidrm/smi_snd.h create mode 100644 drivers/gpu/drm/smidrm/smi_ttm.c create mode 100644 drivers/gpu/drm/smidrm/smi_ver.h diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 1960b2d0c788..3164ea74ca9a 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -267,6 +267,8 @@ source "drivers/gpu/drm/udl/Kconfig" source "drivers/gpu/drm/ast/Kconfig" +source "drivers/gpu/drm/smidrm/Kconfig" + source "drivers/gpu/drm/mgag200/Kconfig" source "drivers/gpu/drm/cirrus/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 31063f242596..0761d1066859 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/ obj-$(CONFIG_DRM_GMA500) += gma500/ obj-$(CONFIG_DRM_UDL) += udl/ obj-$(CONFIG_DRM_AST) += ast/ +obj-$(CONFIG_DRM_SMI) += smidrm/ obj-$(CONFIG_DRM_ARMADA) += armada/ obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc/ obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/ diff --git a/drivers/gpu/drm/smidrm/Kconfig b/drivers/gpu/drm/smidrm/Kconfig new file mode 100644 index 000000000000..7bd2e5ce13be --- /dev/null +++ b/drivers/gpu/drm/smidrm/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only +config DRM_SMI + tristate "SiliconMotion SM750/SM768/SM770 DRM driver" + depends on DRM && PCI && MMU + select DRM_TTM + select DRM_KMS_HELPER + select SND_PCM + select DRM_VRAM_HELPER + help + Say yes for SiliconMotion SM750/SM768/SM770 DRM driver. + + + + + + diff --git a/drivers/gpu/drm/smidrm/Makefile b/drivers/gpu/drm/smidrm/Makefile new file mode 100644 index 000000000000..749259130fc3 --- /dev/null +++ b/drivers/gpu/drm/smidrm/Makefile @@ -0,0 +1,48 @@ +obj-$(CONFIG_DRM_SMI) := smifb.o +smifb-objs :=smi_drv.o smi_fbdev.o smi_main.o smi_mode.o smi_plane.o smi_ttm.o smi_prime.o hw750.o hw768.o hw770.o +smifb-objs += ddk750/ddk750_help.o ddk750/ddk750_chip.o ddk750/ddk750_clock.o ddk750/ddk750_mode.o ddk750/ddk750_power.o ddk750/ddk750_helper.o ddk750/ddk750_display.o ddk750/ddk750_2d.o ddk750/ddk750_edid.o ddk750/ddk750_swi2c.o ddk750/ddk750_hwi2c.o ddk750/ddk750_cursor.o + + + + + +ifeq ($(CONFIG_DRM_SMI_HDMI),y) +EXTRA_CFLAGS += -DUSE_HDMICHIP +smifb-y += ddk750/ddk750_sii9022.o +smifb-y += ddk750/siHdmiTx_902x_TPI.o +endif + +ifeq ($(CONFIG_DRM_SMI_EP952),y) +EXTRA_CFLAGS += -DUSE_EP952 +smifb-y += ddk768/ddk768_ep952.o +endif + + +smifb-objs += ddk768/ddk768_help.o ddk768/ddk768_chip.o ddk768/ddk768_clock.o ddk768/ddk768_mode.o ddk768/ddk768_power.o ddk768/ddk768_helper.o ddk768/ddk768_display.o ddk768/ddk768_2d.o \ +ddk768/ddk768_edid.o ddk768/ddk768_swi2c.o ddk768/ddk768_hwi2c.o ddk768/ddk768_cursor.o ddk768/ddk768_video.o ddk768/ddk768_hdmi.o ddk768/ddk768_pwm.o ddk768/ddk768_timer.o ddk768/ddk768_intr.o + + + +smifb-y += smi_snd.o +smifb-y += ddk768/ddk768_iis.o +smifb-y += ddk768/uda1345.o +smifb-y += ddk768/l3.o +smifb-y += ddk768/wm8978.o +smifb-y += ddk770/ddk770_wm8978.o + +smifb-y += ddk770/ddk770_help.o ddk770/ddk770_ddkdebug.o ddk770/ddk770_helper.o \ +ddk770/ddk770_os.o ddk770/ddk770_hardware.o ddk770/ddk770_clock.o ddk770/ddk770_power.o \ +ddk770/ddk770_cursor.o ddk770/ddk770_intr.o ddk770/ddk770_edid.o \ +ddk770/ddk770_hwi2c.o ddk770/ddk770_pwm.o ddk770/ddk770_gpio.o \ +ddk770/ddk770_chip.o ddk770/ddk770_mode.o ddk770/ddk770_video.o \ +ddk770/ddk770_swi2c.o ddk770/ddk770_hdmi_ddc.o ddk770/ddk770_hdmi_audio.o \ +ddk770/ddk770_timer.o ddk770/ddk770_display.o \ +ddk770/ddk770_iis.o ddk770/ddk770_hdmi_phy.o ddk770/ddk770_hdmi.o ddk770/ddk770_dp.o + +EXTRA_CFLAGS += -DPRIME + +ccflags-y :=-O2 -Iinclude/drm -D_D_SMI -D_D_SMI_D -D__cdecl + +ifeq ($(CC_TYPE),gcc) +ccflags-y += -fno-tree-scev-cprop +endif diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_2d.c b/drivers/gpu/drm/smidrm/ddk750/ddk750_2d.c new file mode 100644 index 000000000000..cb8bb52463a6 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_2d.c @@ -0,0 +1,2944 @@ +#include "ddk750_defs.h" +#include "ddk750_hardware.h" +#include "ddk750_chip.h" +#include "ddk750_power.h" +#include "ddk750_sw2d.h" +#include "ddk750_2d.h" +#include "ddk750_help.h" +#include "ddk750_regde.h" + + + +/* Flag to enable the 192 bytes patch to workaround the 2D errata, where the engine + will draws incorrectly for BITBLT function that involves READ from memory. + Currently, this definition flag is only used for testing. */ +#define ENABLE_192_BYTES_PATCH + +/* Static macro */ +#define BYTE_PER_PIXEL(bpp) (bpp / 8) + +/* + * 2D Engine Initialization. + * This function must be called before other 2D functions. + * Assumption: A specific video mode has been properly set up. + */ +void ddk750_deInit(void) +{ + enable2DEngine(1); + + deReset(); /* Just be sure no left-over operations from other applications */ + + /* Set up 2D registers that won't change for a specific mode. */ + + /* Drawing engine bus and pixel mask, always want to enable. */ + POKE_32(DE_MASKS, 0xFFFFFFFF); + + /* Pixel format, which can be 8, 16 or 32. + Assuming setmode is call before 2D init, then pixel format + is available in reg 0x80000 (Panel Display Control) + */ + POKE_32(DE_STRETCH_FORMAT, + FIELD_SET (0, DE_STRETCH_FORMAT, PATTERN_XY, NORMAL) | + FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_Y, 0) | + FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X, 0) | + FIELD_SET (0, DE_STRETCH_FORMAT, ADDRESSING, XY) | + FIELD_VALUE(0, DE_STRETCH_FORMAT, SOURCE_HEIGHT,3)); + + /* Clipping and transparent are disable after INIT */ + deSetClipping(0, 0, 0, 0, 0); + deSetTransparency(0, 0, 0, 0); +} + +/* + * Reset 2D engine by + * 1) Aborting the current 2D operation. + * 2) Re-enable 2D engine to normal state. + */ +void deReset() +{ + unsigned long sysCtrl; + logical_chip_type_t chipType = ddk750_getChipType(); + + if (chipType == SM750 || chipType == SM718) + { + /* Abort current 2D operation */ + sysCtrl = PEEK_32(SYSTEM_CTRL); + sysCtrl = FIELD_SET(sysCtrl, SYSTEM_CTRL, DE_ABORT, ON); + POKE_32(SYSTEM_CTRL, sysCtrl); + + /* Re-enable 2D engine to normal state */ + sysCtrl = PEEK_32(SYSTEM_CTRL); + sysCtrl = FIELD_SET(sysCtrl, SYSTEM_CTRL, DE_ABORT, OFF); + POKE_32(SYSTEM_CTRL, sysCtrl); + } + else /* For SM750LE and SM750HS series */ + { + /* Abort current 2D operation */ + sysCtrl = PEEK_32(DE_STATE1); + sysCtrl = FIELD_SET(sysCtrl, DE_STATE1, DE_ABORT, ON); + POKE_32(DE_STATE1, sysCtrl); + + /* Re-enable 2D engine to normal state */ + sysCtrl = PEEK_32(DE_STATE1); + sysCtrl = FIELD_SET(sysCtrl, DE_STATE1, DE_ABORT, OFF); + POKE_32(DE_STATE1, sysCtrl); + } +} + +/* + * Wait until 2D engine is not busy. + * All 2D operations are recommand to check 2D engine idle before start. + * + * Return: 0 = return because engine is idle and normal. + * -1 = return because time out (2D engine may have problem). + */ +long deWaitForNotBusy(void) +{ + unsigned long dwVal; + logical_chip_type_t chipType; + unsigned long i = 0x100000; + + chipType = ddk750_getChipType(); + + if (chipType == SM750 || chipType == SM718) + { + while (i--) + { + dwVal = PEEK_32(SYSTEM_CTRL); + if ((FIELD_GET(dwVal, SYSTEM_CTRL, DE_STATUS) == SYSTEM_CTRL_DE_STATUS_IDLE) && + (FIELD_GET(dwVal, SYSTEM_CTRL, DE_FIFO) == SYSTEM_CTRL_DE_FIFO_EMPTY) && + (FIELD_GET(dwVal, SYSTEM_CTRL, CSC_STATUS) == SYSTEM_CTRL_CSC_STATUS_IDLE) && + (FIELD_GET(dwVal, SYSTEM_CTRL, DE_MEM_FIFO) == SYSTEM_CTRL_DE_MEM_FIFO_EMPTY)) + { + return 0; /* Return because engine idle */ + } + } + + return -1; /* Return because time out */ + } + else /* For SM750LE & SM750HS */ + { + while (i--) + { + dwVal = PEEK_32(DE_STATE2); + if ((FIELD_GET(dwVal, DE_STATE2, DE_STATUS) == DE_STATE2_DE_STATUS_IDLE) && + (FIELD_GET(dwVal, DE_STATE2, DE_FIFO) == DE_STATE2_DE_FIFO_EMPTY) && + (FIELD_GET(dwVal, DE_STATE2, DE_MEM_FIFO) == DE_STATE2_DE_MEM_FIFO_EMPTY)) + { + return 0; /* Return because engine idle */ + } + } + return -1; /* Return because of timeout */ + } +} + +#if 0 /* Cheok_2013_0118: Delete this funciton since no other functions are calling it. */ +/* deWaitIdle() function. + * + * This function is same as deWaitForNotBusy(), except application can + * input the maximum number of times that this function will check + * the idle register. + * + * Its usage is mainly for debugging purpose. + * + * Wait until 2D engine is not busy. + * All 2D operations are recommand to check 2D engine idle before start. + * + * Return: 0 = return because engine is idle and normal. + * -1 = return because time out (2D engine may have problem). + */ +long deWaitIdle(unsigned long i) +{ + unsigned long dwVal; + + if (ddk750_getChipType() == SM750LE) + { +#if 0 + while (i--) + { + dwVal = PEEK_32(DE_CONTROL); + if (FIELD_GET(dwVal, DE_CONTROL, STATUS) == DE_CONTROL_STATUS_STOP) + return 0; + } + return -1; +#else + while (i--) + { + dwVal = PEEK_32(DE_STATE2); + if ((FIELD_GET(dwVal, DE_STATE2, DE_STATUS) == DE_STATE2_DE_STATUS_IDLE) && + (FIELD_GET(dwVal, DE_STATE2, DE_FIFO) == DE_STATE2_DE_FIFO_EMPTY) && + (FIELD_GET(dwVal, DE_STATE2, DE_MEM_FIFO) == DE_STATE2_DE_MEM_FIFO_EMPTY)) + { + return 0; /* Return because engine idle */ + } + } + + return -1; /* Return because time out */ +#endif + } + + while (i--) + { + dwVal = PEEK_32(SYSTEM_CTRL); + if ((FIELD_GET(dwVal, SYSTEM_CTRL, DE_STATUS) == SYSTEM_CTRL_DE_STATUS_IDLE) && + (FIELD_GET(dwVal, SYSTEM_CTRL, DE_FIFO) == SYSTEM_CTRL_DE_FIFO_EMPTY) && + (FIELD_GET(dwVal, SYSTEM_CTRL, CSC_STATUS) == SYSTEM_CTRL_CSC_STATUS_IDLE) && + (FIELD_GET(dwVal, SYSTEM_CTRL, DE_MEM_FIFO) == SYSTEM_CTRL_DE_MEM_FIFO_EMPTY)) + { + return 0; /* Return because engine idle */ + } + } + + return -1; /* Return because time out */ +} +#endif + +/* + * This function enable/disable clipping area for the 2d engine. + * Note that the clipping area is always rectangular. + * + */ +long deSetClipping( +unsigned long enable, /* 0 = disable clipping, 1 = enable clipping */ +unsigned long x1, /* x1, y1 is the upper left corner of the clipping area */ +unsigned long y1, /* Note that the region includes x1 and y1 */ +unsigned long x2, /* x2, y2 is the lower right corner of the clippiing area */ +unsigned long y2) /* Note that the region will not include x2 and y2 */ +{ + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + /* Upper left corner and enable/disable bit + Note: This module defautls to clip outside region. + "Clip inside" is not a useful feature since nothing gets drawn. + */ + POKE_32(DE_CLIP_TL, + FIELD_VALUE(0, DE_CLIP_TL, TOP, y1) | + ((enable)? + FIELD_SET(0, DE_CLIP_TL, STATUS, ENABLE) + : FIELD_SET(0, DE_CLIP_TL, STATUS, DISABLE))| + FIELD_SET (0, DE_CLIP_TL, INHIBIT,OUTSIDE) | + FIELD_VALUE(0, DE_CLIP_TL, LEFT, x1)); + + /* Lower right corner */ + POKE_32(DE_CLIP_BR, + FIELD_VALUE(0, DE_CLIP_BR, BOTTOM,y2) | + FIELD_VALUE(0, DE_CLIP_BR, RIGHT, x2)); + + return 0; +} + +/* + * Function description: + * When transparency is enable, the blt engine compares each pixel value + * (either source or destination) with DE_COLOR_COMPARE register. + * If match, the destination pixel will NOT be updated. + * If not match, the destination pixel will be updated. + */ +long deSetTransparency( +unsigned long enable, /* 0 = disable, 1 = enable transparency feature */ +unsigned long tSelect, /* 0 = compare source, 1 = compare destination */ +unsigned long tMatch, /* 0 = Opaque mode, 1 = transparent mode */ +unsigned long ulColor) /* Color to compare. */ +{ + unsigned long de_ctrl; + + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + /* Set mask */ + if (enable) + { + POKE_32(DE_COLOR_COMPARE_MASK, 0x00ffffff); + + /* Set compare color */ + POKE_32(DE_COLOR_COMPARE, ulColor); + } + else + { + POKE_32(DE_COLOR_COMPARE_MASK, 0x0); + POKE_32(DE_COLOR_COMPARE, 0x0); + } + + /* Set up transparency control, without affecting other bits + Note: There are two operatiing modes: Transparent and Opague. + We only use transparent mode because Opaque mode may have bug. + */ + de_ctrl = PEEK_32(DE_CONTROL) + & FIELD_CLEAR(DE_CONTROL, TRANSPARENCY) + & FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_MATCH) + & FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_SELECT); + + /* For DE_CONTROL_TRANSPARENCY_MATCH bit, always set it + to TRANSPARENT mode, OPAQUE mode don't seem working. + */ + de_ctrl |= + ((enable)? + FIELD_SET(0, DE_CONTROL, TRANSPARENCY, ENABLE) + : FIELD_SET(0, DE_CONTROL, TRANSPARENCY, DISABLE)) | + ((tMatch)? + FIELD_SET(0, DE_CONTROL, TRANSPARENCY_MATCH, TRANSPARENT) + : FIELD_SET(0, DE_CONTROL, TRANSPARENCY_MATCH, OPAQUE)) | + ((tSelect)? + FIELD_SET(0, DE_CONTROL, TRANSPARENCY_SELECT, DESTINATION) + : FIELD_SET(0, DE_CONTROL, TRANSPARENCY_SELECT, SOURCE)); + + POKE_32(DE_CONTROL, de_ctrl); + + return 0; +} + +/* + * This function gets the transparency status from DE_CONTROL register. + * It returns a double word with the transparent fields properly set, + * while other fields are 0. + */ +static unsigned long deGetTransparency(void) +{ + unsigned long de_ctrl; + + de_ctrl = PEEK_32(DE_CONTROL); + + de_ctrl &= + FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) | + FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT)| + FIELD_MASK(DE_CONTROL_TRANSPARENCY); + + return de_ctrl; +} + +/* + * This function sets the pixel format that will apply to the 2D Engine. + */ +static void deSetPixelFormat( + unsigned long bpp +) +{ + unsigned long de_format; + + de_format = PEEK_32(DE_STRETCH_FORMAT); + + switch (bpp) + { + case 8: + de_format = FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 8); + break; + default: + case 16: + de_format = FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 16); + break; + case 32: + de_format = FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 32); + break; + } + + POKE_32(DE_STRETCH_FORMAT, de_format); +} + +/* + * This function uses 2D engine to fill a rectangular area with a specific color. + * The filled area includes the starting points. + */ +long deRectFill( /*resolution_t resolution, point_t p0, point_t p1, unsigned long color, unsigned long rop2)*/ +unsigned long dBase, /* Base address of destination surface counted from beginning of video frame buffer */ +unsigned long dPitch, /* Pitch value of destination surface in BYTES */ +unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ +unsigned long x, +unsigned long y, /* Upper left corner (X, Y) of rectangle in pixel value */ +unsigned long width, +unsigned long height, /* width and height of rectange in pixel value */ +unsigned long color, /* Color to be filled */ +unsigned long rop2) /* ROP value */ +{ + unsigned long de_ctrl, bytePerPixel; + + bytePerPixel = bpp/8; + + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, (dPitch/bytePerPixel))); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (dPitch/bytePerPixel))); + + POKE_32(DE_FOREGROUND, color); + + /* Set the pixel format of the destination */ + deSetPixelFormat(bpp); + +#ifdef ENABLE_192_BYTES_PATCH + /* Workaround for 192 byte requirement when ROP is not COPY */ + if (((rop2 != ROP2_COPY) || (rop2 != ROP2_Sn) || (rop2 != ROP2_Dn) || + (rop2 != ROP2_D) || (rop2 != ROP2_BLACK) || (rop2 != ROP2_WHITE)) && + ((width * bytePerPixel) > 192)) + { + /* Perform the ROP2 operation in chunks of (xWidth * nHeight) */ + unsigned long xChunk = 192 / bytePerPixel; /* chunk width is in pixels */ + +// DDKDEBUGPRINT((DE_LEVEL, "ROP != ROP_COPY, width * bytePerPixel = %x (> 192 bytes)\n", width * bytePerPixel)); + + while (1) + { + deWaitForNotBusy(); + + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, x) | + FIELD_VALUE(0, DE_DESTINATION, Y, y)); + + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, xChunk) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + de_ctrl = + FIELD_SET (0, DE_CONTROL, STATUS, START) | + FIELD_SET (0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + //FIELD_SET (0, DE_CONTROL,LAST_PIXEL, OFF) | + FIELD_SET (0, DE_CONTROL, COMMAND, RECTANGLE_FILL) | + FIELD_SET (0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, rop2); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + + if (xChunk == width) break; + + x += xChunk; + width -= xChunk; + + if (xChunk > width) + { + /* This is the last chunk. */ + xChunk = width; + } + } + } + else +#endif + { + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, x) | + FIELD_VALUE(0, DE_DESTINATION, Y, y)); + + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + de_ctrl = + FIELD_SET (0, DE_CONTROL, STATUS, START) | + FIELD_SET (0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + //FIELD_SET (0, DE_CONTROL,LAST_PIXEL, OFF) | + FIELD_SET (0, DE_CONTROL, COMMAND, RECTANGLE_FILL) | + FIELD_SET (0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, rop2); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + } + + return 0; +} + +/* + * This function uses 2D engine to draw a trapezoid with a specific color. + * The filled area includes the starting points. + */ +long deStartTrapezoidFill( + unsigned long dBase, /* Base address of destination surface counted from beginning of video frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTES */ + unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ + unsigned long x, + unsigned long y, /* Starting (X, Y) coordinate inside the polygon to be filled */ + unsigned long length, /* Length of the line */ + unsigned long color, /* Color to be filled */ + unsigned long rop2 /* ROP value */ +) +{ + unsigned long de_ctrl = + FIELD_SET (0, DE_CONTROL, STATUS, START) | + FIELD_SET (0, DE_CONTROL, QUICK_START, ENABLE) | + FIELD_SET (0, DE_CONTROL, LAST_PIXEL, OFF) | + FIELD_SET (0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + FIELD_SET (0, DE_CONTROL, COMMAND, TRAPEZOID_FILL) | + FIELD_SET (0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, rop2); + + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp))); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp))); + + /* Set the Line Color */ + POKE_32(DE_FOREGROUND, color); + + /* Set the destination coordinate */ + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, x) | + FIELD_VALUE(0, DE_DESTINATION, Y, y)); + + /* Set the pixel format of the destination */ + deSetPixelFormat(bpp); + + /* Set the line length and width */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, length) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, 0)); + + /* Enable the 2D Engine. */ + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + + return 0; +} + +/* + * Function to continue drawing a line using Trapezoid Fill method. + */ +long deNextTrapezoidFill( + unsigned long x, /* Starting X location. */ + unsigned long length /* Line length */ +) +{ + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + /* Set the X destination coordinate */ + POKE_32(DE_DESTINATION, + FIELD_VALUE(PEEK_32(DE_DESTINATION), DE_DESTINATION, X, x)); + + /* Set the line length */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(PEEK_32(DE_DIMENSION), DE_DIMENSION, X, length)); + + return 0; +} + +/* + * Function to stop the Trapezoid Fill drawing. + * This function has to be called to end the Trapezoid Fill drawing. + * Otherwise, the next 2D function might still use this function. + */ +long deStopTrapezoidFill(void) +{ + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + POKE_32(DE_CONTROL, FIELD_SET(PEEK_32(DE_CONTROL), DE_CONTROL, QUICK_START, DISABLE)); + + return 0; +} + +/* + * Video Memory to Video Memory data transfer. + * Note: + * It works whether the Video Memroy is off-screeen or on-screen. + * This function is a one to one transfer without stretching or + * mono expansion. + */ +long ddk750_deVideoMem2VideoMemBlt( +unsigned long sBase, /* Address of source: offset in frame buffer */ +unsigned long sPitch, /* Pitch value of source surface in BYTE */ +unsigned long sx, +unsigned long sy, /* Starting coordinate of source surface */ +unsigned long dBase, /* Address of destination: offset in frame buffer */ +unsigned long dPitch, /* Pitch value of destination surface in BYTE */ +unsigned long bpp, /* Color depth of destination surface */ +unsigned long dx, +unsigned long dy, /* Starting coordinate of destination surface */ +unsigned long width, +unsigned long height, /* width and height of rectangle in pixel value */ +unsigned long rop2) /* ROP value */ +{ + unsigned long nDirection, de_ctrl, bytePerPixel; + long opSign; + + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + nDirection = LEFT_TO_RIGHT; + opSign = 1; /* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */ + bytePerPixel = bpp/8; + de_ctrl = 0; + + /* If source and destination are the same surface, need to check for overlay cases */ + if (sBase == dBase && sPitch == dPitch) + { + /* Determine direction of operation */ + if (sy < dy) + { + /* +----------+ + |S | + | +----------+ + | | | | + | | | | + +---|------+ | + | D| + +----------+ */ + + nDirection = BOTTOM_TO_TOP; + } + else if (sy > dy) + { + /* +----------+ + |D | + | +----------+ + | | | | + | | | | + +---|------+ | + | S| + +----------+ */ + + nDirection = TOP_TO_BOTTOM; + } + else + { + /* sy == dy */ + + if (sx <= dx) + { + /* +------+---+------+ + |S | | D| + | | | | + | | | | + | | | | + +------+---+------+ */ + + nDirection = RIGHT_TO_LEFT; + } + else + { + /* sx > dx */ + + /* +------+---+------+ + |D | | S| + | | | | + | | | | + | | | | + +------+---+------+ */ + + nDirection = LEFT_TO_RIGHT; + } + } + } + + if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) + { + sx += width - 1; + sy += height - 1; + dx += width - 1; + dy += height - 1; + opSign = (-1); + } + + /* Note: + DE_FOREGROUND are DE_BACKGROUND are don't care. + DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency(). + */ + + /* 2D Source Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_SOURCE_BASE, sBase); + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, (sPitch/bytePerPixel))); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (sPitch/bytePerPixel))); + + /* Set the pixel format of the destination */ + deSetPixelFormat(bpp); + +#ifdef ENABLE_192_BYTES_PATCH + /* This bug is fixed in SM718 for 16 and 32 bpp. However, in 8-bpp, the problem still exists. + The Version AA also have this problem on higher clock with 32-bit memory data bus, + therefore, it needs to be enabled here. + In version AA, the problem happens on the following configurations: + 1. M2XCLK = 336MHz w/ 32-bit, MCLK = 112MHz, and color depth set to 32bpp + 2. M2XCLK = 336MHz w/ 32-bit, MCLK = 84MHz, and color depth set to 16bpp or 32bpp. + Somehow, the problem does not appears in 64-bit memory setting. + */ + + /* Workaround for 192 byte requirement when ROP is not COPY */ + if ((rop2 != ROP2_COPY) && ((width * bytePerPixel) > 192)) + { + /* Perform the ROP2 operation in chunks of (xWidth * nHeight) */ + unsigned long xChunk = 192 / bytePerPixel; /* chunk width is in pixels */ + + //DDKDEBUGPRINT((DE_LEVEL, "ROP != ROP_COPY, width * bytePerPixel = %x (> 192 bytes)\n", width * bytePerPixel)); + + while (1) + { + deWaitForNotBusy(); + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, xChunk) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + de_ctrl = + FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) | + ((nDirection == RIGHT_TO_LEFT) ? + FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT) + : FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + + if (xChunk == width) break; + + sx += (opSign * xChunk); + dx += (opSign * xChunk); + width -= xChunk; + + if (xChunk > width) + { + /* This is the last chunk. */ + xChunk = width; + } + } + } + else +#endif + { + deWaitForNotBusy(); + + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + de_ctrl = + FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) | + ((nDirection == RIGHT_TO_LEFT) ? + FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT) + : FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + } + + return 0; +} + +/* + * System Memory to Video Memory data transfer. + * Only works in D, S, ~D, and ~S ROP. + */ +long deSystemMem2VideoMemBusMasterBlt( + unsigned char *pSBase, /* Address of source in the system memory. + The memory must be a continuous physical address. */ + unsigned long sPitch, /* Pitch value of source surface in BYTE */ + unsigned long sx, + unsigned long sy, /* Starting coordinate of source surface */ + unsigned long dBase, /* Address of destination in frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTE */ + unsigned long bpp, /* Color depth of destination surface */ + unsigned long dx, + unsigned long dy, /* Starting coordinate of destination surface */ + unsigned long width, + unsigned long height, /* width and height of rectangle in pixel value */ + unsigned long rop2 /* ROP value */ +) +{ + unsigned long de_ctrl, bytePerPixel; + unsigned long value, pciMasterBaseAddress; + + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + bytePerPixel = bpp/8; + de_ctrl = 0; + + /* Note: + DE_FOREGROUND are DE_BACKGROUND are don't care. + DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency(). + */ + + /* 2D Source Base. + It is an address offset (128 bit aligned) from the given PCI Master base address + */ + /* Set 2D Source Base Address */ + value = FIELD_VALUE(0, DE_WINDOW_SOURCE_BASE, ADDRESS, (unsigned long)pSBase); + pciMasterBaseAddress = ((unsigned long)pSBase & 0xFC000000) >> 24; + POKE_32(PCI_MASTER_BASE, FIELD_VALUE(0, PCI_MASTER_BASE, ADDRESS, pciMasterBaseAddress)); + value = FIELD_SET(value, DE_WINDOW_SOURCE_BASE, EXT, EXTERNAL); + POKE_32(DE_WINDOW_SOURCE_BASE, value); + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, (sPitch/bytePerPixel))); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (sPitch/bytePerPixel))); + + /* Set the pixel format of the destination */ + deSetPixelFormat(bpp); + +#ifdef ENABLE_192_BYTES_PATCH + /* This bug is fixed in SM718 for 16 and 32 bpp. However, in 8-bpp, the problem still exists. + The Version AA also have this problem on higher clock with 32-bit memory data bus, + therefore, it needs to be enabled here. + In version AA, the problem happens on the following configurations: + 1. M2XCLK = 336MHz w/ 32-bit, MCLK = 112MHz, and color depth set to 32bpp + 2. M2XCLK = 336MHz w/ 32-bit, MCLK = 84MHz, and color depth set to 16bpp or 32bpp. + Somehow, the problem does not appears in 64-bit memory setting. + */ + + /* Workaround for 192 byte requirement when ROP is not COPY */ + if ((rop2 != ROP2_COPY) && ((width * bytePerPixel) > 192)) + { + /* Perform the ROP2 operation in chunks of (xWidth * nHeight) */ + unsigned long xChunk = 192 / bytePerPixel; /* chunk width is in pixels */ + + //DDKDEBUGPRINT((DE_LEVEL, "ROP != ROP_COPY, width * bytePerPixel = %x (> 192 bytes)\n", width * bytePerPixel)); + + while (1) + { + deWaitForNotBusy(); + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); + + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, xChunk) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + de_ctrl = + FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) | + FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + + if (xChunk == width) break; + + sx += xChunk; + dx += xChunk; + width -= xChunk; + + if (xChunk > width) + { + /* This is the last chunk. */ + xChunk = width; + } + } + } + else +#endif + { + deWaitForNotBusy(); + + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + de_ctrl = + FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) | + FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + } + + return 0; +} + +/* + * System memory to Video memory data transfer + * Note: + * We also call it HOST Blt. + * This function is a one to one transfer without stretching or + * mono expansion. + */ +long deSystemMem2VideoMemBlt( + unsigned char *pSrcbuf, /* pointer to source data in system memory */ + long srcDelta, /* width (in Bytes) of the source data, +ive means top down and -ive mean button up */ + unsigned long dBase, /* Address of destination: offset in frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTE */ + unsigned long bpp, /* Color depth of destination surface */ + unsigned long dx, + unsigned long dy, /* Starting coordinate of destination surface */ + unsigned long width, + unsigned long height, /* width and height of rectange in pixel value */ + unsigned long rop2 /* ROP value */ +) +{ + unsigned long bytePerPixel; + unsigned long ulBytesPerScan; + unsigned long ul8BytesPerScan; + unsigned long ulBytesRemain; + unsigned long de_ctrl = 0; + unsigned char ajRemain[8]; + long i, j; + + bytePerPixel = bpp/8; + + /* HOST blt data port must take multiple of 8 bytes as input. + If the source width does not match that requirement, + we need to split it into two portions. The first portion + is 8 byte multiple. The 2nd portion is the remaining bytes. + The remaining bytes will be buffered to an 8 byte array and + and send it to the host blt data port. + */ + ulBytesPerScan = width * bpp / 8; + ul8BytesPerScan = ulBytesPerScan & ~7; + ulBytesRemain = ulBytesPerScan & 7; + + /* Program 2D Drawing Engine */ + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + /* 2D Source Base. + Use 0 for HOST Blt. + */ + POKE_32(DE_WINDOW_SOURCE_BASE, 0); + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch/bytePerPixel) | + FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch/bytePerPixel)); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (dPitch/bytePerPixel))); + + /* Note: For 2D Source in Host Write, only X_K1 field is needed, and Y_K2 field is not used. + For 1 to 1 bitmap transfer, use 0 for X_K1 means source alignment from byte 0. */ + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, 0) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, 0)); + + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + /* Set the pixel format of the destination */ + deSetPixelFormat(bpp); + + de_ctrl = + FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) | + FIELD_SET(0, DE_CONTROL, HOST, COLOR) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + + /* Write bitmap/image data (line by line) to 2D Engine data port */ + for (i = 0; i < height; i++) + { + /* For each line, send the data in chunks of 4 bytes. */ + for (j=0; j < (ul8BytesPerScan/4); j++) + POKE_32(DE_DATA_PORT, *(unsigned long *)(pSrcbuf + (j * 4))); + + if (ulBytesRemain) + { + memcpy(ajRemain, pSrcbuf+ul8BytesPerScan, ulBytesRemain); + POKE_32(DE_DATA_PORT, *(unsigned long *)ajRemain); + POKE_32(DE_DATA_PORT, *(unsigned long *)(ajRemain+4)); + } + + pSrcbuf += srcDelta; + } + + return 0; +} + +/* + * System memory to Video memory monochrome expansion. + * Source is monochrome image in system memory. + * This function expands the monochrome data to color image in video memory. + */ +long deSystemMem2VideoMemMonoBlt( +unsigned char *pSrcbuf, /* pointer to start of source buffer in system memory */ +long srcDelta, /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */ +unsigned long startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */ +unsigned long dBase, /* Address of destination: offset in frame buffer */ +unsigned long dPitch, /* Pitch value of destination surface in BYTE */ +unsigned long bpp, /* Color depth of destination surface */ +unsigned long dx, +unsigned long dy, /* Starting coordinate of destination surface */ +unsigned long width, +unsigned long height, /* width and height of rectange in pixel value */ +unsigned long fColor, /* Foreground color (corresponding to a 1 in the monochrome data */ +unsigned long bColor, /* Background color (corresponding to a 0 in the monochrome data */ +unsigned long rop2) /* ROP value */ +{ + unsigned long bytePerPixel; + unsigned long ulBytesPerScan; + unsigned long ul4BytesPerScan; + unsigned long ulBytesRemain; + unsigned long de_ctrl = 0; + unsigned char ajRemain[4]; + long i, j; + + bytePerPixel = bpp/8; + + startBit &= 7; /* Just make sure the start bit is within legal range */ + ulBytesPerScan = (width + startBit + 7) / 8; + ul4BytesPerScan = ulBytesPerScan & ~3; + ulBytesRemain = ulBytesPerScan & 3; + + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + /* 2D Source Base. + Use 0 for HOST Blt. + */ + POKE_32(DE_WINDOW_SOURCE_BASE, 0); + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch/bytePerPixel) | + FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch/bytePerPixel)); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (dPitch/bytePerPixel))); + + /* Note: For 2D Source in Host Write, only X_K1_MONO field is needed, and Y_K2 field is not used. + For mono bitmap, use startBit for X_K1. */ + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1_MONO, startBit)); + + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + POKE_32(DE_FOREGROUND, fColor); + POKE_32(DE_BACKGROUND, bColor); + + /* Set the pixel format of the destination */ + deSetPixelFormat(bpp); + + de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) | + FIELD_SET(0, DE_CONTROL, HOST, MONO) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + + /* Write MONO data (line by line) to 2D Engine data port */ + for (i=0; i> 24; + POKE_32(PCI_MASTER_BASE, FIELD_VALUE(0, PCI_MASTER_BASE, ADDRESS, pciMasterBaseAddress)); + value = FIELD_SET(value, DE_WINDOW_SOURCE_BASE, EXT, EXTERNAL); + POKE_32(DE_WINDOW_SOURCE_BASE, value); + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel conversion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, 1)); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, 0)); /* Source window width is don't care */ + + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, startBit) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, 0)); + + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + POKE_32(DE_FOREGROUND, fColor); + POKE_32(DE_BACKGROUND, bColor); + + /* Set the pixel format of the destination */ + deSetPixelFormat(bpp); + + de_ctrl = + FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, FONT) | + FIELD_SET(0, DE_CONTROL, HOST, MONO) | + FIELD_VALUE(0, DE_CONTROL, MONO_DATA, packed) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + + return 0; +} +#endif + + +/* + * Video memory to Video memory monochrome expansion. + * Source is the starting location of monochrome image in Video memory. + * This function expands the monochrome data to color image. + * + * Note: + * This fnnction can be used to diaplay a mono-font charater to the screen. + * Input source points to the starting location of the font character. + */ +long deVideoMem2VideoMemMonoBlt( +unsigned long sBase, /* Address of mono-chrome source data in frame buffer */ +unsigned long dBase, /* Base address of destination in frame buffer */ +unsigned long dPitch, /* Pitch value of destination surface in BYTE */ +unsigned long bpp, /* Color depth of destination surface */ +unsigned long dx, +unsigned long dy, /* Starting coordinate of destination surface */ +unsigned long width, /* width of mono-chrome picture in pixel value */ +unsigned long height, /* height of mono-chrome picture in pixel value */ +unsigned long fColor, /* Foreground color (corresponding to a 1 in the monochrome data */ +unsigned long bColor, /* Background color (corresponding to a 0 in the monochrome data */ +unsigned long rop2) /* ROP value */ +{ + unsigned long bytePerPixel, de_ctrl, packed; + + bytePerPixel = bpp/8; + + switch ( width ) + { + case 8: + packed = DE_CONTROL_MONO_DATA_8_PACKED; + break; + case 16: + packed = DE_CONTROL_MONO_DATA_16_PACKED; + break; + case 32: + packed = DE_CONTROL_MONO_DATA_32_PACKED; + break; + default: + packed = DE_CONTROL_MONO_DATA_NOT_PACKED; + } + + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + /* Note: + DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency(). + */ + + /* Monochrome source data in frame buffer. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_SOURCE_BASE, sBase); + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, 0)); /* Source pitch is don't care */ + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, 0 )); /* Source window width is don't care */ + + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, 0) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, 0)); /* Source data starts at location (0, 0) */ + + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + POKE_32(DE_FOREGROUND, fColor); + POKE_32(DE_BACKGROUND, bColor); + POKE_32(DE_COLOR_COMPARE, bColor); + + /* Set the pixel format of the destination */ + deSetPixelFormat(bpp); + + de_ctrl = + FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, FONT) | + FIELD_SET(0, DE_CONTROL, HOST, MONO) | + FIELD_VALUE(0, DE_CONTROL, MONO_DATA, packed) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + + return 0; +} + +/* + * Video memory to Video memory monochrome expansion. + * + * Difference between this function and deVideoMem2VideoMemMonoBlt(): + * 1) Input is base address of the whole font table. + * 2) An extra input about which character in the font table to display. + * 3) This function demos how to use registers DE_SOURCE and + * DE_WINDOW_WIDTH, where they are set to 0 in deVideoMem2VideoMemMonoBlt(). + */ +long deFontCacheTblMonoBlt( +unsigned long fontTblBase,/* Base address of monochrome font table in frame buffer */ +unsigned long fontNumber, /* Which character in the font table, starting from 0 */ +unsigned long dBase, /* Base address of destination in frame buffer */ +unsigned long dPitch, /* Pitch value of destination surface in BYTE */ +unsigned long bpp, /* Color depth of destination surface */ +unsigned long dx, +unsigned long dy, /* Starting coordinate of destination surface */ +unsigned long width, /* width of each monochrome font in pixel value */ +unsigned long height, /* height of each monochrome font in pixel value */ +unsigned long fColor, /* Foreground color (corresponding to a 1 in the monochrome data */ +unsigned long bColor, /* Background color (corresponding to a 0 in the monochrome data */ +unsigned long rop2) /* ROP value */ +{ + unsigned long bytePerPixel, distBetweenFont, de_ctrl, packed; + + bytePerPixel = bpp/8; + + /* Distance between fonts in pixel value */ + distBetweenFont = width * height; + + /* SM50x hardware requires each font character be a minimum of 128 + pixel value apart. + For 8x8 fonts, each font character is only 64 pixel apart. + However, if application uses deCacheFontToFrameBuffer() + to cache the font in video memory, each font character will be + stored as 128 pixels apart. + */ + if (distBetweenFont < 128) + distBetweenFont = 128; + + switch ( width ) + { + case 8: + packed = DE_CONTROL_MONO_DATA_8_PACKED; + break; + case 16: + packed = DE_CONTROL_MONO_DATA_16_PACKED; + break; + case 32: + packed = DE_CONTROL_MONO_DATA_32_PACKED; + break; + default: + packed = DE_CONTROL_MONO_DATA_NOT_PACKED; + } + + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + /* Note: + DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency(). + */ + + /* Base address of font table in frame buffer */ + POKE_32(DE_WINDOW_SOURCE_BASE, fontTblBase); + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, 0)); /* Source pitch is don't care */ + + /* Pay attention how DE_WINDOW_WIDTH:SOURCE is different from + deVideoMem2VideoMemMonoBlt() + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, distBetweenFont)); + + /* Pay attention how DE_SOURCE:Y_K2 is different from + deVideoMem2VideoMemMonoBlt() + */ + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, 0) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, fontNumber)); + + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + POKE_32(DE_FOREGROUND, fColor); + POKE_32(DE_BACKGROUND, bColor); + POKE_32(DE_COLOR_COMPARE, bColor); + + /* Set the pixel format of the destination */ + deSetPixelFormat(bpp); + + de_ctrl = + FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, FONT) | + FIELD_SET(0, DE_CONTROL, HOST, MONO) | + FIELD_VALUE(0, DE_CONTROL, MONO_DATA, packed) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + + return 0; +} + + +/* + * Rotation helper function. + * + * This function sets the source coordinate, destination coordinate, window + * dimension, and also the control register. This function is only used statically + * to simplify the deRotateBlt function. + * + */ +void deRotate( + unsigned long sx, /* X Coordinate of the source */ + unsigned long sy, /* Y Coordinate of the source */ + unsigned long dx, /* X Coordinate of the destination */ + unsigned long dy, /* Y Coordinate of the destination */ + unsigned long width, /* Width of the window */ + unsigned long height, /* Height of the window */ + unsigned long de_ctrl /* DE_CONTROL Control Value */ +) +{ + /* Wait until the engine is not busy */ + deWaitForNotBusy(); + + /* Set the source coordinate */ + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); + + /* Set the destination coordinate */ + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + + /* Set the source width and height dimension */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + /* Start the DE Control */ + POKE_32(DE_CONTROL, de_ctrl); +} + +/* + * Rotation Blt. + * + * This function rotates an image to the screen based on the given rotation direction + * (0, 90, 180, or 270 degree). + * + * NOTE: + * 1. The function takes care of any coordinates that pass the top and left + * boundary, but it does not take care of right and bottom boundary since + * more information is needed in order to do so. However, it seems that + * SM50x will take care the right and bottom by using wrap around. + * Depending on the implementation, this function might be modified further. + * 2. There are 3 hardware bugs found on the rotation: + * a. The rotated image sometimes is not correct when using some width number + * due to FIFO bug. Therefore, the image is divided into segments and + * rotated based on segment by segment using 32/byte per pixel as the width. + * This value (32/byte per pixel) seems to be consistent in producing a good + * rotated image. + * b. Rotating 0 degree using the actual Rotation BLT will have the same result + * as rotation 270 degree. + * c. Rotating 180 degree on some x destination coordinate will result in + * incorrect image. To workaround this problem, two 90 degree rotations are + * used. + * 3. The rop parameter might not be necessary if only one ROP operation is used. + * This might be deleted in the future as necessary. + */ +long deVideoMem2VideoMemRotateBlt( + unsigned long sBase, /* Source Base Address */ + unsigned long sPitch, /* Source pitch */ + unsigned long sx, /* X Coordinate of the source */ + unsigned long sy, /* Y Coordinate of the source */ + unsigned long dBase, /* Destination Base Address */ + unsigned long dPitch, /* Destination pitch */ + unsigned long bpp, /* Color depth of destination surface */ + unsigned long dx, /* X Coordinate of the destination */ + unsigned long dy, /* Y Coordinate of the destination */ + unsigned long width, /* Width of un-rotated image in pixel value */ + unsigned long height, /* Height of un-rotated image in pixel value */ + rotate_dir_t rotateDirection, /* Direction of the rotation */ + unsigned long repeatEnable, /* Enable repeat rotation control where the + drawing engine is started again every vsync */ + unsigned long rop2 /* ROP control */ +) +{ + unsigned long de_ctrl = 0; + unsigned long maxRotationWidth; + + /* Maximum rotation width BLT */ + maxRotationWidth = 32 / BYTE_PER_PIXEL(bpp); + + /* Wait for the engine to be idle */ + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + return -1; + + /* or */ + /* deReset(); */ + } + + /* Return error if either the width or height is zero */ + if ((width == 0) || (height == 0)) + return -1; + + /* 2D Source Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_SOURCE_BASE, sBase); + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, sPitch / BYTE_PER_PIXEL(bpp))); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, sPitch / BYTE_PER_PIXEL(bpp))); + + /* Set the pixel format of the destination */ + deSetPixelFormat(bpp); + + /* Setup Control Register */ + de_ctrl = FIELD_SET(0, DE_CONTROL, STATUS, START) | + FIELD_SET(0, DE_CONTROL, COMMAND, ROTATE) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + ((repeatEnable == 1) ? + FIELD_SET(0, DE_CONTROL, REPEAT_ROTATE, ENABLE) : + FIELD_SET(0, DE_CONTROL, REPEAT_ROTATE, DISABLE)) | + deGetTransparency(); + + /* 501 Hardware cannot handle rotblits > 32 bytes. Therefore the rotation + should be done part by part. Note on each rotation case. */ + switch (rotateDirection) + { + case ROTATE_NORMAL: +#if 0 /* Enable this on if the hardware 0 degree rotation bug has been fixed */ + + /* Setup rotation direction to 0 degree */ + de_ctrl |= (FIELD_SET(0, DE_CONTROL, STEP_X, POSITIVE) | + FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE)); + + deRotate(sx, sy, dx, dy, width, height, de_ctrl); +#else + /* + * Due to the hardware bug on the SM750, rotate normal is simply done + * by calling the normal bit BLT. Calling the rotation with 0 degree + * will cause the hardware to rotate it 270 degree. + */ + return(ddk750_deVideoMem2VideoMemBlt( + sBase, + sPitch, + sx, + sy, + dBase, + dPitch, + bpp, + dx, + dy, + width, + height, + rop2)); +#endif + break; + + case ROTATE_180_DEGREE: + /* The 180 degree rotation that has problem */ + + return -1; /* Don't do anything until there is a HW fix */ + + de_ctrl |= (FIELD_SET(0, DE_CONTROL, STEP_X, NEGATIVE) | + FIELD_SET(0, DE_CONTROL, STEP_Y, NEGATIVE)); + + deRotate(sx, sy, dx, dy, width, height, de_ctrl); + break; + + case ROTATE_90_DEGREE: + /* 90 degrees rotation. Calculate destination + coordinates: + + *---+ + | | +-----+ + | | | | + | | --> | | + | | | | + | | *-----+ + +---+ + */ + /* Update the new width */ + if (dy < width) + width = dy+1; + + /* Set up the rotation direction to 90 degree */ + de_ctrl |= (FIELD_SET(0, DE_CONTROL, STEP_X, NEGATIVE) | + FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE)); + +#if 1 /* Disable this one if the hardware bug has been fixed */ + + /* Do rotation part by part based on the maxRotationWidth */ + while (width > maxRotationWidth) + { + deRotate(sx, sy, dx, dy, maxRotationWidth, height, de_ctrl); + + width -= maxRotationWidth; + sx += maxRotationWidth; + dy -= maxRotationWidth; + } +#endif + /* Rotate the rest of the segment */ + if (width > 0) + deRotate(sx, sy, dx, dy, width, height, de_ctrl); + + break; + + case ROTATE_270_DEGREE: + /* 270 degrees (90 degree CW) rotation. Calculate destination + coordinates: + + *---+ + | | +-----* + | | | | + | | --> | | + | | | | + | | +-----+ + +---+ + */ + de_ctrl |= (FIELD_SET(0, DE_CONTROL, STEP_X, POSITIVE) | + FIELD_SET(0, DE_CONTROL, STEP_Y, NEGATIVE)); + +#if 1 /* Disable this one if the hardware bug has been fixed */ + + /* Do rotation part by part based on the maxRotationWidth */ + while (width > maxRotationWidth) + { + deRotate(sx, sy, dx, dy, maxRotationWidth, height, de_ctrl); + + width -= maxRotationWidth; + sx += maxRotationWidth; + dy += maxRotationWidth; + } +#endif + /* Update the rest of the segment */ + if (width > 0) + deRotate(sx, sy, dx, dy, width, height, de_ctrl); + break; + } + + return 0; +} + +/* + * Function to draw a vertical line. + * + * Note: + * This function is using Short Stroke line + */ +long deVerticalLine( + unsigned long dBase, /* Base address of destination surface counted from beginning of video frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTES */ + unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ + unsigned long x, /* Starting X Coordinate */ + unsigned long y, /* Starting Y Coordinate */ + unsigned long length, /* Length of the line */ + unsigned long color, /* Color of the line */ + unsigned long rop2 /* ROP value */ +) +{ + unsigned long de_ctrl; + + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp))); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp))); + + /* Set the Line Color */ + POKE_32(DE_FOREGROUND, color); + + /* Set the destination coordinate. */ + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, x) | + FIELD_VALUE(0, DE_DESTINATION, Y, y)); + + /* Set the line length and width */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, 1) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, length)); + + /* Set the pixel format of the destination */ + deSetPixelFormat(bpp); + + /* Set the control register. For the Vertical line Short Stroke, the Direction Control + should be set to 0 (which is defined as Left to Right). */ + de_ctrl = + FIELD_SET (0, DE_CONTROL, STATUS, START) | + FIELD_SET (0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + FIELD_SET (0, DE_CONTROL, MAJOR, Y) | + FIELD_SET (0, DE_CONTROL, STEP_X, NEGATIVE) | + FIELD_SET (0, DE_CONTROL, STEP_Y, NEGATIVE) | + FIELD_SET (0, DE_CONTROL, LAST_PIXEL, OFF) | + FIELD_SET (0, DE_CONTROL, COMMAND, SHORT_STROKE) | + FIELD_SET (0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, rop2); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + + return 0; +} + +/* + * Function to draw a horizontal line. + * + * Note: + * This function is using Short Stroke line + */ +long deHorizontalLine( + unsigned long dBase, /* Base address of destination surface counted from beginning of video frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTES */ + unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ + unsigned long x, /* Starting X Coordinate */ + unsigned long y, /* Starting Y Coordinate */ + unsigned long length, /* Length of the line */ + unsigned long color, /* Color of the line */ + unsigned long rop2 /* ROP value */ +) +{ + unsigned long de_ctrl; + + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp))); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp))); + + /* Set the Line Color */ + POKE_32(DE_FOREGROUND, color); + + /* Set the destination coordinate */ + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, x) | + FIELD_VALUE(0, DE_DESTINATION, Y, y)); + + /* Set the line length and width */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, length) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, 1)); + + /* Set the pixel format of the destination */ + deSetPixelFormat(bpp); + + /* Set the control register. For the Horizontal line Short Stroke, the Direction Control + should be set to 1 (which is defined as Right to Left). */ + de_ctrl = + FIELD_SET (0, DE_CONTROL, STATUS, START) | + FIELD_SET (0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT) | + FIELD_SET (0, DE_CONTROL, MAJOR, X) | + FIELD_SET (0, DE_CONTROL, STEP_X, NEGATIVE) | + FIELD_SET (0, DE_CONTROL, STEP_Y, NEGATIVE) | + FIELD_SET (0, DE_CONTROL, LAST_PIXEL, OFF) | + FIELD_SET (0, DE_CONTROL, COMMAND, SHORT_STROKE) | + FIELD_SET (0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, rop2); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + + return 0; +} + +/* + * Function to draw a line. + * + * Note: + * This function is using Short Stroke Command for Vertical, Horizontal, and + * Diagonal line. Other line are drawn using the Line Draw Command. + */ +long deLine( + unsigned long dBase, /* Base address of destination surface counted from beginning of video frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTES */ + unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ + long x0, /* Starting X Coordinate */ + long y0, /* Starting Y Coordinate */ + long x1, /* Ending X Coordinate */ + long y1, /* Ending Y Coordinate */ + unsigned long color, /* Color of the line */ + unsigned long rop2 /* ROP value */ +) +{ + unsigned long de_ctrl = + FIELD_SET (0, DE_CONTROL, STATUS, START) | + FIELD_SET (0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + FIELD_SET (0, DE_CONTROL, MAJOR, X) | + FIELD_SET (0, DE_CONTROL, STEP_X, POSITIVE) | + FIELD_SET (0, DE_CONTROL, STEP_Y, POSITIVE) | + FIELD_SET (0, DE_CONTROL, LAST_PIXEL, ON) | + FIELD_SET (0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, rop2); + + unsigned long dx, dy; + + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + //DDKDEBUGPRINT((DE_LEVEL, "x0=%d(%x), y0=%d(%0x)\n", x0, x0, y0, y0)); + //DDKDEBUGPRINT((DE_LEVEL, "x1=%d(%x), y1=%d(%0x)\n", x1, x1, y1, y1)); + + /* Return error if x0 and/or y0 are negative numbers. The hardware does not take + any negative values on these two origin line coordinate. + When drawing with a negative x0, the line might be drawn incorrectly. + When drawing with a negative y0, the system might reboot or hang. + */ + if ((x0 < 0) || (y0 < 0)) + { + //DDKDEBUGPRINT((ERROR_LEVEL, "Negative origin coordinates are not allowed (x0, y0) = (%d, %d).\n", x0, y0)); + return (-1); + } + + /* Calculate delta X */ + if (x0 <= x1) + { + dx = x1 - x0; + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE); + } + else + dx = x0 - x1; + + /* Calculate delta Y */ + if (y0 <= y1) + { + dy = y1 - y0; + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE); + } + else + dy = y0 - y1; + + /* Determine the major axis */ + if (dx < dy) + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y); + + /***************************************************** + * Draw the line based on the calculated information * + *****************************************************/ + + /* Vertical line? */ + if (x0 == x1) + deVerticalLine(dBase, dPitch, bpp, x0, (y0 < y1) ? y0 : y1, dy + 1, color, rop2); + + /* Horizontal line? */ + else if (y0 == y1) + deHorizontalLine(dBase, dPitch, bpp, (x0 < x1) ? x0 : x1, y0, dx + 1, color, rop2); + + else + { + /**************************** + * Set the common registers * + ****************************/ + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp))); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp))); + + /* Set the Line Color */ + POKE_32(DE_FOREGROUND, color); + + /* Set the destination coordinate */ + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, x0) | + FIELD_VALUE(0, DE_DESTINATION, Y, y0)); + + /* Set the pixel format of the destination */ + deSetPixelFormat(bpp); + + /* Diagonal line? */ + if (dx == dy) + { + /* Set the line length and width */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, 1) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, dx + 1)); + + /* Set the command register. */ + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, COMMAND, SHORT_STROKE); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + } + + /* Generic line */ + else + { + long k1, k2, et, w; + + if (dx < dy) + { + k1 = 2 * dx; + et = k1 - dy; + k2 = et - dy; + w = dy + 1; + } + else + { + k1 = 2 * dy; + et = k1 - dx; + k2 = et - dx; + w = dx + 1; + } + + //DDKDEBUGPRINT((DE_LEVEL, "k1=%d(%x), k2=%d(%x)\n", k1, k1, k2, k2)); + + /* Return error if the value of K1 and/or K2 is/are overflowed which is + determined using the following condition: + 0 < k1 < (2^13 - 1) + -2^13 < k2 < 0 + Bit-14 is the sign bit. + + Failing to follow this guidance will result in incorrect line drawing. + On failure, please use software to draw the correct line. + */ + if ((k1 > 8191) || (k2 < (0 - 8192))) + { + //DDKDEBUGPRINT((ERROR_LEVEL, "K1=%d(0x%04x) and/or K2=%d(0x%04x) is/are overflowed.\n", k1, k1, k2, k2)); + return (-1); + } + + /* Set the k1 and k2 */ + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1_LINE, k1) | + FIELD_VALUE(0, DE_SOURCE, Y_K2_LINE, k2)); + + /* Set the line length and width */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, w) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, et)); + + /* Set the control register. */ + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, COMMAND, LINE_DRAW); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + } + } + + return 0; +} + +#if 0 /* These RLE functions are not working. */ +/* + * The following functions, that uses to draw line using RLE Strip command, are not working, + * as described in the following: + * 1. Line strips can not be used to draw line vertically. + * 2. Origin Y automatic update is not work. Only Origin X automatic update is working. + * 3. Line counter to accelerate drawing multiple strip of the same characteristics does + * not work. + * For more information about RLE Line Strips, please refer to "Programmer's Guide to the EGA, + * VGA, and Super VGA Cards", third edition, page 727-730. + */ + +/* + * Function to draw a line using RLE line strip method. + */ +long deStartLineStrip( + unsigned long dBase, /* Base address of destination surface counted from beginning of video frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTES */ + unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ + unsigned long x, /* X Coordinate */ + unsigned long y, /* Y Coordinate */ + unsigned long length, /* Length of the line */ + unsigned long lineCounter, /* Line Counter */ + unsigned long direction, /* Direction: 0 - Left to Right + 1 - Right to Left + 2 - Top to Bottom + 3 - Bottom to Top + */ + unsigned long color, /* Color of the line */ + unsigned long rop2 /* ROP value */ +) +{ + unsigned long dx, dy; + unsigned long de_ctrl = + FIELD_SET (0, DE_CONTROL, STATUS, START) | + FIELD_SET (0, DE_CONTROL, QUICK_START, ENABLE) | + FIELD_SET (0, DE_CONTROL, LAST_PIXEL, OFF) | + FIELD_SET (0, DE_CONTROL, COMMAND, RLE_STRIP) | + FIELD_SET (0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, rop2); + + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp))); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp))); + + /* Set the Line Color */ + POKE_32(DE_FOREGROUND, color); + + /* Set the destination coordinate */ + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, x) | + FIELD_VALUE(0, DE_DESTINATION, Y, y)); + + /* Set the pixel format of the destination */ + deSetPixelFormat(bpp); + +#if 1 /* Testing if any of the configuration combination of the following have + any differences. */ + switch (direction) + { + case 0: + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE); + break; + case 1: + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE); + break; + case 2: + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE); + break; + case 3: + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE); + break; + case 4: + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE); + break; + case 5: + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE); + break; + case 6: + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE); + break; + case 7: + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE); + break; + case 8: + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE); + break; + case 9: + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE); + break; + case 10: + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE); + break; + case 11: + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE); + break; + case 12: + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE); + break; + case 13: + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE); + break; + case 14: + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE); + break; + case 15: + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE); + break; + } + + /* Set the line length and width */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, lineCounter) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, length)); +#else + /* Determine the x & y steps direction control and major axis */ + switch (direction) + { + case 0: + /* Left to Right */ + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE); + + /* Set the line length and width */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, length) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, lineCounter)); + break; + + case 1: + /* Right to Left */ + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, X); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, NEGATIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE); + + /* Set the line length and width */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, length) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, lineCounter)); + break; + + case 2: + /* Top to Bottom */ + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, POSITIVE); + + /* Set the line length and width */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, lineCounter) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, length)); + break; + + case 3: + /* Bottom to Top */ + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, MAJOR, Y); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_X, POSITIVE); + de_ctrl = FIELD_SET(de_ctrl, DE_CONTROL, STEP_Y, NEGATIVE); + + /* Set the line length and width */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, lineCounter) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, length)); + break; + } +#endif + + /* Enable the 2D Engine. */ + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + + return 0; +} + +/* + * Function to continue drawing a line using RLE line strip method. + */ +long deNextLineStrip( + unsigned long length, /* Line strip length */ + unsigned long lineCounter /* Line Counter */ +) +{ + unsigned long de_ctrl; + + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + de_ctrl = PEEK_32(DE_CONTROL); + + if (FIELD_GET(de_ctrl, DE_CONTROL, MAJOR) == DE_CONTROL_MAJOR_X) + { + /* Set the line length and width */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, length) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, lineCounter)); + } + else + { + /* Set the line length and width */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, lineCounter) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, length)); + } + + return 0; +} + +/* + * Function to stop the RLE line strip drawing. + * This function has to be called to end the Line Strip drawing. + * Otherwise, the next 2D function might still use this function. + */ +long deStopLineStrip() +{ + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + POKE_32(DE_CONTROL, FIELD_SET(PEEK_32(DE_CONTROL), DE_CONTROL, QUICK_START, DISABLE)); + + return 0; +} +#endif + +/* Define this definition to block transparency in Alpha Blend blt since + transparency does not work with alpha blend. */ +//#define ALPHA_BLEND_BLOCK_TRANSPARENCY + +/* + * Alpha Blend Blt. + * + * This function blends the source with the destination image. + */ +long deVideoMem2VideoMemAlphaBlendBlt( + unsigned long sBase, /* Source Base Address */ + unsigned long sPitch, /* Source pitch */ + unsigned long sx, /* X Coordinate of the source */ + unsigned long sy, /* Y Coordinate of the source */ + unsigned long sWidth, /* Source Width */ + unsigned long sHeight, /* Source Height */ + unsigned long dBase, /* Destination Base Address */ + unsigned long dPitch, /* Destination pitch */ + unsigned long bpp, /* Color depth of destination surface */ + unsigned long dx, /* X Coordinate of the destination */ + unsigned long dy, /* Y Coordinate of the destination */ + unsigned long dHeight, /* Destination Height (only height stretch is supported) */ + unsigned long alphaValue, /* Alpha value for Alpha Blend*/ + unsigned long rop2 /* ROP control */ +) +{ + unsigned long de_ctrl = 0, bytePerPixel; +#ifdef ALPHA_BLEND_BLOCK_TRANSPARENCY + unsigned long transparency = 0; +#endif + + bytePerPixel = bpp/8; + + /* Wait for the engine to be idle */ + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + return -1; + + /* or */ + /* deReset(); */ + } + + /* Return error if either the width or height is zero */ + if ((sWidth == 0) || (sHeight == 0) || (dHeight == 0)) + return -1; + +#ifdef ALPHA_BLEND_BLOCK_TRANSPARENCY + /* Get the transparency settings. The transparency does not work with Alpha Blend, + therefore, save the transparency setting, disable, and restore it back later. */ + transparency = deGetTransparency(); +#endif + + /* 2D Source Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_SOURCE_BASE, sBase); + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel conversion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, sPitch / BYTE_PER_PIXEL(bpp))); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, sPitch / BYTE_PER_PIXEL(bpp))); + + /* Set the Source Height */ + POKE_32(DE_STRETCH_FORMAT, + FIELD_VALUE(PEEK_32(DE_STRETCH_FORMAT), DE_STRETCH_FORMAT, SOURCE_HEIGHT, sHeight)); + + /* Set the alpha blend value */ + POKE_32(DE_ALPHA, + FIELD_VALUE(0, DE_ALPHA, VALUE, alphaValue)); + + /* Set the pixel format of the destination */ + deSetPixelFormat(bpp); + +#ifdef ENABLE_192_BYTES_PATCH + /* Workaround for 192 byte requirement */ + if ((sWidth * bytePerPixel) > 192) + { + /* Perform the ROP2 operation in chunks of (xWidth * nHeight) */ + unsigned long xChunk = 192 / bytePerPixel; /* chunk width is in pixels */ + + //DDKDEBUGPRINT((DE_LEVEL, "width * bytePerPixel = %x (> 192 bytes)\n", sWidth * bytePerPixel)); + + while (1) + { + deWaitForNotBusy(); + + /* Set the source coordinate */ + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); + + /* Set the destination coordinate */ + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + + /* Set the Destination Dimension */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, xChunk) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, dHeight)); + + /* Setup Control Register */ + de_ctrl = FIELD_SET(0, DE_CONTROL, STATUS, START) | + FIELD_SET(0, DE_CONTROL, COMMAND, ALPHA_BLEND) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + ((sHeight < dHeight) ? + FIELD_SET(0, DE_CONTROL, STRETCH, ENABLE) : + FIELD_SET(0, DE_CONTROL, STRETCH, DISABLE)); + + POKE_32(DE_CONTROL, de_ctrl); + + if (xChunk == sWidth) + break; + + sx += xChunk; + dx += xChunk; + sWidth -= xChunk; + + if (xChunk > sWidth) + { + /* This is the last chunk. */ + xChunk = sWidth; + } + } + } + else +#endif + { + deWaitForNotBusy(); + + /* Set the source coordinate */ + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); + + /* Set the destination coordinate */ + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + + /* Set the Destination Dimension */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, sWidth) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, dHeight)); + + /* Setup Control Register */ + de_ctrl = FIELD_SET(0, DE_CONTROL, STATUS, START) | + FIELD_SET(0, DE_CONTROL, COMMAND, ALPHA_BLEND) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + ((sHeight < dHeight) ? + FIELD_SET(0, DE_CONTROL, STRETCH, ENABLE) : + FIELD_SET(0, DE_CONTROL, STRETCH, DISABLE)); + + POKE_32(DE_CONTROL, de_ctrl); + } + +#ifdef ALPHA_BLEND_BLOCK_TRANSPARENCY + /* Restore back the transparency */ + deWaitForNotBusy(); + de_ctrl = PEEK_32(de_ctrl) | transparency; + POKE_32(DE_CONTROL, de_ctrl); +#endif + + return 0; +} + +/* + * This function sets the monochrome pattern on the pattern registers. + */ +void deSetPattern( + unsigned long monoPatternLow, + unsigned long monoPatternHigh +) +{ + POKE_32(DE_MONO_PATTERN_LOW, monoPatternLow); + POKE_32(DE_MONO_PATTERN_HIGH, monoPatternHigh); +} + +/* + * This function uses 2D engine to fill a rectangular area with a specific pattern. + * The filled area includes the starting points. + */ +long deRectPatternFill( + unsigned long dBase, /* Base address of destination surface counted from beginning of video frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTES */ + unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ + unsigned long x, + unsigned long y, /* Upper left corner (X, Y) of rectangle in pixel value */ + unsigned long width, + unsigned long height, /* width and height of rectange in pixel value */ + unsigned long color, /* Color to be filled */ + unsigned long rop3) /* ROP value */ +{ + unsigned long de_ctrl, bytePerPixel; + + bytePerPixel = bpp/8; + + if (deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* deReset(); */ + } + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, (dPitch/bytePerPixel))); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (dPitch/bytePerPixel))); + + POKE_32(DE_FOREGROUND, color); + + /* Set the pixel format of the destination */ + deSetPixelFormat(bpp); + +#ifdef ENABLE_192_BYTES_PATCH + /* Workaround for 192 byte requirement when ROP is not COPY */ + if (((rop3 != ROP2_COPY) || (rop3 != ROP2_Sn) || (rop3 != ROP2_Dn) || + (rop3 != ROP2_D) || (rop3 != ROP2_BLACK) || (rop3 != ROP2_WHITE)) && + ((width * bytePerPixel) > 192)) + { + /* Perform the ROP2 operation in chunks of (xWidth * nHeight) */ + unsigned long xChunk = 192 / bytePerPixel; /* chunk width is in pixels */ + + //DDKDEBUGPRINT((DE_LEVEL, "ROP != ROP_COPY, width * bytePerPixel = %x (> 192 bytes)\n", width * bytePerPixel)); + + while (1) + { + deWaitForNotBusy(); + + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, x) | + FIELD_VALUE(0, DE_DESTINATION, Y, y)); + + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, xChunk) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + de_ctrl = + FIELD_SET (0, DE_CONTROL, STATUS, START) | + FIELD_SET (0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + //FIELD_SET (0, DE_CONTROL,LAST_PIXEL, OFF) | + FIELD_SET (0, DE_CONTROL, COMMAND, RECTANGLE_FILL) | + FIELD_SET (0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, rop3); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + + if (xChunk == width) break; + + x += xChunk; + width -= xChunk; + + if (xChunk > width) + { + /* This is the last chunk. */ + xChunk = width; + } + } + } + else +#endif + { + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, x) | + FIELD_VALUE(0, DE_DESTINATION, Y, y)); + + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + de_ctrl = + FIELD_SET (0, DE_CONTROL, STATUS, START) | + FIELD_SET (0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + //FIELD_SET (0, DE_CONTROL,LAST_PIXEL, OFF) | + FIELD_SET (0, DE_CONTROL, COMMAND, RECTANGLE_FILL) | + FIELD_SET (0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, rop3); + + POKE_32(DE_CONTROL, de_ctrl | deGetTransparency()); + } + + return 0; +} diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_2d.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_2d.h new file mode 100644 index 000000000000..00c937350c1b --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_2d.h @@ -0,0 +1,480 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* 2d.h --- SM750/SM718 DDK +* This file contains the definitions for the 2D Engine interrupt. +* +*******************************************************************/ +#ifndef _2D_H_ +#define _2D_H_ + +//#include "csc.h" + +#define POKE_8(address, value) pokeRegisterByte(address, value) +#define POKE_16(address, value) pokeRegisterWord(address, value) +#define POKE_32(address, value) pokeRegisterDWord(address, value) +#define PEEK_8(address) peekRegisterByte(address) +#define PEEK_16(address) peekRegisterWord(address) +#define PEEK_32(address) peekRegisterDWord(address) + +/* Rotation Direction */ +typedef enum _rotate_dir_t +{ + ROTATE_NORMAL = 0, + ROTATE_90_DEGREE, + ROTATE_180_DEGREE, + ROTATE_270_DEGREE +} +rotate_dir_t; + +/* + * 2D Engine Initialization. + * This function must be called before other 2D functions. + * Assumption: A specific vidoe mode has been properly set up. + */ +void ddk750_deInit(void); + +/* + * Reset 2D engine by + * 1) Aborting the current 2D operation. + * 2) Re-enable 2D engine to normal state. + */ +void deReset(void); + +/* + * Wait until 2D engine is not busy. + * All 2D operations are recommand to check 2D engine idle before start. + * + * Return: 0 = return because engine is idle and normal. + * -1 = return because time out (2D engine may have problem). + */ +long deWaitForNotBusy(void); + +/* deWaitIdle() function. + * + * This function is same as deWaitForNotBusy(), except application can + * input the maximum number of times that this function will check + * the idle register. + * + * Its usage is mainly for debugging purpose. + * + * Wait until 2D engine is not busy. + * All 2D operations are recommand to check 2D engine idle before start. + * + * Return: 0 = return because engine is idle and normal. + * -1 = return because time out (2D engine may have problem). + */ +long deWaitIdle(unsigned long i); + +/* + * This function enable/disable clipping area for the 2d engine. + * Note that the clipping area is always rectangular. + * + */ +long deSetClipping( +unsigned long enable, /* 0 = disable clipping, 1 = enable clipping */ +unsigned long x1, /* x1, y1 is the upper left corner of the clipping area */ +unsigned long y1, /* Note that the region includes x1 and y1 */ +unsigned long x2, /* x2, y2 is the lower right corner of the clippiing area */ +unsigned long y2); /* Note that the region will not include x2 and y2 */ + +/* + * Function description: + * When transparency is enable, the blt engine compares each pixel value + * (either source or destination) with DE_COLOR_COMPARE register. + * If match, the destination pixel will NOT be updated. + * If not match, the destination pixel will be updated. + */ +long deSetTransparency( +unsigned long enable, /* 0 = disable, 1 = enable transparency feature */ +unsigned long tSelect, /* 0 = compare source, 1 = compare destination */ +unsigned long tMatch, /* 0 = Opaque mode, 1 = transparent mode */ +unsigned long ulColor); /* Color to compare. */ + +/* + * This function uses 2D engine to fill a rectangular area with a specific color. + * The filled area includes the starting points. + */ +long deRectFill( /*resolution_t resolution, point_t p0, point_t p1, unsigned long color, unsigned long rop2)*/ +unsigned long dBase, /* Base address of destination surface counted from beginning of video frame buffer */ +unsigned long dPitch, /* Pitch value of destination surface in BYTES */ +unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ +unsigned long x, +unsigned long y, /* Upper left corner (X, Y) of rectangle in pixel value */ +unsigned long width, +unsigned long height, /* width and height of rectange in pixel value */ +unsigned long color, /* Color to be filled */ +unsigned long rop2); /* ROP value */ + +/* + * Video Memory to Video Memory data transfer. + * Note: + * It works whether the Video Memroy is off-screeen or on-screen. + * This function is a one to one transfer without stretching or + * mono expansion. + */ +long ddk750_deVideoMem2VideoMemBlt( +unsigned long sBase, /* Address of source: offset in frame buffer */ +unsigned long sPitch, /* Pitch value of source surface in BYTE */ +unsigned long sx, +unsigned long sy, /* Starting coordinate of source surface */ +unsigned long dBase, /* Address of destination: offset in frame buffer */ +unsigned long dPitch, /* Pitch value of destination surface in BYTE */ +unsigned long bpp, /* Color depth of destination surface */ +unsigned long dx, +unsigned long dy, /* Starting coordinate of destination surface */ +unsigned long width, +unsigned long height, /* width and height of rectange in pixel value */ +unsigned long rop2); /* ROP value */ + +/* + * System Memory to Video Memory data transfer. + * Note: + * It works whether the Video Memroy is off-screeen or on-screen. + * This function is a one to one transfer without stretching or + * mono expansion. + */ +long deSystemMem2VideoMemBusMasterBlt( + unsigned char *pSBase, /* Address of source: offset in frame buffer */ + unsigned long sPitch, /* Pitch value of source surface in BYTE */ + unsigned long sx, + unsigned long sy, /* Starting coordinate of source surface */ + unsigned long dBase, /* Address of destination: offset in frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTE */ + unsigned long bpp, /* Color depth of destination surface */ + unsigned long dx, + unsigned long dy, /* Starting coordinate of destination surface */ + unsigned long width, + unsigned long height, /* width and height of rectangle in pixel value */ + unsigned long rop2 /* ROP value */ +); + +/* + * System memory to Video memory data transfer + * Note: + * We also call it HOST Blt. + * This function is a one to one transfer without stretching or + * mono expansion. + */ +long deSystemMem2VideoMemBlt( +unsigned char *pSrcbuf, /* pointer to source data in system memory */ +long srcDelta, /* width (in Bytes) of the source data, +ive means top down and -ive mean button up */ +unsigned long dBase, /* Address of destination: offset in frame buffer */ +unsigned long dPitch, /* Pitch value of destination surface in BYTE */ +unsigned long bpp, /* Color depth of destination surface */ +unsigned long dx, +unsigned long dy, /* Starting coordinate of destination surface */ +unsigned long width, +unsigned long height, /* width and height of rectange in pixel value */ +unsigned long rop2); /* ROP value */ + +/* + * System memory to Video memory monochrome expansion. + * Source is monochrome image in system memory. + * This function expands the monochrome data to color image in video memory. + */ +long deSystemMem2VideoMemMonoBlt( +unsigned char *pSrcbuf, /* pointer to start of source buffer in system memory */ +long srcDelta, /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */ +unsigned long startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */ +unsigned long dBase, /* Address of destination: offset in frame buffer */ +unsigned long dPitch, /* Pitch value of destination surface in BYTE */ +unsigned long bpp, /* Color depth of destination surface */ +unsigned long dx, +unsigned long dy, /* Starting coordinate of destination surface */ +unsigned long width, +unsigned long height, /* width and height of rectange in pixel value */ +unsigned long fColor, /* Foreground color (corresponding to a 1 in the monochrome data */ +unsigned long bColor, /* Background color (corresponding to a 0 in the monochrome data */ +unsigned long rop2); /* ROP value */ + +#if 0 +/* + * System memory to Video memory monochrome expansion. + * Source is the starting location of monochrome image in System memory. + * This function expands the monochrome data to color image. + * + * Note: + * This fnnction can be used to diaplay a mono-font charater to the screen. + * Input source points to the starting location of the font character. + */ +long deSystemMem2VideoMemMonoBusMasterBlt( + unsigned char *pSBase, /* Address of mono-chrome source data in frame buffer */ + unsigned long sPitch, /* Pitch value (in bytes) of the source buffer. */ + unsigned long startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */ + unsigned long dBase, /* Base address of destination in frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTE */ + unsigned long bpp, /* Color depth of destination surface */ + unsigned long dx, + unsigned long dy, /* Starting coordinate of destination surface */ + unsigned long width, /* width of mono-chrome picture in pixel value */ + unsigned long height, /* height of mono-chrome picture in pixel value */ + unsigned long fColor, /* Foreground color (corresponding to a 1 in the monochrome data */ + unsigned long bColor, /* Background color (corresponding to a 0 in the monochrome data */ + unsigned long rop2 /* ROP value */ +); +#endif + +/* + * This function cache font table into frame buffer. + * + * Inputs: + * Pointer to font table in system memory. + * Charcter size in byte: How many bytes are used to store the font for one characer. + * As an example: For 8x8 mono font, the size is 8 bytes; + * For 8x16 mono font, the size is 16 bytes. + * For 16x32 mono font, the size is 64 bytes. + * Number of characters in the font table. + * Pointer to location of frame buffer to store the font: This is an offset from the beginning of frame buffer. + * + * Rules for storing fonts in off-screen. + * 1) Base address of font table must be 16 byte (or 128 bit) aligned. + * 2) Each font character must be stored in a 16 byte (128 bit) aligned + * location. + * + */ +long deCacheFontToFrameBuffer( +unsigned char *fontTable, /* Pointer to font table in system memory */ +unsigned long sizeOfChar, /* How many bytes for one monochrome character */ +unsigned long numberOfChar, /* Number of characters in the font table */ +unsigned long fbAddr); /* Destination in Video memory to store the font */ + +/* + * Video memory to Video memory monochrome expansion. + * Source is the starting location of monochrome image in Video memory. + * This function expands the monochrome data to color image. + * + * Note: + * This fnnction can be used to diaplay a mono-font charater to the screen. + * Input source points to the starting location of the font character. + */ +long deVideoMem2VideoMemMonoBlt( +unsigned long sBase, /* Address of mono-chrome source data in frame buffer */ +unsigned long dBase, /* Base address of destination in frame buffer */ +unsigned long dPitch, /* Pitch value of destination surface in BYTE */ +unsigned long bpp, /* Color depth of destination surface */ +unsigned long dx, +unsigned long dy, /* Starting coordinate of destination surface */ +unsigned long width, /* width of mono-chrome picture in pixel value */ +unsigned long height, /* height of mono-chrome picture in pixel value */ +unsigned long fColor, /* Foreground color (corresponding to a 1 in the monochrome data */ +unsigned long bColor, /* Background color (corresponding to a 0 in the monochrome data */ +unsigned long rop2); /* ROP value */ + +/* + * Video memory to Video memory monochrome expansion. + * + * Difference between this function and deVideoMem2VideoMemMonoBlt(): + * 1) Input is base address of the whole font table. + * 2) An extra input about which character in the font table to display. + * 3) This function demos how to use registers DE_SOURCE and + * DE_WINDOW_WIDTH, where they are set to 0 in deVideoMem2VideoMemMonoBlt(). + */ +long deFontCacheTblMonoBlt( +unsigned long fontTblBase,/* Base address of monochrome font table in frame buffer */ +unsigned long fontNumber, /* Which character in the font table, starting from 0 */ +unsigned long dBase, /* Base address of destination in frame buffer */ +unsigned long dPitch, /* Pitch value of destination surface in BYTE */ +unsigned long bpp, /* Color depth of destination surface */ +unsigned long dx, +unsigned long dy, /* Starting coordinate of destination surface */ +unsigned long width, /* width of each monochrome font in pixel value */ +unsigned long height, /* height of each monochrome font in pixel value */ +unsigned long fColor, /* Foreground color (corresponding to a 1 in the monochrome data */ +unsigned long bColor, /* Background color (corresponding to a 0 in the monochrome data */ +unsigned long rop2); /* ROP value */ + +/* + * Stretch Blt. + * + * The stretch blt is done by using the CSC engine. + */ +long deStretchBlt( + unsigned long sBase, /* Source Base address */ + unsigned long sPitch, /* Source pitch value in bytes */ + unsigned long sbpp, /* Source bits per pixel */ + unsigned long sx, /* Source x coordinate */ + unsigned long sy, /* Source y coordinate */ + unsigned long sWidth, /* Width of source in pixel */ + unsigned long sHeight, /* Height of source in lines */ + unsigned long dBase, /* Destination base address */ + unsigned long dPitch, /* Destination pitch value in bytes */ + unsigned long dbpp, /* Destination bits per pixel */ + unsigned long dx, /* Destination x coordinate */ + unsigned long dy, /* Destination y coordinate */ + unsigned long dWidth, /* Width of the destination display */ + unsigned long dHeight /* Height of the destination display */ +); + +/* + * Rotation Blt. + * + * This function rotates an image to the screen based on the given rotation direction + * (0, 90, 180, or 270 degree). + * + */ +long deVideoMem2VideoMemRotateBlt( + unsigned long sBase, /* Source Base Address */ + unsigned long sPitch, /* Source pitch */ + unsigned long sx, /* X Coordinate of the source */ + unsigned long sy, /* Y Coordinate of the source */ + unsigned long dBase, /* Destination Base Address */ + unsigned long dPitch, /* Destination pitch */ + unsigned long bpp, /* Color depth of destination surface */ + unsigned long dx, /* X Coordinate of the destination */ + unsigned long dy, /* Y Coordinate of the destination */ + unsigned long width, /* Width of un-rotated image in pixel value */ + unsigned long height, /* Height of un-rotated image in pixel value */ + rotate_dir_t rotateDirection, /* Direction of the rotation */ + unsigned long repeatEnable, /* Enable repeat rotation control where the + drawing engine is started again every vsync */ + unsigned long rop2 /* ROP control */ +); + +/* + * Function to draw a vertical line. + * + * Note: + * This function is using Short Stroke line + */ +long deVerticalLine( + unsigned long dBase, /* Base address of destination surface counted from beginning of video frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTES */ + unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ + unsigned long x, /* Starting X Coordinate */ + unsigned long y, /* Starting Y Coordinate */ + unsigned long length, /* Length of the line */ + unsigned long color, /* Color of the line */ + unsigned long rop2 /* ROP value */ +); + +/* + * Function to draw a horizontal line. + * + * Note: + * This function is using Short Stroke line + */ +long deHorizontalLine( + unsigned long dBase, /* Base address of destination surface counted from beginning of video frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTES */ + unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ + unsigned long x, /* Starting X Coordinate */ + unsigned long y, /* Starting Y Coordinate */ + unsigned long length, /* Length of the line */ + unsigned long color, /* Color of the line */ + unsigned long rop2 /* ROP value */ +); + +/* + * Function to draw a line. + * + * Note: + * This function is using Short Stroke Command for Vertical, Horizontal, and + * Diagonal line. Other line are drawn using the Line Draw Command. + */ +long deLine( + unsigned long dBase, /* Base address of destination surface counted from beginning of video frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTES */ + unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ + long x0, /* Starting X Coordinate */ + long y0, /* Starting Y Coordinate */ + long x1, /* Ending X Coordinate */ + long y1, /* Ending Y Coordinate */ + unsigned long color, /* Color of the line */ + unsigned long rop2 /* ROP value */ +); + +/* + * Alpha Blend Blt. + * + * This function blends the source with the destination image. + */ +long deVideoMem2VideoMemAlphaBlendBlt( + unsigned long sBase, /* Source Base Address */ + unsigned long sPitch, /* Source pitch */ + unsigned long sx, /* X Coordinate of the source */ + unsigned long sy, /* Y Coordinate of the source */ + unsigned long sWidth, /* Source Width */ + unsigned long sHeight, /* Source Height */ + unsigned long dBase, /* Destination Base Address */ + unsigned long dPitch, /* Destination pitch */ + unsigned long bpp, /* Color depth of destination surface */ + unsigned long dx, /* X Coordinate of the destination */ + unsigned long dy, /* Y Coordinate of the destination */ + unsigned long dHeight, /* Destination Height (only height stretch is supported) */ + unsigned long alphaValue, /* Alpha value for Alpha Blend*/ + unsigned long rop2 /* ROP control */ +); + +#if 0 /* These RLE functions are not working. */ +/* + * Function to draw a line using RLE line strip method. + */ +long deStartLineStrip( + unsigned long dBase, /* Base address of destination surface counted from beginning of video frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTES */ + unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ + unsigned long x, /* X Coordinate */ + unsigned long y, /* Y Coordinate */ + unsigned long length, /* Length of the line */ + unsigned long lineCounter, /* Line Counter */ + unsigned long direction, /* Direction: 0 - Left to Right + 1 - Right to Left + 2 - Top to Bottom + 3 - Bottom to Top + */ + unsigned long color, /* Color of the line */ + unsigned long rop2 /* ROP value */ +); + +/* + * Function to continue drawing a line using RLE line strip method. + */ +long deNextLineStrip( + unsigned long length, /* Line strip length */ + unsigned long lineCounter /* Line Counter */ +); + +/* + * Function to stop the RLE line strip drawing. + * This function has to be called to end the Line Strip drawing. + * Otherwise, the next 2D function might still use this function. + */ +long deStopLineStrip(); +#endif + + +/* + * This function uses 2D engine to draw a trapezoid with a specific color. + * The filled area includes the starting points. + */ +long deStartTrapezoidFill( + unsigned long dBase, /* Base address of destination surface counted from beginning of video frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTES */ + unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ + unsigned long x, + unsigned long y, /* Starting (X, Y) coordinate inside the polygon to be filled */ + unsigned long length, /* Length of the line */ + unsigned long color, /* Color to be filled */ + unsigned long rop2); + +/* + * Function to continue drawing a line using Trapezoid Fill method. + */ +long deNextTrapezoidFill( + unsigned long x, /* Starting X location. */ + unsigned long length /* Line length */ +); + +/* + * Function to stop the Trapezoid Fill drawing. + * This function has to be called to end the Trapezoid Fill drawing. + * Otherwise, the next 2D function might still use this function. + */ +long deStopTrapezoidFill(void); + +#endif /* _2D_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_chip.c b/drivers/gpu/drm/smidrm/ddk750/ddk750_chip.c new file mode 100644 index 000000000000..ce2aaeedaa2d --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_chip.c @@ -0,0 +1,234 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* CHIP.C --- SMI DDK +* This file contains the source code for the mode table. +* +*******************************************************************/ +#include "ddk750_defs.h" +#include "ddk750_regdc.h" +#include "ddk750_helper.h" +#include "ddk750_power.h" +#include "ddk750_clock.h" +#include "ddk750_chip.h" +#include "ddk750_help.h" + +/* + * Get the default memory clock value used by this DDK + */ +unsigned long ddk750_getDefaultMemoryClock(void) +{ + switch(ddk750_getChipType()) + { + case SM718: + return DEFAULT_SM718_MEMORY_CLK; + break; + case SM750: + return DEFAULT_SM750_MEMORY_CLK; + break; + case SM750LE: + return SM750LE_MEMORY_CLK; + break; + case SM750HS_F: + return SM750HS_F_MEMORY_CLK; + break; + case SM750HS_A: + return SM750HS_A_MEMORY_CLK; + break; + case SM750HS: + default: + return SM750HS_MEMORY_CLK; + break; + } +} + +/* + * This function returns frame buffer memory size in Byte units. + */ +unsigned long ddk750_getFrameBufSize(void) +{ + unsigned long sizeSymbol, memSize; + + sizeSymbol = FIELD_GET(peekRegisterDWord(MISC_CTRL), MISC_CTRL, LOCALMEM_SIZE); + switch(sizeSymbol) + { + case MISC_CTRL_LOCALMEM_SIZE_8M: memSize = MB(8); break; /* 8 Mega byte */ + case MISC_CTRL_LOCALMEM_SIZE_16M: memSize = MB(16); break; /* 16 Mega byte */ + case MISC_CTRL_LOCALMEM_SIZE_32M: memSize = MB(32); break; /* 32 Mega byte */ + case MISC_CTRL_LOCALMEM_SIZE_64M: memSize = MB(64); break; /* 64 Mega byte */ + default: memSize = MB(0); break; /* 0 Mege byte */ + } + + return memSize; +} + + +/* + * This function returns the logical chip type defined in chip.h + * It is one of the following: SM501, SM502, SM107, SM718, SM 750 or + * SM_UNKNOWN. + */ +logical_chip_type_t ddk750_getChipType() +{ + return SM750; +} + +/* + * ddk750_resetFrameBufferMemory + * This function resets the Frame Buffer Memory + */ +void ddk750_resetFrameBufferMemory() +{ + unsigned long ulReg; + logical_chip_type_t chipType = ddk750_getChipType(); + + + /* Only SM718 and SM750 has register to reset video memory */ + if (chipType == SM718 || chipType == SM750) + { + ulReg = peekRegisterDWord(MISC_CTRL); + ulReg = FIELD_SET(ulReg, MISC_CTRL, LOCALMEM_RESET, RESET); + pokeRegisterDWord(MISC_CTRL, ulReg); + + ulReg = FIELD_SET(ulReg, MISC_CTRL, LOCALMEM_RESET, NORMAL); + pokeRegisterDWord(MISC_CTRL, ulReg); + } +} + +/* + * Initialize a single chip and environment according to input parameters. + * + * Input: initchip_param_t structure. + * + * Return: 0 (or NO_ERROR) if successful. + * -1 if fail. + * + * Note: + * Caller needs to call the detectDevice and setCurrentDevice + * to set the device before calling this initChipParamEx. + */ +long ddk750_initChipParamEx(initchip_param_t * pInitParam) +{ + unsigned long ulReg; + + + /* Set power mode. + Check parameter validity first. + If calling function didn't set it up properly or set to some + weird value, always default it to 0. + */ + if (pInitParam->powerMode > 1) + pInitParam->powerMode = 0; + setPowerMode(pInitParam->powerMode); + + /* Set the Main Chip Clock */ + setChipClock(MHz(pInitParam->chipClock)); + + /* Set up memory clock. */ + setMemoryClock(MHz(pInitParam->memClock)); + + /* Set up master clock */ + setMasterClock(MHz(pInitParam->masterClock)); + + /* Reset the memory controller. If the memory controller is not reset in SM750, + the system might hang when sw accesses the memory. + The memory should be resetted after changing the MXCLK. + */ + if (pInitParam->resetMemory == 1) + ddk750_resetFrameBufferMemory(); + + if (pInitParam->setAllEngOff == 1) + { + enable2DEngine(0); + + /* Disable Overlay, if a former application left it on */ + ulReg = peekRegisterDWord(VIDEO_DISPLAY_CTRL); + ulReg = FIELD_SET(ulReg, VIDEO_DISPLAY_CTRL, PLANE, DISABLE); + pokeRegisterDWord(VIDEO_DISPLAY_CTRL, ulReg); + + /* Disable video alpha, if a former application left it on */ + ulReg = peekRegisterDWord(VIDEO_ALPHA_DISPLAY_CTRL); + ulReg = FIELD_SET(ulReg, VIDEO_ALPHA_DISPLAY_CTRL, PLANE, DISABLE); + pokeRegisterDWord(VIDEO_ALPHA_DISPLAY_CTRL, ulReg); + + /* Disable alpha plane, if a former application left it on */ + ulReg = peekRegisterDWord(ALPHA_DISPLAY_CTRL); + ulReg = FIELD_SET(ulReg, ALPHA_DISPLAY_CTRL, PLANE, DISABLE); + pokeRegisterDWord(ALPHA_DISPLAY_CTRL, ulReg); + + /* Disable Primary hardware cursor, if a former application left it on */ + ulReg = peekRegisterDWord(PRIMARY_HWC_ADDRESS); + ulReg = FIELD_SET(ulReg, PRIMARY_HWC_ADDRESS, ENABLE, DISABLE); + pokeRegisterDWord(PRIMARY_HWC_ADDRESS, ulReg); + + /* Disable Secondary hardware cursor, if a former application left it on */ + ulReg = peekRegisterDWord(SECONDARY_HWC_ADDRESS); + ulReg = FIELD_SET(ulReg, SECONDARY_HWC_ADDRESS, ENABLE, DISABLE); + pokeRegisterDWord(SECONDARY_HWC_ADDRESS, ulReg); +#if 0 + /* Disable ZV Port 0, if a former application left it on */ + ulReg = peekRegisterDWord(ZV0_CAPTURE_CTRL); + ulReg = FIELD_SET(ulReg, ZV0_CAPTURE_CTRL, CAP, DISABLE); + pokeRegisterDWord(ZV0_CAPTURE_CTRL, ulReg); + + /* Disable ZV Port 1, if a former application left it on */ + ulReg = peekRegisterDWord(ZV1_CAPTURE_CTRL); + ulReg = FIELD_SET(ulReg, ZV1_CAPTURE_CTRL, CAP, DISABLE); + pokeRegisterDWord(ZV1_CAPTURE_CTRL, ulReg); + + /* Disable ZV Port Power, if a former application left it on */ + enableZVPort(0); + + /* Disable i2c */ + enableI2C(0); + + /* Disable DMA Channel, if a former application left it on */ + ulReg = peekRegisterDWord(DMA_ABORT_INTERRUPT); + ulReg = FIELD_SET(ulReg, DMA_ABORT_INTERRUPT, ABORT_1, ABORT); + pokeRegisterDWord(DMA_ABORT_INTERRUPT, ulReg); + + /* Disable DMA Power, if a former application left it on */ + enableDMA(0); +#endif + } + + /* We can add more initialization as needed. */ + + return 0; +} + +/* + * Initialize chip with default parameters. + * + * Input: none. + * + * Return: 0 (or NO_ERROR) if successful. + * -1 if fail. + * + * Note: + * This function initialize with a default set of parameters. + * Use initChipParam() if you don't want default parameters. + */ +long ddk750_initChip() +{ + initchip_param_t initParam; + + /* Check if any SMI VGX family chip exist and alive */ +// if (detectDevices() == 0) +// return (-1); + + /* Initialize the chip with some default parameters */ + initParam.powerMode = 0; + initParam.memClock = ddk750_getDefaultMemoryClock(); + initParam.chipClock = initParam.memClock; + initParam.masterClock = initParam.chipClock/3; + + initParam.setAllEngOff = 1; + initParam.resetMemory = 1; + + return(ddk750_initChipParamEx(&initParam)); +} \ No newline at end of file diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_chip.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_chip.h new file mode 100644 index 000000000000..94e54d75894c --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_chip.h @@ -0,0 +1,194 @@ +/******************************************************************* +* +* Copyright (c) 2008 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* CHIP.H --- SMI DDK +* This file contains the source code for the SM750/SM718 chip. +* +*******************************************************************/ +#ifndef _CHIP_H_ +#define _CHIP_H_ + +/* This is all the chips recognized by this library */ +typedef enum _logical_chip_type_t +{ + SM_UNKNOWN = 0, + SM718 = 1, + SM750 = 2, + SM750LE = 3, + /* There will 3 versions of SM750HS because of different interfaces connected to the Graphic IP. + The major difference between them are the methods to set up the PLL for pixel clock. */ + SM750HS = 4, /* SMI FPGA verification version */ + SM750HS_F = 5, /* HiS FPGA verification version */ + SM750HS_A = 6 /* HiS ASIC version */ +} +logical_chip_type_t; + +/* input struct to initChipParam() function */ +typedef struct _initchip_param_t +{ + unsigned short powerMode; /* Use power mode 0 or 1 */ + unsigned short chipClock; /* Speed of main chip clock in MHz unit + 0 = keep the current clock setting + Others = the new main chip clock + */ + unsigned short memClock; /* Speed of memory clock in MHz unit + 0 = keep the current clock setting + Others = the new memory clock + */ + unsigned short masterClock; /* Speed of master clock in MHz unit + 0 = keep the current clock setting + Others = the new master clock + */ + unsigned short setAllEngOff; /* 0 = leave all engine state untouched. + 1 = make sure they are off: 2D, Overlay, + video alpha, alpha, hardware cursors + */ + unsigned char resetMemory; /* 0 = Do not reset the memory controller + 1 = Reset the memory controller + */ + + /* More initialization parameter can be added if needed */ +} +initchip_param_t; + +/* + * Get the default memory clock value used by this DDK + */ +unsigned long ddk750_getDefaultMemoryClock(void); + +/* + * This function returns frame buffer memory size in Byte units. + */ +unsigned long ddk750_getFrameBufSize(void); + +/* + * This function gets the Frame buffer location. + */ +unsigned char ddk750_getFrameBufLocation(void); + +/* + * This function returns the logical chip type defined in chip.h + * It is one of the following: SM501, SM502, SM107, SM718, SM 750 or + * SM_UNKNOWN. + */ +logical_chip_type_t ddk750_getChipType(void); + +/* + * Return a char string name of the current chip. + * It's convenient for application need to display the chip name. + */ +char * ddk750_getChipTypeString(void); + +/* + * resetFrameBufferMemory + * This function resets the Frame Buffer Memory + */ +void ddk750_resetFrameBufferMemory(void); + +/* + * Initialize a single chip and environment according to input parameters. + * + * Input: initchip_param_t structure. + * + * Return: 0 (or NO_ERROR) if successful. + * -1 if fail. + * + * Note: + * Caller needs to call the detectDevice and setCurrentDevice + * to set the device before calling this initChipParamEx. + */ +long ddk750_initChipParamEx(initchip_param_t * pInitParam); + +/* + * Initialize every chip and environment according to input parameters. + * (Obsolete) + * + * Input: initchip_param_t structure. + * + * Return: 0 (or NO_ERROR) if successful. + * -1 if fail. + */ +long ddk750_initChipParam(initchip_param_t * pInitParam); + +/* + * Initialize a single chip with default parameters. + * + * Input: none. + * + * Return: 0 (or NO_ERROR) if successful. + * -1 if fail. + * + * Note: + * Caller needs to call the detectDevice and setCurrentDevice + * to set the device before calling this initChipEx. + */ +long ddk750_initChipEx(void); + +/* + * Initialize the chip with default parameters. + * + * Input: none. + * + * Return: 0 (or NO_ERROR) if successful. + * -1 if fail. + */ +long ddk750_initChip(void); + +/******************************************************************* + * Scratch Data implementation (To be used by DDK library only) + *******************************************************************/ + +/* + * Set Scratch Data + */ +void setScratchData( + unsigned long dataFlag, + unsigned long data +); + +/* + * Get Scratch Data + */ +unsigned long getScratchData( + unsigned long dataFlag +); + + +#define MB(x) (x*0x100000) /* Don't use this macro if x is fraction number */ + +/* Memory Clock Default Values */ +#define DEFAULT_SM750_MEMORY_CLK 290 +#define DEFAULT_SM718_MEMORY_CLK 290 + +/* Cheok_0509: Define some fixed values for SM750LE */ +#define SM750LE_REVISION_ID 0XFE +#define SM750LE_MEMORY_CLK 333 /* In MHz */ +#define SM750LE_MASTER_CLK 130 /* in MHz */ +#define SM750LE_MEM_SIZE MB(16) /* SP605 has 64M, but Huawei's actual system has only 16M */ +#define SM750LE_I2C_SCL 0 /* GPIO 0 is used as I2C clk */ +#define SM750LE_I2C_SDA 1 /* GPIO 1 is used as I2C data */ +#define CH7301_I2C_ADDRESS 0xEC /* I2C address of CH7301 in Xilinx SP605 */ + +/* Cheok_2012_1211: Define some fixed values for SM750HS */ +/* The following values are fixed in FPGA and cannot be adjusted */ +#define SM750HS_REVISION_ID 0XE0 +#define SM750HS_MEMORY_CLK 333 /* In MHz */ +#define SM750HS_MASTER_CLK 100 /* in MHz */ +#define SM750HS_MEM_SIZE MB(16) /* Actual size unknown at the moment */ + +#define SM750HS_F_REVISION_ID 0X00 +#define SM750HS_F_MEMORY_CLK 333 /* In MHz */ +#define SM750HS_F_MASTER_CLK 100 /* in MHz */ +#define SM750HS_F_MEM_SIZE MB(16) /* Actual size unknown at the moment */ + +#define SM750HS_A_REVISION_ID 0X10 +#define SM750HS_A_MEMORY_CLK 333 /* In MHz */ +#define SM750HS_A_MASTER_CLK 100 /* in MHz */ +#define SM750HS_A_MEM_SIZE MB(16) /* Actual size unknown at the moment */ + +#endif /* _CHIP_H_ */ + diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_clock.c b/drivers/gpu/drm/smidrm/ddk750/ddk750_clock.c new file mode 100644 index 000000000000..565af8b37063 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_clock.c @@ -0,0 +1,564 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* CLOCK.C --- Voyager GX DDK +* This file contains source code for the Voyager Family PLL's +* +*******************************************************************/ +#include "ddk750_defs.h" +//#include "ddk750_hardware.h" +#include "ddk750_helper.h" +#include "ddk750_power.h" +#include "ddk750_clock.h" +#include "ddk750_chip.h" +#include "ddk750_helper.h" +#include "ddk750_help.h" + +//#include "ddkdebug.h" + +static unsigned char g_ucMemoryClockDivider[] = { 1, 2, 3, 4 }; +static unsigned char g_ucMasterClockDivider[] = { 3, 4, 6, 8 }; + +/* + * A local function to calculate the clock value of the given PLL. + * + * Input: + * Pointer to a PLL structure to be calculated based on the + * following formula: + * inputFreq * M / N / (2 to the power of OD) / (2 to the power of POD) + */ +unsigned long calcPLL(pll_value_t *pPLL) +{ + return (pPLL->inputFreq * pPLL->M / pPLL->N / twoToPowerOfx(pPLL->OD) / twoToPowerOfx(pPLL->POD)); +} + +/* + * Given a requested clock frequency, this function calculates the + * best M, N & OD values for the PLL. + * + * Input: Requested pixel clock in Hz unit. + * The followiing fields of PLL has to be set up properly: + * pPLL->clockType, pPLL->inputFreq. + * + * Output: Update the PLL structure with the proper M, N and OD values + * Return: The actual clock in Hz that the PLL is able to set up. + * + * The PLL uses this formula to operate: + * requestClk = inputFreq * M / N / (2 to the power of OD) / (2 to the power of POD) + * + * The PLL specification mention the following restrictions: + * 1 MHz <= inputFrequency / N <= 25 MHz + * 200 MHz <= outputFrequency <= 1000 MHz --> However, it seems that it can + * be set to lower than 200 MHz. + */ +unsigned long calcPllValue( +unsigned long ulRequestClk, /* Required pixel clock in Hz unit */ +pll_value_t *pPLL /* Structure to hold the value to be set in PLL */ +) +{ + unsigned long M, N, OD, POD = 0, diff, pllClk, odPower, podPower, tempRequestClk; + unsigned long bestDiff = 0xffffffff; /* biggest 32 bit unsigned number */ + + /* Init PLL structure to know states */ + pPLL->M = 0; + pPLL->N = 0; + pPLL->OD = 0; + pPLL->POD = 0; + + //if (getChipType() == SM750LE) + if (ddk750_getChipType() >= SM750LE) + { + /* SM750LE don't have prgrammable PLL and M/N values to work on. + Just return the requested clock. */ + return ulRequestClk; + } + + /* Convert everything in Khz range in order to avoid calculation overflow */ + pPLL->inputFreq /= 1000; + tempRequestClk = ulRequestClk / 1000; + + /* If the requested clock is higher than 1 GHz, then set it to the maximum, which is + 1 GHz. */ + if (tempRequestClk > MHz(1)) + tempRequestClk = MHz(1); + + /* The maximum of post divider is 8. */ + for (POD=0; POD<=3; POD++) + { + /* MXCLK_PLL does not have post divider. */ + if ((POD > 0) && (pPLL->clockType == MXCLK_PLL)) + break; + + /* Work out 2 to the power of POD */ + podPower = twoToPowerOfx(POD); + + /* OD has only 2 bits [15:14] and its value must between 0 to 3 */ + for (OD=0; OD<=3; OD++) + { + /* Work out 2 to the power of OD */ + odPower = twoToPowerOfx(OD); + + /* N has 4 bits [11:8] and its value must between 2 and 15. + The N == 1 will behave differently --> Result is not correct. */ + for (N=2; N<=15; N++) + { + /* The formula for PLL is ulRequestClk = inputFreq * M / N / (2^OD) + In the following steps, we try to work out a best M value given the others are known. + To avoid decimal calculation, we use 1000 as multiplier for up to 3 decimal places of accuracy. + */ + M = tempRequestClk * N * odPower * podPower / pPLL->inputFreq; + + /* M field has only 8 bits, reject value bigger than 8 bits */ + if (M < 256) + { + /* Calculate the actual clock for a given M & N */ + pllClk = pPLL->inputFreq * M / N / odPower / podPower; + + /* How much are we different from the requirement */ + diff = absDiff(pllClk, tempRequestClk); + + if (diff < bestDiff) + { + bestDiff = diff; + + /* Store M and N values */ + pPLL->M = M; + pPLL->N = N; + pPLL->OD = OD; + pPLL->POD = POD; + } + } + } + } + } + + /* Restore input frequency from Khz to hz unit */ + pPLL->inputFreq *= 1000; + + /* Output debug information */ +// DDKDEBUGPRINT((DISPLAY_LEVEL, "calcPllValue: Requested Frequency = %d\n", ulRequestClk)); +// DDKDEBUGPRINT((DISPLAY_LEVEL, "calcPllValue: Input CLK = %dHz, M=%d, N=%d, OD=%d, POD=%d\n", pPLL->inputFreq, pPLL->M, pPLL->N, pPLL->OD, pPLL->POD)); + + /* Return actual frequency that the PLL can set */ + return calcPLL(pPLL); +} + +/* + * Set up the corresponding bit field of the programmable PLL register. + * + * Input: Pointer to PLL structure with type and values set up properly. + * Usually, calcPllValue() function will be called before this to calculate the values first. + * + */ +unsigned long formatPllReg(pll_value_t *pPLL) +{ + unsigned long ulPllReg = 0; + + /* Note that all PLL's have the same format. Here, we just use Panel PLL parameter + to work out the bit fields in the register. + On returning a 32 bit number, the value can be applied to any PLL in the calling function. + */ + ulPllReg = + FIELD_SET( 0, PRIMARY_PLL_CTRL, BYPASS, OFF) + | FIELD_SET( 0, PRIMARY_PLL_CTRL, POWER, ON) + | FIELD_SET( 0, PRIMARY_PLL_CTRL, INPUT, OSC) + | FIELD_VALUE(0, PRIMARY_PLL_CTRL, POD, pPLL->POD) + | FIELD_VALUE(0, PRIMARY_PLL_CTRL, OD, pPLL->OD) + | FIELD_VALUE(0, PRIMARY_PLL_CTRL, N, pPLL->N) + | FIELD_VALUE(0, PRIMARY_PLL_CTRL, M, pPLL->M); + + // DDKDEBUGPRINT((DISPLAY_LEVEL, "formatPllReg: PLL register value = 0x%08x\n", ulPllReg)); + + return(ulPllReg); +} + +/* + * Get the programmable PLL register value. + * + * Input: + * clockType - The clock Type that the PLL is associated with. + * pPLL - Pointer to a PLL structure to be filled with the + * PLL value read from the register. + * Output: + * The actual clock value calculated, together with the values of + * PLL register stored in the pPLL pointer. + */ +unsigned long getPllValue(clock_type_t clockType, pll_value_t *pPLL) +{ + unsigned long ulPllReg = 0; + + pPLL->inputFreq = DEFAULT_INPUT_CLOCK; + pPLL->clockType = clockType; + + switch (clockType) + { + case MXCLK_PLL: + ulPllReg = peekRegisterDWord(MXCLK_PLL_CTRL); + break; + case PRIMARY_PLL: + ulPllReg = peekRegisterDWord(PRIMARY_PLL_CTRL); + break; + case SECONDARY_PLL: + ulPllReg = peekRegisterDWord(SECONDARY_PLL_CTRL); + break; + case VGA0_PLL: + ulPllReg = peekRegisterDWord(VGA_PLL0_CTRL); + break; + case VGA1_PLL: + ulPllReg = peekRegisterDWord(VGA_PLL1_CTRL); + break; + } + + pPLL->M = FIELD_GET(ulPllReg, PRIMARY_PLL_CTRL, M); + pPLL->N = FIELD_GET(ulPllReg, PRIMARY_PLL_CTRL, N); + pPLL->OD = FIELD_GET(ulPllReg, PRIMARY_PLL_CTRL, OD); + pPLL->POD = FIELD_GET(ulPllReg, PRIMARY_PLL_CTRL, POD); + + return calcPLL(pPLL); +} + +/* + * This function set up the main chip clock. + * + * Input: Frequency to be set. + */ +void setChipClock(unsigned long frequency) +{ + pll_value_t pll; + unsigned long ulActualMxClk; + +#if 1 + /* Cheok_0509: For SM750LE, the chip clock is fixed. Nothing to set. */ + //if (getChipType() == SM750LE) + if (ddk750_getChipType() >= SM750LE) + return; +#endif + + if (frequency != 0) + { + /* + * Set up PLL, a structure to hold the value to be set in clocks. + */ + pll.inputFreq = DEFAULT_INPUT_CLOCK; /* Defined in CLOCK.H */ + pll.clockType = MXCLK_PLL; + + /* + * Call calcPllValue() to fill up the other fields for PLL structure. + * Sometime, the chip cannot set up the exact clock required by User. + * Return value from calcPllValue() gives the actual possible clock. + */ + // DDKDEBUGPRINT((INIT_LEVEL, "setMemoryClock: frequency = 0x%08x\n", frequency)); + ulActualMxClk = calcPllValue(frequency, &pll); + // DDKDEBUGPRINT((INIT_LEVEL, "setMemoryClock: Current Clock = 0x%08x\n", ulActualMxClk)); + + /* Master Clock Control: MXCLK_PLL */ + pokeRegisterDWord(MXCLK_PLL_CTRL, formatPllReg(&pll)); + } +} + +/* + * This function gets the Main Chip Clock value. + * + * Output: + * The Actual Main Chip clock value. + */ +unsigned long getChipClock() +{ + pll_value_t pll; + +#if 1 + /* Cheok_0509: For SM750LE, the chip clock is fixed */ + //if (getChipType() == SM750LE) + if (ddk750_getChipType() >= SM750LE) + return (MHz(SM750LE_MASTER_CLK)); +#endif + + return getPllValue(MXCLK_PLL, &pll); +} + +/* + * This function set up the memory clock. + * + * Input: Frequency to be set. + * + * NOTE: + * The maximum frequency that the DDR Memory clock can be set is 336MHz. + */ +void setMemoryClock(unsigned long frequency) +{ + unsigned long ulReg, divisor; + +#if 1 + /* Cheok_0509: For SM750LE, the memory clock is fixed. Nothing to set. */ + //if (getChipType() == SM750LE) + if (ddk750_getChipType() >= SM750LE) + return; +#endif + + if (frequency != 0) + { + /* Set the frequency to the maximum frequency that the DDR Memory can take + which is 336MHz. */ + if (frequency > MHz(336)) + frequency = MHz(336); + + /* Calculate the divisor */ + divisor = (unsigned long) roundedDiv(getChipClock(), frequency); + + /* Set the corresponding divisor in the register. */ + ulReg = peekRegisterDWord(CURRENT_GATE); + switch(divisor) + { + default: + case 1: + ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_1); + break; + case 2: + ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_2); + break; + case 3: + ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_3); + break; + case 4: + ulReg = FIELD_SET(ulReg, CURRENT_GATE, M2XCLK, DIV_4); + break; + } + + setCurrentGate(ulReg); + } +} + +/* + * This function set up the master clock (MCLK). + * + * Input: Frequency to be set. + * + * NOTE: + * The maximum frequency the engine can run is 168MHz. + */ +void setMasterClock(unsigned long frequency) +{ + unsigned long ulReg, divisor; + +#if 1 + /* Cheok_0509: For SM750LE, the master clock is fixed. Nothing to set. */ + //if (getChipType() == SM750LE) + if (ddk750_getChipType() >= SM750LE) + return; +#endif + + if (frequency != 0) + { + /* Set the frequency to the maximum frequency that the SM750 engine can + run, which is about 190 MHz. */ + if (frequency > MHz(190)) + frequency = MHz(190); + + /* Calculate the divisor */ + divisor = (unsigned long) roundedDiv(getChipClock(), frequency); + + /* Set the corresponding divisor in the register. */ + ulReg = peekRegisterDWord(CURRENT_GATE); + switch(divisor) + { + default: + case 3: + ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_3); + break; + case 4: + ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_4); + break; + case 6: + ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_6); + break; + case 8: + ulReg = FIELD_SET(ulReg, CURRENT_GATE, MCLK, DIV_8); + break; + } + + setCurrentGate(ulReg); + } +} + +/* + * This function get the Primary Display Control Pixel Clock value. + * + * Output: + * The Primary Display Control Pixel Clock value in whole number. + */ +unsigned long getPrimaryDispCtrlClock() +{ + pll_value_t pll; + return getPllValue(PRIMARY_PLL, &pll); +} + +/* + * This function get the Secondary Display Control Pixel Clock value. + * + * Output: + * The Secondary Display Control Pixel Clock value in whole number. + */ +unsigned long getSecondaryDispCtrlClock() +{ + pll_value_t pll; + return getPllValue(SECONDARY_PLL, &pll); +} + +/* + * This function gets the Master Clock value. + * + * Output: + * The Master Clock value in whole number. + */ +unsigned long getMasterClock() +{ + unsigned long value, divisor; + +#if 1 + /* Cheok_0509: For SM750LE, the chip clock is fixed */ + //if (getChipType() == SM750LE) + if (ddk750_getChipType() >= SM750LE) + return(MHz(SM750LE_MASTER_CLK)); +#endif + + /* Get the divisor */ + value = peekRegisterDWord(CURRENT_GATE); + switch (FIELD_GET(value, CURRENT_GATE, MCLK)) + { + case CURRENT_GATE_MCLK_DIV_3: + divisor = 3; + break; + case CURRENT_GATE_MCLK_DIV_4: + divisor = 4; + break; + case CURRENT_GATE_MCLK_DIV_6: + divisor = 6; + break; + case CURRENT_GATE_MCLK_DIV_8: + divisor = 8; + break; + } + + return (getChipClock() / divisor); +} + +/* + * This function gets the Memory Clock value. + * + * Output: + * The Memory Clock value in whole number. + */ +unsigned long getMemoryClock() +{ + unsigned long value, divisor; + +#if 1 + /* Cheok_0509: For SM750LE, the memory clock is fixed. */ + //if (getChipType() == SM750LE) + if (ddk750_getChipType() >= SM750LE) + return (MHz(SM750LE_MEMORY_CLK)); +#endif + + /* Get the divisor */ + value = peekRegisterDWord(CURRENT_GATE); + switch (FIELD_GET(value, CURRENT_GATE, M2XCLK)) + { + case CURRENT_GATE_M2XCLK_DIV_1: + divisor = 1; + break; + case CURRENT_GATE_M2XCLK_DIV_2: + divisor = 2; + break; + case CURRENT_GATE_M2XCLK_DIV_3: + divisor = 3; + break; + case CURRENT_GATE_M2XCLK_DIV_4: + divisor = 4; + break; + } + + return (getChipClock() / divisor); +} + +/* + * This function gets the Master Clock Divider Values List. + * + * Output: + * The list of Master Clock divider values. + */ +unsigned char *getMasterClockDivider() +{ + return g_ucMasterClockDivider; +} + +/* + * This function gets the total number of Master Clock Divider Values. + */ +unsigned long getTotalMasterClockDivider() +{ + return (sizeof(g_ucMasterClockDivider)/sizeof(unsigned char)); +} + +/* + * This function gets the Memory Clock Divider Values List. + * + * Output: + * The list of Memory Clock divider values. + */ +unsigned char *getMemoryClockDivider() +{ + return g_ucMemoryClockDivider; +} + +/* + * This function gets the total number of Memory Clock Divider Values. + */ +unsigned long getTotalMemoryClockDivider() +{ + return (sizeof(g_ucMemoryClockDivider)/sizeof(unsigned char)); +} + +/* + * This function uses the Master Clock PLL clock counter to provide some delay in ms. + */ +void waitMasterClock( + unsigned long miliseconds +) +{ + unsigned long totalClockCount, startCount, endCount, diff, value; + + /* Calculate the clock counter needed for the delay */ + totalClockCount = roundedDiv(getMasterClock(), 1000) * miliseconds; + + /* Enable PLL Clock Count*/ + pokeRegisterDWord(MISC_CTRL, FIELD_SET(peekRegisterDWord(MISC_CTRL), MISC_CTRL, PLL_CLK_COUNT, ON)); + + /* Start the counter */ + endCount = 0; + while (totalClockCount > 0) + { + startCount = endCount; + value = FIELD_GET(peekRegisterDWord(PLL_CLK_COUNT), PLL_CLK_COUNT, COUNTER); + endCount = value; + + /* Check if the counter has overflown */ + if (startCount > endCount) + endCount += 0x10000; + + /* Find the counter difference from last to start counter. */ + diff = endCount - startCount; + + /* Decrement the total clock counter with the difference until it reaches 0. */ + if (totalClockCount > diff) + totalClockCount -= diff; + else + totalClockCount = 0; + } + + /* Disable the PLL Clock Count to reset the counter the next time this function is called. */ + pokeRegisterDWord(MISC_CTRL, FIELD_SET(peekRegisterDWord(MISC_CTRL), MISC_CTRL, PLL_CLK_COUNT, OFF)); +} diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_clock.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_clock.h new file mode 100644 index 000000000000..6c880450526d --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_clock.h @@ -0,0 +1,178 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* CLOCK.H --- Voyager GX DDK +* +*******************************************************************/ +#ifndef _CLOCK_H_ +#define _CLOCK_H_ + +#define DEFAULT_INPUT_CLOCK 14318181 /* Default reference clock */ +#define MHz(x) (x*1000000) /* Don't use this macro if x is fraction number */ + +/* The following maximum value is not the optimum value. */ +/* Maximum Master Clock is about 190MHz */ +#define MAXIMUM_MASTER_CLOCK MHz(190) + +/* Maximum Chip Clock (MXCLK) is 1 GHz */ +#define MAXIMUM_CHIP_CLOCK MHz(1000) + +typedef enum _clock_type_t +{ + MXCLK_PLL, /* Programmable Master clock */ + PRIMARY_PLL, /* Programmable Primary pixel clock */ + SECONDARY_PLL, /* Programmable Secondary pixel clock */ + VGA0_PLL, + VGA1_PLL, +} +clock_type_t; + +typedef struct pll_value_t +{ + clock_type_t clockType; + unsigned long inputFreq; /* Input clock frequency to the PLL */ + unsigned long M; + unsigned long N; + unsigned long OD; + unsigned long POD; +} +pll_value_t; + +/* + * Given a requested clock frequency, this function calculates the + * best M, N & OD values for the PLL. + * + * Input: Requested pixel clock in Hz unit. + * The followiing fields of PLL has to be set up properly: + * pPLL->clockType, pPLL->inputFreq. + * + * Output: Update the PLL structure with the proper N, N and OD values + * Return: The actual clock in Hz that the PLL is able to set up. + * + * The PLL uses this formula to operate: + * requestClk = inputFreq * M / N / (2 to the power of OD) + * + */ +unsigned long calcPllValue( +unsigned long ulRequestClk, /* Required pixel clock in Hz unit */ +pll_value_t *pPLL /* Structure to hold the value to be set in PLL */ +); + +/* + * Set up the corresponding bit field of the programmable PLL register. + * + * Input: Pointer to PLL structure with type and values set up properly. + * Usually, calcPllValue() function will be called before this to calculate the values first. + * + */ +unsigned long formatPllReg(pll_value_t *pPLL); + +/* + * This function set up the main chip clock. + * + * Input: Frequency to be set. + */ +void setChipClock(unsigned long frequency); + +/* + * This function gets the Main Chip Clock value. + * + * Output: + * The Actual Main Chip clock value. + */ +unsigned long getChipClock(void); + +/* + * This function set up the memory clock. + * + * Input: Frequency to be set. + */ +void setMemoryClock(unsigned long frequency); + +/* + * getMemoryClock + * This function gets the Memory Clock value. + * + * Output: + * The Memory Clock value in whole number. + */ +unsigned long getMemoryClock(void); + +/* + * This function set up the master clock (MCLK). + * + * Input: Frequency to be set. + */ +void setMasterClock(unsigned long frequency); + +/* + * getMasterClock + * This function gets the Master Clock value. + * + * Output: + * The Master Clock value in whole number. + */ +unsigned long getMasterClock(void); + +/* + * This function get the Primary display control Pixel Clock value. + * + * Output: + * The Primary display control Pixel Clock value in whole number. + */ +unsigned long getPrimaryDispCtrlClock(void); + +/* + * This function get the Secondary display control Pixel Clock value. + * + * Output: + * The Secondary display control Pixel Clock value in whole number. + */ +unsigned long getSecondaryDispCtrlClock(void); + +/* + * This function gets the Master Clock Divider Values List. + * + * Output: + * The list of Master Clock divider values. + */ +unsigned char *getMasterClockDivider(void); + +/* + * This function gets the total number of Master Clock Divider Values. + */ +unsigned long getTotalMasterClockDivider(void); + +/* + * This function gets the Memory Clock Divider Values List. + * + * Output: + * The list of Memory Clock divider values. + */ +unsigned char *getMemoryClockDivider(void); + +/* + * This function gets the total number of Memory Clock Divider Values. + */ +unsigned long getTotalMemoryClockDivider(void); + +/* + * This function uses the Master Clock PLL clock counter to provide some delay in ms. + */ +void waitMasterClock( + unsigned long miliseconds +); + +/* + * This function provides new logic to program the PLL registers for HiSilicon ASIC. + * + * Input: + * The value of HiSilicon PLL register. + */ +void setVclock_HiSilicon(unsigned long pll); + +#endif /*_CLOCK_H_*/ diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_cursor.c b/drivers/gpu/drm/smidrm/ddk750/ddk750_cursor.c new file mode 100644 index 000000000000..146c473a6303 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_cursor.c @@ -0,0 +1,104 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* CURSOR.C --- Voyager GX SDK +* This file contains the definitions for the Panel cursor functions. +* +*******************************************************************/ +#include "ddk750_defs.h" +#include "ddk750_hardware.h" +#include "ddk750_cursor.h" +#include "ddk750_help.h" +/* + * This function initializes the cursor attributes. + */ +void ddk750_initCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long base, /* Base Address */ + unsigned long color1, /* Cursor color 1 in RGB 5:6:5 format */ + unsigned long color2, /* Cursor color 2 in RGB 5:6:5 format */ + unsigned long color3 /* Cursor color 3 in RGB 5:6:5 format */ +) +{ + /* + * 1. Set the cursor source address + */ + pokeRegisterDWord( + (dispControl == CHANNEL0_CTRL) ? PRIMARY_HWC_ADDRESS : SECONDARY_HWC_ADDRESS, + FIELD_SET(0, PRIMARY_HWC_ADDRESS, EXT, LOCAL) | + FIELD_VALUE(0, PRIMARY_HWC_ADDRESS, ADDRESS, base)); + + /* + * 2. Set the cursor color composition + */ + pokeRegisterDWord( + (dispControl == CHANNEL0_CTRL) ? PRIMARY_HWC_COLOR_12 : SECONDARY_HWC_COLOR_12, + FIELD_VALUE(0, PRIMARY_HWC_COLOR_12, 1_RGB565, color1) | + FIELD_VALUE(0, PRIMARY_HWC_COLOR_12, 2_RGB565, color2) ); + + pokeRegisterDWord( + (dispControl == CHANNEL0_CTRL) ? PRIMARY_HWC_COLOR_3 : SECONDARY_HWC_COLOR_3, + FIELD_VALUE(0, PRIMARY_HWC_COLOR_3, RGB565, color3)); +} + +/* + * This function sets the cursor position. + */ +void ddk750_setCursorPosition( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long dx, /* X Coordinate of the cursor */ + unsigned long dy, /* Y Coordinate of the cursor */ + unsigned char topOutside, /* Top Boundary Select: either partially outside (= 1) + or within the screen top boundary (= 0) */ + unsigned char leftOutside /* Left Boundary Select: either partially outside (= 1) + or within the screen left boundary (= 0) */ +) +{ + unsigned long value; + + /* Set the XY coordinate */ + value = FIELD_VALUE(0, PRIMARY_HWC_LOCATION, X, dx) | + FIELD_VALUE(0, PRIMARY_HWC_LOCATION, Y, dy); + + /* Set the top boundary select either partially outside the top boundary + screen or inside */ + if (topOutside) + value = FIELD_SET(value, PRIMARY_HWC_LOCATION, TOP, OUTSIDE); + else + value = FIELD_SET(value, PRIMARY_HWC_LOCATION, TOP, INSIDE); + + /* Set the left boundary select either partially outside the left boundary + screen or inside */ + if (leftOutside) + value = FIELD_SET(value, PRIMARY_HWC_LOCATION, LEFT, OUTSIDE); + else + value = FIELD_SET(value, PRIMARY_HWC_LOCATION, LEFT, INSIDE); + + /* Set the register accordingly, either Panel cursor or CRT cursor */ + pokeRegisterDWord((dispControl == CHANNEL0_CTRL) ? PRIMARY_HWC_LOCATION : SECONDARY_HWC_LOCATION, value); +} + +/* + * This function enables/disables the cursor. + */ +void ddk750_enableCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long enable +) +{ + unsigned long cursorRegister, value; + + cursorRegister = (dispControl == CHANNEL0_CTRL) ? PRIMARY_HWC_ADDRESS : SECONDARY_HWC_ADDRESS; + + value = peekRegisterDWord(cursorRegister); + if (enable) + value = FIELD_SET(value, PRIMARY_HWC_ADDRESS, ENABLE, ENABLE); + else + value = FIELD_SET(value, PRIMARY_HWC_ADDRESS, ENABLE, DISABLE); + + pokeRegisterDWord(cursorRegister, value); +} diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_cursor.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_cursor.h new file mode 100644 index 000000000000..69f219245511 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_cursor.h @@ -0,0 +1,48 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* cursor.h --- SMI DDK +* This file contains the definitions for the cursor functions. +* +*******************************************************************/ +#ifndef _CURSOR_H_ +#define _CURSOR_H_ + +#include "ddk750_mode.h" +/* + * This function initializes the cursor attributes. + */ +void ddk750_initCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long base, /* Base Address */ + unsigned long color1, /* Cursor color 1 in RGB 5:6:5 format */ + unsigned long color2, /* Cursor color 2 in RGB 5:6:5 format */ + unsigned long color3 /* Cursor color 3 in RGB 5:6:5 format */ +); + +/* + * This function sets the cursor position. + */ +void ddk750_setCursorPosition( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long dx, /* X Coordinate of the cursor */ + unsigned long dy, /* Y Coordinate of the cursor */ + unsigned char topOutside, /* Top Boundary Select: either partially outside (= 1) + or within the screen top boundary (= 0) */ + unsigned char leftOutside /* Left Boundary Select: either partially outside (= 1) + or within the screen left boundary (= 0) */ +); + +/* + * This function enables/disables the cursor. + */ +void ddk750_enableCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long enable +); + +#endif /* _CURSOR_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_defs.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_defs.h new file mode 100644 index 000000000000..78a12f069cec --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_defs.h @@ -0,0 +1,83 @@ +/******************************************************************* +* +* Copyright (c) 2008 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* DEFS.H (The name of this file is defs.h in 718 DDK) +* This file contains register and common macro definitions. +* +*******************************************************************/ +#ifndef _DEFS_H_ +#define _DEFS_H_ + +/* For validation purpose only */ +/*#define SM750_AA*/ +//#include "ddk750_help.h" +#include "ddk750_regsc.h" +#include "ddk750_reggpio.h" +//#include "ddk750_regpwm.h" +//#include "ddk750_regssp.h" +#include "ddk750_regdc.h" +//#include "ddk750_regdma.h" +//#include "ddk750_regde.h" +//#include "ddk750_regzv.h" +#include "ddk750_regi2c.h" + +/* Internal macros */ +#define _F_START(f) (0 ? f) +#define _F_END(f) (1 ? f) +#define _F_SIZE(f) (1 + _F_END(f) - _F_START(f)) +#define _F_MASK(f) (((1 << _F_SIZE(f)) - 1) << _F_START(f)) +#define _F_NORMALIZE(v, f) (((v) & _F_MASK(f)) >> _F_START(f)) +#define _F_DENORMALIZE(v, f) (((v) << _F_START(f)) & _F_MASK(f)) + +/* Global macros */ +#define FIELD_GET(x, reg, field) \ +( \ + _F_NORMALIZE((x), reg ## _ ## field) \ +) + +#define FIELD_SET(x, reg, field, value) \ +( \ + (x & ~_F_MASK(reg ## _ ## field)) \ + | _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \ +) + +#define FIELD_VALUE(x, reg, field, value) \ +( \ + (x & ~_F_MASK(reg ## _ ## field)) \ + | _F_DENORMALIZE(value, reg ## _ ## field) \ +) + +#define FIELD_CLEAR(reg, field) \ +( \ + ~ _F_MASK(reg ## _ ## field) \ +) + +/* FIELD MACROS */ +#define FIELD_START(field) (0 ? field) +#define FIELD_END(field) (1 ? field) +#define FIELD_SIZE(field) (1 + FIELD_END(field) - FIELD_START(field)) +#define FIELD_MASK(field) (((1 << (FIELD_SIZE(field)-1)) | ((1 << (FIELD_SIZE(field)-1)) - 1)) << FIELD_START(field)) +#define FIELD_NORMALIZE(reg, field) (((reg) & FIELD_MASK(field)) >> FIELD_START(field)) +#define FIELD_DENORMALIZE(field, value) (((value) << FIELD_START(field)) & FIELD_MASK(field)) +#define FIELD_INIT(reg, field, value) FIELD_DENORMALIZE(reg ## _ ## field, \ + reg ## _ ## field ## _ ## value) +#define FIELD_INIT_VAL(reg, field, value) \ + (FIELD_DENORMALIZE(reg ## _ ## field, value)) +#define FIELD_VAL_SET(x, r, f, v) x = x & ~FIELD_MASK(r ## _ ## f) \ + | FIELD_DENORMALIZE(r ## _ ## f, r ## _ ## f ## _ ## v) + +#define RGB(r, g, b) \ +( \ + (unsigned long) (((r) << 16) | ((g) << 8) | (b)) \ +) + +#define RGB16(r, g, b) \ +( \ + (unsigned short) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | (((b) & 0xF8) >> 3)) \ +) + +#endif /* _DEFS_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_display.c b/drivers/gpu/drm/smidrm/ddk750/ddk750_display.c new file mode 100644 index 000000000000..ddbe6876af69 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_display.c @@ -0,0 +1,1702 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* DISPLAY.C --- Voyager GX SDK +* This file contains the source code for the panel and CRT functions. +* +*******************************************************************/ +#include "ddk750_defs.h" +#include "ddk750_hardware.h" +#include "ddk750_chip.h" +//#include "ddk750/ddk750_swi2c.h" +#include "ddk750_display.h" +//#include "ddk750/ddk750_dvi.h" +#include "ddk750_power.h" +#include "ddk750_help.h" + +#define Validate_718_AA 1 + +/* When use actual Panel, then do not need to turn on the DAC. */ +#define ENABLE_PANEL_DAC + +/* Monitor Detection RGB Default Threshold values */ +#define DEFAULT_MON_DETECTION_THRESHOLD 0x64 + + +/* + * This function checks whether dual panel is enabled or not + * + * Output: + * 0 - Not Enable + * 1 - Enable + */ +unsigned char isDualPanelEnable(void) +{ + unsigned long value; + + value = FIELD_GET(peekRegisterDWord(PRIMARY_DISPLAY_CTRL), PRIMARY_DISPLAY_CTRL, DUAL_DISPLAY); + + return ((value == PRIMARY_DISPLAY_CTRL_DUAL_DISPLAY_ENABLE) ? 1 : 0); +} + +/* + * This function gets the panel type + * + * Output: + * panelType - The type of the panel to be set + */ +panel_type_t getPanelType(void) +{ + if (FIELD_GET(peekRegisterDWord(PRIMARY_DISPLAY_CTRL), PRIMARY_DISPLAY_CTRL, DOUBLE_PIXEL) == + PRIMARY_DISPLAY_CTRL_DOUBLE_PIXEL_ENABLE) + { + return TFT_36BIT; + } + else if (isDualPanelEnable() == 1) + return TFT_18BIT; + else + return TFT_24BIT; +} + +/* + * This function sets the panel type + * + * Input: + * panelType - The type of the panel to be set + */ +long setPanelType( + panel_type_t panelType +) +{ + unsigned long value; + + /* Set the panel type. */ + value = peekRegisterDWord(PRIMARY_DISPLAY_CTRL); + switch (panelType) + { + case TFT_18BIT: + value = FIELD_SET(value, PRIMARY_DISPLAY_CTRL, DUAL_DISPLAY, ENABLE); + value = FIELD_SET(value, PRIMARY_DISPLAY_CTRL, DOUBLE_PIXEL, DISABLE); + break; + case TFT_24BIT: + value = FIELD_SET(value, PRIMARY_DISPLAY_CTRL, DUAL_DISPLAY, DISABLE); + value = FIELD_SET(value, PRIMARY_DISPLAY_CTRL, DOUBLE_PIXEL, DISABLE); + break; + case TFT_36BIT: + value = FIELD_SET(value, PRIMARY_DISPLAY_CTRL, DUAL_DISPLAY, DISABLE); + value = FIELD_SET(value, PRIMARY_DISPLAY_CTRL, DOUBLE_PIXEL, ENABLE); + break; + default: + return (-1); + } + pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, value); + + //DDKDEBUGPRINT((DISPLAY_LEVEL, "(setPanelType)PRIMARY_DISPLAY_CTRL: %x\n", peekRegisterDWord(PRIMARY_DISPLAY_CTRL))); + + return 0; +} + +/* + * Use vertical sync as time delay function. + * + * Input: + * dispControl - Display Control (either panel or crt) + * vsync_count - Number of vertical sync to wait. + * + * Note: + * This function is waiting for the next vertical sync. + */ +void waitNextVerticalSync(disp_control_t dispControl, unsigned long vsync_count) +{ + unsigned long status; + unsigned long ulLoopCount = 0; + static unsigned long ulDeadLoopCount = 10000; + + if (dispControl == CHANNEL0_CTRL) + { + /* Do not wait when the Primary PLL is off or display control is already off. + This will prevent the software to wait forever. */ + if ((FIELD_GET(peekRegisterDWord(PRIMARY_PLL_CTRL), PRIMARY_PLL_CTRL, POWER) == + PRIMARY_PLL_CTRL_POWER_OFF) || + (FIELD_GET(peekRegisterDWord(PRIMARY_DISPLAY_CTRL), PRIMARY_DISPLAY_CTRL, TIMING) == + PRIMARY_DISPLAY_CTRL_TIMING_DISABLE)) + { + return; + } + + while (vsync_count-- > 0) + { + ulLoopCount = 0; + /* Wait for end of vsync. */ + do + { + status = FIELD_GET(peekRegisterDWord(SYSTEM_CTRL), + SYSTEM_CTRL, + PRIMARY_VSYNC); + if(ulLoopCount++ > ulDeadLoopCount) + break; + } + while (status == SYSTEM_CTRL_PRIMARY_VSYNC_ACTIVE); + + ulLoopCount = 0; + /* Wait for start of vsync. */ + do + { + status = FIELD_GET(peekRegisterDWord(SYSTEM_CTRL), + SYSTEM_CTRL, + PRIMARY_VSYNC); + if(ulLoopCount++ > ulDeadLoopCount) + break; + } + while (status == SYSTEM_CTRL_PRIMARY_VSYNC_INACTIVE); + } + } + else + { + /* Do not wait when the display control is already off. This will prevent + the software to wait forever. */ + if ((FIELD_GET(peekRegisterDWord(SECONDARY_PLL_CTRL), SECONDARY_PLL_CTRL, POWER) == + SECONDARY_PLL_CTRL_POWER_OFF) || + (FIELD_GET(peekRegisterDWord(SECONDARY_DISPLAY_CTRL), SECONDARY_DISPLAY_CTRL, TIMING) == + SECONDARY_DISPLAY_CTRL_TIMING_DISABLE)) + { + return; + } + + while (vsync_count-- > 0) + { + ulLoopCount = 0; + /* Wait for end of vsync. */ + do + { + status = FIELD_GET(peekRegisterDWord(SYSTEM_CTRL), + SYSTEM_CTRL, + SECONDARY_VSYNC); + if(ulLoopCount++ > ulDeadLoopCount) + break; + } + while (status == SYSTEM_CTRL_SECONDARY_VSYNC_ACTIVE); + + ulLoopCount = 0; + /* Wait for start of vsync. */ + do + { + status = FIELD_GET(peekRegisterDWord(SYSTEM_CTRL), + SYSTEM_CTRL, + SECONDARY_VSYNC); + if(ulLoopCount++ > ulDeadLoopCount) + break; + } + while (status == SYSTEM_CTRL_SECONDARY_VSYNC_INACTIVE); + } + } +} + +/* + * Use Primary vertical sync as time delay function. + * Input: Number of vertical sync to wait. + */ +void primaryWaitVerticalSync(unsigned long vsync_count) +{ + waitNextVerticalSync(CHANNEL0_CTRL, vsync_count); +} + +/* + * Use crt vertical sync as time delay function. + * Input: Number of vertical sync to wait. + */ +void secondaryWaitVerticalSync(unsigned long vsync_count) +{ + waitNextVerticalSync(CHANNEL1_CTRL, vsync_count); +} + +/* + * Use panel vertical sync line as time delay function. + * This function does not wait for the next VSync. Instead, it will wait + * until the current line reaches the Vertical Sync line. + * This function is really useful when flipping display to prevent tearing. + * + * Input: display control (CHANNEL0_CTRL or CHANNEL1_CTRL) + */ +void waitVSyncLine(disp_control_t dispControl) +{ + unsigned long value; + mode_parameter_t modeParam; + + /* Get the current mode parameter of the specific display control */ + modeParam = getCurrentModeParam(dispControl); + + do + { + if (dispControl == CHANNEL0_CTRL) + value = FIELD_GET(peekRegisterDWord(PRIMARY_CURRENT_LINE), PRIMARY_CURRENT_LINE, LINE); + else + value = FIELD_GET(peekRegisterDWord(SECONDARY_CURRENT_LINE), SECONDARY_CURRENT_LINE, LINE); + } + while (value < modeParam.vertical_sync_start); +} + + +void swPanelPowerSequence_SM750LE(disp_state_t dispState, unsigned long vsync_delay) +{ + unsigned long ulDispControl, ulMask; + + ulDispControl = peekRegisterDWord(DISPLAY_CONTROL_750LE); + + if (dispState == DISP_ON) + { + ulMask = FIELD_SET(0, DISPLAY_CONTROL_750LE, EN, HIGH) | + FIELD_SET(0, DISPLAY_CONTROL_750LE, BIAS, HIGH) | + FIELD_SET(0, DISPLAY_CONTROL_750LE, DATA, ENABLE) | + FIELD_SET(0, DISPLAY_CONTROL_750LE, VDD, HIGH); + + pokeRegisterDWord(DISPLAY_CONTROL_750LE, (ulDispControl | ulMask)); + } + else + { + ulMask = FIELD_SET(0, DISPLAY_CONTROL_750LE, EN, LOW) | + FIELD_SET(0, DISPLAY_CONTROL_750LE, BIAS, LOW) | + FIELD_SET(0, DISPLAY_CONTROL_750LE, DATA, DISABLE) | + FIELD_SET(0, DISPLAY_CONTROL_750LE, VDD, LOW); + + pokeRegisterDWord(DISPLAY_CONTROL_750LE, (ulDispControl & ulMask)); + } +} + +/* + * This functions uses software sequence to turn on/off the panel. + */ +void swPanelPowerSequence(disp_state_t dispState, unsigned long vsync_delay) +{ + unsigned long primaryControl = peekRegisterDWord(PRIMARY_DISPLAY_CTRL); + + //DDKDEBUGPRINT((DISPLAY_LEVEL, "swPanelPowerSequence +\n")); + + if (dispState == DISP_ON) + { + /* Turn on FPVDDEN. */ + primaryControl = FIELD_SET(primaryControl, PRIMARY_DISPLAY_CTRL, FPVDDEN, HIGH); + pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, primaryControl); + primaryWaitVerticalSync(vsync_delay); + + /* Turn on FPDATA. */ + primaryControl = FIELD_SET(primaryControl, PRIMARY_DISPLAY_CTRL, DATA, ENABLE); + pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, primaryControl); + primaryWaitVerticalSync(vsync_delay); + + /* Turn on FPVBIAS. */ + primaryControl = FIELD_SET(primaryControl, PRIMARY_DISPLAY_CTRL, VBIASEN, HIGH); + pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, primaryControl); + primaryWaitVerticalSync(vsync_delay); + + /* Turn on FPEN. */ + primaryControl = FIELD_SET(primaryControl, PRIMARY_DISPLAY_CTRL, FPEN, HIGH); + pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, primaryControl); + } + + else + { + /* Turn off FPEN. */ + primaryControl = FIELD_SET(primaryControl, PRIMARY_DISPLAY_CTRL, FPEN, LOW); + pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, primaryControl); + primaryWaitVerticalSync(vsync_delay); + + /* Turn off FPVBIASEN. */ + primaryControl = FIELD_SET(primaryControl, PRIMARY_DISPLAY_CTRL, VBIASEN, LOW); + pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, primaryControl); + primaryWaitVerticalSync(vsync_delay); + + /* Turn off FPDATA. */ + primaryControl = FIELD_SET(primaryControl, PRIMARY_DISPLAY_CTRL, DATA, DISABLE); + pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, primaryControl); + primaryWaitVerticalSync(vsync_delay); + + /* Turn off FPVDDEN. */ + primaryControl = FIELD_SET(primaryControl, PRIMARY_DISPLAY_CTRL, FPVDDEN, LOW); + pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, primaryControl); + } + + //DDKDEBUGPRINT((DISPLAY_LEVEL, "swPanelPowerSequence -\n")); +} + +/* + * This function turns on/off the DAC for CRT display control. + * Input: On or off + */ +void setDAC(disp_state_t state) +{ + //DDKDEBUGPRINT((DISPLAY_LEVEL, "setDAC: %s\n", (state == DISP_ON) ? "on" : "off")); + + if (state == DISP_ON) + { + pokeRegisterDWord(MISC_CTRL, FIELD_SET(peekRegisterDWord(MISC_CTRL), + MISC_CTRL, + DAC_POWER, + ON)); + } + else + { + pokeRegisterDWord(MISC_CTRL, FIELD_SET(peekRegisterDWord(MISC_CTRL), + MISC_CTRL, + DAC_POWER, + OFF)); + } +} + +/* + * This function turns on/off the display control. + * Currently, it for CRT and Panel controls only. + * Input: Panel or CRT, or ... + * On or Off. + * + * This function manipulate the physical display channels + * and devices. + * + * Note: + * Turning on/off the timing and the plane requires programming sequence. + * The plane can not be changed without turning on the timing. However, + * changing the plane has no effect when the timing (clock) is off. Below, + * is the description of the timing and plane combination setting. + * + * +-----------+-----------+-----------------------------------------------+ + * | Timing | Plane | Description | + * +-----------+-----------+-----------------------------------------------+ + * | ON | OFF | no Display but clock is on (consume power) | + * | ON | ON | normal display | + * | OFF | OFF | no display and no clock (power down) | + * | OFF | ON | no display and no clock (same as power down) | + * +-----------+-----------+-----------------------------------------------+ + */ +void setDisplayControl(disp_control_t dispControl, disp_state_t dispState) +{ + unsigned long ulDisplayCtrlReg, ulReservedBits; + + /* Set the primary display control */ + if (dispControl == CHANNEL0_CTRL) + { + ulDisplayCtrlReg = peekRegisterDWord(PRIMARY_DISPLAY_CTRL); + + //DDKDEBUGPRINT((DISPLAY_LEVEL, "(setDispCtrl) PRIMARY_DISPLAY_CTRL before set: %x\n", peekRegisterDWord(PRIMARY_DISPLAY_CTRL))); + + /* Turn on/off the Panel display control */ + if (dispState == DISP_ON) + { + /* Timing should be enabled first before enabling the plane because changing at the + same time does not guarantee that the plane will also enabled or disabled. + */ + ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, PRIMARY_DISPLAY_CTRL, TIMING, ENABLE); + pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, ulDisplayCtrlReg); + + ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, PRIMARY_DISPLAY_CTRL, PLANE, ENABLE); + + /* Added some masks to mask out the reserved bits. + * Sometimes, the reserved bits are set/reset randomly when + * writing to the PRIMARY_DISPLAY_CTRL, therefore, the register + * reserved bits are needed to be masked out. + */ + ulReservedBits = FIELD_SET(0, PRIMARY_DISPLAY_CTRL, RESERVED_1_MASK, ENABLE) | + FIELD_SET(0, PRIMARY_DISPLAY_CTRL, RESERVED_2_MASK, ENABLE) | + FIELD_SET(0, PRIMARY_DISPLAY_CTRL, RESERVED_3_MASK, ENABLE); + + /* Somehow the register value on the plane is not set until a few delay. Need to write + and read it a couple times*/ + pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, ulDisplayCtrlReg); + primaryWaitVerticalSync(2); + } + else + { + /* When turning off, there is no rule on the programming sequence since whenever the + clock is off, then it does not matter whether the plane is enabled or disabled. + Note: Modifying the plane bit will take effect on the next vertical sync. Need to + find out if it is necessary to wait for 1 vsync before modifying the timing + enable bit. + */ + ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, PRIMARY_DISPLAY_CTRL, PLANE, DISABLE); + pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, ulDisplayCtrlReg); + + ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, PRIMARY_DISPLAY_CTRL, TIMING, DISABLE); + pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, ulDisplayCtrlReg); + } + + //DDKDEBUGPRINT((DISPLAY_LEVEL, "(setDispCtrl) PRIMARY_DISPLAY_CTRL after set: %x\n", peekRegisterDWord(PRIMARY_DISPLAY_CTRL))); + } + /* Set the secondary display control */ + else if(dispControl == CHANNEL1_CTRL) + { + ulDisplayCtrlReg = peekRegisterDWord(SECONDARY_DISPLAY_CTRL); + + //DDKDEBUGPRINT((DISPLAY_LEVEL, "(setDispCtrl) SECONDARY_DISPLAY_CTRL before set: %x\n", peekRegisterDWord(SECONDARY_DISPLAY_CTRL))); + + if (dispState == DISP_ON) + { + /* Timing should be enabled first before enabling the plane because changing at the + same time does not guarantee that the plane will also enabled or disabled. + */ + ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, SECONDARY_DISPLAY_CTRL, TIMING, ENABLE); + pokeRegisterDWord(SECONDARY_DISPLAY_CTRL, ulDisplayCtrlReg); + + ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, SECONDARY_DISPLAY_CTRL, PLANE, ENABLE); + + /* Added some masks to mask out the reserved bits. + * Sometimes, the reserved bits are set/reset randomly when + * writing to the PRIMARY_DISPLAY_CTRL, therefore, the register + * reserved bits are needed to be masked out. + */ + ulReservedBits = FIELD_SET(0, SECONDARY_DISPLAY_CTRL, RESERVED_1_MASK, ENABLE) | + FIELD_SET(0, SECONDARY_DISPLAY_CTRL, RESERVED_2_MASK, ENABLE) | + FIELD_SET(0, SECONDARY_DISPLAY_CTRL, RESERVED_3_MASK, ENABLE) | + FIELD_SET(0, SECONDARY_DISPLAY_CTRL, RESERVED_4_MASK, ENABLE); + + + pokeRegisterDWord(SECONDARY_DISPLAY_CTRL, ulDisplayCtrlReg); + secondaryWaitVerticalSync(2); + } + else + { + /* When turning off, there is no rule on the programming sequence since whenever the + clock is off, then it does not matter whether the plane is enabled or disabled. + Note: Modifying the plane bit will take effect on the next vertical sync. Need to + find out if it is necessary to wait for 1 vsync before modifying the timing + enable bit. + */ + ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, SECONDARY_DISPLAY_CTRL, PLANE, DISABLE); + pokeRegisterDWord(SECONDARY_DISPLAY_CTRL, ulDisplayCtrlReg); + + ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, SECONDARY_DISPLAY_CTRL, TIMING, DISABLE); + pokeRegisterDWord(SECONDARY_DISPLAY_CTRL, ulDisplayCtrlReg); + } + + //DDKDEBUGPRINT((DISPLAY_LEVEL, "(setDispCtrl) SECONDARY_DISPLAY_CTRL after set: %x\n", peekRegisterDWord(SECONDARY_DISPLAY_CTRL))); + } +} + +/* + * This function set the display path together with the HSync and VSync. + * + * Note: + * This function has to be called last after setting all the display Control + * and display output. + */ +void setPath( + disp_path_t dispPath, + disp_control_t dispControl, + disp_state_t dispState +) +{ + unsigned long control; + mode_parameter_t modeParam; + unsigned long clock0, clock1, MiscControl; + + /* Get the current mode parameter of the specific display control */ + modeParam = getCurrentModeParam(dispControl); + + if (dispPath == SMI0_PATH) + { + control = peekRegisterDWord(PRIMARY_DISPLAY_CTRL); + if (dispState == DISP_ON) + { + /* Adjust the Clock polarity */ + if (modeParam.clock_phase_polarity == POS) + control = FIELD_SET(control, PRIMARY_DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_HIGH); + else + control = FIELD_SET(control, PRIMARY_DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_LOW); + + /* Adjust the VSync polarity */ + if (modeParam.vertical_sync_polarity == POS) + control = FIELD_SET(control, PRIMARY_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_HIGH); + else + control = FIELD_SET(control, PRIMARY_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW); + + /* Adjust the HSync polarity */ + if (modeParam.horizontal_sync_polarity == POS) + control = FIELD_SET(control, PRIMARY_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_HIGH); + else + control = FIELD_SET(control, PRIMARY_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW); + + /* Display control is not swapped, so use the normal display data flow */ + if (dispControl == CHANNEL0_CTRL) + control = FIELD_SET(control, PRIMARY_DISPLAY_CTRL, SELECT, PRIMARY); + else /* Secondary Control */ + control = FIELD_SET(control, PRIMARY_DISPLAY_CTRL, SELECT, SECONDARY); + } + +#if Validate_718_AA + //if (hwDeviceExtension1[0]->ChipID==0x718 || + // hwDeviceExtension1[1]->ChipID==0x718) + { + //patch for sm718aa, when set 80028[28] from 0 to 1, failed some time. needs to set the master + //clock to 56mhz. + clock0 = peekRegisterDWord(MODE0_GATE); + pokeRegisterDWord(MODE0_GATE, FIELD_SET(clock0, MODE0_GATE, MCLK, 42MHZ)); + clock1 = peekRegisterDWord(MODE1_GATE); + pokeRegisterDWord(MODE1_GATE, FIELD_SET(clock1, MODE1_GATE, MCLK, 42MHZ)); + } +#endif + pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, control); +#if Validate_718_AA + //if (hwDeviceExtension1[0]->ChipID==0x718 || + // hwDeviceExtension1[1]->ChipID==0x718) + { + //patch for sm718aa, restore mclk. + pokeRegisterDWord(MODE0_GATE, clock0); + pokeRegisterDWord(MODE1_GATE, clock1); + + //Reset video memory, otherwise, screen would show garbage. + MiscControl= peekRegisterDWord(MISC_CTRL); + MiscControl= FIELD_SET(MiscControl, MISC_CTRL, LOCALMEM_RESET, RESET); + pokeRegisterDWord(MISC_CTRL, MiscControl); + MiscControl= FIELD_SET(MiscControl, MISC_CTRL, LOCALMEM_RESET, NORMAL); + pokeRegisterDWord(MISC_CTRL, MiscControl); + } +#endif + + // DDKDEBUGPRINT((DISPLAY_LEVEL, "(setPath) PRIMARY_DISPLAY_CTRL: %x\n", peekRegisterDWord(PRIMARY_DISPLAY_CTRL))); + } + else if(dispPath == SMI1_PATH) /* CRT Path */ + { + control = peekRegisterDWord(SECONDARY_DISPLAY_CTRL); + + if (dispState == DISP_ON) + { + /* Adjust the Clock polarity */ + if (modeParam.clock_phase_polarity == POS) + control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_HIGH); + else + control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_LOW); + + /* Adjust the VSync polarity */ + if (modeParam.vertical_sync_polarity == POS) + control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_HIGH); + else + control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW); + + /* Adjust the HSync polarity */ + if (modeParam.horizontal_sync_polarity == POS) + control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_HIGH); + else + control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW); + + /* Display control is not swapped, so use the normal display data flow */ + if (dispControl == CHANNEL0_CTRL) + control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, SELECT, PRIMARY); + else + control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, SELECT, SECONDARY); + + /* Enable the CRT Pixel */ + control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, BLANK, OFF); + } + else + { + /* Disable the CRT Pixel */ + control = FIELD_SET(control, SECONDARY_DISPLAY_CTRL, BLANK, ON); + } + + pokeRegisterDWord(SECONDARY_DISPLAY_CTRL, control); + + //DDKDEBUGPRINT((DISPLAY_LEVEL, "(setPath) SECONDARY_DISPLAY_CTRL: %x\n", peekRegisterDWord(SECONDARY_DISPLAY_CTRL))); + } +} + +/* + * This function gets the CRT2 Monitor Detection Threshold value. + * + * Input: + * pRedValue - Pointer to a variable to store the Red color threshold + * value. + * pGreenValue - Pointer to a variable to store the Green color threshold + * value. + * pBlueValue - Pointer to a variable to store the Blue color threshold + * value. + */ +void getCRTDetectThreshold( + unsigned char *pRedValue, + unsigned char *pGreenValue, + unsigned char *pBlueValue +) +{ + unsigned long value; + + value = peekRegisterDWord(SECONDARY_MONITOR_DETECT); + + if (pRedValue != (unsigned char *)0) + *pRedValue = (unsigned char)FIELD_GET(value, SECONDARY_MONITOR_DETECT, RED); + + if (pGreenValue != (unsigned char *)0) + *pGreenValue = (unsigned char)FIELD_GET(value, SECONDARY_MONITOR_DETECT, GREEN); + + if (pBlueValue != (unsigned char *)0) + *pBlueValue = (unsigned char)FIELD_GET(value, SECONDARY_MONITOR_DETECT, BLUE); +} + +/* + * This function detects if the CRT monitor is attached. + * + * Input: + * redValue - Threshold value to be detected on the red color. + * greenValue - Threshold value to be detected on the green color. + * blueValue - Threshold value to be detected on the blue color. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk750_detectCRTMonitor( + unsigned char redValue, + unsigned char greenValue, + unsigned char blueValue +) +{ + unsigned long value, red, green, blue; + long result = (-1); + + /* Use the given red, green, and blue threshold value to detect the monitor or + default. */ + if (redValue != 0) + red = redValue; + else + red = DEFAULT_MON_DETECTION_THRESHOLD; + + if (greenValue != 0) + green = greenValue; + else + green = DEFAULT_MON_DETECTION_THRESHOLD; + + if (blueValue != 0) + blue = blueValue; + else + blue = DEFAULT_MON_DETECTION_THRESHOLD; + + /* Set the RGB Threshold value and enable the monitor detection. */ + value = ((unsigned long)red << 16) | + ((unsigned long)green << 8) | + ((unsigned long)blue); + value = FIELD_SET(value, SECONDARY_MONITOR_DETECT, ENABLE, ENABLE); + pokeRegisterDWord(SECONDARY_MONITOR_DETECT, value); + + /* Add some delay here. Otherwise, the detection is not stable. */ + value = 0xFFFF; + while (value--); + + /* Check if the monitor is detected. */ + if (FIELD_GET(peekRegisterDWord(SECONDARY_MONITOR_DETECT), SECONDARY_MONITOR_DETECT, VALUE) == + SECONDARY_MONITOR_DETECT_VALUE_ENABLE) + { + result = 0; + } + + /* Disable the Monitor Detect Enable bit. Somehow, enabling this bit will + cause the CRT to lose display. */ + value = peekRegisterDWord(SECONDARY_MONITOR_DETECT); + value = FIELD_SET(value, SECONDARY_MONITOR_DETECT, ENABLE, DISABLE); + pokeRegisterDWord(SECONDARY_MONITOR_DETECT, value); + + return result; +} + +/* + * This function set the logical display output. + * + * The output is called logical because it is independent of physical implementation. + * For example, CRT2 only mode is not using the internal secondary control. It uses the + * Primary Control with its output directed to CRT DAC. + * + * Input: + * output - Logical Display output + * dispCtrlUsage - Display Control Flag Usage: + * 0 : Use primary display control (CHANNEL0_CTRL) to control + * primary output (LCD1 & CRT1) and use secondary display + * control (CHANNEL1_CTRL) to control secondary output + * (CRT2 & LCD2) + * 1 : Use primary display control (CHANNEL0_CTRL) to control + * secondary output (LCD2 & CRT2) and use secondary display + * control (CHANNEL1_CTRL) to control primary output + * (LCD1 & CRT1) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long setLogicalDispOutput( + + disp_output_t output, + unsigned char dispCtrlUsage +) +{ + //DDKDEBUGPRINT((DISPLAY_LEVEL, "setLogicalDispOutput\n")); + + switch (output) + { + case NO_DISPLAY: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "NO_DISPLAY\n")); + + /* In here, all the display device has to be turned off first before the + the display control. */ + swPanelPowerSequence(DISP_OFF, 4); /* Turn off Panel */ + setDAC(DISP_OFF); /* Turn off DAC */ + setDPMS(DPMS_OFF); /* Turn off DPMS */ + + setDisplayControl(CHANNEL0_CTRL, DISP_OFF); /* Turn off Panel control */ + setDisplayControl(CHANNEL1_CTRL, DISP_OFF); /* Turn off CRT control */ + + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_OFF); /* Turn off Panel path */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_OFF); /* Turn off CRT path */ + break; + } + case LCD1_ONLY: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_ONLY\n")); + + /* + * 1. Set all the display control and the display path + */ + if (dispCtrlUsage == 0) + { + /* Turn on Primary control */ + setDisplayControl(CHANNEL0_CTRL, DISP_ON); + if (isScalingEnabled(CHANNEL0_CTRL) == 1) + { + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on CRT control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + } + else + { + setDisplayControl(CHANNEL1_CTRL, DISP_OFF); /* Turn off CRT control */ + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on Panel Path and use panel data */ + } + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_OFF); /* Turn off CRT Path */ + } + else + { + setDisplayControl(CHANNEL0_CTRL, DISP_OFF); /* Turn off Primary control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_OFF); /* Turn off CRT Path */ + } + + /* + * 2. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_ON, 4); /* Turn on Panel */ +#ifdef ENABLE_PANEL_DAC + /* When using Analog CRT connected to the DVI channel, the DAC needs + to be turned on. The power is using the same power as CRT DAC. */ + setDAC(DISP_ON); /* Turn on DAC */ +#else + setDAC(DISP_OFF); /* Turn off DAC */ +#endif + setDPMS(DPMS_OFF); /* Turn off DPMS */ + break; + } + case LCD2_ONLY: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD2_ONLY\n")); + + /* + * 1. Check the conditions + */ + /* Can not enable LCD22 when the panel type is not 18-bit panel. */ + if (getPanelType() != TFT_18BIT) + return (-1); + + /* + * 2. Set all the display control and the display path + */ + if (dispCtrlUsage == 0) + { + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary control */ + if (isScalingEnabled(CHANNEL0_CTRL) == 1) + { + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + else + { + setDisplayControl(CHANNEL1_CTRL, DISP_OFF); /* Turn off Secondary control */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on CRT Path and use primary data */ + } + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_OFF); /* Turn off Panel Path */ + } + else + { + setDisplayControl(CHANNEL0_CTRL, DISP_OFF); /* Turn off Primary control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn off CRT Path and use secondary data */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_OFF); /* Turn off Panel Path */ + } + + /* + * 3. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_OFF, 4); /* Turn off Panel 1 */ + setDAC(DISP_OFF); /* Turn off DAC */ + setDPMS(DPMS_OFF); /* Turn off DPMS */ + break; + } + case CRT2_ONLY: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "CRT2_ONLY\n")); + + /* + * 1. Set all the display control and the display path + */ + if (dispCtrlUsage == 0) + { + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_OFF); /* Turn off Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_OFF); /* Turn off Panel Path */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn off CRT Path and use Primary data */ + } + else + { + setDisplayControl(CHANNEL0_CTRL, DISP_OFF); /* Turn off Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_OFF); /* Turn off Panel Path */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn off CRT Path and use Primary data */ + } + + /* + * 2. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_OFF, 4); /* Turn off Panel */ + setDAC(DISP_ON); /* Turn on DAC */ + setDPMS(DPMS_ON); /* Turn on DPMS to drive CRT */ + break; + } + case LCD1_CRT2_SIMUL: /* Panel and CRT same content */ + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_CRT2_SIMUL\n")); + + /* + * 1. Set all the display control and the display path + */ + if (dispCtrlUsage == 0) + { + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary Control */ + if (isScalingEnabled(CHANNEL0_CTRL) == 1) + { + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + } + else + { + setDisplayControl(CHANNEL1_CTRL, DISP_OFF); /* Turn off Secondary control */ + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on Panel Path and use Primary data */ + } + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on CRT Path and use Primary data */ + } + else + { + setDisplayControl(CHANNEL0_CTRL, DISP_OFF); /* Turn off Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Primary data */ + } + + /* + * 2. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_ON, 4); /* Turn on Panel */ + setDAC(DISP_ON); /* Turn on DAC */ + setDPMS(DPMS_ON); /* Turn on DPMS to drive CRT */ + break; + } + case LCD1_LCD2_SIMUL: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_LCD2_SIMUL\n")); + + /* + * 1. Check the conditions + */ + /* Can not enable PANEL2 when the panel type is not 18-bit panel. */ + if (getPanelType() != TFT_18BIT) + return (-1); + + /* + * 2. Set all the display control and the display path + */ + if (dispCtrlUsage == 0) + { + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary Control */ + if (isScalingEnabled(CHANNEL0_CTRL) == 1) + { + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + else + { + setDisplayControl(CHANNEL1_CTRL, DISP_OFF); /* Turn off Secondary control */ + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on Panel Path and use Primary data */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on CRT Path and use Primary data */ + } + } + else + { + setDisplayControl(CHANNEL0_CTRL, DISP_OFF); /* Turn off Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + + /* + * 3. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_ON, 4); /* Turn on Panel */ +#ifdef ENABLE_PANEL_DAC + /* When using Analog CRT connected to the DVI channel, the DAC needs + to be turned on. The power is using the same power as CRT DAC. */ + setDAC(DISP_ON); /* Turn on DAC */ +#else + setDAC(DISP_OFF); /* Turn off DAC */ +#endif + setDPMS(DPMS_OFF); /* Turn off DPMS */ + break; + } + case CRT2_LCD2_SIMUL: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "CRT2_LCD2_SIMUL\n")); + + /* + * 1. Check the conditions + */ + /* Can not enable PANEL2 when the panel type is not 18-bit panel. */ + if (getPanelType() != TFT_18BIT) + return (-1); + + /* + * 2. Set all the display control and the display path + */ + if (dispCtrlUsage == 0) + { + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary Control */ + if (isScalingEnabled(CHANNEL0_CTRL) == 1) + { + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + else + { + setDisplayControl(CHANNEL1_CTRL, DISP_OFF); /* Turn off Secondary control */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on CRT Path and use Primary data */ + } + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_OFF); /* Turn on Panel Path and use Primary data */ + } + else + { + setDisplayControl(CHANNEL0_CTRL, DISP_OFF); /* Turn off Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_OFF); /* Turn on Panel Path and use Primary data */ + } + + /* + * 3. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_ON, 4); /* Turn on Panel */ + setDAC(DISP_ON); /* Turn on DAC */ + setDPMS(DPMS_ON); /* Turn on DPMS to drive CRT */ + break; + } + case LCD1_LCD2_CRT2_SIMUL: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_LCD2_CRT2_SIMUL\n")); + + /* + * 1. Check the conditions + */ + /* Can not enable PANEL2 when the panel type is not 18-bit panel. */ + if (getPanelType() != TFT_18BIT) + return (-1); + + /* + * 2. Set all the display control and the display path + */ + if (dispCtrlUsage == 0) + { + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary Control */ + if (isScalingEnabled(CHANNEL0_CTRL) == 1) + { + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + else + { + setDisplayControl(CHANNEL1_CTRL, DISP_OFF); /* Turn off Secondary control */ + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on Panel Path and use Primary data */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on CRT Path and use Primary data */ + } + } + else + { + setDisplayControl(CHANNEL0_CTRL, DISP_OFF); /* Turn off Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + + /* + * 3. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_ON, 4); /* Turn on Panel */ + setDAC(DISP_ON); /* Turn on DAC */ + setDPMS(DPMS_ON); /* Turn on DPMS to drive CRT */ + break; + } + case LCD1_CRT2_DUAL: /* Panel and CRT different content */ + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_CRT2_DUAL\n")); + + /* + * 1. Check the conditions + */ + /* This combination is not valid if panel 1 requires scaling and display + control is not swapped. */ + // if (isScalingEnabled(CHANNEL0_CTRL) == 1) + // return (-1); + + /* + * 2. Set all the display control and the display path + */ + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + + + if (dispCtrlUsage == 0) + { + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on Panel Path and use Primary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + + + } + else + { + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on CRT Path and use Primary data */ + + + } + + /* + * 3. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_ON, 4); /* Turn on Panel */ + setDAC(DISP_ON); /* Turn on DAC */ + setDPMS(DPMS_ON); /* Turn on DPMS to drive CRT */ + break; + } + case LCD1_LCD2_DUAL: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_LCD2_DUAL\n")); + + /* + * 1. Check the conditions + */ + /* This combination is not valid if panel requires scaling and display + control is not swapped. */ + // if (isScalingEnabled(CHANNEL0_CTRL) == 1) + // return (-1); + + /* Can not enable PANEL2 when the panel type is not 18-bit panel. */ + if (getPanelType() != TFT_18BIT) + return (-1); + + /* + * 2. Set all the display control and the display path + */ + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + if (dispCtrlUsage == 0) + { + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on Panel Path and use Primary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + else + { + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on CRT Path and use Primary data */ + } + + /* + * 3. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_ON, 4); /* Turn on Panel */ +#ifdef ENABLE_PANEL_DAC + /* When using Analog CRT connected to the DVI channel, the DAC needs + to be turned on. The power is using the same power as CRT DAC. */ + setDAC(DISP_ON); /* Turn on DAC */ +#else + setDAC(DISP_OFF); /* Turn off DAC */ +#endif + setDPMS(DPMS_OFF); /* Turn off DPMS to drive CRT */ + break; + } + case LCD1_LCD2_CRT2_DUAL: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_LCD2_CRT2_DUAL\n")); + + /* + * 1. Check the conditions + */ + /* This combination is not valid if panel requires scaling and display + control is not swapped. */ + //if (isScalingEnabled(CHANNEL0_CTRL) == 1) + // return (-1); + + /* Can not enable PANEL2 when the panel type is not 18-bit panel. */ + if (getPanelType() != TFT_18BIT) + return (-1); + + /* + * 2. Set all the display control and the display path + */ + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + if (dispCtrlUsage == 0) + { + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on Panel Path and use Primary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + else + { + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on CRT Path and use Primary data */ + } + + /* + * 3. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_ON, 4); /* Turn on Panel */ + setDAC(DISP_ON); /* Turn on DAC */ + setDPMS(DPMS_ON); /* Turn on DPMS to drive CRT */ + break; + } + } + + return 0; +} + +/* + * This function set the logical display output. + * + * The output is called logical because it is independent of physical implementation. + * For example, CRT2 only mode is not using the internal secondary control. It uses the + * Primary Control with its output directed to CRT DAC. + * + * Input: + * isSnd - is or not the second view + * output - Logical Display output + * dispCtrlUsage - Display Control Flag Usage: + * 0 : Use primary display control (CHANNEL0_CTRL) to control + * primary output (LCD1 & CRT1) and use secondary display + * control (CHANNEL1_CTRL) to control secondary output + * (CRT2 & LCD2) + * 1 : Use primary display control (CHANNEL0_CTRL) to control + * secondary output (LCD2 & CRT2) and use secondary display + * control (CHANNEL1_CTRL) to control primary output + * (LCD1 & CRT1) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long setLogicalDispOutputExt( + long isSecondDisplay, + disp_output_t output, + unsigned char dispCtrlUsage +) +{ + //DDKDEBUGPRINT((DISPLAY_LEVEL, "setLogicalDispOutputExt\n")); + + switch (output) + { + case NO_DISPLAY: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "NO_DISPLAY\n")); + + /* In here, all the display device has to be turned off first before the + the display control. */ + swPanelPowerSequence(DISP_OFF, 4); /* Turn off Panel */ + setDAC(DISP_OFF); /* Turn off DAC */ + setDPMS(DPMS_OFF); /* Turn off DPMS */ + + setDisplayControl(CHANNEL0_CTRL, DISP_OFF); /* Turn off Panel control */ + setDisplayControl(CHANNEL1_CTRL, DISP_OFF); /* Turn off CRT control */ + + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_OFF); /* Turn off Panel path */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_OFF); /* Turn off CRT path */ + break; + } + case LCD1_ONLY: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_ONLY\n")); + + /* + * 1. Set all the display control and the display path + */ + if (dispCtrlUsage == 0) + { + /* Turn on Primary control */ + setDisplayControl(CHANNEL0_CTRL, DISP_ON); + if (isScalingEnabled(CHANNEL0_CTRL) == 1) + { + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on CRT control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + } + else + { + setDisplayControl(CHANNEL1_CTRL, DISP_OFF); /* Turn off CRT control */ + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on Panel Path and use panel data */ + } + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_OFF); /* Turn off CRT Path */ + } + else + { + setDisplayControl(CHANNEL0_CTRL, DISP_OFF); /* Turn off Primary control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_OFF); /* Turn off CRT Path */ + } + + /* + * 2. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_ON, 4); /* Turn on Panel */ +#ifdef ENABLE_PANEL_DAC + /* When using Analog CRT connected to the DVI channel, the DAC needs + to be turned on. The power is using the same power as CRT DAC. */ + setDAC(DISP_ON); /* Turn on DAC */ +#else + setDAC(DISP_OFF); /* Turn off DAC */ +#endif + setDPMS(DPMS_OFF); /* Turn off DPMS */ + break; + } + case LCD2_ONLY: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD2_ONLY\n")); + + /* + * 1. Check the conditions + */ + /* Can not enable LCD22 when the panel type is not 18-bit panel. */ + if (getPanelType() != TFT_18BIT) + return (-1); + + /* + * 2. Set all the display control and the display path + */ + if (dispCtrlUsage == 0) + { + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary control */ + if (isScalingEnabled(CHANNEL0_CTRL) == 1) + { + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + else + { + setDisplayControl(CHANNEL1_CTRL, DISP_OFF); /* Turn off Secondary control */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on CRT Path and use primary data */ + } + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_OFF); /* Turn off Panel Path */ + } + else + { + setDisplayControl(CHANNEL0_CTRL, DISP_OFF); /* Turn off Primary control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn off CRT Path and use secondary data */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_OFF); /* Turn off Panel Path */ + } + + /* + * 3. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_OFF, 4); /* Turn off Panel 1 */ + setDAC(DISP_OFF); /* Turn off DAC */ + setDPMS(DPMS_OFF); /* Turn off DPMS */ + break; + } + case CRT2_ONLY: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "CRT2_ONLY\n")); + + /* + * 1. Set all the display control and the display path + */ + if (dispCtrlUsage == 0) + { + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_OFF); /* Turn off Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_OFF); /* Turn off Panel Path */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn off CRT Path and use Primary data */ + } + else + { + setDisplayControl(CHANNEL0_CTRL, DISP_OFF); /* Turn off Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_OFF); /* Turn off Panel Path */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn off CRT Path and use Primary data */ + } + + /* + * 2. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_OFF, 4); /* Turn off Panel */ + setDAC(DISP_ON); /* Turn on DAC */ + setDPMS(DPMS_ON); /* Turn on DPMS to drive CRT */ + break; + } + case LCD1_CRT2_SIMUL: /* Panel and CRT same content */ + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_CRT2_SIMUL\n")); + + /* + * 1. Set all the display control and the display path + */ + if (dispCtrlUsage == 0) + { + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary Control */ + if (isScalingEnabled(CHANNEL0_CTRL) == 1) + { + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + } + else + { + setDisplayControl(CHANNEL1_CTRL, DISP_OFF); /* Turn off Secondary control */ + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on Panel Path and use Primary data */ + } + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on CRT Path and use Primary data */ + } + else + { + setDisplayControl(CHANNEL0_CTRL, DISP_OFF); /* Turn off Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Primary data */ + } + + /* + * 2. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_ON, 4); /* Turn on Panel */ + setDAC(DISP_ON); /* Turn on DAC */ + setDPMS(DPMS_ON); /* Turn on DPMS to drive CRT */ + break; + } + case LCD1_LCD2_SIMUL: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_LCD2_SIMUL\n")); + + /* + * 1. Check the conditions + */ + /* Can not enable PANEL2 when the panel type is not 18-bit panel. */ + if (getPanelType() != TFT_18BIT) + return (-1); + + /* + * 2. Set all the display control and the display path + */ + if (dispCtrlUsage == 0) + { + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary Control */ + if (isScalingEnabled(CHANNEL0_CTRL) == 1) + { + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + else + { + setDisplayControl(CHANNEL1_CTRL, DISP_OFF); /* Turn off Secondary control */ + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on Panel Path and use Primary data */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on CRT Path and use Primary data */ + } + } + else + { + setDisplayControl(CHANNEL0_CTRL, DISP_OFF); /* Turn off Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + + /* + * 3. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_ON, 4); /* Turn on Panel */ +#ifdef ENABLE_PANEL_DAC + /* When using Analog CRT connected to the DVI channel, the DAC needs + to be turned on. The power is using the same power as CRT DAC. */ + setDAC(DISP_ON); /* Turn on DAC */ +#else + setDAC(DISP_OFF); /* Turn off DAC */ +#endif + setDPMS(DPMS_OFF); /* Turn off DPMS */ + break; + } + case CRT2_LCD2_SIMUL: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "CRT2_LCD2_SIMUL\n")); + + /* + * 1. Check the conditions + */ + /* Can not enable PANEL2 when the panel type is not 18-bit panel. */ + if (getPanelType() != TFT_18BIT) + return (-1); + + /* + * 2. Set all the display control and the display path + */ + if (dispCtrlUsage == 0) + { + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary Control */ + if (isScalingEnabled(CHANNEL0_CTRL) == 1) + { + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + else + { + setDisplayControl(CHANNEL1_CTRL, DISP_OFF); /* Turn off Secondary control */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on CRT Path and use Primary data */ + } + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_OFF); /* Turn on Panel Path and use Primary data */ + } + else + { + setDisplayControl(CHANNEL0_CTRL, DISP_OFF); /* Turn off Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_OFF); /* Turn on Panel Path and use Primary data */ + } + + /* + * 3. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_ON, 4); /* Turn on Panel */ + setDAC(DISP_ON); /* Turn on DAC */ + setDPMS(DPMS_ON); /* Turn on DPMS to drive CRT */ + break; + } + case LCD1_LCD2_CRT2_SIMUL: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_LCD2_CRT2_SIMUL\n")); + + /* + * 1. Check the conditions + */ + /* Can not enable PANEL2 when the panel type is not 18-bit panel. */ + if (getPanelType() != TFT_18BIT) + return (-1); + + /* + * 2. Set all the display control and the display path + */ + if (dispCtrlUsage == 0) + { + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary Control */ + if (isScalingEnabled(CHANNEL0_CTRL) == 1) + { + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + else + { + setDisplayControl(CHANNEL1_CTRL, DISP_OFF); /* Turn off Secondary control */ + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on Panel Path and use Primary data */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on CRT Path and use Primary data */ + } + } + else + { + setDisplayControl(CHANNEL0_CTRL, DISP_OFF); /* Turn off Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + + /* + * 3. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_ON, 4); /* Turn on Panel */ + setDAC(DISP_ON); /* Turn on DAC */ + setDPMS(DPMS_ON); /* Turn on DPMS to drive CRT */ + break; + } + case LCD1_CRT2_DUAL: /* Panel and CRT different content */ + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_CRT2_DUAL\n")); + + /* + * 1. Check the conditions + */ + /* This combination is not valid if panel 1 requires scaling and display + control is not swapped. */ + if (isScalingEnabled(CHANNEL0_CTRL) == 1) + return (-1); + + /* + * 2. Set all the display control and the display path + */ + if(!isSecondDisplay) + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary Control */ + else + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + if (dispCtrlUsage == 0) + { + if(!isSecondDisplay) + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on Panel Path and use Primary data */ + else + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + else + { + if(isSecondDisplay) + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + else + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on CRT Path and use Primary data */ + } + /* + * 3. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_ON, 4); /* Turn on Panel */ + setDAC(DISP_ON); /* Turn on DAC */ + setDPMS(DPMS_ON); /* Turn on DPMS to drive CRT */ + break; + } + case LCD1_LCD2_DUAL: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_LCD2_DUAL\n")); + + /* + * 1. Check the conditions + */ + /* This combination is not valid if panel requires scaling and display + control is not swapped. */ + if (isScalingEnabled(CHANNEL0_CTRL) == 1) + return (-1); + + /* Can not enable PANEL2 when the panel type is not 18-bit panel. */ + if (getPanelType() != TFT_18BIT) + return (-1); + + /* + * 2. Set all the display control and the display path + */ + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + if (dispCtrlUsage == 0) + { + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on Panel Path and use Primary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + else + { + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on CRT Path and use Primary data */ + } + + /* + * 3. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_ON, 4); /* Turn on Panel */ +#ifdef ENABLE_PANEL_DAC + /* When using Analog CRT connected to the DVI channel, the DAC needs + to be turned on. The power is using the same power as CRT DAC. */ + setDAC(DISP_ON); /* Turn on DAC */ +#else + setDAC(DISP_OFF); /* Turn off DAC */ +#endif + setDPMS(DPMS_OFF); /* Turn off DPMS to drive CRT */ + break; + } + case LCD1_LCD2_CRT2_DUAL: + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "LCD1_LCD2_CRT2_DUAL\n")); + + /* + * 1. Check the conditions + */ + /* This combination is not valid if panel requires scaling and display + control is not swapped. */ + if (isScalingEnabled(CHANNEL0_CTRL) == 1) + return (-1); + + /* Can not enable PANEL2 when the panel type is not 18-bit panel. */ + if (getPanelType() != TFT_18BIT) + return (-1); + + /* + * 2. Set all the display control and the display path + */ + setDisplayControl(CHANNEL0_CTRL, DISP_ON); /* Turn on Primary Control */ + setDisplayControl(CHANNEL1_CTRL, DISP_ON); /* Turn on Secondary control */ + if (dispCtrlUsage == 0) + { + setPath(SMI0_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on Panel Path and use Primary data */ + setPath(SMI1_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on CRT Path and use Secondary data */ + } + else + { + setPath(SMI0_PATH, CHANNEL1_CTRL, DISP_ON); /* Turn on Panel Path and use Secondary data */ + setPath(SMI1_PATH, CHANNEL0_CTRL, DISP_ON); /* Turn on CRT Path and use Primary data */ + } + + /* + * 3. Enable/disable the display devices. + */ + swPanelPowerSequence(DISP_ON, 4); /* Turn on Panel */ + setDAC(DISP_ON); /* Turn on DAC */ + setDPMS(DPMS_ON); /* Turn on DPMS to drive CRT */ + break; + } + } + + return 0; +} + +/* + * This function checks whether the scaling is enabled. + * + * Input: + * dispCtrl - Display control to be checked. + * + * Output: + * 0 - Scaling is not enabled + * 1 - Scaling is enabled + */ +unsigned char isScalingEnabled( + disp_control_t dispCtrl +) +{ + unsigned long value; + + /* If display control is not swapped, then check the expansion bit for CHANNEL0_CTRL + and SECONDARY_SCALE register for CHANNEL1_CTRL. */ + if (dispCtrl == CHANNEL0_CTRL) + { + value = peekRegisterDWord(SECONDARY_DISPLAY_CTRL); + if (FIELD_GET(value, SECONDARY_DISPLAY_CTRL, EXPANSION) == SECONDARY_DISPLAY_CTRL_EXPANSION_ENABLE) + return 1; + } + else + { + value = peekRegisterDWord(SECONDARY_SCALE); + if ((FIELD_GET(value, SECONDARY_SCALE, VERTICAL_SCALE) != 0) || + (FIELD_GET(value, SECONDARY_SCALE, HORIZONTAL_SCALE) != 0)) + return 1; + } + + return 0; +} + diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_display.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_display.h new file mode 100644 index 000000000000..2667b604eb04 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_display.h @@ -0,0 +1,213 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* display.h --- SM750/SM718 DDK +* This file contains the function prototypes for the display. +* +*******************************************************************/ +#ifndef _DISPLAY_H_ +#define _DISPLAY_H_ + +#include "ddk750_mode.h" +#include "../hw_com.h" + +typedef enum _disp_output_t +{ + NO_DISPLAY, /* All display off. */ + LCD1_ONLY, /* LCD1 only */ + LCD2_ONLY, /* LCD2 only */ + CRT2_ONLY, /* CRT2 only */ + LCD1_CRT2_SIMUL, /* Both LCD1 and CRT2 displaying the same content. */ + LCD1_LCD2_SIMUL, /* Both LCD1 and LCD2 displaying the same content. */ + CRT2_LCD2_SIMUL, /* CRT2 and LCD2 displaying the same content. */ + LCD1_LCD2_CRT2_SIMUL, /* LCD1, LCD2, and CRT2 displaying the same content. */ + LCD1_CRT2_DUAL, /* LCD1 and CRT2 displaying different contents. */ + LCD1_LCD2_DUAL, /* LCD1 and LCD2 displaying different contents. */ + LCD1_LCD2_CRT2_DUAL /* LCD2 and CRT2 displaying the same content while + the Panel displaying different content. */ +} +disp_output_t; + +typedef enum _panel_type_t +{ + TFT_18BIT = 0, + TFT_24BIT, + TFT_36BIT +} +panel_type_t; + +void setPath( + disp_path_t dispPath, + disp_control_t dispControl, + disp_state_t dispState +); +/* + * This functions sets the CRT Path. + */ +void setCRTPath(disp_control_t dispControl); + +/* + * This functions uses software sequence to turn on/off the panel. + */ +void swPanelPowerSequence(disp_state_t dispState, unsigned long vsync_delay); + +/* + * This function turns on/off the DAC for CRT display control. + * Input: On or off + */ +void setDAC(disp_state_t state); + +/* + * This function turns on/off the display control. + * Currently, it for CRT and Panel controls only. + * Input: Panel or CRT, or ... + * On or Off. + */ +void setDisplayControl(disp_control_t dispControl, disp_state_t dispState); + +/* + * This function set the logical display output. + * + * The output is called logical because it is independent of physical implementation. + * For example, CRT2 only mode is not using the internal secondary control. It uses the + * Primary Control with its output directed to CRT DAC. + * + * Input: + * output - Logical Display output + * dispCtrlUsage - Display Control Flag Usage: + * 0 : Use primary display control (CHANNEL0_CTRL) to control + * primary output (LCD1 & CRT1) and use secondary display + * control (CHANNEL1_CTRL) to control secondary output + * (CRT2 & LCD2) + * 1 : Use primary display control (CHANNEL0_CTRL) to control + * secondary output (LCD2 & CRT2) and use secondary display + * control (CHANNEL1_CTRL) to control primary output + * (LCD1 & CRT1) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long setLogicalDispOutput( + disp_output_t output, + unsigned char dispCtrlUsage +); + +/* + * This function set the logical display output. + * + * The output is called logical because it is independent of physical implementation. + * For example, CRT2 only mode is not using the internal secondary control. It uses the + * Primary Control with its output directed to CRT DAC. + * + * Input: + * isSecondDispay - Enable primary or secondary control + * 0 : Enable primary display control + * 1 : Enable secondary display control + * output - Logical Display output + * dispCtrlUsage - Display Control Flag Usage: + * 0 : Use primary display control (CHANNEL0_CTRL) to control + * primary output (LCD1 & CRT1) and use secondary display + * control (CHANNEL1_CTRL) to control secondary output + * (CRT2 & LCD2) + * 1 : Use primary display control (CHANNEL0_CTRL) to control + * secondary output (LCD2 & CRT2) and use secondary display + * control (CHANNEL1_CTRL) to control primary output + * (LCD1 & CRT1) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long setLogicalDispOutputExt( + long isSecondDisplay, + disp_output_t output, + unsigned char dispCtrlUsage +); +/* + * Use vertical sync as time delay function. + * Input: + * dispControl - Display Control (CHANNEL0_CTRL or CHANNEL1_CTRL) + * vsync_count - Number of vertical sync to wait. + * + * Note: + * This function is waiting for the next vertical sync. + */ +void waitNextVerticalSync(disp_control_t dispControl, unsigned long vsync_count); + +/* + * Use panel vertical sync line as time delay function. + * This function does not wait for the next VSync. Instead, it will wait + * until the current line reaches the Vertical Sync line. + * This function is really useful when flipping display to prevent tearing. + * + * Input: display control (CHANNEL0_CTRL or CHANNEL1_CTRL) + */ +void waitVSyncLine(disp_control_t dispControl); + +/* + * This function gets the panel type + * + * Output: + * panelType - The type of the panel to be set + */ +panel_type_t getPanelType(void); + +long setPanelType(panel_type_t panelType); + + +/* + * This function gets the CRT Monitor Detection Threshold value. + * + * Input: + * pRedValue - Pointer to a variable to store the Red color threshold + * value. + * pGreenValue - Pointer to a variable to store the Green color threshold + * value. + * pBlueValue - Pointer to a variable to store the Blue color threshold + * value. + */ +void getCRTDetectThreshold( + unsigned char *pRedValue, + unsigned char *pGreenValue, + unsigned char *pBlueValue +); + +/* + * This function detects if the CRT monitor is attached. + * + * Input: + * redValue - Threshold value to be detected on the red color. + * greenValue - Threshold value to be detected on the green color. + * blueValue - Threshold value to be detected on the blue color. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk750_detectCRTMonitor( + unsigned char redValue, + unsigned char greenValue, + unsigned char blueValue +); + +/* + * This function checks whether the scaling is enabled. + * + * Input: + * dispCtrl - Display control to be checked. + * + * Output: + * 0 - Scaling is not enabled + * 1 - Scaling is enabled + */ +unsigned char isScalingEnabled( + disp_control_t dispCtrl +); + + +#endif /* _DISPLAY_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_edid.c b/drivers/gpu/drm/smidrm/ddk750/ddk750_edid.c new file mode 100644 index 000000000000..882a90cbb74e --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_edid.c @@ -0,0 +1,2240 @@ +/******************************************************************* +* +* Copyright (c) 2009 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* edid.c --- SM750/SM718 DDK +* This file contains functions to interpret the EDID structure. +* +*******************************************************************/ +//#include +#include "ddk750_defs.h" +#include "ddk750_hardware.h" +#include "ddk750_helper.h" +#include "ddk750_hwi2c.h" +#include "ddk750_swi2c.h" +#include "ddk750_edid.h" + +#include "ddkdebug.h" +#include + +/* Enable this one to print the VDIF timing when debug is enabled. */ +//#define ENABLE_DEBUG_PRINT_VDIF + +/**************************************************************** + * Configuration setting + ****************************************************************/ +/* I2C Address of each Monitor. Currently, there is only one i2c bus and + both display devices will responds to 0xA0 address with analog CRT as the first priority + The second version of evaluation board will separate the i2c bus, so that each i2c bus + corresponds to one display devices. + The new monitor devices (at least the tested DVI monitor) also corresponds to 0xA2, + which is temporarily used in this DDK. */ +#define EDID_DEVICE_I2C_ADDRESS 0xA0 + +/* GPIO used for the I2C on the SMI0_PATH size */ +#define EDID_PANEL_I2C_SCL DEFAULT_I2C_SCL +#define EDID_PANEL_I2C_SDA DEFAULT_I2C_SDA + +/* GPIO used for the I2C on the SMI1_PATH size. + These GPIO pins only available in the Evaluation Board version 2.2. + Need to find out which pins are used for the SMI1_PATH i2c. */ +#define EDID_CRT_I2C_SCL 17 +#define EDID_CRT_I2C_SDA 18 + +#define TOTAL_EDID_REGISTERS 128 + +#define TOTAL_EDID_REGISTERS_128 128 +#define TOTAL_EDID_REGISTERS_256 256 +#define EDID_EXTEND_BLOCK 126 + + +typedef struct _est_timing_mode_t +{ + unsigned long x; /* Mode Width */ + unsigned long y; /* Mode Height */ + unsigned long hz; /* Refresh Rate */ + unsigned char source; /* Source: 0 - VESA + 1 - IBM + 2 - Apple + */ +} +est_timing_mode_t; + +/* These values only applies to EDID Version 1 */ +static est_timing_mode_t establishTiming[3][8] = +{ + /* Established Timing 1 */ + { + { 800, 600, 60, 0}, + { 800, 600, 56, 0}, + { 640, 480, 75, 0}, + { 640, 480, 72, 0}, + { 640, 480, 67, 2}, + { 640, 480, 60, 1}, + { 720, 400, 88, 1}, + { 720, 400, 70, 1}, + }, + { + {1280, 1024, 75, 0}, + {1024, 768, 75, 0}, + {1024, 768, 70, 0}, + {1024, 768, 60, 0}, + {1024, 768, 87, 1}, + { 832, 624, 75, 0}, + { 800, 600, 75, 0}, + { 800, 600, 72, 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}, + {1152, 870, 75, 2}, + } +}; + +static void printVdif( + vdif_t *pVDIF +) +{ +#ifdef DDKDEBUG + +#ifndef ENABLE_DEBUG_PRINT_VDIF + DDKDEBUGENABLE(0); +#endif + + DDKDEBUGPRINT((DISPLAY_LEVEL, "pixelClock = %d\n", pVDIF->pixelClock)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "characterWidth = %d\n", pVDIF->characterWidth)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "scanType = %s\n", (pVDIF->scanType == VDIF_INTERLACED) ? "Interlaced" : "Progressive")); + + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalFrequency = %d\n", pVDIF->horizontalFrequency)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalTotal = %d\n", pVDIF->horizontalTotal)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalActive = %d\n", pVDIF->horizontalActive)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalBlankStart = %d\n", pVDIF->horizontalBlankStart)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalBlankTime = %d\n", pVDIF->horizontalBlankTime)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalSyncStart = %d\n", pVDIF->horizontalSyncStart)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalRightBorder = %d\n", pVDIF->horizontalRightBorder)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalFrontPorch = %d\n", pVDIF->horizontalFrontPorch)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalSyncWidth = %d\n", pVDIF->horizontalSyncWidth)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalBackPorch = %d\n", pVDIF->horizontalBackPorch)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalLeftBorder = %d\n", pVDIF->horizontalLeftBorder)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalSyncPolarity = %s\n", + (pVDIF->horizontalSyncPolarity == VDIF_SYNC_NEGATIVE) ? "Negative" : "Positive")); + + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalFrequency = %d\n", pVDIF->verticalFrequency)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalTotal = %d\n", pVDIF->verticalTotal)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalActive = %d\n", pVDIF->verticalActive)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBlankStart = %d\n", pVDIF->verticalBlankStart)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBlankTime = %d\n", pVDIF->verticalBlankTime)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalSyncStart = %d\n", pVDIF->verticalSyncStart)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBottomBorder = %d\n", pVDIF->verticalBottomBorder)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalFrontPorch = %d\n", pVDIF->verticalFrontPorch)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalSyncHeight = %d\n", pVDIF->verticalSyncHeight)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBackPorch = %d\n", pVDIF->verticalBackPorch)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalTopBorder = %d\n", pVDIF->verticalTopBorder)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalSyncPolarity = %s\n", + (pVDIF->verticalSyncPolarity == VDIF_SYNC_NEGATIVE) ? "Negative" : "Positive")); + +#ifndef ENABLE_DEBUG_PRINT_VDIF + DDKDEBUGENABLE(1); +#endif +#endif +} + +/* + * edidGetVersion + * This function gets the EDID version + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRevision - Revision of the EDIE (if exist) + * + * Output: + * Revision number of the given EDID buffer. + */ +unsigned char edidGetVersion( + unsigned char *pEDIDBuffer, + unsigned char *pRevision +) +{ + unsigned char version; + + if (pEDIDBuffer != (unsigned char *)0) + { + /* Check the header */ + if ((pEDIDBuffer[0] == 0x00) && (pEDIDBuffer[1] == 0xFF) && (pEDIDBuffer[2] == 0xFF) && + (pEDIDBuffer[3] == 0xFF) && (pEDIDBuffer[4] == 0xFF) && (pEDIDBuffer[5] == 0xFF) && + (pEDIDBuffer[6] == 0xFF) && (pEDIDBuffer[7] == 0x00)) + { + /* + * EDID Structure Version 1. + */ + + /* Read the version field from the buffer. It should be 1 */ + version = pEDIDBuffer[18]; + + if (version == 1) + { + /* Copy the revision first */ + if (pRevision != (unsigned char *)0) + *pRevision = pEDIDBuffer[19]; + + return version; + } + } + else + { + /* + * EDID Structure Version 2 + */ + + /* Read the version and revision field from the buffer. */ + version = pEDIDBuffer[0]; + + if ((version >> 4) == 2) + { + /* Copy the revision */ + if (pRevision != (unsigned char *)0) + *pRevision = version & 0x0F; + + return (version >> 4); + } + } + } + + DDKDEBUGPRINT((DISPLAY_LEVEL, "Invalid EDID Structure\n")); + return 0; +} + +/* + * edidGetProductInfo + * This function gets the vendor and product information. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor [in] + * pManufacturerName - Pointer to a 3 byte length variable to store the manufacturer name [out] + * pProductCode - Pointer to a variable to store the product code [out] + * pSerialNumber - Pointer to a variable to store the serial number [out] + * pWeekOfManufacture - Pointer to a variable to store the week of manufacture [out] + * pYearOfManufacture - Pointer to a variable to store the year of manufacture + * or model year (if WeekOfManufacture is 0xff) [out] + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetProductInfo( + unsigned char *pEDIDBuffer, + char *pManufacturerName, + unsigned short *pProductCode, + unsigned long *pSerialNumber, + unsigned char *pWeekOfManufacture, + unsigned short *pYearOfManufacture +) +{ + unsigned char version, revision; + unsigned short manufactureID; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + if (pManufacturerName != (char *)0) + { + /* Swap the byte */ + manufactureID = (pEDIDStructure->manufacturerID >> 8) + (pEDIDStructure->manufacturerID << 8); + pManufacturerName[0] = ((manufactureID >> 10) & 0x001F) + 'A' - 1; + pManufacturerName[1] = ((manufactureID >> 5) & 0x001F) + 'A' - 1; + pManufacturerName[2] = (manufactureID & 0x001F) + 'A' - 1; + pManufacturerName[3] = '\0'; + } + + if (pProductCode != (unsigned short *)0) + *pProductCode = pEDIDStructure->productCode; + + /* Only EDID structure version 1.1 and 1.2 supports this. EDID 1.3 uses + detail timing descriptor to store the serial number in ASCII. */ + if (pSerialNumber != (unsigned long *)0) + *pSerialNumber = pEDIDStructure->serialNumber; + + /* + * Rev 1.3: - A value of 0 means that week of manufacture is not specified + * - A value in the range of 1 to 54 (0x01 - 0x36) means the week of manufacture + * - Any values greater than 54 is invalid. + * + * Rev 1.4: - A value of 0 means that week of manufacture is not specified + * - A value in the range of 1 to 54 (0x01 - 0x36) means the week of manufacture + * - A value of 0xFF means that Year of Manufacture contains the model year + * instead of year of Manufacture. + * - Other values means invalid + */ + if (pWeekOfManufacture != (unsigned char *)0) + *pWeekOfManufacture = pEDIDStructure->weekOfManufacture; + + /* The value must be greater than 3 and less than or equal to the current + year minus 1990. + A value of 3 or less would indicated that the display was manufactured + before the EDID standard was defined. + A value greater than (current year - 1990) would indicate that the display + has not yet been manufactured. + */ + if (pYearOfManufacture != (unsigned short *)0) + *pYearOfManufacture = (unsigned short) pEDIDStructure->yearOfManufacture + 1990; + + return 0; + } + + return (-1); +} + +/* + * edidCheckMonitorInputSignal + * This function checks whether the monitor is expected analog/digital + * input signal. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Analog + * 1 - Digital + */ +unsigned char edidCheckMonitorInputSignal( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->videoInputDefinition.analogSignal.inputSignal; + + return 0; +} + +/* + * edidGetAnalogSignalInfo + * This function gets the analog video input signal information + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRefWhiteAboveBlank - Pointer to a variable to store the reference white above blank + * value. The value is in milliVolt. + * pSyncLevelBelowBlank - Pointer to a variable to store the Sync tip level below blank + * The value is also in milliVolt + * pBlank2BlackSetup - Pointer to a variable to store the Blank to black setup or + * pedestal per appropriate Signal Level Standard flag. + * 1 means that the display expect the setup. + * pSeparateSyncSupport - Pointer to a variable to store the flag to indicate that the + * monitor supports separate sync. + * pCompositeSyncSupport - Pointer to a variable to store a flag to indicate that the + * monitor supports composite sync. + * pSyncOnGreenSupport - Pointer to a variable to store a flag to indicate that + * the monitor supports sync on green video. + * pVSyncSerrationRequired - Pointer to a variable to store a flag to indicate that serration + * of the VSync pulse is required when composite sync or + * sync-on-green video is used. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetAnalogSignalInfo( + unsigned char *pEDIDBuffer, + unsigned short *pRefWhiteAboveBlank, + unsigned short *pSyncLevelBelowBlank, + unsigned char *pBlank2BlackSetup, + unsigned char *pSeparateSyncSupport, + unsigned char *pCompositeSyncSupport, + unsigned char *pSyncOnGreenSupport, + unsigned char *pVSyncSerrationRequired +) +{ + unsigned char version, revision; + unsigned short whiteReference, syncLevel; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + /* Check if the input signal is analog */ + if (pEDIDStructure->videoInputDefinition.analogSignal.inputSignal != 0) + return (-1); + + switch (pEDIDStructure->videoInputDefinition.analogSignal.signalLevelStd) + { + case 0: + whiteReference = 700; + syncLevel = 300; + break; + case 1: + whiteReference = 714; + syncLevel = 286; + break; + case 2: + whiteReference = 1000; + syncLevel = 400; + break; + case 3: + whiteReference = 700; + syncLevel = 0; + break; + } + + if (pRefWhiteAboveBlank != (unsigned short *)0) + *pRefWhiteAboveBlank = whiteReference; + + if (pSyncLevelBelowBlank != (unsigned short *)0) + *pSyncLevelBelowBlank = syncLevel; + + if (pBlank2BlackSetup != (unsigned char *)0) + *pBlank2BlackSetup = (unsigned char) + pEDIDStructure->videoInputDefinition.analogSignal.blank2Black; + + if (pSeparateSyncSupport != (unsigned char *)0) + *pSeparateSyncSupport = (unsigned char) + pEDIDStructure->videoInputDefinition.analogSignal.separateSyncSupport; + + if (pCompositeSyncSupport != (unsigned char *)0) + *pCompositeSyncSupport = (unsigned char) + pEDIDStructure->videoInputDefinition.analogSignal.compositeSyncSupport; + + if (pSyncOnGreenSupport != (unsigned char *)0) + *pSyncOnGreenSupport = (unsigned char) + pEDIDStructure->videoInputDefinition.analogSignal.syncOnGreenSupport; + + if (pVSyncSerrationRequired != (unsigned char *)0) + *pVSyncSerrationRequired = (unsigned char) + pEDIDStructure->videoInputDefinition.analogSignal.vsyncSerration; + + return 0; + } + else + { + /* EDID Structure 2 */ + } + + return (-1); +} + +/* + * edidGetDigitalSignalInfo + * This function gets the digital video input signal information. + * Only applies to EDID 1.3 and above. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pDFP1xSupport - Pointer to a variable to store the flag to indicate that + * the mointor interface is signal compatible with VESA + * DFP 1.x TMDS CRGB, 1 pixel/clock, up to 8 bits / color + * MSB aligned, DE active high + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetDigitalSignalInfo( + unsigned char *pEDIDBuffer, + unsigned char *pDFP1xSupport +) +{ + unsigned char version, revision; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, &revision); + + if ((version == 1) && (revision == 3)) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + /* Check if the input signal is digital */ + if (pEDIDStructure->videoInputDefinition.digitalSignal.inputSignal != 1) + return (-1); + + if (pDFP1xSupport != (unsigned char *)0) + *pDFP1xSupport = pEDIDStructure->videoInputDefinition.digitalSignal.dfp1Support; + + return 0; + } + + return (-1); +} + +/* + * edidGetDisplaySize + * This function gets the display sizes in cm. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMaxHorzImageSize - Pointer to a variable to store the maximum horizontal + * image size to the nearest centimeter. A value of 0 + * indicates that the size is indeterminate size. + * pMaxVertImageSize - Pointer to a variable to store the maximum vertical + * image size to the nearest centimeter. A value of 0 + * indicates that the size is indeterminate size. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetDisplaySize( + unsigned char *pEDIDBuffer, + unsigned char *pMaxHorzImageSize, + unsigned char *pMaxVertImageSize +) +{ + unsigned char version, revision; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + if (pMaxHorzImageSize != (unsigned char *)0) + *pMaxHorzImageSize = pEDIDStructure->maxHorzImageSize; + + if (pMaxVertImageSize != (unsigned char *)0) + *pMaxVertImageSize = pEDIDStructure->maxVertImageSize; + + return 0; + } + + return (-1); +} + +#if 0 /* Use the edidGetWhitePoint to get the Gamma */ +/* + * edidGetGamma + * This function gets the Display Transfer Characteristic (Gamma). + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * Gamma value multiplied by 100. A value of 0xFFFF (-1) indicates that + * the gamma value is not defined. + */ +unsigned short edidGetGamma( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned short)(((edid_version_1_t *)pEDIDBuffer)->displayTransferChar + 100); + + return (-1); +} +#endif + +/* + * edidGetPowerManagementSupport + * This function gets the monitor's power management support. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStandBy - Pointer to a variable to store the flag to indicate that + * standby power mode is supported. + * pSuspend - Pointer to a variable to store the flag to indicate that + * suspend power mode is supported. + * pLowPower - Pointer to a variable to store the flag to indicate that + * the display consumes low power when it receives a timing + * signal that is outside its declared active operating range. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetPowerManagementSupport( + unsigned char *pEDIDBuffer, + unsigned char *pStandBy, + unsigned char *pSuspend, + unsigned char *pLowPower +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + if (pStandBy != (unsigned char *)0) + *pStandBy = (unsigned char) pEDIDStructure->featureSupport.standbySupport; + + if (pSuspend != (unsigned char *)0) + *pSuspend = (unsigned char) pEDIDStructure->featureSupport.suspendSupport; + + if (pLowPower != (unsigned char *)0) + *pLowPower = (unsigned char) pEDIDStructure->featureSupport.lowPowerSupport; + + return 0; + } + + return (-1); +} + +/* + * edidGetDisplayType + * This function gets the display type. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Monochrome / grayscale display + * 1 - RGB Color Display + * 2 - Non-RGB multicolor display, e.g. R/G/Y + * 3 - Undefined + */ +unsigned char edidGetDisplayType( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.displayType; + + return (3); +} + +/* + * edidChecksRGBUsage + * This function checks if the display is using the sRGB standard default + * color space as its primary color space. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Does not use sRGB as its primary color space + * 1 - Use sRGB as its primary color space + */ +unsigned char edidChecksRGBUsage( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.sRGBSupport; + + return (0); +} + +/* + * edidIsPreferredTimingAvailable + * This function checks whether the preffered timing mode is available. + * Use of preferred timing mode is required by EDID structure version 1 + * Revision 3 and higher. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Preferred Timing is not available + * 1 - Preferred Timing is available + */ +unsigned char edidIsPreferredTimingAvailable( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + + if (pEDIDBuffer != (unsigned char *)0) + { + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.preferredTiming; + } + + return (0); +} + +/* + * edidIsDefaultGTFSupported + * This function checks whether the display supports timings based on the + * GTF standard using default GTF parameter values. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Default GTF is not supported + * 1 - Default GTF is supported + */ +unsigned char edidIsDefaultGTFSupported( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.defaultGTFSupport; + + return (0); +} + +/* + * edidCalculateChromaticValue + * This function calculates the chromatic value. + * + * Input: + * colorBinaryValue - Color Characteristic Binary Representation Value + * to be computed + * + * Output: + * The chromatic value times a 1000. + */ +static unsigned short edidCalculateChromaticValue( + unsigned short colorBinaryValue +) +{ + unsigned long index; + unsigned long result; + + result = 0; + for (index = 10; index > 0; index--) + { + /* Times 1000000 to make it accurate to the micro value. */ + result += roundedDiv((colorBinaryValue & 0x0001) * 1000000, twoToPowerOfx(index)); + colorBinaryValue >>= 1; + } + + /* Make it accurate to 1000 place */ + return ((unsigned short)roundedDiv(result, 1000)); +} + +/* + * edidGetColorCharacteristic + * This function gets the chromaticity and white point values expressed as + * an integer value which represents the actual value times 1000. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRedX - Pointer to a variable to store the Red X values + * pRedY - Pointer to a variable to store the Red Y values + * pGreenX - Pointer to a variable to store the Green X values + * pGreenY - Pointer to a variable to store the Green Y values + * pBlueX - Pointer to a variable to store the Blue X values + * pBlueY - Pointer to a variable to store the Blue Y values + * + * Note: + * To get the White color characteristic, use the edidGetWhitePoint + */ +void edidGetColorCharacteristic( + unsigned char *pEDIDBuffer, + unsigned short *pRedX, + unsigned short *pRedY, + unsigned short *pGreenX, + unsigned short *pGreenY, + unsigned short *pBlueX, + unsigned short *pBlueY +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + if (pRedX != (unsigned short *)0) + { + *pRedX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->redX << 2) + + (unsigned short)pEDIDStructure->redGreenLowBits.redXLowBits); + } + + if (pRedY != (unsigned short *)0) + { + *pRedY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->redY << 2) + + (unsigned short)pEDIDStructure->redGreenLowBits.redYLowBits); + } + + if (pGreenX != (unsigned short *)0) + { + *pGreenX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->greenX << 2) + + (unsigned short)pEDIDStructure->redGreenLowBits.greenXLowBits); + } + + if (pGreenY != (unsigned short *)0) + { + *pGreenY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->greenY << 2) + + (unsigned short)pEDIDStructure->redGreenLowBits.greenYLowBits); + } + + if (pBlueX != (unsigned short *)0) + { + *pBlueX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->blueX << 2) + + (unsigned short)pEDIDStructure->blueWhiteLowBits.blueXLowBits); + } + + if (pBlueY != (unsigned short *)0) + { + *pBlueY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->blueY << 2) + + (unsigned short)pEDIDStructure->blueWhiteLowBits.blueYLowBits); + } + } +} + +/* + * edidGetWhitePoint + * This function gets the white point. + * To get the default white point, set the index to 0. For multiple white point, + * call this function multiple times to check if more than 1 white point is supported. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pWhitePointIndex - Pointer to a variable that contains the white point index + * to be retrieved. + * pWhiteX - Pointer to a variable to store the White X value + * pWhiteY - Pointer to a variable to store the White Y value + * pWhiteGamma - Pointer to a variable to store the White Gamma value + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetWhitePoint( + unsigned char *pEDIDBuffer, + unsigned char *pWhitePointIndex, + unsigned short *pWhiteX, + unsigned short *pWhiteY, + unsigned short *pWhiteGamma +) +{ + unsigned char version, index, tableIndex; + + if (pWhitePointIndex == (unsigned char *)0) + return (-1); + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + /* Get the index to a temporary variable and increment the index for the + next loop. */ + index = *pWhitePointIndex; + (*pWhitePointIndex)++; + + if (index == 0) + { + if (pWhiteX != (unsigned short *)0) + { + *pWhiteX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->whiteX << 2) + + (unsigned short)pEDIDStructure->blueWhiteLowBits.whiteXLowBits); + } + + if (pWhiteY != (unsigned short *)0) + { + *pWhiteY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->whiteY << 2) + + (unsigned short)pEDIDStructure->blueWhiteLowBits.whiteYLowBits); + } + + if (pWhiteGamma != (unsigned short *)0) + *pWhiteGamma = pEDIDStructure->displayTransferChar + 100; + + return 0; + } + else + { + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFB) && + (pMonitorDescriptor->descriptor.colorPoint.white[index-1].whitePointIndex != 0)) + { + if (pWhiteX != (unsigned short *)0) + { + *pWhiteX = edidCalculateChromaticValue(((unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteX << 2) + + (unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteLowBits.whiteXLowBits); + } + + if (pWhiteY != (unsigned short *)0) + { + *pWhiteY = edidCalculateChromaticValue(((unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteY << 2) + + (unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteLowBits.whiteYLowBits); + } + + if (pWhiteGamma != (unsigned short *)0) + *pWhiteGamma = pMonitorDescriptor->descriptor.colorPoint.white[index-1].gamma + 100; + + return 0; + } + } + } + } + + return (-1); +} + +/* + * edidCalculateChecksum + * This function adds all one-byte value of the EDID buffer. + * The total should be equal to 0x00 + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * Total of one-byte values. It should equal to 0x00. A value other than + * 0x00 indicates the EDID buffer is not valid. + */ +__attribute__((unused)) static unsigned char edidCalculateChecksum( + unsigned char *pEDIDBuffer) +{ + unsigned char version, revision, checksum; + unsigned short index; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, &revision); + + checksum = 0; + if (version == 1) + { + for (index = 0; index < 128; index++) + checksum += pEDIDBuffer[index]; + } + + return checksum; +} + +/* + * edidGetExtension + * This function gets the number of (optional) EDID extension blocks to follow + * the given EDID buffer. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * Total number of EDID Extension to follow the given EDID buffer. + */ +unsigned char edidGetExtension( + unsigned char *pEDIDBuffer +) +{ + unsigned char version, revision; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + return ((edid_version_1_t *)pEDIDBuffer)->extFlag; + + return 0; +} + +#define EDID_TOTAL_RETRY_COUNTER 1 + +#if 0 + +/* + * edidReadMonitor + * This function reads the EDID structure from the attached monitor + * + * Input: + * displayPath - Display device which EDID to be read from. + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * sclGpio - GPIO pin used as the I2C Clock (SCL) + * sdaGpio - GPIO pin used as the I2C Data (SDA) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk750_edidReadMonitorEx( + disp_path_t displayPath, + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char sclGpio, + unsigned char sdaGpio +) +{ + unsigned char value, retry, edidVersion, edidRevision; + unsigned char edidBuffer[256]; + unsigned long offset; + + /* Initialize the i2c bus */ + swI2CInit(sclGpio, sdaGpio); + + for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++) + { + DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry)); + + /* Read the EDID from the monitor. */ + for (offset = 0; offset < TOTAL_EDID_REGISTERS; offset++) + edidBuffer[offset] = swI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); + + /* Check if the EDID is valid. */ + edidVersion = edidGetVersion((unsigned char *)&edidBuffer, (unsigned char *)&edidRevision); + DDKDEBUGPRINT((DISPLAY_LEVEL, "EDID Structure Version: %d.%d\n", edidVersion, edidRevision)); + if (edidVersion != 0) + break; + } + + /* + * The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol, + * which uses the Vertical Sync to clock in the EDID data. + * Currently this function return error. DDC1 protocol can be added later. + */ + if (retry == EDID_TOTAL_RETRY_COUNTER) + { + /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is + * only an acknowledge flag, which could be high or low. However, SCL line + * is not used. Instead the data is clock-in using vertical sync. + */ + return (-1); + } + + /* Copy the data to the given buffer */ + if (pEDIDBuffer != (unsigned char *)0) + { + for (offset = 0; offset < bufferSize; offset++) + pEDIDBuffer[offset] = edidBuffer[offset]; + } + +#if 0 /*def DDKDEBUG*/ + for (offset = 0; offset < TOTAL_EDID_REGISTERS; offset++) + { + if ((offset % 16) == 0) + { + if (offset != 0) + DDKDEBUGPRINT((0/*DISPLAY_LEVEL*/, "\n")); + DDKDEBUGPRINT((0/*DISPLAY_LEVEL*/, "%02x:\t", offset)); + } + DDKDEBUGPRINT((0/*DISPLAY_LEVEL*/, "%02x ", pEDIDBuffer[offset])); + } + DDKDEBUGPRINT((0/*DISPLAY_LEVEL*/, "\n")); +#endif + + return 0; +} + +#else + +/* + * ddk750_edidReadMonitor + * This function reads the EDID structure from the attached monitor + * + * Input: + * displayPath - Display device which EDID to be read from. + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * sclGpio - GPIO pin used as the I2C Clock (SCL) + * sdaGpio - GPIO pin used as the I2C Data (SDA) + * + * Output: + * 0 - Fail + * edidSize - Success and return the edid's size + */ +long ddk750_edidReadMonitorEx( + disp_path_t displayPath, + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char sclGpio, + unsigned char sdaGpio +) +{ + unsigned char retry, edidVersion, edidRevision; + unsigned char edidBuffer[TOTAL_EDID_REGISTERS_256]; + unsigned long offset; + long edidSize = TOTAL_EDID_REGISTERS_128; + + /* Initialize the i2c bus */ + swI2CInit(sclGpio, sdaGpio); + + for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++) + { + // DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry)); +#ifndef READ_EDID_CONTINUOUS + /* Read the EDID from the monitor. */ + for (offset = 0; offset < TOTAL_EDID_REGISTERS_128; offset++) + edidBuffer[offset] = swI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); +#else + if (!swI2CReadReg_Continuous(EDID_DEVICE_I2C_ADDRESS, 0, TOTAL_EDID_REGISTERS_128, edidBuffer)) + memset(edidBuffer, 0xFF, TOTAL_EDID_REGISTERS_128); /* read error */ +#endif + + if(edidBuffer[EDID_EXTEND_BLOCK]) + { +#ifndef READ_EDID_CONTINUOUS + for (offset = TOTAL_EDID_REGISTERS_128; offset < TOTAL_EDID_REGISTERS_256; offset++) + edidBuffer[offset] = swI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); +#else + if (!swI2CReadReg_Continuous(EDID_DEVICE_I2C_ADDRESS, TOTAL_EDID_REGISTERS_128, TOTAL_EDID_REGISTERS_128, edidBuffer + TOTAL_EDID_REGISTERS_128)) + memset(edidBuffer + TOTAL_EDID_REGISTERS_128, 0xFF, TOTAL_EDID_REGISTERS_128); /* read error */ +#endif + edidSize = TOTAL_EDID_REGISTERS_256; + } + + /* Check if the EDID is valid. */ + edidVersion = edidGetVersion((unsigned char *)&edidBuffer, (unsigned char *)&edidRevision); + //DDKDEBUGPRINT((DISPLAY_LEVEL, "EDID Structure Version: %d.%d\n", edidVersion, edidRevision)); + if (edidVersion != 0) + break; + } + + /* + * The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol, + * which uses the Vertical Sync to clock in the EDID data. + * Currently this function return error. DDC1 protocol can be added later. + */ + if (retry == EDID_TOTAL_RETRY_COUNTER) + { + /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is + * only an acknowledge flag, which could be high or low. However, SCL line + * is not used. Instead the data is clock-in using vertical sync. + */ + return 0; + } + + /* Copy the data to the given buffer */ + if (pEDIDBuffer != (unsigned char *)0) + { + for (offset = 0; offset < edidSize; offset++) + pEDIDBuffer[offset] = edidBuffer[offset]; + } + + return edidSize; +} + +#endif + +long ddk750_edidReadMonitorEx_HW( + disp_path_t displayPath, + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo +) +{ + unsigned char value, retry, edidVersion, edidRevision; + unsigned char edidBuffer[256]; + unsigned long offset; + long edidSize = 0; + + /* Initialize the i2c bus */ + ddk750_hwI2CInit(1); + +#if 0 + for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++) + { + + /* Read the EDID from the monitor. */ + for (offset = 0; offset < TOTAL_EDID_REGISTERS; offset++) + edidBuffer[offset] = ddk750_hwI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); + + /* Check if the EDID is valid. */ + edidVersion = edidGetVersion((unsigned char *)&edidBuffer, (unsigned char *)&edidRevision); + if (edidVersion != 0) + break; + } +#else + + for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++) + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry)); + edidSize = 0; + /* Read the EDID from the monitor. */ + for (offset = 0; offset < TOTAL_EDID_REGISTERS_128; offset++) + { + value = ddk750_hwI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); + if(0xFFFFFFFF == value) + break; + edidBuffer[offset] = (0xFF & value); + } + if(0xFFFFFFFF != value) + { + edidSize = TOTAL_EDID_REGISTERS_128; + if(edidBuffer[EDID_EXTEND_BLOCK]) + { + for (offset = TOTAL_EDID_REGISTERS_128; offset < TOTAL_EDID_REGISTERS_256; offset++) + { + value = ddk750_hwI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); + + if(0xFFFFFFFF == value) + break; + edidBuffer[offset] = (0xFF & value); + } + + if(0xFFFFFFFF != value) + edidSize = TOTAL_EDID_REGISTERS_256; + } + if(0xFFFFFFFF != value) + { + /* Check if the EDID is valid. */ + edidVersion = edidGetVersion((unsigned char *)&edidBuffer, (unsigned char *)&edidRevision); + // DDKDEBUGPRINT((DISPLAY_LEVEL, "EDID Structure Version: %d.%d\n", edidVersion, edidRevision)); + if (edidVersion != 0) + break; + } + } + } + +#endif + /* Finish using HW I2C, we can close the device. */ + ddk750_hwI2CClose(); + + /* + * The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol, + * which uses the Vertical Sync to clock in the EDID data. + * Currently this function return error. DDC1 protocol can be added later. + */ + if (retry == EDID_TOTAL_RETRY_COUNTER) + { + /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is + * only an acknowledge flag, which could be high or low. However, SCL line + * is not used. Instead the data is clock-in using vertical sync. + */ + return (-1); + } + + /* Copy the data to the given buffer */ + if (pEDIDBuffer != (unsigned char *)0) + { + for (offset = 0; offset < edidSize; offset++) + pEDIDBuffer[offset] = edidBuffer[offset]; + } + +#if 0 /*def DDKDEBUG*/ + for (offset = 0; offset < TOTAL_EDID_REGISTERS; offset++) + { + if ((offset % 16) == 0) + { + if (offset != 0) + DDKDEBUGPRINT((0/*DISPLAY_LEVEL*/, "\n")); + DDKDEBUGPRINT((0/*DISPLAY_LEVEL*/, "%02x:\t", offset)); + } + DDKDEBUGPRINT((0/*DISPLAY_LEVEL*/, "%02x ", pEDIDBuffer[offset])); + } + DDKDEBUGPRINT((0/*DISPLAY_LEVEL*/, "\n")); +#endif + + return edidSize; +} + + + +/* + * edidReadMonitor + * This function reads the EDID structure from the attached monitor + * + * Input: + * displayPath - Display device which EDID to be read from. + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk750_edidReadMonitor( + disp_path_t displayPath, + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo +) +{ + return ddk750_edidReadMonitorEx(displayPath, pEDIDBuffer, bufferSize, edidExtNo, DEFAULT_I2C_SCL, DEFAULT_I2C_SDA); +} + +#define HEADER_EDID_REGISTERS 8 + +/* + * edidGetHeader + * This function gets the EDID Header + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 get header success; -1 fail. + */ +unsigned char ddk750_edidGetHeader( + unsigned char *pEDIDBuffer +) +{ + if (pEDIDBuffer != (unsigned char *)0) + { + /* Check the header */ + if ((pEDIDBuffer[0] == 0x00) && (pEDIDBuffer[1] == 0xFF) && (pEDIDBuffer[2] == 0xFF) && + (pEDIDBuffer[3] == 0xFF) && (pEDIDBuffer[4] == 0xFF) && (pEDIDBuffer[5] == 0xFF) && + (pEDIDBuffer[6] == 0xFF) && (pEDIDBuffer[7] == 0x00)) + { + return 0; + } + else + return -1; + } + + // DDKDEBUGPRINT((DISPLAY_LEVEL, "Invalid EDID bufffer\n")); + return -1; +} + + + +/* + * edidHeaderReadMonitor + * This function reads the EDID header from the attached monitor + * + * Input: + * sclGpio - GPIO pin used as the I2C Clock (SCL) + * sdaGpio - GPIO pin used as the I2C Data (SDA) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk750_edidHeaderReadMonitorEx( + unsigned char sclGpio, + unsigned char sdaGpio +) +{ + unsigned char retry;//value, + unsigned char edidBuffer[10]; +#ifndef READ_EDID_CONTINUOUS + unsigned long offset; +#endif + + /* Initialize the i2c bus */ + swI2CInit(sclGpio, sdaGpio); + + for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++) + { + // DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry)); + +#ifndef READ_EDID_CONTINUOUS + /* Read the EDID from the monitor. */ + for (offset = 0; offset < HEADER_EDID_REGISTERS; offset++) + edidBuffer[offset] = swI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); +#else + if (!swI2CReadReg_Continuous(EDID_DEVICE_I2C_ADDRESS, 0, HEADER_EDID_REGISTERS, edidBuffer)) + memset(edidBuffer, 0xFF, HEADER_EDID_REGISTERS); /* read error */ +#endif + + + /* Check if the EDID header is valid. */ + if (!ddk750_edidGetHeader((unsigned char *)&edidBuffer)) + break; + } + + /* + * The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol, + * which uses the Vertical Sync to clock in the EDID data. + * Currently this function return error. DDC1 protocol can be added later. + */ + if (retry == EDID_TOTAL_RETRY_COUNTER) + { + /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is + * only an acknowledge flag, which could be high or low. However, SCL line + * is not used. Instead the data is clock-in using vertical sync. + */ + return (-1); + } + + return 0; +} + +long ddk750_edidHeaderReadMonitorExHwI2C(void) +{ + unsigned char retry;//value, + unsigned char edidBuffer[10]; + unsigned long offset; + + /* Initialize the i2c bus */ + ddk750_hwI2CInit(1); + + for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++) + { + DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry)); + + /* Read the EDID from the monitor. */ + for (offset = 0; offset < HEADER_EDID_REGISTERS; offset++) + edidBuffer[offset] = ddk750_hwI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); + + /* Check if the EDID header is valid. */ + if (!ddk750_edidGetHeader((unsigned char *)&edidBuffer)) + break; + } + + /* Finish using HW I2C, we can close the device. */ + //ddk750_hwI2CClose(); + + /* + * The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol, + * which uses the Vertical Sync to clock in the EDID data. + * Currently this function return error. DDC1 protocol can be added later. + */ + if (retry == EDID_TOTAL_RETRY_COUNTER) + { + /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is + * only an acknowledge flag, which could be high or low. However, SCL line + * is not used. Instead the data is clock-in using vertical sync. + */ + return 0; + } + + return 1; +} + + + + +/* + * edidGetEstablishedTiming + * This function gets the established timing list from the given EDID buffer, + * table, and timing index. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor (In) + * pEstTableIndex - Pointer to the Established Timing Table index (In/Out) + * pIndex - Pointer to the Establihsed Timing Index (In/Out) + * pWidth - Pointer to a variable that to store the horizontal active / width + * value of the retrieved timing (Out) + * pHeight - Pointer to a variable to store the vertical active / height + * value of the retrieved timing (Out) + * pRefreshRate - Pointer to a variable to store the vertical frequency value + * of the retrieved timing (out) + * pSource - Pointer to a variable to store the standard timing source: + * 0 - VESA + * 1 - IBM + * 2 - Apple + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetEstablishedTiming( + unsigned char *pEDIDBuffer, + /*unsigned char *pEstTableIndex,*/ + unsigned char *pIndex, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pRefreshRate, + unsigned char *pSource +) +{ + unsigned char version, revision; + unsigned char tableIndex, index; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + while (1) + { + /* Get index */ + index = *pIndex; + + if (index > 16) + break; + + /* Search Established Table index 0 when the index is less than 8 */ + tableIndex = index / 8; + + /* Exit the function when it has reached the last table. */ + if (tableIndex > 2) + break; + + /* Increment the index value and update the index accordingly */ + (*pIndex)++; + index %= 8; + + /* Check */ + if ((pEDIDStructure->estTiming[tableIndex] & (1 << index)) != 0) + { + if (pWidth != (unsigned long *)0) + *pWidth = establishTiming[tableIndex][index].x; + + if (pHeight != (unsigned long *)0) + *pHeight = establishTiming[tableIndex][index].y; + + if (pRefreshRate != (unsigned long *)0) + *pRefreshRate = establishTiming[tableIndex][index].hz; + + if (pSource != (unsigned char *)0) + *pSource = establishTiming[tableIndex][index].source; + + /* Return success */ + return 0; + } + } + } + else + { + /* EDID Structure Version 2.0. */ + } + + return (-1); +} + +/* + * edidCalculateStdTiming + * This function calculates the width, height, and vertical frequency values + * from the given Standard Timing structure. This function only applies to + * EDID structure version 1. It will give the wrong result when used with + * EDID version 2. + * + * Input: + * pStdTiming - Pointer to a standard timing structure that contains the + * standard timing value to be calculated (In) + * edid1Revision - Revision of the EDID 1 (In) + * pWidth - Pointer to a variable that to store the horizontal active / width + * value of the retrieved timing (Out) + * pHeight - Pointer to a variable to store the vertical active / height + * value of the retrieved timing (Out) + * pRefreshRate - Pointer to a variable to store the vertical frequency value + * of the retrieved timing (out) + * + * Output: + * 0 - Success + * -1 - Fail + */ +static long edidCalculateStdTiming( + standard_timing_t *pStdTiming, + unsigned char edid1Revision, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pRefreshRate +) +{ + unsigned long x, y; + + /* Calculate the standard timing into x and y mode dimension */ + if (pStdTiming->horzActive != 0x01) + { + /* Calculate the X and Y */ + x = (pStdTiming->horzActive + 31) * 8; + switch (pStdTiming->stdTimingInfo.aspectRatio) + { + case 0: + if (edid1Revision != 3) + y = x; /* 1:1 aspect ratio (prior revision 1.3) */ + else + y = x * 10 / 16; /* 16:10 aspect ratio (revision 1.3) */ + break; + case 1: + y = x * 3 / 4; /* 4:3 aspect ratio */ + break; + case 2: + y = x * 4 / 5; /* 5:4 aspect ratio */ + break; + case 3: + y = x * 9 / 16; /* 16:9 aspect ratio */ + break; + } + + if (pWidth != (unsigned long *)0) + *pWidth = x; + + if (pHeight != (unsigned long *)0) + *pHeight = y; + + if (pRefreshRate != (unsigned long *)0) + *pRefreshRate = pStdTiming->stdTimingInfo.refreshRate + 60; + + return 0; + } + + return (-1); +} + +/* + * edidGetStandardTiming + * This function gets the standard timing from the given EDID buffer and + * calculates the width, height, and vertical frequency from that timing. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStdTimingIndex - Pointer to a standard timing index to be retrieved + * pWidth - Pointer to a variable that to store the horizontal active / width + * value of the retrieved timing (Out) + * pHeight - Pointer to a variable to store the vertical active / height + * value of the retrieved timing (Out) + * pRefreshRate - Pointer to a variable to store the vertical frequency value + * of the retrieved timing (out) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetStandardTiming( + unsigned char *pEDIDBuffer, + unsigned char *pStdTimingIndex, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pRefreshRate +) +{ + unsigned char version, revision, timingIndex, tableIndex; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + while (1) + { + /* There are only 8 standard timing entries */ + if (*pStdTimingIndex > 7) + break; + + /* Get the table index first before incrementing the index. */ + timingIndex = *pStdTimingIndex; + + /* Increment the standard timing index */ + (*pStdTimingIndex)++; + + if (timingIndex < 8) + { + /* + * Search the first Standard Timing Identifier table + */ + + /* Calculate the standard timing into x and y mode dimension */ + if (edidCalculateStdTiming(&pEDIDStructure->stdTiming[timingIndex], + revision, pWidth, pHeight, pRefreshRate) == 0) + { + return 0; + } + } + else + { + /* + * Search Standard Timing Identifier Table in the detailed Timing block. + */ + + /* + * Each Detailed Timing Identifier can contains 6 entries of Standard Timing + * Identifier. Based on this value, we can get the Detailed Timing Table Index + * that contains the requested standard timing. + */ + timingIndex = timingIndex - 8; + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + /* Get detailed info */ + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFA)) + { + if (timingIndex >= 6) + { + timingIndex-=6; + continue; + } + else + { + if (edidCalculateStdTiming(&pMonitorDescriptor->descriptor.stdTimingExt.stdTiming[timingIndex], + revision, pWidth, pHeight, pRefreshRate) == 0) + { + return 0; + } + } + } + } + } + } + } + else + { + /* EDID Structure version 2 */ + } + + return (-1); +} + +/* + * edidGetDetailedTiming + * This function gets the detailed timing from the given EDID buffer. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pDetailedTimingIndex - Pointer to a detailed timing index to be retrieved + * pModeParameter - Pointer to a mode_parameter_t structure that will be + * filled with the detailed timing. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetDetailedTiming( + unsigned char *pEDIDBuffer, + unsigned char *pDetailedTimingIndex, + vdif_t *pVDIF +) +{ + unsigned char version, revision, tableIndex; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + detailed_timing_t *pDetailedTiming; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + while (1) + { + if (*pDetailedTimingIndex > 3) + break; + + /* Get the Detail Timing entry index */ + tableIndex = *pDetailedTimingIndex; + + /* Increment the index */ + (*pDetailedTimingIndex)++; + + /* Get detailed info */ + pDetailedTiming = &pEDIDStructure->miscInformation.detailTiming[tableIndex]; + if ((pDetailedTiming->pixelClock != 0) && (pVDIF != (vdif_t *)0)) + { + /* Translate the Detail timing to VDIF format. */ + pVDIF->pixelClock = (unsigned long)pDetailedTiming->pixelClock * 10000; + pVDIF->characterWidth = 8; + pVDIF->scanType = (pDetailedTiming->flags.interlaced == 0) ? VDIF_NONINTERLACED : VDIF_INTERLACED; + + pVDIF->horizontalActive = + ((unsigned long)pDetailedTiming->horzActiveBlanking.horzActiveMSB << 8) + + (unsigned long)pDetailedTiming->horzActive; + pVDIF->horizontalBlankStart = pVDIF->horizontalActive; + pVDIF->horizontalBlankTime = + ((unsigned long)pDetailedTiming->horzActiveBlanking.horzBlankingMSB << 8) + + (unsigned long)pDetailedTiming->horzBlanking; + pVDIF->horizontalTotal = pVDIF->horizontalActive + pVDIF->horizontalBlankTime; + pVDIF->horizontalFrontPorch = + ((unsigned long)pDetailedTiming->syncAuxInfo.horzSyncOffset << 8) + + (unsigned long)pDetailedTiming->horzSyncOffset; + pVDIF->horizontalSyncStart = pVDIF->horizontalBlankStart + pVDIF->horizontalFrontPorch; + pVDIF->horizontalSyncWidth = + ((unsigned long)pDetailedTiming->syncAuxInfo.horzSyncWidth << 8) + + (unsigned long)pDetailedTiming->horzSyncPulseWidth; + pVDIF->horizontalBackPorch = + pVDIF->horizontalBlankTime - (pVDIF->horizontalFrontPorch + pVDIF->horizontalSyncWidth); + pVDIF->horizontalFrequency = roundedDiv(pVDIF->pixelClock, pVDIF->horizontalTotal); + pVDIF->horizontalLeftBorder = 0; + pVDIF->horizontalRightBorder = 0; + + pVDIF->verticalActive = + ((unsigned long)pDetailedTiming->vertActiveBlanking.vertActiveMSB << 8) + + (unsigned long)pDetailedTiming->vertActive; + pVDIF->verticalBlankStart = pVDIF->verticalActive; + pVDIF->verticalBlankTime = + ((unsigned long)pDetailedTiming->vertActiveBlanking.vertBlankingMSB << 8) + + (unsigned long)pDetailedTiming->vertBlanking; + pVDIF->verticalTotal = pVDIF->verticalActive + pVDIF->verticalBlankTime; + pVDIF->verticalFrontPorch = + ((unsigned long)pDetailedTiming->syncAuxInfo.vertSyncOffset << 8) + + (unsigned long)pDetailedTiming->verticalSyncInfo.syncOffset; + pVDIF->verticalSyncStart = pVDIF->verticalBlankStart + pVDIF->verticalFrontPorch; + pVDIF->verticalSyncHeight = + ((unsigned long)pDetailedTiming->syncAuxInfo.vertSyncWidth << 8) + + (unsigned long)pDetailedTiming->verticalSyncInfo.syncWidth; + pVDIF->verticalBackPorch = + pVDIF->verticalBlankTime - (pVDIF->verticalFrontPorch + pVDIF->verticalSyncHeight); + pVDIF->verticalFrequency = + roundedDiv(pVDIF->pixelClock, (pVDIF->horizontalTotal * pVDIF->verticalTotal)); + pVDIF->verticalTopBorder = 0; + pVDIF->verticalBottomBorder = 0; + + if (pDetailedTiming->flags.connectionType == 3) + { + pVDIF->verticalSyncPolarity = + (pDetailedTiming->flags.vertSyncFlag == 1) ? VDIF_SYNC_POSITIVE : VDIF_SYNC_NEGATIVE; + pVDIF->horizontalSyncPolarity = + (pDetailedTiming->flags.horzSyncFlag == 1) ? VDIF_SYNC_POSITIVE : VDIF_SYNC_NEGATIVE; + } + else + { + pVDIF->verticalSyncPolarity = VDIF_SYNC_NEGATIVE; + pVDIF->horizontalSyncPolarity = VDIF_SYNC_NEGATIVE; + } + + /* For debugging purpose. */ + printVdif(pVDIF); + + return 0; + } + } + } + + return (-1); +} + +/* + * edidGetMonitorSerialNumber + * This function gets the monitor serial number from the EDID structure. + * Only EDID version 1 and revision 1 or above supports this feature. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorSerialNumber - Pointer to a buffer to store the serial number + * retrieved from the EDID + * bufferSize - The size of the buffer to store the serial number. + * The maximum size required is 13 bytes. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetMonitorSerialNumber( + unsigned char *pEDIDBuffer, + char *pMonitorSerialNumber, + unsigned char bufferSize +) +{ + unsigned char version, revision, tableIndex, charIndex; + + /* If no pointer is given or the buffer size is set to 0, then return fail. */ + if ((pMonitorSerialNumber == (char *)0) || (bufferSize == 0)) + return (-1); + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, &revision); + + if ((version == 1) && (revision > 0)) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFF)) + { + bufferSize = (bufferSize > 13) ? 13 : bufferSize; + for (charIndex = 0; charIndex < 13; charIndex++) + { + if (pMonitorDescriptor->descriptor.serialNo[charIndex] == 0x0A) + { + pMonitorSerialNumber[charIndex] = '\0'; + break; + } + + pMonitorSerialNumber[charIndex] = pMonitorDescriptor->descriptor.serialNo[charIndex]; + } + + return 0; + } + } + } + + /* Serial Number is not found. */ + return (-1); +} + +/* + * edidGetDataString + * This function gets the data string from the EDID + * Only EDID version 1 and revision 1 or above supports this feature. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorSerialNumber - Pointer to a buffer to store the data string + * retrieved from the EDID + * bufferSize - The size of the buffer to store the data string + * The maximum size required is 13 bytes. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetDataString( + unsigned char *pEDIDBuffer, + char *pDataString, + unsigned char bufferSize +) +{ + unsigned char version, revision, tableIndex, charIndex; + + /* If no pointer is given or the buffer size is set to 0, then return fail. */ + if ((pDataString == (char *)0) || (bufferSize == 0)) + return (-1); + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, &revision); + + if ((version == 1) && (revision > 0)) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFE)) + { + bufferSize = (bufferSize > 13) ? 13 : bufferSize; + for (charIndex = 0; charIndex < 13; charIndex++) + { + if (pMonitorDescriptor->descriptor.dataString[charIndex] == 0x0A) + { + pDataString[charIndex] = '\0'; + break; + } + + pDataString[charIndex] = pMonitorDescriptor->descriptor.dataString[charIndex]; + } + + return 0; + } + } + } + + /* Data String is not found. */ + return (-1); +} + +/* + * edidGetMonitorRangeLimit + * This function gets the monitor range limits from the EDID structure. + * Only EDID version 1 revision 1 or above supports this feature. + * This is a required field in EDID Version 1.3 + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMinVerticalRate - Pointer to a variable to store the Minimum Vertical Rate (Hz) + * pMaxVerticalRate - Pointer to a variable to store the Maximum Vertical Rate (Hz) + * pMinHorzFreq - Pointer to a variable to store the Minimum Horz. Freq (kHz) + * pMaxHorzFreq - Pointer to a variable to store the Maximum Horz. Freq (kHz) + * pMaxPixelClock - Pointer to a variable to store the Maximum Pixel Clock (Hz) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetMonitorRangeLimit( + unsigned char *pEDIDBuffer, + unsigned char *pMinVerticalRate, + unsigned char *pMaxVerticalRate, + unsigned char *pMinHorzFreq, + unsigned char *pMaxHorzFreq, + unsigned long *pMaxPixelClock +) +{ + unsigned char version, revision, tableIndex; + + if (pEDIDBuffer == (unsigned char *)0) + return (-1); + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, &revision); + + if ((version == 1) && (revision > 0)) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFD) && (pMonitorDescriptor->flag3 == 0)) + { + if (pMinVerticalRate != (unsigned char *)0) + *pMinVerticalRate = pMonitorDescriptor->descriptor.monitorRange.minVertRate; + + if (pMaxVerticalRate != (unsigned char *)0) + *pMaxVerticalRate = pMonitorDescriptor->descriptor.monitorRange.maxVertRate; + + if (pMinHorzFreq != (unsigned char *)0) + *pMinHorzFreq = pMonitorDescriptor->descriptor.monitorRange.minHorzFrequency; + + if (pMaxHorzFreq != (unsigned char *)0) + *pMaxHorzFreq = pMonitorDescriptor->descriptor.monitorRange.maxHorzFrequency; + + if (pMaxPixelClock != (unsigned long *)0) + *pMaxPixelClock = (unsigned long) pMonitorDescriptor->descriptor.monitorRange.maxPixelClock * 10 * 1000000; + + return 0; + } + } + } + + /* Data String is not found. */ + return (-1); +} + +/* + * edidGetSecondaryTimingSupport + * This function gets the secondary GTF timing support. + * Only EDID version 1 and revision 1 or above supports this feature. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStartFrequency - Pointer to a variable to store the start frequency of + * the secondary GTF + * pOffset - Pointer to a variable to store the Offset (C) value of + * the secondary GTF + * pGradient - Pointer to a variable to store the Gradient (M) value of + * the secondary GTF + * pScalingFactor - Pointer to a variable to store the Scaling Factor (K) + * value of the secondary GTF + * pScalingFactorWeight - Pointer to a variable to store the Scaling Factore Weight (J) + * value of the secondary GTF + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetSecondaryTimingSupport( + unsigned char *pEDIDBuffer, + unsigned short *pStartFrequency, + unsigned char *pOffset, + unsigned short *pGradient, + unsigned char *pScalingFactor, + unsigned char *pScalingFactorWeight +) +{ + unsigned char version, revision, tableIndex; + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, &revision); + + if ((version == 1) && (revision > 0) && (pEDIDBuffer != (unsigned char *)0)) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFD) && + (pMonitorDescriptor->descriptor.monitorRange.secondaryTimingFlag == 0x02)) + { + if (pStartFrequency != (unsigned short *)0) + *pStartFrequency = (unsigned short) + pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.startFrequency * 2 * 1000; + + if (pOffset != (unsigned char *)0) + *pOffset = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.cParam/2; + + if (pGradient != (unsigned short *)0) + *pGradient = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.mParam; + + if (pScalingFactor != (unsigned char *)0) + *pScalingFactor = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.kParam; + + if (pScalingFactorWeight != (unsigned char *)0) + *pScalingFactorWeight = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.jParam / 2; + + return 0; + } + } + } + + /* Data String is not found. */ + return (-1); +} + +/* + * edidGetMonitorName + * This function gets the monitor name from the EDID structure. + * This is a required field in EDID Version 1.3 + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorName - Pointer to a buffer to store the monitor name + * retrieved from the EDID + * bufferSize - The size of the buffer to store the monitor name + * The maximum size required is 13 bytes. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetMonitorName( + unsigned char *pEDIDBuffer, + char *pMonitorName, + unsigned char bufferSize +) +{ + unsigned char version, revision, tableIndex, charIndex; + + /* If no pointer is given or the buffer size is set to 0, then return fail. */ + if ((pMonitorName == (char *)0) || (bufferSize == 0)) + return (-1); + + /* Get EDID Version and revision */ + version = edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFC) && (pMonitorDescriptor->flag3 == 0)) + { + bufferSize = (bufferSize > 13) ? 13 : bufferSize; + for (charIndex = 0; charIndex < 13; charIndex++) + { + if (pMonitorDescriptor->descriptor.monitorName[charIndex] == 0x0A) + { + pMonitorName[charIndex] = '\0'; + break; + } + + pMonitorName[charIndex] = pMonitorDescriptor->descriptor.monitorName[charIndex]; + } + + return 0; + } + } + } + + /* Data String is not found. */ + return (-1); +} + +/* + * edidGetPreferredTiming + * This function gets the preferred/native timing of the monitor + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pWidth - Pointer to an unsigned long buffer to store the width + * of the preferred (native) timing. + * pHeight - Pointer to an unsigned long buffer to store the height + * of the preferred (native) timing. + * pVerticalFrequency - Pointer to an unsigned long buffer to store the refresh + * rate of the preferred (native) timing. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetPreferredTiming( + unsigned char *pEDIDBuffer, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pVerticalFrequency +) +{ + unsigned char index = 0; + vdif_t vdifBuffer; + +/* Disable this checking since some old monitor does have the Detailed Timing although the preferred timing flag is 0. */ +#if 0 + /* Check if preferred timing is available */ + if (edidIsPreferredTimingAvailable(pEDIDBuffer) == 1) +#endif + { + /* The preferred (native) timing is available, so get the timing. It is located + at the first index of detailed timing. + */ + if (edidGetDetailedTiming(pEDIDBuffer, &index, &vdifBuffer) == 0) + { + if (pWidth != (unsigned long *)0) + *pWidth = vdifBuffer.horizontalActive; + + if (pHeight != (unsigned long *)0) + *pHeight = vdifBuffer.verticalActive; + + if (pVerticalFrequency != (unsigned long *)0) + *pVerticalFrequency = vdifBuffer.verticalFrequency; + + return 0; + } + } + + return (-1); +} diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_edid.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_edid.h new file mode 100644 index 000000000000..d542d836bce4 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_edid.h @@ -0,0 +1,762 @@ +/******************************************************************* +* +* Copyright (c) 2009 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* edid.h --- SMI DDK +* This file contains the EDID structure and function API to +* interpret the EDID +* +*******************************************************************/ +#ifndef _EDID_H_ +#define _EDID_H_ + +#include "ddk750_display.h" +#include "vdif.h" +#include "../hw_com.h" +/* Set the alignment to 1-bit aligned. Otherwise, it can't get the EDID correctly. */ +#pragma pack(1) + +#define READ_EDID_CONTINUOUS + + + + +#if 0 /* Temporary on hold. To be completed later. */ + +/* EDID Version 2.0. Not widely used. Usually defined for displays that follow + the original VESA Plug & Display (P&D) and Flat Panel Display Interface-2 (FPDI-2) + Standards + */ +typedef struct _edid_version_2_t +{ + /* + * EDID Structure Version/Revision (1 byte) + */ + unsigned char version:4; + unsigned char revision:4; + + /* + * Vendor / Product ID (7 bytes) + */ + unsigned short manufacturerID; /* ID Manufacturer Name */ + unsigned short productID; /* ID Product Code */ + unsigned char manufactureWeek; /* Week of Manufacture */ + unsigned short manufactureYear; /* Year of Manufacture */ + + /* + * Manufacturer/Product ID string (32 bytes) + */ + unsigned char productName; /* This string is compiresed of both manufacture name + and model name, which are separated using ASCII code 09h. + If the entire string is <32 bytes, then it is terminated + with ASCII code 0Ah and the field is padded with ASCII + code 20h + */ + + /* + * Serial number string (16 bytes) + */ + unsigned char serianNumber[16]; /* Serial number string. If <16 bytes then the string is + terminated with ASCII code 0Ah and the field padded + with ASCII code 20h + */ + + /* + * Unused/Reserved (8 bytes) + */ + unsigned char reserved[8]; + + /* + * Display Interface Parameters (15 bytes) + */ + unsigned char secondaryPhysicalIF:4; /* Look at defaultPhysicalIF description above. */ + unsigned char defaultPhysicalIF:4; /* Physical Connector Types. Consists of 2 fields. Bit 7-4 + indicates the connector for the default interface. If + a secondary interface is available, its connector is + indicated using bit 3-0. Both fields value description + is listed below: + 0 = None (Not valid for default connector) + 1 = BNC + 2 = 15 pin VGA + 3 = 13w3 + 4 = VESA EVC + 5 = VESA P&D-D + 6 = Micro-ribbon Connector (per the VESA P&D standard) + 7 = IEEE-1394 connector + 8 = VESA FPDI-2 + 9-E = Reserved + F = Non-standard connector + */ + unsigned char secondaryVideoIF:4; /* Look at the defaultVideoIF description above. */ + unsigned char defaultVideoIF:4; /* Video Interface Types. Consists of 2 fields. Bit 7-4 + defines the default video interface. Bit 3-0 defines + the secondary interface. Descriptions of the field is + listed below: + 0 = None (Not valid for default interface) + 1 = Analog + 2 = Analog w/ sampled pixel clock + 3 = TMDS (Transition Minimized Differential Signaling) + 4 = IEEE-1394-1995 + 5 = LVDS + 6 = Parallel + 7-F = Reserved + */ + unsigned char analogIFDataFormat[4]; /* Analog Interface Data Format */ + unsigned char digitalIFDataFormat[4]; /* Digital Interface Data Format */ + unsigned char secondaryColorEncodingIF:4; /* Secondary Color Encoding Interface */ + unsigned char defaultColorEncodingIF:4; /* Color Encoding default Interface */ + unsigned char primarySubChannel1:4; /* Supported bit-depth of sub-channel 1 ("Green") + of the Primary interface. */ + unsigned char primarySubChannel0:4; /* Supported bit-depth of sub-channel 0 ("Red") + of the Primary interface. */ + unsigned char primarySubChannel3:4; /* Supported bit-depth of sub-channel 3 of the + Primary interface. */ + unsigned char primarySubChannel2:4; /* Supported bit-depth of sub-channel 2 ("Blue") + of the Primary interface. */ + unsigned char secondarySubChannel1:4; /* Supported bit-depth of sub-channel 1 ("Green") + of the Secondary interface. */ + unsigned char secondarySubChannel0:4; /* Supported bit-depth of sub-channel 0 ("Red") + of the Secondary interface. */ + unsigned char secondarySubChannel3:4; /* Supported bit-depth of sub-channel 3 of the + Secondary interface. */ + unsigned char secondarySubChannel2:4; /* Supported bit-depth of sub-channel 2 ("Blue") + of the Secondary interface. */ + + /* + * Display Device Description (5 bytes) + */ + unsigned char displayType; /* Display technology type/subtype*/ + unsigned char displayCharacteristic; /* Major display characteristics. */ + unsigned char featureSupport[3]; /* Feature Support */ + + /* + * Display Response Time (2 bytes) + */ + unsigned char riseTimeResponse:4; /* Rise time response in seconds */ + unsigned char riseTimeExponent:4; /* Rise time exponent */ + unsigned char fallTimeResponse:4; /* Fall time response in seconds */ + unsigned char fallTimeExponent:4; /* Fall time exponent */ + + /* + * Color / Luminance Description (28 bytes) + */ + unsigned char whiteGamme; /* (Gamma x 100) - 100, [range 1.00 --> 3.55] */ + unsigned char redGamma; /* Color 0 ("red") Gamma (optional). Set to ffh if unused. */ + unsigned char greenGamma; /* Color 1 ("green") Gamma (optional). Set to ffh if unused. */ + unsigned char blueGamma; /* Color 2 ("blue") Gamma (optional). Set to ffh if unused. */ + unsigned short maxLuminance; /* Maximum LUminance (white) in units of cd/m^2*10 */ + unsigned char colorConfig; /* Standard RGB Model, adjustable Gamma and its offset */ + unsigned char offsetValue; /* Color Offset value */ + + /* Calorimetry and White Point(s) */ + unsigned char redGreenLowBits; /* Red / Green Low Bits */ +} +edid_version_2_t; + +#endif + +/* Restore alignment */ +#pragma pack() + +/************************************************************** + * Function Prototypes + **************************************************************/ + +/* + * edidGetVersion + * This function gets the EDID version + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRevision - Revision of the EDIE (if exist) + * + * Output: + * Revision number of the given EDID buffer. + */ +unsigned char edidGetVersion( + unsigned char *pEDIDBuffer, + unsigned char *pRevision +); + +/* + * edidGetProductInfo + * This function gets the vendor and product information. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor [in] + * pManufacturerName - Pointer to a 3 byte length variable to store the manufacturer name [out] + * pProductCode - Pointer to a variable to store the product code [out] + * pSerialNumber - Pointer to a variable to store the serial number [out] + * pWeekOfManufacture - Pointer to a variable to store the week of manufacture [out] + * pYearOfManufacture - Pointer to a variable to store the year of manufacture + * or model year (if WeekOfManufacture is 0xff) [out] + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetProductInfo( + unsigned char *pEDIDBuffer, + char *pManufacturerName, + unsigned short *pProductCode, + unsigned long *pSerialNumber, + unsigned char *pWeekOfManufacture, + unsigned short *pYearOfManufacture +); + +/* + * edidCheckMonitorInputSignal + * This function checks whether the monitor is expected analog/digital + * input signal. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Analog + * 1 - Digital + */ +unsigned char edidCheckMonitorInputSignal( + unsigned char *pEDIDBuffer +); + +/* + * edidGetAnalogSignalInfo + * This function gets the analog video input signal information + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRefWhiteAboveBlank - Pointer to a variable to store the reference white above blank + * value. The value is in milliVolt. + * pSyncLevelBelowBlank - Pointer to a variable to store the Sync tip level below blank + * The value is also in milliVolt + * pBlank2BlackSetup - Pointer to a variable to store the Blank to black setup or + * pedestal per appropriate Signal Level Standard flag. + * 1 means that the display expect the setup. + * pSeparateSyncSupport - Pointer to a variable to store the flag to indicate that the + * monitor supports separate sync. + * pCompositeSyncSupport - Pointer to a variable to store a flag to indicate that the + * monitor supports composite sync. + * pSyncOnGreenSupport - Pointer to a variable to store a flag to indicate that + * the monitor supports sync on green video. + * pVSyncSerrationRequired - Pointer to a variable to store a flag to indicate that serration + * of the VSync pulse is required when composite sync or + * sync-on-green video is used. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetAnalogSignalInfo( + unsigned char *pEDIDBuffer, + unsigned short *pRefWhiteAboveBlank, + unsigned short *pSyncLevelBelowBlank, + unsigned char *pBlank2BlackSetup, + unsigned char *pSeparateSyncSupport, + unsigned char *pCompositeSyncSupport, + unsigned char *pSyncOnGreenSupport, + unsigned char *pVSyncSerrationRequired +); + +/* + * edidGetDigitalSignalInfo + * This function gets the digital video input signal information + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pDFP1xSupport - Pointer to a variable to store the flag to indicate that + * the mointor interface is signal compatible with VESA + * DFP 1.x TMDS CRGB, 1 pixel/clock, up to 8 bits / color + * MSB aligned, DE active high + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetDigitalSignalInfo( + unsigned char *pEDIDBuffer, + unsigned char *pDFP1xSupport +); + +/* + * edidGetDisplaySize + * This function gets the display sizes in cm. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMaxHorzImageSize - Pointer to a variable to store the maximum horizontal + * image size to the nearest centimeter. A value of 0 + * indicates that the size is indeterminate size. + * pMaxVertImageSize - Pointer to a variable to store the maximum vertical + * image size to the nearest centimeter. A value of 0 + * indicates that the size is indeterminate size. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetDisplaySize( + unsigned char *pEDIDBuffer, + unsigned char *pMaxHorzImageSize, + unsigned char *pMaxVertImageSize +); + +/* + * edidGetPowerManagementSupport + * This function gets the monitor's power management support. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStandBy - Pointer to a variable to store the flag to indicate that + * standby power mode is supported. + * pSuspend - Pointer to a variable to store the flag to indicate that + * suspend power mode is supported. + * pLowPower - Pointer to a variable to store the flag to indicate that + * the display consumes low power when it receives a timing + * signal that is outside its declared active operating range. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetPowerManagementSupport( + unsigned char *pEDIDBuffer, + unsigned char *pStandBy, + unsigned char *pSuspend, + unsigned char *pLowPower +); + +/* + * edidGetDisplayType + * This function gets the display type. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Monochrome / grayscale display + * 1 - RGB Color Display + * 2 - Non-RGB multicolor display, e.g. R/G/Y + * 3 - Undefined + */ +unsigned char edidGetDisplayType( + unsigned char *pEDIDBuffer +); + +/* + * edidChecksRGBUsage + * This function checks if the display is using the sRGB standard default + * color space as its primary color space. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Does not use sRGB as its primary color space + * 1 - Use sRGB as its primary color space + */ +unsigned char edidChecksRGBUsage( + unsigned char *pEDIDBuffer +); + +/* + * edidIsPreferredTimingAvailable + * This function checks whether the preffered timing mode is available. + * Use of preferred timing mode is required by EDID structure version 1 + * Revision 3 and higher. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Preferred Timing is not available + * 1 - Preferred Timing is available + */ +unsigned char edidIsPreferredTimingAvailable( + unsigned char *pEDIDBuffer +); + +/* + * edidIsDefaultGTFSupported + * This function checks whether the display supports timings based on the + * GTF standard using default GTF parameter values. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Default GTF is not supported + * 1 - Default GTF is supported + */ +unsigned char edidIsDefaultGTFSupported( + unsigned char *pEDIDBuffer +); + +/* + * edidGetColorCharacteristic + * This function gets the chromaticity and white point values expressed as + * an integer value which represents the actual value times 1000. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRedX - Pointer to a variable to store the Red X values + * pRedY - Pointer to a variable to store the Red Y values + * pGreenX - Pointer to a variable to store the Green X values + * pGreenY - Pointer to a variable to store the Green Y values + * pBlueX - Pointer to a variable to store the Blue X values + * pBlueY - Pointer to a variable to store the Blue Y values + * + * Note: + * To get the White color characteristic, use the edidGetWhitePoint + */ +void edidGetColorCharacteristic( + unsigned char *pEDIDBuffer, + unsigned short *pRedX, + unsigned short *pRedY, + unsigned short *pGreenX, + unsigned short *pGreenY, + unsigned short *pBlueX, + unsigned short *pBlueY +); + +/* + * edidGetWhitePoint + * This function gets the white point. + * To get the default white point, set the index to 0. For multiple white point, + * call this function multiple times to check if more than 1 white point is supported. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pWhitePointIndex - Pointer to a variable that contains the white point index + * to be retrieved. + * pWhiteX - Pointer to a variable to store the White X value + * pWhiteY - Pointer to a variable to store the White Y value + * pWhiteGamma - Pointer to a variable to store the White Gamma value + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetWhitePoint( + unsigned char *pEDIDBuffer, + unsigned char *pWhitePointIndex, + unsigned short *pWhiteX, + unsigned short *pWhiteY, + unsigned short *pWhiteGamma +); + +/* + * edidGetExtension + * This function gets the number of (optional) EDID extension blocks to follow + * the given EDID buffer. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * Total number of EDID Extension to follow the given EDID buffer. + */ +unsigned char edidGetExtension( + unsigned char *pEDIDBuffer +); + +/* + * edidReadMonitor + * This function reads the EDID structure from the attached monitor + * + * Input: + * displayPath - Display device which EDID to be read from. + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidReadMonitor( + disp_path_t displayPath, + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo +); + +/* + * edidReadMonitor + * This function reads the EDID structure from the attached monitor + * + * Input: + * displayPath - Display device which EDID to be read from. + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * sclGpio - GPIO pin used as the I2C Clock (SCL) + * sdaGpio - GPIO pin used as the I2C Data (SDA) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk750_edidReadMonitorEx( + disp_path_t displayPath, + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char sclGpio, + unsigned char sdaGpio +); + +long ddk750_edidReadMonitorEx_HW( + disp_path_t displayPath, + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo +); + +/* + * edidGetHeader + * This function gets the EDID Header + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 get header success; -1 fail. + */ +unsigned char ddk750_edidGetHeader( + unsigned char *pEDIDBuffer +); + +long ddk750_edidHeaderReadMonitorExHwI2C(void); + + +/* + * edidGetEstablishedTiming + * This function gets the established timing list from the given EDID buffer, + * table, and timing index. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor (In) + * pEstTableIndex - Pointer to the Established Timing Table index (In/Out) + * pIndex - Pointer to the Establihsed Timing Index (In/Out) + * pWidth - Pointer to a variable that to store the horizontal active / width + * value of the retrieved timing (Out) + * pHeight - Pointer to a variable to store the vertical active / height + * value of the retrieved timing (Out) + * pRefreshRate - Pointer to a variable to store the vertical frequency value + * of the retrieved timing (out) + * pSource - Pointer to a variable to store the standard timing source: + * 0 - VESA + * 1 - IBM + * 2 - Apple + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetEstablishedTiming( + unsigned char *pEDIDBuffer, + /*unsigned char *pEstTableIndex,*/ + unsigned char *pIndex, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pRefreshRate, + unsigned char *pSource +); + +/* + * edidGetStandardTiming + * This function gets the standard timing from the given EDID buffer and + * calculates the width, height, and vertical frequency from that timing. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStdTimingIndex - Pointer to a standard timing index to be retrieved + * pWidth - Pointer to a variable that to store the horizontal active / width + * value of the retrieved timing (Out) + * pHeight - Pointer to a variable to store the vertical active / height + * value of the retrieved timing (Out) + * pRefreshRate - Pointer to a variable to store the vertical frequency value + * of the retrieved timing (out) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetStandardTiming( + unsigned char *pEDIDBuffer, + unsigned char *pStdTimingIndex, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pRefreshRate +); + +/* + * edidGetDetailedTiming + * This function gets the detailed timing from the given EDID buffer. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pDetailedTimingIndex - Pointer to a detailed timing index to be retrieved + * pModeParameter - Pointer to a mode_parameter_t structure that will be + * filled with the detailed timing. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetDetailedTiming( + unsigned char *pEDIDBuffer, + unsigned char *pDetailedTimingIndex, + vdif_t *pVDIF +); + +/* + * edidGetMonitorSerialNumber + * This function gets the monitor serial number from the EDID structure. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorSerialNumber - Pointer to a buffer to store the serial number + * retrieved from the EDID + * bufferSize - The size of the buffer to store the serial number. + * The maximum size required is 13 bytes. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetMonitorSerialNumber( + unsigned char *pEDIDBuffer, + char *pMonitorSerialNumber, + unsigned char bufferSize +); + +/* + * edidGetDataString + * This function gets the data string from the EDID structure. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorSerialNumber - Pointer to a buffer to store the data string + * retrieved from the EDID + * bufferSize - The size of the buffer to store the data string + * The maximum size required is 13 bytes. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetDataString( + unsigned char *pEDIDBuffer, + char *pDataString, + unsigned char bufferSize +); + +/* + * edidGetMonitorRangeLimit + * This function gets the monitor range limits from the EDID structure. + * Only EDID version 1 and revision 1 or above supports this feature. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMinVerticalRate - Pointer to a variable to store the Minimum Vertical Rate (Hz) + * pMaxVerticalRate - Pointer to a variable to store the Maximum Vertical Rate (Hz) + * pMinHorzFreq - Pointer to a variable to store the Minimum Horz. Freq (kHz) + * pMaxHorzFreq - Pointer to a variable to store the Maximum Horz. Freq (kHz) + * pMaxPixelClock - Pointer to a variable to store the Maximum Pixel Clock (Hz) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetMonitorRangeLimit( + unsigned char *pEDIDBuffer, + unsigned char *pMinVerticalRate, + unsigned char *pMaxVerticalRate, + unsigned char *pMinHorzFreq, + unsigned char *pMaxHorzFreq, + unsigned long *pMaxPixelClock +); + +/* + * edidGetSecondaryTimingSupport + * This function gets the secondary GTF timing support. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStartFrequency - Pointer to a variable to store the start frequency of + * the secondary GTF + * pOffset - Pointer to a variable to store the Offset (C) value of + * the secondary GTF + * pGradient - Pointer to a variable to store the Gradient (M) value of + * the secondary GTF + * pScalingFactor - Pointer to a variable to store the Scaling Factor (K) + * value of the secondary GTF + * pScalingFactorWeight - Pointer to a variable to store the Scaling Factore Weight (J) + * value of the secondary GTF + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetSecondaryTimingSupport( + unsigned char *pEDIDBuffer, + unsigned short *pStartFrequency, + unsigned char *pOffset, + unsigned short *pGradient, + unsigned char *pScalingFactor, + unsigned char *pScalingFactorWeight +); + +/* + * edidGetMonitorName + * This function gets the monitor name from the EDID structure. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorName - Pointer to a buffer to store the monitor name + * retrieved from the EDID + * bufferSize - The size of the buffer to store the monitor name + * The maximum size required is 13 bytes. + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetMonitorName( + unsigned char *pEDIDBuffer, + char *pMonitorName, + unsigned char bufferSize +); + +/* + * edidGetPreferredTiming + * This function gets the preferred/native timing of the monitor + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pWidth - Pointer to an unsigned long buffer to store the width + * of the preferred (native) timing. + * pHeight - Pointer to an unsigned long buffer to store the height + * of the preferred (native) timing. + * pVerticalFrequency - Pointer to an unsigned long buffer to store the refresh + * rate of the preferred (native) timing. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetPreferredTiming( + unsigned char *pEDIDBuffer, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pVerticalFrequency +); + +#endif /* _EDID_H_ */ + + + diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_hardware.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_hardware.h new file mode 100644 index 000000000000..86b84b4497d9 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_hardware.h @@ -0,0 +1,191 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* HARDWARE.h --- Voyager GX SDK +* This file contains the definitions for the physical hardware. +* +*******************************************************************/ +#ifndef _HARDWARE_H_ +#define _HARDWARE_H_ + +/* Use IO Port to access the MMIO + NOTE: + The easiest way to run the application in MS-DOS when using the SM750 as + secondary adapter is using the following steps: + 1. Disable the VGA enable bit in the primary card's PCI to PCI bridge. + This bit is location at offset 0x3E bit 3. --> This can be implemented + in the application or run the PCI Tools to modify the PCI to PCI bridge manually. + 2. Enable the VGA enable bit in the secondary (SM750) card's PCI to PCI bridge. + --> This can be implemented + in the application or run the PCI Tools to modify the PCI to PCI bridge manually. + 3. Enable "USE_IO_PORT" definition and compile it. --> It will automatically + enable the IO Port Access in the PCI Configuration Register offset 4, bit 1. + 4. Configure the DOS system to use Serial port. Hints: Use "mode" command + and "ctty com1". It requires NULL model serial cable and another system to + operate the DOS from the other serial port. --> This step can be done in + any sequence prior running the application. + 5. Run the application from the serial port. + */ +//#define USE_IO_PORT + +/* Use 0xA0000 as the frame buffer access. */ +//#define USE_A0000 + +/* Silicon Motion PCI vendor ID */ +#define SMI_PCI_VENDOR_ID 0x126F +#define HIS_PCI_VENDOR_ID 0x19E5 + +/* Maximum number of devices with the same ID supported by this library. */ +#define MAX_SMI_DEVICE 4 + +/* List of Silicon Motion PCI Device ID that is supported by this library. */ +#define SMI_DEVICE_ID_SM750 0x0750 +#define SMI_DEVICE_ID_SM718 0x0718 +#define HIS_DEVICE_ID_SM750 0x1711 + +/* Size of the SM750 MMIO and memory */ +#define SM750_PCI_ALLOC_MMIO_SIZE (2*1024*1024) +#define SM750_PCI_ALLOC_MEMORY_SIZE (64*1024*1024) + +/* Register types */ +typedef enum _reg_type_t +{ + MISCELLANEOUS_REGISTER, + SEQUENCER_REGISTER, + CRT_REGISTER, + GRAPHICS_REGISTER, + OTHER_REGISTER +} +reg_type_t; + +#ifdef USE_A0000 +/* + * Set the bank size when using A0000h memory addressing . + */ +void setBankSize( + unsigned long bankSize +); +#endif + +/* + * Get the physical address of an offset location in frame buffer. + * In DOS, the physical and the logical address most likely are the same. + * Return: A valid address if success. + * NULL address if fail. + */ +void *getPhysicalAddress(unsigned long offset /* Offset from base of physical frame buffer */); + +/* + * Get the logical address of an offset location in frame buffer. + * Return: A valid address if success. + * NULL address if fail. + */ +void *getAddress(unsigned long offset /*Offset from base of frame buffer*/); + +/* + * Get the IRQ number of the current device. + */ +unsigned char getIRQ(void); + +/* + * This function detects what SMI chips is in the system. + * + * Return: A non-zero device ID if SMI chip is detected. + * Zero means NO SMI chip is detected. + */ +unsigned short detectDevices(void); + +/* + * Function to return vendor ID, chip ID and revision of the current chip, if any. + */ +unsigned short getVendorId(void); +unsigned short getDeviceId(void); +unsigned char getDeviceRev(void); + +/* + * How many devices of the same ID are there. + */ +unsigned short getNumOfDevices(void); + +/* + * This function sets up the current accessible device, if more + * than one of the same ID exist in the system. + * + * Note: + * Single device application don't need to call this function. + * This function is to control multiple devices. + */ +long setCurrentDevice(unsigned short dev); +//unsigned short getCurrentDevice(void); +#define getCurrentDevice(...) SM750 + +/* Video Memory read/write functions */ +unsigned char peekByte(unsigned long offset); +unsigned short peekWord(unsigned long offset); +unsigned long peekDWord(unsigned long offset); +void poke_4_Byte(unsigned long offset, unsigned char *buf); +void pokeByte(unsigned long offset, unsigned char value); +void pokeWord(unsigned long offset, unsigned short value); +void pokeDWord(unsigned long offset, unsigned long value); +#if 0 //by ilena +/* MMIO read/write functions */ +unsigned char peekRegisterByte(unsigned long offset); +unsigned short peekRegisterWord(unsigned long offset); +unsigned long peekRegisterDWord(unsigned long offset); +void pokeRegisterByte(unsigned long offset, unsigned char value); +void pokeRegisterWord(unsigned long offset, unsigned short value); +void pokeRegisterDWord(unsigned long offset, unsigned long value); +#endif + +#if 0 /* For Testing Purpose */ +/* + * Read SM718 PCI byte value + */ +unsigned char readDevicePCIByte( + unsigned short offset +); + +/* + * Read SM718 PCI word value + */ +unsigned short readDevicePCIWord( + unsigned short offset +); + +/* + * Read SM718 PCI dword value + */ +unsigned long readDevicePCIDWord( + unsigned short offset +); + +/* + * Write SM718 PCI byte value + */ +long writeDevicePCIByte( + unsigned short offset, + unsigned char value +); + +/* + * Write SM718 PCI word value + */ +long writeDevicePCIWord( + unsigned short offset, + unsigned short value +); + +/* + * Write SM718 PCI dword value + */ +long writeDevicePCIDWord( + unsigned short offset, + unsigned long value +); +#endif + +#endif /* _HARDWARE_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_help.c b/drivers/gpu/drm/smidrm/ddk750/ddk750_help.c new file mode 100644 index 000000000000..5e36214b95e4 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_help.c @@ -0,0 +1,18 @@ +#include "ddk750_help.h" + +volatile unsigned char __iomem * mmio750 = NULL; +char revId750 = 0; +unsigned short devId750 = 0; + + + +/* after driver mapped io registers, use this function first */ +void ddk750_set_mmio(volatile unsigned char * addr,unsigned short devId,char revId) +{ + mmio750 = addr; + devId750 = devId; + revId750 = revId; + if(revId == 0xfe) + printk("found sm750le\n"); +} + diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_help.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_help.h new file mode 100644 index 000000000000..4cf2b6e20d4e --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_help.h @@ -0,0 +1,33 @@ +#ifndef DDK750_HELP_H__ +#define DDK750_HELP_H__ +#include "ddk750_chip.h" +#ifndef USE_INTERNAL_REGISTER_ACCESS + +#include +#include +#include +#include "ddk750_mode.h" + + +#define PEEK32(addr) readl((addr)+mmio750) +#define POKE32(addr,data) writel((data),(addr)+mmio750) +#define peekRegisterDWord PEEK32 +#define pokeRegisterDWord POKE32 + + +#define peekRegisterByte(addr) readb((addr)+mmio750) +#define pokeRegisterByte(addr,data) writeb((data),(addr)+mmio750) + + + +extern volatile unsigned char __iomem * mmio750; +extern char revId750; +extern unsigned short devId750; +void ddk750_set_mmio(volatile unsigned char *,unsigned short,char); + +#else +/* implement if you want use it*/ +#endif + +#endif + diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_helper.c b/drivers/gpu/drm/smidrm/ddk750/ddk750_helper.c new file mode 100644 index 000000000000..1e200984ffcd --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_helper.c @@ -0,0 +1,35 @@ +#include "ddk750_helper.h" + +/* Perform a rounded division. + * For example, if the result is 4.5, this function returns 5. + * If the result is 4.4, this function returns 4. + */ +unsigned long roundedDiv(unsigned long num, unsigned long denom) +{ + /* n / d + 1 / 2 = (2n + d) / 2d */ + return (2 * num + denom) / (2 * denom); +} + + +/* Absolute differece between two numbers */ +unsigned long absDiff(unsigned long a, unsigned long b) +{ + if ( a >= b ) + return(a - b); + else + return(b - a); +} + +/* This function calculates 2 to the power of x + Input is the power number. + */ +unsigned long twoToPowerOfx(unsigned long x) +{ + unsigned long i; + unsigned long result = 1; + + for (i=1; i<=x; i++) + result *= 2; + + return result; +} diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_helper.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_helper.h new file mode 100644 index 000000000000..e1f550e91a1c --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_helper.h @@ -0,0 +1,18 @@ +#ifndef _HELPER_H_ +#define _HELPER_H_ + +/* Perform a rounded division. + * For example, if the result is 4.5, this function returns 5. + * If the result is 4.4, this function returns 4. + */ +unsigned long roundedDiv(unsigned long num, unsigned long denom); + +/* Absolute differece between two numbers */ +unsigned long absDiff(unsigned long a, unsigned long b); + +/* This function calculates 2 to the power of x + Input is the power number. + */ +unsigned long twoToPowerOfx(unsigned long x); + +#endif /* _HELPER_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_hwi2c.c b/drivers/gpu/drm/smidrm/ddk750/ddk750_hwi2c.c new file mode 100644 index 000000000000..bd441650a9ef --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_hwi2c.c @@ -0,0 +1,489 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* hwi2c.c --- SMI DDK +* This file contains the source code for hardware i2c. +* +*******************************************************************/ + +#include "ddk750_defs.h" +#include "ddk750_hardware.h" +#include "ddk750_power.h" +#include "ddk750_help.h" +#include "ddk750_hwi2c.h" + +#define MAX_HWI2C_FIFO 16 + + +static unsigned long hwI2CWriteData( + unsigned char deviceAddress, + unsigned long length, + unsigned char *pBuffer +); + +static unsigned long hwI2CReadData( + unsigned char deviceAddress, + unsigned long length, + unsigned char *pBuffer +); + +static int ddk750_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], + int num) +{ + unsigned long ret; + int i, count = 0; + + for (i = 0; i < (num - 1); i++) + if (msgs[i].flags & I2C_M_RD) + { + pr_err("only one read message supported, has to be last\n"); + return -EOPNOTSUPP; + } + + while (msgs->len && (count < num)) + { + msgs->addr = msgs->addr << 1; + if (!(msgs->flags & I2C_M_RD)) + { + ret = hwI2CWriteData( + msgs->addr, + msgs->len, + msgs->buf); + if (ret < msgs->len) + { + pr_err("ddk50 i2c xfer tx failed %ld.\n", ret); + break; + } + } + else + { + ret = hwI2CReadData( + msgs->addr, + msgs->len, + msgs->buf); + if (ret < msgs->len) + { + pr_err("ddk750 i2c xfer rx failed %ld.\n", ret); + break; + } + } + + msgs++; + count++; + } + + if (count < num) + { + pr_err("ddk750 i2c xfer failed %d(%d).\n", count, num); + return -EIO; + } + + return num; +} + +static u32 ddk750_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + + +static const struct i2c_algorithm ddk750_i2c_algo = { + .master_xfer = ddk750_i2c_xfer, + .functionality = ddk750_i2c_func +}; + + +/* + * This function initializes the hardware i2c + * + * Parameters: + * busSpeedMode - I2C Bus Speed Mode + * 0 = Standard Mode (100kbps) + * 1 = Fast Mode (400kbps) + * + * Return Value: + * 0 - Success + * -1 - Fail to initialize i2c + */ +long ddk750_hwI2CInit( + unsigned char busSpeedMode +) +{ + unsigned long value; + + /* Enable GPIO 30 & 31 as IIC clock & data */ + value = peekRegisterDWord(GPIO_MUX); + value = FIELD_SET(value, GPIO_MUX, 30, I2C) | + FIELD_SET(0, GPIO_MUX, 31, I2C); + pokeRegisterDWord(GPIO_MUX, value); + + /* Enable Hardware I2C power. + TODO: Check if we need to enable GPIO power? + */ + enableI2C(1); + + /* Enable the I2C Controller and set the bus speed mode */ + value = peekRegisterByte(I2C_CTRL); + if (busSpeedMode == 0) + value = FIELD_SET(value, I2C_CTRL, MODE, STANDARD); + else + value = FIELD_SET(value, I2C_CTRL, MODE, FAST); + value = FIELD_SET(value, I2C_CTRL, EN, ENABLE); + pokeRegisterByte(I2C_CTRL, value); + + return 0; +} + +long ddk750_AdaptHWI2CInit(struct smi_connector *connector) +{ + int ret; + + ddk750_hwI2CInit(1); + + connector->adapter.owner = THIS_MODULE; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 8, 0) + connector->adapter.class = I2C_CLASS_DDC; +#endif + snprintf(connector->adapter.name, I2C_NAME_SIZE, "SMI HW I2C Bus"); + connector->adapter.dev.parent = connector->base.dev->dev; + i2c_set_adapdata(&connector->adapter, connector); + connector->adapter.algo = &ddk750_i2c_algo; + ret = i2c_add_adapter(&connector->adapter); + if (ret) + { + pr_err("HW i2c add adapter failed. %d\n", ret); + return -1; + } + + return 0; +} + + +/* + * This function closes the hardware i2c. + */ +void ddk750_hwI2CClose() +{ + unsigned long value; + + /* Disable I2C controller */ + value = peekRegisterByte(I2C_CTRL); + value = FIELD_SET(value, I2C_CTRL, EN, DISABLE); + pokeRegisterByte(I2C_CTRL, value); + + /* Disable I2C Power */ + enableI2C(0); + + /* Set GPIO 30 & 31 back as GPIO pins */ + value = peekRegisterDWord(GPIO_MUX); + value = FIELD_SET(value, GPIO_MUX, 30, GPIO); + value = FIELD_SET(value, GPIO_MUX, 31, GPIO); + pokeRegisterDWord(GPIO_MUX, value); +} + +long ddk750_AdaptHWI2CCleanBus(struct smi_connector *connector) +{ + ddk750_hwI2CClose(); + return 0; +} + +/* + * This function waits until the transfer is completed within the timeout value. + * + * Return Value: + * 0 - Transfer is completed + * -1 - Tranfer is not successful (timeout) + */ +#define HWI2C_WAIT_TIMEOUT 0xF0000 +static long hwI2CWaitTXDone(void) +{ + unsigned long timeout; + + /* Wait until the transfer is completed. */ + timeout = HWI2C_WAIT_TIMEOUT; + while ((FIELD_GET(peekRegisterByte(I2C_STATUS), I2C_STATUS, TX) != I2C_STATUS_TX_COMPLETED) && + (timeout != 0)) + timeout--; + + if (timeout == 0) + return (-1); + + return 0; +} + +/* + * This function writes data to the i2c slave device registers. + * + * Parameters: + * deviceAddress - i2c Slave device address + * length - Total number of bytes to be written to the device + * pBuffer - The buffer that contains the data to be written to the + * i2c device. + * + * Return Value: + * Total number of bytes those are actually written. + */ +static unsigned long hwI2CWriteData( + unsigned char deviceAddress, + unsigned long length, + unsigned char *pBuffer +) +{ + unsigned char count, i; + unsigned long totalBytes = 0; + + /* Set the Device Address */ + pokeRegisterByte(I2C_SLAVE_ADDRESS, deviceAddress & ~0x01); + + /* Write data. + * Note: + * Only 16 byte can be accessed per i2c start instruction. + */ + do + { + /* Reset I2C by writing 0 to I2C_RESET register to clear the previous status. */ + pokeRegisterByte(I2C_RESET, 0); + + /* Set the number of bytes to be written */ + if (length < MAX_HWI2C_FIFO) + count = length - 1; + else + count = MAX_HWI2C_FIFO - 1; + pokeRegisterByte(I2C_BYTE_COUNT, count); + + /* Move the data to the I2C data register */ + for (i = 0; i <= count; i++) + pokeRegisterByte(I2C_DATA0 + i, *pBuffer++); + + /* Start the I2C */ + pokeRegisterByte(I2C_CTRL, FIELD_SET(peekRegisterByte(I2C_CTRL), I2C_CTRL, CTRL, START)); + + /* Wait until the transfer is completed. */ + if (hwI2CWaitTXDone() != 0) + break; + + /* Substract length */ + length -= (count + 1); + + /* Total byte written */ + totalBytes += (count + 1); + + } while (length > 0); + + return totalBytes; +} + +/* + * This function reads data from the slave device and stores them + * in the given buffer + * + * Parameters: + * deviceAddress - i2c Slave device address + * length - Total number of bytes to be read + * pBuffer - Pointer to a buffer to be filled with the data read + * from the slave device. It has to be the same size as the + * length to make sure that it can keep all the data read. + * + * Return Value: + * Total number of actual bytes read from the slave device + */ +static unsigned long hwI2CReadData( + unsigned char deviceAddress, + unsigned long length, + unsigned char *pBuffer +) +{ + unsigned char count, i; + unsigned long totalBytes = 0; + + /* Set the Device Address */ + pokeRegisterByte(I2C_SLAVE_ADDRESS, deviceAddress | 0x01); + + /* Read data and save them to the buffer. + * Note: + * Only 16 byte can be accessed per i2c start instruction. + */ + do + { + /* Reset I2C by writing 0 to I2C_RESET register to clear all the status. */ + pokeRegisterByte(I2C_RESET, 0); + + /* Set the number of bytes to be read */ + if (length <= MAX_HWI2C_FIFO) + count = length - 1; + else + count = MAX_HWI2C_FIFO - 1; + pokeRegisterByte(I2C_BYTE_COUNT, count); + + /* Start the I2C */ + pokeRegisterByte(I2C_CTRL, FIELD_SET(peekRegisterByte(I2C_CTRL), I2C_CTRL, CTRL, START)); + + /* Wait until transaction done. */ + if (hwI2CWaitTXDone() != 0) + break; + + /* Save the data to the given buffer */ + for (i = 0; i <= count; i++) { + *pBuffer++ = peekRegisterByte(I2C_DATA0 + i); + } + + /* Substract length by 16 */ + length -= (count + 1); + + /* Number of bytes read. */ + totalBytes += (count + 1); + + } while (length > 0); + + return totalBytes; +} + +/* + * This function reads the slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be read from + * registerIndex - Slave device's register to be read + * + * Return Value: + * Register value + */ +unsigned char ddk750_hwI2CReadReg( + unsigned char deviceAddress, + unsigned char registerIndex +) +{ + unsigned char value = (0xFF); + + if (hwI2CWriteData(deviceAddress, 1, ®isterIndex) == 1) + hwI2CReadData(deviceAddress, 1, &value); + + return value; +} + +/* + * This function writes a value to the slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be written + * registerIndex - Slave device's register to be written + * data - Data to be written to the register + * + * Result: + * 0 - Success + * -1 - Fail + */ +long ddk750_hwI2CWriteReg( + unsigned char deviceAddress, + unsigned char registerIndex, + unsigned char data +) +{ + unsigned char value[2]; + + value[0] = registerIndex; + value[1] = data; + if (hwI2CWriteData(deviceAddress, 2, value) == 2) + return 0; + + return (-1); +} + +#if 0 +/* + * This function read the i2c device register value + * + * Input: deviceAddress - I2C Device Address + * registerIndex - Register index to be read + * + * Output: + * The value of the register being read. + */ +unsigned long hwI2CReadRegMultiple( + unsigned char deviceAddress, + unsigned char registerIndex, + unsigned long length, + unsigned char *pBuffer +) +{ + unsigned long totalData = 0; + + /* The length is limited to 256 since register index is limited to unsigned char. */ + if ((registerIndex + length) > 256) + length = 256 - registerIndex; + + /* Read from the slave device */ + if (hwI2CWriteData(deviceAddress, 1, ®isterIndex) == 1) + totalData = hwI2CReadData(deviceAddress, length, pBuffer); + + /* Return the total number of read data */ + return totalData; +} + +/* + * This function writes a value to the i2c device register. + * + * Input: deviceAddress - I2C Device Address + * registerIndex - Register index to be read + * + * Output: + * The value of the register being read. + */ +long hwI2CWriteRegMultiple( + unsigned char deviceAddress, + unsigned char registerIndex, + unsigned long length, + unsigned char *pBuffer +) +{ + unsigned char value[MAX_HWI2C_FIFO], index, count, start = 1; + unsigned long totalData = 0; + + /* The length is limited to 256 since register index is limited to unsigned char. */ + if ((registerIndex + length) > 256) + length = 256 - registerIndex; + +#if 1 + /* Temporary use this one */ + for (index = 0; index < (unsigned char)length; index++) + { + if (hwI2CWriteReg(deviceAddress, registerIndex + index, *pBuffer++) != 0) + return (-1); + } +#else + /* Does not work here. Need to find out how to write multiple data at once. */ + while (length > 0) + { + if (length < MAX_HWI2C_FIFO) + count = length + 1; /* Add one for the register Index. */ + else + count = MAX_HWI2C_FIFO; + + /* Write the starting register index */ + value[0] = registerIndex; + + /* Write the data */ + for (index = 1; index < count; index++) + value[index] = *pBuffer++; + + if (hwI2CWriteData(deviceAddress, count, &value[0]) != count) + return (-1); + + /* Update the length */ + length -= (count - 1); + + /* Update the registerIndex */ + registerIndex += (count - 1); + } +#endif + + return 0; +} +#endif + diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_hwi2c.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_hwi2c.h new file mode 100644 index 000000000000..578e2169e58b --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_hwi2c.h @@ -0,0 +1,76 @@ +/******************************************************************* +* +* Copyright (c) 2008 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* hwi2c.H --- SMI DDK +* This file contains the definitions for Hardware I2C. +* +*******************************************************************/ +#ifndef _HWI2C_H_ +#define _HWI2C_H_ + +#include "../smi_drv.h" + + +/* + * This function initializes the hardware i2c + * + * Parameters: + * busSpeedMode - I2C Bus Speed Mode + * 0 = Standard Mode (100kbps) + * 1 = Fast Mode (400kbps) + * + * Return Value: + * 0 - Success + * -1 - Fail to initialize i2c + */ +long ddk750_hwI2CInit( + unsigned char busSpeedMode +); + +/* + * This function close the hardware i2c + */ +void ddk750_hwI2CClose(void); + +/* + * This function read the i2c device register value + * + * Input: deviceAddress - I2C Device Address + * registerIndex - Register index to be read + * + * Output: + * The value of the register being read. + */ +unsigned char ddk750_hwI2CReadReg( + unsigned char deviceAddress, + unsigned char registerIndex +); + +/* + * This function writes a value to the i2c device register. + * + * Input: deviceAddress - I2C Device Address + * registerIndex - Register index to be written to + * data - Data to be written to + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk750_hwI2CWriteReg( + unsigned char deviceAddress, + unsigned char registerIndex, + unsigned char data +); + + +long ddk750_AdaptHWI2CInit(struct smi_connector *connector); +long ddk750_AdaptHWI2CCleanBus(struct smi_connector *connector); + + + +#endif /* _HWI2C_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_mode.c b/drivers/gpu/drm/smidrm/ddk750/ddk750_mode.c new file mode 100644 index 000000000000..99ed267d3f19 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_mode.c @@ -0,0 +1,1189 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* MODE.C --- SMI DDK +* This file contains the source code for the mode table. +* +*******************************************************************/ +//#include +#include "ddk750_defs.h" +#include "ddk750_chip.h" +#include "ddk750_clock.h" +#include "ddk750_hardware.h" +#include "ddk750_helper.h" +#include "ddk750_power.h" +#include "ddk750_mode.h" +#include "ddk750_help.h" + +//#include "ddk750_os.h" + +//#include "ddkdebug.h" + +#define SCALE_CONSTANT (1 << 12) + +/* Maximum panel size scaling */ +#define MAX_PANEL_SIZE_WIDTH 1920 +#define MAX_PANEL_SIZE_HEIGHT 1440 + +/* The valid signature of the user data pointer for the setmode function. + The following definition is ASCII representation of the word 'USER' + */ +#define MODE_USER_DATA_SIGNATURE 0x55534552 + +/* + * Default Timing parameter for some popular modes. + * Note that the most timings in this table is made according to standard VESA + * parameters for the popular modes. + */ +static mode_parameter_t gDefaultModeParamTable[] = + { + /*800x480*/ + //{0, 800, 0, 0, NEG, 0, 480, 0, 0, POS, 0, 0, 0, NEG}, + /* 320 x 240 [4:3] */ + {352, 320, 335, 8, NEG, 265, 240, 254, 2, NEG, 5600000, 15909, 60, NEG}, + + /* 400 x 300 [4:3] -- Not a popular mode */ + {528, 400, 420, 64, NEG, 314, 300, 301, 2, NEG, 9960000, 18864, 60, NEG}, + + /* 480 x 272 -- Not a popular mode --> only used for panel testing */ + /* { 525, 480, 482, 41, NEG, 286, 272, 274, 10, NEG, 9009000, 17160, 60, NEG}, */ + + /* 640 x 480 [4:3] */ + /* The first 2 commented lines below are taken from SM502, the rest timing are + taken from the VESA Monitor Timing Standard */ + /* { 840, 640, 680, 64, NEG, 500, 480, 481, 3, NEG, 31500000, 37500, 75, NEG}, */ + /* { 832, 640, 700, 56, NEG, 509, 480, 481, 3, NEG, 36000000, 43269, 85, NEG}, */ + {800, 640, 656, 96, NEG, 525, 480, 490, 2, NEG, 25175000, 31469, 60, NEG}, + {840, 640, 656, 64, NEG, 500, 480, 481, 3, NEG, 31500000, 37500, 75, NEG}, + {832, 640, 696, 56, NEG, 509, 480, 481, 3, NEG, 36000000, 43269, 85, NEG}, + + /* 720 x 480 [3:2] */ + {889, 720, 738, 108, POS, 525, 480, 490, 2, NEG, 28000000, 31496, 60, NEG}, + + /* 720 x 540 [4:3] -- Not a popular mode */ + {886, 720, 740, 96, POS, 576, 540, 545, 2, POS, 30600000, 34537, 60, NEG}, + + /* 800 x 480 [5:3] -- Not a popular mode */ + {973, 800, 822, 56, POS, 524, 480, 490, 2, NEG, 30600000, 31449, 60, NEG}, + + /* 800 x 600 [4:3] */ + /* The first 2 commented lines below are taken from SM502, the rest timing are + taken from the VESA Monitor Timing Standard */ + /* {1062, 800, 840,128, POS, 628, 600, 601, 4, POS, 40000000, 37665, 60, NEG}, */ + /* {1054, 800, 842, 64, POS, 625, 600, 601, 3, POS, 56000000, 53131, 85, NEG}, */ + {1056, 800, 840, 128, POS, 628, 600, 601, 4, POS, 40000000, 37879, 60, NEG}, + {1056, 800, 816, 80, POS, 625, 600, 601, 3, POS, 49500000, 46875, 75, NEG}, + {1048, 800, 832, 64, POS, 631, 600, 601, 3, POS, 56250000, 53674, 85, NEG}, + + /* 960 x 720 [4:3] -- Not a popular mode */ + {1245, 960, 992, 64, POS, 750, 720, 721, 3, POS, 56000000, 44980, 60, NEG}, + + /* 1024 x 600 [16:9] 1.7 */ + {1313, 1024, 1064, 104, POS, 622, 600, 601, 3, POS, 49000000, 37319, 60, NEG}, + + /* 1024 x 768 [4:3] */ + /* The first 2 commented lines below are taken from SM502, the rest timing are + taken from the VESA Monitor Timing Standard */ + /* {1340,1024,1060,136, NEG, 809, 768, 772, 6, NEG, 65000000, 48507, 60, NEG}, */ + /* {1337,1024,1072, 96, NEG, 808, 768, 780, 3, NEG, 81000000, 60583, 75, NEG}, */ + {1344, 1024, 1048, 136, NEG, 806, 768, 771, 6, NEG, 65000000, 48363, 60, NEG}, + {1312, 1024, 1040, 96, POS, 800, 768, 769, 3, POS, 78750000, 60023, 75, NEG}, + {1376, 1024, 1072, 96, POS, 808, 768, 769, 3, POS, 94500000, 68677, 85, NEG}, + + /* 1152 x 864 [4:3] -- Widescreen eXtended Graphics Array */ + /* {1475,1152,1208, 96, NEG, 888, 864, 866, 3, NEG, 78600000, 53288, 60, NEG},*/ + {1475, 1152, 1208, 96, POS, 888, 864, 866, 3, POS, 78600000, 53288, 60, NEG}, + {1600, 1152, 1216, 128, POS, 900, 864, 865, 3, POS, 108000000, 67500, 75, NEG}, + + /* 1280 x 720 [16:9] -- HDTV (WXGA) */ + {1664, 1280, 1336, 136, POS, 746, 720, 721, 3, POS, 74481000, 44760, 60, NEG}, + + /* 1280 x 768 [5:3] -- Not a popular mode */ + {1678, 1280, 1350, 136, POS, 795, 768, 769, 3, POS, 80000000, 47676, 60, NEG}, + + /* 1280 x 800 [8:5] -- Not a popular mode */ + {1650, 1280, 1344, 136, NEG, 824, 800, 800, 3, NEG, 81600000, 49455, 60, NEG}, + + /* 1280 x 960 [4:3] */ + /* The first commented line below are taken from SM502, the rest timing are + taken from the VESA Monitor Timing Standard */ + /* {1618,1280,1330, 96, NEG, 977, 960, 960, 2, NEG, 94500000, 59259, 60, NEG},*/ + {1800, 1280, 1376, 112, POS, 1000, 960, 961, 3, POS, 108000000, 60000, 60, NEG}, + {1728, 1280, 1344, 160, POS, 1011, 960, 961, 3, POS, 148500000, 85938, 85, NEG}, + +/* 1280 x 1024 [5:4] */ +#if 1 + /* GTF with C = 40, M = 600, J = 20, K = 128 */ + {1712, 1280, 1360, 136, NEG, 1060, 1024, 1025, 3, POS, 108883200, 63600, 60, NEG}, + {1728, 1280, 1368, 136, NEG, 1069, 1024, 1025, 3, POS, 138542400, 80175, 75, NEG}, + {1744, 1280, 1376, 136, NEG, 1075, 1024, 1025, 3, POS, 159358000, 91375, 85, NEG}, +#else + /* VESA Standard */ + {1688, 1280, 1328, 112, POS, 1066, 1024, 1025, 3, POS, 108000000, 63981, 60, NEG}, + {1688, 1280, 1296, 144, POS, 1066, 1024, 1025, 3, POS, 135000000, 79976, 75, NEG}, + {1728, 1280, 1344, 160, POS, 1072, 1024, 1025, 3, POS, 157500000, 91146, 85, NEG}, +#endif + +/* 1360 x 768 [16:9] */ +#if 1 + /* GTF with C = 40, M = 600, J = 20, K = 128 */ + //{1776,1360,1432,136, NEG, 795, 768, 769, 3, POS, 84715200, 47700, 60, NEG}, + + /* GTF with C = 30, M = 600, J = 20, K = 128 */ + {1664, 1360, 1384, 128, NEG, 795, 768, 769, 3, POS, 79372800, 47700, 60, NEG}, +#else + /* Previous Calculation */ + {1776, 1360, 1424, 144, POS, 795, 768, 769, 3, POS, 84715000, 47700, 60, NEG}, +#endif + + /* 1366 x 768 [16:9] */ + /* Previous Calculation */ + {1722, 1366, 1424, 112, NEG, 784, 768, 769, 3, NEG, 81000000, 47038, 60, NEG}, + + /* 1400 x 1050 [4:3] -- Hitachi TX38D95VC1CAH -- It is not verified yet, therefore + temporarily disabled. */ + //{1688,1400,1448,112, NEG,1068,1050,1051, 3, NEG,108000000, 64000, 60, NEG}, + //{1688,1400,1464,112, NEG,1068,1050,1051, 3, NEG,108167040, 64080, 60, NEG}, + + /* Taken from the www.tinyvga.com */ + {1880, 1400, 1488, 152, NEG, 1087, 1050, 1051, 3, POS, 122610000, 65218, 60, NEG}, + + /* 1440 x 900 [8:5] -- Widescreen Super eXtended Graphics Array (WSXGA) */ + {1904, 1440, 1520, 152, NEG, 932, 900, 901, 3, POS, 106470000, 55919, 60, NEG}, + + /* 1440 x 960 [3:2] -- Not a popular mode */ + {1920, 1440, 1528, 152, POS, 994, 960, 961, 3, POS, 114509000, 59640, 60, NEG}, + + /* 1600 x 900 */ + {2128, 1600, 1664, 192, POS, 932, 900, 901, 3, POS, 119000000, 56000, 60, NEG}, + + /* 1600 x 1200 [4:3]. -- Ultra eXtended Graphics Array */ + /* VESA */ + {2160, 1600, 1664, 192, POS, 1250, 1200, 1201, 3, POS, 162000000, 75000, 60, NEG}, + {2160, 1600, 1664, 192, POS, 1250, 1200, 1201, 3, POS, 202500000, 93750, 75, NEG}, + {2160, 1600, 1664, 192, POS, 1250, 1200, 1201, 3, POS, 229500000, 106250, 85, NEG}, + + /* + * The timing below is taken from the www.tinyvga.com/vga-timing. + * With the exception of 1920x1080. + */ + + /* 1680 x 1050 [8:5]. -- Widescreen Super eXtended Graphics Array Plus (WSXGA+) */ + /* The first commented timing might be used for DVI LCD Monitor timing. */ + /* {1840,1680,1728, 32, NEG,1080,1050,1053, 6, POS,119232000, 64800, 60, NEG}, */ + /* GTF with C = 30, M = 600, J = 20, K = 128 */ + {2256, 1680, 1784, 184, NEG, 1087, 1050, 1051, 3, POS, 147140000, 65222, 60, NEG}, + /* + {2272,1680,1792,184, NEG,1093,1050,1051, 3, POS,173831000, 76510, 70, NEG}, + {2288,1680,1800,184, NEG,1096,1050,1051, 3, POS,188074000, 82200, 75, NEG}, +*/ + + /* 1792 x 1344 [4:3]. -- Not a popular mode */ + {2448, 1792, 1920, 200, NEG, 1394, 1344, 1345, 3, POS, 204800000, 83660, 60, NEG}, + {2456, 1792, 1888, 216, NEG, 1417, 1344, 1345, 3, POS, 261000000, 106270, 75, NEG}, + + /* 1856 x 1392 [4:3]. -- Not a popular mode + The 1856 x 1392 @ 75Hz has not been tested due to high Horizontal Frequency + where not all monitor can support it (including the developer monitor) + */ + {2528, 1856, 1952, 224, NEG, 1439, 1392, 1393, 3, POS, 218300000, 86353, 60, NEG}, + /* {2560,1856,1984,224, NEG,1500,1392,1393, 3, POS,288000000,112500, 75, NEG},*/ + + /* 1920 x 1080 [16:9]. This is a make-up value, need to be proven. + The Pixel clock is calculated based on the maximum resolution of + "Single Link" DVI, which support a maximum 165MHz pixel clock. + The second values are taken from: + http://www.tek.com/Measurement/App_Notes/25_14700/eng/25W_14700_3.pdf + */ + /* {2560,1920,2048,208, NEG,1125,1080,1081, 3, POS,172800000, 67500, 60, NEG}, */ + {2200, 1920, 2008, 44, NEG, 1125, 1080, 1081, 3, POS, 148500000, 67500, 60, NEG}, + + /* 1920 x 1200 [8:5]. -- Widescreen Ultra eXtended Graphics Array (WUXGA) */ + {2592, 1920, 2048, 208, NEG, 1242, 1200, 1201, 3, POS, 193160000, 74522, 60, NEG}, + + /* 1920 x 1440 [4:3]. */ + /* In the databook, it mentioned only support up to 1920x1440 @ 60Hz. + The timing for 75 Hz is provided here if necessary to do testing. - Some underflow + has been noticed. */ + {2600, 1920, 2048, 208, NEG, 1500, 1440, 1441, 3, POS, 234000000, 90000, 60, NEG}, + /* {2640,1920,2064,224, NEG,1500,1440,1441, 3, POS,297000000,112500, 75, NEG}, */ + + /* End of table. */ + {0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, +}; + +#if 0 +static mode_parameter_t gPrimaryModeParamTable[MAX_SMI_DEVICE][MAX_MODE_TABLE_ENTRIES] = +{ + { + /* End of table */ + { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, + }, + { + /* End of table */ + { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, + }, + { + /* End of table */ + { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, + }, + { + /* End of table */ + { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, + } +}; + +static mode_parameter_t gSecondaryModeParamTable[MAX_SMI_DEVICE][MAX_MODE_TABLE_ENTRIES] = +{ + { + /* End of table */ + { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, + }, + { + /* End of table */ + { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, + }, + { + /* End of table */ + { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, + }, + { + /* End of table */ + { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, + } +}; +#endif + +/* Static variable to store the mode information. */ +static mode_parameter_t gPrimaryCurrentModeParam[MAX_SMI_DEVICE]; +static mode_parameter_t gSecondaryCurrentModeParam[MAX_SMI_DEVICE]; + +/* + * getUserDataSignature + * This function gets the user data mode signature + * + * Output: + * The signature to be filled in the user_data_mode_t structure to be considered + * a valid structure. + */ +unsigned long getUserDataSignature(void) +{ + return MODE_USER_DATA_SIGNATURE; +} + +/* + * findModeParamFromTable + * This function locates the requested mode in the given parameter table + * + * Input: + * width - Mode width + * height - Mode height + * refresh_rate - Mode refresh rate + * index - Index that is used for multiple search of the same mode + * that have the same width, height, and refresh rate, + * but have different timing parameters. + * + * Output: + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *findModeParamFromTable( + unsigned long width, + unsigned long height, + unsigned long refresh_rate, + unsigned short index, + mode_parameter_t *pModeTable +) +{ + unsigned short modeIndex = 0; +#if 0 + unsigned short tempIndex = 0; +#endif + /* Walk the entire mode table. */ + while (pModeTable[modeIndex].pixel_clock != 0) + { + if (((width == (unsigned long)(-1)) || (pModeTable[modeIndex].horizontal_display_end == width)) && + ((height == (unsigned long)(-1)) || (pModeTable[modeIndex].vertical_display_end == height)) && + ((refresh_rate == (unsigned long)(-1)) || (pModeTable[modeIndex].vertical_frequency == refresh_rate))) + { +#if 0 + if (tempIndex < index) + tempIndex++; + else +#endif + { + return (&pModeTable[modeIndex]); + } + } + + /* Next entry */ + modeIndex++; + } + + /* No match, return NULL pointer */ + return((mode_parameter_t *)0); +} + +/* + * Locate in-stock parameter table for the requested mode. + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *findModeParam( + disp_control_t dispCtrl, + unsigned long width, + unsigned long height, + unsigned long refresh_rate, + unsigned short index +) +{ + return findModeParamFromTable(width, height, refresh_rate, index, getStockModeParamTableEx(dispCtrl)); +} + +/* + * Use the + * Locate timing parameter for the requested mode from the default mode table. + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *findVesaModeParam( + unsigned long width, + unsigned long height, + unsigned long refresh_rate +) +{ + switch(ddk750_getChipType()) + { + default: /* Normal SM750/SM718 */ + return findModeParamFromTable(width, height, refresh_rate, 0, gDefaultModeParamTable); + } +} + +/* + * (Obsolete) + * Return a point to the gDefaultModeParamTable. + * Function in other files used this to get the mode table pointer. + */ +mode_parameter_t *getStockModeParamTable(void) +{ + switch(ddk750_getChipType()) + { + default: + return (gDefaultModeParamTable); + } +} + +/* + * (Obsolete) + * Return the size of the Stock Mode Param Table + */ +unsigned long getStockModeParamTableSize(void) +{ + + return (sizeof(gDefaultModeParamTable) / sizeof(mode_parameter_t) - 1); + +} + +/* + * getStockModeParamTableEx + * This function gets the mode parameters table associated to the + * display control (CHANNEL0_CTRL or SECONDAR_CTRL). + * + * Input: + * dispCtrl - Display Control of the mode table that is associated to. + * + * Output: + * Pointer to the mode table + */ +mode_parameter_t *getStockModeParamTableEx( + disp_control_t dispCtrl +) +{ + mode_parameter_t *pModeTable; + pModeTable = getStockModeParamTable(); +#if 0 + if (dispCtrl == CHANNEL0_CTRL) + pModeTable = (mode_parameter_t *)&gPrimaryModeParamTable[getCurrentDevice()]; + else + pModeTable = (mode_parameter_t *)&gSecondaryModeParamTable[getCurrentDevice()]; + + /* Check if the table exist by checking the first entry. + If it doesn't, then use the default mode table. */ + if (pModeTable->pixel_clock == 0) + { +#if 1 /* Cheok_2013_0118 */ + pModeTable = getStockModeParamTable(); +#else + if (ddk750_getChipType() == SM750LE) + pModeTable = (mode_parameter_t *)&gSM750LEModeParamTable; + else + pModeTable = (mode_parameter_t *)&gDefaultModeParamTable; +#endif + } +#endif + return (pModeTable); +} + +/* + * getStockModeParamTableSizeEx + * This function gets the size of the mode parameter table associated with + * specific display control + * + * Input: + * dispCtrl - Display control of the mode param table that is associated to. + * + * Output: + * Size of the requeted mode param table. + */ +unsigned long getStockModeParamTableSizeEx( + disp_control_t dispCtrl +) +{ + unsigned long tableSize; + mode_parameter_t *pModeTable; + + /* Get the mode table */ + pModeTable = getStockModeParamTableEx(dispCtrl); + + /* Calculate the table size by finding the end of table entry indicated by all zeroes. */ + tableSize = 0; + while (pModeTable[tableSize].pixel_clock != 0) + tableSize++; + + return tableSize; +} + + +/* + * This function returns the current mode. + */ +mode_parameter_t getCurrentModeParam( + disp_control_t dispCtrl +) +{ + if (dispCtrl == CHANNEL0_CTRL) + return gPrimaryCurrentModeParam[getCurrentDevice()]; + else + return gSecondaryCurrentModeParam[getCurrentDevice()]; +} + +/* + * Convert the timing into possible SM750 timing. + * If actual pixel clock is not equal to timing pixel clock. + * other parameter like horizontal total and sync have to be changed. + * + * Input: Pointer to a mode parameters. + * Pointer to a an empty mode parameter structure to be filled. + * Actual pixel clock generated by SMI hardware. + * + * Output: + * 1) Fill up input structure mode_parameter_t with possible timing for SM750. + */ +long adjustModeParam( +mode_parameter_t *pModeParam,/* Pointer to mode parameter */ +mode_parameter_t *pMode, /* Pointer to mode parameter to be updated here */ +unsigned long ulPClk /* real pixel clock feasible by SM750 */ +) +{ + unsigned long blank_width, sync_start, sync_width; + + /* Sanity check */ + if ( pModeParam == (mode_parameter_t *)0 || + pMode == (mode_parameter_t *)0 || + ulPClk == 0) + { + return -1; + } + + /* Copy VESA mode into SM750 mode. */ + *pMode = *pModeParam; + + /* If it can generate the vesa required pixel clock, and there are a minimum of + 24 pixel difference between the horizontal sync start and the horizontal display + end, then there is nothing to change */ + if ((ulPClk == pModeParam->pixel_clock) && + ((pModeParam->horizontal_sync_start - pModeParam->horizontal_display_end) > 24)) + return 0; + + pMode->pixel_clock = ulPClk; /* Update actual pixel clock into mode */ + + /* Calculate the sync percentages of the VESA mode. */ + blank_width = pModeParam->horizontal_total - pModeParam->horizontal_display_end; + sync_start = roundedDiv((pModeParam->horizontal_sync_start - + pModeParam->horizontal_display_end) * 100, blank_width); + sync_width = roundedDiv(pModeParam->horizontal_sync_width * 100, blank_width); + + /* Calculate the horizontal total based on the actual pixel clock and VESA line frequency. */ + pMode->horizontal_total = roundedDiv(pMode->pixel_clock, + pModeParam->horizontal_frequency); + + /* Calculate the sync start and width based on the VESA percentages. */ + blank_width = pMode->horizontal_total - pMode->horizontal_display_end; + + if (ddk750_getChipType() == SM750) + { + unsigned long sync_adjustment; + + /* There is minimum delay of 22 pixels between the horizontal display end + to the horizontal sync start. Therefore, the horizontal sync start value + needs to be adjusted if the value falls below 22 pixels. + The 22 pixels comes from the propagating delay from the CRT display to + all the 11 display pipes inside SM750. The factor of 2 is caused by the + double pixel support in SM750. The value used here is 24 to align to + 8 bit character width. + */ + sync_adjustment = roundedDiv(blank_width * sync_start, 100); + if (sync_adjustment < 24) + sync_adjustment = 24; + pMode->horizontal_sync_start = pMode->horizontal_display_end + sync_adjustment; + + /* Check if the adjustment of the sync start will cause the sync width to go + over the horizontal total. If it is, then reduce the width instead of + changing the horizontal total. + */ + /* Maximum value for sync width and back porch. */ + sync_adjustment = blank_width - sync_adjustment; + pMode->horizontal_sync_width = roundedDiv(blank_width * sync_width, 100); + if (sync_adjustment <= pMode->horizontal_sync_width) + pMode->horizontal_sync_width = sync_adjustment/2; + } + else + { + /* SM718 does not have the above restriction. */ + pMode->horizontal_sync_start = pMode->horizontal_display_end + roundedDiv(blank_width * sync_start, 100); + pMode->horizontal_sync_width = roundedDiv(blank_width * sync_width, 100); + } + + /* Calculate the line and screen frequencies. */ + pMode->horizontal_frequency = roundedDiv(pMode->pixel_clock, + pMode->horizontal_total); + pMode->vertical_frequency = roundedDiv(pMode->horizontal_frequency, + pMode->vertical_total); + return 0; +} + + +/* + * This function gets the display status + * + * Input: + * dispControl - display control of which display status to be retrieved. + * + * Output: + * 0 - Display is pending + * -1 - Display is not pending + */ +long isCurrentDisplayPending( + disp_control_t dispControl +) +{ + /* Get the display status */ + if (dispControl == CHANNEL0_CTRL) + { + if (FIELD_GET(peekRegisterDWord(PRIMARY_FB_ADDRESS), PRIMARY_FB_ADDRESS, STATUS) == PRIMARY_FB_ADDRESS_STATUS_PENDING) + return 0; + } + else if (dispControl == CHANNEL1_CTRL) + { + if (FIELD_GET(peekRegisterDWord(SECONDARY_FB_ADDRESS), SECONDARY_FB_ADDRESS, STATUS) == SECONDARY_FB_ADDRESS_STATUS_PENDING) + return 0; + } + + return (-1); +} + +/* + * This function sets the display base address + * + * Input: + * dispControl - display control of which base address to be set. + * ulBaseAddress - Base Address value to be set. + */ +void setDisplayBaseAddress( + disp_control_t dispControl, + unsigned long ulBaseAddress +) +{ + if (dispControl == CHANNEL0_CTRL) + { + /* Frame buffer base for this mode */ + pokeRegisterDWord(PRIMARY_FB_ADDRESS, + FIELD_SET(0, PRIMARY_FB_ADDRESS, STATUS, PENDING) + | FIELD_SET(0, PRIMARY_FB_ADDRESS, EXT, LOCAL) + | FIELD_VALUE(0, PRIMARY_FB_ADDRESS, ADDRESS, ulBaseAddress)); + } + else if (dispControl == CHANNEL1_CTRL) + { + /* Frame buffer base for this mode */ + pokeRegisterDWord(SECONDARY_FB_ADDRESS, + FIELD_SET(0, SECONDARY_FB_ADDRESS, STATUS, PENDING) + | FIELD_SET(0, SECONDARY_FB_ADDRESS, EXT, LOCAL) + | FIELD_VALUE(0, SECONDARY_FB_ADDRESS, ADDRESS, ulBaseAddress)); + } +} + + +/* + * Program the hardware for a specific video mode + */ +void programModeRegisters( +mode_parameter_t *pModeParam, /* mode information about pixel clock, horizontal total, etc. */ +unsigned long ulBpp, /* Color depth for this mode */ +unsigned long ulBaseAddress, /* Offset in frame buffer */ +unsigned long ulPitch, /* Mode pitch value in byte: no of bytes between two lines. */ +pll_value_t *pPLL /* Pre-calculated values for the PLL */ +) +{ + unsigned long ulTmpValue, ulReg, ulReservedBits; + unsigned long palette_ram; + unsigned long offset; + logical_chip_type_t chipType; + + /* Enable display power gate */ + ulTmpValue = peekRegisterDWord(CURRENT_GATE); + ulTmpValue = FIELD_SET(ulTmpValue, CURRENT_GATE, DISPLAY, ON); + setCurrentGate(ulTmpValue); + + if (pPLL->clockType == SECONDARY_PLL) + { + // printk("func[%s], secondary reg, ulPitch=[%d]\n", __func__, ulPitch); + /* Secondary Display Control: SECONDARY_PLL */ + pokeRegisterDWord(SECONDARY_PLL_CTRL, formatPllReg(pPLL)); + + /* Frame buffer base for this mode */ + //setDisplayBaseAddress(CHANNEL1_CTRL, ulBaseAddress);//move by ilena + + /* Pitch value (Sometime, hardware people calls it Offset) */ + // pokeRegisterDWord(SECONDARY_FB_WIDTH, + // FIELD_VALUE(0, SECONDARY_FB_WIDTH, WIDTH, ulPitch) + // | FIELD_VALUE(0, SECONDARY_FB_WIDTH, OFFSET, ulPitch)); + + pokeRegisterDWord(SECONDARY_HORIZONTAL_TOTAL, + FIELD_VALUE(0, SECONDARY_HORIZONTAL_TOTAL, TOTAL, pModeParam->horizontal_total - 1) + | FIELD_VALUE(0, SECONDARY_HORIZONTAL_TOTAL, DISPLAY_END, pModeParam->horizontal_display_end - 1)); + + pokeRegisterDWord(SECONDARY_HORIZONTAL_SYNC, + FIELD_VALUE(0, SECONDARY_HORIZONTAL_SYNC, WIDTH, pModeParam->horizontal_sync_width) + | FIELD_VALUE(0, SECONDARY_HORIZONTAL_SYNC, START, pModeParam->horizontal_sync_start - 1)); + + pokeRegisterDWord(SECONDARY_VERTICAL_TOTAL, + FIELD_VALUE(0, SECONDARY_VERTICAL_TOTAL, TOTAL, pModeParam->vertical_total - 1) + | FIELD_VALUE(0, SECONDARY_VERTICAL_TOTAL, DISPLAY_END, pModeParam->vertical_display_end - 1)); + + pokeRegisterDWord(SECONDARY_VERTICAL_SYNC, + FIELD_VALUE(0, SECONDARY_VERTICAL_SYNC, HEIGHT, pModeParam->vertical_sync_height) + | FIELD_VALUE(0, SECONDARY_VERTICAL_SYNC, START, pModeParam->vertical_sync_start - 1)); + + /* Set control register value */ + ulTmpValue = + (pModeParam->vertical_sync_polarity == POS + ? FIELD_SET(0, SECONDARY_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_HIGH) + : FIELD_SET(0, SECONDARY_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW)) + | (pModeParam->horizontal_sync_polarity == POS + ? FIELD_SET(0, SECONDARY_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_HIGH) + : FIELD_SET(0, SECONDARY_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW)) + | FIELD_SET(0, SECONDARY_DISPLAY_CTRL, SELECT, SECONDARY) + | FIELD_SET(0, SECONDARY_DISPLAY_CTRL, TIMING, ENABLE) + | FIELD_SET(0, SECONDARY_DISPLAY_CTRL, PLANE, ENABLE) + | (ulBpp == 8 + ? FIELD_SET(0, SECONDARY_DISPLAY_CTRL, FORMAT, 8) + : (ulBpp == 16 + ? FIELD_SET(0, SECONDARY_DISPLAY_CTRL, FORMAT, 16) + : FIELD_SET(0, SECONDARY_DISPLAY_CTRL, FORMAT, 32))); + + chipType = ddk750_getChipType(); + + if (chipType == SM750 || chipType == SM718) + { + /* TODO: Check if the auto expansion bit can be cleared here */ + ulReg = peekRegisterDWord(SECONDARY_DISPLAY_CTRL) + & FIELD_CLEAR(SECONDARY_DISPLAY_CTRL, VSYNC_PHASE) + & FIELD_CLEAR(SECONDARY_DISPLAY_CTRL, HSYNC_PHASE) + & FIELD_CLEAR(SECONDARY_DISPLAY_CTRL, SELECT) + & FIELD_CLEAR(SECONDARY_DISPLAY_CTRL, TIMING) + & FIELD_CLEAR(SECONDARY_DISPLAY_CTRL, PLANE) + & FIELD_CLEAR(SECONDARY_DISPLAY_CTRL, FORMAT) + & FIELD_CLEAR(SECONDARY_DISPLAY_CTRL, LOCK_TIMING) + & FIELD_CLEAR(SECONDARY_DISPLAY_CTRL, EXPANSION); + + pokeRegisterDWord(SECONDARY_DISPLAY_CTRL, ulTmpValue | ulReg); + } + + + /* Palette RAM. */ + palette_ram = SECONDARY_PALETTE_RAM; + + /* Save the current mode param */ + gSecondaryCurrentModeParam[getCurrentDevice()] = *pModeParam; + } + else + { + /* Primary display control clock: PRIMARY_PLL */ + pokeRegisterDWord(PRIMARY_PLL_CTRL, formatPllReg(pPLL)); + + /* Program primary PLL, if applicable */ + if (pPLL->clockType == PRIMARY_PLL) + { + pokeRegisterDWord(PRIMARY_PLL_CTRL, formatPllReg(pPLL)); + + /* Program to Non-VGA mode when using primary PLL */ + pokeRegisterDWord(VGA_CONFIGURATION, + FIELD_SET(peekRegisterDWord(VGA_CONFIGURATION), VGA_CONFIGURATION, PLL, PRIMARY)); + } + + /* Frame buffer base for this mode */ + //setDisplayBaseAddress(CHANNEL0_CTRL, ulBaseAddress);// move by iena + //printk("func[%s], primary reg, ulPitch=[%d]\n", __func__, ulPitch); + /* Pitch value (Sometime, hardware people calls it Offset) */ + //pokeRegisterDWord(PRIMARY_FB_WIDTH, + // FIELD_VALUE(0, PRIMARY_FB_WIDTH, WIDTH, ulPitch) + //| FIELD_VALUE(0, PRIMARY_FB_WIDTH, OFFSET, ulPitch)); + + pokeRegisterDWord(PRIMARY_WINDOW_WIDTH, + FIELD_VALUE(0, PRIMARY_WINDOW_WIDTH, WIDTH, pModeParam->horizontal_display_end - 1) + | FIELD_VALUE(0, PRIMARY_WINDOW_WIDTH, X, 0)); + + pokeRegisterDWord(PRIMARY_WINDOW_HEIGHT, + FIELD_VALUE(0, PRIMARY_WINDOW_HEIGHT, HEIGHT, pModeParam->vertical_display_end - 1) + | FIELD_VALUE(0, PRIMARY_WINDOW_HEIGHT, Y, 0)); + + pokeRegisterDWord(PRIMARY_PLANE_TL, + FIELD_VALUE(0, PRIMARY_PLANE_TL, TOP, 0) + | FIELD_VALUE(0, PRIMARY_PLANE_TL, LEFT, 0)); + + pokeRegisterDWord(PRIMARY_PLANE_BR, + FIELD_VALUE(0, PRIMARY_PLANE_BR, BOTTOM, pModeParam->vertical_display_end - 1) + | FIELD_VALUE(0, PRIMARY_PLANE_BR, RIGHT, pModeParam->horizontal_display_end - 1)); + + pokeRegisterDWord(PRIMARY_HORIZONTAL_TOTAL, + FIELD_VALUE(0, PRIMARY_HORIZONTAL_TOTAL, TOTAL, pModeParam->horizontal_total - 1) + | FIELD_VALUE(0, PRIMARY_HORIZONTAL_TOTAL, DISPLAY_END, pModeParam->horizontal_display_end - 1)); + + pokeRegisterDWord(PRIMARY_HORIZONTAL_SYNC, + FIELD_VALUE(0, PRIMARY_HORIZONTAL_SYNC, WIDTH, pModeParam->horizontal_sync_width) + | FIELD_VALUE(0, PRIMARY_HORIZONTAL_SYNC, START, pModeParam->horizontal_sync_start - 1)); + + pokeRegisterDWord(PRIMARY_VERTICAL_TOTAL, + FIELD_VALUE(0, PRIMARY_VERTICAL_TOTAL, TOTAL, pModeParam->vertical_total - 1) + | FIELD_VALUE(0, PRIMARY_VERTICAL_TOTAL, DISPLAY_END, pModeParam->vertical_display_end - 1)); + + pokeRegisterDWord(PRIMARY_VERTICAL_SYNC, + FIELD_VALUE(0, PRIMARY_VERTICAL_SYNC, HEIGHT, pModeParam->vertical_sync_height) + | FIELD_VALUE(0, PRIMARY_VERTICAL_SYNC, START, pModeParam->vertical_sync_start - 1)); + + /* Set control register value */ + ulTmpValue = + (pModeParam->clock_phase_polarity == POS + ? FIELD_SET(0, PRIMARY_DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_HIGH) + : FIELD_SET(0, PRIMARY_DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_LOW)) + | (pModeParam->vertical_sync_polarity == POS + ? FIELD_SET(0, PRIMARY_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_HIGH) + : FIELD_SET(0, PRIMARY_DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW)) + | (pModeParam->horizontal_sync_polarity == POS + ? FIELD_SET(0, PRIMARY_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_HIGH) + : FIELD_SET(0, PRIMARY_DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW)) + | FIELD_SET(0, PRIMARY_DISPLAY_CTRL, TIMING, ENABLE) + | FIELD_SET(0, PRIMARY_DISPLAY_CTRL, PLANE, ENABLE) + | (ulBpp == 8 + ? FIELD_SET(0, PRIMARY_DISPLAY_CTRL, FORMAT, 8) + : (ulBpp == 16 + ? FIELD_SET(0, PRIMARY_DISPLAY_CTRL, FORMAT, 16) + : FIELD_SET(0, PRIMARY_DISPLAY_CTRL, FORMAT, 32))); + + /* Added some masks to mask out the reserved bits. + * Sometimes, the reserved bits are set/reset randomly when + * writing to the PRIMARY_DISPLAY_CTRL, therefore, the register + * reserved bits are needed to be masked out. + */ + ulReservedBits = FIELD_SET(0, PRIMARY_DISPLAY_CTRL, RESERVED_1_MASK, ENABLE) | + FIELD_SET(0, PRIMARY_DISPLAY_CTRL, RESERVED_2_MASK, ENABLE) | + FIELD_SET(0, PRIMARY_DISPLAY_CTRL, RESERVED_3_MASK, ENABLE); + + ulReg = (peekRegisterDWord(PRIMARY_DISPLAY_CTRL) & ~ulReservedBits) + & FIELD_CLEAR(PRIMARY_DISPLAY_CTRL, CLOCK_PHASE) + & FIELD_CLEAR(PRIMARY_DISPLAY_CTRL, VSYNC_PHASE) + & FIELD_CLEAR(PRIMARY_DISPLAY_CTRL, HSYNC_PHASE) + & FIELD_CLEAR(PRIMARY_DISPLAY_CTRL, TIMING) + & FIELD_CLEAR(PRIMARY_DISPLAY_CTRL, VERTICAL_PAN) + & FIELD_CLEAR(PRIMARY_DISPLAY_CTRL, HORIZONTAL_PAN) + & FIELD_CLEAR(PRIMARY_DISPLAY_CTRL, PLANE) + & FIELD_CLEAR(PRIMARY_DISPLAY_CTRL, FORMAT); + + pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, ulTmpValue | ulReg); + + /* + * PRIMARY_DISPLAY_CTRL register seems requiring few writes + * before a value can be succesfully written in. + * Added some masks to mask out the reserved bits. + * Note: This problem happens by design. The hardware will wait for the + * next vertical sync to turn on/off the plane. + */ + while((peekRegisterDWord(PRIMARY_DISPLAY_CTRL) & ~ulReservedBits) != (ulTmpValue|ulReg)) + { + pokeRegisterDWord(PRIMARY_DISPLAY_CTRL, ulTmpValue | ulReg); + } + + /* Palette RAM */ + palette_ram = PRIMARY_PALETTE_RAM; + + /* Save the current mode param */ + gPrimaryCurrentModeParam[getCurrentDevice()] = *pModeParam; + } + + /* In case of 8-bpp, fill palette */ + if (ulBpp==8) + { + /* Start with RGB = 0,0,0. */ + unsigned char red = 0, green = 0, blue = 0; + unsigned long gray = 0; + for (offset = 0; offset < 256 * 4; offset += 4) + { + /* Store current RGB value. */ + pokeRegisterDWord(palette_ram + offset, gray + ? RGB((gray + 50) / 100, + (gray + 50) / 100, + (gray + 50) / 100) + : RGB(red, green, blue)); + + if (gray) + { + /* Walk through grays (40 in total). */ + gray += 654; + } + + else + { + /* Walk through colors (6 per base color). */ + if (blue != 255) + { + blue += 51; + } + else if (green != 255) + { + blue = 0; + green += 51; + } + else if (red != 255) + { + green = blue = 0; + red += 51; + } + else + { + gray = 1; + } + } + } + } + + /* For 16- and 32-bpp, fill palette with gamma values. */ + else + { + /* Start with RGB = 0,0,0. */ + ulTmpValue = 0x000000; + for (offset = 0; offset < 256 * 4; offset += 4) + { + pokeRegisterDWord(palette_ram + offset, ulTmpValue); + + /* Advance RGB by 1,1,1. */ + ulTmpValue += 0x010101; + } + } +} + +/* + * This function gets the available clock type + * + */ +clock_type_t getClockType(disp_control_t dispCtrl) +{ + clock_type_t clockType; + + switch (dispCtrl) + { + case CHANNEL0_CTRL: + clockType = PRIMARY_PLL; + break; + default: + case CHANNEL1_CTRL: + clockType = SECONDARY_PLL; + break; + } + return clockType; +} + +/* + * Input: + * 1) pLogicalMode contains information such as x, y resolution and bpp. + * 2) A user defined parameter table for the mode. + * + * This function calculate and programs the hardware to set up the + * requested mode. + * + * This function allows the use of user defined parameter table if + * predefined Vesa parameter table (gDefaultModeParamTable) does not fit. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long setCustomMode( + logicalMode_t *pLogicalMode, + mode_parameter_t *pUserModeParam +) +{ + mode_parameter_t pModeParam; /* physical parameters for the mode */ + pll_value_t pll; + unsigned long ulActualPixelClk, ulTemp; + + /* + * Minimum check on mode base address. + * At least it shouldn't be bigger than the size of frame buffer. + */ + if (ddk750_getFrameBufSize() <= pLogicalMode->baseAddress) + {printk("in func [%s], line[%d], return error\n", __func__, __LINE__); + return -1; + } + + /* + * Set up PLL, a structure to hold the value to be set in clocks. + */ + pll.inputFreq = DEFAULT_INPUT_CLOCK; /* Defined in CLOCK.H */ + + /* Get the Clock Type */ + pll.clockType = getClockType(pLogicalMode->dispCtrl); + + /* + * Call calcPllValue() to fill up the other fields for PLL structure. + * Sometime, the chip cannot set up the exact clock required by User. + * Return value from calcPllValue() gives the actual possible pixel clock. + */ + ulActualPixelClk = calcPllValue(pUserModeParam->pixel_clock, &pll); + //DDKDEBUGPRINT((DISPLAY_LEVEL, "Actual Pixel Clock: %d\n", ulActualPixelClk)); + + /* + * Adjust Vesa mode parameter to feasible mode parameter for SMI hardware. + */ + if (adjustModeParam(pUserModeParam, &pModeParam, ulActualPixelClk) != 0 ) + { + //printk("in func [%s], line[%d], return error\n", __func__, __LINE__); + return -1; + } + + /* If calling function don't have a preferred pitch value, + work out a 16 byte aligned pitch value. + */ + //printk("func[%s], ulPitch=[%d]\n", __func__, pLogicalMode->pitch); + if (pLogicalMode->pitch <= 0) + { + /* + * Pitch value calculation in Bytes. + * Usually, it is (screen width) * (byte per pixel). + * However, there are cases that screen width is not 16 pixel aligned, which is + * a requirement for some OS and the hardware itself. + * For standard 4:3 resolutions: 320, 640, 800, 1024 and 1280, they are all + * 16 pixel aligned and pitch is simply (screen width) * (byte per pixel). + * + * However, 1366 resolution, for example, has to be adjusted for 16 pixel aligned. + */ + + ulTemp = (pLogicalMode->x + 15) & ~15; /* This calculation has no effect on 640, 800, 1024 and 1280. */ + pLogicalMode->pitch = ulTemp * (pLogicalMode->bpp / 8); + } + //printk("func[%s], ulPitch=[%d]\n", __func__, pLogicalMode->pitch); + + /* Program the hardware to set up the mode. */ + programModeRegisters( + &pModeParam, + pLogicalMode->bpp, + pLogicalMode->baseAddress, + pLogicalMode->pitch, + &pll); + + return (0); +} + +/* + * Input: + * 1) pLogicalMode contains information such as x, y resolution, bpp, xLCD, and yLCD. + * 2) A user defined parameter table for the mode. + * + * This function calculate and programs the hardware to set up the + * requested mode and scale the mode if necessary. + * + * This function allows the use of user defined parameter table if + * predefined parameter table does not fit. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long setCustomModeEx( + logicalMode_t *pLogicalMode, + mode_parameter_t *pUserModeParam +) +{ + long returnValue = 0; + +#if 0 /* userData field is used on DDK version 1.1 and above. Thereofre, this checking is + not needed anymore. */ + /* For the current DDK version, the userData needs to be set to 0. If not, then return error. */ + if (pLogicalMode->userData != (void *)0) + return (-1); +#endif + + /* Return error when the mode is bigger than the panel size. Might be temporary solution + depending whether we will support panning or not. */ + if (((pLogicalMode->xLCD != 0) && + (pLogicalMode->yLCD != 0)) && + ((pLogicalMode->xLCD < pLogicalMode->x) || + (pLogicalMode->yLCD < pLogicalMode->y))) + { + //printk("in func [%s], line[%d], return error\n", __func__, __LINE__); + return (-1); + } + + /* Return error when the panel size exceed the maximum mode that we can support. */ + if ((pLogicalMode->xLCD > MAX_PANEL_SIZE_WIDTH) || + (pLogicalMode->yLCD > MAX_PANEL_SIZE_HEIGHT)) + { + //printk("in func [%s], line[%d], return error\n", __func__, __LINE__); + return (-1); /* Unsupported panel size. */ + } + + /* Set the mode first */ + returnValue = setCustomMode(pLogicalMode, pUserModeParam); + + + return (returnValue); +} + +/* + * Input pLogicalMode contains information such as x, y resolution, bpp, + * xLCD and yLCD. The main difference between setMode and setModeEx are + * these two parameters (xLCD and yLCD). Use this setModeEx API to set + * expansion while setMode API for regular setmode without any expansion. + * Refer to MODE.h for the details. + * + * This function calculate and programs the hardware to set up the + * requested mode. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long setModeEx( + logicalMode_t *pLogicalMode +) +{ + mode_parameter_t *pModeParam; /* physical parameters for the mode */ + unsigned short index = 0; + unsigned long modeWidth, modeHeight; + userData_t *pUserData; + + /* Conditions to set the mode when scaling is needed (xLCD and yLCD is not zeroes) + * 1. CHANNEL0_CTRL + * a. Set the primary display control timing to the actual display mode. + * b. Set the secondary display control timing to the mode that equals to + * the panel size. + * 2. CHANNEL1_CTRL + * a. Set the secondary display control timing to the mode that equals to + * the panel size. + */ + if ((pLogicalMode->dispCtrl == CHANNEL1_CTRL) && + (pLogicalMode->xLCD != 0) && (pLogicalMode->yLCD != 0)) + { + modeWidth = pLogicalMode->xLCD; + modeHeight = pLogicalMode->yLCD; + } + else + { + modeWidth = pLogicalMode->x; + modeHeight = pLogicalMode->y; + } + + /* + * Check the validity of the userData pointer and translate the information as necessary + */ + pUserData = (userData_t *)pLogicalMode->userData; + if ((pUserData != (userData_t *)0) && + (pUserData->signature == getUserDataSignature()) && + (pUserData->size == sizeof(userData_t))) + { + /* Interpret the userData information */ + if (pUserData->paramList.size == sizeof(userDataParam_t)) + { + if (pUserData->paramList.modeInfoID == MODE_INFO_INDEX) + index = pUserData->paramList.paramInfo.index; + } + } + + /* + * Check if we already have physical timing parameter for this mode. + */ + // printk("fine ctrl=[%d], width[%d](x=[%d]), height[%d], hz[%d], index[%d], disp=[%d]\n", pLogicalMode->dispCtrl, modeWidth,pLogicalMode->x,modeHeight, pLogicalMode->hz, index,pLogicalMode->dispCtrl); + pModeParam = findModeParam(pLogicalMode->dispCtrl, modeWidth, modeHeight, pLogicalMode->hz, index); + if (pModeParam == (mode_parameter_t *)0) + { + //printk("in func [%s], line[%d], return error\n", __func__, __LINE__); + return -1; + } + + return(setCustomModeEx(pLogicalMode, pModeParam)); +} + +/* + * Input pLogicalMode contains information such as x, y resolution and bpp. + * Refer to MODE.h for the details. + * + * This function calculate and programs the hardware to set up the + * requested mode. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long setMode( + logicalMode_t *pLogicalMode +) +{ + /* Initialize the panel size to 0 */ + pLogicalMode->xLCD = 0; + pLogicalMode->yLCD = 0; + pLogicalMode->userData = (void *)0; + + /* Call the setModeEx to set the mode. */ + return setModeEx(pLogicalMode); +} + +/* + * setInterpolation + * This function enables/disables the horizontal and vertical interpolation + * for the secondary display control. Primary display control does not have + * this capability. + * + * Input: + * enableHorzInterpolation - Flag to enable/disable Horizontal interpolation + * enableVertInterpolation - Flag to enable/disable Vertical interpolation + */ +void setInterpolation( + unsigned long enableHorzInterpolation, + unsigned long enableVertInterpolation +) +{ + unsigned long value; + + value = peekRegisterDWord(SECONDARY_DISPLAY_CTRL); + + if (enableHorzInterpolation) + value = FIELD_SET(value, SECONDARY_DISPLAY_CTRL, HORIZONTAL_MODE, INTERPOLATE); + else + value = FIELD_SET(value, SECONDARY_DISPLAY_CTRL, HORIZONTAL_MODE, REPLICATE); + + if (enableVertInterpolation) + value = FIELD_SET(value, SECONDARY_DISPLAY_CTRL, VERTICAL_MODE, INTERPOLATE); + else + value = FIELD_SET(value, SECONDARY_DISPLAY_CTRL, VERTICAL_MODE, REPLICATE); + + pokeRegisterDWord(SECONDARY_DISPLAY_CTRL, value); +} diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_mode.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_mode.h new file mode 100644 index 000000000000..ed764f5c8818 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_mode.h @@ -0,0 +1,450 @@ +#ifndef _MODE_H_ +#define _MODE_H_ + +#include "../hw_com.h" +/* Maximum parameters those can be saved in the mode table. */ +#define MAX_MODE_TABLE_ENTRIES 60 + +/* Set the alignment to 1-bit aligned. Otherwise, the memory compare used in the + modeext to compare timing will not work. */ +#pragma pack(1) + + + +/* + * ID of the modeInfoID used in the userDataParam_t + */ +#define MODE_INFO_INDEX 0x01 + +/* Restore alignment */ +#pragma pack() + +/* + * getUserDataSignature + * This function gets the user data mode signature + * + * Output: + * The signature to be filled in the user_data_mode_t structure to be considered + * a valid structure. + */ +unsigned long getUserDataSignature(void); + +/* + * compareModeParam + * This function compares two mode parameters + * + * Input: + * pModeParam1 - Pointer to the first mode parameter to be compared + * pModeParam2 - Pointer to the second mode parameter to be compared + * + * Output: + * 0 - Identical mode + * -1 - Mode is not identical + */ +long compareModeParam( + mode_parameter_t *pModeParam1, + mode_parameter_t *pModeParam2 +); + +/* + * getDuplicateModeIndex + * This function retrieves the index of dupicate modes, but having different timing. + * + * Input: + * dispCtrl - Display Control where the mode table belongs to. + * pModeParam - The mode parameters which index to be checked. + * + * Output: + * 0xFFFF - The mode parameter can not be found in the current mode table + * Other - The index of the given parameters among the duplicate modes. + * 0 means that the mode param is the first mode encountered in the table + * 1 means that the mode param is the second mode encountered in the table + * etc... + */ +unsigned short getDuplicateModeIndex( + disp_control_t dispCtrl, + mode_parameter_t *pModeParam +); + +/* + * findModeParamFromTable + * This function locates the requested mode in the given parameter table + * + * Input: + * width - Mode width + * height - Mode height + * refresh_rate - Mode refresh rate + * index - Index that is used for multiple search of the same mode + * that have the same width, height, and refresh rate, + * but have different timing parameters. + * + * Output: + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *findModeParamFromTable( + unsigned long width, + unsigned long height, + unsigned long refresh_rate, + unsigned short index, + mode_parameter_t *pModeTable +); + +/* + * Locate in-stock parameter table for the requested mode. + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *findModeParam( + disp_control_t dispCtrl, + unsigned long width, + unsigned long height, + unsigned long refresh_rate, + unsigned short index +); + +/* + * (Obsolete) --> replace by findModeParam + * Locate in-stock parameter table for the requested mode. + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *findVesaModeParam( + unsigned long width, + unsigned long height, + unsigned long refresh_rate +); + +/* + * Return a point to the gModeParamTable. + * Function in other files used this to get the mode table pointer. + */ +mode_parameter_t *getStockModeParamTable(void); + +/* + * Return the size of the Stock Mode Param Table + */ +unsigned long getStockModeParamTableSize(void); + +/* + * getStockModeParamTableEx + * This function gets the mode parameters table associated to the + * display control (CHANNEL0_CTRL or SECONDAR_CTRL). + * + * Input: + * dispCtrl - Display Control of the mode table that is associated to. + * + * Output: + * Pointer to the mode table + */ +mode_parameter_t *getStockModeParamTableEx( + disp_control_t dispCtrl +); + +/* + * getStockModeParamTableSizeEx + * This function gets the size of the mode parameter table associated with + * specific display control + * + * Input: + * dispCtrl - Display control of the mode param table that is associated to. + * + * Output: + * Size of the requeted mode param table. + */ +unsigned long getStockModeParamTableSizeEx( + disp_control_t dispCtrl +); + +/* + * This function returns the current mode. + */ +mode_parameter_t getCurrentModeParam( + disp_control_t dispCtrl +); + +/* + * getMaximumModeEntries + * This function gets the maximum entries that can be stored in the mode table. + * + * Output: + * Total number of maximum entries + */ +unsigned long getMaximumModeEntries(void); + +/* + * Input: + * 1) pLogicalMode contains information such as x, y resolution and bpp. + * 2) A user defined parameter table for the mode. + * + * This function calculate and programs the hardware to set up the + * requested mode. + * + * This function allows the use of user defined parameter table if + * predefined Vesa parameter table (gModeParamTable) does not fit. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long setCustomMode( + logicalMode_t *pLogicalMode, + mode_parameter_t *pUserModeParam +); + +/* + * Input: + * 1) pLogicalMode contains information such as x, y resolution, bpp, xLCD, and yLCD. + * 2) A user defined parameter table for the mode. + * + * Similar like setCustomMode, this function calculate and programs the hardware + * to set up the requested mode and also scale the mode if necessary. + * + * This function allows the use of user defined parameter table if + * predefined Vesa parameter table (gModeParamTable) does not fit. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long setCustomModeEx( + logicalMode_t *pLogicalMode, + mode_parameter_t *pUserModeParam +); + +/* + * Input pLogicalMode contains information such as x, y resolution and bpp. + * Refer to MODE.h for the details. + * + * This function calculate and programs the hardware to set up the + * requested mode. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long setMode( + logicalMode_t *pLogicalMode +); + +/* + * Input pLogicalMode contains information such as x, y resolution, bpp, + * xLCD and yLCD. The main difference between setMode and setModeEx are + * the xLCD and yLCD parameters. Use this setModeEx API to set the mode + * and enable expansion. setMode API does not support expansion. + * + * This function calculate and programs the hardware to set up the + * requested mode. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long setModeEx( + logicalMode_t *pLogicalMode +); + + +/* + * setInterpolation + * This function enables/disables the horizontal and vertical interpolation + * for the secondary display control. Primary display control does not have + * this capability. + * + * Input: + * enableHorzInterpolation - Flag to enable/disable Horizontal interpolation + * enableVertInterpolation - Flag to enable/disable Vertical interpolation + */ +void setInterpolation( + unsigned long enableHorzInterpolation, + unsigned long enableVertInterpolation +); + +/*********************************************************************************** + * + * The following function prototypes are the extension of mode.c where it involves + * EDID, GTF, and others calculation. Please include modeext.c to use these + * functions. + * + ***********************************************************************************/ + +/* + * registerEdidTiming + * This function registers timing from EDID, LCD Monitor Timing Extension, + * Standard Timing Extension, etc... + * + * Input: + * dispCtrl - Display control where the mode will be associated to + * pEDIDBuffer - Pointer to the display device's EDID Buffer + * pLCDTimingExt - Pointer to LCD Monitor Timing Extension (currently is not supported) + * pStdTimingExt - Pointer to Standard Timing extension (currently is not supported) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long registerEdidTiming( + disp_control_t dispCtrl, + unsigned char *pEDIDBuffer, + unsigned char *pLCDTimingExt, + unsigned char *pStdTimingExt +); + +/* + * calculateGtfTiming + * This function calculate the GTF Timing and produce the SM750 mode parameter + * format + * + * Input: + * width - Mode Width + * height - Mode Height + * refreshRate - Mode Refresh Rate + * pModeParam - Pointer to SM750 mode parameter format variable to store + * the calculated value of the GTF + * + * Output: + * 0 - Success + * -1 - Fail + */ +long calculateDefaultGtfTiming( + unsigned long width, + unsigned long height, + unsigned long refreshRate, + mode_parameter_t *pModeParam +); + +/* + * calculateGtfTiming + * This function calculate the GTF Timing and produce the SM750 mode parameter + * format + * + * Input: + * width - Mode Width + * height - Mode Height + * refreshRate - Mode Refresh Rate + * pModeParam - Pointer to SM750 mode parameter format variable to store + * the calculated value of the GTF + * offset - The value of GTF Offset parameter + * gradient - The value of GTF Gradient parameter + * scalingFactor - The value of the GTF scaling factor parameter + * scalingFactorWeight - The value of the GTF scaling Factor Weight parameter + * + * Output: + * 0 - Success + * -1 - Fail + */ +long calculateGtfTiming( + unsigned long width, + unsigned long height, + unsigned long refreshRate, + mode_parameter_t *pModeParam, + unsigned char offset, + unsigned short gradient, + unsigned char scalingFactor, + unsigned char scalingFactorWeight + +); + +/* + * isDefaultGtfTiming + * Check if the given timing is default GTF timing. + * Default here means it uses the following configuration to calculate the timing: + * Offset (C) = 40% + * Gradient (M) = 600%/kHz + * Scaling Factor (K) = 128 + * Weighted Scaling Factor (J) = 20% + * + * Input: + * pModeParam - Mode Parameter that will be checked whether is default GTF or not + * + * Output: + * 0 - Indicates that the given mode parameter is a NOT a default GTF Timing + * Other - Indicates that the given mode parameter is a default GTF Timing + */ +long isDefaultGtfTiming( + mode_parameter_t *pModeParam +); + +/* + * isSecondaryGtfTiming + * Check if the given timing is the secondary GTF timing calculated based on the + * given offset (C), gradient (M), scaling factor (K), and weighted scaling factor (J). + * + * Input: + * pModeParam - Mode Parameter that will be checked whether is secondary GTF or not + * offset - Blanking formula offset used to calculate the secondary GTF mode param. + * gradient - Blanking formula gradient used to calculate the secondary GTF + * mode param. + * scalingFactor - Blanking formula scaling factor used to calculate the secondary + * GTF mode param + * scalingFactorWeight - Blanking formula scaling factor weighting used to calculate the + * secondary GTF mode param + * + * Output: + * 0 - Indicates that the given mode parameter is NOT a default GTF Timing + * Other - Indicates that the given mode parameter is a default GTF Timing + */ +long isSecondaryGtfTiming( + mode_parameter_t *pModeParam, + unsigned char offset, + unsigned short gradient, + unsigned char scalingFactor, + unsigned char scalingFactorWeight +); + +/* + * isVesaTiming + * Check if the given timing is the VESA Discrete Monitor Timing Standard. + * + * Input: + * pModeParam - Mode Parameter that will be checked whether is VESA Timing or not + * + * Output: + * 0 - Indicates that the given mode parameter is NOT a VESA DMT Timing + * Other - Indicates that the given mode parameter is a VESA DMT Timing + */ +long isVesaTiming( + mode_parameter_t *pModeParam +); + +/* + * isEdidPreferredTiming + * Check if the given timing is the EDID preferred timing. + * + * Input: + * pEDIDBuffer - Pointer to an EDID Buffer. + * pModeParam - Mode Parameter that will be checked whether is EDID + * preferred timing or not. + * + * Output: + * >0 - Indicates that the given mode parameter is a default GTF Timing + * 0 - Indicates that the given mode parameter is NOT a default GTF Timing + */ +long isEdidPreferredTiming( + unsigned char *pEDIDBuffer, + mode_parameter_t *pModeParam +); + +/* + * This function sets the display base address + * + * Input: + * dispControl - display control of which base address to be set. + * ulBaseAddress - Base Address value to be set. + */ +void setDisplayBaseAddress( + disp_control_t dispControl, + unsigned long ulBaseAddress +); + +/* + * This function gets the display status + * + * Input: + * dispControl - display control of which display status to be retrieved. + * + * Output: + * 0 - Display is pending + * -1 - Display is not pending + */ +long isCurrentDisplayPending( + disp_control_t dispControl +); + +#endif /* _MODE_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_power.c b/drivers/gpu/drm/smidrm/ddk750/ddk750_power.c new file mode 100644 index 000000000000..5f3317b216d7 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_power.c @@ -0,0 +1,495 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* power.c --- Voyager GX SDK +* This file contains the source code for the power functions. +* +*******************************************************************/ +#include "ddk750_defs.h" +#include "ddk750_chip.h" +#include "ddk750_clock.h" +#include "ddk750_hardware.h" +#include "ddk750_power.h" +#include "ddk750_help.h" + +//#include "ddkdebug.h" + +/* Semaphore Counter for Bus Master Enable Bit */ +unsigned long g_ulBusMasterSemaphoreCounter[MAX_SMI_DEVICE] = { 0, 0, 0, 0}; +unsigned long g_ulPCISlaveBurstWriteSemaphoreCounter[MAX_SMI_DEVICE] = { 0, 0, 0, 0}; +unsigned long g_ulPCISlaveBurstReadSemaphoreCounter[MAX_SMI_DEVICE] = { 0, 0, 0, 0}; + +/* Set DPMS state */ +void setDPMS(DPMS_t state) +{ + unsigned long value; + + //if(ddk750_getChipType() == SM750LE) + if(ddk750_getChipType() >= SM750LE) + { + value = peekRegisterDWord(SECONDARY_DISPLAY_CTRL); + switch (state) + { + case DPMS_ON: + value = FIELD_SET(value, SECONDARY_DISPLAY_CTRL, DPMS, 0); + break; + + case DPMS_STANDBY: + value = FIELD_SET(value, SECONDARY_DISPLAY_CTRL, DPMS, 1); + break; + + case DPMS_SUSPEND: + value = FIELD_SET(value, SECONDARY_DISPLAY_CTRL, DPMS, 2); + break; + + case DPMS_OFF: + value = FIELD_SET(value, SECONDARY_DISPLAY_CTRL, DPMS, 3); + break; + } + + pokeRegisterDWord(SECONDARY_DISPLAY_CTRL, value); + return; + } + + value = peekRegisterDWord(SYSTEM_CTRL); + switch (state) + { + case DPMS_ON: + value = FIELD_SET(value, SYSTEM_CTRL, DPMS, VPHP); + break; + + case DPMS_STANDBY: + value = FIELD_SET(value, SYSTEM_CTRL, DPMS, VPHN); + break; + + case DPMS_SUSPEND: + value = FIELD_SET(value, SYSTEM_CTRL, DPMS, VNHP); + break; + + case DPMS_OFF: + value = FIELD_SET(value, SYSTEM_CTRL, DPMS, VNHN); + break; + } + + pokeRegisterDWord(SYSTEM_CTRL, value); +} + +/* + * This function gets the power mode, one of three modes: 0, 1 or Sleep. + * On hardware reset, power mode 0 is default. + */ +unsigned long getPowerMode() +{ + + return (FIELD_GET(peekRegisterDWord(POWER_MODE_CTRL), POWER_MODE_CTRL, MODE)); +} + +/* + * SM750/SM718 can operate in one of three modes: 0, 1 or Sleep. + * On hardware reset, power mode 0 is default. + */ +void setPowerMode(unsigned long powerMode) +{ + unsigned long control_value = 0, previousPowerState; + + /* Get the current power mode ctrl register value and save it + before switching the power mode. */ + control_value = peekRegisterDWord(POWER_MODE_CTRL); + previousPowerState = FIELD_GET(control_value, POWER_MODE_CTRL, MODE); + + /* Set the power mode to the requested power mode. */ + switch (powerMode) + { + case 0: + control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, MODE0); + break; + + case 1: + control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, MODE1); + break; + + case 2: + control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, SLEEP); + break; + + default: + break; + } + +#if 0 /* These routines are removed since turning off the oscillator during sleep + will require the software to reset the frame buffer memory. + */ + /* Set up other fields in Power Control Register */ + if (powerMode == POWER_MODE_CTRL_MODE_SLEEP) + control_value = FIELD_SET(control_value, POWER_MODE_CTRL, OSC_INPUT, OFF); + else + control_value = FIELD_SET(control_value, POWER_MODE_CTRL, OSC_INPUT, ON); +#endif + + /* Program new power mode. */ + pokeRegisterDWord(POWER_MODE_CTRL, control_value); + + /* In SM718, the chip needs to wait until wake up from the sleep mode and wait for + a few milliseconds before reseting the memory and resume the normal operation. */ + if ((powerMode != 2) && (previousPowerState != FIELD_GET(control_value, POWER_MODE_CTRL, MODE))) + { + /* Switching power mode between power mode 0 and 1 */ + + /* Need a minimum of 16ms between power mode switching */ + waitMasterClock(16); + + /* Reset Memory. */ + ddk750_resetFrameBufferMemory(); + } +} + +void setCurrentGate(unsigned long gate) +{ + unsigned long gate_reg; + unsigned long mode; + + /* Get current power mode. */ + mode = getPowerMode(); + + switch (mode) + { + case POWER_MODE_CTRL_MODE_MODE0: + gate_reg = MODE0_GATE; + break; + + case POWER_MODE_CTRL_MODE_MODE1: + gate_reg = MODE1_GATE; + break; + + default: + gate_reg = MODE0_GATE; + break; + } + pokeRegisterDWord(gate_reg, gate); +} + +/* + * This function enable/disable Bus Master + */ +void enableBusMaster(unsigned long enable) +{ + unsigned long busMasterCounter, value; + + /* Enable Bus Master as necessary.*/ + busMasterCounter = g_ulBusMasterSemaphoreCounter[getCurrentDevice()]; + value = peekRegisterDWord(SYSTEM_CTRL); + + /* Currently, only SM718 needs to enable the Bus Master enable bit. + The Bus Master in SM750 is enabled by default, without programming any bits. */ + if (enable) + { + if ((ddk750_getChipType() == SM718) && (busMasterCounter == 0)) + pokeRegisterDWord(SYSTEM_CTRL, FIELD_SET(peekRegisterDWord(SYSTEM_CTRL), SYSTEM_CTRL, PCI_MASTER, ON)); + + busMasterCounter++; + } + else + { + if (busMasterCounter > 0) + busMasterCounter--; + + if ((ddk750_getChipType() == SM718) && (busMasterCounter == 0)) + pokeRegisterDWord(SYSTEM_CTRL, FIELD_SET(peekRegisterDWord(SYSTEM_CTRL), SYSTEM_CTRL, PCI_MASTER, OFF)); + } + + g_ulBusMasterSemaphoreCounter[getCurrentDevice()] = busMasterCounter; +} + +/* + * setPCIMasterBaseAddress + * This function set the PCI Master Base Address (used by bus master or DMA). + * + * Input: + * physicalSystemMemAddress - System physical memory address which PCI + * Master Base Address to be set to. + * + * Output: + * The memory address to be set in the register. + */ +unsigned long setPCIMasterBaseAddress( + unsigned long physicalSystemMemAddress +) +{ + unsigned long pciMasterBaseAddress, remainingAddress; + + /* Set PCI Master Base Address */ + if (ddk750_getChipType() == SM750) + { +#ifdef SM750_AA + pciMasterBaseAddress = ((physicalSystemMemAddress & 0xFFF00000) >> 23) << 3; + pokeRegisterDWord(PCI_MASTER_BASE, FIELD_VALUE(0, PCI_MASTER_BASE, ADDRESS, pciMasterBaseAddress)); + + /* This errata only applies to System Memory. For local to local, no correction is + needed. */ + remainingAddress = ((physicalSystemMemAddress & 0x00700000) << 3) + (physicalSystemMemAddress & 0x000FFFFF); +#else + pciMasterBaseAddress = physicalSystemMemAddress >> 23; + pciMasterBaseAddress = (pciMasterBaseAddress > 0xFF) ? 0xFF : pciMasterBaseAddress; + pokeRegisterDWord(PCI_MASTER_BASE, FIELD_VALUE(0, PCI_MASTER_BASE, ADDRESS, pciMasterBaseAddress)); + remainingAddress = physicalSystemMemAddress - (pciMasterBaseAddress << 23); +#endif + } + else + { + pciMasterBaseAddress = physicalSystemMemAddress & 0xFFF00000; + pokeRegisterDWord(SM718_PCI_MASTER_BASE, FIELD_VALUE(0, SM718_PCI_MASTER_BASE, ADDRESS, pciMasterBaseAddress)); + remainingAddress = physicalSystemMemAddress - pciMasterBaseAddress; + } + + //DDKDEBUGPRINT((DMA_LEVEL, "pciMasterBaseAddress: %x\n", pciMasterBaseAddress)); + + /* Send back the remaining address */ + return remainingAddress; +} + +/* + * This function enable/disable PCI Slave Burst Write provided the CPU supports Write Combine. + * + * Input: + * enable - Enable/Disable the PCI Slave Burst Write (0 = disable, 1 = enable) + */ +void enablePCISlaveBurstWrite( + unsigned long enable +) +{ + unsigned long pciSlaveBurstWriteCounter, value; + + /* Enable PCI Slave Burst Write */ + pciSlaveBurstWriteCounter = g_ulPCISlaveBurstWriteSemaphoreCounter[getCurrentDevice()]; + value = peekRegisterDWord(SYSTEM_CTRL); + + if (enable != 0) + { + if ((ddk750_getChipType() == SM718) && (pciSlaveBurstWriteCounter == 0)) + { + /* Enable PCI Slave Burst Write. */ + value = FIELD_SET(peekRegisterDWord(SYSTEM_CTRL), SYSTEM_CTRL, PCI_BURST, ON); + pokeRegisterDWord(SYSTEM_CTRL, value); + } + + pciSlaveBurstWriteCounter++; + } + else + { + if (pciSlaveBurstWriteCounter > 0) + pciSlaveBurstWriteCounter--; + + if ((ddk750_getChipType() == SM718) && (pciSlaveBurstWriteCounter == 0)) + { + /* Disable PCI Slave Burst Write */ + value = FIELD_SET(peekRegisterDWord(SYSTEM_CTRL), SYSTEM_CTRL, PCI_BURST, OFF); + pokeRegisterDWord(SYSTEM_CTRL, value); + } + } + + g_ulPCISlaveBurstWriteSemaphoreCounter[getCurrentDevice()] = pciSlaveBurstWriteCounter; +} + +/* + * This function enable/disable PCI Slave Burst Read provided the CPU supports it. + * + * Input: + * enable - Enable/Disable the PCI Slave Burst Read (0 = disable, 1 = enable) + * burstReadSize - Burst Read Size in 32-words (valid values are 1, 2, 4, and 8) + */ +void enablePCISlaveBurstRead( + unsigned long enable, + unsigned long burstReadSize +) +{ + unsigned long pciSlaveBurstReadCounter, value; + + /* Currently, only SM718 needs to enable the Bus Master enable bit. + The Bus Master in SM750 is enabled by default, without programming any bits. */ + pciSlaveBurstReadCounter = g_ulPCISlaveBurstReadSemaphoreCounter[getCurrentDevice()]; + value = peekRegisterDWord(SYSTEM_CTRL); + + if (enable != 0) + { + if ((ddk750_getChipType() == SM718) && (pciSlaveBurstReadCounter == 0)) + { + value = peekRegisterDWord(SYSTEM_CTRL); + + /* Enable PCI Slave Burst Read. */ + value = FIELD_SET(value, SYSTEM_CTRL, PCI_BURST_READ, ON); + + /* Set the Read Size */ + switch(burstReadSize) + { + case 1: + value = FIELD_SET(value, SYSTEM_CTRL, PCI_SLAVE_BURST_READ_SIZE, 1); + break; + case 2: + value = FIELD_SET(value, SYSTEM_CTRL, PCI_SLAVE_BURST_READ_SIZE, 2); + break; + case 4: + value = FIELD_SET(value, SYSTEM_CTRL, PCI_SLAVE_BURST_READ_SIZE, 4); + break; + default: + case 8: + value = FIELD_SET(value, SYSTEM_CTRL, PCI_SLAVE_BURST_READ_SIZE, 8); + break; + } + pokeRegisterDWord(SYSTEM_CTRL, value); + } + + pciSlaveBurstReadCounter++; + } + else + { + if (pciSlaveBurstReadCounter > 0) + pciSlaveBurstReadCounter--; + + if ((ddk750_getChipType() == SM718) && (pciSlaveBurstReadCounter == 0)) + { + /* Disable PCI Slave Burst */ + value = FIELD_SET(peekRegisterDWord(SYSTEM_CTRL), SYSTEM_CTRL, PCI_BURST_READ, OFF); + pokeRegisterDWord(SYSTEM_CTRL, value); + } + } + + g_ulPCISlaveBurstReadSemaphoreCounter[getCurrentDevice()] = pciSlaveBurstReadCounter; +} + +/* + * This function enable/disable the 2D engine. + */ +void enable2DEngine(unsigned long enable) +{ + unsigned long gate; + + gate = peekRegisterDWord(CURRENT_GATE); + if (enable) + { + gate = FIELD_SET(gate, CURRENT_GATE, DE, ON); + gate = FIELD_SET(gate, CURRENT_GATE, CSC, ON); + } + else + { + gate = FIELD_SET(gate, CURRENT_GATE, DE, OFF); + gate = FIELD_SET(gate, CURRENT_GATE, CSC, OFF); + } + + setCurrentGate(gate); +} + +/* + * This function enable/disable the ZV Port. + */ +void enableZVPort(unsigned long enable) +{ + unsigned long gate; + + /* Enable ZV Port Gate */ + gate = peekRegisterDWord(CURRENT_GATE); + if (enable) + { + gate = FIELD_SET(gate, CURRENT_GATE, ZVPORT, ON); +#if 1 + /* Using Software I2C */ + gate = FIELD_SET(gate, CURRENT_GATE, GPIO, ON); +#endif + } + else + { + /* Disable ZV Port Gate. There is no way to know whether the GPIO pins are being used + or not. Therefore, do not disable the GPIO gate. */ + gate = FIELD_SET(gate, CURRENT_GATE, ZVPORT, OFF); + } + + setCurrentGate(gate); +} + +/* + * This function enable/disable the SSP. + */ +void enableSSP(unsigned long enable) +{ + unsigned long gate; + + /* Enable SSP Gate */ + gate = peekRegisterDWord(CURRENT_GATE); + if (enable) + gate = FIELD_SET(gate, CURRENT_GATE, SSP, ON); + else + gate = FIELD_SET(gate, CURRENT_GATE, SSP, OFF); + + setCurrentGate(gate); +} + +/* + * This function enable/disable the DMA Engine + */ +void enableDMA(unsigned long enable) +{ + unsigned long gate; + + /* Enable DMA Gate */ + gate = peekRegisterDWord(CURRENT_GATE); + if (enable) + gate = FIELD_SET(gate, CURRENT_GATE, DMA, ON); + else + gate = FIELD_SET(gate, CURRENT_GATE, DMA, OFF); + + setCurrentGate(gate); +} + +/* + * This function enable/disable the GPIO Engine + */ +void enableGPIO(unsigned long enable) +{ + unsigned long gate; + + /* Enable GPIO Gate */ + gate = peekRegisterDWord(CURRENT_GATE); + if (enable) + gate = FIELD_SET(gate, CURRENT_GATE, GPIO, ON); + else + gate = FIELD_SET(gate, CURRENT_GATE, GPIO, OFF); + + setCurrentGate(gate); +} + +/* + * This function enable/disable the PWM Engine + */ +void enablePWM(unsigned long enable) +{ + unsigned long gate; + + /* Enable PWM Gate */ + gate = peekRegisterDWord(CURRENT_GATE); + if (enable) + gate = FIELD_SET(gate, CURRENT_GATE, PWM, ON); + else + gate = FIELD_SET(gate, CURRENT_GATE, PWM, OFF); + + setCurrentGate(gate); +} + +/* + * This function enable/disable the I2C Engine + */ +void enableI2C(unsigned long enable) +{ + unsigned long gate; + + /* Enable I2C Gate */ + gate = peekRegisterDWord(CURRENT_GATE); + if (enable) + gate = FIELD_SET(gate, CURRENT_GATE, I2C, ON); + else + gate = FIELD_SET(gate, CURRENT_GATE, I2C, OFF); + + setCurrentGate(gate); +} diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_power.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_power.h new file mode 100644 index 000000000000..9f8c4e41d446 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_power.h @@ -0,0 +1,121 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* power.h --- Voyager GX SDK +* This file contains the definitions for the power functions. +* +*******************************************************************/ +#ifndef _POWER_H_ +#define _POWER_H_ +#include "../hw_com.h" +// typedef enum _DPMS_t +// { +// DPMS_ON, +// DPMS_STANDBY, +// DPMS_SUSPEND, +// DPMS_OFF +// } +// DPMS_t; + +/* + * This function sets the DPMS state + */ +void setDPMS(DPMS_t state); + +/* + * This function gets the current power mode + */ +unsigned long getPowerMode(void); + +/* + * This function sets the current power mode + */ +void setPowerMode(unsigned long powerMode); + +/* + * This function sets current gate + */ +void setCurrentGate(unsigned long gate); + +/* + * This function enable/disable Bus Master + */ +void enableBusMaster(unsigned long enable); + +/* + * setPCIMasterBaseAddress + * This function set the PCI Master Base Address (used by bus master or DMA). + * + * Input: + * physicalSystemMemAddress - System physical memory address which PCI + * Master Base Address to be set to. + * + * Output: + * The memory address to be set in the register. + */ +unsigned long setPCIMasterBaseAddress( + unsigned long physicalSystemMemAddress +); + +/* + * This function enable/disable PCI Slave Burst Write provided the CPU supports Write Combine. + * + * Input: + * enable - Enable/Disable the PCI Slave Burst Write (0 = disable, 1 = enable) + */ +void enablePCISlaveBurstWrite( + unsigned long enable +); + +/* + * This function enable/disable PCI Slave Burst Read provided the CPU supports it. + * + * Input: + * enable - Enable/Disable the PCI Slave Burst Read (0 = disable, 1 = enable) + * burstReadSize - Burst Read Size in 32-words (valid values are 1, 2, 4, and 8) + */ +void enablePCISlaveBurstRead( + unsigned long enable, + unsigned long burstReadSize +); + +/* + * This function enable/disable the 2D engine. + */ +void enable2DEngine(unsigned long enable); + +/* + * This function enable/disable the ZV Port + */ +void enableZVPort(unsigned long enable); + +/* + * This function enable/disable the DMA Engine + */ +void enableDMA(unsigned long enable); + +/* + * This function enable/disable the GPIO Engine + */ +void enableGPIO(unsigned long enable); + +/* + * This function enable/disable the PWM Engine + */ +void enablePWM(unsigned long enable); + +/* + * This function enable/disable the I2C Engine + */ +void enableI2C(unsigned long enable); + +/* + * This function enable/disable the SSP. + */ +void enableSSP(unsigned long enable); + +#endif /* _POWER_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_regdc.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_regdc.h new file mode 100644 index 000000000000..07cc3e01a316 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_regdc.h @@ -0,0 +1,960 @@ +/******************************************************************* +* +* Copyright (c) 2008 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* RegDC.h --- SMI DDK +* This file contains the definitions for the Display Controller registers. +* +*******************************************************************/ + +/* Primary Graphics Control */ + +#define PRIMARY_DISPLAY_CTRL 0x080000 +#define PRIMARY_DISPLAY_CTRL_RESERVED_1_MASK 31:30 +#define PRIMARY_DISPLAY_CTRL_RESERVED_1_MASK_DISABLE 0 +#define PRIMARY_DISPLAY_CTRL_RESERVED_1_MASK_ENABLE 3 +#define PRIMARY_DISPLAY_CTRL_SELECT 29:28 +#define PRIMARY_DISPLAY_CTRL_SELECT_PRIMARY 0 +#define PRIMARY_DISPLAY_CTRL_SELECT_VGA 1 +#define PRIMARY_DISPLAY_CTRL_SELECT_SECONDARY 2 +#define PRIMARY_DISPLAY_CTRL_FPEN 27:27 +#define PRIMARY_DISPLAY_CTRL_FPEN_LOW 0 +#define PRIMARY_DISPLAY_CTRL_FPEN_HIGH 1 +#define PRIMARY_DISPLAY_CTRL_VBIASEN 26:26 +#define PRIMARY_DISPLAY_CTRL_VBIASEN_LOW 0 +#define PRIMARY_DISPLAY_CTRL_VBIASEN_HIGH 1 +#define PRIMARY_DISPLAY_CTRL_DATA 25:25 +#define PRIMARY_DISPLAY_CTRL_DATA_DISABLE 0 +#define PRIMARY_DISPLAY_CTRL_DATA_ENABLE 1 +#define PRIMARY_DISPLAY_CTRL_FPVDDEN 24:24 +#define PRIMARY_DISPLAY_CTRL_FPVDDEN_LOW 0 +#define PRIMARY_DISPLAY_CTRL_FPVDDEN_HIGH 1 +#define PRIMARY_DISPLAY_CTRL_RESERVED_2_MASK 23:20 +#define PRIMARY_DISPLAY_CTRL_RESERVED_2_MASK_DISABLE 0 +#define PRIMARY_DISPLAY_CTRL_RESERVED_2_MASK_ENABLE 15 +#define PRIMARY_DISPLAY_CTRL_DUAL_DISPLAY 19:19 +#define PRIMARY_DISPLAY_CTRL_DUAL_DISPLAY_DISABLE 0 +#define PRIMARY_DISPLAY_CTRL_DUAL_DISPLAY_ENABLE 1 +#define PRIMARY_DISPLAY_CTRL_DOUBLE_PIXEL 18:18 +#define PRIMARY_DISPLAY_CTRL_DOUBLE_PIXEL_DISABLE 0 +#define PRIMARY_DISPLAY_CTRL_DOUBLE_PIXEL_ENABLE 1 +#define PRIMARY_DISPLAY_CTRL_FIFO 17:16 +#define PRIMARY_DISPLAY_CTRL_FIFO_1 0 +#define PRIMARY_DISPLAY_CTRL_FIFO_3 1 +#define PRIMARY_DISPLAY_CTRL_FIFO_7 2 +#define PRIMARY_DISPLAY_CTRL_FIFO_11 3 +#define PRIMARY_DISPLAY_CTRL_RESERVED_3_MASK 15:15 +#define PRIMARY_DISPLAY_CTRL_RESERVED_3_MASK_DISABLE 0 +#define PRIMARY_DISPLAY_CTRL_RESERVED_3_MASK_ENABLE 1 +#define PRIMARY_DISPLAY_CTRL_CLOCK_PHASE 14:14 +#define PRIMARY_DISPLAY_CTRL_CLOCK_PHASE_ACTIVE_HIGH 0 +#define PRIMARY_DISPLAY_CTRL_CLOCK_PHASE_ACTIVE_LOW 1 +#define PRIMARY_DISPLAY_CTRL_VSYNC_PHASE 13:13 +#define PRIMARY_DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_HIGH 0 +#define PRIMARY_DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_LOW 1 +#define PRIMARY_DISPLAY_CTRL_HSYNC_PHASE 12:12 +#define PRIMARY_DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_HIGH 0 +#define PRIMARY_DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_LOW 1 +#define PRIMARY_DISPLAY_CTRL_VSYNC 11:11 +#define PRIMARY_DISPLAY_CTRL_VSYNC_ACTIVE_HIGH 0 +#define PRIMARY_DISPLAY_CTRL_VSYNC_ACTIVE_LOW 1 +#define PRIMARY_DISPLAY_CTRL_CAPTURE_TIMING 10:10 +#define PRIMARY_DISPLAY_CTRL_CAPTURE_TIMING_DISABLE 0 +#define PRIMARY_DISPLAY_CTRL_CAPTURE_TIMING_ENABLE 1 +#define PRIMARY_DISPLAY_CTRL_COLOR_KEY 9:9 +#define PRIMARY_DISPLAY_CTRL_COLOR_KEY_DISABLE 0 +#define PRIMARY_DISPLAY_CTRL_COLOR_KEY_ENABLE 1 +#define PRIMARY_DISPLAY_CTRL_TIMING 8:8 +#define PRIMARY_DISPLAY_CTRL_TIMING_DISABLE 0 +#define PRIMARY_DISPLAY_CTRL_TIMING_ENABLE 1 +#define PRIMARY_DISPLAY_CTRL_VERTICAL_PAN_DIR 7:7 +#define PRIMARY_DISPLAY_CTRL_VERTICAL_PAN_DIR_DOWN 0 +#define PRIMARY_DISPLAY_CTRL_VERTICAL_PAN_DIR_UP 1 +#define PRIMARY_DISPLAY_CTRL_VERTICAL_PAN 6:6 +#define PRIMARY_DISPLAY_CTRL_VERTICAL_PAN_DISABLE 0 +#define PRIMARY_DISPLAY_CTRL_VERTICAL_PAN_ENABLE 1 +#define PRIMARY_DISPLAY_CTRL_HORIZONTAL_PAN_DIR 5:5 +#define PRIMARY_DISPLAY_CTRL_HORIZONTAL_PAN_DIR_RIGHT 0 +#define PRIMARY_DISPLAY_CTRL_HORIZONTAL_PAN_DIR_LEFT 1 +#define PRIMARY_DISPLAY_CTRL_HORIZONTAL_PAN 4:4 +#define PRIMARY_DISPLAY_CTRL_HORIZONTAL_PAN_DISABLE 0 +#define PRIMARY_DISPLAY_CTRL_HORIZONTAL_PAN_ENABLE 1 +#define PRIMARY_DISPLAY_CTRL_GAMMA 3:3 +#define PRIMARY_DISPLAY_CTRL_GAMMA_DISABLE 0 +#define PRIMARY_DISPLAY_CTRL_GAMMA_ENABLE 1 +#define PRIMARY_DISPLAY_CTRL_PLANE 2:2 +#define PRIMARY_DISPLAY_CTRL_PLANE_DISABLE 0 +#define PRIMARY_DISPLAY_CTRL_PLANE_ENABLE 1 +#define PRIMARY_DISPLAY_CTRL_FORMAT 1:0 +#define PRIMARY_DISPLAY_CTRL_FORMAT_8 0 +#define PRIMARY_DISPLAY_CTRL_FORMAT_16 1 +#define PRIMARY_DISPLAY_CTRL_FORMAT_32 2 + +#define PRIMARY_PAN_CTRL 0x080004 +#define PRIMARY_PAN_CTRL_VERTICAL_PAN 31:24 +#define PRIMARY_PAN_CTRL_VERTICAL_VSYNC 21:16 +#define PRIMARY_PAN_CTRL_HORIZONTAL_PAN 15:8 +#define PRIMARY_PAN_CTRL_HORIZONTAL_VSYNC 5:0 + +#define PRIMARY_COLOR_KEY 0x080008 +#define PRIMARY_COLOR_KEY_MASK 31:16 +#define PRIMARY_COLOR_KEY_VALUE 15:0 + +#define PRIMARY_FB_ADDRESS 0x08000C +#define PRIMARY_FB_ADDRESS_STATUS 31:31 +#define PRIMARY_FB_ADDRESS_STATUS_CURRENT 0 +#define PRIMARY_FB_ADDRESS_STATUS_PENDING 1 +#define PRIMARY_FB_ADDRESS_EXT 27:27 +#define PRIMARY_FB_ADDRESS_EXT_LOCAL 0 +#define PRIMARY_FB_ADDRESS_EXT_EXTERNAL 1 +#define PRIMARY_FB_ADDRESS_ADDRESS 25:0 + +#define PRIMARY_FB_WIDTH 0x080010 +#define PRIMARY_FB_WIDTH_WIDTH 29:16 +#define PRIMARY_FB_WIDTH_OFFSET 13:0 + +#define PRIMARY_WINDOW_WIDTH 0x080014 +#define PRIMARY_WINDOW_WIDTH_WIDTH 27:16 +#define PRIMARY_WINDOW_WIDTH_X 11:0 + +#define PRIMARY_WINDOW_HEIGHT 0x080018 +#define PRIMARY_WINDOW_HEIGHT_HEIGHT 27:16 +#define PRIMARY_WINDOW_HEIGHT_Y 11:0 + +#define PRIMARY_PLANE_TL 0x08001C +#define PRIMARY_PLANE_TL_TOP 26:16 +#define PRIMARY_PLANE_TL_LEFT 10:0 + +#define PRIMARY_PLANE_BR 0x080020 +#define PRIMARY_PLANE_BR_BOTTOM 26:16 +#define PRIMARY_PLANE_BR_RIGHT 10:0 + +#define PRIMARY_HORIZONTAL_TOTAL 0x080024 +#define PRIMARY_HORIZONTAL_TOTAL_TOTAL 27:16 +#define PRIMARY_HORIZONTAL_TOTAL_DISPLAY_END 11:0 + +#define PRIMARY_HORIZONTAL_SYNC 0x080028 +#define PRIMARY_HORIZONTAL_SYNC_WIDTH 23:16 +#define PRIMARY_HORIZONTAL_SYNC_START 11:0 + +#define PRIMARY_VERTICAL_TOTAL 0x08002C +#define PRIMARY_VERTICAL_TOTAL_TOTAL 26:16 +#define PRIMARY_VERTICAL_TOTAL_DISPLAY_END 10:0 + +#define PRIMARY_VERTICAL_SYNC 0x080030 +#define PRIMARY_VERTICAL_SYNC_HEIGHT 21:16 +#define PRIMARY_VERTICAL_SYNC_START 10:0 + +#define PRIMARY_CURRENT_LINE 0x080034 +#define PRIMARY_CURRENT_LINE_LINE 10:0 + +/* Video Control */ + +#define VIDEO_DISPLAY_CTRL 0x080040 +#define VIDEO_DISPLAY_CTRL_LINE_BUFFER 18:18 +#define VIDEO_DISPLAY_CTRL_LINE_BUFFER_DISABLE 0 +#define VIDEO_DISPLAY_CTRL_LINE_BUFFER_ENABLE 1 +#define VIDEO_DISPLAY_CTRL_FIFO 17:16 +#define VIDEO_DISPLAY_CTRL_FIFO_1 0 +#define VIDEO_DISPLAY_CTRL_FIFO_3 1 +#define VIDEO_DISPLAY_CTRL_FIFO_7 2 +#define VIDEO_DISPLAY_CTRL_FIFO_11 3 +#define VIDEO_DISPLAY_CTRL_BUFFER 15:15 +#define VIDEO_DISPLAY_CTRL_BUFFER_0 0 +#define VIDEO_DISPLAY_CTRL_BUFFER_1 1 +#define VIDEO_DISPLAY_CTRL_CAPTURE 14:14 +#define VIDEO_DISPLAY_CTRL_CAPTURE_DISABLE 0 +#define VIDEO_DISPLAY_CTRL_CAPTURE_ENABLE 1 +#define VIDEO_DISPLAY_CTRL_DOUBLE_BUFFER 13:13 +#define VIDEO_DISPLAY_CTRL_DOUBLE_BUFFER_DISABLE 0 +#define VIDEO_DISPLAY_CTRL_DOUBLE_BUFFER_ENABLE 1 +#define VIDEO_DISPLAY_CTRL_BYTE_SWAP 12:12 +#define VIDEO_DISPLAY_CTRL_BYTE_SWAP_DISABLE 0 +#define VIDEO_DISPLAY_CTRL_BYTE_SWAP_ENABLE 1 +#define VIDEO_DISPLAY_CTRL_VERTICAL_SCALE 11:11 +#define VIDEO_DISPLAY_CTRL_VERTICAL_SCALE_NORMAL 0 +#define VIDEO_DISPLAY_CTRL_VERTICAL_SCALE_HALF 1 +#define VIDEO_DISPLAY_CTRL_HORIZONTAL_SCALE 10:10 +#define VIDEO_DISPLAY_CTRL_HORIZONTAL_SCALE_NORMAL 0 +#define VIDEO_DISPLAY_CTRL_HORIZONTAL_SCALE_HALF 1 +#define VIDEO_DISPLAY_CTRL_VERTICAL_MODE 9:9 +#define VIDEO_DISPLAY_CTRL_VERTICAL_MODE_REPLICATE 0 +#define VIDEO_DISPLAY_CTRL_VERTICAL_MODE_INTERPOLATE 1 +#define VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE 8:8 +#define VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE_REPLICATE 0 +#define VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE_INTERPOLATE 1 +#define VIDEO_DISPLAY_CTRL_PIXEL 7:4 +#define VIDEO_DISPLAY_CTRL_GAMMA 3:3 +#define VIDEO_DISPLAY_CTRL_GAMMA_DISABLE 0 +#define VIDEO_DISPLAY_CTRL_GAMMA_ENABLE 1 +#define VIDEO_DISPLAY_CTRL_PLANE 2:2 +#define VIDEO_DISPLAY_CTRL_PLANE_DISABLE 0 +#define VIDEO_DISPLAY_CTRL_PLANE_ENABLE 1 +#define VIDEO_DISPLAY_CTRL_FORMAT 1:0 +#define VIDEO_DISPLAY_CTRL_FORMAT_8 0 +#define VIDEO_DISPLAY_CTRL_FORMAT_16 1 +#define VIDEO_DISPLAY_CTRL_FORMAT_32 2 +#define VIDEO_DISPLAY_CTRL_FORMAT_YUV 3 + +#define VIDEO_FB_0_ADDRESS 0x080044 +#define VIDEO_FB_0_ADDRESS_STATUS 31:31 +#define VIDEO_FB_0_ADDRESS_STATUS_CURRENT 0 +#define VIDEO_FB_0_ADDRESS_STATUS_PENDING 1 +#define VIDEO_FB_0_ADDRESS_EXT 27:27 +#define VIDEO_FB_0_ADDRESS_EXT_LOCAL 0 +#define VIDEO_FB_0_ADDRESS_EXT_EXTERNAL 1 +#define VIDEO_FB_0_ADDRESS_ADDRESS 25:0 + +#define VIDEO_FB_WIDTH 0x080048 +#define VIDEO_FB_WIDTH_WIDTH 29:16 +#define VIDEO_FB_WIDTH_OFFSET 13:0 + +#define VIDEO_FB_0_LAST_ADDRESS 0x08004C +#define VIDEO_FB_0_LAST_ADDRESS_EXT 27:27 +#define VIDEO_FB_0_LAST_ADDRESS_EXT_LOCAL 0 +#define VIDEO_FB_0_LAST_ADDRESS_EXT_EXTERNAL 1 +#define VIDEO_FB_0_LAST_ADDRESS_ADDRESS 25:0 + +#define VIDEO_PLANE_TL 0x080050 +#define VIDEO_PLANE_TL_TOP 26:16 +#define VIDEO_PLANE_TL_LEFT 10:0 + +#define VIDEO_PLANE_BR 0x080054 +#define VIDEO_PLANE_BR_BOTTOM 26:16 +#define VIDEO_PLANE_BR_RIGHT 10:0 + +#define VIDEO_SCALE 0x080058 +#define VIDEO_SCALE_VERTICAL_MODE 31:31 +#define VIDEO_SCALE_VERTICAL_MODE_EXPAND 0 +#define VIDEO_SCALE_VERTICAL_MODE_SHRINK 1 +#define VIDEO_SCALE_VERTICAL_SCALE 27:16 +#define VIDEO_SCALE_HORIZONTAL_MODE 15:15 +#define VIDEO_SCALE_HORIZONTAL_MODE_EXPAND 0 +#define VIDEO_SCALE_HORIZONTAL_MODE_SHRINK 1 +#define VIDEO_SCALE_HORIZONTAL_SCALE 11:0 + +#define VIDEO_INITIAL_SCALE 0x08005C +#define VIDEO_INITIAL_SCALE_FB_1 27:16 +#define VIDEO_INITIAL_SCALE_FB_0 11:0 + +#define VIDEO_YUV_CONSTANTS 0x080060 +#define VIDEO_YUV_CONSTANTS_Y 31:24 +#define VIDEO_YUV_CONSTANTS_R 23:16 +#define VIDEO_YUV_CONSTANTS_G 15:8 +#define VIDEO_YUV_CONSTANTS_B 7:0 + +#define VIDEO_FB_1_ADDRESS 0x080064 +#define VIDEO_FB_1_ADDRESS_STATUS 31:31 +#define VIDEO_FB_1_ADDRESS_STATUS_CURRENT 0 +#define VIDEO_FB_1_ADDRESS_STATUS_PENDING 1 +#define VIDEO_FB_1_ADDRESS_EXT 27:27 +#define VIDEO_FB_1_ADDRESS_EXT_LOCAL 0 +#define VIDEO_FB_1_ADDRESS_EXT_EXTERNAL 1 +#define VIDEO_FB_1_ADDRESS_ADDRESS 25:0 + +#define VIDEO_FB_1_LAST_ADDRESS 0x080068 +#define VIDEO_FB_1_LAST_ADDRESS_EXT 27:27 +#define VIDEO_FB_1_LAST_ADDRESS_EXT_LOCAL 0 +#define VIDEO_FB_1_LAST_ADDRESS_EXT_EXTERNAL 1 +#define VIDEO_FB_1_LAST_ADDRESS_ADDRESS 25:0 + +#define VIDEO_EDGE_DETECTION 0x080074 +#define VIDEO_EDGE_DETECTION_DETECT 24:24 +#define VIDEO_EDGE_DETECTION_DETECT_DISABLE 0 +#define VIDEO_EDGE_DETECTION_DETECT_ENABLE 1 +#define VIDEO_EDGE_DETECTION_VALUE 9:0 + +/* Video Alpha Control */ + +#define VIDEO_ALPHA_DISPLAY_CTRL 0x080080 +#define VIDEO_ALPHA_DISPLAY_CTRL_SELECT 28:28 +#define VIDEO_ALPHA_DISPLAY_CTRL_SELECT_PER_PIXEL 0 +#define VIDEO_ALPHA_DISPLAY_CTRL_SELECT_ALPHA 1 +#define VIDEO_ALPHA_DISPLAY_CTRL_ALPHA 27:24 +#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO 17:16 +#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_1 0 +#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_3 1 +#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_7 2 +#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_11 3 +#define VIDEO_ALPHA_DISPLAY_CTRL_VERT_SCALE 11:11 +#define VIDEO_ALPHA_DISPLAY_CTRL_VERT_SCALE_NORMAL 0 +#define VIDEO_ALPHA_DISPLAY_CTRL_VERT_SCALE_HALF 1 +#define VIDEO_ALPHA_DISPLAY_CTRL_HORZ_SCALE 10:10 +#define VIDEO_ALPHA_DISPLAY_CTRL_HORZ_SCALE_NORMAL 0 +#define VIDEO_ALPHA_DISPLAY_CTRL_HORZ_SCALE_HALF 1 +#define VIDEO_ALPHA_DISPLAY_CTRL_VERT_MODE 9:9 +#define VIDEO_ALPHA_DISPLAY_CTRL_VERT_MODE_REPLICATE 0 +#define VIDEO_ALPHA_DISPLAY_CTRL_VERT_MODE_INTERPOLATE 1 +#define VIDEO_ALPHA_DISPLAY_CTRL_HORZ_MODE 8:8 +#define VIDEO_ALPHA_DISPLAY_CTRL_HORZ_MODE_REPLICATE 0 +#define VIDEO_ALPHA_DISPLAY_CTRL_HORZ_MODE_INTERPOLATE 1 +#define VIDEO_ALPHA_DISPLAY_CTRL_PIXEL 7:4 +#define VIDEO_ALPHA_DISPLAY_CTRL_CHROMA_KEY 3:3 +#define VIDEO_ALPHA_DISPLAY_CTRL_CHROMA_KEY_DISABLE 0 +#define VIDEO_ALPHA_DISPLAY_CTRL_CHROMA_KEY_ENABLE 1 +#define VIDEO_ALPHA_DISPLAY_CTRL_PLANE 2:2 +#define VIDEO_ALPHA_DISPLAY_CTRL_PLANE_DISABLE 0 +#define VIDEO_ALPHA_DISPLAY_CTRL_PLANE_ENABLE 1 +#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT 1:0 +#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_8 0 +#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_16 1 +#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4 2 +#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4_4_4 3 + +#define VIDEO_ALPHA_FB_ADDRESS 0x080084 +#define VIDEO_ALPHA_FB_ADDRESS_STATUS 31:31 +#define VIDEO_ALPHA_FB_ADDRESS_STATUS_CURRENT 0 +#define VIDEO_ALPHA_FB_ADDRESS_STATUS_PENDING 1 +#define VIDEO_ALPHA_FB_ADDRESS_EXT 27:27 +#define VIDEO_ALPHA_FB_ADDRESS_EXT_LOCAL 0 +#define VIDEO_ALPHA_FB_ADDRESS_EXT_EXTERNAL 1 +#define VIDEO_ALPHA_FB_ADDRESS_ADDRESS 25:0 + +#define VIDEO_ALPHA_FB_WIDTH 0x080088 +#define VIDEO_ALPHA_FB_WIDTH_WIDTH 29:16 +#define VIDEO_ALPHA_FB_WIDTH_OFFSET 13:0 + +#define VIDEO_ALPHA_FB_LAST_ADDRESS 0x08008C +#define VIDEO_ALPHA_FB_LAST_ADDRESS_EXT 27:27 +#define VIDEO_ALPHA_FB_LAST_ADDRESS_EXT_LOCAL 0 +#define VIDEO_ALPHA_FB_LAST_ADDRESS_EXT_EXTERNAL 1 +#define VIDEO_ALPHA_FB_LAST_ADDRESS_ADDRESS 25:0 + +#define VIDEO_ALPHA_PLANE_TL 0x080090 +#define VIDEO_ALPHA_PLANE_TL_TOP 26:16 +#define VIDEO_ALPHA_PLANE_TL_LEFT 10:0 + +#define VIDEO_ALPHA_PLANE_BR 0x080094 +#define VIDEO_ALPHA_PLANE_BR_BOTTOM 26:16 +#define VIDEO_ALPHA_PLANE_BR_RIGHT 10:0 + +#define VIDEO_ALPHA_SCALE 0x080098 +#define VIDEO_ALPHA_SCALE_VERTICAL_MODE 31:31 +#define VIDEO_ALPHA_SCALE_VERTICAL_MODE_EXPAND 0 +#define VIDEO_ALPHA_SCALE_VERTICAL_MODE_SHRINK 1 +#define VIDEO_ALPHA_SCALE_VERTICAL_SCALE 27:16 +#define VIDEO_ALPHA_SCALE_HORIZONTAL_MODE 15:15 +#define VIDEO_ALPHA_SCALE_HORIZONTAL_MODE_EXPAND 0 +#define VIDEO_ALPHA_SCALE_HORIZONTAL_MODE_SHRINK 1 +#define VIDEO_ALPHA_SCALE_HORIZONTAL_SCALE 11:0 + +#define VIDEO_ALPHA_INITIAL_SCALE 0x08009C +#define VIDEO_ALPHA_INITIAL_SCALE_VERTICAL 27:16 +#define VIDEO_ALPHA_INITIAL_SCALE_HORIZONTAL 11:0 + +#define VIDEO_ALPHA_CHROMA_KEY 0x0800A0 +#define VIDEO_ALPHA_CHROMA_KEY_MASK 31:16 +#define VIDEO_ALPHA_CHROMA_KEY_VALUE 15:0 + +#define VIDEO_ALPHA_COLOR_LOOKUP_01 0x0800A4 +#define VIDEO_ALPHA_COLOR_LOOKUP_01_1 31:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_01_1_RED 31:27 +#define VIDEO_ALPHA_COLOR_LOOKUP_01_1_GREEN 26:21 +#define VIDEO_ALPHA_COLOR_LOOKUP_01_1_BLUE 20:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_01_0 15:0 +#define VIDEO_ALPHA_COLOR_LOOKUP_01_0_RED 15:11 +#define VIDEO_ALPHA_COLOR_LOOKUP_01_0_GREEN 10:5 +#define VIDEO_ALPHA_COLOR_LOOKUP_01_0_BLUE 4:0 + +#define VIDEO_ALPHA_COLOR_LOOKUP_23 0x0800A8 +#define VIDEO_ALPHA_COLOR_LOOKUP_23_3 31:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_23_3_RED 31:27 +#define VIDEO_ALPHA_COLOR_LOOKUP_23_3_GREEN 26:21 +#define VIDEO_ALPHA_COLOR_LOOKUP_23_3_BLUE 20:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_23_2 15:0 +#define VIDEO_ALPHA_COLOR_LOOKUP_23_2_RED 15:11 +#define VIDEO_ALPHA_COLOR_LOOKUP_23_2_GREEN 10:5 +#define VIDEO_ALPHA_COLOR_LOOKUP_23_2_BLUE 4:0 + +#define VIDEO_ALPHA_COLOR_LOOKUP_45 0x0800AC +#define VIDEO_ALPHA_COLOR_LOOKUP_45_5 31:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_45_5_RED 31:27 +#define VIDEO_ALPHA_COLOR_LOOKUP_45_5_GREEN 26:21 +#define VIDEO_ALPHA_COLOR_LOOKUP_45_5_BLUE 20:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_45_4 15:0 +#define VIDEO_ALPHA_COLOR_LOOKUP_45_4_RED 15:11 +#define VIDEO_ALPHA_COLOR_LOOKUP_45_4_GREEN 10:5 +#define VIDEO_ALPHA_COLOR_LOOKUP_45_4_BLUE 4:0 + +#define VIDEO_ALPHA_COLOR_LOOKUP_67 0x0800B0 +#define VIDEO_ALPHA_COLOR_LOOKUP_67_7 31:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_67_7_RED 31:27 +#define VIDEO_ALPHA_COLOR_LOOKUP_67_7_GREEN 26:21 +#define VIDEO_ALPHA_COLOR_LOOKUP_67_7_BLUE 20:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_67_6 15:0 +#define VIDEO_ALPHA_COLOR_LOOKUP_67_6_RED 15:11 +#define VIDEO_ALPHA_COLOR_LOOKUP_67_6_GREEN 10:5 +#define VIDEO_ALPHA_COLOR_LOOKUP_67_6_BLUE 4:0 + +#define VIDEO_ALPHA_COLOR_LOOKUP_89 0x0800B4 +#define VIDEO_ALPHA_COLOR_LOOKUP_89_9 31:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_89_9_RED 31:27 +#define VIDEO_ALPHA_COLOR_LOOKUP_89_9_GREEN 26:21 +#define VIDEO_ALPHA_COLOR_LOOKUP_89_9_BLUE 20:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_89_8 15:0 +#define VIDEO_ALPHA_COLOR_LOOKUP_89_8_RED 15:11 +#define VIDEO_ALPHA_COLOR_LOOKUP_89_8_GREEN 10:5 +#define VIDEO_ALPHA_COLOR_LOOKUP_89_8_BLUE 4:0 + +#define VIDEO_ALPHA_COLOR_LOOKUP_AB 0x0800B8 +#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B 31:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B_RED 31:27 +#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B_GREEN 26:21 +#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B_BLUE 20:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A 15:0 +#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A_RED 15:11 +#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A_GREEN 10:5 +#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A_BLUE 4:0 + +#define VIDEO_ALPHA_COLOR_LOOKUP_CD 0x0800BC +#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D 31:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D_RED 31:27 +#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D_GREEN 26:21 +#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D_BLUE 20:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C 15:0 +#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C_RED 15:11 +#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C_GREEN 10:5 +#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C_BLUE 4:0 + +#define VIDEO_ALPHA_COLOR_LOOKUP_EF 0x0800C0 +#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F 31:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F_RED 31:27 +#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F_GREEN 26:21 +#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F_BLUE 20:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E 15:0 +#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E_RED 15:11 +#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E_GREEN 10:5 +#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E_BLUE 4:0 + +/* Primary Cursor Control */ + +#define PRIMARY_HWC_ADDRESS 0x0800F0 +#define PRIMARY_HWC_ADDRESS_ENABLE 31:31 +#define PRIMARY_HWC_ADDRESS_ENABLE_DISABLE 0 +#define PRIMARY_HWC_ADDRESS_ENABLE_ENABLE 1 +#define PRIMARY_HWC_ADDRESS_MODE 30:30 +#define PRIMARY_HWC_ADDRESS_MODE_MONO 0 +#define PRIMARY_HWC_ADDRESS_MODE_COLOR 1 +#define PRIMARY_HWC_ADDRESS_EXT 27:27 +#define PRIMARY_HWC_ADDRESS_EXT_LOCAL 0 +#define PRIMARY_HWC_ADDRESS_EXT_EXTERNAL 1 +#define PRIMARY_HWC_ADDRESS_ADDRESS 25:0 + +#define PRIMARY_HWC_LOCATION 0x0800F4 +#define PRIMARY_HWC_LOCATION_TOP 27:27 +#define PRIMARY_HWC_LOCATION_TOP_INSIDE 0 +#define PRIMARY_HWC_LOCATION_TOP_OUTSIDE 1 +#define PRIMARY_HWC_LOCATION_Y 26:16 +#define PRIMARY_HWC_LOCATION_LEFT 11:11 +#define PRIMARY_HWC_LOCATION_LEFT_INSIDE 0 +#define PRIMARY_HWC_LOCATION_LEFT_OUTSIDE 1 +#define PRIMARY_HWC_LOCATION_X 10:0 + +#define PRIMARY_HWC_COLOR_12 0x0800F8 +#define PRIMARY_HWC_COLOR_12_2_RGB565 31:16 +#define PRIMARY_HWC_COLOR_12_1_RGB565 15:0 + +#define PRIMARY_HWC_COLOR_3 0x0800FC +#define PRIMARY_HWC_COLOR_3_RGB565 15:0 + +/* Alpha Control */ + +#define ALPHA_DISPLAY_CTRL 0x080100 +#define ALPHA_DISPLAY_CTRL_SELECT 28:28 +#define ALPHA_DISPLAY_CTRL_SELECT_PER_PIXEL 0 +#define ALPHA_DISPLAY_CTRL_SELECT_ALPHA 1 +#define ALPHA_DISPLAY_CTRL_ALPHA 27:24 +#define ALPHA_DISPLAY_CTRL_FIFO 17:16 +#define ALPHA_DISPLAY_CTRL_FIFO_1 0 +#define ALPHA_DISPLAY_CTRL_FIFO_3 1 +#define ALPHA_DISPLAY_CTRL_FIFO_7 2 +#define ALPHA_DISPLAY_CTRL_FIFO_11 3 +#define ALPHA_DISPLAY_CTRL_PIXEL 7:4 +#define ALPHA_DISPLAY_CTRL_CHROMA_KEY 3:3 +#define ALPHA_DISPLAY_CTRL_CHROMA_KEY_DISABLE 0 +#define ALPHA_DISPLAY_CTRL_CHROMA_KEY_ENABLE 1 +#define ALPHA_DISPLAY_CTRL_PLANE 2:2 +#define ALPHA_DISPLAY_CTRL_PLANE_DISABLE 0 +#define ALPHA_DISPLAY_CTRL_PLANE_ENABLE 1 +#define ALPHA_DISPLAY_CTRL_FORMAT 1:0 +#define ALPHA_DISPLAY_CTRL_FORMAT_16 1 +#define ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4 2 +#define ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4_4_4 3 + +#define ALPHA_FB_ADDRESS 0x080104 +#define ALPHA_FB_ADDRESS_STATUS 31:31 +#define ALPHA_FB_ADDRESS_STATUS_CURRENT 0 +#define ALPHA_FB_ADDRESS_STATUS_PENDING 1 +#define ALPHA_FB_ADDRESS_EXT 27:27 +#define ALPHA_FB_ADDRESS_EXT_LOCAL 0 +#define ALPHA_FB_ADDRESS_EXT_EXTERNAL 1 +#define ALPHA_FB_ADDRESS_ADDRESS 25:0 + +#define ALPHA_FB_WIDTH 0x080108 +#define ALPHA_FB_WIDTH_WIDTH 29:16 +#define ALPHA_FB_WIDTH_OFFSET 13:0 + +#define ALPHA_PLANE_TL 0x08010C +#define ALPHA_PLANE_TL_TOP 26:16 +#define ALPHA_PLANE_TL_LEFT 10:0 + +#define ALPHA_PLANE_BR 0x080110 +#define ALPHA_PLANE_BR_BOTTOM 26:16 +#define ALPHA_PLANE_BR_RIGHT 10:0 + +#define ALPHA_CHROMA_KEY 0x080114 +#define ALPHA_CHROMA_KEY_MASK 31:16 +#define ALPHA_CHROMA_KEY_VALUE 15:0 + +#define ALPHA_COLOR_LOOKUP_01 0x080118 +#define ALPHA_COLOR_LOOKUP_01_1 31:16 +#define ALPHA_COLOR_LOOKUP_01_1_RED 31:27 +#define ALPHA_COLOR_LOOKUP_01_1_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_01_1_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_01_0 15:0 +#define ALPHA_COLOR_LOOKUP_01_0_RED 15:11 +#define ALPHA_COLOR_LOOKUP_01_0_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_01_0_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_23 0x08011C +#define ALPHA_COLOR_LOOKUP_23_3 31:16 +#define ALPHA_COLOR_LOOKUP_23_3_RED 31:27 +#define ALPHA_COLOR_LOOKUP_23_3_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_23_3_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_23_2 15:0 +#define ALPHA_COLOR_LOOKUP_23_2_RED 15:11 +#define ALPHA_COLOR_LOOKUP_23_2_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_23_2_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_45 0x080120 +#define ALPHA_COLOR_LOOKUP_45_5 31:16 +#define ALPHA_COLOR_LOOKUP_45_5_RED 31:27 +#define ALPHA_COLOR_LOOKUP_45_5_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_45_5_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_45_4 15:0 +#define ALPHA_COLOR_LOOKUP_45_4_RED 15:11 +#define ALPHA_COLOR_LOOKUP_45_4_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_45_4_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_67 0x080124 +#define ALPHA_COLOR_LOOKUP_67_7 31:16 +#define ALPHA_COLOR_LOOKUP_67_7_RED 31:27 +#define ALPHA_COLOR_LOOKUP_67_7_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_67_7_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_67_6 15:0 +#define ALPHA_COLOR_LOOKUP_67_6_RED 15:11 +#define ALPHA_COLOR_LOOKUP_67_6_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_67_6_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_89 0x080128 +#define ALPHA_COLOR_LOOKUP_89_9 31:16 +#define ALPHA_COLOR_LOOKUP_89_9_RED 31:27 +#define ALPHA_COLOR_LOOKUP_89_9_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_89_9_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_89_8 15:0 +#define ALPHA_COLOR_LOOKUP_89_8_RED 15:11 +#define ALPHA_COLOR_LOOKUP_89_8_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_89_8_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_AB 0x08012C +#define ALPHA_COLOR_LOOKUP_AB_B 31:16 +#define ALPHA_COLOR_LOOKUP_AB_B_RED 31:27 +#define ALPHA_COLOR_LOOKUP_AB_B_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_AB_B_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_AB_A 15:0 +#define ALPHA_COLOR_LOOKUP_AB_A_RED 15:11 +#define ALPHA_COLOR_LOOKUP_AB_A_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_AB_A_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_CD 0x080130 +#define ALPHA_COLOR_LOOKUP_CD_D 31:16 +#define ALPHA_COLOR_LOOKUP_CD_D_RED 31:27 +#define ALPHA_COLOR_LOOKUP_CD_D_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_CD_D_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_CD_C 15:0 +#define ALPHA_COLOR_LOOKUP_CD_C_RED 15:11 +#define ALPHA_COLOR_LOOKUP_CD_C_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_CD_C_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_EF 0x080134 +#define ALPHA_COLOR_LOOKUP_EF_F 31:16 +#define ALPHA_COLOR_LOOKUP_EF_F_RED 31:27 +#define ALPHA_COLOR_LOOKUP_EF_F_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_EF_F_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_EF_E 15:0 +#define ALPHA_COLOR_LOOKUP_EF_E_RED 15:11 +#define ALPHA_COLOR_LOOKUP_EF_E_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_EF_E_BLUE 4:0 + +/* Secondary Graphics Control */ + +#define SECONDARY_DISPLAY_CTRL 0x080200 + +/* SM750 and SM718 definition */ +#define SECONDARY_DISPLAY_CTRL_RESERVED_1_MASK 31:27 +#define SECONDARY_DISPLAY_CTRL_RESERVED_1_MASK_DISABLE 0 +#define SECONDARY_DISPLAY_CTRL_RESERVED_1_MASK_ENABLE 0x1F +/* SM750LE definition */ +#define SECONDARY_DISPLAY_CTRL_DPMS 31:30 +#define SECONDARY_DISPLAY_CTRL_DPMS_0 0 +#define SECONDARY_DISPLAY_CTRL_DPMS_1 1 +#define SECONDARY_DISPLAY_CTRL_DPMS_2 2 +#define SECONDARY_DISPLAY_CTRL_DPMS_3 3 +#define SECONDARY_DISPLAY_CTRL_CLK 29:27 +#define SECONDARY_DISPLAY_CTRL_CLK_PLL25 0 +#define SECONDARY_DISPLAY_CTRL_CLK_PLL41 1 +#define SECONDARY_DISPLAY_CTRL_CLK_PLL62 2 +#define SECONDARY_DISPLAY_CTRL_CLK_PLL65 3 +#define SECONDARY_DISPLAY_CTRL_CLK_PLL74 4 +#define SECONDARY_DISPLAY_CTRL_CLK_PLL80 5 +#define SECONDARY_DISPLAY_CTRL_CLK_PLL108 6 +#define SECONDARY_DISPLAY_CTRL_CLK_RESERVED 7 +#define SECONDARY_DISPLAY_CTRL_SHIFT_VGA_DAC 26:26 +#define SECONDARY_DISPLAY_CTRL_SHIFT_VGA_DAC_DISABLE 1 +#define SECONDARY_DISPLAY_CTRL_SHIFT_VGA_DAC_ENABLE 0 + +/* SM750 and SM718 definition */ +#define SECONDARY_DISPLAY_CTRL_RESERVED_2_MASK 25:24 +#define SECONDARY_DISPLAY_CTRL_RESERVED_2_MASK_DISABLE 0 +#define SECONDARY_DISPLAY_CTRL_RESERVED_2_MASK_ENABLE 3 + +/* SM750LE definition */ +#define SECONDARY_DISPLAY_CTRL_CRTSELECT 25:25 +#define SECONDARY_DISPLAY_CTRL_CRTSELECT_VGA 0 +#define SECONDARY_DISPLAY_CTRL_CRTSELECT_CRT 1 +#define SECONDARY_DISPLAY_CTRL_RGBBIT 24:24 +#define SECONDARY_DISPLAY_CTRL_RGBBIT_24BIT 0 +#define SECONDARY_DISPLAY_CTRL_RGBBIT_12BIT 1 + +#define SECONDARY_DISPLAY_CTRL_LOCK_TIMING 23:23 +#define SECONDARY_DISPLAY_CTRL_LOCK_TIMING_DISABLE 0 +#define SECONDARY_DISPLAY_CTRL_LOCK_TIMING_ENABLE 1 +#define SECONDARY_DISPLAY_CTRL_EXPANSION 22:22 +#define SECONDARY_DISPLAY_CTRL_EXPANSION_DISABLE 0 +#define SECONDARY_DISPLAY_CTRL_EXPANSION_ENABLE 1 +#define SECONDARY_DISPLAY_CTRL_VERTICAL_MODE 21:21 +#define SECONDARY_DISPLAY_CTRL_VERTICAL_MODE_REPLICATE 0 +#define SECONDARY_DISPLAY_CTRL_VERTICAL_MODE_INTERPOLATE 1 +#define SECONDARY_DISPLAY_CTRL_HORIZONTAL_MODE 20:20 +#define SECONDARY_DISPLAY_CTRL_HORIZONTAL_MODE_REPLICATE 0 +#define SECONDARY_DISPLAY_CTRL_HORIZONTAL_MODE_INTERPOLATE 1 +#define SECONDARY_DISPLAY_CTRL_SELECT 19:18 +#define SECONDARY_DISPLAY_CTRL_SELECT_PRIMARY 0 +#define SECONDARY_DISPLAY_CTRL_SELECT_VGA 1 +#define SECONDARY_DISPLAY_CTRL_SELECT_SECONDARY 2 +#define SECONDARY_DISPLAY_CTRL_FIFO 17:16 +#define SECONDARY_DISPLAY_CTRL_FIFO_1 0 +#define SECONDARY_DISPLAY_CTRL_FIFO_3 1 +#define SECONDARY_DISPLAY_CTRL_FIFO_7 2 +#define SECONDARY_DISPLAY_CTRL_FIFO_11 3 +#define SECONDARY_DISPLAY_CTRL_RESERVED_3_MASK 15:15 +#define SECONDARY_DISPLAY_CTRL_RESERVED_3_MASK_DISABLE 0 +#define SECONDARY_DISPLAY_CTRL_RESERVED_3_MASK_ENABLE 1 +#define SECONDARY_DISPLAY_CTRL_CLOCK_PHASE 14:14 +#define SECONDARY_DISPLAY_CTRL_CLOCK_PHASE_ACTIVE_HIGH 0 +#define SECONDARY_DISPLAY_CTRL_CLOCK_PHASE_ACTIVE_LOW 1 +#define SECONDARY_DISPLAY_CTRL_VSYNC_PHASE 13:13 +#define SECONDARY_DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_HIGH 0 +#define SECONDARY_DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_LOW 1 +#define SECONDARY_DISPLAY_CTRL_HSYNC_PHASE 12:12 +#define SECONDARY_DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_HIGH 0 +#define SECONDARY_DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_LOW 1 +#define SECONDARY_DISPLAY_CTRL_BLANK 10:10 +#define SECONDARY_DISPLAY_CTRL_BLANK_OFF 0 +#define SECONDARY_DISPLAY_CTRL_BLANK_ON 1 +#define SECONDARY_DISPLAY_CTRL_RESERVED_4_MASK 9:9 +#define SECONDARY_DISPLAY_CTRL_RESERVED_4_MASK_DISABLE 0 +#define SECONDARY_DISPLAY_CTRL_RESERVED_4_MASK_ENABLE 1 +#define SECONDARY_DISPLAY_CTRL_TIMING 8:8 +#define SECONDARY_DISPLAY_CTRL_TIMING_DISABLE 0 +#define SECONDARY_DISPLAY_CTRL_TIMING_ENABLE 1 +#define SECONDARY_DISPLAY_CTRL_PIXEL 7:4 +#define SECONDARY_DISPLAY_CTRL_GAMMA 3:3 +#define SECONDARY_DISPLAY_CTRL_GAMMA_DISABLE 0 +#define SECONDARY_DISPLAY_CTRL_GAMMA_ENABLE 1 +#define SECONDARY_DISPLAY_CTRL_PLANE 2:2 +#define SECONDARY_DISPLAY_CTRL_PLANE_DISABLE 0 +#define SECONDARY_DISPLAY_CTRL_PLANE_ENABLE 1 +#define SECONDARY_DISPLAY_CTRL_FORMAT 1:0 +#define SECONDARY_DISPLAY_CTRL_FORMAT_8 0 +#define SECONDARY_DISPLAY_CTRL_FORMAT_16 1 +#define SECONDARY_DISPLAY_CTRL_FORMAT_32 2 +#define SECONDARY_DISPLAY_CTRL_RESERVED_BITS_MASK 0xFF000200 + +#define SECONDARY_FB_ADDRESS 0x080204 +#define SECONDARY_FB_ADDRESS_STATUS 31:31 +#define SECONDARY_FB_ADDRESS_STATUS_CURRENT 0 +#define SECONDARY_FB_ADDRESS_STATUS_PENDING 1 +#define SECONDARY_FB_ADDRESS_EXT 27:27 +#define SECONDARY_FB_ADDRESS_EXT_LOCAL 0 +#define SECONDARY_FB_ADDRESS_EXT_EXTERNAL 1 +#define SECONDARY_FB_ADDRESS_ADDRESS 25:0 + +#define SECONDARY_FB_WIDTH 0x080208 +#define SECONDARY_FB_WIDTH_WIDTH 29:16 +#define SECONDARY_FB_WIDTH_OFFSET 13:0 + +#define SECONDARY_HORIZONTAL_TOTAL 0x08020C +#define SECONDARY_HORIZONTAL_TOTAL_TOTAL 27:16 +#define SECONDARY_HORIZONTAL_TOTAL_DISPLAY_END 11:0 + +#define SECONDARY_HORIZONTAL_SYNC 0x080210 +#define SECONDARY_HORIZONTAL_SYNC_WIDTH 23:16 +#define SECONDARY_HORIZONTAL_SYNC_START 11:0 + +#define SECONDARY_VERTICAL_TOTAL 0x080214 +#define SECONDARY_VERTICAL_TOTAL_TOTAL 26:16 +#define SECONDARY_VERTICAL_TOTAL_DISPLAY_END 10:0 + +#define SECONDARY_VERTICAL_SYNC 0x080218 +#define SECONDARY_VERTICAL_SYNC_HEIGHT 21:16 +#define SECONDARY_VERTICAL_SYNC_START 10:0 + +#define SECONDARY_SIGNATURE_ANALYZER 0x08021C +#define SECONDARY_SIGNATURE_ANALYZER_STATUS 31:16 +#define SECONDARY_SIGNATURE_ANALYZER_ENABLE 3:3 +#define SECONDARY_SIGNATURE_ANALYZER_ENABLE_DISABLE 0 +#define SECONDARY_SIGNATURE_ANALYZER_ENABLE_ENABLE 1 +#define SECONDARY_SIGNATURE_ANALYZER_RESET 2:2 +#define SECONDARY_SIGNATURE_ANALYZER_RESET_NORMAL 0 +#define SECONDARY_SIGNATURE_ANALYZER_RESET_RESET 1 +#define SECONDARY_SIGNATURE_ANALYZER_SOURCE 1:0 +#define SECONDARY_SIGNATURE_ANALYZER_SOURCE_RED 0 +#define SECONDARY_SIGNATURE_ANALYZER_SOURCE_GREEN 1 +#define SECONDARY_SIGNATURE_ANALYZER_SOURCE_BLUE 2 + +#define SECONDARY_CURRENT_LINE 0x080220 +#define SECONDARY_CURRENT_LINE_LINE 10:0 + +#define SECONDARY_MONITOR_DETECT 0x080224 +#define SECONDARY_MONITOR_DETECT_VALUE 25:25 +#define SECONDARY_MONITOR_DETECT_VALUE_DISABLE 0 +#define SECONDARY_MONITOR_DETECT_VALUE_ENABLE 1 +#define SECONDARY_MONITOR_DETECT_ENABLE 24:24 +#define SECONDARY_MONITOR_DETECT_ENABLE_DISABLE 0 +#define SECONDARY_MONITOR_DETECT_ENABLE_ENABLE 1 +#define SECONDARY_MONITOR_DETECT_RED 23:16 +#define SECONDARY_MONITOR_DETECT_GREEN 15:8 +#define SECONDARY_MONITOR_DETECT_BLUE 7:0 + +#define SECONDARY_SCALE 0x080228 +#define SECONDARY_SCALE_VERTICAL_MODE 31:31 +#define SECONDARY_SCALE_VERTICAL_MODE_EXPAND 0 +#define SECONDARY_SCALE_VERTICAL_MODE_SHRINK 1 +#define SECONDARY_SCALE_VERTICAL_SCALE 27:16 +#define SECONDARY_SCALE_HORIZONTAL_MODE 15:15 +#define SECONDARY_SCALE_HORIZONTAL_MODE_EXPAND 0 +#define SECONDARY_SCALE_HORIZONTAL_MODE_SHRINK 1 +#define SECONDARY_SCALE_HORIZONTAL_SCALE 11:0 + +/* Secondary Cursor Control */ + +#define SECONDARY_HWC_ADDRESS 0x080230 +#define SECONDARY_HWC_ADDRESS_ENABLE 31:31 +#define SECONDARY_HWC_ADDRESS_ENABLE_DISABLE 0 +#define SECONDARY_HWC_ADDRESS_ENABLE_ENABLE 1 +#define SECONDARY_HWC_ADDRESS_MODE 30:30 +#define SECONDARY_HWC_ADDRESS_MODE_MONO 0 +#define SECONDARY_HWC_ADDRESS_MODE_COLOR 1 +#define SECONDARY_HWC_ADDRESS_EXT 27:27 +#define SECONDARY_HWC_ADDRESS_EXT_LOCAL 0 +#define SECONDARY_HWC_ADDRESS_EXT_EXTERNAL 1 +#define SECONDARY_HWC_ADDRESS_ADDRESS 25:0 + +#define SECONDARY_HWC_LOCATION 0x080234 +#define SECONDARY_HWC_LOCATION_TOP 27:27 +#define SECONDARY_HWC_LOCATION_TOP_INSIDE 0 +#define SECONDARY_HWC_LOCATION_TOP_OUTSIDE 1 +#define SECONDARY_HWC_LOCATION_Y 26:16 +#define SECONDARY_HWC_LOCATION_LEFT 11:11 +#define SECONDARY_HWC_LOCATION_LEFT_INSIDE 0 +#define SECONDARY_HWC_LOCATION_LEFT_OUTSIDE 1 +#define SECONDARY_HWC_LOCATION_X 10:0 + +#define SECONDARY_HWC_COLOR_12 0x080238 +#define SECONDARY_HWC_COLOR_12_2_RGB565 31:16 +#define SECONDARY_HWC_COLOR_12_1_RGB565 15:0 + +#define SECONDARY_HWC_COLOR_3 0x08023C +#define SECONDARY_HWC_COLOR_3_RGB565 15:0 + +/* This vertical expansion below start at 0x080240 ~ 0x080264 */ +#define SECONDARY_VERTICAL_EXPANSION 0x080240 +#define SECONDARY_VERTICAL_EXPANSION_CENTERING_VALUE 31:24 +#define SECONDARY_VERTICAL_EXPANSION_COMPARE_VALUE 23:16 +#define SECONDARY_VERTICAL_EXPANSION_LINE_BUFFER 15:12 +#define SECONDARY_VERTICAL_EXPANSION_SCALE_FACTOR 11:0 + +/* This horizontal expansion below start at 0x080268 ~ 0x08027C */ +#define SECONDARY_HORIZONTAL_EXPANSION 0x080268 +#define SECONDARY_HORIZONTAL_EXPANSION_CENTERING_VALUE 31:24 +#define SECONDARY_HORIZONTAL_EXPANSION_COMPARE_VALUE 23:16 +#define SECONDARY_HORIZONTAL_EXPANSION_SCALE_FACTOR 11:0 + +/* Auto Centering */ +#define SECONDARY_AUTO_CENTERING_TL 0x080280 +#define SECONDARY_AUTO_CENTERING_TL_TOP 26:16 +#define SECONDARY_AUTO_CENTERING_TL_LEFT 10:0 + +#define SECONDARY_AUTO_CENTERING_BR 0x080284 +#define SECONDARY_AUTO_CENTERING_BR_BOTTOM 26:16 +#define SECONDARY_AUTO_CENTERING_BR_RIGHT 10:0 + +/* SM750LE new register to control panel output */ +#define DISPLAY_CONTROL_750LE 0x80288 +#define DISPLAY_CONTROL_750LE_RESERVED 31:5 +#define DISPLAY_CONTROL_750LE_PANEL 4:4 +#define DISPLAY_CONTROL_750LE_PANEL_NORMAL 0 +#define DISPLAY_CONTROL_750LE_PANEL_TRISTATE 1 +#define DISPLAY_CONTROL_750LE_EN 3:3 +#define DISPLAY_CONTROL_750LE_EN_LOW 0 +#define DISPLAY_CONTROL_750LE_EN_HIGH 1 +#define DISPLAY_CONTROL_750LE_BIAS 2:2 +#define DISPLAY_CONTROL_750LE_BIAS_LOW 0 +#define DISPLAY_CONTROL_750LE_BIAS_HIGH 1 +#define DISPLAY_CONTROL_750LE_DATA 1:1 +#define DISPLAY_CONTROL_750LE_DATA_DISABLE 0 +#define DISPLAY_CONTROL_750LE_DATA_ENABLE 1 +#define DISPLAY_CONTROL_750LE_VDD 0:0 +#define DISPLAY_CONTROL_750LE_VDD_LOW 0 +#define DISPLAY_CONTROL_750LE_VDD_HIGH 1 + +/* SM750LE new register for display interrtup control */ +#define RAW_INT_750LE 0x080290 +#define RAW_INT_750LE_RESERVED1 31:3 +#define RAW_INT_750LE_SECONDARY_VSYNC 2:2 +#define RAW_INT_750LE_SECONDARY_VSYNC_INACTIVE 0 +#define RAW_INT_750LE_SECONDARY_VSYNC_ACTIVE 1 +#define RAW_INT_750LE_SECONDARY_VSYNC_CLEAR 1 +#define RAW_INT_750LE_PRIMARY_VSYNC 1:1 +#define RAW_INT_750LE_PRIMARY_VSYNC_INACTIVE 0 +#define RAW_INT_750LE_PRIMARY_VSYNC_ACTIVE 1 +#define RAW_INT_750LE_PRIMARY_VSYNC_CLEAR 1 +#define RAW_INT_750LE_VGA_VSYNC 0:0 +#define RAW_INT_750LE_VGA_VSYNC_INACTIVE 0 +#define RAW_INT_750LE_VGA_VSYNC_ACTIVE 1 +#define RAW_INT_750LE_VGA_VSYNC_CLEAR 1 + +#define INT_STATUS_750LE 0x080294 +#define INT_STATUS_750LE_RESERVED1 31:3 +#define INT_STATUS_750LE_SECONDARY_VSYNC 2:2 +#define INT_STATUS_750LE_SECONDARY_VSYNC_INACTIVE 0 +#define INT_STATUS_750LE_SECONDARY_VSYNC_ACTIVE 1 +#define INT_STATUS_750LE_PRIMARY_VSYNC 1:1 +#define INT_STATUS_750LE_PRIMARY_VSYNC_INACTIVE 0 +#define INT_STATUS_750LE_PRIMARY_VSYNC_ACTIVE 1 +#define INT_STATUS_750LE_VGA_VSYNC 0:0 +#define INT_STATUS_750LE_VGA_VSYNC_INACTIVE 0 +#define INT_STATUS_750LE_VGA_VSYNC_ACTIVE 1 + +#define INT_MASK_750LE 0x080298 +#define INT_MASK_750LE_RESERVED1 31:3 +#define INT_MASK_750LE_SECONDARY_VSYNC 2:2 +#define INT_MASK_750LE_SECONDARY_VSYNC_DISABLE 0 +#define INT_MASK_750LE_SECONDARY_VSYNC_ENABLE 1 +#define INT_MASK_750LE_PRIMARY_VSYNC 1:1 +#define INT_MASK_750LE_PRIMARY_VSYNC_DISABLE 0 +#define INT_MASK_750LE_PRIMARY_VSYNC_ENABLE 1 +#define INT_MASK_750LE_VGA_VSYNC 0:0 +#define INT_MASK_750LE_VGA_VSYNC_DISABLE 0 +#define INT_MASK_750LE_VGA_VSYNC_ENABLE 1 + +/* SM750HS new register and values for PLL control */ +#define CRT_PLL1_750HS 0x802a8 +#define CRT_PLL1_750HS_25MHZ 0x00 +#define CRT_PLL1_750HS_40MHZ 0x01 +#define CRT_PLL1_750HS_65MHZ 0x03 +#define CRT_PLL1_750HS_78MHZ 0x05 +#define CRT_PLL1_750HS_74MHZ 0x04 +#define CRT_PLL1_750HS_80MHZ 0x05 +#define CRT_PLL1_750HS_108MHZ 0x06 +#define CRT_PLL1_750HS_162MHZ 0x21 +#define CRT_PLL1_750HS_148MHZ 0x20 +#define CRT_PLL1_750HS_193MHZ 0x22 + +/* +#define CRT_PLL1_750HS_F_25MHZ 0x1D40A02 +#define CRT_PLL1_750HS_F_40MHZ 0x3940801 +#define CRT_PLL1_750HS_F_65MHZ 0x3940D01 +#define CRT_PLL1_750HS_F_78MHZ 0x1540F82 +#define CRT_PLL1_750HS_F_74MHZ 0x1541D82 +#define CRT_PLL1_750HS_F_80MHZ 0x3941001 +#define CRT_PLL1_750HS_F_108MHZ 0x3941B01 +#define CRT_PLL1_750HS_F_162MHZ 0x3942881 +#define CRT_PLL1_750HS_F_148MHZ 0x1541D82 +#define CRT_PLL1_750HS_F_193MHZ 0x1542682 +*/ +#define CRT_PLL1_750HS_F_25MHZ 0x23d40f02 +#define CRT_PLL1_750HS_F_40MHZ 0x23940801 +#define CRT_PLL1_750HS_F_65MHZ 0x23940d01 +#define CRT_PLL1_750HS_F_78MHZ 0x23540F82 +#define CRT_PLL1_750HS_F_74MHZ 0x23941dc2 +#define CRT_PLL1_750HS_F_80MHZ 0x23941001 +#define CRT_PLL1_750HS_F_80MHZ_1152 0x23540fc2 +#define CRT_PLL1_750HS_F_108MHZ 0x23b41b01 +#define CRT_PLL1_750HS_F_162MHZ 0x23480681 +#define CRT_PLL1_750HS_F_148MHZ 0x23541dc2 +#define CRT_PLL1_750HS_F_193MHZ 0x234807c1 + +#define CRT_PLL1_750HS_A_25MHZ 0x1D40A02 +#define CRT_PLL1_750HS_A_40MHZ 0x3940801 +#define CRT_PLL1_750HS_A_65MHZ 0x3940D01 +#define CRT_PLL1_750HS_A_78MHZ 0x1540F82 +#define CRT_PLL1_750HS_A_74MHZ 0x1541D82 +#define CRT_PLL1_750HS_A_80MHZ 0x3941001 +#define CRT_PLL1_750HS_A_108MHZ 0x3941B01 +#define CRT_PLL1_750HS_A_162MHZ 0x3942881 +#define CRT_PLL1_750HS_A_148MHZ 0x1541D82 +#define CRT_PLL1_750HS_A_193MHZ 0x1542682 + +#define CRT_PLL2_750HS 0x802ac +#define CRT_PLL2_750HS_25MHZ 0x0 +#define CRT_PLL2_750HS_40MHZ 0x0 +#define CRT_PLL2_750HS_65MHZ 0x0 +#define CRT_PLL2_750HS_78MHZ 0x0 +#define CRT_PLL2_750HS_74MHZ 0x0 +#define CRT_PLL2_750HS_80MHZ 0x0 +#define CRT_PLL2_750HS_108MHZ 0x0 +#define CRT_PLL2_750HS_162MHZ 0x0 +#define CRT_PLL2_750HS_148MHZ 0x0 +#define CRT_PLL2_750HS_193MHZ 0x0 + +#define CRT_PLL2_750HS_F_25MHZ 0x206B851E +#define CRT_PLL2_750HS_F_40MHZ 0x30000000 +#define CRT_PLL2_750HS_F_65MHZ 0x40000000 +#define CRT_PLL2_750HS_F_78MHZ 0x50E147AE +#define CRT_PLL2_750HS_F_74MHZ 0x602B6AE7 +#define CRT_PLL2_750HS_F_80MHZ 0x70000000 +#define CRT_PLL2_750HS_F_108MHZ 0x80000000 +#define CRT_PLL2_750HS_F_162MHZ 0xA0000000 +#define CRT_PLL2_750HS_F_148MHZ 0xB0CCCCCD +#define CRT_PLL2_750HS_F_193MHZ 0xC0872B02 + +#define CRT_PLL2_750HS_A_25MHZ 0x206B851E +#define CRT_PLL2_750HS_A_40MHZ 0x30000000 +#define CRT_PLL2_750HS_A_65MHZ 0x40000000 +#define CRT_PLL2_750HS_A_78MHZ 0x50E147AE +#define CRT_PLL2_750HS_A_74MHZ 0x602B6AE7 +#define CRT_PLL2_750HS_A_80MHZ 0x70000000 +#define CRT_PLL2_750HS_A_108MHZ 0x80000000 +#define CRT_PLL2_750HS_A_162MHZ 0xA0000000 +#define CRT_PLL2_750HS_A_148MHZ 0xB0CCCCCD +#define CRT_PLL2_750HS_A_193MHZ 0xC0872B02 + +/* SM750HS, the following PLL are for BIOS to set VGA modes. + DDK don't use them. Just keep here for the record. */ +#define VGA1_PLL1_750HS 0x802b0 +#define VGA1_PLL2_750HS 0x802b4 +#define VGA2_PLL1_750HS 0x802b8 +#define VGA2_PLL2_750HS 0x802bc + +/* Palette RAM */ + +/* Panel Pallete register starts at 0x080400 ~ 0x0807FC */ +#define PRIMARY_PALETTE_RAM 0x080400 + +/* Panel Pallete register starts at 0x080C00 ~ 0x080FFC */ +#define SECONDARY_PALETTE_RAM 0x080C00 diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_regde.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_regde.h new file mode 100644 index 000000000000..70c26e3575b0 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_regde.h @@ -0,0 +1,359 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* RegDE.h --- Voyager GX SDK +* This file contains the definitions for the Drawing Engine registers. +* +*******************************************************************/ +/* 2D registers. */ + +#define DE_SOURCE 0x100000 +#define DE_SOURCE_WRAP 31:31 +#define DE_SOURCE_WRAP_DISABLE 0 +#define DE_SOURCE_WRAP_ENABLE 1 + +/* + * The following definitions are used in different setting + */ + +/* Use these definitions in XY addressing mode or linear addressing mode. */ +#define DE_SOURCE_X_K1 27:16 +#define DE_SOURCE_Y_K2 11:0 + +/* Use this definition in host write mode for mono. The Y_K2 is not used + in host write mode. */ +#define DE_SOURCE_X_K1_MONO 20:16 + +/* Use these definitions in Bresenham line drawing mode. */ +#define DE_SOURCE_X_K1_LINE 29:16 +#define DE_SOURCE_Y_K2_LINE 13:0 + +#define DE_DESTINATION 0x100004 +#define DE_DESTINATION_WRAP 31:31 +#define DE_DESTINATION_WRAP_DISABLE 0 +#define DE_DESTINATION_WRAP_ENABLE 1 +#if 1 + #define DE_DESTINATION_X 27:16 + #define DE_DESTINATION_Y 11:0 +#else + #define DE_DESTINATION_X 28:16 + #define DE_DESTINATION_Y 15:0 +#endif + +#define DE_DIMENSION 0x100008 +#define DE_DIMENSION_X 28:16 +#define DE_DIMENSION_Y_ET 15:0 + +#define DE_CONTROL 0x10000C +#define DE_CONTROL_STATUS 31:31 +#define DE_CONTROL_STATUS_STOP 0 +#define DE_CONTROL_STATUS_START 1 +#define DE_CONTROL_PATTERN 30:30 +#define DE_CONTROL_PATTERN_MONO 0 +#define DE_CONTROL_PATTERN_COLOR 1 +#define DE_CONTROL_UPDATE_DESTINATION_X 29:29 +#define DE_CONTROL_UPDATE_DESTINATION_X_DISABLE 0 +#define DE_CONTROL_UPDATE_DESTINATION_X_ENABLE 1 +#define DE_CONTROL_QUICK_START 28:28 +#define DE_CONTROL_QUICK_START_DISABLE 0 +#define DE_CONTROL_QUICK_START_ENABLE 1 +#define DE_CONTROL_DIRECTION 27:27 +#define DE_CONTROL_DIRECTION_LEFT_TO_RIGHT 0 +#define DE_CONTROL_DIRECTION_RIGHT_TO_LEFT 1 +#define DE_CONTROL_MAJOR 26:26 +#define DE_CONTROL_MAJOR_X 0 +#define DE_CONTROL_MAJOR_Y 1 +#define DE_CONTROL_STEP_X 25:25 +#define DE_CONTROL_STEP_X_POSITIVE 0 +#define DE_CONTROL_STEP_X_NEGATIVE 1 +#define DE_CONTROL_STEP_Y 24:24 +#define DE_CONTROL_STEP_Y_POSITIVE 0 +#define DE_CONTROL_STEP_Y_NEGATIVE 1 +#define DE_CONTROL_STRETCH 23:23 +#define DE_CONTROL_STRETCH_DISABLE 0 +#define DE_CONTROL_STRETCH_ENABLE 1 +#define DE_CONTROL_HOST 22:22 +#define DE_CONTROL_HOST_COLOR 0 +#define DE_CONTROL_HOST_MONO 1 +#define DE_CONTROL_LAST_PIXEL 21:21 +#define DE_CONTROL_LAST_PIXEL_OFF 0 +#define DE_CONTROL_LAST_PIXEL_ON 1 +#define DE_CONTROL_COMMAND 20:16 +#define DE_CONTROL_COMMAND_BITBLT 0 +#define DE_CONTROL_COMMAND_RECTANGLE_FILL 1 +#define DE_CONTROL_COMMAND_DE_TILE 2 +#define DE_CONTROL_COMMAND_TRAPEZOID_FILL 3 +#define DE_CONTROL_COMMAND_ALPHA_BLEND 4 +#define DE_CONTROL_COMMAND_RLE_STRIP 5 +#define DE_CONTROL_COMMAND_SHORT_STROKE 6 +#define DE_CONTROL_COMMAND_LINE_DRAW 7 +#define DE_CONTROL_COMMAND_HOST_WRITE 8 +#define DE_CONTROL_COMMAND_HOST_READ 9 +#define DE_CONTROL_COMMAND_HOST_WRITE_BOTTOM_UP 10 +#define DE_CONTROL_COMMAND_ROTATE 11 +#define DE_CONTROL_COMMAND_FONT 12 +#define DE_CONTROL_COMMAND_TEXTURE_LOAD 15 +#define DE_CONTROL_ROP_SELECT 15:15 +#define DE_CONTROL_ROP_SELECT_ROP3 0 +#define DE_CONTROL_ROP_SELECT_ROP2 1 +#define DE_CONTROL_ROP2_SOURCE 14:14 +#define DE_CONTROL_ROP2_SOURCE_BITMAP 0 +#define DE_CONTROL_ROP2_SOURCE_PATTERN 1 +#define DE_CONTROL_MONO_DATA 13:12 +#define DE_CONTROL_MONO_DATA_NOT_PACKED 0 +#define DE_CONTROL_MONO_DATA_8_PACKED 1 +#define DE_CONTROL_MONO_DATA_16_PACKED 2 +#define DE_CONTROL_MONO_DATA_32_PACKED 3 +#define DE_CONTROL_REPEAT_ROTATE 11:11 +#define DE_CONTROL_REPEAT_ROTATE_DISABLE 0 +#define DE_CONTROL_REPEAT_ROTATE_ENABLE 1 +#define DE_CONTROL_TRANSPARENCY_MATCH 10:10 +#define DE_CONTROL_TRANSPARENCY_MATCH_OPAQUE 0 +#define DE_CONTROL_TRANSPARENCY_MATCH_TRANSPARENT 1 +#define DE_CONTROL_TRANSPARENCY_SELECT 9:9 +#define DE_CONTROL_TRANSPARENCY_SELECT_SOURCE 0 +#define DE_CONTROL_TRANSPARENCY_SELECT_DESTINATION 1 +#define DE_CONTROL_TRANSPARENCY 8:8 +#define DE_CONTROL_TRANSPARENCY_DISABLE 0 +#define DE_CONTROL_TRANSPARENCY_ENABLE 1 +#define DE_CONTROL_ROP 7:0 + +/* Pseudo fields. */ + +#define DE_CONTROL_SHORT_STROKE_DIR 27:24 +#define DE_CONTROL_SHORT_STROKE_DIR_225 0 +#define DE_CONTROL_SHORT_STROKE_DIR_135 1 +#define DE_CONTROL_SHORT_STROKE_DIR_315 2 +#define DE_CONTROL_SHORT_STROKE_DIR_45 3 +#define DE_CONTROL_SHORT_STROKE_DIR_270 4 +#define DE_CONTROL_SHORT_STROKE_DIR_90 5 +#define DE_CONTROL_SHORT_STROKE_DIR_180 8 +#define DE_CONTROL_SHORT_STROKE_DIR_0 10 +#define DE_CONTROL_ROTATION 25:24 +#define DE_CONTROL_ROTATION_0 0 +#define DE_CONTROL_ROTATION_270 1 +#define DE_CONTROL_ROTATION_90 2 +#define DE_CONTROL_ROTATION_180 3 + +#define DE_PITCH 0x100010 +#define DE_PITCH_DESTINATION 28:16 +#define DE_PITCH_SOURCE 12:0 + +#define DE_FOREGROUND 0x100014 +#define DE_FOREGROUND_COLOR 31:0 + +#define DE_BACKGROUND 0x100018 +#define DE_BACKGROUND_COLOR 31:0 + +#define DE_STRETCH_FORMAT 0x10001C +#define DE_STRETCH_FORMAT_PATTERN_XY 30:30 +#define DE_STRETCH_FORMAT_PATTERN_XY_NORMAL 0 +#define DE_STRETCH_FORMAT_PATTERN_XY_OVERWRITE 1 +#define DE_STRETCH_FORMAT_PATTERN_Y 29:27 +#define DE_STRETCH_FORMAT_PATTERN_X 25:23 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT 21:20 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_8 0 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_16 1 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_32 2 +#define DE_STRETCH_FORMAT_ADDRESSING 19:16 +#define DE_STRETCH_FORMAT_ADDRESSING_XY 0 +#define DE_STRETCH_FORMAT_ADDRESSING_LINEAR 15 +#define DE_STRETCH_FORMAT_SOURCE_HEIGHT 11:0 + +#define DE_COLOR_COMPARE 0x100020 +#define DE_COLOR_COMPARE_COLOR 23:0 + +#define DE_COLOR_COMPARE_MASK 0x100024 +#define DE_COLOR_COMPARE_MASK_MASKS 23:0 + +#define DE_MASKS 0x100028 +#define DE_MASKS_BYTE_MASK 31:16 +#define DE_MASKS_BIT_MASK 15:0 + +#define DE_CLIP_TL 0x10002C +#define DE_CLIP_TL_TOP 31:16 +#define DE_CLIP_TL_STATUS 13:13 +#define DE_CLIP_TL_STATUS_DISABLE 0 +#define DE_CLIP_TL_STATUS_ENABLE 1 +#define DE_CLIP_TL_INHIBIT 12:12 +#define DE_CLIP_TL_INHIBIT_OUTSIDE 0 +#define DE_CLIP_TL_INHIBIT_INSIDE 1 +#define DE_CLIP_TL_LEFT 11:0 + +#define DE_CLIP_BR 0x100030 +#define DE_CLIP_BR_BOTTOM 31:16 +#define DE_CLIP_BR_RIGHT 12:0 + +#define DE_MONO_PATTERN_LOW 0x100034 +#define DE_MONO_PATTERN_LOW_PATTERN 31:0 + +#define DE_MONO_PATTERN_HIGH 0x100038 +#define DE_MONO_PATTERN_HIGH_PATTERN 31:0 + +#define DE_WINDOW_WIDTH 0x10003C +#define DE_WINDOW_WIDTH_DESTINATION 28:16 +#define DE_WINDOW_WIDTH_SOURCE 12:0 + +#define DE_WINDOW_SOURCE_BASE 0x100040 +#define DE_WINDOW_SOURCE_BASE_EXT 27:27 +#define DE_WINDOW_SOURCE_BASE_EXT_LOCAL 0 +#define DE_WINDOW_SOURCE_BASE_EXT_EXTERNAL 1 +#define DE_WINDOW_SOURCE_BASE_CS 26:26 +#define DE_WINDOW_SOURCE_BASE_CS_0 0 +#define DE_WINDOW_SOURCE_BASE_CS_1 1 +#define DE_WINDOW_SOURCE_BASE_ADDRESS 25:0 + +#define DE_WINDOW_DESTINATION_BASE 0x100044 +#define DE_WINDOW_DESTINATION_BASE_EXT 27:27 +#define DE_WINDOW_DESTINATION_BASE_EXT_LOCAL 0 +#define DE_WINDOW_DESTINATION_BASE_EXT_EXTERNAL 1 +#define DE_WINDOW_DESTINATION_BASE_CS 26:26 +#define DE_WINDOW_DESTINATION_BASE_CS_0 0 +#define DE_WINDOW_DESTINATION_BASE_CS_1 1 +#define DE_WINDOW_DESTINATION_BASE_ADDRESS 25:0 + +#define DE_ALPHA 0x100048 +#define DE_ALPHA_VALUE 7:0 + +#define DE_WRAP 0x10004C +#define DE_WRAP_X 31:16 +#define DE_WRAP_Y 15:0 + +#define DE_STATUS 0x100050 +#define DE_STATUS_CSC 1:1 +#define DE_STATUS_CSC_CLEAR 0 +#define DE_STATUS_CSC_NOT_ACTIVE 0 +#define DE_STATUS_CSC_ACTIVE 1 +#define DE_STATUS_2D 0:0 +#define DE_STATUS_2D_CLEAR 0 +#define DE_STATUS_2D_NOT_ACTIVE 0 +#define DE_STATUS_2D_ACTIVE 1 + +/* New register for SM750LE */ +#define DE_STATE1 0x100054 +#define DE_STATE1_DE_ABORT 0:0 +#define DE_STATE1_DE_ABORT_OFF 0 +#define DE_STATE1_DE_ABORT_ON 1 + +#define DE_STATE2 0x100058 +#define DE_STATE2_DE_FIFO 3:3 +#define DE_STATE2_DE_FIFO_NOTEMPTY 0 +#define DE_STATE2_DE_FIFO_EMPTY 1 +#define DE_STATE2_DE_STATUS 2:2 +#define DE_STATE2_DE_STATUS_IDLE 0 +#define DE_STATE2_DE_STATUS_BUSY 1 +#define DE_STATE2_DE_MEM_FIFO 1:1 +#define DE_STATE2_DE_MEM_FIFO_NOTEMPTY 0 +#define DE_STATE2_DE_MEM_FIFO_EMPTY 1 +#define DE_STATE2_DE_RESERVED 0:0 + +/* Color Space Conversion registers. */ + +#define CSC_Y_SOURCE_BASE 0x1000C8 +#define CSC_Y_SOURCE_BASE_EXT 27:27 +#define CSC_Y_SOURCE_BASE_EXT_LOCAL 0 +#define CSC_Y_SOURCE_BASE_EXT_EXTERNAL 1 +#define CSC_Y_SOURCE_BASE_CS 26:26 +#define CSC_Y_SOURCE_BASE_CS_0 0 +#define CSC_Y_SOURCE_BASE_CS_1 1 +#define CSC_Y_SOURCE_BASE_ADDRESS 25:0 + +#define CSC_CONSTANTS 0x1000CC +#define CSC_CONSTANTS_Y 31:24 +#define CSC_CONSTANTS_R 23:16 +#define CSC_CONSTANTS_G 15:8 +#define CSC_CONSTANTS_B 7:0 + +#define CSC_Y_SOURCE_X 0x1000D0 +#define CSC_Y_SOURCE_X_INTEGER 26:16 +#define CSC_Y_SOURCE_X_FRACTION 15:3 + +#define CSC_Y_SOURCE_Y 0x1000D4 +#define CSC_Y_SOURCE_Y_INTEGER 27:16 +#define CSC_Y_SOURCE_Y_FRACTION 15:3 + +#define CSC_U_SOURCE_BASE 0x1000D8 +#define CSC_U_SOURCE_BASE_EXT 27:27 +#define CSC_U_SOURCE_BASE_EXT_LOCAL 0 +#define CSC_U_SOURCE_BASE_EXT_EXTERNAL 1 +#define CSC_U_SOURCE_BASE_CS 26:26 +#define CSC_U_SOURCE_BASE_CS_0 0 +#define CSC_U_SOURCE_BASE_CS_1 1 +#define CSC_U_SOURCE_BASE_ADDRESS 25:0 + +#define CSC_V_SOURCE_BASE 0x1000DC +#define CSC_V_SOURCE_BASE_EXT 27:27 +#define CSC_V_SOURCE_BASE_EXT_LOCAL 0 +#define CSC_V_SOURCE_BASE_EXT_EXTERNAL 1 +#define CSC_V_SOURCE_BASE_CS 26:26 +#define CSC_V_SOURCE_BASE_CS_0 0 +#define CSC_V_SOURCE_BASE_CS_1 1 +#define CSC_V_SOURCE_BASE_ADDRESS 25:0 + +#define CSC_SOURCE_DIMENSION 0x1000E0 +#define CSC_SOURCE_DIMENSION_X 31:16 +#define CSC_SOURCE_DIMENSION_Y 15:0 + +#define CSC_SOURCE_PITCH 0x1000E4 +#define CSC_SOURCE_PITCH_Y 31:16 +#define CSC_SOURCE_PITCH_UV 15:0 + +#define CSC_DESTINATION 0x1000E8 +#define CSC_DESTINATION_WRAP 31:31 +#define CSC_DESTINATION_WRAP_DISABLE 0 +#define CSC_DESTINATION_WRAP_ENABLE 1 +#define CSC_DESTINATION_X 27:16 +#define CSC_DESTINATION_Y 11:0 + +#define CSC_DESTINATION_DIMENSION 0x1000EC +#define CSC_DESTINATION_DIMENSION_X 31:16 +#define CSC_DESTINATION_DIMENSION_Y 15:0 + +#define CSC_DESTINATION_PITCH 0x1000F0 +#define CSC_DESTINATION_PITCH_X 31:16 +#define CSC_DESTINATION_PITCH_Y 15:0 + +#define CSC_SCALE_FACTOR 0x1000F4 +#define CSC_SCALE_FACTOR_HORIZONTAL 31:16 +#define CSC_SCALE_FACTOR_VERTICAL 15:0 + +#define CSC_DESTINATION_BASE 0x1000F8 +#define CSC_DESTINATION_BASE_EXT 27:27 +#define CSC_DESTINATION_BASE_EXT_LOCAL 0 +#define CSC_DESTINATION_BASE_EXT_EXTERNAL 1 +#define CSC_DESTINATION_BASE_CS 26:26 +#define CSC_DESTINATION_BASE_CS_0 0 +#define CSC_DESTINATION_BASE_CS_1 1 +#define CSC_DESTINATION_BASE_ADDRESS 25:0 + +#define CSC_CONTROL 0x1000FC +#define CSC_CONTROL_STATUS 31:31 +#define CSC_CONTROL_STATUS_STOP 0 +#define CSC_CONTROL_STATUS_START 1 +#define CSC_CONTROL_SOURCE_FORMAT 30:28 +#define CSC_CONTROL_SOURCE_FORMAT_YUV422 0 +#define CSC_CONTROL_SOURCE_FORMAT_YUV420I 1 +#define CSC_CONTROL_SOURCE_FORMAT_YUV420 2 +#define CSC_CONTROL_SOURCE_FORMAT_YVU9 3 +#define CSC_CONTROL_SOURCE_FORMAT_IYU1 4 +#define CSC_CONTROL_SOURCE_FORMAT_IYU2 5 +#define CSC_CONTROL_SOURCE_FORMAT_RGB565 6 +#define CSC_CONTROL_SOURCE_FORMAT_RGB8888 7 +#define CSC_CONTROL_DESTINATION_FORMAT 27:26 +#define CSC_CONTROL_DESTINATION_FORMAT_RGB565 0 +#define CSC_CONTROL_DESTINATION_FORMAT_RGB8888 1 +#define CSC_CONTROL_HORIZONTAL_FILTER 25:25 +#define CSC_CONTROL_HORIZONTAL_FILTER_DISABLE 0 +#define CSC_CONTROL_HORIZONTAL_FILTER_ENABLE 1 +#define CSC_CONTROL_VERTICAL_FILTER 24:24 +#define CSC_CONTROL_VERTICAL_FILTER_DISABLE 0 +#define CSC_CONTROL_VERTICAL_FILTER_ENABLE 1 +#define CSC_CONTROL_BYTE_ORDER 23:23 +#define CSC_CONTROL_BYTE_ORDER_YUYV 0 +#define CSC_CONTROL_BYTE_ORDER_UYVY 1 + +#define DE_DATA_PORT 0x110000 diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_reggpio.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_reggpio.h new file mode 100644 index 000000000000..eb08a8000ca0 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_reggpio.h @@ -0,0 +1,239 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* RegGPIO.h --- Voyager GX SDK +* This file contains the definitions for the GPIO registers. +* +*******************************************************************/ +#define GPIO_DATA 0x010000 +#define GPIO_DATA_31 31:31 +#define GPIO_DATA_30 30:30 +#define GPIO_DATA_29 29:29 +#define GPIO_DATA_28 28:28 +#define GPIO_DATA_27 27:27 +#define GPIO_DATA_26 26:26 +#define GPIO_DATA_25 25:25 +#define GPIO_DATA_24 24:24 +#define GPIO_DATA_23 23:23 +#define GPIO_DATA_22 22:22 +#define GPIO_DATA_21 21:21 +#define GPIO_DATA_20 20:20 +#define GPIO_DATA_19 19:19 +#define GPIO_DATA_18 18:18 +#define GPIO_DATA_17 17:17 +#define GPIO_DATA_16 16:16 +#define GPIO_DATA_15 15:15 +#define GPIO_DATA_14 14:14 +#define GPIO_DATA_13 13:13 +#define GPIO_DATA_12 12:12 +#define GPIO_DATA_11 11:11 +#define GPIO_DATA_10 10:10 +#define GPIO_DATA_9 9:9 +#define GPIO_DATA_8 8:8 +#define GPIO_DATA_7 7:7 +#define GPIO_DATA_6 6:6 +#define GPIO_DATA_5 5:5 +#define GPIO_DATA_4 4:4 +#define GPIO_DATA_3 3:3 +#define GPIO_DATA_2 2:2 +#define GPIO_DATA_1 1:1 +#define GPIO_DATA_0 0:0 + +#define GPIO_DATA_DIRECTION 0x010004 +#define GPIO_DATA_DIRECTION_31 31:31 +#define GPIO_DATA_DIRECTION_31_INPUT 0 +#define GPIO_DATA_DIRECTION_31_OUTPUT 1 +#define GPIO_DATA_DIRECTION_30 30:30 +#define GPIO_DATA_DIRECTION_30_INPUT 0 +#define GPIO_DATA_DIRECTION_30_OUTPUT 1 +#define GPIO_DATA_DIRECTION_29 29:29 +#define GPIO_DATA_DIRECTION_29_INPUT 0 +#define GPIO_DATA_DIRECTION_29_OUTPUT 1 +#define GPIO_DATA_DIRECTION_28 28:28 +#define GPIO_DATA_DIRECTION_28_INPUT 0 +#define GPIO_DATA_DIRECTION_28_OUTPUT 1 +#define GPIO_DATA_DIRECTION_27 27:27 +#define GPIO_DATA_DIRECTION_27_INPUT 0 +#define GPIO_DATA_DIRECTION_27_OUTPUT 1 +#define GPIO_DATA_DIRECTION_26 26:26 +#define GPIO_DATA_DIRECTION_26_INPUT 0 +#define GPIO_DATA_DIRECTION_26_OUTPUT 1 +#define GPIO_DATA_DIRECTION_25 25:25 +#define GPIO_DATA_DIRECTION_25_INPUT 0 +#define GPIO_DATA_DIRECTION_25_OUTPUT 1 +#define GPIO_DATA_DIRECTION_24 24:24 +#define GPIO_DATA_DIRECTION_24_INPUT 0 +#define GPIO_DATA_DIRECTION_24_OUTPUT 1 +#define GPIO_DATA_DIRECTION_23 23:23 +#define GPIO_DATA_DIRECTION_23_INPUT 0 +#define GPIO_DATA_DIRECTION_23_OUTPUT 1 +#define GPIO_DATA_DIRECTION_22 22:22 +#define GPIO_DATA_DIRECTION_22_INPUT 0 +#define GPIO_DATA_DIRECTION_22_OUTPUT 1 +#define GPIO_DATA_DIRECTION_21 21:21 +#define GPIO_DATA_DIRECTION_21_INPUT 0 +#define GPIO_DATA_DIRECTION_21_OUTPUT 1 +#define GPIO_DATA_DIRECTION_20 20:20 +#define GPIO_DATA_DIRECTION_20_INPUT 0 +#define GPIO_DATA_DIRECTION_20_OUTPUT 1 +#define GPIO_DATA_DIRECTION_19 19:19 +#define GPIO_DATA_DIRECTION_19_INPUT 0 +#define GPIO_DATA_DIRECTION_19_OUTPUT 1 +#define GPIO_DATA_DIRECTION_18 18:18 +#define GPIO_DATA_DIRECTION_18_INPUT 0 +#define GPIO_DATA_DIRECTION_18_OUTPUT 1 +#define GPIO_DATA_DIRECTION_17 17:17 +#define GPIO_DATA_DIRECTION_17_INPUT 0 +#define GPIO_DATA_DIRECTION_17_OUTPUT 1 +#define GPIO_DATA_DIRECTION_16 16:16 +#define GPIO_DATA_DIRECTION_16_INPUT 0 +#define GPIO_DATA_DIRECTION_16_OUTPUT 1 +#define GPIO_DATA_DIRECTION_15 15:15 +#define GPIO_DATA_DIRECTION_15_INPUT 0 +#define GPIO_DATA_DIRECTION_15_OUTPUT 1 +#define GPIO_DATA_DIRECTION_14 14:14 +#define GPIO_DATA_DIRECTION_14_INPUT 0 +#define GPIO_DATA_DIRECTION_14_OUTPUT 1 +#define GPIO_DATA_DIRECTION_13 13:13 +#define GPIO_DATA_DIRECTION_13_INPUT 0 +#define GPIO_DATA_DIRECTION_13_OUTPUT 1 +#define GPIO_DATA_DIRECTION_12 12:12 +#define GPIO_DATA_DIRECTION_12_INPUT 0 +#define GPIO_DATA_DIRECTION_12_OUTPUT 1 +#define GPIO_DATA_DIRECTION_11 11:11 +#define GPIO_DATA_DIRECTION_11_INPUT 0 +#define GPIO_DATA_DIRECTION_11_OUTPUT 1 +#define GPIO_DATA_DIRECTION_10 10:10 +#define GPIO_DATA_DIRECTION_10_INPUT 0 +#define GPIO_DATA_DIRECTION_10_OUTPUT 1 +#define GPIO_DATA_DIRECTION_9 9:9 +#define GPIO_DATA_DIRECTION_9_INPUT 0 +#define GPIO_DATA_DIRECTION_9_OUTPUT 1 +#define GPIO_DATA_DIRECTION_8 8:8 +#define GPIO_DATA_DIRECTION_8_INPUT 0 +#define GPIO_DATA_DIRECTION_8_OUTPUT 1 +#define GPIO_DATA_DIRECTION_7 7:7 +#define GPIO_DATA_DIRECTION_7_INPUT 0 +#define GPIO_DATA_DIRECTION_7_OUTPUT 1 +#define GPIO_DATA_DIRECTION_6 6:6 +#define GPIO_DATA_DIRECTION_6_INPUT 0 +#define GPIO_DATA_DIRECTION_6_OUTPUT 1 +#define GPIO_DATA_DIRECTION_5 5:5 +#define GPIO_DATA_DIRECTION_5_INPUT 0 +#define GPIO_DATA_DIRECTION_5_OUTPUT 1 +#define GPIO_DATA_DIRECTION_4 4:4 +#define GPIO_DATA_DIRECTION_4_INPUT 0 +#define GPIO_DATA_DIRECTION_4_OUTPUT 1 +#define GPIO_DATA_DIRECTION_3 3:3 +#define GPIO_DATA_DIRECTION_3_INPUT 0 +#define GPIO_DATA_DIRECTION_3_OUTPUT 1 +#define GPIO_DATA_DIRECTION_2 2:2 +#define GPIO_DATA_DIRECTION_2_INPUT 0 +#define GPIO_DATA_DIRECTION_2_OUTPUT 1 +#define GPIO_DATA_DIRECTION_1 1:1 +#define GPIO_DATA_DIRECTION_1_INPUT 0 +#define GPIO_DATA_DIRECTION_1_OUTPUT 1 +#define GPIO_DATA_DIRECTION_0 0:0 +#define GPIO_DATA_DIRECTION_0_INPUT 0 +#define GPIO_DATA_DIRECTION_0_OUTPUT 1 + +#define GPIO_INTERRUPT_SETUP 0x010008 +#define GPIO_INTERRUPT_SETUP_TRIGGER_31 22:22 +#define GPIO_INTERRUPT_SETUP_TRIGGER_31_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_31_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_30 21:21 +#define GPIO_INTERRUPT_SETUP_TRIGGER_30_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_30_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_29 20:20 +#define GPIO_INTERRUPT_SETUP_TRIGGER_29_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_29_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_28 19:19 +#define GPIO_INTERRUPT_SETUP_TRIGGER_28_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_28_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_27 18:18 +#define GPIO_INTERRUPT_SETUP_TRIGGER_27_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_27_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_26 17:17 +#define GPIO_INTERRUPT_SETUP_TRIGGER_26_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_26_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_25 16:16 +#define GPIO_INTERRUPT_SETUP_TRIGGER_25_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_25_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_31 14:14 +#define GPIO_INTERRUPT_SETUP_ACTIVE_31_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_31_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_30 13:13 +#define GPIO_INTERRUPT_SETUP_ACTIVE_30_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_30_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_29 12:12 +#define GPIO_INTERRUPT_SETUP_ACTIVE_29_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_29_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_28 11:11 +#define GPIO_INTERRUPT_SETUP_ACTIVE_28_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_28_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_27 10:10 +#define GPIO_INTERRUPT_SETUP_ACTIVE_27_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_27_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_26 9:9 +#define GPIO_INTERRUPT_SETUP_ACTIVE_26_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_26_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_25 8:8 +#define GPIO_INTERRUPT_SETUP_ACTIVE_25_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_25_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_31 6:6 +#define GPIO_INTERRUPT_SETUP_ENABLE_31_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_31_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_30 5:5 +#define GPIO_INTERRUPT_SETUP_ENABLE_30_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_30_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_29 4:4 +#define GPIO_INTERRUPT_SETUP_ENABLE_29_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_29_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_28 3:3 +#define GPIO_INTERRUPT_SETUP_ENABLE_28_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_28_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_27 2:2 +#define GPIO_INTERRUPT_SETUP_ENABLE_27_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_27_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_26 1:1 +#define GPIO_INTERRUPT_SETUP_ENABLE_26_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_26_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_25 0:0 +#define GPIO_INTERRUPT_SETUP_ENABLE_25_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_25_INTERRUPT 1 + +#define GPIO_INTERRUPT_STATUS 0x01000C +#define GPIO_INTERRUPT_STATUS_31 22:22 +#define GPIO_INTERRUPT_STATUS_31_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_31_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_31_RESET 1 +#define GPIO_INTERRUPT_STATUS_30 21:21 +#define GPIO_INTERRUPT_STATUS_30_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_30_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_30_RESET 1 +#define GPIO_INTERRUPT_STATUS_29 20:20 +#define GPIO_INTERRUPT_STATUS_29_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_29_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_29_RESET 1 +#define GPIO_INTERRUPT_STATUS_28 19:19 +#define GPIO_INTERRUPT_STATUS_28_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_28_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_28_RESET 1 +#define GPIO_INTERRUPT_STATUS_27 18:18 +#define GPIO_INTERRUPT_STATUS_27_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_27_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_27_RESET 1 +#define GPIO_INTERRUPT_STATUS_26 17:17 +#define GPIO_INTERRUPT_STATUS_26_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_26_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_26_RESET 1 +#define GPIO_INTERRUPT_STATUS_25 16:16 +#define GPIO_INTERRUPT_STATUS_25_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_25_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_25_RESET 1 + + diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_regi2c.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_regi2c.h new file mode 100644 index 000000000000..62555c6424c2 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_regi2c.h @@ -0,0 +1,69 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* RegI2C.h --- Voyager GX SDK +* This file contains the definitions for the HW I2C registers. +* +*******************************************************************/ +#define I2C_BYTE_COUNT 0x010040 +#define I2C_BYTE_COUNT_COUNT 3:0 + +#define I2C_CTRL 0x010041 +#define I2C_CTRL_INT 4:4 +#define I2C_CTRL_INT_DISABLE 0 +#define I2C_CTRL_INT_ENABLE 1 +#define I2C_CTRL_CTRL 2:2 +#define I2C_CTRL_CTRL_STOP 0 +#define I2C_CTRL_CTRL_START 1 +#define I2C_CTRL_MODE 1:1 +#define I2C_CTRL_MODE_STANDARD 0 +#define I2C_CTRL_MODE_FAST 1 +#define I2C_CTRL_EN 0:0 +#define I2C_CTRL_EN_DISABLE 0 +#define I2C_CTRL_EN_ENABLE 1 + +#define I2C_STATUS 0x010042 +#define I2C_STATUS_TX 3:3 +#define I2C_STATUS_TX_PROGRESS 0 +#define I2C_STATUS_TX_COMPLETED 1 +#define I2C_STATUS_ERR 2:2 +#define I2C_STATUS_ERR_NORMAL 0 +#define I2C_STATUS_ERR_ERROR 1 +#define I2C_STATUS_ERR_CLEAR 0 +#define I2C_STATUS_ACK 1:1 +#define I2C_STATUS_ACK_RECEIVED 0 +#define I2C_STATUS_ACK_NOT 1 +#define I2C_STATUS_BSY 0:0 +#define I2C_STATUS_BSY_IDLE 0 +#define I2C_STATUS_BSY_BUSY 1 + +#define I2C_RESET 0x010042 +#define I2C_RESET_BUS_ERROR 2:2 +#define I2C_RESET_BUS_ERROR_CLEAR 0 + +#define I2C_SLAVE_ADDRESS 0x010043 +#define I2C_SLAVE_ADDRESS_ADDRESS 7:1 +#define I2C_SLAVE_ADDRESS_RW 0:0 +#define I2C_SLAVE_ADDRESS_RW_W 0 +#define I2C_SLAVE_ADDRESS_RW_R 1 + +#define I2C_DATA0 0x010044 +#define I2C_DATA1 0x010045 +#define I2C_DATA2 0x010046 +#define I2C_DATA3 0x010047 +#define I2C_DATA4 0x010048 +#define I2C_DATA5 0x010049 +#define I2C_DATA6 0x01004A +#define I2C_DATA7 0x01004B +#define I2C_DATA8 0x01004C +#define I2C_DATA9 0x01004D +#define I2C_DATA10 0x01004E +#define I2C_DATA11 0x01004F +#define I2C_DATA12 0x010050 +#define I2C_DATA13 0x010051 +#define I2C_DATA14 0x010052 +#define I2C_DATA15 0x010053 diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_regsc.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_regsc.h new file mode 100644 index 000000000000..e70d39b6bfd5 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_regsc.h @@ -0,0 +1,900 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* RegSC.h --- SM718 SDK +* This file contains the definitions for the System Configuration registers. +* +*******************************************************************/ +#define SYSTEM_CTRL 0x000000 +#define SYSTEM_CTRL_DPMS 31:30 +#define SYSTEM_CTRL_DPMS_VPHP 0 +#define SYSTEM_CTRL_DPMS_VPHN 1 +#define SYSTEM_CTRL_DPMS_VNHP 2 +#define SYSTEM_CTRL_DPMS_VNHN 3 +#define SYSTEM_CTRL_PCI_BURST 29:29 +#define SYSTEM_CTRL_PCI_BURST_OFF 0 +#define SYSTEM_CTRL_PCI_BURST_ON 1 +#define SYSTEM_CTRL_PCI_MASTER 25:25 +#define SYSTEM_CTRL_PCI_MASTER_OFF 0 +#define SYSTEM_CTRL_PCI_MASTER_ON 1 +#define SYSTEM_CTRL_LATENCY_TIMER 24:24 +#define SYSTEM_CTRL_LATENCY_TIMER_ON 0 +#define SYSTEM_CTRL_LATENCY_TIMER_OFF 1 +#define SYSTEM_CTRL_DE_FIFO 23:23 +#define SYSTEM_CTRL_DE_FIFO_NOTEMPTY 0 +#define SYSTEM_CTRL_DE_FIFO_EMPTY 1 +#define SYSTEM_CTRL_DE_STATUS 22:22 +#define SYSTEM_CTRL_DE_STATUS_IDLE 0 +#define SYSTEM_CTRL_DE_STATUS_BUSY 1 +#define SYSTEM_CTRL_DE_MEM_FIFO 21:21 +#define SYSTEM_CTRL_DE_MEM_FIFO_NOTEMPTY 0 +#define SYSTEM_CTRL_DE_MEM_FIFO_EMPTY 1 +#define SYSTEM_CTRL_CSC_STATUS 20:20 +#define SYSTEM_CTRL_CSC_STATUS_IDLE 0 +#define SYSTEM_CTRL_CSC_STATUS_BUSY 1 +#define SYSTEM_CTRL_SECONDARY_VSYNC 19:19 +#define SYSTEM_CTRL_SECONDARY_VSYNC_INACTIVE 0 +#define SYSTEM_CTRL_SECONDARY_VSYNC_ACTIVE 1 +#define SYSTEM_CTRL_PRIMARY_VSYNC 18:18 +#define SYSTEM_CTRL_PRIMARY_VSYNC_INACTIVE 0 +#define SYSTEM_CTRL_PRIMARY_VSYNC_ACTIVE 1 +#define SYSTEM_CTRL_CURRENT_BUFFER 17:17 +#define SYSTEM_CTRL_CURRENT_BUFFER_NORMAL 0 +#define SYSTEM_CTRL_CURRENT_BUFFER_FLIP_PENDING 1 +#define SYSTEM_CTRL_DMA_STATUS 16:16 +#define SYSTEM_CTRL_DMA_STATUS_IDLE 0 +#define SYSTEM_CTRL_DMA_STATUS_BUSY 1 +#define SYSTEM_CTRL_PCI_BURST_READ 15:15 +#define SYSTEM_CTRL_PCI_BURST_READ_OFF 0 +#define SYSTEM_CTRL_PCI_BURST_READ_ON 1 +#define SYSTEM_CTRL_DE_ABORT 13:13 +#define SYSTEM_CTRL_DE_ABORT_OFF 0 +#define SYSTEM_CTRL_DE_ABORT_ON 1 +#define SYSTEM_CTRL_PCI_SUBSYS_ID_LOCK 11:11 +#define SYSTEM_CTRL_PCI_SUBSYS_ID_LOCK_OFF 0 +#define SYSTEM_CTRL_PCI_SUBSYS_ID_LOCK_ON 1 +#define SYSTEM_CTRL_PCI_RETRY 7:7 +#define SYSTEM_CTRL_PCI_RETRY_ON 0 +#define SYSTEM_CTRL_PCI_RETRY_OFF 1 +#define SYSTEM_CTRL_PCI_SLAVE_BURST_READ_SIZE 5:4 +#define SYSTEM_CTRL_PCI_SLAVE_BURST_READ_SIZE_1 0 +#define SYSTEM_CTRL_PCI_SLAVE_BURST_READ_SIZE_2 1 +#define SYSTEM_CTRL_PCI_SLAVE_BURST_READ_SIZE_4 2 +#define SYSTEM_CTRL_PCI_SLAVE_BURST_READ_SIZE_8 3 +#define SYSTEM_CTRL_CRT_TRISTATE 3:3 +#define SYSTEM_CTRL_CRT_TRISTATE_OFF 0 +#define SYSTEM_CTRL_CRT_TRISTATE_ON 1 +#define SYSTEM_CTRL_PCIMEM_TRISTATE 2:2 +#define SYSTEM_CTRL_PCIMEM_TRISTATE_OFF 0 +#define SYSTEM_CTRL_PCIMEM_TRISTATE_ON 1 +#define SYSTEM_CTRL_LOCALMEM_TRISTATE 1:1 +#define SYSTEM_CTRL_LOCALMEM_TRISTATE_OFF 0 +#define SYSTEM_CTRL_LOCALMEM_TRISTATE_ON 1 +#define SYSTEM_CTRL_PANEL_TRISTATE 0:0 +#define SYSTEM_CTRL_PANEL_TRISTATE_OFF 0 +#define SYSTEM_CTRL_PANEL_TRISTATE_ON 1 + +#define MISC_CTRL 0x000004 +#define MISC_CTRL_DRAM_RERESH_COUNT 27:27 +#define MISC_CTRL_DRAM_RERESH_COUNT_1ROW 0 +#define MISC_CTRL_DRAM_RERESH_COUNT_3ROW 1 +#define MISC_CTRL_DRAM_REFRESH_TIME 26:25 +#define MISC_CTRL_DRAM_REFRESH_TIME_8 0 +#define MISC_CTRL_DRAM_REFRESH_TIME_16 1 +#define MISC_CTRL_DRAM_REFRESH_TIME_32 2 +#define MISC_CTRL_DRAM_REFRESH_TIME_64 3 +#define MISC_CTRL_INT_OUTPUT 24:24 +#define MISC_CTRL_INT_OUTPUT_NORMAL 0 +#define MISC_CTRL_INT_OUTPUT_INVERT 1 +#define MISC_CTRL_PLL_CLK_COUNT 23:23 +#define MISC_CTRL_PLL_CLK_COUNT_OFF 0 +#define MISC_CTRL_PLL_CLK_COUNT_ON 1 +#define MISC_CTRL_DAC_POWER 20:20 +#define MISC_CTRL_DAC_POWER_ON 0 +#define MISC_CTRL_DAC_POWER_OFF 1 +#define MISC_CTRL_CLK_SELECT 16:16 +#define MISC_CTRL_CLK_SELECT_OSC 0 +#define MISC_CTRL_CLK_SELECT_TESTCLK 1 +#define MISC_CTRL_DRAM_COLUMN_SIZE 15:14 +#define MISC_CTRL_DRAM_COLUMN_SIZE_256 0 +#define MISC_CTRL_DRAM_COLUMN_SIZE_512 1 +#define MISC_CTRL_DRAM_COLUMN_SIZE_1024 2 +#define MISC_CTRL_LOCALMEM_SIZE 13:12 +#define MISC_CTRL_LOCALMEM_SIZE_8M 3 +#define MISC_CTRL_LOCALMEM_SIZE_16M 0 +#define MISC_CTRL_LOCALMEM_SIZE_32M 1 +#define MISC_CTRL_LOCALMEM_SIZE_64M 2 +#define MISC_CTRL_DRAM_TWTR 11:11 +#define MISC_CTRL_DRAM_TWTR_2CLK 0 +#define MISC_CTRL_DRAM_TWTR_1CLK 1 +#define MISC_CTRL_DRAM_TWR 10:10 +#define MISC_CTRL_DRAM_TWR_3CLK 0 +#define MISC_CTRL_DRAM_TWR_2CLK 1 +#define MISC_CTRL_DRAM_TRP 9:9 +#define MISC_CTRL_DRAM_TRP_3CLK 0 +#define MISC_CTRL_DRAM_TRP_4CLK 1 +#define MISC_CTRL_DRAM_TRFC 8:8 +#define MISC_CTRL_DRAM_TRFC_12CLK 0 +#define MISC_CTRL_DRAM_TRFC_14CLK 1 +#define MISC_CTRL_DRAM_TRAS 7:7 +#define MISC_CTRL_DRAM_TRAS_7CLK 0 +#define MISC_CTRL_DRAM_TRAS_8CLK 1 +#define MISC_CTRL_LOCALMEM_RESET 6:6 +#define MISC_CTRL_LOCALMEM_RESET_RESET 0 +#define MISC_CTRL_LOCALMEM_RESET_NORMAL 1 +#define MISC_CTRL_LOCALMEM_STATE 5:5 +#define MISC_CTRL_LOCALMEM_STATE_ACTIVE 0 +#define MISC_CTRL_LOCALMEM_STATE_INACTIVE 1 +#define MISC_CTRL_CPU_CAS_LATENCY 4:4 +#define MISC_CTRL_CPU_CAS_LATENCY_2CLK 0 +#define MISC_CTRL_CPU_CAS_LATENCY_3CLK 1 +#define MISC_CTRL_DLL 3:3 +#define MISC_CTRL_DLL_ON 0 +#define MISC_CTRL_DLL_OFF 1 +#define MISC_CTRL_DRAM_OUTPUT 2:2 +#define MISC_CTRL_DRAM_OUTPUT_LOW 0 +#define MISC_CTRL_DRAM_OUTPUT_HIGH 1 +#define MISC_CTRL_LOCALMEM_BUS_SIZE 1:1 +#define MISC_CTRL_LOCALMEM_BUS_SIZE_32 0 +#define MISC_CTRL_LOCALMEM_BUS_SIZE_64 1 +#define MISC_CTRL_EMBEDDED_LOCALMEM 0:0 +#define MISC_CTRL_EMBEDDED_LOCALMEM_ON 0 +#define MISC_CTRL_EMBEDDED_LOCALMEM_OFF 1 + +#define GPIO_MUX 0x000008 +#define GPIO_MUX_31 31:31 +#define GPIO_MUX_31_GPIO 0 +#define GPIO_MUX_31_I2C 1 +#define GPIO_MUX_30 30:30 +#define GPIO_MUX_30_GPIO 0 +#define GPIO_MUX_30_I2C 1 +#define GPIO_MUX_29 29:29 +#define GPIO_MUX_29_GPIO 0 +#define GPIO_MUX_29_SSP1 1 +#define GPIO_MUX_28 28:28 +#define GPIO_MUX_28_GPIO 0 +#define GPIO_MUX_28_SSP1 1 +#define GPIO_MUX_27 27:27 +#define GPIO_MUX_27_GPIO 0 +#define GPIO_MUX_27_SSP1 1 +#define GPIO_MUX_26 26:26 +#define GPIO_MUX_26_GPIO 0 +#define GPIO_MUX_26_SSP1 1 +#define GPIO_MUX_25 25:25 +#define GPIO_MUX_25_GPIO 0 +#define GPIO_MUX_25_SSP1 1 +#define GPIO_MUX_24 24:24 +#define GPIO_MUX_24_GPIO 0 +#define GPIO_MUX_24_SSP0 1 +#define GPIO_MUX_23 23:23 +#define GPIO_MUX_23_GPIO 0 +#define GPIO_MUX_23_SSP0 1 +#define GPIO_MUX_22 22:22 +#define GPIO_MUX_22_GPIO 0 +#define GPIO_MUX_22_SSP0 1 +#define GPIO_MUX_21 21:21 +#define GPIO_MUX_21_GPIO 0 +#define GPIO_MUX_21_SSP0 1 +#define GPIO_MUX_20 20:20 +#define GPIO_MUX_20_GPIO 0 +#define GPIO_MUX_20_SSP0 1 +#define GPIO_MUX_19 19:19 +#define GPIO_MUX_19_GPIO 0 +#define GPIO_MUX_19_PWM 1 +#define GPIO_MUX_18 18:18 +#define GPIO_MUX_18_GPIO 0 +#define GPIO_MUX_18_PWM 1 +#define GPIO_MUX_17 17:17 +#define GPIO_MUX_17_GPIO 0 +#define GPIO_MUX_17_PWM 1 +#define GPIO_MUX_16 16:16 +#define GPIO_MUX_16_GPIO_ZVPORT 0 +#define GPIO_MUX_16_TEST_DATA 1 +#define GPIO_MUX_15 15:15 +#define GPIO_MUX_15_GPIO_ZVPORT 0 +#define GPIO_MUX_15_TEST_DATA 1 +#define GPIO_MUX_14 14:14 +#define GPIO_MUX_14_GPIO_ZVPORT 0 +#define GPIO_MUX_14_TEST_DATA 1 +#define GPIO_MUX_13 13:13 +#define GPIO_MUX_13_GPIO_ZVPORT 0 +#define GPIO_MUX_13_TEST_DATA 1 +#define GPIO_MUX_12 12:12 +#define GPIO_MUX_12_GPIO_ZVPORT 0 +#define GPIO_MUX_12_TEST_DATA 1 +#define GPIO_MUX_11 11:11 +#define GPIO_MUX_11_GPIO_ZVPORT 0 +#define GPIO_MUX_11_TEST_DATA 1 +#define GPIO_MUX_10 10:10 +#define GPIO_MUX_10_GPIO_ZVPORT 0 +#define GPIO_MUX_10_TEST_DATA 1 +#define GPIO_MUX_9 9:9 +#define GPIO_MUX_9_GPIO_ZVPORT 0 +#define GPIO_MUX_9_TEST_DATA 1 +#define GPIO_MUX_8 8:8 +#define GPIO_MUX_8_GPIO_ZVPORT 0 +#define GPIO_MUX_8_TEST_DATA 1 +#define GPIO_MUX_7 7:7 +#define GPIO_MUX_7_GPIO_ZVPORT 0 +#define GPIO_MUX_7_TEST_DATA 1 +#define GPIO_MUX_6 6:6 +#define GPIO_MUX_6_GPIO_ZVPORT 0 +#define GPIO_MUX_6_TEST_DATA 1 +#define GPIO_MUX_5 5:5 +#define GPIO_MUX_5_GPIO_ZVPORT 0 +#define GPIO_MUX_5_TEST_DATA 1 +#define GPIO_MUX_4 4:4 +#define GPIO_MUX_4_GPIO_ZVPORT 0 +#define GPIO_MUX_4_TEST_DATA 1 +#define GPIO_MUX_3 3:3 +#define GPIO_MUX_3_GPIO_ZVPORT 0 +#define GPIO_MUX_3_TEST_DATA 1 +#define GPIO_MUX_2 2:2 +#define GPIO_MUX_2_GPIO_ZVPORT 0 +#define GPIO_MUX_2_TEST_DATA 1 +#define GPIO_MUX_1 1:1 +#define GPIO_MUX_1_GPIO_ZVPORT 0 +#define GPIO_MUX_1_TEST_DATA 1 +#define GPIO_MUX_0 0:0 +#define GPIO_MUX_0_GPIO_ZVPORT 0 +#define GPIO_MUX_0_TEST_DATA 1 + +#define LOCALMEM_ARBITRATION 0x00000C +#define LOCALMEM_ARBITRATION_ROTATE 28:28 +#define LOCALMEM_ARBITRATION_ROTATE_OFF 0 +#define LOCALMEM_ARBITRATION_ROTATE_ON 1 +#define LOCALMEM_ARBITRATION_VGA 26:24 +#define LOCALMEM_ARBITRATION_VGA_OFF 0 +#define LOCALMEM_ARBITRATION_VGA_PRIORITY_1 1 +#define LOCALMEM_ARBITRATION_VGA_PRIORITY_2 2 +#define LOCALMEM_ARBITRATION_VGA_PRIORITY_3 3 +#define LOCALMEM_ARBITRATION_VGA_PRIORITY_4 4 +#define LOCALMEM_ARBITRATION_VGA_PRIORITY_5 5 +#define LOCALMEM_ARBITRATION_VGA_PRIORITY_6 6 +#define LOCALMEM_ARBITRATION_VGA_PRIORITY_7 7 +#define LOCALMEM_ARBITRATION_DMA 22:20 +#define LOCALMEM_ARBITRATION_DMA_OFF 0 +#define LOCALMEM_ARBITRATION_DMA_PRIORITY_1 1 +#define LOCALMEM_ARBITRATION_DMA_PRIORITY_2 2 +#define LOCALMEM_ARBITRATION_DMA_PRIORITY_3 3 +#define LOCALMEM_ARBITRATION_DMA_PRIORITY_4 4 +#define LOCALMEM_ARBITRATION_DMA_PRIORITY_5 5 +#define LOCALMEM_ARBITRATION_DMA_PRIORITY_6 6 +#define LOCALMEM_ARBITRATION_DMA_PRIORITY_7 7 +#define LOCALMEM_ARBITRATION_ZVPORT1 18:16 +#define LOCALMEM_ARBITRATION_ZVPORT1_OFF 0 +#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_1 1 +#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_2 2 +#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_3 3 +#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_4 4 +#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_5 5 +#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_6 6 +#define LOCALMEM_ARBITRATION_ZVPORT1_PRIORITY_7 7 +#define LOCALMEM_ARBITRATION_ZVPORT0 14:12 +#define LOCALMEM_ARBITRATION_ZVPORT0_OFF 0 +#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_1 1 +#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_2 2 +#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_3 3 +#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_4 4 +#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_5 5 +#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_6 6 +#define LOCALMEM_ARBITRATION_ZVPORT0_PRIORITY_7 7 +#define LOCALMEM_ARBITRATION_VIDEO 10:8 +#define LOCALMEM_ARBITRATION_VIDEO_OFF 0 +#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_1 1 +#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_2 2 +#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_3 3 +#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_4 4 +#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_5 5 +#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_6 6 +#define LOCALMEM_ARBITRATION_VIDEO_PRIORITY_7 7 +#define LOCALMEM_ARBITRATION_PANEL 6:4 +#define LOCALMEM_ARBITRATION_PANEL_OFF 0 +#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_1 1 +#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_2 2 +#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_3 3 +#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_4 4 +#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_5 5 +#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_6 6 +#define LOCALMEM_ARBITRATION_PANEL_PRIORITY_7 7 +#define LOCALMEM_ARBITRATION_CRT 2:0 +#define LOCALMEM_ARBITRATION_CRT_OFF 0 +#define LOCALMEM_ARBITRATION_CRT_PRIORITY_1 1 +#define LOCALMEM_ARBITRATION_CRT_PRIORITY_2 2 +#define LOCALMEM_ARBITRATION_CRT_PRIORITY_3 3 +#define LOCALMEM_ARBITRATION_CRT_PRIORITY_4 4 +#define LOCALMEM_ARBITRATION_CRT_PRIORITY_5 5 +#define LOCALMEM_ARBITRATION_CRT_PRIORITY_6 6 +#define LOCALMEM_ARBITRATION_CRT_PRIORITY_7 7 + +#define PCIMEM_ARBITRATION 0x000010 +#define PCIMEM_ARBITRATION_ROTATE 28:28 +#define PCIMEM_ARBITRATION_ROTATE_OFF 0 +#define PCIMEM_ARBITRATION_ROTATE_ON 1 +#define PCIMEM_ARBITRATION_VGA 26:24 +#define PCIMEM_ARBITRATION_VGA_OFF 0 +#define PCIMEM_ARBITRATION_VGA_PRIORITY_1 1 +#define PCIMEM_ARBITRATION_VGA_PRIORITY_2 2 +#define PCIMEM_ARBITRATION_VGA_PRIORITY_3 3 +#define PCIMEM_ARBITRATION_VGA_PRIORITY_4 4 +#define PCIMEM_ARBITRATION_VGA_PRIORITY_5 5 +#define PCIMEM_ARBITRATION_VGA_PRIORITY_6 6 +#define PCIMEM_ARBITRATION_VGA_PRIORITY_7 7 +#define PCIMEM_ARBITRATION_DMA 22:20 +#define PCIMEM_ARBITRATION_DMA_OFF 0 +#define PCIMEM_ARBITRATION_DMA_PRIORITY_1 1 +#define PCIMEM_ARBITRATION_DMA_PRIORITY_2 2 +#define PCIMEM_ARBITRATION_DMA_PRIORITY_3 3 +#define PCIMEM_ARBITRATION_DMA_PRIORITY_4 4 +#define PCIMEM_ARBITRATION_DMA_PRIORITY_5 5 +#define PCIMEM_ARBITRATION_DMA_PRIORITY_6 6 +#define PCIMEM_ARBITRATION_DMA_PRIORITY_7 7 +#define PCIMEM_ARBITRATION_ZVPORT1 18:16 +#define PCIMEM_ARBITRATION_ZVPORT1_OFF 0 +#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_1 1 +#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_2 2 +#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_3 3 +#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_4 4 +#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_5 5 +#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_6 6 +#define PCIMEM_ARBITRATION_ZVPORT1_PRIORITY_7 7 +#define PCIMEM_ARBITRATION_ZVPORT0 14:12 +#define PCIMEM_ARBITRATION_ZVPORT0_OFF 0 +#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_1 1 +#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_2 2 +#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_3 3 +#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_4 4 +#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_5 5 +#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_6 6 +#define PCIMEM_ARBITRATION_ZVPORT0_PRIORITY_7 7 +#define PCIMEM_ARBITRATION_VIDEO 10:8 +#define PCIMEM_ARBITRATION_VIDEO_OFF 0 +#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_1 1 +#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_2 2 +#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_3 3 +#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_4 4 +#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_5 5 +#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_6 6 +#define PCIMEM_ARBITRATION_VIDEO_PRIORITY_7 7 +#define PCIMEM_ARBITRATION_PANEL 6:4 +#define PCIMEM_ARBITRATION_PANEL_OFF 0 +#define PCIMEM_ARBITRATION_PANEL_PRIORITY_1 1 +#define PCIMEM_ARBITRATION_PANEL_PRIORITY_2 2 +#define PCIMEM_ARBITRATION_PANEL_PRIORITY_3 3 +#define PCIMEM_ARBITRATION_PANEL_PRIORITY_4 4 +#define PCIMEM_ARBITRATION_PANEL_PRIORITY_5 5 +#define PCIMEM_ARBITRATION_PANEL_PRIORITY_6 6 +#define PCIMEM_ARBITRATION_PANEL_PRIORITY_7 7 +#define PCIMEM_ARBITRATION_CRT 2:0 +#define PCIMEM_ARBITRATION_CRT_OFF 0 +#define PCIMEM_ARBITRATION_CRT_PRIORITY_1 1 +#define PCIMEM_ARBITRATION_CRT_PRIORITY_2 2 +#define PCIMEM_ARBITRATION_CRT_PRIORITY_3 3 +#define PCIMEM_ARBITRATION_CRT_PRIORITY_4 4 +#define PCIMEM_ARBITRATION_CRT_PRIORITY_5 5 +#define PCIMEM_ARBITRATION_CRT_PRIORITY_6 6 +#define PCIMEM_ARBITRATION_CRT_PRIORITY_7 7 + +#define RAW_INT 0x000020 +#define RAW_INT_ZVPORT1_VSYNC 4:4 +#define RAW_INT_ZVPORT1_VSYNC_INACTIVE 0 +#define RAW_INT_ZVPORT1_VSYNC_ACTIVE 1 +#define RAW_INT_ZVPORT1_VSYNC_CLEAR 1 +#define RAW_INT_ZVPORT0_VSYNC 3:3 +#define RAW_INT_ZVPORT0_VSYNC_INACTIVE 0 +#define RAW_INT_ZVPORT0_VSYNC_ACTIVE 1 +#define RAW_INT_ZVPORT0_VSYNC_CLEAR 1 +#define RAW_INT_SECONDARY_VSYNC 2:2 +#define RAW_INT_SECONDARY_VSYNC_INACTIVE 0 +#define RAW_INT_SECONDARY_VSYNC_ACTIVE 1 +#define RAW_INT_SECONDARY_VSYNC_CLEAR 1 +#define RAW_INT_PRIMARY_VSYNC 1:1 +#define RAW_INT_PRIMARY_VSYNC_INACTIVE 0 +#define RAW_INT_PRIMARY_VSYNC_ACTIVE 1 +#define RAW_INT_PRIMARY_VSYNC_CLEAR 1 +#define RAW_INT_VGA_VSYNC 0:0 +#define RAW_INT_VGA_VSYNC_INACTIVE 0 +#define RAW_INT_VGA_VSYNC_ACTIVE 1 +#define RAW_INT_VGA_VSYNC_CLEAR 1 + +#define INT_STATUS 0x000024 +#define INT_STATUS_GPIO31 31:31 +#define INT_STATUS_GPIO31_INACTIVE 0 +#define INT_STATUS_GPIO31_ACTIVE 1 +#define INT_STATUS_GPIO30 30:30 +#define INT_STATUS_GPIO30_INACTIVE 0 +#define INT_STATUS_GPIO30_ACTIVE 1 +#define INT_STATUS_GPIO29 29:29 +#define INT_STATUS_GPIO29_INACTIVE 0 +#define INT_STATUS_GPIO29_ACTIVE 1 +#define INT_STATUS_GPIO28 28:28 +#define INT_STATUS_GPIO28_INACTIVE 0 +#define INT_STATUS_GPIO28_ACTIVE 1 +#define INT_STATUS_GPIO27 27:27 +#define INT_STATUS_GPIO27_INACTIVE 0 +#define INT_STATUS_GPIO27_ACTIVE 1 +#define INT_STATUS_GPIO26 26:26 +#define INT_STATUS_GPIO26_INACTIVE 0 +#define INT_STATUS_GPIO26_ACTIVE 1 +#define INT_STATUS_GPIO25 25:25 +#define INT_STATUS_GPIO25_INACTIVE 0 +#define INT_STATUS_GPIO25_ACTIVE 1 +#define INT_STATUS_I2C 12:12 +#define INT_STATUS_I2C_INACTIVE 0 +#define INT_STATUS_I2C_ACTIVE 1 +#define INT_STATUS_PWM 11:11 +#define INT_STATUS_PWM_INACTIVE 0 +#define INT_STATUS_PWM_ACTIVE 1 +#if 1 /* SM750 new definition (DMA0 is removed in SM750), therefore, the interrupt is + moved to the DMA0 location. + */ + #define INT_STATUS_DMA1 9:9 + #define INT_STATUS_DMA1_INACTIVE 0 + #define INT_STATUS_DMA1_ACTIVE 1 +#else + #define INT_STATUS_DMA1 10:10 + #define INT_STATUS_DMA1_INACTIVE 0 + #define INT_STATUS_DMA1_ACTIVE 1 + #define INT_STATUS_DMA0 9:9 + #define INT_STATUS_DMA0_INACTIVE 0 + #define INT_STATUS_DMA0_ACTIVE 1 +#endif +#define INT_STATUS_PCI 8:8 +#define INT_STATUS_PCI_INACTIVE 0 +#define INT_STATUS_PCI_ACTIVE 1 +#define INT_STATUS_SSP1 7:7 +#define INT_STATUS_SSP1_INACTIVE 0 +#define INT_STATUS_SSP1_ACTIVE 1 +#define INT_STATUS_SSP0 6:6 +#define INT_STATUS_SSP0_INACTIVE 0 +#define INT_STATUS_SSP0_ACTIVE 1 +#define INT_STATUS_DE 5:5 +#define INT_STATUS_DE_INACTIVE 0 +#define INT_STATUS_DE_ACTIVE 1 +#define INT_STATUS_ZVPORT1_VSYNC 4:4 +#define INT_STATUS_ZVPORT1_VSYNC_INACTIVE 0 +#define INT_STATUS_ZVPORT1_VSYNC_ACTIVE 1 +#define INT_STATUS_ZVPORT0_VSYNC 3:3 +#define INT_STATUS_ZVPORT0_VSYNC_INACTIVE 0 +#define INT_STATUS_ZVPORT0_VSYNC_ACTIVE 1 +#define INT_STATUS_SECONDARY_VSYNC 2:2 +#define INT_STATUS_SECONDARY_VSYNC_INACTIVE 0 +#define INT_STATUS_SECONDARY_VSYNC_ACTIVE 1 +#define INT_STATUS_PRIMARY_VSYNC 1:1 +#define INT_STATUS_PRIMARY_VSYNC_INACTIVE 0 +#define INT_STATUS_PRIMARY_VSYNC_ACTIVE 1 +#define INT_STATUS_VGA_VSYNC 0:0 +#define INT_STATUS_VGA_VSYNC_INACTIVE 0 +#define INT_STATUS_VGA_VSYNC_ACTIVE 1 + +#define INT_MASK 0x000028 +#define INT_MASK_GPIO31 31:31 +#define INT_MASK_GPIO31_DISABLE 0 +#define INT_MASK_GPIO31_ENABLE 1 +#define INT_MASK_GPIO30 30:30 +#define INT_MASK_GPIO30_DISABLE 0 +#define INT_MASK_GPIO30_ENABLE 1 +#define INT_MASK_GPIO29 29:29 +#define INT_MASK_GPIO29_DISABLE 0 +#define INT_MASK_GPIO29_ENABLE 1 +#define INT_MASK_GPIO28 28:28 +#define INT_MASK_GPIO28_DISABLE 0 +#define INT_MASK_GPIO28_ENABLE 1 +#define INT_MASK_GPIO27 27:27 +#define INT_MASK_GPIO27_DISABLE 0 +#define INT_MASK_GPIO27_ENABLE 1 +#define INT_MASK_GPIO26 26:26 +#define INT_MASK_GPIO26_DISABLE 0 +#define INT_MASK_GPIO26_ENABLE 1 +#define INT_MASK_GPIO25 25:25 +#define INT_MASK_GPIO25_DISABLE 0 +#define INT_MASK_GPIO25_ENABLE 1 +#define INT_MASK_I2C 12:12 +#define INT_MASK_I2C_DISABLE 0 +#define INT_MASK_I2C_ENABLE 1 +#define INT_MASK_PWM 11:11 +#define INT_MASK_PWM_DISABLE 0 +#define INT_MASK_PWM_ENABLE 1 +#if 1 /* SM750 new definition (DMA0 is removed in SM750), therefore, the interrupt is + moved to the DMA0 location. + */ + #define INT_MASK_DMA1 9:9 + #define INT_MASK_DMA1_DISABLE 0 + #define INT_MASK_DMA1_ENABLE 1 +#else + #define INT_MASK_DMA1 10:10 + #define INT_MASK_DMA1_DISABLE 0 + #define INT_MASK_DMA1_ENABLE 1 + #define INT_MASK_DMA 9:9 + #define INT_MASK_DMA_DISABLE 0 + #define INT_MASK_DMA_ENABLE 1 +#endif +#define INT_MASK_PCI 8:8 +#define INT_MASK_PCI_DISABLE 0 +#define INT_MASK_PCI_ENABLE 1 +#define INT_MASK_SSP1 7:7 +#define INT_MASK_SSP1_DISABLE 0 +#define INT_MASK_SSP1_ENABLE 1 +#define INT_MASK_SSP0 6:6 +#define INT_MASK_SSP0_DISABLE 0 +#define INT_MASK_SSP0_ENABLE 1 +#define INT_MASK_DE 5:5 +#define INT_MASK_DE_DISABLE 0 +#define INT_MASK_DE_ENABLE 1 +#define INT_MASK_ZVPORT1_VSYNC 4:4 +#define INT_MASK_ZVPORT1_VSYNC_DISABLE 0 +#define INT_MASK_ZVPORT1_VSYNC_ENABLE 1 +#define INT_MASK_ZVPORT0_VSYNC 3:3 +#define INT_MASK_ZVPORT0_VSYNC_DISABLE 0 +#define INT_MASK_ZVPORT0_VSYNC_ENABLE 1 +#define INT_MASK_SECONDARY_VSYNC 2:2 +#define INT_MASK_SECONDARY_VSYNC_DISABLE 0 +#define INT_MASK_SECONDARY_VSYNC_ENABLE 1 +#define INT_MASK_PRIMARY_VSYNC 1:1 +#define INT_MASK_PRIMARY_VSYNC_DISABLE 0 +#define INT_MASK_PRIMARY_VSYNC_ENABLE 1 +#define INT_MASK_VGA_VSYNC 0:0 +#define INT_MASK_VGA_VSYNC_DISABLE 0 +#define INT_MASK_VGA_VSYNC_ENABLE 1 + +#define CURRENT_GATE 0x000040 +#define CURRENT_GATE_MCLK 15:14 +#define CURRENT_GATE_MCLK_DIV_3 0 +#define CURRENT_GATE_MCLK_DIV_4 1 +#define CURRENT_GATE_MCLK_DIV_6 2 +#define CURRENT_GATE_MCLK_DIV_8 3 +#define CURRENT_GATE_M2XCLK 13:12 +#define CURRENT_GATE_M2XCLK_DIV_1 0 +#define CURRENT_GATE_M2XCLK_DIV_2 1 +#define CURRENT_GATE_M2XCLK_DIV_3 2 +#define CURRENT_GATE_M2XCLK_DIV_4 3 +#define CURRENT_GATE_VGA 10:10 +#define CURRENT_GATE_VGA_OFF 0 +#define CURRENT_GATE_VGA_ON 1 +#define CURRENT_GATE_PWM 9:9 +#define CURRENT_GATE_PWM_OFF 0 +#define CURRENT_GATE_PWM_ON 1 +#define CURRENT_GATE_I2C 8:8 +#define CURRENT_GATE_I2C_OFF 0 +#define CURRENT_GATE_I2C_ON 1 +#define CURRENT_GATE_SSP 7:7 +#define CURRENT_GATE_SSP_OFF 0 +#define CURRENT_GATE_SSP_ON 1 +#define CURRENT_GATE_GPIO 6:6 +#define CURRENT_GATE_GPIO_OFF 0 +#define CURRENT_GATE_GPIO_ON 1 +#define CURRENT_GATE_ZVPORT 5:5 +#define CURRENT_GATE_ZVPORT_OFF 0 +#define CURRENT_GATE_ZVPORT_ON 1 +#define CURRENT_GATE_CSC 4:4 +#define CURRENT_GATE_CSC_OFF 0 +#define CURRENT_GATE_CSC_ON 1 +#define CURRENT_GATE_DE 3:3 +#define CURRENT_GATE_DE_OFF 0 +#define CURRENT_GATE_DE_ON 1 +#define CURRENT_GATE_DISPLAY 2:2 +#define CURRENT_GATE_DISPLAY_OFF 0 +#define CURRENT_GATE_DISPLAY_ON 1 +#define CURRENT_GATE_LOCALMEM 1:1 +#define CURRENT_GATE_LOCALMEM_OFF 0 +#define CURRENT_GATE_LOCALMEM_ON 1 +#define CURRENT_GATE_DMA 0:0 +#define CURRENT_GATE_DMA_OFF 0 +#define CURRENT_GATE_DMA_ON 1 + +#define MODE0_GATE 0x000044 +#define MODE0_GATE_MCLK 15:14 +#define MODE0_GATE_MCLK_112MHZ 0 +#define MODE0_GATE_MCLK_84MHZ 1 +#define MODE0_GATE_MCLK_56MHZ 2 +#define MODE0_GATE_MCLK_42MHZ 3 +#define MODE0_GATE_M2XCLK 13:12 +#define MODE0_GATE_M2XCLK_336MHZ 0 +#define MODE0_GATE_M2XCLK_168MHZ 1 +#define MODE0_GATE_M2XCLK_112MHZ 2 +#define MODE0_GATE_M2XCLK_84MHZ 3 +#define MODE0_GATE_VGA 10:10 +#define MODE0_GATE_VGA_OFF 0 +#define MODE0_GATE_VGA_ON 1 +#define MODE0_GATE_PWM 9:9 +#define MODE0_GATE_PWM_OFF 0 +#define MODE0_GATE_PWM_ON 1 +#define MODE0_GATE_I2C 8:8 +#define MODE0_GATE_I2C_OFF 0 +#define MODE0_GATE_I2C_ON 1 +#define MODE0_GATE_SSP 7:7 +#define MODE0_GATE_SSP_OFF 0 +#define MODE0_GATE_SSP_ON 1 +#define MODE0_GATE_GPIO 6:6 +#define MODE0_GATE_GPIO_OFF 0 +#define MODE0_GATE_GPIO_ON 1 +#define MODE0_GATE_ZVPORT 5:5 +#define MODE0_GATE_ZVPORT_OFF 0 +#define MODE0_GATE_ZVPORT_ON 1 +#define MODE0_GATE_CSC 4:4 +#define MODE0_GATE_CSC_OFF 0 +#define MODE0_GATE_CSC_ON 1 +#define MODE0_GATE_DE 3:3 +#define MODE0_GATE_DE_OFF 0 +#define MODE0_GATE_DE_ON 1 +#define MODE0_GATE_DISPLAY 2:2 +#define MODE0_GATE_DISPLAY_OFF 0 +#define MODE0_GATE_DISPLAY_ON 1 +#define MODE0_GATE_LOCALMEM 1:1 +#define MODE0_GATE_LOCALMEM_OFF 0 +#define MODE0_GATE_LOCALMEM_ON 1 +#define MODE0_GATE_DMA 0:0 +#define MODE0_GATE_DMA_OFF 0 +#define MODE0_GATE_DMA_ON 1 + +#define MODE1_GATE 0x000048 +#define MODE1_GATE_MCLK 15:14 +#define MODE1_GATE_MCLK_112MHZ 0 +#define MODE1_GATE_MCLK_84MHZ 1 +#define MODE1_GATE_MCLK_56MHZ 2 +#define MODE1_GATE_MCLK_42MHZ 3 +#define MODE1_GATE_M2XCLK 13:12 +#define MODE1_GATE_M2XCLK_336MHZ 0 +#define MODE1_GATE_M2XCLK_168MHZ 1 +#define MODE1_GATE_M2XCLK_112MHZ 2 +#define MODE1_GATE_M2XCLK_84MHZ 3 +#define MODE1_GATE_VGA 10:10 +#define MODE1_GATE_VGA_OFF 0 +#define MODE1_GATE_VGA_ON 1 +#define MODE1_GATE_PWM 9:9 +#define MODE1_GATE_PWM_OFF 0 +#define MODE1_GATE_PWM_ON 1 +#define MODE1_GATE_I2C 8:8 +#define MODE1_GATE_I2C_OFF 0 +#define MODE1_GATE_I2C_ON 1 +#define MODE1_GATE_SSP 7:7 +#define MODE1_GATE_SSP_OFF 0 +#define MODE1_GATE_SSP_ON 1 +#define MODE1_GATE_GPIO 6:6 +#define MODE1_GATE_GPIO_OFF 0 +#define MODE1_GATE_GPIO_ON 1 +#define MODE1_GATE_ZVPORT 5:5 +#define MODE1_GATE_ZVPORT_OFF 0 +#define MODE1_GATE_ZVPORT_ON 1 +#define MODE1_GATE_CSC 4:4 +#define MODE1_GATE_CSC_OFF 0 +#define MODE1_GATE_CSC_ON 1 +#define MODE1_GATE_DE 3:3 +#define MODE1_GATE_DE_OFF 0 +#define MODE1_GATE_DE_ON 1 +#define MODE1_GATE_DISPLAY 2:2 +#define MODE1_GATE_DISPLAY_OFF 0 +#define MODE1_GATE_DISPLAY_ON 1 +#define MODE1_GATE_LOCALMEM 1:1 +#define MODE1_GATE_LOCALMEM_OFF 0 +#define MODE1_GATE_LOCALMEM_ON 1 +#define MODE1_GATE_DMA 0:0 +#define MODE1_GATE_DMA_OFF 0 +#define MODE1_GATE_DMA_ON 1 + +#define POWER_MODE_CTRL 0x00004C +#define POWER_MODE_CTRL_OSC_INPUT 3:3 +#define POWER_MODE_CTRL_OSC_INPUT_OFF 0 +#define POWER_MODE_CTRL_OSC_INPUT_ON 1 +#define POWER_MODE_CTRL_ACPI 2:2 +#define POWER_MODE_CTRL_ACPI_OFF 0 +#define POWER_MODE_CTRL_ACPI_ON 1 +#define POWER_MODE_CTRL_MODE 1:0 +#define POWER_MODE_CTRL_MODE_MODE0 0 +#define POWER_MODE_CTRL_MODE_MODE1 1 +#define POWER_MODE_CTRL_MODE_SLEEP 2 + +/* This definition is for SM750 */ +#define PCI_MASTER_BASE 0x000050 +#define PCI_MASTER_BASE_ADDRESS 7:0 + +/* This definition is for SM718 */ +#define SM718_PCI_MASTER_BASE 0x000050 +#define SM718_PCI_MASTER_BASE_ADDRESS 31:20 + +#define DEVICE_ID 0x000054 +#define DEVICE_ID_DEVICE_ID 31:16 +#define DEVICE_ID_REVISION_ID 7:0 + +#define PLL_CLK_COUNT 0x000058 +#define PLL_CLK_COUNT_COUNTER 15:0 + +#define PRIMARY_PLL_CTRL 0x00005C +#define PRIMARY_PLL_CTRL_BYPASS 18:18 +#define PRIMARY_PLL_CTRL_BYPASS_OFF 0 +#define PRIMARY_PLL_CTRL_BYPASS_ON 1 +#define PRIMARY_PLL_CTRL_POWER 17:17 +#define PRIMARY_PLL_CTRL_POWER_OFF 0 +#define PRIMARY_PLL_CTRL_POWER_ON 1 +#define PRIMARY_PLL_CTRL_INPUT 16:16 +#define PRIMARY_PLL_CTRL_INPUT_OSC 0 +#define PRIMARY_PLL_CTRL_INPUT_TESTCLK 1 +#define PRIMARY_PLL_CTRL_POD 15:14 +#define PRIMARY_PLL_CTRL_OD 13:12 +#define PRIMARY_PLL_CTRL_N 11:8 +#define PRIMARY_PLL_CTRL_M 7:0 + +#define SECONDARY_PLL_CTRL 0x000060 +#define SECONDARY_PLL_CTRL_BYPASS 18:18 +#define SECONDARY_PLL_CTRL_BYPASS_OFF 0 +#define SECONDARY_PLL_CTRL_BYPASS_ON 1 +#define SECONDARY_PLL_CTRL_POWER 17:17 +#define SECONDARY_PLL_CTRL_POWER_OFF 0 +#define SECONDARY_PLL_CTRL_POWER_ON 1 +#define SECONDARY_PLL_CTRL_INPUT 16:16 +#define SECONDARY_PLL_CTRL_INPUT_OSC 0 +#define SECONDARY_PLL_CTRL_INPUT_TESTCLK 1 +#define SECONDARY_PLL_CTRL_POD 15:14 +#define SECONDARY_PLL_CTRL_OD 13:12 +#define SECONDARY_PLL_CTRL_N 11:8 +#define SECONDARY_PLL_CTRL_M 7:0 + +#define VGA_PLL0_CTRL 0x000064 +#define VGA_PLL0_CTRL_BYPASS 18:18 +#define VGA_PLL0_CTRL_BYPASS_OFF 0 +#define VGA_PLL0_CTRL_BYPASS_ON 1 +#define VGA_PLL0_CTRL_POWER 17:17 +#define VGA_PLL0_CTRL_POWER_OFF 0 +#define VGA_PLL0_CTRL_POWER_ON 1 +#define VGA_PLL0_CTRL_INPUT 16:16 +#define VGA_PLL0_CTRL_INPUT_OSC 0 +#define VGA_PLL0_CTRL_INPUT_TESTCLK 1 +#define VGA_PLL0_CTRL_POD 15:14 +#define VGA_PLL0_CTRL_OD 13:12 +#define VGA_PLL0_CTRL_N 11:8 +#define VGA_PLL0_CTRL_M 7:0 + +#define VGA_PLL1_CTRL 0x000068 +#define VGA_PLL1_CTRL_BYPASS 18:18 +#define VGA_PLL1_CTRL_BYPASS_OFF 0 +#define VGA_PLL1_CTRL_BYPASS_ON 1 +#define VGA_PLL1_CTRL_POWER 17:17 +#define VGA_PLL1_CTRL_POWER_OFF 0 +#define VGA_PLL1_CTRL_POWER_ON 1 +#define VGA_PLL1_CTRL_INPUT 16:16 +#define VGA_PLL1_CTRL_INPUT_OSC 0 +#define VGA_PLL1_CTRL_INPUT_TESTCLK 1 +#define VGA_PLL1_CTRL_POD 15:14 +#define VGA_PLL1_CTRL_OD 13:12 +#define VGA_PLL1_CTRL_N 11:8 +#define VGA_PLL1_CTRL_M 7:0 +#define VGA_PLL1_MASK 0x00FFFFFF + +/* Use peekRegisterByte to access this scratch data */ +#define SCRATCH_DATA 0x00006b +/* The following register is used by HW */ +/*#define SCRATCH_DATA 0x00006c*/ + +#define MXCLK_PLL_CTRL 0x000070 +#define MXCLK_PLL_CTRL_BYPASS 18:18 +#define MXCLK_PLL_CTRL_BYPASS_OFF 0 +#define MXCLK_PLL_CTRL_BYPASS_ON 1 +#define MXCLK_PLL_CTRL_POWER 17:17 +#define MXCLK_PLL_CTRL_POWER_OFF 0 +#define MXCLK_PLL_CTRL_POWER_ON 1 +#define MXCLK_PLL_CTRL_INPUT 16:16 +#define MXCLK_PLL_CTRL_INPUT_OSC 0 +#define MXCLK_PLL_CTRL_INPUT_TESTCLK 1 +#define MXCLK_PLL_CTRL_POD 15:14 +#define MXCLK_PLL_CTRL_OD 13:12 +#define MXCLK_PLL_CTRL_N 11:8 +#define MXCLK_PLL_CTRL_M 7:0 + +/* Host Interface registers support. Only applies to SM718 */ +#define HOST_INTERFACE 0x000074 +#define HOST_INTERFACE_NON_CACHE_ADDRESS 30:17 +/* The following status is read-only. + When SM718 is transitioning back from sleep mode to normal mode, software needs + to poll this bit until it becomes "0" before writing any other command to the chip. */ +#define HOST_INTERFACE_STATUS 16:16 +#define HOST_INTERFACE_STATUS_NORMAL 0 +#define HOST_INTERFACE_STATUS_SLEEP 1 +#define HOST_INTERFACE_CPU 15:15 +#define HOST_INTERFACE_CPU_32BIT 0 +#define HOST_INTERFACE_CPU_16BIT 1 +#define HOST_INTERFACE_XSCALE_INPUT_SOURCE 14:14 +#define HOST_INTERFACE_XSCALE_INPUT_SOURCE_PLL 0 +#define HOST_INTERFACE_XSCALE_INPUT_SOURCE_HCLK 1 +#define HOST_INTERFACE_ENDIAN 7:7 +#define HOST_INTERFACE_ENDIAN_LITTLE 0 +#define HOST_INTERFACE_ENDIAN_BIG 1 +/* The following polarity is determined by GPIO20 pin at reset */ +#define HOST_INTERFACE_HITACHI_POLARITY 6:6 +#define HOST_INTERFACE_HITACHI_POLARITY_ACTIVE_LOW 0 +#define HOST_INTERFACE_HITACHI_POLARITY_ACTIVE_HIGH 1 +#define HOST_INTERFACE_NEC_MEMORY_MAP_LOCATION 5:5 +#define HOST_INTERFACE_NEC_MEMORY_MAP_LOCATION_30MB 0 +#define HOST_INTERFACE_NEC_MEMORY_MAP_LOCATION_62MB 1 +#define HOST_INTERFACE_SH4_READY 4:3 +#define HOST_INTERFACE_SH4_READY_ONE_CLOCK 0 +#define HOST_INTERFACE_SH4_READY_TWO_CLOCKS 1 +#define HOST_INTERFACE_SH4_READY_CS_CONTROL 2 +/* The following bus type is determined by GPIO19, GPIO18, and GPIO17 pins at reset */ +#define HOST_INTERFACE_BUS_TYPE 2:0 +#define HOST_INTERFACE_BUS_TYPE_HITACHI_SH3_SH4 0 +#define HOST_INTERFACE_BUS_TYPE_PCI 1 +#define HOST_INTERFACE_BUS_TYPE_INTEL_XSCALE 2 +#define HOST_INTERFACE_BUS_TYPE_NEC 6 + +/* System memory register. Only applies to SM718 */ +#define SYSTEM_MEMORY 0x000078 +/* Extend the bus holding when SM718 is a host bust master to access system SDRAM. */ +#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT 23:20 +#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT_0 0 +#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT_16 1 +#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT_32 2 +#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT_48 3 +#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT_64 4 +#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT_80 5 +#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT_96 6 +#define SYSTEM_MEMORY_HOST_BUS_HOLDING_EXT_112 7 +#define SYSTEM_MEMORY_BURST_LENGTH 19:17 +#define SYSTEM_MEMORY_BURST_LENGTH_1_WORD 0 +#define SYSTEM_MEMORY_BURST_LENGTH_2_WORDS 1 +#define SYSTEM_MEMORY_BURST_LENGTH_4_WORDS 2 +#define SYSTEM_MEMORY_BURST_LENGTH_8_WORDS 3 +#define SYSTEM_MEMORY_CAS_LATENCY 16:16 +#define SYSTEM_MEMORY_CAS_LATENCY_2_CLOCKS 0 +#define SYSTEM_MEMORY_CAS_LATENCY_3_CLOCKS 1 +#define SYSTEM_MEMORY_BUS_HOLD_TIME 15:13 +#define SYSTEM_MEMORY_BUS_HOLD_TIME_FIFO_EMPTY 0 +#define SYSTEM_MEMORY_BUS_HOLD_TIME_8_TRANSACTIONS 1 +#define SYSTEM_MEMORY_BUS_HOLD_TIME_16_TRANSACTIONS 2 +#define SYSTEM_MEMORY_BUS_HOLD_TIME_24_TRANSACTIONS 3 +#define SYSTEM_MEMORY_BUS_HOLD_TIME_32_TRANSACTIONS 4 +#define SYSTEM_MEMORY_COLUMN_SIZE 12:11 +#define SYSTEM_MEMORY_COLUMN_SIZE_1024_WORDS 0 +#define SYSTEM_MEMORY_COLUMN_SIZE_512_WORDS 2 +#define SYSTEM_MEMORY_COLUMN_SIZE_256_WORDS 3 +#define SYSTEM_MEMORY_SIZE 10:8 +#define SYSTEM_MEMORY_SIZE_2MB 0 +#define SYSTEM_MEMORY_SIZE_4MB 1 +#define SYSTEM_MEMORY_SIZE_64MB 4 +#define SYSTEM_MEMORY_SIZE_32MB 5 +#define SYSTEM_MEMORY_SIZE_16MB 6 +#define SYSTEM_MEMORY_SIZE_8MB 7 +/* System Memory Active to Pre-charge delay */ +#define SYSTEM_MEMORY_ACTIVE_DELAY 7:7 +#define SYSTEM_MEMORY_ACTIVE_DELAY_6_CLOCKS 0 +#define SYSTEM_MEMORY_ACTIVE_DELAY_7_CLOCKS 1 +/* System Memory Write to Pre-charge delay */ +#define SYSTEM_MEMORY_WRITE_DELAY 6:6 +#define SYSTEM_MEMORY_WRITE_DELAY_2_CLOCKS 0 +#define SYSTEM_MEMORY_WRITE_DELAY_1_CLOCK 1 +#define SYSTEM_MEMORY_BANK 5:5 +#define SYSTEM_MEMORY_BANK_4 0 +#define SYSTEM_MEMORY_BANK_2 1 +#define SYSTEM_MEMORY_RESET 4:4 +#define SYSTEM_MEMORY_RESET_ENABLE 0 +#define SYSTEM_MEMORY_RESET_DISABLE 1 +/* Delay time to latch read data for external SDRAM controller (in 1/2 ns step) */ +#define SYSTEM_MEMORY_LATCH_DELAY 3:1 +#define SYSTEM_MEMORY_LATCH_DELAY_0 0 +#define SYSTEM_MEMORY_LATCH_DELAY_1 1 +#define SYSTEM_MEMORY_LATCH_DELAY_2 2 +#define SYSTEM_MEMORY_LATCH_DELAY_3 3 +#define SYSTEM_MEMORY_LATCH_DELAY_4 4 +#define SYSTEM_MEMORY_LATCH_DELAY_5 5 +#define SYSTEM_MEMORY_CPU_MASTER_BURST_LENGTH 0:0 +#define SYSTEM_MEMORY_CPU_MASTER_BURST_LENGTH_8 0 +#define SYSTEM_MEMORY_CPU_MASTER_BURST_LENGTH_1 1 + +#define VGA_CONFIGURATION 0x000088 +#define VGA_CONFIGURATION_A0000_ACCESS 7:7 +#define VGA_CONFIGURATION_A0000_ACCESS_DISABLE 0 +#define VGA_CONFIGURATION_A0000_ACCESS_ENABLE 1 +#define VGA_CONFIGURATION_USER_DEFINE 5:4 +#define VGA_CONFIGURATION_PLL 2:2 +#define VGA_CONFIGURATION_PLL_VGA 0 +#define VGA_CONFIGURATION_PLL_PRIMARY 1 +#define VGA_CONFIGURATION_MODE 1:1 +#define VGA_CONFIGURATION_MODE_TEXT 0 +#define VGA_CONFIGURATION_MODE_GRAPHIC 1 +/* The following only applies to SM718 (Strap pin MA Line 11) */ +#define VGA_CONFIGURATION_C0000_ACCESS 0:0 +#define VGA_CONFIGURATION_C0000_ACCESS_DISABLE 0 +#define VGA_CONFIGURATION_C0000_ACCESS_ENABLE 1 diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_sii9022.c b/drivers/gpu/drm/smidrm/ddk750/ddk750_sii9022.c new file mode 100644 index 000000000000..17d7597a6cd3 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_sii9022.c @@ -0,0 +1,91 @@ +#ifdef USE_HDMICHIP + +#include +#include +#include +#include +#include + + +#include "siHdmiTx_902x_TPI.h" +#include "ddk750_hwi2c.h" +#include "ddk750_swi2c.h" + + +#define SII9022_DEVICE_ID 0xb0 + +#define i2cWriteReg swI2CWriteReg +#define i2cReadReg swI2CReadReg + + + +unsigned char sii9022xIsConnected(void) +{ + return 1; +} + +__attribute__((unused)) static void dump9022a(uint8_t reg) +{ +#if 1 + printk("reg%x=%x\n",reg,i2cReadReg(SII9022A_I2C_ADDRESS,reg)); +#endif +} +int sii9022xSetMode(int num) +{ + int ret; + + swI2CInit(DEFAULT_I2C_SCL, DEFAULT_I2C_SDA); + siHdmiTx_VideoSel(num); + siHdmiTx_AudioSel(0x02); + siHdmiTx_TPI_Init(); + ret = siHdmiTx_VideoSet(); + i2cWriteReg(SII9022A_I2C_ADDRESS,0x63,0); + return ret; +} + +int sii9022xInitChip(void) +{ + int rcc,retries = 10; + + swI2CInit(DEFAULT_I2C_SCL, DEFAULT_I2C_SDA); + + /* enter TPI mode */ + i2cWriteReg(SII9022A_I2C_ADDRESS,0xc7,0); + do{ + msleep(1); + rcc = i2cReadReg(SII9022A_I2C_ADDRESS,0x1B); + }while((rcc != SII9022_DEVICE_ID) && retries--); + + if(rcc != SII9022_DEVICE_ID){ + printk("cannot detect sii9022a chip:rcc=%x\n",rcc); + return -1; + } + return 0; +} + +byte SysCtrlReg; + +int ddk750_GetDDC_9022Access(void) +{ + int ret = 0; + swI2CInit(DEFAULT_I2C_SCL, DEFAULT_I2C_SDA); + ret = GetDDC_Access(&SysCtrlReg); + return ret; +} + + + +int ddk750_Release9022DDC(void) +{ + int ret = ReleaseDDC(SysCtrlReg); + return ret; +} + +void ddk750_DoEdidRead(void) +{ + DoEdidRead(); +} + + + +#endif diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_sii9022.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_sii9022.h new file mode 100644 index 000000000000..c47cfeb0e93e --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_sii9022.h @@ -0,0 +1,7 @@ +int sii9022xInitChip(void); +int sii9022xSetMode(int); +unsigned char sii9022xIsConnected(void); +int ddk750_GetDDC_9022Access(void); +int ddk750_Release9022DDC(void); +void ddk750_DoEdidRead(void); + diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_sw2d.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_sw2d.h new file mode 100644 index 000000000000..a52f69de32c2 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_sw2d.h @@ -0,0 +1,200 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* sw2d.h --- SM750/SM718 DDK +* This file contains the function prototype for 2D Function +* implementation. +* +*******************************************************************/ +#ifndef _SW2D_H_ +#define _SW2D_H_ + +/* Some color definitions */ +#define BPP32_RED 0x00ff0000 +#define BPP32_GREEN 0x0000ff00 +#define BPP32_BLUE 0x000000ff +#define BPP32_WHITE 0x00ffffff +#define BPP32_GRAY 0x00808080 +#define BPP32_YELLOW 0x00ffff00 +#define BPP32_CYAN 0x0000ffff +#define BPP32_PINK 0x00ff00ff +#define BPP32_BLACK 0x00000000 + +#define BPP16_RED 0x0000f800 +#define BPP16_GREEN 0x000007e0 +#define BPP16_BLUE 0x0000001f +#define BPP16_WHITE 0x0000ffff +#define BPP16_GRAY 0x00008410 +#define BPP16_YELLOW 0x0000ffe0 +#define BPP16_CYAN 0x000007ff +#define BPP16_PINK 0x0000f81f +#define BPP16_BLACK 0x00000000 + +#define BPP8_RED 0x000000b4 +#define BPP8_GREEN 0x0000001e +#define BPP8_BLUE 0x00000005 +#define BPP8_WHITE 0x000000ff +#define BPP8_GRAY 0x000000ec +#define BPP8_YELLOW 0x000000d2 +#define BPP8_CYAN 0x00000023 +#define BPP8_PINK 0x000000b9 +#define BPP8_BLACK 0x00000000 + +/* Raster Op 2 functions */ +#define ROP2_XOR 0x06 +#define ROP2_AND 0x08 +#define ROP2_COPY 0x0C +#define ROP2_OR 0x0E + +#define ROP2_BLACK 0x00 +#define ROP2_DSon 0x01 +#define ROP2_DSna 0x02 +#define ROP2_Sn 0x03 +#define ROP2_SDna 0x04 +#define ROP2_Dn 0x05 +#define ROP2_DSx 0x06 +#define ROP2_SDan 0x07 +#define ROP2_DSa 0x08 +#define ROP2_SDnx 0x09 +#define ROP2_D 0x0A +#define ROP2_DSno 0x0B +#define ROP2_S 0x0C +#define ROP2_SDno 0x0D +#define ROP2_DSo 0x0E +#define ROP2_WHITE 0x0F + +/* Blt Direction definitions */ +#define TOP_TO_BOTTOM 0 +#define LEFT_TO_RIGHT 0 +#define BOTTOM_TO_TOP 1 +#define RIGHT_TO_LEFT 1 + +unsigned long swRasterOp2(unsigned long S, unsigned long D, unsigned long rop2); + +/* + * This function set up a pixel value in the frame buffer. + * + * Note: + * 1) It can only set pixel within the frame buffer. + * 2) This function is NOT for drawing surface created in system memory. + * + */ +void swSetPixel( +unsigned long destBase, /* Base address of destination surface counted from beginning of video frame buffer */ +unsigned long pitch, /* Pitch value of destination surface in BYTES */ +unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ +unsigned long x, +unsigned long y, /* Position (X, Y) to set in pixel value */ +unsigned long color, /* Color */ +unsigned long rop2); /* ROP value */ + +/* + * This function gets a pixel value in the frame buffer. + * + * Note: + * 1) It can only get pixel within the frame buffer. + * 2) This function is NOT for drawing surface created in system memory. + * 3) This function always return a 32 bit pixel value disregard bpp = 8, 16, or 32. + * The calling funtion has to type cast the return value into Byte, word or + * DWord according to BPP. + * + */ +unsigned long swGetPixel( +unsigned long destBase, /* Base address of destination surface counted from beginning of video frame buffer */ +unsigned long pitch, /* Pitch value of destination surface in BYTES */ +unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ +unsigned long x, +unsigned long y); /* Position (X, Y) to set in pixel value */ + +/* + * This function uses software only method to fill a rectangular area with a specific color. + * Input: See comment of code below. + * + */ +void swRectFill( +unsigned long destBase, /* Base address of destination surface counted from beginning of video frame buffer */ +unsigned long pitch, /* Pitch value of destination surface in BYTES */ +unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ +unsigned long x, +unsigned long y, /* Upper left corner (X, Y) of rectangle in pixel value */ +unsigned long width, +unsigned long height, /* width and height of rectange in pixel value */ +unsigned long color, /* Fill color */ +unsigned long rop2); /* ROP value */ + +/* + * This function draws a hollow rectangle, no fills. + */ +void swRect( +unsigned long destBase, /* Base address of destination surface counted from beginning of video frame buffer */ +unsigned long pitch, /* Pitch value of destination surface in BYTES */ +unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ +unsigned long x, +unsigned long y, /* Upper left corner (X, Y) of rectangle in pixel value */ +unsigned long width, +unsigned long height, /* width and height of rectange in pixel value */ +unsigned long color, /* border color */ +unsigned long rop2); /* ROP value */ + +void swHorizontalLine( +unsigned long destBase, /* Base address of destination surface counted from beginning of video frame buffer */ +unsigned long pitch, /* Pitch value of destination surface in BYTES */ +unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ +unsigned long x, +unsigned long y, /* Starting point (X, Y) of line */ +unsigned long length, /* Length of line */ +unsigned long color, /* Color */ +unsigned long rop2); /* ROP value */ + +void swVerticalLine( +unsigned long destBase, /* Base address of destination surface counted from beginning of video frame buffer */ +unsigned long pitch, /* Pitch value of destination surface in BYTES */ +unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ +unsigned long x, +unsigned long y, /* Starting point (X, Y) of line */ +unsigned long length, /* Length of line */ +unsigned long color, /* Color */ +unsigned long rop2); /* ROP value */ + +/* + * Function to draw a line. + */ +long swLine( + unsigned long destBase, /* Base address of destination surface counted from beginning of video frame buffer */ + unsigned long pitch, /* Pitch value of destination surface in BYTES */ + unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ + unsigned long x0, /* Starting X Coordinate */ + unsigned long y0, /* Starting Y Coordinate */ + unsigned long x1, /* Ending X Coordinate */ + unsigned long y1, /* Ending Y Coordinate */ + unsigned long color, /* Color of the line */ + unsigned long rop2 /* ROP value */ +); + +/* + * Video Memory to Video Memroy data transfer. + * + * Note: + * 1) All addresses are offset from the beginning for frame buffer. + * 2) Both source and destination have to be same bpp (color depth). + * + */ +void swVideoMem2VideoMemBlt( +unsigned long sBase, /* Address of source: offset in frame buffer */ +unsigned long sPitch, /* Pitch value of source surface in BYTE */ +unsigned long sx, +unsigned long sy, /* Starting coordinate of source surface */ +unsigned long dBase, /* Address of destination: offset in frame buffer */ +unsigned long dPitch, /* Pitch value of destination surface in BYTE */ +unsigned long bpp, /* color depth of destiination, source must have same bpp */ +unsigned long dx, +unsigned long dy, /* Starting coordinate of destination surface */ +unsigned long width, +unsigned long height, /* width and height of rectange in pixel value */ +unsigned long rop2); /* ROP value */ + +#endif /* _SW2D_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_swi2c.c b/drivers/gpu/drm/smidrm/ddk750/ddk750_swi2c.c new file mode 100644 index 000000000000..33ccf4f5921c --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_swi2c.c @@ -0,0 +1,822 @@ +#include +#include "ddk750_defs.h" +#include "ddk750_hardware.h" +#include "ddk750_power.h" +#include "ddk750_help.h" +#include "ddk750_swi2c.h" + + +/******************************************************************* + * I2C Software Master Driver: + * =========================== + * Each i2c cycle is split into 4 sections. Each of these section marks + * a point in time where the SCL or SDA may be changed. + * + * 1 Cycle == | Section I. | Section 2. | Section 3. | Section 4. | + * +-------------+-------------+-------------+-------------+ + * | SCL set LOW |SCL no change| SCL set HIGH|SCL no change| + * + * ____________ _____________ + * SCL == XXXX _____________ ____________ / + * + * I.e. the SCL may only be changed in section 1. and section 3. while + * the SDA may only be changed in section 2. and section 4. The table + * below gives the changes for these 2 lines in the varios sections. + * + * Section changes Table: + * ====================== + * blank = no change, L = set bit LOW, H = set bit HIGH + * + * | 1.| 2.| 3.| 4.| + * ---------------+---+---+---+---+ + * Tx Start SDA | | H | | L | + * SCL | L | | H | | + * ---------------+---+---+---+---+ + * Tx Stop SDA | | L | | H | + * SCL | L | | H | | + * ---------------+---+---+---+---+ + * Tx bit H SDA | | H | | | + * SCL | L | | H | | + * ---------------+---+---+---+---+ + * Tx bit L SDA | | L | | | + * SCL | L | | H | | + * ---------------+---+---+---+---+ + * + ******************************************************************/ + +/* GPIO pins used for this I2C. It ranges from 0 to 63. */ +static unsigned char g_i2cClockGPIO = DEFAULT_I2C_SCL; +static unsigned char g_i2cDataGPIO = DEFAULT_I2C_SDA; + +/* + * Below is the variable declaration for the GPIO pin register usage + * for the i2c Clock and i2c Data. + * + * Note: + * Notice that the GPIO usage for the i2c clock and i2c Data are + * separated. This is to make this code flexible enough when + * two separate GPIO pins for the clock and data are located + * in two different GPIO register set (worst case). + */ + +/* i2c Clock GPIO Register usage */ +static unsigned long g_i2cClkGPIOMuxReg = GPIO_MUX; +static unsigned long g_i2cClkGPIODataReg = GPIO_DATA; +static unsigned long g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION; + +/* i2c Data GPIO Register usage */ +static unsigned long g_i2cDataGPIOMuxReg = GPIO_MUX; +static unsigned long g_i2cDataGPIODataReg = GPIO_DATA; +static unsigned long g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION; + +/* + * This function puts a delay between command + */ +static void swI2CWait(void) +{ + int i, Temp; + + for(i=0; i<600; i++) + { + Temp = i; + Temp += i; + } +} + +/* + * This function set/reset the SCL GPIO pin + * + * Parameters: + * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) + * + * Notes: + * When setting SCL to high, just set the GPIO as input where the pull up + * resistor will pull the signal up. Do not use software to pull up the + * signal because the i2c will fail when other device try to drive the + * signal due to SM50x will drive the signal to always high. + */ +void swI2CSCL(unsigned char value) +{ + unsigned long ulGPIOData; + unsigned long ulGPIODirection; + + ulGPIODirection = peekRegisterDWord(g_i2cClkGPIODataDirReg); + if (value) /* High */ + { + /* Set direction as input. This will automatically pull the signal up. */ + ulGPIODirection &= ~(1 << g_i2cClockGPIO); + pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection); + } + else /* Low */ + { + /* Set the signal down */ + ulGPIOData = peekRegisterDWord(g_i2cClkGPIODataReg); + ulGPIOData &= ~(1 << g_i2cClockGPIO); + pokeRegisterDWord(g_i2cClkGPIODataReg, ulGPIOData); + + /* Set direction as output */ + ulGPIODirection |= (1 << g_i2cClockGPIO); + pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection); + } +} + +/* + * This function set/reset the SDA GPIO pin + * + * Parameters: + * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) + * + * Notes: + * When setting SCL to high, just set the GPIO as input where the pull up + * resistor will pull the signal up. Do not use software to pull up the + * signal because the i2c will fail when other device try to drive the + * signal due to SM50x will drive the signal to always high. + */ +void swI2CSDA(unsigned char value) +{ + unsigned long ulGPIOData; + unsigned long ulGPIODirection; + + ulGPIODirection = peekRegisterDWord(g_i2cDataGPIODataDirReg); + if (value) /* High */ + { + /* Set direction as input. This will automatically pull the signal up. */ + ulGPIODirection &= ~(1 << g_i2cDataGPIO); + pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection); + } + else /* Low */ + { + /* Set the signal down */ + ulGPIOData = peekRegisterDWord(g_i2cDataGPIODataReg); + ulGPIOData &= ~(1 << g_i2cDataGPIO); + pokeRegisterDWord(g_i2cDataGPIODataReg, ulGPIOData); + + /* Set direction as output */ + ulGPIODirection |= (1 << g_i2cDataGPIO); + pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection); + } +} + +/* + * This function read the data from the SDA GPIO pin + * + * Return Value: + * The SDA data bit sent by the Slave + */ +static unsigned char swI2CReadSDA(void) +{ + unsigned long ulGPIODirection; + unsigned long ulGPIOData; + + /* Make sure that the direction is input (High) */ + ulGPIODirection = peekRegisterDWord(g_i2cDataGPIODataDirReg); + if ((ulGPIODirection & (1 << g_i2cDataGPIO)) != (~(1 << g_i2cDataGPIO))) + { + ulGPIODirection &= ~(1 << g_i2cDataGPIO); + pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection); + } + + /* Now read the SDA line */ + ulGPIOData = peekRegisterDWord(g_i2cDataGPIODataReg); + if (ulGPIOData & (1 << g_i2cDataGPIO)) + return 1; + else + return 0; +} + +#pragma GCC push_options +#pragma GCC optimize("O0") + +/* + * This function sends ACK signal + */ +static void swI2CAck(unsigned char ack) +{ + if(ack) + { + swI2CSCL(0); + swI2CSDA(0); + swI2CWait(); + swI2CSCL(1); + swI2CWait(); + swI2CSCL(0); + swI2CSDA(0); + swI2CWait(); + } + else + { + swI2CSCL(0); + swI2CSDA(1); + swI2CWait(); + swI2CSCL(1); + swI2CWait(); + swI2CSCL(0); + swI2CSDA(0); + swI2CWait(); + } + return; /* Single byte read is ok without it. */ +} + +/* + * This function sends the start command to the slave device + */ +static void swI2CStart(void) +{ + /* Start I2C */ + swI2CSDA(1); + swI2CSCL(1); + swI2CSDA(0); +} + +/* + * This function sends the stop command to the slave device + */ +static void swI2CStop(void) +{ + /* Stop the I2C */ + swI2CSCL(1); + swI2CSDA(0); + swI2CSDA(1); +} + +/* + * This function writes one byte to the slave device + * + * Parameters: + * data - Data to be write to the slave device + * + * Return Value: + * 0 - Success + * -1 - Fail to write byte + */ +static long swI2CWriteByte(unsigned char data) +{ + unsigned char value = data; + int i; + + /* Sending the data bit by bit */ + for (i=0; i<8; i++) + { + /* Set SCL to low */ + swI2CSCL(0); + + /* Send data bit */ + if ((value & 0x80) != 0) + swI2CSDA(1); + else + swI2CSDA(0); + + swI2CWait(); + + /* Toggle clk line to one */ + swI2CSCL(1); + + /* Shift byte to be sent */ + value = value << 1; + } + + /* Set the SCL Low and SDA High (prepare to get input) */ + swI2CSCL(0); + swI2CSDA(1); + + /* Set the SCL High for ack */ + swI2CWait(); + swI2CSCL(1); + + /* Read SDA, until SDA==0 */ + for(i=0; i<0xff; i++) + { + swI2CWait(); + swI2CWait(); + if (!swI2CReadSDA()) + break; + } + + /* Set the SCL Low and SDA High */ + swI2CSCL(0); + swI2CSDA(1); + + if (i<0xff) + return 0; + else + return (-1); +} + +/* + * This function reads one byte from the slave device + * + * Parameters: + * ack - Flag to indicate either to send the acknowledge + * message to the slave device or not + * + * Return Value: + * One byte data read from the Slave device + */ +static unsigned char swI2CReadByte(unsigned char ack) +{ + int i; + unsigned char data = 0; + + for(i=7; i>=0; i--) + { + /* Set the SCL to Low and SDA to High (Input) */ + swI2CSCL(0); + swI2CSDA(1); + swI2CWait(); + + /* Set the SCL High */ + swI2CSCL(1); + swI2CWait(); + + /* Read data bits from SDA */ + data |= (swI2CReadSDA() << i); + } + + swI2CAck(ack); + + return data; +} +#pragma GCC pop_options + +/* + * This function initializes the i2c attributes and bus + * + * Parameters: + * i2cClkGPIO - The GPIO pin to be used as i2c SCL + * i2cDataGPIO - The GPIO pin to be used as i2c SDA + * + * Return Value: + * -1 - Fail to initialize the i2c + * 0 - Success + */ +long swI2CInit( + unsigned char i2cClkGPIO, + unsigned char i2cDataGPIO +) +{ + int i; + + /* Return 0 if the GPIO pins to be used is out of range. The range is only from [0..63] */ + if ((i2cClkGPIO > 31) || (i2cDataGPIO > 31)) + return (-1); + + /* Initialize the GPIO pin for the i2c Clock Register */ + g_i2cClkGPIOMuxReg = GPIO_MUX; + g_i2cClkGPIODataReg = GPIO_DATA; + g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION; + + /* Initialize the Clock GPIO Offset */ + g_i2cClockGPIO = i2cClkGPIO; + + /* Initialize the GPIO pin for the i2c Data Register */ + g_i2cDataGPIOMuxReg = GPIO_MUX; + g_i2cDataGPIODataReg = GPIO_DATA; + g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION; + + /* Initialize the Data GPIO Offset */ + g_i2cDataGPIO = i2cDataGPIO; + + /* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */ + pokeRegisterDWord(g_i2cClkGPIOMuxReg, + peekRegisterDWord(g_i2cClkGPIOMuxReg) & ~(1 << g_i2cClockGPIO)); + pokeRegisterDWord(g_i2cDataGPIOMuxReg, + peekRegisterDWord(g_i2cDataGPIOMuxReg) & ~(1 << g_i2cDataGPIO)); + + /* Enable GPIO power */ + enableGPIO(1); + + /* Clear the i2c lines. */ + for(i=0; i<9; i++) + swI2CStop(); + + return 0; +} + +/* + * This function reads the slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be read from + * registerIndex - Slave device's register to be read + * + * Return Value: + * Register value + */ +unsigned char swI2CReadReg( + unsigned char deviceAddress, + unsigned char registerIndex +) +{ + unsigned char data; + + /* Send the Start signal */ + swI2CStart(); + + /* Send the device address */ + swI2CWriteByte(deviceAddress); + + /* Send the register index */ + swI2CWriteByte(registerIndex); + + /* Get the bus again and get the data from the device read address */ + swI2CStart(); + swI2CWriteByte(deviceAddress + 1); + data = swI2CReadByte(0); + + /* Stop swI2C and release the bus */ + swI2CStop(); + + return data; +} + +/* +* This function reads the slave device's register continuously. +* +* Parameters: +* deviceAddress - i2c Slave device address which register +* to be read from +* start_registerIndex - Slave device's first register(start address) to be read +* length - total length you want to read from the start address +* dest - buffer address which will store the data read from slave device +* +* Return Value: +* 0: fail +* actual size +* +*/ +long swI2CReadReg_Continuous( + unsigned char deviceAddress, + unsigned char start_registerIndex, + unsigned long length, + unsigned char * dest +) +{ + long ret = 128; + int i; + /* Send the Start signal */ + swI2CStart(); + + /* Send the device address */ + ret = swI2CWriteByte(deviceAddress); + /* if failed to write, there is no necessary continuing */ + if(-1 == ret) + return 0; + + /* Send the register index */ + ret = swI2CWriteByte(start_registerIndex); + /* if failed to write, there is no necessary continuing */ + if(-1 == ret) + return 0; + + /* Get the bus again and get the data from the device read address */ + swI2CStart(); + ret = swI2CWriteByte(deviceAddress + 1); + /* if failed to write, there is no necessary continuing */ + if(-1 == ret) + return 0; + + + for(i = 0;i<(length-1);i++) + { + dest[i] = swI2CReadByte(1); + } + + dest[length-1] = swI2CReadByte(0); + /* Stop swI2C and release the bus */ + swI2CStop(); + + ret = length; + + return ret; +} + + + + +/* + * This function writes a value to the slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be written + * registerIndex - Slave device's register to be written + * data - Data to be written to the register + * + * Result: + * 0 - Success + * -1 - Fail + */ +long swI2CWriteReg( + unsigned char deviceAddress, + unsigned char registerIndex, + unsigned char data +) +{ + long returnValue = 0; + + /* Send the Start signal */ + swI2CStart(); +#ifndef USE_HDMICHIP + /* Send the device address and read the data. All should return success + in order for the writing processed to be successful + */ + if ((swI2CWriteByte(deviceAddress) != 0) || + (swI2CWriteByte(registerIndex) != 0) || + (swI2CWriteByte(data) != 0)) + { + returnValue = -1; + } +#else + + swI2CWriteByte(deviceAddress); + swI2CWriteByte(registerIndex); + swI2CWriteByte(data); +#endif + + /* Stop i2c and release the bus */ + swI2CStop(); + + return returnValue; +} + +static long adapterI2CInit( + unsigned char i2cClkGPIO, + unsigned char i2cDataGPIO +) +{ + int i; + + /* Return 0 if the GPIO pins to be used is out of range. The range is only from [0..63] */ + if ((i2cClkGPIO > 31) || (i2cDataGPIO > 31)) + return (-1); + + /* Initialize the GPIO pin for the i2c Clock Register */ + g_i2cClkGPIOMuxReg = GPIO_MUX; + g_i2cClkGPIODataReg = GPIO_DATA; + g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION; + + /* Initialize the Clock GPIO Offset */ +// g_i2cClockGPIO = i2cClkGPIO; + + /* Initialize the GPIO pin for the i2c Data Register */ + g_i2cDataGPIOMuxReg = GPIO_MUX; + g_i2cDataGPIODataReg = GPIO_DATA; + g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION; + + /* Initialize the Data GPIO Offset */ +// g_i2cDataGPIO = i2cDataGPIO; + + /* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */ + pokeRegisterDWord(g_i2cClkGPIOMuxReg, + peekRegisterDWord(g_i2cClkGPIOMuxReg) & ~(1 << i2cClkGPIO)); + pokeRegisterDWord(g_i2cDataGPIOMuxReg, + peekRegisterDWord(g_i2cDataGPIOMuxReg) & ~(1 << i2cDataGPIO)); + + /* Enable GPIO power */ + enableGPIO(1); + + /* Clear the i2c lines. */ + for(i=0; i<9; i++) + swI2CStop(); + + return 0; +} + +static void adapterI2CSCL(unsigned char value, unsigned char i2cClockGPIO) +{ + unsigned long ulGPIOData; + unsigned long ulGPIODirection; + + ulGPIODirection = peekRegisterDWord(g_i2cClkGPIODataDirReg); + if (value) /* High */ + { + /* Set direction as input. This will automatically pull the signal up. */ + ulGPIODirection &= ~(1 << i2cClockGPIO); + pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection); + } + else /* Low */ + { + /* Set the signal down */ + ulGPIOData = peekRegisterDWord(g_i2cClkGPIODataReg); + ulGPIOData &= ~(1 << i2cClockGPIO); + pokeRegisterDWord(g_i2cClkGPIODataReg, ulGPIOData); + + /* Set direction as output */ + ulGPIODirection |= (1 << i2cClockGPIO); + pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection); + } +} + +/* + * This function read the data from the SDA GPIO pin + * + * Return Value: + * The SDA data bit sent by the Slave + */ +static unsigned char adapterI2CReadSCL(unsigned char i2cClockGPIO) +{ + unsigned long ulGPIODirection; + unsigned long ulGPIOData; + + /* Make sure that the direction is input (High) */ + ulGPIODirection = peekRegisterDWord(g_i2cClkGPIODataDirReg); + if ((ulGPIODirection & (1 << i2cClockGPIO)) != (~(1 << i2cClockGPIO))) + { + ulGPIODirection &= ~(1 << i2cClockGPIO); + pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection); + } + + + + /* Now read the SCL line */ + ulGPIOData = peekRegisterDWord(g_i2cClkGPIODataReg); + if (ulGPIOData & (1 << i2cClockGPIO)) + { + return 1; + } + else + { + return 0; + } +} + +static void adapterI2CSDA(unsigned char value, unsigned char i2cDataGPIO) +{ + unsigned long ulGPIOData; + unsigned long ulGPIODirection; + + ulGPIODirection = peekRegisterDWord(g_i2cDataGPIODataDirReg); + if (value) /* High */ + { + /* Set direction as input. This will automatically pull the signal up. */ + ulGPIODirection &= ~(1 << i2cDataGPIO); + pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection); + } + else /* Low */ + { + /* Set the signal down */ + ulGPIOData = peekRegisterDWord(g_i2cDataGPIODataReg); + ulGPIOData &= ~(1 << i2cDataGPIO); + pokeRegisterDWord(g_i2cDataGPIODataReg, ulGPIOData); + + /* Set direction as output */ + ulGPIODirection |= (1 << i2cDataGPIO); + pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection); + } +} + +/* + * This function read the data from the SDA GPIO pin + * + * Return Value: + * The SDA data bit sent by the Slave + */ +static unsigned char adapterI2CReadSDA(unsigned char i2cDataGPIO) +{ + unsigned long ulGPIODirection; + unsigned long ulGPIOData; + + /* Make sure that the direction is input (High) */ + ulGPIODirection = peekRegisterDWord(g_i2cDataGPIODataDirReg); + if ((ulGPIODirection & (1 << i2cDataGPIO)) != (~(1 << i2cDataGPIO))) + { + ulGPIODirection &= ~(1 << i2cDataGPIO); + pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection); + } + + /* Now read the SDA line */ + ulGPIOData = peekRegisterDWord(g_i2cDataGPIODataReg); + if (ulGPIOData & (1 << i2cDataGPIO)) + { + return 1; + } + else + { + return 0; + } +} + +static void smi_ddc_setsda(void *data, int state) +{ + struct smi_connector *connector = data; + adapterI2CSDA(state, connector->i2c_sda); + /* smi_set_i2c_signal(data, I2C_SDA_MASK, state); */ +} + +static void smi_ddc_setscl(void *data, int state) +{ + struct smi_connector *connector = data; + adapterI2CSCL(state, connector->i2c_scl); + /* smi_set_i2c_signal(data, I2C_SCL_MASK, state); */ +} + +static int smi_ddc_getsda(void *data) +{ + + struct smi_connector *connector = data; + return (int)adapterI2CReadSDA(connector->i2c_sda); + /* return smi_get_i2c_signal(data, I2C_SDA_MASK); */ +} + +static int smi_ddc_getscl(void *data) +{ + struct smi_connector *connector = data; + return (int)adapterI2CReadSCL(connector->i2c_scl); + /* return smi_get_i2c_signal(data, I2C_SCL_MASK); */ +} + +static int smi_ddc_create(struct smi_connector *connector) +{ + connector->adapter.owner = THIS_MODULE; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 8, 0) + connector->adapter.class = I2C_CLASS_DDC; +#endif + snprintf(connector->adapter.name, I2C_NAME_SIZE, "SMI SW I2C Bit Bus"); + connector->adapter.dev.parent = connector->base.dev->dev; + i2c_set_adapdata(&connector->adapter, connector); + connector->adapter.algo_data = &connector->bit_data; + + connector->bit_data.udelay = 2; /* 0x3ff ticks, 168MHZ */ + connector->bit_data.timeout = usecs_to_jiffies(2200); + connector->bit_data.data = connector; + connector->bit_data.setsda = smi_ddc_setsda; + connector->bit_data.setscl = smi_ddc_setscl; + connector->bit_data.getsda = smi_ddc_getsda; + connector->bit_data.getscl = smi_ddc_getscl; + + if (i2c_bit_add_bus(&connector->adapter)) + { + return -1; + } + + return 0; +} + +long ddk750_AdaptSWI2CInit(struct smi_connector *smi_connector) +{ + struct drm_connector *connector = &smi_connector->base; + unsigned char i2cClkGPIO; + unsigned char i2cDataGPIO; + + if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) + { + i2cClkGPIO = 30; + i2cDataGPIO = 31; + } + else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA) + { + i2cClkGPIO = 17; + i2cDataGPIO = 18; + } + else + { + return -1; + } + + smi_connector->i2c_scl = i2cClkGPIO; + smi_connector->i2c_sda = i2cDataGPIO; + + if (adapterI2CInit(i2cClkGPIO, i2cDataGPIO)) + { + return (-1); + } + +#if 0 + /* Clear the i2c lines. */ + { + int i = 0; + for (i = 0; i < 9; i++) + ddk768_swI2CStop(); + } +#endif + + udelay(20); + + if (smi_ddc_create(smi_connector)) + { + return -1; + } + + return 0; +} + +/* After closing HW I2C, give a SCL clk by SW to avoid the deadlock */ +long ddk750_AdapSWI2CCleanBus( + struct smi_connector *connector) +{ + unsigned char i2cClkGPIO = connector->i2c_scl; + unsigned char i2cDataGPIO = connector->i2c_sda; + + if (adapterI2CInit(i2cClkGPIO, i2cDataGPIO)) + return (-1); + + udelay(20); + swI2CSCL(0); + udelay(20); + swI2CSCL(1); + udelay(20); + + return 0; +} + diff --git a/drivers/gpu/drm/smidrm/ddk750/ddk750_swi2c.h b/drivers/gpu/drm/smidrm/ddk750/ddk750_swi2c.h new file mode 100644 index 000000000000..ad328a52d263 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddk750_swi2c.h @@ -0,0 +1,111 @@ +#ifndef _SWI2C_H_ +#define _SWI2C_H_ + +#include "../smi_drv.h" + + +/* Default i2c CLK and Data GPIO. These are the default i2c pins */ +#define DEFAULT_I2C_SCL 30 +#define DEFAULT_I2C_SDA 31 + +/* + * This function initializes the i2c attributes and bus + * + * Parameters: + * i2cClkGPIO - The GPIO pin to be used as i2c SCL + * i2cDataGPIO - The GPIO pin to be used as i2c SDA + * + * Return Value: + * -1 - Fail to initialize the i2c + * 0 - Success + */ +long swI2CInit( + unsigned char i2cClkGPIO, + unsigned char i2cDataGPIO +); + +/* + * This function reads the slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be read from + * registerIndex - Slave device's register to be read + * + * Return Value: + * Register value + */ +unsigned char swI2CReadReg( + unsigned char deviceAddress, + unsigned char registerIndex +); + +/* + * This function reads the slave device's register continuously. + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be read from + * start_registerIndex - Slave device's first register(start address) to be read + * length - total length you want to read from the start address + * dest - buffer address which will store the data read from slave device + * + * Return Value: + * 0: fail + * actual size + */ +long swI2CReadReg_Continuous( + unsigned char deviceAddress, + unsigned char start_registerIndex, + unsigned long length, + unsigned char * dest +); + + + +/* + * This function writes a value to the slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be written + * registerIndex - Slave device's register to be written + * data - Data to be written to the register + * + * Result: + * 0 - Success + * -1 - Fail + */ +long swI2CWriteReg( + unsigned char deviceAddress, + unsigned char registerIndex, + unsigned char data +); + +/* + * These two functions are used to toggle the data on the SCL and SDA I2C lines. + * The used of these two functions are not recommended unless it is necessary. + */ + +/* + * This function set/reset the SCL GPIO pin + * + * Parameters: + * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) + */ +void swI2CSCL(unsigned char value); + +/* + * This function set/reset the SDA GPIO pin + * + * Parameters: + * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) + */ +void swI2CSDA(unsigned char value); + +long ddk750_AdaptSWI2CInit(struct smi_connector *smi_connector); + +long ddk750_AdapSWI2CCleanBus(struct smi_connector *connector); + + +#endif /* _SWI2C_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk750/ddkdebug.h b/drivers/gpu/drm/smidrm/ddk750/ddkdebug.h new file mode 100644 index 000000000000..aa1df840174f --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/ddkdebug.h @@ -0,0 +1,141 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* ddkdebug.h --- DDK Debug module +* This file contains the definitions for the SMI DDK debugging. +* +*******************************************************************/ +#ifndef _DDKDEBUG_H_ +#define _DDKDEBUG_H_ + +#ifdef DDKDEBUG + +/********************* + * Definition + *********************/ + +/* Debug Print Level definitions */ +/* Bit 16 ~ 31 are used by the library. Bit 0 ~ 15 can be used by application */ +#define ERROR_LEVEL 0x00010000 +#define WARNING_LEVEL 0x00020000 +#define INIT_LEVEL 0x00040000 +#define DISPLAY_LEVEL 0x00080000 +#define DMA_LEVEL 0x00100000 +#define DE_LEVEL 0x00200000 +#define CAPTURE_LEVEL 0x00400000 +#define SSP_LEVEL 0x00800000 +#define RESERVED8_LEVEL 0x01000000 +#define RESERVED9_LEVEL 0x02000000 +#define RESERVED10_LEVEL 0x04000000 +#define RESERVED11_LEVEL 0x08000000 +#define RESERVED12_LEVEL 0x10000000 +#define RESERVED13_LEVEL 0x20000000 +#define RESERVED14_LEVEL 0x40000000 +#define RESERVED15_LEVEL 0x80000000 + +#define SYSTEM_LEVEL_MASK 0xFFFF0000 +#define APPLICATION_LEVEL_MASK 0x0000FFFF + +/********************* + * Structure + *********************/ +typedef enum _ddk_debug_output_t +{ + DEBUG_OUTPUT_SCREEN = 0, + DEBUG_OUTPUT_FILE, + DEBUG_OUTPUT_SERIAL +} +ddk_debug_output_t; + +/********************* + * MACROS + *********************/ + +/* This function has to be called before calling other DEBUGPIRNT functions. */ +#define DDKDEBUGPRINTINIT(debugOutput, debugLevelMask) \ + ddkDebugPrintInit(debugOutput, debugLevelMask) + +/* This function enable or disable the debug message. + * Note: + * This function can be used to enable/disable the debug message + * at certain point of software, so that the debug messages, that + * are printed, are only the important ones. + */ +#define DDKDEBUGENABLE(arg) \ + ddkDebugEnable(arg) + +/* Calling the DDKDEBUGPRINT needs to have the arg to be enclosed with + two of open and close brackets. + Example: + DDKDEBUGPRINT(("Hello World: %s\n", pszString)); + */ +#define DDKDEBUGPRINT(arg) \ + ddkDebugPrint arg + +/* This function has to be called when exiting the application. + It is necessary to clean up the debug module. */ +#define DDKDEBUGPRINTEXIT() \ + ddkDebugPrintExit() + +/********************* + * Function prototype + *********************/ + +/* + * This function initializes the debug print out system. + * + * Input: + * debugOutput - Output where to print out the debug. It could be + * screen, file, or serial port. + * debugLevel - Debugging level + */ +void ddkDebugPrintInit(ddk_debug_output_t debugOutput, unsigned long debugLevelMask); + +/* + * This function enable or disable the debug message. + * + * Input: + * enableDebugMessage - Enable/disable the debug message + * 0 - Disable Debug Message + * 1 - Enable Debug Message + * + * Note: + * This function can be used to enable/disable the debug message + * at certain point of software, so that the debug messages, that + * are printed, are only the important ones. + */ +void ddkDebugEnable(unsigned char enableDebugMessage); + +/* + * This function prints out the formatted string. + * + * Input: + * debugLevel - The level of the debug of which the message is intended for. + * pszFormat - Format of the printed message + */ +void ddkDebugPrint(unsigned long debugLevel, const char* pszFormat, ...); + +/* + * This function cleans up (such as closing the debug file, etc...) when + * exiting the debug module. + */ +void ddkDebugPrintExit(); + +#else + +/* + * If there is no DEBUG definition, then treat the macro as an empty macro. + * Therefore all the debug print will be stripped out. + */ +#define DDKDEBUGPRINTINIT(debugOutput, debugLevelMask) +#define DDKDEBUGENABLE(arg) +#define DDKDEBUGPRINT(arg) +#define DDKDEBUGPRINTEXIT() + +#endif + +#endif /* _DDKDEBUG_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk750/siHdmiTx_902x_TPI.c b/drivers/gpu/drm/smidrm/ddk750/siHdmiTx_902x_TPI.c new file mode 100644 index 000000000000..4548433b155e --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/siHdmiTx_902x_TPI.c @@ -0,0 +1,3522 @@ +/*************************************************************************** + * + * SIMG PART NUMBER - HDMI Transmitter Driver + * + * Copyright (C) (2011, Silicon Image) + * + * 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; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include "siHdmiTx_902x_TPI.h" +#include "ddk750_hwi2c.h" +#include "ddk750_swi2c.h" + +#define i2cWriteReg swI2CWriteReg +#define i2cReadReg swI2CReadReg + + + +SIHDMITX_CONFIG siHdmiTx; +GLOBAL_SYSTEM g_sys; +GLOBAL_HDCP g_hdcp; +GLOBAL_EDID g_edid; +byte tpivmode[3]; // saved TPI Reg0x08/Reg0x09/Reg0x0A values. + +bool Sii9024A_HDCP_supported=false; //if the chip is 9024A, you can support HDCP by set this variable to 1.If the chip is 9022A, it means noting. + + +//bool HDCP_Supported=false; + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////// The following functions are related with target system!!! ////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +//sbit siHdmiTx_HwResetPin = P2^1; // Connected to 9022A/4A pin C3 (CRST#) + +//extern void DelayMS (word MS); +//extern byte I2CReadByte ( byte SlaveAddr, byte RegAddr ); +//extern void I2CWriteByte ( byte SlaveAddr, byte RegAddr, byte Data ); +//extern byte I2CReadBlock( byte SlaveAddr, byte RegAddr, byte NBytes, byte * Data ); +//extern byte I2CWriteBlock( byte SlaveAddr, byte RegAddr, byte NBytes, byte * Data ); +//extern byte siiReadSegmentBlockEDID(byte SlaveAddr, byte Segment, byte Offset, byte *Buffer, byte Length); + +struct i2c_client *sii902xA = NULL; +struct i2c_client *siiEDID = NULL; +struct i2c_client *siiSegEDID = NULL; +struct i2c_client *siiHDCP = NULL; + + + +void DelayMS (word MS) +{ + mdelay(MS);//call linux kernel delay API function +} + + +byte I2CReadBlock(struct i2c_client *client, byte RegAddr, byte NBytes, byte * Data ) +{ + byte i = 0; + while(i Internal page num +// 2. 0xBD => Indexed register offset +// +// Read: +// 3. 0xBE => Returns the indexed register value +//------------------------------------------------------------------------------ +byte ReadIndexedRegister(byte PageNum, byte RegOffset) +{ + WriteByteTPI(TPI_INTERNAL_PAGE_REG, PageNum); // Internal page + WriteByteTPI(TPI_INDEXED_OFFSET_REG, RegOffset); // Indexed register + return ReadByteTPI(TPI_INDEXED_VALUE_REG); // Return read value +} + +//------------------------------------------------------------------------------ +// Function Name: WriteIndexedRegister() +// Function Description: Write a value to an indexed register +// +// Write: +// 1. 0xBC => Internal page num +// 2. 0xBD => Indexed register offset +// 3. 0xBE => Set the indexed register value +//------------------------------------------------------------------------------ +void WriteIndexedRegister (byte PageNum, byte RegOffset, byte RegValue) +{ + WriteByteTPI(TPI_INTERNAL_PAGE_REG, PageNum); // Internal page + WriteByteTPI(TPI_INDEXED_OFFSET_REG, RegOffset); // Indexed register + WriteByteTPI(TPI_INDEXED_VALUE_REG, RegValue); // Read value into buffer +} + +//------------------------------------------------------------------------------ +// Function Name: ReadModifyWriteIndexedRegister() +// Function Description: Write "Value" to all bits in TPI offset "Offset" that are set +// to "1" in "Mask"; Leave all other bits in "Offset" +// unchanged. +//------------------------------------------------------------------------------ +void ReadModifyWriteIndexedRegister(byte PageNum, byte RegOffset, byte Mask, byte Value) +{ + byte Tmp; + WriteByteTPI(TPI_INTERNAL_PAGE_REG, PageNum); + WriteByteTPI(TPI_INDEXED_OFFSET_REG, RegOffset); + Tmp = ReadByteTPI(TPI_INDEXED_VALUE_REG); + + Tmp &= ~Mask; + Tmp |= (Value & Mask); + + WriteByteTPI(TPI_INDEXED_VALUE_REG, Tmp); +} + +//------------------------------------------------------------------------------ +void TXHAL_InitPostReset (void) +{ + // Set terminations to default. + WriteByteTPI(TMDS_CONT_REG, 0x25); + // HW debounce to 64ms (0x14) + WriteByteTPI(0x7C, 0x14); +} + +#if 0 +void TxHW_Reset (void) +{ + TPI_TRACE_PRINT((">>TxHW_Reset()\n")); + + Sii902xA_plat_data = sii902xA->dev.platform_data; + if (Sii902xA_plat_data->reset) + Sii902xA_plat_data->reset(); + /* + siHdmiTx_HwResetPin = LOW; + DelayMS(TX_HW_RESET_PERIOD); + siHdmiTx_HwResetPin = HIGH; + */ + TXHAL_InitPostReset(); +} +#endif + +//------------------------------------------------------------------------------ +// Function Name: InitializeStateVariables() +// Function Description: Initialize system state variables +//------------------------------------------------------------------------------ +void InitializeStateVariables (void) +{ + g_sys.tmdsPoweredUp = FALSE; + g_sys.hdmiCableConnected = FALSE; + g_sys.dsRxPoweredUp = FALSE; + +#ifdef DEV_SUPPORT_EDID + g_edid.edidDataValid = FALSE; +#endif +} + +//------------------------------------------------------------------------------ +// Function Name: EnableTMDS() +// Function Description: Enable TMDS +//------------------------------------------------------------------------------ +void EnableTMDS (void) +{ + TPI_DEBUG_PRINT(("TMDS -> Enabled\n")); + ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, TMDS_OUTPUT_CONTROL_MASK, TMDS_OUTPUT_CONTROL_ACTIVE); + WriteByteTPI(TPI_PIX_REPETITION, tpivmode[0]); // Write register 0x08 + g_sys.tmdsPoweredUp = TRUE; +} + +//------------------------------------------------------------------------------ +// Function Name: DisableTMDS() +// Function Description: Disable TMDS +//------------------------------------------------------------------------------ +void DisableTMDS (void) +{ + TPI_DEBUG_PRINT(("TMDS -> Disabled\n")); + ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, TMDS_OUTPUT_CONTROL_MASK | AV_MUTE_MASK, + TMDS_OUTPUT_CONTROL_POWER_DOWN | AV_MUTE_MUTED); + g_sys.tmdsPoweredUp = FALSE; +} + +//------------------------------------------------------------------------------ +// Function Name: EnableInterrupts() +// Function Description: Enable the interrupts specified in the input parameter +// +// Accepts: A bit pattern with "1" for each interrupt that needs to be +// set in the Interrupt Enable Register (TPI offset 0x3C) +// Returns: TRUE +// Globals: none +//------------------------------------------------------------------------------ +byte EnableInterrupts(byte Interrupt_Pattern) +{ + TPI_TRACE_PRINT((">>EnableInterrupts()\n")); + ReadSetWriteTPI(TPI_INTERRUPT_ENABLE_REG, Interrupt_Pattern); + return TRUE; +} + +//------------------------------------------------------------------------------ +// Function Name: DisableInterrupts() +// Function Description: Disable the interrupts specified in the input parameter +// +// Accepts: A bit pattern with "1" for each interrupt that needs to be +// cleared in the Interrupt Enable Register (TPI offset 0x3C) +// Returns: TRUE +// Globals: none +//------------------------------------------------------------------------------ +byte DisableInterrupts (byte Interrupt_Pattern) +{ + TPI_TRACE_PRINT((">>DisableInterrupts()\n")); + ReadClearWriteTPI(TPI_INTERRUPT_ENABLE_REG, Interrupt_Pattern); + + return TRUE; +} + + + +#ifdef DEV_SUPPORT_EDID +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +///////////////////////*************************/////////////////////////////// +/////////////////////// EDID /////////////////////////////// +///////////////////////*************************/////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static u8 g_CommData [EDID_BLOCK_SIZE]; + +#define ReadBlockEDID(a,b,c) I2CReadEDID(siiEDID, a, b, c) +#define ReadSegmentBlockEDID(a,b,c,d) siiReadSegmentBlockEDID(siiEDID, a, b, d, c) + +//------------------------------------------------------------------------------ +// Function Name: GetDDC_Access() +// Function Description: Request access to DDC bus from the receiver +// +// Accepts: none +// Returns: TRUE or FLASE +// Globals: none +//------------------------------------------------------------------------------ +#define T_DDC_ACCESS 50 + +byte GetDDC_Access (byte* SysCtrlRegVal) +{ + byte sysCtrl; + byte DDCReqTimeout = T_DDC_ACCESS; + byte TPI_ControlImage; + + + sysCtrl = ReadByteTPI (TPI_SYSTEM_CONTROL_DATA_REG); // Read and store original value. Will be passed into ReleaseDDC() + *SysCtrlRegVal = sysCtrl; + + sysCtrl |= DDC_BUS_REQUEST_REQUESTED; + WriteByteTPI (TPI_SYSTEM_CONTROL_DATA_REG, sysCtrl); + + while (DDCReqTimeout--) // Loop till 0x1A[1] reads "1" + { + TPI_ControlImage = ReadByteTPI(TPI_SYSTEM_CONTROL_DATA_REG); + + if (TPI_ControlImage & DDC_BUS_GRANT_MASK) // When 0x1A[1] reads "1" + { + sysCtrl |= DDC_BUS_GRANT_GRANTED; + WriteByteTPI(TPI_SYSTEM_CONTROL_DATA_REG, sysCtrl); // lock host DDC bus access (0x1A[2:1] = 11) + return TRUE; + } + WriteByteTPI(TPI_SYSTEM_CONTROL_DATA_REG, sysCtrl); // 0x1A[2] = "1" - Requst the DDC bus + DelayMS(200); + } + + WriteByteTPI(TPI_SYSTEM_CONTROL_DATA_REG, sysCtrl); // Failure... restore original value. + printk("Get DDC Access failed\n"); + return FALSE; +} + +//------------------------------------------------------------------------------ +// Function Name: ReleaseDDC() +// Function Description: Release DDC bus +// +// Accepts: none +// Returns: TRUE if bus released successfully. FALSE if failed. +// Globals: none +//------------------------------------------------------------------------------ +byte ReleaseDDC (byte SysCtrlRegVal) +{ + byte DDCReqTimeout = T_DDC_ACCESS; + byte TPI_ControlImage; + + SysCtrlRegVal &= ~BITS_2_1; // Just to be sure bits [2:1] are 0 before it is written + + while (DDCReqTimeout--) // Loop till 0x1A[1] reads "0" + { + // Cannot use ReadClearWriteTPI() here. A read of TPI_SYSTEM_CONTROL is invalid while DDC is granted. + // Doing so will return 0xFF, and cause an invalid value to be written back. + //ReadClearWriteTPI(TPI_SYSTEM_CONTROL,BITS_2_1); // 0x1A[2:1] = "0" - release the DDC bus + + WriteByteTPI(TPI_SYSTEM_CONTROL_DATA_REG, SysCtrlRegVal); + TPI_ControlImage = ReadByteTPI(TPI_SYSTEM_CONTROL_DATA_REG); + + if (!(TPI_ControlImage & BITS_2_1)) // When 0x1A[2:1] read "0" + return TRUE; + } + printk("failed to release DDC bus control\n"); + return FALSE; // Failed to release DDC bus control +} + +//------------------------------------------------------------------------------ +// Function Name: CheckEDID_Header() +// Function Description: Checks if EDID header is correct per VESA E-EDID standard +// +// Accepts: Pointer to 1st EDID block +// Returns: TRUE or FLASE +// Globals: EDID data +//------------------------------------------------------------------------------ +byte CheckEDID_Header (byte *Block) +{ + byte i = 0; + + if (Block[i]) // byte 0 must be 0 + return FALSE; + + for (i = 1; i < 1 + EDID_HDR_NO_OF_FF; i++) + { + if(Block[i] != 0xFF) // bytes [1..6] must be 0xFF + return FALSE; + } + + if (Block[i]) // byte 7 must be 0 + return FALSE; + + return TRUE; +} + +//------------------------------------------------------------------------------ +// Function Name: DoEDID_Checksum() +// Function Description: Calculte checksum of the 128 byte block pointed to by the +// pointer passed as parameter +// +// Accepts: Pointer to a 128 byte block whose checksum needs to be calculated +// Returns: TRUE or FLASE +// Globals: EDID data +//------------------------------------------------------------------------------ +byte DoEDID_Checksum (byte *Block) +{ + byte i; + byte CheckSum = 0; + + for (i = 0; i < EDID_BLOCK_SIZE; i++) + CheckSum += Block[i]; + + if (CheckSum) + return FALSE; + + return TRUE; +} + +//------------------------------------------------------------------------------ +// Function Name: ParseEstablishedTiming() +// Function Description: Parse the established timing section of EDID Block 0 and +// print their decoded meaning to the screen. +// +// Accepts: Pointer to the 128 byte array where the data read from EDID Block0 is stored. +// Returns: none +// Globals: EDID data +//------------------------------------------------------------------------------ +#if (CONF__TPI_EDID_PRINT == ENABLE) +void ParseEstablishedTiming (byte *Data) +{ + TPI_EDID_PRINT(("Parsing Established Timing:\n")); + TPI_EDID_PRINT(("===========================\n")); + + // Parse Established Timing Byte #0 + if(Data[ESTABLISHED_TIMING_INDEX] & BIT_7) + TPI_EDID_PRINT(("720 x 400 @ 70Hz\n")); + if(Data[ESTABLISHED_TIMING_INDEX] & BIT_6) + TPI_EDID_PRINT(("720 x 400 @ 88Hz\n")); + if(Data[ESTABLISHED_TIMING_INDEX] & BIT_5) + TPI_EDID_PRINT(("640 x 480 @ 60Hz\n")); + if(Data[ESTABLISHED_TIMING_INDEX] & BIT_4) + TPI_EDID_PRINT(("640 x 480 @ 67Hz\n")); + if(Data[ESTABLISHED_TIMING_INDEX] & BIT_3) + TPI_EDID_PRINT(("640 x 480 @ 72Hz\n")); + if(Data[ESTABLISHED_TIMING_INDEX] & BIT_2) + TPI_EDID_PRINT(("640 x 480 @ 75Hz\n")); + if(Data[ESTABLISHED_TIMING_INDEX] & BIT_1) + TPI_EDID_PRINT(("800 x 600 @ 56Hz\n")); + if(Data[ESTABLISHED_TIMING_INDEX] & BIT_0) + TPI_EDID_PRINT(("800 x 400 @ 60Hz\n")); + + // Parse Established Timing Byte #1: + if(Data[ESTABLISHED_TIMING_INDEX + 1] & BIT_7) + TPI_EDID_PRINT(("800 x 600 @ 72Hz\n")); + if(Data[ESTABLISHED_TIMING_INDEX + 1] & BIT_6) + TPI_EDID_PRINT(("800 x 600 @ 75Hz\n")); + if(Data[ESTABLISHED_TIMING_INDEX + 1] & BIT_5) + TPI_EDID_PRINT(("832 x 624 @ 75Hz\n")); + if(Data[ESTABLISHED_TIMING_INDEX + 1] & BIT_4) + TPI_EDID_PRINT(("1024 x 768 @ 87Hz\n")); + if(Data[ESTABLISHED_TIMING_INDEX + 1] & BIT_3) + TPI_EDID_PRINT(("1024 x 768 @ 60Hz\n")); + if(Data[ESTABLISHED_TIMING_INDEX + 1] & BIT_2) + TPI_EDID_PRINT(("1024 x 768 @ 70Hz\n")); + if(Data[ESTABLISHED_TIMING_INDEX + 1] & BIT_1) + TPI_EDID_PRINT(("1024 x 768 @ 75Hz\n")); + if(Data[ESTABLISHED_TIMING_INDEX + 1] & BIT_0) + TPI_EDID_PRINT(("1280 x 1024 @ 75Hz\n")); + + // Parse Established Timing Byte #2: + if(Data[ESTABLISHED_TIMING_INDEX + 2] & 0x80) + TPI_EDID_PRINT(("1152 x 870 @ 75Hz\n")); + + if((!Data[0])&&(!Data[ESTABLISHED_TIMING_INDEX + 1] )&&(!Data[2])) + TPI_EDID_PRINT(("No established video modes\n")); +} + +//------------------------------------------------------------------------------ +// Function Name: ParseStandardTiming() +// Function Description: Parse the standard timing section of EDID Block 0 and +// print their decoded meaning to the screen. +// +// Accepts: Pointer to the 128 byte array where the data read from EDID Block0 is stored. +// Returns: none +// Globals: EDID data +//------------------------------------------------------------------------------ +void ParseStandardTiming (byte *Data) +{ + byte i; + byte AR_Code; + + TPI_EDID_PRINT(("Parsing Standard Timing:\n")); + TPI_EDID_PRINT(("========================\n")); + + for (i = 0; i < NUM_OF_STANDARD_TIMINGS; i += 2) + { + if ((Data[STANDARD_TIMING_OFFSET + i] == 0x01) && ((Data[STANDARD_TIMING_OFFSET + i +1]) == 1)) + { + TPI_EDID_PRINT(("Standard Timing Undefined\n")); // per VESA EDID standard, Release A, Revision 1, February 9, 2000, Sec. 3.9 + } + else + { + TPI_EDID_PRINT(("Horizontal Active pixels: %i\n", (int)((Data[STANDARD_TIMING_OFFSET + i] + 31)*8))); // per VESA EDID standard, Release A, Revision 1, February 9, 2000, Table 3.15 + + AR_Code = (Data[STANDARD_TIMING_OFFSET + i +1] & TWO_MSBITS) >> 6; + TPI_EDID_PRINT(("Aspect Ratio: ")); + + switch(AR_Code) + { + case AR16_10: + TPI_EDID_PRINT(("16:10\n")); + break; + + case AR4_3: + TPI_EDID_PRINT(("4:3\n")); + break; + + case AR5_4: + TPI_EDID_PRINT(("5:4\n")); + break; + + case AR16_9: + TPI_EDID_PRINT(("16:9\n")); + break; + } + } + } +} + +//------------------------------------------------------------------------------ +// Function Name: ParseDetailedTiming() +// Function Description: Parse the detailed timing section of EDID Block 0 and +// print their decoded meaning to the screen. +// +// Accepts: Pointer to the 128 byte array where the data read from EDID Block0 is stored. +// Offset to the beginning of the Detailed Timing Descriptor data. +// +// Block indicator to distinguish between block #0 and blocks #2, #3 +// Returns: none +// Globals: EDID data +//------------------------------------------------------------------------------ +byte ParseDetailedTiming (byte *Data, byte DetailedTimingOffset, byte Block) +{ + byte TmpByte; + byte i; + word TmpWord; + + TmpWord = Data[DetailedTimingOffset + PIX_CLK_OFFSET] + + 256 * Data[DetailedTimingOffset + PIX_CLK_OFFSET + 1]; + + if (TmpWord == 0x00) // 18 byte partition is used as either for Monitor Name or for Monitor Range Limits or it is unused + { + if (Block == EDID_BLOCK_0) // if called from Block #0 and first 2 bytes are 0 => either Monitor Name or for Monitor Range Limits + { + if (Data[DetailedTimingOffset + 3] == 0xFC) // these 13 bytes are ASCII coded monitor name + { + TPI_EDID_PRINT(("Monitor Name: ")); + + for (i = 0; i < 13; i++) + { + TPI_EDID_PRINT(("%c", Data[DetailedTimingOffset + 5 + i])); // Display monitor name on SiIMon + } + TPI_EDID_PRINT(("\n")); + } + + else if (Data[DetailedTimingOffset + 3] == 0xFD) // these 13 bytes contain Monitor Range limits, binary coded + { + TPI_EDID_PRINT(("Monitor Range Limits:\n\n")); + + i = 0; + TPI_EDID_PRINT(("Min Vertical Rate in Hz: %d\n", (int) Data[DetailedTimingOffset + 5 + i++])); // + TPI_EDID_PRINT(("Max Vertical Rate in Hz: %d\n", (int) Data[DetailedTimingOffset + 5 + i++])); // + TPI_EDID_PRINT(("Min Horizontal Rate in Hz: %d\n", (int) Data[DetailedTimingOffset + 5 + i++])); // + TPI_EDID_PRINT(("Max Horizontal Rate in Hz: %d\n", (int) Data[DetailedTimingOffset + 5 + i++])); // + TPI_EDID_PRINT(("Max Supported pixel clock rate in MHz/10: %d\n", (int) Data[DetailedTimingOffset + 5 + i++])); // + TPI_EDID_PRINT(("Tag for secondary timing formula (00h=not used): %d\n", (int) Data[DetailedTimingOffset + 5 + i++])); // + TPI_EDID_PRINT(("Min Vertical Rate in Hz %d\n", (int) Data[DetailedTimingOffset + 5 + i])); // + TPI_EDID_PRINT(("\n")); + } + } + + else if (Block == EDID_BLOCK_2_3) // if called from block #2 or #3 and first 2 bytes are 0x00 (padding) then this + { // descriptor partition is not used and parsing should be stopped + TPI_EDID_PRINT(("No More Detailed descriptors in this block\n")); + TPI_EDID_PRINT(("\n")); + return FALSE; + } + } + + else // first 2 bytes are not 0 => this is a detailed timing descriptor from either block + { + if((Block == EDID_BLOCK_0) && (DetailedTimingOffset == 0x36)) + { + TPI_EDID_PRINT(("\n\n\nParse Results, EDID Block #0, Detailed Descriptor Number 1:\n")); + TPI_EDID_PRINT(("===========================================================\n\n")); + } + else if((Block == EDID_BLOCK_0) && (DetailedTimingOffset == 0x48)) + { + TPI_EDID_PRINT(("\n\n\nParse Results, EDID Block #0, Detailed Descriptor Number 2:\n")); + TPI_EDID_PRINT(("===========================================================\n\n")); + } + + TPI_EDID_PRINT(("Pixel Clock (MHz * 100): %d\n", (int)TmpWord)); + + TmpWord = Data[DetailedTimingOffset + H_ACTIVE_OFFSET] + + 256 * ((Data[DetailedTimingOffset + H_ACTIVE_OFFSET + 2] >> 4) & FOUR_LSBITS); + TPI_EDID_PRINT(("Horizontal Active Pixels: %d\n", (int)TmpWord)); + + TmpWord = Data[DetailedTimingOffset + H_BLANKING_OFFSET] + + 256 * (Data[DetailedTimingOffset + H_BLANKING_OFFSET + 1] & FOUR_LSBITS); + TPI_EDID_PRINT(("Horizontal Blanking (Pixels): %d\n", (int)TmpWord)); + + TmpWord = (Data[DetailedTimingOffset + V_ACTIVE_OFFSET] )+ + 256 * ((Data[DetailedTimingOffset + (V_ACTIVE_OFFSET) + 2] >> 4) & FOUR_LSBITS); + TPI_EDID_PRINT(("Vertical Active (Lines): %d\n", (int)TmpWord)); + + TmpWord = Data[DetailedTimingOffset + V_BLANKING_OFFSET] + + 256 * (Data[DetailedTimingOffset + V_BLANKING_OFFSET + 1] & LOW_NIBBLE); + TPI_EDID_PRINT(("Vertical Blanking (Lines): %d\n", (int)TmpWord)); + + TmpWord = Data[DetailedTimingOffset + H_SYNC_OFFSET] + + 256 * ((Data[DetailedTimingOffset + (H_SYNC_OFFSET + 3)] >> 6) & TWO_LSBITS); + TPI_EDID_PRINT(("Horizontal Sync Offset (Pixels): %d\n", (int)TmpWord)); + + TmpWord = Data[DetailedTimingOffset + H_SYNC_PW_OFFSET] + + 256 * ((Data[DetailedTimingOffset + (H_SYNC_PW_OFFSET + 2)] >> 4) & TWO_LSBITS); + TPI_EDID_PRINT(("Horizontal Sync Pulse Width (Pixels): %d\n", (int)TmpWord)); + + TmpWord = (Data[DetailedTimingOffset + V_SYNC_OFFSET] >> 4) & FOUR_LSBITS + + 256 * ((Data[DetailedTimingOffset + (V_SYNC_OFFSET + 1)] >> 2) & TWO_LSBITS); + TPI_EDID_PRINT(("Vertical Sync Offset (Lines): %d\n", (int)TmpWord)); + + TmpWord = (Data[DetailedTimingOffset + V_SYNC_PW_OFFSET]) & FOUR_LSBITS + + 256 * (Data[DetailedTimingOffset + (V_SYNC_PW_OFFSET + 1)] & TWO_LSBITS); + TPI_EDID_PRINT(("Vertical Sync Pulse Width (Lines): %d\n", (int)TmpWord)); + + TmpWord = Data[DetailedTimingOffset + H_IMAGE_SIZE_OFFSET] + + 256 * (((Data[DetailedTimingOffset + (H_IMAGE_SIZE_OFFSET + 2)]) >> 4) & FOUR_LSBITS); + TPI_EDID_PRINT(("Horizontal Image Size (mm): %d\n", (int)TmpWord)); + + TmpWord = Data[DetailedTimingOffset + V_IMAGE_SIZE_OFFSET] + + 256 * (Data[DetailedTimingOffset + (V_IMAGE_SIZE_OFFSET + 1)] & FOUR_LSBITS); + TPI_EDID_PRINT(("Vertical Image Size (mm): %d\n", (int)TmpWord)); + + TmpByte = Data[DetailedTimingOffset + H_BORDER_OFFSET]; + TPI_EDID_PRINT(("Horizontal Border (Pixels): %d\n", (int)TmpByte)); + + TmpByte = Data[DetailedTimingOffset + V_BORDER_OFFSET]; + TPI_EDID_PRINT(("Vertical Border (Lines): %d\n", (int)TmpByte)); + + TmpByte = Data[DetailedTimingOffset + FLAGS_OFFSET]; + if (TmpByte & BIT_7) + TPI_EDID_PRINT(("Interlaced\n")); + else + TPI_EDID_PRINT(("Non-Interlaced\n")); + + if (!(TmpByte & BIT_5) && !(TmpByte & BIT_6)) + TPI_EDID_PRINT(("Normal Display, No Stereo\n")); + else + TPI_EDID_PRINT(("Refer to VESA E-EDID Release A, Revision 1, table 3.17\n")); + + if (!(TmpByte & BIT_3) && !(TmpByte & BIT_4)) + TPI_EDID_PRINT(("Analog Composite\n")); + if ((TmpByte & BIT_3) && !(TmpByte & BIT_4)) + TPI_EDID_PRINT(("Bipolar Analog Composite\n")); + else if (!(TmpByte & BIT_3) && (TmpByte & BIT_4)) + TPI_EDID_PRINT(("Digital Composite\n")); + + else if ((TmpByte & BIT_3) && (TmpByte & BIT_4)) + TPI_EDID_PRINT(("Digital Separate\n")); + + TPI_EDID_PRINT(("\n")); + } + return TRUE; +} + +//------------------------------------------------------------------------------ +// Function Name: ParseBlock_0_TimingDescriptors() +// Function Description: Parse EDID Block 0 timing descriptors per EEDID 1.3 +// standard. printf() values to screen. +// +// Accepts: Pointer to the 128 byte array where the data read from EDID Block0 is stored. +// Returns: none +// Globals: EDID data +//------------------------------------------------------------------------------ +void ParseBlock_0_TimingDescriptors (byte *Data) +{ + byte i; + byte Offset; + + ParseEstablishedTiming(Data); + ParseStandardTiming(Data); + + for (i = 0; i < NUM_OF_DETAILED_DESCRIPTORS; i++) + { + Offset = DETAILED_TIMING_OFFSET + (LONG_DESCR_LEN * i); + ParseDetailedTiming(Data, Offset, EDID_BLOCK_0); + } +} +#endif + +//------------------------------------------------------------------------------ +// Function Name: ParseEDID() +// Function Description: Extract sink properties from its EDID file and save them in +// global structure g_edid. +// +// Accepts: none +// Returns: TRUE or FLASE +// Globals: EDID data +// NOTE: Fields that are not supported by the 9022/4 (such as deep color) were not parsed. +//------------------------------------------------------------------------------ +byte ParseEDID (byte *pEdid, byte *numExt) +{ + byte i, j, k; + + TPI_EDID_PRINT(("\n")); + TPI_EDID_PRINT(("EDID DATA (Segment = 0 Block = 0 Offset = %d):\n", (int) EDID_BLOCK_0_OFFSET)); + + for (j = 0, i = 0; j < 128; j++) + { + k = pEdid[j]; + TPI_EDID_PRINT(("%2.2X ", (int) k)); + i++; + + if (i == 0x10) + { + TPI_EDID_PRINT(("\n")); + i = 0; + } + } + TPI_EDID_PRINT(("\n")); + + if (!CheckEDID_Header(pEdid)) //Checks if EDID header is correct per VESA E-EDID standard(/byte 0 must be 0, bytes [1..6] must be 0xFF,byte 7 must be 0) + { + // first 8 bytes of EDID must be {0, FF, FF, FF, FF, FF, FF, 0} + TPI_DEBUG_PRINT(("EDID -> Incorrect Header\n")); + return EDID_INCORRECT_HEADER; + } + + if (!DoEDID_Checksum(pEdid)) + { + // non-zero EDID checksum + TPI_DEBUG_PRINT(("EDID -> Checksum Error\n")); + return EDID_CHECKSUM_ERROR; + } + +#if (CONF__TPI_EDID_PRINT == ENABLE) + ParseBlock_0_TimingDescriptors(pEdid); // Parse EDID Block #0 Desctiptors +#endif + + *numExt = pEdid[NUM_OF_EXTEN_ADDR]; // read # of extensions from offset 0x7E of block 0 + TPI_EDID_PRINT(("EDID -> 861 Extensions = %d\n", (int) *numExt)); + + if (!(*numExt)) + { + // No extensions to worry about + return EDID_NO_861_EXTENSIONS; + } + + //return Parse861Extensions(NumOfExtensions); // Parse 861 Extensions (short and long descriptors); + return (EDID_OK); +} + +//------------------------------------------------------------------------------ +// Function Name: Parse861ShortDescriptors() +// Function Description: Parse CEA-861 extension short descriptors of the EDID block +// passed as a parameter and save them in global structure g_edid. +// +// Accepts: A pointer to the EDID 861 Extension block being parsed. +// Returns: EDID_PARSED_OK if EDID parsed correctly. Error code if failed. +// Globals: EDID data +// NOTE: Fields that are not supported by the 9022/4 (such as deep color) were not parsed. +//------------------------------------------------------------------------------ +byte Parse861ShortDescriptors (byte *Data) +{ + byte LongDescriptorOffset; + byte DataBlockLength; + byte DataIndex; + byte ExtendedTagCode; + byte VSDB_BaseOffset = 0; + + byte V_DescriptorIndex = 0; // static to support more than one extension + byte A_DescriptorIndex = 0; // static to support more than one extension + + byte TagCode; + + byte i; + byte j; + + if (Data[EDID_TAG_ADDR] != EDID_EXTENSION_TAG) + { + TPI_EDID_PRINT(("EDID -> Extension Tag Error\n")); + return EDID_EXT_TAG_ERROR; + } + + if (Data[EDID_REV_ADDR] != EDID_REV_THREE) + { + TPI_EDID_PRINT(("EDID -> Revision Error\n")); + return EDID_REV_ADDR_ERROR; + } + + LongDescriptorOffset = Data[LONG_DESCR_PTR_IDX]; // block offset where long descriptors start + + g_edid.UnderScan = ((Data[MISC_SUPPORT_IDX]) >> 7) & LSBIT; // byte #3 of CEA extension version 3 + g_edid.BasicAudio = ((Data[MISC_SUPPORT_IDX]) >> 6) & LSBIT; + g_edid.YCbCr_4_4_4 = ((Data[MISC_SUPPORT_IDX]) >> 5) & LSBIT; + g_edid.YCbCr_4_2_2 = ((Data[MISC_SUPPORT_IDX]) >> 4) & LSBIT; + + DataIndex = EDID_DATA_START; // 4 + + while (DataIndex < LongDescriptorOffset) + { + TagCode = (Data[DataIndex] >> 5) & THREE_LSBITS; + DataBlockLength = Data[DataIndex++] & FIVE_LSBITS; + if ((DataIndex + DataBlockLength) > LongDescriptorOffset) + { + TPI_EDID_PRINT(("EDID -> V Descriptor Overflow\n")); + return EDID_V_DESCR_OVERFLOW; + } + + i = 0; // num of short video descriptors in current data block + + switch (TagCode) + { + case VIDEO_D_BLOCK: + while ((i < DataBlockLength) && (i < MAX_V_DESCRIPTORS)) // each SVD is 1 byte long + { + g_edid.VideoDescriptor[V_DescriptorIndex++] = Data[DataIndex++]; + i++; + } + DataIndex += DataBlockLength - i; // if there are more STDs than MAX_V_DESCRIPTORS, skip the last ones. Update DataIndex + + TPI_EDID_PRINT(("EDID -> Short Descriptor Video Block\n")); + break; + + case AUDIO_D_BLOCK: + while (i < DataBlockLength/3) // each SAD is 3 bytes long + { + j = 0; + while (j < AUDIO_DESCR_SIZE) // 3 + { + g_edid.AudioDescriptor[A_DescriptorIndex][j++] = Data[DataIndex++]; + } + A_DescriptorIndex++; + i++; + } + TPI_EDID_PRINT(("EDID -> Short Descriptor Audio Block\n")); + break; + + case SPKR_ALLOC_D_BLOCK: + g_edid.SpkrAlloc[i++] = Data[DataIndex++]; // although 3 bytes are assigned to Speaker Allocation, only + DataIndex += 2; // the first one carries information, so the next two are ignored by this code. + TPI_EDID_PRINT(("EDID -> Short Descriptor Speaker Allocation Block\n")); + break; + + case USE_EXTENDED_TAG: + ExtendedTagCode = Data[DataIndex++]; + + switch (ExtendedTagCode) + { + case VIDEO_CAPABILITY_D_BLOCK: + TPI_EDID_PRINT(("EDID -> Short Descriptor Video Capability Block\n")); + + // TO BE ADDED HERE: Save "video capability" parameters in g_edid data structure + // Need to modify that structure definition + // In the meantime: just increment DataIndex by 1 + DataIndex += 1; // replace with reading and saving the proper data per CEA-861 sec. 7.5.6 while incrementing DataIndex + break; + + case COLORIMETRY_D_BLOCK: + g_edid.ColorimetrySupportFlags = Data[DataIndex++] & BITS_1_0; + g_edid.MetadataProfile = Data[DataIndex++] & BITS_2_1_0; + + TPI_EDID_PRINT(("EDID -> Short Descriptor Colorimetry Block\n")); + break; + } + break; + + case VENDOR_SPEC_D_BLOCK: + VSDB_BaseOffset = DataIndex - 1; + + if ((Data[DataIndex++] == 0x03) && // check if sink is HDMI compatible + (Data[DataIndex++] == 0x0C) && + (Data[DataIndex++] == 0x00)) + + g_edid.HDMI_Sink = TRUE; + else + g_edid.HDMI_Sink = FALSE; + + g_edid.CEC_A_B = Data[DataIndex++]; // CEC Physical address + g_edid.CEC_C_D = Data[DataIndex++]; + +#ifdef DEV_SUPPORT_CEC + // Take the Address that was passed in the EDID and use this API + // to set the physical address for CEC. + { + word phyAddr; + phyAddr = (word)g_edid.CEC_C_D; // Low-order nibbles + phyAddr |= ((word)g_edid.CEC_A_B << 8); // Hi-order nibbles + // Is the new PA different from the current PA? + if (phyAddr != SI_CecGetDevicePA ()) + { + // Yes! So change the PA + SI_CecSetDevicePA (phyAddr); + } + } +#endif + + if ((DataIndex + 7) > VSDB_BaseOffset + DataBlockLength) // Offset of 3D_Present bit in VSDB + g_edid._3D_Supported = FALSE; + else if (Data[DataIndex + 7] >> 7) + g_edid._3D_Supported = TRUE; + else + g_edid._3D_Supported = FALSE; + + DataIndex += DataBlockLength - HDMI_SIGNATURE_LEN - CEC_PHYS_ADDR_LEN; // Point to start of next block + TPI_EDID_PRINT(("EDID -> Short Descriptor Vendor Block\n")); + TPI_EDID_PRINT(("\n")); + break; + + default: + TPI_EDID_PRINT(("EDID -> Unknown Tag Code\n")); + return EDID_UNKNOWN_TAG_CODE; + + } // End, Switch statement + } // End, while (DataIndex < LongDescriptorOffset) statement + + return EDID_SHORT_DESCRIPTORS_OK; +} + +//------------------------------------------------------------------------------ +// Function Name: Parse861LongDescriptors() +// Function Description: Parse CEA-861 extension long descriptors of the EDID block +// passed as a parameter and printf() them to the screen. +// +// Accepts: A pointer to the EDID block being parsed +// Returns: An error code if no long descriptors found; EDID_PARSED_OK if descriptors found. +// Globals: none +//------------------------------------------------------------------------------ +byte Parse861LongDescriptors (byte *Data) +{ + byte LongDescriptorsOffset; + byte DescriptorNum = 1; + + LongDescriptorsOffset = Data[LONG_DESCR_PTR_IDX]; // EDID block offset 2 holds the offset + + if (!LongDescriptorsOffset) // per CEA-861-D, table 27 + { + TPI_DEBUG_PRINT(("EDID -> No Detailed Descriptors\n")); + return EDID_NO_DETAILED_DESCRIPTORS; + } + + // of the 1st 18-byte descriptor + while (LongDescriptorsOffset + LONG_DESCR_LEN < EDID_BLOCK_SIZE) + { + TPI_EDID_PRINT(("Parse Results - CEA-861 Long Descriptor #%d:\n", (int) DescriptorNum)); + TPI_EDID_PRINT(("===============================================================\n")); + +#if (CONF__TPI_EDID_PRINT == ENABLE) + if (!ParseDetailedTiming(Data, LongDescriptorsOffset, EDID_BLOCK_2_3)) + break; +#endif + LongDescriptorsOffset += LONG_DESCR_LEN; + DescriptorNum++; + } + + return EDID_LONG_DESCRIPTORS_OK; +} + +//------------------------------------------------------------------------------ +// Function Name: Parse861Extensions() +// Function Description: Parse CEA-861 extensions from EDID ROM (EDID blocks beyond +// block #0). Save short descriptors in global structure +// g_edid. printf() long descriptors to the screen. +// +// Accepts: The number of extensions in the EDID being parsed +// Returns: EDID_PARSED_OK if EDID parsed correctly. Error code if failed. +// Globals: EDID data +// NOTE: Fields that are not supported by the 9022/4 (such as deep color) were not parsed. +//------------------------------------------------------------------------------ +byte Parse861Extensions (byte NumOfExtensions) +{ + byte i,j,k; + + byte ErrCode; + + //byte V_DescriptorIndex = 0; + //byte A_DescriptorIndex = 0; + + byte Segment = 0; + byte Block = 0; + byte Offset = 0; + + g_edid.HDMI_Sink = FALSE; + + do + { + Block++; + + Offset = 0; + if ((Block % 2) > 0) + { + Offset = EDID_BLOCK_SIZE; + } + + Segment = (byte) (Block / 2); + + if (Block == 1) + { + ReadBlockEDID(EDID_BLOCK_1_OFFSET, EDID_BLOCK_SIZE, g_CommData); // read first 128 bytes of EDID ROM + } + else + { + ReadSegmentBlockEDID(Segment, Offset, EDID_BLOCK_SIZE, g_CommData); // read next 128 bytes of EDID ROM + } + + TPI_TRACE_PRINT(("\n")); + TPI_TRACE_PRINT(("EDID DATA (Segment = %d Block = %d Offset = %d):\n", (int) Segment, (int) Block, (int) Offset)); + for (j=0, i=0; j<128; j++) + { + k = g_CommData[j]; + TPI_EDID_PRINT(("%2.2X ", (int) k)); + i++; + + if (i == 0x10) + { + TPI_EDID_PRINT(("\n")); + i = 0; + } + } + TPI_EDID_PRINT(("\n")); + + if ((NumOfExtensions > 1) && (Block == 1)) + { + continue; + } + + ErrCode = Parse861ShortDescriptors(g_CommData); + if (ErrCode != EDID_SHORT_DESCRIPTORS_OK) + { + return ErrCode; + } + + ErrCode = Parse861LongDescriptors(g_CommData); + if (ErrCode != EDID_LONG_DESCRIPTORS_OK) + { + return ErrCode; + } + + } while (Block < NumOfExtensions); + + return EDID_OK; +} + +//------------------------------------------------------------------------------ +// Function Name: DoEdidRead() +// Function Description: EDID processing +// +// Accepts: none +// Returns: TRUE or FLASE +// Globals: none +//------------------------------------------------------------------------------ +byte DoEdidRead (void) +{ + byte SysCtrlReg; + byte Result; + byte NumOfExtensions; + + // If we already have valid EDID data, ship this whole thing + if (g_edid.edidDataValid == FALSE) + { + // Request access to DDC bus from the receiver + if (GetDDC_Access(&SysCtrlReg)) + { + ReadBlockEDID(EDID_BLOCK_0_OFFSET, EDID_BLOCK_SIZE, g_CommData); // read first 128 bytes of EDID ROM + Result = ParseEDID(g_CommData, &NumOfExtensions); + if (Result != EDID_OK) + { + if (Result == EDID_NO_861_EXTENSIONS) + { + TPI_DEBUG_PRINT (("EDID -> No 861 Extensions\n")); + g_edid.HDMI_Sink = FALSE; + g_edid.YCbCr_4_4_4 = FALSE; + g_edid.YCbCr_4_2_2 = FALSE; + g_edid.CEC_A_B = 0x00; + g_edid.CEC_C_D = 0x00; + } + else + { + TPI_DEBUG_PRINT (("EDID -> Parse FAILED\n")); + g_edid.HDMI_Sink = TRUE; + g_edid.YCbCr_4_4_4 = FALSE; + g_edid.YCbCr_4_2_2 = FALSE; + g_edid.CEC_A_B = 0x00; + g_edid.CEC_C_D = 0x00; + } + } + else + { + TPI_DEBUG_PRINT (("EDID -> Parse OK\n")); + Result = Parse861Extensions(NumOfExtensions); // Parse 861 Extensions (short and long descriptors); + if (Result != EDID_OK) + { + TPI_DEBUG_PRINT(("EDID -> Extension Parse FAILED\n")); + g_edid.HDMI_Sink = TRUE; + g_edid.YCbCr_4_4_4 = FALSE; + g_edid.YCbCr_4_2_2 = FALSE; + g_edid.CEC_A_B = 0x00; + g_edid.CEC_C_D = 0x00; + } + } + + if (!ReleaseDDC(SysCtrlReg)) // Host must release DDC bus once it is done reading EDID + { + TPI_DEBUG_PRINT (("EDID -> DDC bus release failed\n")); + return EDID_DDC_BUS_RELEASE_FAILURE; + } + } + else + { + TPI_DEBUG_PRINT (("EDID -> DDC bus request failed\n")); + g_edid.HDMI_Sink = TRUE; + g_edid.YCbCr_4_4_4 = FALSE; + g_edid.YCbCr_4_2_2 = FALSE; + g_edid.CEC_A_B = 0x00; + g_edid.CEC_C_D = 0x00; + return EDID_DDC_BUS_REQ_FAILURE; + } + + TPI_DEBUG_PRINT(("EDID -> g_edid.HDMI_Sink = %d\n", (int)g_edid.HDMI_Sink)); + TPI_DEBUG_PRINT(("EDID -> g_edid.YCbCr_4_4_4 = %d\n", (int)g_edid.YCbCr_4_4_4)); + TPI_DEBUG_PRINT(("EDID -> g_edid.YCbCr_4_2_2 = %d\n", (int)g_edid.YCbCr_4_2_2)); + TPI_DEBUG_PRINT(("EDID -> g_edid.CEC_A_B = 0x%x\n", (int)g_edid.CEC_A_B)); + TPI_DEBUG_PRINT(("EDID -> g_edid.CEC_C_D = 0x%x\n", (int)g_edid.CEC_C_D)); + + g_edid.edidDataValid = TRUE; + } + return 0; +} + +#endif + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +///////////////////////*************************/////////////////////////////// +/////////////////////// HDCP /////////////////////////////// +///////////////////////*************************/////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//------------------------------------------------------------------------------ +// Function Name: IsHDCP_Supported() +// Function Description: Check Tx revision number to find if this Tx supports HDCP +// by reading the HDCP revision number from TPI register 0x30. +// +// Accepts: none +// Returns: TRUE if Tx supports HDCP. FALSE if not. +// Globals: none +//------------------------------------------------------------------------------ +byte IsHDCP_Supported (void) +{ + byte HDCP_Rev; + byte HDCP_Supported; + + TPI_TRACE_PRINT((">>IsHDCP_Supported()\n")); + + HDCP_Supported = TRUE; + + // Check Device ID + HDCP_Rev = ReadByteTPI(TPI_HDCP_REVISION_DATA_REG); + + if (HDCP_Rev != (HDCP_MAJOR_REVISION_VALUE | HDCP_MINOR_REVISION_VALUE)) + { + HDCP_Supported = FALSE; + } + + // Even if HDCP is supported check for incorrect Device ID // for SiI_9022AYBT_DEVICEID_CHECK + HDCP_Rev = ReadByteTPI(TPI_AKSV_1_REG); + if (HDCP_Rev == 0x09) + { + HDCP_Rev = ReadByteTPI(TPI_AKSV_2_REG); + if (HDCP_Rev == 0x00) + { + HDCP_Rev = ReadByteTPI(TPI_AKSV_3_REG); + if (HDCP_Rev == 0x02) + { + HDCP_Rev = ReadByteTPI(TPI_AKSV_4_REG); + if (HDCP_Rev == 0x02) + { + HDCP_Rev = ReadByteTPI(TPI_AKSV_5_REG); + if (HDCP_Rev == 0x0a) + { + HDCP_Supported = FALSE; + TPI_TRACE_PRINT((">>sii902xA found, NO HDCP supported\n")); + } + } + } + } + } + return HDCP_Supported; +} + +//------------------------------------------------------------------------------ +// Function Name: AreAKSV_OK() +// Function Description: Check if AKSVs contain 20 '0' and 20 '1' +// +// Accepts: none +// Returns: TRUE if 20 zeros and 20 ones found in AKSV. FALSE OTHERWISE +// Globals: none +//------------------------------------------------------------------------------ +byte AreAKSV_OK (void) +{ + byte B_Data[AKSV_SIZE]; + byte NumOfOnes = 0; + byte i, j; + + TPI_TRACE_PRINT((">>AreAKSV_OK()\n")); + + ReadBlockTPI(TPI_AKSV_1_REG, AKSV_SIZE, B_Data); + + for (i=0; i>= 1; + } + } + if (NumOfOnes != NUM_OF_ONES_IN_KSV) + return FALSE; + + return TRUE; +} + +//------------------------------------------------------------------------------ +// Function Name: HDCP_Off() +// Function Description: Switch hdcp off. +//------------------------------------------------------------------------------ +void HDCP_Off (void) +{ + TPI_TRACE_PRINT((">>HDCP_Off()\n")); + + // AV MUTE + ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, AV_MUTE_MASK, AV_MUTE_MUTED); + WriteByteTPI(TPI_HDCP_CONTROL_DATA_REG, PROTECTION_LEVEL_MIN); + + g_hdcp.HDCP_Started = FALSE; + g_hdcp.HDCP_LinkProtectionLevel = EXTENDED_LINK_PROTECTION_NONE | LOCAL_LINK_PROTECTION_NONE; +} + +//------------------------------------------------------------------------------ +// Function Name: HDCP_On() +// Function Description: Switch hdcp on. +//------------------------------------------------------------------------------ +void HDCP_On (void) +{ + if (g_hdcp.HDCP_Override == FALSE) + { + TPI_DEBUG_PRINT(("HDCP Started\n")); + + WriteByteTPI(TPI_HDCP_CONTROL_DATA_REG, PROTECTION_LEVEL_MAX); + + g_hdcp.HDCP_Started = TRUE; + } + else + { + g_hdcp.HDCP_Started = FALSE; + } +} + +//------------------------------------------------------------------------------ +// Function Name: RestartHDCP() +// Function Description: Restart HDCP. +//------------------------------------------------------------------------------ +void RestartHDCP (void) +{ + TPI_DEBUG_PRINT (("HDCP -> Restart\n")); + + DisableTMDS(); + HDCP_Off(); + EnableTMDS(); +} + +//------------------------------------------------------------------------------ +// Function Name: HDCP_Init() +// Function Description: Tests Tx and Rx support of HDCP. If found, checks if +// and attempts to set the security level accordingly. +// +// Accepts: none +// Returns: TRUE if HW TPI started successfully. FALSE if failed to. +// Globals: HDCP_TxSupports - initialized to FALSE, set to TRUE if supported by this device +// HDCP_AksvValid - initialized to FALSE, set to TRUE if valid AKSVs are read from this device +// HDCP_Started - initialized to FALSE +// HDCP_LinkProtectionLevel - initialized to (EXTENDED_LINK_PROTECTION_NONE | LOCAL_LINK_PROTECTION_NONE) +//------------------------------------------------------------------------------ +void HDCP_Init (void) +{ + TPI_TRACE_PRINT((">>HDCP_Init()\n")); + + g_hdcp.HDCP_TxSupports = FALSE; + g_hdcp.HDCP_AksvValid = FALSE; + g_hdcp.HDCP_Started = FALSE; + g_hdcp.HDCP_LinkProtectionLevel = EXTENDED_LINK_PROTECTION_NONE | LOCAL_LINK_PROTECTION_NONE; + + // This is TX-related... need only be done once. + if (!IsHDCP_Supported()) + { + // The TX does not support HDCP, so authentication will never be attempted. + // Video will be shown as soon as TMDS is enabled. + TPI_DEBUG_PRINT(("HDCP -> TX does not support HDCP\n")); + return; + } + g_hdcp.HDCP_TxSupports = TRUE; + + // This is TX-related... need only be done once. + if (!AreAKSV_OK()) + { + // The TX supports HDCP, but does not have valid AKSVs. + // Video will not be shown. + TPI_DEBUG_PRINT(("HDCP -> Illegal AKSV\n")); + return; + } + g_hdcp.HDCP_AksvValid = TRUE; + +#ifdef KSVFORWARD + // Enable the KSV Forwarding feature and the KSV FIFO Intererrupt + ReadModifyWriteTPI(TPI_HDCP_CONTROL_DATA_REG, KSV_FORWARD_MASK, KSV_FORWARD_ENABLE); + ReadModifyWriteTPI(TPI_KSV_FIFO_READY_INT_EN, KSV_FIFO_READY_EN_MASK, KSV_FIFO_READY_ENABLE); +#endif + + TPI_DEBUG_PRINT(("HDCP -> Supported by TX, AKSVs valid\n")); +} + +#ifdef READKSV +//------------------------------------------------------------------------------ +// Function Name: IsRepeater() +// Function Description: Test if sink is a repeater. +// +// Accepts: none +// Returns: TRUE if sink is a repeater. FALSE if not. +// Globals: none +//------------------------------------------------------------------------------ +byte IsRepeater (void) +{ + byte RegImage; + + TPI_TRACE_PRINT((">>IsRepeater()\n")); + + RegImage = ReadByteTPI(TPI_HDCP_QUERY_DATA_REG); + + if (RegImage & HDCP_REPEATER_MASK) + return TRUE; + + return FALSE; // not a repeater +} + +//------------------------------------------------------------------------------ +// Function Name: ReadBlockHDCP() +// Function Description: Read NBytes from offset Addr of the HDCP slave address +// into a byte Buffer pointed to by Data +// +// Accepts: HDCP port offset, number of bytes to read and a pointer to the data buffer where +// the data read will be saved +// Returns: none +// Globals: none +//------------------------------------------------------------------------------ +void ReadBlockHDCP (byte TPI_Offset, word NBytes, byte * pData) +{ + I2CReadBlock(siiHDCP, TPI_Offset, NBytes, pData); +} + +//------------------------------------------------------------------------------ +// Function Name: GetKSV() +// Function Description: Collect all downstrean KSV for verification. +// +// Accepts: none +// Returns: TRUE if KSVs collected successfully. False if not. +// Globals: KSV_Array[], The buffer is limited to KSV_ARRAY_SIZE due to the 8051 implementation. +//------------------------------------------------------------------------------ +byte GetKSV (void) +{ + byte i; + word KeyCount; + byte KSV_Array[KSV_ARRAY_SIZE]; + + TPI_TRACE_PRINT((">>GetKSV()\n")); + ReadBlockHDCP(DDC_BSTATUS_ADDR_L, 1, &i); + KeyCount = (i & DEVICE_COUNT_MASK) * 5; + if (KeyCount != 0) + { + ReadBlockHDCP(DDC_KSV_FIFO_ADDR, KeyCount, KSV_Array); + } + + /* + TPI_TRACE_PRINT(("KeyCount = %d\n", (int) KeyCount)); + for (i=0; i ")); + + LinkStatus = ReadByteTPI(TPI_HDCP_QUERY_DATA_REG); + LinkStatus &= LINK_STATUS_MASK; + + ClearInterrupt(SECURITY_CHANGE_EVENT); + + switch (LinkStatus) + { + case LINK_STATUS_NORMAL: + TPI_DEBUG_PRINT (("Link = Normal\n")); + break; + + case LINK_STATUS_LINK_LOST: + TPI_DEBUG_PRINT (("Link = Lost\n")); + RestartHDCP(); + break; + + case LINK_STATUS_RENEGOTIATION_REQ: + TPI_DEBUG_PRINT (("Link = Renegotiation Required\n")); + HDCP_Off(); + HDCP_On(); + break; + + case LINK_STATUS_LINK_SUSPENDED: + TPI_DEBUG_PRINT (("Link = Suspended\n")); + HDCP_On(); + break; + } + } + + // Check if HDCP state has changed: + if (InterruptStatusImage & HDCP_CHANGE_EVENT) + { + RegImage = ReadByteTPI(TPI_HDCP_QUERY_DATA_REG); + + NewLinkProtectionLevel = RegImage & (EXTENDED_LINK_PROTECTION_MASK | LOCAL_LINK_PROTECTION_MASK); + if (NewLinkProtectionLevel != g_hdcp.HDCP_LinkProtectionLevel) + { + TPI_DEBUG_PRINT (("HDCP -> ")); + + g_hdcp.HDCP_LinkProtectionLevel = NewLinkProtectionLevel; + + switch (g_hdcp.HDCP_LinkProtectionLevel) + { + case (EXTENDED_LINK_PROTECTION_NONE | LOCAL_LINK_PROTECTION_NONE): + TPI_DEBUG_PRINT (("Protection = None\n")); + RestartHDCP(); + break; + + case LOCAL_LINK_PROTECTION_SECURE: + + if (IsHDMI_Sink()) + { + ReadModifyWriteTPI(TPI_AUDIO_INTERFACE_REG, AUDIO_MUTE_MASK, AUDIO_MUTE_NORMAL); + } + + ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, AV_MUTE_MASK, AV_MUTE_NORMAL); + TPI_DEBUG_PRINT (("Protection = Local, Video Unmuted\n")); + break; + + case (EXTENDED_LINK_PROTECTION_SECURE | LOCAL_LINK_PROTECTION_SECURE): + TPI_DEBUG_PRINT (("Protection = Extended\n")); +#ifdef READKSV + if (IsRepeater()) + { + RiCnt = ReadIndexedRegister(INDEXED_PAGE_0, 0x25); + while (RiCnt > 0x70) // Frame 112 + { + RiCnt = ReadIndexedRegister(INDEXED_PAGE_0, 0x25); + } + ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, 0x06, 0x06); + GetKSV(); + RiCnt = ReadByteTPI(TPI_SYSTEM_CONTROL_DATA_REG); + ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, 0x08, 0x00); + } +#endif + break; + + default: + TPI_DEBUG_PRINT (("Protection = Extended but not Local?\n")); + RestartHDCP(); + break; + } + } + +#ifdef KSVFORWARD + // Check if KSV FIFO is ready and forward - Bug# 17892 + // If interrupt never goes off: + // a) KSV formwarding is not enabled + // b) not a repeater + // c) a repeater with device count == 0 + // and therefore no KSV list to forward + if ((ReadByteTPI(TPI_KSV_FIFO_READY_INT) & KSV_FIFO_READY_MASK) == KSV_FIFO_READY_YES) + { + ReadModifyWriteTPI(TPI_KSV_FIFO_READY_INT, KSV_FIFO_READY_MASK, KSV_FIFO_READY_YES); + TPI_DEBUG_PRINT (("KSV Fwd: KSV FIFO has data...\n")); + { + // While !(last byte has been read from KSV FIFO) + // if (count = 0) then a byte is not in the KSV FIFO yet, do not read + // else read a byte from the KSV FIFO and forward it or keep it for revocation check + do + { + ksv = ReadByteTPI(TPI_KSV_FIFO_STATUS_REG); + if (ksv & KSV_FIFO_COUNT_MASK) + { + TPI_DEBUG_PRINT (("KSV Fwd: KSV FIFO Count = %d, ", (int)(ksv & KSV_FIFO_COUNT_MASK))); + ksv = ReadByteTPI(TPI_KSV_FIFO_VALUE_REG); // Forward or store for revocation check + TPI_DEBUG_PRINT (("Value = %d\n", (int)ksv)); + } + } while ((ksv & KSV_FIFO_LAST_MASK) == KSV_FIFO_LAST_NO); + TPI_DEBUG_PRINT (("KSV Fwd: Last KSV FIFO forward complete\n")); + } + } +#endif + ClearInterrupt(HDCP_CHANGE_EVENT); + } + } +} + + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +///////////////////////*************************/////////////////////////////// +/////////////////////// AV CONFIG /////////////////////////////// +///////////////////////*************************/////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +//------------------------------------------------------------------------------ +// Video mode table +//------------------------------------------------------------------------------ +struct ModeIdType +{ + byte Mode_C1; + byte Mode_C2; + byte SubMode; +}; + +struct PxlLnTotalType +{ + word Pixels; + word Lines; +} ; +struct HVPositionType +{ + word H; + word V; +}; + +struct HVResolutionType +{ + word H; + word V; +}; + +struct TagType +{ + byte RefrTypeVHPol; + word VFreq; + struct PxlLnTotalType Total; +}; + +struct _656Type +{ + byte IntAdjMode; + word HLength; + byte VLength; + word Top; + word Dly; + word HBit2HSync; + byte VBit2VSync; + word Field2Offset; +}; + +struct Vspace_Vblank +{ + byte VactSpace1; + byte VactSpace2; + byte Vblank1; + byte Vblank2; + byte Vblank3; +}; + +// +// WARNING! The entries in this enum must remian in the samre order as the PC Codes part +// of the VideoModeTable[]. +// +typedef enum +{ + PC_640x350_85_08 = 0, + PC_640x400_85_08, + PC_720x400_70_08, + PC_720x400_85_04, + PC_640x480_59_94, + PC_640x480_72_80, + PC_640x480_75_00, + PC_640x480_85_00, + PC_800x600_56_25, + PC_800x600_60_317, + PC_800x600_72_19, + PC_800x600_75, + PC_800x600_85_06, + PC_1024x768_60, + PC_1024x768_70_07, + PC_1024x768_75_03, + PC_1024x768_85, + PC_1152x864_75, + PC_1600x1200_60, + PC_1280x768_59_95, + PC_1280x768_59_87, + PC_280x768_74_89, + PC_1280x768_85, + PC_1280x960_60, + PC_1280x960_85, + PC_1280x1024_60, + PC_1280x1024_75, + PC_1280x1024_85, + PC_1360x768_60, + PC_1400x105_59_95, + PC_1400x105_59_98, + PC_1400x105_74_87, + PC_1400x105_84_96, + PC_1600x1200_65, + PC_1600x1200_70, + PC_1600x1200_75, + PC_1600x1200_85, + PC_1792x1344_60, + PC_1792x1344_74_997, + PC_1856x1392_60, + PC_1856x1392_75, + PC_1920x1200_59_95, + PC_1920x1200_59_88, + PC_1920x1200_74_93, + PC_1920x1200_84_93, + PC_1920x1440_60, + PC_1920x1440_75, + PC_12560x1440_60, + PC_SIZE // Must be last +} PcModeCode_t; + +struct VModeInfoType +{ + struct ModeIdType ModeId; + dword PixClk; + struct TagType Tag; + struct HVPositionType Pos; + struct HVResolutionType Res; + byte AspectRatio; + struct _656Type _656; + byte PixRep; + struct Vspace_Vblank VsVb; + byte _3D_Struct; +}; + +#define NSM 0 // No Sub-Mode + +#define DEFAULT_VIDEO_MODE 0 // 640 x 480p @ 60 VGA + +#define ProgrVNegHNeg 0x00 +#define ProgrVNegHPos 0x01 +#define ProgrVPosHNeg 0x02 +#define ProgrVPosHPos 0x03 + +#define InterlaceVNegHNeg 0x04 +#define InterlaceVPosHNeg 0x05 +#define InterlaceVNgeHPos 0x06 +#define InterlaceVPosHPos 0x07 + +#define VIC_BASE 0 +#define HDMI_VIC_BASE 43 +#define VIC_3D_BASE 47 +#define PC_BASE 64 + +// Aspect ratio +//================================================= +#define R_4 0 // 4:3 +#define R_4or16 1 // 4:3 or 16:9 +#define R_16 2 // 16:9 + +// +// These are the VIC codes that we support in a 3D mode +// +#define VIC_FOR_480P_60Hz_4X3 2 // 720p x 480p @60Hz +#define VIC_FOR_480P_60Hz_16X9 3 // 720p x 480p @60Hz +#define VIC_FOR_720P_60Hz 4 // 1280 x 720p @60Mhz +#define VIC_FOR_1080i_60Hz 5 // 1920 x 1080i @60Mhz +#define VIC_FOR_1080p_60Hz 16 // 1920 x 1080i @60hz +#define VIC_FOR_720P_50Hz 19 // 1280 x 720p @50Mhz +#define VIC_FOR_1080i_50Hz 20 // 1920 x 1080i @50Mhz +#define VIC_FOR_1080p_50Hz 31 // 1920 x 720p @50Hz +#define VIC_FOR_1080p_24Hz 32 // 1920 x 720p @24Hz + + +static struct VModeInfoType VModesTable[] = +{ + //=================================================================================================================================================================================================================================== + // VIC Refresh type Refresh-Rate Pixel-Totals Position Active Aspect Int Length Hbit Vbit Field Pixel Vact Space/Blank + // 1 2 SubM PixClk V/H Position VFreq H V H V H V Ratio Adj H V Top Dly HSync VSync Offset Repl Space1 Space2 Blank1 Blank2 Blank3 3D + //=================================================================================================================================================================================================================================== + {{ 1, 0, NSM}, 2517, {ProgrVNegHNeg, 6000, { 800, 525}}, {144, 35}, { 640, 480}, R_4, {0, 96, 2, 33, 48, 16, 10, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 0 - 1. 640 x 480p @ 60 VGA + {{ 2, 3, NSM}, 2700, {ProgrVNegHNeg, 6000, { 858, 525}}, {122, 36}, { 720, 480}, R_4or16, {0, 62, 6, 30, 60, 19, 9, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 1 - 2,3 720 x 480p + {{ 4, 0, NSM}, 7425, {ProgrVPosHPos, 6000, {1650, 750}}, {260, 25}, {1280, 720}, R_16, {0, 40, 5, 20, 220, 110, 5, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 2 - 4 1280 x 720p@60Hz + {{ 5, 0, NSM}, 7425, {InterlaceVPosHPos, 6000, {2200, 562}}, {192, 20}, {1920,1080}, R_16, {0, 44, 5, 15, 148, 88, 2, 1100}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 3 - 5 1920 x 1080i + {{ 6, 7, NSM}, 2700, {InterlaceVNegHNeg, 6000, {1716, 264}}, {119, 18}, { 720, 480}, R_4or16, {3, 62, 3, 15, 114, 17, 5, 429}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 4 - 6,7 1440 x 480i,pix repl + {{ 8, 9, 1}, 2700, {ProgrVNegHNeg, 6000, {1716, 262}}, {119, 18}, {1440, 240}, R_4or16, {0, 124, 3, 15, 114, 38, 4, 0}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 5 - 8,9(1) 1440 x 240p + {{ 8, 9, 2}, 2700, {ProgrVNegHNeg, 6000, {1716, 263}}, {119, 18}, {1440, 240}, R_4or16, {0, 124, 3, 15, 114, 38, 4, 0}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 6 - 8,9(2) 1440 x 240p + {{ 10, 11, NSM}, 5400, {InterlaceVNegHNeg, 6000, {3432, 525}}, {238, 18}, {2880, 480}, R_4or16, {0, 248, 3, 15, 228, 76, 4, 1716}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 7 - 10,11 2880 x 480i + {{ 12, 13, 1}, 5400, {ProgrVNegHNeg, 6000, {3432, 262}}, {238, 18}, {2880, 240}, R_4or16, {0, 248, 3, 15, 228, 76, 4, 0}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 8 - 12,13(1) 2880 x 240p + {{ 12, 13, 2}, 5400, {ProgrVNegHNeg, 6000, {3432, 263}}, {238, 18}, {2880, 240}, R_4or16, {0, 248, 3, 15, 228, 76, 4, 0}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 9 - 12,13(2) 2880 x 240p + {{ 14, 15, NSM}, 5400, {ProgrVNegHNeg, 6000, {1716, 525}}, {244, 36}, {1440, 480}, R_4or16, {0, 124, 6, 30, 120, 32, 9, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 10 - 14,15 1440 x 480p + {{ 16, 0, NSM}, 14835, {ProgrVPosHPos, 6000, {2200, 1125}}, {192, 41}, {1920,1080}, R_16, {0, 44, 5, 36, 148, 88, 4, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 11 - 16 1920 x 1080p + {{ 17, 18, NSM}, 2700, {ProgrVNegHNeg, 5000, { 864, 625}}, {132, 44}, { 720, 576}, R_4or16, {0, 64, 5, 39, 68, 12, 5, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 12 - 17,18 720 x 576p + {{ 19, 0, NSM}, 7425, {ProgrVPosHPos, 5000, {1980, 750}}, {260, 25}, {1280, 720}, R_16, {0, 40, 5, 20, 220, 440, 5, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 13 - 19 1280 x 720p@50Hz + {{ 20, 0, NSM}, 7425, {InterlaceVPosHPos, 5000, {2640, 1125}}, {192, 20}, {1920,1080}, R_16, {0, 44, 5, 15, 148, 528, 2, 1320}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 14 - 20 1920 x 1080i + {{ 21, 22, NSM}, 2700, {InterlaceVNegHNeg, 5000, {1728, 625}}, {132, 22}, { 720, 576}, R_4, {3, 63, 3, 19, 138, 24, 2, 432}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 15 - 21,22 1440 x 576i + {{ 23, 24, 1}, 2700, {ProgrVNegHNeg, 5000, {1728, 312}}, {132, 22}, {1440, 288}, R_4or16, {0, 126, 3, 19, 138, 24, 2, 0}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 16 - 23,24(1) 1440 x 288p + {{ 23, 24, 2}, 2700, {ProgrVNegHNeg, 5000, {1728, 313}}, {132, 22}, {1440, 288}, R_4or16, {0, 126, 3, 19, 138, 24, 2, 0}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 17 - 23,24(2) 1440 x 288p + {{ 23, 24, 3}, 2700, {ProgrVNegHNeg, 5000, {1728, 314}}, {132, 22}, {1440, 288}, R_4or16, {0, 126, 3, 19, 138, 24, 2, 0}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 18 - 23,24(3) 1440 x 288p + {{ 25, 26, NSM}, 5400, {InterlaceVNegHNeg, 5000, {3456, 625}}, {264, 22}, {2880, 576}, R_4or16, {0, 252, 3, 19, 276, 48, 2, 1728}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 19 - 25,26 2880 x 576i + {{ 27, 28, 1}, 5400, {ProgrVNegHNeg, 5000, {3456, 312}}, {264, 22}, {2880, 288}, R_4or16, {0, 252, 3, 19, 276, 48, 2, 0}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 20 - 27,28(1) 2880 x 288p + {{ 27, 28, 2}, 5400, {ProgrVNegHNeg, 5000, {3456, 313}}, {264, 22}, {2880, 288}, R_4or16, {0, 252, 3, 19, 276, 48, 3, 0}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 21 - 27,28(2) 2880 x 288p + {{ 27, 28, 3}, 5400, {ProgrVNegHNeg, 5000, {3456, 314}}, {264, 22}, {2880, 288}, R_4or16, {0, 252, 3, 19, 276, 48, 4, 0}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 22 - 27,28(3) 2880 x 288p + {{ 29, 30, NSM}, 5400, {ProgrVPosHNeg, 5000, {1728, 625}}, {264, 44}, {1440, 576}, R_4or16, {0, 128, 5, 39, 136, 24, 5, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 23 - 29,30 1440 x 576p + {{ 31, 0, NSM}, 14850, {ProgrVPosHPos, 5000, {2640, 1125}}, {192, 41}, {1920,1080}, R_16, {0, 44, 5, 36, 148, 528, 4, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 24 - 31(1) 1920 x 1080p + {{ 32, 0, NSM}, 7417, {ProgrVPosHPos, 2400, {2750, 1125}}, {192, 41}, {1920,1080}, R_16, {0, 44, 5, 36, 148, 638, 4, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 25 - 32(2) 1920 x 1080p@24Hz + {{ 33, 0, NSM}, 7425, {ProgrVPosHPos, 2500, {2640, 1125}}, {192, 41}, {1920,1080}, R_16, {0, 44, 5, 36, 148, 528, 4, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 26 - 33(3) 1920 x 1080p + {{ 34, 0, NSM}, 7417, {ProgrVPosHPos, 3000, {2200, 1125}}, {192, 41}, {1920,1080}, R_16, {0, 44, 5, 36, 148, 528, 4, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 27 - 34(4) 1920 x 1080p + {{ 35, 36, NSM}, 10800, {ProgrVNegHNeg, 5994, {3432, 525}}, {488, 36}, {2880, 480}, R_4or16, {0, 248, 6, 30, 240, 64, 10, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 28 - 35, 36 2880 x 480p@59.94/60Hz + {{ 37, 38, NSM}, 10800, {ProgrVNegHNeg, 5000, {3456, 625}}, {272, 39}, {2880, 576}, R_4or16, {0, 256, 5, 40, 272, 48, 5, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 29 - 37, 38 2880 x 576p@50Hz + {{ 39, 0, NSM}, 7200, {InterlaceVNegHNeg, 5000, {2304, 1250}}, {352, 62}, {1920,1080}, R_16, {0, 168, 5, 87, 184, 32, 24, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 30 - 39 1920 x 1080i@50Hz + {{ 40, 0, NSM}, 14850, {InterlaceVPosHPos, 10000,{2640, 1125}}, {192, 20}, {1920,1080}, R_16, {0, 44, 5, 15, 148, 528, 2, 1320}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 31 - 40 1920 x 1080i@100Hz + {{ 41, 0, NSM}, 14850, {InterlaceVPosHPos, 10000,{1980, 750}}, {260, 25}, {1280, 720}, R_16, {0, 40, 5, 20, 220, 400, 5, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 32 - 41 1280 x 720p@100Hz + {{ 42, 43, NSM}, 5400, {ProgrVNegHNeg, 10000,{ 864, 144}}, {132, 44}, { 720, 576}, R_4or16, {0, 64, 5, 39, 68, 12, 5, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 33 - 42, 43, 720p x 576p@100Hz + {{ 44, 45, NSM}, 5400, {InterlaceVNegHNeg, 10000,{ 864, 625}}, {132, 22}, { 720, 576}, R_4or16, {0, 63, 3, 19, 69, 12, 2, 432}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 34 - 44, 45, 720p x 576i@100Hz, pix repl + {{ 46, 0, NSM}, 14835, {InterlaceVPosHPos, 11988,{2200, 1125}}, {192, 20}, {1920,1080}, R_16, {0, 44, 5, 15, 149, 88, 2, 1100}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 35 - 46, 1920 x 1080i@119.88/120Hz + {{ 47, 0, NSM}, 14835, {ProgrVPosHPos, 11988,{1650, 750}}, {260, 25}, {1280, 720}, R_16, {0, 40, 5, 20, 220, 110, 5, 1100}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 36 - 47, 1280 x 720p@119.88/120Hz + {{ 48, 49, NSM}, 5400, {ProgrVNegHNeg, 11988,{ 858, 525}}, {122, 36}, { 720, 480}, R_4or16, {0, 62, 6, 30, 60, 16, 10, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 37 - 48, 49 720 x 480p@119.88/120Hz + {{ 50, 51, NSM}, 5400, {InterlaceVNegHNeg, 11988,{ 858, 525}}, {119, 18}, { 720, 480}, R_4or16, {0, 62, 3, 15, 57, 19, 4, 429}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 38 - 50, 51 720 x 480i@119.88/120Hz + {{ 52, 53, NSM}, 10800, {ProgrVNegHNeg, 20000,{ 864, 625}}, {132, 44}, { 720, 576}, R_4or16, {0, 64, 5, 39, 68, 12, 5, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 39 - 52, 53, 720 x 576p@200Hz + {{ 54, 55, NSM}, 10800, {InterlaceVNegHNeg, 20000,{ 864, 625}}, {132, 22}, { 720, 576}, R_4or16, {0, 63, 3, 19, 69, 12, 2, 432}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 40 - 54, 55, 1440 x 576i @200Hz, pix repl + {{ 56, 57, NSM}, 10800, {ProgrVNegHNeg, 24000,{ 858, 525}}, {122, 42}, { 720, 480}, R_4or16, {0, 62, 6, 30, 60, 16, 9, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 41 - 56, 57, 720 x 480p @239.76/240Hz + {{ 58, 59, NSM}, 10800, {InterlaceVNegHNeg, 24000,{ 858, 525}}, {119, 18}, { 720, 480}, R_4or16, {0, 62, 3, 15, 57, 19, 4, 429}, 1, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 42 - 58, 59, 1440 x 480i @239.76/240Hz, pix repl + + + {{PC_BASE , 0,NSM}, 3150, {ProgrVNegHPos, 8508, {832, 445}}, {160,63}, {640,350}, R_16, {0, 64, 3, 60, 96, 32, 32, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 64 - 640x350@85.08 + {{PC_BASE+1, 0,NSM}, 3150, {ProgrVPosHNeg, 8508, {832, 445}}, {160,44}, {640,400}, R_16, {0, 64, 3, 41, 96, 32, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 65 - 640x400@85.08 + {{PC_BASE+2, 0,NSM}, 2700, {ProgrVPosHNeg, 7008, {900, 449}}, {0,0}, {720,400}, R_16, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 66 - 720x400@70.08 + {{PC_BASE+3, 0,NSM}, 3500, {ProgrVPosHNeg, 8504, {936, 446}}, {20,45}, {720,400}, R_16, {0, 72, 3, 42, 108, 36, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 67 - 720x400@85.04 + {{PC_BASE+4, 0,NSM}, 2517, {ProgrVNegHNeg, 5994, {800, 525}}, {144,35}, {640,480}, R_4, {0, 96, 2, 33, 48, 16, 10, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 68 - 640x480@59.94 + {{PC_BASE+5, 0,NSM}, 3150, {ProgrVNegHNeg, 7281, {832, 520}}, {144,31}, {640,480}, R_4, {0, 40, 3, 28, 128, 128, 9, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 69 - 640x480@72.80 + {{PC_BASE+6, 0,NSM}, 3150, {ProgrVNegHNeg, 7500, {840, 500}}, {21,19}, {640,480}, R_4, {0, 64, 3, 28, 128, 24, 9, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 70 - 640x480@75.00 + {{PC_BASE+7,0,NSM}, 3600, {ProgrVNegHNeg, 8500, {832, 509}}, {168,28}, {640,480}, R_4, {0, 56, 3, 25, 128, 24, 9, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 71 - 640x480@85.00 + {{PC_BASE+8,0,NSM}, 3600, {ProgrVPosHPos, 5625, {1024, 625}}, {200,24}, {800,600}, R_4, {0, 72, 2, 22, 128, 24, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 72 - 800x600@56.25 + {{PC_BASE+9,0,NSM}, 4000, {ProgrVPosHPos, 6032, {1056, 628}}, {216,27}, {800,600}, R_4, {0, 128, 4, 23, 88, 40, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 73 - 800x600@60.317 + {{PC_BASE+10,0,NSM}, 5000, {ProgrVPosHPos, 7219, {1040, 666}}, {184,29}, {800,600}, R_4, {0, 120, 6, 23, 64, 56, 37, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 74 - 800x600@72.19 + {{PC_BASE+11,0,NSM}, 4950, {ProgrVPosHPos, 7500, {1056, 625}}, {240,24}, {800,600}, R_4, {0, 80, 3, 21, 160, 16, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 75 - 800x600@75 + {{PC_BASE+12,0,NSM}, 5625, {ProgrVPosHPos, 8506, {1048, 631}}, {216,30}, {800,600}, R_4, {0, 64, 3, 27, 152, 32, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 76 - 800x600@85.06 + {{PC_BASE+13,0,NSM}, 6500, {ProgrVNegHNeg, 6000, {1344, 806}}, {296,35}, {1024,768}, R_4, {0, 136, 6, 29, 160, 24, 3, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 77 - 1024x768@60 + {{PC_BASE+14,0,NSM}, 7500, {ProgrVNegHNeg, 7007, {1328, 806}}, {280,35}, {1024,768}, R_4, {0, 136, 6, 19, 144, 24, 3, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 78 - 1024x768@70.07 + {{PC_BASE+15,0,NSM}, 7875, {ProgrVPosHPos, 7503, {1312, 800}}, {272,31}, {1024,768}, R_4, {0, 96, 3, 28, 176, 16, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 79 - 1024x768@75.03 + {{PC_BASE+16,0,NSM}, 9450, {ProgrVPosHPos, 8500, {1376, 808}}, {304,39}, {1024,768}, R_4, {0, 96, 3, 36, 208, 48, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 80 - 1024x768@85 + {{PC_BASE+17,0,NSM}, 10800, {ProgrVPosHPos, 7500, {1600, 900}}, {384,35}, {1152,864}, R_4, {0, 128, 3, 32, 256, 64, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 81 - 1152x864@75 + {{PC_BASE+18,0,NSM}, 16200, {ProgrVPosHPos, 6000, {2160, 1250}}, {496,49}, {1600,1200}, R_4, {0, 304, 3, 46, 304, 64, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 82 - 1600x1200@60 + {{PC_BASE+19,0,NSM}, 6825, {ProgrVNegHPos, 6000, {1440, 790}}, {112,19}, {1280,768}, R_16, {0, 32, 7, 12, 80, 48, 3, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 83 - 1280x768@59.95 + {{PC_BASE+20,0,NSM}, 7950, {ProgrVPosHNeg, 5987, {1664, 798}}, {320,27}, {1280,768}, R_16, {0, 128, 7, 20, 192, 64, 3, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 84 - 1280x768@59.87 + {{PC_BASE+21,0,NSM}, 10220, {ProgrVPosHNeg, 6029, {1696, 805}}, {320,27}, {1280,768}, R_16, {0, 128, 7, 27, 208, 80, 3, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 85 - 1280x768@74.89 + {{PC_BASE+22,0,NSM}, 11750, {ProgrVPosHNeg, 8484, {1712, 809}}, {352,38}, {1280,768}, R_16, {0, 136, 7, 31, 216, 80, 3, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 86 - 1280x768@85 + {{PC_BASE+23,0,NSM}, 10800, {ProgrVPosHPos, 6000, {1800, 1000}}, {424,39}, {1280,960}, R_4, {0, 112, 3, 36, 312, 96, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 87 - 1280x960@60 + {{PC_BASE+24,0,NSM}, 14850, {ProgrVPosHPos, 8500, {1728, 1011}}, {384,50}, {1280,960}, R_4, {0, 160, 3, 47, 224, 64, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 88 - 1280x960@85 + {{PC_BASE+25,0,NSM}, 10800, {ProgrVPosHPos, 6002, {1688, 1066}}, {360,41}, {1280,1024}, R_4, {0, 112, 3, 38, 248, 48, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 89 - 1280x1024@60 + {{PC_BASE+26,0,NSM}, 13500, {ProgrVPosHPos, 7502, {1688, 1066}}, {392,41}, {1280,1024}, R_4, {0, 144, 3, 38, 248, 16, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 90 - 1280x1024@75 + {{PC_BASE+27,0,NSM}, 15750, {ProgrVPosHPos, 8502, {1728, 1072}}, {384,47}, {1280,1024}, R_4, {0, 160, 3, 4, 224, 64, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 91 - 1280x1024@85 + {{PC_BASE+28,0,NSM}, 8550, {ProgrVPosHPos, 6002, {1792, 795}}, {368,24}, {1360,768}, R_16, {0, 112, 6, 18, 256, 64, 3, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 92 - 1360x768@60 + {{PC_BASE+29,0,NSM}, 10100, {ProgrVNegHPos, 5995, {1560, 1080}}, {112,27}, {1400,1050}, R_4, {0, 32, 4, 23, 80, 48, 3, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 93 - 1400x105@59.95 + {{PC_BASE+30,0,NSM}, 12175, {ProgrVPosHNeg, 5998, {1864, 1089}}, {376,36}, {1400,1050}, R_4, {0, 144, 4, 32, 232, 88, 3, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 94 - 1400x105@59.98 + {{PC_BASE+31,0,NSM}, 15600, {ProgrVPosHNeg, 7487, {1896, 1099}}, {392,46}, {1400,1050}, R_4, {0, 144, 4, 22, 248, 104, 3, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 95 - 1400x105@74.87 + {{PC_BASE+32,0,NSM}, 17950, {ProgrVPosHNeg, 8496, {1912, 1105}}, {408,52}, {1400,1050}, R_4, {0, 152, 4, 48, 256, 104, 3, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 96 - 1400x105@84.96 + {{PC_BASE+33,0,NSM}, 17550, {ProgrVPosHPos, 6500, {2160, 1250}}, {496,49}, {1600,1200}, R_4, {0, 192, 3, 46, 304, 64, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 97 - 1600x1200@65 + {{PC_BASE+34,0,NSM}, 18900, {ProgrVPosHPos, 7000, {2160, 1250}}, {496,49}, {1600,1200}, R_4, {0, 192, 3, 46, 304, 64, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 98 - 1600x1200@70 + {{PC_BASE+35,0,NSM}, 20250, {ProgrVPosHPos, 7500, {2160, 1250}}, {496,49}, {1600,1200}, R_4, {0, 192, 3, 46, 304, 64, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 99 - 1600x1200@75 + {{PC_BASE+36,0,NSM}, 22950, {ProgrVPosHPos, 8500, {2160, 1250}}, {496,49}, {1600,1200}, R_4, {0, 192, 3, 46, 304, 64, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 100 - 1600x1200@85 + {{PC_BASE+37,0,NSM}, 20475, {ProgrVPosHNeg, 6000, {2448, 1394}}, {528,49}, {1792,1344}, R_4, {0, 200, 3, 46, 328, 128, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 101 - 1792x1344@60 + {{PC_BASE+38,0,NSM}, 26100, {ProgrVPosHNeg, 7500, {2456, 1417}}, {568,72}, {1792,1344}, R_4, {0, 216, 3, 69, 352, 96, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 102 - 1792x1344@74.997 + {{PC_BASE+39,0,NSM}, 21825, {ProgrVPosHNeg, 6000, {2528, 1439}}, {576,46}, {1856,1392}, R_4, {0, 224, 3, 43, 352, 96, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 103 - 1856x1392@60 + {{PC_BASE+40,0,NSM}, 28800, {ProgrVPosHNeg, 7500, {2560, 1500}}, {576,107}, {1856,1392}, R_4, {0, 224, 3, 104, 352, 128, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 104 - 1856x1392@75 + {{PC_BASE+41,0,NSM}, 15400, {ProgrVNegHPos, 5995, {2080, 1235}}, {112,32}, {1920,1200}, R_16, {0, 32, 6, 26, 80, 48, 3, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 106 - 1920x1200@59.95 + {{PC_BASE+42,0,NSM}, 19325, {ProgrVPosHNeg, 5988, {2592, 1245}}, {536,42}, {1920,1200}, R_16, {0, 200, 6, 36, 336, 136, 3, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 107 - 1920x1200@59.88 + {{PC_BASE+43,0,NSM}, 24525, {ProgrVPosHNeg, 7493, {2608, 1255}}, {552,52}, {1920,1200}, R_16, {0, 208, 6, 46, 344, 136, 3, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 108 - 1920x1200@74.93 + {{PC_BASE+44,0,NSM}, 28125, {ProgrVPosHNeg, 8493, {2624, 1262}}, {560,59}, {1920,1200}, R_16, {0, 208, 6, 53, 352, 144, 3, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 109 - 1920x1200@84.93 + {{PC_BASE+45,0,NSM}, 23400, {ProgrVPosHNeg, 6000, {2600, 1500}}, {552,59}, {1920,1440}, R_4, {0, 208, 3, 56, 344, 128, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 110 - 1920x1440@60 + {{PC_BASE+46,0,NSM}, 29700, {ProgrVPosHNeg, 7500, {2640, 1500}}, {576,59}, {1920,1440}, R_4, {0, 224, 3, 56, 352, 144, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 111 - 1920x1440@75 + {{PC_BASE+47,0,NSM}, 24150, {ProgrVPosHNeg, 6000, {2720, 1481}}, {48, 3}, {2560,1440}, R_16, {0, 32, 5, 56, 352, 144, 1, 0}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 112 - 2560x1440@60 // %%% need work + {{PC_BASE+48,0,NSM}, 2700, {InterlaceVNegHNeg, 6000, {1716, 264}}, {244,18}, {1440, 480},R_4or16,{3, 124, 3, 15, 114, 17, 5, 429}, 0, {0, 0, 0, 0, 0}, NO_3D_SUPPORT}, // 113 - 1440 x 480i +}; + + +//------------------------------------------------------------------------------ +// Aspect Ratio table defines the aspect ratio as function of VIC. This table +// should be used in conjunction with the 861-D part of VModeInfoType VModesTable[] +// (formats 0 - 59) because some formats that differ only in their AR are grouped +// together (e.g., formats 2 and 3). +//------------------------------------------------------------------------------ +static u8 AspectRatioTable[] = +{ + R_4, R_4, R_16, R_16, R_16, R_4, R_16, R_4, R_16, R_4, + R_16, R_4, R_16, R_4, R_16, R_16, R_4, R_16, R_16, R_16, + R_4, R_16, R_4, R_16, R_4, R_16, R_4, R_16, R_4, R_16, + R_16, R_16, R_16, R_16, R_4, R_16, R_4, R_16, R_16, R_16, + R_16, R_4, R_16, R_4, R_16, R_16, R_16, R_4, R_16, R_4, + R_16, R_4, R_16, R_4, R_16, R_4, R_16, R_4, R_16 +}; + +//------------------------------------------------------------------------------ +// VIC to Indexc table defines which VideoModeTable entry is appropreate for this VIC code. +// Note: This table is valid ONLY for VIC codes in 861-D formats, NOT for HDMI_VIC codes +// or 3D codes! +//------------------------------------------------------------------------------ +static u8 VIC2Index[] = +{ + 0, 0, 1, 1, 2, 3, 4, 4, 5, 5, + 7, 7, 8, 8, 10, 10, 11, 12, 12, 13, + 14, 15, 15, 16, 16, 19, 19, 20, 20, 23, + 23, 24, 25, 26, 27, 28, 28, 29, 29, 30, + 31, 32, 33, 33, 34, 34, 35, 36, 37, 37, + 38, 38, 39, 39, 40, 40, 41, 41, 42, 42 +}; + +//------------------------------------------------------------------------------ +// Function Name: ConvertVIC_To_VM_Index() +// Function Description: Convert Video Identification Code to the corresponding +// index of VModesTable[]. Conversion also depends on the +// value of the 3D_Structure parameter in the case of 3D video format. +// Accepts: VIC to be converted; 3D_Structure value +// Returns: Index into VModesTable[] corrsponding to VIC +// Globals: VModesTable[] siHdmiTx +// Note: Conversion is for 861-D formats, HDMI_VIC or 3D +//------------------------------------------------------------------------------ +byte ConvertVIC_To_VM_Index (void) +{ + byte index; + + // + // The global VideoModeDescription contains all the information we need about + // the Video mode for use to find its entry in the Videio mode table. + // + // The first issue. The "VIC" may be a 891-D VIC code, or it might be an + // HDMI_VIC code, or it might be a 3D code. Each require different handling + // to get the proper video mode table index. + // + if (siHdmiTx.HDMIVideoFormat == VMD_HDMIFORMAT_CEA_VIC) + { + // + // This is a regular 861-D format VIC, so we use the VIC to Index + // table to look up the index. + // + index = VIC2Index[siHdmiTx.VIC]; + } + else if (siHdmiTx.HDMIVideoFormat == VMD_HDMIFORMAT_HDMI_VIC) + { + // + // HDMI_VIC conversion is simple. We need to subtract one because the codes start + // with one instead of zero. These values are from HDMI 1.4 Spec Table 8-13. + // + if ((siHdmiTx.VIC < 1) || (siHdmiTx.VIC > 4)) + { + index = DEFAULT_VIDEO_MODE; + } + else + { + index = (HDMI_VIC_BASE - 1) + siHdmiTx.VIC; + } + } + else if (siHdmiTx.HDMIVideoFormat == VMD_HDMIFORMAT_3D) + { + // + // Currently there are only a few VIC modes that we can do in 3D. If the VIC code is not + // one of these OR if the packing type is not supported for that VIC code, then it is an + // error and we go to the default video mode. See HDMI Spec 1.4 Table H-6. + // + switch (siHdmiTx.VIC) + { + case VIC_FOR_480P_60Hz_4X3: + case VIC_FOR_480P_60Hz_16X9: + // We only support Side-by-Side (Half) for these modes + if (siHdmiTx.ThreeDStructure == SIDE_BY_SIDE_HALF) + index = VIC_3D_BASE + 0; + else + index = DEFAULT_VIDEO_MODE; + break; + + case VIC_FOR_720P_60Hz: + switch(siHdmiTx.ThreeDStructure) + { + case FRAME_PACKING: + index = VIC_3D_BASE + 1; + break; + default: + index = DEFAULT_VIDEO_MODE; + break; + } + break; + + case VIC_FOR_1080i_60Hz: + switch(siHdmiTx.ThreeDStructure) + { + case FRAME_PACKING: + index = VIC_3D_BASE + 2; + break; + case VMD_3D_FIELDALTERNATIVE: + index = VIC_3D_BASE + 3; + break; + default: + index = DEFAULT_VIDEO_MODE; + break; + } + break; + + case VIC_FOR_1080p_60Hz: + switch(siHdmiTx.ThreeDStructure) + { + case FRAME_PACKING: + index = VIC_3D_BASE + 4; + break; + case VMD_3D_LINEALTERNATIVE: + index = VIC_3D_BASE + 5; + break; + case SIDE_BY_SIDE_FULL: + index = VIC_3D_BASE + 6; + break; + case SIDE_BY_SIDE_HALF: + index = VIC_3D_BASE + 7; + break; + default: + index = DEFAULT_VIDEO_MODE; + break; + } + break; + + case VIC_FOR_720P_50Hz: + switch(siHdmiTx.ThreeDStructure) + { + case FRAME_PACKING: + index = VIC_3D_BASE + 8; + break; + case VMD_3D_LDEPTH: + index = VIC_3D_BASE + 9; + break; + case VMD_3D_LDEPTHGRAPHICS: + index = VIC_3D_BASE + 10; + break; + default: + index = DEFAULT_VIDEO_MODE; + break; + } + break; + + case VIC_FOR_1080i_50Hz: + switch(siHdmiTx.ThreeDStructure) + { + case FRAME_PACKING: + index = VIC_3D_BASE + 11; + break; + case VMD_3D_FIELDALTERNATIVE: + index = VIC_3D_BASE + 12; + break; + default: + index = DEFAULT_VIDEO_MODE; + break; + } + break; + + case VIC_FOR_1080p_50Hz: + switch(siHdmiTx.ThreeDStructure) + { + case FRAME_PACKING: + index = VIC_3D_BASE + 13; + break; + case VMD_3D_LINEALTERNATIVE: + index = VIC_3D_BASE + 14; + break; + case SIDE_BY_SIDE_FULL: + index = VIC_3D_BASE + 15; + break; + default: + index = DEFAULT_VIDEO_MODE; + break; + } + break; + + case VIC_FOR_1080p_24Hz: + switch(siHdmiTx.ThreeDStructure) + { + case FRAME_PACKING: + index = VIC_3D_BASE + 16; + break; + default: + index = DEFAULT_VIDEO_MODE; + break; + } + break; + + default: + index = DEFAULT_VIDEO_MODE; + break; + } + } + else if (siHdmiTx.HDMIVideoFormat == VMD_HDMIFORMAT_PC) + { + if (siHdmiTx.VIC < PC_SIZE) + { + index = siHdmiTx.VIC + PC_BASE; + } + else + { + index = DEFAULT_VIDEO_MODE; + } + } + else + { + // This should never happen! If so, default to first table entry + index = DEFAULT_VIDEO_MODE; + } + + return index; +} + + +// Patches +//======== +byte TPI_REG0x63_SAVED = 0; + +//------------------------------------------------------------------------------ +// Function Name: SetEmbeddedSync() +// Function Description: Set the 9022/4 registers to extract embedded sync. +// +// Accepts: Index of video mode to set +// Returns: TRUE +// Globals: VModesTable[] +//------------------------------------------------------------------------------ +byte SetEmbeddedSync (void) +{ + byte ModeTblIndex; + word H_Bit_2_H_Sync; + word Field2Offset; + word H_SyncWidth; + + byte V_Bit_2_V_Sync; + byte V_SyncWidth; + byte B_Data[8]; + + TPI_TRACE_PRINT((">>SetEmbeddedSync()\n")); + + ReadModifyWriteIndexedRegister(INDEXED_PAGE_0, 0x0A, 0x01, 0x01); //set Output Format YCbCr 4:4:4 + ReadClearWriteTPI(TPI_SYNC_GEN_CTRL, MSBIT); // set 0x60[7] = 0 for External DE mode + WriteByteTPI(TPI_DE_CTRL, 0x30); //Vsync and Hsync Polarity settings 1 : Negative(leading edge falls) + ReadSetWriteTPI(TPI_SYNC_GEN_CTRL, MSBIT); // set 0x60[7] = 1 for Embedded Sync + + ModeTblIndex = ConvertVIC_To_VM_Index(); + + H_Bit_2_H_Sync = VModesTable[ModeTblIndex]._656.HBit2HSync; + Field2Offset = VModesTable[ModeTblIndex]._656.Field2Offset; + H_SyncWidth = VModesTable[ModeTblIndex]._656.HLength; + V_Bit_2_V_Sync = VModesTable[ModeTblIndex]._656.VBit2VSync; + V_SyncWidth = VModesTable[ModeTblIndex]._656.VLength; + + B_Data[0] = H_Bit_2_H_Sync & LOW_BYTE; // Setup HBIT_TO_HSYNC 8 LSBits (0x62) + + B_Data[1] = (H_Bit_2_H_Sync >> 8) & TWO_LSBITS; // HBIT_TO_HSYNC 2 MSBits + //B_Data[1] |= BIT_EN_SYNC_EXTRACT; // and Enable Embedded Sync to 0x63 + TPI_REG0x63_SAVED = B_Data[1]; + + B_Data[2] = Field2Offset & LOW_BYTE; // 8 LSBits of "Field2 Offset" to 0x64 + B_Data[3] = (Field2Offset >> 8) & LOW_NIBBLE; // 2 MSBits of "Field2 Offset" to 0x65 + + B_Data[4] = H_SyncWidth & LOW_BYTE; + B_Data[5] = (H_SyncWidth >> 8) & TWO_LSBITS; // HWIDTH to 0x66, 0x67 + B_Data[6] = V_Bit_2_V_Sync; // VBIT_TO_VSYNC to 0x68 + B_Data[7] = V_SyncWidth; // VWIDTH to 0x69 + + WriteBlockTPI(TPI_HBIT_TO_HSYNC_7_0, 8, &B_Data[0]); + + return TRUE; +} + +//------------------------------------------------------------------------------ +// Function Name: EnableEmbeddedSync() +// Function Description: EnableEmbeddedSync +// +// Accepts: none +// Returns: none +// Globals: none +//------------------------------------------------------------------------------ +void EnableEmbeddedSync (void) +{ + TPI_TRACE_PRINT((">>EnableEmbeddedSync()\n")); + + ReadClearWriteTPI(TPI_SYNC_GEN_CTRL, MSBIT); // set 0x60[7] = 0 for DE mode + WriteByteTPI(TPI_DE_CTRL, 0x30); + ReadSetWriteTPI(TPI_SYNC_GEN_CTRL, MSBIT); // set 0x60[7] = 1 for Embedded Sync + ReadSetWriteTPI(TPI_DE_CTRL, BIT_6); +} + +//------------------------------------------------------------------------------ +// Function Name: SetDE() +// Function Description: Set the 9022/4 internal DE generator parameters +// +// Accepts: none +// Returns: DE_SET_OK +// Globals: none +// +// NOTE: 0x60[7] must be set to "0" for the follwing settings to take effect +//------------------------------------------------------------------------------ +byte SetDE (void) +{ + byte RegValue; + byte ModeTblIndex; + + word H_StartPos, V_StartPos; + word Htotal, Vtotal; + word H_Res, V_Res; + + byte Polarity; + byte B_Data[12]; + + TPI_TRACE_PRINT((">>SetDE()\n")); + + ModeTblIndex = ConvertVIC_To_VM_Index(); + + if (VModesTable[ModeTblIndex]._3D_Struct != NO_3D_SUPPORT) + { + return DE_CANNOT_BE_SET_WITH_3D_MODE; + TPI_TRACE_PRINT((">>SetDE() not allowed with 3D video format\n")); + } + + // Make sure that External Sync method is set before enableing the DE Generator: + RegValue = ReadByteTPI(TPI_SYNC_GEN_CTRL); + + if (RegValue & BIT_7) + { + return DE_CANNOT_BE_SET_WITH_EMBEDDED_SYNC; + } + + H_StartPos = VModesTable[ModeTblIndex].Pos.H; + V_StartPos = VModesTable[ModeTblIndex].Pos.V; + + Htotal = VModesTable[ModeTblIndex].Tag.Total.Pixels; + Vtotal = VModesTable[ModeTblIndex].Tag.Total.Lines; + + Polarity = (~VModesTable[ModeTblIndex].Tag.RefrTypeVHPol) & TWO_LSBITS; + + H_Res = VModesTable[ModeTblIndex].Res.H; + + if ((VModesTable[ModeTblIndex].Tag.RefrTypeVHPol & 0x04)) + { + V_Res = (VModesTable[ModeTblIndex].Res.V) >> 1; //if interlace V-resolution divided by 2 + } + else + { + V_Res = (VModesTable[ModeTblIndex].Res.V); + } + + B_Data[0] = H_StartPos & LOW_BYTE; // 8 LSB of DE DLY in 0x62 + + B_Data[1] = (H_StartPos >> 8) & TWO_LSBITS; // 2 MSBits of DE DLY to 0x63 + B_Data[1] |= (Polarity << 4); // V and H polarity + B_Data[1] |= BIT_EN_DE_GEN; // enable DE generator + + B_Data[2] = V_StartPos & SEVEN_LSBITS; // DE_TOP in 0x64 + B_Data[3] = 0x00; // 0x65 is reserved + B_Data[4] = H_Res & LOW_BYTE; // 8 LSBits of DE_CNT in 0x66 + B_Data[5] = (H_Res >> 8) & LOW_NIBBLE; // 4 MSBits of DE_CNT in 0x67 + B_Data[6] = V_Res & LOW_BYTE; // 8 LSBits of DE_LIN in 0x68 + B_Data[7] = (V_Res >> 8) & THREE_LSBITS; // 3 MSBits of DE_LIN in 0x69 + B_Data[8] = Htotal & LOW_BYTE; // 8 LSBits of H_RES in 0x6A + B_Data[9] = (Htotal >> 8) & LOW_NIBBLE; // 4 MSBITS of H_RES in 0x6B + B_Data[10] = Vtotal & LOW_BYTE; // 8 LSBits of V_RES in 0x6C + B_Data[11] = (Vtotal >> 8) & BITS_2_1_0; // 3 MSBITS of V_RES in 0x6D + + WriteBlockTPI(TPI_DE_DLY, 12, &B_Data[0]); + TPI_REG0x63_SAVED = B_Data[1]; + + return DE_SET_OK; // Write completed successfully +} + +//------------------------------------------------------------------------------ +// Function Name: SetFormat() +// Function Description: Set the 9022/4 format +// +// Accepts: none +// Returns: DE_SET_OK +// Globals: none +//------------------------------------------------------------------------------ +void SetFormat (byte *Data) +{ + ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, OUTPUT_MODE_MASK, OUTPUT_MODE_HDMI); // Set HDMI mode to allow color space conversion + + WriteBlockTPI(TPI_INPUT_FORMAT_REG, 2, Data); // Program TPI AVI Input and Output Format + WriteByteTPI(TPI_END_RIGHT_BAR_MSB, 0x00); // Set last byte of TPI AVI InfoFrame for TPI AVI I/O Format to take effect + + if (!IsHDMI_Sink()) + { + ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, OUTPUT_MODE_MASK, OUTPUT_MODE_DVI); + } + + if (siHdmiTx.SyncMode == EMBEDDED_SYNC) + EnableEmbeddedSync(); // Last byte of TPI AVI InfoFrame resets Embedded Sync Extraction +} + +//------------------------------------------------------------------------------ +// Function Name: printVideoMode() +// Function Description: print video mode +// +// Accepts: siHdmiTx.VIC +// Returns: none +// Globals: none +//------------------------------------------------------------------------------ +void printVideoMode (void) +{ + TPI_TRACE_PRINT((">>Video mode = ")); + + switch (siHdmiTx.VIC) + { + case 6: + TPI_TRACE_PRINT(("HDMI_480I60_4X3 \n")); + break; + case 21: + TPI_TRACE_PRINT(("HDMI_576I50_4X3 \n")); + break; + case 2: + TPI_TRACE_PRINT(("HDMI_480P60_4X3 \n")); + break; + case 17: + TPI_TRACE_PRINT(("HDMI_576P50_4X3 \n")); + break; + case 4: + TPI_TRACE_PRINT(("HDMI_720P60 \n")); + break; + case 19: + TPI_TRACE_PRINT(("HDMI_720P50 \n")); + break; + case 5: + TPI_TRACE_PRINT(("HDMI_1080I60 \n")); + break; + case 20: + TPI_TRACE_PRINT(("HDMI_1080I50 \n")); + break; + case 16: + TPI_TRACE_PRINT(("HDMI_1080P60 \n")); + break; + case 31: + TPI_TRACE_PRINT(("HDMI_1080P50 \n")); + break; + case PC_BASE+13: + TPI_TRACE_PRINT(("HDMI_1024_768_60 \n")); + break; + case PC_BASE+9: + TPI_TRACE_PRINT(("HDMI_800_600_60 \n")); + break; + default: + break; + } +} + +//------------------------------------------------------------------------------ +// Function Name: InitVideo() +// Function Description: Set the 9022/4 to the video mode determined by GetVideoMode() +// +// Accepts: Index of video mode to set; Flag that distinguishes between +// calling this function after power up and after input +// resolution change +// Returns: TRUE +// Globals: VModesTable, VideoCommandImage +//------------------------------------------------------------------------------ +byte InitVideo (byte TclkSel) +{ + byte ModeTblIndex; + +#ifdef DEEP_COLOR + byte temp; +#endif + byte B_Data[8]; + + byte EMB_Status; //EmbeddedSync set flag + byte DE_Status; + byte Pattern; + + TPI_TRACE_PRINT((">>InitVideo()\n")); + printVideoMode(); + TPI_TRACE_PRINT((" HF:%d", (int) siHdmiTx.HDMIVideoFormat)); + TPI_TRACE_PRINT((" VIC:%d", (int) siHdmiTx.VIC)); + TPI_TRACE_PRINT((" A:%x", (int) siHdmiTx.AspectRatio)); + TPI_TRACE_PRINT((" CS:%x", (int) siHdmiTx.ColorSpace)); + TPI_TRACE_PRINT((" CD:%x", (int) siHdmiTx.ColorDepth)); + TPI_TRACE_PRINT((" CR:%x", (int) siHdmiTx.Colorimetry)); + TPI_TRACE_PRINT((" SM:%x", (int) siHdmiTx.SyncMode)); + TPI_TRACE_PRINT((" TCLK:%x", (int) siHdmiTx.TclkSel)); + TPI_TRACE_PRINT((" 3D:%d", (int) siHdmiTx.ThreeDStructure)); + TPI_TRACE_PRINT((" 3Dx:%d\n", (int) siHdmiTx.ThreeDExtData)); + + ModeTblIndex = (byte)ConvertVIC_To_VM_Index(); + + Pattern = (TclkSel << 6) & TWO_MSBITS; // Use TPI 0x08[7:6] for 9022A/24A video clock multiplier + ReadSetWriteTPI(TPI_PIX_REPETITION, Pattern); //TClkSel1:Ratio of output TMDS clock to input video clock,00-x0.5,01- x1 (default),10 -x2,11-x4 + + // Take values from VModesTable[]: + if( (siHdmiTx.VIC == 6) || (siHdmiTx.VIC == 7) || //480i + (siHdmiTx.VIC == 21) || (siHdmiTx.VIC == 22) ) //576i + { + if( siHdmiTx.ColorSpace == YCBCR422_8BITS) //27Mhz pixel clock + { + B_Data[0] = VModesTable[ModeTblIndex].PixClk & 0x00FF; + B_Data[1] = (VModesTable[ModeTblIndex].PixClk >> 8) & 0xFF; + } + else //13.5Mhz pixel clock + { + B_Data[0] = (VModesTable[ModeTblIndex].PixClk /2) & 0x00FF; + B_Data[1] = ((VModesTable[ModeTblIndex].PixClk /2) >> 8) & 0xFF; + } + + } + else + { + B_Data[0] = VModesTable[ModeTblIndex].PixClk & 0x00FF; // write Pixel clock to TPI registers 0x00, 0x01 + B_Data[1] = (VModesTable[ModeTblIndex].PixClk >> 8) & 0xFF; + } + + B_Data[2] = VModesTable[ModeTblIndex].Tag.VFreq & 0x00FF; // write Vertical Frequency to TPI registers 0x02, 0x03 + B_Data[3] = (VModesTable[ModeTblIndex].Tag.VFreq >> 8) & 0xFF; + + if( (siHdmiTx.VIC == 6) || (siHdmiTx.VIC == 7) || //480i + (siHdmiTx.VIC == 21) || (siHdmiTx.VIC == 22) ) //576i + { + B_Data[4] = (VModesTable[ModeTblIndex].Tag.Total.Pixels /2) & 0x00FF; // write total number of pixels to TPI registers 0x04, 0x05 + B_Data[5] = ((VModesTable[ModeTblIndex].Tag.Total.Pixels /2) >> 8) & 0xFF; + } + else + { + B_Data[4] = VModesTable[ModeTblIndex].Tag.Total.Pixels & 0x00FF; // write total number of pixels to TPI registers 0x04, 0x05 + B_Data[5] = (VModesTable[ModeTblIndex].Tag.Total.Pixels >> 8) & 0xFF; + } + + B_Data[6] = VModesTable[ModeTblIndex].Tag.Total.Lines & 0x00FF; // write total number of lines to TPI registers 0x06, 0x07 + B_Data[7] = (VModesTable[ModeTblIndex].Tag.Total.Lines >> 8) & 0xFF; + + WriteBlockTPI(TPI_PIX_CLK_LSB, 8, B_Data); // Write TPI Mode data.//0x00-0x07 :Video Mode Defines the incoming resolution + + // TPI Input Bus and Pixel Repetition Data + // B_Data[0] = Reg0x08; + B_Data[0] = 0; // Set to default 0 for use again + //B_Data[0] = (VModesTable[ModeTblIndex].PixRep) & LOW_BYTE; // Set pixel replication field of 0x08 + B_Data[0] |= BIT_BUS_24; // Set 24 bit bus:Input Bus Select. The input data bus can be either one pixel wide or 1/2 pixel wide. The bit defaults to 1 to select full pixel mode. In 1/2 pixel mode, the full pixel is brought in on two successive clock edges (one rising, one falling). + //All parts support 24-bit full-pixel and 12-bit half-pixel input modes. + B_Data[0] |= (TclkSel << 6) & TWO_MSBITS; + +#ifdef CLOCK_EDGE_FALLING + B_Data[0] &= ~BIT_EDGE_RISE; // Set to falling edge +#elif defined(CLOCK_EDGE_RISING) + B_Data[0] |= BIT_EDGE_RISE; // Set to rising edge +#endif + + tpivmode[0] = B_Data[0]; // saved TPI Reg0x08 value. + WriteByteTPI(TPI_PIX_REPETITION, B_Data[0]); // 0x08 + + // TPI AVI Input and Output Format Data + // B_Data[0] = Reg0x09; + // B_Data[1] = Reg0x0A; + B_Data[0] = 0; // Set to default 0 for use again + B_Data[1] = 0; // Set to default 0 for use again + + if (siHdmiTx.SyncMode == EMBEDDED_SYNC) + { + EMB_Status = SetEmbeddedSync(); + EnableEmbeddedSync(); //enablle EmbeddedSync + } + + if (siHdmiTx.SyncMode == INTERNAL_DE) + { + ReadClearWriteTPI(TPI_SYNC_GEN_CTRL, MSBIT); // set 0x60[7] = 0 for External Sync + DE_Status = SetDE(); // Call SetDE() with Video Mode as a parameter + } + + if (siHdmiTx.ColorSpace == RGB) + B_Data[0] = (((BITS_IN_RGB | BITS_IN_AUTO_RANGE) & ~BIT_EN_DITHER_10_8) & ~BIT_EXTENDED_MODE); // reg0x09 + + else if (siHdmiTx.ColorSpace == YCBCR444) + B_Data[0] = (((BITS_IN_YCBCR444 | BITS_IN_AUTO_RANGE) & ~BIT_EN_DITHER_10_8) & ~BIT_EXTENDED_MODE); // 0x09 + + else if ((siHdmiTx.ColorSpace == YCBCR422_16BITS) ||(siHdmiTx.ColorSpace == YCBCR422_8BITS)) + B_Data[0] = (((BITS_IN_YCBCR422 | BITS_IN_AUTO_RANGE) & ~BIT_EN_DITHER_10_8) & ~BIT_EXTENDED_MODE); // 0x09 + +#ifdef DEEP_COLOR + switch (siHdmiTx.ColorDepth) + { + case 0: temp = 0x00; ReadModifyWriteTPI(TPI_DEEP_COLOR_GCP, BIT_2, 0x00); break; + case 1: temp = 0x80; ReadModifyWriteTPI(TPI_DEEP_COLOR_GCP, BIT_2, BIT_2); break; + case 2: temp = 0xC0; ReadModifyWriteTPI(TPI_DEEP_COLOR_GCP, BIT_2, BIT_2); break; + case 3: temp = 0x40; ReadModifyWriteTPI(TPI_DEEP_COLOR_GCP, BIT_2, BIT_2); break; + default: temp = 0x00; ReadModifyWriteTPI(TPI_DEEP_COLOR_GCP, BIT_2, 0x00); break; + //General Control Packet ¨C Deep color settings require the General Control Packet to be sent once per video field + //with the correct PP and CD information. This must be enabled by software via TPI Deep Color Packet Enable + //Register 0x40[2] = 1, enable transmission of the GCP packet. + } + B_Data[0] = ((B_Data[0] & 0x3F) | temp);// reg0x09 +#endif + + B_Data[1] = (BITS_OUT_RGB | BITS_OUT_AUTO_RANGE); //Reg0x0A + + if ((siHdmiTx.VIC == 6) || (siHdmiTx.VIC == 7) || //480i + (siHdmiTx.VIC == 21) || (siHdmiTx.VIC == 22) ||//576i + (siHdmiTx.VIC == 2) || (siHdmiTx.VIC == 3) || //480p + (siHdmiTx.VIC == 17) ||(siHdmiTx.VIC == 18)) //576p + { + B_Data[1] &= ~BIT_BT_709; + } + else + { + B_Data[1] |= BIT_BT_709; + } + +#ifdef DEEP_COLOR + B_Data[1] = ((B_Data[1] & 0x3F) | temp); +#endif + +#ifdef DEV_SUPPORT_EDID + if (!IsHDMI_Sink()) + { + B_Data[1] = ((B_Data[1] & 0xFC) | BITS_OUT_RGB); + } + else + { + // Set YCbCr color space depending on EDID + if (g_edid.YCbCr_4_4_4) + { + B_Data[1] = ((B_Data[1] & 0xFC) | BITS_OUT_YCBCR444); + } + else + { + if (g_edid.YCbCr_4_2_2) + { + B_Data[1] = ((B_Data[1] & 0xFC) | BITS_OUT_YCBCR422); + } + else + { + B_Data[1] = ((B_Data[1] & 0xFC) | BITS_OUT_RGB); + } + } + } +#endif + + tpivmode[1] = B_Data[0]; // saved TPI Reg0x09 value. + tpivmode[2] = B_Data[1]; // saved TPI Reg0x0A value. + SetFormat(B_Data); + + ReadClearWriteTPI(TPI_SYNC_GEN_CTRL, BIT_2); // Number HSync pulses from VSync active edge to Video Data Period should be 20 (VS_TO_VIDEO) + + return TRUE; +} + +//------------------------------------------------------------------------------ +// Function Name: SetAVI_InfoFrames() +// Function Description: Load AVI InfoFrame data into registers and send to sink +// +// Accepts: An API_Cmd parameter that holds the data to be sent in the InfoFrames +// Returns: TRUE +// Globals: none +// +// Note: : Infoframe contents are from spec CEA-861-D +// +//------------------------------------------------------------------------------ +byte SetAVI_InfoFrames (void) +{ + byte B_Data[SIZE_AVI_INFOFRAME]; + byte i; + byte TmpVal; + byte VModeTblIndex; + + TPI_TRACE_PRINT((">>SetAVI_InfoFrames()\n")); + + for (i = 0; i < SIZE_AVI_INFOFRAME; i++) + B_Data[i] = 0; + +#ifdef DEV_SUPPORT_EDID + if (g_edid.YCbCr_4_4_4) + TmpVal = 2; + else if (g_edid.YCbCr_4_2_2) + TmpVal = 1; + else + TmpVal = 0; +#else + TmpVal = 0; +#endif + + B_Data[1] = (TmpVal << 5) & BITS_OUT_FORMAT; // AVI Byte1: Y1Y0 (output format) + B_Data[1] |= 0x11; // A0 = 1; Active format identification data is present in the AVI InfoFrame. // S1:S0 = 01; Overscanned (television). + + if (siHdmiTx.ColorSpace == XVYCC444) // Extended colorimetry - xvYCC + { + B_Data[2] = 0xC0; // Extended colorimetry info (B_Data[3] valid (CEA-861D, Table 11) + + if (siHdmiTx.Colorimetry == COLORIMETRY_601) // xvYCC601 + B_Data[3] &= ~BITS_6_5_4; + + else if (siHdmiTx.Colorimetry == COLORIMETRY_709) // xvYCC709 + B_Data[3] = (B_Data[3] & ~BITS_6_5_4) | BIT_4; + } + + else if (siHdmiTx.Colorimetry == COLORIMETRY_709) // BT.709 + B_Data[2] = 0x80; // AVI Byte2: C1C0 + + else if (siHdmiTx.Colorimetry == COLORIMETRY_601) // BT.601 + B_Data[2] = 0x40; // AVI Byte2: C1C0 + + else // Carries no data + { // AVI Byte2: C1C0 + B_Data[2] &= ~BITS_7_6; // colorimetry = 0 + B_Data[3] &= ~BITS_6_5_4; // Extended colorimetry = 0 + } + + VModeTblIndex = ConvertVIC_To_VM_Index(); + + B_Data[4] = siHdmiTx.VIC; + + // Set the Aspect Ration info into the Infoframe Byte 2 + if (siHdmiTx.AspectRatio == VMD_ASPECT_RATIO_16x9) + { + B_Data[2] |= _16_To_9; // AVI Byte2: M1M0 + // If the Video Mode table says this mode can be 4x3 OR 16x9, and we are pointing to the + // table entry that is 4x3, then we bump to the next Video Table entry which will be for 16x9. + if ((VModesTable[VModeTblIndex].AspectRatio == R_4or16) && (AspectRatioTable[siHdmiTx.VIC - 1] == R_4)) + { + siHdmiTx.VIC++; + B_Data[4]++; + } + } + else + { + B_Data[2] |= _4_To_3; // AVI Byte4: VIC + } + + B_Data[2] |= SAME_AS_AR; // AVI Byte2: R3..R1 - Set to "Same as Picture Aspect Ratio" + B_Data[5] = VModesTable[VModeTblIndex].PixRep; // AVI Byte5: Pixel Replication - PR3..PR0 + + // Calculate AVI InfoFrame ChecKsum + B_Data[0] = 0x82 + 0x02 +0x0D; + for (i = 1; i < SIZE_AVI_INFOFRAME; i++) + { + B_Data[0] += B_Data[i]; + } + B_Data[0] = 0x100 - B_Data[0]; + + // Write the Inforframe data to the TPI Infoframe registers + WriteBlockTPI(TPI_AVI_BYTE_0, SIZE_AVI_INFOFRAME, B_Data); + + if (siHdmiTx.SyncMode == EMBEDDED_SYNC) + EnableEmbeddedSync(); + + return TRUE; +} + +extern void siHdmiTx_PowerStateD0 (void); +extern void SetAudioMute (byte audioMute); +//------------------------------------------------------------------------------ +// Function Name: siHdmiTx_Init() +// Function Description: Set the 9022/4 video and video. +// +// Accepts: none +// Returns: none +// Globals: siHdmiTx +//------------------------------------------------------------------------------ +void siHdmiTx_Init (void) +{ + TPI_TRACE_PRINT((">>siHdmiTx_Init()\n")); + + // workaround for Bug#18128 + if (siHdmiTx.ColorDepth == VMD_COLOR_DEPTH_8BIT) + { + // Yes it is, so force 16bpps first! + siHdmiTx.ColorDepth = VMD_COLOR_DEPTH_16BIT; + InitVideo(siHdmiTx.TclkSel); + // Now put it back to 8bit and go do the expected InitVideo() call + siHdmiTx.ColorDepth = VMD_COLOR_DEPTH_8BIT; + } + // end workaround + + InitVideo(siHdmiTx.TclkSel); // Set PLL Multiplier to x1 upon power up + + siHdmiTx_PowerStateD0(); + + if (IsHDMI_Sink()) // Set InfoFrames only if HDMI output mode + { + SetAVI_InfoFrames(); + siHdmiTx_AudioSet(); // set audio interface to basic audio (an external command is needed to set to any other mode + } + else + { + SetAudioMute(AUDIO_MUTE_MUTED); + } + + // THIS PATCH IS NEEDED BECAUSE SETTING UP AVI InfoFrames CLEARS 0x63 and 0x60[5] + if (siHdmiTx.ColorSpace == YCBCR422_8BITS) + ReadSetWriteTPI(TPI_SYNC_GEN_CTRL, BIT_5); // Set 0x60[5] according to input color space. + + // THIS PATCH IS NEEDED BECAUSE SETTING UP AVI InfoFrames CLEARS 0x63 + TPI_REG0x63_SAVED = 0x30; + printk("set 0x63 to %02x\n",TPI_REG0x63_SAVED); + WriteByteTPI(TPI_DE_CTRL, TPI_REG0x63_SAVED); + + //========================================================== + WriteByteTPI(TPI_YC_Input_Mode, 0x00); + + + if ((g_hdcp.HDCP_TxSupports == TRUE) && (g_hdcp.HDCPAuthenticated == VMD_HDCP_AUTHENTICATED)&&(Sii9024A_HDCP_supported)) + { + if (g_hdcp.HDCP_AksvValid == TRUE) + { + // AV MUTE + TPI_DEBUG_PRINT (("TMDS -> Enabled (Video Muted)\n")); + ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, LINK_INTEGRITY_MODE_MASK | TMDS_OUTPUT_CONTROL_MASK | AV_MUTE_MASK, + LINK_INTEGRITY_DYNAMIC | TMDS_OUTPUT_CONTROL_ACTIVE | AV_MUTE_MUTED); + + WriteByteTPI(TPI_PIX_REPETITION, tpivmode[0]); // Write register 0x08 + g_sys.tmdsPoweredUp = TRUE; + EnableInterrupts(HOT_PLUG_EVENT | RX_SENSE_EVENT | AUDIO_ERROR_EVENT | SECURITY_CHANGE_EVENT | HDCP_CHANGE_EVENT); + } + } + else{ + TPI_DEBUG_PRINT (("TMDS -> Enabled\n")); + ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, LINK_INTEGRITY_MODE_MASK | TMDS_OUTPUT_CONTROL_MASK | AV_MUTE_MASK, + LINK_INTEGRITY_DYNAMIC | TMDS_OUTPUT_CONTROL_ACTIVE | AV_MUTE_NORMAL); + + WriteByteTPI(TPI_PIX_REPETITION, tpivmode[0]); // Write register 0x08 + g_sys.tmdsPoweredUp = TRUE; + EnableInterrupts(HOT_PLUG_EVENT | RX_SENSE_EVENT );//| AUDIO_ERROR_EVENT); + } +} + +//------------------------------------------------------------------------------ +// Function Name: siHdmiTx_VideoSet() +// Function Description: Set the 9022/4 video resolution +// +// Accepts: none +// Returns: Success message if video resolution changed successfully. +// Error Code if resolution change failed +// Globals: siHdmiTx +//------------------------------------------------------------------------------ + +byte siHdmiTx_VideoSet (void) +{ + TPI_TRACE_PRINT((">>siHdmiTx_VideoSet()\n")); + // Note: this's necessary for fixing 480i_13.5MHz to 1080p_148.5MHz no display issue. + siHdmiTx_TPI_Init(); + g_sys.hdmiCableConnected = TRUE; + g_sys.dsRxPoweredUp = TRUE; + siHdmiTx_Init(); + if (Sii9024A_HDCP_supported) + HDCP_CheckStatus( ReadByteTPI(TPI_INTERRUPT_STATUS_REG) ); + + return VIDEO_MODE_SET_OK; +} + + +byte SetAudioInfoFrames(byte ChannelCount,byte CodingType,byte ss,byte Fs, byte SpeakerConfig) +{ + byte B_Data[SIZE_AUDIO_INFOFRAME]; + byte i; + + TPI_TRACE_PRINT((">>SetAudioInfoFrames()\n")); + + for (i = 0; i < SIZE_AUDIO_INFOFRAME; i++) + B_Data[i] = 0; + + WriteByteTPI(MISC_INFO_FRAMES_CTRL, DISABLE_AUDIO); + + B_Data[0] = TYPE_AUDIO_INFOFRAMES; + B_Data[1] = AUDIO_INFOFRAMES_VERSION; + B_Data[2] = AUDIO_INFOFRAMES_LENGTH; + B_Data[3] = TYPE_AUDIO_INFOFRAMES + AUDIO_INFOFRAMES_VERSION + AUDIO_INFOFRAMES_LENGTH; + + B_Data[4] = ChannelCount; + B_Data[4] |= (CodingType << 4); + B_Data[5] = ((Fs & THREE_LSBITS) << 2) | (ss & TWO_LSBITS); + B_Data[7] = SpeakerConfig; + + for (i = 4; i < SIZE_AUDIO_INFOFRAME; i++) + B_Data[3] += B_Data[i]; + + B_Data[3] = 0x100 - B_Data[3]; + WriteByteTPI(MISC_INFO_FRAMES_CTRL, EN_AND_RPT_AUDIO); + WriteBlockTPI(MISC_INFO_FRAMES_TYPE, SIZE_AUDIO_INFOFRAME, B_Data); + if (siHdmiTx.SyncMode == EMBEDDED_SYNC) + EnableEmbeddedSync(); + + return TRUE; +} + +//------------------------------------------------------------------------------ +// Function Name: SetAudioMute() +// Function Description: Mute audio +// +// Accepts: Mute or unmute. +// Returns: none +// Globals: none +//------------------------------------------------------------------------------ +void SetAudioMute (byte audioMute) +{ + ReadModifyWriteTPI(TPI_AUDIO_INTERFACE_REG, AUDIO_MUTE_MASK, audioMute); +} + +#ifndef F_9022A_9334 +//------------------------------------------------------------------------------ +// Function Name: SetChannelLayout() +// Function Description: Set up the Channel layout field of internal register 0x2F (0x2F[1]) +// +// Accepts: Number of audio channels: "0 for 2-Channels ."1" for 8. +// Returns: none +// Globals: none +//------------------------------------------------------------------------------ +void SetChannelLayout (byte Count) +{ + // Indexed register 0x7A:0x2F[1]: + WriteByteTPI(TPI_INTERNAL_PAGE_REG, 0x02); // Internal page 2 + WriteByteTPI(TPI_INDEXED_OFFSET_REG, 0x2F); + + Count &= THREE_LSBITS; + + if (Count == TWO_CHANNEL_LAYOUT) + { + // Clear 0x2F[1]: + ReadClearWriteTPI(TPI_INDEXED_VALUE_REG, BIT_1); + } + + else if (Count == EIGHT_CHANNEL_LAYOUT) + { + // Set 0x2F[1]: + ReadSetWriteTPI(TPI_INDEXED_VALUE_REG, BIT_1); + } +} +#endif + +//------------------------------------------------------------------------------ +// Function Name: siHdmiTx_AudioSet() +// Function Description: Set the 9022/4 audio interface to basic audio. +// +// Accepts: none +// Returns: Success message if audio changed successfully. +// Error Code if resolution change failed +// Globals: siHdmiTx +//------------------------------------------------------------------------------ +byte siHdmiTx_AudioSet (void) +{ + TPI_TRACE_PRINT((">>siHdmiTx_AudioSet()\n")); + + SetAudioMute(AUDIO_MUTE_MUTED); // mute output + + if (siHdmiTx.AudioMode == AMODE_I2S) // I2S input + { + ReadModifyWriteTPI(TPI_AUDIO_INTERFACE_REG, AUDIO_SEL_MASK, AUD_IF_I2S); // 0x26 = 0x80 + WriteByteTPI(TPI_AUDIO_HANDLING, 0x08 | AUD_DO_NOT_CHECK); // 0x25 + } + else // SPDIF input + { + ReadModifyWriteTPI(TPI_AUDIO_INTERFACE_REG, AUDIO_SEL_MASK, AUD_IF_SPDIF); // 0x26 = 0x40 + WriteByteTPI(TPI_AUDIO_HANDLING, AUD_PASS_BASIC); // 0x25 = 0x00 + } + +#ifndef F_9022A_9334 + if (siHdmiTx.AudioChannels == ACHANNEL_2CH) + SetChannelLayout(TWO_CHANNELS); // Always 2 channesl in S/PDIF + else + SetChannelLayout(EIGHT_CHANNELS); +#else + if (siHdmiTx.AudioChannels == ACHANNEL_2CH) + ReadClearWriteTPI(TPI_AUDIO_INTERFACE_REG, BIT_5); // Use TPI 0x26[5] for 9022A/24A and 9334 channel layout + else + ReadSetWriteTPI(TPI_AUDIO_INTERFACE_REG, BIT_5); // Use TPI 0x26[5] for 9022A/24A and 9334 channel layout +#endif + + if (siHdmiTx.AudioMode == AMODE_I2S) // I2S input + { + // I2S - Map channels - replace with call to API MAPI2S + WriteByteTPI(TPI_I2S_EN, 0x80); // 0x1F + + if (siHdmiTx.AudioChannels > ACHANNEL_2CH) + WriteByteTPI(TPI_I2S_EN, 0x91); + + if (siHdmiTx.AudioChannels > ACHANNEL_4CH) + WriteByteTPI(TPI_I2S_EN, 0xA2); + + if (siHdmiTx.AudioChannels > ACHANNEL_6CH) + WriteByteTPI(TPI_I2S_EN, 0xB3); + + // I2S - Stream Header Settings - replace with call to API SetI2S_StreamHeader + WriteByteTPI(TPI_I2S_CHST_0, 0x00); // 0x21 + WriteByteTPI(TPI_I2S_CHST_1, 0x00); + WriteByteTPI(TPI_I2S_CHST_2, 0x00); + WriteByteTPI(TPI_I2S_CHST_3, siHdmiTx.AudioFs); + WriteByteTPI(TPI_I2S_CHST_4, (siHdmiTx.AudioFs << 4) |siHdmiTx.AudioWordLength); + + // Oscar 20100929 added for 16bit auido noise issue + WriteIndexedRegister(INDEXED_PAGE_1, AUDIO_INPUT_LENGTH, siHdmiTx.AudioWordLength); + + // I2S - Input Configuration + WriteByteTPI(TPI_I2S_IN_CFG, siHdmiTx.AudioI2SFormat); //TPI_Reg0x20 + } + + WriteByteTPI(TPI_AUDIO_SAMPLE_CTRL, REFER_TO_STREAM_HDR); + SetAudioInfoFrames(siHdmiTx.AudioChannels & THREE_LSBITS, REFER_TO_STREAM_HDR, REFER_TO_STREAM_HDR, REFER_TO_STREAM_HDR, 0x00); + + SetAudioMute(AUDIO_MUTE_NORMAL); // unmute output + + return AUDIO_MODE_SET_OK; +} + +#ifdef F_9022A_9334 +//------------------------------------------------------------------------------ +// Function Name: SetGBD_InfoFrame() +// Function Description: Sets and sends the the 9022A/4A GBD InfoFrames. +// +// Accepts: none +// Returns: Success message if GBD packet set successfully. Error +// Code if failed +// Globals: none +// NOTE: Currently this function is a place holder. It always returns a Success message +//------------------------------------------------------------------------------ +byte SetGBD_InfoFrame (void) +{ + byte CheckSum; + + TPI_TRACE_PRINT((">>SetGBD_InfoFrame()\n")); + + // Set MPEG InfoFrame Header to GBD InfoFrame Header values: + WriteByteTPI(MISC_INFO_FRAMES_CTRL, DISABLE_MPEG); // 0xBF = Use MPEG InfoFrame for GBD - 0x03 + WriteByteTPI(MISC_INFO_FRAMES_TYPE, TYPE_GBD_INFOFRAME); // 0xC0 = 0x0A + WriteByteTPI(MISC_INFO_FRAMES_VER, NEXT_FIELD | GBD_PROFILE | AFFECTED_GAMUT_SEQ_NUM); // 0x0C1 = 0x81 + WriteByteTPI(MISC_INFO_FRAMES_LEN, ONLY_PACKET | CURRENT_GAMUT_SEQ_NUM); // 0x0C2 = 0x31 + + CheckSum = TYPE_GBD_INFOFRAME + + NEXT_FIELD + + GBD_PROFILE + + AFFECTED_GAMUT_SEQ_NUM + + ONLY_PACKET + + CURRENT_GAMUT_SEQ_NUM; + + CheckSum = 0x100 - CheckSum; + + WriteByteTPI(MISC_INFO_FRAMES_CTRL, EN_AND_RPT_MPEG); // Enable and Repeat MPEG InfoFrames + WriteByteTPI(MISC_INFO_FRAMES_CHKSUM, CheckSum); // 0X00 - Send header only + + return GBD_SET_SUCCESSFULLY; +} +#endif + +#ifdef DEV_SUPPORT_3D +//------------------------------------------------------------------------------ +// Function Name: Set_VSIF() +// Function Description: Construct Vendor Specific InfoFrame for 3D support. use MPEG InfoFrame +// +// Accepts: none +// Returns: none +// Globals: siHdmiTx +//------------------------------------------------------------------------------ +// VSIF Constants +//============================================================ +#define VSIF_TYPE 0x81 +#define VSIF_VERSION 0x01 +#define VSIF_LEN 0x06 + +void Set_VSIF (void) +{ + byte i; + byte Data[SIZE_MPEG_INFOFRAME]; //10 + + for (i = 0; i < SIZE_MPEG_INFOFRAME; i++) + { + Data[i] = 0; + } + + // Disable transmission of VSIF during re-configuration + WriteByteTPI(MISC_INFO_FRAMES_CTRL, DISABLE_MPEG); + + // Header Bytes + Data[0] = VSIF_TYPE; // HB0 Packet Type 0x81 + Data[1] = VSIF_VERSION; // HB1 Version = 0x01 + + // PB1 - PB3 contain the 24bit IEEE Registration Identifier + Data[4] = 0x03; // HDMI Signature LS Byte + Data[5] = 0x0C; // HDMI Signature middle byte + Data[6] = 0x00; // HDMI Signature MS Byte + + // PB4 - HDMI_Video_Format into bits 7:5 + Data[7] = siHdmiTx.HDMIVideoFormat << 5; + + // PB5 - Depending on the video format, this byte will contain either the HDMI_VIC + // code in buts 7:0, OR the 3D_Structure in bits 7:4. + switch(siHdmiTx.HDMIVideoFormat) + { + case VMD_HDMIFORMAT_HDMI_VIC: + // This is a 2x4K mode, set the HDMI_VIC in buts 7:0. Values + // are from HDMI 1.4 Spec, 8.2.3.1 (Table 8-13). + Data[8] = siHdmiTx.VIC; + Data[9] = 0; + break; + + case VMD_HDMIFORMAT_3D: + // This is a 3D mode, set the 3D_Structure in buts 7:4 + // Bits 3:0 are reseved so set to 0. Values are from HDMI 1.4 + // Spec, Appendix H (Table H-2). + Data[8] = siHdmiTx.ThreeDStructure << 4; + // Add the Extended data field when the 3D format is Side-by-Side(Half). + // See Spec Table H-3 for details. + if ((Data[8] >> 4) == VMD_3D_SIDEBYSIDEHALF) + { + Data[2] = VSIF_LEN; + Data[9] = siHdmiTx.ThreeDExtData << 4;; + } + else + { + Data[2] = VSIF_LEN-1; + } + break; + + case VMD_HDMIFORMAT_CEA_VIC: + default: + Data[8] = 0; + Data[9] = 0; + break; + } + + // Packet Bytes + Data[3] = VSIF_TYPE+ // PB0 partial checksum + VSIF_VERSION+ + Data[2]; + + // Complete the checksum with PB1 through PB7 + for (i = 4; i < SIZE_MPEG_INFOFRAME; i++) + { + Data[3] += Data[i]; + } + // Data[3] %= 0x100; + Data[3] = 0x100 - Data[3]; // Final checksum + + WriteByteTPI(MISC_INFO_FRAMES_CTRL, EN_AND_RPT_MPEG); // Enable and Repeat MPEG/Vendor Specific InfoFrames + + WriteBlockTPI(MISC_INFO_FRAMES_TYPE, SIZE_MPEG_INFOFRAME, Data); // Write VSIF to MPEG registers and start transmission + WriteByteTPI(0xDE, 0x00); // Set last byte of MPEG InfoFrame for data to be sent to sink. +} +#endif + + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +///////////////////////*************************/////////////////////////////// +/////////////////////// TPI /////////////////////////////// +///////////////////////*************************/////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + + +//------------------------------------------------------------------------------ +// Function Name: StartTPI() +// Function Description: Start HW TPI mode by writing 0x00 to TPI address 0xC7. +// +// Accepts: none +// Returns: TRUE if HW TPI started successfully. FALSE if failed to. +// Globals: none +//------------------------------------------------------------------------------ +byte StartTPI (void) +{ + byte devID = 0x00; + word wID = 0x0000; + + TPI_TRACE_PRINT((">>StartTPI()\n")); + + WriteByteTPI(TPI_ENABLE, 0x00); // Write "0" to 72:C7 to start HW TPI mode + + DelayMS(100); + + devID = ReadIndexedRegister(INDEXED_PAGE_0, 0x03); + wID = devID; + wID <<= 8; + devID = ReadIndexedRegister(INDEXED_PAGE_0, 0x02); + wID |= devID; + + devID = ReadByteTPI(TPI_DEVICE_ID); + + TPI_TRACE_PRINT(("0x%04X\n", (int)wID)); + TPI_TRACE_PRINT(("%s:%d:devID=0x%04x \n", __func__,__LINE__,devID)); + + if (wID == 0x9022) + Sii9024A_HDCP_supported = false; + if (devID == SII902XA_DEVICE_ID) + return TRUE; + + TPI_TRACE_PRINT(("Unsupported TX, devID = 0x%X\n", (int)devID)); + return FALSE; +} + +//------------------------------------------------------------------------------ +// Function Name: siHdmiTx_TPI_Init() +// Function Description: TPI initialization: HW Reset, Interrupt enable. +// +// Accepts: none +// Returns: TRUE or FLASE +// Globals: none +//------------------------------------------------------------------------------ +byte siHdmiTx_TPI_Init (void) +{ + TPI_TRACE_PRINT(("\n>>siHdmiTx_TPI_Init()\n")); + TPI_TRACE_PRINT(("\n%s\n", TPI_FW_VERSION)); + + // Chip powers up in D2 mode. + g_sys.txPowerState = TX_POWER_STATE_D0; + + InitializeStateVariables(); + + // Toggle TX reset pin + //TxHW_Reset(); + WriteByteTPI(0xF5, 0x00); + // Enable HW TPI mode, check device ID + if (StartTPI()) + { + if (Sii9024A_HDCP_supported){ + g_hdcp.HDCP_Override = FALSE; + g_hdcp.HDCPAuthenticated = VMD_HDCP_AUTHENTICATED; + HDCP_Init(); + } + +#ifdef DEV_SUPPORT_CEC + //SI_CecInit(); +#endif + + EnableInterrupts(HOT_PLUG_EVENT); + + return 0; + } + + return EPERM; +} + +//------------------------------------------------------------------------------ +// Function Name: OnDownstreamRxPoweredDown() +// Function Description: HDMI cable unplug handle. +// +// Accepts: none +// Returns: none +// Globals: none +//------------------------------------------------------------------------------ +void OnDownstreamRxPoweredDown (void) +{ + TPI_DEBUG_PRINT (("DSRX -> Powered Down\n")); + g_sys.dsRxPoweredUp = FALSE; + + if (g_hdcp.HDCP_Started == TRUE && Sii9024A_HDCP_supported) + HDCP_Off(); + DisableTMDS(); + ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, OUTPUT_MODE_MASK,OUTPUT_MODE_DVI); // Set to DVI output mode to reset HDCP +} + +extern void HotPlugService(void); +//------------------------------------------------------------------------------ +// Function Name: OnDownstreamRxPoweredUp() +// Function Description: DSRX power up handle. +// +// Accepts: none +// Returns: none +// Globals: none +//------------------------------------------------------------------------------ +void OnDownstreamRxPoweredUp (void) +{ + TPI_DEBUG_PRINT (("DSRX -> Powered Up\n")); + g_sys.dsRxPoweredUp = TRUE; + + HotPlugService(); +} + +//------------------------------------------------------------------------------ +// Function Name: OnHdmiCableDisconnected() +// Function Description: HDMI cable unplug handle. +// +// Accepts: none +// Returns: none +// Globals: none +//------------------------------------------------------------------------------ +void OnHdmiCableDisconnected (void) +{ + TPI_DEBUG_PRINT (("HDMI Disconnected\n")); + + g_sys.hdmiCableConnected = FALSE; + +#ifdef DEV_SUPPORT_EDID + g_edid.edidDataValid = FALSE; +#endif + + OnDownstreamRxPoweredDown(); +} + +//------------------------------------------------------------------------------ +// Function Name: OnHdmiCableConnected() +// Function Description: HDMI cable plug in handle. +// +// Accepts: none +// Returns: none +// Globals: none +//------------------------------------------------------------------------------ +void OnHdmiCableConnected (void) +{ + TPI_DEBUG_PRINT (("Cable Connected\n")); + // No need to call TPI_Init here unless TX has been powered down on cable removal. + //TPI_Init(); + + g_sys.hdmiCableConnected = TRUE; + + if ((Sii9024A_HDCP_supported) + && (g_hdcp.HDCP_TxSupports == TRUE) + && (g_hdcp.HDCP_AksvValid == TRUE) + && (g_hdcp.HDCPAuthenticated == VMD_HDCP_AUTHENTICATED)) + { + WriteIndexedRegister(INDEXED_PAGE_0, 0xCE, 0x00); // Clear BStatus + WriteIndexedRegister(INDEXED_PAGE_0, 0xCF, 0x00); + } + + + // Added for EDID read for Michael Wang recommaned by oscar 20100908 + //siHdmiTx_PowerStateD0(); + //ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, TMDS_OUTPUT_CONTROL_MASK | AV_MUTE_MASK, TMDS_OUTPUT_CONTROL_ACTIVE | AV_MUTE_MUTED); + +#ifdef DEV_SUPPORT_EDID + DoEdidRead(); +#endif + +#ifdef READKSV + ReadModifyWriteTPI(0xBB, 0x08, 0x08); +#endif + + if (IsHDMI_Sink()) // select output mode (HDMI/DVI) according to sink capabilty + { + TPI_DEBUG_PRINT (("HDMI Sink Detected\n")); + ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, OUTPUT_MODE_MASK, OUTPUT_MODE_HDMI); + } + else + { + TPI_DEBUG_PRINT (("DVI Sink Detected\n")); + ReadModifyWriteTPI(TPI_SYSTEM_CONTROL_DATA_REG, OUTPUT_MODE_MASK, OUTPUT_MODE_DVI); + } +} + +//------------------------------------------------------------------------------ +// Function Name: siHdmiTx_PowerStateD0() +// Function Description: Set TX to D0 mode. +//------------------------------------------------------------------------------ +void siHdmiTx_PowerStateD0 (void) +{ + ReadModifyWriteTPI(TPI_DEVICE_POWER_STATE_CTRL_REG, TX_POWER_STATE_MASK, TX_POWER_STATE_D0); + TPI_DEBUG_PRINT(("TX Power State D0\n")); + g_sys.txPowerState = TX_POWER_STATE_D0; +} + +//------------------------------------------------------------------------------ +// Function Name: siHdmiTx_PowerStateD2() +// Function Description: Set TX to D2 mode. +//------------------------------------------------------------------------------ +void siHdmiTx_PowerStateD2 (void) +{ + ReadModifyWriteTPI(TPI_DEVICE_POWER_STATE_CTRL_REG, TX_POWER_STATE_MASK, TX_POWER_STATE_D2); + TPI_DEBUG_PRINT(("TX Power State D2\n")); + g_sys.txPowerState = TX_POWER_STATE_D2; +} + +//------------------------------------------------------------------------------ +// Function Name: siHdmiTx_PowerStateD0fromD2() +// Function Description: Set TX to D0 mode from D2 mode. +//------------------------------------------------------------------------------ +void siHdmiTx_PowerStateD0fromD2 (void) +{ + ReadModifyWriteTPI(TPI_DEVICE_POWER_STATE_CTRL_REG, TX_POWER_STATE_MASK, TX_POWER_STATE_D0); + + if (Sii9024A_HDCP_supported) + RestartHDCP(); + else + EnableTMDS(); + + TPI_DEBUG_PRINT(("TX Power State D0 from D2\n")); + g_sys.txPowerState = TX_POWER_STATE_D0; +} + +//------------------------------------------------------------------------------ +// Function Name: HotPlugService() +// Function Description: Implement Hot Plug Service Loop activities +// +// Accepts: none +// Returns: An error code that indicates success or cause of failure +// Globals: LinkProtectionLevel +//------------------------------------------------------------------------------ +void HotPlugService (void) +{ + TPI_TRACE_PRINT((">>HotPlugService()\n")); + + DisableInterrupts(0xFF); + + //siHdmiTx.VIC = g_edid.VideoDescriptor[0]; // use 1st mode supported by sink + + siHdmiTx_Init(); +} + +//------------------------------------------------------------------------------ +// Function Name: siHdmiTx_TPI_Poll() +// Function Description: Poll Interrupt Status register for new interrupts +// +// Accepts: none +// Returns: none +// Globals: none +//------------------------------------------------------------------------------ + +void siHdmiTx_TPI_Poll (void) +{ + byte InterruptStatus; + + if (g_sys.txPowerState == TX_POWER_STATE_D0) + { + InterruptStatus = ReadByteTPI(TPI_INTERRUPT_STATUS_REG); + + if (InterruptStatus & HOT_PLUG_EVENT) //judge if HPD is connected + { + TPI_DEBUG_PRINT (("HPD -> ")); + ReadSetWriteTPI(TPI_INTERRUPT_ENABLE_REG, HOT_PLUG_EVENT); // Enable HPD interrupt bit + + // Repeat this loop while cable is bouncing: + do + { + WriteByteTPI(TPI_INTERRUPT_STATUS_REG, HOT_PLUG_EVENT); //Write 1 to interrupt bits to clear the 'pending' status. + DelayMS(T_HPD_DELAY); // Delay for metastability protection and to help filter out connection bouncing + InterruptStatus = ReadByteTPI(TPI_INTERRUPT_STATUS_REG); // Read Interrupt status register + } while (InterruptStatus & HOT_PLUG_EVENT); // loop as long as HP interrupts recur + + if (((InterruptStatus & HOT_PLUG_STATE) >> 2) != g_sys.hdmiCableConnected) + { + if (g_sys.hdmiCableConnected == TRUE) + { + OnHdmiCableDisconnected(); + } + else + { + OnHdmiCableConnected(); + ReadModifyWriteIndexedRegister(INDEXED_PAGE_0, 0x0A, 0x08, 0x08); + } + + if (g_sys.hdmiCableConnected == FALSE) + { + return; + } + } + } + + // Check rx power + if (((InterruptStatus & RX_SENSE_STATE) >> 3) != g_sys.dsRxPoweredUp) + { + if (g_sys.hdmiCableConnected == TRUE) + { + if (g_sys.dsRxPoweredUp == TRUE) + { + OnDownstreamRxPoweredDown(); + } + else + { + OnDownstreamRxPoweredUp(); + } + } + DelayMS(100); // Delay for metastability protection and to help filter out connection bouncing + ClearInterrupt(RX_SENSE_EVENT); + } + + // Check if Audio Error event has occurred: + if (InterruptStatus & AUDIO_ERROR_EVENT) + { + //TPI_DEBUG_PRINT (("TP -> Audio Error Event\n")); + // The hardware handles the event without need for host intervention (PR, p. 31) + ClearInterrupt(AUDIO_ERROR_EVENT); + } + + if ((Sii9024A_HDCP_supported) + && (g_sys.hdmiCableConnected == TRUE) + && (g_sys.dsRxPoweredUp == TRUE) + && (g_hdcp.HDCPAuthenticated == VMD_HDCP_AUTHENTICATED)) + { + HDCP_CheckStatus(InterruptStatus); + } + +#ifdef DEV_SUPPORT_CEC + //SI_CecHandler(0 , 0); +#endif + } + +} + +void siHdmiTx_VideoSel (byte vmode) +{ + siHdmiTx.HDMIVideoFormat = VMD_HDMIFORMAT_CEA_VIC; + siHdmiTx.ColorSpace = RGB; + siHdmiTx.ColorDepth = VMD_COLOR_DEPTH_8BIT; + siHdmiTx.SyncMode = EXTERNAL_HSVSDE; +// siHdmiTx.SyncMode = 1; + + switch (vmode) + { + case HDMI_480I60_4X3: + siHdmiTx.VIC = 6; + siHdmiTx.AspectRatio = VMD_ASPECT_RATIO_4x3; + siHdmiTx.Colorimetry = COLORIMETRY_601; + siHdmiTx.TclkSel = X2; + break; + + case HDMI_576I50_4X3: + siHdmiTx.VIC = 21; + siHdmiTx.AspectRatio = VMD_ASPECT_RATIO_4x3; + siHdmiTx.Colorimetry = COLORIMETRY_601; + siHdmiTx.TclkSel = X2; + break; + + case HDMI_480P60_4X3: + siHdmiTx.VIC = 2; + siHdmiTx.AspectRatio = VMD_ASPECT_RATIO_4x3; + siHdmiTx.Colorimetry = COLORIMETRY_601; + siHdmiTx.TclkSel = X1; + break; + + case HDMI_576P50_4X3: + siHdmiTx.VIC = 17; + siHdmiTx.AspectRatio = VMD_ASPECT_RATIO_4x3; + siHdmiTx.Colorimetry = COLORIMETRY_601; + siHdmiTx.TclkSel = X1; + break; + + case HDMI_720P60: + siHdmiTx.VIC = 4; + siHdmiTx.AspectRatio = VMD_ASPECT_RATIO_16x9; + siHdmiTx.Colorimetry = COLORIMETRY_709; + siHdmiTx.TclkSel = X1; + break; + + case HDMI_720P50: + siHdmiTx.VIC = 19; + siHdmiTx.AspectRatio = VMD_ASPECT_RATIO_16x9; + siHdmiTx.Colorimetry = COLORIMETRY_709; + siHdmiTx.TclkSel = X1; + break; + + case HDMI_1080I60: + siHdmiTx.VIC = 5; + siHdmiTx.AspectRatio = VMD_ASPECT_RATIO_16x9; + siHdmiTx.Colorimetry = COLORIMETRY_709; + siHdmiTx.TclkSel = X1; + break; + + case HDMI_1080I50: + siHdmiTx.VIC = 20; + siHdmiTx.AspectRatio = VMD_ASPECT_RATIO_16x9; + siHdmiTx.Colorimetry = COLORIMETRY_709; + siHdmiTx.TclkSel = X1; + break; + + case HDMI_1080P60: + siHdmiTx.VIC = 16; + siHdmiTx.AspectRatio = VMD_ASPECT_RATIO_16x9; + siHdmiTx.Colorimetry = COLORIMETRY_709; + siHdmiTx.TclkSel = X1; + break; + + case HDMI_1080P50: + siHdmiTx.VIC = 31; + siHdmiTx.AspectRatio = VMD_ASPECT_RATIO_16x9; + siHdmiTx.Colorimetry = COLORIMETRY_709; + siHdmiTx.TclkSel = X1; + break; + + case HDMI_1024_768_60: + siHdmiTx.VIC = PC_BASE+13; + siHdmiTx.AspectRatio = VMD_ASPECT_RATIO_4x3; + siHdmiTx.Colorimetry = COLORIMETRY_709; + siHdmiTx.TclkSel = X1; + break; + case HDMI_800_600_60: + siHdmiTx.VIC = PC_BASE+9; + siHdmiTx.AspectRatio = VMD_ASPECT_RATIO_4x3; + siHdmiTx.Colorimetry = COLORIMETRY_709; + siHdmiTx.TclkSel = X1; + break; + default: + break; + } +} + +//------------------------------------------------------------------------------ +// Function Name: siHdmiTx_AudioSel() +// Function Description: Select output audio mode +// +// Accepts: Audio Fs +// Returns: none +// Globals: none +//------------------------------------------------------------------------------ +void siHdmiTx_AudioSel (byte Afs) +{ + siHdmiTx.AudioMode = AMODE_I2S; + siHdmiTx.AudioChannels = ACHANNEL_2CH; + siHdmiTx.AudioFs = Afs; + siHdmiTx.AudioWordLength = ALENGTH_16BITS; + siHdmiTx.AudioI2SFormat = (MCLK256FS << 4) |SCK_SAMPLE_RISING_EDGE |0x00; //last num 0x00-->0x02 +} + diff --git a/drivers/gpu/drm/smidrm/ddk750/siHdmiTx_902x_TPI.h b/drivers/gpu/drm/smidrm/ddk750/siHdmiTx_902x_TPI.h new file mode 100644 index 000000000000..8fb3427b4c2b --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/siHdmiTx_902x_TPI.h @@ -0,0 +1,1131 @@ +/*************************************************************************** +* +* SIMG PART NUMBER -HDMI Transmitter Driver +* +* Copyright (C) (2011, Silicon Image) +* +* 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; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*****************************************************************************/ + + +#ifndef _SIHDMITX_902X_TPI_H_ +#define _SIHDMITX_902X_TPI_H_ + +/* smi added */ +#define SII9022A_I2C_ADDRESS 0x72 +#ifdef USE_HW_I2C +#define i2cWriteReg hwI2CWriteReg +#define i2cReadReg hwI2CReadReg +#else +#define i2cWriteReg swI2CWriteReg +#define i2cReadReg swI2CReadReg +#endif + +//-------------------------------------------------------------------- +// typedef +//-------------------------------------------------------------------- + +typedef unsigned char byte; +typedef unsigned short word; +typedef unsigned int dword; + +//-------------------------------------------------------------------- +// System Macro definition +//-------------------------------------------------------------------- +#define IIC_OK 0 + + +#define DEV_SUPPORT_EDID 0 +//#define DEV_SUPPORT_HDCP +//#define DEV_SUPPORT_CEC +//#define DEV_SUPPORT_3D + +#define CLOCK_EDGE_RISING +//#define CLOCK_EDGE_FALLING + +#define F_9022A_9334 +//#define HW_INT_ENABLE + + + +//-------------------------------------------------------------------- +// TPI Firmware Version +//-------------------------------------------------------------------- +static const char TPI_FW_VERSION[] = "TPI Firmware v6.6.3_APP v1.3"; + +// Generic Constants +//==================================================== +#define FALSE 0 +#define TRUE 1 + +#define OFF 0 +#define ON 1 + +#define LOW 0 +#define HIGH 1 + +#define DISABLE 0x00 +#define ENABLE 0xFF + + +#define MAX_V_DESCRIPTORS 20 +#define MAX_A_DESCRIPTORS 10 +#define MAX_SPEAKER_CONFIGURATIONS 4 +#define AUDIO_DESCR_SIZE 3 + +#define RGB 0 +#define YCBCR444 1 +#define YCBCR422_16BITS 2 +#define YCBCR422_8BITS 3 +#define XVYCC444 4 + +#define EXTERNAL_HSVSDE 0 +#define INTERNAL_DE 1 +#define EMBEDDED_SYNC 2 + +#define COLORIMETRY_601 0 +#define COLORIMETRY_709 1 + +//==================================================== +#define MCLK128FS 0 +#define MCLK256FS 1 +#define MCLK384FS 2 +#define MCLK512FS 3 +#define MCLK768FS 4 +#define MCLK1024FS 5 +#define MCLK1152FS 6 +#define MCLK192FS 7 + +#define SCK_SAMPLE_FALLING_EDGE 0x00 +#define SCK_SAMPLE_RISING_EDGE 0x80 + +//==================================================== +// Video mode define +#define HDMI_480I60_4X3 1 +#define HDMI_576I50_4X3 2 +#define HDMI_480P60_4X3 3 +#define HDMI_576P50_4X3 4 +#define HDMI_720P60 5 +#define HDMI_720P50 6 +#define HDMI_1080I60 7 +#define HDMI_1080I50 8 +#define HDMI_1080P60 9 +#define HDMI_1080P50 10 +#define HDMI_1024_768_60 11 +#define HDMI_800_600_60 12 + + + + + +//==================================================== +#define AMODE_I2S 0 +#define AMODE_SPDIF 1 +#define AMODE_HBR 2 +#define AMODE_DSD 3 + +#define ACHANNEL_2CH 1 +#define ACHANNEL_3CH 2 +#define ACHANNEL_4CH 3 +#define ACHANNEL_5CH 4 +#define ACHANNEL_6CH 5 +#define ACHANNEL_7CH 6 +#define ACHANNEL_8CH 7 + +#define AFS_44K1 0x00 +#define AFS_48K 0x02 +#define AFS_32K 0x03 +#define AFS_88K2 0x08 +#define AFS_768K 0x09 +#define AFS_96K 0x0a +#define AFS_176K4 0x0c +#define AFS_192K 0x0e + +#define ALENGTH_16BITS 0x02 +#define ALENGTH_17BITS 0x0c +#define ALENGTH_18BITS 0x04 +#define ALENGTH_19BITS 0x08 +#define ALENGTH_20BITS 0x0a +#define ALENGTH_21BITS 0x0d +#define ALENGTH_22BITS 0x05 +#define ALENGTH_23BITS 0x09 +#define ALENGTH_24BITS 0x0b + +//==================================================== +typedef struct +{ + byte HDMIVideoFormat; // 0 = CEA-861 VIC; 1 = HDMI_VIC; 2 = 3D + byte VIC; // VIC or the HDMI_VIC + byte AspectRatio; // 4x3 or 16x9 + byte ColorSpace; // 0 = RGB; 1 = YCbCr4:4:4; 2 = YCbCr4:2:2_16bits; 3 = YCbCr4:2:2_8bits; 4 = xvYCC4:4:4 + byte ColorDepth; // 0 = 8bits; 1 = 10bits; 2 = 12bits + byte Colorimetry; // 0 = 601; 1 = 709 + byte SyncMode; // 0 = external HS/VS/DE; 1 = external HS/VS and internal DE; 2 = embedded sync + byte TclkSel; // 0 = x0.5CLK; 1 = x1CLK; 2 = x2CLK; 3 = x4CLK + byte ThreeDStructure; // Valid when (HDMIVideoFormat == VMD_HDMIFORMAT_3D) + byte ThreeDExtData; // Valid when (HDMIVideoFormat == VMD_HDMIFORMAT_3D) && (ThreeDStructure == VMD_3D_SIDEBYSIDEHALF) + + byte AudioMode; // 0 = I2S; 1 = S/PDIF; 2 = HBR; 3 = DSD; + byte AudioChannels; // 1 = 2chs; 2 = 3chs; 3 = 4chs; 4 = 5chs; 5 = 6chs; 6 = 7chs; 7 = 8chs; + byte AudioFs; // 0-44.1kHz; 2-48kHz; 3-32kHz; 8-88.2kHz; 9-768kHz; A-96kHz; C-176.4kHz; E-192kHz; 1/4/5/6/7/B/D/F-not indicated + byte AudioWordLength; // 0/1-not available; 2-16 bit; 4-18 bit; 8-19 bit; A-20 bit; C-17 bit; 5-22 bit; 9-23 bit; B-24 bit; D-21 bit + byte AudioI2SFormat; // Please refer to TPI reg0x20 for detailed. + //[7]_SCK Sample Edge: 0 = Falling; 1 = Rising + //[6:4]_MCLK Multiplier: 000:MCLK=128Fs; 001:MCLK=256Fs; 010:MCLK=384Fs; 011:MCLK=512Fs; 100:MCLK=768Fs; 101:MCLK=1024Fs; 110:MCLK=1152Fs; 111:MCLK=192Fs; + //[3]_WS Polarity-Left when: 0 = WS is low when Left; 1 = WS is high when Left + //[2]_SD Justify Data is justified: 0 = Left; 1 = Right + //[1]_SD Direction Byte shifted first: 0 = MSB; 1 = LSB + //[0]_WS to SD First Bit Shift: 0 = Yes; 1 = No + +}SIHDMITX_CONFIG; + +//==================================================== +typedef struct +{ + byte txPowerState; + byte tmdsPoweredUp; + byte hdmiCableConnected; + byte dsRxPoweredUp; + +}GLOBAL_SYSTEM; + +//==================================================== +typedef struct +{ + byte HDCP_TxSupports; + byte HDCP_AksvValid; + byte HDCP_Started; + byte HDCP_LinkProtectionLevel; + byte HDCP_Override; + byte HDCPAuthenticated; + +}GLOBAL_HDCP; + +//==================================================== +typedef struct +{ // for storing EDID parsed data + byte edidDataValid; + byte VideoDescriptor[MAX_V_DESCRIPTORS]; // maximum number of video descriptors + byte AudioDescriptor[MAX_A_DESCRIPTORS][3]; // maximum number of audio descriptors + byte SpkrAlloc[MAX_SPEAKER_CONFIGURATIONS]; // maximum number of speaker configurations + byte UnderScan; // "1" if DTV monitor underscans IT video formats by default + byte BasicAudio; // Sink supports Basic Audio + byte YCbCr_4_4_4; // Sink supports YCbCr 4:4:4 + byte YCbCr_4_2_2; // Sink supports YCbCr 4:2:2 + byte HDMI_Sink; // "1" if HDMI signature found + byte CEC_A_B; // CEC Physical address. See HDMI 1.3 Table 8-6 + byte CEC_C_D; + byte ColorimetrySupportFlags; // IEC 61966-2-4 colorimetry support: 1 - xvYCC601; 2 - xvYCC709 + byte MetadataProfile; + byte _3D_Supported; + +} GLOBAL_EDID; + +enum EDID_ErrorCodes +{ + 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 +}; + + +#ifdef DEV_SUPPORT_EDID +#define IsHDMI_Sink() (g_edid.HDMI_Sink) +#define IsCEC_DEVICE() (((g_edid.CEC_A_B != 0xFF) && (g_edid.CEC_C_D != 0xFF)) ? TRUE : FALSE) + +#else +#define IsHDMI_Sink() (TRUE) +#define IsCEC_DEVICE() (FALSE) +#endif + + + +//-------------------------------------------------------------------- +// Debug Definitions +//-------------------------------------------------------------------- +// Compile debug prints inline or not +#define CONF__TPI_TRACE_PRINT (DISABLE) +#define CONF__TPI_DEBUG_PRINT (DISABLE) +#define CONF__TPI_EDID_PRINT (DISABLE) +#define CONF__CPI_DEBUG_PRINT (DISABLE) + + +// Trace Print Macro +// Note: TPI_TRACE_PRINT Requires double parenthesis +// Example: TPI_TRACE_PRINT(("hello, world!\n")); +#if (CONF__TPI_TRACE_PRINT == ENABLE) + #define TPI_TRACE_PRINT(x) printk x; +#else + #define TPI_TRACE_PRINT(x) +#endif + +// Debug Print Macro +// Note: TPI_DEBUG_PRINT Requires double parenthesis +// Example: TPI_DEBUG_PRINT(("hello, world!\n")); +#if (CONF__TPI_DEBUG_PRINT == ENABLE) + #define TPI_DEBUG_PRINT(x) printk x; +#else + #define TPI_DEBUG_PRINT(x) +#endif + +// EDID Print Macro +// Note: To enable EDID description printing, both CONF__TPI_EDID_PRINT and CONF__TPI_DEBUG_PRINT must be enabled +// Note: TPI_EDID_PRINT Requires double parenthesis +// Example: TPI_EDID_PRINT(("hello, world!\n")); +#if (CONF__TPI_EDID_PRINT == ENABLE) + #define TPI_EDID_PRINT(x) TPI_DEBUG_PRINT(x) +#else + #define TPI_EDID_PRINT(x) +#endif + +// CPI Debug Print Macro +// Note: To enable CPI description printing, both CONF__CPI_DEBUG_PRINT and CONF__TPI_DEBUG_PRINT must be enabled +// Note: CPI_DEBUG_PRINT Requires double parenthesis +// Example: CPI_DEBUG_PRINT(("hello, world!\n")); +#if (CONF__CPI_DEBUG_PRINT == ENABLE) + #define CPI_DEBUG_PRINT(x) TPI_DEBUG_PRINT(x) +#else + #define CPI_DEBUG_PRINT(x) +#endif + + + +enum AV_ConfigErrorCodes +{ + DE_CANNOT_BE_SET_WITH_EMBEDDED_SYNC, + V_MODE_NOT_SUPPORTED, + SET_EMBEDDED_SYC_FAILURE, + I2S_MAPPING_SUCCESSFUL, + I2S_INPUT_CONFIG_SUCCESSFUL, + I2S_HEADER_SET_SUCCESSFUL, + EHDMI_ARC_SINGLE_SET_SUCCESSFUL, + EHDMI_ARC_COMMON_SET_SUCCESSFUL, + EHDMI_HEC_SET_SUCCESSFUL, + EHDMI_ARC_CM_WITH_HEC_SET_SUCCESSFUL, + AUD_MODE_NOT_SUPPORTED, + I2S_NOT_SET, + DE_SET_OK, + VIDEO_MODE_SET_OK, + AUDIO_MODE_SET_OK, + GBD_SET_SUCCESSFULLY, + DE_CANNOT_BE_SET_WITH_3D_MODE, +}; + + +#define ClearInterrupt(x) WriteByteTPI(TPI_INTERRUPT_STATUS_REG, x) // write "1" to clear interrupt bit + +// Generic Masks +//==================================================== +#define LOW_BYTE 0x00FF + +#define LOW_NIBBLE 0x0F +#define HI_NIBBLE 0xF0 + +#define MSBIT 0x80 +#define LSBIT 0x01 + +#define BIT_0 0x01 +#define BIT_1 0x02 +#define BIT_2 0x04 +#define BIT_3 0x08 +#define BIT_4 0x10 +#define BIT_5 0x20 +#define BIT_6 0x40 +#define BIT_7 0x80 + +#define TWO_LSBITS 0x03 +#define THREE_LSBITS 0x07 +#define FOUR_LSBITS 0x0F +#define FIVE_LSBITS 0x1F +#define SEVEN_LSBITS 0x7F +#define TWO_MSBITS 0xC0 +#define EIGHT_BITS 0xFF +#define BYTE_SIZE 0x08 +#define BITS_1_0 0x03 +#define BITS_2_1 0x06 +#define BITS_2_1_0 0x07 +#define BITS_3_2 0x0C +#define BITS_4_3_2 0x1C +#define BITS_5_4 0x30 +#define BITS_5_4_3 0x38 +#define BITS_6_5 0x60 +#define BITS_6_5_4 0x70 +#define BITS_7_6 0xC0 + +#define TPI_INTERNAL_PAGE_REG 0xBC +#define TPI_INDEXED_OFFSET_REG 0xBD +#define TPI_INDEXED_VALUE_REG 0xBE + +// Interrupt Masks +//==================================================== +#define HOT_PLUG_EVENT 0x01 +#define RX_SENSE_EVENT 0x02 +#define HOT_PLUG_STATE 0x04 +#define RX_SENSE_STATE 0x08 + +#define AUDIO_ERROR_EVENT 0x10 +#define SECURITY_CHANGE_EVENT 0x20 +#define V_READY_EVENT 0x40 +#define HDCP_CHANGE_EVENT 0x80 + +#define NON_MASKABLE_INT 0xFF + +// TPI Control Masks +//==================================================== + +#define CS_HDMI_RGB 0x00 +#define CS_DVI_RGB 0x03 + +#define ENABLE_AND_REPEAT 0xC0 +#define EN_AND_RPT_MPEG 0xC3 +#define DISABLE_MPEG 0x03 // Also Vendor Specific InfoFrames + +// Pixel Repetition Masks +//==================================================== +#define BIT_BUS_24 0x20 +#define BIT_BUS_12 0x00 + +#define BIT_EDGE_RISE 0x10 + +//Audio Maps +//==================================================== +#define BIT_AUDIO_MUTE 0x10 + +// Input/Output Format Masks +//==================================================== +#define BITS_IN_RGB 0x00 +#define BITS_IN_YCBCR444 0x01 +#define BITS_IN_YCBCR422 0x02 + +#define BITS_IN_AUTO_RANGE 0x00 +#define BITS_IN_FULL_RANGE 0x04 +#define BITS_IN_LTD_RANGE 0x08 + +#define BIT_EN_DITHER_10_8 0x40 +#define BIT_EXTENDED_MODE 0x80 + +#define BITS_OUT_RGB 0x00 +#define BITS_OUT_YCBCR444 0x01 +#define BITS_OUT_YCBCR422 0x02 + +#define BITS_OUT_AUTO_RANGE 0x00 +#define BITS_OUT_FULL_RANGE 0x04 +#define BITS_OUT_LTD_RANGE 0x08 + +#define BIT_BT_709 0x10 + + +// DE Generator Masks +//==================================================== +#define BIT_EN_DE_GEN 0x40 +#define DE 0x00 +#define DeDataNumBytes 12 + +// Embedded Sync Masks +//==================================================== +#define BIT_EN_SYNC_EXTRACT 0x40 +#define EMB 0x80 +#define EmbDataNumBytes 8 + + +// Audio Modes +//==================================================== +#define AUD_PASS_BASIC 0x00 +#define AUD_PASS_ALL 0x01 +#define AUD_DOWN_SAMPLE 0x02 +#define AUD_DO_NOT_CHECK 0x03 + +#define REFER_TO_STREAM_HDR 0x00 +#define TWO_CHANNELS 0x00 +#define EIGHT_CHANNELS 0x01 +#define AUD_IF_SPDIF 0x40 +#define AUD_IF_I2S 0x80 +#define AUD_IF_DSD 0xC0 +#define AUD_IF_HBR 0x04 + +#define TWO_CHANNEL_LAYOUT 0x00 +#define EIGHT_CHANNEL_LAYOUT 0x20 + + +// I2C Slave Addresses +//==================================================== +#define TX_SLAVE_ADDR 0x72 +#define CBUS_SLAVE_ADDR 0xC8 +#define HDCP_SLAVE_ADDR 0x74 +#define EDID_ROM_ADDR 0xA0 +#define EDID_SEG_ADDR 0x60 + +// Indexed Register Offsets, Constants +//==================================================== +#define INDEXED_PAGE_0 0x01 +#define INDEXED_PAGE_1 0x02 +#define INDEXED_PAGE_2 0x03 + +#define TMDS_CONT_REG 0x82 + +// DDC Bus Addresses +//==================================================== +#define DDC_BSTATUS_ADDR_L 0x41 +#define DDC_BSTATUS_ADDR_H 0x42 +#define DDC_KSV_FIFO_ADDR 0x43 +#define KSV_ARRAY_SIZE 128 + +// DDC Bus Bit Masks +//==================================================== +#define BIT_DDC_HDMI 0x80 +#define BIT_DDC_REPEATER 0x40 +#define BIT_DDC_FIFO_RDY 0x20 +#define DEVICE_COUNT_MASK 0x7F + +// KSV Buffer Size +//==================================================== +#define DEVICE_COUNT 128 // May be tweaked as needed + +// InfoFrames +//==================================================== +#define SIZE_AVI_INFOFRAME 0x0E // including checksum byte +#define BITS_OUT_FORMAT 0x60 // Y1Y0 field + +#define _4_To_3 0x10 // Aspect ratio - 4:3 in InfoFrame DByte 1 +#define _16_To_9 0x20 // Aspect ratio - 16:9 in InfoFrame DByte 1 +#define SAME_AS_AR 0x08 // R3R2R1R0 - in AVI InfoFrame DByte 2 + +#define BT_601 0x40 +#define BT_709 0x80 + +//#define EN_AUDIO_INFOFRAMES 0xC2 +#define TYPE_AUDIO_INFOFRAMES 0x84 +#define AUDIO_INFOFRAMES_VERSION 0x01 +#define AUDIO_INFOFRAMES_LENGTH 0x0A + +#define TYPE_GBD_INFOFRAME 0x0A + +#define ENABLE_AND_REPEAT 0xC0 + +#define EN_AND_RPT_MPEG 0xC3 +#define DISABLE_MPEG 0x03 // Also Vendor Specific InfoFrames + +#define EN_AND_RPT_AUDIO 0xC2 +#define DISABLE_AUDIO 0x02 + +#define EN_AND_RPT_AVI 0xC0 // Not normally used. Write to TPI 0x19 instead +#define DISABLE_AVI 0x00 // But this is used to Disable + +#define NEXT_FIELD 0x80 +#define GBD_PROFILE 0x00 +#define AFFECTED_GAMUT_SEQ_NUM 0x01 + +#define ONLY_PACKET 0x30 +#define CURRENT_GAMUT_SEQ_NUM 0x01 + +// FPLL Multipliers: +//==================================================== + +#define X0d5 0x00 +#define X1 0x01 +#define X2 0x02 +#define X4 0x03 + +// 3D Constants +//==================================================== + +#define _3D_STRUC_PRESENT 0x02 + +// 3D_Stucture Constants +//==================================================== +#define FRAME_PACKING 0x00 +#define FIELD_ALTERNATIVE 0x01 +#define LINE_ALTERNATIVE 0x02 +#define SIDE_BY_SIDE_FULL 0x03 +#define L_PLUS_DEPTH 0x04 +#define L_PLUS_DEPTH_PLUS_GRAPHICS 0x05 +#define SIDE_BY_SIDE_HALF 0x08 + +// 3D_Ext_Data Constants +//==================================================== +#define HORIZ_ODD_LEFT_ODD_RIGHT 0x00 +#define HORIZ_ODD_LEFT_EVEN_RIGHT 0x01 +#define HORIZ_EVEN_LEFT_ODD_RIGHT 0x02 +#define HORIZ_EVEN_LEFT_EVEN_RIGHT 0x03 + +#define QUINCUNX_ODD_LEFT_EVEN_RIGHT 0x04 +#define QUINCUNX_ODD_LEFT_ODD_RIGHT 0x05 +#define QUINCUNX_EVEN_LEFT_ODD_RIGHT 0x06 +#define QUINCUNX_EVEN_LEFT_EVEN_RIGHT 0x07 + +#define NO_3D_SUPPORT 0x0F + +// InfoFrame Type Code +//==================================================== +#define AVI 0x00 +#define SPD 0x01 +#define AUDIO 0x02 +#define MPEG 0x03 +#define GEN_1 0x04 +#define GEN_2 0x05 +#define HDMI_VISF 0x06 +#define GBD 0x07 + +// Size of InfoFrame Data types +#define MAX_SIZE_INFOFRAME_DATA 0x22 +#define SIZE_AVI_INFOFRAME 0x0E // 14 bytes +#define SIZE_SPD_INFOFRAME 0x19 // 25 bytes +#define SISE_AUDIO_INFOFRAME_IFORM 0x0A // 10 bytes +#define SIZE_AUDIO_INFOFRAME 0x0F // 15 bytes +#define SIZE_MPRG_HDMI_INFOFRAME 0x1B // 27 bytes +#define SIZE_MPEG_INFOFRAME 0x0A // 10 bytes +#define SIZE_GEN_1_INFOFRAME 0x1F // 31 bytes +#define SIZE_GEN_2_INFOFRAME 0x1F // 31 bytes +#define SIZE_HDMI_VISF_INFOFRAME 0x1E // 31 bytes +#define SIZE_GBD_INFOFRAME 0x1C // 28 bytes + +#define AVI_INFOFRM_OFFSET 0x0C +#define OTHER_INFOFRM_OFFSET 0xC4 +#define TPI_INFOFRAME_ACCESS_REG 0xBF + +// Serial Communication Buffer constants +#define MAX_COMMAND_ARGUMENTS 50 +#define GLOBAL_BYTE_BUF_BLOCK_SIZE 131 + + +// Video Mode Constants +//==================================================== +#define VMD_ASPECT_RATIO_4x3 0x01 +#define VMD_ASPECT_RATIO_16x9 0x02 + +#define VMD_COLOR_SPACE_RGB 0x00 +#define VMD_COLOR_SPACE_YCBCR422 0x01 +#define VMD_COLOR_SPACE_YCBCR444 0x02 + +#define VMD_COLOR_DEPTH_8BIT 0x00 +#define VMD_COLOR_DEPTH_10BIT 0x01 +#define VMD_COLOR_DEPTH_12BIT 0x02 +#define VMD_COLOR_DEPTH_16BIT 0x03 + +#define VMD_HDCP_NOT_AUTHENTICATED 0x00 +#define VMD_HDCP_AUTHENTICATED 0x01 + +#define VMD_HDMIFORMAT_CEA_VIC 0x00 +#define VMD_HDMIFORMAT_HDMI_VIC 0x01 +#define VMD_HDMIFORMAT_3D 0x02 +#define VMD_HDMIFORMAT_PC 0x03 + +// These values are from HDMI Spec 1.4 Table H-2 +#define VMD_3D_FRAMEPACKING 0 +#define VMD_3D_FIELDALTERNATIVE 1 +#define VMD_3D_LINEALTERNATIVE 2 +#define VMD_3D_SIDEBYSIDEFULL 3 +#define VMD_3D_LDEPTH 4 +#define VMD_3D_LDEPTHGRAPHICS 5 +#define VMD_3D_SIDEBYSIDEHALF 8 + + +//-------------------------------------------------------------------- +// System Macro Definitions +//-------------------------------------------------------------------- +#define TX_HW_RESET_PERIOD 200 +#define SII902XA_DEVICE_ID 0xB0 + +#define T_HPD_DELAY 10 + +//-------------------------------------------------------------------- +// HDCP Macro Definitions +//-------------------------------------------------------------------- +#define AKSV_SIZE 5 +#define NUM_OF_ONES_IN_KSV 20 + +//-------------------------------------------------------------------- +// EDID Constants Definition +//-------------------------------------------------------------------- +#define EDID_BLOCK_0_OFFSET 0x00 +#define EDID_BLOCK_1_OFFSET 0x80 + +#define EDID_BLOCK_SIZE 128 +#define EDID_HDR_NO_OF_FF 0x06 +#define NUM_OF_EXTEN_ADDR 0x7E + +#define EDID_TAG_ADDR 0x00 +#define EDID_REV_ADDR 0x01 +#define EDID_TAG_IDX 0x02 +#define LONG_DESCR_PTR_IDX 0x02 +#define MISC_SUPPORT_IDX 0x03 + +#define ESTABLISHED_TIMING_INDEX 35 // Offset of Established Timing in EDID block +#define NUM_OF_STANDARD_TIMINGS 8 +#define STANDARD_TIMING_OFFSET 38 +#define LONG_DESCR_LEN 18 +#define NUM_OF_DETAILED_DESCRIPTORS 4 + +#define DETAILED_TIMING_OFFSET 0x36 + +// Offsets within a Long Descriptors Block +//==================================================== +#define PIX_CLK_OFFSET 0 +#define H_ACTIVE_OFFSET 2 +#define H_BLANKING_OFFSET 3 +#define V_ACTIVE_OFFSET 5 +#define V_BLANKING_OFFSET 6 +#define H_SYNC_OFFSET 8 +#define H_SYNC_PW_OFFSET 9 +#define V_SYNC_OFFSET 10 +#define V_SYNC_PW_OFFSET 10 +#define H_IMAGE_SIZE_OFFSET 12 +#define V_IMAGE_SIZE_OFFSET 13 +#define H_BORDER_OFFSET 15 +#define V_BORDER_OFFSET 16 +#define FLAGS_OFFSET 17 + +#define AR16_10 0 +#define AR4_3 1 +#define AR5_4 2 +#define AR16_9 3 + +// Data Block Tag Codes +//==================================================== +#define AUDIO_D_BLOCK 0x01 +#define VIDEO_D_BLOCK 0x02 +#define VENDOR_SPEC_D_BLOCK 0x03 +#define SPKR_ALLOC_D_BLOCK 0x04 +#define USE_EXTENDED_TAG 0x07 + +// Extended Data Block Tag Codes +//==================================================== +#define COLORIMETRY_D_BLOCK 0x05 + +#define HDMI_SIGNATURE_LEN 0x03 + +#define CEC_PHYS_ADDR_LEN 0x02 +#define EDID_EXTENSION_TAG 0x02 +#define EDID_REV_THREE 0x03 +#define EDID_DATA_START 0x04 + +#define EDID_BLOCK_0 0x00 +#define EDID_BLOCK_2_3 0x01 + +#define VIDEO_CAPABILITY_D_BLOCK 0x00 + + + + + +//-------------------------------------------------------------------- +// TPI Register Definition +//-------------------------------------------------------------------- + +// TPI Video Mode Data +#define TPI_PIX_CLK_LSB (0x00) +#define TPI_PIX_CLK_MSB (0x01) +#define TPI_VERT_FREQ_LSB (0x02) +#define TPI_VERT_FREQ_MSB (0x03) +#define TPI_TOTAL_PIX_LSB (0x04) +#define TPI_TOTAL_PIX_MSB (0x05) +#define TPI_TOTAL_LINES_LSB (0x06) +#define TPI_TOTAL_LINES_MSB (0x07) + +// Pixel Repetition Data +#define TPI_PIX_REPETITION (0x08) + +// TPI AVI Input and Output Format Data +/// AVI Input Format Data +#define TPI_INPUT_FORMAT_REG (0x09) +#define INPUT_COLOR_SPACE_MASK (BIT_1 | BIT_0) +#define INPUT_COLOR_SPACE_RGB (0x00) +#define INPUT_COLOR_SPACE_YCBCR444 (0x01) +#define INPUT_COLOR_SPACE_YCBCR422 (0x02) +#define INPUT_COLOR_SPACE_BLACK_MODE (0x03) + +/// AVI Output Format Data +#define TPI_OUTPUT_FORMAT_REG (0x0A) +#define TPI_YC_Input_Mode (0x0B) + +// TPI InfoFrame related constants +#define TPI_AVI_INFO_REG_ADDR (0x0C) // AVI InfoFrame Checksum +#define TPI_OTHER_INFO_REG_ADDR (0xBF) +#define TPI_INFO_FRAME_REG_OFFSET (0xC4) + +// TPI AVI InfoFrame Data +#define TPI_AVI_BYTE_0 (0x0C) +#define TPI_AVI_BYTE_1 (0x0D) +#define TPI_AVI_BYTE_2 (0x0E) +#define TPI_AVI_BYTE_3 (0x0F) +#define TPI_AVI_BYTE_4 (0x10) +#define TPI_AVI_BYTE_5 (0x11) + +#define TPI_INFO_FRM_DBYTE5 (0xC8) +#define TPI_INFO_FRM_DBYTE6 (0xC9) + +#define TPI_END_TOP_BAR_LSB (0x12) +#define TPI_END_TOP_BAR_MSB (0x13) + +#define TPI_START_BTM_BAR_LSB (0x14) +#define TPI_START_BTM_BAR_MSB (0x15) + +#define TPI_END_LEFT_BAR_LSB (0x16) +#define TPI_END_LEFT_BAR_MSB (0x17) + +#define TPI_END_RIGHT_BAR_LSB (0x18) +#define TPI_END_RIGHT_BAR_MSB (0x19) + +// Colorimetry +#define SET_EX_COLORIMETRY (0x0C) // Set TPI_AVI_BYTE_2 to extended colorimetry and use + //TPI_AVI_BYTE_3 + +#define TPI_SYSTEM_CONTROL_DATA_REG (0x1A) + +#define LINK_INTEGRITY_MODE_MASK (BIT_6) +#define LINK_INTEGRITY_STATIC (0x00) +#define LINK_INTEGRITY_DYNAMIC (0x40) + +#define TMDS_OUTPUT_CONTROL_MASK (BIT_4) +#define TMDS_OUTPUT_CONTROL_ACTIVE (0x00) +#define TMDS_OUTPUT_CONTROL_POWER_DOWN (0x10) + +#define AV_MUTE_MASK (BIT_3) +#define AV_MUTE_NORMAL (0x00) +#define AV_MUTE_MUTED (0x08) + +#define DDC_BUS_REQUEST_MASK (BIT_2) +#define DDC_BUS_REQUEST_NOT_USING (0x00) +#define DDC_BUS_REQUEST_REQUESTED (0x04) + +#define DDC_BUS_GRANT_MASK (BIT_1) +#define DDC_BUS_GRANT_NOT_AVAILABLE (0x00) +#define DDC_BUS_GRANT_GRANTED (0x02) + +#define OUTPUT_MODE_MASK (BIT_0) +#define OUTPUT_MODE_DVI (0x00) +#define OUTPUT_MODE_HDMI (0x01) + +// TPI Identification Registers +#define TPI_DEVICE_ID (0x1B) +#define TPI_DEVICE_REV_ID (0x1C) + +#define TPI_RESERVED2 (0x1D) + +#define TPI_DEVICE_POWER_STATE_CTRL_REG (0x1E) + +#define CTRL_PIN_CONTROL_MASK (BIT_4) +#define CTRL_PIN_TRISTATE (0x00) +#define CTRL_PIN_DRIVEN_TX_BRIDGE (0x10) + +#define TX_POWER_STATE_MASK (BIT_1 | BIT_0) +#define TX_POWER_STATE_D0 (0x00) +#define TX_POWER_STATE_D1 (0x01) +#define TX_POWER_STATE_D2 (0x02) +#define TX_POWER_STATE_D3 (0x03) + +// Configuration of I2S Interface +#define TPI_I2S_EN (0x1F) +#define TPI_I2S_IN_CFG (0x20) +#define SCK_SAMPLE_EDGE (BIT_7) + +// Available only when TPI 0x26[7:6]=10 to select I2S input +#define TPI_I2S_CHST_0 (0x21) +#define TPI_I2S_CHST_1 (0x22) +#define TPI_I2S_CHST_2 (0x23) +#define TPI_I2S_CHST_3 (0x24) +#define TPI_I2S_CHST_4 (0x25) + +#define AUDIO_INPUT_LENGTH (0x24) + +// Available only when 0x26[7:6]=01 +#define TPI_SPDIF_HEADER (0x24) +#define TPI_AUDIO_HANDLING (0x25) + +// Audio Configuration Regiaters +#define TPI_AUDIO_INTERFACE_REG (0x26) +#define AUDIO_MUTE_MASK (BIT_4) +#define AUDIO_MUTE_NORMAL (0x00) +#define AUDIO_MUTE_MUTED (0x10) + +#define AUDIO_SEL_MASK (BITS_7_6) + + +#define TPI_AUDIO_SAMPLE_CTRL (0x27) +#define TPI_SPEAKER_CFG (0xC7) +#define TPI_CODING_TYPE_CHANNEL_COUNT (0xC4) + +//-------------------------------------------------------------------- +// HDCP Implementation +// HDCP link security logic is implemented in certain transmitters; unique +// keys are embedded in each chip as part of the solution. The security +// scheme is fully automatic and handled completely by the hardware. +//-------------------------------------------------------------------- + +/// HDCP Query Data Register +#define TPI_HDCP_QUERY_DATA_REG (0x29) + +#define EXTENDED_LINK_PROTECTION_MASK (BIT_7) +#define EXTENDED_LINK_PROTECTION_NONE (0x00) +#define EXTENDED_LINK_PROTECTION_SECURE (0x80) + +#define LOCAL_LINK_PROTECTION_MASK (BIT_6) +#define LOCAL_LINK_PROTECTION_NONE (0x00) +#define LOCAL_LINK_PROTECTION_SECURE (0x40) + +#define LINK_STATUS_MASK (BIT_5 | BIT_4) +#define LINK_STATUS_NORMAL (0x00) +#define LINK_STATUS_LINK_LOST (0x10) +#define LINK_STATUS_RENEGOTIATION_REQ (0x20) +#define LINK_STATUS_LINK_SUSPENDED (0x30) + +#define HDCP_REPEATER_MASK (BIT_3) +#define HDCP_REPEATER_NO (0x00) +#define HDCP_REPEATER_YES (0x08) + +#define CONNECTOR_TYPE_MASK (BIT_2 | BIT_0) +#define CONNECTOR_TYPE_DVI (0x00) +#define CONNECTOR_TYPE_RSVD (0x01) +#define CONNECTOR_TYPE_HDMI (0x04) +#define CONNECTOR_TYPE_FUTURE (0x05) + +#define PROTECTION_TYPE_MASK (BIT_1) +#define PROTECTION_TYPE_NONE (0x00) +#define PROTECTION_TYPE_HDCP (0x02) + +/// HDCP Control Data Register +#define TPI_HDCP_CONTROL_DATA_REG (0x2A) +#define PROTECTION_LEVEL_MASK (BIT_0) +#define PROTECTION_LEVEL_MIN (0x00) +#define PROTECTION_LEVEL_MAX (0x01) + +#define KSV_FORWARD_MASK (BIT_4) +#define KSV_FORWARD_ENABLE (0x10) +#define KSV_FORWARD_DISABLE (0x00) + +/// HDCP BKSV Registers +#define TPI_BKSV_1_REG (0x2B) +#define TPI_BKSV_2_REG (0x2C) +#define TPI_BKSV_3_REG (0x2D) +#define TPI_BKSV_4_REG (0x2E) +#define TPI_BKSV_5_REG (0x2F) + +/// HDCP Revision Data Register +#define TPI_HDCP_REVISION_DATA_REG (0x30) + +#define HDCP_MAJOR_REVISION_MASK (BIT_7 | BIT_6 | BIT_5 | BIT_4) +#define HDCP_MAJOR_REVISION_VALUE (0x10) + +#define HDCP_MINOR_REVISION_MASK (BIT_3 | BIT_2 | BIT_1 | BIT_0) +#define HDCP_MINOR_REVISION_VALUE (0x02) + +/// HDCP KSV and V' Value Data Register +#define TPI_V_PRIME_SELECTOR_REG (0x31) + +/// V' Value Readback Registers +#define TPI_V_PRIME_7_0_REG (0x32) +#define TPI_V_PRIME_15_9_REG (0x33) +#define TPI_V_PRIME_23_16_REG (0x34) +#define TPI_V_PRIME_31_24_REG (0x35) + +/// HDCP AKSV Registers +#define TPI_AKSV_1_REG (0x36) +#define TPI_AKSV_2_REG (0x37) +#define TPI_AKSV_3_REG (0x38) +#define TPI_AKSV_4_REG (0x39) +#define TPI_AKSV_5_REG (0x3A) + +#define TPI_DEEP_COLOR_GCP (0x40) + +//-------------------------------------------------------------------- +// Interrupt Service +// TPI can be configured to generate an interrupt to the host to notify it of +// various events. The host can either poll for activity or use an interrupt +// handler routine. TPI generates on a single interrupt (INT) to the host. +//-------------------------------------------------------------------- + +/// Interrupt Enable Register +#define TPI_INTERRUPT_ENABLE_REG (0x3C) + +#define HDCP_AUTH_STATUS_CHANGE_EN_MASK (BIT_7) +#define HDCP_AUTH_STATUS_CHANGE_DISABLE (0x00) +#define HDCP_AUTH_STATUS_CHANGE_ENABLE (0x80) + +#define HDCP_VPRIME_VALUE_READY_EN_MASK (BIT_6) +#define HDCP_VPRIME_VALUE_READY_DISABLE (0x00) +#define HDCP_VPRIME_VALUE_READY_ENABLE (0x40) + +#define HDCP_SECURITY_CHANGE_EN_MASK (BIT_5) +#define HDCP_SECURITY_CHANGE_DISABLE (0x00) +#define HDCP_SECURITY_CHANGE_ENABLE (0x20) + +#define AUDIO_ERROR_EVENT_EN_MASK (BIT_4) +#define AUDIO_ERROR_EVENT_DISABLE (0x00) +#define AUDIO_ERROR_EVENT_ENABLE (0x10) + +#define CPI_EVENT_NO_RX_SENSE_MASK (BIT_3) +#define CPI_EVENT_NO_RX_SENSE_DISABLE (0x00) +#define CPI_EVENT_NO_RX_SENSE_ENABLE (0x08) + +#define RECEIVER_SENSE_EVENT_EN_MASK (BIT_1) +#define RECEIVER_SENSE_EVENT_DISABLE (0x00) +#define RECEIVER_SENSE_EVENT_ENABLE (0x02) + +#define HOT_PLUG_EVENT_EN_MASK (BIT_0) +#define HOT_PLUG_EVENT_DISABLE (0x00) +#define HOT_PLUG_EVENT_ENABLE (0x01) + +/// Interrupt Status Register +#define TPI_INTERRUPT_STATUS_REG (0x3D) + +#define HDCP_AUTH_STATUS_CHANGE_EVENT_MASK (BIT_7) +#define HDCP_AUTH_STATUS_CHANGE_EVENT_NO (0x00) +#define HDCP_AUTH_STATUS_CHANGE_EVENT_YES (0x80) + +#define HDCP_VPRIME_VALUE_READY_EVENT_MASK (BIT_6) +#define HDCP_VPRIME_VALUE_READY_EVENT_NO (0x00) +#define HDCP_VPRIME_VALUE_READY_EVENT_YES (0x40) + +#define HDCP_SECURITY_CHANGE_EVENT_MASK (BIT_5) +#define HDCP_SECURITY_CHANGE_EVENT_NO (0x00) +#define HDCP_SECURITY_CHANGE_EVENT_YES (0x20) + +#define AUDIO_ERROR_EVENT_MASK (BIT_4) +#define AUDIO_ERROR_EVENT_NO (0x00) +#define AUDIO_ERROR_EVENT_YES (0x10) + +#define CPI_EVENT_MASK (BIT_3) +#define CPI_EVENT_NO (0x00) +#define CPI_EVENT_YES (0x08) +#define RX_SENSE_MASK (BIT_3) // This bit is dual purpose depending on the value of 0x3C[3] +#define RX_SENSE_NOT_ATTACHED (0x00) +#define RX_SENSE_ATTACHED (0x08) + +#define HOT_PLUG_PIN_STATE_MASK (BIT_2) +#define HOT_PLUG_PIN_STATE_LOW (0x00) +#define HOT_PLUG_PIN_STATE_HIGH (0x04) + +#define RECEIVER_SENSE_EVENT_MASK (BIT_1) +#define RECEIVER_SENSE_EVENT_NO (0x00) +#define RECEIVER_SENSE_EVENT_YES (0x02) + +#define HOT_PLUG_EVENT_MASK (BIT_0) +#define HOT_PLUG_EVENT_NO (0x00) +#define HOT_PLUG_EVENT_YES (0x01) + +/// KSV FIFO First Status Register +#define TPI_KSV_FIFO_READY_INT (0x3E) + +#define KSV_FIFO_READY_MASK (BIT_1) +#define KSV_FIFO_READY_NO (0x00) +#define KSV_FIFO_READY_YES (0x02) + +#define TPI_KSV_FIFO_READY_INT_EN (0x3F) + +#define KSV_FIFO_READY_EN_MASK (BIT_1) +#define KSV_FIFO_READY_DISABLE (0x00) +#define KSV_FIFO_READY_ENABLE (0x02) + +/// KSV FIFO Last Status Register +#define TPI_KSV_FIFO_STATUS_REG (0x41) +#define TPI_KSV_FIFO_VALUE_REG (0x42) + +#define KSV_FIFO_LAST_MASK (BIT_7) +#define KSV_FIFO_LAST_NO (0x00) +#define KSV_FIFO_LAST_YES (0x80) + +#define KSV_FIFO_COUNT_MASK (BIT_4 | BIT_3 | BIT_2 | BIT_1 | BIT_0) + +// Sync Register Configuration and Sync Monitoring Registers +#define TPI_SYNC_GEN_CTRL (0x60) +#define TPI_SYNC_POLAR_DETECT (0x61) + +// Explicit Sync DE Generator Registers (TPI 0x60[7]=0) +#define TPI_DE_DLY (0x62) +#define TPI_DE_CTRL (0x63) +#define TPI_DE_TOP (0x64) + +#define TPI_RESERVED4 (0x65) + +#define TPI_DE_CNT_7_0 (0x66) +#define TPI_DE_CNT_11_8 (0x67) + +#define TPI_DE_LIN_7_0 (0x68) +#define TPI_DE_LIN_10_8 (0x69) + +#define TPI_DE_H_RES_7_0 (0x6A) +#define TPI_DE_H_RES_10_8 (0x6B) + +#define TPI_DE_V_RES_7_0 (0x6C) +#define TPI_DE_V_RES_10_8 (0x6D) + +// Embedded Sync Register Set (TPI 0x60[7]=1) +#define TPI_HBIT_TO_HSYNC_7_0 (0x62) +#define TPI_HBIT_TO_HSYNC_9_8 (0x63) +#define TPI_FIELD_2_OFFSET_7_0 (0x64) +#define TPI_FIELD_2_OFFSET_11_8 (0x65) +#define TPI_HWIDTH_7_0 (0x66) +#define TPI_HWIDTH_8_9 (0x67) +#define TPI_VBIT_TO_VSYNC (0x68) +#define TPI_VWIDTH (0x69) + +// H/W Optimization Control Registers +#define TPI_HW_OPT_CTRL_1 (0xB9) +#define TPI_HW_OPT_CTRL_2 (0xBA) +#define TPI_HW_OPT_CTRL_3 (0xBB) + +// H/W Optimization Control Register #3 Set +#define DDC_DELAY_BIT9_MASK (BIT_7) +#define DDC_DELAY_BIT9_NO (0x00) +#define DDC_DELAY_BIT9_YES (0x80) +#define RI_CHECK_SKIP_MASK (BIT_3) +#define RI_CHECK_SKIP_NO (0x00) +#define RI_CHECK_SKIP_YES (0x08) + +// TPI Enable Register +#define TPI_ENABLE (0xC7) + +// Misc InfoFrames +#define MISC_INFO_FRAMES_CTRL (0xBF) +#define MISC_INFO_FRAMES_TYPE (0xC0) +#define MISC_INFO_FRAMES_VER (0xC1) +#define MISC_INFO_FRAMES_LEN (0xC2) +#define MISC_INFO_FRAMES_CHKSUM (0xC3) +//-------------------------------------------------------------------- +void DelayMS (word MS); + +byte I2CReadBlock(struct i2c_client *client, byte RegAddr, byte NBytes, byte * Data ); +byte I2CWriteBlock(struct i2c_client *client, byte RegAddr, byte NBytes, byte * Data ); +byte siiReadSegmentBlockEDID(struct i2c_client *client, byte Segment, byte Offset, byte *Buffer, byte Length); + +void WriteByteTPI (byte RegOffset, byte Data); +byte ReadByteTPI (byte RegOffset); + + +void siHdmiTx_PowerStateD2 (void); +void siHdmiTx_PowerStateD0fromD2 (void); + +void siHdmiTx_Init (void); + +byte DoEdidRead (void); +byte GetDDC_Access (byte* SysCtrlRegVal); +byte ReleaseDDC (byte SysCtrlRegVal); + + + + +byte siHdmiTx_VideoSet (void); +byte siHdmiTx_AudioSet (void); +byte siHdmiTx_TPI_Init (void); +void siHdmiTx_TPI_Poll (void); +void siHdmiTx_VideoSel (byte vmode); +void siHdmiTx_AudioSel (byte Afs); +#endif diff --git a/drivers/gpu/drm/smidrm/ddk750/vdif.h b/drivers/gpu/drm/smidrm/ddk750/vdif.h new file mode 100644 index 000000000000..36d11d6daa54 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk750/vdif.h @@ -0,0 +1,63 @@ +/******************************************************************* +* +* Copyright (c) 2009 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* vdif.h --- SMI DDK +* This file contains the video display information format structure +* +*******************************************************************/ +#ifndef _VDIF_H_ +#define _VDIF_H_ + +/* Sync polarity */ +typedef enum _vdif_sync_polarity_t +{ + VDIF_SYNC_NEGATIVE = 0, + VDIF_SYNC_POSITIVE +} vdif_sync_polarity_t; + +/* Scan type */ +typedef enum _vdif_scan_type_t +{ + VDIF_NONINTERLACED = 0, + VDIF_INTERLACED +} vdif_scan_type_t; + +/* Monitor Timing Information */ +typedef struct _video_display_information_format_t +{ + unsigned long pixelClock; + unsigned long characterWidth; + vdif_scan_type_t scanType; + + unsigned long horizontalFrequency; + vdif_sync_polarity_t horizontalSyncPolarity; + unsigned long horizontalTotal; + unsigned long horizontalActive; + unsigned long horizontalBlankStart; + unsigned long horizontalBlankTime; + unsigned long horizontalSyncStart; + unsigned long horizontalRightBorder; + unsigned long horizontalFrontPorch; + unsigned long horizontalSyncWidth; + unsigned long horizontalBackPorch; + unsigned long horizontalLeftBorder; + + unsigned long verticalFrequency; + vdif_sync_polarity_t verticalSyncPolarity; + unsigned long verticalTotal; + unsigned long verticalActive; + unsigned long verticalBlankStart; + unsigned long verticalBlankTime; + unsigned long verticalSyncStart; + unsigned long verticalBottomBorder; + unsigned long verticalFrontPorch; + unsigned long verticalSyncHeight; + unsigned long verticalBackPorch; + unsigned long verticalTopBorder; +} vdif_t; + +#endif /* _VDIF_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768.h b/drivers/gpu/drm/smidrm/ddk768/ddk768.h new file mode 100644 index 000000000000..8285c868494b --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768.h @@ -0,0 +1,23 @@ +#ifndef DDK768_H__ +#define DDK768_H__ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* RegSC.h --- SM718 SDK +* This file contains the definitions for the System Configuration registers. +* +*******************************************************************/ +#include "ddk768_reg.h" +#include "ddk768_help.h" + + +#include "ddk768_mode.h" +#include "ddk768_chip.h" +#include "ddk768_power.h" +#include "ddk768_display.h" +#include "ddk768_2d.h" +#endif diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_2d.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_2d.c new file mode 100644 index 000000000000..7afad4944a2c --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_2d.c @@ -0,0 +1,1198 @@ +#include "linux/string.h" +#include "ddk768_reg.h" + +#include "ddk768_chip.h" +#include "ddk768_power.h" +#include "ddk768_2d.h" +#include "ddk768_help.h" + +/* Blt Direction definitions */ +#define TOP_TO_BOTTOM 0 +#define LEFT_TO_RIGHT 0 +#define BOTTOM_TO_TOP 1 +#define RIGHT_TO_LEFT 1 + +#if 0 /* Cheok: Block it out to test if it is problem in new chip */ + +/* Flag to enable the 192 bytes patch to workaround the 2D errata, where the engine + will draws incorrectly for BITBLT function that involves READ from memory. + Currently, this definition flag is only used for testing. */ +#define ENABLE_192_BYTES_PATCH +#endif + +/* Static macro */ +#define BYTE_PER_PIXEL(bpp) (bpp / 8) + +/* + * 2D Engine Initialization. + * This function must be called before other 2D functions. + * Assumption: A specific video mode has been properly set up. + */ +void ddk768_deInit() +{ + ddk768_enable2DEngine(1); + + ddk768_deReset(); /* Just be sure no left-over operations from other applications */ + + /* Set up 2D registers that won't change for a specific mode. */ + + /* Drawing engine bus and pixel mask, always want to enable. */ + POKE_32(DE_MASKS, 0xFFFFFFFF); + + /* Pixel format, which can be 8, 16 or 32. + Assuming setmode is call before 2D init, then pixel format + is available in reg 0x80000 (Panel Display Control) + */ + POKE_32(DE_STRETCH_FORMAT, + FIELD_SET (0, DE_STRETCH_FORMAT, PATTERN_XY, NORMAL) | + FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_Y, 0) | + FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X, 0) | + FIELD_SET (0, DE_STRETCH_FORMAT, ADDRESSING, XY) | + FIELD_VALUE(0, DE_STRETCH_FORMAT, SOURCE_HEIGHT,3)); + + /* Clipping and transparent are disable after INIT */ + ddk768_deSetClipping(0, 0, 0, 0, 0); + ddk768_deSetTransparency(0, 0, 0, 0); +} + +/* + * Reset 2D engine by + * 1) Aborting the current 2D operation. + * 2) Re-enable 2D engine to normal state. + */ +void ddk768_deReset() +{ +#if 0 /* Cheok(2/11/2014): Not sure which registers are used for Falcon */ + unsigned long sysCtrl; + logical_chip_type_t chipType = ddk768_getChipType(); + + if (chipType == SM750 || chipType == SM718) + { + /* Abort current 2D operation */ + sysCtrl = PEEK_32(SYSTEM_CTRL); + sysCtrl = FIELD_SET(sysCtrl, SYSTEM_CTRL, DE_ABORT, ON); + POKE_32(SYSTEM_CTRL, sysCtrl); + + /* Re-enable 2D engine to normal state */ + sysCtrl = PEEK_32(SYSTEM_CTRL); + sysCtrl = FIELD_SET(sysCtrl, SYSTEM_CTRL, DE_ABORT, OFF); + POKE_32(SYSTEM_CTRL, sysCtrl); + } + else /* For SM750LE and SM750HS series */ + { + /* Abort current 2D operation */ + sysCtrl = PEEK_32(DE_STATE1); + sysCtrl = FIELD_SET(sysCtrl, DE_STATE1, DE_ABORT, ON); + POKE_32(DE_STATE1, sysCtrl); + + /* Re-enable 2D engine to normal state */ + sysCtrl = PEEK_32(DE_STATE1); + sysCtrl = FIELD_SET(sysCtrl, DE_STATE1, DE_ABORT, OFF); + POKE_32(DE_STATE1, sysCtrl); + } +#endif +} + +/* + * Wait until 2D engine is not busy. + * All 2D operations are recommand to check 2D engine idle before start. + * + * Return: 0 = return because engine is idle and normal. + * -1 = return because time out (2D engine may have problem). + */ +long ddk768_deWaitForNotBusy(void) +{ + unsigned long dwVal; + unsigned long i = 0x100000; + + while (i--) + { + dwVal = PEEK_32(DE_STATE2); + if ((FIELD_GET(dwVal, DE_STATE2, DE_STATUS) == DE_STATE2_DE_STATUS_IDLE) && + (FIELD_GET(dwVal, DE_STATE2, DE_FIFO) == DE_STATE2_DE_FIFO_EMPTY) && + (FIELD_GET(dwVal, DE_STATE2, DE_MEM_FIFO) == DE_STATE2_DE_MEM_FIFO_EMPTY)) + { + return 0; /* Return because engine idle */ + } + } + return -1; /* Return because of timeout */ +} + +/* + * This function enable/disable clipping area for the 2d engine. + * Note that the clipping area is always rectangular. + * + */ +long ddk768_deSetClipping( +unsigned long enable, /* 0 = disable clipping, 1 = enable clipping */ +unsigned long x1, /* x1, y1 is the upper left corner of the clipping area */ +unsigned long y1, /* Note that the region includes x1 and y1 */ +unsigned long x2, /* x2, y2 is the lower right corner of the clippiing area */ +unsigned long y2) /* Note that the region will not include x2 and y2 */ +{ + if (ddk768_deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* ddk768_deReset(); */ + } + + /* Upper left corner and enable/disable bit + Note: This module defautls to clip outside region. + "Clip inside" is not a useful feature since nothing gets drawn. + */ + POKE_32(DE_CLIP_TL, + FIELD_VALUE(0, DE_CLIP_TL, TOP, y1) | + ((enable)? + FIELD_SET(0, DE_CLIP_TL, STATUS, ENABLE) + : FIELD_SET(0, DE_CLIP_TL, STATUS, DISABLE))| + FIELD_SET (0, DE_CLIP_TL, INHIBIT,OUTSIDE) | + FIELD_VALUE(0, DE_CLIP_TL, LEFT, x1)); + + /* Lower right corner */ + POKE_32(DE_CLIP_BR, + FIELD_VALUE(0, DE_CLIP_BR, BOTTOM,y2) | + FIELD_VALUE(0, DE_CLIP_BR, RIGHT, x2)); + + return 0; +} + +/* + * Function description: + * When transparency is enable, the blt engine compares each pixel value + * (either source or destination) with DE_COLOR_COMPARE register. + * If match, the destination pixel will NOT be updated. + * If not match, the destination pixel will be updated. + */ +long ddk768_deSetTransparency( +unsigned long enable, /* 0 = disable, 1 = enable transparency feature */ +unsigned long tSelect, /* 0 = compare source, 1 = compare destination */ +unsigned long tMatch, /* 0 = Opaque mode, 1 = transparent mode */ +unsigned long ulColor) /* Color to compare. */ +{ + unsigned long de_ctrl; + + if (ddk768_deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* ddk768_deReset(); */ + } + + /* Set mask */ + if (enable) + { + POKE_32(DE_COLOR_COMPARE_MASK, 0x00ffffff); + + /* Set compare color */ + POKE_32(DE_COLOR_COMPARE, ulColor); + } + else + { + POKE_32(DE_COLOR_COMPARE_MASK, 0x0); + POKE_32(DE_COLOR_COMPARE, 0x0); + } + + /* Set up transparency control, without affecting other bits + Note: There are two operatiing modes: Transparent and Opague. + We only use transparent mode because Opaque mode may have bug. + */ + de_ctrl = PEEK_32(DE_CONTROL) + & FIELD_CLEAR(DE_CONTROL, TRANSPARENCY) + & FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_MATCH) + & FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_SELECT); + + /* For DE_CONTROL_TRANSPARENCY_MATCH bit, always set it + to TRANSPARENT mode, OPAQUE mode don't seem working. + */ + de_ctrl |= + ((enable)? + FIELD_SET(0, DE_CONTROL, TRANSPARENCY, ENABLE) + : FIELD_SET(0, DE_CONTROL, TRANSPARENCY, DISABLE)) | + ((tMatch)? + FIELD_SET(0, DE_CONTROL, TRANSPARENCY_MATCH, TRANSPARENT) + : FIELD_SET(0, DE_CONTROL, TRANSPARENCY_MATCH, OPAQUE)) | + ((tSelect)? + FIELD_SET(0, DE_CONTROL, TRANSPARENCY_SELECT, DESTINATION) + : FIELD_SET(0, DE_CONTROL, TRANSPARENCY_SELECT, SOURCE)); + + POKE_32(DE_CONTROL, de_ctrl); + + return 0; +} + +/* + * This function gets the transparency status from DE_CONTROL register. + * It returns a double word with the transparent fields properly set, + * while other fields are 0. + */ +unsigned long ddk768_deGetTransparency(void) +{ + unsigned long de_ctrl; + + de_ctrl = PEEK_32(DE_CONTROL); + + de_ctrl &= + FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) | + FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT)| + FIELD_MASK(DE_CONTROL_TRANSPARENCY); + + return de_ctrl; +} + +/* + * This function sets the pixel format that will apply to the 2D Engine. + */ +void ddk768_deSetPixelFormat( + unsigned long bpp +) +{ + unsigned long de_format; + + de_format = PEEK_32(DE_STRETCH_FORMAT); + + switch (bpp) + { + case 8: + de_format = FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 8); + break; + default: + case 16: + de_format = FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 16); + break; + case 32: + de_format = FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 32); + break; + } + + POKE_32(DE_STRETCH_FORMAT, de_format); +} + +/* + * This function uses 2D engine to fill a rectangular area with a specific color. + * The filled area includes the starting points. + */ +long ddk768_deRectFill( /*resolution_t resolution, point_t p0, point_t p1, unsigned long color, unsigned long rop2)*/ +unsigned long dBase, /* Base address of destination surface counted from beginning of video frame buffer */ +unsigned long dPitch, /* Pitch value of destination surface in BYTES */ +unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ +unsigned long x, +unsigned long y, /* Upper left corner (X, Y) of rectangle in pixel value */ +unsigned long width, +unsigned long height, /* width and height of rectange in pixel value */ +unsigned long color, /* Color to be filled */ +unsigned long rop2) /* ROP value */ +{ + unsigned long de_ctrl, bytePerPixel; + + bytePerPixel = bpp/8; + + if (ddk768_deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* ddk768_deReset(); */ + } + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, (dPitch/bytePerPixel))); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (dPitch/bytePerPixel))); + + POKE_32(DE_FOREGROUND, color); + + /* Set the pixel format of the destination */ + ddk768_deSetPixelFormat(bpp); + +#ifdef ENABLE_192_BYTES_PATCH + /* Workaround for 192 byte requirement when ROP is not COPY */ + if (((rop2 != ROP2_COPY) || (rop2 != ROP2_Sn) || (rop2 != ROP2_Dn) || + (rop2 != ROP2_D) || (rop2 != ROP2_BLACK) || (rop2 != ROP2_WHITE)) && + ((width * bytePerPixel) > 192)) + { + /* Perform the ROP2 operation in chunks of (xWidth * nHeight) */ + unsigned long xChunk = 192 / bytePerPixel; /* chunk width is in pixels */ + + //DDKDEBUGPRINT((DE_LEVEL, "ROP != ROP_COPY, width * bytePerPixel = %x (> 192 bytes)\n", width * bytePerPixel)); + + while (1) + { + ddk768_deWaitForNotBusy(); + + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, x) | + FIELD_VALUE(0, DE_DESTINATION, Y, y)); + + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, xChunk) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + de_ctrl = + FIELD_SET (0, DE_CONTROL, STATUS, START) | + FIELD_SET (0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + //FIELD_SET (0, DE_CONTROL,LAST_PIXEL, OFF) | + FIELD_SET (0, DE_CONTROL, COMMAND, RECTANGLE_FILL) | + FIELD_SET (0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, rop2); + + POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency()); + + if (xChunk == width) break; + + x += xChunk; + width -= xChunk; + + if (xChunk > width) + { + /* This is the last chunk. */ + xChunk = width; + } + } + } + else +#endif + { + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, x) | + FIELD_VALUE(0, DE_DESTINATION, Y, y)); + + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + de_ctrl = + FIELD_SET (0, DE_CONTROL, STATUS, START) | + FIELD_SET (0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + //FIELD_SET (0, DE_CONTROL,LAST_PIXEL, OFF) | + FIELD_SET (0, DE_CONTROL, COMMAND, RECTANGLE_FILL) | + FIELD_SET (0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, rop2); + + POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency()); + } + + return 0; +} + +/* + * This function uses 2D engine to draw a trapezoid with a specific color. + * The filled area includes the starting points. + */ +long ddk768_deStartTrapezoidFill( + unsigned long dBase, /* Base address of destination surface counted from beginning of video frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTES */ + unsigned long bpp, /* Color depth of destination surface: 8, 16 or 32 */ + unsigned long x, + unsigned long y, /* Starting (X, Y) coordinate inside the polygon to be filled */ + unsigned long length, /* Length of the line */ + unsigned long color, /* Color to be filled */ + unsigned long rop2 /* ROP value */ +) +{ + unsigned long de_ctrl = + FIELD_SET (0, DE_CONTROL, STATUS, START) | + FIELD_SET (0, DE_CONTROL, QUICK_START, ENABLE) | + FIELD_SET (0, DE_CONTROL, LAST_PIXEL, OFF) | + FIELD_SET (0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + FIELD_SET (0, DE_CONTROL, COMMAND, TRAPEZOID_FILL) | + FIELD_SET (0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, rop2); + + if (ddk768_deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* ddk768_deReset(); */ + } + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp))); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, dPitch / BYTE_PER_PIXEL(bpp)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, dPitch / BYTE_PER_PIXEL(bpp))); + + /* Set the Line Color */ + POKE_32(DE_FOREGROUND, color); + + /* Set the destination coordinate */ + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, x) | + FIELD_VALUE(0, DE_DESTINATION, Y, y)); + + /* Set the pixel format of the destination */ + ddk768_deSetPixelFormat(bpp); + + /* Set the line length and width */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, length) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, 0)); + + /* Enable the 2D Engine. */ + POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency()); + + return 0; +} + +/* + * Function to continue drawing a line using Trapezoid Fill method. + */ +long ddk768_deNextTrapezoidFill( + unsigned long x, /* Starting X location. */ + unsigned long length /* Line length */ +) +{ + if (ddk768_deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* ddk768_deReset(); */ + } + + /* Set the X destination coordinate */ + POKE_32(DE_DESTINATION, + FIELD_VALUE(PEEK_32(DE_DESTINATION), DE_DESTINATION, X, x)); + + /* Set the line length */ + POKE_32(DE_DIMENSION, + FIELD_VALUE(PEEK_32(DE_DIMENSION), DE_DIMENSION, X, length)); + + return 0; +} + +/* + * Function to stop the Trapezoid Fill drawing. + * This function has to be called to end the Trapezoid Fill drawing. + * Otherwise, the next 2D function might still use this function. + */ +long ddk768_deStopTrapezoidFill() +{ + if (ddk768_deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* ddk768_deReset(); */ + } + + POKE_32(DE_CONTROL, FIELD_SET(PEEK_32(DE_CONTROL), DE_CONTROL, QUICK_START, DISABLE)); + + return 0; +} + +/* + * Video Memory to Video Memory data transfer. + * Note: + * It works whether the Video Memroy is off-screeen or on-screen. + * This function is a one to one transfer without stretching or + * mono expansion. + */ +long ddk768_deVideoMem2VideoMemBlt( +unsigned long sBase, /* Address of source: offset in frame buffer */ +unsigned long sPitch, /* Pitch value of source surface in BYTE */ +unsigned long sx, +unsigned long sy, /* Starting coordinate of source surface */ +unsigned long dBase, /* Address of destination: offset in frame buffer */ +unsigned long dPitch, /* Pitch value of destination surface in BYTE */ +unsigned long bpp, /* Color depth of destination surface */ +unsigned long dx, +unsigned long dy, /* Starting coordinate of destination surface */ +unsigned long width, +unsigned long height, /* width and height of rectangle in pixel value */ +unsigned long rop2) /* ROP value */ +{ + unsigned long nDirection, de_ctrl, bytePerPixel; + long opSign; + + if (ddk768_deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* ddk768_deReset(); */ + } + + nDirection = LEFT_TO_RIGHT; + opSign = 1; /* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */ + bytePerPixel = bpp/8; + de_ctrl = 0; + + /* If source and destination are the same surface, need to check for overlay cases */ + if (sBase == dBase && sPitch == dPitch) + { + /* Determine direction of operation */ + if (sy < dy) + { + /* +----------+ + |S | + | +----------+ + | | | | + | | | | + +---|------+ | + | D| + +----------+ */ + + nDirection = BOTTOM_TO_TOP; + } + else if (sy > dy) + { + /* +----------+ + |D | + | +----------+ + | | | | + | | | | + +---|------+ | + | S| + +----------+ */ + + nDirection = TOP_TO_BOTTOM; + } + else + { + /* sy == dy */ + + if (sx <= dx) + { + /* +------+---+------+ + |S | | D| + | | | | + | | | | + | | | | + +------+---+------+ */ + + nDirection = RIGHT_TO_LEFT; + } + else + { + /* sx > dx */ + + /* +------+---+------+ + |D | | S| + | | | | + | | | | + | | | | + +------+---+------+ */ + + nDirection = LEFT_TO_RIGHT; + } + } + } + + if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) + { + sx += width - 1; + sy += height - 1; + dx += width - 1; + dy += height - 1; + opSign = (-1); + } + + /* Note: + DE_FOREGROUND are DE_BACKGROUND are don't care. + DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set ddk768_deSetTransparency(). + */ + + /* 2D Source Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_SOURCE_BASE, sBase); + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, (sPitch/bytePerPixel))); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (sPitch/bytePerPixel))); + + /* Set the pixel format of the destination */ + ddk768_deSetPixelFormat(bpp); + +#ifdef ENABLE_192_BYTES_PATCH + /* This bug is fixed in SM718 for 16 and 32 bpp. However, in 8-bpp, the problem still exists. + The Version AA also have this problem on higher clock with 32-bit memory data bus, + therefore, it needs to be enabled here. + In version AA, the problem happens on the following configurations: + 1. M2XCLK = 336MHz w/ 32-bit, MCLK = 112MHz, and color depth set to 32bpp + 2. M2XCLK = 336MHz w/ 32-bit, MCLK = 84MHz, and color depth set to 16bpp or 32bpp. + Somehow, the problem does not appears in 64-bit memory setting. + */ + + /* Workaround for 192 byte requirement when ROP is not COPY */ + if ((rop2 != ROP2_COPY) && ((width * bytePerPixel) > 192)) + { + /* Perform the ROP2 operation in chunks of (xWidth * nHeight) */ + unsigned long xChunk = 192 / bytePerPixel; /* chunk width is in pixels */ + + //DDKDEBUGPRINT((DE_LEVEL, "ROP != ROP_COPY, width * bytePerPixel = %x (> 192 bytes)\n", width * bytePerPixel)); + + while (1) + { + ddk768_deWaitForNotBusy(); + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, xChunk) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + de_ctrl = + FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) | + ((nDirection == RIGHT_TO_LEFT) ? + FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT) + : FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency()); + + if (xChunk == width) break; + + sx += (opSign * xChunk); + dx += (opSign * xChunk); + width -= xChunk; + + if (xChunk > width) + { + /* This is the last chunk. */ + xChunk = width; + } + } + } + else +#endif + { + ddk768_deWaitForNotBusy(); + + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + de_ctrl = + FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) | + ((nDirection == RIGHT_TO_LEFT) ? + FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT) + : FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency()); + } + + return 0; +} +#if 0 + +/* + * System Memory to Video Memory data transfer. + * Only works in D, S, ~D, and ~S ROP. + */ +long ddk768_deSystemMem2VideoMemBusMasterBlt( + unsigned char *pSBase, /* Address of source in the system memory. + The memory must be a continuous physical address. */ + unsigned long sPitch, /* Pitch value of source surface in BYTE */ + unsigned long sx, + unsigned long sy, /* Starting coordinate of source surface */ + unsigned long dBase, /* Address of destination in frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTE */ + unsigned long bpp, /* Color depth of destination surface */ + unsigned long dx, + unsigned long dy, /* Starting coordinate of destination surface */ + unsigned long width, + unsigned long height, /* width and height of rectangle in pixel value */ + unsigned long rop2 /* ROP value */ +) +{ + unsigned long de_ctrl, bytePerPixel; + unsigned long value, pciMasterBaseAddress; + long opSign; + + if (ddk768_deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* ddk768_deReset(); */ + } + + bytePerPixel = bpp/8; + de_ctrl = 0; + + /* Note: + DE_FOREGROUND are DE_BACKGROUND are don't care. + DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set ddk768_deSetTransparency(). + */ + + /* 2D Source Base. + It is an address offset (128 bit aligned) from the given PCI Master base address + */ + /* Set 2D Source Base Address */ + value = FIELD_VALUE(0, DE_WINDOW_SOURCE_BASE, ADDRESS, (unsigned long)pSBase); + pciMasterBaseAddress = ((unsigned long)pSBase & 0xFC000000) >> 24; + POKE_32(PCI_MASTER_BASE, FIELD_VALUE(0, PCI_MASTER_BASE, ADDRESS, pciMasterBaseAddress)); + POKE_32(DE_WINDOW_SOURCE_BASE, value); + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, (sPitch/bytePerPixel))); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (sPitch/bytePerPixel))); + + /* Set the pixel format of the destination */ + ddk768_deSetPixelFormat(bpp); + +#ifdef ENABLE_192_BYTES_PATCH + /* This bug is fixed in SM718 for 16 and 32 bpp. However, in 8-bpp, the problem still exists. + The Version AA also have this problem on higher clock with 32-bit memory data bus, + therefore, it needs to be enabled here. + In version AA, the problem happens on the following configurations: + 1. M2XCLK = 336MHz w/ 32-bit, MCLK = 112MHz, and color depth set to 32bpp + 2. M2XCLK = 336MHz w/ 32-bit, MCLK = 84MHz, and color depth set to 16bpp or 32bpp. + Somehow, the problem does not appears in 64-bit memory setting. + */ + + /* Workaround for 192 byte requirement when ROP is not COPY */ + if ((rop2 != ROP2_COPY) && ((width * bytePerPixel) > 192)) + { + /* Perform the ROP2 operation in chunks of (xWidth * nHeight) */ + unsigned long xChunk = 192 / bytePerPixel; /* chunk width is in pixels */ + + //DDKDEBUGPRINT((DE_LEVEL, "ROP != ROP_COPY, width * bytePerPixel = %x (> 192 bytes)\n", width * bytePerPixel)); + + while (1) + { + ddk768_deWaitForNotBusy(); + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); + + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, xChunk) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + de_ctrl = + FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) | + FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency()); + + if (xChunk == width) break; + + sx += xChunk; + dx += xChunk; + width -= xChunk; + + if (xChunk > width) + { + /* This is the last chunk. */ + xChunk = width; + } + } + } + else +#endif + { + ddk768_deWaitForNotBusy(); + + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + de_ctrl = + FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) | + FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency()); + } + + return 0; +} +#endif +/* + * System memory to Video memory data transfer + * Note: + * We also call it HOST Blt. + * This function is a one to one transfer without stretching or + * mono expansion. + */ +long ddk768_deSystemMem2VideoMemBlt( + unsigned char *pSrcbuf, /* pointer to source data in system memory */ + long srcDelta, /* width (in Bytes) of the source data, +ive means top down and -ive mean button up */ + unsigned long dBase, /* Address of destination: offset in frame buffer */ + unsigned long dPitch, /* Pitch value of destination surface in BYTE */ + unsigned long bpp, /* Color depth of destination surface */ + unsigned long dx, + unsigned long dy, /* Starting coordinate of destination surface */ + unsigned long width, + unsigned long height, /* width and height of rectange in pixel value */ + unsigned long rop2 /* ROP value */ +) +{ + unsigned long bytePerPixel; + unsigned long ulBytesPerScan; + unsigned long ul8BytesPerScan; + unsigned long ulBytesRemain; + unsigned long de_ctrl = 0; + unsigned char ajRemain[8]; + long i, j; + + bytePerPixel = bpp/8; + + /* HOST blt data port must take multiple of 8 bytes as input. + If the source width does not match that requirement, + we need to split it into two portions. The first portion + is 8 byte multiple. The 2nd portion is the remaining bytes. + The remaining bytes will be buffered to an 8 byte array and + and send it to the host blt data port. + */ + //ulBytesPerScan = width * bpp / 8; + ulBytesPerScan = width / 8; + ul8BytesPerScan = ulBytesPerScan & ~7; + ulBytesRemain = ulBytesPerScan & 7; + + /* Program 2D Drawing Engine */ + if (ddk768_deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* ddk768_deReset(); */ + } + + /* 2D Source Base. + Use 0 for HOST Blt. + */ + POKE_32(DE_WINDOW_SOURCE_BASE, 0); + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch/bytePerPixel) | + FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch/bytePerPixel)); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (dPitch/bytePerPixel))); + + /* Note: For 2D Source in Host Write, only X_K1 field is needed, and Y_K2 field is not used. + For 1 to 1 bitmap transfer, use 0 for X_K1 means source alignment from byte 0. */ + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, 0) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, 0)); + + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + /* Set the pixel format of the destination */ + ddk768_deSetPixelFormat(bpp); + + de_ctrl = + FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) | + FIELD_SET(0, DE_CONTROL, HOST, COLOR) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency()); + + /* Write bitmap/image data (line by line) to 2D Engine data port */ + for (i = 0; i < height; i++) + { + /* For each line, send the data in chunks of 4 bytes. */ + for (j=0; j < (ul8BytesPerScan/4); j++) + POKE_32(DE_DATA_PORT, *(unsigned long *)(pSrcbuf + (j * 4))); + + if (ulBytesRemain) + { + memcpy(ajRemain, pSrcbuf+ul8BytesPerScan, ulBytesRemain); + POKE_32(DE_DATA_PORT, *(unsigned long *)ajRemain); + POKE_32(DE_DATA_PORT, *(unsigned long *)(ajRemain+4)); + } + + pSrcbuf += srcDelta; + } + + return 0; +} + +/* + * System memory to Video memory monochrome expansion. + * Source is monochrome image in system memory. + * This function expands the monochrome data to color image in video memory. + */ +long ddk768_deSystemMem2VideoMemMonoBlt( +unsigned char *pSrcbuf, /* pointer to start of source buffer in system memory */ +long srcDelta, /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */ +unsigned long startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */ +unsigned long dBase, /* Address of destination: offset in frame buffer */ +unsigned long dPitch, /* Pitch value of destination surface in BYTE */ +unsigned long bpp, /* Color depth of destination surface */ +unsigned long dx, +unsigned long dy, /* Starting coordinate of destination surface */ +unsigned long width, +unsigned long height, /* width and height of rectange in pixel value */ +unsigned long fColor, /* Foreground color (corresponding to a 1 in the monochrome data */ +unsigned long bColor, /* Background color (corresponding to a 0 in the monochrome data */ +unsigned long rop2) /* ROP value */ +{ + unsigned long bytePerPixel; + unsigned long ulBytesPerScan; + unsigned long ul4BytesPerScan; + unsigned long ulBytesRemain; + unsigned long de_ctrl = 0; + unsigned char ajRemain[4]; + long i, j; + + bytePerPixel = bpp/8; + + startBit &= 7; /* Just make sure the start bit is within legal range */ + ulBytesPerScan = (width + startBit + 7) / 8; + ul4BytesPerScan = ulBytesPerScan & ~3; + ulBytesRemain = ulBytesPerScan & 3; + + if (ddk768_deWaitForNotBusy() != 0) + { + /* The 2D engine is always busy for some unknown reason. + Application can choose to return ERROR, or reset it and + continue the operation. + */ + + return -1; + + /* or */ + /* ddk768_deReset(); */ + } + + /* 2D Source Base. + Use 0 for HOST Blt. + */ + POKE_32(DE_WINDOW_SOURCE_BASE, 0); + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + POKE_32(DE_WINDOW_DESTINATION_BASE, dBase); + + /* Program pitch (distance between the 1st points of two adjacent lines). + Note that input pitch is BYTE value, but the 2D Pitch register uses + pixel values. Need Byte to pixel convertion. + */ + POKE_32(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch/bytePerPixel) | + FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch/bytePerPixel)); + + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + POKE_32(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (dPitch/bytePerPixel))); + + /* Note: For 2D Source in Host Write, only X_K1_MONO field is needed, and Y_K2 field is not used. + For mono bitmap, use startBit for X_K1. */ + POKE_32(DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1_MONO, startBit)); + + POKE_32(DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + + POKE_32(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + POKE_32(DE_FOREGROUND, fColor); + POKE_32(DE_BACKGROUND, bColor); + + /* Set the pixel format of the destination */ + ddk768_deSetPixelFormat(bpp); + + de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) | + FIELD_SET(0, DE_CONTROL, HOST, MONO) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + POKE_32(DE_CONTROL, de_ctrl | ddk768_deGetTransparency()); + + /* Write MONO data (line by line) to 2D Engine data port */ + for (i=0; isetAllEngOff == 1) + { + ulReg = peekRegisterDWord(VIDEO_DISPLAY_CTRL); + ulReg = FIELD_SET(ulReg, VIDEO_DISPLAY_CTRL, PLANE, DISABLE); + pokeRegisterDWord(VIDEO_DISPLAY_CTRL, ulReg); /* Channel 0 */ + pokeRegisterDWord(VIDEO_DISPLAY_CTRL+CHANNEL_OFFSET, ulReg); /* Channel 1 */ + + /* Disable alpha plane, if a former application left it on */ + ulReg = peekRegisterDWord(ALPHA_DISPLAY_CTRL); + ulReg = FIELD_SET(ulReg, ALPHA_DISPLAY_CTRL, PLANE, DISABLE); + pokeRegisterDWord(ALPHA_DISPLAY_CTRL, ulReg); /* Channel 0 */ + pokeRegisterDWord(ALPHA_DISPLAY_CTRL+CHANNEL_OFFSET, ulReg); /* Channel 1 */ + + /* Disable hardware cursor, if a former application left it on */ + ulReg = peekRegisterDWord(HWC_CONTROL); + ulReg = FIELD_SET(ulReg, HWC_CONTROL, MODE, DISABLE); + pokeRegisterDWord(HWC_CONTROL, ulReg); /* Channel 0 */ + pokeRegisterDWord(HWC_CONTROL+CHANNEL_OFFSET, ulReg); /* Channel 1 */ + } + + /* We can add more initialization as needed. */ + + + return 0; +} + +/* + * Initialize chip with default parameters. + * + * Input: none. + * + * Return: 0 (or NO_ERROR) if successful. + * -1 if fail. + */ +long ddk768_initChip() +{ + initchip_param_t initParam; + + /* Initialize the chip with some default parameters */ + + initParam.setAllEngOff = 1; + + + return(ddk768_initChipParamEx(&initParam)); +} + +#if 0 +#define PHY_STATUS(A, B)\ + peekRegisterDWord(A) & B +/* + Program DDR PHY register PIR to do DDR training. + Other parameters for training are assumed well set before calling here. +*/ +void ddrTraining() +{ + unsigned long ulTmp; + + ulTmp = peekRegisterDWord(CLOCK_ENABLE); + + //Shut off all active components, espically ARM + pokeRegisterDWord(CLOCK_ENABLE, 0); + + pokeRegisterDWord(PIR, 0); + pokeRegisterDWord(PIR, 0x1ff); + + // May take few cycles for PGSR.IDONE = 0 after kick off DDR training. + while((PHY_STATUS(PGSR, 0x00000001))){} + + // Wait until DDR training completed + while(!(PHY_STATUS(PGSR, 0x00000001))){} + + //Restore clocks + pokeRegisterDWord(CLOCK_ENABLE, ulTmp); +} +#endif + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_chip.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_chip.h new file mode 100644 index 000000000000..3577e4f8fd60 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_chip.h @@ -0,0 +1,90 @@ +/******************************************************************* +* +* Copyright (c) 2008 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* CHIP.H --- SMI DDK +* This file contains the source code for the SM750/SM718 chip. +* +*******************************************************************/ +#ifndef _DDK768_CHIP_H_ +#define _DDK768_CHIP_H_ + +/* This is all the chips recognized by this library */ +typedef enum _logical_chip_type_t +{ + SM_UNKNOWN = 0, + SM768 = 1 +} +logical_chip_type_t; + +/* input struct to initChipParam() function */ +typedef struct _initchip_param_t +{ + + unsigned short setAllEngOff; /* 0 = leave all engine state untouched. + 1 = make sure they are off: 2D, Overlay, + video alpha, alpha, hardware cursors + */ + + /* More initialization parameter can be added if needed */ +} +initchip_param_t; + + + +unsigned int ddk768_getCrystalType(void); +unsigned int ddk768_getPixelType(void); + + + +/* + * This function returns frame buffer memory size in Byte units. + */ +unsigned long ddk768_getFrameBufSize(void); + + + +/* + * This function returns the logical chip type defined in chip.h + * It is one of the following: SM501, SM502, SM107, SM718, SM 750 or + * SM_UNKNOWN. + */ +logical_chip_type_t ddk768_getChipType(void); + +/* + * Return a char string name of the current chip. + * It's convenient for application need to display the chip name. + */ +char * ddk768_getChipTypeString(void); + +/* + * Initialize a single chip and environment according to input parameters. + * + * Input: initchip_param_t structure. + * + * Return: 0 (or NO_ERROR) if successful. + * -1 if fail. + * + */ +long ddk768_initChipParamEx(initchip_param_t * pInitParam); + +/* + * Initialize the chip with default parameters. + * + * Input: none. + * + * Return: 0 (or NO_ERROR) if successful. + * -1 if fail. + */ +long ddk768_initChip(void); + +#define MB(x) (x<<20) /* Macro for Mega Bytes */ + + + + +#endif /* _CHIP_H_ */ + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_clock.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_clock.c new file mode 100644 index 000000000000..b6ea80dda0c2 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_clock.c @@ -0,0 +1,171 @@ +#include "ddk768_reg.h" + +#include "ddk768_chip.h" +#include "ddk768_power.h" +#include "ddk768_clock.h" +#include "ddk768_mode.h" + + +#include "ddk768_help.h" +#include "ddk768_helper.h" + +/* + * A local function to calculate the output frequency of a given PLL structure. + * + */ +unsigned long ddk768_calcPLL(pll_value_t *pPLL) +{ + unsigned long pllClk, vcoPower; + unsigned long fifteenPower = ddk768_twoToPowerOfx(15); /* 2^15 */ + + /* Convert everything in Khz range in order to avoid calculation overflow */ + pPLL->inputFreq /= 1000; + + /* Work out 2 to the power of (VCO + 1) */ + vcoPower = ddk768_twoToPowerOfx(pPLL->VCO + 1); + + pllClk = (pPLL->inputFreq * pPLL->INT + pPLL->inputFreq * pPLL->FRAC / fifteenPower) / vcoPower; + + /* Restore input frequency from Khz to hz unit */ + pPLL->inputFreq *= 1000; + pllClk *= 1000; + + return pllClk; +} + +/* + * Given a requested clock frequency, this function calculates the + * best INT, FRAC, VCO and BS values for the PLL. + * + * Input: Requested pixel clock in Hz unit. + * The followiing fields of PLL has to be set up properly: + * pPLL->inputFreq. + * + * Output: Update the PLL structure with the proper values + * Return: The actual clock in Hz that the PLL is able to set up. + * + */ +unsigned long ddk768_calcPllValue( +unsigned long ulRequestClk, /* Required pixel clock in Hz unit */ +pll_value_t *pPLL /* Structure to hold the value to be set in PLL */ +) +{ + + unsigned long INTEGER, FRAC, VCO, diff, pllClk, vcoPower, tempRequestClk; + unsigned long bestDiff = 0xffffffff; /* biggest 32 bit unsigned number */ + unsigned long fifteenPower = ddk768_twoToPowerOfx(15); /* 2^15 */ + + /* Init PLL structure to known states */ + pPLL->INT = 0; + pPLL->FRAC = 0; + pPLL->VCO = 0; + pPLL->BS = 0; + + /* Convert everything in Khz range in order to avoid calculation overflow */ + pPLL->inputFreq /= 1000; + tempRequestClk = ulRequestClk / 1000; + + /* If the requested clock is higher than 1 GHz, then set it to the maximum, which is + 1 GHz. */ + if (tempRequestClk > MHz(1)) + tempRequestClk = MHz(1); + + /* The maximum of VCO is 5. */ + for (VCO=0; VCO<=5; VCO++) + { + /* Work out 2 to the power of (VCO + 1) */ + vcoPower = ddk768_twoToPowerOfx(VCO + 1); + + INTEGER = tempRequestClk * vcoPower / pPLL->inputFreq; + + /* 28 <= INT <= 56 */ + if ((INTEGER >= 28) && (INTEGER <=56)) + { + /* FRAC = (requestClk * vcoPower / inputFreq - INT ) * (2^15) + Use formula as following to avoid decimal calculation: + FRAC = (requestClk * vcoPower - INT * inputFreq) * (2^15) / inputFreq + */ + FRAC = ((tempRequestClk * vcoPower) - (INTEGER * pPLL->inputFreq)) * fifteenPower / pPLL->inputFreq; + + /* FRAC field has 15 bits, reject value bigger than 15 bits */ + if (FRAC < FRAC_MAX) + { + /* Calculate the actual clock for a given INT & FRAC */ + pllClk = (pPLL->inputFreq * INTEGER + pPLL->inputFreq * FRAC / fifteenPower) / vcoPower; + + /* How much are we different from the requirement */ + diff = ddk768_absDiff(pllClk, tempRequestClk); + + if (diff < bestDiff) + { + bestDiff = diff; + + /* Store INT and FRAC values */ + pPLL->INT = INTEGER; + pPLL->FRAC = FRAC; + pPLL->VCO = VCO; + } + } + } + } + + /* Calculate BS value */ + if ((pPLL->INT >= 28) && (pPLL->INT < 35)) + { + pPLL->BS = 0; + } + else if ((pPLL->INT >=35) && (pPLL->INT < 42)) + { + pPLL->BS = 1; + } + else if ((pPLL->INT >= 42) && (pPLL->INT < 49)) + { + pPLL->BS = 2; + } + else if ((pPLL->INT >= 49) && (pPLL->INT <= 56)) + { + pPLL->BS = 3; + } + + /* Restore input frequency from Khz to hz unit */ + pPLL->inputFreq *= 1000; +#if 0 + /* Output debug information */ + DDKDEBUGPRINT((DISPLAY_LEVEL, "calcPllValue: Requested Frequency = %d\n", ulRequestClk)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "calcPllValue: Input CLK = %dHz, INT=%d, FRAC=%d, VCO=%d, BS=%d\n", + pPLL->inputFreq, pPLL->INT, pPLL->FRAC, pPLL->VCO, pPLL->BS)); +#endif + /* Return actual frequency that the PLL can set */ + return ddk768_calcPLL(pPLL); + + +} + +/* + * Set up the corresponding bit field of the programmable PLL register. + * + * Input: Pointer to PLL structure with all values set up properly. + * + */ +unsigned long ddk768_formatPllReg(pll_value_t *pPLL) +{ + + unsigned long ulPllReg = 0; + + /* Note that all PLL's have the same format. Here, we just use Panel PLL parameter + to work out the bit fields in the register. + On returning a 32 bit number, the value can be applied to any PLL in the calling function. + */ + ulPllReg = + FIELD_SET(0, VCLK_PLL, FN, FRAC_MODE) + | FIELD_VALUE(0, VCLK_PLL, BS, pPLL->BS) + | FIELD_VALUE(0, VCLK_PLL, VCO, pPLL->VCO) + | FIELD_VALUE(0, VCLK_PLL, INT, pPLL->INT) + | FIELD_VALUE(0, VCLK_PLL, FRAC, pPLL->FRAC); + + return(ulPllReg); + +} + + + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_clock.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_clock.h new file mode 100644 index 000000000000..a8e59634fdab --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_clock.h @@ -0,0 +1,66 @@ +/******************************************************************* +* +* Copyright (c) 2016 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* CLOCK.H --- Falcon DDK +* +*******************************************************************/ +#ifndef _DDK768_CLOCK_H_ +#define _DDK768_CLOCK_H_ + +#define MHz(x) (x*1000000) /* Don't use this macro if x is fraction number */ + + +#define GHz(x) (x*1000000000) //1000000000HZ = 1(Ghz) +#define FRAC_MAX 32768 + +typedef struct pll_value_t +{ + unsigned long inputFreq; /* Input clock frequency to the PLL */ + unsigned long INT; + unsigned long FRAC; + unsigned long VCO; + unsigned long BS; +} +pll_value_t; + +/* + * Given a requested clock frequency, this function calculates the + * best INT, FRAC, VCO and BS values for the PLL. + * + * Input: Requested pixel clock in Hz unit. + * The followiing fields of PLL has to be set up properly: + * pPLL->inputFreq. + * + * Output: Update the PLL structure with the proper values + * Return: The actual clock in Hz that the PLL is able to set up. + * + */ +unsigned long ddk768_calcPllValue( +unsigned long ulRequestClk, /* Required pixel clock in Hz unit */ +pll_value_t *pPLL /* Structure to hold the value to be set in PLL */ +); + +/* + * Set up the corresponding bit field of the programmable PLL register. + * + * Input: Pointer to PLL structure with all values set up properly. + * + */ +unsigned long ddk768_formatPllReg(pll_value_t *pPLL); + +/* + This funtion sets up pixel clock for Falcon FPGA. + Final product will have another PLL clock. +*/ + +long ddk768_setVclock(unsigned dispCtrl, unsigned long pixelClock); + + + + + +#endif /*_CLOCK_H_*/ diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_cursor.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_cursor.c new file mode 100644 index 000000000000..30a08028e1e7 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_cursor.c @@ -0,0 +1,100 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* CURSOR.C --- Voyager GX SDK +* This file contains the definitions for the Panel cursor functions. +* +*******************************************************************/ +#include "ddk768.h" + +#include "ddk768_cursor.h" + +/* + * This function initializes the cursor attributes. + */ +void ddk768_initCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long base, /* Base Address */ + unsigned long color1, /* Cursor color 1 in RGB 5:6:5 format */ + unsigned long color2, /* Cursor color 2 in RGB 5:6:5 format */ + unsigned long color3 /* Cursor color 3 in RGB 5:6:5 format */ +) +{ + /* + * 1. Set the cursor source address + */ + pokeRegisterDWord( + (dispControl == CHANNEL0_CTRL) ? CHANNEL0_HWC_ADDRESS : CHANNEL1_HWC_ADDRESS, + FIELD_VALUE(0, CHANNEL0_HWC_ADDRESS, ADDRESS, base)); + + /* + * 2. Set the cursor color composition + */ + pokeRegisterDWord( + (dispControl == CHANNEL0_CTRL) ? CHANNEL0_HWC_COLOR_0 : CHANNEL1_HWC_COLOR_0, + FIELD_VALUE(0, CHANNEL0_HWC_COLOR_0, RGB888, color1)); + + pokeRegisterDWord( + (dispControl == CHANNEL0_CTRL) ? CHANNEL0_HWC_COLOR_1 : CHANNEL1_HWC_COLOR_1, + FIELD_VALUE(0, CHANNEL0_HWC_COLOR_1, RGB888, color2)); + +} + +/* + * This function sets the cursor position. + */ +void ddk768_setCursorPosition( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long dx, /* X Coordinate of the cursor */ + unsigned long dy, /* Y Coordinate of the cursor */ + unsigned char topOutside, /* Top Boundary Select: either partially outside (= 1) + or within the screen top boundary (= 0) */ + unsigned char leftOutside /* Left Boundary Select: either partially outside (= 1) + or within the screen left boundary (= 0) */ +) +{ + unsigned long value; + + /* Set the XY coordinate */ + value = FIELD_VALUE(0, HWC_LOCATION, X, dx) | + FIELD_VALUE(0, HWC_LOCATION, Y, dy); + + /* Set the top boundary select either partially outside the top boundary + screen or inside */ + if (topOutside) + value = FIELD_SET(value, HWC_LOCATION, TOP, OUTSIDE); + else + value = FIELD_SET(value, HWC_LOCATION, TOP, INSIDE); + + /* Set the left boundary select either partially outside the left boundary + screen or inside */ + if (leftOutside) + value = FIELD_SET(value, HWC_LOCATION, LEFT, OUTSIDE); + else + value = FIELD_SET(value, HWC_LOCATION, LEFT, INSIDE); + + /* Set the register accordingly, either Panel cursor or CRT cursor */ + pokeRegisterDWord((dispControl == CHANNEL0_CTRL) ? HWC_LOCATION : (HWC_LOCATION+CHANNEL_OFFSET), value); +} + +/* + * This function enables/disables the cursor. + */ +void ddk768_enableCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long mode /* Cursor type - 00 disable, 0x01 mask cursor, 0x02 mono, 0x03 alpha cursor */ +) +{ + unsigned long cursorRegister, value; + + cursorRegister = (dispControl == CHANNEL0_CTRL) ? HWC_CONTROL : (HWC_CONTROL+CHANNEL_OFFSET); + + value = peekRegisterDWord(cursorRegister); + value = FIELD_VALUE(value, HWC_CONTROL, MODE, mode); + + pokeRegisterDWord(cursorRegister, value); +} diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_cursor.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_cursor.h new file mode 100644 index 000000000000..59afd2990675 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_cursor.h @@ -0,0 +1,54 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* cursor.h --- SMI DDK +* This file contains the definitions for the cursor functions. +* +*******************************************************************/ +#ifndef _DDK768_CURSOR_H_ +#define _DDK768_CURSOR_H_ + +#include "ddk768_mode.h" + +#define CURSOR_DISABLE 0x00 +#define CURSOR_ALPHA 0x01 +#define CURSOR_MONO 0x02 +#define CURSOR_MASK 0x03 + +/* + * This function initializes the cursor attributes. + */ +void ddk768_initCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long base, /* Base Address */ + unsigned long color1, /* Cursor color 1 in RGB 5:6:5 format */ + unsigned long color2, /* Cursor color 2 in RGB 5:6:5 format */ + unsigned long color3 /* Cursor color 3 in RGB 5:6:5 format */ +); + +/* + * This function sets the cursor position. + */ +void ddk768_setCursorPosition( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long dx, /* X Coordinate of the cursor */ + unsigned long dy, /* Y Coordinate of the cursor */ + unsigned char topOutside, /* Top Boundary Select: either partially outside (= 1) + or within the screen top boundary (= 0) */ + unsigned char leftOutside /* Left Boundary Select: either partially outside (= 1) + or within the screen left boundary (= 0) */ +); + +/* + * This function enables/disables the cursor. + */ +void ddk768_enableCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long enable +); + +#endif /* _CURSOR_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_display.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_display.c new file mode 100644 index 000000000000..de8c6cebcd62 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_display.c @@ -0,0 +1,850 @@ +#include "ddk768_reg.h" + + +#include "ddk768_chip.h" +#include "ddk768_power.h" +#include "ddk768_display.h" +#include "ddk768_timer.h" + +#include "ddk768_help.h" + + + +/* Monitor Detection RGB Default Threshold values */ +#define DEFAULT_MON_DETECTION_THRESHOLD 0x64 + +/* + * This function initializes the display. + * + * Output: + * 0 - Success + * 1 - Fail + */ +long initDisplay() +{ +#if 0 + /* set 80024[30:28] and 88024[30:28] to 0x3 in order for the DAC to output stronger signal. */ + unsigned long value; + value = peekRegisterDWord(CRT_DETECT); + value &= 0xCFFFFFFF; + value |= 0x30000000; + pokeRegisterDWord(CRT_DETECT, value); + value = peekRegisterDWord(CRT_DETECT + CHANNEL_OFFSET); + value &= 0xCFFFFFFF; + value |= 0x30000000; + pokeRegisterDWord(CRT_DETECT + CHANNEL_OFFSET, value); +#endif + return 0; + +} + +/* New for Falcon: DPMS control is moved to display controller. + * This function sets the display DPMS state + * It is used to set CRT monitor to On, off, or suspend states, + * while display channel are still active. + */ +void setDisplayDPMS( + disp_control_t dispControl, /* Channel 0 or Channel 1) */ + DISP_DPMS_t state /* DPMS state */ + ) +{ + unsigned long ulDispCtrlAddr; + unsigned long ulDispCtrlReg; + + /* Get the control register for channel 0 or 1. */ + ulDispCtrlAddr = (dispControl == CHANNEL0_CTRL)? DISPLAY_CTRL : (DISPLAY_CTRL+CHANNEL_OFFSET); + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + + switch (state) + { + case DISP_DPMS_ON: + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DPMS, VPHP); + break; + + case DISP_DPMS_STANDBY: + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DPMS, VPHN); + break; + + case DISP_DPMS_SUSPEND: + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DPMS, VNHP); + break; + + case DISP_DPMS_OFF: + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DPMS, VNHN); + break; + } + + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); +} + +/* + * New for Falcon. + * This funciton configures: + * 1. Output from channel 0 or channel 1 is 24 single or 48 double pixel. + * 2. Output data comes from data path of channel 0 or channel 1. + * + * Input: See the commnet in the input parameter below. + * + * Return: 0 is OK, -1 is error. + */ +long setDisplayFormat( + disp_control_t outputInterface, /* Use the output of channel 0 or 1 */ + disp_control_t dataPath, /* Use the data path from channel 0 or 1 */ + disp_format_t dispFormat /* 24 bit single or 48 bit double pixel */ + ) +{ + unsigned long ulDispCtrlAddr, ulDispCtrlReg; + + ulDispCtrlAddr = (outputInterface == CHANNEL0_CTRL)? DISPLAY_CTRL : (DISPLAY_CTRL+CHANNEL_OFFSET); + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + + if (dispFormat == DOUBLE_PIXEL_48BIT) + { + if (dataPath == CHANNEL0_CTRL) + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, CHANNEL_OUTPUT_FORMAT, CHANNEL0_48BIT); + else + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, CHANNEL_OUTPUT_FORMAT, CHANNEL1_48BIT); + + // When in 48 bit mode, enable double pixel clock + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, ENABLE); + } + else + { + if (dataPath == CHANNEL0_CTRL) + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, CHANNEL_OUTPUT_FORMAT, CHANNEL0_24BIT); + else + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, CHANNEL_OUTPUT_FORMAT, CHANNEL1_24BIT); + + // When in 24 bit mode, disable double pixel. + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, DISABLE); + } + + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + + return 0; +} + +/* + * Wait number of Vertical Vsync + * + * Input: + * dispControl - Display Control (either channel 0 or 1) + * vSyncCount - Number of vertical sync to wait. + * + * Note: + * This function is waiting for the next vertical sync. + */ +void waitDispVerticalSync(disp_control_t dispControl, unsigned long vSyncCount) +{ + unsigned long ulDispCtrlAddr; + unsigned long status; + unsigned long ulLoopCount = 0; + static unsigned long ulDeadLoopCount = 10; + + if (dispControl == CHANNEL0_CTRL) + { + // There is no Vsync when PLL is off + if ((FIELD_GET(peekRegisterDWord(CLOCK_ENABLE), CLOCK_ENABLE, DC0) == CLOCK_ENABLE_DC0_OFF)) + return; + + ulDispCtrlAddr = DISPLAY_CTRL; + } + else + { + // There is no Vsync when PLL is off + if ((FIELD_GET(peekRegisterDWord(CLOCK_ENABLE), CLOCK_ENABLE, DC1) == CLOCK_ENABLE_DC1_OFF)) + return; + + ulDispCtrlAddr = DISPLAY_CTRL+CHANNEL_OFFSET; + } + + //There is no Vsync when display timing is off. + if ((FIELD_GET(peekRegisterDWord(ulDispCtrlAddr), DISPLAY_CTRL, TIMING) == + DISPLAY_CTRL_TIMING_DISABLE)) + { + return; + } + + /* Count number of Vsync. */ + while (vSyncCount-- > 0) + { + /* If VSync is active when entering this function. Ignore it and + wait for the next. + */ + ulLoopCount = 0; + do + { + status = FIELD_GET(peekRegisterDWord(ulDispCtrlAddr), DISPLAY_CTRL, VSYNC); + //Insert delay to reduce number of Vsync checks + timerWaitTicks(3, 0xffff); + if(ulLoopCount++ > ulDeadLoopCount) break; + } + while (status == DISPLAY_CTRL_VSYNC_ACTIVE); + + /* Wait for end of vsync or timeout */ + ulLoopCount = 0; + do + { + status = FIELD_GET(peekRegisterDWord(ulDispCtrlAddr), DISPLAY_CTRL, VSYNC); + timerWaitTicks(3, 0xffff); + if(ulLoopCount++ > ulDeadLoopCount) break; + } + while (status == DISPLAY_CTRL_VSYNC_INACTIVE); + } +} + +/* + * Use panel vertical sync line as time delay function. + * This function does not wait for the next VSync. Instead, it will wait + * until the current line reaches the Vertical Sync line. + * This function is really useful when flipping display to prevent tearing. + * + * Input: display control (CHANNEL0_CTRL or CHANNEL1_CTRL) + */ +void ddk768_waitVSyncLine(disp_control_t dispControl) +{ + unsigned long ulDispCtrlAddr; + unsigned long value; + mode_parameter_t modeParam; + + ulDispCtrlAddr = (dispControl == CHANNEL0_CTRL)? CURRENT_LINE : (CURRENT_LINE+CHANNEL_OFFSET); + + /* Get the current mode parameter of the specific display control */ + modeParam = ddk768_getCurrentModeParam(dispControl); + + do + { + value = FIELD_GET(peekRegisterDWord(ulDispCtrlAddr), CURRENT_LINE, LINE); + } + while (value < modeParam.vertical_sync_start); +} + +/* + * Get current display line number + */ +__attribute__((unused)) static unsigned long getDisplayLine(disp_control_t dispControl) +{ + unsigned long ulRegAddr; + unsigned long ulRegValue; + + ulRegAddr = (dispControl == CHANNEL0_CTRL)? CURRENT_LINE : (CURRENT_LINE+DC_OFFSET); + ulRegValue = FIELD_GET(peekRegisterDWord(ulRegAddr), CURRENT_LINE, LINE); + + return(ulRegValue); +} + +/* + * This functions uses software sequence to turn on/off the panel of the digital interface. + */ +void ddk768_swPanelPowerSequence(disp_control_t dispControl, disp_state_t dispState, unsigned long vSyncDelay) +{ + unsigned long ulDispCtrlAddr; + unsigned long ulDispCtrlReg; + + + ulDispCtrlAddr = (dispControl == CHANNEL0_CTRL)? DISPLAY_CTRL : (DISPLAY_CTRL+CHANNEL_OFFSET); + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + + if (dispState == DISP_ON) + { + //If bit 27:24 are already ON. Don't need to set them again + //because setting panel seq is time consuming. + if ((ulDispCtrlReg & 0x0f000000) == 0x0f000000) return; + + /* Turn on FPVDDEN. */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, FPVDDEN, HIGH); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + waitDispVerticalSync(dispControl, vSyncDelay); + + /* Turn on FPDATA. */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DATA, ENABLE); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + waitDispVerticalSync(dispControl, vSyncDelay); + + /* Turn on FPVBIAS. */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, VBIASEN, HIGH); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + waitDispVerticalSync(dispControl, vSyncDelay); + + /* Turn on FPEN. */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, FPEN, HIGH); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + } + else + { + //If bit 27:24 are already OFF. Don't need to clear them again. + if ((ulDispCtrlReg & 0x0f000000) == 0x00000000) return; + + /* Turn off FPEN. */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, FPEN, LOW); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + waitDispVerticalSync(dispControl, vSyncDelay); + + + /* Turn off FPVBIASEN. */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, VBIASEN, LOW); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + waitDispVerticalSync(dispControl, vSyncDelay); + + /* Turn off FPDATA. */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DATA, DISABLE); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + waitDispVerticalSync(dispControl, vSyncDelay); + + /* Turn off FPVDDEN. */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, FPVDDEN, LOW); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + } + +} + +/* + * This function turns on/off the DAC for CRT display control. + * Input: On or off + */ +void ddk768_setDAC(disp_state_t state) +{ + +#if 1 + /* Cheok(10/16/2013): For Falcon, DAC definition not exist yet.*/ + +#else + if (state == DISP_ON) + { + pokeRegisterDWord(MISC_CTRL, FIELD_SET(peekRegisterDWord(MISC_CTRL), + MISC_CTRL, + DAC_POWER, + ON)); + } + else + { + pokeRegisterDWord(MISC_CTRL, FIELD_SET(peekRegisterDWord(MISC_CTRL), + MISC_CTRL, + DAC_POWER, + OFF)); + } +#endif +} + +/* + * This function turns on/off the display control of Channel 0 or channel 1. + * + * Note: + * Turning on/off the timing and the plane requires programming sequence. + * The plane can not be changed without turning on the timing. However, + * changing the plane has no effect when the timing (clock) is off. Below, + * is the description of the timing and plane combination setting. + */ +//Cheok(10/18/2013): New function similar to setDisplayControl() +void ddk768_setDisplayEnable( + disp_control_t dispControl, /* Channel 0 or Channel 1) */ + disp_state_t dispState /* ON or OFF */ +) +{ + unsigned long ulDispCtrlAddr; + unsigned long ulDispCtrlReg; + + ulDispCtrlAddr = (dispControl == CHANNEL0_CTRL)? DISPLAY_CTRL : (DISPLAY_CTRL+CHANNEL_OFFSET); + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + + + + /* Turn on/off the Panel display control */ + if (dispState == DISP_ON) + { + /* Timing should be enabled first before enabling the plane because changing at the + same time does not guarantee that the plane will also enabled or disabled. + */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, TIMING, ENABLE); + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DIRECTION, INPUT); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, PLANE, ENABLE)| + FIELD_SET(0, DISPLAY_CTRL, DATA_PATH, EXTENDED); + + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + } + else + { + /* When turning off, there is no rule on the programming sequence since whenever the + clock is off, then it does not matter whether the plane is enabled or disabled. + Note: Modifying the plane bit will take effect on the next vertical sync. Need to + find out if it is necessary to wait for 1 vsync before modifying the timing + enable bit. + */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, PLANE, DISABLE); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, TIMING, DISABLE); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + + } + + +} + + +/* + * This function set display channel data direction. + * + */ + +__attribute__((unused)) static void setDataDirection( + disp_control_t dispControl, /* Channel 0 or Channel 1) */ + disp_state_t dispState /* ON or OFF */ +) +{ + unsigned long ulDispCtrlAddr; + unsigned long ulDispCtrlReg; + if (dispState == DISP_ON) + { + ulDispCtrlAddr = (dispControl == CHANNEL0_CTRL)? DISPLAY_CTRL : (DISPLAY_CTRL+CHANNEL_OFFSET); + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + + /*set data direction */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DIRECTION, INPUT); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + + + } +} + + + + +/* + * This function detects if the CRT monitor is attached. + * + * Input: + * redValue - Threshold value to be detected on the red color. + * greenValue - Threshold value to be detected on the green color. + * blueValue - Threshold value to be detected on the blue color. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_detectCRTMonitor( + disp_control_t dispControl, + unsigned char redValue, + unsigned char greenValue, + unsigned char blueValue +) +{ + unsigned long ulMonitorDetectAddr; + unsigned long value = 0, red, green, blue; + long result = (-1); + + ulMonitorDetectAddr = (dispControl == CHANNEL0_CTRL)? CRT_DETECT : (CRT_DETECT+DC_OFFSET); + + /* Use the given red, green, and blue threshold value to detect the monitor or + default. */ + if (redValue != 0) + red = redValue; + else + red = DEFAULT_MON_DETECTION_THRESHOLD; + + if (greenValue != 0) + green = greenValue; + else + green = DEFAULT_MON_DETECTION_THRESHOLD; + + if (blueValue != 0) + blue = blueValue; + else + blue = DEFAULT_MON_DETECTION_THRESHOLD; + + /* Set the RGB Threshold value and enable the monitor detection. */ + value = FIELD_VALUE(0, CRT_DETECT, DATA_RED, red) | + FIELD_VALUE(0, CRT_DETECT, DATA_GREEN, green) | + FIELD_VALUE(0, CRT_DETECT, DATA_BLUE, blue) | + FIELD_SET(value, CRT_DETECT, ENABLE, ENABLE); + pokeRegisterDWord(ulMonitorDetectAddr, value); + + /* Add some delay here. Otherwise, the detection is not stable. + SM768 has internal timer. It's better than SW countdown loop. + */ + timerWaitTicks(3, 0x7ffff); + + /* Check if the monitor is detected. */ + if (FIELD_GET(peekRegisterDWord(ulMonitorDetectAddr), CRT_DETECT, CRT) == + CRT_DETECT_CRT_PRESENT) + { + result = 0; + } + + /* Disable the Monitor Detect Enable bit. Somehow, enabling this bit will + cause the CRT to lose display. */ + value = peekRegisterDWord(ulMonitorDetectAddr); + value = FIELD_SET(value, CRT_DETECT, ENABLE, DISABLE); + pokeRegisterDWord(ulMonitorDetectAddr, value); + + return result; +} + + +/* + * This function controls monitor on/off and data path. + * It can be used to set up any veiws: single view, clone view, dual view, output with channel swap, etc. + * However, it needs too many input parameter. + * There are other set view functions with less parameters, but not as flexible as this one. + * + */ +long setDisplayView( + disp_control_t dispOutput, /* Monitor 0 or 1 */ + disp_state_t dispState, /* On or off */ + disp_control_t dataPath, /* Use the data path of channel 0 or channel 1 (optional when OFF) */ + disp_format_t dispFormat) /* 24 or 48 bit digital interface (optional when OFF */ +{ + + ddk768_setDisplayEnable(dispOutput, dispState); /* Enable or disable Channel output timing */ + ddk768_swPanelPowerSequence(dispOutput, dispState, 4); /* Turn on or off output power */ + setDisplayFormat(dispOutput, dataPath, dispFormat); /* Set dataPath and output pixel format */ + +#if 0 + if (dispState == DISP_ON) + setDisplayDPMS(dispOutput, DISP_DPMS_ON); /* DPMS on */ +#endif + return 0; +} + +/* + * Convenient function to trun on single view + */ +long setSingleViewOn(disp_control_t dispOutput) +{ + setDisplayView( + dispOutput, /* Output monitor */ + DISP_ON, /* Turn On */ + dispOutput, /* Assume monitor 0 is using data path 0, and monitor 1 is using data path 1 */ + SINGLE_PIXEL_24BIT); /* Default to 24 bit single pixel, the most used case */ + + return 0; +} + +/* + * Convenient function to trun off single view + */ +long setSingleViewOff(disp_control_t dispOutput) +{ + setDisplayView( + dispOutput, /* Output monitor */ + DISP_OFF, /* Turn Off */ + dispOutput, /* Assume monitor 0 is using data path 0, and monitor 1 is using data path 1 */ + SINGLE_PIXEL_24BIT); /* Default to 24 bit single pixel, the most used case */ + + return 0; +} + +/* + * Convenient function to trun on clone view + */ +long setCloneViewOn(disp_control_t dataPath) +{ + setDisplayView( + CHANNEL0_CTRL, /* For Clone view, monitor 0 has to be ON */ + DISP_ON, + dataPath, /* Use this data path for monitor 0 */ + SINGLE_PIXEL_24BIT); /* Default to 24 bit single pixel, the most used case */ + + setDisplayView( + CHANNEL1_CTRL, /* For Clone view, monitor 1 has to be ON */ + DISP_ON, + dataPath, /* Use this data path for monitor 1 */ + SINGLE_PIXEL_24BIT); /* Default to 24 bit single pixel, the most used case */ + + return 0; +} + +/* + * Convenient function to trun on dual view + */ +long setDualViewOn() +{ + setSingleViewOn(CHANNEL0_CTRL); + setSingleViewOn(CHANNEL1_CTRL); + + return 0; +} + +/* + * Convenient function to trun off all views + */ +long setAllViewOff() +{ + setSingleViewOff(CHANNEL0_CTRL); /* Turn Off monitor 0 */ + setSingleViewOff(CHANNEL1_CTRL); /* Turn Off monitor 1 */ + + return 0; +} + +/* + * Disable double pixel clock. + * This is a temporary function, used to patch for the random fuzzy font problem. + */ +void DisableDoublePixel(disp_control_t dispControl) +{ + unsigned long ulDispCtrlAddr; + unsigned long ulDispCtrlReg; + + if(dispControl == CHANNEL0_CTRL) { + ulDispCtrlAddr = DISPLAY_CTRL; + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, DISABLE); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + }else{ + ulDispCtrlAddr = DISPLAY_CTRL+CHANNEL_OFFSET; + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, DISABLE); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + } +} + + + + +void EnableDoublePixel(disp_control_t dispControl) +{ + unsigned long ulDispCtrlAddr; + unsigned long ulDispCtrlReg; + + if(dispControl == CHANNEL0_CTRL) { + ulDispCtrlAddr = DISPLAY_CTRL; + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, ENABLE); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + }else{ + ulDispCtrlAddr = DISPLAY_CTRL+CHANNEL_OFFSET; + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, ENABLE); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + } +} + +void enableLVDS( + unsigned short lvds, //LVDS 1 or 2 + unsigned short on //On =1, and off = 0 +) +{ + unsigned long ulTmpValue; + + ulTmpValue = peekRegisterDWord(LVDS_CTRL2); + + if (lvds == 1) + { + ulTmpValue &= FIELD_CLEAR(LVDS_CTRL2, PD_PLL1); + if (!on) + ulTmpValue |= FIELD_SET(0, LVDS_CTRL2, PD_PLL1, DOWN); + } + else + { + ulTmpValue &= FIELD_CLEAR(LVDS_CTRL2, PD_PLL2); + if (!on) + ulTmpValue |= FIELD_SET(0, LVDS_CTRL2, PD_PLL2, DOWN); + } + + pokeRegisterDWord(LVDS_CTRL2, ulTmpValue); +} + + + +void setupLVDS(unsigned short lvds) +{ + unsigned long ulTmpValue; + + /* Set lvds control register 0x80020 */ + // Program 0x80020 + // bit 31:30 = 00 binary + //bit 29:23 = 0x63 + //bit 22:16 = 0x63 + ulTmpValue = 0; + ulTmpValue |= + FIELD_SET(0, LVDS_CTRL1, CLKSEL_PLL2, RE) + | FIELD_SET(0, LVDS_CTRL1, CLKSEL_PLL1, RE) + | FIELD_SET(0, LVDS_CTRL1, DCLK2, DEFAULT) + | FIELD_SET(0, LVDS_CTRL1, DCLK1, DEFAULT); + + pokeRegisterDWord(LVDS_CTRL1, ulTmpValue); + + /* Set lvds control register 0x8002c */ + //Program 0x8002c + // bit 31 to 0 = 0x750fed0e + ulTmpValue = 0; + ulTmpValue |= + FIELD_SET(0, LVDS_CTRL2, SHTDNB2, NORMAL) + | FIELD_SET(0, LVDS_CTRL2, SHTDNB1, NORMAL) + | FIELD_SET(0, LVDS_CTRL2, CLK2_DS, 5MA) + | FIELD_SET(0, LVDS_CTRL2, CLK1_DS, 5MA) + | FIELD_SET(0, LVDS_CTRL2, DS, 5MA) + | FIELD_SET(0, LVDS_CTRL2, CLK2_TR, 0) + | FIELD_SET(0, LVDS_CTRL2, CLK1_TR, 0) + | FIELD_SET(0, LVDS_CTRL2, TR, 0) + | FIELD_SET(0, LVDS_CTRL2, CLK2_COMP, 3) + | FIELD_SET(0, LVDS_CTRL2, CLK1_COMP, 3) + | FIELD_SET(0, LVDS_CTRL2, PRE_COMP, 3) + | FIELD_SET(0, LVDS_CTRL2, VCOS_PLL2, 350M) + | FIELD_SET(0, LVDS_CTRL2, VCOS_PLL1, 350M) + | FIELD_SET(0, LVDS_CTRL2, SHORTS_PLL2, 2048) + | FIELD_SET(0, LVDS_CTRL2, SHORTS_PLL1, 2048) + | FIELD_SET(0, LVDS_CTRL2, PD_PLL2, DOWN) + | FIELD_SET(0, LVDS_CTRL2, PD_PLL1, DOWN) + | FIELD_SET(0, LVDS_CTRL2, MODESEL2, DC1) + | FIELD_SET(0, LVDS_CTRL2, MODESEL1, DC0); + + pokeRegisterDWord(LVDS_CTRL2, ulTmpValue); +} + +/* + * Set up 48 bit LVDS output with the input DC channel. + */ +long set48bitLVDS(disp_control_t dataPath) +{ + unsigned long ulTmpValue; + unsigned long offset; + + offset = (dataPath==CHANNEL0_CTRL)? 0 : CHANNEL_OFFSET; + + // Set Display Control for dual lvds + ulTmpValue = peekRegisterDWord(DISPLAY_CTRL+offset) + & FIELD_CLEAR(DISPLAY_CTRL, LVDS_OUTPUT_FORMAT) + & FIELD_CLEAR(DISPLAY_CTRL, PIXEL_CLOCK_SELECT) + & FIELD_CLEAR(DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK); + + + // Program 0x80000 + // bit 17:16 = 10 binary + // bit 15 = 1 + // bit 11 = 1 + if (offset) + ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, LVDS_OUTPUT_FORMAT, CHANNEL1_48BIT); + else + ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, LVDS_OUTPUT_FORMAT, CHANNEL0_48BIT); + + ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, PIXEL_CLOCK_SELECT, HALF); + ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, ENABLE); + + ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_LOW); ////DP and dual chanel LVDS shuold set to low + + pokeRegisterDWord(DISPLAY_CTRL+offset, ulTmpValue); + + // For 48 bit output, the other channel has to set up properly as well. + if (offset) //If data path is DC1, set DC0 + { + ulTmpValue = peekRegisterDWord(DISPLAY_CTRL) & FIELD_CLEAR(DISPLAY_CTRL, LVDS_OUTPUT_FORMAT); + + // Program 0x80000 + // bit 17:16 = 3 + ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, LVDS_OUTPUT_FORMAT, CHANNEL1_48BIT); + + pokeRegisterDWord(DISPLAY_CTRL, ulTmpValue); + } + else // If data path is DC0, set DC1 + { + ulTmpValue = peekRegisterDWord(DISPLAY_CTRL+CHANNEL_OFFSET) & FIELD_CLEAR(DISPLAY_CTRL, LVDS_OUTPUT_FORMAT); + + // Program 0x88000 + // bit 17:16 = 2 + ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, LVDS_OUTPUT_FORMAT, CHANNEL0_48BIT); + + pokeRegisterDWord(DISPLAY_CTRL+CHANNEL_OFFSET, ulTmpValue); + } + + /* Set LVDS clock polarity */ + // Program 0x80024 + // bit 26 = 0 + ulTmpValue = peekRegisterDWord(CRT_DETECT+offset) + & FIELD_CLEAR(CRT_DETECT, LVDS_CLK); + + //printf( "0x80024 = %08x\n", ulTmpValue); + pokeRegisterDWord(CRT_DETECT+offset, ulTmpValue); + + setupLVDS(3); + + //Wait for LVDS PLL to settle before enable it. + waitDispVerticalSync(dataPath, 3); + + // program 0x8002c again + //bit 31:0 = 0x750fed02 + enableLVDS(1, 1); + enableLVDS(2, 1); + + return 0; +} + + + +/* + * Set up Single LVDS output with the input DC channel. + */ +long setSingleLVDS(disp_control_t dataPath) +{ + unsigned long ulTmpValue; + unsigned long offset; + + offset = (dataPath==CHANNEL0_CTRL)? 0 : CHANNEL_OFFSET; + + // Set Display Control for dual lvds + ulTmpValue = peekRegisterDWord(DISPLAY_CTRL+offset) + & FIELD_CLEAR(DISPLAY_CTRL, LVDS_OUTPUT_FORMAT) + & FIELD_CLEAR(DISPLAY_CTRL, PIXEL_CLOCK_SELECT) + & FIELD_CLEAR(DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK); + + // Program 0x80000 + // bit 17:16 = 10 binary + // bit 15 = 1 + // bit 11 = 1 + if (offset) + ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, LVDS_OUTPUT_FORMAT, CHANNEL1_24BIT); + else + ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, LVDS_OUTPUT_FORMAT, CHANNEL0_24BIT); + + + ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_HIGH); //others should set to high + pokeRegisterDWord(DISPLAY_CTRL+offset, ulTmpValue); + + // For 48 bit output, the other channel has to set up properly as well. + if (offset) //If data path is DC1, set DC0 + { + ulTmpValue = peekRegisterDWord(DISPLAY_CTRL) & FIELD_CLEAR(DISPLAY_CTRL, LVDS_OUTPUT_FORMAT); + + // Program 0x80000 + // bit 17:16 = 3 + ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, LVDS_OUTPUT_FORMAT, CHANNEL1_24BIT); + + pokeRegisterDWord(DISPLAY_CTRL, ulTmpValue); + } + else // If data path is DC0, set DC1 + { + ulTmpValue = peekRegisterDWord(DISPLAY_CTRL+CHANNEL_OFFSET) & FIELD_CLEAR(DISPLAY_CTRL, LVDS_OUTPUT_FORMAT); + + // Program 0x88000 + // bit 17:16 = 2 + ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, LVDS_OUTPUT_FORMAT, CHANNEL0_24BIT); + + pokeRegisterDWord(DISPLAY_CTRL+CHANNEL_OFFSET, ulTmpValue); + } + + /* Set LVDS clock polarity */ + // Program 0x80024 + // bit 26 = 0 + ulTmpValue = peekRegisterDWord(CRT_DETECT+offset) + & FIELD_CLEAR(CRT_DETECT, LVDS_CLK); + + //printf( "0x80024 = %08x\n", ulTmpValue); + pokeRegisterDWord(CRT_DETECT+offset, ulTmpValue); + + setupLVDS(3); + + //Wait for LVDS PLL to settle before enable it. + waitDispVerticalSync(dataPath, 3); + + // program 0x8002c again + //bit 31:0 = 0x750fed02 + enableLVDS(1, 1); + enableLVDS(2, 1); + + return 0; +} + + + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_display.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_display.h new file mode 100644 index 000000000000..656afed726e9 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_display.h @@ -0,0 +1,216 @@ +#ifndef _DDK768_DISPLAY_H_ +#define _DDK768_DISPLAY_H_ +#include "ddk768_mode.h" +#include "../hw_com.h" + + +//Cheok: obsolete for Falcon, delete after old code cleans up. +typedef enum _disp_output_t +{ + NO_DISPLAY, /* All display off. */ + LCD1_ONLY, /* LCD1 only */ + LCD2_ONLY, /* LCD2 only */ + CRT2_ONLY, /* CRT2 only */ + LCD1_CRT2_SIMUL, /* Both LCD1 and CRT2 displaying the same content. */ + LCD1_LCD2_SIMUL, /* Both LCD1 and LCD2 displaying the same content. */ + CRT2_LCD2_SIMUL, /* CRT2 and LCD2 displaying the same content. */ + LCD1_LCD2_CRT2_SIMUL, /* LCD1, LCD2, and CRT2 displaying the same content. */ + LCD1_CRT2_DUAL, /* LCD1 and CRT2 displaying different contents. */ + LCD1_LCD2_DUAL, /* LCD1 and LCD2 displaying different contents. */ + LCD1_LCD2_CRT2_DUAL /* LCD2 and CRT2 displaying the same content while + the Panel displaying different content. */ +} +disp_output_t; + +//Cheok(10/172013): New interface for Falcon. +typedef enum _disp_interface_t +{ + DIGITAL_24BIT = 0, + DIGITAL_48BIT, + CRT, + LVDS, + HDMI +} +disp_interface_t; + +typedef enum _disp_format_t +{ + SINGLE_PIXEL_24BIT = 0, + DOUBLE_PIXEL_48BIT +} +disp_format_t; + + +/* + * This function initializes the display. + * + * Output: + * 0 - Success + * 1 - Fail + */ +long initDisplay(void); + +/* + * This function sets the display DPMS state + * It is used to set CRT monitor to On, off, or suspend states, + * while display channel are still active. + */ +void setDisplayDPMS( + disp_control_t dispControl, /* Channel 0 or Channel 1) */ + DISP_DPMS_t state /* DPMS state */ + ); + +/* + * This funciton sets: + * 1. Output from channel 0 or channel 1 is 24 single or 48 double pixel. + * 2. Output data comes from path of channel 0 or 1. + * + * Input: See the commnet in the input parameter below. + * + * Return: 0 is OK, -1 is error. + */ +long setDisplayFormat( + disp_control_t outputInterface, /* Use the output of channel 0 or 1 */ + disp_control_t dataPath, /* Use the data path from channel 0 or 1 */ + disp_format_t dispFormat /* 24 bit single or 48 bit double pixel */ + ); + +/* + * This functions sets the CRT Path. + */ +void setCRTPath(disp_control_t dispControl); + +/* + * This functions uses software sequence to turn on/off the panel. + */ +void ddk768_swPanelPowerSequence(disp_control_t dispControl, disp_state_t dispState, unsigned long vsync_delay); + +/* + * This functions uses software sequence to turn on/off the digital interface. + */ +void swDispPowerSequence(disp_control_t dispControl, disp_state_t dispState, unsigned long vSyncDelay); + +/* + * This function turns on/off the DAC for CRT display control. + * Input: On or off + */ +void ddk768_setDAC(disp_state_t state); + +/* + * Wait number of Vertical Vsync + * + * Input: + * dispControl - Display Control (either channel 0 or 1) + * vSyncCount - Number of vertical sync to wait. + * + * Note: + * This function is waiting for the next vertical sync. + */ +void waitDispVerticalSync(disp_control_t dispControl, unsigned long vSyncCount); + +/* + * Use panel vertical sync line as time delay function. + * This function does not wait for the next VSync. Instead, it will wait + * until the current line reaches the Vertical Sync line. + * This function is really useful when flipping display to prevent tearing. + * + * Input: display control (CHANNEL0_CTRL or CHANNEL1_CTRL) + */ +void ddk768_waitVSyncLine(disp_control_t dispControl); + +/* + * This function detects if the CRT monitor is attached. + * + * Input: + * redValue - Threshold value to be detected on the red color. + * greenValue - Threshold value to be detected on the green color. + * blueValue - Threshold value to be detected on the blue color. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_detectCRTMonitor( + disp_control_t dispControl, + unsigned char redValue, + unsigned char greenValue, + unsigned char blueValue +); + + + +/* + * This function turns on/off the display control of Channel 0 or channel 1. + * + * Note: + * Turning on/off the timing and the plane requires programming sequence. + * The plane can not be changed without turning on the timing. However, + * changing the plane has no effect when the timing (clock) is off. Below, + * is the description of the timing and plane combination setting. + */ +void ddk768_setDisplayEnable( +disp_control_t dispControl, /* Channel 0 or Channel 1) */ +disp_state_t dispState /* ON or OFF */ +); + +/* + * This function controls monitor on/off and data path. + * It can be used to set up any veiws: single view, clone view, dual view, output with channel swap, etc. + * However, it needs too many input parameter. + * There are other set view functions with less parameters, but not as flexible as this one. + * + */ +long setDisplayView( + disp_control_t dispOutput, /* Monitor 0 or 1 */ + disp_state_t dispState, /* On or off */ + disp_control_t dataPath, /* Use the data path of channel 0 or channel 1 (optional when OFF) */ + disp_format_t dispFormat); /* 24 or 48 bit digital interface (optional when OFF */ + +/* + * Convenient function to trun on single view + */ +long setSingleViewOn(disp_control_t dispOutput); + +/* + * Convenient function to trun off single view + */ +long setSingleViewOff(disp_control_t dispOutput); + +/* + * Convenient function to trun on clone view + */ +long setCloneViewOn(disp_control_t dataPath); + +/* + * Convenient function to trun on dual view + */ +long setDualViewOn(void); + +/* + * Convenient function to trun off all views + */ +long setAllViewOff(void); + + +/* + * Disable double pixel clock. + * This is a teporary function, used to patch for the random fuzzy font problem. + */ +void DisableDoublePixel(disp_control_t dispControl); +void EnableDoublePixel(disp_control_t dispControl); + + +void enableLVDS( + unsigned short lvds, //LVDS 1 or 2 + unsigned short on //On =1, and off = 0 +); + + +void setupLVDS(unsigned short lvds); + + +long set48bitLVDS(disp_control_t dataPath); +long setSingleLVDS(disp_control_t dataPath); + + +#endif /* _DISPLAY_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_edid.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_edid.c new file mode 100644 index 000000000000..9af61b40796a --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_edid.c @@ -0,0 +1,2145 @@ +/******************************************************************* +* +* Copyright (c) 2009 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* edid.c --- SM750/SM718 DDK +* This file contains functions to interpret the EDID structure. +* +*******************************************************************/ + +#include "ddk768_help.h" +#include "ddk768_helper.h" +#include "ddk768_hwi2c.h" +#include "ddk768_swi2c.h" +#include "ddk768_edid.h" + +#include "ddkdebug.h" + + +/* Enable this one to print the VDIF timing when debug is enabled. */ +//#define ENABLE_DEBUG_PRINT_VDIF + + +#define HEADER_EDID_REGISTERS 8 + +typedef struct _est_timing_mode_t +{ + unsigned long x; /* Mode Width */ + unsigned long y; /* Mode Height */ + unsigned long hz; /* Refresh Rate */ + unsigned char source; /* Source: 0 - VESA + 1 - IBM + 2 - Apple + */ +} +est_timing_mode_t; + +/* These values only applies to EDID Version 1 */ +static est_timing_mode_t establishTiming[3][8] = +{ + /* Established Timing 1 */ + { + { 800, 600, 60, 0}, + { 800, 600, 56, 0}, + { 640, 480, 75, 0}, + { 640, 480, 72, 0}, + { 640, 480, 67, 2}, + { 640, 480, 60, 1}, + { 720, 400, 88, 1}, + { 720, 400, 70, 1}, + }, + { + {1280, 1024, 75, 0}, + {1024, 768, 75, 0}, + {1024, 768, 70, 0}, + {1024, 768, 60, 0}, + {1024, 768, 87, 1}, + { 832, 624, 75, 0}, + { 800, 600, 75, 0}, + { 800, 600, 72, 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}, + {1152, 870, 75, 2}, + } +}; + +static void printVdif( + vdif_t *pVDIF +) +{ +#ifdef DDKDEBUG + +#ifndef ENABLE_DEBUG_PRINT_VDIF + DDKDEBUGENABLE(0); +#endif + + DDKDEBUGPRINT((DISPLAY_LEVEL, "pixelClock = %d\n", pVDIF->pixelClock)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "characterWidth = %d\n", pVDIF->characterWidth)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "scanType = %s\n", (pVDIF->scanType == VDIF_INTERLACED) ? "Interlaced" : "Progressive")); + + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalFrequency = %d\n", pVDIF->horizontalFrequency)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalTotal = %d\n", pVDIF->horizontalTotal)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalActive = %d\n", pVDIF->horizontalActive)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalBlankStart = %d\n", pVDIF->horizontalBlankStart)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalBlankTime = %d\n", pVDIF->horizontalBlankTime)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalSyncStart = %d\n", pVDIF->horizontalSyncStart)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalRightBorder = %d\n", pVDIF->horizontalRightBorder)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalFrontPorch = %d\n", pVDIF->horizontalFrontPorch)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalSyncWidth = %d\n", pVDIF->horizontalSyncWidth)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalBackPorch = %d\n", pVDIF->horizontalBackPorch)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalLeftBorder = %d\n", pVDIF->horizontalLeftBorder)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalSyncPolarity = %s\n", + (pVDIF->horizontalSyncPolarity == VDIF_SYNC_NEGATIVE) ? "Negative" : "Positive")); + + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalFrequency = %d\n", pVDIF->verticalFrequency)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalTotal = %d\n", pVDIF->verticalTotal)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalActive = %d\n", pVDIF->verticalActive)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBlankStart = %d\n", pVDIF->verticalBlankStart)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBlankTime = %d\n", pVDIF->verticalBlankTime)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalSyncStart = %d\n", pVDIF->verticalSyncStart)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBottomBorder = %d\n", pVDIF->verticalBottomBorder)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalFrontPorch = %d\n", pVDIF->verticalFrontPorch)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalSyncHeight = %d\n", pVDIF->verticalSyncHeight)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBackPorch = %d\n", pVDIF->verticalBackPorch)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalTopBorder = %d\n", pVDIF->verticalTopBorder)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalSyncPolarity = %s\n", + (pVDIF->verticalSyncPolarity == VDIF_SYNC_NEGATIVE) ? "Negative" : "Positive")); + +#ifndef ENABLE_DEBUG_PRINT_VDIF + DDKDEBUGENABLE(1); +#endif +#endif +} + +/* + * edidGetHeader + * This function gets the EDID Header + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 get header success; -1 fail. + */ +__attribute__((unused)) static unsigned char edidGetHeader( + unsigned char *pEDIDBuffer +) +{ + if (pEDIDBuffer != (unsigned char *)0) + { + /* Check the header */ + if ((pEDIDBuffer[0] == 0x00) && (pEDIDBuffer[1] == 0xFF) && (pEDIDBuffer[2] == 0xFF) && + (pEDIDBuffer[3] == 0xFF) && (pEDIDBuffer[4] == 0xFF) && (pEDIDBuffer[5] == 0xFF) && + (pEDIDBuffer[6] == 0xFF) && (pEDIDBuffer[7] == 0x00)) + { + return 0; + } + else + return -1; + } + + // DDKDEBUGPRINT((DISPLAY_LEVEL, "Invalid EDID bufffer\n")); + return -1; +} + +/* + * edidGetVersion + * This function gets the EDID version + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRevision - Revision of the EDIE (if exist) + * + * Output: + * Revision number of the given EDID buffer. + */ +unsigned char ddk768_edidGetVersion( + unsigned char *pEDIDBuffer, + unsigned char *pRevision +) +{ + unsigned char version; + + if (pEDIDBuffer != (unsigned char *)0) + { + /* Check the header */ + if ((pEDIDBuffer[0] == 0x00) && (pEDIDBuffer[1] == 0xFF) && (pEDIDBuffer[2] == 0xFF) && + (pEDIDBuffer[3] == 0xFF) && (pEDIDBuffer[4] == 0xFF) && (pEDIDBuffer[5] == 0xFF) && + (pEDIDBuffer[6] == 0xFF) && (pEDIDBuffer[7] == 0x00)) + { + /* + * EDID Structure Version 1. + */ + + /* Read the version field from the buffer. It should be 1 */ + version = pEDIDBuffer[18]; + + if (version == 1) + { + /* Copy the revision first */ + if (pRevision != (unsigned char *)0) + *pRevision = pEDIDBuffer[19]; + + return version; + } + } + else + { + /* + * EDID Structure Version 2 + */ + + /* Read the version and revision field from the buffer. */ + version = pEDIDBuffer[0]; + + if ((version >> 4) == 2) + { + /* Copy the revision */ + if (pRevision != (unsigned char *)0) + *pRevision = version & 0x0F; + + return (version >> 4); + } + } + } + + DDKDEBUGPRINT((DISPLAY_LEVEL, "Invalid EDID Structure\n")); + return 0; +} + +/* + * ddk768_edidGetProductInfo + * This function gets the vendor and product information. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor [in] + * pManufacturerName - Pointer to a 3 byte length variable to store the manufacturer name [out] + * pProductCode - Pointer to a variable to store the product code [out] + * pSerialNumber - Pointer to a variable to store the serial number [out] + * pWeekOfManufacture - Pointer to a variable to store the week of manufacture [out] + * pYearOfManufacture - Pointer to a variable to store the year of manufacture + * or model year (if WeekOfManufacture is 0xff) [out] + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetProductInfo( + unsigned char *pEDIDBuffer, + char *pManufacturerName, + unsigned short *pProductCode, + unsigned long *pSerialNumber, + unsigned char *pWeekOfManufacture, + unsigned short *pYearOfManufacture +) +{ + unsigned char version, revision; + unsigned short manufactureID; + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + if (pManufacturerName != (char *)0) + { + /* Swap the byte */ + manufactureID = (pEDIDStructure->manufacturerID >> 8) + (pEDIDStructure->manufacturerID << 8); + pManufacturerName[0] = ((manufactureID >> 10) & 0x001F) + 'A' - 1; + pManufacturerName[1] = ((manufactureID >> 5) & 0x001F) + 'A' - 1; + pManufacturerName[2] = (manufactureID & 0x001F) + 'A' - 1; + pManufacturerName[3] = '\0'; + } + + if (pProductCode != (unsigned short *)0) + *pProductCode = pEDIDStructure->productCode; + + /* Only EDID structure version 1.1 and 1.2 supports this. EDID 1.3 uses + detail timing descriptor to store the serial number in ASCII. */ + if (pSerialNumber != (unsigned long *)0) + *pSerialNumber = pEDIDStructure->serialNumber; + + /* + * Rev 1.3: - A value of 0 means that week of manufacture is not specified + * - A value in the range of 1 to 54 (0x01 - 0x36) means the week of manufacture + * - Any values greater than 54 is invalid. + * + * Rev 1.4: - A value of 0 means that week of manufacture is not specified + * - A value in the range of 1 to 54 (0x01 - 0x36) means the week of manufacture + * - A value of 0xFF means that Year of Manufacture contains the model year + * instead of year of Manufacture. + * - Other values means invalid + */ + if (pWeekOfManufacture != (unsigned char *)0) + *pWeekOfManufacture = pEDIDStructure->weekOfManufacture; + + /* The value must be greater than 3 and less than or equal to the current + year minus 1990. + A value of 3 or less would indicated that the display was manufactured + before the EDID standard was defined. + A value greater than (current year - 1990) would indicate that the display + has not yet been manufactured. + */ + if (pYearOfManufacture != (unsigned short *)0) + *pYearOfManufacture = (unsigned short) pEDIDStructure->yearOfManufacture + 1990; + + return 0; + } + + return (-1); +} + +/* + * ddk768_edidCheckMonitorInputSignal + * This function checks whether the monitor is expected analog/digital + * input signal. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Analog + * 1 - Digital + */ +unsigned char ddk768_edidCheckMonitorInputSignal( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->videoInputDefinition.analogSignal.inputSignal; + + return 0; +} + +/* + * ddk768_edidGetAnalogSignalInfo + * This function gets the analog video input signal information + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRefWhiteAboveBlank - Pointer to a variable to store the reference white above blank + * value. The value is in milliVolt. + * pSyncLevelBelowBlank - Pointer to a variable to store the Sync tip level below blank + * The value is also in milliVolt + * pBlank2BlackSetup - Pointer to a variable to store the Blank to black setup or + * pedestal per appropriate Signal Level Standard flag. + * 1 means that the display expect the setup. + * pSeparateSyncSupport - Pointer to a variable to store the flag to indicate that the + * monitor supports separate sync. + * pCompositeSyncSupport - Pointer to a variable to store a flag to indicate that the + * monitor supports composite sync. + * pSyncOnGreenSupport - Pointer to a variable to store a flag to indicate that + * the monitor supports sync on green video. + * pVSyncSerrationRequired - Pointer to a variable to store a flag to indicate that serration + * of the VSync pulse is required when composite sync or + * sync-on-green video is used. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetAnalogSignalInfo( + unsigned char *pEDIDBuffer, + unsigned short *pRefWhiteAboveBlank, + unsigned short *pSyncLevelBelowBlank, + unsigned char *pBlank2BlackSetup, + unsigned char *pSeparateSyncSupport, + unsigned char *pCompositeSyncSupport, + unsigned char *pSyncOnGreenSupport, + unsigned char *pVSyncSerrationRequired +) +{ + unsigned char version, revision; + unsigned short whiteReference, syncLevel; + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + /* Check if the input signal is analog */ + if (pEDIDStructure->videoInputDefinition.analogSignal.inputSignal != 0) + return (-1); + + switch (pEDIDStructure->videoInputDefinition.analogSignal.signalLevelStd) + { + case 0: + whiteReference = 700; + syncLevel = 300; + break; + case 1: + whiteReference = 714; + syncLevel = 286; + break; + case 2: + whiteReference = 1000; + syncLevel = 400; + break; + case 3: + whiteReference = 700; + syncLevel = 0; + break; + } + + if (pRefWhiteAboveBlank != (unsigned short *)0) + *pRefWhiteAboveBlank = whiteReference; + + if (pSyncLevelBelowBlank != (unsigned short *)0) + *pSyncLevelBelowBlank = syncLevel; + + if (pBlank2BlackSetup != (unsigned char *)0) + *pBlank2BlackSetup = (unsigned char) + pEDIDStructure->videoInputDefinition.analogSignal.blank2Black; + + if (pSeparateSyncSupport != (unsigned char *)0) + *pSeparateSyncSupport = (unsigned char) + pEDIDStructure->videoInputDefinition.analogSignal.separateSyncSupport; + + if (pCompositeSyncSupport != (unsigned char *)0) + *pCompositeSyncSupport = (unsigned char) + pEDIDStructure->videoInputDefinition.analogSignal.compositeSyncSupport; + + if (pSyncOnGreenSupport != (unsigned char *)0) + *pSyncOnGreenSupport = (unsigned char) + pEDIDStructure->videoInputDefinition.analogSignal.syncOnGreenSupport; + + if (pVSyncSerrationRequired != (unsigned char *)0) + *pVSyncSerrationRequired = (unsigned char) + pEDIDStructure->videoInputDefinition.analogSignal.vsyncSerration; + + return 0; + } + else + { + /* EDID Structure 2 */ + } + + return (-1); +} + +/* + * ddk768_edidGetDigitalSignalInfo + * This function gets the digital video input signal information. + * Only applies to EDID 1.3 and above. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pDFP1xSupport - Pointer to a variable to store the flag to indicate that + * the mointor interface is signal compatible with VESA + * DFP 1.x TMDS CRGB, 1 pixel/clock, up to 8 bits / color + * MSB aligned, DE active high + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetDigitalSignalInfo( + unsigned char *pEDIDBuffer, + unsigned char *pDFP1xSupport +) +{ + unsigned char version, revision; + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, &revision); + + if ((version == 1) && (revision == 3)) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + /* Check if the input signal is digital */ + if (pEDIDStructure->videoInputDefinition.digitalSignal.inputSignal != 1) + return (-1); + + if (pDFP1xSupport != (unsigned char *)0) + *pDFP1xSupport = pEDIDStructure->videoInputDefinition.digitalSignal.dfp1Support; + + return 0; + } + + return (-1); +} + +/* + * ddk768_edidGetDisplaySize + * This function gets the display sizes in cm. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMaxHorzImageSize - Pointer to a variable to store the maximum horizontal + * image size to the nearest centimeter. A value of 0 + * indicates that the size is indeterminate size. + * pMaxVertImageSize - Pointer to a variable to store the maximum vertical + * image size to the nearest centimeter. A value of 0 + * indicates that the size is indeterminate size. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetDisplaySize( + unsigned char *pEDIDBuffer, + unsigned char *pMaxHorzImageSize, + unsigned char *pMaxVertImageSize +) +{ + unsigned char version, revision; + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + if (pMaxHorzImageSize != (unsigned char *)0) + *pMaxHorzImageSize = pEDIDStructure->maxHorzImageSize; + + if (pMaxVertImageSize != (unsigned char *)0) + *pMaxVertImageSize = pEDIDStructure->maxVertImageSize; + + return 0; + } + + return (-1); +} + +#if 0 /* Use the ddk768_edidGetWhitePoint to get the Gamma */ +/* + * edidGetGamma + * This function gets the Display Transfer Characteristic (Gamma). + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * Gamma value multiplied by 100. A value of 0xFFFF (-1) indicates that + * the gamma value is not defined. + */ +unsigned short edidGetGamma( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned short)(((edid_version_1_t *)pEDIDBuffer)->displayTransferChar + 100); + + return (-1); +} +#endif + +/* + * ddk768_edidGetPowerManagementSupport + * This function gets the monitor's power management support. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStandBy - Pointer to a variable to store the flag to indicate that + * standby power mode is supported. + * pSuspend - Pointer to a variable to store the flag to indicate that + * suspend power mode is supported. + * pLowPower - Pointer to a variable to store the flag to indicate that + * the display consumes low power when it receives a timing + * signal that is outside its declared active operating range. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetPowerManagementSupport( + unsigned char *pEDIDBuffer, + unsigned char *pStandBy, + unsigned char *pSuspend, + unsigned char *pLowPower +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + if (pStandBy != (unsigned char *)0) + *pStandBy = (unsigned char) pEDIDStructure->featureSupport.standbySupport; + + if (pSuspend != (unsigned char *)0) + *pSuspend = (unsigned char) pEDIDStructure->featureSupport.suspendSupport; + + if (pLowPower != (unsigned char *)0) + *pLowPower = (unsigned char) pEDIDStructure->featureSupport.lowPowerSupport; + + return 0; + } + + return (-1); +} + +/* + * ddk768_edidGetDisplayType + * This function gets the display type. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Monochrome / grayscale display + * 1 - RGB Color Display + * 2 - Non-RGB multicolor display, e.g. R/G/Y + * 3 - Undefined + */ +unsigned char ddk768_edidGetDisplayType( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.displayType; + + return (3); +} + +/* + * ddk768_edidChecksRGBUsage + * This function checks if the display is using the sRGB standard default + * color space as its primary color space. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Does not use sRGB as its primary color space + * 1 - Use sRGB as its primary color space + */ +unsigned char ddk768_edidChecksRGBUsage( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.sRGBSupport; + + return (0); +} + +/* + * ddk768_edidIsPreferredTimingAvailable + * This function checks whether the preffered timing mode is available. + * Use of preferred timing mode is required by EDID structure version 1 + * Revision 3 and higher. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Preferred Timing is not available + * 1 - Preferred Timing is available + */ +unsigned char ddk768_edidIsPreferredTimingAvailable( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + + if (pEDIDBuffer != (unsigned char *)0) + { + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.preferredTiming; + } + + return (0); +} + +/* + * ddk768_edidIsDefaultGTFSupported + * This function checks whether the display supports timings based on the + * GTF standard using default GTF parameter values. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Default GTF is not supported + * 1 - Default GTF is supported + */ +unsigned char ddk768_edidIsDefaultGTFSupported( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.defaultGTFSupport; + + return (0); +} + +/* + * edidCalculateChromaticValue + * This function calculates the chromatic value. + * + * Input: + * colorBinaryValue - Color Characteristic Binary Representation Value + * to be computed + * + * Output: + * The chromatic value times a 1000. + */ +static unsigned short edidCalculateChromaticValue( + unsigned short colorBinaryValue +) +{ + unsigned long index; + unsigned long result; + + result = 0; + for (index = 10; index > 0; index--) + { + /* Times 1000000 to make it accurate to the micro value. */ + result += ddk768_roundedDiv((colorBinaryValue & 0x0001) * 1000000, ddk768_twoToPowerOfx(index)); + colorBinaryValue >>= 1; + } + + /* Make it accurate to 1000 place */ + return ((unsigned short)ddk768_roundedDiv(result, 1000)); +} + +/* + * ddk768_edidGetColorCharacteristic + * This function gets the chromaticity and white point values expressed as + * an integer value which represents the actual value times 1000. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRedX - Pointer to a variable to store the Red X values + * pRedY - Pointer to a variable to store the Red Y values + * pGreenX - Pointer to a variable to store the Green X values + * pGreenY - Pointer to a variable to store the Green Y values + * pBlueX - Pointer to a variable to store the Blue X values + * pBlueY - Pointer to a variable to store the Blue Y values + * + * Note: + * To get the White color characteristic, use the ddk768_edidGetWhitePoint + */ +void ddk768_edidGetColorCharacteristic( + unsigned char *pEDIDBuffer, + unsigned short *pRedX, + unsigned short *pRedY, + unsigned short *pGreenX, + unsigned short *pGreenY, + unsigned short *pBlueX, + unsigned short *pBlueY +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + if (pRedX != (unsigned short *)0) + { + *pRedX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->redX << 2) + + (unsigned short)pEDIDStructure->redGreenLowBits.redXLowBits); + } + + if (pRedY != (unsigned short *)0) + { + *pRedY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->redY << 2) + + (unsigned short)pEDIDStructure->redGreenLowBits.redYLowBits); + } + + if (pGreenX != (unsigned short *)0) + { + *pGreenX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->greenX << 2) + + (unsigned short)pEDIDStructure->redGreenLowBits.greenXLowBits); + } + + if (pGreenY != (unsigned short *)0) + { + *pGreenY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->greenY << 2) + + (unsigned short)pEDIDStructure->redGreenLowBits.greenYLowBits); + } + + if (pBlueX != (unsigned short *)0) + { + *pBlueX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->blueX << 2) + + (unsigned short)pEDIDStructure->blueWhiteLowBits.blueXLowBits); + } + + if (pBlueY != (unsigned short *)0) + { + *pBlueY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->blueY << 2) + + (unsigned short)pEDIDStructure->blueWhiteLowBits.blueYLowBits); + } + } +} + +/* + * ddk768_edidGetWhitePoint + * This function gets the white point. + * To get the default white point, set the index to 0. For multiple white point, + * call this function multiple times to check if more than 1 white point is supported. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pWhitePointIndex - Pointer to a variable that contains the white point index + * to be retrieved. + * pWhiteX - Pointer to a variable to store the White X value + * pWhiteY - Pointer to a variable to store the White Y value + * pWhiteGamma - Pointer to a variable to store the White Gamma value + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetWhitePoint( + unsigned char *pEDIDBuffer, + unsigned char *pWhitePointIndex, + unsigned short *pWhiteX, + unsigned short *pWhiteY, + unsigned short *pWhiteGamma +) +{ + unsigned char version, index, tableIndex; + + if (pWhitePointIndex == (unsigned char *)0) + return (-1); + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + /* Get the index to a temporary variable and increment the index for the + next loop. */ + index = *pWhitePointIndex; + (*pWhitePointIndex)++; + + if (index == 0) + { + if (pWhiteX != (unsigned short *)0) + { + *pWhiteX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->whiteX << 2) + + (unsigned short)pEDIDStructure->blueWhiteLowBits.whiteXLowBits); + } + + if (pWhiteY != (unsigned short *)0) + { + *pWhiteY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->whiteY << 2) + + (unsigned short)pEDIDStructure->blueWhiteLowBits.whiteYLowBits); + } + + if (pWhiteGamma != (unsigned short *)0) + *pWhiteGamma = pEDIDStructure->displayTransferChar + 100; + + return 0; + } + else + { + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFB) && + (pMonitorDescriptor->descriptor.colorPoint.white[index-1].whitePointIndex != 0)) + { + if (pWhiteX != (unsigned short *)0) + { + *pWhiteX = edidCalculateChromaticValue(((unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteX << 2) + + (unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteLowBits.whiteXLowBits); + } + + if (pWhiteY != (unsigned short *)0) + { + *pWhiteY = edidCalculateChromaticValue(((unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteY << 2) + + (unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteLowBits.whiteYLowBits); + } + + if (pWhiteGamma != (unsigned short *)0) + *pWhiteGamma = pMonitorDescriptor->descriptor.colorPoint.white[index-1].gamma + 100; + + return 0; + } + } + } + } + + return (-1); +} + +/* + * edidCalculateChecksum + * This function adds all one-byte value of the EDID buffer. + * The total should be equal to 0x00 + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * Total of one-byte values. It should equal to 0x00. A value other than + * 0x00 indicates the EDID buffer is not valid. + */ +__attribute__((unused)) static unsigned char edidCalculateChecksum( + unsigned char *pEDIDBuffer) +{ + unsigned char version, revision, checksum; + unsigned short index; + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, &revision); + + checksum = 0; + if (version == 1) + { + for (index = 0; index < 128; index++) + checksum += pEDIDBuffer[index]; + } + + return checksum; +} + +/* + * ddk768_edidGetExtension + * This function gets the number of (optional) EDID extension blocks to follow + * the given EDID buffer. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * Total number of EDID Extension to follow the given EDID buffer. + */ +unsigned char ddk768_edidGetExtension( + unsigned char *pEDIDBuffer +) +{ + unsigned char version, revision; + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + return ((edid_version_1_t *)pEDIDBuffer)->extFlag; + + return 0; +} + + +#define EDID_TOTAL_RETRY_COUNTER 1 + +#if 0 +/* + * ddk768_edidReadMonitor + * This function reads the EDID structure from the attached monitor + * + * Input: + * displayPath - Display device which EDID to be read from. + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * sclGpio - GPIO pin used as the I2C Clock (SCL) + * sdaGpio - GPIO pin used as the I2C Data (SDA) + * + * Output: + * 0 - Fail + * edidSize - Success and return the edid's size + */ +long ddk768_edidReadMonitorEx( + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char sclGpio, + unsigned char sdaGpio +) +{ + unsigned char retry, edidVersion, edidRevision; + unsigned char edidBuffer[TOTAL_EDID_REGISTERS_256]; + unsigned long offset; + long edidSize = TOTAL_EDID_REGISTERS_128; + + /* Initialize the i2c bus */ + ddk768_swI2CInit(sclGpio, sdaGpio); + + + + for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++) + { + // DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry)); + +#ifndef READ_EDID_CONTINUOUS + /* Read the EDID from the monitor. */ + for (offset = 0; offset < TOTAL_EDID_REGISTERS_128; offset++) + edidBuffer[offset] = ddk768_swI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); +#else + if (!ddk768_swI2CReadReg_Continuous(EDID_DEVICE_I2C_ADDRESS, 0,TOTAL_EDID_REGISTERS_128,edidBuffer)) + memset(edidBuffer, 0xFF, TOTAL_EDID_REGISTERS_128); /* read error */ +#endif + + if(edidBuffer[EDID_EXTEND_BLOCK]) + { +#ifndef READ_EDID_CONTINUOUS + for (offset = TOTAL_EDID_REGISTERS_128; offset < TOTAL_EDID_REGISTERS_256; offset++) + edidBuffer[offset] = ddk768_swI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); +#else + if (!ddk768_swI2CReadReg_Continuous(EDID_DEVICE_I2C_ADDRESS, TOTAL_EDID_REGISTERS_128, TOTAL_EDID_REGISTERS_128, edidBuffer + TOTAL_EDID_REGISTERS_128)) + memset(edidBuffer + TOTAL_EDID_REGISTERS_128, 0xFF, TOTAL_EDID_REGISTERS_128); /* read error */ +#endif + + edidSize = TOTAL_EDID_REGISTERS_256; + } + + /* Check if the EDID is valid. */ + edidVersion = ddk768_edidGetVersion((unsigned char *)&edidBuffer, (unsigned char *)&edidRevision); + //DDKDEBUGPRINT((DISPLAY_LEVEL, "EDID Structure Version: %d.%d\n", edidVersion, edidRevision)); + if (edidVersion != 0) + break; + + ddk768_swI2CCleanBus(sclGpio, sdaGpio); + } + + /* + * The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol, + * which uses the Vertical Sync to clock in the EDID data. + * Currently this function return error. DDC1 protocol can be added later. + */ + if (retry == EDID_TOTAL_RETRY_COUNTER) + { + /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is + * only an acknowledge flag, which could be high or low. However, SCL line + * is not used. Instead the data is clock-in using vertical sync. + */ + return 0; + } + + /* Copy the data to the given buffer */ + if (pEDIDBuffer != (unsigned char *)0) + { + for (offset = 0; offset < edidSize; offset++) + pEDIDBuffer[offset] = edidBuffer[offset]; + } + + return edidSize; +} +#endif + +/* + * This function is same as editReadMonitorEx(), but using HW I2C. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * i2cNumber - 0 = I2C0 and 1 = I2C1 + * + * Output: + * 0 - Fail + * edidSize - Success and return the edid's size. + */ +long ddk768_edidReadMonitorExHwI2C( + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char i2cNumber +) +{ + unsigned char retry, edidVersion, edidRevision; + unsigned long value; + unsigned char edidBuffer[TOTAL_EDID_REGISTERS_256]; + unsigned long offset; + long edidSize = 0; + + /* Initialize the i2c bus */ + ddk768_hwI2CInit(i2cNumber); +#if 0 + for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++) + { + // DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry)); + + /* Read the EDID from the monitor. */ + for (offset = 0; offset < TOTAL_EDID_REGISTERS; offset++) + edidBuffer[offset] = ddk768_hwI2CReadReg(i2cNumber, EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); + + /* Check if the EDID is valid. */ + edidVersion = ddk768_edidGetVersion((unsigned char *)&edidBuffer, (unsigned char *)&edidRevision); + // DDKDEBUGPRINT((DISPLAY_LEVEL, "EDID Structure Version: %d.%d\n", edidVersion, edidRevision)); + if (edidVersion != 0) + break; + } +#else + + for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++) + { + //DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry)); + edidSize = 0; + /* Read the EDID from the monitor. */ + for (offset = 0; offset < TOTAL_EDID_REGISTERS_128; offset++) + { + value = ddk768_hwI2CReadReg(i2cNumber,EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); + if(0xFFFFFFFF == value) + break; + edidBuffer[offset] = (0xFF & value); + } + if(0xFFFFFFFF != value) + { + edidSize = TOTAL_EDID_REGISTERS_128; + if(edidBuffer[EDID_EXTEND_BLOCK]) + { + for (offset = TOTAL_EDID_REGISTERS_128; offset < TOTAL_EDID_REGISTERS_256; offset++) + { + value = ddk768_hwI2CReadReg(i2cNumber,EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); + + if(0xFFFFFFFF == value) + break; + edidBuffer[offset] = (0xFF & value); + } + + if(0xFFFFFFFF != value) + edidSize = TOTAL_EDID_REGISTERS_256; + } + if(0xFFFFFFFF != value) + { + /* Check if the EDID is valid. */ + edidVersion = ddk768_edidGetVersion((unsigned char *)&edidBuffer, (unsigned char *)&edidRevision); + // DDKDEBUGPRINT((DISPLAY_LEVEL, "EDID Structure Version: %d.%d\n", edidVersion, edidRevision)); + if (edidVersion != 0) + break; + } + } + } +#endif + + /* Finish using HW I2C, we can close the device. */ + ddk768_hwI2CClose(i2cNumber); + + /* + * The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol, + * which uses the Vertical Sync to clock in the EDID data. + * Currently this function return error. DDC1 protocol can be added later. + */ + if (retry == EDID_TOTAL_RETRY_COUNTER) + { + /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is + * only an acknowledge flag, which could be high or low. However, SCL line + * is not used. Instead the data is clock-in using vertical sync. + */ + return 0; + } + + /* Copy the data to the given buffer */ + if (pEDIDBuffer != (unsigned char *)0) + { + for (offset = 0; offset < edidSize; offset++) + pEDIDBuffer[offset] = edidBuffer[offset]; + } + + return edidSize; +} + +#if 0 + +/* + * ddk768_edidReadMonitor + * This function reads the EDID structure from the attached monitor + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * i2cNumber - 0 = I2c0 and 1 = 12c1 + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidReadMonitor( + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char i2cNumber +) +{ + + unsigned char i2cSCL, i2cSDA; + + if (i2cNumber == 0) + { + i2cSCL = DEFAULT_I2C0_SCL; + i2cSDA = DEFAULT_I2C0_SDA; + } + else + { + i2cSCL = DEFAULT_I2C1_SCL; + i2cSDA = DEFAULT_I2C1_SDA; + } + + return ddk768_edidReadMonitorEx(pEDIDBuffer, bufferSize, edidExtNo, i2cSCL, i2cSDA); +} + + +/* + * edidHeaderReadMonitor + * This function reads the EDID header from the attached monitor + * + * Input: + * sclGpio - GPIO pin used as the I2C Clock (SCL) + * sdaGpio - GPIO pin used as the I2C Data (SDA) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidHeaderReadMonitorEx( + unsigned char sclGpio, + unsigned char sdaGpio +) +{ + unsigned char retry;//value, + unsigned char edidBuffer[10]; +#ifndef READ_EDID_CONTINUOUS + unsigned long offset; +#endif + + /* Initialize the i2c bus */ + ddk768_swI2CInit(sclGpio, sdaGpio); + + for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++) + { + DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry)); + +#ifndef READ_EDID_CONTINUOUS + /* Read the EDID from the monitor. */ + for (offset = 0; offset < HEADER_EDID_REGISTERS; offset++) + edidBuffer[offset] = ddk768_swI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); + +#else + if (!ddk768_swI2CReadReg_Continuous(EDID_DEVICE_I2C_ADDRESS, 0, HEADER_EDID_REGISTERS, edidBuffer)) + memset(edidBuffer, 0xFF, HEADER_EDID_REGISTERS); /* read error */ +#endif + + /* Check if the EDID header is valid. */ + if (!edidGetHeader((unsigned char *)&edidBuffer)) + break; + ddk768_swI2CCleanBus(sclGpio, sdaGpio); + } + + /* + * The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol, + * which uses the Vertical Sync to clock in the EDID data. + * Currently this function return error. DDC1 protocol can be added later. + */ + if (retry == EDID_TOTAL_RETRY_COUNTER) + { + /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is + * only an acknowledge flag, which could be high or low. However, SCL line + * is not used. Instead the data is clock-in using vertical sync. + */ + return (-1); + } + + return 0; +} + +#endif + +long ddk768_edidHeaderReadMonitorExHwI2C( + unsigned char i2cNumber +) +{ + unsigned char retry;//value, + unsigned char edidBuffer[10]; + unsigned long offset; + + /* Initialize the i2c bus */ + ddk768_hwI2CInit(i2cNumber); + + for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++) + { + DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry)); + + /* Read the EDID from the monitor. */ + for (offset = 0; offset < HEADER_EDID_REGISTERS; offset++) + edidBuffer[offset] = ddk768_hwI2CReadReg(i2cNumber,EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); + + /* Check if the EDID header is valid. */ + if (!edidGetHeader((unsigned char *)&edidBuffer)) + break; + } + + /* Finish using HW I2C, we can close the device. */ + //ddk768_hwI2CClose(i2cNumber); + + /* + * The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol, + * which uses the Vertical Sync to clock in the EDID data. + * Currently this function return error. DDC1 protocol can be added later. + */ + if (retry == EDID_TOTAL_RETRY_COUNTER) + { + /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is + * only an acknowledge flag, which could be high or low. However, SCL line + * is not used. Instead the data is clock-in using vertical sync. + */ + return 0; + } + + return 1; +} + + + +/* + * ddk768_edidGetEstablishedTiming + * This function gets the established timing list from the given EDID buffer, + * table, and timing index. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor (In) + * pEstTableIndex - Pointer to the Established Timing Table index (In/Out) + * pIndex - Pointer to the Establihsed Timing Index (In/Out) + * pWidth - Pointer to a variable that to store the horizontal active / width + * value of the retrieved timing (Out) + * pHeight - Pointer to a variable to store the vertical active / height + * value of the retrieved timing (Out) + * pRefreshRate - Pointer to a variable to store the vertical frequency value + * of the retrieved timing (out) + * pSource - Pointer to a variable to store the standard timing source: + * 0 - VESA + * 1 - IBM + * 2 - Apple + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetEstablishedTiming( + unsigned char *pEDIDBuffer, + /*unsigned char *pEstTableIndex,*/ + unsigned char *pIndex, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pRefreshRate, + unsigned char *pSource +) +{ + unsigned char version, revision; + unsigned char tableIndex, index; + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + while (1) + { + /* Get index */ + index = *pIndex; + + if (index > 16) + break; + + /* Search Established Table index 0 when the index is less than 8 */ + tableIndex = index / 8; + + /* Exit the function when it has reached the last table. */ + if (tableIndex > 2) + break; + + /* Increment the index value and update the index accordingly */ + (*pIndex)++; + index %= 8; + + /* Check */ + if ((pEDIDStructure->estTiming[tableIndex] & (1 << index)) != 0) + { + if (pWidth != (unsigned long *)0) + *pWidth = establishTiming[tableIndex][index].x; + + if (pHeight != (unsigned long *)0) + *pHeight = establishTiming[tableIndex][index].y; + + if (pRefreshRate != (unsigned long *)0) + *pRefreshRate = establishTiming[tableIndex][index].hz; + + if (pSource != (unsigned char *)0) + *pSource = establishTiming[tableIndex][index].source; + + /* Return success */ + return 0; + } + } + } + else + { + /* EDID Structure Version 2.0. */ + } + + return (-1); +} + +/* + * edidCalculateStdTiming + * This function calculates the width, height, and vertical frequency values + * from the given Standard Timing structure. This function only applies to + * EDID structure version 1. It will give the wrong result when used with + * EDID version 2. + * + * Input: + * pStdTiming - Pointer to a standard timing structure that contains the + * standard timing value to be calculated (In) + * edid1Revision - Revision of the EDID 1 (In) + * pWidth - Pointer to a variable that to store the horizontal active / width + * value of the retrieved timing (Out) + * pHeight - Pointer to a variable to store the vertical active / height + * value of the retrieved timing (Out) + * pRefreshRate - Pointer to a variable to store the vertical frequency value + * of the retrieved timing (out) + * + * Output: + * 0 - Success + * -1 - Fail + */ +static long edidCalculateStdTiming( + standard_timing_t *pStdTiming, + unsigned char edid1Revision, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pRefreshRate +) +{ + unsigned long x, y; + + /* Calculate the standard timing into x and y mode dimension */ + if (pStdTiming->horzActive != 0x01) + { + /* Calculate the X and Y */ + x = (pStdTiming->horzActive + 31) * 8; + switch (pStdTiming->stdTimingInfo.aspectRatio) + { + case 0: + if (edid1Revision != 3) + y = x; /* 1:1 aspect ratio (prior revision 1.3) */ + else + y = x * 10 / 16; /* 16:10 aspect ratio (revision 1.3) */ + break; + case 1: + y = x * 3 / 4; /* 4:3 aspect ratio */ + break; + case 2: + y = x * 4 / 5; /* 5:4 aspect ratio */ + break; + case 3: + y = x * 9 / 16; /* 16:9 aspect ratio */ + break; + } + + if (pWidth != (unsigned long *)0) + *pWidth = x; + + if (pHeight != (unsigned long *)0) + *pHeight = y; + + if (pRefreshRate != (unsigned long *)0) + *pRefreshRate = pStdTiming->stdTimingInfo.refreshRate + 60; + + return 0; + } + + return (-1); +} + +/* + * ddk768_edidGetStandardTiming + * This function gets the standard timing from the given EDID buffer and + * calculates the width, height, and vertical frequency from that timing. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStdTimingIndex - Pointer to a standard timing index to be retrieved + * pWidth - Pointer to a variable that to store the horizontal active / width + * value of the retrieved timing (Out) + * pHeight - Pointer to a variable to store the vertical active / height + * value of the retrieved timing (Out) + * pRefreshRate - Pointer to a variable to store the vertical frequency value + * of the retrieved timing (out) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetStandardTiming( + unsigned char *pEDIDBuffer, + unsigned char *pStdTimingIndex, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pRefreshRate +) +{ + unsigned char version, revision, timingIndex, tableIndex; + + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + while (1) + { + /* There are only 8 standard timing entries */ + if (*pStdTimingIndex > 7) + break; + + /* Get the table index first before incrementing the index. */ + timingIndex = *pStdTimingIndex; + + /* Increment the standard timing index */ + (*pStdTimingIndex)++; + + if (timingIndex < 8) + { + /* + * Search the first Standard Timing Identifier table + */ + + /* Calculate the standard timing into x and y mode dimension */ + if (edidCalculateStdTiming(&pEDIDStructure->stdTiming[timingIndex], + revision, pWidth, pHeight, pRefreshRate) == 0) + { + return 0; + } + } + else + { + /* + * Search Standard Timing Identifier Table in the detailed Timing block. + */ + + /* + * Each Detailed Timing Identifier can contains 6 entries of Standard Timing + * Identifier. Based on this value, we can get the Detailed Timing Table Index + * that contains the requested standard timing. + */ + timingIndex = timingIndex - 8; + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + /* Get detailed info */ + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFA)) + { + if (timingIndex >= 6) + { + timingIndex-=6; + continue; + } + else + { + if (edidCalculateStdTiming(&pMonitorDescriptor->descriptor.stdTimingExt.stdTiming[timingIndex], + revision, pWidth, pHeight, pRefreshRate) == 0) + { + return 0; + } + } + } + } + } + } + } + else + { + /* EDID Structure version 2 */ + } + + return (-1); +} + +/* + * ddk768_edidGetDetailedTiming + * This function gets the detailed timing from the given EDID buffer. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pDetailedTimingIndex - Pointer to a detailed timing index to be retrieved + * pModeParameter - Pointer to a mode_parameter_t structure that will be + * filled with the detailed timing. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetDetailedTiming( + unsigned char *pEDIDBuffer, + unsigned char *pDetailedTimingIndex, + vdif_t *pVDIF +) +{ + unsigned char version, revision, tableIndex; + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + detailed_timing_t *pDetailedTiming; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + while (1) + { + if (*pDetailedTimingIndex > 3) + break; + + /* Get the Detail Timing entry index */ + tableIndex = *pDetailedTimingIndex; + + /* Increment the index */ + (*pDetailedTimingIndex)++; + + /* Get detailed info */ + pDetailedTiming = &pEDIDStructure->miscInformation.detailTiming[tableIndex]; + if ((pDetailedTiming->pixelClock != 0) && (pVDIF != (vdif_t *)0)) + { + /* Translate the Detail timing to VDIF format. */ + pVDIF->pixelClock = (unsigned long)pDetailedTiming->pixelClock * 10000; + pVDIF->characterWidth = 8; + pVDIF->scanType = (pDetailedTiming->flags.interlaced == 0) ? VDIF_NONINTERLACED : VDIF_INTERLACED; + + pVDIF->horizontalActive = + ((unsigned long)pDetailedTiming->horzActiveBlanking.horzActiveMSB << 8) + + (unsigned long)pDetailedTiming->horzActive; + pVDIF->horizontalBlankStart = pVDIF->horizontalActive; + pVDIF->horizontalBlankTime = + ((unsigned long)pDetailedTiming->horzActiveBlanking.horzBlankingMSB << 8) + + (unsigned long)pDetailedTiming->horzBlanking; + pVDIF->horizontalTotal = pVDIF->horizontalActive + pVDIF->horizontalBlankTime; + pVDIF->horizontalFrontPorch = + ((unsigned long)pDetailedTiming->syncAuxInfo.horzSyncOffset << 8) + + (unsigned long)pDetailedTiming->horzSyncOffset; + pVDIF->horizontalSyncStart = pVDIF->horizontalBlankStart + pVDIF->horizontalFrontPorch; + pVDIF->horizontalSyncWidth = + ((unsigned long)pDetailedTiming->syncAuxInfo.horzSyncWidth << 8) + + (unsigned long)pDetailedTiming->horzSyncPulseWidth; + pVDIF->horizontalBackPorch = + pVDIF->horizontalBlankTime - (pVDIF->horizontalFrontPorch + pVDIF->horizontalSyncWidth); + pVDIF->horizontalFrequency = ddk768_roundedDiv(pVDIF->pixelClock, pVDIF->horizontalTotal); + pVDIF->horizontalLeftBorder = 0; + pVDIF->horizontalRightBorder = 0; + + pVDIF->verticalActive = + ((unsigned long)pDetailedTiming->vertActiveBlanking.vertActiveMSB << 8) + + (unsigned long)pDetailedTiming->vertActive; + pVDIF->verticalBlankStart = pVDIF->verticalActive; + pVDIF->verticalBlankTime = + ((unsigned long)pDetailedTiming->vertActiveBlanking.vertBlankingMSB << 8) + + (unsigned long)pDetailedTiming->vertBlanking; + pVDIF->verticalTotal = pVDIF->verticalActive + pVDIF->verticalBlankTime; + pVDIF->verticalFrontPorch = + ((unsigned long)pDetailedTiming->syncAuxInfo.vertSyncOffset << 8) + + (unsigned long)pDetailedTiming->verticalSyncInfo.syncOffset; + pVDIF->verticalSyncStart = pVDIF->verticalBlankStart + pVDIF->verticalFrontPorch; + pVDIF->verticalSyncHeight = + ((unsigned long)pDetailedTiming->syncAuxInfo.vertSyncWidth << 8) + + (unsigned long)pDetailedTiming->verticalSyncInfo.syncWidth; + pVDIF->verticalBackPorch = + pVDIF->verticalBlankTime - (pVDIF->verticalFrontPorch + pVDIF->verticalSyncHeight); + pVDIF->verticalFrequency = + ddk768_roundedDiv(pVDIF->pixelClock, (pVDIF->horizontalTotal * pVDIF->verticalTotal)); + pVDIF->verticalTopBorder = 0; + pVDIF->verticalBottomBorder = 0; + + if (pDetailedTiming->flags.connectionType == 3) + { + pVDIF->verticalSyncPolarity = + (pDetailedTiming->flags.vertSyncFlag == 1) ? VDIF_SYNC_POSITIVE : VDIF_SYNC_NEGATIVE; + pVDIF->horizontalSyncPolarity = + (pDetailedTiming->flags.horzSyncFlag == 1) ? VDIF_SYNC_POSITIVE : VDIF_SYNC_NEGATIVE; + } + else + { + pVDIF->verticalSyncPolarity = VDIF_SYNC_NEGATIVE; + pVDIF->horizontalSyncPolarity = VDIF_SYNC_NEGATIVE; + } + + /* For debugging purpose. */ + printVdif(pVDIF); + + return 0; + } + } + } + + return (-1); +} + +/* + * ddk768_edidGetMonitorSerialNumber + * This function gets the monitor serial number from the EDID structure. + * Only EDID version 1 and revision 1 or above supports this feature. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorSerialNumber - Pointer to a buffer to store the serial number + * retrieved from the EDID + * bufferSize - The size of the buffer to store the serial number. + * The maximum size required is 13 bytes. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetMonitorSerialNumber( + unsigned char *pEDIDBuffer, + char *pMonitorSerialNumber, + unsigned char bufferSize +) +{ + unsigned char version, revision, tableIndex, charIndex; + + /* If no pointer is given or the buffer size is set to 0, then return fail. */ + if ((pMonitorSerialNumber == (char *)0) || (bufferSize == 0)) + return (-1); + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, &revision); + + if ((version == 1) && (revision > 0)) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFF)) + { + bufferSize = (bufferSize > 13) ? 13 : bufferSize; + for (charIndex = 0; charIndex < 13; charIndex++) + { + if (pMonitorDescriptor->descriptor.serialNo[charIndex] == 0x0A) + { + pMonitorSerialNumber[charIndex] = '\0'; + break; + } + + pMonitorSerialNumber[charIndex] = pMonitorDescriptor->descriptor.serialNo[charIndex]; + } + + return 0; + } + } + } + + /* Serial Number is not found. */ + return (-1); +} + +/* + * ddk768_edidGetDataString + * This function gets the data string from the EDID + * Only EDID version 1 and revision 1 or above supports this feature. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorSerialNumber - Pointer to a buffer to store the data string + * retrieved from the EDID + * bufferSize - The size of the buffer to store the data string + * The maximum size required is 13 bytes. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetDataString( + unsigned char *pEDIDBuffer, + char *pDataString, + unsigned char bufferSize +) +{ + unsigned char version, revision, tableIndex, charIndex; + + /* If no pointer is given or the buffer size is set to 0, then return fail. */ + if ((pDataString == (char *)0) || (bufferSize == 0)) + return (-1); + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, &revision); + + if ((version == 1) && (revision > 0)) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFE)) + { + bufferSize = (bufferSize > 13) ? 13 : bufferSize; + for (charIndex = 0; charIndex < 13; charIndex++) + { + if (pMonitorDescriptor->descriptor.dataString[charIndex] == 0x0A) + { + pDataString[charIndex] = '\0'; + break; + } + + pDataString[charIndex] = pMonitorDescriptor->descriptor.dataString[charIndex]; + } + + return 0; + } + } + } + + /* Data String is not found. */ + return (-1); +} + +/* + * ddk768_edidGetMonitorRangeLimit + * This function gets the monitor range limits from the EDID structure. + * Only EDID version 1 revision 1 or above supports this feature. + * This is a required field in EDID Version 1.3 + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMinVerticalRate - Pointer to a variable to store the Minimum Vertical Rate (Hz) + * pMaxVerticalRate - Pointer to a variable to store the Maximum Vertical Rate (Hz) + * pMinHorzFreq - Pointer to a variable to store the Minimum Horz. Freq (kHz) + * pMaxHorzFreq - Pointer to a variable to store the Maximum Horz. Freq (kHz) + * pMaxPixelClock - Pointer to a variable to store the Maximum Pixel Clock (Hz) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetMonitorRangeLimit( + unsigned char *pEDIDBuffer, + unsigned char *pMinVerticalRate, + unsigned char *pMaxVerticalRate, + unsigned char *pMinHorzFreq, + unsigned char *pMaxHorzFreq, + unsigned long *pMaxPixelClock +) +{ + unsigned char version, revision, tableIndex; + + if (pEDIDBuffer == (unsigned char *)0) + return (-1); + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, &revision); + + if ((version == 1) && (revision > 0)) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFD) && (pMonitorDescriptor->flag3 == 0)) + { + if (pMinVerticalRate != (unsigned char *)0) + *pMinVerticalRate = pMonitorDescriptor->descriptor.monitorRange.minVertRate; + + if (pMaxVerticalRate != (unsigned char *)0) + *pMaxVerticalRate = pMonitorDescriptor->descriptor.monitorRange.maxVertRate; + + if (pMinHorzFreq != (unsigned char *)0) + *pMinHorzFreq = pMonitorDescriptor->descriptor.monitorRange.minHorzFrequency; + + if (pMaxHorzFreq != (unsigned char *)0) + *pMaxHorzFreq = pMonitorDescriptor->descriptor.monitorRange.maxHorzFrequency; + + if (pMaxPixelClock != (unsigned long *)0) + *pMaxPixelClock = (unsigned long) pMonitorDescriptor->descriptor.monitorRange.maxPixelClock * 10 * 1000000; + + return 0; + } + } + } + + /* Data String is not found. */ + return (-1); +} + +/* + * edidGetChannel1TimingSupport + * This function gets the secondary GTF timing support. + * Only EDID version 1 and revision 1 or above supports this feature. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStartFrequency - Pointer to a variable to store the start frequency of + * the secondary GTF + * pOffset - Pointer to a variable to store the Offset (C) value of + * the secondary GTF + * pGradient - Pointer to a variable to store the Gradient (M) value of + * the secondary GTF + * pScalingFactor - Pointer to a variable to store the Scaling Factor (K) + * value of the secondary GTF + * pScalingFactorWeight - Pointer to a variable to store the Scaling Factore Weight (J) + * value of the secondary GTF + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetChannel1TimingSupport( + unsigned char *pEDIDBuffer, + unsigned short *pStartFrequency, + unsigned char *pOffset, + unsigned short *pGradient, + unsigned char *pScalingFactor, + unsigned char *pScalingFactorWeight +) +{ + unsigned char version, revision, tableIndex; + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, &revision); + + if ((version == 1) && (revision > 0) && (pEDIDBuffer != (unsigned char *)0)) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFD) && + (pMonitorDescriptor->descriptor.monitorRange.secondaryTimingFlag == 0x02)) + { + if (pStartFrequency != (unsigned short *)0) + *pStartFrequency = (unsigned short) + pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.startFrequency * 2 * 1000; + + if (pOffset != (unsigned char *)0) + *pOffset = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.cParam/2; + + if (pGradient != (unsigned short *)0) + *pGradient = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.mParam; + + if (pScalingFactor != (unsigned char *)0) + *pScalingFactor = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.kParam; + + if (pScalingFactorWeight != (unsigned char *)0) + *pScalingFactorWeight = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.jParam / 2; + + return 0; + } + } + } + + /* Data String is not found. */ + return (-1); +} + +/* + * ddk768_edidGetMonitorName + * This function gets the monitor name from the EDID structure. + * This is a required field in EDID Version 1.3 + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorName - Pointer to a buffer to store the monitor name + * retrieved from the EDID + * bufferSize - The size of the buffer to store the monitor name + * The maximum size required is 13 bytes. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetMonitorName( + unsigned char *pEDIDBuffer, + char *pMonitorName, + unsigned char bufferSize +) +{ + unsigned char version, revision, tableIndex, charIndex; + + /* If no pointer is given or the buffer size is set to 0, then return fail. */ + if ((pMonitorName == (char *)0) || (bufferSize == 0)) + return (-1); + + /* Get EDID Version and revision */ + version = ddk768_edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFC) && (pMonitorDescriptor->flag3 == 0)) + { + bufferSize = (bufferSize > 13) ? 13 : bufferSize; + for (charIndex = 0; charIndex < 13; charIndex++) + { + if (pMonitorDescriptor->descriptor.monitorName[charIndex] == 0x0A) + { + pMonitorName[charIndex] = '\0'; + break; + } + + pMonitorName[charIndex] = pMonitorDescriptor->descriptor.monitorName[charIndex]; + } + + return 0; + } + } + } + + /* Data String is not found. */ + return (-1); +} + +/* + * ddk768_edidGetPreferredTiming + * This function gets the preferred/native timing of the monitor + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pWidth - Pointer to an unsigned long buffer to store the width + * of the preferred (native) timing. + * pHeight - Pointer to an unsigned long buffer to store the height + * of the preferred (native) timing. + * pVerticalFrequency - Pointer to an unsigned long buffer to store the refresh + * rate of the preferred (native) timing. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetPreferredTiming( + unsigned char *pEDIDBuffer, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pVerticalFrequency +) +{ + unsigned char index = 0; + vdif_t vdifBuffer; + + + { + /* The preferred (native) timing is available, so get the timing. It is located + at the first index of detailed timing. + */ + if (ddk768_edidGetDetailedTiming(pEDIDBuffer, &index, &vdifBuffer) == 0) + { + if (pWidth != (unsigned long *)0) + *pWidth = vdifBuffer.horizontalActive; + + if (pHeight != (unsigned long *)0) + *pHeight = vdifBuffer.verticalActive; + + if (pVerticalFrequency != (unsigned long *)0) + *pVerticalFrequency = vdifBuffer.verticalFrequency; + + return 0; + } + } + + return (-1); +} diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_edid.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_edid.h new file mode 100644 index 000000000000..9d096525c042 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_edid.h @@ -0,0 +1,793 @@ +/******************************************************************* +* +* Copyright (c) 2009 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* edid.h --- SMI DDK +* This file contains the EDID structure and function API to +* interpret the EDID +* +*******************************************************************/ +#ifndef _EDID_H_ +#define _EDID_H_ + +#include "ddk768_display.h" +#include "vdif.h" +#include "../hw_com.h" + +#define EDID_DEVICE_I2C_ADDRESS 0xA0 +#define TOTAL_EDID_REGISTERS 128 + +/* Set the alignment to 1-bit aligned. Otherwise, it can't get the EDID correctly. */ +#pragma pack(1) + +#define TOTAL_EDID_REGISTERS_128 128 +#define TOTAL_EDID_REGISTERS_256 256 +#define EDID_EXTEND_BLOCK 126 +#define READ_EDID_CONTINUOUS + + +#if 0 /* Temporary on hold. To be completed later. */ + +/* EDID Version 2.0. Not widely used. Usually defined for displays that follow + the original VESA Plug & Display (P&D) and Flat Panel Display Interface-2 (FPDI-2) + Standards + */ +// typedef struct _edid_version_2_t +// { +// /* +// * EDID Structure Version/Revision (1 byte) +// */ +// unsigned char version:4; +// unsigned char revision:4; + +// /* +// * Vendor / Product ID (7 bytes) +// */ +// unsigned short manufacturerID; /* ID Manufacturer Name */ +// unsigned short productID; /* ID Product Code */ +// unsigned char manufactureWeek; /* Week of Manufacture */ +// unsigned short manufactureYear; /* Year of Manufacture */ + +// /* +// * Manufacturer/Product ID string (32 bytes) +// */ +// unsigned char productName; /* This string is compiresed of both manufacture name +// and model name, which are separated using ASCII code 09h. +// If the entire string is <32 bytes, then it is terminated +// with ASCII code 0Ah and the field is padded with ASCII +// code 20h +// */ + +// /* +// * Serial number string (16 bytes) +// */ +// unsigned char serianNumber[16]; /* Serial number string. If <16 bytes then the string is +// terminated with ASCII code 0Ah and the field padded +// with ASCII code 20h +// */ + +// /* +// * Unused/Reserved (8 bytes) +// */ +// unsigned char reserved[8]; + +// /* +// * Display Interface Parameters (15 bytes) +// */ +// unsigned char secondaryPhysicalIF:4; /* Look at defaultPhysicalIF description above. */ +// unsigned char defaultPhysicalIF:4; /* Physical Connector Types. Consists of 2 fields. Bit 7-4 +// indicates the connector for the default interface. If +// a secondary interface is available, its connector is +// indicated using bit 3-0. Both fields value description +// is listed below: +// 0 = None (Not valid for default connector) +// 1 = BNC +// 2 = 15 pin VGA +// 3 = 13w3 +// 4 = VESA EVC +// 5 = VESA P&D-D +// 6 = Micro-ribbon Connector (per the VESA P&D standard) +// 7 = IEEE-1394 connector +// 8 = VESA FPDI-2 +// 9-E = Reserved +// F = Non-standard connector +// */ +// unsigned char secondaryVideoIF:4; /* Look at the defaultVideoIF description above. */ +// unsigned char defaultVideoIF:4; /* Video Interface Types. Consists of 2 fields. Bit 7-4 +// defines the default video interface. Bit 3-0 defines +// the secondary interface. Descriptions of the field is +// listed below: +// 0 = None (Not valid for default interface) +// 1 = Analog +// 2 = Analog w/ sampled pixel clock +// 3 = TMDS (Transition Minimized Differential Signaling) +// 4 = IEEE-1394-1995 +// 5 = LVDS +// 6 = Parallel +// 7-F = Reserved +// */ +// unsigned char analogIFDataFormat[4]; /* Analog Interface Data Format */ +// unsigned char digitalIFDataFormat[4]; /* Digital Interface Data Format */ +// unsigned char secondaryColorEncodingIF:4; /* Channel1 Color Encoding Interface */ +// unsigned char defaultColorEncodingIF:4; /* Color Encoding default Interface */ +// unsigned char primarySubChannel1:4; /* Supported bit-depth of sub-channel 1 ("Green") +// of the Channel0 interface. */ +// unsigned char primarySubChannel0:4; /* Supported bit-depth of sub-channel 0 ("Red") +// of the Channel0 interface. */ +// unsigned char primarySubChannel3:4; /* Supported bit-depth of sub-channel 3 of the +// Channel0 interface. */ +// unsigned char primarySubChannel2:4; /* Supported bit-depth of sub-channel 2 ("Blue") +// of the Channel0 interface. */ +// unsigned char secondarySubChannel1:4; /* Supported bit-depth of sub-channel 1 ("Green") +// of the Channel1 interface. */ +// unsigned char secondarySubChannel0:4; /* Supported bit-depth of sub-channel 0 ("Red") +// of the Channel1 interface. */ +// unsigned char secondarySubChannel3:4; /* Supported bit-depth of sub-channel 3 of the +// Channel1 interface. */ +// unsigned char secondarySubChannel2:4; /* Supported bit-depth of sub-channel 2 ("Blue") +// of the Channel1 interface. */ + +// /* +// * Display Device Description (5 bytes) +// */ +// unsigned char displayType; /* Display technology type/subtype*/ +// unsigned char displayCharacteristic; /* Major display characteristics. */ +// unsigned char featureSupport[3]; /* Feature Support */ + +// /* +// * Display Response Time (2 bytes) +// */ +// unsigned char riseTimeResponse:4; /* Rise time response in seconds */ +// unsigned char riseTimeExponent:4; /* Rise time exponent */ +// unsigned char fallTimeResponse:4; /* Fall time response in seconds */ +// unsigned char fallTimeExponent:4; /* Fall time exponent */ + +// /* +// * Color / Luminance Description (28 bytes) +// */ +// unsigned char whiteGamme; /* (Gamma x 100) - 100, [range 1.00 --> 3.55] */ +// unsigned char redGamma; /* Color 0 ("red") Gamma (optional). Set to ffh if unused. */ +// unsigned char greenGamma; /* Color 1 ("green") Gamma (optional). Set to ffh if unused. */ +// unsigned char blueGamma; /* Color 2 ("blue") Gamma (optional). Set to ffh if unused. */ +// unsigned short maxLuminance; /* Maximum LUminance (white) in units of cd/m^2*10 */ +// unsigned char colorConfig; /* Standard RGB Model, adjustable Gamma and its offset */ +// unsigned char offsetValue; /* Color Offset value */ + +// /* Calorimetry and White Point(s) */ +// unsigned char redGreenLowBits; /* Red / Green Low Bits */ +// } +// edid_version_2_t; + +#endif + +/* Restore alignment */ +#pragma pack() + +/************************************************************** + * Function Prototypes + **************************************************************/ + +/* + * ddk768_edidGetVersion + * This function gets the EDID version + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRevision - Revision of the EDIE (if exist) + * + * Output: + * Revision number of the given EDID buffer. + */ +unsigned char ddk768_edidGetVersion( + unsigned char *pEDIDBuffer, + unsigned char *pRevision +); + +/* + * ddk768_edidGetProductInfo + * This function gets the vendor and product information. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor [in] + * pManufacturerName - Pointer to a 3 byte length variable to store the manufacturer name [out] + * pProductCode - Pointer to a variable to store the product code [out] + * pSerialNumber - Pointer to a variable to store the serial number [out] + * pWeekOfManufacture - Pointer to a variable to store the week of manufacture [out] + * pYearOfManufacture - Pointer to a variable to store the year of manufacture + * or model year (if WeekOfManufacture is 0xff) [out] + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetProductInfo( + unsigned char *pEDIDBuffer, + char *pManufacturerName, + unsigned short *pProductCode, + unsigned long *pSerialNumber, + unsigned char *pWeekOfManufacture, + unsigned short *pYearOfManufacture +); + +/* + * ddk768_edidCheckMonitorInputSignal + * This function checks whether the monitor is expected analog/digital + * input signal. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Analog + * 1 - Digital + */ +unsigned char ddk768_edidCheckMonitorInputSignal( + unsigned char *pEDIDBuffer +); + +/* + * ddk768_edidGetAnalogSignalInfo + * This function gets the analog video input signal information + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRefWhiteAboveBlank - Pointer to a variable to store the reference white above blank + * value. The value is in milliVolt. + * pSyncLevelBelowBlank - Pointer to a variable to store the Sync tip level below blank + * The value is also in milliVolt + * pBlank2BlackSetup - Pointer to a variable to store the Blank to black setup or + * pedestal per appropriate Signal Level Standard flag. + * 1 means that the display expect the setup. + * pSeparateSyncSupport - Pointer to a variable to store the flag to indicate that the + * monitor supports separate sync. + * pCompositeSyncSupport - Pointer to a variable to store a flag to indicate that the + * monitor supports composite sync. + * pSyncOnGreenSupport - Pointer to a variable to store a flag to indicate that + * the monitor supports sync on green video. + * pVSyncSerrationRequired - Pointer to a variable to store a flag to indicate that serration + * of the VSync pulse is required when composite sync or + * sync-on-green video is used. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetAnalogSignalInfo( + unsigned char *pEDIDBuffer, + unsigned short *pRefWhiteAboveBlank, + unsigned short *pSyncLevelBelowBlank, + unsigned char *pBlank2BlackSetup, + unsigned char *pSeparateSyncSupport, + unsigned char *pCompositeSyncSupport, + unsigned char *pSyncOnGreenSupport, + unsigned char *pVSyncSerrationRequired +); + +/* + * ddk768_edidGetDigitalSignalInfo + * This function gets the digital video input signal information + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pDFP1xSupport - Pointer to a variable to store the flag to indicate that + * the mointor interface is signal compatible with VESA + * DFP 1.x TMDS CRGB, 1 pixel/clock, up to 8 bits / color + * MSB aligned, DE active high + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetDigitalSignalInfo( + unsigned char *pEDIDBuffer, + unsigned char *pDFP1xSupport +); + +/* + * ddk768_edidGetDisplaySize + * This function gets the display sizes in cm. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMaxHorzImageSize - Pointer to a variable to store the maximum horizontal + * image size to the nearest centimeter. A value of 0 + * indicates that the size is indeterminate size. + * pMaxVertImageSize - Pointer to a variable to store the maximum vertical + * image size to the nearest centimeter. A value of 0 + * indicates that the size is indeterminate size. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetDisplaySize( + unsigned char *pEDIDBuffer, + unsigned char *pMaxHorzImageSize, + unsigned char *pMaxVertImageSize +); + +/* + * ddk768_edidGetPowerManagementSupport + * This function gets the monitor's power management support. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStandBy - Pointer to a variable to store the flag to indicate that + * standby power mode is supported. + * pSuspend - Pointer to a variable to store the flag to indicate that + * suspend power mode is supported. + * pLowPower - Pointer to a variable to store the flag to indicate that + * the display consumes low power when it receives a timing + * signal that is outside its declared active operating range. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetPowerManagementSupport( + unsigned char *pEDIDBuffer, + unsigned char *pStandBy, + unsigned char *pSuspend, + unsigned char *pLowPower +); + +/* + * ddk768_edidGetDisplayType + * This function gets the display type. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Monochrome / grayscale display + * 1 - RGB Color Display + * 2 - Non-RGB multicolor display, e.g. R/G/Y + * 3 - Undefined + */ +unsigned char ddk768_edidGetDisplayType( + unsigned char *pEDIDBuffer +); + +/* + * ddk768_edidChecksRGBUsage + * This function checks if the display is using the sRGB standard default + * color space as its primary color space. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Does not use sRGB as its primary color space + * 1 - Use sRGB as its primary color space + */ +unsigned char ddk768_edidChecksRGBUsage( + unsigned char *pEDIDBuffer +); + +/* + * ddk768_edidIsPreferredTimingAvailable + * This function checks whether the preffered timing mode is available. + * Use of preferred timing mode is required by EDID structure version 1 + * Revision 3 and higher. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Preferred Timing is not available + * 1 - Preferred Timing is available + */ +unsigned char ddk768_edidIsPreferredTimingAvailable( + unsigned char *pEDIDBuffer +); + +/* + * ddk768_edidIsDefaultGTFSupported + * This function checks whether the display supports timings based on the + * GTF standard using default GTF parameter values. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Default GTF is not supported + * 1 - Default GTF is supported + */ +unsigned char ddk768_edidIsDefaultGTFSupported( + unsigned char *pEDIDBuffer +); + +/* + * ddk768_edidGetColorCharacteristic + * This function gets the chromaticity and white point values expressed as + * an integer value which represents the actual value times 1000. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRedX - Pointer to a variable to store the Red X values + * pRedY - Pointer to a variable to store the Red Y values + * pGreenX - Pointer to a variable to store the Green X values + * pGreenY - Pointer to a variable to store the Green Y values + * pBlueX - Pointer to a variable to store the Blue X values + * pBlueY - Pointer to a variable to store the Blue Y values + * + * Note: + * To get the White color characteristic, use the ddk768_edidGetWhitePoint + */ +void ddk768_edidGetColorCharacteristic( + unsigned char *pEDIDBuffer, + unsigned short *pRedX, + unsigned short *pRedY, + unsigned short *pGreenX, + unsigned short *pGreenY, + unsigned short *pBlueX, + unsigned short *pBlueY +); + +/* + * ddk768_edidGetWhitePoint + * This function gets the white point. + * To get the default white point, set the index to 0. For multiple white point, + * call this function multiple times to check if more than 1 white point is supported. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pWhitePointIndex - Pointer to a variable that contains the white point index + * to be retrieved. + * pWhiteX - Pointer to a variable to store the White X value + * pWhiteY - Pointer to a variable to store the White Y value + * pWhiteGamma - Pointer to a variable to store the White Gamma value + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetWhitePoint( + unsigned char *pEDIDBuffer, + unsigned char *pWhitePointIndex, + unsigned short *pWhiteX, + unsigned short *pWhiteY, + unsigned short *pWhiteGamma +); + +/* + * This function is same as editReadMonitorEx(), but using HW I2C. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * i2cNumber - 0 = I2C0 and 1 = I2C1 + * + * Output: + * 0 - Fail + * edidSize - Success and return the edid's size. + */ +long ddk768_edidReadMonitorExHwI2C( + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char i2cNumber +); + +long ddk768_edidHeaderReadMonitorExHwI2C( + unsigned char i2cNumber +); + +/* + * ddk768_edidGetExtension + * This function gets the number of (optional) EDID extension blocks to follow + * the given EDID buffer. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * Total number of EDID Extension to follow the given EDID buffer. + */ +unsigned char ddk768_edidGetExtension( + unsigned char *pEDIDBuffer +); + +/* + * ddk768_edidReadMonitor + * This function reads the EDID structure from the attached monitor + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * i2cNumber - 0 = I2c0 and 1 = 12c1 + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidReadMonitor( + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char i2cNumber +); + +/* + * ddk768_edidReadMonitor + * This function reads the EDID structure from the attached monitor + * + * Input: + * displayPath - Display device which EDID to be read from. + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * sclGpio - GPIO pin used as the I2C Clock (SCL) + * sdaGpio - GPIO pin used as the I2C Data (SDA) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidReadMonitorEx( + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char sclGpio, + unsigned char sdaGpio +); + +/* + * This function is same as editReadMonitorEx(), but using HW I2C. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * i2cNumber - 0 = I2C0 and 1 = I2C1 + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidReadMonitorExHwI2C( + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char i2cNumber +); + +long ddk750_edidHeaderReadMonitorExHwI2C(void); +long ddk750_edidHeaderReadMonitorEx( + unsigned char sclGpio, + unsigned char sdaGpio +); + + +/* + * ddk768_edidGetEstablishedTiming + * This function gets the established timing list from the given EDID buffer, + * table, and timing index. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor (In) + * pEstTableIndex - Pointer to the Established Timing Table index (In/Out) + * pIndex - Pointer to the Establihsed Timing Index (In/Out) + * pWidth - Pointer to a variable that to store the horizontal active / width + * value of the retrieved timing (Out) + * pHeight - Pointer to a variable to store the vertical active / height + * value of the retrieved timing (Out) + * pRefreshRate - Pointer to a variable to store the vertical frequency value + * of the retrieved timing (out) + * pSource - Pointer to a variable to store the standard timing source: + * 0 - VESA + * 1 - IBM + * 2 - Apple + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetEstablishedTiming( + unsigned char *pEDIDBuffer, + /*unsigned char *pEstTableIndex,*/ + unsigned char *pIndex, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pRefreshRate, + unsigned char *pSource +); + +/* + * ddk768_edidGetStandardTiming + * This function gets the standard timing from the given EDID buffer and + * calculates the width, height, and vertical frequency from that timing. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStdTimingIndex - Pointer to a standard timing index to be retrieved + * pWidth - Pointer to a variable that to store the horizontal active / width + * value of the retrieved timing (Out) + * pHeight - Pointer to a variable to store the vertical active / height + * value of the retrieved timing (Out) + * pRefreshRate - Pointer to a variable to store the vertical frequency value + * of the retrieved timing (out) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetStandardTiming( + unsigned char *pEDIDBuffer, + unsigned char *pStdTimingIndex, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pRefreshRate +); + +/* + * ddk768_edidGetDetailedTiming + * This function gets the detailed timing from the given EDID buffer. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pDetailedTimingIndex - Pointer to a detailed timing index to be retrieved + * pModeParameter - Pointer to a mode_parameter_t structure that will be + * filled with the detailed timing. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetDetailedTiming( + unsigned char *pEDIDBuffer, + unsigned char *pDetailedTimingIndex, + vdif_t *pVDIF +); + +/* + * ddk768_edidGetMonitorSerialNumber + * This function gets the monitor serial number from the EDID structure. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorSerialNumber - Pointer to a buffer to store the serial number + * retrieved from the EDID + * bufferSize - The size of the buffer to store the serial number. + * The maximum size required is 13 bytes. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetMonitorSerialNumber( + unsigned char *pEDIDBuffer, + char *pMonitorSerialNumber, + unsigned char bufferSize +); + +/* + * ddk768_edidGetDataString + * This function gets the data string from the EDID structure. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorSerialNumber - Pointer to a buffer to store the data string + * retrieved from the EDID + * bufferSize - The size of the buffer to store the data string + * The maximum size required is 13 bytes. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetDataString( + unsigned char *pEDIDBuffer, + char *pDataString, + unsigned char bufferSize +); + +/* + * ddk768_edidGetMonitorRangeLimit + * This function gets the monitor range limits from the EDID structure. + * Only EDID version 1 and revision 1 or above supports this feature. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMinVerticalRate - Pointer to a variable to store the Minimum Vertical Rate (Hz) + * pMaxVerticalRate - Pointer to a variable to store the Maximum Vertical Rate (Hz) + * pMinHorzFreq - Pointer to a variable to store the Minimum Horz. Freq (kHz) + * pMaxHorzFreq - Pointer to a variable to store the Maximum Horz. Freq (kHz) + * pMaxPixelClock - Pointer to a variable to store the Maximum Pixel Clock (Hz) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetMonitorRangeLimit( + unsigned char *pEDIDBuffer, + unsigned char *pMinVerticalRate, + unsigned char *pMaxVerticalRate, + unsigned char *pMinHorzFreq, + unsigned char *pMaxHorzFreq, + unsigned long *pMaxPixelClock +); + +/* + * edidGetChannel1TimingSupport + * This function gets the secondary GTF timing support. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStartFrequency - Pointer to a variable to store the start frequency of + * the secondary GTF + * pOffset - Pointer to a variable to store the Offset (C) value of + * the secondary GTF + * pGradient - Pointer to a variable to store the Gradient (M) value of + * the secondary GTF + * pScalingFactor - Pointer to a variable to store the Scaling Factor (K) + * value of the secondary GTF + * pScalingFactorWeight - Pointer to a variable to store the Scaling Factore Weight (J) + * value of the secondary GTF + * + * Output: + * 0 - Success + * -1 - Fail + */ +long edidGetChannel1TimingSupport( + unsigned char *pEDIDBuffer, + unsigned short *pStartFrequency, + unsigned char *pOffset, + unsigned short *pGradient, + unsigned char *pScalingFactor, + unsigned char *pScalingFactorWeight +); + +/* + * ddk768_edidGetMonitorName + * This function gets the monitor name from the EDID structure. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorName - Pointer to a buffer to store the monitor name + * retrieved from the EDID + * bufferSize - The size of the buffer to store the monitor name + * The maximum size required is 13 bytes. + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetMonitorName( + unsigned char *pEDIDBuffer, + char *pMonitorName, + unsigned char bufferSize +); + +/* + * ddk768_edidGetPreferredTiming + * This function gets the preferred/native timing of the monitor + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pWidth - Pointer to an unsigned long buffer to store the width + * of the preferred (native) timing. + * pHeight - Pointer to an unsigned long buffer to store the height + * of the preferred (native) timing. + * pVerticalFrequency - Pointer to an unsigned long buffer to store the refresh + * rate of the preferred (native) timing. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_edidGetPreferredTiming( + unsigned char *pEDIDBuffer, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pVerticalFrequency +); + +#endif /* _EDID_H_ */ + + + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_ep952.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_ep952.c new file mode 100644 index 000000000000..43dccec25dcc --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_ep952.c @@ -0,0 +1,911 @@ +#include +#include +#include + + +#include "ddk768_power.h" +#include "ddk768_intr.h" +#include "ddkdebug.h" +#include "ddk768_edid.h" +#include "ddk768_timer.h" + + +#include "ddk768_ep952.h" + +#include "ddk768_swi2c.h" +#include "../ddk750/ddk750_swi2c.h" + + +#include "ddk768_help.h" +#include "ddk768_display.h" +#include "ddk768_reg.h" + +#include "ep952api.h" +#include "ep952controller.h" // HDMI Transmiter +#include "ep952settingsdata.h" + + + +#ifdef HDMI_DEBUG +#define HDMI_DEBUG_Printf printk +#else +#define HDMI_DEBUG_Printf(fmt,...) +#endif + +int is_SM768 = 0; + +void EP952_Register_Message(void); + + + +EP952C_REGISTER_MAP EP952C_Registers = {0}; +// Private Data +unsigned char IIC_EP952_Addr, IIC_HDCPKey_Addr; +unsigned short TempUSHORT; +//unsigned char Temp_Data[15]; + +// Global date for HDMI Transmiter +unsigned char is_RSEN; +unsigned char Cache_EP952_DE_Control; + +// Private Functions +static unsigned char IIC_Write(unsigned char IICAddr, unsigned char ByteAddr, unsigned char *Data, unsigned int Size); +static unsigned char IIC_Read(unsigned char IICAddr, unsigned char ByteAddr, unsigned char *Data, unsigned int Size); + +//================================================================================================== +// +// Private Functions +// + +static unsigned char IIC_Write(unsigned char IICAddr, unsigned char ByteAddr, unsigned char *Data, unsigned int Size) +{ + ///////////////////////////////////////////////////////////////////////////////////////////////// + // return 0; for success + // return 2; for No_ACK + // return 4; for Arbitration + ///////////////////////////////////////////////////////////////////////////////////////////////// + + unsigned char status = 0; + unsigned int i; + + + for (i = 0; i < Size; i++) + { + if(is_SM768) + ddk768_swI2CWriteReg(IICAddr, (ByteAddr + i), *(Data + i)); + else + swI2CWriteReg(IICAddr, (ByteAddr + i), *(Data + i)); + } + return status; + +} + +static unsigned char IIC_Read(unsigned char IICAddr, unsigned char ByteAddr, unsigned char *Data, unsigned int Size) +{ + ///////////////////////////////////////////////////////////////////////////////////////////////// + // return 0; for success + // return 2; for No_ACK + // return 4; for Arbitration + ///////////////////////////////////////////////////////////////////////////////////////////////// + + unsigned char status = 0; + unsigned int i; + + for (i = 0; i < Size; i++) + { + if(is_SM768) + *(Data + i) = ddk768_swI2CReadReg(IICAddr,(ByteAddr + i)); + else + *(Data + i) = swI2CReadReg(IICAddr,(ByteAddr + i)); + } + + return status; + +} +//-------------------------------------------------------------------------------------------------- +// +// Hardware Interface +// + +unsigned char EP952_Reg_Read(unsigned char ByteAddr, unsigned char *Data, unsigned int Size) +{ + return IIC_Read(IIC_EP952_Addr, ByteAddr, Data, Size); +} + +unsigned char EP952_Reg_Write(unsigned char ByteAddr, unsigned char *Data, unsigned int Size) +{ + return IIC_Write(IIC_EP952_Addr, ByteAddr, Data, Size); +} + +unsigned char EP952_Reg_Set_Bit(unsigned char ByteAddr, unsigned char BitMask) +{ + int result = 1; + unsigned char Temp_Data[15] = {0}; + result = IIC_Read(IIC_EP952_Addr, ByteAddr, Temp_Data, 1); + if(result == 0) + { + // Write back to Reg Reg_Addr + Temp_Data[0] |= BitMask; + + return IIC_Write(IIC_EP952_Addr, ByteAddr, Temp_Data, 1); + } + else + { + return result; + } +} + +unsigned char EP952_Reg_Clear_Bit(unsigned char ByteAddr, unsigned char BitMask) +{ + int result = 1; + unsigned char Temp_Data[15] = {0}; + result = IIC_Read(IIC_EP952_Addr, ByteAddr, Temp_Data, 1); + if(result == 0) + { + // Write back to Reg Reg_Addr + Temp_Data[0] &= ~BitMask; + + return IIC_Write(IIC_EP952_Addr, ByteAddr, Temp_Data, 1); + } + else + { + return result; + } +} + +//================================================================================================== +// +// Public Function Implementation +// + +//-------------------------------------------------------------------------------------------------- +// Hardware Interface + +void EP952_IIC_Initial() +{ + unsigned char Temp_Data[15] = {0}; + IIC_EP952_Addr = 0x52; // EP952 slave address + IIC_HDCPKey_Addr = 0xA8; // HDCP Key (EEPROM) slave address + + + // Initial Variables + Temp_Data[0] = EP952_TX_PHY_Control_0__TERM_ON; + EP952_Reg_Write(EP952_TX_PHY_Control_0, Temp_Data, 1); + + Temp_Data[0] = 0; + EP952_Reg_Write(EP952_TX_PHY_Control_1, Temp_Data, 1); + + +} + +void EP952_Info_Reset(void) +{ + int i; + unsigned char Temp_Data[15] = {0}; + // Global date for HDMI Transmiter + is_RSEN = 0; + Cache_EP952_DE_Control = 0x03; + + // Initial Settings + EP952_Reg_Set_Bit(EP952_Packet_Control, EP952_Packet_Control__VTX0); + EP952_Reg_Set_Bit(EP952_General_Control_1, EP952_General_Control_1__INT_OD); + + // + // Set Default AVI Info Frame + // + memset(Temp_Data, 0x00, 14); + + // Set AVI Info Frame to RGB + Temp_Data[1] &= 0x60; + Temp_Data[1] |= 0x00; // RGB + + // Set AVI Info Frame to 601 + Temp_Data[2] &= 0xC0; + Temp_Data[2] |= 0x40; + + // Write AVI Info Frame + Temp_Data[0] = 0; + for(i=1; i<14; ++i) { + Temp_Data[0] += Temp_Data[i]; + } + Temp_Data[0] = ~(Temp_Data[0] - 1); + EP952_Reg_Write(EP952_AVI_Packet, Temp_Data, 14); + + // + // Set Default ADO Info Frame + // + memset(Temp_Data, 0x00, 6); + + // Write ADO Info Frame + Temp_Data[0] = 0; + for(i=1; i<6; ++i) { + Temp_Data[0] += Temp_Data[i]; + } + Temp_Data[0] = ~(Temp_Data[0] - 1); + EP952_Reg_Write(EP952_ADO_Packet, Temp_Data, 6); + + // + // Set Default CS Info Frame + // + memset(Temp_Data, 0x00, 5); + + EP952_Reg_Write(EP952_Channel_Status, Temp_Data, 5); +/* + // + // clear Packet_1 Info Frame + // + Temp_Data[0] = 0; + for(i=EP952_Data_Packet_Header; i<= 0x5F; i++) { + EP952_Reg_Write(i, Temp_Data, 1); + } +*/ +} + + +// System flags +unsigned char is_Cap_dsel; +unsigned char is_Cap_HDMI; +unsigned char is_Cap_YCC444; +unsigned char is_Cap_YCC422; +unsigned char is_Forced_Output_RGB; + +unsigned char is_Hot_Plug; +unsigned char is_Connected; +unsigned char is_ReceiverSense; +unsigned char ChkSum, ConnectionState; +unsigned char EP952_Debug = 0; + +// System Data +unsigned char HP_ChangeCount; +unsigned char PowerUpCount; +TX_STATE TX_State; +VDO_PARAMS Video_Params; +ADO_PARAMS Audio_Params; +PEP952C_REGISTER_MAP pEP952C_Registers; + +//------------------------------------ +// Special for config + +void HDMI_Tx_AMute_Enable(void) +{ + EP952_Reg_Set_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__AMUTE); + EP952_Reg_Set_Bit(EP952_Pixel_Repetition_Control, EP952_Pixel_Repetition_Control__CTS_M); + + EP952_Reg_Clear_Bit(EP952_IIS_Control, EP952_IIS_Control__ADO_EN); + EP952_Reg_Clear_Bit(EP952_IIS_Control, EP952_IIS_Control__AUDIO_EN); +} + +void HDMI_Tx_AMute_Disable(void) +{ + EP952_Reg_Clear_Bit(EP952_Pixel_Repetition_Control, EP952_Pixel_Repetition_Control__CTS_M); + EP952_Reg_Clear_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__AVMUTE); + EP952_Reg_Clear_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__AMUTE); + + EP952_Reg_Set_Bit(EP952_IIS_Control, EP952_IIS_Control__ADO_EN); + EP952_Reg_Set_Bit(EP952_IIS_Control, EP952_IIS_Control__AUDIO_EN); +} + +void HDMI_Tx_VMute_Enable(void) +{ + EP952_Reg_Set_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__VMUTE); +} + +void HDMI_Tx_VMute_Disable(void) +{ + EP952_Reg_Clear_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__AVMUTE); + EP952_Reg_Clear_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__VMUTE); +} + +//-------------------------------------------------------------------------------------------------- +// +// HDMI Transmiter (EP952-Tx Implementation) +// + +void HDMI_Tx_HDMI(void) +{ + EP952_Reg_Set_Bit(EP952_General_Control_4, EP952_General_Control_4__HDMI); +} + +void HDMI_Tx_DVI(void) +{ + EP952_Reg_Clear_Bit(EP952_General_Control_4, EP952_General_Control_4__HDMI); +} + +void HDMI_Tx_Power_Down(void) +{ + // Software power down + EP952_Reg_Clear_Bit(EP952_General_Control_1, EP952_General_Control_1__PU); +} + +void HDMI_Tx_Power_Up(void) +{ + // Software power up + EP952_Reg_Set_Bit(EP952_General_Control_1, EP952_General_Control_1__PU); +} + +void HDMI_Tx_Mute_Enable(void) +{ + HDMI_Tx_AMute_Enable(); + HDMI_Tx_VMute_Enable(); +} + +void HDMI_Tx_Mute_Disable(void) +{ + HDMI_Tx_VMute_Disable(); + HDMI_Tx_AMute_Disable(); +} + +void HDMI_Tx_HDCP_Disable(void) +{ + EP952_Reg_Clear_Bit(EP952_General_Control_5, EP952_General_Control_5__ENC_EN); +} + +void EP952_HDCP_Reset(void) +{ + pEP952C_Registers->System_Status |= EP_TX_System_Status__KEY_FAIL; + pEP952C_Registers->System_Configuration |= EP_TX_System_Configuration__HDCP_DIS; +} + +VDO_SETTINGS EP952_VDO_Settings[] = { + // HVRes_Type, DE_Gen(DLY,CNT,TOP,LIN), E_Sync, AR_PR, Pix_Freq_Type, + { 0,{ 0, 0, 0, 0},{ 0, 0, 0, 0},{0x00, 0, 0, 0, 0, 0}, 0x00, PIX_FREQ_25175KHz}, // 0: + // HDMI Mode + { 1,{VNegHNeg, 800, 525,16666},{ 48, 640, 34, 480},{0x00, 12, 96, 10, 2, 0}, 0x10, PIX_FREQ_25175KHz}, // 1: 640 x 480p + { 2,{VNegHNeg, 858, 525,16666},{ 60, 720, 31, 480},{0x00, 12, 62, 9, 6, 0}, 0x10, PIX_FREQ_27000KHz}, // 2: 720 x 480p 4:3 + { 3,{VNegHNeg, 858, 525,16666},{ 60, 720, 31, 480},{0x00, 12, 62, 9, 6, 0}, 0x20, PIX_FREQ_27000KHz}, // 3: 720 x 480p 16:9 + { 4,{VPosHPos,1650, 750,16666},{220,1280, 21, 720},{0x00,106, 40, 5, 5, 0}, 0x20, PIX_FREQ_74176KHz}, // 4: 1280 x 720p + { 5,{VPosHPos,2200, 563,16666},{148,1920, 16, 540},{0x09, 84, 44, 2, 5,1100}, 0x20, PIX_FREQ_74176KHz}, // 5: 1920 x 1080i + { 6,{VNegHNeg, 858, 262,16666},{ 57, 720, 16, 240},{0x09, 15, 62, 4, 3, 429}, 0x15, PIX_FREQ_27000KHz}, // 6: 720 x 480i, pix repl + { 7,{VNegHNeg, 858, 262,16666},{ 57, 720, 16, 240},{0x09, 15, 62, 4, 3, 429}, 0x25, PIX_FREQ_27000KHz}, // 7: 720 x 480i, pix repl + { 8,{VNegHNeg, 858, 262,16666},{ 57, 720, 16, 240},{0x00, 15, 62, 4, 3, 0}, 0x15, PIX_FREQ_27000KHz}, // 8: 720 x 240p, pix repl + { 9,{VNegHNeg, 858, 262,16666},{ 57, 720, 16, 240},{0x00, 15, 62, 4, 3, 0}, 0x25, PIX_FREQ_27000KHz}, // 9: 720 x 240p, pix repl + { 10,{VNegHNeg,3432, 262,16666},{228,2880, 16, 240},{0x09, 72,248, 4, 3,1716}, 0x10, PIX_FREQ_54000KHz}, // 10: 2880 x 480i 4:3 + { 11,{VNegHNeg,3432, 262,16666},{228,2880, 16, 240},{0x09, 72,248, 4, 3,1716}, 0x20, PIX_FREQ_54000KHz}, // 11: 2880 x 480i 16:9 + { 12,{VNegHNeg,3432, 262,16666},{228,2880, 16, 240},{0x00, 72,248, 4, 3, 0}, 0x10, PIX_FREQ_54000KHz}, // 12: 2880 x 240p 4:3 + { 13,{VNegHNeg,3432, 262,16666},{228,2880, 16, 240},{0x00, 72,248, 4, 3, 0}, 0x20, PIX_FREQ_54000KHz}, // 13: 2880 x 240p 16:9 + { 14,{VNegHNeg,1716, 525,16666},{120,1440, 31, 480},{0x00, 28,124, 9, 6, 0}, 0x10, PIX_FREQ_54000KHz}, // 14: 1440 x 480p 4:3 + { 15,{VNegHNeg,1716, 525,16666},{120,1440, 31, 480},{0x00, 28,124, 9, 6, 0}, 0x20, PIX_FREQ_54000KHz}, // 15: 1440 x 480p 16:9 + { 16,{VPosHPos,2200,1125,16666},{148,1920, 37,1080},{0x00, 84, 44, 4, 5, 0}, 0x20, PIX_FREQ_148500KHz}, // 16: 1920 x 1080p + { 17,{VNegHNeg, 864, 625,20000},{ 68, 720, 40, 576},{0x00, 8, 64, 5, 5, 0}, 0x10, PIX_FREQ_27000KHz}, // 17: 720 x 576p 4:3 + { 18,{VNegHNeg, 864, 625,20000},{ 68, 720, 40, 576},{0x00, 8, 64, 5, 5, 0}, 0x20, PIX_FREQ_27000KHz}, // 18: 720 x 576p 16:9 + { 19,{VPosHPos,1980, 750,20000},{220,1280, 21, 720},{0x00,436, 40, 5, 5, 0}, 0x20, PIX_FREQ_74250KHz}, // 19: 1280 x 720p, 50 Hz + { 20,{VPosHPos,2640, 563,20000},{148,1920, 16, 540},{0x09,524, 44, 2, 5,1320}, 0x20, PIX_FREQ_74250KHz}, // 20: 1920 x 1080i, 50 Hz + { 21,{VNegHNeg, 864, 313,20000},{ 69, 720, 20, 288},{0x09, 8, 63, 2, 3, 432}, 0x15, PIX_FREQ_27000KHz}, // 21: 720 x 576i, pix repl + { 22,{VNegHNeg, 864, 313,20000},{ 69, 720, 20, 288},{0x09, 8, 63, 2, 3, 432}, 0x25, PIX_FREQ_27000KHz}, // 22: 720 x 576i, pix repl + { 23,{VNegHNeg, 864, 313,20000},{ 69, 720, 20, 288},{0x00, 8, 63, 3, 3, 0}, 0x15, PIX_FREQ_27000KHz}, // 23: 720 x 288p, pix repl + { 24,{VNegHNeg, 864, 313,20000},{ 69, 720, 20, 288},{0x00, 8, 63, 3, 3, 0}, 0x25, PIX_FREQ_27000KHz}, // 24: 720 x 288p, pix repl + { 25,{VNegHNeg,3456, 313,20000},{276,2880, 20, 288},{0x09, 44,252, 2, 3,1728}, 0x10, PIX_FREQ_54000KHz}, // 25: 2880 x 576i + { 26,{VNegHNeg,3456, 313,20000},{276,2880, 20, 288},{0x09, 44,252, 2, 3,1728}, 0x20, PIX_FREQ_54000KHz}, // 26: 2880 x 576i + { 27,{VNegHNeg,3456, 313,20000},{276,2880, 20, 288},{0x00, 44,252, 3, 3, 0}, 0x10, PIX_FREQ_54000KHz}, // 27: 2880 x 288p + { 28,{VNegHNeg,3456, 313,20000},{276,2880, 20, 288},{0x00, 44,252, 3, 3, 0}, 0x20, PIX_FREQ_54000KHz}, // 28: 2880 x 288p + { 29,{VPosHNeg,1728, 625,20000},{136,1440, 40, 576},{0x00, 20,128, 5, 5, 0}, 0x10, PIX_FREQ_54000KHz}, // 29: 1440 x 576p + { 30,{VPosHNeg,1728, 625,20000},{136,1440, 40, 576},{0x00, 20,128, 5, 5, 0}, 0x20, PIX_FREQ_54000KHz}, // 30: 1440 x 576p + { 31,{VPosHPos,2640,1125,20000},{148,1920, 37,1080},{0x00,524, 44, 4, 5, 0}, 0x20, PIX_FREQ_148500KHz}, // 31: 1920 x 1080p, 50 Hz + { 32,{VPosHPos,2750,1125,41666},{148,1920, 37,1080},{0x00,634, 44, 4, 5, 0}, 0x20, PIX_FREQ_74176KHz}, // 32: 1920 x 1080p + { 33,{VPosHPos,2640,1125,40000},{148,1920, 37,1080},{0x00,524, 44, 4, 5, 0}, 0x20, PIX_FREQ_74250KHz}, // 33: 1920 x 1080p, 25 Hz + { 34,{VPosHPos,2200,1125,33333},{148,1920, 37,1080},{0x00, 84, 44, 4, 5, 0}, 0x20, PIX_FREQ_74176KHz}, // 34: 1920 x 1080p + +}; + +unsigned char EP952_VDO_Settings_Max = (sizeof(EP952_VDO_Settings)/sizeof(EP952_VDO_Settings[0])); + +void HDMI_Tx_Video_Config(PVDO_PARAMS Params) +{ + int i; + unsigned char Temp_Data[15] = {0}; + + // Disable auto transmission AVI packet + EP952_Reg_Clear_Bit(EP952_IIS_Control, EP952_IIS_Control__AVI_EN); + + //////////////////////////////////////////////////////// + // Video Interface + + // De_Skew + EP952_Reg_Read(EP952_General_Control_3, Temp_Data, 1); + Temp_Data[0] &= ~0xF0; + Temp_Data[0] |= Params->Interface & 0xF0; + EP952_Reg_Write(EP952_General_Control_3, Temp_Data, 1); + + // input DSEL BSEL EDGE + EP952_Reg_Read(EP952_General_Control_1, Temp_Data, 1); + Temp_Data[0] &= ~0x0E; + Temp_Data[0] |= Params->Interface & 0x0E; + if(is_Cap_dsel) + Temp_Data[0] |= 0x08; // DSEL = 1 + else + Temp_Data[0] &= 0xf7; // DSEL = 0 + EP952_Reg_Write(EP952_General_Control_1, Temp_Data, 1); + + if(Params->Interface & 0x01) { + EP952_Reg_Set_Bit(EP952_General_Control_4, EP952_General_Control_4__FMT12); + } + else { + EP952_Reg_Clear_Bit(EP952_General_Control_4, EP952_General_Control_4__FMT12); + } + + // update HVPol + EP952_Reg_Read(EP952_General_Control_4, Temp_Data, 1); + Params->HVPol = Temp_Data[0] & (EP952_DE_Control__VSO_POL | EP952_DE_Control__HSO_POL); + + //////////////////////////////////////////////////////// + // Sync Mode + switch(Params->SyncMode) { + default: + case SYNCMODE_HVDE: + // Disable E_SYNC + EP952_Reg_Clear_Bit(EP952_General_Control_4, EP952_General_Control_4__E_SYNC); + // Disable DE_GEN + Cache_EP952_DE_Control &= ~EP952_DE_Control__DE_GEN; + + // Regular VSO_POL, HSO_POL + if((Params->HVPol & VNegHPos) != (EP952_VDO_Settings[Params->VideoSettingIndex].HVRes_Type.HVPol & VNegHPos)) { // V + Cache_EP952_DE_Control |= EP952_DE_Control__VSO_POL; // Invert + } + else { + Cache_EP952_DE_Control &= ~EP952_DE_Control__VSO_POL; + } + if((Params->HVPol & VPosHNeg) != (EP952_VDO_Settings[Params->VideoSettingIndex].HVRes_Type.HVPol & VPosHNeg)) { // H + Cache_EP952_DE_Control |= EP952_DE_Control__HSO_POL; // Invert + } + else { + Cache_EP952_DE_Control &= ~EP952_DE_Control__HSO_POL; + } + break; + + case SYNCMODE_HV: + // Disable E_SYNC + EP952_Reg_Clear_Bit(EP952_General_Control_4, EP952_General_Control_4__E_SYNC); + // Enable DE_GEN + Cache_EP952_DE_Control |= EP952_DE_Control__DE_GEN; + + // Regular VSO_POL, HSO_POL + if((Params->HVPol & VNegHPos) != (EP952_VDO_Settings[Params->VideoSettingIndex].HVRes_Type.HVPol & VNegHPos)) { // V + Cache_EP952_DE_Control |= EP952_DE_Control__VSO_POL; // Invert + } + else { + Cache_EP952_DE_Control &= ~EP952_DE_Control__VSO_POL; + } + if((Params->HVPol & VPosHNeg) != (EP952_VDO_Settings[Params->VideoSettingIndex].HVRes_Type.HVPol & VPosHNeg)) { // H + Cache_EP952_DE_Control |= EP952_DE_Control__HSO_POL; // Invert + } + else { + Cache_EP952_DE_Control &= ~EP952_DE_Control__HSO_POL; + } + + // Set DE generation params + if(Params->VideoSettingIndex < EP952_VDO_Settings_Max) { + Cache_EP952_DE_Control &= ~0x03; + +#ifdef Little_Endian + Cache_EP952_DE_Control |= ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_DLY)[1]; + Temp_Data[0] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_DLY)[0]; + EP952_Reg_Write(EP952_DE_DLY, Temp_Data, 1); +#else // Big Endian + Cache_EP952_DE_Control |= ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_DLY)[0]; + Temp_Data[0] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_DLY)[1]; + EP952_Reg_Write(EP952_DE_DLY, Temp_Data, 1); +#endif + + Temp_Data[0] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_TOP)[0]; + EP952_Reg_Write(EP952_DE_TOP, Temp_Data, 1); + +#ifdef Little_Endian + Temp_Data[0] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_CNT)[0]; + Temp_Data[1] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_CNT)[1]; + EP952_Reg_Write(EP952_DE_CNT, Temp_Data, 2); +#else // Big Endian + Temp_Data[0] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_CNT)[1]; + Temp_Data[1] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_CNT)[0]; + EP952_Reg_Write(EP952_DE_CNT, Temp_Data, 2); +#endif + + +#ifdef Little_Endian + Temp_Data[0] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_LIN)[1]; + Temp_Data[1] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_LIN)[0]; + EP952_Reg_Write(EP952_DE_LIN, Temp_Data, 2); +#else // Big Endian + Temp_Data[0] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_LIN)[1]; + Temp_Data[1] = ((unsigned char *)&EP952_VDO_Settings[Params->VideoSettingIndex].DE_Gen.DE_LIN)[0]; + EP952_Reg_Write(EP952_DE_LIN, Temp_Data, 2); +#endif + + } + else { + //DBG_printf(("ERROR: VideoCode overflow DE_GEN table\r\n")); + } + break; + } + EP952_Reg_Write(EP952_DE_Control, &Cache_EP952_DE_Control, 1); + + //////////////////////////////////////////////////////// + // Pixel Repetition + EP952_Reg_Read(EP952_Pixel_Repetition_Control, Temp_Data, 1); + Temp_Data[0] &= ~EP952_Pixel_Repetition_Control__PR; + if(Params->VideoSettingIndex < EP952_VDO_Settings_Max) { + Temp_Data[0] |= EP952_VDO_Settings[Params->VideoSettingIndex].AR_PR & 0x03; + } + EP952_Reg_Write(EP952_Pixel_Repetition_Control, Temp_Data, 1); + + //////////////////////////////////////////////////////// + // Color Space + // Set to RGB + EP952_Reg_Clear_Bit(EP952_General_Control_4, EP952_General_Control_4__YCC_IN | EP952_General_Control_4__422_IN); + if(Params->VideoSettingIndex < EP952_VDO_Settings_IT_Start) { // CE Timing + EP952_Reg_Clear_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__YCC_OUT | EP952_Color_Space_Control__422_OUT); + EP952_Reg_Set_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__YCC_Range); // Output limit range RGB + } + else { // IT Timing + EP952_Reg_Clear_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__YCC_OUT | EP952_Color_Space_Control__422_OUT | EP952_Color_Space_Control__YCC_Range); + } + + // Color Space + switch(Params->ColorSpace) { + default: + case COLORSPACE_601: + // Set to 601 + EP952_Reg_Clear_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__COLOR); + break; + + case COLORSPACE_709: + // Set to 709 + EP952_Reg_Set_Bit(EP952_Color_Space_Control, EP952_Color_Space_Control__COLOR); + break; + } + + /////////////////////////////////////////////////////////////////// + // AVI Info Frame + // + + // clear AVI Info Frame + memset(Temp_Data, 0x00, 14); + + // AVI InfoFrame Data Byte 1 + //switch(Params->FormatOut) { + Temp_Data[1] |= 0x00; // AVI_Y1,Y0 = RGB + Temp_Data[1] |= 0x10; // AVI_A0 = Active Format Information valid + + //SCAN + switch(Params->SCAN) { + default: + case 0: + Temp_Data[1] &= ~0x03; // AVI_S1,S0 = No Data + break; + case 1: // AVI_S1,S0 = overscan + Temp_Data[1] |= 0x01; + break; + case 2: // AVI_S1,S0 = underscan + Temp_Data[1] |= 0x02; + break; + } + + // AVI InfoFrame Data Byte 2 + switch(Params->ColorSpace) { + default: + case COLORSPACE_601: + Temp_Data[2] |= 0x40; // AVI_C1,C0 = 601 + break; + + case COLORSPACE_709: + Temp_Data[2] |= 0x80; // AVI_C1,C0 = 709 + break; + } + + if(Params->VideoSettingIndex < EP952_VDO_Settings_Max) { + Temp_Data[2] |= EP952_VDO_Settings[Params->VideoSettingIndex].AR_PR & 0x30; // AVI_M1,M0 : Picture Aspect Ratio + } + Temp_Data[2] |= Params->AFARate & 0x0F;// AVI_R3~0: Active format Aspect Ratio + + // AVI InfoFrame Data Byte 3 is 0 + + // AVI InfoFrame Data Byte 4 is VIC + if(Params->VideoSettingIndex < EP952_VDO_Settings_IT_Start) { + Temp_Data[4] |= EP952_VDO_Settings[Params->VideoSettingIndex].VideoCode;// AVI_VIC6~0 : Vedio Identification code + } + + // AVI InfoFrame Data Byte 5 + if(Params->VideoSettingIndex < EP952_VDO_Settings_Max) { + Temp_Data[5] |= (EP952_VDO_Settings[Params->VideoSettingIndex].AR_PR & 0x0C) >> 2;// AVI_PR3~0 : Pixel Repetition + } + + // AVI InfoFrame Data Byte 0 is checksum + Temp_Data[0] = 0x91; + for(i=1; i<6; ++i) { + Temp_Data[0] += Temp_Data[i]; + } + Temp_Data[0] = ~(Temp_Data[0] - 1); // checksum + + // Write AVI InfoFrame Data Byte + EP952_Reg_Write(EP952_AVI_Packet, Temp_Data, 14); + + // Enable auto transmission AVI packet + EP952_Reg_Set_Bit(EP952_IIS_Control, EP952_IIS_Control__AVI_EN | EP952_IIS_Control__GC_EN); + + +} + +//-------------------------------------------------------------------------------------------------------------------- + +void EP952Controller_Initial(PEP952C_REGISTER_MAP pEP952C_RegMap) +{ + // Save the Logical Hardware Assignment + pEP952C_Registers = pEP952C_RegMap; + + // Initial IIC address + if(is_SM768) + ddk768_swI2CInit(30, 31); + else + swI2CInit(30, 31); + + EP952_IIC_Initial(); + + // Software power down + HDMI_Tx_Power_Down(); + + // Enable Audio Mute and Video Mute + HDMI_Tx_Mute_Enable(); + + // Reset Variables + is_Cap_HDMI = 0; + is_Cap_YCC444 = is_Cap_YCC422 = 0; + is_Forced_Output_RGB = 0; + is_Connected = 1; + TX_State = TXS_Search_EDID; + HP_ChangeCount = 0; + PowerUpCount = 0; + is_ReceiverSense = 0; + + // Reset all EP952 parameters + pEP952C_Registers->System_Status = 0; + pEP952C_Registers->EDID_ASFreq = 0; + pEP952C_Registers->EDID_AChannel = 0; + pEP952C_Registers->Video_change = 0; + pEP952C_Registers->Audio_change = 0; + pEP952C_Registers->System_Configuration = 0; + pEP952C_Registers->Video_Input_Format[1]= 0; + //pEP952C_Registers->Video_Output_Format = 0; // Auto select output + pEP952C_Registers->Video_Output_Format = 0x03; // Forced set RGB out + + // Disable HDCP + HDMI_Tx_HDCP_Disable(); + + // HDCP KEY reset + EP952_HDCP_Reset(); + + // Info Frame Reset + EP952_Info_Reset(); +} + + + +#if 0 +void EP_HDMI_DumpMessage(void) +{ + unsigned char temp_R = 0xFF, reg_addr = 0; + + ddk768_swI2CInit(30, 31); + IIC_EP952_Addr = 0x52; // EP952 slave address + IIC_HDCPKey_Addr = 0xA8; // HDCP Key (EEPROM) slave address + + printk("[Samtest EP952 Register value]\r\n"); + printk(" -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -A -B -C -D -E -F\r\n"); + printk(" -----------------------------------------------"); + for(reg_addr=0; reg_addr<=0x88; reg_addr++) + { + EP952_Reg_Read(reg_addr, &temp_R, 1); + + if(reg_addr%16 == 0) + { + printk("\r\n%02x| ",((reg_addr/16)<<4)); + } + printk("%02x ",temp_R); + + } + printk("\r\n"); + printk(" -----------------------------------------------\r\n"); +} + +void EP_HDMI_DumpRegister(void) +{ + unsigned char temp_R = 0xFF, reg_addr = 0; + + ddk768_swI2CInit(30, 31); + IIC_EP952_Addr = 0x52; // EP952 slave address + IIC_HDCPKey_Addr = 0xA8; // HDCP Key (EEPROM) slave address + + printk(" +++++"); + for(reg_addr=0x3A; reg_addr<=0x3D; reg_addr++) + { + EP952_Reg_Read(reg_addr, &temp_R, 1); + + printk("$%02X=%02X ", reg_addr, temp_R); + + } + printk(" -----\r\n"); +} +#endif +void EP_HDMI_Init(int chipID) +{ + if(chipID) + is_SM768 = 1; + else + is_SM768 = 0; + + EP952Controller_Initial(&EP952C_Registers); +} + +void EP952_Video_reg_set(void) +{ + // Mute Control + HDMI_Tx_Mute_Enable(); + + //if(pEP952C_Registers->Video_Input_Format[0] != 0) + { + // HDMI Mode + if(!is_Cap_HDMI ) { + HDMI_Tx_DVI(); // Set to DVI output mode (The Info Frame and Audio Packets would not be send) + is_Forced_Output_RGB = 1; + } + else { + HDMI_Tx_HDMI(); // Set to HDMI output mode + } + + /////////////////////////////////////////////////////////////////////// + // Update Video Params + // + + // Video Interface + Video_Params.Interface = pEP952C_Registers->Video_Interface[0]; + //Video_Params.Interface = 0x87 + + // Video Timing + if(pEP952C_Registers->Video_Input_Format[0] < 35) { + Video_Params.VideoSettingIndex = pEP952C_Registers->Video_Input_Format[0]; + //Video_Params.VideoSettingIndex = 0x16; + } + else{ + Video_Params.VideoSettingIndex = 0; + } + + // Select Sync Mode + Video_Params.SyncMode = (SYNCMODE)((pEP952C_Registers->Video_Interface[1] & EP_TX_Video_Interface_Setting_1__SYNC) >> 2); + //Video_Params.SyncMode = 0; + + // Select Color Space + switch(Video_Params.VideoSettingIndex) { + case 4: case 5: case 16: case 19: case 20: case 31: case 32: + case 33: case 34: // HD Timing + Video_Params.ColorSpace = COLORSPACE_709; + break; + + default: + if(Video_Params.VideoSettingIndex) { // SD Timing + Video_Params.ColorSpace = COLORSPACE_601; + } + else { // IT Timing + Video_Params.ColorSpace = COLORSPACE_709; + } + break; + } + + // Forced Output RGB Format + if(pEP952C_Registers->Video_Output_Format == 0x03) { + is_Forced_Output_RGB = 1; + } + + // Set In and Output Color Format + switch(pEP952C_Registers->Video_Interface[1] & EP_TX_Video_Interface_Setting_1__VIN_FMT) { + + default: + case EP_TX_Video_Interface_Setting_1__VIN_FMT__RGB: // input is RGB + Video_Params.FormatIn = COLORFORMAT_RGB; + Video_Params.FormatOut = COLORFORMAT_RGB; + break; + + case EP_TX_Video_Interface_Setting_1__VIN_FMT__YCC444: // input is YCC444 + Video_Params.FormatIn = COLORFORMAT_YCC444; + if(!is_Forced_Output_RGB && is_Cap_YCC444) { + Video_Params.FormatOut = COLORFORMAT_YCC444; + } + else { + Video_Params.FormatOut = COLORFORMAT_RGB; + } + break; + + case EP_TX_Video_Interface_Setting_1__VIN_FMT__YCC422: // inut is YCC422 + Video_Params.FormatIn = COLORFORMAT_YCC422; + if(!is_Forced_Output_RGB && is_Cap_YCC422) { + Video_Params.FormatOut = COLORFORMAT_YCC422; + } + else { + Video_Params.FormatOut = COLORFORMAT_RGB; + } + break; + } + // AFAR + Video_Params.AFARate = AFAR_VideoCode; + + // SCAN + Video_Params.SCAN = SCAN_NoData; + + // Update EP952 Video Registers + HDMI_Tx_Video_Config(&Video_Params); + + // mute control + HDMI_Tx_Mute_Disable(); + } + + // clear flag + pEP952C_Registers->Video_change = 0; + +} + +void EP_HDMI_Set_Video_Timing(unsigned int isHDMI, unsigned int dsel) //(logicalMode_t *pLogicalMode, unsigned int isHDMI) +{ + ///////////////////////////////////////////////////////////////////////// + // + // need to select EP952 video input interface + // detail description need reference to file " Video_Interface[0].jpg " and " Video_Interface[1].jpg " + // + ///////////////////////////////////////////////////////////////////////// + EP952C_Registers.Video_Interface[0] = 0x87; // reference to Video_Interface[0].jpg; + + EP952C_Registers.Video_Interface[1] = 0x00; // reference to Video_Interface[1].jpg; + + + ///////////////////////////////////////////////////////////////////////// + // need to select video timing, timing detail description as below + // + // [Example]: + // EP_HDMI_Set_Video_Timing(16); // 1080P 60Hz + // + // EP_HDMI_Set_Video_Timing(4); // 720P 60Hz + // + ///////////////////////////////////////////////////////////////////////// + EP952C_Registers.Video_Input_Format[0] = 16; + EP952C_Registers.Video_change = 1; // Vedio setting change flag + + if (isHDMI) + is_Cap_HDMI = 1; + else + is_Cap_HDMI = 0; + + if (dsel) + is_Cap_dsel = 1; + else + is_Cap_dsel = 0; + + // power down Tx + HDMI_Tx_Power_Down(); + + // update EP952 register setting + //EP952_Audio_reg_set(); + EP952_Video_reg_set(); + + EP952_Debug = 1; + + // Power Up Tx + HDMI_Tx_Power_Up(); + + TX_State = TXS_Stream; +} + +void EP952_Register_Message(void) +{ + unsigned char temp[0x90] = {0}; + unsigned char reg_addr = 0; + + //ddk768_swI2CInit(30, 31); + IIC_EP952_Addr = 0x52; // EP952 slave address + IIC_HDCPKey_Addr = 0xA8; // HDCP Key (EEPROM) slave address + + printk(KERN_INFO "[Samtest EP952 Register value]"); + printk(KERN_INFO " \t-0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -A -B -C -D -E -F"); + printk(KERN_INFO " \t-----------------------------------------------"); + for(reg_addr=0; reg_addr<=0x88; reg_addr++) + { + EP952_Reg_Read(reg_addr, &temp[reg_addr], 1); + } + print_hex_dump(KERN_INFO, " \t", DUMP_PREFIX_NONE, 16, 1, temp, 0x90, false); + printk(KERN_INFO " \t-----------------------------------------------"); +} diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_ep952.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_ep952.h new file mode 100644 index 000000000000..c183d2082d42 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_ep952.h @@ -0,0 +1,62 @@ +#ifndef _HDMI_H_ +#define _HDMI_H_ + + +//----------------------------------------------------------------------------- +// Type Definition +//----------------------------------------------------------------------------- + +typedef enum _HDMI_PNP_STATUS_ +{ + HDMI_INTR_HOT_PLUG, + HDMI_INTR_OTHERS = 0xFF, +}HDMI_PNP_STATUS; + + +/* + * Function: + * HDMI_Set_Mode + * + * Input: + * pLogicalMode + * + * Output: + * None + * + * Return: + * 0 - Success + * -1 - Error + * + */ +int EP952_HDMI_Set_Mode (logicalMode_t *pLogicalMode); + +/* + * Function: + * HDMI_Read_Edid. + * + * Input: + * pEDIDBuffer - EDID buffer + * bufferSize - EDID buffer size (usually 128-bytes or 256 bytes) + * Output: + * -1 - Error + * 0 - exist block0 EDID (128 Bytes) + * 1 - exist block0 & block1 EDID (256 Bytes) + */ +int EP952_HDMI_Read_Edid(char *pEDIDBuffer, unsigned long bufferSize); + +/* + * Function: + * HDMI_hotplug_check + * + * Input: + * None + * + * Output: + * 0 - unplugged + * 1 - plugged + * + */ + +void hdmiHandler(void); + +#endif /* _HDMI_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_hdmi.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_hdmi.c new file mode 100644 index 000000000000..1ee2e9534bc8 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_hdmi.c @@ -0,0 +1,1654 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* Hdmi.c --- +* This file contains the source code for HDMI functions. +* +*******************************************************************/ + + + +#include +#include + +#include "ddk768_help.h" +#include "ddk768_hdmi.h" +#include "ddk768_reg.h" +#include "ddk768_power.h" +#include "ddk768_chip.h" + +#include "hdmiregs.h" + + +//----------------------------------------------------------------------------- +// Parameter Table +//----------------------------------------------------------------------------- + +/* + * Hdmi parameter for some popular modes. + * Note that the most timings in this table is made according to CEA standard + * parameters for the popular modes. + */ +static hdmi_PHY_param_t gHdmiPHYParamTable[] = +{ +/* TMDS clock range 0-50 MHz [8bpc] */ + { 0x22, 0x06, 0x00, 0x40, 0x40, 0x1E, 0x94, 0x2E, 0x10, 0x00}, //640x480 5D: 0x70->0x10 + +/* TMDS clock range 50-100 MHz [8bpc] */ + { 0x22, 0x0A, 0x00, 0x40, 0x40, 0x1E, 0x94, 0x2E, 0x70, 0x00}, + +/* TMDS clock range 100-150 MHz [8bpc] */ + { 0x22, 0x0E, 0x00, 0x40, 0x40, 0x1E, 0x91, 0x2E, 0x70, 0x00}, //1080P 5B:0x92->0x91 + +/* TMDS clock range 150-200 MHz [8bpc] */ + { 0x22, 0x0E, 0x00, 0x40, 0x40, 0x1E, 0x94, 0x2E, 0x71, 0x00}, + +/* TMDS clock range 200-250 MHz [8bpc] */ + { 0x22, 0x0E, 0x00, 0x40, 0x40, 0x1E, 0x94, 0x2E, 0x71, 0x00}, + +/* TMDS clock range 250-297 MHz [8bpc] */ + //{ 0x22, 0x0E, 0x00, 0x40, 0x40, 0x1E, 0x95, 0x2E, 0x71, 0x00}, + { 0x22, 0x0E, 0x00, 0x40, 0x40, 0x5E, 0x95, 0x7E, 0x64, 0x00}, // SLI uses it to run 4K compliance test + +/* End of table. */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +}; + +/* HDMI mode VIC value table.*/ +static hdmi_vic_param_t gHdmiVICParamTable[] = +{ + {640, 480, 1, 0x18}, + {720, 480, 2, 0x00}, + {1280, 720, 4, 0x28}, + {1440, 480, 14, 0x00}, + {1920, 1080, 16, 0x28}, + {2880, 480, 35, 0x00}, + {1680, 720, 83, 0x00}, + {2560, 1080, 90, 0x00}, + {3840, 2160, 95, 0x00}, + + /* End of table. */ + {0, 0, 0,0}, +}; + +//----------------------------------------------------------------------------- +// Global Variable +//----------------------------------------------------------------------------- + +BYTE g_INT_94h = 0; +BYTE g_INT_95h = 0; +BYTE PowerMode = PowerMode_A; +BYTE g_ucHDMIedidRead=0; +BYTE AudioMode = 0; +BYTE gEdidBuffer[256] = {0}; + +/* Find mode VIC parameer from the table according to Width & Height*/ +hdmi_vic_param_t *FindVicParam(unsigned long Width, unsigned long Height) +{ + unsigned char index = 0; + hdmi_vic_param_t * pVicTable = gHdmiVICParamTable; + + while (pVicTable[index].Width != 0) + { + if ((pVicTable[index].Width == Width) && (pVicTable[index].Height == Height)) + return &pVicTable[index]; + + /* Next entry */ + index++; + } + + /* If no such a mode, set vic to 0. */ + return &pVicTable[index]; +} +void Delay (void) +{ + unsigned long d; + for (d = 0; d < 0x13FF; d++) + ; +} + +void DelayMs (BYTE millisecond) +{ + usleep_range(millisecond * 1000 , millisecond * 1100); +} + +//----------------------------------------------------------------------------- +// HDMI Interrupt functions +//----------------------------------------------------------------------------- +typedef struct _hdmi_interrupt_t +{ + struct _hdmi_interrupt_t *next; + void (*handler)(void); +} +hdmi_interrupt_t; +#if 0 +static hdmi_interrupt_t *g_pHdmiIntHandlers = ((hdmi_interrupt_t *)0); + +/* HDMI Interrupt Service Routine */ +void hdmiISR( + unsigned long status +) +{ + hdmi_interrupt_t *pfnHandler; + + if (FIELD_GET(status, INT_STATUS, HDMI) == INT_STATUS_HDMI_ACTIVE) + { + /* Walk all registered handlers for handlers that support this interrupt status */ + for (pfnHandler = g_pHdmiIntHandlers; pfnHandler != ((hdmi_interrupt_t *)0); pfnHandler = pfnHandler->next) + pfnHandler->handler(); + + // Save interrupt status value for further usage. + if (PowerMode == PowerMode_A) + { + // PS mode a->b + HDMI_System_PD(PowerMode_B); + DelayMs(1); + } + g_INT_94h = readHDMIRegister (X94_INT1_ST); + g_INT_95h = readHDMIRegister (X95_INT2_ST); + + // clear all interrupt status + writeHDMIRegister (X94_INT1_ST, 0xFF); + writeHDMIRegister (X95_INT2_ST, 0xFF); + } +} +#endif +/* + * This is the main interrupt hook for HDMI engine. + */ +long hookHDMIInterrupt( + void (*handler)(void) +) +{ + +#if 0 + hdmi_interrupt_t *pfnNewHandler, *pfnHandler; + unsigned short returnValue = 0; + + /* Allocate a new interrupt structure */ + pfnNewHandler = (hdmi_interrupt_t *)malloc(sizeof(hdmi_interrupt_t)); + if (pfnNewHandler == ((hdmi_interrupt_t *)0)) + { + /* No more memory */ + return (-1); + } + + /* Make sure that it has not been register more than once */ + for (pfnHandler = g_pHdmiIntHandlers; pfnHandler != ((hdmi_interrupt_t *)0); pfnHandler = pfnHandler->next) + { + if (pfnHandler->handler == handler) + return (-1); /* Duplicate entry */ + } + + /* If this is the first interrupt handler, register this panel VSync ISR */ + if (g_pHdmiIntHandlers == ((hdmi_interrupt_t *)0)) + returnValue = registerHandler(hdmiISR, FIELD_SET(0, INT_MASK, HDMI, ENABLE)); + + if (returnValue == 0) + { + /* Fill interrupt structure. */ + pfnNewHandler->next = g_pHdmiIntHandlers; + pfnNewHandler->handler = handler; + g_pHdmiIntHandlers = pfnNewHandler; + } +#endif + return 0;//returnValue; +} + +/* + * This function un-register HDMI Interrupt handler. + */ +long unhookHDMIInterrupt( + void (*handler)(void) +) +{ +#if 0 + hdmi_interrupt_t *pfnHandler, *prev; + + /* Find the requested handle to unregister */ + for (pfnHandler = g_pHdmiIntHandlers, prev = ((hdmi_interrupt_t *)0); + pfnHandler != ((hdmi_interrupt_t *)0); + prev = pfnHandler, pfnHandler = pfnHandler->next) + { + if (pfnHandler->handler == handler) + { + /* Remove the interrupt handler */ + if (prev == ((hdmi_interrupt_t *)0)) + g_pHdmiIntHandlers = pfnHandler->next; + else + prev->next = pfnHandler->next; + + free(pfnHandler); + + /* If this was the last interrupt handler, remove the IRQ handler */ + if (g_pHdmiIntHandlers == ((hdmi_interrupt_t *)0)) + unregisterHandler(hdmiISR); + + /* Success */ + return (0); + } + } +#endif + /* Oops, handler is not registered */ + return (-1); +} + +//----------------------------------------------------------------------------- +// HDMI Misc. functions +//----------------------------------------------------------------------------- + +/* + * Function: + * writeHDMIRegister + * + * Input: + * addr - HDMI register index (could be from 0x01 to 0xFF) + * value - HDMI register value + * + * Output: + * None + * + * + * WRITE is a 2 step process. For example, write a value of 0x82 to register with index 0x45, the steps are: + * (MMIO base + 0x800C0) = 0x00018245 + * (MMIO base + 0x800C0) = 0x00008245 + * + */ +void writeHDMIRegister(unsigned char addr, unsigned char value) +{ + + pokeRegisterDWord(HDMI_CONFIG, + FIELD_SET(0, HDMI_CONFIG, WRITE, ENABLE) | + FIELD_VALUE(0, HDMI_CONFIG, DATA, value) | + FIELD_VALUE(0, HDMI_CONFIG, ADDRESS, addr)); + + DelayMs(1); + + pokeRegisterDWord(HDMI_CONFIG, + FIELD_VALUE(0, HDMI_CONFIG, DATA, value) | + FIELD_VALUE(0, HDMI_CONFIG, ADDRESS, addr)); + + DelayMs(1); +} + +/* + * Function: + * readHDMIRegister + * + * Input: + * addr - HDMI register index (could be from 0x01 to 0xFF) + * + * Output: + * register value + * + * + * READ is a 3 step process, For example, read a value from register with index 0x45. + * (MMIO base + 0x800C0) = 0x20045 + * (MMIO base + 0x800C0) = 0x00045 + * Value = (MMIO base + 0x800C0) =0x1845 + * + */ +unsigned char readHDMIRegister(unsigned char addr) +{ + unsigned long value; + + pokeRegisterDWord(HDMI_CONFIG, + FIELD_SET(0, HDMI_CONFIG, READ, ENABLE) | + FIELD_VALUE(0, HDMI_CONFIG, ADDRESS, addr)); + + DelayMs(1); + + pokeRegisterDWord(HDMI_CONFIG, FIELD_VALUE(0, HDMI_CONFIG, ADDRESS, addr)); + + DelayMs(1); + + value = peekRegisterDWord(HDMI_CONFIG); + + return (unsigned char)((value >> 8) & 0xFF); +} + +/* + * Function: + * writeHDMIControlRegister + * This functions writes HDMI System Control register (index 0x00). + * + * Input: + * value - HDMI register 0x00 value + * + * Output: + * None + * + */ +void writeHDMIControlRegister(unsigned char value) +{ + + pokeRegisterDWord(HDMI_CONTROL, value); + +} + +/* + * Function: + * readHDMIRegister + * This functions reads HDMI System Control register (index 0x00). + * + * Input: + * None + * + * Output: + * register value + * + */ +unsigned char readHDMIControlRegister(void) +{ + unsigned long value; + + // Need to write 0x800c0[7:0] (config address) to 00 first, otherwise could not read back + // real value of HDMI control register. + pokeRegisterDWord(HDMI_CONFIG, + FIELD_SET(0, HDMI_CONFIG, READ, ENABLE) | + FIELD_VALUE(0, HDMI_CONFIG, ADDRESS, 0)); + + DelayMs(1); + + value = peekRegisterDWord(HDMI_CONTROL); + + return (unsigned char)(value & 0xFF); +} + +/* + * Function: + * writeHdmiPHYRegister + * + * Input: + * addr - HDMI register index (for PHY registers only, could be from 0x57 to 0x5E) + * value - HDMI register value + * + * Output: + * None + * + */ +void writeHdmiPHYRegister(unsigned char addr, unsigned char value) +{ + writeHDMIRegister(addr, value); + + writeHDMIControlRegister(0x2D); // PLLA/B reset + DelayMs(1); // wait 100us + + writeHDMIControlRegister(0x21); // PLLA/B release + DelayMs(1); // wait 1ms for PLL lock +} + +/* + * Function: + * setHDMIChannel + * + * Input: + * channel number - 0 = Select Channel 0 to HDMI + * - 1 = Select Channel 1 to HDMI + * + * Output: + * None + * + */ +void setHDMIChannel(unsigned char Channel) +{ + unsigned long value; + + value = peekRegisterDWord(DISPLAY_CTRL); + if (Channel == 0) + { + pokeRegisterDWord(DISPLAY_CTRL, + FIELD_SET(value, DISPLAY_CTRL, HDMI_SELECT, CHANNEL0)); + } + else + { + pokeRegisterDWord(DISPLAY_CTRL, + FIELD_SET(value, DISPLAY_CTRL, HDMI_SELECT, CHANNEL1)); + } + +} + +/* Send clear AVMute to HDMI Sink for one time. Not send Clear AVMute and Set AVMute in General Control Packet when display. */ +void HDMI_Clear_AVMute(void) +{ + unsigned char temp = 0; + temp = readHDMIRegister(X45_VIDEO2); + temp = FIELD_SET(temp, X45_VIDEO2, CLR_AVMUTE, EN) | + FIELD_SET(temp, X45_VIDEO2, SET_AVMUTE, DIS); + writeHDMIRegister(X45_VIDEO2, temp); + writeHDMIRegister(X40_CTRL_PKT_EN, 0x80); // Send General Control Packet once + + /* In display period, Clear AVMute and Set AVMute should not be sent in General Control Packet. */ + temp = readHDMIRegister(X45_VIDEO2); + temp = FIELD_SET(temp, X45_VIDEO2, CLR_AVMUTE, DIS) | + FIELD_SET(temp, X45_VIDEO2, SET_AVMUTE, DIS); + writeHDMIRegister(X45_VIDEO2, temp); + writeHDMIRegister(X40_CTRL_PKT_EN, 0x80); // Send General Control Packet once +} + +/* Before set HDMI IP mode, send AVMute to HDMI Sink in General Control Packet. */ +void HDMI_Set_AVMute(void) +{ + unsigned char temp = 0; + temp = readHDMIRegister(X45_VIDEO2); + temp = FIELD_SET(temp, X45_VIDEO2, CLR_AVMUTE, DIS) | + FIELD_SET(temp, X45_VIDEO2, SET_AVMUTE, EN); + writeHDMIRegister(X45_VIDEO2, temp); + writeHDMIRegister(X40_CTRL_PKT_EN, 0x80); // Send General Control Packet once +} + + +/* + * Function: + * enableHdmiI2C + * + * Input: +* enable/disable - 0 = HDMI I2C to GPIO[9:8] +* - 1 = HW I2C to GPIO[9:8] + * + * Output: + * None + * + */ +void enableHdmI2C(unsigned long enable) +{ + unsigned long value; + + value = peekRegisterDWord(TEST_CONTROL); + + if (enable) + value = FIELD_SET(value, TEST_CONTROL, I2C, HDMI); + else + value = FIELD_SET(value, TEST_CONTROL, I2C, I2C1); + + pokeRegisterDWord(TEST_CONTROL, value); +} + +/* + * Function: + * HDMI_Dump_Registers (Used for debug) + * + * Input: + * None + * + * Output: + * None + * + * Linda: for debug purpose only + */ +void HDMI_Dump_Registers (void) +{ + unsigned char i = 0, j = 0; + + printk("++++++++++ HDMI Regsiters 0x00 - 0x7F ++++++++++\n"); + + for (i = 0; i < 16; i++) + { + printk("Offset 0x%02x: ", (i * 8)); + for (j = 0; j < 8; j++) + printk("%02x ", readHDMIRegister((j + i * 8))); + printk("\n"); + } +} + + +//----------------------------------------------------------------------------- +// HDMI Functions +//----------------------------------------------------------------------------- + +// +// Parameters : unsigned char mode. 4 modes available. +// MODE_A (sleep), MODE_B (register access), MODE_D (clock), MODE_E (active). +// +void HDMI_System_PD (unsigned char mode) +{ + PowerMode = mode; + + // PLL A/B Reset + if (PowerMode != PowerMode_A) + { + writeHDMIControlRegister (mode | 0x0C); + DelayMs(8); // wait 8ms + } + // PLL A/B Release + writeHDMIControlRegister (mode); + DelayMs(10); // wait 10ms + + +} + +/* + * Function: + * HDMI_Set_Control_Packet + * + * Input: + * None + * + * Output: + * None + * + */ +void HDMI_Init(void) +{ + unsigned char temp; + + // Enable HDMI clock + ddk768_enableHDMI(1); + + // select channel 0 to HDMI by default + setHDMIChannel(0); + + // set INT polarity to Active High + temp = readHDMIControlRegister(); + writeHDMIControlRegister (temp | 0x01); + + // Set AVMute to Sink + HDMI_Set_AVMute(); + + // Set to power mode B, in order to read/write to registers + HDMI_System_PD (PowerMode_B); + DelayMs(1); + + // Setting AVI InfoFrame + writeHDMIRegister (X5F_PACKET_INDEX, AVI_INFO_PACKET); // Index.6 AVI InfoFrame + // HB0 for generic control packet + writeHDMIRegister (X41_SEND_CPKT_AUTO, 0x10); + writeHDMIRegister (X60_PACKET_HB0, 0x82); // HB0 + writeHDMIRegister (X61_PACKET_HB1, 0x02); // HB1 + writeHDMIRegister (X62_PACKET_HB2, 0x0D); // HB2 + writeHDMIRegister (X63_PACKET_PB0, 0x16); // PB0 + writeHDMIRegister (X64_PACKET_PB1, 0x00); // PB1 + writeHDMIRegister (X65_PACKET_PB2, 0x00); // PB2 + writeHDMIRegister (X66_PACKET_PB3, 0x12); // PB3 + writeHDMIRegister (X67_PACKET_PB4, 0x00); // PB4 + writeHDMIRegister (X68_PACKET_PB5, 0x00); // PB5 + writeHDMIRegister (X69_PACKET_PB6, 0xe4); // PB6 + writeHDMIRegister (X6A_PACKET_PB7, 0xb5); // PB7 + writeHDMIRegister (X6B_PACKET_PB8, 0x4e); // PB8 + writeHDMIRegister (X6C_PACKET_PB9, 0x59); // PB9 + writeHDMIRegister (X6D_PACKET_PB10, 0xd2); // PB10 + writeHDMIRegister (X6E_PACKET_PB11, 0xeb); // PB11 + writeHDMIRegister (X6F_PACKET_PB12, 0x18); // PB12 + writeHDMIRegister (X70_PACKET_PB13, 0x1d); // PB13 + + // Setting Audio InfoFrame + writeHDMIRegister (X5F_PACKET_INDEX, AUDIO_INFO_PACKET); // Index.8 Audio + writeHDMIRegister (X60_PACKET_HB0, 0x84); // HB0 + writeHDMIRegister (X61_PACKET_HB1, 0x01); // HB1 + writeHDMIRegister (X62_PACKET_HB2, 0x0A); // HB2 + writeHDMIRegister (X63_PACKET_PB0, 0x70); // PB0 + writeHDMIRegister (X64_PACKET_PB1, 0x01); // PB1 + writeHDMIRegister (X65_PACKET_PB2, 0x00); // PB2 + writeHDMIRegister (X66_PACKET_PB3, 0x00); // PB3 + writeHDMIRegister (X67_PACKET_PB4, 0x00); // PB4 + writeHDMIRegister (X68_PACKET_PB5, 0x00); // PB5 + + // init DDC bus frequency + writeHDMIRegister (X81_ISRC2_PB0, 0x20); + writeHDMIRegister (X82_ISRC2_PB1, 0x00); + + // Unmask MSENS detect interrupt. Hot plug interrupt is enough for hot-plug + // detection, we don't need to detect both at the same time. + // writeHDMIRegister (X92_INT_MASK1, 0x80); +} + + +/* + * Function: + * HDMI_Unplugged + * + * Input: + * None + * + * Return: + * None + * + */ +void HDMI_Unplugged (void) +{ + unsigned char temp = 0; + + // disable video & audio output: write 11b to #45h[1:0] + temp = readHDMIRegister(X45_VIDEO2); + writeHDMIRegister(X45_VIDEO2, (temp | 0x03)); + + // audio reset: write 1b to #45h[2], followed by 500us wait time + temp = readHDMIRegister(X45_VIDEO2); + writeHDMIRegister(X45_VIDEO2, (temp | 0x04)); + DelayMs(1); + + // PS mode e->d->b->a + HDMI_System_PD (PowerMode_D); + HDMI_System_PD (PowerMode_B); + HDMI_System_PD (PowerMode_A); +} + +/* + * Function: + * HDMI_Audio_Reset + * + * Input: + * None + * + * Output: + * None + * + * Return: + * None + * + */ +void HDMI_Audio_Reset (void) +{ + unsigned char temp = 0; + + if (PowerMode == PowerMode_E) + { + // Audio reset/release + // Audio is mute after reset of audio is set. + // Therefore, set it in the following procedures. + // Audio: Save value of now => Audio Reset => Audio Active => Set value again + temp = readHDMIRegister(X45_VIDEO2); + writeHDMIRegister(X45_VIDEO2, temp | 0x06 ); // Reset + DelayMs(1); // Followed by 1ms wait time + writeHDMIRegister(X45_VIDEO2, temp & 0xFB ); // Reset Release and Audio Mute) + DelayMs(1); // Followed by 1ms wait time + writeHDMIRegister(X45_VIDEO2, temp ); // Reset Release and Audio Mute) + } +} + +/* + * Function: + * HDMI_Audio_Mute + * + * Input: + * None + * + * Output: + * None + * + * Return: + * None + * + */ +void HDMI_Audio_Mute (void) +{ + unsigned char temp = 0; + + if (PowerMode == PowerMode_E) + { + // disable audio output: write 1b to #45h[1] + temp = readHDMIRegister(X45_VIDEO2); + writeHDMIRegister(X45_VIDEO2, (temp | 0x02)); + } + + AudioMode = Audio_Mute; +} + +/* + * Function: + * HDMI_Audio_Unmute + * + * Input: + * None + * + * Output: + * None + * + * Return: + * None + * + */ +void HDMI_Audio_Unmute (void) +{ + unsigned char temp = 0; + + if (PowerMode == PowerMode_E) + { + // enable audio output: write 0b to #45h[1] + temp = readHDMIRegister(X45_VIDEO2); + writeHDMIRegister(X45_VIDEO2, (temp & (~0x02))); + + // Audio reset/release + // Audio is mute after reset of audio is set. + // Therefore, set it in the following procedures. + // Audio: Save value of now => Audio Reset => Audio Active => Set value again + temp = readHDMIRegister(X45_VIDEO2); + writeHDMIRegister(X45_VIDEO2, temp | 0x04 ); // Reset + DelayMs(1); // Followed by 1ms wait time + writeHDMIRegister(X45_VIDEO2, temp & (~0x04) ); // Reset Release and Audio Mute) + } + AudioMode = Audio_Unmute; +} + + + +/* + * Function: + * HDMI_Control_Packet_Auto_Send + * + * Input: + * None + * + * Output: + * None + * + */ +void HDMI_Control_Packet_Auto_Send (void) +{ + writeHDMIRegister (X42_AUTO_CHECKSUM, 0x01); // enable auto checksum + writeHDMIRegister (X40_CTRL_PKT_EN, 0x00); +} + +/* + * Function: + * HDMI_Audio_Setting_44100Hz + * + * Input: + * pLogicalMode + * + * Output: + * None + * + * Return: + * None + * + */ +void HDMI_Audio_Setting_44100Hz (mode_parameter_t *pModeParam) +{ + unsigned long N = 6272, CTS = 0; // default N value is 6272 + unsigned char regValue = 0; + + // calculate CTS with recommended N + // recommended N value is 4704 for 4K mode + if ((pModeParam->horizontal_display_end >= 3840 && pModeParam->horizontal_display_end < 5120) && + (pModeParam->vertical_display_end >= 2160 && pModeParam->vertical_display_end < 2880)) + { + N = 4704; + } + + // CTS = (fTMDS_clock x N) / (128 x fS) + CTS = ((pModeParam->pixel_clock / 1000) * N / 128) * 10 / 441; + //printf("44100Hz: N = %d, CTS = %d\n", N, CTS); + + // set N and CTS into registers + regValue = (unsigned char)((N >> 16) & 0x0F); + writeHDMIRegister(X01_N19_16, regValue); + regValue = (unsigned char)(N >> 8); + writeHDMIRegister(X02_N15_8, regValue); + regValue = (unsigned char)N; + writeHDMIRegister(X03_N7_0, regValue); + + regValue = (unsigned char)((CTS >> 16) & 0x0F); + writeHDMIRegister(X07_CTS_EXT, regValue); + regValue = (unsigned char)(CTS >> 8); + writeHDMIRegister(X08_CTS_EXT, regValue); + regValue = (unsigned char)CTS; + writeHDMIRegister(X09_CTS_EXT, regValue); + + // set audio setting registers + writeHDMIRegister(X0A_AUDIO_SOURCE, 0x80); // external CTS + writeHDMIRegister(X0B_AUDIO_SET2, 0x40); + writeHDMIRegister(X0C_I2S_MODE, 0x04); // I2S 2ch (0x3C for 8ch) + I2S + //writeHDMIRegister(X0D_DSD_MODE, 0x00); // DSD audio disabled + writeHDMIRegister(X10_I2S_PINMODE, 0x00); // I2S input pin swap + writeHDMIRegister(X11_ASTATUS1, 0x0F); // Original Fs = 44.1kHz + writeHDMIRegister(X12_ASTATUS2, 0x22); + writeHDMIRegister(X13_CAT_CODE, 0x00); + writeHDMIRegister(X14_A_SOURCE, 0x51); // 24 bits word length + + regValue = (readHDMIRegister(X15_AVSET1) & 0x0F); // set freq 44.1kHz + writeHDMIRegister(X15_AVSET1, regValue); + + regValue = readHDMIRegister(X0A_AUDIO_SOURCE) & 0x9F; + writeHDMIRegister(X0A_AUDIO_SOURCE, regValue); // dounsampling none (bit 6:5 = 00) + + regValue = readHDMIRegister(X0A_AUDIO_SOURCE) & 0xF7; + writeHDMIRegister(X0A_AUDIO_SOURCE, regValue); // disable SPDIF + +} + + + +void HDMI_Audio_Setting_48000Hz (mode_parameter_t *pModeParam) +{ + unsigned long N = 6144, CTS = 0; // default N value is 6144 + unsigned char regValue = 0; + + // calculate CTS with recommended N + // recommended N value is 5120 for 4K mode + if ((pModeParam->horizontal_display_end >= 3840 && pModeParam->horizontal_display_end < 5120) && + (pModeParam->vertical_display_end >= 2160 && pModeParam->vertical_display_end < 2880)) + { + N = 5120; + } + + // CTS = (fTMDS_clock x N) / (128 x fS) + CTS = ((pModeParam->pixel_clock / 1000) * N / 128) * 10 / 480; + + // set N and CTS into registers + regValue = (unsigned char)((N >> 16) & 0x0F); + writeHDMIRegister(X01_N19_16, regValue); + regValue = (unsigned char)(N >> 8); + writeHDMIRegister(X02_N15_8, regValue); + regValue = (unsigned char)N; + writeHDMIRegister(X03_N7_0, regValue); + + regValue = (unsigned char)((CTS >> 16) & 0x0F); + writeHDMIRegister(X07_CTS_EXT, regValue); + regValue = (unsigned char)(CTS >> 8); + writeHDMIRegister(X08_CTS_EXT, regValue); + regValue = (unsigned char)CTS; + writeHDMIRegister(X09_CTS_EXT, regValue); + + // set audio setting registers + writeHDMIRegister(X0A_AUDIO_SOURCE, 0x80); // external CTS + writeHDMIRegister(X0B_AUDIO_SET2, 0x40); + writeHDMIRegister(X0C_I2S_MODE, 0x04); // I2S 2ch (0x3C for 8ch) + I2S + //writeHDMIRegister(X0D_DSD_MODE, 0x00); // DSD audio disabled + writeHDMIRegister(X10_I2S_PINMODE, 0x00); // I2S input pin swap + writeHDMIRegister(X11_ASTATUS1, 0x0D); // Original Fs = 48kHz + writeHDMIRegister(X12_ASTATUS2, 0x22); + writeHDMIRegister(X13_CAT_CODE, 0x00); + writeHDMIRegister(X14_A_SOURCE, 0x51); // 24 bits word length + + regValue = ((readHDMIRegister(X15_AVSET1) & 0x0F) | 0x20); // set freq 48kHz + writeHDMIRegister(X15_AVSET1, regValue); + + regValue = readHDMIRegister(X0A_AUDIO_SOURCE) & 0x9F; + writeHDMIRegister(X0A_AUDIO_SOURCE, regValue); // dounsampling none (bit 6:5 = 00) + + regValue = readHDMIRegister(X0A_AUDIO_SOURCE) & 0xF7; + writeHDMIRegister(X0A_AUDIO_SOURCE, regValue); // disable SPDIF + +} + + + + +void HDMI_Audio_Setting_32000Hz (mode_parameter_t *pModeParam) +{ + unsigned long N = 4096, CTS = 0; // default N value is 4096 + unsigned char regValue = 0; + + // calculate CTS with recommended N + // recommended N value is 5120 for 4K mode + if ((pModeParam->horizontal_display_end >= 3840 && pModeParam->horizontal_display_end < 5120) && + (pModeParam->vertical_display_end >= 2160 && pModeParam->vertical_display_end < 2880)) + { + N = 3072; + } + + // CTS = (fTMDS_clock x N) / (128 x fS) + CTS = ((pModeParam->pixel_clock / 1000) * N / 128) * 10 / 480; + + // set N and CTS into registers + regValue = (unsigned char)((N >> 16) & 0x0F); + writeHDMIRegister(X01_N19_16, regValue); + regValue = (unsigned char)(N >> 8); + writeHDMIRegister(X02_N15_8, regValue); + regValue = (unsigned char)N; + writeHDMIRegister(X03_N7_0, regValue); + + regValue = (unsigned char)((CTS >> 16) & 0x0F); + writeHDMIRegister(X07_CTS_EXT, regValue); + regValue = (unsigned char)(CTS >> 8); + writeHDMIRegister(X08_CTS_EXT, regValue); + regValue = (unsigned char)CTS; + writeHDMIRegister(X09_CTS_EXT, regValue); + + // set audio setting registers + writeHDMIRegister(X0A_AUDIO_SOURCE, 0x80); // external CTS + writeHDMIRegister(X0B_AUDIO_SET2, 0x40); + writeHDMIRegister(X0C_I2S_MODE, 0x04); // I2S 2ch (0x3C for 8ch) + I2S + //writeHDMIRegister(X0D_DSD_MODE, 0x00); // DSD audio disabled + writeHDMIRegister(X10_I2S_PINMODE, 0x00); // I2S input pin swap + writeHDMIRegister(X11_ASTATUS1, 0x0C); // Original Fs = 32kHz + writeHDMIRegister(X12_ASTATUS2, 0x22); + writeHDMIRegister(X13_CAT_CODE, 0x00); + writeHDMIRegister(X14_A_SOURCE, 0x51); // 24 bits word length + + regValue = (readHDMIRegister(X15_AVSET1) & 0x0F); // set freq 44.1kHz + regValue |= 0x30; // set freq 32kHz + writeHDMIRegister(X15_AVSET1, regValue); + + regValue = readHDMIRegister(X0A_AUDIO_SOURCE) & 0x9F; + writeHDMIRegister(X0A_AUDIO_SOURCE, regValue); // dounsampling none (bit 6:5 = 00) + + regValue = readHDMIRegister(X0A_AUDIO_SOURCE) & 0xF7; + writeHDMIRegister(X0A_AUDIO_SOURCE, regValue); // disable SPDIF + +} + + +/* + * Function: + * HDMI_Video_Setting + * isHDMI - 1: HDMI monitor; 0: DVI monitor + * + * Input: + * pModeParam + * + * Output: + * None + * + * Return: + * None + * + */ +void HDMI_Video_Setting (mode_parameter_t *pModeParam, bool isHDMI) +{ + unsigned long temp = 0; + unsigned char regValue = 0; + + // video set timing + regValue = readHDMIRegister(X30_EXT_VPARAMS); + regValue &= 0xF2; + regValue = + (pModeParam->vertical_sync_polarity == POS + ? FIELD_SET(regValue, X30_EXT_VPARAMS, VSYNC_PHASE, POS) + : FIELD_SET(regValue, X30_EXT_VPARAMS, VSYNC_PHASE, NEG)) + | (pModeParam->horizontal_sync_polarity == POS + ? FIELD_SET(regValue, X30_EXT_VPARAMS, HSYNC_PHASE, POS) + : FIELD_SET(regValue, X30_EXT_VPARAMS, HSYNC_PHASE, NEG)) + | FIELD_SET(regValue, X30_EXT_VPARAMS, USE, EXTERNAL); + writeHDMIRegister(X30_EXT_VPARAMS, regValue); + + writeHDMIRegister(X31_EXT_HTOTAL, (pModeParam->horizontal_total & 0xFF)); // horizontal total + writeHDMIRegister(X32_EXT_HTOTAL, (pModeParam->horizontal_total & 0xFF00)>>8); + + temp = pModeParam->horizontal_total - pModeParam->horizontal_display_end; // horizontal blanking + writeHDMIRegister(X33_EXT_HBLANK, (temp & 0xFF)); + writeHDMIRegister(X34_EXT_HBLANK, (temp & 0xFF00)>>8); + + temp = pModeParam->horizontal_total - pModeParam->horizontal_sync_start; // horizontal delay + writeHDMIRegister(X35_EXT_HDLY, (temp & 0xFF)); + writeHDMIRegister(X36_EXT_HDLY, (temp & 0xFF00)>>8); + + writeHDMIRegister(X37_EXT_HS_DUR, (pModeParam->horizontal_sync_width & 0xFF)); // horizontal duration + writeHDMIRegister(X38_EXT_HS_DUR, (pModeParam->horizontal_sync_width & 0xFF00)>>8); + + writeHDMIRegister(X39_EXT_VTOTAL, (pModeParam->vertical_total & 0xFF)); // vertical total + writeHDMIRegister(X3A_EXT_VTOTAL, (pModeParam->vertical_total & 0xFF00)>>8); + + temp = pModeParam->vertical_total - pModeParam->vertical_display_end; // vertical blanking + writeHDMIRegister(X3D_EXT_VBLANK, temp); + + temp = pModeParam->vertical_total - pModeParam->vertical_sync_start; // vertical delay + writeHDMIRegister(X3E_EXT_VDLY, temp); + + writeHDMIRegister(X3F_EXT_VS_DUR, pModeParam->vertical_sync_height); // vertical duration + + // video set color - deep_color_8bit + regValue = readHDMIRegister(X17_DC_REG); + regValue = (regValue & 0x3F) | 0x00; + writeHDMIRegister(X17_DC_REG, regValue); + + writeHDMIRegister(X16_VIDEO1, 0x30); + + // video set format + regValue = (readHDMIRegister(X15_AVSET1) & 0xF0); + regValue |= 0x01; // set RGB & external DE + writeHDMIRegister(X15_AVSET1, regValue); + writeHDMIRegister(X3B_AVSET2, 0x40); + //writeHDMIRegister(X40_CTRL_PKT_EN, 0x00); + //writeHDMIRegister(X45_VIDEO2, 0x83); + writeHDMIRegister(X46_OUTPUT_OPTION, 0x04); + writeHDMIRegister(XD3_CSC_CONFIG1, 0x01); + + // video set output - setting to HDMI/DVI mode + regValue = readHDMIRegister(XAF_HDCP_CTRL); + if (isHDMI) + writeHDMIRegister(XAF_HDCP_CTRL, (regValue | 0x02)); + else + writeHDMIRegister(XAF_HDCP_CTRL, (regValue & 0xFD)); + + // set DDC bus access frequency control register based on pixel clock value (400kHz is preferred) + // At mode_d/mode_e: + // DDC Bus access frequency = TDMS_CK input clock frequency / (register value) / 4 + temp = pModeParam ->pixel_clock / 4 / 400000; + writeHDMIRegister(X81_ISRC2_PB0, (temp & 0xFF)); // LSB + writeHDMIRegister(X82_ISRC2_PB1, (temp & 0xFF00)>>8); // MSB + +} + +/* + * Function: + * HDMI_PHY_Setting + * + * Input: + * pLogicalMode + * + * Output: + * None + * + * Return: + * 0 - Success + * -1 - Error + * + */ +long HDMI_PHY_Setting (mode_parameter_t *pModeParam) +{ + unsigned long clkIndex; + hdmi_PHY_param_t *pPHYParamTable; + + // Decide which PHY params to use depend on TMDS clock range. + if (pModeParam->pixel_clock > 0 && pModeParam->pixel_clock < 50000000) + { + clkIndex = CLK_0_to_50; + } + else if (pModeParam->pixel_clock >= 50000000 && pModeParam->pixel_clock < 100000000) + { + clkIndex = CLK_50_to_100; + } + else if (pModeParam->pixel_clock >= 100000000 && pModeParam->pixel_clock < 150000000) + { + clkIndex = CLK_100_to_150; + } + else if (pModeParam->pixel_clock >= 150000000 && pModeParam->pixel_clock < 200000000) + { + clkIndex = CLK_150_to_200; + } + else if (pModeParam->pixel_clock >= 200000000 && pModeParam->pixel_clock < 250000000) + { + clkIndex = CLK_200_to_250; + } + else if (pModeParam->pixel_clock >= 250000000 && pModeParam->pixel_clock <= 297000000) + { + clkIndex = CLK_4Kmode; + } + else + { + // Does not support TMDS clock higher than 297MHz. + return (-1); + } + + pPHYParamTable = (hdmi_PHY_param_t *)gHdmiPHYParamTable; + + // load PHY parameters into registers + writeHdmiPHYRegister(X57_PHY_CTRL, pPHYParamTable[clkIndex].X57_PHY_value); + writeHdmiPHYRegister(X58_PHY_CTRL, pPHYParamTable[clkIndex].X58_PHY_value); + writeHdmiPHYRegister(X59_PHY_CTRL, pPHYParamTable[clkIndex].X59_PHY_value); + writeHdmiPHYRegister(X5A_PHY_CTRL, pPHYParamTable[clkIndex].X5A_PHY_value); + writeHdmiPHYRegister(X5B_PHY_CTRL, pPHYParamTable[clkIndex].X5B_PHY_value); + writeHdmiPHYRegister(X5C_PHY_CTRL, pPHYParamTable[clkIndex].X5C_PHY_value); + writeHdmiPHYRegister(X5D_PHY_CTRL, pPHYParamTable[clkIndex].X5D_PHY_value); + writeHdmiPHYRegister(X5E_PHY_CTRL, pPHYParamTable[clkIndex].X5E_PHY_value); + writeHdmiPHYRegister(X56_PHY_CTRL, pPHYParamTable[clkIndex].X56_PHY_value); + writeHdmiPHYRegister(X17_DC_REG, pPHYParamTable[clkIndex].X17_PHY_value); + + return 0; +} + +/* + * Function: + * HDMI_Set_Mode + * + * Input: + * pLogicalMode + * isHDMI - 1: HDMI monitor; 0: DVI monitor + * + * Output: + * None + * + * Return: + * 0 - Success + * -1 - Error + * + */ +long HDMI_Set_Mode (logicalMode_t *pLogicalMode, mode_parameter_t *pModeParam, bool isHDMI) +{ + + unsigned char temp = 0; + unsigned long ret = 0; + hdmi_vic_param_t *PBTable; + // set mode b + if (PowerMode != PowerMode_B) + { + HDMI_System_PD (PowerMode_B); + } + + if (!pLogicalMode->valid_edid) + { + // find mode parameters for input mode + pModeParam = ddk768_findModeParam(pLogicalMode->dispCtrl, pLogicalMode->x, pLogicalMode->y, pLogicalMode->hz, 0); + if (pModeParam == (mode_parameter_t *)0) + return -1; + } + + /* Set VIC */ + if((pLogicalMode->x == 3840) && (pLogicalMode->y == 2160)) + { + /* Write 4K specail vic parameters.*/ + writeHDMIRegister (X5F_PACKET_INDEX, VENDOR_INFO_PACKET); + writeHDMIRegister (X60_PACKET_HB0, 0x81); // HB0 0x82 + writeHDMIRegister (X61_PACKET_HB1, 0x01); // HB1 0x02 + writeHDMIRegister (X62_PACKET_HB2, 0x07); // HB2 0x0D + writeHDMIRegister (X64_PACKET_PB1, 0x03); // PB1 0x00 + writeHDMIRegister (X65_PACKET_PB2, 0x0C); // PB2 0x00 + writeHDMIRegister (X66_PACKET_PB3, 0x00); // PB3 0x12 + writeHDMIRegister (X67_PACKET_PB4, 0x20); // PB4 + writeHDMIRegister (X68_PACKET_PB5, 0x01); // PB5 0x00 + writeHDMIRegister (X69_PACKET_PB6, 0x00); // PB6 0xe4 + writeHDMIRegister (X6A_PACKET_PB7, 0x00); // PB7 0xb5 + } + else + { + PBTable = FindVicParam(pLogicalMode->x, pLogicalMode->y); + writeHDMIRegister (X5F_PACKET_INDEX, AVI_INFO_PACKET); + writeHDMIRegister (X67_PACKET_PB4, PBTable->Vic); + + /* For un-4k mode, the following registers should be re-write.*/ + writeHDMIRegister (X60_PACKET_HB0, 0x82); // HB0 + writeHDMIRegister (X61_PACKET_HB1, 0x02); // HB1 + writeHDMIRegister (X62_PACKET_HB2, 0x0D); // HB2 + writeHDMIRegister (X64_PACKET_PB1, 0x00); //0x18); // PB1 + writeHDMIRegister (X65_PACKET_PB2, PBTable->PB2); //0xc8); // PB2 + writeHDMIRegister (X66_PACKET_PB3, 0x12); // PB3 + writeHDMIRegister (X68_PACKET_PB5, 0x00); // PB5 + writeHDMIRegister (X69_PACKET_PB6, 0xe4); // PB6 + writeHDMIRegister (X6A_PACKET_PB7, 0xb5); // PB7 + + } + // Index.8 Audio + writeHDMIRegister(X5F_PACKET_INDEX, AUDIO_INFO_PACKET); + + // set video param + HDMI_Video_Setting(pModeParam, isHDMI); + + // set audio param + if (ddk768_getCrystalType()) + HDMI_Audio_Setting_48000Hz(pModeParam); + else + HDMI_Audio_Setting_44100Hz(pModeParam); + + // control packet auto send + HDMI_Control_Packet_Auto_Send(); + + // set PHY param + ret = HDMI_PHY_Setting(pModeParam); + if (ret != 0) + { + return ret; + } + + // disable video & audio output: write 11b to #45h[1:0] + temp = readHDMIRegister(X45_VIDEO2); + writeHDMIRegister(X45_VIDEO2, (temp | 0x03)); + + // set Channel # to HDMI + setHDMIChannel((unsigned char)pLogicalMode->dispCtrl); + + // mode b->d: (0x4d, 100us) -> (0x49, 100us) -> 0x41 + PowerMode = PowerMode_D; + writeHDMIControlRegister (PowerMode | 0x0C); + DelayMs (1); + writeHDMIControlRegister (PowerMode | 0x08); + DelayMs (1); + writeHDMIControlRegister (PowerMode); + DelayMs (1); + + // mode d->e: 0x81 + //HDMI_System_PD (PowerMode_E); + PowerMode = PowerMode_E; + writeHDMIControlRegister (PowerMode); + DelayMs(10); // wait 10ms + + HDMI_Audio_Reset(); + + if (AudioMode) + { + // enable video & audio output: write 00b to #45h[1:0] + temp = readHDMIRegister(X45_VIDEO2); + temp &= 0xFB; + writeHDMIRegister(X45_VIDEO2, (temp & 0xFC)); + + } + else + { + // enable video output: write 0b to #45h[0] + temp = readHDMIRegister(X45_VIDEO2); + writeHDMIRegister(X45_VIDEO2, (temp & (~0x01))); + } + + +#if 0 // for debug only + HDMI_Dump_Registers(); +#endif + + return 0; +} +void HDMI_Enable_Output(void) +{ + unsigned char temp = 0; + + + if (PowerMode == PowerMode_B){ + // mode b->d: (0x4d, 100us) -> (0x49, 100us) -> 0x41 + PowerMode = PowerMode_D; + writeHDMIControlRegister (PowerMode | 0x0C); + DelayMs (1); + writeHDMIControlRegister (PowerMode | 0x08); + DelayMs (1); + writeHDMIControlRegister (PowerMode); + DelayMs (1); + + // mode d->e: 0x81 + HDMI_System_PD (PowerMode_E); + } + + // enable video & audio output: write 00b to #45h[1:0] + temp = readHDMIRegister(X45_VIDEO2); + writeHDMIRegister(X45_VIDEO2, (temp & (~0x03))); + + // Audio reset/release + // Audio is mute after reset of audio is set. + // Therefore, set it in the following procedures. + // Audio: Save value of now => Audio Reset => Audio Active => Set value again + temp = readHDMIRegister(X45_VIDEO2); + writeHDMIRegister(X45_VIDEO2, temp | 0x04 ); // Reset + DelayMs(1); // Followed by 1ms wait time + writeHDMIRegister(X45_VIDEO2, temp & 0xFB ); // Reset Release and Audio Mute) + +#if 0 // for debug only + HDMI_Dump_Registers(); +#endif + + return ; + +} + +/* + * Function: + * HDMI_Disable_Output + * + * Input: + * None + * + * Output: + * None + * + * Return: + * None + * + */ +void HDMI_Disable_Output (void) +{ + unsigned char temp = 0; + + // disable video & audio output: write 11b to #45h[1:0] + temp = readHDMIRegister(X45_VIDEO2); + writeHDMIRegister(X45_VIDEO2, (temp | 0x03)); + + // audio reset: write 1b to #45h[2], followed by 500us wait time + temp = readHDMIRegister(X45_VIDEO2); + writeHDMIRegister(X45_VIDEO2, (temp | 0x04)); + DelayMs(1); + + // PS mode e->d->b + HDMI_System_PD (PowerMode_D); + HDMI_System_PD (PowerMode_B); +} + + + +/* + * Function: + * HDMI_Edid_ReadFirstByte + * + * Input: + * None + * + * Return: + * Fisrt byte of HDMI EDID FIFO + * + */ +unsigned char HDMI_Edid_ReadFirstByte(void) +{ + unsigned long value; + + pokeRegisterDWord(HDMI_CONFIG, + FIELD_SET(0, HDMI_CONFIG, READ, LATCH) | + FIELD_VALUE(0, HDMI_CONFIG, ADDRESS, X80_EDID)); + + DelayMs(1); + + pokeRegisterDWord(HDMI_CONFIG, FIELD_VALUE(0, HDMI_CONFIG, ADDRESS, X80_EDID)); + + DelayMs(1); + + value = peekRegisterDWord(HDMI_CONFIG); + + return (unsigned char)((value >> 8) & 0xFF); +} + +/* + * Function: + * HDMI_Edid_CheckSum + * + * Input: + * array - EDID data + * size - size of array + * + * Return: + * byChecksum + * + */ +BYTE HDMI_Edid_CheckSum (BYTE* array, unsigned long size) +{ + BYTE i, sum = 0; + for (i = 0; i < size; i++) + sum += array[i]; + + return sum; +} + +/* + * Function: + * HDMI_Read_Edid. + * + * Input: + * pEDIDBuffer - EDID buffer + * bufferSize - EDID buffer size (usually 128-bytes or 256 bytes) + * Output: + * -1 - Error + * 0 - exist block0 EDID (128 Bytes) + * 1 - exist block0 & block1 EDID (256 Bytes) + */ +long HDMI_Read_Edid(BYTE *pEDIDBuffer, unsigned long bufferSize) +{ + BYTE byEDID_current = 0; + BYTE byEDID_size = 0; + BYTE byEDID_finish = 0; + #define EDID_WORD ((byEDID_current % 2) ? 0x80 : 0x00) + #define EDID_SEG (byEDID_current /2) + #define EDID_EXT (gEdidBuffer[126]) + + BYTE byChecksum = 0, regValue; + unsigned long i = 0; + unsigned long retry = 1000; + + if (pEDIDBuffer == (unsigned char *)0) + { + printk("buffer is NULL!\n"); + return (-1); + } + + // PS mode a -> b if current power mode is in PS mode a + if (PowerMode == PowerMode_A) + { + HDMI_System_PD (PowerMode_B); + } + + // clear interrupt status before reading EDID + writeHDMIRegister (X94_INT1_ST, 0xFF); + writeHDMIRegister (X95_INT2_ST, 0xFF); + + // Enable EDID interrupt + regValue = readHDMIRegister (X92_INT_MASK1); + writeHDMIRegister (X92_INT_MASK1, (regValue | 0x06)); + + while(byEDID_finish == 0) + { + // Set EDID word address (set to 00h for the first 128 bytes) + writeHDMIRegister (XC5_EDID_WD_ADDR, EDID_WORD); + // Set EDID segment pointer 0 + // (Regsiter write to XC4_SEG_PTR will start EDID reading) + writeHDMIRegister (XC4_SEG_PTR, EDID_SEG); + + /* Hook the interrupt before going to the while */ + //hookHDMIInterrupt(HdmiHandler); + + retry = 1000; + while(retry) + { + retry--; + + g_INT_94h = readHDMIRegister (X94_INT1_ST); + g_INT_95h = readHDMIRegister (X95_INT2_ST); + + // EDID ERR interrupt, or EDID not ready + if ((g_INT_94h & EDID_ERR)) + { + // clear error interrupt + writeHDMIRegister (X94_INT1_ST, 0xFF); + writeHDMIRegister (X95_INT2_ST, 0xFF); + DelayMs(1); + } + else if (g_INT_94h & EDID_RDY) + { + // clear ready interrupt + writeHDMIRegister (X94_INT1_ST, 0xFF); + writeHDMIRegister (X95_INT2_ST, 0xFF); + + // Read EDID for current block (128bytes) + gEdidBuffer[byEDID_current* 0x80] = HDMI_Edid_ReadFirstByte(); + + for(i=1;i<128;i++) + { + gEdidBuffer[byEDID_current* 0x80+i] = readHDMIRegister(X80_EDID); + DelayMs(1); + } + printk("EDID read finish\n"); + + // Calculate EDID data byChecksum + byChecksum = HDMI_Edid_CheckSum(gEdidBuffer + (byEDID_current * 0x80), 128); + // printf("checksum = %x\n", byChecksum); + + if (byChecksum != 0) + { + // Return fail + printk("Block %x Checksum != 0, fail.\n",byEDID_current); + if (byEDID_current == 0) + { + // Disable EDID interrupt + regValue = readHDMIRegister (X92_INT_MASK1); + writeHDMIRegister (X92_INT_MASK1, (regValue & (~0x06))); + + return (-1); + } + else + { + // Disable EDID interrupt + regValue = readHDMIRegister (X92_INT_MASK1); + writeHDMIRegister (X92_INT_MASK1, (regValue & (~0x06))); + + // DDKDEBUGPRINT((DISPLAY_LEVEL, "Return the first 128 bytes only.\n")); + // Copy 128 bytes data to the given buffer + for (i = 0; i < 128; i++) + { + // printf("%x ", gEdidBuffer[i]); + pEDIDBuffer[i] = gEdidBuffer[i]; + } + printk("\n"); + + return 0; // read first 128 bytes successfully, extension 128 bytes failed. + } + } + else + { + //Read Extension flag of EDID + byEDID_size = EDID_EXT; + + if ((byEDID_size==1) && (byEDID_current < 1)) + { + // Move to next EDID block + byEDID_current++; + printk("Exist extern EDID information.\n"); + // EDID read block1 + //byEDID_STATE = HDMI_STATE_EDID_START; + break; + } + else + { + printk("HDMI EDID Finished.\n"); + byEDID_finish = 1; + break; + } + + } + + } + } + + if (retry == 0) + { + printk("Read HDMI EDID fail.\n"); + // Disable EDID interrupt + regValue = readHDMIRegister (X92_INT_MASK1); + writeHDMIRegister (X92_INT_MASK1, (regValue & (~0x06))); + + return (-1); + } + /* unhook the interrupt */ + //unhookHDMIInterrupt(HdmiHandler); + } + + // Disable EDID interrupt + regValue = readHDMIRegister (X92_INT_MASK1); + writeHDMIRegister (X92_INT_MASK1, (regValue & (~0x06))); + + // Copy data to the given buffer + for (i = 0; i < bufferSize; i++) + { + pEDIDBuffer[i] = gEdidBuffer[i]; + } + +#if 0 // for debug only + // Print EDID data + for (j = 0; j < 8; j++) + { + printf("0x%02x: ", (j*16)); + for (i = 0; i < 16; i++) + printf("%02x ", gEdidBuffer[(j*16+i)]); + printf("\n"); + } + if (byEDID_current > 0) + { + printf("E_EDID:\n"); + for (j = 8; j < 16; j++) + { + printf("0x%02x: ", (j*16)); + for (i = 0; i < 16; i++) + printf("%02x ", gEdidBuffer[(j*16+i)]); + printf("\n"); + } + printf("\n"); + } +#endif + + // Return EDID block number + return byEDID_current; +} + +/* + * Function: + * HDMI_hotplug_check + * + * Input: + * None + * + * Output: + * 0 - unplugged + * 1 - plugged + * + */ +BYTE HDMI_connector_detect(void) +{ + unsigned long value = 0; + + //enable GPIO + pokeRegisterDWord(GPIO_INTERRUPT_SETUP, 0); + value = FIELD_SET(peekRegisterDWord(GPIO_DATA_DIRECTION), GPIO_DATA_DIRECTION, 1, INPUT); + pokeRegisterDWord(GPIO_DATA_DIRECTION, value); + value = peekRegisterDWord(GPIO_DATA); + + return (value & (1<<1)); +} + +/* + * Function: + * HDMI_hotplug_check + * + * Input: + * None + * + * Output: + * 0 - unplugged + * 1 - plugged + * + */ +BYTE HDMI_hotplug_check (void) +{ + BYTE STAT_DFh; + + // Wait time before check hot plug & MSENS pin status + DelayMs (15); + + STAT_DFh = readHDMIRegister (XDF_HPG_STATUS); + + if ((STAT_DFh & HPG_MSENS) == HPG_MSENS) // HPD & MSENS status both high? + { + // DDC I2C master controller reset ... ddc_ctrl_reset[bit4] + writeHDMIRegister (X3B_AVSET2, readHDMIRegister (X3B_AVSET2) | 0x10); + writeHDMIRegister (X3B_AVSET2, readHDMIRegister (X3B_AVSET2) & 0xEF); + + return 1; + } + else + { + return 0; + } + +} + + +int hdmi_detect(void) +{ + unsigned int intStatus; + + + intStatus = peekRegisterDWord(INT_STATUS); + + if (FIELD_GET(intStatus, INT_STATUS, HDMI) == INT_STATUS_HDMI_ACTIVE) + { + + + if (PowerMode == PowerMode_A) + { + // PS mode a->b + HDMI_System_PD(PowerMode_B); + } + + // Save interrupt status from the last interrupt + g_INT_94h = readHDMIRegister(X94_INT1_ST); + g_INT_95h = readHDMIRegister(X95_INT2_ST); + + // check if plug-in or plug-out detect + if ((g_INT_94h & HPG_MSENS) == HPG_MSENS) // HPD & MSENS status both high? + { + // clear all interrupts + writeHDMIRegister(X94_INT1_ST, 0xFF); + writeHDMIRegister(X95_INT2_ST, 0xFF); + + if (HDMI_hotplug_check()) + { + return 1; + } + else + { + return 0; + } + + } + + } + return 3; //nothing to do +} + + + + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_hdmi.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_hdmi.h new file mode 100644 index 000000000000..1ed3824213dd --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_hdmi.h @@ -0,0 +1,490 @@ +/******************************************************************* +* +* Copyright (c) 2009 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* HDMI.H --- SMI DDK +* This file contains the source code for the HDMI controller chip +* +*******************************************************************/ + +#ifndef _HDMI_HEADER_H_ +#define _HDMI_HEADER_H_ + +#include "ddk768_mode.h" + +#define SMI_HDMI_LIB_VERSION ("2.0") + +#ifndef BYTE +typedef unsigned char BYTE; +#endif + +// This macro is for HDMI PNP detection - interrupt mode +//#define HDMI_PNP_USE_INT + +//----------------------------------------------------------------------------- +// Global Constants +//----------------------------------------------------------------------------- + +// Video setting constants +#define VID_01_640x480p 1 +#define VID_02_720x480p 2 +#define VID_03_720x480p 3 +#define VID_04_1280x720p 4 +#define VID_05_1920x1080i 5 +#define VID_06_720x480i 6 +#define VID_07_720x480i 7 +#define VID_08_720x240p 8 +#define VID_09_720x240p 9 +#define VID_10_2880x480i 10 +#define VID_11_2880x480i 11 +#define VID_12_2880x240p 12 +#define VID_13_2880x240p 13 +#define VID_14_1440x480p 14 +#define VID_15_1440x480p 15 +#define VID_16_1920x1080p 16 +#define VID_17_720x576p 17 +#define VID_18_720x576p 18 +#define VID_19_1280x720p 19 +#define VID_20_1920x1080i 20 +#define VID_21_720x576i 21 +#define VID_22_720x576i 22 +#define VID_23_720x288p 23 +#define VID_24_720x288p 24 +#define VID_25_2880x576i 25 +#define VID_26_2880x576i 26 +#define VID_27_2880x288p 27 +#define VID_28_2880x288p 28 +#define VID_29_1440x576p 29 +#define VID_30_1440x576p 30 +#define VID_31_1920x1080p 31 +#define VID_32_1920x1080p 32 +#define VID_33_1920x1080p 33 +#define VID_34_1920x1080p 34 +#define VID_35_2880x480p 35 +#define VID_36_2880x480p 36 +#define VID_37_2880x576p 37 +#define VID_38_2880x567p 38 +#define VID_39_1920x1080i 39 +#define VID_40_1920x1080i 40 +#define VID_41_1280x720p 41 +#define VID_42_720x576p 42 +#define VID_43_720x576p 43 +#define VID_44_720x576i 44 +#define VID_45_720x576i 45 +#define VID_46_1920x1080i 46 +#define VID_47_1280x720p 47 +#define VID_48_720x480p 48 +#define VID_49_720x480p 49 +#define VID_50_720x480i 50 +#define VID_51_720x480i 51 +#define VID_52_720x576p 52 +#define VID_53_720x576p 53 +#define VID_54_720x576i 54 +#define VID_55_720x576i 55 +#define VID_56_720x480p 56 +#define VID_57_720x480p 57 +#define VID_58_720x480i 58 +#define VID_59_720x480i 59 + +// Audio setting constants +#define AUD_48K 0x10 +#define AUD_96K 0x20 +#define AUD_192K 0x30 +#define AUD_2CH 0x40 // 2ch audio +#define AUD_8CH 0x80 // 8ch audio +//#define DS_none 0x00 // No Downsampling +#define DS_none 0x01 // No Downsampling +#define DS_2 0x04 // Downsampling 96k to 48k +#define DS_4 0x08 // DOwnsampling 192k to 48k +#define AUD_SPDIF 0x01 +#define AUD_I2S 0x02 + +// Power Mode - System Control +#define PowerMode_A 0x11 +#define PowerMode_B 0x21 +#define PowerMode_D 0x41 +#define PowerMode_E 0x81 + +// Audio Mode - For HDMI_Set_Mode's use, in case audio command is received before mode setting +#define Audio_Mute 0x00 +#define Audio_Unmute 0x01 + +// Output Format +#define FORMAT_RGB 0 +#define FORMAT_YCC422 1 +#define FORMAT_YCC444 2 + +// Deep Color Bit, +// Should follow GCP_CD[3:0] definition +#define DEEP_COLOR_8BIT 4 +#define DEEP_COLOR_10BIT 5 +#define DEEP_COLOR_12BIT 6 + +// Register Values for Register 94h: Interrupt Status 1 +#define INT1_RSVD 0x09 +#define HOT_PLUG 0x80 +#define HPG_MSENS 0xC0 +#define EDID_ERR 0x02 +#define EDID_RDY 0x04 +#define VSYNC 0x20 + +// Register Values for Register 95h: Interrupt Status 2 +#define INT2_RSVD 0x07 +#define HDCP_ERR 0x80 +#define BKSV_RDY 0x60 +#define HDCP_AUTH 0x08 +#define HDCP_DONE 0x10 + +// STATE +#define HDMI_STATE_IDLE 0x01 +#define HDMI_STATE_HOTPLUG 0x02 +#define HDMI_STATE_EDID_START 0x03 +#define HDMI_STATE_EDID_READY 0x04 +#define HDMI_STATE_EDID_READ 0x05 +#define HDMI_STATE_EDID_PROCESS 0x06 +#define HDMI_STATE_TX_SETTING 0x07 +#define HDMI_STATE_TX_START 0x08 +#define HDMI_STATE_TX_RUNNING 0x09 +#define HDMI_STATE_HDCP_START 0x0A +#define HDMI_STATE_HDCP_READY 0x0B +#define HDMI_STATE_HDCP_READ 0x0C +#define HDMI_STATE_HDCP_AUTH 0x0D +//#define HDMI_STATE_PHY_RESET 0x0E +#define HDMI_STATE_ERROR 0x00 +#define STATE_DEBUG 0xFF + + +//----------------------------------------------------------------------------- +// Type Definition +//----------------------------------------------------------------------------- + +typedef enum _aspect_ratio_t +{ + AR_4to3, /* 4:3 */ + AR_16to9, /* 16:9 */ +} +aspect_ratio_t; + +typedef enum _TMDS_clk_t +{ + CLK_0_to_50, /* 0-50MHz TMDS clock */ + CLK_50_to_100, /* 50-100MHz TMDS clock */ + CLK_100_to_150, /* 100-150MHz TMDS clock */ + CLK_150_to_200, /* 150-200MHz TMDS clock */ + CLK_200_to_250, /* 200-250MHz TMDS clock */ + CLK_4Kmode, /* 4K mode uses seperate PHY parameters */ +} +TMDS_clk_t; + +typedef struct _hdmi_PHY_param_t +{ + unsigned char X17_PHY_value; + unsigned char X56_PHY_value; + unsigned char X57_PHY_value; + unsigned char X58_PHY_value; + unsigned char X59_PHY_value; + unsigned char X5A_PHY_value; + unsigned char X5B_PHY_value; + unsigned char X5C_PHY_value; + unsigned char X5D_PHY_value; + unsigned char X5E_PHY_value; +} +hdmi_PHY_param_t; + +typedef struct _hdmi_vic_param_t +{ + unsigned long Width; + unsigned long Height; + unsigned char Vic; + unsigned char PB2; +} +hdmi_vic_param_t; + +//----------------------------------------------------------------------------- +// Prototypes +//----------------------------------------------------------------------------- + +/* + * This is the main interrupt hook for HDMI engine. + */ +long hookHDMIInterrupt( + void (*handler)(void) +); + +/* + * This function un-register HDMI Interrupt handler. + */ +long unhookHDMIInterrupt( + void (*handler)(void) +); + +/* + * Function: + * writeHDMIRegister + * + * Input: + * addr - HDMI register index (could be from 0x01 to 0xFF) + * value - HDMI register value + * + * Output: + * None + * + */ +void writeHDMIRegister(unsigned char addr, unsigned char value); + +/* + * Function: + * readHDMIRegister + * + * Input: + * addr - HDMI register index (could be from 0x01 to 0xFF) + * + * Output: + * register value + * + */ +unsigned char readHDMIRegister(unsigned char addr); + +/* + * Function: + * writeHDMIControlRegister + * This functions writes HDMI System Control register (index 0x00). + * + * Input: + * value - HDMI register 0x00 value + * + * Output: + * None + * + */ +void writeHDMIControlRegister(unsigned char value); + +/* + * Function: + * readHDMIRegister + * This functions reads HDMI System Control register (index 0x00). + * + * Input: + * None + * + * Output: + * register value + * + */ +unsigned char readHDMIControlRegister(void); + +/* + * Function: + * writeHdmiPHYRegister + * + * Input: + * addr - HDMI register index (for PHY registers only, could be from 0x57 to 0x5E) + * value - HDMI register value + * + * Output: + * None + * + */ +void writeHdmiPHYRegister(unsigned char addr, unsigned char value); + +/* + * Function: + * setHDMIChannel + * + * Input: + * channel number - 0 = Select Channel 0 to HDMI + * - 1 = Select Channel 1 to HDMI + * + * Output: + * None + * + */ +void setHDMIChannel(unsigned char Channel); + +/* + * Function: + * enableHdmiI2C + * + * Input: + * enable/disable - 0 = HDMI I2C to GPIO[7:6] + * - 1 = HW I2C to GPIO[7:6] + * + * Output: + * None + * + */ +void enableHdmI2C(unsigned long enable); + +/* + * Function: + * HDMI_Dump_Registers (Used for debug) + * + * Input: + * None + * + * Output: + * None + * + */ +void HDMI_Dump_Registers (void); + +// +// Parameters : unsigned char mode. 4 modes available. +// MODE_A (sleep), MODE_B (register access), MODE_D (clock), MODE_E (active). +// +void HDMI_System_PD (unsigned char mode); + +/* + * Function: + * HDMI_Set_Control_Packet + * + * Input: + * None + * + * Output: + * None + * + */ +void HDMI_Init (void); + +/* + * Function: + * HDMI_Set_Mode + * + * Input: + * pLogicalMode + * isHDMI - 1: HDMI monitor; 0: DVI monitor + * + * Output: + * None + * + * Return: + * 0 - Success + * -1 - Error + * + */ +long HDMI_Set_Mode (logicalMode_t *pLogicalMode, mode_parameter_t *pModeParam, bool isHDMI); + + +void HDMI_Enable_Output(void); + +/* + * Function: + * HDMI_Disable_Output + * + * Input: + * None + * + * Output: + * None + * + * Return: + * None + * + */ +void HDMI_Disable_Output (void); + +/* + * Function: + * HDMI_Unplugged + * + * Input: + * None + * + * Return: + * None + * + */ +void HDMI_Unplugged (void); + +/* + * Function: + * HDMI_Audio_Reset + * + * Input: + * None + * + * Output: + * None + * + * Return: + * None + * + */ +void HDMI_Audio_Reset (void); + +/* + * Function: + * HDMI_Audio_Mute + * + * Input: + * None + * + * Output: + * None + * + * Return: + * None + * + */ +void HDMI_Audio_Mute (void); + +/* + * Function: + * HDMI_Audio_Unmute + * + * Input: + * None + * + * Output: + * None + * + * Return: + * None + * + */ +void HDMI_Audio_Unmute (void); + + + + +/* + * Function: + * HDMI_Read_Edid. + * + * Input: + * pEDIDBuffer - EDID buffer + * bufferSize - EDID buffer size (usually 128-bytes or 256 bytes) + * Output: + * -1 - Error + * 0 - exist block0 EDID (128 Bytes) + * 1 - exist block0 & block1 EDID (256 Bytes) + */ +long HDMI_Read_Edid(BYTE *pEDIDBuffer, unsigned long bufferSize); + +/* + * Function: + * HDMI_hotplug_check + * + * Input: + * None + * + * Output: + * 0 - unplugged + * 1 - plugged + * + */ +BYTE HDMI_hotplug_check (void); + +int hdmi_detect(void); + +BYTE HDMI_connector_detect(void); + +void hdmiHandler(void); +void Delay (void); +void DelayMs (BYTE millisecond); + +#endif /* _HDMI_HEADER_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_help.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_help.c new file mode 100644 index 000000000000..c9c5474b19cf --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_help.c @@ -0,0 +1,12 @@ +#include "ddk768_help.h" + +volatile unsigned char __iomem * mmio768 = NULL; + +/* after driver mapped io registers, use this function first */ +void ddk768_set_mmio(volatile unsigned char * addr,unsigned short devId,char revId) +{ + mmio768 = addr; + printk("Found SM768 SOC Chip\n"); +} + + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_help.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_help.h new file mode 100644 index 000000000000..c0aa4dc0eb1e --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_help.h @@ -0,0 +1,36 @@ +#ifndef _DDK768_HELP_H__ +#define _DDK768_HELP_H__ + +#ifndef USE_INTERNAL_REGISTER_ACCESS + +#include +#include +#include + + + +#define PEEK32(addr) readl((addr)+mmio768) +#define POKE32(addr,data) writel((data),(addr)+mmio768) + + +#define peekRegisterDWord(addr) readl((addr)+mmio768) +#define pokeRegisterDWord(addr,data) writel((data),(addr)+mmio768) + +#define peekRegisterByte(addr) readb((addr)+mmio768) +#define pokeRegisterByte(addr,data) writeb((data),(addr)+mmio768) + + +/* Size of SM768 MMIO and memory */ +#define SM768_PCI_ALLOC_MMIO_SIZE (2*1024*1024) +#define SM768_PCI_ALLOC_MEMORY_SIZE (128*1024*1024) + + +void ddk768_set_mmio(volatile unsigned char * addr,unsigned short devId,char revId); + +extern volatile unsigned char __iomem * mmio768; + +#else +/* implement if you want use it*/ +#endif + +#endif diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_helper.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_helper.c new file mode 100644 index 000000000000..9407956d1410 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_helper.c @@ -0,0 +1,84 @@ +/******************************************************************* +* +* Copyright (c) 2009 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* helper.c --- SM750 DDK +* This file contains helper functions those are used throughout +* the DDK library. +* +*******************************************************************/ +#include "ddkdebug.h" + +/* A test counter to be shared by all modules */ +static unsigned long gTestCounter; + +/* Functions to manipulate a test counter. */ +unsigned long getTestCounter(void) +{ + return gTestCounter; +} + +void setTestCounter(unsigned long value) +{ + gTestCounter = value; +} + +void incTestCounter(void) +{ + gTestCounter++; +} + +/* Perform a rounded division with signed number. + * For example, if the result is 4.5, this function returns 5. + * If the result is 4.4, this function returns 4. + */ +long lRoundedDiv(long num, long denom) +{ + /* n / d + 1 / 2 = (2n + d) / 2d */ + return (2 * num + denom) / (2 * denom); +} + +/* Perform a rounded division. + * For example, if the result is 4.5, this function returns 5. + * If the result is 4.4, this function returns 4. + */ +unsigned long ddk768_roundedDiv(unsigned long num, unsigned long denom) +{ + /* n / d + 1 / 2 = (2n + d) / 2d */ + return (2 * num + denom) / (2 * denom); +} + +/* Perform a rounded division with unsigned number. + * For example, if the result is 4.5, this function returns 5. + * If the result is 4.4, this function returns 4. + */ +unsigned long ulRoundedDiv(unsigned long num, unsigned long denom) +{ + return ddk768_roundedDiv(num, denom); +} + +/* Absolute differece between two numbers */ +unsigned long ddk768_absDiff(unsigned long a, unsigned long b) +{ + if ( a >= b ) + return(a - b); + else + return(b - a); +} + +/* This function calculates 2 to the power of x + Input is the power number. + */ +unsigned long ddk768_twoToPowerOfx(unsigned long x) +{ + unsigned long i; + unsigned long result = 1; + + for (i=1; i<=x; i++) + result *= 2; + + return result; +} diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_helper.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_helper.h new file mode 100644 index 000000000000..cd6f9f8bf0eb --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_helper.h @@ -0,0 +1,44 @@ +/******************************************************************* +* +* Copyright (c) 2009 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* helper.h --- SMI DDK +* This file contains the helper functions those are used throughout +* the library +* +*******************************************************************/ +#ifndef _DDK768_HELPER_H_ +#define _DDK768_HELPER_H_ + +/* Functions to manipulate a test counter. */ +unsigned long getTestCounter(void); + +void setTestCounter(unsigned long value); + +void incTestCounter(void); + + +/* Perform a rounded division with signed number. + * For example, if the result is 4.5, this function returns 5. + * If the result is 4.4, this function returns 4. + */ +long lRoundedDiv(long num, long denom); + +/* Perform a rounded division. + * For example, if the result is 4.5, this function returns 5. + * If the result is 4.4, this function returns 4. + */ +unsigned long ddk768_roundedDiv(unsigned long num, unsigned long denom); + +/* Absolute differece between two numbers */ +unsigned long ddk768_absDiff(unsigned long a, unsigned long b); + +/* This function calculates 2 to the power of x + Input is the power number. + */ +unsigned long ddk768_twoToPowerOfx(unsigned long x); + +#endif /* _HELPER_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_hwi2c.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_hwi2c.c new file mode 100644 index 000000000000..cb3f860ba0b0 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_hwi2c.c @@ -0,0 +1,418 @@ +#include "ddk768_reg.h" +#include "ddk768_power.h" +#include "ddk768_hwi2c.h" +#include "ddk768_help.h" + +unsigned long hwI2CWriteData( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned long length, + unsigned char *pBuffer +); + +unsigned long hwI2CReadData( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned long length, + unsigned char *pBuffer +); + +static int ddk768_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], + int num) +{ + struct smi_connector *connector = i2c_get_adapdata(adap); + unsigned char i2cNumber = connector->i2cNumber; + unsigned long ret = 0; + int i = 0; + + if(i2cNumber > 1) + { + return -EOPNOTSUPP; + } + + for (i = 0; i < num; i++) { + if (msgs[i].len == 0) { + pr_err("unsupported transfer %d/%d, no data\n", + i + 1, num); + return -EOPNOTSUPP; + } + } + + + for (i = 0; i < num; i++) + { + msgs->addr = msgs->addr << 1; + + if (msgs->flags & I2C_M_RD) + { + + ret = hwI2CReadData( + i2cNumber, // I2C0 or I2C1 + msgs->addr, + msgs->len, + msgs->buf); + if (ret < msgs->len) + { + ret = 0; + pr_err("ddk768 i2c xfer rx failed %ld.\n", ret); + break; + } + } + else + { + ret = hwI2CWriteData( + i2cNumber, // I2C0 or I2C1 + msgs->addr, + msgs->len, + msgs->buf); + if (ret < msgs->len) + { + ret = 0; + pr_err("ddk768 i2c xfer tx failed %ld.\n", ret); + break; + } + } + + msgs++; + } + + if (ret) + ret = num; + + return ret; + +} + +static u32 ddk768_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + + +const struct i2c_algorithm ddk768_i2c_algo = { + .master_xfer = ddk768_i2c_xfer, + .functionality = ddk768_i2c_func +}; + +/* + * This function initializes the hardware i2c + * + * Return Value: + * 0 - Success + * -1 - Fail to initialize i2c + */ +long ddk768_hwI2CInit( + unsigned char i2cNumber //I2C0 or I2C1 +) +{ + unsigned long value, offset; + if(i2cNumber > 1) { + return -1; + } + + /* Enable GPIO pins as IIC clock & data */ + if (i2cNumber == 0) + { + value = FIELD_SET(peekRegisterDWord(GPIO_MUX), GPIO_MUX, I2C0, ENABLE); + pokeRegisterDWord(GPIO_MUX, value); + offset = 0; + } + else + { + value = FIELD_SET(peekRegisterDWord(GPIO_MUX), GPIO_MUX, I2C1, ENABLE); + pokeRegisterDWord(GPIO_MUX, value); + offset = I2C_OFFSET; + } + + /* Enable the I2C Controller and set the bus speed mode */ + value = FIELD_SET(peekRegisterByte(I2C_CTRL+offset), I2C_CTRL, EN, ENABLE); + value = FIELD_SET(value, I2C_CTRL, MODE, FAST); + pokeRegisterByte(I2C_CTRL+offset, value); + + return 0; +} + +/* + * This function closes the hardware i2c. + */ +void ddk768_hwI2CClose( + unsigned char i2cNumber //I2C0 or I2C1 +) +{ + unsigned long value, offset; + + /* Set GPIO 30 & 31 back as GPIO pins */ + if (i2cNumber == 0) + { + value = FIELD_SET(peekRegisterDWord(GPIO_MUX), GPIO_MUX, I2C0, DISABLE); + pokeRegisterDWord(GPIO_MUX, value); + offset = 0; + } + else + { + value = FIELD_SET(peekRegisterDWord(GPIO_MUX), GPIO_MUX, I2C1, DISABLE); + pokeRegisterDWord(GPIO_MUX, value); + offset = I2C_OFFSET; + } + + /* Disable I2C controller */ + value = FIELD_SET(peekRegisterByte(I2C_CTRL+offset), I2C_CTRL, EN, DISABLE); + pokeRegisterByte(I2C_CTRL+offset, value); +} + +/* + * This function waits until the transfer is completed within the timeout value. + * + * Return Value: + * 0 - Transfer is completed + * -1 - Tranfer is not successful (timeout) + */ +static long ddk768_hwI2CWaitTXDone( + unsigned char i2cNumber //I2C0 or I2C1 +) +{ + unsigned long timeout, offset; + + offset = (i2cNumber == 0)? 0 : I2C_OFFSET; + + /* Wait until the transfer is completed. */ + timeout = HWI2C_WAIT_TIMEOUT; + while ((FIELD_GET(peekRegisterByte(I2C_STATUS+offset), I2C_STATUS, TX) != I2C_STATUS_TX_COMPLETED) && + (timeout != 0)) + timeout--; + + if (timeout == 0) + return (-1); + + return 0; +} + +/* + * This function writes data to the i2c slave device registers. + * + * Parameters: + * deviceAddress - i2c Slave device address + * length - Total number of bytes to be written to the device + * pBuffer - The buffer that contains the data to be written to the + * i2c device. + * + * Return Value: + * Total number of bytes those are actually written. + */ +unsigned long hwI2CWriteData( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned long length, + unsigned char *pBuffer +) +{ + unsigned char count, i; + unsigned long offset, totalBytes = 0; + + offset = (i2cNumber == 0)? 0 : I2C_OFFSET; + + /* Set the Device Address */ + pokeRegisterByte(I2C_SLAVE_ADDRESS+offset, deviceAddress & ~0x01); + + /* Write data. + * Note: + * Only 16 byte can be accessed per i2c start instruction. + */ + do + { + /* Reset I2C by writing 0 to I2C_RESET register to clear the previous status. */ + pokeRegisterByte(I2C_RESET+offset, 0); + + /* Set the number of bytes to be written */ + if (length < MAX_HWI2C_FIFO) + count = length - 1; + else + count = MAX_HWI2C_FIFO - 1; + pokeRegisterByte(I2C_BYTE_COUNT+offset, count); + + /* Move the data to the I2C data register */ + for (i = 0; i <= count; i++) + pokeRegisterByte(I2C_DATA0 + i + offset, *pBuffer++); + + /* Start the I2C */ + pokeRegisterByte(I2C_CTRL+offset, FIELD_SET(peekRegisterByte(I2C_CTRL+offset), I2C_CTRL, CTRL, START)); + + /* Wait until the transfer is completed. */ + if (ddk768_hwI2CWaitTXDone(i2cNumber) != 0) + break; + + /* Substract length */ + length -= (count + 1); + + /* Total byte written */ + totalBytes += (count + 1); + + } while (length > 0); + + return totalBytes; +} + +/* + * This function reads data from the slave device and stores them + * in the given buffer + * + * Parameters: + * deviceAddress - i2c Slave device address + * length - Total number of bytes to be read + * pBuffer - Pointer to a buffer to be filled with the data read + * from the slave device. It has to be the same size as the + * length to make sure that it can keep all the data read. + * + * Return Value: + * Total number of actual bytes read from the slave device + */ +unsigned long hwI2CReadData( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned long length, + unsigned char *pBuffer +) +{ + unsigned char count, i; + unsigned long offset, totalBytes = 0; + + offset = (i2cNumber == 0)? 0 : I2C_OFFSET; + + /* Set the Device Address */ + pokeRegisterByte(I2C_SLAVE_ADDRESS+offset, deviceAddress | 0x01); + + /* Read data and save them to the buffer. + * Note: + * Only 16 byte can be accessed per i2c start instruction. + */ + do + { + /* Reset I2C by writing 0 to I2C_RESET register to clear all the status. */ + pokeRegisterByte(I2C_RESET+offset, 0); + + /* Set the number of bytes to be read */ + if (length <= MAX_HWI2C_FIFO) + count = length - 1; + else + count = MAX_HWI2C_FIFO - 1; + pokeRegisterByte(I2C_BYTE_COUNT+offset, count); + + /* Start the I2C */ + pokeRegisterByte(I2C_CTRL+offset, FIELD_SET(peekRegisterByte(I2C_CTRL+offset), I2C_CTRL, CTRL, START)); + + /* Wait until transaction done. */ + if (ddk768_hwI2CWaitTXDone(i2cNumber) != 0) + break; + + /* Save the data to the given buffer */ + for (i = 0; i <= count; i++) + { + *pBuffer++ = peekRegisterByte(I2C_DATA0 + i + offset); + } + + /* Substract length by 16 */ + length -= (count + 1); + + /* Number of bytes read. */ + totalBytes += (count + 1); + + } while (length > 0); + + return totalBytes; +} + +/* + * This function reads the slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be read from + * registerIndex - Slave device's register to be read + * + * Return Value: + * Register value + */ +unsigned char ddk768_hwI2CReadReg( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned char registerIndex +) +{ + unsigned char value = (0xFF); + + if (hwI2CWriteData(i2cNumber, deviceAddress, 1, ®isterIndex) == 1) + hwI2CReadData(i2cNumber, deviceAddress, 1, &value); + + return value; +} + +/* + * This function writes a value to the slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be written + * registerIndex - Slave device's register to be written + * data - Data to be written to the register + * + * Result: + * 0 - Success + * -1 - Fail + */ +long ddk768_hwI2CWriteReg( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned char registerIndex, + unsigned char data +) +{ + unsigned char value[2]; + + value[0] = registerIndex; + value[1] = data; + if (hwI2CWriteData(i2cNumber, deviceAddress, 2, value) == 2) + return 0; + + return (-1); +} + + +long ddk768_AdaptHWI2CInit(struct smi_connector *connector) +{ + int ret; + + if (connector->base.connector_type == DRM_MODE_CONNECTOR_VGA) + connector->i2cNumber = 1; + else if (connector->base.connector_type == DRM_MODE_CONNECTOR_DVII) + connector->i2cNumber = 0; + else + connector->i2cNumber = 2; // No exist. + + ddk768_hwI2CInit(connector->i2cNumber); + + connector->adapter.owner = THIS_MODULE; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 8, 0) + connector->adapter.class = I2C_CLASS_DDC; +#endif + snprintf(connector->adapter.name, I2C_NAME_SIZE, "SMI HW I2C Bus"); + connector->adapter.dev.parent = connector->base.dev->dev; + i2c_set_adapdata(&connector->adapter, connector); + connector->adapter.algo = &ddk768_i2c_algo; + ret = i2c_add_adapter(&connector->adapter); + if (ret) + { + pr_err("HW i2c add adapter failed. %d\n", ret); + return -1; + } + + return 0; +} + +long ddk768_AdaptHWI2CCleanBus(struct smi_connector *connector) +{ + ddk768_hwI2CClose(connector->i2cNumber); + return 0; +} + + + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_hwi2c.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_hwi2c.h new file mode 100644 index 000000000000..1121bb64bdbf --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_hwi2c.h @@ -0,0 +1,70 @@ +#ifndef _DDK768_HWI2C_H_ +#define _DDK768_HWI2C_H_ + + +#include "../smi_drv.h" + + +#define MAX_HWI2C_FIFO 16 +#define HWI2C_WAIT_TIMEOUT 0x7FF + +extern const struct i2c_algorithm ddk768_i2c_algo; + + +/* + * This function initializes the hardware i2c + * + * Return Value: + * 0 - Success + * -1 - Fail to initialize i2c + */ +long ddk768_hwI2CInit( + unsigned char i2cNumber //I2C0 or I2C1 +); + +/* + * This function close the hardware i2c + */ +void ddk768_hwI2CClose( + unsigned char i2cNumber //I2C0 or I2C1 +); + +/* + * This function read the i2c device register value + * + * Input: deviceAddress - I2C Device Address + * registerIndex - Register index to be read + * + * Output: + * The value of the register being read. + */ +unsigned char ddk768_hwI2CReadReg( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned char registerIndex +); + +/* + * This function writes a value to the i2c device register. + * + * Input: deviceAddress - I2C Device Address + * registerIndex - Register index to be written to + * data - Data to be written to + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk768_hwI2CWriteReg( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned char registerIndex, + unsigned char data +); + +long ddk768_AdaptHWI2CInit(struct smi_connector *connector); +long ddk768_AdaptHWI2CCleanBus(struct smi_connector *connector); + + + +#endif /* _HWI2C_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_iis.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_iis.c new file mode 100644 index 000000000000..7424c5dc3cad --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_iis.c @@ -0,0 +1,274 @@ +/******************************************************************* +* +* Copyright (c) 2014 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* This file contains the definitions for the IIS functions. +* +*******************************************************************/ + + +#include "ddk768_reg.h" +#include "ddk768_iis.h" +#include "ddk768_help.h" +#include "ddk768_power.h" +#include "ddk768_chip.h" + + +/* + * Set up I2S and GPIO registers to transmit/receive data. + */ +void iisOpen( + unsigned long wordLength, //Number of bits in IIS data: 16 bit, 24 bit, 32 bit + unsigned long sampleRate //Sampling rate. +) +{ + unsigned long value, clockDivider, iisRefClk; + unsigned char ws; + + ddk768_enableI2S(1); //Turn on I2S clock + + /* Configure GPIO Mux for I2s output */ + value = peekRegisterDWord(GPIO_MUX); + value |= (1 << GPIO_MUX_IIS_RX_SHIFT); // I2S Data Input + value &= ~(1 << GPIO_MUX_GPIO_IIS_TX_SHIFT); // I2S Tx Output + value &= ~(1 << GPIO_MUX_GPIO_IIS_WS_SHIFT); // I2S Word Select + value &= ~(1 << GPIO_MUX_GPIO_IIS_CLK_SHIFT); // I2S Clock Out + value |= (1 << GPIO_MUX_IIS_TX_SELECT_SHIFT); + value |= (1 << GPIO_MUX_IIS_WS_SELECT_SHIFT); + value |= (1 << GPIO_MUX_IIS_CLK_SELECT_SHIFT); + pokeRegisterDWord(GPIO_MUX, value); + + /* Make sure GPIO data direction (0x10004) bit 28 = 0 (input) */ + value = peekRegisterDWord(GPIO_DATA_DIRECTION); + value &= ~(1 << GPIO_DATA_DIRECTION_IIS_RX_SHIFT); + pokeRegisterDWord(GPIO_DATA_DIRECTION, value); + + /* IIS register set up */ + pokeRegisterDWord(I2S_TX_DATA_L, 0); //Clear Tx registers + pokeRegisterDWord(I2S_TX_DATA_R, 0); + + //Figure out Word Select value + switch (wordLength) + { + case 32: + ws = 2; + break; + case 24: + ws = 1; + break; + default: + ws = 0; + } + + /* Calculate IIS_REF_CLOCK.*/ + value = FIELD_GET(peekRegisterDWord(USBH_CLOCK), USBH_CLOCK, FS_IIS); + + if (ddk768_getCrystalType()) + iisRefClk = 24576000 * value / 8; + else + iisRefClk = 24000000 * value / 8; + + clockDivider = (iisRefClk / (4 * sampleRate * wordLength)) - 1; + + pokeRegisterDWord(I2S_CTRL, + FIELD_VALUE(0, I2S_CTRL, CS, ws) + | FIELD_VALUE(0, I2S_CTRL , CDIV, clockDivider)); + + pokeRegisterDWord(I2S_SRAM_DMA, 0); //Default no DMA. Call another function to set up DMA +} + + +/* + * Turn off I2S and close GPIO + */ +void iisClose() +{ + unsigned long value; + + /* Close GPIO Mux for I2s output Clear bit 28 and 4:2*/ + value = peekRegisterDWord(GPIO_MUX); + value &= ~(1 << GPIO_MUX_IIS_RX_SHIFT); + value &= ~(1 << GPIO_MUX_IIS_TX_SELECT_SHIFT); + value &= ~(1 << GPIO_MUX_IIS_WS_SELECT_SHIFT); + value &= ~(1 << GPIO_MUX_IIS_CLK_SELECT_SHIFT); + pokeRegisterDWord(GPIO_MUX, value); + + pokeRegisterDWord(I2S_TX_DATA_L, 0); //Clear Tx registers + pokeRegisterDWord(I2S_TX_DATA_R, 0); + pokeRegisterDWord(I2S_STATUS, 0); //Disable Tx line out + pokeRegisterDWord(I2S_CTRL, 0); //Clear clock setting. + pokeRegisterDWord(I2S_SRAM_DMA, 0); //Clear DMA setting. + +} + + + + +/* + * This function set up I2S to DMA data from SRAM. + * + * SRAM area has max size of 2048 bytes (or 512 DWords). + * Max size of each I2S DMA session is 256 DWords. + * + * Inputs: + * offset address in SRAM to start DMA (DWord aligned) + * Number of bytes to DMA (DWord aligned) + */ +void iisTxDmaSetup( + unsigned long offset, /* Offset from start of SRAM to start DMA */ + unsigned long len /* Number of bytes to DMA */ + ) +{ + unsigned long dmaPointer; + + offset >>= 2; //I2S DMA register requires offset to be expressed in DWord + len >>= 2; + len--; //I2S DMA register requires length to be expressed as DWord - 1. + + dmaPointer = FIELD_GET(peekRegisterDWord(I2S_SRAM_DMA), I2S_SRAM_DMA, ADDRESS); + + //If DMA pointer already at the requested offset. Just set up the length. + if (dmaPointer == offset) + { + pokeRegisterDWord(I2S_SRAM_DMA, + FIELD_SET(0, I2S_SRAM_DMA, STATE, ENABLE) + | FIELD_VALUE(0, I2S_SRAM_DMA, SIZE, len) + | FIELD_VALUE(0, I2S_SRAM_DMA, ADDRESS, offset)); + + return; + } + + //Position DMA pointer to the new base pointer (or offset). + //Note that DMA reload base pointer only when it gets to end of SRAM. + //Therefore, we need to advance DMA from current position to the end. + pokeRegisterDWord(I2S_SRAM_DMA, + FIELD_SET(0, I2S_SRAM_DMA, STATE, ENABLE) + | FIELD_VALUE(0, I2S_SRAM_DMA, SIZE, (0x1FF - dmaPointer)) + | FIELD_VALUE(0, I2S_SRAM_DMA, ADDRESS, dmaPointer)); + + iisStartNoTx();//Start DMA without output the old data from Tx line. + + //Once DMA starts, make the new base pointer ready. + pokeRegisterDWord(I2S_SRAM_DMA, + FIELD_SET(0, I2S_SRAM_DMA, STATE, ENABLE) + | FIELD_VALUE(0, I2S_SRAM_DMA, SIZE, len) + | FIELD_VALUE(0, I2S_SRAM_DMA, ADDRESS, offset)); + + // When DMA get to the end of SRAM, it loads the new base pointer. + do + { + dmaPointer = FIELD_GET(peekRegisterDWord(I2S_SRAM_DMA), I2S_SRAM_DMA, ADDRESS); + } while(dmaPointer != offset); + + iisStop(); +} + +/* + * Return current IIS DMA position. + */ +unsigned long iisDmaPointer(void) +{ + return(FIELD_GET(peekRegisterDWord(I2S_SRAM_DMA), I2S_SRAM_DMA, ADDRESS)); +} + +/* + * This function start IIS without enabling Tx line. + * It can be used to flush left over SRAM data without + * sending them to Codec. + */ +void iisStartNoTx(void) +{ + unsigned long value; + + value = FIELD_SET(peekRegisterDWord(I2S_CTRL), I2S_CTRL, MODE, MASTER); + pokeRegisterDWord(I2S_CTRL, value); +} + + +/* + * This function is needed only when I2S is intended to operate in master mode. + * + * For slave mode, just use iisOpen() is enough, because I2S will start + * functioning as soon as an external clock is detected after iisOpen(). + * + */ + +void iisStart(void) +{ + unsigned long value; + + pokeRegisterDWord(I2S_STATUS, FIELD_SET(0, I2S_STATUS, TX, ENABLE)); //Enable Tx line out + + value = FIELD_SET(peekRegisterDWord(I2S_CTRL), I2S_CTRL, MODE, MASTER); + pokeRegisterDWord(I2S_CTRL, value); + +} + +/* + * This function is useful only when I2S is operating in master mode. + * + * For slave mode, clock is external and cannot be stopped by IIS + * control register. + * + */ +void iisStop(void) +{ + unsigned long value; + + value = FIELD_SET(peekRegisterDWord(I2S_CTRL), I2S_CTRL, MODE, SLAVE); + pokeRegisterDWord(I2S_CTRL, value); + + pokeRegisterDWord(I2S_STATUS, FIELD_SET(0, I2S_STATUS, TX, DISABLE)); //Disable Tx line out + +} + + +/* + * Set values for left Tx and right Tx register. + */ +void iisSetTx( + unsigned long left, //Data for left channel Tx + unsigned long right //Data for right channel Tx + ) +{ + pokeRegisterDWord(I2S_TX_DATA_L, left); + pokeRegisterDWord(I2S_TX_DATA_R, right); +} + + + +/* + * This function clears the RAW interrupt status of I2S. + * + * When I2S completes sending data, the raw interrupt bit will be set. + * It has to be cleared, in order to distinguish between different sessions of countdown. + * + */ +void iisClearRawInt(void) +{ + /* Read I2S Control & TX to clear INT when IIS get data from Tx & Rx. */ + peekRegisterDWord(I2S_STATUS); + + /* Write 0 to I2S SRAM DMA status when IIS get data from SRAM */ + pokeRegisterDWord(I2S_SRAM_DMA_STATUS, 0); + +} + + +/* + * This function returns the INT mask for IIS. + * + */ +unsigned long iisIntMask(void) +{ + unsigned long mask = 0; + + mask |= FIELD_SET(0, INT_MASK, I2S, ENABLE); + + return mask; +} + + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_iis.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_iis.h new file mode 100644 index 000000000000..230a7cb0ab8d --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_iis.h @@ -0,0 +1,109 @@ +/******************************************************************* +* +* Copyright (c) 2014 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* This file contains the definitions for the IIS functions. +* +*******************************************************************/ +#ifndef _IIS_H_ +#define _IIS_H_ + + +#define IIS_REF_CLOCK 48000000 + + +/* + * Set up I2S and GPIO registers to transmit/receive data. + */ +void iisOpen( + unsigned long wordLength, //Number of bits in IIS data: 16 bit, 24 bit, 32 bit + unsigned long sampleRate //Sampling rate. +); + +/* + * Turn off I2S and close GPIO + */ +void iisClose(void); + +/* + * This function set up I2S to DMA data from SRAM. + * + * SRAM area has max size of 2048 bytes (or 512 DWords). + * Max size of each I2S DMA session is 256 DWords. + * + * Inputs: + * offset address in SRAM to start DMA (DWord aligned) + * Number of bytes to DMA (DWord aligned) + */ +void iisTxDmaSetup( + unsigned long offset, /* Offset from start of SRAM area */ + unsigned long len /* Number of bytes to DMA */ + ); + +/* + * Return current IIS DMA position. + */ +unsigned long iisDmaPointer(void); + +/* + * This function start IIS without enabling Tx line. + * It can be used to flush left over SRAM data without + * sending them to Codec. + */ +void iisStartNoTx(void); + +/* + * This function is needed only when I2S is intended to operate in master mode. + * + * For slave mode, just use iisOpen() is enough, because I2S will start + * functioning as soon as an external clock is detected after iisOpen(). + * + */ +void iisStart(void); + +/* + * This function is useful only when I2S is operating in master mode. + * + * For slave mode, clock is external and cannot be stopped by IIS + * control register. + * + */ +void iisStop(void); + +/* + * Set values for left Tx and right Tx register. + */ +void iisSetTx( + unsigned long left, //Data for left channel Tx + unsigned long right //Data for right channel Tx + ); + +/* + * This function clears the RAW interrupt status of I2S. + * + * When I2S completes sending data, the raw interrupt bit will be set. + * It has to be cleared, in order to distinguish between different sessions of countdown. + * + */ +void iisClearRawInt(void); + +/* + * This function returns the INT mask for IIS. + * + */ +unsigned long iisIntMask(void); + +/* + * This is a reference sample showing how to implement ISR for I2S. + * It works wiht libsrc\intr.c together. + * + * Refer to Apps\iis\tstiis.c on how to hook up this function with system + * interrupt under WATCOM DOS extender. + * + */ + + +#endif /* _IIS_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_intr.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_intr.c new file mode 100644 index 000000000000..16ad93c7e838 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_intr.c @@ -0,0 +1,62 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* intr.c --- SM750/SM718 DDK +* This file contains the source code for the interrupt management. +* +*******************************************************************/ + +#include "ddk768_reg.h" +#include "ddk768_chip.h" +#include "ddk768_intr.h" +#include "ddk768_help.h" + + +/* + * Change interrupt mask + */ +void setIntMask( + unsigned long mask_on, + unsigned long mask_off +) +{ + unsigned long mask; + + /* Get current interrupt mask */ + mask = peekRegisterDWord(INT_MASK); + + /* Enable new masks and disable old masks */ + mask = mask | mask_on; + mask = mask & ~mask_off; + + /* Program new interrupt mask */ + pokeRegisterDWord(INT_MASK, mask); +} + + +void sb_IRQMask(int irq_num) +{ + unsigned int mask; + mask = peekRegisterDWord(INT_MASK); + mask &= ~(0x1< + + +#include "ddk768_reg.h" + +#include "ddk768_chip.h" +#include "ddk768_clock.h" +#include "ddk768_power.h" +#include "ddk768_mode.h" + +#include "ddk768_help.h" + +extern int lvds_channel; + +extern int clk_phase; + + +/* The valid signature of the user data pointer for the setmode function. + The following definition is ASCII representation of the word 'USER' + */ +#define MODE_USER_DATA_SIGNATURE 0x55534552 + +/* + * Default Timing parameter for some popular modes. + * Note that the most timings in this table is made according to standard VESA + * parameters for the popular modes. + */ +static mode_parameter_t gDefaultModeParamTable[] = +{ +/* 640 x 480 [4:3] */ +/* The first 2 commented lines below are taken from SM502, the rest timing are + taken from the VESA Monitor Timing Standard */ +/* { 840, 640, 680, 64, NEG, 500, 480, 481, 3, NEG, 31500000, 37500, 75, NEG}, */ +/* { 832, 640, 700, 56, NEG, 509, 480, 481, 3, NEG, 36000000, 43269, 85, NEG}, */ + { 800, 640, 656, 96, NEG, 525, 480, 490, 2, NEG, 25175000, 31469, 60, NEG}, + { 840, 640, 656, 64, NEG, 500, 480, 481, 3, NEG, 31500000, 37500, 75, NEG}, + { 832, 640, 696, 56, NEG, 509, 480, 481, 3, NEG, 36000000, 43269, 85, NEG}, + +/* 720 x 480 [3:2] */ + { 889, 720, 738,108, POS, 525, 480, 490, 2, NEG, 28000000, 31496, 60, NEG}, + +/* 720 x 540 [4:3] -- Not a popular mode */ + { 886, 720, 740, 96, POS, 576, 540, 545, 2, POS, 30600000, 34537, 60, NEG}, + +/*720 x 576 [5:4] -- Not a popular mode*/ + { 912, 720, 744, 96, POS, 597, 576, 580, 1, NEG, 32670000, 35820, 60, POS}, + +/* 800 x 480 [5:3] -- Not a popular mode */ + { 973, 800, 822, 56, POS, 524, 480, 490, 2, NEG, 30600000, 31449, 60, NEG}, + +/* 800 x 600 [4:3] */ +/* The first 2 commented lines below are taken from SM502, the rest timing are + taken from the VESA Monitor Timing Standard */ +/* {1062, 800, 840,128, POS, 628, 600, 601, 4, POS, 40000000, 37665, 60, NEG}, */ +/* {1054, 800, 842, 64, POS, 625, 600, 601, 3, POS, 56000000, 53131, 85, NEG}, */ + {1056, 800, 840,128, POS, 628, 600, 601, 4, POS, 40000000, 37879, 60, NEG}, + {1056, 800, 816, 80, POS, 625, 600, 601, 3, POS, 49500000, 46875, 75, NEG}, + {1048, 800, 832, 64, POS, 631, 600, 601, 3, POS, 56250000, 53674, 85, NEG}, + +/* 960 x 720 [4:3] -- Not a popular mode */ + {1245, 960, 992, 64, POS, 750, 720, 721, 3, POS, 56000000, 44980, 60, NEG}, + +/* 1024 x 600 [16:9] 1.7 */ + {1313,1024,1064,104, POS, 622, 600, 601, 3, POS, 49000000, 37319, 60, NEG}, + +/* 1024 x 768 [4:3] */ +/* The first 2 commented lines below are taken from SM502, the rest timing are + taken from the VESA Monitor Timing Standard */ +/* {1340,1024,1060,136, NEG, 809, 768, 772, 6, NEG, 65000000, 48507, 60, NEG}, */ +/* {1337,1024,1072, 96, NEG, 808, 768, 780, 3, NEG, 81000000, 60583, 75, NEG}, */ + {1344,1024,1048,136, NEG, 806, 768, 771, 6, NEG, 65000000, 48363, 60, NEG}, + {1312,1024,1040, 96, POS, 800, 768, 769, 3, POS, 78750000, 60023, 75, NEG}, + {1376,1024,1072, 96, POS, 808, 768, 769, 3, POS, 94500000, 68677, 85, NEG}, + +/* 1152 x 864 [4:3] -- Widescreen eXtended Graphics Array */ +/* {1475,1152,1208, 96, NEG, 888, 864, 866, 3, NEG, 78600000, 53288, 60, NEG},*/ + {1475,1152,1208, 96, POS, 888, 864, 866, 3, POS, 78600000, 53288, 60, NEG}, + {1600,1152,1216,128, POS, 900, 864, 865, 3, POS,108000000, 67500, 75, NEG}, + +/* 1280 x 720 [16:9] -- HDTV (WXGA) */ + {1664,1280,1336,136, POS, 746, 720, 721, 3, POS, 74481000, 44760, 60, NEG}, + +/* 1280 x 768 [5:3] -- Not a popular mode */ + {1678,1280,1350,136, POS, 795, 768, 769, 3, POS, 80000000, 47676, 60, NEG}, + +/* 1280 x 800 [8:5] -- Not a popular mode */ + {1650,1280,1344,136, NEG, 824, 800, 800, 3, NEG, 81600000, 49455, 60, NEG}, + +/* 1280 x 960 [4:3] */ +/* The first commented line below are taken from SM502, the rest timing are + taken from the VESA Monitor Timing Standard */ +/* {1618,1280,1330, 96, NEG, 977, 960, 960, 2, NEG, 94500000, 59259, 60, NEG},*/ + {1800,1280,1376,112, POS,1000, 960, 961, 3, POS,108000000, 60000, 60, NEG}, + {1728,1280,1344,160, POS,1011, 960, 961, 3, POS,148500000, 85938, 85, NEG}, + +/* 1280 x 1024 [5:4] */ +#if 1 + /* GTF with C = 40, M = 600, J = 20, K = 128 */ + {1712,1280,1360,136, NEG,1060,1024,1025, 3, POS,108883200, 63600, 60, NEG}, + {1728,1280,1368,136, NEG,1069,1024,1025, 3, POS,138542400, 80175, 75, NEG}, + {1744,1280,1376,136, NEG,1075,1024,1025, 3, POS,159358000, 91375, 85, NEG}, +#else + /* VESA Standard */ + {1688,1280,1328,112, POS,1066,1024,1025, 3, POS,108000000, 63981, 60, NEG}, + {1688,1280,1296,144, POS,1066,1024,1025, 3, POS,135000000, 79976, 75, NEG}, + {1728,1280,1344,160, POS,1072,1024,1025, 3, POS,157500000, 91146, 85, NEG}, +#endif + +/* 1360 x 768 [16:9] */ +#if 1 + /* GTF with C = 40, M = 600, J = 20, K = 128 */ + //{1776,1360,1432,136, NEG, 795, 768, 769, 3, POS, 84715200, 47700, 60, NEG}, + + /* GTF with C = 30, M = 600, J = 20, K = 128 */ + {1664,1360,1384,128, NEG, 795, 768, 769, 3, POS, 79372800, 47700, 60, NEG}, +#else + /* Previous Calculation */ + {1776,1360,1424,144, POS, 795, 768, 769, 3, POS, 84715000, 47700, 60, NEG}, +#endif + +/* 1366 x 768 [16:9] */ + /* Previous Calculation */ + {1722,1366,1424,112, NEG, 784, 768, 769, 3, NEG, 81000000, 47038, 60, NEG}, + +/* 1400 x 1050 [4:3] -- Hitachi TX38D95VC1CAH -- It is not verified yet, therefore + temporarily disabled. */ + //{1688,1400,1448,112, NEG,1068,1050,1051, 3, NEG,108000000, 64000, 60, NEG}, + //{1688,1400,1464,112, NEG,1068,1050,1051, 3, NEG,108167040, 64080, 60, NEG}, + + /* Taken from the www.tinyvga.com */ + {1880,1400,1488,152, NEG,1087,1050,1051, 3, POS,122610000, 65218, 60, NEG}, + +/* 1440 x 900 [8:5] -- Widescreen Super eXtended Graphics Array (WSXGA) */ + {1904,1440,1520,152, NEG, 932, 900, 901, 3, POS,106470000, 55919, 60, NEG}, + +/* 1440 x 960 [3:2] -- Not a popular mode */ + {1920,1440,1528,152, POS, 994, 960, 961, 3, POS,114509000, 59640, 60, NEG}, + +/* 1600 x 900 */ +{2128,1600,1664,192, POS,932,900,901, 3, POS,119000000, 56000, 60, NEG}, + + +/* 1600 x 1200 [4:3]. -- Ultra eXtended Graphics Array */ + /* VESA */ + {2160,1600,1664,192, POS,1250,1200,1201, 3, POS,162000000, 75000, 60, POS}, + {2160,1600,1664,192, POS,1250,1200,1201, 3, POS,202500000, 93750, 75, POS}, + {2160,1600,1664,192, POS,1250,1200,1201, 3, POS,229500000,106250, 85, POS}, + +/* + * The timing below is taken from the www.tinyvga.com/vga-timing. + * With the exception of 1920x1080. + */ + +/* 1680 x 1050 [8:5]. -- Widescreen Super eXtended Graphics Array Plus (WSXGA+) */ +/* The first commented timing might be used for DVI LCD Monitor timing. */ +/* {1840,1680,1728, 32, NEG,1080,1050,1053, 6, POS,119232000, 64800, 60, NEG}, */ + /* GTF with C = 30, M = 600, J = 20, K = 128 */ + {2256,1680,1784,184, NEG,1087,1050,1051, 3, POS,147140000, 65222, 60, POS}, +/* + {2272,1680,1792,184, NEG,1093,1050,1051, 3, POS,173831000, 76510, 70, NEG}, + {2288,1680,1800,184, NEG,1096,1050,1051, 3, POS,188074000, 82200, 75, NEG}, +*/ + +/* 1792 x 1344 [4:3]. -- Not a popular mode */ + {2448,1792,1920,200, NEG,1394,1344,1345, 3, POS,204800000, 83660, 60, NEG}, + {2456,1792,1888,216, NEG,1417,1344,1345, 3, POS,261000000,106270, 75, NEG}, + +/* 1856 x 1392 [4:3]. -- Not a popular mode + The 1856 x 1392 @ 75Hz has not been tested due to high Horizontal Frequency + where not all monitor can support it (including the developer monitor) + */ + {2528,1856,1952,224, NEG,1439,1392,1393, 3, POS,218300000, 86353, 60, NEG}, +/* {2560,1856,1984,224, NEG,1500,1392,1393, 3, POS,288000000,112500, 75, NEG},*/ + +/* 1920 x 1080 [16:9]. */ + +{2200,1920,2008, 44, POS,1125,1080,1084, 5, POS,148500000, 67500, 60, POS}, //Adjusted + +/* 1920 x 1200 [8:5]. -- Widescreen Ultra eXtended Graphics Array (WUXGA) */ + {2592,1920,2048,208, NEG,1242,1200,1201, 3, POS,193160000, 74522, 60, NEG}, + +/* 1920 x 1440 [4:3]. */ +/* In the databook, it mentioned only support up to 1920x1440 @ 60Hz. + The timing for 75 Hz is provided here if necessary to do testing. - Some underflow + has been noticed. */ + {2600,1920,2048,208, NEG,1500,1440,1441, 3, POS,234000000, 90000, 60, NEG}, +/* {2640,1920,2064,224, NEG,1500,1440,1441, 3, POS,297000000,112500, 75, NEG}, */ + +/* 2560x1440 [16:9]. */ +/* 2K mode */ + {2720,2560,2608,32, POS,1481,1440,1443, 5, NEG,241500000, 88000, 60, NEG}, + +/* 3840 x 2160 (UHD) */ + {4400,3840,4016,88, POS,2250,2160,2168, 10, POS,297000000, 67500, 30, POS}, //Adjusted + + +/* End of table. */ + { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, +}; + +/* + * Default Timing parameter for some popular modes. + * Note that the most timings in this table is made according to standard VESA + * parameters for the popular modes. + */ +static mode_parameter_t gLVDSModeParamTable[] = +{ +/* 640 x 480 [4:3] */ +/* The first 2 commented lines below are taken from SM502, the rest timing are + taken from the VESA Monitor Timing Standard */ +/* { 840, 640, 680, 64, NEG, 500, 480, 481, 3, NEG, 31500000, 37500, 75, NEG}, */ +/* { 832, 640, 700, 56, NEG, 509, 480, 481, 3, NEG, 36000000, 43269, 85, NEG}, */ + { 800, 640, 656, 96, NEG, 525, 480, 490, 2, NEG, 25175000, 31469, 60, NEG}, + { 840, 640, 656, 64, NEG, 500, 480, 481, 3, NEG, 31500000, 37500, 75, NEG}, + { 832, 640, 696, 56, NEG, 509, 480, 481, 3, NEG, 36000000, 43269, 85, NEG}, + +/* 720 x 480 [3:2] */ + { 889, 720, 738,108, POS, 525, 480, 490, 2, NEG, 28000000, 31496, 60, NEG}, + +/* 720 x 540 [4:3] -- Not a popular mode */ + { 886, 720, 740, 96, POS, 576, 540, 545, 2, POS, 30600000, 34537, 60, NEG}, + +/*720 x 576 [5:4] -- Not a popular mode*/ + { 912, 720, 744, 96, POS, 597, 576, 580, 1, NEG, 32670000, 35820, 60, POS}, + +/* 800 x 480 [5:3] -- Not a popular mode */ + { 973, 800, 822, 56, POS, 524, 480, 490, 2, NEG, 30600000, 31449, 60, NEG}, + +/* 800 x 600 [4:3] */ +/* The first 2 commented lines below are taken from SM502, the rest timing are + taken from the VESA Monitor Timing Standard */ +/* {1062, 800, 840,128, POS, 628, 600, 601, 4, POS, 40000000, 37665, 60, NEG}, */ +/* {1054, 800, 842, 64, POS, 625, 600, 601, 3, POS, 56000000, 53131, 85, NEG}, */ + {1056, 800, 840,128, POS, 628, 600, 601, 4, POS, 40000000, 37879, 60, NEG}, + {1056, 800, 816, 80, POS, 625, 600, 601, 3, POS, 49500000, 46875, 75, NEG}, + {1048, 800, 832, 64, POS, 631, 600, 601, 3, POS, 56250000, 53674, 85, NEG}, + +/* 960 x 720 [4:3] -- Not a popular mode */ + {1245, 960, 992, 64, POS, 750, 720, 721, 3, POS, 56000000, 44980, 60, NEG}, + +/* 1024 x 600 [16:9] 1.7 */ + {1313,1024,1064,104, POS, 622, 600, 601, 3, POS, 49000000, 37319, 60, NEG}, + +/* 1024 x 768 [4:3] */ +/* The first 2 commented lines below are taken from SM502, the rest timing are + taken from the VESA Monitor Timing Standard */ +/* {1340,1024,1060,136, NEG, 809, 768, 772, 6, NEG, 65000000, 48507, 60, NEG}, */ +/* {1337,1024,1072, 96, NEG, 808, 768, 780, 3, NEG, 81000000, 60583, 75, NEG}, */ + {1344,1024,1048,136, NEG, 806, 768, 771, 6, NEG, 65000000, 48363, 60, NEG}, + {1312,1024,1040, 96, POS, 800, 768, 769, 3, POS, 78750000, 60023, 75, NEG}, + {1376,1024,1072, 96, POS, 808, 768, 769, 3, POS, 94500000, 68677, 85, NEG}, + +/* 1152 x 864 [4:3] -- Widescreen eXtended Graphics Array */ +/* {1475,1152,1208, 96, NEG, 888, 864, 866, 3, NEG, 78600000, 53288, 60, NEG},*/ + {1475,1152,1208, 96, POS, 888, 864, 866, 3, POS, 78600000, 53288, 60, NEG}, + {1600,1152,1216,128, POS, 900, 864, 865, 3, POS,108000000, 67500, 75, NEG}, + +/* 1280 x 720 [16:9] -- HDTV (WXGA) */ + {1664,1280,1336,136, POS, 746, 720, 721, 3, POS, 74481000, 44760, 60, NEG}, + +/* 1280 x 768 [5:3] -- Not a popular mode */ + {1678,1280,1350,136, POS, 795, 768, 769, 3, POS, 80000000, 47676, 60, NEG}, + +/* 1280 x 800 [8:5] -- Not a popular mode */ + {1650,1280,1344,136, NEG, 824, 800, 800, 3, NEG, 81600000, 49455, 60, NEG}, + +/* 1280 x 960 [4:3] */ +/* The first commented line below are taken from SM502, the rest timing are + taken from the VESA Monitor Timing Standard */ +/* {1618,1280,1330, 96, NEG, 977, 960, 960, 2, NEG, 94500000, 59259, 60, NEG},*/ + {1800,1280,1376,112, POS,1000, 960, 961, 3, POS,108000000, 60000, 60, NEG}, + {1728,1280,1344,160, POS,1011, 960, 961, 3, POS,148500000, 85938, 85, NEG}, + +/* 1280 x 1024 [5:4] */ +#if 1 + /* GTF with C = 40, M = 600, J = 20, K = 128 */ + {1712,1280,1360,136, NEG,1060,1024,1025, 3, POS,108883200, 63600, 60, NEG}, + {1728,1280,1368,136, NEG,1069,1024,1025, 3, POS,138542400, 80175, 75, NEG}, + {1744,1280,1376,136, NEG,1075,1024,1025, 3, POS,159358000, 91375, 85, NEG}, +#else + /* VESA Standard */ + {1688,1280,1328,112, POS,1066,1024,1025, 3, POS,108000000, 63981, 60, NEG}, + {1688,1280,1296,144, POS,1066,1024,1025, 3, POS,135000000, 79976, 75, NEG}, + {1728,1280,1344,160, POS,1072,1024,1025, 3, POS,157500000, 91146, 85, NEG}, +#endif + +/* 1360 x 768 [16:9] */ +#if 1 + /* GTF with C = 40, M = 600, J = 20, K = 128 */ + //{1776,1360,1432,136, NEG, 795, 768, 769, 3, POS, 84715200, 47700, 60, NEG}, + + /* GTF with C = 30, M = 600, J = 20, K = 128 */ + {1664,1360,1384,128, NEG, 795, 768, 769, 3, POS, 79372800, 47700, 60, NEG}, +#else + /* Previous Calculation */ + {1776,1360,1424,144, POS, 795, 768, 769, 3, POS, 84715000, 47700, 60, NEG}, +#endif + +/* 1366 x 768 [16:9] */ + /* Previous Calculation */ + {1722,1366,1424,112, NEG, 784, 768, 769, 3, NEG, 81000000, 47038, 60, NEG}, + +/* 1400 x 1050 [4:3] -- Hitachi TX38D95VC1CAH -- It is not verified yet, therefore + temporarily disabled. */ + //{1688,1400,1448,112, NEG,1068,1050,1051, 3, NEG,108000000, 64000, 60, NEG}, + //{1688,1400,1464,112, NEG,1068,1050,1051, 3, NEG,108167040, 64080, 60, NEG}, + + /* Taken from the www.tinyvga.com */ + {1880,1400,1488,152, NEG,1087,1050,1051, 3, POS,122610000, 65218, 60, NEG}, + +/* 1440 x 900 [8:5] -- Widescreen Super eXtended Graphics Array (WSXGA) */ + {1904,1440,1520,152, NEG, 932, 900, 901, 3, POS,106470000, 55919, 60, NEG}, + +/* 1440 x 960 [3:2] -- Not a popular mode */ + {1920,1440,1528,152, POS, 994, 960, 961, 3, POS,114509000, 59640, 60, NEG}, + +/* 1600 x 900 */ +{2128,1600,1664,192, POS,932,900,901, 3, POS,119000000, 56000, 60, NEG}, + + +/* 1600 x 1200 [4:3]. -- Ultra eXtended Graphics Array */ + /* VESA */ + {2160,1600,1664,192, POS,1250,1200,1201, 3, POS,162000000, 75000, 60, POS}, + {2160,1600,1664,192, POS,1250,1200,1201, 3, POS,202500000, 93750, 75, POS}, + {2160,1600,1664,192, POS,1250,1200,1201, 3, POS,229500000,106250, 85, POS}, + +/* + * The timing below is taken from the www.tinyvga.com/vga-timing. + * With the exception of 1920x1080. + */ + +/* 1680 x 1050 [8:5]. -- Widescreen Super eXtended Graphics Array Plus (WSXGA+) */ +/* The first commented timing might be used for DVI LCD Monitor timing. */ +/* {1840,1680,1728, 32, NEG,1080,1050,1053, 6, POS,119232000, 64800, 60, NEG}, */ + /* GTF with C = 30, M = 600, J = 20, K = 128 */ + {2256,1680,1784,184, NEG,1087,1050,1051, 3, POS,147140000, 65222, 60, POS}, +/* + {2272,1680,1792,184, NEG,1093,1050,1051, 3, POS,173831000, 76510, 70, NEG}, + {2288,1680,1800,184, NEG,1096,1050,1051, 3, POS,188074000, 82200, 75, NEG}, +*/ + +/* 1792 x 1344 [4:3]. -- Not a popular mode */ + {2448,1792,1920,200, NEG,1394,1344,1345, 3, POS,204800000, 83660, 60, NEG}, + {2456,1792,1888,216, NEG,1417,1344,1345, 3, POS,261000000,106270, 75, NEG}, + +/* 1856 x 1392 [4:3]. -- Not a popular mode + The 1856 x 1392 @ 75Hz has not been tested due to high Horizontal Frequency + where not all monitor can support it (including the developer monitor) + */ + {2528,1856,1952,224, NEG,1439,1392,1393, 3, POS,218300000, 86353, 60, NEG}, +/* {2560,1856,1984,224, NEG,1500,1392,1393, 3, POS,288000000,112500, 75, NEG},*/ + +/* 1920 x 1080 [16:9]. This is a make-up value, need to be proven. + The Pixel clock is calculated based on the maximum resolution of + "Single Link" DVI, which support a maximum 165MHz pixel clock. + The second values are taken from: + http://www.tek.com/Measurement/App_Notes/25_14700/eng/25W_14700_3.pdf + */ +/* {2560,1920,2048,208, NEG,1125,1080,1081, 3, POS,172800000, 67500, 60, NEG}, */ + {2200,1920,2008, 44, NEG,1125,1080,1081, 3, POS,148500000, 67500, 60, POS}, + +/* 1920 x 1200 [8:5]. -- Widescreen Ultra eXtended Graphics Array (WUXGA) */ + {2592,1920,2048,208, NEG,1242,1200,1201, 3, POS,193160000, 74522, 60, NEG}, + +/* 1920 x 1440 [4:3]. */ +/* In the databook, it mentioned only support up to 1920x1440 @ 60Hz. + The timing for 75 Hz is provided here if necessary to do testing. - Some underflow + has been noticed. */ + {2600,1920,2048,208, NEG,1500,1440,1441, 3, POS,234000000, 90000, 60, NEG}, +/* {2640,1920,2064,224, NEG,1500,1440,1441, 3, POS,297000000,112500, 75, NEG}, */ + +/* 2560x1440 [16:9]. */ +/* 2K mode */ + {2720,2560,2608,32, POS,1481,1440,1443, 5, NEG,241500000, 88000, 60, NEG}, + +/* 3840 x 2160 (UHD) */ + {4400,3840,4016,88, POS,2250,2160,2168, 10, POS,297000000, 67500, 30, NEG}, + + +/* End of table. */ + { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, +}; + + +static mode_parameter_t gChannel0ModeParamTable[MAX_MODE_TABLE_ENTRIES] = +{ + /* End of table */ + { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, +}; + +static mode_parameter_t gChannel1ModeParamTable[MAX_MODE_TABLE_ENTRIES] = +{ + /* End of table */ + { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, +}; + +/* Static variable to store the mode information. */ +static mode_parameter_t gChannel0CurrentModeParam; +static mode_parameter_t gChannel1CurrentModeParam; + + +void debug_mode_param(mode_parameter_t *modeParam) +{ + printk(KERN_INFO "%lu %lu %lu %lu %s %lu %lu %lu %lu %s %lu %lu %lu %s\n", + modeParam->horizontal_total, modeParam->horizontal_display_end, + modeParam->horizontal_sync_start, modeParam->horizontal_sync_width, + modeParam->horizontal_sync_polarity == POS ? "POS" : "NEG", + modeParam->vertical_total, modeParam->vertical_display_end, + modeParam->vertical_sync_start, modeParam->vertical_sync_height, + modeParam->vertical_sync_polarity == POS ? "POS" : "NEG", + modeParam->pixel_clock, modeParam->horizontal_frequency, + modeParam->vertical_frequency, + modeParam->clock_phase_polarity == POS ? "POS" : "NEG"); +} + + + +/* + * ddk768_getUserDataSignature + * This function gets the user data mode signature + * + * Output: + * The signature to be filled in the user_data_mode_t structure to be considered + * a valid structure. + */ +unsigned long ddk768_getUserDataSignature() +{ + return MODE_USER_DATA_SIGNATURE; +} + +/* + * compareModeParam + * This function compares two mode parameters + * + * Input: + * pModeParam1 - Pointer to the first mode parameter to be compared + * pModeParam2 - Pointer to the second mode parameter to be compared + * + * Output: + * 0 - Identical mode + * -1 - Mode is not identical + */ +long compareModeParam( + mode_parameter_t *pModeParam1, + mode_parameter_t *pModeParam2 +) +{ + if ((pModeParam1 != (mode_parameter_t *)0) && + (pModeParam2 != (mode_parameter_t *)0)) + { + if (memcmp((void *)pModeParam1, (void *)pModeParam2, sizeof(mode_parameter_t)) == 0) + return 0; + } + + return (-1); +} + +/* + * getDuplicateModeIndex + * This function retrieves the index of dupicate modes, but having different timing. + * + * Input: + * dispCtrl - Display Control where the mode table belongs to. + * pModeParam - The mode parameters which index to be checked. + * + * Output: + * The index of the given parameters among the duplicate modes. + * 0 means that the mode param is the first mode encountered in the table + * 1 means that the mode param is the second mode encountered in the table + * etc... + */ +unsigned short getDuplicateModeIndex( + disp_control_t dispCtrl, + mode_parameter_t *pModeParam +) +{ + unsigned short index, modeIndex; + mode_parameter_t *pModeTable; + + /* Get the mode table */ + pModeTable = ddk768_getStockModeParamTableEx(dispCtrl); + + /* Search the current mode */ + modeIndex = 0; + index = 0; + while (pModeTable[modeIndex].pixel_clock != 0) + { + if ((pModeTable[modeIndex].horizontal_display_end == pModeParam->horizontal_display_end) && + (pModeTable[modeIndex].vertical_display_end == pModeParam->vertical_display_end) && + (pModeTable[modeIndex].vertical_frequency == pModeParam->vertical_frequency)) + { + /* Check if this is the same/identical mode param. */ + if (compareModeParam(&pModeTable[modeIndex], pModeParam) == 0) + break; + + /* Increment the index */ + index++; + } + modeIndex++; + } + + return index; +} + +/* + * ddk768_findModeParamFromTable + * This function locates the requested mode in the given parameter table + * + * Input: + * width - Mode width + * height - Mode height + * refresh_rate - Mode refresh rate + * index - Index that is used for multiple search of the same mode + * that have the same width, height, and refresh rate, + * but have different timing parameters. + * + * Output: + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *ddk768_findModeParamFromTable( + unsigned long width, + unsigned long height, + unsigned long refresh_rate, + unsigned short index, + mode_parameter_t *pModeTable +) +{ + unsigned short modeIndex = 0, tempIndex = 0; + + /* Walk the entire mode table. */ + while (pModeTable[modeIndex].pixel_clock != 0) + { + if (((width == (unsigned long)(-1)) || (pModeTable[modeIndex].horizontal_display_end == width)) && + ((height == (unsigned long)(-1)) || (pModeTable[modeIndex].vertical_display_end == height)) && + ((refresh_rate == (unsigned long)(-1)) || (pModeTable[modeIndex].vertical_frequency == refresh_rate))) + { + if (tempIndex < index) + tempIndex++; + else + return (&pModeTable[modeIndex]); + } + + /* Next entry */ + modeIndex++; + } + + /* No match, return NULL pointer */ + return((mode_parameter_t *)0); +} + +/* + * Locate in-stock parameter table for the requested mode. + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *ddk768_findModeParam( + disp_control_t dispCtrl, + unsigned long width, + unsigned long height, + unsigned long refresh_rate, + unsigned short index +) +{ + return ddk768_findModeParamFromTable(width, height, refresh_rate, index, ddk768_getStockModeParamTableEx(dispCtrl)); +} + +/* + * Use the + * Locate timing parameter for the requested mode from the default mode table. + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *ddk768_findVesaModeParam( + unsigned long width, + unsigned long height, + unsigned long refresh_rate +) +{ + return ddk768_findModeParamFromTable(width, height, refresh_rate, 0, gDefaultModeParamTable); +} + +/* + * (Obsolete) + * Return a point to the gDefaultModeParamTable. + * Function in other files used this to get the mode table pointer. + */ +mode_parameter_t *ddk768_getStockModeParamTable() +{ + return(gDefaultModeParamTable); +} + +/* + * (Obsolete) + * Return the size of the Stock Mode Param Table + */ +unsigned long ddk768_getStockModeParamTableSize() +{ + return (sizeof(gDefaultModeParamTable) / sizeof(mode_parameter_t) - 1); +} + +/* + * ddk768_getStockModeParamTableEx + * This function gets the mode parameters table associated to the + * display control (CHANNEL0_CTRL or SECONDAR_CTRL). + * + * Input: + * dispCtrl - Display Control of the mode table that is associated to. + * + * Output: + * Pointer to the mode table + */ +mode_parameter_t *ddk768_getStockModeParamTableEx( + disp_control_t dispCtrl +) +{ + mode_parameter_t *pModeTable; + + if (dispCtrl == CHANNEL0_CTRL){ + pModeTable = (mode_parameter_t *)gChannel0ModeParamTable; + }else{ + pModeTable = (mode_parameter_t *)gChannel1ModeParamTable; + } + + if(lvds_channel) + { + pModeTable = (mode_parameter_t *)gLVDSModeParamTable; + } + + /* Check if the table exist by checking the first entry. + If it doesn't, then use the default mode table. */ + + if (pModeTable->pixel_clock == 0) + { + pModeTable = ddk768_getStockModeParamTable(); + } + + return (pModeTable); +} + +/* + * ddk768_getStockModeParamTableSizeEx + * This function gets the size of the mode parameter table associated with + * specific display control + * + * Input: + * dispCtrl - Display control of the mode param table that is associated to. + * + * Output: + * Size of the requeted mode param table. + */ +unsigned long ddk768_getStockModeParamTableSizeEx( + disp_control_t dispCtrl +) +{ + unsigned long tableSize; + mode_parameter_t *pModeTable; + + /* Get the mode table */ + pModeTable = ddk768_getStockModeParamTableEx(dispCtrl); + + /* Calculate the table size by finding the end of table entry indicated by all zeroes. */ + tableSize = 0; + while (pModeTable[tableSize].pixel_clock != 0) + tableSize++; + + return tableSize; +} + +/* + * getMaximumModeEntries + * This function gets the maximum entries that can be stored in the mode table. + * + * Output: + * Total number of maximum entries + */ +unsigned long getMaximumModeEntries() +{ + return MAX_MODE_TABLE_ENTRIES; +} + +/* + * This function returns the current mode. + */ +mode_parameter_t ddk768_getCurrentModeParam( + disp_control_t dispCtrl +) +{ + if (dispCtrl == CHANNEL0_CTRL) + return gChannel0CurrentModeParam; + else + return gChannel1CurrentModeParam; +} + +/* + * addTiming + * This function adds the SM750 mode parameter timing to the specified mode table + * + * Input: + * dispCtrl - Display control where the mode will be associated to + * pNewModeList - Pointer to a list table of SM750 mode parameter to be added + * to the current specified display control mode table. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long addTiming( + disp_control_t dispCtrl, + mode_parameter_t *pNewModeList, + unsigned long totalList, + unsigned char clearTable +) +{ + mode_parameter_t *pModeParamTable; + unsigned char index; + long returnValue = 0; + + /* Get the correct table */ + if (dispCtrl == CHANNEL0_CTRL) + pModeParamTable = (mode_parameter_t *)gChannel0ModeParamTable; + else + pModeParamTable = (mode_parameter_t *)gChannel1ModeParamTable; + + if (clearTable == 0) + { + /* Find the last index where the timing will be added to */ + index = 0; + while(pModeParamTable[index].pixel_clock != 0) + index++; + } + else + { + /* Clear and reset the mode table first */ + for (index = 0; index < MAX_MODE_TABLE_ENTRIES; index++) + memset((void*)&pModeParamTable[index], 0, sizeof(mode_parameter_t)); + + /* Reset index */ + index = 0; + } + + /* Update the number of modes those can be added to the current table. */ + if (totalList > (unsigned long)(MAX_MODE_TABLE_ENTRIES - index)) + totalList = (unsigned long)(MAX_MODE_TABLE_ENTRIES - index); + else + returnValue = (-1); + + /* Check if totalList is 0, which means that the table is full. */ + if (totalList == 0) + returnValue = (-1); + + /* Add the list of modes provided by the caller */ + while (totalList--) + { + memcpy((void *)&pModeParamTable[index], (void *)&pNewModeList[index], sizeof(mode_parameter_t)); + index++; + } + + return returnValue; +} + +/* + * This function sets the display base address + * + * Input: + * dispControl - display control of which base address to be set. + * ulBaseAddress - Base Address value to be set. + */ +void ddk768_setDisplayBaseAddress( + disp_control_t dispControl, + unsigned long ulBaseAddress +) +{ + unsigned long regFB; + + regFB = (dispControl == CHANNEL0_CTRL) ? FB_ADDRESS : (FB_ADDRESS+CHANNEL_OFFSET); + + /* Frame buffer base for this mode */ + pokeRegisterDWord(regFB, + FIELD_SET(0, FB_ADDRESS, STATUS, PENDING) + | FIELD_VALUE(0, FB_ADDRESS, ADDRESS, ulBaseAddress)); +} + +/* + * This function checks if change of "display base address" has effective. + * Change of DC base address will not effective until next VSync, SW sets pending bit to 1 during address change. + * HW resets pending bit when it starts to use the new address. + * + * Input: + * dispControl - display control of which display status to be retrieved. + * + * Output: + * 1 - Display is pending + * 0 - Display is not pending + */ +long isDisplayBasePending( + disp_control_t dispControl +) +{ + unsigned long regFB; + + regFB = (dispControl == CHANNEL0_CTRL) ? FB_ADDRESS : (FB_ADDRESS+CHANNEL_OFFSET); + + if (FIELD_GET(peekRegisterDWord(regFB), FB_ADDRESS, STATUS) == FB_ADDRESS_STATUS_PENDING) + return 1; + + return (0); +} + + +/* + * Program the hardware for a specific video mode + * + * return: + * 0 = success + * -1 = fail. + */ +long ddk768_programModeRegisters( +logicalMode_t *pLogicalMode, +mode_parameter_t *pModeParam, /* mode information about pixel clock, horizontal total, etc. */ +pll_value_t *pPLL /* Pre-calculated values for the PLL */ +) +{ + unsigned long ulTmpValue; + unsigned long paletteRam; + unsigned long offset, pllReg; + unsigned long hdmi_channel; + unsigned long regvalue; +#if 0 // print UHD register setting for debug. + if (pLogicalMode->x == 3840) + return(printModeRegisters(pLogicalMode, pModeParam, pPLL)); +#endif + + /* Make sure normal display channel is used, not VGA channel */ + pokeRegisterDWord(VGA_CONFIGURATION, + FIELD_SET(0, VGA_CONFIGURATION, PLL, PANEL) | FIELD_SET(0, VGA_CONFIGURATION, MODE, GRAPHIC)); + + offset = (pLogicalMode->dispCtrl==CHANNEL0_CTRL)? 0 : CHANNEL_OFFSET; + pllReg = (pLogicalMode->dispCtrl==CHANNEL0_CTRL)? VCLK0_PLL : VCLK1_PLL; + + + /* Turn off PLL at first. */ + regvalue = peekRegisterByte(pllReg); + regvalue |= (1 << 0); + pokeRegisterDWord(pllReg, regvalue); + /* Poke setting. */ + regvalue = ddk768_formatPllReg(pPLL); + regvalue |= (1 << 0); + pokeRegisterDWord(pllReg, regvalue); + /* Delay 100 us and turn on PLL. */ + udelay(100); + regvalue = ddk768_formatPllReg(pPLL); + regvalue &= ~(1 << 0); + pokeRegisterDWord(pllReg, regvalue); + + +#if 0 + /* Frame buffer base */ + pokeRegisterDWord((FB_ADDRESS+offset), + FIELD_SET(0, FB_ADDRESS, STATUS, PENDING) + | FIELD_VALUE(0, FB_ADDRESS, ADDRESS, pLogicalMode->baseAddress)); + +#endif + + + /* Pitch value (Hardware people calls it Offset) */ + pokeRegisterDWord((FB_WIDTH+offset), + FIELD_VALUE(0, FB_WIDTH, WIDTH, pLogicalMode->pitch)); + + pokeRegisterDWord((HORIZONTAL_TOTAL+offset), + FIELD_VALUE(0, HORIZONTAL_TOTAL, TOTAL, pModeParam->horizontal_total - 1) + | FIELD_VALUE(0, HORIZONTAL_TOTAL, DISPLAY_END, pModeParam->horizontal_display_end - 1)); + + pokeRegisterDWord((HORIZONTAL_SYNC+offset), + FIELD_VALUE(0, HORIZONTAL_SYNC, WIDTH, pModeParam->horizontal_sync_width) + | FIELD_VALUE(0, HORIZONTAL_SYNC, START, pModeParam->horizontal_sync_start - 1)); + + pokeRegisterDWord((VERTICAL_TOTAL+offset), + FIELD_VALUE(0, VERTICAL_TOTAL, TOTAL, pModeParam->vertical_total - 1) + | FIELD_VALUE(0, VERTICAL_TOTAL, DISPLAY_END, pModeParam->vertical_display_end - 1)); + + pokeRegisterDWord((VERTICAL_SYNC+offset), + FIELD_VALUE(0, VERTICAL_SYNC, HEIGHT, pModeParam->vertical_sync_height) + | FIELD_VALUE(0, VERTICAL_SYNC, START, pModeParam->vertical_sync_start - 1)); + + + + hdmi_channel = FIELD_GET(peekRegisterDWord(DISPLAY_CTRL+offset), + DISPLAY_CTRL, + HDMI_SELECT); + + ulTmpValue = peekRegisterDWord(DISPLAY_CTRL+offset); + + /* Set control register value */ + ulTmpValue = + (pModeParam->vertical_sync_polarity == POS + ? FIELD_SET(ulTmpValue, DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_HIGH) + : FIELD_SET(ulTmpValue, DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW)); + + ulTmpValue = (pModeParam->horizontal_sync_polarity == POS + ? FIELD_SET(ulTmpValue, DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_HIGH) + : FIELD_SET(ulTmpValue, DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW)); + + ulTmpValue = (pModeParam->clock_phase_polarity == POS + ? FIELD_SET(ulTmpValue, DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_HIGH) + : FIELD_SET(ulTmpValue, DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_LOW)); + ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, DATA_PATH, EXTENDED); + ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, DIRECTION, INPUT); + ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, TIMING, ENABLE); + ulTmpValue = FIELD_SET(ulTmpValue, DISPLAY_CTRL, PLANE, ENABLE); + ulTmpValue = (pLogicalMode->bpp == 8 ? FIELD_SET(ulTmpValue, DISPLAY_CTRL, FORMAT, 8) + : (pLogicalMode->bpp == 16 + ? FIELD_SET(ulTmpValue, DISPLAY_CTRL, FORMAT, 16) + : FIELD_SET(ulTmpValue, DISPLAY_CTRL, FORMAT, 32))); + + if (offset == 0 && clk_phase == 0) + ulTmpValue = + FIELD_SET(ulTmpValue, DISPLAY_CTRL, CLOCK_PHASE, + ACTIVE_LOW); + if (offset == 0 && clk_phase == 1) + ulTmpValue = + FIELD_SET(ulTmpValue, DISPLAY_CTRL, CLOCK_PHASE, + ACTIVE_HIGH); + + if( hdmi_channel == DISPLAY_CTRL_HDMI_SELECT_CHANNEL0) + ulTmpValue= FIELD_SET(ulTmpValue,DISPLAY_CTRL, HDMI_SELECT, CHANNEL0); + else + ulTmpValue= FIELD_SET(ulTmpValue,DISPLAY_CTRL, HDMI_SELECT, CHANNEL1); + + + pokeRegisterDWord((DISPLAY_CTRL+offset), ulTmpValue); + + /* Palette RAM. */ + paletteRam = PALETTE_RAM + offset; + + /* Save the current mode param */ + if (pLogicalMode->dispCtrl == CHANNEL0_CTRL) + gChannel0CurrentModeParam = *pModeParam; + else + gChannel1CurrentModeParam = *pModeParam; + + /* In case of 8-bpp, fill palette */ + if (pLogicalMode->bpp==8) + { + /* Start with RGB = 0,0,0. */ + unsigned char red = 0, green = 0, blue = 0; + unsigned long gray = 0; + for (offset = 0; offset < 256 * 4; offset += 4) + { + /* Store current RGB value. */ + pokeRegisterDWord(paletteRam + offset, gray + ? RGB((gray + 50) / 100, + (gray + 50) / 100, + (gray + 50) / 100) + : RGB(red, green, blue)); + + if (gray) + { + /* Walk through grays (40 in total). */ + gray += 654; + } + + else + { + /* Walk through colors (6 per base color). */ + if (blue != 255) + { + blue += 51; + } + else if (green != 255) + { + blue = 0; + green += 51; + } + else if (red != 255) + { + green = blue = 0; + red += 51; + } + else + { + gray = 1; + } + } + } + } + /* For 16- and 32-bpp, fill palette with gamma values. */ + else + { + /* Start with RGB = 0,0,0. */ + ulTmpValue = 0x000000; + for (offset = 0; offset < 256 * 4; offset += 4) + { + pokeRegisterDWord(paletteRam + offset, ulTmpValue); + + /* Advance RGB by 1,1,1. */ + ulTmpValue += 0x010101; + } + } + + return 0; +} + +/* + * Input: + * 1) pLogicalMode contains information such as x, y resolution and bpp. + * 2) A user defined parameter table for the mode. + * + * This function calculate and programs the hardware to set up the + * requested mode. + * + * This function allows the use of user defined parameter table if + * predefined Vesa parameter table (gDefaultModeParamTable) does not fit. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long ddk768_setCustomMode( + logicalMode_t *pLogicalMode, + mode_parameter_t *pUserModeParam +) +{ + //mode_parameter_t pModeParam; /* physical parameters for the mode */ + pll_value_t pll; + unsigned long ulActualPixelClk; + + /* + * Minimum check on mode base address. + * At least it shouldn't be bigger than the size of frame buffer. + */ + if (ddk768_getFrameBufSize() <= pLogicalMode->baseAddress) + return -1; + + /* + * Set up PLL, a structure to hold the value to be set in clocks. + */ + if (ddk768_getCrystalType()) + pll.inputFreq = (24576000/2); + else + pll.inputFreq = (24000000/2); + + /* + * Call calcPllValue() to fill up the other fields for PLL structure. + * Sometime, the chip cannot set up the exact clock required by User. + * Return value from calcPllValue() gives the actual possible pixel clock. + */ + ulActualPixelClk = ddk768_calcPllValue(pUserModeParam->pixel_clock, &pll); + + + + + /* If calling function don't have a preferred pitch value, + work out a 16 byte aligned pitch value. + */ + if (pLogicalMode->pitch == 0) + { + /* + * Pitch value calculation in Bytes. + * Usually, it is (screen width) * (byte per pixel). + * However, there are cases that screen width is not 16 pixel aligned, which is + * a requirement for some OS and the hardware itself. + * For standard 4:3 resolutions: 320, 640, 800, 1024 and 1280, they are all + * 16 pixel aligned and pitch is simply (screen width) * (byte per pixel). + * + * However, 1366 resolution, for example, has to be adjusted for 16 pixel aligned. + */ + pLogicalMode->pitch = PITCH(pLogicalMode->x, pLogicalMode->bpp); + } + + /* Program the hardware to set up the mode. */ + return( ddk768_programModeRegisters( + pLogicalMode, + pUserModeParam, + &pll)); +} + +/* + * Input pLogicalMode contains information such as x, y resolution and bpp + * The main difference between setMode and setModeEx userData. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long ddk768_setModeEx( + logicalMode_t *pLogicalMode +) +{ + mode_parameter_t *pModeParam; /* physical parameters for the mode */ + unsigned short index = 0; + userData_t *pUserData; + + /* + * Check the validity of the userData pointer and translate the information as necessary + */ + pUserData = (userData_t *)pLogicalMode->userData; + if ((pUserData != (userData_t *)0) && + (pUserData->signature == ddk768_getUserDataSignature()) && + (pUserData->size == sizeof(userData_t))) + { + /* Interpret the userData information */ + if (pUserData->paramList.size == sizeof(userDataParam_t)) + { + if (pUserData->paramList.modeInfoID == MODE_INFO_INDEX) + index = pUserData->paramList.paramInfo.index; + } + } + + /* + * Check if we already have physical timing parameter for this mode. + */ + pModeParam = ddk768_findModeParam(pLogicalMode->dispCtrl, pLogicalMode->x, pLogicalMode->y, pLogicalMode->hz, index); + if (pModeParam == (mode_parameter_t *)0) + return -1; + + return(ddk768_setCustomMode(pLogicalMode, pModeParam)); +} + +/* + * Input pLogicalMode contains information such as x, y resolution and bpp. + * If there is no special parameters, use this function. + * If there are special parameters, use setModeEx. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long ddk768_setMode( + logicalMode_t *pLogicalMode +) +{ + pLogicalMode->userData = (void *)0; + + /* Call the setModeEx to set the mode. */ + return ddk768_setModeEx(pLogicalMode); +} + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_mode.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_mode.h new file mode 100644 index 000000000000..26fdd136d439 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_mode.h @@ -0,0 +1,268 @@ +#ifndef _DDK768_MODE_H_ +#define _DDK768_MODE_H_ +#include "../hw_com.h" +/* Maximum parameters those can be saved in the mode table. */ +#define MAX_MODE_TABLE_ENTRIES 60 +#define PITCH(width, bpp) (((width) * (bpp) / 8 + 15) & ~15) + +/* Set the alignment to 1-bit aligned. Otherwise, the memory compare used in the + modeext to compare timing will not work. */ +#pragma pack(1) + + +/* + * ID of the modeInfoID used in the userDataParam_t + */ +#define MODE_INFO_INDEX 0x01 + + + +/* Restore alignment */ +#pragma pack() + +/* + * ddk768_getUserDataSignature + * This function gets the user data mode signature + * + * Output: + * The signature to be filled in the user_data_mode_t structure to be considered + * a valid structure. + */ +unsigned long ddk768_getUserDataSignature(void); + +/* + * compareModeParam + * This function compares two mode parameters + * + * Input: + * pModeParam1 - Pointer to the first mode parameter to be compared + * pModeParam2 - Pointer to the second mode parameter to be compared + * + * Output: + * 0 - Identical mode + * -1 - Mode is not identical + */ +long compareModeParam( + mode_parameter_t *pModeParam1, + mode_parameter_t *pModeParam2 +); + +/* + * getDuplicateModeIndex + * This function retrieves the index of dupicate modes, but having different timing. + * + * Input: + * dispCtrl - Display Control where the mode table belongs to. + * pModeParam - The mode parameters which index to be checked. + * + * Output: + * The index of the given parameters among the duplicate modes. + * 0 means that the mode param is the first mode encountered in the table + * 1 means that the mode param is the second mode encountered in the table + * etc... + */ +unsigned short getDuplicateModeIndex( + disp_control_t dispCtrl, + mode_parameter_t *pModeParam +); + +/* + * ddk768_findModeParamFromTable + * This function locates the requested mode in the given parameter table + * + * Input: + * width - Mode width + * height - Mode height + * refresh_rate - Mode refresh rate + * index - Index that is used for multiple search of the same mode + * that have the same width, height, and refresh rate, + * but have different timing parameters. + * + * Output: + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *ddk768_findModeParamFromTable( + unsigned long width, + unsigned long height, + unsigned long refresh_rate, + unsigned short index, + mode_parameter_t *pModeTable +); + +/* + * Locate in-stock parameter table for the requested mode. + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *ddk768_findModeParam( + disp_control_t dispCtrl, + unsigned long width, + unsigned long height, + unsigned long refresh_rate, + unsigned short index +); + +/* + * Use the + * Locate timing parameter for the requested mode from the default mode table. + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *ddk768_findVesaModeParam( + unsigned long width, + unsigned long height, + unsigned long refresh_rate +); + +/* + * Return a point to the gDefaultModeParamTable. + * Function in other files used this to get the mode table pointer. + */ +mode_parameter_t *ddk768_getStockModeParamTable(void); + +/* + * Return the size of the Stock Mode Param Table + */ +unsigned long ddk768_getStockModeParamTableSize(void); + +/* + * ddk768_getStockModeParamTableEx + * This function gets the mode parameters table associated to the + * display control (CHANNEL0_CTRL or SECONDAR_CTRL). + * + * Input: + * dispCtrl - Display Control of the mode table that is associated to. + * + * Output: + * Pointer to the mode table + */ +mode_parameter_t *ddk768_getStockModeParamTableEx( + disp_control_t dispCtrl +); + +/* + * ddk768_getStockModeParamTableSizeEx + * This function gets the size of the mode parameter table associated with + * specific display control + * + * Input: + * dispCtrl - Display control of the mode param table that is associated to. + * + * Output: + * Size of the requeted mode param table. + */ +unsigned long ddk768_getStockModeParamTableSizeEx( + disp_control_t dispCtrl +); + +/* + * This function returns the current mode. + */ +mode_parameter_t ddk768_getCurrentModeParam( + disp_control_t dispCtrl +); + +/* + * getMaximumModeEntries + * This function gets the maximum entries that can be stored in the mode table. + * + * Output: + * Total number of maximum entries + */ +unsigned long getMaximumModeEntries(void); + +/* + * addTiming + * This function adds the SM750 mode parameter timing to the specified mode table + * + * Input: + * dispCtrl - Display control where the mode will be associated to + * pNewModeList - Pointer to a list table of SM750 mode parameter to be added + * to the current specified display control mode table. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long addTiming( + disp_control_t dispCtrl, + mode_parameter_t *pNewModeList, + unsigned long totalList, + unsigned char clearTable +); + + + +/* + * This function sets the display base address + * + * Input: + * dispControl - display control of which base address to be set. + * ulBaseAddress - Base Address value to be set. + */ +void ddk768_setDisplayBaseAddress( + disp_control_t dispControl, + unsigned long ulBaseAddress +); + +/* + * This function checks if change of "display base address" has effective. + * Change of DC base address will not effective until next VSync, SW sets pending bit to 1 during address change. + * HW resets pending bit when it starts to use the new address. + * + * Input: + * dispControl - display control of which display status to be retrieved. + * + * Output: + * 1 - Display is pending + * 0 - Display is not pending + */ +long isDisplayBasePending( + disp_control_t dispControl +); + +/* + * Input: + * 1) pLogicalMode contains information such as x, y resolution and bpp. + * 2) A user defined parameter table for the mode. + * + * This function calculate and programs the hardware to set up the + * requested mode. + * + * This function allows the use of user defined parameter table if + * predefined Vesa parameter table (gDefaultModeParamTable) does not fit. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long ddk768_setCustomMode( + logicalMode_t *pLogicalMode, + mode_parameter_t *pUserModeParam +); + +/* + * Input pLogicalMode contains information such as x, y resolution and bpp + * The main difference between setMode and setModeEx userData. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long ddk768_setModeEx( + logicalMode_t *pLogicalMode +); + +/* + * Input pLogicalMode contains information such as x, y resolution and bpp. + * If there is no special parameters, use this function. + * If there are special parameters, use setModeEx. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long ddk768_setMode( + logicalMode_t *pLogicalMode +); + + +#endif /* _MODE_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_power.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_power.c new file mode 100644 index 000000000000..023022c99606 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_power.c @@ -0,0 +1,269 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* power.c --- Voyager GX SDK +* This file contains the source code for the power functions. +* +*******************************************************************/ +#include "ddk768_reg.h" + +#include "ddk768_chip.h" +#include "ddk768_power.h" + +#include "ddk768_help.h" + + + +/* + * Enable/disable jpeg decoder 1. + */ +void ddk768_enableJPU1(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, JPU1, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, JPU1, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + +/* + * This function enable/disable the 2D engine. + */ +void ddk768_enable2DEngine(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DE, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DE, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); + +} + +/* + * This function enable/disable the ZV Port. + */ +void ddk768_enableZVPort(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, ZV, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, ZV, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); + +} + +/* + * This function enable/disable the SSP. + */ +void ddk768_enableSSP(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, SSP, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, SSP, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); + +} + +/* + * This function enable/disable the DMA Engine + */ +void ddk768_enableDMA(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DMA, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DMA, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); + +} + + + +/* + * This function enable/disable HDMI + */ +void ddk768_enableHDMI(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, HDMI, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, HDMI, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + +/* + * Enable/disable USB 2 Host. + */ +void ddk768_enableUsbHost(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, USBH, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, USBH, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + +/* + * Enable/disable USB 3 device + */ +void ddk768_enableUsbDevice(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, USBS, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, USBS, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + +/* + * Enable/disable jpeg decoder. + */ +void ddk768_enableJPU(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, JPU, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, JPU, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + +/* + * Enable/disable H264 video decoder. + */ +void ddk768_enableVPU(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, VPU, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, VPU, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + + +/* + * Enable/disable UART + */ +void ddk768_enableUART(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, UART, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, UART, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + +/* + * Enable/disable I2S + */ +void ddk768_enableI2S(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, I2S, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, I2S, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + + + +/* + * Enable/disable ARM + */ +void ddk768_enableARM(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, ARM, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, ARM, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + +/* + * Enable/disable display control 0 + */ +void ddk768_enableDC0(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DC0, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DC0, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + +/* + * Enable/disable display control 1 + */ +void ddk768_enableDC1(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DC1, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DC1, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_power.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_power.h new file mode 100644 index 000000000000..a37ff583fc81 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_power.h @@ -0,0 +1,62 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* power.h --- Voyager GX SDK +* This file contains the definitions for the power functions. +* +*******************************************************************/ +#ifndef _DDK768_POWER_H_ +#define _DDK768_POWER_H_ + + +void ddk768_enableUsbHost(unsigned long enable); + + +/* + * Enable/disable jpeg decoder 1. + */ +void ddk768_enableJPU1(unsigned long enable); + + +/* + * This function enable/disable the 2D engine. + */ +void ddk768_enable2DEngine(unsigned long enable); + +/* + * This function enable/disable the ZV Port + */ +void ddk768_enableZVPort(unsigned long enable); + +/* + * This function enable/disable the DMA Engine + */ +void ddk768_enableDMA(unsigned long enable); + + + +/* + * This function enable/disable the PWM Engine + */ +void ddk768_enablePWM(unsigned long enable); + +/* + * This function enable/disable the SSP. + */ +void ddk768_enableSSP(unsigned long enable); + +/* + * This function enable/disable the HDMI Clock. + */ +void ddk768_enableHDMI(unsigned long enable); + + +void ddk768_enableI2S(unsigned long enable); + + + +#endif /* _POWER_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_pwm.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_pwm.c new file mode 100644 index 000000000000..05b756b3c52f --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_pwm.c @@ -0,0 +1,287 @@ +/******************************************************************* +* +* Copyright (c) 2014 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* This file contains the definitions for the PWM functions. +* +*******************************************************************/ + + +#include "ddk768_help.h" +#include "ddk768_reg.h" +#include "ddk768_helper.h" +#include "ddk768_intr.h" +#include "ddk768_pwm.h" + + +static unsigned long gPwm = 0; + +/* + * This function open PWM lines in GPIO Mux + */ +void ddk768_pwmOpen( + unsigned long pwm /* which pwm: 0 to 2 */ +) +{ + unsigned long value; + + /* Enable GPIO mux (0x10010) 19, 18 or 17 for PWM output */ + value = peekRegisterDWord(GPIO_MUX); + + switch(pwm) + { + case 0: + value = FIELD_SET(value, GPIO_MUX, 17, PWM0); + break; + + case 1: + value = FIELD_SET(value, GPIO_MUX, 18, PWM1); + break; + + default: + value = FIELD_SET(value, GPIO_MUX, 19, PWM2); + break; + } + + pokeRegisterDWord(GPIO_MUX, value); +} + +/* + * This function closes PWM lines in GPIO Mux + */ +void ddk768_pwmClose( + unsigned long pwm /* which pwm: 0 to 2 */ +) +{ + unsigned long value; + + /* Enable GPIO mux (0x10010) 19, 18 or 17 for PWM output */ + value = peekRegisterDWord(GPIO_MUX); + + switch(pwm) + { + case 0: + value = FIELD_SET(value, GPIO_MUX, 17, GPIO); + break; + + case 1: + value = FIELD_SET(value, GPIO_MUX, 18, GPIO); + break; + + default: + value = FIELD_SET(value, GPIO_MUX, 19, GPIO); + break; + } + + pokeRegisterDWord(GPIO_MUX, value); +} + +/* + * According to input time, this function calculates values + * for PWM clock divide and PWM counter with 50% duty cycle. + */ +void ddk768_pwmCalcCounter( + unsigned long mSec, /* Input time in milli second */ + unsigned long *clkDivider, /* Output clock divider value */ + unsigned long *counter /* Output counter value for both high and low counter at 50% duty cycle */ +) +{ + /* The value of counter depends on the clock frequency the counter is running. + For FPGA, it is 100MHz. For ASIC, it is 180 to 200 MHz. + */ + + /* For FPGA testing purpose, just return any number for now */ + *clkDivider = 8; /* Divide by 256 */ + *counter = 0xfff; /* Max 12 bit value */ +} + +/* + * This function starts PWM. + * When PWM completes a cycle, its raw interrupt pending bit will be set. + * + * Important limitation: Since all three PWM shares one INT status and mask, + * only one PWM can set up ISR at any time. + * + */ +void ddk768_pwmStart( + unsigned long pwm, /* which pwm: 0 to 2 */ + unsigned long divider, + unsigned long highCounter, + unsigned long lowCounter, + unsigned long isrSupport /* 1 if user wants to hook an ISR, 0 if use pulling method + Note that only one PWM can have ISR at any time. + */ +) +{ + unsigned long pwmAddr, pwmValue; + + if (pwm > 2) return; /* Invalid PWM number */ + + if (highCounter == 0 || lowCounter == 0) return; /* Nothing to set */ + + /* Work out the PWM's MMIO address + PWM 0 address + ( PWM x 4 ) + */ + pwmAddr = PWM_CONTROL + (pwm << 2); + + pwmValue = + FIELD_VALUE(0, PWM_CONTROL, HIGH_COUNTER, highCounter) + | FIELD_VALUE(0, PWM_CONTROL, LOW_COUNTER, lowCounter) + | FIELD_VALUE(0, PWM_CONTROL, CLOCK_DIVIDE, divider) + | FIELD_SET(0, PWM_CONTROL, INTERRUPT_STATUS, CLEAR) /* Reset the raw interrupt */ + | FIELD_SET(0, PWM_CONTROL, INTERRUPT, ENABLE) /* Enable raw interrupt to happen */ + | FIELD_SET(0, PWM_CONTROL, STATUS, ENABLE); /* Start PWM */ + + pokeRegisterDWord(pwmAddr, pwmValue); + + if (isrSupport) + gPwm = pwm; +} + +/* + * This function checks if a PWM's raw interrupt has been pending. + * When raw interrupt is detected with pending status, it indicate the + * a pulse cycle is completed after pwmStart(). + * + * Return: + * 1 = Raw interrupt status is pending. + * 0 = Raw int is NOT pending. + */ +unsigned long ddk768_pwmRawIntPending( + unsigned long pwm /* which pwm: 0 to 2 */ +) +{ + unsigned long pwmAddr, rawIntStatus; + + if (pwm > 2) return 0; /* Invalid PWM number */ + + /* Work out the PWM's MMIO address + PWM 0 address + ( PWM x 4 ) + */ + pwmAddr = PWM_CONTROL + (pwm << 2); + + rawIntStatus = FIELD_GET(peekRegisterDWord(pwmAddr), PWM_CONTROL, INTERRUPT_STATUS); + + return(rawIntStatus); +} + +/* + * This function clears the RAW interrupt status of PWM. + * + * When PWM completes a cycle, the raw interrupt bit will be set. + * It has to be cleared, in order to distinguish between different cycles. + * + */ +void ddk768_pwmClearRawInt( + unsigned long pwm /* which pwm: 0 to 2 */ +) +{ + unsigned long pwmAddr, pwmValue; + + if (pwm > 2) return; /* Invalid PWM number */ + + /* Work out the PWM's MMIO address + PWM 0 address + ( PWM x 4 ) + */ + pwmAddr = PWM_CONTROL + (pwm << 2); + + pwmValue = peekRegisterDWord(pwmAddr); + + pokeRegisterDWord(pwmAddr, + pwmValue + | FIELD_SET(0, PWM_CONTROL, INTERRUPT_STATUS, CLEAR)); /* Reset the raw interrupt */ +} + +/* + * This function stop PWM + * + */ +void ddk768_pwmStop( + unsigned long pwm /* which pwm: 0 to 2 */ +) +{ + unsigned long pwmAddr, pwmValue; + + if (pwm > 2) return; /* Invalid PWM number */ + + /* Work out the PWM's MMIO address + PWM 0 address + ( PWM x 4 ) + */ + pwmAddr = PWM_CONTROL + (pwm << 2); + + pwmValue = + FIELD_SET(0, PWM_CONTROL, INTERRUPT_STATUS, CLEAR) /* Reset the raw interrupt */ + | FIELD_SET(0, PWM_CONTROL, STATUS, DISABLE); /* Stop the PWM */ + + pokeRegisterDWord(pwmAddr, pwmValue); +} + +/* + * This funciton uses PWM to wait a specific amount of time. + * + * Input: millisecond unit. + */ +void ddk768_pwmWait( + unsigned long pwm, + unsigned long milliSeconds +) +{ + unsigned long divider, highCounter, lowCounter; + + if (pwm > 2) return; /* Invalid PWM number */ + + /* Calculate how many ticks are needed for the amount of time.*/ + ddk768_pwmCalcCounter(milliSeconds, ÷r, &highCounter); + lowCounter = highCounter; + + ddk768_pwmStart(pwm, divider, highCounter, lowCounter, 0); + + while (!ddk768_pwmRawIntPending(pwm)); /* Danger, put a timeout here later */ + + ddk768_pwmStop(pwm); +} + +/* + * This function returns the INT mask for a specific PWM + * + */ +unsigned long ddk768_pwmIntMask( + unsigned long pwm /* which pwm: 0 to 2 */ +) +{ + unsigned long mask = 0; + + /* Note: In falcon, all PWM shares one INT mask */ + mask |= FIELD_SET(0, INT_MASK, PWM, ENABLE); + + return mask; +} + +/* + * This is a reference sample showing how to implement ISR for PWM + * It works together with libsrc\intr.c + * + * Refer to Apps\timer\tstpwm.c on how to hook up this function with system + * interrupt under WATCOM DOS extender. + * + */ +void ddk768_pwmIsrTemplate(unsigned long status) +{ + /* Check if it's PWM interrupt. */ + + if (FIELD_GET(status, INT_STATUS, PWM)) + { + /* Perform ISR action for timer 0 here */ + incTestCounter(); /* Dummy example action */ + + /* In Falcon, sicne all 3 PWM shares one PWM mask, + There is no way to tell which PWM generates the interrupt. + Just Clear the one marked down by pwmStart. + */ + ddk768_pwmClearRawInt(gPwm); + } +} + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_pwm.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_pwm.h new file mode 100644 index 000000000000..0bc92a00ae5b --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_pwm.h @@ -0,0 +1,117 @@ +/******************************************************************* +* +* Copyright (c) 2014 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* This file contains the definitions for the timer functions. +* +*******************************************************************/ +#ifndef _PWM_H_ +#define _PWM_H_ + +/* + * This function open PWM lines in GPIO Mux + */ +void ddk768_pwmOpen( + unsigned long pwm /* which pwm: 0 to 2 */ +); + +/* + * This function closes PWM lines in GPIO Mux + */ +void ddk768_pwmClose( + unsigned long pwm /* which pwm: 0 to 2 */ +); + +/* + * According to input time, this function calculates values + * for PWM clock divide and PWM counter with 50% duty cycle. + */ +void ddk768_pwmCalcCounter( + unsigned long mSec, /* Input time in milli second */ + unsigned long *clkDivider, /* Output clock divider value */ + unsigned long *counter /* Output counter value for both high and low counter at 50% duty cycle */ +); + +/* + * This function starts PWM. + * When PWM completes a cycle, its raw interrupt pending bit will be set. + * + * Important limitation: Since all three PWM shares one INT status and mask, + * only one PWM can set up ISR at any time. + * + */ +void ddk768_pwmStart( + unsigned long pwm, /* which pwm: 0 to 2 */ + unsigned long divider, + unsigned long highCounter, + unsigned long lowCounter, + unsigned long isrSupport /* 1 if user wants to hook an ISR, 0 if use pulling method + Note that only one PWM can have ISR at any time. + */ +); + +/* + * This function checks if a PWM's raw interrupt has been pending. + * When raw interrupt is detected with pending status, it indicate the + * a pulse cycle is completed after pwmStart(). + * + * Return: + * 1 = Raw interrupt status is pending. + * 0 = Raw int is NOT pending. + */ +unsigned long ddk768_pwmRawIntPending( + unsigned long pwm /* which pwm: 0 to 2 */ +); + +/* + * This function clears the RAW interrupt status of PWM. + * + * When PWM completes a cycle, the raw interrupt bit will be set. + * It has to be cleared, in order to distinguish between different cycles. + * + */ +void ddk768_pwmClearRawInt( + unsigned long pwm /* which pwm: 0 to 2 */ +); + +/* + * This function stop PWM + * + */ +void ddk768_pwmStop( + unsigned long pwm /* which pwm: 0 to 2 */ +); + +/* + * This funciton uses PWM to wait a specific amount of time. + * + * Input: millisecond unit. + */ +void ddk768_pwmWait( + unsigned long pwm, + unsigned long milliSeconds +); + +/* + * This function returns the INT mask for a specific PWM + * + */ +unsigned long ddk768_pwmIntMask( + unsigned long pwm /* which pwm: 0 to 2 */ +); + +/* + * This is a reference sample showing how to implement ISR for PWM + * It works together with libsrc\intr.c + * + * Refer to Apps\timer\tstpwm.c on how to hook up this function with system + * interrupt under WATCOM DOS extender. + * + */ +void ddk768_pwmIsrTemplate(unsigned long status); + +#endif /* _PWM_H_ */ + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_reg.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_reg.h new file mode 100644 index 000000000000..6335d2f6766c --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_reg.h @@ -0,0 +1,2813 @@ + +//#include "regsc.h" + +#define SCRATCH_PAD0 0x000060 + +#define SCRATCH_PAD1 0x000064 + +#define CLOCK_ENABLE 0x000068 +#define CLOCK_ENABLE_JPU1R 30:30 +#define CLOCK_ENABLE_JPU1R_NORMAL 0 +#define CLOCK_ENABLE_JPU1R_RESET 1 +#define CLOCK_ENABLE_HDMIR 29:29 +#define CLOCK_ENABLE_HDMIR_NORMAL 0 +#define CLOCK_ENABLE_HDMIR_RESET 1 +#define CLOCK_ENABLE_USBHR 28:28 +#define CLOCK_ENABLE_USBHR_NORMAL 0 +#define CLOCK_ENABLE_USBHR_RESET 1 +#define CLOCK_ENABLE_USBSR 27:27 +#define CLOCK_ENABLE_USBSR_NORMAL 0 +#define CLOCK_ENABLE_USBSR_RESET 1 +#define CLOCK_ENABLE_ZVR 26:26 +#define CLOCK_ENABLE_ZVR_NORMAL 0 +#define CLOCK_ENABLE_ZVR_RESET 1 +#define CLOCK_ENABLE_JPUR 25:25 +#define CLOCK_ENABLE_JPUR_NORMAL 0 +#define CLOCK_ENABLE_JPUR_RESET 1 +#define CLOCK_ENABLE_VPUR 24:24 +#define CLOCK_ENABLE_VPUR_NORMAL 0 +#define CLOCK_ENABLE_VPUR_RESET 1 +#define CLOCK_ENABLE_DER 23:23 +#define CLOCK_ENABLE_DER_NORMAL 0 +#define CLOCK_ENABLE_DER_RESET 1 +#define CLOCK_ENABLE_DMAR 22:22 +#define CLOCK_ENABLE_DMAR_NORMAL 0 +#define CLOCK_ENABLE_DMAR_RESET 1 +#define CLOCK_ENABLE_DC1R 18:18 +#define CLOCK_ENABLE_DC1R_NORMAL 0 +#define CLOCK_ENABLE_DC1R_RESET 1 +#define CLOCK_ENABLE_DC0R 17:17 +#define CLOCK_ENABLE_DC0R_NORMAL 0 +#define CLOCK_ENABLE_DC0R_RESET 1 +#define CLOCK_ENABLE_ARMR 16:16 +#define CLOCK_ENABLE_ARMR_NORMAL 0 +#define CLOCK_ENABLE_ARMR_RESET 1 +#define CLOCK_ENABLE_JPU1 14:14 +#define CLOCK_ENABLE_JPU1_OFF 0 +#define CLOCK_ENABLE_JPU1_ON 1 +#define CLOCK_ENABLE_HDMI 13:13 +#define CLOCK_ENABLE_HDMI_OFF 0 +#define CLOCK_ENABLE_HDMI_ON 1 +#define CLOCK_ENABLE_USBH 12:12 +#define CLOCK_ENABLE_USBH_OFF 0 +#define CLOCK_ENABLE_USBH_ON 1 +#define CLOCK_ENABLE_USBS 11:11 +#define CLOCK_ENABLE_USBS_OFF 0 +#define CLOCK_ENABLE_USBS_ON 1 +#define CLOCK_ENABLE_ZV 10:10 +#define CLOCK_ENABLE_ZV_OFF 0 +#define CLOCK_ENABLE_ZV_ON 1 +#define CLOCK_ENABLE_JPU 9:9 +#define CLOCK_ENABLE_JPU_OFF 0 +#define CLOCK_ENABLE_JPU_ON 1 +#define CLOCK_ENABLE_VPU 8:8 +#define CLOCK_ENABLE_VPU_OFF 0 +#define CLOCK_ENABLE_VPU_ON 1 +#define CLOCK_ENABLE_DE 7:7 +#define CLOCK_ENABLE_DE_OFF 0 +#define CLOCK_ENABLE_DE_ON 1 +#define CLOCK_ENABLE_DMA 6:6 +#define CLOCK_ENABLE_DMA_OFF 0 +#define CLOCK_ENABLE_DMA_ON 1 +#define CLOCK_ENABLE_UART 5:5 +#define CLOCK_ENABLE_UART_OFF 0 +#define CLOCK_ENABLE_UART_ON 1 +#define CLOCK_ENABLE_I2S 4:4 +#define CLOCK_ENABLE_I2S_OFF 0 +#define CLOCK_ENABLE_I2S_ON 1 +#define CLOCK_ENABLE_SSP 3:3 +#define CLOCK_ENABLE_SSP_OFF 0 +#define CLOCK_ENABLE_SSP_ON 1 +#define CLOCK_ENABLE_DC1 2:2 +#define CLOCK_ENABLE_DC1_OFF 0 +#define CLOCK_ENABLE_DC1_ON 1 +#define CLOCK_ENABLE_DC0 1:1 +#define CLOCK_ENABLE_DC0_OFF 0 +#define CLOCK_ENABLE_DC0_ON 1 +#define CLOCK_ENABLE_ARM 0:0 +#define CLOCK_ENABLE_ARM_OFF 0 +#define CLOCK_ENABLE_ARM_ON 1 + +/* No bit fields for VGA PLL since DDK don't use it */ +#define VGA25PLL 0x00006C +#define VGA28PLL 0x000070 + + +/* Master clock for DDR and core */ +#define MCLK_PLL 0x000074 +#define MCLK_PLL_VCO 23:22 +#define MCLK_PLL_INT 21:16 +#define MCLK_PLL_POWER 0:0 +#define MCLK_PLL_POWER_NORMAL 0 +#define MCLK_PLL_POWER_DOWN 1 + +/* Video clock 0 */ +#define VCLK0_PLL 0x000078 +/* VCLK Definition for FPGA */ +#define VCLK0_PLL_FREQ 4:0 +#define VCLK0_PLL_FREQ_25MHZ 0 +#define VCLK0_PLL_FREQ_40MHZ 1 +#define VCLK0_PLL_FREQ_65MHZ 3 +#define VCLK0_PLL_FREQ_74MHZ 4 +#define VCLK0_PLL_FREQ_80MHZ 5 +#define VCLK0_PLL_FREQ_108MHZ 6 + +/* VCLK Definition for ASIC */ +#define VCLK_PLL_SSCG 30:30 +#define VCLK_PLL_SSC 29:28 +#define VCLK_PLL_FN 27:27 +#define VCLK_PLL_FN_INT_MODE 0 +#define VCLK_PLL_FN_FRAC_MODE 1 +#define VCLK_PLL_BS 26:25 +#define VCLK_PLL_VCO 24:22 +#define VCLK_PLL_INT 21:16 +#define VCLK_PLL_FRAC 15:1 +#define VCLK_PLL_POWER 0:0 +#define VCLK_PLL_POWER_NORMAL 0 +#define VCLK_PLL_POWER_DOWN 1 + +/* Video clock 1. Bit field definiton is same as VCLK0 */ +#define VCLK1_PLL 0x00007C + +#define PROTOCOL_SEMAPHORE0 0x000080 +#define PROTOCOL_SEMAPHORE1 0x000084 + + +#define VGA_CONFIGURATION 0x000088 +#define VGA_CONFIGURATION_PLL 2:2 +#define VGA_CONFIGURATION_PLL_VGA 0 +#define VGA_CONFIGURATION_PLL_PANEL 1 +#define VGA_CONFIGURATION_MODE 1:1 +#define VGA_CONFIGURATION_MODE_TEXT 0 +#define VGA_CONFIGURATION_MODE_GRAPHIC 1 +#define VGA_CONFIGURATION_PREFETCH 0:0 +#define VGA_CONFIGURATION_PREFETCH_DISABLE 0 +#define VGA_CONFIGURATION_PREFETCH_ENABLE 1 + +/* Lock or unlock PCIE bar 2 to 5 */ +#define PCIE_BAR 0x00008C +#define PCIE_BAR_LOCK 0:0 +#define PCIE_BAR_LOCK_UNLOCK 0 +#define PCIE_BAR_LOCK_LOCK 1 + + +#define RAW_INT 0x000090 +#define RAW_INT_CSC 5:5 +#define RAW_INT_CSC_INACTIVE 0 +#define RAW_INT_CSC_ACTIVE 1 +#define RAW_INT_CSC_CLEAR 1 +#define RAW_INT_DE 4:4 +#define RAW_INT_DE_INACTIVE 0 +#define RAW_INT_DE_ACTIVE 1 +#define RAW_INT_DE_CLEAR 1 +#define RAW_INT_ZVPORT_VSYNC 3:3 +#define RAW_INT_ZVPORT_VSYNC_INACTIVE 0 +#define RAW_INT_ZVPORT_VSYNC_ACTIVE 1 +#define RAW_INT_ZVPORT_VSYNC_CLEAR 1 +#define RAW_INT_CHANNEL1_VSYNC 2:2 +#define RAW_INT_CHANNEL1_VSYNC_INACTIVE 0 +#define RAW_INT_CHANNEL1_VSYNC_ACTIVE 1 +#define RAW_INT_CHANNEL1_VSYNC_CLEAR 1 +#define RAW_INT_CHANNEL0_VSYNC 1:1 +#define RAW_INT_CHANNEL0_VSYNC_INACTIVE 0 +#define RAW_INT_CHANNEL0_VSYNC_ACTIVE 1 +#define RAW_INT_CHANNEL0_VSYNC_CLEAR 1 +#define RAW_INT_VGA_VSYNC 0:0 +#define RAW_INT_VGA_VSYNC_INACTIVE 0 +#define RAW_INT_VGA_VSYNC_ACTIVE 1 +#define RAW_INT_VGA_VSYNC_CLEAR 1 + +#ifdef SMI_ARM +#define INT_STATUS 0x0000A8 +#else +#define INT_STATUS 0x000094 +#endif +#define INT_STATUS_TIMER3 31:31 +#define INT_STATUS_TIMER3_INACTIVE 0 +#define INT_STATUS_TIMER3_ACTIVE 1 +#define INT_STATUS_TIMER2 30:30 +#define INT_STATUS_TIMER2_INACTIVE 0 +#define INT_STATUS_TIMER2_ACTIVE 1 +#define INT_STATUS_TIMER1 29:29 +#define INT_STATUS_TIMER1_INACTIVE 0 +#define INT_STATUS_TIMER1_ACTIVE 1 +#define INT_STATUS_TIMER0 28:28 +#define INT_STATUS_TIMER0_INACTIVE 0 +#define INT_STATUS_TIMER0_ACTIVE 1 +#define INT_STATUS_VPU 27:27 +#define INT_STATUS_VPU_INACTIVE 0 +#define INT_STATUS_VPU_ACTIVE 1 +#define INT_STATUS_JPU 26:26 +#define INT_STATUS_JPU_INACTIVE 0 +#define INT_STATUS_JPU_ACTIVE 1 +#define INT_STATUS_USBH 25:25 +#define INT_STATUS_USBH_INACTIVE 0 +#define INT_STATUS_USBH_ACTIVE 1 +#define INT_STATUS_USBS 24:24 +#define INT_STATUS_USBS_INACTIVE 0 +#define INT_STATUS_USBS_ACTIVE 1 +#define INT_STATUS_I2S 23:23 +#define INT_STATUS_I2S_INACTIVE 0 +#define INT_STATUS_I2S_ACTIVE 1 +#define INT_STATUS_UART1 22:22 +#define INT_STATUS_UART1_INACTIVE 0 +#define INT_STATUS_UART1_ACTIVE 1 +#define INT_STATUS_UART0 21:21 +#define INT_STATUS_UART0_INACTIVE 0 +#define INT_STATUS_UART0_ACTIVE 1 +#define INT_STATUS_SSP1 20:20 +#define INT_STATUS_SSP1_INACTIVE 0 +#define INT_STATUS_SSP1_ACTIVE 1 +#define INT_STATUS_SSP0 19:19 +#define INT_STATUS_SSP0_INACTIVE 0 +#define INT_STATUS_SSP0_ACTIVE 1 +#define INT_STATUS_I2C1 18:18 +#define INT_STATUS_I2C1_INACTIVE 0 +#define INT_STATUS_I2C1_ACTIVE 1 +#define INT_STATUS_I2C0 17:17 +#define INT_STATUS_I2C0_INACTIVE 0 +#define INT_STATUS_I2C0_ACTIVE 1 +#define INT_STATUS_PWM 16:16 +#define INT_STATUS_PWM_INACTIVE 0 +#define INT_STATUS_PWM_ACTIVE 1 +#define INT_STATUS_GPIO6 15:15 +#define INT_STATUS_GPIO6_INACTIVE 0 +#define INT_STATUS_GPIO6_ACTIVE 1 +#define INT_STATUS_GPIO5 14:14 +#define INT_STATUS_GPIO5_INACTIVE 0 +#define INT_STATUS_GPIO5_ACTIVE 1 +#define INT_STATUS_GPIO4 13:13 +#define INT_STATUS_GPIO4_INACTIVE 0 +#define INT_STATUS_GPIO4_ACTIVE 1 +#define INT_STATUS_GPIO3 12:12 +#define INT_STATUS_GPIO3_INACTIVE 0 +#define INT_STATUS_GPIO3_ACTIVE 1 +#define INT_STATUS_GPIO2 11:11 +#define INT_STATUS_GPIO2_INACTIVE 0 +#define INT_STATUS_GPIO2_ACTIVE 1 +#define INT_STATUS_GPIO1 10:10 +#define INT_STATUS_GPIO1_INACTIVE 0 +#define INT_STATUS_GPIO1_ACTIVE 1 +#define INT_STATUS_GPIO0 9:9 +#define INT_STATUS_GPIO0_INACTIVE 0 +#define INT_STATUS_GPIO0_ACTIVE 1 +#define INT_STATUS_DMA 8:8 +#define INT_STATUS_DMA_INACTIVE 0 +#define INT_STATUS_DMA_ACTIVE 1 +#define INT_STATUS_PCI 7:7 +#define INT_STATUS_PCI_INACTIVE 0 +#define INT_STATUS_PCI_ACTIVE 1 +#define INT_STATUS_HDMI 6:6 +#define INT_STATUS_HDMI_INACTIVE 0 +#define INT_STATUS_HDMI_ACTIVE 1 +#define INT_STATUS_CSC 5:5 +#define INT_STATUS_CSC_INACTIVE 0 +#define INT_STATUS_CSC_ACTIVE 1 +#define INT_STATUS_DE 4:4 +#define INT_STATUS_DE_INACTIVE 0 +#define INT_STATUS_DE_ACTIVE 1 +#define INT_STATUS_ZVPORT_VSYNC 3:3 +#define INT_STATUS_ZVPORT_VSYNC_INACTIVE 0 +#define INT_STATUS_ZVPORT_VSYNC_ACTIVE 1 +#define INT_STATUS_CHANNEL1_VSYNC 2:2 +#define INT_STATUS_CHANNEL1_VSYNC_INACTIVE 0 +#define INT_STATUS_CHANNEL1_VSYNC_ACTIVE 1 +#define INT_STATUS_CHANNEL0_VSYNC 1:1 +#define INT_STATUS_CHANNEL0_VSYNC_INACTIVE 0 +#define INT_STATUS_CHANNEL0_VSYNC_ACTIVE 1 +#define INT_STATUS_VGA_VSYNC 0:0 +#define INT_STATUS_VGA_VSYNC_INACTIVE 0 +#define INT_STATUS_VGA_VSYNC_ACTIVE 1 + +#ifdef SMI_ARM +#define INT_MASK 0x00009C +#else +#define INT_MASK 0x000098 +#endif + +#define INT_MASK_TIMER3 31:31 +#define INT_MASK_TIMER3_DISABLE 0 +#define INT_MASK_TIMER3_ENABLE 1 +#define INT_MASK_TIMER2 30:30 +#define INT_MASK_TIMER2_DISABLE 0 +#define INT_MASK_TIMER2_ENABLE 1 +#define INT_MASK_TIMER1 29:29 +#define INT_MASK_TIMER1_DISABLE 0 +#define INT_MASK_TIMER1_ENABLE 1 +#define INT_MASK_TIMER0 28:28 +#define INT_MASK_TIMER0_DISABLE 0 +#define INT_MASK_TIMER0_ENABLE 1 +#define INT_MASK_VPU 27:27 +#define INT_MASK_VPU_DISABLE 0 +#define INT_MASK_VPU_ENABLE 1 +#define INT_MASK_JPU 26:26 +#define INT_MASK_JPU_DISABLE 0 +#define INT_MASK_JPU_ENABLE 1 +#define INT_MASK_USBH 25:25 +#define INT_MASK_USBH_DISABLE 0 +#define INT_MASK_USBH_ENABLE 1 +#define INT_MASK_USBS 24:24 +#define INT_MASK_USBS_DISABLE 0 +#define INT_MASK_USBS_ENABLE 1 +#define INT_MASK_I2S 23:23 +#define INT_MASK_I2S_DISABLE 0 +#define INT_MASK_I2S_ENABLE 1 +#define INT_MASK_UART1 22:22 +#define INT_MASK_UART1_DISABLE 0 +#define INT_MASK_UART1_ENABLE 1 +#define INT_MASK_UART0 21:21 +#define INT_MASK_UART0_DISABLE 0 +#define INT_MASK_UART0_ENABLE 1 +#define INT_MASK_SSP1 20:20 +#define INT_MASK_SSP1_DISABLE 0 +#define INT_MASK_SSP1_ENABLE 1 +#define INT_MASK_SSP0 19:19 +#define INT_MASK_SSP0_DISABLE 0 +#define INT_MASK_SSP0_ENABLE 1 +#define INT_MASK_I2C1 18:18 +#define INT_MASK_I2C1_DISABLE 0 +#define INT_MASK_I2C1_ENABLE 1 +#define INT_MASK_I2C0 17:17 +#define INT_MASK_I2C0_DISABLE 0 +#define INT_MASK_I2C0_ENABLE 1 +#define INT_MASK_PWM 16:16 +#define INT_MASK_PWM_DISABLE 0 +#define INT_MASK_PWM_ENABLE 1 +#define INT_MASK_GPIO6 15:15 +#define INT_MASK_GPIO6_DISABLE 0 +#define INT_MASK_GPIO6_ENABLE 1 +#define INT_MASK_GPIO5 14:14 +#define INT_MASK_GPIO5_DISABLE 0 +#define INT_MASK_GPIO5_ENABLE 1 +#define INT_MASK_GPIO4 13:13 +#define INT_MASK_GPIO4_DISABLE 0 +#define INT_MASK_GPIO4_ENABLE 1 +#define INT_MASK_GPIO3 12:12 +#define INT_MASK_GPIO3_DISABLE 0 +#define INT_MASK_GPIO3_ENABLE 1 +#define INT_MASK_GPIO2 11:11 +#define INT_MASK_GPIO2_DISABLE 0 +#define INT_MASK_GPIO2_ENABLE 1 +#define INT_MASK_GPIO1 10:10 +#define INT_MASK_GPIO1_DISABLE 0 +#define INT_MASK_GPIO1_ENABLE 1 +#define INT_MASK_GPIO0 9:9 +#define INT_MASK_GPIO0_DISABLE 0 +#define INT_MASK_GPIO0_ENABLE 1 +#define INT_MASK_DMA 8:8 +#define INT_MASK_DMA_DISABLE 0 +#define INT_MASK_DMA_ENABLE 1 +#define INT_MASK_CPU 7:7 +#define INT_MASK_CPU_DISABLE 0 +#define INT_MASK_CPU_ENABLE 1 +#define INT_MASK_HDMI 6:6 +#define INT_MASK_HDMI_DISABLE 0 +#define INT_MASK_HDMI_ENABLE 1 +#define INT_MASK_CSC 5:5 +#define INT_MASK_CSC_DISABLE 0 +#define INT_MASK_CSC_ENABLE 1 +#define INT_MASK_DE 4:4 +#define INT_MASK_DE_DISABLE 0 +#define INT_MASK_DE_ENABLE 1 +#define INT_MASK_ZVPORT_VSYNC 3:3 +#define INT_MASK_ZVPORT_VSYNC_DISABLE 0 +#define INT_MASK_ZVPORT_VSYNC_ENABLE 1 +#define INT_MASK_CHANNEL1_VSYNC 2:2 +#define INT_MASK_CHANNEL1_VSYNC_DISABLE 0 +#define INT_MASK_CHANNEL1_VSYNC_ENABLE 1 +#define INT_MASK_CHANNEL0_VSYNC 1:1 +#define INT_MASK_CHANNEL0_VSYNC_DISABLE 0 +#define INT_MASK_CHANNEL0_VSYNC_ENABLE 1 +#define INT_MASK_VGA_VSYNC 0:0 +#define INT_MASK_VGA_VSYNC_DISABLE 0 +#define INT_MASK_VGA_VSYNC_ENABLE 1 + +#define ARM_PROTOCOL_INT 0x0000A0 +#define ARM_PROTOCOL_INT_TOKEN 31:1 +#define ARM_PROTOCOL_INT_ENABLE 0:0 +#define ARM_PROTOCOL_INT_ENABLE_CLEAR 0 +#define ARM_PROTOCOL_INT_ENABLE_ENABLE 1 + +#define PCIE_PROTOCOL_INT 0x0000A4 +#define PCIE_PROTOCOL_INT_TOKEN 31:1 +#define PCIE_PROTOCOL_INT_ENABLE 0:0 +#define PCIE_PROTOCOL_INT_ENABLE_CLEAR 0 +#define PCIE_PROTOCOL_INT_ENABLE_ENABLE 1 + +#define ARM_STARTUP_CONFIG 0x000100 +#define ARM_STARTUP_CONFIG_USBH 30:30 +#define ARM_STARTUP_CONFIG_USBH_NORMAL 0 +#define ARM_STARTUP_CONFIG_USBH_RESET 1 +#define ARM_STARTUP_CONFIG_USBHPHY 29:29 +#define ARM_STARTUP_CONFIG_USBHPHY_NORMAL 0 +#define ARM_STARTUP_CONFIG_USBHPHY_RESET 1 +#define ARM_STARTUP_CONFIG_USBSPHY 28:28 +#define ARM_STARTUP_CONFIG_USBSPHY_NORMAL 0 +#define ARM_STARTUP_CONFIG_USBSPHY_RESET 1 +#define ARM_STARTUP_CONFIG_USBS 27:27 +#define ARM_STARTUP_CONFIG_USBS_NORMAL 0 +#define ARM_STARTUP_CONFIG_USBS_RESET 1 +#define ARM_STARTUP_CONFIG_ARM 0:0 +#define ARM_STARTUP_CONFIG_ARM_STOP 0 +#define ARM_STARTUP_CONFIG_ARM_START 1 + +#define ARM_CONTROL 0x000110 +#define ARM_CONTROL_RESET 0:0 +#define ARM_CONTROL_RESET_RESET 0 +#define ARM_CONTROL_RESET_NORMAL 1 + +/* DDK shoudn't need to program this register */ +#define USBH_CLOCK 0x00114 +#define USBH_CLOCK_31_13 31:13 +#define USBH_CLOCK_FS_IIS 12:8 +#define USBH_CLOCK_7_6 7:6 +#define USBH_CLOCK_PD 5:5 +#define USBH_CLOCK_PD_NORMAL 0 +#define USBH_CLOCK_PD_PDPLL 1 +#define USBH_CLOCK_HS 4:0 + + +#define TEST_CONTROL 0x00011C +#define TEST_CONTROL_I2C 11:11 +#define TEST_CONTROL_I2C_I2C1 0 +#define TEST_CONTROL_I2C_HDMI 1 +#define TEST_CONTROL_SSP1 10:10 +#define TEST_CONTROL_SSP1_GPIO 0 +#define TEST_CONTROL_SSP1_USBSPHY 1 + + +#define STRAP_PINS 0x00012C +#define STRAP_PINS_DEV_ID 15:14 +#define STRAP_PINS_DEV_ID_SM768 0 +#define STRAP_PINS_DEV_ID_SM765 1 +#define STRAP_PINS_DEV_ID_SM766 2 +#define STRAP_PINS_AUDIO 13:13 +#define STRAP_PINS_AUDIO_ENABLE 0 +#define STRAP_PINS_AUDIO_DISABLE 1 +#define STRAP_PINS_CRYSTAL_CONFIG 12:12 +#define STRAP_PINS_CRYSTAL_CONFIG_24000 0 +#define STRAP_PINS_CRYSTAL_CONFIG_24576 1 +#define STRAP_PINS_PIXEL_CONFIG 10:10 +#define STRAP_PINS_PIXEL_CONFIG_FULL 0 +#define STRAP_PINS_PIXEL_CONFIG_HALF 1 + + +#define STRAP_PINS_MEM_SIZE 1:0 +#define STRAP_PINS_MEM_SIZE_128M 0 +#define STRAP_PINS_MEM_SIZE_256M 1 +#define STRAP_PINS_MEM_SIZE_512M 2 +#define STRAP_PINS_MEM_SIZE_1024M 3 + + +#define DDR_CONTROL 0x000130 +#define DDR_CONTROL_COL 3:2 +#define DDR_CONTROL_COL_1024 0 +#define DDR_CONTROL_COL_2048 1 +#define DDR_CONTROL_COL_256 2 +#define DDR_CONTROL_COL_512 3 +#define DDR_CONTROL_SIZE 1:0 +#define DDR_CONTROL_SIZE_256M 0 +#define DDR_CONTROL_SIZE_512M 1 +#define DDR_CONTROL_SIZE_1024M 2 +#define DDR_CONTROL_SIZE_128M 3 + +#define JPU_PERFORMANCE_MODE 0x000134 +#define JPU_PERFORMANCE_MODE_JPU1 3:2 +#define JPU_PERFORMANCE_MODE_JPU1_DISABLE 0 +#define JPU_PERFORMANCE_MODE_JPU1_HD 1 +#define JPU_PERFORMANCE_MODE_JPU1_UHD 2 +#define JPU_PERFORMANCE_MODE_JPU0 1:0 +#define JPU_PERFORMANCE_MODE_JPU0_DISABLE 0 +#define JPU_PERFORMANCE_MODE_JPU0_HD 1 +#define JPU_PERFORMANCE_MODE_JPU0_UHD 2 + +#define DDR_PRIORITY1 0x000138 + +#define DDR_PRIORITY2 0x00013C + + +//#include "reggpio.h" + + + +#define GPIO_DATA 0x010000 +#define GPIO_DATA_IIC0_DATA_DVI_SHIFT 31 +#define GPIO_DATA_IIC0_CLK_DVI_SHIFT 30 +#define GPIO_DATA_SSP1_CLK_OUT_SHIFT 29 +#define GPIO_DATA_GPIO_CODEC_DATA_SHIFT 29 +#define GPIO_DATA_SSP1_FRAMEINPUT_SHIFT 28 +#define GPIO_DATA_IIS_RX_SHIFT 28 +#define GPIO_DATA_SSP1_FRAMEOUT_SHIFT 27 +#define GPIO_DATA_GPIO_IIS_TX_SHIFT 27 +#define GPIO_DATA_SSP1_RX_SHIFT 26 +#define GPIO_DATA_GPIO_IIS_WS_SHIFT 26 +#define GPIO_DATA_SSP1_TX_SHIFT 25 +#define GPIO_DATA_GPIO_IIS_CLK_SHIFT 25 +#define GPIO_DATA_SSP0_CLK_OUT_SHIFT 24 +#define GPIO_DATA_GPIO_SWSSP_CLK_OUT_SHIFT 24 +#define GPIO_DATA_SSP0_FRAMINPUT_SHIFT 23 +#define GPIO_DATA_GPIO_SWSSP_FRAMINPUT_SHIFT 23 +#define GPIO_DATA_SSP0_FRAMEOUT_SHIFT 22 +#define GPIO_DATA_GPIO_SWSSP_FRAMEOUT_SHIFT 22 +#define GPIO_DATA_SSP0_RX_SHIFT 21 +#define GPIO_DATA_GPIO_SWSSP_RX_SHIFT 21 +#define GPIO_DATA_SSP0_TX_SHIFT 20 +#define GPIO_DATA_GPIO_SWSSP_TX_SHIFT 20 +#define GPIO_DATA_PWM2_SHIFT 19 +#define GPIO_DATA_GPIO_UART1_EXT_CLK_SHIFT 19 +#define GPIO_DATA_GPIO_UART0_EXT_CLK_SHIFT 19 +#define GPIO_DATA_PWM1_SHIFT 18 +#define GPIO_DATA_PWM0_SHIFT 17 +#define GPIO_DATA_PCIE_SHIFT 16 +#define GPIO_DATA_UART0_SIN_SHIFT 15 +#define GPIO_DATA_UART0_NCTSIN_SHIFT 14 +#define GPIO_DATA_UART0_TXD_SHIFT 13 +#define GPIO_DATA_UART0_NRTS_SHIFT 12 +#define GPIO_DATA_UART1_SIN_SHIFT 11 +#define GPIO_DATA_GPIO_CODEC_CLK_SHIFT 11 +#define GPIO_DATA_UART1_NCTSIN_SHIFT 10 +#define GPIO_DATA_GPIO_CODEC_MODE_SHIFT 10 +#define GPIO_DATA_UART1_TXD_SHIFT 9 +#define GPIO_DATA_GPIO_IIC_DATA_HDMI_SHIFT 9 +#define GPIO_DATA_GPIO_IIC_CLK_HDMI_SHIFT 8 +#define GPIO_DATA_UART1_NRTS_SHIFT 8 +#define GPIO_DATA_IIC1_DATA_CRT_SHIFT 7 +#define GPIO_DATA_IIC1_CLK_CRT_SHIFT 6 +#define GPIO_DATA_GPIO_VBUS_SHIFT 5 +#define GPIO_DATA_IIS_TX_SELECT_SHIFT 4 +#define GPIO_DATA_GPIO_DVI_PNP_SHIFT 4 +#define GPIO_DATA_IIS_WS_SELECT_SHIFT 3 +#define GPIO_DATA_GPIO_AUDIO_PNP_SHIFT 3 +#define GPIO_DATA_IIS_CLK_SELECT_SHIFT 2 +#define GPIO_DATA_UART1_EXT_CLK_SELECT_SHIFT 1 +#define GPIO_DATA_GPIO_HDMI_PNP_SHIFT 1 +#define GPIO_DATA_UART0_EXT_CLK_SELECT_SHIFT 0 + +#define GPIO_DATA_DIRECTION 0x010004 +#define GPIO_DATA_DIRECTION_IIC0_DATA_DVI_SHIFT 31 +#define GPIO_DATA_DIRECTION_IIC0_CLK_DVI_SHIFT 30 +#define GPIO_DATA_DIRECTION_SSP1_CLK_OUT_SHIFT 29 +#define GPIO_DATA_DIRECTION_GPIO_CODEC_DATA_SHIFT 29 +#define GPIO_DATA_DIRECTION_SSP1_FRAMEINPUT_SHIFT 28 +#define GPIO_DATA_DIRECTION_IIS_RX_SHIFT 28 +#define GPIO_DATA_DIRECTION_SSP1_FRAMEOUT_SHIFT 27 +#define GPIO_DATA_DIRECTION_GPIO_IIS_TX_SHIFT 27 +#define GPIO_DATA_DIRECTION_SSP1_RX_SHIFT 26 +#define GPIO_DATA_DIRECTION_GPIO_IIS_WS_SHIFT 26 +#define GPIO_DATA_DIRECTION_SSP1_TX_SHIFT 25 +#define GPIO_DATA_DIRECTION_GPIO_IIS_CLK_SHIFT 25 +#define GPIO_DATA_DIRECTION_SSP0_CLK_OUT_SHIFT 24 +#define GPIO_DATA_DIRECTION_GPIO_SWSSP_CLK_OUT_SHIFT 24 +#define GPIO_DATA_DIRECTION_SSP0_FRAMEINPUT_SHIFT 23 +#define GPIO_DATA_DIRECTION_GPIO_SWSSP_FRAMEINPUT_SHIFT 23 +#define GPIO_DATA_DIRECTION_SSP0_FRAMEOUT_SHIFT 22 +#define GPIO_DATA_DIRECTION_GPIO_SWSSP_FRAMEOUT_SHIFT 22 +#define GPIO_DATA_DIRECTION_SSP0_RX_SHIFT 21 +#define GPIO_DATA_DIRECTION_GPIO_SWSSP_RX_SHIFT 21 +#define GPIO_DATA_DIRECTION_SSP0_TX_SHIFT 20 +#define GPIO_DATA_DIRECTION_GPIO_SWSSP_TX_SHIFT 20 +#define GPIO_DATA_DIRECTION_PWM2_SHIFT 19 +#define GPIO_DATA_DIRECTION_GPIO_UART1_EXT_CLK_SHIFT 19 +#define GPIO_DATA_DIRECTION_GPIO_UART0_EXT_CLK_SHIFT 19 +#define GPIO_DATA_DIRECTION_PWM1_SHIFT 18 +#define GPIO_DATA_DIRECTION_PWM0_SHIFT 17 +#define GPIO_DATA_DIRECTION_PCIE_SHIFT 16 +#define GPIO_DATA_DIRECTION_UART0_SIN_SHIFT 15 +#define GPIO_DATA_DIRECTION_UART0_NCTSIN_SHIFT 14 +#define GPIO_DATA_DIRECTION_UART0_TXD_SHIFT 13 +#define GPIO_DATA_DIRECTION_UART0_NRTS_SHIFT 12 +#define GPIO_DATA_DIRECTION_UART1_SIN_SHIFT 11 +#define GPIO_DATA_DIRECTION_GPIO_CODEC_CLK_SHIFT 11 +#define GPIO_DATA_DIRECTION_UART1_NCTSIN_SHIFT 10 +#define GPIO_DATA_DIRECTION_GPIO_CODEC_MODE_SHIFT 10 +#define GPIO_DATA_DIRECTION_UART1_TXD_SHIFT 9 +#define GPIO_DATA_DIRECTION_GPIO_IIC_DATA_HDMI_SHIFT 9 +#define GPIO_DATA_DIRECTION_GPIO_IIC_CLK_HDMI_SHIFT 8 +#define GPIO_DATA_DIRECTION_UART1_NRTS_SHIFT 8 +#define GPIO_DATA_DIRECTION_IIC1_DATA_CRT_SHIFT 7 +#define GPIO_DATA_DIRECTION_IIC1_CLK_CRT_SHIFT 6 +#define GPIO_DATA_DIRECTION_GPIO_VBUS_SHIFT 5 +#define GPIO_DATA_DIRECTION_IIS_TX_SELECT_SHIFT 4 +#define GPIO_DATA_DIRECTION_GPIO_DVI_PNP_SHIFT 4 +#define GPIO_DATA_DIRECTION_IIS_WS_SELECT_SHIFT 3 +#define GPIO_DATA_DIRECTION_GPIO_AUDIO_PNP_SHIFT 3 +#define GPIO_DATA_DIRECTION_IIS_CLK_SELECT_SHIFT 2 +#define GPIO_DATA_DIRECTION_UART1_EXT_CLK_SELECT_SHIFT 1 +#define GPIO_DATA_DIRECTION_GPIO_HDMI_PNP_SHIFT 1 +#define GPIO_DATA_DIRECTION_UART0_EXT_CLK_SELECT_SHIFT 0 + + +#define GPIO_INTERRUPT_SETUP 0x010008 +#define GPIO_INTERRUPT_SETUP_VBUS_TRIGGER_EDGE_SHIFT 21 +#define GPIO_INTERRUPT_SETUP_VBUS_TRIGGER_LEVEL_SHIFT 21 +#define GPIO_INTERRUPT_SETUP_DVI_PNP_TRIGGER_EDGE_SHIFT 20 +#define GPIO_INTERRUPT_SETUP_DVI_PNP_TRIGGER_LEVEL_SHIFT 20 +#define GPIO_INTERRUPT_SETUP_AUDIO_PNP_TRIGGER_EDGE_SHIFT 19 +#define GPIO_INTERRUPT_SETUP_AUDIO_PNP_TRIGGER_LEVEL_SHIFT 19 +#define GPIO_INTERRUPT_SETUP_HDMI_PNP_TRIGGER_EDGE_SHIFT 17 +#define GPIO_INTERRUPT_SETUP_HDMI_PNP_TRIGGER_LEVEL_SHIFT 17 + + +#define GPIO_INTERRUPT_SETUP_VBUS_ACTIVE_LOW_SHIFT 13 +#define GPIO_INTERRUPT_SETUP_VBUS_ACTIVE_HIGH_SHIFT 13 +#define GPIO_INTERRUPT_SETUP_DVI_PNP_ACTIVE_LOW_SHIFT 12 +#define GPIO_INTERRUPT_SETUP_DVI_PNP_ACTIVE_HIGH_SHIFT 12 +#define GPIO_INTERRUPT_SETUP_AUDIO_PNP_ACTIVE_LOW_SHIFT 11 +#define GPIO_INTERRUPT_SETUP_AUDIO_PNP_ACTIVE_HIGH_SHIFT 11 +#define GPIO_INTERRUPT_SETUP_HDMI_PNP_ACTIVE_LOW_SHIFT 9 +#define GPIO_INTERRUPT_SETUP_HDMI_PNP_ACTIVE_HIGH_SHIFT 9 + + +#define GPIO_INTERRUPT_SETUP_VBUS_ENABLE_SHIFT 5 +#define GPIO_INTERRUPT_SETUP_VBUS_GPIO_ENABLE_SHIFT 5 +#define GPIO_INTERRUPT_SETUP_DVI_PNP_ENABLE_SHIFT 4 +#define GPIO_INTERRUPT_SETUP_DVI_PNP_GPIO_ENABLE_SHIFT 4 +#define GPIO_INTERRUPT_SETUP_AUDIO_PNP_ENABLE_SHIFT 3 +#define GPIO_INTERRUPT_SETUP_AUDIO_PNP_GPIO_ENABLE_SHIFT 3 +#define GPIO_INTERRUPT_SETUP_HDMI_PNP_ENABLE_SHIFT 1 +#define GPIO_INTERRUPT_SETUP_HDMI_PNP_GPIO_ENABLE_SHIFT 1 + +#define GPIO_INTERRUPT_STATUS 0x01000C +#define GPIO_INTERRUPT_STATUS_VBUS_INACTIVE 5 +#define GPIO_INTERRUPT_STATUS_VBUS_ACTIVE 5 +#define GPIO_INTERRUPT_STATUS_VBUS_RESET 5 +#define GPIO_INTERRUPT_STATUS_DVI_PNP_INACTIVE 4 +#define GPIO_INTERRUPT_STATUS_DVI_PNP_ACTIVE 4 +#define GPIO_INTERRUPT_STATUS_DVI_PNP_RESET 4 +#define GPIO_INTERRUPT_STATUS_AUDIO_PNP_INACTIVE 3 +#define GPIO_INTERRUPT_STATUS_AUDIO_PNP_ACTIVE 3 +#define GPIO_INTERRUPT_STATUS_AUDIO_PNP_RESET 3 +#define GPIO_INTERRUPT_STATUS_HDMI_PNP_INACTIVE 1 +#define GPIO_INTERRUPT_STATUS_HDMI_PNP_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_HDMI_PNP_RESET 1 + +/*xxx_GPIO_xxxx means 0 is valid*/ +#define GPIO_MUX 0x010010 +#define GPIO_MUX_IIC0_DATA_DVI_SHIFT 31 +#define GPIO_MUX_IIC0_CLK_DVI_SHIFT 30 +#define GPIO_MUX_SSP1_CLK_OUT_SHIFT 29 +#define GPIO_MUX_GPIO_CODEC_DATA_SHIFT 29 +#define GPIO_MUX_SSP1_FRAMEINPUT_SHIFT 28 +#define GPIO_MUX_IIS_RX_SHIFT 28 +#define GPIO_MUX_SSP1_FRAMEOUT_SHIFT 27 +#define GPIO_MUX_GPIO_IIS_TX_SHIFT 27 +#define GPIO_MUX_SSP1_RX_SHIFT 26 +#define GPIO_MUX_GPIO_IIS_WS_SHIFT 26 +#define GPIO_MUX_SSP1_TX_SHIFT 25 +#define GPIO_MUX_GPIO_IIS_CLK_SHIFT 25 +#define GPIO_MUX_SSP0_CLK_OUT_SHIFT 24 +#define GPIO_MUX_GPIO_SWSSP_CLK_OUT_SHIFT 24 +#define GPIO_MUX_SSP0_FRAMEINPUT_SHIFT 23 +#define GPIO_MUX_GPIO_SWSSP_FRAMEINPUT_SHIFT 23 +#define GPIO_MUX_SSP0_FRAMEOUT_SHIFT 22 +#define GPIO_MUX_GPIO_SWSSP_FRAMEOUT_SHIFT 22 +#define GPIO_MUX_SSP0_RX_SHIFT 21 +#define GPIO_MUX_GPIO_SWSSP_RX_SHIFT 21 +#define GPIO_MUX_SSP0_TX_SHIFT 20 +#define GPIO_MUX_GPIO_SWSSP_TX_SHIFT 20 +#define GPIO_MUX_PWM2_SHIFT 19 +#define GPIO_MUX_GPIO_UART1_EXT_CLK_SHIFT 19 +#define GPIO_MUX_GPIO_UART0_EXT_CLK_SHIFT 19 +#define GPIO_MUX_PWM1_SHIFT 18 +#define GPIO_MUX_PWM0_SHIFT 17 +#define GPIO_MUX_PCIE_SHIFT 16 +#define GPIO_MUX_UART0_SIN_SHIFT 15 +#define GPIO_MUX_UART0_NCTSIN_SHIFT 14 +#define GPIO_MUX_UART0_TXD_SHIFT 13 +#define GPIO_MUX_UART0_NRTS_SHIFT 12 +#define GPIO_MUX_UART1_SIN_SHIFT 11 +#define GPIO_MUX_GPIO_CODEC_CLK_SHIFT 11 +#define GPIO_MUX_UART1_NCTSIN_SHIFT 10 +#define GPIO_MUX_GPIO_CODEC_MODE_SHIFT 10 +#define GPIO_MUX_UART1_TXD_SHIFT 9 +#define GPIO_MUX_GPIO_IIC_DATA_HDMI_SHIFT 9 +#define GPIO_MUX_GPIO_IIC_CLK_HDMI_SHIFT 8 +#define GPIO_MUX_UART1_NRTS_SHIFT 8 +#define GPIO_MUX_IIC1_DATA_CRT_SHIFT 7 +#define GPIO_MUX_IIC1_CLK_CRT_SHIFT 6 +#define GPIO_MUX_GPIO_VBUS_SHIFT 5 +#define GPIO_MUX_IIS_TX_SELECT_SHIFT 4 +#define GPIO_MUX_GPIO_DVI_PNP_SHIFT 4 +#define GPIO_MUX_IIS_WS_SELECT_SHIFT 3 +#define GPIO_MUX_GPIO_AUDIO_PNP_SHIFT 3 +#define GPIO_MUX_IIS_CLK_SELECT_SHIFT 2 +#define GPIO_MUX_UART1_EXT_CLK_SELECT_SHIFT 1 +#define GPIO_MUX_GPIO_HDMI_PNP_SHIFT 1 +#define GPIO_MUX_UART0_EXT_CLK_SELECT_SHIFT 0 + + + +#define GPIO_DATA_31 31:31 +#define GPIO_DATA_30 30:30 +#define GPIO_DATA_29 29:29 +#define GPIO_DATA_28 28:28 +#define GPIO_DATA_27 27:27 +#define GPIO_DATA_26 26:26 +#define GPIO_DATA_25 25:25 +#define GPIO_DATA_24 24:24 +#define GPIO_DATA_23 23:23 +#define GPIO_DATA_22 22:22 +#define GPIO_DATA_21 21:21 +#define GPIO_DATA_20 20:20 +#define GPIO_DATA_19 19:19 +#define GPIO_DATA_18 18:18 +#define GPIO_DATA_17 17:17 +#define GPIO_DATA_16 16:16 +#define GPIO_DATA_15 15:15 +#define GPIO_DATA_14 14:14 +#define GPIO_DATA_13 13:13 +#define GPIO_DATA_12 12:12 +#define GPIO_DATA_11 11:11 +#define GPIO_DATA_10 10:10 +#define GPIO_DATA_9 9:9 +#define GPIO_DATA_8 8:8 +#define GPIO_DATA_7 7:7 +#define GPIO_DATA_6 6:6 +#define GPIO_DATA_5 5:5 +#define GPIO_DATA_4 4:4 +#define GPIO_DATA_3 3:3 +#define GPIO_DATA_2 2:2 +#define GPIO_DATA_1 1:1 +#define GPIO_DATA_0 0:0 + + +#define GPIO_DATA_DIRECTION_31 31:31 +#define GPIO_DATA_DIRECTION_31_INPUT 0 +#define GPIO_DATA_DIRECTION_31_OUTPUT 1 +#define GPIO_DATA_DIRECTION_30 30:30 +#define GPIO_DATA_DIRECTION_30_INPUT 0 +#define GPIO_DATA_DIRECTION_30_OUTPUT 1 +#define GPIO_DATA_DIRECTION_29 29:29 +#define GPIO_DATA_DIRECTION_29_INPUT 0 +#define GPIO_DATA_DIRECTION_29_OUTPUT 1 +#define GPIO_DATA_DIRECTION_28 28:28 +#define GPIO_DATA_DIRECTION_28_INPUT 0 +#define GPIO_DATA_DIRECTION_28_OUTPUT 1 +#define GPIO_DATA_DIRECTION_27 27:27 +#define GPIO_DATA_DIRECTION_27_INPUT 0 +#define GPIO_DATA_DIRECTION_27_OUTPUT 1 +#define GPIO_DATA_DIRECTION_26 26:26 +#define GPIO_DATA_DIRECTION_26_INPUT 0 +#define GPIO_DATA_DIRECTION_26_OUTPUT 1 +#define GPIO_DATA_DIRECTION_25 25:25 +#define GPIO_DATA_DIRECTION_25_INPUT 0 +#define GPIO_DATA_DIRECTION_25_OUTPUT 1 +#define GPIO_DATA_DIRECTION_24 24:24 +#define GPIO_DATA_DIRECTION_24_INPUT 0 +#define GPIO_DATA_DIRECTION_24_OUTPUT 1 +#define GPIO_DATA_DIRECTION_23 23:23 +#define GPIO_DATA_DIRECTION_23_INPUT 0 +#define GPIO_DATA_DIRECTION_23_OUTPUT 1 +#define GPIO_DATA_DIRECTION_22 22:22 +#define GPIO_DATA_DIRECTION_22_INPUT 0 +#define GPIO_DATA_DIRECTION_22_OUTPUT 1 +#define GPIO_DATA_DIRECTION_21 21:21 +#define GPIO_DATA_DIRECTION_21_INPUT 0 +#define GPIO_DATA_DIRECTION_21_OUTPUT 1 +#define GPIO_DATA_DIRECTION_20 20:20 +#define GPIO_DATA_DIRECTION_20_INPUT 0 +#define GPIO_DATA_DIRECTION_20_OUTPUT 1 +#define GPIO_DATA_DIRECTION_19 19:19 +#define GPIO_DATA_DIRECTION_19_INPUT 0 +#define GPIO_DATA_DIRECTION_19_OUTPUT 1 +#define GPIO_DATA_DIRECTION_18 18:18 +#define GPIO_DATA_DIRECTION_18_INPUT 0 +#define GPIO_DATA_DIRECTION_18_OUTPUT 1 +#define GPIO_DATA_DIRECTION_17 17:17 +#define GPIO_DATA_DIRECTION_17_INPUT 0 +#define GPIO_DATA_DIRECTION_17_OUTPUT 1 +#define GPIO_DATA_DIRECTION_16 16:16 +#define GPIO_DATA_DIRECTION_16_INPUT 0 +#define GPIO_DATA_DIRECTION_16_OUTPUT 1 +#define GPIO_DATA_DIRECTION_15 15:15 +#define GPIO_DATA_DIRECTION_15_INPUT 0 +#define GPIO_DATA_DIRECTION_15_OUTPUT 1 +#define GPIO_DATA_DIRECTION_14 14:14 +#define GPIO_DATA_DIRECTION_14_INPUT 0 +#define GPIO_DATA_DIRECTION_14_OUTPUT 1 +#define GPIO_DATA_DIRECTION_13 13:13 +#define GPIO_DATA_DIRECTION_13_INPUT 0 +#define GPIO_DATA_DIRECTION_13_OUTPUT 1 +#define GPIO_DATA_DIRECTION_12 12:12 +#define GPIO_DATA_DIRECTION_12_INPUT 0 +#define GPIO_DATA_DIRECTION_12_OUTPUT 1 +#define GPIO_DATA_DIRECTION_11 11:11 +#define GPIO_DATA_DIRECTION_11_INPUT 0 +#define GPIO_DATA_DIRECTION_11_OUTPUT 1 +#define GPIO_DATA_DIRECTION_10 10:10 +#define GPIO_DATA_DIRECTION_10_INPUT 0 +#define GPIO_DATA_DIRECTION_10_OUTPUT 1 +#define GPIO_DATA_DIRECTION_9 9:9 +#define GPIO_DATA_DIRECTION_9_INPUT 0 +#define GPIO_DATA_DIRECTION_9_OUTPUT 1 +#define GPIO_DATA_DIRECTION_8 8:8 +#define GPIO_DATA_DIRECTION_8_INPUT 0 +#define GPIO_DATA_DIRECTION_8_OUTPUT 1 +#define GPIO_DATA_DIRECTION_7 7:7 +#define GPIO_DATA_DIRECTION_7_INPUT 0 +#define GPIO_DATA_DIRECTION_7_OUTPUT 1 +#define GPIO_DATA_DIRECTION_6 6:6 +#define GPIO_DATA_DIRECTION_6_INPUT 0 +#define GPIO_DATA_DIRECTION_6_OUTPUT 1 +#define GPIO_DATA_DIRECTION_5 5:5 +#define GPIO_DATA_DIRECTION_5_INPUT 0 +#define GPIO_DATA_DIRECTION_5_OUTPUT 1 +#define GPIO_DATA_DIRECTION_4 4:4 +#define GPIO_DATA_DIRECTION_4_INPUT 0 +#define GPIO_DATA_DIRECTION_4_OUTPUT 1 +#define GPIO_DATA_DIRECTION_3 3:3 +#define GPIO_DATA_DIRECTION_3_INPUT 0 +#define GPIO_DATA_DIRECTION_3_OUTPUT 1 +#define GPIO_DATA_DIRECTION_2 2:2 +#define GPIO_DATA_DIRECTION_2_INPUT 0 +#define GPIO_DATA_DIRECTION_2_OUTPUT 1 +#define GPIO_DATA_DIRECTION_1 1:1 +#define GPIO_DATA_DIRECTION_1_INPUT 0 +#define GPIO_DATA_DIRECTION_1_OUTPUT 1 +#define GPIO_DATA_DIRECTION_0 0:0 +#define GPIO_DATA_DIRECTION_0_INPUT 0 +#define GPIO_DATA_DIRECTION_0_OUTPUT 1 + + +#define GPIO_INTERRUPT_SETUP_TRIGGER_31 22:22 +#define GPIO_INTERRUPT_SETUP_TRIGGER_31_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_31_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_30 21:21 +#define GPIO_INTERRUPT_SETUP_TRIGGER_30_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_30_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_29 20:20 +#define GPIO_INTERRUPT_SETUP_TRIGGER_29_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_29_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_28 19:19 +#define GPIO_INTERRUPT_SETUP_TRIGGER_28_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_28_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_27 18:18 +#define GPIO_INTERRUPT_SETUP_TRIGGER_27_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_27_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_26 17:17 +#define GPIO_INTERRUPT_SETUP_TRIGGER_26_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_26_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_25 16:16 +#define GPIO_INTERRUPT_SETUP_TRIGGER_25_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_25_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_31 14:14 +#define GPIO_INTERRUPT_SETUP_ACTIVE_31_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_31_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_30 13:13 +#define GPIO_INTERRUPT_SETUP_ACTIVE_30_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_30_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_29 12:12 +#define GPIO_INTERRUPT_SETUP_ACTIVE_29_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_29_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_28 11:11 +#define GPIO_INTERRUPT_SETUP_ACTIVE_28_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_28_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_27 10:10 +#define GPIO_INTERRUPT_SETUP_ACTIVE_27_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_27_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_26 9:9 +#define GPIO_INTERRUPT_SETUP_ACTIVE_26_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_26_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_25 8:8 +#define GPIO_INTERRUPT_SETUP_ACTIVE_25_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_25_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_31 6:6 +#define GPIO_INTERRUPT_SETUP_ENABLE_31_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_31_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_30 5:5 +#define GPIO_INTERRUPT_SETUP_ENABLE_30_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_30_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_29 4:4 +#define GPIO_INTERRUPT_SETUP_ENABLE_29_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_29_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_28 3:3 +#define GPIO_INTERRUPT_SETUP_ENABLE_28_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_28_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_27 2:2 +#define GPIO_INTERRUPT_SETUP_ENABLE_27_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_27_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_26 1:1 +#define GPIO_INTERRUPT_SETUP_ENABLE_26_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_26_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_25 0:0 +#define GPIO_INTERRUPT_SETUP_ENABLE_25_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_25_INTERRUPT 1 + + +#define GPIO_INTERRUPT_STATUS_31 22:22 +#define GPIO_INTERRUPT_STATUS_31_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_31_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_31_RESET 1 +#define GPIO_INTERRUPT_STATUS_30 21:21 +#define GPIO_INTERRUPT_STATUS_30_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_30_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_30_RESET 1 +#define GPIO_INTERRUPT_STATUS_29 20:20 +#define GPIO_INTERRUPT_STATUS_29_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_29_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_29_RESET 1 +#define GPIO_INTERRUPT_STATUS_28 19:19 +#define GPIO_INTERRUPT_STATUS_28_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_28_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_28_RESET 1 +#define GPIO_INTERRUPT_STATUS_27 18:18 +#define GPIO_INTERRUPT_STATUS_27_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_27_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_27_RESET 1 +#define GPIO_INTERRUPT_STATUS_26 17:17 +#define GPIO_INTERRUPT_STATUS_26_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_26_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_26_RESET 1 +#define GPIO_INTERRUPT_STATUS_25 16:16 +#define GPIO_INTERRUPT_STATUS_25_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_25_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_25_RESET 1 + + +#define GPIO_MUX_I2C0 31:30 +#define GPIO_MUX_I2C0_DISABLE 0 +#define GPIO_MUX_I2C0_ENABLE 3 +#define GPIO_MUX_31 31:31 +#define GPIO_MUX_31_GPIO 0 +#define GPIO_MUX_31_I2C0 1 +#define GPIO_MUX_30 30:30 +#define GPIO_MUX_30_GPIO 0 +#define GPIO_MUX_30_I2C0 1 +#define GPIO_MUX_29 29:29 +#define GPIO_MUX_29_GPIO 0 +#define GPIO_MUX_29_SSP1 1 +#define GPIO_MUX_28 28:28 +#define GPIO_MUX_28_GPIO 0 +#define GPIO_MUX_28_SSP1 1 +#define GPIO_MUX_28_I2S_RX 1 +#define GPIO_MUX_27 27:27 +#define GPIO_MUX_27_GPIO 0 +#define GPIO_MUX_27_I2S_TX 0 +#define GPIO_MUX_27_SSP1 1 +#define GPIO_MUX_26 26:26 +#define GPIO_MUX_26_GPIO 0 +#define GPIO_MUX_26_I2S_WS 0 +#define GPIO_MUX_26_SSP1 1 +#define GPIO_MUX_25 25:25 +#define GPIO_MUX_25_GPIO 0 +#define GPIO_MUX_25_I2S_CK 0 +#define GPIO_MUX_25_SSP1 1 +#define GPIO_MUX_24 24:24 +#define GPIO_MUX_24_GPIO 0 +#define GPIO_MUX_24_SSP0 1 +#define GPIO_MUX_23 23:23 +#define GPIO_MUX_23_GPIO 0 +#define GPIO_MUX_23_SSP0 1 +#define GPIO_MUX_22 22:22 +#define GPIO_MUX_22_GPIO 0 +#define GPIO_MUX_22_SSP0 1 +#define GPIO_MUX_21 21:21 +#define GPIO_MUX_21_GPIO 0 +#define GPIO_MUX_21_SSP0 1 +#define GPIO_MUX_20 20:20 +#define GPIO_MUX_20_GPIO 0 +#define GPIO_MUX_20_SSP0 1 +#define GPIO_MUX_19 19:19 +#define GPIO_MUX_19_GPIO 0 +#define GPIO_MUX_19_PWM2 1 +#define GPIO_MUX_18 18:18 +#define GPIO_MUX_18_GPIO 0 +#define GPIO_MUX_18_PWM1 1 +#define GPIO_MUX_17 17:17 +#define GPIO_MUX_17_GPIO 0 +#define GPIO_MUX_17_PWM0 1 +#define GPIO_MUX_16 16:16 +#define GPIO_MUX_16_GPIO 0 +#define GPIO_MUX_16_UNUSED 1 +#define GPIO_MUX_UART0 15:12 +#define GPIO_MUX_UART0_DISABLE 0 +#define GPIO_MUX_UART0_ENABLE 15 +#define GPIO_MUX_15 15:15 +#define GPIO_MUX_15_GPIO 0 +#define GPIO_MUX_15_UART0 1 +#define GPIO_MUX_14 14:14 +#define GPIO_MUX_14_GPIO 0 +#define GPIO_MUX_14_UART0 1 +#define GPIO_MUX_13 13:13 +#define GPIO_MUX_13_GPIO 0 +#define GPIO_MUX_13_UART0 1 +#define GPIO_MUX_12 12:12 +#define GPIO_MUX_12_GPIO 0 +#define GPIO_MUX_12_UART0 1 +#define GPIO_MUX_UART1 11:8 +#define GPIO_MUX_UART1_DISABLE 0 +#define GPIO_MUX_UART1_ENABLE 15 +#define GPIO_MUX_11 11:11 +#define GPIO_MUX_11_GPIO 0 +#define GPIO_MUX_11_UART1 1 +#define GPIO_MUX_10 10:10 +#define GPIO_MUX_10_GPIO 0 +#define GPIO_MUX_10_UART1 1 +#define GPIO_MUX_9 9:9 +#define GPIO_MUX_9_GPIO 0 +#define GPIO_MUX_9_UART1 1 +#define GPIO_MUX_8 8:8 +#define GPIO_MUX_8_GPIO 0 +#define GPIO_MUX_8_UART1 1 +#define GPIO_MUX_I2C1 7:6 +#define GPIO_MUX_I2C1_DISABLE 0 +#define GPIO_MUX_I2C1_ENABLE 3 +#define GPIO_MUX_7 7:7 +#define GPIO_MUX_7_GPIO 0 +#define GPIO_MUX_7_I2C1 1 +#define GPIO_MUX_6 6:6 +#define GPIO_MUX_6_GPIO 0 +#define GPIO_MUX_6_I2C1 1 +#define GPIO_MUX_5 5:5 +#define GPIO_MUX_5_GPIO 0 +#define GPIO_MUX_5_RESERVE 1 +#define GPIO_MUX_4 4:4 +#define GPIO_MUX_4_GPIO27 0 +#define GPIO_MUX_4_I2S_TX 1 +#define GPIO_MUX_3 3:3 +#define GPIO_MUX_3_GPIO26 0 +#define GPIO_MUX_3_I2S_WS 1 +#define GPIO_MUX_2 2:2 +#define GPIO_MUX_2_GPIO25 0 +#define GPIO_MUX_2_I2S_CK 1 +#define GPIO_MUX_1 1:1 +#define GPIO_MUX_1_UART1_INT_CLK 0 +#define GPIO_MUX_1_UART1_EXT_CLK 1 +#define GPIO_MUX_0 0:0 +#define GPIO_MUX_0_UART0_INT_CLK 0 +#define GPIO_MUX_0_UART0_EXT_CLK 1 + + +//#include "regpwm.h" + +#define PWM_CONTROL 0x010020 +#define PWM_CONTROL_HIGH_COUNTER 31:20 +#define PWM_CONTROL_LOW_COUNTER 19:8 +#define PWM_CONTROL_CLOCK_DIVIDE 7:4 +#define PWM_CONTROL_CLOCK_DIVIDE_1 0 +#define PWM_CONTROL_CLOCK_DIVIDE_2 1 +#define PWM_CONTROL_CLOCK_DIVIDE_4 2 +#define PWM_CONTROL_CLOCK_DIVIDE_8 3 +#define PWM_CONTROL_CLOCK_DIVIDE_16 4 +#define PWM_CONTROL_CLOCK_DIVIDE_32 5 +#define PWM_CONTROL_CLOCK_DIVIDE_64 6 +#define PWM_CONTROL_CLOCK_DIVIDE_128 7 +#define PWM_CONTROL_CLOCK_DIVIDE_256 8 +#define PWM_CONTROL_CLOCK_DIVIDE_512 9 +#define PWM_CONTROL_CLOCK_DIVIDE_1024 10 +#define PWM_CONTROL_CLOCK_DIVIDE_2048 11 +#define PWM_CONTROL_CLOCK_DIVIDE_4096 12 +#define PWM_CONTROL_CLOCK_DIVIDE_8192 13 +#define PWM_CONTROL_CLOCK_DIVIDE_16384 14 +#define PWM_CONTROL_CLOCK_DIVIDE_32768 15 +#define PWM_CONTROL_INTERRUPT_STATUS 3:3 +#define PWM_CONTROL_INTERRUPT_STATUS_NOT_PENDING 0 +#define PWM_CONTROL_INTERRUPT_STATUS_PENDING 1 +#define PWM_CONTROL_INTERRUPT_STATUS_CLEAR 1 +#define PWM_CONTROL_INTERRUPT 2:2 +#define PWM_CONTROL_INTERRUPT_DISABLE 0 +#define PWM_CONTROL_INTERRUPT_ENABLE 1 +#define PWM_CONTROL_STATUS 0:0 +#define PWM_CONTROL_STATUS_DISABLE 0 +#define PWM_CONTROL_STATUS_ENABLE 1 + + +//#include "regssp.h" + +#define SSP_0_CONTROL_0 0x020000 +#define SSP_0_CONTROL_0_CLOCK_RATE 15:8 +#define SSP_0_CONTROL_0_SCLKOUT_PHASE 7:7 +#define SSP_0_CONTROL_0_SCLKOUT_PHASE_0 0 +#define SSP_0_CONTROL_0_SCLKOUT_PHASE_1 1 +#define SSP_0_CONTROL_0_SCLKOUT_POLARITY 6:6 +#define SSP_0_CONTROL_0_SCLKOUT_POLARITY_RISING 0 +#define SSP_0_CONTROL_0_SCLKOUT_POLARITY_FALLING 1 +#define SSP_0_CONTROL_0_FRAME_FORMAT 5:4 +#define SSP_0_CONTROL_0_FRAME_FORMAT_MOTOROLA 0 +#define SSP_0_CONTROL_0_FRAME_FORMAT_TI 1 +#define SSP_0_CONTROL_0_FRAME_FORMAT_NATIONAL 2 +#define SSP_0_CONTROL_0_DATA_SIZE 3:0 +#define SSP_0_CONTROL_0_DATA_SIZE_4 3 +#define SSP_0_CONTROL_0_DATA_SIZE_5 4 +#define SSP_0_CONTROL_0_DATA_SIZE_6 5 +#define SSP_0_CONTROL_0_DATA_SIZE_7 6 +#define SSP_0_CONTROL_0_DATA_SIZE_8 7 +#define SSP_0_CONTROL_0_DATA_SIZE_9 8 +#define SSP_0_CONTROL_0_DATA_SIZE_10 9 +#define SSP_0_CONTROL_0_DATA_SIZE_11 10 +#define SSP_0_CONTROL_0_DATA_SIZE_12 11 +#define SSP_0_CONTROL_0_DATA_SIZE_13 12 +#define SSP_0_CONTROL_0_DATA_SIZE_14 13 +#define SSP_0_CONTROL_0_DATA_SIZE_15 14 +#define SSP_0_CONTROL_0_DATA_SIZE_16 15 + +#define SSP_0_CONTROL_1 0x020004 +#define SSP_0_CONTROL_1_SLAVE_OUTPUT 6:6 +#define SSP_0_CONTROL_1_SLAVE_OUTPUT_ENABLE 0 +#define SSP_0_CONTROL_1_SLAVE_OUTPUT_DISABLE 1 +#define SSP_0_CONTROL_1_MODE_SELECT 5:5 +#define SSP_0_CONTROL_1_MODE_SELECT_MASTER 0 +#define SSP_0_CONTROL_1_MODE_SELECT_SLAVE 1 +#define SSP_0_CONTROL_1_STATUS 4:4 +#define SSP_0_CONTROL_1_STATUS_DISABLE 0 +#define SSP_0_CONTROL_1_STATUS_ENABLE 1 +#define SSP_0_CONTROL_1_LOOP_BACK 3:3 +#define SSP_0_CONTROL_1_LOOP_BACK_DISABLE 0 +#define SSP_0_CONTROL_1_LOOP_BACK_ENABLE 1 +#define SSP_0_CONTROL_1_OVERRUN_INTERRUPT 2:2 +#define SSP_0_CONTROL_1_OVERRUN_INTERRUPT_DISABLE 0 +#define SSP_0_CONTROL_1_OVERRUN_INTERRUPT_ENABLE 1 +#define SSP_0_CONTROL_1_TRANSMIT_INTERRUPT 1:1 +#define SSP_0_CONTROL_1_TRANSMIT_INTERRUPT_DISABLE 0 +#define SSP_0_CONTROL_1_TRANSMIT_INTERRUPT_ENABLE 1 +#define SSP_0_CONTROL_1_RECEIVE_INTERRUPT 0:0 +#define SSP_0_CONTROL_1_RECEIVE_INTERRUPT_DISABLE 0 +#define SSP_0_CONTROL_1_RECEIVE_INTERRUPT_ENABLE 1 + +#define SSP_0_DATA 0x020008 +#define SSP_0_DATA_DATA 15:0 + +#define SSP_0_STATUS 0x02000C +#define SSP_0_STATUS_STATUS 4:4 +#define SSP_0_STATUS_STATUS_IDLE 0 +#define SSP_0_STATUS_STATUS_BUSY 1 +#define SSP_0_STATUS_RECEIVE_FIFO 3:2 +#define SSP_0_STATUS_RECEIVE_FIFO_EMPTY 0 +#define SSP_0_STATUS_RECEIVE_FIFO_NOT_EMPTY 1 +#define SSP_0_STATUS_RECEIVE_FIFO_FULL 3 +#define SSP_0_STATUS_TRANSMIT_FIFO 1:0 +#define SSP_0_STATUS_TRANSMIT_FIFO_FULL 0 +#define SSP_0_STATUS_TRANSMIT_FIFO_NOT_FULL 2 +#define SSP_0_STATUS_TRANSMIT_FIFO_EMPTY 3 + +#define SSP_0_CLOCK_PRESCALE 0x020010 +#define SSP_0_CLOCK_PRESCALE_DIVISOR 7:0 + +#define SSP_0_INTERRUPT_STATUS 0x020014 +#define SSP_0_INTERRUPT_STATUS_OVERRUN 2:2 +#define SSP_0_INTERRUPT_STATUS_OVERRUN_NOT_ACTIVE 0 +#define SSP_0_INTERRUPT_STATUS_OVERRUN_ACTIVE 1 +#define SSP_0_INTERRUPT_STATUS_OVERRUN_CLEAR 1 +#define SSP_0_INTERRUPT_STATUS_TRANSMIT 1:1 +#define SSP_0_INTERRUPT_STATUS_TRANSMIT_NOT_ACTIVE 0 +#define SSP_0_INTERRUPT_STATUS_TRANSMIT_ACTIVE 1 +#define SSP_0_INTERRUPT_STATUS_RECEIVE 0:0 +#define SSP_0_INTERRUPT_STATUS_RECEIVE_NOT_ACTIVE 0 +#define SSP_0_INTERRUPT_STATUS_RECEIVE_ACTIVE 1 + +/* SSP 1 */ + +#define SSP_1_CONTROL_0 0x020100 +#define SSP_1_CONTROL_0_CLOCK_RATE 15:8 +#define SSP_1_CONTROL_0_SCLKOUT_PHASE 7:7 +#define SSP_1_CONTROL_0_SCLKOUT_PHASE_0 0 +#define SSP_1_CONTROL_0_SCLKOUT_PHASE_1 1 +#define SSP_1_CONTROL_0_SCLKOUT_POLARITY 6:6 +#define SSP_1_CONTROL_0_SCLKOUT_POLARITY_RISING 0 +#define SSP_1_CONTROL_0_SCLKOUT_POLARITY_FALLING 1 +#define SSP_1_CONTROL_0_FRAME_FORMAT 5:4 +#define SSP_1_CONTROL_0_FRAME_FORMAT_MOTOROLA 0 +#define SSP_1_CONTROL_0_FRAME_FORMAT_TI 1 +#define SSP_1_CONTROL_0_FRAME_FORMAT_NATIONAL 2 +#define SSP_1_CONTROL_0_DATA_SIZE 3:0 +#define SSP_1_CONTROL_0_DATA_SIZE_4 3 +#define SSP_1_CONTROL_0_DATA_SIZE_5 4 +#define SSP_1_CONTROL_0_DATA_SIZE_6 5 +#define SSP_1_CONTROL_0_DATA_SIZE_7 6 +#define SSP_1_CONTROL_0_DATA_SIZE_8 7 +#define SSP_1_CONTROL_0_DATA_SIZE_9 8 +#define SSP_1_CONTROL_0_DATA_SIZE_10 9 +#define SSP_1_CONTROL_0_DATA_SIZE_11 10 +#define SSP_1_CONTROL_0_DATA_SIZE_12 11 +#define SSP_1_CONTROL_0_DATA_SIZE_13 12 +#define SSP_1_CONTROL_0_DATA_SIZE_14 13 +#define SSP_1_CONTROL_0_DATA_SIZE_15 14 +#define SSP_1_CONTROL_0_DATA_SIZE_16 15 + +#define SSP_1_CONTROL_1 0x020104 +#define SSP_1_CONTROL_1_SLAVE_OUTPUT 6:6 +#define SSP_1_CONTROL_1_SLAVE_OUTPUT_ENABLE 0 +#define SSP_1_CONTROL_1_SLAVE_OUTPUT_DISABLE 1 +#define SSP_1_CONTROL_1_MODE_SELECT 5:5 +#define SSP_1_CONTROL_1_MODE_SELECT_MASTER 0 +#define SSP_1_CONTROL_1_MODE_SELECT_SLAVE 1 +#define SSP_1_CONTROL_1_STATUS 4:4 +#define SSP_1_CONTROL_1_STATUS_DISABLE 0 +#define SSP_1_CONTROL_1_STATUS_ENABLE 1 +#define SSP_1_CONTROL_1_LOOP_BACK 3:3 +#define SSP_1_CONTROL_1_LOOP_BACK_DISABLE 0 +#define SSP_1_CONTROL_1_LOOP_BACK_ENABLE 1 +#define SSP_1_CONTROL_1_OVERRUN_INTERRUPT 2:2 +#define SSP_1_CONTROL_1_OVERRUN_INTERRUPT_DISABLE 0 +#define SSP_1_CONTROL_1_OVERRUN_INTERRUPT_ENABLE 1 +#define SSP_1_CONTROL_1_TRANSMIT_INTERRUPT 1:1 +#define SSP_1_CONTROL_1_TRANSMIT_INTERRUPT_DISABLE 0 +#define SSP_1_CONTROL_1_TRANSMIT_INTERRUPT_ENABLE 1 +#define SSP_1_CONTROL_1_RECEIVE_INTERRUPT 0:0 +#define SSP_1_CONTROL_1_RECEIVE_INTERRUPT_DISABLE 0 +#define SSP_1_CONTROL_1_RECEIVE_INTERRUPT_ENABLE 1 + +#define SSP_1_DATA 0x020108 +#define SSP_1_DATA_DATA 15:0 + +#define SSP_1_STATUS 0x02010C +#define SSP_1_STATUS_STATUS 4:4 +#define SSP_1_STATUS_STATUS_IDLE 0 +#define SSP_1_STATUS_STATUS_BUSY 1 +#define SSP_1_STATUS_RECEIVE_FIFO 3:2 +#define SSP_1_STATUS_RECEIVE_FIFO_EMPTY 0 +#define SSP_1_STATUS_RECEIVE_FIFO_NOT_EMPTY 1 +#define SSP_1_STATUS_RECEIVE_FIFO_FULL 3 +#define SSP_1_STATUS_TRANSMIT_FIFO 1:0 +#define SSP_1_STATUS_TRANSMIT_FIFO_FULL 0 +#define SSP_1_STATUS_TRANSMIT_FIFO_NOT_FULL 2 +#define SSP_1_STATUS_TRANSMIT_FIFO_EMPTY 3 + +#define SSP_1_CLOCK_PRESCALE 0x020110 +#define SSP_1_CLOCK_PRESCALE_DIVISOR 7:0 + +#define SSP_1_INTERRUPT_STATUS 0x020114 +#define SSP_1_INTERRUPT_STATUS_OVERRUN 2:2 +#define SSP_1_INTERRUPT_STATUS_OVERRUN_NOT_ACTIVE 0 +#define SSP_1_INTERRUPT_STATUS_OVERRUN_ACTIVE 1 +#define SSP_1_INTERRUPT_STATUS_OVERRUN_CLEAR 1 +#define SSP_1_INTERRUPT_STATUS_TRANSMIT 1:1 +#define SSP_1_INTERRUPT_STATUS_TRANSMIT_NOT_ACTIVE 0 +#define SSP_1_INTERRUPT_STATUS_TRANSMIT_ACTIVE 1 +#define SSP_1_INTERRUPT_STATUS_RECEIVE 0:0 +#define SSP_1_INTERRUPT_STATUS_RECEIVE_NOT_ACTIVE 0 +#define SSP_1_INTERRUPT_STATUS_RECEIVE_ACTIVE 1 + +//#include "regdc.h" + + +#define HDMI_CONTROL 0x0800C4 +#define HDMI_CONTROL_MODE_SELECT 7:4 +#define HDMI_CONTROL_MODE_SELECT_A 1 +#define HDMI_CONTROL_MODE_SELECT_B 2 +#define HDMI_CONTROL_MODE_SELECT_D 4 +#define HDMI_CONTROL_MODE_SELECT_E 8 +#define HDMI_CONTROL_PLLB 3:3 +#define HDMI_CONTROL_PLLB_NORMAL 0 +#define HDMI_CONTROL_PLLB_RESET 1 +#define HDMI_CONTROL_PLLA 2:2 +#define HDMI_CONTROL_PLLA_NORMAL 0 +#define HDMI_CONTROL_PLLA_RESET 1 +#define HDMI_CONTROL_INTMODE 1:1 +#define HDMI_CONTROL_INT_MODE_OPEN 0 +#define HDMI_CONTROL_INT_MODE_PULL 1 +#define HDMI_CONTROL_INT_POLARITY 0:0 +#define HDMI_CONTROL_INT_POLARITY_LOW 0 +#define HDMI_CONTROL_INT_POLARITY_HIGH 1 + +#define HDMI_CONFIG 0x0800C0 +#define HDMI_CONFIG_READ 17:17 +#define HDMI_CONFIG_READ_LATCH 0 +#define HDMI_CONFIG_READ_ENABLE 1 +#define HDMI_CONFIG_WRITE 16:16 +#define HDMI_CONFIG_WRITE_LATCH 0 +#define HDMI_CONFIG_WRITE_ENABLE 1 +#define HDMI_CONFIG_DATA 15:8 +#define HDMI_CONFIG_ADDRESS 7:0 + + + + +#define DISPLAY_CTRL 0x080000 +#define DISPLAY_CTRL_DPMS 31:30 +#define DISPLAY_CTRL_DPMS_VPHP 0 +#define DISPLAY_CTRL_DPMS_VPHN 1 +#define DISPLAY_CTRL_DPMS_VNHP 2 +#define DISPLAY_CTRL_DPMS_VNHN 3 +#define DISPLAY_CTRL_DATA_PATH 29:29 +#define DISPLAY_CTRL_DATA_PATH_VGA 0 +#define DISPLAY_CTRL_DATA_PATH_EXTENDED 1 +#define DISPLAY_CTRL_DIRECTION 28:28 +#define DISPLAY_CTRL_DIRECTION_INPUT 0 +#define DISPLAY_CTRL_DIRECTION_OUTPUT 1 +#define DISPLAY_CTRL_FPEN 27:27 +#define DISPLAY_CTRL_FPEN_LOW 0 +#define DISPLAY_CTRL_FPEN_HIGH 1 +#define DISPLAY_CTRL_VBIASEN 26:26 +#define DISPLAY_CTRL_VBIASEN_LOW 0 +#define DISPLAY_CTRL_VBIASEN_HIGH 1 +#define DISPLAY_CTRL_DATA 25:25 +#define DISPLAY_CTRL_DATA_DISABLE 0 +#define DISPLAY_CTRL_DATA_ENABLE 1 +#define DISPLAY_CTRL_FPVDDEN 24:24 +#define DISPLAY_CTRL_FPVDDEN_LOW 0 +#define DISPLAY_CTRL_FPVDDEN_HIGH 1 +#define DISPLAY_CTRL_CAPTURE_DATA_SELECT 23:23 +#define DISPLAY_CTRL_CAPTURE_DATA_SELECT_CHANNEL0 0 +#define DISPLAY_CTRL_CAPTURE_DATA_SELECT_CHANNEL1 1 +#define DISPLAY_CTRL_LOOP_BACK_SELECT 22:22 +#define DISPLAY_CTRL_LOOP_BACK_SELECT_CHANNEL0 0 +#define DISPLAY_CTRL_LOOP_BACK_SELECT_CHANNEL1 1 +#define DISPLAY_CTRL_CHANNEL_OUTPUT_FORMAT 21:20 +#define DISPLAY_CTRL_CHANNEL_OUTPUT_FORMAT_CHANNEL0_24BIT 0 +#define DISPLAY_CTRL_CHANNEL_OUTPUT_FORMAT_CHANNEL1_24BIT 1 +#define DISPLAY_CTRL_CHANNEL_OUTPUT_FORMAT_CHANNEL0_48BIT 2 +#define DISPLAY_CTRL_CHANNEL_OUTPUT_FORMAT_CHANNEL1_48BIT 3 +#define DISPLAY_CTRL_HDMI_CLK 19:19 +#define DISPLAY_CTRL_HDMI_CLK_NEG 0 +#define DISPLAY_CTRL_HDMI_CLK_POS 1 +#define DISPLAY_CTRL_HDMI_SELECT 18:18 +#define DISPLAY_CTRL_HDMI_SELECT_CHANNEL0 0 +#define DISPLAY_CTRL_HDMI_SELECT_CHANNEL1 1 +#define DISPLAY_CTRL_LVDS_OUTPUT_FORMAT 17:16 +#define DISPLAY_CTRL_LVDS_OUTPUT_FORMAT_CHANNEL0_24BIT 0 +#define DISPLAY_CTRL_LVDS_OUTPUT_FORMAT_CHANNEL1_24BIT 1 +#define DISPLAY_CTRL_LVDS_OUTPUT_FORMAT_CHANNEL0_48BIT 2 +#define DISPLAY_CTRL_LVDS_OUTPUT_FORMAT_CHANNEL1_48BIT 3 +#define DISPLAY_CTRL_PIXEL_CLOCK_SELECT 15:15 +#define DISPLAY_CTRL_PIXEL_CLOCK_SELECT_SINGLE 0 +#define DISPLAY_CTRL_PIXEL_CLOCK_SELECT_HALF 1 +#define DISPLAY_CTRL_CLOCK_PHASE 14:14 +#define DISPLAY_CTRL_CLOCK_PHASE_ACTIVE_HIGH 0 +#define DISPLAY_CTRL_CLOCK_PHASE_ACTIVE_LOW 1 +#define DISPLAY_CTRL_VSYNC_PHASE 13:13 +#define DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_HIGH 0 +#define DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_LOW 1 +#define DISPLAY_CTRL_HSYNC_PHASE 12:12 +#define DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_HIGH 0 +#define DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_LOW 1 +#define DISPLAY_CTRL_DOUBLE_PIXEL_CLOCK 11:11 +#define DISPLAY_CTRL_DOUBLE_PIXEL_CLOCK_DISABLE 0 +#define DISPLAY_CTRL_DOUBLE_PIXEL_CLOCK_ENABLE 1 +#define DISPLAY_CTRL_VSYNC 11:11 +#define DISPLAY_CTRL_VSYNC_INACTIVE 0 +#define DISPLAY_CTRL_VSYNC_ACTIVE 1 +#define DISPLAY_CTRL_DAC_FORMAT 10:10 +#define DISPLAY_CTRL_DAC_FORMAT_6BIT 0 +#define DISPLAY_CTRL_DAC_FORMAT_8BIT 1 +#define DISPLAY_CTRL_COLOR_KEY 9:9 +#define DISPLAY_CTRL_COLOR_KEY_DISABLE 0 +#define DISPLAY_CTRL_COLOR_KEY_ENABLE 1 +#define DISPLAY_CTRL_TIMING 8:8 +#define DISPLAY_CTRL_TIMING_DISABLE 0 +#define DISPLAY_CTRL_TIMING_ENABLE 1 +#define DISPLAY_CTRL_PIXEL 7:4 +#define DISPLAY_CTRL_GAMMA 3:3 +#define DISPLAY_CTRL_GAMMA_DISABLE 0 +#define DISPLAY_CTRL_GAMMA_ENABLE 1 +#define DISPLAY_CTRL_PLANE 2:2 +#define DISPLAY_CTRL_PLANE_DISABLE 0 +#define DISPLAY_CTRL_PLANE_ENABLE 1 +#define DISPLAY_CTRL_FORMAT 1:0 +#define DISPLAY_CTRL_FORMAT_8 0 +#define DISPLAY_CTRL_FORMAT_16 1 +#define DISPLAY_CTRL_FORMAT_32 2 + +#define FB_ADDRESS 0x080004 +#define FB_ADDRESS_STATUS 31:31 +#define FB_ADDRESS_STATUS_CURRENT 0 +#define FB_ADDRESS_STATUS_PENDING 1 +#define FB_ADDRESS_ADDRESS 29:0 + +#define CHANNEL1_FB_ADDRESS 0x088004 +#define CHANNEL1_FB_ADDRESS_STATUS 31:31 +#define CHANNEL1_FB_ADDRESS_STATUS_CURRENT 0 +#define CHANNEL1_FB_ADDRESS_STATUS_PENDING 1 +#define CHANNEL1_FB_ADDRESS_ADDRESS 29:0 + + + +#define FB_WIDTH 0x080008 +#define FB_WIDTH_WIDTH 29:16 +#define FB_WIDTH_OFFSET 13:0 + +#define HORIZONTAL_TOTAL 0x08000C +#define HORIZONTAL_TOTAL_TOTAL 28:16 +#define HORIZONTAL_TOTAL_DISPLAY_END 11:0 + +#define HORIZONTAL_SYNC 0x080010 +#define HORIZONTAL_SYNC_WIDTH 25:16 +#define HORIZONTAL_SYNC_START 12:0 + +#define VERTICAL_TOTAL 0x080014 +#define VERTICAL_TOTAL_TOTAL 27:16 +#define VERTICAL_TOTAL_DISPLAY_END 11:0 + +#define VERTICAL_SYNC 0x080018 +#define VERTICAL_SYNC_HEIGHT 21:16 +#define VERTICAL_SYNC_START 11:0 + +#define CURRENT_LINE 0x080020 +#define CURRENT_LINE_LINE 11:0 + + +#define LVDS_CTRL1 0x80020 +#define LVDS_CTRL1_CLKSEL_PLL2 31:31 +#define LVDS_CTRL1_CLKSEL_PLL2_RE 0 +#define LVDS_CTRL1_CLKSEL_PLL2_FE 1 +#define LVDS_CTRL1_CLKSEL_PLL1 30:30 +#define LVDS_CTRL1_CLKSEL_PLL1_RE 0 +#define LVDS_CTRL1_CLKSEL_PLL1_FE 1 +#define LVDS_CTRL1_DCLK2 29:23 +#define LVDS_CTRL1_DCLK2_DEFAULT 0x63 +#define LVDS_CTRL1_DCLK1 22:16 +#define LVDS_CTRL1_DCLK1_DEFAULT 0x63 +#define LVDS_CTRL1_PLL2_LOCK 15:15 +#define LVDS_CTRL1_PLL1_LOCK 14:14 +#define LVDS_CTRL1_POR25 13:13 +#define LVDS_CTRL1_POR12 12:12 + + + +#define CRT_DETECT 0x080024 +#define CRT_DETECT_DAC 31:31 +#define CRT_DETECT_DAC_ENABLE 0 +#define CRT_DETECT_DAC_DOWN 1 +#define CRT_DETECT_CRT_CLK 27:27 +#define CRT_DETECT_CRT_CLK_POS 0 +#define CRT_DETECT_CRT_CLK_NEG 1 +#define CRT_DETECT_LVDS_CLK 26:26 +#define CRT_DETECT_LVDS_CLK_POS 0 +#define CRT_DETECT_LVDS_CLK_NEG 1 +#define CRT_DETECT_CRT 25:25 +#define CRT_DETECT_CRT_ABSENT 0 +#define CRT_DETECT_CRT_PRESENT 1 +#define CRT_DETECT_ENABLE 24:24 +#define CRT_DETECT_ENABLE_DISABLE 0 +#define CRT_DETECT_ENABLE_ENABLE 1 +#define CRT_DETECT_DATA_RED 23:16 +#define CRT_DETECT_DATA_GREEN 15:8 +#define CRT_DETECT_DATA_BLUE 7:0 + +#define COLOR_KEY 0x080028 +#define COLOR_KEY_MASK 31:16 +#define COLOR_KEY_VALUE 15:0 + +#define LVDS_CTRL2 0x08002C +#define LVDS_CTRL2_SHTDNB2 30:30 +#define LVDS_CTRL2_SHTDNB2_RESET 0 +#define LVDS_CTRL2_SHTDNB2_NORMAL 1 +#define LVDS_CTRL2_SHTDNB1 29:29 +#define LVDS_CTRL2_SHTDNB1_RESET 0 +#define LVDS_CTRL2_SHTDNB1_NORMAL 1 +#define LVDS_CTRL2_CLK2_DS 28:27 +#define LVDS_CTRL2_CLK2_DS_3MA 0 +#define LVDS_CTRL2_CLK2_DS_1MA 1 +#define LVDS_CTRL2_CLK2_DS_5MA 2 +#define LVDS_CTRL2_CLK2_DS_2MA 3 +#define LVDS_CTRL2_CLK1_DS 26:25 +#define LVDS_CTRL2_CLK1_DS_3MA 0 +#define LVDS_CTRL2_CLK1_DS_1MA 1 +#define LVDS_CTRL2_CLK1_DS_5MA 2 +#define LVDS_CTRL2_CLK1_DS_2MA 3 +#define LVDS_CTRL2_DS 24:23 +#define LVDS_CTRL2_DS_3MA 0 +#define LVDS_CTRL2_DS_1MA 1 +#define LVDS_CTRL2_DS_5MA 2 +#define LVDS_CTRL2_DS_2MA 3 +#define LVDS_CTRL2_CLK2_TR 22:22 +#define LVDS_CTRL2_CLK2_TR_0 0 +#define LVDS_CTRL2_CLK2_TR_100 1 +#define LVDS_CTRL2_CLK1_TR 21:21 +#define LVDS_CTRL2_CLK1_TR_0 0 +#define LVDS_CTRL2_CLK1_TR_100 1 +#define LVDS_CTRL2_TR 20:20 +#define LVDS_CTRL2_TR_0 0 +#define LVDS_CTRL2_TR_100 1 +#define LVDS_CTRL2_CLK2_COMP 19:18 +#define LVDS_CTRL2_CLK2_COMP_0 0 +#define LVDS_CTRL2_CLK2_COMP_1 1 +#define LVDS_CTRL2_CLK2_COMP_2 2 +#define LVDS_CTRL2_CLK2_COMP_3 3 +#define LVDS_CTRL2_CLK1_COMP 17:16 +#define LVDS_CTRL2_CLK1_COMP_0 0 +#define LVDS_CTRL2_CLK1_COMP_1 1 +#define LVDS_CTRL2_CLK1_COMP_2 2 +#define LVDS_CTRL2_CLK1_COMP_3 3 +#define LVDS_CTRL2_PRE_COMP 15:14 +#define LVDS_CTRL2_PRE_COMP_0 0 +#define LVDS_CTRL2_PRE_COMP_1 1 +#define LVDS_CTRL2_PRE_COMP_2 2 +#define LVDS_CTRL2_PRE_COMP_3 3 +#define LVDS_CTRL2_VCOS_PLL2 13:11 +#define LVDS_CTRL2_VCOS_PLL2_10M 0 +#define LVDS_CTRL2_VCOS_PLL2_20M 1 +#define LVDS_CTRL2_VCOS_PLL2_40M 2 +#define LVDS_CTRL2_VCOS_PLL2_80M 3 +#define LVDS_CTRL2_VCOS_PLL2_160M 4 +#define LVDS_CTRL2_VCOS_PLL2_350M 5 +#define LVDS_CTRL2_VCOS_PLL1 10:8 +#define LVDS_CTRL2_VCOS_PLL1_10M 0 +#define LVDS_CTRL2_VCOS_PLL1_20M 1 +#define LVDS_CTRL2_VCOS_PLL1_40M 2 +#define LVDS_CTRL2_VCOS_PLL1_80M 3 +#define LVDS_CTRL2_VCOS_PLL1_160M 4 +#define LVDS_CTRL2_VCOS_PLL1_350M 5 +#define LVDS_CTRL2_SHORTS_PLL2 7:6 +#define LVDS_CTRL2_SHORTS_PLL2_2048 0 +#define LVDS_CTRL2_SHORTS_PLL2_1024 1 +#define LVDS_CTRL2_SHORTS_PLL2_512 2 +#define LVDS_CTRL2_SHORTS_PLL2_256 3 +#define LVDS_CTRL2_SHORTS_PLL1 5:4 +#define LVDS_CTRL2_SHORTS_PLL1_2048 0 +#define LVDS_CTRL2_SHORTS_PLL1_1024 1 +#define LVDS_CTRL2_SHORTS_PLL1_512 2 +#define LVDS_CTRL2_SHORTS_PLL1_256 3 +#define LVDS_CTRL2_PD_PLL2 3:3 +#define LVDS_CTRL2_PD_PLL2_NORMAL 0 +#define LVDS_CTRL2_PD_PLL2_DOWN 1 +#define LVDS_CTRL2_PD_PLL1 2:2 +#define LVDS_CTRL2_PD_PLL1_NORMAL 0 +#define LVDS_CTRL2_PD_PLL1_DOWN 1 +#define LVDS_CTRL2_MODESEL2 1:1 +#define LVDS_CTRL2_MODESEL2_DC0 0 +#define LVDS_CTRL2_MODESEL2_DC1 1 +#define LVDS_CTRL2_MODESEL1 0:0 +#define LVDS_CTRL2_MODESEL1_DC0 0 +#define LVDS_CTRL2_MODESEL1_DC1 1 + + + + + +/* Cursor Control */ +#define HWC_CONTROL 0x080030 +#define HWC_CONTROL_MODE 31:30 +#define HWC_CONTROL_MODE_DISABLE 0 +#define HWC_CONTROL_MODE_MASK 1 +#define HWC_CONTROL_MODE_MONO 2 +#define HWC_CONTROL_MODE_ALPHA 3 +#define HWC_CONTROL_ADDRESS 29:0 + +#define HWC_LOCATION 0x080034 +#define HWC_LOCATION_TOP 31:31 +#define HWC_LOCATION_TOP_INSIDE 0 +#define HWC_LOCATION_TOP_OUTSIDE 1 +#define HWC_LOCATION_Y 27:16 +#define HWC_LOCATION_LEFT 15:15 +#define HWC_LOCATION_LEFT_INSIDE 0 +#define HWC_LOCATION_LEFT_OUTSIDE 1 +#define HWC_LOCATION_X 11:0 + +#define HWC_COLOR0 0x080038 +#define HWC_COLOR0_RGB888 23:0 + +#define HWC_COLOR1 0x08003C +#define HWC_COLOR1_RGB888 23:0 + + +/* Channel0 Cursor Control */ +#define CHANNEL0_HWC_ADDRESS 0x080030 +#define CHANNEL0_HWC_ADDRESS_ENABLE 31:30 +#define CHANNEL0_HWC_ADDRESS_ENABLE_DISABLE 0 +#define CHANNEL0_HWC_ADDRESS_ENABLE_MASK 1 +#define CHANNEL0_HWC_ADDRESS_ENABLE_MONO 2 +#define CHANNEL0_HWC_ADDRESS_ENABLE_ALPHA 3 +#define CHANNEL0_HWC_ADDRESS_ADDRESS 29:0 + +#define CHANNEL0_HWC_LOCATION 0x080034 +#define CHANNEL0_HWC_LOCATION_TOP 31:31 +#define CHANNEL0_HWC_LOCATION_TOP_INSIDE 0 +#define CHANNEL0_HWC_LOCATION_TOP_OUTSIDE 1 +#define CHANNEL0_HWC_LOCATION_Y 27:16 +#define CHANNEL0_HWC_LOCATION_LEFT 15:15 +#define CHANNEL0_HWC_LOCATION_LEFT_INSIDE 0 +#define CHANNEL0_HWC_LOCATION_LEFT_OUTSIDE 1 +#define CHANNEL0_HWC_LOCATION_X 11:0 + +#define CHANNEL0_HWC_COLOR_0 0x080038 +#define CHANNEL0_HWC_COLOR_0_RGB888 23:0 + +#define CHANNEL0_HWC_COLOR_1 0x08003C +#define CHANNEL0_HWC_COLOR_1_RGB888 23:0 + +/* Channel1 Cursor Control */ +#define CHANNEL1_HWC_ADDRESS 0x088030 +#define CHANNEL1_HWC_ADDRESS_ENABLE 31:30 +#define CHANNEL1_HWC_ADDRESS_ENABLE_DISABLE 0 +#define CHANNEL1_HWC_ADDRESS_ENABLE_MASK 1 +#define CHANNEL1_HWC_ADDRESS_ENABLE_MONO 2 +#define CHANNEL1_HWC_ADDRESS_ENABLE_ALPHA 3 +#define CHANNEL1_HWC_ADDRESS_ADDRESS 29:0 + +#define CHANNEL1_HWC_LOCATION 0x088034 +#define CHANNEL1_HWC_LOCATION_TOP 31:31 +#define CHANNEL1_HWC_LOCATION_TOP_INSIDE 0 +#define CHANNEL1_HWC_LOCATION_TOP_OUTSIDE 1 +#define CHANNEL1_HWC_LOCATION_Y 27:16 +#define CHANNEL1_HWC_LOCATION_LEFT 15:15 +#define CHANNEL1_HWC_LOCATION_LEFT_INSIDE 0 +#define CHANNEL1_HWC_LOCATION_LEFT_OUTSIDE 1 +#define CHANNEL1_HWC_LOCATION_X 11:0 + +#define CHANNEL1_HWC_COLOR_0 0x088038 +#define CHANNEL1_HWC_COLOR_0_RGB888 23:0 + +#define CHANNEL1_HWC_COLOR_1 0x08803C +#define CHANNEL1_HWC_COLOR_1_RGB888 23:0 + + +/* Video Control */ +#define VIDEO_DISPLAY_CTRL 0x080040 +#define VIDEO_DISPLAY_CTRL_BYTE_SWAP 12:12 +#define VIDEO_DISPLAY_CTRL_BYTE_SWAP_DISABLE 0 +#define VIDEO_DISPLAY_CTRL_BYTE_SWAP_ENABLE 1 +#define VIDEO_DISPLAY_CTRL_VERTICAL_MODE 9:9 +#define VIDEO_DISPLAY_CTRL_VERTICAL_MODE_REPLICATE 0 +#define VIDEO_DISPLAY_CTRL_VERTICAL_MODE_INTERPOLATE 1 +#define VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE 8:8 +#define VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE_REPLICATE 0 +#define VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE_INTERPOLATE 1 +#define VIDEO_DISPLAY_CTRL_PIXEL 7:4 +#define VIDEO_DISPLAY_CTRL_GAMMA 3:3 +#define VIDEO_DISPLAY_CTRL_GAMMA_DISABLE 0 +#define VIDEO_DISPLAY_CTRL_GAMMA_ENABLE 1 +#define VIDEO_DISPLAY_CTRL_PLANE 2:2 +#define VIDEO_DISPLAY_CTRL_PLANE_DISABLE 0 +#define VIDEO_DISPLAY_CTRL_PLANE_ENABLE 1 +#define VIDEO_DISPLAY_CTRL_FORMAT 1:0 +#define VIDEO_DISPLAY_CTRL_FORMAT_16 0 +#define VIDEO_DISPLAY_CTRL_FORMAT_32 1 +#define VIDEO_DISPLAY_CTRL_FORMAT_YUV422 2 +#define VIDEO_DISPLAY_CTRL_FORMAT_YUV420 3 + +#define VIDEO_FB_ADDRESS 0x080044 +#define VIDEO_FB_ADDRESS_STATUS 31:31 +#define VIDEO_FB_ADDRESS_STATUS_CURRENT 0 +#define VIDEO_FB_ADDRESS_STATUS_PENDING 1 +#define VIDEO_FB_ADDRESS_ADDRESS 29:0 + +#define VIDEO_FB_WIDTH 0x080048 +#define VIDEO_FB_WIDTH_WIDTH 29:16 +#define VIDEO_FB_WIDTH_OFFSET 13:0 + +#define VIDEO_FB_ADDRESS_Y 0x080044 +#define VIDEO_FB_ADDRESS_Y_ADDRESS 29:0 + +#define VIDEO_FB_WIDTH_Y 0x080048 +#define VIDEO_FB_WIDTH_Y_WIDTH 29:16 +#define VIDEO_FB_WIDTH_Y_OFFSET 13:0 + + +#define VIDEO_FB_ADDRESS_U 0x08004C +#define VIDEO_FB_ADDRESS_U_ADDRESS 29:0 + +#define VIDEO_FB_WIDTH_U 0x080050 +#define VIDEO_FB_WIDTH_U_WIDTH 29:16 +#define VIDEO_FB_WIDTH_U_OFFSET 13:0 + +#define VIDEO_FB_ADDRESS_V 0x080054 +#define VIDEO_FB_ADDRESS_V_ADDRESS 29:0 + +#define VIDEO_FB_WIDTH_V 0x080058 +#define VIDEO_FB_WIDTH_V_WIDTH 29:16 +#define VIDEO_FB_WIDTH_V_OFFSET 13:0 + +#define VIDEO_YUV_CONSTANTS 0x08005C +#define VIDEO_YUV_CONSTANTS_Y 31:24 +#define VIDEO_YUV_CONSTANTS_R 23:16 +#define VIDEO_YUV_CONSTANTS_G 15:8 +#define VIDEO_YUV_CONSTANTS_B 7:0 + +#define VIDEO_PLANE_TL 0x080060 +#define VIDEO_PLANE_TL_TOP 26:16 +#define VIDEO_PLANE_TL_LEFT 11:0 + +#define VIDEO_PLANE_BR 0x080064 +#define VIDEO_PLANE_BR_BOTTOM 26:16 +#define VIDEO_PLANE_BR_RIGHT 11:0 + +#define VIDEO_SCALE 0x080068 +#define VIDEO_SCALE_VERTICAL_SCALE 27:16 +#define VIDEO_SCALE_HORIZONTAL_SCALE 11:0 + +#define VIDEO_INITIAL_SCALE 0x08006C +#define VIDEO_INITIAL_SCALE_VERTICAL 27:16 +#define VIDEO_INITIAL_SCALE_HORIZONTAL 11:0 + +/* Video Alpha Control */ +#if 1 +#define VIDEO_ALPHA_DISPLAY_CTRL 0x080080 +#define VIDEO_ALPHA_DISPLAY_CTRL_SELECT 28:28 +#define VIDEO_ALPHA_DISPLAY_CTRL_SELECT_PER_PIXEL 0 +#define VIDEO_ALPHA_DISPLAY_CTRL_SELECT_ALPHA 1 +#define VIDEO_ALPHA_DISPLAY_CTRL_ALPHA 27:24 +#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO 17:16 +#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_1 0 +#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_3 1 +#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_7 2 +#define VIDEO_ALPHA_DISPLAY_CTRL_FIFO_11 3 +#define VIDEO_ALPHA_DISPLAY_CTRL_PIXEL 7:4 +#define VIDEO_ALPHA_DISPLAY_CTRL_CHROMA_KEY 3:3 +#define VIDEO_ALPHA_DISPLAY_CTRL_CHROMA_KEY_DISABLE 0 +#define VIDEO_ALPHA_DISPLAY_CTRL_CHROMA_KEY_ENABLE 1 +#define VIDEO_ALPHA_DISPLAY_CTRL_PLANE 2:2 +#define VIDEO_ALPHA_DISPLAY_CTRL_PLANE_DISABLE 0 +#define VIDEO_ALPHA_DISPLAY_CTRL_PLANE_ENABLE 1 +#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT 1:0 +#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_8 0 +#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_16 1 +#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4 2 +#define VIDEO_ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4_4_4 3 + +#define VIDEO_ALPHA_FB_ADDRESS 0x080084 +#define VIDEO_ALPHA_FB_ADDRESS_STATUS 31:31 +#define VIDEO_ALPHA_FB_ADDRESS_STATUS_CURRENT 0 +#define VIDEO_ALPHA_FB_ADDRESS_STATUS_PENDING 1 +#define VIDEO_ALPHA_FB_ADDRESS_ADDRESS 29:0 + +#define VIDEO_ALPHA_FB_WIDTH 0x080088 +#define VIDEO_ALPHA_FB_WIDTH_WIDTH 29:16 +#define VIDEO_ALPHA_FB_WIDTH_OFFSET 13:0 + +#define VIDEO_ALPHA_PLANE_TL 0x08008C +#define VIDEO_ALPHA_PLANE_TL_TOP 26:16 +#define VIDEO_ALPHA_PLANE_TL_LEFT 11:0 + +#define VIDEO_ALPHA_PLANE_BR 0x080090 +#define VIDEO_ALPHA_PLANE_BR_BOTTOM 26:16 +#define VIDEO_ALPHA_PLANE_BR_RIGHT 11:0 + +#define VIDEO_ALPHA_CHROMA_KEY 0x080094 +#define VIDEO_ALPHA_CHROMA_KEY_MASK 31:16 +#define VIDEO_ALPHA_CHROMA_KEY_VALUE 15:0 + +#define VIDEO_ALPHA_COLOR_LOOKUP_01 0x080098 +#define VIDEO_ALPHA_COLOR_LOOKUP_01_1 31:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_01_1_RED 31:27 +#define VIDEO_ALPHA_COLOR_LOOKUP_01_1_GREEN 26:21 +#define VIDEO_ALPHA_COLOR_LOOKUP_01_1_BLUE 20:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_01_0 15:0 +#define VIDEO_ALPHA_COLOR_LOOKUP_01_0_RED 15:11 +#define VIDEO_ALPHA_COLOR_LOOKUP_01_0_GREEN 10:5 +#define VIDEO_ALPHA_COLOR_LOOKUP_01_0_BLUE 4:0 + +#define VIDEO_ALPHA_COLOR_LOOKUP_23 0x08009C +#define VIDEO_ALPHA_COLOR_LOOKUP_23_3 31:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_23_3_RED 31:27 +#define VIDEO_ALPHA_COLOR_LOOKUP_23_3_GREEN 26:21 +#define VIDEO_ALPHA_COLOR_LOOKUP_23_3_BLUE 20:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_23_2 15:0 +#define VIDEO_ALPHA_COLOR_LOOKUP_23_2_RED 15:11 +#define VIDEO_ALPHA_COLOR_LOOKUP_23_2_GREEN 10:5 +#define VIDEO_ALPHA_COLOR_LOOKUP_23_2_BLUE 4:0 + +#define VIDEO_ALPHA_COLOR_LOOKUP_45 0x0800A0 +#define VIDEO_ALPHA_COLOR_LOOKUP_45_5 31:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_45_5_RED 31:27 +#define VIDEO_ALPHA_COLOR_LOOKUP_45_5_GREEN 26:21 +#define VIDEO_ALPHA_COLOR_LOOKUP_45_5_BLUE 20:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_45_4 15:0 +#define VIDEO_ALPHA_COLOR_LOOKUP_45_4_RED 15:11 +#define VIDEO_ALPHA_COLOR_LOOKUP_45_4_GREEN 10:5 +#define VIDEO_ALPHA_COLOR_LOOKUP_45_4_BLUE 4:0 + +#define VIDEO_ALPHA_COLOR_LOOKUP_67 0x0800A4 +#define VIDEO_ALPHA_COLOR_LOOKUP_67_7 31:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_67_7_RED 31:27 +#define VIDEO_ALPHA_COLOR_LOOKUP_67_7_GREEN 26:21 +#define VIDEO_ALPHA_COLOR_LOOKUP_67_7_BLUE 20:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_67_6 15:0 +#define VIDEO_ALPHA_COLOR_LOOKUP_67_6_RED 15:11 +#define VIDEO_ALPHA_COLOR_LOOKUP_67_6_GREEN 10:5 +#define VIDEO_ALPHA_COLOR_LOOKUP_67_6_BLUE 4:0 + +#define VIDEO_ALPHA_COLOR_LOOKUP_89 0x0800A8 +#define VIDEO_ALPHA_COLOR_LOOKUP_89_9 31:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_89_9_RED 31:27 +#define VIDEO_ALPHA_COLOR_LOOKUP_89_9_GREEN 26:21 +#define VIDEO_ALPHA_COLOR_LOOKUP_89_9_BLUE 20:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_89_8 15:0 +#define VIDEO_ALPHA_COLOR_LOOKUP_89_8_RED 15:11 +#define VIDEO_ALPHA_COLOR_LOOKUP_89_8_GREEN 10:5 +#define VIDEO_ALPHA_COLOR_LOOKUP_89_8_BLUE 4:0 + +#define VIDEO_ALPHA_COLOR_LOOKUP_AB 0x0800AC +#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B 31:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B_RED 31:27 +#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B_GREEN 26:21 +#define VIDEO_ALPHA_COLOR_LOOKUP_AB_B_BLUE 20:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A 15:0 +#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A_RED 15:11 +#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A_GREEN 10:5 +#define VIDEO_ALPHA_COLOR_LOOKUP_AB_A_BLUE 4:0 + +#define VIDEO_ALPHA_COLOR_LOOKUP_CD 0x0800B0 +#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D 31:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D_RED 31:27 +#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D_GREEN 26:21 +#define VIDEO_ALPHA_COLOR_LOOKUP_CD_D_BLUE 20:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C 15:0 +#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C_RED 15:11 +#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C_GREEN 10:5 +#define VIDEO_ALPHA_COLOR_LOOKUP_CD_C_BLUE 4:0 + +#define VIDEO_ALPHA_COLOR_LOOKUP_EF 0x0800B4 +#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F 31:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F_RED 31:27 +#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F_GREEN 26:21 +#define VIDEO_ALPHA_COLOR_LOOKUP_EF_F_BLUE 20:16 +#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E 15:0 +#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E_RED 15:11 +#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E_GREEN 10:5 +#define VIDEO_ALPHA_COLOR_LOOKUP_EF_E_BLUE 4:0 +#endif + +/* Alpha Control */ + +#define ALPHA_DISPLAY_CTRL 0x080080 +#define ALPHA_DISPLAY_CTRL_SELECT 28:28 +#define ALPHA_DISPLAY_CTRL_SELECT_PER_PIXEL 0 +#define ALPHA_DISPLAY_CTRL_SELECT_ALPHA 1 +#define ALPHA_DISPLAY_CTRL_ALPHA 27:24 +#define ALPHA_DISPLAY_CTRL_FIFO 17:16 +#define ALPHA_DISPLAY_CTRL_FIFO_1 0 +#define ALPHA_DISPLAY_CTRL_FIFO_3 1 +#define ALPHA_DISPLAY_CTRL_FIFO_7 2 +#define ALPHA_DISPLAY_CTRL_FIFO_11 3 +#define ALPHA_DISPLAY_CTRL_PIXEL 7:4 +#define ALPHA_DISPLAY_CTRL_CHROMA_KEY 3:3 +#define ALPHA_DISPLAY_CTRL_CHROMA_KEY_DISABLE 0 +#define ALPHA_DISPLAY_CTRL_CHROMA_KEY_ENABLE 1 +#define ALPHA_DISPLAY_CTRL_PLANE 2:2 +#define ALPHA_DISPLAY_CTRL_PLANE_DISABLE 0 +#define ALPHA_DISPLAY_CTRL_PLANE_ENABLE 1 +#define ALPHA_DISPLAY_CTRL_FORMAT 1:0 +#define ALPHA_DISPLAY_CTRL_FORMAT_16 1 +#define ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4 2 +#define ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4_4_4 3 + +#define ALPHA_FB_ADDRESS 0x080084 +#define ALPHA_FB_ADDRESS_STATUS 31:31 +#define ALPHA_FB_ADDRESS_STATUS_CURRENT 0 +#define ALPHA_FB_ADDRESS_STATUS_PENDING 1 +#define ALPHA_FB_ADDRESS_ADDRESS 29:0 + +#define ALPHA_FB_WIDTH 0x080088 +#define ALPHA_FB_WIDTH_WIDTH 29:16 +#define ALPHA_FB_WIDTH_OFFSET 13:0 + +#define ALPHA_PLANE_TL 0x08008C +#define ALPHA_PLANE_TL_TOP 26:16 +#define ALPHA_PLANE_TL_LEFT 10:0 + +#define ALPHA_PLANE_BR 0x080090 +#define ALPHA_PLANE_BR_BOTTOM 26:16 +#define ALPHA_PLANE_BR_RIGHT 10:0 + +#define ALPHA_CHROMA_KEY 0x080094 +#define ALPHA_CHROMA_KEY_MASK 31:16 +#define ALPHA_CHROMA_KEY_VALUE 15:0 + +#define ALPHA_COLOR_LOOKUP_01 0x080098 +#define ALPHA_COLOR_LOOKUP_01_1 31:16 +#define ALPHA_COLOR_LOOKUP_01_1_RED 31:27 +#define ALPHA_COLOR_LOOKUP_01_1_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_01_1_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_01_0 15:0 +#define ALPHA_COLOR_LOOKUP_01_0_RED 15:11 +#define ALPHA_COLOR_LOOKUP_01_0_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_01_0_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_23 0x08009C +#define ALPHA_COLOR_LOOKUP_23_3 31:16 +#define ALPHA_COLOR_LOOKUP_23_3_RED 31:27 +#define ALPHA_COLOR_LOOKUP_23_3_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_23_3_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_23_2 15:0 +#define ALPHA_COLOR_LOOKUP_23_2_RED 15:11 +#define ALPHA_COLOR_LOOKUP_23_2_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_23_2_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_45 0x0800a0 +#define ALPHA_COLOR_LOOKUP_45_5 31:16 +#define ALPHA_COLOR_LOOKUP_45_5_RED 31:27 +#define ALPHA_COLOR_LOOKUP_45_5_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_45_5_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_45_4 15:0 +#define ALPHA_COLOR_LOOKUP_45_4_RED 15:11 +#define ALPHA_COLOR_LOOKUP_45_4_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_45_4_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_67 0x0800a4 +#define ALPHA_COLOR_LOOKUP_67_7 31:16 +#define ALPHA_COLOR_LOOKUP_67_7_RED 31:27 +#define ALPHA_COLOR_LOOKUP_67_7_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_67_7_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_67_6 15:0 +#define ALPHA_COLOR_LOOKUP_67_6_RED 15:11 +#define ALPHA_COLOR_LOOKUP_67_6_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_67_6_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_89 0x0800a8 +#define ALPHA_COLOR_LOOKUP_89_9 31:16 +#define ALPHA_COLOR_LOOKUP_89_9_RED 31:27 +#define ALPHA_COLOR_LOOKUP_89_9_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_89_9_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_89_8 15:0 +#define ALPHA_COLOR_LOOKUP_89_8_RED 15:11 +#define ALPHA_COLOR_LOOKUP_89_8_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_89_8_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_AB 0x0800AC +#define ALPHA_COLOR_LOOKUP_AB_B 31:16 +#define ALPHA_COLOR_LOOKUP_AB_B_RED 31:27 +#define ALPHA_COLOR_LOOKUP_AB_B_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_AB_B_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_AB_A 15:0 +#define ALPHA_COLOR_LOOKUP_AB_A_RED 15:11 +#define ALPHA_COLOR_LOOKUP_AB_A_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_AB_A_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_CD 0x0800B0 +#define ALPHA_COLOR_LOOKUP_CD_D 31:16 +#define ALPHA_COLOR_LOOKUP_CD_D_RED 31:27 +#define ALPHA_COLOR_LOOKUP_CD_D_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_CD_D_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_CD_C 15:0 +#define ALPHA_COLOR_LOOKUP_CD_C_RED 15:11 +#define ALPHA_COLOR_LOOKUP_CD_C_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_CD_C_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_EF 0x0800B4 +#define ALPHA_COLOR_LOOKUP_EF_F 31:16 +#define ALPHA_COLOR_LOOKUP_EF_F_RED 31:27 +#define ALPHA_COLOR_LOOKUP_EF_F_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_EF_F_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_EF_E 15:0 +#define ALPHA_COLOR_LOOKUP_EF_E_RED 15:11 +#define ALPHA_COLOR_LOOKUP_EF_E_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_EF_E_BLUE 4:0 + +/* Distance between channel 1 and channel 2 display control */ +#define CHANNEL_OFFSET 0x8000 + +#define DC_OFFSET 0x8000 + + +/* Palette RAM */ +/* Panel Pallete register starts at 0x080400 ~ 0x0807FC */ +#define CHANNEL0_PALETTE_RAM 0x080C00 +#define PALETTE_RAM 0x080C00 + +/* Panel Pallete register starts at 0x080C00 ~ 0x080FFC */ +#define CHANNEL1_PALETTE_RAM 0x088C00 + +//#include "regdma.h" + +/* New DMA engine definition for Falcon */ +/* DMA 0 is uni-directional from Serial ROM to local DDR only */ +#define DMA0_DESTINATION 0x0D0000 +#define DMA0_DESTINATION_ADDRESS 29:0 + +#define DMA0_SOURCE 0x0D0004 +#define DMA0_SOURCE_ADDRESS 23:0 + +#define DMA0_CONTROL 0x0D0008 +#define DMA0_CONTROL_STATUS 31:31 +#define DMA0_CONTROL_STATUS_IDLE 0 +#define DMA0_CONTROL_STATUS_ENABLE 1 +#define DMA0_CONTROL_SIZE 23:0 + +/* DMA 1 can transfer from: + System to local DDR. + local DDR to system. + local DDR to local DDR. + + The source is alwasy linear and the destination is always tiled. +*/ +#define DMA1_SOURCE0 0x0D0010 +#define DMA1_SOURCE0_SEL 31:31 +#define DMA1_SOURCE0_SEL_LOCAL 0 +#define DMA1_SOURCE0_SEL_SYSTEM 1 +#define DMA1_SOURCE0_DECODE 30:30 +#define DMA1_SOURCE0_DECODE_DISABLE 0 +#define DMA1_SOURCE0_DECODE_ENABLE 1 +#define DMA1_SOURCE0_ADDRESS 29:0 + +#define DMA1_SOURCE0_SIZE 0x0D0014 +#define DMA1_SOURCE0_SIZE_NSC_CSS 27:27 +#define DMA1_SOURCE0_SIZE_NSC_CSS_DISABLE 0 +#define DMA1_SOURCE0_SIZE_NSC_CSS_ENABLE 1 +#define DMA1_SOURCE0_SIZE_NSC_CLL 26:24 +#define DMA1_SOURCE0_SIZE_SIZE 23:0 + +#define DMA1_DESTINATION 0x0D0018 +#define DMA1_DESTINATION_SEL 31:31 +#define DMA1_DESTINATION_SEL_LOCAL 0 +#define DMA1_DESTINATION_SEL_SYSTEM 1 +#define DMA1_DESTINATION_ADDRESS 29:0 + +#define DMA1_CONTROL 0x0D001C +#define DMA1_CONTROL_STATUS 31:31 +#define DMA1_CONTROL_STATUS_IDLE 0 +#define DMA1_CONTROL_STATUS_ENABLE 1 +#define DMA1_CONTROL_TRI_STREAM 30:30 +#define DMA1_CONTROL_TRI_STREAM_DISABLE 0 +#define DMA1_CONTROL_TRI_STREAM_ENABLE 1 +#define DMA1_CONTROL_FORMAT 29:28 +#define DMA1_CONTROL_FORMAT_8BPP 0 +#define DMA1_CONTROL_FORMAT_16BPP 1 +#define DMA1_CONTROL_FORMAT_32BPP 2 +#define DMA1_CONTROL_TILE_HEIGHT 27:16 +#define DMA1_CONTROL_TILE_WIDTH 12:0 + +#define DMA1_DESTINATION_PITCH 0x0D0020 +#define DMA1_DESTINATION_PITCH_PITCH 14:0 + +#define DMA_CONTROL 0x0D0024 +#define DMA_CONTROL_NSC_RB_SWAP 11:11 +#define DMA_CONTROL_NSC_RB_SWAP_DISABLE 0 +#define DMA_CONTROL_NSC_RB_SWAP_ENABLE 1 +#define DMA_CONTROL_CSC 10:10 +#define DMA_CONTROL_CSC_DISABLE 0 +#define DMA_CONTROL_CSC_ENABLE 1 +#define DMA_CONTROL_DECOMP 9:8 +#define DMA_CONTROL_DECOMP_TEXT 0 +#define DMA_CONTROL_DECOMP_NSC 1 +#define DMA_CONTROL_DECOMP_GOLOMB 2 +#define DMA_CONTROL_DMA1_STATUS 5:5 +#define DMA_CONTROL_DMA1_STATUS_NORMAL 0 +#define DMA_CONTROL_DMA1_STATUS_ABORT 1 +#define DMA_CONTROL_DMA0_STATUS 4:4 +#define DMA_CONTROL_DMA0_STATUS_NORMAL 0 +#define DMA_CONTROL_DMA0_STATUS_ABORT 1 +#define DMA_CONTROL_DMA1_RAWINT 1:1 +#define DMA_CONTROL_DMA1_RAWINT_CLEAR 0 +#define DMA_CONTROL_DMA1_RAWINT_SET 1 +#define DMA_CONTROL_DMA0_RAWINT 0:0 +#define DMA_CONTROL_DMA0_RAWINT_CLEAR 0 +#define DMA_CONTROL_DMA0_RAWINT_SET 1 + +/* DMA 1 source 1 and source 2 are only used when RGB is in 3 separate planes.*/ +#define DMA1_SOURCE1 0x0D0028 +#define DMA1_SOURCE1_ADDRESS 29:0 + +#define DMA1_SOURCE1_SIZE 0x0D002c +#define DMA1_SOURCE1_SIZE_NSC_CSS 27:27 +#define DMA1_SOURCE1_SIZE_NSC_CSS_DISABLE 0 +#define DMA1_SOURCE1_SIZE_NSC_CSS_ENABLE 1 +#define DMA1_SOURCE1_SIZE_NSC_CLL 26:24 +#define DMA1_SOURCE1_SIZE_SIZE 23:0 + +#define DMA1_SOURCE2 0x0D0030 +#define DMA1_SOURCE2_ADDRESS 29:0 + +#define DMA1_SOURCE2_SIZE 0x0D0034 +#define DMA1_SOURCE2_SIZE_NSC_CSS 27:27 +#define DMA1_SOURCE2_SIZE_NSC_CSS_DISABLE 0 +#define DMA1_SOURCE2_SIZE_NSC_CSS_ENABLE 1 +#define DMA1_SOURCE2_SIZE_NSC_CLL 26:24 +#define DMA1_SOURCE2_SIZE_SIZE 23:0 + + +//#include "regde.h" +/* 2D registers. */ + +#define DE_SOURCE 0x100000 +#define DE_SOURCE_WRAP 31:31 +#define DE_SOURCE_WRAP_DISABLE 0 +#define DE_SOURCE_WRAP_ENABLE 1 + +/* + * The following definitions are used in different setting + */ + +/* Use these definitions in XY addressing mode or linear addressing mode. */ +#define DE_SOURCE_X_K1 27:16 +#define DE_SOURCE_Y_K2 11:0 + +/* Use this definition in host write mode for mono. The Y_K2 is not used + in host write mode. */ +#define DE_SOURCE_X_K1_MONO 20:16 + +/* Use these definitions in Bresenham line drawing mode. */ +#define DE_SOURCE_X_K1_LINE 29:16 +#define DE_SOURCE_Y_K2_LINE 13:0 + +#define DE_DESTINATION 0x100004 +#define DE_DESTINATION_WRAP 31:31 +#define DE_DESTINATION_WRAP_DISABLE 0 +#define DE_DESTINATION_WRAP_ENABLE 1 +#if 1 + #define DE_DESTINATION_X 27:16 + #define DE_DESTINATION_Y 11:0 +#else + #define DE_DESTINATION_X 28:16 + #define DE_DESTINATION_Y 15:0 +#endif + +#define DE_DIMENSION 0x100008 +#define DE_DIMENSION_X 28:16 +#define DE_DIMENSION_Y_ET 15:0 + +#define DE_CONTROL 0x10000C +#define DE_CONTROL_STATUS 31:31 +#define DE_CONTROL_STATUS_STOP 0 +#define DE_CONTROL_STATUS_START 1 +#define DE_CONTROL_PATTERN 30:30 +#define DE_CONTROL_PATTERN_MONO 0 +#define DE_CONTROL_PATTERN_COLOR 1 +#define DE_CONTROL_UPDATE_DESTINATION_X 29:29 +#define DE_CONTROL_UPDATE_DESTINATION_X_DISABLE 0 +#define DE_CONTROL_UPDATE_DESTINATION_X_ENABLE 1 +#define DE_CONTROL_QUICK_START 28:28 +#define DE_CONTROL_QUICK_START_DISABLE 0 +#define DE_CONTROL_QUICK_START_ENABLE 1 +#define DE_CONTROL_DIRECTION 27:27 +#define DE_CONTROL_DIRECTION_LEFT_TO_RIGHT 0 +#define DE_CONTROL_DIRECTION_RIGHT_TO_LEFT 1 +#define DE_CONTROL_MAJOR 26:26 +#define DE_CONTROL_MAJOR_X 0 +#define DE_CONTROL_MAJOR_Y 1 +#define DE_CONTROL_STEP_X 25:25 +#define DE_CONTROL_STEP_X_POSITIVE 0 +#define DE_CONTROL_STEP_X_NEGATIVE 1 +#define DE_CONTROL_STEP_Y 24:24 +#define DE_CONTROL_STEP_Y_POSITIVE 0 +#define DE_CONTROL_STEP_Y_NEGATIVE 1 +#define DE_CONTROL_STRETCH 23:23 +#define DE_CONTROL_STRETCH_DISABLE 0 +#define DE_CONTROL_STRETCH_ENABLE 1 +#define DE_CONTROL_HOST 22:22 +#define DE_CONTROL_HOST_COLOR 0 +#define DE_CONTROL_HOST_MONO 1 +#define DE_CONTROL_LAST_PIXEL 21:21 +#define DE_CONTROL_LAST_PIXEL_OFF 0 +#define DE_CONTROL_LAST_PIXEL_ON 1 +#define DE_CONTROL_COMMAND 20:16 +#define DE_CONTROL_COMMAND_BITBLT 0 +#define DE_CONTROL_COMMAND_RECTANGLE_FILL 1 +#define DE_CONTROL_COMMAND_DE_TILE 2 +#define DE_CONTROL_COMMAND_TRAPEZOID_FILL 3 +#define DE_CONTROL_COMMAND_ALPHA_BLEND 4 +#define DE_CONTROL_COMMAND_RLE_STRIP 5 +#define DE_CONTROL_COMMAND_SHORT_STROKE 6 +#define DE_CONTROL_COMMAND_LINE_DRAW 7 +#define DE_CONTROL_COMMAND_HOST_WRITE 8 +#define DE_CONTROL_COMMAND_HOST_READ 9 +#define DE_CONTROL_COMMAND_HOST_WRITE_BOTTOM_UP 10 +#define DE_CONTROL_COMMAND_ROTATE 11 +#define DE_CONTROL_COMMAND_FONT 12 +#define DE_CONTROL_COMMAND_TEXTURE_LOAD 15 +#define DE_CONTROL_ROP_SELECT 15:15 +#define DE_CONTROL_ROP_SELECT_ROP3 0 +#define DE_CONTROL_ROP_SELECT_ROP2 1 +#define DE_CONTROL_ROP2_SOURCE 14:14 +#define DE_CONTROL_ROP2_SOURCE_BITMAP 0 +#define DE_CONTROL_ROP2_SOURCE_PATTERN 1 +#define DE_CONTROL_MONO_DATA 13:12 +#define DE_CONTROL_MONO_DATA_NOT_PACKED 0 +#define DE_CONTROL_MONO_DATA_8_PACKED 1 +#define DE_CONTROL_MONO_DATA_16_PACKED 2 +#define DE_CONTROL_MONO_DATA_32_PACKED 3 +#define DE_CONTROL_REPEAT_ROTATE 11:11 +#define DE_CONTROL_REPEAT_ROTATE_DISABLE 0 +#define DE_CONTROL_REPEAT_ROTATE_ENABLE 1 +#define DE_CONTROL_TRANSPARENCY_MATCH 10:10 +#define DE_CONTROL_TRANSPARENCY_MATCH_OPAQUE 0 +#define DE_CONTROL_TRANSPARENCY_MATCH_TRANSPARENT 1 +#define DE_CONTROL_TRANSPARENCY_SELECT 9:9 +#define DE_CONTROL_TRANSPARENCY_SELECT_SOURCE 0 +#define DE_CONTROL_TRANSPARENCY_SELECT_DESTINATION 1 +#define DE_CONTROL_TRANSPARENCY 8:8 +#define DE_CONTROL_TRANSPARENCY_DISABLE 0 +#define DE_CONTROL_TRANSPARENCY_ENABLE 1 +#define DE_CONTROL_ROP 7:0 + +/* Pseudo fields. */ + +#define DE_CONTROL_SHORT_STROKE_DIR 27:24 +#define DE_CONTROL_SHORT_STROKE_DIR_225 0 +#define DE_CONTROL_SHORT_STROKE_DIR_135 1 +#define DE_CONTROL_SHORT_STROKE_DIR_315 2 +#define DE_CONTROL_SHORT_STROKE_DIR_45 3 +#define DE_CONTROL_SHORT_STROKE_DIR_270 4 +#define DE_CONTROL_SHORT_STROKE_DIR_90 5 +#define DE_CONTROL_SHORT_STROKE_DIR_180 8 +#define DE_CONTROL_SHORT_STROKE_DIR_0 10 +#define DE_CONTROL_ROTATION 25:24 +#define DE_CONTROL_ROTATION_0 0 +#define DE_CONTROL_ROTATION_270 1 +#define DE_CONTROL_ROTATION_90 2 +#define DE_CONTROL_ROTATION_180 3 + +#define DE_PITCH 0x100010 +#define DE_PITCH_DESTINATION 28:16 +#define DE_PITCH_SOURCE 12:0 + +#define DE_FOREGROUND 0x100014 +#define DE_FOREGROUND_COLOR 31:0 + +#define DE_BACKGROUND 0x100018 +#define DE_BACKGROUND_COLOR 31:0 + +#define DE_STRETCH_FORMAT 0x10001C +#define DE_STRETCH_FORMAT_PATTERN_XY 30:30 +#define DE_STRETCH_FORMAT_PATTERN_XY_NORMAL 0 +#define DE_STRETCH_FORMAT_PATTERN_XY_OVERWRITE 1 +#define DE_STRETCH_FORMAT_PATTERN_Y 29:27 +#define DE_STRETCH_FORMAT_PATTERN_X 25:23 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT 21:20 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_8 0 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_16 1 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_32 2 +#define DE_STRETCH_FORMAT_ADDRESSING 19:16 +#define DE_STRETCH_FORMAT_ADDRESSING_XY 0 +#define DE_STRETCH_FORMAT_ADDRESSING_LINEAR 15 +#define DE_STRETCH_FORMAT_SOURCE_HEIGHT 11:0 + +#define DE_COLOR_COMPARE 0x100020 +#define DE_COLOR_COMPARE_COLOR 23:0 + +#define DE_COLOR_COMPARE_MASK 0x100024 +#define DE_COLOR_COMPARE_MASK_MASKS 23:0 + +#define DE_MASKS 0x100028 +#define DE_MASKS_BYTE_MASK 31:16 +#define DE_MASKS_BIT_MASK 15:0 + +#define DE_CLIP_TL 0x10002C +#define DE_CLIP_TL_TOP 31:16 +#define DE_CLIP_TL_STATUS 13:13 +#define DE_CLIP_TL_STATUS_DISABLE 0 +#define DE_CLIP_TL_STATUS_ENABLE 1 +#define DE_CLIP_TL_INHIBIT 12:12 +#define DE_CLIP_TL_INHIBIT_OUTSIDE 0 +#define DE_CLIP_TL_INHIBIT_INSIDE 1 +#define DE_CLIP_TL_LEFT 11:0 + +#define DE_CLIP_BR 0x100030 +#define DE_CLIP_BR_BOTTOM 31:16 +#define DE_CLIP_BR_RIGHT 12:0 + +#define DE_MONO_PATTERN_LOW 0x100034 +#define DE_MONO_PATTERN_LOW_PATTERN 31:0 + +#define DE_MONO_PATTERN_HIGH 0x100038 +#define DE_MONO_PATTERN_HIGH_PATTERN 31:0 + +#define DE_WINDOW_WIDTH 0x10003C +#define DE_WINDOW_WIDTH_DESTINATION 28:16 +#define DE_WINDOW_WIDTH_SOURCE 12:0 + +#define DE_WINDOW_SOURCE_BASE 0x100040 +#define DE_WINDOW_SOURCE_BASE_ADDRESS 29:0 + +#define DE_WINDOW_DESTINATION_BASE 0x100044 +#define DE_WINDOW_DESTINATION_BASE_ADDRESS 29:0 + +#define DE_ALPHA 0x100048 +#define DE_ALPHA_VALUE 7:0 + +#define DE_WRAP 0x10004C +#define DE_WRAP_X 31:16 +#define DE_WRAP_Y 15:0 + +#define DE_STATE2 0x100054 +#define DE_STATE2_DE_FIFO 3:3 +#define DE_STATE2_DE_FIFO_NOTEMPTY 1 +#define DE_STATE2_DE_FIFO_EMPTY 0 +#define DE_STATE2_DE_STATUS 2:2 +#define DE_STATE2_DE_STATUS_IDLE 0 +#define DE_STATE2_DE_STATUS_BUSY 1 +#define DE_STATE2_DE_MEM_FIFO 1:1 +#define DE_STATE2_DE_MEM_FIFO_NOTEMPTY 0 +#define DE_STATE2_DE_MEM_FIFO_EMPTY 1 +#define DE_STATE2_DE_ABORT 0:0 +#define DE_STATE2_DE_ABORT_OFF 0 +#define DE_STATE2_DE_ABORT_ON 1 + +/* Color Space Conversion registers. */ + +#define CSC_Y_SOURCE_BASE 0x1000C8 +#define CSC_Y_SOURCE_BASE_ADDRESS 29:0 + +#define CSC_CONSTANTS 0x1000CC +#define CSC_CONSTANTS_Y 31:24 +#define CSC_CONSTANTS_R 23:16 +#define CSC_CONSTANTS_G 15:8 +#define CSC_CONSTANTS_B 7:0 + +#define CSC_Y_SOURCE_X 0x1000D0 +#define CSC_Y_SOURCE_X_INTEGER 26:16 +#define CSC_Y_SOURCE_X_FRACTION 15:3 + +#define CSC_Y_SOURCE_Y 0x1000D4 +#define CSC_Y_SOURCE_Y_INTEGER 27:16 +#define CSC_Y_SOURCE_Y_FRACTION 15:3 + +#define CSC_U_SOURCE_BASE 0x1000D8 +#define CSC_U_SOURCE_BASE_ADDRESS 29:0 + +#define CSC_V_SOURCE_BASE 0x1000DC +#define CSC_V_SOURCE_BASE_ADDRESS 29:0 + +#define CSC_SOURCE_DIMENSION 0x1000E0 +#define CSC_SOURCE_DIMENSION_X 31:16 +#define CSC_SOURCE_DIMENSION_Y 15:0 + +#define CSC_SOURCE_PITCH 0x1000E4 +#define CSC_SOURCE_PITCH_Y 31:16 +#define CSC_SOURCE_PITCH_UV 15:0 + +#define CSC_DESTINATION 0x1000E8 +#define CSC_DESTINATION_WRAP 31:31 +#define CSC_DESTINATION_WRAP_DISABLE 0 +#define CSC_DESTINATION_WRAP_ENABLE 1 +#define CSC_DESTINATION_X 27:16 +#define CSC_DESTINATION_Y 11:0 + +#define CSC_DESTINATION_DIMENSION 0x1000EC +#define CSC_DESTINATION_DIMENSION_X 31:16 +#define CSC_DESTINATION_DIMENSION_Y 15:0 + +#define CSC_DESTINATION_PITCH 0x1000F0 +#define CSC_DESTINATION_PITCH_X 31:16 +#define CSC_DESTINATION_PITCH_Y 15:0 + +#define CSC_SCALE_FACTOR 0x1000F4 +#define CSC_SCALE_FACTOR_HORIZONTAL 31:16 +#define CSC_SCALE_FACTOR_VERTICAL 15:0 + +#define CSC_DESTINATION_BASE 0x1000F8 +#define CSC_DESTINATION_BASE_ADDRESS 29:0 + +#define CSC_CONTROL 0x1000FC +#define CSC_CONTROL_STATUS 31:31 +#define CSC_CONTROL_STATUS_STOP 0 +#define CSC_CONTROL_STATUS_START 1 +#define CSC_CONTROL_SOURCE_FORMAT 30:28 +#define CSC_CONTROL_SOURCE_FORMAT_YUV422 0 +#define CSC_CONTROL_SOURCE_FORMAT_YUV420I 1 +#define CSC_CONTROL_SOURCE_FORMAT_YUV420 2 +#define CSC_CONTROL_SOURCE_FORMAT_YVU9 3 +#define CSC_CONTROL_SOURCE_FORMAT_IYU1 4 +#define CSC_CONTROL_SOURCE_FORMAT_IYU2 5 +#define CSC_CONTROL_SOURCE_FORMAT_RGB565 6 +#define CSC_CONTROL_SOURCE_FORMAT_RGB8888 7 +#define CSC_CONTROL_DESTINATION_FORMAT 27:26 +#define CSC_CONTROL_DESTINATION_FORMAT_RGB565 0 +#define CSC_CONTROL_DESTINATION_FORMAT_RGB8888 1 +#define CSC_CONTROL_HORIZONTAL_FILTER 25:25 +#define CSC_CONTROL_HORIZONTAL_FILTER_DISABLE 0 +#define CSC_CONTROL_HORIZONTAL_FILTER_ENABLE 1 +#define CSC_CONTROL_VERTICAL_FILTER 24:24 +#define CSC_CONTROL_VERTICAL_FILTER_DISABLE 0 +#define CSC_CONTROL_VERTICAL_FILTER_ENABLE 1 +#define CSC_CONTROL_BYTE_ORDER 23:23 +#define CSC_CONTROL_BYTE_ORDER_YUYV 0 +#define CSC_CONTROL_BYTE_ORDER_UYVY 1 + +#define DE_DATA_PORT 0x110000 + +//#include "regzv.h" + +/* ZV0 */ + +#define ZV0_CAPTURE_CTRL 0x090000 +#define ZV0_CAPTURE_CTRL_FIELD_INPUT 27:27 +#define ZV0_CAPTURE_CTRL_FIELD_INPUT_EVEN_FIELD 0 +#define ZV0_CAPTURE_CTRL_FIELD_INPUT_ODD_FIELD 1 +#define ZV0_CAPTURE_CTRL_SCAN 26:26 +#define ZV0_CAPTURE_CTRL_SCAN_PROGRESSIVE 0 +#define ZV0_CAPTURE_CTRL_SCAN_INTERLACE 1 +#define ZV0_CAPTURE_CTRL_CURRENT_BUFFER 25:25 +#define ZV0_CAPTURE_CTRL_CURRENT_BUFFER_0 0 +#define ZV0_CAPTURE_CTRL_CURRENT_BUFFER_1 1 +#define ZV0_CAPTURE_CTRL_VERTICAL_SYNC 24:24 +#define ZV0_CAPTURE_CTRL_VERTICAL_SYNC_INACTIVE 0 +#define ZV0_CAPTURE_CTRL_VERTICAL_SYNC_ACTIVE 1 +#define ZV0_CAPTURE_CTRL_OUTPUT_FORMAT 22:22 +#define ZV0_CAPTURE_CTRL_OUTPUT_FORMAT_16 0 +#define ZV0_CAPTURE_CTRL_OUTPUT_FORMAT_32 1 +#define ZV0_CAPTURE_CTRL_INCOME_DATA 21:21 +#define ZV0_CAPTURE_CTRL_INCOME_DATA_16 0 +#define ZV0_CAPTURE_CTRL_INCOME_DATA_32 1 +#define ZV0_CAPTURE_CTRL_ADJ 19:19 +#define ZV0_CAPTURE_CTRL_ADJ_NORMAL 0 +#define ZV0_CAPTURE_CTRL_ADJ_DELAY 1 +#define ZV0_CAPTURE_CTRL_HA 18:18 +#define ZV0_CAPTURE_CTRL_HA_DISABLE 0 +#define ZV0_CAPTURE_CTRL_HA_ENABLE 1 +#define ZV0_CAPTURE_CTRL_VSK 17:17 +#define ZV0_CAPTURE_CTRL_VSK_DISABLE 0 +#define ZV0_CAPTURE_CTRL_VSK_ENABLE 1 +#define ZV0_CAPTURE_CTRL_HSK 16:16 +#define ZV0_CAPTURE_CTRL_HSK_DISABLE 0 +#define ZV0_CAPTURE_CTRL_HSK_ENABLE 1 +#define ZV0_CAPTURE_CTRL_FD 15:15 +#define ZV0_CAPTURE_CTRL_FD_RISING 0 +#define ZV0_CAPTURE_CTRL_FD_FALLING 1 +#define ZV0_CAPTURE_CTRL_VP 14:14 +#define ZV0_CAPTURE_CTRL_VP_HIGH 0 +#define ZV0_CAPTURE_CTRL_VP_LOW 1 +#define ZV0_CAPTURE_CTRL_HP 13:13 +#define ZV0_CAPTURE_CTRL_HP_HIGH 0 +#define ZV0_CAPTURE_CTRL_HP_LOW 1 +#define ZV0_CAPTURE_CTRL_CP 12:12 +#define ZV0_CAPTURE_CTRL_CP_HIGH 0 +#define ZV0_CAPTURE_CTRL_CP_LOW 1 +#define ZV0_CAPTURE_CTRL_UVS 11:11 +#define ZV0_CAPTURE_CTRL_UVS_DISABLE 0 +#define ZV0_CAPTURE_CTRL_UVS_ENABLE 1 +#define ZV0_CAPTURE_CTRL_BS 10:10 +#define ZV0_CAPTURE_CTRL_BS_DISABLE 0 +#define ZV0_CAPTURE_CTRL_BS_ENABLE 1 +#define ZV0_CAPTURE_CTRL_CS 9:9 +#define ZV0_CAPTURE_CTRL_CS_16 0 +#define ZV0_CAPTURE_CTRL_CS_8 1 +#define ZV0_CAPTURE_CTRL_CF 8:8 +#define ZV0_CAPTURE_CTRL_CF_YUV 0 +#define ZV0_CAPTURE_CTRL_CF_RGB 1 +#define ZV0_CAPTURE_CTRL_FS 7:7 +#define ZV0_CAPTURE_CTRL_FS_DISABLE 0 +#define ZV0_CAPTURE_CTRL_FS_ENABLE 1 +#define ZV0_CAPTURE_CTRL_WEAVE 6:6 +#define ZV0_CAPTURE_CTRL_WEAVE_DISABLE 0 +#define ZV0_CAPTURE_CTRL_WEAVE_ENABLE 1 +#define ZV0_CAPTURE_CTRL_BOB 5:5 +#define ZV0_CAPTURE_CTRL_BOB_DISABLE 0 +#define ZV0_CAPTURE_CTRL_BOB_ENABLE 1 +#define ZV0_CAPTURE_CTRL_DB 4:4 +#define ZV0_CAPTURE_CTRL_DB_DISABLE 0 +#define ZV0_CAPTURE_CTRL_DB_ENABLE 1 +#define ZV0_CAPTURE_CTRL_CC 3:3 +#define ZV0_CAPTURE_CTRL_CC_CONTINUE 0 +#define ZV0_CAPTURE_CTRL_CC_CONDITION 1 +#define ZV0_CAPTURE_CTRL_RGB 2:2 +#define ZV0_CAPTURE_CTRL_RGB_DISABLE 0 +#define ZV0_CAPTURE_CTRL_RGB_ENABLE 1 +#define ZV0_CAPTURE_CTRL_656 1:1 +#define ZV0_CAPTURE_CTRL_656_DISABLE 0 +#define ZV0_CAPTURE_CTRL_656_ENABLE 1 +#define ZV0_CAPTURE_CTRL_CAP 0:0 +#define ZV0_CAPTURE_CTRL_CAP_DISABLE 0 +#define ZV0_CAPTURE_CTRL_CAP_ENABLE 1 + +#define ZV0_CAPTURE_CLIP 0x090004 +#define ZV0_CAPTURE_CLIP_YCLIP_EVEN_FIELD 25:16 +#define ZV0_CAPTURE_CLIP_YCLIP 25:16 +#define ZV0_CAPTURE_CLIP_XCLIP 9:0 + +#define ZV0_CAPTURE_SIZE 0x090008 +#define ZV0_CAPTURE_SIZE_HEIGHT 26:16 +#define ZV0_CAPTURE_SIZE_WIDTH 10:0 + +#define ZV0_CAPTURE_BUF0_ADDRESS 0x09000C +#define ZV0_CAPTURE_BUF0_ADDRESS_STATUS 31:31 +#define ZV0_CAPTURE_BUF0_ADDRESS_STATUS_CURRENT 0 +#define ZV0_CAPTURE_BUF0_ADDRESS_STATUS_PENDING 1 +#define ZV0_CAPTURE_BUF0_ADDRESS_ADDRESS 29:0 + +#define ZV0_CAPTURE_BUF1_ADDRESS 0x090010 +#define ZV0_CAPTURE_BUF1_ADDRESS_STATUS 31:31 +#define ZV0_CAPTURE_BUF1_ADDRESS_STATUS_CURRENT 0 +#define ZV0_CAPTURE_BUF1_ADDRESS_STATUS_PENDING 1 +#define ZV0_CAPTURE_BUF1_ADDRESS_ADDRESS 29:0 + +#define ZV0_CAPTURE_BUF_OFFSET 0x090014 +#define ZV0_CAPTURE_BUF_OFFSET_YCLIP_ODD_FIELD 25:16 +#define ZV0_CAPTURE_BUF_OFFSET_OFFSET 15:0 + +#define ZV0_CAPTURE_FIFO_CTRL 0x090018 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO 2:0 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO_0 0 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO_1 1 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO_2 2 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO_3 3 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO_4 4 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO_5 5 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO_6 6 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO_7 7 + +#define ZV0_CAPTURE_YRGB_CONST 0x09001C +#define ZV0_CAPTURE_YRGB_CONST_Y 31:24 +#define ZV0_CAPTURE_YRGB_CONST_R 23:16 +#define ZV0_CAPTURE_YRGB_CONST_G 15:8 +#define ZV0_CAPTURE_YRGB_CONST_B 7:0 + +#define ZV0_CAPTURE_LINE_COMP 0x090020 +#define ZV0_CAPTURE_LINE_COMP_LC 10:0 + +/* ZV1 */ + +#define ZV1_CAPTURE_CTRL 0x098000 +#define ZV1_CAPTURE_CTRL_FIELD_INPUT 27:27 +#define ZV1_CAPTURE_CTRL_FIELD_INPUT_EVEN_FIELD 0 +#define ZV1_CAPTURE_CTRL_FIELD_INPUT_ODD_FIELD 0 +#define ZV1_CAPTURE_CTRL_SCAN 26:26 +#define ZV1_CAPTURE_CTRL_SCAN_PROGRESSIVE 0 +#define ZV1_CAPTURE_CTRL_SCAN_INTERLACE 1 +#define ZV1_CAPTURE_CTRL_CURRENT_BUFFER 25:25 +#define ZV1_CAPTURE_CTRL_CURRENT_BUFFER_0 0 +#define ZV1_CAPTURE_CTRL_CURRENT_BUFFER_1 1 +#define ZV1_CAPTURE_CTRL_VERTICAL_SYNC 24:24 +#define ZV1_CAPTURE_CTRL_VERTICAL_SYNC_INACTIVE 0 +#define ZV1_CAPTURE_CTRL_VERTICAL_SYNC_ACTIVE 1 +#define ZV1_CAPTURE_CTRL_CHANNEL0 20:20 +#define ZV1_CAPTURE_CTRL_CHANNEL0_DISABLE 0 +#define ZV1_CAPTURE_CTRL_CHANNEL0_ENABLE 1 +#define ZV1_CAPTURE_CTRL_ADJ 19:19 +#define ZV1_CAPTURE_CTRL_ADJ_NORMAL 0 +#define ZV1_CAPTURE_CTRL_ADJ_DELAY 1 +#define ZV1_CAPTURE_CTRL_HA 18:18 +#define ZV1_CAPTURE_CTRL_HA_DISABLE 0 +#define ZV1_CAPTURE_CTRL_HA_ENABLE 1 +#define ZV1_CAPTURE_CTRL_VSK 17:17 +#define ZV1_CAPTURE_CTRL_VSK_DISABLE 0 +#define ZV1_CAPTURE_CTRL_VSK_ENABLE 1 +#define ZV1_CAPTURE_CTRL_HSK 16:16 +#define ZV1_CAPTURE_CTRL_HSK_DISABLE 0 +#define ZV1_CAPTURE_CTRL_HSK_ENABLE 1 +#define ZV1_CAPTURE_CTRL_FD 15:15 +#define ZV1_CAPTURE_CTRL_FD_RISING 0 +#define ZV1_CAPTURE_CTRL_FD_FALLING 1 +#define ZV1_CAPTURE_CTRL_VP 14:14 +#define ZV1_CAPTURE_CTRL_VP_HIGH 0 +#define ZV1_CAPTURE_CTRL_VP_LOW 1 +#define ZV1_CAPTURE_CTRL_HP 13:13 +#define ZV1_CAPTURE_CTRL_HP_HIGH 0 +#define ZV1_CAPTURE_CTRL_HP_LOW 1 +#define ZV1_CAPTURE_CTRL_CP 12:12 +#define ZV1_CAPTURE_CTRL_CP_HIGH 0 +#define ZV1_CAPTURE_CTRL_CP_LOW 1 +#define ZV1_CAPTURE_CTRL_UVS 11:11 +#define ZV1_CAPTURE_CTRL_UVS_DISABLE 0 +#define ZV1_CAPTURE_CTRL_UVS_ENABLE 1 +#define ZV1_CAPTURE_CTRL_BS 10:10 +#define ZV1_CAPTURE_CTRL_BS_DISABLE 0 +#define ZV1_CAPTURE_CTRL_BS_ENABLE 1 +#define ZV1_CAPTURE_CTRL_CS 9:9 +#define ZV1_CAPTURE_CTRL_CS_16 0 +#define ZV1_CAPTURE_CTRL_CS_8 1 +#define ZV1_CAPTURE_CTRL_CF 8:8 +#define ZV1_CAPTURE_CTRL_CF_YUV 0 +#define ZV1_CAPTURE_CTRL_CF_RGB 1 +#define ZV1_CAPTURE_CTRL_FS 7:7 +#define ZV1_CAPTURE_CTRL_FS_DISABLE 0 +#define ZV1_CAPTURE_CTRL_FS_ENABLE 1 +#define ZV1_CAPTURE_CTRL_WEAVE 6:6 +#define ZV1_CAPTURE_CTRL_WEAVE_DISABLE 0 +#define ZV1_CAPTURE_CTRL_WEAVE_ENABLE 1 +#define ZV1_CAPTURE_CTRL_BOB 5:5 +#define ZV1_CAPTURE_CTRL_BOB_DISABLE 0 +#define ZV1_CAPTURE_CTRL_BOB_ENABLE 1 +#define ZV1_CAPTURE_CTRL_DB 4:4 +#define ZV1_CAPTURE_CTRL_DB_DISABLE 0 +#define ZV1_CAPTURE_CTRL_DB_ENABLE 1 +#define ZV1_CAPTURE_CTRL_CC 3:3 +#define ZV1_CAPTURE_CTRL_CC_CONTINUE 0 +#define ZV1_CAPTURE_CTRL_CC_CONDITION 1 +#define ZV1_CAPTURE_CTRL_RGB 2:2 +#define ZV1_CAPTURE_CTRL_RGB_DISABLE 0 +#define ZV1_CAPTURE_CTRL_RGB_ENABLE 1 +#define ZV1_CAPTURE_CTRL_656 1:1 +#define ZV1_CAPTURE_CTRL_656_DISABLE 0 +#define ZV1_CAPTURE_CTRL_656_ENABLE 1 +#define ZV1_CAPTURE_CTRL_CAP 0:0 +#define ZV1_CAPTURE_CTRL_CAP_DISABLE 0 +#define ZV1_CAPTURE_CTRL_CAP_ENABLE 1 + +#define ZV1_CAPTURE_CLIP 0x098004 +#define ZV1_CAPTURE_CLIP_YCLIP 25:16 +#define ZV1_CAPTURE_CLIP_XCLIP 9:0 + +#define ZV1_CAPTURE_SIZE 0x098008 +#define ZV1_CAPTURE_SIZE_HEIGHT 26:16 +#define ZV1_CAPTURE_SIZE_WIDTH 10:0 + +#define ZV1_CAPTURE_BUF0_ADDRESS 0x09800C +#define ZV1_CAPTURE_BUF0_ADDRESS_STATUS 31:31 +#define ZV1_CAPTURE_BUF0_ADDRESS_STATUS_CURRENT 0 +#define ZV1_CAPTURE_BUF0_ADDRESS_STATUS_PENDING 1 +#define ZV1_CAPTURE_BUF0_ADDRESS_ADDRESS 29:0 + +#define ZV1_CAPTURE_BUF1_ADDRESS 0x098010 +#define ZV1_CAPTURE_BUF1_ADDRESS_STATUS 31:31 +#define ZV1_CAPTURE_BUF1_ADDRESS_STATUS_CURRENT 0 +#define ZV1_CAPTURE_BUF1_ADDRESS_STATUS_PENDING 1 +#define ZV1_CAPTURE_BUF1_ADDRESS_ADDRESS 29:0 + +#define ZV1_CAPTURE_BUF_OFFSET 0x098014 +#define ZV1_CAPTURE_BUF_OFFSET_OFFSET 15:0 + +#define ZV1_CAPTURE_FIFO_CTRL 0x098018 +#define ZV1_CAPTURE_FIFO_CTRL_FIFO 2:0 +#define ZV1_CAPTURE_FIFO_CTRL_FIFO_0 0 +#define ZV1_CAPTURE_FIFO_CTRL_FIFO_1 1 +#define ZV1_CAPTURE_FIFO_CTRL_FIFO_2 2 +#define ZV1_CAPTURE_FIFO_CTRL_FIFO_3 3 +#define ZV1_CAPTURE_FIFO_CTRL_FIFO_4 4 +#define ZV1_CAPTURE_FIFO_CTRL_FIFO_5 5 +#define ZV1_CAPTURE_FIFO_CTRL_FIFO_6 6 +#define ZV1_CAPTURE_FIFO_CTRL_FIFO_7 7 + +#define ZV1_CAPTURE_YRGB_CONST 0x09801C +#define ZV1_CAPTURE_YRGB_CONST_Y 31:24 +#define ZV1_CAPTURE_YRGB_CONST_R 23:16 +#define ZV1_CAPTURE_YRGB_CONST_G 15:8 +#define ZV1_CAPTURE_YRGB_CONST_B 7:0 + + + +//#include "regi2c.h" +#define I2C_BYTE_COUNT 0x010040 +#define I2C_BYTE_COUNT_COUNT 3:0 + +#define I2C_CTRL 0x010041 +#define I2C_CTRL_INT 4:4 +#define I2C_CTRL_INT_DISABLE 0 +#define I2C_CTRL_INT_ENABLE 1 +#define I2C_CTRL_CTRL 2:2 +#define I2C_CTRL_CTRL_STOP 0 +#define I2C_CTRL_CTRL_START 1 +#define I2C_CTRL_MODE 1:1 +#define I2C_CTRL_MODE_STANDARD 0 +#define I2C_CTRL_MODE_FAST 1 +#define I2C_CTRL_EN 0:0 +#define I2C_CTRL_EN_DISABLE 0 +#define I2C_CTRL_EN_ENABLE 1 + +#define I2C_STATUS 0x010042 +#define I2C_STATUS_TX 3:3 +#define I2C_STATUS_TX_PROGRESS 0 +#define I2C_STATUS_TX_COMPLETED 1 +#define I2C_STATUS_ERR 2:2 +#define I2C_STATUS_ERR_NORMAL 0 +#define I2C_STATUS_ERR_ERROR 1 +#define I2C_STATUS_ERR_CLEAR 0 +#define I2C_STATUS_ACK 1:1 +#define I2C_STATUS_ACK_RECEIVED 0 +#define I2C_STATUS_ACK_NOT 1 +#define I2C_STATUS_BSY 0:0 +#define I2C_STATUS_BSY_IDLE 0 +#define I2C_STATUS_BSY_BUSY 1 + +#define I2C_RESET 0x010042 +#define I2C_RESET_BUS_ERROR 2:2 +#define I2C_RESET_BUS_ERROR_CLEAR 0 + +#define I2C_SLAVE_ADDRESS 0x010043 +#define I2C_SLAVE_ADDRESS_ADDRESS 7:1 +#define I2C_SLAVE_ADDRESS_RW 0:0 +#define I2C_SLAVE_ADDRESS_RW_W 0 +#define I2C_SLAVE_ADDRESS_RW_R 1 + +#define I2C_DATA0 0x010044 +#define I2C_DATA1 0x010045 +#define I2C_DATA2 0x010046 +#define I2C_DATA3 0x010047 +#define I2C_DATA4 0x010048 +#define I2C_DATA5 0x010049 +#define I2C_DATA6 0x01004A +#define I2C_DATA7 0x01004B +#define I2C_DATA8 0x01004C +#define I2C_DATA9 0x01004D +#define I2C_DATA10 0x01004E +#define I2C_DATA11 0x01004F +#define I2C_DATA12 0x010050 +#define I2C_DATA13 0x010051 +#define I2C_DATA14 0x010052 +#define I2C_DATA15 0x010053 + +/* MMIO offset between I2C0 and I2C1 */ +#define I2C_OFFSET 0x20 + +//#include "regtimer.h" + +/* There are 4 timers in the system with the same definition, + but different MMIO address as below + + TIMER 0 0x010030 + TIMER 1 0x010034 + TIMER 2 0x010038 + TIMER 3 0x01003C + + We only define the MMIO for timer 0, the MMIO for other + timer can be work out like this: + 0x10030 + (4 x Timer number) + +*/ + +#define TIMER_CONTROL 0x010030 +#define TIMER_CONTROL_COUNTER 31:4 +#define TIMER_CONTROL_RAWINT_STATUS 3:3 +#define TIMER_CONTROL_RAWINT_STATUS_CLEAR 0 +#define TIMER_CONTROL_RAWINT_STATUS_PENDING 1 +#define TIMER_CONTROL_RAWINT_STATUS_RESET 1 +#define TIMER_CONTROL_RAWINT_ENABLE 2:2 +#define TIMER_CONTROL_RAWINT_ENABLE_DISABLE 0 +#define TIMER_CONTROL_RAWINT_ENABLE_ENABLE 1 +#define TIMER_CONTROL_DIV16 1:1 +#define TIMER_CONTROL_DIV16_DISABLE 0 +#define TIMER_CONTROL_DIV16_ENABLE 1 +#define TIMER_CONTROL_ENABLE 0:0 +#define TIMER_CONTROL_ENABLE_DISABLE 0 +#define TIMER_CONTROL_ENABLE_ENABLE 1 + +#define I2S_TX_DATA_L 0x0A0200 +#define I2S_TX_DATA_L_DATA 15:0 + +#define I2S_TX_DATA_R 0x0A0204 +#define I2S_TX_DATA_R_DATA 15:0 + +#define I2S_RX_DATA_L 0x0A0208 +#define I2S_RX_DATA_L_DATA 15:0 + +#define I2S_RX_DATA_R 0x0A020C +#define I2S_RX_DATA_R_DATA 15:0 + +#define I2S_STATUS 0x0A0210 +#define I2S_STATUS_R 11:11 +#define I2S_STATUS_R_NO_ERR 0 +#define I2S_STATUS_R_OVERFLOW 1 +#define I2S_STATUS_T 10:10 +#define I2S_STATUS_T_NO_ERR 0 +#define I2S_STATUS_T_UNDERFLOW 1 +#define I2S_STATUS_TX 2:2 +#define I2S_STATUS_TX_DISABLE 0 +#define I2S_STATUS_TX_ENABLE 1 + +#define I2S_CTRL 0x0A0214 +#define I2S_CTRL_MODE 7:7 +#define I2S_CTRL_MODE_SLAVE 0 +#define I2S_CTRL_MODE_MASTER 1 +#define I2S_CTRL_CS 6:5 +#define I2S_CTRL_CS_16 0 +#define I2S_CTRL_CS_24 1 +#define I2S_CTRL_CS_32 2 +#define I2S_CTRL_CDIV 4:0 + + +#define I2S_SRAM_DMA 0x0A0218 +#define I2S_SRAM_DMA_STATE 31:31 +#define I2S_SRAM_DMA_STATE_DISABLE 0 +#define I2S_SRAM_DMA_STATE_ENABLE 1 +#define I2S_SRAM_DMA_SIZE 23:16 +#define I2S_SRAM_DMA_ADDRESS 8:0 + +#define I2S_SRAM_DMA_STATUS 0x0A021C +#define I2S_SRAM_DMA_STATUS_TC 0:0 +#define I2S_SRAM_DMA_STATUS_TC_COMPLETE 1 +#define I2S_SRAM_DMA_STATUS_TC_CLEAR 0 + + + +#define SRAM_OUTPUT_BASE 0x8000 +#define SRAM_INPUT_BASE 0x8800 +#define SRAM_SIZE 0x0800 + + + +/* Internal macros */ +#define _F_START(f) (0 ? f) +#define _F_END(f) (1 ? f) +#define _F_SIZE(f) (1 + _F_END(f) - _F_START(f)) +#define _F_MASK(f) (((1 << _F_SIZE(f)) - 1) << _F_START(f)) +#define _F_NORMALIZE(v, f) (((v) & _F_MASK(f)) >> _F_START(f)) +#define _F_DENORMALIZE(v, f) (((v) << _F_START(f)) & _F_MASK(f)) + +/* Global macros */ +#define FIELD_GET(x, reg, field) \ +( \ + _F_NORMALIZE((x), reg ## _ ## field) \ +) + +#define FIELD_SET(x, reg, field, value) \ +( \ + (x & ~_F_MASK(reg ## _ ## field)) \ + | _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \ +) + +#define FIELD_VALUE(x, reg, field, value) \ +( \ + (x & ~_F_MASK(reg ## _ ## field)) \ + | _F_DENORMALIZE(value, reg ## _ ## field) \ +) + +#define FIELD_CLEAR(reg, field) \ +( \ + ~ _F_MASK(reg ## _ ## field) \ +) + +/* FIELD MACROS */ +#define FIELD_START(field) (0 ? field) +#define FIELD_END(field) (1 ? field) +#define FIELD_SIZE(field) (1 + FIELD_END(field) - FIELD_START(field)) +#define FIELD_MASK(field) (((1 << (FIELD_SIZE(field)-1)) | ((1 << (FIELD_SIZE(field)-1)) - 1)) << FIELD_START(field)) +#define FIELD_NORMALIZE(reg, field) (((reg) & FIELD_MASK(field)) >> FIELD_START(field)) +#define FIELD_DENORMALIZE(field, value) (((value) << FIELD_START(field)) & FIELD_MASK(field)) +#define FIELD_INIT(reg, field, value) FIELD_DENORMALIZE(reg ## _ ## field, \ + reg ## _ ## field ## _ ## value) +#define FIELD_INIT_VAL(reg, field, value) \ + (FIELD_DENORMALIZE(reg ## _ ## field, value)) +#define FIELD_VAL_SET(x, r, f, v) x = x & ~FIELD_MASK(r ## _ ## f) \ + | FIELD_DENORMALIZE(r ## _ ## f, r ## _ ## f ## _ ## v) + +#define RGB(r, g, b) \ +( \ + (unsigned long) (((r) << 16) | ((g) << 8) | (b)) \ +) + +#define RGB16(r, g, b) \ +( \ + (unsigned short) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | (((b) & 0xF8) >> 3)) \ +) + + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_swi2c.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_swi2c.c new file mode 100644 index 000000000000..bb16370c3d1f --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_swi2c.c @@ -0,0 +1,714 @@ +#include + +#include "ddk768_reg.h" +#include "ddk768_chip.h" +#include "ddk768_power.h" +#include "ddk768_timer.h" +#include "ddk768_swi2c.h" +#include "ddk768_help.h" + + + + +/******************************************************************* + * I2C Software Master Driver: + * =========================== + * Each i2c cycle is split into 4 sections. Each of these section marks + * a point in time where the SCL or SDA may be changed. + * + * 1 Cycle == | Section I. | Section 2. | Section 3. | Section 4. | + * +-------------+-------------+-------------+-------------+ + * | SCL set LOW |SCL no change| SCL set HIGH|SCL no change| + * + * ____________ _____________ + * SCL == XXXX _____________ ____________ / + * + * I.e. the SCL may only be changed in section 1. and section 3. while + * the SDA may only be changed in section 2. and section 4. The table + * below gives the changes for these 2 lines in the varios sections. + * + * Section changes Table: + * ====================== + * blank = no change, L = set bit LOW, H = set bit HIGH + * + * | 1.| 2.| 3.| 4.| + * ---------------+---+---+---+---+ + * Tx Start SDA | | H | | L | + * SCL | L | | H | | + * ---------------+---+---+---+---+ + * Tx Stop SDA | | L | | H | + * SCL | L | | H | | + * ---------------+---+---+---+---+ + * Tx bit H SDA | | H | | | + * SCL | L | | H | | + * ---------------+---+---+---+---+ + * Tx bit L SDA | | L | | | + * SCL | L | | H | | + * ---------------+---+---+---+---+ + * + ******************************************************************/ + +/* GPIO pins used for this I2C. It ranges from 0 to 31. */ +unsigned char g_i2cClockGPIO = DEFAULT_I2C0_SCL; +unsigned char g_i2cDataGPIO = DEFAULT_I2C0_SDA; + +/* + * Below is the variable declaration for the GPIO pin register usage + * for the i2c Clock and i2c Data. + * + * Note: + * Notice that the GPIO usage for the i2c clock and i2c Data are + * separated. This is to make this code flexible enough when + * two separate GPIO pins for the clock and data are located + * in two different GPIO register set (worst case). + */ + +/* i2c Clock GPIO Register usage */ +static unsigned long g_i2cClkGPIOMuxReg = GPIO_MUX; +static unsigned long g_i2cClkGPIODataReg = GPIO_DATA; +static unsigned long g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION; + +/* i2c Data GPIO Register usage */ +static unsigned long g_i2cDataGPIOMuxReg = GPIO_MUX; +static unsigned long g_i2cDataGPIODataReg = GPIO_DATA; +static unsigned long g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION; + +/* + * This function puts a delay between command + */ +static void swI2CWait(void) +{ + //SM768 has build-in timer. Use it instead of SW loop. + timerWaitTicks(3, 0x3ff); +} + +/* + * This function set/reset the SCL GPIO pin + * + * Parameters: + * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) + * + * Notes: + * When setting SCL to high, just set the GPIO as input where the pull up + * resistor will pull the signal up. Do not use software to pull up the + * signal because the i2c will fail when other device try to drive the + * signal due to SM50x will drive the signal to always high. + */ +static void swI2CSCL(unsigned char value, unsigned char i2cClockGPIO) +{ + unsigned long ulGPIOData; + unsigned long ulGPIODirection; + + ulGPIODirection = peekRegisterDWord(g_i2cClkGPIODataDirReg); + if (value) /* High */ + { + /* Set direction as input. This will automatically pull the signal up. */ + ulGPIODirection &= ~(1 << i2cClockGPIO); + pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection); + } + else /* Low */ + { + /* Set the signal down */ + ulGPIOData = peekRegisterDWord(g_i2cClkGPIODataReg); + ulGPIOData &= ~(1 << i2cClockGPIO); + pokeRegisterDWord(g_i2cClkGPIODataReg, ulGPIOData); + + /* Set direction as output */ + ulGPIODirection |= (1 << i2cClockGPIO); + pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection); + } +} + +/* + * This function read the data from the SDA GPIO pin + * + * Return Value: + * The SDA data bit sent by the Slave + */ +static unsigned char swI2CReadSCL(unsigned char i2cClockGPIO) +{ + unsigned long ulGPIODirection; + unsigned long ulGPIOData; + + /* Make sure that the direction is input (High) */ + ulGPIODirection = peekRegisterDWord(g_i2cClkGPIODataDirReg); + if ((ulGPIODirection & (1 << i2cClockGPIO)) != (~(1 << i2cClockGPIO))) + { + ulGPIODirection &= ~(1 << i2cClockGPIO); + pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection); + } + + /* Now read the SCL line */ + ulGPIOData = peekRegisterDWord(g_i2cClkGPIODataReg); + if (ulGPIOData & (1 << i2cClockGPIO)) + return 1; + else + return 0; +} + +static void swI2CSDA(unsigned char value, unsigned char i2cDataGPIO) +{ + unsigned long ulGPIOData; + unsigned long ulGPIODirection; + + ulGPIODirection = peekRegisterDWord(g_i2cDataGPIODataDirReg); + if (value) /* High */ + { + /* Set direction as input. This will automatically pull the signal up. */ + ulGPIODirection &= ~(1 << i2cDataGPIO); + pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection); + } + else /* Low */ + { + /* Set the signal down */ + ulGPIOData = peekRegisterDWord(g_i2cDataGPIODataReg); + ulGPIOData &= ~(1 << i2cDataGPIO); + pokeRegisterDWord(g_i2cDataGPIODataReg, ulGPIOData); + + /* Set direction as output */ + ulGPIODirection |= (1 << i2cDataGPIO); + pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection); + } +} + +/* + * This function read the data from the SDA GPIO pin + * + * Return Value: + * The SDA data bit sent by the Slave + */ +static unsigned char swI2CReadSDA(unsigned char i2cDataGPIO) +{ + unsigned long ulGPIODirection; + unsigned long ulGPIOData; + + /* Make sure that the direction is input (High) */ + ulGPIODirection = peekRegisterDWord(g_i2cDataGPIODataDirReg); + if ((ulGPIODirection & (1 << i2cDataGPIO)) != (~(1 << i2cDataGPIO))) + { + ulGPIODirection &= ~(1 << i2cDataGPIO); + pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection); + } + + /* Now read the SDA line */ + ulGPIOData = peekRegisterDWord(g_i2cDataGPIODataReg); + if (ulGPIOData & (1 << i2cDataGPIO)) + return 1; + else + return 0; +} + +/* + * This function set/reset the SDA GPIO pin + * + * Parameters: + * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) + * + * Notes: + * When setting SCL to high, just set the GPIO as input where the pull up + * resistor will pull the signal up. Do not use software to pull up the + * signal because the i2c will fail when other device try to drive the + * signal due to SM50x will drive the signal to always high. + */ +static void ddk768_swI2CSDA(unsigned char value) +{ + unsigned long ulGPIOData; + unsigned long ulGPIODirection; + + ulGPIODirection = peekRegisterDWord(g_i2cDataGPIODataDirReg); + if (value) /* High */ + { + /* Set direction as input. This will automatically pull the signal up. */ + ulGPIODirection &= ~(1 << g_i2cDataGPIO); + pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection); + } + else /* Low */ + { + /* Set the signal down */ + ulGPIOData = peekRegisterDWord(g_i2cDataGPIODataReg); + ulGPIOData &= ~(1 << g_i2cDataGPIO); + pokeRegisterDWord(g_i2cDataGPIODataReg, ulGPIOData); + + /* Set direction as output */ + ulGPIODirection |= (1 << g_i2cDataGPIO); + pokeRegisterDWord(g_i2cDataGPIODataDirReg, ulGPIODirection); + } +} + + +/* + * This function set/reset the SCL GPIO pin + * + * Parameters: + * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) + * + * Notes: + * When setting SCL to high, just set the GPIO as input where the pull up + * resistor will pull the signal up. Do not use software to pull up the + * signal because the i2c will fail when other device try to drive the + * signal due to SM50x will drive the signal to always high. + */ +static void ddk768_swI2CSCL(unsigned char value) +{ + unsigned long ulGPIOData; + unsigned long ulGPIODirection; + + ulGPIODirection = peekRegisterDWord(g_i2cClkGPIODataDirReg); + if (value) /* High */ + { + /* Set direction as input. This will automatically pull the signal up. */ + ulGPIODirection &= ~(1 << g_i2cClockGPIO); + pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection); + } + else /* Low */ + { + /* Set the signal down */ + ulGPIOData = peekRegisterDWord(g_i2cClkGPIODataReg); + ulGPIOData &= ~(1 << g_i2cClockGPIO); + pokeRegisterDWord(g_i2cClkGPIODataReg, ulGPIOData); + + /* Set direction as output */ + ulGPIODirection |= (1 << g_i2cClockGPIO); + pokeRegisterDWord(g_i2cClkGPIODataDirReg, ulGPIODirection); + } +} +#pragma GCC push_options +#pragma GCC optimize("O0") +/* + * This function sends ACK signal + */ +static void swI2CAck(unsigned char ack) +{ + if(ack) + { + ddk768_swI2CSCL(0); + ddk768_swI2CSDA(0); + swI2CWait(); + ddk768_swI2CSCL(1); + swI2CWait(); + ddk768_swI2CSCL(0); + ddk768_swI2CSDA(0); + swI2CWait(); + } + else + { + ddk768_swI2CSCL(0); + ddk768_swI2CSDA(1); + swI2CWait(); + ddk768_swI2CSCL(1); + swI2CWait(); + ddk768_swI2CSCL(0); + ddk768_swI2CSDA(0); + swI2CWait(); + } + + return; /* Single byte read is ok without it. */ +} + + +/* + * This function sends the start command to the slave device + */ +static void ddk768_swI2CStart(void) +{ + /* Start I2C */ + swI2CSDA(1, g_i2cDataGPIO); + swI2CSCL(1, g_i2cClockGPIO); + swI2CSDA(0, g_i2cDataGPIO); +} + +/* + * This function sends the stop command to the slave device + */ +static void ddk768_swI2CStop(void) +{ + /* Stop the I2C */ + swI2CSCL(1, g_i2cClockGPIO); + swI2CSDA(0, g_i2cDataGPIO); + swI2CSDA(1, g_i2cDataGPIO); +} + +__attribute__((unused)) static void ddk768_swI2CClean(void) +{ + swI2CSCL(0, g_i2cClockGPIO); + swI2CWait(); + swI2CSCL(1, g_i2cClockGPIO); + swI2CWait(); +} + +/* + * This function writes one byte to the slave device + * + * Parameters: + * data - Data to be write to the slave device + * + * Return Value: + * 0 - Success + * -1 - Fail to write byte + */ +static long ddk768_swI2CWriteByte(unsigned char data) +{ + unsigned char value = data; + int i; + + /* Sending the data bit by bit */ + for (i=0; i<8; i++) + { + /* Set SCL to low */ + swI2CSCL(0, g_i2cClockGPIO); + + /* Send data bit */ + if ((value & 0x80) != 0) + swI2CSDA(1, g_i2cDataGPIO); + else + swI2CSDA(0, g_i2cDataGPIO); + + swI2CWait(); + + /* Toggle clk line to one */ + swI2CSCL(1, g_i2cClockGPIO); + + + /* Shift byte to be sent */ + value = value << 1; + } + + /* Set the SCL Low and SDA High (prepare to get input) */ + swI2CSCL(0, g_i2cClockGPIO); + swI2CSDA(1, g_i2cDataGPIO); + + /* Set the SCL High for ack */ + swI2CWait(); + swI2CSCL(1, g_i2cClockGPIO); + + + /* Read SDA, until SDA==0 */ + for(i=0; i<0xf; i++) + { + if (!swI2CReadSDA(g_i2cDataGPIO)) + break; + + + swI2CWait(); + + swI2CWait(); + } + + /* Set the SCL Low and SDA High */ + swI2CSCL(0, g_i2cClockGPIO); + swI2CSDA(1, g_i2cDataGPIO); + + if (i<0xf) + return 0; + else + return (-1); +} + +#pragma GCC pop_options + +static long ddk768_swI2CSetGPIO( + unsigned char i2cClkGPIO, + unsigned char i2cDataGPIO) +{ + /* Return 0 if the GPIO pins to be used is out of range. The range is only from [0..63] */ + if ((i2cClkGPIO > 31) || (i2cDataGPIO > 31)) + return (-1); + + /* Initialize the GPIO pin for the i2c Clock Register */ + g_i2cClkGPIOMuxReg = GPIO_MUX; + g_i2cClkGPIODataReg = GPIO_DATA; + g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION; + + + + /* Initialize the GPIO pin for the i2c Data Register */ + g_i2cDataGPIOMuxReg = GPIO_MUX; + g_i2cDataGPIODataReg = GPIO_DATA; + g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION; + + + + /* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */ + pokeRegisterDWord(g_i2cClkGPIOMuxReg, + peekRegisterDWord(g_i2cClkGPIOMuxReg) & ~(1 << i2cClkGPIO)); + pokeRegisterDWord(g_i2cDataGPIOMuxReg, + peekRegisterDWord(g_i2cDataGPIOMuxReg) & ~(1 << i2cDataGPIO)); + + /* Enable GPIO power */ + //enableGPIO(1); + + return 0; +} + +/* + * This function initializes the i2c attributes and bus + * + * Parameters: + * i2cClkGPIO - The GPIO pin to be used as i2c SCL + * i2cDataGPIO - The GPIO pin to be used as i2c SDA + * + * Return Value: + * -1 - Fail to initialize the i2c + * 0 - Success + */ +long ddk768_swI2CInit(unsigned char i2cClkGPIO, unsigned char i2cDataGPIO) +{ + + /* GPIO pins used for this I2C. It ranges from 0 to 31. */ + g_i2cClockGPIO = i2cClkGPIO; + g_i2cDataGPIO = i2cDataGPIO; + + if (ddk768_swI2CSetGPIO(i2cClkGPIO, i2cDataGPIO)) + return (-1); + +#if 0 + /* Clear the i2c lines. */ + { + int i = 0; + for (i = 0; i < 9; i++) + ddk768_swI2CStop(); + } +#endif + return 0; +} + +static void smi_ddc_setsda(void *data, int state) +{ + struct smi_connector *connector = data; + swI2CSDA(state, connector->i2c_sda); + /* smi_set_i2c_signal(data, I2C_SDA_MASK, state); */ +} + +static void smi_ddc_setscl(void *data, int state) +{ + struct smi_connector *connector = data; + swI2CSCL(state, connector->i2c_scl); + /* smi_set_i2c_signal(data, I2C_SCL_MASK, state); */ +} + +static int smi_ddc_getsda(void *data) +{ + + struct smi_connector *connector = data; + return (int)swI2CReadSDA(connector->i2c_sda); + /* return smi_get_i2c_signal(data, I2C_SDA_MASK); */ +} + +static int smi_ddc_getscl(void *data) +{ + struct smi_connector *connector = data; + return (int)swI2CReadSCL(connector->i2c_scl); + /* return smi_get_i2c_signal(data, I2C_SCL_MASK); */ +} + +static int smi_ddc_create(struct smi_connector *connector) +{ + connector->adapter.owner = THIS_MODULE; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 8, 0) + connector->adapter.class = I2C_CLASS_DDC; +#endif + snprintf(connector->adapter.name, I2C_NAME_SIZE, "SMI SW I2C Bit Bus"); + connector->adapter.dev.parent = connector->base.dev->dev; + i2c_set_adapdata(&connector->adapter, connector); + connector->adapter.algo_data = &connector->bit_data; + + connector->bit_data.udelay = 2; /* 0x3ff ticks, 168MHZ */ + connector->bit_data.timeout = usecs_to_jiffies(2200); + connector->bit_data.data = connector; + connector->bit_data.setsda = smi_ddc_setsda; + connector->bit_data.setscl = smi_ddc_setscl; + connector->bit_data.getsda = smi_ddc_getsda; + connector->bit_data.getscl = smi_ddc_getscl; + + if (i2c_bit_add_bus(&connector->adapter)) + { + return -1; + } + + return 0; +} + + +long ddk768_AdaptSWI2CInit(struct smi_connector *smi_connector) +{ + struct drm_connector *connector = &smi_connector->base; + unsigned char i2cClkGPIO; + unsigned char i2cDataGPIO; + + if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) + { + i2cClkGPIO = 30; + i2cDataGPIO = 31; + } + else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA) + { + i2cClkGPIO = 6; + i2cDataGPIO = 7; + } + else if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA) + { + i2cClkGPIO = 8; + i2cDataGPIO = 9; + } + else + { + return -1; + } + + smi_connector->i2c_scl = i2cClkGPIO; + smi_connector->i2c_sda = i2cDataGPIO; + + if (ddk768_swI2CSetGPIO(i2cClkGPIO, i2cDataGPIO)) + { + return (-1); + } + +#if 0 + /* Clear the i2c lines. */ + { + int i = 0; + for (i = 0; i < 9; i++) + ddk768_swI2CStop(); + } +#endif + + udelay(20); + + if (smi_ddc_create(smi_connector)) + { + return -1; + } + + return 0; +} + + +/* After closing HW I2C, give a SCL clk by SW to avoid the deadlock */ +long ddk768_AdaptSWI2CCleanBus( + struct smi_connector *connector) +{ + unsigned char i2cClkGPIO = connector->i2c_scl; + unsigned char i2cDataGPIO = connector->i2c_sda; + + if (ddk768_swI2CSetGPIO(i2cClkGPIO, i2cDataGPIO)) + return (-1); + + udelay(20); + swI2CSCL(0, i2cClkGPIO); + udelay(20); + swI2CSCL(1, i2cClkGPIO); + udelay(20); +// ddk768_swI2CClean(); + + return 0; +} + + + +/* + * This function writes a value to the slave device's register + * (here the g_i2cClockGPIO and g_i2cDataGPIO must have been initilized) + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be written + * registerIndex - Slave device's register to be written + * data - Data to be written to the register + * + * Result: + * 0 - Success + * -1 - Fail + */ +long ddk768_swI2CWriteReg( + unsigned char deviceAddress, + unsigned char registerIndex, + unsigned char data) +{ + long returnValue = 0; + + /* Send the Start signal */ + ddk768_swI2CStart(); + + /* Send the device address and read the data. All should return success + in order for the writing processed to be successful + */ + if ((ddk768_swI2CWriteByte(deviceAddress) != 0) || + (ddk768_swI2CWriteByte(registerIndex) != 0) || + (ddk768_swI2CWriteByte(data) != 0)) + { + returnValue = -1; + } + + /* Stop i2c and release the bus */ + ddk768_swI2CStop(); + + return returnValue; +} + + +static unsigned char ddk768_swI2CReadByte(unsigned char ack) +{ + int i; + unsigned char data = 0; + + for(i=7; i>=0; i--) + { + /* Set the SCL to Low and SDA to High (Input) */ + ddk768_swI2CSCL(0); + ddk768_swI2CSDA(1); + swI2CWait(); + + /* Set the SCL High */ + ddk768_swI2CSCL(1); + swI2CWait(); + + /* Read data bits from SDA */ + data |= (swI2CReadSDA(g_i2cDataGPIO) << i); + } + + swI2CAck(ack); + + + return data; +} + +/* + * This function reads the slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be read from + * registerIndex - Slave device's register to be read + * + * Return Value: + * Register value + */ + + +unsigned char ddk768_swI2CReadReg( + unsigned char deviceAddress, + unsigned char registerIndex +) +{ + unsigned char data; + + /* Send the Start signal */ + ddk768_swI2CStart(); + + /* Send the device address */ + ddk768_swI2CWriteByte(deviceAddress); + + /* Send the register index */ + ddk768_swI2CWriteByte(registerIndex); + + /* Get the bus again and get the data from the device read address */ + ddk768_swI2CStart(); + ddk768_swI2CWriteByte(deviceAddress + 1); + + data = ddk768_swI2CReadByte(0); + + /* Stop swI2C and release the bus */ + ddk768_swI2CStop(); + + return data; +} + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_swi2c.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_swi2c.h new file mode 100644 index 000000000000..f2743c753134 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_swi2c.h @@ -0,0 +1,62 @@ + +#ifndef _DDK768_SWI2C_H_ +#define _DDK768_SWI2C_H_ + +#include "../smi_drv.h" + +/* Default i2c CLK and Data GPIO. These are the default i2c pins */ +#define DEFAULT_I2C0_SCL 30 +#define DEFAULT_I2C0_SDA 31 + +#define DEFAULT_I2C1_SCL 6 +#define DEFAULT_I2C1_SDA 7 + +/* + * This function initializes the i2c attributes and bus + * + * Parameters: + * i2cClkGPIO - The GPIO pin to be used as i2c SCL + * i2cDataGPIO - The GPIO pin to be used as i2c SDA + * + * Return Value: + * -1 - Fail to initialize the i2c + * 0 - Success + */ +long ddk768_swI2CInit( + unsigned char i2cClkGPIO, + unsigned char i2cDataGPIO +); + +/* + * This function writes a value to the slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be written + * registerIndex - Slave device's register to be written + * data - Data to be written to the register + * + * Result: + * 0 - Success + * -1 - Fail + */ +long ddk768_swI2CWriteReg( + unsigned char deviceAddress, + unsigned char registerIndex, + unsigned char data +); + +unsigned char ddk768_swI2CReadReg( + unsigned char deviceAddress, + unsigned char registerIndex +); + + +long ddk768_AdaptSWI2CInit(struct smi_connector *smi_connector); + +long ddk768_AdaptSWI2CCleanBus( + struct smi_connector *connector); + + + +#endif /* _SWI2C_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_timer.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_timer.c new file mode 100644 index 000000000000..63d83f5fae51 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_timer.c @@ -0,0 +1,343 @@ +/******************************************************************* +* +* Copyright (c) 2014 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* This file contains the definitions for the timer functions. +* +*******************************************************************/ +#include "ddk768_reg.h" +#include "ddk768_helper.h" +#include "ddk768_intr.h" +#include "ddk768_timer.h" +#include "ddk768_help.h" + +/* + * A global varible to store the counter values set in the timer. + * It is needed because the counter value cannot be read back from the timer. + * A read to the timer counter only gets the latest value being decremented. + */ +static unsigned long gTimerCounter[4] = {0, 0, 0, 0}; + +/* + * Calculate a value for timer counter according to input time in micro-second. + * Calculation is based on 168MHz master clock, and the counter decrements at every 16 ticks. + */ +unsigned long calcTimerCounter( + unsigned long microSeconds +) +{ + return( microSeconds * 168 / 16); +} + +/* + * This function start the timer with raw interrupt enabled. + * When the timer decrements to 0, timer raw interrupt will be generated. + * + * Raw interrupt of the timers can be used in one of 2 ways: + * 1. In pulling mode, detection of raw interrupt pending means timer is decremented to 0. + * 2. In interrupt mode, unlock the timer interrupt mask will generate a interrput to system. + * + */ +void timerStart( + timer_number_t timer, /* which timer: 0 to 3 */ + unsigned long timerCounter, /* Timer counter */ + unsigned long div16Enable /* Enable the 16 divisor, time out will be increased by 16 */ +) +{ + unsigned long ulTimerAddr, ulTimerValue; + + if (timerCounter == 0) return; /* Nothing to set */ + + /* Work out the timer's MMIO address + Timer 0 address + ( timer number x 4 ) + */ + ulTimerAddr = TIMER_CONTROL + (timer << 2); + + ulTimerValue = + FIELD_VALUE(0, TIMER_CONTROL, COUNTER, timerCounter) + | FIELD_SET(0, TIMER_CONTROL, RAWINT_STATUS, RESET) /* Reset the raw interrupt */ + | FIELD_SET(0, TIMER_CONTROL, RAWINT_ENABLE, ENABLE) /* Enable raw interrupt to happen when time out */ + | FIELD_VALUE(0, TIMER_CONTROL, DIV16, div16Enable) + | FIELD_SET(0, TIMER_CONTROL, ENABLE, ENABLE); /* Start the timer */ + + pokeRegisterDWord(ulTimerAddr, ulTimerValue); + + gTimerCounter[timer] = timerCounter; +} + +/* + * This function checks if a timer's raw interrupt has been pending. + * When raw interrupt is detected with pending status, it indicate the + * countdown of timerStart() has been completed. + * + * Return: + * 1 = Raw interrupt status is pending. + * 0 = Raw int is NOT pending. + */ +unsigned long timerRawIntPending( + timer_number_t timer /* which timer: 0 to 3 */ +) +{ + unsigned long ulTimerAddr, rawIntStatus; + + /* Work out the timer's MMIO address + Timer 0 address + ( timer number x 4 ) + */ + ulTimerAddr = TIMER_CONTROL + (timer << 2); + rawIntStatus = FIELD_GET(peekRegisterDWord(ulTimerAddr), TIMER_CONTROL, RAWINT_STATUS); + + return(rawIntStatus); +} + +/* + * This function clears the RAW interrupt status of the timer. + * + * When a timer completes countdown, the raw interrupt bit will be set. + * It has to be cleared, in order to distinguish between different sessions of countdown. + * + */ +void timerClearRawInt( + timer_number_t timer /* which timer: 0 to 3 */ +) +{ + unsigned long ulTimerAddr, ulTimerValue; + + /* Work out the timer's MMIO address + Timer 0 address + ( timer number x 4 ) + */ + ulTimerAddr = TIMER_CONTROL + (timer << 2); + ulTimerValue = peekRegisterDWord(ulTimerAddr) + & FIELD_CLEAR(TIMER_CONTROL, COUNTER); /* We don't want the current counter value */ + + pokeRegisterDWord(ulTimerAddr, + ulTimerValue + | FIELD_VALUE(0, TIMER_CONTROL, COUNTER, gTimerCounter[timer]) /* When clearing raw int, we don't want to erase the original counter value */ + | FIELD_SET(0, TIMER_CONTROL, RAWINT_STATUS, RESET)); /* Reset the raw interrupt */ +} + +/* + * This function stop the timer. + * + */ +void timerStop( + timer_number_t timer /* which timer: 0 to 3 */ +) +{ + unsigned long ulTimerAddr, ulTimerValue; + + /* Work out the timer's MMIO address + Timer 0 address + ( timer number x 4 ) + */ + ulTimerAddr = TIMER_CONTROL + (timer << 2); + + ulTimerValue = + FIELD_SET(0, TIMER_CONTROL, RAWINT_STATUS, RESET) /* Reset the raw interrupt */ + | FIELD_SET(0, TIMER_CONTROL, ENABLE, DISABLE); /* Stop the timer */ + + pokeRegisterDWord(ulTimerAddr, ulTimerValue); + + gTimerCounter[timer] = 0; +} + +/* + * This function read the current value in the timer counter. + * + * Note: When timer is disable, always read back 0. + */ +unsigned long timerGetCounter( + timer_number_t timer /* which timer: 0 to 3 */ +) +{ + unsigned long ulTimerAddr, ulCounter; + + /* Work out the timer's MMIO address + Timer 0 address + ( timer number x 4 ) + */ + ulTimerAddr = TIMER_CONTROL + (timer << 2); + ulCounter = FIELD_GET(peekRegisterDWord(ulTimerAddr), TIMER_CONTROL, COUNTER); + + return(ulCounter); +} + +/* + * This function gets the countdown setting stored in timer. + * Function timerGetCounter() can only get the current counter value. + * It cannot get the original countdown setting of timer. + * + * Note: When timer is disable, always read back 0. + */ +unsigned long timerGetCounterSetting( + timer_number_t timer /* which timer: 0 to 3 */ +) +{ + /* The counter value put in timer cannot be read back from the register. + It has to keep in global variable. + */ + return(gTimerCounter[timer]); +} + +/* + * This funciton uses the timer to wait a specific amount of time + * in micro-second. + */ +void timerWait( + timer_number_t timer, + unsigned long microSeconds +) +{ + unsigned long ticks; + unsigned long retry = 1000; + + // Limit max delay to 10 seconds + if (microSeconds > 10000000) + microSeconds = 10000000; + + ticks = calcTimerCounter(microSeconds); + + //Tick count is based on enabling DIV 16. + //Third parameter to timerStart is 1. + timerStart(timer, ticks, 1); + + while (!timerRawIntPending(timer) && --retry); + + timerStop(timer); +} + +/* + * This funciton uses the timer to wait a specific ticks of master clock + * + */ +void timerWaitTicks( + timer_number_t timer, /* Use timer 0, 1, 2 or 3 */ + unsigned long ticks +) +{ + unsigned long retry = 1000; + //Counter is 28 bits only. + ticks &= 0xFFFFFFF; + + timerStart(timer, ticks, 0); + + while (!timerRawIntPending(timer) && --retry); + + timerStop(timer); +} + +/* + * This function returns the INT mask for a specific timer. + * + */ +unsigned long timerIntMask( + timer_number_t timer /* Which timer: 0 to 3 */ +) +{ + unsigned long mask; + + mask = 0; + switch (timer) + { + case 0: + mask |= FIELD_SET(0, INT_MASK, TIMER0, ENABLE); + break; + case 1: + mask |= FIELD_SET(0, INT_MASK, TIMER1, ENABLE); + break; + case 2: + mask |= FIELD_SET(0, INT_MASK, TIMER2, ENABLE); + break; + case 3: + mask |= FIELD_SET(0, INT_MASK, TIMER3, ENABLE); + break; + default: + break; + } + + return mask; +} + +/* + * This is a reference sample showing how to implement ISR for timers. + * It works together with libsrc\intr.c module. + * + * Refer to Apps\timer\tstimer.c on how to hook up this function with system + * interrupt under WATCOM DOS extender. + * + */ +void timerIsrTemplate(unsigned long status) +{ + if (FIELD_GET(status, INT_STATUS, TIMER0) == INT_STATUS_TIMER0_ACTIVE) + { + /* Perform ISR action for timer 0 here */ + incTestCounter(); + + timerClearRawInt(0); + } + + if (FIELD_GET(status, INT_STATUS, TIMER1) == INT_STATUS_TIMER1_ACTIVE) + { + /* Perform ISR action for timer 1 here */ + incTestCounter(); + + timerClearRawInt(1); + } + + if (FIELD_GET(status, INT_STATUS, TIMER2) == INT_STATUS_TIMER2_ACTIVE) + { + /* Perform ISR action for timer 2 here */ + incTestCounter(); + + timerClearRawInt(2); + } + + if (FIELD_GET(status, INT_STATUS, TIMER3) == INT_STATUS_TIMER3_ACTIVE) + { + /* Perform ISR action for timer 3 here */ + incTestCounter(); + + timerClearRawInt(3); + } +} + + +void timerWaitMsec( + unsigned long milliSeconds +) +{ + timer_number_t timer = TIMER3; + unsigned long ticks; + + /* Calculate how many ticks are needed for the amount of time. */ + ticks = 168000 * milliSeconds; + + timerStart(timer, ticks, 0); + + while (!timerRawIntPending(timer)); + + timerStop(timer); +} + +void timerWaitUsec( + unsigned long USeconds +) +{ + timer_number_t timer = TIMER3; + unsigned long ticks; + + /* Calculate how many ticks are needed for the amount of time. */ + ticks = 168 * USeconds; + + timerStart(timer, ticks, 0); + + while (!timerRawIntPending(timer)); + + timerStop(timer); +} + + + + + + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_timer.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_timer.h new file mode 100644 index 000000000000..f2f0420960cd --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_timer.h @@ -0,0 +1,150 @@ +/******************************************************************* +* +* Copyright (c) 2014 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* This file contains the definitions for the timer functions. +* +*******************************************************************/ +#ifndef _TIMER_H_ +#define _TIMER_H_ + + + +typedef enum _timer_number_t +{ + TIMER0 = 0, + TIMER1 = 1, + TIMER2 = 2, + TIMER3 = 3, +} +timer_number_t; + +/* + * Calculate a value for timer counter according to input time in micro-second. + * Calculation is based on 168MHz master clock, and the counter decrements at every 16 ticks. + */ +unsigned long calcTimerCounter( + unsigned long microSeconds +); + +/* + * This function start the timer with raw interrupt enabled. + * When the timer decrements to 0, timer raw interrupt will be generated. + * + * Raw interrupt of the timers can be used in one of 2 ways: + * 1. In pulling mode, detection of raw interrupt pending means timer is decremented to 0. + * 2. In interrupt mode, unlock the timer interrupt mask will generate a interrput to system. + * + */ +void timerStart( + timer_number_t timer, /* which timer: 0 to 3 */ + unsigned long timerCounter, /* Timer counter: use calcTimerCounter() to work out a counter for a specific period. */ + unsigned long div16Enable /* Enable the 16 divisor, time out will be increased by 16 */ +); + +/* + * This function checks if a timer's raw interrupt has been pending. + * When raw interrupt is detected with pending status, it indicate the + * countdown of timerStart() has been completed. + * + * Return: + * 1 = Raw interrupt status is pending. + * 0 = Raw int is NOT pending. + */ +unsigned long timerRawIntPending( + timer_number_t timer /* which timer: 0 to 3 */ +); + +/* + * This function clears the RAW interrupt status of the timer. + * + * When a timer completes countdown, the raw interrupt bit will be set. + * It has to be cleared, in order to distinguish between different sessions of countdown. + * + */ +void timerClearRawInt( + timer_number_t timer /* which timer: 0 to 3 */ +); + +/* + * This function stop the timer. + * + */ +void timerStop( + timer_number_t timer /* which timer: 0 to 3 */ +); + +/* + * This function read the current value in the timer counter. + * + * Note: When timer is disable, always read back 0. + */ +unsigned long timerGetCounter( + timer_number_t timer /* which timer: 0 to 3 */ +); + +/* + * This function gets the countdown setting stored in timer. + * Function timerGetCounter() can only get the current counter value. + * It cannot get the original countdown setting of timer. + * + * Note: When timer is disable, always read back 0. + */ +unsigned long timerGetCounterSetting( + timer_number_t timer /* which timer: 0 to 3 */ +); + +/* + * This funciton uses the timer to wait a specific amount of time + * in micro-second. + */ +void timerWait( + timer_number_t timer, + unsigned long microSeconds +); + +/* + * This funciton uses the timer to wait a specific ticks of master clock + * + */ +void timerWaitTicks( + timer_number_t timer, /* Use timer 0, 1, 2 or 3 */ + unsigned long ticks +); + +/* + * This function returns the INT mask for a specific timer. + * + */ +unsigned long timerIntMask( + timer_number_t timer /* Which timer: 0 to 3 */ +); + +unsigned long getTestCounter(void); + +void setTestCounter(unsigned long value); + +/* + * This is a reference sample showing how to implement ISR for timers. + * It works together with libsrc\intr.c module. + * + * Refer to Apps\timer\tstimer.c on how to hook up this function with system + * interrupt under WATCOM DOS extender. + * + */ +void timerIsrTemplate(unsigned long status); + +void timerWaitMsec( + unsigned long milliSeconds +); + +void timerWaitUsec( + unsigned long USeconds +); +#define sb_OS_WAIT_MSEC_POLL(ms) timerWaitMsec(ms) +#define sb_OS_WAIT_USEC_POLL(us) timerWaitUsec(us) +#endif /* _TIMER_H_ */ + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_video.c b/drivers/gpu/drm/smidrm/ddk768/ddk768_video.c new file mode 100644 index 000000000000..4de5af27cb48 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_video.c @@ -0,0 +1,1153 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* Video.C --- Falcon SDK +* This file contains the definitions for the Video functions. +* +*******************************************************************/ +#include "ddk768_help.h" +#include "ddk768_chip.h" +#include "ddk768_mode.h" +#include "ddk768_video.h" +#include "ddk768_reg.h" + + +/* New video function */ + +#define SCALE_CONSTANT (1 << 12) + +/* Offset Adjustment for the window */ +static short gWidthAdjustment = 0; +static short gHeightAdjustment = 0; + +/* Source Video Width and Height */ +static unsigned long gSrcVideoWidth = 0; +static unsigned long gSrcVideoHeight = 0; + +/* + * videoSetWindowAdjustment + * This function sets the video window adjustment. There are usually + * some garbage lines or pixels at the bottom and right of the video + * window. These function will adjust the video window accordingly. + * + * Input: + * widthAdjustment - Width adjustments in pixel + * heightAdjustment - Height adjustment in line + */ +void videoSetWindowAdjustment( + unsigned dispCtrl, + short widthAdjustment, + short heightAdjustment +) +{ + unsigned long width, height; + videoGetWindowSize(dispCtrl, &width, &height); + + gWidthAdjustment = widthAdjustment; + gHeightAdjustment = heightAdjustment; + + videoSetWindowSize(dispCtrl, width, height); +} + +/* + * videoGetWindowAdjustment + * This function gets the video window adjustment. + * + * Input: + * widthAdjustment - Width adjustments in pixel + * heightAdjustment - Height adjustment in line + */ +void videoGetWindowAdjustment( + short *pWidthAdjustment, + short *pHeightAdjustment +) +{ + if (pWidthAdjustment != ((short *)0)) + *pWidthAdjustment = gWidthAdjustment; + + if (pHeightAdjustment != ((short *)0)) + *pHeightAdjustment = gHeightAdjustment; +} + +/* + * videoGetBufferStatus + * This function gets the status of the video buffer, either the buffer + * has been used or not. + * + * Input: + * bufferIndex - The index of the buffer which size to be retrieved + * + * Output: + * 0 - No flip pending + * 1 - Flip pending + */ +unsigned long videoGetBufferStatus( + unsigned long bufferIndex +) +{ + return (FIELD_GET(peekRegisterDWord(VIDEO_FB_ADDRESS), VIDEO_FB_ADDRESS, STATUS)); +} + +/* + * videoGetPitch + * This function gets the video plane pitch + * + * Output: + * pitch - Number of bytes per line of the video plane + * specified in 128-bit aligned bytes. + */ +unsigned short videoGetPitch() +{ + return (FIELD_GET(peekRegisterDWord(VIDEO_FB_WIDTH), VIDEO_FB_WIDTH, WIDTH)); +} + +/* + * videoGetLineOffset + * This function gets the video plane line offset + * + * Output: + * lineOffset - Number of 128-bit aligned bytes per line + * of the video plane. + */ +unsigned short videoGetLineOffset() +{ + return (FIELD_GET(peekRegisterDWord(VIDEO_FB_WIDTH), VIDEO_FB_WIDTH, OFFSET)); +} + +/* + * videoGetBufferSize + * This function gets the buffer size + * + * Input: + * bufferIndex - The index of the buffer which size to be retrieved + */ +unsigned long videoGetBufferSize( + unsigned long bufferIndex +) +{ + unsigned long value = 0; + + if (bufferIndex == 0) + { + value = (unsigned long) + FIELD_GET(peekRegisterDWord(VIDEO_FB_ADDRESS), VIDEO_FB_ADDRESS, ADDRESS); + } + + return value; +} + + +/* + * videoGetBuffer + * This function gets the video buffer + * + * Input: + * bufferIndex - The index of the buffer to get + * + * Output: + * The video buffer of the requested index. + */ +unsigned long videoGetBuffer( + unsigned char bufferIndex +) +{ + return (FIELD_GET(peekRegisterDWord(VIDEO_FB_ADDRESS), VIDEO_FB_ADDRESS, ADDRESS)); +} + +/* + * videoSetBufferLastAddress + * This function sets the video buffer last address. + * The value can be calculated by subtracting one line offset + * from the buffer size (Total number of line offset * + * source video height). + * + * Input: + * bufferIndex - The index of the buffer to be set + * bufferSize - Size of the video buffer. + */ +void videoSetBufferLastAddress( + unsigned char bufferIndex, /* The index of the buffer to be set. */ + unsigned long bufferStart, /* Buffer start */ + unsigned long bufferSize /* Size of the video buffer */ +) +{ +#if 0 + + if (getChipType() == SM750) + { + /* Substract with one line offset to get the last address value when added + with the bufferStart. Somehow, this is only happen in SM750 chip */ + bufferSize -= (unsigned long) videoGetLineOffset(); + } + + if (bufferIndex == 0) + { + /* Set Video Buffer 0 Last Address */ + pokeRegisterDWord(VIDEO_FB_0_LAST_ADDRESS, + FIELD_VALUE(0, VIDEO_FB_0_LAST_ADDRESS, ADDRESS, bufferStart + bufferSize)); + } + else + { + /* Set Video Buffer 1 Last Address */ + pokeRegisterDWord(VIDEO_FB_1_LAST_ADDRESS, + FIELD_VALUE(0, VIDEO_FB_1_LAST_ADDRESS, ADDRESS, bufferStart + bufferSize)); + } +#endif +} + +/* + * videoGetBufferLastAddress + * This function gets the video buffer last address. + * + * Input: + * bufferIndex - The index of the buffer last address to be retrieved + */ +unsigned long videoGetBufferLastAddress( + unsigned char bufferIndex /* The index of the buffer last address to be retrieved. */ +) +{ +#if 0 + if (bufferIndex == 0) + { + /* Get Video Buffer 0 Last Address */ + return (unsigned long) (FIELD_GET(peekRegisterDWord(VIDEO_FB_0_LAST_ADDRESS), + VIDEO_FB_0_LAST_ADDRESS, ADDRESS)); + } + else + { + /* Get Video Buffer 1 Last Address */ + return (unsigned long) (FIELD_GET(peekRegisterDWord(VIDEO_FB_1_LAST_ADDRESS), + VIDEO_FB_1_LAST_ADDRESS, ADDRESS)); + } +#endif + return 0; +} + +/* + * videoSetBuffer + * This function sets the video buffer + * + * Input: + * bufferIndex - The index of the buffer to be set + * bufferStartAddress - The starting address of the buffer + */ +void videoSetBuffer( + unsigned dispCtrl, + unsigned char bufferIndex, /* The index of the buffer to be set. */ + unsigned long bufferStartAddress /* Video buffer with 128-bit alignment */ +) +{ + unsigned long bufferSize, lastAddress; + unsigned long regFB; + + /* Get the buffer size first */ + bufferSize = videoGetBufferSize(bufferIndex); + + lastAddress = videoGetBufferLastAddress(bufferIndex); +#if 0 + if (getChipType() == SM750) + { + if (lastAddress <= (bufferStartAddress + bufferSize - videoGetLineOffset())) + videoSetBufferLastAddress(bufferIndex, bufferStartAddress, bufferSize); + } + else +#endif + { + if (lastAddress <= (bufferStartAddress + bufferSize)) + videoSetBufferLastAddress(bufferIndex, bufferStartAddress, bufferSize); + } + + if (bufferIndex == 0) + { + regFB = (dispCtrl == CHANNEL0_CTRL)? VIDEO_FB_ADDRESS : (VIDEO_FB_ADDRESS+CHANNEL_OFFSET); + pokeRegisterDWord(regFB, + FIELD_SET(0, VIDEO_FB_ADDRESS, STATUS, PENDING) | + FIELD_VALUE(0, VIDEO_FB_ADDRESS, ADDRESS, bufferStartAddress)); + } +} +/* + * videoSetUVBuffer + * This function sets the video buffer + * + * Input: + * bufferIndex - The index of the buffer to be set + * bufferStartAddress - The starting address of the buffer + */ +void videoSetUVBuffer( + unsigned dispCtrl, + unsigned long bufferStartUAddress, /* Video buffer with 128-bit alignment */ + unsigned long bufferStartVAddress /* Video buffer with 128-bit alignment */ +) +{ + unsigned long regU, regV; + + regU = (dispCtrl == CHANNEL0_CTRL)? VIDEO_FB_ADDRESS_U : (VIDEO_FB_ADDRESS_U+CHANNEL_OFFSET); + regV = (dispCtrl == CHANNEL0_CTRL)? VIDEO_FB_ADDRESS_V : (VIDEO_FB_ADDRESS_V+CHANNEL_OFFSET); + pokeRegisterDWord(regU, + FIELD_VALUE(0, VIDEO_FB_ADDRESS_U, ADDRESS, bufferStartUAddress)); + pokeRegisterDWord(regV, + FIELD_VALUE(0, VIDEO_FB_ADDRESS_V, ADDRESS, bufferStartVAddress)); +} + +/* + * videoSetPitchOffset + * This function sets the video plane pitch and offset + * + * Input: + * pitch - Number of bytes per line of the video plane + * specified in 128-bit aligned bytes. + * lineOffset - Number of 128-bit aligned bytes per line + * of the video plane. + */ +void videoSetPitchOffset( + unsigned dispCtrl, + unsigned short pitch, + unsigned short lineOffset +) +{ + unsigned long regWidth; + + /* Set Video Buffer Offset (pitch) */ + regWidth = (dispCtrl == CHANNEL0_CTRL)? VIDEO_FB_WIDTH : (VIDEO_FB_WIDTH+CHANNEL_OFFSET); + pokeRegisterDWord(regWidth, + FIELD_VALUE(0, VIDEO_FB_WIDTH, WIDTH, pitch) | + FIELD_VALUE(0, VIDEO_FB_WIDTH, OFFSET, lineOffset)); +} +/* + * videoSetUVPitchOffset + * This function sets the video plane pitch and offset of U and V + * + * Input: + * pitch - Number of bytes per line of the video plane + * specified in 128-bit aligned bytes. + * lineOffset - Number of 128-bit aligned bytes per line + * of the video plane. + */ +void videoSetUVPitchOffset( + unsigned dispCtrl, + unsigned short pitch, + unsigned short lineOffset +) +{ + unsigned long regWidthU, regWidthV; + regWidthU = (dispCtrl == CHANNEL0_CTRL)? VIDEO_FB_WIDTH_U : (VIDEO_FB_WIDTH_U+CHANNEL_OFFSET); + regWidthV = (dispCtrl == CHANNEL0_CTRL)? VIDEO_FB_WIDTH_V : (VIDEO_FB_WIDTH_V+CHANNEL_OFFSET); + pokeRegisterDWord(regWidthU, + FIELD_VALUE(0, VIDEO_FB_WIDTH_U, WIDTH, pitch) | + FIELD_VALUE(0, VIDEO_FB_WIDTH_U, OFFSET, lineOffset)); + pokeRegisterDWord(regWidthV, + FIELD_VALUE(0, VIDEO_FB_WIDTH_V, WIDTH, pitch) | + FIELD_VALUE(0, VIDEO_FB_WIDTH_V, OFFSET, lineOffset)); +} +/* + * videoSetLast + * This function sets the video source last lines and width. + * + * Input: + * + * width - Video source width + * height - Video source height + */ +void videoSetLast( + unsigned dispCtrl, + unsigned long width, + unsigned long height +) +{ +#if 0 // SM768 don't have this register. Leave empty function here. + if (dispCtrl == CHANNEL0_CTRL) + { + pokeRegisterDWord(CHANNEL0_VIDEO_LAST, + FIELD_VALUE(0, CHANNEL0_VIDEO_LAST, COLUMN, width) | + FIELD_VALUE(0, CHANNEL0_VIDEO_LAST, ROW, height)); + } + else + { + pokeRegisterDWord(CHANNEL1_VIDEO_LAST, + FIELD_VALUE(0, CHANNEL1_VIDEO_LAST, COLUMN, width) | + FIELD_VALUE(0, CHANNEL1_VIDEO_LAST, ROW, height)); + } +#endif +} +/* + * videoSetWindowSize + * This function sets the video window size. + * + * Input: + * width - Video Window width + * height - Video Window height + */ +void videoSetWindowSize( + unsigned dispCtrl, + unsigned long width, + unsigned long height +) +{ + unsigned long value, startX, startY; + unsigned long regTL, regBR; + regTL = (dispCtrl == CHANNEL0_CTRL)? VIDEO_PLANE_TL : (VIDEO_PLANE_TL+CHANNEL_OFFSET); + regBR = (dispCtrl == CHANNEL0_CTRL)? VIDEO_PLANE_BR : (VIDEO_PLANE_BR+CHANNEL_OFFSET); + + value = peekRegisterDWord(regTL); + startX = FIELD_GET(value, VIDEO_PLANE_TL, LEFT); + startY = FIELD_GET(value, VIDEO_PLANE_TL, TOP); + + /* Set bottom and right position */ + pokeRegisterDWord(regBR, + FIELD_VALUE(0, VIDEO_PLANE_BR, BOTTOM, startY + height - 1 - gHeightAdjustment) | + FIELD_VALUE(0, VIDEO_PLANE_BR, RIGHT, startX + width - 1 - gWidthAdjustment)); +} + +/* + * videoGetWindowSize + * This function gets the video window size. + * + * Output: + * width - Video Window width + * height - Video Window height + */ +void videoGetWindowSize( + unsigned dispCtrl, + unsigned long *pVideoWidth, + unsigned long *pVideoHeight +) +{ + unsigned long positionTopLeft, positionRightBottom; + unsigned long videoWidth, videoHeight; + unsigned long regTL, regBR; + regTL = (dispCtrl == CHANNEL0_CTRL)? VIDEO_PLANE_TL : (VIDEO_PLANE_TL+CHANNEL_OFFSET); + regBR = (dispCtrl == CHANNEL0_CTRL)? VIDEO_PLANE_BR : (VIDEO_PLANE_BR+CHANNEL_OFFSET); + + positionTopLeft = peekRegisterDWord(regTL); + positionRightBottom = peekRegisterDWord(regBR); + videoWidth = FIELD_GET(positionRightBottom, VIDEO_PLANE_BR, RIGHT) - + FIELD_GET(positionTopLeft, VIDEO_PLANE_TL, LEFT) + 1 + + gWidthAdjustment; + videoHeight = FIELD_GET(positionRightBottom, VIDEO_PLANE_BR, BOTTOM) - + FIELD_GET(positionTopLeft, VIDEO_PLANE_TL, TOP) + 1 + + gHeightAdjustment; + + if (pVideoWidth != ((unsigned long *)0)) + *pVideoWidth = videoWidth; + + if (pVideoHeight != ((unsigned long *)0)) + *pVideoHeight = videoHeight; +} + +/* + * videoSetPosition + * This function sets the video starting coordinate position. + * + * Input: + * startX - X Coordinate of the video window starting position + * startY - Y Coordinate of the video window starting position + */ +void videoSetPosition( + unsigned dispCtrl, + unsigned long startX, + unsigned long startY +) +{ + unsigned long videoWidth, videoHeight; + unsigned long regTL; + + regTL = (dispCtrl == CHANNEL0_CTRL)? VIDEO_PLANE_TL : (VIDEO_PLANE_TL+CHANNEL_OFFSET); + + /* Get the video window width and height */ + videoGetWindowSize(dispCtrl, &videoWidth, &videoHeight); + + pokeRegisterDWord(regTL, + FIELD_VALUE(0, VIDEO_PLANE_TL, TOP, startY) | + FIELD_VALUE(0, VIDEO_PLANE_TL, LEFT, startX)); + + /* Set bottom and right position */ + videoSetWindowSize(dispCtrl, videoWidth, videoHeight); + +} + +/* + * videoSetConstants + * This function sets the video constants. The actual component will be + * added by this constant to get the expected component value. + * + * Input: + * yConstant - Y Constant Value + * redConstant - Red Constant Value + * greenConstant - Green Constant Value + * blueConstant - Blue Constant Value + */ +void videoSetConstants( + unsigned dispCtrl, + unsigned char yConstant, /* Y Adjustment */ + unsigned char redConstant, /* Red Conversion constant */ + unsigned char greenConstant, /* Green Conversion constant */ + unsigned char blueConstant /* Blue Conversion constant */ +) +{ + unsigned long regYUV; + + regYUV = (dispCtrl == CHANNEL0_CTRL)? VIDEO_YUV_CONSTANTS : (VIDEO_YUV_CONSTANTS+CHANNEL_OFFSET); + pokeRegisterDWord(regYUV, + FIELD_VALUE(0, VIDEO_YUV_CONSTANTS, Y, yConstant) | + FIELD_VALUE(0, VIDEO_YUV_CONSTANTS, R, redConstant) | + FIELD_VALUE(0, VIDEO_YUV_CONSTANTS, G, greenConstant) | + FIELD_VALUE(0, VIDEO_YUV_CONSTANTS, B, blueConstant)); +} + +/* + * videoSetInitialScale + * This function sets the video buffer initial vertical scale. + * + * Input: + * bufferIndex - Index of the buffer which vertical scale value + * to be set. + * bufferInitScale - Buffer Initial vertical scale value + */ +void videoSetInitialScale( + unsigned dispCtrl, + unsigned short InitScaleHorizontal, + unsigned short InitScaleVertical +) +{ + unsigned long value; + unsigned long regScale; + + regScale = (dispCtrl == CHANNEL0_CTRL)? VIDEO_INITIAL_SCALE : (VIDEO_INITIAL_SCALE+CHANNEL_OFFSET); + + value = peekRegisterDWord(regScale); + value = FIELD_VALUE(value, VIDEO_INITIAL_SCALE, VERTICAL, InitScaleVertical); + value = FIELD_VALUE(value, VIDEO_INITIAL_SCALE, HORIZONTAL, InitScaleHorizontal); + pokeRegisterDWord(regScale, value); +} + +/* + * videoGetInitialScale + * This function gets the video buffer initial vertical scale. + * + * Input: + * pbuffer0InitScale - Pointer to variable to store buffer 0 initial vertical scale + * pbuffer1InitScale - Pointer to variable to store buffer 1 initial vertical scale + */ +void videoGetInitialScale( + unsigned dispCtrl, + unsigned short *pBufferVInitScale, + unsigned short *pBufferHInitScale +) +{ + unsigned long regScale; + + regScale = (dispCtrl == CHANNEL0_CTRL)? VIDEO_INITIAL_SCALE : (VIDEO_INITIAL_SCALE+CHANNEL_OFFSET); + + *pBufferHInitScale = (unsigned short) + FIELD_GET(peekRegisterDWord(regScale), VIDEO_INITIAL_SCALE, HORIZONTAL); + *pBufferVInitScale = (unsigned short) + FIELD_GET(peekRegisterDWord(regScale), VIDEO_INITIAL_SCALE, VERTICAL); +} + +/* + * videoScale + * This function scales the video. + * + * Input: + * srcWidth - The source video width + * srcHeight - The source video height + * dstWidth - The destination video width + * dstHeight - The destination video height + */ +void videoScale( + unsigned dispCtrl, + unsigned long srcWidth, + unsigned long srcHeight, + unsigned long dstWidth, + unsigned long dstHeight +) +{ + unsigned long value = 0; + unsigned long scaleFactor; + unsigned long regScale; + + regScale = (dispCtrl == CHANNEL0_CTRL)? VIDEO_SCALE : (VIDEO_SCALE+CHANNEL_OFFSET); + + if (dstHeight >= srcHeight) + { + /* Calculate the factor */ + scaleFactor = (srcHeight-1) * SCALE_CONSTANT / dstHeight; + value = FIELD_VALUE(value, VIDEO_SCALE , VERTICAL_SCALE, scaleFactor); + } + + /* Scale the horizontal size */ + if (dstWidth >= srcWidth) + { + /* Calculate the factor */ + scaleFactor = (srcWidth-1) * SCALE_CONSTANT / dstWidth; + value = FIELD_VALUE(value, VIDEO_SCALE, HORIZONTAL_SCALE, scaleFactor); + } + + pokeRegisterDWord(regScale, value); +} + + +/* + * videoSwapYUVByte + * This function swaps the YUV data byte. + * + * Input: + * byteSwap - Flag to enable/disable YUV data byte swap. + */ +void videoSwapYUVByte( + unsigned dispCtrl, + video_byteswap_t byteSwap +) +{ + unsigned long value; + unsigned long regCtrl; + + regCtrl = (dispCtrl == CHANNEL0_CTRL)? VIDEO_DISPLAY_CTRL : (VIDEO_DISPLAY_CTRL+CHANNEL_OFFSET); + + value = peekRegisterDWord(regCtrl); + if (byteSwap == SWAP_BYTE) + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, BYTE_SWAP, ENABLE); + else + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, BYTE_SWAP, DISABLE); + + pokeRegisterDWord(regCtrl, value); +} + +/* + * videoSetInterpolation + * This function enables/disables the horizontal and vertical interpolation. + * + * Input: + * enableHorzInterpolation - Flag to enable/disable Horizontal interpolation + * enableVertInterpolation - Flag to enable/disable Vertical interpolation + */ +void videoSetInterpolation( + unsigned dispCtrl, + unsigned long enableHorzInterpolation, + unsigned long enableVertInterpolation +) +{ + unsigned long value; + unsigned long regCtrl; + + regCtrl = (dispCtrl == CHANNEL0_CTRL)? VIDEO_DISPLAY_CTRL : (VIDEO_DISPLAY_CTRL+CHANNEL_OFFSET); + + value = peekRegisterDWord(regCtrl); + + if (enableHorzInterpolation) + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, HORIZONTAL_MODE, INTERPOLATE); + else + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, HORIZONTAL_MODE, REPLICATE); + + if (enableVertInterpolation) + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, VERTICAL_MODE, INTERPOLATE); + else + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, VERTICAL_MODE, REPLICATE); + + pokeRegisterDWord(regCtrl, value); +} + +/* + * videoGetInterpolation + * This function gets the horizontal and vertical interpolation enable status. + * + * Input: + * pHorzInterpolationStatus - Pointer to store the horizontal interpolation status + * pVertInterpolationStatus - Pointer to store the vertical interpolation status + */ +void videoGetInterpolation( + unsigned long *pHorzInterpolationStatus, + unsigned long *pVertInterpolationStatus +) +{ + unsigned long value; + + value = peekRegisterDWord(VIDEO_DISPLAY_CTRL); + if (pHorzInterpolationStatus != (unsigned long *)0) + { + if (FIELD_GET(value, VIDEO_DISPLAY_CTRL, HORIZONTAL_MODE) == VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE_INTERPOLATE) + *pHorzInterpolationStatus = 1; + else + *pHorzInterpolationStatus = 0; + } + + if (pHorzInterpolationStatus != (unsigned long *)0) + { + if (FIELD_GET(value, VIDEO_DISPLAY_CTRL, VERTICAL_MODE) == VIDEO_DISPLAY_CTRL_VERTICAL_MODE_INTERPOLATE) + *pVertInterpolationStatus = 1; + else + *pVertInterpolationStatus = 0; + } +} + +/* + * videoSetStartPanningPixel + * This function sets the starting pixel number for smooth pixel panning. + * + * Input: + * startPixel - Starting pixel number for smooth pixel panning + */ +void videoSetStartPanningPixel( + unsigned char startPixel +) +{ + pokeRegisterDWord(VIDEO_DISPLAY_CTRL, + peekRegisterDWord(VIDEO_DISPLAY_CTRL) | + FIELD_VALUE(0, VIDEO_DISPLAY_CTRL, PIXEL, startPixel)); +} + +/* + * videoSetGamma + * This function enables/disables gamma control. + * + * Input: + * enableGammaCtrl - The gamma enable control + * + * NOTE: + * The gamma can only be enabled in RGB565 and RGB888. Enable this gamma + * without proper format will have no effect. + */ +void videoSetGammaCtrl( + unsigned dispCtrl, + unsigned long enableGammaCtrl +) +{ + unsigned long value; + unsigned long regCtrl; + + regCtrl = (dispCtrl == CHANNEL0_CTRL)? VIDEO_DISPLAY_CTRL : (VIDEO_DISPLAY_CTRL+CHANNEL_OFFSET); + + value = peekRegisterDWord(regCtrl); + + if (enableGammaCtrl) + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, GAMMA, ENABLE); + else + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, GAMMA, DISABLE); + + pokeRegisterDWord(regCtrl, value); +} + +/* + * isVideoEnable + * This function check whether the video plane is already enabled or not. + * + * Output: + * 0 - Disable + * 1 - Enable + */ +unsigned char isVideoEnable() +{ + unsigned long value; + + value = peekRegisterDWord(VIDEO_DISPLAY_CTRL); + + return ((FIELD_GET(value, VIDEO_DISPLAY_CTRL, PLANE) == VIDEO_DISPLAY_CTRL_PLANE_ENABLE) ? 1 : 0); +} + +/* + * videoSetCtrl + * This function enable/disable the video plane. + * + * Input: + * videoCtrl - Enable/Disable video + */ +static void videoSetCtrl( + disp_control_t dispCtrl, + video_ctrl_t videoCtrl +) +{ + unsigned long value; + unsigned long regCtrl; + + regCtrl = (dispCtrl == CHANNEL0_CTRL)? VIDEO_DISPLAY_CTRL : (VIDEO_DISPLAY_CTRL+CHANNEL_OFFSET); + + value = peekRegisterDWord(regCtrl); + + if (videoCtrl == VIDEO_ON) + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, PLANE, ENABLE); + else + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, PLANE, DISABLE); + + pokeRegisterDWord(regCtrl, value); +} + +/* + * videoSetFormat + * This function sets the video format. + * + * Input: + * videoFormat - The video content format + * * FORMAT_RGB565 - 16-bit RGB 5:6:5 mode + * * FORMAT_YUYV - 16-bit YUYV mode + */ +static void videoSetFormat( + unsigned dispCtrl, + video_format_t videoFormat +) +{ + unsigned long value; + unsigned long regCtrl; + + regCtrl = (dispCtrl == CHANNEL0_CTRL)? VIDEO_DISPLAY_CTRL : (VIDEO_DISPLAY_CTRL+CHANNEL_OFFSET); + + value = peekRegisterDWord(regCtrl); + switch (videoFormat) + { + default: + case FORMAT_RGB565: + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL , FORMAT, 16); + break; + case FORMAT_RGB888: + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL , FORMAT, 32); + break; + case FORMAT_YUYV: + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL , FORMAT, YUV422); + break; + case FORMAT_YUV420: + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL , FORMAT, YUV420); + break; + } + + pokeRegisterDWord(regCtrl, value); +} + +/* + * videoSetEdgeDetection + * This function enable/disable the edge detection and fill out the edge detection + * value as well. This function only works in SM718. SM750 does not support this + * feature. + * + * Input: + * enableEdgeDetect - Enable/Disable Edge Detection (0 - disable, 1 = enable) + * edgeDetectValue - The Edge Detection value. This is the difference (delta) + * of the pixel colors to be considered as an edge. + * + * Note: + * This edge correction only works in up-scale video. + */ +void videoSetEdgeDetection( + unsigned long enableEdgeDetect, + unsigned long edgeDetectValue +) +{ +#if 0 //SM768 don't have this register. Just leave an empty function here. + unsigned long value; + + if (getChipType() == SM718) + { + if (enableEdgeDetect == 1) + { + value = FIELD_SET(0, VIDEO_EDGE_DETECTION, DETECT, ENABLE) | + FIELD_VALUE(value, VIDEO_EDGE_DETECTION, VALUE, edgeDetectValue); + pokeRegisterDWord(VIDEO_EDGE_DETECTION, value); + } + else + { + value = FIELD_SET(peekRegisterDWord(VIDEO_EDGE_DETECTION), VIDEO_EDGE_DETECTION, DETECT, DISABLE); + pokeRegisterDWord(VIDEO_EDGE_DETECTION, value); + } + } +#endif +} + +/* + * videoGetEdgeDetection + * This function gets the information whether the edge detection is enabled or not. + * It also outputs the edge detection value if required. + * This function only works in SM718. SM750 does not support this feature. + * + * Input: + * pEdgeDetectValue - Pointer to a buffer to store the edge detection value. + * + * Note: + * 0 - Edge Detection is disabled + * 1 - Edge Detection is enabled + */ +unsigned long videoGetEdgeDetection( + unsigned long *pEdgeDetectValue +) +{ +#if 0 //Not for SM768 + unsigned long value; + + if (getChipType() == SM718) + { + value = peekRegisterDWord(VIDEO_EDGE_DETECTION); + + if (pEdgeDetectValue != (unsigned long *)0) + *pEdgeDetectValue = (unsigned long) FIELD_GET(value, VIDEO_EDGE_DETECTION, VALUE); + + if (FIELD_GET(value, VIDEO_EDGE_DETECTION, DETECT) == VIDEO_EDGE_DETECTION_DETECT_ENABLE) + return 1; + else + return 0; + } +#endif + return 0; +} + +/* + * videoSetup + * This function setups the video. This function only works in SM718. + * SM750 does not support edge detection feature. If calling this function + * in SM750, set edgeDetect flag to 0 + * + * Input: + * x - X Coordinate of the video window + * y - Y Coordinate of the video window + * srcWidth - The source video width + * srcHeight - The source video height + * dstWidth - The destination video width + * dstHeight - The destination video height + * doubleBuffer - Double Buffer enable flag + * srcAddress0 - The source of the video buffer 0 to display + * srcAddress1 - The source of the video buffer 1 to display + * (only for double buffering). + * srcPitch - The source video plane pitch in bytes + * srcLineOffset - The source video plane line offset in bytes. + * In normal usage, set it the same as the srcBufferPitch + * videoFormat - Source video format + * edgeDetect - Edge Detection enable flag (can only works with vertical upscaling) + * 0 - Disable + * 1 - Always Enable (alwasy enabled regardless horizontal scaling condition) + * 2 - Auto Enable (only enabled when no horizontal shrink) + * edgeDetectValue - Edge Detection value + * + * Output: + * 0 - Success + * -1 - Fail + */ +unsigned char videoSetupEx( + unsigned dispCtrl, + unsigned long x, /* X Coordinate of the video window */ + unsigned long y, /* Y Coordinate of the video window */ + unsigned long srcWidth, /* The source video width */ + unsigned long srcHeight, /* The source video height */ + unsigned long dstWidth, /* The destination video width */ + unsigned long dstHeight, /* The destination video height */ + unsigned long doubleBuffer, /* Double Buffer enable flag */ + unsigned long srcAddress0, /* The source of the video buffer 0 to display */ + unsigned long sUAddress, /* U Source Base Address (not used in RGB Space) */ + unsigned long sVAddress, /* V Source Base Address (not used in RGB Space) */ + unsigned long sUVPitch, /* UV plane pitch value in bytes (not used in */ + unsigned long srcPitch, /* The source video plane pitch in bytes */ + unsigned long srcLineOffset, /* The source video plane line offset in bytes. + Set it the same as srcPitch in normal + usage. */ + video_format_t videoFormat, /* Source video format */ + unsigned long edgeDetect, /* Edge Detection enable flag */ + unsigned long edgeDetectValue /* Edge Detection value. SM718 only use bit 9 to 0 */ +) +{ + unsigned long enableEdgeDetect; + /* Save the source video width and height */ + gSrcVideoWidth = srcWidth; + gSrcVideoHeight = srcHeight; + /* Disable the video plane first */ + videoSetCtrl(dispCtrl, VIDEO_OFF); + + /* Set the video position */ + videoSetPosition(dispCtrl, x, y); + + /* Set the scale factor */ + videoScale(dispCtrl, srcWidth, srcHeight, dstWidth, dstHeight); + + /* Set the video format */ + videoSetFormat(dispCtrl, videoFormat); + + /* Set the buffer pitch */ + videoSetPitchOffset(dispCtrl, srcPitch, srcLineOffset); + /* Set the UV buffer pitch */ + videoSetUVPitchOffset(dispCtrl, sUVPitch, sUVPitch); + + /* Enable double buffer */ +// videoEnableDoubleBuffer(doubleBuffer); + + /* Set the video buffer 0 and 1 */ + videoSetBuffer(dispCtrl, 0, srcAddress0); +// videoSetBuffer(dispCtrl, 1, srcAddress1); + + /* Set the video buffer U and V */ + videoSetUVBuffer(dispCtrl, sUAddress, sVAddress); + + /* Set the destination video window */ + videoSetWindowSize(dispCtrl, dstWidth, dstHeight); + + /* Set the last line */ + videoSetLast(dispCtrl, srcWidth, srcHeight); + + /* Set the edge detection enable bit and its value (if applicable) */ + if (edgeDetect == 0) + enableEdgeDetect = 0; + else if (edgeDetect == 1) + enableEdgeDetect = 1; + else + { + /* Only enable the edgeDetection when scaling up vertically and no + shrinking on the horizontal. */ + if ((dstHeight > srcHeight) && (dstWidth >= srcWidth)) + enableEdgeDetect = 1; + else + enableEdgeDetect = 0; + } + videoSetEdgeDetection(enableEdgeDetect, edgeDetectValue); + + return 0; +} + +/* + * videoSetup + * This function setups the video. + * + * Input: + * x - X Coordinate of the video window + * y - Y Coordinate of the video window + * srcWidth - The source video width + * srcHeight - The source video height + * dstWidth - The destination video width + * dstHeight - The destination video height + * doubleBuffer - Double Buffer enable flag + * srcAddress0 - The source of the video buffer 0 to display + * srcAddress1 - The source of the video buffer 1 to display + * (only for double buffering). + * srcPitch - The source video plane pitch in bytes + * srcLineOffset - The source video plane line offset in bytes. + * In normal usage, set it the same as the srcBufferPitch + * videoFormat - Source video format + * + * Output: + * 0 - Success + * -1 - Fail + */ +unsigned char videoSetup( + disp_control_t dispCtrl, + unsigned long x, /* X Coordinate of the video window */ + unsigned long y, /* Y Coordinate of the video window */ + unsigned long srcWidth, /* The source video width */ + unsigned long srcHeight, /* The source video height */ + unsigned long dstWidth, /* The destination video width */ + unsigned long dstHeight, /* The destination video height */ + unsigned long doubleBuffer, /* Double Buffer enable flag */ + unsigned long srcAddress0, /* The source of the video buffer 0 to display */ + unsigned long srcAddress1, /* The source of the video buffer 1 to display + (only for double buffering). + */ + unsigned long srcPitch, /* The source video plane pitch in bytes */ + unsigned long srcLineOffset, /* The source video plane line offset in bytes. + Set it the same as srcPitch in normal + usage. */ + video_format_t videoFormat /* Source video format */ +) +{ + return videoSetupEx(dispCtrl, x, y, srcWidth, srcHeight, dstWidth, dstHeight, doubleBuffer, + srcAddress0, 0, 0, 0,srcPitch, srcLineOffset, videoFormat, + 0, 0); + +} + +/* + * startVideo + * This function starts the video. + */ +void startVideo( +unsigned dispCtrl +) +{ + /* Enable the video plane */ + videoSetCtrl(dispCtrl, VIDEO_ON); +} + +/* + * stopVideo + * This function stops the video. + */ +void stopVideo(unsigned dispCtrl) +{ + /* Just disable the video plane */ + videoSetCtrl(dispCtrl, VIDEO_OFF); +} + +/* + * Only valid for Overlay layer. Setup video settings and enable it. +*/ + +int SM768_setOverlay( + disp_control_t dispControl, /* Channel 0 or Channel 1) */ + PBLIT_BLK src, /* Only need: source Width & Height, Pitch */ + PYUV_BUF_ADDR SrcAddr, /* Y U V source base address */ + PBLIT_BLK dest, /* Needed input value: destination X & Y & Width & Height */ + file_format srcFormat +) +{ + unsigned long yPitch = 0, uvPitch = 0; + video_format_t VideoFormat = FORMAT_RGB565; + + /* Set Video Conversion Constant */ + videoSetConstants( + dispControl, + 0, /* Y Adjustment */ + 0xED, /* Red Conversion constant */ + 0xED, /* Green Conversion constant */ + 0xED); /* Blue Conversion constant */ + + /* Set video initial scale for Buffer 0 and buffer 1 */ + videoSetInitialScale(dispControl, 0, 0); + + /* Set source buffer */ + // videoSetSourceBuffer(NORMAL_BUFFER); + + /* Set the YUV Swap byte */ + videoSwapYUVByte(dispControl,NORMAL); + + /* Set video interpolation */ + videoSetInterpolation(dispControl, 0, 0); + + /* Not using Gamma Control */ + videoSetGammaCtrl(dispControl, 0); + + /* Setup the video */ + /* Based on the selected fileFormat, calculate the video source addresses (if necessary) and pitches. */ + switch (srcFormat) + { + case FFT_RGB565: + yPitch = PITCH(src->Width, 16); + uvPitch = 0; + VideoFormat = FORMAT_RGB565; + break; + case FFT_RGBx888: + yPitch = PITCH(src->Width, 32); + uvPitch = 0; + VideoFormat = FORMAT_RGB888; + break; + } + videoSetupEx( + dispControl, + dest->x, /* X Coordinate of the video window */ + dest->y, /* Y Coordinate of the video window */ + src->Width, /* The source video width */ + src->Height, /* The source video height */ + dest->Width, /* The destination video width */ + dest->Height, /* The destination video height */ + 0, /* Double buffer enable flag */ + SrcAddr->bufYAddr, /* The source of the video buffer 0 to display */ + SrcAddr->bufCbAddr, /* U Source Base Address (not used in RGB Space) */ + SrcAddr->bufCrAddr, /* V Source Base Address (not used in RGB Space) */ + uvPitch, /* UV plane pitch value in bytes (not used in */ + yPitch, /* The source address buffer pitch in bytes */ + yPitch, /* The source address buffer offset in bytes. + Set it the same as srcPitch in normal + usage. */ + VideoFormat, /* Source video format */ + 0, /* Edge Detection enable flag */ + 0); /* Edge Detection value. SM718 only use bit 9 to 0 */ + + /* Start Video */ + startVideo(dispControl); + return 0; +} + + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddk768_video.h b/drivers/gpu/drm/smidrm/ddk768/ddk768_video.h new file mode 100644 index 000000000000..bdfa4c5222ca --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddk768_video.h @@ -0,0 +1,606 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* Video.H --- SM768 DDK +* This file contains the definitions for the Video functions. +* +*******************************************************************/ + + +/**************************************************************************** + Structure and data type definition + ****************************************************************************/ + +/* video format: + - 16-bit RGB 5:6:5 mode + - 16-bit YUYV mode + + Note: The 8-bit index and RGB 8:8:8 formats are not supported + */ +typedef enum _video_format_t +{ + FORMAT_RGB565 = 0, + FORMAT_YUV420, + FORMAT_YUYV, + FORMAT_RGB888 +} +video_format_t; + +/* YUV Data Byte Swap */ +typedef enum _video_byteswap_t +{ + NORMAL = 0, + SWAP_BYTE +} +video_byteswap_t; + +/* Turn on/off video */ +typedef enum _video_sync_source_t +{ + NORMAL_BUFFER = 0, + CAPTURE_BUFFER +} +video_sync_source_t; + +/* FIFO Request Level */ +typedef enum _video_fifo_t +{ + FIFO_LEVEL_1 = 0, + FIFO_LEVEL_3, + FIFO_LEVEL_7, + FIFO_LEVEL_11 +} +video_fifo_t; + +/* Turn on/off video */ +typedef enum _video_ctrl_t +{ + VIDEO_OFF = 0, + VIDEO_ON +} +video_ctrl_t; + + + + + + +#define PITCH(width, bpp) (((width) * (bpp) / 8 + 15) & ~15) + +typedef enum _file_format +{ + FFT_RGB565 = 0 , + FFT_RGBx888 +}file_format; + +typedef struct YUV_BUF_ADDR +{ + unsigned long bufYAddr; + unsigned long bufCbAddr; + unsigned long bufCrAddr; +} YUV_BUF_ADDR, *PYUV_BUF_ADDR; +typedef struct BLIT_BLK +{ + unsigned long Base; + unsigned long Pitch; + unsigned long Bpp; /* Only needed for the destination surface */ + unsigned long x; + unsigned long y; + unsigned long Width; + unsigned long Height; +} BLIT_BLK, *PBLIT_BLK; + + + + + + + +/**************************************************************************** + Function prototype + ****************************************************************************/ + +/* + * videoSetWindowAdjustment + * This function sets the video window adjustment. There are usually + * some garbage lines or pixels at the bottom and right of the video + * window. These function will adjust the video window accordingly. + * + * Input: + * widthAdjustment - Width adjustments in pixel + * heightAdjustment - Height adjustment in line + */ +void videoSetWindowAdjustment( + unsigned dispCtrl, + short widthAdjustment, + short heightAdjustment +); + +/* + * videoGetWindowAdjustment + * This function gets the video window adjustment. + * + * Input: + * widthAdjustment - Width adjustments in pixel + * heightAdjustment - Height adjustment in line + */ +void videoGetWindowAdjustment( + short *pWidthAdjustment, + short *pHeightAdjustment +); + +/* + * videoGetCurrentBufferDisplay + * This function gets the current buffer used by SM50x to display on the screen + * + * Return: + * 0 - Buffer 0 + * 1 - Buffer 1 + */ +// unsigned char videoGetCurrentBufferDisplay(); + +/* + * videoEnableDoubleBuffer + * This function enables/disables the double buffer usage + * + * Input: + * enable - Flag to enable/disable the double buffer. + */ +#if 0 +void videoEnableDoubleBuffer( + unsigned long enable +); +#endif + +/* + * videoGetBufferStatus + * This function gets the status of the video buffer, either the buffer + * has been used or not. + * + * Input: + * bufferIndex - The index of the buffer which size to be retrieved + * + * Output: + * 0 - No flip pending + * 1 - Flip pending + */ +unsigned long videoGetBufferStatus( + unsigned long bufferIndex +); + +/* + * videoGetBuffer + * This function gets the video buffer + * + * Input: + * bufferIndex - The index of the buffer to get + * + * Output: + * The video buffer of the requested index. + */ +unsigned long videoGetBuffer( + unsigned char bufferIndex +); + +/* + * videoSetBuffer + * This function sets the video buffer + * + * Input: + * bufferIndex - The index of the buffer to be set + * bufferStartAddress - The starting address of the buffer + */ +void videoSetBuffer( + unsigned dispCtrl, + unsigned char bufferIndex, /* The index of the buffer to be set. */ + unsigned long bufferStartAddress /* Video buffer with 128-bit alignment */ +); +/* + * videoSetUVBuffer + * This function sets the video buffer of U and V + * + * Input: + * bufferIndex - The index of the buffer to be set + * bufferStartAddress - The starting address of the buffer + */ +void videoSetUVBuffer( + unsigned dispCtrl, + unsigned long bufferStartUAddress, /* Video buffer with 128-bit alignment */ + unsigned long bufferStartVAddress /* Video buffer with 128-bit alignment */ +); + +/* + * videoSetPitchOffset + * This function sets the video plane pitch and offset + * + * Input: + * pitch - Number of bytes per line of the video plane + * specified in 128-bit aligned bytes. + * lineOffset - Number of 128-bit aligned bytes per line + * of the video plane. + */ +void videoSetPitchOffset( + unsigned dispCtrl, + unsigned short pitch, + unsigned short lineOffset +); + +/* + * videoSetUVPitchOffset + * This function sets the video plane pitch and offset of U and V + * + * Input: + * pitch - Number of bytes per line of the video plane + * specified in 128-bit aligned bytes. + * lineOffset - Number of 128-bit aligned bytes per line + * of the video plane. + */ +void videoSetUVPitchOffset( + unsigned dispCtrl, + unsigned short pitch, + unsigned short lineOffset +); + +/* + * videoGetPitch + * This function gets the video plane pitch + * + * Output: + * pitch - Number of bytes per line of the video plane + * specified in 128-bit aligned bytes. + */ +unsigned short videoGetPitch(void); + +/* + * videoGetLineOffset + * This function gets the video plane line offset + * + * Output: + * lineOffset - Number of 128-bit aligned bytes per line + * of the video plane. + */ +unsigned short videoGetLineOffset(void); +/* + * videoSetLast + * This function sets the video source last lines and width. + * + * Input: + * + * width - Video source width + * height - Video source height + */ +void videoSetLast( + unsigned dispCtrl, + unsigned long width, + unsigned long height +); + +/* + * videoSetWindowSize + * This function sets the video window size. + * + * Input: + * width - Video Window width + * height - Video Window height + */ +void videoSetWindowSize( + unsigned dispCtrl, + unsigned long width, + unsigned long height +); + +/* + * videoGetWindowSize + * This function gets the video window size. + * + * Output: + * width - Video Window width + * height - Video Window height + */ +void videoGetWindowSize( + unsigned dispCtrl, + unsigned long *pWidth, + unsigned long *pHeight +); + +/* + * videoSetPosition + * This function sets the video starting coordinate position. + * + * Input: + * startX - X Coordinate of the video window starting position + * startY - Y Coordinate of the video window starting position + */ +void videoSetPosition( + unsigned dispCtrl, + unsigned long startX, + unsigned long startY +); + +/* + * videoSetConstants + * This function sets the video constants. The actual component will be + * added by this constant to get the expected component value. + * + * Input: + * yConstant - Y Constant Value + * redConstant - Red Constant Value + * greenConstant - Green Constant Value + * blueConstant - Blue Constant Value + */ +void videoSetConstants( + unsigned dispCtrl, + unsigned char yConstant, /* Y Adjustment */ + unsigned char redConstant, /* Red Conversion constant */ + unsigned char greenConstant, /* Green Conversion constant */ + unsigned char blueConstant /* Blue Conversion constant */ +); + +/* + * videoSetInitialScale + * This function sets the video buffer initial vertical scale. + * + * Input: + * bufferIndex - Index of the buffer which vertical scale value + * to be set. + * bufferInitScale - Buffer Initial vertical scale value + */ +void videoSetInitialScale( + unsigned dispCtrl, + unsigned short InitScaleHorizontal, + unsigned short InitScaleVertical +); + +/* + * videoSetFIFOLevel + * This function sets the video FIFO Request Level. + * + * Input: + * videoSource - Buffer source selection + */ +#if 0 +void videoSetFIFOLevel( + video_fifo_t videoFIFO +); +#endif +/* + * videoSetSourceBuffer + * This function sets the video to use the capture buffer as the source. + * + * Input: + * videoSource - Buffer source selection + */ +#if 0 +void videoSetSourceBuffer( + video_sync_source_t videoSource +); +#endif + +/* + * videoSwapYUVByte + * This function swaps the YUV data byte. + * + * Input: + * byteSwap - Flag to enable/disable YUV data byte swap. + */ +void videoSwapYUVByte( + unsigned dispCtrl, + video_byteswap_t byteSwap +); + +/* + * videoSetInterpolation + * This function enables/disables the horizontal and vertical interpolation. + * + * Input: + * enableHorzInterpolation - Flag to enable/disable Horizontal interpolation + * enableVertInterpolation - Flag to enable/disable Vertical interpolation + */ +void videoSetInterpolation( + unsigned dispCtrl, + unsigned long enableHorzInterpolation, + unsigned long enableVertInterpolation +); + +/* + * videoGetInterpolation + * This function gets the horizontal and vertical interpolation enable status. + * + * Input: + * pHorzInterpolationStatus - Pointer to store the horizontal interpolation status + * pVertInterpolationStatus - Pointer to store the vertical interpolation status + */ +void videoGetInterpolation( + unsigned long *pHorzInterpolationStatus, + unsigned long *pVertInterpolationStatus +); + +/* + * videoSetStartPanningPixel + * This function sets the starting pixel number for smooth pixel panning. + * + * Input: + * startPixel - Starting pixel number for smooth pixel panning + */ +void videoSetStartPanningPixel( + unsigned char startPixel +); + +/* + * videoSetGamma + * This function enables/disables gamma control. + * + * Input: + * enableGammaCtrl - The gamma enable control + * + * NOTE: + * The gamma can only be enabled in RGB565 and RGB888. Enable this gamma + * without proper format will have no effect. + */ +void videoSetGammaCtrl( + unsigned dispCtrl, + unsigned long enableGammaCtrl +); + +/* + * isVideoEnable + * This function check whether the video plane is already enabled or not. + * + * Output: + * 0 - Disable + * 1 - Enable + */ +unsigned char isVideoEnable(void); + +/* + * videoSetEdgeDetection + * This function enable/disable the edge detection and fill out the edge detection + * value as well. This function only works in SM718. SM750 does not support this + * feature. + * + * Input: + * enableEdgeDetect - Enable/Disable Edge Detection + * edgeDetectValue - The Edge Detection value. This is the difference (delta) + * of the pixel colors to be considered as an edge. + * + * Note: + * This edge correction only works in up-scale video. + */ +void videoSetEdgeDetection( + unsigned long enableEdgeDetect, + unsigned long edgeDetectValue +); + +/* + * videoGetEdgeDetection + * This function gets the information whether the edge detection is enabled or not. + * It also outputs the edge detection value if required. + * This function only works in SM718. SM750 does not support this feature. + * + * Input: + * pEdgeDetectValue - Pointer to a buffer to store the edge detection value. + * + * Note: + * 0 - Edge Detection is disabled + * 1 - Edge Detection is enabled + */ +unsigned long videoGetEdgeDetection( + unsigned long *pEdgeDetectValue +); + +/* + * videoSetupEx + * This function setups the video. It only applies in SM718 + * + * Input: + * x - X Coordinate of the video window + * y - Y Coordinate of the video window + * srcWidth - The source video width + * srcHeight - The source video height + * dstWidth - The destination video width + * dstHeight - The destination video height + * doubleBuffer - Double Buffer enable flag + * srcAddress0 - The source of the video buffer 0 to display + * srcAddress1 - The source of the video buffer 1 to display + * (only for double buffering). + * srcPitch - The source video plane pitch in bytes + * srcLineOffset - The source video plane line offset in bytes. + * In normal usage, set it the same as the srcBufferPitch + * videoFormat - Source video format + * edgeDetect - Edge Detection enable flag + * edgeDetectValue - Edge Detection value + * + * Output: + * 0 - Success + * -1 - Fail + */ +unsigned char videoSetupEx( + unsigned dispCtrl, + unsigned long x, /* X Coordinate of the video window */ + unsigned long y, /* Y Coordinate of the video window */ + unsigned long srcWidth, /* The source video width */ + unsigned long srcHeight, /* The source video height */ + unsigned long dstWidth, /* The destination video width */ + unsigned long dstHeight, /* The destination video height */ + unsigned long doubleBuffer, /* Double Buffer enable flag */ + unsigned long srcAddress0, /* The source of the video buffer 0 to display */ + unsigned long sUAddress, /* U Source Base Address (not used in RGB Space) */ + unsigned long sVAddress, /* V Source Base Address (not used in RGB Space) */ + unsigned long sUVPitch, /* UV plane pitch value in bytes (not used in */ + unsigned long srcPitch, /* The source video plane pitch in bytes */ + unsigned long srcLineOffset, /* The source video plane line offset in bytes. + Set it the same as srcPitch in normal + usage. */ + video_format_t videoFormat, /* Source video format */ + unsigned long edgeDetect, /* Edge Detection enable flag */ + unsigned long edgeDetectValue /* Edge Detection value. SM718 only use bit 9 to 0 */ +); + +/* + * videoSetup + * This function setups the video. + * + * Input: + * x - X Coordinate of the video window + * y - Y Coordinate of the video window + * srcWidth - The source video width + * srcHeight - The source video height + * dstWidth - The destination video width + * dstHeight - The destination video height + * doubleBuffer - Double Buffer enable flag + * srcAddress0 - The source of the video buffer 0 to display + * srcAddress1 - The source of the video buffer 1 to display + * (only for double buffering). + * srcPitch - The source video plane pitch in bytes + * srcLineOffset - The source video plane line offset in bytes. + * In normal usage, set it the same as the srcBufferPitch + * videoFormat - Source video format + * + * Output: + * 0 - Success + * -1 - Fail + */ +unsigned char videoSetup( + disp_control_t dispCtrl, + unsigned long x, /* X Coordinate of the video window */ + unsigned long y, /* Y Coordinate of the video window */ + unsigned long srcWidth, /* The source video width */ + unsigned long srcHeight, /* The source video height */ + unsigned long dstWidth, /* The destination video width */ + unsigned long dstHeight, /* The destination video height */ + unsigned long doubleBuffer, /* Double Buffer enable flag */ + unsigned long srcAddress0, /* The source of the video buffer 0 to display */ + unsigned long srcAddress1, /* The source of the video buffer 1 to display + (only for double buffering). + */ + unsigned long srcPitch, /* The source video plane pitch in bytes */ + unsigned long srcLineOffset, /* The source video plane line offset in bytes. + Set it the same as srcPitch in normal + usage. */ + video_format_t videoFormat /* Source video format */ +); + +/* + * startVideo + * This function starts the video. + */ +void startVideo(unsigned dispCtrl); + +/* + * stopVideo + * This function stops the video. + */ +void stopVideo(unsigned dispCtrl); + +int SM768_setOverlay( + disp_control_t dispControl, /* Channel 0 or Channel 1) */ + PBLIT_BLK src, /* Only need: source Width & Height, Pitch */ + PYUV_BUF_ADDR SrcAddr, /* Y U V source base address */ + PBLIT_BLK dest, /* Needed input value: destination X & Y & Width & Height */ + file_format srcFormat +); + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddkdebug.c b/drivers/gpu/drm/smidrm/ddk768/ddkdebug.c new file mode 100644 index 000000000000..95b807eed509 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddkdebug.c @@ -0,0 +1,227 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* ddkdebug.c --- DDK Debug Tool +* This file contains the source code for the SMI DDK Debugging. +* +*******************************************************************/ +#ifdef DDKDEBUG /* Don't enable debug flag in ARM yet */ +#include +#include +#include +#include "ddkdebug.h" +#include "os.h" + +/* COM Port index that is used for the debugging */ +#define DEBUG_COM_PORT_INDEX 0 + +/* Buffer length */ +#define BUFFER_LENGTH 1024 + +static ddk_debug_output_t gDebugOutput = DEBUG_OUTPUT_SCREEN; +static unsigned long gDebugLevelMask = 0; +static FILE *gFileHandle = (FILE *)0; +static short gCOMInit = 0; +static unsigned char gEnableDebugMessage; + +/* + * This function initializes the debug print out system. + * + * Input: + * debugOutput - Output where to print out the debug. It could be + * screen, file, or serial port. + * debugLevel - Debugging level + */ +void ddkDebugPrintInit(ddk_debug_output_t debugOutput, unsigned long debugLevelMask) +{ + gDebugOutput = debugOutput; + gDebugLevelMask = debugLevelMask; + gEnableDebugMessage = 1; + + /* Initialize the output media as necessary */ + switch (gDebugOutput) + { + default: + case DEBUG_OUTPUT_SCREEN: + /* Do nothing */ + break; + case DEBUG_OUTPUT_FILE: + /* Close the previous log file if opened */ + if (gFileHandle != (FILE *)0) + fclose(gFileHandle); + + /* Create a LOG file */ + gFileHandle = fopen("ddkdebug.log", "w"); + if (gFileHandle == NULL) + ddkDebugPrint(0, "Can not open log file\n"); + break; + case DEBUG_OUTPUT_SERIAL: + /* Open COM Port */ + if (comInit(DEBUG_COM_PORT_INDEX, + COM_9600, + DATA_SIZE_8, + PARITY_NONE, + STOP_BIT_1, + FLOW_CONTROL_NONE) == 0) + gCOMInit = 1; + else + ddkDebugPrint(0, "Can not open COM Port\n"); + break; + } +} + +/* + * This function enable or disable the debug message. + * + * Input: + * enableDebugMessage - Enable/disable the debug message + * 0 - Disable Debug Message + * 1 - Enable Debug Message + * + * Note: + * This function can be used to enable/disable the debug message + * at certain point of software, so that the debug messages, that + * are printed, are only the important ones. + */ +void ddkDebugEnable(unsigned char enableDebugMessage) +{ + gEnableDebugMessage = enableDebugMessage; +} + +/* + * This function prints out the formatted string. + * + * Input: + * debugLevel - The level of the debug of which the message is intended for. + * pszFormat - Format of the printed message + */ +void ddkDebugPrint(unsigned long debugLevel, const char* pszFormat, ...) +{ + static char pszPrintBuffer[BUFFER_LENGTH]; + unsigned long nWritten; + + /* Do not print any messages when this variable is flagged. */ + if (gEnableDebugMessage == 0) + return; + + /* Only process any ddkDebugPrint with the debugLevel less or equal the preset + debug Level during the init */ + if (((debugLevel & gDebugLevelMask) != 0) || (debugLevel == 0)) + { + /* Format the string */ + va_list arg_ptr; + va_start(arg_ptr, pszFormat); + nWritten = (unsigned long) vsnprintf(pszPrintBuffer, BUFFER_LENGTH - 1, pszFormat, arg_ptr); + va_end(arg_ptr); + + /* Check for buffer overflow */ + if (nWritten == (unsigned long)(-1)) + { + ddkDebugPrint(0, "ddkDebugPrint(): BUFFER OVERFLOW DETECTED!!!\r\n" \ + "MAX STRING LENGTH = %d\n", BUFFER_LENGTH); + return; + } + + /* Print out the data */ + switch (gDebugOutput) + { + default: + case DEBUG_OUTPUT_SCREEN: + printk(KERN_DEBUG "%s", pszPrintBuffer); + + /* + * Flush the stdout before the getch function. Otherwise the + * previous printf will not be displayed correctly sometimes. + */ + fflush(stdout); + break; + case DEBUG_OUTPUT_FILE: + /* Print out the message to the log file */ + if (gFileHandle != NULL) + { + fprintf(gFileHandle, pszPrintBuffer); + fflush(gFileHandle); + } + break; + case DEBUG_OUTPUT_SERIAL: + /* Send the data out to the COM Port */ + if (gCOMInit) + { +#if 1 + char *pString1, *pString2; + unsigned long length; + char linefeed = '\r'; + + length = 0; + pString1 = pszPrintBuffer; + while(nWritten) + { + /* Search for all '\n' and add '\r' so that the serial port can display correctly. */ + pString2 = strchr(pString1, '\n'); + if (pString2 != (char *)0) + { + length = pString2 - pString1 + 1; + + /* Check the previous character and the next character */ + if ((*(pString2 - 1) != '\r') && (*(pString2 + 1) != '\r')) + { + /* Write the buffer with the '\r' */ + comWrite(pString1, length); + comWrite(&linefeed, 1); + } + else + comWrite(pString1, length); + + /* Adjust the nWritten */ + nWritten -= length; + + /* Adjust the new string pointer */ + pString1 = pString2 + 1; + } + else + { + comWrite(pString1, nWritten); + nWritten = 0; + } + } +#else + comWrite(pszPrintBuffer, nWritten); +#endif + } + break; + } + } +} + +/* + * This function cleans up (such as closing the debug file, etc...) when + * exiting the debug module. + */ +void ddkDebugPrintExit() +{ + /* Clean up the debug print module */ + switch (gDebugOutput) + { + default: + case DEBUG_OUTPUT_SCREEN: + /* Do nothing */ + break; + case DEBUG_OUTPUT_FILE: + /* Close the log file */ + if (gFileHandle != (FILE *)0) + fclose(gFileHandle); + break; + case DEBUG_OUTPUT_SERIAL: + comClose(); + break; + } +} + +#endif + + + diff --git a/drivers/gpu/drm/smidrm/ddk768/ddkdebug.h b/drivers/gpu/drm/smidrm/ddk768/ddkdebug.h new file mode 100644 index 000000000000..aa1df840174f --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ddkdebug.h @@ -0,0 +1,141 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* ddkdebug.h --- DDK Debug module +* This file contains the definitions for the SMI DDK debugging. +* +*******************************************************************/ +#ifndef _DDKDEBUG_H_ +#define _DDKDEBUG_H_ + +#ifdef DDKDEBUG + +/********************* + * Definition + *********************/ + +/* Debug Print Level definitions */ +/* Bit 16 ~ 31 are used by the library. Bit 0 ~ 15 can be used by application */ +#define ERROR_LEVEL 0x00010000 +#define WARNING_LEVEL 0x00020000 +#define INIT_LEVEL 0x00040000 +#define DISPLAY_LEVEL 0x00080000 +#define DMA_LEVEL 0x00100000 +#define DE_LEVEL 0x00200000 +#define CAPTURE_LEVEL 0x00400000 +#define SSP_LEVEL 0x00800000 +#define RESERVED8_LEVEL 0x01000000 +#define RESERVED9_LEVEL 0x02000000 +#define RESERVED10_LEVEL 0x04000000 +#define RESERVED11_LEVEL 0x08000000 +#define RESERVED12_LEVEL 0x10000000 +#define RESERVED13_LEVEL 0x20000000 +#define RESERVED14_LEVEL 0x40000000 +#define RESERVED15_LEVEL 0x80000000 + +#define SYSTEM_LEVEL_MASK 0xFFFF0000 +#define APPLICATION_LEVEL_MASK 0x0000FFFF + +/********************* + * Structure + *********************/ +typedef enum _ddk_debug_output_t +{ + DEBUG_OUTPUT_SCREEN = 0, + DEBUG_OUTPUT_FILE, + DEBUG_OUTPUT_SERIAL +} +ddk_debug_output_t; + +/********************* + * MACROS + *********************/ + +/* This function has to be called before calling other DEBUGPIRNT functions. */ +#define DDKDEBUGPRINTINIT(debugOutput, debugLevelMask) \ + ddkDebugPrintInit(debugOutput, debugLevelMask) + +/* This function enable or disable the debug message. + * Note: + * This function can be used to enable/disable the debug message + * at certain point of software, so that the debug messages, that + * are printed, are only the important ones. + */ +#define DDKDEBUGENABLE(arg) \ + ddkDebugEnable(arg) + +/* Calling the DDKDEBUGPRINT needs to have the arg to be enclosed with + two of open and close brackets. + Example: + DDKDEBUGPRINT(("Hello World: %s\n", pszString)); + */ +#define DDKDEBUGPRINT(arg) \ + ddkDebugPrint arg + +/* This function has to be called when exiting the application. + It is necessary to clean up the debug module. */ +#define DDKDEBUGPRINTEXIT() \ + ddkDebugPrintExit() + +/********************* + * Function prototype + *********************/ + +/* + * This function initializes the debug print out system. + * + * Input: + * debugOutput - Output where to print out the debug. It could be + * screen, file, or serial port. + * debugLevel - Debugging level + */ +void ddkDebugPrintInit(ddk_debug_output_t debugOutput, unsigned long debugLevelMask); + +/* + * This function enable or disable the debug message. + * + * Input: + * enableDebugMessage - Enable/disable the debug message + * 0 - Disable Debug Message + * 1 - Enable Debug Message + * + * Note: + * This function can be used to enable/disable the debug message + * at certain point of software, so that the debug messages, that + * are printed, are only the important ones. + */ +void ddkDebugEnable(unsigned char enableDebugMessage); + +/* + * This function prints out the formatted string. + * + * Input: + * debugLevel - The level of the debug of which the message is intended for. + * pszFormat - Format of the printed message + */ +void ddkDebugPrint(unsigned long debugLevel, const char* pszFormat, ...); + +/* + * This function cleans up (such as closing the debug file, etc...) when + * exiting the debug module. + */ +void ddkDebugPrintExit(); + +#else + +/* + * If there is no DEBUG definition, then treat the macro as an empty macro. + * Therefore all the debug print will be stripped out. + */ +#define DDKDEBUGPRINTINIT(debugOutput, debugLevelMask) +#define DDKDEBUGENABLE(arg) +#define DDKDEBUGPRINT(arg) +#define DDKDEBUGPRINTEXIT() + +#endif + +#endif /* _DDKDEBUG_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk768/ep952_if.h b/drivers/gpu/drm/smidrm/ddk768/ep952_if.h new file mode 100644 index 000000000000..a0297f106e44 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ep952_if.h @@ -0,0 +1,147 @@ +#ifndef EP952_IF_H +#define EP952_IF_H + +#include "ep952api.h" +#include "ep952regdef.h" + +//================================================================================================== +// +// Protected Data Member +// + +typedef enum { + COLORSPACE_601 = 1, + COLORSPACE_709 +} COLORSPACE; + +typedef enum { + SYNCMODE_HVDE = 0, + SYNCMODE_HV, + SYNCMODE_Embeded +} SYNCMODE; + +typedef enum { + COLORFORMAT_RGB = 0, + COLORFORMAT_YCC444, + COLORFORMAT_YCC422 +} COLORFORMAT; + +typedef enum { + AFAR_VideoCode = 0, + AFAR_4_3, + AFAR_16_9, + AFAR_14_9 +} AFAR; + +typedef enum { + SCAN_NoData = 0, + SCAN_OverScan, + SCAN_UnderScan, + SCAN_Future +} SCAN_MODE; + + +// Video Output Congif Params +typedef struct _VDO_PARAMS { +// Which cause Timing Change Reset + unsigned char Interface; // DK[3:1], DKEN, DSEL, BSEL, EDGE, FMT12 + unsigned char VideoSettingIndex; // VIC + unsigned char HVPol; // x, x, x, x, VSO_POL, HSO_POL, x, x + SYNCMODE SyncMode; // 0 = HVDE, 1 = HV(DE Gen), 2 = Embedded Sync + COLORFORMAT FormatIn; // 0 = RGB, 1 = YCC444, 2 = YCC422 + COLORFORMAT FormatOut; // 0 = RGB, 1 = YCC444, 2 = YCC422 +// Which don't cause Timing Chage Reset + COLORSPACE ColorSpace; // 0 = Auto, 1 = 601, 2 = 709 + AFAR AFARate; // 0 = Auto, 1 = 4:3, 2 = 16:9, 3 = 14:9 + SCAN_MODE SCAN; // 0 = no data, 1 = overscan, 2 = underscan, 3 = future +} VDO_PARAMS, *PVDO_PARAMS; + +typedef enum { + ADSFREQ_32000Hz = 0x03, + ADSFREQ_44100Hz = 0x00, + ADSFREQ_48000Hz = 0x02, + ADSFREQ_88200Hz = 0x08, + ADSFREQ_96000Hz = 0x0A, + ADSFREQ_176400Hz = 0x0C, + ADSFREQ_192000Hz = 0x0E +} ADSFREQ; + +// Audio Output Congif Params +typedef struct _ADO_PARAMS { + unsigned char Interface; // x, x, x, x, IIS, WS_M, WS_POL, SCK_POL + unsigned char VideoSettingIndex; // VIC + unsigned char ChannelNumber; // 1 = 2 ch, 2 = 3 ch, ... , 5 = 5.1 ch, 7 = 7.1 ch + unsigned char ADSRate; // 1 = SF/2, 2 = SF/3, 3 = SF/4 (Down Sample) + ADSFREQ InputFrequency; // ADSFREQ + unsigned char VFS; // 0 = 59.94Hz, 1 = 60Hz (Vertical Frequency Shift of Video) + unsigned char NoCopyRight; +} ADO_PARAMS, *PADO_PARAMS; + +//================================================================================================== +// +// Public Functions +// + +//-------------------------------------------------------------------------------------------------- +// +// General +// + +// All Interface Inital +extern void EP952_IIC_Initial(void); +extern void EP952_Info_Reset(void); + + +//-------------------------------------------------------------------------------------------------- +// +// HDMI Transmiter Interface +// + +// Common +extern void HDMI_Tx_Power_Down(void); +extern void HDMI_Tx_Power_Up(void); +extern void HDMI_Tx_HDMI(void); +extern void HDMI_Tx_DVI(void); +extern unsigned char HDMI_Tx_HTPLG(void); +extern unsigned char HDMI_Tx_RSEN(void); + +// HDCP +extern void HDMI_Tx_Mute_Enable(void); +extern void HDMI_Tx_Mute_Disable(void); +extern void HDMI_Tx_HDCP_Enable(void); +extern void HDMI_Tx_HDCP_Disable(void); +extern void HDMI_Tx_RPTR_Set(void); +extern void HDMI_Tx_RPTR_Clear(void); +extern unsigned char HDMI_Tx_RI_RDY(void); +extern void HDMI_Tx_write_AN(unsigned char *pAN); +extern unsigned char HDMI_Tx_AKSV_RDY(void); +extern unsigned char HDMI_Tx_read_AKSV(unsigned char *pAKSV); +extern void HDMI_Tx_write_BKSV(unsigned char *pBKSV); +extern unsigned char HDMI_Tx_read_RI(unsigned char *pRI); +extern void HDMI_Tx_read_M0(unsigned char *pM0); +extern SMBUS_STATUS HDMI_Tx_Get_Key(unsigned char *Key); + +// Special for EP952E +extern void HDMI_Tx_AMute_Enable(void); +extern void HDMI_Tx_AMute_Disable(void); +extern void HDMI_Tx_VMute_Enable(void); +extern void HDMI_Tx_VMute_Disable(void); +extern void HDMI_Tx_Video_Config(PVDO_PARAMS Params); +extern void HDMI_Tx_Audio_Config(PADO_PARAMS Params); + + +//-------------------------------------------------------------------------------------------------- +// +// Hardware Interface +// + +// EP952 +extern unsigned char EP952_Reg_Read(unsigned char ByteAddr, unsigned char *Data, unsigned int Size); +extern unsigned char EP952_Reg_Write(unsigned char ByteAddr, unsigned char *Data, unsigned int Size); +extern unsigned char EP952_Reg_Set_Bit(unsigned char ByteAddr, unsigned char BitMask); +extern unsigned char EP952_Reg_Clear_Bit(unsigned char ByteAddr, unsigned char BitMask); + + +#endif // EP952_IF_H + + diff --git a/drivers/gpu/drm/smidrm/ddk768/ep952api.h b/drivers/gpu/drm/smidrm/ddk768/ep952api.h new file mode 100644 index 000000000000..6730baa33d99 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ep952api.h @@ -0,0 +1,113 @@ +#ifndef EP952_API_H +#define EP952_API_H + +//#include + + +// HDCP enable define //////////////// + +#define Enable_HDCP 0 + +////////////////////////////////////// + + +// Debug define ////////////////////// + +#define DBG_printf(x) printf x // enable DBG message +//#define DBG_printf(x) // disable DBG message + +////////////////////////////////////// + +// ----------------------------------------------------------------------------- + +typedef enum { + // Master + SMBUS_STATUS_Success = 0x00, + SMBUS_STATUS_Pending,// SMBUS_STATUS_Abort, + SMBUS_STATUS_NoAct = 0x02, + SMBUS_STATUS_TimeOut, + SMBUS_STATUS_ArbitrationLoss = 0x04, +} SMBUS_STATUS; + + +/*typedef enum { + AUD_I2S = 0, + AUD_SPDIF +}HDMI_AudFmt_t;*/ + +typedef enum { + AUD_None = 0, + AUD_SF_32000Hz = 1, + AUD_SF_44100Hz, + AUD_SF_48000Hz, + //AUD_SF_88200Hz, + //AUD_SF_96000Hz, + //AUD_SF_176400Hz, + //AUD_SF_192000Hz + +}HDMI_AudFreq; + +//-------------------------------------------------------------------------------------------------- +// BitMask Value +#define EP_TX_System_Status__KEY_FAIL 0x02 +#define EP_TX_System_Configuration__HDCP_DIS 0x20 + +#define EP_TX_Video_Interface_Setting_0__DKEN_Disable 0x80 // Disable De-skew +#define EP_TX_Video_Interface_Setting_0__DKEN_M_4_Step 0x10 // -4 step +#define EP_TX_Video_Interface_Setting_0__DKEN_M_3_Step 0x30 // -3 step +#define EP_TX_Video_Interface_Setting_0__DKEN_M_2_Step 0x50 // -2 step +#define EP_TX_Video_Interface_Setting_0__DKEN_M_1_Step 0x70 // -1 step +#define EP_TX_Video_Interface_Setting_0__DKEN_M_0_Step 0x90 // 0 step +#define EP_TX_Video_Interface_Setting_0__DKEN_P_1_Step 0xB0 // +1 step +#define EP_TX_Video_Interface_Setting_0__DKEN_P_2_Step 0xD0 // +2 step +#define EP_TX_Video_Interface_Setting_0__DKEN_P_3_Step 0xF0 // +3 step + +#define EP_TX_Video_Interface_Setting_0__DSEL 0x08 +#define EP_TX_Video_Interface_Setting_0__BSEL 0x04 +#define EP_TX_Video_Interface_Setting_0__EDGE 0x02 +#define EP_TX_Video_Interface_Setting_0__FMT12 0x01 + +#define EP_TX_Video_Interface_Setting_1__SYNC 0x0C +#define EP_TX_Video_Interface_Setting_1__SYNC__HVDE 0x00 +#define EP_TX_Video_Interface_Setting_1__SYNC__HV 0x04 +#define EP_TX_Video_Interface_Setting_1__SYNC__Embeded 0x08 + +#define EP_TX_Video_Interface_Setting_1__VIN_FMT 0x03 +#define EP_TX_Video_Interface_Setting_1__VIN_FMT__RGB 0x00 +#define EP_TX_Video_Interface_Setting_1__VIN_FMT__YCC444 0x01 +#define EP_TX_Video_Interface_Setting_1__VIN_FMT__YCC422 0x02 + +#define EP_TX_Audio_Input_Format__ADO_FREQ 0x07 +#define EP_TX_Audio_Input_Format__ADO_FREQ__None 0x00 +#define EP_TX_Audio_Input_Format__ADO_FREQ__32000Hz 0x01 +#define EP_TX_Audio_Input_Format__ADO_FREQ__44100Hz 0x02 +#define EP_TX_Audio_Input_Format__ADO_FREQ__48000Hz 0x03 +#define EP_TX_Audio_Input_Format__ADO_FREQ__88200Hz 0x04 +#define EP_TX_Audio_Input_Format__ADO_FREQ__96000Hz 0x05 +#define EP_TX_Audio_Input_Format__ADO_FREQ__176400Hz 0x06 +#define EP_TX_Audio_Input_Format__ADO_FREQ__192000Hz 0x07 + +// ----------------------------------------------------------------------------- + +#ifndef min +#define min(a,b) (((a)<(b))? (a):(b)) +#endif + +#ifndef max +#define max(a,b) (((a)>(b))? (a):(b)) +#endif + +//-------------------------------------------------------------------------------------------------- +void EP_EP952_Reset(void); +//void EP_HDMI_Set_Audio_Fmt(HDMI_AudFmt_t Audfmt, HDMI_AudFreq Audfreq); +void EP_HDMI_Set_Video_Timing(unsigned int isHDMI,unsigned int dsel); //(logicalMode_t *pLogicalMode, unsigned int isHDMI); +void EP_HDMI_Init(int chipID); +void EP_Register_Init(void); +int EP952_HDMI_Set_Mode (logicalMode_t *pLogicalMode); +void EP952_Register_Message(void); + + + + +//-------------------------------------------------------------------------------------------------- +#endif diff --git a/drivers/gpu/drm/smidrm/ddk768/ep952controller.h b/drivers/gpu/drm/smidrm/ddk768/ep952controller.h new file mode 100644 index 000000000000..6d6707e71866 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ep952controller.h @@ -0,0 +1,82 @@ +#ifndef EP952CONTROLLER_H +#define EP952CONTROLLER_H + +#include "ep952_if.h" +#include "ep952api.h" + + + +#define VERSION_MAJOR 52 +#define VERSION_MINOR 1 + +#define INT_enable 1 +#define INT_disable 0 +#define INT_OPEN_DRAIN 1 +#define INT_PUSH_PULL 0 +#define INT_High 1 +#define INT_Low 0 + +typedef enum { + TXS_Search_EDID, + TXS_Wait_Upstream, + TXS_Stream, + TXS_HDCP +} TX_STATE; + +typedef struct _EP952C_REGISTER_MAP { + + unsigned char System_Status; + +#if Enable_HDCP + unsigned char HDCP_Status; + unsigned char HDCP_State; + unsigned char HDCP_AKSV[5]; + unsigned char HDCP_BKSV[5]; + unsigned char HDCP_BCAPS3[3]; + unsigned char HDCP_KSV_FIFO[5*16]; + unsigned char HDCP_SHA[20]; + unsigned char HDCP_M0[8]; +#endif + + unsigned char Readed_EDID[256]; + unsigned char EDID_ASFreq; + unsigned char EDID_AChannel; + //unsigned char EDID_VideoDataAddr; + //unsigned char EDID_AudioDataAddr; + //unsigned char EDID_SpeakerDataAddr; + //unsigned char EDID_VendorDataAddr; + + unsigned char System_Configuration; + + unsigned char Video_Interface[2]; // + unsigned char Video_Input_Format[2]; // + unsigned char Video_Output_Format; // + + unsigned char Audio_Interface; // + unsigned char Audio_Input_Format; // + + unsigned char Video_change; + unsigned char Audio_change; + +} EP952C_REGISTER_MAP, *PEP952C_REGISTER_MAP; + +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- + +typedef void (*EP952C_CALLBACK)(void); + +void EP952Controller_Initial(PEP952C_REGISTER_MAP pEP952C_RegMap); + +void EP952Controller_Task(void); + +void EP952Controller_Timer(void); + +void EP952_Audio_reg_set(void); +void EP952_Video_reg_set(void); + +void EP952_EXTINT_init(unsigned char INT_Enable, unsigned char INT_OD, unsigned char INT_POL); +void EP_HDMI_DumpMessage(void); + +// ----------------------------------------------------------------------------- +#endif + diff --git a/drivers/gpu/drm/smidrm/ddk768/ep952regdef.h b/drivers/gpu/drm/smidrm/ddk768/ep952regdef.h new file mode 100644 index 000000000000..742c804fb138 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ep952regdef.h @@ -0,0 +1,159 @@ +#ifndef EP952REGDEF_H +#define EP952REGDEF_H + +// Registers Word BitMask + +#define EP952_TX_PHY_Control_0 0x00 +#define EP952_TX_PHY_Control_0__TERM_ON 0x80 +#define EP952_TX_PHY_Control_0__DSWING 0x30 + +#define EP952_TX_PHY_Control_1 0x01 +#define EP952_TX_PHY_Control_1__SCLK_DLY 0x80 +#define EP952_TX_PHY_Control_1__TPHY_RST 0x40 +#define EP952_TX_PHY_Control_1__RESN_DIS 0x20 +#define EP952_TX_PHY_Control_1__VCO_GAIN 0x0C +#define EP952_TX_PHY_Control_1__PHD_CUR 0x03 + +#define EP952_TX_EE_SUM 0x02 + +#define EP952_General_Control_8 0x05 +#define EP952_General_Control_8__ADO_SPDIF_IN 0x00 +#define EP952_General_Control_8__ADO_IIS_IN 0x10 +#define EP952_General_Control_8__COMR_DIS 0x04 + +#define EP952_SMPRD 0x06 // 2 Byte + +#define EP952_General_Control_1 0x08 +#define EP952_General_Control_1__TSEL_HTP 0x80 +#define EP952_General_Control_1__INT_OD 0x40 +#define EP952_General_Control_1__INT_POL 0x20 +#define EP952_General_Control_1__OSC_PD 0x10 +#define EP952_General_Control_1__DSEL 0x08 +#define EP952_General_Control_1__BSEL 0x04 +#define EP952_General_Control_1__EDGE 0x02 +#define EP952_General_Control_1__PU 0x01 + +#define EP952_General_Control_2 0x09 +#define EP952_General_Control_2__RSEN 0x80 +#define EP952_General_Control_2__HTPLG 0x40 +#define EP952_General_Control_2__PIFE 0x08 +#define EP952_General_Control_2__RIFE 0x04 +#define EP952_General_Control_2__VIFE 0x02 +#define EP952_General_Control_2__MIFE 0x01 + +#define EP952_General_Control_3 0x0A + +#define EP952_Configuration 0x0B + +#define EP952_Color_Space_Control 0x0C +#define EP952_Color_Space_Control__422_OUT 0x80 +#define EP952_Color_Space_Control__YCC_OUT 0x40 +#define EP952_Color_Space_Control__COLOR 0x20 +#define EP952_Color_Space_Control__YCC_Range 0x10 +#define EP952_Color_Space_Control__VMUTE 0x08 +#define EP952_Color_Space_Control__AMUTE 0x04 +#define EP952_Color_Space_Control__AVMUTE 0x02 + +#define EP952_Pixel_Repetition_Control 0x0D +#define EP952_Pixel_Repetition_Control__CS_M 0x80 +#define EP952_Pixel_Repetition_Control__CTS_M 0x40 +#define EP952_Pixel_Repetition_Control__ADSR 0x30 +#define EP952_Pixel_Repetition_Control__VSYNC 0x04 +#define EP952_Pixel_Repetition_Control__PR 0x03 + +#define EP952_General_Control_4 0x0E +#define EP952_General_Control_4__FMT12 0x80 +#define EP952_General_Control_4__422_IN 0x40 +#define EP952_General_Control_4__YCC_IN 0x20 +#define EP952_General_Control_4__E_SYNC 0x10 +#define EP952_General_Control_4__VPOL_DET 0x08 +#define EP952_General_Control_4__HPOL_DET 0x04 +#define EP952_General_Control_4__EESS 0x02 +#define EP952_General_Control_4__HDMI 0x01 + +#define EP952_General_Control_5 0x0F +#define EP952_General_Control_5__AKSV_RDY 0x80 +#define EP952_General_Control_5__RPTR 0x10 +#define EP952_General_Control_5__RI_RDY 0x02 +#define EP952_General_Control_5__ENC_EN 0x01 + +#define EP952_BKSV 0x10 // BKSV1-BKSV5 0x10-0x14 + +#define EP952_AN 0x15 // AN1-AN8 0x15-0x1C + +#define EP952_AKSV 0x1D // AKSV1-AKSV5 0x1D-0x21 + +#define EP952_RI 0x22 // RI1-RI2 0x22-0x23 + +#define EP952_M0 0x25 // 0x25-0x32 + +#define EP952_DE_DLY 0x32 // 10 bit + +#define EP952_DE_Control 0x33 // 10 bit +#define EP952_DE_Control__DE_GEN 0x40 +#define EP952_DE_Control__VSO_POL 0x08 +#define EP952_DE_Control__HSO_POL 0x04 + +#define EP952_DE_TOP 0x34 // 6 bit + +#define EP952_DE_CNT 0x36 // 10 bit + +#define EP952_DE_LIN 0x38 // 10 bit + +#define EP952_H_RES 0x3A // 11 bit + +#define EP952_V_RES 0x3C // 11 bit + +#define EP952_Audio_Subpacket_Allocation 0x3E // Default 0xE4 + +#define EP952_IIS_Control 0x3F // Default 0x00 +#define EP952_IIS_Control__ACR_EN 0x80 +#define EP952_IIS_Control__AVI_EN 0x40 +#define EP952_IIS_Control__ADO_EN 0x20 +#define EP952_IIS_Control__GC_EN 0x10 +#define EP952_IIS_Control__AUDIO_EN 0x08 +#define EP952_IIS_Control__WS_M 0x04 +#define EP952_IIS_Control__WS_POL 0x02 +#define EP952_IIS_Control__SCK_POL 0x01 + +#define EP952_Packet_Control 0x40 // Default 0x00 +#define EP952_Packet_Control__FLAT 0x10 +#define EP952_Packet_Control__VTX0 0x08 +#define EP952_Packet_Control__PKT_RDY 0x01 + +#define EP952_Data_Packet_Header 0x41 // HB0-HB2 0x41-0x43 +#define EP952_Data_Packet 0x44 // PB0-PB27 0x44-0x5F + +#define EP952_CTS_H 0x60 // 20bit (3 Byte) +#define EP952_CTS_M 0x61 // 20bit (3 Byte) +#define EP952_CTS_L 0x62 // 20bit (3 Byte) + +#define EP952_N_H 0x63 // 20bit (3 Byte) +#define EP952_N_M 0x64 // 20bit (3 Byte) +#define EP952_N_L 0x65 // 20bit (3 Byte) + +#define EP952_AVI_Packet 0x66 // 14 Byte 0x66-0x73 + +#define EP952_ADO_Packet 0x74 // 6 Byte 0x74-0x79 + +#define EP952_SPDIF_Sampling_Frequency 0x7A // 1 Byte + +#define EP952_Channel_Status 0x7B // 5 Byte 0x7B-0x7F + +#define EP952_Embedded_Sync_Control 0x80 // Default 0x00 + +#define EP952_H_Delay 0x81 // 10 bit (2 Byte) + +#define EP952_H_Width 0x83 // 10 bit (2 Byte) + +#define EP952_V_Delay 0x85 // 6 bit + +#define EP952_V_Width 0x86 // 6 bit + +#define EP952_V_Off_Set 0x87 // 12 bit (2 Byte) + +#define EP952_Key_Add 0xF0 // 1 Byte + +#define EP952_Key_Data 0xF1 // 7 Byte + +#endif diff --git a/drivers/gpu/drm/smidrm/ddk768/ep952settingsdata.h b/drivers/gpu/drm/smidrm/ddk768/ep952settingsdata.h new file mode 100644 index 000000000000..43a24d9c4b31 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/ep952settingsdata.h @@ -0,0 +1,101 @@ +#ifndef EP952SETTINGDATA_H +#define EP952SETTINGDATA_H + +// ----------------------------------------------------------------------------- + +#define EP952_VDO_Settings_IT_Start 76 + +// Definition of H/V Polarity +#define VPosHPos 0x00 +#define VPosHNeg 0x04 +#define VNegHPos 0x08 +#define VNegHNeg 0x0C + +// Pixel Freq Type +typedef enum { + PIX_FREQ_25175KHz = 0, + PIX_FREQ_25200KHz, + + PIX_FREQ_27000KHz, + PIX_FREQ_27027KHz, + + PIX_FREQ_54000KHz, + PIX_FREQ_54054KHz, + + PIX_FREQ_72000KHz, + + PIX_FREQ_74176KHz, + PIX_FREQ_74250KHz, + + PIX_FREQ_108000KHz, + PIX_FREQ_108108KHz, + + PIX_FREQ_148352KHz, + PIX_FREQ_148500KHz, + + PIX_FREQ_PC + +} PIX_FREQ_TYPE; + +// +// Index = [Video Code] +// +typedef struct _HVRES_TYPE { + unsigned char HVPol; + unsigned short Hres; + unsigned short Vres; + unsigned short Vprd; +} HVRES_TYPE, *PHVRES_TYPE; + +// DE Generation +typedef struct _DE_GEN_SETTINGS { + unsigned short DE_DLY; + unsigned short DE_CNT; + unsigned char DE_TOP; + unsigned short DE_LIN; +} DE_GEN_SETTINGS, *PDE_GEN_SETTINGS; + +// Embeded Sybc +typedef struct _E_SYNC_SETTINGS { + unsigned char CTL; + unsigned short H_DLY; + unsigned short H_WIDTH; + unsigned char V_DLY; + unsigned char V_WIDTH; + unsigned short V_OFST; +} E_SYNC_SETTINGS, *PE_SYNC_SETTINGS; + +// AVI Settings +typedef struct _VDO_SETTINGS { + unsigned char VideoCode; + HVRES_TYPE HVRes_Type; + DE_GEN_SETTINGS DE_Gen; + E_SYNC_SETTINGS E_Sync; // (HV_Gen) + unsigned char AR_PR; + PIX_FREQ_TYPE Pix_Freq_Type; +} VDO_SETTINGS, *PVDO_SETTINGS; + +// Index = [Channel Number] +// Audio Channel and Allocation +typedef struct _ADO_SETTINGS { + unsigned char SpeakerMapping; + unsigned char Flat; +} ADO_SETTINGS, *PADO_SETTINGS; + +// Index = [Pixel Freq Type] +// N and CTS +typedef struct _N_CTS_SETTINGS { + unsigned long N; + unsigned long CTS; // Use hardware to calculate the CTS +} N_CTS_SETTINGS, *PN_CTS_SETTINGS; + + +extern unsigned char EP952_VDO_Settings_Max; +extern VDO_SETTINGS EP952_VDO_Settings[]; +extern ADO_SETTINGS EP952_ADO_Settings[]; +extern N_CTS_SETTINGS N_CTS_32K[]; +extern N_CTS_SETTINGS N_CTS_44K1[]; +extern N_CTS_SETTINGS N_CTS_48K[]; + + +#endif diff --git a/drivers/gpu/drm/smidrm/ddk768/hdmiregs.h b/drivers/gpu/drm/smidrm/ddk768/hdmiregs.h new file mode 100644 index 000000000000..e158d82f5e86 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/hdmiregs.h @@ -0,0 +1,945 @@ +#ifndef _HDMIREGS_H_ +#define _HDMIREGS_H_ + +// SLI-204-06012 Rev.2.01a +//----------------------------------------------------------------------------- +// SLISHDMI13T Regsiter Defines Addr RW init Description +//----------------------------------------------------------------------------- +#define X00_SYSTEM_CONTROL 0 // RW 10h Power save and interrupt output control + #define X00_SYSTEM_CONTROL_MODE 7:4 + #define X00_SYSTEM_CONTROL_MODE_A 1 + #define X00_SYSTEM_CONTROL_MODE_B 2 + #define X00_SYSTEM_CONTROL_MODE_D 4 + #define X00_SYSTEM_CONTROL_MODE_E 8 + #define X00_SYSTEM_CONTROL_PLLB 3:3 + #define X00_SYSTEM_CONTROL_PLLB_RST 1 + #define X00_SYSTEM_CONTROL_PLLB_UNRST 0 + #define X00_SYSTEM_CONTROL_INTOUT 1:1 + #define X00_SYSTEM_CONTROL_INTOUT_N 0 //Interrupt output mode + #define X00_SYSTEM_CONTROL_INTOUT_PP 1 //Interrupt output mode + #define X00_SYSTEM_CONTROL_INTOUT_POLARITY 0:0 + #define X00_SYSTEM_CONTROL_INTOUT_POLARITY_L 0 //Interrupt output polarity + #define X00_SYSTEM_CONTROL_INTOUT_POLARITY_H 1 //Interrupt output polarity + +#define X01_N19_16 1 // RW 00h 20-bit N used for cycle time stamp + #define X01_N19_16_LRC_SWAP 7:4 + #define X01_N19_16_LRC_SWAP_NO 0 //L/R data swap + #define X01_N19_16_LRC_SWAP_SP1 2 + #define X01_N19_16_LRC_SWAP_SP2 4 + #define X01_N19_16_LRC_SWAP_SP3 8 + #define X01_N19_16_AUDCLK 3:0 +#define X02_N15_8 2 // RW 00h +#define X03_N7_0 3 // RW 00h +#define X04_SPDIF_FS 4 // RO 00h SPDIF sampling frequency/CTS[19:16] internal + #define X04_SPDIF_FS_K 7:4 + #define X04_SPDIF_FS_K32 3 + #define X04_SPDIF_FS_K44_1 0 + #define X04_SPDIF_FS_K48 2 + #define X04_SPDIF_FS_K88_2 8 + #define X04_SPDIF_FS_K96 10 + #define X04_SPDIF_FS_K176_4 12 + #define X04_SPDIF_FS_K192 14 + #define X04_SPDIF_FS_CTSIN_19_16 3:0 + +#define X05_CTS_INT 5 // RO 00h CTS[15:8] internal +#define X06_CTS_INT 6 // RO 00h CTS[7:0] internal +#define X07_CTS_EXT 7 // RW 00h CTS[19:16] external +#define X08_CTS_EXT 8 // RW 00h CTS[15:8] external +#define X09_CTS_EXT 9 // RW 00h CTS[7:0] external +#define X0A_AUDIO_SOURCE 10 // RW 00h Audio setting.1 + #define X0A_AUDIO_SOURCE_CTS 7:7 + #define X0A_AUDIO_SOURCE_CTS_INTERNAL 0 + #define X0A_AUDIO_SOURCE_CTS_EXTERNAL 1 + #define X0A_AUDIO_SOURCE_DS 6:5 + #define X0A_AUDIO_SOURCE_DS_NONE 0 + #define X0A_AUDIO_SOURCE_DS_2 1 + #define X0A_AUDIO_SOURCE_DS_4 2 + #define X0A_AUDIO_SOURCE_SEL 4:3 + #define X0A_AUDIO_SOURCE_SEL_I2S 0 + #define X0A_AUDIO_SOURCE_SEL_SPDIF 1 + #define X0A_AUDIO_SOURCE_SEL_DSD 2 + #define X0A_AUDIO_SOURCE_SEL_HBR 3 + #define X0A_AUDIO_SOURCE_MCLK 2:2 + #define X0A_AUDIO_SOURCE_MCLK_OFF 0 + #define X0A_AUDIO_SOURCE_MCLK_ON 1 + #define X0A_AUDIO_SOURCE_MRATIO 1:0 + #define X0A_AUDIO_SOURCE_MRATIO_128FS 0 + #define X0A_AUDIO_SOURCE_MRATIO_256FS 1 + #define X0A_AUDIO_SOURCE_MRATIO_384FS 2 + #define X0A_AUDIO_SOURCE_MRATIO_512FS 3 + +#define X0B_AUDIO_SET2 11 // RW 00h Audio setting.2 + #define X0B_AUDIO_SET2_IDCLK 7:7 + #define X0B_AUDIO_SET2_IDCLK1 0 //BIT.7 + #define X0B_AUDIO_SET2_IDCLK1_2 1 //BIT.7 + #define X0B_AUDIO_SET2_PRI 6:6 + #define X0B_AUDIO_SET2_PRI_ASP 0 + #define X0B_AUDIO_SET2_PRI_ACR 1 + #define X0B_AUDIO_SET2_IDCLK_MODE 5:5 + #define X0B_AUDIO_SET2_IDCLK_MODE_AUTO 0 //BIT.5 + #define X0B_AUDIO_SET2_IDCLK_MODE_FIX 1 //BIT.5 + #define X0B_AUDIO_SET2_FLATLINE 4:4 + #define X0B_AUDIO_SET2_FLATLINE_NORMAL 0 + #define X0B_AUDIO_SET2_FLATLINE_FLAT 1 + #define X0B_AUDIO_SET2_CHANNEL 3:0 //NOT ALL LIST + #define X0B_AUDIO_SET2_CHANNEL_NOT 0 + #define X0B_AUDIO_SET2_CHANNEL_LEFT 8 + #define X0B_AUDIO_SET2_CHANNEL_RIGHT 4 + +#define X0C_I2S_MODE 12 // RW 00h I2S audio setting + #define X0C_I2S_MODE_MCLKFQ 7:7 + #define X0C_I2S_MODE_MCLKFQ_BY0AH 0 + #define X0C_I2S_MODE_MCLKFQ_OVERRIDE 1 + #define X0C_I2S_MODE_CHANNEL 5:2 + #define X0C_I2S_MODE_CHANNEL_2 1 + #define X0C_I2S_MODE_CHANNEL_4 3 + #define X0C_I2S_MODE_CHANNEL_6 7 + #define X0C_I2S_MODE_CHANNEL_8 15 + #define X0C_I2S_MODE_SEL 1:0 + #define X0C_I2S_MODE_SEL_STANDARD 0 + #define X0C_I2S_MODE_SEL_JSTF_RIGHT 1 + #define X0C_I2S_MODE_SEL_JSTF_LEFT 2 + +#define X0D_DSD_MODE 13 // RW 00h DSD audio setting + #define X0D_DSD_MODE_CHANNEL 7:4 + #define X0D_DSD_MODE_CHANNEL_2 1 + #define X0D_DSD_MODE_CHANNEL_4 3 + #define X0D_DSD_MODE_CHANNEL_6 7 + #define X0D_DSD_MODE_CHANNEL_8 0XF + +#define X0E_DEBUG_MONITOR1 14 // RO 00h Reserved +#define X0F_DEBUG_MONITOR2 15 // RO 00h Reserved +#define X10_I2S_PINMODE 16 // RW 00h I2S input pin swap + +#define X11_ASTATUS1 17 // RW 00h Audio status bits setting1 + #define X11_ASTATUS1_VALID 7:7 + #define X11_ASTATUS1_FREQ 3:0 + #define X11_ASTATUS1_FREQ_44_1K 15 + #define X11_ASTATUS1_FREQ_88_2K 7 + #define X11_ASTATUS1_FREQ_22_05K 11 + #define X11_ASTATUS1_FREQ_176_4K 3 + #define X11_ASTATUS1_FREQ_48K 13 + #define X11_ASTATUS1_FREQ_96K 5 + #define X11_ASTATUS1_FREQ_24K 9 + #define X11_ASTATUS1_FREQ_192K 1 + #define X11_ASTATUS1_FREQ_8K 6 + #define X11_ASTATUS1_FREQ_11_025K 10 + #define X11_ASTATUS1_FREQ_12K 2 + #define X11_ASTATUS1_FREQ_32K 12 + #define X11_ASTATUS1_FREQ_16K 8 + #define X11_ASTATUS1_FREQ_DEFAUT 0 +#define X12_ASTATUS2 18 // RW 00h Audio status bits setting2 + #define X12_ASTATUS2_CS1 7:7 + #define X12_ASTATUS2_CS1_LPCM 0 + #define X12_ASTATUS2_CS1_NONLPCM 1 + #define X12_ASTATUS2_CS0 6:6 + #define X12_ASTATUS2_CS0_CONSUMER 0 + #define X12_ASTATUS2_CS0_PROFESSIONAL 1 + #define X12_ASTATUS2_COPYRIGHT 5:5 + #define X12_ASTATUS2_ADDITION 4:2 + #define X12_ASTATUS2_ADDITION_PREM_NO 0 + #define X12_ASTATUS2_ADDITION_PREM_50US 1 + #define X12_ASTATUS2_CLKLEVEL 1:0 + #define X12_ASTATUS2_CLKLEVEL_II 0 + #define X12_ASTATUS2_CLKLEVEL_I 1 + #define X12_ASTATUS2_CLKLEVEL_III 2 + +#define X13_CAT_CODE 19 // RW 00h Category code +#define X14_A_SOURCE 20 // RW 00h Source number/ Audio word length +#define X14_A_SOURCE_NUM 7:4 + #define X14_A_SOURCE_NUM_NOCOUNT 0 + #define X14_A_SOURCE_NUM_1 1 + #define X14_A_SOURCE_NUM_2 2 + #define X14_A_SOURCE_NUM_3 3 + #define X14_A_SOURCE_NUM_4 4 + #define X14_A_SOURCE_NUM_5 5 + #define X14_A_SOURCE_NUM_6 6 + #define X14_A_SOURCE_NUM_7 7 + #define X14_A_SOURCE_NUM_8 8 + #define X14_A_SOURCE_NUM_9 9 + #define X14_A_SOURCE_NUM_10 10 + #define X14_A_SOURCE_NUM_11 11 + #define X14_A_SOURCE_NUM_12 12 + #define X14_A_SOURCE_NUM_13 13 + #define X14_A_SOURCE_NUM_14 14 + #define X14_A_SOURCE_NUM_15 15 + #define X14_A_SOURCE_LENGTH 3:0 + #define X14_A_SOURCE_LENGTH_16B 2 + #define X14_A_SOURCE_LENGTH_17B 12 + #define X14_A_SOURCE_LENGTH_18B 4 + #define X14_A_SOURCE_LENGTH_19B 8 + #define X14_A_SOURCE_LENGTH_20B 10 + #define X14_A_SOURCE_LENGTH_20BIT 3 + #define X14_A_SOURCE_LENGTH_21B 13 + #define X14_A_SOURCE_LENGTH_22B 5 + #define X14_A_SOURCE_LENGTH_23B 9 + #define X14_A_SOURCE_LENGTH_24B 11 + +#define X15_AVSET1 21 // RW 00h Audio/Video setting.1 + #define X15_AVSET1_AUDFREQ 7:4 + #define X15_AVSET1_AUDFREQ_32K 3 + #define X15_AVSET1_AUDFREQ_44_1K 0 + #define X15_AVSET1_AUDFREQ_48K 2 + #define X15_AVSET1_AUDFREQ_88_2K 8 + #define X15_AVSET1_AUDFREQ_96K 10 + #define X15_AVSET1_AUDFREQ_176_4K 12 + #define X15_AVSET1_AUDFREQ_192K 14 + #define X15_AVSET1_AUDFREQ_768K 9 + #define X15_AVSET1_VIDFORM 3:1 + #define X15_AVSET1_VIDFORM_RGB_YCC444 0 + #define X15_AVSET1_VIDFORM_YCC422 1 + #define X15_AVSET1_VIDFORM_YCC422_SAVEAV 2 + #define X15_AVSET1_VIDFORM_SEPA_SYNCS 3 + #define X15_AVSET1_VIDFORM_EMBED_SYNCS 4 + #define X15_AVSET1_VIDFORM_RGB444_YCC444 5 + #define X15_AVSET1_VIDFORM_DDR_YCC422 6 + #define X15_AVSET1_DE 0:0 + #define X15_AVSET1_DE_INTERNAL 0 + #define X15_AVSET1_DE_EXTERNAL 1 + +#define X16_VIDEO1 22 // RW 34h Video setting.1 + #define X16_VIDEO1_OUT 7:6 + #define X16_VIDEO1_OUT_RGB444 0 + #define X16_VIDEO1_OUT_YCC444 1 + #define X16_VIDEO1_OUT_YCC422 2 + #define X16_VIDEO1_IN 5:4 + #define X16_VIDEO1_IN_WID_12 0 + #define X16_VIDEO1_IN_WID_10 1 + #define X16_VIDEO1_IN_WID_8 3 + #define X16_VIDEO1_SAV_EAV 3:2 + #define X16_VIDEO1_SAV_EAV_CH0 0 + #define X16_VIDEO1_SAV_EAV_CH1 1 + #define X16_VIDEO1_SAV_EAV_CH2 2 + #define X16_VIDEO1_IN_COLOR 0:0 + #define X16_VIDEO1_IN_COLOR_RGB 0 + #define X16_VIDEO1_IN_COLOR_YCC 1 + +#define X17_DC_REG 23 // RW 20h Deep color setting + #define X17_DC_REG_TMDS 7:6 + #define X17_DC_REG_TMDS_8b 0 + #define X17_DC_REG_TMDS_10b 1 + #define X17_DC_REG_TMDS_12b 2 + #define X17_DC_REG_FIFO 5:5 + #define X17_DC_REG_ESART 4:4 + #define X17_DC_REG_ELAST 3:3 + #define X17_DC_REG_EBYTE 2:2 + #define X17_DC_REG_EXTCLR 1:1 + #define X17_DC_REG_EXTCLR_SOF 0 + #define X17_DC_REG_EXTCLR_SOH 1 + +#define X18_CSC_C0_HI 24 // RW 04h Color Space Conversion Parameters +#define X19_CSC_C0_LO 25 // RW 00h +#define X1A_CSC_C1_HI 26 // RW 05h Color Space Conversion Parameters +#define X1B_CSC_C1_LO 27 // RW 09h +#define X1C_CSC_C2_HI 28 // RW 00h +#define X1D_CSC_C2_LO 29 // RW 00h +#define X1E_CSC_C3_HI 30 // RW 02h +#define X1F_CSC_C3_LO 31 // RW A1h +#define X20_CSC_C4_HI 32 // RW 04h +#define X21_CSC_C4_LO 33 // RW 00h +#define X22_CSC_C5_HI 34 // RW 12h +#define X23_CSC_C5_LO 35 // RW 91h +#define X24_CSC_C6_HI 36 // RW 11h +#define X25_CSC_C6_LO 37 // RW 59h +#define X26_CSC_C7_HI 38 // RW 00h +#define X27_CSC_C7_LO 39 // RW 7Dh +#define X28_CSC_C8_HI 40 // RW 04h +#define X29_CSC_C8_LO 41 // RW 00h +#define X2A_CSC_C9_HI 42 // RW 00h +#define X2B_CSC_C9_LO 43 // RW 00h +#define X2C_CSC_C10_HI 44 // RW 06h +#define X2D_CSC_C10_LO 45 // RW EFh +#define X2E_CSC_C11_HI 46 // RW 02h +#define X2F_CSC_C11_LO 47 // RW DDh + +#define X30_EXT_VPARAMS 48 // RW 00h External video parameter settings +#define X30_EXT_VPARAMS_VSYNC_OFFSET 7:4 +#define X30_EXT_VPARAMS_VSYNC_PHASE 3:3 +#define X30_EXT_VPARAMS_VSYNC_PHASE_NEG 0 +#define X30_EXT_VPARAMS_VSYNC_PHASE_POS 1 +#define X30_EXT_VPARAMS_HSYNC_PHASE 2:2 +#define X30_EXT_VPARAMS_HSYNC_PHASE_NEG 0 +#define X30_EXT_VPARAMS_HSYNC_PHASE_POS 1 +#define X30_EXT_VPARAMS_PI 1:1 +#define X30_EXT_VPARAMS_PI_PROGRESSIVE 0 +#define X30_EXT_VPARAMS_PI_INTERLACE 1 +#define X30_EXT_VPARAMS_USE 0:0 +#define X30_EXT_VPARAMS_USE_PRE_PROG 0 +#define X30_EXT_VPARAMS_USE_EXTERNAL 1 + +#define X31_EXT_HTOTAL 49 // RW 00h External horizontal total +#define X32_EXT_HTOTAL 50 // +#define X33_EXT_HBLANK 51 // RW 00h External horizontal blank +#define X34_EXT_HBLANK 52 // +#define X35_EXT_HDLY 53 // RW 00h External horizontal delay +#define X36_EXT_HDLY 54 // +#define X37_EXT_HS_DUR 55 // RW 00h External horizontal duration +#define X38_EXT_HS_DUR 56 // +#define X39_EXT_VTOTAL 57 // RW 00h External vertical total +#define X3A_EXT_VTOTAL 58 // +#define X3B_AVSET2 59 // RW 00h Audio/Video setting.2 + #define X3B_AVSET2_CTS_DEBUG 7:7 + #define X3B_AVSET2_CD_ZERO 6:6 + #define X3B_AVSET2_EXT_DE 5:5 + #define X3B_AVSET2_DCC_I2C_RST 4:4 + #define X3B_AVSET2_VID_CODE39 3:3 + #define X3B_AVSET2_BLACK_FULL 1:1 + #define X3B_AVSET2_CSC 0:0 +// #define CSC_ENABLE 0x01 // R/W 1b Color Space Conversion enable +// #define SEL_FULL_RANGE 0x02 // R/W 1b Select Full/Limited range for Send black video mode +// #define EN_M0_LOAD 0x04 // R/W 1b Load M0 into Akey area +// #define EXT_DE_CNT 0x20 // R/W 1b External DE control +// #define CD_ZERO 0x40 // R/W 1b CD all zero override +// #define CTS_DEBUG 0x80 // R/W 1b Debug bit for CTS timing +#define X3C_EX_VID 60 // RW 00h External input Video ID(VID) +#define X3D_EXT_VBLANK 61 // RW 00h External virtical blank +#define X3E_EXT_VDLY 62 // RW 00h External virtical delay +#define X3F_EXT_VS_DUR 63 // RW 00h External virtical duration +// #define X40_CTRL_PKT_EN 64 // RW 00h Control packet enable + #define X40_CTRL_PKT_EN 0X40 + #define X40_CTRL_PKT_EN_GENE_CTRL 7:7 + #define X40_CTRL_PKT_EN_GENE_CTRL_DIS 0 + #define X40_CTRL_PKT_EN_GENE_CTRL_EN 1 + #define X40_CTRL_PKT_EN_MPEG 6:6 + #define X40_CTRL_PKT_EN_MPEG_DIS 0 + #define X40_CTRL_PKT_EN_MPEG_EN 1 + #define X40_CTRL_PKT_EN_PROD 5:5 + #define X40_CTRL_PKT_EN_PROD_DIS 0 + #define X40_CTRL_PKT_EN_PROD_EN 1 + #define X40_CTRL_PKT_EN_VENDOR 4:4 + #define X40_CTRL_PKT_EN_VENDOR_DIS 0 + #define X40_CTRL_PKT_EN_VENDOR_EN 1 + #define X40_CTRL_PKT_EN_GAMUT 3:3 + #define X40_CTRL_PKT_EN_GAMUT_DIS 0 + #define X40_CTRL_PKT_EN_GAMUT_EN 1 + #define X40_CTRL_PKT_EN_ISRC 2:2 + #define X40_CTRL_PKT_EN_ISRC_DIS 0 + #define X40_CTRL_PKT_EN_ISRC_EN 1 + #define X40_CTRL_PKT_EN_ACP 1:1 + #define X40_CTRL_PKT_EN_ACP_DIS 0 + #define X40_CTRL_PKT_EN_ACP_EN 1 + #define X40_CTRL_PKT_EN_GENE 0:0 + #define X40_CTRL_PKT_EN_GENE_DIS 0 + #define X40_CTRL_PKT_EN_GENE_EN 1 + +#define X41_SEND_CPKT_AUTO 65 // RW 00h HB0 for generic control packet + #define X41_SEND_CPKT_AUTO_GENE_CTRL 7:7 + #define X41_SEND_CPKT_AUTO_GENE_CTRL_DIS 0 + #define X41_SEND_CPKT_AUTO_GENE_CTRL_EN 1 + #define X41_SEND_CPKT_AUTO_MPEG 6:6 + #define X41_SEND_CPKT_AUTO_MPEG_DIS 0 + #define X41_SEND_CPKT_AUTO_MPEG_EN 1 + #define X41_SEND_CPKT_AUTO_PROD 5:5 + #define X41_SEND_CPKT_AUTO_PROD_DIS 0 + #define X41_SEND_CPKT_AUTO_PROD_EN 1 + #define X41_SEND_CPKT_AUTO_VENDOR 4:4 + #define X41_SEND_CPKT_AUTO_VENDOR_DIS 0 + #define X41_SEND_CPKT_AUTO_VENDOR_EN 1 + #define X41_SEND_CPKT_AUTO_GAMUT 3:3 + #define X41_SEND_CPKT_AUTO_GAMUT_DIS 0 + #define X41_SEND_CPKT_AUTO_GAMUT_EN 1 + #define X41_SEND_CPKT_AUTO_ISRC 2:2 + #define X41_SEND_CPKT_AUTO_ISRC_DIS 0 + #define X41_SEND_CPKT_AUTO_ISRC_EN 1 + #define X41_SEND_CPKT_AUTO_ACP 1:1 + #define X41_SEND_CPKT_AUTO_ACP_DIS 0 + #define X41_SEND_CPKT_AUTO_ACP_EN 1 + #define X41_SEND_CPKT_AUTO_GENERIC 0:0 + #define X41_SEND_CPKT_AUTO_GENERIC_DIS 0 + #define X41_SEND_CPKT_AUTO_GENERIC_EN 1 + +#define X42_AUTO_CHECKSUM 66 // RW 00h Auto checksum option +#define X42_AUTO_CHECKSUM_OPT 0:0 +#define X42_AUTO_CHECKSUM_OPT_DIS 0 +#define X42_AUTO_CHECKSUM_OPT_EN 1 + +// #define RESERVED 67 // RW 00h +// #define RESERVED 68 // RW 00h +#define X45_VIDEO2 69 // RW 00h Video setting.2 + #define X45_VIDEO2_CLR_AVMUTE 7:7 + #define X45_VIDEO2_CLR_AVMUTE_DIS 0 + #define X45_VIDEO2_CLR_AVMUTE_EN 1 + #define X45_VIDEO2_SET_AVMUTE 6:6 + #define X45_VIDEO2_SET_AVMUTE_DIS 0 + #define X45_VIDEO2_SET_AVMUTE_EN 1 + #define X45_VIDEO2_AUDIO_RESET 2:2 + #define X45_VIDEO2_AUDIO_RESET_CLR 0 + #define X45_VIDEO2_AUDIO_RESET_SET 1 + #define X45_VIDEO2_NOAUDIO 1:1 + #define X45_VIDEO2_NOAUDIO_CLR 0 + #define X45_VIDEO2_NOAUDIO_SET 1 + #define X45_VIDEO2_NOVIDEO 0:0 + #define X45_VIDEO2_NOVIDEO_CLR 0 + #define X45_VIDEO2_NOVIDEO_SET 1 +// #define NOVIDEO 0x01 // R/W 1b Send black video +// #define NOAUDIO 0x02 // R/W 1b Send no audio +// #define AUDIORST 0x04 // R/W 1b Audio capture logic reset +// #define SET_AV_MUTE 0x40 // R/W 1b Send gSet AV muteh +// #define CLEAR_AV_MUTE 0x80 // R/W 1b Clear AV muteh +// #define RESERVED 70 // RW 00h Reserved + #define X46_OUTPUT_OPTION 70 // RW 00h Reserved +// #define X47_VIDEO4 71 // RW 00h Video setting.4 +// #define X48_ACT_LN_STRT_LSB 72 // RW 00h Active Line Start LSB +// #define X49_ACT_LN_STRT_MSB 73 // RW 00h Active Line Start MSB +// #define X4A_ACT_LN_END_LSB 74 // RW 00h Active Line End LSB +// #define X4B_ACT_LN_END_MSB 75 // RW 00h Active Line End MSB +// #define X4C_ACT_PIX_STRT_LSB 76 // RW 00h Active Pixel Start LSB +// #define X4D_ACT_PIX_STRT_MSB 77 // RW 00h Active Pixel Start MSB +// #define X4E_ACT_PIX_END_LSB 78 // RW 00h Active Pixel End LSB +// #define X4F_ACT_PIX_END_MSB 79 // RW 00h Active Pixel End MSB +// #define X50_EXT_AUDIO_SET 80 // RW 00h Extra audio setting +//SLI10131 +// #define X51_SPEAKER_MAP 81 // RW 00h speaker Mapping CA[7:0] +//IP V2.11 +#define X51_PHY_CTRL 81 // RW 00h Revervd[7:4],PHY_OPTION[3:0] + +#define X52_HSYNC_PLACE_656 82 // RW 00h HSYNC placement at ITU656 +#define X53_HSYNC_PLACE_656 83 // +#define X54_VSYNC_PLACE_656 84 // RW 00h VSYNC placement at ITU656 +#define X55_VSYNC_PLACE_656 85 // + #define X55_VSYNC_PLACE_656_EN 7:7 + #define X55_VSYNC_PLACE_656_EN_INACT 0 + #define X55_VSYNC_PLACE_656_EN_ACT 1 +#define X56_PHY_CTRL 86 // RW 0Fh SLIPHDMIT parameter settings + #define X56_PHY_CTRL_DRV_TEST_IN 7:7 + #define X56_PHY_CTRL_DRV_TEST_EN 6:6 + #define X56_PHY_CTRL_PLLA_BYPAS 4:4 + #define X56_PHY_CTRL_SPEED_B 3:2 + #define X56_PHY_CTRL_SPEED_A 1:0 + +#define X57_PHY_CTRL 87 // RW 00h + #define X57_PHY_CTRL_PLLB_CONFIG17 2:2 + #define X57_PHY_CTRL_PLLA_CONFIG17 1:1 +#define X58_PHY_CTRL 88 // RW 00h + #define X58_PHY_CTRL_BGR_DISC 7:7 + #define X58_PHY_CTRL_BGR_V_OFFSET 6:4 //BIT6-4 + #define X58_PHY_CTRL_BGR_I_OFFSET 2:0 //BIT2-0 + +#define X59_PHY_CTRL 89 // RW 20h +#define X5A_PHY_CTRL 90 // RW 00h +#define X5B_PHY_CTRL 91 // RW 20h +#define X5C_PHY_CTRL 92 // RW 00h + +#define X5D_PHY_CTRL 93 // RW 00h + #define X5D_PHY_CTRL_DRV_CONFIG2_0 6:4 //BIT6-4 + #define X5D_PHY_CTRL_PE_CNTRL2_0 2:0 //BIT2-0 +#define X5E_PHY_CTRL 94 // RW 00h + #define X5E_PHY_CTRL_PLLB_CONFIG16 5:5 + #define X5E_PHY_CTRL_PLLA_CONFIG16 4:4 + #define X5E_PHY_CTRL_AMON_SEL2_0 2:0 +#define X5F_PACKET_INDEX 95 // R/W 00h Packet Buffer Index + #define GENERIC_PACKET 0x00 // R/W 00h Generic packet + #define ACP_PACKET 0x01 // R/W 00h ACP packet + #define ISRC1_PACKET 0x02 // R/W 00h ISRC1 packet + #define ISRC2_PACKET 0x03 // R/W 00h ISRC2 packet + #define GAMUT_PACKET 0x04 // R/W 00h Gamut metadata packet + #define VENDOR_INFO_PACKET 0x05 // R/W 00h Vendor specific InfoFrame + #define AVI_INFO_PACKET 0x06 // R/W 00h AVI InfoFrame + #define PRODUCT_INFO_PACKET 0x07 // R/W 00h Source product descriptor InfoFrame + #define AUDIO_INFO_PACKET 0x08 // R/W 00h Audio InfoFrame packet + #define MPEG_SRC_INFO_PACKET 0x09 // R/W 00h MPEG source InfoFrame +#define X60_PACKET_HB0 96 // RW 00h HB0 +#define X61_PACKET_HB1 97 // RW 00h HB1 +#define X62_PACKET_HB2 98 // RW 00h HB2 +#define X63_PACKET_PB0 99 // RW 00h PB0 +#define X64_PACKET_PB1 100 // RW 00h +#define X65_PACKET_PB2 101 // RW 00h +#define X66_PACKET_PB3 102 // RW 00h +#define X67_PACKET_PB4 103 // RW 00h +#define X68_PACKET_PB5 104 // RW 00h +#define X69_PACKET_PB6 105 // RW 00h +#define X6A_PACKET_PB7 106 // RW 00h +#define X6B_PACKET_PB8 107 // RW 00h +#define X6C_PACKET_PB9 108 // RW 00h +#define X6D_PACKET_PB10 109 // RW 00h +#define X6E_PACKET_PB11 110 // RW 00h +#define X6F_PACKET_PB12 111 // RW 00h +#define X70_PACKET_PB13 112 // RW 00h +#define X71_PACKET_PB14 113 // RW 00h +#define X72_PACKET_PB15 114 // RW 00h +#define X73_PACKET_PB16 115 // RW 00h +#define X74_PACKET_PB17 116 // RW 00h +#define X75_PACKET_PB18 117 // RW 00h +#define X76_PACKET_PB19 118 // RW 00h +#define X77_PACKET_PB20 119 // RW 00h +#define X78_PACKET_PB21 120 // RW 00h +#define X79_PACKET_PB22 121 // RW 00h +#define X7A_PACKET_PB23 122 // RW 00h +#define X7B_PACKET_PB24 123 // RW 00h +#define X7C_PACKET_PB25 124 // RW 00h +#define X7D_PACKET_PB26 125 // RW 00h +#define X7E_PACKET_PB27 126 // RW 00h PB27 +// #define RESERVED 127 // Reserved +#define X80_EDID 128 // RO - Access window for EDID buffer +#define X81_ISRC2_PB0 129 // RW 00h ISRC2 PB0-15 +#define X82_ISRC2_PB1 130 // RW 00h + + +// #define X83_ISRC2_PB2 131 // RW 00h +// #define X84_ISRC2_PB3 132 // RW 00h +// #define X85_ISRC2_PB4 133 // RW 00h +// #define X86_ISRC2_PB5 134 // RW 00h +// #define X87_ISRC2_PB6 135 // RW 00h +// #define X88_ISRC2_PB7 136 // RW 00h +// #define X89_ISRC2_PB8 137 // RW 00h +// #define X8A_ISRC2_PB9 138 // RW 00h ISRC2 PB0-15 +// #define X8B_ISRC2_PB10 139 // RW 00h +// #define X8C_ISRC2_PB11 140 // RW 00h +// #define X8D_ISRC2_PB12 141 // RW 00h +// #define X8E_ISRC2_PB13 142 // RW 00h +// #define X8F_ISRC2_PB14 143 // RW 00h +// #define X90_ISRC2_PB15 144 // RW 00h +// #define X91_ISRC1_HB1 145 // RW 00h ISRC2 HB1 +#define X92_INT_MASK1 146 // RW C0h Mask for Interrupt Group1 + #define X92_INT_MASK1_HPG 7:7 //'1B' NO MASKED + #define X92_INT_MASK1_MSENS 6:6 //'1B' NO MASKED + #define X92_INT_MASK1_VSYNC 5:5 //'1B' NO MASKED + #define X92_INT_MASK1_AFIFO_FULL 4:4 //'1B' NO MASKED + #define X92_INT_MASK1_EDID_RDY 2:2 //'1B' NO MASKED + #define X92_INT_MASK1_EDID_ERR 1:1 //'1B' NO MASKED + + +// #define EDID_ERR_MSK 0x02 // R/W 1b EDID error detect interrupt mask +// #define EDID_RDY_MSK 0x04 // R/W 1b EDID ready interrupt mask +// #define AFIFO_FULL_MSK 0x10 // R/W 0b Audio FIFO full detect interrupt mask +// #define VSYNC_MSK 0x20 // R/W 0b VSYNC detect interrupt mask +// #define MSENS_MSK 0x40 // R/W 0b MSENS detect interrupt mask +// #define HPG_MSK 0x80 // R/W 0b Hot plug detect interrupt mask +#define X93_INT_MASK2 147 // RW 78h Mask for Interrupt Group2 + #define X93_INT_MASK2_HDCP_ERR 7:7 //'1B' NO MASKED + #define X93_INT_MASK2_BKSV_RPRDY 6:6 //'1B' NO MASKED + #define X93_INT_MASK2_BKSV_RCRDY 5:5 //'1B' NO MASKED + #define X93_INT_MASK2_AUTH_DONE 4:4 //'1B' NO MASKED + #define X93_INT_MASK2_RDY_AUTH 3:3 //'1B' NO MASKED + + +// #define RDY_AUTH_MSK 0x08 // R/W 1b Authentication ready interrupt mask +// #define AUTH_DONE_MSK 0x10 // R/W 1b HDCP authentication done interrupt mask +// #define BKSV_RCRDY_MSK 0x20 // R/W 1b BKSV ready from receiver interrupt mask +// #define BKSV_RPRDY_MSK 0x40 // R/W 1b BKSVs list ready from repeater interrupt mask +// #define HDCP_ERR_MSK 0x80 // R/W 0b HDCP error detect interrupt mask +#define X94_INT1_ST 148 // RW 00h Interrupt status Group1 + #define X94_INT1_ST_HPG 7:7 // 1b means Interrupted + #define X94_INT1_ST_HPG_EN 1 + #define X94_INT1_ST_HPG_NO 0 + #define X94_INT1_ST_MSENS 6:6 // 1b means Interrupted + #define X94_INT1_ST_MSENS_EN 1 + #define X94_INT1_ST_MSENS_NO 0 + #define X94_INT1_ST_VSYNC 5:5 // 1b means Interrupted + #define X94_INT1_ST_VSYNC_EN 1 + #define X94_INT1_ST_VSYNC_NO 0 + #define X94_INT1_ST_AFIFO_FULL 4:4 // 1b means Interrupted + #define X94_INT1_ST_AFIFO_FULL_EN 1 + #define X94_INT1_ST_AFIFO_FULL_NO 0 + #define X94_INT1_ST_EDID_RDY 2:2 // 1b means Interrupted + #define X94_INT1_ST_EDID_RDY_EN 1 + #define X94_INT1_ST_EDID_RDY_NO 0 + #define X94_INT1_ST_EDID_ERR 1:1 // 1b means Interrupted + #define X94_INT1_ST_EDID_ERR_EN 1 + #define X94_INT1_ST_EDID_ERR_NO 0 + +// #define EDID_ERR_INT 0x02 // R/W 0b EDID error detect interrupt +// #define EDID_RDY_INT 0x04 // R/W 0b EDID ready interrupt +// #define AFIFO_FULL_INT 0x10 // R/W 0b Audio FIFO full detect interrupt +// #define VSYNC_INT 0x20 // R/W 0b VSYNC detect interrupt +// #define MSENS_INT 0x40 // R/W 0b MSENS detect interrupt +// #define HPG_INT 0x80 // R/W 0b Hot plug detect interrupt +#define X95_INT2_ST 149 // RW 00h Interrupt status Group2 + #define X95_INT2_ST_HDCP_ERR 7:7 + #define X95_INT2_ST_BKSV_RPRDY 6:6 + #define X95_INT2_ST_BKSV_RCRDY 5:5 + #define X95_INT2_ST_AUTH_DONE 4:4 + #define X95_INT2_ST_RDY_AUTH 3:3 + +// #define RDY_AUTH_INT 0x08 // R/W 0b Authentication ready interrupt +// #define AUTH_DONE_INT 0x10 // R/W 0b HDCP authentication done interrupt +// #define BKSV_RCRDY_INT 0x20 // R/W 0b BKSV ready from receiver interrupt +// #define BKSV_RPRDY_INT 0x40 // R/W 0b BKSVs list ready from repeater interrupt +// #define HDCP_ERR_INT 0x80 // R/W 0b HDCP error detect interrupt +#define X96_INT_MASK3 0X96 +#define X97_INT_MASK3 0X97 +#define X98_INT3_ST 0X98 + #define X98_INT3_ST_SF_MODE_READY 7:7 + #define X98_INT3_ST_RI_READY 6:6 + #define X98_INT3_ST_PJ_READY 5:5 + #define X98_INT3_ST_AN_READY 4:4 + #define X98_INT3_ST_SHA1_READY 3:3 + #define X98_INT3_ST_ENC_EN 2:2 + #define X98_INT3_ST_ENC_DIS_AVMUTE 1:1 + #define X98_INT3_ST_ENC_DIS_NO_AVMUTE 0:0 + +#define X99_INT4_ST 0X99 + #define X99_INT4_ST_I2C_ACK 7:7 + #define X99_INT4_ST_I2C_ERR_ACK 6:6 + #define X99_INT4_ST_RI_SAVE_READY 5:5 + #define X99_INT4_ST_PJ_SAVE_READY 4:4 + #define X99_INT4_ST_FR_CNT_UPDATE 3:3 + +#define X9A_HDCP_CTRL1 0X9A + #define X9A_HDCP_CTRL1_AUTH 7:7 + #define X9A_HDCP_CTRL1_AUTH_HWARE 0 + #define X9A_HDCP_CTRL1_AUTH_SWARE 1 + #define X9A_HDCP_CTRL1_SOFT 5:5 + #define X9A_HDCP_CTRL1_SOFT_CLR 0 + #define X9A_HDCP_CTRL1_SOFT_SET 1 + #define X9A_HDCP_CTRL1_PREP_AN 4:4 + #define X9A_HDCP_CTRL1_REPEAT 2:2 + #define X9A_HDCP_CTRL1_REPEAT_CLR 0 + #define X9A_HDCP_CTRL1_REPEAT_SET 1 + #define X9A_HDCP_CTRL1_START_AUTH 1:1 + #define X9A_HDCP_CTRL1_CALC_SHA1 0:0 + +#define X9C_FRAME_CNT 0X9C +#define X9D_FRAME_CNT_RI 0X9D +#define X9E_DDC_ACS_LENGTH 0X9E +#define XA0_I2C_OFFSET 0XA0 +#define XA1_DDC_I2C_CTRL 0XA1 + #define XA1_DDC_I2C_CTRL_SEL 2:2 + #define XA1_DDC_I2C_CTRL_SEL_BUF0_4 0 + #define XA1_DDC_I2C_CTRL_SEL_80H 1 + #define XA1_DDC_I2C_CTRL_W_START 1:1 + #define XA1_DDC_I2C_CTRL_R_START 0:0 +#define XA2_DDC_I2C_RBUF0 0XA2 +#define XA3_DDC_I2C_RBUF1 0XA3 +#define XA4_DDC_I2C_RBUF2 0XA4 +#define XA5_DDC_I2C_RBUF3 0XA5 +#define XA6_DDC_I2C_RBUF4 0XA6 +#define XA7_DDC_I2C_WBUF0 0XA7 +#define XA8_DDC_I2C_WBUF1 0XA8 +#define XA9_DDC_I2C_WBUF2 0XA9 +#define XAA_DDC_I2C_WBUF3 0XAA +#define XAB_DDC_I2C_WBUF4 0XAB +#define XAC_DDC_I2C_WBUF5 0XAC +#define XAD_DDC_I2C_WBUF6 0XAD +#define XAE_DDC_I2C_WBUF7 0XAE + + + +// #define VN1 150 // RW 00h Generic control packet (PB1-PB23) +// #define VN2 151 // RW 00h +// #define VN3 152 // RW 00h +// #define VN4 153 // RW 00h +// #define VN5 154 // RW 00h +// #define VN6 155 // RW 00h +// #define VN7 156 // RW 00h +// #define VN8 157 // RW 00h +// #define PD1 158 // RW 00h +// #define PD2 159 // RW 00h +// #define PD3 160 // RW 00h +// #define PD4 161 // RW 00h +// #define PD5 162 // RW 00h +// #define PD6 163 // RW 00h +// #define PD7 164 // RW 00h +// #define PD8 165 // RW 00h +// #define PD9 166 // RW 00h +// #define PD10 167 // RW 00h +// #define PD11 168 // RW 00h +// #define PD12 169 // RW 00h +// #define PD13 170 // RW 00h +// #define PD14 171 // RW 00h +// #define PD15 172 // RW 00h +// #define PD16 173 // RW 00h Generic control packet (PB24-PB25) +// #define SRC_DEV_INFO 174 // RW 00h +#define XAF_HDCP_CTRL 175 // R/W 12h HDCP Control Register + #define XAF_HDCP_CTRL_HDCP_REQ 7:7 + #define XAF_HDCP_CTRL_BKSV_PASS 6:6 + #define XAF_HDCP_CTRL_BKSV_FAIL 5:5 + #define XAF_HDCP_CTRL_FRAME_ENC 4:4 + #define XAF_HDCP_CTRL_STOP_AUTH 3:3 + #define XAF_HDCP_CTRL_ADV_CIPHER 2:2 + #define XAF_HDCP_CTRL_MODE 1:1 + #define XAF_HDCP_CTRL_MODE_DVI 0 + #define XAF_HDCP_CTRL_MODE_HDMI 1 + #define XAF_HDCP_CTRL_RESET 0:0 + +// #define HDCP_RESET 0x01 // R/W 0b Reset HDCP +// #define HDMI_MODE_CTRL 0x02 // R/W 0b HDMI/DVI mode +// #define ADV_CIPHER 0x04 // R/W 0b Advanced cipher mode +// #define STOP_AUTH 0x08 // R/W 0b Stop HDCP authentication +// #define FRAME_ENC 0x10 // R/W 0b Frame encrypt +// #define BKSV_FAIL 0x20 // R/W 0b BKSV check result (FAIL) +// #define BKSV_PASS 0x40 // R/W 0b BKSV check result (PASS) +// #define HDCP_REQ 0x80 // R/W 0b HDCP authentication start +// #define AN 176 // RO 00h An register +// 177 // +// 178 // +// 179 // +// 180 // +// 181 // +// 182 // +// 183 // +// #define XB0_HDCP_STATUS 176 // RO 00h HDCP Status Register +#define XB2_RI_FRAME_CNT 0XB2 +#define XB7_DDC_CTL 0XB7 + #define XB7_DDC_CTL_PRESCL 7:7 + #define XB7_DDC_CTL_PRESCL_Y 0 + #define XB7_DDC_CTL_PRESCL_NO 1 + #define XB7_DDC_CTL_SDA_DRV 6:6 + #define XB7_DDC_CTL_SDA_DRV_L 0 + #define XB7_DDC_CTL_SDA_DRV_H 1 + #define XB7_DDC_CTL_SCL_DRV 5:5 + #define XB7_DDC_CTL_SCL_DRV_L 0 + #define XB7_DDC_CTL_SCL_DRV_H 1 + #define XB7_DDC_CTL_OVERRIDE 4:4 + #define XB7_DDC_CTL_OVERRIDE_N 0 + #define XB7_DDC_CTL_OVERRIDE_Y 1 + #define XB7_DDC_CTL_SDA_ST 1:1 + #define XB7_DDC_CTL_SDA_ST_L 0 + #define XB7_DDC_CTL_SDA_ST_H 1 + #define XB7_DDC_CTL_SCL_ST 0:0 + #define XB7_DDC_CTL_SCL_ST_L 0 + #define XB7_DDC_CTL_SCL_ST_H 1 + +#define XB8_HDCP_STATUS 184 // RO 00h HDCP Status Register + #define XB8_HDCP_STATUS_AUTH 7:7 + #define XB8_HDCP_STATUS_AUTH_N 0 + #define XB8_HDCP_STATUS_AUTH_Y 1 + #define XB8_HDCP_STATUS_ENC 6:6 + #define XB8_HDCP_STATUS_ENC_N 0 + #define XB8_HDCP_STATUS_ENC_Y 1 + #define XB8_HDCP_STATUS_MODE 5:5 + #define XB8_HDCP_STATUS_MODE_DVI 0 + #define XB8_HDCP_STATUS_MODE_HDMI 1 + #define XB8_HDCP_STATUS_IDLE 4:4 + #define XB8_HDCP_STATUS_IDLE_N 0 + #define XB8_HDCP_STATUS_IDLE_Y 1 + #define XB8_HDCP_STATUS_ADV_CIPHER 3:3 + #define XB8_HDCP_STATUS_ADV_CIPHER_N 0 + #define XB8_HDCP_STATUS_ADV_CIPHER_Y 1 +// #define ADV_CIPHERI_STATUS 0x08 // R 0b Advanced cipher status +// #define HDCP_IDLE 0x10 // R 0b HDCP state machine status +// #define HDMI_STATUS 0x20 // R 0b HDMI/DVI status +// #define ENC 0x40 // R 0b Encryption status +// #define AUTH 0x80 // R 0b HDCP authentication status +// #define SHA_DISP0 185 // RO 00h SHA1 value +// #define SHA_DISP1 186 // RO 00h +// #define SHA_DISP2 187 // RO 00h +// #define SHA_DISP3 188 // RO 00h +// #define SHA_DISP4 189 // RO 00h +#define XB9_SHA0 0XB9 +#define XBA_SHA1 0XBA +#define XBB_SHA2 0XBB +#define XBC_SHA3 0XBC +#define XBD_SHA4 0XBD +// #define XBE_BCAPS 0XBE + + + +#define XBE_BCAPS 190 // RO 00h BCAPS value +#define XBF_KSV7_0 191 // RO 00h KSV[7:0] - AKSV/BKSV monitor registers +#define XC0_KSV15_8 192 // RO 00h KSV[15:8] - AKSV/BKSV monitor registers +#define XC1_KSV23_16 193 // RO 00h KSV[23:16] - AKSV/BKSV monitor registers +#define XC2_KSV31_24 194 // RO 00h KSV[31:24] - AKSV/BKSV monitor registers +#define XC3_KSV39_32 195 // RO 00h KSV[39:32] - AKSV/BKSV monitor registers +#define XC4_SEG_PTR 196 // RW 00h EDID segment pointer +#define XC5_EDID_WD_ADDR 197 // RW 00h EDID word address +#define XC6_GEN_PB26 198 // RW 00h Generic control packet (PB26) +#define XC7_NUM_DEV 0XC7 + +// #define NUM_DEV 199 // RO 00h HDCP BKSV Size +#define XC8_HDCP_ERR 200 // RO 00h HDCP error +#define BAD_BKSV 0x01 // R/W 0b BKSV does not contain 20 0's and 20 1's +#define XC9_TIMER 201 // RW 46h Timer value for 100ms +#define XCA_TIMER 202 // RW 2ch Timer value for 5sec +#define XCB_READ_RI_CNT 203 // RW 12h Ri read count +#define XCC_AN_SEED 204 // RW 00h An Seed +#define XCD_MAX_REC_NUM 205 // RW 16d maximum number of receivers allowed +#define XCE_HDCP_MEM_CNTL1 0XCE +#define XCE_HDCP_MEM_CNTL1_SHORT 7:7 +#define XCE_HDCP_MEM_CNTL1_W4_DATA 6:0 + + +// #define //RESERVED 206 // RO 00h +#define XCF_HDCP_MEM_CTRL2 207 // RW 0Oh [1:0] ID_FAX_KEY, ID_HDCP_KEY + #define XCF_HDCP_MEM_CTRL2_LD_HDCP 1:1 + #define XCF_HDCP_MEM_CTRL2_LD_FAX 0:0 + +// #define LD_HDCP_KEY 0x01 // R/W 0b Trigger for loading HDCP key from external memory +// #define LD_FAX_KEY 0x02 // R/W 0b Trigger for loading fax HDCP key +#define XD0_HDCP_CTRL2 208 // R/W 08h HDCP Control 2 +#define XD0_HDCP_CTRL2_DIS_127_CHK 7:7 +#define XD0_HDCP_CTRL2_BKSV_CHK 6:6 +#define XD0_HDCP_CTRL2_EN_PJ_CALC 5:5 +#define XD0_HDCP_CTRL2_DIS_0LEN_HASH 4:4 +#define XD0_HDCP_CTRL2_DELAY_RI_CHK 3:3 +#define XD0_HDCP_CTRL2_USE_PRESENT_AN 2:2 +#define XD0_HDCP_CTRL2_SEL_PRESENT_AN 1:0 + + +// #define DELAY_RI_CHK 0x08 // R/W 0b Set this bit to compare Ri at 129th frame instead of 128th frame for slower receivers. +// #define DIS_0LEN_HASH 0x10 // R/W 0b Some early repeaters may not load Hash value if number of devices is 0. Set this bit to skip Hash comparison when number of devices in Bstatus equals 0. +// #define EN_PJ_CALC 0x20 // R/W 0b Even though this bit is set, Pj calculation is enabled only if adv_cipher mode is selected. +// #define DIS_127_CHK 0x80 // R/W 0b This bit must be set to disable 127th Ri check if Ri check frequency is altered by ri_frame_cnt (B2h). +// #define //RESERVED 209 // RO 00h +#define XD2_HDCP_KEY_CTRL 210 // R/W 00h HDCP KEY memory control +#define XD2_HDCP_KEY_CTRL_USE_KSV1 6:6 +#define XD2_HDCP_KEY_CTRL_USE_KSV2 5:5 +#define XD2_HDCP_KEY_CTRL_LOAD_AKSV 4:4 +#define XD2_HDCP_KEY_CTRL_KSV_SEL 3:3 +#define XD2_HDCP_KEY_CTRL_KSV_VALID 2:2 +#define XD2_HDCP_KEY_CTRL_KEY_VALID 1:1 +#define XD2_HDCP_KEY_CTRL_KEY_READY 0:0 +// #define KEY_READY 0x01 // R 0b This bit shows that HDCP key load has finished. +// #define KEY_VALID 0x02 // R 0b This bit shows whether HDCP key loaded from HDCP memory is valid. +// #define KSV_VALID 0x04 // R 0b This bit shows whether the loaded KSV is valid (has 20 1fs and 0fs). +// #define KSV_SEL 0x08 // R 0b This bit shows which KSV was actually loaded into memory from HDCP memory. +// #define LOAD_AKSV 0x10 // R/W 0b Select which KSV to be loaded into AKSV/BKSV register (BFh~C3h). Write 1 to load AKSV. +// #define USE_KSV2 0x20 // R/W 0b If this bit is set, load the 2nd KSV written in the HDCP memory. If both usv_ksv1 and use_ksv2 are 0, hardware loads whichever that has 20 1fs and 0fs. +// #define USE_KSV1 0x40 // R/W 0b If this bit is set, load the 1st KSV written in the HDCP memory. +#define XD3_CSC_CONFIG1 211 // RW 81h CSC/Video Config.1 +#define XD3_CSC_CONFIG1_MODE 7:7 +#define XD3_CSC_CONFIG1_MODE_MANU 0 +#define XD3_CSC_CONFIG1_MODE_AUTO 1 +#define XD3_CSC_CONFIG1_COEF 6:3 +#define XD3_CSC_CONFIG1_COEF_SDTV_LIM 8 +#define XD3_CSC_CONFIG1_COEF_SDTV_FUL 4 +#define XD3_CSC_CONFIG1_COEF_HDTV 2 +#define XD3_CSC_CONFIG1_COEF_HDTV_50HZ 1 +#define XD3_CSC_CONFIG1_CSC 2:2 +#define XD3_CSC_CONFIG1_CSC_OFF 0 +#define XD3_CSC_CONFIG1_CSC_ON 1 +#define XD3_CSC_CONFIG1_VID_ID 1:1 +#define XD3_CSC_CONFIG1_VID_ID_5_19 0 +#define XD3_CSC_CONFIG1_VID_ID_28_29 1 +#define XD3_CSC_CONFIG1_SWAP_BR 0:0 +#define XD3_CSC_CONFIG1_SWAP_BR_DONE 0 +#define XD3_CSC_CONFIG1_SWAP_BR_NOT 1 + + + +#define XD4_VIDEO3 212 // RW 00h Video setting 3 +// #define RI 213 // RO 00h Ri +// 214 // RO 00h Pj +// #define PJ 215 // Dir. Reset Descriptions +// #define SHA_RD 216 // RW 00h SHA index for read + +#define XD5_RI_N7_0 0XD5 +#define XD6_RI_N15_8 0XD6 +#define XD7_PJ 0XD7 +#define XD8_SHA_RD 0XD8 + +#define XD9_GEN_PB27 217 // RW 00h Generic InfoFrame PB27 +// #define MPEG_B0 218 // RW 00h MPEG source InfoFrame +// #define MPEG_B1 219 // RW 00h +// #define MPEG_B2 220 // RW 00h +// #define MPEG_B3 221 // RW 00h +// #define MPEG_FR_MF 222 // RW 00h +#define XDA_RI_N15_8_SAV 0XDA +#define XDB_PJ_SAV 0XDB +#define XDC_NUM_DEVICE 0XDC + + +#define XDF_HPG_STATUS 223 // R 00h Hot plug/MSENS status + #define XDF_HPG_STATUS_HPG_PRT 7:7 + #define XDF_HPG_STATUS_HPG_PRT_L 0 + #define XDF_HPG_STATUS_HPG_PRT_H 1 + #define XDF_HPG_STATUS_MSENS_PRT 6:6 + #define XDF_HPG_STATUS_MSENS_PRT_L 0 + #define XDF_HPG_STATUS_MSENS_PRT_H 1 + #define XDF_HPG_STATUS_BIST 1:0 + #define XDF_HPG_STATUS_BIST_PASS 2 + #define XDF_HPG_STATUS_BIST_FAIL 1 + +// #define BIST_FAIL 0x01 // R 0b Dual port RAM BIST result fail +// #define BIST_PASS 0x02 // R 0b Dual port RAM BIST result passed +// #define MSENS_PRT 0x40 // R 0b MSENS input port status +// #define HPG_PRT 0x80 // R 0b Hot plug input port status +#define XE0_GAMUT_HB1 224 // RW 00h gamut metadata HB1 +#define XE1_GAMUT_HB2 225 // RW 00h gamut metadata HB2 +// #define GAMUT_PB0 226 // RW 00h gamut metadata PB0 +// #define GAMUT_PB1 227 // RW 00h gamut metadata PB1 +// #define GAMUT_PB2 228 // RW 00h gamut metadata PB2 +// #define GAMUT_PB3 229 // RW 00h gamut metadata PB3 +// #define GAMUT_PB4 230 // RW 00h gamut metadata PB4 +// #define GAMUT_PB5 231 // RW 00h gamut metadata PB5 +#define XE3_BKSV_N7_0 0XE3 +#define XE4_BKSV_N15_8 0XE4 +#define XE5_BKSV_N23_16 0XE5 +#define XE6_BKSV_N31_24 0XE6 +#define XE7_BKSV_N39_32 0XE7 +// #define XE8_AN_N7_0 0XE8 + + +#define XE8_AN0 232 // RW 00h An[7:0] +#define XE9_AN1 0XE9 +#define XEA_AN2 0XEA +#define XEB_AN3 0XEB +#define XEC_AN4 0XEC +#define XED_AN5 0XED +#define XEE_AN6 0XEE +#define XEF_AN7 0XEF + +#define XF0_PROD_ID 0XF0 +#define XF1_REVS_ID 0XF1 +#define XF3_START_BLK1_LSB 0XF3 +#define XF4_START_BLK1_MSB 0XF4 +#define XF5_DURA_BLK1 0XF5 +#define XF6_DURA_BLK2_LSB 0XF6 +#define XF7_DURA_BLK2_MSB 0XF7 +#define XF8_DURA_BLK2 0XF8 +#define XF9_START_BLK3_LSB 0XF9 +#define XFA_START_BLK3_MSB 0XFA +#define XFB_DURA_BLK3 0XFB +#define XFC_VID_INPUT 0XFC + #define XFC_VID_INPUT_HSYNC 1:1 + #define XFC_VID_INPUT_HSYNC_ADJ_Y 0 + #define XFC_VID_INPUT_HSYNC_ADJ_N 1 + #define XFC_VID_INPUT_VSYNC 0:0 + #define XFC_VID_INPUT_VSYNC_ADJ_Y 0 + #define XFC_VID_INPUT_VSYNC_ADJ_N 1 +#define XFD_RDAT_OUTPUT 0XFD +#define XFE_TEST 0XFE +#define XFE_TEST_FBCK 7:7 +#define XFE_TEST_FBCK_DIS 0 +#define XFE_TEST_FBCK_EN 1 +#define XFE_TEST_FBCK20 5:5 +#define XFE_TEST_FBCK20_DIS 0 +#define XFE_TEST_FBCK20_EN 1 +#define XFE_TEST_FBCK10 4:4 +#define XFE_TEST_FBCK10_DIS 0 +#define XFE_TEST_FBCK10_EN 1 +#define XFE_TEST_BIST_FLAG 3:3 +#define XFE_TEST_BIST_FLAG_END 0 +#define XFE_TEST_BIST_FLAG_WORK 1 +#define XFE_TEST_PHY_ONLY 2:2 +#define XFE_TEST_PHY_ONLY_DIS 0 +#define XFE_TEST_PHY_ONLY_EN 1 +#define XFE_TEST_AUTO_LB 1:1 +#define XFE_TEST_AUTO_LB_MANUAL 0 +#define XFE_TEST_AUTO_LB_RANDOM 1 +#define XFE_TEST_LB 0:0 +#define XFE_TEST_LB_DIS 0 +#define XFE_TEST_LB_EN 1 + +// #define GAMUT_PB7 233 // RW 00h gamut metadata PB7 +// #define GAMUT_PB8 234 // RW 00h gamut metadata PB8 +// #define GAMUT_PB9 235 // RW 00h gamut metadata PB9 +// #define GAMUT_PB10 236 // RW 00h gamut metadata PB10 +// #define GAMUT_PB11 237 // RW 00h gamut metadata PB11 +// #define GAMUT_PB12 238 // RW 00h gamut metadata PB12 +// #define GAMUT_PB13 239 // RW 00h gamut metadata PB13 +// #define GAMUT_PB14 240 // RW 00h gamut metadata PB14 +// #define GAMUT_PB15 241 // RW 00h gamut metadata PB15 +// #define GAMUT_PB16 242 // RW 00h gamut metadata PB16 +// #define GAMUT_PB17 243 // RW 00h gamut metadata PB17 +// #define GAMUT_PB18 244 // RW 00h gamut metadata PB18 +// #define GAMUT_PB19 245 // RW 00h gamut metadata PB19 +// #define GAMUT_PB20 246 // RW 00h gamut metadata PB20 +// #define GAMUT_PB21 247 // RW 00h gamut metadata PB21 +// #define GAMUT_PB22 248 // RW 00h gamut metadata PB22 +// #define GAMUT_PB23 249 // RW 00h gamut metadata PB23 +// #define GAMUT_PB24 250 // RW 00h gamut metadata PB24 +// #define GAMUT_PB25 251 // RW 00h gamut metadata PB25 +// #define GAMUT_PB26 252 // RW 00h gamut metadata PB26 +// #define GAMUT_PB27 253 // RW 00h gamut metadata PB27 +// #define TEST_MODE 254 // RW 00h test mode register +// #define XFF_IP_COM_CONTROL 255 // R/W 40h I/P conversion control +// #define IP_CONV_PIX_REP 0x01 // R/W 0b I/P conversion control +// #define IP_CONV_EN 0x02 // R/W 0b I/P conversion mode control +// #define PRE_COLOR_CONV_ON 0x10 // R/W 0b Pre-color space converter (RGB->YCbCr) control +// #define PRE_DOWN_CONV_ON 0x20 // R/W 0b Pre-pixel encoding converter (down sampler) control +// #define STGAM_OFF 0x40 // R/W 1b Gamma correction control +// #define IP_REG_OFFSET 0x80 // R/W 0b I/P conversion control register access control + + +#endif /* _HDMIREGS_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk768/l3.c b/drivers/gpu/drm/smidrm/ddk768/l3.c new file mode 100644 index 000000000000..e68c371ce307 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/l3.c @@ -0,0 +1,65 @@ + +#include "l3.h" + +/* + * Send one byte of data to the chip. Data is latched into the chip on + * the rising edge of the clock. + */ +static void sendbyte(struct l3_pins *adap, unsigned int byte) +{ + int i; + + for (i = 0; i < 8; i++) { + adap->setclk(0); + sb_OS_WAIT_USEC_POLL(adap->data_hold); + adap->setdat(byte & 1); + sb_OS_WAIT_USEC_POLL(adap->data_setup); + adap->setclk(1); + sb_OS_WAIT_USEC_POLL(adap->clock_high); + byte >>= 1; + } +} + +/* + * Send a set of bytes to the chip. We need to pulse the MODE line + * between each byte, but never at the start nor at the end of the + * transfer. + */ +static void sendbytes(struct l3_pins *adap, const u8 *buf, + int len) +{ + int i; + + for (i = 0; i < len; i++) { + if (i) { + sb_OS_WAIT_USEC_POLL(adap->mode_hold); + adap->setmode(0); + sb_OS_WAIT_USEC_POLL(adap->mode); + } + adap->setmode(1); + sb_OS_WAIT_USEC_POLL(adap->mode_setup); + sendbyte(adap, buf[i]); + } +} + +int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len) +{ + adap->setclk(1); + adap->setdat(1); + adap->setmode(1); + sb_OS_WAIT_USEC_POLL(adap->mode); + + adap->setmode(0); + sb_OS_WAIT_USEC_POLL(adap->mode_setup); + sendbyte(adap, addr); + sb_OS_WAIT_USEC_POLL(adap->mode_hold); + + sendbytes(adap, data, len); + + adap->setclk(1); + adap->setdat(1); + adap->setmode(0); + + return len; +} + diff --git a/drivers/gpu/drm/smidrm/ddk768/l3.h b/drivers/gpu/drm/smidrm/ddk768/l3.h new file mode 100644 index 000000000000..227d9753c4a5 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/l3.h @@ -0,0 +1,22 @@ +#ifndef _L3_H_ +#define _L3_H_ + +#include +#include "ddk768_timer.h" + + +struct l3_pins { + void (*setdat)(int); + void (*setclk)(int); + void (*setmode)(int); + int data_hold; + int data_setup; + int clock_high; + int mode_hold; + int mode; + int mode_setup; +}; + +int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len); + +#endif diff --git a/drivers/gpu/drm/smidrm/ddk768/uda1345.c b/drivers/gpu/drm/smidrm/ddk768/uda1345.c new file mode 100644 index 000000000000..16ca7bbd32e8 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/uda1345.c @@ -0,0 +1,368 @@ +#include +#include "ddk768_reg.h" +#include "ddk768_help.h" +#include "uda1345.h" + +static void setdat(int v); +static void setclk(int v); +static void setmode(int v); + +static const u8 uda1346_reg[UDA1345_REGS_NUM] = +{ + /* Status, data regs */ + 0x00, 0x00, 0x80, 0xc1, +}; + +static u8 cache[sizeof(uda1346_reg)]; + +static struct uda1345_data falcon_uda1345 = +{ + .l3 = { + .setdat = setdat, + .setclk = setclk, + .setmode = setmode, + .data_hold = 1, + .data_setup = 1, + .clock_high = 1, + .mode_hold = 1, + .mode = 1, + .mode_setup = 1, + }, + .reg_cache_default = (void*)uda1346_reg, + .cache_init = 0, +}; + +static void setdat(int v) +{ + unsigned long value; + + value = peekRegisterDWord(GPIO_DATA); + pokeRegisterDWord(GPIO_DATA, 0 < v ? (value | (1 << GPIO_DATA_GPIO_CODEC_DATA_SHIFT)) : \ + (value & ~(1 << GPIO_DATA_GPIO_CODEC_DATA_SHIFT))); + +} + +static void setclk(int v) +{ + unsigned long value; + + value = peekRegisterDWord(GPIO_DATA); + pokeRegisterDWord(GPIO_DATA, 0 < v ? (value | (1 << GPIO_DATA_GPIO_CODEC_CLK_SHIFT)) : \ + (value & ~(1 << GPIO_DATA_GPIO_CODEC_CLK_SHIFT))); + + +} + +static void setmode(int v) +{ + unsigned long value; + + value = peekRegisterDWord(GPIO_DATA); + pokeRegisterDWord(GPIO_DATA, 0 < v ? (value | (1 << GPIO_DATA_GPIO_CODEC_MODE_SHIFT)) : \ + (value & ~(1 << GPIO_DATA_GPIO_CODEC_MODE_SHIFT))); + +} + +static void uda1345_GPIOInit(void) +{ + unsigned long value; + /*l3 mode control pins*/ + + value = peekRegisterDWord(GPIO_MUX); + value &= ~(1 << GPIO_MUX_GPIO_CODEC_MODE_SHIFT); + value &= ~(1 << GPIO_MUX_GPIO_CODEC_CLK_SHIFT); + value &= ~(1 << GPIO_MUX_GPIO_CODEC_DATA_SHIFT); + pokeRegisterDWord(GPIO_MUX, value); + + /*set 3 pins as input*/ + value = peekRegisterDWord(GPIO_DATA_DIRECTION); + value |= (1 << GPIO_DATA_DIRECTION_GPIO_CODEC_MODE_SHIFT); + value |= (1 << GPIO_DATA_DIRECTION_GPIO_CODEC_CLK_SHIFT); + value |= (1 << GPIO_DATA_DIRECTION_GPIO_CODEC_DATA_SHIFT); + pokeRegisterDWord(GPIO_DATA_DIRECTION, value); + + +} + +static inline unsigned int uda1345_read_reg_cache(struct uda1345_data *codec, + unsigned int reg) +{ + u8 *cache = (u8 *)codec->reg_cache; + + if (reg >= UDA1345_REGS_NUM) + return -1; + + return cache[reg]; +} + +/* + * Write the register cache + */ +static inline int uda1345_write_reg_cache(struct uda1345_data *codec, + u8 reg, unsigned int value) +{ + u8 *cache = (u8 *)codec->reg_cache; + + if (reg >= UDA1345_REGS_NUM) + return -1; + cache[reg] = value; + return 0; +} + + +/* + * Write to the uda134x registers + * + */ +static int uda1345_write(unsigned int reg, + unsigned int value) +{ + int ret; + u8 addr; + u8 data = value; + + if (reg >= UDA1345_REGS_NUM) + { + + return -1; + } + + uda1345_write_reg_cache(&falcon_uda1345, reg, value); + + switch (reg) + { + case UDA1345_STATUS: + addr = UDA1345_STATUS_ADDR; + break; + case UDA1345_DATA_VOLUME: + case UDA1345_DATA_DE_MUTE: + case UDA1345_DATA_POWER: + addr = UDA1345_DATA_ADDR; + break; + default: + break; + } + + ret = l3_write(&falcon_uda1345.l3, + addr, &data, 1); + + if (ret != 1) + return -1; + + return 0; +} + +int uda1345_setsysclkfs(enum uda1345_sysclkf sysclk) +{ + u8 data; + + data = uda1345_read_reg_cache(&falcon_uda1345,UDA1345_STATUS); + + data &= ~UDA1345_SYSCLKF_MASK; + switch(sysclk) + { + case SYSCLKF_512FS: + data |= UDA1345_SYSCLKF_512FS; + break; + case SYSCLKF_384FS: + data |= UDA1345_SYSCLKF_384FS; + break; + case SYSCLKF_256FS: + data |= UDA1345_SYSCLKF_256FS; + break; + default: + return -1; + } + + return uda1345_write(UDA1345_STATUS,data); + +} + +int uda1345_setformat(enum uda1345_input_format informat) +{ + + u8 data; + data = uda1345_read_reg_cache(&falcon_uda1345,UDA1345_STATUS); + data &= ~UDA1345_FORMAT_MASK; + switch(informat) + { + case I2S_BUS: + data |= UDA1345_I2S_BUS; + break; + case LSB_16BITS: + data |= UDA1345_LSB_16BITS; + break; + case LSB_18BITS: + data |= UDA1345_LSB_18BITS; + break; + case LSB_20BITS: + data |= UDA1345_LSB_20BITS; + break; + case MSB_JUSTIFIED: + data |= UDA1345_MSB_JUSTIFIED; + break; + case MSB_OUTPUT_LSB_16BITS_INPUT: + data |= UDA1345_MSB_OUTPUT_LSB_16BITS_INPUT; + break; + case MSB_OUTPUT_LSB_18BITS_INPUT: + data |= UDA1345_MSB_OUTPUT_LSB_18BITS_INPUT; + break; + case MSB_OUTPUT_LSB_20BITS_INPUT: + data |= UDA1345_MSB_OUTPUT_LSB_20BITS_INPUT; + break; + default: + return -1; + } + return uda1345_write(UDA1345_STATUS,data); + +} + + +int uda1345_setdcfilter(enum uda1345_dc_filter onoff) +{ + + u8 data; + data = uda1345_read_reg_cache(&falcon_uda1345,UDA1345_STATUS); + data &= ~UDA1345_DC_MASK; + switch(onoff) + { + case NO_DC_FILTERING: + data |= UDA1345_NO_DC_FILTERING; + break; + case DC_FILTERING: + data |= UDA1345_DC_FILTERING; + break; + default: + return -1; + } + return uda1345_write(UDA1345_STATUS,data); + +} + + +int uda1345_setvolume(u8 dB) +{ + + u8 data; + data = uda1345_read_reg_cache(&falcon_uda1345,UDA1345_DATA_VOLUME); + data &= ~UDA1345_VOLUME_MASK; + data |= (dB&UDA1345_VOLUME_MASK); + return uda1345_write(UDA1345_DATA_VOLUME,data); + +} + + +int uda1345_setdemphasis(enum uda1345_de_emphasis emphasis) +{ + u8 data; + data = uda1345_read_reg_cache(&falcon_uda1345,UDA1345_DATA_DE_MUTE); + data &= ~UDA1345_DE_EMPHASIS_MASK; + switch(emphasis) + { + case NO_DE_EMPHASIS: + data |= UDA1345_NO_DE_EMPHASIS; + break; + case DE_EMPHASIS_32KHZ: + data |= UDA1345_DE_EMPHASIS_32KHZ; + break; + case DE_EMPHASIS_44KHZ: + data |= UDA1345_DE_EMPHASIS_44KHZ; + break; + case DE_EMPHASIS_48KHZ: + data |= UDA1345_DE_EMPHASIS_48KHZ; + break; + default: + + return -1; + } + return uda1345_write(UDA1345_DATA_DE_MUTE,data); + +} + +int uda1345_setmute(enum uda1345_mute onoff) +{ + u8 data; + data = uda1345_read_reg_cache(&falcon_uda1345,UDA1345_DATA_DE_MUTE); + data &= ~UDA1345_MUTE_MASK; + switch(onoff) + { + case NO_MUTE: + data |= UDA1345_NO_MUTE; + break; + case MUTE: + data |= UDA1345_MUTE; + break; + default: + return -1; + } + return uda1345_write(UDA1345_DATA_DE_MUTE,data); + +} + +int uda1345_setpower(enum uda1345_power onoff) +{ + u8 data; + data = uda1345_read_reg_cache(&falcon_uda1345,UDA1345_DATA_POWER); + data &= ~UDA1345_ADC_DAC_MASK; + switch(onoff) + { + case ADCOFF_DACOFF: + data |= UDA1345_ADCOFF_DACOFF; + break; + case ADCOFF_DACON: + data |= UDA1345_ADCOFF_DACON; + break; + case ADCON_DACOFF: + data |= UDA1345_ADCON_DACOFF; + break; + case ADCON_DACON: + data |= UDA1345_ADCON_DACON; + break; + default: + return -1; + } + return uda1345_write(UDA1345_DATA_POWER,data); + +} + +int uda1345_init(void) +{ + uda1345_GPIOInit(); + + if(0 == falcon_uda1345.cache_init) + { + falcon_uda1345.cache_size = sizeof(uda1346_reg); + falcon_uda1345.reg_cache = cache; + memcpy(falcon_uda1345.reg_cache, falcon_uda1345.reg_cache_default,falcon_uda1345.cache_size ); + falcon_uda1345.cache_init = 1; + } + + if(uda1345_setsysclkfs(SYSCLKF_384FS)) + return -1; + if(uda1345_setformat(I2S_BUS)) + return -1; + if(uda1345_setdcfilter(NO_DC_FILTERING)) + return -1; + if(uda1345_setdemphasis(NO_DE_EMPHASIS)) + return -1; + if(uda1345_setvolume(0)) + return -1; + if(uda1345_setmute(MUTE)) + return -1; + if(uda1345_setpower(ADCOFF_DACOFF)) + return -1; + + return 0; +} + +int uda1345_deinit(void) +{ + uda1345_setpower(ADCOFF_DACOFF); + if(falcon_uda1345.cache_init&&falcon_uda1345.reg_cache) + { + falcon_uda1345.reg_cache = NULL; + falcon_uda1345.cache_init = 0; + } + return 0; +} + diff --git a/drivers/gpu/drm/smidrm/ddk768/uda1345.h b/drivers/gpu/drm/smidrm/ddk768/uda1345.h new file mode 100644 index 000000000000..926b2c72f2a6 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/uda1345.h @@ -0,0 +1,131 @@ +#ifndef _UDA1345_CODEC_H +#define _UDA1345_CODEC_H +#include "l3.h" + + +#define UDA1345_L3ADDR 5 +#define UDA1345_DATA_ADDR ((UDA1345_L3ADDR << 2) | 0) +#define UDA1345_STATUS_ADDR ((UDA1345_L3ADDR << 2) | 2) + + +/* UDA1345 registers */ +#define UDA1345_STATUS 0 +#define UDA1345_DATA_VOLUME 1 +#define UDA1345_DATA_DE_MUTE 2 +#define UDA1345_DATA_POWER 3 + +#define UDA1345_REGS_NUM 4 + +/*UDA1345 System clock frequency*/ +#define UDA1345_SYSCLKF_MASK (3 << 4) +#define UDA1345_SYSCLKF_512FS (0 << 4) +#define UDA1345_SYSCLKF_384FS (1 << 4) +#define UDA1345_SYSCLKF_256FS (2 << 4) +enum uda1345_sysclkf +{ + SYSCLKF_512FS = 0, + SYSCLKF_384FS, + SYSCLKF_256FS, +}; + +/*UDA1345 data input format*/ +#define UDA1345_FORMAT_MASK (7 << 1) +#define UDA1345_I2S_BUS (0 << 1) +#define UDA1345_LSB_16BITS (1 << 1) +#define UDA1345_LSB_18BITS (2 << 1) +#define UDA1345_LSB_20BITS (3 << 1) +#define UDA1345_MSB_JUSTIFIED (4 << 1) +#define UDA1345_MSB_OUTPUT_LSB_16BITS_INPUT (5 << 1) +#define UDA1345_MSB_OUTPUT_LSB_18BITS_INPUT (6 << 1) +#define UDA1345_MSB_OUTPUT_LSB_20BITS_INPUT (7 << 1) +enum uda1345_input_format +{ + I2S_BUS = 0, + LSB_16BITS, + LSB_18BITS, + LSB_20BITS, + MSB_JUSTIFIED, + MSB_OUTPUT_LSB_16BITS_INPUT, + MSB_OUTPUT_LSB_18BITS_INPUT, + MSB_OUTPUT_LSB_20BITS_INPUT, +}; + +/*UDA1345 dc filter*/ +#define UDA1345_DC_MASK 1 +#define UDA1345_DC_FILTERING 1 +#define UDA1345_NO_DC_FILTERING 0 +enum uda1345_dc_filter +{ + NO_DC_FILTERING = 0, + DC_FILTERING, +}; + +/*UDA1345 volume*/ +#define UDA1345_VOLUME_MASK 0x3f +#define UDA1345_VOLUME_N5DB 6 +#define UDA1345_VOLUME_N10DB 0xB + +/*UDA1345 DE-EMPHASIS*/ +#define UDA1345_DE_EMPHASIS_MASK (3 << 3) +#define UDA1345_NO_DE_EMPHASIS (0 << 3) +#define UDA1345_DE_EMPHASIS_32KHZ (1 << 3) +#define UDA1345_DE_EMPHASIS_44KHZ (2 << 3) +#define UDA1345_DE_EMPHASIS_48KHZ (3 << 3) +enum uda1345_de_emphasis +{ + NO_DE_EMPHASIS = 0, + DE_EMPHASIS_32KHZ, + DE_EMPHASIS_44KHZ, + DE_EMPHASIS_48KHZ, +}; + +/*UDA1345 mute*/ +#define UDA1345_MUTE_MASK (1 << 2) +#define UDA1345_NO_MUTE (0 << 2) +#define UDA1345_MUTE (1 << 2) +enum uda1345_mute +{ + NO_MUTE = 0, + MUTE, +}; + +/*UDA1345 power control*/ +#define UDA1345_ADC_DAC_MASK 3 +#define UDA1345_ADCOFF_DACOFF 0 +#define UDA1345_ADCOFF_DACON 1 +#define UDA1345_ADCON_DACOFF 2 +#define UDA1345_ADCON_DACON 3 +enum uda1345_power +{ + ADCOFF_DACOFF = 0, + ADCOFF_DACON, + ADCON_DACOFF, + ADCON_DACON, +}; + + +struct uda1345_data +{ + struct l3_pins l3; + void * reg_cache_default; + void * reg_cache; + unsigned int cache_size; + unsigned int cache_init : 1; + +}; + + + + + +int uda1345_setsysclkfs(enum uda1345_sysclkf sysclk); +int uda1345_setformat(enum uda1345_input_format informat); +int uda1345_setdcfilter(enum uda1345_dc_filter onoff); +int uda1345_setvolume(u8 dB); +int uda1345_setdemphasis(enum uda1345_de_emphasis emphasis); +int uda1345_setmute(enum uda1345_mute onoff); +int uda1345_setpower(enum uda1345_power onoff); +int uda1345_init(void); +int uda1345_deinit(void); +#endif + diff --git a/drivers/gpu/drm/smidrm/ddk768/vdif.h b/drivers/gpu/drm/smidrm/ddk768/vdif.h new file mode 100644 index 000000000000..36d11d6daa54 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/vdif.h @@ -0,0 +1,63 @@ +/******************************************************************* +* +* Copyright (c) 2009 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* vdif.h --- SMI DDK +* This file contains the video display information format structure +* +*******************************************************************/ +#ifndef _VDIF_H_ +#define _VDIF_H_ + +/* Sync polarity */ +typedef enum _vdif_sync_polarity_t +{ + VDIF_SYNC_NEGATIVE = 0, + VDIF_SYNC_POSITIVE +} vdif_sync_polarity_t; + +/* Scan type */ +typedef enum _vdif_scan_type_t +{ + VDIF_NONINTERLACED = 0, + VDIF_INTERLACED +} vdif_scan_type_t; + +/* Monitor Timing Information */ +typedef struct _video_display_information_format_t +{ + unsigned long pixelClock; + unsigned long characterWidth; + vdif_scan_type_t scanType; + + unsigned long horizontalFrequency; + vdif_sync_polarity_t horizontalSyncPolarity; + unsigned long horizontalTotal; + unsigned long horizontalActive; + unsigned long horizontalBlankStart; + unsigned long horizontalBlankTime; + unsigned long horizontalSyncStart; + unsigned long horizontalRightBorder; + unsigned long horizontalFrontPorch; + unsigned long horizontalSyncWidth; + unsigned long horizontalBackPorch; + unsigned long horizontalLeftBorder; + + unsigned long verticalFrequency; + vdif_sync_polarity_t verticalSyncPolarity; + unsigned long verticalTotal; + unsigned long verticalActive; + unsigned long verticalBlankStart; + unsigned long verticalBlankTime; + unsigned long verticalSyncStart; + unsigned long verticalBottomBorder; + unsigned long verticalFrontPorch; + unsigned long verticalSyncHeight; + unsigned long verticalBackPorch; + unsigned long verticalTopBorder; +} vdif_t; + +#endif /* _VDIF_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk768/wm8978.c b/drivers/gpu/drm/smidrm/ddk768/wm8978.c new file mode 100644 index 000000000000..07e1a56b0970 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/wm8978.c @@ -0,0 +1,231 @@ + +#include +#include "ddk768_reg.h" +#include "ddk768_help.h" +#include "ddk768_swi2c.h" +#include "ddk768_hwi2c.h" +#include "wm8978.h" + +static unsigned short WM8978_REGVAL[58]= +{ + 0X0000,0X0000,0X0000,0X0000,0X0050,0X0000,0X0140,0X0000, + 0X0000,0X0000,0X0000,0X00FF,0X00FF,0X0000,0X0100,0X00FF, + 0X00FF,0X0000,0X012C,0X002C,0X002C,0X002C,0X002C,0X0000, + 0X0032,0X0000,0X0000,0X0000,0X0000,0X0000,0X0000,0X0000, + 0X0038,0X000B,0X0032,0X0000,0X0008,0X000C,0X0093,0X00E9, + 0X0000,0X0000,0X0000,0X0000,0X0003,0X0010,0X0010,0X0100, + 0X0100,0X0002,0X0001,0X0001,0X0039,0X0039,0X0039,0X0039, + 0X0001,0X0001 +}; + +unsigned char WM8978_Write_Reg(unsigned char reg, unsigned short val) +{ + unsigned char res; + unsigned char RegAddr; + unsigned char RegValue; + RegAddr = (reg<<1)|((unsigned char)((val>>8)&0x01)); + RegValue = (unsigned char)val; + if(!hwi2c_en) + res = ddk768_swI2CWriteReg(WM8978_ADDR, RegAddr, RegValue); + else + res = ddk768_hwI2CWriteReg(0, WM8978_ADDR, RegAddr, RegValue); + + if(res == 0) + WM8978_REGVAL[reg]=val; + return res; +} + +unsigned short WM8978_Read_Reg(unsigned char reg) +{ + return WM8978_REGVAL[reg]; +} + +unsigned char WM8978_Init(void) +{ + unsigned char Res; + + if(hwi2c_en) + ddk768_hwI2CInit(0); + else + ddk768_swI2CInit(30, 31); + + + Res = WM8978_Write_Reg(0, 0); //软å¤ä½WM8978 + if(Res) + return 1; //å‘逿Œ‡ä»¤å¤±è´¥,WM8978异常 + /* Set volume to 0 can improve the noise when init codec */ + WM8978_HPvol_Set(0, 0); //耳机音é‡0-63(左和å³åˆ†å¼€è®¾ç½®ï¼‰ + WM8978_SPKvol_Set(0); //å–‡å­éŸ³é‡0-63 + WM8978_Write_Reg(1, 0x1B); //R1,MICEN设置为1(MIC使能),BIASEN设置为1(模拟器工作),VMIDSEL[1:0]设置为:11(5K) + WM8978_Write_Reg(2, 0x1B0); //R2,ROUT1,LOUT1输出使能(耳机å¯ä»¥å·¥ä½œ),BOOSTENR,BOOSTENL使能 + WM8978_Write_Reg(3, 0x6C); //R3,LOUT2,ROUT2输出使能(å–‡å­å·¥ä½œ),RMIX,LMIX使能 + WM8978_Write_Reg(6, 0); //R6,MCLK由外部æä¾› + WM8978_Write_Reg(43, 1<<4);//R43,INVROUT2åå‘,é©±åŠ¨å–‡å­ + WM8978_Write_Reg(47, 1<<8);//R47设置,PGABOOSTL,左通é“MIC获得20å€å¢žç›Š + WM8978_Write_Reg(48, 1<<8);//R48设置,PGABOOSTR,å³é€šé“MIC获得20å€å¢žç›Š + WM8978_Write_Reg(49, 1<<1);//R49,TSDEN,å¼€å¯è¿‡çƒ­ä¿æŠ¤ + WM8978_Write_Reg(10, 1<<3);//R10,SOFTMUTE关闭,128x采样,最佳SNR + WM8978_Write_Reg(14, 1<<3);//R14,ADC 128x采样率 + + /* Playback and record setup */ + + WM8978_I2S_Cfg(2, 0); //设置I2SæŽ¥å£æ¨¡å¼ï¼Œæ•°æ®ä½æ•°ä¸éœ€è¦è®¾ç½®ï¼Œæ’­æ”¾ä»Žè®¾å¤‡ä¸ä½¿ç”¨ + WM8978_ADDA_Cfg(1, 1); //å¼€å¯DACå’ŒADC + WM8978_Input_Cfg(1, 1, 1); //å¼€å¯Line in输入通é“,MICå’ŒAUX + WM8978_MIC_Gain(20); //MIC增益设置,MIC录制时å¯å¼€å¯ + WM8978_Output_Cfg(1, 0); //å¼€å¯DAC输出,关闭BYPASS输出 + + /* Make sure the IIC is idle when do this operation */ + WM8978_HPvol_Set(50, 50); + WM8978_SPKvol_Set(50); + + return 0; +} + +void WM8978_DeInit(void) +{ + if(hwi2c_en) + ddk768_hwI2CClose(0); + else + ddk768_swI2CInit(30, 31); + + /* To Do: Here should be read device register not globle array.*/ + WM8978_Write_Reg(0, 0); +} + +//WM8978 DAC/ADCé…ç½® +//adcen:adc使能(1)/关闭(0) +//dacen:dac使能(1)/关闭(0) +void WM8978_ADDA_Cfg(unsigned char dacen, unsigned char adcen) +{ + unsigned short regval; + regval = WM8978_Read_Reg(3); //读å–R3 + if(dacen) + regval |= 3<<0; //R3最低2个ä½è®¾ç½®ä¸º1,å¼€å¯DACR&DACL + else + regval &= ~(3<<0); //R3最低2ä¸ªä½æ¸…é›¶,关闭DACR&DACL. + WM8978_Write_Reg(3, regval); //设置R3 + regval = WM8978_Read_Reg(2); //读å–R2 + if(adcen) + regval |= 3<<0; //R2最低2个ä½è®¾ç½®ä¸º1,å¼€å¯ADCR&ADCL + else + regval &= ~(3<<0); //R2最低2ä¸ªä½æ¸…é›¶,关闭ADCR&ADCL. + WM8978_Write_Reg(2, regval); //设置R2 +} + +//WM8978 输入通é“é…ç½® +//micen:MICå¼€å¯(1)/关闭(0) +//lineinen:Line Inå¼€å¯(1)/关闭(0) +//auxen:auxå¼€å¯(1)/关闭(0) +void WM8978_Input_Cfg(unsigned char micen, unsigned char lineinen, unsigned char auxen) +{ + unsigned short regval; + regval = WM8978_Read_Reg(2); //读å–R2 + if(micen) + regval |= 3<<2; //å¼€å¯INPPGAENR,INPPGAENL(MICçš„PGA放大) + else + regval &= ~(3<<2); //关闭INPPGAENR,INPPGAENL. + WM8978_Write_Reg(2, regval); //设置R2 + regval = WM8978_Read_Reg(44);//读å–R44 + if(micen) + regval |= 3<<4|3<<0; //å¼€å¯LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA. + else + regval &= ~(3<<4|3<<0); //关闭LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA. + WM8978_Write_Reg(44, regval); //设置R44 + if(lineinen) + WM8978_LINEIN_Gain(5); //LINE IN 0dB增益 + else + WM8978_LINEIN_Gain(0); //关闭LINE IN + if(auxen) + WM8978_AUX_Gain(7);//AUX 6dB增益 + else + WM8978_AUX_Gain(0);//关闭AUX输入 +} + +//WM8978 MIC增益设置(ä¸åŒ…括BOOSTçš„20dB,MIC-->ADC输入部分的增益) +//gain:0~63,对应-12dB~35.25dB,0.75dB/Step +void WM8978_MIC_Gain(unsigned char gain) +{ + gain &= 0x3F; + WM8978_Write_Reg(45, gain); //R45,左通é“PGA设置 + WM8978_Write_Reg(46, gain|1<<8); //R46,å³é€šé“PGA设置 +} + +//WM8978 L2/R2(也就是Line In)增益设置(L2/R2-->ADC输入部分的增益) +//gain:0~7,0表示通é“ç¦æ­¢,1~7,对应-12dB~6dB,3dB/Step +void WM8978_LINEIN_Gain(unsigned char gain) +{ + unsigned short regval; + gain &= 0x07; + regval = WM8978_Read_Reg(47); //读å–R47 + regval &= ~(7<<4); //清除原æ¥çš„设置 + WM8978_Write_Reg(47, regval|gain<<4); //设置R47 + regval = WM8978_Read_Reg(48); //读å–R48 + regval &= ~(7<<4); //清除原æ¥çš„设置 + WM8978_Write_Reg(48,regval|gain<<4); //设置R48 +} + +//WM8978 AUXR,AUXL(PWM音频部分)增益设置(AUXR/L-->ADC输入部分的增益) +//gain:0~7,0表示通é“ç¦æ­¢,1~7,对应-12dB~6dB,3dB/Step +void WM8978_AUX_Gain(unsigned char gain) +{ + unsigned short regval; + gain &= 0x07; + regval = WM8978_Read_Reg(47); //读å–R47 + regval &= ~(7<<0); //清除原æ¥çš„设置 + WM8978_Write_Reg(47, regval|gain<<0); //设置R47 + regval = WM8978_Read_Reg(48); //读å–R48 + regval &= ~(7<<0); //清除原æ¥çš„设置 + WM8978_Write_Reg(48, regval|gain<<0); //设置R48 +} + +//WM8978 输出é…ç½® +//dacen:DAC输出(放音)å¼€å¯(1)/关闭(0) +//bpsen:Bypass输出(录音,包括MIC,LINE IN,AUXç­‰)å¼€å¯(1)/关闭(0) +void WM8978_Output_Cfg(unsigned char dacen, unsigned char bpsen) +{ + unsigned short regval = 0; + if(dacen) + regval |= 1<<0; //DAC输出使能 + if(bpsen) + { + regval |= 1<<1; //BYPASS使能 + regval |= 5<<2; //0dB增益 + } + WM8978_Write_Reg(50,regval); //R50设置 + WM8978_Write_Reg(51,regval); //R51设置 +} + +//设置耳机左å³å£°é“éŸ³é‡ +//voll:左声é“音é‡(0~63) +//volr:å³å£°é“音é‡(0~63) +void WM8978_HPvol_Set(unsigned char voll, unsigned char volr) +{ + voll &= 0x3F; + volr &= 0x3F; //é™å®šèŒƒå›´ + if(voll == 0)voll |= 1<<6; //音é‡ä¸º0æ—¶,直接mute + if(volr == 0)volr |= 1<<6; //音é‡ä¸º0æ—¶,直接mute + WM8978_Write_Reg(52, voll); //R52,耳机左声é“音é‡è®¾ç½® + WM8978_Write_Reg(53, volr|(1<<8)); //R53,耳机å³å£°é“音é‡è®¾ç½®,åŒæ­¥æ›´æ–°(HPVU=1) +} + +//设置喇å­éŸ³é‡ +//voll:左声é“音é‡(0~63) +void WM8978_SPKvol_Set(unsigned char volx) +{ + volx &= 0x3F;//é™å®šèŒƒå›´ + if(volx == 0)volx |= 1<<6; //音é‡ä¸º0æ—¶,直接mute + WM8978_Write_Reg(54, volx); //R54,å–‡å­å·¦å£°é“音é‡è®¾ç½® + WM8978_Write_Reg(55, volx|(1<<8)); //R55,å–‡å­å³å£°é“音é‡è®¾ç½®,åŒæ­¥æ›´æ–°(SPKVU=1) +} + +//设置I2Så·¥ä½œæ¨¡å¼ +//fmt:0,LSB(å³å¯¹é½);1,MSB(左对é½);2,飞利浦标准I2S;3,PCM/DSP; +//len:0,16ä½;1,20ä½;2,24ä½;3,32ä½; +void WM8978_I2S_Cfg(unsigned char fmt, unsigned char len) +{ + fmt &= 0x03; + len &= 0x03; //é™å®šèŒƒå›´ + WM8978_Write_Reg(4, (fmt<<3)|(len<<5)); //R4,WM8978工作模å¼è®¾ç½® + +} diff --git a/drivers/gpu/drm/smidrm/ddk768/wm8978.h b/drivers/gpu/drm/smidrm/ddk768/wm8978.h new file mode 100644 index 000000000000..0fb554297396 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk768/wm8978.h @@ -0,0 +1,23 @@ +#ifndef __WM8978_H +#define __WM8978_H + +#define WM8978_ADDR 0x34 + +unsigned char WM8978_Write_Reg(unsigned char reg, unsigned short val); +unsigned short WM8978_Read_Reg(unsigned char reg); +unsigned char WM8978_Init(void); +void WM8978_DeInit(void); +void WM8978_ADDA_Cfg(unsigned char dacen, unsigned char adcen); +void WM8978_Output_Cfg(unsigned char dacen, unsigned char bpsen); +void WM8978_HPvol_Set(unsigned char voll, unsigned char volr); +void WM8978_SPKvol_Set(unsigned char volx); +void WM8978_I2S_Cfg(unsigned char fmt, unsigned char len); +void WM8978_Input_Cfg(unsigned char micen, unsigned char lineinen, unsigned char auxen); +void WM8978_MIC_Gain(unsigned char gain); +void WM8978_LINEIN_Gain(unsigned char gain); +void WM8978_AUX_Gain(unsigned char gain); + +extern int hwi2c_en; + + +#endif diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_chip.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_chip.c new file mode 100644 index 000000000000..01a5ad6bfec1 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_chip.c @@ -0,0 +1,192 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* CHIP.C --- SMI DDK +* This file contains the source code for the mode table. +* +*******************************************************************/ +#include "ddk770_reg.h" +#include "ddk770_chip.h" +#include "ddk770_hardware.h" +#include "ddk770_helper.h" +#include "ddk770_power.h" +#include "ddk770_clock.h" +#include "ddk770_help.h" +#include "ddk770_ddkdebug.h" +#include "ddk770_display.h" + + +/* + * This function returns frame buffer memory size in Byte units. + */ +unsigned long ddk770_getFrameBufSize() +{ + +#if 1 + unsigned long strapPin; + unsigned long rValue; + + strapPin = (FIELD_VAL_GET(peekRegisterDWord(STRAP_PINS2), STRAP_PINS2, MEM_SIZE) << 1 ) | FIELD_VAL_GET(peekRegisterDWord(STRAP_PINS1), STRAP_PINS1, MEM_SIZE) ; + + switch(strapPin) + { + case 0x02: + rValue = MB(512); + break; + case 0x01: + rValue = MB(1024); + break; + case 0x00: + rValue = MB(2048); + break; + case 0x03: + default: /* default size of 512MB. Don't need to do anything */ + rValue = MB(256); + break; + } + return(rValue); +#else + return SMI_MEMORY_SIZE_SM770; +#endif + +} + + + +/* + * This function returns the logical chip type defined in chip.h. + * Currently, it's either SM768 or unknown. + */ +logical_chip_type_t ddk770_getChipType() +{ + logical_chip_type_t chip; + + chip = SM770; + + return chip; +} + +/* + * Return a char string name of the current chip. + * It's convenient for application need to display the chip name. + */ +char *ddk770_getChipTypeString() +{ + char * chipName; + + switch(ddk770_getChipType()) + { + case SM768: + chipName = "SM770"; + break; + default: + chipName = "Unknown"; + break; + } + + return chipName; +} + +/* + * Initialize a single chip and environment according to input parameters. + * Use this function when don't want to use default setting of ddk770_initChip(). + * + * Input: initchip_param_t structure. + * + * Return: 0 (or NO_ERROR) if successful. + * -1 if fail. + * + */ +long ddk770_initChipParamEx(initchip_param_t * pInitParam) +{ + unsigned long ulReg; + + /* Check if we know this chip */ + if (ddk770_getChipType() == SM_UNKNOWN){ + return -1; + } + + if(ddk770_GetChipRev() == CHIP_REV_AB) + pokeRegisterDWord(0x130, 0x78000000); + + if (pInitParam->setAllEngOff == 1) + { + ulReg = peekRegisterDWord(VIDEO_DISPLAY_CTRL); + ulReg = FIELD_SET(ulReg, VIDEO_DISPLAY_CTRL, PLANE, DISABLE); + ulReg = FIELD_SET(ulReg, VIDEO_DISPLAY_CTRL, JPUP, DISABLE); + pokeRegisterDWord(VIDEO_DISPLAY_CTRL, ulReg); /* Channel 0 */ + pokeRegisterDWord(VIDEO_DISPLAY_CTRL+CHANNEL_OFFSET, ulReg); /* Channel 1 */ + pokeRegisterDWord(VIDEO_DISPLAY_CTRL+CHANNEL_OFFSET2, ulReg); /* Channel 2 */ + + /* Disable alpha plane, if a former application left it on */ + ulReg = peekRegisterDWord(ALPHA_DISPLAY_CTRL); + ulReg = FIELD_SET(ulReg, ALPHA_DISPLAY_CTRL, PLANE, DISABLE); + pokeRegisterDWord(ALPHA_DISPLAY_CTRL, ulReg); /* Channel 0 */ + pokeRegisterDWord(ALPHA_DISPLAY_CTRL+CHANNEL_OFFSET, ulReg); /* Channel 1 */ + pokeRegisterDWord(ALPHA_DISPLAY_CTRL+CHANNEL_OFFSET2, ulReg); /* Channel 2 */ + + /* Disable hardware cursor, if a former application left it on */ + ulReg = peekRegisterDWord(HWC_CONTROL); + ulReg = FIELD_SET(ulReg, HWC_CONTROL, MODE, DISABLE); + pokeRegisterDWord(HWC_CONTROL, ulReg); /* Channel 0 */ + pokeRegisterDWord(HWC_CONTROL+CHANNEL_OFFSET, ulReg); /* Channel 1 */ + pokeRegisterDWord(HWC_CONTROL+CHANNEL_OFFSET2, ulReg); /* Channel 2 */ + + clearDCOutput(); + } + + /* We can add more initialization as needed. */ + + + return 0; +} + +/* + * Initialize the chip with default parameters. + * + * Input: + * argc: + * argv: memory and register delay what we want. + * + * Return: 0 (or NO_ERROR) if successful. + * -1 if fail. + */ +long ddk770_initChip(void) +{ + initchip_param_t initParam; + + /* Initialize the chip with some default parameters */ + + initParam.setAllEngOff = 1; + + + return(ddk770_initChipParamEx(&initParam)); + +} + +/* + We may not need this function in the future. + Just during validation, we want the code able to work + dynamically in both FPGA and ASIC. +*/ +unsigned long isFPGA() +{ + + return 0; + +} + + +unsigned int ddk770_GetChipRev(void) +{ + + return peekRegisterDWord(CHIP_REV); +} + + + + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_chip.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_chip.h new file mode 100644 index 000000000000..ecae7f23d587 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_chip.h @@ -0,0 +1,85 @@ +/******************************************************************* +* +* Copyright (c) 2008 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* CHIP.H --- SMI DDK +* This file contains the source code for the SM750/SM718 chip. +* +*******************************************************************/ +#ifndef _DDK770_CHIP_H_ +#define _DDK770_CHIP_H_ + +/* This is all the chips recognized by this library */ +typedef enum _logical_chip_type_t +{ + SM_UNKNOWN = 0, + SM768 = 1, + SM770 = 2 +} +logical_chip_type_t; + +/* input struct to initChipParam() function. +*/ +typedef struct _initchip_param_t +{ + + unsigned short setAllEngOff; /* 0 = leave all engine state untouched. + 1 = make sure they are off: 2D, Overlay, + video alpha, alpha, hardware cursors + */ + + /* More initialization parameter can be added if needed */ +} +initchip_param_t; + +/* + * This function returns frame buffer memory size in Byte units. + */ +unsigned long ddk770_getFrameBufSize(void); + +/* + * This function returns the logical chip type defined in chip.h + * It is one of the following: SM501, SM502, SM107, SM718, SM 750 or + * SM_UNKNOWN. + */ +logical_chip_type_t ddk770_getChipType(void); + +/* + * Return a char string name of the current chip. + * It's convenient for application need to display the chip name. + */ +char * ddk770_getChipTypeString(void); + +/* + * Initialize a single chip and environment according to input parameters. + * + * Input: initchip_param_t structure. + * + * Return: 0 (or NO_ERROR) if successful. + * -1 if fail. + * + */ +long ddk770_initChipParamEx(initchip_param_t * pInitParam); + +/* + * Initialize the chip with default parameters. + * + * Input: + * argc: + * argv: memory and register delay what we want. + * + * Return: 0 (or NO_ERROR) if successful. + * -1 if fail. + */ +long ddk770_initChip(void); + + +unsigned long isFPGA(void); + +unsigned int ddk770_GetChipRev(void); + +#endif /* _CHIP_H_ */ + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_clock.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_clock.c new file mode 100644 index 000000000000..c985ae47e78f --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_clock.c @@ -0,0 +1,589 @@ +/******************************************************************* +* +* Copyright (c) 2024 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* CLOCK.C --- SM770 DDK +* This file contains source code for the SM770 PLL's +* +*******************************************************************/ +#include +#include +#include "ddk770_reg.h" +#include "ddk770_hardware.h" +#include "ddk770_chip.h" +#include "ddk770_helper.h" +#include "ddk770_clock.h" +#include "ddk770_help.h" +#include "ddk770_mode.h" +#include "ddk770_ddkdebug.h" +/* + * A local function to calculate the output frequency of a given PLL structure. + * + */ +static unsigned long ddk770_calcPLL(pll_value_t *pPLL) +{ + unsigned long pllClk, vcoPower; + + /* Convert everything in Khz range in order to avoid calculation overflow */ + pPLL->inputFreq /= 1000; + + /* Work out 2 to the power of (VCO + 1) */ + vcoPower = ddk770_twoToPowerOfx(pPLL->VCO + 1); + + pllClk = (pPLL->inputFreq * pPLL->DIV) / vcoPower; + + /* Restore input frequency from Khz to hz unit */ + pPLL->inputFreq *= 1000; + pllClk *= 1000; + + // printk("Acture pixel clock = %d\n",pllClk); + + return pllClk; +} + +/* + * Given a requested clock frequency, this function calculates the + * best INT, VCO values for the PLL. + * + * Input: Requested pixel clock in Hz unit. + * The followiing fields of PLL has to be set up properly: + * pPLL->inputFreq. + * + * Output: Update the PLL structure with the proper values + * Return: The actual clock in Hz that the PLL is able to set up. + * + */ +unsigned long ddk770_calcPllValue( +unsigned long ulRequestClk, /* Required pixel clock in Hz unit */ +pll_value_t *pPLL /* Structure to hold the value to be set in PLL */ +) +{ + unsigned long DIVIDER, VCO, diff, pllClk, vcoPower, tempRequestClk; + unsigned long bestDiff = 0xffffffff; /* biggest 32 bit unsigned number */ + + unsigned long DivMin,DivMax; + + if(pPLL->inputFreq ==12500000){ + DivMin = 64; + DivMax = 128; + }else{ + DivMin = 32; + DivMax = 64; + } + // printk("divmin=%d,divmax=%d\n",DivMin,DivMax); + + /* Init PLL structure to known states */ + pPLL->DIV = 0; + pPLL->VCO = 0; + + + /* Convert everything in Khz range in order to avoid calculation overflow */ + pPLL->inputFreq /= 1000; + tempRequestClk = ulRequestClk / 1000; + + /* If the requested clock is higher than 1 GHz, then set it to the maximum, which is + 1 GHz. */ + if (tempRequestClk > MHz(1)) + tempRequestClk = MHz(1); + + /* The maximum of VCO is 5. */ + for (VCO=0; VCO<=7; VCO++) + { + /* Work out 2 to the power of (VCO + 1) */ + vcoPower = ddk770_twoToPowerOfx(VCO + 1); + + DIVIDER = ddk770_roundedDiv(tempRequestClk * vcoPower , pPLL->inputFreq); + + /* 32 <= INT <= 64 */ + if ((DIVIDER >= DivMin) && (DIVIDER <= DivMax)) + { + /* Calculate the actual clock for a given INT & FRAC */ + pllClk = (pPLL->inputFreq * DIVIDER) / vcoPower; + + /* How much are we different from the requirement */ + diff = ddk770_absDiff(pllClk, tempRequestClk); + + if (diff < bestDiff) + { + bestDiff = diff; + /* Store DIV and VCO values */ + pPLL->DIV = DIVIDER; + pPLL->VCO = VCO; + } + + } + } + + /* Restore input frequency from Khz to hz unit */ + pPLL->inputFreq *= 1000; + + /* Output debug information */ + // printk("ddk770_calcPllValue: Requested Frequency = %d\n", ulRequestClk); + // printk("ddk770_calcPllValue: Input CLK = %dHz, DIV=%d, VCO=%d,\n", + // pPLL->inputFreq, pPLL->DIV, pPLL->VCO); + + /* Return actual frequency that the PLL can set */ + return ddk770_calcPLL(pPLL); +} + +/* + * Set up the corresponding bit field of the programmable PLL register. + * + * Input: Pointer to PLL structure with all values set up properly. + * + */ +unsigned long ddk770_formatPllReg(pll_value_t *pPLL, unsigned long origPllValue ) +{ + unsigned long ulPllReg = 0; + + /* Note that all PLL's have the same format. Here, we just use Panel PLL parameter + to work out the bit fields in the register. + On returning a 32 bit number, the value can be applied to any PLL in the calling function. + */ + if(pPLL->inputFreq == 12500000){ + printk("Use 12.5MHz input clock\n"); + ulPllReg = FIELD_SET(origPllValue,VCLK_PLL, PRESEL,125); + ulPllReg = FIELD_VALUE(ulPllReg, VCLK_PLL, VCO, pPLL->VCO); + ulPllReg = FIELD_VALUE(ulPllReg, VCLK_PLL, DIVIDER, pPLL->DIV); + }else{ + ulPllReg = FIELD_SET(origPllValue,VCLK_PLL, PRESEL,250); + ulPllReg = FIELD_VALUE(ulPllReg, VCLK_PLL, VCO, pPLL->VCO); + ulPllReg = FIELD_VALUE(ulPllReg, VCLK_PLL, DIVIDER, pPLL->DIV); + } + + printk("formatPllReg: PLL register value = 0x%08lx\n", ulPllReg); + + return(ulPllReg); +} + + +unsigned long SetPllReg(unsigned long pllReg, pll_value_t *pPLL) +{ + unsigned long ulTmpValue; + unsigned int timeout = 10000; + unsigned int pllFlag; + + switch(pllReg){ + case VCLK_PLL: + pokeRegisterDWord(PLL_SET, FIELD_SET(peekRegisterDWord(PLL_SET),PLL_SET,VCLK0PD,ON)); + break; + case VCLK1_PLL: + pokeRegisterDWord(PLL_SET, FIELD_SET(peekRegisterDWord(PLL_SET),PLL_SET,VCLK1PD,ON)); + break; + case VCLK2_PLL: + pokeRegisterDWord(PLL_SET1, FIELD_SET(peekRegisterDWord(PLL_SET1),PLL_SET1,VCLK2PD,ON)); + break; + } + + ulTmpValue = peekRegisterDWord(pllReg); + pokeRegisterDWord(pllReg, ddk770_formatPllReg(pPLL,ulTmpValue)); + + + //Set VCLK CP + switch(pllReg){ + case VCLK_PLL: + pokeRegisterDWord(PLL_SET1, FIELD_VALUE(peekRegisterDWord(PLL_SET1),PLL_SET1,VCLK0CP,0x2)); + break; + case VCLK1_PLL: + pokeRegisterDWord(VCLK1_PLL, FIELD_VALUE(peekRegisterDWord(VCLK1_PLL),VCLK1_PLL,VCLK1CP,0x2)); + break; + case VCLK2_PLL: + pokeRegisterDWord(VCLK2_PLL, FIELD_VALUE(peekRegisterDWord(VCLK2_PLL),VCLK2_PLL,VCLK2CP,0x2)); + break; + } + + switch(pllReg){ + case VCLK_PLL: + pokeRegisterDWord(PLL_SET, FIELD_SET(peekRegisterDWord(PLL_SET),PLL_SET,VCLK0PD,OFF)); + break; + case VCLK1_PLL: + pokeRegisterDWord(PLL_SET, FIELD_SET(peekRegisterDWord(PLL_SET),PLL_SET,VCLK1PD,OFF)); + break; + case VCLK2_PLL: + pokeRegisterDWord(PLL_SET1, FIELD_SET(peekRegisterDWord(PLL_SET1),PLL_SET1,VCLK2PD,OFF)); + break; + } + usleep_range(100, 200); + + do{ + switch(pllReg){ + case VCLK_PLL: + pllFlag = FIELD_VAL_GET(peekRegisterDWord(PLL_SET),PLL_SET,VCLK0LOCK); + break; + case VCLK1_PLL: + pllFlag = FIELD_VAL_GET(peekRegisterDWord(PLL_SET),PLL_SET,VCLK1LOCK); + break; + case VCLK2_PLL: + pllFlag = FIELD_VAL_GET(peekRegisterDWord(PLL_SET),PLL_SET,VCLK2LOCK); + break; + } + + }while(!pllFlag && (timeout--)); + + + return 0; +} + +__attribute__((unused)) static void SetPllSSCG(unsigned long pllReg) +{ + unsigned int ulTmpValue; + ulTmpValue = peekRegisterDWord(SSCG_CTL); + + ulTmpValue = FIELD_SET(ulTmpValue,SSCG_CTL, FN, ENABLE); + ulTmpValue = FIELD_SET(ulTmpValue, SSCG_CTL, PORCORE, ENABLE); + ulTmpValue = FIELD_SET(ulTmpValue, SSCG_CTL, SSCGPD, OFF); + + pokeRegisterDWord(SSCG_CTL, ulTmpValue ); + + + + ulTmpValue = peekRegisterDWord(SSCG_SET); + ulTmpValue = FIELD_SET(ulTmpValue, SSCG_SET, MODE, NO); + // ulTmpValue = FIELD_VALUE(ulTmpValue, SSCG_SET, DIV, 0x246d); + ulTmpValue = FIELD_VALUE(ulTmpValue, SSCG_SET, DIV, 0x1ae); + pokeRegisterDWord(SSCG_SET, ulTmpValue ); + + + + + ulTmpValue = peekRegisterDWord(pllReg); + ulTmpValue = FIELD_SET(ulTmpValue ,VCLK_PLL, SSCSEL,SSCG); + pokeRegisterDWord(pllReg, ulTmpValue); + + return; + +} + + + + +void Set_JPUVPU_PLL2_600(void){ + + unsigned long ulTmpValue; + unsigned int timeout = 10000; + unsigned int pllFlag; + // Set PLL2_PD = 1 + + pokeRegisterDWord(PLL_SET, FIELD_SET(peekRegisterDWord(PLL_SET),PLL_SET,PLL2PD,ON)); + + + // PLL2 to 600MHz,PLL2_PRE_SEL=0, PLL2_DIVIDER_SEL[7:0]=8'h30, PLL3_VCO_SEL=3'000 + + ulTmpValue = peekRegisterDWord(PLL2_PLL); + + ulTmpValue = FIELD_SET(ulTmpValue,PLL2_PLL, PRESEL,250); + ulTmpValue = FIELD_VALUE(ulTmpValue, PLL2_PLL, VCO, 0x0); + ulTmpValue = FIELD_VALUE(ulTmpValue, PLL2_PLL, DIVIDER, 0x30); + + pokeRegisterDWord(PLL2_PLL, ulTmpValue ); + + // Set PLL2_PD = 0 + pokeRegisterDWord(PLL_SET, FIELD_SET(peekRegisterDWord(PLL_SET),PLL_SET,PLL2PD,OFF)); + + do{ + + pllFlag = FIELD_VAL_GET(peekRegisterDWord(PLL_SET),PLL_SET,PLL2LOCK); + + + }while(!pllFlag && (timeout--)); + +} + +__attribute__((unused)) static void Set_Sys_PLL3_400(void){ + + unsigned long ulTmpValue; + + unsigned int timeout = 10000; + unsigned int pllFlag; + + // Set SYSCLK_SEL = 3'b010 25MHz + ulTmpValue = peekRegisterDWord(0x3bc); + ulTmpValue = (ulTmpValue & (~0x7U)) | 0x02; + pokeRegisterDWord(0x3bc, ulTmpValue); + + // Set PLL3_PD = 1 + + pokeRegisterDWord(PLL3_SET, FIELD_SET(peekRegisterDWord(PLL3_SET),PLL3_SET,PLL3PD,ON)); + + + // PLL3 APB to 800MHz,PLL3_PRE_SEL=0, PLL3_DIVIDER_SEL[7:0]=8'h20, PLL3_VCO_SEL=3'000 + ulTmpValue= peekRegisterDWord(PLL3_PLL); + ulTmpValue = FIELD_SET(ulTmpValue,PLL3_PLL, PRESEL,250); + ulTmpValue = FIELD_VALUE(ulTmpValue, PLL3_PLL, VCO, 0x2); + ulTmpValue = FIELD_VALUE(ulTmpValue, PLL3_PLL, DIVIDER, 0x20); + + pokeRegisterDWord(PLL3_PLL, ulTmpValue) ; + + // Set PLL3_PD = 0 + pokeRegisterDWord(PLL3_SET, FIELD_SET(peekRegisterDWord(PLL3_SET),PLL3_SET,PLL3PD,OFF)); + + usleep_range(100, 200); + + + do{ + + pllFlag = FIELD_VAL_GET(peekRegisterDWord(PLL_SET),PLL_SET,PLL3LOCK); + + + }while(!pllFlag && (timeout--)); + + // Set SYSCLK_SEL = 3'b001 + ulTmpValue = peekRegisterDWord(0x3bc); + ulTmpValue = (ulTmpValue & (~0x7U)) | 0x01; + pokeRegisterDWord(0x3bc, ulTmpValue); + + +} + +static void Set_Sys_PLL3_600(void){ + + unsigned long ulTmpValue; + + unsigned int timeout = 10000; + unsigned int pllFlag; + + // Set SYSCLK_SEL = 3'b010 25MHz Crystal Clock + ulTmpValue = peekRegisterDWord(0x3bc); + ulTmpValue = (ulTmpValue & (~0x7U)) | 0x02; + pokeRegisterDWord(0x3bc, ulTmpValue); + + // Set PLL3_PD = 1 Need to set 0x230 bit 10 + + pokeRegisterDWord(PLL3_SET, FIELD_SET(peekRegisterDWord(PLL3_SET),PLL3_SET,PLL3PD,ON)); + + + // PLL3 APB to 800MHz,PLL3_PRE_SEL=0, PLL3_DIVIDER_SEL[7:0]=8'h20, PLL3_VCO_SEL=3'000 + ulTmpValue= peekRegisterDWord(PLL3_PLL); + ulTmpValue = FIELD_SET(ulTmpValue,PLL3_PLL, PRESEL,250); + ulTmpValue = FIELD_VALUE(ulTmpValue, PLL3_PLL, VCO, 0x01); + ulTmpValue = FIELD_VALUE(ulTmpValue, PLL3_PLL, DIVIDER, 0x30); + + pokeRegisterDWord(PLL3_PLL, ulTmpValue) ; + + // Set PLL3_PD = 0 0x230 bit 10 + pokeRegisterDWord(PLL3_SET, FIELD_SET(peekRegisterDWord(PLL3_SET),PLL3_SET,PLL3PD,OFF)); + + usleep_range(100, 200); + + + do{ + + pllFlag = FIELD_VAL_GET(peekRegisterDWord(PLL_SET),PLL_SET,PLL3LOCK); + + + }while(!pllFlag && (timeout--)); + + // Set SYSCLK_SEL = 3'b001 + ulTmpValue = peekRegisterDWord(0x3bc); + ulTmpValue = (ulTmpValue & (~0x7U)) | 0x01; + pokeRegisterDWord(0x3bc, ulTmpValue); + +} + + + + +__attribute__((unused)) static void Set_Sys_PLL3_500(void){ + + unsigned long ulTmpValue; + + unsigned int timeout = 10000; + unsigned int pllFlag; + + // Set SYSCLK_SEL = 3'b010 25MHz + ulTmpValue = peekRegisterDWord(0x3bc); + ulTmpValue = (ulTmpValue & (~0x7U)) | 0x02; + pokeRegisterDWord(0x3bc, ulTmpValue); + + // Set PLL3_PD = 1 Need to set 0x230 bit 10 + + pokeRegisterDWord(PLL3_SET, FIELD_SET(peekRegisterDWord(PLL3_SET),PLL3_SET,PLL3PD,ON)); + + + // PLL3 APB to 800MHz,PLL3_PRE_SEL=0, PLL3_DIVIDER_SEL[7:0]=8'h20, PLL3_VCO_SEL=3'000 + ulTmpValue= peekRegisterDWord(PLL3_PLL); + ulTmpValue = FIELD_SET(ulTmpValue,PLL3_PLL, PRESEL,250); + ulTmpValue = FIELD_VALUE(ulTmpValue, PLL3_PLL, VCO, 0x01); + ulTmpValue = FIELD_VALUE(ulTmpValue, PLL3_PLL, DIVIDER, 0x28); + + pokeRegisterDWord(PLL3_PLL, ulTmpValue) ; + + // Set PLL3_PD = 0 0x230 bit 10 + pokeRegisterDWord(PLL3_SET, FIELD_SET(peekRegisterDWord(PLL3_SET),PLL3_SET,PLL3PD,OFF)); + + usleep_range(100, 200); + + + do{ + + pllFlag = FIELD_VAL_GET(peekRegisterDWord(PLL_SET),PLL_SET,PLL3LOCK); + + + }while(!pllFlag && (timeout--)); + + // Set SYSCLK_SEL = 3'b001 + ulTmpValue = peekRegisterDWord(0x3bc); + ulTmpValue = (ulTmpValue & (~0x7U)) | 0x01; + pokeRegisterDWord(0x3bc, ulTmpValue); + +} + + + + + +static void Set_Sys_PLL3_800(void){ + + unsigned long ulTmpValue; + + unsigned int timeout = 10000; + unsigned int pllFlag; + + // Set SYSCLK_SEL = 3'b010 25MHz Crystal Clock + ulTmpValue = peekRegisterDWord(0x3bc); + ulTmpValue = (ulTmpValue & (~0x7U)) | 0x02; + pokeRegisterDWord(0x3bc, ulTmpValue); + + // Set PLL3_PD = 1 + + pokeRegisterDWord(PLL3_SET, FIELD_SET(peekRegisterDWord(PLL3_SET),PLL3_SET,PLL3PD,ON)); + + + // PLL3 APB to 800MHz,PLL3_PRE_SEL=0, PLL3_DIVIDER_SEL[7:0]=8'h20, PLL3_VCO_SEL=3'000 + ulTmpValue= peekRegisterDWord(PLL3_PLL); + ulTmpValue = FIELD_SET(ulTmpValue,PLL3_PLL, PRESEL,250); + ulTmpValue = FIELD_VALUE(ulTmpValue, PLL3_PLL, VCO, 0x0); + ulTmpValue = FIELD_VALUE(ulTmpValue, PLL3_PLL, DIVIDER, 0x20); + + pokeRegisterDWord(PLL3_PLL, ulTmpValue) ; + + // Set PLL3_PD = 0 + pokeRegisterDWord(PLL3_SET, FIELD_SET(peekRegisterDWord(PLL3_SET),PLL3_SET,PLL3PD,OFF)); + + usleep_range(100, 200); + + + do{ + + pllFlag = FIELD_VAL_GET(peekRegisterDWord(PLL_SET),PLL_SET,PLL3LOCK); + + + }while(!pllFlag && (timeout--)); + + // Set SYSCLK_SEL = 3'b001 + ulTmpValue = peekRegisterDWord(0x3bc); + ulTmpValue = (ulTmpValue & (~0x7U)) | 0x01; + pokeRegisterDWord(0x3bc, ulTmpValue); + + +} + +static void Sys_PLL_Setting(ddr_type_t type){ + + unsigned long ulTmpValue; + + if( LPDDR4_3P2K_FD == type || LPDDR4_3P2K_HD == type || DDR4_3P2K_FD == type || DDR4_3P2K_HD == type ){ + //system/DDR: 800MHz@3200 CPU: 400MHz APB: 200MHz ESM: 200MHz USB RAM: 400MHz PCIe AXI: 400MHz VPU bclk: 400MHz) + + + ulTmpValue = peekRegisterDWord(0x3b0); + + // Set CPU clock 0x0003b0[6:4]=3'h4 system clock divided by 2 + ulTmpValue = (ulTmpValue & (~(0x7U<<4))) | (0x02 << 4); + // Set APB clock 0x0003b0[10:8]=3'h4 system clock divided by 4 + ulTmpValue = (ulTmpValue & (~(0x7U<<8))) | (0x04 << 8); + + // Set HDCP ESM clock 0x0003b0[18:16]=3'h4 system clock divided by 4 + ulTmpValue = (ulTmpValue & (~(0x7U<<16))) | (0x04 << 16); + + //clock source for sram in the USB mac. system clock divided by 2 + ulTmpValue = (ulTmpValue & (~(0x7U<<24))) | (0x02 << 24); + + + pokeRegisterDWord(0x3b0, ulTmpValue); + + printk("sys pll to 800\n"); + + Set_Sys_PLL3_800(); + + } + else if( DDR4_2P4K_FD == type || DDR4_2P4K_HD == type || LPDDR4_2P4K_FD || LPDDR4_2P4K_HD){ + //system/DDR: 800MHz@3200 CPU: 400MHz APB: 200MHz ESM: 200MHz USB RAM: 400MHz PCIe AXI: 400MHz VPU bclk: 400MHz) + + ulTmpValue = peekRegisterDWord(0x3b0); + + // Set CPU clock 0x0003b0[6:4]=3'h4 system clock divided by 2 + ulTmpValue = (ulTmpValue & (~(0x7U<<4))) | (0x02 << 4); + // Set APB clock 0x0003b0[10:8]=3'h4 system clock divided by 4 + ulTmpValue = (ulTmpValue & (~(0x7U<<8))) | (0x04 << 8); + + // Set HDCP ESM clock 0x0003b0[18:16]=3'h4 system clock divided by 4 + ulTmpValue = (ulTmpValue & (~(0x7U<<16))) | (0x04 << 16); + + //clock source for sram in the USB mac. system clock divided by 2 + ulTmpValue = (ulTmpValue & (~(0x7U<<24))) | (0x02 << 24); + + + pokeRegisterDWord(0x3b0, ulTmpValue); + + + printk("sys pll to 600\n"); + + Set_Sys_PLL3_600(); + } + else{ + printk("Sys PLL to 400\n"); + //system/DDR: 400MHz@1600 CPU: 400MHz APB: 200MHz ESM: 200MHz USB RAM: 400MHz PCIe AXI: 400MHz VPU bclk: 400MHz + + + //0x3b0 Power-on Default 0x12111221 + // Set CPU clock 0x0003b0[6:4]=3'h1 system clock (PLL3 output clock in normal mission mode) + // Set ESM clock 0x0003b0[18:16]=3'h2 system clock divided by 2 + // Set USB ram clock 0x0003b0[26:24]=3'h1 system clock (PLL3 output clock in normal mission mode) + ulTmpValue = peekRegisterDWord(0x3b0); + ulTmpValue = (ulTmpValue & (~(0x7U<<4))) | (0x01 << 4); + ulTmpValue = (ulTmpValue & (~(0x7U<<16))) | (0x02 << 16); + ulTmpValue = (ulTmpValue & (~(0x7U<<24))) | (0x01 << 24); + pokeRegisterDWord(0x3b0, ulTmpValue); + + // Set PCIe AXI Clock 0x0003b4[2:0]=3'h1 + // Set VPU bclk 0x0003b4[6:4]=3'h1 + ulTmpValue = peekRegisterDWord(0x3b4); + ulTmpValue = (ulTmpValue & (~0x7U)) | 0x01; + ulTmpValue = (ulTmpValue & (~(0x7U<<4))) | (0x01 << 4); + pokeRegisterDWord(0x3b4, ulTmpValue); + + + } +} + +unsigned int Check_DDR_Rate(void) +{ + + unsigned long ulTmpValue; + ddr_fre_type_t type; + + //strap5: 0x010018[1] + ulTmpValue = peekRegisterDWord(STRAP_PINS2); + + if (FIELD_VAL_GET(ulTmpValue, STRAP_PINS2, DDRRATE) == STRAP_PINS2_DDRRATE_3200){ + type = DDR4_3200; + } + else{ + type = DDR4_1600; + } + + + return type; +} + +void Sys_Init_PLL(ddr_type_t type) +{ + + + Sys_PLL_Setting(type); + +} diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_clock.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_clock.h new file mode 100644 index 000000000000..3197972123e7 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_clock.h @@ -0,0 +1,84 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* CLOCK.H --- Voyager GX DDK +* +*******************************************************************/ +#ifndef _DDK770_CLOCK_H_ +#define _DDK770_CLOCK_H_ + +#define MHz(x) (x*1000000) /* Don't use this macro if x is fraction number */ + +#define CPU_CLOCK MHz(400) + + +#define DEFAULT_INPUT_CLOCK MHz(25) /* Default reference clock */ + +typedef enum { + DDR4_3200 = 0x0, + DDR4_1600 = 0x1, +} ddr_fre_type_t; + +typedef enum { + LPDDR4_3P2K_FD, + LPDDR4_3P2K_HD, + DDR4_3P2K_FD, + DDR4_3P2K_HD, + DDR4_2P4K_FD, + DDR4_2P4K_HD, + LPDDR4_2P4K_FD, + LPDDR4_2P4K_HD, + +} ddr_type_t; + +typedef struct pll_value_t +{ + unsigned long inputFreq; /* Input clock frequency to the PLL */ + unsigned long DIV; + unsigned long VCO; +} +pll_value_t; + +/* + * Given a requested clock frequency, this function calculates the + * best INT, FRAC, VCO and BS values for the PLL. + * + * Input: Requested pixel clock in Hz unit. + * The followiing fields of PLL has to be set up properly: + * pPLL->inputFreq. + * + * Output: Update the PLL structure with the proper values + * Return: The actual clock in Hz that the PLL is able to set up. + * + */ +unsigned long ddk770_calcPllValue( +unsigned long ulRequestClk, /* Required pixel clock in Hz unit */ +pll_value_t *pPLL /* Structure to hold the value to be set in PLL */ +); + +/* + * Set up the corresponding bit field of the programmable PLL register. + * + * Input: Pointer to PLL structure with all values set up properly. + * + */ +unsigned long ddk770_formatPllReg(pll_value_t *pPLL,unsigned long oriPllValue); + + +unsigned long SetPllReg(unsigned long pllReg, pll_value_t *pPLL); + + +long ddk770_setVclock(unsigned dispCtrl, unsigned long pixel_clock); + +unsigned int Check_DDR_Rate(void); + +void Sys_Init_PLL(ddr_type_t type); + +void Set_JPUVPU_PLL2_600(void); + + +#endif /*_CLOCK_H_*/ diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_cursor.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_cursor.c new file mode 100644 index 000000000000..7f929eeda5c2 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_cursor.c @@ -0,0 +1,185 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* CURSOR.C --- Voyager GX SDK +* This file contains the definitions for the Panel cursor functions. +* +*******************************************************************/ +#include "ddk770_reg.h" +#include "ddk770_cursor.h" +#include "ddk770_help.h" +#include "ddk770_display.h" + + +static int makeEven(int num) { + + return num & (~1U); +} + + + +/* + * This function set alpha cursor size + */ +void SetAlphaCursorSize( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long size +) +{ + unsigned long cursorRegister, value; + + cursorRegister = HWC_LOCATION + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + + value = peekRegisterDWord(cursorRegister); + value = FIELD_VALUE(value, HWC_LOCATION, SIZE, size); + + pokeRegisterDWord(cursorRegister, value); +} + + + +/* + * This function set alpha cursor size + */ +void SetCursorPrefetch( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned int enable +) +{ + unsigned long cursorRegister, value; + + cursorRegister = HWC_LOCATION + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + + value = peekRegisterDWord(cursorRegister); + if(enable) + value = FIELD_SET(value, HWC_LOCATION, PREFETCH, ENABLE); + else + value = FIELD_SET(value, HWC_LOCATION, PREFETCH, DISABLE); + + pokeRegisterDWord(cursorRegister, value); + ddk770_waitDispVerticalSync(dispControl,2); +} + + + + + +/* + * This function initializes the cursor attributes. + */ +void ddk770_initCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long base, /* Base Address */ + unsigned long color0, /* Monochrome cursor color 0 in RGB 8 8 8 format */ + unsigned long color1, /* Monochrome cursor color 1 in RGB 8 8 8 format */ + unsigned long color2 /* Monochrome cursor color 2 in RGB 8 8 8 format */ +) +{ + /* + * 1. Set the cursor source address + */ + pokeRegisterDWord( + HWC_CONTROL + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET), + + FIELD_VALUE(0, HWC_CONTROL, ADDRESS, base)); + + /* + * 2. Set the cursor color composition + */ + pokeRegisterDWord( + HWC_COLOR0 + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET), + FIELD_VALUE(0, HWC_COLOR0, RGB888, color0)); + + pokeRegisterDWord( + HWC_COLOR1 + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET), + FIELD_VALUE(0, HWC_COLOR1, RGB888, color1)); + + + SetAlphaCursorSize(dispControl,0); + +} + +/* + * This function sets the cursor position. + */ +void ddk770_setCursorPosition( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long dx, /* X Coordinate of the cursor */ + unsigned long dy, /* Y Coordinate of the cursor */ + unsigned char topOutside, /* Top Boundary Select: either partially outside (= 1) + or within the screen top boundary (= 0) */ + unsigned char leftOutside, /* Left Boundary Select: either partially outside (= 1) + or within the screen left boundary (= 0) */ + unsigned int enable +) +{ + unsigned long cursorRegister, value; + + cursorRegister = HWC_LOCATION + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + + value = peekRegisterDWord(cursorRegister); + + /* Set the XY coordinate */ + value = FIELD_VALUE(value, HWC_LOCATION, X, dx); + value = FIELD_VALUE(value, HWC_LOCATION, Y, makeEven(dy)); + + /* Set the top boundary select either partially outside the top boundary + screen or inside */ + if (topOutside) + value = FIELD_SET(value, HWC_LOCATION, TOP, OUTSIDE); + else + value = FIELD_SET(value, HWC_LOCATION, TOP, INSIDE); + + /* Set the left boundary select either partially outside the left boundary + screen or inside */ + if (leftOutside){ + value = FIELD_SET(value, HWC_LOCATION, LEFT, OUTSIDE); + } + else{ + value = FIELD_SET(value, HWC_LOCATION, LEFT, INSIDE); + } + + value = FIELD_VALUE(value, HWC_LOCATION, SIZE, 0); + + if(enable) + value = FIELD_SET(value, HWC_LOCATION, PREFETCH, ENABLE); + else + value = FIELD_SET(value, HWC_LOCATION, PREFETCH, DISABLE); + /* Set the register accordingly, either Panel cursor or CRT cursor */ + pokeRegisterDWord(cursorRegister, value); + + //ddk770_waitDispVerticalSync(dispControl,2); +} + + + + +/* + * This function enables/disables the cursor. + */ +void ddk770_enableCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long mode /* Cursor type - 00 disable, 0x01 mask cursor, 0x02 mono, 0x03 alpha cursor */ +) +{ + unsigned long cursorRegister, value; + + +#if 0 + cursorRegister = HWC_LOCATION + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + value = peekRegisterDWord(cursorRegister); + value = FIELD_SET(value, HWC_LOCATION, PREFETCH, ENABLE); + pokeRegisterDWord(cursorRegister, value); +#endif + + cursorRegister = HWC_CONTROL + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + value = peekRegisterDWord(cursorRegister); + value = FIELD_VALUE(value, HWC_CONTROL, MODE, mode); + + pokeRegisterDWord(cursorRegister, value); + +} diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_cursor.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_cursor.h new file mode 100644 index 000000000000..9dac5890901b --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_cursor.h @@ -0,0 +1,73 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* cursor.h --- SMI DDK +* This file contains the definitions for the cursor functions. +* +*******************************************************************/ +#ifndef _DDk770_CURSOR_H_ +#define _DDK770_CURSOR_H_ + +#include "ddk770_mode.h" + +#define CURSOR_DISABLE 0x0 +#define CURSOR_ALPHA 0x3 +#define CURSOR_MONO 0x2 +#define CURSOR_MASK 0x1 + + +/* + * This function initializes the cursor attributes. + */ +void ddk770_initCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long base, /* Base Address */ + unsigned long color0, /* Monochrome cursor color 0 in RGB 8 8 8 format */ + unsigned long color1, /* Monochrome cursor color 1 in RGB 8 8 8 format */ + unsigned long color2 /* Monochrome cursor color 2 in RGB 8 8 8 format */ +); + + +void SetCursorPrefetch( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned int enable +); + + +/* + * This function sets the cursor position. + */ +void ddk770_setCursorPosition( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long dx, /* X Coordinate of the cursor */ + unsigned long dy, /* Y Coordinate of the cursor */ + unsigned char topOutside, /* Top Boundary Select: either partially outside (= 1) + or within the screen top boundary (= 0) */ + unsigned char leftOutside, /* Left Boundary Select: either partially outside (= 1) + or within the screen left boundary (= 0) */ + unsigned int enable + +); + +/* + * This function set alpha cursor size + */ +void SetAlphaCursorSize( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long size +); + + +/* + * This function enables/disables the cursor. + */ +void ddk770_enableCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long enable +); + +#endif /* _CURSOR_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_ddkdebug.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_ddkdebug.c new file mode 100644 index 000000000000..bc0512a31d0f --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_ddkdebug.c @@ -0,0 +1,227 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* ddkdebug.c --- DDK Debug Tool +* This file contains the source code for the SMI DDK Debugging. +* +*******************************************************************/ +#ifdef DDKDEBUG /* Don't enable debug flag in ARM yet */ +#include +#include +#include +#include "ddk770_ddkdebug.h" +#include "ddk770_os.h" + +/* COM Port index that is used for the debugging */ +#define DEBUG_COM_PORT_INDEX 0 + +/* Buffer length */ +#define BUFFER_LENGTH 1024 + +static ddk_debug_output_t gDebugOutput = DEBUG_OUTPUT_SCREEN; +static unsigned long gDebugLevelMask = 0; +static FILE *gFileHandle = (FILE *)0; +static short gCOMInit = 0; +static unsigned char gEnableDebugMessage; + +/* + * This function initializes the debug print out system. + * + * Input: + * debugOutput - Output where to print out the debug. It could be + * screen, file, or serial port. + * debugLevel - Debugging level + */ +void ddkDebugPrintInit(ddk_debug_output_t debugOutput, unsigned long debugLevelMask) +{ + gDebugOutput = debugOutput; + gDebugLevelMask = debugLevelMask; + gEnableDebugMessage = 1; + + /* Initialize the output media as necessary */ + switch (gDebugOutput) + { + default: + case DEBUG_OUTPUT_SCREEN: + /* Do nothing */ + break; + case DEBUG_OUTPUT_FILE: + /* Close the previous log file if opened */ + if (gFileHandle != (FILE *)0) + fclose(gFileHandle); + + /* Create a LOG file */ + gFileHandle = fopen("ddkdebug.log", "w"); + if (gFileHandle == NULL) + ddkDebugPrint(0, "Can not open log file\n"); + break; + case DEBUG_OUTPUT_SERIAL: + /* Open COM Port */ + if (comInit(DEBUG_COM_PORT_INDEX, + COM_9600, + DATA_SIZE_8, + PARITY_NONE, + STOP_BIT_1, + FLOW_CONTROL_NONE) == 0) + gCOMInit = 1; + else + ddkDebugPrint(0, "Can not open COM Port\n"); + break; + } +} + +/* + * This function enable or disable the debug message. + * + * Input: + * enableDebugMessage - Enable/disable the debug message + * 0 - Disable Debug Message + * 1 - Enable Debug Message + * + * Note: + * This function can be used to enable/disable the debug message + * at certain point of software, so that the debug messages, that + * are printed, are only the important ones. + */ +void ddkDebugEnable(unsigned char enableDebugMessage) +{ + gEnableDebugMessage = enableDebugMessage; +} + +/* + * This function prints out the formatted string. + * + * Input: + * debugLevel - The level of the debug of which the message is intended for. + * pszFormat - Format of the printed message + */ +void ddkDebugPrint(unsigned long debugLevel, const char* pszFormat, ...) +{ + static char pszPrintBuffer[BUFFER_LENGTH]; + unsigned long nWritten; + + /* Do not print any messages when this variable is flagged. */ + if (gEnableDebugMessage == 0) + return; + + /* Only process any ddkDebugPrint with the debugLevel less or equal the preset + debug Level during the init */ + if (((debugLevel & gDebugLevelMask) != 0) || (debugLevel == 0)) + { + /* Format the string */ + va_list arg_ptr; + va_start(arg_ptr, pszFormat); + nWritten = (unsigned long) vsnprintf(pszPrintBuffer, BUFFER_LENGTH - 1, pszFormat, arg_ptr); + va_end(arg_ptr); + + /* Check for buffer overflow */ + if (nWritten == (unsigned long)(-1)) + { + ddkDebugPrint(0, "ddkDebugPrint(): BUFFER OVERFLOW DETECTED!!!\r\n" \ + "MAX STRING LENGTH = %d\n", BUFFER_LENGTH); + return; + } + + /* Print out the data */ + switch (gDebugOutput) + { + default: + case DEBUG_OUTPUT_SCREEN: + printk(pszPrintBuffer); + + /* + * Flush the stdout before the getch function. Otherwise the + * previous printf will not be displayed correctly sometimes. + */ + fflush(stdout); + break; + case DEBUG_OUTPUT_FILE: + /* Print out the message to the log file */ + if (gFileHandle != NULL) + { + fprintf(gFileHandle, pszPrintBuffer); + fflush(gFileHandle); + } + break; + case DEBUG_OUTPUT_SERIAL: + /* Send the data out to the COM Port */ + if (gCOMInit) + { +#if 1 + char *pString1, *pString2; + unsigned long length; + char linefeed = '\r'; + + length = 0; + pString1 = pszPrintBuffer; + while(nWritten) + { + /* Search for all '\n' and add '\r' so that the serial port can display correctly. */ + pString2 = strchr(pString1, '\n'); + if (pString2 != (char *)0) + { + length = pString2 - pString1 + 1; + + /* Check the previous character and the next character */ + if ((*(pString2 - 1) != '\r') && (*(pString2 + 1) != '\r')) + { + /* Write the buffer with the '\r' */ + comWrite(pString1, length); + comWrite(&linefeed, 1); + } + else + comWrite(pString1, length); + + /* Adjust the nWritten */ + nWritten -= length; + + /* Adjust the new string pointer */ + pString1 = pString2 + 1; + } + else + { + comWrite(pString1, nWritten); + nWritten = 0; + } + } +#else + comWrite(pszPrintBuffer, nWritten); +#endif + } + break; + } + } +} + +/* + * This function cleans up (such as closing the debug file, etc...) when + * exiting the debug module. + */ +void ddkDebugPrintExit() +{ + /* Clean up the debug print module */ + switch (gDebugOutput) + { + default: + case DEBUG_OUTPUT_SCREEN: + /* Do nothing */ + break; + case DEBUG_OUTPUT_FILE: + /* Close the log file */ + if (gFileHandle != (FILE *)0) + fclose(gFileHandle); + break; + case DEBUG_OUTPUT_SERIAL: + comClose(); + break; + } +} + +#endif + + + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_ddkdebug.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_ddkdebug.h new file mode 100644 index 000000000000..096e4d282067 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_ddkdebug.h @@ -0,0 +1,141 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* ddkdebug.h --- DDK Debug module +* This file contains the definitions for the SMI DDK debugging. +* +*******************************************************************/ +#ifndef _DDk770_DDKDEBUG_H_ +#define _DDK770_DDKDEBUG_H_ + +#ifdef DDKDEBUG + +/********************* + * Definition + *********************/ + +/* Debug Print Level definitions */ +/* Bit 16 ~ 31 are used by the library. Bit 0 ~ 15 can be used by application */ +#define ERROR_LEVEL 0x00010000 +#define WARNING_LEVEL 0x00020000 +#define INIT_LEVEL 0x00040000 +#define DISPLAY_LEVEL 0x00080000 +#define DMA_LEVEL 0x00100000 +#define DE_LEVEL 0x00200000 +#define CAPTURE_LEVEL 0x00400000 +#define SSP_LEVEL 0x00800000 +#define RESERVED8_LEVEL 0x01000000 +#define RESERVED9_LEVEL 0x02000000 +#define RESERVED10_LEVEL 0x04000000 +#define RESERVED11_LEVEL 0x08000000 +#define RESERVED12_LEVEL 0x10000000 +#define RESERVED13_LEVEL 0x20000000 +#define RESERVED14_LEVEL 0x40000000 +#define RESERVED15_LEVEL 0x80000000 + +#define SYSTEM_LEVEL_MASK 0xFFFF0000 +#define APPLICATION_LEVEL_MASK 0x0000FFFF + +/********************* + * Structure + *********************/ +typedef enum _ddk_debug_output_t +{ + DEBUG_OUTPUT_SCREEN = 0, + DEBUG_OUTPUT_FILE, + DEBUG_OUTPUT_SERIAL +} +ddk_debug_output_t; + +/********************* + * MACROS + *********************/ + +/* This function has to be called before calling other DEBUGPIRNT functions. */ +#define DDKDEBUGPRINTINIT(debugOutput, debugLevelMask) \ + ddkDebugPrintInit(debugOutput, debugLevelMask) + +/* This function enable or disable the debug message. + * Note: + * This function can be used to enable/disable the debug message + * at certain point of software, so that the debug messages, that + * are printed, are only the important ones. + */ +#define DDKDEBUGENABLE(arg) \ + ddkDebugEnable(arg) + +/* Calling the DDKDEBUGPRINT needs to have the arg to be enclosed with + two of open and close brackets. + Example: + DDKDEBUGPRINT(("Hello World: %s\n", pszString)); + */ +#define DDKDEBUGPRINT(arg) \ + ddkDebugPrint arg + +/* This function has to be called when exiting the application. + It is necessary to clean up the debug module. */ +#define DDKDEBUGPRINTEXIT() \ + ddkDebugPrintExit() + +/********************* + * Function prototype + *********************/ + +/* + * This function initializes the debug print out system. + * + * Input: + * debugOutput - Output where to print out the debug. It could be + * screen, file, or serial port. + * debugLevel - Debugging level + */ +void ddkDebugPrintInit(ddk_debug_output_t debugOutput, unsigned long debugLevelMask); + +/* + * This function enable or disable the debug message. + * + * Input: + * enableDebugMessage - Enable/disable the debug message + * 0 - Disable Debug Message + * 1 - Enable Debug Message + * + * Note: + * This function can be used to enable/disable the debug message + * at certain point of software, so that the debug messages, that + * are printed, are only the important ones. + */ +void ddkDebugEnable(unsigned char enableDebugMessage); + +/* + * This function prints out the formatted string. + * + * Input: + * debugLevel - The level of the debug of which the message is intended for. + * pszFormat - Format of the printed message + */ +void ddkDebugPrint(unsigned long debugLevel, const char* pszFormat, ...); + +/* + * This function cleans up (such as closing the debug file, etc...) when + * exiting the debug module. + */ +void ddkDebugPrintExit(); + +#else + +/* + * If there is no DEBUG definition, then treat the macro as an empty macro. + * Therefore all the debug print will be stripped out. + */ +#define DDKDEBUGPRINTINIT(debugOutput, debugLevelMask) +#define DDKDEBUGENABLE(arg) +#define DDKDEBUGPRINT(arg) +#define DDKDEBUGPRINTEXIT() + +#endif + +#endif /* _DDKDEBUG_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_display.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_display.c new file mode 100644 index 000000000000..e70bcb1a9ff9 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_display.c @@ -0,0 +1,782 @@ +/******************************************************************* +* +* This code is free software and distributed as is wihtout any +* warranty. +* +* DISPLAY.C --- SM768 GX SDK +* This file contains the source code for the panel and CRT functions. +* +*******************************************************************/ +#include +#include +#include "ddk770_reg.h" +#include "ddk770_chip.h" +#include "ddk770_power.h" +#include "ddk770_display.h" +#include "ddk770_timer.h" +#include "ddk770_ddkdebug.h" +#include "ddk770_help.h" +#include "ddk770_hdmi.h" +#include "ddk770_dp.h" + +/* Monitor Detection RGB Default Threshold values */ +#define DEFAULT_MON_DETECTION_THRESHOLD 0x64 + +/* + * This function initializes the display. + * + * Output: + * 0 - Success + * 1 - Fail + */ +long ddk770_initDisplay() +{ + + ddk770_HDMI_Init(0); + ddk770_HDMI_Init(1); + ddk770_HDMI_Init(2); + + DP_Init(0); + DP_Init(1); + + return 0; +} + +/* New for Falcon: DPMS control is moved to display controller. + * This function sets the display DPMS state + * It is used to set CRT monitor to On, off, or suspend states, + * while display channel are still active. + */ +void ddk770_setDisplayDPMS( + disp_control_t dispControl, /* Channel 0 or Channel 1) */ + DISP_DPMS_t state /* DPMS state */ + ) +{ + unsigned long ulDispCtrlAddr; + unsigned long ulDispCtrlReg; + + /* Get the control register for channel 0 or 1. */ + + ulDispCtrlAddr = DISPLAY_CTRL+ (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + + switch (state) + { + case DISP_DPMS_ON: + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DPMS, VPHP); + break; + + case DISP_DPMS_STANDBY: + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DPMS, VPHN); + break; + + case DISP_DPMS_SUSPEND: + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DPMS, VNHP); + break; + + case DISP_DPMS_OFF: + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DPMS, VNHN); + break; + } + + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); +} + +/* + * Wait number of Vertical Vsync + * + * Input: + * dispControl - Display Control (either channel 0 or 1) + * vSyncCount - Number of vertical sync to wait. + * + * Note: + * This function is waiting for the next vertical sync. + */ +void ddk770_waitDispVerticalSync(disp_control_t dispControl, unsigned long vSyncCount) +{ + unsigned long ulDispCtrlAddr; + unsigned long status; + unsigned long ulLoopCount = 0; + static unsigned long ulDeadLoopCount = 10; + + ulDispCtrlAddr = DISPLAY_CTRL + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + + if (dispControl == CHANNEL0_CTRL) + { + // There is no Vsync when PLL is off + if ((FIELD_VAL_GET(peekRegisterDWord(CLOCK_ENABLE), CLOCK_ENABLE, DC0) == CLOCK_ENABLE_DC0_OFF)) + return; + } + else if(dispControl == CHANNEL1_CTRL) + { + // There is no Vsync when PLL is off + if ((FIELD_VAL_GET(peekRegisterDWord(CLOCK_ENABLE), CLOCK_ENABLE, DC1) == CLOCK_ENABLE_DC1_OFF)) + return; + } + else + { + // There is no Vsync when PLL is off + if ((FIELD_VAL_GET(peekRegisterDWord(CLOCK_ENABLE), CLOCK_ENABLE, DC2) == CLOCK_ENABLE_DC2_OFF)) + return; + + } + + //There is no Vsync when display timing is off. + if ((FIELD_VAL_GET(peekRegisterDWord(ulDispCtrlAddr), DISPLAY_CTRL, TIMING) == + DISPLAY_CTRL_TIMING_DISABLE)) + { + return; + } + + /* Count number of Vsync. */ + while (vSyncCount-- > 0) + { + /* If VSync is active when entering this function. Ignore it and + wait for the next. + */ + ulLoopCount = 0; + do + { + status = FIELD_VAL_GET(peekRegisterDWord(ulDispCtrlAddr), VERTICAL_SYNC, VSYNC); + //Insert delay to reduce number of Vsync checks + ddk770_timerWaitTicks(3, 0xffff); + if(ulLoopCount++ > ulDeadLoopCount) break; + } + while (status == VERTICAL_SYNC_VSYNC_ACTIVE); + + /* Wait for end of vsync or timeout */ + ulLoopCount = 0; + do + { + status = FIELD_VAL_GET(peekRegisterDWord(ulDispCtrlAddr), VERTICAL_SYNC, VSYNC); + ddk770_timerWaitTicks(3, 0xffff); + if(ulLoopCount++ > ulDeadLoopCount) break; + } + while (status == VERTICAL_SYNC_VSYNC_INACTIVE); + } +} + +/* + * Use panel vertical sync line as time delay function. + * This function does not wait for the next VSync. Instead, it will wait + * until the current line reaches the Vertical Sync line. + * This function is really useful when flipping display to prevent tearing. + * + * Input: display control (CHANNEL0_CTRL or CHANNEL1_CTRL) + */ +void ddk770_waitVSyncLine(disp_control_t dispControl) +{ + unsigned long ulDispCtrlAddr; + unsigned long value; + mode_parameter_t modeParam; + + ulDispCtrlAddr = CURRENT_LINE + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + + /* Get the current mode parameter of the specific display control */ + modeParam = ddk770_getCurrentModeParam(dispControl); + + do + { + value = FIELD_VAL_GET(peekRegisterDWord(ulDispCtrlAddr), CURRENT_LINE, LINE); + } + while (value < modeParam.vertical_sync_start); +} + +/* + * Get current display line number + */ +unsigned long ddk770_getDisplayLine(disp_control_t dispControl) +{ + unsigned long ulRegAddr; + unsigned long ulRegValue; + + ulRegAddr = CURRENT_LINE + (dispControl> 1? DC_OFFSET2 : dispControl * DC_OFFSET); + ulRegValue = FIELD_VAL_GET(peekRegisterDWord(ulRegAddr), CURRENT_LINE, LINE); + + return(ulRegValue); +} + +/* + * This functions uses software sequence to turn on/off the panel of the digital interface. + */ +void ddk770_swPanelPowerSequence( + disp_control_t dispControl, + disp_state_t dispState, + disp_control_t dataPath, + unsigned long vSyncDelay) +{ + unsigned long ulDispCtrlAddr; + unsigned long ulDispCtrlReg; + + DDKDEBUGPRINT((DISPLAY_LEVEL, "ddk770_swPanelPowerSequence +\n")); + + ulDispCtrlAddr = DISPLAY_CTRL + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + + if (dispState == DISP_ON) + { + //If bit 27:24 are already ON. Don't need to set them again + //because setting panel seq is time consuming. + if ((ulDispCtrlReg & 0x0f000000) == 0x0f000000) return; + + /* Turn on FPVDDEN. */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, FPVDDEN, HIGH); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + ddk770_waitDispVerticalSync(dataPath, vSyncDelay); + + /* Turn on FPDATA. */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DATA, ENABLE); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + ddk770_waitDispVerticalSync(dataPath, vSyncDelay); + + /* Turn on FPVBIAS. */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, VBIASEN, HIGH); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + ddk770_waitDispVerticalSync(dataPath, vSyncDelay); + + /* Turn on FPEN. */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, FPEN, HIGH); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + } + else + { + //If bit 27:24 are already OFF. Don't need to clear them again. + if ((ulDispCtrlReg & 0x0f000000) == 0x00000000) return; + + /* Turn off FPEN. */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, FPEN, LOW); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + ddk770_waitDispVerticalSync(dataPath, vSyncDelay); + + + /* Turn off FPVBIASEN. */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, VBIASEN, LOW); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + ddk770_waitDispVerticalSync(dataPath, vSyncDelay); + + /* Turn off FPDATA. */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DATA, DISABLE); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + ddk770_waitDispVerticalSync(dataPath, vSyncDelay); + + /* Turn off FPVDDEN. */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, FPVDDEN, LOW); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + } + DDKDEBUGPRINT((DISPLAY_LEVEL, "ddk770_swPanelPowerSequence -\n")); +} + +/* + * This function turns on/off the display control of Channel 0 or channel 1. + * + * Note: + * Turning on/off the timing and the plane requires programming sequence. + * The plane can not be changed without turning on the timing. However, + * changing the plane has no effect when the timing (clock) is off. Below, + * is the description of the timing and plane combination setting. + */ +//Cheok(10/18/2013): New function similar to setDisplayControl() +void ddk770_setDisplayEnable( + disp_control_t dispControl, /* Channel 0 or Channel 1) */ + disp_state_t dispState /* ON or OFF */ +) +{ + unsigned long ulDispCtrlAddr; + unsigned long ulDispCtrlReg; + + ulDispCtrlAddr = DISPLAY_CTRL + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + + DDKDEBUGPRINT((DISPLAY_LEVEL, "(setDisplayControl) Display Control Reg before set: %x\n", ulDispCtrlReg)); + + /* Turn on/off the Panel display control */ + if (dispState == DISP_ON) + { + /* Timing should be enabled first before enabling the plane because changing at the + same time does not guarantee that the plane will also enabled or disabled. + */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, TIMING, ENABLE); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, PLANE, ENABLE); + ulDispCtrlReg = FIELD_SET( ulDispCtrlReg, DISPLAY_CTRL, DATA_PATH, EXTENDED); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + } + else + { + /* When turning off, there is no rule on the programming sequence since whenever the + clock is off, then it does not matter whether the plane is enabled or disabled. + Note: Modifying the plane bit will take effect on the next vertical sync. Need to + find out if it is necessary to wait for 1 vsync before modifying the timing + enable bit. + */ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, PLANE, DISABLE); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, TIMING, DISABLE); + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + + } + + DDKDEBUGPRINT((DISPLAY_LEVEL, "(setDisplayControl) DISPLAY_CTRL after set: %x\n", peekRegisterDWord(ulDispCtrlAddr))); +} + + +/* + * This function controls monitor on/off and data path. + * It can be used to set up any veiws: single view, clone view, dual view, output with channel swap, etc. + * However, it needs too many input parameter. + * There are other set view functions with less parameters, but not as flexible as this one. + * + */ +long ddk770_setDisplayView( + disp_control_t dispOutput, /* Monitor 0 or 1 */ + disp_state_t dispState, /* On or off */ + disp_control_t dataPath) /* 24 or 48 bit digital interface (optional when OFF */ +{ + + ddk770_setDisplayEnable(dispOutput, dispState); + ddk770_swPanelPowerSequence(dispOutput, dispState, dataPath, 2); /* Turn on or off output power */ + + if (dispState == DISP_ON) + ddk770_setDisplayDPMS(dispOutput, DISP_DPMS_ON); /* DPMS on */ + else + ddk770_setDisplayDPMS(dispOutput, DISP_DPMS_OFF); /* DPMS off */ + + return 0; +} + +/* + * Convenient function to trun on single view + */ +long ddk770_setSingleViewOn(disp_control_t dispOutput) +{ + ddk770_setDisplayView( + dispOutput, /* Output monitor */ + DISP_ON, /* Turn On */ + dispOutput); /* Default to 24 bit single pixel, the most used case */ + + return 0; +} + +/* + * Convenient function to trun off single view + */ +long ddk770_setSingleViewOff(disp_control_t dispOutput) +{ + ddk770_setDisplayView( + dispOutput, /* Output monitor */ + DISP_OFF, /* Turn Off */ + dispOutput); /* Default to 24 bit single pixel, the most used case */ + + return 0; +} + +/* + * Convenient function to trun on clone view + */ +long ddk770_setCloneViewOn(disp_control_t dataPath) +{ + ddk770_setDisplayView( + CHANNEL0_CTRL, /* For Clone view, monitor 0 has to be ON */ + DISP_ON, + dataPath); /* Default to 24 bit single pixel, the most used case */ + + ddk770_setDisplayView( + CHANNEL1_CTRL, /* For Clone view, monitor 1 has to be ON */ + DISP_ON, + dataPath); /* Default to 24 bit single pixel, the most used case */ + + ddk770_setDisplayView( + CHANNEL2_CTRL, /* For Clone view, monitor 1 has to be ON */ + DISP_ON, + dataPath); /* Default to 24 bit single pixel, the most used case */ + + return 0; +} + +/* + * Convenient function to trun on dual view + */ +long ddk770_setDualViewOn() +{ + ddk770_setSingleViewOn(CHANNEL0_CTRL); + ddk770_setSingleViewOn(CHANNEL1_CTRL); + + return 0; +} + +/* + * Convenient function to trun on dual view + */ +// long setTripleViewOn() +// { +// ddk770_setSingleViewOn(CHANNEL0_CTRL); +// ddk770_setSingleViewOn(CHANNEL1_CTRL); +// ddk770_setSingleViewOn(CHANNEL2_CTRL); + +// return 0; +// } + + +/* + * Convenient function to trun off all views + */ +long ddk770_setAllViewOff() +{ + ddk770_setSingleViewOff(CHANNEL0_CTRL); /* Turn Off monitor 0 */ + ddk770_setSingleViewOff(CHANNEL1_CTRL); /* Turn Off monitor 1 */ + ddk770_setSingleViewOff(CHANNEL2_CTRL); /* Turn Off monitor 1 */ + // setAllLVDSOff(); + return 0; +} + + +/* + * Disable double pixel clock. + * This is a temporary function, used to patch for the random fuzzy font problem. + */ +void ddk770_DisableDoublePixel(disp_control_t dispControl) +{ + unsigned long ulDispCtrlAddr; + unsigned long ulDispCtrlReg; + + + ulDispCtrlAddr = DISPLAY_CTRL + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, DISABLE); + + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + +} + + + +void ddk770_EnableDoublePixel(disp_control_t dispControl) +{ + unsigned long ulDispCtrlAddr; + unsigned long ulDispCtrlReg; + + + ulDispCtrlAddr = DISPLAY_CTRL + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, ENABLE); + + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + +} + + + + + + +void ddk770_SetLVDSHalfPixel(unsigned int enable) +{ + + unsigned int ulTmpValue; + + ulTmpValue = peekRegisterDWord(CLOCK3_CTL); + + if(enable){ + ulTmpValue = FIELD_SET(ulTmpValue, CLOCK3_CTL, LVDS1CLK, HALF); + ulTmpValue = FIELD_SET(ulTmpValue, CLOCK3_CTL, LVDS0CLK, HALF); + }else{ + ulTmpValue = FIELD_SET(ulTmpValue, CLOCK3_CTL, LVDS1CLK, NORMAL); + ulTmpValue = FIELD_SET(ulTmpValue, CLOCK3_CTL, LVDS0CLK, NORMAL); + } + pokeRegisterDWord(CLOCK3_CTL, ulTmpValue); //Open half clock. + +} + + + +void ddk770_setupLVDS(unsigned short lvds_ch) +{ + //unsigned int ulTmpValue; + unsigned int lvdsAddr = 0; + + switch(lvds_ch){ + case 0: + lvdsAddr=0x3400; + break; + case 1: + lvdsAddr=0x3800; + break; + } + printk("LVDS%d initiation start\n",lvds_ch); + pokeRegisterDWord(lvdsAddr + (0x15 << 2), 0x40); + + // Set Lvds PLL register + pokeRegisterDWord(lvdsAddr + (0x0B << 2), 0xf8); + pokeRegisterDWord(lvdsAddr + (0x01 << 2), 0x12); + // Wait Lvds PLL lock + while(1) + { + if ((peekRegisterDWord(0x3fec) & (0x1<>(dcOutput*4); + if((output&0xf)==1) + return CHANNEL0_CTRL; + else if ((output&0xf)==2) + return CHANNEL1_CTRL; + else if ((output&0xf)==4) + return CHANNEL2_CTRL; + else + { + printk("No DC output to this mode\n"); + return -1; + } + + } +void setDCMUX(disp_output_t dcOutput,disp_control_t dc) +{ + unsigned int output=peekRegisterDWord(DC_MUX); + + if(DEFAULT_DC==dcOutput) + return; + + output &=~(0xf<<(dcOutput*4)); // clear this bit before set + if(dc==CHANNEL0_CTRL) + { + output|=0x1<<(dcOutput*4); // set this bet + } + else if(dc==CHANNEL1_CTRL) + { + output|=0x2<<(dcOutput*4); + } + else if(dc==CHANNEL2_CTRL) + { + output|=0x4<<(dcOutput*4); + } + else + { + return; + } + + printk("0x3ffc value will be %x\n",output); + + pokeRegisterDWord(DC_MUX, output); +} + +void ClearDCMUX(disp_output_t dcOutput) +{ + unsigned int output=peekRegisterDWord(DC_MUX); + + if(DEFAULT_DC==dcOutput) + return; + + output &=~(0xf<<(dcOutput*4)); // clear this bit + pokeRegisterDWord(DC_MUX, output); +} + +unsigned char GetDCMUX(disp_output_t dcOutput) +{ + unsigned int output; + + output = peekRegisterDWord(DC_MUX); + return output & (0xf<<(dcOutput*4)); // get this byte +} + +void cloneDCOutput(disp_control_t dc) +{ + unsigned int output; + if(dc==CHANNEL0_CTRL) + output=0x1111111; + + else if(dc==CHANNEL1_CTRL) + output =0x2222222; + + else + output=0x4444444; + + pokeRegisterDWord(DC_MUX, output); +} + + + + + +/* + * This function is to enable/disable display channel timing. + * + */ +void ddk770_EnableChannelTiming( + disp_control_t dispControl, /* Channel 0 or Channel 1) */ + unsigned short enable +) +{ + unsigned long ulDispCtrlAddr; + unsigned long ulDispCtrlReg; + + //DDKDEBUGPRINT((DISPLAY_LEVEL, "DisableChannelTiming + \n")); + + ulDispCtrlAddr = DISPLAY_CTRL + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + + if(enable) + { + /* Turn on the display Panel.*/ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, TIMING, ENABLE); + + } + else + { + /* Turn off the display Panel.*/ + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, TIMING, DISABLE); + } + + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); +} + +unsigned char ddk770_isTimingEnable(disp_control_t dispControl) +{ + unsigned long ulDispCtrlAddr; + unsigned long ulDispCtrlReg; + + ulDispCtrlAddr = DISPLAY_CTRL + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + + return ((FIELD_VAL_GET(ulDispCtrlReg, DISPLAY_CTRL, TIMING) == DISPLAY_CTRL_TIMING_ENABLE) ? 1 : 0); +} + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_display.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_display.h new file mode 100644 index 000000000000..770d7e87657d --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_display.h @@ -0,0 +1,191 @@ +/******************************************************************* +* +* This code is free software and distributed as is wihtout any +* warranty. +* +* display.h --- SM768 DDK +* This file contains the function prototypes for the display. +* +*******************************************************************/ +#ifndef _DDK770_DISPLAY_H_ +#define _DDK770_DISPLAY_H_ + +#include "ddk770_mode.h" +#include "../hw_com.h" + +typedef enum _disp_format_t +{ + SINGLE_PIXEL_24BIT = 0, + DOUBLE_PIXEL_48BIT +} +disp_format_t; + +typedef enum _disp_output_t +{ + HDMI0=0, + HDMI1, + HDMI2, + DP0, + DP1, + LVDS0, + LVDS1, + DEFAULT_DC, +} +disp_output_t; + + +/* + * This function initializes the display. + * + * Output: + * 0 - Success + * 1 - Fail + */ +long ddk770_initDisplay(void); + +/* + * This function sets the display DPMS state + * It is used to set CRT monitor to On, off, or suspend states, + * while display channel are still active. + */ +void ddk770_setDisplayDPMS( + disp_control_t dispControl, /* Channel 0 or Channel 1) */ + DISP_DPMS_t state /* DPMS state */ + ); + +/* + * This functions uses software sequence to turn on/off the panel. + */ +void ddk770_swPanelPowerSequence( + disp_control_t dispControl, + disp_state_t dispState, + disp_control_t dataPath, + unsigned long vSyncDelay); + +/* + * This function turns on/off the DAC for CRT display control. + * Input: On or off + */ +void enableDAC( + disp_control_t dispControl, /* Channel 0 or Channel 1) */ + disp_state_t state); + +/* + * Wait number of Vertical Vsync + * + * Input: + * dispControl - Display Control (either channel 0 or 1) + * vSyncCount - Number of vertical sync to wait. + * + * Note: + * This function is waiting for the next vertical sync. + */ +void ddk770_waitDispVerticalSync(disp_control_t dispControl, unsigned long vSyncCount); + +/* + * Use panel vertical sync line as time delay function. + * This function does not wait for the next VSync. Instead, it will wait + * until the current line reaches the Vertical Sync line. + * This function is really useful when flipping display to prevent tearing. + * + * Input: display control (CHANNEL0_CTRL or CHANNEL1_CTRL) + */ +void ddk770_waitVSyncLine(disp_control_t dispControl); + +/* + * Get current display line number + */ +unsigned long ddk770_getDisplayLine(disp_control_t dispControl); + + + + +/* + * This function turns on/off the display control of Channel 0 or channel 1. + * + * Note: + * Turning on/off the timing and the plane requires programming sequence. + * The plane can not be changed without turning on the timing. However, + * changing the plane has no effect when the timing (clock) is off. Below, + * is the description of the timing and plane combination setting. + */ +void ddk770_setDisplayEnable( +disp_control_t dispControl, /* Channel 0 or Channel 1) */ +disp_state_t dispState /* ON or OFF */ +); + + +/* + * This function controls monitor on/off and data path. + * It can be used to set up any veiws: single view, clone view, dual view, output with channel swap, etc. + * However, it needs too many input parameter. + * There are other set view functions with less parameters, but not as flexible as this one. + * + */ +long ddk770_setDisplayView( + disp_control_t dispOutput, /* Monitor 0 or 1 */ + disp_state_t dispState, /* On or off */ + disp_control_t dataPath); /* 24 or 48 bit digital interface (optional when OFF */ + +/* + * Convenient function to trun on single view + */ +long ddk770_setSingleViewOn(disp_control_t dispOutput); + +/* + * Convenient function to trun off single view + */ +long ddk770_setSingleViewOff(disp_control_t dispOutput); + +/* + * Convenient function to trun on clone view + */ +long ddk770_setCloneViewOn(disp_control_t dataPath); + +/* + * Convenient function to trun on dual view + */ +long ddk770_setDualViewOn(void); + +/* + * Convenient function to trun off all views + */ +long ddk770_setAllViewOff(void); + +void ddk770_DisableDoublePixel(disp_control_t dispControl); + +void ddk770_EnableDoublePixel(disp_control_t dispControl); + + +void ddk770_SetLVDSHalfPixel(unsigned int enable); + +void ddk770_setupLVDS(unsigned short lvds); + +void ddk770_setupSingleLVDS(unsigned short lvds_ch,disp_control_t dataPath); + +long ddk770_set48bitLVDS(disp_control_t dataPath); + +//New for SM770 + +void clearDCOutput(void); + +disp_control_t getOutputDC(disp_output_t dcOutput); +void setDCMUX(disp_output_t dcOutput,disp_control_t dc); +void ClearDCMUX(disp_output_t dcOutput); +unsigned char GetDCMUX(disp_output_t dcOutput); + +void cloneDCOutput(disp_control_t dc); + + + +/* + * This function is to enable/disable display channel timing. + * + */ +void ddk770_EnableChannelTiming( + disp_control_t dispControl, /* Channel 0 or Channel 1) */ + unsigned short enable +); + +unsigned char ddk770_isTimingEnable(disp_control_t dispControl); +#endif /* _DISPLAY_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_dp.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_dp.c new file mode 100644 index 000000000000..4b72aafecc48 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_dp.c @@ -0,0 +1,1686 @@ +#ifdef __linux__ +#include +#include +#endif +#include "ddk770_reg.h" +#include "ddk770_dp.h" +#include "ddk770_help.h" +#include "ddk770_hwi2c.h" +#include "ddk770_display.h" +#include "ddk770_chip.h" +#include "ddk770_mode.h" +#include "ddk770_hdmi_ddc.h" +#include +#include + + +#define BIT1(x) (0x1 << x) +#define min1(a, b) ((a) < (b) ? (a) : (b)) +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif + +dp_info g_dp_info[2] = { {0}, {0} }; + +unsigned int pll_table[][4] = { + /* prediv, fbdiv, postdiv, clkdiv_16m */ + { 0x02, 0x87, 0x01, 0x0d}, + { 0x02, 0xe1, 0x01, 0x15}, + { 0x02, 0xe1, 0x00, 0x2a}, +}; + +static void DP_Write32(dp_index index, unsigned int offset, unsigned int value) +{ + pokeRegisterDWord(DP_BASE + (DP_OFFSET * index) + offset, value); + // printk("write 0x%x 0x%x\n", DP_BASE + (DP_OFFSET * index) + offset, value); +} + +static unsigned int DP_Read32(dp_index index, unsigned int offset) +{ + return peekRegisterDWord(DP_BASE + (DP_OFFSET * index) + offset); +} + +static void DP_AUX_Request(dp_index index) +{ + DP_Write32(index, DP_CONTROLLER418, + FIELD_SET(DP_Read32(index, DP_CONTROLLER418), DP_CONTROLLER418, CFG_PHY_AUX_START, TRUE)); +} + +static unsigned int DP_Aux_Write(dp_index index, unsigned int cmd, unsigned int addr, unsigned int * wr_buf, unsigned int length) +{ + unsigned int val; + int i; + + //Read Request Transaction + val = DP_Read32(index, DP_CONTROLLER400); + val = FIELD_VALUE(val, DP_CONTROLLER400, CFG_PHY_AUX_DATA_CMD, cmd); + val = FIELD_VALUE(val, DP_CONTROLLER400, CFG_PHY_AUX_DATA_ADDR, addr); + val = FIELD_VALUE(val, DP_CONTROLLER400, CFG_PHY_AUX_DATA_LENGTH, length); + DP_Write32(index, DP_CONTROLLER400, val); + + //Write Request Transaction + if (!(cmd & 0x1)) + { + for (i = 0; i < 4; i++) + DP_Write32(index, DP_CONTROLLER408 + i * 4, wr_buf[i]); + } + + DP_AUX_Request(index); + + return DP_SUCCESS; +} + +static unsigned int DP_Aux_Read(dp_index index, unsigned int read, unsigned int addr, unsigned int * rd_buf) +{ + unsigned int ret, retry = 0; + int i; + //unsigned DPBaseAddr = DP_BASE + (DP_OFFSET * index); + + while (retry++ <= 30) { + if (FIELD_VAL_GET(DP_Read32(index, DP_TOP80), DP_TOP80, STA_AUX_REPLY_EVENT)) + break; + usleep_range(1000, 1100); + } + + DP_Write32(index, DP_TOP80, + FIELD_SET(DP_Read32(index, DP_TOP80), DP_TOP80, STA_AUX_REPLY_EVENT, TRUE)); + + if (read == 1) + { + usleep_range(2000, 2100); + for (i = 0; i < 4; i++) + rd_buf[i] = DP_Read32(index, DP_CONTROLLER408 + i * 4); + } + + ret = FIELD_VAL_GET(DP_Read32(index, DP_CONTROLLER404), DP_CONTROLLER404, AUX_REPLY_CMD); + + return ret; +} + +static unsigned int DP_Aux_Channel_Run(dp_index index, struct aux_cfg *aux_get_rx) +{ + unsigned int ret = 0; + + ret = DP_Aux_Write(index, aux_get_rx->aux_cmd, + aux_get_rx->dpcd_addr, aux_get_rx->wr_buff, + aux_get_rx->length); + if (ret == 1) + return 1; + + ret = DP_Aux_Read(index, aux_get_rx->read, + aux_get_rx->dpcd_addr, aux_get_rx->rd_buff); + + return ret; +} + +static int DP_Aux_Msg(dp_index index, struct aux_cfg *aux_msg) +{ + int ret = 0; + unsigned int retry = 0, max_retry = 7; + + for (retry = 0; retry < max_retry; retry++) { + ret = DP_Aux_Channel_Run(index, aux_msg); + if (ret == DP_AUX_REPLY_DEFER || ret == DP_AUX_I2C_REPLY_DEFER) { + usleep_range(2000, 2100); + continue; + } else { + break; + } + } + + return ret; +} + +static int DP_Aux_Transfer(dp_index index, unsigned char request, + unsigned int offset, void *buffer, int size) +{ + int ret = 0, j = 0; + unsigned int wr_buf[4] = {0}; + unsigned int rd_buf[4] = {0}; + struct aux_cfg aux_link = { 0 }; + + if (size > DP_AUX_MAX_PAYLOAD_BYTES) + return -1; + + aux_link.wr_buff = wr_buf; + aux_link.rd_buff = rd_buf; + aux_link.aux_cmd = request; + aux_link.dpcd_addr = offset; + aux_link.length = size ? size - 1 : 0x10; + + switch (request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_WRITE_STATUS_UPDATE: + { + aux_link.read = 0; + if (size && buffer) { + for (j = 0; j < size; j++) + aux_link.wr_buff[j / 4] |= (((unsigned char *)buffer)[j] << ((j % 4) * 8)); + } + ret = DP_Aux_Msg(index, &aux_link); + } + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + { + aux_link.read = 1; + ret = DP_Aux_Msg(index, &aux_link); + if (size && buffer) { + for (j = 0; j < size; j++) + ((unsigned char *)buffer)[j] = (aux_link.rd_buff[j / 4] >> (8 *(j % 4))) & 0xff; + } + } + break; + default: + ret = -1; + break; + } + + if (ret) + return -1; + else + return size; +} + +static int DP_DPCD_Access(dp_index index, unsigned char request, + unsigned int offset, void *buffer, int size) +{ + void *msg_buf = NULL; + int transfer_size = DP_AUX_MAX_PAYLOAD_BYTES; + int i = 0, msg_size = 0, msg_offset = 0, ret = 0; + + if (!buffer) + return -1; + + for (i = 0; i < size; i += msg_size) { + msg_buf = (unsigned char*)buffer + i; + msg_size = min1(size - i, transfer_size); + msg_offset = offset + i; + ret += DP_Aux_Transfer(index, request, msg_offset, msg_buf, msg_size); + } + + return ret; +} + +static int DP_DPCD_Write(dp_index index, unsigned int offset, void *buffer, int size) +{ + return DP_DPCD_Access(index, DP_AUX_NATIVE_WRITE, offset, buffer, size); +} + +static int DP_DPCD_Read(dp_index index, unsigned int offset, void *buffer, int size) +{ + return DP_DPCD_Access(index, DP_AUX_NATIVE_READ, offset, buffer, size); +} + +void DP_Audio_Reset(dp_index index) +{ + + DP_Write32(index, DP_TOP1C, + FIELD_SET(DP_Read32(index, DP_TOP1C), DP_TOP1C, REG_RESET_AUDIO, TRUE)); + DP_Write32(index, DP_TOP1C, + FIELD_SET(DP_Read32(index, DP_TOP1C), DP_TOP1C, REG_RESET_AUDIO, FALSE)); +} + + + +void DP_Audio_CheckOverrun(dp_index index) +{ + int timeout = 100; + + + // enable Audio overun event + DP_Write32(index, DP_TOP84, + FIELD_SET(DP_Read32(index, DP_TOP84), DP_TOP84, ENABLE_AUD_OVERRUN, TRUE)); + + + while ((FIELD_VAL_GET(DP_Read32(index,DP_TOP80), DP_TOP80, STA_AUD_OVERRUN) == DP_TOP80_STA_AUD_OVERRUN_TRUE) && timeout--) + { + + + DP_Write32(index,DP_TOP80,FIELD_SET(DP_Read32(index, DP_TOP80), DP_TOP80, STA_AUD_OVERRUN, TRUE)); //Clear status + + DP_Audio_Reset(index); + + } + +} + +/* + * Note:You must read the monitor's edid to determine if the monitor + * supports audio before enabling the audio function. + */ +static void DP_Audio_Start(dp_index index, int bits, int channel) +{ + unsigned int regval; + + /* sdp_audio_stream_vertical enable */ + /* sdp_audio_timestamp_vertical enable */ + DP_Write32(index, DP_CONTROLLER500, + FIELD_SET(0, DP_CONTROLLER500, SDP_AUDIO_STREAM_VERTICAL, ENABLE) | + FIELD_SET(0, DP_CONTROLLER500, SDP_AUDIO_TIMESTAMP_VERTICAL, ENABLE)); + + /* sdp_audio_stream_horizontal_enable */ + /* sdp_audio_timestamp_horizontal enable */ + DP_Write32(index, DP_CONTROLLER504, + FIELD_SET(0, DP_CONTROLLER504, SDP_AUDIO_STREAM_HORIZONTAL, ENABLE) | + FIELD_SET(0, DP_CONTROLLER504, SDP_AUDIO_TIMESTAMP_HORIZONTAL, ENABLE)); + + + regval = DP_Read32(index, DP_CONTROLLER300); + + if (channel == 2) + regval = FIELD_VALUE(regval, DP_CONTROLLER300, AUDIO_DATA_EN, DP_CONTROLLER300_AUDIO_DATA_EN_12); + else // sampleChannels == 8 + regval = FIELD_VALUE(regval, DP_CONTROLLER300, AUDIO_DATA_EN, DP_CONTROLLER300_AUDIO_DATA_EN_ALL); + + + regval = FIELD_VALUE(regval, DP_CONTROLLER300, AUDIO_DATA_WIDTH, bits); + regval = FIELD_VALUE(regval, DP_CONTROLLER300, AUDIO_CHANNEL_NUM, channel>2?channel:(channel-1)); + regval = FIELD_SET(regval, DP_CONTROLLER300, AUDIO_LEGEND, ALL); /* indicates channels 1,2 input data is vaild */ + + DP_Write32(index, DP_CONTROLLER300,regval); + + //disable AUD MUTE + DP_Write32(index, DP_CONTROLLER300, + FIELD_SET(DP_Read32(index, DP_CONTROLLER300), DP_CONTROLLER300, AUDIO_MUTE, CLEAR)); + + DP_Write32(index, 0x304, 0); + + //reset audio, + DP_Audio_Reset(index); + +} + +__attribute__((unused)) static int DP_Audio_Stop(dp_index index) +{ + DP_Write32(index, DP_CONTROLLER300, + FIELD_VALUE(DP_Read32(index, DP_CONTROLLER300), DP_CONTROLLER300, AUDIO_DATA_EN, DP_CONTROLLER300_AUDIO_DATA_EN_0)); /* indicates channels input data invaild */ + + /* sdp_audio_stream_vertical disable */ + /* sdp_audio_timestamp_vertical disable */ + DP_Write32(index, DP_CONTROLLER500, + FIELD_SET(0, DP_CONTROLLER500, SDP_AUDIO_TIMESTAMP_VERTICAL, DISABLE)); + + /* sdp_audio_stream_horizontal_disable */ + /* sdp_audio_timestamp_horizontal disable */ + DP_Write32(index, DP_CONTROLLER504, + FIELD_SET(0, DP_CONTROLLER504, SDP_AUDIO_TIMESTAMP_HORIZONTAL, DISABLE)); + + return 0; +} + + + + +void DP_Audio_Mute(dp_index index) +{ + + unsigned int regval; + + regval = DP_Read32(index, DP_CONTROLLER300); + regval = FIELD_SET(regval, DP_CONTROLLER300, AUDIO_MUTE, SET); + regval = FIELD_VALUE(regval, DP_CONTROLLER300, AUDIO_DATA_EN, 0); + regval = FIELD_VALUE(regval, DP_CONTROLLER300, AUDIO_CHANNEL_NUM, DP_CONTROLLER300_AUDIO_CHANNEL_NUM_1); + + DP_Write32(index, DP_CONTROLLER300,regval); + + +} + + +void DP_Audio_UnMute(dp_index index) +{ + + unsigned int regval; + + regval = DP_Read32(index, DP_CONTROLLER300); + + regval = FIELD_SET(regval, DP_CONTROLLER300, AUDIO_MUTE, CLEAR); + regval = FIELD_VALUE(regval, DP_CONTROLLER300, AUDIO_DATA_EN, DP_CONTROLLER300_AUDIO_DATA_EN_12); + regval = FIELD_VALUE(regval, DP_CONTROLLER300, AUDIO_CHANNEL_NUM, DP_CONTROLLER300_AUDIO_CHANNEL_NUM_2); + + DP_Write32(index, DP_CONTROLLER300,regval); + + +} + + + +static void DP_Drv_Init(dp_index index) +{ + // phy soft reset + DP_Write32(index, DP_TOP1C, // set reg0x001c[1] to 1 + FIELD_SET(DP_Read32(index, DP_TOP1C), DP_TOP1C, REG_RESET_PHY, TRUE)); + + usleep_range(1000, 1100); + + DP_Write32(index, DP_TOP1C, // set reg0x001c[1] to 0 + FIELD_SET(DP_Read32(index, DP_TOP1C), DP_TOP1C, REG_RESET_PHY, FALSE)); + + //dpureg(0x100), fast sim, disable lane channel + DP_Write32(index, DP_PHY100, (0x1 << 31) | + FIELD_SET(DP_Read32(index, DP_PHY100), DP_PHY100, TRANSMIT_ENABLE, NONE)); +} + +static void DP_Aux_Init(dp_index index) +{ + DP_Write32(index, 0x1a0, BIT1(15) | BIT1(14) | + DP_Read32(index, 0x1a0)); + + DP_Write32(index, DP_ANALOG180, + FIELD_SET(0, DP_ANALOG180, SSCG, DISABLE)); + DP_Write32(index, DP_ANALOG188, + FIELD_VALUE(DP_Read32(index, DP_ANALOG188), DP_ANALOG188, DA_COREPLL_POSTDIV, 0x1)); + + DP_Write32(index, 0x18c, 0x2a); + + DP_Write32(index, DP_ANALOG180, + FIELD_SET(0, DP_ANALOG180, SSCG, DISABLE) | + FIELD_VALUE(0, DP_ANALOG180, DA_COREPLL_PREDIV, 0x01) | + FIELD_VALUE(0, DP_ANALOG180, COREPLL_FBDIV, 0xe1)); + + usleep_range(1000, 1100); +} + +static void DP_Training_Pattern_Set(dp_index index, unsigned int pattern) +{ + unsigned int temp = 0; + + /* dpureg(0x100 DP_LANE_CONFIG) */ + temp = DP_Read32(index, DP_PHY100); + temp &= ~0xf; + temp |= BIT1(16); + temp |= pattern; + DP_Write32(index, DP_PHY100, temp); +} + +static void DP_Phy_Cfg(dp_index index) +{ + unsigned char lane_en = (1 << g_dp_info[index].lane_count) - 1; + + DP_Write32(index, DP_PHY100, + FIELD_VALUE(0, DP_PHY100, TRANSMIT_ENABLE, lane_en) | + FIELD_VALUE(0, DP_PHY100, PHY_LANES, g_dp_info[index].phy_lanes) | + FIELD_VALUE(0, DP_PHY100, PHY_RATE, g_dp_info[index].phy_rate)); + + if (g_dp_info[index].enhance_mode) { + DP_Write32(index, DP_TOP18, + FIELD_SET(DP_Read32(index, DP_TOP18), DP_TOP18, ENHANCE_FRAMING, ENABLE)); + } else { + DP_Write32(index, DP_TOP18, + FIELD_SET(DP_Read32(index, DP_TOP18), DP_TOP18, ENHANCE_FRAMING, DISABLE)); + } +} + +static void DP_Core_PLL_Cfg(dp_index index) +{ + + + if (g_dp_info[index].phy_rate >= ARRAY_SIZE(pll_table) || g_dp_info[index].phy_rate < 0) + g_dp_info[index].phy_rate = 1; + + DP_Write32(index, DP_ANALOG188, //dpureg(0x188), DP_SPREAD_CFG + FIELD_VALUE(DP_Read32(index, DP_ANALOG188), DP_ANALOG188, DA_COREPLL_POSTDIV, + (unsigned char) (pll_table[g_dp_info[index].phy_rate][pll_postdiv]))); + + DP_Write32(index, 0x18c, //dpureg(0x18c), DP_CLKDIV_16M + pll_table[g_dp_info[index].phy_rate][pll_clkdiv_16m]); + + DP_Write32(index, DP_ANALOG180, //dpureg(0x180) + FIELD_VALUE(0, DP_ANALOG180, DA_COREPLL_FBDIV, + (unsigned char) (0xf0 | ((pll_table[g_dp_info[index].phy_rate][pll_fbdiv] >> 8) & 0xf)) & 0xf) | + FIELD_VALUE(0, DP_ANALOG180, COREPLL_FBDIV, + (unsigned char) (pll_table[g_dp_info[index].phy_rate][pll_fbdiv] & 0xff)) | + FIELD_VALUE(0, DP_ANALOG180, DA_COREPLL_PREDIV, + (unsigned char) (0x0 | (pll_table[g_dp_info[index].phy_rate][pll_prediv] & 0x1f))) | + FIELD_SET(0, DP_ANALOG180, SSCG, DISABLE)); + + usleep_range(1000, 1100); + +} + +#define DIV_ROUNDUP(n, d) (((n) + (d) - 1) / (d)) + + +static void DP_Tu_Init(dp_index index) +{ + unsigned short htotal = g_dp_info[index].cea_mode->h_active + g_dp_info[index].cea_mode->h_blank; + //unsigned short hactive = g_dp_info[index].cea_mode->h_active; + unsigned short hblank = g_dp_info[index].cea_mode->h_blank; + unsigned int clock = g_dp_info[index].cea_mode->tmds_clk / 1000; + unsigned int hb_num = 0; + unsigned int tu; + unsigned int tu_frac; + unsigned int tu_int; + unsigned int rd_thres; + unsigned int link_rate = 0; + + if (!htotal) + return; + + if (g_dp_info[index].phy_rate == 0x00) { // 162GBPS + hb_num = hblank * 405 / clock/10; //(162 / 4) + link_rate = 162; + } else if (g_dp_info[index].phy_rate == 0x1) { // 270GBPS + hb_num = hblank * 675 / clock/10; //(270 / 4) + link_rate = 270; + } else if (g_dp_info[index].phy_rate == 0x2) { // 540GBPS + hb_num = hblank * 135 / clock; //(540 / 4) + link_rate = 540; + } + + tu = DIV_ROUNDUP(clock * 24 * 640 , 8 * g_dp_info[index].lane_count * link_rate) ; + + tu_frac = tu % 10; + tu_int = tu / 10; + + if (tu_int < 6) { + rd_thres = 32; + } else if (hblank < 80) { + rd_thres = 12; + } else { + rd_thres = 16; + } + + // hblank *link_clk/pixel_clk; link_clk = symbol clock /4; @1.62G --> 280*(162/4)/148.5 = 76.3636 + DP_Write32(index, DP_CONTROLLER230, + FIELD_VALUE(0, DP_CONTROLLER230, HBLANK_LINK_CYC, hb_num)); + // tu = 148.5*24*640 / 8*4*1620 = 44 + DP_Write32(index, DP_CONTROLLER220, + FIELD_VALUE(0, DP_CONTROLLER220, REG_LINE_RD_THRES, rd_thres) | + FIELD_VALUE(0, DP_CONTROLLER220, REG_AVG_PER_TU_INT, tu_int) | + FIELD_VALUE(0, DP_CONTROLLER220, REG_AVG_PER_TU_FRAC, tu_frac)); +} + +static unsigned char DP_Link_Status(const unsigned char link_status[DP_LINK_STATUS_SIZE], int r) +{ + return link_status[r - DP_LANE0_1_STATUS]; +} + +static unsigned char DP_Get_Lane_Status(const unsigned char link_status[DP_LINK_STATUS_SIZE], + int lane) +{ + int i = DP_LANE0_1_STATUS + (lane >> 1); + int s = (lane & 1) * 4; + unsigned char l = DP_Link_Status(link_status, i); + + return (l >> s) & 0xf; +} + +static unsigned char DP_Get_Adjust_Request_Voltage(const unsigned char link_status[DP_LINK_STATUS_SIZE], + int lane) +{ + int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); + int s = ((lane & 1) ? + DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : + DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT); + unsigned char l = DP_Link_Status(link_status, i); + + return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT; +} + +static unsigned char DP_Get_Adjust_Request_Pre_Emphasis(const unsigned char link_status[DP_LINK_STATUS_SIZE], + int lane) +{ + int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); + int s = ((lane & 1) ? + DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT : + DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT); + unsigned char l = DP_Link_Status(link_status, i); + + return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; +} + +static bool DP_Clk_Recovery_OK(const unsigned char link_status[DP_LINK_STATUS_SIZE], + int lane_count) +{ + int lane; + unsigned char lane_status; + + for (lane = 0; lane < lane_count; lane++) { + lane_status = DP_Get_Lane_Status(link_status, lane); + if ((lane_status & DP_LANE_CR_DONE) == 0) + return false; + } + return true; +} + +static bool DP_Channel_EQ_OK(const unsigned char link_status[DP_LINK_STATUS_SIZE], + int lane_count) +{ + unsigned char lane_align; + unsigned char lane_status; + int lane; + + lane_align = DP_Link_Status(link_status, + DP_LANE_ALIGN_STATUS_UPDATED); + if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) + return false; + for (lane = 0; lane < lane_count; lane++) { + lane_status = DP_Get_Lane_Status(link_status, lane); + if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS) + return false; + } + return true; +} + +static inline bool +DP_Enhanced_Frame_Cap(const unsigned char dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_DPCD_REV] >= 0x11 && + (dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP); +} + +static void DP_Get_Adjust_Train(dp_index index, + const unsigned char link_status[DP_LINK_STATUS_SIZE]) +{ + unsigned char post_cursor; + int lane; + DP_DPCD_Read(index, DP_ADJUST_REQUEST_POST_CURSOR2, &post_cursor, sizeof(post_cursor)); + + for (lane = 0; lane < g_dp_info[index].lane_count; lane++) { + g_dp_info[index].swing[lane] = DP_Get_Adjust_Request_Voltage(link_status, lane); + g_dp_info[index].preem[lane] = DP_Get_Adjust_Request_Pre_Emphasis(link_status, lane); + g_dp_info[index].pcursor[lane] = (post_cursor >> (lane << 1)) & 0x3; + } +} + +static void DP_Voltage_Swing_Adjust(dp_index index) +{ + unsigned char train_set[4]; + int i, lane; + + /* FROM KERNEL CODE!!! write currently selected post-cursor level (if supported) */ + if (g_dp_info[index].dpcd_rev >= 0x12 && g_dp_info[index].lane_rate == DP_LINK_BW_5_4) + { + train_set[0] = train_set[1] = 0; + + for (i = 0; i < g_dp_info[index].lane_count; i++) + train_set[i / 2] |= (((g_dp_info[index].pcursor[i]) & 0x3) << (((i) & 1) << 2)); + + DP_DPCD_Write(index, DP_TRAINING_LANE0_1_SET2, train_set, + (((g_dp_info[index].lane_count) + (2) - 1) / (2))); + } + + for (lane = 0; lane < g_dp_info[index].lane_count; lane++) { + train_set[lane] = g_dp_info[index].swing[lane]; + if (g_dp_info[index].swing[lane] >= DP_TRAIN_VOLTAGE_SWING_LEVEL_2) + train_set[lane] |= DP_TRAIN_MAX_SWING_REACHED; + + train_set[lane] |= (g_dp_info[index].preem[lane]); + if (g_dp_info[index].preem[lane] >= DP_TRAIN_PRE_EMPH_LEVEL_2) + train_set[lane] |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; + } + + DP_DPCD_Write(index, DP_TRAINING_LANE0_SET, + train_set, g_dp_info[index].lane_count); +} + +static int dp_bw_table[] = { + DP_LINK_BW_1_62, + DP_LINK_BW_2_7, + DP_LINK_BW_5_4, + DP_LINK_BW_8_1, +}; + +static int DP_Rate_Index(const int *rates, int len, int rate) +{ + int i; + + for (i = 0; i < len; i++) + if (rate == rates[i]) + return i; + + return -1; +} + +static void DP_EDP_Init_DPCD(dp_index index) +{ + unsigned char edp_rev = 0; + int val = 0, i = 0; + unsigned char sink_rates[DP_MAX_SUPPORTED_RATES * 2]; + + /* Read the eDP display control registers. */ + DP_DPCD_Read(index, DP_EDP_DPCD_REV, &edp_rev, 1); + + if (edp_rev >= DP_EDP_14) { + /* Read the eDP 1.4+ supported link rates. */ + DP_DPCD_Read(index, DP_SUPPORTED_LINK_RATES, sink_rates, sizeof(sink_rates)); + + for (i = 0; i < DP_MAX_SUPPORTED_RATES; i++) { + val = sink_rates[i * 2 + 1] << 8 | + sink_rates[i * 2 + 0]; + + if (val == 0) + break; + + /* Value read multiplied by 200kHz gives the per-lane + * link rate in kHz. + */ + g_dp_info[index].sink_rates[i] = (val * 200) / 270000; + + if (g_dp_info[index].sink_rates[i] > g_dp_info[index].max_sink_rates && + g_dp_info[index].sink_rates[i] <= DP_LINK_BW_5_4 && + DP_Rate_Index(dp_bw_table, ARRAY_SIZE(dp_bw_table), g_dp_info[index].sink_rates[i]) >= 0) { + g_dp_info[index].max_sink_rates = g_dp_info[index].sink_rates[i]; + } + } + g_dp_info[index].num_sink_rates = i; + } +} + +static void DP_EDP_Rate_Set(dp_index index) +{ + unsigned char rate_select = 0; + + if (g_dp_info[index].max_sink_rates) { + rate_select = DP_Rate_Index(g_dp_info[index].sink_rates, + g_dp_info[index].num_sink_rates, g_dp_info[index].lane_rate); + + if (rate_select >= 0) { + DP_DPCD_Write(index, DP_LINK_RATE_SET, &rate_select, 1); + } + } +} + +static void DP_CDR_Training(dp_index index) +{ + int i = 0; + //unsigned int value; + unsigned char link_cfg[2]; + unsigned char link_status[DP_LINK_STATUS_SIZE]; + + DP_Training_Pattern_Set(index, DP_TRAINING_PATTERN_1); + + DP_EDP_Rate_Set(index); + + /* Write the link configuration data */ + link_cfg[0] = g_dp_info[index].lane_rate; + link_cfg[1] = g_dp_info[index].lane_count | (g_dp_info[index].enhance_mode << 7); /* DP_LANE_COUNT_SET */ + DP_DPCD_Write(index, DP_LINK_BW_SET, link_cfg, 2); + + link_cfg[0] = 0; + link_cfg[1] = DP_DP_PHY108_SET_ANSI_8B10B; + DP_DPCD_Write(index, DP_PHY108, link_cfg, 2); + + link_cfg[0] = DP_TRAINING_PATTERN_1; /* DP_TRAINING_PATTERN_SET */ + DP_DPCD_Write(index, DP_TRAINING_PATTERN_SET, link_cfg, 1); + + if (g_dp_info[index].cdr_delay <= 0) + g_dp_info[index].cdr_delay = 4; + else + g_dp_info[index].cdr_delay *= 4; + + for (i = 0; i < 15; i++) { + + usleep_range(g_dp_info[index].cdr_delay * 1000, g_dp_info[index].cdr_delay * 1100); + + if (DP_DPCD_Read(index, DP_LANE0_1_STATUS, link_status, + DP_LINK_STATUS_SIZE) != DP_LINK_STATUS_SIZE) { + return; + } + + if (DP_Clk_Recovery_OK(link_status, g_dp_info[index].lane_count)) { + printk("dp[%d] get DPCD 0x%.2x%.2x, tps1 pass\n", index, link_status[0], link_status[1]); + break; + } else { + printk("dp[%d] get DPCD 0x%.2x%.2x, tps1 fail, retry\n", index, link_status[0], link_status[1]); + DP_Get_Adjust_Train(index, link_status); + DP_Voltage_Swing_Adjust(index); + } + } +} + +static void DP_EQ_Training(dp_index index) +{ + int i = 0, delay = 0; + unsigned char link_cfg[2]; + unsigned char link_status[DP_LINK_STATUS_SIZE]; + + DP_Training_Pattern_Set(index, DP_TRAINING_PATTERN_2); + + link_cfg[0] = DP_TRAINING_PATTERN_2; /* DP_TRAINING_PATTERN_SET */ + DP_DPCD_Write(index, DP_TRAINING_PATTERN_SET, link_cfg, 1); + + if (g_dp_info[index].eq_delay <= 0) + g_dp_info[index].eq_delay = 4; + else + g_dp_info[index].eq_delay *= 4; + + delay = g_dp_info[index].eq_delay; + + for (i = 0; i < 15; i++) { + + usleep_range(delay*1000, delay*1100); + + if (DP_DPCD_Read(index, DP_LANE0_1_STATUS, link_status, + DP_LINK_STATUS_SIZE) != DP_LINK_STATUS_SIZE) { + return; + } + + if (DP_Channel_EQ_OK(link_status, g_dp_info[index].lane_count)) { + printk("dp[%d] get DPCD 0x%.2x%.2x, tps2 pass\n", index, link_status[0], link_status[1]); + break; + } else { + printk("dp[%d] get DPCD 0x%.2x%.2x, tps2 fail, retry\n", index, link_status[0], link_status[1]); + DP_Get_Adjust_Train(index, link_status); + DP_Voltage_Swing_Adjust(index); + } + + // Sometimes, we won't be able to get the correct status because of the lack of delay. + delay = g_dp_info[index].eq_delay * 10; + } +} + +static void DP_Link_Start(dp_index index) +{ + unsigned char link_cfg[9] = {0}; + + DP_Training_Pattern_Set(index, DP_TRAINING_PATTERN_DISABLE); + + link_cfg[0] = DP_TRAINING_PATTERN_DISABLE; + DP_DPCD_Write(index, DP_TRAINING_PATTERN_SET, link_cfg, 1); +} + +static int DP_Sink_Lane_Status_Get(dp_index index, unsigned char status[DP_LINK_STATUS_SIZE]) +{ + if (DP_DPCD_Read(index, DP_LANE0_1_STATUS, status, DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE) + return 0; + + return -1; +} + +static void DP_Link_Cfg(dp_index index) +{ + DP_Core_PLL_Cfg(index); + // ebable SSC + + +// DP_SSC_Enable(index,1,0,0); + + + DP_Phy_Cfg(index); + DP_Tu_Init(index); +} + + +static bool DP_Rate_Valid(int lane_rate, int lane_count, int clock, int bpc) +{ + unsigned long requirement, capacity; + + /* bandwidth: rate * lane_count + * rate = lane_rate * 27 unit(GBps) + * For more detailed information see the DP specification + */ + + capacity = lane_rate * 27 * 1000 * 8 * lane_count; + requirement = clock * bpc * 3 ; + + if (capacity >= requirement) + return true; + + return false; +} + +static int DP_Rate_Adjust(dp_index index) +{ + unsigned char reduce_lane_rate = 0; + unsigned char reduce_phy_rate = 0; + int i = 0; + + i = DP_Rate_Index(dp_bw_table, ARRAY_SIZE(dp_bw_table), g_dp_info[index].lane_rate); + if (i > 0 && i < ARRAY_SIZE(dp_bw_table)) { + reduce_lane_rate = dp_bw_table[i - 1]; + reduce_phy_rate = i - 1; + } else { + return -1; + } + + if (DP_Rate_Valid(reduce_lane_rate, g_dp_info[index].lane_count, + g_dp_info[index].cea_mode->tmds_clk, 8) && i >= 0) { + g_dp_info[index].lane_rate = reduce_lane_rate; + g_dp_info[index].phy_rate = reduce_phy_rate; + return 0; + } + + return -1; +} + +static unsigned char DP_Check_Sink_Power(dp_index index) +{ + return g_dp_info[index].sink_power_status; +} + +static int DP_Link_Train_Lock(dp_index index) +{ + unsigned char link_status[DP_LINK_STATUS_SIZE]; + + if (!DP_Sink_Lane_Status_Get(index, link_status) && + (!DP_Clk_Recovery_OK(link_status, g_dp_info[index].lane_count) || !DP_Channel_EQ_OK(link_status, g_dp_info[index].lane_count))) + return false; + + return true; +} + +int DP_Check_Sink_Status(dp_index index) +{ + unsigned char ret = 1; + + // The powerStatus of some displays does not turn on when it is 0. + ret = DP_Check_Sink_Power(index); + if (ret == 2) + return -1; + // Sometimes, the training results may change, requiring re-training. + ret = DP_Link_Train_Lock(index); + if (ret == false) + return -1; + + return 0; +} + +static int DP_Link_Train(dp_index index) +{ + int retry_count = 0; + +RETRY: + if (!DP_HPD_Detect(index)) + { + printk("dp unplug\n"); + return DP_FAILURE; + } + + printk("dp[%d] Training Start. rate[%x] count[%x]\n", index, g_dp_info[index].lane_rate, g_dp_info[index].lane_count); + DP_CDR_Training(index); + DP_EQ_Training(index); + DP_Link_Start(index); + + if (!DP_Link_Train_Lock(index)){ + printk("link train fail\n"); + if (retry_count < 3) { + retry_count++; + goto RETRY; + } else { + if (!DP_Rate_Adjust(index)) + { + DP_Link_Cfg(index); + retry_count = 0; + goto RETRY; + } + } + } + + return DP_SUCCESS; +} + +static int DP_Sink_Power_Ctrl(dp_index index, bool power_on) +{ + unsigned char value = 0; + int err = -1; + + if (g_dp_info[index].dpcd_rev < DP_REV_11) + goto END; + + err = DP_DPCD_Read(index, DP_SET_POWER, &value, 1); + if (err < 0) + goto END; + + value &= ~DP_SET_POWER_MASK; + /* Sink - (State3 Sleep): + * 1. Hpd asserted + * 2. Aux enabled for differential signal monitoring, + * 3. Main-link Rx disabled + */ + + /* Sink - (State 2 standby): + * 1. Hpd asserted + * 2. Aux enabled for differential signal monitoring, + * 3. Main-link Rx enabled + */ + + value |= (power_on ? DP_SET_POWER_D0 : DP_SET_POWER_D3); + + err = DP_DPCD_Write(index, DP_SET_POWER, &value, 1); + if (err < 0) + goto END; + + /* According to the DP 1.1 specification, a "Sink Device must exit the + * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink + * Control Field" (register 0x600). + */ + if (power_on) { + /* For an embedded connection, a Sink device may take up to 20 ms from a power-save mode + * until it is ready to reply to an AUX request transaction + */ + if (g_dp_info[index].max_sink_rates) + usleep_range(20000,21000); + else + usleep_range(1000, 1100); + } + +END: + return err; +} + +static void DP_Link_Caps_Reset(dp_index index) +{ + g_dp_info[index].cdr_delay = 0; + g_dp_info[index].eq_delay = 0; + g_dp_info[index].dpcd_rev = 0; + g_dp_info[index].enhance_mode = 1; + g_dp_info[index].max_sink_rates = 0; + g_dp_info[index].num_sink_rates = 0; + g_dp_info[index].lane_count = 4; + g_dp_info[index].lane_rate = DP_LINK_BW_5_4; + g_dp_info[index].cea_mode = 0; + g_dp_info[index].max_downspread = 0; +} + +static void DP_Compliance_Cfg(dp_index index) +{ + int ret = 0; + unsigned int retry = 0, i = 0; + + DP_Link_Caps_Reset(index); + + for (retry = 0; retry <= 3; retry++) { + ret = DP_DPCD_Read(index, DP_DPCD_REV, g_dp_info[index].dpcd, DP_RECEIVER_CAP_SIZE); + if (ret == DP_RECEIVER_CAP_SIZE && + g_dp_info[index].dpcd[DP_DPCD_REV] >= DP_REV_10 && + g_dp_info[index].dpcd[DP_DPCD_REV] <= DP_REV_14) { + + g_dp_info[index].dpcd_rev = g_dp_info[index].dpcd[DP_DPCD_REV]; + g_dp_info[index].lane_rate = g_dp_info[index].dpcd[DP_MAX_LINK_RATE]; + g_dp_info[index].lane_count = g_dp_info[index].dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK; + g_dp_info[index].enhance_mode = DP_Enhanced_Frame_Cap(g_dp_info[index].dpcd) ? 1 : 0; + g_dp_info[index].cdr_delay = g_dp_info[index].dpcd[DP_TRAINING_AUX_RD_INTERVAL] & 0x7f; + g_dp_info[index].eq_delay = g_dp_info[index].dpcd[DP_TRAINING_AUX_RD_INTERVAL] & 0x7f; + + if (g_dp_info[index].lane_rate >= DP_LINK_BW_5_4) + { + g_dp_info[index].lane_rate = DP_LINK_BW_5_4; + } + + DP_EDP_Init_DPCD(index); + + break; + } else if (ret < 0) { + break; + } + + usleep_range(5000, 5100); + } + + /* For EDP 1.4 */ + if (g_dp_info[index].max_sink_rates) + g_dp_info[index].lane_rate = g_dp_info[index].max_sink_rates; + + i = DP_Rate_Index(dp_bw_table, ARRAY_SIZE(dp_bw_table), g_dp_info[index].lane_rate); + if (i >= 0) { + g_dp_info[index].phy_rate = i; + } else { + g_dp_info[index].lane_rate = DP_LINK_BW_5_4; + g_dp_info[index].phy_rate = 0x2; + } + + if (g_dp_info[index].lane_count >= 0x1 && g_dp_info[index].lane_count <= 0x4) { + g_dp_info[index].phy_lanes = g_dp_info[index].lane_count >> 1; + } else { + g_dp_info[index].phy_lanes = 0x2; + g_dp_info[index].lane_count = 0x4; + } + + printk("get current dp[%d] info: rev[%x] laneRate[%x] laneCount[%x] phyRate[%x] phyLanes[%x]\n", + index, g_dp_info[index].dpcd_rev, g_dp_info[index].lane_rate, g_dp_info[index].lane_count, + g_dp_info[index].phy_rate, g_dp_info[index].phy_lanes); +} + +static void DP_Video_Cfg(dp_index index) +{ + unsigned short htotal = g_dp_info[index].cea_mode->h_active + g_dp_info[index].cea_mode->h_blank; + unsigned short hactive = g_dp_info[index].cea_mode->h_active; + unsigned short vtotal = g_dp_info[index].cea_mode->v_active + g_dp_info[index].cea_mode->v_blank; + unsigned short vactive = g_dp_info[index].cea_mode->v_active; + unsigned short hblank = g_dp_info[index].cea_mode->h_blank; + unsigned short hsync = g_dp_info[index].cea_mode->hsync_width; + unsigned short hoffset = g_dp_info[index].cea_mode->h_blank - g_dp_info[index].cea_mode->hsync_delay; + unsigned short vblank = g_dp_info[index].cea_mode->v_blank; + unsigned short vsync = g_dp_info[index].cea_mode->vsync_width; + unsigned short voffset = g_dp_info[index].cea_mode->v_blank - g_dp_info[index].cea_mode->vsync_delay; + unsigned short hpolarity = g_dp_info[index].cea_mode->hsync_polarity; + unsigned short vpolarity = g_dp_info[index].cea_mode->vsync_polarity; + unsigned char msa_misc0 = 0x20; + unsigned char msa_misc1 = 0x00; + + // RGB 8bit + DP_Write32(index, DP_CONTROLLER200, + FIELD_SET(DP_Read32(index, DP_CONTROLLER200), DP_CONTROLLER200, VIDEO_MAPPING, RGB8)); + // h/v start + DP_Write32(index, DP_CONTROLLER224, + FIELD_VALUE(0, DP_CONTROLLER224, REG_TX_HSTART, hoffset) | + FIELD_VALUE(0, DP_CONTROLLER224, REG_TX_VSTART, voffset)); + // sync polarity + DP_Write32(index, DP_CONTROLLER20C, + FIELD_VALUE(0, DP_CONTROLLER20C, REG_TX_POLARITY_HSYNC, hpolarity) | + FIELD_VALUE(0, DP_CONTROLLER20C, REG_TX_POLARITY_VSYNC, vpolarity)); + // misc0, 8 bits/color respectively + DP_Write32(index, DP_CONTROLLER228, + FIELD_VALUE(0, DP_CONTROLLER228, REG_TX_MSA_MISC0, msa_misc0)); + // h active/blank + DP_Write32(index, DP_CONTROLLER210, + FIELD_VALUE(0, DP_CONTROLLER210, REG_TX_HBLANK, hblank) | + FIELD_VALUE(0, DP_CONTROLLER210, REG_TX_HACTIVE, hactive)); + // misc1 + DP_Write32(index, DP_CONTROLLER22C, + FIELD_VALUE(0, DP_CONTROLLER22C, REG_TX_MSA_MISC1, msa_misc1)); + // v active/blank + DP_Write32(index, DP_CONTROLLER214, + FIELD_VALUE(0, DP_CONTROLLER214, REG_TX_VBLANK, vblank) | + FIELD_VALUE(0, DP_CONTROLLER214, REG_TX_VACTIVE, vactive)); + // h sync/front porch + DP_Write32(index, DP_CONTROLLER218, + FIELD_VALUE(0, DP_CONTROLLER218, REG_TX_H_FRONT_PORCH, htotal - hactive - hoffset) | + FIELD_VALUE(0, DP_CONTROLLER218, REG_TX_HSWIDTH, hsync)); + // v sync/front porch + DP_Write32(index, DP_CONTROLLER21C, + FIELD_VALUE(0, DP_CONTROLLER21C, REG_TX_V_FRONT_PORCH, vtotal - vactive - voffset) | + FIELD_VALUE(0, DP_CONTROLLER21C, REG_TX_VSWIDTH, vsync)); + + DP_Tu_Init(index); +} + +static int DP_Check_EDID_Sum(unsigned char *edid) +{ + int i, checksum = 0; + + for(i = 0; i < DP_EDID_BUF_LEN; i++) // EDID_LEN -> 128 + checksum += edid[i]; + + return checksum % (DP_EDID_BUF_LEN * 2); //CEA-861 Spec +} + +static int DP_EDID_Is_Invalid(unsigned char *pEDIDBuffer, int blockCount) +{ + int error = 0; + const unsigned char header[] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}; + + if (blockCount == 1) + { + error = memcmp(pEDIDBuffer, (unsigned char *)header, sizeof(header)); + if (error) + { + printk("EDID header check failed\n"); + goto END; + } + } + + error = DP_Check_EDID_Sum(pEDIDBuffer); + if(error){ + printk("EDID checksum failed\n"); + goto END; + } + +END: + return error; +} + +static int DP_Read_EDID_IIC_Aux(dp_index index, unsigned char *pEDIDBuffer, unsigned short *pBufferSize, bool sigleByte) +{ + int ret = 0, blockCount = 1, i,j; + int lenLeft = DP_EDID_BUF_LEN; + unsigned char val[16] = { 0 }; + + /* Send a bare address packet to start the transaction. + * Zero sized messages specify an address only (bare + * address) transaction. + */ + DP_Aux_Transfer(index, DP_AUX_I2C_WRITE, 0x50, NULL, 0); + + for (i = 0; i < blockCount; i++) + { + lenLeft = DP_EDID_BUF_LEN; + do + { + if (lenLeft < DP_AUX_MAX_PAYLOAD_BYTES || sigleByte) + { + ret = DP_Aux_Transfer(index, DP_AUX_I2C_READ, 0x50, val, 1); + if (ret <= 0 || ret > DP_AUX_MAX_PAYLOAD_BYTES) + goto ERR; + }else{ + ret = DP_Aux_Transfer(index, DP_AUX_I2C_READ, 0x50, val, DP_AUX_MAX_PAYLOAD_BYTES); + if (ret <= 0 || ret > DP_AUX_MAX_PAYLOAD_BYTES) + goto ERR; + } + + for (j = 0; j < ret; j++) + pEDIDBuffer[j + *pBufferSize] = val[j]; + + *pBufferSize += ret; + lenLeft = DP_EDID_BUF_LEN * (i + 1) - *pBufferSize; + } while (lenLeft > 0); + + blockCount = pEDIDBuffer[126] + 1; + if (*pBufferSize % DP_EDID_BUF_LEN != 0) + goto ERR; + if (DP_EDID_Is_Invalid(pEDIDBuffer, *pBufferSize / DP_EDID_BUF_LEN)) + goto ERR; + } + + /* Send a bare address packet to close out the transaction. + * Zero sized messages specify an address only (bare + * address) transaction. + */ + DP_Aux_Transfer(index, DP_AUX_I2C_WRITE & ~DP_AUX_I2C_MOT, 0x50, NULL, 0); + return DP_SUCCESS; +ERR: + DP_Aux_Transfer(index, DP_AUX_I2C_WRITE & ~DP_AUX_I2C_MOT, 0x50, NULL, 0); + return DP_FAILURE; +} + +void DP_Set_Channel(dp_index index, disp_control_t dc) +{ + disp_output_t disp_index; + + if (index == INDEX_DP0) + { + disp_index = DP0; + }else if (index == INDEX_DP1){ + disp_index = DP1; + }else{ + return; + } + + setDCMUX(disp_index, dc); +} + +void DP_Clear_Channel(dp_index index) +{ + disp_output_t disp_index; + + if (index == INDEX_DP0) + { + disp_index = DP0; + }else if (index == INDEX_DP1){ + disp_index = DP1; + }else{ + return; + } + + ClearDCMUX(disp_index); +} + +unsigned char DP_Get_Channel(dp_index index) +{ + disp_output_t disp_index; + + if (index == INDEX_DP0) + { + disp_index = DP0; + }else if (index == INDEX_DP1){ + disp_index = DP1; + }else{ + return 0; + } + + return GetDCMUX(disp_index); +} + +static void DP_HPD_Enable(dp_index index) +{ + unsigned int regval = 0; + + /*fast sim*/ + DP_Write32(index, DP_TOP18, + FIELD_SET(DP_Read32(index, DP_TOP18), DP_TOP18, REG_HPD_SCALE, SCALING)); + + regval = DP_Read32(index, DP_TOP84); + // enable plug in hpd event + regval = FIELD_SET(regval, DP_TOP84, ENABLE_HPD_PLUG_EVENT, TRUE); + // enable unplug hpd event + regval = FIELD_SET(regval, DP_TOP84, ENABLE_HPD_UNPLUG_EVENT, TRUE); + DP_Write32(index, DP_TOP84, regval); + + regval = DP_Read32(index, DP_TOP8C); + // enable hpd plug + regval = FIELD_SET(regval, DP_TOP8C, HPD_PLUG, ENABLE); + // enable hpd unplug + regval = FIELD_SET(regval, DP_TOP8C, HPD_UNPLUG, ENABLE); + // enable hpd irq + regval = FIELD_SET(regval, DP_TOP8C, HPD_IRQ, ENABLE); + DP_Write32(index, DP_TOP8C, regval); +} + +int DP_HPD_Detect(dp_index index) +{ + DP_HPD_Enable(index); + + if ((DP_Read32(index, DP_TOP88) & 0xf00) == 0xf00) + return true; + + return false; +} + +int DP_Enable(dp_index index) +{ + DP_Sink_Power_Ctrl(index, true); + + if (DP_Link_Train(index) == DP_FAILURE) + { + return DP_FAILURE; + } + + DP_Write32(index, DP_CONTROLLER200, + FIELD_SET(DP_Read32(index, DP_CONTROLLER200), DP_CONTROLLER200, VIDEO_STREAM, ENABLE)); + + DP_Audio_Start(index, DP_CONTROLLER300_AUDIO_DATA_WIDTH_24, 2); + + DP_Audio_CheckOverrun(index); + + return DP_SUCCESS; +} + +int DP_Disable(dp_index index) +{ + DP_Write32(index, DP_PHY100, + FIELD_SET(DP_Read32(index, DP_PHY100), DP_PHY100, TRANSMIT_ENABLE, NONE)); + + DP_Write32(index, DP_CONTROLLER200, + FIELD_SET(DP_Read32(index, DP_CONTROLLER200), DP_CONTROLLER200, VIDEO_STREAM, DISABLE)); + + return 0; +} + + +void DP_SSC_Enable(dp_index index, unsigned int downspread, unsigned int freq, unsigned int amp) +{ + unsigned int val; + + printk("Enable DP SSC\n"); + + val = DP_Read32(index, DP_ANALOG188); + if (freq){ + freq = 24000000/pll_table[g_dp_info[index].phy_rate][pll_fbdiv]/128/freq; + val = FIELD_VALUE(val, DP_ANALOG188, REG_DIVVAL, freq); + } + else + val = FIELD_VALUE(val, DP_ANALOG188, REG_DIVVAL, 0x3); + + if (amp) + val = FIELD_VALUE(val, DP_ANALOG188, REG_SPREAD, amp); + DP_Write32(index, DP_ANALOG188, val); + + val = DP_Read32(index, DP_ANALOG180); + + if (downspread) + val = FIELD_SET(val, DP_ANALOG180, DOWNSPREAD, DOWN); + else + val = FIELD_SET(val, DP_ANALOG180, DOWNSPREAD, CENTER); + + val = FIELD_VALUE(val, DP_ANALOG180, DA_COREPLL_FRAC_PD, 0X0); + val = FIELD_SET(val, DP_ANALOG180, SSCG, ENABLE); + DP_Write32(index, DP_ANALOG180, val); +} + +void DP_SSC_Disable(dp_index index) +{ + + DP_Write32(index, DP_ANALOG180, + FIELD_SET(DP_Read32(index, DP_ANALOG180), DP_ANALOG180, SSCG, DISABLE)); + +} + +int DP_Setmode(dp_index index, logicalMode_t *pLogicalMode , mode_parameter_t *pModeParam) +{ + cea_parameter_t cea_mode = {0}; + unsigned int offset = (pLogicalMode->dispCtrl > 1)? CHANNEL_OFFSET2 : pLogicalMode->dispCtrl * CHANNEL_OFFSET; + + if (!DP_HPD_Detect(index)) + { + printk("dp unplug\n"); + return DP_FAILURE; + } + + printk("DP Setmode Start.\n"); + + + + if ((int)Get_CEA_Mode(pLogicalMode,&cea_mode, pModeParam, 1) < 0) + { + return DP_FAILURE; + } + + DP_Drv_Init(index); + DP_Aux_Init(index); + + DP_Compliance_Cfg(index); + g_dp_info[index].cea_mode = &cea_mode; + g_dp_info[index].sink_power_status = 1; + + DP_Link_Cfg(index); + + DP_Write32(index, DP_TOP18, + FIELD_SET(DP_Read32(index, DP_TOP18), DP_TOP18, SCRAMBLE, ENABLE)); + DP_Write32(index, DP_TOP18, + FIELD_SET(DP_Read32(index, DP_TOP18), DP_TOP18, ENHANCE_FRAMING, ENABLE)); + DP_Write32(index, DP_TOP18, + FIELD_SET(DP_Read32(index, DP_TOP18), DP_TOP18, REG_HPD_SCALE, SCALING)); + + pokeRegisterDWord(VERTICAL_SYNC + offset, FIELD_VALUE(peekRegisterDWord(VERTICAL_SYNC + offset), VERTICAL_SYNC, DPMODE, 0)); + + DP_Video_Cfg(index); + + if (DP_Enable(index) == DP_FAILURE) + { + + return DP_FAILURE; + } + + + printk("DP Setmode Finish.\n"); + return DP_SUCCESS; +} + +__attribute__((unused)) static unsigned char Check_Sink_Power(dp_index index) +{ + return g_dp_info[index].sink_power_status; +} + +void DP_Enable_Output(dp_index index) +{ + DP_Write32(index, DP_CONTROLLER200, + FIELD_SET(DP_Read32(index, DP_CONTROLLER200),DP_CONTROLLER200, VIDEO_STREAM, ENABLE)); + DP_Audio_UnMute(index); +} + +void DP_Disable_Output(dp_index index) +{ + DP_Write32(index, DP_CONTROLLER200, + FIELD_SET(DP_Read32(index, DP_CONTROLLER200),DP_CONTROLLER200, VIDEO_STREAM,DISABLE)); + DP_Audio_Mute(index); +} + +int DP_Read_EDID(dp_index index, unsigned char *pEDIDBuffer, unsigned short *pBufferSize) +{ + int ret = -1, retry; + unsigned char *pTmpaddr = pEDIDBuffer; + *pBufferSize = 0; + + + if (pEDIDBuffer == NULL) + { + printk("buffer is NULL!\n"); + return 0; + } + + if (DP_HPD_Detect(index)) + { + bool singleByte = false; + for (retry = 0; retry < 5; retry++) + { + if (retry >=2) + singleByte = true; + if (DP_Read_EDID_IIC_Aux(index, pEDIDBuffer, pBufferSize, singleByte) == DP_SUCCESS) + { + return 0; + } + pEDIDBuffer = pTmpaddr; + *pBufferSize = 0; + } + } + + return ret; +} + +/* +The GPIO needs to be forcibly pulled low +to avoid the HPD state remaining as "connected" when the DP HPD pin is floating. +*/ +static void DP_HPD_PD_Enable(dp_index index) +{ + unsigned int regval; + regval = peekRegisterDWord(GPIO_PAD_DP0_HPD + index * 4); + regval = FIELD_SET(regval, GPIO_PAD_DP0_HPD, PD, ENABLE); + + pokeRegisterDWord(GPIO_PAD_DP0_HPD + index * 4, regval); +} +int DP_Init(dp_index index) +{ + // From INNO advice + DP_Write32(index, 0x1a4 , 0x55ff0f0f); + DP_Write32(index, 0x1a8 , 0x1f1f0055); + DP_Write32(index, 0x1ac , 0x44441f1f); + DP_Write32(index, 0x1b0 , 0xf0000000); + DP_Write32(index, 0x1a0 , 0x0000d090); + + DP_Drv_Init(index); + DP_Aux_Init(index); + DP_HPD_PD_Enable(index); + return DP_SUCCESS; +} + +//----------------------------------------------------------------------------- +// DP Interrupt functions +//----------------------------------------------------------------------------- +typedef struct _dp_interrupt_t +{ + struct _dp_interrupt_t *next; + void (*handler)(void); +} dp_interrupt_t; + +static dp_interrupt_t *g_pDP0IntHandlers = ((dp_interrupt_t *)0); +static dp_interrupt_t *g_pDP1IntHandlers = ((dp_interrupt_t *)0); + +/* HDMI Interrupt Service Routine */ +__attribute__((unused)) static void dp0ISR( + unsigned int status) +{ + dp_interrupt_t *pfnHandler; + + if (FIELD_VAL_GET(status, INT_STATUS, DP0) == INT_STATUS_DP0_ACTIVE) + { + /* Walk all registered handlers for handlers that support this interrupt status */ + for (pfnHandler = g_pDP0IntHandlers; pfnHandler != ((dp_interrupt_t *)0); pfnHandler = pfnHandler->next) + pfnHandler->handler(); + + // What we need to do in ISR + printk("We are in DP0 ISR\n"); + } +} + +__attribute__((unused)) static void dp1ISR( + unsigned int status) +{ + dp_interrupt_t *pfnHandler; + + if (FIELD_VAL_GET(status, INT_STATUS, DP1) == INT_STATUS_DP1_ACTIVE) + { + /* Walk all registered handlers for handlers that support this interrupt status */ + for (pfnHandler = g_pDP1IntHandlers; pfnHandler != ((dp_interrupt_t *)0); pfnHandler = pfnHandler->next) + pfnHandler->handler(); + + // What we need to do in ISR + printk("We are in DP1 ISR\n"); + } +} + +void DP_Hpd_Interrupt_Enable(dp_index index, unsigned int enable) +{ + unsigned int DPBaseAddr, value; + + DPBaseAddr = DP_BASE + (DP_OFFSET * index); + + if (enable) + { + value = peekRegisterDWord(INT_MASK); + if (index == INDEX_DP0) + value = FIELD_SET(value, INT_MASK, DP0, ENABLE); + else + value = FIELD_SET(value, INT_MASK, DP1, ENABLE); + pokeRegisterDWord(INT_MASK, value); + + DP_HPD_Enable(index); + } + else + { + value = peekRegisterDWord(INT_MASK); + if (index == INDEX_DP0) + value = FIELD_SET(value, INT_MASK, DP0, DISABLE); + else + value = FIELD_SET(value, INT_MASK, DP1, DISABLE); + pokeRegisterDWord(INT_MASK, value); + + // hpd dectection + value = FIELD_SET(peekRegisterDWord(DPBaseAddr + DP_TOP84), DP_TOP84, ENABLE_HPD_PLUG_EVENT, FALSE); + value = FIELD_SET(value, DP_TOP84, ENABLE_HPD_UNPLUG_EVENT, FALSE); + pokeRegisterDWord(DPBaseAddr + DP_TOP84, value); // disable hpd event + + value = FIELD_SET(peekRegisterDWord(DPBaseAddr + DP_TOP8C), DP_TOP8C, HPD_PLUG, DISABLE); + value = FIELD_SET(value, DP_TOP8C, HPD_UNPLUG, DISABLE); + value = FIELD_SET(value, DP_TOP8C, HPD_IRQ, DISABLE); + pokeRegisterDWord(DPBaseAddr + DP_TOP8C, value); // disable hpd plug + } +} + +#if USE_I2C_ADAPTER +static void drm_dp_i2c_msg_set_request(struct drm_dp_aux_msg *msg, + const struct i2c_msg *i2c_msg) +{ + msg->request = (i2c_msg->flags & I2C_M_RD) ? + DP_AUX_I2C_READ : DP_AUX_I2C_WRITE; + if (!(i2c_msg->flags & I2C_M_STOP)) + msg->request |= DP_AUX_I2C_MOT; +} + +static int ddk770_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct smi_connector *connector = i2c_get_adapdata(adap); + struct drm_dp_aux_msg msg; + int i, j, index; + int ret = 0; + unsigned transfer_size; + u8 addr = msgs[0].addr; + + if (addr == DDC_CI_ADDR) + /* + * The internal I2C controller does not support the multi-byte + * read and write operations needed for DDC/CI. + * TOFIX: Blacklist the DDC/CI address until we filter out + * unsupported I2C operations. + */ + return -EOPNOTSUPP; + + + mutex_lock(&connector->i2c_lock); + memset(&msg, 0, sizeof(msg)); + + connector->i2c_is_segment = false; + connector->i2c_is_regaddr = false; + + /* reset */ + if (connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) { + index = 0; + } else if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) { + index = 1; + } else { + pr_err("Unknown connector type\n"); + ret = -EMEDIUMTYPE; + goto end; + } + + if (!DP_HPD_Detect(index)) { + ret = -ENODEV; + goto end; + } + + //DP_Aux_Transfer(index, DP_AUX_I2C_WRITE & ~DP_AUX_I2C_MOT, 0x50, 0x0,1); + for (i = 0; i < num; i++) { + if ((!(msgs[i].flags & I2C_M_RD)) && msgs[i].len == 1 && + msgs[i].buf[0] == 0x00) { + connector->i2c_is_segment = true; + } + + if ((msgs[i].flags & I2C_M_RD) && (msgs[i].len > 1) && + (connector->i2c_is_segment == true)) { + connector->i2c_is_regaddr = true; + } + + if (connector->i2c_is_regaddr == true) { + DP_Aux_Transfer(index, + DP_AUX_I2C_WRITE & ~DP_AUX_I2C_MOT, + 0x50, NULL, 0); + } + + msg.address = msgs[i].addr; + drm_dp_i2c_msg_set_request(&msg, &msgs[i]); + + msg.buffer = NULL; + msg.size = 0; + + transfer_size = 16; + for (j = 0; j < msgs[i].len; j += msg.size) { + + msg.buffer = msgs[i].buf + j; + if (msgs[i].len - j > transfer_size) { + msg.size = transfer_size; + } else { + msg.size = msgs[i].len - j; + } + + ret = DP_Aux_Transfer(index, msg.request, msg.address, + msg.buffer, msg.size); + /* + * Reset msg.request in case in case it got + * changed into a WRITE_STATUS_UPDATE. + */ + // drm_dp_i2c_msg_set_request(&msg, &msgs[i]); + + if (ret < 0) { + pr_err("[error] ddk770_hdmi_i2c_xfer ret:%d\n",ret); + goto end; + } + transfer_size = ret; + } + DP_Aux_Transfer(index, DP_AUX_I2C_WRITE & ~DP_AUX_I2C_MOT, 0x50, NULL,0); + } + + + ret = num; + mutex_unlock(&connector->i2c_lock); + return ret; + +end: + mutex_unlock(&connector->i2c_lock); + return ret; +} + +static u32 ddk770_dp_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm ddk770_dp_i2c_algo = { + .master_xfer = ddk770_dp_i2c_xfer, + .functionality = ddk770_dp_i2c_func +}; + +long ddk770_DP_AdaptHWI2CInit(struct smi_connector *connector) +{ + //TODO + int ret = 0; + + mutex_init(&connector->i2c_lock); + + connector->dp_adapter.owner = THIS_MODULE; + snprintf(connector->dp_adapter.name, I2C_NAME_SIZE, "SMI HW DP I2C Bus"); + connector->dp_adapter.dev.parent = connector->base.dev->dev; + i2c_set_adapdata(&connector->dp_adapter, connector); + connector->dp_adapter.algo = &ddk770_dp_i2c_algo; + ret = i2c_add_adapter(&connector->dp_adapter); + if (ret) { + pr_err("HW i2c add dp_adapter failed. %d\n", ret); + return -1; + } + + return ret; +} +#endif \ No newline at end of file diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_dp.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_dp.h new file mode 100644 index 000000000000..102dfea44c83 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_dp.h @@ -0,0 +1,432 @@ +#ifndef _DDK770_DP_H_ +#define _DDK770_DP_H_ + +#include "ddk770_mode.h" +#include "ddk770_display.h" +#include "../hw_com.h" +#include "../smi_drv.h" + +#define DP_SUCCESS 0L +#define DP_FAILURE 1L +#define DP_SCRAMBLE_ENABLE 1 +#define DP_SCRAMBLE_DISABLE 0 + +#define DP_IIC_NUMBER 0 +#define DP_IIC_BASE_ADDR 0x40800000 +#define DP_IIC_VFMCEXP_0_ADDR 0x64 +#define DP_IIC_VFMCEXP_1_ADDR 0x65 +#define DP_IIC_MUX_ADDR 0x70 +#define DP_IIC_TI_DP141_ADDR 0x5 +#define DP_IIC_IDT8N49_ADDR 0x7C +#define DP_IIC_LMK03318_ADDR 0x50 + +#define DP_EDID_BUF_LEN 128 /** Per Block size, */ + +#define DP_IDT_8T49N24X_FIN_MIN 8000 +#define DP_IDT_8T49N24X_FIN_MAX 875000000 + +#define DP_AUX_I2C_WRITE 0x0 +#define DP_AUX_I2C_READ 0x1 +#define DP_AUX_I2C_WRITE_STATUS_UPDATE 0x2 +#define DP_AUX_I2C_MOT 0x4 +#define DP_AUX_NATIVE_WRITE 0x8 +#define DP_AUX_NATIVE_READ 0x9 + +#define DP_AUX_NATIVE_REPLY_ACK 0x0 +#define DP_AUX_NATIVE_REPLY_NACK 0x1 + +#define DP_AUX_NATIVE_WAIT_REPLY 0x1 +#define DP_AUX_NATIVE_RECEIVED_REPLY 0x0 + +#define DP_OFFSET 0x8000 + +// FROM INNO SDK +/* DPCD */ +#define DP_DPCD_REV 0x000 + +#define DP_MAX_LINK_RATE 0x01 + +#define DP_MAX_LANE_COUNT 0x02 // 0x002 + +#define DP_MAX_DOWNSPREAD 0x03 + +#define DP_MAX_LANE_COUNT_MASK 0x1f +#define DP_TPS3_SUPPORTED (1 << 6) /* 1.2 */ +#define DP_ENHANCED_FRAME_CAP (1 << 7) + +#define DP_TRAINING_AUX_RD_INTERVAL 0x00e /* XXX 1.2? */ +#define DP_TRAINING_AUX_RD_MASK 0x7F /* DP 1.3 */ +#define DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT (1 << 7) /* DP 1.3 */ + +#define DP_SET_POWER 0x600 +#define DP_SET_POWER_D0 0x1 +#define DP_SET_POWER_D3 0x2 +#define DP_SET_POWER_MASK 0x3 + +#define DP_AUX_MAX_PAYLOAD_BYTES 16 + +#define DP_AUX_REPLY_ACK (0x0) +#define DP_AUX_REPLY_NACK (0x1) +#define DP_AUX_REPLY_DEFER (0x2) +#define DP_AUX_I2C_REPLY_NAKE (0x4) +#define DP_AUX_I2C_REPLY_DEFER (0x8) + +#define DP_LINK_STATUS_SIZE 6 + +// FROM INNO SDK +/* hpd */ +#define DP_LINK_SERVICE_IRQ_VECTOR_ESI0 0x2005 +#define DP_HPD_IRQ (0x1) +#define DP_HPD_IN (0x2) +#define DP_HPD_OUT (0x4) + + +// DP_PHY100 +/* link configuration */ +#define DP_LINK_BW_SET 0x100 +#define DP_LINK_BW_1_62 (0x06) +#define DP_LINK_BW_2_7 (0x0a) +#define DP_LINK_BW_5_4 (0x14) +#define DP_LINK_BW_8_1 (0x1e) + +#define DP_LANE_COUNT_SET 0x101 +#define DP_TRAINING_PATTERN_SET 0x102 +#define DP_TRAINING_PATTERN_DISABLE 0 +#define DP_TRAINING_PATTERN_1 1 +#define DP_TRAINING_PATTERN_2 2 +#define DP_TRAINING_PATTERN_2_CDS 3 /* 2.0 E11 */ +#define DP_TRAINING_PATTERN_3 3 /* 1.2 */ +#define DP_TRAINING_PATTERN_4 7 /* 1.4 */ +#define DP_TRAINING_PATTERN_MASK 0x3 +#define DP_TRAINING_PATTERN_MASK_1_4 0xf + +/* DPCD 1.1 only. For DPCD >= 1.2 see per-lane DP_LINK_QUAL_LANEn_SET */ +#define DP_LINK_QUAL_PATTERN_11_DISABLE (0 << 2) +#define DP_LINK_QUAL_PATTERN_11_D10_2 (1 << 2) +#define DP_LINK_QUAL_PATTERN_11_ERROR_RATE (2 << 2) +#define DP_LINK_QUAL_PATTERN_11_PRBS7 (3 << 2) +#define DP_LINK_QUAL_PATTERN_11_MASK (3 << 2) + +#define DP_RECOVERED_CLOCK_OUT_EN (1 << 4) +#define DP_LINK_SCRAMBLING_DISABLE (1 << 5) + +#define DP_SYMBOL_ERROR_COUNT_BOTH (0 << 6) +#define DP_SYMBOL_ERROR_COUNT_DISPARITY (1 << 6) +#define DP_SYMBOL_ERROR_COUNT_SYMBOL (2 << 6) +#define DP_SYMBOL_ERROR_COUNT_MASK (3 << 6) + + +#define DP_TRAINING_LANE0_SET 0x103 +#define DP_TRAINING_LANE1_SET 0x104 +#define DP_TRAINING_LANE2_SET 0x105 +#define DP_TRAINING_LANE3_SET 0x106 + +#define DP_TRAIN_VOLTAGE_SWING_MASK 0x3 +#define DP_TRAIN_VOLTAGE_SWING_SHIFT 0 +#define DP_TRAIN_MAX_SWING_REACHED (1 << 2) +#define DP_TRAIN_VOLTAGE_SWING_LEVEL_0 (0 << 0) +#define DP_TRAIN_VOLTAGE_SWING_LEVEL_1 (1 << 0) +#define DP_TRAIN_VOLTAGE_SWING_LEVEL_2 (2 << 0) +#define DP_TRAIN_VOLTAGE_SWING_LEVEL_3 (3 << 0) + +#define DP_TRAIN_PRE_EMPHASIS_MASK (3 << 3) +#define DP_TRAIN_PRE_EMPH_LEVEL_0 (0 << 3) +#define DP_TRAIN_PRE_EMPH_LEVEL_1 (1 << 3) +#define DP_TRAIN_PRE_EMPH_LEVEL_2 (2 << 3) +#define DP_TRAIN_PRE_EMPH_LEVEL_3 (3 << 3) + +#define DP_DOWNSPREAD_CTRL 0x107 +#define DP_SPREAD_AMP_0_5 (1 << 4) +#define DP_FIXED_VTOTAL_AS_SDP_EN_IN_PR_ACTIVE (1 << 6) +#define DP_MSA_TIMING_PAR_IGNORE_EN (1 << 7) /* eDP */ + +#define DP_MAIN_LINK_CHANNEL_CODING_SET 0x108 +#define DP_SET_ANSI_8B10B (1 << 0) +#define DP_SET_ANSI_128B132B (1 << 1) + +#define DP_I2C_SPEED_CONTROL_STATUS 0x109 /* DPI */ +/* bitmask as for DP_I2C_SPEED_CAP */ + +#define DP_EDP_CONFIGURATION_SET 0x10a /* XXX 1.2? */ +#define DP_ALTERNATE_SCRAMBLER_RESET_ENABLE (1 << 0) +#define DP_FRAMING_CHANGE_ENABLE (1 << 1) +#define DP_PANEL_SELF_TEST_ENABLE (1 << 7) + +#define DP_LINK_QUAL_LANE0_SET 0x10b /* DPCD >= 1.2 */ +#define DP_LINK_QUAL_LANE1_SET 0x10c +#define DP_LINK_QUAL_LANE2_SET 0x10d +#define DP_LINK_QUAL_LANE3_SET 0x10e +#define DP_LINK_QUAL_PATTERN_DISABLE 0 +#define DP_LINK_QUAL_PATTERN_D10_2 1 +#define DP_LINK_QUAL_PATTERN_ERROR_RATE 2 +#define DP_LINK_QUAL_PATTERN_PRBS7 3 +#define DP_LINK_QUAL_PATTERN_80BIT_CUSTOM 4 +#define DP_LINK_QUAL_PATTERN_HBR2_EYE 5 +#define DP_LINK_QUAL_PATTERN_MASK 7 + +#define DP_TRAINING_LANE0_1_SET2 0x10f +#define DP_TRAINING_LANE2_3_SET2 0x110 +#define DP_LANE02_POST_CURSOR2_SET_MASK (3 << 0) +#define DP_LANE02_MAX_POST_CURSOR2_REACHED (1 << 2) +#define DP_LANE13_POST_CURSOR2_SET_MASK (3 << 4) +#define DP_LANE13_MAX_POST_CURSOR2_REACHED (1 << 6) + +#define DP_MSTM_CTRL 0x111 /* 1.2 */ +#define DP_MST_EN (1 << 0) +#define DP_UP_REQ_EN (1 << 1) +#define DP_UPSTREAM_IS_SRC (1 << 2) + +#define DP_AUDIO_DELAY0 0x112 /* 1.2 */ +#define DP_AUDIO_DELAY1 0x113 +#define DP_AUDIO_DELAY2 0x114 + +#define DP_TRAIN_PRE_EMPHASIS_SHIFT 3 +#define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED (1 << 5) + +#define DP_TRAINING_LANE0_1_SET2 0x10f +#define DP_TRAINING_LANE2_3_SET2 0x110 +#define DP_LANE02_POST_CURSOR2_SET_MASK (3 << 0) +#define DP_LANE02_MAX_POST_CURSOR2_REACHED (1 << 2) +#define DP_LANE13_POST_CURSOR2_SET_MASK (3 << 4) +#define DP_LANE13_MAX_POST_CURSOR2_REACHED (1 << 6) + +#define DP_LINK_RATE_SET 0x115 /* eDP 1.4 */ +#define DP_LINK_RATE_SET_SHIFT 0 +#define DP_LINK_RATE_SET_MASK (7 << 0) + +#define DP_SINK_COUNT 0x200 +#define DP_DEVICE_SERVICE_IRQ_VECTOR 0x201 +#define DP_REMOTE_CONTROL_COMMAND_PENDING (1 << 0) +#define DP_AUTOMATED_TEST_REQUEST (1 << 1) +#define DP_CP_IRQ (1 << 2) +#define DP_MCCS_IRQ (1 << 3) +#define DP_DOWN_REP_MSG_RDY (1 << 4) /* 1.2 MST */ +#define DP_UP_REQ_MSG_RDY (1 << 5) /* 1.2 MST */ +#define DP_SINK_SPECIFIC_IRQ (1 << 6) + + +#define DP_LANE0_1_STATUS 0x202 +#define DP_LANE2_3_STATUS 0x203 +#define DP_LANE_CR_DONE (1 << 0) +#define DP_LANE_CHANNEL_EQ_DONE (1 << 1) +#define DP_LANE_SYMBOL_LOCKED (1 << 2) + +#define DP_CHANNEL_EQ_BITS (DP_LANE_CR_DONE | \ + DP_LANE_CHANNEL_EQ_DONE | \ + DP_LANE_SYMBOL_LOCKED) + +#define DP_LANE_ALIGN_STATUS_UPDATED 0x204 +#define DP_INTERLANE_ALIGN_DONE (1 << 0) +#define DP_128B132B_DPRX_EQ_INTERLANE_ALIGN_DONE (1 << 2) /* 2.0 E11 */ +#define DP_128B132B_DPRX_CDS_INTERLANE_ALIGN_DONE (1 << 3) /* 2.0 E11 */ +#define DP_128B132B_LT_FAILED (1 << 4) /* 2.0 E11 */ +#define DP_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6) +#define DP_LINK_STATUS_UPDATED (1 << 7) + +#define DP_AUX_I2C_WRITE 0x0 +#define DP_AUX_I2C_READ 0x1 +#define DP_AUX_I2C_WRITE_STATUS_UPDATE 0x2 +#define DP_AUX_I2C_MOT 0x4 +#define DP_AUX_NATIVE_WRITE 0x8 +#define DP_AUX_NATIVE_READ 0x9 + +#define DP_SUPPORTED_LINK_RATES 0x010 /* eDP 1.4 */ +#define DP_MAX_SUPPORTED_RATES 8 /* 16-bit little-endian */ + +#define DP_SET_POWER 0x600 +#define DP_SET_POWER_D0 0x1 +#define DP_SET_POWER_D3 0x2 +#define DP_SET_POWER_MASK 0x3 + +#define DP_EDP_DPCD_REV 0x700 /* eDP 1.2 */ +#define DP_EDP_11 0x00 +#define DP_EDP_12 0x01 +#define DP_EDP_13 0x02 +#define DP_EDP_14 0x03 + +#define DP_REV_10 0x10 +#define DP_REV_11 0x11 +#define DP_REV_12 0x12 +#define DP_REV_13 0x13 +#define DP_REV_14 0x14 + +#define DP_ADJUST_REQUEST_LANE0_1 0x206 +#define DP_ADJUST_REQUEST_LANE2_3 0x207 +#define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK 0x03 +#define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0 +#define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK 0x0c +#define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT 2 +#define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK 0x30 +#define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4 +#define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK 0xc0 +#define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6 + + +#define DP_PAYLOAD_TABLE_UPDATE_STATUS 0x2c0 /* 1.2 MST */ +#define DP_PAYLOAD_TABLE_UPDATED (1 << 0) +#define DP_PAYLOAD_ACT_HANDLED (1 << 1) + +#define DP_VC_PAYLOAD_ID_SLOT_1 0x2c1 /* 1.2 MST */ +/* up to ID_SLOT_63 at 0x2ff */ + +#define DP_RECEIVER_CAP_SIZE (0xf + 1) // 16 + +#define DP_AUX_MAX_PAYLOAD_BYTES 16 + +#define DP_AUX_DEFAULT_BRIGHTNESS (512/2) +#define DP_BRIGHTNESS_NITS_LSB 0x354 +#define DP_BRIGHTNESS_MODE_PWM (1) +#define DP_BRIGHTNESS_MODE_VESA (2) +#define DP_BRIGHTNESS_MODE_HDR (3) + +#define DP_HPD_IRQ (0x1) +#define DP_HPD_IN (0x2) +#define DP_HPD_OUT (0x4) + +#define DP_RX_CAP_CHANGED (1 << 0) /* 1.2 */ +#define DP_LINK_STATUS_CHANGED (1 << 1) +#define DP_STREAM_STATUS_CHANGED (1 << 2) +#define DP_HDMI_LINK_STATUS_CHANGED (1 << 3) +#define DP_CONNECTED_OFF_ENTRY_REQUESTED (1 << 4) + +#define DP_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \ + .name = nm, .status = 0, .type = (t), .clock = (c), \ + .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ + .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \ + .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \ + .vscan = (vs), .flags = (f), \ + .base.type = DRM_MODE_OBJECT_MODE + +struct dp_compliance_data { + unsigned long edid; + unsigned char video_pattern; + unsigned short hdisplay, vdisplay; + unsigned char bpc; + unsigned char phy_pattern; +}; + +struct dp_compliance { + unsigned long test_type; + struct dp_compliance_data test_data; + bool test_active; + unsigned char test_link_rate; + unsigned char test_lane_count; +}; + + +#define DP_ADJUST_REQUEST_POST_CURSOR2 0x20c +#define DP_ADJUST_POST_CURSOR2_LANE0_MASK 0x03 +#define DP_ADJUST_POST_CURSOR2_LANE0_SHIFT 0 +#define DP_ADJUST_POST_CURSOR2_LANE1_MASK 0x0c +#define DP_ADJUST_POST_CURSOR2_LANE1_SHIFT 2 +#define DP_ADJUST_POST_CURSOR2_LANE2_MASK 0x30 +#define DP_ADJUST_POST_CURSOR2_LANE2_SHIFT 4 +#define DP_ADJUST_POST_CURSOR2_LANE3_MASK 0xc0 +#define DP_ADJUST_POST_CURSOR2_LANE3_SHIFT 6 + +typedef enum { + BASE_DP0 = 0x190000, + BASE_DP1 = 0x198000, + BASE_DP_PHY = 0x198000 +} dp_base_addr; + + +#define pll_prediv (0) +#define pll_fbdiv (1) +#define pll_postdiv (2) +#define pll_clkdiv_16m (3) + + +struct aux_cfg { + unsigned int aux_cmd; + unsigned int dpcd_addr; + unsigned int *wr_buff; + unsigned int *rd_buff; + unsigned int length; + unsigned int rd_print; + unsigned int read; +}; + +typedef struct { + unsigned char dpcd_rev; + unsigned char lane_rate; + unsigned char lane_count; + unsigned char enhance_mode; + unsigned char phy_rate; + unsigned char phy_lanes; + unsigned char max_downspread; + unsigned char swing[4]; + unsigned char preem[4]; + unsigned char pcursor[4]; + + /* Displayport compliance testing */ + struct dp_compliance compliance; + /* sink rates as reported by DP_MAX_LINK_RATE/DP_SUPPORTED_LINK_RATES */ + int max_sink_rates; + int num_sink_rates; + int sink_rates[DP_MAX_SUPPORTED_RATES]; + unsigned char cdr_delay; + unsigned char eq_delay; + + unsigned char dpcd[DP_RECEIVER_CAP_SIZE]; + unsigned char sink_power_status; + cea_parameter_t* cea_mode; +} dp_info; + +struct drm_dp_aux_msg { + unsigned int address; + u8 request; + u8 reply; + void *buffer; + size_t size; +}; + +void dpHandler(void); + +/* + * This is the main interrupt hook for HDMI engine. + */ +long hookDPInterrupt( + dp_index index, + void (*handler)(void) +); + +/* + * This function un-register HDMI Interrupt handler. + */ +long unhookDPInterrupt( + dp_index index, + void (*handler)(void) +); + +void DP_Hpd_Interrupt_Enable(dp_index index, unsigned int enable); + +int DP_Read_EDID(dp_index index, unsigned char *pEDIDBuffer, unsigned short *pBufferSize); +int DP_HPD_Detect(dp_index index); + + +int DP_Setmode(dp_index index, logicalMode_t *pLogicalMode , mode_parameter_t *pModeParam); + + +int DP_Init(dp_index index); +int DP_Enable(dp_index index); +int DP_Disable(dp_index index); +void DP_Set_Channel(dp_index index, disp_control_t dc); +void DP_Clear_Channel(dp_index index); +unsigned char DP_Get_Channel(dp_index index); + +void DP_SSC_Enable(dp_index index, unsigned int downspread, unsigned int freq, unsigned int amp); +void DP_SSC_Disable(dp_index index); + +void DP_Audio_CheckOverrun(dp_index index); + +void DP_Audio_Mute(dp_index index); +void DP_Audio_UnMute(dp_index index); +void DP_Enable_Output(dp_index index); +void DP_Disable_Output(dp_index index); +void DP_Audio_Reset(dp_index index); + +int Dp_HDP_Irq_Handle(dp_index index); +int DP_Check_Sink_Status(dp_index index); +long ddk770_DP_AdaptHWI2CInit(struct smi_connector *connector); +#endif /* _DP_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_edid.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_edid.c new file mode 100644 index 000000000000..443c90a97218 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_edid.c @@ -0,0 +1,1959 @@ +/******************************************************************* +* +* Copyright (c) 2009 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* edid.c --- SM750/SM718 DDK +* This file contains functions to interpret the EDID structure. +* +*******************************************************************/ +#include "ddk770_reg.h" +#include "ddk770_hardware.h" +#include "ddk770_helper.h" +#include "ddk770_hwi2c.h" +#include "ddk770_swi2c.h" +#include "ddk770_edid.h" + +#include "ddk770_ddkdebug.h" + +/* Enable this one to print the VDIF timing when debug is enabled. */ +//#define ENABLE_DEBUG_PRINT_VDIF + +typedef struct _est_timing_mode_t +{ + unsigned long x; /* Mode Width */ + unsigned long y; /* Mode Height */ + unsigned long hz; /* Refresh Rate */ + unsigned char source; /* Source: 0 - VESA + 1 - IBM + 2 - Apple + */ +} +est_timing_mode_t; + +/* These values only applies to EDID Version 1 */ +static est_timing_mode_t establishTiming[3][8] = +{ + /* Established Timing 1 */ + { + { 800, 600, 60, 0}, + { 800, 600, 56, 0}, + { 640, 480, 75, 0}, + { 640, 480, 72, 0}, + { 640, 480, 67, 2}, + { 640, 480, 60, 1}, + { 720, 400, 88, 1}, + { 720, 400, 70, 1}, + }, + { + {1280, 1024, 75, 0}, + {1024, 768, 75, 0}, + {1024, 768, 70, 0}, + {1024, 768, 60, 0}, + {1024, 768, 87, 1}, + { 832, 624, 75, 0}, + { 800, 600, 75, 0}, + { 800, 600, 72, 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}, + {1152, 870, 75, 2}, + } +}; + +static void printVdif( + vdif_t *pVDIF +) +{ +#ifdef DDKDEBUG + +#ifndef ENABLE_DEBUG_PRINT_VDIF + DDKDEBUGENABLE(0); +#endif + + DDKDEBUGPRINT((DISPLAY_LEVEL, "pixelClock = %d\n", pVDIF->pixelClock)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "characterWidth = %d\n", pVDIF->characterWidth)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "scanType = %s\n", (pVDIF->scanType == VDIF_INTERLACED) ? "Interlaced" : "Progressive")); + + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalFrequency = %d\n", pVDIF->horizontalFrequency)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalTotal = %d\n", pVDIF->horizontalTotal)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalActive = %d\n", pVDIF->horizontalActive)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalBlankStart = %d\n", pVDIF->horizontalBlankStart)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalBlankTime = %d\n", pVDIF->horizontalBlankTime)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalSyncStart = %d\n", pVDIF->horizontalSyncStart)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalRightBorder = %d\n", pVDIF->horizontalRightBorder)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalFrontPorch = %d\n", pVDIF->horizontalFrontPorch)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalSyncWidth = %d\n", pVDIF->horizontalSyncWidth)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalBackPorch = %d\n", pVDIF->horizontalBackPorch)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalLeftBorder = %d\n", pVDIF->horizontalLeftBorder)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "horizontalSyncPolarity = %s\n", + (pVDIF->horizontalSyncPolarity == VDIF_SYNC_NEGATIVE) ? "Negative" : "Positive")); + + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalFrequency = %d\n", pVDIF->verticalFrequency)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalTotal = %d\n", pVDIF->verticalTotal)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalActive = %d\n", pVDIF->verticalActive)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBlankStart = %d\n", pVDIF->verticalBlankStart)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBlankTime = %d\n", pVDIF->verticalBlankTime)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalSyncStart = %d\n", pVDIF->verticalSyncStart)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBottomBorder = %d\n", pVDIF->verticalBottomBorder)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalFrontPorch = %d\n", pVDIF->verticalFrontPorch)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalSyncHeight = %d\n", pVDIF->verticalSyncHeight)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalBackPorch = %d\n", pVDIF->verticalBackPorch)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalTopBorder = %d\n", pVDIF->verticalTopBorder)); + DDKDEBUGPRINT((DISPLAY_LEVEL, "verticalSyncPolarity = %s\n", + (pVDIF->verticalSyncPolarity == VDIF_SYNC_NEGATIVE) ? "Negative" : "Positive")); + +#ifndef ENABLE_DEBUG_PRINT_VDIF + DDKDEBUGENABLE(1); +#endif +#endif +} + +/* + * edidGetHeader + * This function gets the EDID Header + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 get header success; -1 fail. + */ +__attribute__((unused)) static unsigned char ddk770_edidGetHeader( + unsigned char *pEDIDBuffer +) +{ + if (pEDIDBuffer != (unsigned char *)0) + { + /* Check the header */ + if ((pEDIDBuffer[0] == 0x00) && (pEDIDBuffer[1] == 0xFF) && (pEDIDBuffer[2] == 0xFF) && + (pEDIDBuffer[3] == 0xFF) && (pEDIDBuffer[4] == 0xFF) && (pEDIDBuffer[5] == 0xFF) && + (pEDIDBuffer[6] == 0xFF) && (pEDIDBuffer[7] == 0x00)) + { + return 0; + } + else + return -1; + } + + // DDKDEBUGPRINT((DISPLAY_LEVEL, "Invalid EDID bufffer\n")); + return -1; +} + +/* + * edidGetVersion + * This function gets the EDID version + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRevision - Revision of the EDIE (if exist) + * + * Output: + * Revision number of the given EDID buffer. + */ +unsigned char ddk770_edidGetVersion( + unsigned char *pEDIDBuffer, + unsigned char *pRevision +) +{ + unsigned char version; + + if (pEDIDBuffer != (unsigned char *)0) + { + /* Check the header */ + if ((pEDIDBuffer[0] == 0x00) && (pEDIDBuffer[1] == 0xFF) && (pEDIDBuffer[2] == 0xFF) && + (pEDIDBuffer[3] == 0xFF) && (pEDIDBuffer[4] == 0xFF) && (pEDIDBuffer[5] == 0xFF) && + (pEDIDBuffer[6] == 0xFF) && (pEDIDBuffer[7] == 0x00)) + { + /* + * EDID Structure Version 1. + */ + + /* Read the version field from the buffer. It should be 1 */ + version = pEDIDBuffer[18]; + + if (version == 1) + { + /* Copy the revision first */ + if (pRevision != (unsigned char *)0) + *pRevision = pEDIDBuffer[19]; + + return version; + } + } + else + { + /* + * EDID Structure Version 2 + */ + + /* Read the version and revision field from the buffer. */ + version = pEDIDBuffer[0]; + + if ((version >> 4) == 2) + { + /* Copy the revision */ + if (pRevision != (unsigned char *)0) + *pRevision = version & 0x0F; + + return (version >> 4); + } + } + } + + DDKDEBUGPRINT((DISPLAY_LEVEL, "Invalid EDID Structure\n")); + return 0; +} + +/* + * ddk770_edidGetProductInfo + * This function gets the vendor and product information. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor [in] + * pManufacturerName - Pointer to a 3 byte length variable to store the manufacturer name [out] + * pProductCode - Pointer to a variable to store the product code [out] + * pSerialNumber - Pointer to a variable to store the serial number [out] + * pWeekOfManufacture - Pointer to a variable to store the week of manufacture [out] + * pYearOfManufacture - Pointer to a variable to store the year of manufacture + * or model year (if WeekOfManufacture is 0xff) [out] + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetProductInfo( + unsigned char *pEDIDBuffer, + char *pManufacturerName, + unsigned short *pProductCode, + unsigned long *pSerialNumber, + unsigned char *pWeekOfManufacture, + unsigned short *pYearOfManufacture +) +{ + unsigned char version, revision; + unsigned short manufactureID; + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + if (pManufacturerName != (char *)0) + { + /* Swap the byte */ + manufactureID = (pEDIDStructure->manufacturerID >> 8) + (pEDIDStructure->manufacturerID << 8); + pManufacturerName[0] = ((manufactureID >> 10) & 0x001F) + 'A' - 1; + pManufacturerName[1] = ((manufactureID >> 5) & 0x001F) + 'A' - 1; + pManufacturerName[2] = (manufactureID & 0x001F) + 'A' - 1; + pManufacturerName[3] = '\0'; + } + + if (pProductCode != (unsigned short *)0) + *pProductCode = pEDIDStructure->productCode; + + /* Only EDID structure version 1.1 and 1.2 supports this. EDID 1.3 uses + detail timing descriptor to store the serial number in ASCII. */ + if (pSerialNumber != (unsigned long *)0) + *pSerialNumber = pEDIDStructure->serialNumber; + + /* + * Rev 1.3: - A value of 0 means that week of manufacture is not specified + * - A value in the range of 1 to 54 (0x01 - 0x36) means the week of manufacture + * - Any values greater than 54 is invalid. + * + * Rev 1.4: - A value of 0 means that week of manufacture is not specified + * - A value in the range of 1 to 54 (0x01 - 0x36) means the week of manufacture + * - A value of 0xFF means that Year of Manufacture contains the model year + * instead of year of Manufacture. + * - Other values means invalid + */ + if (pWeekOfManufacture != (unsigned char *)0) + *pWeekOfManufacture = pEDIDStructure->weekOfManufacture; + + /* The value must be greater than 3 and less than or equal to the current + year minus 1990. + A value of 3 or less would indicated that the display was manufactured + before the EDID standard was defined. + A value greater than (current year - 1990) would indicate that the display + has not yet been manufactured. + */ + if (pYearOfManufacture != (unsigned short *)0) + *pYearOfManufacture = (unsigned short) pEDIDStructure->yearOfManufacture + 1990; + + return 0; + } + + return (-1); +} + +/* + * ddk770_edidCheckMonitorInputSignal + * This function checks whether the monitor is expected analog/digital + * input signal. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Analog + * 1 - Digital + */ +unsigned char ddk770_edidCheckMonitorInputSignal( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + //unsigned short index; + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->videoInputDefinition.analogSignal.inputSignal; + + return 0; +} + +/* + * ddk770_edidGetAnalogSignalInfo + * This function gets the analog video input signal information + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRefWhiteAboveBlank - Pointer to a variable to store the reference white above blank + * value. The value is in milliVolt. + * pSyncLevelBelowBlank - Pointer to a variable to store the Sync tip level below blank + * The value is also in milliVolt + * pBlank2BlackSetup - Pointer to a variable to store the Blank to black setup or + * pedestal per appropriate Signal Level Standard flag. + * 1 means that the display expect the setup. + * pSeparateSyncSupport - Pointer to a variable to store the flag to indicate that the + * monitor supports separate sync. + * pCompositeSyncSupport - Pointer to a variable to store a flag to indicate that the + * monitor supports composite sync. + * pSyncOnGreenSupport - Pointer to a variable to store a flag to indicate that + * the monitor supports sync on green video. + * pVSyncSerrationRequired - Pointer to a variable to store a flag to indicate that serration + * of the VSync pulse is required when composite sync or + * sync-on-green video is used. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetAnalogSignalInfo( + unsigned char *pEDIDBuffer, + unsigned short *pRefWhiteAboveBlank, + unsigned short *pSyncLevelBelowBlank, + unsigned char *pBlank2BlackSetup, + unsigned char *pSeparateSyncSupport, + unsigned char *pCompositeSyncSupport, + unsigned char *pSyncOnGreenSupport, + unsigned char *pVSyncSerrationRequired +) +{ + unsigned char version, revision; + unsigned short whiteReference, syncLevel; + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + /* Check if the input signal is analog */ + if (pEDIDStructure->videoInputDefinition.analogSignal.inputSignal != 0) + return (-1); + + switch (pEDIDStructure->videoInputDefinition.analogSignal.signalLevelStd) + { + case 0: + whiteReference = 700; + syncLevel = 300; + break; + case 1: + whiteReference = 714; + syncLevel = 286; + break; + case 2: + whiteReference = 1000; + syncLevel = 400; + break; + case 3: + whiteReference = 700; + syncLevel = 0; + break; + } + + if (pRefWhiteAboveBlank != (unsigned short *)0) + *pRefWhiteAboveBlank = whiteReference; + + if (pSyncLevelBelowBlank != (unsigned short *)0) + *pSyncLevelBelowBlank = syncLevel; + + if (pBlank2BlackSetup != (unsigned char *)0) + *pBlank2BlackSetup = (unsigned char) + pEDIDStructure->videoInputDefinition.analogSignal.blank2Black; + + if (pSeparateSyncSupport != (unsigned char *)0) + *pSeparateSyncSupport = (unsigned char) + pEDIDStructure->videoInputDefinition.analogSignal.separateSyncSupport; + + if (pCompositeSyncSupport != (unsigned char *)0) + *pCompositeSyncSupport = (unsigned char) + pEDIDStructure->videoInputDefinition.analogSignal.compositeSyncSupport; + + if (pSyncOnGreenSupport != (unsigned char *)0) + *pSyncOnGreenSupport = (unsigned char) + pEDIDStructure->videoInputDefinition.analogSignal.syncOnGreenSupport; + + if (pVSyncSerrationRequired != (unsigned char *)0) + *pVSyncSerrationRequired = (unsigned char) + pEDIDStructure->videoInputDefinition.analogSignal.vsyncSerration; + + return 0; + } + else + { + /* EDID Structure 2 */ + } + + return (-1); +} + +/* + * ddk770_edidGetDigitalSignalInfo + * This function gets the digital video input signal information. + * Only applies to EDID 1.3 and above. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pDFP1xSupport - Pointer to a variable to store the flag to indicate that + * the mointor interface is signal compatible with VESA + * DFP 1.x TMDS CRGB, 1 pixel/clock, up to 8 bits / color + * MSB aligned, DE active high + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetDigitalSignalInfo( + unsigned char *pEDIDBuffer, + unsigned char *pDFP1xSupport +) +{ + unsigned char version, revision; + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, &revision); + + if ((version == 1) && (revision == 3)) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + /* Check if the input signal is digital */ + if (pEDIDStructure->videoInputDefinition.digitalSignal.inputSignal != 1) + return (-1); + + if (pDFP1xSupport != (unsigned char *)0) + *pDFP1xSupport = pEDIDStructure->videoInputDefinition.digitalSignal.dfp1Support; + + return 0; + } + + return (-1); +} + +/* + * ddk770_edidGetDisplaySize + * This function gets the display sizes in cm. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMaxHorzImageSize - Pointer to a variable to store the maximum horizontal + * image size to the nearest centimeter. A value of 0 + * indicates that the size is indeterminate size. + * pMaxVertImageSize - Pointer to a variable to store the maximum vertical + * image size to the nearest centimeter. A value of 0 + * indicates that the size is indeterminate size. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetDisplaySize( + unsigned char *pEDIDBuffer, + unsigned char *pMaxHorzImageSize, + unsigned char *pMaxVertImageSize +) +{ + unsigned char version, revision; + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + if (pMaxHorzImageSize != (unsigned char *)0) + *pMaxHorzImageSize = pEDIDStructure->maxHorzImageSize; + + if (pMaxVertImageSize != (unsigned char *)0) + *pMaxVertImageSize = pEDIDStructure->maxVertImageSize; + + return 0; + } + + return (-1); +} + +/* You can also use ddk770_edidGetWhitePoint to get the Gamma */ +/* + * edidGetGamma + * This function gets the Display Transfer Characteristic (Gamma). + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * Gamma value multiplied by 100. A value of 0xFFFF (-1) indicates that + * the gamma value is not defined. + */ +__attribute__((unused)) static unsigned short edidGetGamma( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned short)(((edid_version_1_t *)pEDIDBuffer)->displayTransferChar + 100); + + return (-1); +} + +/* + * ddk770_edidGetPowerManagementSupport + * This function gets the monitor's power management support. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStandBy - Pointer to a variable to store the flag to indicate that + * standby power mode is supported. + * pSuspend - Pointer to a variable to store the flag to indicate that + * suspend power mode is supported. + * pLowPower - Pointer to a variable to store the flag to indicate that + * the display consumes low power when it receives a timing + * signal that is outside its declared active operating range. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetPowerManagementSupport( + unsigned char *pEDIDBuffer, + unsigned char *pStandBy, + unsigned char *pSuspend, + unsigned char *pLowPower +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + if (pStandBy != (unsigned char *)0) + *pStandBy = (unsigned char) pEDIDStructure->featureSupport.standbySupport; + + if (pSuspend != (unsigned char *)0) + *pSuspend = (unsigned char) pEDIDStructure->featureSupport.suspendSupport; + + if (pLowPower != (unsigned char *)0) + *pLowPower = (unsigned char) pEDIDStructure->featureSupport.lowPowerSupport; + + return 0; + } + + return (-1); +} + +/* + * ddk770_edidGetDisplayType + * This function gets the display type. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Monochrome / grayscale display + * 1 - RGB Color Display + * 2 - Non-RGB multicolor display, e.g. R/G/Y + * 3 - Undefined + */ +unsigned char ddk770_edidGetDisplayType( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.displayType; + + return (3); +} + +/* + * ddk770_edidChecksRGBUsage + * This function checks if the display is using the sRGB standard default + * color space as its primary color space. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Does not use sRGB as its primary color space + * 1 - Use sRGB as its primary color space + */ +unsigned char ddk770_edidChecksRGBUsage( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.sRGBSupport; + + return (0); +} + +/* + * ddk770_edidIsPreferredTimingAvailable + * This function checks whether the preffered timing mode is available. + * Use of preferred timing mode is required by EDID structure version 1 + * Revision 3 and higher. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Preferred Timing is not available + * 1 - Preferred Timing is available + */ +unsigned char ddk770_edidIsPreferredTimingAvailable( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + + if (pEDIDBuffer != (unsigned char *)0) + { + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.preferredTiming; + } + + return (0); +} + +/* + * ddk770_edidIsDefaultGTFSupported + * This function checks whether the display supports timings based on the + * GTF standard using default GTF parameter values. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Default GTF is not supported + * 1 - Default GTF is supported + */ +unsigned char ddk770_edidIsDefaultGTFSupported( + unsigned char *pEDIDBuffer +) +{ + unsigned char version; + //unsigned char revision; + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + return (unsigned char)((edid_version_1_t *)pEDIDBuffer)->featureSupport.defaultGTFSupport; + + return (0); +} + +/* + * edidCalculateChromaticValue + * This function calculates the chromatic value. + * + * Input: + * colorBinaryValue - Color Characteristic Binary Representation Value + * to be computed + * + * Output: + * The chromatic value times a 1000. + */ +static unsigned short edidCalculateChromaticValue( + unsigned short colorBinaryValue +) +{ + unsigned long index; + unsigned long result; + + result = 0; + for (index = 10; index > 0; index--) + { + /* Times 1000000 to make it accurate to the micro value. */ + result += ddk770_roundedDiv((colorBinaryValue & 0x0001) * 1000000, ddk770_twoToPowerOfx(index)); + colorBinaryValue >>= 1; + } + + /* Make it accurate to 1000 place */ + return ((unsigned short)ddk770_roundedDiv(result, 1000)); +} + +/* + * ddk770_edidGetColorCharacteristic + * This function gets the chromaticity and white point values expressed as + * an integer value which represents the actual value times 1000. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRedX - Pointer to a variable to store the Red X values + * pRedY - Pointer to a variable to store the Red Y values + * pGreenX - Pointer to a variable to store the Green X values + * pGreenY - Pointer to a variable to store the Green Y values + * pBlueX - Pointer to a variable to store the Blue X values + * pBlueY - Pointer to a variable to store the Blue Y values + * + * Note: + * To get the White color characteristic, use the ddk770_edidGetWhitePoint + */ +void ddk770_edidGetColorCharacteristic( + unsigned char *pEDIDBuffer, + unsigned short *pRedX, + unsigned short *pRedY, + unsigned short *pGreenX, + unsigned short *pGreenY, + unsigned short *pBlueX, + unsigned short *pBlueY +) +{ + unsigned char version; + //unsigned char revision; + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + if (pRedX != (unsigned short *)0) + { + *pRedX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->redX << 2) + + (unsigned short)pEDIDStructure->redGreenLowBits.redXLowBits); + } + + if (pRedY != (unsigned short *)0) + { + *pRedY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->redY << 2) + + (unsigned short)pEDIDStructure->redGreenLowBits.redYLowBits); + } + + if (pGreenX != (unsigned short *)0) + { + *pGreenX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->greenX << 2) + + (unsigned short)pEDIDStructure->redGreenLowBits.greenXLowBits); + } + + if (pGreenY != (unsigned short *)0) + { + *pGreenY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->greenY << 2) + + (unsigned short)pEDIDStructure->redGreenLowBits.greenYLowBits); + } + + if (pBlueX != (unsigned short *)0) + { + *pBlueX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->blueX << 2) + + (unsigned short)pEDIDStructure->blueWhiteLowBits.blueXLowBits); + } + + if (pBlueY != (unsigned short *)0) + { + *pBlueY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->blueY << 2) + + (unsigned short)pEDIDStructure->blueWhiteLowBits.blueYLowBits); + } + } +} + +/* + * ddk770_edidGetWhitePoint + * This function gets the white point. + * To get the default white point, set the index to 0. For multiple white point, + * call this function multiple times to check if more than 1 white point is supported. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pWhitePointIndex - Pointer to a variable that contains the white point index + * to be retrieved. + * pWhiteX - Pointer to a variable to store the White X value + * pWhiteY - Pointer to a variable to store the White Y value + * pWhiteGamma - Pointer to a variable to store the White Gamma value + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetWhitePoint( + unsigned char *pEDIDBuffer, + unsigned char *pWhitePointIndex, + unsigned short *pWhiteX, + unsigned short *pWhiteY, + unsigned short *pWhiteGamma +) +{ + unsigned char version, index, tableIndex; + //unsigned char revision; + + if (pWhitePointIndex == (unsigned char *)0) + return (-1); + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, (unsigned char *)0); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + /* Get the index to a temporary variable and increment the index for the + next loop. */ + index = *pWhitePointIndex; + (*pWhitePointIndex)++; + + if (index == 0) + { + if (pWhiteX != (unsigned short *)0) + { + *pWhiteX = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->whiteX << 2) + + (unsigned short)pEDIDStructure->blueWhiteLowBits.whiteXLowBits); + } + + if (pWhiteY != (unsigned short *)0) + { + *pWhiteY = edidCalculateChromaticValue(((unsigned short)pEDIDStructure->whiteY << 2) + + (unsigned short)pEDIDStructure->blueWhiteLowBits.whiteYLowBits); + } + + if (pWhiteGamma != (unsigned short *)0) + *pWhiteGamma = pEDIDStructure->displayTransferChar + 100; + + return 0; + } + else + { + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFB) && + (pMonitorDescriptor->descriptor.colorPoint.white[index-1].whitePointIndex != 0)) + { + if (pWhiteX != (unsigned short *)0) + { + *pWhiteX = edidCalculateChromaticValue(((unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteX << 2) + + (unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteLowBits.whiteXLowBits); + } + + if (pWhiteY != (unsigned short *)0) + { + *pWhiteY = edidCalculateChromaticValue(((unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteY << 2) + + (unsigned short)pMonitorDescriptor->descriptor.colorPoint.white[index-1].whiteLowBits.whiteYLowBits); + } + + if (pWhiteGamma != (unsigned short *)0) + *pWhiteGamma = pMonitorDescriptor->descriptor.colorPoint.white[index-1].gamma + 100; + + return 0; + } + } + } + } + + return (-1); +} + +/* + * edidCalculateChecksum + * This function adds all one-byte value of the EDID buffer. + * The total should be equal to 0x00 + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * Total of one-byte values. It should equal to 0x00. A value other than + * 0x00 indicates the EDID buffer is not valid. + */ +// static unsigned char edidCalculateChecksum( +// unsigned char *pEDIDBuffer +// ) +// { +// unsigned char version, revision, checksum; +// unsigned short index; + +// /* Get EDID Version and revision */ +// version = ddk770_edidGetVersion(pEDIDBuffer, &revision); + +// checksum = 0; +// if (version == 1) +// { +// for (index = 0; index < 128; index++) +// checksum += pEDIDBuffer[index]; +// } + +// return checksum; +// } + +/* + * ddk770_edidGetExtension + * This function gets the number of (optional) EDID extension blocks to follow + * the given EDID buffer. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * Total number of EDID Extension to follow the given EDID buffer. + */ +unsigned char ddk770_edidGetExtension( + unsigned char *pEDIDBuffer +) +{ + unsigned char version, revision; + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + return ((edid_version_1_t *)pEDIDBuffer)->extFlag; + + return 0; +} + +#define EDID_TOTAL_RETRY_COUNTER 4 +/* + * ddk770_edidReadMonitor + * This function reads the EDID structure from attached monitor with SW I2C + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * sclGpio - GPIO pin used as the I2C Clock (SCL) + * sdaGpio - GPIO pin used as the I2C Data (SDA) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidReadMonitorEx( + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char sclGpio, + unsigned char sdaGpio +) +{ + unsigned char retry, edidVersion, edidRevision; + unsigned char edidBuffer[256]; + unsigned long offset; + + /* Initialize the i2c bus */ + ddk770_swI2CInit(sclGpio, sdaGpio); + + for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++) + { + DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry)); + + /* Read the EDID from the monitor. */ + for (offset = 0; offset < TOTAL_EDID_REGISTERS; offset++) + edidBuffer[offset] = ddk770_swI2CReadReg(EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); + + /* Check if the EDID is valid. */ + edidVersion = ddk770_edidGetVersion((unsigned char *)&edidBuffer, (unsigned char *)&edidRevision); + DDKDEBUGPRINT((DISPLAY_LEVEL, "EDID Structure Version: %d.%d\n", edidVersion, edidRevision)); + if (edidVersion != 0) + break; + } + + /* + * The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol, + * which uses the Vertical Sync to clock in the EDID data. + * Currently this function return error. DDC1 protocol can be added later. + */ + if (retry == EDID_TOTAL_RETRY_COUNTER) + { + /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is + * only an acknowledge flag, which could be high or low. However, SCL line + * is not used. Instead the data is clock-in using vertical sync. + */ + return (-1); + } + + /* Copy the data to the given buffer */ + if (pEDIDBuffer != (unsigned char *)0) + { + for (offset = 0; offset < bufferSize; offset++) + pEDIDBuffer[offset] = edidBuffer[offset]; + } + + return 0; +} + +/* + * This function is same as editReadMonitorEx(), but using HW I2C. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * i2cNumber - 0 = I2C0 and 1 = I2C1 + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidReadMonitorExHwI2C( + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char i2cNumber +) +{ + unsigned char retry, edidVersion, edidRevision; + unsigned char edidBuffer[256]; + unsigned long offset; + + /* Initialize the i2c bus */ + ddk770_hwI2CInit(i2cNumber); + + for (retry = 0; retry < EDID_TOTAL_RETRY_COUNTER; retry++) + { + DDKDEBUGPRINT((DISPLAY_LEVEL, "retry: %d\n", retry)); + + /* Read the EDID from the monitor. */ + for (offset = 0; offset < TOTAL_EDID_REGISTERS; offset++) + edidBuffer[offset] = ddk770_hwI2CReadReg(i2cNumber, EDID_DEVICE_I2C_ADDRESS, (unsigned char)offset); + + /* Check if the EDID is valid. */ + edidVersion = ddk770_edidGetVersion((unsigned char *)&edidBuffer, (unsigned char *)&edidRevision); + DDKDEBUGPRINT((DISPLAY_LEVEL, "EDID Structure Version: %d.%d\n", edidVersion, edidRevision)); + if (edidVersion != 0) + break; + } + + /* Finish using HW I2C, we can close the device. */ + ddk770_hwI2CClose(i2cNumber); + + /* + * The monitor might not be DDC2B compliance. Therefore, need to use DDC1 protocol, + * which uses the Vertical Sync to clock in the EDID data. + * Currently this function return error. DDC1 protocol can be added later. + */ + if (retry == EDID_TOTAL_RETRY_COUNTER) + { + /* DDC1 uses the SDA line to transmit 9 bit data per byte. The last bit is + * only an acknowledge flag, which could be high or low. However, SCL line + * is not used. Instead the data is clock-in using vertical sync. + */ + return (-1); + } + + /* Copy the data to the given buffer */ + if (pEDIDBuffer != (unsigned char *)0) + { + for (offset = 0; offset < bufferSize; offset++) + pEDIDBuffer[offset] = edidBuffer[offset]; + } + + return 0; +} + +/* + * ddk770_edidReadMonitor + * This function reads the EDID structure from the attached monitor + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * i2cNumber - 0 = I2c0 and 1 = 12c1 + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidReadMonitor( + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char i2cNumber +) +{ + unsigned char i2cSCL, i2cSDA; + + if (i2cNumber == 0) + { + i2cSCL = DEFAULT_I2C0_SCL; + i2cSDA = DEFAULT_I2C0_SDA; + } + else + { + i2cSCL = DEFAULT_I2C1_SCL; + i2cSDA = DEFAULT_I2C1_SDA; + } + + return ddk770_edidReadMonitorEx(pEDIDBuffer, bufferSize, edidExtNo, i2cSCL, i2cSDA); +} + +/* + * ddk770_edidGetEstablishedTiming + * This function gets the established timing list from the given EDID buffer, + * table, and timing index. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor (In) + * pEstTableIndex - Pointer to the Established Timing Table index (In/Out) + * pIndex - Pointer to the Establihsed Timing Index (In/Out) + * pWidth - Pointer to a variable that to store the horizontal active / width + * value of the retrieved timing (Out) + * pHeight - Pointer to a variable to store the vertical active / height + * value of the retrieved timing (Out) + * pRefreshRate - Pointer to a variable to store the vertical frequency value + * of the retrieved timing (out) + * pSource - Pointer to a variable to store the standard timing source: + * 0 - VESA + * 1 - IBM + * 2 - Apple + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetEstablishedTiming( + unsigned char *pEDIDBuffer, + /*unsigned char *pEstTableIndex,*/ + unsigned char *pIndex, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pRefreshRate, + unsigned char *pSource +) +{ + unsigned char version, revision; + unsigned char tableIndex, index; + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + while (1) + { + /* Get index */ + index = *pIndex; + + if (index > 16) + break; + + /* Search Established Table index 0 when the index is less than 8 */ + tableIndex = index / 8; + + /* Exit the function when it has reached the last table. */ + if (tableIndex > 2) + break; + + /* Increment the index value and update the index accordingly */ + (*pIndex)++; + index %= 8; + + /* Check */ + if ((pEDIDStructure->estTiming[tableIndex] & (1 << index)) != 0) + { + if (pWidth != (unsigned long *)0) + *pWidth = establishTiming[tableIndex][index].x; + + if (pHeight != (unsigned long *)0) + *pHeight = establishTiming[tableIndex][index].y; + + if (pRefreshRate != (unsigned long *)0) + *pRefreshRate = establishTiming[tableIndex][index].hz; + + if (pSource != (unsigned char *)0) + *pSource = establishTiming[tableIndex][index].source; + + /* Return success */ + return 0; + } + } + } + else + { + /* EDID Structure Version 2.0. */ + } + + return (-1); +} + +/* + * edidCalculateStdTiming + * This function calculates the width, height, and vertical frequency values + * from the given Standard Timing structure. This function only applies to + * EDID structure version 1. It will give the wrong result when used with + * EDID version 2. + * + * Input: + * pStdTiming - Pointer to a standard timing structure that contains the + * standard timing value to be calculated (In) + * edid1Revision - Revision of the EDID 1 (In) + * pWidth - Pointer to a variable that to store the horizontal active / width + * value of the retrieved timing (Out) + * pHeight - Pointer to a variable to store the vertical active / height + * value of the retrieved timing (Out) + * pRefreshRate - Pointer to a variable to store the vertical frequency value + * of the retrieved timing (out) + * + * Output: + * 0 - Success + * -1 - Fail + */ +static long edidCalculateStdTiming( + standard_timing_t *pStdTiming, + unsigned char edid1Revision, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pRefreshRate +) +{ + unsigned long x, y; + + /* Calculate the standard timing into x and y mode dimension */ + if (pStdTiming->horzActive != 0x01) + { + /* Calculate the X and Y */ + x = (pStdTiming->horzActive + 31) * 8; + switch (pStdTiming->stdTimingInfo.aspectRatio) + { + case 0: + if (edid1Revision != 3) + y = x; /* 1:1 aspect ratio (prior revision 1.3) */ + else + y = x * 10 / 16; /* 16:10 aspect ratio (revision 1.3) */ + break; + case 1: + y = x * 3 / 4; /* 4:3 aspect ratio */ + break; + case 2: + y = x * 4 / 5; /* 5:4 aspect ratio */ + break; + case 3: + y = x * 9 / 16; /* 16:9 aspect ratio */ + break; + } + + if (pWidth != (unsigned long *)0) + *pWidth = x; + + if (pHeight != (unsigned long *)0) + *pHeight = y; + + if (pRefreshRate != (unsigned long *)0) + *pRefreshRate = pStdTiming->stdTimingInfo.refreshRate + 60; + + return 0; + } + + return (-1); +} + +/* + * ddk770_edidGetStandardTiming + * This function gets the standard timing from the given EDID buffer and + * calculates the width, height, and vertical frequency from that timing. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStdTimingIndex - Pointer to a standard timing index to be retrieved + * pWidth - Pointer to a variable that to store the horizontal active / width + * value of the retrieved timing (Out) + * pHeight - Pointer to a variable to store the vertical active / height + * value of the retrieved timing (Out) + * pRefreshRate - Pointer to a variable to store the vertical frequency value + * of the retrieved timing (out) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetStandardTiming( + unsigned char *pEDIDBuffer, + unsigned char *pStdTimingIndex, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pRefreshRate +) +{ + unsigned char version, revision, timingIndex, tableIndex; + //unsigned long x, y, aspectRatio; + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + while (1) + { + /* There are only 8 standard timing entries */ + if (*pStdTimingIndex > 7) + break; + + /* Get the table index first before incrementing the index. */ + timingIndex = *pStdTimingIndex; + + /* Increment the standard timing index */ + (*pStdTimingIndex)++; + + if (timingIndex < 8) + { + /* + * Search the first Standard Timing Identifier table + */ + + /* Calculate the standard timing into x and y mode dimension */ + if (edidCalculateStdTiming(&pEDIDStructure->stdTiming[timingIndex], + revision, pWidth, pHeight, pRefreshRate) == 0) + { + return 0; + } + } + else + { + /* + * Search Standard Timing Identifier Table in the detailed Timing block. + */ + + /* + * Each Detailed Timing Identifier can contains 6 entries of Standard Timing + * Identifier. Based on this value, we can get the Detailed Timing Table Index + * that contains the requested standard timing. + */ + timingIndex = timingIndex - 8; + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + /* Get detailed info */ + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFA)) + { + if (timingIndex >= 6) + { + timingIndex-=6; + continue; + } + else + { + if (edidCalculateStdTiming(&pMonitorDescriptor->descriptor.stdTimingExt.stdTiming[timingIndex], + revision, pWidth, pHeight, pRefreshRate) == 0) + { + return 0; + } + } + } + } + } + } + } + else + { + /* EDID Structure version 2 */ + } + + return (-1); +} + +/* + * ddk770_edidGetDetailedTiming + * This function gets the detailed timing from the given EDID buffer. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pDetailedTimingIndex - Pointer to a detailed timing index to be retrieved + * pModeParameter - Pointer to a mode_parameter_t structure that will be + * filled with the detailed timing. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetDetailedTiming( + unsigned char *pEDIDBuffer, + unsigned char *pDetailedTimingIndex, + vdif_t *pVDIF +) +{ + unsigned char version, revision, tableIndex; + //unsigned long x, y, aspectRatio; + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + detailed_timing_t *pDetailedTiming; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + while (1) + { + if (*pDetailedTimingIndex > 3) + break; + + /* Get the Detail Timing entry index */ + tableIndex = *pDetailedTimingIndex; + + /* Increment the index */ + (*pDetailedTimingIndex)++; + + /* Get detailed info */ + pDetailedTiming = &pEDIDStructure->miscInformation.detailTiming[tableIndex]; + if ((pDetailedTiming->pixelClock != 0) && (pVDIF != (vdif_t *)0)) + { + /* Translate the Detail timing to VDIF format. */ + pVDIF->pixelClock = (unsigned long)pDetailedTiming->pixelClock * 10000; + pVDIF->characterWidth = 8; + pVDIF->scanType = (pDetailedTiming->flags.interlaced == 0) ? VDIF_NONINTERLACED : VDIF_INTERLACED; + + pVDIF->horizontalActive = + ((unsigned long)pDetailedTiming->horzActiveBlanking.horzActiveMSB << 8) + + (unsigned long)pDetailedTiming->horzActive; + pVDIF->horizontalBlankStart = pVDIF->horizontalActive; + pVDIF->horizontalBlankTime = + ((unsigned long)pDetailedTiming->horzActiveBlanking.horzBlankingMSB << 8) + + (unsigned long)pDetailedTiming->horzBlanking; + pVDIF->horizontalTotal = pVDIF->horizontalActive + pVDIF->horizontalBlankTime; + pVDIF->horizontalFrontPorch = + ((unsigned long)pDetailedTiming->syncAuxInfo.horzSyncOffset << 8) + + (unsigned long)pDetailedTiming->horzSyncOffset; + pVDIF->horizontalSyncStart = pVDIF->horizontalBlankStart + pVDIF->horizontalFrontPorch; + pVDIF->horizontalSyncWidth = + ((unsigned long)pDetailedTiming->syncAuxInfo.horzSyncWidth << 8) + + (unsigned long)pDetailedTiming->horzSyncPulseWidth; + pVDIF->horizontalBackPorch = + pVDIF->horizontalBlankTime - (pVDIF->horizontalFrontPorch + pVDIF->horizontalSyncWidth); + pVDIF->horizontalFrequency = ddk770_roundedDiv(pVDIF->pixelClock, pVDIF->horizontalTotal); + pVDIF->horizontalLeftBorder = 0; + pVDIF->horizontalRightBorder = 0; + + pVDIF->verticalActive = + ((unsigned long)pDetailedTiming->vertActiveBlanking.vertActiveMSB << 8) + + (unsigned long)pDetailedTiming->vertActive; + pVDIF->verticalBlankStart = pVDIF->verticalActive; + pVDIF->verticalBlankTime = + ((unsigned long)pDetailedTiming->vertActiveBlanking.vertBlankingMSB << 8) + + (unsigned long)pDetailedTiming->vertBlanking; + pVDIF->verticalTotal = pVDIF->verticalActive + pVDIF->verticalBlankTime; + pVDIF->verticalFrontPorch = + ((unsigned long)pDetailedTiming->syncAuxInfo.vertSyncOffset << 8) + + (unsigned long)pDetailedTiming->verticalSyncInfo.syncOffset; + pVDIF->verticalSyncStart = pVDIF->verticalBlankStart + pVDIF->verticalFrontPorch; + pVDIF->verticalSyncHeight = + ((unsigned long)pDetailedTiming->syncAuxInfo.vertSyncWidth << 8) + + (unsigned long)pDetailedTiming->verticalSyncInfo.syncWidth; + pVDIF->verticalBackPorch = + pVDIF->verticalBlankTime - (pVDIF->verticalFrontPorch + pVDIF->verticalSyncHeight); + pVDIF->verticalFrequency = + ddk770_roundedDiv(pVDIF->pixelClock, (pVDIF->horizontalTotal * pVDIF->verticalTotal)); + pVDIF->verticalTopBorder = 0; + pVDIF->verticalBottomBorder = 0; + + if (pDetailedTiming->flags.connectionType == 3) + { + pVDIF->verticalSyncPolarity = + (pDetailedTiming->flags.vertSyncFlag == 1) ? VDIF_SYNC_POSITIVE : VDIF_SYNC_NEGATIVE; + pVDIF->horizontalSyncPolarity = + (pDetailedTiming->flags.horzSyncFlag == 1) ? VDIF_SYNC_POSITIVE : VDIF_SYNC_NEGATIVE; + } + else + { + pVDIF->verticalSyncPolarity = VDIF_SYNC_NEGATIVE; + pVDIF->horizontalSyncPolarity = VDIF_SYNC_NEGATIVE; + } + + /* For debugging purpose. */ + printVdif(pVDIF); + + return 0; + } + } + } + + return (-1); +} + +/* + * ddk770_edidGetMonitorSerialNumber + * This function gets the monitor serial number from the EDID structure. + * Only EDID version 1 and revision 1 or above supports this feature. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorSerialNumber - Pointer to a buffer to store the serial number + * retrieved from the EDID + * bufferSize - The size of the buffer to store the serial number. + * The maximum size required is 13 bytes. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetMonitorSerialNumber( + unsigned char *pEDIDBuffer, + char *pMonitorSerialNumber, + unsigned char bufferSize +) +{ + unsigned char version, revision, tableIndex, charIndex; + + /* If no pointer is given or the buffer size is set to 0, then return fail. */ + if ((pMonitorSerialNumber == (char *)0) || (bufferSize == 0)) + return (-1); + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, &revision); + + if ((version == 1) && (revision > 0)) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFF)) + { + bufferSize = (bufferSize > 13) ? 13 : bufferSize; + for (charIndex = 0; charIndex < 13; charIndex++) + { + if (pMonitorDescriptor->descriptor.serialNo[charIndex] == 0x0A) + { + pMonitorSerialNumber[charIndex] = '\0'; + break; + } + + pMonitorSerialNumber[charIndex] = pMonitorDescriptor->descriptor.serialNo[charIndex]; + } + + return 0; + } + } + } + + /* Serial Number is not found. */ + return (-1); +} + +/* + * ddk770_edidGetDataString + * This function gets the data string from the EDID + * Only EDID version 1 and revision 1 or above supports this feature. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorSerialNumber - Pointer to a buffer to store the data string + * retrieved from the EDID + * bufferSize - The size of the buffer to store the data string + * The maximum size required is 13 bytes. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetDataString( + unsigned char *pEDIDBuffer, + char *pDataString, + unsigned char bufferSize +) +{ + unsigned char version, revision, tableIndex, charIndex; + + /* If no pointer is given or the buffer size is set to 0, then return fail. */ + if ((pDataString == (char *)0) || (bufferSize == 0)) + return (-1); + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, &revision); + + if ((version == 1) && (revision > 0)) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFE)) + { + bufferSize = (bufferSize > 13) ? 13 : bufferSize; + for (charIndex = 0; charIndex < 13; charIndex++) + { + if (pMonitorDescriptor->descriptor.dataString[charIndex] == 0x0A) + { + pDataString[charIndex] = '\0'; + break; + } + + pDataString[charIndex] = pMonitorDescriptor->descriptor.dataString[charIndex]; + } + + return 0; + } + } + } + + /* Data String is not found. */ + return (-1); +} + +/* + * ddk770_edidGetMonitorRangeLimit + * This function gets the monitor range limits from the EDID structure. + * Only EDID version 1 revision 1 or above supports this feature. + * This is a required field in EDID Version 1.3 + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMinVerticalRate - Pointer to a variable to store the Minimum Vertical Rate (Hz) + * pMaxVerticalRate - Pointer to a variable to store the Maximum Vertical Rate (Hz) + * pMinHorzFreq - Pointer to a variable to store the Minimum Horz. Freq (kHz) + * pMaxHorzFreq - Pointer to a variable to store the Maximum Horz. Freq (kHz) + * pMaxPixelClock - Pointer to a variable to store the Maximum Pixel Clock (Hz) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetMonitorRangeLimit( + unsigned char *pEDIDBuffer, + unsigned char *pMinVerticalRate, + unsigned char *pMaxVerticalRate, + unsigned char *pMinHorzFreq, + unsigned char *pMaxHorzFreq, + unsigned long *pMaxPixelClock +) +{ + unsigned char version, revision, tableIndex; + //unsigned char charIndex; + + if (pEDIDBuffer == (unsigned char *)0) + return (-1); + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, &revision); + + if ((version == 1) && (revision > 0)) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFD) && (pMonitorDescriptor->flag3 == 0)) + { + if (pMinVerticalRate != (unsigned char *)0) + *pMinVerticalRate = pMonitorDescriptor->descriptor.monitorRange.minVertRate; + + if (pMaxVerticalRate != (unsigned char *)0) + *pMaxVerticalRate = pMonitorDescriptor->descriptor.monitorRange.maxVertRate; + + if (pMinHorzFreq != (unsigned char *)0) + *pMinHorzFreq = pMonitorDescriptor->descriptor.monitorRange.minHorzFrequency; + + if (pMaxHorzFreq != (unsigned char *)0) + *pMaxHorzFreq = pMonitorDescriptor->descriptor.monitorRange.maxHorzFrequency; + + if (pMaxPixelClock != (unsigned long *)0) + *pMaxPixelClock = (unsigned long) pMonitorDescriptor->descriptor.monitorRange.maxPixelClock * 10 * 1000000; + + return 0; + } + } + } + + /* Data String is not found. */ + return (-1); +} + +/* + * edidGetChannel1TimingSupport + * This function gets the secondary GTF timing support. + * Only EDID version 1 and revision 1 or above supports this feature. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStartFrequency - Pointer to a variable to store the start frequency of + * the secondary GTF + * pOffset - Pointer to a variable to store the Offset (C) value of + * the secondary GTF + * pGradient - Pointer to a variable to store the Gradient (M) value of + * the secondary GTF + * pScalingFactor - Pointer to a variable to store the Scaling Factor (K) + * value of the secondary GTF + * pScalingFactorWeight - Pointer to a variable to store the Scaling Factore Weight (J) + * value of the secondary GTF + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetChannel1TimingSupport( + unsigned char *pEDIDBuffer, + unsigned short *pStartFrequency, + unsigned char *pOffset, + unsigned short *pGradient, + unsigned char *pScalingFactor, + unsigned char *pScalingFactorWeight +) +{ + unsigned char version, revision, tableIndex; + //unsigned char charIndex; + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, &revision); + + if ((version == 1) && (revision > 0) && (pEDIDBuffer != (unsigned char *)0)) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFD) && + (pMonitorDescriptor->descriptor.monitorRange.secondaryTimingFlag == 0x02)) + { + if (pStartFrequency != (unsigned short *)0) + *pStartFrequency = (unsigned short) + pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.startFrequency * 2 * 1000; + + if (pOffset != (unsigned char *)0) + *pOffset = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.cParam/2; + + if (pGradient != (unsigned short *)0) + *pGradient = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.mParam; + + if (pScalingFactor != (unsigned char *)0) + *pScalingFactor = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.kParam; + + if (pScalingFactorWeight != (unsigned char *)0) + *pScalingFactorWeight = pMonitorDescriptor->descriptor.monitorRange.secondaryTimingInfo.cmkjParam.jParam / 2; + + return 0; + } + } + } + + /* Data String is not found. */ + return (-1); +} + +/* + * ddk770_edidGetMonitorName + * This function gets the monitor name from the EDID structure. + * This is a required field in EDID Version 1.3 + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorName - Pointer to a buffer to store the monitor name + * retrieved from the EDID + * bufferSize - The size of the buffer to store the monitor name + * The maximum size required is 13 bytes. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetMonitorName( + unsigned char *pEDIDBuffer, + char *pMonitorName, + unsigned char bufferSize +) +{ + unsigned char version, revision, tableIndex, charIndex; + + /* If no pointer is given or the buffer size is set to 0, then return fail. */ + if ((pMonitorName == (char *)0) || (bufferSize == 0)) + return (-1); + + /* Get EDID Version and revision */ + version = ddk770_edidGetVersion(pEDIDBuffer, &revision); + + if (version == 1) + { + edid_version_1_t *pEDIDStructure; + monitor_desc_t *pMonitorDescriptor; + + /* EDID Structure Version 1. */ + pEDIDStructure = (edid_version_1_t *)pEDIDBuffer; + for (tableIndex = 0; tableIndex < 4; tableIndex++) + { + pMonitorDescriptor = &pEDIDStructure->miscInformation.monitorDesc[tableIndex]; + if ((pMonitorDescriptor->flag1 == 0) && (pMonitorDescriptor->flag2 == 0) && + (pMonitorDescriptor->dataTypeTag == 0xFC) && (pMonitorDescriptor->flag3 == 0)) + { + bufferSize = (bufferSize > 13) ? 13 : bufferSize; + for (charIndex = 0; charIndex < 13; charIndex++) + { + if (pMonitorDescriptor->descriptor.monitorName[charIndex] == 0x0A) + { + pMonitorName[charIndex] = '\0'; + break; + } + + pMonitorName[charIndex] = pMonitorDescriptor->descriptor.monitorName[charIndex]; + } + + return 0; + } + } + } + + /* Data String is not found. */ + return (-1); +} + +/* + * ddk770_edidGetPreferredTiming + * This function gets the preferred/native timing of the monitor + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pWidth - Pointer to an unsigned long buffer to store the width + * of the preferred (native) timing. + * pHeight - Pointer to an unsigned long buffer to store the height + * of the preferred (native) timing. + * pVerticalFrequency - Pointer to an unsigned long buffer to store the refresh + * rate of the preferred (native) timing. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetPreferredTiming( + unsigned char *pEDIDBuffer, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pVerticalFrequency +) +{ + unsigned char index = 0; + vdif_t vdifBuffer; + + { + /* The preferred (native) timing is available, so get the timing. It is located + at the first index of detailed timing. + */ + if (ddk770_edidGetDetailedTiming(pEDIDBuffer, &index, &vdifBuffer) == 0) + { + if (pWidth != (unsigned long *)0) + *pWidth = vdifBuffer.horizontalActive; + + if (pHeight != (unsigned long *)0) + *pHeight = vdifBuffer.verticalActive; + + if (pVerticalFrequency != (unsigned long *)0) + *pVerticalFrequency = vdifBuffer.verticalFrequency; + + return 0; + } + } + + return (-1); +} diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_edid.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_edid.h new file mode 100644 index 000000000000..e8da6371acf6 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_edid.h @@ -0,0 +1,657 @@ +#ifndef _DDK770_EDID_H_ +#define _DDK770_EDID_H_ + +#include "ddk770_display.h" +#include "../hw_com.h" + +#define CEA_EXT 0x02 +#define VENDOR_BLOCK 0x03 + +#define HDMI_IEEE_OUI 0x000c03 + +/* Sync polarity */ +typedef enum _vdif_sync_polarity_t +{ + VDIF_SYNC_NEGATIVE = 0, + VDIF_SYNC_POSITIVE +} vdif_sync_polarity_t; + +/* Scan type */ +typedef enum _vdif_scan_type_t +{ + VDIF_NONINTERLACED = 0, + VDIF_INTERLACED +} vdif_scan_type_t; + +/* Monitor Timing Information */ +typedef struct _video_display_information_format_t +{ + unsigned long pixelClock; + unsigned long characterWidth; + vdif_scan_type_t scanType; + + unsigned long horizontalFrequency; + vdif_sync_polarity_t horizontalSyncPolarity; + unsigned long horizontalTotal; + unsigned long horizontalActive; + unsigned long horizontalBlankStart; + unsigned long horizontalBlankTime; + unsigned long horizontalSyncStart; + unsigned long horizontalRightBorder; + unsigned long horizontalFrontPorch; + unsigned long horizontalSyncWidth; + unsigned long horizontalBackPorch; + unsigned long horizontalLeftBorder; + + unsigned long verticalFrequency; + vdif_sync_polarity_t verticalSyncPolarity; + unsigned long verticalTotal; + unsigned long verticalActive; + unsigned long verticalBlankStart; + unsigned long verticalBlankTime; + unsigned long verticalSyncStart; + unsigned long verticalBottomBorder; + unsigned long verticalFrontPorch; + unsigned long verticalSyncHeight; + unsigned long verticalBackPorch; + unsigned long verticalTopBorder; +} vdif_t; + + + +/* Restore alignment */ +#pragma pack() + +/************************************************************** + * Function Prototypes + **************************************************************/ + +/* + * ddk770_edidGetVersion + * This function gets the EDID version + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRevision - Revision of the EDIE (if exist) + * + * Output: + * Revision number of the given EDID buffer. + */ +unsigned char ddk770_edidGetVersion( + unsigned char *pEDIDBuffer, + unsigned char *pRevision +); + +/* + * ddk770_edidGetProductInfo + * This function gets the vendor and product information. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor [in] + * pManufacturerName - Pointer to a 3 byte length variable to store the manufacturer name [out] + * pProductCode - Pointer to a variable to store the product code [out] + * pSerialNumber - Pointer to a variable to store the serial number [out] + * pWeekOfManufacture - Pointer to a variable to store the week of manufacture [out] + * pYearOfManufacture - Pointer to a variable to store the year of manufacture + * or model year (if WeekOfManufacture is 0xff) [out] + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetProductInfo( + unsigned char *pEDIDBuffer, + char *pManufacturerName, + unsigned short *pProductCode, + unsigned long *pSerialNumber, + unsigned char *pWeekOfManufacture, + unsigned short *pYearOfManufacture +); + +/* + * ddk770_edidCheckMonitorInputSignal + * This function checks whether the monitor is expected analog/digital + * input signal. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Analog + * 1 - Digital + */ +unsigned char ddk770_edidCheckMonitorInputSignal( + unsigned char *pEDIDBuffer +); + +/* + * ddk770_edidGetAnalogSignalInfo + * This function gets the analog video input signal information + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRefWhiteAboveBlank - Pointer to a variable to store the reference white above blank + * value. The value is in milliVolt. + * pSyncLevelBelowBlank - Pointer to a variable to store the Sync tip level below blank + * The value is also in milliVolt + * pBlank2BlackSetup - Pointer to a variable to store the Blank to black setup or + * pedestal per appropriate Signal Level Standard flag. + * 1 means that the display expect the setup. + * pSeparateSyncSupport - Pointer to a variable to store the flag to indicate that the + * monitor supports separate sync. + * pCompositeSyncSupport - Pointer to a variable to store a flag to indicate that the + * monitor supports composite sync. + * pSyncOnGreenSupport - Pointer to a variable to store a flag to indicate that + * the monitor supports sync on green video. + * pVSyncSerrationRequired - Pointer to a variable to store a flag to indicate that serration + * of the VSync pulse is required when composite sync or + * sync-on-green video is used. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetAnalogSignalInfo( + unsigned char *pEDIDBuffer, + unsigned short *pRefWhiteAboveBlank, + unsigned short *pSyncLevelBelowBlank, + unsigned char *pBlank2BlackSetup, + unsigned char *pSeparateSyncSupport, + unsigned char *pCompositeSyncSupport, + unsigned char *pSyncOnGreenSupport, + unsigned char *pVSyncSerrationRequired +); + +/* + * ddk770_edidGetDigitalSignalInfo + * This function gets the digital video input signal information + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pDFP1xSupport - Pointer to a variable to store the flag to indicate that + * the mointor interface is signal compatible with VESA + * DFP 1.x TMDS CRGB, 1 pixel/clock, up to 8 bits / color + * MSB aligned, DE active high + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetDigitalSignalInfo( + unsigned char *pEDIDBuffer, + unsigned char *pDFP1xSupport +); + +/* + * ddk770_edidGetDisplaySize + * This function gets the display sizes in cm. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMaxHorzImageSize - Pointer to a variable to store the maximum horizontal + * image size to the nearest centimeter. A value of 0 + * indicates that the size is indeterminate size. + * pMaxVertImageSize - Pointer to a variable to store the maximum vertical + * image size to the nearest centimeter. A value of 0 + * indicates that the size is indeterminate size. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetDisplaySize( + unsigned char *pEDIDBuffer, + unsigned char *pMaxHorzImageSize, + unsigned char *pMaxVertImageSize +); + +/* + * ddk770_edidGetPowerManagementSupport + * This function gets the monitor's power management support. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStandBy - Pointer to a variable to store the flag to indicate that + * standby power mode is supported. + * pSuspend - Pointer to a variable to store the flag to indicate that + * suspend power mode is supported. + * pLowPower - Pointer to a variable to store the flag to indicate that + * the display consumes low power when it receives a timing + * signal that is outside its declared active operating range. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetPowerManagementSupport( + unsigned char *pEDIDBuffer, + unsigned char *pStandBy, + unsigned char *pSuspend, + unsigned char *pLowPower +); + +/* + * ddk770_edidGetDisplayType + * This function gets the display type. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Monochrome / grayscale display + * 1 - RGB Color Display + * 2 - Non-RGB multicolor display, e.g. R/G/Y + * 3 - Undefined + */ +unsigned char ddk770_edidGetDisplayType( + unsigned char *pEDIDBuffer +); + +/* + * ddk770_edidChecksRGBUsage + * This function checks if the display is using the sRGB standard default + * color space as its primary color space. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Does not use sRGB as its primary color space + * 1 - Use sRGB as its primary color space + */ +unsigned char ddk770_edidChecksRGBUsage( + unsigned char *pEDIDBuffer +); + +/* + * ddk770_edidIsPreferredTimingAvailable + * This function checks whether the preffered timing mode is available. + * Use of preferred timing mode is required by EDID structure version 1 + * Revision 3 and higher. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Preferred Timing is not available + * 1 - Preferred Timing is available + */ +unsigned char ddk770_edidIsPreferredTimingAvailable( + unsigned char *pEDIDBuffer +); + +/* + * ddk770_edidIsDefaultGTFSupported + * This function checks whether the display supports timings based on the + * GTF standard using default GTF parameter values. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * 0 - Default GTF is not supported + * 1 - Default GTF is supported + */ +unsigned char ddk770_edidIsDefaultGTFSupported( + unsigned char *pEDIDBuffer +); + +/* + * ddk770_edidGetColorCharacteristic + * This function gets the chromaticity and white point values expressed as + * an integer value which represents the actual value times 1000. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pRedX - Pointer to a variable to store the Red X values + * pRedY - Pointer to a variable to store the Red Y values + * pGreenX - Pointer to a variable to store the Green X values + * pGreenY - Pointer to a variable to store the Green Y values + * pBlueX - Pointer to a variable to store the Blue X values + * pBlueY - Pointer to a variable to store the Blue Y values + * + * Note: + * To get the White color characteristic, use the ddk770_edidGetWhitePoint + */ +void ddk770_edidGetColorCharacteristic( + unsigned char *pEDIDBuffer, + unsigned short *pRedX, + unsigned short *pRedY, + unsigned short *pGreenX, + unsigned short *pGreenY, + unsigned short *pBlueX, + unsigned short *pBlueY +); + +/* + * ddk770_edidGetWhitePoint + * This function gets the white point. + * To get the default white point, set the index to 0. For multiple white point, + * call this function multiple times to check if more than 1 white point is supported. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pWhitePointIndex - Pointer to a variable that contains the white point index + * to be retrieved. + * pWhiteX - Pointer to a variable to store the White X value + * pWhiteY - Pointer to a variable to store the White Y value + * pWhiteGamma - Pointer to a variable to store the White Gamma value + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetWhitePoint( + unsigned char *pEDIDBuffer, + unsigned char *pWhitePointIndex, + unsigned short *pWhiteX, + unsigned short *pWhiteY, + unsigned short *pWhiteGamma +); + +/* + * ddk770_edidGetExtension + * This function gets the number of (optional) EDID extension blocks to follow + * the given EDID buffer. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * + * Output: + * Total number of EDID Extension to follow the given EDID buffer. + */ +unsigned char ddk770_edidGetExtension( + unsigned char *pEDIDBuffer +); + +/* + * ddk770_edidReadMonitor + * This function reads the EDID structure from the attached monitor + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * i2cNumber - 0 = I2c0 and 1 = 12c1 + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidReadMonitor( + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char i2cNumber +); + +/* + * ddk770_edidReadMonitor + * This function reads the EDID structure from the attached monitor + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * sclGpio - GPIO pin used as the I2C Clock (SCL) + * sdaGpio - GPIO pin used as the I2C Data (SDA) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidReadMonitorEx( + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char sclGpio, + unsigned char sdaGpio +); + +/* + * This function is same as editReadMonitorEx(), but using HW I2C. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * i2cNumber - 0 = I2C0 and 1 = I2C1 + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidReadMonitorExHwI2C( + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char i2cNumber +); + +/* + * ddk770_edidGetEstablishedTiming + * This function gets the established timing list from the given EDID buffer, + * table, and timing index. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor (In) + * pEstTableIndex - Pointer to the Established Timing Table index (In/Out) + * pIndex - Pointer to the Establihsed Timing Index (In/Out) + * pWidth - Pointer to a variable that to store the horizontal active / width + * value of the retrieved timing (Out) + * pHeight - Pointer to a variable to store the vertical active / height + * value of the retrieved timing (Out) + * pRefreshRate - Pointer to a variable to store the vertical frequency value + * of the retrieved timing (out) + * pSource - Pointer to a variable to store the standard timing source: + * 0 - VESA + * 1 - IBM + * 2 - Apple + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetEstablishedTiming( + unsigned char *pEDIDBuffer, + /*unsigned char *pEstTableIndex,*/ + unsigned char *pIndex, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pRefreshRate, + unsigned char *pSource +); + +/* + * ddk770_edidGetStandardTiming + * This function gets the standard timing from the given EDID buffer and + * calculates the width, height, and vertical frequency from that timing. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStdTimingIndex - Pointer to a standard timing index to be retrieved + * pWidth - Pointer to a variable that to store the horizontal active / width + * value of the retrieved timing (Out) + * pHeight - Pointer to a variable to store the vertical active / height + * value of the retrieved timing (Out) + * pRefreshRate - Pointer to a variable to store the vertical frequency value + * of the retrieved timing (out) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetStandardTiming( + unsigned char *pEDIDBuffer, + unsigned char *pStdTimingIndex, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pRefreshRate +); + +/* + * ddk770_edidGetDetailedTiming + * This function gets the detailed timing from the given EDID buffer. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pDetailedTimingIndex - Pointer to a detailed timing index to be retrieved + * pModeParameter - Pointer to a mode_parameter_t structure that will be + * filled with the detailed timing. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetDetailedTiming( + unsigned char *pEDIDBuffer, + unsigned char *pDetailedTimingIndex, + vdif_t *pVDIF +); + +/* + * ddk770_edidGetMonitorSerialNumber + * This function gets the monitor serial number from the EDID structure. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorSerialNumber - Pointer to a buffer to store the serial number + * retrieved from the EDID + * bufferSize - The size of the buffer to store the serial number. + * The maximum size required is 13 bytes. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetMonitorSerialNumber( + unsigned char *pEDIDBuffer, + char *pMonitorSerialNumber, + unsigned char bufferSize +); + +/* + * ddk770_edidGetDataString + * This function gets the data string from the EDID structure. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorSerialNumber - Pointer to a buffer to store the data string + * retrieved from the EDID + * bufferSize - The size of the buffer to store the data string + * The maximum size required is 13 bytes. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetDataString( + unsigned char *pEDIDBuffer, + char *pDataString, + unsigned char bufferSize +); + +/* + * ddk770_edidGetMonitorRangeLimit + * This function gets the monitor range limits from the EDID structure. + * Only EDID version 1 and revision 1 or above supports this feature. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMinVerticalRate - Pointer to a variable to store the Minimum Vertical Rate (Hz) + * pMaxVerticalRate - Pointer to a variable to store the Maximum Vertical Rate (Hz) + * pMinHorzFreq - Pointer to a variable to store the Minimum Horz. Freq (kHz) + * pMaxHorzFreq - Pointer to a variable to store the Maximum Horz. Freq (kHz) + * pMaxPixelClock - Pointer to a variable to store the Maximum Pixel Clock (Hz) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetMonitorRangeLimit( + unsigned char *pEDIDBuffer, + unsigned char *pMinVerticalRate, + unsigned char *pMaxVerticalRate, + unsigned char *pMinHorzFreq, + unsigned char *pMaxHorzFreq, + unsigned long *pMaxPixelClock +); + +/* + * ddk770_edidGetChannel1TimingSupport + * This function gets the secondary GTF timing support. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pStartFrequency - Pointer to a variable to store the start frequency of + * the secondary GTF + * pOffset - Pointer to a variable to store the Offset (C) value of + * the secondary GTF + * pGradient - Pointer to a variable to store the Gradient (M) value of + * the secondary GTF + * pScalingFactor - Pointer to a variable to store the Scaling Factor (K) + * value of the secondary GTF + * pScalingFactorWeight - Pointer to a variable to store the Scaling Factore Weight (J) + * value of the secondary GTF + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetChannel1TimingSupport( + unsigned char *pEDIDBuffer, + unsigned short *pStartFrequency, + unsigned char *pOffset, + unsigned short *pGradient, + unsigned char *pScalingFactor, + unsigned char *pScalingFactorWeight +); + +/* + * ddk770_edidGetMonitorName + * This function gets the monitor name from the EDID structure. + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pMonitorName - Pointer to a buffer to store the monitor name + * retrieved from the EDID + * bufferSize - The size of the buffer to store the monitor name + * The maximum size required is 13 bytes. + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetMonitorName( + unsigned char *pEDIDBuffer, + char *pMonitorName, + unsigned char bufferSize +); + +/* + * ddk770_edidGetPreferredTiming + * This function gets the preferred/native timing of the monitor + * + * Input: + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * pWidth - Pointer to an unsigned long buffer to store the width + * of the preferred (native) timing. + * pHeight - Pointer to an unsigned long buffer to store the height + * of the preferred (native) timing. + * pVerticalFrequency - Pointer to an unsigned long buffer to store the refresh + * rate of the preferred (native) timing. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_edidGetPreferredTiming( + unsigned char *pEDIDBuffer, + unsigned long *pWidth, + unsigned long *pHeight, + unsigned long *pVerticalFrequency +); + +#endif /* _EDID_H_ */ + + + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_gpio.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_gpio.c new file mode 100644 index 000000000000..196088deb99d --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_gpio.c @@ -0,0 +1,89 @@ +#include +#include "ddk770_os.h" +#include "ddk770_reg.h" +#include "ddk770_power.h" +#include "ddk770_ddkdebug.h" +#include "ddk770_help.h" +#include "ddk770_gpio.h" + + +void ddk770_gpioMode(int pin , int mode) //0 =output 1 = intput +{ + unsigned int regval, pinoffset = 0; + + pinoffset = pin << 2; + + regval = peekRegisterDWord(GPIO0_PAD_CONTROL+pinoffset); + + if(mode == 0) { + pokeRegisterDWord(GPIO0_PAD_CONTROL+pinoffset, + FIELD_SET(regval, GPIO0_PAD_CONTROL, OEN, OUTPUT)); + + } + else if(mode == 1) { + pokeRegisterDWord(GPIO0_PAD_CONTROL+pinoffset, + FIELD_SET(regval, GPIO0_PAD_CONTROL, OEN, INPUT)); + } + return ; +} + + +/* +This used for disable or enable GPIO Resistor. + +mode: 1: Without Resistor(No PU or PD) 0: With Resistor + +*/ +void ddk770_gpioRENMode(int pin,int mode) +{ + unsigned int regval, pinoffset = 0; + + pinoffset = pin << 2; + pokeRegisterDWord(GPIO0_PAD_CONTROL+pinoffset,0x300); + + regval = peekRegisterDWord(GPIO0_PAD_CONTROL+pinoffset); + pokeRegisterDWord(GPIO0_PAD_CONTROL+pinoffset, + FIELD_VALUE(regval, GPIO0_PAD_CONTROL, MSC, mode)); +} + + + + +void ddk770_gpioWrite(int pin, int value) +{ + unsigned int regval, pinoffset = 0; + + pinoffset = pin << 2; + + regval = peekRegisterDWord(GPIO0_PAD_CONTROL + pinoffset); + pokeRegisterDWord(GPIO0_PAD_CONTROL + pinoffset, + FIELD_VALUE(regval, GPIO0_PAD_CONTROL, DATA, value)); + + return ; +} + +unsigned char ddk770_gpioRead(int pin) +{ + unsigned int regval; + //unsigned int val; + + if(pin < 32){ + regval = peekRegisterDWord(GPIO_DATA); + if(regval & 1< +#include "ddk770_reg.h" +#include "ddk770_os.h" +#include "ddk770_help.h" +#include "ddk770_hardware.h" +#include "ddk770_ddkdebug.h" + + + +// static device_object_t deviceObject; +static device_object_t *pDeviceObject = (device_object_t *)0; + +/* Total number of devices with the same ID in the system. + Use 0 as default. +*/ +static unsigned short gwNumOfDev = 0; + +/* Current device in use. + If there is only ONE device, it's always device 0. + If gwNumDev > 1, user need to set device 0, device 1, device 2, etc.. + The purpose is using it control multiple devices of the same ID, if any. +*/ +static unsigned short gwCurDev = 0; + + + +/* Functions to return property of device Object */ + +/* + * Function to return vendor ID property of device object. + */ +unsigned short getVendorId(void) +{ + if (pDeviceObject == (device_object_t *)0) + return 0; + + return pDeviceObject->vendorId; +} + +/* + * Function to return device ID property of device object. + */ +unsigned short getDeviceId(void) +{ + if (pDeviceObject == (device_object_t *)0) + return 0; + + return pDeviceObject->deviceId; +} + +/* + * Function to return revision ID property of device object. + */ +unsigned char getDeviceRev(void) +{ + if (pDeviceObject == (device_object_t *)0) + return 0; + + return pDeviceObject->deviceRev; +} + +/* + * Get the IRQ number of the current device. + */ +unsigned char getIRQ(void) +{ + if (pDeviceObject == (device_object_t *)0) + return 0; + else + return(pDeviceObject->irq); +} + +/* + * Get the frame buffer size of the current device. + */ +unsigned long getFrameBufSize(void) +{ + if (pDeviceObject == (device_object_t *)0) + return 0; + else + return(pDeviceObject->frameBufSize); +} + +/* + * Get a pointer to the physical base of Memory Mapped IO space. + * + * Return: A pointer to physical base of MMIO. + * NULL pointer if fail. + */ +void *getMmioPhysicalBase(void) +{ + if (pDeviceObject == (device_object_t *)0) + return (void *)0; + else + return(pDeviceObject->mmioPhysicalBase[gwCurDev]); +} + +/* + * Get a pointer to the logical base of Memory Mapped IO space. + * Software need this base address to access MMIO (not the mmioPhysicalBase). + * + * Return: A pointer to base of MMIO. + * NULL pointer if fail. + */ +void *getMmioBase(void) +{ + if (pDeviceObject == (device_object_t *)0) + return (void *)0; + else + return(pDeviceObject->mmioBase[gwCurDev]); +} + +/* + * Get the logical address of an offset location in MMIO space. + * Return: A valid address if success. + * NULL address if fail. + */ +void *getMmioAddress(unsigned long offset /*Offset from base of MMIO*/) +/* Note: When offset is equal to 0, this funciton is same as getMmioBase() */ +{ + if (pDeviceObject == (device_object_t *)0) + return (void *)0; + else + return((void *)((unsigned long)pDeviceObject->mmioBase[gwCurDev] + offset)); +} + +/* + * Get a pointer to the physical base video memory. This can be used for DMA transfer. + * In DOS, the physical and the logical address most likely are the same. + * Return: A pointer to base of physical video memory. + * NULL pointer if fail. + */ +void *getFrameBufPhysicalBase(void) +{ + if (pDeviceObject == (device_object_t *)0) + return (void *)0; + else + return(pDeviceObject->frameBufPhysicalBase[gwCurDev]); +} + +/* + * Get the physical address of an offset location in frame buffer. + * In DOS, the physical and the logical address most likely are the same. + * Return: A valid address if success. + * NULL address if fail. + */ +void *getFrameBufPhysicalAddress(unsigned long offset /* Offset from base of physical frame buffer */) +/* Note: When offset is equal to 0, this function is same as getFrameBufPhysicalBase() */ +{ + if (pDeviceObject == (device_object_t *)0) + return (void *)0; + else + return((void *)((unsigned long)pDeviceObject->frameBufPhysicalBase[gwCurDev]+offset)); +} + +/* + * Get a pointer to the logical base address of video memory (or frame buffer). + * Software can only work with logical address. + * + * Return: A pointer to base of video memory. + * NULL pointer if fail. + */ +void *getFrameBufBase(void) +{ + if (pDeviceObject == (device_object_t *)0) + return (void *)0; + else + return(pDeviceObject->frameBufBase[gwCurDev]); +} + +/* + * Get the logical address of an offset location in frame buffer. + * Return: A valid address if success. + * NULL address if fail. + */ +void *getFrameBufAddress(unsigned long offset /*Offset from base of frame buffer*/) +/* Note: When offset is equal to 0, this function is same as getFrameBufBase() */ +{ + if (pDeviceObject == (device_object_t *)0) + return (void *)0; + else + return((void *)((unsigned long)pDeviceObject->frameBufBase[gwCurDev]+offset)); +} + +/* + * How many devices of the same ID are there. + */ +unsigned short getNumOfDevices() +{ + return gwNumOfDev; +} + +/* + * This function sets up the current accessible device, if more + * than one of the same ID exist in the system. + * + * Note: + * Single device application don't need to call this function. + * This function is to control multiple devices. + */ +long setCurrentDevice(unsigned short dev) +{ + /* Error check */ + if ( dev >= gwNumOfDev) + return -1; + + gwCurDev = dev; + return 0; +} + +/* + * This function gets the current accessible device index. + */ +unsigned short getCurrentDevice() +{ + return gwCurDev; +} + + +/* + * This function uses strap pin to detect DDR size, and + * set up DDR controller accordingly. + */ +unsigned long setupMemController() +{ + unsigned long strapPin; + unsigned long rValue; + unsigned long regValue; + unsigned int g_ddr_size; + regValue = peekRegisterDWord(0x6bc); + regValue &=0xfffffff1; + strapPin = ( FIELD_VAL_GET(peekRegisterDWord(STRAP_PINS2), STRAP_PINS2, MEM_SIZE) << 1 ) | FIELD_VAL_GET(peekRegisterDWord(STRAP_PINS1), STRAP_PINS1, MEM_SIZE) ; + + switch(strapPin) + { + case 0x02: + rValue = MB(512); + regValue |= 0x6; + g_ddr_size = 1; + break; + case 0x01: + rValue = MB(1024); + regValue |= 0x4; + g_ddr_size = 2; + break; + case 0x00: + rValue = MB(2048); + regValue |= 0x2; + g_ddr_size = 3; + break; + case 0x03: + default: /* default size of 512MB. Don't need to do anything */ + rValue = MB(256); + regValue |= 0x8; + g_ddr_size = 0; + break; + } + printk("%s strapPin:%lx rValue:%lx \n", __FUNCTION__,strapPin,rValue); + //rValue = MB(256); //Just use 1024MB for mammping + pokeRegisterDWord(0x6bc, regValue); + + return(rValue); +} + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_hardware.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_hardware.h new file mode 100644 index 000000000000..4c013958bc38 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_hardware.h @@ -0,0 +1,205 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* HARDWARE.h --- Voyager GX SDK +* This file contains the definitions for the physical hardware. +* +*******************************************************************/ +#ifndef _DDK770_HARDWARE_H_ +#define _DDK770_HARDWARE_H_ + +/* ARM related definitions*/ +#ifdef __ICCARM__ +#include + +#define MMIO_BASE 0x80200000U + +#define REG32(reg) (*(volatile uint32_t*)((uint32_t)reg)) +#define REG16(reg) (*(volatile uint16_t*)((uint32_t)reg)) +#define REG8(reg) (*(volatile uint8_t*)((uint32_t)reg)) +#endif + + + +/* Silicon Motion PCI vendor ID */ +#define SMI_PCI_VENDOR_ID 0x126F + +/* Silicon Motion Device ID that is supported by this library. */ +#define SMI_DEVICE_ID_SM770 0x0770 + +/* Maximum number of devices with the same ID supported by this library. */ +#define MAX_SMI_DEVICE 4 + +//#define MB(x) (x<<20) /* Macro for Mega Bytes */ +#define MB(val) ((long long)(val) * 1024 * 1024) + +/* Size of SM768 MMIO and memory */ +#define SMI_MMIO_SIZE_SM770 MB(2) /* 2M of MMIO space */ +#define SMI_MEMORY_SIZE_SM770 MB(256) /* Falcon ASIC shuttle 2 has 256M of DDR */ +#define DEFAULT_MEM_SIZE MB(256) + + +#if 1 +#define SMI_RELEASE 3 +#define PRINT_MAX_NUM 512 +//#define REC_SPEED + + +#define DEBUG_FILE_PATH "/root/tstdma.log" +//#define MB(val) (val * 1024 * 1024) +#define FILE_MAX_SIZE MB(1) +#define LOG_BUF_SIZE 128 + +#if (SMI_RELEASE != 2) +#define SMI_PRINT(...) \ +do{ \ +char buf[PRINT_MAX_NUM]; \ +sprintf(buf, __VA_ARGS__); \ +smi_Print(buf); \ +}while(0) +#else +#define SMI_PRINT(...) printf( __VA_ARGS__) +#endif + + +int smi_Print(char * string); +char transChar(char cin); +#endif +/* This object holds essential informaiton to access the device */ +typedef struct _device_object_t +{ + unsigned short vendorId; + unsigned short deviceId; + unsigned short deviceNum; + unsigned short deviceRev; + unsigned short irq; + void *mmioPhysicalBase[MAX_SMI_DEVICE]; + void *mmioBase[MAX_SMI_DEVICE]; + void *frameBufPhysicalBase[MAX_SMI_DEVICE]; + void *frameBufBase[MAX_SMI_DEVICE]; + unsigned long mmioSize; + unsigned long frameBufSize; +} +device_object_t; + +/* + * This function detects if SMI chips is in the system, + * and create a device object. + * + * Input: + * regInterval: register delay. + * memInterval: memory delay. + * + * Return: A non-zero device ID if SMI chip is detected. + * Zero means NO SMI chip is detected. + */ +// void * detectDevices(unsigned long regInterval, unsigned long memInterval); + +/* Functions to return property of device Object */ + +/* + * Function to return vendor ID property of device object. + */ +unsigned short getVendorId(void); + +/* + * Function to return device ID property of device object. + */ +unsigned short getDeviceId(void); + +/* + * Function to return revision ID property of device object. + */ +unsigned char getDeviceRev(void); + +/* + * Get the IRQ number of the current device. + */ +unsigned char getIRQ(void); + +/* + * Get the frame buffer size of the current device. + */ +unsigned long getFrameBufSize(void); + +/* + * Get a pointer to the physical base of Memory Mapped IO space. + * + * Return: A pointer to physical base of MMIO. + * NULL pointer if fail. + */ +void *getMmioPhysicalBase(void); + +/* + * Get a pointer to the logical base of Memory Mapped IO space. + * Software need this base address to access MMIO (not the mmioPhysicalBase). + * + * Return: A pointer to base of MMIO. + * NULL pointer if fail. + */ +void *getMmioBase(void); + +/* + * Get the logical address of an offset location in MMIO space. + * Return: A valid address if success. + * NULL address if fail. + */ +void *getMmioAddress(unsigned long offset /*Offset from base of MMIO*/); + +/* + * Get a pointer to the physical base video memory. This can be used for DMA transfer. + * In DOS, the physical and the logical address most likely are the same. + * Return: A pointer to base of physical video memory. + * NULL pointer if fail. + */ +void *getFrameBufPhysicalBase(void); + +/* + * Get the physical address of an offset location in frame buffer. + * In DOS, the physical and the logical address most likely are the same. + * Return: A valid address if success. + * NULL address if fail. + */ +void *getFrameBufPhysicalAddress(unsigned long offset /* Offset from base of physical frame buffer */); + +/* + * Get a pointer to the logical base address of video memory (or frame buffer). + * Software can only work with logical address. + * + * Return: A pointer to base of video memory. + * NULL pointer if fail. + */ +void *getFrameBufBase(void); + +/* + * Get the logical address of an offset location in frame buffer. + * Return: A valid address if success. + * NULL address if fail. + */ +void *getFrameBufAddress(unsigned long offset /*Offset from base of frame buffer*/); + +unsigned short getNumOfDevices(void); +long setCurrentDevice(unsigned short dev); +unsigned short getCurrentDevice(void); + +/* Video Memory read/write functions */ +unsigned char peekByte(unsigned long offset); +unsigned short peekWord(unsigned long offset); +unsigned int peekDWord(unsigned long offset); +void poke_4_Byte(unsigned long offset, unsigned char *buf); +void pokeByte(unsigned long offset, unsigned char value); +void pokeWord(unsigned long offset, unsigned short value); +void pokeDWord(unsigned long offset, unsigned long value); + + +/* + * This function uses strap pin to detect DDR size, and + * set up DDR controller accordingly. + */ +unsigned long setupMemController(void); + +#endif /* _HARDWARE_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi.c new file mode 100644 index 000000000000..52caf8518bc2 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi.c @@ -0,0 +1,1349 @@ +#include "ddk770_os.h" +#include "ddk770_reg.h" +#include "ddk770_power.h" +#include "ddk770_intr.h" +#include "ddk770_ddkdebug.h" +#include "ddk770_hwi2c.h" +#include "ddk770_hdmi_phy.h" +#include "ddk770_hdmi.h" +#include "ddk770_chip.h" +#include "ddk770_help.h" +#include +#include +#include "ddk770_hdmi_ddc.h" +#include "ddk770_hdmi_audio.h" +#include "ddk770_gpio.h" + + +static DEFINE_MUTEX(hdmi_mode_mutex); + +int g_if_scrambling_lowR_HDMI[3] = { 0, 0, 0}; +int g_scdc_present[3] = { 1, 1, 1}; + +/** + * Find first (least significant) bit set + * @param[in] data word to search + * @return bit position or 32 if none is set + */ +static inline u32 first_bit_set(u32 data) +{ + u32 n = 0; + + if (data != 0) { + for (n = 0; (data & 1) == 0; n++) { + data >>= 1; + } + } + return n; +} + +void ddk770_HDMI_Write_Register(hdmi_index index, u32 offset, u32 value) +{ + u32 baseAddr; + + baseAddr = BASE_HDMI0 + (HDMI_BASE_OFFSET * index); + + pokeRegisterDWord(baseAddr + (offset << 2), value); + return; +} + +u32 ddk770_HDMI_Read_Register(hdmi_index index, u32 offset) +{ + u32 baseAddr; + + baseAddr = BASE_HDMI0 + (HDMI_BASE_OFFSET * index); + + return peekRegisterDWord(baseAddr + (offset << 2)); +} + +void ddk770_HDMI_write_mask(hdmi_index index, u32 addr, u32 mask, u32 data) +{ + u32 temp = 0; + u32 shift = first_bit_set(mask); + + temp = ddk770_HDMI_Read_Register(index, addr); + temp &= ~(mask); + temp |= (mask & data << shift); + ddk770_HDMI_Write_Register(index, addr, temp); +} + +u32 ddk770_HDMI_read_mask(hdmi_index index, u32 addr, u32 mask) +{ + u32 shift = first_bit_set(mask); + return ((ddk770_HDMI_Read_Register(index, addr) & mask) >> shift); +} + + +//---------------------------------------------------------------------- +// Initial set +//------------------------------------ ---------------------------------- +static void ddk770_HDMI_TX_Common_Init( + hdmi_index index, u32 pixelClock, u32 freq) +{ + int data; + + //printk("Initial HDMI Setting begin\n"); + +#if 1 + audio_Initialize(index); + audio_Configure(index,pixelClock,freq); +#else + ddk770_HDMI_Write_Register(index, 0x1025, 0x20); + ddk770_HDMI_Write_Register(index, 0x1026, 0x33); // 24bit 48kHz + ddk770_HDMI_Write_Register(index, 0x3206, 0x02); + ddk770_HDMI_Write_Register(index, 0x3205, 0x13); // N = 3072 CTS = 222750 + ddk770_HDMI_Write_Register(index, 0x3204, 0xC6); + ddk770_HDMI_Write_Register(index, 0x3203, 0xCC); + ddk770_HDMI_Write_Register(index, 0x3202, 0x00); // ncts_atomic_write = 0 + ddk770_HDMI_Write_Register(index, 0x3201, 0x50); + ddk770_HDMI_Write_Register(index, 0x3200, 0x00); +#endif + + +#if 1 //for hdcp1.4 + // HDCP1.4 config + ddk770_HDMI_Write_Register(index, 0x5009, 0x1F); // a_vidpolcfg + ddk770_HDMI_Write_Register(index, 0x500a, 0x40); // a_oesswcfg + ddk770_HDMI_Write_Register(index, 0x5001, 0x04); // a_hdcpcfg1 + ddk770_HDMI_Write_Register(index, 0x5000, 0x33); // a_hdcpcfg0 + + // // HDCP14 registers control and status + ddk770_HDMI_Write_Register(index, 0x7904, 0x02); // hdcp14reg_ctrl + data = ddk770_HDMI_Read_Register(index, 0x7908); // hdcp14reg_sts + ddk770_HDMI_Write_Register(index, 0x7904, 0x03); // hdcp14reg_ctrl + data = ddk770_HDMI_Read_Register(index, 0x7908); // hdcp14reg_sts + ddk770_HDMI_Write_Register(index, 0x7904, 0x06); // hdcp14reg_ctrl + data = ddk770_HDMI_Read_Register(index, 0x7908); // hdcp14reg_sts + ddk770_HDMI_Write_Register(index, 0x7904, 0x00); // hdcp14reg_ctrl + data = ddk770_HDMI_Read_Register(index, 0x7908); // hdcp14reg_sts + +#else //forhdcp2.2 + // HDCP22 registers control and status + ddk770_HDMI_Write_Register(index, 0x7904, 0x06); // hdcp22reg_ctrl + data = ddk770_HDMI_Read_Register(index, 0x7908); // hdcp22reg_sts + ddk770_HDMI_Write_Register(index, 0x7904, 0x07); // hdcp22reg_ctrl + data = ddk770_HDMI_Read_Register(index, 0x7908); // hdcp22reg_sts + + + data = ddk770_HDMI_Read_Register(index, 0x7904); // hdcp22reg_sts + ddk770_HDMI_Write_Register(index, 0x1000, 0xF8); // hdcp22reg_ctrl + +#endif + +} + + +static void fc_video_PreambleFilter(hdmi_index index, u8 value, unsigned channel) +{ + + if (channel == 0) + ddk770_HDMI_Write_Register(index, (FC_CH0PREAM), value); + else if (channel == 1) + ddk770_HDMI_write_mask(index, FC_CH1PREAM, FC_CH1PREAM_CH1_PREAMBLE_FILTER_MASK, value); + else if (channel == 2) + ddk770_HDMI_write_mask(index, FC_CH2PREAM, FC_CH2PREAM_CH2_PREAMBLE_FILTER_MASK, value); + else + printk("invalid channel number: %d", channel); +} + + +static void fc_video_hdcp_keepout(hdmi_index index, u8 bit) +{ + + ddk770_HDMI_write_mask(index, FC_INVIDCONF, FC_INVIDCONF_HDCP_KEEPOUT_MASK, bit); +} + + +__attribute__((unused)) static void fc_video_DviOrHdmi(hdmi_index index, u8 bit) +{ + /* 1: HDMI; 0: DVI */ + ddk770_HDMI_write_mask(index, FC_INVIDCONF, FC_INVIDCONF_DVI_MODEZ_MASK, bit); +} + + + +//---------------------------------------------------------------------- +// Cfg HDMI frame composer setting +//---------------------------------------------------------------------- +static void ddk770_HDMI_TX_Common_CfgFrame( + hdmi_index index, + cea_parameter_t *cea_mode, + bool isHDMI +) +{ + gColorFormat colorFormat = COLOR_RGB; + u32 dataWr = 0x00; + + u32 vic = cea_mode->vic; + u32 h_active = cea_mode->h_active; + u32 h_blank = cea_mode->h_blank; + u32 hsync_delay = cea_mode->hsync_delay; + u32 hsync_width = cea_mode->hsync_width; + u32 v_active = cea_mode->v_active; + u32 v_blank = cea_mode->v_blank; + u32 vsync_delay = cea_mode->vsync_delay; + u32 vsync_width = cea_mode->vsync_width; + u8 de_polarity = cea_mode->de_polarity; + + u8 hsync_polarity = cea_mode->hsync_polarity; + u8 vsync_polarity = cea_mode->vsync_polarity; + // logic [19:0] freq, + u32 freq = cea_mode->freq; + u8 vblank_osc = cea_mode->vblank_osc; + u8 progressive_nI = cea_mode->progressive_nI; + int i; + + if (colorFormat == COLOR_YUV_420) + { + h_active = h_active / 2; + h_blank = h_blank / 2; + hsync_delay = hsync_delay / 2; + hsync_width = hsync_width / 2; + } + + dataWr = 0x00; + dataWr |= (1 << 7); ////Always due to HDCP and Scrambler + dataWr |= (vsync_polarity << 6); // v polarity low + dataWr |= (hsync_polarity << 5); // h polarity low + dataWr |= (de_polarity << 4); // de polarity high + dataWr |= ((isHDMI == 1 ? 1 : 0) << 3); // HDMI mode/DVI Mode + dataWr |= (vblank_osc << 1); + dataWr &= ~(progressive_nI << 0); + + //printk("HDMI Reg FC_INVIDCONF 0x1000 data=%x\n",dataWr); + + ddk770_HDMI_Write_Register(index, FC_INVIDCONF, dataWr); // fc_invidcon vsync_in_polarity[6] hsync_in_polarity[5] 0 Low de_in_polarity[4] 1 High + + fc_video_hdcp_keepout(index, 1); + + ddk770_HDMI_Write_Register(index, FC_INHACTIV1, h_active >> 8); // fc_inhactiv1 //picture width[13:8] + ddk770_HDMI_Write_Register(index, FC_INHACTIV0, h_active & 0xFF); // fc_inhactiv0 //picture width[7:0] + ddk770_HDMI_Write_Register(index, FC_INVACTIV1, v_active >> 8); // fc_invactiv1 //picture height[13:8] + ddk770_HDMI_Write_Register(index, FC_INVACTIV0, v_active & 0xFF); // fc_invactiv0 //picture height[7:0] + ddk770_HDMI_Write_Register(index, FC_INHBLANK1, h_blank >> 8); // fc_inhblank1 //H blanking[12:8] Between DE and DE + ddk770_HDMI_Write_Register(index, FC_INHBLANK0, h_blank & 0xFF); // fc_inhblank0 //H blanking[7:0] Between DE and DE + ddk770_HDMI_Write_Register(index, FC_INVBLANK, v_blank & 0xFF); // fc_invblank0 //V blanking[7:0] Between the last DE in a frame and the first DE of the next frame + ddk770_HDMI_Write_Register(index, FC_HSYNCINDELAY1, hsync_delay >> 8); // fc_hsyncindelay1 //Tail of DE to HSYNC[12:8] + ddk770_HDMI_Write_Register(index, FC_HSYNCINDELAY0, hsync_delay & 0xFF); // fc_hsyncindelay0 //Tail of DE to HSYNC[7:0] + ddk770_HDMI_Write_Register(index, FC_VSYNCINDELAY, vsync_delay & 0xFF); // fc_vsyncindelay0 //Tail of HSYNC to VSYNC[7:0] + ddk770_HDMI_Write_Register(index, FC_HSYNCINWIDTH1, hsync_width >> 8); // fc_hsyninwidth1 //Between HSYNC and HSYNC[9:8] + ddk770_HDMI_Write_Register(index, FC_HSYNCINWIDTH0, hsync_width & 0xFF); // fc_hsyninwidth0 //Between HSYNC and HSYNC[7:0] + ddk770_HDMI_Write_Register(index, FC_VSYNCINWIDTH, vsync_width & 0xFF); // fc_vsyninwidth0 //Between VSYNC and VSYNC[7:0] + ddk770_HDMI_Write_Register(index, FC_INFREQ0, freq & 0xFF); // fc_infreq0 0x100e & fc_infreq1 0x100f & fc_infreq2 0x1010 + ddk770_HDMI_Write_Register(index, FC_INFREQ1, (freq >> 8) & 0xFF); + ddk770_HDMI_Write_Register(index, FC_INFREQ2, (freq >> 16) & 0xF); + + ddk770_HDMI_Write_Register(index, FC_CTRLDUR, 12); + + ddk770_HDMI_Write_Register(index, FC_EXCTRLDUR, 32); + + ddk770_HDMI_Write_Register(index, FC_EXCTRLSPAC, 1); + + for (i = 0; i < 3; i++) + fc_video_PreambleFilter(index, (i + 1) * 11, i); + + + ddk770_HDMI_Write_Register(index, FC_AVIVID, vic); // vic + + + + switch (colorFormat) + { + case COLOR_RGB: + ddk770_HDMI_Write_Register(index, 0x200, 0x01); + break; + + case COLOR_YUV_444: + ddk770_HDMI_Write_Register(index, 0x200, 0x09); + break; + + case COLOR_YUV_422: + ddk770_HDMI_Write_Register(index, 0x200, 0x16); + + dataWr = ddk770_HDMI_Read_Register(index, 0x802); + dataWr |= (1 << 2); + ddk770_HDMI_Write_Register(index, 0x802, dataWr); + dataWr = ddk770_HDMI_Read_Register(index, 0x804); + dataWr |= (1 << 3) | (1 << 0); + ddk770_HDMI_Write_Register(index, 0x804, dataWr); + + break; + + case COLOR_YUV_420: + ddk770_HDMI_Write_Register(index, 0x200, 0x09); + break; + } + + +} + +long ddk770_HDMI_Intr_Mute(hdmi_index index, u32 mute) +{ + if(mute) + ddk770_HDMI_Write_Register(index, IH_MUTE, 0x3); + else + ddk770_HDMI_Write_Register(index, IH_MUTE, 0x0); + + return 0; +} + + +/* +Return value +0x1 : HPD=1 RX Sense=0 //Need to setmode +0x3 : HPD=1 RX Sense=1 //Need to setmode and notify OS +0x2 : HPD=0 RX Sense=1 //Nothing to do +0x0 : HPD=0 RX Sense=0 //Do plug out and notify OS + +*/ + +long ddk770_HDMI_HPD_Detect(hdmi_index index) +{ + u8 hpd, rxsense,value; + + hpd = phy_hot_plug_state(index); + rxsense = phy_rx_sense_state(index); + + value = rxsense << 1 | hpd; + + if(value == 0x02){ + usleep_range(200000,201000); + hpd = phy_hot_plug_state(index); + rxsense = phy_rx_sense_state(index); + value = rxsense << 1 | hpd; + } + return hpd; +} + +int ddk770_HDMI_Read_EDID_Basic(hdmi_index index, u8 *pEDIDBuffer, u32 bufferSize, u16* pReadSize) +{ + int error = 0; + + const u8 header[] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}; + + + //i2cddc_clk_config(index, 2500, I2C_MIN_SS_SCL_LOW_TIME, I2C_MIN_SS_SCL_HIGH_TIME, I2C_MIN_FS_SCL_LOW_TIME, I2C_MIN_FS_SCL_HIGH_TIME); + +#if 1 + //Reducing the HDMI IIC speed to 50khz to make the IIC more stable, just like DL + ddk770_HDMI_Write_Register(index,0x7e0c,0xD8); + ddk770_HDMI_Write_Register(index,0x7e0e,0xFE); + +#else + //Reducing the HDMI IIC speed to 25khz to make the IIC more stable, just like DL + ddk770_HDMI_Write_Register(index,0x7e0b,0x01); + ddk770_HDMI_Write_Register(index,0x7e0c,0xB0); + ddk770_HDMI_Write_Register(index,0x7e0d,0x01); + ddk770_HDMI_Write_Register(index,0x7e0e,0xFC); +#endif + + error = ddc_read(index, EDID_I2C_ADDR, EDID_I2C_SEGMENT_ADDR, 0, 0, bufferSize, pEDIDBuffer); + if(error){ + printk("EDID basic read failed\n"); + return error; + } + + error = memcmp(pEDIDBuffer, (u8 *) header, sizeof(header)); + if(error){ + printk("EDID header check failed\n"); + return error; + } + + error = _edid_checksum(pEDIDBuffer); + if(error){ + printk("EDID checksum failed\n"); + return error; + } + + *pReadSize += bufferSize; + + return 0; +} + +static int ddk770_HDMI_Read_EDID_Extension(hdmi_index index, u8 block, u8 *pEDIDBuffer, u32 bufferSize, u16* pReadSize) +{ + int error = 0; + + u8 start_pointer = block / 2; // pointer to segments of 256 bytes + u8 start_address = ((block % 2) * 0x80); //offset in segment; first block 0-127; second 128-255 + + pEDIDBuffer += (start_address + (start_pointer * 256)); + + error = ddc_read(index, EDID_I2C_ADDR, EDID_I2C_SEGMENT_ADDR, start_pointer, start_address, bufferSize, pEDIDBuffer); + if(error){ + printk("EDID extension read failed"); + return error; + } + + error = _edid_checksum(pEDIDBuffer); + if(error){ + printk("EDID checksum failed"); + return error; + } + + *pReadSize += bufferSize; + + return 0; +} + +static void ddk770_HDMI_Check_EDID_IIC_State(hdmi_index index) +{ + unsigned int gpioPin = peekRegisterDWord(GPIO_MUX); + + if (FIELD_VAL_GET(gpioPin, GPIO_MUX, I2C0) == GPIO_MUX_I2C0_ENABLE && + FIELD_VAL_GET(gpioPin, GPIO_MUX, I2C1) == GPIO_MUX_I2C1_ENABLE && + FIELD_VAL_GET(gpioPin, GPIO_MUX, I2C2) == GPIO_MUX_I2C2_ENABLE) + { + return; + } + else + { + ddk770_HDMI_Init(index); + } +} + +static int ddk770_HDMI_EDID_Block_Tag(const void *_block) +{ + const u8 *block = _block; + + return block[0]; +} + +static int ddk770_HDMI_EDID_Cea_Revision(const u8 *cea) +{ + /* + * FIXME is this correct for the DispID variant? + * The DispID spec doesn't really specify whether + * this is the revision of the CEA extension or + * the DispID CEA data block. And the only value + * given as an example is 0. + */ + return cea[1]; +} + +/* + * References: + * - CTA-861-H section 7.3.3 CTA Extension Version 3 + */ +static int ddk770_HDMI_EDID_Cea_Db_Collection_Size(const u8 *cta) +{ + u8 d = cta[2]; + + if (d < 4 || d > 127) + return 0; + + return d - 4; +} + +/* CTA-861-H section 7.4 CTA Data BLock Collection */ +struct cea_db { + u8 tag_length; + u8 data[]; +}; + +static int ddk770_HDMI_EDID_Cea_Db_tag(const struct cea_db *db) +{ + return db->tag_length >> 5; +} + +static int ddk770_HDMI_EDID_Cea_Db_Payload_Len(const void *_db) +{ + /* FIXME: Transition to passing struct cea_db * everywhere. */ + const struct cea_db *db = _db; + + return db->tag_length & 0x1f; +} + +static bool ddk770_HDMI_EDID_Cea_Db_Is_Extended_Tag(const struct cea_db *db, int tag) +{ + // cea_db_tag(db) == CTA_DB_EXTENDED_TAG == 7 + return ddk770_HDMI_EDID_Cea_Db_tag(db) == 7 && + ddk770_HDMI_EDID_Cea_Db_Payload_Len(db) >= 1 && + db->data[0] == tag; +} + +static bool ddk770_HDMI_EDID_Cea_Db_Is_Hdmi_Forum_Eeodb(const void *db) +{ + // CTA_EXT_DB_HF_EEODB == 0x78 + return ddk770_HDMI_EDID_Cea_Db_Is_Extended_Tag(db, 0x78) && + ddk770_HDMI_EDID_Cea_Db_Payload_Len(db) >= 2; +} + +/* + * Get the HF-EEODB override extension block count from EDID. + * + * The passed in EDID may be partially read, as long as it has at least two + * blocks (base block and one extension block) if EDID extension count is > 0. + * + * Note that this is *not* how you should parse CTA Data Blocks in general; this + * is only to handle partially read EDIDs. Normally, use the CTA Data Block + * iterators instead. + * + * References: + * - HDMI 2.1 section 10.3.6 HDMI Forum EDID Extension Override Data Block + */ +static int ddk770_HDMI_EDID_Hfeeodb_Block_Count(u8 *pEDIDBuffer) +{ + const u8 *cta; + + /* No extensions according to base block, no HF-EEODB. */ + if (!pEDIDBuffer[126]) + return 0; + + /* HF-EEODB is always in the first EDID extension block only */ + cta = &pEDIDBuffer[EDID_LENGTH]; + if (ddk770_HDMI_EDID_Block_Tag(cta) != 0x02 || ddk770_HDMI_EDID_Cea_Revision(cta) < 3) // CEA_EXT = 0x02 + return 0; + + /* Need to have the data block collection, and at least 3 bytes. */ + if (ddk770_HDMI_EDID_Cea_Db_Collection_Size(cta) < 3) + return 0; + + /* + * Sinks that include the HF-EEODB in their E-EDID shall include one and + * only one instance of the HF-EEODB in the E-EDID, occupying bytes 4 + * through 6 of Block 1 of the E-EDID. + */ + if (!ddk770_HDMI_EDID_Cea_Db_Is_Hdmi_Forum_Eeodb(&cta[4])) + return 0; + + return cta[4 + 2]; +} + +void ddk770_HDMI_set_SCDC(hdmi_index index, u8 *pEDIDBuffer) +{ + // Search for HF-VSDB if HDMI support scrambling under 340M TMDS Clk. + int i; + u8 scrambling_block_lowR; + u16 offset_block; + + scrambling_block_lowR = pEDIDBuffer[126] < 3 ? 1 : 2; + offset_block = scrambling_block_lowR * EDID_LENGTH; + g_if_scrambling_lowR_HDMI[index] = 0; + g_scdc_present[index] = 0; + for (i = 4; i < 4 + pEDIDBuffer[offset_block + 2];) { + int tag_code = pEDIDBuffer[offset_block + i] >> 5; + int length = pEDIDBuffer[offset_block + i] & 0x1F; + + // printk("i %x pEDIDBuffer[offset_block + i] %x tag_code %x length %x\n", i, pEDIDBuffer[offset_block + i], tag_code, length); + + // Check if the block is HF-VSDB (Vendor Specific Data Block with HDMI identifier) + /* + * All HDMI 2.0 monitors must support scrambling at rates > 340 MHz. + * And as per the spec, three factors confirm this: + * * Availability of a HF-VSDB block in EDID (check) + * * Non zero Max_TMDS_Char_Rate filed in HF-VSDB (let's check) + * * SCDC support available (let's check) + * Lets check it out. + */ + if (tag_code == 0x03 && length >= 6 && + pEDIDBuffer[offset_block + i + 1] == 0xD8 && + pEDIDBuffer[offset_block + i + 2] == 0x5D && + pEDIDBuffer[offset_block + i + 3] == 0xC4) { + int scdc_present = pEDIDBuffer[offset_block + i + 6] >> + 7; + if (scdc_present) + g_scdc_present[index] = 1; + if (pEDIDBuffer[offset_block + i + 5]) { + unsigned char byte_scramble = + pEDIDBuffer[offset_block + i + 6]; + if (g_scdc_present[index]) + g_if_scrambling_lowR_HDMI[index] = + byte_scramble & (0x1 << 3) ? 1 : + 0; + } + } + i += (length + 1); + } +} + +long ddk770_HDMI_Read_EDID(hdmi_index index, u8 *pEDIDBuffer, u16* bufferSize) +{ + + int ret = 0, edid_tries = 3; + int num_blocks = 0;//, invalid_blocks = 0; + int i; + *bufferSize = 0; + + g_scdc_present[index] = 1; + + ddk770_HDMI_Check_EDID_IIC_State(index); + + if(!ddk770_HDMI_HPD_Detect(index)) + { + //not plug-in + // memset(pEDIDBuffer, 0, *bufferSize); + return -1; + } + + //DelayMs(600); + do + { + + ret = ddk770_HDMI_Read_EDID_Basic(index, pEDIDBuffer, EDID_LENGTH, bufferSize); + if (ret) + { + ddk770_i2c_reset_busclear(index); + continue; + } + break; + } while (edid_tries--); + + if (ret) + { + return ret; + } + + num_blocks = pEDIDBuffer[126]; + + // 1 block per 128 bytes + if (num_blocks) + for (i = 0; i < num_blocks; i++) + { + edid_tries = 3; + do + { + ret = ddk770_HDMI_Read_EDID_Extension(index, i + 1, pEDIDBuffer, EDID_LENGTH, bufferSize); + if (ret) + { + ddk770_i2c_reset_busclear(index); + continue; + } + if (i == 0) + { + int eeodb = ddk770_HDMI_EDID_Hfeeodb_Block_Count(pEDIDBuffer); + + if (eeodb > num_blocks) + { + num_blocks = eeodb; + } + } + + break; + } while (edid_tries--); + } + + ddk770_HDMI_set_SCDC(index, pEDIDBuffer); + + + // Search for HF-VSDB if HDMI support scrambling under 340M TMDS Clk. + + // scrambling_block_lowR = pEDIDBuffer[126] < 3 ? 1 : 2; + // offset_block = scrambling_block_lowR * EDID_LENGTH; + // g_if_scrambling_lowR_HDMI[index] = 0; + // g_scdc_present[index] = 0; + // for (i = 4; i < 4 + pEDIDBuffer[offset_block + 2]; ) + // { + // int tag_code = pEDIDBuffer[offset_block + i] >> 5; + // int length = pEDIDBuffer[offset_block + i] & 0x1F; + + // // printk("i %x pEDIDBuffer[offset_block + i] %x tag_code %x length %x\n", i, pEDIDBuffer[offset_block + i], tag_code, length); + + // // Check if the block is HF-VSDB (Vendor Specific Data Block with HDMI identifier) + // /* + // * All HDMI 2.0 monitors must support scrambling at rates > 340 MHz. + // * And as per the spec, three factors confirm this: + // * * Availability of a HF-VSDB block in EDID (check) + // * * Non zero Max_TMDS_Char_Rate filed in HF-VSDB (let's check) + // * * SCDC support available (let's check) + // * Lets check it out. + // */ + // if (tag_code == 0x03 && length >= 6 && pEDIDBuffer[offset_block + i + 1] == 0xD8 && pEDIDBuffer[offset_block + i + 2] == 0x5D && pEDIDBuffer[offset_block + i + 3] == 0xC4) + // { + // int scdc_present = pEDIDBuffer[offset_block + i + 6] >> 7; + // if (scdc_present) + // g_scdc_present[index] = 1; + // if (pEDIDBuffer[offset_block + i + 5]) + // { + // unsigned char byte_scramble = pEDIDBuffer[offset_block + i + 6]; + // if (g_scdc_present[index]) + // g_if_scrambling_lowR_HDMI[index] = byte_scramble & (0x1 << 3) ? 1 : 0; + + // } + // } + // i += (length + 1); + // } + + return ret; +} + +void ddk770_HDMI_Set_Channel(hdmi_index index, disp_control_t dc) +{ + disp_output_t disp_index; + if (index == INDEX_HDMI0) + { + disp_index = HDMI0; + }else if (index == INDEX_HDMI1) + { + disp_index = HDMI1; + }else if (index == INDEX_HDMI2) + { + disp_index = HDMI2; + } else { + dbg_msg("invalid hdmi index\n"); + return; + } + + setDCMUX(disp_index, dc); +} + +void ddk770_HDMI_Clear_Channel(hdmi_index index) +{ + disp_output_t disp_index; + if (index == INDEX_HDMI0) + { + disp_index = HDMI0; + }else if (index == INDEX_HDMI1) + { + disp_index = HDMI1; + }else if (index == INDEX_HDMI2) + { + disp_index = HDMI2; + }else { + dbg_msg("invalid hdmi index\n"); + return; + } + + ClearDCMUX(disp_index); +} + +unsigned char ddk770_HDMI_Get_Channel(hdmi_index index) +{ + disp_output_t disp_index; + if (index == INDEX_HDMI0) + { + disp_index = HDMI0; + }else if (index == INDEX_HDMI1) + { + disp_index = HDMI1; + }else if (index == INDEX_HDMI2) + { + disp_index = HDMI2; + } else { + dbg_msg("invalid hdmi index\n"); + return 0; + } + + return GetDCMUX(disp_index); +} + +void ddk770_i2c_reset_busclear(hdmi_index index) +{ + i2c_reset(index); + i2c_bus_clear(index); + +} + + + +static void _EnableAvmute(hdmi_index index, u8 bit) +{ + ddk770_HDMI_write_mask(index, A_HDCPCFG0, A_HDCPCFG0_AVMUTE_MASK, bit); +} + +static void hdcp_av_mute(hdmi_index index, int enable) +{ + + _EnableAvmute(index, + (enable == 1) ? 1 : 0); +} + +static void packets_AvMute(hdmi_index index, u8 enable) +{ + + ddk770_HDMI_write_mask(index, FC_GCP, FC_GCP_SET_AVMUTE_MASK, (enable ? 1 : 0)); + ddk770_HDMI_write_mask(index, FC_GCP, FC_GCP_CLEAR_AVMUTE_MASK, (enable ? 0 : 1)); +} + +static void api_avmute(hdmi_index index, int enable) +{ + packets_AvMute(index, enable); + hdcp_av_mute(index, enable); +} + +static void fc_force_audio(hdmi_index index, u8 bit) +{ + ddk770_HDMI_write_mask(index, FC_DBGFORCE, FC_DBGFORCE_FORCEAUDIO_MASK, bit); +} + + +static void fc_force_video(hdmi_index index, u8 bit) +{ + + /* avoid glitches */ + if (bit != 0) { + ddk770_HDMI_Write_Register(index, FC_DBGTMDS2, 0x00); /* R */ + ddk770_HDMI_Write_Register(index, FC_DBGTMDS1, 0x00); /* G */ + ddk770_HDMI_Write_Register(index, FC_DBGTMDS0, 0xFF); /* B */ + ddk770_HDMI_write_mask(index, FC_DBGFORCE, FC_DBGFORCE_FORCEVIDEO_MASK, 1); + } else { + ddk770_HDMI_write_mask(index, FC_DBGFORCE, FC_DBGFORCE_FORCEVIDEO_MASK, 0); + ddk770_HDMI_Write_Register(index, FC_DBGTMDS2, 0x00); /* R */ + ddk770_HDMI_Write_Register(index, FC_DBGTMDS1, 0x00); /* G */ + ddk770_HDMI_Write_Register(index, FC_DBGTMDS0, 0x00); /* B */ + } +} + +static void fc_force_output(hdmi_index index, int enable) +{ + fc_force_audio(index, 0); + fc_force_video(index, (u8)enable); +} + + +static void mc_disable_all_clocks(hdmi_index index) +{ + ddk770_HDMI_Write_Register(index, MC_CLKDIS, 0xff); +} + +static void mc_enable_all_clocks(hdmi_index index) +{ + ddk770_HDMI_Write_Register(index, MC_CLKDIS, 0x00); +} + + + +int ddk770_HDMI_Standby(hdmi_index index) +{ + mc_disable_all_clocks(index); + phy_standby(index); + + return 1; +} + + + + + + +void ddk770_HDMI_Init(hdmi_index index) +{ + unsigned int gpioPin; + + //Set GPIO to HDMI I2C + gpioPin = peekRegisterDWord(GPIO_MUX); + + pokeRegisterDWord(GPIO_MUX, + FIELD_SET(gpioPin, GPIO_MUX, I2C2, ENABLE) | + FIELD_SET(gpioPin, GPIO_MUX, I2C1, ENABLE) | + FIELD_SET(gpioPin, GPIO_MUX, I2C0, ENABLE)); + + + irq_mask_all(index); //except PHY + + irq_hpd_sense_enable(index); + + //Always due to HDCP and Scrambler + fc_video_hdcp_keepout(index, 1); + + mc_disable_all_clocks(index); + + phy_initialize(index); + + ddk770_HDMI_Clear_Intr_State(index); + + // disable blue screen transmission after turning on all necessary blocks (e.g. HDCP) + fc_force_output(index, 1); + + // unmask interrupts.Can't enable interrupt. +// HDMI_Intr_Mute(index,0); + ddk770_HDMI_phy_interrupt_mask(index, PHY_MASK0_TX_PHY_LOCK_MASK| + PHY_MASK0_RX_SENSE_0_MASK | + PHY_MASK0_RX_SENSE_1_MASK | + PHY_MASK0_RX_SENSE_2_MASK | + PHY_MASK0_RX_SENSE_3_MASK); + ddk770_HDMI_phy_interrupt_unmask(index, PHY_MASK0_HPD_MASK); + + +} + + +long ddk770_HDMI_Set_Mode(hdmi_index index, logicalMode_t *pLogicalMode, mode_parameter_t *pModeParam, bool isHDMI) +{ + cea_parameter_t cea_mode = {0}; + u8 scdc_val; + long ret =0; + + ret = Get_CEA_Mode(pLogicalMode,&cea_mode, pModeParam, 0); + if(ret < 0) + { + return ret; + } + + mutex_lock(&hdmi_mode_mutex); + phy_standby(index); + api_avmute(index, 1); + ddk770_HDMI_Intr_Mute(index,1); + + printk("HDMI %d Set Mode\n",index); + + fc_force_output(index, 1); + + if (cea_mode.tmds_clk > 340000) + { + scdc_val = 0x1; + scdc_write(index, SCDC_SINK_VER, 1, &scdc_val); + scrambling(index, 1); + scdc_tmds_high_enable_flag(index, 1); + printk("Enabling Scrambling and Enable TMDS High.\n"); + } + else if (g_if_scrambling_lowR_HDMI[index]) + { //<340MHz, but has scrambling_lowR bit + scdc_val = 0x1; + scdc_write(index, SCDC_SINK_VER, 1, &scdc_val); + scrambling(index, 1); + scdc_tmds_high_enable_flag(index, 0); + printk("Enabling Scrambling and Disable TMDS High.\n"); + } + else if (g_scdc_present[index]) + { // <340MHz + scrambling(index, 0); + scdc_tmds_high_enable_flag(index, 0); + printk("Disable Scrambling.\n"); + }else{ + printk("Just Disable Scrambling on TX.\n"); + scrambling_Enable(index, 0); + } + + //Video + + ddk770_HDMI_TX_Common_CfgFrame(index,&cea_mode,isHDMI); + + //Audio and HDCP + + ddk770_HDMI_TX_Common_Init(index,cea_mode.tmds_clk, SAMPLE_RATE); + + //Enable All clocks + + mc_enable_all_clocks(index); + + usleep_range(10000,11000); + + //HDMI PHY Set + + ret = ddk770_HDMI_PHY_Set_Mode(index,cea_mode.tmds_clk); + + + // Disable blue screen transmission after turning on all necessary blocks (e.g. HDCP) + fc_force_output(index, 0); + + ddk770_HDMI_Intr_Mute(index,0); + api_avmute(index,0); + + mutex_unlock(&hdmi_mode_mutex); + return ret; + +} + + + + + +void ddk770_HDMI_Enable_Output(hdmi_index index) +{ + api_avmute(index,0); +} + +void ddk770_HDMI_Disable_Output(hdmi_index index) +{ + api_avmute(index,1); +} + + + +void ddk770_HDMI_Audio_Mute(hdmi_index index) +{ + fc_audio_mute(index); +} + + +void ddk770_HDMI_Audio_Unmute(hdmi_index index) +{ + fc_audio_unmute(index); +} + + + +//----------------------------------------------------------------------------- +// HDMI Interrupt functions +//----------------------------------------------------------------------------- +typedef struct _hdmi_interrupt_t +{ + struct _hdmi_interrupt_t *next; + void (*handler)(void); +} +hdmi_interrupt_t; + +static hdmi_interrupt_t *g_pHdmi0IntHandlers = ((hdmi_interrupt_t *)0); +static hdmi_interrupt_t *g_pHdmi1IntHandlers = ((hdmi_interrupt_t *)0); +static hdmi_interrupt_t *g_pHdmi2IntHandlers = ((hdmi_interrupt_t *)0); + + + +static void irq_clear_hpd_source(hdmi_index index) +{ + ddk770_HDMI_Write_Register(index, IH_PHY_STAT0,0xff); +} + + +void irq_mask_all(hdmi_index index) +{ + ddk770_HDMI_Intr_Mute(index,1); /* disable interrupts */ + + ddk770_HDMI_Write_Register(index, IH_MUTE_FC_STAT0, 0xff); + ddk770_HDMI_Write_Register(index, IH_MUTE_FC_STAT1, 0xff); + ddk770_HDMI_Write_Register(index, IH_MUTE_FC_STAT2, 0xff); + ddk770_HDMI_Write_Register(index, IH_MUTE_AS_STAT0, 0xff); + ddk770_HDMI_Write_Register(index, IH_MUTE_I2CM_STAT0, 0xff); + ddk770_HDMI_Write_Register(index, IH_MUTE_CEC_STAT0, 0xff); + ddk770_HDMI_Write_Register(index, IH_MUTE_VP_STAT0, 0xff); + ddk770_HDMI_Write_Register(index, IH_MUTE_I2CMPHY_STAT0, 0xff); + ddk770_HDMI_Write_Register(index, IH_MUTE_AHBDMAAUD_STAT0, 0xff); + ddk770_HDMI_Write_Register(index, IH_MUTE_PHY_STAT0, 0xff); +} + + + + + + +void ddk770_HDMI_Clear_Intr_State(hdmi_index index) +{ + + irq_clear_hpd_source(index); +} + + +/* HDMI Interrupt Service Routine */ +__attribute__((unused)) static void hdmi0ISR( + unsigned long status) +{ + hdmi_interrupt_t *pfnHandler; + u32 decode = 0; + u32 phy_decode = 0; + + + if (FIELD_VAL_GET(status, INT_STATUS, HDMI0) == INT_STATUS_HDMI0_ACTIVE) + { + decode = read_interrupt_decode(INDEX_HDMI0); + + if (decode_is_phy(decode)) + { + phy_decode = ddk770_HDMI_Read_Register(INDEX_HDMI0, IH_PHY_STAT0); + + if (decode_is_phy_hpd(phy_decode)) + { + // What we need to do in ISR + printk("We are in hdmi0 hpd ISR\n"); + + /* Walk all registered handlers for handlers that support this interrupt status */ + for (pfnHandler = g_pHdmi0IntHandlers; pfnHandler != ((hdmi_interrupt_t *)0); pfnHandler = pfnHandler->next) + pfnHandler->handler(); + + + phy_hot_plug_detected(INDEX_HDMI0); + } + } + /* Clear all the HDMI Interrupt */ + ddk770_HDMI_Clear_Intr_State(INDEX_HDMI0); + } + + +} + +/* HDMI Interrupt Service Routine */ +__attribute__((unused)) static void hdmi1ISR( + unsigned long status +) +{ + hdmi_interrupt_t *pfnHandler; + u32 decode = 0; + u32 phy_decode = 0; + + if (FIELD_VAL_GET(status, INT_STATUS, HDMI1) == INT_STATUS_HDMI1_ACTIVE) + { + decode = read_interrupt_decode(INDEX_HDMI1); + + if (decode_is_phy(decode)) + { + phy_decode = ddk770_HDMI_Read_Register(INDEX_HDMI1, IH_PHY_STAT0); + + if (decode_is_phy_hpd(phy_decode)) + { + // What we need to do in ISR + printk("We are in hdmi1 hpd ISR\n"); + + /* Walk all registered handlers for handlers that support this interrupt status */ + for (pfnHandler = g_pHdmi1IntHandlers; pfnHandler != ((hdmi_interrupt_t *)0); pfnHandler = pfnHandler->next) + pfnHandler->handler(); + + + phy_hot_plug_detected(INDEX_HDMI1); + } + } + /* Clear all the HDMI Interrupt */ + ddk770_HDMI_Clear_Intr_State(INDEX_HDMI1); + } + +} + + +/* HDMI Interrupt Service Routine */ +__attribute__((unused)) static void hdmi2ISR( + unsigned long status +) +{ + hdmi_interrupt_t *pfnHandler; + u32 decode = 0; + u32 phy_decode = 0; + + if (FIELD_VAL_GET(status, INT_STATUS, HDMI2) == INT_STATUS_HDMI2_ACTIVE) + { + decode = read_interrupt_decode(INDEX_HDMI2); + + if (decode_is_phy(decode)) + { + phy_decode = ddk770_HDMI_Read_Register(INDEX_HDMI2, IH_PHY_STAT0); + + if (decode_is_phy_hpd(phy_decode)) + { + // What we need to do in ISR + printk("We are in hdmi2 hpd ISR\n"); + + /* Walk all registered handlers for handlers that support this interrupt status */ + for (pfnHandler = g_pHdmi2IntHandlers; pfnHandler != ((hdmi_interrupt_t *)0); pfnHandler = pfnHandler->next) + pfnHandler->handler(); + + + phy_hot_plug_detected(INDEX_HDMI2); + } + } + /* Clear all the HDMI Interrupt */ + ddk770_HDMI_Clear_Intr_State(INDEX_HDMI2); + } + +} + + +int hdmiISR( + hdmi_index index) +{ + int intStatus; + u32 decode = 0; + u32 phy_decode = 0; + int ret = 0; + int bit_value = 0; + intStatus = peekRegisterDWord(INT_STATUS); + if(index == (hdmi_index)HDMI0) + bit_value = (intStatus >>11)&1; + else if(index == (hdmi_index)HDMI1) + bit_value = (intStatus >>13)&1; + else if(index == (hdmi_index)HDMI2) + bit_value = (intStatus >>15)&1; + if (bit_value == INT_STATUS_HDMI0_ACTIVE) + { + decode = read_interrupt_decode(index); + + if (decode_is_phy(decode)) + { + phy_decode = ddk770_HDMI_Read_Register(index, IH_PHY_STAT0); + + if (decode_is_phy_hpd(phy_decode)) + { + // What we need to do in ISR + printk("We are in hdmi%d hpd ISR\n",index); + ret = HDMI_INT_HPD; + phy_hot_plug_detected(index); + + }else + ret = HDMI_INT_NOT_HPD; + }else + ret = HDMI_INT_NOT_HPD; + /* Clear all the HDMI Interrupt */ + ddk770_HDMI_Clear_Intr_State(index); + } + return ret; + +} + + +void ddk770_HDMI_interrupt_enable(hdmi_index index, unsigned int enable) +{ + unsigned int value; + value = peekRegisterDWord(INT_MASK); + + if(enable) + { + ddk770_HDMI_Intr_Mute(index,0); + + if(index == INDEX_HDMI0) + value = FIELD_SET(value, INT_MASK, HDMI0, ENABLE); + else if(index == INDEX_HDMI1) + value = FIELD_SET(value, INT_MASK, HDMI1, ENABLE); + else + value = FIELD_SET(value, INT_MASK, HDMI2, ENABLE); + + pokeRegisterDWord(INT_MASK, value); + + + }else{ + ddk770_HDMI_Intr_Mute(index,1); + + if(index == INDEX_HDMI0) + value = FIELD_SET(value, INT_MASK, HDMI0, DISABLE); + else if(index == INDEX_HDMI1) + value = FIELD_SET(value, INT_MASK, HDMI1, DISABLE); + else + value = FIELD_SET(value, INT_MASK, HDMI2, DISABLE); + + pokeRegisterDWord(INT_MASK, value); + + } + + +} + +#if USE_I2C_ADAPTER +static int ddk770_hdmi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], + int num) +{ + struct smi_connector *connector = i2c_get_adapdata(adap); + int i, index; + int ret = 0; + u8 addr = msgs[0].addr; + + if (addr == DDC_CI_ADDR) + /* + * The internal I2C controller does not support the multi-byte + * read and write operations needed for DDC/CI. + * TOFIX: Blacklist the DDC/CI address until we filter out + * unsupported I2C operations. + */ + return -EOPNOTSUPP; + + for (i = 0; i < num; i++) { + if (msgs[i].len == 0) { + pr_info("unsupported transfer %d/%d, no data\n", i + 1, + num); + ret = -EOPNOTSUPP; + goto end; + } + } + + mutex_lock(&connector->i2c_lock); + connector->i2c_is_segment = false; + connector->i2c_is_regaddr = false; + connector->i2c_slave_number = 0; + + /* reset */ + if (connector->base.connector_type == DRM_MODE_CONNECTOR_HDMIA) { + index = 0; + } else if (connector->base.connector_type == DRM_MODE_CONNECTOR_HDMIB) { + index = 1; + } else if (connector->base.connector_type == DRM_MODE_CONNECTOR_DVID) { + index = 2; + } else { + pr_err("Unknown connector type\n"); + ret = -EMEDIUMTYPE; + goto end; + } + + ddk770_HDMI_Check_EDID_IIC_State(index); + if (!ddk770_HDMI_HPD_Detect(index)) { + ret = -ENODEV; + goto end; + } + /* Reducing the HDMI IIC speed to 50khz to make the IIC more stable, just like DL */ + ddk770_HDMI_Write_Register(index, 0x7e0c, 0xD8); + ddk770_HDMI_Write_Register(index, 0x7e0e, 0xFE); + + for (i = 0; i < num; i++) { + if (msgs[i].addr == EDID_I2C_SEGMENT_ADDR && msgs[i].len == 1) { + connector->i2c_is_segment = true; + connector->i2c_slave_number = (u8)*msgs[i].buf; + continue; + } + + if (msgs[i].flags & I2C_M_RD) { + if (!connector->i2c_is_regaddr) { + connector->i2c_slave_reg = 0x00; + connector->i2c_is_regaddr = true; + } + + if (connector->i2c_is_segment) { + ret = ddc_read(index, + EDID_I2C_ADDR, + EDID_I2C_SEGMENT_ADDR, + connector->i2c_slave_number, + connector->i2c_slave_reg, + msgs[i].len, msgs[i].buf); + if (ret) { + pr_err("ddc_read failed\n"); + goto end; + } + connector->i2c_slave_reg += msgs[i].len; + } else { + ret = ddc_read(index, + EDID_I2C_ADDR, 0, 0, + connector->i2c_slave_reg, + msgs[i].len, msgs[i].buf); + if (ret) { + pr_err("ddc_read failed\n"); + goto end; + } + connector->i2c_slave_reg += msgs[i].len; + } + connector->i2c_is_regaddr = false; + } else { + if (!connector->i2c_is_regaddr) { + /* Use the first write byte as register address */ + connector->i2c_slave_reg = msgs[i].buf[0]; + msgs[i].len--; + msgs[i].buf++; + connector->i2c_is_regaddr = true; + } + + connector->i2c_slave_reg += msgs[i].len; + } + } + ret = num; + mutex_unlock(&connector->i2c_lock); + + return ret; + +end: + mutex_unlock(&connector->i2c_lock); + return ret; +} + +static u32 ddk770_hdmi_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm ddk770_hdmi_i2c_algo = { + .master_xfer = ddk770_hdmi_i2c_xfer, + .functionality = ddk770_hdmi_i2c_func +}; + +long ddk770_HDMI_AdaptHWI2CInit(struct smi_connector *connector) +{ + int ret; + + mutex_init(&connector->i2c_lock); + + connector->adapter.owner = THIS_MODULE; + snprintf(connector->adapter.name, I2C_NAME_SIZE, "SMI HW I2C Bus"); + connector->adapter.dev.parent = connector->base.dev->dev; + i2c_set_adapdata(&connector->adapter, connector); + connector->adapter.algo = &ddk770_hdmi_i2c_algo; + ret = i2c_add_adapter(&connector->adapter); + if (ret) { + pr_err("HW i2c add adapter failed. %d\n", ret); + return -1; + } + + return 0; +} + +#endif \ No newline at end of file diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi.h new file mode 100644 index 000000000000..a3699da8a6d5 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi.h @@ -0,0 +1,101 @@ +#ifndef _DDK770_HDMI_H_ +#define _DDK770_HDMI_H_ + +#include "ddk770_mode.h" +#include "ddk770_display.h" +#include "../hw_com.h" +#include "../smi_drv.h" + +#define HDMI_BASE_OFFSET 0x20000 + +#define PHY_TIMEOUT 100 + +#define I2CM_OPERATION_READ 0x01 +#define I2CM_OPERATION_READ_EXT 0x02 +#define I2CM_OPERATION_READ_SEQ 0x04 +#define I2CM_OPERATION_READ_SEQ_EXT 0x08 +#define I2CM_OPERATION_WRITE 0x10 + +#define I2CDDC_TIMEOUT 10 + + +typedef enum { + COLOR_RGB, + COLOR_YUV_420, + COLOR_YUV_422, + COLOR_YUV_444 +} gColorFormat; + +typedef enum { + BASE_HDMI0 = 0x1a0000, + BASE_HDMI1 = 0x1c0000, + BASE_HDMI2 = 0x1e0000, + BASE_HDMI_PHY = 0x198000, + BASE_DC0 = 0x80000, + BASE_DC1 = 0x88000, + BASE_DC2 = 0x98000 +} hdmi_base_addr; + + +void ddk770_i2c_reset_busclear(hdmi_index index); + + + +void ddk770_HDMI_Write_Register(hdmi_index index, u32 offset, u32 value); +u32 ddk770_HDMI_Read_Register(hdmi_index index, u32 offset); +void ddk770_HDMI_Init(hdmi_index hdmi_index); + +long ddk770_HDMI_Set_Mode(hdmi_index index, logicalMode_t *pLogicalMode, mode_parameter_t *pModeParam, bool isHDMI); + +long ddk770_HDMI_HPD_Detect(hdmi_index index); +void ddk770_HDMI_set_SCDC(hdmi_index index, u8 *pEDIDBuffer); +long ddk770_HDMI_Read_EDID(hdmi_index index, u8 *pEDIDBuffer, u16* bufferSize); +int ddk770_HDMI_Read_EDID_Basic(hdmi_index index, u8 *pEDIDBuffer, u32 bufferSize, u16* pReadSize); + +void ddk770_HDMI_Set_Channel(hdmi_index index, disp_control_t dc); +void ddk770_HDMI_Clear_Channel(hdmi_index index); +unsigned char ddk770_HDMI_Get_Channel(hdmi_index index); +void ddk770_HDMI_Audio_I2S_Configure(hdmi_index index); +void ddk770_HDMI_Enable_Output(hdmi_index index); +void ddk770_HDMI_Disable_Output (hdmi_index index); +void hdmiHandler(void); +void ddk770_HDMI_Clear_Intr_State(hdmi_index index); +void irq_mask_all(hdmi_index index); + +void ddk770_HDMI_Audio_Unmute(hdmi_index index); +void ddk770_HDMI_Audio_Mute(hdmi_index index); + +/* + * This is the main interrupt hook for HDMI engine. + */ +long ddk770_hookHDMIInterrupt( + hdmi_index index, + void (*handler)(void) +); + + +/* + * This function un-register HDMI Interrupt handler. + */ +long ddk770_unhookHDMIInterrupt( + hdmi_index index, + void (*handler)(void) +); + +long ddk770_HDMI_Intr_Mute(hdmi_index index,u32 mute); + +u32 ddk770_HDMI_read_mask(hdmi_index index, u32 addr, u32 mask); +void ddk770_HDMI_write_mask(hdmi_index index, u32 addr, u32 mask, u32 data); + + + +void ddk770_HDMI_interrupt_enable(hdmi_index index, unsigned int enable); + + + +int ddk770_HDMI_Standby(hdmi_index index); +int hdmiISR(hdmi_index index); +long ddk770_HDMI_AdaptHWI2CInit(struct smi_connector *connector); + + +#endif /* _HDMI_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_audio.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_audio.c new file mode 100644 index 000000000000..69e6523bf750 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_audio.c @@ -0,0 +1,391 @@ +#include "ddk770_os.h" +#include "ddk770_reg.h" +#include "ddk770_hardware.h" +#include "ddk770_power.h" +#include "ddk770_ddkdebug.h" +#include "ddk770_hwi2c.h" +#include "ddk770_hdmi_phy.h" +#include "ddk770_hdmi.h" +#include "ddk770_chip.h" +#include +#include "ddk770_gpio.h" +#include "ddk770_hdmi_audio.h" + + +audio_n_computation_t n_values_48[] = { + {0, 6144}, + {25175, 6864}, + {25200, 6144}, + {27000, 6144}, + {27027, 6144}, + {54000, 6144}, + {54054, 6144}, + {74176,11648}, + {74250, 6144}, + {148352,5824}, + {148500, 6144}, + {296703,5824}, + {297000, 5120}, + {593410, 5824}, + {594000, 6144}, + {0, 0} +}; + + + +static u32 audio_ComputeN(u32 freq, u32 pixelClk) +{ + int i = 0; + u32 n = 0; + audio_n_computation_t *n_values = NULL; + int multiplier_factor = 1; + + if(u32_is_equal(freq, 64) || u32_is_equal(freq, 88) || u32_is_equal(freq, 96)){ + multiplier_factor = 2; + } + else if(u32_is_equal(freq, 128) || u32_is_equal(freq, 176) || u32_is_equal(freq, 192)){ + multiplier_factor = 4; + } + else if(u32_is_equal(freq, 256) || u32_is_equal(freq, 352) || u32_is_equal(freq, 384)){ + multiplier_factor = 8; + } + if(u32_is_equal(48, freq/multiplier_factor)){ + n_values = n_values_48; + } + + for(i = 0; n_values[i].n != 0; i++){ + if(u32_is_equal(pixelClk, n_values[i].pixel_clock)){ + n = n_values[i].n * multiplier_factor; + return n; + } + } + + n = n_values[0].n * multiplier_factor; + return n; +} + +static void _audio_clock_cts(hdmi_index index, u32 value) +{ + + if(value > 0){ + /* 19-bit width */ + ddk770_HDMI_write_mask(index, AUD_CTS3, AUD_CTS3_AUDCTS_MASK, (u8)(value >> 16)); + ddk770_HDMI_write_mask(index, AUD_CTS3, AUD_CTS3_CTS_MANUAL_MASK, 1); + ddk770_HDMI_Write_Register(index, AUD_CTS2, (u8)(value >> 8)); + ddk770_HDMI_Write_Register(index, AUD_CTS1, (u8)(value >> 0)); + } + else{ + /* Set to automatic generation of CTS values */ + ddk770_HDMI_write_mask(index, AUD_CTS3, AUD_CTS3_CTS_MANUAL_MASK, 0); + } +} + +static void _audio_clock_atomic(hdmi_index index, u8 value) +{ + + ddk770_HDMI_write_mask(index, AUD_N3, AUD_N3_NCTS_ATOMIC_WRITE_MASK, value); +} +static void _audio_clock_n(hdmi_index index, u32 value) +{ + + /* 19-bit width */ + ddk770_HDMI_write_mask(index, AUD_N3, AUD_N3_AUDN_MASK, (u8)(value >> 16)); + ddk770_HDMI_Write_Register(index, AUD_N2, (u8)(value >> 8)); + ddk770_HDMI_Write_Register(index, AUD_N1, (u8)(value >> 0)); + + + /* no shift */ + ddk770_HDMI_write_mask(index, AUD_CTS3, AUD_CTS3_N_SHIFT_MASK, 0); +} + +static void mc_audio_sampler_clock_enable(hdmi_index index, u8 bit) +{ + + ddk770_HDMI_write_mask(index, MC_CLKDIS, MC_CLKDIS_AUDCLK_DISABLE_MASK, bit); +} + +static void fc_sample_freq(hdmi_index index, u8 sf) +{ + + ddk770_HDMI_write_mask(index, FC_AUDICONF1, FC_AUDICONF1_SF_MASK, sf); +} + +static void fc_coding_type(hdmi_index index, u8 codingType) +{ + + ddk770_HDMI_write_mask(index, FC_AUDICONF0, FC_AUDICONF0_CT_MASK, codingType); +} + +static void fc_sampling_size(hdmi_index index, u8 ss) +{ + + ddk770_HDMI_write_mask(index, FC_AUDICONF1, FC_AUDICONF1_SS_MASK, ss); +} + +static void fc_audio_info_config(hdmi_index index, u32 freq) +{ + + u32 sampling_freq = freq; + + /* Audio InfoFrame sample frequency when OBA or DST */ + if (u32_is_equal(sampling_freq, 32)) + { + fc_sample_freq(index, 1); + } + else if (u32_is_equal(sampling_freq, 42)) + { + fc_sample_freq(index, 2); + } + else if (u32_is_equal(sampling_freq, 48)) + { + fc_sample_freq(index, 3); + printk("sample freq is 48\n"); + } + else if (u32_is_equal(sampling_freq, 88)) + { + fc_sample_freq(index, 4); + } + else if (u32_is_equal(sampling_freq, 96)) + { + fc_sample_freq(index, 5); + } + else if (u32_is_equal(sampling_freq, 176)) + { + fc_sample_freq(index, 6); + } + else if (u32_is_equal(sampling_freq, 192)) + { + fc_sample_freq(index, 7); + } + else + { + fc_sample_freq(index, 0); + } + + fc_coding_type(index, 0); /* for HDMI refer to stream header (0) */ + fc_sampling_size(index, 0); /* for HDMI refer to stream header (0) */ +} + +static void _audio_i2s_reset_fifo(hdmi_index index) +{ + + ddk770_HDMI_write_mask(index, AUD_CONF0, AUD_CONF0_SW_AUDIO_FIFO_RST_MASK, 1); +} + +static void _audio_i2s_reset(hdmi_index index) +{ + + ddk770_HDMI_write_mask(index, MC_SWRSTZREQ, MC_SWRSTZREQ_II2SSWRST_REQ_MASK, 0); +} + +static void _audio_i2s_data_enable(hdmi_index index, u8 value) +{ + + ddk770_HDMI_write_mask(index, AUD_CONF0, AUD_CONF0_I2S_IN_EN_MASK, value); +} + +static void _audio_i2s_data_mode(hdmi_index index, u8 value) +{ + + ddk770_HDMI_write_mask(index, AUD_CONF1, AUD_CONF1_I2S_MODE_MASK, value); +} + +static void _audio_i2s_data_width(hdmi_index index, u8 value) +{ + + ddk770_HDMI_write_mask(index, AUD_CONF1, AUD_CONF1_I2S_WIDTH_MASK, value); +} + +static void audio_i2s_select(hdmi_index index, u8 bit) +{ + + ddk770_HDMI_write_mask(index, AUD_CONF0, AUD_CONF0_I2S_SELECT_MASK, bit); +} + +static void audio_i2s_interrupt_mask(hdmi_index index, u8 value) +{ + + ddk770_HDMI_write_mask(index, AUD_INT, AUD_INT_FIFO_FULL_MASK_MASK | + AUD_INT_FIFO_EMPTY_MASK_MASK, value); +} + +static void audio_spdif_interrupt_mask(hdmi_index index, u8 value) +{ + ddk770_HDMI_write_mask(index, AUD_SPDIFINT, AUD_SPDIFINT_SPDIF_FIFO_FULL_MASK_MASK | + AUD_SPDIFINT_SPDIF_FIFO_EMPTY_MASK_MASK, value); +} + + + +static void fc_iec_clock_accuracy(hdmi_index index, u8 value) +{ + + ddk770_HDMI_write_mask(index, FC_AUDSCHNL7, FC_AUDSCHNL7_OIEC_CLKACCURACY_MASK, value); +} + +static void fc_iec_sampling_freq(hdmi_index index, u8 value) +{ + + ddk770_HDMI_write_mask(index, FC_AUDSCHNL7, FC_AUDSCHNL7_OIEC_SAMPFREQ_MASK, value); +} + +static void fc_iec_original_sampling_freq(hdmi_index index, u8 value) +{ + + ddk770_HDMI_write_mask(index, FC_AUDSCHNL8, FC_AUDSCHNL8_OIEC_ORIGSAMPFREQ_MASK, value); +} + + +static void fc_iec_word_length(hdmi_index index, u8 value) +{ + ddk770_HDMI_write_mask(index, FC_AUDSCHNL8, FC_AUDSCHNL8_OIEC_WORDLENGTH_MASK, value); +} + +static void fc_packet_layout(hdmi_index index, u8 bit) +{ + + ddk770_HDMI_write_mask(index, FC_AUDSCONF, FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK, bit); +} + + +static void fc_iec_channel_right(hdmi_index index, u8 value, unsigned channel) +{ + + if (channel == 0) + ddk770_HDMI_write_mask(index, FC_AUDSCHNL3, FC_AUDSCHNL3_OIEC_CHANNELNUMCR0_MASK, value); + else if (channel == 1) + ddk770_HDMI_write_mask(index, FC_AUDSCHNL3, FC_AUDSCHNL3_OIEC_CHANNELNUMCR1_MASK, value); + else if (channel == 2) + ddk770_HDMI_write_mask(index, FC_AUDSCHNL4, FC_AUDSCHNL4_OIEC_CHANNELNUMCR2_MASK, value); + else if (channel == 3) + ddk770_HDMI_write_mask(index, FC_AUDSCHNL4, FC_AUDSCHNL4_OIEC_CHANNELNUMCR3_MASK, value); + +} + +static void fc_iec_channel_left(hdmi_index index, u8 value, unsigned channel) +{ + + if (channel == 0) + ddk770_HDMI_write_mask(index, FC_AUDSCHNL5, FC_AUDSCHNL5_OIEC_CHANNELNUMCL0_MASK, value); + else if (channel == 1) + ddk770_HDMI_write_mask(index, FC_AUDSCHNL5, FC_AUDSCHNL5_OIEC_CHANNELNUMCL1_MASK, value); + else if (channel == 2) + ddk770_HDMI_write_mask(index, FC_AUDSCHNL6, FC_AUDSCHNL6_OIEC_CHANNELNUMCL2_MASK, value); + else if (channel == 3) + ddk770_HDMI_write_mask(index, FC_AUDSCHNL6, FC_AUDSCHNL6_OIEC_CHANNELNUMCL3_MASK, value); + +} + + + +static void _audio_clock_f(hdmi_index index, u8 value) +{ + + ddk770_HDMI_write_mask(index, AUD_INPUTCLKFS, AUD_INPUTCLKFS_IFSFACTOR_MASK, value); +} + + +static void fc_audio_config(hdmi_index index) +{ + int i = 0; + + fc_packet_layout(index, 0); /// More than 2 channels => layout 1 else layout 0 + + for (i = 0; i < 4; i++) { /* 0, 1, 2, 3 */ + fc_iec_channel_left(index, 2 * i + 1, i); /* 1, 3, 5, 7 */ + fc_iec_channel_right(index, 2 * (i + 1), i); /* 2, 4, 6, 8 */ + } + + fc_iec_clock_accuracy(index, 0); + + fc_iec_sampling_freq(index, 0x2); + + fc_iec_original_sampling_freq(index, 0xD); + + fc_iec_word_length(index, 0xB); //word width +} + + + + + +int audio_Initialize(hdmi_index index) +{ + + + // Mask all interrupts + audio_i2s_interrupt_mask(index, 0x3); + audio_spdif_interrupt_mask(index, 0x3); + + return 0; +} + + + + +void audio_Configure(hdmi_index index, u32 pixel_clock, u32 samplefreq) +{ + u32 n = 0; + + fc_audio_mute(index); + + // Configure Frame Composer audio parameters + fc_audio_config(index); + + audio_i2s_configure(index, SAMPLE_SIZE ); + //if set HDMI_AUD_INPUTCLKFS_128FS,TV does not have sound. + _audio_clock_f(index, 4); //HDMI_AUD_INPUTCLKFS_64FS; + + n = audio_ComputeN(samplefreq, pixel_clock); + + printk("Audio N=%d\n",n); + + mc_audio_sampler_clock_enable(index, 0); + + usleep_range(1000, 1100); + + _audio_clock_atomic(index, 1); + + _audio_clock_cts(index, 0); + + _audio_clock_n(index, n); + + fc_audio_unmute(index); + + // Configure audio info frame packets + fc_audio_info_config(index, samplefreq); + + +} + +void audio_i2s_configure(hdmi_index index, int sampleSize) +{ + audio_i2s_select(index, 1); + + _audio_i2s_data_enable(index, 0x1); // I2S_in_en[0] - I2Sdata[0] enable + + /* ATTENTION: fixed I2S data mode (standard) */ + _audio_i2s_data_mode(index, 0x0); + _audio_i2s_data_width(index, sampleSize); + audio_i2s_interrupt_mask(index, 3); + _audio_i2s_reset_fifo(index); + _audio_i2s_reset(index); +} + + + +void fc_audio_mute(hdmi_index index) +{ + ddk770_HDMI_write_mask(index, FC_AUDSCONF, FC_AUDSCONF_AUD_PACKET_SAMPFLT_MASK, 0xF); + _audio_i2s_data_enable(index, 0x0); +} + +void fc_audio_unmute(hdmi_index index) +{ + _audio_i2s_data_enable(index, 0x1); + ddk770_HDMI_write_mask(index, FC_AUDSCONF, FC_AUDSCONF_AUD_PACKET_SAMPFLT_MASK, 0x0); + +} + + + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_audio.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_audio.h new file mode 100644 index 000000000000..fd61633c3408 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_audio.h @@ -0,0 +1,22 @@ +#ifndef _DDK770_HDMI_AUDIO_H_ +#define _DDK770_HDMI_AUDIO_H_ + +#include "ddk770_mode.h" + +#define SAMPLE_RATE 48 +#define SAMPLE_SIZE 24 +#define WORD_LENGTH 24 + +typedef struct audio_n_computation { + u32 pixel_clock; + u32 n; +}audio_n_computation_t; + +int audio_Initialize(hdmi_index index); +void audio_Configure(hdmi_index index, u32 pixel_clock, u32 samplefreq); +void audio_i2s_configure(hdmi_index index, int sampleSize); + +void fc_audio_mute(hdmi_index index); +void fc_audio_unmute(hdmi_index index); + +#endif \ No newline at end of file diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_ddc.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_ddc.c new file mode 100644 index 000000000000..e7b906b12269 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_ddc.c @@ -0,0 +1,382 @@ +#include "ddk770_os.h" +#include "ddk770_reg.h" +#include "ddk770_hardware.h" +#include "ddk770_power.h" +#include "ddk770_ddkdebug.h" +#include "ddk770_hwi2c.h" +#include "ddk770_hdmi_phy.h" +#include "ddk770_hdmi.h" +#include "ddk770_chip.h" +#include +#include "ddk770_gpio.h" +#include "ddk770_hdmi_ddc.h" + + + +/** + * Find first (least significant) bit set + * @param[in] data word to search + * @return bit position or 32 if none is set + */ +static inline u32 first_bit_set(u32 data) +{ + u32 n = 0; + + if (data != 0) { + for (n = 0; (data & 1) == 0; n++) { + data >>= 1; + } + } + return n; +} + +/** + * Set bit field + * @param[in] data raw data + * @param[in] mask bit field mask + * @param[in] value new value + * @return new raw data + */ +static inline u32 set(u32 data, u32 mask, u32 value) +{ + return (((value << first_bit_set(mask)) & mask) | (data & ~mask)); +} + +/** + * calculate the fast sped high time counter - round up + */ +static u16 _scl_calc(u16 sfrClock, u16 sclMinTime) +{ + unsigned long tmp_scl_period = 0; + if (((sfrClock * sclMinTime) % I2C_DIV_FACTOR) != 0) { + tmp_scl_period = (unsigned long)((sfrClock * sclMinTime) + (I2C_DIV_FACTOR - ((sfrClock * sclMinTime) % I2C_DIV_FACTOR))) / I2C_DIV_FACTOR; + } + else { + tmp_scl_period = (unsigned long)(sfrClock * sclMinTime) / I2C_DIV_FACTOR; + } + return (u16)(tmp_scl_period); +} + + +int _edid_checksum(u8 * edid) +{ + int i, checksum = 0; + + for(i = 0; i < EDID_LENGTH; i++) + checksum += edid[i]; + + return checksum % 256; //CEA-861 Spec +} + + + + +static void _fast_speed_high_clk_ctrl(hdmi_index index, u16 value) +{ + + ddk770_HDMI_Write_Register(index, I2CM_FS_SCL_HCNT_1_ADDR, (u8) (value >> 8)); + ddk770_HDMI_Write_Register(index, I2CM_FS_SCL_HCNT_0_ADDR, (u8) (value >> 0)); +} + +static void _fast_speed_low_clk_ctrl(hdmi_index index, u16 value) +{ + + ddk770_HDMI_Write_Register(index, I2CM_FS_SCL_LCNT_1_ADDR, (u8) (value >> 8)); + ddk770_HDMI_Write_Register(index, I2CM_FS_SCL_LCNT_0_ADDR, (u8) (value >> 0)); +} + +static void _standard_speed_high_clk_ctrl(hdmi_index index, u16 value) +{ + + ddk770_HDMI_Write_Register(index, I2CM_SS_SCL_HCNT_1_ADDR, (u8) (value >> 8)); + ddk770_HDMI_Write_Register(index, I2CM_SS_SCL_HCNT_0_ADDR, (u8) (value >> 0)); +} + +static void _standard_speed_low_clk_ctrl(hdmi_index index, u16 value) +{ + + ddk770_HDMI_Write_Register(index, I2CM_SS_SCL_LCNT_1_ADDR, (u8) (value >> 8)); + ddk770_HDMI_Write_Register(index, I2CM_SS_SCL_LCNT_0_ADDR, (u8) (value >> 0)); +} + + + + +__attribute__((unused)) static void i2cddc_clk_config(hdmi_index index, u16 sfrClock, u16 ss_low_ckl, u16 ss_high_ckl, u16 fs_low_ckl, u16 fs_high_ckl) +{ + _standard_speed_low_clk_ctrl(index, _scl_calc(sfrClock, ss_low_ckl)); + _standard_speed_high_clk_ctrl(index, _scl_calc(sfrClock, ss_high_ckl)); + _fast_speed_low_clk_ctrl(index, _scl_calc(sfrClock, fs_low_ckl)); + _fast_speed_high_clk_ctrl(index, _scl_calc(sfrClock, fs_high_ckl)); +} + +int i2c_bus_clear(hdmi_index index) +{ + ddk770_HDMI_write_mask(index, I2CM_OPERATION, I2CM_OPERATION_BUSCLEAR_MASK, 1); + + return 0; +} + +int i2c_reset(hdmi_index index) +{ + ddk770_HDMI_write_mask(index, I2CM_SOFTRSTZ, I2CM_SOFTRSTZ_I2C_SOFTRSTZ_MASK, 1); + + return 0; +} + + +static int ddci2c_write(hdmi_index index, u8 i2cAddr, u8 addr, u8 data) +{ + int timeout = I2CDDC_TIMEOUT; + u32 status = 0; + + ddk770_HDMI_write_mask(index, I2CM_SLAVE, I2CM_SLAVE_SLAVEADDR_MASK, i2cAddr); + ddk770_HDMI_Write_Register(index, I2CM_ADDRESS, addr); + ddk770_HDMI_Write_Register(index, I2CM_DATAO, data); + ddk770_HDMI_Write_Register(index, I2CM_OPERATION, I2CM_OPERATION_WRITE); + do { + usleep_range(5000, 5100); + status = ddk770_HDMI_read_mask(index, IH_I2CM_STAT0, IH_I2CM_STAT0_I2CMASTERERROR_MASK | + IH_I2CM_STAT0_I2CMASTERDONE_MASK); + } while (status == 0 && (timeout--)); + + ddk770_HDMI_Write_Register(index, IH_I2CM_STAT0, status); //clear read status + + if(status & IH_I2CM_STAT0_I2CMASTERERROR_MASK){ + printk("error\n"); + return -1; + } + + if(status & IH_I2CM_STAT0_I2CMASTERDONE_MASK){ + return 0; + } + + return -1; + +} + +static int ddci2c_read8(hdmi_index index, u8 i2cAddr, u8 segment, u8 pointer, u32 addr, u8 * value) +{ + int timeout = I2CDDC_TIMEOUT; + u32 status = 0; + + ddk770_HDMI_write_mask(index, I2CM_SLAVE, I2CM_SLAVE_SLAVEADDR_MASK, i2cAddr); + ddk770_HDMI_Write_Register(index, I2CM_ADDRESS, addr); + ddk770_HDMI_Write_Register(index, I2CM_SEGADDR, segment); + ddk770_HDMI_Write_Register(index, I2CM_SEGPTR, pointer); + + if(pointer) + ddk770_HDMI_Write_Register(index, I2CM_OPERATION, I2CM_OPERATION_READ_SEQ_EXT); + else + ddk770_HDMI_Write_Register(index, I2CM_OPERATION, I2CM_OPERATION_READ_SEQ); + + do { + + usleep_range(5000, 5100); + status = ddk770_HDMI_read_mask(index, IH_I2CM_STAT0, IH_I2CM_STAT0_I2CMASTERERROR_MASK | + IH_I2CM_STAT0_I2CMASTERDONE_MASK); + } while (status == 0 && (timeout--)); + + ddk770_HDMI_Write_Register(index, IH_I2CM_STAT0, status); //clear read status + + if(status & IH_I2CM_STAT0_I2CMASTERERROR_MASK){ + printk("error\n"); + return -1; + } + + + if(status & IH_I2CM_STAT0_I2CMASTERDONE_MASK){ + int i = 0; + while(i < 8){ //read 8 bytes + value[i] = (u8) ddk770_HDMI_Read_Register(index, I2CM_READ_BUFF0 + i); + i +=1; + } + return 0; + } + + return -1; +} + + + +static int ddci2c_read(hdmi_index index, u8 i2cAddr, u8 segment, u8 pointer, u32 addr, u8 * value) +{ + int timeout = I2CDDC_TIMEOUT; + u32 status = 0; + + ddk770_HDMI_write_mask(index, I2CM_SLAVE, I2CM_SLAVE_SLAVEADDR_MASK, i2cAddr); + ddk770_HDMI_Write_Register(index, I2CM_ADDRESS, addr); + ddk770_HDMI_Write_Register(index, I2CM_SEGADDR, segment); + ddk770_HDMI_Write_Register(index, I2CM_SEGPTR, pointer); + + if(pointer) + ddk770_HDMI_Write_Register(index, I2CM_OPERATION, I2CM_OPERATION_READ_EXT); + else + ddk770_HDMI_Write_Register(index, I2CM_OPERATION, I2CM_OPERATION_READ); + + do { + + usleep_range(5000, 5100); + status = ddk770_HDMI_read_mask(index, IH_I2CM_STAT0, IH_I2CM_STAT0_I2CMASTERERROR_MASK | + IH_I2CM_STAT0_I2CMASTERDONE_MASK); + } while (status == 0 && (timeout--)); + + ddk770_HDMI_Write_Register(index, IH_I2CM_STAT0, status); //clear read status + + if(status & IH_I2CM_STAT0_I2CMASTERERROR_MASK){ + printk("error\n"); + return -1; + } + + if(status & IH_I2CM_STAT0_I2CMASTERDONE_MASK){ + *value = (u8) ddk770_HDMI_Read_Register(index, I2CM_DATAI); + return 0; + } + + return -1; +} + + +int ddc_write(hdmi_index index, u8 i2cAddr, u8 addr, u8 len, u8 * data) +{ + int i, status = 0; + + for(i = 0; i < len; i++){ + int tries = 3; + do { + + status = ddci2c_write(index, i2cAddr, addr, data[i]); + } while (status && tries--); + + if(status) //Error after 3 failed writes + return status; + } + return 0; +} + + +int ddc_read(hdmi_index index, u8 i2cAddr, u8 segment, u8 pointer, u8 addr, u32 len, u8 * data) +{ + int i, status = 0; + + for(i = 0; i < len;){ + int tries = 3; + + if ((len - i) >= 8){ + do { + status = ddci2c_read8(index, i2cAddr, segment, pointer, addr + i, &(data[i])); + } while (status && tries--); + + if(status) //Error after 3 failed writes + return status; + + i +=8; + } else { + + do { + status = ddci2c_read(index, i2cAddr, segment, pointer, addr + i, &(data[i])); + } while (status && tries--); + + if(status) //Error after 3 failed writes + return status; + + i++; + } + + } + + return 0; +} + + + +static int scdc_read(hdmi_index index, u8 address, u8 size, u8 * data) +{ + if(ddc_read(index, SCDC_SLAVE_ADDRESS, 0,0 , address, size, data)){ + return -1; + } + return 0; +} + +int scdc_write(hdmi_index index, u8 address, u8 size, u8 * data) +{ + if(ddc_write(index, SCDC_SLAVE_ADDRESS, address, size, data)){ + return -1; + } + return 0; +} + + +static int scdc_scrambling_enable_flag(hdmi_index index, u8 enable) +{ + u8 read_value = 0; + if(scdc_read(index, SCDC_TMDS_CONFIG, 1 , &read_value)){ + return -1; + } + read_value = set(read_value, 0x1, enable ? 0x1 : 0x0); + if(scdc_write(index, SCDC_TMDS_CONFIG, 1, &read_value)){ + return -1; + } + return 0; +} + +int scdc_scrambling_status(hdmi_index index) +{ + u8 read_value = 0; + if(scdc_read(index, SCDC_SCRAMBLER_STAT, 1, &read_value)){ + return 0; + } + return (read_value & 0x01); +} + + +int scdc_tmds_high_enable_flag(hdmi_index index, u8 enable) +{ + u8 read_value = 0; + if(scdc_read(index, SCDC_TMDS_CONFIG, 1 , &read_value)){ + return -1; + } + read_value = set(read_value, 0x2, enable ? 0x1 : 0x0); + if(scdc_write(index, SCDC_TMDS_CONFIG, 1, &read_value)){ + return -1; + } + return 0; +} + +void scrambling_Enable(hdmi_index index, unsigned int enable) +{ + ddk770_HDMI_write_mask(index, FC_SCRAMBLER_CTRL, FC_SCRAMBLER_CTRL_SCRAMBLER_ON_MASK, enable); +} + + +static void mc_tmds_clock_reset(hdmi_index index, unsigned char bit) +{ + + ddk770_HDMI_write_mask(index, MC_SWRSTZREQ, MC_SWRSTZREQ_TMDSSWRST_REQ_MASK, bit); +} + + +void scrambling(hdmi_index index, unsigned int enable){ + if (enable == 1) { + scdc_scrambling_enable_flag(index, 1); + usleep_range(100, 200); + + /* Start/stop HDCP keep-out window generation not needed because it's always on */ + /* TMDS software reset request */ + mc_tmds_clock_reset(index, 1); + + /* Enable/Disable Scrambling */ + scrambling_Enable(index, 1); + } else { + /* Enable/Disable Scrambling */ + scrambling_Enable(index, 0); + scdc_scrambling_enable_flag(index, 0); + + /* TMDS software reset request */ + mc_tmds_clock_reset(index, 0); + } +} + + + + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_ddc.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_ddc.h new file mode 100644 index 000000000000..fd222156950d --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_ddc.h @@ -0,0 +1,60 @@ +#ifndef _DDK770_HDMI_DDC_H_ +#define _DDK770_HDMI_DDC_H_ + +#include "ddk770_hdmi.h" + + +#define EDID_I2C_ADDR 0x50 +#define EDID_I2C_SEGMENT_ADDR 0x30 +#define DDC_CI_ADDR 0x37 +#define EDID_LENGTH 128 + + +#define I2C_DIV_FACTOR 100000 +#define I2C_MIN_FS_SCL_HIGH_TIME 61 //63 //75 +#define I2C_MIN_FS_SCL_LOW_TIME 132 //137 //163 +#define I2C_MIN_SS_SCL_HIGH_TIME 4592 //4737 //5625 +#define I2C_MIN_SS_SCL_LOW_TIME 5102 //5263 //6250 + +/* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */ +#define EDID_TIMING_ASPECT_SHIFT 6 +#define EDID_TIMING_ASPECT_MASK (0x3 << EDID_TIMING_ASPECT_SHIFT) + +/* need to add 60 */ +#define EDID_TIMING_VFREQ_SHIFT 0 +#define EDID_TIMING_VFREQ_MASK (0x3f << EDID_TIMING_VFREQ_SHIFT) + +#define DRM_EDID_PT_HSYNC_POSITIVE (1 << 1) +#define DRM_EDID_PT_VSYNC_POSITIVE (1 << 2) +#define DRM_EDID_PT_SEPARATE_SYNC (3 << 3) +#define DRM_EDID_PT_STEREO (1 << 5) +#define DRM_EDID_PT_INTERLACED (1 << 7) + +#define EDID_DETAIL_EST_TIMINGS 0xf7 +#define EDID_DETAIL_CVT_3BYTE 0xf8 +#define EDID_DETAIL_COLOR_MGMT_DATA 0xf9 +#define EDID_DETAIL_STD_MODES 0xfa +#define EDID_DETAIL_MONITOR_CPDATA 0xfb +#define EDID_DETAIL_MONITOR_NAME 0xfc +#define EDID_DETAIL_MONITOR_RANGE 0xfd +#define EDID_DETAIL_MONITOR_STRING 0xfe +#define EDID_DETAIL_MONITOR_SERIAL 0xff + +#define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8)) + + +int _edid_checksum(u8 * edid); +void scrambling(hdmi_index index, unsigned int enable); +void scrambling_Enable(hdmi_index index, unsigned int enable); +int scdc_tmds_high_enable_flag(hdmi_index index, u8 enable); +int scdc_scrambling_status(hdmi_index index); +int ddc_read(hdmi_index index, u8 i2cAddr, u8 segment, u8 pointer, u8 addr, u32 len, u8 * data); +int scdc_write(hdmi_index index, u8 address, u8 size, u8 * data); +int i2c_bus_clear(hdmi_index index); +int i2c_reset(hdmi_index index); +int ddc_write(hdmi_index index, u8 i2cAddr, u8 addr, u8 len, u8 * data); + + + +#endif + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_phy.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_phy.c new file mode 100644 index 000000000000..bd4ac8b38909 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_phy.c @@ -0,0 +1,1148 @@ +#include "ddk770_os.h" +#include "ddk770_reg.h" +#include "ddk770_hardware.h" +#include "ddk770_power.h" +#include "ddk770_ddkdebug.h" +#include "ddk770_hwi2c.h" +#include "ddk770_hdmi_phy.h" +#include "ddk770_hdmi.h" +#include +#include +#include + +static struct phy_config phy311[] = { + {13500, PIXEL_REPETITION_1, COLOR_DEPTH_8, HDMI_14, 0x0133, 0x0039, 0x0002, LT_1_485GBPS}, + {13500, PIXEL_REPETITION_1, COLOR_DEPTH_10, HDMI_14, 0x2173, 0x0039, 0x0002, LT_1_485GBPS}, + {13500, PIXEL_REPETITION_1, COLOR_DEPTH_12, HDMI_14, 0x41B3, 0x003D, 0x0002, LT_1_485GBPS}, + {13500, PIXEL_REPETITION_1, COLOR_DEPTH_16, HDMI_14, 0x6132, 0x0039, 0x0002, LT_1_485GBPS}, + {13500, PIXEL_REPETITION_3, COLOR_DEPTH_8, HDMI_14, 0x0132, 0x0039, 0x0002, LT_1_485GBPS}, + {13500, PIXEL_REPETITION_3, COLOR_DEPTH_10, HDMI_14, 0x2172, 0x0039, 0x0002, LT_1_485GBPS}, + {13500, PIXEL_REPETITION_3, COLOR_DEPTH_12, HDMI_14, 0x41B2, 0x003D, 0x0002, LT_1_485GBPS}, + {13500, PIXEL_REPETITION_3, COLOR_DEPTH_16, HDMI_14, 0x6131, 0x0039, 0x0002, LT_1_485GBPS}, + {13500, PIXEL_REPETITION_7, COLOR_DEPTH_8, HDMI_14, 0x0131, 0x0039, 0x0002, LT_1_485GBPS}, + {13500, PIXEL_REPETITION_7, COLOR_DEPTH_10, HDMI_14, 0x2171, 0x0039, 0x0002, LT_1_485GBPS}, + {13500, PIXEL_REPETITION_7, COLOR_DEPTH_12, HDMI_14, 0x41B1, 0x003D, 0x0002, LT_2_22GBPS}, + {13500, PIXEL_REPETITION_7, COLOR_DEPTH_16, HDMI_14, 0x6130, 0x0039, 0x0002, LT_2_22GBPS}, + {18000, PIXEL_REPETITION_2, COLOR_DEPTH_8, HDMI_14, 0x00F2, 0x0030, 0x0002, LT_1_485GBPS}, + {18000, PIXEL_REPETITION_2, COLOR_DEPTH_10, HDMI_14, 0x2162, 0x0039, 0x0002, LT_1_485GBPS}, + {18000, PIXEL_REPETITION_2, COLOR_DEPTH_12, HDMI_14, 0x41A2, 0x0039, 0x0002, LT_1_485GBPS}, + {18000, PIXEL_REPETITION_2, COLOR_DEPTH_16, HDMI_14, 0x60F1, 0x0030, 0x0002, LT_1_485GBPS}, + {18000, PIXEL_REPETITION_5, COLOR_DEPTH_8, HDMI_14, 0x00F1, 0x0030, 0x0002, LT_1_485GBPS}, + {18000, PIXEL_REPETITION_5, COLOR_DEPTH_10, HDMI_14, 0x2161, 0x0039, 0x0002, LT_1_485GBPS}, + {18000, PIXEL_REPETITION_5, COLOR_DEPTH_12, HDMI_14, 0x41A1, 0x0039, 0x0002, LT_2_22GBPS}, + {18000, PIXEL_REPETITION_5, COLOR_DEPTH_16, HDMI_14, 0x60F0, 0x0030, 0x0002, LT_2_22GBPS}, + {21600, PIXEL_REPETITION_4, COLOR_DEPTH_8, HDMI_14, 0x0151, 0x0030, 0x0002, LT_1_485GBPS}, + {21600, PIXEL_REPETITION_4, COLOR_DEPTH_12, HDMI_14, 0x4161, 0x0039, 0x0002, LT_2_22GBPS}, + {21600, PIXEL_REPETITION_4, COLOR_DEPTH_16, HDMI_14, 0x6150, 0x0030, 0x0002, LT_2_22GBPS}, + {21600, PIXEL_REPETITION_9, COLOR_DEPTH_8, HDMI_14, 0x0150, 0x0030, 0x0002, LT_2_22GBPS}, + {21600, PIXEL_REPETITION_9, COLOR_DEPTH_12, HDMI_14, 0x4160, 0x0039, 0x0002, LT_3_40GBPS}, + {21600, PIXEL_REPETITION_9, COLOR_DEPTH_16, HDMI_20, 0x7B70, 0x0031, 0x0003, GT_3_40GBPS}, + {24000, PIXEL_REPETITION_8, COLOR_DEPTH_8, HDMI_14, 0x00E0, 0x0028, 0x0002, LT_2_22GBPS}, + {24000, PIXEL_REPETITION_8, COLOR_DEPTH_16, HDMI_20, 0x7BA0, 0x0031, 0x0003, GT_3_40GBPS}, + {25175, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x00B3, 0x0028, 0x0002, LT_1_485GBPS}, + {25175, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x2153, 0x0030, 0x0002, LT_1_485GBPS}, + {25175, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x40F3, 0x0030, 0x0002, LT_1_485GBPS}, + {25175, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_14, 0x60B2, 0x0028, 0x0002, LT_1_485GBPS}, + {27000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x00B3, 0x0028, 0x0002, LT_1_485GBPS}, + {27000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x2153, 0x0030, 0x0002, LT_1_485GBPS}, + {27000, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x40F3, 0x0030, 0x0002, LT_1_485GBPS}, + {27000, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_14, 0x60B2, 0x0028, 0x0002, LT_1_485GBPS}, + {27000, PIXEL_REPETITION_1, COLOR_DEPTH_8, HDMI_14, 0x00B2, 0x0028, 0x0002, LT_1_485GBPS}, + {27000, PIXEL_REPETITION_1, COLOR_DEPTH_10, HDMI_14, 0x2152, 0x0030, 0x0002, LT_1_485GBPS}, + {27000, PIXEL_REPETITION_1, COLOR_DEPTH_12, HDMI_14, 0x40F2, 0x0030, 0x0002, LT_1_485GBPS}, + {27000, PIXEL_REPETITION_1, COLOR_DEPTH_16, HDMI_14, 0x60B1, 0x0028, 0x0002, LT_1_485GBPS}, + {27000, PIXEL_REPETITION_3, COLOR_DEPTH_8, HDMI_14, 0x00B1, 0x0028, 0x0002, LT_1_485GBPS}, + {27000, PIXEL_REPETITION_3, COLOR_DEPTH_10, HDMI_14, 0x2151, 0x0030, 0x0002, LT_1_485GBPS}, + {27000, PIXEL_REPETITION_3, COLOR_DEPTH_12, HDMI_14, 0x40F1, 0x0030, 0x0002, LT_2_22GBPS}, + {27000, PIXEL_REPETITION_3, COLOR_DEPTH_16, HDMI_14, 0x60B0, 0x0028, 0x0002, LT_2_22GBPS}, + {27000, PIXEL_REPETITION_7, COLOR_DEPTH_8, HDMI_14, 0x00B0, 0x0028, 0x0002, LT_2_22GBPS}, + {27000, PIXEL_REPETITION_7, COLOR_DEPTH_10, HDMI_14, 0x2150, 0x0030, 0x0002, LT_2_97GBPS}, + {27000, PIXEL_REPETITION_7, COLOR_DEPTH_12, HDMI_14, 0x40F0, 0x0030, 0x0002, LT_3_40GBPS}, + {27000, PIXEL_REPETITION_7, COLOR_DEPTH_16, HDMI_20, 0x7B30, 0x0031, 0x0003, GT_3_40GBPS}, + {31500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x00B3, 0x0028, 0x0002, LT_1_485GBPS}, + {33750, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x00B3, 0x0028, 0x0002, LT_1_485GBPS}, + {35500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x00B3, 0x0028, 0x0002, LT_1_485GBPS}, + {36000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x00B3, 0x0028, 0x0002, LT_1_485GBPS}, + {36000, PIXEL_REPETITION_2, COLOR_DEPTH_8, HDMI_14, 0x00A1, 0x0028, 0x0002, LT_1_485GBPS}, + {36000, PIXEL_REPETITION_2, COLOR_DEPTH_10, HDMI_14, 0x2165, 0x0039, 0x0002, LT_1_485GBPS}, + {36000, PIXEL_REPETITION_2, COLOR_DEPTH_12, HDMI_14, 0x40E1, 0x0028, 0x0002, LT_2_22GBPS}, + {36000, PIXEL_REPETITION_2, COLOR_DEPTH_16, HDMI_14, 0x60A0, 0x0028, 0x0002, LT_2_22GBPS}, + {36000, PIXEL_REPETITION_5, COLOR_DEPTH_8, HDMI_14, 0x00A0, 0x0028, 0x0002, LT_2_22GBPS}, + {36000, PIXEL_REPETITION_5, COLOR_DEPTH_10, HDMI_14, 0x2164, 0x0039, 0x0002, LT_2_97GBPS}, + {36000, PIXEL_REPETITION_5, COLOR_DEPTH_12, HDMI_14, 0x40E0, 0x0028, 0x0002, LT_3_40GBPS}, + {36000, PIXEL_REPETITION_5, COLOR_DEPTH_16, HDMI_20, 0x7AF0, 0x0031, 0x0003, GT_3_40GBPS}, + {40000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x00B3, 0x0028, 0x0002, LT_1_485GBPS}, + {43200, PIXEL_REPETITION_4, COLOR_DEPTH_8, HDMI_14, 0x0140, 0x001A, 0x0002, LT_2_22GBPS}, + {43200, PIXEL_REPETITION_4, COLOR_DEPTH_12, HDMI_14, 0x4164, 0x0039, 0x0002, LT_3_40GBPS}, + {43200, PIXEL_REPETITION_4, COLOR_DEPTH_16, HDMI_20, 0x7B50, 0x0031, 0x0003, GT_3_40GBPS}, + {44900, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x00B3, 0x0028, 0x0002, LT_1_485GBPS}, + {49500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {50000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {50350, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {50350, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x2142, 0x001A, 0x0002, LT_1_485GBPS}, + {50350, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x40A2, 0x0028, 0x0002, LT_1_485GBPS}, + {50350, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_14, 0x6071, 0x001A, 0x0002, LT_1_485GBPS}, + {54000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {54000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x2142, 0x001A, 0x0002, LT_1_485GBPS}, + {54000, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x40A2, 0x0028, 0x0002, LT_1_485GBPS}, + {54000, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_14, 0x6071, 0x001A, 0x0002, LT_1_485GBPS}, + {54000, PIXEL_REPETITION_1, COLOR_DEPTH_8, HDMI_14, 0x0071, 0x001A, 0x0002, LT_1_485GBPS}, + {54000, PIXEL_REPETITION_1, COLOR_DEPTH_10, HDMI_14, 0x2141, 0x001A, 0x0002, LT_1_485GBPS}, + {54000, PIXEL_REPETITION_1, COLOR_DEPTH_12, HDMI_14, 0x40A1, 0x0028, 0x0002, LT_2_22GBPS}, + {54000, PIXEL_REPETITION_1, COLOR_DEPTH_16, HDMI_14, 0x6070, 0x001A, 0x0002, LT_2_22GBPS}, + {54000, PIXEL_REPETITION_3, COLOR_DEPTH_8, HDMI_14, 0x0070, 0x001A, 0x0002, LT_2_22GBPS}, + {54000, PIXEL_REPETITION_3, COLOR_DEPTH_10, HDMI_14, 0x2140, 0x001A, 0x0002, LT_2_97GBPS}, + {54000, PIXEL_REPETITION_3, COLOR_DEPTH_12, HDMI_14, 0x40A0, 0x0028, 0x0002, LT_3_40GBPS}, + {54000, PIXEL_REPETITION_3, COLOR_DEPTH_16, HDMI_20, 0x7AB0, 0x0031, 0x0003, GT_3_40GBPS}, + {56250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {59400, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {59400, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x2142, 0x001A, 0x0002, LT_1_485GBPS}, + {59400, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x40A2, 0x0028, 0x0002, LT_1_485GBPS}, + {59400, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_14, 0x6071, 0x001A, 0x0002, LT_1_485GBPS}, + {65000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {68250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {71000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {72000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {72000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x2142, 0x001A, 0x0002, LT_1_485GBPS}, + {72000, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x4061, 0x0010, 0x0002, LT_1_485GBPS}, + {72000, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_14, 0x6071, 0x001A, 0x0002, LT_1_485GBPS}, + {72000, PIXEL_REPETITION_2, COLOR_DEPTH_8, HDMI_14, 0x0060, 0x0010, 0x0002, LT_2_22GBPS}, + {72000, PIXEL_REPETITION_2, COLOR_DEPTH_10, HDMI_14, 0x216C, 0x0039, 0x0002, LT_2_97GBPS}, + {72000, PIXEL_REPETITION_2, COLOR_DEPTH_12, HDMI_14, 0x40E4, 0x0028, 0x0002, LT_3_40GBPS}, + {72000, PIXEL_REPETITION_2, COLOR_DEPTH_16, HDMI_20, 0x7AA0, 0x0031, 0x0003, GT_3_40GBPS}, + {73250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {74250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {74250, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x2145, 0x001A, 0x0002, LT_1_485GBPS}, + {74250, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x4061, 0x0010, 0x0002, LT_1_485GBPS}, + {74250, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_14, 0x6071, 0x001A, 0x0002, LT_2_22GBPS}, + {75000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {78750, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {79500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {82500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {82500, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x2145, 0x001A, 0x0002, LT_1_485GBPS}, + {82500, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x4061, 0x0010, 0x0002, LT_1_485GBPS}, + {82500, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_14, 0x6071, 0x001A, 0x0002, LT_2_22GBPS}, + {83500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {85500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {88750, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {90000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0072, 0x001A, 0x0002, LT_1_485GBPS}, + {90000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x2145, 0x001A, 0x0002, LT_1_485GBPS}, + {90000, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x4061, 0x0010, 0x0002, LT_1_485GBPS}, + {90000, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_14, 0x6071, 0x001A, 0x0002, LT_2_22GBPS}, + {94500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {99000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {99000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x2145, 0x001A, 0x0002, LT_1_485GBPS}, + {99000, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x4061, 0x0010, 0x0002, LT_2_22GBPS}, + {99000, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_14, 0x6050, 0x000A, 0x0002, LT_2_22GBPS}, + {100700, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {100700, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x2145, 0x001A, 0x0002, LT_1_485GBPS}, + {100700, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x4061, 0x0010, 0x0002, LT_2_22GBPS}, + {100700, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_14, 0x6050, 0x000A, 0x0002, LT_2_22GBPS}, + {101000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {102250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {106500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {108000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {108000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x2145, 0x001A, 0x0002, LT_1_485GBPS}, + {108000, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x4061, 0x0010, 0x0002, LT_2_22GBPS}, + {108000, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_14, 0x6050, 0x000A, 0x0002, LT_2_22GBPS}, + {108000, PIXEL_REPETITION_1, COLOR_DEPTH_8, HDMI_14, 0x0050, 0x000A, 0x0002, LT_2_22GBPS}, + {108000, PIXEL_REPETITION_1, COLOR_DEPTH_10, HDMI_14, 0x2144, 0x001A, 0x0002, LT_2_97GBPS}, + {108000, PIXEL_REPETITION_1, COLOR_DEPTH_12, HDMI_14, 0x4060, 0x0010, 0x0002, LT_3_40GBPS}, + {108000, PIXEL_REPETITION_1, COLOR_DEPTH_16, HDMI_20, 0x7A70, 0x0029, 0x0003, GT_3_40GBPS}, + {115500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {117500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {118800, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {118800, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x2145, 0x001A, 0x0002, LT_2_22GBPS}, + {118800, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x4061, 0x0010, 0x0002, LT_2_22GBPS}, + {118800, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_14, 0x6050, 0x000A, 0x0002, LT_2_97GBPS}, + {119000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {121750, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {122500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {135000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {136750, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {140250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {144000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {144000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x2145, 0x001A, 0x0002, LT_2_22GBPS}, + {144000, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x4064, 0x0010, 0x0002, LT_2_22GBPS}, + {144000, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_14, 0x6050, 0x000A, 0x0002, LT_2_97GBPS}, + {146250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {148250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_1_485GBPS}, + {148500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_2_22GBPS}, + {148500, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x214C, 0x001A, 0x0002, LT_2_22GBPS}, + {148500, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x4064, 0x0010, 0x0002, LT_2_97GBPS}, + {148500, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_14, 0x6050, 0x000A, 0x0002, LT_3_40GBPS}, + {154000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_2_22GBPS}, + {156000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_2_22GBPS}, + {157000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_2_22GBPS}, + {157500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_2_22GBPS}, + {162000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_2_22GBPS}, + {165000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_2_22GBPS}, + {165000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x214C, 0x001A, 0x0002, LT_2_22GBPS}, + {165000, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x4064, 0x0010, 0x0002, LT_2_97GBPS}, + {165000, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_14, 0x6050, 0x000A, 0x0002, LT_3_40GBPS}, + {175500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_2_22GBPS}, + {179500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_2_22GBPS}, + {180000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_2_22GBPS}, + {180000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x214C, 0x001A, 0x0002, LT_2_97GBPS}, + {180000, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x4064, 0x0010, 0x0002, LT_2_97GBPS}, + {180000, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_20, 0x7A50, 0x0011, 0x0003, GT_3_40GBPS}, + {182750, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0051, 0x000A, 0x0002, LT_2_22GBPS}, + {185625, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_22GBPS}, + {185625, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x214C, 0x001A, 0x0002, LT_2_97GBPS}, + {185625, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x4064, 0x0010, 0x0002, LT_2_97GBPS}, + {185625, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_20, 0x7A50, 0x0011, 0x0003, GT_3_40GBPS}, + {187000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_22GBPS}, + {187250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_22GBPS}, + {189000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_22GBPS}, + {193250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_22GBPS}, + {198000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_22GBPS}, + {198000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x214C, 0x001A, 0x0002, LT_2_97GBPS}, + {198000, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x4064, 0x0010, 0x0002, LT_3_40GBPS}, + {198000, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_20, 0x7A50, 0x0011, 0x0003, GT_3_40GBPS}, + {202500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_22GBPS}, + {204750, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_22GBPS}, + {208000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_22GBPS}, + {214750, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_22GBPS}, + {216000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_22GBPS}, + {216000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x214C, 0x001A, 0x0002, LT_2_97GBPS}, + {216000, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_14, 0x4064, 0x0010, 0x0002, LT_3_40GBPS}, + {216000, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_20, 0x7A50, 0x0011, 0x0003, GT_3_40GBPS}, + {218250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_22GBPS}, + {229500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_97GBPS}, + {234000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_97GBPS}, + {237600, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_97GBPS}, + {237600, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_14, 0x214C, 0x001A, 0x0002, LT_3_40GBPS}, + {237600, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_20, 0x5A64, 0x0019, 0x0003, GT_3_40GBPS}, + {237600, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_20, 0x7A50, 0x0011, 0x0003, GT_3_40GBPS}, + {245250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_97GBPS}, + {245500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_97GBPS}, + {261000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_97GBPS}, + {268250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_97GBPS}, + {268500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_97GBPS}, + {281250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_97GBPS}, + {288000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_97GBPS}, + {288000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_20, 0x3B4C, 0x0031, 0x0003, GT_3_40GBPS}, + {288000, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_20, 0x5A64, 0x0019, 0x0003, GT_3_40GBPS}, + {288000, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_20, 0x7A50, 0x0011, 0x0003, GT_3_40GBPS}, + {297000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_3_40GBPS}, + {297000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_20, 0x3B4C, 0x0031, 0x0003, GT_3_40GBPS}, + {297000, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_20, 0x5A64, 0x0019, 0x0003, GT_3_40GBPS}, + {297000, PIXEL_REPETITION_OFF, COLOR_DEPTH_16, HDMI_20, 0x7A50, 0x0011, 0x0003, GT_3_40GBPS}, + {317000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_3_40GBPS}, + {330000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_3_40GBPS}, + {330000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_20, 0x3B4C, 0x0031, 0x0003, GT_3_40GBPS}, + {330000, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_20, 0x5A64, 0x0019, 0x0003, GT_3_40GBPS}, + {333250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_3_40GBPS}, + {340000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_3_40GBPS}, + {348500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_20, 0x1A40, 0x003f, 0x0003, GT_3_40GBPS}, + {356500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_20, 0x1A40, 0x003f, 0x0003, GT_3_40GBPS}, + {360000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_20, 0x1A40, 0x003f, 0x0003, GT_3_40GBPS}, + {360000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_20, 0x3B4C, 0x0031, 0x0003, GT_3_40GBPS}, + {360000, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_20, 0x5A64, 0x0019, 0x0003, GT_3_40GBPS}, + {371250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_20, 0x1A40, 0x003f, 0x0003, GT_3_40GBPS}, + {371250, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_20, 0x3B4C, 0x0031, 0x0003, GT_3_40GBPS}, + {371250, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_20, 0x5A64, 0x0019, 0x0003, GT_3_40GBPS}, + {281250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_14, 0x0040, 0x0001, 0x0002, LT_2_97GBPS}, + {396000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_20, 0x1A40, 0x003f, 0x0003, GT_3_40GBPS}, + {396000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_20, 0x3B4C, 0x0031, 0x0003, GT_3_40GBPS}, + {396000, PIXEL_REPETITION_OFF, COLOR_DEPTH_12, HDMI_20, 0x5A64, 0x0019, 0x0003, GT_3_40GBPS}, + {432000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_20, 0x1A40, 0x003f, 0x0003, GT_3_40GBPS}, + {432000, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_20, 0x3B4C, 0x0031, 0x0003, GT_3_40GBPS}, + {380500, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_20, 0x1A40, 0x003f, 0x0003, GT_3_40GBPS}, + {475200, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_20, 0x1A40, 0x003f, 0x0003, GT_3_40GBPS}, + {475200, PIXEL_REPETITION_OFF, COLOR_DEPTH_10, HDMI_20, 0x3B4C, 0x0031, 0x0003, GT_3_40GBPS}, + {495000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_20, 0x1A40, 0x003f, 0x0003, GT_3_40GBPS}, + {505250, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_20, 0x1A40, 0x003f, 0x0003, GT_3_40GBPS}, + {552750, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_20, 0x1A40, 0x003f, 0x0003, GT_3_40GBPS}, + {580000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_20, 0x1A40, 0x003f, 0x0003, GT_3_40GBPS}, + {594000, PIXEL_REPETITION_OFF, COLOR_DEPTH_8, HDMI_20, 0x1A40, 0x003f, 0x0003, GT_3_40GBPS}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +}; + +static int u32_fabs(int x) { + if (x < 0) { + return -x; + } + return x; +} + +u8 u32_is_equal(u32 a, u32 b){ + + return (u32_fabs((int)a-(int)b) < 5); + +} + + +void ddk770_HDMI_phy_i2c_slave_address(hdmi_index index, u8 value) +{ + + ddk770_HDMI_write_mask(index, PHY_I2CM_SLAVE, PHY_I2CM_SLAVE_SLAVEADDR_MASK, value); +} + +int ddk770_HDMI_phy_i2c_write(hdmi_index index, u8 addr, u16 data) +{ + int timeout = PHY_TIMEOUT; + u32 status = 0; + + //Set address + ddk770_HDMI_Write_Register(index, PHY_I2CM_ADDRESS, addr); // phy_i2cm_address (OPMODE_PLLCFG) + + //Set value + ddk770_HDMI_Write_Register(index, PHY_I2CM_DATAO_0, (u8) (data & 0xFF)); // phy_i2cm_datao_0 + ddk770_HDMI_Write_Register(index, PHY_I2CM_DATAO_1, (u8) ((data >> 8) & 0xFF)); // phy_i2cm_datao_1 + + + ddk770_HDMI_Write_Register(index, PHY_I2CM_OPERATION, PHY_I2CM_OPERATION_WR_MASK); // phy_i2cm_operation + + do { + usleep_range(10000, 11000); + status = ddk770_HDMI_read_mask(index, IH_I2CMPHY_STAT0, IH_I2CMPHY_STAT0_I2CMPHYERROR_MASK | + IH_I2CMPHY_STAT0_I2CMPHYDONE_MASK); + } while (status == 0 && (timeout--)); + + ddk770_HDMI_Write_Register(index, IH_I2CMPHY_STAT0, status); //clear read status + + if(status & IH_I2CMPHY_STAT0_I2CMPHYERROR_MASK){ + return -1; + } + + if(status & IH_I2CMPHY_STAT0_I2CMPHYDONE_MASK){ + return 0; + } + + return -1; +} + +int ddk770_HDMI_phy_i2c_read(hdmi_index index, u8 addr, u16 * value) +{ + int timeout = PHY_TIMEOUT; + u32 status = 0; + + //Set address + ddk770_HDMI_Write_Register(index, PHY_I2CM_ADDRESS, addr); + + ddk770_HDMI_Write_Register(index, PHY_I2CM_OPERATION, PHY_I2CM_OPERATION_RD_MASK); + + do { + usleep_range(10000, 11000); + status = ddk770_HDMI_read_mask(index, IH_I2CMPHY_STAT0, IH_I2CMPHY_STAT0_I2CMPHYERROR_MASK | + IH_I2CMPHY_STAT0_I2CMPHYDONE_MASK); + } while (status == 0 && (timeout--)); + + ddk770_HDMI_Write_Register(index, IH_I2CMPHY_STAT0, status); //clear read status + + if(status & IH_I2CMPHY_STAT0_I2CMPHYERROR_MASK){ + return -1; + } + + if(status & IH_I2CMPHY_STAT0_I2CMPHYDONE_MASK){ + + *value = ((u16) (ddk770_HDMI_Read_Register(index, (PHY_I2CM_DATAI_1)) << 8) + | ddk770_HDMI_Read_Register(index, (PHY_I2CM_DATAI_0))); + return 0; + } + + + return -1; +} + + + +static u32 phy_get_freq(u32 pClk) +{ + + if(((pClk >= 25175) && (pClk <= 25180)) || ((pClk >= 25195) && (pClk <= 25205))) + return 25175; + else if (((pClk >= 26995) && (pClk <= 27005)) || ((pClk >= 27022) && (pClk <= 27032))) + return 27000; + else if (u32_is_equal(pClk, 31500)) + return 31500; + else if (u32_is_equal(pClk, 33750)) + return 33750; + else if (u32_is_equal(pClk, 35500)) + return 35500; + else if (((pClk >= 35995) && (pClk <= 36005)) || ((pClk >= 36031) && (pClk <= 36041))) + return 36000; + else if (u32_is_equal(pClk, 40000)) + return 40000; + else if (u32_is_equal(pClk, 44900)) + return 44900; + else if (u32_is_equal(pClk, 49500)) + return 49500; + else if (u32_is_equal(pClk, 50000)) + return 50000; + else if (((pClk >= 50345) && (pClk <= 50355)) || ((pClk >= 50395) && (pClk <= 50405))) + return 50350; + else if (((pClk >= 53995) && (pClk <= 54005)) || ((pClk >= 50049) && (pClk <= 54059))) + return 54000; + else if (u32_is_equal(pClk, 56250)) + return 56250; + else if (((pClk >= 59336) && (pClk <= 59346)) || ((pClk >= 59395) && (pClk <= 59405))) + return 59400; + else if (u32_is_equal(pClk, 65000)) + return 65000; + else if (u32_is_equal(pClk, 68250)) + return 68250; + else if (u32_is_equal(pClk, 71000)) + return 71000; + else if (u32_is_equal(pClk, 72000)) + return 72000; + else if (u32_is_equal(pClk, 73250)) + return 73250; + else if (((pClk >= 74171) && (pClk <= 74181)) || ((pClk >= 74245) && (pClk <= 74255))) + return 74250; + else if (u32_is_equal(pClk, 75000)) + return 75000; + else if (u32_is_equal(pClk, 78750)) + return 78750; + else if (u32_is_equal(pClk, 79500)) + return 79500; + else if (((pClk >= 82143) && (pClk <= 82153)) || ((pClk >= 82495) && (pClk <= 82505))) + return 82500; + else if (u32_is_equal(pClk, 83500)) + return 83500; + else if (u32_is_equal(pClk, 85500)) + return 85500; + else if (u32_is_equal(pClk, 88750)) + return 88750; + else if (u32_is_equal(pClk, 90000)) + return 90000; + else if (u32_is_equal(pClk, 94500)) + return 94500; + else if (((pClk >= 98896) && (pClk <= 98906)) || ((pClk >= 98995) && (pClk <= 99005))) + return 99000; + else if (((pClk >= 100695) && (pClk <= 100705)) || ((pClk >= 100795) && (pClk <= 100805))) + return 100700; + else if (u32_is_equal(pClk, 101000)) + return 101000; + else if (u32_is_equal(pClk, 102250)) + return 102250; + else if (u32_is_equal(pClk, 106500)) + return 106500; + else if (((pClk >= 107995) && (pClk <= 108005)) || ((pClk >= 108103) && (pClk <= 108113))) + return 108000; + else if (u32_is_equal(pClk, 115500)) + return 115500; + else if (u32_is_equal(pClk, 117500)) + return 117500; + else if (((pClk >= 118795) && (pClk <= 118805)) || ((pClk >= 118677) && (pClk <= 118687))) + return 118800; + else if (u32_is_equal(pClk, 119000)) + return 119000; + else if (u32_is_equal(pClk, 121750)) + return 122500; + else if (u32_is_equal(pClk, 122500)) + return 121750; + else if (u32_is_equal(pClk, 135000)) + return 135000; + else if (u32_is_equal(pClk, 136750)) + return 136750; + else if (u32_is_equal(pClk, 140250)) + return 140250; + else if (u32_is_equal(pClk, 144000)) + return 144000; + else if (u32_is_equal(pClk, 146250)) + return 146250; + else if (u32_is_equal(pClk, 148250)) + return 148250; + else if (((pClk >= 148347) && (pClk <= 148357)) || ((pClk >= 148495) && (pClk <= 148505))) + return 148500; + else if (u32_is_equal(pClk, 154000)) + return 154000; + else if (u32_is_equal(pClk, 156000)) + return 156000; + else if (u32_is_equal(pClk, 157000)) + return 157000; + else if (u32_is_equal(pClk, 157500)) + return 157500; + else if (u32_is_equal(pClk, 162000)) + return 162000; + else if (((pClk >= 164830) && (pClk <= 164840)) || ((pClk >= 164995) && (pClk <= 165005))) + return 165000; + else if (u32_is_equal(pClk, 175500)) + return 175500; + else if (u32_is_equal(pClk, 179500)) + return 179500; + else if (u32_is_equal(pClk, 180000)) + return 180000; + else if (u32_is_equal(pClk, 182750)) + return 182750; + else if (((pClk >= 185435) && (pClk <= 185445)) || ((pClk >= 185620) && (pClk <= 185630))) + return 185625; + else if (u32_is_equal(pClk, 187000)) + return 187000; + else if (u32_is_equal(pClk, 187250)) + return 187250; + else if (u32_is_equal(pClk, 189000)) + return 189000; + else if (u32_is_equal(pClk, 193250)) + return 193250; + else if (((pClk >= 197797) && (pClk <= 197807)) || ((pClk >= 197995) && (pClk <= 198005))) + return 198000; + else if (u32_is_equal(pClk, 202500)) + return 202500; + else if (u32_is_equal(pClk, 204750)) + return 204750; + else if (u32_is_equal(pClk, 208000)) + return 208000; + else if (u32_is_equal(pClk, 214750)) + return 214750; + else if (((pClk >= 216211) && (pClk <= 216221)) || ((pClk >= 215995) && (pClk <= 216005))) + return 216000; + else if (u32_is_equal(pClk, 218250)) + return 218250; + else if (u32_is_equal(pClk, 229500)) + return 229500; + else if (u32_is_equal(pClk, 234000)) + return 234000; + else if (((pClk >= 237359) && (pClk <= 237369)) || ((pClk >= 237595) && (pClk <= 237605))) + return 237600; + else if (u32_is_equal(pClk, 245250)) + return 245250; + else if (u32_is_equal(pClk, 245500)) + return 245500; + else if (u32_is_equal(pClk, 261000)) + return 261000; + else if (u32_is_equal(pClk, 268250)) + return 268250; + else if (u32_is_equal(pClk, 268500)) + return 268500; + else if (u32_is_equal(pClk, 281250)) + return 281250; + else if (u32_is_equal(pClk, 288000)) + return 288000; + else if (((pClk >= 296698) && (pClk <= 296708)) || ((pClk >= 296995) && (pClk <= 297005))) + return 297000; + else if (u32_is_equal(pClk, 317000)) + return 317000; + else if (u32_is_equal(pClk, 330000)) + return 330000; + else if (u32_is_equal(pClk, 333250)) + return 333250; + else if (((pClk >= 339655) && (pClk <= 339665)) || ((pClk >= 339995) && (pClk <= 340005))) + return 340000; + else if (u32_is_equal(pClk, 348500)) + return 348500; + else if (u32_is_equal(pClk, 356500)) + return 356500; + else if (u32_is_equal(pClk, 360000)) + return 360000; + else if (((pClk >= 370874) && (pClk <= 370884)) || ((pClk >= 371245) && (pClk <= 371255))) + return 371250; + else if (u32_is_equal(pClk, 380500)) + return 380500; + else if (((pClk >= 395599) && (pClk <= 395609)) || ((pClk >= 395995) && (pClk <= 396005))) + return 396000; + else if (((pClk >= 431952) && (pClk <= 431967)) || ((pClk >= 431995) && (pClk <= 432005)) || ((pClk >= 432427) && (pClk <= 432437))) + return 432000; + else if (u32_is_equal(pClk, 443250)) + return 443250; + else if (((pClk >= 475148) && (pClk <= 475158)) || ((pClk >= 475195) && (pClk <= 475205)) || ((pClk >= 474723) && (pClk <= 474733))) + return 475200; + else if (((pClk >= 494500) && (pClk <= 494510)) || ((pClk >= 494995) && (pClk <= 495005))) + return 495000; + else if (u32_is_equal(pClk, 505250)) + return 505250; + else if (u32_is_equal(pClk, 552750)) + return 552750; + else if (((pClk >= 579995) && (pClk <= 580005)) || ((pClk >= 579403) && (pClk <= 579413))) + return 580000; + else if (((pClk >= 593995) && (pClk <= 594005)) || ((pClk >= 593403) && (pClk <= 593413))) + return 594000; + + //If it is not matched, the loan is required + + else if ((pClk >= 345500) && (pClk <= 600000)) + return 594000; + else if ((pClk >= 183000) && (pClk < 345500)) + return 297000; + else if ((pClk >= 92000) && (pClk < 183000)) + { + return 148500; + } + else if ((pClk >= 45000) && (pClk < 92000)) + return 85500; + else if ((pClk >= 15000) && (pClk < 45000)) + return 36000; + + else{ + printk("Unable to map input pixel clock frequency %dMHz\n", pClk); + } + return 1000; + +} + +void ddk770_HDMI_phy_interrupt_mask(hdmi_index index, u8 mask) +{ + // Mask will determine which bits will be enabled + ddk770_HDMI_write_mask(index, PHY_MASK0, mask, 0xff); +} + +void ddk770_HDMI_phy_interrupt_unmask(hdmi_index index, u8 mask) +{ + // Mask will determine which bits will be enabled + ddk770_HDMI_write_mask(index, PHY_MASK0, mask, 0x0); +} + +static int phy_interrupt_enable(hdmi_index index, u8 value) +{ + + ddk770_HDMI_Write_Register(index, PHY_MASK0, value); + return 1; +} + +__attribute__((unused)) static void ddk770_HDMI_phy_disable(hdmi_index index) +{ + + ddk770_HDMI_Write_Register(index, 0x3000, 0x32); +} + + +static void _power_down(hdmi_index index, u8 bit) +{ + + ddk770_HDMI_write_mask(index, PHY_CONF0, PHY_CONF0_SPARES_2_MASK, (bit ? 1 : 0)); +} + + +static void phy_enable_hpd_sense(hdmi_index index, u8 bit) +{ + + ddk770_HDMI_write_mask(index, PHY_CONF0, PHY_CONF0_ENHPDRXSENSE_MASK, (bit ? 1 : 0)); +} + + +static void _enable_tmds(hdmi_index index, u8 bit) +{ + + + ddk770_HDMI_write_mask(index, PHY_CONF0, PHY_CONF0_SPARES_1_MASK, (bit ? 1 : 0)); +} + +static void _set_pddq(hdmi_index index, u8 bit) +{ + + ddk770_HDMI_write_mask(index, PHY_CONF0, PHY_CONF0_PDDQ_MASK, (bit ? 1 : 0)); +} + +static void _tx_power_on(hdmi_index index, u8 bit) +{ + + ddk770_HDMI_write_mask(index, PHY_CONF0, PHY_CONF0_TXPWRON_MASK, (bit ? 1 : 0)); +} + + +static void _data_enable_polarity(hdmi_index index, u8 bit) +{ + + ddk770_HDMI_write_mask(index, PHY_CONF0, PHY_CONF0_SELDATAENPOL_MASK, (bit ? 1 : 0)); +} + +static void _interface_control(hdmi_index index, u8 bit) +{ + + ddk770_HDMI_write_mask(index, PHY_CONF0, PHY_CONF0_SELDIPIF_MASK, (bit ? 1 : 0)); +} + +static void phy_i2c_mask_interrupts(hdmi_index index, int mask) +{ + + ddk770_HDMI_write_mask(index, PHY_I2CM_INT, PHY_I2CM_INT_DONE_MASK_MASK, mask ? 1 : 0); + ddk770_HDMI_write_mask(index, PHY_I2CM_CTLINT, PHY_I2CM_CTLINT_ARBITRATION_MASK_MASK, mask ? 1 : 0); + ddk770_HDMI_write_mask(index, PHY_I2CM_CTLINT, PHY_I2CM_CTLINT_NACK_MASK_MASK, mask ? 1 : 0); +} + + +static void phy_interrupt_unmask_bit(hdmi_index index,unsigned char bit_mask) +{ + + ddk770_HDMI_write_mask(index, IH_MUTE_PHY_STAT0, bit_mask, 0); +} + + + +void irq_hpd_sense_enable(hdmi_index index) +{ + u32 mask; + + /* Set i2cddc to standard mode */ + ddk770_HDMI_write_mask(index, I2CM_DIV, I2CM_DIV_FAST_STD_MODE_MASK, 0); + + + // Enable HDMI TX PHY HPD Detector + phy_enable_hpd_sense(index, 1); + + // Un-mask the HPD sense + mask = IH_MUTE_PHY_STAT0_HPD_MASK; +#if 0 + mask |= IH_MUTE_PHY_STAT0_RX_SENSE_0_MASK; + mask |= IH_MUTE_PHY_STAT0_RX_SENSE_1_MASK; + mask |= IH_MUTE_PHY_STAT0_RX_SENSE_2_MASK; + mask |= IH_MUTE_PHY_STAT0_RX_SENSE_3_MASK; +#endif + phy_interrupt_unmask_bit(index, mask); + + + // Un-mask the PHY_mask register - hpd bit + mask = PHY_MASK0_HPD_MASK; +#if 0 + mask |= PHY_MASK0_RX_SENSE_0_MASK; + mask |= PHY_MASK0_RX_SENSE_1_MASK; + mask |= PHY_MASK0_RX_SENSE_2_MASK; + mask |= PHY_MASK0_RX_SENSE_3_MASK; +#endif + phy_interrupt_enable(index, ~mask); + + // Un-mask main interrupt + // ddk770_HDMI_Intr_Mute(index,0); +} + + +int phy_hot_plug_detected(hdmi_index index) +{ + /* MASK STATUS POLARITY INTERRUPT HPD + * 0 0 0 1 0 + * 0 1 0 0 1 + * 0 0 1 0 0 + * 0 1 1 1 1 + * 1 x x 0 x + */ + + int hpd_polarity = ddk770_HDMI_read_mask(index, PHY_POL0, PHY_POL0_HPD_MASK); + int hpd = ddk770_HDMI_read_mask(index, PHY_STAT0, PHY_STAT0_HPD_MASK); + + // Mask interrupt + ddk770_HDMI_phy_interrupt_mask(index, PHY_MASK0_HPD_MASK); + + if (hpd_polarity == hpd) { + ddk770_HDMI_write_mask(index, PHY_POL0, PHY_POL0_HPD_MASK, !hpd_polarity); + + // Un-mask interrupts + ddk770_HDMI_write_mask(index, PHY_MASK0, PHY_MASK0_HPD_MASK, 0x0); + + return hpd_polarity; + } + + // Un-mask interrupts + ddk770_HDMI_write_mask(index, PHY_MASK0, PHY_MASK0_HPD_MASK, 0x0); + + return !hpd_polarity; +} + + +__attribute__((unused)) static int phy_rx_s0_detected(hdmi_index index) +{ + /* MASK STATUS POLARITY INTERRUPT RxS + * 0 0 0 1 0 + * 0 1 0 0 1 + * 0 0 1 0 0 + * 0 1 1 1 1 + * 1 x x 0 x + */ + + int RxS_polarity = ddk770_HDMI_read_mask(index, PHY_POL0, PHY_POL0_RX_SENSE_0_MASK); + int RxS = ddk770_HDMI_read_mask(index, PHY_STAT0, PHY_STAT0_RX_SENSE_0_MASK); + + // Mask interrupt + ddk770_HDMI_phy_interrupt_mask(index, PHY_MASK0_RX_SENSE_0_MASK); + + if (RxS_polarity == RxS) { + ddk770_HDMI_write_mask(index, PHY_POL0, PHY_POL0_RX_SENSE_0_MASK, !RxS_polarity); + + // Un-mask interrupts + ddk770_HDMI_phy_interrupt_unmask(index, PHY_MASK0_RX_SENSE_0_MASK); + + return RxS_polarity; + } + + // Un-mask interrupts + ddk770_HDMI_phy_interrupt_unmask(index, PHY_MASK0_RX_SENSE_0_MASK); + + return !RxS_polarity; +} + +__attribute__((unused)) static int phy_rx_s1_detected(hdmi_index index) +{ + /* MASK STATUS POLARITY INTERRUPT RxS + * 0 0 0 1 0 + * 0 1 0 0 1 + * 0 0 1 0 0 + * 0 1 1 1 1 + * 1 x x 0 x + */ + + int RxS_polarity = ddk770_HDMI_read_mask(index, PHY_POL0, PHY_POL0_RX_SENSE_1_MASK); + int RxS = ddk770_HDMI_read_mask(index, PHY_STAT0, PHY_STAT0_RX_SENSE_1_MASK); + + // Mask interrupt + ddk770_HDMI_phy_interrupt_mask(index, PHY_MASK0_RX_SENSE_1_MASK); + + if (RxS_polarity == RxS) { + ddk770_HDMI_write_mask(index, PHY_POL0, PHY_POL0_RX_SENSE_1_MASK, !RxS_polarity); + + // Un-mask interrupts + ddk770_HDMI_phy_interrupt_unmask(index, PHY_MASK0_RX_SENSE_1_MASK); + + return RxS_polarity; + } + + // Un-mask interrupts + ddk770_HDMI_phy_interrupt_unmask(index, PHY_MASK0_RX_SENSE_1_MASK); + + return !RxS_polarity; +} + +__attribute__((unused)) static int phy_rx_s2_detected(hdmi_index index) +{ + /* MASK STATUS POLARITY INTERRUPT RxS + * 0 0 0 1 0 + * 0 1 0 0 1 + * 0 0 1 0 0 + * 0 1 1 1 1 + * 1 x x 0 x + */ + + int RxS_polarity = ddk770_HDMI_read_mask(index, PHY_POL0, PHY_POL0_RX_SENSE_2_MASK); + int RxS = ddk770_HDMI_read_mask(index, PHY_STAT0, PHY_STAT0_RX_SENSE_2_MASK); + + // Mask interrupt + ddk770_HDMI_phy_interrupt_mask(index, PHY_MASK0_RX_SENSE_2_MASK); + + if (RxS_polarity == RxS) { + ddk770_HDMI_write_mask(index, PHY_POL0, PHY_POL0_RX_SENSE_2_MASK, !RxS_polarity); + + // Un-mask interrupts + ddk770_HDMI_phy_interrupt_unmask(index, PHY_MASK0_RX_SENSE_2_MASK); + + return RxS_polarity; + } + + // Un-mask interrupts + ddk770_HDMI_phy_interrupt_unmask(index, PHY_MASK0_RX_SENSE_2_MASK); + + return !RxS_polarity; +} + +__attribute__((unused)) static int phy_rx_s3_detected(hdmi_index index) +{ + /* MASK STATUS POLARITY INTERRUPT RxS + * 0 0 0 1 0 + * 0 1 0 0 1 + * 0 0 1 0 0 + * 0 1 1 1 1 + * 1 x x 0 x + */ + + int RxS_polarity = ddk770_HDMI_read_mask(index, PHY_POL0, PHY_POL0_RX_SENSE_3_MASK); + int RxS = ddk770_HDMI_read_mask(index, PHY_STAT0, PHY_STAT0_RX_SENSE_3_MASK); + + // Mask interrupt + ddk770_HDMI_phy_interrupt_mask(index, PHY_MASK0_RX_SENSE_3_MASK); + + if (RxS_polarity == RxS) { + ddk770_HDMI_write_mask(index, PHY_POL0, PHY_POL0_RX_SENSE_3_MASK, !RxS_polarity); + + // Un-mask interrupts + ddk770_HDMI_phy_interrupt_unmask(index, PHY_MASK0_RX_SENSE_3_MASK); + + return RxS_polarity; + } + + // Un-mask interrupts + ddk770_HDMI_phy_interrupt_unmask(index, PHY_MASK0_RX_SENSE_3_MASK); + + return !RxS_polarity; +} + + +int decode_is_phy(u32 decode) +{ + return (decode & IH_DECODE_IH_PHY_MASK) ? 1 : 0; +} + +int decode_is_phy_hpd(u32 decode) +{ + return (decode & IH_PHY_STAT0_HPD_MASK) ? 1 : 0; +} + +__attribute__((unused)) static int decode_is_phy_rx_s0(u32 decode) +{ + return (decode & IH_PHY_STAT0_RX_SENSE_0_MASK) ? 1 : 0; +} + +__attribute__((unused)) static int decode_is_phy_rx_s1(u32 decode) +{ + return (decode & IH_PHY_STAT0_RX_SENSE_1_MASK) ? 1 : 0; +} + +__attribute__((unused)) static int decode_is_phy_rx_s2(u32 decode) +{ + return (decode & IH_PHY_STAT0_RX_SENSE_2_MASK) ? 1 : 0; +} + +__attribute__((unused)) static int decode_is_phy_rx_s3(u32 decode) +{ + return (decode & IH_PHY_STAT0_RX_SENSE_3_MASK) ? 1 : 0; +} + + +u32 read_interrupt_decode(hdmi_index index) +{ + return (ddk770_HDMI_Read_Register(index, IH_DECODE) & 0xFF); +} + +static u8 phy_rx_s0_state(hdmi_index index) +{ + + return ddk770_HDMI_read_mask(index, (PHY_STAT0), PHY_STAT0_RX_SENSE_0_MASK); +} + +static u8 phy_rx_s1_state(hdmi_index index) +{ + + return ddk770_HDMI_read_mask(index, (PHY_STAT0), PHY_STAT0_RX_SENSE_1_MASK); +} +static u8 phy_rx_s2_state(hdmi_index index) +{ + + return ddk770_HDMI_read_mask(index, (PHY_STAT0), PHY_STAT0_RX_SENSE_2_MASK); +} + +static u8 phy_rx_s3_state(hdmi_index index) +{ + + return ddk770_HDMI_read_mask(index, (PHY_STAT0), PHY_STAT0_RX_SENSE_3_MASK); +} + +u8 phy_rx_sense_state(hdmi_index index) +{ + u8 state; + state = phy_rx_s0_state(index); + state |= phy_rx_s1_state(index); + state |= phy_rx_s2_state(index); + state |= phy_rx_s3_state(index); + return state; +} + + + +u8 phy_hot_plug_state(hdmi_index index) +{ + return ddk770_HDMI_read_mask(index, (PHY_STAT0), PHY_STAT0_HPD_MASK); +} + + +int phy_standby(hdmi_index index) +{ + ddk770_HDMI_phy_interrupt_mask(index, PHY_MASK0_TX_PHY_LOCK_MASK | + PHY_MASK0_RX_SENSE_0_MASK | + PHY_MASK0_RX_SENSE_1_MASK | + PHY_MASK0_RX_SENSE_2_MASK | + PHY_MASK0_RX_SENSE_3_MASK); /* mask phy interrupts - leave HPD */ + _enable_tmds(index, 0); + _power_down(index, 0); /* disable PHY */ + _tx_power_on(index, 0); + _set_pddq(index, 1); + + return 1; +} + + + +int phy_initialize(hdmi_index index) +{ + _tx_power_on(index, 0); + _set_pddq(index, 1); + + ddk770_HDMI_phy_interrupt_mask(index, PHY_MASK0_TX_PHY_LOCK_MASK | + PHY_MASK0_HPD_MASK | + PHY_MASK0_RX_SENSE_0_MASK | + PHY_MASK0_RX_SENSE_1_MASK | + PHY_MASK0_RX_SENSE_2_MASK | + PHY_MASK0_RX_SENSE_3_MASK); + _data_enable_polarity(index, 1); + _interface_control(index, 0); + _enable_tmds(index, 0); + _power_down(index, 0); /* disable PHY */ + phy_i2c_mask_interrupts(index, 0); + + // Clean IH_I2CMPHY_STAT0 + ddk770_HDMI_write_mask(index, IH_I2CMPHY_STAT0, IH_I2CMPHY_STAT0_I2CMPHYERROR_MASK | IH_I2CMPHY_STAT0_I2CMPHYDONE_MASK, 0); + + + + return 0; +} + + +__attribute__((unused)) static int hdmi_phy_configure_supported(hdmi_index index, u32 pClk, color_depth_t color, + pixel_repetition_t pixel) +{ + int i = 0; + + // Color resolution 0 is 8 bit color depth + if (color == 0) + color = COLOR_DEPTH_8; + + pClk = phy_get_freq(pClk); + + for (i = 0; phy311[i].clock != 0; i++ ){ + if(u32_is_equal(pClk, phy311[i].clock) && + (color == phy311[i].color) && + (pixel == phy311[i].pixel)){ + return 1; + } + } + + return 0; +} + +static struct phy_config * hdmi_phy_get_configs(u32 pClk, color_depth_t color, + pixel_repetition_t pixel) +{ + + int i = 0; + pClk = phy_get_freq(pClk); + + if(pClk == 1000) + return NULL; + for (i = 0; phy311[i].clock != 0; i++ ){ + + if(u32_is_equal(pClk, phy311[i].clock) && + (color == phy311[i].color) && + (pixel == phy311[i].pixel)){ + return &(phy311[i]); + } + } + return NULL; + +} + +static void mc_phy_reset(hdmi_index index, u8 bit) +{ + + /* active high for (gen2) */ + /* active low for (thrd_party ack) */ + ddk770_HDMI_write_mask(index, MC_PHYRSTZ, MC_PHYRSTZ_PHYRSTZ_MASK, bit); +} + +static int phy_phase_lock_loop_state(hdmi_index index) +{ + + return ddk770_HDMI_read_mask(index, (PHY_STAT0), PHY_STAT0_TX_PHY_LOCK_MASK); +} + + +static int phy_reconfigure_interface(hdmi_index index) +{ + + ddk770_HDMI_Write_Register(index, JTAG_PHY_CONFIG, JTAG_PHY_CONFIG_I2C_JTAGZ_MASK); + ddk770_HDMI_phy_i2c_slave_address(index,PHY_I2C_SLAVE_ADDR); + + return 0; + +} + +static int hdmi_phy_configure(hdmi_index index, u32 pClk, color_depth_t color, pixel_repetition_t pixel) +{ + int i = 0; + u16 phyRead = 0; + u8 lock = 0; + struct phy_config * config = NULL; + u32 value = 0; + + // Color resolution 0 is 8 bit color depth + if (color == 0) + color = COLOR_DEPTH_8; + + config = hdmi_phy_get_configs(pClk, color, pixel); + + if (config == NULL) { + printk("Configuration for clk %d color depth %d" + " pixel repetition %d not found", pClk, color, pixel); + return -1; + } + + // 0x40=24bit/pixel & no repetition + ddk770_HDMI_Write_Register(index, 0x801, 0x40); + + // Set PHYTXCONFIG txphy_hdmi_i2c_jtagz=1(I2C) +#if 0 + value = dev_read(dev, 0xb0020); + value |= (1 << 9); + dev_write(dev, 0xb0020, value); +#else + value = ddk770_HDMI_Read_Register(index, 0x3034 /*jtag_phy_conf*/); + value |= (1 << 4); + ddk770_HDMI_Write_Register(index, 0x3034, value); +#endif + + mc_phy_reset(index, 1); //GEN2 highHDMI Source PHY active low reset control for PHY GEN1, active high reset control for PHY GEN2 ? + + ddk770_HDMI_write_mask(index, PHY_CONF0, PHY_CONF0_TXPWRON_MASK, 0); + ddk770_HDMI_write_mask(index, PHY_CONF0, PHY_CONF0_PDDQ_MASK, 1); + ddk770_HDMI_write_mask(index, PHY_CONF0, PHY_CONF0_SVSRET_MASK, 1); // 3000 0b00110xxx + + mc_phy_reset(index, 0); + + phy_reconfigure_interface(index); //slave addr 0x69 + + ddk770_HDMI_phy_i2c_write(index, OPMODE_PLLCFG, config->oppllcfg); + if(ddk770_HDMI_phy_i2c_read(index, OPMODE_PLLCFG, &phyRead) || (phyRead != config->oppllcfg)) + printk("OPMODE_PLLCFG Mismatch Write 0x%04x Read 0x%04x\n", + config->oppllcfg , phyRead); + + ddk770_HDMI_phy_i2c_write(index, PLLCURRCTRL, config->pllcurrctrl); + if(ddk770_HDMI_phy_i2c_read(index, PLLCURRCTRL, &phyRead) || (phyRead != config->pllcurrctrl)) + printk("PLLCURRCTRL Mismatch Write 0x%04x Read 0x%04x", + config->pllcurrctrl , phyRead); + + ddk770_HDMI_phy_i2c_write(index, PLLGMPCTRL, config->pllgmpctrl); + if(ddk770_HDMI_phy_i2c_read(index, PLLGMPCTRL, &phyRead) || (phyRead != config->pllgmpctrl)) + printk("PLLGMPCTRL Mismatch Write 0x%04x Read 0x%04x\n", + config->pllgmpctrl , phyRead); + + ddk770_HDMI_phy_i2c_write(index, TXTERM, config->txterm); + if(ddk770_HDMI_phy_i2c_read(index, TXTERM, &phyRead) || (phyRead != config->txterm)) + printk("TXTERM Mismatch Write 0x%04x Read 0x%04x\n", + config->txterm , phyRead); + + ddk770_HDMI_phy_i2c_write(index, VLEVCTRL, config->vlevctrl); + if(ddk770_HDMI_phy_i2c_read(index, VLEVCTRL, &phyRead) || (phyRead != config->vlevctrl)) + printk("VLEVCTRL Mismatch Write 0x%04x Read 0x%04x\n", + config->vlevctrl , phyRead); + + ddk770_HDMI_phy_i2c_write(index, CKSYMTXCTRL, config->cksymtxctrl); + if(ddk770_HDMI_phy_i2c_read(index, CKSYMTXCTRL, &phyRead) || (phyRead != config->cksymtxctrl)) + printk("CKSYMTXCTRL Mismatch Write 0x%04x Read 0x%04x\n", + config->cksymtxctrl , phyRead); + + ddk770_HDMI_write_mask(index, PHY_CONF0, PHY_CONF0_PDDQ_MASK, 0); + ddk770_HDMI_write_mask(index, PHY_CONF0, PHY_CONF0_TXPWRON_MASK, 1); + + /* wait PHY_TIMEOUT no of cycles at most for the PLL lock signal to raise ~around 20us max */ + for (i = 0; i < PHY_TIMEOUT; i++) { + lock = phy_phase_lock_loop_state(index); + if (lock & 0x1) { + //printk("PHY PLL locked\n"); + return 0; + } + usleep_range(1000, 2000); + } + + + printk("PHY PLL not locked\n"); + return -1; +} + +int ddk770_HDMI_PHY_Set_Mode(hdmi_index index, u32 pClk) +{ + int ret = 0; + ret = hdmi_phy_configure(index,pClk,0,0); + + return ret; + +} + + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_phy.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_phy.h new file mode 100644 index 000000000000..3a57dcbb1a02 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_hdmi_phy.h @@ -0,0 +1,148 @@ +#ifndef _DDK770_HDMI_PHY_H_ +#define _DDK770_HDMI_PHY_H_ + +#include "ddk770_hdmi.h" + +#define PHY_I2C_SLAVE_ADDR 0x69 + +#define OPMODE_PLLCFG 0x06 //Mode of Operation and PLL Dividers Control Register +#define CKSYMTXCTRL 0x09 //Clock Symbol and Transmitter Control Register +#define PLLCURRCTRL 0x10 //PLL Current Control Register +#define VLEVCTRL 0x0E //Voltage Level Control Register +#define PLLGMPCTRL 0x15 //PLL Gmp Control Register +#define TXTERM 0x19 //Transmission Termination Register + +#define LT_1_485GBPS_TXTERM 0x0004 +#define LT_1_485GBPS_VLEVCTRL 0x0232 +#define LT_1_485GBPS_CKSYMTXCTRL 0x8009 + +#define LT_2_22GBPS_TXTERM 0x0004 +#define LT_2_22GBPS_VLEVCTRL 0x0230 +#define LT_2_22GBPS_CKSYMTXCTRL 0x8009 + +#define LT_2_97GBPS_TXTERM 0x0004 +#define LT_2_97GBPS_VLEVCTRL 0x0273 +#define LT_2_97GBPS_CKSYMTXCTRL 0x8009 + +#define LT_3_40GBPS_TXTERM 0x0004 +#define LT_3_40GBPS_VLEVCTRL 0x0273 +#define LT_3_40GBPS_CKSYMTXCTRL 0x8029 + +#define GT_3_40GBPS_TXTERM 0x0000 +#define GT_3_40GBPS_VLEVCTRL 0x00C6 +#define GT_3_40GBPS_CKSYMTXCTRL 0x8039 + +#define LT_1_485GBPS LT_1_485GBPS_TXTERM, LT_1_485GBPS_VLEVCTRL, LT_1_485GBPS_CKSYMTXCTRL +#define LT_2_22GBPS LT_2_22GBPS_TXTERM, LT_2_22GBPS_VLEVCTRL, LT_2_22GBPS_CKSYMTXCTRL +#define LT_2_97GBPS LT_2_97GBPS_TXTERM, LT_2_97GBPS_VLEVCTRL, LT_2_97GBPS_CKSYMTXCTRL +#define LT_3_40GBPS LT_3_40GBPS_TXTERM, LT_3_40GBPS_VLEVCTRL, LT_3_40GBPS_CKSYMTXCTRL +#define GT_3_40GBPS GT_3_40GBPS_TXTERM, GT_3_40GBPS_VLEVCTRL, GT_3_40GBPS_CKSYMTXCTRL + +typedef enum { + COLOR_DEPTH_INVALID = 0, + COLOR_DEPTH_8 = 8, + COLOR_DEPTH_10 = 10, + COLOR_DEPTH_12 = 12, + COLOR_DEPTH_16 = 16 +} color_depth_t; + +typedef enum { + PIXEL_REPETITION_OFF = 0, + PIXEL_REPETITION_1 = 1, + PIXEL_REPETITION_2 = 2, + PIXEL_REPETITION_3 = 3, + PIXEL_REPETITION_4 = 4, + PIXEL_REPETITION_5 = 5, + PIXEL_REPETITION_6 = 6, + PIXEL_REPETITION_7 = 7, + PIXEL_REPETITION_8 = 8, + PIXEL_REPETITION_9 = 9, + PIXEL_REPETITION_10 = 10 +} pixel_repetition_t; + +typedef enum { + HDMI_14 = 1, + HDMI_20, + MHL_24 , + MHL_PACKEDPIXEL +} operation_mode_t; + +typedef enum { + ENC_UNDEFINED = -1, + RGB = 0, + YCC444, + YCC422, + YCC420 +} encoding_t; + +typedef enum { + UNDEFINED_COLORIMETRY = 0xFF, + ITU601 = 1, + ITU709, + EXTENDED_COLORIMETRY +} colorimetry_t; + +typedef enum { + UNDEFINED_EXTCOLOR = 0xFF, + XV_YCC601 = 0, + XV_YCC709, + S_YCC601, + ADOBE_YCC601, + ADOBE_RGB +} ext_colorimetry_t; + +typedef enum { + UNDEFINED_FORMAT = 0xFF, + HDMI_NORMAL_FORMAT = 0, + HDMI_EXT_RES_FORMAT = 1, + HDMI_3D_FORMAT = 2, +} hdmi_video_format_t; + +typedef enum { + UNDEFINED_3D = 0xFF, + FRAME_PACKING_3D = 0, + TOP_AND_BOTTOM_3D = 6, + SIDE_BY_SIDE_3D = 8 +} hdmi_3d_structure_t; + +typedef enum { + UNDEFINED_EXTDATA_3D = 0, +} hdmi_3d_extdata_t; + +typedef enum { + UNDEFINED_HDMI_VIC = 0xFF, +} hdmi_vic_t; + + +struct phy_config{ + unsigned int clock; + pixel_repetition_t pixel; + color_depth_t color; + operation_mode_t opmode; + unsigned short oppllcfg; + unsigned short pllcurrctrl; + unsigned short pllgmpctrl; + unsigned short txterm; + unsigned short vlevctrl; + unsigned short cksymtxctrl; +}; + +int ddk770_HDMI_PHY_Set_Mode(hdmi_index index, u32 pClk); +int phy_initialize(hdmi_index index); +void ddk770_HDMI_phy_interrupt_unmask(hdmi_index index, u8 mask); +void ddk770_HDMI_phy_interrupt_mask(hdmi_index index, u8 mask); +int ddk770_HDMI_phy_i2c_write(hdmi_index index, u8 addr, u16 data); +int ddk770_HDMI_phy_i2c_read(hdmi_index index, u8 addr, u16 * value); +void ddk770_HDMI_phy_i2c_slave_address(hdmi_index index, u8 value); +int phy_standby(hdmi_index index); +void irq_hpd_sense_enable(hdmi_index index); +int decode_is_phy(u32 decode); +int decode_is_phy_hpd(u32 decode); +u32 read_interrupt_decode(hdmi_index index); +int phy_hot_plug_detected(hdmi_index index); +u8 phy_rx_sense_state(hdmi_index index); +u8 phy_hot_plug_state(hdmi_index index); +u8 u32_is_equal(u32 a, u32 b); + + +#endif diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_help.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_help.c new file mode 100644 index 000000000000..89408337002c --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_help.c @@ -0,0 +1,44 @@ +#include "ddk770_help.h" + +volatile unsigned char __iomem * mmio770 = NULL; + +#if 0 +unsigned int peekRegisterDWord(unsigned int offset) +{ + + return *(volatile unsigned int *)(mmio770 + offset); +} + + +void pokeRegisterDWord(unsigned int offset, unsigned int value) +{ + + *(volatile unsigned int *)(mmio770 + offset) = value; +} + + +unsigned char peekRegisterByte(unsigned int offset) +{ + + + return *(volatile unsigned char *)(mmio770 + offset); +} + +void pokeRegisterByte(unsigned int offset, unsigned char value) +{ + + *(volatile unsigned char *)(mmio770 + offset) = value; + +} + + +#endif + +/* after driver mapped io registers, use this function first */ +void ddk770_set_mmio(volatile unsigned char * addr,unsigned short devId,char revId) +{ + mmio770 = addr; + printk("Found SM770 SOC Chip\n"); +} + + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_help.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_help.h new file mode 100644 index 000000000000..9ee12beed617 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_help.h @@ -0,0 +1,44 @@ +#ifndef _DDK770_HELP_H__ +#define _DDK770_HELP_H__ +#include +#include +#include + + + +#define PEEK32(addr) readl((addr)+mmio770) +#define POKE32(addr,data) writel((data),(addr)+mmio770) + +#if 0 +unsigned int peekRegisterDWord(unsigned int offset); +void pokeRegisterDWord(unsigned int offset, unsigned int value); + + +unsigned char peekRegisterByte(unsigned int offset); + +void pokeRegisterByte(unsigned int offset, unsigned char value); + + + +#else + + +#define peekRegisterDWord(addr) readl((addr)+mmio770) +#define pokeRegisterDWord(addr,data) writel((data),(addr)+mmio770) + +#define peekRegisterByte(addr) readb((addr)+mmio770) +#define pokeRegisterByte(addr,data) writeb((data),(addr)+mmio770) + +#endif + +/* Size of SM770 MMIO and memory */ +#define SM770_PCI_ALLOC_MMIO_SIZE (2*1024*1024) +#define SM770_PCI_ALLOC_MEMORY_SIZE (256*1024*1024) + + +void ddk770_set_mmio(volatile unsigned char * addr,unsigned short devId,char revId); + +extern volatile unsigned char __iomem * mmio770; + + +#endif diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_helper.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_helper.c new file mode 100644 index 000000000000..146958a03f33 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_helper.c @@ -0,0 +1,85 @@ +/******************************************************************* +* +* Copyright (c) 2009 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* helper.c --- SM750 DDK +* This file contains helper functions those are used throughout +* the DDK library. +* +*******************************************************************/ +#include "ddk770_ddkdebug.h" +#include "ddk770_helper.h" + +/* A test counter to be shared by all modules */ +static unsigned long gTestCounter; + +/* Functions to manipulate a test counter. */ +unsigned long ddk770_getTestCounter(void) +{ + return gTestCounter; +} + +void ddk770_setTestCounter(unsigned long value) +{ + gTestCounter = value; +} + +void ddk770_incTestCounter(void) +{ + gTestCounter++; +} + +/* Perform a rounded division with signed number. + * For example, if the result is 4.5, this function returns 5. + * If the result is 4.4, this function returns 4. + */ +long ddk770_lRoundedDiv(long num, long denom) +{ + /* n / d + 1 / 2 = (2n + d) / 2d */ + return (2 * num + denom) / (2 * denom); +} + +/* Perform a rounded division. + * For example, if the result is 4.5, this function returns 5. + * If the result is 4.4, this function returns 4. + */ +unsigned long ddk770_roundedDiv(unsigned long num, unsigned long denom) +{ + /* n / d + 1 / 2 = (2n + d) / 2d */ + return (2 * num + denom) / (2 * denom); +} + +/* Perform a rounded division with unsigned number. + * For example, if the result is 4.5, this function returns 5. + * If the result is 4.4, this function returns 4. + */ +__attribute__((unused)) static unsigned long ddk770_ulRoundedDiv(unsigned long num, unsigned long denom) +{ + return ddk770_roundedDiv(num, denom); +} + +/* Absolute differece between two numbers */ +unsigned long ddk770_absDiff(unsigned long a, unsigned long b) +{ + if ( a >= b ) + return(a - b); + else + return(b - a); +} + +/* This function calculates 2 to the power of x + Input is the power number. + */ +unsigned long ddk770_twoToPowerOfx(unsigned long x) +{ + unsigned long i; + unsigned long result = 1; + + for (i=1; i<=x; i++) + result *= 2; + + return result; +} diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_helper.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_helper.h new file mode 100644 index 000000000000..8b8435fc508a --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_helper.h @@ -0,0 +1,44 @@ +/******************************************************************* +* +* Copyright (c) 2009 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* helper.h --- SMI DDK +* This file contains the helper functions those are used throughout +* the library +* +*******************************************************************/ +#ifndef _DDK770_HELPER_H_ +#define _DDK770_HELPER_H_ + +/* Functions to manipulate a test counter. */ +unsigned long ddk770_getTestCounter(void); + +void ddk770_setTestCounter(unsigned long value); + +void ddk770_incTestCounter(void); + + +/* Perform a rounded division with signed number. + * For example, if the result is 4.5, this function returns 5. + * If the result is 4.4, this function returns 4. + */ +long ddk770_lRoundedDiv(long num, long denom); + +/* Perform a rounded division. + * For example, if the result is 4.5, this function returns 5. + * If the result is 4.4, this function returns 4. + */ +unsigned long ddk770_roundedDiv(unsigned long num, unsigned long denom); + +/* Absolute differece between two numbers */ +unsigned long ddk770_absDiff(unsigned long a, unsigned long b); + +/* This function calculates 2 to the power of x + Input is the power number. + */ +unsigned long ddk770_twoToPowerOfx(unsigned long x); + +#endif /* _HELPER_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_hwi2c.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_hwi2c.c new file mode 100644 index 000000000000..4b0bb1ad6b53 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_hwi2c.c @@ -0,0 +1,354 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* hwi2c.c --- SMI DDK +* This file contains the source code for hardware i2c. +* +*******************************************************************/ +#include "ddk770_reg.h" +#include "ddk770_power.h" +#include "ddk770_hwi2c.h" +#include "ddk770_gpio.h" +#include "ddk770_help.h" + +/* + * This function initializes the hardware i2c + * + * Return Value: + * 0 - Success + * -1 - Fail to initialize i2c + */ +long ddk770_hwI2CInit( + unsigned char i2cNumber //I2C0 or I2C1 +) +{ + unsigned long value; + + /* Enable GPIO pins as IIC clock & data */ + + value = FIELD_SET(peekRegisterDWord(GPIO_MUX), GPIO_MUX, I2C3, ENABLE); + pokeRegisterDWord(GPIO_MUX, value); + + +#if 0 + ddk770_gpioMode(24,0); + ddk770_gpioMode(25,0); +#endif + + + /* Enable the I2C Controller and set the bus speed mode */ + value = FIELD_SET(peekRegisterByte(I2C_CTRL), I2C_CTRL, EN, ENABLE); + value = FIELD_SET(value, I2C_CTRL, MODE, STANDARD); + pokeRegisterByte(I2C_CTRL, value); + + return 0; +} + +/* + * This function closes the hardware i2c. + */ +void ddk770_hwI2CClose( + unsigned char i2cNumber //I2C0 or I2C1 +) +{ + unsigned long value; + + value = FIELD_SET(peekRegisterDWord(GPIO_MUX), GPIO_MUX, I2C3, DISABLE); + pokeRegisterDWord(GPIO_MUX, value); + + + /* Disable I2C controller */ + value = FIELD_SET(peekRegisterByte(I2C_CTRL), I2C_CTRL, EN, DISABLE); + pokeRegisterByte(I2C_CTRL, value); +} + +/* + * This function waits until the transfer is completed within the timeout value. + * + * Return Value: + * 0 - Transfer is completed + * -1 - Tranfer is not successful (timeout) + */ +static long ddk770_hwI2CWaitTXDone( + unsigned char i2cNumber //I2C0 or I2C1 +) +{ + unsigned long timeout; + + + /* Wait until the transfer is completed. */ + timeout = HWI2C_WAIT_TIMEOUT; + while ((FIELD_VAL_GET(peekRegisterByte(I2C_STATUS), I2C_STATUS, TX) != I2C_STATUS_TX_COMPLETED) && + (timeout != 0)) + timeout--; + + if (timeout == 0) + return (-1); + + return 0; +} + +/* + * This function writes data to the i2c slave device registers. + * + * Parameters: + * deviceAddress - i2c Slave device address + * length - Total number of bytes to be written to the device + * pBuffer - The buffer that contains the data to be written to the + * i2c device. + * + * Return Value: + * Total number of bytes those are actually written. + */ +unsigned long ddk770_hwI2CWriteData( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned long length, + unsigned char *pBuffer +) +{ + unsigned char count, i; + unsigned long totalBytes = 0; + //unsigned char value; + //unsigned long timeout; + + /* Set the Device Address */ + pokeRegisterByte(I2C_SLAVE_ADDRESS, deviceAddress & ~0x01); + + /* Write data. + * Note: + * Only 16 byte can be accessed per i2c start instruction. + */ + do + { + /* Reset I2C by writing 0 to I2C_RESET register to clear the previous status. */ + pokeRegisterByte(I2C_RESET, 0); + + /* Set the number of bytes to be written */ + if (length < MAX_HWI2C_FIFO) + count = length - 1; + else + count = MAX_HWI2C_FIFO - 1; + pokeRegisterByte(I2C_BYTE_COUNT, count); + + /* Move the data to the I2C data register */ + for (i = 0; i <= count; i++) + pokeRegisterByte(I2C_DATA0 + i, *pBuffer++); + + /* Start the I2C */ + pokeRegisterByte(I2C_CTRL, FIELD_SET(peekRegisterByte(I2C_CTRL), I2C_CTRL, CTRL, START)); + + /* Wait until the transfer is completed. */ + if (ddk770_hwI2CWaitTXDone(i2cNumber) != 0) + break; + + /* Substract length */ + length -= (count + 1); + + /* Total byte written */ + totalBytes += (count + 1); + + } while (length > 0); + + return totalBytes; +} + +/* + * This function reads data from the slave device and stores them + * in the given buffer + * + * Parameters: + * deviceAddress - i2c Slave device address + * length - Total number of bytes to be read + * pBuffer - Pointer to a buffer to be filled with the data read + * from the slave device. It has to be the same size as the + * length to make sure that it can keep all the data read. + * + * Return Value: + * Total number of actual bytes read from the slave device + */ +unsigned long ddk770_hwI2CReadData( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned long length, + unsigned char *pBuffer +) +{ + unsigned char count, i; + unsigned long totalBytes = 0; + //unsigned char value; + + + /* Set the Device Address */ + pokeRegisterByte(I2C_SLAVE_ADDRESS, deviceAddress | 0x01); + + /* Read data and save them to the buffer. + * Note: + * Only 16 byte can be accessed per i2c start instruction. + */ + do + { + /* Reset I2C by writing 0 to I2C_RESET register to clear all the status. */ + pokeRegisterByte(I2C_RESET, 0); + + /* Set the number of bytes to be read */ + if (length <= MAX_HWI2C_FIFO) + count = length - 1; + else + count = MAX_HWI2C_FIFO - 1; + pokeRegisterByte(I2C_BYTE_COUNT, count); + + /* Start the I2C */ + pokeRegisterByte(I2C_CTRL, FIELD_SET(peekRegisterByte(I2C_CTRL), I2C_CTRL, CTRL, START)); + + /* Wait until transaction done. */ + if (ddk770_hwI2CWaitTXDone(i2cNumber) != 0) + break; + + /* Save the data to the given buffer */ + for (i = 0; i <= count; i++) + { + *pBuffer++ = peekRegisterByte(I2C_DATA0 + i); + } + + /* Substract length by 16 */ + length -= (count + 1); + + /* Number of bytes read. */ + totalBytes += (count + 1); + + } while (length > 0); + + return totalBytes; +} + +/* + * This function reads the slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be read from + * registerIndex - Slave device's register to be read + * + * Return Value: + * Register value + */ +unsigned char ddk770_hwI2CReadReg( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned char registerIndex +) +{ + unsigned char value = (0xFF); + + deviceAddress = (deviceAddress << 1); + + if (ddk770_hwI2CWriteData(i2cNumber, deviceAddress, 1, ®isterIndex) == 1) + ddk770_hwI2CReadData(i2cNumber, deviceAddress, 1, &value); + + return value; +} + +/* + * This function reads the 16bit i2c slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be read from + * registerIndex - Slave device's register to be read + * + * Return Value: + * Register value + */ +unsigned short hwI2CReadReg_16bit( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned short registerIndex +) +{ + unsigned short ret = 0xffff; + unsigned char value[2]= {0xff, 0xff}; + unsigned char offset[2] = {0xff, 0xff}; + offset[0] = (registerIndex >> 8) & 0xff; + offset[1] = registerIndex & 0xff; + + deviceAddress = (deviceAddress << 1); + + if (ddk770_hwI2CWriteData(i2cNumber, deviceAddress, 2, offset) == 2) + ddk770_hwI2CReadData(i2cNumber, deviceAddress, 2, value); + + ret = value[0]; + ret = ret << 8 | value[1]; + return ret; +} + +/* + * This function writes a value to the slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be written + * registerIndex - Slave device's register to be written + * data - Data to be written to the register + * + * Result: + * 0 - Success + * -1 - Fail + */ +long ddk770_hwI2CWriteReg( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned char registerIndex, + unsigned char data +) +{ + unsigned char value[2]; + + deviceAddress = (deviceAddress << 1); + + value[0] = registerIndex; + value[1] = data; + if (ddk770_hwI2CWriteData(i2cNumber, deviceAddress, 2, value) == 2) + return 0; + + return (-1); +} + +/* + * This function writes a value to the 16bit slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be written + * registerIndex - Slave device's register to be written + * data - Data to be written to the register + * + * Result: + * 0 - Success + * -1 - Fail + */ +long hwI2CWriteReg_16bit( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned short registerIndex, + unsigned short data +) +{ + unsigned char val[4]; + + deviceAddress = (deviceAddress << 1); + + val[0] = (registerIndex >> 8) & 0xff; + val[1] = registerIndex & 0xff; + val[2] = (data >> 8) & 0xff; + val[3] = data & 0xff; + + if (ddk770_hwI2CWriteData(i2cNumber, deviceAddress, 4, val) == 4) + return 0; + + return (-1); +} \ No newline at end of file diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_hwi2c.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_hwi2c.h new file mode 100644 index 000000000000..fe3461059ccd --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_hwi2c.h @@ -0,0 +1,143 @@ +/******************************************************************* +* +* Copyright (c) 2008 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* hwi2c.H --- SMI DDK +* This file contains the definitions for Hardware I2C. +* +*******************************************************************/ +#ifndef _DDK770_HWI2C_H_ +#define _DDK770_HWI2C_H_ + +#define MAX_HWI2C_FIFO 16 +#define HWI2C_WAIT_TIMEOUT 0x1000 //0x7FF + +#include "../smi_drv.h" +/* + * This function initializes the hardware i2c + * + * Return Value: + * 0 - Success + * -1 - Fail to initialize i2c + */ +long ddk770_hwI2CInit( + unsigned char i2cNumber //I2C0 or I2C1 +); + +/* + * This function close the hardware i2c + */ +void ddk770_hwI2CClose( + unsigned char i2cNumber //I2C0 or I2C1 +); + +/* + * This function writes data to the i2c slave device registers. + * + * Parameters: + * deviceAddress - i2c Slave device address + * length - Total number of bytes to be written to the device + * pBuffer - The buffer that contains the data to be written to the + * i2c device. + * + * Return Value: + * Total number of bytes those are actually written. + */ +unsigned long ddk770_hwI2CWriteData( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned long length, + unsigned char *pBuffer +); + +/* + * This function reads data from the slave device and stores them + * in the given buffer + * + * Parameters: + * deviceAddress - i2c Slave device address + * length - Total number of bytes to be read + * pBuffer - Pointer to a buffer to be filled with the data read + * from the slave device. It has to be the same size as the + * length to make sure that it can keep all the data read. + * + * Return Value: + * Total number of actual bytes read from the slave device + */ +unsigned long ddk770_hwI2CReadData( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned long length, + unsigned char *pBuffer +); + +/* + * This function read the i2c device register value + * + * Input: deviceAddress - I2C Device Address + * registerIndex - Register index to be read + * + * Output: + * The value of the register being read. + */ +unsigned char ddk770_hwI2CReadReg( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned char registerIndex +); + +/* + * This function read the i2c 16 bit device register value + * + * Input: deviceAddress - I2C Device Address + * registerIndex - Register index to be read + * + * Output: + * The value of the register being read. + */ +unsigned short hwI2CReadReg_16bit( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned short registerIndex +); + +/* + * This function writes a value to the i2c device register. + * + * Input: deviceAddress - I2C Device Address + * registerIndex - Register index to be written to + * data - Data to be written to + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_hwI2CWriteReg( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned char registerIndex, + unsigned char data +); + +/* + * This function writes a value to the i2c 16bit device register. + * + * Input: deviceAddress - I2C Device Address + * registerIndex - Register index to be written to + * data - Data to be written to + * + * Output: + * 0 - Success + * -1 - Fail + */ +long hwI2CWriteReg_16bit( + unsigned char i2cNumber, //I2C0 or I2C1 + unsigned char deviceAddress, + unsigned short registerIndex, + unsigned short data +); + +#endif /* _HWI2C_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_iis.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_iis.c new file mode 100644 index 000000000000..38e10b8ec0cd --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_iis.c @@ -0,0 +1,283 @@ +/******************************************************************* +* +* Copyright (c) 2014 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* This file contains the definitions for the IIS functions. +* +*******************************************************************/ +#include "ddk770_reg.h" +#include "ddk770_clock.h" +#include "ddk770_power.h" +#include "ddk770_helper.h" +#include "ddk770_chip.h" +#include "ddk770_iis.h" +#include "ddk770_gpio.h" +#include +#include "ddk770_help.h" + + +void ddk770_iis_Init(void) +{ + unsigned int val; + + printk("IIS Init\n"); + + // phy soft reset + val = FIELD_SET(peekRegisterDWord(DP_BASE + DP_TOP1C), DP_TOP1C, REG_RESET_PHY, TRUE); // set reg0x001c[1] to 1 + pokeRegisterDWord(DP_BASE + DP_TOP1C, val); + + usleep_range(50000 , 50100); + val = FIELD_SET(peekRegisterDWord(DP_BASE + DP_TOP1C), DP_TOP1C, REG_RESET_PHY, FALSE); // set reg0x001c[1] to 0 + pokeRegisterDWord(DP_BASE + DP_TOP1C, val); + + + // pixl pll + pokeRegisterDWord(DP_BASE + DP_ANALOG190, 0x10530); + pokeRegisterDWord(DP_BASE + DP_ANALOG194, 0x1050005); +} + + +/* + * Set up I2S and GPIO registers to transmit/receive data. + */ +void ddk770_iisOpen( + unsigned long wordLength, //Number of bits in IIS data: 16 bit, 24 bit, 32 bit + unsigned long sampleRate //Sampling rate. +) +{ + unsigned long gpioPin, clockDivider; + unsigned char ws; + + ddk770_enableI2S(1); //Turn on I2S clock + + /* Configure GPIO Mux for IIS output */ + gpioPin = peekRegisterDWord(GPIO_MUX); + + /* Select IIS Pins */ + pokeRegisterDWord(GPIO_MUX, + FIELD_SET(gpioPin, GPIO_MUX, 9, I2S_RX) | + FIELD_SET(gpioPin, GPIO_MUX, 8, I2S_TX) | + FIELD_SET(gpioPin, GPIO_MUX, 7, I2S_WS) | + FIELD_SET(gpioPin, GPIO_MUX, 6, I2S_CK)); + + + /* Make sure GPIO9(IIS RX) data direction is input */ + + ddk770_gpioMode(9,1); + + + /* IIS register set up */ + pokeRegisterDWord(I2S_TX_DATA_L, 0); //Clear Tx registers + pokeRegisterDWord(I2S_TX_DATA_R, 0); + + //Figure out Word Select value + switch (wordLength) + { + case 32: + ws = 2; + break; + case 24: + ws = 1; + break; + default: + ws = 0; + } + + clockDivider = (24576000)/(4*sampleRate*wordLength) - 1; + + pokeRegisterDWord(I2S_CTRL, + FIELD_VALUE(0, I2S_CTRL, CS, ws) + | FIELD_VALUE(0, I2S_CTRL , CDIV, clockDivider)); + + pokeRegisterDWord(I2S_SRAM_DMA, 0); //Default no DMA. Call another function to set up DMA +} + +/* + * Turn off I2S and close GPIO + */ +void ddk770_iisClose() +{ + unsigned long gpioPin; + + gpioPin = peekRegisterDWord(GPIO_MUX); + pokeRegisterDWord(GPIO_MUX, + FIELD_SET(gpioPin, GPIO_MUX, 9, GPIO) | + FIELD_SET(gpioPin, GPIO_MUX, 8, GPIO) | + FIELD_SET(gpioPin, GPIO_MUX, 7, GPIO) | + FIELD_SET(gpioPin, GPIO_MUX, 6, GPIO)); + + pokeRegisterDWord(I2S_TX_DATA_L, 0); //Clear Tx registers + pokeRegisterDWord(I2S_TX_DATA_R, 0); + pokeRegisterDWord(I2S_STATUS, 0); //Disable Tx line out + pokeRegisterDWord(I2S_CTRL, 0); //Clear clock setting. + pokeRegisterDWord(I2S_SRAM_DMA, 0); //Clear DMA setting. + + ddk770_enableI2S(0); //Turn off I2S clock +} + + + + +/* + * This function set up I2S to DMA data from SRAM. + * + * SRAM area has max size of 2048 bytes (or 512 DWords). + * Max size of each I2S DMA session is 256 DWords. + * + * Inputs: + * offset address in SRAM to start DMA (DWord aligned) + * Number of bytes to DMA (DWord aligned) + */ +void ddk770_iisTxDmaSetup( + unsigned long offset, /* Offset from start of SRAM to start DMA */ + unsigned long len /* Number of bytes to DMA */ + ) +{ + unsigned long dmaPointer; + + offset >>= 2; //I2S DMA register requires offset to be expressed in DWord + len >>= 2; + len--; //I2S DMA register requires length to be expressed as DWord - 1. + + dmaPointer = FIELD_VAL_GET(peekRegisterDWord(I2S_SRAM_DMA), I2S_SRAM_DMA, ADDRESS); + + //If DMA pointer already at the requested offset. Just set up the length. + if (dmaPointer == offset) + { + pokeRegisterDWord(I2S_SRAM_DMA, + FIELD_SET(0, I2S_SRAM_DMA, STATE, ENABLE) + | FIELD_VALUE(0, I2S_SRAM_DMA, SIZE, len) + | FIELD_VALUE(0, I2S_SRAM_DMA, ADDRESS, offset)); + + return; + } + + //Position DMA pointer to the new base pointer (or offset). + //Note that DMA reload base pointer only when it gets to end of SRAM. + //Therefore, we need to advance DMA from current position to the end. + pokeRegisterDWord(I2S_SRAM_DMA, + FIELD_SET(0, I2S_SRAM_DMA, STATE, ENABLE) + | FIELD_VALUE(0, I2S_SRAM_DMA, SIZE, (0x1FF - dmaPointer)) + | FIELD_VALUE(0, I2S_SRAM_DMA, ADDRESS, dmaPointer)); + + ddk770_iisStartNoTx();//Start DMA without output the old data from Tx line. + + //Once DMA starts, make the new base pointer ready. + pokeRegisterDWord(I2S_SRAM_DMA, + FIELD_SET(0, I2S_SRAM_DMA, STATE, ENABLE) + | FIELD_VALUE(0, I2S_SRAM_DMA, SIZE, len) + | FIELD_VALUE(0, I2S_SRAM_DMA, ADDRESS, offset)); + + // When DMA get to the end of SRAM, it loads the new base pointer. + do + { + dmaPointer = FIELD_VAL_GET(peekRegisterDWord(I2S_SRAM_DMA), I2S_SRAM_DMA, ADDRESS); + } while(dmaPointer != offset); + + ddk770_iisStop(); +} + +/* + * Return current IIS DMA position. + */ +unsigned long ddk770_iisDmaPointer(void) +{ + return(FIELD_VAL_GET(peekRegisterDWord(I2S_SRAM_DMA), I2S_SRAM_DMA, ADDRESS)); +} + +/* + * This function start IIS without enabling Tx line. + * It can be used to flush left over SRAM data without + * sending them to Codec. + */ +void ddk770_iisStartNoTx(void) +{ + unsigned long value; + + value = FIELD_SET(peekRegisterDWord(I2S_CTRL), I2S_CTRL, MODE, MASTER); + pokeRegisterDWord(I2S_CTRL, value); +} + +/* + * This function is needed only when I2S is intended to operate in master mode. + * + * For slave mode, just use iisOpen() is enough, because I2S will start + * functioning as soon as an external clock is detected after iisOpen(). + * + */ + +void ddk770_iisStart(void) +{ + unsigned long value; + + pokeRegisterDWord(I2S_STATUS, FIELD_SET(0, I2S_STATUS, TX, ENABLE)); //Enable Tx line out + + value = FIELD_SET(peekRegisterDWord(I2S_CTRL), I2S_CTRL, MODE, MASTER); + pokeRegisterDWord(I2S_CTRL, value); +} + +/* + * This function is useful only when I2S is operating in master mode. + * + * For slave mode, clock is external and cannot be stopped by IIS + * control register. + * + */ +void ddk770_iisStop(void) +{ + unsigned long value; + + value = FIELD_SET(peekRegisterDWord(I2S_CTRL), I2S_CTRL, MODE, SLAVE); + pokeRegisterDWord(I2S_CTRL, value); + + pokeRegisterDWord(I2S_STATUS, FIELD_SET(0, I2S_STATUS, TX, DISABLE)); //Disable Tx line out + +} + + +/* + * Set values for left Tx and right Tx register. + */ +void ddk770_iisSetTx( + unsigned long left, //Data for left channel Tx + unsigned long right //Data for right channel Tx + ) +{ + pokeRegisterDWord(I2S_TX_DATA_L, left); + pokeRegisterDWord(I2S_TX_DATA_R, right); +} + + +/* + * This function clears the RAW interrupt status of I2S. + * + * When I2S completes sending data, the raw interrupt bit will be set. + * It has to be cleared, in order to distinguish between different sessions of countdown. + * + */ +void ddk770_iisClearRawInt(void) +{ + /* Read I2S Control & TX to clear INT when IIS get data from Tx & Rx. */ + peekRegisterDWord(I2S_STATUS); + + /* Write 0 to I2S SRAM DMA status when IIS get data from SRAM */ + pokeRegisterDWord(I2S_SRAM_DMA_STATUS, 0); +} + +/* + * This function returns the INT mask for IIS. + * + */ +unsigned long ddk770_iisIntMask(void) +{ + unsigned long mask = 0; + + mask |= FIELD_SET(0, INT_MASK, I2S, ENABLE); + + return mask; +} + + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_iis.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_iis.h new file mode 100644 index 000000000000..7b5109ab73af --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_iis.h @@ -0,0 +1,102 @@ +#ifndef _DDK770_IIS_H_ +#define _DDK770_IIS_H_ + +#define MHz(x) (x*1000000) /* Don't use this macro if x is fraction number */ + +#define IIS_REF_CLOCK MHz(40) + + +void ddk770_iis_Init(void); + +/* + * Set up I2S and GPIO registers to transmit/receive data. + */ +void ddk770_iisOpen( + unsigned long wordLength, //Number of bits in IIS data: 16 bit, 24 bit, 32 bit + unsigned long sampleRate //Sampling rate. +); + +/* + * Turn off I2S and close GPIO + */ +void ddk770_iisClose(void); + +/* + * This function set up I2S to DMA data from SRAM. + * + * SRAM area has max size of 2048 bytes (or 512 DWords). + * Max size of each I2S DMA session is 256 DWords. + * + * Inputs: + * offset address in SRAM to start DMA (DWord aligned) + * Number of bytes to DMA (DWord aligned) + */ +void ddk770_iisTxDmaSetup( + unsigned long offset, /* Offset from start of SRAM area */ + unsigned long len /* Number of bytes to DMA */ + ); + +/* + * Return current IIS DMA position. + */ +unsigned long ddk770_iisDmaPointer(void); + +/* + * This function start IIS without enabling Tx line. + * It can be used to flush left over SRAM data without + * sending them to Codec. + */ +void ddk770_iisStartNoTx(void); + +/* + * This function is needed only when I2S is intended to operate in master mode. + * + * For slave mode, just use iisOpen() is enough, because I2S will start + * functioning as soon as an external clock is detected after iisOpen(). + * + */ +void ddk770_iisStart(void); + +/* + * This function is useful only when I2S is operating in master mode. + * + * For slave mode, clock is external and cannot be stopped by IIS + * control register. + * + */ +void ddk770_iisStop(void); + +/* + * Set values for left Tx and right Tx register. + */ +void ddk770_iisSetTx( + unsigned long left, //Data for left channel Tx + unsigned long right //Data for right channel Tx + ); + +/* + * This function clears the RAW interrupt status of I2S. + * + * When I2S completes sending data, the raw interrupt bit will be set. + * It has to be cleared, in order to distinguish between different sessions of countdown. + * + */ +void ddk770_iisClearRawInt(void); + +/* + * This function returns the INT mask for IIS. + * + */ +unsigned long ddk770_iisIntMask(void); + +/* + * This is a reference sample showing how to implement ISR for I2S. + * It works wiht libsrc\intr.c together. + * + * Refer to Apps\iis\tstiis.c on how to hook up this function with system + * interrupt under WATCOM DOS extender. + * + */ + + +#endif /* _IIS_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_intr.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_intr.c new file mode 100644 index 000000000000..ed5ee4345cb1 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_intr.c @@ -0,0 +1,51 @@ +#include "ddk770_reg.h" +#include "ddk770_chip.h" +#include "ddk770_intr.h" +#include "ddk770_help.h" + + +/* + * Change interrupt mask + */ +void ddk770_setIntMask( + unsigned long mask_on, + unsigned long mask_off +) +{ + unsigned long mask; + + /* Get current interrupt mask */ + mask = peekRegisterDWord(INT_MASK); + + /* Enable new masks and disable old masks */ + mask = mask | mask_on; + mask = mask & ~mask_off; + + /* Program new interrupt mask */ + pokeRegisterDWord(INT_MASK, mask); +} + + +void ddk770_sb_IRQMask(int irq_num) +{ + unsigned int mask; + mask = peekRegisterDWord(INT_MASK); + mask &= ~(0x1< +#include +#include +#include +#include +#include + +/* Global variable to save all the SMI devices */ +static struct pci_dev *g_pCurrentDevice = (struct pci_dev *)0; +static struct pci_access *g_pAccess; +static struct pci_filter g_filter; + +/* + * This function maps a physical address into logical address. + * Return: NULL address pointer if fail + * A Logical address pointer if success. + */ +void *mapPhysicalAddress( + void *phyAddr, /* 32 bit physical address */ + unsigned long size /* Memory size to be mapped */ +) +{ + unsigned long address; + int fileDescriptor; + + fileDescriptor = open("/dev/mem", O_RDWR); + if (fileDescriptor == -1) + return ((void *)0); + + address = (unsigned long) mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileDescriptor, (unsigned long)phyAddr); + + if ((void *) address == MAP_FAILED) + return ((void *)0); + + return ((void *) address); +} + +/* Initialize the PCI */ +long initPCI( + unsigned short vendorId, + unsigned short deviceId, + unsigned short deviceNum +) +{ + unsigned short deviceIndex; + + /* Get the pci_access structure */ + g_pAccess = pci_alloc(); + + /* Initialize the PCI library */ + pci_init(g_pAccess); + + /* Set all options you want -- here we stick with the defaults */ + pci_filter_init(g_pAccess, &g_filter); + g_filter.vendor = vendorId; + g_filter.device = deviceId; + + /* Get the list of devices */ + pci_scan_bus(g_pAccess); + for(g_pCurrentDevice = g_pAccess->devices, deviceIndex = 0; + g_pCurrentDevice; + g_pCurrentDevice = g_pCurrentDevice->next) + { + if (pci_filter_match(&g_filter, g_pCurrentDevice)) + { + if (deviceIndex == deviceNum) + { + pci_fill_info(g_pCurrentDevice, PCI_FILL_IDENT | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES); + return 0; + } + + /* Increment the device index */ + deviceIndex++; + } + } + + return (-1); +} + +/* + * This function reads a DWord value from the PCI configuration space + * of a specific PCI device. + * + * Inputs are the Vendor and device ID of the device in question. + * Return: a DWord value. + */ +unsigned long readPCIDword( + unsigned short vendorId, /* PCI vendor ID */ + unsigned short deviceId, /* PCI device ID */ + unsigned short deviceNum, /* If more than one device in system, device number are ordered as 0, 1, 2,... */ + unsigned short offset /* Offset in configuration space to be read */ +) +{ + if (initPCI(vendorId, deviceId, deviceNum) == 0) + { + return ((unsigned long) pci_read_long(g_pCurrentDevice, offset)); + } + + return 0; +} + +unsigned long readPCIBar0Size( + unsigned short vendorId, /* PCI vendor ID */ + unsigned short deviceId, /* PCI device ID */ + unsigned short deviceNum, /* If more than one device in system, device number are ordered as 0, 1, 2,... */ + unsigned short offset /* Offset in configuration space to be read */ +) +{ + if (initPCI(vendorId, deviceId, deviceNum) == 0) + { + return g_pCurrentDevice->size[0]; + } + + return 0; +} + +/* + * This function reads a Word value from the PCI configuration space + * of a specific device. + * + * Inputs are the Vendor and device ID of the device in question. + * Return: a WORD value. + */ +unsigned short readPCIWord( + unsigned short vendorId, /* PCI vendor ID */ + unsigned short deviceId, /* PCI device ID */ + unsigned short deviceNum, /* If more than one device in system, device number are ordered as 0, 1, 2,... */ + unsigned short offset /* Offset in configuration space to be read */ +) +{ + if (initPCI(vendorId, deviceId, deviceNum) == 0) + { + return ((unsigned short) pci_read_word(g_pCurrentDevice, offset)); + } + + return 0; +} + +/* + * This function reads a byte value from the PCI configuration space + * of a specific device. + * + * Inputs are the Vendor and device ID of the device in question. + * Return: a BYTE value. + */ +unsigned char readPCIByte( + unsigned short vendorId, /* PCI Vendor ID */ + unsigned short deviceId, /* PCI device ID */ + unsigned short deviceNum, /* If more than one device in system, device number are ordered as 0, 1, 2,... */ + unsigned short offset /* Offset in configuration space to be read */ +) +{ + if (initPCI(vendorId, deviceId, deviceNum) == 0) + { + return ((unsigned char) pci_read_byte(g_pCurrentDevice, offset)); + } + + return 0; +} + +/* + * This function writes a byte value to the PCI configuration space + * of a specific device. + * + * Inputs are the Vendor and device ID of the device in question. + * Return: 0 = Success. + * -1 = Fail. + */ +long writePCIByte( + unsigned short vendorId, /* PCI vendor ID */ + unsigned short deviceId, /* PCI device ID */ + unsigned short deviceNum, /* If more than one device in system, device number are ordered as 0, 1, 2,... */ + unsigned short offset, /* Offset in configuration space to be written */ + unsigned char value /* To be written BYTE value */ +) +{ + if (initPCI(vendorId, deviceId, deviceNum) == 0) + return (pci_write_byte(g_pCurrentDevice, offset, value)); + + return (-1); +} + +/* + * This function enable the write combine (burst) + */ +long registerWCMemoryRange( + void *phyAddr, /* 32 bit physical address */ + unsigned long size +) +{ + return (-1); //unsupport yet +} + +/* + * This function disable the write combine (burst) + */ +long unregisterWCMemoryRange( + void *phyAddr, /* 32 bit physical address */ + unsigned long size +) +{ + + long returnValue = (-1); + + return returnValue; +} + +/******************************************************************* + * Interrupt implementation support from the OS + * + * This implementation is used for handling the SM50x interrupt. + *******************************************************************/ +#if 1 //CheokTest(2014/10/01): No use at the moment. +extern void irqHandler(); +#endif + +short enableTimerInterrupt( + unsigned char enable +) +{ +#if 1 //CheokTest(2014/10/01): No use at the moment. + struct itimerval tick; + + /* Initialize struct */ + memset((void *)&tick, 0, sizeof(tick)); + + if (enable != 0) + { + signal(SIGALRM, irqHandler); + + /* Timeout to run function first time */ + tick.it_value.tv_sec = 0; /* sec */ + tick.it_value.tv_usec = 5880/*16666*/; /* micro sec. */ + + /* Interval time to run function */ + tick.it_interval.tv_sec = 0; + tick.it_interval.tv_usec = 5880/*16666*/; + } + + /* Set timer, ITIMER_REAL : real-time to decrease timer, send SIGALRM when timeout */ + if (setitimer(ITIMER_REAL, &tick, NULL)) { + printk("setitimer error %d\n", errno); + return (-1); + } +#endif + + return (0); +} + +/* + * Register an interrupt handler (ISR) to the interrupt vector table associated + * with the given irq number. + * + * Input: + * irqNumber - IRQ Number + * pfnHandler - Pointer to the ISR function + * + * Output: + * 0 - Success + * -1 - Fail + */ +short registerInterrupt( + unsigned char irqNumber, + void (*pfnHandler)() +) +{ + return enableTimerInterrupt(1); +} + +/* + * Unregister an interrupt handler from the interrupt vector table + * + * Input: + * irqNumber - IRQ Number + */ +short unregisterInterrupt( + unsigned char irqNumber +) +{ + return enableTimerInterrupt(0); +} + +/* + * Signal the End Of Interrupt to the system and chain the interrupt + * if necessary. + * + * Input: + * irqNumber - IRQ Number + */ +void interruptEOI( + unsigned char irqNumber +) +{ +} + + +/******************************************************************* + * Timer Interrupt implementation + *******************************************************************/ + +/* Interrupt structure */ +typedef struct _timer_interrupt_t +{ + struct _timer_interrupt_t *next; + unsigned long totalTicks; + unsigned long ticksCount; + void (*handler)(void); +} +timer_interrupt_t; + +#define TIMER_INTERRUPT 0x08 + +static timer_interrupt_t *timer_int_handlers = (timer_interrupt_t *)0; +static void (*pfnOldTimerInterrupt)() = (void (*))0; + +static void timerHandler() +{ + timer_interrupt_t *p; + + /* Walk all registered handlers for handlers */ + for (p = timer_int_handlers; p != ((timer_interrupt_t *)0); p = p->next) + { + /* Increment the tick count for each handlers */ + p->ticksCount++; + + /* Call the handler and reset the tickCounts when the function has waited + for totalTicks number of tick count */ + if (p->ticksCount == p->totalTicks) + { + /* Call the function */ + p->handler(); + + /* Reset the tick count */ + p->ticksCount = 0; + } + } + + /* Send EOI to PIC 1 */ + //outp(0x20, 0x20); + +#if 0 + /* Chain to previous handler. Somehow, the chain does not seem to work. + Need further investigation if necessary to chain the interrupt. + It might not be needed in DOS since we only have one process. */ + if (pfnOldTimerInterrupt) + _chain_intr (pfnOldTimerInterrupt); +#endif +} + +static struct sigaction tact; +static struct itimerval value; +static void init_sigaction(void (*handler)(void)) +{ + tact.sa_handler = handler; + tact.sa_flags = 0; + + sigemptyset(&tact.sa_mask); + sigaction(SIGALRM, &tact, NULL); +} + + +static void init_time(struct itimerval *value) +{ + + setitimer(ITIMER_REAL, value, NULL); +} + +/* + * Register interrupt handler + * + * Output: + * 0 - Success + * -1 - Out of memory + * + * Note: + * The interrupt is happens every 55ms, or about 18.2 ticks per second. + */ +short registerTimerHandler( + void (*handler)(void), + unsigned long totalTicks /* Total number of ticks to wait */ +) +{ + timer_interrupt_t *p; + + /* Allocate a new interrupt structure */ + p = (timer_interrupt_t *) malloc(sizeof(timer_interrupt_t)); + if (p == ((timer_interrupt_t *)0)) + { + /* No more memory */ + return(-1); + } + + /* If this is the first interrupt handler, intercept the correct IRQ */ + if (timer_int_handlers == ((timer_interrupt_t *)0)) + { + #if 0 // dos + /* Get the previous ISR for the timer interrupt */ + pfnOldTimerInterrupt = _dos_getvect(TIMER_INTERRUPT); + + /* Install the new timer interrupt handler */ + _dos_setvect (TIMER_INTERRUPT, timerHandler); + + /* Enable the interrupt in Interrupt Mask register */ + outp(0x21, inp(0x21) & ~0x01); + #else // linux + init_sigaction(timerHandler); + value.it_value.tv_sec = 0; + value.it_value.tv_usec = 50000; // 50ms + value.it_interval = value.it_value; + init_time(&value); + #endif + } + + + /* Fill interrupt structure */ + p->next = timer_int_handlers; + p->totalTicks = totalTicks; + p->ticksCount = 0; + p->handler = handler; + timer_int_handlers = p; + + return 0; +} + +/* + * Unregister a registered interrupt handler + * + * Output: + * 0 - Success + * -1 - Handler is not found + */ +short unregisterTimerHandler( + void (*handler)(void) /* Interrupt function to be unregistered from the SM50x interrupt */ +) +{ + timer_interrupt_t *p, *prev; + + /* Find the requested handle to unregister */ + for (p = timer_int_handlers, prev = ((timer_interrupt_t *)0); p != ((timer_interrupt_t *)0); prev = p, p = p->next) + { + if (p->handler == handler) + { + /* Remove the interrupt handler */ + if (prev == ((timer_interrupt_t *)0)) + { + timer_int_handlers = p->next; + } + else + { + prev->next = p->next; + } + free(p); + + /* If this was the last interrupt handler, remove the IRQ handler */ + if (timer_int_handlers == ((timer_interrupt_t *)0)) + { + #if 0 //dos + /* Restore the actual protected mode ISR of the original timer interrupt */ + _dos_setvect(TIMER_INTERRUPT, pfnOldTimerInterrupt); + #else + + value.it_value.tv_sec = 0; + value.it_value.tv_usec = 0; // stop the timer + value.it_interval = value.it_value; + init_time(&value); + //init_sigaction(NULL); + #endif + } + + /* Success */ + return 0; + } + } + + /* Oops, handler is not registered */ + return -1; +} + + +#include +#include +#include +#include +int kbhit(void) +{ + struct termios oldt, newt; + int ch; + int oldf; + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + oldf = fcntl(STDIN_FILENO, F_GETFL, 0); + fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); + ch = getchar(); + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + fcntl(STDIN_FILENO, F_SETFL, oldf); + if(ch != EOF) + { + ungetc(ch, stdin); + return 1; + } + return 0; +} + +/* Get current time in milliseconds. */ +unsigned long getCurrentTime() +{ + time_t now; + struct tm *timenow; + unsigned long milliseconds; + + /* Get the tick count. */ + time(&now); + timenow = localtime(&now); + + milliseconds = (((unsigned long)timenow->tm_hour * 3600 + + (unsigned long)timenow->tm_min * 60 + + (unsigned long)timenow->tm_sec) * 1000); + + return milliseconds; +} + +unsigned char getKeyInput() +{ + unsigned char key; + key = getSingleChar(); + return key; +} + +#endif /* LINUX */ diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_mode.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_mode.c new file mode 100644 index 000000000000..f63405072327 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_mode.c @@ -0,0 +1,1106 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* MODE.C --- SMI DDK +* This file contains the source code for the mode table. +* +*******************************************************************/ +#include "linux/string.h" +#include +#include "ddk770_help.h" +#include "ddk770_reg.h" +#include "ddk770_os.h" +#include "ddk770_chip.h" +#include "ddk770_clock.h" +#include "ddk770_helper.h" +#include "ddk770_power.h" +#include "ddk770_mode.h" +#include "ddk770_ddkdebug.h" + +/* The valid signature of the user data pointer for the setmode function. + The following definition is ASCII representation of the word 'USER' + */ +#define MODE_USER_DATA_SIGNATURE 0x55534552 + + + + + +/* + * Default Timing parameter for some popular modes. + * Note that the most timings in this table is made according to standard VESA + * parameters for the popular modes. + */ + +static cea_parameter_t cea_mode_array[] = { +{1, 640, 160, 16, 96, 480, 45, 10, 2, 60000, 1, 0, 0, 0, 1, CEA_MODE_640x480p_60, 43, 25174999 }, +{2, 720, 138, 16, 62, 480, 45, 9, 6, 60000, 1, 0, 0, 0, 1, CEA_MODE_720x480p_60, 43, 27027000 }, +{3, 720, 138, 16, 62, 480, 45, 9, 6, 60000, 1, 0, 0, 0, 1, CEA_MODE_720x480p_60, 169, 27027000 }, +{4, 1280, 370, 110, 40, 720, 30, 5, 5, 60000, 1, 1, 1, 0, 1, CEA_MODE_1280x720p_60, 169, 74250000 }, +{5, 1920, 280, 88, 44, 540, 22, 2, 5, 60000, 1, 1, 1, 1, 0, CEA_MODE_1920x1080i_60, 169, 74250000 }, +{6, 1440, 276, 38, 124, 240, 22, 4, 3, 60000, 1, 0, 0, 1, 0, CEA_MODE_1440x480i_60, 43, 27027000 }, +{7, 1440, 276, 38, 124, 240, 22, 4, 3, 60000, 1, 0, 0, 1, 0, CEA_MODE_1440x480i_60, 169, 27027000 }, +{8, 1440, 276, 38, 124, 240, 22, 4, 3, 60000, 1, 0, 0, 0, 1, CEA_MODE_1440x240p_60, 43, 27027000 }, +{9, 1440, 276, 38, 124, 240, 22, 4, 3, 60000, 1, 0, 0, 0, 1, CEA_MODE_1440x240p_60, 169, 27027000 }, +{10, 2880, 552, 76, 248, 240, 22, 4, 3, 59940, 1, 0, 0, 1, 0, CEA_MODE_2880x480i_59, 43, 54000000 }, +{11, 2880, 552, 76, 248, 240, 22, 4, 3, 59940, 1, 0, 0, 1, 0, CEA_MODE_2880x480i_60, 169, 54000000 }, +{12, 2880, 552, 76, 248, 240, 22, 4, 3, 59940, 1, 0, 0, 0, 1, CEA_MODE_2880x240p_60, 43, 54000000 }, +{13, 2880, 552, 76, 248, 240, 22, 4, 3, 59940, 1, 0, 0, 0, 1, CEA_MODE_2880x240p_60, 169, 54000000 }, +{14, 1440, 276, 32, 124, 480, 45, 9, 6, 59940, 1, 0, 0, 0, 1, CEA_MODE_1440x480p_60, 43, 54000000 }, +{15, 1440, 276, 32, 124, 480, 45, 9, 6, 59940, 1, 0, 0, 0, 1, CEA_MODE_1440x480p_60, 169, 54000000 }, +{16, 1920, 280, 88, 44, 1080, 45, 4, 5, 60000, 1, 1, 1, 0, 1, CEA_MODE_1920x1080p_60, 169, 148500000 }, +{17, 720, 144, 12, 64, 576, 49, 5, 5, 50000, 1, 0, 0, 0, 1, CEA_MODE_720x576p_50, 43, 27027000 }, +{18, 720, 144, 12, 64, 576, 49, 5, 5, 50000, 1, 0, 0, 0, 1, CEA_MODE_720x576p_50, 169, 27027000 }, +{19, 1280, 700, 440, 40, 720, 30, 5, 5, 50000, 1, 1, 1, 0, 1, CEA_MODE_1280x720p_50, 169, 74250000 }, +{20, 1920, 720, 528, 44, 540, 22, 2, 5, 50000, 1, 1, 1, 1, 0, CEA_MODE_1920x1080i_50, 169, 74250000 }, +{21, 1440, 288, 24, 126, 288, 24, 2, 3, 50000, 1, 0, 0, 1, 0, CEA_MODE_1440x576i_50, 43, 27027000 }, +{22, 1440, 288, 24, 126, 288, 24, 2, 3, 50000, 1, 0, 0, 1, 0, CEA_MODE_1440x576i_50, 169, 27027000 }, +{23, 1440, 288, 24, 126, 288, 24, 2, 3, 50000, 1, 0, 0, 0, 1, CEA_MODE_1440x288p_50, 43, 27027000 }, +{24, 1440, 288, 24, 126, 288, 24, 2, 3, 50000, 1, 0, 0, 0, 1, CEA_MODE_1440x288p_50, 169, 27027000 }, +{25, 2880, 576, 48, 252, 288, 24, 2, 3, 50000, 1, 0, 0, 1, 0, CEA_MODE_2880x576i_50, 43, 54000000 }, +{26, 2880, 576, 48, 252, 288, 24, 2, 3, 50000, 1, 0, 0, 1, 0, CEA_MODE_2880x576i_50, 169, 54000000 }, +{27, 2880, 576, 48, 252, 288, 24, 2, 3, 50000, 1, 0, 0, 0, 1, CEA_MODE_2880x288p_50, 43, 54000000 }, +{28, 2880, 576, 48, 252, 288, 24, 2, 3, 50000, 1, 0, 0, 0, 1, CEA_MODE_2880x288p_50, 169, 54000000 }, +{29, 1440, 288, 24, 128, 576, 49, 5, 5, 50000, 1, 0, 0, 0, 1, CEA_MODE_1440x576p_50, 43, 54000000 }, +{30, 1440, 288, 24, 128, 576, 49, 5, 5, 50000, 1, 0, 0, 0, 1, CEA_MODE_1440x576p_50, 169, 54000000 }, +{31, 1920, 720, 528, 44, 1080, 45, 4, 5, 50000, 1, 1, 1, 0, 1, CEA_MODE_1920x1080p_50, 169, 148500000 }, +{32, 1920, 830, 638, 44, 1080, 45, 4, 5, 24000, 1, 1, 1, 0, 1, CEA_MODE_1920x1080p_24, 169, 74250000 }, +{33, 1920, 720, 528, 44, 1080, 45, 4, 5, 25000, 1, 1, 1, 0, 1, CEA_MODE_1920x1080p_25, 169, 74250000 }, +{34, 1920, 280, 88, 44, 1080, 45, 4, 5, 30000, 1, 1, 1, 0, 1, CEA_MODE_1920x1080p_30, 169, 74250000 }, +{35, 2880, 552, 64, 248, 480, 45, 9, 6, 59940, 1, 0, 0, 0, 1, CEA_MODE_2880x480p_59, 43, 108000000 }, +{36, 2880, 552, 64, 248, 480, 45, 9, 6, 60000, 1, 0, 0, 0, 1, CEA_MODE_2880x480p_60, 169, 108000000 }, +{37, 2880, 576, 48, 256, 576, 49, 5, 5, 50000, 1, 0, 0, 0, 1, CEA_MODE_2880x576p_60, 43, 108000000 }, +{38, 2880, 576, 48, 256, 576, 49, 5, 5, 50000, 1, 0, 0, 0, 1, CEA_MODE_2880x576p_60, 169, 108000000 }, +{39, 1920, 384, 32, 168, 540, 85, 23, 5, 50000, 1, 1, 0, 0, 0, CEA_MODE_1920x1080i_50, 169, 74250000 }, +{40, 1920, 720, 528, 44, 540, 22, 2, 5, 100000, 1, 1, 1, 1, 0, CEA_MODE_1920x1080i_100, 169, 148500000 }, +{41, 1280, 700, 440, 40, 720, 30, 5, 5, 100000, 1, 1, 1, 0, 1, CEA_MODE_1280x720p_100, 169, 148500000 }, +{42, 720, 144, 12, 64, 576, 49, 5, 5, 100000, 1, 0, 0, 0, 1, CEA_MODE_720x576p_100, 43, 54000000 }, +{43, 720, 144, 12, 64, 576, 49, 5, 5, 100000, 1, 0, 0, 0, 1, CEA_MODE_720x576p_100, 169, 54000000 }, +{44, 1440, 288, 24, 126, 288, 24, 2, 3, 100000, 1, 0, 0, 1, 0, CEA_MODE_1440x576i_100, 43, 54000000 }, +{45, 1440, 288, 24, 126, 288, 24, 2, 3, 100000, 1, 0, 0, 1, 0, CEA_MODE_1440x576i_100, 169, 54000000 }, +{46, 1920, 288, 88, 44, 540, 22, 2, 5, 120000, 1, 1, 1, 1, 0, CEA_MODE_1920x1080i_120, 169, 148500000 }, +{47, 1280, 370, 110, 40, 720, 30, 5, 5, 120000, 1, 1, 1, 0, 1, CEA_MODE_1280x720p_120, 169, 148500000 }, +{48, 720, 138, 16, 62, 480, 45, 9, 6, 120000, 1, 0, 0, 0, 1, CEA_MODE_720x480p_120, 43, 54000000 }, +{49, 720, 138, 16, 62, 480, 45, 9, 6, 120000, 1, 0, 0, 0, 1, CEA_MODE_720x480p_120, 169, 54000000 }, +{50, 1440, 276, 38, 124, 240, 22, 4, 3, 120000, 1, 0, 0, 1, 0, CEA_MODE_1440x480i_120, 43, 54000000 }, +{51, 1440, 276, 38, 124, 240, 22, 4, 3, 120000, 1, 0, 0, 1, 0, CEA_MODE_1440x480i_120, 169, 54000000 }, +{52, 720, 144, 12, 64, 576, 49, 5, 5, 200000, 1, 0, 0, 0, 1, CEA_MODE_720x480i_0, 0, 108000000 }, +{53, 720, 144, 12, 64, 576, 49, 5, 5, 200000, 1, 0, 0, 0, 1, CEA_MODE_720x480i_0, 0, 108000000 }, +{54, 1440, 288, 24, 126, 288, 24, 2, 3, 200000, 1, 0, 0, 1, 0, CEA_MODE_1440x576i_200, 43, 108000000 }, +{55, 1440, 288, 24, 126, 288, 24, 2, 3, 200000, 1, 0, 0, 1, 0, CEA_MODE_1440x576i_200, 169, 108000000 }, +{56, 720, 138, 16, 62, 480, 45, 9, 6, 240000, 1, 0, 0, 0, 1, CEA_MODE_720x480p_240, 43, 108000000 }, +{57, 720, 138, 16, 62, 480, 45, 9, 6, 240000, 1, 0, 0, 0, 1, CEA_MODE_720x480p_240, 169, 108000000 }, +{58, 1440, 276, 38, 124, 240, 22, 4, 3, 240000, 1, 0, 0, 1, 0, CEA_MODE_1440x480i_240, 43, 108000000 }, +{59, 1440, 276, 38, 124, 240, 22, 4, 3, 240000, 1, 0, 0, 1, 0, CEA_MODE_1440x480i_240, 169, 108000000 }, +{60, 1280, 2020, 1760, 40, 720, 30, 5, 5, 24000, 1, 1, 1, 0, 1, CEA_MODE_1280x720p_24, 169, 54000000 }, +{61, 1280, 2680, 2420, 40, 720, 30, 5, 5, 24000, 1, 1, 1, 0, 1, CEA_MODE_1280x720p_25, 169, 74250000 }, +{62, 1280, 2020, 1760, 40, 720, 30, 5, 5, 30000, 1, 1, 1, 0, 1, CEA_MODE_1280x720p_30, 169, 74250000 }, +{63, 1920, 280, 88, 44, 1080, 45, 4, 5, 120000, 1, 1, 1, 0, 1, CEA_MODE_1920x1080p_120, 169, 297000000 }, +{64, 1920, 720, 528, 44, 1080, 45, 4, 5, 100000, 1, 1, 1, 0, 1, CEA_MODE_1920x1080p_100, 169, 297000000 }, +{95, 3840, 560, 176, 88, 2160, 90, 8, 10, 30000, 1, 1, 1, 0, 1, CEA_MODE_3840x2160p_30, 169, 297000000 }, +{94, 3840, 1440, 1056, 88, 2160, 90, 8, 10, 25000, 1, 1, 1, 0, 1, CEA_MODE_3840x2160p_25, 169, 297000000 }, +{93, 3840, 1660, 1276, 88, 2160, 90, 8, 10, 24000, 1, 1, 1, 0,1, CEA_MODE_3840x2160p_24, 169, 297000000 }, +{96, 3840, 1440, 1056, 88, 2160, 90, 9, 10, 50000, 1, 1, 1, 0, 1, CEA_MODE_3840x2160p_50, 169, 594000000 }, +{97, 3840, 560, 176, 88, 2160, 90, 8, 10, 60000, 1, 1, 1, 0, 1, CEA_MODE_3840x2160p_60, 169, 594000000 }, +{98, 4096, 1404, 1024, 88, 2160, 90, 8, 10, 24000, 1, 1, 1, 0, 1, CEA_MODE_4096x2160p_24, 169, 297000000 }, +{102, 4096, 304, 88, 88, 2160, 90, 8, 10, 24000, 1, 1, 1, 0, 1, CEA_MODE_4096x2160p_60, 169, 600000000 }, +{4, 1024, 344, 160, 136, 768, 30, 6, 23, 60000, 1, 1, 1, 0, 1, CEA_MODE_1024x768p_60, 43, 65000000 }, +{4, 800, 128, 16, 96, 600, 29, 2, 2, 60000, 1, 1, 1, 0, 1, CEA_MODE_800x600p_60, 43, 25175000 }, +{0, 2560, 160, 48, 32, 1440, 21, 3, 5, 60000, 1, 1, 1, 0, 1, CEA_MODE_2560x1440p_60, 169, 245250000 }, +{0, 2560, 160, 48, 32, 1440, 41, 3, 5, 144000, 1, 1, 1, 0, 1, CEA_MODE_2560x1440p_144,169, 580000000 }, + +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} +}; + + +static mode_parameter_t gDefaultModeParamTable[] = +{ +/* cea mode */ + + /* 640 x 480 [4:3] vic 1*/ + { 800, 640, 656, 96, NEG, 525, 480, 490, 2, NEG, 25175000, 31469, 60, NEG}, + + /* 720 x 480 [4:3]/[16:9] vic 2/3*/ + { 858, 720, 736, 62, NEG, 525, 480, 489, 6, NEG, 27000000, 31469, 60, NEG}, + + /* 1280 x 720 [16:9] vic 4*/ + { 1650, 1280, 1390, 40, POS, 750, 720, 725, 5, POS, 74250000, 45000, 60, NEG}, + + /* 1440 x 480 [4:3]/[16:9] vic 14/15 */ + { 1716, 1440, 1472, 124, NEG, 525, 480, 489, 6, NEG, 54000000, 31469, 60, NEG}, + + /* 1920 x 1080 [16:9] vic 16*/ + { 2200, 1920, 2008, 44, POS, 1125, 1080, 1084, 5, POS, 148500000, 67500, 60, NEG}, + + /* 720 x 576 [4:3]/[16:9] vic 17/18 */ + { 864, 720, 732, 64, NEG, 625, 576, 581, 5, NEG, 27000000, 31250, 50, NEG}, + + /* 1280 x 720 [16:9] vic 19*/ + { 1980, 1280, 1720, 40, POS, 750, 720, 725, 5, POS, 74250000, 37500, 50, NEG}, + + /* 1920 x 1080 [16:9] vic 31*/ + { 2640, 1920, 2448, 44, POS, 1125, 1080, 1084, 5, POS, 148500000, 56250, 50, NEG}, + + /* 1920 x 1080 [16:9] vic 34*/ + { 2200, 1920, 2008, 44, POS, 1125, 1080, 1084, 5, POS, 74250000, 33750, 30, NEG}, + + /* 2880 x 480 [4:3]/[16:9] vic 35/36 */ + { 3432, 2880, 2944, 248, NEG, 525, 480, 489, 6, NEG, 108000000, 31469, 60, NEG}, + + /* 1280 x 720 [16:9] vic 41*/ + { 1980, 1280, 1720, 40, POS, 750, 720, 725, 5, POS, 148500000, 45000, 100, NEG}, + + /* 720 x 480 [16:9] vic 49*/ + { 858, 720, 736, 62, NEG, 525, 480, 489, 6, NEG, 54000000, 62937, 120, NEG}, + + /* 1280 x 720 [16:9] vic 62*/ + { 3300, 1280, 3040, 40, POS, 750, 720, 725, 5, POS, 74250000, 22500, 30, NEG}, + + /* 1920 x 1080 [16:9] vic 63*/ + { 2200, 1920, 2008, 44, POS, 1125, 1080, 1084, 5, POS, 297000000, 135000, 120, NEG}, + + /* 1920 x 1080 [16:9] vic 64*/ + { 2640, 1920, 2448, 44, POS, 1125, 1080, 1084, 5, POS, 297000000, 112500, 100, NEG}, + + /* 2560 x 1080 [64:27] vic 88*/ + { 3520, 2560, 3328, 44, POS, 1125, 1080, 1084, 5, POS, 118800000, 33750, 30, NEG}, + + /* 2560 x 1080 [64:27] vic 90*/ + { 3000, 2560, 2808, 44, POS, 1100, 1080, 1084, 5, POS, 198000000, 66000, 60, NEG}, + + /* 3840 x 2160 [16:9] vic 95*/ + { 4400, 3840, 4016, 88, POS, 2250, 2160, 2168, 10, POS, 297000000, 67500, 30, NEG}, + + /* 3840 x 2160 [16:9] vic 96*/ + { 5280, 3840, 4896, 88, POS, 2250, 2160, 2168, 10, POS, 594000000, 112500, 50, NEG}, + + /* 3840 x 2160 [16:9] vic 97*/ + { 4400, 3840, 4016, 88, POS, 2250, 2160, 2168, 10, POS, 594000000, 135000, 60, NEG}, + +/* other mode Vesa/gtf*/ + /* 640 x 480 [4:3] */ + { 840, 640, 656, 64, NEG, 500, 480, 481, 3, NEG, 31500000, 37500, 75, NEG}, + { 832, 640, 696, 56, NEG, 509, 480, 481, 3, NEG, 36000000, 43269, 85, NEG}, + + /* 720 x 540 [4:3] -- Not a popular mode */ + { 886, 720, 740, 96, POS, 576, 540, 545, 2, POS, 30600000, 34537, 60, NEG}, + + /* 720 x 576 [4:3] */ + + { 912, 720, 744, 96, POS, 597, 576, 580, 1, NEG, 32670000, 35820, 60, POS}, + + /* 800 x 480 [5:3] -- Not a popular mode */ + /* { 973, 800, 822, 56, POS, 524, 480, 490, 2, NEG, 30600000, 31449, 60, NEG}, //By Daniel for Futaba */ + {1056, 800, 1000, 10, NEG, 525, 480, 492, 10, NEG, 33300000, 31534, 60, POS }, + + /* 800 x 600 [4:3] */ + {1056, 800, 840,128, POS, 628, 600, 601, 4, POS, 40000000, 37879, 60, NEG}, + {1056, 800, 816, 80, POS, 625, 600, 601, 3, POS, 49500000, 46875, 75, NEG}, + {1048, 800, 832, 64, POS, 631, 600, 601, 3, POS, 56250000, 53674, 85, NEG}, + + /* 960 x 720 [4:3] -- Not a popular mode */ + {1245, 960, 992, 64, POS, 750, 720, 721, 3, POS, 56000000, 44980, 60, NEG}, + + /* 1024 x 600 [16:9] 1.7 */ + {1313,1024,1064,104, POS, 622, 600, 601, 3, POS, 49000000, 37319, 60, NEG}, + + /* 1024 x 768 [4:3] */ + {1344,1024,1048,136, NEG, 806, 768, 771, 6, NEG, 65000000, 48363, 60, NEG}, + {1312,1024,1040, 96, POS, 800, 768, 769, 3, POS, 78750000, 60023, 75, NEG}, + {1376,1024,1072, 96, POS, 808, 768, 769, 3, POS, 94500000, 68677, 85, NEG}, + + /* 1152 x 864 [4:3] -- Widescreen eXtended Graphics Array */ + {1475,1152,1208, 96, POS, 888, 864, 866, 3, POS, 78600000, 53288, 60, NEG}, + {1600,1152,1216,128, POS, 900, 864, 865, 3, POS,108000000, 67500, 75, NEG}, + + /* 1280 x 768 [5:3] -- Not a popular mode */ + {1664, 1280, 1344, 128, NEG, 798, 768, 771, 7, POS, 79500000, 47776, 60, NEG}, + + /* 1280 x 800 [8:5] -- Not a popular mode */ + {1680, 1280, 1352, 128, NEG, 831, 800, 803, 6, POS, 83500000, 49702, 60, NEG}, + + /* 1280 x 960 [4:3] */ + {1800,1280,1376,112, POS,1000, 960, 961, 3, POS,108000000, 60000, 60, NEG}, + {1728,1280,1344,160, POS,1011, 960, 961, 3, POS,148500000, 85938, 85, NEG}, + + /* 1280 x 1024 [5:4] */ + /* VESA Standard */ + {1688,1280,1328,112, POS,1066,1024,1025, 3, POS,108000000, 63981, 60, NEG}, + {1688,1280,1296,144, POS,1066,1024,1025, 3, POS,135000000, 79976, 75, NEG}, + {1728,1280,1344,160, POS,1072,1024,1025, 3, POS,157500000, 91146, 85, NEG}, + + /* 1360 x 768 [16:9] */ + {1792, 1360, 1424, 112, POS, 795, 768, 771, 6, POS, 85500000, 47712, 60, NEG}, + + /* 1366 x 768 [16:9] */ + /* Previous Calculation */ + {1792, 1366, 1436, 143, POS, 798, 768, 771, 3, POS, 85750000, 47852, 60, NEG}, + + /* 1400 x 1050 [4:3] */ + {1864, 1400, 1488, 144, NEG, 1089, 1050, 1053, 4, POS, 121750000, 65317, 60, NEG}, + + /* 1440 x 900 [8:5] -- Widescreen Super eXtended Graphics Array (WSXGA) */ + {1904, 1440, 1520, 152, NEG, 934, 900, 903, 6, POS, 106500000, 55935, 60, NEG}, + + /* 1440 x 960 [3:2] -- Not a popular mode */ + {1920,1440,1528,152, POS, 994, 960, 961, 3, POS,114509000, 59640, 60, NEG}, + + /* 1600 x 900 [16:9] -- ViewSonic VS2033-LED */ + {1800, 1600, 1624, 80, POS, 1000, 900, 901, 3, POS, 108000000, 60000, 60, POS}, + + /* 1600 x 1200 [4:3]. -- Ultra eXtended Graphics Array */ + /* VESA */ + {2160, 1600, 1664, 192, POS, 1250, 1200, 1201, 3, POS, 162000000, 75000, 60, NEG}, + {2160, 1600, 1664, 192, POS, 1250, 1200, 1201, 3, POS, 202500000, 93750, 75, NEG}, + {2160, 1600, 1664, 192, POS, 1250, 1200, 1201, 3, POS, 229500000, 106250, 85, NEG}, + + /* 1680 x 1050 [8:5]. -- Widescreen Super eXtended Graphics Array Plus (WSXGA+) */ + {2240, 1680, 1784, 176, NEG, 1089, 1050, 1053, 6, POS, 146250000, 65290, 60, NEG}, + {2272, 1680, 1800, 176, NEG, 1099, 1050, 1053, 6, POS, 187000000, 82306, 75, NEG}, + + /* 1792 x 1344 [4:3]. -- Not a popular mode */ + {2448, 1792, 1920, 200, NEG, 1394, 1344, 1345, 3, POS, 204750000, 836640, 60, NEG}, + + /* 1856 x 1392 [4:3]. -- Not a popular mode + The 1856 x 1392 @ 75Hz has not been tested due to high Horizontal Frequency + where not all monitor can support it (including the developer monitor) + */ + {2528, 1856, 1952, 224, NEG, 1439, 1392, 1393, 3, POS, 218250000, 86333, 60, NEG}, + //{2560, 1856, 1984, 224, NEG, 1500, 1392, 1393, 3, POS, 288000000, 112500, 75, NEG}, + + {2640, 1920, 2448, 44, POS, 1125, 1080, 1084, 5, POS, 148500000, 56250, 50, NEG}, + + /* 1920 x 1200 [8:5]. -- Widescreen Ultra eXtended Graphics Array (WUXGA) */ + //{2592, 1920, 2048, 208, NEG, 1242, 1200, 1201, 3, POS, 193160000, 74522, 60, NEG}, + {2592, 1920, 2056, 200, NEG, 1245, 1200, 1203, 6, POS, 193250000, 74556, 60, NEG}, + + /* 1920 x 1440 [4:3]. */ + /* In the databook, it mentioned only support up to 1920x1440 @ 60Hz. + The timing for 75 Hz is provided here if necessary to do testing. - Some underflow + has been noticed. */ + {2600,1920,2048,208, NEG,1500,1440,1441, 3, POS,234000000, 90000, 60, NEG}, + /* {2640,1920,2064,224, NEG,1500,1440,1441, 3, POS,297000000,112500, 75, NEG}, */ + + /* 2160 x 1200 for HTC_VIVE.*/ + {2260,2160,2200,20, NEG,1464,1200,1228, 2, NEG,297000000, 131000, 90, NEG}, + + /*2K@120hz*/ + {2720,2560,2608,32, POS,1525,1440,1443, 5, POS,497750000, 182996, 120, NEG}, + /* 2560 * 1440 60 */ + {2720,2560,2608,32, POS,1481,1440,1443, 5, POS,241500000, 88000, 60, NEG}, + /* 2560 * 1440 144 */ + {2720,2560,2608,32, POS,1481,1440,1443, 5, POS,586000000, 213200, 144, NEG}, + /*3840x1080@60*/ + {3920,3840,3848,32, POS,1111,1080,1097, 8,POS,261307000, 66660, 60, POS}, + + /*3840x1080@120*/ + {4000,3840,3888,64, POS,1144,1080,1083, 10,POS,549000000, 137250, 120, POS}, + + /*3440x1440@60*/ + {3600, 3440, 3488, 32, POS, 1481, 1440, 1443, 10, NEG, 319750000, 88819, 60, POS}, + /*3440x1440@100*/ + {3600, 3440, 3488, 64, NEG, 1490, 1440, 1443, 10, POS, 536400000, 149000, 100, POS}, + // {3760, 3440, 3488, 64, NEG, 1540, 1440, 1443, 10, POS, 536400000, 149000, 100, POS}, + //add vblank and hblank for 100hz,add sync time and then have voice + //{3760, 3440, 3488, 64, NEG, 1540, 1440, 1443, 10, POS, 536400000, 149000, 100, POS}, + /*3440x1440@75*/ + {3600, 3440, 3488, 64, POS, 1492, 1440, 1443, 10, NEG, 402750000, 111875, 75, POS}, + /* End of table. */ + { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, +}; + + +static mode_parameter_t gChannel0ModeParamTable[MAX_MODE_TABLE_ENTRIES] = +{ + /* End of table */ + { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, +}; + +static mode_parameter_t gChannel1ModeParamTable[MAX_MODE_TABLE_ENTRIES] = +{ + /* End of table */ + { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, +}; + +static mode_parameter_t gChannel2ModeParamTable[MAX_MODE_TABLE_ENTRIES] = +{ + /* End of table */ + { 0, 0, 0, 0, NEG, 0, 0, 0, 0, NEG, 0, 0, 0, NEG}, +}; + + +/* Static variable to store the mode information. */ +static mode_parameter_t gChannel0CurrentModeParam; +static mode_parameter_t gChannel1CurrentModeParam; +static mode_parameter_t gChannel2CurrentModeParam; + +/* + * ddk770_getUserDataSignature + * This function gets the user data mode signature + * + * Output: + * The signature to be filled in the user_data_mode_t structure to be considered + * a valid structure. + */ +unsigned long ddk770_getUserDataSignature() +{ + return MODE_USER_DATA_SIGNATURE; +} + +/* + * ddk770_compareModeParam + * This function compares two mode parameters + * + * Input: + * pModeParam1 - Pointer to the first mode parameter to be compared + * pModeParam2 - Pointer to the second mode parameter to be compared + * + * Output: + * 0 - Identical mode + * -1 - Mode is not identical + */ +long ddk770_compareModeParam( + mode_parameter_t *pModeParam1, + mode_parameter_t *pModeParam2 +) +{ + if ((pModeParam1 != (mode_parameter_t *)0) && + (pModeParam2 != (mode_parameter_t *)0)) + { + if (memcmp((void *)pModeParam1, (void *)pModeParam2, sizeof(mode_parameter_t)) == 0) + return 0; + } + + return (-1); +} + +/* + * ddk770_getDuplicateModeIndex + * This function retrieves the index of dupicate modes, but having different timing. + * + * Input: + * dispCtrl - Display Control where the mode table belongs to. + * pModeParam - The mode parameters which index to be checked. + * + * Output: + * The index of the given parameters among the duplicate modes. + * 0 means that the mode param is the first mode encountered in the table + * 1 means that the mode param is the second mode encountered in the table + * etc... + */ +__attribute__((unused)) static unsigned short ddk770_getDuplicateModeIndex( + disp_control_t dispCtrl, + mode_parameter_t *pModeParam +) +{ + unsigned short index, modeIndex; + mode_parameter_t *pModeTable; + + /* Get the mode table */ + pModeTable = ddk770_getStockModeParamTableEx(dispCtrl); + + /* Search the current mode */ + modeIndex = 0; + index = 0; + while (pModeTable[modeIndex].pixel_clock != 0) + { + if ((pModeTable[modeIndex].horizontal_display_end == pModeParam->horizontal_display_end) && + (pModeTable[modeIndex].vertical_display_end == pModeParam->vertical_display_end) && + (pModeTable[modeIndex].vertical_frequency == pModeParam->vertical_frequency)) + { + /* Check if this is the same/identical mode param. */ + if (ddk770_compareModeParam(&pModeTable[modeIndex], pModeParam) == 0) + break; + + /* Increment the index */ + index++; + } + modeIndex++; + } + + return index; +} + +/* + * ddk770_findModeParamFromTable + * This function locates the requested mode in the given parameter table + * + * Input: + * width - Mode width + * height - Mode height + * refresh_rate - Mode refresh rate + * index - Index that is used for multiple search of the same mode + * that have the same width, height, and refresh rate, + * but have different timing parameters. + * + * Output: + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *ddk770_findModeParamFromTable( + unsigned long width, + unsigned long height, + unsigned long refresh_rate, + unsigned short index, + mode_parameter_t *pModeTable +) +{ + unsigned short modeIndex = 0, tempIndex = 0; + + /* Walk the entire mode table. */ + while (pModeTable[modeIndex].pixel_clock != 0) + { + if (((width == (unsigned long)(-1)) || (pModeTable[modeIndex].horizontal_display_end == width)) && + ((height == (unsigned long)(-1)) || (pModeTable[modeIndex].vertical_display_end == height)) && + ((refresh_rate == (unsigned long)(-1)) || (pModeTable[modeIndex].vertical_frequency == refresh_rate))) + { + if (tempIndex < index) + tempIndex++; + else + return (&pModeTable[modeIndex]); + } + + /* Next entry */ + modeIndex++; + } + + /* No match, return NULL pointer */ + return((mode_parameter_t *)0); +} + +/* + * Locate in-stock parameter table for the requested mode. + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *ddk770_findModeParam( + disp_control_t dispCtrl, + unsigned long width, + unsigned long height, + unsigned long refresh_rate, + unsigned short index +) +{ + return ddk770_findModeParamFromTable(width, height, refresh_rate, index, ddk770_getStockModeParamTableEx(dispCtrl)); +} + +/* + * Use the + * Locate timing parameter for the requested mode from the default mode table. + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *ddk770_findVesaModeParam( + unsigned long width, + unsigned long height, + unsigned long refresh_rate +) +{ + return ddk770_findModeParamFromTable(width, height, refresh_rate, 0, gDefaultModeParamTable); +} + +/* + * (Obsolete) + * Return a point to the gDefaultModeParamTable. + * Function in other files used this to get the mode table pointer. + */ +mode_parameter_t *ddk770_getStockModeParamTable() +{ + return(gDefaultModeParamTable); +} + +/* + * (Obsolete) + * Return the size of the Stock Mode Param Table + */ +unsigned long ddk770_getStockModeParamTableSize() +{ + return (sizeof(gDefaultModeParamTable) / sizeof(mode_parameter_t) - 1); +} + +/* + * ddk770_getStockModeParamTableEx + * This function gets the mode parameters table associated to the + * display control (CHANNEL0_CTRL or SECONDAR_CTRL). + * + * Input: + * dispCtrl - Display Control of the mode table that is associated to. + * + * Output: + * Pointer to the mode table + */ +mode_parameter_t *ddk770_getStockModeParamTableEx( + disp_control_t dispCtrl +) +{ + mode_parameter_t *pModeTable; + + if (dispCtrl == CHANNEL0_CTRL) + pModeTable = (mode_parameter_t *)gChannel0ModeParamTable; + else if (dispCtrl == CHANNEL1_CTRL) + pModeTable = (mode_parameter_t *)gChannel1ModeParamTable; + else + pModeTable = (mode_parameter_t *)gChannel1ModeParamTable; + + /* Check if the table exist by checking the first entry. + If it doesn't, then use the default mode table. */ + + if (pModeTable->pixel_clock == 0) + { + pModeTable = ddk770_getStockModeParamTable(); + } + + return (pModeTable); +} + +/* + * ddk770_getStockModeParamTableSizeEx + * This function gets the size of the mode parameter table associated with + * specific display control + * + * Input: + * dispCtrl - Display control of the mode param table that is associated to. + * + * Output: + * Size of the requeted mode param table. + */ +unsigned long ddk770_getStockModeParamTableSizeEx( + disp_control_t dispCtrl +) +{ + unsigned long tableSize; + mode_parameter_t *pModeTable; + + /* Get the mode table */ + pModeTable = ddk770_getStockModeParamTableEx(dispCtrl); + + /* Calculate the table size by finding the end of table entry indicated by all zeroes. */ + tableSize = 0; + while (pModeTable[tableSize].pixel_clock != 0) + tableSize++; + + return tableSize; +} + +/* + * ddk770_getMaximumModeEntries + * This function gets the maximum entries that can be stored in the mode table. + * + * Output: + * Total number of maximum entries + */ +unsigned long ddk770_getMaximumModeEntries() +{ + return MAX_MODE_TABLE_ENTRIES; +} + +/* + * This function returns the current mode. + */ +mode_parameter_t ddk770_getCurrentModeParam( + disp_control_t dispCtrl +) +{ + if (dispCtrl == CHANNEL0_CTRL) + return gChannel0CurrentModeParam; + else if (dispCtrl == CHANNEL1_CTRL) + return gChannel1CurrentModeParam; + else + return gChannel2CurrentModeParam; +} + +/* + * ddk770_addTiming + * This function adds the SM750 mode parameter timing to the specified mode table + * + * Input: + * dispCtrl - Display control where the mode will be associated to + * pNewModeList - Pointer to a list table of SM750 mode parameter to be added + * to the current specified display control mode table. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_addTiming( + disp_control_t dispCtrl, + mode_parameter_t *pNewModeList, + unsigned long totalList, + unsigned char clearTable +) +{ + mode_parameter_t *pModeParamTable; + unsigned char index; + long returnValue = 0; + + /* Get the correct table */ + if (dispCtrl == CHANNEL0_CTRL) + pModeParamTable = (mode_parameter_t *)gChannel0ModeParamTable; + else if(dispCtrl == CHANNEL1_CTRL) + pModeParamTable = (mode_parameter_t *)gChannel1ModeParamTable; + else + pModeParamTable = (mode_parameter_t *)gChannel2ModeParamTable; + if (clearTable == 0) + { + /* Find the last index where the timing will be added to */ + index = 0; + while(pModeParamTable[index].pixel_clock != 0) + index++; + } + else + { + /* Clear and reset the mode table first */ + for (index = 0; index < MAX_MODE_TABLE_ENTRIES; index++) + memset((void*)&pModeParamTable[index], 0, sizeof(mode_parameter_t)); + + /* Reset index */ + index = 0; + } + + /* Update the number of modes those can be added to the current table. */ + if (totalList > (unsigned long)(MAX_MODE_TABLE_ENTRIES - index)) + totalList = (unsigned long)(MAX_MODE_TABLE_ENTRIES - index); + else + returnValue = (-1); + + /* Check if totalList is 0, which means that the table is full. */ + if (totalList == 0) + returnValue = (-1); + + /* Add the list of modes provided by the caller */ + while (totalList--) + { + memcpy((void *)&pModeParamTable[index], (void *)&pNewModeList[index], sizeof(mode_parameter_t)); + index++; + } + + return returnValue; +} + +/* + * This function sets the display base address + * + * Input: + * dispControl - display control of which base address to be set. + * ulBaseAddress - Base Address value to be set. + */ +void ddk770_setDisplayBaseAddress( + disp_control_t dispControl, + unsigned long ulBaseAddress +) +{ + unsigned long regFB; + + regFB = FB_ADDRESS + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + + /* Frame buffer base for this mode */ + pokeRegisterDWord(regFB, + FIELD_SET(0, FB_ADDRESS, STATUS, PENDING) + | FIELD_VALUE(0, FB_ADDRESS, ADDRESS, ulBaseAddress)); +} + +/* + * This function checks if change of "display base address" has effective. + * Change of DC base address will not effective until next VSync, SW sets pending bit to 1 during address change. + * HW resets pending bit when it starts to use the new address. + * + * Input: + * dispControl - display control of which display status to be retrieved. + * + * Output: + * 1 - Display is pending + * 0 - Display is not pending + */ +long ddk770_isDisplayBasePending( + disp_control_t dispControl +) +{ + unsigned long regFB; + + regFB = FB_ADDRESS + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + + if (FIELD_VAL_GET(peekRegisterDWord(regFB), FB_ADDRESS, STATUS) == FB_ADDRESS_STATUS_PENDING) + return 1; + + return (0); +} + + + +/* + * Program the hardware for a specific video mode + * + * return: + * 0 = success + * -1 = fail. + */ +static long ddk770_programModeRegisters( +logicalMode_t *pLogicalMode, +mode_parameter_t *pModeParam, /* mode information about pixel clock, horizontal total, etc. */ +pll_value_t *pPLL /* Pre-calculated values for the PLL */ +) +{ + unsigned long ulTmpValue; + unsigned long paletteRam; + unsigned long offset, pllReg; + unsigned long LineOffset; + + LineOffset = alignLineOffset(pLogicalMode->pitch); + + + /* Make sure normal display channel is used, not VGA channel */ + pokeRegisterDWord(VGA_CONFIGURATION, + FIELD_SET(0, VGA_CONFIGURATION, PLL, PANEL) + | FIELD_SET(0, VGA_CONFIGURATION, MODE, GRAPHIC)); + + offset = (pLogicalMode->dispCtrl > 1)? CHANNEL_OFFSET2 : pLogicalMode->dispCtrl * CHANNEL_OFFSET; + if(pLogicalMode->dispCtrl==CHANNEL0_CTRL) + pllReg = VCLK_PLL; + else if (pLogicalMode->dispCtrl==CHANNEL1_CTRL) + pllReg = VCLK1_PLL; + else + pllReg = VCLK2_PLL; + + /* Program PLL */ + + SetPllReg(pllReg,pPLL); + + + + /* Frame buffer base */ + pokeRegisterDWord((FB_ADDRESS+offset), + FIELD_SET(0, FB_ADDRESS, STATUS, PENDING) + | FIELD_VALUE(0, FB_ADDRESS, ADDRESS, pLogicalMode->baseAddress)); + + /* Pitch value (Hardware people calls it Offset) */ + pokeRegisterDWord((FB_WIDTH+offset), + FIELD_VALUE(0, FB_WIDTH, WIDTH, pLogicalMode->pitch) + | FIELD_VALUE(0, FB_WIDTH, OFFSET, LineOffset)); + + pokeRegisterDWord((HORIZONTAL_TOTAL+offset), + FIELD_VALUE(0, HORIZONTAL_TOTAL, TOTAL, pModeParam->horizontal_total - 1) + | FIELD_VALUE(0, HORIZONTAL_TOTAL, DISPLAY_END, pModeParam->horizontal_display_end - 1)); + + pokeRegisterDWord((HORIZONTAL_SYNC+offset), + FIELD_VALUE(0, HORIZONTAL_SYNC, WIDTH, pModeParam->horizontal_sync_width) + | FIELD_VALUE(0, HORIZONTAL_SYNC, START, pModeParam->horizontal_sync_start - 1)); + + + pokeRegisterDWord((VERTICAL_TOTAL+offset), + FIELD_VALUE(0, VERTICAL_TOTAL, TOTAL, pModeParam->vertical_total - 1) + | FIELD_VALUE(0, VERTICAL_TOTAL, DISPLAY_END, pModeParam->vertical_display_end - 1)); + + pokeRegisterDWord((VERTICAL_SYNC+offset), + FIELD_VALUE(0, VERTICAL_SYNC, HEIGHT, pModeParam->vertical_sync_height) + | FIELD_VALUE(0, VERTICAL_SYNC, START, pModeParam->vertical_sync_start - 1)); + + /* Set control register value */ + ulTmpValue = peekRegisterDWord(DISPLAY_CTRL+offset) + & FIELD_CLEAR(DISPLAY_CTRL, DPMS) + & FIELD_CLEAR(DISPLAY_CTRL, DATA_PATH) + & FIELD_CLEAR(DISPLAY_CTRL, CLOCK_PHASE) + & FIELD_CLEAR(DISPLAY_CTRL, VSYNC_PHASE) + & FIELD_CLEAR(DISPLAY_CTRL, HSYNC_PHASE) + & FIELD_CLEAR(DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK) + & FIELD_CLEAR(DISPLAY_CTRL, COLOR_KEY) + & FIELD_CLEAR(DISPLAY_CTRL, TIMING) + & FIELD_CLEAR(DISPLAY_CTRL, PLANE) + & FIELD_CLEAR(DISPLAY_CTRL, FORMAT); + + ulTmpValue |= + FIELD_SET(0, DISPLAY_CTRL, DATA_PATH, EXTENDED) + | (pModeParam->clock_phase_polarity == POS + ? FIELD_SET(0, DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_HIGH) + : FIELD_SET(0, DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_LOW)) + | (pModeParam->vertical_sync_polarity == POS + ? FIELD_SET(0, DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_HIGH) + : FIELD_SET(0, DISPLAY_CTRL, VSYNC_PHASE, ACTIVE_LOW)) + | (pModeParam->horizontal_sync_polarity == POS + ? FIELD_SET(0, DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_HIGH) + : FIELD_SET(0, DISPLAY_CTRL, HSYNC_PHASE, ACTIVE_LOW)) + | FIELD_SET(0, DISPLAY_CTRL, TIMING, ENABLE) + | FIELD_SET(0, DISPLAY_CTRL, PLANE, ENABLE) + | (pLogicalMode->bpp == 8 + ? FIELD_SET(0, DISPLAY_CTRL, FORMAT, 8) + : (pLogicalMode->bpp == 16 + ? FIELD_SET(0, DISPLAY_CTRL, FORMAT, 16) + : FIELD_SET(0, DISPLAY_CTRL, FORMAT, 32))); + + pokeRegisterDWord((DISPLAY_CTRL+offset), ulTmpValue); + + /* Palette RAM. */ + paletteRam = PALETTE_RAM + offset; + + /* Save the current mode param */ + if (pLogicalMode->dispCtrl == CHANNEL0_CTRL) + gChannel0CurrentModeParam = *pModeParam; + else if(pLogicalMode->dispCtrl == CHANNEL1_CTRL) + gChannel1CurrentModeParam = *pModeParam; + else + gChannel2CurrentModeParam = *pModeParam; + + /* In case of 8-bpp, fill palette */ + if (pLogicalMode->bpp==8) + { + /* Start with RGB = 0,0,0. */ + unsigned char red = 0, green = 0, blue = 0; + unsigned long gray = 0; + for (offset = 0; offset < 256 * 4; offset += 4) + { + /* Store current RGB value. */ + pokeRegisterDWord(paletteRam + offset, gray + ? RGB((gray + 50) / 100, + (gray + 50) / 100, + (gray + 50) / 100) + : RGB(red, green, blue)); + + if (gray) + { + /* Walk through grays (40 in total). */ + gray += 654; + } + + else + { + /* Walk through colors (6 per base color). */ + if (blue != 255) + { + blue += 51; + } + else if (green != 255) + { + blue = 0; + green += 51; + } + else if (red != 255) + { + green = blue = 0; + red += 51; + } + else + { + gray = 1; + } + } + } + } + /* For 16- and 32-bpp, fill palette with gamma values. */ + else + { + /* Start with RGB = 0,0,0. */ + ulTmpValue = 0x000000; + for (offset = 0; offset < 256 * 4; offset += 4) + { + pokeRegisterDWord(paletteRam + offset, ulTmpValue); + + /* Advance RGB by 1,1,1. */ + ulTmpValue += 0x010101; + } + } + + return 0; +} + +/* + * Input: + * 1) pLogicalMode contains information such as x, y resolution and bpp. + * 2) A user defined parameter table for the mode. + * + * This function calculate and programs the hardware to set up the + * requested mode. + * + * This function allows the use of user defined parameter table if + * predefined Vesa parameter table (gDefaultModeParamTable) does not fit. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long ddk770_setCustomMode( + logicalMode_t *pLogicalMode, + mode_parameter_t *pUserModeParam +) +{ + // mode_parameter_t pModeParam; /* physical parameters for the mode */ + pll_value_t pll; + //unsigned long ulTemp; + + /* + * Minimum check on mode base address. + * At least it shouldn't be bigger than the size of frame buffer. + */ + if (ddk770_getFrameBufSize() <= pLogicalMode->baseAddress) + { + return -1; + } + + pll.inputFreq = 12500000; //12.5MHz //DEFAULT_INPUT_CLOCK; + ddk770_calcPllValue(pUserModeParam->pixel_clock, &pll); + + /* If calling function don't have a preferred pitch value, + work out a 16 byte aligned pitch value. + */ + if (pLogicalMode->pitch == 0) + { + /* + * Pitch value calculation in Bytes. + * Usually, it is (screen width) * (byte per pixel). + * However, there are cases that screen width is not 16 pixel aligned, which is + * a requirement for some OS and the hardware itself. + * For standard 4:3 resolutions: 320, 640, 800, 1024 and 1280, they are all + * 16 pixel aligned and pitch is simply (screen width) * (byte per pixel). + * + * However, 1366 resolution, for example, has to be adjusted for 16 pixel aligned. + */ + pLogicalMode->pitch = PITCH(pLogicalMode->x, pLogicalMode->bpp); + } + + /* Program the hardware to set up the mode. */ + return( ddk770_programModeRegisters( + pLogicalMode, + pUserModeParam, + &pll)); +} + +static unsigned long getActurePixelClock(unsigned long pixelClock) +{ + pll_value_t pll; + pll.inputFreq = 12500000; //12.5MHz //DEFAULT_INPUT_CLOCK; + return ddk770_calcPllValue(pixelClock, &pll); +} +/* + * Input pLogicalMode contains information such as x, y resolution and bpp + * The main difference between ddk770_setMode and setModeEx userData. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long ddk770_setModeEx( + logicalMode_t *pLogicalMode +) +{ + mode_parameter_t *pModeParam; /* physical parameters for the mode */ + unsigned short index = 0; + userData_t *pUserData; + + /* + * Check the validity of the userData pointer and translate the information as necessary + */ + pUserData = (userData_t *)pLogicalMode->userData; + if ((pUserData != (userData_t *)0) && + (pUserData->signature == ddk770_getUserDataSignature()) && + (pUserData->size == sizeof(userData_t))) + { + /* Interpret the userData information */ + if (pUserData->paramList.size == sizeof(userDataParam_t)) + { + if (pUserData->paramList.modeInfoID == MODE_INFO_INDEX) + index = pUserData->paramList.paramInfo.index; + } + } + + /* + * Check if we already have physical timing parameter for this mode. + */ + pModeParam = ddk770_findModeParam(pLogicalMode->dispCtrl, pLogicalMode->x, pLogicalMode->y, pLogicalMode->hz, index); + if (pModeParam == (mode_parameter_t *)0) + return -1; + + return(ddk770_setCustomMode(pLogicalMode, pModeParam)); +} + +/* + * Input pLogicalMode contains information such as x, y resolution and bpp. + * If there is no special parameters, use this function. + * If there are special parameters, use setModeEx. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long ddk770_setMode( + logicalMode_t *pLogicalMode +) +{ + pLogicalMode->userData = (void *)0; + + /* Call the setModeEx to set the mode. */ + return ddk770_setModeEx(pLogicalMode); +} + + +unsigned short alignLineOffset(unsigned short lineOffset) +{ + + if(0 == lineOffset || lineOffset > 0xff00) + return lineOffset; + + return (lineOffset + 255) & ~255; + +} + +long Get_CEA_Mode(logicalMode_t *pLogicalMode, cea_parameter_t *cea_mode, mode_parameter_t *pModeParam, unsigned int isDP) +{ + int i; + unsigned long acturePixelClock; + + if (!pLogicalMode->valid_edid) + { + pModeParam = ddk770_findModeParam(pLogicalMode->dispCtrl, pLogicalMode->x, pLogicalMode->y, pLogicalMode->hz, 0); + if (pModeParam == (mode_parameter_t *)0) + { + printk("ddk770_findModeParam: no mode found"); + return -1; + } + } + cea_mode->de_polarity = 1; + cea_mode->vblank_osc = 0; + cea_mode->progressive_nI = 1; + cea_mode->hdmi_mode = 1; + cea_mode->aspect_ratio = 169; + cea_mode->vic = 0; + + cea_mode->h_active = pModeParam->horizontal_display_end; + cea_mode->h_blank = pModeParam->horizontal_total - pModeParam->horizontal_display_end; + cea_mode->hsync_delay = pModeParam->horizontal_sync_start - pModeParam->horizontal_display_end; + cea_mode->hsync_width = pModeParam->horizontal_sync_width; + + cea_mode->v_active = pModeParam->vertical_display_end; + cea_mode->v_blank = pModeParam->vertical_total - pModeParam->vertical_display_end; + cea_mode->vsync_delay = pModeParam->vertical_sync_start - pModeParam->vertical_display_end; + cea_mode->vsync_width = pModeParam->vertical_sync_height; + + cea_mode->freq = pLogicalMode->hz * 1000; + + cea_mode->hsync_polarity = pModeParam->horizontal_sync_polarity == POS ? 1 : 0; + cea_mode->vsync_polarity = pModeParam->vertical_sync_polarity == POS ? 1 : 0; + + if(isDP){ + acturePixelClock = getActurePixelClock(pModeParam->pixel_clock); + cea_mode->tmds_clk = acturePixelClock / 1000; + }else{ + acturePixelClock = pModeParam->pixel_clock; + cea_mode->tmds_clk = pModeParam->pixel_clock / 1000; + } + printk(" acturePixelClock= %ld\n", acturePixelClock); + + for (i = 0; cea_mode_array[i].h_active != 0; i++) //Check if the modes can be found in cea table + { + if ((cea_mode->h_active == cea_mode_array[i].h_active) && + (cea_mode->v_active == cea_mode_array[i].v_active) && + (cea_mode->freq == cea_mode_array[i].freq)) + { + cea_mode->de_polarity = cea_mode_array[i].de_polarity; + cea_mode->vblank_osc = cea_mode_array[i].vblank_osc; + cea_mode->progressive_nI = cea_mode_array[i].progressive_nI; + cea_mode->hdmi_mode = cea_mode_array[i].hdmi_mode; + cea_mode->aspect_ratio = cea_mode_array[i].aspect_ratio; + cea_mode->vic = cea_mode_array[i].vic; + return 0; + } + } + + return 0; +} \ No newline at end of file diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_mode.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_mode.h new file mode 100644 index 000000000000..3db7b8b32a3d --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_mode.h @@ -0,0 +1,392 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* MODE.H --- SMI DDK +* This file contains the definitions for the mode tables. +* +*******************************************************************/ +#ifndef _DDK770_MODE_H_ +#define _DDK770_MODE_H_ + +#include "../hw_com.h" + +/* Set the alignment to 1-bit aligned. Otherwise, the memory compare used in the + modeext to compare timing will not work. */ +#pragma pack(1) + + +typedef unsigned long long u64; +typedef unsigned int u32; +typedef unsigned short u16; +typedef unsigned char u8; + +typedef struct _cea_parameter_t +{ + u32 vic; + u32 h_active; + u32 h_blank; + u32 hsync_delay; + u32 hsync_width; + u32 v_active; + u32 v_blank; + u32 vsync_delay; + u32 vsync_width; + u32 freq; + u8 de_polarity; + u8 hsync_polarity; + u8 vsync_polarity; + u8 vblank_osc; + u8 progressive_nI; + u32 hdmi_mode; + u32 aspect_ratio; + u32 tmds_clk; +} +cea_parameter_t; + +typedef enum _mode_menu_index_t +{ + CEA_MODE_1920x1080p_60 = 0, + CEA_MODE_1920x1080i_60, + CEA_MODE_1280x720p_60, + CEA_MODE_720x480p_60, + CEA_MODE_800x600p_60, + CEA_MODE_1024x768p_60, + CEA_MODE_3840x2160p_30, + CEA_MODE_3840x2160p_60, + CEA_MODE_3840x2160p_50, + CEA_MODE_2560x1440p_60, + CEA_MODE_640x480p_60, + CEA_MODE_640x480p_59, + CEA_MODE_1440x480p_60, + CEA_MODE_1440x240p_60, + CEA_MODE_2880x480p_59, + CEA_MODE_2880x480p_60, + CEA_MODE_2880x240p_60, + CEA_MODE_720x576p_50, + CEA_MODE_1280x720p_50, + CEA_MODE_1920x1080p_50, + CEA_MODE_1440x576p_50, + CEA_MODE_1440x288p_50, + CEA_MODE_2880x576p_50, + CEA_MODE_2880x288p_50, + CEA_MODE_2880x576p_60, + CEA_MODE_1920x1080p_24, + CEA_MODE_1920x1080p_25, + CEA_MODE_1920x1080p_30, + CEA_MODE_1920x1080p_100, + CEA_MODE_1280x720p_100, + CEA_MODE_720x576p_100, + CEA_MODE_1440x576p_100, + CEA_MODE_1920x1080p_0, + CEA_MODE_1920x1080p_120, + CEA_MODE_1280x720p_120, + CEA_MODE_720x480p_120, + CEA_MODE_1440x480p_120, + CEA_MODE_720x576p_200, + CEA_MODE_1440x576p_200, + CEA_MODE_720x480p_240, + CEA_MODE_1440x480p_240, + CEA_MODE_1280x720p_24, + CEA_MODE_1280x720p_25, + CEA_MODE_1280x720p_30, + CEA_MODE_1440x480i_60, + CEA_MODE_2880x480i_59, + CEA_MODE_2880x480i_60, + CEA_MODE_1920x1080i_50, + CEA_MODE_1440x576i_50, + CEA_MODE_2880x576i_50, + CEA_MODE_1920x1080i_100, + CEA_MODE_1920x1080i_120, + CEA_MODE_1440x576i_100, + CEA_MODE_1440x480i_120, + CEA_MODE_720x480i_0, + CEA_MODE_1440x576i_200, + CEA_MODE_1440x480i_240, + CEA_MODE_3840x2160p_25, + CEA_MODE_3840x2160p_24, + CEA_MODE_4096x2160p_24, + CEA_MODE_4096x2160p_60, + CEA_MODE_2560x1440p_144 +} +mode_menu_index_t, *pmode_menu_index_t; + +/* + u32 vic; + u32 h_active; + u32 h_blank; + u32 hsync_delay; + u32 hsync_width; + u32 v_active; + u32 v_blank; + u32 vsync_delay; + u32 vsync_width; + u32 freq; + u8 de_polarity; + u8 hsync_polarity; + u8 vsync_polarity; + u8 vblank_osc; + u8 progressive_nI; + u32 hdmi_mode; + u32 aspect_ratio; + double tmds_clk; + +*/ + + +/* Restore alignment */ +#pragma pack() + +long Get_CEA_Mode(logicalMode_t *pLogicalMode, cea_parameter_t *cea_mode, mode_parameter_t *pModeParam, unsigned int isDP); + + + +/* + * ddk770_getUserDataSignature + * This function gets the user data mode signature + * + * Output: + * The signature to be filled in the user_data_mode_t structure to be considered + * a valid structure. + */ +unsigned long ddk770_getUserDataSignature(void); + +/* + * ddk770_compareModeParam + * This function compares two mode parameters + * + * Input: + * pModeParam1 - Pointer to the first mode parameter to be compared + * pModeParam2 - Pointer to the second mode parameter to be compared + * + * Output: + * 0 - Identical mode + * -1 - Mode is not identical + */ +long ddk770_compareModeParam( + mode_parameter_t *pModeParam1, + mode_parameter_t *pModeParam2 +); + +/* + * getDuplicateModeIndex + * This function retrieves the index of dupicate modes, but having different timing. + * + * Input: + * dispCtrl - Display Control where the mode table belongs to. + * pModeParam - The mode parameters which index to be checked. + * + * Output: + * The index of the given parameters among the duplicate modes. + * 0 means that the mode param is the first mode encountered in the table + * 1 means that the mode param is the second mode encountered in the table + * etc... + */ +unsigned short getDuplicateModeIndex( + disp_control_t dispCtrl, + mode_parameter_t *pModeParam +); + +/* + * ddk770_findModeParamFromTable + * This function locates the requested mode in the given parameter table + * + * Input: + * width - Mode width + * height - Mode height + * refresh_rate - Mode refresh rate + * index - Index that is used for multiple search of the same mode + * that have the same width, height, and refresh rate, + * but have different timing parameters. + * + * Output: + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *ddk770_findModeParamFromTable( + unsigned long width, + unsigned long height, + unsigned long refresh_rate, + unsigned short index, + mode_parameter_t *pModeTable +); + +/* + * Locate in-stock parameter table for the requested mode. + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *ddk770_findModeParam( + disp_control_t dispCtrl, + unsigned long width, + unsigned long height, + unsigned long refresh_rate, + unsigned short index +); + +/* + * Use the + * Locate timing parameter for the requested mode from the default mode table. + * Success: return a pointer to the mode_parameter_t entry. + * Fail: a NULL pointer. + */ +mode_parameter_t *ddk770_findVesaModeParam( + unsigned long width, + unsigned long height, + unsigned long refresh_rate +); + +/* + * Return a point to the gDefaultModeParamTable. + * Function in other files used this to get the mode table pointer. + */ +mode_parameter_t *ddk770_getStockModeParamTable(void); + +/* + * Return the size of the Stock Mode Param Table + */ +unsigned long ddk770_getStockModeParamTableSize(void); + +/* + * ddk770_getStockModeParamTableEx + * This function gets the mode parameters table associated to the + * display control (CHANNEL0_CTRL or SECONDAR_CTRL). + * + * Input: + * dispCtrl - Display Control of the mode table that is associated to. + * + * Output: + * Pointer to the mode table + */ +mode_parameter_t *ddk770_getStockModeParamTableEx( + disp_control_t dispCtrl +); + +/* + * ddk770_getStockModeParamTableSizeEx + * This function gets the size of the mode parameter table associated with + * specific display control + * + * Input: + * dispCtrl - Display control of the mode param table that is associated to. + * + * Output: + * Size of the requeted mode param table. + */ +unsigned long ddk770_getStockModeParamTableSizeEx( + disp_control_t dispCtrl +); + +/* + * ddk770_getMaximumModeEntries + * This function gets the maximum entries that can be stored in the mode table. + * + * Output: + * Total number of maximum entries + */ +unsigned long ddk770_getMaximumModeEntries(void); + +/* + * This function returns the current mode. + */ +mode_parameter_t ddk770_getCurrentModeParam( + disp_control_t dispCtrl +); + +/* + * ddk770_addTiming + * This function adds the SM750 mode parameter timing to the specified mode table + * + * Input: + * dispCtrl - Display control where the mode will be associated to + * pNewModeList - Pointer to a list table of SM750 mode parameter to be added + * to the current specified display control mode table. + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk770_addTiming( + disp_control_t dispCtrl, + mode_parameter_t *pNewModeList, + unsigned long totalList, + unsigned char clearTable +); + +/* + * This function sets the display base address + * + * Input: + * dispControl - display control of which base address to be set. + * ulBaseAddress - Base Address value to be set. + */ +void ddk770_setDisplayBaseAddress( + disp_control_t dispControl, + unsigned long ulBaseAddress +); + +/* + * This function checks if change of "display base address" has effective. + * Change of DC base address will not effective until next VSync, SW sets pending bit to 1 during address change. + * HW resets pending bit when it starts to use the new address. + * + * Input: + * dispControl - display control of which display status to be retrieved. + * + * Output: + * 1 - Display is pending + * 0 - Display is not pending + */ +long ddk770_isDisplayBasePending( + disp_control_t dispControl +); + +/* + * Input: + * 1) pLogicalMode contains information such as x, y resolution and bpp. + * 2) A user defined parameter table for the mode. + * + * This function calculate and programs the hardware to set up the + * requested mode. + * + * This function allows the use of user defined parameter table if + * predefined Vesa parameter table (gDefaultModeParamTable) does not fit. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long ddk770_setCustomMode( + logicalMode_t *pLogicalMode, + mode_parameter_t *pUserModeParam +); + +/* + * Input pLogicalMode contains information such as x, y resolution and bpp + * The main difference between ddk770_setMode and setModeEx userData. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long ddk770_setModeEx( + logicalMode_t *pLogicalMode +); + +/* + * Input pLogicalMode contains information such as x, y resolution and bpp. + * If there is no special parameters, use this function. + * If there are special parameters, use setModeEx. + * + * Return: 0 (or NO_ERROR) if mode can be set successfully. + * -1 if any set mode error. + */ +long ddk770_setMode( + logicalMode_t *pLogicalMode +); + +unsigned short alignLineOffset(unsigned short lineOffset); + + +#endif /* _MODE_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_os.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_os.c new file mode 100644 index 000000000000..6ddba8f115ec --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_os.c @@ -0,0 +1,41 @@ +/******************************************************************* +* +* Copyright (c) 2008 by Silicon Motion, Inc. (SMI) +* +* OS.C --- SMI DDK +* +* OS or platform dependent files are conditionally compiled here. +* +*******************************************************************/ +#include "ddk770_os.h" + +/* + * Use WATCOM DOS Extender compiler to implement the functions in OS.H + */ +#ifdef WDOSE +#include "WATCOM.C" +#endif + + +/* + * Use Linux compiler to implement the functions in OS.H + */ +#ifdef LINUX +#include "ddk770_linux.c" +#endif + + +/* + * Use ARM interface functions. + */ +#ifdef SMI_ARM +/* Don't need this when using ARM DS 5 build environment. + The DS 5 project builder will include armds5.c automatically. + + Other ARM compilers may be different. +*/ + +//#include "arm.c" +#endif + + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_os.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_os.h new file mode 100644 index 000000000000..06884d2c343f --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_os.h @@ -0,0 +1,325 @@ +/******************************************************************* +* +* Copyright (c) 2008 by Silicon Motion, Inc. (SMI) +* +* OS.H --- VGX family DDK +* +*******************************************************************/ +#ifndef _DDK770_OS_H_ +#define _DDK770_OS_H_ + +/* The following definitioin for interrupt service function is platform dependent */ +#ifdef WDOSE +#define ISR_FUNC interrupt far +#else +#define ISR_FUNC +#endif + +/* Falcon ARM has no OS and PCIe interface. + We don't need those functions for embeddeded implementation with ARM. + */ +#ifndef SMI_ARM + +/* + * Important: + * How to implement the functions here is OS, bus and CPU dependent. + * Please refer to OS.C as an implementation example for WATCOM DOS extender. + * + * By keeping the same interface here, rest of the codes in this DDK are + * pretty much portable for different compilers. + */ + +/* + * This function reads a DWord value from the PCI configuration space + * of a specific PCI device. + * + * Inputs are the Vendor and device ID of the device in question. + * Return: a DWord value. + */ +unsigned long readPCIDword( + unsigned short vendorId, /* PCI vendor ID */ + unsigned short deviceId, /* PCI device ID */ + unsigned short deviceNum, /* If more than one device in system, device number are ordered as 0, 1, 2,... */ + unsigned short offset /* Offset in configuration space to be read */ +); + +/* + * This function writes a dword value to the PCI configuration space + * of a specific device. + * + * Inputs are the Vendor and device ID of the device in question. + * Return: 0 = Success. + * -1 = Fail. + */ +long writePCIDword( + unsigned short vendorId, /* PCI vendor ID */ + unsigned short deviceId, /* PCI device ID */ + unsigned short deviceNum, /* If more than one device in system, device number are ordered as 0, 1, 2,... */ + unsigned short offset, /* Offset in configuration space to be written */ + unsigned long value /* To be written BYTE value */ +); + +/* + * This function reads a Word value from the PCI configuration space + * of a specific device. + * + * Inputs are the Vendor and device ID of the device in question. + * Return: a WORD value. + */ +unsigned short readPCIWord( + unsigned short vendorId, /* PCI vendor ID */ + unsigned short deviceId, /* PCI device ID */ + unsigned short deviceNum, /* If more than one device in system, device number are ordered as 0, 1, 2,... */ + unsigned short offset /* Offset in configuration space to be read */ +); + +/* + * This function writes a word value to the PCI configuration space + * of a specific device. + * + * Inputs are the Vendor and device ID of the device in question. + * Return: 0 = Success. + * -1 = Fail. + */ +long writePCIWord( + unsigned short vendorId, /* PCI vendor ID */ + unsigned short deviceId, /* PCI device ID */ + unsigned short deviceNum, /* If more than one device in system, device number are ordered as 0, 1, 2,... */ + unsigned short offset, /* Offset in configuration space to be written */ + unsigned short value /* To be written BYTE value */ +); + +/* + * This function reads a byte value from the PCI configuration space + * of a specific device. + * + * Inputs are the Vendor and device ID of the device in question. + * Return: a BYTE value. + */ +unsigned char readPCIByte( + unsigned short vendorId, /* PCI Vendor ID */ + unsigned short deviceId, /* PCI device ID */ + unsigned short deviceNum, /* If more than one device in system, device number are ordered as 0, 1, 2,... */ + unsigned short offset /* Offset in configuration space to be read */ +); + +/* + * This function writes a byte value to the PCI configuration space + * of a specific device. + * + * Inputs are the Vendor and device ID of the device in question. + * Return: 0 = Success. + * -1 = Fail. + */ +long writePCIByte( + unsigned short vendorId, /* PCI vendor ID */ + unsigned short deviceId, /* PCI device ID */ + unsigned short deviceNum, /* If more than one device in system, device number are ordered as 0, 1, 2,... */ + unsigned short offset, /* Offset in configuration space to be written */ + unsigned char value /* To be written BYTE value */ +); + +/* + * This function maps a physical address into logical address. + * Return: NULL address pointer if fail + * A Logical address pointer if success. + */ +void *mapPhysicalAddress( + void *phyAddr, /* 32 bit physical address */ + unsigned long size /* Memory size to be mapped */ +); + +/* + * This function unmaps a linear logical address obtained by mapPhysicalAddress. + * Return: + * 0 - Success + * -1 - Fail + */ +long unmapPhysicalAddress( + void *linearAddr /* 32 bit linear address */ +); +#endif /* #ifndef SMI_ARM */ + +/******************************************************************* + * Interrupt implementation support from the OS + * + * This implementation is used for handling the interrupt. + *******************************************************************/ + +/* + * Register an interrupt handler (ISR) to the interrupt vector table associated + * with the given irq number. + * + * Input: + * irqNumber - IRQ Number + * pfnHandler - Pointer to the ISR function + * + * Output: + * 0 - Success + * -1 - Fail + */ +short registerInterrupt( + unsigned char irqNumber, + void (ISR_FUNC *pfnHandler)(void) +); + +/* + * Unregister an interrupt handler from the interrupt vector table + * + * Input: + * irqNumber - IRQ Number + */ +short unregisterInterrupt( + unsigned char irqNumber +); + +/* + * Signal the End Of Interrupt to the system and chain the interrupt + * if necessary. + * + * Input: + * irqNumber - IRQ Number + */ +void interruptEOI( + unsigned char irqNumber +); + +/* + We didn't port the following low level functions to ARM yet. + */ +#ifndef SMI_ARM +/******************************************************************* + * COM Port implementation + * + * This implementation is used by Debug module to send any + * debugging messages to other system through serial port. + *******************************************************************/ +typedef enum _baud_rate_t +{ + COM_2400 = 0, + COM_4800, + COM_9600, + COM_19200, + COM_38400, + COM_57600, + COM_115200 +} +baud_rate_t; + +typedef enum _data_size_t +{ + DATA_SIZE_8, + DATA_SIZE_7 +} +data_size_t; + +// typedef enum _parity_t +// { +// PARITY_NONE = 0, +// PARITY_ODD, +// PARITY_EVEN, +// PARITY_SPACE +// } +// parity_t; + +typedef enum _stop_bit_t +{ + STOP_BIT_1, + STOP_BIT_2 +} +stop_bit_t; + +typedef enum _flow_ctrl_t +{ + FLOW_CONTROL_NONE = 0, + FLOW_CONTROL_HW, + FLOW_CONTROL_SW +} +flow_ctrl_t; + +/* + * Initialize the serial port. + * + * Parameters: + * comPortIndex - Serial Port Index + * baudRate - The communication speed to be set + * dataSize - Number of bits per characters + * parity - Error checking + * stopBit - Number of bits used as the end of each character + * flowCtrl - Serial port Flow Control (handshake) + * + * Returns: + * 0 - Success + * -1 - Fail + */ +// long comInit( +// unsigned char comPortIndex, +// baud_rate_t baudRate, +// data_size_t dataSize, +// parity_t parity, +// stop_bit_t stopBit, +// flow_ctrl_t flowCtrl +// ); + +/* + * Send data out to through the serial port. + * + * Parameters: + * pszPrintBuffer - Pointer to a buffer which data to be sent out + * length - Number of characters to be sent out. + * + * Returns: + * Number of characters that are actually sent out. + */ +unsigned long comWrite( + char* pszPrintBuffer, + unsigned long length +); + +/* + * Close the serial communication port. + */ +void comClose(void); + +/* + * Call BIOS to set mode + */ +void setModeBIOS(unsigned short mode); + +/* + * Read the IO Port. + */ +unsigned char readIO( + unsigned short ioPort /* IO Port */ +); + +/* + * Write to the IO Port. + */ +void writeIO( + unsigned short ioPort, /* IO Port */ + unsigned char value /* Value to be written to the port */ +); + +/******************************************************************* + * Time related functions + * + * This implementation can be used for performance analysis or delay + * function. + *******************************************************************/ + +/* Tick count will be reset after midnight 24 hours. Therefore, when the tick count counter + reset, it means that it has passed the 24 hours boundary. + A Timer tick occurs every 1,193,180 / 65536 (= ~18.20648) times per second. + The maximum tick count is calculated as follows: (24*3600*1000/54.9254) = ~1573040 + */ +#define MAX_TICKCOUNT 1573040 +unsigned long getSystemTickCount(void); + +/* Get current time in milliseconds. */ +#define MAX_TIME_VALUE (24*3600*1000) +unsigned long getCurrentTime(void); + +#endif /* #ifndef SMI_ARM */ + +#endif /* _OS_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_power.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_power.c new file mode 100644 index 000000000000..cafa33244427 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_power.c @@ -0,0 +1,303 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* power.c --- Voyager GX SDK +* This file contains the source code for the power functions. +* +*******************************************************************/ +#include "ddk770_reg.h" +#include "ddk770_hardware.h" +#include "ddk770_chip.h" +#include "ddk770_power.h" +#include "ddk770_help.h" +#include "ddk770_ddkdebug.h" + +/* + * Enable/disable jpeg decoder 1. + */ +void ddk770_enableJPU1(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, JPU1, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, JPU1, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + +/* + * This function enable/disable HDMI + */ +void ddk770_enableHDMI(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, HDMI, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, HDMI, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + + +/* + * Enable/disable USB 3 device + */ +void ddk770_enableUsbDevice(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, USBS, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, USBS, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + + + +/* + * Enable/disable jpeg decoder. + */ +void ddk770_enableJPU(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, JPU, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, JPU, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + + + +void ddk770_enablePCIE(unsigned int enable) +{ + + + unsigned int regValue; + + regValue = peekRegisterDWord(CLOCK1_ENABLE); + if (enable) + { + regValue = FIELD_SET(regValue, CLOCK1_ENABLE, PCIER, NORMAL); + regValue = FIELD_SET(regValue, CLOCK1_ENABLE, PCIE, ON); + } + else + { + regValue = FIELD_SET(regValue, CLOCK1_ENABLE, PCIER, RESET); + regValue = FIELD_SET(regValue, CLOCK1_ENABLE, PCIE, OFF); + } + pokeRegisterDWord(CLOCK1_ENABLE, regValue); + +} + + + +/* + * Enable/disable H264 video decoder. + */ +void ddk770_enableVPU(unsigned long enable) +{ + unsigned int regValue; + + regValue = peekRegisterDWord(0x1060); //set VPU's sram goes to sleep mode + if (enable) + regValue = regValue & (~0x1U); + else + regValue = regValue | 0x01; + + pokeRegisterDWord(0x1060, regValue); + + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable){ + regValue = FIELD_SET(regValue, CLOCK_ENABLE, VPU, ON); + regValue = FIELD_SET(regValue, CLOCK_ENABLE, VPUR, NORMAL); + } + else{ + regValue = FIELD_SET(regValue, CLOCK_ENABLE, VPU, OFF); + regValue = FIELD_SET(regValue, CLOCK_ENABLE, VPUR, RESET); + } + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + + +/* + * This function enable/disable the 2D engine. + */ +void ddk770_enable2DEngine(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DE, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DE, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + +/* + * This function enable/disable the DMA Engine + */ +void ddk770_enableDMA(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DMA, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DMA, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + + +/* + * This function enable/disable the DMA1 and DMA2 Engine + */ +void ddk770_enableDMA1(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DMA1, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DMA1, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + + + +/* + * Enable/disable UART + */ +void ddk770_enableUART(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, UART, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, UART, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + +/* + * Enable/disable I2S + */ +void ddk770_enableI2S(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, I2S, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, I2S, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + +/* + * This function enable/disable the SSP. + */ +void ddk770_enableSSP(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, SSP, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, SSP, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + + +/* + * Enable/disable display control 2 + */ +void ddk770_enableDC2(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DC2, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DC2, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + +/* + * Enable/disable display control 1 + */ +void ddk770_enableDC1(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DC1, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DC1, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + +/* + * Enable/disable display control 0 + */ +void ddk770_enableDC0(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DC0, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, DC0, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + +/* + * Enable/disable ARM + */ +void ddk770_enableARM(unsigned long enable) +{ + unsigned long regValue; + + regValue = peekRegisterDWord(CLOCK_ENABLE); + if (enable) + regValue = FIELD_SET(regValue, CLOCK_ENABLE, ARM, ON); + else + regValue = FIELD_SET(regValue, CLOCK_ENABLE, ARM, OFF); + + pokeRegisterDWord(CLOCK_ENABLE, regValue); +} + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_power.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_power.h new file mode 100644 index 000000000000..a85d9e44f94f --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_power.h @@ -0,0 +1,99 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* power.h --- Voyager GX SDK +* This file contains the definitions for the power functions. +* +*******************************************************************/ +#ifndef _DDK770_POWER_H_ +#define _DDK770_POWER_H_ + +/* + * Enable/disable jpeg decoder 1. + */ +void ddk770_enableJPU1(unsigned long enable); + + +void ddk770_enablePCIE(unsigned int enable); + + +/* + * This function enable/disable HDMI + */ +void ddk770_enableHDMI(unsigned long enable); + + +/* + * Enable/disable USB 3 device + */ +void ddk770_enableUsbDevice(unsigned long enable); + +/* + * This function enable/disable the ZV Port. + */ +void ddk770_enableZVPort(unsigned long enable); + +/* + * Enable/disable jpeg decoder. + */ +void ddk770_enableJPU(unsigned long enable); + +/* + * Enable/disable H264 video decoder. + */ +void ddk770_enableVPU(unsigned long enable); + +/* + * This function enable/disable the 2D engine. + */ +void ddk770_enable2DEngine(unsigned long enable); + +/* + * This function enable/disable the DMA Engine + */ +void ddk770_enableDMA(unsigned long enable); + + +void ddk770_enableDMA1(unsigned long enable); + + +/* + * Enable/disable UART + */ +void ddk770_enableUART(unsigned long enable); + +/* + * Enable/disable I2S + */ +void ddk770_enableI2S(unsigned long enable); + +/* + * This function enable/disable the SSP. + */ +void ddk770_enableSSP(unsigned long enable); + +/* + * Enable/disable display control 2 + */ +void ddk770_enableDC2(unsigned long enable); + +/* + * Enable/disable display control 1 + */ +void ddk770_enableDC1(unsigned long enable); + +/* + * Enable/disable display control 0 + */ +void ddk770_enableDC0(unsigned long enable); + +/* + * Enable/disable ARM + */ +void ddk770_enableARM(unsigned long enable); + +#endif /* _POWER_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_pwm.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_pwm.c new file mode 100644 index 000000000000..3bae40877f3d --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_pwm.c @@ -0,0 +1,283 @@ +/******************************************************************* +* +* Copyright (c) 2014 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* This file contains the definitions for the PWM functions. +* +*******************************************************************/ +#include "ddk770_reg.h" +#include "ddk770_helper.h" +#include "ddk770_pwm.h" +#include "ddk770_help.h" + +static unsigned long gPwm = 0; + +/* + * This function open PWM lines in GPIO Mux + */ +void ddk770_pwmOpen( + unsigned long pwm /* which pwm: 0 to 2 */ +) +{ + unsigned long value; + + /* Enable GPIO mux (0x10010) 19, 18 or 17 for PWM output */ + value = peekRegisterDWord(GPIO_MUX); + + switch(pwm) + { + case 0: + value = FIELD_SET(value, GPIO_MUX, 21, PWM0); + break; + + case 1: + value = FIELD_SET(value, GPIO_MUX, 22, PWM1); + break; + + default: + value = FIELD_SET(value, GPIO_MUX, 23, PWM2); + break; + } + + pokeRegisterDWord(GPIO_MUX, value); +} + +/* + * This function closes PWM lines in GPIO Mux + */ +void ddk770_pwmClose( + unsigned long pwm /* which pwm: 0 to 2 */ +) +{ + unsigned long value; + + /* Enable GPIO mux (0x10010) 19, 18 or 17 for PWM output */ + value = peekRegisterDWord(GPIO_MUX); + + switch(pwm) + { + case 0: + value = FIELD_SET(value, GPIO_MUX, 21, GPIO); + break; + + case 1: + value = FIELD_SET(value, GPIO_MUX, 22, GPIO); + break; + + default: + value = FIELD_SET(value, GPIO_MUX, 23, GPIO); + break; + } + + pokeRegisterDWord(GPIO_MUX, value); +} + +/* + * According to input time, this function calculates values + * for PWM clock divide and PWM counter with 50% duty cycle. + */ +void ddk770_pwmCalcCounter( + unsigned long mSec, /* Input time in milli second */ + unsigned long *clkDivider, /* Output clock divider value */ + unsigned long *counter /* Output counter value for both high and low counter at 50% duty cycle */ +) +{ + /* The value of counter depends on the clock frequency the counter is running. + For FPGA, it is 100MHz. For ASIC, it is 180 to 200 MHz. + */ + + /* For FPGA testing purpose, just return any number for now */ + *clkDivider = 8; /* Divide by 256 */ + *counter = 0xfff; /* Max 12 bit value */ +} + +/* + * This function starts PWM. + * When PWM completes a cycle, its raw interrupt pending bit will be set. + * + * Important limitation: Since all three PWM shares one INT status and mask, + * only one PWM can set up ISR at any time. + * + */ +void ddk770_pwmStart( + unsigned long pwm, /* which pwm: 0 to 2 */ + unsigned long divider, + unsigned long highCounter, + unsigned long lowCounter, + unsigned long isrSupport /* 1 if user wants to hook an ISR, 0 if use pulling method + Note that only one PWM can have ISR at any time. + */ +) +{ + unsigned long pwmAddr, pwmValue; + + if (pwm > 2) return; /* Invalid PWM number */ + + if (highCounter == 0 || lowCounter == 0) return; /* Nothing to set */ + + /* Work out the PWM's MMIO address + PWM 0 address + ( PWM x 4 ) + */ + pwmAddr = PWM_CONTROL + (pwm << 2); + + pwmValue = + FIELD_VALUE(0, PWM_CONTROL, HIGH_COUNTER, highCounter) + | FIELD_VALUE(0, PWM_CONTROL, LOW_COUNTER, lowCounter) + | FIELD_VALUE(0, PWM_CONTROL, CLOCK_DIVIDE, divider) + | FIELD_SET(0, PWM_CONTROL, INTERRUPT_STATUS, CLEAR) /* Reset the raw interrupt */ + | FIELD_SET(0, PWM_CONTROL, INTERRUPT, ENABLE) /* Enable raw interrupt to happen */ + | FIELD_SET(0, PWM_CONTROL, STATUS, ENABLE); /* Start PWM */ + + pokeRegisterDWord(pwmAddr, pwmValue); + + if (isrSupport) + gPwm = pwm; +} + +/* + * This function checks if a PWM's raw interrupt has been pending. + * When raw interrupt is detected with pending status, it indicate the + * a pulse cycle is completed after ddk770_pwmStart(). + * + * Return: + * 1 = Raw interrupt status is pending. + * 0 = Raw int is NOT pending. + */ +unsigned long ddk770_pwmRawIntPending( + unsigned long pwm /* which pwm: 0 to 2 */ +) +{ + unsigned long pwmAddr, rawIntStatus; + + if (pwm > 2) return 0; /* Invalid PWM number */ + + /* Work out the PWM's MMIO address + PWM 0 address + ( PWM x 4 ) + */ + pwmAddr = PWM_CONTROL + (pwm << 2); + + rawIntStatus = FIELD_VAL_GET(peekRegisterDWord(pwmAddr), PWM_CONTROL, INTERRUPT_STATUS); + + return(rawIntStatus); +} + +/* + * This function clears the RAW interrupt status of PWM. + * + * When PWM completes a cycle, the raw interrupt bit will be set. + * It has to be cleared, in order to distinguish between different cycles. + * + */ +void ddk770_pwmClearRawInt( + unsigned long pwm /* which pwm: 0 to 2 */ +) +{ + unsigned long pwmAddr, pwmValue; + + if (pwm > 2) return; /* Invalid PWM number */ + + /* Work out the PWM's MMIO address + PWM 0 address + ( PWM x 4 ) + */ + pwmAddr = PWM_CONTROL + (pwm << 2); + + pwmValue = peekRegisterDWord(pwmAddr); + + pokeRegisterDWord(pwmAddr, + pwmValue + | FIELD_SET(0, PWM_CONTROL, INTERRUPT_STATUS, CLEAR)); /* Reset the raw interrupt */ +} + +/* + * This function stop PWM + * + */ +void ddk770_pwmStop( + unsigned long pwm /* which pwm: 0 to 2 */ +) +{ + unsigned long pwmAddr, pwmValue; + + if (pwm > 2) return; /* Invalid PWM number */ + + /* Work out the PWM's MMIO address + PWM 0 address + ( PWM x 4 ) + */ + pwmAddr = PWM_CONTROL + (pwm << 2); + + pwmValue = + FIELD_SET(0, PWM_CONTROL, INTERRUPT_STATUS, CLEAR) /* Reset the raw interrupt */ + | FIELD_SET(0, PWM_CONTROL, STATUS, DISABLE); /* Stop the PWM */ + + pokeRegisterDWord(pwmAddr, pwmValue); +} + +/* + * This funciton uses PWM to wait a specific amount of time. + * + * Input: millisecond unit. + */ +void ddk770_pwmWait( + unsigned long pwm, + unsigned long milliSeconds +) +{ + unsigned long divider, highCounter, lowCounter; + + if (pwm > 2) return; /* Invalid PWM number */ + + /* Calculate how many ticks are needed for the amount of time.*/ + ddk770_pwmCalcCounter(milliSeconds, ÷r, &highCounter); + lowCounter = highCounter; + + ddk770_pwmStart(pwm, divider, highCounter, lowCounter, 0); + + while (!ddk770_pwmRawIntPending(pwm)); /* Danger, put a timeout here later */ + + ddk770_pwmStop(pwm); +} + +/* + * This function returns the INT mask for a specific PWM + * + */ +unsigned long ddk770_pwmIntMask( + unsigned long pwm /* which pwm: 0 to 2 */ +) +{ + unsigned long mask = 0; + + /* Note: In falcon, all PWM shares one INT mask */ + mask |= FIELD_SET(0, INT_MASK1, PWM, ENABLE); + + return mask; +} + +/* + * This is a reference sample showing how to implement ISR for PWM + * It works together with libsrc\intr.c + * + * Refer to Apps\timer\tstpwm.c on how to hook up this function with system + * interrupt under WATCOM DOS extender. + * + */ +void ddk770_pwmIsrTemplate(unsigned long status) +{ + /* Check if it's PWM interrupt. */ + + if (FIELD_VAL_GET(status, INT_STATUS1, PWM)) + { + /* Perform ISR action for timer 0 here */ + ddk770_incTestCounter(); /* Dummy example action */ + + /* In Falcon, sicne all 3 PWM shares one PWM mask, + There is no way to tell which PWM generates the interrupt. + Just Clear the one marked down by ddk770_pwmStart. + */ + ddk770_pwmClearRawInt(gPwm); + } +} + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_pwm.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_pwm.h new file mode 100644 index 000000000000..973a5e44a3e6 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_pwm.h @@ -0,0 +1,119 @@ +/******************************************************************* +* +* Copyright (c) 2014 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* This file contains the definitions for the timer functions. +* +*******************************************************************/ +#ifndef _DDK770_PWM_H_ +#define _DDK770_PWM_H_ + +#include "ddk770_os.h" + +/* + * This function open PWM lines in GPIO Mux + */ +void ddk770_pwmOpen( + unsigned long pwm /* which pwm: 0 to 2 */ +); + +/* + * This function closes PWM lines in GPIO Mux + */ +void ddk770_pwmClose( + unsigned long pwm /* which pwm: 0 to 2 */ +); + +/* + * According to input time, this function calculates values + * for PWM clock divide and PWM counter with 50% duty cycle. + */ +void ddk770_pwmCalcCounter( + unsigned long mSec, /* Input time in milli second */ + unsigned long *clkDivider, /* Output clock divider value */ + unsigned long *counter /* Output counter value for both high and low counter at 50% duty cycle */ +); + +/* + * This function starts PWM. + * When PWM completes a cycle, its raw interrupt pending bit will be set. + * + * Important limitation: Since all three PWM shares one INT status and mask, + * only one PWM can set up ISR at any time. + * + */ +void ddk770_pwmStart( + unsigned long pwm, /* which pwm: 0 to 2 */ + unsigned long divider, + unsigned long highCounter, + unsigned long lowCounter, + unsigned long isrSupport /* 1 if user wants to hook an ISR, 0 if use pulling method + Note that only one PWM can have ISR at any time. + */ +); + +/* + * This function checks if a PWM's raw interrupt has been pending. + * When raw interrupt is detected with pending status, it indicate the + * a pulse cycle is completed after ddk770_pwmStart(). + * + * Return: + * 1 = Raw interrupt status is pending. + * 0 = Raw int is NOT pending. + */ +unsigned long ddk770_pwmRawIntPending( + unsigned long pwm /* which pwm: 0 to 2 */ +); + +/* + * This function clears the RAW interrupt status of PWM. + * + * When PWM completes a cycle, the raw interrupt bit will be set. + * It has to be cleared, in order to distinguish between different cycles. + * + */ +void ddk770_pwmClearRawInt( + unsigned long pwm /* which pwm: 0 to 2 */ +); + +/* + * This function stop PWM + * + */ +void ddk770_pwmStop( + unsigned long pwm /* which pwm: 0 to 2 */ +); + +/* + * This funciton uses PWM to wait a specific amount of time. + * + * Input: millisecond unit. + */ +void ddk770_pwmWait( + unsigned long pwm, + unsigned long milliSeconds +); + +/* + * This function returns the INT mask for a specific PWM + * + */ +unsigned long ddk770_pwmIntMask( + unsigned long pwm /* which pwm: 0 to 2 */ +); + +/* + * This is a reference sample showing how to implement ISR for PWM + * It works together with libsrc\intr.c + * + * Refer to Apps\timer\tstpwm.c on how to hook up this function with system + * interrupt under WATCOM DOS extender. + * + */ +void ddk770_pwmIsrTemplate(unsigned long status); + +#endif /* _PWM_H_ */ + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_reg.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_reg.h new file mode 100644 index 000000000000..8efb0772f01a --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_reg.h @@ -0,0 +1,3971 @@ + +#define DP_BASE 0x00190000 + +#define DP_OFFSET 0x8000 + +#define DP1_BASE DP_BASE+DP_OFFSET + +#define DP_PIN 0x0000 +#define DP_PIN_SYS_RSTN 0:0 +#define DP_PIN_TEST_SEL 0:0 +#define DP_PIN_TEST_EN 0:0 +#define DP_PIN_TEST_DONE 0:0 +#define DP_PIN_TEST_PASS 0:0 + +#define DP_TOP18 0x0018 +#define DP_TOP18_SCRAMBLE 0:0 +#define DP_TOP18_SCRAMBLE_ENABLE 0 +#define DP_TOP18_SCRAMBLE_DISABLE 1 +#define DP_TOP18_ENHANCE_FRAMING 1:1 +#define DP_TOP18_ENHANCE_FRAMING_ENABLE 1 +#define DP_TOP18_ENHANCE_FRAMING_DISABLE 0 +#define DP_TOP18_REG_HPD_SCALE 3:3 +#define DP_TOP18_REG_HPD_SCALE_NORMAL 0 +#define DP_TOP18_REG_HPD_SCALE_SCALING 1 + +#define DP_TOP1C 0x001C +#define DP_TOP1C_REG_RESET_AUDIO 3:3 +#define DP_TOP1C_REG_RESET_AUDIO_TRUE 1 +#define DP_TOP1C_REG_RESET_AUDIO_FALSE 0 +#define DP_TOP1C_REG_RESET_PHY 1:1 +#define DP_TOP1C_REG_RESET_PHY_TRUE 1 +#define DP_TOP1C_REG_RESET_PHY_FALSE 0 + +#define DP_TOP80 0x0080 +#define DP_TOP80_STA_AUD_OVERRUN 5:5 +#define DP_TOP80_STA_AUD_OVERRUN_TRUE 1 +#define DP_TOP80_STA_AUD_OVERRUN_FALSE 0 +#define DP_TOP80_STA_AUX_REPLY_EVENT 1:1 +#define DP_TOP80_STA_AUX_REPLY_EVENT_TRUE 1 +#define DP_TOP80_STA_AUX_REPLY_EVENT_FALSE 0 +#define DP_TOP80_STA_HPD_EVENT 0:0 +#define DP_TOP80_STA_HPD_EVENT_TRUE 1 +#define DP_TOP80_STA_HPD_EVENT_FALSE 0 + +#define DP_TOP84 0x0084 + +#define DP_TOP84_ENABLE_AUD_OVERRUN 5:5 +#define DP_TOP84_ENABLE_AUD_OVERRUN_TRUE 1 +#define DP_TOP84_ENABLE_AUD_OVERRUN_FALSE 0 + +#define DP_TOP84_ENABLE_HPD_UNPLUG_EVENT 2:2 +#define DP_TOP84_ENABLE_HPD_UNPLUG_EVENT_TRUE 1 +#define DP_TOP84_ENABLE_HPD_UNPLUG_EVENT_FALSE 0 + +#define DP_TOP84_ENABLE_AUX_REPLY_EVENT 1:1 +#define DP_TOP84_ENABLE_AUX_REPLY_EVENT_TRUE 1 +#define DP_TOP84_ENABLE_AUX_REPLY_EVENT_FALSE 0 +#define DP_TOP84_ENABLE_HPD_PLUG_EVENT 0:0 +#define DP_TOP84_ENABLE_HPD_PLUG_EVENT_TRUE 1 +#define DP_TOP84_ENABLE_HPD_PLUG_EVENT_FALSE 0 + +#define DP_TOP88 0x0088 +#define DP_TOP88_STA_HPD_UNPLUG 2:2 +#define DP_TOP88_STA_HPD_UNPLUG_TRUE 1 +#define DP_TOP88_STA_HPD_UNPLUG_FALSE 0 +#define DP_TOP88_STA_HPD_PLUG 1:1 +#define DP_TOP88_STA_HPD_PLUG_TRUE 1 +#define DP_TOP88_STA_HPD_PLUG_FALSE 0 + +#define DP_TOP8C 0x008C +#define DP_TOP8C_HPD_UNPLUG 2:2 +#define DP_TOP8C_HPD_UNPLUG_ENABLE 1 +#define DP_TOP8C_HPD_UNPLUG_DISABLE 0 +#define DP_TOP8C_HPD_PLUG 1:1 +#define DP_TOP8C_HPD_PLUG_ENABLE 1 +#define DP_TOP8C_HPD_PLUG_DISABLE 0 +#define DP_TOP8C_HPD_IRQ 0:0 +#define DP_TOP8C_HPD_IRQ_ENABLE 1 +#define DP_TOP8C_HPD_IRQ_DISABLE 0 + +#define DP_PHY100 0x0100 +#define DP_PHY100_DP_PHY_RATE 28:26 +#define DP_PHY100_DP_PHY_RATE_216 1 +#define DP_PHY100_DP_PHY_RATE_243 2 +#define DP_PHY100_DP_PHY_RATE_OTHER 0 +#define DP_PHY100_TRANSMIT_ENABLE 11:8 +#define DP_PHY100_TRANSMIT_ENABLE_NONE 0 +#define DP_PHY100_TRANSMIT_ENABLE_LANE0 1 +#define DP_PHY100_TRANSMIT_ENABLE_LANE1 2 +#define DP_PHY100_TRANSMIT_ENABLE_LANE2 4 +#define DP_PHY100_TRANSMIT_ENABLE_LANE3 8 +#define DP_PHY100_TRANSMIT_ENABLE_ALL 15 +#define DP_PHY100_PHY_LANES 7:6 +#define DP_PHY100_PHY_LANES_1 0 +#define DP_PHY100_PHY_LANES_2 1 +#define DP_PHY100_PHY_LANES_4 2 +#define DP_PHY100_PHY_RATE 5:4 +#define DP_PHY100_PHY_RATE_810 3 +#define DP_PHY100_PHY_RATE_540 2 +#define DP_PHY100_PHY_RATE_270 1 +#define DP_PHY100_PHY_RATE_162 0 +#define DP_PHY100_TPS_SEL 3:0 +#define DP_PHY100_TPS_SEL_NO 0 +#define DP_PHY100_TPS_SEL_TPS1 1 +#define DP_PHY100_TPS_SEL_TPS2 2 +#define DP_PHY100_TPS_SEL_TPS3 3 +#define DP_PHY100_TPS_SEL_TPS4 4 + +#define DP_PHY108 0x108 //DP_MAIN_LINK_CHANNEL_CODING_SET +#define DP_DP_PHY108_SET_ANSI_8B10B (1 << 0) +#define DP_DP_PHY108_SET_ANSI_128B132B (1 << 1) + +#define DP_ANALOG180 0x0180 +#define DP_ANALOG180_COREPLL_FBDIV 31:24 +#define DP_ANALOG180_SSCG 21:21 +#define DP_ANALOG180_SSCG_ENABLE 0 +#define DP_ANALOG180_SSCG_DISABLE 1 +#define DP_ANALOG180_DOWNSPREAD 20:20 +#define DP_ANALOG180_DOWNSPREAD_DOWN 1 +#define DP_ANALOG180_DOWNSPREAD_CENTER 0 +#define DP_ANALOG180_DA_COREPLL_FBDIV 19:16 +#define DP_ANALOG180_DA_COREPLL_PREDIV 13:8 +#define DP_ANALOG180_DA_COREPLL_LOCK 7:7 +#define DP_ANALOG180_DA_COREPLL_LOCK_TRUE 1 +#define DP_ANALOG180_DA_COREPLL_LOCK_FALSE 0 +#define DP_ANALOG180_DA_COREPLL_FRAC_PD 5:4 +#define DP_ANALOG180_COREPLL_PD 0:0 +#define DP_ANALOG180_COREPLL_PD_TRUE 1 +#define DP_ANALOG180_COREPLL_PD_FALSE 0 + +#define DP_ANALOG184 0X184 +#define DP_ANALOG184_REG_COREPLL_FRAC 23:0 + +#define DP_ANALOG188 0X188 +#define DP_ANALOG188_REG_SPREAD 30:28 +#define DP_ANALOG188_REG_DIVVAL 27:24 +#define DP_ANALOG188_DA_COREPLL_POSTDIV 3:2 + +#define DP_ANALOG190 0X190 +#define DP_ANALOG190_DA_PIXELPLL_FBDIV1 31:24 +#define DP_ANALOG190_DA_PIXELPLL_FBDIV0 19:16 +#define DP_ANALOG190_DA_PIXELPLL_PREDIV 13:8 +#define DP_ANALOG190_DA_PIXELPLL_LOCK 7:7 +#define DP_ANALOG190_DA_PIXELPLL_LOCK_TRUE 1 +#define DP_ANALOG190_DA_PIXELPLL_LOCK_FALSE 0 +#define DP_ANALOG190_DA_PIXELPLL_FRAC_PD 5:4 +#define DP_ANALOG190_REG_PIXELPLL_PD 0:0 +#define DP_ANALOG190_REG_PIXELPLL_PD_TRUE 1 +#define DP_ANALOG190_REG_PIXELPLL_PD_FALSE 0 + +#define DP_ANALOG194 0X194 +#define DP_ANALOG194_PIXEL_PLL_DIVIDER_C 20:16 +#define DP_ANALOG194_PIXEL_PLL_DIVIDER_B 9:8 +#define DP_ANALOG194_PIXEL_PLL_DIVIDER_A 4:0 + +#define DP_ANALOG19C 0X19C +#define DP_ANALOG19C_DA_PIXELPLL_FRAC0 23:16 +#define DP_ANALOG19C_DA_PIXELPLL_FRAC1 15:8 +#define DP_ANALOG19C_DA_PIXELPLL_FRAC2 7:0 + +#define DP_ANALOG1A4 0X1a4 +#define DP_ANALOG1A4_DA_TX_ISEL_DRV_D3 31:28 +#define DP_ANALOG1A4_DA_TX_ISEL_DRV_D2 27:24 + +#define DP_ANALOG1A8 0X1a8 +#define DP_ANALOG1A8_DA_TX_MAINSEL_D2 28:24 +#define DP_ANALOG1A8_DA_TX_MAINSEL_D3 20:16 +#define DP_ANALOG1A8_DA_TX_MAINSEL_D1 7:4 +#define DP_ANALOG1A8_DA_TX_MAINSEL_D0 3:0 + +#define DP_ANALOG1AC 0X1ac +#define DP_ANALOG1AC_DA_TX_POSTSEL_D1 31:28 +#define DP_ANALOG1AC_DA_TX_POSTSEL_D0 27:24 +#define DP_ANALOG1AC_DA_TX_POSTSEL_D3 23:20 +#define DP_ANALOG1AC_DA_TX_POSTSEL_D2 19:16 +#define DP_ANALOG1AC_DA_TX_MAINSEL_D0 12:8 +#define DP_ANALOG1AC_DA_TX_MAINSEL_D1 4:0 + +#define DP_ANALOG1B0 0x1b0 +#define DP_ANALOG1B0_DA_TX_PRESEL_D1 14:12 +#define DP_ANALOG1B0_DA_TX_PRESEL_D0 10:8 +#define DP_ANALOG1B0_DA_TX_PRESEL_D3 6:4 +#define DP_ANALOG1B0_DA_TX_PRESEL_D2 2:0 + +#define DP_ANALOG1C0 0x1c0 +#define DP_ANALOG1C0_REG_BG_RCAL_SEL 26:25 +#define DP_ANALOG1C0_REG_RTCAL_FREQDIV0 23:16 +#define DP_ANALOG1C0_REG_RTCAL_BYPASS 15:15 +#define DP_ANALOG1C0_REG_RTCAL_FREQDIV1 14:8 +#define DP_ANALOG1C0_REG_BG_RCAL_VAL 5:0 + +#define DP_ANALOG1C4 0x1c4 +#define DP_ANALOG1C4_REG_TX_RTM_D3 29:24 +#define DP_ANALOG1C4_REG_TX_RTM_D2 21:16 +#define DP_ANALOG1C4_REG_TX_RTM_D1 13:8 +#define DP_ANALOG1C4_REG_TX_RTM_D0 5:0 + +#define DP_CONTROLLER200 0x0200 +#define DP_CONTROLLER200_REG_ALT_SCREAMBLE_RESET 24:24 +#define DP_CONTROLLER200_REG_ALT_SCREAMBLE_RESET_TRUE 1 +#define DP_CONTROLLER200_REG_ALT_SCREAMBLE_RESET_FALSE 0 +#define DP_CONTROLLER200_VIDEO_MAPPING 20:16 +#define DP_CONTROLLER200_VIDEO_MAPPING_RGB6 0 +#define DP_CONTROLLER200_VIDEO_MAPPING_RGB8 1 +#define DP_CONTROLLER200_VIDEO_MAPPING_RGB10 2 +#define DP_CONTROLLER200_VIDEO_MAPPING_RGB12 3 +#define DP_CONTROLLER200_VIDEO_MAPPING_RGB16 4 +#define DP_CONTROLLER200_VIDEO_MAPPING_YCBCR444_8 5 +#define DP_CONTROLLER200_VIDEO_MAPPING_YCBCR444_10 6 +#define DP_CONTROLLER200_VIDEO_MAPPING_YCBCR444_12 7 +#define DP_CONTROLLER200_VIDEO_MAPPING_YCBCR444_16 8 +#define DP_CONTROLLER200_VIDEO_MAPPING_YCBCR422_8 9 +#define DP_CONTROLLER200_VIDEO_MAPPING_YCBCR422_10 10 +#define DP_CONTROLLER200_VIDEO_MAPPING_YCBCR422_12 11 +#define DP_CONTROLLER200_VIDEO_MAPPING_YCBCR422_16 12 +#define DP_CONTROLLER200_VIDEO_STREAM 5:5 +#define DP_CONTROLLER200_VIDEO_STREAM_ENABLE 1 +#define DP_CONTROLLER200_VIDEO_STREAM_DISABLE 0 + +#define DP_CONTROLLER20C 0x020C +#define DP_CONTROLLER20C_REG_TX_POLARITY +#define DP_CONTROLLER20C_REG_TX_POLARITY_HSYNC 1:1 +#define DP_CONTROLLER20C_REG_TX_POLARITY_HSYNC_HIGH 1 +#define DP_CONTROLLER20C_REG_TX_POLARITY_HSYNC_LOW 1 +#define DP_CONTROLLER20C_REG_TX_POLARITY_VSYNC 0:0 +#define DP_CONTROLLER20C_REG_TX_POLARITY_VSYNC_HIGH 1 +#define DP_CONTROLLER20C_REG_TX_POLARITY_VSYNC_LOW 1 + +#define DP_CONTROLLER210 0x0210 +#define DP_CONTROLLER210_REG_TX_HACTIVE 31:16 +#define DP_CONTROLLER210_REG_TX_HBLANK 15:2 + +#define DP_CONTROLLER214 0x0214 +#define DP_CONTROLLER214_REG_TX_VBLANK 31:16 +#define DP_CONTROLLER214_REG_TX_VACTIVE 15:0 + +#define DP_CONTROLLER218 0x0218 +#define DP_CONTROLLER218_REG_TX_HSWIDTH 31:16 +#define DP_CONTROLLER218_REG_TX_H_FRONT_PORCH 15:0 + +#define DP_CONTROLLER21C 0x021C +#define DP_CONTROLLER21C_REG_TX_VSWIDTH 31:16 +#define DP_CONTROLLER21C_REG_TX_V_FRONT_PORCH 15:0 + +#define DP_CONTROLLER220 0x0220 +#define DP_CONTROLLER220_REG_AVG_PER_TU_FRAC 19:16 +#define DP_CONTROLLER220_REG_LINE_RD_THRES 13:7 +#define DP_CONTROLLER220_REG_AVG_PER_TU_INT 6:0 + +#define DP_CONTROLLER224 0x0224 +#define DP_CONTROLLER224_REG_TX_VSTART 31:16 +#define DP_CONTROLLER224_REG_TX_HSTART 15:0 + +#define DP_CONTROLLER228 0x0228 +#define DP_CONTROLLER228_REG_TX_MSA_MISC0 31:24 + +#define DP_CONTROLLER22C 0x022C +#define DP_CONTROLLER22C_REG_TX_MSA_MISC1 31:24 + + +#define DP_CONTROLLER230 0x0230 +#define DP_CONTROLLER230_HBLANK_LINK_CYC 15:0 + +#define DP_CONTROLLER300 0x0300 +#define DP_CONTROLLER300_AUDIO_MUTE 15:15 +#define DP_CONTROLLER300_AUDIO_MUTE_SET 1 +#define DP_CONTROLLER300_AUDIO_MUTE_CLEAR 0 +#define DP_CONTROLLER300_AUDIO_CHANNEL_NUM 14:12 +#define DP_CONTROLLER300_AUDIO_CHANNEL_NUM_1 0x0 +#define DP_CONTROLLER300_AUDIO_CHANNEL_NUM_2 0x1 +#define DP_CONTROLLER300_AUDIO_CHANNEL_NUM_8 0x8 +#define DP_CONTROLLER300_AUDIO_LEGEND 11:11 +#define DP_CONTROLLER300_AUDIO_LEGEND_VALID 0x0 // i2s stream format is legend, only include valid audio data +#define DP_CONTROLLER300_AUDIO_LEGEND_ALL 0x1 // change input i2s stream format, include PR, P, C, U, V��valid audio data +#define DP_CONTROLLER300_AUDIO_DATA_WIDTH 9:5 +#define DP_CONTROLLER300_AUDIO_DATA_WIDTH_16 0X10 +#define DP_CONTROLLER300_AUDIO_DATA_WIDTH_20 0X14 +#define DP_CONTROLLER300_AUDIO_DATA_WIDTH_24 0X18 +#define DP_CONTROLLER300_AUDIO_DATA_EN 4:1 +#define DP_CONTROLLER300_AUDIO_DATA_EN_0 0x0 +#define DP_CONTROLLER300_AUDIO_DATA_EN_12 0x1 +#define DP_CONTROLLER300_AUDIO_DATA_EN_34 0x2 +#define DP_CONTROLLER300_AUDIO_DATA_EN_56 0x4 +#define DP_CONTROLLER300_AUDIO_DATA_EN_78 0x8 +#define DP_CONTROLLER300_AUDIO_DATA_EN_ALL 0xf +#define DP_CONTROLLER300_AUDIO_INTERFACE_SEL 0:0 +#define DP_CONTROLLER300_AUDIO_INTERFACE_SEL_I2S 0 +#define DP_CONTROLLER300_AUDIO_INTERFACE_SEL_SPDIF 1 + +#define DP_CONTROLLER304 0x0304 +#define DP_CONTROLLER304_AUDSET 15:8 + +#define DP_CONTROLLER308 0x0308 +#define DP_CONTROLLER308_AUDSET 15:8 + +#define DP_CONTROLLER30C 0x030c +#define DP_CONTROLLER30C_AUDSET1 5:0 +#define DP_CONTROLLER30C_AUDSET2 11:8 + + +#define DP_CONTROLLER310 0x0310 +#define DP_CONTROLLER310_AUDSET 7:0 + +#define DP_CONTROLLER400 0x0400 +#define DP_CONTROLLER400_CFG_PHY_AUX_DATA_CMD 31:28 +#define DP_CONTROLLER400_CFG_PHY_AUX_DATA_ADDR 27:8 +#define DP_CONTROLLER400_CFG_PHY_AUX_DATA_LENGTH 3:0 + +#define DP_CONTROLLER404 0x0404 +#define DP_CONTROLLER404_AUX_TIMEOUT 17:17 +#define DP_CONTROLLER404_AUX_TIMEOUT_TRUE 1 +#define DP_CONTROLLER404_AUX_TIMEOUT_FALSE 0 +#define DP_CONTROLLER404_AUX_REPLY_RECEIVED 16:16 +#define DP_CONTROLLER404_AUX_REPLY_RECEIVED_TRUE 0 +#define DP_CONTROLLER404_AUX_REPLY_RECEIVED_FALSE 1 +#define DP_CONTROLLER404_AUX_REPLY_CMD 7:4 +#define DP_CONTROLLER404_AUX_REPLY_CMD_ACK 0 +#define DP_CONTROLLER404_AUX_REPLY_CMD_NOACK 1 + +#define DP_CONTROLLER408 0x0408 + +#define DP_CONTROLLER40C 0x040C + +#define DP_CONTROLLER410 0x0410 + +#define DP_CONTROLLER414 0x0414 + +#define DP_CONTROLLER418 0x0418 +#define DP_CONTROLLER418_CFG_PHY_AUX_START 0:0 +#define DP_CONTROLLER418_CFG_PHY_AUX_START_TRUE 1 +#define DP_CONTROLLER418_CFG_PHY_AUX_START_FALSE 0 + +#define DP_CONTROLLER500 0x0500 +#define DP_CONTROLLER500_SDP_AUDIO_INFO_FRAME 3:3 +#define DP_CONTROLLER500_SDP_AUDIO_INFO_FRAME_ENABLE 1 +#define DP_CONTROLLER500_SDP_AUDIO_INFO_FRAME_DISABLE 0 +#define DP_CONTROLLER500_SDP_AUDIO_STREAM_VERTICAL 1:1 +#define DP_CONTROLLER500_SDP_AUDIO_STREAM_VERTICAL_ENABLE 1 +#define DP_CONTROLLER500_SDP_AUDIO_STREAM_VERTICAL_DISABLE 0 +#define DP_CONTROLLER500_SDP_AUDIO_TIMESTAMP_VERTICAL 0:0 +#define DP_CONTROLLER500_SDP_AUDIO_TIMESTAMP_VERTICAL_ENABLE 1 +#define DP_CONTROLLER500_SDP_AUDIO_TIMESTAMP_VERTICAL_DISABLE 0 + +#define DP_CONTROLLER504 0x0504 +#define DP_CONTROLLER504_SDP_AUDIO_STREAM_HORIZONTAL 1:1 +#define DP_CONTROLLER504_SDP_AUDIO_STREAM_HORIZONTAL_ENABLE 1 +#define DP_CONTROLLER504_SDP_AUDIO_STREAM_HORIZONTAL_DISABLE 0 +#define DP_CONTROLLER504_SDP_AUDIO_TIMESTAMP_HORIZONTAL 0:0 +#define DP_CONTROLLER504_SDP_AUDIO_TIMESTAMP_HORIZONTAL_ENABLE 1 +#define DP_CONTROLLER504_SDP_AUDIO_TIMESTAMP_HORIZONTAL_DISABLE 0 + +/* +`define apbCfg_REGISTER_ADDR_0508 16'h0508, 5'd31 , 5'd0 +`define apbCfg_SDP_STATUS 16'h0508, 5'd19, 5'd0 +`define apbCfg_REGISTER_ADDR_0510 16'h0510, 5'd31 , 5'd0 +`define apbCfg_SDP_STATUS_ENABLE 16'h0510, 5'd19, 5'd0 +`define apbCfg_REGISTER_ADDR_050C 16'h050C, 5'd31 , 5'd0 +`define apbCfg_SDP_MANUAL_CTRL_MANUAL_MODE 16'h050C, 5'd19, 5'd0 + +`define apbCfg_SDP_STATUS_VSC_HB 16'h0624, 5'd31, 5'd0 +`define apbCfg_SDP_STATUS_VSC_PAYLOAD0 16'h0628, 5'd31, 5'd0 +`define apbCfg_SDP_STATUS_VSC_PAYLOAD1 16'h062c, 5'd31, 5'd0 +`define apbCfg_SDP_STATUS_VSC_PAYLOAD2 16'h0630, 5'd31, 5'd0 +`define apbCfg_SDP_STATUS_VSC_PAYLOAD3 16'h0634, 5'd31, 5'd0 +`define apbCfg_SDP_STATUS_VSC_PAYLOAD4 16'h0638, 5'd31, 5'd0 +*/ + +#define DP_CONTROLLER50C 0x050C +#define DP_CONTROLLER50C_SDP_MANUAL_CTRL_MANUAL_MODE 19:0 + +#define DP_CONTROLLER624 0x0624 +#define DP_CONTROLLER624_VSC_HB 31:0 +#define DP_CONTROLLER628 0x0628 +#define DP_CONTROLLER628_VSC_PAYLOAD0 31:0 +#define DP_CONTROLLER62C 0x062C +#define DP_CONTROLLER62C_VSC_PAYLOAD1 31:0 +#define DP_CONTROLLER630 0x0630 +#define DP_CONTROLLER630_VSC_PAYLOAD2 31:0 +#define DP_CONTROLLER634 0x0634 +#define DP_CONTROLLER634_VSC_PAYLOAD3 31:0 +#define DP_CONTROLLER638 0x0638 +#define DP_CONTROLLER638_VSC_PAYLOAD4 31:0 +#define DP_CONTROLLER63C 0x063c +#define DP_CONTROLLER63C_VSC_PAYLOAD5 31:0 +#define DP_CONTROLLER640 0x0640 +#define DP_CONTROLLER640_VSC_PAYLOAD6 31:0 +#define DP_CONTROLLER644 0x0644 +#define DP_CONTROLLER644_VSC_PAYLOAD7 31:0 + +#define SCRATCH_PAD0 0x000060 + +#define SCRATCH_PAD1 0x000064 + +#ifdef __ICCARM__ +#define CLOCK_ENABLE (0x000068 + MMIO_BASE) +#else +#define CLOCK_ENABLE 0x0068 +#endif +#define CLOCK_ENABLE_DMA1R 31:31 +#define CLOCK_ENABLE_DMA1R_NORMAL 0 +#define CLOCK_ENABLE_DMA1R_RESET 1 +#define CLOCK_ENABLE_JPU1R 30:30 +#define CLOCK_ENABLE_JPU1R_NORMAL 0 +#define CLOCK_ENABLE_JPU1R_RESET 1 +#define CLOCK_ENABLE_HDMIR 29:29 +#define CLOCK_ENABLE_HDMIR_NORMAL 0 +#define CLOCK_ENABLE_HDMIR_RESET 1 +#define CLOCK_ENABLE_DDRR 28:28 +#define CLOCK_ENABLE_DDRR_NORMAL 0 +#define CLOCK_ENABLE_DDRR_RESET 1 +#define CLOCK_ENABLE_USBSR 27:27 +#define CLOCK_ENABLE_USBSR_NORMAL 0 +#define CLOCK_ENABLE_USBSR_RESET 1 +#define CLOCK_ENABLE_DC2R 26:26 +#define CLOCK_ENABLE_DC2R_NORMAL 0 +#define CLOCK_ENABLE_DC2R_RESET 1 +#define CLOCK_ENABLE_JPUR 25:25 +#define CLOCK_ENABLE_JPUR_NORMAL 0 +#define CLOCK_ENABLE_JPUR_RESET 1 +#define CLOCK_ENABLE_VPUR 24:24 +#define CLOCK_ENABLE_VPUR_NORMAL 0 +#define CLOCK_ENABLE_VPUR_RESET 1 +#define CLOCK_ENABLE_DER 23:23 +#define CLOCK_ENABLE_DER_NORMAL 0 +#define CLOCK_ENABLE_DER_RESET 1 +#define CLOCK_ENABLE_DMAR 22:22 +#define CLOCK_ENABLE_DMAR_NORMAL 0 +#define CLOCK_ENABLE_DMAR_RESET 1 +#define CLOCK_ENABLE_UARTR 21:21 +#define CLOCK_ENABLE_UARTR_NORMAL 0 +#define CLOCK_ENABLE_UARTR_RESET 1 +#define CLOCK_ENABLE_I2SR 20:20 +#define CLOCK_ENABLE_I2SR_NORMAL 0 +#define CLOCK_ENABLE_I2SR_RESET 1 +#define CLOCK_ENABLE_SSPR 19:19 +#define CLOCK_ENABLE_SSPR_NORMAL 0 +#define CLOCK_ENABLE_SSPR_RESET 1 +#define CLOCK_ENABLE_DC1R 18:18 +#define CLOCK_ENABLE_DC1R_NORMAL 0 +#define CLOCK_ENABLE_DC1R_RESET 1 +#define CLOCK_ENABLE_DC0R 17:17 +#define CLOCK_ENABLE_DC0R_NORMAL 0 +#define CLOCK_ENABLE_DC0R_RESET 1 +#define CLOCK_ENABLE_ARMR 16:16 +#define CLOCK_ENABLE_ARMR_NORMAL 0 +#define CLOCK_ENABLE_ARMR_RESET 1 +#define CLOCK_ENABLE_DMA1 15:15 +#define CLOCK_ENABLE_DMA1_OFF 0 +#define CLOCK_ENABLE_DMA1_ON 1 +#define CLOCK_ENABLE_JPU1 14:14 +#define CLOCK_ENABLE_JPU1_OFF 0 +#define CLOCK_ENABLE_JPU1_ON 1 +#define CLOCK_ENABLE_HDMI 13:13 +#define CLOCK_ENABLE_HDMI_OFF 0 +#define CLOCK_ENABLE_HDMI_ON 1 +#define CLOCK_ENABLE_USBS 11:11 +#define CLOCK_ENABLE_USBS_OFF 0 +#define CLOCK_ENABLE_USBS_ON 1 +#define CLOCK_ENABLE_DC2 10:10 +#define CLOCK_ENABLE_DC2_OFF 0 +#define CLOCK_ENABLE_DC2_ON 1 +#define CLOCK_ENABLE_JPU 9:9 +#define CLOCK_ENABLE_JPU_OFF 0 +#define CLOCK_ENABLE_JPU_ON 1 +#define CLOCK_ENABLE_VPU 8:8 +#define CLOCK_ENABLE_VPU_OFF 0 +#define CLOCK_ENABLE_VPU_ON 1 +#define CLOCK_ENABLE_DE 7:7 +#define CLOCK_ENABLE_DE_OFF 0 +#define CLOCK_ENABLE_DE_ON 1 +#define CLOCK_ENABLE_DMA 6:6 +#define CLOCK_ENABLE_DMA_OFF 0 +#define CLOCK_ENABLE_DMA_ON 1 +#define CLOCK_ENABLE_UART 5:5 +#define CLOCK_ENABLE_UART_OFF 0 +#define CLOCK_ENABLE_UART_ON 1 +#define CLOCK_ENABLE_I2S 4:4 +#define CLOCK_ENABLE_I2S_OFF 0 +#define CLOCK_ENABLE_I2S_ON 1 +#define CLOCK_ENABLE_SSP 3:3 +#define CLOCK_ENABLE_SSP_OFF 0 +#define CLOCK_ENABLE_SSP_ON 1 +#define CLOCK_ENABLE_DC1 2:2 +#define CLOCK_ENABLE_DC1_OFF 0 +#define CLOCK_ENABLE_DC1_ON 1 +#define CLOCK_ENABLE_DC0 1:1 +#define CLOCK_ENABLE_DC0_OFF 0 +#define CLOCK_ENABLE_DC0_ON 1 +#define CLOCK_ENABLE_ARM 0:0 +#define CLOCK_ENABLE_ARM_OFF 0 +#define CLOCK_ENABLE_ARM_ON 1 + +#define CLOCK1_ENABLE 0x0140 +#define CLOCK1_ENABLE_PCIER 30:30 +#define CLOCK1_ENABLE_PCIER_NORMAL 0 +#define CLOCK1_ENABLE_PCIER_RESET 1 + +#define CLOCK1_ENABLE_EFUSER 27:27 +#define CLOCK1_ENABLE_EFUSER_NORMAL 0 +#define CLOCK1_ENABLE_EFUSER_RESET 1 +#define CLOCK1_ENABLE_LVDSPHYR 26:26 +#define CLOCK1_ENABLE_LVDSPHYR_NORMAL 0 +#define CLOCK1_ENABLE_LVDSPHYR_RESET 1 +#define CLOCK1_ENABLE_LPDDR4PHYR 25:25 +#define CLOCK1_ENABLE_LPDDR4PHYR_NORMAL 0 +#define CLOCK1_ENABLE_LPDDR4PHYR_RESET 1 +#define CLOCK1_ENABLE_LPDDR4CTLR 24:24 +#define CLOCK1_ENABLE_LPDDR4CTLR_NORMAL 0 +#define CLOCK1_ENABLE_LPDDR4CTLR_RESET 1 +#define CLOCK1_ENABLE_DP1R 23:23 +#define CLOCK1_ENABLE_DP1R_NORMAL 0 +#define CLOCK1_ENABLE_DP1R_RESET 1 +#define CLOCK1_ENABLE_DP0R 22:22 +#define CLOCK1_ENABLE_DP0R_NORMAL 0 +#define CLOCK1_ENABLE_DP0R_RESET 1 +#define CLOCK1_ENABLE_HDCP0R 21:21 +#define CLOCK1_ENABLE_HDCP0R_NORMAL 0 +#define CLOCK1_ENABLE_HDCP0R_RESET 1 + +#define CLOCK1_ENABLE_HDMI2R 20:20 +#define CLOCK1_ENABLE_HDMI2R_NORMAL 0 +#define CLOCK1_ENABLE_HDMI2R_RESET 1 +#define CLOCK1_ENABLE_HDMI1R 19:19 +#define CLOCK1_ENABLE_HDMI1R_NORMAL 0 +#define CLOCK1_ENABLE_HDMI1R_RESET 1 +#define CLOCK1_ENABLE_HDMI0R 18:18 +#define CLOCK1_ENABLE_HDMI0R_NORMAL 0 +#define CLOCK1_ENABLE_HDMI0R_RESET 1 + +#define CLOCK1_ENABLE_JPU3R 17:17 +#define CLOCK1_ENABLE_JPU3R_NORMAL 0 +#define CLOCK1_ENABLE_JPU3R_RESET 1 +#define CLOCK1_ENABLE_JPU2R 16:16 +#define CLOCK1_ENABLE_JPU2R_NORMAL 0 +#define CLOCK1_ENABLE_JPU2R_RESET 1 + +#define CLOCK1_ENABLE_PCIE 14:14 +#define CLOCK1_ENABLE_PCIE_OFF 0 +#define CLOCK1_ENABLE_PCIE_ON 1 + +#define CLOCK1_ENABLE_LPDDR4 8:8 +#define CLOCK1_ENABLE_LPDDR4_OFF 0 +#define CLOCK1_ENABLE_LPDDR4_ON 1 +#define CLOCK1_ENABLE_DP1 7:7 +#define CLOCK1_ENABLE_DP1_OFF 0 +#define CLOCK1_ENABLE_DP1_ON 1 +#define CLOCK1_ENABLE_DP0 6:6 +#define CLOCK1_ENABLE_DP0_OFF 0 +#define CLOCK1_ENABLE_DP0_ON 1 + +#define CLOCK1_ENABLE_HDCP0 5:5 +#define CLOCK1_ENABLE_HDCP0_OFF 0 +#define CLOCK1_ENABLE_HDCP0_ON 1 + + +#define CLOCK1_ENABLE_HDMI2 4:4 +#define CLOCK1_ENABLE_HDMI2_OFF 0 +#define CLOCK1_ENABLE_HDMI2_ON 1 +#define CLOCK1_ENABLE_HDMI1 3:3 +#define CLOCK1_ENABLE_HDMI1_OFF 0 +#define CLOCK1_ENABLE_HDMI1_ON 1 +#define CLOCK1_ENABLE_HDMI0 2:2 +#define CLOCK1_ENABLE_HDMI0_OFF 0 +#define CLOCK1_ENABLE_HDMI0_ON 1 + +#define CLOCK1_ENABLE_JPU3 1:1 +#define CLOCK1_ENABLE_JPU3_OFF 0 +#define CLOCK1_ENABLE_JPU3_ON 1 +#define CLOCK1_ENABLE_JPU2 0:0 +#define CLOCK1_ENABLE_JPU2_OFF 0 +#define CLOCK1_ENABLE_JPU2_ON 1 + + + +/* No bit fields for VGA PLL since DDK don't use it */ +#define VGA25PLL 0x00006C +#define VGA28PLL 0x000070 + +/* Master clock for DDR and core */ +#define MCLK_PLL 0x000074 +#define MCLK_PLL_VCO 23:22 +#define MCLK_PLL_INT 21:16 +#define MCLK_PLL_POWER 0:0 +#define MCLK_PLL_POWER_NORMAL 0 +#define MCLK_PLL_POWER_DOWN 1 + +#define PLL3_SET 0x000230 +#define PLL3_SET_PLL3PD 10:10 +#define PLL3_SET_PLL3PD_OFF 0 +#define PLL3_SET_PLL3PD_ON 1 + +#define PLL_SET 0x000228 +#define PLL_SET_VCLK0PD 16:16 +#define PLL_SET_VCLK0PD_OFF 0 +#define PLL_SET_VCLK0PD_ON 1 +#define PLL_SET_VCLK1PD 28:28 +#define PLL_SET_VCLK1PD_OFF 0 +#define PLL_SET_VCLK1PD_ON 1 + +#if 0 +#define PLL_SET_PLL3PD 24:24 +#define PLL_SET_PLL3PD_OFF 0 +#define PLL_SET_PLL3PD_ON 1 +#endif + +#define PLL_SET_PLL2PD 20:20 +#define PLL_SET_PLL2PD_OFF 0 +#define PLL_SET_PLL2PD_ON 1 + +#define PLL_SET_VCLK0LOCK 13:13 +#define PLL_SET_VCLK0LOCK_ON 1 +#define PLL_SET_VCLK0LOCK_OFF 0 + +#define PLL_SET_PLL2LOCK 7:7 +#define PLL_SET_PLL2LOCK_ON 1 +#define PLL_SET_PLL2LOCK_OFF 0 + +#define PLL_SET_PLL3LOCK 4:4 +#define PLL_SET_PLL3LOCK_ON 1 +#define PLL_SET_PLL3LOCK_OFF 0 + +#define PLL_SET_VCLK1LOCK 2:2 +#define PLL_SET_VCLK1LOCK_ON 1 +#define PLL_SET_VCLK1LOCK_OFF 0 +#define PLL_SET_VCLK2LOCK 0:0 +#define PLL_SET_VCLK2LOCK_ON 1 +#define PLL_SET_VCLK2LOCK_OFF 0 + +#define PLL_SET1 0x00022C +#define PLL_SET1_VCLK0CP 29:28 +#define PLL_SET1_VCLK2PD 0:0 +#define PLL_SET1_VCLK2PD_OFF 0 +#define PLL_SET1_VCLK2PD_ON 1 + +/* Video clock 0 */ +#define VCLK_PLL 0x000230 +#define VCLK_PLL_SSCSEL 30:30 +#define VCLK_PLL_SSCSEL_XTAL 0 +#define VCLK_PLL_SSCSEL_SSCG 1 +#define VCLK_PLL_PRESEL 27:27 +#define VCLK_PLL_PRESEL_250 0 +#define VCLK_PLL_PRESEL_125 1 +#define VCLK_PLL_VCO 26:24 +#define VCLK_PLL_DIVIDER 23:16 + +/* Video clock 1. Bit field definiton is same as VCLK0 */ +#define VCLK1_PLL 0x000238 +#define VCLK1_PLL_VCLK1CP 13:12 + +/* Video clock 1. Bit field definiton is same as VCLK0 */ +#define VCLK2_PLL 0x00023c +#define VCLK2_PLL_VCLK2CP 13:12 + +/* PLL3 (system including DDR/CPU/APB) */ +#define PLL3_PLL 0x000234 +#define PLL3_PLL_PRESEL 27:27 +#define PLL3_PLL_PRESEL_250 0 +#define PLL3_PLL_PRESEL_125 1 +#define PLL3_PLL_VCO 26:24 +#define PLL3_PLL_DIVIDER 23:16 + +/* PLL2 (VPU and JPU) */ +#define PLL2_PLL 0x000234 +#define PLL2_PLL_PRESEL 11:11 +#define PLL2_PLL_PRESEL_250 0 +#define PLL2_PLL_PRESEL_125 1 +#define PLL2_PLL_VCO 10:8 +#define PLL2_PLL_DIVIDER 7:0 + +#define SSCG_CTL 0x000354 +#define SSCG_CTL_FN 27:27 +#define SSCG_CTL_FN_DISABLE 0 +#define SSCG_CTL_FN_ENABLE 1 +#define SSCG_CTL_PORCORE 17:17 +#define SSCG_CTL_PORCORE_DISABLE 0 +#define SSCG_CTL_PORCORE_ENABLE 1 +#define SSCG_CTL_SSCGPD 5:5 +#define SSCG_CTL_SSCGPD_OFF 0 +#define SSCG_CTL_SSCGPD_ON 1 + +#define SSCG_SET 0x000358 +#define SSCG_SET_MODE 31:30 +#define SSCG_SET_MODE_NO 0 +#define SSCG_SET_MODE_DOWN 1 +#define SSCG_SET_MODE_CENTER 2 +#define SSCG_SET_MODE_UP 3 +#define SSCG_SET_DIV 14:0 + +/* Clock Control 3 */ +#define CLOCK3_CTL 0x3bc + +#define CLOCK3_CTL_LVDS1CLK 6:6 +#define CLOCK3_CTL_LVDS1CLK_HALF 1 +#define CLOCK3_CTL_LVDS1CLK_NORMAL 0 +#define CLOCK3_CTL_LVDS0CLK 5:5 +#define CLOCK3_CTL_LVDS0CLK_HALF 1 +#define CLOCK3_CTL_LVDS0CLK_NORMAL 0 + +#define CLOCK3_CTL_SYCCLK 2:0 +#define CLOCK3_CTL_SYCCLK_PLL3 1 +#define CLOCK3_CTL_SYCCLK_24MHZ 2 +#define CLOCK3_CTL_SYCCLK_LFOSC 4 + +#define PROTOCOL_SEMAPHORE0 0x000080 +#define PROTOCOL_SEMAPHORE1 0x000084 + +#define VGA_CONFIGURATION 0x000088 +#define VGA_CONFIGURATION_PLL 2:2 +#define VGA_CONFIGURATION_PLL_VGA 0 +#define VGA_CONFIGURATION_PLL_PANEL 1 +#define VGA_CONFIGURATION_MODE 1:1 +#define VGA_CONFIGURATION_MODE_TEXT 0 +#define VGA_CONFIGURATION_MODE_GRAPHIC 1 +#define VGA_CONFIGURATION_PREFETCH 0:0 +#define VGA_CONFIGURATION_PREFETCH_DISABLE 0 +#define VGA_CONFIGURATION_PREFETCH_ENABLE 1 + +/* Lock or unlock PCIE bar 2 to 5 */ +#define PCIE_BAR 0x00008C +#define PCIE_BAR_LOCK 0:0 +#define PCIE_BAR_LOCK_UNLOCK 0 +#define PCIE_BAR_LOCK_LOCK 1 + +#define RAW_INT 0x000090 +#define RAW_INT_VPU 6:6 +#define RAW_INT_VPU_INACTIVE 0 +#define RAW_INT_VPU_ACTIVE 1 +#define RAW_INT_VPU_CLEAR 1 +#define RAW_INT_CSC 5:5 +#define RAW_INT_CSC_INACTIVE 0 +#define RAW_INT_CSC_ACTIVE 1 +#define RAW_INT_CSC_CLEAR 1 +#define RAW_INT_DE 4:4 +#define RAW_INT_DE_INACTIVE 0 +#define RAW_INT_DE_ACTIVE 1 +#define RAW_INT_DE_CLEAR 1 +#define RAW_INT_CHANNEL2_VSYNC 3:3 +#define RAW_INT_CHANNEL2_VSYNC_INACTIVE 0 +#define RAW_INT_CHANNEL2_VSYNC_ACTIVE 1 +#define RAW_INT_CHANNEL2_VSYNC_CLEAR 1 +#define RAW_INT_CHANNEL1_VSYNC 2:2 +#define RAW_INT_CHANNEL1_VSYNC_INACTIVE 0 +#define RAW_INT_CHANNEL1_VSYNC_ACTIVE 1 +#define RAW_INT_CHANNEL1_VSYNC_CLEAR 1 +#define RAW_INT_CHANNEL0_VSYNC 1:1 +#define RAW_INT_CHANNEL0_VSYNC_INACTIVE 0 +#define RAW_INT_CHANNEL0_VSYNC_ACTIVE 1 +#define RAW_INT_CHANNEL0_VSYNC_CLEAR 1 +#define RAW_INT_VGA_VSYNC 0:0 +#define RAW_INT_VGA_VSYNC_INACTIVE 0 +#define RAW_INT_VGA_VSYNC_ACTIVE 1 +#define RAW_INT_VGA_VSYNC_CLEAR 1 + +#ifdef SMI_ARM +#define INT_STATUS 0x0000A8 +#else +#define INT_STATUS 0x000094 +#endif +#define INT_STATUS_TIMER3 31:31 +#define INT_STATUS_TIMER3_INACTIVE 0 +#define INT_STATUS_TIMER3_ACTIVE 1 +#define INT_STATUS_TIMER2 30:30 +#define INT_STATUS_TIMER2_INACTIVE 0 +#define INT_STATUS_TIMER2_ACTIVE 1 +#define INT_STATUS_TIMER1 29:29 +#define INT_STATUS_TIMER1_INACTIVE 0 +#define INT_STATUS_TIMER1_ACTIVE 1 +#define INT_STATUS_TIMER0 28:28 +#define INT_STATUS_TIMER0_INACTIVE 0 +#define INT_STATUS_TIMER0_ACTIVE 1 +#define INT_STATUS_VPU 27:27 +#define INT_STATUS_VPU_INACTIVE 0 +#define INT_STATUS_VPU_ACTIVE 1 +#define INT_STATUS_JPU3 26:26 +#define INT_STATUS_JPU3_INACTIVE 0 +#define INT_STATUS_JPU3_ACTIVE 1 +#define INT_STATUS_JPU2 25:25 +#define INT_STATUS_JPU2_INACTIVE 0 +#define INT_STATUS_JPU2_ACTIVE 1 +#define INT_STATUS_JPU1 24:24 +#define INT_STATUS_JPU1_INACTIVE 0 +#define INT_STATUS_JPU1_ACTIVE 1 +#define INT_STATUS_JPU0 23:23 +#define INT_STATUS_JPU0_INACTIVE 0 +#define INT_STATUS_JPU0_ACTIVE 1 +#define INT_STATUS_USBS 22:22 +#define INT_STATUS_USBS_INACTIVE 0 +#define INT_STATUS_USBS_ACTIVE 1 +#define INT_STATUS_I2S 21:21 +#define INT_STATUS_I2S_INACTIVE 0 +#define INT_STATUS_I2S_ACTIVE 1 +#define INT_STATUS_SSP0 20:20 +#define INT_STATUS_SSP0_INACTIVE 0 +#define INT_STATUS_SSP0_ACTIVE 1 +#define INT_STATUS_I2C0 18:18 +#define INT_STATUS_I2C0_INACTIVE 0 +#define INT_STATUS_I2C0_ACTIVE 1 +#define INT_STATUS_HDCP 17:17 +#define INT_STATUS_HDCP_INACTIVE 0 +#define INT_STATUS_HDCP_ACTIVE 1 +#define INT_STATUS_HDMI2WK 16:16 +#define INT_STATUS_HDMI2WK_INACTIVE 0 +#define INT_STATUS_HDMI2WK_ACTIVE 1 +#define INT_STATUS_HDMI2 15:15 +#define INT_STATUS_HDMI2_INACTIVE 0 +#define INT_STATUS_HDMI2_ACTIVE 1 +#define INT_STATUS_HDMI1WK 14:14 +#define INT_STATUS_HDMI1WK_INACTIVE 0 +#define INT_STATUS_HDMI1WK_ACTIVE 1 +#define INT_STATUS_HDMI1 13:13 +#define INT_STATUS_HDMI1_INACTIVE 0 +#define INT_STATUS_HDMI1_ACTIVE 1 +#define INT_STATUS_HDMI0WK 12:12 +#define INT_STATUS_HDMI0WK_INACTIVE 0 +#define INT_STATUS_HDMI0WK_ACTIVE 1 +#define INT_STATUS_HDMI0 11:11 +#define INT_STATUS_HDMI0_INACTIVE 0 +#define INT_STATUS_HDMI0_ACTIVE 1 +#define INT_STATUS_HDMI0_CLEAR 1 +#define INT_STATUS_DP1 10:10 +#define INT_STATUS_DP1_INACTIVE 0 +#define INT_STATUS_DP1_ACTIVE 1 +#define INT_STATUS_DP0 9:9 +#define INT_STATUS_DP0_INACTIVE 0 +#define INT_STATUS_DP0_ACTIVE 1 +#define INT_STATUS_DMA 8:8 +#define INT_STATUS_DMA_INACTIVE 0 +#define INT_STATUS_DMA_ACTIVE 1 +#define INT_STATUS_CPU 7:7 +#define INT_STATUS_CPU_INACTIVE 0 +#define INT_STATUS_CPU_ACTIVE 1 +#define INT_STATUS_DE 6:6 +#define INT_STATUS_DE_INACTIVE 0 +#define INT_STATUS_DE_ACTIVE 1 +#define INT_STATUS_CHANNEL2_VSYNC 5:5 +#define INT_STATUS_CHANNEL2_VSYNC_INACTIVE 0 +#define INT_STATUS_CHANNEL2_VSYNC_ACTIVE 1 +#define INT_STATUS_CHANNEL1_VSYNC 4:4 +#define INT_STATUS_CHANNEL1_VSYNC_INACTIVE 0 +#define INT_STATUS_CHANNEL1_VSYNC_ACTIVE 1 +#define INT_STATUS_CHANNEL0_VSYNC 3:3 +#define INT_STATUS_CHANNEL0_VSYNC_INACTIVE 0 +#define INT_STATUS_CHANNEL0_VSYNC_ACTIVE 1 +#define INT_STATUS_PCIE_ST0 0:0 +#define INT_STATUS_PCIE_ST0_INACTIVE 0 +#define INT_STATUS_PCIE_ST0_ACTIVE 1 + +#ifdef SMI_ARM +#define INT_MASK 0x00009C +#else +#define INT_MASK 0x000098 +#endif + +#define INT_MASK_TIMER3 31:31 +#define INT_MASK_TIMER3_DISABLE 0 +#define INT_MASK_TIMER3_ENABLE 1 +#define INT_MASK_TIMER2 30:30 +#define INT_MASK_TIMER2_DISABLE 0 +#define INT_MASK_TIMER2_ENABLE 1 +#define INT_MASK_TIMER1 29:29 +#define INT_MASK_TIMER1_DISABLE 0 +#define INT_MASK_TIMER1_ENABLE 1 +#define INT_MASK_TIMER0 28:28 +#define INT_MASK_TIMER0_DISABLE 0 +#define INT_MASK_TIMER0_ENABLE 1 +#define INT_MASK_VPU 27:27 +#define INT_MASK_VPU_DISABLE 0 +#define INT_MASK_VPU_ENABLE 1 +#define INT_MASK_JPU3 26:26 +#define INT_MASK_JPU3_DISABLE 0 +#define INT_MASK_JPU3_ENABLE 1 +#define INT_MASK_JPU2 25:25 +#define INT_MASK_JPU2_DISABLE 0 +#define INT_MASK_JPU2_ENABLE 1 +#define INT_MASK_JPU1 24:24 +#define INT_MASK_JPU1_DISABLE 0 +#define INT_MASK_JPU1_ENABLE 1 +#define INT_MASK_JPU0 23:23 +#define INT_MASK_JPU0_DISABLE 0 +#define INT_MASK_JPU0_ENABLE 1 +#define INT_MASK_USBS 22:22 +#define INT_MASK_USBS_DISABLE 0 +#define INT_MASK_USBS_ENABLE 1 +#define INT_MASK_I2S 21:21 +#define INT_MASK_I2S_DISABLE 0 +#define INT_MASK_I2S_ENABLE 1 +#define INT_MASK_SSP0 20:20 +#define INT_MASK_SSP0_DISABLE 0 +#define INT_MASK_SSP0_ENABLE 1 +#define INT_MASK_I2C1 19:19 +#define INT_MASK_I2C1_DISABLE 0 +#define INT_MASK_I2C1_ENABLE 1 +#define INT_MASK_I2C0 18:18 +#define INT_MASK_I2C0_DISABLE 0 +#define INT_MASK_I2C0_ENABLE 1 +#define INT_MASK_HDCP 17:17 +#define INT_MASK_HDCP_DISABLE 0 +#define INT_MASK_HDCP_ENABLE 1 +#define INT_MASK_HDMI2WK 16:16 +#define INT_MASK_HDMI2WK_DISABLE 0 +#define INT_MASK_HDMI2WK_ENABLE 1 +#define INT_MASK_HDMI2 15:15 +#define INT_MASK_HDMI2_DISABLE 0 +#define INT_MASK_HDMI2_ENABLE 1 +#define INT_MASK_HDMI1WK 14:14 +#define INT_MASK_HDMI1WK_DISABLE 0 +#define INT_MASK_HDMI1WK_ENABLE 1 +#define INT_MASK_HDMI1 13:13 +#define INT_MASK_HDMI1_DISABLE 0 +#define INT_MASK_HDMI1_ENABLE 1 +#define INT_MASK_HDMI0WK 12:12 +#define INT_MASK_HDMI0WK_DISABLE 0 +#define INT_MASK_HDMI0WK_ENABLE 1 +#define INT_MASK_HDMI0 11:11 +#define INT_MASK_HDMI0_DISABLE 0 +#define INT_MASK_HDMI0_ENABLE 1 +#define INT_MASK_DP1 10:10 +#define INT_MASK_DP1_DISABLE 0 +#define INT_MASK_DP1_ENABLE 1 +#define INT_MASK_DP0 9:9 +#define INT_MASK_DP0_DISABLE 0 +#define INT_MASK_DP0_ENABLE 1 +#define INT_MASK_DMA 8:8 +#define INT_MASK_DMA_DISABLE 0 +#define INT_MASK_DMA_ENABLE 1 +#define INT_MASK_CPU 7:7 +#define INT_MASK_CPU_DISABLE 0 +#define INT_MASK_CPU_ENABLE 1 +#define INT_MASK_DE 6:6 +#define INT_MASK_DE_DISABLE 0 +#define INT_MASK_DE_ENABLE 1 +#define INT_MASK_CHANNEL2_VSYNC 5:5 +#define INT_MASK_CHANNEL2_VSYNC_DISABLE 0 +#define INT_MASK_CHANNEL2_VSYNC_ENABLE 1 +#define INT_MASK_CHANNEL1_VSYNC 4:4 +#define INT_MASK_CHANNEL1_VSYNC_DISABLE 0 +#define INT_MASK_CHANNEL1_VSYNC_ENABLE 1 +#define INT_MASK_CHANNEL0_VSYNC 3:3 +#define INT_MASK_CHANNEL0_VSYNC_DISABLE 0 +#define INT_MASK_CHANNEL0_VSYNC_ENABLE 1 +#define INT_MASK_STATUS_PCIE_ST0 0:0 +#define INT_MASK_STATUS_PCIE_ST0_DISABLE 0 +#define INT_MASK_STATUS_PCIE_ST0_ENABLE 1 + +#define INT_STATUS1 0x0000B4 + +#define INT_STATUS1_PWM 11:11 +#define INT_STATUS1_PWM_INACTIVE 0 +#define INT_STATUS1_PWM_ACTIVE 1 +#define INT_STATUS1_TRNG 10:10 +#define INT_STATUS1_TRNG_INACTIVE 0 +#define INT_STATUS1_TRNG_ACTIVE 1 +#define INT_STATUS1_UART1 9:9 +#define INT_STATUS1_UART1_INACTIVE 0 +#define INT_STATUS1_UART1_ACTIVE 1 +#define INT_STATUS1_UART0 8:8 +#define INT_STATUS1_UART0_INACTIVE 0 +#define INT_STATUS1_UART0_ACTIVE 1 +#define INT_STATUS1_GPIO44 7:7 +#define INT_STATUS1_GPIO44_INACTIVE 0 +#define INT_STATUS1_GPIO44_ACTIVE 1 +#define INT_STATUS1_GPIO43 6:6 +#define INT_STATUS1_GPIO43_INACTIVE 0 +#define INT_STATUS1_GPIO43_ACTIVE 1 +#define INT_STATUS1_GPIO57 5:5 +#define INT_STATUS1_GPIO57_INACTIVE 0 +#define INT_STATUS1_GPIO57_ACTIVE 1 +#define INT_STATUS1_GPIO56 4:4 +#define INT_STATUS1_GPIO56_INACTIVE 0 +#define INT_STATUS1_GPIO56_ACTIVE 1 +#define INT_STATUS1_GPIO55 3:3 +#define INT_STATUS1_GPIO55_INACTIVE 0 +#define INT_STATUS1_GPIO55_ACTIVE 1 +#define INT_STATUS1_GPIO54 2:2 +#define INT_STATUS1_GPIO54_INACTIVE 0 +#define INT_STATUS1_GPIO54_ACTIVE 1 +#define INT_STATUS1_GPIO53 1:1 +#define INT_STATUS1_GPIO53_INACTIVE 0 +#define INT_STATUS1_GPIO53_ACTIVE 1 +#define INT_STATUS1_CSC 0:0 +#define INT_STATUS1_CSC_INACTIVE 0 +#define INT_STATUS1_CSC_ACTIVE 1 + +#define INT_MASK1 0x0000B8 + +#define INT_MASK1_PWM 11:11 +#define INT_MASK1_PWM_DISABLE 0 +#define INT_MASK1_PWM_ENABLE 1 +#define INT_MASK1_TRNG 10:10 +#define INT_MASK1_TRNG_DISABLE 0 +#define INT_MASK1_TRNG_ENABLE 1 +#define INT_MASK1_UART1 9:9 +#define INT_MASK1_UART1_DISABLE 0 +#define INT_MASK1_UART1_ENABLE 1 +#define INT_MASK1_UART0 8:8 +#define INT_MASK1_UART0_DISABLE 0 +#define INT_MASK1_UART0_ENABLE 1 +#define INT_MASK1_GPIO44 7:7 +#define INT_MASK1_GPIO44_DISABLE 0 +#define INT_MASK1_GPIO44_ENABLE 1 +#define INT_MASK1_GPIO43 6:6 +#define INT_MASK1_GPIO43_DISABLE 0 +#define INT_MASK1_GPIO43_ENABLE 1 +#define INT_MASK1_GPIO57 5:5 +#define INT_MASK1_GPIO57_DISABLE 0 +#define INT_MASK1_GPIO57_ENABLE 1 +#define INT_MASK1_GPIO56 4:4 +#define INT_MASK1_GPIO56_DISABLE 0 +#define INT_MASK1_GPIO56_ENABLE 1 +#define INT_MASK1_GPIO55 3:3 +#define INT_MASK1_GPIO55_DISABLE 0 +#define INT_MASK1_GPIO55_ENABLE 1 +#define INT_MASK1_GPIO54 2:2 +#define INT_MASK1_GPIO54_DISABLE 0 +#define INT_MASK1_GPIO54_ENABLE 1 +#define INT_MASK1_GPIO53 1:1 +#define INT_MASK1_GPIO53_DISABLE 0 +#define INT_MASK1_GPIO53_ENABLE 1 +#define INT_MASK1_CSC 0:0 +#define INT_MASK1_CSC_DISABLE 0 +#define INT_MASK1_CSC_ENABLE 1 + +#define ARM_PROTOCOL_INT 0x0000A0 +#define ARM_PROTOCOL_INT_TOKEN 31:1 +#define ARM_PROTOCOL_INT_ENABLE 0:0 +#define ARM_PROTOCOL_INT_ENABLE_CLEAR 0 +#define ARM_PROTOCOL_INT_ENABLE_ENABLE 1 + +#define PCIE_PROTOCOL_INT 0x0000A4 +#define PCIE_PROTOCOL_INT_TOKEN 31:1 +#define PCIE_PROTOCOL_INT_ENABLE 0:0 +#define PCIE_PROTOCOL_INT_ENABLE_CLEAR 0 +#define PCIE_PROTOCOL_INT_ENABLE_ENABLE 1 + +#define ARM_STARTUP_CONFIG 0x000100 +#define ARM_STARTUP_CONFIG_USBH 30:30 +#define ARM_STARTUP_CONFIG_USBH_NORMAL 0 +#define ARM_STARTUP_CONFIG_USBH_RESET 1 +#define ARM_STARTUP_CONFIG_USBHPHY 29:29 +#define ARM_STARTUP_CONFIG_USBHPHY_NORMAL 0 +#define ARM_STARTUP_CONFIG_USBHPHY_RESET 1 +#define ARM_STARTUP_CONFIG_USBSPHY 28:28 +#define ARM_STARTUP_CONFIG_USBSPHY_NORMAL 0 +#define ARM_STARTUP_CONFIG_USBSPHY_RESET 1 +#define ARM_STARTUP_CONFIG_USBS 27:27 +#define ARM_STARTUP_CONFIG_USBS_NORMAL 0 +#define ARM_STARTUP_CONFIG_USBS_RESET 1 +#define ARM_STARTUP_CONFIG_ARM 0:0 +#define ARM_STARTUP_CONFIG_ARM_STOP 0 +#define ARM_STARTUP_CONFIG_ARM_START 1 + +#define ARM_CONTROL 0x000110 +#define ARM_CONTROL_RESET 0:0 +#define ARM_CONTROL_RESET_RESET 0 +#define ARM_CONTROL_RESET_NORMAL 1 + +#define STRAP_PINS1 0x0010000 +#define STRAP_PINS1_BOOTDMA 30:30 +#define STRAP_PINS1_BOOTDMA_USB 0 +#define STRAP_PINS1_BOOTDMA_PCIE 1 +#define STRAP_PINS1_MEM_SIZE 31:31 +#define STRAP_PINS1_MEM_SIZE_256M 0 +#define STRAP_PINS1_MEM_SIZE_512M 1 + +#define STRAP_PINS2 0x0010018 +#define STRAP_PINS2_MEM_SIZE 0:0 +#define STRAP_PINS2_MEM_SIZE_X1 0 +#define STRAP_PINS2_MEM_SIZE_X4 1 +#define STRAP_PINS2_DDRRATE 1:1 +#define STRAP_PINS2_DDRRATE_3200 0 +#define STRAP_PINS2_DDRRATE_1600 1 +#define STRAP_PINS2_DDRWIDTH 2:2 +#define STRAP_PINS2_DDRWIDTH_HALF 0 +#define STRAP_PINS2_DDRWIDTH_FULL 1 +#define STRAP_PINS2_DDRTYPE 3:3 +#define STRAP_PINS2_DDRTYPE_DDR4 0 +#define STRAP_PINS2_DDRTYPE_LPDDR4 1 + +#define JPU_PERFORMANCE_MODE 0x000134 +#define JPU_PERFORMANCE_MODE_JPU1 3:2 +#define JPU_PERFORMANCE_MODE_JPU1_DISABLE 0 +#define JPU_PERFORMANCE_MODE_JPU1_HD 1 +#define JPU_PERFORMANCE_MODE_JPU1_UHD 2 +#define JPU_PERFORMANCE_MODE_JPU0 1:0 +#define JPU_PERFORMANCE_MODE_JPU0_DISABLE 0 +#define JPU_PERFORMANCE_MODE_JPU0_HD 1 +#define JPU_PERFORMANCE_MODE_JPU0_UHD 2 + +#define PMODE_2K 2048 +#define PMODE_4K 4096 + +#define DDR_PRIORITY1 0x000138 + +#define DDR_PRIORITY2 0x00013C + +#define THERMAL_SENSOR 0x214 +#define THERMAL_SENSOR_STATUS 10:10 +#define THERMAL_SENSOR_STATUS_ENABLE 1 +#define THERMAL_SENSOR_STATUS_DISABLE 0 +#define THERMAL_SENSOR_VALUE_BIT8 9:9 +#define THERMAL_SENSOR_PD 8:8 +#define THERMAL_SENSOR_PD_ENABLE 1 +#define THERMAL_SENSOR_PD_DISABLE 0 +#define THERMAL_SENSOR_VALUE_LOWBIT 7:0 + +#define CHIP_REV 0x8B0 +#define CHIP_REV_AA 0 +#define CHIP_REV_AB 1 + +#define GPIO_DATA 0x010000 +#define GPIO_DATA_31 31:31 +#define GPIO_DATA_30 30:30 +#define GPIO_DATA_29 29:29 +#define GPIO_DATA_28 28:28 +#define GPIO_DATA_27 27:27 +#define GPIO_DATA_26 26:26 +#define GPIO_DATA_25 25:25 +#define GPIO_DATA_24 24:24 +#define GPIO_DATA_23 23:23 +#define GPIO_DATA_22 22:22 +#define GPIO_DATA_21 21:21 +#define GPIO_DATA_20 20:20 +#define GPIO_DATA_19 19:19 +#define GPIO_DATA_18 18:18 +#define GPIO_DATA_17 17:17 +#define GPIO_DATA_16 16:16 +#define GPIO_DATA_15 15:15 +#define GPIO_DATA_14 14:14 +#define GPIO_DATA_13 13:13 +#define GPIO_DATA_12 12:12 +#define GPIO_DATA_11 11:11 +#define GPIO_DATA_10 10:10 +#define GPIO_DATA_9 9:9 +#define GPIO_DATA_8 8:8 +#define GPIO_DATA_7 7:7 +#define GPIO_DATA_6 6:6 +#define GPIO_DATA_5 5:5 +#define GPIO_DATA_4 4:4 +#define GPIO_DATA_3 3:3 +#define GPIO_DATA_2 2:2 +#define GPIO_DATA_1 1:1 +#define GPIO_DATA_0 0:0 + +#define GPIO_DATA2 0x010018 +#define GPIO_DATA2_60 28:28 +#define GPIO_DATA2_59 27:27 +#define GPIO_DATA2_58 26:26 +#define GPIO_DATA2_57 25:25 +#define GPIO_DATA2_56 24:24 +#define GPIO_DATA2_55 23:23 +#define GPIO_DATA2_54 22:22 +#define GPIO_DATA2_53 21:21 +#define GPIO_DATA2_52 20:20 +#define GPIO_DATA2_51 19:19 +#define GPIO_DATA2_50 18:18 +#define GPIO_DATA2_49 17:17 +#define GPIO_DATA2_48 16:16 +#define GPIO_DATA2_47 15:15 +#define GPIO_DATA2_46 14:14 +#define GPIO_DATA2_45 13:13 +#define GPIO_DATA2_44 12:12 +#define GPIO_DATA2_43 11:11 +#define GPIO_DATA2_42 10:10 +#define GPIO_DATA2_41 9:9 +#define GPIO_DATA2_40 8:8 +#define GPIO_DATA2_39 7:7 +#define GPIO_DATA2_38 6:6 +#define GPIO_DATA2_37 5:5 +#define GPIO_DATA2_36 4:4 +#define GPIO_DATA2_35 3:3 +#define GPIO_DATA2_34 2:2 +#define GPIO_DATA2_33 1:1 +#define GPIO_DATA2_32 0:0 + +#define GPIO0_PAD_CONTROL 0x10080 +#define GPIO0_PAD_CONTROL_INPUT 24:24 //input signal from core side +#define GPIO0_PAD_CONTROL_MSC 17:17 //Mode selector +#define GPIO0_PAD_CONTROL_ST 16:16 //Schmitt trigger enable +#define GPIO0_PAD_CONTROL_ST_ENABLE 1 +#define GPIO0_PAD_CONTROL_ST_DISABLE 0 +#define GPIO0_PAD_CONTROL_SL 15:15 //Slew-rate-control enable +#define GPIO0_PAD_CONTROL_DS2 14:14 //Driving selctor +#define GPIO0_PAD_CONTROL_DS1 13:13 //Driving selctor +#define GPIO0_PAD_CONTROL_DS0 12:12 //Driving selctor + +#define GPIO0_PAD_CONTROL_PD 11:11 //Pull down enable +#define GPIO0_PAD_CONTROL_PD_ENABLE 1 +#define GPIO0_PAD_CONTROL_PD_DISABLE 0 + +#define GPIO0_PAD_CONTROL_PU 10:10 //Pull up enable +#define GPIO0_PAD_CONTROL_PU_ENABLE 1 +#define GPIO0_PAD_CONTROL_PU_DISABLE 0 + +#define GPIO0_PAD_CONTROL_OEN 8:8 //Output enable +#define GPIO0_PAD_CONTROL_OEN_INPUT 1 +#define GPIO0_PAD_CONTROL_OEN_OUTPUT 0 + +#define GPIO0_PAD_CONTROL_DATA 0:0 //Data bit reflect the valeue on the GPIO pin + +#define GPIO_PAD_DP0_HPD 0x10110 +#define GPIO_PAD_DP0_HPD_PD 11:11 +#define GPIO_PAD_DP0_HPD_PD_ENABLE 1 +#define GPIO_PAD_DP0_HPD_PD_DISABLE 0 + + +#define GPIO_INTERRUPT_SETUP 0x010008 +#define GPIO_INTERRUPT_SETUP_TRIGGER_44 22:22 +#define GPIO_INTERRUPT_SETUP_TRIGGER_44_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_44_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_43 21:21 +#define GPIO_INTERRUPT_SETUP_TRIGGER_43_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_43_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_57 20:20 +#define GPIO_INTERRUPT_SETUP_TRIGGER_57_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_57_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_56 19:19 +#define GPIO_INTERRUPT_SETUP_TRIGGER_56_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_56_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_55 18:18 +#define GPIO_INTERRUPT_SETUP_TRIGGER_55_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_55_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_54 17:17 +#define GPIO_INTERRUPT_SETUP_TRIGGER_54_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_54_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_TRIGGER_53 16:16 +#define GPIO_INTERRUPT_SETUP_TRIGGER_53_EDGE 0 +#define GPIO_INTERRUPT_SETUP_TRIGGER_53_LEVEL 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_44 14:14 +#define GPIO_INTERRUPT_SETUP_ACTIVE_44_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_44_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_43 13:13 +#define GPIO_INTERRUPT_SETUP_ACTIVE_43_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_43_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_57 12:12 +#define GPIO_INTERRUPT_SETUP_ACTIVE_57_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_57_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_56 11:11 +#define GPIO_INTERRUPT_SETUP_ACTIVE_56_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_56_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_55 10:10 +#define GPIO_INTERRUPT_SETUP_ACTIVE_55_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_55_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_54 9:9 +#define GPIO_INTERRUPT_SETUP_ACTIVE_54_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_54_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ACTIVE_53 8:8 +#define GPIO_INTERRUPT_SETUP_ACTIVE_53_LOW 0 +#define GPIO_INTERRUPT_SETUP_ACTIVE_53_HIGH 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_44 6:6 +#define GPIO_INTERRUPT_SETUP_ENABLE_44_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_44_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_43 5:5 +#define GPIO_INTERRUPT_SETUP_ENABLE_43_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_43_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_57 4:4 +#define GPIO_INTERRUPT_SETUP_ENABLE_57_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_57_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_56 3:3 +#define GPIO_INTERRUPT_SETUP_ENABLE_56_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_56_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_55 2:2 +#define GPIO_INTERRUPT_SETUP_ENABLE_55_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_55_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_54 1:1 +#define GPIO_INTERRUPT_SETUP_ENABLE_54_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_54_INTERRUPT 1 +#define GPIO_INTERRUPT_SETUP_ENABLE_53 0:0 +#define GPIO_INTERRUPT_SETUP_ENABLE_53_GPIO 0 +#define GPIO_INTERRUPT_SETUP_ENABLE_53_INTERRUPT 1 + +#define GPIO_INTERRUPT_STATUS 0x01000C +#define GPIO_INTERRUPT_STATUS_44 6:6 +#define GPIO_INTERRUPT_STATUS_44_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_44_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_44_RESET 1 +#define GPIO_INTERRUPT_STATUS_43 5:5 +#define GPIO_INTERRUPT_STATUS_43_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_43_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_43_RESET 1 +#define GPIO_INTERRUPT_STATUS_57 4:4 +#define GPIO_INTERRUPT_STATUS_57_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_57_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_57_RESET 1 +#define GPIO_INTERRUPT_STATUS_56 3:3 +#define GPIO_INTERRUPT_STATUS_56_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_56_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_56_RESET 1 +#define GPIO_INTERRUPT_STATUS_55 2:2 +#define GPIO_INTERRUPT_STATUS_55_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_55_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_55_RESET 1 +#define GPIO_INTERRUPT_STATUS_54 1:1 +#define GPIO_INTERRUPT_STATUS_54_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_54_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_54_RESET 1 +#define GPIO_INTERRUPT_STATUS_53 0:0 +#define GPIO_INTERRUPT_STATUS_53_INACTIVE 0 +#define GPIO_INTERRUPT_STATUS_53_ACTIVE 1 +#define GPIO_INTERRUPT_STATUS_53_RESET 1 + +#define GPIO_MUX 0x010010 + +//I2C4 is for Slave mode +#if 0 +#define GPIO_MUX_I2C4 27:26 +#define GPIO_MUX_I2C4_DISABLE 0 +#define GPIO_MUX_I2C4_ENABLE 3 +#endif + +//I2C3 is for General IIC Master +#define GPIO_MUX_I2C3 25:24 +#define GPIO_MUX_I2C3_DISABLE 0 +#define GPIO_MUX_I2C3_ENABLE 3 + +//I2C0-2 is for HDMI0-HDMI2 DDC +#define GPIO_MUX_I2C2 5:4 +#define GPIO_MUX_I2C2_DISABLE 0 +#define GPIO_MUX_I2C2_ENABLE 3 + +#define GPIO_MUX_I2C1 3:2 +#define GPIO_MUX_I2C1_DISABLE 0 +#define GPIO_MUX_I2C1_ENABLE 3 + +#define GPIO_MUX_I2C0 1:0 +#define GPIO_MUX_I2C0_DISABLE 0 +#define GPIO_MUX_I2C0_ENABLE 3 + +#define GPIO_MUX_UART0 20:18 +#define GPIO_MUX_UART0_DISABLE 0 +#define GPIO_MUX_UART0_ENABLE 7 + +#define GPIO_MUX_UART1 19:17 +#define GPIO_MUX_UART1_DISABLE 0 +#define GPIO_MUX_UART1_ENABLE 7 + +#define GPIO_MUX_25 25:25 +#define GPIO_MUX_25_GPIO 0 +#define GPIO_MUX_25_I2C3 1 +#define GPIO_MUX_24 24:24 +#define GPIO_MUX_24_GPIO 0 +#define GPIO_MUX_24_I2C3 1 +#define GPIO_MUX_23 23:23 +#define GPIO_MUX_23_GPIO 0 +#define GPIO_MUX_23_PWM2 1 +#define GPIO_MUX_22 22:22 +#define GPIO_MUX_22_GPIO 0 +#define GPIO_MUX_22_PWM1 1 +#define GPIO_MUX_21 21:21 +#define GPIO_MUX_21_GPIO 0 +#define GPIO_MUX_21_PWM0 1 +#define GPIO_MUX_20 20:20 +#define GPIO_MUX_20_GPIO 0 +#define GPIO_MUX_20_UART0 1 +#define GPIO_MUX_19 19:19 +#define GPIO_MUX_19_GPIO 0 +#define GPIO_MUX_19_UART1 1 +#define GPIO_MUX_18 18:18 +#define GPIO_MUX_18_GPIO 0 +#define GPIO_MUX_18_UART0 1 +#define GPIO_MUX_17 17:17 +#define GPIO_MUX_17_GPIO 0 +#define GPIO_MUX_17_UART1 1 +#define GPIO_MUX_16 16:16 +#define GPIO_MUX_16_GPIO 0 +#define GPIO_MUX_16_RESERVE 1 +#define GPIO_MUX_15 15:15 +#define GPIO_MUX_15_GPIO 0 +#define GPIO_MUX_15_USBPNP 1 +#define GPIO_MUX_14 14:14 +#define GPIO_MUX_14_GPIO 0 +#define GPIO_MUX_14_SSP0 1 +#define GPIO_MUX_13 13:13 +#define GPIO_MUX_13_GPIO 0 +#define GPIO_MUX_13_SSP0 1 +#define GPIO_MUX_12 12:12 +#define GPIO_MUX_12_GPIO 0 +#define GPIO_MUX_12_SSP0 1 +#define GPIO_MUX_11 11:11 +#define GPIO_MUX_11_GPIO 0 +#define GPIO_MUX_11_SSP0 1 +#define GPIO_MUX_10 10:10 +#define GPIO_MUX_10_GPIO 0 +#define GPIO_MUX_10_SSP0 1 +#define GPIO_MUX_9 9:9 +#define GPIO_MUX_9_GPIO 0 +#define GPIO_MUX_9_I2S_RX 1 +#define GPIO_MUX_8 8:8 +#define GPIO_MUX_8_GPIO 0 +#define GPIO_MUX_8_I2S_TX 1 +#define GPIO_MUX_7 7:7 +#define GPIO_MUX_7_GPIO 0 +#define GPIO_MUX_7_I2S_WS 1 +#define GPIO_MUX_6 6:6 +#define GPIO_MUX_6_GPIO 0 +#define GPIO_MUX_6_I2S_CK 1 +#define GPIO_MUX_5 5:5 +#define GPIO_MUX_5_GPIO 0 +#define GPIO_MUX_5_I2C2 1 +#define GPIO_MUX_4 4:4 +#define GPIO_MUX_4_GPIO 0 +#define GPIO_MUX_4_I2C2 1 +#define GPIO_MUX_3 3:3 +#define GPIO_MUX_3_GPIO 0 +#define GPIO_MUX_3_I2C1 1 +#define GPIO_MUX_2 2:2 +#define GPIO_MUX_2_GPIO 0 +#define GPIO_MUX_2_I2C1 1 +#define GPIO_MUX_1 1:1 +#define GPIO_MUX_1_GPIO 0 +#define GPIO_MUX_1_I2C0 1 +#define GPIO_MUX_0 0:0 +#define GPIO_MUX_0_GPIO 0 +#define GPIO_MUX_0_I2C0 1 + +#define GPIO_MUX1 0x010014 + +#define GPIO_MUX1_52 20:20 +#define GPIO_MUX1_52_GPIO52 0 +#define GPIO_MUX1_52_HDMI2CEC 1 + +#define GPIO_MUX1_51 19:19 +#define GPIO_MUX1_51_GPIO51 0 +#define GPIO_MUX1_51_HDMI1CEC 1 + +#define GPIO_MUX1_50 18:18 +#define GPIO_MUX1_50_GPIO50 0 +#define GPIO_MUX1_50_HDMI0CEC 1 + +/* There are 50 GPIO pads in the system with the same definition, + but different MMIO address as below + + 0x10080 to 0x10148 + + We only define the MMIO for GPIO0, the MMIO for other + GPIO pad control can be work out like this: + 0x10080 + (4 x GPIO number) + +*/ +#define GPIO_CONTROL 0x010080 + + +#define GPIO_CONTROL_DATA 0:0 + +/* There are 3 PWM in the system with the same definition, + but different MMIO address as below + + PWM 0 0x010020 + PWM 1 0x010024 + PWM 2 0x010028 + + We only define the MMIO for PWM 0, the MMIO for other + PWM can be work out like this: + 0x10020 + (4 x PWM number) +*/ +#define PWM_CONTROL 0x010020 +#define PWM_CONTROL_HIGH_COUNTER 31:20 +#define PWM_CONTROL_LOW_COUNTER 19:8 +#define PWM_CONTROL_CLOCK_DIVIDE 7:4 +#define PWM_CONTROL_CLOCK_DIVIDE_1 0 +#define PWM_CONTROL_CLOCK_DIVIDE_2 1 +#define PWM_CONTROL_CLOCK_DIVIDE_4 2 +#define PWM_CONTROL_CLOCK_DIVIDE_8 3 +#define PWM_CONTROL_CLOCK_DIVIDE_16 4 +#define PWM_CONTROL_CLOCK_DIVIDE_32 5 +#define PWM_CONTROL_CLOCK_DIVIDE_64 6 +#define PWM_CONTROL_CLOCK_DIVIDE_128 7 +#define PWM_CONTROL_CLOCK_DIVIDE_256 8 +#define PWM_CONTROL_CLOCK_DIVIDE_512 9 +#define PWM_CONTROL_CLOCK_DIVIDE_1024 10 +#define PWM_CONTROL_CLOCK_DIVIDE_2048 11 +#define PWM_CONTROL_CLOCK_DIVIDE_4096 12 +#define PWM_CONTROL_CLOCK_DIVIDE_8192 13 +#define PWM_CONTROL_CLOCK_DIVIDE_16384 14 +#define PWM_CONTROL_CLOCK_DIVIDE_32768 15 +#define PWM_CONTROL_INTERRUPT_STATUS 3:3 +#define PWM_CONTROL_INTERRUPT_STATUS_NOT_PENDING 0 +#define PWM_CONTROL_INTERRUPT_STATUS_PENDING 1 +#define PWM_CONTROL_INTERRUPT_STATUS_CLEAR 1 +#define PWM_CONTROL_INTERRUPT 2:2 +#define PWM_CONTROL_INTERRUPT_DISABLE 0 +#define PWM_CONTROL_INTERRUPT_ENABLE 1 +#define PWM_CONTROL_STATUS 0:0 +#define PWM_CONTROL_STATUS_DISABLE 0 +#define PWM_CONTROL_STATUS_ENABLE 1 + +/* There are 2 Synchronous Serial Port (SSP) in SM768 with identical definitions, + but different MMIO address as below + + SSP 0 0x20000 + SSP 1 0x20100 + + We only define the MMIO for SSP 0, the MMIO for + SSP 1 can be work out like this: + 0x20000 + SSP0_SSP1_GAP, where SSP0_SSP1_GAP is defined as 0x100. +*/ +#define SSP_CONTROL_0 0x020000 +#define SSP_CONTROL_0_CLOCK_RATE 15:8 +#define SSP_CONTROL_0_SCLKOUT_PHASE 7:7 +#define SSP_CONTROL_0_SCLKOUT_PHASE_0 0 +#define SSP_CONTROL_0_SCLKOUT_PHASE_1 1 +#define SSP_CONTROL_0_SCLKOUT_POLARITY 6:6 +#define SSP_CONTROL_0_SCLKOUT_POLARITY_RISING 0 +#define SSP_CONTROL_0_SCLKOUT_POLARITY_FALLING 1 +#define SSP_CONTROL_0_FRAME_FORMAT 5:4 +#define SSP_CONTROL_0_FRAME_FORMAT_MOTOROLA 0 +#define SSP_CONTROL_0_FRAME_FORMAT_TI 1 +#define SSP_CONTROL_0_FRAME_FORMAT_NATIONAL 2 +#define SSP_CONTROL_0_DATA_SIZE 3:0 +#define SSP_CONTROL_0_DATA_SIZE_4 3 +#define SSP_CONTROL_0_DATA_SIZE_5 4 +#define SSP_CONTROL_0_DATA_SIZE_6 5 +#define SSP_CONTROL_0_DATA_SIZE_7 6 +#define SSP_CONTROL_0_DATA_SIZE_8 7 +#define SSP_CONTROL_0_DATA_SIZE_9 8 +#define SSP_CONTROL_0_DATA_SIZE_10 9 +#define SSP_CONTROL_0_DATA_SIZE_11 10 +#define SSP_CONTROL_0_DATA_SIZE_12 11 +#define SSP_CONTROL_0_DATA_SIZE_13 12 +#define SSP_CONTROL_0_DATA_SIZE_14 13 +#define SSP_CONTROL_0_DATA_SIZE_15 14 +#define SSP_CONTROL_0_DATA_SIZE_16 15 + +#define SSP_CONTROL_1 0x020004 +#define SSP_CONTROL_1_SLAVE_OUTPUT 6:6 +#define SSP_CONTROL_1_SLAVE_OUTPUT_ENABLE 0 +#define SSP_CONTROL_1_SLAVE_OUTPUT_DISABLE 1 +#define SSP_CONTROL_1_MODE_SELECT 5:5 +#define SSP_CONTROL_1_MODE_SELECT_MASTER 0 +#define SSP_CONTROL_1_MODE_SELECT_SLAVE 1 +#define SSP_CONTROL_1_STATUS 4:4 +#define SSP_CONTROL_1_STATUS_DISABLE 0 +#define SSP_CONTROL_1_STATUS_ENABLE 1 +#define SSP_CONTROL_1_LOOP_BACK 3:3 +#define SSP_CONTROL_1_LOOP_BACK_DISABLE 0 +#define SSP_CONTROL_1_LOOP_BACK_ENABLE 1 +#define SSP_CONTROL_1_OVERRUN_INTERRUPT 2:2 +#define SSP_CONTROL_1_OVERRUN_INTERRUPT_DISABLE 0 +#define SSP_CONTROL_1_OVERRUN_INTERRUPT_ENABLE 1 +#define SSP_CONTROL_1_TRANSMIT_INTERRUPT 1:1 +#define SSP_CONTROL_1_TRANSMIT_INTERRUPT_DISABLE 0 +#define SSP_CONTROL_1_TRANSMIT_INTERRUPT_ENABLE 1 +#define SSP_CONTROL_1_RECEIVE_INTERRUPT 0:0 +#define SSP_CONTROL_1_RECEIVE_INTERRUPT_DISABLE 0 +#define SSP_CONTROL_1_RECEIVE_INTERRUPT_ENABLE 1 + +#define SSP_DATA 0x020008 +#define SSP_DATA_DATA 15:0 + +#define SSP_STATUS 0x02000C +#define SSP_STATUS_STATUS 4:4 +#define SSP_STATUS_STATUS_IDLE 0 +#define SSP_STATUS_STATUS_BUSY 1 +#define SSP_STATUS_RECEIVE_FIFO 3:2 +#define SSP_STATUS_RECEIVE_FIFO_EMPTY 0 +#define SSP_STATUS_RECEIVE_FIFO_NOT_EMPTY 1 +#define SSP_STATUS_RECEIVE_FIFO_FULL 3 +#define SSP_STATUS_TRANSMIT_FIFO 1:0 +#define SSP_STATUS_TRANSMIT_FIFO_FULL 0 +#define SSP_STATUS_TRANSMIT_FIFO_NOT_FULL 2 +#define SSP_STATUS_TRANSMIT_FIFO_EMPTY 3 + +#define SSP_CLOCK_PRESCALE 0x020010 +#define SSP_CLOCK_PRESCALE_DIVISOR 7:0 + +#define SSP_INTERRUPT_STATUS 0x020014 +#define SSP_INTERRUPT_STATUS_OVERRUN 2:2 +#define SSP_INTERRUPT_STATUS_OVERRUN_NOT_ACTIVE 0 +#define SSP_INTERRUPT_STATUS_OVERRUN_ACTIVE 1 +#define SSP_INTERRUPT_STATUS_OVERRUN_CLEAR 1 +#define SSP_INTERRUPT_STATUS_TRANSMIT 1:1 +#define SSP_INTERRUPT_STATUS_TRANSMIT_NOT_ACTIVE 0 +#define SSP_INTERRUPT_STATUS_TRANSMIT_ACTIVE 1 +#define SSP_INTERRUPT_STATUS_RECEIVE 0:0 +#define SSP_INTERRUPT_STATUS_RECEIVE_NOT_ACTIVE 0 +#define SSP_INTERRUPT_STATUS_RECEIVE_ACTIVE 1 + +/* Different register offset location between the first and the second SSP */ +#define SSP0_SSP1_GAP 0x100 +#define SSP1_OFFSET 0x100 + +/* There are 2 display channels in the system with the same definition, + but different MMIO address as below + + Display Channel 0 0x080000 + Display Channel 1 0x088000 + Display Channel 2 0x098000 + + We only define the MMIO for Display Channel 0, the MMIO for + Display Channel 1 can be work out like this: + 0x080000 + CHANNEL_OFFSET, where CHANNEL_OFFSET is defined as 0x8000. +*/ +#define LVDS_SET 0x3ff0 +#define LVDS_SET_LVDS1_ENABLE 3:3 +#define LVDS_SET_LVDS1_ENABLE_ON 1 +#define LVDS_SET_LVDS1_ENABLE_OFF 0 +#define LVDS_SET_LVDS1_PD 2:2 +#define LVDS_SET_LVDS1_PD_ON 1 +#define LVDS_SET_LVDS1_PD_OFF 0 +#define LVDS_SET_LVDS0_ENABLE 1:1 +#define LVDS_SET_LVDS0_ENABLE_ON 1 +#define LVDS_SET_LVDS0_ENABLE_OFF 0 +#define LVDS_SET_LVDS0_PD 0:0 +#define LVDS_SET_LVDS0_PD_ON 1 +#define LVDS_SET_LVDS0_PD_OFF 0 + +#define DC_MUX 0x00003ffc +#define DC_MUX_HDMI0 3:0 +#define DC_MUX_HDMI0_DC0 1 +#define DC_MUX_HDMI0_DC1 2 +#define DC_MUX_HDMI0_DC2 4 + +#define DC_MUX_HDMI1 7:4 +#define DC_MUX_HDMI1_DC0 1 +#define DC_MUX_HDMI1_DC1 2 +#define DC_MUX_HDMI1_DC2 4 + +#define DC_MUX_HDMI2 11:8 +#define DC_MUX_HDMI2_DC0 1 +#define DC_MUX_HDMI2_DC1 2 +#define DC_MUX_HDMI2_DC2 4 + +#define DC_MUX_DP0 15:12 +#define DC_MUX_DP0_DC0 1 +#define DC_MUX_DP0_DC1 2 +#define DC_MUX_DP0_DC2 4 + +#define DC_MUX_DP1 19:16 +#define DC_MUX_DP1_DC0 1 +#define DC_MUX_DP1_DC1 2 +#define DC_MUX_DP1_DC2 4 + +#define DC_MUX_LVDS0 23:20 +#define DC_MUX_LVDS0_DC0 1 +#define DC_MUX_LVDS0_DC1 2 +#define DC_MUX_LVDS0_DC2 4 + +#define DC_MUX_LVDS1 27:24 +#define DC_MUX_LVDS1_DC0 1 +#define DC_MUX_LVDS1_DC1 2 +#define DC_MUX_LVDS1_DC2 4 + +#define DISPLAY_CTRL 0x080000 +#define DISPLAY_CTRL_DPMS 31:30 +#define DISPLAY_CTRL_DPMS_VPHP 0 +#define DISPLAY_CTRL_DPMS_VPHN 1 +#define DISPLAY_CTRL_DPMS_VNHP 2 +#define DISPLAY_CTRL_DPMS_VNHN 3 +#define DISPLAY_CTRL_DATA_PATH 29:29 +#define DISPLAY_CTRL_DATA_PATH_VGA 0 +#define DISPLAY_CTRL_DATA_PATH_EXTENDED 1 +#define DISPLAY_CTRL_FPEN 27:27 +#define DISPLAY_CTRL_FPEN_LOW 0 +#define DISPLAY_CTRL_FPEN_HIGH 1 +#define DISPLAY_CTRL_VBIASEN 26:26 +#define DISPLAY_CTRL_VBIASEN_LOW 0 +#define DISPLAY_CTRL_VBIASEN_HIGH 1 +#define DISPLAY_CTRL_DATA 25:25 +#define DISPLAY_CTRL_DATA_DISABLE 0 +#define DISPLAY_CTRL_DATA_ENABLE 1 +#define DISPLAY_CTRL_FPVDDEN 24:24 +#define DISPLAY_CTRL_FPVDDEN_LOW 0 +#define DISPLAY_CTRL_FPVDDEN_HIGH 1 +#define DISPLAY_CTRL_LOOP_BACK_SELECT 22:22 +#define DISPLAY_CTRL_LOOP_BACK_SELECT_CHANNEL0 0 +#define DISPLAY_CTRL_LOOP_BACK_SELECT_CHANNEL1 1 +#define DISPLAY_CTRL_CLOCK_PHASE 14:14 +#define DISPLAY_CTRL_CLOCK_PHASE_ACTIVE_HIGH 0 +#define DISPLAY_CTRL_CLOCK_PHASE_ACTIVE_LOW 1 +#define DISPLAY_CTRL_VSYNC_PHASE 13:13 +#define DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_HIGH 0 +#define DISPLAY_CTRL_VSYNC_PHASE_ACTIVE_LOW 1 +#define DISPLAY_CTRL_HSYNC_PHASE 12:12 +#define DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_HIGH 0 +#define DISPLAY_CTRL_HSYNC_PHASE_ACTIVE_LOW 1 +#define DISPLAY_CTRL_DOUBLE_PIXEL_CLOCK 11:11 +#define DISPLAY_CTRL_DOUBLE_PIXEL_CLOCK_DISABLE 0 +#define DISPLAY_CTRL_DOUBLE_PIXEL_CLOCK_ENABLE 1 +#define DISPLAY_CTRL_COLOR_KEY 9:9 +#define DISPLAY_CTRL_COLOR_KEY_DISABLE 0 +#define DISPLAY_CTRL_COLOR_KEY_ENABLE 1 +#define DISPLAY_CTRL_TIMING 8:8 +#define DISPLAY_CTRL_TIMING_DISABLE 0 +#define DISPLAY_CTRL_TIMING_ENABLE 1 +#define DISPLAY_CTRL_PIXEL 7:4 +#define DISPLAY_CTRL_GAMMA 3:3 +#define DISPLAY_CTRL_GAMMA_DISABLE 0 +#define DISPLAY_CTRL_GAMMA_ENABLE 1 +#define DISPLAY_CTRL_PLANE 2:2 +#define DISPLAY_CTRL_PLANE_DISABLE 0 +#define DISPLAY_CTRL_PLANE_ENABLE 1 +#define DISPLAY_CTRL_FORMAT 1:0 +#define DISPLAY_CTRL_FORMAT_8 0 +#define DISPLAY_CTRL_FORMAT_16 1 +#define DISPLAY_CTRL_FORMAT_32 2 +#define DISPLAY_CTRL_FORMAT_YUV422 3 + +#define FB_ADDRESS 0x080004 +#define FB_ADDRESS_STATUS 31:31 +#define FB_ADDRESS_STATUS_CURRENT 0 +#define FB_ADDRESS_STATUS_PENDING 1 +#define FB_ADDRESS_ADDRESS 30:0 + +#define FB_WIDTH 0x080008 +#define FB_WIDTH_WIDTH 31:16 +#define FB_WIDTH_OFFSET 15:0 + +#define HORIZONTAL_TOTAL 0x08000C +#define HORIZONTAL_TOTAL_PIPESEL 31:31 +#define HORIZONTAL_TOTAL_DATASEQ 30:30 +#define HORIZONTAL_TOTAL_DATASEQ_DISABLE 0 +#define HORIZONTAL_TOTAL_DATASEQ_ENABLE 1 +#define HORIZONTAL_TOTAL_VGA 29:29 +#define HORIZONTAL_TOTAL_VGA_DISABLE 0 +#define HORIZONTAL_TOTAL_VGA_ENABLE 1 +#define HORIZONTAL_TOTAL_TOTAL 28:16 +#define HORIZONTAL_TOTAL_DISPLAY_END 12:0 + +#define HORIZONTAL_SYNC 0x080010 +#define HORIZONTAL_SYNC_WIDTH 25:16 +#define HORIZONTAL_SYNC_START 12:0 + +#define VERTICAL_TOTAL 0x080014 +#define VERTICAL_TOTAL_TOTAL 27:16 +#define VERTICAL_TOTAL_DISPLAY_END 11:0 + +#define VERTICAL_SYNC 0x080018 +#define VERTICAL_SYNC_DPMODE 31:31 +#define VERTICAL_SYNC_VSYNC 30:30 +#define VERTICAL_SYNC_VSYNC_INACTIVE 0 +#define VERTICAL_SYNC_VSYNC_ACTIVE 1 +#define VERTICAL_SYNC_HEIGHT 22:16 +#define VERTICAL_SYNC_START 11:0 + +#define CURRENT_LINE 0x080020 +#define CURRENT_LINE_LINE 11:0 + +#define CRT_DETECT 0x080024 +#define CRT_DETECT_LVDS_CLK 26:26 +#define CRT_DETECT_LVDS_CLK_POS 0 +#define CRT_DETECT_LVDS_CLK_NEG 1 +#define CRT_DETECT_CRT 25:25 +#define CRT_DETECT_CRT_ABSENT 0 +#define CRT_DETECT_CRT_PRESENT 1 +#define CRT_DETECT_ENABLE 24:24 +#define CRT_DETECT_ENABLE_DISABLE 0 +#define CRT_DETECT_ENABLE_ENABLE 1 +#define CRT_DETECT_DATA_RED 23:16 +#define CRT_DETECT_DATA_GREEN 15:8 +#define CRT_DETECT_DATA_BLUE 7:0 + +#define COLOR_KEY 0x080028 +#define COLOR_KEY_MASK 31:16 +#define COLOR_KEY_VALUE 15:0 + +/* Cursor Control */ +#define HWC_CONTROL 0x080030 +#define HWC_CONTROL_MODE 31:30 +#define HWC_CONTROL_MODE_DISABLE 0 +#define HWC_CONTROL_MODE_MASK 1 +#define HWC_CONTROL_MODE_MONO 2 +#define HWC_CONTROL_MODE_ALPHA 3 +#define HWC_CONTROL_ADDRESS 29:0 + +#define HWC_LOCATION 0x080034 +#define HWC_LOCATION_TOP 31:31 +#define HWC_LOCATION_TOP_INSIDE 0 +#define HWC_LOCATION_TOP_OUTSIDE 1 +#define HWC_LOCATION_SIZE 30:30 +#define HWC_LOCATION_SIZE_64 0 +#define HWC_LOCATION_SIZE_128 1 +#define HWC_LOCATION_PREFETCH 29:29 +#define HWC_LOCATION_PREFETCH_DISABLE 0 +#define HWC_LOCATION_PREFETCH_ENABLE 1 +#define HWC_LOCATION_LASTPIXEL 28:28 +#define HWC_LOCATION_LASTPIXEL_DISABLE 0 +#define HWC_LOCATION_LASTPIXEL_ENABLE 1 + + +#define HWC_LOCATION_Y 27:16 +#define HWC_LOCATION_LEFT 15:15 +#define HWC_LOCATION_LEFT_INSIDE 0 +#define HWC_LOCATION_LEFT_OUTSIDE 1 +#define HWC_LOCATION_X 11:0 + +#define HWC_COLOR0 0x080038 +#define HWC_COLOR0_RGB888 23:0 + +#define HWC_COLOR1 0x08003C +#define HWC_COLOR1_RGB888 23:0 + +/* Video Control */ +#define VIDEO_DISPLAY_CTRL 0x080040 +#define VIDEO_DISPLAY_CTRL_JPUP 15:14 +#define VIDEO_DISPLAY_CTRL_JPUP_DISABLE 0 +#define VIDEO_DISPLAY_CTRL_JPUP_HD 1 +#define VIDEO_DISPLAY_CTRL_JPUP_UHD 2 +#define VIDEO_DISPLAY_CTRL_BYTE_SWAP 12:12 +#define VIDEO_DISPLAY_CTRL_BYTE_SWAP_DISABLE 0 +#define VIDEO_DISPLAY_CTRL_BYTE_SWAP_ENABLE 1 +#define VIDEO_DISPLAY_CTRL_YUV444FMT 10:10 +#define VIDEO_DISPLAY_CTRL_YUV444FMT_DISABLE 0 +#define VIDEO_DISPLAY_CTRL_YUV444FMT_ENABLE 1 +#define VIDEO_DISPLAY_CTRL_VERTICAL_MODE 9:9 +#define VIDEO_DISPLAY_CTRL_VERTICAL_MODE_REPLICATE 0 +#define VIDEO_DISPLAY_CTRL_VERTICAL_MODE_INTERPOLATE 1 +#define VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE 8:8 +#define VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE_REPLICATE 0 +#define VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE_INTERPOLATE 1 +#define VIDEO_DISPLAY_CTRL_PIXEL 7:4 +#define VIDEO_DISPLAY_CTRL_GAMMA 3:3 +#define VIDEO_DISPLAY_CTRL_GAMMA_DISABLE 0 +#define VIDEO_DISPLAY_CTRL_GAMMA_ENABLE 1 +#define VIDEO_DISPLAY_CTRL_PLANE 2:2 +#define VIDEO_DISPLAY_CTRL_PLANE_DISABLE 0 +#define VIDEO_DISPLAY_CTRL_PLANE_ENABLE 1 +#define VIDEO_DISPLAY_CTRL_FORMAT 1:0 +#define VIDEO_DISPLAY_CTRL_FORMAT_16 0 +#define VIDEO_DISPLAY_CTRL_FORMAT_32 1 +#define VIDEO_DISPLAY_CTRL_FORMAT_YUV422 2 +#define VIDEO_DISPLAY_CTRL_FORMAT_YUV420 3 + +#define VIDEO_FB_ADDRESS 0x080044 +#define VIDEO_FB_ADDRESS_STATUS 31:31 +#define VIDEO_FB_ADDRESS_STATUS_CURRENT 0 +#define VIDEO_FB_ADDRESS_STATUS_PENDING 1 +#define VIDEO_FB_ADDRESS_ADDRESS 30:0 + +#define VIDEO_FB_WIDTH 0x080048 +#define VIDEO_FB_WIDTH_WIDTH 29:16 +#define VIDEO_FB_WIDTH_OFFSET 15:0 + +#define VIDEO_FB_ADDRESS_Y 0x080044 +#define VIDEO_FB_ADDRESS_Y_ADDRESS 29:0 + +#define VIDEO_FB_WIDTH_Y 0x080048 +#define VIDEO_FB_WIDTH_Y_WIDTH 29:16 +#define VIDEO_FB_WIDTH_Y_OFFSET 15:0 + +#define VIDEO_FB_ADDRESS_U 0x08004C +#define VIDEO_FB_ADDRESS_U_ADDRESS 30:0 + +#define VIDEO_FB_WIDTH_U 0x080050 +#define VIDEO_FB_WIDTH_U_WIDTH 29:16 +#define VIDEO_FB_WIDTH_U_OFFSET 15:0 + +#define VIDEO_FB_ADDRESS_V 0x080054 +#define VIDEO_FB_ADDRESS_V_ADDRESS 30:0 + +#define VIDEO_FB_WIDTH_V 0x080058 +#define VIDEO_FB_WIDTH_V_WIDTH 29:16 +#define VIDEO_FB_WIDTH_V_OFFSET 15:0 + +#define VIDEO_YUV_CONSTANTS 0x08005C +#define VIDEO_YUV_CONSTANTS_Y 31:24 +#define VIDEO_YUV_CONSTANTS_R 23:16 +#define VIDEO_YUV_CONSTANTS_G 15:8 +#define VIDEO_YUV_CONSTANTS_B 7:0 + +#define VIDEO_PLANE_TL 0x080060 +#define VIDEO_PLANE_TL_TOP 27:16 +#define VIDEO_PLANE_TL_LEFT 12:0 + +#define VIDEO_PLANE_BR 0x080064 +#define VIDEO_PLANE_BR_BOTTOM 27:16 +#define VIDEO_PLANE_BR_RIGHT 12:0 + +#define VIDEO_SCALE 0x080068 +#define VIDEO_SCALE_VERTICAL_SCALE 27:16 +#define VIDEO_SCALE_HORIZONTAL_SCALE 11:0 + +#define VIDEO_INITIAL_SCALE 0x08006C +#define VIDEO_INITIAL_SCALE_VERTICAL 27:16 +#define VIDEO_INITIAL_SCALE_HORIZONTAL 11:0 + +#define VIDEO_SOURCE_SIZE 0x080070 +#define VIDEO_SOURCE_SIZE_4KPATCH 31:31 +#define VIDEO_SOURCE_SIZE_4KPATCH_DISABLE 0 +#define VIDEO_SOURCE_SIZE_4KPATCH_ENABLE 1 +#define VIDEO_SOURCE_SIZE_YUVPREFETCH 30:30 +#define VIDEO_SOURCE_SIZE_YUVPREFETCH_DISABLE 0 +#define VIDEO_SOURCE_SIZE_YUVPREFETCH_ENABLE 1 +#define VIDEO_SOURCE_SIZE_YUVARLENINC 29:29 +#define VIDEO_SOURCE_SIZE_YUVARLENINC_DISABLE 0 +#define VIDEO_SOURCE_SIZE_YUVARLENINC_ENABLE 1 +#define VIDEO_SOURCE_SIZE_YUVUVREDUCE 28:28 +#define VIDEO_SOURCE_SIZE_YUVUVREDUCE_DISABLE 0 +#define VIDEO_SOURCE_SIZE_YUVUVREDUCE_ENABLE 1 +#define VIDEO_SOURCE_SIZE_LASTLINE 27:16 +#define VIDEO_SOURCE_SIZE_LASTPIXEL 11:0 + +/* Alpha Control */ +#define ALPHA_DISPLAY_CTRL 0x080080 +#define ALPHA_DISPLAY_CTRL_SELECT 28:28 +#define ALPHA_DISPLAY_CTRL_SELECT_PER_PIXEL 0 +#define ALPHA_DISPLAY_CTRL_SELECT_ALPHA 1 +#define ALPHA_DISPLAY_CTRL_ALPHA 27:24 +#define ALPHA_DISPLAY_CTRL_FIFO 17:16 +#define ALPHA_DISPLAY_CTRL_FIFO_1 0 +#define ALPHA_DISPLAY_CTRL_FIFO_3 1 +#define ALPHA_DISPLAY_CTRL_FIFO_7 2 +#define ALPHA_DISPLAY_CTRL_FIFO_11 3 +#define ALPHA_DISPLAY_CTRL_PIXEL 7:4 +#define ALPHA_DISPLAY_CTRL_CHROMA_KEY 3:3 +#define ALPHA_DISPLAY_CTRL_CHROMA_KEY_DISABLE 0 +#define ALPHA_DISPLAY_CTRL_CHROMA_KEY_ENABLE 1 +#define ALPHA_DISPLAY_CTRL_PLANE 2:2 +#define ALPHA_DISPLAY_CTRL_PLANE_DISABLE 0 +#define ALPHA_DISPLAY_CTRL_PLANE_ENABLE 1 +#define ALPHA_DISPLAY_CTRL_FORMAT 1:0 +#define ALPHA_DISPLAY_CTRL_FORMAT_8 0 +#define ALPHA_DISPLAY_CTRL_FORMAT_16 1 +#define ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4 2 +#define ALPHA_DISPLAY_CTRL_FORMAT_ALPHA_4_4_4_4 3 + +#define ALPHA_FB_ADDRESS 0x080084 +#define ALPHA_FB_ADDRESS_STATUS 31:31 +#define ALPHA_FB_ADDRESS_STATUS_CURRENT 0 +#define ALPHA_FB_ADDRESS_STATUS_PENDING 1 +#define ALPHA_FB_ADDRESS_ADDRESS 29:0 + +#define ALPHA_FB_WIDTH 0x080088 +#define ALPHA_FB_WIDTH_WIDTH 29:16 +#define ALPHA_FB_WIDTH_OFFSET 13:0 + +#define ALPHA_PLANE_TL 0x08008C +#define ALPHA_PLANE_TL_TOP 27:16 +#define ALPHA_PLANE_TL_LEFT 11:0 + +#define ALPHA_PLANE_BR 0x080090 +#define ALPHA_PLANE_BR_BOTTOM 27:16 +#define ALPHA_PLANE_BR_RIGHT 11:0 + +#define ALPHA_CHROMA_KEY 0x080094 +#define ALPHA_CHROMA_KEY_MASK 31:16 +#define ALPHA_CHROMA_KEY_VALUE 15:0 + +#define ALPHA_COLOR_LOOKUP_01 0x080098 +#define ALPHA_COLOR_LOOKUP_01_1 31:16 +#define ALPHA_COLOR_LOOKUP_01_1_RED 31:27 +#define ALPHA_COLOR_LOOKUP_01_1_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_01_1_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_01_0 15:0 +#define ALPHA_COLOR_LOOKUP_01_0_RED 15:11 +#define ALPHA_COLOR_LOOKUP_01_0_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_01_0_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_23 0x08009C +#define ALPHA_COLOR_LOOKUP_23_3 31:16 +#define ALPHA_COLOR_LOOKUP_23_3_RED 31:27 +#define ALPHA_COLOR_LOOKUP_23_3_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_23_3_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_23_2 15:0 +#define ALPHA_COLOR_LOOKUP_23_2_RED 15:11 +#define ALPHA_COLOR_LOOKUP_23_2_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_23_2_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_45 0x0800a0 +#define ALPHA_COLOR_LOOKUP_45_5 31:16 +#define ALPHA_COLOR_LOOKUP_45_5_RED 31:27 +#define ALPHA_COLOR_LOOKUP_45_5_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_45_5_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_45_4 15:0 +#define ALPHA_COLOR_LOOKUP_45_4_RED 15:11 +#define ALPHA_COLOR_LOOKUP_45_4_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_45_4_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_67 0x0800a4 +#define ALPHA_COLOR_LOOKUP_67_7 31:16 +#define ALPHA_COLOR_LOOKUP_67_7_RED 31:27 +#define ALPHA_COLOR_LOOKUP_67_7_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_67_7_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_67_6 15:0 +#define ALPHA_COLOR_LOOKUP_67_6_RED 15:11 +#define ALPHA_COLOR_LOOKUP_67_6_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_67_6_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_89 0x0800a8 +#define ALPHA_COLOR_LOOKUP_89_9 31:16 +#define ALPHA_COLOR_LOOKUP_89_9_RED 31:27 +#define ALPHA_COLOR_LOOKUP_89_9_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_89_9_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_89_8 15:0 +#define ALPHA_COLOR_LOOKUP_89_8_RED 15:11 +#define ALPHA_COLOR_LOOKUP_89_8_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_89_8_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_AB 0x0800AC +#define ALPHA_COLOR_LOOKUP_AB_B 31:16 +#define ALPHA_COLOR_LOOKUP_AB_B_RED 31:27 +#define ALPHA_COLOR_LOOKUP_AB_B_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_AB_B_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_AB_A 15:0 +#define ALPHA_COLOR_LOOKUP_AB_A_RED 15:11 +#define ALPHA_COLOR_LOOKUP_AB_A_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_AB_A_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_CD 0x0800B0 +#define ALPHA_COLOR_LOOKUP_CD_D 31:16 +#define ALPHA_COLOR_LOOKUP_CD_D_RED 31:27 +#define ALPHA_COLOR_LOOKUP_CD_D_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_CD_D_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_CD_C 15:0 +#define ALPHA_COLOR_LOOKUP_CD_C_RED 15:11 +#define ALPHA_COLOR_LOOKUP_CD_C_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_CD_C_BLUE 4:0 + +#define ALPHA_COLOR_LOOKUP_EF 0x0800B4 +#define ALPHA_COLOR_LOOKUP_EF_F 31:16 +#define ALPHA_COLOR_LOOKUP_EF_F_RED 31:27 +#define ALPHA_COLOR_LOOKUP_EF_F_GREEN 26:21 +#define ALPHA_COLOR_LOOKUP_EF_F_BLUE 20:16 +#define ALPHA_COLOR_LOOKUP_EF_E 15:0 +#define ALPHA_COLOR_LOOKUP_EF_E_RED 15:11 +#define ALPHA_COLOR_LOOKUP_EF_E_GREEN 10:5 +#define ALPHA_COLOR_LOOKUP_EF_E_BLUE 4:0 + +#define HDMI_CONTROL 0x0800C0 +#define HDMI_CONTROL_MODE_SELECT 7:4 +#define HDMI_CONTROL_MODE_SELECT_A 1 +#define HDMI_CONTROL_MODE_SELECT_B 2 +#define HDMI_CONTROL_MODE_SELECT_D 4 +#define HDMI_CONTROL_MODE_SELECT_E 8 +#define HDMI_CONTROL_PLLB 3:3 +#define HDMI_CONTROL_PLLB_NORMAL 0 +#define HDMI_CONTROL_PLLB_RESET 1 +#define HDMI_CONTROL_PLLA 2:2 +#define HDMI_CONTROL_PLLA_NORMAL 0 +#define HDMI_CONTROL_PLLA_RESET 1 +#define HDMI_CONTROL_INTMODE 1:1 +#define HDMI_CONTROL_INT_MODE_OPEN 0 +#define HDMI_CONTROL_INT_MODE_PULL 1 +#define HDMI_CONTROL_INT_POLARITY 0:0 +#define HDMI_CONTROL_INT_POLARITY_LOW 0 +#define HDMI_CONTROL_INT_POLARITY_HIGH 1 + +#define HDMI_CONFIG 0x0800C0 +#define HDMI_CONFIG_READ 17:17 +#define HDMI_CONFIG_READ_LATCH 0 +#define HDMI_CONFIG_READ_ENABLE 1 +#define HDMI_CONFIG_WRITE 16:16 +#define HDMI_CONFIG_WRITE_LATCH 0 +#define HDMI_CONFIG_WRITE_ENABLE 1 +#define HDMI_CONFIG_DATA 15:8 +#define HDMI_CONFIG_ADDRESS 7:0 + +#define DISPLAY_YUV_CONVERSION_1 0x0800D4 //Default value:0x726f5d12 +#define DISPLAY_YUV_CONVERSION_1_UB 31:24 +#define DISPLAY_YUV_CONVERSION_1_VR 23:16 +#define DISPLAY_YUV_CONVERSION_1_VG 15:8 +#define DISPLAY_YUV_CONVERSION_1_VB 7:0 + + +#define DISPLAY_YUV_CONVERSION_2 0x0800D8 //Default value:0x80182645 +#define DISPLAY_YUV_CONVERSION_2_YG 31:24 +#define DISPLAY_YUV_CONVERSION_2_YB 23:16 +#define DISPLAY_YUV_CONVERSION_2_UR 15:8 +#define DISPLAY_YUV_CONVERSION_2_UG 7:0 + +#define DISPLAY_YUV_CONVERSION_3 0x0800DC //Default value:0x40 +#define DISPLAY_YUV_CONVERSION_3_R2YCTRL 10:8 +#define DISPLAY_YUV_CONVERSION_3_R2YCTRL_RGB888 0 +#define DISPLAY_YUV_CONVERSION_3_R2YCTRL_YUV422 1 +#define DISPLAY_YUV_CONVERSION_3_R2YCTRL_RGB666 2 +#define DISPLAY_YUV_CONVERSION_3_YR 7:0 + +#define DISPLAY_YUV 0x0800E0 //Default value:0x1000 +#define DISPLAY_YUV_BRIGHTNESS 19:0 + +/* Palette RAM */ +#define PALETTE_RAM 0x080C00 + +/* Distance between channel 1 and channel 2 display control */ +#define CHANNEL_OFFSET 0x8000 +#define CHANNEL_OFFSET2 0x18000 +// #define CHANNEL_OFFSET2 0x8000 +#define DC_OFFSET 0x8000 +#define DC_OFFSET2 0x18000 +// #define DC_OFFSET2 0x8000 + +#define DMA0_DESTINATION 0x0D0000 +#define DMA0_DESTINATION_DIRECTION 31:31 +#define DMA0_DESTINATION_DIRECTION_TODDR 0 +#define DMA0_DESTINATION_DIRECTION_TOTCM 1 +#define DMA0_DESTINATION_TCM 25:24 +#define DMA0_DESTINATION_TCM_CPU0 1 +#define DMA0_DESTINATION_TCM_CPU1 3 +#define DMA0_DESTINATION_ADDRESS 29:0 + +#define DMA0_SOURCE 0x0D0004 +#define DMA0_SOURCE_ADDRESS 23:0 + +#define DMA0_CONTROL 0x0D0008 +#define DMA0_CONTROL_STATUS 31:31 +#define DMA0_CONTROL_STATUS_IDLE 0 +#define DMA0_CONTROL_STATUS_ENABLE 1 +#define DMA0_CONTROL_SIZE 23:0 + +/* DMA 2 can transfer from: + DDR to SRAM. + SRAM to DDR. +*/ +#define DMA2_SOURCE 0x0D8010 +#define DMA2_SOURCE_SEL 31:31 +#define DMA2_SOURCE_SEL_DDR 0 +#define DMA2_SOURCE_SEL_SRAM 1 +#define DMA2_SOURCE_ADDRESS 30:0 + +#define DMA2_SOURCE_SIZE 0x0D8014 +#define DMA2_SOURCE_SIZE_SIZE 23:0 + +#define DMA2_DESTINATION 0x0D8018 +#define DMA2_DESTINATION_SEL 31:31 +#define DMA2_DESTINATION_SEL_DDR 0 +#define DMA2_DESTINATION_SEL_SRAM 1 +#define DMA2_DESTINATION_ADDRESS 29:0 + +#define DMA2_CONTROL 0x0D801C +#define DMA2_CONTROL_STATUS 31:31 +#define DMA2_CONTROL_STATUS_IDLE 0 +#define DMA2_CONTROL_STATUS_ENABLE 1 +#define DMA2_CONTROL_TRI_STREAM 30:30 +#define DMA2_CONTROL_TRI_STREAM_DISABLE 0 +#define DMA2_CONTROL_TRI_STREAM_ENABLE 1 +#define DMA2_CONTROL_FORMAT 29:28 +#define DMA2_CONTROL_FORMAT_8BPP 0 +#define DMA2_CONTROL_FORMAT_16BPP 1 +#define DMA2_CONTROL_FORMAT_32BPP 2 +#define DMA2_CONTROL_TILE_HEIGHT 27:16 +#define DMA2_CONTROL_TILE_WIDTH 12:0 + +#define DMA2_DESTINATION_PITCH 0x0D8020 +#define DMA2_DESTINATION_PITCH_PITCH 14:0 + +#define DMA2_INTCTL 0x0D8024 +#define DMA2_INTCTL_DMA2_STATUS 1:1 +#define DMA2_INTCTL_DMA2_STATUS_NORMAL 0 +#define DMA2_INTCTL_DMA2_STATUS_ABORT 1 +#define DMA2_INTCTL_DMA2_RAWINT 0:0 +#define DMA2_INTCTL_DMA2_RAWINT_CLEAR 0 +#define DMA2_INTCTL_DMA2_RAWINT_SET 1 + +/* DMA 1 can transfer from: + System to local DDR. + local DDR to system. + local DDR to local DDR. + + The source is alwasy linear and the destination is always tiled. +*/ +#define DMA1_SOURCE0 0x0D0010 +#define DMA1_SOURCE0_SEL 31:31 +#define DMA1_SOURCE0_SEL_LOCAL 0 +#define DMA1_SOURCE0_SEL_SYSTEM 1 +#define DMA1_SOURCE0_DECODE 30:30 +#define DMA1_SOURCE0_DECODE_DISABLE 0 +#define DMA1_SOURCE0_DECODE_ENABLE 1 +#define DMA1_SOURCE0_ADDRESS 29:0 + +#define DMA1_SOURCE0_SIZE 0x0D0014 +#define DMA1_SOURCE0_SIZE_NSC_CSS 27:27 +#define DMA1_SOURCE0_SIZE_NSC_CSS_DISABLE 0 +#define DMA1_SOURCE0_SIZE_NSC_CSS_ENABLE 1 +#define DMA1_SOURCE0_SIZE_NSC_CLL 26:24 +#define DMA1_SOURCE0_SIZE_SIZE 23:0 + +#define DMA1_DESTINATION 0x0D0018 +#define DMA1_DESTINATION_SEL 31:31 +#define DMA1_DESTINATION_SEL_LOCAL 0 +#define DMA1_DESTINATION_SEL_SYSTEM 1 +#define DMA1_DESTINATION_ADDRESS 29:0 + +#define DMA1_CONTROL 0x0D001C +#define DMA1_CONTROL_STATUS 31:31 +#define DMA1_CONTROL_STATUS_IDLE 0 +#define DMA1_CONTROL_STATUS_ENABLE 1 +#define DMA1_CONTROL_TRI_STREAM 30:30 +#define DMA1_CONTROL_TRI_STREAM_DISABLE 0 +#define DMA1_CONTROL_TRI_STREAM_ENABLE 1 +#define DMA1_CONTROL_FORMAT 29:28 +#define DMA1_CONTROL_FORMAT_8BPP 0 +#define DMA1_CONTROL_FORMAT_16BPP 1 +#define DMA1_CONTROL_FORMAT_32BPP 2 +#define DMA1_CONTROL_TILE_HEIGHT 27:16 +#define DMA1_CONTROL_TILE_WIDTH 12:0 + +#define DMA1_DESTINATION_PITCH 0x0D0020 +#define DMA1_DESTINATION_PITCH_PITCH 14:0 + +#define DMA_CONTROL 0x0D0024 +#define DMA_CONTROL_NSC_RB_SWAP 11:11 +#define DMA_CONTROL_NSC_RB_SWAP_DISABLE 0 +#define DMA_CONTROL_NSC_RB_SWAP_ENABLE 1 +#define DMA_CONTROL_CSC 10:10 +#define DMA_CONTROL_CSC_DISABLE 0 +#define DMA_CONTROL_CSC_ENABLE 1 +#define DMA_CONTROL_DECOMP 9:8 +#define DMA_CONTROL_DECOMP_TEXT 0 +#define DMA_CONTROL_DECOMP_NSC 1 +#define DMA_CONTROL_DECOMP_GOLOMB 2 +#define DMA_CONTROL_DMA1_STATUS 5:5 +#define DMA_CONTROL_DMA1_STATUS_NORMAL 0 +#define DMA_CONTROL_DMA1_STATUS_ABORT 1 +#define DMA_CONTROL_DMA0_STATUS 4:4 +#define DMA_CONTROL_DMA0_STATUS_NORMAL 0 +#define DMA_CONTROL_DMA0_STATUS_ABORT 1 +#define DMA_CONTROL_DMA1_RAWINT 1:1 +#define DMA_CONTROL_DMA1_RAWINT_CLEAR 0 +#define DMA_CONTROL_DMA1_RAWINT_SET 1 +#define DMA_CONTROL_DMA0_RAWINT 0:0 +#define DMA_CONTROL_DMA0_RAWINT_CLEAR 0 +#define DMA_CONTROL_DMA0_RAWINT_SET 1 + +/* DMA 1 source 1 and source 2 are only used when RGB is in 3 separate planes.*/ +#define DMA1_SOURCE1 0x0D0028 +#define DMA1_SOURCE1_ADDRESS 29:0 + +#define DMA1_SOURCE1_SIZE 0x0D002c +#define DMA1_SOURCE1_SIZE_NSC_CSS 27:27 +#define DMA1_SOURCE1_SIZE_NSC_CSS_DISABLE 0 +#define DMA1_SOURCE1_SIZE_NSC_CSS_ENABLE 1 +#define DMA1_SOURCE1_SIZE_NSC_CLL 26:24 +#define DMA1_SOURCE1_SIZE_SIZE 23:0 + +#define DMA1_SOURCE2 0x0D0030 +#define DMA1_SOURCE2_ADDRESS 29:0 + +#define DMA1_SOURCE2_SIZE 0x0D0034 +#define DMA1_SOURCE2_SIZE_NSC_CSS 27:27 +#define DMA1_SOURCE2_SIZE_NSC_CSS_DISABLE 0 +#define DMA1_SOURCE2_SIZE_NSC_CSS_ENABLE 1 +#define DMA1_SOURCE2_SIZE_NSC_CLL 26:24 +#define DMA1_SOURCE2_SIZE_SIZE 23:0 + + +/* 2D registers. */ + +#define DE_SOURCE 0x100000 +#define DE_SOURCE_WRAP 31:31 +#define DE_SOURCE_WRAP_DISABLE 0 +#define DE_SOURCE_WRAP_ENABLE 1 + +/* + * The following definitions are used in different setting + */ + +/* Use these definitions in XY addressing mode or linear addressing mode. */ +#define DE_SOURCE_X_K1 27:16 +#define DE_SOURCE_Y_K2 11:0 + +/* Use this definition in host write mode for mono. The Y_K2 is not used + in host write mode. */ +#define DE_SOURCE_X_K1_MONO 20:16 + +/* Use these definitions in Bresenham line drawing mode. */ +#define DE_SOURCE_X_K1_LINE 29:16 +#define DE_SOURCE_Y_K2_LINE 13:0 + +#define DE_DESTINATION 0x100004 +#define DE_DESTINATION_WRAP 31:31 +#define DE_DESTINATION_WRAP_DISABLE 0 +#define DE_DESTINATION_WRAP_ENABLE 1 +#if 1 + #define DE_DESTINATION_X 27:16 + #define DE_DESTINATION_Y 11:0 +#else + #define DE_DESTINATION_X 28:16 + #define DE_DESTINATION_Y 15:0 +#endif + +#define DE_DIMENSION 0x100008 +#define DE_DIMENSION_X 28:16 +#define DE_DIMENSION_Y_ET 15:0 + +#define DE_CONTROL 0x10000C +#define DE_CONTROL_STATUS 31:31 +#define DE_CONTROL_STATUS_STOP 0 +#define DE_CONTROL_STATUS_START 1 +#define DE_CONTROL_PATTERN 30:30 +#define DE_CONTROL_PATTERN_MONO 0 +#define DE_CONTROL_PATTERN_COLOR 1 +#define DE_CONTROL_UPDATE_DESTINATION_X 29:29 +#define DE_CONTROL_UPDATE_DESTINATION_X_DISABLE 0 +#define DE_CONTROL_UPDATE_DESTINATION_X_ENABLE 1 +#define DE_CONTROL_QUICK_START 28:28 +#define DE_CONTROL_QUICK_START_DISABLE 0 +#define DE_CONTROL_QUICK_START_ENABLE 1 +#define DE_CONTROL_DIRECTION 27:27 +#define DE_CONTROL_DIRECTION_LEFT_TO_RIGHT 0 +#define DE_CONTROL_DIRECTION_RIGHT_TO_LEFT 1 +#define DE_CONTROL_MAJOR 26:26 +#define DE_CONTROL_MAJOR_X 0 +#define DE_CONTROL_MAJOR_Y 1 +#define DE_CONTROL_STEP_X 25:25 +#define DE_CONTROL_STEP_X_POSITIVE 0 +#define DE_CONTROL_STEP_X_NEGATIVE 1 +#define DE_CONTROL_STEP_Y 24:24 +#define DE_CONTROL_STEP_Y_POSITIVE 0 +#define DE_CONTROL_STEP_Y_NEGATIVE 1 +#define DE_CONTROL_STRETCH 23:23 +#define DE_CONTROL_STRETCH_DISABLE 0 +#define DE_CONTROL_STRETCH_ENABLE 1 +#define DE_CONTROL_HOST 22:22 +#define DE_CONTROL_HOST_COLOR 0 +#define DE_CONTROL_HOST_MONO 1 +#define DE_CONTROL_LAST_PIXEL 21:21 +#define DE_CONTROL_LAST_PIXEL_OFF 0 +#define DE_CONTROL_LAST_PIXEL_ON 1 +#define DE_CONTROL_COMMAND 20:16 +#define DE_CONTROL_COMMAND_BITBLT 0 +#define DE_CONTROL_COMMAND_RECTANGLE_FILL 1 +#define DE_CONTROL_COMMAND_DE_TILE 2 +#define DE_CONTROL_COMMAND_TRAPEZOID_FILL 3 +#define DE_CONTROL_COMMAND_ALPHA_BLEND 4 +#define DE_CONTROL_COMMAND_RLE_STRIP 5 +#define DE_CONTROL_COMMAND_SHORT_STROKE 6 +#define DE_CONTROL_COMMAND_LINE_DRAW 7 +#define DE_CONTROL_COMMAND_HOST_WRITE 8 +#define DE_CONTROL_COMMAND_HOST_READ 9 +#define DE_CONTROL_COMMAND_HOST_WRITE_BOTTOM_UP 10 +#define DE_CONTROL_COMMAND_ROTATE 11 +#define DE_CONTROL_COMMAND_FONT 12 +#define DE_CONTROL_COMMAND_TEXTURE_LOAD 15 +#define DE_CONTROL_ROP_SELECT 15:15 +#define DE_CONTROL_ROP_SELECT_ROP3 0 +#define DE_CONTROL_ROP_SELECT_ROP2 1 +#define DE_CONTROL_ROP2_SOURCE 14:14 +#define DE_CONTROL_ROP2_SOURCE_BITMAP 0 +#define DE_CONTROL_ROP2_SOURCE_PATTERN 1 +#define DE_CONTROL_MONO_DATA 13:12 +#define DE_CONTROL_MONO_DATA_NOT_PACKED 0 +#define DE_CONTROL_MONO_DATA_8_PACKED 1 +#define DE_CONTROL_MONO_DATA_16_PACKED 2 +#define DE_CONTROL_MONO_DATA_32_PACKED 3 +#define DE_CONTROL_REPEAT_ROTATE 11:11 +#define DE_CONTROL_REPEAT_ROTATE_DISABLE 0 +#define DE_CONTROL_REPEAT_ROTATE_ENABLE 1 +#define DE_CONTROL_TRANSPARENCY_MATCH 10:10 +#define DE_CONTROL_TRANSPARENCY_MATCH_OPAQUE 0 +#define DE_CONTROL_TRANSPARENCY_MATCH_TRANSPARENT 1 +#define DE_CONTROL_TRANSPARENCY_SELECT 9:9 +#define DE_CONTROL_TRANSPARENCY_SELECT_SOURCE 0 +#define DE_CONTROL_TRANSPARENCY_SELECT_DESTINATION 1 +#define DE_CONTROL_TRANSPARENCY 8:8 +#define DE_CONTROL_TRANSPARENCY_DISABLE 0 +#define DE_CONTROL_TRANSPARENCY_ENABLE 1 +#define DE_CONTROL_ROP 7:0 + +/* Pseudo fields. */ + +#define DE_CONTROL_SHORT_STROKE_DIR 27:24 +#define DE_CONTROL_SHORT_STROKE_DIR_225 0 +#define DE_CONTROL_SHORT_STROKE_DIR_135 1 +#define DE_CONTROL_SHORT_STROKE_DIR_315 2 +#define DE_CONTROL_SHORT_STROKE_DIR_45 3 +#define DE_CONTROL_SHORT_STROKE_DIR_270 4 +#define DE_CONTROL_SHORT_STROKE_DIR_90 5 +#define DE_CONTROL_SHORT_STROKE_DIR_180 8 +#define DE_CONTROL_SHORT_STROKE_DIR_0 10 +#define DE_CONTROL_ROTATION 25:24 +#define DE_CONTROL_ROTATION_0 0 +#define DE_CONTROL_ROTATION_270 1 +#define DE_CONTROL_ROTATION_90 2 +#define DE_CONTROL_ROTATION_180 3 + +#define DE_PITCH 0x100010 +#define DE_PITCH_DESTINATION 28:16 +#define DE_PITCH_SOURCE 12:0 + +#define DE_FOREGROUND 0x100014 +#define DE_FOREGROUND_COLOR 31:0 + +#define DE_BACKGROUND 0x100018 +#define DE_BACKGROUND_COLOR 31:0 + +#define DE_STRETCH_FORMAT 0x10001C +#define DE_STRETCH_FORMAT_PATTERN_XY 30:30 +#define DE_STRETCH_FORMAT_PATTERN_XY_NORMAL 0 +#define DE_STRETCH_FORMAT_PATTERN_XY_OVERWRITE 1 +#define DE_STRETCH_FORMAT_PATTERN_Y 29:27 +#define DE_STRETCH_FORMAT_PATTERN_X 25:23 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT 21:20 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_8 0 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_16 1 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_32 2 +#define DE_STRETCH_FORMAT_ADDRESSING 19:16 +#define DE_STRETCH_FORMAT_ADDRESSING_XY 0 +#define DE_STRETCH_FORMAT_ADDRESSING_LINEAR 15 +#define DE_STRETCH_FORMAT_SOURCE_HEIGHT 11:0 + +#define DE_COLOR_COMPARE 0x100020 +#define DE_COLOR_COMPARE_COLOR 23:0 + +#define DE_COLOR_COMPARE_MASK 0x100024 +#define DE_COLOR_COMPARE_MASK_MASKS 23:0 + +#define DE_MASKS 0x100028 +#define DE_MASKS_BYTE_MASK 31:16 +#define DE_MASKS_BIT_MASK 15:0 + +#define DE_CLIP_TL 0x10002C +#define DE_CLIP_TL_TOP 31:16 +#define DE_CLIP_TL_STATUS 13:13 +#define DE_CLIP_TL_STATUS_DISABLE 0 +#define DE_CLIP_TL_STATUS_ENABLE 1 +#define DE_CLIP_TL_INHIBIT 12:12 +#define DE_CLIP_TL_INHIBIT_OUTSIDE 0 +#define DE_CLIP_TL_INHIBIT_INSIDE 1 +#define DE_CLIP_TL_LEFT 11:0 + +#define DE_CLIP_BR 0x100030 +#define DE_CLIP_BR_BOTTOM 31:16 +#define DE_CLIP_BR_RIGHT 12:0 + +#define DE_MONO_PATTERN_LOW 0x100034 +#define DE_MONO_PATTERN_LOW_PATTERN 31:0 + +#define DE_MONO_PATTERN_HIGH 0x100038 +#define DE_MONO_PATTERN_HIGH_PATTERN 31:0 + +#define DE_WINDOW_WIDTH 0x10003C +#define DE_WINDOW_WIDTH_DESTINATION 28:16 +#define DE_WINDOW_WIDTH_SOURCE 12:0 + +#define DE_WINDOW_SOURCE_BASE 0x100040 +#define DE_WINDOW_SOURCE_BASE_ADDRESS 29:0 + +#define DE_WINDOW_DESTINATION_BASE 0x100044 +#define DE_WINDOW_DESTINATION_BASE_ADDRESS 29:0 + +#define DE_ALPHA 0x100048 +#define DE_ALPHA_VALUE 7:0 + +#define DE_WRAP 0x10004C +#define DE_WRAP_X 31:16 +#define DE_WRAP_Y 15:0 + +#define DE_STATE2 0x100054 +#define DE_STATE2_DE_FIFO 3:3 +#define DE_STATE2_DE_FIFO_NOTEMPTY 1 +#define DE_STATE2_DE_FIFO_EMPTY 0 +#define DE_STATE2_DE_STATUS 2:2 +#define DE_STATE2_DE_STATUS_IDLE 0 +#define DE_STATE2_DE_STATUS_BUSY 1 +#define DE_STATE2_DE_MEM_FIFO 1:1 +#define DE_STATE2_DE_MEM_FIFO_NOTEMPTY 0 +#define DE_STATE2_DE_MEM_FIFO_EMPTY 1 +#define DE_STATE2_DE_ABORT 0:0 +#define DE_STATE2_DE_ABORT_OFF 0 +#define DE_STATE2_DE_ABORT_ON 1 + +/* Color Space Conversion registers. */ + +#define CSC_Y_SOURCE_BASE 0x1000C8 +#define CSC_Y_SOURCE_BASE_ADDRESS 29:0 + +#define CSC_CONSTANTS 0x1000CC +#define CSC_CONSTANTS_Y 31:24 +#define CSC_CONSTANTS_R 23:16 +#define CSC_CONSTANTS_G 15:8 +#define CSC_CONSTANTS_B 7:0 + +#define CSC_Y_SOURCE_X 0x1000D0 +#define CSC_Y_SOURCE_X_INTEGER 27:16 +#define CSC_Y_SOURCE_X_FRACTION 15:3 + +#define CSC_Y_SOURCE_Y 0x1000D4 +#define CSC_Y_SOURCE_Y_INTEGER 27:16 +#define CSC_Y_SOURCE_Y_FRACTION 15:3 + +#define CSC_U_SOURCE_BASE 0x1000D8 +#define CSC_U_SOURCE_BASE_ADDRESS 29:0 + +#define CSC_V_SOURCE_BASE 0x1000DC +#define CSC_V_SOURCE_BASE_ADDRESS 29:0 + +#define CSC_SOURCE_DIMENSION 0x1000E0 +#define CSC_SOURCE_DIMENSION_X 31:16 +#define CSC_SOURCE_DIMENSION_Y 15:0 + +#define CSC_SOURCE_PITCH 0x1000E4 +#define CSC_SOURCE_PITCH_Y 31:16 +#define CSC_SOURCE_PITCH_UV 15:0 + +#define CSC_DESTINATION 0x1000E8 +#define CSC_DESTINATION_WRAP 31:31 +#define CSC_DESTINATION_WRAP_DISABLE 0 +#define CSC_DESTINATION_WRAP_ENABLE 1 +#define CSC_DESTINATION_X 27:16 +#define CSC_DESTINATION_Y 11:0 + +#define CSC_DESTINATION_DIMENSION 0x1000EC +#define CSC_DESTINATION_DIMENSION_X 31:16 +#define CSC_DESTINATION_DIMENSION_Y 15:0 + +#define CSC_DESTINATION_PITCH 0x1000F0 +#define CSC_DESTINATION_PITCH_X 31:16 +#define CSC_DESTINATION_PITCH_Y 15:0 + +#define CSC_SCALE_FACTOR 0x1000F4 +#define CSC_SCALE_FACTOR_HORIZONTAL 31:16 +#define CSC_SCALE_FACTOR_VERTICAL 15:0 + +#define CSC_DESTINATION_BASE 0x1000F8 +#define CSC_DESTINATION_BASE_ADDRESS 29:0 + +#define CSC_CONTROL 0x1000FC +#define CSC_CONTROL_STATUS 31:31 +#define CSC_CONTROL_STATUS_STOP 0 +#define CSC_CONTROL_STATUS_START 1 +#define CSC_CONTROL_SOURCE_FORMAT 30:28 +#define CSC_CONTROL_SOURCE_FORMAT_YUV422 0 +#define CSC_CONTROL_SOURCE_FORMAT_YUV420I 1 +#define CSC_CONTROL_SOURCE_FORMAT_YUV420 2 +#define CSC_CONTROL_SOURCE_FORMAT_YVU9 3 +#define CSC_CONTROL_SOURCE_FORMAT_IYU1 4 +#define CSC_CONTROL_SOURCE_FORMAT_IYU2 5 +#define CSC_CONTROL_SOURCE_FORMAT_RGB565 6 +#define CSC_CONTROL_SOURCE_FORMAT_RGB8888 7 +#define CSC_CONTROL_DESTINATION_FORMAT 27:26 +#define CSC_CONTROL_DESTINATION_FORMAT_RGB565 0 +#define CSC_CONTROL_DESTINATION_FORMAT_RGB8888 1 +#define CSC_CONTROL_HORIZONTAL_FILTER 25:25 +#define CSC_CONTROL_HORIZONTAL_FILTER_DISABLE 0 +#define CSC_CONTROL_HORIZONTAL_FILTER_ENABLE 1 +#define CSC_CONTROL_VERTICAL_FILTER 24:24 +#define CSC_CONTROL_VERTICAL_FILTER_DISABLE 0 +#define CSC_CONTROL_VERTICAL_FILTER_ENABLE 1 +#define CSC_CONTROL_BYTE_ORDER 23:23 +#define CSC_CONTROL_BYTE_ORDER_YUYV 0 +#define CSC_CONTROL_BYTE_ORDER_UYVY 1 + +#define DE_DATA_PORT 0x110000 + + +#define ZV0_CAPTURE_CTRL 0x090000 +#define ZV0_CAPTURE_CTRL_FIELD_INPUT 27:27 +#define ZV0_CAPTURE_CTRL_FIELD_INPUT_EVEN_FIELD 0 +#define ZV0_CAPTURE_CTRL_FIELD_INPUT_ODD_FIELD 1 +#define ZV0_CAPTURE_CTRL_SCAN 26:26 +#define ZV0_CAPTURE_CTRL_SCAN_PROGRESSIVE 0 +#define ZV0_CAPTURE_CTRL_SCAN_INTERLACE 1 +#define ZV0_CAPTURE_CTRL_CURRENT_BUFFER 25:25 +#define ZV0_CAPTURE_CTRL_CURRENT_BUFFER_0 0 +#define ZV0_CAPTURE_CTRL_CURRENT_BUFFER_1 1 +#define ZV0_CAPTURE_CTRL_VERTICAL_SYNC 24:24 +#define ZV0_CAPTURE_CTRL_VERTICAL_SYNC_INACTIVE 0 +#define ZV0_CAPTURE_CTRL_VERTICAL_SYNC_ACTIVE 1 +#define ZV0_CAPTURE_CTRL_OUTPUT_FORMAT 22:22 +#define ZV0_CAPTURE_CTRL_OUTPUT_FORMAT_16 0 +#define ZV0_CAPTURE_CTRL_OUTPUT_FORMAT_32 1 +#define ZV0_CAPTURE_CTRL_INCOME_DATA 21:21 +#define ZV0_CAPTURE_CTRL_INCOME_DATA_16 0 +#define ZV0_CAPTURE_CTRL_INCOME_DATA_32 1 +#define ZV0_CAPTURE_CTRL_ADJ 19:19 +#define ZV0_CAPTURE_CTRL_ADJ_NORMAL 0 +#define ZV0_CAPTURE_CTRL_ADJ_DELAY 1 +#define ZV0_CAPTURE_CTRL_HA 18:18 +#define ZV0_CAPTURE_CTRL_HA_DISABLE 0 +#define ZV0_CAPTURE_CTRL_HA_ENABLE 1 +#define ZV0_CAPTURE_CTRL_VSK 17:17 +#define ZV0_CAPTURE_CTRL_VSK_DISABLE 0 +#define ZV0_CAPTURE_CTRL_VSK_ENABLE 1 +#define ZV0_CAPTURE_CTRL_HSK 16:16 +#define ZV0_CAPTURE_CTRL_HSK_DISABLE 0 +#define ZV0_CAPTURE_CTRL_HSK_ENABLE 1 +#define ZV0_CAPTURE_CTRL_FD 15:15 +#define ZV0_CAPTURE_CTRL_FD_RISING 0 +#define ZV0_CAPTURE_CTRL_FD_FALLING 1 +#define ZV0_CAPTURE_CTRL_VP 14:14 +#define ZV0_CAPTURE_CTRL_VP_HIGH 0 +#define ZV0_CAPTURE_CTRL_VP_LOW 1 +#define ZV0_CAPTURE_CTRL_HP 13:13 +#define ZV0_CAPTURE_CTRL_HP_HIGH 0 +#define ZV0_CAPTURE_CTRL_HP_LOW 1 +#define ZV0_CAPTURE_CTRL_CP 12:12 +#define ZV0_CAPTURE_CTRL_CP_HIGH 0 +#define ZV0_CAPTURE_CTRL_CP_LOW 1 +#define ZV0_CAPTURE_CTRL_UVS 11:11 +#define ZV0_CAPTURE_CTRL_UVS_DISABLE 0 +#define ZV0_CAPTURE_CTRL_UVS_ENABLE 1 +#define ZV0_CAPTURE_CTRL_BS 10:10 +#define ZV0_CAPTURE_CTRL_BS_DISABLE 0 +#define ZV0_CAPTURE_CTRL_BS_ENABLE 1 +#define ZV0_CAPTURE_CTRL_CS 9:9 +#define ZV0_CAPTURE_CTRL_CS_16 0 +#define ZV0_CAPTURE_CTRL_CS_8 1 +#define ZV0_CAPTURE_CTRL_CF 8:8 +#define ZV0_CAPTURE_CTRL_CF_YUV 0 +#define ZV0_CAPTURE_CTRL_CF_RGB 1 +#define ZV0_CAPTURE_CTRL_FS 7:7 +#define ZV0_CAPTURE_CTRL_FS_DISABLE 0 +#define ZV0_CAPTURE_CTRL_FS_ENABLE 1 +#define ZV0_CAPTURE_CTRL_WEAVE 6:6 +#define ZV0_CAPTURE_CTRL_WEAVE_DISABLE 0 +#define ZV0_CAPTURE_CTRL_WEAVE_ENABLE 1 +#define ZV0_CAPTURE_CTRL_BOB 5:5 +#define ZV0_CAPTURE_CTRL_BOB_DISABLE 0 +#define ZV0_CAPTURE_CTRL_BOB_ENABLE 1 +#define ZV0_CAPTURE_CTRL_DB 4:4 +#define ZV0_CAPTURE_CTRL_DB_DISABLE 0 +#define ZV0_CAPTURE_CTRL_DB_ENABLE 1 +#define ZV0_CAPTURE_CTRL_CC 3:3 +#define ZV0_CAPTURE_CTRL_CC_CONTINUE 0 +#define ZV0_CAPTURE_CTRL_CC_CONDITION 1 +#define ZV0_CAPTURE_CTRL_RGB 2:2 +#define ZV0_CAPTURE_CTRL_RGB_DISABLE 0 +#define ZV0_CAPTURE_CTRL_RGB_ENABLE 1 +#define ZV0_CAPTURE_CTRL_656 1:1 +#define ZV0_CAPTURE_CTRL_656_DISABLE 0 +#define ZV0_CAPTURE_CTRL_656_ENABLE 1 +#define ZV0_CAPTURE_CTRL_CAP 0:0 +#define ZV0_CAPTURE_CTRL_CAP_DISABLE 0 +#define ZV0_CAPTURE_CTRL_CAP_ENABLE 1 + +#define ZV0_CAPTURE_CLIP 0x090004 +#define ZV0_CAPTURE_CLIP_YCLIP_EVEN_FIELD 25:16 +#define ZV0_CAPTURE_CLIP_YCLIP 25:16 +#define ZV0_CAPTURE_CLIP_XCLIP 9:0 + +#define ZV0_CAPTURE_SIZE 0x090008 +#define ZV0_CAPTURE_SIZE_HEIGHT 26:16 +#define ZV0_CAPTURE_SIZE_WIDTH 10:0 + +#define ZV0_CAPTURE_BUF0_ADDRESS 0x09000C +#define ZV0_CAPTURE_BUF0_ADDRESS_STATUS 31:31 +#define ZV0_CAPTURE_BUF0_ADDRESS_STATUS_CURRENT 0 +#define ZV0_CAPTURE_BUF0_ADDRESS_STATUS_PENDING 1 +#define ZV0_CAPTURE_BUF0_ADDRESS_ADDRESS 29:0 + +#define ZV0_CAPTURE_BUF1_ADDRESS 0x090010 +#define ZV0_CAPTURE_BUF1_ADDRESS_STATUS 31:31 +#define ZV0_CAPTURE_BUF1_ADDRESS_STATUS_CURRENT 0 +#define ZV0_CAPTURE_BUF1_ADDRESS_STATUS_PENDING 1 +#define ZV0_CAPTURE_BUF1_ADDRESS_ADDRESS 29:0 + +#define ZV0_CAPTURE_BUF_OFFSET 0x090014 +#define ZV0_CAPTURE_BUF_OFFSET_YCLIP_ODD_FIELD 25:16 +#define ZV0_CAPTURE_BUF_OFFSET_OFFSET 15:0 + +#define ZV0_CAPTURE_FIFO_CTRL 0x090018 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO 2:0 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO_0 0 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO_1 1 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO_2 2 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO_3 3 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO_4 4 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO_5 5 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO_6 6 +#define ZV0_CAPTURE_FIFO_CTRL_FIFO_7 7 + +#define ZV0_CAPTURE_YRGB_CONST 0x09001C +#define ZV0_CAPTURE_YRGB_CONST_Y 31:24 +#define ZV0_CAPTURE_YRGB_CONST_R 23:16 +#define ZV0_CAPTURE_YRGB_CONST_G 15:8 +#define ZV0_CAPTURE_YRGB_CONST_B 7:0 + +#define ZV0_CAPTURE_LINE_COMP 0x090020 +#define ZV0_CAPTURE_LINE_COMP_LC 10:0 + + + +#define I2C_BYTE_COUNT 0x010040 +#define I2C_BYTE_COUNT_COUNT 3:0 + +#define I2C_CTRL 0x010041 +#define I2C_CTRL_REPEAT 6:6 +#define I2C_CTRL_REPEAT_DISABLE 0 +#define I2C_CTRL_REPEAT_ENABLE 1 +#define I2C_CTRL_INTACK 5:5 +#define I2C_CTRL_INTACK_DISABLE 0 +#define I2C_CTRL_INTACK_ENABLE 1 +#define I2C_CTRL_INT 4:4 +#define I2C_CTRL_INT_DISABLE 0 +#define I2C_CTRL_INT_ENABLE 1 +#define I2C_CTRL_CTRL 2:2 +#define I2C_CTRL_CTRL_STOP 0 +#define I2C_CTRL_CTRL_START 1 +#define I2C_CTRL_MODE 1:1 +#define I2C_CTRL_MODE_STANDARD 0 +#define I2C_CTRL_MODE_FAST 1 +#define I2C_CTRL_EN 0:0 +#define I2C_CTRL_EN_DISABLE 0 +#define I2C_CTRL_EN_ENABLE 1 + +#define I2C_STATUS 0x010042 +#define I2C_STATUS_TX 3:3 +#define I2C_STATUS_TX_PROGRESS 0 +#define I2C_STATUS_TX_COMPLETED 1 +#define I2C_STATUS_ERR 2:2 +#define I2C_STATUS_ERR_NORMAL 0 +#define I2C_STATUS_ERR_ERROR 1 +#define I2C_STATUS_ACK 1:1 +#define I2C_STATUS_ACK_RECEIVED 1 +#define I2C_STATUS_ACK_NOT 0 +#define I2C_STATUS_BUS 0:0 +#define I2C_STATUS_BUS_IDLE 0 +#define I2C_STATUS_BUS_BUSY 1 + +#define I2C_RESET 0x010042 +#define I2C_RESET_TX 3:3 +#define I2C_RESET_TX_CLEAR 0 +#define I2C_RESET_ERR 2:2 +#define I2C_RESET_ERR_CLEAR 0 +#define I2C_RESET_ACK 1:1 +#define I2C_RESET_ACK_CLEAR 0 +#define I2C_RESET_BUS 0:0 +#define I2C_RESET_BUS_CLEAR 0 + +#define I2C_SLAVE_ADDRESS 0x010043 +#define I2C_SLAVE_ADDRESS_ADDRESS 7:1 +#define I2C_SLAVE_ADDRESS_RW 0:0 +#define I2C_SLAVE_ADDRESS_RW_W 0 +#define I2C_SLAVE_ADDRESS_RW_R 1 + +#define I2C_DATA0 0x010044 +#define I2C_DATA1 0x010045 +#define I2C_DATA2 0x010046 +#define I2C_DATA3 0x010047 +#define I2C_DATA4 0x010048 +#define I2C_DATA5 0x010049 +#define I2C_DATA6 0x01004A +#define I2C_DATA7 0x01004B +#define I2C_DATA8 0x01004C +#define I2C_DATA9 0x01004D +#define I2C_DATA10 0x01004E +#define I2C_DATA11 0x01004F +#define I2C_DATA12 0x010050 +#define I2C_DATA13 0x010051 +#define I2C_DATA14 0x010052 +#define I2C_DATA15 0x010053 + +/* MMIO offset between I2C0 and I2C1 */ +#define I2C_OFFSET 0x20 + + +#define TIMER_CONTROL 0x010030 +#define TIMER_CONTROL_COUNTER 31:4 +#define TIMER_CONTROL_RAWINT_STATUS 3:3 +#define TIMER_CONTROL_RAWINT_STATUS_CLEAR 0 +#define TIMER_CONTROL_RAWINT_STATUS_PENDING 1 +#define TIMER_CONTROL_RAWINT_STATUS_RESET 1 +#define TIMER_CONTROL_RAWINT_ENABLE 2:2 +#define TIMER_CONTROL_RAWINT_ENABLE_DISABLE 0 +#define TIMER_CONTROL_RAWINT_ENABLE_ENABLE 1 +#define TIMER_CONTROL_DIV16 1:1 +#define TIMER_CONTROL_DIV16_DISABLE 0 +#define TIMER_CONTROL_DIV16_ENABLE 1 +#define TIMER_CONTROL_ENABLE 0:0 +#define TIMER_CONTROL_ENABLE_DISABLE 0 +#define TIMER_CONTROL_ENABLE_ENABLE 1 + +#define TIMER_OFFSET 4 + + +#define UART_RX 0x030000 +#define UART_RX_DATA 7:0 + +#define UART_TX 0x030000 +#define UART_TX_DATA 7:0 + +#define UART_DLL 0x030000 +#define UART_DLL_DATA 7:0 + +#define UART_DLM 0x030004 +#define UART_DLM_DATA 7:0 + +#define UART_INT 0x030004 +#define UART_INT_RX_LINE 2:2 +#define UART_INT_RX_LINE_DISABLE 0 +#define UART_INT_RX_LINE_ENABLE 1 +#define UART_INT_TX_BUF_EMTPTY 1:1 +#define UART_INT_TX_BUF_EMPTY_DISABLE 0 +#define UART_INT_TX_BUF_EMPTY_ENABLE 1 +#define UART_INT_RX_BUF_FULL 0:0 +#define UART_INT_RX_BUF_FULL_DISABLE 0 +#define UART_INT_RX_BUF_FULL_ENABLE 1 + +#define UART_STATUS 0x030008 +#define UART_STATUS_FIFO 7:6 +#define UART_STATUS_FIFO_DISABLE 0 +#define UART_STATUS_FIFO_ENABLE 3 +#define UART_STATUS_INT_ID 5:1 +#define UART_STATUS_INT_ID_RXLINE 3 +#define UART_STATUS_INT_ID_RXDATA 2 +#define UART_STATUS_INT_ID_RXFIFO 6 +#define UART_STATUS_INT_ID_TXEMPTY 1 +#define UART_STATUS_INT_ID_XOFF 8 +#define UART_STATUS_INT_ID_EDGE 16 +#define UART_STATUS_NINT 0:0 +#define UART_STATUS_NINT_PENDING 0 +#define UART_STATUS_NINT_NOPENDING 1 + +#define UART_CONTROL 0x030008 +#define UART_CONTROL_RX_FIFO 7:6 +#define UART_CONTROL_RX_FIFO_1 0 +#define UART_CONTROL_RX_FIFO_16 1 +#define UART_CONTROL_RX_FIFO_32 2 +#define UART_CONTROL_RX_FIFO_62 3 +#define UART_CONTROL_TX_FIFO 5:4 +#define UART_CONTROL_TX_FIFO_1 0 +#define UART_CONTROL_TX_FIFO_16 1 +#define UART_CONTROL_TX_FIFO_32 2 +#define UART_CONTROL_TX_FIFO_62 3 +#define UART_CONTROL_TX_FIFOCLR 2:2 +#define UART_CONTROL_TX_FIFOCLR_CLR 1 +#define UART_CONTROL_RX_FOFOCLR 1:1 +#define UART_CONTROL_RX_FIFOCLR_CLR 1 +#define UART_CONTROL_FIFO 0:0 +#define UART_CONTROL_FIFO_DISABLE 0 +#define UART_CONTROL_FIFO_ENABLE 1 + +#define UART_LINECONTROL 0x03000C +#define UART_LINECONTROL_DLAB 7:7 +#define UART_LINECONTROL_DLAB_NORMAL 0 +#define UART_LINECONTROL_DLAB_CONFIG 1 +#define UART_LINECONTROL_SETBREAK 6:6 +#define UART_LINECONTROL_SETBREAK_DISABLE 0 +#define UART_LINECONTROL_SETBREAK_ENABLE 1 +#define UART_LINECONTROL_STICKPARITY 5:5 +#define UART_LINECONTROL_STICKPARITY_DISABLE 0 +#define UART_LINECONTROL_STICKPARITY_ENABLE 1 +#define UART_LINECONTROL_PARITYSELECT 4:4 +#define UART_LINECONTROL_PARITYSELECT_ODD 0 +#define UART_LINECONTROL_PARITYSELECT_EVEN 1 +#define UART_LINECONTROL_PARITY 3:3 +#define UART_LINECONTROL_PARITY_DISABLE 0 +#define UART_LINECONTROL_PARITY_ENABLE 1 +#define UART_LINECONTROL_STOPBIT 2:2 +#define UART_LINECONTROL_STOPBIT_ONE 0 +#define UART_LINECONTROL_STOPBIT_TWO 1 +#define UART_LINECONTROL_LENGTH 1:0 +#define UART_LINECONTROL_LENGTH_5BIT 0 +#define UART_LINECONTROL_LENGTH_6BIT 1 +#define UART_LINECONTROL_LENGTH_7BIT 2 +#define UART_LINECONTROL_LENGTH_8BIT 3 + +#define UART_LINESTATUS 0x030014 +#define UART_LINESTATUS_FIFO_ERR 7:7 +#define UART_LINESTATUS_TX_EMPTY 6:6 +#define UART_LINESTATUS_TX_HOLDEMPTY 5:5 +#define UART_LINESTATUS_BI 4:4 +#define UART_LINESTATUS_FRAME_ERR 3:3 +#define UART_LINESTATUS_PARITY_ERR 2:2 +#define UART_LINESTATUS_OVERRUN_ERR 1:1 +#define UART_LINESTATUS_DATA_READY 0:0 + +#define UART_OFFSET 0x20 + +#define UART_SCRATCH 0x03001C + + + +#define I2S_TX_DATA_L 0x0A0200 +#define I2S_TX_DATA_L_DATA 15:0 + +#define I2S_TX_DATA_R 0x0A0204 +#define I2S_TX_DATA_R_DATA 15:0 + +#define I2S_RX_DATA_L 0x0A0208 +#define I2S_RX_DATA_L_DATA 15:0 + +#define I2S_RX_DATA_R 0x0A020C +#define I2S_RX_DATA_R_DATA 15:0 + +#define I2S_STATUS 0x0A0210 +#define I2S_STATUS_R 11:11 +#define I2S_STATUS_R_NO_ERR 0 +#define I2S_STATUS_R_OVERFLOW 1 +#define I2S_STATUS_T 10:10 +#define I2S_STATUS_T_NO_ERR 0 +#define I2S_STATUS_T_UNDERFLOW 1 +#define I2S_STATUS_TX 2:2 +#define I2S_STATUS_TX_DISABLE 0 +#define I2S_STATUS_TX_ENABLE 1 + +#define I2S_CTRL 0x0A0214 +#define I2S_CTRL_MODE 7:7 +#define I2S_CTRL_MODE_SLAVE 0 +#define I2S_CTRL_MODE_MASTER 1 +#define I2S_CTRL_CS 6:5 +#define I2S_CTRL_CS_16 0 +#define I2S_CTRL_CS_24 1 +#define I2S_CTRL_CS_32 2 +#define I2S_CTRL_CDIV 4:0 + +#define I2S_SRAM_DMA 0x0A0218 +#define I2S_SRAM_DMA_STATE 31:31 +#define I2S_SRAM_DMA_STATE_DISABLE 0 +#define I2S_SRAM_DMA_STATE_ENABLE 1 +#define I2S_SRAM_DMA_SIZE 23:16 +#define I2S_SRAM_DMA_ADDRESS 8:0 + +#define I2S_SRAM_DMA_STATUS 0x0A021C +#define I2S_SRAM_DMA_STATUS_TC 0:0 +#define I2S_SRAM_DMA_STATUS_TC_COMPLETE 1 +#define I2S_SRAM_DMA_STATUS_TC_CLEAR 0 + +#define SRAM_OUTPUT_BASE 0x8000 +#define SRAM_INPUT_BASE 0x8800 +#define SRAM_SIZE 0x0800 + + +#define SM768_PHY_MAX_LANE 4 + +#define DDRPHYREG(A) (A * 4) + 0x4000 +#define RIDR DDRPHYREG(0x00) +#define PIR DDRPHYREG(0x01) +#define ACIOCR DDRPHYREG(0x09) +#define BISTMSKR0 DDRPHYREG(0x41) +#define BISTMSKR1 DDRPHYREG(0x42) +#define BISTLSR DDRPHYREG(0x44) +#define BISTUDPR DDRPHYREG(0x48) +#define BISTBER0 DDRPHYREG(0x4B) +#define BISTBER1 DDRPHYREG(0x4C) +#define BISTBER2 DDRPHYREG(0x4D) +#define BISTWCSR DDRPHYREG(0x4E) +#define BISTFWR0 DDRPHYREG(0x4F) +#define BISTFWR1 DDRPHYREG(0x50) +#define DX0DLLCR DDRPHYREG(0x73) +#define DX0DQSTR DDRPHYREG(0x75) +#define DX1DLLCR DDRPHYREG(0x83) +#define DX1DQSTR DDRPHYREG(0x85) +#define DX2DLLCR DDRPHYREG(0x93) +#define DX2DQSTR DDRPHYREG(0x95) +#define DX3DLLCR DDRPHYREG(0xA3) +#define DX3DQSTR DDRPHYREG(0xA5) + +#define PGCR DDRPHYREG(0x02) +#define PGCR_LBMODE 31:31 +#define PGCR_LBGDQS 30:30 +#define PGCR_LBDQSS 29:29 +#define PGCR_RFSHDT 28:25 +#define PGCR_PDDISDX 24:24 +#define PGCR_ZCKSEL 23:22 +#define PGCR_RANKEN 21:18 +#define PGCR_IODDRM 17:16 +#define PGCR_IOLB 15:15 +#define PGCR_IOLB_AFTERPAD 0 +#define PGCR_IOLB_BEFOREPAD 1 +#define PGCR_CKINV 14:14 +#define PGCR_CKDV 13:12 +#define PGCR_CKEN 11:9 +#define PGCR_DTOSEL 8:5 +#define PGCR_DFTLMT 4:3 +#define PGCR_DFTCMP 2:2 +#define PGCR_DQSCFG 1:1 +#define PGCR_ITMDMD 0:0 +#define PGCR_ITMDMD_DQSDQS 0 +#define PGCR_ITMDMD_DQS 1 + +#define PGSR DDRPHYREG(0x03) +#define PGSR_TQ 31:31 +#define PGSR_RESERVED 30:10 +#define PGSR_RVEIRR 9:9 +#define PGSR_RVERR 8:8 +#define PGSR_DFTERR 7:7 +#define PGSR_DTIERR 6:6 +#define PGSR_DTERR 5:5 +#define PGSR_DTDONE 4:4 +#define PGSR_DIDONE 3:3 +#define PGSR_ZCDONE 2:2 +#define PGSR_DLDONE 1:1 +#define PGSR_IDONE 0:0 +#define PGSR_IDONE_NO 0 +#define PGSR_IDONE_YES 1 + +#define BISTRR DDRPHYREG(0x40) //BIST Run Register +#define BISTRR_RESERVED 31:26 +#define BISTRR_BCKSEL 25:23 +#define BISTRR_BDXSEL 22:19 +#define BISTRR_BDPAT 18:17 +#define BISTRR_BDPAT_WALKING0 0 +#define BISTRR_BDPAT_WALKING1 1 +#define BISTRR_BDPAT_RANDOM 2 +#define BISTRR_BDPAT_PROGRAM 3 +#define BISTRR_BDMEN 16:16 +#define BISTRR_BDMEM_DISABLE 0 +#define BISTRR_BDMEN_ENABLE 1 +#define BISTRR_BACEN 15:15 +#define BISTRR_BACEN_DISABLE 0 +#define BISTRR_BACEN_ENABLE 1 +#define BISTRR_BDXEN 14:14 +#define BISTRR_BDXEN_DISABLE 0 +#define BISTRR_BDXEN_ENABLE 1 +#define BISTRR_BSONF 13:13 +#define BISTRR_NFAIL 12:5 +#define BISTRR_BINF 4:4 +#define BISTRR_BINF_STOPONDONE 0 +#define BISTRR_BINF_NONSTOP 1 +#define BISTRR_BMODE 3:3 +#define BISTRR_BMODE_LOOPBACK 0 +#define BISTRR_BMODE_DRAM 1 +#define BISTRR_BINST 2:0 +#define BISTRR_BINST_NOP 0 +#define BISTRR_BINST_RUN 1 +#define BISTRR_BINST_STOP 2 +#define BISTRR_BINST_RESET 3 + +#define BISTWCR DDRPHYREG(0x43) +#define BISTWCR_RESERVED 31:16 +#define BISTWCR_BWCNT 15:0 + +#define BISTAR0 DDRPHYREG(0x45) +#define BISTAR0_RESERVED 31:31 +#define BISTAR0_BBANK 30:28 +#define BISTAR0_BROW 27:12 +#define BISTAR0_BCOL 11:0 + +#define BISTAR1 DDRPHYREG(0x46) +#define BISTAR1_RESERVED 31:16 +#define BISTAR1_BAINC 15:4 +#define BISTAR1_BMRANK 3:2 +#define BISTAR1_BRANK 1:0 + +#define BISTAR2 DDRPHYREG(0x47) +#define BISTAR2_RESERVED 31:31 +#define BISTAR2_BMBANK 30:28 +#define BISTAR2_BMROW 27:12 +#define BISTAR2_BMCOL 11:0 + +#define BISTGSR DDRPHYREG(0x49) +#define BISTGSR_CASBER 31:30 +#define BISTGSR_RASBER 29:28 +#define BISTGSR_DMBER 27:24 +#define BISTGSR_TDPBER 23:22 +#define BISTGSR_PARBER 21:20 +#define BISTGSR_RESERVED 19:3 +#define BISTGSR_BDXERR 2:2 +#define BISTGSR_BDXERR_NO 0 +#define BISTGSR_BDXERR_YES 1 +#define BISTGSR_BACERR 1:1 +#define BISTGSR_BACERR_NO 0 +#define BISTGSR_BACERR_YES 1 +#define BISTGSR_BDONE 0:0 +#define BISTGSR_BDONE_NO 0 +#define BISTGSR_BDONE_YES 1 + +#define BISTWER DDRPHYREG(0x4A) +#define BISTWER_DXWER 31:16 +#define BISTWER_ACWER 15:0 + + + + + + +//PHY Interface Interrupt Mute Control Register +#define IH_MUTE_PHY_STAT0 0x00000184 +#define IH_MUTE_PHY_STAT0_HPD_MASK 0x00000001 //When set to 1, mutes ih_phy_stat0[0] +#define IH_MUTE_PHY_STAT0_TX_PHY_LOCK_MASK 0x00000002 //When set to 1, mutes ih_phy_stat0[1] +#define IH_MUTE_PHY_STAT0_RX_SENSE_0_MASK 0x00000004 //When set to 1, mutes ih_phy_stat0[2] +#define IH_MUTE_PHY_STAT0_RX_SENSE_1_MASK 0x00000008 //When set to 1, mutes ih_phy_stat0[3] +#define IH_MUTE_PHY_STAT0_RX_SENSE_2_MASK 0x00000010 //When set to 1, mutes ih_phy_stat0[4] +#define IH_MUTE_PHY_STAT0_RX_SENSE_3_MASK 0x00000020 //When set to 1, mutes ih_phy_stat0[5] + +//Frame Composer video/audio Force Enable Register This register allows to force the controller to output audio and video data the values configured in the FC_DBGAUD and FC_DBGTMDS registers +#define FC_DBGFORCE 0x00001200 +#define FC_DBGFORCE_FORCEVIDEO_MASK 0x00000001 //Force fixed video output with FC_DBGTMDSx register contents +#define FC_DBGFORCE_FORCEAUDIO_MASK 0x00000010 //Force fixed audio output with FC_DBGAUDxCHx register contents + +#define FC_DBGTMDS0 0x1219 +#define FC_DBGTMDS1 0x121A +#define FC_DBGTMDS2 0x121B + +//Frame Composer Scrambler Control +#define FC_SCRAMBLER_CTRL 0x000010E1 +#define FC_SCRAMBLER_CTRL_SCRAMBLER_ON_MASK 0x00000001 //When set (1'b1), this field activates the HDMI 2 +#define FC_SCRAMBLER_CTRL_SCRAMBLER_UCP_LINE_MASK 0x00000010 //Debug register + +//Main Controller Software Reset Register Main controller software reset request per clock domain +#define MC_SWRSTZREQ 0x0004002 +#define MC_SWRSTZREQ_PIXELSWRST_REQ_MASK 0x00000001 //Pixel software reset request +#define MC_SWRSTZREQ_TMDSSWRST_REQ_MASK 0x00000002 //TMDS software reset request +#define MC_SWRSTZREQ_PREPSWRST_REQ_MASK 0x00000004 //Pixel Repetition software reset request +#define MC_SWRSTZREQ_II2SSWRST_REQ_MASK 0x00000008 //I2S audio software reset request +#define MC_SWRSTZREQ_ISPDIFSWRST_REQ_MASK 0x00000010 //SPDIF audio software reset request +#define MC_SWRSTZREQ_CECSWRST_REQ_MASK 0x00000040 //CEC software reset request +#define MC_SWRSTZREQ_IGPASWRST_REQ_MASK 0x00000080 //GPAUD interface soft reset request + +/* SCDC Registers */ +#define SCDC_SLAVE_ADDRESS 0x54 + +#define SCDC_SINK_VER 0x01 /* sink version */ +#define SCDC_SOURCE_VER 0x02 /* source version */ +#define SCDC_UPDATE_0 0x10 /* Update_0 */ +#define SCDC_UPDATE_0_STATUS 0x1 /* Status update flag */ +#define SCDC_UPDATE_0_CED 0x2 /* Character error update flag */ +#define SCDC_UPDATE_0_RR_TEST 0x4 /* Read request test */ + +#define SCDC_UPDATE_1 0x11 /* Update_1 */ +#define SCDC_UPDATE_RESERVED 0x12 /* 0x12-0x1f - Reserved for Update Related Uses */ +#define SCDC_TMDS_CONFIG 0x20 /* TMDS_Config */ +#define SCDC_SCRAMBLER_STAT 0x21 /* Scrambler_Status */ +#define SCDC_CONFIG_0 0x30 /* Config_0 */ +#define SCDC_CONFIG_RESERVED 0x31 /* 0x31-0x3f - Reserved for configuration */ +#define SCDC_STATUS_FLAG_0 0x40 /* Status_Flag_0 */ +#define SCDC_STATUS_FLAG_1 0x41 /* Status_Flag_1 */ +#define SCDC_STATUS_RESERVED 0x42 /* 0x42-0x4f - Reserved for Status Related Uses */ +#define SCDC_ERR_DET_0_L 0x50 /* Err_Det_0_L */ +#define SCDC_ERR_DET_0_H 0x51 /* Err_Det_0_H */ +#define SCDC_ERR_DET_1_L 0x52 /* Err_Det_1_L */ +#define SCDC_ERR_DET_1_H 0x53 /* Err_Det_1_H */ +#define SCDC_ERR_DET_2_L 0x54 /* Err_Det_2_L */ +#define SCDC_ERR_DET_2_H 0x55 /* Err_Det_2_H */ +#define SCDC_ERR_DET_CHKSUM 0x56 /* Err_Det_Checksum */ +#define SCDC_TEST_CFG_0 0xc0 /* Test_config_0 */ +#define SCDC_TEST_RESERVED 0xc1 /* 0xc1-0xcf - Reserved for test features */ +#define SCDC_MAN_OUI_3RD 0xd0 /* Manufacturer IEEE OUI, Third Octet */ +#define SCDC_MAN_OUI_2ND 0xd1 /* Manufacturer IEEE OUI, Second Octet */ +#define SCDC_MAN_OUI_1ST 0xd2 /* Manufacturer IEEE OUI, First Octet */ +#define SCDC_DEVICE_ID 0xd3 /* 0xd3-0xdd - Device ID */ +#define SCDC_MAN_SPECIFIC 0xde /* 0xde-0xff - ManufacturerSpecific */ + +/***************************************************************************** + * * + * Main Controller Registers * + * * + *****************************************************************************/ + +//Main Controller Synchronous Clock Domain Disable Register +#define MC_CLKDIS 0x0004001 +#define MC_CLKDIS_PIXELCLK_DISABLE_MASK 0x00000001 //Pixel clock synchronous disable signal +#define MC_CLKDIS_TMDSCLK_DISABLE_MASK 0x00000002 //TMDS clock synchronous disable signal +#define MC_CLKDIS_PREPCLK_DISABLE_MASK 0x00000004 //Pixel Repetition clock synchronous disable signal +#define MC_CLKDIS_AUDCLK_DISABLE_MASK 0x00000008 //Audio Sampler clock synchronous disable signal +#define MC_CLKDIS_CSCCLK_DISABLE_MASK 0x00000010 //Color Space Converter clock synchronous disable signal +#define MC_CLKDIS_CECCLK_DISABLE_MASK 0x00000020 //CEC Engine clock synchronous disable signal +#define MC_CLKDIS_HDCPCLK_DISABLE_MASK 0x00000040 //HDCP clock synchronous disable signal + +//Main Controller Software Reset Register Main controller software reset request per clock domain +#define MC_SWRSTZREQ 0x0004002 +#define MC_SWRSTZREQ_PIXELSWRST_REQ_MASK 0x00000001 //Pixel software reset request +#define MC_SWRSTZREQ_TMDSSWRST_REQ_MASK 0x00000002 //TMDS software reset request +#define MC_SWRSTZREQ_PREPSWRST_REQ_MASK 0x00000004 //Pixel Repetition software reset request +#define MC_SWRSTZREQ_II2SSWRST_REQ_MASK 0x00000008 //I2S audio software reset request +#define MC_SWRSTZREQ_ISPDIFSWRST_REQ_MASK 0x00000010 //SPDIF audio software reset request +#define MC_SWRSTZREQ_CECSWRST_REQ_MASK 0x00000040 //CEC software reset request +#define MC_SWRSTZREQ_IGPASWRST_REQ_MASK 0x00000080 //GPAUD interface soft reset request + +//Main Controller HDCP Bypass Control Register +#define MC_OPCTRL 0x0004003 +#define MC_OPCTRL_HDCP_BLOCK_BYP_MASK 0x00000001 //Block HDCP bypass mechanism - 1'b0: This is the default value + +//Main Controller Feed Through Control Register +#define MC_FLOWCTRL 0x0004004 +#define MC_FLOWCTRL_FEED_THROUGH_OFF_MASK 0x00000001 //Video path Feed Through enable bit: - 1b: Color Space Converter is in the video data path + +//Main Controller PHY Reset Register +#define MC_PHYRSTZ 0x0004005 +#define MC_PHYRSTZ_PHYRSTZ_MASK 0x00000001 //HDMI Source PHY active low reset control for PHY GEN1, active high reset control for PHY GEN2 + +//Main Controller Clock Present Register +#define MC_LOCKONCLOCK 0x0004006 +#define MC_LOCKONCLOCK_CECCLK_MASK 0x00000001 //CEC clock status +#define MC_LOCKONCLOCK_AUDIOSPDIFCLK_MASK 0x00000004 //SPDIF clock status +#define MC_LOCKONCLOCK_I2SCLK_MASK 0x00000008 //I2S clock status +#define MC_LOCKONCLOCK_PREPCLK_MASK 0x00000010 //Pixel Repetition clock status +#define MC_LOCKONCLOCK_TCLK_MASK 0x00000020 //TMDS clock status +#define MC_LOCKONCLOCK_PCLK_MASK 0x00000040 //Pixel clock status +#define MC_LOCKONCLOCK_IGPACLK_MASK 0x00000080 //GPAUD interface clock status + +/***************************************************************************** + * * + * Interrupt Registers * + * * + *****************************************************************************/ + +//Frame Composer Interrupt Status Register 0 (Packet Interrupts) +#define IH_FC_STAT0 0x00000100 +#define IH_FC_STAT0_NULL_MASK 0x00000001 //Active after successful transmission of an Null packet +#define IH_FC_STAT0_ACR_MASK 0x00000002 //Active after successful transmission of an Audio Clock Regeneration (N/CTS transmission) packet +#define IH_FC_STAT0_AUDS_MASK 0x00000004 //Active after successful transmission of an Audio Sample packet +#define IH_FC_STAT0_NVBI_MASK 0x00000008 //Active after successful transmission of an NTSC VBI packet +#define IH_FC_STAT0_MAS_MASK 0x00000010 //Active after successful transmission of an MultiStream Audio packet +#define IH_FC_STAT0_HBR_MASK 0x00000020 //Active after successful transmission of an Audio HBR packet +#define IH_FC_STAT0_ACP_MASK 0x00000040 //Active after successful transmission of an Audio Content Protection packet +#define IH_FC_STAT0_AUDI_MASK 0x00000080 //Active after successful transmission of an Audio InfoFrame packet + +//Frame Composer Interrupt Status Register 1 (Packet Interrupts) +#define IH_FC_STAT1 0x00000101 +#define IH_FC_STAT1_GCP_MASK 0x00000001 //Active after successful transmission of an General Control Packet +#define IH_FC_STAT1_AVI_MASK 0x00000002 //Active after successful transmission of an AVI InfoFrame packet +#define IH_FC_STAT1_AMP_MASK 0x00000004 //Active after successful transmission of an Audio Metadata packet +#define IH_FC_STAT1_SPD_MASK 0x00000008 //Active after successful transmission of an Source Product Descriptor InfoFrame packet +#define IH_FC_STAT1_VSD_MASK 0x00000010 //Active after successful transmission of an Vendor Specific Data InfoFrame packet +#define IH_FC_STAT1_ISCR2_MASK 0x00000020 //Active after successful transmission of an International Standard Recording Code 2 packet +#define IH_FC_STAT1_ISCR1_MASK 0x00000040 //Active after successful transmission of an International Standard Recording Code 1 packet +#define IH_FC_STAT1_GMD_MASK 0x00000080 //Active after successful transmission of an Gamut metadata packet + +//Frame Composer Interrupt Status Register 2 (Packet Queue Overflow Interrupts) +#define IH_FC_STAT2 0x00000102 +#define IH_FC_STAT2_HIGHPRIORITY_OVERFLOW_MASK 0x00000001 //Frame Composer high priority packet queue descriptor overflow indication +#define IH_FC_STAT2_LOWPRIORITY_OVERFLOW_MASK 0x00000002 //Frame Composer low priority packet queue descriptor overflow indication + +//Audio Sampler Interrupt Status Register (FIFO Threshold, Underflow and Overflow Interrupts) +#define IH_AS_STAT0 0x00000103 +#define IH_AS_STAT0_AUD_FIFO_OVERFLOW_MASK 0x00000001 //Audio Sampler audio FIFO full indication +#define IH_AS_STAT0_AUD_FIFO_UNDERFLOW_MASK 0x00000002 //Audio Sampler audio FIFO empty indication +#define IH_AS_STAT0_AUD_FIFO_UNDERFLOW_THR_MASK 0x00000004 //Audio Sampler audio FIFO empty threshold (four samples) indication for the legacy HBR audio interface +#define IH_AS_STAT0_FIFO_OVERRUN_MASK 0x00000008 //Indicates an overrun on the audio FIFO + +//PHY Interface Interrupt Status Register (RXSENSE, PLL Lock and HPD Interrupts) +#define IH_PHY_STAT0 0x00000104 +#define IH_PHY_STAT0_HPD_MASK 0x00000001 //HDMI Hot Plug Detect indication +#define IH_PHY_STAT0_TX_PHY_LOCK_MASK 0x00000002 //TX PHY PLL lock indication +#define IH_PHY_STAT0_RX_SENSE_0_MASK 0x00000004 //TX PHY RX_SENSE indication for driver 0 +#define IH_PHY_STAT0_RX_SENSE_1_MASK 0x00000008 //TX PHY RX_SENSE indication for driver 1 +#define IH_PHY_STAT0_RX_SENSE_2_MASK 0x00000010 //TX PHY RX_SENSE indication for driver 2 +#define IH_PHY_STAT0_RX_SENSE_3_MASK 0x00000020 //TX PHY RX_SENSE indication for driver 3 + +//E-DDC I2C Master Interrupt Status Register (Done and Error Interrupts) +#define IH_I2CM_STAT0 0x00000105 +#define IH_I2CM_STAT0_I2CMASTERERROR_MASK 0x00000001 //I2C Master error indication +#define IH_I2CM_STAT0_I2CMASTERDONE_MASK 0x00000002 //I2C Master done indication +#define IH_I2CM_STAT0_SCDC_READREQ_MASK 0x00000004 //I2C Master SCDC read request indication + +//CEC Interrupt Status Register (Functional Operation Interrupts) +#define IH_CEC_STAT0 0x00000106 +#define IH_CEC_STAT0_DONE_MASK 0x00000001 //CEC Done Indication +#define IH_CEC_STAT0_EOM_MASK 0x00000002 //CEC End of Message Indication +#define IH_CEC_STAT0_NACK_MASK 0x00000004 //CEC Not Acknowledge indication +#define IH_CEC_STAT0_ARB_LOST_MASK 0x00000008 //CEC Arbitration Lost indication +#define IH_CEC_STAT0_ERROR_INITIATOR_MASK 0x00000010 //CEC Error Initiator indication +#define IH_CEC_STAT0_ERROR_FOLLOW_MASK 0x00000020 //CEC Error Follow indication +#define IH_CEC_STAT0_WAKEUP_MASK 0x00000040 //CEC Wake-up indication + +//Video Packetizer Interrupt Status Register (FIFO Full and Empty Interrupts) +#define IH_VP_STAT0 0x00000107 +#define IH_VP_STAT0_FIFOEMPTYBYP_MASK 0x00000001 //Video Packetizer 8 bit bypass FIFO empty interrupt +#define IH_VP_STAT0_FIFOFULLBYP_MASK 0x00000002 //Video Packetizer 8 bit bypass FIFO full interrupt +#define IH_VP_STAT0_FIFOEMPTYREMAP_MASK 0x00000004 //Video Packetizer pixel YCC 422 re-mapper FIFO empty interrupt +#define IH_VP_STAT0_FIFOFULLREMAP_MASK 0x00000008 //Video Packetizer pixel YCC 422 re-mapper FIFO full interrupt +#define IH_VP_STAT0_FIFOEMPTYPP_MASK 0x00000010 //Video Packetizer pixel packing FIFO empty interrupt +#define IH_VP_STAT0_FIFOFULLPP_MASK 0x00000020 //Video Packetizer pixel packing FIFO full interrupt +#define IH_VP_STAT0_FIFOEMPTYREPET_MASK 0x00000040 //Video Packetizer pixel repeater FIFO empty interrupt +#define IH_VP_STAT0_FIFOFULLREPET_MASK 0x00000080 //Video Packetizer pixel repeater FIFO full interrupt + +//Interruption Handler Decode Assist Register +#define IH_DECODE 0x00000170 +#define IH_DECODE_IH_AHBDMAAUD_STAT0_MASK 0x00000001 //Interruption active at the ih_ahbdmaaud_stat0 register +#define IH_DECODE_IH_CEC_STAT0_MASK 0x00000002 //Interruption active at the ih_cec_stat0 register +#define IH_DECODE_IH_I2CM_STAT0_MASK 0x00000004 //Interruption active at the ih_i2cm_stat0 register +#define IH_DECODE_IH_PHY_MASK 0x00000008 //Interruption active at the ih_phy_stat0 or ih_i2cmphy_stat0 register +#define IH_DECODE_IH_AS_STAT0_MASK 0x00000010 //Interruption active at the ih_as_stat0 register +#define IH_DECODE_IH_FC_STAT2_VP_MASK 0x00000020 //Interruption active at the ih_fc_stat2 or ih_vp_stat0 register +#define IH_DECODE_IH_FC_STAT1_MASK 0x00000040 //Interruption active at the ih_fc_stat1 register +#define IH_DECODE_IH_FC_STAT0_MASK 0x00000080 //Interruption active at the ih_fc_stat0 register + +//Frame Composer Interrupt Mute Control Register 0 +#define IH_MUTE_FC_STAT0 0x00000180 +#define IH_MUTE_FC_STAT0_NULL_MASK 0x00000001 //When set to 1, mutes ih_fc_stat0[0] +#define IH_MUTE_FC_STAT0_ACR_MASK 0x00000002 //When set to 1, mutes ih_fc_stat0[1] +#define IH_MUTE_FC_STAT0_AUDS_MASK 0x00000004 //When set to 1, mutes ih_fc_stat0[2] +#define IH_MUTE_FC_STAT0_NVBI_MASK 0x00000008 //When set to 1, mutes ih_fc_stat0[3] +#define IH_MUTE_FC_STAT0_MAS_MASK 0x00000010 //When set to 1, mutes ih_fc_stat0[4] +#define IH_MUTE_FC_STAT0_HBR_MASK 0x00000020 //When set to 1, mutes ih_fc_stat0[5] +#define IH_MUTE_FC_STAT0_ACP_MASK 0x00000040 //When set to 1, mutes ih_fc_stat0[6] +#define IH_MUTE_FC_STAT0_AUDI_MASK 0x00000080 //When set to 1, mutes ih_fc_stat0[7] + +//Frame Composer Interrupt Mute Control Register 1 +#define IH_MUTE_FC_STAT1 0x00000181 +#define IH_MUTE_FC_STAT1_GCP_MASK 0x00000001 //When set to 1, mutes ih_fc_stat1[0] +#define IH_MUTE_FC_STAT1_AVI_MASK 0x00000002 //When set to 1, mutes ih_fc_stat1[1] +#define IH_MUTE_FC_STAT1_AMP_MASK 0x00000004 //When set to 1, mutes ih_fc_stat1[2] +#define IH_MUTE_FC_STAT1_SPD_MASK 0x00000008 //When set to 1, mutes ih_fc_stat1[3] +#define IH_MUTE_FC_STAT1_VSD_MASK 0x00000010 //When set to 1, mutes ih_fc_stat1[4] +#define IH_MUTE_FC_STAT1_ISCR2_MASK 0x00000020 //When set to 1, mutes ih_fc_stat1[5] +#define IH_MUTE_FC_STAT1_ISCR1_MASK 0x00000040 //When set to 1, mutes ih_fc_stat1[6] +#define IH_MUTE_FC_STAT1_GMD_MASK 0x00000080 //When set to 1, mutes ih_fc_stat1[7] + +//Frame Composer Interrupt Mute Control Register 2 +#define IH_MUTE_FC_STAT2 0x00000182 +#define IH_MUTE_FC_STAT2_HIGHPRIORITY_OVERFLOW_MASK 0x00000001 //When set to 1, mutes ih_fc_stat2[0] +#define IH_MUTE_FC_STAT2_LOWPRIORITY_OVERFLOW_MASK 0x00000002 //When set to 1, mutes ih_fc_stat2[1] + +//Audio Sampler Interrupt Mute Control Register +#define IH_MUTE_AS_STAT0 0x00000183 +#define IH_MUTE_AS_STAT0_AUD_FIFO_OVERFLOW_MASK 0x00000001 //When set to 1, mutes ih_as_stat0[0] +#define IH_MUTE_AS_STAT0_AUD_FIFO_UNDERFLOW_MASK 0x00000002 //When set to 1, mutes ih_as_stat0[1] +#define IH_MUTE_AS_STAT0_AUD_FIFO_UNDERFLOW_THR_MASK 0x00000004 //When set to 1, mutes ih_as_stat0[2] +#define IH_MUTE_AS_STAT0_FIFO_OVERRUN_MASK 0x00000008 //When set to 1, mutes ih_as_stat0[3] + +//PHY Interface Interrupt Mute Control Register +#define IH_MUTE_PHY_STAT0 0x00000184 +#define IH_MUTE_PHY_STAT0_HPD_MASK 0x00000001 //When set to 1, mutes ih_phy_stat0[0] +#define IH_MUTE_PHY_STAT0_TX_PHY_LOCK_MASK 0x00000002 //When set to 1, mutes ih_phy_stat0[1] +#define IH_MUTE_PHY_STAT0_RX_SENSE_0_MASK 0x00000004 //When set to 1, mutes ih_phy_stat0[2] +#define IH_MUTE_PHY_STAT0_RX_SENSE_1_MASK 0x00000008 //When set to 1, mutes ih_phy_stat0[3] +#define IH_MUTE_PHY_STAT0_RX_SENSE_2_MASK 0x00000010 //When set to 1, mutes ih_phy_stat0[4] +#define IH_MUTE_PHY_STAT0_RX_SENSE_3_MASK 0x00000020 //When set to 1, mutes ih_phy_stat0[5] + +//E-DDC I2C Master Interrupt Mute Control Register +#define IH_MUTE_I2CM_STAT0 0x00000185 +#define IH_MUTE_I2CM_STAT0_I2CMASTERERROR_MASK 0x00000001 //When set to 1, mutes ih_i2cm_stat0[0] +#define IH_MUTE_I2CM_STAT0_I2CMASTERDONE_MASK 0x00000002 //When set to 1, mutes ih_i2cm_stat0[1] +#define IH_MUTE_I2CM_STAT0_SCDC_READREQ_MASK 0x00000004 //When set to 1, mutes ih_i2cm_stat0[2] + +//CEC Interrupt Mute Control Register +#define IH_MUTE_CEC_STAT0 0x00000186 +#define IH_MUTE_CEC_STAT0_DONE_MASK 0x00000001 //When set to 1, mutes ih_cec_stat0[0] +#define IH_MUTE_CEC_STAT0_EOM_MASK 0x00000002 //When set to 1, mutes ih_cec_stat0[1] +#define IH_MUTE_CEC_STAT0_NACK_MASK 0x00000004 //When set to 1, mutes ih_cec_stat0[2] +#define IH_MUTE_CEC_STAT0_ARB_LOST_MASK 0x00000008 //When set to 1, mutes ih_cec_stat0[3] +#define IH_MUTE_CEC_STAT0_ERROR_INITIATOR_MASK 0x00000010 //When set to 1, mutes ih_cec_stat0[4] +#define IH_MUTE_CEC_STAT0_ERROR_FOLLOW_MASK 0x00000020 //When set to 1, mutes ih_cec_stat0[5] +#define IH_MUTE_CEC_STAT0_WAKEUP_MASK 0x00000040 //When set to 1, mutes ih_cec_stat0[6] + +//Video Packetizer Interrupt Mute Control Register +#define IH_MUTE_VP_STAT0 0x00000187 +#define IH_MUTE_VP_STAT0_FIFOEMPTYBYP_MASK 0x00000001 //When set to 1, mutes ih_vp_stat0[0] +#define IH_MUTE_VP_STAT0_FIFOFULLBYP_MASK 0x00000002 //When set to 1, mutes ih_vp_stat0[1] +#define IH_MUTE_VP_STAT0_FIFOEMPTYREMAP_MASK 0x00000004 //When set to 1, mutes ih_vp_stat0[2] +#define IH_MUTE_VP_STAT0_FIFOFULLREMAP_MASK 0x00000008 //When set to 1, mutes ih_vp_stat0[3] +#define IH_MUTE_VP_STAT0_FIFOEMPTYPP_MASK 0x00000010 //When set to 1, mutes ih_vp_stat0[4] +#define IH_MUTE_VP_STAT0_FIFOFULLPP_MASK 0x00000020 //When set to 1, mutes ih_vp_stat0[5] +#define IH_MUTE_VP_STAT0_FIFOEMPTYREPET_MASK 0x00000040 //When set to 1, mutes ih_vp_stat0[6] +#define IH_MUTE_VP_STAT0_FIFOFULLREPET_MASK 0x00000080 //When set to 1, mutes ih_vp_stat0[7] + +//PHY GEN2 I2C Master Interrupt Mute Control Register +#define IH_MUTE_I2CMPHY_STAT0 0x00000188 +#define IH_MUTE_I2CMPHY_STAT0_I2CMPHYERROR_MASK 0x00000001 //When set to 1, mutes ih_i2cmphy_stat0[0] +#define IH_MUTE_I2CMPHY_STAT0_I2CMPHYDONE_MASK 0x00000002 //When set to 1, mutes ih_i2cmphy_stat0[1] + +//AHB Audio DMA Interrupt Mute Control Register +#define IH_MUTE_AHBDMAAUD_STAT0 0x00000189 +#define IH_MUTE_AHBDMAAUD_STAT0_INTBUFFEMPTY_MASK 0x00000001 //When set to 1, mutes ih_ahbdmaaud_stat0[0] +#define IH_MUTE_AHBDMAAUD_STAT0_INTBUFFULL_MASK 0x00000002 //en set to 1, mutes ih_ahbdmaaud_stat0[1] +#define IH_MUTE_AHBDMAAUD_STAT0_INTDONE_MASK 0x00000004 //When set to 1, mutes ih_ahbdmaaud_stat0[2] +#define IH_MUTE_AHBDMAAUD_STAT0_INTINTERTRYSPLIT_MASK 0x00000008 //When set to 1, mutes ih_ahbdmaaud_stat0[3] +#define IH_MUTE_AHBDMAAUD_STAT0_INTLOSTOWNERSHIP_MASK 0x00000010 //When set to 1, mutes ih_ahbdmaaud_stat0[4] +#define IH_MUTE_AHBDMAAUD_STAT0_INTERROR_MASK 0x00000020 //When set to 1, mutes ih_ahbdmaaud_stat0[5] +#define IH_MUTE_AHBDMAAUD_STAT0_INTBUFFOVERRUN_MASK 0x00000040 //When set to 1, mutes ih_ahbdmaaud_stat0[6] + +/***************************************************************************** + * * + * PHY Configuration Registers * + * * + *****************************************************************************/ + //PHY Configuration Register This register holds the power down, data enable polarity, and interface control of the HDMI Source PHY control +#define PHY_CONF0 0x00003000 +#define PHY_CONF0_SELDIPIF_MASK 0x00000001 //Select interface control +#define PHY_CONF0_SELDATAENPOL_MASK 0x00000002 //Select data enable polarity +#define PHY_CONF0_ENHPDRXSENSE_MASK 0x00000004 //PHY ENHPDRXSENSE signal +#define PHY_CONF0_TXPWRON_MASK 0x00000008 //PHY TXPWRON signal +#define PHY_CONF0_PDDQ_MASK 0x00000010 //PHY PDDQ signal +#define PHY_CONF0_SVSRET_MASK 0x00000020 //Reserved as "spare" register with no associated functionality +#define PHY_CONF0_SPARES_1_MASK 0x00000040 //Reserved as "spare" register with no associated functionality +#define PHY_CONF0_SPARES_2_MASK 0x00000080 //Reserved as "spare" register with no associated functionality + +//PHY RXSENSE, PLL Lock, and HPD Status Register This register contains the following active high packet sent status indications +#define PHY_STAT0 0x3004 +#define PHY_STAT0_TX_PHY_LOCK_MASK 0x00000001 //Status bit +#define PHY_STAT0_HPD_MASK 0x00000002 //Status bit +#define PHY_STAT0_RX_SENSE_0_MASK 0x00000010 //Status bit +#define PHY_STAT0_RX_SENSE_1_MASK 0x00000020 //Status bit +#define PHY_STAT0_RX_SENSE_2_MASK 0x00000040 //Status bit +#define PHY_STAT0_RX_SENSE_3_MASK 0x00000080 //Status bit + +//PHY RXSENSE, PLL Lock, and HPD Interrupt Register This register contains the interrupt indication of the PHY_STAT0 status interrupts +#define PHY_INT0 0x3005 +#define PHY_INT0_TX_PHY_LOCK_MASK 0x00000001 //Interrupt indication bit +#define PHY_INT0_HPD_MASK 0x00000002 //Interrupt indication bit +#define PHY_INT0_RX_SENSE_0_MASK 0x00000010 //Interrupt indication bit +#define PHY_INT0_RX_SENSE_1_MASK 0x00000020 //Interrupt indication bit +#define PHY_INT0_RX_SENSE_2_MASK 0x00000040 //Interrupt indication bit +#define PHY_INT0_RX_SENSE_3_MASK 0x00000080 //Interrupt indication bit + +//PHY RXSENSE, PLL Lock, and HPD Mask Register Mask register for generation of PHY_INT0 interrupts +#define PHY_MASK0 0x3006 +#define PHY_MASK0_TX_PHY_LOCK_MASK 0x00000001 //Mask bit for PHY_INT0 +#define PHY_MASK0_HPD_MASK 0x00000002 //Mask bit for PHY_INT0 +#define PHY_MASK0_RX_SENSE_0_MASK 0x00000010 //Mask bit for PHY_INT0 +#define PHY_MASK0_RX_SENSE_1_MASK 0x00000020 //Mask bit for PHY_INT0 +#define PHY_MASK0_RX_SENSE_2_MASK 0x00000040 //Mask bit for PHY_INT0 +#define PHY_MASK0_RX_SENSE_3_MASK 0x00000080 //Mask bit for PHY_INT0 + +//PHY RXSENSE, PLL Lock, and HPD Polarity Register Polarity register for generation of PHY_INT0 interrupts +#define PHY_POL0 0x3007 +#define PHY_POL0_TX_PHY_LOCK_MASK 0x00000001 //Polarity bit for PHY_INT0 +#define PHY_POL0_HPD_MASK 0x00000002 //Polarity bit for PHY_INT0 +#define PHY_POL0_RX_SENSE_0_MASK 0x00000010 //Polarity bit for PHY_INT0 +#define PHY_POL0_RX_SENSE_1_MASK 0x00000020 //Polarity bit for PHY_INT0 +#define PHY_POL0_RX_SENSE_2_MASK 0x00000040 //Polarity bit for PHY_INT0 +#define PHY_POL0_RX_SENSE_3_MASK 0x00000080 //Polarity bit for PHY_INT0 + +//PHY I2C Slave Address Configuration Register +#define PHY_I2CM_SLAVE 0x00003020 +#define PHY_I2CM_SLAVE_SLAVEADDR_MASK 0x0000007F //Slave address to be sent during read and write operations + +//PHY I2C Address Configuration Register This register writes the address for read and write operations +#define PHY_I2CM_ADDRESS 0x00003021 +#define PHY_I2CM_ADDRESS_ADDRESS_MASK 0x000000FF //Register address for read and write operations + +//PHY I2C Data Write Register 1 +#define PHY_I2CM_DATAO_1 0x00003022 +#define PHY_I2CM_DATAO_1_DATAO_MASK 0x000000FF //Data MSB (datao[15:8]) to be written on register pointed by phy_i2cm_address [7:0] + +//PHY I2C Data Write Register 0 +#define PHY_I2CM_DATAO_0 0x00003023 +#define PHY_I2CM_DATAO_0_DATAO_MASK 0x000000FF //Data LSB (datao[7:0]) to be written on register pointed by phy_i2cm_address [7:0] + +//PHY I2C Data Read Register 1 +#define PHY_I2CM_DATAI_1 0x00003024 +#define PHY_I2CM_DATAI_1_DATAI_MASK 0x000000FF //Data MSB (datai[15:8]) read from register pointed by phy_i2cm_address[7:0] + +//PHY I2C Data Read Register 0 +#define PHY_I2CM_DATAI_0 0x00003025 +#define PHY_I2CM_DATAI_0_DATAI_MASK 0x000000FF //Data LSB (datai[7:0]) read from register pointed by phy_i2cm_address[7:0] + +//PHY I2C RD/RD_EXT/WR Operation Register This register requests read and write operations from the I2C Master PHY +#define PHY_I2CM_OPERATION 0x00003026 +#define PHY_I2CM_OPERATION_RD_MASK 0x00000001 //Read operation request +#define PHY_I2CM_OPERATION_WR_MASK 0x00000010 //Write operation request + +//PHY I2C Done Interrupt Register This register contains and configures I2C master PHY done interrupt +#define PHY_I2CM_INT 0x00003027 +#define PHY_I2CM_INT_DONE_STATUS_MASK 0x00000001 //Operation done status bit +#define PHY_I2CM_INT_DONE_INTERRUPT_MASK 0x00000002 //Operation done interrupt bit +#define PHY_I2CM_INT_DONE_MASK_MASK 0x00000004 //Done interrupt mask signal +#define PHY_I2CM_INT_DONE_POL_MASK 0x00000008 //Done interrupt polarity configuration + +//PHY I2C error Interrupt Register This register contains and configures the I2C master PHY error interrupts +#define PHY_I2CM_CTLINT 0x00003028 +#define PHY_I2CM_CTLINT_ARBITRATION_STATUS_MASK 0x00000001 //Arbitration error status bit +#define PHY_I2CM_CTLINT_ARBITRATION_INTERRUPT_MASK 0x00000002 //Arbitration error interrupt bit {arbitration_interrupt = (arbitration_mask==0b) && (arbitration_status==arbitration_pol)} Note: This bit field is read by the sticky bits present on the ih_i2cmphy_stat0 register +#define PHY_I2CM_CTLINT_ARBITRATION_MASK_MASK 0x00000004 //Arbitration error interrupt mask signal +#define PHY_I2CM_CTLINT_ARBITRATION_POL_MASK 0x00000008 //Arbitration error interrupt polarity configuration +#define PHY_I2CM_CTLINT_NACK_STATUS_MASK 0x00000010 //Not acknowledge error status bit +#define PHY_I2CM_CTLINT_NACK_INTERRUPT_MASK 0x00000020 //Not acknowledge error interrupt bit +#define PHY_I2CM_CTLINT_NACK_MASK_MASK 0x00000040 //Not acknowledge error interrupt mask signal +#define PHY_I2CM_CTLINT_NACK_POL_MASK 0x00000080 //Not acknowledge error interrupt polarity configuration + +//PHY I2C Speed control Register This register wets the I2C Master PHY to work in either Fast or Standard mode +#define PHY_I2CM_DIV 0x00003029 +#define PHY_I2CM_DIV_SPARE_MASK 0x00000007 //Reserved as "spare" register with no associated functionality +#define PHY_I2CM_DIV_FAST_STD_MODE_MASK 0x00000008 //Sets the I2C Master to work in Fast Mode or Standard Mode: 1: Fast Mode 0: Standard Mode + +//PHY I2C SW reset control register This register sets the I2C Master PHY software reset +#define PHY_I2CM_SOFTRSTZ 0x0000302A +#define PHY_I2CM_SOFTRSTZ_I2C_SOFTRSTZ_MASK 0x00000001 //I2C Master Software Reset + +//PHY GEN2 I2C Master Interrupt Status Register (Done and Error Interrupts) +#define IH_I2CMPHY_STAT0 0x00000108 +#define IH_I2CMPHY_STAT0_I2CMPHYERROR_MASK 0x00000001 //I2C Master PHY error indication +#define IH_I2CMPHY_STAT0_I2CMPHYDONE_MASK 0x00000002 //I2C Master PHY done indication + +//Main Controller PHY Reset Register +#define MC_PHYRSTZ 0x0004005 +#define MC_PHYRSTZ_PHYRSTZ_MASK 0x00000001 //HDMI Source PHY active low reset control for PHY GEN1, active high reset control for PHY GEN2 + +//PHY I2C/JTAG I/O Configuration Control Register +#define JTAG_PHY_CONFIG 0x00003034 +#define JTAG_PHY_CONFIG_JTAG_TRST_N_MASK 0x00000001 //Configures the JTAG PHY interface output pin JTAG_TRST_N when in internal control mode (iphy_ext_ctrl=1'b0) or ophyext_jtag_trst_n when PHY_EXTERNAL=1 +#define JTAG_PHY_CONFIG_I2C_JTAGZ_MASK 0x00000010 //Configures the JTAG PHY interface output pin I2C_JTAGZ to select the PHY configuration interface when in internal control mode (iphy_ext_ctrl=1'b0) or ophyext_jtag_i2c_jtagz when PHY_EXTERNAL=1 + +/***************************************************************************** + * * + * Audio Sample Registers * + * * + *****************************************************************************/ + +//Audio I2S Software FIFO Reset, Select, and Enable Control Register 0 This register configures the I2S input enable that indicates which input I2S channels have valid data +#define AUD_CONF0 0x00003100 +#define AUD_CONF0_I2S_IN_EN_MASK 0x0000000F //Action I2S_in_en[0] - I2Sdata[0] enable I2S_in_en[1] - I2Sdata[1] enable I2S_in_en[2] - I2Sdata[2] enable I2S_in_en[3] - I2Sdata[3] enable +#define AUD_CONF0_SPARE_1_MASK 0x00000010 //This field is a "spare" bit with no associated functionality +#define AUD_CONF0_I2S_SELECT_MASK 0x00000020 //1b: Selects I2S Audio Interface 0b: Selects the second (SPDIF/GPA) interface, in configurations with more that one audio interface (DOUBLE/GDOUBLE) +#define AUD_CONF0_SPARE_2_MASK 0x00000040 //This field is a "spare" bit with no associated functionality +#define AUD_CONF0_SW_AUDIO_FIFO_RST_MASK 0x00000080 //Audio FIFOs software reset - Writing 0b: no action taken - Writing 1b: Resets all audio FIFOs Reading from this register always returns 0b + +//Audio I2S Width and Mode Configuration Register 1 This register configures the I2S mode and data width of the input data +#define AUD_CONF1 0x00003101 +#define AUD_CONF1_I2S_WIDTH_MASK 0x0000001F //I2S input data width I2S_width[4:0] | Action 00000b-01111b | Not used 10000b | 16 bit data samples at input 10001b | 17 bit data samples at input 10010b | 18 bit data samples at input 10011b | 19 bit data samples at input 10100b | 20 bit data samples at input 10101b | 21 bit data samples at input 10110b | 22 bit data samples at input 10111b | 23 bit data samples at input 11000b | 24 bit data samples at input 11001b-11111b | Not Used +//I2S input data mode I2S_mode[4:0] | Action +// 000b | Standard I2S mode +// 001b | Right-justified I2S mode +// 010b | Left-justified I2S mode +// 011b | Burst 1 mode +// 100b | Burst 2 mode +#define AUD_CONF1_I2S_MODE_MASK 0x000000E0 +//I2S FIFO status and interrupts +#define AUD_INT 0x00003102 +#define AUD_INT_FIFO_FULL_MASK_MASK 0x00000004 //FIFO full mask +#define AUD_INT_FIFO_EMPTY_MASK_MASK 0x00000008 //FIFO empty mask + +//Audio I2S NLPCM and HBR configuration Register 2 This register configures the I2S Audio Data mapping +#define AUD_CONF2 0x00003103 +#define AUD_CONF2_HBR_MASK 0x00000001 //I2S HBR Mode Enable +#define AUD_CONF2_NLPCM_MASK 0x00000002 //I2S NLPCM Mode Enable + +//I2S Mask Interrupt Register This register masks the interrupts present in the I2S module +#define AUD_INT1 0x00003104 +#define AUD_INT1_FIFO_OVERRUN_MASK_MASK 0x00000010 //FIFO overrun mask + +//Audio SPDIF FIFO Empty/Full Mask Register +#define AUD_SPDIFINT 0x00003302 +#define AUD_SPDIFINT_SPDIF_FIFO_FULL_MASK_MASK 0x00000004 //SPDIF FIFO full mask +#define AUD_SPDIFINT_SPDIF_FIFO_EMPTY_MASK_MASK 0x00000008 //SPDIF FIFO empty mask + +/***************************************************************************** + * * + * Frame Composer Registers * + * * + *****************************************************************************/ + +//Frame Composer Input Video Configuration and HDCP Keepout Register +#define FC_INVIDCONF 0x00001000 +#define FC_INVIDCONF_IN_I_P_MASK 0x00000001 //Input video mode: 1b: Interlaced 0b: Progressive +#define FC_INVIDCONF_R_V_BLANK_IN_OSC_MASK 0x00000002 //Used for CEA861-D modes with fractional Vblank (for example, modes 5, 6, 7, 10, 11, 20, 21, and 22) +#define FC_INVIDCONF_DVI_MODEZ_MASK 0x00000008 //Active low 0b: DVI mode selected 1b: HDMI mode selected +#define FC_INVIDCONF_DE_IN_POLARITY_MASK 0x00000010 //Data enable input polarity 1b: Active high 0b: Active low +#define FC_INVIDCONF_HSYNC_IN_POLARITY_MASK 0x00000020 //Hsync input polarity 1b: Active high 0b: Active low +#define FC_INVIDCONF_VSYNC_IN_POLARITY_MASK 0x00000040 //Vsync input polarity 1b: Active high 0b: Active low +#define FC_INVIDCONF_HDCP_KEEPOUT_MASK 0x00000080 //Start/stop HDCP keepout window generation 1b: Active + +//Frame Composer Input Video HActive Pixels Register 0 +#define FC_INHACTIV0 0x00001001 +#define FC_INHACTIV0_H_IN_ACTIV_MASK 0x000000FF //Input video Horizontal active pixel region width + +//Frame Composer Input Video HActive Pixels Register 1 +#define FC_INHACTIV1 0x00001002 +#define FC_INHACTIV1_H_IN_ACTIV_MASK 0x0000000F //Input video Horizontal active pixel region width +#define FC_INHACTIV1_H_IN_ACTIV_12_MASK 0x00000010 //Input video Horizontal active pixel region width (0 +#define FC_INHACTIV1_H_IN_ACTIV_13_MASK 0x00000020 //Input video Horizontal active pixel region width (0 + +//Frame Composer Input Video HBlank Pixels Register 0 +#define FC_INHBLANK0 0x00001003 +#define FC_INHBLANK0_H_IN_BLANK_MASK 0x000000FF //Input video Horizontal blanking pixel region width + +//Frame Composer Input Video HBlank Pixels Register 1 +#define FC_INHBLANK1 0x00001004 +#define FC_INHBLANK1_H_IN_BLANK_MASK 0x00000003 //Input video Horizontal blanking pixel region width this bit field holds bits 9:8 of number of Horizontal blanking pixels +#define FC_INHBLANK1_H_IN_BLANK_12_MASK 0x0000001C //Input video Horizontal blanking pixel region width If configuration parameter DWC_HDMI_TX_14 = True (1), this bit field holds bit 12:10 of number of horizontal blanking pixels + +//Frame Composer Input Video VActive Pixels Register 0 +#define FC_INVACTIV0 0x00001005 +#define FC_INVACTIV0_V_IN_ACTIV_MASK 0x000000FF //Input video Vertical active pixel region width + +//Frame Composer Input Video VActive Pixels Register 1 +#define FC_INVACTIV1 0x00001006 +#define FC_INVACTIV1_V_IN_ACTIV_MASK 0x00000007 //Input video Vertical active pixel region width +#define FC_INVACTIV1_V_IN_ACTIV_12_11_MASK 0x00000018 //Input video Vertical active pixel region width + +//Frame Composer Input Video VBlank Pixels Register +#define FC_INVBLANK 0x00001007 +#define FC_INVBLANK_V_IN_BLANK_MASK 0x000000FF //Input video Vertical blanking pixel region width + +//Frame Composer Input Video HSync Front Porch Register 0 +#define FC_HSYNCINDELAY0 0x00001008 +#define FC_HSYNCINDELAY0_H_IN_DELAY_MASK 0x000000FF //Input video Hsync active edge delay + +//Frame Composer Input Video HSync Front Porch Register 1 +#define FC_HSYNCINDELAY1 0x00001009 +#define FC_HSYNCINDELAY1_H_IN_DELAY_MASK 0x00000007 //Input video Horizontal active edge delay +#define FC_HSYNCINDELAY1_H_IN_DELAY_12_MASK 0x00000018 //Input video Horizontal active edge delay + +//Frame Composer Input Video HSync Width Register 0 +#define FC_HSYNCINWIDTH0 0x0000100a +#define FC_HSYNCINWIDTH0_H_IN_WIDTH_MASK 0x000000FF //Input video Hsync active pulse width + +//Frame Composer Input Video HSync Width Register 1 +#define FC_HSYNCINWIDTH1 0x0000100b +#define FC_HSYNCINWIDTH1_H_IN_WIDTH_MASK 0x00000001 //Input video Hsync active pulse width +#define FC_HSYNCINWIDTH1_H_IN_WIDTH_9_MASK 0x00000002 //Input video Hsync active pulse width + +//Frame Composer Input Video VSync Front Porch Register +#define FC_VSYNCINDELAY 0x0000100c +#define FC_VSYNCINDELAY_V_IN_DELAY_MASK 0x000000FF //Input video Vsync active edge delay + +//Frame Composer Input Video VSync Width Register +#define FC_VSYNCINWIDTH 0x0000100d +#define FC_VSYNCINWIDTH_V_IN_WIDTH_MASK 0x0000003F //Input video Vsync active pulse width + +//Frame Composer Input Video Refresh Rate Register 0 +#define FC_INFREQ0 0x0000100e +#define FC_INFREQ0_INFREQ_MASK 0x000000FF //Video refresh rate in Hz*1E3 format + +//Frame Composer Input Video Refresh Rate Register 1 +#define FC_INFREQ1 0x0000100f +#define FC_INFREQ1_INFREQ_MASK 0x000000FF //Video refresh rate in Hz*1E3 format + +//Frame Composer Input Video Refresh Rate Register 2 +#define FC_INFREQ2 0x00001010 +#define FC_INFREQ2_INFREQ_MASK 0x0000000F //Video refresh rate in Hz*1E3 format + +//Frame Composer Control Period Duration Register +#define FC_CTRLDUR 0x00001011 +#define FC_CTRLDUR_CTRLPERIODDURATION_MASK 0x000000FF //Configuration of the control period minimum duration (minimum of 12 pixel clock cycles; refer to HDMI 1 + +//Frame Composer Extended Control Period Duration Register +#define FC_EXCTRLDUR 0x00001012 +#define FC_EXCTRLDUR_EXCTRLPERIODDURATION_MASK 0x000000FF //Configuration of the extended control period minimum duration (minimum of 32 pixel clock cycles; refer to HDMI 1 + +//Frame Composer Extended Control Period Maximum Spacing Register +#define FC_EXCTRLSPAC 0x00001013 +#define FC_EXCTRLSPAC_EXCTRLPERIODSPACING_MASK 0x000000FF //Configuration of the maximum spacing between consecutive extended control periods (maximum of 50ms; refer to the applicable HDMI specification) + +//Frame Composer Channel 0 Non-Preamble Data Register +#define FC_CH0PREAM 0x00001014 +#define FC_CH0PREAM_CH0_PREAMBLE_FILTER_MASK 0x000000FF //When in control mode, configures 8 bits that fill the channel 0 data lines not used to transmit the preamble (for more clarification, refer to the HDMI 1 + +//Frame Composer Channel 1 Non-Preamble Data Register +#define FC_CH1PREAM 0x00001015 +#define FC_CH1PREAM_CH1_PREAMBLE_FILTER_MASK 0x0000003F //When in control mode, configures 6 bits that fill the channel 1 data lines not used to transmit the preamble (for more clarification, refer to the HDMI 1 + +//Frame Composer Channel 2 Non-Preamble Data Register +#define FC_CH2PREAM 0x00001016 +#define FC_CH2PREAM_CH2_PREAMBLE_FILTER_MASK 0x0000003F //When in control mode, configures 6 bits that fill the channel 2 data lines not used to transmit the preamble (for more clarification, refer to the HDMI 1 + +//Frame Composer AVI Packet Configuration Register 3 +#define FC_AVICONF3 0x00001017 +#define FC_AVICONF3_CN_MASK 0x00000003 //IT content type according to CEA the specification +#define FC_AVICONF3_YQ_MASK 0x0000000C //YCC Quantization range according to the CEA specification + +//Frame Composer GCP Packet Configuration Register +#define FC_GCP 0x00001018 +#define FC_GCP_CLEAR_AVMUTE_MASK 0x00000001 //Value of "clear_avmute" in the GCP packet +#define FC_GCP_SET_AVMUTE_MASK 0x00000002 //Value of "set_avmute" in the GCP packet Once the AVmute is set, the frame composer schedules the GCP packet with AVmute set in the packet scheduler to be sent once (may only be transmitted between the active edge of VSYNC and 384 pixels following this edge) +#define FC_GCP_DEFAULT_PHASE_MASK 0x00000004 //Value of "default_phase" in the GCP packet + +//Frame Composer AVI Packet Configuration Register 0 +#define FC_AVICONF0 0x00001019 +#define FC_AVICONF0_RGC_YCC_INDICATION_MASK 0x00000003 //Y1,Y0 RGB or YCC indicator +#define FC_AVICONF0_BAR_INFORMATION_MASK 0x0000000C //Bar information data valid +#define FC_AVICONF0_SCAN_INFORMATION_MASK 0x00000030 //Scan information +#define FC_AVICONF0_ACTIVE_FORMAT_PRESENT_MASK 0x00000040 //Active format present +#define FC_AVICONF0_RGC_YCC_INDICATION_2_MASK 0x00000080 //Y2, Bit 2 of rgc_ycc_indication + +//Frame Composer AVI Packet Configuration Register 1 +#define FC_AVICONF1 0x0000101a +#define FC_AVICONF1_ACTIVE_ASPECT_RATIO_MASK 0x0000000F //Active aspect ratio +#define FC_AVICONF1_PICTURE_ASPECT_RATIO_MASK 0x00000030 //Picture aspect ratio +#define FC_AVICONF1_COLORIMETRY_MASK 0x000000C0 //Colorimetry + +//Frame Composer AVI Packet Configuration Register 2 +#define FC_AVICONF2 0x0000101b +#define FC_AVICONF2_NON_UNIFORM_PICTURE_SCALING_MASK 0x00000003 //Non-uniform picture scaling +#define FC_AVICONF2_QUANTIZATION_RANGE_MASK 0x0000000C //Quantization range +#define FC_AVICONF2_EXTENDED_COLORIMETRY_MASK 0x00000070 //Extended colorimetry +#define FC_AVICONF2_IT_CONTENT_MASK 0x00000080 //IT content + +//Frame Composer AVI Packet VIC Register +#define FC_AVIVID 0x0000101c +#define FC_AVIVID_FC_AVIVID_MASK 0x0000007F //Configures the AVI InfoFrame Video Identification code +#define FC_AVIVID_FC_AVIVID_7_MASK 0x00000080 //Bit 7 of fc_avivid register + +#define FC_AVIETB0 0x101d +#define FC_AVIETB1 0x101e +#define FC_AVISBB0 0x101f +#define FC_AVISBB1 0x1020 +#define FC_AVIELB0 0x1021 +#define FC_AVIELB1 0x1022 +#define FC_AVISRB0 0x1023 +#define FC_AVISRB1 0x1024 + +//Frame Composer AUD Packet Configuration Register 0 +#define FC_AUDICONF0 0x00001025 +#define FC_AUDICONF0_CT_MASK 0x0000000F //Coding Type +#define FC_AUDICONF0_CC_MASK 0x00000070 //Channel count + +//Frame Composer AUD Packet Configuration Register 1 +#define FC_AUDICONF1 0x00001026 +#define FC_AUDICONF1_SF_MASK 0x00000007 //Sampling frequency +#define FC_AUDICONF1_SS_MASK 0x00000030 //Sampling size + +//Frame Composer AUD Packet Configuration Register 2 +#define FC_AUDICONF2 0x00001027 +#define FC_AUDICONF2_CA_MASK 0x000000FF //Channel allocation + +//Frame Composer AUD Packet Configuration Register 0 +#define FC_AUDICONF3 0x00001028 +#define FC_AUDICONF3_LSV_MASK 0x0000000F //Level shift value (for down mixing) +#define FC_AUDICONF3_DM_INH_MASK 0x00000010 //Down mix enable +#define FC_AUDICONF3_LFEPBL_MASK 0x00000060 //LFE playback information LFEPBL1, LFEPBL0 LFE playback level as compared to the other channels + +//Frame Composer Audio Sample Flat and Layout Configuration Register +#define FC_AUDSCONF 0x00001063 +#define FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK 0x00000001 //Set the audio packet layout to be sent in the packet: 1b: layout 1 0b: layout 0 If DWC_HDMI_TX_20 is defined and register field fc_multistream_ctrl +#define FC_AUDSCONF_AUD_PACKET_SAMPFLT_MASK 0x000000F0 //Set the audio packet sample flat value to be sent on the packet + +//Frame Composer Audio Sample Channel Status Configuration Register 0 +#define FC_AUDSCHNL0 0x00001067 +#define FC_AUDSCHNL0_OIEC_COPYRIGHT_MASK 0x00000001 //IEC Copyright indication +#define FC_AUDSCHNL0_OIEC_CGMSA_MASK 0x00000030 //CGMS-A + +//Frame Composer Audio Sample Channel Status Configuration Register 1 +#define FC_AUDSCHNL1 0x00001068 +#define FC_AUDSCHNL1_OIEC_CATEGORYCODE_MASK 0x000000FF //Category code + +//Frame Composer Audio Sample Channel Status Configuration Register 2 +#define FC_AUDSCHNL2 0x00001069 +#define FC_AUDSCHNL2_OIEC_SOURCENUMBER_MASK 0x0000000F //Source number +#define FC_AUDSCHNL2_OIEC_PCMAUDIOMODE_MASK 0x00000070 //PCM audio mode + +//Frame Composer Audio Sample Channel Status Configuration Register 3 +#define FC_AUDSCHNL3 0x0000106a +#define FC_AUDSCHNL3_OIEC_CHANNELNUMCR0_MASK 0x0000000F //Channel number for first right sample +#define FC_AUDSCHNL3_OIEC_CHANNELNUMCR1_MASK 0x000000F0 //Channel number for second right sample + +//Frame Composer Audio Sample Channel Status Configuration Register 4 +#define FC_AUDSCHNL4 0x0000106b +#define FC_AUDSCHNL4_OIEC_CHANNELNUMCR2_MASK 0x0000000F //Channel number for third right sample +#define FC_AUDSCHNL4_OIEC_CHANNELNUMCR3_MASK 0x000000F0 //Channel number for fourth right sample + +//Frame Composer Audio Sample Channel Status Configuration Register 5 +#define FC_AUDSCHNL5 0x0000106c +#define FC_AUDSCHNL5_OIEC_CHANNELNUMCL0_MASK 0x0000000F //Channel number for first left sample +#define FC_AUDSCHNL5_OIEC_CHANNELNUMCL1_MASK 0x000000F0 //Channel number for second left sample + +//Frame Composer Audio Sample Channel Status Configuration Register 6 +#define FC_AUDSCHNL6 0x0000106d +#define FC_AUDSCHNL6_OIEC_CHANNELNUMCL2_MASK 0x0000000F //Channel number for third left sample +#define FC_AUDSCHNL6_OIEC_CHANNELNUMCL3_MASK 0x000000F0 //Channel number for fourth left sample + +//Frame Composer Audio Sample Channel Status Configuration Register 7 +#define FC_AUDSCHNL7 0x0000106e +#define FC_AUDSCHNL7_OIEC_SAMPFREQ_MASK 0x0000000F //Sampling frequency +#define FC_AUDSCHNL7_OIEC_CLKACCURACY_MASK 0x00000030 //Clock accuracy +#define FC_AUDSCHNL7_OIEC_SAMPFREQ_EXT_MASK 0x000000C0 //Sampling frequency (channel status bits 31 and 30) + +//Frame Composer Audio Sample Channel Status Configuration Register 8 +#define FC_AUDSCHNL8 0x0000106f +#define FC_AUDSCHNL8_OIEC_WORDLENGTH_MASK 0x0000000F //Word length configuration +#define FC_AUDSCHNL8_OIEC_ORIGSAMPFREQ_MASK 0x000000F0 //Original sampling frequency + +/***************************************************************************** + * * + * Audio Packetizer Registers * + * * + *****************************************************************************/ + +//Audio Clock Regenerator N Value Register 1 For N expected values, refer to the HDMI 1 +#define AUD_N1 0x00003200 +#define AUD_N1_AUDN_MASK 0x000000FF //HDMI Audio Clock Regenerator N value + +//Audio Clock Regenerator N Value Register 2 For N expected values, refer to the HDMI 1 +#define AUD_N2 0x00003201 +#define AUD_N2_AUDN_MASK 0x000000FF //HDMI Audio Clock Regenerator N value + +//Audio Clock Regenerator N Value Register 3 For N expected values, refer to the HDMI 1 +#define AUD_N3 0x00003202 +#define AUD_N3_AUDN_MASK 0x0000000F //HDMI Audio Clock Regenerator N value +#define AUD_N3_NCTS_ATOMIC_WRITE_MASK 0x00000080 //When set, the new N and CTS values are only used when aud_n1 register is written + +//Audio Clock Regenerator CTS Value Register 1 For CTS expected values, refer to the HDMI 1 +#define AUD_CTS1 0x00003203 +#define AUD_CTS1_AUDCTS_MASK 0x000000FF //HDMI Audio Clock Regenerator CTS calculated value + +//Audio Clock Regenerator CTS Register 2 For CTS expected values, refer to the HDMI 1 +#define AUD_CTS2 0x00003204 +#define AUD_CTS2_AUDCTS_MASK 0x000000FF //HDMI Audio Clock Regenerator CTS calculated value + +//Audio Clock Regenerator CTS value Register 3 +#define AUD_CTS3 0x00003205 +#define AUD_CTS3_AUDCTS_MASK 0x0000000F //HDMI Audio Clock Regenerator CTS calculated value +#define AUD_CTS3_CTS_MANUAL_MASK 0x00000010 //If the CTS_manual bit equals 0b, this registers contains audCTS[19:0] generated by the Cycle time counter according to the specified timing +#define AUD_CTS3_N_SHIFT_MASK 0x000000E0 //N_shift factor configuration: N_shift | Shift Factor | Action 0 | 1 | This is the N shift factor used for the case that N' ="audN[19:0]" + +//Audio Input Clock FS Factor Register +#define AUD_INPUTCLKFS 0x00003206 +#define AUD_INPUTCLKFS_IFSFACTOR_MASK 0x00000007 //Fs factor configuration: ifsfactor[2:0] | Audio Clock | Action 0 | 128xFs | If you select the Bypass SPDIF DRU unit in coreConsultant, the input audio clock (either I2S or SPDIF according to configuration) is used at the audio packetizer to calculate the CTS value and ACR packet insertion rate + +/***************************************************************************** + * * + * E-DDC Registers * + * * + *****************************************************************************/ + +//I2C DDC Slave address Configuration Register +#define I2CM_SLAVE 0x7E00 +#define I2CM_SLAVE_SLAVEADDR_MASK 0x0000007F //Slave address to be sent during read and write normal operations + +//I2C DDC Address Configuration Register +#define I2CM_ADDRESS 0x7E01 +#define I2CM_ADDRESS_ADDRESS_MASK 0x000000FF //Register address for read and write operations + +//I2C DDC Data Write Register +#define I2CM_DATAO 0x7E02 +#define I2CM_DATAO_DATAO_MASK 0x000000FF //Data to be written on register pointed by address[7:0] + +//I2C DDC Data read Register +#define I2CM_DATAI 0x7E03 +#define I2CM_DATAI_DATAI_MASK 0x000000FF //Data read from register pointed by address[7:0] + +//I2C DDC RD/RD_EXT/WR Operation Register Read and write operation request +#define I2CM_OPERATION 0x7E04 +#define I2CM_OPERATION_RD_MASK 0x00000001 //Single byte read operation request +#define I2CM_OPERATION_RD_EXT_MASK 0x00000002 //After writing 1'b1 to rd_ext bit a extended data read operation is started (E-DDC read operation) +#define I2CM_OPERATION_RD8_MASK 0x00000004 //Sequential read operation request +#define I2CM_OPERATION_RD8_EXT_MASK 0x00000008 //Extended sequential read operation request +#define I2CM_OPERATION_WR_MASK 0x00000010 //Single byte write operation request +#define I2CM_OPERATION_BUSCLEAR_MASK 0x00000020 //Single byte write operation request + +//I2C DDC Done Interrupt Register This register configures the I2C master interrupts +#define I2CM_INT 0x7E05 +#define I2CM_INT_DONE_MASK 0x00000004 //Done interrupt mask signal +#define I2CM_INT_READ_REQ_MASK 0x00000040 //Read request interruption mask signal + +//I2C DDC error Interrupt Register This register configures the I2C master arbitration lost and not acknowledge error interrupts +#define I2CM_CTLINT 0x7E06 +#define I2CM_CTLINT_ARBITRATION_MASK 0x00000004 //Arbitration error interrupt mask signal +#define I2CM_CTLINT_NACK_MASK 0x00000040 //Not acknowledge error interrupt mask signal + +//I2C DDC Speed Control Register This register configures the division relation between master and scl clock +#define I2CM_DIV 0x7E07 +#define I2CM_DIV_SPARE_MASK 0x00000007 //This bit is a spare register with no associated functionality +#define I2CM_DIV_FAST_STD_MODE_MASK 0x00000008 //Sets the I2C Master to work in Fast Mode or Standard Mode: 1: Fast Mode 0: Standard Mode + +//I2C DDC Segment Address Configuration Register This register configures the segment address for extended R/W destination and is used for EDID reading operations, particularly for the Extended Data Read Operation for Enhanced DDC +#define I2CM_SEGADDR 0x7E08 +#define I2CM_SEGADDR_SEG_ADDR_MASK 0x0000007F //I2C DDC Segment Address Configuration Register + +//I2C DDC Software Reset Control Register This register resets the I2C master +#define I2CM_SOFTRSTZ 0x7E09 +#define I2CM_SOFTRSTZ_I2C_SOFTRSTZ_MASK 0x00000001 //I2C Master Software Reset + +//I2C DDC Segment Pointer Register This register configures the segment pointer for extended RD/WR request +#define I2CM_SEGPTR 0x7E0A +#define I2CM_SEGPTR_SEGPTR_MASK 0x000000FF //I2C DDC Segment Pointer Register + +//I2C DDC Slow Speed SCL High Level Control Register 1 +#define I2CM_SS_SCL_HCNT_1_ADDR 0x7E0B +#define I2CM_SS_SCL_HCNT_1_ADDR_I2CMP_SS_SCL_HCNT1_MASK 0x000000FF //I2C DDC Slow Speed SCL High Level Control Register 1 + +//I2C DDC Slow Speed SCL High Level Control Register 0 +#define I2CM_SS_SCL_HCNT_0_ADDR 0x7E0C +#define I2CM_SS_SCL_HCNT_0_ADDR_I2CMP_SS_SCL_HCNT0_MASK 0x000000FF //I2C DDC Slow Speed SCL High Level Control Register 0 + +//I2C DDC Slow Speed SCL Low Level Control Register 1 +#define I2CM_SS_SCL_LCNT_1_ADDR 0x7E0D +#define I2CM_SS_SCL_LCNT_1_ADDR_I2CMP_SS_SCL_LCNT1_MASK 0x000000FF //I2C DDC Slow Speed SCL Low Level Control Register 1 + +//I2C DDC Slow Speed SCL Low Level Control Register 0 +#define I2CM_SS_SCL_LCNT_0_ADDR 0x7E0E +#define I2CM_SS_SCL_LCNT_0_ADDR_I2CMP_SS_SCL_LCNT0_MASK 0x000000FF //I2C DDC Slow Speed SCL Low Level Control Register 0 + +//I2C DDC Fast Speed SCL High Level Control Register 1 +#define I2CM_FS_SCL_HCNT_1_ADDR 0x7E0F +#define I2CM_FS_SCL_HCNT_1_ADDR_I2CMP_FS_SCL_HCNT1_MASK 0x000000FF //I2C DDC Fast Speed SCL High Level Control Register 1 + +//I2C DDC Fast Speed SCL High Level Control Register 0 +#define I2CM_FS_SCL_HCNT_0_ADDR 0x7E10 +#define I2CM_FS_SCL_HCNT_0_ADDR_I2CMP_FS_SCL_HCNT0_MASK 0x000000FF //I2C DDC Fast Speed SCL High Level Control Register 0 + +//I2C DDC Fast Speed SCL Low Level Control Register 1 +#define I2CM_FS_SCL_LCNT_1_ADDR 0x7E11 +#define I2CM_FS_SCL_LCNT_1_ADDR_I2CMP_FS_SCL_LCNT1_MASK 0x000000FF //I2C DDC Fast Speed SCL Low Level Control Register 1 + +//I2C DDC Fast Speed SCL Low Level Control Register 0 +#define I2CM_FS_SCL_LCNT_0_ADDR 0x7E12 +#define I2CM_FS_SCL_LCNT_0_ADDR_I2CMP_FS_SCL_LCNT0_MASK 0x000000FF //I2C DDC Fast Speed SCL Low Level Control Register 0 + +//I2C DDC SDA Hold Register +#define I2CM_SDA_HOLD 0x7E13 +#define I2CM_SDA_HOLD_OSDA_HOLD_MASK 0x000000FF //Defines the number of SFR clock cycles to meet tHD;DAT (300 ns) osda_hold = round_to_high_integer (300 ns / (1 / isfrclk_frequency)) + +//SCDC Control Register This register configures the SCDC update status read through the I2C master interface +#define I2CM_SCDC_READ_UPDATE 0x7E14 +#define I2CM_SCDC_READ_UPDATE_READ_UPDATE_MASK 0x00000001 //When set to 1'b1, a SCDC Update Read is performed and the read data loaded into registers i2cm_scdc_update0 and i2cm_scdc_update1 +#define I2CM_SCDC_READ_UPDATE_READ_REQUEST_EN_MASK 0x00000010 //Read request enabled +#define I2CM_SCDC_READ_UPDATE_UPDTRD_VSYNCPOLL_EN_MASK 0x00000020 //Update read polling enabled + +//I2C Master Sequential Read Buffer Register 0 +#define I2CM_READ_BUFF0 0x7E20 +#define I2CM_READ_BUFF0_I2CM_READ_BUFF0_MASK 0x000000FF //Byte 0 of a I2C read buffer sequential read (from address i2cm_address) + +//I2C Master Sequential Read Buffer Register 1 +#define I2CM_READ_BUFF1 0x7E21 +#define I2CM_READ_BUFF1_I2CM_READ_BUFF1_MASK 0x000000FF //Byte 1 of a I2C read buffer sequential read (from address i2cm_address+1) + +//I2C Master Sequential Read Buffer Register 2 +#define I2CM_READ_BUFF2 0x7E22 +#define I2CM_READ_BUFF2_I2CM_READ_BUFF2_MASK 0x000000FF //Byte 2 of a I2C read buffer sequential read (from address i2cm_address+2) + +//I2C Master Sequential Read Buffer Register 3 +#define I2CM_READ_BUFF3 0x7E23 +#define I2CM_READ_BUFF3_I2CM_READ_BUFF3_MASK 0x000000FF //Byte 3 of a I2C read buffer sequential read (from address i2cm_address+3) + +//I2C Master Sequential Read Buffer Register 4 +#define I2CM_READ_BUFF4 0x7E24 +#define I2CM_READ_BUFF4_I2CM_READ_BUFF4_MASK 0x000000FF //Byte 4 of a I2C read buffer sequential read (from address i2cm_address+4) + +//I2C Master Sequential Read Buffer Register 5 +#define I2CM_READ_BUFF5 0x7E25 +#define I2CM_READ_BUFF5_I2CM_READ_BUFF5_MASK 0x000000FF //Byte 5 of a I2C read buffer sequential read (from address i2cm_address+5) + +//I2C Master Sequential Read Buffer Register 6 +#define I2CM_READ_BUFF6 0x7E26 +#define I2CM_READ_BUFF6_I2CM_READ_BUFF6_MASK 0x000000FF //Byte 6 of a I2C read buffer sequential read (from address i2cm_address+6) + +//I2C Master Sequential Read Buffer Register 7 +#define I2CM_READ_BUFF7 0x7E27 +#define I2CM_READ_BUFF7_I2CM_READ_BUFF7_MASK 0x000000FF //Byte 7 of a I2C read buffer sequential read (from address i2cm_address+7) + +//I2C SCDC Read Update Register 0 +#define I2CM_SCDC_UPDATE0 0x7E30 +#define I2CM_SCDC_UPDATE0_I2CM_SCDC_UPDATE0_MASK 0x000000FF //Byte 0 of a SCDC I2C update sequential read + +//I2C SCDC Read Update Register 1 +#define I2CM_SCDC_UPDATE1 0x7E31 +#define I2CM_SCDC_UPDATE1_I2CM_SCDC_UPDATE1_MASK 0x000000FF //Byte 1 of a SCDC I2C update sequential read + +//Global Interrupt Mute Control Register +#define IH_MUTE 0x000001FF +#define IH_MUTE_MUTE_ALL_INTERRUPT_MASK 0x00000001 //When set to 1, mutes the main interrupt line (where all interrupts are ORed) +#define IH_MUTE_MUTE_WAKEUP_INTERRUPT_MASK 0x00000002 //When set to 1, mutes the main interrupt output port + +/***************************************************************************** + * * + * HDCP Registers * + * * + *****************************************************************************/ + +//HDCP Enable and Functional Control Configuration Register 0 +#define A_HDCPCFG0 0x0005000 +#define A_HDCPCFG0_HDMIDVI_MASK 0x00000001 //Configures the transmitter to operate with a HDMI capable device or with a DVI device +#define A_HDCPCFG0_EN11FEATURE_MASK 0x00000002 //Enable the use of features 1 +#define A_HDCPCFG0_RXDETECT_MASK 0x00000004 //Information that a sink device was detected connected to the HDMI port +#define A_HDCPCFG0_AVMUTE_MASK 0x00000008 //This register holds the current AVMUTE state of the DWC_hdmi_tx controller, as expected to be perceived by the connected HDMI/HDCP sink device +#define A_HDCPCFG0_SYNCRICHECK_MASK 0x00000010 //Configures if the Ri check should be done at every 2s even or synchronously to every 128 encrypted frame +#define A_HDCPCFG0_BYPENCRYPTION_MASK 0x00000020 //Bypasses all the data encryption stages +#define A_HDCPCFG0_I2CFASTMODE_MASK 0x00000040 //Enable the I2C fast mode option from the transmitter's side +#define A_HDCPCFG0_ELVENA_MASK 0x00000080 //Enables the Enhanced Link Verification from the transmitter's side + +/* Internal macros */ +#define _F_START(f) (0 ? f) +#define _F_END(f) (1 ? f) +#define _F_SIZE(f) (1 + _F_END(f) - _F_START(f)) +//#define _F_MASK(f) (((1 << _F_SIZE(f)) - 1) << _F_START(f)) +#define _F_MASK(f) (((1ULL << _F_SIZE(f)) - 1) << _F_START(f)) +#define _F_NORMALIZE(v, f) (((v) & _F_MASK(f)) >> _F_START(f)) +#define _F_DENORMALIZE(v, f) (((v) << _F_START(f)) & _F_MASK(f)) + +/* Global macros */ +#define FIELD_VAL_GET(x, reg, field) \ +( \ + _F_NORMALIZE((x), reg ## _ ## field) \ +) + +#define FIELD_SET(x, reg, field, value) \ +( \ + (x & ~_F_MASK(reg ## _ ## field)) \ + | _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \ +) + +#define FIELD_VALUE(x, reg, field, value) \ +( \ + (x & ~_F_MASK(reg ## _ ## field)) \ + | _F_DENORMALIZE(value, reg ## _ ## field) \ +) + +#define FIELD_CLEAR(reg, field) \ +( \ + ~ _F_MASK(reg ## _ ## field) \ +) + +/* FIELD MACROS */ +#define FIELD_START(field) (0 ? field) +#define FIELD_END(field) (1 ? field) +#define FIELD_SIZE(field) (1 + FIELD_END(field) - FIELD_START(field)) +#define FIELD_MASK(field) (((1 << (FIELD_SIZE(field)-1)) | ((1 << (FIELD_SIZE(field)-1)) - 1)) << FIELD_START(field)) +#define FIELD_NORMALIZE(reg, field) (((reg) & FIELD_MASK(field)) >> FIELD_START(field)) +#define FIELD_DENORMALIZE(field, value) (((value) << FIELD_START(field)) & FIELD_MASK(field)) +#define FIELD_INIT(reg, field, value) FIELD_DENORMALIZE(reg ## _ ## field, \ + reg ## _ ## field ## _ ## value) +#define FIELD_INIT_VAL(reg, field, value) \ + (FIELD_DENORMALIZE(reg ## _ ## field, value)) +#define FIELD_VAL_SET(x, r, f, v) x = x & ~FIELD_MASK(r ## _ ## f) \ + | FIELD_DENORMALIZE(r ## _ ## f, r ## _ ## f ## _ ## v) + +#define RGB(r, g, b) ( (unsigned long) (((r) << 16) | ((g) << 8) | (b)) ) + +#define RGB16(r, g, b) ( (unsigned short) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | (((b) & 0xF8) >> 3))) \ No newline at end of file diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_swi2c.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_swi2c.c new file mode 100644 index 000000000000..56d1f966dfe6 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_swi2c.c @@ -0,0 +1,424 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* swi2c.c --- SM750/SM718 DDK +* This file contains the source code for I2C using software +* implementation. +* +*******************************************************************/ +#include "ddk770_reg.h" +#include "ddk770_os.h" +#include "ddk770_chip.h" +#include "ddk770_power.h" +#include "ddk770_swi2c.h" +#include "ddk770_timer.h" +#include "ddk770_gpio.h" +#include "ddk770_help.h" + +/******************************************************************* + * I2C Software Master Driver: + * =========================== + * Each i2c cycle is split into 4 sections. Each of these section marks + * a point in time where the SCL or SDA may be changed. + * + * 1 Cycle == | Section I. | Section 2. | Section 3. | Section 4. | + * +-------------+-------------+-------------+-------------+ + * | SCL set LOW |SCL no change| SCL set HIGH|SCL no change| + * + * ____________ _____________ + * SCL == XXXX _____________ ____________ / + * + * I.e. the SCL may only be changed in section 1. and section 3. while + * the SDA may only be changed in section 2. and section 4. The table + * below gives the changes for these 2 lines in the varios sections. + * + * Section changes Table: + * ====================== + * blank = no change, L = set bit LOW, H = set bit HIGH + * + * | 1.| 2.| 3.| 4.| + * ---------------+---+---+---+---+ + * Tx Start SDA | | H | | L | + * SCL | L | | H | | + * ---------------+---+---+---+---+ + * Tx Stop SDA | | L | | H | + * SCL | L | | H | | + * ---------------+---+---+---+---+ + * Tx bit H SDA | | H | | | + * SCL | L | | H | | + * ---------------+---+---+---+---+ + * Tx bit L SDA | | L | | | + * SCL | L | | H | | + * ---------------+---+---+---+---+ + * + ******************************************************************/ + +/* GPIO pins used for this I2C. It ranges from 0 to 31. */ +static unsigned char g_i2cClockGPIO = DEFAULT_I2C0_SCL; +static unsigned char g_i2cDataGPIO = DEFAULT_I2C0_SDA; + +/* + * Below is the variable declaration for the GPIO pin register usage + * for the i2c Clock and i2c Data. + * + * Note: + * Notice that the GPIO usage for the i2c clock and i2c Data are + * separated. This is to make this code flexible enough when + * two separate GPIO pins for the clock and data are located + * in two different GPIO register set (worst case). + */ + +/* i2c Clock GPIO Register usage */ +static unsigned long g_i2cClkGPIOMuxReg = GPIO_MUX; +static unsigned long g_i2cClkGPIODataReg = GPIO_DATA; + +/* i2c Data GPIO Register usage */ +static unsigned long g_i2cDataGPIOMuxReg = GPIO_MUX; +static unsigned long g_i2cDataGPIODataReg = GPIO_DATA; + + +/* + * This function puts a delay between command + */ +static void ddk770_swI2CWait(void) +{ + //SM770 has build-in timer. Use it instead of SW loop. + ddk770_timerWaitTicks(3, 0x3ff); +} + +/* + * This function set/reset the SCL GPIO pin + * + * Parameters: + * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) + * + * Notes: + * When setting SCL to high, just set the GPIO as input where the pull up + * resistor will pull the signal up. Do not use software to pull up the + * signal because the i2c will fail when other device try to drive the + * signal due to SM50x will drive the signal to always high. + */ +void ddk770_swI2CSCL(unsigned char value) +{ + + ddk770_gpioMode(g_i2cClockGPIO,0); + + ddk770_gpioWrite(g_i2cClockGPIO,value); + +} + +/* + * This function set/reset the SDA GPIO pin + * + * Parameters: + * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) + * + * Notes: + * When setting SCL to high, just set the GPIO as input where the pull up + * resistor will pull the signal up. Do not use software to pull up the + * signal because the i2c will fail when other device try to drive the + * signal due to SM50x will drive the signal to always high. + */ +void ddk770_swI2CSDA(unsigned char value) +{ + + ddk770_gpioMode(g_i2cDataGPIO,0); + + ddk770_gpioWrite(g_i2cDataGPIO,value); + +} + +/* + * This function read the data from the SDA GPIO pin + * + * Return Value: + * The SDA data bit sent by the Slave + */ +static unsigned char ddk770_swI2CReadSDA(void) +{ + //unsigned long ulGPIODirection; + //unsigned long ulGPIOData; + + ddk770_gpioMode(g_i2cDataGPIO,1); + + return ddk770_gpioRead(g_i2cDataGPIO); + +} + +#ifdef _MSC_VER +#pragma optimize( "", off ) +#endif + +/* + * This function sends ACK signal + */ +static void ddk770_swI2CAck(void) +{ + return; /* Single byte read is ok without it. */ +} + +/* + * This function sends the start command to the slave device + */ +static void ddk770_swI2CStart(void) +{ + /* Start I2C */ + ddk770_swI2CSDA(1); + ddk770_swI2CSCL(1); + ddk770_swI2CSDA(0); +} + +/* + * This function sends the stop command to the slave device + */ +static void ddk770_swI2CStop(void) +{ + /* Stop the I2C */ + ddk770_swI2CSCL(1); + ddk770_swI2CSDA(0); + ddk770_swI2CSDA(1); +} + +/* + * This function writes one byte to the slave device + * + * Parameters: + * data - Data to be write to the slave device + * + * Return Value: + * 0 - Success + * -1 - Fail to write byte + */ +static long ddk770_swI2CWriteByte(unsigned char data) +{ + unsigned char value = data; + int i; + + /* Sending the data bit by bit */ + for (i=0; i<8; i++) + { + /* Set SCL to low */ + ddk770_swI2CSCL(0); + + /* Send data bit */ + if ((value & 0x80) != 0) + ddk770_swI2CSDA(1); + else + ddk770_swI2CSDA(0); + + ddk770_swI2CWait(); + + /* Toggle clk line to one */ + ddk770_swI2CSCL(1); + ddk770_swI2CWait(); + + /* Shift byte to be sent */ + value = value << 1; + } + + /* Set the SCL Low and SDA High (prepare to get input) */ + ddk770_swI2CSCL(0); + ddk770_swI2CSDA(1); + + /* Set the SCL High for ack */ + ddk770_swI2CWait(); + ddk770_swI2CSCL(1); + ddk770_swI2CWait(); + + /* Read SDA, until SDA==0 */ + for(i=0; i<0xff; i++) + { + if (!ddk770_swI2CReadSDA()) + break; + + ddk770_swI2CSCL(0); + ddk770_swI2CWait(); + ddk770_swI2CSCL(1); + ddk770_swI2CWait(); + } + + /* Set the SCL Low and SDA High */ + ddk770_swI2CSCL(0); + ddk770_swI2CSDA(1); + + if (i<0xff) + return 0; + else + return (-1); +} + +/* + * This function reads one byte from the slave device + * + * Parameters: + * ack - Flag to indicate either to send the acknowledge + * message to the slave device or not + * + * Return Value: + * One byte data read from the Slave device + */ +static unsigned char ddk770_swI2CReadByte(unsigned char ack) +{ + int i; + unsigned char data = 0; + + for(i=7; i>=0; i--) + { + /* Set the SCL to Low and SDA to High (Input) */ + ddk770_swI2CSCL(0); + ddk770_swI2CSDA(1); + ddk770_swI2CWait(); + + /* Set the SCL High */ + ddk770_swI2CSCL(1); + ddk770_swI2CWait(); + + /* Read data bits from SDA */ + data |= (ddk770_swI2CReadSDA() << i); + } + + if (ack) + ddk770_swI2CAck(); + + /* Set the SCL Low and SDA High */ + ddk770_swI2CSCL(0); + ddk770_swI2CSDA(1); + + return data; +} + +#ifdef _MSC_VER +#pragma optimize( "", on ) +#endif + +/* + * This function initializes the i2c attributes and bus + * + * Parameters: + * i2cClkGPIO - The GPIO pin to be used as i2c SCL + * i2cDataGPIO - The GPIO pin to be used as i2c SDA + * + * Return Value: + * -1 - Fail to initialize the i2c + * 0 - Success + */ +long ddk770_swI2CInit( + unsigned char i2cClkGPIO, + unsigned char i2cDataGPIO +) +{ + int i; + + /* Return 0 if the GPIO pins to be used is out of range. The range is only from [0..63] */ + if ((i2cClkGPIO > 60) || (i2cDataGPIO > 60)) + return (-1); + + + /* Initialize the GPIO pin for the i2c Clock Register */ + g_i2cClkGPIOMuxReg = GPIO_MUX; + g_i2cClkGPIODataReg = GPIO_DATA; + + /* Initialize the Clock GPIO Offset */ + g_i2cClockGPIO = i2cClkGPIO; + + /* Initialize the GPIO pin for the i2c Data Register */ + g_i2cDataGPIOMuxReg = GPIO_MUX; + g_i2cDataGPIODataReg = GPIO_DATA; + + /* Initialize the Data GPIO Offset */ + g_i2cDataGPIO = i2cDataGPIO; + + /* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */ + pokeRegisterDWord(g_i2cClkGPIOMuxReg, + peekRegisterDWord(g_i2cClkGPIOMuxReg) & ~(1 << g_i2cClockGPIO)); + pokeRegisterDWord(g_i2cDataGPIOMuxReg, + peekRegisterDWord(g_i2cDataGPIOMuxReg) & ~(1 << g_i2cDataGPIO)); + + /* Clear the i2c lines. */ + for(i=0; i<9; i++) + ddk770_swI2CStop(); + + return 0; +} + +/* + * This function reads the slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be read from + * registerIndex - Slave device's register to be read + * + * Return Value: + * Register value + */ +unsigned char ddk770_swI2CReadReg( + unsigned char deviceAddress, + unsigned char registerIndex +) +{ + unsigned char data; + + /* Send the Start signal */ + ddk770_swI2CStart(); + + /* Send the device address */ + ddk770_swI2CWriteByte(deviceAddress); + + /* Send the register index */ + ddk770_swI2CWriteByte(registerIndex); + + /* Get the bus again and get the data from the device read address */ + ddk770_swI2CStart(); + ddk770_swI2CWriteByte(deviceAddress + 1); + data = ddk770_swI2CReadByte(1); + + /* Stop swI2C and release the bus */ + ddk770_swI2CStop(); + + return data; +} + +/* + * This function writes a value to the slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be written + * registerIndex - Slave device's register to be written + * data - Data to be written to the register + * + * Result: + * 0 - Success + * -1 - Fail + */ +long ddk770_swI2CWriteReg( + unsigned char deviceAddress, + unsigned char registerIndex, + unsigned char data +) +{ + long returnValue = 0; + + /* Send the Start signal */ + ddk770_swI2CStart(); + + /* Send the device address and read the data. All should return success + in order for the writing processed to be successful + */ + if ((ddk770_swI2CWriteByte(deviceAddress) != 0) || + (ddk770_swI2CWriteByte(registerIndex) != 0) || + (ddk770_swI2CWriteByte(data) != 0)) + { + returnValue = -1; + } + + /* Stop i2c and release the bus */ + ddk770_swI2CStop(); + + return returnValue; +} diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_swi2c.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_swi2c.h new file mode 100644 index 000000000000..7fcb01f234ba --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_swi2c.h @@ -0,0 +1,97 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* swi2c.h --- SM750/SM718 DDK +* This file contains the definitions for i2c using software +* implementation. +* +*******************************************************************/ +#ifndef _DDK770_SWI2C_H_ +#define _DDK770_SWI2C_H_ + +/* Default i2c CLK and Data GPIO. These are the default i2c pins */ +#define DEFAULT_I2C0_SCL 24 +#define DEFAULT_I2C0_SDA 25 + +#define DEFAULT_I2C1_SCL 6 +#define DEFAULT_I2C1_SDA 7 + +#include "../smi_drv.h" + +/* + * This function initializes the i2c attributes and bus + * + * Parameters: + * i2cClkGPIO - The GPIO pin to be used as i2c SCL + * i2cDataGPIO - The GPIO pin to be used as i2c SDA + * + * Return Value: + * -1 - Fail to initialize the i2c + * 0 - Success + */ +long ddk770_swI2CInit( + unsigned char i2cClkGPIO, + unsigned char i2cDataGPIO +); + +/* + * This function reads the slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be read from + * registerIndex - Slave device's register to be read + * + * Return Value: + * Register value + */ +unsigned char ddk770_swI2CReadReg( + unsigned char deviceAddress, + unsigned char registerIndex +); + +/* + * This function writes a value to the slave device's register + * + * Parameters: + * deviceAddress - i2c Slave device address which register + * to be written + * registerIndex - Slave device's register to be written + * data - Data to be written to the register + * + * Result: + * 0 - Success + * -1 - Fail + */ +long ddk770_swI2CWriteReg( + unsigned char deviceAddress, + unsigned char registerIndex, + unsigned char data +); + +/* + * These two functions are used to toggle the data on the SCL and SDA I2C lines. + * The used of these two functions are not recommended unless it is necessary. + */ + +/* + * This function set/reset the SCL GPIO pin + * + * Parameters: + * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) + */ +void ddk770_swI2CSCL(unsigned char value); + +/* + * This function set/reset the SDA GPIO pin + * + * Parameters: + * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) + */ +void ddk770_swI2CSDA(unsigned char value); + +#endif /* _SWI2C_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_timer.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_timer.c new file mode 100644 index 000000000000..f68b3f8e8bf3 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_timer.c @@ -0,0 +1,300 @@ +/******************************************************************* +* +* Copyright (c) 2014 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* This file contains the definitions for the timer functions. +* +*******************************************************************/ +#include "ddk770_reg.h" +#include "ddk770_helper.h" +#include "ddk770_timer.h" +#include "ddk770_help.h" + +/* + * A global varible to store the counter values set in the timer. + * It is needed because the counter value cannot be read back from the timer. + * A read to the timer counter only gets the latest value being decremented. + */ +static unsigned long gTimerCounter[4] = {0, 0, 0, 0}; + +/* + * Calculate a value for timer counter according to input time in micro-second. + * Calculation is based on 168MHz master clock, and the counter decrements at every 16 ticks. + */ +unsigned long ddk770_calcTimerCounter( + unsigned long microSeconds +) +{ + return( microSeconds * 168 / 16); +} + +/* + * This function start the timer with raw interrupt enabled. + * When the timer decrements to 0, timer raw interrupt will be generated. + * + * Raw interrupt of the timers can be used in one of 2 ways: + * 1. In pulling mode, detection of raw interrupt pending means timer is decremented to 0. + * 2. In interrupt mode, unlock the timer interrupt mask will generate a interrput to system. + * + */ +void ddk770_timerStart( + timer_number_t timer, /* which timer: 0 to 3 */ + unsigned long timerCounter, /* Timer counter */ + unsigned long div16Enable /* Enable the 16 divisor, time out will be increased by 16 */ +) +{ + unsigned long ulTimerAddr, ulTimerValue; + + if (timerCounter == 0) return; /* Nothing to set */ + + /* Work out the timer's MMIO address + Timer 0 address + ( timer number x 4 ) + */ + ulTimerAddr = TIMER_CONTROL + (timer << 2); + + ulTimerValue = + FIELD_VALUE(0, TIMER_CONTROL, COUNTER, timerCounter) + | FIELD_SET(0, TIMER_CONTROL, RAWINT_STATUS, RESET) /* Reset the raw interrupt */ + | FIELD_SET(0, TIMER_CONTROL, RAWINT_ENABLE, ENABLE) /* Enable raw interrupt to happen when time out */ + | FIELD_VALUE(0, TIMER_CONTROL, DIV16, div16Enable) + | FIELD_SET(0, TIMER_CONTROL, ENABLE, ENABLE); /* Start the timer */ + + pokeRegisterDWord(ulTimerAddr, ulTimerValue); + + gTimerCounter[timer] = timerCounter; +} + +/* + * This function checks if a timer's raw interrupt has been pending. + * When raw interrupt is detected with pending status, it indicate the + * countdown of ddk770_timerStart() has been completed. + * + * Return: + * 1 = Raw interrupt status is pending. + * 0 = Raw int is NOT pending. + */ +unsigned long ddk770_timerRawIntPending( + timer_number_t timer /* which timer: 0 to 3 */ +) +{ + unsigned long ulTimerAddr, rawIntStatus; + + /* Work out the timer's MMIO address + Timer 0 address + ( timer number x 4 ) + */ + ulTimerAddr = TIMER_CONTROL + (timer << 2); + rawIntStatus = FIELD_VAL_GET(peekRegisterDWord(ulTimerAddr), TIMER_CONTROL, RAWINT_STATUS); + + return(rawIntStatus); +} + +/* + * This function clears the RAW interrupt status of the timer. + * + * When a timer completes countdown, the raw interrupt bit will be set. + * It has to be cleared, in order to distinguish between different sessions of countdown. + * + */ +void ddk770_timerClearRawInt( + timer_number_t timer /* which timer: 0 to 3 */ +) +{ + unsigned long ulTimerAddr, ulTimerValue; + + /* Work out the timer's MMIO address + Timer 0 address + ( timer number x 4 ) + */ + ulTimerAddr = TIMER_CONTROL + (timer << 2); + ulTimerValue = peekRegisterDWord(ulTimerAddr) + & FIELD_CLEAR(TIMER_CONTROL, COUNTER); /* We don't want the current counter value */ + + pokeRegisterDWord(ulTimerAddr, + ulTimerValue + | FIELD_VALUE(0, TIMER_CONTROL, COUNTER, gTimerCounter[timer]) /* When clearing raw int, we don't want to erase the original counter value */ + | FIELD_SET(0, TIMER_CONTROL, RAWINT_STATUS, RESET)); /* Reset the raw interrupt */ +} + +/* + * This function stop the timer. + * + */ +void ddk770_timerStop( + timer_number_t timer /* which timer: 0 to 3 */ +) +{ + unsigned long ulTimerAddr, ulTimerValue; + + /* Work out the timer's MMIO address + Timer 0 address + ( timer number x 4 ) + */ + ulTimerAddr = TIMER_CONTROL + (timer << 2); + + ulTimerValue = + FIELD_SET(0, TIMER_CONTROL, RAWINT_STATUS, RESET) /* Reset the raw interrupt */ + | FIELD_SET(0, TIMER_CONTROL, ENABLE, DISABLE); /* Stop the timer */ + + pokeRegisterDWord(ulTimerAddr, ulTimerValue); + + gTimerCounter[timer] = 0; +} + +/* + * This function read the current value in the timer counter. + * + * Note: When timer is disable, always read back 0. + */ +unsigned long ddk770_timerGetCounter( + timer_number_t timer /* which timer: 0 to 3 */ +) +{ + unsigned long ulTimerAddr, ulCounter; + + /* Work out the timer's MMIO address + Timer 0 address + ( timer number x 4 ) + */ + ulTimerAddr = TIMER_CONTROL + (timer << 2); + ulCounter = FIELD_VAL_GET(peekRegisterDWord(ulTimerAddr), TIMER_CONTROL, COUNTER); + + return(ulCounter); +} + +/* + * This function gets the countdown setting stored in timer. + * Function ddk770_timerGetCounter() can only get the current counter value. + * It cannot get the original countdown setting of timer. + * + * Note: When timer is disable, always read back 0. + */ +unsigned long ddk770_timerGetCounterSetting( + timer_number_t timer /* which timer: 0 to 3 */ +) +{ + /* The counter value put in timer cannot be read back from the register. + It has to keep in global variable. + */ + return(gTimerCounter[timer]); +} + +/* + * This funciton uses the timer to wait a specific amount of time + * in micro-second. + */ +void ddk770_timerWait( + timer_number_t timer, + unsigned long microSeconds +) +{ + unsigned long ticks; + + // Limit max delay to 10 seconds + if (microSeconds > 10000000) + microSeconds = 10000000; + + ticks = ddk770_calcTimerCounter(microSeconds); + + //Tick count is based on enabling DIV 16. + //Third parameter to ddk770_timerStart is 1. + ddk770_timerStart(timer, ticks, 1); + + while (!ddk770_timerRawIntPending(timer)); + + ddk770_timerStop(timer); +} + +/* + * This funciton uses the timer to wait a specific ticks of master clock + * + */ +void ddk770_timerWaitTicks( + timer_number_t timer, /* Use timer 0, 1, 2 or 3 */ + unsigned long ticks +) +{ + //Counter is 28 bits only. + ticks &= 0xFFFFFFF; + + ddk770_timerStart(timer, ticks, 0); + + while (!ddk770_timerRawIntPending(timer)); + + ddk770_timerStop(timer); +} + +/* + * This function returns the INT mask for a specific timer. + * + */ +unsigned long ddk770_timerIntMask( + timer_number_t timer /* Which timer: 0 to 3 */ +) +{ + unsigned long mask; + + mask = 0; + switch (timer) + { + case 0: + mask |= FIELD_SET(0, INT_MASK, TIMER0, ENABLE); + break; + case 1: + mask |= FIELD_SET(0, INT_MASK, TIMER1, ENABLE); + break; + case 2: + mask |= FIELD_SET(0, INT_MASK, TIMER2, ENABLE); + break; + case 3: + mask |= FIELD_SET(0, INT_MASK, TIMER3, ENABLE); + break; + default: + break; + } + + return mask; +} + +/* + * This is a reference sample showing how to implement ISR for timers. + * It works together with libsrc\intr.c module. + * + * Refer to Apps\timer\tstimer.c on how to hook up this function with system + * interrupt under WATCOM DOS extender. + * + */ +void ddk770_timerIsrTemplate(unsigned long status) +{ + if (FIELD_VAL_GET(status, INT_STATUS, TIMER0) == INT_STATUS_TIMER0_ACTIVE) + { + /* Perform ISR action for timer 0 here */ + ddk770_incTestCounter(); + + ddk770_timerClearRawInt(0); + } + + if (FIELD_VAL_GET(status, INT_STATUS, TIMER1) == INT_STATUS_TIMER1_ACTIVE) + { + /* Perform ISR action for timer 1 here */ + ddk770_incTestCounter(); + + ddk770_timerClearRawInt(1); + } + + if (FIELD_VAL_GET(status, INT_STATUS, TIMER2) == INT_STATUS_TIMER2_ACTIVE) + { + /* Perform ISR action for timer 2 here */ + ddk770_incTestCounter(); + + ddk770_timerClearRawInt(2); + } + + if (FIELD_VAL_GET(status, INT_STATUS, TIMER3) == INT_STATUS_TIMER3_ACTIVE) + { + /* Perform ISR action for timer 3 here */ + ddk770_incTestCounter(); + + ddk770_timerClearRawInt(3); + } +} + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_timer.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_timer.h new file mode 100644 index 000000000000..519fcaaedef3 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_timer.h @@ -0,0 +1,141 @@ +/******************************************************************* +* +* Copyright (c) 2014 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* This file contains the definitions for the timer functions. +* +*******************************************************************/ +#ifndef _DDK770_TIMER_H_ +#define _DDK770_TIMER_H_ + +#include "ddk770_os.h" + +typedef enum _timer_number_t +{ + TIMER0 = 0, + TIMER1 = 1, + TIMER2 = 2, + TIMER3 = 3, +} +timer_number_t; + +/* + * Calculate a value for timer counter according to input time in micro-second. + * Calculation is based on 168MHz master clock, and the counter decrements at every 16 ticks. + */ +unsigned long ddk770_calcTimerCounter( + unsigned long microSeconds +); + +/* + * This function start the timer with raw interrupt enabled. + * When the timer decrements to 0, timer raw interrupt will be generated. + * + * Raw interrupt of the timers can be used in one of 2 ways: + * 1. In pulling mode, detection of raw interrupt pending means timer is decremented to 0. + * 2. In interrupt mode, unlock the timer interrupt mask will generate a interrput to system. + * + */ +void ddk770_timerStart( + timer_number_t timer, /* which timer: 0 to 3 */ + unsigned long timerCounter, /* Timer counter: use ddk770_calcTimerCounter() to work out a counter for a specific period. */ + unsigned long div16Enable /* Enable the 16 divisor, time out will be increased by 16 */ +); + +/* + * This function checks if a timer's raw interrupt has been pending. + * When raw interrupt is detected with pending status, it indicate the + * countdown of ddk770_timerStart() has been completed. + * + * Return: + * 1 = Raw interrupt status is pending. + * 0 = Raw int is NOT pending. + */ +unsigned long ddk770_timerRawIntPending( + timer_number_t timer /* which timer: 0 to 3 */ +); + +/* + * This function clears the RAW interrupt status of the timer. + * + * When a timer completes countdown, the raw interrupt bit will be set. + * It has to be cleared, in order to distinguish between different sessions of countdown. + * + */ +void ddk770_timerClearRawInt( + timer_number_t timer /* which timer: 0 to 3 */ +); + +/* + * This function stop the timer. + * + */ +void ddk770_timerStop( + timer_number_t timer /* which timer: 0 to 3 */ +); + +/* + * This function read the current value in the timer counter. + * + * Note: When timer is disable, always read back 0. + */ +unsigned long ddk770_timerGetCounter( + timer_number_t timer /* which timer: 0 to 3 */ +); + +/* + * This function gets the countdown setting stored in timer. + * Function ddk770_timerGetCounter() can only get the current counter value. + * It cannot get the original countdown setting of timer. + * + * Note: When timer is disable, always read back 0. + */ +unsigned long ddk770_timerGetCounterSetting( + timer_number_t timer /* which timer: 0 to 3 */ +); + +/* + * This funciton uses the timer to wait a specific amount of time + * in micro-second. + */ +void ddk770_timerWait( + timer_number_t timer, + unsigned long microSeconds +); + +/* + * This funciton uses the timer to wait a specific ticks of master clock + * + */ +void ddk770_timerWaitTicks( + timer_number_t timer, /* Use timer 0, 1, 2 or 3 */ + unsigned long ticks +); + +/* + * This function returns the INT mask for a specific timer. + * + */ +unsigned long ddk770_timerIntMask( + timer_number_t timer /* Which timer: 0 to 3 */ +); + +unsigned long ddk770_getTestCounter(void); + +void ddk770_setTestCounter(unsigned long value); + +/* + * This is a reference sample showing how to implement ISR for timers. + * It works together with libsrc\intr.c module. + * + * Refer to Apps\timer\tstimer.c on how to hook up this function with system + * interrupt under WATCOM DOS extender. + * + */ +void ddk770_timerIsrTemplate(unsigned long status); + +#endif /* _TIMER_H_ */ + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_video.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_video.c new file mode 100644 index 000000000000..de3daa02a970 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_video.c @@ -0,0 +1,1098 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* Video.C --- Voyager GX SDK +* This file contains the definitions for the Video functions. +* +*******************************************************************/ +#include "ddk770_reg.h" +#include "ddk770_hardware.h" +#include "ddk770_chip.h" +#include "ddk770_mode.h" +#include "ddk770_video.h" +#include "ddk770_help.h" + +/* New video function */ + +#define SCALE_CONSTANT (1 << 12) + +/* Offset Adjustment for the window */ +static short gWidthAdjustment = 0; +static short gHeightAdjustment = 0; + +/* Source Video Width and Height */ +static unsigned long gSrcVideoWidth = 0; +static unsigned long gSrcVideoHeight = 0; +static unsigned long gPerfModeStride = 0; //Performance mode parameter. + +/* + * ddk770_videoGetBufferStatus + * This function gets the status of the video buffer, either the buffer + * has been used or not. + * + * Input: + * bufferIndex - The index of the buffer which size to be retrieved + * + * Output: + * 0 - No flip pending + * 1 - Flip pending + */ +unsigned long ddk770_videoGetBufferStatus( + unsigned long bufferIndex +) +{ + return (FIELD_VAL_GET(peekRegisterDWord(VIDEO_FB_ADDRESS), VIDEO_FB_ADDRESS, STATUS)); +} + +/* + * ddk770_videoGetPitch + * This function gets the video plane pitch + * + * Output: + * pitch - Number of bytes per line of the video plane + * specified in 128-bit aligned bytes. + */ +unsigned short ddk770_videoGetPitch() +{ + return (FIELD_VAL_GET(peekRegisterDWord(VIDEO_FB_WIDTH), VIDEO_FB_WIDTH, WIDTH)); +} + +/* + * ddk770_videoGetLineOffset + * This function gets the video plane line offset + * + * Output: + * lineOffset - Number of 128-bit aligned bytes per line + * of the video plane. + */ +unsigned short ddk770_videoGetLineOffset() +{ + return (FIELD_VAL_GET(peekRegisterDWord(VIDEO_FB_WIDTH), VIDEO_FB_WIDTH, OFFSET)); +} + +/* + * ddk770_videoGetBufferSize + * This function gets the buffer size + * + * Input: + * bufferIndex - The index of the buffer which size to be retrieved + */ +static unsigned long ddk770_videoGetBufferSize( + unsigned long bufferIndex +) +{ + unsigned long value; + + if (bufferIndex == 0) + { + value -= (unsigned long) + FIELD_VAL_GET(peekRegisterDWord(VIDEO_FB_ADDRESS), VIDEO_FB_ADDRESS, ADDRESS); + } + + return value; +} + + +/* + * ddk770_videoGetBuffer + * This function gets the video buffer + * + * Input: + * bufferIndex - The index of the buffer to get + * + * Output: + * The video buffer of the requested index. + */ +unsigned long ddk770_videoGetBuffer( + unsigned char bufferIndex +) +{ + return (FIELD_VAL_GET(peekRegisterDWord(VIDEO_FB_ADDRESS), VIDEO_FB_ADDRESS, ADDRESS)); +} + +/* + * ddk770_videoSetBufferLastAddress + * This function sets the video buffer last address. + * The value can be calculated by subtracting one line offset + * from the buffer size (Total number of line offset * + * source video height). + * + * Input: + * bufferIndex - The index of the buffer to be set + * bufferSize - Size of the video buffer. + */ +static void ddk770_videoSetBufferLastAddress( + unsigned char bufferIndex, /* The index of the buffer to be set. */ + unsigned long bufferStart, /* Buffer start */ + unsigned long bufferSize /* Size of the video buffer */ +) +{ + //if (ddk770_getChipType() == SM750) + if (ddk770_getChipType() == SM768) + { + /* Substract with one line offset to get the last address value when added + with the bufferStart. Somehow, this is only happen in SM750 chip */ + bufferSize -= (unsigned long) ddk770_videoGetLineOffset(); + } +} + +/* + * ddk770_videoGetBufferLastAddress + * This function gets the video buffer last address. + * + * Input: + * bufferIndex - The index of the buffer last address to be retrieved + */ +static unsigned long ddk770_videoGetBufferLastAddress( + unsigned char bufferIndex /* The index of the buffer last address to be retrieved. */ +) +{ + return 0; +} + +/* + * ddk770_videoSetBuffer + * This function sets the video buffer + * + * Input: + * bufferIndex - The index of the buffer to be set + * bufferStartAddress - The starting address of the buffer + */ +void ddk770_videoSetBuffer( + unsigned dispCtrl, + unsigned char bufferIndex, /* The index of the buffer to be set. */ + unsigned long bufferStartAddress /* Video buffer with 128-bit alignment */ +) +{ + unsigned long bufferSize, lastAddress; + unsigned long regFB; + + /* Get the buffer size first */ + bufferSize = ddk770_videoGetBufferSize(bufferIndex); + + lastAddress = ddk770_videoGetBufferLastAddress(bufferIndex); + + //if (ddk770_getChipType() == SM750) + if (ddk770_getChipType() == SM768) + { + if (lastAddress <= (bufferStartAddress + bufferSize - ddk770_videoGetLineOffset())) + ddk770_videoSetBufferLastAddress(bufferIndex, bufferStartAddress, bufferSize); + } + else + { + if (lastAddress <= (bufferStartAddress + bufferSize)) + ddk770_videoSetBufferLastAddress(bufferIndex, bufferStartAddress, bufferSize); + } + + if (bufferIndex == 0) + { + regFB = VIDEO_FB_ADDRESS+(dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + pokeRegisterDWord(regFB, + FIELD_SET(0, VIDEO_FB_ADDRESS, STATUS, PENDING) | + FIELD_VALUE(0, VIDEO_FB_ADDRESS, ADDRESS, bufferStartAddress)); + } +} +/* + * ddk770_videoSetUVBuffer + * This function sets the video buffer + * + * Input: + * bufferIndex - The index of the buffer to be set + * bufferStartAddress - The starting address of the buffer + */ +void ddk770_videoSetUVBuffer( + unsigned dispCtrl, + unsigned long bufferStartUAddress, /* Video buffer with 128-bit alignment */ + unsigned long bufferStartVAddress /* Video buffer with 128-bit alignment */ +) +{ + //unsigned long bufferSize; + unsigned long regU, regV; + + + regU = VIDEO_FB_ADDRESS_U + (dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + regV = VIDEO_FB_ADDRESS_V + (dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + pokeRegisterDWord(regU, + FIELD_VALUE(0, VIDEO_FB_ADDRESS_U, ADDRESS, bufferStartUAddress)); + pokeRegisterDWord(regV, + FIELD_VALUE(0, VIDEO_FB_ADDRESS_V, ADDRESS, bufferStartVAddress)); +} + +/* + * ddk770_videoSetPitchOffset + * This function sets the video plane pitch and offset + * + * Input: + * pitch - Number of bytes per line of the video plane + * specified in 128-bit aligned bytes. + * lineOffset - Number of 128-bit aligned bytes per line + * of the video plane. + */ +void ddk770_videoSetPitchOffset( + unsigned dispCtrl, + unsigned short pitch, + unsigned short lineOffset +) +{ + unsigned long regWidth; + + /* Set Video Buffer Offset (pitch) */ + regWidth = VIDEO_FB_WIDTH + (dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + lineOffset = alignLineOffset(lineOffset); + + pokeRegisterDWord(regWidth, + FIELD_VALUE(0, VIDEO_FB_WIDTH, WIDTH, pitch) | + FIELD_VALUE(0, VIDEO_FB_WIDTH, OFFSET, lineOffset)); +} +/* + * ddk770_videoSetUVPitchOffset + * This function sets the video plane pitch and offset of U and V + * + * Input: + * pitch - Number of bytes per line of the video plane + * specified in 128-bit aligned bytes. + * lineOffset - Number of 128-bit aligned bytes per line + * of the video plane. + */ +void ddk770_videoSetUVPitchOffset( + unsigned dispCtrl, + unsigned short pitch, + unsigned short lineOffset +) +{ + unsigned long regWidthU, regWidthV; + + regWidthU = VIDEO_FB_WIDTH_U + (dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + regWidthV = VIDEO_FB_WIDTH_V + (dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + lineOffset = alignLineOffset(lineOffset); + + pokeRegisterDWord(regWidthU, + FIELD_VALUE(0, VIDEO_FB_WIDTH_U, WIDTH, pitch) | + FIELD_VALUE(0, VIDEO_FB_WIDTH_U, OFFSET, lineOffset)); + pokeRegisterDWord(regWidthV, + FIELD_VALUE(0, VIDEO_FB_WIDTH_V, WIDTH, pitch) | + FIELD_VALUE(0, VIDEO_FB_WIDTH_V, OFFSET, lineOffset)); +} +/* + * ddk770_videoSetLast + * This function sets the video source last lines and width. + * + * Input: + * + * width - Video source width + * height - Video source height + */ +void ddk770_videoSetLast( + unsigned dispCtrl, + unsigned long width, + unsigned long height +) +{ +#if 0 // SM768 don't have this register. Leave empty function here. + if (dispCtrl == CHANNEL0_CTRL) + { + pokeRegisterDWord(CHANNEL0_VIDEO_LAST, + FIELD_VALUE(0, CHANNEL0_VIDEO_LAST, COLUMN, width) | + FIELD_VALUE(0, CHANNEL0_VIDEO_LAST, ROW, height)); + } + else + { + pokeRegisterDWord(CHANNEL1_VIDEO_LAST, + FIELD_VALUE(0, CHANNEL1_VIDEO_LAST, COLUMN, width) | + FIELD_VALUE(0, CHANNEL1_VIDEO_LAST, ROW, height)); + } +#endif +} +/* + * ddk770_videoSetWindowSize + * This function sets the video window size. + * + * Input: + * width - Video Window width + * height - Video Window height + */ +void ddk770_videoSetWindowSize( + unsigned dispCtrl, + unsigned long width, + unsigned long height +) +{ + unsigned long value, startX, startY; + unsigned long regTL, regBR; + + regTL =VIDEO_PLANE_TL+(dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + regBR =VIDEO_PLANE_BR+(dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + value = peekRegisterDWord(regTL); + startX = FIELD_VAL_GET(value, VIDEO_PLANE_TL, LEFT); + startY = FIELD_VAL_GET(value, VIDEO_PLANE_TL, TOP); + + /* Set bottom and right position */ + pokeRegisterDWord(regBR, + FIELD_VALUE(0, VIDEO_PLANE_BR, BOTTOM, startY + height - 1 - gHeightAdjustment) | + FIELD_VALUE(0, VIDEO_PLANE_BR, RIGHT, startX + width - 1 - gWidthAdjustment)); +} + +/* + * ddk770_videoGetWindowSize + * This function gets the video window size. + * + * Output: + * width - Video Window width + * height - Video Window height + */ +void ddk770_videoGetWindowSize( + unsigned dispCtrl, + unsigned long *pVideoWidth, + unsigned long *pVideoHeight +) +{ + unsigned long positionTopLeft, positionRightBottom; + unsigned long videoWidth, videoHeight; + unsigned long regTL, regBR; + + regTL = VIDEO_PLANE_TL + (dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + regBR = VIDEO_PLANE_BR + (dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + positionTopLeft = peekRegisterDWord(regTL); + positionRightBottom = peekRegisterDWord(regBR); + videoWidth = FIELD_VAL_GET(positionRightBottom, VIDEO_PLANE_BR, RIGHT) - + FIELD_VAL_GET(positionTopLeft, VIDEO_PLANE_TL, LEFT) + 1 + + gWidthAdjustment; + videoHeight = FIELD_VAL_GET(positionRightBottom, VIDEO_PLANE_BR, BOTTOM) - + FIELD_VAL_GET(positionTopLeft, VIDEO_PLANE_TL, TOP) + 1 + + gHeightAdjustment; + + if (pVideoWidth != ((unsigned long *)0)) + *pVideoWidth = videoWidth; + + if (pVideoHeight != ((unsigned long *)0)) + *pVideoHeight = videoHeight; +} + +/* + * ddk770_videoSetPosition + * This function sets the video starting coordinate position. + * + * Input: + * startX - X Coordinate of the video window starting position + * startY - Y Coordinate of the video window starting position + */ +void ddk770_videoSetPosition( + unsigned dispCtrl, + unsigned long startX, + unsigned long startY +) +{ + unsigned long videoWidth, videoHeight; + unsigned long regTL; + + regTL = VIDEO_PLANE_TL + (dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + /* Get the video window width and height */ + ddk770_videoGetWindowSize(dispCtrl, &videoWidth, &videoHeight); + + pokeRegisterDWord(regTL, + FIELD_VALUE(0, VIDEO_PLANE_TL, TOP, startY) | + FIELD_VALUE(0, VIDEO_PLANE_TL, LEFT, startX)); + + /* Set bottom and right position */ + ddk770_videoSetWindowSize(dispCtrl, videoWidth, videoHeight); + +} + +/* + * ddk770_videoSetConstants + * This function sets the video constants. The actual component will be + * added by this constant to get the expected component value. + * + * Input: + * yConstant - Y Constant Value + * redConstant - Red Constant Value + * greenConstant - Green Constant Value + * blueConstant - Blue Constant Value + */ +void ddk770_videoSetConstants( + unsigned dispCtrl, + unsigned char yConstant, /* Y Adjustment */ + unsigned char redConstant, /* Red Conversion constant */ + unsigned char greenConstant, /* Green Conversion constant */ + unsigned char blueConstant /* Blue Conversion constant */ +) +{ + unsigned long regYUV; + + regYUV = VIDEO_YUV_CONSTANTS + (dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + pokeRegisterDWord(regYUV, + FIELD_VALUE(0, VIDEO_YUV_CONSTANTS, Y, yConstant) | + FIELD_VALUE(0, VIDEO_YUV_CONSTANTS, R, redConstant) | + FIELD_VALUE(0, VIDEO_YUV_CONSTANTS, G, greenConstant) | + FIELD_VALUE(0, VIDEO_YUV_CONSTANTS, B, blueConstant)); +} + +/* + * ddk770_videoSetInitialScale + * This function sets the video buffer initial vertical scale. + * + * Input: + * bufferIndex - Index of the buffer which vertical scale value + * to be set. + * bufferInitScale - Buffer Initial vertical scale value + */ +void ddk770_videoSetInitialScale( + unsigned dispCtrl, + unsigned short InitScaleHorizontal, + unsigned short InitScaleVertical +) +{ + unsigned long value; + unsigned long regScale; + + regScale = VIDEO_INITIAL_SCALE + (dispCtrl > 1? CHANNEL_OFFSET2: dispCtrl*CHANNEL_OFFSET); + + value = peekRegisterDWord(regScale); + value = FIELD_VALUE(value, VIDEO_INITIAL_SCALE, VERTICAL, InitScaleVertical); + value = FIELD_VALUE(value, VIDEO_INITIAL_SCALE, HORIZONTAL, InitScaleHorizontal); + pokeRegisterDWord(regScale, value); +} + +/* + * ddk770_videoGetInitialScale + * This function gets the video buffer initial vertical scale. + * + * Input: + * pbuffer0InitScale - Pointer to variable to store buffer 0 initial vertical scale + * pbuffer1InitScale - Pointer to variable to store buffer 1 initial vertical scale + */ +__attribute__((unused)) static void ddk770_videoGetInitialScale( + unsigned dispCtrl, + unsigned short *pBufferVInitScale, + unsigned short *pBufferHInitScale +) +{ + unsigned long regScale; + + regScale = VIDEO_INITIAL_SCALE + (dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + *pBufferHInitScale = (unsigned short) + FIELD_VAL_GET(peekRegisterDWord(regScale), VIDEO_INITIAL_SCALE, HORIZONTAL); + *pBufferVInitScale = (unsigned short) + FIELD_VAL_GET(peekRegisterDWord(regScale), VIDEO_INITIAL_SCALE, VERTICAL); +} + +/* + * ddk770_videoScale + * This function scales the video. + * + * Input: + * srcWidth - The source video width + * srcHeight - The source video height + * dstWidth - The destination video width + * dstHeight - The destination video height + */ +static void ddk770_videoScale( + unsigned dispCtrl, + unsigned long srcWidth, + unsigned long srcHeight, + unsigned long dstWidth, + unsigned long dstHeight +) +{ + unsigned long value = 0; + unsigned long scaleFactor; + unsigned long regScale; + + regScale = VIDEO_SCALE + (dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + if (dstHeight > srcHeight) + { + /* Calculate the factor */ + scaleFactor = (srcHeight-1) * SCALE_CONSTANT / dstHeight; + value = FIELD_VALUE(value, VIDEO_SCALE , VERTICAL_SCALE, scaleFactor); + } + + /* Scale the horizontal size */ + if (dstWidth > srcWidth) + { + /* Calculate the factor */ + scaleFactor = (srcWidth-1) * SCALE_CONSTANT / dstWidth; + value = FIELD_VALUE(value, VIDEO_SCALE, HORIZONTAL_SCALE, scaleFactor); + } + + pokeRegisterDWord(regScale, value); +} + + +/* + * ddk770_videoSwapYUVByte + * This function swaps the YUV data byte. + * + * Input: + * byteSwap - Flag to enable/disable YUV data byte swap. + */ +void ddk770_videoSwapYUVByte( + unsigned dispCtrl, + video_byteswap_t byteSwap +) +{ + unsigned long value; + unsigned long regCtrl; + + regCtrl = VIDEO_DISPLAY_CTRL + (dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + value = peekRegisterDWord(regCtrl); + if (byteSwap == SWAP_BYTE) + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, BYTE_SWAP, ENABLE); + else + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, BYTE_SWAP, DISABLE); + + pokeRegisterDWord(regCtrl, value); +} + + +void ddk770_videoYUVPrefetch( + unsigned dispCtrl, + unsigned long enable +) +{ + unsigned long value; + unsigned long regCtrl; + + regCtrl = VIDEO_SOURCE_SIZE + (dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + value = peekRegisterDWord(regCtrl); + if (enable) + { + value = FIELD_SET(value, VIDEO_SOURCE_SIZE, YUVPREFETCH, ENABLE); + value = FIELD_SET(value, VIDEO_SOURCE_SIZE, YUVARLENINC, ENABLE); + value = FIELD_SET(value, VIDEO_SOURCE_SIZE, YUVUVREDUCE, DISABLE); + } + else + { + value = FIELD_SET(value, VIDEO_SOURCE_SIZE, YUVPREFETCH, DISABLE); + value = FIELD_SET(value, VIDEO_SOURCE_SIZE, YUVARLENINC, DISABLE); + value = FIELD_SET(value, VIDEO_SOURCE_SIZE, YUVUVREDUCE, DISABLE); + } + + pokeRegisterDWord(regCtrl, value); +} + + + + +/* + * ddk770_videoSetInterpolation + * This function enables/disables the horizontal and vertical interpolation. + * + * Input: + * enableHorzInterpolation - Flag to enable/disable Horizontal interpolation + * enableVertInterpolation - Flag to enable/disable Vertical interpolation + */ +void ddk770_videoSetInterpolation( + unsigned dispCtrl, + unsigned long enableHorzInterpolation, + unsigned long enableVertInterpolation +) +{ + unsigned long value; + unsigned long regCtrl; + + regCtrl = VIDEO_DISPLAY_CTRL + (dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + value = peekRegisterDWord(regCtrl); + + if (enableHorzInterpolation) + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, HORIZONTAL_MODE, INTERPOLATE); + else + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, HORIZONTAL_MODE, REPLICATE); + + if (enableVertInterpolation) + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, VERTICAL_MODE, INTERPOLATE); + else + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, VERTICAL_MODE, REPLICATE); + + pokeRegisterDWord(regCtrl, value); +} + +/* + * ddk770_videoGetInterpolation + * This function gets the horizontal and vertical interpolation enable status. + * + * Input: + * pHorzInterpolationStatus - Pointer to store the horizontal interpolation status + * pVertInterpolationStatus - Pointer to store the vertical interpolation status + */ +void ddk770_videoGetInterpolation( + unsigned long *pHorzInterpolationStatus, + unsigned long *pVertInterpolationStatus +) +{ + unsigned long value; + + value = peekRegisterDWord(VIDEO_DISPLAY_CTRL); + if (pHorzInterpolationStatus != (unsigned long *)0) + { + if (FIELD_VAL_GET(value, VIDEO_DISPLAY_CTRL, HORIZONTAL_MODE) == VIDEO_DISPLAY_CTRL_HORIZONTAL_MODE_INTERPOLATE) + *pHorzInterpolationStatus = 1; + else + *pHorzInterpolationStatus = 0; + } + + if (pHorzInterpolationStatus != (unsigned long *)0) + { + if (FIELD_VAL_GET(value, VIDEO_DISPLAY_CTRL, VERTICAL_MODE) == VIDEO_DISPLAY_CTRL_VERTICAL_MODE_INTERPOLATE) + *pVertInterpolationStatus = 1; + else + *pVertInterpolationStatus = 0; + } +} + +/* + * ddk770_videoSetStartPanningPixel + * This function sets the starting pixel number for smooth pixel panning. + * + * Input: + * startPixel - Starting pixel number for smooth pixel panning + */ +void ddk770_videoSetStartPanningPixel( + unsigned char startPixel +) +{ + pokeRegisterDWord(VIDEO_DISPLAY_CTRL, + peekRegisterDWord(VIDEO_DISPLAY_CTRL) | + FIELD_VALUE(0, VIDEO_DISPLAY_CTRL, PIXEL, startPixel)); +} + +/* + * videoSetGamma + * This function enables/disables gamma control. + * + * Input: + * enableGammaCtrl - The gamma enable control + * + * NOTE: + * The gamma can only be enabled in RGB565 and RGB888. Enable this gamma + * without proper format will have no effect. + */ +void ddk770_videoSetGammaCtrl( + unsigned dispCtrl, + unsigned long enableGammaCtrl +) +{ + unsigned long value; + unsigned long regCtrl; + + regCtrl = VIDEO_DISPLAY_CTRL+(dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + value = peekRegisterDWord(regCtrl); + + if (enableGammaCtrl) + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, GAMMA, ENABLE); + else + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, GAMMA, DISABLE); + + pokeRegisterDWord(regCtrl, value); +} + +/* + * ddk770_isVideoEnable + * This function check whether the video plane is already enabled or not. + * + * Output: + * 0 - Disable + * 1 - Enable + */ +unsigned char ddk770_isVideoEnable() +{ + unsigned long value; + + value = peekRegisterDWord(VIDEO_DISPLAY_CTRL); + + return ((FIELD_VAL_GET(value, VIDEO_DISPLAY_CTRL, PLANE) == VIDEO_DISPLAY_CTRL_PLANE_ENABLE) ? 1 : 0); +} + +/* + * videoSetCtrl + * This function enable/disable the video plane. + * + * Input: + * videoCtrl - Enable/Disable video + */ +static void videoSetCtrl( + disp_control_t dispCtrl, + video_ctrl_t videoCtrl +) +{ + unsigned long value; + unsigned long regCtrl; + + regCtrl = VIDEO_DISPLAY_CTRL+(dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + value = peekRegisterDWord(regCtrl); + + if (videoCtrl == VIDEO_ON) + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, PLANE, ENABLE); + else + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL, PLANE, DISABLE); + + pokeRegisterDWord(regCtrl, value); +} + +/* + * videoSetFormat + * This function sets the video format. + * + * Input: + * videoFormat - The video content format + * * FORMAT_RGB565 - 16-bit RGB 5:6:5 mode + * * FORMAT_YUYV - 16-bit YUYV mode + */ +static void videoSetFormat( + unsigned dispCtrl, + video_format_t videoFormat +) +{ + unsigned long value; + unsigned long regCtrl; + + regCtrl = VIDEO_DISPLAY_CTRL+(dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + value = peekRegisterDWord(regCtrl); + switch (videoFormat) + { + default: + case FORMAT_YUV444: + case FORMAT_RGB565: + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL , FORMAT, 16); + break; + case FORMAT_RGB888: + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL , FORMAT, 32); + break; + case FORMAT_YUYV: + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL , FORMAT, YUV422); + break; + case FORMAT_YUV420: + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL , FORMAT, YUV420); + break; + } + + if(videoFormat == FORMAT_YUV444) + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL , YUV444FMT, ENABLE); + else + value = FIELD_SET(value, VIDEO_DISPLAY_CTRL , YUV444FMT, DISABLE); + + pokeRegisterDWord(regCtrl, value); +} + +/* + * ddk770_videoGetEdgeDetection + * This function gets the information whether the edge detection is enabled or not. + * It also outputs the edge detection value if required. + * This function only works in SM718. SM750 does not support this feature. + * + * Input: + * pEdgeDetectValue - Pointer to a buffer to store the edge detection value. + * + * Note: + * 0 - Edge Detection is disabled + * 1 - Edge Detection is enabled + */ +unsigned long ddk770_videoGetEdgeDetection( + unsigned long *pEdgeDetectValue +) +{ + return 0; +} + +/* + * ddk770_videoSetup + * This function setups the video. This function only works in SM718. + * SM750 does not support edge detection feature. If calling this function + * in SM750, set edgeDetect flag to 0 + * + * Input: + * x - X Coordinate of the video window + * y - Y Coordinate of the video window + * srcWidth - The source video width + * srcHeight - The source video height + * dstWidth - The destination video width + * dstHeight - The destination video height + * doubleBuffer - Double Buffer enable flag + * srcAddress0 - The source of the video buffer 0 to display + * srcAddress1 - The source of the video buffer 1 to display + * (only for double buffering). + * srcPitch - The source video plane pitch in bytes + * srcLineOffset - The source video plane line offset in bytes. + * In normal usage, set it the same as the srcBufferPitch + * videoFormat - Source video format + * edgeDetect - Edge Detection enable flag (can only works with vertical upscaling) + * 0 - Disable + * 1 - Always Enable (alwasy enabled regardless horizontal scaling condition) + * 2 - Auto Enable (only enabled when no horizontal shrink) + * edgeDetectValue - Edge Detection value + * + * Output: + * 0 - Success + * -1 - Fail + */ +unsigned char ddk770_videoSetupEx( + unsigned dispCtrl, + unsigned long x, /* X Coordinate of the video window */ + unsigned long y, /* Y Coordinate of the video window */ + unsigned long srcWidth, /* The source video width */ + unsigned long srcHeight, /* The source video height */ + unsigned long dstWidth, /* The destination video width */ + unsigned long dstHeight, /* The destination video height */ + unsigned long yuvprefetch, /* YUV Prefetch enable flag */ + unsigned long srcAddress0, /* The source of the video buffer 0 to display */ + unsigned long sUAddress, /* U Source Base Address (not used in RGB Space) */ + unsigned long sVAddress, /* V Source Base Address (not used in RGB Space) */ + unsigned long sUVPitch, /* UV plane pitch value in bytes (not used in */ + unsigned long srcPitch, /* The source video plane pitch in bytes */ + unsigned long srcLineOffset, /* The source video plane line offset in bytes. + Set it the same as srcPitch in normal + usage. */ + video_format_t videoFormat, /* Source video format */ + unsigned long edgeDetect, /* Edge Detection enable flag */ + unsigned long edgeDetectValue /* Edge Detection value. SM718 only use bit 9 to 0 */ +) +{ + unsigned long enableEdgeDetect; + /* Save the source video width and height */ + gSrcVideoWidth = srcWidth; + gSrcVideoHeight = srcHeight; + + + /* Disable the video plane first */ + videoSetCtrl(dispCtrl, VIDEO_OFF); + + /* Set the video position */ + ddk770_videoSetPosition(dispCtrl, x, y); + + /* Set the scale factor */ + ddk770_videoScale(dispCtrl, srcWidth, srcHeight, dstWidth, dstHeight); + + /* Set the video format */ + videoSetFormat(dispCtrl, videoFormat); + + + /* Enable 4K Prefetch for bandwidth */ + + if ((videoFormat == FORMAT_RGB888) || (videoFormat == FORMAT_RGB565) || (videoFormat == FORMAT_YUV444)) + ddk770_videoYUVPrefetch(dispCtrl,0); + else + ddk770_videoYUVPrefetch(dispCtrl,1); + + /* Set the buffer pitch */ + ddk770_videoSetPitchOffset(dispCtrl, srcPitch, srcLineOffset); + /* Set the UV buffer pitch */ + ddk770_videoSetUVPitchOffset(dispCtrl, sUVPitch, sUVPitch); + + /* Enable double buffer */ +// videoEnableDoubleBuffer(doubleBuffer); + + /* Set the video buffer 0 and 1 */ + ddk770_videoSetBuffer(dispCtrl, 0, srcAddress0); +// ddk770_videoSetBuffer(dispCtrl, 1, srcAddress1); + + /* Set the video buffer U and V */ + ddk770_videoSetUVBuffer(dispCtrl, sUAddress, sVAddress); + + /* Set the destination video window */ + ddk770_videoSetWindowSize(dispCtrl, dstWidth, dstHeight); + + /* Set the last line */ + ddk770_videoSetLast(dispCtrl, srcWidth, srcHeight); + + /* Set the edge detection enable bit and its value (if applicable) */ + if (edgeDetect == 0) + enableEdgeDetect = 0; + else if (edgeDetect == 1) + enableEdgeDetect = 1; + else + { + /* Only enable the edgeDetection when scaling up vertically and no + shrinking on the horizontal. */ + if ((dstHeight > srcHeight) && (dstWidth >= srcWidth)) + enableEdgeDetect = 1; + else + enableEdgeDetect = 0; + } + + return 0; +} + +/* + * ddk770_videoSetup + * This function setups the video. + * + * Input: + * x - X Coordinate of the video window + * y - Y Coordinate of the video window + * srcWidth - The source video width + * srcHeight - The source video height + * dstWidth - The destination video width + * dstHeight - The destination video height + * doubleBuffer - Double Buffer enable flag + * srcAddress0 - The source of the video buffer 0 to display + * srcAddress1 - The source of the video buffer 1 to display + * (only for double buffering). + * srcPitch - The source video plane pitch in bytes + * srcLineOffset - The source video plane line offset in bytes. + * In normal usage, set it the same as the srcBufferPitch + * videoFormat - Source video format + * + * Output: + * 0 - Success + * -1 - Fail + */ +unsigned char ddk770_videoSetup( + disp_control_t dispCtrl, + unsigned long x, /* X Coordinate of the video window */ + unsigned long y, /* Y Coordinate of the video window */ + unsigned long srcWidth, /* The source video width */ + unsigned long srcHeight, /* The source video height */ + unsigned long dstWidth, /* The destination video width */ + unsigned long dstHeight, /* The destination video height */ + unsigned long yuvprefetch, /* Double Buffer enable flag */ + unsigned long srcAddress0, /* The source of the video buffer 0 to display */ + unsigned long srcAddress1, /* The source of the video buffer 1 to display + (only for double buffering). + */ + unsigned long srcPitch, /* The source video plane pitch in bytes */ + unsigned long srcLineOffset, /* The source video plane line offset in bytes. + Set it the same as srcPitch in normal + usage. */ + video_format_t videoFormat /* Source video format */ +) +{ + return ddk770_videoSetupEx(dispCtrl, x, y, srcWidth, srcHeight, dstWidth, dstHeight, yuvprefetch, + srcAddress0, 0, 0, 0,srcPitch, srcLineOffset, videoFormat, + 0, 0); + +} + +/* + * ddk770_startVideo + * This function starts the video. + */ +void ddk770_startVideo( +unsigned dispCtrl +) +{ + /* Enable the video plane */ + videoSetCtrl(dispCtrl, VIDEO_ON); +} + +/* + * ddk770_stopVideo + * This function stops the video. + */ +void ddk770_stopVideo(unsigned dispCtrl) +{ + /* Just disable the video plane */ + videoSetCtrl(dispCtrl, VIDEO_OFF); +} + + +// Called by other function to get overlay's offset value in performance mode. +// If return 0, it means performance mode disable. +unsigned long videoPerformanceModeStride() +{ + return gPerfModeStride; +} + +//Return overlay YUV buffers location of performance mode. +void videoPerformanceModeBuf( +unsigned long *Cy, unsigned long *Cr, unsigned long *Cb, +unsigned long sX, unsigned long sY) +{ + unsigned long offset; + offset = sY * gPerfModeStride; + + *Cy = CYADDR + offset + sX; + *Cr = CBADDR + (offset >> 1 ) + (sX >> 1); + *Cb = CRADDR + (offset >> 1 ) + (sX >> 1); +} + +//Cheok: Performance mode +//This functon sets up performance mode for JPU and overlay +//The location for YUV stream in DDR should be pre-calculate during SW architect +//In this DDK example, we set it at 96M, 110M and 120M +void videoPerformanceModeEnable(logicalMode_t *pLogicalMode) +{ + unsigned long dcOffset, bufOffset, yAddr, uAddr, vAddr, videoCtrl; + + dcOffset = pLogicalMode->dispCtrl> 1? DC_OFFSET2 : pLogicalMode->dispCtrl * DC_OFFSET; + + yAddr = CYADDR; //CyAddr + uAddr = CRADDR; //CbAddr + vAddr = CBADDR; //CrAddr + + videoCtrl = peekRegisterDWord(VIDEO_DISPLAY_CTRL+dcOffset); + + if (pLogicalMode->x <= PMODE_2K) + { + bufOffset = gPerfModeStride = PMODE_2K; + + //Set JPU to 2K performance mode + pokeRegisterDWord(JPU_PERFORMANCE_MODE, + FIELD_SET(0, JPU_PERFORMANCE_MODE, JPU0, HD) + | FIELD_SET(0, JPU_PERFORMANCE_MODE, JPU1, HD)); + + //Set overlay to 2K performance mode + videoCtrl = FIELD_SET(videoCtrl, VIDEO_DISPLAY_CTRL, JPUP, HD); + } + else + { + bufOffset = gPerfModeStride = PMODE_4K; + + //Set JPU to 4K performance mode + pokeRegisterDWord(JPU_PERFORMANCE_MODE, + FIELD_SET(0, JPU_PERFORMANCE_MODE, JPU0, UHD) + | FIELD_SET(0, JPU_PERFORMANCE_MODE, JPU1, UHD)); + + //Set overlay to 4K performance mode + videoCtrl = FIELD_SET(videoCtrl, VIDEO_DISPLAY_CTRL, JPUP, UHD); + } + + pokeRegisterDWord(VIDEO_FB_ADDRESS +dcOffset, yAddr); + pokeRegisterDWord(VIDEO_FB_WIDTH +dcOffset, (pLogicalMode->x << 16 | bufOffset)); + pokeRegisterDWord(VIDEO_FB_ADDRESS_U+dcOffset, uAddr); + pokeRegisterDWord(VIDEO_FB_WIDTH_U +dcOffset, (pLogicalMode->x << 16 | bufOffset)); + pokeRegisterDWord(VIDEO_FB_ADDRESS_V+dcOffset, vAddr); + pokeRegisterDWord(VIDEO_FB_WIDTH_V +dcOffset, (pLogicalMode->x << 16 | bufOffset)); + pokeRegisterDWord(VIDEO_PLANE_TL +dcOffset, 0); + pokeRegisterDWord(VIDEO_PLANE_BR +dcOffset, ((pLogicalMode->y) << 16 | pLogicalMode->x)); + pokeRegisterDWord(VIDEO_SCALE +dcOffset, 0x0ffc0ffc); + + pokeRegisterDWord(VIDEO_DISPLAY_CTRL+dcOffset, + videoCtrl + | FIELD_SET(0, VIDEO_DISPLAY_CTRL, PLANE, ENABLE) + | FIELD_SET(0, VIDEO_DISPLAY_CTRL, FORMAT, YUV420)); +} + +void videoPerformanceModeDisable(logicalMode_t *pLogicalMode) +{ + unsigned long dcOffset, videoCtrl; + + gPerfModeStride = 0; + + pokeRegisterDWord(JPU_PERFORMANCE_MODE, + FIELD_SET(0, JPU_PERFORMANCE_MODE, JPU0, DISABLE) + | FIELD_SET(0, JPU_PERFORMANCE_MODE, JPU1, DISABLE)); + + dcOffset = (pLogicalMode->dispCtrl > 1)? DC_OFFSET2 : pLogicalMode->dispCtrl * DC_OFFSET; + videoCtrl = peekRegisterDWord(VIDEO_DISPLAY_CTRL+dcOffset); + videoCtrl = FIELD_SET(videoCtrl, VIDEO_DISPLAY_CTRL, JPUP, DISABLE); + pokeRegisterDWord(VIDEO_DISPLAY_CTRL+dcOffset, videoCtrl); +} + diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_video.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_video.h new file mode 100644 index 000000000000..06e36c0ad5fe --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_video.h @@ -0,0 +1,601 @@ +/******************************************************************* +* +* Copyright (c) 2007 by Silicon Motion, Inc. (SMI) +* +* All rights are reserved. Reproduction or in part is prohibited +* without the written consent of the copyright owner. +* +* Video.H --- SM750/SM718 DDK +* This file contains the definitions for the Video functions. +* +*******************************************************************/ +#ifndef _DDK770_VIDEO_H_ +#define _DDK770_VIDEO_H_ + +#include "ddk770_mode.h" + +/**************************************************************************** + Structure and data type definition + ****************************************************************************/ + +/* video format: + - 16-bit RGB 5:6:5 mode + - 16-bit YUYV mode + + Note: The 8-bit index and RGB 8:8:8 formats are not supported + */ +typedef enum _ddk770_video_format_t +{ + FORMAT_RGB565 = 0, + FORMAT_YUV420, + FORMAT_YUYV, + FORMAT_RGB888, + FORMAT_YUV444 +} +video_format_t; + +/* YUV Data Byte Swap */ +typedef enum _ddk770_video_byteswap_t +{ + NORMAL = 0, + SWAP_BYTE +} +video_byteswap_t; + +/* Turn on/off video */ +typedef enum _ddk770_video_sync_source_t +{ + NORMAL_BUFFER = 0, + CAPTURE_BUFFER +} +video_sync_source_t; + +/* FIFO Request Level */ +typedef enum _ddk770_video_fifo_t +{ + FIFO_LEVEL_1 = 0, + FIFO_LEVEL_3, + FIFO_LEVEL_7, + FIFO_LEVEL_11 +} +video_fifo_t; + +/* Turn on/off video */ +typedef enum _ddk770_video_ctrl_t +{ + VIDEO_OFF = 0, + VIDEO_ON +} +video_ctrl_t; + + +/**************************************************************************** + Function prototype + ****************************************************************************/ + +/* + * videoSetWindowAdjustment + * This function sets the video window adjustment. There are usually + * some garbage lines or pixels at the bottom and right of the video + * window. These function will adjust the video window accordingly. + * + * Input: + * widthAdjustment - Width adjustments in pixel + * heightAdjustment - Height adjustment in line + */ +void videoSetWindowAdjustment( + unsigned dispCtrl, + short widthAdjustment, + short heightAdjustment +); + +/* + * videoGetWindowAdjustment + * This function gets the video window adjustment. + * + * Input: + * widthAdjustment - Width adjustments in pixel + * heightAdjustment - Height adjustment in line + */ +void videoGetWindowAdjustment( + short *pWidthAdjustment, + short *pHeightAdjustment +); + +/* + * videoGetCurrentBufferDisplay + * This function gets the current buffer used by SM50x to display on the screen + * + * Return: + * 0 - Buffer 0 + * 1 - Buffer 1 + */ +// unsigned char videoGetCurrentBufferDisplay(); + +/* + * videoEnableDoubleBuffer + * This function enables/disables the double buffer usage + * + * Input: + * enable - Flag to enable/disable the double buffer. + */ +#if 0 +void videoEnableDoubleBuffer( + unsigned long enable +); +#endif + +/* + * ddk770_videoGetBufferStatus + * This function gets the status of the video buffer, either the buffer + * has been used or not. + * + * Input: + * bufferIndex - The index of the buffer which size to be retrieved + * + * Output: + * 0 - No flip pending + * 1 - Flip pending + */ +unsigned long ddk770_videoGetBufferStatus( + unsigned long bufferIndex +); + +/* + * ddk770_videoGetBuffer + * This function gets the video buffer + * + * Input: + * bufferIndex - The index of the buffer to get + * + * Output: + * The video buffer of the requested index. + */ +unsigned long ddk770_videoGetBuffer( + unsigned char bufferIndex +); + +/* + * ddk770_videoSetBuffer + * This function sets the video buffer + * + * Input: + * bufferIndex - The index of the buffer to be set + * bufferStartAddress - The starting address of the buffer + */ +void ddk770_videoSetBuffer( + unsigned dispCtrl, + unsigned char bufferIndex, /* The index of the buffer to be set. */ + unsigned long bufferStartAddress /* Video buffer with 128-bit alignment */ +); +/* + * ddk770_videoSetUVBuffer + * This function sets the video buffer of U and V + * + * Input: + * bufferIndex - The index of the buffer to be set + * bufferStartAddress - The starting address of the buffer + */ +void ddk770_videoSetUVBuffer( + unsigned dispCtrl, + unsigned long bufferStartUAddress, /* Video buffer with 128-bit alignment */ + unsigned long bufferStartVAddress /* Video buffer with 128-bit alignment */ +); + +/* + * ddk770_videoSetPitchOffset + * This function sets the video plane pitch and offset + * + * Input: + * pitch - Number of bytes per line of the video plane + * specified in 128-bit aligned bytes. + * lineOffset - Number of 128-bit aligned bytes per line + * of the video plane. + */ +void ddk770_videoSetPitchOffset( + unsigned dispCtrl, + unsigned short pitch, + unsigned short lineOffset +); + +/* + * ddk770_videoSetUVPitchOffset + * This function sets the video plane pitch and offset of U and V + * + * Input: + * pitch - Number of bytes per line of the video plane + * specified in 128-bit aligned bytes. + * lineOffset - Number of 128-bit aligned bytes per line + * of the video plane. + */ +void ddk770_videoSetUVPitchOffset( + unsigned dispCtrl, + unsigned short pitch, + unsigned short lineOffset +); + +/* + * ddk770_videoGetPitch + * This function gets the video plane pitch + * + * Output: + * pitch - Number of bytes per line of the video plane + * specified in 128-bit aligned bytes. + */ +unsigned short ddk770_videoGetPitch(void); + +/* + * ddk770_videoGetLineOffset + * This function gets the video plane line offset + * + * Output: + * lineOffset - Number of 128-bit aligned bytes per line + * of the video plane. + */ +unsigned short ddk770_videoGetLineOffset(void); +/* + * ddk770_videoSetLast + * This function sets the video source last lines and width. + * + * Input: + * + * width - Video source width + * height - Video source height + */ +void ddk770_videoSetLast( + unsigned dispCtrl, + unsigned long width, + unsigned long height +); + +/* + * ddk770_videoSetWindowSize + * This function sets the video window size. + * + * Input: + * width - Video Window width + * height - Video Window height + */ +void ddk770_videoSetWindowSize( + unsigned dispCtrl, + unsigned long width, + unsigned long height +); + +/* + * ddk770_videoGetWindowSize + * This function gets the video window size. + * + * Output: + * width - Video Window width + * height - Video Window height + */ +void ddk770_videoGetWindowSize( + unsigned dispCtrl, + unsigned long *pWidth, + unsigned long *pHeight +); + +/* + * ddk770_videoSetPosition + * This function sets the video starting coordinate position. + * + * Input: + * startX - X Coordinate of the video window starting position + * startY - Y Coordinate of the video window starting position + */ +void ddk770_videoSetPosition( + unsigned dispCtrl, + unsigned long startX, + unsigned long startY +); + +/* + * ddk770_videoSetConstants + * This function sets the video constants. The actual component will be + * added by this constant to get the expected component value. + * + * Input: + * yConstant - Y Constant Value + * redConstant - Red Constant Value + * greenConstant - Green Constant Value + * blueConstant - Blue Constant Value + */ +void ddk770_videoSetConstants( + unsigned dispCtrl, + unsigned char yConstant, /* Y Adjustment */ + unsigned char redConstant, /* Red Conversion constant */ + unsigned char greenConstant, /* Green Conversion constant */ + unsigned char blueConstant /* Blue Conversion constant */ +); + +/* + * ddk770_videoSetInitialScale + * This function sets the video buffer initial vertical scale. + * + * Input: + * bufferIndex - Index of the buffer which vertical scale value + * to be set. + * bufferInitScale - Buffer Initial vertical scale value + */ +void ddk770_videoSetInitialScale( + unsigned dispCtrl, + unsigned short InitScaleHorizontal, + unsigned short InitScaleVertical +); + +/* + * videoSetFIFOLevel + * This function sets the video FIFO Request Level. + * + * Input: + * videoSource - Buffer source selection + */ +#if 0 +void videoSetFIFOLevel( + video_fifo_t videoFIFO +); +#endif +/* + * videoSetSourceBuffer + * This function sets the video to use the capture buffer as the source. + * + * Input: + * videoSource - Buffer source selection + */ +#if 0 +void videoSetSourceBuffer( + video_sync_source_t videoSource +); +#endif + +/* + * ddk770_videoSwapYUVByte + * This function swaps the YUV data byte. + * + * Input: + * byteSwap - Flag to enable/disable YUV data byte swap. + */ +void ddk770_videoSwapYUVByte( + unsigned dispCtrl, + video_byteswap_t byteSwap +); + + +void ddk770_videoYUVPrefetch( + unsigned dispCtrl, + unsigned long enable +); + + + +/* + * ddk770_videoSetInterpolation + * This function enables/disables the horizontal and vertical interpolation. + * + * Input: + * enableHorzInterpolation - Flag to enable/disable Horizontal interpolation + * enableVertInterpolation - Flag to enable/disable Vertical interpolation + */ +void ddk770_videoSetInterpolation( + unsigned dispCtrl, + unsigned long enableHorzInterpolation, + unsigned long enableVertInterpolation +); + +/* + * ddk770_videoGetInterpolation + * This function gets the horizontal and vertical interpolation enable status. + * + * Input: + * pHorzInterpolationStatus - Pointer to store the horizontal interpolation status + * pVertInterpolationStatus - Pointer to store the vertical interpolation status + */ +void ddk770_videoGetInterpolation( + unsigned long *pHorzInterpolationStatus, + unsigned long *pVertInterpolationStatus +); + +/* + * ddk770_videoSetStartPanningPixel + * This function sets the starting pixel number for smooth pixel panning. + * + * Input: + * startPixel - Starting pixel number for smooth pixel panning + */ +void ddk770_videoSetStartPanningPixel( + unsigned char startPixel +); + +/* + * videoSetGamma + * This function enables/disables gamma control. + * + * Input: + * enableGammaCtrl - The gamma enable control + * + * NOTE: + * The gamma can only be enabled in RGB565 and RGB888. Enable this gamma + * without proper format will have no effect. + */ +void ddk770_videoSetGammaCtrl( + unsigned dispCtrl, + unsigned long enableGammaCtrl +); + +/* + * ddk770_isVideoEnable + * This function check whether the video plane is already enabled or not. + * + * Output: + * 0 - Disable + * 1 - Enable + */ +unsigned char ddk770_isVideoEnable(void); + +/* + * ddk770_videoSetEdgeDetection + * This function enable/disable the edge detection and fill out the edge detection + * value as well. This function only works in SM718. SM750 does not support this + * feature. + * + * Input: + * enableEdgeDetect - Enable/Disable Edge Detection + * edgeDetectValue - The Edge Detection value. This is the difference (delta) + * of the pixel colors to be considered as an edge. + * + * Note: + * This edge correction only works in up-scale video. + */ +void ddk770_videoSetEdgeDetection( + unsigned long enableEdgeDetect, + unsigned long edgeDetectValue +); + +/* + * ddk770_videoGetEdgeDetection + * This function gets the information whether the edge detection is enabled or not. + * It also outputs the edge detection value if required. + * This function only works in SM718. SM750 does not support this feature. + * + * Input: + * pEdgeDetectValue - Pointer to a buffer to store the edge detection value. + * + * Note: + * 0 - Edge Detection is disabled + * 1 - Edge Detection is enabled + */ +unsigned long ddk770_videoGetEdgeDetection( + unsigned long *pEdgeDetectValue +); + +/* + * ddk770_videoSetupEx + * This function setups the video. It only applies in SM718 + * + * Input: + * x - X Coordinate of the video window + * y - Y Coordinate of the video window + * srcWidth - The source video width + * srcHeight - The source video height + * dstWidth - The destination video width + * dstHeight - The destination video height + * doubleBuffer - Double Buffer enable flag + * srcAddress0 - The source of the video buffer 0 to display + * srcAddress1 - The source of the video buffer 1 to display + * (only for double buffering). + * srcPitch - The source video plane pitch in bytes + * srcLineOffset - The source video plane line offset in bytes. + * In normal usage, set it the same as the srcBufferPitch + * videoFormat - Source video format + * edgeDetect - Edge Detection enable flag + * edgeDetectValue - Edge Detection value + * + * Output: + * 0 - Success + * -1 - Fail + */ +unsigned char ddk770_videoSetupEx( + unsigned dispCtrl, + unsigned long x, /* X Coordinate of the video window */ + unsigned long y, /* Y Coordinate of the video window */ + unsigned long srcWidth, /* The source video width */ + unsigned long srcHeight, /* The source video height */ + unsigned long dstWidth, /* The destination video width */ + unsigned long dstHeight, /* The destination video height */ + unsigned long yuvprefetch, /* Double Buffer enable flag */ + unsigned long srcAddress0, /* The source of the video buffer 0 to display */ + unsigned long sUAddress, /* U Source Base Address (not used in RGB Space) */ + unsigned long sVAddress, /* V Source Base Address (not used in RGB Space) */ + unsigned long sUVPitch, /* UV plane pitch value in bytes (not used in */ + unsigned long srcPitch, /* The source video plane pitch in bytes */ + unsigned long srcLineOffset, /* The source video plane line offset in bytes. + Set it the same as srcPitch in normal + usage. */ + video_format_t videoFormat, /* Source video format */ + unsigned long edgeDetect, /* Edge Detection enable flag */ + unsigned long edgeDetectValue /* Edge Detection value. SM718 only use bit 9 to 0 */ +); + +/* + * ddk770_videoSetup + * This function setups the video. + * + * Input: + * x - X Coordinate of the video window + * y - Y Coordinate of the video window + * srcWidth - The source video width + * srcHeight - The source video height + * dstWidth - The destination video width + * dstHeight - The destination video height + * doubleBuffer - Double Buffer enable flag + * srcAddress0 - The source of the video buffer 0 to display + * srcAddress1 - The source of the video buffer 1 to display + * (only for double buffering). + * srcPitch - The source video plane pitch in bytes + * srcLineOffset - The source video plane line offset in bytes. + * In normal usage, set it the same as the srcBufferPitch + * videoFormat - Source video format + * + * Output: + * 0 - Success + * -1 - Fail + */ +unsigned char ddk770_videoSetup( + disp_control_t dispCtrl, + unsigned long x, /* X Coordinate of the video window */ + unsigned long y, /* Y Coordinate of the video window */ + unsigned long srcWidth, /* The source video width */ + unsigned long srcHeight, /* The source video height */ + unsigned long dstWidth, /* The destination video width */ + unsigned long dstHeight, /* The destination video height */ + unsigned long yuvprefetch, /* Double Buffer enable flag */ + unsigned long srcAddress0, /* The source of the video buffer 0 to display */ + unsigned long srcAddress1, /* The source of the video buffer 1 to display + (only for double buffering). + */ + unsigned long srcPitch, /* The source video plane pitch in bytes */ + unsigned long srcLineOffset, /* The source video plane line offset in bytes. + Set it the same as srcPitch in normal + usage. */ + video_format_t videoFormat /* Source video format */ +); + +/* + * ddk770_startVideo + * This function starts the video. + */ +void ddk770_startVideo(unsigned dispCtrl); + +/* + * ddk770_stopVideo + * This function stops the video. + */ +void ddk770_stopVideo(unsigned dispCtrl); + +//Since performance mode has special requirement of 256 byte aligned buffer +//and occupy a lot of memory, it's better to pre-define some available fixed locations. +#define CYADDR MB(96) +#define CBADDR MB(120) +#define CRADDR MB(110) + + +// Called by other function to get overlay's offset value in performance mode. +// If return 0, it means performance mode disable. +unsigned long videoPerformanceModeStride(void); + +//Return overlay YUV buffers location of performance mode. +void videoPerformanceModeBuf( +unsigned long *Cy, unsigned long *Cr, unsigned long *Cb, +unsigned long sX, unsigned long sY); + +//Cheok: Performance mode +//This functon sets up performance mode for JPU and overlay +//The location for YUV stream in DDR should be pre-calculate during SW architect +//In this DDK example, we set it at 96M, 110M and 120M +void videoPerformanceModeEnable(logicalMode_t *pLogicalMode); + +void videoPerformanceModeDisable(logicalMode_t *pLogicalMode); + + +#endif /* _VIDEO_H_ */ diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_wm8978.c b/drivers/gpu/drm/smidrm/ddk770/ddk770_wm8978.c new file mode 100644 index 000000000000..1087c04dae33 --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_wm8978.c @@ -0,0 +1,196 @@ +#include +#include "ddk770_reg.h" +#include "ddk770_help.h" +#include "ddk770_swi2c.h" +#include "ddk770_hwi2c.h" +#include "ddk770_wm8978.h" + +#define WM8978_ADDR 0x34 + +static unsigned short WM8978_REGVAL[58]= +{ + 0X0000,0X0000,0X0000,0X0000,0X0050,0X0000,0X0140,0X0000, + 0X0000,0X0000,0X0000,0X00FF,0X00FF,0X0000,0X0100,0X00FF, + 0X00FF,0X0000,0X012C,0X002C,0X002C,0X002C,0X002C,0X0000, + 0X0032,0X0000,0X0000,0X0000,0X0000,0X0000,0X0000,0X0000, + 0X0038,0X000B,0X0032,0X0000,0X0008,0X000C,0X0093,0X00E9, + 0X0000,0X0000,0X0000,0X0000,0X0003,0X0010,0X0010,0X0100, + 0X0100,0X0002,0X0001,0X0001,0X0039,0X0039,0X0039,0X0039, + 0X0001,0X0001 +}; + +static unsigned char WM8978_Write_Reg(unsigned char reg, unsigned short val) +{ + unsigned char res; + unsigned char RegAddr; + unsigned char RegValue; + RegAddr = (reg<<1)|((unsigned char)((val>>8)&0x01)); + RegValue = (unsigned char)val; + + res = ddk770_hwI2CWriteReg(0, WM8978_ADDR, RegAddr, RegValue); + + if(res == 0) + WM8978_REGVAL[reg]=val; + return res; +} + +static unsigned short WM8978_Read_Reg(unsigned char reg) +{ + return WM8978_REGVAL[reg]; +} + +static void WM8978_MIC_Gain(unsigned char gain) +{ + gain &= 0x3F; + WM8978_Write_Reg(45, gain); + WM8978_Write_Reg(46, gain|1<<8); +} + +static void WM8978_LINEIN_Gain(unsigned char gain) +{ + unsigned short regval; + gain &= 0x07; + regval = WM8978_Read_Reg(47); + regval &= ~(7<<4); + WM8978_Write_Reg(47, regval|gain<<4); + regval = WM8978_Read_Reg(48); + regval &= ~(7<<4); + WM8978_Write_Reg(48,regval|gain<<4); +} + +static void WM8978_AUX_Gain(unsigned char gain) +{ + unsigned short regval; + gain &= 0x07; + regval = WM8978_Read_Reg(47); + regval &= ~(7<<0); + WM8978_Write_Reg(47, regval|gain<<0); + regval = WM8978_Read_Reg(48); + regval &= ~(7<<0); + WM8978_Write_Reg(48, regval|gain<<0); +} + + +static void WM8978_Output_Cfg(unsigned char dacen, unsigned char bpsen) +{ + unsigned short regval = 0; + if(dacen) + regval |= 1<<0; + if(bpsen) + { + regval |= 1<<1; + regval |= 5<<2; + } + WM8978_Write_Reg(50,regval); + WM8978_Write_Reg(51,regval); +} + +static void WM8978_ADDA_Cfg(unsigned char dacen, unsigned char adcen) +{ + unsigned short regval; + regval = WM8978_Read_Reg(3); + if(dacen) + regval |= 3<<0; + else + regval &= ~(3<<0); + WM8978_Write_Reg(3, regval); + regval = WM8978_Read_Reg(2); + if(adcen) + regval |= 3<<0; + else + regval &= ~(3<<0); + WM8978_Write_Reg(2, regval); +} + +static void WM8978_Input_Cfg(unsigned char micen, unsigned char lineinen, unsigned char auxen) +{ + unsigned short regval; + regval = WM8978_Read_Reg(2); + if(micen) + regval |= 3<<2; + else + regval &= ~(3<<2); + WM8978_Write_Reg(2, regval); + regval = WM8978_Read_Reg(44); + if(micen) + regval |= 3<<4|3<<0; + else + regval &= ~(3<<4|3<<0); + WM8978_Write_Reg(44, regval); + if(lineinen) + WM8978_LINEIN_Gain(5); + else + WM8978_LINEIN_Gain(0); + if(auxen) + WM8978_AUX_Gain(7); + else + WM8978_AUX_Gain(0); +} + +static void WM8978_I2S_Cfg(unsigned char fmt, unsigned char len) +{ + fmt &= 0x03; + len &= 0x03; + WM8978_Write_Reg(4, (fmt<<3)|(len<<5)); +} + + +unsigned char ddk770_WM8978_Init(void) +{ + unsigned char Res; + + ddk770_hwI2CInit(0); + + Res = WM8978_Write_Reg(0, 0); + if(Res) + return 1; + /* Set volume to 0 can improve the noise when init codec */ + ddk770_WM8978_HPvol_Set(0, 0); + ddk770_WM8978_SPKvol_Set(0); + WM8978_Write_Reg(1, 0x1B); + WM8978_Write_Reg(2, 0x1B0); + WM8978_Write_Reg(3, 0x6C); + WM8978_Write_Reg(6, 0); + WM8978_Write_Reg(43, 1<<4); + WM8978_Write_Reg(47, 1<<8); + WM8978_Write_Reg(48, 1<<8); + WM8978_Write_Reg(49, 1<<1); + WM8978_Write_Reg(10, 1<<3); + WM8978_Write_Reg(14, 1<<3); + + /* Playback and record setup */ + + WM8978_I2S_Cfg(2, 0); + WM8978_ADDA_Cfg(1, 1); + WM8978_Input_Cfg(1, 1, 1); + WM8978_MIC_Gain(63); //R45&R46, MIC gain (record gain, 0 ~ 63) + WM8978_Output_Cfg(1, 0); + + return 0; +} + +void ddk770_WM8978_DeInit(void) +{ + ddk770_hwI2CClose(0); + /* To Do: Here should be read device register not globle array.*/ + WM8978_Write_Reg(0, 0); +} + +void ddk770_WM8978_HPvol_Set(unsigned char voll, unsigned char volr) +{ + voll &= 0x3F; + volr &= 0x3F; + if(voll == 0)voll |= 1<<6; + if(volr == 0)volr |= 1<<6; + WM8978_Write_Reg(52, voll); + WM8978_Write_Reg(53, volr|(1<<8)); +} + + +void ddk770_WM8978_SPKvol_Set(unsigned char volx) +{ + volx &= 0x3F; + if(volx == 0)volx |= 1<<6; + WM8978_Write_Reg(54, volx); + WM8978_Write_Reg(55, volx|(1<<8)); +} diff --git a/drivers/gpu/drm/smidrm/ddk770/ddk770_wm8978.h b/drivers/gpu/drm/smidrm/ddk770/ddk770_wm8978.h new file mode 100644 index 000000000000..c49d4af8927a --- /dev/null +++ b/drivers/gpu/drm/smidrm/ddk770/ddk770_wm8978.h @@ -0,0 +1,13 @@ +#ifndef __DDK770_WM8978_H +#define __DDK770_WM8978_H + + +unsigned char ddk770_WM8978_Init(void); +void ddk770_WM8978_DeInit(void); +void ddk770_WM8978_HPvol_Set(unsigned char voll, unsigned char volr); +void ddk770_WM8978_SPKvol_Set(unsigned char volx); + +extern int hwi2c_en; + + +#endif diff --git a/drivers/gpu/drm/smidrm/hw750.c b/drivers/gpu/drm/smidrm/hw750.c new file mode 100644 index 000000000000..eae9afce5cf6 --- /dev/null +++ b/drivers/gpu/drm/smidrm/hw750.c @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2023, SiliconMotion Inc. + + +#include "ddk750/ddk750_mode.h" +#include "ddk750/ddk750_help.h" +#include "ddk750/ddk750_regdc.h" +#include "ddk750/ddk750_defs.h" +#include "ddk750/ddk750_display.h" +#include "ddk750/ddk750_2d.h" +#include "ddk750/ddk750_power.h" +#include "ddk750/ddk750_edid.h" +#include "ddk750/ddk750_cursor.h" +#include "ddk750/ddk750_swi2c.h" +#include "ddk750/ddk750_hwi2c.h" + + +#ifdef USE_HDMICHIP +#include "ddk750/ddk750_sii9022.h" +#endif + + + +struct smi_750_register{ + /* registers for save */ + uint32_t system_ctrl, misc_ctrl,gpio_mux, localmem_arbitration; + uint32_t pcimem_arbitration, raw_int, int_status, int_mask; + uint32_t current_gate, mode0_gate, mode1_gate, power_mode_ctrl; + uint32_t pci_master_base, primary_pll_ctrl, secondary_pll_ctrl, vga_pll0_ctrl; + uint32_t vga_pll1_ctrl, mxclk_pll_ctrl, vga_configuration; + + uint32_t de_stretch_format, de_masks, de_window_width, de_control; + + uint32_t primary_display_ctrl,primary_pan_ctrl,primary_color_key,primary_fb_address; + uint32_t primary_fb_width, primary_window_width,primary_window_height, primary_plane_tl; + uint32_t primary_plane_br, primary_horizontal_total, primary_horizontal_sync, primary_vertical_total; + uint32_t primary_vertical_sync, primary_current_line; + + uint32_t secondary_display_ctrl, secondary_fb_address, secondary_fb_width; + uint32_t secondary_horizontal_total, secondary_horizontal_sync; + uint32_t secondary_vertical_total, secondary_vertical_sync; + uint32_t secondary_auto_centering_tl, secondary_auto_centering_br; + uint32_t secondary_scale, secondary_hwc_address, secondary_hwc_location; + uint32_t secondary_hwc_color_12, secondary_hwc_color_3; +}; + + + +void hw750_suspend(struct smi_750_register * pSave) +{ + + /* save mmio registers */ + + pSave->system_ctrl = PEEK32(SYSTEM_CTRL); + pSave->misc_ctrl = PEEK32(MISC_CTRL); + pSave->gpio_mux = PEEK32(GPIO_MUX); + pSave->localmem_arbitration = PEEK32(LOCALMEM_ARBITRATION); + pSave->pcimem_arbitration = PEEK32(PCIMEM_ARBITRATION); + pSave->raw_int = PEEK32(RAW_INT); + pSave->int_status = PEEK32(INT_STATUS); + pSave->int_mask = PEEK32(INT_MASK); + pSave->current_gate = PEEK32(CURRENT_GATE); + pSave->mode0_gate = PEEK32(MODE0_GATE); + pSave->mode1_gate = PEEK32(MODE1_GATE); + pSave->power_mode_ctrl = PEEK32(POWER_MODE_CTRL); + pSave->pci_master_base = PEEK32(PCI_MASTER_BASE); + pSave->primary_pll_ctrl = PEEK32(PRIMARY_PLL_CTRL); + pSave->secondary_pll_ctrl = PEEK32(SECONDARY_PLL_CTRL); + pSave->vga_pll0_ctrl = PEEK32(VGA_PLL0_CTRL); + pSave->vga_pll1_ctrl = PEEK32(VGA_PLL1_CTRL); + pSave->mxclk_pll_ctrl = PEEK32(MXCLK_PLL_CTRL); + pSave->vga_configuration = PEEK32(VGA_CONFIGURATION); + +#if 0// for 2d, JUST HOLD IT. + pSave->de_stretch_format = PEEK32(DE_STRETCH_FORMAT); + pSave->de_masks = PEEK32(DE_MASKS); + pSave->de_window_width = PEEK32(DE_WINDOW_WIDTH); + pSave->de_control = PEEK32(DE_CONTROL); +#endif + pSave->primary_display_ctrl = PEEK32(PRIMARY_DISPLAY_CTRL); + pSave->primary_pan_ctrl = PEEK32(PRIMARY_PAN_CTRL); + pSave->primary_color_key = PEEK32(PRIMARY_COLOR_KEY); + pSave->primary_fb_address = PEEK32(PRIMARY_FB_ADDRESS); + pSave->primary_fb_width = PEEK32(PRIMARY_FB_WIDTH); + pSave->primary_window_width= PEEK32(PRIMARY_WINDOW_WIDTH); + pSave->primary_window_height= PEEK32(PRIMARY_WINDOW_HEIGHT); + pSave->primary_plane_tl= PEEK32(PRIMARY_PLANE_TL); + pSave->primary_plane_br= PEEK32(PRIMARY_PLANE_BR); + pSave->primary_horizontal_total = PEEK32(PRIMARY_HORIZONTAL_TOTAL); + pSave->primary_horizontal_sync = PEEK32(PRIMARY_HORIZONTAL_SYNC); + pSave->primary_vertical_total = PEEK32(PRIMARY_VERTICAL_TOTAL); + pSave->primary_vertical_sync = PEEK32(PRIMARY_VERTICAL_SYNC); + pSave->primary_current_line = PEEK32(PRIMARY_CURRENT_LINE); +#if 0 //for hw cursor, JUST HOLD IT. + pSave->primary_hwc_address = PEEK32(PRIMARY_HWC_ADDRESS); + pSave->primary_hwc_location = PEEK32(PRIMARY_HWC_LOCATION); + pSave->primary_hwc_color_12 = PEEK32(PRIMARY_HWC_COLOR_12); + pSave->primary_hwc_color_3 = PEEK32(PRIMARY_HWC_COLOR_3); +#endif + + pSave->secondary_display_ctrl = PEEK32(SECONDARY_DISPLAY_CTRL); + pSave->secondary_fb_address = PEEK32(SECONDARY_FB_ADDRESS); + pSave->secondary_fb_width = PEEK32(SECONDARY_FB_WIDTH); + pSave->secondary_horizontal_total = PEEK32(SECONDARY_HORIZONTAL_TOTAL); + pSave->secondary_horizontal_sync = PEEK32(SECONDARY_HORIZONTAL_SYNC); + pSave->secondary_vertical_total = PEEK32(SECONDARY_VERTICAL_TOTAL); + pSave->secondary_vertical_sync = PEEK32(SECONDARY_VERTICAL_SYNC); + pSave->secondary_scale = PEEK32(SECONDARY_SCALE); + pSave->secondary_hwc_address = PEEK32(SECONDARY_HWC_ADDRESS); + pSave->secondary_hwc_location = PEEK32(SECONDARY_HWC_LOCATION); + pSave->secondary_hwc_color_12 = PEEK32(SECONDARY_HWC_COLOR_12); + pSave->secondary_hwc_color_3 = PEEK32(SECONDARY_HWC_COLOR_3); + pSave->secondary_auto_centering_tl = PEEK32(SECONDARY_AUTO_CENTERING_TL); + pSave->secondary_auto_centering_br = PEEK32(SECONDARY_AUTO_CENTERING_BR); + +} + +void hw750_resume(struct smi_750_register * pSave) +{ + /* restore mmio registers */ + POKE32(SYSTEM_CTRL, pSave->system_ctrl); + POKE32(MISC_CTRL, pSave->misc_ctrl); + POKE32(GPIO_MUX, pSave->gpio_mux); + POKE32(LOCALMEM_ARBITRATION, pSave->localmem_arbitration); + POKE32(PCIMEM_ARBITRATION, pSave->pcimem_arbitration); + POKE32(RAW_INT, pSave->raw_int); + POKE32(INT_STATUS, pSave->int_status); + POKE32(INT_MASK, pSave->int_mask); + POKE32(CURRENT_GATE, pSave->current_gate); + + POKE32(MODE0_GATE, pSave->mode0_gate); + POKE32(MODE1_GATE, pSave->mode1_gate); + POKE32(POWER_MODE_CTRL, pSave->power_mode_ctrl); + POKE32(PCI_MASTER_BASE, pSave->pci_master_base); + POKE32(PRIMARY_PLL_CTRL, pSave->primary_pll_ctrl); + POKE32(SECONDARY_PLL_CTRL, pSave->secondary_pll_ctrl); + POKE32(VGA_PLL0_CTRL, pSave->vga_pll0_ctrl); + POKE32(VGA_PLL1_CTRL, pSave->vga_pll1_ctrl); + POKE32(MXCLK_PLL_CTRL, pSave->mxclk_pll_ctrl); + POKE32(VGA_CONFIGURATION, pSave->vga_configuration); + + POKE32(PRIMARY_DISPLAY_CTRL, pSave->primary_display_ctrl); + POKE32(PRIMARY_PAN_CTRL, pSave->primary_pan_ctrl); + POKE32(PRIMARY_COLOR_KEY, pSave->primary_color_key ); + POKE32(PRIMARY_FB_ADDRESS, pSave->primary_fb_address); + POKE32(PRIMARY_FB_WIDTH, pSave->primary_fb_width); + POKE32(PRIMARY_WINDOW_WIDTH, pSave->primary_window_width); + POKE32(PRIMARY_WINDOW_HEIGHT, pSave->primary_window_height); + POKE32(PRIMARY_PLANE_TL, pSave->primary_plane_tl); + POKE32(PRIMARY_PLANE_BR, pSave->primary_plane_br); + POKE32(PRIMARY_HORIZONTAL_TOTAL, pSave->primary_horizontal_total); + POKE32(PRIMARY_HORIZONTAL_SYNC, pSave->primary_horizontal_sync); + POKE32(PRIMARY_VERTICAL_TOTAL, pSave->primary_vertical_total); + POKE32(PRIMARY_VERTICAL_SYNC, pSave->primary_vertical_sync); + POKE32(PRIMARY_CURRENT_LINE, pSave->primary_current_line); + + POKE32(SECONDARY_DISPLAY_CTRL, pSave->secondary_display_ctrl); + POKE32(SECONDARY_FB_ADDRESS, pSave->secondary_fb_address); + POKE32(SECONDARY_FB_WIDTH, pSave->secondary_fb_width); + POKE32(SECONDARY_HORIZONTAL_TOTAL, pSave->secondary_horizontal_total); + + POKE32(SECONDARY_HORIZONTAL_SYNC, pSave->secondary_horizontal_sync); + POKE32(SECONDARY_VERTICAL_TOTAL, pSave->secondary_vertical_total); + POKE32(SECONDARY_VERTICAL_SYNC, pSave->secondary_vertical_sync); + POKE32(SECONDARY_SCALE, pSave->secondary_scale); + +#if 0 + POKE32(SECONDARY_HWC_ADDRESS, pSave->secondary_hwc_address); + POKE32(SECONDARY_HWC_LOCATION, pSave->secondary_hwc_location); + POKE32(SECONDARY_HWC_COLOR_12, pSave->secondary_hwc_color_12); + POKE32(SECONDARY_HWC_COLOR_3, pSave->secondary_hwc_color_3); +#endif + POKE32(SECONDARY_AUTO_CENTERING_TL, pSave->secondary_auto_centering_tl); + POKE32(SECONDARY_AUTO_CENTERING_BR, pSave->secondary_auto_centering_br); + + +#if 0 //HOLD FOR 2D + POKE32(DE_STRETCH_FORMAT, pSave->de_stretch_format); + POKE32(DE_MASKS, pSave->de_masks); + POKE32(DE_WINDOW_WIDTH, pSave->de_window_width); + POKE32(DE_CONTROL, pSave->de_control); +#endif + +} + +void hw750_set_base(int display,int pitch,int base_addr) +{ + + if(display == 0) + { + pokeRegisterDWord(PRIMARY_FB_WIDTH, + FIELD_VALUE(0, PRIMARY_FB_WIDTH, WIDTH, pitch) + | FIELD_VALUE(0, PRIMARY_FB_WIDTH, OFFSET, pitch)); + setDisplayBaseAddress(CHANNEL0_CTRL, base_addr); + } + else + { + pokeRegisterDWord(SECONDARY_FB_WIDTH, + FIELD_VALUE(0, SECONDARY_FB_WIDTH, WIDTH, pitch) + | FIELD_VALUE(0, SECONDARY_FB_WIDTH, OFFSET, pitch)); + setDisplayBaseAddress(CHANNEL1_CTRL, base_addr); + } +} + +void hw750_set_dpms(int display,int state) +{ + if(display == 0) + { + setDisplayControl(CHANNEL0_CTRL, state); /* Turn on Primary Control */ + setPath(SMI0_PATH, CHANNEL0_CTRL, state); + } + else + { + setDisplayControl(CHANNEL1_CTRL, state); /* Turn on Secondary control */ + setPath(SMI1_PATH, CHANNEL1_CTRL, state); + } +} +int hw750_en_dis_interrupt(int status, int pipe) +{ + if(status == 0) + { + pokeRegisterDWord(INT_MASK, (pipe == CHANNEL1_CTRL) ? + FIELD_SET(0, INT_MASK, SECONDARY_VSYNC, DISABLE): + FIELD_SET(0, INT_MASK, PRIMARY_VSYNC, DISABLE)); + } + else + { + pokeRegisterDWord(INT_MASK, (pipe == CHANNEL1_CTRL) ? + FIELD_SET(0, INT_MASK, SECONDARY_VSYNC, ENABLE): + FIELD_SET(0, INT_MASK, PRIMARY_VSYNC, ENABLE)); + } + return 0; +} + + + +int hw750_check_vsync_interrupt(int path) +{ + + unsigned long value1,value2; + + value1 = peekRegisterDWord(RAW_INT); + value2 = peekRegisterDWord(INT_MASK); + + if(path == CHANNEL0_CTRL) + { + if ((FIELD_GET(value1, RAW_INT, PRIMARY_VSYNC) == RAW_INT_PRIMARY_VSYNC_ACTIVE) + &&(FIELD_GET(value2, INT_MASK, PRIMARY_VSYNC) == INT_MASK_PRIMARY_VSYNC_ENABLE)) + { + return true; + } + }else{ + if ((FIELD_GET(value1, RAW_INT, SECONDARY_VSYNC) == RAW_INT_SECONDARY_VSYNC_ACTIVE) + &&(FIELD_GET(value2, INT_MASK, SECONDARY_VSYNC) == INT_MASK_SECONDARY_VSYNC_ENABLE)) + { + return true; + } + } + return false; +} + + + +void hw750_clear_vsync_interrupt(int path) +{ + + unsigned long value; + + value = peekRegisterDWord(RAW_INT); + + if(path == CHANNEL0_CTRL) + { + + pokeRegisterDWord(RAW_INT, FIELD_SET(value, RAW_INT, PRIMARY_VSYNC, CLEAR)); + + }else{ + + pokeRegisterDWord(RAW_INT, FIELD_SET(value, RAW_INT, SECONDARY_VSYNC, CLEAR)); + + } + +} + +void ddk750_disable_IntMask(void) +{ + + pokeRegisterDWord(INT_MASK, 0); +} + + +void hw750_setgamma(disp_control_t dispCtrl, unsigned long enable) +{ + unsigned long value; + unsigned long regCtrl; + + + + if(dispCtrl == CHANNEL0_CTRL) + regCtrl = PRIMARY_DISPLAY_CTRL; + else + regCtrl = SECONDARY_DISPLAY_CTRL; + + + value = peekRegisterDWord(regCtrl); + + if (enable) + value = FIELD_SET(value, PRIMARY_DISPLAY_CTRL, GAMMA, ENABLE); + else + value = FIELD_SET(value, PRIMARY_DISPLAY_CTRL, GAMMA, DISABLE); + + pokeRegisterDWord(regCtrl, value); +} + +void hw750_load_lut(disp_control_t dispCtrl, int size, u8 lut_r[], u8 lut_g[], u8 lut_b[]) +{ + unsigned int i, v; + unsigned long regCtrl; + + if(dispCtrl == CHANNEL0_CTRL) + regCtrl = PRIMARY_PALETTE_RAM; + else + regCtrl = SECONDARY_PALETTE_RAM; + + for (i = 0; i < size; i++) { + v = (lut_r[i] << 16); + v |= (lut_g[i] << 8); + v |= lut_b[i]; + pokeRegisterDWord(regCtrl + (i * 4), v); + } +} + + +long hw750_AdaptI2CInit(struct smi_connector *smi_connector) +{ + if(hwi2c_en && (smi_connector->base.connector_type == DRM_MODE_CONNECTOR_DVII)) + { + smi_connector->i2c_hw_enabled = 1; + } + else + { + smi_connector->i2c_hw_enabled = 0; + } + + if(smi_connector->i2c_hw_enabled) + { + return ddk750_AdaptHWI2CInit(smi_connector); + } + else + { + return ddk750_AdaptSWI2CInit(smi_connector); + } +} + + +long hw750_AdaptI2CCleanBus(struct drm_connector *connector) +{ + struct smi_connector *smi_connector = to_smi_connector(connector); + + if(smi_connector->i2c_hw_enabled) + { + return ddk750_AdaptHWI2CCleanBus(smi_connector); + } + else + { + return ddk750_AdapSWI2CCleanBus(smi_connector); + } + + return 0; +} + + + + diff --git a/drivers/gpu/drm/smidrm/hw750.h b/drivers/gpu/drm/smidrm/hw750.h new file mode 100644 index 000000000000..fa51bdba4314 --- /dev/null +++ b/drivers/gpu/drm/smidrm/hw750.h @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2023, SiliconMotion Inc. + + +#ifndef LYNX_HW750_H__ +#define LYNX_HW750_H__ + +#include "hw_com.h" +#ifdef USE_EP952 +#include "ddk768/ep952api.h" +#endif + + + + +void ddk750_set_mmio(volatile unsigned char * addr,unsigned short devId,char revId); +unsigned long ddk750_getFrameBufSize(void); +long ddk750_initChip(void); +void ddk750_deInit(void); +long ddk750_detectCRTMonitor(unsigned char redValue, unsigned char greenValue, + unsigned char blueValue); + +long ddk750_edidHeaderReadMonitorExHwI2C(void); +long ddk750_edidHeaderReadMonitorEx( + unsigned char sclGpio, + unsigned char sdaGpio +); + +/* + * edidReadMonitor + * This function reads the EDID structure from the attached monitor + * + * Input: + * displayPath - Display device which EDID to be read from. + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk750_edidReadMonitor( + disp_path_t displayPath, + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo +); + +/* + * edidReadMonitor + * This function reads the EDID structure from the attached monitor + * + * Input: + * displayPath - Display device which EDID to be read from. + * pEDIDBuffer - Buffer that contains the EDID structure of the monitor + * bufferSize - The EDID Buffer size index (usually 128-bytes) + * edidExtNo - Extension Index of the EDID Structure to be read + * sclGpio - GPIO pin used as the I2C Clock (SCL) + * sdaGpio - GPIO pin used as the I2C Data (SDA) + * + * Output: + * 0 - Success + * -1 - Fail + */ +long ddk750_edidReadMonitorEx( + disp_path_t displayPath, + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char sclGpio, + unsigned char sdaGpio +); + + +long ddk750_edidReadMonitorEx_HW( + disp_path_t displayPath, + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo +); + + +/* + * This function initializes the cursor attributes. + */ +void ddk750_initCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long base, /* Base Address */ + unsigned long color1, /* Cursor color 1 in RGB 5:6:5 format */ + unsigned long color2, /* Cursor color 2 in RGB 5:6:5 format */ + unsigned long color3 /* Cursor color 3 in RGB 5:6:5 format */ +); + +/* + * This function sets the cursor position. + */ +void ddk750_setCursorPosition( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long dx, /* X Coordinate of the cursor */ + unsigned long dy, /* Y Coordinate of the cursor */ + unsigned char topOutside, /* Top Boundary Select: either partially outside (= 1) + or within the screen top boundary (= 0) */ + unsigned char leftOutside /* Left Boundary Select: either partially outside (= 1) + or within the screen left boundary (= 0) */ +); + +/* + * This function enables/disables the cursor. + */ +void ddk750_enableCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long enable +); + + + +void hw750_set_base(int display,int pitch,int base_addr); + +long setMode( + logicalMode_t *pLogicalMode +); +void setDisplayControl(disp_control_t dispControl, disp_state_t dispState); +void setPath( + disp_path_t dispPath, + disp_control_t dispControl, + disp_state_t dispState +); + +void swPanelPowerSequence(disp_state_t dispState, unsigned long vsync_delay); +void setDAC(disp_state_t state); +void setDPMS(DPMS_t state); + + + +void hw750_set_dpms(int display,int state); +void hw750_suspend(struct smi_750_register * pSave); +void hw750_resume(struct smi_750_register * pSave); +int hw750_check_vsync_interrupt(int path); +void hw750_clear_vsync_interrupt(int path); + +int hw750_en_dis_interrupt(int status, int pipe); + +void ddk750_disable_IntMask(void); + +int sii9022xInitChip(void); +int sii9022xSetMode(int); +unsigned char sii9022xIsConnected(void); + +int ddk750_GetDDC_9022Access(void); +int ddk750_Release9022DDC(void); + +void ddk750_DoEdidRead(void); + +void hw750_setgamma(disp_control_t dispCtrl, unsigned long enable); +void hw750_load_lut(disp_control_t dispCtrl, int size, u8 lut_r[], u8 lut_g[], u8 lut_b[]); + +long hw750_AdaptI2CInit(struct smi_connector *smi_connector); +long hw750_AdaptI2CCleanBus(struct drm_connector *connector); + +#endif diff --git a/drivers/gpu/drm/smidrm/hw768.c b/drivers/gpu/drm/smidrm/hw768.c new file mode 100644 index 000000000000..17612b2f8c80 --- /dev/null +++ b/drivers/gpu/drm/smidrm/hw768.c @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2023, SiliconMotion Inc. + + +#include + +#include "ddk768/ddk768_mode.h" +#include "ddk768/ddk768_help.h" +#include "ddk768/ddk768_reg.h" +#include "ddk768/ddk768_display.h" +#include "ddk768/ddk768_2d.h" +#include "ddk768/ddk768_power.h" +#include "ddk768/ddk768_cursor.h" +#include "ddk768/ddk768_video.h" +#include "ddk768/ddk768_hdmi.h" +#include "ddk768/ddk768_pwm.h" +#include "ddk768/ddk768_swi2c.h" +#include "ddk768/ddk768_hwi2c.h" +#include + + +extern int lcd_scale; +extern int pwm_ctrl; + + +struct smi_768_register{ + uint32_t clock_enable, pll_ctrl[3]; + + uint32_t primary_display_ctrl[10], lvds_ctrl, primary_hwcurs_ctrl[4]; + uint32_t secondary_display_ctrl[10], secondary_hwcurs_ctrl[4]; +}; + + +static mode_parameter_t convert_drm_mode_to_ddk_mode(struct drm_display_mode mode) +{ + mode_parameter_t modeP; + + modeP.horizontal_total = mode.htotal; + modeP.horizontal_display_end = mode.hdisplay; + modeP.horizontal_sync_start = mode.hsync_start; + modeP.horizontal_sync_width = mode.hsync_end - mode.hsync_start; + modeP.horizontal_sync_polarity = mode.flags & DRM_MODE_FLAG_PHSYNC ? POS : NEG; + + /* Vertical timing. */ + modeP.vertical_total = mode.vtotal; + modeP.vertical_display_end = mode.vdisplay; + modeP.vertical_sync_start = mode.vsync_start; + modeP.vertical_sync_height = mode.vsync_end - mode.vsync_start; + modeP.vertical_sync_polarity = mode.flags & DRM_MODE_FLAG_PVSYNC ? POS : NEG; + + /* Refresh timing. */ + modeP.pixel_clock = mode.clock * 1000; + modeP.horizontal_frequency = 0; + modeP.vertical_frequency = 0; + + /* Clock Phase. This clock phase only applies to Panel. */ + modeP.clock_phase_polarity = NEG; + + return modeP; +} + + + +void hw768_enable_lvds(int channels) +{ + + if(channels == 1){ + setSingleLVDS(0); + + }else{ + set48bitLVDS(0); + } + + + if(pwm_ctrl) + { + unsigned long pwm, divider, highCounter, lowCounter; + + pwm = pwm_ctrl & 0xf; + divider = (pwm_ctrl & 0xf0) >> 4; + highCounter = (pwm_ctrl & 0xfff00) >> 8; + lowCounter = (pwm_ctrl & 0xfff00000) >> 20; + + ddk768_pwmOpen(pwm); + ddk768_pwmStart(pwm, divider, highCounter, lowCounter, 0); + } + + +} + + + +void ddk768_setDisplayPlaneDisableOnly( + disp_control_t dispControl /* Channel 0 or Channel 1) */ +) +{ + unsigned long ulDispCtrlAddr; + unsigned long ulDispCtrlReg; + + ulDispCtrlAddr = (dispControl == CHANNEL0_CTRL)? DISPLAY_CTRL : (DISPLAY_CTRL+CHANNEL_OFFSET); + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + + + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, PLANE, DISABLE)| + FIELD_SET(0, DISPLAY_CTRL, DATA_PATH, EXTENDED); + + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + +} + + + + +void hw768_suspend(struct smi_768_register * pSave) +{ + +#if 0 + int i; + + pSave->clock_enable = peekRegisterDWord(CLOCK_ENABLE); + for (i = 0; i < 3; i++) + pSave->pll_ctrl[i] = peekRegisterDWord(MCLK_PLL + i * 4); + + for (i = 0; i < 10; i++) + pSave->primary_display_ctrl[i] = peekRegisterDWord(DISPLAY_CTRL + i * 4); + pSave->lvds_ctrl = peekRegisterDWord(LVDS_CTRL2); + for (i = 0; i < 4; i++) + pSave->primary_hwcurs_ctrl[i] = peekRegisterDWord(HWC_CONTROL + i * 4); + + for (i = 0; i < 10; i++) + pSave->secondary_display_ctrl[i] = peekRegisterDWord(0x8000 + DISPLAY_CTRL + i * 4); + for (i = 0; i < 4; i++) + pSave->secondary_hwcurs_ctrl[i] = peekRegisterDWord(0x8000 + HWC_CONTROL + i * 4); + +#endif + +} + +void hw768_resume(struct smi_768_register * pSave) +{ + +#if 0 + int i; + + pokeRegisterDWord(CLOCK_ENABLE, pSave->clock_enable); + for (i = 0; i < 3; i++) + pokeRegisterDWord(MCLK_PLL + i * 4, pSave->pll_ctrl[i]); + + for (i = 0; i < 10; i++) + pokeRegisterDWord(DISPLAY_CTRL + i * 4, pSave->primary_display_ctrl[i]); + pokeRegisterDWord(LVDS_CTRL2, pSave->lvds_ctrl); + for (i = 0; i < 4; i++) + pokeRegisterDWord(HWC_CONTROL + i * 4, pSave->primary_hwcurs_ctrl[i]); + + for (i = 0; i < 10; i++) + pokeRegisterDWord(0x8000 + DISPLAY_CTRL + i * 4, pSave->secondary_display_ctrl[i]); + for (i = 0; i < 4; i++) + pokeRegisterDWord(0x8000 + HWC_CONTROL + i * 4, pSave->secondary_hwcurs_ctrl[i]); + +#endif +} +void hw768_set_base(int display,int pitch,int base_addr) +{ + + if(display == 0) + { + /* Frame buffer base */ + pokeRegisterDWord((FB_ADDRESS), + FIELD_SET(0, FB_ADDRESS, STATUS, PENDING) + | FIELD_VALUE(0, FB_ADDRESS, ADDRESS, base_addr)); + + /* Pitch value (Hardware people calls it Offset) */ + pokeRegisterDWord((FB_WIDTH), FIELD_VALUE(peekRegisterDWord(FB_WIDTH), FB_WIDTH, OFFSET, pitch)); + + if(lcd_scale){ + pokeRegisterDWord((VIDEO_FB_WIDTH), + FIELD_VALUE(0, VIDEO_FB_WIDTH, WIDTH, pitch) | + FIELD_VALUE(0, VIDEO_FB_WIDTH, OFFSET, pitch)); + + pokeRegisterDWord(VIDEO_FB_ADDRESS, + FIELD_SET(0, VIDEO_FB_ADDRESS, STATUS, PENDING) | + FIELD_VALUE(0, VIDEO_FB_ADDRESS, ADDRESS, base_addr)); + + } + } + else + { + /* Frame buffer base */ + pokeRegisterDWord((FB_ADDRESS+CHANNEL_OFFSET), + FIELD_SET(0, FB_ADDRESS, STATUS, PENDING) + | FIELD_VALUE(0, FB_ADDRESS, ADDRESS, base_addr)); + + + /* Pitch value (Hardware people calls it Offset) */ + pokeRegisterDWord((FB_WIDTH+CHANNEL_OFFSET),FIELD_VALUE(peekRegisterDWord(FB_WIDTH+CHANNEL_OFFSET), FB_WIDTH, OFFSET, pitch)); + + } +} + + +void hw768_init_hdmi(void) +{ + HDMI_Init(); +} + +int hw768_set_hdmi_mode(logicalMode_t *pLogicalMode, struct drm_display_mode mode, bool isHDMI) +{ + int ret = 1; + mode_parameter_t modeParam; + + // set HDMI parameters + HDMI_Disable_Output(); + + if(pLogicalMode->valid_edid) + modeParam = convert_drm_mode_to_ddk_mode(mode); + ret = HDMI_Set_Mode(pLogicalMode,&modeParam,isHDMI); + return ret; +} + +int hw768_en_dis_interrupt(int status, int pipe) +{ + if(status == 0) + { + pokeRegisterDWord(INT_MASK, (pipe == CHANNEL0_CTRL) ? + FIELD_SET(0, INT_MASK, CHANNEL1_VSYNC, DISABLE): + FIELD_SET(0, INT_MASK, CHANNEL0_VSYNC, DISABLE)); + } + else + { + pokeRegisterDWord(INT_MASK, (pipe == CHANNEL1_CTRL) ? + FIELD_SET(0, INT_MASK, CHANNEL1_VSYNC, ENABLE): + FIELD_SET(0, INT_MASK, CHANNEL0_VSYNC, ENABLE)); + } + return 0; +} +void hw768_HDMI_Enable_Output(void) +{ + HDMI_Enable_Output(); +} + +void hw768_HDMI_Disable_Output(void) +{ + HDMI_Disable_Output(); +} + + +int hw768_get_hdmi_edid(unsigned char *pEDIDBuffer) +{ + int ret; + enableHdmI2C(1); + ret = HDMI_Read_Edid(pEDIDBuffer, 128); + enableHdmI2C(0); + + return ret; +} + +int hw768_check_iis_interrupt(void) +{ + + unsigned long value; + + value = peekRegisterDWord(INT_STATUS); + + + if (FIELD_GET(value, INT_STATUS, I2S) == INT_STATUS_I2S_ACTIVE) + return true; + else + return false; +} + + +int hw768_check_vsync_interrupt(int path) +{ + + unsigned long value1,value2; + + value1 = peekRegisterDWord(RAW_INT); + value2 = peekRegisterDWord(INT_MASK); + + if(path == CHANNEL0_CTRL) + { + if ((FIELD_GET(value1, RAW_INT, CHANNEL0_VSYNC) == RAW_INT_CHANNEL0_VSYNC_ACTIVE) + &&(FIELD_GET(value2, INT_MASK, CHANNEL0_VSYNC) == INT_MASK_CHANNEL0_VSYNC_ENABLE)) + { + return true; + } + }else{ + if ((FIELD_GET(value1, RAW_INT, CHANNEL1_VSYNC) == RAW_INT_CHANNEL1_VSYNC_ACTIVE) + &&(FIELD_GET(value2, INT_MASK, CHANNEL1_VSYNC) == INT_MASK_CHANNEL1_VSYNC_ENABLE)) + { + return true; + } + } + + return false; +} + + +void hw768_clear_vsync_interrupt(int path) +{ + + unsigned long value; + + value = peekRegisterDWord(RAW_INT); + + if (path == CHANNEL0_CTRL) + { + pokeRegisterDWord(RAW_INT, FIELD_SET(value, RAW_INT, CHANNEL0_VSYNC, CLEAR)); + } + else + { + pokeRegisterDWord(RAW_INT, FIELD_SET(value, RAW_INT, CHANNEL1_VSYNC, CLEAR)); + } +} + +long hw768_setMode(logicalMode_t *pLogicalMode, struct drm_display_mode mode) +{ + + if (!pLogicalMode->valid_edid) + return ddk768_setMode(pLogicalMode); + else + { + mode_parameter_t ModeParam; + ModeParam = convert_drm_mode_to_ddk_mode(mode); + return ddk768_setCustomMode(pLogicalMode, &ModeParam); + } + +} + + +int hdmi_int_status = 0; + +inline int hdmi_hotplug_detect(void) +{ + int ret = 0; + unsigned int intMask = peekRegisterDWord(INT_MASK); + intMask = FIELD_SET(intMask, INT_MASK, HDMI, ENABLE); + pokeRegisterDWord(INT_MASK, intMask); + + ret = hdmi_detect(); + + if (ret == 1) + { + hdmi_int_status = 1; + } + else if (ret == 0) + { + hdmi_int_status = 0; + } + else + { + hdmi_int_status = hdmi_int_status & ret; + } + + intMask = peekRegisterDWord(INT_MASK); + intMask = FIELD_SET(intMask, INT_MASK, HDMI, DISABLE); + pokeRegisterDWord(INT_MASK, intMask); + + return hdmi_int_status; +} + +void ddk768_disable_IntMask(void) +{ + + pokeRegisterDWord(INT_MASK, 0); +} + +void hw768_SetPixelClockFormat(disp_control_t dispControl,unsigned int is_half) +{ + unsigned long ulDispCtrlAddr; + unsigned long ulDispCtrlReg; + + if (dispControl == CHANNEL0_CTRL) + { + ulDispCtrlAddr = DISPLAY_CTRL; + } + else + return; + + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + + if(is_half) + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, PIXEL_CLOCK_SELECT, HALF); + else + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, PIXEL_CLOCK_SELECT, SINGLE); + + + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); +} + +void hw768_setgamma(disp_control_t dispCtrl, unsigned long enable, unsigned long lvds_ch) +{ + unsigned long value; + unsigned long regCtrl; + + regCtrl = (dispCtrl == CHANNEL0_CTRL)? DISPLAY_CTRL + : (DISPLAY_CTRL+CHANNEL_OFFSET); + + value = peekRegisterDWord(regCtrl); + + if (enable) + value = FIELD_SET(value, DISPLAY_CTRL, GAMMA, ENABLE); + else + value = FIELD_SET(value, DISPLAY_CTRL, GAMMA, DISABLE); + + if((lvds_ch == 2) && (dispCtrl == CHANNEL0_CTRL)) //dual channel LVDS and channel 0 gamma setting + value = FIELD_SET(value, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, ENABLE); + else{ + value = FIELD_SET(value, DISPLAY_CTRL, DOUBLE_PIXEL_CLOCK, DISABLE); + } + + pokeRegisterDWord(regCtrl, value); +} + +void hw768_load_lut(disp_control_t dispCtrl, int size, u8 lut_r[], u8 lut_g[], u8 lut_b[]) +{ + unsigned int i, v; + unsigned long regCtrl; + + regCtrl = (dispCtrl == CHANNEL0_CTRL)? PALETTE_RAM + : (PALETTE_RAM+CHANNEL_OFFSET); + + for (i = 0; i < size; i++) { + v = (lut_r[i] << 16); + v |= (lut_g[i] << 8); + v |= lut_b[i]; + pokeRegisterDWord(regCtrl + (i * 4), v); + } +} + + + +long hw768_AdaptI2CInit(struct smi_connector *smi_connector) +{ +#if 0 + if(hwi2c_en) + { + smi_connector->i2c_hw_enabled = 1; + } + else + { + smi_connector->i2c_hw_enabled = 0; + } + + if(smi_connector->i2c_hw_enabled) + { + return ddk768_AdaptHWI2CInit(smi_connector); + } + else + { + return ddk768_AdaptSWI2CInit(smi_connector); + } +#endif + struct drm_connector *connector = &smi_connector->base; + switch(connector->connector_type){ + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_VGA: + if(hwi2c_en){ + smi_connector->i2c_hw_enabled = 1; + return ddk768_AdaptHWI2CInit(smi_connector); + } + break; + case DRM_MODE_CONNECTOR_HDMIA: + default: + break; + + } + smi_connector->i2c_hw_enabled = 0; + + return ddk768_AdaptSWI2CInit(smi_connector); + +} + + +long hw768_AdaptI2CCleanBus(struct drm_connector *connector) +{ + struct smi_connector *smi_connector = to_smi_connector(connector); + + if(smi_connector->i2c_hw_enabled) + { + return ddk768_AdaptHWI2CCleanBus(smi_connector); + } + else + { + return ddk768_AdaptSWI2CCleanBus(smi_connector); + } +} + + + diff --git a/drivers/gpu/drm/smidrm/hw768.h b/drivers/gpu/drm/smidrm/hw768.h new file mode 100644 index 000000000000..8291111e3071 --- /dev/null +++ b/drivers/gpu/drm/smidrm/hw768.h @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2023, SiliconMotion Inc. + + +#ifndef LYNX_HW768_H__ +#define LYNX_HW768_H__ +#include "hw_com.h" +#ifdef USE_EP952 +#include "ddk768/ep952api.h" +#endif + + +void ddk768_setDisplayPlaneDisableOnly( + disp_control_t dispControl /* Channel 0 or Channel 1) */ +); + + +void hw768_enable_lvds(int channels); + +void ddk768_set_mmio(volatile unsigned char * addr,unsigned short devId,char revId); +unsigned long ddk768_getFrameBufSize(void); +long ddk768_initChip(void); +void ddk768_deInit(void); + +void ddk768_swPanelPowerSequence(disp_control_t dispControl, disp_state_t dispState, unsigned long vSyncDelay); + + +long ddk768_edidHeaderReadMonitorEx( + unsigned char sclGpio, + unsigned char sdaGpio +); + +long ddk768_edidHeaderReadMonitorExHwI2C( + unsigned char i2cNumber +); + + + +long ddk768_detectCRTMonitor(disp_control_t dispControl, unsigned char redValue, + unsigned char greenValue, unsigned char blueValue); + +long ddk768_edidReadMonitor( + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char i2cNumber +); + + + + + +long ddk768_edidReadMonitorEx( + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char sclGpio, + unsigned char sdaGpio +); + + + +int hw768_get_hdmi_edid(unsigned char *pEDIDBuffer); + + + +long ddk768_edidReadMonitorExHwI2C( + unsigned char *pEDIDBuffer, + unsigned long bufferSize, + unsigned char edidExtNo, + unsigned char i2cNumber +); + +/* + * Disable double pixel clock. + * This is a teporary function, used to patch for the random fuzzy font problem. + */ +void DisableDoublePixel(disp_control_t dispControl); +void EnableDoublePixel(disp_control_t dispControl); +void hw768_SetPixelClockFormat(disp_control_t dispControl,unsigned int is_half); + + +/* + * This function initializes the cursor attributes. + */ +void ddk768_initCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long base, /* Base Address */ + unsigned long color1, /* Cursor color 1 in RGB 5:6:5 format */ + unsigned long color2, /* Cursor color 2 in RGB 5:6:5 format */ + unsigned long color3 /* Cursor color 3 in RGB 5:6:5 format */ +); + +/* + * This function sets the cursor position. + */ +void ddk768_setCursorPosition( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long dx, /* X Coordinate of the cursor */ + unsigned long dy, /* Y Coordinate of the cursor */ + unsigned char topOutside, /* Top Boundary Select: either partially outside (= 1) + or within the screen top boundary (= 0) */ + unsigned char leftOutside /* Left Boundary Select: either partially outside (= 1) + or within the screen left boundary (= 0) */ +); + +void hw768_set_base(int display,int pitch,int base_addr); + +/* + * This function enables/disables the cursor. + */ +void ddk768_enableCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long enable +); + +void hw768_HDMI_Enable_Output(void); + +void hw768_HDMI_Disable_Output(void); + + +long ddk768_setMode( + logicalMode_t *pLogicalMode +); +long setSingleViewOn(disp_control_t dispOutput); +long initDisplay(void); + +void setDisplayDPMS( + disp_control_t dispControl, /* Channel 0 or Channel 1) */ + DISP_DPMS_t state /* DPMS state */ + ); + +void hw768_init_hdmi(void); +int hw768_set_hdmi_mode(logicalMode_t *pLogicalMode, struct drm_display_mode mode, bool isHDMI); + + + +void ddk768_setDisplayEnable(disp_control_t dispControl, /* Channel 0 or Channel 1) */ +disp_state_t dispState /* ON or OFF */); + +int hw768_check_iis_interrupt(void); + +int hw768_check_vsync_interrupt(int path); +void hw768_clear_vsync_interrupt(int path); + +long hw768_setMode(logicalMode_t *pLogicalMode, struct drm_display_mode mode); + + +int hw768_en_dis_interrupt(int status, int pipe); + +int hdmi_detect(void); + +int hdmi_hotplug_detect(void); + +void HDMI_Audio_Mute (void); + +void HDMI_Audio_Unmute (void); + + +void ddk768_disable_IntMask(void); + +void hw768_suspend(struct smi_768_register * pSave); +void hw768_resume(struct smi_768_register * pSave); + +void hw768_setgamma(disp_control_t dispCtrl, unsigned long enable,unsigned long lvds_ch); +void hw768_load_lut(disp_control_t dispCtrl, int size, u8 lut_r[], u8 lut_g[], u8 lut_b[]); + +long hw768_AdaptI2CCleanBus(struct drm_connector *connector); +long hw768_AdaptI2CInit(struct smi_connector *smi_connector); +#endif diff --git a/drivers/gpu/drm/smidrm/hw770.c b/drivers/gpu/drm/smidrm/hw770.c new file mode 100644 index 000000000000..d088975f88ff --- /dev/null +++ b/drivers/gpu/drm/smidrm/hw770.c @@ -0,0 +1,641 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2023, SiliconMotion Inc. + + +#include +#include "ddk770/ddk770_reg.h" +#include "ddk770/ddk770_help.h" +#include "ddk770/ddk770_mode.h" +#include "ddk770/ddk770_hardware.h" +#include "ddk770/ddk770_display.h" +#include "ddk770/ddk770_power.h" +#include "ddk770/ddk770_cursor.h" +#include "ddk770/ddk770_video.h" +#include "ddk770/ddk770_hdmi.h" +#include "ddk770/ddk770_pwm.h" +#include "ddk770/ddk770_swi2c.h" +#include "ddk770/ddk770_hwi2c.h" +#include "ddk770/ddk770_iis.h" +#include "ddk770/ddk770_dp.h" +#include "ddk770/ddk770_intr.h" +#include "ddk770/ddk770_chip.h" +#include "ddk770/ddk770_wm8978.h" +#include "hw770.h" +#include "smi_snd.h" +#include "smi_ver.h" + + +extern int lcd_scale; +extern int pwm_ctrl; + +static mode_parameter_t hw770_convert_drm_mode_to_ddk_mode(struct drm_display_mode mode) +{ + mode_parameter_t modeP; + + modeP.horizontal_total = mode.htotal; + modeP.horizontal_display_end = mode.hdisplay; + modeP.horizontal_sync_start = mode.hsync_start; + modeP.horizontal_sync_width = mode.hsync_end - mode.hsync_start; + modeP.horizontal_sync_polarity = mode.flags & DRM_MODE_FLAG_PHSYNC ? POS : NEG; + + /* Vertical timing. */ + modeP.vertical_total = mode.vtotal; + modeP.vertical_display_end = mode.vdisplay; + modeP.vertical_sync_start = mode.vsync_start; + modeP.vertical_sync_height = mode.vsync_end - mode.vsync_start; + modeP.vertical_sync_polarity = mode.flags & DRM_MODE_FLAG_PVSYNC ? POS : NEG; + + /* Refresh timing. */ + modeP.pixel_clock = mode.clock * 1000; + modeP.horizontal_frequency = 0; + modeP.vertical_frequency = 0; + + /* Clock Phase. This clock phase only applies to Panel. */ + modeP.clock_phase_polarity = NEG; + + return modeP; +} + + +void hw770_enable_lvds(int channels) +{ + +} + + + +void hw770_setDisplayPlaneDisableOnly( + disp_control_t dispControl /* Channel 0 or Channel 1) */ +) +{ + unsigned long ulDispCtrlAddr; + unsigned long ulDispCtrlReg; + + ulDispCtrlAddr = DISPLAY_CTRL + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + ulDispCtrlReg = peekRegisterDWord(ulDispCtrlAddr); + + + ulDispCtrlReg = FIELD_SET(ulDispCtrlReg, DISPLAY_CTRL, PLANE, DISABLE)| + FIELD_SET(0, DISPLAY_CTRL, DATA_PATH, EXTENDED); + + pokeRegisterDWord(ulDispCtrlAddr, ulDispCtrlReg); + +} + + + + +void hw770_suspend(struct smi_770_register * pSave) +{ + ; + // int i; + + // pSave->clock_enable = peekRegisterDWord(CLOCK_ENABLE); + // for (i = 0; i < 3; i++) + // pSave->pll_ctrl[i] = peekRegisterDWord(MCLK_PLL + i * 4); + + // for (i = 0; i < 10; i++) + // pSave->primary_display_ctrl[i] = peekRegisterDWord(DISPLAY_CTRL + i * 4); + // pSave->lvds_ctrl = peekRegisterDWord(LVDS_CTRL2); + // for (i = 0; i < 4; i++) + // pSave->primary_hwcurs_ctrl[i] = peekRegisterDWord(HWC_CONTROL + i * 4); + + // for (i = 0; i < 10; i++) + // pSave->secondary_display_ctrl[i] = peekRegisterDWord(0x8000 + DISPLAY_CTRL + i * 4); + // for (i = 0; i < 4; i++) + // pSave->secondary_hwcurs_ctrl[i] = peekRegisterDWord(0x8000 + HWC_CONTROL + i * 4); + + +} + +void hw770_resume(struct smi_770_register * pSave) +{ + if (ddk770_GetChipRev() == CHIP_REV_AB) { + pokeRegisterDWord(0x130, 0x78000000); + } + + ddk770_iis_Init(); + hw770_init_hdmi(); + hw770_init_dp(); + // int i; + + // pokeRegisterDWord(CLOCK_ENABLE, pSave->clock_enable); + // for (i = 0; i < 3; i++) + // pokeRegisterDWord(MCLK_PLL + i * 4, pSave->pll_ctrl[i]); + + // for (i = 0; i < 10; i++) + // pokeRegisterDWord(DISPLAY_CTRL + i * 4, pSave->primary_display_ctrl[i]); + // pokeRegisterDWord(LVDS_CTRL2, pSave->lvds_ctrl); + // for (i = 0; i < 4; i++) + // pokeRegisterDWord(HWC_CONTROL + i * 4, pSave->primary_hwcurs_ctrl[i]); + + // for (i = 0; i < 10; i++) + // pokeRegisterDWord(0x8000 + DISPLAY_CTRL + i * 4, pSave->secondary_display_ctrl[i]); + // for (i = 0; i < 4; i++) + // pokeRegisterDWord(0x8000 + HWC_CONTROL + i * 4, pSave->secondary_hwcurs_ctrl[i]); + + + +} +void hw770_set_base(disp_control_t dispControl,int pitch,int base_addr) +{ + + unsigned int ulFBBaseAddr, ulFBPitchAddr, ulFBPitchReg,LineOffset; + + LineOffset = alignLineOffset(pitch); + + ulFBBaseAddr = FB_ADDRESS + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + + /* Frame buffer base */ + pokeRegisterDWord(ulFBBaseAddr, + FIELD_SET(0, FB_ADDRESS, STATUS, PENDING) + | FIELD_VALUE(0, FB_ADDRESS, ADDRESS, base_addr)); + + + + /* Pitch value (Hardware people calls it Offset) */ + + ulFBPitchAddr = FB_WIDTH + (dispControl> 1? CHANNEL_OFFSET2 : dispControl * CHANNEL_OFFSET); + + ulFBPitchReg = peekRegisterDWord(ulFBPitchAddr); + + pokeRegisterDWord(ulFBPitchAddr, FIELD_VALUE(ulFBPitchReg, FB_WIDTH, OFFSET, LineOffset)); + + + +} + + + +void hw770_init_hdmi(void) +{ + ddk770_HDMI_Init(0); + ddk770_HDMI_Init(1); + ddk770_HDMI_Init(2); +} + +void hw770_init_dp(void) +{ + DP_Init(0); + DP_Init(1); +} + +int hw770_set_hdmi_mode(logicalMode_t *pLogicalMode, struct drm_display_mode mode, bool isHDMI,int hdmi_index) +{ + int ret = 1; + mode_parameter_t modeParam; + + ddk770_HDMI_Set_Channel(hdmi_index,pLogicalMode->dispCtrl); + ddk770_setSingleViewOn(pLogicalMode->dispCtrl); + + printk("hdmi_index= %x, DC=%x, 0x3ffc value=%x\n",hdmi_index,pLogicalMode->dispCtrl,peekRegisterDWord(0x3ffc)); + + if(pLogicalMode->valid_edid) + modeParam = hw770_convert_drm_mode_to_ddk_mode(mode); + ret = ddk770_HDMI_Set_Mode(hdmi_index, pLogicalMode,&modeParam, isHDMI); + return ret; +} + +int hw770_hdmi_vga_mode(hdmi_index index) +{ + int ret = 1; + mode_parameter_t modeParam; + logicalMode_t logicalMode; + + logicalMode.valid_edid = false; + + logicalMode.baseAddress = 0; + logicalMode.x = 640; + logicalMode.y = 480; + logicalMode.bpp = 32; + logicalMode.dispCtrl = (disp_control_t)index; + logicalMode.hz = 60; + logicalMode.pitch = 0;; + + + ddk770_setMode(&logicalMode); + + ddk770_HDMI_Set_Channel(index,logicalMode.dispCtrl); + ddk770_setSingleViewOn(logicalMode.dispCtrl); + + ret = ddk770_HDMI_Set_Mode(index, &logicalMode,&modeParam, 1); + + return ret; + + +} + +int hw770_set_dp_mode(logicalMode_t *pLogicalMode, struct drm_display_mode mode, int dp_index) +{ + int ret = 1; + mode_parameter_t modeParam; + + DP_Set_Channel(dp_index,pLogicalMode->dispCtrl); + + ddk770_setSingleViewOn(pLogicalMode->dispCtrl); + + printk("dp_index= %x, DC=%x, 0x3ffc value=%x\n",dp_index,pLogicalMode->dispCtrl,peekRegisterDWord(0x3ffc)); + + if(pLogicalMode->valid_edid) + modeParam = hw770_convert_drm_mode_to_ddk_mode(mode); + ret = DP_Setmode(dp_index, pLogicalMode,&modeParam); + return ret; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0) +int hw770_en_dis_interrupt(int status, int pipe) +{ + int channel_mask = 0; + + switch (pipe) { + case CHANNEL0_CTRL: + channel_mask = (status == 0) ? FIELD_SET(0, INT_MASK, CHANNEL0_VSYNC, DISABLE) : + FIELD_SET(0, INT_MASK, CHANNEL0_VSYNC, ENABLE); + break; + case CHANNEL1_CTRL: + channel_mask = (status == 0) ? FIELD_SET(0, INT_MASK, CHANNEL1_VSYNC, DISABLE) : + FIELD_SET(0, INT_MASK, CHANNEL1_VSYNC, ENABLE); + break; + case CHANNEL2_CTRL: + channel_mask = (status == 0) ? FIELD_SET(0, INT_MASK, CHANNEL2_VSYNC, DISABLE) : + FIELD_SET(0, INT_MASK, CHANNEL2_VSYNC, ENABLE); + break; + default: + return -1; + } + pokeRegisterDWord(INT_MASK, channel_mask); + + return 0; +} +#else +int hw770_en_dis_interrupt(int status) + { + if(status == 0) + { + pokeRegisterDWord(INT_MASK, FIELD_SET(0, INT_MASK, CHANNEL2_VSYNC, DISABLE)); + pokeRegisterDWord(INT_MASK, FIELD_SET(0, INT_MASK, CHANNEL1_VSYNC, DISABLE)); + pokeRegisterDWord(INT_MASK, FIELD_SET(0, INT_MASK, CHANNEL0_VSYNC, DISABLE)); + } + else + { + pokeRegisterDWord(INT_MASK, FIELD_SET(0, INT_MASK, CHANNEL2_VSYNC, ENABLE)); + pokeRegisterDWord(INT_MASK, FIELD_SET(0, INT_MASK, CHANNEL1_VSYNC, ENABLE)); + pokeRegisterDWord(INT_MASK, FIELD_SET(0, INT_MASK, CHANNEL0_VSYNC, ENABLE)); + } + return 0; + } + +#endif + +void hw770_HDMI_Disable_Output(hdmi_index index) +{ + + ddk770_HDMI_Disable_Output(index); + ddk770_HDMI_Clear_Channel(index); + ddk770_HDMI_Standby(index); + hw770_hdmi_interrupt_enable(index,0); +} + +void hw770_DP_Disable_Output(dp_index index) +{ + DP_Clear_Channel(index); + DP_Disable_Output(index); +} + +void hw770_HDMI_Clear_Channel(hdmi_index index) +{ + if(ddk770_HDMI_Get_Channel(index) != 0) //DC will be 0x1 , 0x2 or 0x4 + { + ddk770_HDMI_Disable_Output(index); + ddk770_HDMI_Clear_Channel(index); + ddk770_HDMI_Standby(index); + + } + +} + +int hw770_get_hdmi_edid(hdmi_index index, unsigned char *pEDIDBuffer) +{ + u16 edidSize = 0; + + ddk770_HDMI_Read_EDID(index, pEDIDBuffer, &edidSize); + + return edidSize; + +} + +int hw770_get_dp_edid(dp_index index, unsigned char *pEDIDBuffer) +{ + u16 edidSize = 0; + + DP_Read_EDID(index, pEDIDBuffer, &edidSize); + + return edidSize; + +} + +void hw770_DP_Clear_Channel(dp_index index) +{ + if(DP_Get_Channel(index) != 0) + DP_Clear_Channel(index); +} + +int hw770_check_iis_interrupt(void) +{ + + unsigned long value; + + value = peekRegisterDWord(INT_STATUS); + + + if (FIELD_VAL_GET(value, INT_STATUS, I2S) == INT_STATUS_I2S_ACTIVE) + return true; + else + return false; +} + +int hw770_check_vsync_interrupt(int path) +{ + + unsigned long value1,value2; + + value1 = peekRegisterDWord(RAW_INT); + value2 = peekRegisterDWord(INT_MASK); + + if(path == CHANNEL0_CTRL) + { + if ((FIELD_VAL_GET(value1, RAW_INT, CHANNEL0_VSYNC) == RAW_INT_CHANNEL0_VSYNC_ACTIVE) + &&(FIELD_VAL_GET(value2, INT_MASK, CHANNEL0_VSYNC) == INT_MASK_CHANNEL0_VSYNC_ENABLE)) + { + return true; + } + }else if (path == CHANNEL1_CTRL){ + if ((FIELD_VAL_GET(value1, RAW_INT, CHANNEL1_VSYNC) == RAW_INT_CHANNEL1_VSYNC_ACTIVE) + &&(FIELD_VAL_GET(value2, INT_MASK, CHANNEL1_VSYNC) == INT_MASK_CHANNEL1_VSYNC_ENABLE)) + { + return true; + } + }else{ + if ((FIELD_VAL_GET(value1, RAW_INT, CHANNEL2_VSYNC) == RAW_INT_CHANNEL2_VSYNC_ACTIVE) + &&(FIELD_VAL_GET(value2, INT_MASK, CHANNEL2_VSYNC) == INT_MASK_CHANNEL2_VSYNC_ENABLE)) + { + return true; + } + + } + + return false; +} + +void hw770_clear_vsync_interrupt(int path) +{ + + unsigned long value; + + value = peekRegisterDWord(RAW_INT); + + if (path == CHANNEL0_CTRL) + { + pokeRegisterDWord(RAW_INT, FIELD_SET(value, RAW_INT, CHANNEL0_VSYNC, CLEAR)); + } + else if (path == CHANNEL1_CTRL) + { + pokeRegisterDWord(RAW_INT, FIELD_SET(value, RAW_INT, CHANNEL1_VSYNC, CLEAR)); + } + else + { + pokeRegisterDWord(RAW_INT, FIELD_SET(value, RAW_INT, CHANNEL2_VSYNC, CLEAR)); + } +} + +long hw770_setMode(logicalMode_t *pLogicalMode, struct drm_display_mode mode) +{ + if (!pLogicalMode->valid_edid) + return ddk770_setMode(pLogicalMode); + else + { + mode_parameter_t ModeParam; + ModeParam = hw770_convert_drm_mode_to_ddk_mode(mode); + return ddk770_setCustomMode(pLogicalMode, &ModeParam); + } + +} + +int hw770_hdmi_detect(hdmi_index hdmi_index) +{ + + return ddk770_HDMI_HPD_Detect(hdmi_index); + +} + +int hw770_dp_detect(dp_index dp_index) +{ + + return DP_HPD_Detect(dp_index); + +} + +void ddk770_disable_IntMask(void) +{ + pokeRegisterDWord(INT_MASK, 0); +} + +void hw770_SetPixelClockFormat(disp_control_t dispControl,unsigned int is_half) +{ + +} + +void hw770_setgamma(disp_control_t dispCtrl, unsigned long enable) +{ + unsigned long value; + unsigned long regCtrl; + + regCtrl = DISPLAY_CTRL + (dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + value = peekRegisterDWord(regCtrl); + + if (enable) + value = FIELD_SET(value, DISPLAY_CTRL, GAMMA, ENABLE); + else + value = FIELD_SET(value, DISPLAY_CTRL, GAMMA, DISABLE); + + + pokeRegisterDWord(regCtrl, value); +} + +void hw770_load_lut(disp_control_t dispCtrl, int size, u8 lut_r[], u8 lut_g[], u8 lut_b[]) +{ + unsigned int i, v; + unsigned long regCtrl; + + + regCtrl = PALETTE_RAM + (dispCtrl> 1? CHANNEL_OFFSET2 : dispCtrl * CHANNEL_OFFSET); + + for (i = 0; i < size; i++) { + v = (lut_r[i] << 16); + v |= (lut_g[i] << 8); + v |= lut_b[i]; + pokeRegisterDWord(regCtrl + (i * 4), v); + } +} + + + +long hw770_AdaptI2CInit(struct smi_connector *smi_connector) +{ + if (smi_connector->base.connector_type == DRM_MODE_CONNECTOR_DVID || + smi_connector->base.connector_type == DRM_MODE_CONNECTOR_HDMIB || + smi_connector->base.connector_type == DRM_MODE_CONNECTOR_HDMIA) { +#if USE_I2C_ADAPTER + return ddk770_HDMI_AdaptHWI2CInit(smi_connector); +#endif + } else if (smi_connector->base.connector_type == + DRM_MODE_CONNECTOR_DisplayPort || + smi_connector->base.connector_type == + DRM_MODE_CONNECTOR_eDP) { +#if USE_I2C_ADAPTER + return ddk770_DP_AdaptHWI2CInit(smi_connector); +#endif + } + return 0; +#if 0 + if(hwi2c_en) + { + smi_connector->i2c_hw_enabled = 1; + } + else + { + smi_connector->i2c_hw_enabled = 0; + } + + if(smi_connector->i2c_hw_enabled) + { + return 0; + + } + else + { + return 0; + + } +#endif +} + + +long hw770_AdaptI2CCleanBus(struct drm_connector *connector) +{ + return 0; + +} + +void hw770_AudioInit(unsigned long wordLength, unsigned long sampleRate) +{ + + // Set up I2S and GPIO registers to transmit/receive data. + ddk770_iisOpen(wordLength, sampleRate); + //Set I2S to DMA 256 DWord from SRAM starting at location 0 of SRAM + ddk770_iisTxDmaSetup(0,SRAM_SECTION_SIZE); +} + +void hw770_AudioStart(void) +{ + int i = 0; + + for (i = 0 ; i <3 ;i++) + { + ddk770_HDMI_Audio_Unmute(i); + } + + for (i = 0 ; i <2 ;i++) + { + DP_Audio_UnMute(i); + + } + + ddk770_iisStart(); +} + +void hw770_AudioStop(void) +{ + int i; + for (i = 0 ; i <3 ;i++) + { + ddk770_HDMI_Audio_Mute(i); + + } + + for (i = 0 ; i <2 ;i++) + { + DP_Audio_Mute(i); + + } + ddk770_iisStop(); + +} + +void hw770_AudioDeinit(void) +{ + ddk770_iisStop(); + + ddk770_iisClose(); + + ddk770_sb_IRQMask(SM770_SB_IRQ_VAL_I2S); + + ddk770_iisClearRawInt(); + + ddk770_enableI2S(0); +} + + +int hw770_check_pnp_interrupt(hdmi_index index) +{ + int ret = 0; + ret = hdmiISR(index); + return ret; +} + +void hw770_hdmi_interrupt_enable(hdmi_index index,int enable) +{ + ddk770_HDMI_interrupt_enable(index,enable); +} + +void hw770_get_current_fb_info(disp_control_t index, struct smi_770_fb_info *fb_info) +{ + unsigned int baseAddr = FB_ADDRESS + (index > 1 ? CHANNEL_OFFSET2 : index * CHANNEL_OFFSET); + fb_info->fb_addr = peekRegisterDWord(baseAddr); + + baseAddr = FB_WIDTH + (index > 1 ? CHANNEL_OFFSET2 : index * CHANNEL_OFFSET); + fb_info->fb_pitch = peekRegisterDWord(baseAddr); +} + +void hw770_set_current_pitch(disp_control_t index, struct smi_770_fb_info *fb_info) +{ + unsigned int baseAddr = FB_ADDRESS + (index > 1 ? CHANNEL_OFFSET2 : index * CHANNEL_OFFSET); + pokeRegisterDWord(baseAddr, fb_info->fb_addr); + + baseAddr = FB_WIDTH + (index > 1 ? CHANNEL_OFFSET2 : index * CHANNEL_OFFSET); + pokeRegisterDWord(baseAddr, fb_info->fb_pitch); +} + +void hw770_i2c_reset_busclear(hdmi_index index) +{ + ddk770_i2c_reset_busclear(index); + +} + +int hw770_dp_check_sink_status(dp_index index) +{ + int ret; + ret = DP_Check_Sink_Status(index); + + return ret; +} + +int hw770_get_current_mode_width(disp_control_t index) +{ + int width; + unsigned int baseAddr = HORIZONTAL_TOTAL + (index > 1 ? CHANNEL_OFFSET2 : index * CHANNEL_OFFSET); + width = (peekRegisterDWord(baseAddr)&0xfff) + 1; + + return width; +} \ No newline at end of file diff --git a/drivers/gpu/drm/smidrm/hw770.h b/drivers/gpu/drm/smidrm/hw770.h new file mode 100644 index 000000000000..4eee7f6ea37f --- /dev/null +++ b/drivers/gpu/drm/smidrm/hw770.h @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2023, SiliconMotion Inc. + + +#ifndef LYNX_HW770_H__ +#define LYNX_HW770_H__ + +#include "hw_com.h" + + +struct smi_770_register{ + uint32_t clock_enable, pll_ctrl[3]; + + uint32_t primary_display_ctrl[10], lvds_ctrl, primary_hwcurs_ctrl[4]; + uint32_t secondary_display_ctrl[10], secondary_hwcurs_ctrl[4]; +}; + +struct smi_770_fb_info{ + unsigned int fb_addr; + unsigned long fb_pitch; + +}; + +void hw770_setDisplayPlaneDisableOnly( + disp_control_t dispControl /* Channel 0 or Channel 1) */ +); + + +void hw770_enable_lvds(int channels); + +void ddk770_set_mmio(volatile unsigned char * addr,unsigned short devId,char revId); +unsigned long ddk770_getFrameBufSize(void); +long ddk770_initChip(void); + + +void ddk770_swPanelPowerSequence( + disp_control_t dispControl, + disp_state_t dispState, + disp_control_t dataPath, + unsigned long vSyncDelay +); + + +int hw770_get_hdmi_edid(hdmi_index index, unsigned char *pEDIDBuffer); +int hw770_get_dp_edid(dp_index index, unsigned char *pEDIDBuffer); + + +int hw770_set_dp_mode(logicalMode_t *pLogicalMode, struct drm_display_mode mode, int dp_index); + + + +void DP_Enable_Output(dp_index index); + +void hw770_DP_Disable_Output(dp_index index); + + +/* + * Disable double pixel clock. + * This is a teporary function, used to patch for the random fuzzy font problem. + */ +void hw770_SetPixelClockFormat(disp_control_t dispControl,unsigned int is_half); + +void ddk770_EnableChannelTiming( + disp_control_t dispControl, /* Channel 0 or Channel 1) */ + unsigned short enable +); + +/* + * This function initializes the cursor attributes. + */ +void ddk770_initCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long base, /* Base Address */ + unsigned long color1, /* Cursor color 1 in RGB 5:6:5 format */ + unsigned long color2, /* Cursor color 2 in RGB 5:6:5 format */ + unsigned long color3 /* Cursor color 3 in RGB 5:6:5 format */ +); + +/* + * This function sets the cursor position. + */ +void ddk770_setCursorPosition( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long dx, /* X Coordinate of the cursor */ + unsigned long dy, /* Y Coordinate of the cursor */ + unsigned char topOutside, /* Top Boundary Select: either partially outside (= 1) + or within the screen top boundary (= 0) */ + unsigned char leftOutside, /* Left Boundary Select: either partially outside (= 1) + or within the screen left boundary (= 0) */ + unsigned int enable +); + +void hw770_set_base(disp_control_t dispControl,int pitch,int base_addr); + +/* + * This function enables/disables the cursor. + */ +void ddk770_enableCursor( + disp_control_t dispControl, /* Display control (CHANNEL0_CTRL or CHANNEL1_CTRL) */ + unsigned long enable +); + +void ddk770_HDMI_Enable_Output(hdmi_index index); +void hw770_HDMI_Disable_Output(hdmi_index index); +void ddk770_HDMI_Set_Channel(hdmi_index index, disp_control_t dc); + +void hw770_HDMI_Clear_Channel(hdmi_index index); + +void hw770_DP_Clear_Channel(dp_index index); + +int hw770_hdmi_vga_mode(hdmi_index index); + + +void DP_Set_Channel(dp_index index, disp_control_t dc); + + +void ddk770_setDisplayDPMS( + disp_control_t dispControl, /* Channel 0 or Channel 1) */ + DISP_DPMS_t state /* DPMS state */ + ); + +void hw770_init_hdmi(void); +int hw770_set_hdmi_mode(logicalMode_t *pLogicalMode, struct drm_display_mode mode, bool isHDMI, int hdmi_index); + + +int hw770_check_iis_interrupt(void); + +int hw770_check_vsync_interrupt(int path); +void hw770_clear_vsync_interrupt(int path); + +long hw770_setMode(logicalMode_t *pLogicalMode, struct drm_display_mode mode); + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0) +int hw770_en_dis_interrupt(int status, int pipe); +#else +int hw770_en_dis_interrupt(int status); +#endif + +long ddk770_HDMI_HPD_Detect(hdmi_index index); + +int DP_HPD_Detect(dp_index dp_index); + +void ddk770_disable_IntMask(void); + +void hw770_suspend(struct smi_770_register * pSave); +void hw770_resume(struct smi_770_register * pSave); + +void hw770_setgamma(disp_control_t dispCtrl, unsigned long enable); +void hw770_load_lut(disp_control_t dispCtrl, int size, u8 lut_r[], u8 lut_g[], u8 lut_b[]); + +long hw770_AdaptI2CCleanBus( + struct drm_connector *connector +); +long hw770_AdaptI2CInit(struct smi_connector *smi_connector); + +void hw770_AudioInit(unsigned long wordLength, unsigned long sampleRate); +void hw770_AudioStart(void); +void hw770_AudioStop(void); +void hw770_AudioDeinit(void); + +void hw770_init_dp(void); +void ddk770_iis_Init(void); +int hw770_dp_detect(dp_index dp_index); +void ddk770_iisClearRawInt(void); +unsigned long ddk770_iisDmaPointer(void); + +void ddk770_sb_IRQUnmask(int irq_num); + +unsigned char ddk770_WM8978_Init(void); +void ddk770_WM8978_DeInit(void); +void ddk770_WM8978_HPvol_Set(unsigned char voll, unsigned char volr); +void ddk770_WM8978_SPKvol_Set(unsigned char volx); + +unsigned short alignLineOffset(unsigned short lineOffset); + +int hw770_hdmi_detect(hdmi_index hdmi_index); +int hw770_check_pnp_interrupt(hdmi_index index); +void hw770_hdmi_interrupt_enable(hdmi_index index,int enable); + +void hw770_get_current_fb_info(disp_control_t index, struct smi_770_fb_info *fb_info); +void hw770_set_current_pitch(disp_control_t index, struct smi_770_fb_info *fb_info); +void hw770_i2c_reset_busclear(hdmi_index index); +int hw770_dp_check_sink_status(dp_index index); + +int hw770_get_current_mode_width(disp_control_t index); + +void SetCursorPrefetch(disp_control_t dispControl, unsigned int enable); +#endif diff --git a/drivers/gpu/drm/smidrm/hw_com.h b/drivers/gpu/drm/smidrm/hw_com.h new file mode 100644 index 000000000000..43a0bce8f575 --- /dev/null +++ b/drivers/gpu/drm/smidrm/hw_com.h @@ -0,0 +1,472 @@ +/* + * Copyright 2016 SiliconMotion Inc. + * + * This file is subject to the terms and conditions of the GNU General + * Public License version 2. See the file COPYING in the main + * directory of this archive for more details. + * + */ + + + +#ifndef LYNX_HW_COM_H__ +#define LYNX_HW_COM_H__ + +/* Maximum parameters those can be saved in the mode table. */ +#define MAX_MODE_TABLE_ENTRIES 60 +#define PITCH(width, bpp) (((width) * (bpp) / 8 + 15) & ~15) + +/* + * ID of the modeInfoID used in the userDataParam_t + */ +#define MODE_INFO_INDEX 0x01 +#define EDID_DEVICE_I2C_ADDRESS 0xA0 +#define TOTAL_EDID_REGISTERS 128 +#define READ_EDID_CONTINUOUS + + + +/* Set the alignment to 1-bit aligned. Otherwise, the memory compare used in the + modeext to compare timing will not work. */ +#pragma pack(1) + +typedef enum _disp_path_t +{ + SMI0_PATH = 0, + SMI1_PATH = 1, +} +disp_path_t; + +typedef enum _disp_control_t +{ + CHANNEL0_CTRL = 0, + CHANNEL1_CTRL = 1, + CHANNEL2_CTRL = 2, + ERROR_CTRL = 3, +} +disp_control_t; + +typedef enum _disp_state_t +{ + DISP_OFF = 0, + DISP_ON = 1, +} +disp_state_t; +typedef enum _DPMS_t +{ + DPMS_ON, + DPMS_STANDBY, + DPMS_SUSPEND, + DPMS_OFF +} +DPMS_t; + +typedef enum _DISP_DPMS_t +{ + DISP_DPMS_ON, + DISP_DPMS_STANDBY, + DISP_DPMS_SUSPEND, + DISP_DPMS_OFF +} +DISP_DPMS_t; + +typedef enum{ + INDEX_HDMI0 = 0, + INDEX_HDMI1, + INDEX_HDMI2, +} hdmi_index; + +typedef enum{ + INDEX_DP0 = 0, + INDEX_DP1, + INDEX_DP_PHY +} dp_index; + + +typedef enum _spolarity_t +{ + NEG, /* negative */ + POS, /* positive */ +} +spolarity_t; + +typedef struct _mode_parameter_t +{ + /* Horizontal timing. */ + unsigned long horizontal_total; + unsigned long horizontal_display_end; + unsigned long horizontal_sync_start; + unsigned long horizontal_sync_width; + spolarity_t horizontal_sync_polarity; + + /* Vertical timing. */ + unsigned long vertical_total; + unsigned long vertical_display_end; + unsigned long vertical_sync_start; + unsigned long vertical_sync_height; + spolarity_t vertical_sync_polarity; + + /* Refresh timing. */ + unsigned long pixel_clock; + unsigned long horizontal_frequency; + unsigned long vertical_frequency; + + /* Clock Phase. This clock phase only applies to Panel. */ + spolarity_t clock_phase_polarity; + +} +mode_parameter_t; + +typedef struct _userDataParam_t +{ + unsigned long size; /* Size of this parameter */ + unsigned char modeInfoID; /* Mode information ID */ + + /* As the modeInfoID might be expanded in the future to support more stuffs as necessary, + the following parameter list might be expanded in the future. */ + union + { + unsigned char index; /* The index of the mode timing of the given resolution: + 0 - The first mode timing found in the table + 1 - The second mode timing found in the table + etc... + */ + /* Add more user data information parameters here as necessary. */ + } paramInfo; +} userDataParam_t; + +/* + * Structure that is used as userData pointer in the logicalMode_t + */ +typedef struct _userData_t +{ + unsigned long signature; /* Signature of the userData pointer. + It has to be filled with user data Signature to be a valid + structure pointer. The signature can be obtained by + calling ddk770_getUserDataSignature function. + */ + unsigned long size; /* Size of this data structure. */ + userDataParam_t paramList; /* List of parameters those are associated with this userData + Currently, only one modeInfoID is supported. Later on, when + the ID is expanded, then the paramList might be expanded + as an array. */ +} +userData_t; + +typedef struct _logicalMode_t +{ + unsigned long x; /* X resolution */ + unsigned long y; /* Y resolution */ + unsigned long bpp; /* Bits per pixel */ + unsigned long hz; /* Refresh rate */ + + unsigned long baseAddress; /* Offset from beginning of frame buffer. + It is used to control the starting location of a mode. + Calling function must initialize this field. + */ + + unsigned long pitch; /* Mode pitch in byte. + If initialized to 0, setMode function will set + up this field. + If not zero, setMode function will use this value. + */ + unsigned long valid_edid; + disp_control_t dispCtrl; /* SECONDARY or PRIMARY display control channel */ + + /* These two parameters are used in the setModeEx. */ + unsigned long xLCD; /* Panel width */ + unsigned long yLCD; /* Panel height */ + + void *userData; /* Not used now, set it to 0 (for future used only) */ + +} +logicalMode_t; + +/* Standard Timing Structure */ +typedef struct _standard_timing_t +{ + unsigned char horzActive; /* (Horizontal active pixels / 8 ) - 31 */ + struct + { + unsigned char refreshRate:6; /* Refresh Rate (Hz) - 60; Range 60 --> 123 */ + unsigned char aspectRatio:2; /* Aspect Ratio: + Bit 7 Bit 6 Operation + 0 0 1:1 (prior Version 1.3) + 0 0 16:10 (Version 1.3) + 0 1 4:3 + 1 0 5:4 + 1 1 16:9 + */ + } stdTimingInfo; +} standard_timing_t; + +/* Detailed Timing Description Structure */ +typedef struct _detailed_timing_t +{ + unsigned short pixelClock; + unsigned char horzActive; + unsigned char horzBlanking; + struct + { + unsigned char horzBlankingMSB:4; + unsigned char horzActiveMSB:4; + } horzActiveBlanking; + unsigned char vertActive; + unsigned char vertBlanking; + struct + { + unsigned char vertBlankingMSB:4; + unsigned char vertActiveMSB:4; + } vertActiveBlanking; + unsigned char horzSyncOffset; + unsigned char horzSyncPulseWidth; + struct + { + unsigned char syncWidth:4; + unsigned char syncOffset:4; + } verticalSyncInfo; + struct + { + unsigned char vertSyncWidth:2; + unsigned char vertSyncOffset:2; + unsigned char horzSyncWidth:2; + unsigned char horzSyncOffset:2; + } syncAuxInfo; + unsigned char horzImageSize; + unsigned char vertImageSize; + struct + { + unsigned char vertImageSizeMSB:4; + unsigned char horzImageSizeMSB:4; + } horzVertImageSize; + unsigned char horzBorder; + unsigned char vertBorder; + struct + { + unsigned char interleaved:1; + unsigned char horzSyncFlag:1; + unsigned char vertSyncFlag:1; + unsigned char connectionType:2; + unsigned char stereo:2; + unsigned char interlaced:1; + } flags; +} detailed_timing_t; + +typedef struct _color_point_t +{ + unsigned char whitePointIndex; + struct + { + unsigned char whiteYLowBits:2; + unsigned char whiteXLowBits:2; + unsigned char reserved:4; + } whiteLowBits; + unsigned char whiteX; + unsigned char whiteY; + unsigned char gamma; +} color_point_t; + +typedef struct _monitor_desc_t +{ + unsigned short flag1; /* Flag = 0000h when block used as descriptor */ + unsigned char flag2; /* Flag = 00h when block used as descriptor */ + unsigned char dataTypeTag; /* Data type tag: + FFh: Monitor Serial Number - Stored as ASCII, + code page #437, <= 13bytes + FEh: ASCII String - Stored as ASCII, code + page #437, <= 13 bytes + FDh: Monitor range limits, binary coded + FCh: Monitor name, stored as ASCII, code page #437 + FBh: Descriptor contains additional color point data + FAh: Descriptor contains additional Standard Timing + Identifications + F9h-11h: Currently undefined + 10h: Dummy descriptor, used to indicate + that the descriptor space is unused + 0Fh-00h: Descriptor defined by manufacturer. + */ + unsigned char flag3; /* Flag = 00h when block used as descriptor */ + union + { + unsigned char serialNo[13]; + unsigned char dataString[13]; + struct + { + unsigned char minVertRate; + unsigned char maxVertRate; + unsigned char minHorzFrequency; + unsigned char maxHorzFrequency; + unsigned char maxPixelClock; /* Binary coded clock rate in MHz / 10 + Max Pixel Clock those are not a multiple of 10MHz + is rounded up to a multiple of 10MHz + */ + unsigned char secondaryTimingFlag; /* 00h = No secondary timing formula supported + (Support for default GTF indicated in feature byte) + 02h = Channel1 GTF curve supported + All other = Reserved for future timing formula + definitions. + */ + union + { + unsigned char constantStr[7]; + struct + { + unsigned char reserved; + unsigned char startFrequency; + unsigned char cParam; + unsigned short mParam; + unsigned char kParam; + unsigned char jParam; + } cmkjParam; + } secondaryTimingInfo; + } monitorRange; + + unsigned char monitorName[13]; + struct + { + color_point_t white[2]; + unsigned char reserved[3]; /* Set to (0Ah, 20h, 20h)*/ + } colorPoint; + + struct + { + standard_timing_t stdTiming[6]; + unsigned char reserved; /* Set to 0Ah */ + } stdTimingExt; + + unsigned char manufactureSpecifics[13]; + } descriptor; +} +monitor_desc_t; + +/* EDID Structuve Version 1. Within version 1 itself, there are 4 revisions mentioned + below: + - EDID 1.0: The original 128-byte data format + - EDID 1.1: Added definitions for monitor descriptors as an alternate use of the space + originally reserved for detailed timings, as well as definitions for + previously unused fields. + - EDID 1.2: Added definitions to existing data fields. + - EDID 1.3: Added definitions for secondary GTF curve coefficients. This is the new + baseline for EDID data structures, which is recommended for all new monitor + designs. + */ +typedef struct _edid_version_1_t +{ + /* Header (8 bytes) */ + unsigned char header[8]; /* Header */ + + /* Vendor / Product ID (10 bytes) */ + unsigned short manufacturerID; /* Manufacture Identification */ + unsigned short productCode; /* Product code Identification */ + unsigned long serialNumber; /* Serial Number */ + unsigned char weekOfManufacture; /* Week of Manufacture */ + unsigned char yearOfManufacture; /* Year of Manufacture */ + + /* EDID Structure version / revision (2 bytes) */ + unsigned char version; /* EDID Structure Version no. */ + unsigned char revision; /* Revision Version no. */ + + /* Basic Display Parameters / Features (5 bytes) */ + union + { + struct + { + unsigned char vsyncSerration:1; + unsigned char syncOnGreenSupport:1; + unsigned char compositeSyncSupport:1; + unsigned char separateSyncSupport:1; + unsigned char blank2Black:1; + unsigned char signalLevelStd:2; + unsigned char inputSignal:1; /* Input Signal: Analog = 0, Digital = 1 */ + } analogSignal; + struct + { + unsigned char dfp1Support:1; + unsigned char reserved:6; + unsigned char inputSignal:1; /* Input Signal: Analog = 0, Digital = 1 */ + } digitalSignal; + } videoInputDefinition; /* Video Input Definition */ + + unsigned char maxHorzImageSize; /* Maximum Horizontal Image Size */ + unsigned char maxVertImageSize; /* Maximum Vertical Image Size */ + unsigned char displayTransferChar; /* Display Transfer Characteristic (Gamma) */ + struct + { + unsigned char defaultGTFSupport:1; /* Support timings based on the GTF standard using + default GTF parameters + */ + unsigned char preferredTiming:1; /* If set, the display's preferred timing mode is + indicated in the first detailed timing block. + */ + unsigned char sRGBSupport:1; /* If set, the display uses the sRGB standard + default color space as its primary color space + */ + unsigned char displayType:2; /* Display Type: + 00 - Monochrome / Grayscale display + 01 - RGB Color Display + 10 - Non-RGB multicolor display, e.g. R/G/Y + 11 - Undefined + */ + unsigned char lowPowerSupport:1; /* If set, the display consumes much less power when + it receives a timing signal outside its active + operating range. It will revert to normal if the + timing returns to the normal operating range. + */ + unsigned char suspendSupport:1; /* Support Suspend as defined in VESA DPMS spec. */ + unsigned char standbySupport:1; /* Support Standby as defined in VESA DPMS spec. */ + } featureSupport; /* Feature Support */ + + /* Color Characteristics (10 bytes) */ + struct + { + unsigned char greenYLowBits:2; + unsigned char greenXLowBits:2; + unsigned char redYLowBits:2; + unsigned char redXLowBits:2; + } redGreenLowBits; /* Red/Green Low Bits */ + struct + { + unsigned char whiteYLowBits:2; + unsigned char whiteXLowBits:2; + unsigned char blueYLowBits:2; + unsigned char blueXLowBits:2; + } blueWhiteLowBits; /* Blue/White Low Bits */ + unsigned char redX; /* Red-x bits 9-2 */ + unsigned char redY; /* Red-y bits 9-2 */ + unsigned char greenX; /* Green-x bits 9-2 */ + unsigned char greenY; /* Green-y bits 9-2 */ + unsigned char blueX; /* Blue-x bits 9-2 */ + unsigned char blueY; /* Blue-y bits 9-2 */ + unsigned char whiteX; /* White-x bits 9-2 */ + unsigned char whiteY; /* White-y bits 9-2 */ + + /* Established Timings (3 bytes) */ + unsigned char estTiming[3]; /* Established Timings */ + + /* Standard Timing Identification (16 bytes) */ + standard_timing_t stdTiming[8]; /* Standard Timings Identification */ + + /* Detailed Timing Descriptions (72 bytes) */ + union + { + detailed_timing_t detailTiming[4]; /* Detailed Timing Descriptor */ + monitor_desc_t monitorDesc[4]; /* Monitor descriptor */ + } miscInformation; + + /* Extension Flag (1 byte) */ + unsigned char extFlag; /* Number of (optional) 1280byte EDID + extension blocks to follow. + */ + + /* Checksum (1 byte) */ + unsigned char checksum; /* The 1-byte sum of all 128 bytes in + this EDID block shall equal zero. + */ +} +edid_version_1_t; + +/* Restore alignment */ +#pragma pack() + +#endif + diff --git a/drivers/gpu/drm/smidrm/smi_drv.c b/drivers/gpu/drm/smidrm/smi_drv.c new file mode 100644 index 000000000000..4e3777316a9a --- /dev/null +++ b/drivers/gpu/drm/smidrm/smi_drv.c @@ -0,0 +1,846 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2023, SiliconMotion Inc. + +#include +#include +#include +#include +#include "smi_drv.h" +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) +#include +#endif + +#include "hw750.h" +#include "hw768.h" +#include "hw770.h" + + +int smi_modeset = -1; +int smi_indent = 0; +int smi_bpp = 32; +int force_connect = 0; +int smi_pat = 0xff; +int lvds_channel = 0; +int audio_en = 0; +int fixed_width = 0; +int fixed_height = 0; +int hwi2c_en = 0; +int swcur_en = 0; +int edid_mode = 1; +int smi_debug = 0; +int lcd_scale = 0; +int pwm_ctrl = 0; +int clk_phase = -1; + + + +extern void hw750_suspend(struct smi_750_register * pSave); +extern void hw750_resume(struct smi_750_register * pSave); + + +module_param(smi_pat,int, S_IWUSR | S_IRUSR); + + +MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); +module_param_named(modeset, smi_modeset, int, 0400); +MODULE_PARM_DESC(bpp, "Max bits-per-pixel (default:32)"); +module_param_named(bpp, smi_bpp, int, 0400); +MODULE_PARM_DESC(nopnp, "Force conncet to the monitor without monitor EDID (default:0) bit0:DVI,bit1:VGA,bit2:HDMI SM770: bit3-5 HDMI0-2, bit6-7 DP0-1"); +module_param_named(nopnp, force_connect, int, 0400); +MODULE_PARM_DESC(lvds, "LVDS Channel, 0=disable 1=single channel, 2=dual channel (default:0)"); +module_param_named(lvds, lvds_channel, int, 0400); +MODULE_PARM_DESC(width, "Fixed mode width for LVDS or nopnp (default:0)"); +module_param_named(width, fixed_width, int, 0400); +MODULE_PARM_DESC(height, "Fixed mode height for LVDS or nopnp (default:0)"); +module_param_named(height, fixed_height, int, 0400); +MODULE_PARM_DESC(audio, "SM768/SM770 Audio, 0=diable 1=use UDA1345 Codec, 2=use WM8978 Codec(default:0), SM770 only support HDMI/DP Audio"); +module_param_named(audio, audio_en, int, 0400); +MODULE_PARM_DESC(hwi2c, "HW I2C for EDID reading for SM750/SM768, 0=SW I2C 1=HW I2C(default:0)"); +module_param_named(hwi2c, hwi2c_en, int, 0400); +MODULE_PARM_DESC(swcur, "Use Software cursor, 0=HW Cursor 1=SW Cursor(default:0)"); +module_param_named(swcur, swcur_en, int, 0400); +MODULE_PARM_DESC(edidmode, "Use Monitor EDID mode timing, 0 = Driver build-in mode timing 1 = Monitor EDID mode timing(default:1)"); +module_param_named(edidmode, edid_mode, int, 0400); +MODULE_PARM_DESC(debug, "Driver debug log enable, 0 = disable 1 = enable (default:0)"); +module_param_named(debug, smi_debug, int, 0400); +MODULE_PARM_DESC(lcdscale, "LCD(LVDS) scale enable, 0 = disable 1 = enable (default:0)"); +module_param_named(lcdscale, lcd_scale, int, 0400); +MODULE_PARM_DESC(pwm, "PWM Value, 0 = disable (default:0) bit 0-3: PWM 0/1/2 bit4-7: PWM Divider bit8-19: PWM Low Counter bit20-31: PWM High Counter"); +module_param_named(pwm, pwm_ctrl, int, 0400); +MODULE_PARM_DESC(clkphase, "Panel Mode Clock phase, -1 = Use Mode table (Default) 0 = Negative 1 = Postive"); +module_param_named(clkphase, clk_phase, int, 0400); + + + +/* + * This is the generic driver code. This binds the driver to the drm core, + * which then performs further device association and calls our graphics init + * functions + */ +#define PCI_VENDOR_ID_SMI 0x126f +#define PCI_DEVID_SM750 0x0750 +#define PCI_DEVID_SM768 0x0768 +#define PCI_DEVID_SM770 0x0770 + +static struct drm_driver driver; + +/* only bind to the smi chip in qemu */ +static const struct pci_device_id pciidlist[] = { + { PCI_VENDOR_ID_SMI, PCI_DEVID_SM750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_SMI, PCI_DEVID_SM768, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_SMI, PCI_DEVID_SM770, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { + 0, + } +}; + + +static int smi_kick_out_firmware_fb(struct pci_dev *pdev) +{ + struct apertures_struct *ap; + bool primary = false; + + ap = alloc_apertures(1); + if (!ap) + return -ENOMEM; + + ap->ranges[0].base = pci_resource_start(pdev, 0); + ap->ranges[0].size = pci_resource_len(pdev, 0); + +#ifdef CONFIG_X86 + primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0)) + drm_fb_helper_remove_conflicting_framebuffers(ap, "smidrmfb", primary); +#else + remove_conflicting_framebuffers(ap, "smidrmfb", primary); +#endif + + + kfree(ap); + + return 0; +} + +static void claim(void) +{ + printk("+-------------SMI Driver Information------------+\n"); + printk("Release type: " RELEASE_TYPE "\n"); + printk("Driver version: v" _version_ "\n"); + printk("Support products: " SUPPORT_CHIP "\n"); + printk("+-----------------------------------------------+\n"); +} + + +static int smi_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int ret; + + ret = smi_kick_out_firmware_fb(pdev); + if (ret) + return ret; + + claim(); + if (ent->vendor != PCI_VENDOR_ID_SMI && + !(ent->device == PCI_DEVID_LYNX_EXP || ent->device == PCI_DEVID_SM768 || ent->device == PCI_DEVID_SM770)) { + return -ENODEV; + } + + if (ent->vendor == PCI_VENDOR_ID_SMI && (ent->device == PCI_DEVID_SM768 || ent->device == PCI_DEVID_SM770)) { + + if (lvds_channel != 0) { + dbg_msg("LVDS channel set to %d\n", lvds_channel); + } + } + + + return drm_get_pci_dev(pdev, ent, &driver); +} + +static void smi_pci_remove(struct pci_dev *pdev) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + + drm_put_dev(dev); +} + + + +static int smi_drm_freeze(struct drm_device *dev) +{ + struct smi_device *sdev = dev->dev_private; + + ENTER(); + + drm_kms_helper_poll_disable(dev); + + pci_save_state(dev->pdev); + + if (sdev->mode_info.gfbdev) { + console_lock(); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0)) + drm_fb_helper_set_suspend(&sdev->mode_info.gfbdev->helper, 1); + +#else + fb_set_suspend(sdev->mode_info.gfbdev->helper.fbdev, 1); + +#endif + console_unlock(); + } + + if (sdev->specId == SPC_SM750){ + hw750_suspend(sdev->regsave); + }else if(sdev->specId == SPC_SM768){ +#ifndef NO_AUDIO + if(audio_en) + smi_audio_suspend(sdev); +#endif + hw768_suspend(sdev->regsave_768); + }else if(sdev->specId == SPC_SM770){ +#ifndef NO_AUDIO + if(audio_en) + smi_audio_suspend(sdev); +#endif + hw770_suspend(sdev->regsave_770); + hw770_HDMI_Disable_Output(0); + hw770_HDMI_Disable_Output(1); + hw770_HDMI_Disable_Output(2); + + } + LEAVE(0); + +} + +static int smi_drm_thaw(struct drm_device *dev) +{ + struct smi_device *sdev = dev->dev_private; + + ENTER(); + + drm_mode_config_reset(dev); + drm_helper_resume_force_mode(dev); + + if (sdev->mode_info.gfbdev) { + console_lock(); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0)) + drm_fb_helper_set_suspend(&sdev->mode_info.gfbdev->helper, 0); +#else + fb_set_suspend(sdev->mode_info.gfbdev->helper.fbdev, 0); +#endif + smi_fb_zfill(dev, sdev->mode_info.gfbdev); + + console_unlock(); + } + + + if(sdev->specId == SPC_SM750){ + + hw750_resume(sdev->regsave); + }else if(sdev->specId == SPC_SM768){ + + hw768_resume(sdev->regsave_768); +#ifndef NO_AUDIO + if(audio_en) + smi_audio_resume(sdev); +#endif + if(sdev->m_connector & USE_DVI){ + if (lvds_channel == 1){ + hw768_enable_lvds(1); + DisableDoublePixel(0); + } + else if (lvds_channel == 2) { + hw768_enable_lvds(2); + EnableDoublePixel(0); + } + } + }else if(sdev->specId == SPC_SM770){ + hw770_resume(sdev->regsave_770); +#ifndef NO_AUDIO + if(audio_en) + smi_audio_resume(sdev); +#endif + + } + LEAVE(0); +} + + +static int smi_drm_resume(struct drm_device *dev) +{ + struct smi_device *UNUSED(sdev) = dev->dev_private; + int ret; + + ENTER(); + + if (pci_enable_device(dev->pdev)) + return -EIO; + + ret = smi_drm_thaw(dev); + if (ret) + return ret; + + drm_kms_helper_poll_enable(dev); + + LEAVE(0); +} + + +static int smi_pm_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *ddev = pci_get_drvdata(pdev); + int error; + + error = smi_drm_freeze(ddev); + if (error) + return error; + + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + return 0; + +} + + +static int smi_pm_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *ddev = pci_get_drvdata(pdev); + return smi_drm_resume(ddev); +} + + + + +static int smi_pm_freeze(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *ddev = pci_get_drvdata(pdev); + + if (!ddev || !ddev->dev_private) + return -ENODEV; + return smi_drm_freeze(ddev); + +} + + +static int smi_pm_thaw(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *ddev = pci_get_drvdata(pdev); + return smi_drm_thaw(ddev); + +} + + +static int smi_pm_poweroff(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *ddev = pci_get_drvdata(pdev); + + return smi_drm_freeze(ddev); + + +} + +static int smi_enable_vblank(struct drm_device *dev, unsigned int pipe) +{ + struct smi_device *sdev = dev->dev_private; + + if (sdev->specId == SPC_SM750) { + hw750_en_dis_interrupt(1, pipe); + } else if (sdev->specId == SPC_SM768) { + hw768_en_dis_interrupt(1, pipe); + }else if (sdev->specId == SPC_SM770) { + hw770_en_dis_interrupt(1, pipe); + } + return 0; +} + + +static void smi_disable_vblank(struct drm_device *dev, unsigned int pipe) +{ + struct smi_device *sdev = dev->dev_private; + + if (sdev->specId == SPC_SM750) { + hw750_en_dis_interrupt(0, pipe); + } else if (sdev->specId == SPC_SM768) { + hw768_en_dis_interrupt(0, pipe); + } else if (sdev->specId == SPC_SM770) { + hw770_en_dis_interrupt(0, pipe); + } +} + + +static void smi_irq_preinstall(struct drm_device *dev) +{ + //To Do.... + /* Disable *all* interrupts */ + + /* Clear bits if they're already high */ + +} + +static int smi_irq_postinstall(struct drm_device *dev) +{ + return 0; +} + +static void smi_irq_uninstall(struct drm_device *dev) +{ + struct smi_device *sdev = dev->dev_private; + + /* Disable *all* interrupts */ + if (sdev->specId == SPC_SM750) { + ddk750_disable_IntMask(); + } else if (sdev->specId == SPC_SM768) { + ddk768_disable_IntMask(); + } else if (sdev->specId == SPC_SM770) { + ddk770_disable_IntMask(); + } + +} + + +irqreturn_t smi_drm_interrupt(int irq, void *arg) +{ + struct drm_device *dev = (struct drm_device *)arg; + + int handled = 0; + struct smi_device *sdev = dev->dev_private; + + if (sdev->specId == SPC_SM750) { + if (hw750_check_vsync_interrupt(0)) { + /* Clear the panel VSync Interrupt */ + drm_handle_vblank(dev, 0); + handled = 1; + hw750_clear_vsync_interrupt(0); + } + if (hw750_check_vsync_interrupt(1)) { + drm_handle_vblank(dev, 1); + handled = 1; + hw750_clear_vsync_interrupt(1); + } + } else if (sdev->specId == SPC_SM768) { + if (hw768_check_vsync_interrupt(0)) { + /* Clear the panel VSync Interrupt */ + drm_handle_vblank(dev, 0); + handled = 1; + hw768_clear_vsync_interrupt(0); + } + if (hw768_check_vsync_interrupt(1)) { + drm_handle_vblank(dev, 1); + handled = 1; + hw768_clear_vsync_interrupt(1); + } + } else if(sdev->specId == SPC_SM770){ + if (hw770_check_vsync_interrupt(0)) { + /* Clear the panel VSync Interrupt */ + drm_handle_vblank(dev, 0); + handled = 1; + hw770_clear_vsync_interrupt(0); + } + if (hw770_check_vsync_interrupt(1)) { + drm_handle_vblank(dev, 1); + handled = 1; + hw770_clear_vsync_interrupt(1); + } + } + + if (handled) + return IRQ_HANDLED; + return IRQ_NONE; +} + + +irqreturn_t smi_hdmi0_hardirq(int irq, void *dev_id) +{ + int ret; + + ret = hw770_check_pnp_interrupt(0); + if(!ret) + return IRQ_NONE; + else if (ret == HDMI_INT_HPD) + { + return IRQ_WAKE_THREAD; + } + + return IRQ_HANDLED; +} + +irqreturn_t smi_hdmi1_hardirq(int irq, void *dev_id) +{ + int ret; + + ret = hw770_check_pnp_interrupt(1); + if(!ret) + return IRQ_NONE; + else if (ret == HDMI_INT_HPD) + { + return IRQ_WAKE_THREAD; + } + + return IRQ_HANDLED; +} + +irqreturn_t smi_hdmi2_hardirq(int irq, void *dev_id) +{ + int ret; + + ret = hw770_check_pnp_interrupt(2); + if(!ret) + return IRQ_NONE; + else if (ret == HDMI_INT_HPD) + { + return IRQ_WAKE_THREAD; + } + + return IRQ_HANDLED; +} + + +irqreturn_t smi_hdmi0_pnp_handler(int irq, void *dev_id) +{ + struct drm_display_mode *mode; + struct smi_device *sdev; + struct drm_device *dev; + logicalMode_t logicalMode; + unsigned long refresh_rate; + struct drm_crtc *crtc0; + struct smi_770_fb_info fb_info = {0}; + int monitor_status = 0; + int ret = 0; + + dev = dev_id; + sdev = dev->dev_private; + monitor_status = hw770_hdmi_detect(0); + if(!monitor_status) + { + drm_kms_helper_hotplug_event(dev); + return IRQ_HANDLED; + } + crtc0 = sdev->smi_enc_tab[2]->crtc; + if (crtc0) { + dbg_msg("CRTC0 found: %p\n", crtc0); + } else { + dbg_msg("CRTC0 not found\n"); + goto error; + } + + mode = &crtc0->mode; + + if(!mode) + goto error; + + refresh_rate = drm_mode_vrefresh(mode); + hw770_get_current_fb_info(0,&fb_info); + + logicalMode.valid_edid = false; + if (sdev->hdmi0_edid && drm_edid_header_is_valid((u8 *)sdev->hdmi0_edid) == 8) + logicalMode.valid_edid = true; + + logicalMode.x = mode->hdisplay; + logicalMode.y = mode->vdisplay; + logicalMode.bpp = smi_bpp; + logicalMode.hz = refresh_rate; + logicalMode.pitch = 0; + logicalMode.dispCtrl = 0; + + if (monitor_status) + { + dbg_msg("HDMI0: Monitor status is $%d\n", monitor_status); + hw770_setMode(&logicalMode, *mode); + ret = hw770_set_hdmi_mode(&logicalMode, *mode, sdev->is_hdmi[0], INDEX_HDMI0); + if (ret != 0) + { + dbg_msg("HDMI Mode not supported!\n"); + goto error; + } + hw770_set_current_pitch((disp_control_t)INDEX_HDMI0,&fb_info); + } + return IRQ_HANDLED; +error: + return IRQ_HANDLED; + +} + +irqreturn_t smi_hdmi1_pnp_handler(int irq, void *dev_id) +{ + struct drm_display_mode *mode; + struct smi_device *sdev; + struct drm_device *dev; + logicalMode_t logicalMode; + unsigned long refresh_rate; + struct drm_crtc *crtc1; + struct smi_770_fb_info fb_info = {0}; + + int monitor_status = 0; + int ret = 0; + + dev = dev_id; + sdev = dev->dev_private; + monitor_status = hw770_hdmi_detect(1); + if(!monitor_status) + { + drm_kms_helper_hotplug_event(dev); + return IRQ_HANDLED; + } + + crtc1 = sdev->smi_enc_tab[3]->crtc; + if (crtc1) { + dbg_msg("CRTC1 found: %p\n", crtc1); + } else { + dbg_msg("CRTC1 not found\n"); + goto error; + } + + mode = &crtc1->mode; + + + if(!mode) + goto error; + + refresh_rate = drm_mode_vrefresh(mode); + hw770_get_current_fb_info(1,&fb_info); + logicalMode.valid_edid = false; + if (sdev->hdmi1_edid && drm_edid_header_is_valid((u8 *)sdev->hdmi1_edid) == 8) + logicalMode.valid_edid = true; + + logicalMode.x = mode->hdisplay; + logicalMode.y = mode->vdisplay; + logicalMode.bpp = smi_bpp; + logicalMode.hz = refresh_rate; + logicalMode.pitch = 0; + logicalMode.dispCtrl = 1; + + if (monitor_status) + { + dbg_msg("HDMI1: Monitor status is $%d\n", monitor_status); + hw770_setMode(&logicalMode, *mode); + ret = hw770_set_hdmi_mode(&logicalMode, *mode, sdev->is_hdmi[1], INDEX_HDMI1); + if (ret != 0) + { + dbg_msg("HDMI Mode not supported!\n"); + goto error; + } + hw770_set_current_pitch((disp_control_t)INDEX_HDMI1,&fb_info); + } + return IRQ_HANDLED; +error: + return IRQ_HANDLED; + +} + +irqreturn_t smi_hdmi2_pnp_handler(int irq, void *dev_id) +{ + struct drm_display_mode *mode; + struct smi_device *sdev; + struct drm_device *dev; + logicalMode_t logicalMode; + unsigned long refresh_rate; + struct drm_crtc *crtc2; + struct smi_770_fb_info fb_info = {0}; + int monitor_status = 0; + int ret = 0; + + dev = dev_id; + sdev = dev->dev_private; + monitor_status = hw770_hdmi_detect(2); + if(!monitor_status) + { + drm_kms_helper_hotplug_event(dev); + return IRQ_HANDLED; + } + + crtc2 = sdev->smi_enc_tab[4]->crtc; + if (crtc2) { + dbg_msg("CRTC2 found: %p\n", crtc2); + } else { + dbg_msg("CRTC2 not found\n"); + goto error; + } + + mode = &crtc2->mode; + + if(!mode) + goto error; + + refresh_rate = drm_mode_vrefresh(mode); + hw770_get_current_fb_info(2,&fb_info); + logicalMode.valid_edid = false; + if (sdev->hdmi2_edid && drm_edid_header_is_valid((u8 *)sdev->hdmi2_edid) == 8) + logicalMode.valid_edid = true; + + logicalMode.x = mode->hdisplay; + logicalMode.y = mode->vdisplay; + logicalMode.bpp = smi_bpp; + logicalMode.hz = refresh_rate; + logicalMode.pitch = 0; + logicalMode.dispCtrl = 2; + + + if (monitor_status) + { + dbg_msg("HDMI2: Monitor status is $%d\n", monitor_status); + hw770_setMode(&logicalMode, *mode); + ret = hw770_set_hdmi_mode(&logicalMode, *mode, sdev->is_hdmi[2], INDEX_HDMI2); + if (ret != 0) + { + dbg_msg("HDMI Mode not supported!\n"); + goto error; + } + hw770_set_current_pitch((disp_control_t)INDEX_HDMI2,&fb_info); + } + return IRQ_HANDLED; +error: + return IRQ_HANDLED; + +} + + + + + + +static const struct file_operations smi_driver_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .unlocked_ioctl = drm_ioctl, + .mmap = smi_mmap, + .poll = drm_poll, +#ifdef CONFIG_COMPAT + .compat_ioctl = drm_compat_ioctl, +#endif + .read = drm_read, + .llseek = no_llseek, +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,1,0) +#define DRIVER_IRQ_SHARED 0 +#endif + +static struct drm_driver driver = { +#ifdef PRIME + .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |DRIVER_GEM |DRIVER_PRIME | DRIVER_MODESET, +#else + .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |DRIVER_GEM | DRIVER_MODESET, +#endif + .load = smi_driver_load, + .unload = smi_driver_unload, +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0))) + .set_busid = drm_pci_set_busid, +#endif + .fops = &smi_driver_fops, + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,12,0)) + .gem_init_object = smi_gem_init_object, +#endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)) + .gem_free_object = smi_gem_free_object, +#else + .gem_free_object_unlocked = smi_gem_free_object, +#endif + .dumb_create = smi_dumb_create, + .dumb_map_offset = smi_dumb_mmap_offset, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0)) + .dumb_destroy = smi_dumb_destroy, +#else + .dumb_destroy = drm_gem_dumb_destroy, +#endif +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0))) + .get_vblank_counter = drm_vblank_no_hw_counter, +#endif + .enable_vblank = smi_enable_vblank, + .disable_vblank = smi_disable_vblank, + .irq_preinstall = smi_irq_preinstall, + .irq_postinstall = smi_irq_postinstall, + .irq_uninstall = smi_irq_uninstall, + .irq_handler = smi_drm_interrupt, +#ifdef PRIME +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3,14,0)) + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + + .gem_prime_import = drm_gem_prime_import, + .gem_prime_export = drm_gem_prime_export, + + .gem_prime_get_sg_table = smi_gem_prime_get_sg_table, + .gem_prime_import_sg_table = smi_gem_prime_import_sg_table, + .gem_prime_vmap = smi_gem_prime_vmap, + .gem_prime_vunmap = smi_gem_prime_vunmap, + .gem_prime_pin = smi_gem_prime_pin, + .gem_prime_unpin = smi_gem_prime_unpin, +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)) + .gem_prime_res_obj = smi_gem_prime_res_obj, +#endif +#endif + +}; + +static const struct dev_pm_ops smi_pm_ops = { + .suspend = smi_pm_suspend, + .resume = smi_pm_resume, + .freeze = smi_pm_freeze, + .thaw = smi_pm_thaw, + .poweroff = smi_pm_poweroff, + .restore = smi_pm_resume, +}; + +static struct pci_driver smi_pci_driver = { + .name = DRIVER_NAME, + .id_table = pciidlist, + .probe = smi_pci_probe, + .remove = smi_pci_remove, + .driver.pm = &smi_pm_ops, +}; + +static int __init smi_init(void) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)) +#ifdef CONFIG_VGA_CONSOLE + if (vgacon_text_force() && smi_modeset == -1) + return -EINVAL; +#endif +#else + if (vgacon_text_force() && smi_modeset == -1) + return -EINVAL; + +#endif + if (smi_modeset == 0) + return -EINVAL; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)) + return drm_pci_init(&driver, &smi_pci_driver); +#else + return pci_register_driver(&smi_pci_driver); +#endif +} + +static void __exit smi_exit(void) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)) + drm_pci_exit(&driver, &smi_pci_driver); +#else + pci_unregister_driver(&smi_pci_driver); +#endif +} + +module_init(smi_init); +module_exit(smi_exit); + +MODULE_DEVICE_TABLE(pci, pciidlist); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_VERSION(_version_); + diff --git a/drivers/gpu/drm/smidrm/smi_drv.h b/drivers/gpu/drm/smidrm/smi_drv.h new file mode 100644 index 000000000000..71ad4dabbe58 --- /dev/null +++ b/drivers/gpu/drm/smidrm/smi_drv.h @@ -0,0 +1,559 @@ +/* + * Copyright 2016 SiliconMotion Inc. + * + * This file is subject to the terms and conditions of the GNU General + * Public License version 2. See the file COPYING in the main + * directory of this archive for more details. + * + */ + +#ifndef __SMI_DRV_H__ +#define __SMI_DRV_H__ + +#include "smi_ver.h" + +#include