From 378e6f13c85456cc9eb74e20d10921bc357eeb02 Mon Sep 17 00:00:00 2001 From: Liu Xinyun Date: Fri, 28 May 2010 13:36:28 +0800 Subject: [PATCH] add driver for IVI based on 1616 Patch-mainline: Never The code is from Intel internal and base on build 1616 References: BMC#2205: http://bugs.meego.com/show_bug.cgi?id=2205 Signed-off-by: Liu Xinyun Signed-off-by: Li Peng --- drivers/gpu/drm/Kconfig | 8 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/emgd/COPYING | 351 + drivers/gpu/drm/emgd/Makefile | 232 + drivers/gpu/drm/emgd/emgd/cfg/config.h | 125 + drivers/gpu/drm/emgd/emgd/cfg/config_default.h | 191 + drivers/gpu/drm/emgd/emgd/cfg/config_helper.c | 233 + drivers/gpu/drm/emgd/emgd/cfg/personality.h | 43 + .../gpu/drm/emgd/emgd/core/init/cmn/igd_global.c | 49 + drivers/gpu/drm/emgd/emgd/core/init/cmn/igd_init.c | 864 ++ .../drm/emgd/emgd/core/init/cmn/init_dispatch.h | 57 + drivers/gpu/drm/emgd/emgd/core/init/plb/init_plb.c | 657 ++ .../drm/emgd/emgd/core/init/plb/micro_init_plb.c | 386 + drivers/gpu/drm/emgd/emgd/core/init/tnc/init_tnc.c | 744 ++ .../drm/emgd/emgd/core/init/tnc/micro_init_tnc.c | 627 ++ drivers/gpu/drm/emgd/emgd/display/dsp/cmn/dsp.c | 2350 ++++++ .../drm/emgd/emgd/display/dsp/cmn/dsp_dispatch.h | 55 + .../gpu/drm/emgd/emgd/display/dsp/plb/dsp_plb.c | 659 ++ .../gpu/drm/emgd/emgd/display/dsp/tnc/dsp_tnc.c | 491 ++ .../gpu/drm/emgd/emgd/display/mode/cmn/igd_mode.c | 2216 ++++++ drivers/gpu/drm/emgd/emgd/display/mode/cmn/match.c | 1319 ++++ drivers/gpu/drm/emgd/emgd/display/mode/cmn/match.h | 49 + .../drm/emgd/emgd/display/mode/cmn/micro_mode.c | 1630 ++++ .../drm/emgd/emgd/display/mode/cmn/mode_dispatch.h | 163 + .../gpu/drm/emgd/emgd/display/mode/cmn/vga_mode.c | 1285 +++ .../drm/emgd/emgd/display/mode/plb/clocks_plb.c | 512 ++ .../emgd/emgd/display/mode/plb/micro_mode_plb.c | 1393 ++++ .../gpu/drm/emgd/emgd/display/mode/plb/mode_plb.c | 1434 ++++ .../drm/emgd/emgd/display/mode/tnc/clocks_tnc.c | 559 ++ .../emgd/emgd/display/mode/tnc/micro_mode_tnc.c | 1842 +++++ .../gpu/drm/emgd/emgd/display/mode/tnc/mode_tnc.c | 1479 ++++ drivers/gpu/drm/emgd/emgd/display/pd/cmn/pd.c | 517 ++ .../gpu/drm/emgd/emgd/display/pi/cmn/displayid.c | 1058 +++ drivers/gpu/drm/emgd/emgd/display/pi/cmn/edid.c | 1185 +++ .../drm/emgd/emgd/display/pi/cmn/i2c_dispatch.h | 70 + drivers/gpu/drm/emgd/emgd/display/pi/cmn/igd_pi.c | 260 + .../gpu/drm/emgd/emgd/display/pi/cmn/mode_table.c | 2436 ++++++ .../gpu/drm/emgd/emgd/display/pi/cmn/pd_init_all.c | 199 + drivers/gpu/drm/emgd/emgd/display/pi/cmn/pi.c | 1723 ++++ drivers/gpu/drm/emgd/emgd/display/pi/plb/i2c_plb.c | 940 +++ .../drm/emgd/emgd/display/pi/tnc/i2c_bitbash_tnc.c | 588 ++ .../drm/emgd/emgd/display/pi/tnc/i2c_gmbus_tnc.c | 925 +++ drivers/gpu/drm/emgd/emgd/drm/drm_emgd_private.h | 138 + drivers/gpu/drm/emgd/emgd/drm/emgd_drv.c | 1725 ++++ drivers/gpu/drm/emgd/emgd/drm/emgd_drv.h | 181 + drivers/gpu/drm/emgd/emgd/drm/emgd_fb.c | 625 ++ drivers/gpu/drm/emgd/emgd/drm/emgd_interface.c | 2046 +++++ drivers/gpu/drm/emgd/emgd/drm/emgd_mmap.c | 178 + drivers/gpu/drm/emgd/emgd/drm/emgd_test_pvrsrv.c | 1347 ++++ drivers/gpu/drm/emgd/emgd/drm/user_config.c | 317 + drivers/gpu/drm/emgd/emgd/drm/user_config.h | 105 + drivers/gpu/drm/emgd/emgd/gmm/gmm.c | 754 ++ drivers/gpu/drm/emgd/emgd/gmm/gtt.c | 522 ++ drivers/gpu/drm/emgd/emgd/include/cmd.h | 41 + drivers/gpu/drm/emgd/emgd/include/context.h | 240 + drivers/gpu/drm/emgd/emgd/include/debug.h | 168 + drivers/gpu/drm/emgd/emgd/include/decode.h | 70 + drivers/gpu/drm/emgd/emgd/include/dispatch.h | 53 + drivers/gpu/drm/emgd/emgd/include/dispatch_utils.h | 72 + drivers/gpu/drm/emgd/emgd/include/displayid.h | 644 ++ drivers/gpu/drm/emgd/emgd/include/dsp.h | 46 + drivers/gpu/drm/emgd/emgd/include/edid.h | 130 + drivers/gpu/drm/emgd/emgd/include/general.h | 84 + drivers/gpu/drm/emgd/emgd/include/instr_common.h | 48 + drivers/gpu/drm/emgd/emgd/include/intelpci.h | 87 + drivers/gpu/drm/emgd/emgd/include/memlist.h | 162 + drivers/gpu/drm/emgd/emgd/include/mode.h | 304 + drivers/gpu/drm/emgd/emgd/include/mode_access.h | 52 + drivers/gpu/drm/emgd/emgd/include/module_init.h | 103 + drivers/gpu/drm/emgd/emgd/include/msvdx.h | 231 + drivers/gpu/drm/emgd/emgd/include/pd.h | 743 ++ drivers/gpu/drm/emgd/emgd/include/pd_init.h | 191 + drivers/gpu/drm/emgd/emgd/include/pi.h | 85 + drivers/gpu/drm/emgd/emgd/include/plb/appcontext.h | 61 + drivers/gpu/drm/emgd/emgd/include/plb/cmd.h | 498 ++ drivers/gpu/drm/emgd/emgd/include/plb/context.h | 189 + drivers/gpu/drm/emgd/emgd/include/plb/instr.h | 224 + drivers/gpu/drm/emgd/emgd/include/plb/mi.h | 71 + drivers/gpu/drm/emgd/emgd/include/plb/regs.h | 711 ++ drivers/gpu/drm/emgd/emgd/include/plb/sgx.h | 211 + drivers/gpu/drm/emgd/emgd/include/plb/state3d.h | 392 + .../gpu/drm/emgd/emgd/include/plb/state3d_plb.h | 1293 +++ drivers/gpu/drm/emgd/emgd/include/psb_regs.h | 658 ++ drivers/gpu/drm/emgd/emgd/include/rb.h | 186 + drivers/gpu/drm/emgd/emgd/include/reset.h | 37 + drivers/gpu/drm/emgd/emgd/include/sched.h | 250 + drivers/gpu/drm/emgd/emgd/include/state2d.h | 63 + drivers/gpu/drm/emgd/emgd/include/tnc/appcontext.h | 34 + drivers/gpu/drm/emgd/emgd/include/tnc/cmd.h | 33 + drivers/gpu/drm/emgd/emgd/include/tnc/context.h | 31 + drivers/gpu/drm/emgd/emgd/include/tnc/instr.h | 40 + drivers/gpu/drm/emgd/emgd/include/tnc/mi.h | 35 + drivers/gpu/drm/emgd/emgd/include/tnc/regs.h | 849 ++ drivers/gpu/drm/emgd/emgd/include/tnc/sgx.h | 30 + drivers/gpu/drm/emgd/emgd/include/tnc/state3d.h | 37 + .../gpu/drm/emgd/emgd/include/tnc/state3d_plb.h | 32 + drivers/gpu/drm/emgd/emgd/include/topaz.h | 203 + drivers/gpu/drm/emgd/emgd/include/utils.h | 168 + drivers/gpu/drm/emgd/emgd/include/vga.h | 101 + drivers/gpu/drm/emgd/emgd/oal/os/debug.h | 33 + drivers/gpu/drm/emgd/emgd/oal/os/gart.h | 70 + drivers/gpu/drm/emgd/emgd/oal/os/io.h | 154 + drivers/gpu/drm/emgd/emgd/oal/os/list.h | 68 + drivers/gpu/drm/emgd/emgd/oal/os/math_fix.h | 29 + drivers/gpu/drm/emgd/emgd/oal/os/memmap.h | 45 + drivers/gpu/drm/emgd/emgd/oal/os/memory.h | 135 + drivers/gpu/drm/emgd/emgd/oal/os/pci.h | 40 + drivers/gpu/drm/emgd/emgd/oal/os/sched.h | 76 + drivers/gpu/drm/emgd/emgd/oal/src/math_fix.c | 132 + drivers/gpu/drm/emgd/emgd/oal/src/memmap.c | 49 + drivers/gpu/drm/emgd/emgd/oal/src/pci.c | 271 + drivers/gpu/drm/emgd/emgd/pal/Makefile.include | 49 + drivers/gpu/drm/emgd/emgd/pal/lpd/lpd.c | 108 + drivers/gpu/drm/emgd/emgd/pal/lpd/pd_print.h | 65 + drivers/gpu/drm/emgd/emgd/pal/lvds/lvds.c | 1548 ++++ drivers/gpu/drm/emgd/emgd/pal/lvds/lvds.def | 28 + drivers/gpu/drm/emgd/emgd/pal/lvds/lvds.h | 164 + drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo.def | 5 + drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo_attr.c | 1457 ++++ drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo_attr.h | 135 + drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo_hdmi.c | 518 ++ drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo_hdmi.h | 176 + drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo_intf.c | 695 ++ drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo_intf.h | 480 ++ drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo_port.c | 3522 +++++++++ drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo_port.h | 61 + .../state/appcontext/cmn/appcontext_dispatch.h | 50 + .../emgd/state/appcontext/cmn/igd_appcontext.c | 148 + .../emgd/state/appcontext/plb/appcontext_plb.c | 208 + .../gpu/drm/emgd/emgd/state/power/cmn/igd_pwr.c | 289 + .../drm/emgd/emgd/state/power/cmn/pwr_dispatch.h | 51 + .../gpu/drm/emgd/emgd/state/power/plb/pwr_plb.c | 123 + drivers/gpu/drm/emgd/emgd/state/reg/cmn/reg.c | 345 + .../gpu/drm/emgd/emgd/state/reg/cmn/reg_dispatch.h | 64 + drivers/gpu/drm/emgd/emgd/state/reg/plb/reg_plb.c | 1117 +++ drivers/gpu/drm/emgd/emgd/state/reg/tnc/reg_tnc.c | 1191 +++ drivers/gpu/drm/emgd/emgd/video/msvdx/msvdx.c | 838 ++ drivers/gpu/drm/emgd/emgd/video/msvdx/msvdx_init.c | 712 ++ drivers/gpu/drm/emgd/emgd/video/msvdx/msvdx_pvr.c | 309 + drivers/gpu/drm/emgd/emgd/video/msvdx/msvdx_pvr.h | 53 + .../gpu/drm/emgd/emgd/video/msvdx/thread0_bin.c | 3883 +++++++++ .../gpu/drm/emgd/emgd/video/overlay/cmn/igd_ovl.c | 890 +++ .../drm/emgd/emgd/video/overlay/cmn/micro_ovl.c | 159 + .../drm/emgd/emgd/video/overlay/cmn/ovl_coeff.c | 1121 +++ .../drm/emgd/emgd/video/overlay/cmn/ovl_coeff.h | 39 + .../drm/emgd/emgd/video/overlay/cmn/ovl_dispatch.h | 51 + .../gpu/drm/emgd/emgd/video/overlay/cmn/ovl_virt.h | 83 + .../emgd/emgd/video/overlay/plb/micro_ovl_plb.c | 799 ++ .../gpu/drm/emgd/emgd/video/overlay/plb/ovl2_plb.c | 574 ++ .../gpu/drm/emgd/emgd/video/overlay/plb/ovl2_plb.h | 49 + .../emgd/emgd/video/overlay/plb/ovl2_regs_plb.h | 69 + .../gpu/drm/emgd/emgd/video/overlay/plb/ovl_plb.c | 2253 ++++++ .../drm/emgd/emgd/video/overlay/plb/ovl_regs_plb.h | 179 + .../emgd/emgd/video/overlay/tnc/micro_ovl_tnc.c | 852 ++ .../emgd/emgd/video/overlay/tnc/ovl2_regs_tnc.h | 69 + .../gpu/drm/emgd/emgd/video/overlay/tnc/ovl2_tnc.c | 552 ++ .../gpu/drm/emgd/emgd/video/overlay/tnc/ovl2_tnc.h | 49 + .../drm/emgd/emgd/video/overlay/tnc/ovl_regs_tnc.h | 184 + .../gpu/drm/emgd/emgd/video/overlay/tnc/ovl_tnc.c | 1966 +++++ .../emgd/emgd/video/topaz/H263FirmwareCBR_bin.c | 8235 ++++++++++++++++++++ .../emgd/emgd/video/topaz/H263FirmwareCBR_bin.h | 42 + .../emgd/emgd/video/topaz/H263FirmwareVBR_bin.c | 8222 +++++++++++++++++++ .../emgd/emgd/video/topaz/H263FirmwareVBR_bin.h | 40 + .../drm/emgd/emgd/video/topaz/H263Firmware_bin.c | 8222 +++++++++++++++++++ .../drm/emgd/emgd/video/topaz/H263Firmware_bin.h | 41 + .../emgd/emgd/video/topaz/H264FirmwareCBR_bin.c | 8232 +++++++++++++++++++ .../emgd/emgd/video/topaz/H264FirmwareCBR_bin.h | 41 + .../emgd/emgd/video/topaz/H264FirmwareVBR_bin.c | 8230 +++++++++++++++++++ .../emgd/emgd/video/topaz/H264FirmwareVBR_bin.h | 41 + .../drm/emgd/emgd/video/topaz/H264Firmware_bin.c | 8226 +++++++++++++++++++ .../drm/emgd/emgd/video/topaz/H264Firmware_bin.h | 40 + .../emgd/emgd/video/topaz/MPG4FirmwareCBR_bin.c | 8223 +++++++++++++++++++ .../emgd/emgd/video/topaz/MPG4FirmwareCBR_bin.h | 41 + .../emgd/emgd/video/topaz/MPG4FirmwareVBR_bin.c | 8227 +++++++++++++++++++ .../emgd/emgd/video/topaz/MPG4FirmwareVBR_bin.h | 41 + .../drm/emgd/emgd/video/topaz/MPG4Firmware_bin.c | 8227 +++++++++++++++++++ .../drm/emgd/emgd/video/topaz/MPG4Firmware_bin.h | 42 + drivers/gpu/drm/emgd/emgd/video/topaz/topaz.c | 304 + drivers/gpu/drm/emgd/emgd/video/topaz/topaz_hdr.h | 118 + drivers/gpu/drm/emgd/emgd/video/topaz/topaz_init.c | 986 +++ drivers/gpu/drm/emgd/include/emgd_drm.h | 723 ++ drivers/gpu/drm/emgd/include/emgd_shared.h | 62 + drivers/gpu/drm/emgd/include/igd.h | 1424 ++++ drivers/gpu/drm/emgd/include/igd_2d.h | 382 + drivers/gpu/drm/emgd/include/igd_appcontext.h | 81 + drivers/gpu/drm/emgd/include/igd_blend.h | 82 + drivers/gpu/drm/emgd/include/igd_debug.h | 77 + drivers/gpu/drm/emgd/include/igd_errno.h | 55 + drivers/gpu/drm/emgd/include/igd_gart.h | 79 + drivers/gpu/drm/emgd/include/igd_gmm.h | 371 + drivers/gpu/drm/emgd/include/igd_init.h | 799 ++ drivers/gpu/drm/emgd/include/igd_interrupt.h | 302 + drivers/gpu/drm/emgd/include/igd_mode.h | 901 +++ drivers/gpu/drm/emgd/include/igd_ovl.h | 308 + drivers/gpu/drm/emgd/include/igd_pd.h | 504 ++ drivers/gpu/drm/emgd/include/igd_pi.h | 140 + drivers/gpu/drm/emgd/include/igd_pwr.h | 67 + drivers/gpu/drm/emgd/include/igd_rb.h | 101 + drivers/gpu/drm/emgd/include/igd_render.h | 510 ++ drivers/gpu/drm/emgd/include/igd_reset.h | 59 + drivers/gpu/drm/emgd/include/igd_version.h | 43 + drivers/gpu/drm/emgd/include/igd_vga.h | 67 + drivers/gpu/drm/emgd/include/oal/gart.h | 145 + drivers/gpu/drm/emgd/include/oal/io.h | 334 + drivers/gpu/drm/emgd/include/oal/list.h | 58 + drivers/gpu/drm/emgd/include/oal/math_fix.h | 62 + drivers/gpu/drm/emgd/include/oal/memmap.h | 98 + drivers/gpu/drm/emgd/include/oal/memory.h | 347 + drivers/gpu/drm/emgd/include/oal/pci.h | 260 + drivers/gpu/drm/emgd/pvr/include4/dbgdrvif.h | 267 + drivers/gpu/drm/emgd/pvr/include4/img_defs.h | 108 + drivers/gpu/drm/emgd/pvr/include4/img_types.h | 128 + drivers/gpu/drm/emgd/pvr/include4/ioctldef.h | 98 + drivers/gpu/drm/emgd/pvr/include4/pdumpdefs.h | 99 + drivers/gpu/drm/emgd/pvr/include4/pvr_debug.h | 127 + drivers/gpu/drm/emgd/pvr/include4/pvrmodule.h | 31 + drivers/gpu/drm/emgd/pvr/include4/pvrversion.h | 38 + drivers/gpu/drm/emgd/pvr/include4/regpaths.h | 43 + drivers/gpu/drm/emgd/pvr/include4/services.h | 860 ++ drivers/gpu/drm/emgd/pvr/include4/servicesext.h | 648 ++ drivers/gpu/drm/emgd/pvr/include4/sgx_options.h | 224 + drivers/gpu/drm/emgd/pvr/include4/sgxapi_km.h | 327 + drivers/gpu/drm/emgd/pvr/include4/sgxscript.h | 81 + .../services4/3rdparty/emgd_displayclass/emgd_dc.c | 2383 ++++++ .../services4/3rdparty/emgd_displayclass/emgd_dc.h | 297 + .../3rdparty/emgd_displayclass/emgd_dc_linux.c | 268 + .../services4/include/env/linux/pvr_drm_shared.h | 67 + .../drm/emgd/pvr/services4/include/kernelbuffer.h | 60 + .../drm/emgd/pvr/services4/include/kerneldisplay.h | 153 + .../drm/emgd/pvr/services4/include/pvr_bridge.h | 1382 ++++ .../drm/emgd/pvr/services4/include/pvr_bridge_km.h | 287 + .../gpu/drm/emgd/pvr/services4/include/pvrmmap.h | 36 + .../drm/emgd/pvr/services4/include/pvrsrv_errors.h | 193 + .../drm/emgd/pvr/services4/include/servicesint.h | 262 + .../drm/emgd/pvr/services4/include/sgx_bridge.h | 477 ++ .../drm/emgd/pvr/services4/include/sgx_mkif_km.h | 334 + .../gpu/drm/emgd/pvr/services4/include/sgxinfo.h | 288 + .../services4/srvkm/bridged/bridged_pvr_bridge.c | 3421 ++++++++ .../services4/srvkm/bridged/bridged_pvr_bridge.h | 231 + .../pvr/services4/srvkm/bridged/bridged_support.c | 85 + .../pvr/services4/srvkm/bridged/bridged_support.h | 43 + .../srvkm/bridged/sgx/bridged_sgx_bridge.c | 2514 ++++++ .../srvkm/bridged/sgx/bridged_sgx_bridge.h | 42 + .../pvr/services4/srvkm/common/buffer_manager.c | 2036 +++++ .../emgd/pvr/services4/srvkm/common/deviceclass.c | 1769 +++++ .../emgd/pvr/services4/srvkm/common/devicemem.c | 1410 ++++ .../drm/emgd/pvr/services4/srvkm/common/handle.c | 1549 ++++ .../gpu/drm/emgd/pvr/services4/srvkm/common/hash.c | 463 ++ .../drm/emgd/pvr/services4/srvkm/common/lists.c | 99 + .../gpu/drm/emgd/pvr/services4/srvkm/common/mem.c | 151 + .../emgd/pvr/services4/srvkm/common/mem_debug.c | 250 + .../drm/emgd/pvr/services4/srvkm/common/metrics.c | 160 + .../emgd/pvr/services4/srvkm/common/pdump_common.c | 1725 ++++ .../drm/emgd/pvr/services4/srvkm/common/perproc.c | 283 + .../drm/emgd/pvr/services4/srvkm/common/power.c | 747 ++ .../drm/emgd/pvr/services4/srvkm/common/pvrsrv.c | 1197 +++ .../drm/emgd/pvr/services4/srvkm/common/queue.c | 1139 +++ .../gpu/drm/emgd/pvr/services4/srvkm/common/ra.c | 1871 +++++ .../drm/emgd/pvr/services4/srvkm/common/resman.c | 717 ++ .../drm/emgd/pvr/services4/srvkm/devices/sgx/mmu.c | 2776 +++++++ .../drm/emgd/pvr/services4/srvkm/devices/sgx/mmu.h | 139 + .../drm/emgd/pvr/services4/srvkm/devices/sgx/pb.c | 458 ++ .../services4/srvkm/devices/sgx/sgx_bridge_km.h | 147 + .../pvr/services4/srvkm/devices/sgx/sgxconfig.h | 165 + .../pvr/services4/srvkm/devices/sgx/sgxinfokm.h | 352 + .../emgd/pvr/services4/srvkm/devices/sgx/sgxinit.c | 2255 ++++++ .../emgd/pvr/services4/srvkm/devices/sgx/sgxkick.c | 744 ++ .../pvr/services4/srvkm/devices/sgx/sgxpower.c | 469 ++ .../pvr/services4/srvkm/devices/sgx/sgxreset.c | 489 ++ .../pvr/services4/srvkm/devices/sgx/sgxtransfer.c | 549 ++ .../pvr/services4/srvkm/devices/sgx/sgxutils.c | 994 +++ .../pvr/services4/srvkm/devices/sgx/sgxutils.h | 99 + .../emgd/pvr/services4/srvkm/env/linux/env_data.h | 66 + .../pvr/services4/srvkm/env/linux/env_perproc.h | 52 + .../drm/emgd/pvr/services4/srvkm/env/linux/event.c | 273 + .../drm/emgd/pvr/services4/srvkm/env/linux/event.h | 32 + .../pvr/services4/srvkm/env/linux/kbuild/Makefile | 153 + .../emgd/pvr/services4/srvkm/env/linux/linkage.h | 59 + .../drm/emgd/pvr/services4/srvkm/env/linux/lock.h | 32 + .../drm/emgd/pvr/services4/srvkm/env/linux/mm.c | 2385 ++++++ .../drm/emgd/pvr/services4/srvkm/env/linux/mm.h | 331 + .../drm/emgd/pvr/services4/srvkm/env/linux/mmap.c | 1157 +++ .../drm/emgd/pvr/services4/srvkm/env/linux/mmap.h | 107 + .../emgd/pvr/services4/srvkm/env/linux/module.c | 735 ++ .../drm/emgd/pvr/services4/srvkm/env/linux/mutex.c | 136 + .../drm/emgd/pvr/services4/srvkm/env/linux/mutex.h | 70 + .../emgd/pvr/services4/srvkm/env/linux/mutils.c | 133 + .../emgd/pvr/services4/srvkm/env/linux/mutils.h | 101 + .../emgd/pvr/services4/srvkm/env/linux/osfunc.c | 2467 ++++++ .../emgd/pvr/services4/srvkm/env/linux/osperproc.c | 108 + .../drm/emgd/pvr/services4/srvkm/env/linux/pdump.c | 662 ++ .../pvr/services4/srvkm/env/linux/private_data.h | 55 + .../drm/emgd/pvr/services4/srvkm/env/linux/proc.c | 970 +++ .../drm/emgd/pvr/services4/srvkm/env/linux/proc.h | 115 + .../pvr/services4/srvkm/env/linux/pvr_bridge_k.c | 596 ++ .../emgd/pvr/services4/srvkm/env/linux/pvr_debug.c | 426 + .../emgd/pvr/services4/srvkm/env/linux/pvr_drm.c | 307 + .../emgd/pvr/services4/srvkm/env/linux/pvr_drm.h | 69 + .../emgd/pvr/services4/srvkm/hwdefs/sgx535defs.h | 637 ++ .../drm/emgd/pvr/services4/srvkm/hwdefs/sgxdefs.h | 82 + .../emgd/pvr/services4/srvkm/hwdefs/sgxerrata.h | 305 + .../pvr/services4/srvkm/hwdefs/sgxfeaturedefs.h | 164 + .../drm/emgd/pvr/services4/srvkm/hwdefs/sgxmmu.h | 79 + .../pvr/services4/srvkm/include/buffer_manager.h | 213 + .../drm/emgd/pvr/services4/srvkm/include/device.h | 278 + .../drm/emgd/pvr/services4/srvkm/include/handle.h | 382 + .../drm/emgd/pvr/services4/srvkm/include/hash.h | 73 + .../drm/emgd/pvr/services4/srvkm/include/lists.h | 176 + .../drm/emgd/pvr/services4/srvkm/include/metrics.h | 130 + .../drm/emgd/pvr/services4/srvkm/include/osfunc.h | 484 ++ .../emgd/pvr/services4/srvkm/include/osperproc.h | 76 + .../emgd/pvr/services4/srvkm/include/pdump_km.h | 452 ++ .../pvr/services4/srvkm/include/pdump_osfunc.h | 137 + .../drm/emgd/pvr/services4/srvkm/include/perproc.h | 110 + .../drm/emgd/pvr/services4/srvkm/include/power.h | 120 + .../drm/emgd/pvr/services4/srvkm/include/queue.h | 119 + .../gpu/drm/emgd/pvr/services4/srvkm/include/ra.h | 155 + .../drm/emgd/pvr/services4/srvkm/include/resman.h | 113 + .../pvr/services4/srvkm/include/services_headers.h | 49 + .../drm/emgd/pvr/services4/srvkm/include/srvkm.h | 69 + .../emgd/pvr/services4/system/common/sysconfig.c | 1607 ++++ .../emgd/pvr/services4/system/common/sysutils.c | 30 + .../emgd/pvr/services4/system/include/oemfuncs.h | 72 + .../services4/system/include/sys_pvr_drm_shared.h | 38 + .../emgd/pvr/services4/system/include/syscommon.h | 31 + .../emgd/pvr/services4/system/include/sysconfig.h | 328 + .../emgd/pvr/services4/system/include/sysinfo.h | 43 + .../emgd/pvr/services4/system/include/syslocal.h | 84 + .../drm/emgd/pvr/services4/system/plb/sysconfig.c | 50 + .../gpu/drm/emgd/pvr/services4/system/plb/sysplb.h | 37 + .../drm/emgd/pvr/services4/system/tnc/sysconfig.c | 50 + .../gpu/drm/emgd/pvr/services4/system/tnc/systnc.h | 40 + .../emgd/pvr/tools/intern/debug/client/linuxsrv.h | 48 + .../tools/intern/debug/dbgdriv/common/dbgdriv.c | 2076 +++++ .../tools/intern/debug/dbgdriv/common/dbgdriv.h | 116 + .../tools/intern/debug/dbgdriv/common/hostfunc.h | 58 + .../pvr/tools/intern/debug/dbgdriv/common/hotkey.c | 135 + .../pvr/tools/intern/debug/dbgdriv/common/hotkey.h | 60 + .../pvr/tools/intern/debug/dbgdriv/common/ioctl.c | 371 + .../pvr/tools/intern/debug/dbgdriv/common/ioctl.h | 87 + .../tools/intern/debug/dbgdriv/linux/hostfunc.c | 302 + .../intern/debug/dbgdriv/linux/kbuild/Makefile | 35 + .../pvr/tools/intern/debug/dbgdriv/linux/main.c | 298 + .../debug/dbgdriv/linux/makefile.linux.common | 40 + 344 files changed, 226668 insertions(+), 0 deletions(-) create mode 100644 drivers/gpu/drm/emgd/COPYING create mode 100644 drivers/gpu/drm/emgd/Makefile create mode 100644 drivers/gpu/drm/emgd/emgd/cfg/config.h create mode 100644 drivers/gpu/drm/emgd/emgd/cfg/config_default.h create mode 100644 drivers/gpu/drm/emgd/emgd/cfg/config_helper.c create mode 100644 drivers/gpu/drm/emgd/emgd/cfg/personality.h create mode 100644 drivers/gpu/drm/emgd/emgd/core/init/cmn/igd_global.c create mode 100644 drivers/gpu/drm/emgd/emgd/core/init/cmn/igd_init.c create mode 100644 drivers/gpu/drm/emgd/emgd/core/init/cmn/init_dispatch.h create mode 100644 drivers/gpu/drm/emgd/emgd/core/init/plb/init_plb.c create mode 100644 drivers/gpu/drm/emgd/emgd/core/init/plb/micro_init_plb.c create mode 100644 drivers/gpu/drm/emgd/emgd/core/init/tnc/init_tnc.c create mode 100644 drivers/gpu/drm/emgd/emgd/core/init/tnc/micro_init_tnc.c create mode 100755 drivers/gpu/drm/emgd/emgd/display/dsp/cmn/dsp.c create mode 100644 drivers/gpu/drm/emgd/emgd/display/dsp/cmn/dsp_dispatch.h create mode 100644 drivers/gpu/drm/emgd/emgd/display/dsp/plb/dsp_plb.c create mode 100644 drivers/gpu/drm/emgd/emgd/display/dsp/tnc/dsp_tnc.c create mode 100755 drivers/gpu/drm/emgd/emgd/display/mode/cmn/igd_mode.c create mode 100755 drivers/gpu/drm/emgd/emgd/display/mode/cmn/match.c create mode 100755 drivers/gpu/drm/emgd/emgd/display/mode/cmn/match.h create mode 100644 drivers/gpu/drm/emgd/emgd/display/mode/cmn/micro_mode.c create mode 100644 drivers/gpu/drm/emgd/emgd/display/mode/cmn/mode_dispatch.h create mode 100644 drivers/gpu/drm/emgd/emgd/display/mode/cmn/vga_mode.c create mode 100644 drivers/gpu/drm/emgd/emgd/display/mode/plb/clocks_plb.c create mode 100644 drivers/gpu/drm/emgd/emgd/display/mode/plb/micro_mode_plb.c create mode 100644 drivers/gpu/drm/emgd/emgd/display/mode/plb/mode_plb.c create mode 100644 drivers/gpu/drm/emgd/emgd/display/mode/tnc/clocks_tnc.c create mode 100644 drivers/gpu/drm/emgd/emgd/display/mode/tnc/micro_mode_tnc.c create mode 100644 drivers/gpu/drm/emgd/emgd/display/mode/tnc/mode_tnc.c create mode 100755 drivers/gpu/drm/emgd/emgd/display/pd/cmn/pd.c create mode 100644 drivers/gpu/drm/emgd/emgd/display/pi/cmn/displayid.c create mode 100644 drivers/gpu/drm/emgd/emgd/display/pi/cmn/edid.c create mode 100755 drivers/gpu/drm/emgd/emgd/display/pi/cmn/i2c_dispatch.h create mode 100644 drivers/gpu/drm/emgd/emgd/display/pi/cmn/igd_pi.c create mode 100644 drivers/gpu/drm/emgd/emgd/display/pi/cmn/mode_table.c create mode 100644 drivers/gpu/drm/emgd/emgd/display/pi/cmn/pd_init_all.c create mode 100755 drivers/gpu/drm/emgd/emgd/display/pi/cmn/pi.c create mode 100644 drivers/gpu/drm/emgd/emgd/display/pi/plb/i2c_plb.c create mode 100644 drivers/gpu/drm/emgd/emgd/display/pi/tnc/i2c_bitbash_tnc.c create mode 100644 drivers/gpu/drm/emgd/emgd/display/pi/tnc/i2c_gmbus_tnc.c create mode 100644 drivers/gpu/drm/emgd/emgd/drm/drm_emgd_private.h create mode 100644 drivers/gpu/drm/emgd/emgd/drm/emgd_drv.c create mode 100644 drivers/gpu/drm/emgd/emgd/drm/emgd_drv.h create mode 100644 drivers/gpu/drm/emgd/emgd/drm/emgd_fb.c create mode 100644 drivers/gpu/drm/emgd/emgd/drm/emgd_interface.c create mode 100644 drivers/gpu/drm/emgd/emgd/drm/emgd_mmap.c create mode 100644 drivers/gpu/drm/emgd/emgd/drm/emgd_test_pvrsrv.c create mode 100644 drivers/gpu/drm/emgd/emgd/drm/user_config.c create mode 100644 drivers/gpu/drm/emgd/emgd/drm/user_config.h create mode 100644 drivers/gpu/drm/emgd/emgd/gmm/gmm.c create mode 100644 drivers/gpu/drm/emgd/emgd/gmm/gtt.c create mode 100644 drivers/gpu/drm/emgd/emgd/include/cmd.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/context.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/debug.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/decode.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/dispatch.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/dispatch_utils.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/displayid.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/dsp.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/edid.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/general.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/instr_common.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/intelpci.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/memlist.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/mode.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/mode_access.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/module_init.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/msvdx.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/pd.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/pd_init.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/pi.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/plb/appcontext.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/plb/cmd.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/plb/context.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/plb/instr.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/plb/mi.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/plb/regs.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/plb/sgx.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/plb/state3d.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/plb/state3d_plb.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/psb_regs.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/rb.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/reset.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/sched.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/state2d.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/tnc/appcontext.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/tnc/cmd.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/tnc/context.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/tnc/instr.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/tnc/mi.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/tnc/regs.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/tnc/sgx.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/tnc/state3d.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/tnc/state3d_plb.h create mode 100755 drivers/gpu/drm/emgd/emgd/include/topaz.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/utils.h create mode 100644 drivers/gpu/drm/emgd/emgd/include/vga.h create mode 100644 drivers/gpu/drm/emgd/emgd/oal/os/debug.h create mode 100644 drivers/gpu/drm/emgd/emgd/oal/os/gart.h create mode 100644 drivers/gpu/drm/emgd/emgd/oal/os/io.h create mode 100644 drivers/gpu/drm/emgd/emgd/oal/os/list.h create mode 100644 drivers/gpu/drm/emgd/emgd/oal/os/math_fix.h create mode 100644 drivers/gpu/drm/emgd/emgd/oal/os/memmap.h create mode 100644 drivers/gpu/drm/emgd/emgd/oal/os/memory.h create mode 100644 drivers/gpu/drm/emgd/emgd/oal/os/pci.h create mode 100644 drivers/gpu/drm/emgd/emgd/oal/os/sched.h create mode 100644 drivers/gpu/drm/emgd/emgd/oal/src/math_fix.c create mode 100644 drivers/gpu/drm/emgd/emgd/oal/src/memmap.c create mode 100644 drivers/gpu/drm/emgd/emgd/oal/src/pci.c create mode 100644 drivers/gpu/drm/emgd/emgd/pal/Makefile.include create mode 100644 drivers/gpu/drm/emgd/emgd/pal/lpd/lpd.c create mode 100644 drivers/gpu/drm/emgd/emgd/pal/lpd/pd_print.h create mode 100644 drivers/gpu/drm/emgd/emgd/pal/lvds/lvds.c create mode 100644 drivers/gpu/drm/emgd/emgd/pal/lvds/lvds.def create mode 100644 drivers/gpu/drm/emgd/emgd/pal/lvds/lvds.h create mode 100644 drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo.def create mode 100644 drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo_attr.c create mode 100644 drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo_attr.h create mode 100644 drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo_hdmi.c create mode 100644 drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo_hdmi.h create mode 100644 drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo_intf.c create mode 100644 drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo_intf.h create mode 100644 drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo_port.c create mode 100644 drivers/gpu/drm/emgd/emgd/pal/sdvo/sdvo_port.h create mode 100644 drivers/gpu/drm/emgd/emgd/state/appcontext/cmn/appcontext_dispatch.h create mode 100755 drivers/gpu/drm/emgd/emgd/state/appcontext/cmn/igd_appcontext.c create mode 100644 drivers/gpu/drm/emgd/emgd/state/appcontext/plb/appcontext_plb.c create mode 100644 drivers/gpu/drm/emgd/emgd/state/power/cmn/igd_pwr.c create mode 100644 drivers/gpu/drm/emgd/emgd/state/power/cmn/pwr_dispatch.h create mode 100644 drivers/gpu/drm/emgd/emgd/state/power/plb/pwr_plb.c create mode 100644 drivers/gpu/drm/emgd/emgd/state/reg/cmn/reg.c create mode 100644 drivers/gpu/drm/emgd/emgd/state/reg/cmn/reg_dispatch.h create mode 100644 drivers/gpu/drm/emgd/emgd/state/reg/plb/reg_plb.c create mode 100644 drivers/gpu/drm/emgd/emgd/state/reg/tnc/reg_tnc.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/msvdx/msvdx.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/msvdx/msvdx_init.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/msvdx/msvdx_pvr.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/msvdx/msvdx_pvr.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/msvdx/thread0_bin.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/cmn/igd_ovl.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/cmn/micro_ovl.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/cmn/ovl_coeff.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/cmn/ovl_coeff.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/cmn/ovl_dispatch.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/cmn/ovl_virt.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/plb/micro_ovl_plb.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/plb/ovl2_plb.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/plb/ovl2_plb.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/plb/ovl2_regs_plb.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/plb/ovl_plb.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/plb/ovl_regs_plb.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/tnc/micro_ovl_tnc.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/tnc/ovl2_regs_tnc.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/tnc/ovl2_tnc.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/tnc/ovl2_tnc.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/tnc/ovl_regs_tnc.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/overlay/tnc/ovl_tnc.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/H263FirmwareCBR_bin.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/H263FirmwareCBR_bin.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/H263FirmwareVBR_bin.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/H263FirmwareVBR_bin.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/H263Firmware_bin.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/H263Firmware_bin.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/H264FirmwareCBR_bin.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/H264FirmwareCBR_bin.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/H264FirmwareVBR_bin.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/H264FirmwareVBR_bin.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/H264Firmware_bin.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/H264Firmware_bin.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/MPG4FirmwareCBR_bin.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/MPG4FirmwareCBR_bin.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/MPG4FirmwareVBR_bin.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/MPG4FirmwareVBR_bin.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/MPG4Firmware_bin.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/MPG4Firmware_bin.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/topaz.c create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/topaz_hdr.h create mode 100644 drivers/gpu/drm/emgd/emgd/video/topaz/topaz_init.c create mode 100644 drivers/gpu/drm/emgd/include/emgd_drm.h create mode 100644 drivers/gpu/drm/emgd/include/emgd_shared.h create mode 100644 drivers/gpu/drm/emgd/include/igd.h create mode 100644 drivers/gpu/drm/emgd/include/igd_2d.h create mode 100644 drivers/gpu/drm/emgd/include/igd_appcontext.h create mode 100644 drivers/gpu/drm/emgd/include/igd_blend.h create mode 100644 drivers/gpu/drm/emgd/include/igd_debug.h create mode 100644 drivers/gpu/drm/emgd/include/igd_errno.h create mode 100644 drivers/gpu/drm/emgd/include/igd_gart.h create mode 100644 drivers/gpu/drm/emgd/include/igd_gmm.h create mode 100644 drivers/gpu/drm/emgd/include/igd_init.h create mode 100644 drivers/gpu/drm/emgd/include/igd_interrupt.h create mode 100644 drivers/gpu/drm/emgd/include/igd_mode.h create mode 100644 drivers/gpu/drm/emgd/include/igd_ovl.h create mode 100644 drivers/gpu/drm/emgd/include/igd_pd.h create mode 100644 drivers/gpu/drm/emgd/include/igd_pi.h create mode 100644 drivers/gpu/drm/emgd/include/igd_pwr.h create mode 100644 drivers/gpu/drm/emgd/include/igd_rb.h create mode 100644 drivers/gpu/drm/emgd/include/igd_render.h create mode 100644 drivers/gpu/drm/emgd/include/igd_reset.h create mode 100644 drivers/gpu/drm/emgd/include/igd_version.h create mode 100644 drivers/gpu/drm/emgd/include/igd_vga.h create mode 100644 drivers/gpu/drm/emgd/include/oal/gart.h create mode 100644 drivers/gpu/drm/emgd/include/oal/io.h create mode 100644 drivers/gpu/drm/emgd/include/oal/list.h create mode 100644 drivers/gpu/drm/emgd/include/oal/math_fix.h create mode 100644 drivers/gpu/drm/emgd/include/oal/memmap.h create mode 100644 drivers/gpu/drm/emgd/include/oal/memory.h create mode 100644 drivers/gpu/drm/emgd/include/oal/pci.h create mode 100644 drivers/gpu/drm/emgd/pvr/include4/dbgdrvif.h create mode 100644 drivers/gpu/drm/emgd/pvr/include4/img_defs.h create mode 100644 drivers/gpu/drm/emgd/pvr/include4/img_types.h create mode 100644 drivers/gpu/drm/emgd/pvr/include4/ioctldef.h create mode 100644 drivers/gpu/drm/emgd/pvr/include4/pdumpdefs.h create mode 100644 drivers/gpu/drm/emgd/pvr/include4/pvr_debug.h create mode 100644 drivers/gpu/drm/emgd/pvr/include4/pvrmodule.h create mode 100644 drivers/gpu/drm/emgd/pvr/include4/pvrversion.h create mode 100644 drivers/gpu/drm/emgd/pvr/include4/regpaths.h create mode 100644 drivers/gpu/drm/emgd/pvr/include4/services.h create mode 100644 drivers/gpu/drm/emgd/pvr/include4/servicesext.h create mode 100644 drivers/gpu/drm/emgd/pvr/include4/sgx_options.h create mode 100644 drivers/gpu/drm/emgd/pvr/include4/sgxapi_km.h create mode 100644 drivers/gpu/drm/emgd/pvr/include4/sgxscript.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/3rdparty/emgd_displayclass/emgd_dc.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/3rdparty/emgd_displayclass/emgd_dc.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/3rdparty/emgd_displayclass/emgd_dc_linux.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/include/env/linux/pvr_drm_shared.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/include/kernelbuffer.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/include/kerneldisplay.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/include/pvr_bridge.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/include/pvr_bridge_km.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/include/pvrmmap.h create mode 100755 drivers/gpu/drm/emgd/pvr/services4/include/pvrsrv_errors.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/include/servicesint.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/include/sgx_bridge.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/include/sgx_mkif_km.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/include/sgxinfo.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/bridged/bridged_pvr_bridge.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/bridged/bridged_pvr_bridge.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/bridged/bridged_support.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/bridged/bridged_support.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/bridged/sgx/bridged_sgx_bridge.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/bridged/sgx/bridged_sgx_bridge.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/common/buffer_manager.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/common/deviceclass.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/common/devicemem.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/common/handle.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/common/hash.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/common/lists.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/common/mem.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/common/mem_debug.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/common/metrics.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/common/pdump_common.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/common/perproc.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/common/power.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/common/pvrsrv.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/common/queue.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/common/ra.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/common/resman.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/devices/sgx/mmu.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/devices/sgx/mmu.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/devices/sgx/pb.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/devices/sgx/sgx_bridge_km.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/devices/sgx/sgxconfig.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/devices/sgx/sgxinfokm.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/devices/sgx/sgxinit.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/devices/sgx/sgxkick.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/devices/sgx/sgxpower.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/devices/sgx/sgxreset.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/devices/sgx/sgxtransfer.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/devices/sgx/sgxutils.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/devices/sgx/sgxutils.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/env_data.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/env_perproc.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/event.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/event.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/kbuild/Makefile create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/linkage.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/lock.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/mm.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/mm.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/mmap.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/mmap.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/module.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/mutex.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/mutex.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/mutils.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/mutils.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/osfunc.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/osperproc.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/pdump.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/private_data.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/proc.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/proc.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/pvr_bridge_k.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/pvr_debug.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/pvr_drm.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux/pvr_drm.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/hwdefs/sgx535defs.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/hwdefs/sgxdefs.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/hwdefs/sgxerrata.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/hwdefs/sgxfeaturedefs.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/hwdefs/sgxmmu.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/buffer_manager.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/device.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/handle.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/hash.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/lists.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/metrics.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/osfunc.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/osperproc.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/pdump_km.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/pdump_osfunc.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/perproc.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/power.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/queue.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/ra.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/resman.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/services_headers.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/srvkm/include/srvkm.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/system/common/sysconfig.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/system/common/sysutils.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/system/include/oemfuncs.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/system/include/sys_pvr_drm_shared.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/system/include/syscommon.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/system/include/sysconfig.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/system/include/sysinfo.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/system/include/syslocal.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/system/plb/sysconfig.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/system/plb/sysplb.h create mode 100644 drivers/gpu/drm/emgd/pvr/services4/system/tnc/sysconfig.c create mode 100644 drivers/gpu/drm/emgd/pvr/services4/system/tnc/systnc.h create mode 100644 drivers/gpu/drm/emgd/pvr/tools/intern/debug/client/linuxsrv.h create mode 100644 drivers/gpu/drm/emgd/pvr/tools/intern/debug/dbgdriv/common/dbgdriv.c create mode 100644 drivers/gpu/drm/emgd/pvr/tools/intern/debug/dbgdriv/common/dbgdriv.h create mode 100644 drivers/gpu/drm/emgd/pvr/tools/intern/debug/dbgdriv/common/hostfunc.h create mode 100644 drivers/gpu/drm/emgd/pvr/tools/intern/debug/dbgdriv/common/hotkey.c create mode 100644 drivers/gpu/drm/emgd/pvr/tools/intern/debug/dbgdriv/common/hotkey.h create mode 100644 drivers/gpu/drm/emgd/pvr/tools/intern/debug/dbgdriv/common/ioctl.c create mode 100644 drivers/gpu/drm/emgd/pvr/tools/intern/debug/dbgdriv/common/ioctl.h create mode 100644 drivers/gpu/drm/emgd/pvr/tools/intern/debug/dbgdriv/linux/hostfunc.c create mode 100644 drivers/gpu/drm/emgd/pvr/tools/intern/debug/dbgdriv/linux/kbuild/Makefile create mode 100644 drivers/gpu/drm/emgd/pvr/tools/intern/debug/dbgdriv/linux/main.c create mode 100644 drivers/gpu/drm/emgd/pvr/tools/intern/debug/dbgdriv/linux/makefile.linux.common diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 8242c7f..4e27563 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -159,3 +159,11 @@ config DRM_SAVAGE chipset. If M is selected the module will be called savage. source drivers/gpu/drm/mrst/Kconfig + +config DRM_EGD + tristate "Intel IVI EMGD Kernel Module Driver" + depends on DRM &&PCI + default y + help + Choose this option if you have a Tunnel Creak platform. + If M is selected the module will be called emgd. diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index ca0eea7..3f8ac36 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -34,4 +34,5 @@ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/ obj-$(CONFIG_DRM_VIA) +=via/ obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/ obj-$(CONFIG_DRM_MRST) +=mrst/ +obj-$(CONFIG_DRM_EGD) += emgd/ obj-y += i2c/ diff --git a/drivers/gpu/drm/emgd/COPYING b/drivers/gpu/drm/emgd/COPYING new file mode 100644 index 0000000..84ac8ec --- /dev/null +++ b/drivers/gpu/drm/emgd/COPYING @@ -0,0 +1,351 @@ + +This software is Copyright (C) 2008 Imagination Technologies Ltd. + All rights reserved. + +You may use, distribute and copy this software under the terms of +GNU General Public License version 2, which is displayed below. + +------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +------------------------------------------------------------------------- + diff --git a/drivers/gpu/drm/emgd/Makefile b/drivers/gpu/drm/emgd/Makefile new file mode 100644 index 0000000..d146beb --- /dev/null +++ b/drivers/gpu/drm/emgd/Makefile @@ -0,0 +1,232 @@ +#---------------------------------------------------------------------------- +# Filename: Makefile.gnu +# $Revision: 1.37 $ +#---------------------------------------------------------------------------- +# Copyright © 2002-2010, Intel Corporation. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +#---------------------------------------------------------------------------- + +# Get the include paths pointed to the right place. +#export EMGD_MOD_DIR ?= $(CURDIR) +#export EMGD_MOD_DIR ?= drivers/gpu.drm/emgd +#ccflags-y := -I/include/drm + +ccflags-y := -Idrivers/gpu/drm/emgd/include \ + -Idrivers/gpu/drm/emgd/include/oal \ + -Idrivers/gpu/drm/emgd/emgd/display/mode/cmn \ + -Idrivers/gpu/drm/emgd/emgd/video/overlay/cmn \ + -Idrivers/gpu/drm/emgd/emgd/video/msvdx \ + -Idrivers/gpu/drm/emgd/emgd/oal \ + -Idrivers/gpu/drm/emgd/emgd/include \ + -Idrivers/gpu/drm/emgd/emgd/cfg \ + -Idrivers/gpu/drm/emgd/emgd/pal/lpd \ + -Idrivers/gpu/drm/emgd/emgd/drm \ + -Iinclude/drm \ + -Idrivers/gpu/drm/emgd/pvr/include4 \ + -Idrivers/gpu/drm/emgd/pvr/services4/include \ + -Idrivers/gpu/drm/emgd/pvr/services4/include/env/linux \ + -Idrivers/gpu/drm/emgd/pvr/services4/srvkm/env/linux \ + -Idrivers/gpu/drm/emgd/pvr/services4/srvkm/include \ + -Idrivers/gpu/drm/emgd/pvr/services4/srvkm/bridged \ + -Idrivers/gpu/drm/emgd/pvr/services4/system/plb \ + -Idrivers/gpu/drm/emgd/pvr/services4/system/tnc \ + -Idrivers/gpu/drm/emgd/pvr/services4/system/include \ + -Idrivers/gpu/drm/emgd/pvr/services4/srvkm/hwdefs \ + -Idrivers/gpu/drm/emgd/pvr/services4/srvkm/bridged/sgx \ + -Idrivers/gpu/drm/emgd/pvr/services4/srvkm/devices/sgx \ + -DSUPPORT_DRI_DRM_EXT \ + -DLINUX \ + -DPVR_BUILD_DIR="\"emgd\"" \ + -DPVR_BUILD_DATE="20100408" \ + -DPVR_BUILD_TYPE="\"$(CONFIG_PVR_RELEASE)\"" \ + -DPVR_SECURE_HANDLES \ + -DPVR_PROC_USE_SEQ_FILE \ + -DSUPPORT_DRI_DRM \ + -DSGX535 \ + -DSGX_CORE_REV=121 \ + -UDEBUG_LOG_PATH_TRUNCATE \ + -DDISPLAY_CONTROLLER=emgd_dc \ + -D_XOPEN_SOURCE=600 \ + -DSERVICES4 \ + -DPVR2D_VALIDATE_INPUT_PARAMS \ + -DSUPPORT_SRVINIT \ + -DSUPPORT_SGX \ + -DSUPPORT_PERCONTEXT_PB \ + -DSUPPORT_LINUX_X86_WRITECOMBINE \ + -DTRANSFER_QUEUE \ + -DSYS_USING_INTERRUPTS \ + -DSUPPORT_HW_RECOVERY \ + -DSUPPORT_ACTIVE_POWER_MANAGEMENT \ + -DPVR_SECURE_HANDLES \ + -DUSE_PTHREADS \ + -DSUPPORT_SGX_EVENT_OBJECT \ + -DSUPPORT_SGX_HWPERF \ + -DSUPPORT_SGX_LOW_LATENCY_SCHEDULING \ + -DSUPPORT_LINUX_X86_PAT \ + -DSUPPORT_SGX535 \ + -DSUPPORT_CACHE_LINE_FLUSH \ + -DSUPPORT_CPU_CACHED_BUFFERS \ + -DDEBUG_MESA_OGL_TRACE \ + +# -Werror \ + -DSUPPORT_CACHEFLUSH_ON_ALLOC \ + -DSUPPORT_MEMINFO_IDS \ + +EMGD_OBJS := emgd/drm/emgd_fb.o \ + emgd/drm/emgd_mmap.o \ + emgd/drm/emgd_drv.o \ + emgd/drm/emgd_interface.o \ + emgd/drm/emgd_test_pvrsrv.o \ + emgd/drm/user_config.o \ + emgd/display/pd/cmn/pd.o \ + emgd/display/pi/cmn/igd_pi.o \ + emgd/display/pi/cmn/displayid.o \ + emgd/display/pi/cmn/pd_init_all.o \ + emgd/display/pi/cmn/edid.o \ + emgd/display/pi/cmn/pi.o \ + emgd/display/pi/cmn/mode_table.o \ + emgd/display/pi/tnc/i2c_gmbus_tnc.o \ + emgd/display/pi/tnc/i2c_bitbash_tnc.o \ + emgd/display/pi/plb/i2c_plb.o \ + emgd/display/mode/cmn/match.o \ + emgd/display/mode/cmn/micro_mode.o \ + emgd/display/mode/cmn/vga_mode.o \ + emgd/display/mode/cmn/igd_mode.o \ + emgd/display/mode/tnc/micro_mode_tnc.o \ + emgd/display/mode/tnc/mode_tnc.o \ + emgd/display/mode/tnc/clocks_tnc.o \ + emgd/display/mode/plb/micro_mode_plb.o \ + emgd/display/mode/plb/clocks_plb.o \ + emgd/display/mode/plb/mode_plb.o \ + emgd/display/dsp/cmn/dsp.o \ + emgd/display/dsp/tnc/dsp_tnc.o \ + emgd/display/dsp/plb/dsp_plb.o \ + emgd/core/init/cmn/igd_global.o \ + emgd/core/init/cmn/igd_init.o \ + emgd/core/init/tnc/micro_init_tnc.o \ + emgd/core/init/tnc/init_tnc.o \ + emgd/core/init/plb/init_plb.o \ + emgd/core/init/plb/micro_init_plb.o \ + emgd/state/power/cmn/igd_pwr.o \ + emgd/state/power/plb/pwr_plb.o \ + emgd/state/appcontext/cmn/igd_appcontext.o \ + emgd/state/appcontext/plb/appcontext_plb.o \ + emgd/state/reg/cmn/reg.o \ + emgd/state/reg/tnc/reg_tnc.o \ + emgd/state/reg/plb/reg_plb.o \ + emgd/video/overlay/cmn/ovl_coeff.o \ + emgd/video/overlay/cmn/igd_ovl.o \ + emgd/video/overlay/cmn/micro_ovl.o \ + emgd/video/overlay/tnc/ovl_tnc.o \ + emgd/video/overlay/tnc/ovl2_tnc.o \ + emgd/video/overlay/tnc/micro_ovl_tnc.o \ + emgd/video/overlay/plb/ovl2_plb.o \ + emgd/video/overlay/plb/ovl_plb.o \ + emgd/video/overlay/plb/micro_ovl_plb.o \ + emgd/video/msvdx/msvdx_init.o \ + emgd/video/msvdx/msvdx.o \ + emgd/video/msvdx/msvdx_pvr.o \ + emgd/video/topaz/topaz_init.o \ + emgd/video/topaz/topaz.o \ + emgd/video/topaz/H263Firmware_bin.o \ + emgd/video/topaz/H263FirmwareCBR_bin.o \ + emgd/video/topaz/H263FirmwareVBR_bin.o \ + emgd/video/topaz/H264Firmware_bin.o \ + emgd/video/topaz/H264FirmwareCBR_bin.o \ + emgd/video/topaz/H264FirmwareVBR_bin.o \ + emgd/video/topaz/MPG4Firmware_bin.o \ + emgd/video/topaz/MPG4FirmwareCBR_bin.o \ + emgd/video/topaz/MPG4FirmwareVBR_bin.o \ + emgd/pal/sdvo/sdvo_attr.o \ + emgd/pal/sdvo/sdvo_hdmi.o \ + emgd/pal/sdvo/sdvo_port.o \ + emgd/pal/sdvo/sdvo_intf.o \ + emgd/pal/lvds/lvds.o \ + emgd/pal/lpd/lpd.o \ + emgd/gmm/gmm.o \ + emgd/gmm/gtt.o \ + emgd/oal/src/pci.o \ + emgd/oal/src/memmap.o \ + emgd/oal/src/math_fix.o \ + +ENVDIR = pvr/services4/srvkm/env/linux +COMMONDIR = pvr/services4/srvkm/common +BRIDGEDDIR = pvr/services4/srvkm/bridged +SYSCONFIGDIR = pvr/services4/system/common +SGXDIR = pvr/services4/srvkm/devices/sgx +DISPCLASSDIR = pvr/services4/3rdparty/emgd_displayclass + +ENV_OBJS = $(ENVDIR)/osfunc.o \ + $(ENVDIR)/mutils.o \ + $(ENVDIR)/mmap.o \ + $(ENVDIR)/module.o \ + $(ENVDIR)/pdump.o \ + $(ENVDIR)/proc.o \ + $(ENVDIR)/pvr_bridge_k.o \ + $(ENVDIR)/pvr_debug.o \ + $(ENVDIR)/mm.o \ + $(ENVDIR)/mutex.o \ + $(ENVDIR)/event.o \ + $(ENVDIR)/osperproc.o \ + $(ENVDIR)/pvr_drm.o + +COMMON_OBJS = $(COMMONDIR)/buffer_manager.o \ + $(COMMONDIR)/devicemem.o \ + $(COMMONDIR)/deviceclass.o \ + $(COMMONDIR)/handle.o \ + $(COMMONDIR)/hash.o \ + $(COMMONDIR)/metrics.o \ + $(COMMONDIR)/pvrsrv.o \ + $(COMMONDIR)/queue.o \ + $(COMMONDIR)/ra.o \ + $(COMMONDIR)/resman.o \ + $(COMMONDIR)/power.o \ + $(COMMONDIR)/mem.o \ + $(COMMONDIR)/pdump_common.o \ + $(COMMONDIR)/perproc.o \ + $(COMMONDIR)/lists.o \ + $(COMMONDIR)/mem_debug.o + +BRIDGED_OBJS = $(BRIDGEDDIR)/bridged_support.o \ + $(BRIDGEDDIR)/bridged_pvr_bridge.o \ + $(BRIDGEDDIR)/sgx/bridged_sgx_bridge.o + +SYSCONFIG_OBJS = $(SYSCONFIGDIR)/sysconfig.o \ + pvr/services4/system/tnc/sysconfig.o \ + pvr/services4/system/plb/sysconfig.o \ + $(SYSCONFIGDIR)/sysutils.o + +SGX_OBJS = $(SGXDIR)/sgxinit.o \ + $(SGXDIR)/sgxpower.o \ + $(SGXDIR)/sgxreset.o \ + $(SGXDIR)/sgxutils.o \ + $(SGXDIR)/sgxkick.o \ + $(SGXDIR)/sgxtransfer.o \ + $(SGXDIR)/mmu.o \ + $(SGXDIR)/pb.o + +DC_OBJS = $(DISPCLASSDIR)/emgd_dc.o \ + $(DISPCLASSDIR)/emgd_dc_linux.o + + +emgd-y := $(DC_OBJS) \ + $(EMGD_OBJS) \ + $(ENV_OBJS) \ + $(COMMON_OBJS) \ + $(BRIDGED_OBJS) \ + $(SYSCONFIG_OBJS) \ + $(SGX_OBJS) \ + +obj-$(CONFIG_DRM_EGD) += emgd.o diff --git a/drivers/gpu/drm/emgd/emgd/cfg/config.h b/drivers/gpu/drm/emgd/emgd/cfg/config.h new file mode 100644 index 0000000..2223cd7 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/cfg/config.h @@ -0,0 +1,125 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: config.h + * $Revision: 1.6 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * This file contains the compile options for the IGD compile. It is included + * by all IGD OAL and RAL modules. Do not remove valid options from this + * file, simply comment them out. + * Eventually a config tool will auto generate this file based on selected + * options. + *----------------------------------------------------------------------------- + */ + +#ifndef _HAL_CONFIG_H +#define _HAL_CONFIG_H + +/* + * * Select ONE of these to be defined. It controls which OAL port + * * is used during the build and where the output goes. + * */ +/* #define CONFIG_OAL linux */ +#define CONFIG_OAL linux-user +/* #define CONFIG_OAL xfree86 */ +/* #define CONFIG_OAL windows */ +/* #define CONFIG_OAL null */ + +/* #define CONFIG_OAL_WINDOWS_MINIPORT */ + + +//#define CONFIG_NEW_MATCH 1 + +/* + * Which Cores are supported + * + * Use Defaults + */ + +/* + * These print options are the default when a "make" is done. + * They are overridden when "make debug" or "make dist" is done. + */ +/* #define CONFIG_DEBUG */ +/* #define CONFIG_DIST */ + +/* + * This macro configures the DRM/kernel's OS_DEBUG() and OS_DEBUG_S() macros to + * use the KERN_INFO message priority, instead of the normal KERN_DEBUG message + * priority. This is useful for bugs (e.g. crashes) where dmesg can't be used + * to obtain debug messages. + */ +/* #define CONFIG_USE_INFO_PRIORITY */ + + +/* + * Which of the optional modules are included in the build + * for the most part this is for modules that need an init + * or power entry point. + * + * Use Defaults. + */ + +/* + * Default FB/Display Resolution + */ +#define CONFIG_DEFAULT_WIDTH 640 +#define CONFIG_DEFAULT_HEIGHT 480 +#define CONFIG_DEFAULT_PF IGD_PF_ARGB32 + + +/* + power modes supported + 0 -don't support + 1 - support + + Use Defaults. +*/ + +/* + * Turn off fences for performance analysis. 3d makes use of "Use Fences" + * So this will make fences regions become linear but everything should + * still work. + * + * #define CONFIG_NOFENCES + */ + +/* Don't enable Dynamic port driver loading for simple driver. For simple, + * one can limit the port drivers by enabling CONFIG_LIMIT_PDS to + * required port drivers * + * + * Enable Dynamic port driver loading + * + * #define IGD_DPD_ENABLED 1 */ + +/* Enable required port drivers. */ +#define CONFIG_LIMIT_PDS 1 +#define CONFIG_PD_ANALOG 0 +#define CONFIG_PD_LVDS 1 +#define CONFIG_PD_SDVO 1 +#define CONFIG_PD_TV 0 /* Integrated TV for NAPA */ + +#define CONFIG_LINK_PD_LVDS +#define CONFIG_LINK_PD_SDVO + +#define CONFIG_DECODE + +#include + +#endif + diff --git a/drivers/gpu/drm/emgd/emgd/cfg/config_default.h b/drivers/gpu/drm/emgd/emgd/cfg/config_default.h new file mode 100644 index 0000000..c55f707 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/cfg/config_default.h @@ -0,0 +1,191 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: config_default.h + * $Revision: 1.6 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * This file is used in conjunction with the platform's config.h to + * gererate a full set of build defines. This file should provide defaults + * for defines such that a platform's config.h can include only the + * minimal set of non-standard options. + * Defines should be named such that: + * CONFIG_: Is defined or undefined suitable for use with ifdef and + * can be used with the build system's DIRS_FOO or OBJECTS_FOO. Any + * CONFIG_FOO added here must also have an entry in config_helper.c. + * CONFIG_ENABLE_FOO: Should be defined always and defined to a 1 or 0. + * This is suitble for use in if(CONFIG_ENABLE_FOO) and expected that + * a compiler will optimize away if(0)'s. + * CONFIG_LIMIT_FOO: Should prevent some default set of FOO defines + * from being included. For instance CONFIG_LIMIT_MODES prevents the + * long default list of default modes from being used and instead the + * platform's config.h must define the requested modes manually. + *----------------------------------------------------------------------------- + */ + +#ifndef _HAL_CONFIG_DEFAULT_H +#define _HAL_CONFIG_DEFAULT_H + +#include + +#ifndef CONFIG_MICRO +#define CONFIG_FULL +#endif + +#ifndef CONFIG_LIMIT_CORES +#define CONFIG_PLB +#define CONFIG_TNC +#endif /* CONFIG_LIMIT_CORES */ + +#ifdef CONFIG_DEPRECATED +#if 0 /* WHT Modules need some updating */ +#define CONFIG_810 +#define CONFIG_810DC +#define CONFIG_810E +#define CONFIG_815 +#define CONFIG_830 +#define CONFIG_835 +#define CONFIG_845 +#define CONFIG_855 +#define CONFIG_865 +#define CONFIG_915GD +#define CONFIG_915AL +#define CONFIG_945G +#define CONFIG_945GM +#define CONFIG_945GME +#define CONFIG_Q35 +#define CONFIG_965G +#define CONFIG_965GM +#define CONFIG_CTG +#define CONFIG_Q45 +#define CONFIG_PNV +#endif +#endif + +#ifndef CONFIG_LIMIT_MODULES +#define CONFIG_INIT +#define CONFIG_REG +#define CONFIG_POWER +#define CONFIG_MODE +#define CONFIG_DSP +#define CONFIG_PI +#define CONFIG_PD +#define CONFIG_APPCONTEXT +#define CONFIG_OVERLAY +#endif /* CONFIG_LIMIT_MODULES */ + +#ifndef CONFIG_LIMIT_PDS +#define CONFIG_PD_ANALOG +#define CONFIG_PD_LVDS +#define CONFIG_PD_TV +#define CONFIG_PD_HDMI +#define CONFIG_PD_SDVO +#define CONFIG_PD_SOFTPD +#endif + +#ifdef CONFIG_DEPRECATED +#ifndef CONFIG_LIMIT_PDS +#define CONFIG_PD_SII164 +#define CONFIG_PD_CH7009 +#define CONFIG_PD_TL955 +#define CONFIG_PD_RGBA +#define CONFIG_PD_NS2501 +#define CONFIG_PD_TH164 +#define CONFIG_PD_FS454 +#define CONFIG_PD_NS387 +#define CONFIG_PD_CX873 +#define CONFIG_PD_FS460 +#define CONFIG_PD_CH7017 +#define CONFIG_PD_TI410 +#endif +#endif + +#ifndef CONFIG_DEBUG_FLAGS +#define CONFIG_DEBUG_FLAGS \ + 0, /* Command Module */ \ + 0, /* DSP Module */ \ + 0, /* Mode Module */ \ + 0, /* Init Module */ \ + 0, /* Overlay Module */ \ + 0, /* Power Module */ \ + 0, /* 2D Module */ \ + 0, /* Blend Module */ \ + 0, /* State Module */ \ + 0, /* GMM Module */ \ + 0, /* Gart Module */ \ + 0, /* OAL Module */ \ + 0, /* Interrupt Module */ \ + 0, /* Port Driver Module */ \ + 0, /* Video Decode Module */ \ + 0, /* PVR 3-Ptr Disp Drv */ \ +\ + 0, /* Global Tracing */ \ + 0, /* Global Instructions */ \ + 0, /* Global Debug */ \ +\ + 0, /* Verbose Blend Stats */ \ + 0, /* Verbose Overlay Dump */\ + 0, /* Verbose Cmd Dump */ \ + 0, /* Verbose GMM Dump */ \ + 0 /* Verbose Shader Dump */ + +#endif + +#ifndef CONFIG_DEBUG_IAL_FLAGS +#define CONFIG_DEBUG_IAL_FLAGS 0 +#endif + +/* we ensure IAL's that do not support hw binning has this flag as '0' */ +#ifndef CONFIG_ENABLE_BINNING +#define CONFIG_ENABLE_BINNING 0 +#endif + +#ifndef CONFIG_ENABLE_THREADS +#define CONFIG_ENABLE_THREADS 0 +#endif + + + +/* + * These Meta-Defines should not be set in the config.h. They are enabled + * here based on more granular defines that come from config.h. For instance + * CONFIG_NAP should be enabled when any chips from the NAP family are enabled. + */ +#if defined(CONFIG_810) || defined(CONFIG_810DC) || defined(CONFIG_810E) ||\ + defined(CONFIG_815) +#define CONFIG_WHT +#endif + +#if defined(CONFIG_830) || defined(CONFIG_835) || defined(CONFIG_845) ||\ + defined(CONFIG_855) || defined(CONFIG_865) +#define CONFIG_ALM +#endif + +#if defined(CONFIG_915GD) || defined(CONFIG_915AL) || defined(CONFIG_945G) ||\ + defined(CONFIG_945GM) || defined(CONFIG_945GME) || defined(CONFIG_Q35) ||\ + defined(CONFIG_PNV) +#define CONFIG_NAP +#endif + +#if defined(CONFIG_965G) || defined(CONFIG_965GM) || \ + defined(CONFIG_CTG) || defined(CONFIG_Q45) +#define CONFIG_GN4 +#endif + + +#endif /* _HAL_CONFIG_DEFAULT_H */ + diff --git a/drivers/gpu/drm/emgd/emgd/cfg/config_helper.c b/drivers/gpu/drm/emgd/emgd/cfg/config_helper.c new file mode 100644 index 0000000..0037507 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/cfg/config_helper.c @@ -0,0 +1,233 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: config_helper.c + * $Revision: 1.3 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * + *----------------------------------------------------------------------------- + */ + +#include + +#include + +int main(int argc, char **argv) +{ + char configs[] = "" +#ifdef CONFIG_MICRO + "MICRO " +#else + "FULL " +#endif +#ifdef CONFIG_WHT + "WHT " +#endif +#ifdef CONFIG_ALM + "ALM " +#endif +#ifdef CONFIG_NAP + "NAP " +#endif +#ifdef CONFIG_GN4 + "GN4 " +#endif +#ifdef CONFIG_PLB + "PLB " +#endif +#ifdef CONFIG_TNC + "TNC " +#endif +#ifdef CONFIG_MODE + "MODE " +#endif +#ifdef CONFIG_DSP + "DSP " +#endif +#ifdef CONFIG_PI + "PI " +#endif +#ifdef CONFIG_PD + "PD " +#endif +#ifdef CONFIG_INIT + "INIT " +#endif +#ifdef CONFIG_INTERRUPT + "INTERRUPT " +#endif +#ifdef CONFIG_GART + "GART " +#endif +#ifdef CONFIG_REG + "REG " +#endif +#ifdef CONFIG_RESET + "RESET " +#endif +#ifdef CONFIG_POWER + "POWER " +#endif +#ifdef CONFIG_GMM + "GMM " +#endif +#ifdef CONFIG_MICRO_GMM + "MICRO_GMM " +#endif +#ifdef CONFIG_APPCONTEXT + "APPCONTEXT " +#endif +#ifdef CONFIG_CMD + "CMD " +#endif +#ifdef CONFIG_2D + "2D " +#endif +#ifdef CONFIG_BLEND + "BLEND " +#endif +#ifdef CONFIG_OVERLAY + "OVERLAY " +#endif +#ifdef CONFIG_DECODE + "DECODE " +#endif + /* + * Port Driver Compile Options + */ +#ifdef CONFIG_PD_ANALOG + "PD_ANALOG " +#endif +#ifdef CONFIG_PD_SII164 + "PD_SII164 " +#endif +#ifdef CONFIG_PD_CH7009 + "PD_CH7009 " +#endif +#ifdef CONFIG_PD_TL955 + "PD_TL955 " +#endif +#ifdef CONFIG_PD_RGBA + "PD_RGBA " +#endif +#ifdef CONFIG_PD_NS2501 + "PD_NS2501 " +#endif +#ifdef CONFIG_PD_TH164 + "PD_TH164 " +#endif +#ifdef CONFIG_PD_FS454 + "PD_FS454 " +#endif +#ifdef CONFIG_PD_NS387 + "PD_NS387 " +#endif +#ifdef CONFIG_PD_CX873 + "PD_CX873 " +#endif +#ifdef CONFIG_PD_LVDS + "PD_LVDS " +#endif +#ifdef CONFIG_PD_FS460 + "PD_FS460 " +#endif +#ifdef CONFIG_PD_CH7017 + "PD_CH7017 " +#endif +#ifdef CONFIG_PD_TI410 + "PD_TI410 " +#endif +#ifdef CONFIG_PD_TV + "PD_TV " +#endif +#ifdef CONFIG_PD_HDMI + "PD_HDMI " +#endif +#ifdef CONFIG_PD_SDVO + "PD_SDVO " +#endif +#ifdef CONFIG_PD_SOFTPD + "PD_SOFTPD " +#endif + /* + * Port Driver Link Options + */ +#ifdef CONFIG_LINK_PD_ANALOG + "LINK_PD_ANALOG " +#endif +#ifdef CONFIG_LINK_PD_SII164 + "LINK_PD_SII164 " +#endif +#ifdef CONFIG_LINK_PD_CH7009 + "LINK_PD_CH7009 " +#endif +#ifdef CONFIG_LINK_PD_TL955 + "LINK_PD_TL955 " +#endif +#ifdef CONFIG_LINK_PD_RGBA + "LINK_PD_RGBA " +#endif +#ifdef CONFIG_LINK_PD_NS2501 + "LINK_PD_NS2501 " +#endif +#ifdef CONFIG_LINK_PD_TH164 + "LINK_PD_TH164 " +#endif +#ifdef CONFIG_LINK_PD_FS454 + "LINK_PD_FS454 " +#endif +#ifdef CONFIG_LINK_PD_NS387 + "LINK_PD_NS387 " +#endif +#ifdef CONFIG_LINK_PD_CX873 + "LINK_PD_CX873 " +#endif +#ifdef CONFIG_LINK_PD_LVDS + "LINK_PD_LVDS " +#endif +#ifdef CONFIG_LINK_PD_FS460 + "LINK_PD_FS460 " +#endif +#ifdef CONFIG_LINK_PD_CH7017 + "LINK_PD_CH7017 " +#endif +#ifdef CONFIG_LINK_PD_TI410 + "LINK_PD_TI410 " +#endif +#ifdef CONFIG_LINK_PD_TV + "LINK_PD_TV " +#endif +#ifdef CONFIG_LINK_PD_HDMI + "LINK_PD_HDMI " +#endif +#ifdef CONFIG_LINK_PD_SDVO + "LINK_PD_SDVO " +#endif +#ifdef CONFIG_LINK_PD_SOFTPD + "LINK_PD_SOFTPD " +#endif + + +#ifdef CONFIG_COPP + "COPP " +#endif + ; + printf("%s\n", configs); + return 0; +} + diff --git a/drivers/gpu/drm/emgd/emgd/cfg/personality.h b/drivers/gpu/drm/emgd/emgd/cfg/personality.h new file mode 100644 index 0000000..3600e36 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/cfg/personality.h @@ -0,0 +1,43 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: personality.h + * $Revision: 1.2 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * This file is used in conjunction with the default_config.h to + * gererate a full set of build defines. + *----------------------------------------------------------------------------- + */ + +#ifndef _PERSONALITY_H +#define _PERSONALITY_H +/* +TODO: After the 9.1.1 branch, re-enable this code and delete igd_version.h +#define IGD_MAJOR_NUM 9 +#define IGD_MINOR_NUM 1 +#define IGD_BUILD_NUM 1258 + +#define IGD_PCF_VERSION 0x00000400 +*/ + +/* Enable COPP */ +#define CONFIG_COPP + +#include + +#endif diff --git a/drivers/gpu/drm/emgd/emgd/core/init/cmn/igd_global.c b/drivers/gpu/drm/emgd/emgd/core/init/cmn/igd_global.c new file mode 100644 index 0000000..25bd2b3 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/core/init/cmn/igd_global.c @@ -0,0 +1,49 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: igd_global.c + * $Revision: 1.2 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * + *----------------------------------------------------------------------------- + */ +#include +#include + +/* + * This is the global debug flag for IGD. It needs to be available + * even when the init module is not in debug mode. Do not #ifdef it. + */ +igd_debug_t debug_flag = { + { + CONFIG_DEBUG_FLAGS + }, + { + CONFIG_DEBUG_IAL_FLAGS + } +}; + +igd_debug_t *igd_debug = &debug_flag; + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: igd_global.c,v 1.2 2010/04/27 20:33:49 bpaauwe Exp $ + * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/core/init/cmn/igd_global.c,v $ + *---------------------------------------------------------------------------- + */ + diff --git a/drivers/gpu/drm/emgd/emgd/core/init/cmn/igd_init.c b/drivers/gpu/drm/emgd/emgd/core/init/cmn/igd_init.c new file mode 100644 index 0000000..42c517b --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/core/init/cmn/igd_init.c @@ -0,0 +1,864 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: igd_init.c + * $Revision: 1.11 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * This file contains the implementation of the core init module. It + * is responsible from initializing the HAL and the device and gathering + * all necessary general device information. This module is partially + * optional such that portions may be disabled to save code space. + * When CONFIG_MICRO is enabled: + * Firmware parameters are NOT read. + * Only the first device instance is queried and configured. + * Revision ID is NOT queried, it is assumed to be 0. + * MMIO regions are not discovered or mapped. + * FB memory is not discovered or mapped. + * Shutdown is a no-op. + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.init + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "init_dispatch.h" + +/* OAL header */ +#include + +/*! + * @addtogroup core_group + * @{ + */ + +unsigned long _sgx_base, _msvdx_base, _topaz_base; + +/* Notes: If the bus is of value 0xFFFF, then the particular + * device is searched for in the whole PCI topology + */ +typedef struct _iegd_pci { + unsigned short vendor_id; + unsigned short device_id; + unsigned short bus; + unsigned short dev; + unsigned short func; +} iegd_pci_t; + +static iegd_pci_t intel_pci_device_table[] = { +#ifdef CONFIG_810 + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_810, 0, 2, 0}, +#endif +#ifdef CONFIG_810DC + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_810DC, 0, 2, 0}, +#endif +#ifdef CONFIG_810E + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_810E, 0, 2, 0}, +#endif +#ifdef CONFIG_815 + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_815, 0, 2, 0}, +#endif +#ifdef CONFIG_855 + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_855, 0, 2, 0}, +#endif +#ifdef CONFIG_830 + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_830M, 0, 2, 0}, +#endif +#ifdef CONFIG_835 + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_835, 0, 2, 0}, +#endif +#ifdef CONFIG_845 + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_845G, 0, 2, 0}, +#endif +#ifdef CONFIG_865 + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_865G, 0, 2, 0}, +#endif +#ifdef CONFIG_915GD + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_915GD, 0, 2, 0}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_910GL, 0, 2, 0}, +#endif +#ifdef CONFIG_915AL + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_915AL, 0, 2, 0}, +#endif +#ifdef CONFIG_945G + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_945G, 0, 2, 0}, +#endif +#ifdef CONFIG_945GM + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_945GM, 0, 2, 0}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_945GME, 0, 2, 0}, +#endif +#ifdef CONFIG_Q35 + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_Q35, 0, 2, 0}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_Q35A2, 0, 2, 0}, +#endif +#ifdef CONFIG_965G + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_965G, 0, 2, 0}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_G965, 0, 2, 0}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_Q965, 0, 2, 0}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_946GZ, 0, 2, 0}, +#endif +#ifdef CONFIG_965GM + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_GME965, 0, 2, 0}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_GM965, 0, 2, 0}, +#endif +#ifdef CONFIG_CTG + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_CTG, 0, 2, 0}, +#endif +#ifdef CONFIG_PLB + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_PLB, 0, 2, 0}, +#endif +#ifdef CONFIG_TNC + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_TNC, 0, 2, 0}, +#ifdef CONFIG_MSRT + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_TNC_A0, 0, 2, 0}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_LNC, 0, 2, 0}, +#endif +#endif +#ifdef CONFIG_Q45 + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_ELK, 0, 2, 0}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_Q45, 0, 2, 0}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_G45, 0, 2, 0}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VGA_G41, 0, 2, 0}, +#endif + +}; + + +/* + * On platforms with multiple PCI devices (currently only Tunnel Creek), we + * need to disable legacy VGA decoding on the second device, otherwise + * the VGA arbiter will prevent DRI from being used. Keep a list of + * devices we need to disable this on. + */ +static iegd_pci_t disabled_legacy_vga_list[] = { + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SDVO_TNC, 0, 0, 0}, +}; + +#define MAX_PCI_DEVICE_SUPPORTED \ + (sizeof(intel_pci_device_table)/sizeof(intel_pci_device_table[0])) +#define MAX_LEGACY_VGA_DISABLE \ + (sizeof(disabled_legacy_vga_list)/sizeof(disabled_legacy_vga_list[0])) + + +static dispatch_table_t init_dispatch_table[] = { + + DISPATCH_PLB(&init_dispatch_plb) + DISPATCH_TNC(&init_dispatch_tnc) +#ifdef CONFIG_MSRT + DISPATCH_TNC_A0(&init_dispatch_tnc_a0) + DISPATCH_LNC(&init_dispatch_lnc) +#endif + DISPATCH_END +}; + + + +static init_dispatch_t *init_dispatch; + + +/*--------------------------------------------------------------------------- + * Optional Init Module Components + *--------------------------------------------------------------------------*/ +#ifndef CONFIG_MICRO + +/*! + * This function allows for calling the igd_get_param function with a + * display handle instead of a driver handle. This version is exported in + * the dispatch table. + * + * @param display_handle + * @param id + * @param value + * + * @return igd_get_param() + */ +static int _igd_get_param(igd_display_h display_handle, + unsigned long id, + unsigned long *value) +{ + igd_display_context_t *display = (igd_display_context_t *)display_handle; + return igd_get_param((igd_driver_h)display->context, id, value); +} + +/*! + * This function allows for calling the igd_set_param function with a + * display handle instead of a driver handle. This version is exported in + * the dispatch table. + * + * @param display_handle + * @param id + * @param value + * + * @return igd_set_param() + */ +static int _igd_set_param(igd_display_h display_handle, + unsigned long id, + unsigned long value) +{ + igd_display_context_t *display = (igd_display_context_t *)display_handle; + return igd_set_param((igd_driver_h)display->context, id, value); +} + +/*! + * This function should never be called directly. It comprises the optional + * portion of the igd_set_param function which should be used instead. + * + * @param context + * @param id + * @param value + * + * @return set_param() + * @return 0 + */ +static int _init_set_param(igd_context_t *context, + unsigned long id, + unsigned long value) +{ + + switch(id) { + case IGD_PARAM_DEBUG_MASK: + *((unsigned long *)igd_debug) = value; + break; + default: + return init_dispatch->set_param(context, id, value); + } + + return 0; +} + +/*! + * This function should never be called directly. It comprises the optional + * portion of the igd_get_param function which should be used instead. + * + * @param display_handle + * @param id + * @param value + * + * @return set_param() + * @return 0 + */ +static int _init_get_param(igd_display_h display_handle, + unsigned long id, + unsigned long *value) +{ + switch(id) { + case IGD_PARAM_DEBUG_MASK: + *value = *((unsigned long *)igd_debug); + break; + default: + break; + } + return 0; +} + +/*! + * Hook up the dispatch pointers. These are only available when the + * full init module is compiled in. + * + * @param context + * + * @return void + */ +static void _init_dispatch(igd_context_t *context) +{ + /* Hook up top level dispatch table functions owner by init */ + context->dispatch.get_param = _igd_get_param; + context->dispatch.set_param = _igd_set_param; + return; +} + +/*! + * Shutdown all modules in the required order. Optional modules must + * only be called if they exist. + * + * @param context + * + * @return void + */ +static void shutdown_modules(igd_context_t *context) +{ + OS_TRACE_ENTER; + + if(context->mod_dispatch.shutdown_2d) { + context->mod_dispatch.shutdown_2d(context); + } + if(context->mod_dispatch.blend_shutdown) { + context->mod_dispatch.blend_shutdown(context); + } + if(context->mod_dispatch.interrupt_shutdown) { + context->mod_dispatch.interrupt_shutdown(context); + } + if(context->mod_dispatch.appcontext_shutdown) { + context->mod_dispatch.appcontext_shutdown(context); + } + if(context->mod_dispatch.reset_shutdown) { + context->mod_dispatch.reset_shutdown(context); + } + if(context->mod_dispatch.mode_shutdown) { + context->mod_dispatch.mode_shutdown(context); + } + if(context->mod_dispatch.pwr_shutdown) { + context->mod_dispatch.pwr_shutdown(context); + } + if(context->mod_dispatch.overlay_shutdown) { + context->mod_dispatch.overlay_shutdown(context); + } + if(context->mod_dispatch.cmd_shutdown) { + context->mod_dispatch.cmd_shutdown(context); + } + /* + * GMM is not optional shutdown must exist. + */ + gmm_shutdown(context); + + /* + * Reg module must be last to restore the state of the device to the + * way it was before the driver started. + */ + OS_DEBUG("post reg_shutdown: %p", context->mod_dispatch.reg_shutdown); + if(context->mod_dispatch.reg_shutdown) { + context->mod_dispatch.reg_shutdown(context); + } + + OS_TRACE_EXIT; +} + +/*! + * This function should never be called directly. It comprises the optional + * portion of the igd_driver_shutdown function which should be used instead. + * + * @param driver_handle + * + * @return void + */ +static void _init_driver_shutdown(igd_driver_h driver_handle) +{ + igd_context_t *context = (igd_context_t *)driver_handle; + + OS_TRACE_ENTER; + + OS_ASSERT(context, "Null Driver Handle", ); + + if(context->device_context.power_state != IGD_POWERSTATE_D0) { + return; + } + + /* Shutdown Modules */ + shutdown_modules(context); + + /* Shutdown the device context */ + init_dispatch->shutdown(context); + + /* release the driver's context */ + if(context) { + OS_DEBUG("Freeing context"); + OS_FREE(context); + } + + OS_TRACE_EXIT; + return; +} + +#endif + +/*! + * Empty idle function. This insures that anyone can call + * dispatch->idle() in any configuration. If there is a command + * module this will get replaced with a real idle function. + * + * @param driver_handle + * + * @return 0 + */ +static int empty_idle(igd_driver_h driver_handle) +{ + return 0; +} + +/*! + * Empty sync function. This insures that anyone can call + * dispatch->sync() in any configuration. + * + * @param display_handle pointer to an IGD_DISPLAY pointer returned + * from a successful call to dispatch->alter_displays(). + * + * @param priority The command queue to use. IGD_PRIORITY_NORMAL is + * correct for most circumstances. + * + * @param sync The sync identifier that will be populated and returned + * during the call. To insert a new sync, this should be passed + * containing 0 (A pointer to a zero). To check the status of an + * existing sync pass the value returned from a previous call to + * this function. + * + * @param flags Sync flags. + * + * @returns + * 0: On Success + * -IGD_ERROR_BUSY: When the sync is not yet complete + */ +static int empty_sync(igd_display_h display_handle, int priority, + unsigned long *sync, unsigned long flags) +{ + return 0; +} + +/*! + * Non-Optional Init Module Components + * + * @param found_device + * @param pdev + * + * @return 0 on success + * @return -IGD_ERROR_NODEV on failure + */ +static int detect_device(iegd_pci_t **found_device, + os_pci_dev_t *pdev) +{ + int i; + + /* Scan the PCI bus for supported device */ + for(i = 0; i < MAX_PCI_DEVICE_SUPPORTED; i++) { + + *pdev = OS_PCI_FIND_DEVICE(intel_pci_device_table[i].vendor_id, + intel_pci_device_table[i].device_id, + intel_pci_device_table[i].bus, + intel_pci_device_table[i].dev, + intel_pci_device_table[i].func, + (os_pci_dev_t)0); + + if(*pdev) { + *found_device = &intel_pci_device_table[i]; + break; + } + } + if(!*pdev) { + OS_ERROR("No supported VGA devices found."); + return -IGD_ERROR_NODEV; + } + + OS_DEBUG("VGA device found: 0x%x", (*found_device)->device_id); + + return 0; +} + +/* This is currently a global context, because the context is needed + * in io.c for vbios in OS_READx and OS_WRITEx functions. */ +igd_context_t *fixme_vbios_context; + +/* By declaring io_mapped and io_base as globals, we no longer need to + * include context.h in the vbios common io.c */ + +/* Device 0:2:0 io_base */ +unsigned char io_mapped; /* True for io mapped MMIO space */ +unsigned short io_base; + +/* Device 0:2:0 [VGA device] io_base */ +unsigned char io_mapped_lvds; /* True for io mapped MMIO space */ +unsigned short io_base_lvds; + +/* Device 0:3:0 [SDVO device] io_base */ +unsigned char io_mapped_sdvo; /* True for io mapped MMIO space */ +unsigned short io_base_sdvo; + +/* Device 0:31:0 [LPC device] io_base */ +unsigned char io_mapped_lpc; /* True for io mapped MMIO space */ +unsigned short io_base_lpc; + + +/*! + * This function is directly exported. + * + * @param found_device + * @param pdev + * + * @return igd_driver_h + * @return NULL on failure + */ +igd_driver_h igd_driver_init( igd_init_info_t *init_info ) +{ + igd_context_t *context; + os_pci_dev_t pdev = (os_pci_dev_t)NULL; + os_pci_dev_t vga_disable_dev; + iegd_pci_t *found_device; + int ret; + int i; + + OS_TRACE_ENTER; + + /* Allocate a context */ + context = (void *) OS_ALLOC(sizeof(igd_context_t)); + fixme_vbios_context = context; + if(!context) { + OS_ERROR_EXIT("igd_driver_init failed to create context"); + return NULL; + } + OS_MEMSET(context, 0, sizeof(igd_context_t)); + + /* Search VGA devices for a supported one */ + ret = detect_device(&found_device, &pdev); + if(ret) { + OS_FREE(context); + return NULL; + } + + /* + * Some platforms (currently only Tunnel Creek) use two PCI devices (the + * second device being for SDVO) and this causes the VGA arbiter to get + * involved. Legacy VGA decoding must be disabled for all PCI devices + * except one, otherwise the VGA arbiter will prevent DRI usage in the + * X server. + */ + for (i = 0; i < MAX_LEGACY_VGA_DISABLE; i++) { + vga_disable_dev = os_pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SDVO_TNC, 0xFFFF, 0, 0, NULL); + if (vga_disable_dev) { + printk(KERN_INFO "VGA arbiter detected; disabling legacy VGA decoding on SDVO device"); + os_pci_disable_legacy_vga_decoding(vga_disable_dev); + os_pci_free_device(vga_disable_dev); + } + } + + context->device_context.did = found_device->device_id; + init_dispatch = (init_dispatch_t *)dispatch_acquire(context, + init_dispatch_table); + + if(!init_dispatch) { + OS_ERROR_EXIT("No dispatch found for listed device"); + return NULL; + } + + ret = init_dispatch->query(context, init_dispatch, pdev, &init_info->bus, + &init_info->slot, &init_info->func); + if(ret) { + OS_FREE(context); + OS_ERROR_EXIT("Device Dependent Query Failed"); + return NULL; + } + + /* init info */ + init_info->vendor_id = found_device->vendor_id; + init_info->device_id = found_device->device_id; + init_info->name = init_dispatch->name; + init_info->chipset = init_dispatch->chipset; + init_info->default_pd_list = init_dispatch->default_pd_list; + + OS_TRACE_EXIT; + + return (igd_driver_h)context; +} + +/*! + * This function is directly exported. + * + * @param driver_handle + * + * @return 0 on success + * @return 1 on failure + */ +int igd_driver_config(igd_driver_h driver_handle) +{ + igd_context_t *context = (igd_context_t *)driver_handle; + int ret; + + OS_TRACE_ENTER; + + OS_ASSERT(context, "Null context!", -IGD_ERROR_INVAL); + + ret = init_dispatch->config(context, init_dispatch); + if(ret) { + OS_ERROR_EXIT("Device Dependent Config Failed"); + return ret; + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * Initialize modules in the required order. Optional modules must be called + * with their initalization macro to ensure that they are not called when + * their option is not enabled. + * + * @param params + * @param context + * + * @return 0 on success + * @return 1 on failure + */ +/* FIXME: All modules should get params from mod_dispatch */ +static int init_modules(igd_param_t *params, igd_context_t *context) +{ + unsigned int ret; + + OS_TRACE_ENTER; + + /* + * Reg module must be first so that the state of the device can be + * saved before anything else is touched. + */ + ret = REG_INIT(context, (params->preserve_regs)?IGD_DRIVER_SAVE_RESTORE:0); + if (ret) { + OS_DEBUG("Error initializing register module"); + } + + /* + * GMM is not optional. Its init function must exist. + */ + ret = gmm_init(context, params->page_request, params->max_fb_size); + if(ret) { + OS_ERROR_EXIT("GMM Module Init Failed"); + return ret; + } + + ret = CMD_INIT(context); + if(ret) { + OS_ERROR_EXIT("Command Module Init Failed"); + return ret; + } + + /* + * Mode is not optional. Its init function must exist. + */ + ret = mode_init(context); + if (ret) { + OS_ERROR_EXIT("Mode Module Init Failed"); + return ret; + } + + ret = APPCONTEXT_INIT(context); + if (ret) { + OS_ERROR_EXIT("Appcontext Module Init Failed"); + return ret; + } + + ret = OVERLAY_INIT(context, params); + if(ret) { + OS_ERROR_EXIT("Overlay Module Init Failed"); + return ret; + } + + ret = PWR_INIT(context); + if(ret) { + OS_DEBUG("Error initializing power module"); + } + + ret = RESET_INIT(context); + if(ret) { + OS_DEBUG("Error initializing reset module"); + } + + ret = OS_INIT_INTERRUPT(context->device_context.did, + context->device_context.virt_mmadr); + if(ret) { + OS_ERROR_EXIT("Interrupt Module Init Failed"); + return ret; + } + + ret = BLEND_INIT(context); + if(ret) { + OS_DEBUG("Error initializing blend module"); + } + + ret = INIT_2D(context); + if(ret) { + OS_DEBUG("Error initializing 2d module"); + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * This function is directly exported. + * + * @param driver_handle + * @param dsp + * @param params + * + * @return 0 on success + * @return 1 on failure + */ +int igd_module_init(igd_driver_h driver_handle, + igd_dispatch_t **dsp, + igd_param_t *params) +{ + igd_context_t *context = (igd_context_t *)driver_handle; + device_context_t *device; + int ret = 0; + + OS_TRACE_ENTER; + + device = &context->device_context; + context->device_context.power_state = IGD_POWERSTATE_D0; + context->mod_dispatch.init_params = params; + context->dispatch.idle = empty_idle; + context->dispatch.sync = empty_sync; + + /* Intialize IGD Modules */ + ret = init_modules(params, context); + if (ret) { + OS_ERROR_EXIT("Init Modules Failed"); + return ret; + } + + OPT_MICRO_VOID_CALL(_init_dispatch(context)); + + *dsp = &context->dispatch; + + OS_TRACE_EXIT; + return 0; +} + +/*! + * This function is directly exported. + * + * @param driver_handle + * @param info + * + * @return 0 + */ +int igd_get_config_info(igd_driver_h driver_handle, + igd_config_info_t *config_info) +{ + igd_context_t *context = (igd_context_t *)driver_handle; + + OS_TRACE_ENTER; + + OS_ASSERT(context, "Null context!", -IGD_ERROR_INVAL); + OS_ASSERT(config_info, "Null config_info!", -IGD_ERROR_INVAL); + + OS_MEMSET(config_info, 0, sizeof(igd_config_info_t)); + + /* Config information already obtained from driver_config() */ + config_info->mmio_base_phys = context->device_context.mmadr; + config_info->mmio_base_virt = context->device_context.virt_mmadr; + config_info->gtt_memory_base_phys = context->device_context.fb_adr; + /* config_info->gtt_memory_base_virt = context->device_context.virt_fb_adr; */ + config_info->gtt_memory_size = context->device_context.mem_size; + config_info->revision_id = context->device_context.rid; + config_info->hw_status_offset = context->device_context.hw_status_offset; + config_info->stolen_memory_base_virt = + context->device_context.reserved_mem_base_addr; + + /* get the portions held in the dsp module */ + if(context->mod_dispatch.dsp_get_config_info) { + context->mod_dispatch.dsp_get_config_info(context, config_info); + } + /* get the portions held in the pi module */ + if(context->mod_dispatch.pi_get_config_info) { + context->mod_dispatch.pi_get_config_info(context, config_info); + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * This function is directly exported. When compiled without the init + * module the function calls the DD layer get_param function. When the + * full init module is included this function calls _init_get_param to + * first get the DI parameters then calls the DD layer. + * + * @param driver_handle + * @param id + * @param value + * + * @return get_param() + */ +int igd_get_param(igd_driver_h driver_handle, + unsigned long id, + unsigned long *value) +{ + igd_context_t *context = (igd_context_t *)driver_handle; + + OS_ASSERT(context, "Null Driver Handle", -IGD_ERROR_INVAL); + OS_ASSERT(value, "Null Value", -IGD_ERROR_INVAL); + + OPT_MICRO_CALL(_init_get_param(driver_handle, id, value)); + + return init_dispatch->get_param(context, id, value); +} + +/*! + * This function is directly exported. When compiled without the init + * module the function does nothing and returns 0. When the full init + * module is included this function calls _init_set_param and returns + * the result. + * + * @param driver_handle + * @param id + * @param value + * + * @return 0 + */ +int igd_set_param(igd_driver_h driver_handle, + unsigned long id, + unsigned long value) +{ + igd_context_t *context = (igd_context_t *)driver_handle; + + OS_ASSERT(context, "Null Driver Handle", -IGD_ERROR_INVAL); + + OPT_MICRO_CALL(_init_set_param(context, id, value)); + return 0; +} + +/*! + * This function is exported directly. It will shutdown an instance + * of the HAL that was initialized with igd_driver_init. + * + * Since the symbol is exported as part of the documented API it must + * always exist, however it becomes an empty function when the init + * module is not fully included. + * + * @param driver_handle + * + * @return void + */ +void igd_driver_shutdown(igd_driver_h driver_handle) +{ + OPT_MICRO_VOID_CALL(_init_driver_shutdown(driver_handle)); +} + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: igd_init.c,v 1.11 2010/04/27 20:33:49 bpaauwe Exp $ + * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/core/init/cmn/igd_init.c,v $ + *---------------------------------------------------------------------------- + */ + diff --git a/drivers/gpu/drm/emgd/emgd/core/init/cmn/init_dispatch.h b/drivers/gpu/drm/emgd/emgd/core/init/cmn/init_dispatch.h new file mode 100644 index 0000000..f673c0c --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/core/init/cmn/init_dispatch.h @@ -0,0 +1,57 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: init_dispatch.h + * $Revision: 1.3 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * + *----------------------------------------------------------------------------- + */ + +#ifndef _INIT_DISPATCH_H +#define _INIT_DISPATCH_H + +#include + +#include + +/* + * Note: Platforms extend this data structure so the pointer can be used + * as either this DI dispatch or cast to the DD dipatch. + */ +typedef struct _init_dispatch { + char *name; + char *chipset; + char *default_pd_list; + int (*query)(igd_context_t *context, struct _init_dispatch *dispatch, + os_pci_dev_t vga_dev, unsigned int *bus, unsigned int *slot, + unsigned int *func); + int (*config)(igd_context_t *context, struct _init_dispatch *dispatch); + int (*set_param)(igd_context_t *context, unsigned long id, + unsigned long value); + int (*get_param)(igd_context_t *context, unsigned long id, + unsigned long *value); + void (*shutdown)(igd_context_t *context); +} init_dispatch_t; + +extern init_dispatch_t init_dispatch_plb; +extern init_dispatch_t init_dispatch_tnc; +extern init_dispatch_t init_dispatch_tnc_a0; +extern init_dispatch_t init_dispatch_lnc; + +#endif diff --git a/drivers/gpu/drm/emgd/emgd/core/init/plb/init_plb.c b/drivers/gpu/drm/emgd/emgd/core/init/plb/init_plb.c new file mode 100644 index 0000000..4af0002 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/core/init/plb/init_plb.c @@ -0,0 +1,657 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: init_plb.c + * $Revision: 1.13 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.init + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "../cmn/init_dispatch.h" +#include "/usr/include/linux/pci_regs.h" +/*! + * @addtogroup core_group + * @{ + */ + +static int bus_master_enable_plb(platform_context_plb_t *platform_context); +static int full_config_vga_plb(igd_context_t *context, + init_dispatch_t *dispatch); +static int get_stolen_mem_plb(igd_context_t *context, unsigned long *pages); + +int full_get_param_plb(igd_context_t *context, + unsigned long id, + unsigned long *value); + +int gtt_init_plb(igd_context_t *context); + +#ifdef CONFIG_GTT_INIT +#define GTT_INIT_PLB(context) gtt_init_plb(context) +#else +#define GTT_INIT_PLB(context) +#endif + +/*! + * + * @param context + * @param dispatch + * @param vga_dev + * + * @return -IGD_ERROR_NODEV on failure + * @return 0 on success + */ +int get_revision_id_plb(igd_context_t *context, + os_pci_dev_t vga_dev) +{ + OS_TRACE_ENTER; + + /* Read RID */ + if(OS_PCI_READ_CONFIG_8(vga_dev, PCI_RID, + (unsigned char *)&context->device_context.rid)) { + OS_ERROR_EXIT("Error occured reading RID"); + return -IGD_ERROR_NODEV; + } + + OS_DEBUG(" rid = 0x%lx", context->device_context.rid); + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param context + * @param dispatch + * + * @return 1 on failure + * @return 0 on success + */ +int full_config_plb(igd_context_t *context, + init_dispatch_t *dispatch) +{ + unsigned long /* FIXME - reserved_mem, */ graphics_frequency ; + platform_context_plb_t *platform_context; + int ret; + + OS_TRACE_ENTER; + + platform_context = (platform_context_plb_t *)context->platform_context; + + _sgx_base = 0x40000; + _msvdx_base = 0x50000; + + /* + * Enable bus mastering for platforms whose BIOS did not perform this + * task for us. + */ + ret = bus_master_enable_plb(platform_context); + if(ret) { + OS_ERROR("Error: Enabling bus master"); + } + + /* Config VGA */ + ret = full_config_vga_plb(context, dispatch); + if(ret) { + OS_ERROR_EXIT("Config VGA Failed"); + return ret; + } + + get_stolen_mem_plb(context, &context->device_context.reserved_mem); + +#if 0 /* FIXME - WHY IS THIS RETURNING 0 AND SETTING reserved_mem TO 0 ALSO? */ + /* Get mem reservation param if it exists */ + if(!full_get_param_plb(context, IGD_PARAM_MEM_RESERVATION, + &reserved_mem)) { + context->device_context.reserved_mem = reserved_mem; + } +#endif + + /* Get graphics frequency param if it exists */ + if(!full_get_param_plb(context, IGD_PARAM_GFX_FREQ, + &graphics_frequency)) { + context->device_context.gfx_freq = (unsigned short)graphics_frequency; + } + + /* + * The Poulsbo chipset has no aperture, we'll substitute the base of + * stolen memory for fb_adr. See full_config_vga_plb(). + */ + /*if (OS_MAP_STOLEN_MEM(OS_GET_VIRT_APERT_BASE(), + context->device_context.fb_adr, + (context->device_context.reserved_mem * 4096))) { + OS_ERROR("Error: Failed to map stolen memory into virtual aperture"); + return -IGD_ERROR_NODEV; + }*/ + + /* initialize gtt for certain configs */ + GTT_INIT_PLB(context); + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param platform_context + * + * @return -1 on failure + * @return 0 on success + */ +static int bus_master_enable_plb(platform_context_plb_t *platform_context){ + int ret; + unsigned char tmp; + + OS_TRACE_ENTER; + + ret = OS_PCI_READ_CONFIG_8(platform_context->pcidev0, PCI_COMMAND_MASTER, &tmp); + if(ret) { + OS_ERROR_EXIT("PCI read of bus master"); + return -1; + } + + /* + * Get Bit 2, 1, and 0 and see if it is == 1 + * all 3 bits has to be enabled. This is to enable register read/write + * in the case of a PCI card being added + */ + if((tmp & 0x7) != 0x7 ) { + + tmp |= 0x7; + ret = OS_PCI_WRITE_CONFIG_8(platform_context->pcidev0, PCI_COMMAND_MASTER, tmp); + if(ret) { + OS_ERROR_EXIT("PCI write of bus master"); + return -1; + } + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param context + * @param dispatch + * + * @return -IGD_ERROR_NODEV on failure + * @return 0 on success + */ +static int full_config_vga_plb(igd_context_t *context, + init_dispatch_t *dispatch) +{ + unsigned char tmp = 0; + unsigned long size = 0; + int ret; + unsigned long gtt_size = 0; + + platform_context_plb_t *platform_context = + (platform_context_plb_t *)context->platform_context; + + OS_TRACE_ENTER; + + /* + * By design, the Poulsbo chipset cannot use the aperture. Instead it + * uses its own MMU, and not the GTT. Since there is no aperture, + * we'll substitute the base of stolen memory for fb_adr + */ + if(OS_PCI_READ_CONFIG_32(platform_context->pcidev0, + PLB_PCI_BSM, (void*)&context->device_context.fb_adr)) { + OS_ERROR_EXIT("Reading GMADR"); + return -IGD_ERROR_NODEV; + } + context->device_context.fb_adr &= 0xfffff000; + + /* + * In PLB, the Aperture could theoretically be 128MB, or 256MB + * we have to refer to the MSAC for this. In practice, it's always + * 128MB + */ + ret = OS_PCI_READ_CONFIG_8(platform_context->pcidev0, + PLB_OFFSET_VGA_MSAC, (void*)&tmp); + + if(!ret){ + switch (tmp & 0x3) { + case 0x3: + size = 128*1024*1024; + gtt_size = 128*1024; + break; + case 0x2: + size = 256*1024*1024; + gtt_size = 256*1024; + break; + default: + OS_ERROR_EXIT("Invalid Aperture Size"); + return -IGD_ERROR_NODEV; + } + } + + /* + * With a split gart architecture the virtual aperture is always + * 256mb even when the real aperture is only 128MB. + */ + size = 256*1024*1024; + gtt_size = 256*1024; + + /* + * FIXME: device_context.virt_fb_adr is no longer vaild and + * needs to be removed from the device context. + * + * It is not pratical to create a mapping in kernel space + * for the entire 256MB range. + */ + context->device_context.mem_size = size; + + if(OS_PCI_READ_CONFIG_32(platform_context->pcidev0, + PLB_PCI_MMADR, (void*)&context->device_context.mmadr)) { + OS_ERROR_EXIT("Reading MMADR"); + return -IGD_ERROR_NODEV; + } + + context->device_context.mmadr &= 0xfffffff9; + context->device_context.virt_mmadr = + OS_MAP_IO_TO_MEM_NOCACHE(context->device_context.mmadr, PLB_MMIO_SIZE); + + if (!context->device_context.virt_mmadr) { + OS_ERROR_EXIT("Failed to map MMADR"); + return -IGD_ERROR_NODEV; + } + + OS_DEBUG("mmadr mapped %dKB @ (phys):0x%lx (virt):%p", + PLB_MMIO_SIZE/1024, + context->device_context.mmadr, + context->device_context.virt_mmadr); + + /* + * The GTT is programmed through a seperate MMIO range than the + * rest of the registers. It is found at PCI_BAR_3. + */ + if(OS_PCI_READ_CONFIG_32(platform_context->pcidev0, + PLB_PCI_GTTADR, &context->device_context.gttadr)) { + OS_ERROR_EXIT("Failed to read GTTADR"); + return -IGD_ERROR_NODEV; + } + + context->device_context.virt_gttadr = + OS_MAP_IO_TO_MEM_NOCACHE(context->device_context.gttadr, gtt_size); + + if (!context->device_context.virt_gttadr) { + OS_ERROR_EXIT("Failed to map GTTADR"); + return -IGD_ERROR_NODEV; + } + /* Size in number of entries. Poulsbo is set 128K for GTTADR. + * The following result is equal to 128*1024*1024/4096. + */ + context->device_context.gtt_size = gtt_size / 4; + + + OS_DEBUG("GTT mapped %ldK entries @ (phys):0x%lx (virt):%p", + context->device_context.gtt_size/1024, + context->device_context.gttadr, + context->device_context.virt_gttadr); + + /* PCI Interrupt Line */ + if(OS_PCI_READ_CONFIG_8(platform_context->pcidev0, + PCI_INTERRUPT_LINE, (void*)&platform_context->irq)) { + platform_context->irq = 0; + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * Get the # of pages used for video memory. This does not use information from + * the scratch register, since this is done later if it exists. + * + * @param context + * @param pages + * + * @return -IGD_ERROR_INVAL on failure + * @return 0 on success + */ +static int get_stolen_mem_plb(igd_context_t *context, unsigned long *pages) +{ + platform_context_plb_t *platform_context; + os_pci_dev_t vga_dev; + unsigned short gmch_ctl; + unsigned long stolen_mem; /* in bytes */ + int ret; + + OS_TRACE_ENTER; + + platform_context = (platform_context_plb_t *)context->platform_context; + vga_dev = platform_context->pcidev0; + + ret = OS_PCI_READ_CONFIG_16(vga_dev, PLB_PCI_GC, &gmch_ctl); + if (ret) { + OS_ERROR_EXIT("Unable to read PLB_PCI_GC"); + return -IGD_ERROR_INVAL; + } + + switch (gmch_ctl & 0x70) { + case 0x00: + stolen_mem = 0; + break; + case 0x10: + /* 1M */ + stolen_mem = 1*1024*1024; + break; + case 0x20: + /* 4M */ + stolen_mem = 4*1024*1024; + break; + case 0x30: + /* 8M */ + stolen_mem = 8*1024*1024; + break; + case 0x40: + /* 16M */ + stolen_mem = 16*1024*1024; + break; + case 0x50: + /* 32M */ + stolen_mem = 32*1024*1024; + break; + case 0x60: + /* 48M */ + stolen_mem = 48*1024*1024; + case 0x70: + /* 64M */ + stolen_mem = 64*1024*1024; + break; + default: + OS_ERROR_EXIT("Unknown Stolen Memory Size"); + return -IGD_ERROR_INVAL; + } + + if (stolen_mem) { + /* + * Subtract off the size of the GTT which is + * (number of entries in DWORDS) * 4 to get it into bytes + */ + stolen_mem -= context->device_context.gtt_size*4; + /* Subtract off 1 page for the scratch page */ + stolen_mem -= 4*1024; + } + + /* Convert to the # of pages available for stolen memory */ + *pages = stolen_mem / 4096; + + OS_DEBUG("Stolen memory: 0x%lx pages", *pages); + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param context + * @param id + * @param value + * + * @return -IGD_ERROR_INVAL on failure + * @return 0 on success + */ +int full_get_param_plb(igd_context_t *context, + unsigned long id, + unsigned long *value) +{ + int ret = 0; + unsigned char *mmio; + unsigned long control_reg; + + OS_TRACE_ENTER; + + OS_DEBUG("ID: 0x%lx", id); + + /* Scratch registers used as below: + * + * 0x71410: + * -------- + * Bits 31-16 - EID Firmware identifier 0xE1DF + * Bits 15-00 - Tell what data is present. + * Here are bits for what we are using know: + * Bit 0 - Panel id + * Bit 1 - List of ports for which displays are attached + * Bit 2 - Memory reservation + * If any of the above bits is set that mean data is followed + * in the next registers. + * + * 0x71414: + * -------- + * Bits 07-00 - Panel Id + * Bits 11-08 - Port list + * Information for Port list: If any of the bit is set means, + * a display is attached to that port as follows: + * Bit 08 - CRT + * Bit 09 - DVOA/Internal LVDS + * Bit 10 - DVOB/RGBA + * Bit 11 - DVOC + * + * 0x71418: + * -------- + * Bits 15-00 - Reserved Memory value in number of 4k size pages + */ + mmio = context->device_context.virt_mmadr; + control_reg = OS_READ32(OS_MMIO(mmio) + 0x71410); + *value = 0; + + switch(id) { + case IGD_PARAM_PANEL_ID: + /* + * Check for Embedded firmware + */ + if ((control_reg>>16) != 0xE1DF) { + OS_DEBUG("No Embedded vBIOS found"); + OS_TRACE_EXIT; + return -IGD_ERROR_INVAL; + } + + /* + * The panel id bit must be set in the control register + * to indicate valid panel (config) ID value. + */ + if (control_reg & 0x1) { + *value = OS_READ32(OS_MMIO(mmio) + 0x71414) & 0xFF; + if(!(*value)) { + /* we cannot allow for config id = 0 */ + ret = -IGD_ERROR_INVAL; + } + } else { + OS_DEBUG("Panel ID read failed: Incorrect Operation"); + ret = -IGD_ERROR_INVAL; + } + break; + case IGD_PARAM_MEM_RESERVATION: + /* + * Check for Embedded firmware + */ + if ((control_reg>>16) != 0xE1DF) { + OS_DEBUG("No Embedded vBIOS found"); + OS_TRACE_EXIT; + return -IGD_ERROR_INVAL; + } + + /* + * The mem reservation bit must be set in the control register + * to indicate valid mem reservation value. + */ + if (control_reg & 0x4) { + *value = (OS_READ32(OS_MMIO(mmio) + 0x71418) & 0xFFFF); + } else { + OS_DEBUG("Mem Reservation read failed: Incorrect Operation"); + ret = -IGD_ERROR_INVAL; + } + break; + default: + ret = -IGD_ERROR_INVAL; + break; + } + + OS_TRACE_EXIT; + return ret; +} + +/*! + * + * @param context + * + * @return void + */ +void full_shutdown_plb(igd_context_t *context) +{ + platform_context_plb_t *platform_context = + (platform_context_plb_t *)context->platform_context; + + OS_TRACE_ENTER; + + /* unmap registers */ + if(context->device_context.virt_mmadr) { + OS_DEBUG("Unmapping Gfx registers and GTT Table..."); + OS_UNMAP_IO_FROM_MEM((void *) context->device_context.virt_mmadr, + PLB_MMIO_SIZE); + OS_UNMAP_IO_FROM_MEM((void *)context->device_context.virt_gttadr, + context->device_context.gtt_size * 4); + } + + if (platform_context) { + OS_PCI_FREE_DEVICE(platform_context->pcidev0); + } + OS_TRACE_EXIT; +} + +/*! + * Program the GTT. + * + * @param context + * + * @return gtt_init_ret_code + * @return 0 + */ +int gtt_init_plb(igd_context_t *context) +{ + /* Program the GTT. + * The GTT is programmed as follows when NOT using A000 for storing + * Dynamic Data: + * Generic case 256MB RAM with + * 128MB Aperture and + * 8MB Stolen memory + * Example + * -------------------- -------------------- + * ---------- Top of RAM (TR) 256MB + * | GTT | + * S M | | + * t e |--------| TR-sizeof(GTT) 256MB-128KB + * o m |Scrch pg| 4KB for scratch page + * o o |--------| 256MB-132KB + * e r | | + * n y | Video | + * | Mem | + * |--------| TR-sizeof(stolen_mem) 256MB-8MB + * | | + * | System | + * | Mem | + * | | + * ---------- 00000000 0 + * + */ + os_pci_dev_t vga_dev; + unsigned long pci_read_long; + platform_context_plb_t *platform_context; + int gtt_init_ret_code = 0; + unsigned long phys_stolen_mem, phys_page_table, page_table_entry; + unsigned char *mmio, *virt_gttadr; + + OS_TRACE_ENTER; + + platform_context = (platform_context_plb_t *)context->platform_context; + vga_dev = platform_context->pcidev0; + mmio = context->device_context.virt_mmadr; + virt_gttadr = context->device_context.virt_gttadr; + + /* Enable the PCI Device */ + gtt_init_ret_code = OS_ENABLE_PCI(vga_dev); + if(gtt_init_ret_code) { + return gtt_init_ret_code; + } + + /* Get Stolen Memory Base Address */ + OS_PCI_READ_CONFIG_32(vga_dev, PLB_PCI_BSM, &pci_read_long); + context->device_context.reserved_mem_base_addr = + pci_read_long & 0xFFF00000; + + /* Physical address of the beginning of video memory */ + phys_stolen_mem = context->device_context.reserved_mem_base_addr; + + /* Physical address of the beginning of the page table. + * This is at the end of memory - + * size of the gtt((aperture_size/bytes-per-page)*bytes-per-entry) - + * the scratch page. */ + phys_page_table = phys_stolen_mem + + (context->device_context.reserved_mem * 4096) + 4096; + + /* Set the Base of the GTT page table so each entry can be set. + * Also enable the GTT */ + OS_WRITE32(phys_page_table|1, OS_MMIO(mmio) + PGTBL_CTL); + + OS_WRITE32(context->device_context.reserved_mem, OS_MMIO(mmio) + 0x71418); + + /* Program the GTT */ + for(page_table_entry = 0; + page_table_entry < context->device_context.reserved_mem; + page_table_entry++) { + + /* Enable */ + OS_WRITE32(phys_stolen_mem|1, virt_gttadr + (page_table_entry*4)); + phys_stolen_mem += 4096; + } + + /* Program the remainder of the GTT to the scratch page. */ + for(page_table_entry = context->device_context.reserved_mem; + page_table_entry < (context->device_context.gtt_size); + page_table_entry++) { + /* Enable */ + OS_WRITE32((phys_page_table - 4096) | 1, + virt_gttadr + (page_table_entry*4)); + } + + OS_TRACE_EXIT; + + return 0; +} diff --git a/drivers/gpu/drm/emgd/emgd/core/init/plb/micro_init_plb.c b/drivers/gpu/drm/emgd/emgd/core/init/plb/micro_init_plb.c new file mode 100644 index 0000000..0839044 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/core/init/plb/micro_init_plb.c @@ -0,0 +1,386 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: micro_init_plb.c + * $Revision: 1.6 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.init + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "../cmn/init_dispatch.h" + +/*! + * @addtogroup core_group + * @{ + */ + +#ifdef CONFIG_PLB + +extern unsigned char io_mapped; +extern unsigned short io_base; + +extern int full_config_plb(igd_context_t *context, + init_dispatch_t *dispatch); +extern int get_revision_id_plb(igd_context_t *context, os_pci_dev_t vga_dev); +extern int full_get_param_plb(igd_context_t *context, unsigned long id, + unsigned long *value); +extern void full_shutdown_plb(igd_context_t *context); + +static int query_plb(igd_context_t *context,init_dispatch_t *dispatch, + os_pci_dev_t vga_dev, unsigned int *bus, unsigned int *slot, + unsigned int *func); +static int config_plb(igd_context_t *context, + init_dispatch_t *dispatch); +static int set_param_plb(igd_context_t *context, unsigned long id, + unsigned long value); +static int get_param_plb(igd_context_t *context, unsigned long id, + unsigned long *value); +static void shutdown_plb(igd_context_t *context); + + +static platform_context_plb_t platform_context_plb; + +/* Graphics frequency list. This is valid for pouslbo only. This value is obtained + * From the Cspec - SCH Message Network-Port 5*/ +static unsigned short plb_gfx_freq_list[] = +{ + 100, 133, 150, 178, 200, 266, 0, 0 +}; + +init_dispatch_t init_dispatch_plb = { + "Intel SCH US15 Chipset", + "US15", + "lvds", + query_plb, + config_plb, + set_param_plb, + get_param_plb, + shutdown_plb +}; + +/*! + * + * @param context + * @param dispatch + * @param vga_dev + * @param bus + * @param slot + * @param func + * + * @return -IGD_ERROR_NODEV on failure + * @return 0 on success + */ +static int query_plb( + igd_context_t *context, + init_dispatch_t *dispatch, + os_pci_dev_t vga_dev, + unsigned int *bus, + unsigned int *slot, + unsigned int *func) +{ + platform_context_plb_t *platform_context = &platform_context_plb; + + OS_TRACE_ENTER; + + context->platform_context = (void *)&platform_context_plb; + + OS_PTHREAD_MUTEX_INIT(&platform_context_plb.flip_mutex, NULL); + + /* + * Current specs indicate that PLB has only one PCI function. + * If this changes then we need to make sure we have func 0 + * here as in previous chips. + */ + platform_context->pcidev0 = vga_dev; + + OS_PCI_GET_SLOT_ADDRESS(vga_dev, bus, slot, func); + + OPT_MICRO_CALL(get_revision_id_plb(context, vga_dev)); + + /* + * Read BSM. + * This must be in query so it is available early for the vBIOS. + */ + if(OS_PCI_READ_CONFIG_32(vga_dev, + PLB_PCI_BSM, &context->device_context.fb_adr)) { + OS_ERROR_EXIT("Reading BSM"); + return -IGD_ERROR_NODEV; + } + context->device_context.fb_adr &= 0xFFFFF000; + + OS_DEBUG("BSM (High)@: 0x%lx, (Low) 0x%4lx", (context->device_context.fb_adr >> 16), context->device_context.fb_adr); + + /* + * Read IO Base. + * This must be in query so it is available early for the vBIOS. + */ + if(OS_PCI_READ_CONFIG_16(vga_dev, PLB_PCI_IOBAR, &io_base)) { + OS_ERROR_EXIT("Reading IO Base"); + return -IGD_ERROR_NODEV; + } + io_base &= 0xfffe; + OS_DEBUG("io @: 0x%x", io_base); + + /* Gen4 is always io_mapped */ + io_mapped = 1; + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param context + * @param dispatch + * + * @return -IGD_ERROR_NODEV on failure + * @return 0 on success + */ +static int config_plb(igd_context_t *context, + init_dispatch_t *dispatch) +{ + unsigned long coreclk; + unsigned long graphics_frequency; + + platform_context_plb_t *platform_context = + (platform_context_plb_t *)context->platform_context; + + OS_TRACE_ENTER; + + OPT_MICRO_CALL(full_config_plb(context, dispatch)); + + /* Set the Max Dclock */ + if(OS_PCI_READ_CONFIG_32(platform_context->pcidev0, + INTEL_OFFSET_VGA_CORECLK, &coreclk)) { + OS_ERROR_EXIT("PCI Read of VGA Core Clock"); + return -IGD_ERROR_NODEV; + } + + /* Get graphics frequency param if it exists */ + if(!get_param_plb(context, IGD_PARAM_GFX_FREQ, + &graphics_frequency)) { + context->device_context.gfx_freq = (unsigned short)graphics_frequency; + } + + /* + * FIXME: + * Coreclk register above is used to determine some clocking information + * there is also a fuse to limit the dclk. More research needed. + */ + context->device_context.max_dclk = 762000; + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param context + * @param id + * @param value + * + * @return -IGD_ERROR_INVAL on failure + * @return 0 on success + */ +static int get_param_plb(igd_context_t *context, unsigned long id, + unsigned long *value) +{ + int ret = 0; + unsigned long control_reg; + os_pci_dev_t bridge_dev = (os_pci_dev_t)0; + + OS_TRACE_ENTER; + + OS_DEBUG("ID: 0x%lx", id); + + /* Scratch registers used as below: + * + * 0x71410: + * -------- + * Bits 31-16 - EID Firmware identifier 0xE1DF + * Bits 15-00 - Tell what data is present. + * Here are bits for what we are using know: + * Bit 0 - Panel id + * Bit 1 - List of ports for which displays are attached + * Bit 2 - Memory reservation + * If any of the above bits is set that mean data is followed + * in the next registers. + * + * 0x71414: + * -------- + * Bits 07-00 - Panel Id + * Bits 11-08 - Port list + * Information for Port list: If any of the bit is set means, + * a display is attached to that port as follows: + * Bit 08 - CRT + * Bit 09 - DVOA/Internal LVDS + * Bit 10 - DVOB/RGBA + * Bit 11 - DVOC + * + * 0x71418: + * -------- + * Bits 15-00 - Reserved Memory value in number of 4k size pages + */ + *value = 0; + + switch(id) { + case IGD_PARAM_PORT_LIST: + + control_reg = OS_READ32(OS_MMIO(context->device_context.virt_mmadr) + + 0x71410); + + /* + * Verify that the Embedded Firware is present. + */ + if ((control_reg>>16) != 0xE1DF) { + OS_DEBUG("Exit No Embedded vBIOS found"); + OS_TRACE_EXIT; + return -IGD_ERROR_INVAL; + } + + /* + * If the port list bit is set in control register, + * read the port list + */ + if (control_reg & 0x2) { + unsigned char temp; + int i = 0; + + temp = (unsigned char)((OS_READ32(OS_MMIO(context->device_context.virt_mmadr) + 0x71414)>>8) & 0xFF); + OS_DEBUG("Connected Port Bits: 0x%x", temp); + + /* + * The meanings of bits in temp were dictated by VBIOS + * and should not change due to backward compatibility + * with Legacy VBIOS + */ + if (temp & 0x01) { + /* Analog port */ + value[i++] = 5; + } + if (temp & 0x02) { + /* Internal LVDS port */ + value[i++] = 4; + } + if (temp & 0x04) { + /* DVOB Port */ + value[i++] = 2; + } + } else { + OS_DEBUG("Port List read failed: Incorrect Operation"); + ret = -IGD_ERROR_INVAL; + } + break; + case IGD_PARAM_GFX_FREQ: + /* Query register values from the bridge. This method uses the Poulsbo + * SCH Message Network. Setting offset 0xD0 in the host bridge config + * register sends an opcode to the Message Network. Reading register 0xD4 + * from the host bridge config register will get the return value of the + * sent opcode. + * + * This feature is for Pouslbo Only */ + + bridge_dev = OS_PCI_FIND_DEVICE( + PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_BRIDGE_PLB, + 0xFFFF, /* Scan the whole PCI bus */ + 0, + 0, + (os_pci_dev_t)0); + + if(!bridge_dev) { + OS_ERROR_EXIT("Bridge device NOT found."); + return -IGD_ERROR_INVAL; + } + /* write into the Message Control Register (MCR) + * [INPUT] should contain the formatted opcode + * that needs to be sent into the MCR */ + ret = OS_PCI_WRITE_CONFIG_32(bridge_dev, 0xD0, + (0xD0<<24)/*opcode*/|(5<<16)/*port*/|(3<<8)/*reg*/|(0xF<<4)); + if(ret) { + OS_ERROR("Writing into the MCR Failed"); + return -IGD_ERROR_INVAL; + } + /* read from the Message Data Register (MDR) */ + if(OS_PCI_READ_CONFIG_32(bridge_dev, 0xD4, + (void*) &control_reg)) { + OS_ERROR_EXIT("Reading from MDR Failed"); + return -IGD_ERROR_INVAL; + } + *value = plb_gfx_freq_list[control_reg & 0x7]; + OS_PCI_FREE_DEVICE(bridge_dev); + break; + default: + /* + * If the param is not found here then it may only be in the + * full version. + */ + OPT_MICRO_CALL_RET(ret, full_get_param_plb(context, id, value)); + break; + } + + OS_TRACE_EXIT; + return ret; +} + +/*! + * No Settable Params for PLB + * + * @param context + * @param id + * @param value + * + * @return -IGD_ERROR_INVAL + */ +static int set_param_plb(igd_context_t *context, unsigned long id, + unsigned long value) +{ + return -IGD_ERROR_INVAL; +} + +/*! + * + * @param context + * + * @return void + */ +static void shutdown_plb(igd_context_t *context) +{ + OPT_MICRO_VOID_CALL(full_shutdown_plb(context)); +} + +#endif diff --git a/drivers/gpu/drm/emgd/emgd/core/init/tnc/init_tnc.c b/drivers/gpu/drm/emgd/emgd/core/init/tnc/init_tnc.c new file mode 100644 index 0000000..3294c1a --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/core/init/tnc/init_tnc.c @@ -0,0 +1,744 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: init_tnc.c + * $Revision: 1.15 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.init + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "../cmn/init_dispatch.h" +#include "/usr/include/linux/pci_regs.h" + +/*! + * @addtogroup core_group + * @{ + */ + +static int bus_master_enable_tnc(platform_context_tnc_t *platform_context); +static int full_config_vga_tnc(igd_context_t *context, + init_dispatch_t *dispatch); +static int get_stolen_mem_tnc(igd_context_t *context, unsigned long *pages); + +int full_get_param_tnc(igd_context_t *context, + unsigned long id, + unsigned long *value); + +int gtt_init_tnc(igd_context_t *context); + +#ifdef CONFIG_GTT_INIT +#define GTT_INIT_TNC(context) gtt_init_tnc(context) +#else +#define GTT_INIT_TNC(context) +#endif + +/*! + * + * @param context + * @param dispatch + * @param vga_dev + * + * @return -IGD_ERROR_NODEV on failure + * @return 0 on success + */ +int get_revision_id_tnc(igd_context_t *context, + os_pci_dev_t vga_dev) +{ + OS_TRACE_ENTER; + + /* Read RID */ + if(OS_PCI_READ_CONFIG_8(vga_dev, PCI_RID, + (unsigned char *)&context->device_context.rid)) { + OS_ERROR_EXIT("Error occured reading RID"); + return -IGD_ERROR_NODEV; + } + + OS_DEBUG(" rid = 0x%lx", context->device_context.rid); + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param context + * @param dispatch + * + * @return 1 on failure + * @return 0 on success + */ +int full_config_tnc(igd_context_t *context, + init_dispatch_t *dispatch) +{ + unsigned long reserved_mem; + platform_context_tnc_t *platform_context; + int ret; + + OS_TRACE_ENTER; + + platform_context = (platform_context_tnc_t *)context->platform_context; + + _sgx_base = 0x80000; + _msvdx_base = 0x90000; + _topaz_base = 0xA0000; + + /* + * Enable bus mastering for platforms whose BIOS did not perform this + * task for us. + */ + ret = bus_master_enable_tnc(platform_context); + if(ret) { + OS_ERROR("Error: Enabling bus master"); + } + + /* Config VGA */ + ret = full_config_vga_tnc(context, dispatch); + if(ret) { + OS_ERROR_EXIT("Config VGA Failed"); + return ret; + } + + get_stolen_mem_tnc(context, &context->device_context.reserved_mem); + + /* Get mem reservation param if it exists */ + if(!full_get_param_tnc(context, IGD_PARAM_MEM_RESERVATION, + &reserved_mem)) { + context->device_context.reserved_mem = reserved_mem; + } + + /* + * The Poulsbo chipset has no aperture, we'll substitute the base of + * stolen memory for fb_adr. See full_config_vga_tnc(). + */ + /*if (OS_MAP_STOLEN_MEM(OS_GET_VIRT_APERT_BASE(), + context->device_context.fb_adr, + (context->device_context.reserved_mem * 4096))) { + OS_ERROR("Error: Failed to map stolen memory into virtual aperture"); + return -IGD_ERROR_NODEV; + }*/ + + /* initialize gtt for certain configs */ + GTT_INIT_TNC(context); + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param platform_context + * + * @return -1 on failure + * @return 0 on success + */ +/* + */ +static int bus_master_enable_tnc(platform_context_tnc_t *platform_context){ + int ret; + unsigned char tmp, tmp_sdvo; + + OS_TRACE_ENTER; + + ret = OS_PCI_READ_CONFIG_8(platform_context->pcidev0, PCI_COMMAND_MASTER, &tmp); + if(ret) { + OS_ERROR_EXIT("PCI read of bus master"); + return -1; + } + + /* + * Get Bit 2, 1, and 0 and see if it is == 1 + * all 3 bits has to be enabled. This is to enable register read/write + * in the case of a PCI card being added + */ + if((tmp & 0x7) != 0x7 ) { + + tmp |= 0x7; + ret = OS_PCI_WRITE_CONFIG_8(platform_context->pcidev0,PCI_COMMAND_MASTER, tmp); + if(ret) { + OS_ERROR_EXIT("PCI write of bus master"); + return -1; + } + } + + + if (platform_context->pcidev1) { + ret = OS_PCI_READ_CONFIG_8(platform_context->pcidev1,PCI_COMMAND_MASTER, &tmp_sdvo); + if(ret) { + OS_ERROR_EXIT("PCI read of bus master"); + return -1; + } + + if((tmp_sdvo & 0x7) != 0x7 ) { + tmp_sdvo |= 0x7; + ret = OS_PCI_WRITE_CONFIG_8(platform_context->pcidev1, + PCI_COMMAND_MASTER,tmp_sdvo); + if(ret) { + OS_ERROR_EXIT("PCI write of bus master"); + return -1; + } + } + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param context + * @param dispatch + * + * @return -IGD_ERROR_NODEV on failure + * @return 0 on success + */ +static int full_config_vga_tnc(igd_context_t *context, + init_dispatch_t *dispatch) +{ + unsigned char tmp = 0; + unsigned long size = 0; + int ret; + unsigned long gtt_size = 0; + + platform_context_tnc_t *platform_context = + (platform_context_tnc_t *)context->platform_context; + + OS_TRACE_ENTER; + + /* + * By design, the Poulsbo chipset cannot use the aperture. Instead it + * uses its own MMU, and not the GTT. Since there is no aperture, + * we'll substitute the base of stolen memory for fb_adr + */ + if(OS_PCI_READ_CONFIG_32(platform_context->pcidev0, + TNC_PCI_BSM, (void*)&context->device_context.fb_adr)) { + OS_ERROR_EXIT("Reading GMADR"); + return -IGD_ERROR_NODEV; + } + context->device_context.fb_adr &= 0xfffff000; + + /* + * In TNC, the Aperture could theoretically be 128MB, or 256MB + * we have to refer to the MSAC for this. In practice, it's always + * 128MB + */ + ret = OS_PCI_READ_CONFIG_8(platform_context->pcidev0, + TNC_OFFSET_VGA_MSAC, (void*)&tmp); + + if(!ret){ + switch (tmp & 0x3) { + /* + * With a split gart architecture the virtual aperture is always + * 256mb even when the real aperture is only 128MB. + */ + case 0x3: + size = 128*1024*1024; + gtt_size = 128*1024; + break; + case 0x2: + size = 256*1024*1024; + gtt_size = 256*1024; + break; + case 0x1: + size = 512*1024*1024; + gtt_size = 512*1024; + break; + default: + OS_ERROR_EXIT("Invalid Aperture Size"); + return -IGD_ERROR_NODEV; + } + } + + context->device_context.mem_size = size; + + /* + * Map the Device 2 MMIO register. These registers are similar to LNC + * and is located in the TNC Hard Macro + */ + if(OS_PCI_READ_CONFIG_32(platform_context->pcidev0, + TNC_PCI_MMADR, (void*)&context->device_context.mmadr)) { + OS_ERROR_EXIT("Reading MMADR"); + return -IGD_ERROR_NODEV; + } + + context->device_context.mmadr &= 0xfffffff9; + context->device_context.virt_mmadr = + OS_MAP_IO_TO_MEM_NOCACHE(context->device_context.mmadr, TNC_D2_MMIO_SIZE); + + if (!context->device_context.virt_mmadr) { + OS_ERROR_EXIT("Failed to map MMADR"); + return -IGD_ERROR_NODEV; + } + + OS_DEBUG("mmadr mapped %dKB @ (phys):0x%lx (virt):%p", + TNC_D2_MMIO_SIZE/1024, + context->device_context.mmadr, + context->device_context.virt_mmadr); + + + /* + * Map the device 3 MMIO registers. These are TNC specific registers + * located in the TNC Overlay. On LNC, these registers are part of + * the IOH (Langwell) + */ + if(OS_PCI_READ_CONFIG_32(platform_context->pcidev1, + TNC_PCI_MMADR, (void*)&context->device_context.mmadr_sdvo)) { + OS_ERROR_EXIT("Reading MMADR"); + return -IGD_ERROR_NODEV; + } + printk(KERN_ALERT "sdvo mmadr = 0x%lX\n", context->device_context.mmadr_sdvo); + + context->device_context.mmadr_sdvo &= 0xfffffff9; + context->device_context.virt_mmadr_sdvo = + OS_MAP_IO_TO_MEM_NOCACHE(context->device_context.mmadr_sdvo, + TNC_D3_MMIO_SIZE); + + if (!context->device_context.virt_mmadr_sdvo) { + OS_ERROR_EXIT("Failed to map MMADR"); + return -IGD_ERROR_NODEV; + } + + OS_DEBUG("sdvo mmadr mapped %dKB @ (phys):0x%lx (virt):%p", + TNC_D3_MMIO_SIZE/1024, + context->device_context.mmadr_sdvo, + context->device_context.virt_mmadr_sdvo); + + /* Map the GPIO BAR. Provides the 64 bytes of I/O space for GPIO + * BAR is defined by bits 15:6 */ + + if(OS_PCI_READ_CONFIG_16(platform_context->lpc_dev, + TNC_PCI_GBA, (void*)&context->device_context.gpio_bar)) { + + } + context->device_context.gpio_bar |= (1L<<31); + /* Enable the decode of IO Range ppointed to by the BA */ + if(OS_PCI_WRITE_CONFIG_32(platform_context->lpc_dev, + TNC_PCI_GBA, context->device_context.gpio_bar)) { + OS_ERROR_EXIT("Writing LPC GPIO BAR Enable"); + } + + /* read the GPIO BAR (OFFSET 44:47) */ + if(OS_PCI_READ_CONFIG_16(platform_context->lpc_dev, + TNC_PCI_GBA, (void*)&context->device_context.gpio_bar)) { + OS_ERROR_EXIT("Reading LPC GPIO BAR"); + /* We cannot read the GPIO BAR. It is a problem but we can go on with init + * return with NO ERROR*/ + return 0; + } + + context->device_context.gpio_bar &= 0xffc0; + + context->device_context.virt_gpio_bar = + OS_MAP_IO_TO_MEM_NOCACHE( + context->device_context.gpio_bar, 64); + + if (!context->device_context.virt_gpio_bar) { + OS_ERROR_EXIT("Failed to map LPC GPIO BAR"); + return -IGD_ERROR_NODEV; + } + + OS_DEBUG("GPIO mapped %dKB @ (phys):0x%lx (virt):%p", + 64, + context->device_context.gpio_bar, + context->device_context.virt_gpio_bar); + + /* + * The GTT is programmed through a seperate MMIO range than the + * rest of the registers. It is found at PCI_BAR_3. + */ + if(OS_PCI_READ_CONFIG_32(platform_context->pcidev0, + TNC_PCI_GTTADR, &context->device_context.gttadr)) { + OS_ERROR_EXIT("Failed to read GTTADR"); + return -IGD_ERROR_NODEV; + } + + context->device_context.virt_gttadr = + OS_MAP_IO_TO_MEM_NOCACHE(context->device_context.gttadr, gtt_size); + + if (!context->device_context.virt_gttadr) { + OS_ERROR_EXIT("Failed to map GTTADR"); + return -IGD_ERROR_NODEV; + } + /* Size in number of entries. Poulsbo is set 128K for GTTADR. + * The following result is equal to 128*1024*1024/4096. + */ + context->device_context.gtt_size = gtt_size / 4; + + + OS_DEBUG("GTT mapped %ldK entries @ (virt):%p", + context->device_context.gtt_size/1024, + context->device_context.virt_gttadr); + + /* PCI Interrupt Line */ + if(OS_PCI_READ_CONFIG_8(platform_context->pcidev0, + PCI_INTERRUPT_LINE, (void*)&platform_context->irq)) { + platform_context->irq = 0; + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * Get the # of pages used for video memory. This does not use information from + * the scratch register, since this is done later if it exists. + * + * @param context + * @param pages + * + * @return -IGD_ERROR_INVAL on failure + * @return 0 on success + */ +static int get_stolen_mem_tnc(igd_context_t *context, unsigned long *pages) +{ + platform_context_tnc_t *platform_context; + os_pci_dev_t vga_dev; + unsigned short gmch_ctl; + unsigned long stolen_mem; /* in bytes */ + int ret; + + OS_TRACE_ENTER; + + platform_context = (platform_context_tnc_t *)context->platform_context; + vga_dev = platform_context->pcidev0; + + ret = OS_PCI_READ_CONFIG_16(vga_dev, TNC_PCI_GC, &gmch_ctl); + if (ret) { + OS_ERROR_EXIT("Unable to read TNC_PCI_GC"); + return -IGD_ERROR_INVAL; + } + + switch (gmch_ctl & 0x70) { + case 0x00: + stolen_mem = 0; + break; + case 0x10: + /* 1M */ + stolen_mem = 1*1024*1024; + break; + case 0x20: + /* 4M */ + stolen_mem = 4*1024*1024; + break; + case 0x30: + /* 8M */ + stolen_mem = 8*1024*1024; + break; + case 0x40: + /* 16M */ + stolen_mem = 16*1024*1024; + break; + case 0x50: + /* 32M */ + stolen_mem = 32*1024*1024; + break; + case 0x60: + /* 48M */ + stolen_mem = 48*1024*1024; + case 0x70: + /* 64M */ + stolen_mem = 64*1024*1024; + break; + default: + OS_ERROR_EXIT("Unknown Stolen Memory Size"); + return -IGD_ERROR_INVAL; + } + + if (stolen_mem) { + /* + * Subtract off the size of the GTT which is + * (number of entries in DWORDS) * 4 to get it into bytes + */ + stolen_mem -= context->device_context.gtt_size*4; + /* Subtract off 1 page for the scratch page */ + stolen_mem -= 4*1024; + } + + /* Convert to the # of pages available for stolen memory */ + *pages = stolen_mem / 4096; + + OS_DEBUG("Stolen memory: 0x%lx pages", *pages); + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param context + * @param id + * @param value + * + * @return -IGD_ERROR_INVAL on failure + * @return 0 on success + */ +int full_get_param_tnc(igd_context_t *context, + unsigned long id, + unsigned long *value) +{ + int ret = 0; + unsigned char *mmio; + unsigned long control_reg; + + OS_TRACE_ENTER; + + OS_DEBUG("ID: 0x%lx", id); + + /* Scratch registers used as below: + * + * 0x71410: + * -------- + * Bits 31-16 - EID Firmware identifier 0xE1DF + * Bits 15-00 - Tell what data is present. + * Here are bits for what we are using know: + * Bit 0 - Panel id + * Bit 1 - List of ports for which displays are attached + * Bit 2 - Memory reservation + * If any of the above bits is set that mean data is followed + * in the next registers. + * + * 0x71414: + * -------- + * Bits 07-00 - Panel Id + * Bits 11-08 - Port list + * Information for Port list: If any of the bit is set means, + * a display is attached to that port as follows: + * Bit 08 - CRT + * Bit 09 - DVOA/Internal LVDS + * Bit 10 - DVOB/RGBA + * Bit 11 - DVOC + * + * 0x71418: + * -------- + * Bits 15-00 - Reserved Memory value in number of 4k size pages + */ + mmio = context->device_context.virt_mmadr; + control_reg = OS_READ32(OS_MMIO(mmio) + 0x71410); + *value = 0; + + switch(id) { + case IGD_PARAM_PANEL_ID: + /* + * Check for Embedded firmware + */ + if ((control_reg>>16) != 0xE1DF) { + OS_DEBUG("No Embedded vBIOS found"); + OS_TRACE_EXIT; + return -IGD_ERROR_INVAL; + } + + /* + * The panel id bit must be set in the control register + * to indicate valid panel (config) ID value. + */ + if (control_reg & 0x1) { + *value = OS_READ32(OS_MMIO(mmio) + 0x71414) & 0xFF; + if(!(*value)) { + /* we cannot allow for config id = 0 */ + ret = -IGD_ERROR_INVAL; + } + } else { + OS_DEBUG("Panel ID read failed: Incorrect Operation"); + ret = -IGD_ERROR_INVAL; + } + break; + case IGD_PARAM_MEM_RESERVATION: + /* + * Check for Embedded firmware + */ + if ((control_reg>>16) != 0xE1DF) { + OS_DEBUG("No Embedded vBIOS found"); + OS_TRACE_EXIT; + return -IGD_ERROR_INVAL; + } + + /* + * The mem reservation bit must be set in the control register + * to indicate valid mem reservation value. + */ + if (control_reg & 0x4) { + *value = (OS_READ32(OS_MMIO(mmio) + 0x71418) & 0xFFFF); + } else { + OS_DEBUG("Mem Reservation read failed: Incorrect Operation"); + ret = -IGD_ERROR_INVAL; + } + break; + default: + ret = -IGD_ERROR_INVAL; + break; + } + + OS_TRACE_EXIT; + return ret; +} + +/*! + * + * @param context + * + * @return void + */ +void full_shutdown_tnc(igd_context_t *context) +{ + platform_context_tnc_t *platform_context = + (platform_context_tnc_t *)context->platform_context; + + OS_TRACE_ENTER; + + /* unmap registers */ + if(context->device_context.virt_mmadr) { + OS_DEBUG("Unmapping Gfx registers and GTT Table..."); + OS_UNMAP_IO_FROM_MEM((void *)context->device_context.virt_mmadr, + TNC_D2_MMIO_SIZE); + OS_UNMAP_IO_FROM_MEM((void *)context->device_context.virt_mmadr_sdvo, + TNC_D3_MMIO_SIZE); + OS_UNMAP_IO_FROM_MEM((void *)context->device_context.virt_gpio_bar, 64); + OS_UNMAP_IO_FROM_MEM((void *)context->device_context.virt_gttadr, + context->device_context.gtt_size * 4); + } + + if (platform_context) { + OS_PCI_FREE_DEVICE(platform_context->pcidev0); + OS_PCI_FREE_DEVICE(platform_context->pcidev1); + OS_PCI_FREE_DEVICE(platform_context->bridgedev); + if (platform_context->lpc_dev) { + OS_PCI_FREE_DEVICE(platform_context->lpc_dev); + } + } + OS_TRACE_EXIT; +} + +/*! + * Program the GTT. + * + * @param context + * + * @return gtt_init_ret_code + * @return 0 + */ +int gtt_init_tnc(igd_context_t *context) +{ + /* Program the GTT. + * The GTT is programmed as follows when NOT using A000 for storing + * Dynamic Data: + * Generic case 256MB RAM with + * 128MB Aperture and + * 8MB Stolen memory + * Example + * -------------------- -------------------- + * ---------- Top of RAM (TR) 256MB + * | GTT | + * S M | | + * t e |--------| TR-sizeof(GTT) 256MB-128KB + * o m |Scrch pg| 4KB for scratch page + * o o |--------| 256MB-132KB + * e r | | + * n y | Video | + * | Mem | + * |--------| TR-sizeof(stolen_mem) 256MB-8MB + * | | + * | System | + * | Mem | + * | | + * ---------- 00000000 0 + * + */ + os_pci_dev_t vga_dev; + unsigned long pci_read_long; + platform_context_tnc_t *platform_context; + int gtt_init_ret_code = 0; + unsigned long phys_stolen_mem, phys_page_table, page_table_entry; + unsigned char *mmio, *virt_gttadr; + + OS_TRACE_ENTER; + + platform_context = (platform_context_tnc_t *)context->platform_context; + vga_dev = platform_context->pcidev0; + mmio = context->device_context.virt_mmadr; + virt_gttadr = context->device_context.virt_gttadr; + + /* Enable the PCI Device */ + gtt_init_ret_code = OS_ENABLE_PCI(vga_dev); + if(gtt_init_ret_code) { + return gtt_init_ret_code; + } + + /* Get Stolen Memory Base Address */ + OS_PCI_READ_CONFIG_32(vga_dev, TNC_PCI_BSM, &pci_read_long); + context->device_context.reserved_mem_base_addr = + pci_read_long & 0xFFF00000; + + /* Physical address of the beginning of video memory */ + phys_stolen_mem = context->device_context.reserved_mem_base_addr; + + /* Physical address of the beginning of the page table. + * This is at the end of memory - + * size of the gtt((aperture_size/bytes-per-page)*bytes-per-entry) - + * the scratch page. */ + phys_page_table = phys_stolen_mem + + (context->device_context.reserved_mem * 4096) + 4096; + + /* Set the Base of the GTT page table so each entry can be set. + * Also enable the GTT */ + OS_WRITE32(phys_page_table|1, OS_MMIO(mmio) + PGTBL_CTL); + + OS_WRITE32(context->device_context.reserved_mem, OS_MMIO(mmio) + 0x71418); + + /* Program the GTT */ + for(page_table_entry = 0; + page_table_entry < context->device_context.reserved_mem; + page_table_entry++) { + + /* Enable */ + OS_WRITE32(phys_stolen_mem|1, virt_gttadr + (page_table_entry*4)); + phys_stolen_mem += 4096; + } + + /* Program the remainder of the GTT to the scratch page. */ + for(page_table_entry = context->device_context.reserved_mem; + page_table_entry < (context->device_context.gtt_size); + page_table_entry++) { + /* Enable */ + OS_WRITE32((phys_page_table - 4096) | 1, + virt_gttadr + (page_table_entry*4)); + } + + OS_TRACE_EXIT; + + return 0; +} diff --git a/drivers/gpu/drm/emgd/emgd/core/init/tnc/micro_init_tnc.c b/drivers/gpu/drm/emgd/emgd/core/init/tnc/micro_init_tnc.c new file mode 100644 index 0000000..4fef4f4 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/core/init/tnc/micro_init_tnc.c @@ -0,0 +1,627 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: micro_init_tnc.c + * $Revision: 1.12 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.init + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "../cmn/init_dispatch.h" + +/*! + * @addtogroup core_group + * @{ + */ + +#ifdef CONFIG_TNC + +extern unsigned char io_mapped; +extern unsigned short io_base; + +/* For dev2 [0:2:0] */ +extern unsigned char io_mapped_lvds; +extern unsigned short io_base_lvds; + +/* For dev3 [0:3:0] */ +extern unsigned char io_mapped_sdvo; +extern unsigned short io_base_sdvo; + +/* For dev31 [0:31:0] */ +extern unsigned char io_mapped_lpc; +extern unsigned short io_base_lpc; + +extern int full_config_tnc(igd_context_t *context, + init_dispatch_t *dispatch); +extern int get_revision_id_tnc(igd_context_t *context, os_pci_dev_t vga_dev); +extern int full_get_param_tnc(igd_context_t *context, unsigned long id, + unsigned long *value); +extern void full_shutdown_tnc(igd_context_t *context); + +static int query_tnc(igd_context_t *context,init_dispatch_t *dispatch, + os_pci_dev_t vga_dev, unsigned int *bus, unsigned int *slot, + unsigned int *func); +static int config_tnc(igd_context_t *context, + init_dispatch_t *dispatch); +static int set_param_tnc(igd_context_t *context, unsigned long id, + unsigned long value); +static int get_param_tnc(igd_context_t *context, unsigned long id, + unsigned long *value); +static void shutdown_tnc(igd_context_t *context); + +/* Helper Functions */ +static int query_sch_message(unsigned long reg, unsigned long* value); +static int dump_fuse_values(void); + +static platform_context_tnc_t platform_context_tnc; + +init_dispatch_t init_dispatch_tnc = { + "Intel Tunnel Creek Processor", + "TC", + "lvds", + query_tnc, + config_tnc, + set_param_tnc, + get_param_tnc, + shutdown_tnc +}; + +#define SKU_NO 3 +#define RATIO_NO 8 +/* + * Tunnel Creek GFX frequencies + * The gfx clock frequencies depends on the board SKU and ratio + * The table of frequencies can be found in Tunnel Creek EAS + * Chapter: Clocks and Reset Unit + */ +static unsigned short tnc_gfx_freq_list[RATIO_NO][SKU_NO] = +{ + /* rows represent the gfx clock ratio, + * columns the sku */ + + /* sku_100 sku_100L sku_83 */ + {200, 100, 166}, /*1:1*/ + {266, 133, 222}, /*4:3*/ + {320, 160, 266}, /*8:5*/ + {400, 200, 333}, /*2:1 DEFAULT*/ + {0, 0, 0 }, /*16:7 RSVD*/ + {533, 266, 444}, /*8:3*/ + {640, 320, 553}, /*16:5*/ + {800, 400, 666} /*4:1 RSVD*/ +}; + +static unsigned short tnc_core_freq_list[SKU_NO] = +{ +/* sku_100 sku_100L sku_83 */ + 200, 100, 166 +}; + +/* MCR define */ +#define READ_FUS_EFF0 0xD08106F0 +#define READ_FUS_EFF1 0xD08107F0 +#define READ_FUS_EFF2 0xD08108F0 +#define READ_FUS_EFF3 0xD08109F0 +#define READ_FUS_EFF4 0xD0810AF0 +#define READ_FUS_EFF5 0xD0810BF0 + +/*! + * Helper function to query MCR registers + * @param reg + * @param value + * + * @return -IGD_ERROR_INVAL on error + * @return 0 on success + */ +static int query_sch_message(unsigned long reg, unsigned long* value){ + + platform_context_tnc_t *platform_context = &platform_context_tnc; + + /* Send the opcode into the MCR */ + if(OS_PCI_WRITE_CONFIG_32(platform_context->bridgedev, + 0xD0, reg)){ + OS_ERROR_EXIT("Writing into the MCR Failed"); + return -IGD_ERROR_INVAL; + } + + if(OS_PCI_READ_CONFIG_32(platform_context->bridgedev, + 0xD4, value)) { + + OS_ERROR_EXIT("Writing to MDR Failed"); + return -IGD_ERROR_INVAL; + } + + return 0; +} + +/*! + * + * @param context + * @param dispatch + * @param vga_dev + * @param bus + * @param slot + * @param func + * + * @return -IGD_ERROR_NODEV on failure + * @return 0 on success + */ +static int query_tnc( + igd_context_t *context, + init_dispatch_t *dispatch, + os_pci_dev_t vga_dev, + unsigned int *bus, + unsigned int *slot, + unsigned int *func) +{ + platform_context_tnc_t *platform_context = &platform_context_tnc; + unsigned short bridge_id = PCI_DEVICE_ID_BRIDGE_TNC; + + OS_TRACE_ENTER; + + platform_context->did = context->device_context.did; + + /* So we don't have to pollute our function tables with multiple + * entries for every variant of TNC, update the device ID if one + * of the other SKUs is found + */ + context->device_context.did = PCI_DEVICE_ID_VGA_TNC; + + context->platform_context = (void *)&platform_context_tnc; + + OS_PTHREAD_MUTEX_INIT(&platform_context_tnc.flip_mutex, NULL); + + /* find and store the bridge dev since we will be using it a lot + * in the init modules */ + platform_context->bridgedev = OS_PCI_FIND_DEVICE( + PCI_VENDOR_ID_INTEL, + bridge_id, + 0xFFFF, /* Scan the whole PCI bus */ + 0, + 0, + (os_pci_dev_t)0); + /* + * Current specs indicate that tnc has only one PCI function. + * If this changes then we need to make sure we have func 0 + * here as in previous chips. + */ + platform_context->pcidev0 = vga_dev; + + /* find device 3 */ + platform_context->pcidev1 = OS_PCI_FIND_DEVICE(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_SDVO_TNC, + 0, + 3, + 0, + (os_pci_dev_t)0); + + /* Set to NULL, so full_shutdown_tnc() knows whether it was initialized: */ + platform_context->lpc_dev = NULL; + + /* + * finds the bus, device, func to be returned. Do this for D2:F0 only. + * the OS does not need to know the existence of D3:F0 + */ + OS_PCI_GET_SLOT_ADDRESS(vga_dev, bus, slot, func); + + OPT_MICRO_CALL(get_revision_id_tnc(context, vga_dev)); + + /* + * Read BSM. + * This must be in query so it is available early for the vBIOS. + */ + if(OS_PCI_READ_CONFIG_32(vga_dev, + TNC_PCI_BSM, &context->device_context.fb_adr)) { + OS_ERROR_EXIT("Reading BSM"); + return -IGD_ERROR_NODEV; + } + context->device_context.fb_adr &= 0xFFFFF000; + + OS_DEBUG("BSM (High)@: 0x%lx, (Low) 0x%4lx", + (context->device_context.fb_adr >> 16), context->device_context.fb_adr); + + /* + * Read IO Base. + * This must be in query so it is available early for the vBIOS. + */ + if(OS_PCI_READ_CONFIG_16(vga_dev, TNC_PCI_IOBAR, &io_base)) { + OS_ERROR_EXIT("Reading IO Base"); + return -IGD_ERROR_NODEV; + } + + /* Base Address is defined in Bits 15:3*/ + io_base_lvds = io_base &= 0xfff8; + OS_DEBUG("io @: 0x%x", io_base); + + /* Gen4 is always io_mapped */ + io_mapped_lvds = io_mapped = 1; + + /* Set dev3 iobase. */ + if(OS_PCI_READ_CONFIG_16((os_pci_dev_t)platform_context->pcidev1, + TNC_PCI_IOBAR, &io_base_sdvo)) { + + OS_ERROR_EXIT("Reading SDVO IO Base"); + return -IGD_ERROR_NODEV; + } + + /* Base Address is defined in Bits 15:3*/ + io_base_sdvo &= 0xfff8; + + io_mapped_sdvo = 1; + OS_DEBUG("sdvo io @: 0x%x", io_base_sdvo); + + /* --------------------------------------------------- + * Initialize Device 31 : LPC Interface + * --------------------------------------------------*/ + /* + * Map the LPC Interface Configuration [D31:F0]GPIO_BAR. + * The TNC LVDS pins are connected to GPIO pins, + * accessible using LPC Interface GPIO_BAR. These registers + * will later be used to "bit bash" the LVDS DDC signals + * SDVO does not need these registers. + * VBIOS may need access to these registers + */ + + platform_context->lpc_dev = OS_PCI_FIND_DEVICE(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_LPC_TNC, + 0, + 31, /* LPC[D31:F0] */ + 0, + (os_pci_dev_t)0); + + if(!platform_context->lpc_dev){ + /* + * We could not detect the LPC interface in the PCI Bus. This will + * be a problem. Sound the alarm, return with NO ERROR so that we do + * not go and map the GPIO_BAR + */ + OS_ERROR_EXIT("Reading GPIO BAR"); + return 0; + } + + /* Set dev31 iobase */ + + /* Do not enable LPC device as System BIOS owns and does this */ + + /* read the GPIO BAR (OFFSET 44:47) */ + if(OS_PCI_READ_CONFIG_16(platform_context->lpc_dev, + TNC_PCI_GBA, &io_base_lpc)) { + OS_ERROR_EXIT("Reading LPC GPIO BAR"); + /* We cannot read the GPIO BAR. It is a problem but we can go on with init + * return with NO ERROR*/ + return 0; + } + + io_base_lpc &= 0xffc0; + + io_mapped_lpc = 1; + OS_DEBUG("lpc io @: 0x%x", io_base_lpc); + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param context + * @param dispatch + * + * @return -IGD_ERROR_NODEV on failure + * @return 0 on success + */ +static int config_tnc(igd_context_t *context, + init_dispatch_t *dispatch) +{ + unsigned long freq[2]; +#ifndef CONFIG_MICRO + unsigned int lp_ctrl_reg; + unsigned int hp_ctrl_reg; + unsigned int ved_cg_dis_reg; +#endif + + OS_TRACE_ENTER; + + OPT_MICRO_CALL(full_config_tnc(context, dispatch)); + + /* Get graphics and core frequency param if it exists */ + if(!get_param_tnc(context, IGD_PARAM_GFX_FREQ, + freq)) { + context->device_context.gfx_freq = (unsigned short)freq[0]; + context->device_context.core_freq = (unsigned short)freq[1]; + } + + /* + * FIXME: + * Coreclk register above is used to determine some clocking information + * there is also a fuse to limit the dclk. More research needed. + */ + /* From KT: TNC LVDS min and max dot clocks are 19.75 MHz to 79.5 MHz, + * TNC SDVO min and max dot clocks are 25 MHz to 165 MHz */ + context->device_context.max_dclk = 79500; /* in KHz */ + +#ifndef CONFIG_MICRO + /* This breaks VBIOS LVDS display. If this is truly a workaround for + * system BIOS then we need to understand what the system BIOS is going + * to do and make sure it doesn't re-break VBIOS. The hp_ctrl_reg write + * is the write that actually breaks LVDS display. Tested with BIOS34 + * which has the P-Unit workaround and LVDS still works. + */ + + /* This is just a workaround. + * GVD.G_LP_Control register is set to default mode for BIT0~BIT3. + * GVD.H_HP Control register's BIT1 is set 1. + * TODO: Removed this after this is fix in system BIOS. + */ + lp_ctrl_reg = OS_READ32(OS_MMIO(context->device_context.virt_mmadr) + 0x20f4); + lp_ctrl_reg |= BIT1; + lp_ctrl_reg &= ~(BIT2 | BIT3); + OS_WRITE32(lp_ctrl_reg, OS_MMIO(context->device_context.virt_mmadr) + 0x20f4); + + hp_ctrl_reg = OS_READ32(OS_MMIO(context->device_context.virt_mmadr) + 0x20f8); + hp_ctrl_reg |= BIT1; + OS_WRITE32(hp_ctrl_reg, OS_MMIO(context->device_context.virt_mmadr) + 0x20f8); + + /* This is just a workaround. + * GVD.VED_CG_DIS register is set to disable clock gating for BIT16, BIT0~BIT8. + * Tested with Punit B0_500309_CFG2 and Punit C0_060510_CFG2 in BIOS39 and + * BIOS41 or above. + */ + ved_cg_dis_reg = OS_READ32(OS_MMIO(context->device_context.virt_mmadr) + 0x2064); + ved_cg_dis_reg |= (BIT16 | BIT8 | 0xFF); + OS_WRITE32(ved_cg_dis_reg, OS_MMIO(context->device_context.virt_mmadr) + 0x2064); + + /* read out the fuse values */ + dump_fuse_values( ); +#endif + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param context + * @param id + * @param value + * + * @return -IGD_ERROR_INVAL on failure + * @return 0 on success + */ +static int get_param_tnc(igd_context_t *context, unsigned long id, + unsigned long *value) +{ +#define FB_SKU_MASK (BIT12|BIT13|BIT14) +#define FB_SKU_SHIFT 12 +#define FB_GFX_CLOCK_DIVIDE_MASK (BIT20|BIT21|BIT22) +#define FB_GFX_CLOCK_DIVIDE_SHIFT 20 + + int ret = 0; + unsigned long control_reg; + unsigned short sku; + unsigned short ratio; + + OS_TRACE_ENTER; + + OS_DEBUG("ID: 0x%lx", id); + + /* Scratch registers used as below: + * + * 0x71410: + * -------- + * Bits 31-16 - EID Firmware identifier 0xE1DF + * Bits 15-00 - Tell what data is present. + * Here are bits for what we are using know: + * Bit 0 - Panel id + * Bit 1 - List of ports for which displays are attached + * Bit 2 - Memory reservation + * If any of the above bits is set that mean data is followed + * in the next registers. + * + * 0x71414: + * -------- + * Bits 07-00 - Panel Id + * Bits 11-08 - Port list + * Information for Port list: If any of the bit is set means, + * a display is attached to that port as follows: + * Bit 08 - CRT + * Bit 09 - DVOA/Internal LVDS + * Bit 10 - DVOB/RGBA + * Bit 11 - DVOC + * + * 0x71418: + * -------- + * Bits 15-00 - Reserved Memory value in number of 4k size pages + */ + *value = 0; + + switch(id) { + case IGD_PARAM_PORT_LIST: + + control_reg = OS_READ32(OS_MMIO(context->device_context.virt_mmadr) + + 0x71410); + + /* + * Verify that the Embedded Firware is present. + */ + if ((control_reg>>16) != 0xE1DF) { + OS_DEBUG("Exit No Embedded vBIOS found"); + OS_TRACE_EXIT; + return -IGD_ERROR_INVAL; + } + + /* + * If the port list bit is set in control register, + * read the port list + */ + if (control_reg & 0x2) { + unsigned char temp; + int i = 0; + + temp = (unsigned char)((OS_READ32(OS_MMIO(context->device_context.virt_mmadr) + 0x71414)>>8) & 0xFF); + OS_DEBUG("Connected Port Bits: 0x%x", temp); + + /* + * The meanings of bits in temp were dictated by VBIOS + * and should not change due to backward compatibility + * with Legacy VBIOS + */ + if (temp & 0x02) { + /* Internal LVDS port */ + value[i++] = 4; + } + if (temp & 0x04) { + /* DVOB Port */ + value[i++] = 2; + } + } else { + OS_DEBUG("Port List read failed: Incorrect Operation"); + ret = -IGD_ERROR_INVAL; + } + break; + case IGD_PARAM_GFX_FREQ: + + /* Read the fuse value */ + if(query_sch_message(READ_FUS_EFF3, &control_reg)){ + OS_ERROR("Cannot read GFX clock"); + } + OS_DEBUG("SKU [reg 0x%x] value = 0x%lx", READ_FUS_EFF3, control_reg); + + /* + * Sku and Ratio bits determine the gfx clock speed + * sku - 0:sku_100 1:sku_100L 2:sku_83 + * ratio - 0-1:1 1-4:3 2-8:5 3-2:1 4-16:7(rsvd) 5-8:3 6-16:5 7:4:1(rsvd) + */ + sku = (unsigned short)((control_reg & FB_SKU_MASK) >> FB_SKU_SHIFT) & 0x3; + ratio = (unsigned short)((control_reg & FB_GFX_CLOCK_DIVIDE_MASK) >> FB_GFX_CLOCK_DIVIDE_SHIFT) & 0x7; + + OS_DEBUG("sku = 0x%x Ratio = 0x%x", sku, ratio); + + if(sku < SKU_NO && ratio < RATIO_NO){ + /* get the graphics clock speed from the sku-ratio array */ + value[0] = tnc_gfx_freq_list[ratio][sku]; + value[1] = tnc_core_freq_list[sku]; + } else { + OS_ERROR("tnc_gfx_freq_list ARRAY OUT OF RANGE"); + /* set to the lowest default value */ + value[0] = 333; + value[1] = 166; + } + + OS_DEBUG("TNC GFX core frequency = %lu MHz", value[0]); + OS_DEBUG("TNC Core clock frequency = %lu MHz", value[1]); + + break; + + default: + /* If the param is not found here then it may only be in the + * full version. + */ + OPT_MICRO_CALL_RET(ret, full_get_param_tnc(context, id, value)); + break; + } + + OS_TRACE_EXIT; + return ret; +} + +/*! + * + * @param context + * @param id + * @param value + * + * @return -IGD_ERROR_INVAL + */ +static int set_param_tnc(igd_context_t *context, unsigned long id, + unsigned long value) +{ + return 0; +} + +/*! + * Functions reads all the fuse values and dumps out the value + * @return -IGD_ERROR_INVAL + */ +#ifndef CONFIG_MICRO +static int dump_fuse_values(void) +{ + unsigned long value = 0; + + if(query_sch_message(READ_FUS_EFF0, &value)){ + OS_ERROR_EXIT("Reading Fuse Value Failed"); + } + OS_DEBUG("READ_FUS_EFF0 [%lx]", value); + + if(query_sch_message(READ_FUS_EFF1, &value)){ + OS_ERROR_EXIT("Reading Fuse Value Failed"); + } + OS_DEBUG("READ_FUS_EFF1 [%lx]", value); + + if(query_sch_message(READ_FUS_EFF2, &value)){ + OS_ERROR_EXIT("Reading Fuse Value Failed"); + } + OS_DEBUG("READ_FUS_EFF2 [%lx]", value); + + if(query_sch_message(READ_FUS_EFF3, &value)){ + OS_ERROR_EXIT("Reading Fuse Value Failed"); + } + OS_DEBUG("READ_FUS_EFF3 [%lx]", value); + + if(query_sch_message(READ_FUS_EFF4, &value)){ + OS_ERROR_EXIT("Reading Fuse Value Failed"); + } + OS_DEBUG("READ_FUS_EFF4 [%lx]", value); + + if(query_sch_message(READ_FUS_EFF5, &value)){ + OS_ERROR_EXIT("Reading Fuse Value Failed"); + } + OS_DEBUG("READ_FUS_EFF5 [%lx]", value); + + return 0; +} +#endif +/*! + * + * @param context + * + * @return void + */ +static void shutdown_tnc(igd_context_t *context) +{ + OPT_MICRO_VOID_CALL(full_shutdown_tnc(context)); +} + +#endif diff --git a/drivers/gpu/drm/emgd/emgd/display/dsp/cmn/dsp.c b/drivers/gpu/drm/emgd/emgd/display/dsp/cmn/dsp.c new file mode 100755 index 0000000..ae46d40 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/dsp/cmn/dsp.c @@ -0,0 +1,2350 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: dsp.c + * $Revision: 1.15 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * This file contains all the necessary functions for display resource + * manager. This module abstracts all hardware resources and manages them. + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.dsp + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dsp_dispatch.h" + +/*! + * @addtogroup display_group + * @{ + */ + +static dispatch_table_t dsp_dispatch_list[] = { + +#ifdef CONFIG_PLB + {PCI_DEVICE_ID_VGA_PLB, &dsp_dispatch_plb}, +#endif +#ifdef CONFIG_TNC + {PCI_DEVICE_ID_VGA_TNC, &dsp_dispatch_tnc}, +#endif + {0, NULL} +}; + +static int dsp_full_init(igd_context_t *context); +static int dsp_init_cursor(igd_context_t *context, igd_cursor_t *cursor); +static igd_display_port_t *dsp_get_next_port(igd_context_t *context, + igd_display_port_t *last, int reverse); + +/* + * This simple structure wraps the display configuration list so that + * it is easier to manipulate. + * count is the current number of items in the list. + * size is the maximum number of items the list can hold + * dc_list is a pointer to the array of DC's + */ +typedef struct _dsp_dc_list_t { + int count; + int size; + unsigned long *dc_list; +} dsp_dc_list_t; + +typedef struct _dsp_context { + + dsp_dispatch_t *dispatch; + igd_context_t *context; + unsigned long num_dsp_planes; + unsigned long num_dsp_pipes; + unsigned long display_flags; + + unsigned long current_dc; + unsigned long fw_dc; /* The DC programmed by the EFI or VBIOS */ + igd_display_context_t display_list[MAX_DISPLAYS]; + dsp_dc_list_t dsp_dc_list; + /* holds pointer to port based on port numbers (1 based not zero based) */ + igd_display_port_t *port_list[IGD_MAX_PORTS + 1]; + + /* holds pointer to display context based on port numbers + * (1 based not zero based) */ + igd_display_context_t *display_ptr_list[IGD_MAX_PORTS + 1]; +} dsp_context_t; + +static dsp_context_t dsp_context; + + +#ifndef CONFIG_MICRO +#define FREE_PIPE(x) free_pipe(x) + + +/* + * This macro is used to check the validity of a clone/extended DC. It + * makes sure that the ports are capable of using both pipes. p1 and + * p2 need to be on unique pipes, if they both require the same pipe, + * this check returns false. + * + * Note that this is only enabled for the driver since it does add some + * code and currently we have no hardware that could be configured like + * this. + */ +#define DSP_PIPE_OK(p1, p2) ( \ + ((p1->port_features & IGD_PORT_USE_PIPE_MASK) | \ + (p2->port_features & IGD_PORT_USE_PIPE_MASK)) == \ + (IGD_PORT_USE_PIPEA | IGD_PORT_USE_PIPEB)) + +#else +#define FREE_PIPE(x) +#define DSP_PIPE_OK(p1, p2) 1 +#endif + +/* + * Static framebuffer structures used for all chipsets. + */ +igd_framebuffer_info_t fb_info_cmn[2] = { + {0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0} +}; + +/* Design Notes: + * + * 1. The heart of display resources is the display configuration list. + * During initialization, the list display configuration list is + * created with all valid pipe/plane/port combinations. Allocations + * are limited to combinations specified on the list. + * + * 2. Two display handles are maintaine corresponding to the two + * display pipes. To support hardware with more than two pipes, + * the DC value will need to expand beyond the current 32 bit value + * and the number of display handles increased appropriately. + */ + +#ifndef CONFIG_MICRO /* This is N/A for VBIOS */ + +/*! + * Re-construct the DC ( Display Configuration ) that the Gfx hardware + * was programmed by Video BIOS or EFI Video Driver. + * + * TODO: This function does not handle three-display scenario. + * + * @param context + * + * @return fw_dc + */ +static unsigned long dsp_get_fw_dc(igd_context_t *context) +{ + igd_display_port_t *p = NULL; + int pipeb_allocated = 0, pipea_allocated = 0; + int port1 = 0, port2 = 0, mode = 0; + int port_allocated = 0; + unsigned long port_value; + unsigned long fw_dc = 0; + unsigned char *mmio = OS_MMIO(context->device_context.virt_mmadr); + + OS_TRACE_ENTER; + + /* Go through the port table */ + while ((p = dsp_get_next_port(context, p, 0)) != NULL) { + + port_value = OS_READ32(mmio + p->port_reg); + if(port_value & BIT(31)) { /* is the port ON? */ + + if(port1) { + port2 = p->port_number; + } else { + port1 = p->port_number; + } + port_allocated++; + + if (port_value & BIT(30)) { + pipeb_allocated++; + } else { + pipea_allocated++; + } + } + } /* while */ + + if( pipea_allocated > 1 || pipeb_allocated > 1) { + /* Twin Mode */ + OS_DEBUG("Twin mode"); + mode = IGD_DISPLAY_CONFIG_TWIN; + + /* Re-construct the DC back */ + fw_dc = (port2 & 0x0F)<< 8 | (port1 & 0x0F)<< 4 | (mode & 0x0F); + + OS_DEBUG("fw_dc in Twin Mode: 0x%08lx", fw_dc); + + /* Check the fw_dc is in the list */ + if(!dsp_valid_dc(fw_dc, 0)) { + OS_DEBUG("check the fw_dc again in the DC list"); + + /* If the assumed dc doesn't match reverse the order and + * and check again + */ + fw_dc = (port1 & 0x0F)<< 8 | (port2 & 0x0F)<< 4 | (mode & 0x0F); + OS_DEBUG("hw_dc: 0x%08lx", fw_dc); + + if(!dsp_valid_dc(fw_dc, 0)) { + OS_DEBUG("FW DC doesnt match dc list!!"); + fw_dc = 0L; + } + } + + } else if(port_allocated == 1) { + + OS_DEBUG("Single Configuration"); + mode = IGD_DISPLAY_CONFIG_SINGLE; + /* Single Mode */ + fw_dc = (port2 & 0x0F)<< 20 |(port1 & 0x0F)<<4 |(mode & 0x0F); + + OS_DEBUG("fw_dc in Single Config = 0x%08lx", fw_dc); + + /* Checking the assumed dc with the dc list */ + if(!dsp_valid_dc(fw_dc, 0)) { + OS_DEBUG("check again"); + + /* If the assumed dc doesn't match reverse the order and + * and check again + */ + fw_dc = (port1 & 0x0F)<< 20 |(port2 & 0x0F)<<4 |(mode & 0x0F); + if(!dsp_valid_dc(fw_dc, 0)) { + OS_DEBUG("FW DC doesnt match dc list!!!"); + fw_dc = 0L; + } + } + + } else { + + /* VBIOS does not support extended. So i'ts most + * likely clone. + */ + OS_DEBUG("Extended/Clone"); + mode = IGD_DISPLAY_CONFIG_CLONE; + + /* Re-construct the DC back */ + fw_dc = (port2 & 0x0F) << 20 | (port1 & 0x0F) << 4 | (mode & 0x0F); + + OS_DEBUG("fw_dc in Clone Mode:a 0x%08lx", fw_dc); + + /* Check the fw_dc is in the list */ + if(!dsp_valid_dc(fw_dc, 0)) { + OS_DEBUG("Check again. This time reverse primary and secondary"); + + /* if the assumed dc doesn't match reverse the order and + * check again + */ + fw_dc = (port1 & 0x0F) << 20 | (port2 & 0x0F) << 4 | (mode & 0x0F); + if(!dsp_valid_dc(fw_dc, 0)) { + OS_DEBUG("FW DC doesnot match dc list!!!"); + fw_dc = 0L; + } + } + } /* else */ + + OS_DEBUG("DC programmed by the firmware = 0x%08lx", fw_dc); + OS_TRACE_EXIT; + //*dc_list=¤t_dc; + return fw_dc; + +} /* end of dsp_get_fw_dc */ + +#endif /* ifndef CONFIG_MICRO */ + +/*! + * This function gets the next value in a plane, pipe, or port table. The + * caller provides a pointer to the last entry retrieved or NULL to get + * the first entry. + * + * @param list + * @param last + * @param reverse + * + * @return void + */ +static void *dsp_get_next(void **list, void *last, int reverse) + +{ + void **list_end = list; + void **list_start = list; + void **last_p = NULL; + int off = 1; + + while(*list_end) { + if(*list_end == last) { + last_p = list_end; + } + list_end++; + } + list_end--; + + if(reverse) { + list_start = list_end; + list_end = list; + off = -1; + } + if(!last) { + return *list_start; + } + if((last == *list_end) || !last_p) { + return NULL; + } + return last_p[off]; +} + +/*! + * This function allows the caller to loop through the (port | plane | pipe) + * table list and get each entry in turn. The call must provide a pointer + * to the last entry retrieved (or NULL to get the first port). + * + * These functions are called from many places, including some functions + * external to the DSP module. + * + * @param context pointer to the current driver context. + * @param last pointer to the last entry retrieved. + * @param reverse + * + * @return igd_display_port_t pointer to the next entry or NULL if no more ports available. + */ +static igd_display_port_t *dsp_get_next_port(igd_context_t *context, + igd_display_port_t *last, int reverse) +{ + /*OS_DEBUG("Entry, dsp_get_next_port");*/ + + return (igd_display_port_t *)dsp_get_next( + (void **)dsp_context.dispatch->ports, (void *)last, reverse); +} + +static igd_plane_t *dsp_get_next_plane(igd_context_t *context, + igd_plane_t *last, int reverse) +{ + OS_DEBUG("Entry, dsp_get_next_plane"); + + return (igd_plane_t *)dsp_get_next( + (void **)dsp_context.dispatch->planes, (void *)last, reverse); +} + +static igd_display_pipe_t *dsp_get_next_pipe(igd_context_t *context, + igd_display_pipe_t *last, int reverse) +{ + OS_DEBUG("Entry, dsp_get_next_pipe"); + + return (igd_display_pipe_t *)dsp_get_next( + (void **)dsp_context.dispatch->pipes, (void *)last, reverse); +} + +/*! + * Check the DC to see if it is in the list. + * + * Flags: + * IGD_DC_EXACT_MATCH + * IGD_DC_CLOSEST_MATCH + * + * Flags are currently ignored. + * + * @param dc + * @param flags + * + * @return DC + * @return 0 if no match + */ +unsigned long dsp_valid_dc(unsigned long dc, unsigned long flags) +{ + int i; + + for (i = 0; i < dsp_context.dsp_dc_list.count; i++) { + if (dc == dsp_context.dsp_dc_list.dc_list[i]) { + return dsp_context.dsp_dc_list.dc_list[i]; + } + } + + /* Need to define how a closest match is determined */ + + return 0; +} + +/*! + * Convert a DC value into to bitmasks, one for each pipe. + * + * @param dc + * @param pipe1 + * @param pipe2 + * + * @return void + */ +static void dsp_dc_to_masks(unsigned long dc, + unsigned char *pipe1, + unsigned char *pipe2) +{ + int i; + int pn; + + *pipe1 = 0; + *pipe2 = 0; + + for (i = 1; i < 8; i++) { + if ((pn = DC_PORT_NUMBER(dc, i)) > 0) { + if ((i < 5)) { + *pipe1 |= (1 << pn); + } else { + *pipe2 |= (1 << pn); + } + } + } +} + +/*! + * + * @param context + * @param port + * + * @return 1 if connected + * @return 0 if not connected + */ +int dsp_display_connected(igd_context_t *context, + igd_display_port_t *port) +{ + unsigned long port_list[IGD_MAX_PORTS]; + unsigned long connected_ports; + int ret; + pd_port_status_t port_status; + + /* Display detection - + * First, check if the VBIOS has provided the "connected_bits" + * information. If it has, then check if the passed in port is in + * the list. Of course, this is only valid in the driver, vBIOS + * can't check vBIOS bits. + * + * If there isn't any "connected_bits" info, then have the port + * driver try and detect the display. If the display is detected + * or if the port driver is incapabile of doing display detection, + * then return connected. + */ + OS_MEMSET(port_list, 0, sizeof(unsigned long) * IGD_MAX_PORTS); + connected_ports = 0; + if (igd_get_param((igd_driver_h)context, IGD_PARAM_PORT_LIST, + port_list) == 0) { + while ((connected_ports < IGD_MAX_PORTS) && + port_list[connected_ports]) { + if(port_list[connected_ports] == port->port_number) { + return 1; + } + connected_ports++; + } + return 0; + } + + /* No vBIOS info, so do runtime detection if possible. */ + if (port->pd_context == NULL) { + return 0; + } + + ret = port->pd_driver->pd_get_port_status(port->pd_context, &port_status); + if ((ret != PD_SUCCESS) || + (port_status.connected == PD_DISP_STATUS_DETACHED)) { + return 0; + } + + /* Port is connected (as far as we can tell) and OK to use */ + return 1; +} + +/*! + * Checks a given port to make sure it is ok to use it in a + * display configuration. Two things can make a port unusable. + * First it can be marked inuse, which means it isn't listed in + * the current port_order. + * Second, if display detect is enabled and no display is detected. + * + * @param context + * @param port + * @param display_detect + * + * @return 0 if not ok to use + * @return 1 if ok to use + */ +static int dsp_port_is_ok(igd_context_t *context, + igd_display_port_t *port, + int display_detect) +{ + /* + * The port->inuse value is used in two different ways. This is + * causing a conflict now. + * + * - It is set if the port doesn't show up in the port order. + * - It is set if the port is allocated by dsp_alloc() + * + * This is ok if this function is called prior to any dsp_alloc's + * + * Maybe what is really needed here is a check to see if the port + * shows up in the port order. + */ + + /* If it is inuse, then it isn't currently ok to use */ + if (port->inuse == 0x80) { + OS_DEBUG("port_ok? Port is marked unsable"); + return 0; + } + + /* Does port have a port driver? */ + if (port->pd_driver == NULL) { + OS_DEBUG("port %ld has no port driver", port->port_number); + return 0; + } + + /* If display detect, then check to make sure display is present */ + if (display_detect) { + return dsp_display_connected(context, port); + } + return 1; +} + +/*! + * Add a new DC to the end of the list. Checks to make sure there is + * space in the allocated list first. + * + * @param dc_list + * @param dc + * @param ext + * + * @return void + */ +void dsp_add_to_dc_list(dsp_dc_list_t *dc_list, unsigned long dc, + unsigned long ext) +{ + unsigned char pipe1, pipe2; + unsigned char p1, p2; + int d; + int ok = 1; + + /* Check for duplicate DC first */ + if ((dc_list->count != 0) && (dc != 0)) { + dsp_dc_to_masks(dc, &pipe1, &pipe2); + for (d = 0; d < dc_list->count; d++) { + /* build a bitmap of port used by DC under test */ + dsp_dc_to_masks(dc_list->dc_list[d], &p1, &p2); + + /* + * Compare the bitmaps. + * + * There are two bitmaps, one for each pipe. This is needed so + * 0x00500232 and 0x00200532 aren't flaged as duplicate. + */ + if ((pipe1 == p1) && (pipe2 == p2)) { + ok = 0; /* duplicate */ + } + if ((pipe1 == p2) && (pipe2 == p1)) { + ok = 0; /* a pipe reversed duplicate DC */ + } + } + } + + if (ok) { + if (dc_list->count < dc_list->size) { + dc_list->dc_list[dc_list->count] = dc; + dc_list->count++; + } + if (ext && (dc_list->count < dc_list->size)) { + dc = (dc & 0xfffffff0) | 8; + dc_list->dc_list[dc_list->count] = dc; + dc_list->count++; + } + } +} + +/*! + * Given a port number, find which display context currently controls + * that port. + * + * @param port_number + * @param display + * @param port + * @param display_detect + * + * @return void + */ +static void dsp_get_display(unsigned short port_number, + igd_display_context_t **display, + igd_display_port_t **_port, + int display_detect) +{ + igd_display_port_t *port = NULL; + + if(_port) { + while ((port = dsp_get_next_port(dsp_context.context, port, 0))) { + if (port->port_number == port_number) { + *_port = port; + if (display_detect && + (dsp_display_connected(dsp_context.context, port) != 1)) { + OS_DEBUG("Usable but unattached port found"); + *_port = NULL; + } + break; + } + } + } + if(display) { + *display = dsp_context.display_ptr_list[port_number]; + } + return; +} + +/*! + * + * @param dc + * @param primary + * @param secondary + * + * @return void + */ +static void dsp_get_dc(unsigned long *dc, + igd_display_context_t **primary, + igd_display_context_t **secondary) +{ + /*OS_TRACE_ENTER;*/ + if(dc) { + *dc = dsp_context.current_dc; + } + if(primary) { + *primary = + dsp_context.display_ptr_list[ + IGD_DC_PRIMARY(dsp_context.current_dc)]; + } + if(secondary) { + *secondary = + dsp_context.display_ptr_list[ + IGD_DC_SECONDARY(dsp_context.current_dc)]; + } + /*OS_TRACE_EXIT;*/ +} + +/*! + * + * @param primary_display_plane + * @param secondary_display_plane + * @param primary_pipe + * @param secondary_pipe + * + * @return void + */ +static void dsp_get_planes_pipes(igd_plane_t **primary_display_plane, + igd_plane_t **secondary_display_plane, + igd_display_pipe_t **primary_pipe, + igd_display_pipe_t **secondary_pipe) +{ + igd_plane_t **plane; + igd_display_pipe_t **pipe; + int is_primary = 1; + + OS_TRACE_ENTER; + + if(!primary_display_plane || !secondary_display_plane || + !primary_pipe || !secondary_pipe) { + + OS_ERROR("Invalid parameters"); + } else { + + plane = dsp_context.dispatch->planes; + + while (*plane) { + if ((*plane)->plane_features & IGD_PLANE_DISPLAY) { + + if(is_primary) { + *primary_display_plane = *plane; + is_primary = 0; + } else { + *secondary_display_plane = *plane; + break; + } + } + plane++; + } + + pipe = dsp_context.dispatch->pipes; + is_primary = 1; + + while (*pipe) { + if(is_primary) { + *primary_pipe = *pipe; + is_primary = 0; + } else { + *secondary_pipe = *pipe; + break; + } + pipe++; + } + } + + OS_TRACE_EXIT; +} + +/*! + * Check port features of multiple ports to see if they can share a pipe. + * Ports that are passed in as NULL are not considered. There must be + * at least two ports. + * + * Sort the ports so that any port that must be pipe master is listed + * first. Return the sorted port order in a format that can be easily + * merged into a full DC value. + * + * @param m + * @param p1 + * @param p2 + * @param p3 + * + * @return 0 if error + * @return DC + */ +unsigned long dsp_shareable(igd_display_port_t *m, + igd_display_port_t *p1, + igd_display_port_t *p2, + igd_display_port_t *p3) +{ + unsigned long features; + unsigned long shareable; + unsigned long dc; + + if (m == NULL) { + /* Error checking */ + OS_ERROR("dsp_shareable: port pointer is NULL."); + return 0; + } + + if (p1 == NULL) { + dc = m->port_number; + return dc; + } + + /* + * OR all the port secondary port type bits together. + * If ANDing this with the primary port's feature bits changes + * the value, then all the ports are not shareable. + * + * This does assume that if port A can share with port B, + * then port B can share with port A. + */ + features = m->port_features & IGD_PORT_SHARE_MASK; + shareable = (p1->port_type & IGD_PORT_SHARE_MASK); + if (p2 != NULL) { + shareable |= (p2->port_type & IGD_PORT_SHARE_MASK); + if (p3 != NULL) { + shareable |= (p3->port_type & IGD_PORT_SHARE_MASK); + } + } + + /* make features a true/false type value */ + features = ((features & shareable) == shareable); + + /* + * This section re-arranges the order of the ports so that the + * port that needs to be the pipe master is always listed first. + * + * FIXME: + * This doesn't support the case where more than one port must + * be pipe master. + * + * FIXME: + * Not sure if this is handling CLOCK_MASTER correctly. CLOCK_MASTER + * can share a pipe with other ports but wants the PLL to be programmed + * with its clock. + */ + if (features) { + dc = m->port_number; + if (p1->pd_flags & PD_FLAG_PIPE_MASTER) { + dc = (dc << 4) | p1->port_number; + } else if (p1->pd_flags & PD_FLAG_CLOCK_MASTER) { + dc = (dc << 4) | p1->port_number; + } else { + dc = dc | (p1->port_number << 4); + } + if (p2 != NULL) { + if (p2->pd_flags & PD_FLAG_PIPE_MASTER) { + dc = (dc << 4) | p2->port_number; + } else if (p2->pd_flags & PD_FLAG_CLOCK_MASTER) { + dc = (dc << 4) | p2->port_number; + } else { + dc = dc | (p2->port_number << 8); + } + } + if (p3 != NULL) { + if (p3->pd_flags & PD_FLAG_PIPE_MASTER) { + dc = (dc << 4) | p3->port_number; + } else if (p3->pd_flags & PD_FLAG_CLOCK_MASTER) { + dc = (dc << 4) | p3->port_number; + } else { + dc = dc | (p3->port_number << 12); + } + } + return dc; + } else { + return 0; + } +} + +/*! + * Given a group of ports and some basic infomation like how many pipes + * are available, construct a set of valid display configurations. The + * number of ports passed in is variable so that if a port doesn't exist + * it should be passed in as a NULL. At least one port must be passed + * in. Also, NULL ports should be at the end of the list. Don't pass in + * NULL, NULL, NULL, vaid_port because it will break this function. + * + * The flags value is used to enabled dual pipe support and extended + * support. If neither are set, only TWIN configurations will be returned. + * + * @param m + * @param t1 + * @param t2 + * @param t3 + * @param flags + * @param dc_list + * + * @return void + */ +void dsp_build_display_configs(igd_display_port_t *m, + igd_display_port_t *t1, + igd_display_port_t *t2, + igd_display_port_t *t3, + unsigned long flags, dsp_dc_list_t *dc_list) +{ + + unsigned long dc, dc2; + + /* If two pipes, do all clone/extended configurations first */ + if ((flags & 0x0f) > 1) { + /* first two ports on different pipes, all remaining ports on pipe 2 */ + /* can port 0 share with port1 and port 2 */ + if ((dc = dsp_shareable(t1, t2, t3, NULL)) && DSP_PIPE_OK(m, t1)) { + dc = (dc << 20) | 2 | ((m->port_number & 0x0f) << 4); + dsp_add_to_dc_list(dc_list, dc, (flags & IGD_PLANE_DIH)); + } + /* first two ports on different pipes, all remaining ports on pipe 1 */ + if ((dc = dsp_shareable(m, t2, t3, NULL)) && DSP_PIPE_OK(m, t1)) { + dc = (dc << 4) | 2 | ((t1->port_number & 0x0f) << 20); + dsp_add_to_dc_list(dc_list, dc, (flags & IGD_PLANE_DIH)); + } + + /* first two ports on different pipes, remianing ports split */ + if ((dc = dsp_shareable(m, t2, NULL, NULL)) && + (dc2 = dsp_shareable(t1, t3, NULL, NULL)) && + DSP_PIPE_OK(m, t1)) { + dc = (dc << 4) | 2 | (dc2 << 20); + dsp_add_to_dc_list(dc_list, dc, (flags & IGD_PLANE_DIH)); + } + + /* first two ports on different pipes, remianing ports split */ + if ((dc = dsp_shareable(m, t3, NULL, NULL)) && + (dc2 = dsp_shareable(t1, t2, NULL, NULL)) && + DSP_PIPE_OK(m, t1)) { + dc = (dc << 4) | 2 | (dc2 << 20); + dsp_add_to_dc_list(dc_list, dc, (flags & IGD_PLANE_DIH)); + } + } + + /* Twinned type configurations, all ports on first pipe */ + if ((dc = dsp_shareable(m, t1, t2, t3))) { + dc = (dc << 4) | 4; + dsp_add_to_dc_list(dc_list, dc, 0); + } +} + +/*! + * This routine puts the port table entries as per user (via IAL) mentioned + * port order & firmware settings. + * + * @param context + * @param port_order + * + * @return void + */ +void do_port_order(igd_context_t *context, unsigned long *port_order) +{ + igd_display_port_t **port_table; + igd_display_port_t *p; + unsigned long i, j, k, num_ports; + unsigned long num_ports1; + + /* Adjust port detect/allocation order with user/caller preference */ + port_table = dsp_context.dispatch->ports; + num_ports = 0; + while (port_table[num_ports]) { + /* Build a port number to port array */ + dsp_context.port_list[port_table[num_ports]->port_number] = + port_table[num_ports]; + num_ports++; + } + +#if 0 + OS_DEBUG("Initial port table = "); + for (i = 0; i < num_ports; i++) { + OS_DEBUG("\t%ld, inuse=%d", port_table[i]->port_number, + port_table[i]->inuse); + } +#endif + + num_ports1 = 0; + while ((num_ports1 < IGD_MAX_PORTS) && port_order[num_ports1]) { + num_ports1++; + } + + /* + * If port order is specified, then the ports that are not present in the + * port order list should not be allowed to be allocated. Since it is not + * possible to remove ports from port_table, mark ports that cannot be + * allocated as inuse with 0x80. Ports marked in-use by the display + * allocation function will set this to 0x01. This is used in the + * dsp_dc_init() function to detmine what ports are usable. + */ + if (num_ports1 != 0) { + for (i = 0; i < num_ports; i++) { + port_table[i]->inuse = 0x80; + } + } else { +#ifndef CONFIG_MICRO + /* Copying back the port order to the mode_context's port order */ + for (i = 0; i < num_ports; i++) { + port_order[i] = port_table[i]->port_number; + } +#endif + return; + } + + /* Arrange port_table list to match IAL provided port_order list. + * Dont forget to unmark its in-use flag to ensure it's allowed + * for usage. */ + k = 0; + for (i = 0; i < IGD_MAX_PORTS; i++) { + /* Find the port for given port number */ + for (j = k; j < num_ports; j++) { + if (port_table[j]->port_number == port_order[i]) { + port_table[j]->inuse = 0; + p = port_table[k]; + port_table[k] = port_table[j]; + port_table[j] = p; + k++; + break; + } + } + } + return; +} /* end do_port_order() */ + +/*! + * + * @param context + * @param config_info + * + * @return 0 + */ +static int dsp_get_config_info(igd_context_t *context, + igd_config_info_t *config_info) +{ + OS_ASSERT(context, "Null context", -IGD_ERROR_INVAL); + OS_ASSERT(config_info, "Null config_info", -IGD_ERROR_INVAL); + + config_info->num_dsp_planes = dsp_context.num_dsp_planes; + config_info->num_dsp_pipes = dsp_context.num_dsp_pipes; + config_info->fb_caps = dsp_context.dispatch->caps; + + return 0; +} + + +#if 0 +/*! + * Print out the DC list for debug purposes + * + * @param void + * + * @return void + */ +void debug_print_dc_list( void ) +{ + int i = 0; + unsigned long mask; + int x, c, d; + int port; + char tstr[50]; + char *pname[6]; + + pname[0] = "Unused"; + pname[1] = "TV"; + pname[2] = "DVOB"; + pname[3] = "DVOC"; + pname[4] = "LVDS"; + pname[5] = "CRT"; + + for (d = 0; d < dsp_context.dsp_dc_list.count; d++) { + sprintf(tstr, "%3d: ", i); + mask = 0x0000000f; + c = 0; + for (x = 0; x < 7; x++) { + mask = mask << 4; + port = (dsp_context.dsp_dc_list.dc_list[d] & mask) >> (4 * (x+1)); + if ((x == 4) && (port != 0)) { + strcat(tstr, " + "); + c = 0; + } + if (port != 0) { + if (c) { + strcat(tstr, ","); + } + strcat(tstr, pname[port]); + c = 1; + } + } + if ((dsp_context.dsp_dc_list.dc_list[d] & 0x0000000f) == 8) { + strcat(tstr, "/e"); + } + OS_ERROR("%-20s 0x%08lx", tstr, dsp_context.dsp_dc_list.dc_list[d]); + i++; + } +} +#endif + +/*! + * Build a list of valid display configurations (DC) and store for later + * use by the driver. + * + * @param context + * + * @return void + */ +void dsp_dc_init(igd_context_t *context) +{ + igd_display_port_t *p0 = NULL, *p1 = NULL, *p2 = NULL, *p3 = NULL; + unsigned long dc_flags; + int num_ports; + igd_display_port_t **port_table; + igd_plane_t **plane; + unsigned long display_detect; + + /* Build the display configuration list */ + dc_flags = dsp_context.num_dsp_pipes & 0x0f; + + /* Check plane features to see if DIH is possible (IGD_PLANE_DIH) */ + plane = dsp_context.dispatch->planes; + if (*plane) { + if ((*plane)->plane_features & IGD_PLANE_DIH) { + dc_flags |= IGD_PLANE_DIH; + } + } + + display_detect = (dsp_context.display_flags & IGD_DISPLAY_DETECT)?1:0; + + /* + * Given the number of ports and number of pipes can the max number + * of DC's be calculated? + * + * Number of ports squared. + * If clone double. + * If DIH, double again. + */ + + /* Find the number of ports */ + port_table = dsp_context.dispatch->ports; + num_ports = 0; + while (port_table[num_ports]) { + num_ports++; + } + OS_DEBUG("ports = %d, pipes = %ld", num_ports, + dsp_context.num_dsp_pipes); + + + /* If this is the first time called, then allocate memory for the list */ + if (dsp_context.dsp_dc_list.dc_list == NULL) { + dsp_context.dsp_dc_list.size = num_ports * num_ports; + if (dsp_context.num_dsp_pipes > 1) { + dsp_context.dsp_dc_list.size *= 2; + if (dc_flags & IGD_PLANE_DIH) { /* extended modes */ + dsp_context.dsp_dc_list.size *= 2; + } + } + + /* Need to allocate memory for list */ + dsp_context.dsp_dc_list.dc_list = + OS_ALLOC(sizeof(unsigned long) * dsp_context.dsp_dc_list.size); + } + dsp_context.dsp_dc_list.count = 0; + + if (dsp_context.dsp_dc_list.dc_list == NULL) { + OS_DEBUG("Memory allocation error, can't allocate DC list"); + return; + } + +#if 0 + /* Get all possible one display configs */ + while ((p0 = dsp_get_next_port(context, p0)) != NULL) { + if (dsp_port_is_ok(context, p0, display_detect)) { + dsp_add_to_dc_list(&dsp_context.dsp_dc_list, + (1 | ((p0->port_number & 0x0f) << 4)), 0); + } + } + + /* Get all possible two display configs */ + p0 = NULL; + while ((p0 = dsp_get_next_port(context, p0)) != NULL) { + p1 = NULL; + if (!dsp_port_is_ok(context, p0, display_detect)) { + continue; /* skip ports that are inuse (not to be used) */ + } + while ((p1 = dsp_get_next_port(context, p1)) != NULL) { + if (!dsp_port_is_ok(context, p1, display_detect) || (p1 == p0)) { + continue; /* can't use the same port twice! */ + } + dsp_build_display_configs(p0, p1, NULL, NULL, dc_flags, + &dsp_context.dsp_dc_list); + } + } + + /* Get all possible three display configs */ + p0 = NULL; + while ((p0 = dsp_get_next_port(context, p0)) != NULL) { + if (!dsp_port_is_ok(context, p0, display_detect)) { + continue; /* skip ports that are inuse (not to be used) */ + } + p1 = NULL; + while ((p1 = dsp_get_next_port(context, p1)) != NULL) { + if (!dsp_port_is_ok(context, p1, display_detect) || (p1 == p0)) { + continue; /* can't use the same port twice! */ + } + p2 = NULL; + while ((p2 = dsp_get_next_port(context, p2)) != NULL) { + if (!dsp_port_is_ok(context, p2, display_detect) || + (p2 == p0) || (p2 == p1)) { + continue; /* can't use the same port multiple times! */ + } + dsp_build_display_configs(p0, p1, p2, NULL, dc_flags, + &dsp_dc_list); + } + } + } + + /* Get all possible four display configs */ + p0 = NULL; + while ((p0 = dsp_get_next_port(context, p0)) != NULL) { + if (!dsp_port_is_ok(context, p0, display_detect)) { + continue; /* skip ports that are inuse (not to be used) */ + } + p1 = NULL; + while ((p1 = dsp_get_next_port(context, p1)) != NULL) { + if (!dsp_port_is_ok(context, p1, display_detect) || (p1 == p0)) { + continue; /* can't use the same port twice! */ + } + p2 = NULL; + while ((p2 = dsp_get_next_port(context, p2)) != NULL) { + if (!dsp_port_is_ok(context, p2, display_detect) || + (p2 == p0) || (p2 == p1)) { + continue; /* can't use the same port multiple times! */ + } + while ((p3 = dsp_get_next_port(context, p3)) != NULL) { + if (!dsp_port_is_ok(context, p3, display_detect) || + (p3 == p0) || (p3 == p2) || (p3 == p1)) { + continue; /* can't use the same port multiple times! */ + } + dsp_build_display_configs(p0, p1, p2, p3, dc_flags, + &dsp_dc_list); + } + } + } + } +#else + + /* + * This code is much smaller than above but doesn't sort the list + * in the same way. It saves over 300 bytes. + */ + p0 = NULL; + while ((p0 = dsp_get_next_port(context, p0, 0)) != NULL) { + if (dsp_port_is_ok(context, p0, display_detect)) { + dsp_add_to_dc_list(&dsp_context.dsp_dc_list, + (1 | ((p0->port_number & 0x0f) << 4)), 0); + p1 = NULL; + while ((p1 = dsp_get_next_port(context, p1, 0)) != NULL) { + if ((p1 != p0) && dsp_port_is_ok(context, p1, display_detect)) { + dsp_build_display_configs(p0, p1, NULL, NULL, dc_flags, + &dsp_context.dsp_dc_list); + p2 = NULL; + while ((p2 = dsp_get_next_port(context, p2, 0)) != NULL) { + if ((p2 != p0) && (p2 != p1) && + dsp_port_is_ok(context, p2, display_detect)) { + dsp_build_display_configs(p0, p1, p2, NULL, + dc_flags, &dsp_context.dsp_dc_list); + while ((p3 = dsp_get_next_port(context, p3, 0)) != + NULL) { + if ((p3 != p0) && (p3 != p2) && (p3 != p1) && + dsp_port_is_ok(context, p3, display_detect)) { + dsp_build_display_configs(p0, p1, p2, p3, + dc_flags, &dsp_context.dsp_dc_list); + } + } + } + } + } + } + } + } +#endif + + /* zero terminate the list */ + dsp_add_to_dc_list(&dsp_context.dsp_dc_list, 0L, 0L); + + /*If quickboot, get the dc that was programmed by the firware + * i.e. Video BIOS or EFI Video Driver + */ + +#ifndef CONFIG_MICRO /* We don't need this in firmware code */ + dsp_context.fw_dc = dsp_get_fw_dc(context); + dsp_context.context->mod_dispatch.dsp_fw_dc = dsp_context.fw_dc; + +#endif + + /*OPT_DEBUG_VOID_CALL(debug_print_dc_list());*/ + +} /* end dsp_dc_init() */ + + +/*! + * Return the list of valid display configurations. The list returned is + * currently the "live" list. The IAL should not modify it in any way. + * + * For the driver, this will re-initialize the DC list every time it's + * called so that the list will reflect displays that have been attached + * or detached since the last call. If the list is empty (i.e. no + * displays attached and/or no port drivers loaded), then fall back to + * the following default behavior: + * 1. Make sure analog port is marked as available + * 2. Turn off the display detect option. + * 3. Re-initialize the DC list. + * This guarentees that we'll always have at least one valid display (CRT) + * on the list. + * + * @param driver_handle + * + * @param request - The requested display mode. The first DC in the list + * with a matching display mode is returned when the IGD_QUERY_DC_INIT + * flag is set. + * + * @param dc_list - The returned DC list. This will point to the live list + * and as such, should not be freed or altered. + * + * @param flags - Determines what portion of the list is returned. + * + * @return 0: success. + * @return -IGD_ERROR_INVAL: No valid DC list can be returned. + */ +int igd_query_dc(igd_driver_h driver_handle, + unsigned long request, + unsigned long **dc_list, + unsigned long flags) +{ + igd_context_t *context = (igd_context_t *)driver_handle; + int d; + + OS_DEBUG ("Enter igd_query_dc"); + +#ifndef CONIFG_MICRO + dsp_dc_init(context); + /* + * If the list is empty at this point, add single/analog so that + * the driver can run. Under normal conditions, this shouldn't + * happen. In this case, turn off display detect too? + */ + if (dsp_context.dsp_dc_list.count == 1) { + + OS_ERROR("No displays detected or available:"); + + /* If display detect is on, turn it off and try again */ + if (dsp_context.display_flags & IGD_DISPLAY_DETECT) { + + dsp_context.display_flags &= ~IGD_DISPLAY_DETECT; + + /* Turn off display detect */ + OS_ERROR(" Disabling display detect."); + dsp_dc_init(context); + } + +#if 0 + /* Now, analog port driver also loads dynamically, so there is + * no fallback case to analog */ + if (dsp_context.dsp_dc_list.count == 1) { + igd_display_port_t *port = NULL; + void *handle = NULL; + + OS_ERROR(" Defaulting to CRT only."); + dsp_get_display(5, NULL, &port, 0); + if (port == NULL) { + OS_ERROR("No analog port available, this is bad!"); + } else { + if (port->inuse == 0x80) { + /* port was never initialized, so better do that! */ + ANALOG_INIT(handle); + } + port->inuse = 0; /* Mark as available */ + } + + /* Resetting DC list */ + dsp_context.dsp_dc_list.count = 0; + dsp_add_to_dc_list(&dsp_context.dsp_dc_list, 0x00000051L, 0L); + dsp_add_to_dc_list(&dsp_context.dsp_dc_list, 0L, 0L); + } +#endif + } +#endif + + if (flags == IGD_QUERY_DC_ALL) { + *dc_list = dsp_context.dsp_dc_list.dc_list; + return 0; + } else if (flags == IGD_QUERY_DC_PREFERRED) { + /* + * FIXME: + * This case is not yet implemented. No IAL currently uses this + * capability. + * + * Somehow this needs to build a new smaller list and return + * that. The caller would then be responsibile for freeing the + * memory? + * + * For now, this returns the full list so that if an IAL tries + * to use it, it doesn't break. + */ + *dc_list = dsp_context.dsp_dc_list.dc_list; + return 0; + } else if (flags == IGD_QUERY_DC_INIT) { + /* what is the current display config? */ + for(d = 0; d < dsp_context.dsp_dc_list.count; d++) { + if (dsp_context.dsp_dc_list.dc_list[d] == request) { + *dc_list = &dsp_context.dsp_dc_list.dc_list[d]; + return 0; + } + } + /* Find first match of same type */ + for(d = 0; d < dsp_context.dsp_dc_list.count; d++) { + if (dsp_context.dsp_dc_list.dc_list[d] & (request & 0x0f)) { + *dc_list = &dsp_context.dsp_dc_list.dc_list[d]; + return 0; + } + } + } else if (flags == IGD_QUERY_DC_EXISTING) { + *dc_list = &dsp_context.fw_dc; + return 0; + } + OS_ERROR ("igd_query_dc found no match for requested dc = %ld", request); + *dc_list = NULL; + return -IGD_ERROR_INVAL; +} + +/*! + * Mark a plane as available. If there are surfaces allocated to the + * plane, free them. + * + * @param context + * @param plane + * + * @return void + */ +void free_plane(igd_context_t *context, igd_plane_t *plane) +{ + igd_cursor_info_t *ci; + igd_framebuffer_info_t *fb; + + OS_DEBUG("free_plane Entry"); + + if(!plane) { + OS_ERROR("Attempt to free NULL plane"); + return; + } + + /* If a framebuffer was allocated for this plane, free it */ + if (!plane->mirror && (plane->plane_info != NULL)) { + if ((IGD_PLANE_CURSOR & plane->plane_features) == IGD_PLANE_CURSOR){ + ci = (igd_cursor_info_t *)plane->plane_info; + OS_DEBUG("Freeing cursor image @ 0x%08lx", ci->xor_offset); + context->dispatch.gmm_free(ci->xor_offset); + OS_DEBUG("Freeing cursor image @ 0x%08lx", ci->argb_offset); + context->dispatch.gmm_free(ci->argb_offset); + /* Free plane info */ + OS_FREE(plane->plane_info); + plane->plane_info = NULL; + } else { + fb = (igd_framebuffer_info_t *)plane->plane_info; + OS_DEBUG("Freeing framebuffer @ 0x%08lx", fb->fb_base_offset); + if(fb->allocated) { + context->dispatch.gmm_free(fb->fb_base_offset); + } + /* Must retain the offset because it is our reservation */ + fb->allocated = 0; + /* The FB Info is static, don't free it */ + } + } else { + /* If this is mirrored (for clone displays), break the mirror */ + plane->mirror->mirror = NULL; + plane->mirror = NULL; + /* Note: The following fixes a kernel Oops when the DRM module + * initializes the display when it's loaded, and then the X driver uses + * a different port order in its DC (and a dsp_shutdown() frees this, + * followed by an dsp_alloc() which needs to allocate a new cursor). + * That's because the primary and secondary ports/planes switch, and + * plane->plane_info in this context becomes cursor->cursor_info in + * dsp_alloc(), and it must be NULL so that a new cursor is allocated + * (otherwise the old memory location is re-used, even though the + * memory was freed and reallocated for another purpose): + */ + if ((IGD_PLANE_CURSOR & plane->plane_features) == IGD_PLANE_CURSOR){ + plane->plane_info = NULL; + } + } + + OS_DEBUG("De-allocating plane 0x%lx", plane->plane_reg); + plane->inuse = 0; +} /* end free_plane() */ + +/*! + * Take a DC and configure the primary and secondary display handles. + * The two display handles are returned to the caller. + * + * It should be valid to use the 0/1 indexes for pipes & planes here + * because we should never get a DC that isn't valid. So if the hardware + * can't support extended, and extended DC will never show up. + * + * @param context + * @param dc + * @param flags + * + * @return 0: success. + * @return -IGD_INVAL: No valid DC list can be returned. + */ +int dsp_alloc(igd_context_t *context, + unsigned long dc, + unsigned long flags) +{ + igd_plane_t *plane = NULL, *plane2 = NULL, *temp = NULL; + igd_plane_t **plane_tbl; + igd_cursor_t *cursor = NULL, *cursor2 = NULL; + igd_cursor_t *cursora = NULL, *cursorb = NULL; + igd_display_pipe_t *pipe = NULL; + igd_display_port_t *port = NULL; + unsigned short port_number; + int i, swap_plane = 0; + int secondary_pipe = 1; + +#ifndef CONFIG_MICRO + int ret; +#endif + +#ifndef CONFIG_MICRO + /* + * Surfaces in the surface cache have a display handle associated with + * them. To be safe we need to flush everyone out of the cache before + * freeing a handle. + */ + if(context->dispatch.gmm_flush_cache) { + if(dsp_context.display_list[0].allocated || + dsp_context.display_list[1].allocated) { + context->dispatch.gmm_flush_cache(); + } + } +#endif + + /* Clear all the port assignments */ + for (i = 0; i < IGD_MAX_PORTS; i++) { + dsp_context.display_list[0].port[i] = NULL; + dsp_context.display_list[1].port[i] = NULL; + } + + /* Clear display ptr assignments */ + OS_MEMSET(dsp_context.display_ptr_list, 0, + sizeof(dsp_context.display_ptr_list)); + + /* Free any allocated pipes */ + if (dsp_context.display_list[0].pipe) { + PIPE(&dsp_context.display_list[0])->inuse = 0; + } + if (dsp_context.display_list[1].pipe) { + PIPE(&dsp_context.display_list[1])->inuse = 0; + } + + /* Set up planes... */ + plane_tbl = dsp_context.dispatch->planes; + while(*plane_tbl) { + (*plane_tbl)->inuse = 0; + + if ((IGD_PLANE_CURSOR & (*plane_tbl)->plane_features) == + IGD_PLANE_CURSOR) { + if ((cursora == NULL) && + (IGD_CURSOR_USE_PIPEA & (*plane_tbl)->plane_features)) { + cursora = (igd_cursor_t *)(*plane_tbl); + cursor = cursora; + } else if (cursorb == NULL) { + cursorb = (igd_cursor_t *)(*plane_tbl); + cursor2 = cursorb; + } + } else { + if (plane == NULL) { + plane = *plane_tbl; + /* plane->mirror = NULL; */ + } else if (plane2 == NULL) { + plane2 = *plane_tbl; + /* plane2->mirror = NULL; */ + } + } + plane_tbl++; + } + + + /* + * Get the first port from the DC and hook it up as master. + * FIXME: + * If this fails becaue the display isn't attached, and there + * are more choices, this should move on and try the other + * choices, maybe? + */ + OS_MEMSET(&dsp_context.display_list[0], 0, sizeof(igd_display_context_t)); + + port_number = (unsigned short)((dc & 0x000000f0) >> 4); + dsp_get_display(port_number, NULL, &port, 0); + + if (port) { + /* + * Allocate a pipe for this display. Depending on the port + * requirements this could be either pipe. + */ + if (port->port_features & IGD_PORT_USE_PIPEA) { + pipe = dsp_context.dispatch->pipes[0]; + cursor = cursora; + cursor2 = cursorb; + secondary_pipe = 1; + if(plane->plane_features & IGD_PLANE_USE_PIPEB){ + swap_plane = 1; + } + } else if (port->port_features & IGD_PORT_USE_PIPEB) { + pipe = dsp_context.dispatch->pipes[1]; + cursor2 = cursora; + cursor = cursorb; + secondary_pipe = 0; + if(plane->plane_features & IGD_PLANE_USE_PIPEA){ + swap_plane = 1; + } + } else { + OS_ERROR("Error, master port can't use either pipeA or pipeB!"); + return -IGD_INVAL; + } + + if(swap_plane){ + temp = plane; + plane = plane2; + plane2 = temp; + } + pipe->inuse = 0; + +#ifndef CONFIG_MICRO + if(context->mod_dispatch.alloc_queues) { + ret = context->mod_dispatch.alloc_queues(context, pipe, flags); + if (ret) { + OS_ERROR("Error, unable to allocate ring buffers"); + return -IGD_INVAL; + } + } +#endif + + /* set up the display handle */ + dsp_context.display_list[0].plane = (void *)plane; + dsp_context.display_list[0].cursor = (void *)cursor; + dsp_context.display_list[0].pipe = (void *)pipe; + dsp_context.display_list[0].port[port_number-1] = (void *)port; + dsp_context.display_list[0].context = context; + dsp_context.display_list[0].port_number = port_number; + dsp_context.display_list[0].allocated = 1; + dsp_context.display_ptr_list[port_number]= &dsp_context.display_list[0]; + pipe->inuse = 1; + +#ifndef CONFIG_MICRO + if (cursor) { + pipe->cursor = cursor; + cursor->inuse = 1; + if (cursor->cursor_info == NULL) { + cursor->cursor_info = OS_ALLOC(sizeof(igd_cursor_info_t)); + if(!cursor->cursor_info) { + OS_ERROR("Error, memory allocation for cursor_info " + "failed."); + pipe->cursor = NULL; + cursor->inuse = 0; + } else { + if (dsp_init_cursor(context, cursor) != 0) { + pipe->cursor = NULL; + cursor->inuse = 0; + } + } + } + } +#endif + + } /* else { + OS_ERROR("Failed to set up primary: port = %p, pipe = %p, plane = %p", + port, pipe, plane); + } + */ + + + /* Set up secondary. How it is set up depends on the display config */ + switch (dc & 0x0000000f) { + case IGD_DISPLAY_CONFIG_SINGLE: + case IGD_DISPLAY_CONFIG_TWIN: + case 0: + /* + * If display 1 was previouslly allocated, then we were in either + * clone or extended. In either case, we just want to make sure + * the display is no longer allocated and any clone mirror links + * are removed. + * + * Note: This doesn't reduce any reference counts or free any + * resources allocated to display 1. + */ + if (dsp_context.display_list[1].allocated) { + dsp_context.display_list[1].allocated = 0; + dsp_context.display_list[1].plane = NULL; + dsp_context.display_list[1].cursor = NULL; + dsp_context.display_list[1].pipe = NULL; + + /* If the cursor and/or fb were cloned, break the clone */ + if (cursor->mirror != NULL) { + cursor->mirror = NULL; + cursor2->mirror = NULL; + cursor2->cursor_info = NULL; + } + + /* break plane mirror??? */ + if (plane->mirror != NULL) { + plane->mirror = NULL; + plane2->mirror = NULL; + } + } + break; + case IGD_DISPLAY_CONFIG_CLONE: + /* + * When switching to clone we need to free any resources allocated + * to the second display. This can happen if we were ever in + * extended mode prior to this. + * + * NOTE: + * This then needs to fall through to the extended branch because + * the rest of the set up is the same. DO NOT ADD A BREAK STATEMENT! + */ + + /* + * If display_list[1].plane->plane_info exist and the plane_info + * reference count is 1, then this was allocated as an independent + * plane. The surface must be freed and the plane_info record reset. + * + * The same logic applies to the secondary cursor info. Does this + * imply that the display_list needs to have a cursor pointer too? + * What about moving the cursor from the pipe to the display? + */ + if (dsp_context.display_list[1].plane && !plane2->mirror) { + free_plane(context, dsp_context.display_list[1].plane); + } + if (dsp_context.display_list[1].cursor && !cursor2->mirror) { + free_plane(context, (igd_plane_t *)cursor2); + } + + /* Mirror the cursor and framebuffer to the second display */ + plane->mirror = plane2; + plane2->mirror = plane; + /* + * Note: plane_info points to a static data structure so we have + * to get the original pointer back when going into extended. + */ + plane2->plane_info = plane->plane_info; + + /* + * WinCE VEXT uses clone mode, but needs indpendent cursors. Thus, + * we don't want to do this mirroring in this one specific case. + */ + cursor->mirror = cursor2; + cursor2->mirror = cursor; + cursor2->cursor_info = cursor->cursor_info; + + case IGD_DISPLAY_CONFIG_EXTENDED: + if (plane2) { + +#ifndef CONFIG_MICRO + /* This condition is always true, not sure why this check is + * required */ + if (!(dc & IGD_DISPLAY_CONFIG_CLONE)) { + /* If this is really extended and not clone, break mirrors */ + plane->mirror = NULL; + plane2->mirror = NULL; + if (plane2->plane_info == plane->plane_info) { + /* + * Get back the original static pointer by guessing + * and switching it if it is the same as plane 1. + */ + plane2->plane_info = &fb_info_cmn[1]; + if (plane2->plane_info == plane->plane_info) { + plane2->plane_info = &fb_info_cmn[0]; + } + } + cursor->mirror = NULL; + cursor2->mirror = NULL; + if (cursor2->cursor_info == cursor->cursor_info) { + cursor2->cursor_info = NULL; + } + } +#endif + + port_number = IGD_DC_SECONDARY(dc); + dsp_context.display_list[1].plane = (void *)plane2; + dsp_context.display_list[1].context = context; + dsp_context.display_list[1].cursor = (void *)cursor2; + + /* Allocate which ever pipe wasn't used above */ + pipe = dsp_context.dispatch->pipes[secondary_pipe]; + + if (pipe) { + dsp_context.display_list[1].allocated = 1; + pipe->inuse = 1; + dsp_context.display_list[1].pipe = (void *)pipe; + + dsp_get_display(port_number, NULL, &port, 0); + if (port) { + dsp_context.display_list[1].port[port_number-1] = + (void *)port; + dsp_context.display_list[1].port_number = port_number; + dsp_context.display_ptr_list[port_number] = + &dsp_context.display_list[1]; + } else { + OS_ERROR("Failed to get port %d", port_number); + } + +#ifndef CONFIG_MICRO + if (cursor2) { + pipe->cursor = cursor2; + cursor2->inuse = 1; + if (cursor2->cursor_info == NULL) { + cursor2->cursor_info = + OS_ALLOC(sizeof(igd_cursor_info_t)); + if(!cursor2->cursor_info) { + OS_ERROR("Error, memory allocation for cursor_info " + "failed."); + pipe->cursor = NULL; + cursor2->inuse = 0; + } else { + if (dsp_init_cursor(context, cursor2) != 0) { + pipe->cursor = NULL; + cursor2->inuse = 0; + } + } + } + } +#endif + } else { + OS_ERROR("Failed to get pipe #1"); + } + } else { + OS_ERROR("Plane #1 not available"); + } + break; + default: + OS_DEBUG("DC has an invalid display config! 0x%08lx", dc); + break; + } + + /* Assign all twin'd ports to the proper displays */ + for (i = 7; i > 1; i--) { + port_number = DC_PORT_NUMBER(dc, i); + if ((port_number) && (i != 5)) { /* Skip Owner ports */ + dsp_get_display(port_number, NULL, &port, 0); + if (port) { + if (i > 5) { + dsp_context.display_list[1].port[port_number-1] = + (void *)port; + dsp_context.display_ptr_list[port_number] = + &(dsp_context.display_list[1]); + } else { + dsp_context.display_list[0].port[port_number-1] = + (void *)port; + dsp_context.display_ptr_list[port_number] = + &(dsp_context.display_list[0]); + } + } + } + } + + dsp_context.current_dc = dc; + return 0; +} + +/*! + * Does the initialization of dsp module including initializing + * unset values in the plane, pipe and port tables. + * + * @param context + * + * @return 0: success. + * @return -IGD_ERROR_NODEV + */ +int dsp_init(igd_context_t *context) +{ + igd_display_params_t *display_params; + igd_plane_t **plane; + igd_display_pipe_t **pipe; + unsigned long i, num_gpio, *gpio_reg; + unsigned long hal_attr_index, init_attr_index; + igd_param_t *params = context->mod_dispatch.init_params; + int ret; + + OS_DEBUG("Enter dsp_init()"); + + OS_MEMSET(&dsp_context, 0, sizeof(dsp_context)); + + /* Hook up plane, pipe, port, cursor lists here */ + dsp_context.dispatch = (dsp_dispatch_t *)dispatch_acquire(context, + dsp_dispatch_list); + if(!dsp_context.dispatch) { + return -IGD_ERROR_NODEV; + } + + dsp_context.context = context; + + if(dsp_context.dispatch->dsp_init) { + ret = dsp_context.dispatch->dsp_init(context); + if (ret) { + return ret; + } + } + + /* Hook up top-level dispatch functions */ + context->dispatch.query_dc = igd_query_dc; + + /* Hook up inter-module dispatch functions */ + context->mod_dispatch.dsp_get_config_info = dsp_get_config_info; + context->mod_dispatch.dsp_get_next_plane = dsp_get_next_plane; + context->mod_dispatch.dsp_get_next_pipe = dsp_get_next_pipe; + context->mod_dispatch.dsp_get_next_port = dsp_get_next_port; + context->mod_dispatch.dsp_get_dc = dsp_get_dc; + context->mod_dispatch.dsp_get_display = dsp_get_display; + context->mod_dispatch.dsp_get_planes_pipes = dsp_get_planes_pipes; + + + /* Dsp data members in inter module dispatch. This is done to make + * these data members available for vBIOS after init when dsp is + * discarded. */ + context->mod_dispatch.dsp_current_dc = &dsp_context.current_dc; + context->mod_dispatch.dsp_port_list = dsp_context.port_list; + context->mod_dispatch.dsp_display_list = dsp_context.display_ptr_list; + + /* Call the full init if we are not micro */ + OPT_MICRO_CALL(dsp_full_init(context)); + + dsp_context.display_flags = params->display_flags; + + /* Fill the number of planes and number of pipes in mode_context */ + plane = dsp_context.dispatch->planes; + pipe = dsp_context.dispatch->pipes; + + i=0; + while (*plane) { + if ((*plane)->plane_features & IGD_PLANE_DISPLAY) { + /* + * Initialize the offsets of the frame buffer to zero. + */ + (*(igd_display_plane_t **)plane)->fb_info->fb_base_offset = 0; + (*(igd_display_plane_t **)plane)->fb_info->visible_offset = 0; + dsp_context.num_dsp_planes++; + } + plane++; + } + + while (*pipe) { + dsp_context.num_dsp_pipes++; + pipe++; + } + + dsp_context.dsp_dc_list.dc_list = NULL; + + /* Initialize port table with user specified display parameters. */ + do_port_order(context, params->port_order); + + /* Now set the other parameters in port table */ + num_gpio = context->mod_dispatch.mode_get_gpio_sets(&gpio_reg); + + for (i = 1, display_params = params->display_params; i <= 5; i++, + display_params++) { + unsigned long temp; + igd_display_port_t *port = NULL; + + dsp_get_display((unsigned short)display_params->port_number, + NULL, &port, 0); + if (!port) { + /* If the port number is unknown/undefined, + * then skip this parameter */ + continue; + } + + /* process present_params flags */ + if (IGD_PARAM_DDC_GPIO & display_params->present_params) { + temp = display_params->ddc_gpio; + if (temp >= num_gpio) { + OS_DEBUG("Invalid GPIO pin pair %ld specified for DDC.", + temp); + } else { + port->ddc_reg = gpio_reg[temp]; + } + } + if (IGD_PARAM_DDC_SPEED & display_params->present_params) { + temp = display_params->ddc_speed; + if (temp > 400 || temp < 10) { + OS_DEBUG("DDC speed %ld is outside [10-400KHz] range.", + temp); + } else { + port->ddc_speed = temp; + } + } + if (IGD_PARAM_DDC_DAB & display_params->present_params) { + port->ddc_dab = display_params->ddc_dab; + } + if (IGD_PARAM_I2C_GPIO & display_params->present_params) { + temp = display_params->i2c_gpio; + if (temp >= num_gpio) { + OS_DEBUG("Invalid GPIO pin pair %ld specified for I2C.", + temp); + } else { + port->i2c_reg = gpio_reg[temp]; + } + } + if (IGD_PARAM_I2C_SPEED & display_params->present_params) { + temp = display_params->i2c_speed; + if (temp > 400 || temp < 10) { + OS_DEBUG("I2C speed %ld is outside [10-400KHz] range.", + temp); + } else { + port->i2c_speed = temp; + } + } + if (IGD_PARAM_DAB & display_params->present_params) { + port->dab = display_params->i2c_dab; + } + if (IGD_PARAM_FP_INFO & display_params->present_params) { + port->fp_info = (igd_param_fp_info_t *) + OS_ALLOC(sizeof(igd_param_fp_info_t)); + if (NULL != port->fp_info) { + OS_MEMCPY(port->fp_info, &display_params->fp_info, + sizeof(igd_param_fp_info_t)); + OS_DEBUG("IGD_PARAM_FP_INFO: FP width %ld height %ld", + port->fp_info->fp_width, port->fp_info->fp_height); + } else { + OS_DEBUG("IGD_PARAM_FP_INFO: allocation of igd_param_fp_info_t " + "struct failed"); + } + } + if (IGD_PARAM_DTD_LIST & display_params->present_params) { + port->dtd_list = OS_ALLOC(sizeof(igd_param_dtd_list_t)); + if (NULL != port->dtd_list) { + OS_MEMCPY(port->dtd_list, &display_params->dtd_list, + sizeof(*port->dtd_list)); + } else { + OS_DEBUG("IGD_PARAM_DTD_LIST: allocation of " + "igd_param_dtd_list_t struct failed"); + } + } + if (IGD_PARAM_ATTR_LIST & display_params->present_params) { + port->attr_list = OS_ALLOC(sizeof(igd_param_attr_list_t)); + if (NULL != port->attr_list) { + OS_MEMCPY(port->attr_list, &display_params->attr_list, + sizeof(*port->attr_list)); + /* Now allocate memory for attributes */ + port->attr_list->attr = OS_ALLOC(sizeof(igd_param_attr_t) * + port->attr_list->num_attrs); + if (NULL != port->attr_list->attr) { + OS_MEMCPY(port->attr_list->attr, + display_params->attr_list.attr, + sizeof(igd_param_attr_t) * port->attr_list->num_attrs); + } + } + + /* Initialize HAL's attributes */ + for( init_attr_index = 0; + init_attr_index < port->attr_list->num_attrs; + init_attr_index++ ) { + + hal_attr_index = 0; + + while (PD_ATTR_LIST_END != port->attributes[hal_attr_index].id) { + if (port->attributes[hal_attr_index].id == + port->attr_list->attr[init_attr_index].id) { + port->attributes[hal_attr_index].current_value = + port->attr_list->attr[init_attr_index].value; + } + + hal_attr_index++; + } + } /* for: initialize HAL's attributes */ + + } + } + + /* + * Build the list of valid display configurations. + */ + /* dsp_dc_init(context); */ + + return 0; +} /* end dsp_init() */ + +#ifndef CONFIG_MICRO + +/*! + * This function returns the list of available pixel formats for the + * framebuffer and cursor if the pointers are not NULL. + * + * @param display_handle A igd_display_h type returned from a previous + * igd_alloc_display call. + * @param fb_list_pfs Returns the list of pixel formats for framebuffer. + * @param cu_list_pfs Returns the list of pixel formats for the cursor. + * Both of the above lists ends with 0. Dframebuffer and cursor if the + * pointers are not NULL. + * @param overlay_pfs + * @param render_pfs + * @param texture_pfs + * + * @return 0 on success + * @return -IGD_INVAL on failure + */ +static int igd_get_pixelformats(igd_display_h display_handle, + unsigned long **fb_list_pfs, unsigned long **cu_list_pfs, + unsigned long **overlay_pfs, unsigned long **render_pfs, + unsigned long **texture_pfs) +{ + igd_display_context_t *display = (igd_display_context_t *)display_handle; + + + if (!display || !PLANE(display) || !PIPE(display)) { + return -IGD_INVAL; + } + + if (fb_list_pfs) { + *fb_list_pfs = PLANE(display)->pixel_formats; + } + if (cu_list_pfs) { + *cu_list_pfs = PIPE(display)->cursor->pixel_formats; + } + if (overlay_pfs) { + *overlay_pfs = dsp_context.dispatch->overlay_pfs; + } + if (render_pfs) { + *render_pfs = dsp_context.dispatch->render_pfs; + } + if (texture_pfs) { + *texture_pfs = dsp_context.dispatch->texture_pfs; + } + + return 0; + +} /* end igd_get_pixelformats() */ + +/*! + * Given a newly allocated cursor_info record, allocate the + * surfaces needed for both the xor and argb cursor images. Also + * fill in the cursor_info as much as possible. + * + * @param context + * @param cursor + * + * @return 0 on success + * @return -IGD_ERROR_NOMEM on failure + */ +static int dsp_init_cursor(igd_context_t *context, igd_cursor_t *cursor) +{ + unsigned long buffer; + unsigned long buffer_phys = 0; + void* cursor_mem; + unsigned int width = 64; + unsigned int height = 64; + unsigned int pitch = 0; + unsigned long size = 0; + unsigned long flags = IGD_SURFACE_CURSOR; + int ret; + int has_rgb32 = 0; + unsigned long *tmp; + + tmp = (unsigned long *)cursor->pixel_formats; + while (*tmp) { + if (*tmp == IGD_PF_ARGB32) { + has_rgb32 = 1; + break; + } + tmp++; + } + + OS_MEMSET(cursor->cursor_info, 0, sizeof(igd_cursor_info_t)); + + if (has_rgb32) { + /* ARGB32 is used for any 32bit format. */ + GMM_SET_DEBUG_NAME("ARGB Cursor"); + ret = context->dispatch.gmm_alloc_surface(&buffer, + IGD_PF_ARGB32, + &width, &height, &pitch, &size, + IGD_GMM_ALLOC_TYPE_NORMAL, &flags); + if (ret) { + OS_ERROR("ERROR: No memory for ARGB cursor!"); + return -IGD_ERROR_NOMEM; + } + + /* Get the register update physical address in RAM */ + if (context->dispatch.gmm_virt_to_phys(buffer, &buffer_phys)) { +printk(KERN_ALERT "[EGD] dsp_init_cursor(): Virtual to Physical Address " +"translation failed\n"); + OS_ERROR_EXIT("Virtual to Physical Address translation failed"); + return -IGD_ERROR_NOMEM; + } + + cursor_mem = phys_to_virt(buffer_phys); + if(cursor_mem){ + OS_MEMSET(cursor_mem, 0, size); + } + OS_DEBUG("Allocating cursor surface @ 0x%08lx", buffer); + cursor->cursor_info->argb_offset = buffer; + cursor->cursor_info->argb_pitch = pitch; + } + flags = IGD_SURFACE_CURSOR; + + GMM_SET_DEBUG_NAME("XOR Cursor"); + ret = context->dispatch.gmm_alloc_surface(&buffer, + IGD_PF_RGB_2, + &width, &height, &pitch, &size, + IGD_GMM_ALLOC_TYPE_NORMAL, &flags); + if (ret) { + if(has_rgb32) { + context->dispatch.gmm_free(cursor->cursor_info->argb_offset); + cursor->cursor_info->argb_offset = 0; + } + OS_ERROR("ERROR: No memory for XOR cursor!"); + return -IGD_ERROR_NOMEM; + } + + /* Get the register update physical address in RAM */ + if (context->dispatch.gmm_virt_to_phys(buffer, &buffer_phys)) { + OS_ERROR_EXIT("Virtual to Physical Address translation failed"); + return -IGD_ERROR_NOMEM; + } + + /* + * TODO: Verify that phys_to_virt returns a valid address for + * agp memory + */ + cursor_mem = phys_to_virt(buffer_phys); + if(cursor_mem){ + OS_MEMSET(cursor_mem, 0, size); + } + OS_DEBUG("Allocating cursor surface @ 0x%08lx", buffer); + cursor->cursor_info->xor_offset = buffer; + cursor->cursor_info->xor_pitch = pitch; + + /* Set the dsp cursor resource table */ + cursor->cursor_info->width = width; + cursor->cursor_info->height = height; + cursor->cursor_info->pixel_format = + (has_rgb32)?IGD_PF_ARGB32:IGD_PF_RGB_2; + + return 0; +} + +/*! + * Wait for all instructions on the ringbuffer to complete. This needs to be + * done before changing the framebuffer or the display. If we do not wait + * for the ringbuffer to empty, the hardware may lockup. It would be nice, + * if once the timeout occurs, to disable the ringbuffer, and continue with + * the mode changed, but this does not seem to be possible. + * + * @param context + * + * @return 0 on success + * @return -IGD_INVAL on failure + */ +/* FIXME: Move this to rb module */ +int dsp_wait_rb(igd_context_t *context) +{ + int p; + int wait_time = 15; + int ret; + unsigned long sync_val; + os_alarm_t timeout; + + if (context->dispatch.sync) { + for (p = 0; p < 2; p++) { + if (dsp_context.display_list[p].allocated) { + /* Sync the Normal Ring. */ + sync_val = 0; + timeout = OS_SET_ALARM(wait_time * 1000); + do { + ret = context->dispatch.sync( + &dsp_context.display_list[p], + IGD_PRIORITY_NORMAL, &sync_val, IGD_SYNC_BLOCK); + OS_SCHEDULE(); + } while ((ret == -IGD_ERROR_BUSY) && (!OS_TEST_ALARM(timeout))); + + if (ret == -IGD_ERROR_BUSY) { + OS_ERROR("Timeout waiting for sync"); + return (-IGD_INVAL); + } + + if(PIPE(&dsp_context.display_list[p])->queue[IGD_PRIORITY_BIN]) { + /* Sync the Binner also. */ + sync_val = 0; + timeout = OS_SET_ALARM(wait_time * 1000); + do { + ret = context->dispatch.sync( + &dsp_context.display_list[p], + IGD_PRIORITY_BIN, &sync_val, + IGD_SYNC_BLOCK | IGD_SYNC_NOFLUSH_PIPE); + OS_SCHEDULE(); + } while ((ret == -IGD_ERROR_BUSY) && (!OS_TEST_ALARM(timeout))); + + if (ret == -IGD_ERROR_BUSY) { + OS_ERROR("Timeout waiting for Binner sync"); + return (-IGD_INVAL); + } + } + } + } + } + return 0; +} + +/*! + * Browse through the list of displays and frees the display. + * + * @param context + * + * @return void + */ +void dsp_shutdown(igd_context_t *context) +{ + int i; + igd_display_port_t *port = NULL; + igd_plane_t *plane = NULL; + igd_display_pipe_t *temp_pipe = NULL; + + OS_DEBUG("dsp_shutdown Entry"); + + /* + * Free all the ports pt_info's. Need to add this here because there + * is no longer a 1-to-1 relationship between displays and ports. + */ + while ((port = dsp_get_next_port(context, port, 0)) != NULL) { + if (port->pt_info != NULL) { + OS_FREE(port->pt_info); + port->pt_info = NULL; + } + if (port->dtd_list != NULL) { + OS_FREE(port->dtd_list); + port->dtd_list = NULL; + } + if (port->attr_list != NULL) { + if (port->attr_list->attr != NULL) { + OS_FREE(port->attr_list->attr); + } + OS_FREE(port->attr_list); + port->attr_list = NULL; + } + } + + + /* Free pipes, cursors, and any allocated command queues */ + while ((temp_pipe = dsp_get_next_pipe(context, temp_pipe, 0)) != NULL) { + if(context->mod_dispatch.free_queues) { + context->mod_dispatch.free_queues(context, temp_pipe); + } + + /* probably not needed since shutting down */ + temp_pipe->inuse = 0; + temp_pipe->plane = NULL; + temp_pipe->timing = NULL; + temp_pipe->owner = NULL; + } + + /* Free planes */ + while ((plane = dsp_get_next_plane(context, plane, 0)) != NULL) { + if (plane->plane_info) { + free_plane(context, plane); + } + } + + /* Clear display list */ + for(i=0; idispatch.get_pixelformats = igd_get_pixelformats; + + /* Hook up inter-module dispatch functions */ + context->mod_dispatch.dsp_shutdown = dsp_shutdown; + + return 0; +} + +#endif + + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: dsp.c,v 1.15 2010/05/21 15:47:50 achrisan Exp $ + * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/dsp/cmn/dsp.c,v $ + *---------------------------------------------------------------------------- + */ diff --git a/drivers/gpu/drm/emgd/emgd/display/dsp/cmn/dsp_dispatch.h b/drivers/gpu/drm/emgd/emgd/display/dsp/cmn/dsp_dispatch.h new file mode 100644 index 0000000..96cdbcc --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/dsp/cmn/dsp_dispatch.h @@ -0,0 +1,55 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: dsp_dispatch.h + * $Revision: 1.3 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * + *----------------------------------------------------------------------------- + */ + +#ifndef _DSP_DISPATCH_H +#define _DSP_DISPATCH_H + +#include +#include +#include + +#include + +/* + * FIXME: This belong to PI, remove the defaults and let PI set + * them as it does for i2c. + */ +#define DDC_DEFAULT_SPEED 10 /* Default DDC bus speed in KHz */ + +typedef struct _dsp_dispatch { + igd_plane_t **planes; + igd_display_pipe_t **pipes; + igd_display_port_t **ports; + igd_fb_caps_t *caps; + unsigned long *overlay_pfs; + unsigned long *render_pfs; + unsigned long *texture_pfs; + int (*dsp_init)(igd_context_t *context); +} dsp_dispatch_t; + +extern dsp_dispatch_t dsp_dispatch_plb; +extern dsp_dispatch_t dsp_dispatch_tnc; + +#endif diff --git a/drivers/gpu/drm/emgd/emgd/display/dsp/plb/dsp_plb.c b/drivers/gpu/drm/emgd/emgd/display/dsp/plb/dsp_plb.c new file mode 100644 index 0000000..8c633e3 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/dsp/plb/dsp_plb.c @@ -0,0 +1,659 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: dsp_plb.c + * $Revision: 1.2 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * + *----------------------------------------------------------------------------- + */ + + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include "../cmn/dsp_dispatch.h" + +#ifdef CONFIG_PLB + +extern igd_framebuffer_info_t fb_info_cmn[]; + +/* + * NOTE: Some of these format lists are shared with GMM. For this reason + * they cannot be static. + */ +unsigned long fb_pixel_formats_plb[] = { + IGD_PF_ARGB32, + IGD_PF_xRGB32, + IGD_PF_ABGR32, + IGD_PF_ARGB32_2101010, + IGD_PF_RGB16_565, + IGD_PF_ARGB8_INDEXED, + 0 +}; + +unsigned long vga_pixel_formats_plb[] = { + IGD_PF_ARGB8_INDEXED, + 0 +}; + +#ifndef CONFIG_MICRO +unsigned long sprite_pixel_formats_plb[] = { + IGD_PF_ARGB32, + IGD_PF_ABGR32, + IGD_PF_ARGB32_2101010, + IGD_PF_RGB16_565, + IGD_PF_ARGB8_INDEXED, + IGD_PF_YUV422_PACKED_YUY2, + IGD_PF_YUV422_PACKED_UYVY, + 0 +}; + +unsigned long render_pixel_formats_plb[] = { + IGD_PF_ARGB32, + IGD_PF_xRGB32, + IGD_PF_ARGB32_2101010, + IGD_PF_RGB16_565, + IGD_PF_xRGB16_555, + IGD_PF_ARGB16_1555, + IGD_PF_ARGB16_4444, + IGD_PF_YUV422_PACKED_YUY2, + IGD_PF_YUV422_PACKED_UYVY, + IGD_PF_R16F, + IGD_PF_GR32_1616F, + IGD_PF_R32F, + IGD_PF_ABGR64_16161616F, + IGD_PF_YUV420_PLANAR_NV12, + IGD_PF_YUV410_PLANAR_YVU9, + 0 +}; + +unsigned long texture_pixel_formats_plb[] = { + IGD_PF_ARGB32, + IGD_PF_xRGB32, + IGD_PF_ABGR32, + IGD_PF_xBGR32, + IGD_PF_RGB16_565, + IGD_PF_xRGB16_555, + IGD_PF_ARGB16_1555, + IGD_PF_ARGB16_4444, + IGD_PF_ARGB8_INDEXED, + IGD_PF_YUV422_PACKED_YUY2, + IGD_PF_YUV422_PACKED_UYVY, + IGD_PF_YUV420_PLANAR_I420, + IGD_PF_YUV420_PLANAR_IYUV, + IGD_PF_YUV420_PLANAR_YV12, + IGD_PF_YUV410_PLANAR_YVU9, + IGD_PF_YUV420_PLANAR_NV12, + IGD_PF_DVDU_88, + IGD_PF_LDVDU_655, + IGD_PF_xLDVDU_8888, + IGD_PF_DXT1, + IGD_PF_DXT2, + IGD_PF_DXT3, + IGD_PF_DXT4, + IGD_PF_DXT5, + IGD_PF_L8, + IGD_PF_A8, + IGD_PF_AL88, + IGD_PF_AI44, + IGD_PF_L16, + IGD_PF_ARGB32_2101010, + IGD_PF_AWVU32_2101010, + IGD_PF_QWVU32_8888, + IGD_PF_GR32_1616, + IGD_PF_VU32_1616, + IGD_PF_R16F, + IGD_PF_GR32_1616F, + IGD_PF_R32F, + IGD_PF_ABGR64_16161616F, + 0 +}; + +unsigned long depth_pixel_formats_plb[] = { + IGD_PF_Z16, + IGD_PF_Z24, + IGD_PF_S8Z24, + 0 +}; + + +unsigned long cursor_pixel_formats_plb[] = { + IGD_PF_ARGB32, + IGD_PF_RGB_2, + IGD_PF_RGB_XOR_2, + IGD_PF_RGB_T_2, + 0 +}; + +unsigned long overlay_pixel_formats_plb[] = { + IGD_PF_YUV422_PACKED_YUY2, + IGD_PF_YUV422_PACKED_UYVY, + IGD_PF_YUV420_PLANAR_I420, + IGD_PF_YUV420_PLANAR_IYUV, + IGD_PF_YUV420_PLANAR_YV12, + IGD_PF_YUV420_PLANAR_NV12, + IGD_PF_YUV410_PLANAR_YVU9, + 0 +}; + +unsigned long video_pixel_formats_plb[] = { + IGD_PF_YUV420_PLANAR_NV12, + 0 +}; + +unsigned long blt_pixel_formats_plb[] = { + IGD_PF_ARGB32, + IGD_PF_xRGB32, + IGD_PF_ABGR32, + IGD_PF_xBGR32, + IGD_PF_RGB16_565, + IGD_PF_xRGB16_555, + IGD_PF_ARGB16_1555, + IGD_PF_ARGB16_4444, + IGD_PF_ARGB8_INDEXED, + IGD_PF_YUV422_PACKED_YUY2, + IGD_PF_YUV422_PACKED_UYVY, + IGD_PF_YUV420_PLANAR_I420, + IGD_PF_YUV420_PLANAR_IYUV, + IGD_PF_YUV420_PLANAR_YV12, + IGD_PF_YUV420_PLANAR_NV12, + IGD_PF_YUV410_PLANAR_YVU9, + IGD_PF_DVDU_88, + IGD_PF_LDVDU_655, + IGD_PF_xLDVDU_8888, + IGD_PF_DXT1, + IGD_PF_DXT2, + IGD_PF_DXT3, + IGD_PF_DXT4, + IGD_PF_DXT5, + IGD_PF_Z16, + IGD_PF_Z24, + IGD_PF_S8Z24, + IGD_PF_RGB_2, + IGD_PF_RGB_XOR_2, + IGD_PF_RGB_T_2, + IGD_PF_L8, + IGD_PF_A8, + IGD_PF_AL88, + IGD_PF_AI44, + IGD_PF_L16, + IGD_PF_ARGB32_2101010, + IGD_PF_AWVU32_2101010, + IGD_PF_QWVU32_8888, + IGD_PF_GR32_1616, + IGD_PF_VU32_1616, + IGD_PF_R16F, + IGD_PF_GR32_1616F, + IGD_PF_R32F, + IGD_PF_ABGR64_16161616F, + 0 +}; + +static igd_fb_caps_t caps_table_plb[] = { + {IGD_PF_ARGB32, IGD_CAP_FULL_2D | IGD_CAP_BLEND}, + {IGD_PF_xRGB32, IGD_CAP_FULL_2D | IGD_CAP_BLEND}, + {IGD_PF_ABGR32, IGD_CAP_FULL_2D | IGD_CAP_BLEND}, + {IGD_PF_xBGR32, IGD_CAP_FULL_2D | IGD_CAP_BLEND}, + {IGD_PF_ARGB32_2101010, IGD_CAP_FULL_2D | IGD_CAP_BLEND}, + {IGD_PF_RGB16_565, IGD_CAP_FULL_2D | IGD_CAP_BLEND}, + {IGD_PF_ARGB8_INDEXED, IGD_CAP_FULL_2D}, + {0, 0} +}; + +#endif + +/* + * Plane Definitions for PLB family. + */ +static igd_plane_t planea_plb = { + DSPACNTR, IGD_PLANE_DISPLAY | IGD_PLANE_DIH, 0, 0, + fb_pixel_formats_plb, &fb_info_cmn[0], NULL +}; + +static igd_plane_t planeb_plb = { + DSPBCNTR, IGD_PLANE_DISPLAY | IGD_PLANE_SPRITE | IGD_PLANE_DIH, 0, 0, + fb_pixel_formats_plb, &fb_info_cmn[1], NULL +}; + +static igd_plane_t planec_plb = { + DSPCCNTR, IGD_PLANE_SPRITE, 0, 0, + OPT_MICRO_VALUE(sprite_pixel_formats_plb, NULL), NULL, NULL +}; + +static igd_plane_t plane_vga_plb = { + VGACNTRL, IGD_PLANE_VGA, 0, 0, + vga_pixel_formats_plb, NULL, NULL +}; + +static igd_plane_t plane_overlay_plb = { + OVADD, IGD_PLANE_OVERLAY, 0, 0, + OPT_MICRO_VALUE(overlay_pixel_formats_plb, NULL), NULL, NULL +}; + +static igd_plane_t plane_cursora_plb = { + CUR_A_CNTR, IGD_PLANE_CURSOR|IGD_CURSOR_USE_PIPEA|IGD_CURSOR_USE_PIPEB, 0,0, + OPT_MICRO_VALUE(cursor_pixel_formats_plb, NULL), NULL, NULL +}; + +static igd_plane_t plane_cursorb_plb = { + CUR_B_CNTR, IGD_PLANE_CURSOR|IGD_CURSOR_USE_PIPEA|IGD_CURSOR_USE_PIPEB, 0,0, + OPT_MICRO_VALUE(cursor_pixel_formats_plb, NULL), NULL, NULL +}; + +/* + * Plane lists for PLB family members. + */ +/* Two Main Plane, One Sprite, One VGA, One Overlay, Two Cursor */ +static igd_plane_t *plane_table_plb[] = { + &planeb_plb, + &planea_plb, + &planec_plb, + &plane_vga_plb, + &plane_overlay_plb, + &plane_cursora_plb, + &plane_cursorb_plb, + NULL +}; + +static igd_clock_t clock_a_plb = { + DPLLACNTR, FPA0, 16 +}; + +static igd_clock_t clock_b_plb = { + DPLLBCNTR, FPB0, 16 +}; + +/* + * Pipe definitions for PLB family. + */ +static igd_display_pipe_t pipea_plb = { + 0, PIPEA_CONF, PIPEA_TIMINGS, DPALETTE_A, &clock_a_plb, + (IGD_PIPE_IS_PIPEA | IGD_PORT_SHARE_DIGITAL), + 0, 0,{NULL, NULL, NULL}, NULL, NULL, NULL, + NULL, NULL +}; + +static igd_display_pipe_t pipeb_plb = { + 1, PIPEB_CONF, PIPEB_TIMINGS, DPALETTE_B, &clock_b_plb, + (IGD_PIPE_IS_PIPEB | IGD_PORT_SHARE_LVDS), + 0, 0,{NULL, NULL, NULL}, NULL, NULL, NULL, + NULL, NULL +}; + +static igd_display_pipe_t *pipe_table_plb[] = { + &pipea_plb, + &pipeb_plb, + NULL +}; + +/* + * Port definitions for PLB family. + */ + +/* + * Port number: Port number is 1-number of available ports on any hardware. + * Here are the definitions: + * + * On PLB: + * ======= + * Port mappings: + * 1 - None + * 2 - DVO B port + * 3 - None + * 4 - Internal LVDS port + * 5 - None + * + * Note: Port number should match with port numbers in port parameters. + * See igd_init.h for more information. + */ + +#endif +/* + * These are the port attributes that the PLB core support. + * Note that currently it only contains color correction attributes. + * Eventually, this will include all the attributes. + */ +igd_attr_t port_attrib_plb[IGD_MAX_PORTS][5] = { + { /* Config for port 1: Integrated TV Encoder (Alviso only) */ + PD_MAKE_ATTR( + PD_ATTR_ID_FB_GAMMA, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Gamma", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x202020, /* default */ + 0x202020, /* current */ + 0x131313, /* Min: ~0.6 in 3i.5f format for R-G-B*/ + 0xC0C0C0, /* Max: 6 in 3i.5f format for R-G-B */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_FB_BRIGHTNESS, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Brightness", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x808080, + 0x808080, + 0x000000, /* Min: */ + 0xFFFFFF, /* Max: */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_FB_CONTRAST, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Contrast", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x808080, + 0x808080, + 0x000000, /* Min: */ + 0xFFFFFF, /* Max: */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_EXTENSION, + 0, + "", + PD_ATTR_FLAG_PD_INVISIBLE|PD_ATTR_FLAG_USER_INVISIBLE, + 0, + 0, + 0, + 0, + 0), + PD_MAKE_ATTR( + PD_ATTR_LIST_END, + 0, + "", + 0, + 0, + 0, + 0, + 0, + 0) + }, + { /* Config for port 2: DVO B */ + PD_MAKE_ATTR( + PD_ATTR_ID_FB_GAMMA, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Gamma", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x202020, /* default */ + 0x202020, /* current */ + 0x131313, /* Min: ~0.6 in 3i.5f format for R-G-B*/ + 0xC0C0C0, /* Max: 6 in 3i.5f format for R-G-B */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_FB_BRIGHTNESS, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Brightness", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x808080, + 0x808080, + 0x000000, /* Min: */ + 0xFFFFFF, /* Max: */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_FB_CONTRAST, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Contrast", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x808080, + 0x808080, + 0x000000, /* Min: */ + 0xFFFFFF, /* Max: */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_EXTENSION, + 0, + "", + PD_ATTR_FLAG_PD_INVISIBLE|PD_ATTR_FLAG_USER_INVISIBLE, + 0, + 0, + 0, + 0, + 0), + PD_MAKE_ATTR( + PD_ATTR_LIST_END, + 0, + "", + 0, + 0, + 0, + 0, + 0, + 0) + }, + { /* Config for port 3: DVO C */ + PD_MAKE_ATTR( + PD_ATTR_ID_FB_GAMMA, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Gamma", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x202020, /* default */ + 0x202020, /* current */ + 0x131313, /* Min: ~0.6 in 3i.5f format for R-G-B*/ + 0xC0C0C0, /* Max: 6 in 3i.5f format for R-G-B */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_FB_BRIGHTNESS, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Brightness", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x808080, + 0x808080, + 0x000000, /* Min: */ + 0xFFFFFF, /* Max: */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_FB_CONTRAST, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Contrast", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x808080, + 0x808080, + 0x000000, /* Min: */ + 0xFFFFFF, /* Max: */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_EXTENSION, + 0, + "", + PD_ATTR_FLAG_PD_INVISIBLE|PD_ATTR_FLAG_USER_INVISIBLE, + 0, + 0, + 0, + 0, + 0), + PD_MAKE_ATTR( + PD_ATTR_LIST_END, + 0, + "", + 0, + 0, + 0, + 0, + 0, + 0) + }, + { /* Config for port 4: LVDS */ + PD_MAKE_ATTR( + PD_ATTR_ID_FB_GAMMA, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Gamma", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x202020, /* default */ + 0x202020, /* current */ + 0x131313, /* Min: ~0.6 in 3i.5f format for R-G-B*/ + 0xC0C0C0, /* Max: 6 in 3i.5f format for R-G-B */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_FB_BRIGHTNESS, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Brightness", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x808080, + 0x808080, + 0x000000, /* Min: */ + 0xFFFFFF, /* Max: */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_FB_CONTRAST, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Contrast", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x808080, + 0x808080, + 0x000000, /* Min: */ + 0xFFFFFF, /* Max: */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_EXTENSION, + 0, + "", + PD_ATTR_FLAG_PD_INVISIBLE|PD_ATTR_FLAG_USER_INVISIBLE, + 0, + 0, + 0, + 0, + 0), + PD_MAKE_ATTR( + PD_ATTR_LIST_END, + 0, + "", + 0, + 0, + 0, + 0, + 0, + 0) + }, + { /* Config for port 5: ANALOG */ + PD_MAKE_ATTR( + PD_ATTR_ID_FB_GAMMA, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Gamma", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x202020, /* default */ + 0x202020, /* current */ + 0x131313, /* Min: ~0.6 in 3i.5f format for R-G-B*/ + 0xC0C0C0, /* Max: 6 in 3i.5f format for R-G-B */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_FB_BRIGHTNESS, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Brightness", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x808080, + 0x808080, + 0x000000, /* Min: */ + 0xFFFFFF, /* Max: */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_FB_CONTRAST, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Contrast", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x808080, + 0x808080, + 0x000000, /* Min: */ + 0xFFFFFF, /* Max: */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_EXTENSION, + 0, + "", + PD_ATTR_FLAG_PD_INVISIBLE|PD_ATTR_FLAG_USER_INVISIBLE, + 0, + 0, + 0, + 0, + 0), + PD_MAKE_ATTR( + PD_ATTR_LIST_END, + 0, + "", + 0, + 0, + 0, + 0, + 0, + 0) + } +}; + +#ifdef CONFIG_PLB + +igd_display_port_t dvob_port_plb = { + IGD_PORT_DIGITAL, 2, "SDVO B", 0x61140, GMBUS_DVO_REG, 0, + GMBUS_DVOB_DDC, 0xA0, + (IGD_PORT_USE_PIPEA | IGD_VGA_COMPRESS | IGD_RGBA_COLOR | + IGD_PORT_GANG), + TVCLKINBC, 0, IGD_POWERSTATE_D0, IGD_POWERSTATE_D0, + NULL, NULL, + NULL, NULL, NULL, 0, NULL, 0, + DDC_DEFAULT_SPEED, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, + IGD_POWERSTATE_UNDEFINED, + port_attrib_plb[2 - 1], /* Port Number - 1 */ + 0, { NULL }, + (BIT14 | BIT16 | BIT17), + (BIT17), 1, + +}; + +static igd_display_port_t lvds_port_plb = { + IGD_PORT_LVDS, 4, "IntLVDS", 0x61180, 0, 0, + GMBUS_INT_LVDS_DDC, 0xA0, + (IGD_PORT_USE_PIPEB | IGD_VGA_COMPRESS), + DREFCLK, 0, IGD_POWERSTATE_D0, IGD_POWERSTATE_D0, NULL, NULL, + NULL, NULL, NULL, 0, NULL, 0, + DDC_DEFAULT_SPEED, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, + IGD_POWERSTATE_UNDEFINED, + port_attrib_plb[4 - 1], /* Port Number - 1 */ + 0, { NULL }, 0, 0, 0, +}; + +static igd_display_port_t *port_table_plb[] = { + &lvds_port_plb, + &dvob_port_plb, + NULL +}; + +static int dsp_init_plb(igd_context_t *context) +{ + return 0; +} + + +dsp_dispatch_t dsp_dispatch_plb = { + plane_table_plb, pipe_table_plb, port_table_plb, + OPT_MICRO_VALUE(caps_table_plb, NULL), + OPT_MICRO_VALUE(overlay_pixel_formats_plb, NULL), + OPT_MICRO_VALUE(render_pixel_formats_plb, NULL), + OPT_MICRO_VALUE(texture_pixel_formats_plb, NULL), + dsp_init_plb +}; + +#endif + diff --git a/drivers/gpu/drm/emgd/emgd/display/dsp/tnc/dsp_tnc.c b/drivers/gpu/drm/emgd/emgd/display/dsp/tnc/dsp_tnc.c new file mode 100644 index 0000000..5f2ac1d --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/dsp/tnc/dsp_tnc.c @@ -0,0 +1,491 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: dsp_tnc.c + * $Revision: 1.3 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * + *----------------------------------------------------------------------------- + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include "../cmn/dsp_dispatch.h" + +#ifdef CONFIG_TNC + +extern igd_framebuffer_info_t fb_info_cmn[]; + +/* + * NOTE: Some of these format lists are shared with GMM. For this reason + * they cannot be static. + */ +unsigned long fb_pixel_formats_tnc[] = { + IGD_PF_ARGB32, + IGD_PF_xRGB32, + IGD_PF_ABGR32, + IGD_PF_ARGB32_2101010, + IGD_PF_RGB16_565, + IGD_PF_ARGB8_INDEXED, + 0 +}; + +unsigned long vga_pixel_formats_tnc[] = { + IGD_PF_ARGB8_INDEXED, + 0 +}; + +#ifndef CONFIG_MICRO +unsigned long sprite_pixel_formats_tnc[] = { + IGD_PF_ARGB32, + IGD_PF_ABGR32, + IGD_PF_ARGB32_2101010, + IGD_PF_RGB16_565, + IGD_PF_ARGB8_INDEXED, + IGD_PF_YUV422_PACKED_YUY2, + IGD_PF_YUV422_PACKED_UYVY, + 0 +}; + +unsigned long render_pixel_formats_tnc[] = { + IGD_PF_ARGB32, + IGD_PF_xRGB32, + IGD_PF_ARGB32_2101010, + IGD_PF_RGB16_565, + IGD_PF_xRGB16_555, + IGD_PF_ARGB16_1555, + IGD_PF_ARGB16_4444, + IGD_PF_YUV422_PACKED_YUY2, + IGD_PF_YUV422_PACKED_UYVY, + IGD_PF_R16F, + IGD_PF_GR32_1616F, + IGD_PF_R32F, + IGD_PF_ABGR64_16161616F, + IGD_PF_YUV420_PLANAR_NV12, + IGD_PF_YUV410_PLANAR_YVU9, + 0 +}; + +unsigned long texture_pixel_formats_tnc[] = { + IGD_PF_ARGB32, + IGD_PF_xRGB32, + IGD_PF_ABGR32, + IGD_PF_xBGR32, + IGD_PF_RGB16_565, + IGD_PF_xRGB16_555, + IGD_PF_ARGB16_1555, + IGD_PF_ARGB16_4444, + IGD_PF_ARGB8_INDEXED, + IGD_PF_YUV422_PACKED_YUY2, + IGD_PF_YUV422_PACKED_UYVY, + IGD_PF_YUV420_PLANAR_I420, + IGD_PF_YUV420_PLANAR_IYUV, + IGD_PF_YUV420_PLANAR_YV12, + IGD_PF_YUV410_PLANAR_YVU9, + IGD_PF_YUV420_PLANAR_NV12, + IGD_PF_DVDU_88, + IGD_PF_LDVDU_655, + IGD_PF_xLDVDU_8888, + IGD_PF_DXT1, + IGD_PF_DXT2, + IGD_PF_DXT3, + IGD_PF_DXT4, + IGD_PF_DXT5, + IGD_PF_L8, + IGD_PF_A8, + IGD_PF_AL88, + IGD_PF_AI44, + IGD_PF_L16, + IGD_PF_ARGB32_2101010, + IGD_PF_AWVU32_2101010, + IGD_PF_QWVU32_8888, + IGD_PF_GR32_1616, + IGD_PF_VU32_1616, + IGD_PF_R16F, + IGD_PF_GR32_1616F, + IGD_PF_R32F, + IGD_PF_ABGR64_16161616F, + 0 +}; + +unsigned long depth_pixel_formats_tnc[] = { + IGD_PF_Z16, + IGD_PF_Z24, + IGD_PF_S8Z24, + 0 +}; + + +unsigned long cursor_pixel_formats_tnc[] = { + IGD_PF_ARGB32, + IGD_PF_RGB_2, + IGD_PF_RGB_XOR_2, + IGD_PF_RGB_T_2, + 0 +}; + +unsigned long overlay_pixel_formats_tnc[] = { + IGD_PF_YUV422_PACKED_YUY2, + IGD_PF_YUV422_PACKED_UYVY, + IGD_PF_YUV420_PLANAR_I420, + IGD_PF_YUV420_PLANAR_IYUV, + IGD_PF_YUV420_PLANAR_YV12, + IGD_PF_YUV420_PLANAR_NV12, + IGD_PF_YUV410_PLANAR_YVU9, + 0 +}; + +unsigned long video_pixel_formats_tnc[] = { + IGD_PF_YUV420_PLANAR_NV12, + 0 +}; + +unsigned long blt_pixel_formats_tnc[] = { + IGD_PF_ARGB32, + IGD_PF_xRGB32, + IGD_PF_ABGR32, + IGD_PF_xBGR32, + IGD_PF_RGB16_565, + IGD_PF_xRGB16_555, + IGD_PF_ARGB16_1555, + IGD_PF_ARGB16_4444, + IGD_PF_ARGB8_INDEXED, + IGD_PF_YUV422_PACKED_YUY2, + IGD_PF_YUV422_PACKED_UYVY, + IGD_PF_YUV420_PLANAR_I420, + IGD_PF_YUV420_PLANAR_IYUV, + IGD_PF_YUV420_PLANAR_YV12, + IGD_PF_YUV420_PLANAR_NV12, + IGD_PF_YUV410_PLANAR_YVU9, + IGD_PF_DVDU_88, + IGD_PF_LDVDU_655, + IGD_PF_xLDVDU_8888, + IGD_PF_DXT1, + IGD_PF_DXT2, + IGD_PF_DXT3, + IGD_PF_DXT4, + IGD_PF_DXT5, + IGD_PF_Z16, + IGD_PF_Z24, + IGD_PF_S8Z24, + IGD_PF_RGB_2, + IGD_PF_RGB_XOR_2, + IGD_PF_RGB_T_2, + IGD_PF_L8, + IGD_PF_A8, + IGD_PF_AL88, + IGD_PF_AI44, + IGD_PF_L16, + IGD_PF_ARGB32_2101010, + IGD_PF_AWVU32_2101010, + IGD_PF_QWVU32_8888, + IGD_PF_GR32_1616, + IGD_PF_VU32_1616, + IGD_PF_R16F, + IGD_PF_GR32_1616F, + IGD_PF_R32F, + IGD_PF_ABGR64_16161616F, + 0 +}; + +static igd_fb_caps_t caps_table_tnc[] = { + {IGD_PF_ARGB32, IGD_CAP_FULL_2D | IGD_CAP_BLEND}, + {IGD_PF_xRGB32, IGD_CAP_FULL_2D | IGD_CAP_BLEND}, + {IGD_PF_ABGR32, IGD_CAP_FULL_2D | IGD_CAP_BLEND}, + {IGD_PF_xBGR32, IGD_CAP_FULL_2D | IGD_CAP_BLEND}, + {IGD_PF_ARGB32_2101010, IGD_CAP_FULL_2D | IGD_CAP_BLEND}, + {IGD_PF_RGB16_565, IGD_CAP_FULL_2D | IGD_CAP_BLEND}, + {IGD_PF_ARGB8_INDEXED, IGD_CAP_FULL_2D}, + {0, 0} +}; + +#endif + +/* + * Plane Definitions for TNC family. + */ +static igd_plane_t planea_tnc = { + DSPACNTR, IGD_PLANE_DISPLAY | IGD_PLANE_DIH | IGD_PLANE_USE_PIPEA, 0, 0, + fb_pixel_formats_tnc, &fb_info_cmn[0], NULL +}; + +static igd_plane_t planeb_tnc = { + DSPBCNTR, IGD_PLANE_DISPLAY | IGD_PLANE_SPRITE | IGD_PLANE_DIH | IGD_PLANE_USE_PIPEB, 0, 0, + fb_pixel_formats_tnc, &fb_info_cmn[1], NULL +}; + +static igd_plane_t planec_tnc = { + DSPCCNTR, IGD_PLANE_SPRITE, 0, 0, + OPT_MICRO_VALUE(sprite_pixel_formats_tnc, NULL), NULL, NULL +}; + +static igd_plane_t plane_vga_tnc = { + VGACNTRL, IGD_PLANE_VGA, 0, 0, + vga_pixel_formats_tnc, NULL, NULL +}; + +static igd_plane_t plane_overlay_tnc = { + OVADD, IGD_PLANE_OVERLAY, 0, 0, + OPT_MICRO_VALUE(overlay_pixel_formats_tnc, NULL), NULL, NULL +}; + +static igd_plane_t plane_cursora_tnc = { + CUR_A_CNTR, IGD_PLANE_CURSOR|IGD_CURSOR_USE_PIPEA|IGD_CURSOR_USE_PIPEB, 0,0, + OPT_MICRO_VALUE(cursor_pixel_formats_tnc, NULL), NULL, NULL +}; + +static igd_plane_t plane_cursorb_tnc = { + CUR_B_CNTR, IGD_PLANE_CURSOR|IGD_CURSOR_USE_PIPEA|IGD_CURSOR_USE_PIPEB, 0,0, + OPT_MICRO_VALUE(cursor_pixel_formats_tnc, NULL), NULL, NULL +}; + +/* + * Plane lists for TNC family members. + */ +/* Two Main Plane, One Sprite, One VGA, One Overlay, Two Cursor */ +static igd_plane_t *plane_table_tnc[] = { + &planea_tnc, + &planeb_tnc, + &planec_tnc, + &plane_vga_tnc, + &plane_overlay_tnc, + &plane_cursora_tnc, + &plane_cursorb_tnc, + NULL +}; + +static igd_clock_t clock_a_tnc = { + DPLLACNTR, FPA0, 17 +}; + +static igd_clock_t clock_b_tnc = { + DPLLBCNTR, FPB0, 16 +}; + +/* + * Pipe definitions for TNC family. + * Pipe A is always tied to LVDS and Pipe B always to SDVO + */ +static igd_display_pipe_t pipea_tnc = { + 0, PIPEA_CONF, PIPEA_TIMINGS, DPALETTE_A, &clock_a_tnc, + (IGD_PIPE_IS_PIPEA | IGD_PORT_SHARE_LVDS), + 0, 0,{NULL, NULL, NULL}, NULL, NULL, NULL, + NULL, NULL +}; + +static igd_display_pipe_t pipeb_tnc = { + 1, PIPEB_CONF, PIPEB_TIMINGS, DPALETTE_B, &clock_b_tnc, + (IGD_PIPE_IS_PIPEB | IGD_PORT_SHARE_DIGITAL), + 0, 0,{NULL, NULL, NULL}, NULL, NULL, NULL, + NULL, NULL +}; + +static igd_display_pipe_t *pipe_table_tnc[] = { + &pipea_tnc, + &pipeb_tnc, + NULL +}; +#endif /*CONFIG_TNC*/ + +/* + * HAL attributes for TNC display ports + * These are the port attributes that the PLB core support. + * Note that currently it only contains color correction attributes. + */ +igd_attr_t port_attrib_sdvo_tnc[5] = { + /* Config for port 2: DVO B */ + PD_MAKE_ATTR( + PD_ATTR_ID_FB_GAMMA, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Gamma", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x202020, /* default */ + 0x202020, /* current */ + 0x131313, /* Min: ~0.6 in 3i.5f format for R-G-B*/ + 0xC0C0C0, /* Max: 6 in 3i.5f format for R-G-B */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_FB_BRIGHTNESS, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Brightness", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x808080, + 0x808080, + 0x000000, /* Min: */ + 0xFFFFFF, /* Max: */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_FB_CONTRAST, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Contrast", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x808080, + 0x808080, + 0x000000, /* Min: */ + 0xFFFFFF, /* Max: */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_EXTENSION, + 0, + "", + PD_ATTR_FLAG_PD_INVISIBLE|PD_ATTR_FLAG_USER_INVISIBLE, + 0, + 0, + 0, + 0, + 0), + PD_MAKE_ATTR( + PD_ATTR_LIST_END, + 0, + "", + 0, + 0, + 0, + 0, + 0, + 0) +}; + +/* HAL attributes for LVDS port */ +igd_attr_t port_attrib_lvds_tnc[5] = { + /* Config for port 4: LVDS */ + PD_MAKE_ATTR( + PD_ATTR_ID_FB_GAMMA, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Gamma", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x202020, /* default */ + 0x202020, /* current */ + 0x131313, /* Min: ~0.6 in 3i.5f format for R-G-B*/ + 0xC0C0C0, /* Max: 6 in 3i.5f format for R-G-B */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_FB_BRIGHTNESS, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Brightness", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x808080, + 0x808080, + 0x000000, /* Min: */ + 0xFFFFFF, /* Max: */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_FB_CONTRAST, + PD_ATTR_TYPE_RANGE, + "Frame Buffer Contrast", + PD_ATTR_FLAG_PD_INVISIBLE, + 0x808080, + 0x808080, + 0x000000, /* Min: */ + 0xFFFFFF, /* Max: */ + 1), + PD_MAKE_ATTR( + PD_ATTR_ID_EXTENSION, + 0, + "", + PD_ATTR_FLAG_PD_INVISIBLE|PD_ATTR_FLAG_USER_INVISIBLE, + 0, + 0, + 0, + 0, + 0), + PD_MAKE_ATTR( + PD_ATTR_LIST_END, + 0, + "", + 0, + 0, + 0, + 0, + 0, + 0) +}; + +#ifdef CONFIG_TNC +/* + * Port definitions for Tunnel Creek gfx. + * + * Port mappings: + * 1 - None + * 2 - sDVO B port + * 3 - None + * 4 - Internal LVDS port + * 5 - None + */ +igd_display_port_t dvob_port_tnc = { + IGD_PORT_DIGITAL, 2, "SDVO B", 0x61140, GMBUS_DVO_REG, 0, + GMBUS_DVOB_DDC, 0xA0, + (IGD_PORT_USE_PIPEB | IGD_VGA_COMPRESS), + TVCLKINBC, 0, IGD_POWERSTATE_D0, IGD_POWERSTATE_D0, + NULL, NULL, + NULL, NULL, NULL, 0, NULL, 0, + DDC_DEFAULT_SPEED, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, + IGD_POWERSTATE_UNDEFINED, + port_attrib_sdvo_tnc, + 0, { NULL }, + (BIT14 | BIT16 | BIT17), + (BIT17), 1, + +}; + +static igd_display_port_t lvds_port_tnc = { + IGD_PORT_LVDS, 4, "IntLVDS", 0x61180, 0, 0, + I2C_INT_LVDS_DDC, 0xA0, + (IGD_PORT_USE_PIPEA | IGD_VGA_COMPRESS), + DREFCLK, 0, IGD_POWERSTATE_D0, IGD_POWERSTATE_D0, NULL, NULL, + NULL, NULL, NULL, 0, NULL, 0, + DDC_DEFAULT_SPEED, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, + IGD_POWERSTATE_UNDEFINED, + port_attrib_lvds_tnc, + 0, { NULL }, 0, 0, 0, +}; + +static igd_display_port_t *port_table_tnc[] = { + &lvds_port_tnc, + &dvob_port_tnc, + NULL +}; + +static int dsp_init_tnc(igd_context_t *context) +{ + return 0; +} + + +dsp_dispatch_t dsp_dispatch_tnc = { + plane_table_tnc, pipe_table_tnc, port_table_tnc, + OPT_MICRO_VALUE(caps_table_tnc, NULL), + OPT_MICRO_VALUE(overlay_pixel_formats_tnc, NULL), + OPT_MICRO_VALUE(render_pixel_formats_tnc, NULL), + OPT_MICRO_VALUE(texture_pixel_formats_tnc, NULL), + dsp_init_tnc +}; + +#endif diff --git a/drivers/gpu/drm/emgd/emgd/display/mode/cmn/igd_mode.c b/drivers/gpu/drm/emgd/emgd/display/mode/cmn/igd_mode.c new file mode 100755 index 0000000..e6299e9 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/mode/cmn/igd_mode.c @@ -0,0 +1,2216 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: igd_mode.c + * $Revision: 1.16 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * Contains client interface support functions for display allocations + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.mode + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "match.h" +#include "mode_dispatch.h" + +/*! + * @addtogroup display_group + * @{ + */ + +#define CURSOR_1_STATE 0x01 +#define CURSOR_2_STATE 0x02 +#define CURSOR_STATE(display) \ + ((display == &display_list[0]) ? CURSOR_1_STATE : CURSOR_2_STATE) + +/*! + * This function is an exported utility function. + * Its meant for calculating backbuffer to frontbuffer coordinates when in + * rotation, render-scaling and / or flipping (in any combination). + * + * Eventually, this function will be only for HAL usage. + * + * @param rotation + * @param do_flip + * @param do_rscale + * @param x_rnd_scale + * @param y_rnd_scale + * @param front_width + * @param front_height + * @param x + * @param y + * @param hotx + * @param hoty + * + * @return void + */ +void igd_fb_to_screen(unsigned short rotation, + unsigned char do_flip, unsigned char do_rscale, + unsigned long x_rnd_scale, unsigned long y_rnd_scale, + unsigned short front_width, unsigned short front_height, + unsigned short *x, unsigned short *y, + unsigned short hotx, unsigned short hoty); + +/* Do not malloc the context */ +extern mode_context_t mode_context[]; + +/* This symbol has to be in this file as it is part of + * driver ONLY. + */ +static fw_info_t global_fw_info; +static int get_fw_info(mode_context_t *mode_context); + +/*! + * This function sets the per-port attribute to the values given in + * the parameter. If the requested port is the PIPE master, then + * this function will proceed to program the palette. + * + * @param display used to program palette, if necessary + * @param attr_to_set contains the new color attribute to set + * + * @return 0 on success + * @return -IGD_INVAL on failure + */ +int set_color_correct(igd_display_context_t *display, + const igd_range_attr_t *attr_to_set) +{ + igd_display_port_t *port; + igd_attr_t *hal_attr_list; + mode_dispatch_t *dispatch = mode_context->dispatch; + igd_range_attr_t *attr = NULL; + unsigned int i = 0; + + OS_TRACE_ENTER; + + port = PORT_OWNER(display); + hal_attr_list = port->attributes; + + + /* update the HAL's own copy of attributes */ + while (PD_ATTR_LIST_END != hal_attr_list[i].id) { + if (attr_to_set->id == hal_attr_list[i].id) { + attr = (igd_range_attr_t *) &hal_attr_list[i]; + + /* make sure the value is within range */ + attr->current_value = OS_MAX(attr_to_set->current_value, + attr->min); + + attr->current_value = OS_MIN(attr_to_set->current_value, + attr->max); + + break; + } + + i++; + } + + /* if we didn't find anything, then quit with an error */ + if (PD_ATTR_LIST_END == hal_attr_list[i].id) { + return -IGD_ERROR_INVAL; + } + + /* If the current display is not the pipe master, then we're done */ + if (PIPE(display)->owner != display) { + return 0; + } + + /* Program palette */ + dispatch = mode_context->dispatch; + dispatch->full->set_color_correct(display); + + OS_TRACE_EXIT; + return 0; +} + +/*! + * This function is used to put the mode module into the + * requested powerstate. + * + * @param context SS level igd_context + * @param powerstate IGD_POWERSTATE_D* + * + * @return 0 on success + * @return >0 on failure + */ +int mode_pwr(igd_context_t *context, + unsigned long powerstate) +{ + igd_display_context_t *display_list[2]; + igd_display_context_t *display = NULL; + int i,j; + + OS_TRACE_ENTER; + + context->mod_dispatch.dsp_get_dc(NULL, &display_list[0], + &display_list[1]); + + for(j = 0; j < 2; j++) { + display = display_list[j]; + /* if there is no display or display not allocated, continue */ + if(!display || !display->allocated) { + continue; + } + + switch(powerstate) { + case IGD_POWERSTATE_D0: + if (!PIPE(display)->timing) { + /* if there is no pipe timing, cannot enable, continue */ + OS_DEBUG("No pipe timing for port = %lu", display->port_number); + continue; + } + /* Enable command queues */ + if(context->mod_dispatch.cmd_control) { + for (i = 0; i < IGD_MAX_PIPE_QUEUES; i++) { + if (PIPE(display)->queue[i]) { + OS_DEBUG("Enabling command queue [%d]", i); + context->mod_dispatch.cmd_control( + PIPE(display)->queue[i], CMD_CONTROL_ON); + } + } + } + + /* Set port power state */ + for (i = 0; i < IGD_MAX_PORTS; i++) { + if (display->port[i] && + (((igd_display_port_t *)display->port[i])->pt_info->flags & + IGD_DISPLAY_ENABLE)) { + mode_context->dispatch->program_port(display, i+1, TRUE); + } + } + mode_context->dispatch->program_pipe(display, TRUE); + mode_context->dispatch->program_plane(display, TRUE); + for (i = 0; i < IGD_MAX_PORTS; i++) { + if (display->port[i] && + (((igd_display_port_t *)display->port[i])->pt_info->flags & + IGD_DISPLAY_ENABLE)) { + mode_context->dispatch->post_program_port(display, i+1, 0); + } + } + break; + case IGD_POWERSTATE_D1: + case IGD_POWERSTATE_D2: + case IGD_POWERSTATE_D3: + /* Set port power state */ + for (i = 0; i < IGD_MAX_PORTS; i++) { + if (display->port[i] && + (((igd_display_port_t *)display->port[i])->pt_info->flags & + IGD_DISPLAY_ENABLE)) { + mode_context->dispatch->program_port(display, i+1, TRUE); + } + } + mode_context->dispatch->program_plane(display, TRUE); + mode_context->dispatch->program_pipe(display, TRUE); + + /* Disable command queues */ + if(context->mod_dispatch.cmd_control) { + for (i = 0; i < IGD_MAX_PIPE_QUEUES; i++) { + if (PIPE(display)->queue[i]) { + OS_DEBUG("Disabling command queue [%d]", i); + context->mod_dispatch.cmd_control( + PIPE(display)->queue[i], CMD_CONTROL_OFF); + } + } + } + break; + default: + break; + } + } + + OS_TRACE_EXIT; + return 0; +} /* end mode_pwr() */ + +/*! + * This function is used to save mode module register state. + * + * @param context SS level igd_context + * @param state pointer to module_state handle, where module_state_h is + * pointer to actual state + *@param flags should have IGD_REG_SAVE_MODE bit set for save + * + * @return 0 on success + * @return -IGD_INVAL on failure + */ +static int mode_save(igd_context_t *context, module_state_h *state, + unsigned long *flags) +{ + mode_state_t *mstate; + int i, ret; + igd_display_port_t *port = NULL; + inter_module_dispatch_t *md; + + OS_TRACE_ENTER; + + if (!state || !(*flags & IGD_REG_SAVE_MODE)) { + OS_ERROR_EXIT("NULL pointer to save mode state or" + " flags don't have IGD_REG_SAVE_MODE bit set."); + return -IGD_ERROR_INVAL; + } + + /* First allocate memory for mode state which includes pd states */ + mstate = OS_ALLOC(sizeof(mode_state_t)); + if (!mstate) { + OS_ERROR_EXIT("memory allocation failed."); + return -IGD_ERROR_NOMEM; + } + OS_MEMSET(mstate, 0, sizeof(mode_state_t)); + + md = &context->mod_dispatch; + + /* Call pd_save */ + port = NULL; + i = 0; + while ((port = md->dsp_get_next_port(context, port, 0)) != NULL) { + if (port->pd_driver) { + OS_DEBUG("saving %s", port->pd_driver->name); + ret = port->pd_driver->pd_save(port->pd_context, + &(mstate->pd_state[i].state), 0); + if (ret) { + OS_DEBUG("pd_save failed for %s", port->pd_driver->name); + } + + mstate->pd_state[i].port = port; + i++; + } + } + + /* Update mode state */ + *state = (module_state_h) mstate; + + OS_DEBUG("mode_save: saved %d port driver states.", i); + + OS_TRACE_EXIT; + return 0; +} /* end mode_save() */ + +/*! + * This function is used to save mode module register state. + * + * @param context SS level igd_context + * @param state pointer to module_state handle, where module_state_h is + * pointer to actual state + * *@param flags should have IGD_REG_SAVE_MODE bit set for restore + * + * @return 0 on success + * @return -IGD_INVAL on failure + */ +int mode_restore(igd_context_t *context, module_state_h *state, + unsigned long *flags) +{ + int i, ret; + igd_display_port_t *port = NULL; + mode_state_t *mstate; + + OS_TRACE_ENTER; + + if (!state || !(*flags & IGD_REG_SAVE_MODE)) { + OS_ERROR_EXIT("Null mode state.or trying to restore without a save"); + return 0; + } + + mstate = (mode_state_t *)(*state); + + if (!mstate) { + OS_DEBUG("mode_restore: mstate = NULL"); + OS_TRACE_EXIT; + return 0; + } + + /* Restore all PD drivers */ + i = 0; + while (mstate->pd_state[i].port) { + port = mstate->pd_state[i].port; + + OS_DEBUG("restoring %s", port->pd_driver->name); + ret = port->pd_driver->pd_restore(port->pd_context, + mstate->pd_state[i].state, 0); + if (ret) { + /* What can be done if restore fails */ + OS_DEBUG("pd_restore failed for %s", port->pd_driver->name); + } + + i++; + } + + /* Free the memory allocated */ + OS_FREE(mstate); + *state = NULL; + + OS_TRACE_EXIT; + return 0; +} /* end mode_restore() */ + +/*! + * + * @param cursor + * @param image + * @param rotate + * @param flip + * @param width + * @param height + * + * @return void + */ +static void load_argb_cursor_image(unsigned long *cursor, + unsigned long *image, + int rotate, int flip, + int width, int height) +{ + int w, h, x, y; + unsigned short nx, ny; + unsigned long *i; + + w = width; + h = height; + + /* make sure size is constrained to 64x64 */ + if (w > 64) { + w = 64; + } + if (h > 64) { + h = 64; + } + + /* Copy image */ + for (y = 0; y < h; y++) { + i = image; + image += width; + for (x = 0; x < w; x++) { + /* rotate, flip x,y here. No scaling! */ + nx = (unsigned short) x; + ny = (unsigned short) y; + igd_fb_to_screen((unsigned short) rotate, (unsigned char) flip, + 0, 0, 0, 64, 64, &nx, &ny, 0, 0); + cursor[nx + (64 * ny)] = *i++; + } + } +} + +/*! + * + * @param cursor + * @param image + * @param rotate + * @param flip + * @param width + * @param height + * + * @return void + */ +static void load_xor_cursor_image(unsigned char *cursor, + unsigned char *image, + int rotate, int flip, + int width, int height) +{ + int j, x, y; + int pixel_num, byte_num, line_num; + int npixel_num, nbyte_num, nline_num, nbit_num; + unsigned short nx, ny; + unsigned char b_val, sbit, mask, pixel; + + for (j = 0; j < 2; j++) { + cursor += (j * 8); + image += (j * 8); + for (y = 0; y < 64; y++) { + for (x = 0; x < 64; x++) { + pixel_num = x + (y * 64); + line_num = pixel_num / 64; + byte_num = (pixel_num & 63) / 8; + b_val = *(image + (16 * line_num) + byte_num); + pixel = (b_val >> ( 7 - (pixel_num & 7))) & 0x01; + + nx = (unsigned short) x; + ny = (unsigned short) y; + igd_fb_to_screen((unsigned short) rotate, (unsigned char) flip, + 0, 0, 0, (unsigned short) width, (unsigned short) height, + &nx, &ny, 0 , 0); + npixel_num = nx + (ny * 64); + nline_num = npixel_num / 64; + nbyte_num = (npixel_num & 63) / 8; + nbit_num = 7 - (npixel_num & 7); + b_val = *(cursor + (16 * nline_num) + nbyte_num); + + sbit = pixel << nbit_num; + mask = 0x01 << nbit_num; + b_val = (b_val & ~mask) | sbit; + *(cursor + (16 * nline_num) + nbyte_num) = b_val; + + /*(cursor + (16 * line_num) + byte_num) = b_val; */ + } + } + } +} + +/*! + * This function caclulates the correct cursor position from IAL + * provided coordinates. It takes into account hotspot, rotation, flip, + * and render_scale. + * + * This takes an x and y coordinate and sets the internal cursor + * info structure with the updated values. In addition, it + * sets a flag if the coordiantes are outside the displays active + * area. + * + * @param display + * @param x + * @param y + * @param hotx + * @param hoty + * + * @return void + */ +static void igd_set_cursor_pos(igd_display_context_t *display, + unsigned short x, unsigned short y, + unsigned short hotx, unsigned short hoty) +{ + igd_display_context_t *primary; + igd_cursor_info_t *internal_ci; + igd_display_info_t *timing; + igd_display_plane_t *plane; + unsigned char render_scale = 0; + unsigned short rotation, flip; + unsigned long cursor_state; + + if (!display || !PLANE(display) || !PIPE(display) || + !PIPE(display)->cursor || !PIPE(display)->cursor->cursor_info || + !PORT_OWNER(display) || !PORT_OWNER(display)->pt_info) { + return; + } + + internal_ci = PIPE(display)->cursor->cursor_info; + timing = PORT_OWNER(display)->pt_info; + plane = PLANE(display); + + rotation = (unsigned short) ((internal_ci->rotation & + IGD_RENDER_OP_ROT_MASK) >> 8) * 90; + flip = (unsigned short) (internal_ci->rotation & + IGD_RENDER_OP_FLIP) >> 10; + + /* + * Handle rotation, flip and render scale + * Note that the x,y arguments are unsigned, but cursor cordinates + * are signed and we need to preserve the signness when saving back + * into internal_ci structure! + */ + if ((internal_ci->render_scale_x > 0) || + (internal_ci->render_scale_y > 0)) { + render_scale = 1; + } else { + render_scale = 0; + } + + igd_fb_to_screen((unsigned short) rotation, (unsigned char) flip, + render_scale, + internal_ci->render_scale_x, internal_ci->render_scale_y, + (unsigned short) plane->fb_info->width, + (unsigned short) plane->fb_info->height, + &x, &y, + hotx, hoty); + + /* Adjust the x and y values relative to the current display offset */ + internal_ci->x_offset = (long)((short)x - (short)timing->x_offset); + internal_ci->y_offset = (long)((short)y - (short)timing->y_offset); + + + /* Adjust the cursor offset for rotation and flip */ + + switch (rotation) { + case 0: + if (flip) { + internal_ci->x_offset -= 63; + } + break; + case 90: + internal_ci->y_offset += 1; + if (!flip) { + internal_ci->y_offset -= 63; + } + break; + case 180: + internal_ci->x_offset += 1; + internal_ci->y_offset -= 63; + if (!flip) { + internal_ci->x_offset -= 63; + } + break; + case 270: + internal_ci->x_offset -= 63; + if (flip) { + internal_ci->y_offset -= 63; + } + break; + default: + break; + } + + display->context->mod_dispatch.dsp_get_dc(NULL, &primary, NULL); + if(display == primary) { + cursor_state = CURSOR_1_STATE; + } else { + cursor_state = CURSOR_2_STATE; + } + + /* + * When panning, the cursor can be positioned off screen. The hardware + * doesn't like it if this happens. Thus, we set a flag to indicate + * that the cursor is currently off screen. That way it can be + * turned off when actually programmed. + * + * This also moves the position so that it is at the very edge of the + * screen, just in case it is turned on. + */ + + internal_ci->off_screen &= ~cursor_state; + + /* Make sure the cursor is fully displayed */ + if (internal_ci->x_offset < -63) { + internal_ci->x_offset = -63; + internal_ci->off_screen |= cursor_state; + } + if (internal_ci->x_offset >= (long)timing->width) { + internal_ci->x_offset = timing->width - 1; + internal_ci->off_screen |= cursor_state; + } + if (internal_ci->y_offset < -63) { + internal_ci->y_offset = -63; + internal_ci->off_screen |= cursor_state; + } + if (internal_ci->y_offset >= (long)timing->height) { + internal_ci->y_offset = timing->height - 1; + internal_ci->off_screen |= cursor_state; + } + + return; +} + +/*! + * This function sets the cursor_info obtained from igd_alloc_cursor + * and programs the cursor + * + * @param display_handle + * @param cursor_info + * @param image + * + * @return -IGD_ERROR_INVAL on failure + * @return 0 on success + */ +int igd_alter_cursor(igd_display_h display_handle, + igd_cursor_info_t *cursor_info, + unsigned char *image) +{ + igd_display_context_t *display = (igd_display_context_t *) display_handle; + igd_display_context_t *display2; + igd_display_context_t *primary; + igd_cursor_info_t *internal_ci; + unsigned short rotation, flip; + unsigned long cursor_state; + unsigned long cursor_state2; + unsigned long *cursora = NULL; + unsigned char *cursorx = NULL; + + OS_TRACE_ENTER; + + OS_ASSERT(display, "Null Display Handle", -IGD_ERROR_INVAL); + OS_ASSERT(cursor_info, "Null cursor info", -IGD_ERROR_INVAL); + + if(validate_cursor(cursor_info, display)) { + OS_ERROR_EXIT("pixel_format validation failed."); + return -IGD_ERROR_INVAL; + } + + internal_ci = PIPE(display)->cursor->cursor_info; + + cursor_info->argb_offset = internal_ci->argb_offset; + cursor_info->xor_offset = internal_ci->xor_offset; + + rotation = (unsigned short) ((cursor_info->rotation & + IGD_RENDER_OP_ROT_MASK) >> 8) * 90; + flip = (unsigned short) (cursor_info->rotation & IGD_RENDER_OP_FLIP) >> 10; + + display->context->mod_dispatch.dsp_get_dc(NULL, &primary, NULL); + + /* If cursor plane is mirrored, then do the same for the other cursor */ + if (PIPE(display)->cursor->mirror != NULL) { + if(display == primary) { + display->context->mod_dispatch.dsp_get_dc(NULL, NULL, + &display2); + } else { + display2 = primary; + } + } + + /* + * Loading new cursor (for both primary and clone): + * 1. Blank cursor image: This can be avoided if new hotspot and + * new bitmap size are same as existing hotspot and image size. + * 2. Move cursor to new location accounting for new hotspot + * 3. Wait for vblank to load the new cursor to avoid flashing/tearing. + * This impacts performace tests as cursor shape changes several times + * while running/loading tests and this wait for vblank counts against + * test times. So going without a wait for vblank. If flashing/tearing + * becomes a must fix issue, then uncomment below wait_vblank(). + * 4. Load new image + */ + + if ((image != NULL) && (cursor_info->flags & IGD_CURSOR_LOAD_ARGB_IMAGE)) { +#ifdef PRE_KOHEO_CODE + cursora = (unsigned long *)OS_GART_MAP(0, internal_ci->argb_offset, + 0, display->context->device_context.virt_fb_adr); + + if(!cursora){ + cursora = (unsigned long *)(internal_ci->argb_offset + + display->context->device_context.virt_fb_adr); + } +#else /* PRE_KOHEO_CODE */ + unsigned long buffer_phys = 0; + + /* Calculate the cursor's address in kernel-space: */ + if (display->context->dispatch.gmm_virt_to_phys(internal_ci->argb_offset, + &buffer_phys)) { + OS_ERROR_EXIT("GMM Virtual to Physical Address translation failed"); + return -IGD_ERROR_INVAL; + } + + /* + * TODO: Verify that phys_to_virt returns a valid address for + * agp memory + */ + cursora = phys_to_virt(buffer_phys); + OS_DEBUG("ARGB cursor virtual address is 0x%p", cursora); + if (cursora == NULL) { + OS_ERROR_EXIT("Physical to Virtual Address translation failed"); + return -IGD_ERROR_INVAL; + } + +#endif /* PRE_KOHEO_CODE */ + /* Clear cursor plane */ + OS_MEMSET(cursora, 0, 64*64*4); + + } else if ((image != NULL) && + (cursor_info->flags & IGD_CURSOR_LOAD_XOR_IMAGE)) { + +#ifdef PRE_KOHEO_CODE + cursorx = (unsigned char *)(internal_ci->xor_offset + + display->context->device_context.virt_fb_adr); +#else /* PRE_KOHEO_CODE */ + unsigned long buffer_phys = 0; + + /* Calculate the cursor's address in kernel-space: */ + if (display->context->dispatch.gmm_virt_to_phys(internal_ci->xor_offset, + &buffer_phys)) { + OS_ERROR_EXIT("GMM Virtual to Physical Address translation failed"); + return -IGD_ERROR_INVAL; + } + + /* + * TODO: Verify that phys_to_virt returns a valid address for + * agp memory + */ + cursorx = phys_to_virt(buffer_phys); + OS_DEBUG("XOR cursor virtual address is 0x%p", cursorx); + if (cursorx == NULL) { + OS_ERROR_EXIT("Physical to Virtual Address translation failed"); + return -IGD_ERROR_INVAL; + } +#endif /* PRE_KOHEO_CODE */ + } + + /* calculate the cursor position adjusting to new hotspot */ + igd_set_cursor_pos(display, + (unsigned short)cursor_info->x_offset, + (unsigned short)cursor_info->y_offset, + (unsigned short)cursor_info->hot_x, + (unsigned short)cursor_info->hot_y); + + /* Update internal structure with altered data */ + internal_ci->pixel_format = cursor_info->pixel_format; + internal_ci->palette[0] = cursor_info->palette[0]; + internal_ci->palette[1] = cursor_info->palette[1]; + internal_ci->palette[2] = cursor_info->palette[2]; + internal_ci->palette[3] = cursor_info->palette[3]; + internal_ci->flags = cursor_info->flags; + internal_ci->rotation = cursor_info->rotation; + internal_ci->render_scale_x = cursor_info->render_scale_x; + internal_ci->render_scale_y = cursor_info->render_scale_y; + + if(display == primary) { + cursor_state = CURSOR_1_STATE; + cursor_state2 = CURSOR_2_STATE; + } else { + cursor_state = CURSOR_2_STATE; + cursor_state2 = CURSOR_1_STATE; + } + + if ((cursor_info->flags & IGD_CURSOR_ON) && + !(internal_ci->off_screen & cursor_state)) { + mode_context->dispatch->full->program_cursor(display, TRUE); + } else { + mode_context->dispatch->full->program_cursor(display, FALSE); + } + + if (PIPE(display)->cursor->mirror) { + igd_set_cursor_pos(display2, + (unsigned short)cursor_info->x_offset, + (unsigned short)cursor_info->y_offset, + (unsigned short)cursor_info->hot_x, + (unsigned short)cursor_info->hot_y); + + if ((cursor_info->flags & IGD_CURSOR_ON) && + !(internal_ci->off_screen & cursor_state2)) { + mode_context->dispatch->full->program_cursor(display2, TRUE); + } else { + mode_context->dispatch->full->program_cursor(display2, FALSE); + } + } + + /* Pitch may have been altered by program_cursor */ + cursor_info->xor_pitch = internal_ci->xor_pitch; + cursor_info->argb_pitch = internal_ci->argb_pitch; + + /* wait for VBLANK */ + /* mode_context->dispatch->wait_vblank(display); */ + + if ((image != NULL) && + (cursor_info->flags & IGD_CURSOR_LOAD_ARGB_IMAGE)) { + load_argb_cursor_image(cursora, (unsigned long *)image, rotation, flip, + cursor_info->width, cursor_info->height); + + } else if ((image != NULL) && + (cursor_info->flags & IGD_CURSOR_LOAD_XOR_IMAGE)) { + load_xor_cursor_image(cursorx, image, rotation, flip, + cursor_info->width, cursor_info->height); + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * This function programs the cursor position. It takes into account + * rotation, flip, and render_scale. It also knows about clone mode + * and manages the clone cursor automaticlly. + * + * @param display_handle + * @param cursor_info + * + * @return -IGD_INVAL on failure + * @return 0 on success + */ +int igd_alter_cursor_pos(igd_display_h display_handle, + igd_cursor_info_t *cursor_info) +{ + igd_display_context_t *display = (igd_display_context_t *) display_handle; + igd_display_context_t *display2 = NULL; + igd_cursor_info_t *internal_ci; + unsigned long cursor_on_screen; + unsigned long cursor_state=0; + + /* If there is no cursor, return immediately */ + if (!display || !PIPE(display) || !PIPE(display)->cursor) { + return -IGD_INVAL; + } + + if (PIPE(display)->cursor->mirror != NULL) { + display->context->mod_dispatch.dsp_get_dc(NULL, NULL, &display2); + if (display == display2) { + display->context->mod_dispatch.dsp_get_dc(NULL, &display2, NULL); + cursor_state = CURSOR_2_STATE; + } else { + cursor_state = CURSOR_1_STATE; + } + } + + /* Reset display2 if cursor isn't setup */ + if (display2) { + if (!PIPE(display2) || !PIPE(display2)->cursor) { + display2 = NULL; + } + } + + while (display) { + internal_ci = PIPE(display)->cursor->cursor_info; + cursor_on_screen = (internal_ci->off_screen & cursor_state); + + igd_set_cursor_pos(display, + (unsigned short)cursor_info->x_offset, + (unsigned short)cursor_info->y_offset, + (unsigned short)cursor_info->hot_x, + (unsigned short)cursor_info->hot_y); + + if (cursor_on_screen != + (internal_ci->off_screen & cursor_state)) { + /* + * Cursor has moved either on or off screen since the last + * call. If it has moved back on screen, turn the cursor + * back on. If it moved off screen, turn it off. + */ + if (internal_ci->off_screen & cursor_state) { + mode_context->dispatch->full->program_cursor(display, FALSE); + + } else if (cursor_info->flags & IGD_CURSOR_ON) { + /* + * Only program the cursor back on if the IAL already has it + * ON. This is to prevent the problem where the IAL turned + * of the cursor on purpose, e.g. a user app turns it off, and + * then have the HAL turn it back on when moving the cursor + * from one screen to another. + */ + mode_context->dispatch->full->program_cursor(display, TRUE); + } + } + + /* Program cursor position */ + if ((cursor_info->flags & IGD_CURSOR_ON) && + !(internal_ci->off_screen & cursor_state)) { + mode_context->dispatch->full->alter_cursor_pos( + (igd_display_h)display, internal_ci); + } + + /* Switch to the second display if it is mirrored */ + display = display2; + display2 = NULL; + /* Switch the cursor states as well */ + if(cursor_state == CURSOR_1_STATE) { + cursor_state = CURSOR_2_STATE; + } else { + cursor_state = CURSOR_1_STATE; + } + } + + return 0; +} + +/*! + * This function returns the current framebuffer and + * display information. + * + * @param hDisplay required. The hDisplay contains the display + * information to return. This parameter was returned from a + * previous call to igd_alloc_display(). + * @param port_number + * @param pFbInfo required and allocated by the caller. The pFbInfo + * struct is returned to the caller describing the current + * frame buffer. + * @param pPtInfo required and allocated by the caller. The + * pPtInfo struct is returned to caller describing the + * requested display parameters. + * @param ulFlags Currently not used + * + * @return -IGD_INVAL on failure + * @return 0 on success + */ +int igd_get_display( + igd_display_h hDisplay, + unsigned short port_number, + pigd_framebuffer_info_t pFbInfo, + pigd_display_info_t pPtInfo, + unsigned long ulFlags) +{ + igd_display_context_t *display = (igd_display_context_t *)hDisplay; + + OS_TRACE_ENTER; + + /* Check for NULL pointers */ + OS_ASSERT(pFbInfo, "Null FB Info", -IGD_ERROR_INVAL); + OS_ASSERT(pPtInfo, "Null PT Info", -IGD_ERROR_INVAL); + + /* If the port->pt_info isn't set that means it is called just after + * igd_alloc_display and before igd_alter_display(). So, just fill + * port_type into pPtInfo */ + if (PORT(display, port_number)->pt_info == NULL) { + OS_MEMSET(pPtInfo, 0, sizeof(igd_display_info_t)); + pPtInfo->flags = PORT(display, port_number)->port_type; + } else { + OS_MEMCPY(pPtInfo, PORT(display, port_number)->pt_info, + sizeof(igd_display_info_t)); + } + + if (PLANE(display)->fb_info == NULL) { + OS_MEMSET(pFbInfo, 0, sizeof(igd_framebuffer_info_t)); + } else { + OS_MEMCPY(pFbInfo, PLANE(display)->fb_info, + sizeof(igd_framebuffer_info_t)); + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * This function pans the display on the display device. + * It takes a x_offset, y_offset into the frame buffer and + * sets the display from (x_offset, y_offset) to + * (x_offset+width, y_offset+height). + * If x_offset+width, y_offset+height crosses frame buffer + * width and heigth, then it will return error. + * + * @param hDisplay pointer to an IGD_DISPLAY pointer returned + * from a successful call to igd_allocate_display(). + * @param x_offset frame buffer offsets from (0, 0) + * @param y_offset frame buffer offsets from (0, 0) + * + * @return -IGD_INVAL on failure + * @return 0 on success + */ +long igd_pan_display(igd_display_h hDisplay, + unsigned long x_offset, unsigned long y_offset) +{ + igd_display_context_t *display = (igd_display_context_t *)hDisplay; + igd_framebuffer_info_t *fb_info; + igd_display_info_t *pt_info; + unsigned long x_old; + + OS_TRACE_ENTER; + + OS_ASSERT((display && PORT_OWNER(display) && PORT_OWNER(display)->pt_info), + "Unvalid Display Handle", -IGD_ERROR_INVAL); + + fb_info = PLANE(display)->fb_info; + pt_info = PORT_OWNER(display)->pt_info; + + /* Check paning can be done or not */ + if (!fb_info || !pt_info) { + OS_ERROR_EXIT("Panning cannot be done. fb, pt infos weren't set."); + return -IGD_ERROR_INVAL; + } + + if (! (PORT_OWNER(display)->pt_info->flags & IGD_DISPLAY_ENABLE)) { + OS_DEBUG("Currently this display is not enabled."); + OS_TRACE_EXIT; + return -IGD_ERROR_INVAL; + } + + if ((pt_info->width == fb_info->width) && + (pt_info->height == fb_info->height)) { + OS_DEBUG("FB and display pt_info are same size, no paning."); + OS_TRACE_EXIT; + return 0; + } + + /* + address HSD 200474 (08/27/2008 + handle case primary: 1280x720 seconday:1024x768 + TODO (Chandra idea) + "ideally the FB 720 height should center on LVDS 768 height and pan across horizontally that is 1280 FB width pans on LVDS 1024 width." + */ + if (fb_info->height >= pt_info->height) { + if (pt_info->width + x_offset > fb_info->width || + pt_info->height + y_offset > fb_info->height) { + OS_ERROR_EXIT("invalid offsets are passing frame buffer."); + return -IGD_ERROR_INVAL; + } + } else { + if (pt_info->width + x_offset > fb_info->width ) { + OS_ERROR_EXIT("invalid offsets are passing frame buffer."); + return -IGD_ERROR_INVAL; + } + } + + /* Now do the paning. + * Note: Never change the fb_base_offset (it always points to the + * first pixel in the frame buffer), nor the visible_offset (it + * always points to the first pixel of the visible buffer). */ + /* TODO: How to know which fb we are using, frontbuffer/backbuffer? */ + + x_old = x_offset; + mode_context->dispatch->full->set_display_base(display, fb_info, + &x_offset, &y_offset); + + /* Save offsets into pt_info */ + pt_info->x_offset = (unsigned short)x_offset; + pt_info->y_offset = (unsigned short)y_offset; + + /* FIXME: + * This could be negative, and thus conflict with the error codes + * returned above. However, this is needed for Whitney to compensate + * for the framebuffer offset alignment requirements and should only + * be positive. + */ + OS_TRACE_EXIT; + return (x_offset - x_old); + +} /* end igd_pan_display() */ + +/*! + * This function get attributes for a port. SS will + * allocate the memory required to return the *attr_list. + * This is a live copy of attributes used by both IAL and SS. + * Don't deallocate this memory. This will be freed by SS. + * + * The list returned will contain a list of HAL attributes + * followed by a pointer to the PD attributes. + * + * @param driver_handle pointer to an IGD context pointer returned + * from a successful call to igd_init(). + * @param port_number port number of port to get pd attributes. + * @param num_attrs pointer to return the number of attributes + * returned in attr_list. + * @param attr_list - pointer to return the attributes. + * + * @return -IGD_INVAL on failure + * @return 0 on success + */ +int igd_get_attrs( + igd_driver_h driver_handle, + unsigned short port_number, + unsigned long *num_attrs, + igd_attr_t **attr_list) +{ + igd_context_t *context = (igd_context_t *)driver_handle; + igd_display_context_t *display; + int ret; + unsigned long hal_attrib_num, pd_attr_num; + igd_display_port_t *port; + igd_attr_t *pd_attr_list = NULL; + + + OS_TRACE_ENTER; + + /* basic parameter check */ + OS_ASSERT(driver_handle, "Null Driver Handle", -IGD_ERROR_INVAL); + + /* Get the display context that is currently using this port */ + context->mod_dispatch.dsp_get_display(port_number, &display, &port, 0); + + if(!display || !port) { + /* + * No display is using this port, + * should we abort at this point? + */ + OS_TRACE_EXIT; + printk(KERN_ALERT "[EGD] igd_get_attrs exiting: " + "No display is using port %d.\n", port_number); + return -IGD_ERROR_INVAL; + } + + /* Get PD attributes */ + pd_attr_num = *num_attrs; + ret = port->pd_driver->get_attrs( port->pd_context, + &pd_attr_num, + &pd_attr_list ); + + if (ret) { + pd_attr_num = 0; + pd_attr_list = NULL; + } + + /* find the extension attribute and attach the pd_attr_list */ + for (hal_attrib_num = 0; + PD_ATTR_LIST_END != port->attributes[hal_attrib_num].id; + hal_attrib_num++ ) { + + if (PD_ATTR_ID_EXTENSION == port->attributes[hal_attrib_num].id ) { + ((igd_extension_attr_t *)(&port->attributes[hal_attrib_num]))->extension = pd_attr_list; + } + } + + /* If attr_list is NULL then the caller is only interested in + * the number of attributes + */ + if( NULL != attr_list ) { + *attr_list = port->attributes; + } + + if (0 == pd_attr_num ) { + /* if there are no PD attributes, then subtract 1 from hal_attrib_num + * so that the "extension" attribute is not counted*/ + *num_attrs = hal_attrib_num - 1; + } else { + /* subtract 1 because we should not count the "extension" attribute */ + *num_attrs = hal_attrib_num + pd_attr_num - 1; + } + + OS_TRACE_EXIT; + return 0; +} /* end igd_get_attrs() */ + +/*! + * This function set attributes on a port. + * + * @param driver_handle pointer to an IGD context pointer returned + * from a successful call to igd_init(). + * @param port_number port number of port to get pd attributes. + * @param num_attrs pointer to return the number of attributes + * returned in attr_list. + * @param attr_list - pointer to return the attributes. + * + * @return -IGD_INVAL on failure + * @return 0 on success + */ +int igd_set_attrs( + igd_driver_h driver_handle, + unsigned short port_number, + unsigned long num_attrs, + igd_attr_t *attr_list) +{ + igd_context_t *context = (igd_context_t *)driver_handle; + igd_display_context_t *display; + igd_display_port_t *port; + igd_attr_t *attr; + unsigned int i; + + unsigned long num_attrs_set = 0; + int ret = 0, setmode = 0; + igd_timing_info_t *pd_timing_table = NULL; + + OS_TRACE_ENTER; + + /* basic parameter check */ + OS_ASSERT(driver_handle, "Null Driver Handle", -IGD_ERROR_INVAL); + + /* Get the display context that is currently using this port */ + context->mod_dispatch.dsp_get_display(port_number, &display, &port, 0); + if(!display || !port) { + /* No display is using this port, should we abort at this point? */ + return -IGD_ERROR_INVAL; + } + + if(num_attrs == 0) { + return 0; + } + + + /* + * Take care of HAL attributes. Here we keep track of the number of + * attributes set. If the number set is equal to num_attrs, then we + * don't need to call port driver's set_attr when this loop is done + */ + for( i = 0; i < num_attrs; i ++ ) { + switch (attr_list[i].id) { + case PD_ATTR_ID_FB_GAMMA: + case PD_ATTR_ID_FB_BRIGHTNESS: + case PD_ATTR_ID_FB_CONTRAST: + set_color_correct(display, (igd_range_attr_t *) &attr_list[i]); + num_attrs_set++; + break; + + default: + /* ignore all non HAL-related attributes */ + break; + } + } + + /* Pass the attribute list down to the port driver for futher processing + * if necessary */ + if (num_attrs > num_attrs_set) { + ret = port->pd_driver->set_attrs(port->pd_context, num_attrs, attr_list); + + if (ret) { + return -IGD_INVAL; + } + } + + attr = attr_list; + i = 0; + while (i++ < num_attrs) { + if (attr->flags & PD_ATTR_FLAG_SETMODE) { + setmode = 1; + break; + } + attr++; + } + + ret = 0; + if (setmode) { + /* Update internal timings */ + ret = port->pd_driver->get_timing_list(port->pd_context, + (pd_timing_t *)port->timing_table, + (pd_timing_t **)&pd_timing_table); + + if (ret) { + OS_ERROR_EXIT("get_timing_list failed."); + return -IGD_ERROR_INVAL; + } + + port->timing_table = pd_timing_table; + port->num_timing = get_native_dtd(pd_timing_table, + PI_SUPPORTED_TIMINGS, &port->fp_native_dtd, + PD_MODE_DTD_FP_NATIVE); + ret = IGD_DO_QRY_SETMODE; + } + + OS_TRACE_EXIT; + return ret; +} /* end igd_set_attrs() */ + +/*! + * + * @param display_h + * @param width + * @param height + * + * @return -IGD_ERROR_INVAL on failure + * @return 0 on success + */ +int mode_getresolution( + igd_display_h display_h, + unsigned long *width, + unsigned long *height) +{ + igd_display_context_t *display; + int ret = 0; + + if (display_h) { + display = (igd_display_context_t *) display_h; + + if (PORT_OWNER(display)->pt_info) { + *width = PORT_OWNER(display)->pt_info->width; + *height = PORT_OWNER(display)->pt_info->height; + ret = 0; + } + else { + ret = -IGD_ERROR_INVAL; + } + + } else { + ret = -IGD_ERROR_INVAL; + } + + return ret; +} + +/*! + * + * @param driver_handle A igd_driver_h type returned from a previous + * igd_init call. + * @param port_number + * @param port_info Returns the information about port + * + * @return -IGD_INVAL on failure + * @return 0 on success + */ +int igd_get_port_info(igd_driver_h driver_handle, + unsigned short port_number, + igd_port_info_t *port_info) +{ + igd_context_t *context = (igd_context_t *)driver_handle; + igd_display_port_t *port; + pd_port_status_t port_status; + int ret; + + OS_TRACE_ENTER; + + OS_ASSERT(driver_handle, "Invalid Driver Handle", -IGD_ERROR_INVAL); + + if(port_number >= (IGD_MAX_PORTS + 1)) { + OS_ERROR("Error, invalid port number. "); + return -IGD_INVAL; + } + + OS_MEMSET(port_info, 0, sizeof(igd_port_info_t)); + + context->mod_dispatch.dsp_get_display(port_number, NULL, &port, 0); + + if (!port || !port->pd_driver || !port->pd_driver->pd_get_port_status) { + OS_ERROR_EXIT("pd_get_port_status not implemented. "); + return -IGD_ERROR_INVAL; + } + + pd_strcpy(port_info->pd_name, port->pd_driver->name); + pd_strcpy(port_info->port_name, port->port_name); + + port_info->port_num = port->port_number; + OS_MEMCPY(&port_info->driver_version, port->pd_driver->version, + sizeof(pd_version_t)); + + ret = port->pd_driver->pd_get_port_status(port->pd_context, &port_status); + if (ret == PD_SUCCESS) { + if (port_status.connected == PD_DISP_STATUS_DETACHED) { + /* 0 = Not Connected */ + port_info->connected = 0; + } else { + /* PD_DISP_STATUS_ATTACHED, PD_DISP_STATUS_UNKNOWN */ + port_info->connected = 1; + } + } else { + port_info->connected = 1; + } + + port_info->display_type = port_status.display_type; + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param driver_handle A igd_driver_h type returned from a previous + * igd_init call. + * @param i2c_reg + * @param flags + * + * @return -IGD_INVAL on failure + * @return 0 on success + */ +int igd_access_i2c( + igd_driver_h driver_handle, + igd_i2c_reg_t *i2c_reg, + unsigned long flags) +{ + igd_context_t *context = (igd_context_t *)driver_handle; + unsigned char i; + unsigned long *gpio, num_gpio; + int ret = 0; + + OS_TRACE_ENTER; + + if (!driver_handle || !i2c_reg) { + return -IGD_INVAL; + } + + num_gpio = mode_context->dispatch->get_gpio_sets(&gpio); + + if (i2c_reg->bus_id >= num_gpio) { + OS_DEBUG("Invalid bus number specified."); + return -IGD_ERROR_INVAL; + } + + if ((unsigned long)(i2c_reg->reg + i2c_reg->num_bytes) > 0xFF) { + OS_DEBUG("Invalid number of %d bytes requested from reg 0x%x.", + i2c_reg->num_bytes, i2c_reg->reg); + return -IGD_ERROR_INVAL; + } + + if (flags == IGD_I2C_WRITE) { + pd_reg_t temp_reg[2]; + temp_reg[1].reg = PD_REG_LIST_END; + + /* I2C write operation */ + for (i=0; inum_bytes; i++) { + temp_reg[0].reg = i2c_reg->reg + i; + temp_reg[0].value = i2c_reg->buffer[i]; + ret = context->mod_dispatch.i2c_write_reg_list( + context, + gpio[i2c_reg->bus_id], + i2c_reg->i2c_speed, + i2c_reg->dab, + temp_reg, + 0); + if (ret) { + OS_DEBUG("i2c write error."); + break; + } + } + } else if (flags == IGD_I2C_READ) { + /* I2C read operation */ + ret = context->mod_dispatch.i2c_read_regs( + context, + gpio[i2c_reg->bus_id], + i2c_reg->i2c_speed, + i2c_reg->dab, + i2c_reg->reg, + i2c_reg->buffer, + i2c_reg->num_bytes); + if (ret) { + OS_DEBUG("i2c read error."); + } + } + + OS_TRACE_EXIT; + return ret; +} /* end igd_access_i2c() */ + +/*! + * + * @param driver_handle A igd_driver_h type returned from a previous + * igd_init call. + * @param port_number + * @param edid_version + * @param edid_revision + * @param edid_size + * + * @return -IGD_ERROR_INVAL or -IGD_ERROR_EDID on failure + * @return 0 on success + */ +/* FIXME: Move to PI */ +static int igd_get_EDID_info(igd_driver_h driver_handle, + unsigned short port_number, + unsigned char *edid_version, unsigned char *edid_revision, + unsigned long *edid_size) +{ + igd_context_t *context = (igd_context_t *)driver_handle; + igd_display_port_t *port; + int ret; + unsigned char temp_buf[25]; + unsigned char edid_1_3_header[] = { + 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00 + }; + + OS_TRACE_ENTER; + + if (!driver_handle || !edid_version || !edid_revision || !edid_size) { + return -IGD_ERROR_INVAL; + } + + context->mod_dispatch.dsp_get_display(port_number, NULL, &port, 0); + if(!port) { + return -IGD_ERROR_INVAL; + } + + /* Read EDID */ + ret = context->mod_dispatch.i2c_read_regs(context, + port->ddc_reg, + 10, /* DDC speed 10 KHz */ + port->ddc_dab, + 0x00, /* DDC Address */ + temp_buf, /* Read 20 bytes into temp_buf */ + 20); + if (ret) { + return -IGD_ERROR_EDID; + } + + /* Check for EDID version */ + if (!OS_MEMCMP((void *)temp_buf, (void *)edid_1_3_header, 8)) { + *edid_version = temp_buf[18]; + *edid_revision = temp_buf[19]; + *edid_size = 128; + + /* Read EDID byte 0x7E which gives the number of (optional) 128-byte + * EDID extension blocks to follow. */ + temp_buf[0] = 0; + ret = context->mod_dispatch.i2c_read_regs(context, + port->ddc_reg, + 10, /* DDC speed 10 KHz */ + port->ddc_dab, + 0x7E, /* DDC Address */ + &temp_buf[0], /* Read 1 byte into temp_buf */ + 1); + if (ret) { + return -IGD_ERROR_EDID; + } + + *edid_size += (temp_buf[0] * 128); + + } else { + *edid_version = temp_buf[0] >> 4; + if (*edid_version != 2) { + return -IGD_ERROR_EDID; + } + + *edid_revision = temp_buf[0] & 0x0F; + *edid_size = 256; + } + + OS_TRACE_EXIT; + return 0; +} /* end igd_get_EDID_info() */ + +/*! + * This function sets enables or disables a specific port. Or, if + * the port number passed in is zero, it applies the change to all + * ports associated with the display handle. + * + * @param driver_handle display handle. + * @param port_number port number to enable or disable (or zero). + * @param flag IGD_ENABLE or IGD_DISABLE + * @param test IGD_TEST or zero + * + * @return -IGD_INVAL on failure + * @return 0 on success + */ +static int igd_enable_port(igd_display_h display_handle, + unsigned short port_number, + unsigned long flag, + unsigned long test) +{ + igd_display_context_t *display; + igd_display_port_t *port; + int i; + int ret; + + OS_TRACE_ENTER; + + display = (igd_display_context_t *)display_handle; + + /* + * There are a number of things that will probably need to be checked. + * + * When enabling a port, make sure the display has pipe timings. + * + * When enabling a port and display_detect is on, make sure a display + * is detected before enabling the port. + * + * When enabling a port, check if it must be master, if so, the timings + * will need to be changed. + * + * When disabling a port, don't disable the only port allocated to the + * display. + * + * When disabling a port and it was the master, change timings to next + * allocated port. + */ + + if (!PIPE(display)->timing && (flag & IGD_DISPLAY_ENABLE)) { + OS_ERROR("port enable requested without pipe timings."); + return -IGD_ERROR_INVAL; + } + + if ((port_number > 0) && (port_number <= IGD_MAX_PORTS)) { + port = (igd_display_port_t *)display->port[port_number - 1]; + if (port == NULL) { + return -IGD_ERROR_INVAL; + } + + if (test == IGD_TEST) { + if ((port->pt_info->flags & IGD_DISPLAY_ENABLE) == + (flag & IGD_DISPLAY_ENABLE)) { + return 0; + } else { + return -IGD_ERROR_INVAL; + } + } + + if (flag & IGD_DISPLAY_ENABLE) { + /* Can we enable this port? */ + if (dsp_display_connected(display->context, port)) { + port->pt_info->flags |= IGD_DISPLAY_ENABLE; + } else { + return -IGD_ERROR_INVAL; + } + } else { + port->pt_info->flags &= ~IGD_DISPLAY_ENABLE; + } + } else if ((port_number == 0) && !(flag & IGD_DISPLAY_ENABLE)) { + /* special case, disable all ports */ + for (i = 0; i < IGD_MAX_PORTS; i++) { + if (display->port[i]) { + port = (igd_display_port_t *)display->port[i]; + port->pt_info->flags &= ~IGD_DISPLAY_ENABLE; + } + } + } + + /* Program ports to the proper enable/disable state */ + for(i = 0; i < IGD_MAX_PORTS; i++) { + if ((port = (igd_display_port_t *)display->port[i]) != NULL) { + if (!port_number || (port->port_number == port_number)) { + if (port->pt_info->flags & IGD_DISPLAY_ENABLE) { + ret = mode_context->dispatch->program_port(display, i+1, + TRUE); + } else { + ret = mode_context->dispatch->program_port(display, i+1, + FALSE); + } + if (ret != 0) { + OS_ERROR("programming port %d failed", i+1); + } + if (port->pt_info->flags & IGD_DISPLAY_ENABLE) { + /* Call post_program_port if port is getting enabled. */ + ret = mode_context->dispatch->post_program_port + (display, i+1, 0); + } else { + ret = 0; + } + if (ret != 0) { + OS_ERROR("post programming port %d failed", i+1); + } + } + } + } + + OS_TRACE_EXIT; + + return 0; +} + +/*! + * Free memory allocated to hold timing infomation. This must have been + * allocated using the igd_query_mode_list. + * + * @param mode_list + * + * @return void + */ +void igd_free_mode_list(igd_display_info_t *mode_list) +{ + if (mode_list) { + OS_FREE(mode_list); + } +} + +/*! + * Generate a mode list that is correct for the given pipe master and + * any twins. + * + * @param driver_handle + * @param dc + * @param mode_list + * @param port + * + * @return -IGD_ERROR_INVAL on failure + * @return 0 on success + */ +int full_mode_query(igd_driver_h driver_handle, + unsigned long dc, + igd_display_info_t **mode_list, + igd_display_port_t *port) +{ + igd_timing_info_t *tt; + igd_timing_info_t *xt; + int timings = 0; + + /* determine the size of the mode list including the extensions */ + tt = port->timing_table; + if (!tt) { + OS_ERROR("igd_query_mode_list: No Timings"); + return -IGD_ERROR_INVAL; + } + while (tt->width != IGD_TIMING_TABLE_END) { + /* + * Check here to see if this timing is valid on all other + * ports. If it is, then we'll add it to the list, otherwise + * it's skipped. + */ + if (tt->mode_info_flags & PD_MODE_SUPPORTED) { + timings++; + } + tt++; + + /* + * If reached the first table END, then check for timings + * added by the user or EDID. + */ + if ((tt->width == IGD_TIMING_TABLE_END) && tt->extn_ptr) { + tt = tt->extn_ptr; + } + } + timings++; /* add one for the terminating marker */ + + *mode_list = OS_ALLOC(sizeof(igd_timing_info_t) * timings); + if (*mode_list != NULL) { + /* Now build the new mode list */ + tt = port->timing_table; + xt = (igd_timing_info_t *)*mode_list; + while (tt->width != IGD_TIMING_TABLE_END) { + if (tt->mode_info_flags & PD_MODE_SUPPORTED) { + OS_MEMCPY(xt, tt, sizeof(igd_timing_info_t)); + xt++; + } + + tt++; + /* + * If reached the first table END, then check for timings + * added by the user or EDID. + */ + if ((tt->width == IGD_TIMING_TABLE_END) && tt->extn_ptr) { + tt = tt->extn_ptr; + } + } + /* copy end of list marker */ + OS_MEMCPY(xt, tt, sizeof(igd_timing_info_t)); + } else { + OS_ERROR("igd_query_mode_list: Memory allocation failure."); + return -IGD_ERROR_INVAL; + } + return 0; +} + +/*! + * This function is used to shutdown any module/dsp + * module specific structures or tables etc. + * + * @param context SS level igd_context. + * + * @return -IGD_INVAL on failure + * @return 0 on success + */ +static void mode_shutdown(igd_context_t *context) +{ + inter_module_dispatch_t *md; + module_state_h *mode_state = NULL; + unsigned long *flags = NULL; + + OS_DEBUG("mode_shutdown Entry"); + + /* + * Disable all the displays in decending pipe order + * Note: This isn't exactly device independent. It works for all + * multipipe platforms that we know of but is limited to 2 pipes + * and assumes that it is ok to disable pipe b before a. + */ + + dsp_wait_rb(mode_context->context); + + /* Reset all planes, pipe, ports to a known "off" state */ + mode_context->dispatch->reset_plane_pipe_ports(context); + + /* Shutdown dsp module */ + context->mod_dispatch.dsp_shutdown(context); + + /* Restore mode state */ + md = &context->mod_dispatch; + md->reg_get_mod_state(REG_MODE_STATE, &mode_state, &flags); + mode_restore(context, mode_state, flags); + + /* Shutdown PI module */ + context->mod_dispatch.pi_shutdown(context); + + /* + * Do not clear mode_context pointer. It needs to stay around until + * the very last thing. + * + * context->mode_context = NULL; + */ + + OS_DEBUG("Return"); + return; +} /* end mode_shutdown() */ + +/*! + * This function is used to shutdown any module/dsp + * module specific structures or tables etc. + * + * @param context SS level igd_context. + * @param mode_context mode module initialization parameters + * + * @return -IGD_INVAL on failure + * @return 0 on success + */ +int full_mode_init(igd_context_t *context, + mode_context_t *mode_context) +{ + igd_dispatch_t *dispatch = &context->dispatch; + + /* Hook up the IGD dispatch table entires for mode */ + dispatch->get_display = igd_get_display; + dispatch->pan_display = igd_pan_display; + dispatch->alter_cursor = igd_alter_cursor; + dispatch->alter_cursor_pos = igd_alter_cursor_pos; + dispatch->get_attrs = igd_get_attrs; + dispatch->set_attrs = igd_set_attrs; + dispatch->get_port_info = igd_get_port_info; + dispatch->access_i2c = igd_access_i2c; + dispatch->get_EDID_info = igd_get_EDID_info; + dispatch->free_mode_list = igd_free_mode_list; + dispatch->enable_port = igd_enable_port; + + /* Hook up optional inter-module functions */ + context->mod_dispatch.mode_save = mode_save; + context->mod_dispatch.mode_restore = mode_restore; + context->mod_dispatch.mode_pwr = mode_pwr; + context->mod_dispatch.mode_shutdown = mode_shutdown; + context->mod_dispatch.set_flip_pending = + mode_context->dispatch->full->set_flip_pending; + context->mod_dispatch.check_flip_pending = + mode_context->dispatch->full->check_flip_pending; + + /* Hook up Core specific IGD dispatch table entries */ + dispatch->set_palette_entry = mode_context->dispatch->set_palette_entry; + dispatch->get_scanline = mode_context->dispatch->full->get_scanline; + dispatch->wait_vsync = mode_context->dispatch->full->wait_vsync; + dispatch->query_in_vblank = mode_context->dispatch->full->query_in_vblank; + dispatch->get_surface = mode_context->dispatch->full->get_surface; + dispatch->set_surface = mode_context->dispatch->full->set_surface; + dispatch->query_event = mode_context->dispatch->full->query_event; + + /* Assign the fw_info structure and Zero-out the contents */ + mode_context->fw_info = &global_fw_info; + OS_MEMSET(mode_context->fw_info, 0, sizeof(fw_info_t)); + + /* Set the mode context quickboot options from the params */ + mode_context->quickboot = context->mod_dispatch.init_params->quickboot; + mode_context->seamless = context->mod_dispatch.init_params->qb_seamless; + mode_context->video_input = context->mod_dispatch.init_params->qb_video_input; + mode_context->splash = context->mod_dispatch.init_params->qb_splash; + + /* This will get the plane, pipe and port register values and fill up the + * fw_info data structure. This needs to be done at INIT time b4 the driver + * alters any hardware registers. + */ + if(mode_context->seamless == TRUE) { + get_fw_info(mode_context); + } + + return 0; +} /* end full_mode_init() */ + +/*! + * This function clears the framebutffer. + * + * @param mode_context mode module initialization parameters + * @param fb_info + * + * @return void + */ +void full_clear_fb(mode_context_t *mode_context, + igd_framebuffer_info_t *fb_info) +{ + unsigned short line, index; + unsigned char *fb; + + fb = mode_context->context->dispatch.gmm_map(fb_info->fb_base_offset); + OS_DEBUG("After gmm_map(), fb = 0x%p", fb); + for (line = 0; line < fb_info->height; line++) { + for(index = 0; index < fb_info->screen_pitch; index++) { + OS_MEMSET(fb + + (unsigned long)line * + (unsigned long)fb_info->screen_pitch + + index, + (mode_context->display_color>> + ((index%sizeof(unsigned long)) * 8)) & + 0xFF, + 1); + } + } + mode_context->context->dispatch.gmm_unmap(fb); +} + +/*! + * This is done in an attempt to re-use the plane and cursor allocated + * to a port when that port is moved to a new display handle. The basic + * case is when the DC changes in this way: + * + * 0x00200058 -> 0x00000021 + * 0x00000021 -> 0x00200058 + * + * In both these cases, it is better if the plane and cursor are sticky + * to port 2. + * + * @param void + * + * @return void + */ +void swap_fb_cursor( void ) +{ + igd_plane_t *display_plane1, *display_plane2; + igd_display_pipe_t *pipe1, *pipe2; + void *tmp; + + mode_context->context->mod_dispatch.dsp_get_planes_pipes( + &display_plane1, &display_plane2, + &pipe1, &pipe2); + + /* Swap the plane info data */ + if (display_plane1 && display_plane2) { + + tmp = display_plane1->plane_info; + display_plane1->plane_info = display_plane2->plane_info; + display_plane2->plane_info = tmp; + } + + /* Swap the cursor info */ + if (pipe1 && pipe2 && pipe1->cursor && pipe2->cursor) { + + tmp = pipe1->cursor->cursor_info; + pipe1->cursor->cursor_info = pipe2->cursor->cursor_info; + pipe2->cursor->cursor_info = tmp; + } +} + +/*! + * This function calculates target X and Y coordincates + * for a provided front buffer dimension after including + * corrections for render-scaling, rotation and flipping. + * + * @param rotation 0, 90, 180 or 270 + * @param do_flip 0 or 1 + * @param do_rscale 0 or 1 + * @param x_rnd_scale fixed point int = (native_width << 16) / fb_width + * @param y_rnd_scale fixed point int = (native_height << 16) / fb_height + * @param front_width front buffer width for this pipe + * @param front_height front buffer height for this pipe + * @param x + * @param y + * @param hotx + * @param hoty + * + * @return void + */ +void igd_fb_to_screen(unsigned short rotation, + unsigned char do_flip, unsigned char do_rscale, + unsigned long x_rnd_scale, unsigned long y_rnd_scale, + unsigned short front_width, unsigned short front_height, + unsigned short *x, unsigned short *y, + unsigned short hotx, unsigned short hoty) +{ + unsigned short x_temp; + unsigned short y_temp; + + /* + * we only need to up(or down)-scale the coordinates of + * of the cursor when we are moving the cursor... dont care + * about scaling the cursor image itself + */ + if(do_rscale){ + unsigned long phys_x_pos_scale = x_rnd_scale; + unsigned long phys_y_pos_scale = y_rnd_scale; + + if(rotation == 90 || rotation == 270) { + phys_x_pos_scale = y_rnd_scale; + phys_y_pos_scale = x_rnd_scale; + } + + /* Added code to fix rounding error */ + if(*x & 0x8000) { + /* if its a negative x_offset, we need to put in additional + * type casting so the negative signage doesnt get scaled up + * and down and end up being a very large positive number + */ + *x = (unsigned short)(-(short)((((unsigned long ) + ((short)-*x) * phys_x_pos_scale) + ((1<<15)-1)) >> 16)); + } else { + *x = (unsigned short)((((unsigned long)*x * phys_x_pos_scale) + ((1<<15)-1)) >> 16); + } + + if(*y & 0x8000) { + /* if its a negative y_offset, we need to put in additional + * type casting so the negative signage doesnt get scaled up + * and down and end up being a very large positive number + */ + *y = (unsigned short)(-(short)((((unsigned long ) + ((short)-*y) * phys_y_pos_scale) + ((1<<15)-1)) >> 16)); + } else { + *y = (unsigned short)((((unsigned long)*y * phys_y_pos_scale) + ((1<<15)-1)) >> 16); + } + } + + *x -= hotx; + *y -= hoty; + + x_temp = *x; + y_temp = *y; + + switch(rotation) { + case 0: + default: + if(do_flip) { + *x = front_width-1 - x_temp; + } + break; + case 90: + *x = y_temp; + *y = (front_height - 1) - x_temp; + if(do_flip) { + *y = front_height-1 - *y ; + } + break; + case 180: + /* This is accurate for a 180 rotate */ + *x = (front_width -1) - x_temp; + *y = (front_height-1) - y_temp; + if(do_flip) { + *x = (front_width -1) - *x; + } + break; + case 270: + *x = (front_width - 1) - y_temp; + *y= x_temp; + if(do_flip) { + *y = (front_height -1) - *y; + } + break; + } +} + +/* Get the firmware programmed information b4 + * the driver starts re-programming it. + */ +static int get_fw_info(mode_context_t *mode_context) +{ + int ret = 0; + int seamless = FALSE; + OS_TRACE_ENTER; + + if(mode_context->fw_info != NULL) { + seamless = TRUE; + + do { + ret = mode_context->dispatch->full->get_plane_info(); + if(ret) { + seamless = FALSE; + break; + } + + ret = mode_context->dispatch->full->get_pipe_info(); + if(ret) { + seamless = FALSE; + break; + } + + ret = mode_context->dispatch->full->get_port_info(); + if(ret) { + seamless = FALSE; + break; + } + + } while (0); + + } + + if(seamless == FALSE) { + /* If one of these plane/pipe/port functions + * returns an error, we explicitly + * turn-off seamless. + */ + mode_context->seamless = FALSE; + + } + OS_TRACE_EXIT; + return 0; +} + +/*! + * Compare the incoming dc, timing, fb with the one that + * the firmware has already programmed and see if seamless + * is possible. + * + * @param dc + * @param index 0 for primary and 1 for secondary + * @param pt + * @param pf + * @param flags Not used right now + * + * @return TRUE if seamless is possible + * @return FALSE if not possible + */ +int query_seamless(unsigned long dc, + int index, + igd_timing_info_t *pt, + igd_framebuffer_info_t *pf, + unsigned long flags) +{ + int ret = FALSE; + igd_display_info_t *timing; + igd_framebuffer_info_t *fb_info; + + OS_TRACE_ENTER; + OS_DEBUG("Incoming dc = 0x%08lx", dc); + + /* Get the fw programmed DC from the inter-module data + * structure + */ + mode_context->fw_info->fw_dc = + mode_context->context->mod_dispatch.dsp_fw_dc; + + if(dc != mode_context->fw_info->fw_dc) { + /* DC doesn't match */ + return FALSE; + } + + /* Note: this test both overcomes a compiler warning, as well as a + * potential kernel Oops from chasing a NULL pointer: + */ + if ((pt == NULL) || (pf == NULL)) { + return FALSE; + } + OS_DEBUG("Incoming Timing Width = %hu", pt->width); + OS_DEBUG("Incoming Timing height = %hu", pt->height); + OS_DEBUG("Incoming Timing Refresh = %hu", pt->refresh); + + /* Check pipe Timings */ + if(pt != NULL) { + timing = &mode_context->fw_info->timing_arr[index]; + ret = FALSE; + + if( (timing->width == pt->width) && + (timing->height == pt->height) && + (timing->refresh == pt->refresh) ) { + + ret = TRUE; + } + } + + OS_DEBUG(" "); + OS_DEBUG("Firmware Timing Width = %hu", timing->width); + OS_DEBUG("Fimrware Timing Height = %hu", timing->height); + OS_DEBUG("Fimrware Timing Refesh = %hu", timing->refresh); + OS_DEBUG("-------------------------"); + + if(ret == FALSE) { + OS_DEBUG("Incoming Timings and Firmware Timings Do NOT match!"); + OS_DEBUG("Seamless is NOT possible"); + OS_TRACE_EXIT; + return ret; + } + + + OS_DEBUG("Incoming FB Width = %u", pf->width); + OS_DEBUG("Incoming FB Height = %u", pf->height); + OS_DEBUG("Incoming FB Pitch = %u", pf->screen_pitch); + + /* Check Plane information */ + if(pf != NULL) { + fb_info = &mode_context->fw_info->fb_info[index]; + ret = FALSE; + + if( (fb_info->screen_pitch != pf->screen_pitch) || + (fb_info->width != pf->width) || + (fb_info->height != pf->height) ) { + + /* If width, height or pitch is different + * Don't have to turn-off pipe, just update + * the registers with the new values. + * Later we just call program_plane to update + * the registers. + */ + mode_context->fw_info->program_plane = 1; + ret = TRUE; + } + + } + + OS_DEBUG(" "); + OS_DEBUG("Firmware FB Width = %u", fb_info->width); + OS_DEBUG("Firmware FB Height = %u", fb_info->height); + OS_DEBUG("Firmware FB Pitch = %u", fb_info->screen_pitch); + OS_DEBUG("-----------------------"); + + OS_DEBUG("value of ret = %d", ret); + + OS_TRACE_EXIT; + return ret; +} /* end of query_seamless */ + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: igd_mode.c,v 1.16 2010/05/04 16:14:22 ndvanhox Exp $ + *---------------------------------------------------------------------------- + */ diff --git a/drivers/gpu/drm/emgd/emgd/display/mode/cmn/match.c b/drivers/gpu/drm/emgd/emgd/display/mode/cmn/match.c new file mode 100755 index 0000000..168c68d --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/mode/cmn/match.c @@ -0,0 +1,1319 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: match.c + * $Revision: 1.4 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.mode + + +#define CURSOR_DEFAULT_WIDTH 64 +#define CURSOR_DEFAULT_HEIGHT 64 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "match.h" + +/*! + * @addtogroup display_group + * @{ + */ + +/* Local variables */ +#ifndef CONFIG_MICRO +igd_cursor_info_t default_cursor = { + CURSOR_DEFAULT_WIDTH, + CURSOR_DEFAULT_HEIGHT, + CONFIG_DEFAULT_PF, + 0, 0, 0, 0, 0, 0, + 0, 0, {0, 0, 0, 0}, IGD_CURSOR_ON, 0, 0, 0, 0 +}; + +/*! + * + * @param cursor_info + * @param display + * + * @return -IGD_INVAL on failure + * @return 0 on success + */ +int validate_cursor(igd_cursor_info_t *cursor_info, + igd_display_context_t *display) +{ + unsigned long *list_pfs; + igd_display_pipe_t *pipe = (igd_display_pipe_t *)(display->pipe); + + OS_TRACE_ENTER; + if (pipe) { + if (pipe->cursor) { + list_pfs = pipe->cursor->pixel_formats; + + while (*list_pfs) { + if (cursor_info->pixel_format == *list_pfs) { + return 0; + } + list_pfs++; + } + } + } + + OS_TRACE_EXIT; + return -IGD_INVAL; +} +#endif + +/*! + * + * @param timing + * @param pt_info + * + * @return void + */ +static void fill_pt( + igd_timing_info_t *timing, + pigd_display_info_t pt_info) +{ + unsigned long flags; + + OS_DEBUG("fill_pt Entry"); + + /* preserve existing pt_info flags */ + flags = pt_info->flags; + + /* Simply memcpy the structures and fix up the flags */ + OS_MEMCPY(pt_info, timing, sizeof(igd_timing_info_t)); + + pt_info->flags |= flags; + + /* pt_info doesn't require a IGD_MODE_VESA flag, so clear IGD_MODE_VESA + * Setting this flag creates issues in match mode. */ + pt_info->flags &= ~IGD_MODE_VESA; + return; +} + +#ifndef CONFIG_NEW_MATCH + + +extern igd_timing_info_t vga_timing_table[]; +extern igd_timing_info_t crt_timing_table[]; + + +#define MATCH_MOD(x) ((x>0)?x:-x) +#define MATCH_EXACT 0x01 +#define MATCH_NATIVE 0x02 +#define MATCH_CENTER 0x10 +#define MATCH_FOR_VGA 0x20 + +/*! + * + * @param display + * @param timing_table + * @param pt_info + * @param type + * + * @return NULL on failure + * @return timing on success + */ +static igd_timing_info_t *match_resolution( + igd_display_context_t *display, + igd_timing_info_t *timing_table, + igd_display_info_t *pt_info, + int type) +{ + igd_timing_info_t *timing; + igd_timing_info_t *match; + igd_timing_info_t *native_match = NULL; + igd_display_port_t *port; + + OS_DEBUG("Enter match_resolution"); + + OS_DEBUG("Width=%d, height=%d, refresh=%d mode_number=0x%x", + pt_info->width, pt_info->height, pt_info->refresh, + pt_info->mode_number); + + timing = timing_table; + match = NULL; + port = PORT_OWNER(display); + + /* + * Note on Native matching. + * The Ideal thing is for a fp_native_dtd to already be marked as such. + * If there is no native timing indicated then we must choose what is + * most likely correct. + * If the mode is not VGA then we should choose any DTD that closely + * matches the mode being set. Failing that we should choose any timing + * that closely matches the mode. + * If the mode is VGA then we should take the current mode as it is + * more likely correct. + */ + if(type == MATCH_NATIVE) { + if(port->fp_native_dtd) { + OS_DEBUG("Returning quick with a native match"); + + OS_DEBUG("NATIVE Width=%d, height=%d, refresh=%d mode_num=0x%x", + port->fp_native_dtd->width, port->fp_native_dtd->height, + port->fp_native_dtd->refresh, port->fp_native_dtd->mode_number); + + return port->fp_native_dtd; + } + if((pt_info->flags & IGD_MODE_VESA) && + (pt_info->mode_number <= 0x13)) { + if(PIPE(display)->timing) { + native_match = PIPE(display)->timing; + } + } + } + + while (timing->width != IGD_TIMING_TABLE_END) { + if(!(timing->mode_info_flags & IGD_MODE_SUPPORTED)) { + timing++; + continue; + } + + if(type == MATCH_NATIVE) { + if(timing->mode_info_flags & IGD_MODE_DTD_FP_NATIVE) { + port->fp_native_dtd = timing; + return timing; + } + + if(port->fp_info) { + /* + * We may have only fp_width and fp_height which is really + * not enough information to be useful. If we find a + * matching width and height we'll keep the first one while + * still hoping to find an actual native mode later. + */ + if(!match && + (port->fp_info->fp_width == + (unsigned long)timing->width) && + (port->fp_info->fp_height == + (unsigned long)timing->height)) { + match = timing; + } + } else { + /* + * Keep a match because in the event that we never find a + * native DTD then we will just take the exact match. + */ + if(!match && + (timing->width == pt_info->width) && + (timing->height == pt_info->height) && + (timing->refresh == pt_info->refresh)) { + match = timing; + } + } + + /* + * If it is a DTD then keep it only if it is better than any + * found before. + */ + if(timing->mode_info_flags & IGD_MODE_DTD_USER) { + if(native_match) { + if(MATCH_MOD((int)(pt_info->width*pt_info->height) - + (native_match->width * native_match->height)) > + MATCH_MOD((int)(pt_info->width*pt_info->height) - + (timing->width*timing->height))) { + native_match = timing; + } + } else { + native_match = timing; + } + } + } else if (type == MATCH_EXACT) { + /* + * Looking for an exact match. For VGA/VESA it must match + * mode number. Otherwise it must match width, height, refresh + * etc. + */ + if(pt_info->flags & IGD_MODE_VESA) { + /* ((timing->mode_info_flags & IGD_MODE_VESA)) */ + if((pt_info->mode_number == timing->mode_number) && + (!pt_info->refresh || + (pt_info->refresh == timing->refresh))) { + match = timing; + break; + } + } else { + /* If exact match found, then break the loop */ + if((timing->width == pt_info->width) && + (timing->height == pt_info->height) && + (timing->refresh == pt_info->refresh) && + ( + (timing->mode_info_flags & + (IGD_SCAN_INTERLACE|IGD_PIXEL_DOUBLE| + IGD_LINE_DOUBLE)) == + (pt_info->flags & + (IGD_SCAN_INTERLACE|IGD_PIXEL_DOUBLE| + IGD_LINE_DOUBLE)))) { + match = timing; + + /* If exact match found, then break the loop */ + if ((timing->mode_info_flags & PD_MODE_DTD_USER) || + (timing->mode_info_flags & PD_MODE_DTD)) { + break; + } + } + } + } + + + /* Center needs only to be bigger. Aspect ratio doesn't matter. */ + /* + * Note: The timings have to be big enough to fit the pt_info + * including any pixel double flags. VGA modes will sometimes be + * pixel doubled and need to be centered in a pipe that is double + * in size. + * + * Note2: 720x400 VGA modes can be centered in 640x480 with a + * special hardware config that drops every 9th pixel. Only do + * this when requested. + */ + else if(type & MATCH_CENTER) { + unsigned short eff_width = pt_info->width; + unsigned short eff_height = pt_info->height; + + if(type & MATCH_FOR_VGA) { + /* + * 720x400 is a magic mode that means all VGA modes are supported + * always use that mode for centering if found. + */ + if((timing->width == 720) && (timing->height == 400)) { + OS_DEBUG("Returning with a magic VGA mode"); + return timing; + } + if(pt_info->flags & IGD_PIXEL_DOUBLE) { + eff_width *= 2; + } + if(pt_info->flags & IGD_LINE_DOUBLE) { + eff_height *= 2; + } + if((eff_width == 720) && + (port->port_features & IGD_VGA_COMPRESS)) { + eff_width = 640; + } + } + + if((timing->width >= eff_width) && + (timing->height >= eff_height) && + (timing->mode_info_flags & IGD_SCAN_INTERLACE) == + (pt_info->flags & IGD_SCAN_INTERLACE)) { + if(match) { + /* Check for tighter fit */ + if((match->width > timing->width) || + (match->height > timing->height)) { + match = timing; + } + /* Try to match refreshrate as well */ + if((match->width == timing->width) && + (match->height == timing->height) && + (pt_info->refresh == timing->refresh)){ + match = timing; + } + } else { + match = timing; + } + } + } + timing++; + } + + if(native_match) { + OS_DEBUG("Returning with a native match"); + OS_DEBUG("Width=%d, height=%d, refresh=%d mode_number=0x%x", + native_match->width, native_match->height, native_match->refresh, + native_match->mode_number); + return native_match; + } + if (!match) { + OS_DEBUG("Returning with NO match"); + return NULL; + } + + OS_DEBUG("Returning with a match"); + OS_DEBUG("Width=%d, height=%d, refresh=%d mode_number=0x%x", + match->width, match->height, match->refresh, match->mode_number); + return match; +} /* end match_resolution */ + +static igd_timing_info_t scaled_timing[IGD_MAX_PIPES]; + +/*! + * Match the fb and pt structures to a Mode Structure from the table. + * When a mode is found update the input structures to reflect the + * values found. + * + * Notes: + * Match mode has several options for what it can do. Foremost it should + * attempt to find a mode matching the requested one from the timing table + * provided. If the mode requested is not in the list this means one of + * two things. + * 1) The IAL is calling without checking modes. It is just passing down + * something that a user asked for. This is ok but we need to be safe so + * we return the next smaller mode with the same aspect ratio. + * + * 2) The IAL is requesting a very common "required" mode even though the + * port doesn't support it. In this case it should be in the static common + * modes table and can be centered in the next larger timings in the + * mode table. + * + * If the Frambuffer is smaller than the timings requested a fake set of + * centered timings is returned to program the pipe. + * + * In the case of VGA modes. If the mode is in the mode table everything is + * fine and we just return that. If it is not in the table we find the next + * larger suitable mode and prepare to center in that mode. Using the static + * timings from the VGA table as the VGA mode. We do not need to generate + * a fake set of timings because VGA will center itself automatically in + * hardware. + * + * In the case of LVDS both centering and scaling can happen. If the mode + * is in the list it will be scaled to the Native Timings. If the mode + * is not in the list (common or VGA) it will be centered in the next larger + * supported mode and then scaled to the native timings. + * + * Centering is always indicated by returning the timings that should be + * programmed to the pipe. The timings will then have their extension pointer + * set to point to the centered timings. For centering with scaling the + * first extension pointer will contain the scalable timings and the + * second will contain the centering timings. The static "scaled_timings" + * data structure will be used when the scaled timings need to be + * created on the fly due to a Framebuffer that is smaller than the + * timings. + * + * @param display + * @param timing_table + * @param fb_info + * @param pt_info + * @param timing + * + * @return -IGD_ERROR_INVAL on failure + * @return 0 on success + */ +int match_mode ( + igd_display_context_t *display, + igd_timing_info_t *timing_table, + igd_framebuffer_info_t *fb_info, + igd_display_info_t *pt_info, + igd_timing_info_t **timing) +{ + igd_timing_info_t *exact_timing = NULL; + igd_timing_info_t *pipe_timing = NULL; + igd_timing_info_t *user_timing = NULL; + igd_timing_info_t *native_timing = NULL; + igd_timing_info_t *vga_timing = NULL; + igd_timing_info_t *vesa_timing = NULL; + short cntr_dff_w = 0; + short cntr_dff_h = 0; + unsigned long upscale = 0; + + OS_DEBUG("Enter Match Mode"); + + if(!pt_info) { + OS_ERROR("NULL Port info detected, returning"); + return -IGD_ERROR_INVAL; + } + + /* Check for default case */ + if (!(pt_info->flags & IGD_MODE_VESA) && + (pt_info->width == 0) && (pt_info->height == 0)) { + OS_DEBUG("Display Info width, height are zero, using default case"); + pt_info->width = CONFIG_DEFAULT_WIDTH; + pt_info->height = CONFIG_DEFAULT_HEIGHT; + } + + OS_DEBUG("Checking for exact mode match"); + exact_timing = match_resolution(display, timing_table, pt_info, + MATCH_EXACT); + /* + * At this point we have one of these cases: + * 1) Found an exact match, VGA, VESA or other. + * -> Go check for FB centering and finish up. + * 2) Found nothing + * -> Check for VGA/VESA mode to center. + * -> Check common modes. + */ + if(exact_timing) { + pipe_timing = exact_timing; + user_timing = exact_timing; + pipe_timing->extn_ptr = NULL; + } else { + /* No match found? Is it VGA? */ + if( (pt_info->flags & IGD_MODE_VESA) && + (pt_info->mode_number < 0x1D) ){ + OS_DEBUG("Checking for exact match in VGA table"); + /* this only happens if it was a VGA mode number */ + pt_info->refresh = 0; + vga_timing = match_resolution(display, vga_timing_table, + pt_info, MATCH_EXACT); + + if(!vga_timing) { + return -IGD_ERROR_INVAL; + } + + vga_timing->extn_ptr = NULL; + /* We got something sane that needs to be centered */ + user_timing = vga_timing; + fill_pt(vga_timing,pt_info); + + /* continue at the bottom where we have + * pipe_timing = NULL, so we will look + * for centered timings for pt_info and + * use cmn_vga_timings to tell match_resolution + * to take into account special VGA mode + * centering regulations + */ + } + } + + /* Find UPSCALING attr value*/ + pi_pd_find_attr_and_value(PORT_OWNER(display), + PD_ATTR_ID_PANEL_FIT, + 0,/*no PD_FLAG for UPSCALING */ + NULL, /* dont need the attr ptr*/ + &upscale); + /* this PI func will not modify value of upscale if attr does not exist */ + + if(!pipe_timing){ + /* At this point, one of 2 things has happenned: + * - we have a mode request that we could not match exactly. + * and it WASNT a VESA_MODE number request. + * - we have a request based on VESA_MODE number (maybe from + * VBIOS IAL) and we could not get a exact match from the + * port_timing_table, but we did get a match from the vga- + * timing_table. + * In this case, there is one thing to do - MATCH_CENTER. Match + * resolution will handle it this way: + * - if its VESA MODE number based, we only need to get + * the best (tightest) match if its VGA OR DONT match + * if its one of those magic timings + * - Else, we need to get the best (tightest) match, AND + * we need to center requested timings in that tightest fitting + * timing. But wait! This could mean if the requested pt_info + * is bigger than anything in the port timing table, we have + * no choice but to fail. + */ + unsigned char match_type = MATCH_CENTER; + + OS_DEBUG("Checking for a safe centered match"); + if(vga_timing) { + match_type |= MATCH_FOR_VGA; + } else if(pt_info->flags & IGD_MODE_VESA) { + /* if a vesa mode number was requested... + * and we are centering that mode, we + * need to get the common mode fb size + * in case we need it later for VBIOS + * which doesnt populate the FBInfo + */ + vesa_timing = match_resolution(display, crt_timing_table, + pt_info, MATCH_EXACT); + } + + if (upscale && vga_timing) { + /* If port supports upscaling and match is called for VGA, + * then center vga mode resolution directly in the native mode + * instead of centering VGA in another resolution */ + pipe_timing = vga_timing; + } else { + pipe_timing = match_resolution(display, timing_table, pt_info, + match_type); + /* This can happen if there is a spurious pt_info from IAL */ + if (!pipe_timing) { + return -IGD_ERROR_INVAL; + } + pipe_timing->extn_ptr = vga_timing; + /* for the case of non VGA mode call, + * at this point, vga_timing is NULL + */ + } + + if(!vga_timing) { + user_timing = pipe_timing; + } + } + + /* + * At this point pipe_timing is what we are going to program the + * pipe to roughly speaking. If there is a common timing then we + * want it centered in the pipe_timing. + * + * If the framebuffer is smaller than the timings then we need to + * generate a centered set of timings by copying the pipe timings + * and shifting them a bit. + * + * If fb width and height are zero just assume that we want it to + * match the timings and make up a pixel format. This is mostly because + * VGA/VESA modes will just be set by number. We don't know their size + * until we look up the number. + */ + if(fb_info) { + /* + * fb_info is sometimes NULL when just testing something. + */ + if(!fb_info->pixel_format) { + /* Ugly VGA modes, it doesn't matter */ + fb_info->pixel_format = IGD_PF_ARGB8_INDEXED; + } + if(!fb_info->width) { + if(vga_timing) { + fb_info->width = vga_timing->width; + fb_info->height = vga_timing->height; + } else { + if(!vesa_timing){ + vesa_timing = pipe_timing; + /* in case vesa_timing is false set it to + * pipe_timing so we dont need to check for + * validity later, when increasing fb size for + * VBIOS in clone mode (see 18 lines below) + */ + } + fb_info->width = vesa_timing->width; + fb_info->height = vesa_timing->height; + } + } + + /* + * VGA common timings are centered in pipe timings by hardware. + * Otherwise we need to adjust the timings when centering is + * needed. + */ + if (!vga_timing) { + /* + * For VBIOS clone modes the FB should be the biggest mode + * if this is the second match we may need to update the fb + * data structure. + */ + if(fb_info->flags & IGD_VBIOS_FB) { + if ((fb_info->width < vesa_timing->width) || + (fb_info->height < vesa_timing->height)) { + fb_info->width = vesa_timing->width; + fb_info->height = vesa_timing->height; + } + } + + + /* Do centering if fb is smaller than timing except on TV */ + if ((fb_info->width < pipe_timing->width) || + (fb_info->height < pipe_timing->height)) { + unsigned short temp_width = pipe_timing->width; + unsigned short temp_height = pipe_timing->height; + /* Normally, we should NOT be in here. All IALs only + * are supposed to request for timings that ARE surely + * supported by the HAL,... i.e. query the list of + * supported timings by the port first! + * + * The exception would be if the IAL is purposely + * asking for CENTERING!!! (pt_info's that were not + * part of the supported mode list). This could indicate an + * error or an explicit request for VESA centering!. + */ + + /* let's use these 2 variables as flags... and do the + * actual "centering" of the timings later since we do + * also need to acomodate native timings as well + */ + /* NOTE: we could never be in here in fb_info was NULL */ + cntr_dff_w = (pipe_timing->width - fb_info->width) / 2; + cntr_dff_h = (pipe_timing->height - fb_info->height) / 2; + + /* Dont forget to use a different storage sice we dont + * want to change the original (and to be used later) + * ports mode list timings + */ + OS_MEMCPY(&scaled_timing[(PIPE(display)->pipe_num)], + pipe_timing, + sizeof(igd_timing_info_t)); + + pipe_timing = &scaled_timing[(PIPE(display)->pipe_num)]; + + if(PORT_OWNER(display)->pd_type != PD_DISPLAY_TVOUT ) { + /* TV display don't like changed pipe actives, + * Updating syncs work for TV centering */ + if (fb_info->width < temp_width) { + pipe_timing->width = (unsigned short)fb_info->width; + pipe_timing->hblank_start -= cntr_dff_w; + pipe_timing->hblank_end -= cntr_dff_w; + } + + if (fb_info->height < temp_height) { + pipe_timing->height = (unsigned short)fb_info->height; + pipe_timing->vblank_start -= cntr_dff_h; + pipe_timing->vblank_end -= cntr_dff_h; + } + } + + if (fb_info->width < temp_width) { + pipe_timing->hsync_start -= cntr_dff_w; + pipe_timing->hsync_end -= cntr_dff_w; + } + + if (fb_info->height < temp_height) { + pipe_timing->vsync_start -= cntr_dff_h; + pipe_timing->vsync_end -= cntr_dff_h; + } + } + } + } + + if(upscale) { + /* Get the native timings */ + OS_DEBUG("Checking for Native LVDS match for scaling"); + native_timing = match_resolution(display, timing_table, pt_info, + MATCH_NATIVE); + if(native_timing && (native_timing != pipe_timing)) { + native_timing->extn_ptr = pipe_timing; + pipe_timing = native_timing; + } + } + + /* + * Match mode returns as follows: + * In case of VGA setmode: + * 1) We will end up with either: + * magic->vga --- For displays supports native VGA + * or + * native->vga --- Upscaling displays + * or + * pipe->vga --- For other displays + * + * 2) In case of regular setmode: + * pipe --- For regular displays + * or + * native->vesa --- Upscaling displays + * + * Note: 1) Here "pipe" can be munged if centering is required. + * 2) "vesa" is the requested mode, native is the native timing + * of the display. + */ + + /* + * Update Input Structures with values found + * Note: This might not be what is going to be programmed. It is what + * the user thinks they set. Scaling or centering could have altered + * that. + */ + fill_pt(user_timing, pt_info); + *timing = pipe_timing; + OS_DEBUG("Return"); + + return 0; +} +#else + +#define MATCH_NUMBER 0x001 +#define MATCH_REFRESH 0x002 +#define MATCH_WIDTH 0x004 +#define MATCH_HEIGHT 0x008 +#define MATCH_FLAGS 0x010 +#define MATCH_GE_WIDTH 0x020 +#define MATCH_GE_HEIGHT 0x040 +#define MATCH_FOR_VGA 0x100 + +static int modes_match(igd_display_info_t *x, + igd_timing_info_t *y, + unsigned int flags) +{ + if((flags & MATCH_NUMBER) && + (x->mode_number != y->mode_number)) { + return 0; + } + if((flags & MATCH_REFRESH) && + (x->refresh && (x->refresh != y->refresh))) { + return 0; + } + if((flags & MATCH_WIDTH) && + (x->width != y->width)) { + return 0; + } + if((flags & MATCH_HEIGHT) && + (x->height != y->height)) { + return 0; + } + if((flags & MATCH_GE_WIDTH) && + (x->width > y->width)) { + return 0; + } + if((flags & MATCH_GE_HEIGHT) && + (x->height > y->height)) { + return 0; + } + if((flags & MATCH_FLAGS) && + (x->flags & (IGD_SCAN_INTERLACE|IGD_PIXEL_DOUBLE|IGD_LINE_DOUBLE)) != + (y->mode_info_flags & + (IGD_SCAN_INTERLACE|IGD_PIXEL_DOUBLE|IGD_LINE_DOUBLE))) { + return 0; + } + + return 1; +} + +typedef struct _vga_wh { + short width; + short height; +} vga_wh_t; + +static vga_wh_t vga_size[] = { + {640, 400}, {640, 400}, {640, 400}, {640, 400}, + {320, 400}, {320, 400}, {640, 400}, {720, 350}, + {640, 400}, {640, 400}, {640, 350}, {640, 350}, + {640, 350}, {640, 350}, {640, 350}, {640, 350}, + {640, 400}, {720, 400}, {720, 400}, {640, 480}, + {640, 480}, {640, 400} +}; + +/* + * For VGA modes we do not actually have a mode table. Just use a + * temporary slot (one per-pipe) and put the VGA mode number in it. + */ +static igd_timing_info_t vga_timing[] = { + { + 720, 400, 70, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x00, + IGD_MODE_VESA | IGD_MODE_SUPPORTED, + 0, 0, NULL, NULL + }, + { + 720, 400, 70, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x00, + IGD_MODE_VESA | IGD_MODE_SUPPORTED, + 0, 0, NULL, NULL + } +}; + +/* + * The magic mode, when found in a port's mode list, means that the port + * can do native VGA output. A mode with a wxh of 720x480 and refresh of + * 70 is the magic mode. + */ +static igd_display_info_t magic_timing = { + 720, 400, 70, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x00, + IGD_MODE_VESA | PD_MODE_SUPPORTED, + 0, 0, NULL, NULL +}; + +/*! + * Match Resolution searches the provided timing table for a mode that + * matches the requested parameters using the provided criteria. + * + * @param display The display on which the mode will be displayed. + * @param timing_table The list of modes to search through. + * @param pt_info The timing set used as reference for the match + * @param criteria The criteria that must match (bitfield). Options are + * MATCH_NUMBER: Match the VGA/VESA mode number + * MATCH_REFRESH: Match the refresh rate + * MATCH_WIDTH: Match the width + * MATCH_HEIGHT: Match the height + * MATCH_FLAGS: Match relavent interlace, pixel double, etc flags. + * MATCH_GE_WIDTH: Match width greater or equal to requested (used with + * best_match = 1) + * MATCH_GE_HEIGHT: Match height greater or equal to requested (used with + * best_match = 1) + * MATCH_FOR_VGA: Match is used for a VGA container which may need to take + * into accoutn 9th pixel dropping in the hardware. + * @param best_match When set to 0 the first mode found matching the criteria + * will be returned. Null will be returned if no match is found. + * When set to 1 the best matching mode is found after searching all modes. + * if no mode is found matching the criteria, the last mode in the table + * is used (should be the largest mode as mode tables are sorted) + * + * @return igd_timing_info_t + */ +static igd_timing_info_t *match_resolution( + igd_display_context_t *display, + igd_timing_info_t *timing_table, + igd_display_info_t *pt_info, + unsigned int criteria, + int best_match) +{ + igd_timing_info_t *timing; + igd_timing_info_t *match; + igd_timing_info_t *last_mode = NULL; + igd_display_port_t *port; + unsigned short save_width; + + OS_DEBUG("Enter match_resolution"); + + OS_DEBUG("Width=%d, height=%d, refresh=%d mode_number=0x%x", + pt_info->width, pt_info->height, pt_info->refresh, + pt_info->mode_number); + + timing = timing_table; + match = NULL; + port = PORT_OWNER(display); + save_width = pt_info->width; + + /* + * Hardware has a mode where it can drop every 9th pixel to fit + * a 720 width VGA mode into a 640 width container. Modify the + * reference mode to reflect 640 width and put it back at the end. + */ + if(criteria & MATCH_FOR_VGA) { + if((pt_info->width == 720) && + (port->port_features & IGD_VGA_COMPRESS)) { + pt_info->width = 640; + } + } + + while (timing->width != IGD_TIMING_TABLE_END) { + if(!MODE_IS_SUPPORTED(timing)) { + timing++; + continue; + } + if(modes_match(pt_info, timing, criteria)) { + /* + * If we are looking for the first match we are done. + */ + if(!best_match) { + match = timing; + break; + } + /* + * Looking for best match. Compare the new match to the last one + * to see if it is better. + */ + if(match) { + /* Check for tighter fit */ + if((timing->width < match->width) || + (timing->height < match->height)) { + match = timing; + } + } else { + match = timing; + } + } + last_mode = timing; + timing++; + } + + pt_info->width = save_width; + if(!match && best_match) { + /* + * Take the last one in the table for container modes. This insures + * that we never fail a container mode. + */ + match = last_mode; + } + + if (match) { + OS_DEBUG("Returning with a match"); + OS_DEBUG("Width=%d, height=%d, refresh=%d mode_number=0x%x", + match->width, match->height, match->refresh, match->mode_number); + } else { + OS_DEBUG("Returning with NO match"); + } + + return match; +} /* end match_resolution */ + + +void update_fb_size(igd_timing_info_t *match, + igd_framebuffer_info_t *fb_info) +{ + + /* + * fb_info is sometimes NULL when just testing something. + */ + if(fb_info) { + /* + * If The FB data comes in as zero we populate it with the matched + * size. Also if the FB is coming from vBIOS we increase the size + * to fit the match. + */ + if((fb_info->width == 0) || (fb_info->flags & IGD_VBIOS_FB)) { + + if((fb_info->width < match->width) || + (fb_info->height < match->height)) { + fb_info->width = match->width; + fb_info->height = match->height; + } + } + } +} + +/*! + * Push a Match on to the stack which is represented by a link list. + * Only push the mode if it is different than the head of the list. + * + * @param match + * @param timing_stack + * + * @return void + */ +void push_match(igd_timing_info_t *match, + igd_timing_info_t **timing_stack) +{ + + if(match == *timing_stack) { + return; + } + match->extn_ptr = *timing_stack; + *timing_stack = match; + return; +} + + +static igd_timing_info_t scaled_timing[IGD_MAX_PIPES]; + +/*! + * This function determines if the input timings need to be modified + * to accomodate the provided framebuffer. If so it converts the timing set + * to a modified set that centers the provided framebuffer image. + * The provided timings are not modified and the returned set + * may be used until the next mode set. The returned timings do + * not need to be freed. + * + * @param display A pointer to the display used for these timings. + * This parameter is used to determine which pipe the timings + * will be used with. There is one set of static timings for + * each pipe. + * @param timing The input timings which are used as reference to + * generate the new timings. Only the width/height and blank/syncs + * will be altered. The pixel clock and total sizes will not be changed. + * @param fb_info The framebuffer information to center within the + * provided timings. (May be NULL) + * + * @return Modified timing set + */ +igd_timing_info_t *get_centered_timings(igd_display_context_t *display, + igd_timing_info_t *timing, + igd_framebuffer_info_t *fb_info) +{ + short cntr_dff_w = 0; + short cntr_dff_h = 0; + + if(!fb_info) { + return timing; + } + + /* + * If we end up making a munged centered timings we need to use + * a copy and not the originals. + * + */ + OS_MEMCPY(&scaled_timing[(PIPE(display)->pipe_num)], + timing, sizeof(igd_timing_info_t)); + + if(PORT_OWNER(display)->pd_type != PD_DISPLAY_TVOUT) { + /* + * TV display don't like changed pipe actives, + * Updating syncs work for TV centering + */ + if (fb_info->width < timing->width) { + timing = &scaled_timing[(PIPE(display)->pipe_num)]; + cntr_dff_w = (timing->width - fb_info->width) / 2; + timing->width = (unsigned short)fb_info->width; + timing->hblank_start -= cntr_dff_w; + timing->hblank_end -= cntr_dff_w; + } + if (fb_info->height < timing->height) { + timing = &scaled_timing[(PIPE(display)->pipe_num)]; + cntr_dff_h = (timing->height - fb_info->height) / 2; + timing->height = (unsigned short)fb_info->height; + timing->vblank_start -= cntr_dff_h; + timing->vblank_end -= cntr_dff_h; + } + } + + timing->hsync_start -= cntr_dff_w; + timing->hsync_end -= cntr_dff_w; + timing->vsync_start -= cntr_dff_h; + timing->vsync_end -= cntr_dff_h; + + return timing; +} + + +/*! + * Match the fb and pt structures to a Mode Structure from the table. + * When a mode is found update the input structures to reflect the + * values found. + * + * The match mode function will compile all the information needed by + * the HAL to put the hardware into a mode. This may be a regular + * full-screen mode, a centered mode, a panned mode, a scaled mode. + * Below is a table of the mode that will be used and the cases in which + * it will occurr. + * + * Native + * The requested mode is matched in the mode table in terms of width + * height, refresh, and interlace flags. There is no fp_native_dtd or + * the matching mode IS the fp_native_dtd. + * Centered + * 1) The requested mode is matched in the mode table but the framebuffer + * is a smaller size and needs to be centered. + * 2) The requested mode is NOT matched in the mode table and the + * framebuffer matches the requested mode. A container mode is used + * with the original smaller framebuffer. + * Scaled + * The requested mode is matched in the mode table and a fp_native_dtd + * is present for the port. The matched mode does not match the native + * and is therefore scaled to fit. + * Panned/Cropped + * The requested mode is matched in the mode table but the framebuffer + * is larger (in at least one demension) that the mode. The mode is + * set with a cropped FB that may then be panned by the IAL. + * Render Scaled + * The requested mode may or may not be matched in the mode table. The + * framebuffer data is empty. The HAL will match the mode or find a + * container or find the largest mode and set the framebuffer to the + * same size. The IAL will scale the actual framebuffer to the returned + * framebuffer. + * Native VGA + * A VGA mode is requested (by number) and the magic VGA mode is matched + * in the mode table. FB contents are output only. + * Centered VGA + * A VGA mode is requested (by number) and the magic VGA mode is NOT + * matched. A container mode is found or the largest mode is used. The + * VGA is hardware centered in the container mode. FB contents are + * output only. + * Scaled VGA + * A VGA mode is requested (by number) and the magic VGA mode is NOT + * matched. A fp_native_dtd is found. The VGA image will be scaled to + * the native timings. + * + * + * The timings returned may be part of a linked list of timings which + * are used by the HAL to perform centering and scaling operations. One + * of the following will result. + * + * Requested Mode + * The requested mode matched and is returned with no linked modes. + * Munged Requested Mode + * The requested mode was larger than the requested framebuffer. The + * timings were then modified to center the framebuffer. + * Native Mode -> Requested Mode + * The display is fixed resolution and any mode must be scaled to that + * resolution by the PD. The native mode is returned and linked to the + * requested mode which will be scaled to fit the native mode. The + * pt_info will be populated with the requested mode giving the caller + * the impression that the mode was set natively. + * Native Mode -> Munged Requested Mode + * The display is fixed resolution and any mode must be scaled to that + * resolution by the PD. In addition the requested framebuffer is smaller + * then the requested mode. The native mode is returned and linked to the + * requested mode which has been modifed to center the framebuffer. + * The result will be the requested framebuffer scaled to fit the native + * mode. The pt_info will be populated with the requested mode giving the + * caller the impression that the mode was set natively. + * VGA Mode -> Magic VGA Mode + * The requested mode was a legacy VGA mode and the display supports + * native VGA output. The 720x400 "magic" mode is returned to indicate + * to the HAL that native VGA should be used. The magic mode is linked + * to the requested VGA mode. + * Container Mode -> VGA Mode + * The requested mode was a legacy VGA mode but the display does not + * support native VGA output. A larger container mode was found and + * returned. The hardware will center the VGA mode within the container + * for output. The pt_info will contain the VGA mode giving the caller + * the impression that the VGA mode was set natively. + * Native Mode -> VGA Mode + * The requested mode was a legacy VGA mode but the and the PD is + * set for scaling to a fixed resolution display. The Native mode is + * returned linked to the VGA mode. The result is the VGA mode scaled to + * fit the native screen. + * + * @note: There is a tradeoff to this behavior. If a VGA mode is set and + * scaled to full-screen there is no guarentee that ALL VGA modes are + * possible in that configuration. For instance, in DOS if a mode 3 is + * set (720x400) and scaled full-screen, an application cannot directly + * program the VGA registers (as many games do) to get an acceptable + * output at 640x480. This tradeoff is acknoledged and accepted. + * + * + * Assumtions: + * 1) fp_native_dtd is set in all instances where the output is a fixed + * resolution. (and only those instances) + * 2) PDs timing table contains all modes that can be output or all + * modes that can be scaled to the native output. + * 3) Scaling PDs can accept a VGA mode to be scaled to the native. + * + * @param display + * @param timing_table + * @param fb_info + * @param pt_info + * @param timing + * + * @return 0 + */ +int match_mode ( + igd_display_context_t *display, + igd_timing_info_t *timing_table, + igd_framebuffer_info_t *fb_info, + igd_display_info_t *pt_info, + igd_timing_info_t **timing) +{ + igd_timing_info_t *match = NULL; + igd_timing_info_t *timing_stack = NULL; + + OS_DEBUG("Enter Match Mode"); + + OS_ASSERT(pt_info, "Null PT Info", -IGD_ERROR_INVAL); + OS_ASSERT((pt_info->flags & IGD_MODE_VESA) || + (pt_info->width && pt_info->height), + "Width and Height are Zero", -IGD_ERROR_INVAL); + + if(MODE_IS_VGA(pt_info)) { + /* + * The requested mode is a legacy VGA mode + */ + OS_DEBUG("Matching a VGA mode"); + + /* + * All VGA modes are possible. Just use a temporary timing + * block and put the VGA mode number in it. We don't actually + * use any timing information for VGA modes. + */ + match = &vga_timing[(PIPE(display)->pipe_num)]; + match->mode_number = pt_info->mode_number; + match->width = vga_size[pt_info->mode_number].width; + match->height = vga_size[pt_info->mode_number].height; + + push_match(match, &timing_stack); + update_fb_size(match, fb_info); + + /* The caller should think we set the VGA mode directly */ + fill_pt(match, pt_info); + + match = match_resolution(display, timing_table, &magic_timing, + MATCH_WIDTH|MATCH_HEIGHT, 0); + if(match) { + /* + * Magic VGA mode was found. This indicates the display can + * do full native VGA timings. We will send the mode out + * natively. + */ + OS_DEBUG("Native VGA output"); + push_match(match, &timing_stack); + + *timing = timing_stack; + return 0; + } + + /* + * This display cannot do native VGA. We need to center or + * scale the VGA to fit. + */ + if(PORT_OWNER(display)->fp_native_dtd) { + /* + * Native mode in the port indicates the PD can scale. + * Push the native mode on the list to get VGA scaled + * to native. + */ + OS_DEBUG("VGA Scaled to Native"); + push_match(PORT_OWNER(display)->fp_native_dtd, &timing_stack); + } else { + /* + * No native mode means the PD is not scaling. Output + * VGA centered in a safe container mode. + */ + OS_DEBUG("VGA centered in Container"); + match = match_resolution(display, timing_table, pt_info, + MATCH_FOR_VGA|MATCH_GE_WIDTH|MATCH_GE_HEIGHT|MATCH_FLAGS, 1); + OS_ASSERT(match, "Match Container Failed", -IGD_ERROR_INVAL); + + push_match(match, &timing_stack); + } + + *timing = timing_stack; + return 0; + + } + + /* + * Regular NON-VGA mode + */ + OS_DEBUG("Matching a regular NON-VGA mode"); + + match = match_resolution(display, timing_table, pt_info, + (pt_info->flags & IGD_MODE_VESA)? + MATCH_NUMBER|MATCH_REFRESH: + MATCH_WIDTH|MATCH_HEIGHT|MATCH_REFRESH|MATCH_FLAGS, 0); + if(match) { + /* + * Exact match for requested mode was found in the mode table. + * This mode will be output directly. + */ + OS_DEBUG("Input Mode Matched exactly"); + } else { + /* + * Matching mode was not found. This happens for several + * reasons: + * + * 1) We are setting the clone mode but the IAL does not + * know the clone width/height. We are just getting the + * best guess. In this case fb info is populated. + * 2) IAL is doing Render Scaling but doesn't know what mode + * to scale to. We are getting the best fit. In this case + * fb info is all zeros. + * 3) IAL is just setting random modes and wants something + * close. Fb info may or may not be populated. + */ + OS_DEBUG("Input Mode NOT matched, container used"); + match = match_resolution(display, timing_table, pt_info, + MATCH_GE_WIDTH|MATCH_GE_HEIGHT|MATCH_FLAGS, 1); + OS_ASSERT(match, "Match Container Failed", -IGD_ERROR_INVAL); + } + update_fb_size(match, fb_info); + match = get_centered_timings(display, match, fb_info); + push_match(match, &timing_stack); + + fill_pt(match, pt_info); + + if(PORT_OWNER(display)->fp_native_dtd) { + /* + * Native DTD indicates that the PD is scaling. Hook the + * match mode up to the native to get scaling. + */ + OS_DEBUG("Input Mode Scaled to Native"); + push_match(PORT_OWNER(display)->fp_native_dtd, &timing_stack); + } + + + *timing = timing_stack; + return 0; +} + + +#endif + + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: match.c,v 1.4 2010/04/27 20:33:49 bpaauwe Exp $ + * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/mode/cmn/match.c,v $ + *---------------------------------------------------------------------------- + */ diff --git a/drivers/gpu/drm/emgd/emgd/display/mode/cmn/match.h b/drivers/gpu/drm/emgd/emgd/display/mode/cmn/match.h new file mode 100755 index 0000000..0812893 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/mode/cmn/match.h @@ -0,0 +1,49 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: match.h + * $Revision: 1.2 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * This file contains the mode matching algorithms + *----------------------------------------------------------------------------- + */ + +#include + +int validate_fb( + pigd_framebuffer_info_t fb_info, + igd_display_plane_t *plane); + +int validate_cursor( + igd_cursor_info_t *cursor_info, + igd_display_context_t *display); + +int match_mode ( + igd_display_context_t *display, + igd_timing_info_t *timing_table, + igd_framebuffer_info_t *fb_info, + igd_display_info_t *pt_info, + igd_timing_info_t **timing); + + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: match.h,v 1.2 2010/04/27 20:33:49 bpaauwe Exp $ + * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/mode/cmn/match.h,v $ + *---------------------------------------------------------------------------- + */ diff --git a/drivers/gpu/drm/emgd/emgd/display/mode/cmn/micro_mode.c b/drivers/gpu/drm/emgd/emgd/display/mode/cmn/micro_mode.c new file mode 100644 index 0000000..b8b64e9 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/mode/cmn/micro_mode.c @@ -0,0 +1,1630 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: micro_mode.c + * $Revision: 1.9 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * Contains client interface support functions for display allocations + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.mode + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "match.h" +#include "mode_dispatch.h" + +/*! + * @addtogroup display_group + * @{ + */ + +#ifndef CONFIG_MICRO +#define TIMING_CHANGED(a,b,c,d,e,f,g) timing_changed(a,b,c,d,e,f,g) +#define CALCULATE_ELD_INFOFRAMES +#else +#define TIMING_CHANGED(a,b,c,d,e,f,g) 1 +#endif /* CONFIG_MICRO */ + +#define MODE_MIN(x, y) (xpt_info == NULL) { + return 1; + } + + /* + * Make sure we have valid timing info. If not, then don't try + * and change the timings. + */ + if (!pt_info || !fb_info) { + return 0; + } + + /* + * If the caller really wants to re-program the planes/pipes/ports + * then do it + */ + + if (flags & IGD_FORCE_ALTER) { + return 1; + } + + /* + * Check only width, height, refresh. If these don't match, then we + * know that something is changing. + */ + + if ((pt_info->width == PORT_OWNER(display)->pt_info->width) && + (pt_info->height == PORT_OWNER(display)->pt_info->height) && + (pt_info->refresh == PORT_OWNER(display)->pt_info->refresh)) { + + /* Check framebuffer for changes, fb changes may change timing */ + if ((cfb = PLANE(display)->fb_info) != NULL) { + if ((cfb->width != fb_info->width) || + (cfb->height != fb_info->height) || + (cfb->pixel_format != fb_info->pixel_format) || + (cfb->flags != fb_info->flags)) { + /* Timing ok buf fb_info doesn't match */ + return 1; + } + } + } else { + /* Timing doesn't match */ + return 1; + } + + /* Timing and fb have not changed */ + OS_TRACE_EXIT; + return 0; +} +#endif + +/*! + * Update internal data structures for the plane, pipe, and port as + * requested. Allocate a new framebuffer if the new parameters do not + * match the existing framebuffer. + * + * @param display + * @param port_number + * @param timing + * @param pt_info User supplied timing info to check. + * @param fb_info User supplied framebuffer info. + * @param flags + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ +static int mode_update_plane_pipe_ports( + igd_display_context_t *display, + unsigned short port_number, + igd_timing_info_t *timing, + igd_framebuffer_info_t *fb_info, + igd_display_info_t *pt_info, + unsigned long flags) +{ + int ret; + int alloc_fb; + unsigned long size = 0; + igd_framebuffer_info_t *plane_fb_info; + igd_display_plane_t *mirror; + + OS_TRACE_ENTER; + + OS_DEBUG("Port Number (%d)", port_number); + + OS_ASSERT( (fb_info || pt_info), "ERROR: fb_info & pt_info are NULL", + -IGD_ERROR_INVAL); + + OS_ASSERT( PLANE(display)->fb_info, "ERROR: fb_info in plane is NULL", + -IGD_ERROR_INVAL); + + plane_fb_info = PLANE(display)->fb_info; + mirror = PLANE(display)->mirror; + + /* + * If there is a mirror plane (for Clone) and the mirror is populated + * then update our plane from the mirror. If the mirror is not populated + * then update the mirror from ours. + */ + if (mirror) { + if(mirror->fb_info->flags) { + OS_MEMCPY(plane_fb_info, mirror->fb_info, + sizeof(igd_framebuffer_info_t)); + } else { + OS_MEMCPY(mirror->fb_info, plane_fb_info, + sizeof(igd_framebuffer_info_t)); + } + } + + if (PORT(display, port_number)->pt_info == NULL) { + if ((PORT(display, port_number)->pt_info = (igd_display_info_t *) + OS_ALLOC(sizeof(igd_display_info_t))) == NULL) { + OS_ERROR_EXIT("unable to alloc a pt_info struct in pipe."); + return -IGD_ERROR_INVAL; + } + } + + /* + * If the fb_info was provided, and either we were asked to update + * the internal structures via the flags, or we are allocating a new + * framebuffer. + */ + if(fb_info && (flags & MODE_UPDATE_PLANE)) { + + /* Assume we will be allocating a FB */ + alloc_fb = 1; + + /* If the frambuffer parameters are unchanged then do not re-alloc */ + if((fb_info->width == plane_fb_info->width) && + (fb_info->height == plane_fb_info->height) && + (fb_info->pixel_format == plane_fb_info->pixel_format) && + (fb_info->flags == plane_fb_info->flags)) { + alloc_fb = 0; + } + + /* Do not re-alloc a framebuffer if the re-use flag is set. */ + if(fb_info->flags & IGD_REUSE_FB) { + alloc_fb = 0; + /* May need to get the MIN_PITCH flags */ + plane_fb_info->flags = (fb_info->flags & IGD_FB_FLAGS_MASK) | + (plane_fb_info->flags & ~IGD_FB_FLAGS_MASK); + } + + /* + * If we don't have a framebuffer at all then we MUST allocate + * one. + */ + if(!plane_fb_info->allocated && !fb_info->allocated) { + alloc_fb = 1; + } + + OS_DEBUG("plane_fb_info->fb_base_offset = 0x%08lx", + plane_fb_info->fb_base_offset); + if(alloc_fb) { + if(plane_fb_info->allocated) { + /* Free frame buffer memory */ + display->context->dispatch.gmm_free( + plane_fb_info->fb_base_offset); + plane_fb_info->allocated = 0; + } + + fb_info->fb_base_offset = plane_fb_info->fb_base_offset; + /* + * Keep the FB flags, add in Displayable flag and blank out + * the rest. This insures that any tiled or usage flags from an + * earlier call do not get reused. + */ + fb_info->flags = (fb_info->flags & IGD_FB_FLAGS_MASK) | + IGD_SURFACE_DISPLAY; + + /* + * Framebuffer allocations must always come from a reservation + * if the IAL changes the address the new address must also be + * from a reservation. + */ + GMM_SET_DEBUG_NAME("Framebuffer"); + ret = display->context->dispatch.gmm_alloc_surface( + &fb_info->fb_base_offset, + fb_info->pixel_format, + &fb_info->width, + &fb_info->height, + &fb_info->screen_pitch, + &size, + IGD_GMM_ALLOC_TYPE_RESERVATION, + &fb_info->flags); + if(ret) { + OS_ERROR_EXIT("Allocation of Front buffer failed: %d", ret); + return ret; + } + fb_info->allocated = 1; + /* Set the visible offset to the newly-allocated offset: */ + fb_info->visible_offset = fb_info->fb_base_offset; + } else { + /* If not reallocating, use back the offset in plane_fb_info */ + fb_info->fb_base_offset = plane_fb_info->fb_base_offset; + } + + OS_MEMCPY(plane_fb_info, fb_info, sizeof(igd_framebuffer_info_t)); + plane_fb_info->allocated = 1; + OS_DEBUG("plane_fb_info->fb_base_offset = 0x%08lx", + plane_fb_info->fb_base_offset); + + } + + if(timing && (flags & MODE_UPDATE_PIPE)) { + OS_DEBUG("Updating pipe timing."); + PIPE(display)->timing = timing; + PIPE(display)->owner = display; + } + + if(pt_info && (flags & MODE_UPDATE_PORT)) { + OS_DEBUG("OLD_PT========NEW PT "); + IGD_PRINTK_PTINFO_2(PORT(display, port_number)->pt_info, pt_info); + OS_MEMCPY(PORT(display, port_number)->pt_info, pt_info, + sizeof(igd_display_info_t)); + } + + OS_TRACE_EXIT; + return 0; +} /* end mode_update_plane_pipe_ports() */ + +#ifdef CALCULATE_ELD_INFOFRAMES + +/*! + * Calculates infoframes information top be used by HDMI port drivers + * + * @param port + * @param timing_info + * @param temp_cea + * + * @return 0 + */ +static int calculate_infoframes( + igd_display_port_t *port, + igd_timing_info_t *timing_info, + cea_extension_t *temp_cea) +{ + + pd_timing_t *cea_timings = NULL, *cea_timing_temp = NULL; + + OS_TRACE_ENTER; + + /* VBIOS has no access to CEA timing tables and this is not supported + there as well */ + if(timing_info->mode_info_flags & PD_MODE_CEA){ + if(timing_info->width != 640 && timing_info->height != 480){ + port->edid->cea->quantization = HDMI_QUANTIZATION_RGB_220; + } + + /* Based on DPG algorithm. If monitors support more than 2 channels + for 192Khz or/and 92Khz then set two pixel repeat one. + KIV: Add pruning for pixel PIX_REPLICATION_3 if required */ + if(temp_cea->audio_cap[CAP_192_KHZ].max_channels>2 || + temp_cea->audio_cap[CAP_96_KHZ].max_channels>2){ + port->edid->cea->pixel_rep = PIX_REPLICATION_1; + } + + + /* Based on HDMI spec 6.7.1 & 6.7.2 */ + if ((timing_info->width == 720) && ((timing_info->height == 480) || + (timing_info->height== 576))){ + port->edid->cea->colorimetry = HDMI_COLORIMETRY_ITU601; + } else if(((timing_info->width==1280) && (timing_info->height==720)) || + ((timing_info->width == 1920) && (timing_info->height == 1080))){ + port->edid->cea->colorimetry = HDMI_COLORIMETRY_ITU709; + } + + cea_timings = (igd_timing_info_t *) OS_ALLOC(cea_timing_table_size); + OS_MEMCPY(cea_timings, cea_timing_table, cea_timing_table_size); + cea_timing_temp = cea_timings; + + while (cea_timings->width != IGD_TIMING_TABLE_END){ + if(cea_timings->width == timing_info->width && + cea_timings->height == timing_info->height && + cea_timings->refresh == timing_info->refresh && + cea_timings->dclk == timing_info->dclk && + (cea_timings->mode_info_flags & + (PD_ASPECT_16_9| IGD_SCAN_INTERLACE)) == + (timing_info->mode_info_flags & + (PD_ASPECT_16_9| IGD_SCAN_INTERLACE))){ + port->edid->cea->video_code = cea_timings->mode_number; + break; + } + cea_timings++; + } + + OS_FREE(cea_timing_temp); + + } + + OS_TRACE_EXIT; + return 0; +} +#endif /* CALCULATE_ELD_INFOFRAMES */ + +/*! + * Calculates the Edid like data (ELD) if port supports audio transmission + * + * @param port + * @param timing_info + * + * @return 0 + */ +static int calculate_eld( + igd_display_port_t *port, + igd_timing_info_t *timing_info) +{ + /* Calculate for non-content protected & content protected(Array of 2) */ +#ifdef CALCULATE_ELD_INFOFRAMES + unsigned long cal_NPL[2]; /* Number of packer per line calculate*/ + unsigned long poss_NPL[2]; /* Number of packer per line possible*/ + unsigned long max_bitRate_2[2],max_bitRate_8[2]; + unsigned long h_refresh, audio_freq; + unsigned char input; + int i,j,pix_rep; +#endif + cea_extension_t *temp_cea = NULL ; + + OS_TRACE_ENTER; + /* Only calculate eld for HDMI port */ + if((port->pd_driver->type != PD_DISPLAY_HDMI_EXT && + port->pd_driver->type != PD_DISPLAY_HDMI_INT)){ + return 0; + } + if(port->firmware_type == PI_FIRMWARE_EDID){ + temp_cea = (cea_extension_t*)port->edid->cea; + } + /* Displayid unsupported for now. Uncomment this code when audio + information is available for Display ID + temp_cea = (&cea_extension_t)port->displayid->cea;*/ + + if(temp_cea == NULL){ + /* CEA data unavailable, display does not have audio capability? */ + /* We would allocate dummy edid structure and here and we should ony + used canned ELD */ + if(port->edid == NULL) { + port->edid = (edid_t *) OS_ALLOC(sizeof(edid_t)); + OS_MEMSET(port->edid, 0 , (sizeof(edid_t))); + } + + port->edid->cea = (cea_extension_t *) OS_ALLOC(sizeof(cea_extension_t)); + OS_MEMSET(port->edid->cea, 0 , (sizeof(cea_extension_t))); + port->edid->cea->canned_eld = 1; + temp_cea = (cea_extension_t*)port->edid->cea; + port->callback->eld = &(port->edid->cea); + } + + /* Default to canned ELD data */ + temp_cea->LPCM_CAD[0] = 0x9; + temp_cea->speaker_alloc_block[0] = 0x1; + /* Default 0 Pixel replication */ + port->edid->cea->pixel_rep = PIX_REPLICATION_0; + /* Default */ + port->edid->cea->colorimetry = HDMI_COLORIMETRY_NODATA; + /* Default RGB 256 wuantization full range */ + port->edid->cea->quantization = HDMI_QUANTIZATION_RGB_256; + /* Default Unknown video code */ + port->edid->cea->video_code = 0; + port->edid->cea->aspect_ratio = (timing_info->mode_info_flags & PD_ASPECT_16_9) + ? PD_ASPECT_RATIO_16_9 : PD_ASPECT_RATIO_4_3; + +#ifdef CALCULATE_ELD_INFOFRAMES + calculate_infoframes(port,timing_info,temp_cea); + /* If canned eld is not set and audio info from transmitter is available */ + if(temp_cea->canned_eld != 1 && (temp_cea->audio_flag & PD_AUDIO_CHAR_AVAIL)){ + pix_rep = port->edid->cea->pixel_rep; + /*h_refresh = timing_info->dclk/timing_info->htotal;*/ + h_refresh = timing_info->refresh; + cal_NPL[0] = (pix_rep*(timing_info->hsync_end - timing_info->hsync_start) - + port->edid->cea->K0) /32; + cal_NPL[1] = (pix_rep*(timing_info->hsync_end - timing_info->hsync_start) - + port->edid->cea->K1) /32; + + poss_NPL[0] = MODE_MIN(cal_NPL[0],port->edid->cea->NPL); + poss_NPL[1] = MODE_MIN(cal_NPL[1],port->edid->cea->NPL); + + max_bitRate_2[0] = h_refresh * poss_NPL[0] - 1500; + max_bitRate_2[1] = h_refresh * poss_NPL[1] - 1500; + + max_bitRate_8[0] = h_refresh * poss_NPL[0] * 4 - 1500; + max_bitRate_8[1] = h_refresh * poss_NPL[1] * 4 - 1500; + + /* Loop trough Content Protection disabled then enabled */ + for(i=0 ; i<2; i++){ + for(j=0 ; j<3; j++){ + input = 0; + audio_freq = 48000 * (1<96Khz->192Khz */ + if(max_bitRate_8[i] >= audio_freq){ + input = 7; + }else if(max_bitRate_2[i] >= audio_freq){ + input = 1; + } + /* take the minimum value min(transmitter, receiver) */ + input = MODE_MIN(input,temp_cea->audio_cap[j].max_channels); + temp_cea->LPCM_CAD[j] |= input<<((1-i)*3); + if(temp_cea->audio_cap[j]._24bit){ + temp_cea->LPCM_CAD[j] |= BIT(7); + } + if(temp_cea->audio_cap[j]._20bit){ + temp_cea->LPCM_CAD[j] |= BIT(6); + } + } + } + + /* TODO: Further construction of ELD from Monitor Name String begins here + for now we only support VSDB */ + /* By default we don send any vendor specific block unless latency value + use for audio sync feature is available */ + temp_cea->vsdbl = 0; + /* This means the latecy field is available VSBD_LATENCY_FIELD = 8*/ + if(temp_cea->vendor_block.vendor_block_size > VSBD_LATENCY_FIELD){ + OS_MEMCPY(temp_cea->misc_data, temp_cea->vendor_data_block, + temp_cea->vendor_block.vendor_block_size); + temp_cea->vsdbl = temp_cea->vendor_block.vendor_block_size; + /* If the VSBD has latency fields */ + if(*(temp_cea->vendor_data_block + VSBD_LATENCY_FIELD - 1) & 0x80){ + if(timing_info->mode_info_flags & IGD_SCAN_INTERLACE){ + if(*(temp_cea->vendor_data_block + VSBD_LATENCY_FIELD - 1) & 0x40){ + temp_cea->vendor_block.p_latency = 1; + temp_cea->vendor_block.i_latency = 1; + }else{ + /* No latency available: Since it is an interlace mode but no + vsbd_intlc_fld_present is available */ + temp_cea->vendor_block.p_latency = 0; + temp_cea->vendor_block.i_latency = 0; + } + }else{ + temp_cea->vendor_block.p_latency = 1; + temp_cea->vendor_block.i_latency = 0; + } + } + } + } +#endif /* CALCULATE_ELD_INFOFRAMES */ + temp_cea->audio_flag |= ELD_AVAIL; + OS_TRACE_EXIT; + return 0; +} + +/*! + * Configure either the primary or secondary display. This means all the + * timings, the framebuffer, the ports, the plane, and the pipe. + * + * The port range could be calculated based on primary or secondary + * display but it seems easier at this point to pass the port range + * in since it is used for all the for loops. + * + * @param driver_handle + * @param display + * @param pt_info + * @param fb_info + * @param dc + * @param p0 + * @param pn + * @param flags + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ +static int configure_display( + igd_driver_h driver_handle, + igd_display_context_t *display, + igd_display_info_t *pt_info, + igd_framebuffer_info_t *fb_info, + unsigned long dc, + int p0, int pn, + unsigned long flags) +{ + igd_context_t *context = (igd_context_t *)driver_handle; + int p; + igd_display_port_t *port; + igd_timing_info_t *timing_info; + unsigned long update_flags; + unsigned short port_number = 0; + int ret; + int seamless = FALSE; + + OS_TRACE_ENTER; + + /* FIXME: Should this be an assert? */ + if (display == NULL) { + OS_DEBUG("Trying to configure a NULL display"); + return 0; + } + + OS_DEBUG("Configure timings"); + for (p = pn; p > p0; p--) { + OS_DEBUG("Configure port %d", DC_PORT_NUMBER(dc, p)); + if ((port_number = DC_PORT_NUMBER(dc, p))) { + port = context->mod_dispatch.dsp_port_list[port_number]; + if (!port) { + OS_DEBUG("Port %d not found", port_number); + } else { + + /* Put a copy of the timings in the port's structure */ + if (pt_info) { + if (port->pt_info == NULL) { + port->pt_info = OS_ALLOC(sizeof(igd_display_info_t)); + if (!port->pt_info) { + OS_ERROR_EXIT("unable to alloc a pt_info " + "struct in port."); + return -IGD_ERROR_INVAL; + } + } + OS_MEMCPY(port->pt_info, pt_info, + sizeof(igd_display_info_t)); + } else { + OS_ERROR("No primary timing info!"); + } + } + } + } + + if(!(pt_info->flags & IGD_DISPLAY_ENABLE)) { + OS_ERROR_EXIT("Ptinfo has no IGD_DISPLAY_ENABLE!"); + return 0; + } + + display->port_number = DC_PORT_NUMBER(dc, (p0 + 1)); + + /* Set mode */ + OS_DEBUG("Set mode, using port %ld", display->port_number); + port = PORT(display, display->port_number); + + OS_DEBUG("Calling matchmode on display"); + ret = match_mode(display, port->timing_table, fb_info, pt_info, + &timing_info); + if(ret) { + OS_DEBUG("Match Mode for display failed"); + OS_TRACE_EXIT; + return -IGD_ERROR_INVAL; + } + + /* Now b4, we program the timing_info, let's first see if seamless + * option is requested, if it is then + * We need to make sure the incoming dc, timing, framebuffer + * info and etc match. We must respect the FORCE_ALTER flag. + * + * Seamless option buys you a one-time ticket for the seamless + * experience from the firmware to the driver. After the first mode set + * in driver, you don't get it the next time when you alter display. + * + */ +#ifndef CONFIG_MICRO + if(dc && !(flags & IGD_FORCE_ALTER) && + (mode_context->seamless == TRUE) ) { + + /* User wants seamless */ + if(mode_context->fw_info != NULL) { + + OPT_MICRO_CALL_RET(seamless, query_seamless(dc, + (p0/4), + timing_info, + fb_info, + 0)); + + OS_DEBUG(":Seamless = %s", seamless ?"ON" : "OFF"); + mode_context->seamless = FALSE; + /* FIXME: For clone you get called twice. Need to + * Fix that corner case + */ + + } + } +#endif + /* In case the seamless is FALSE, we do reset_plane_pipe_ports + * which is supposed to be called in alter_displays anyway. + * But we have to delay it since the user asked for seamless. + * And we don't want to switch-off the display during + * seamless. + * Now we know that even though the user asked for it, we cannot + * support seamless, so we call reset_plane_pipe_ports now. + */ + if(seamless == FALSE) { + + /* Reset planes/pipes/ports before doing first alter display */ + if (mode_context->first_alter) { + mode_context->dispatch->reset_plane_pipe_ports( + mode_context->context); + mode_context->first_alter = FALSE; + } + + } + + if(calculate_eld(port, timing_info)){ + OS_DEBUG("Fail to calculate ELD"); + } + /* turn on all ports */ + OS_DEBUG("turn on displays plane_pipe_ports %d..%d", (p0 + 1), (pn-1)); + + for (p = (p0 + 1); p <= pn; p++) { + if (DC_PORT_NUMBER(dc, p)) { + port = context->mod_dispatch.dsp_port_list[DC_PORT_NUMBER(dc, p)]; + + display->allocated = 1; + + /* Update mode info for the port */ + if (p == (p0 + 1)) { + update_flags = MODE_UPDATE_PLANE | MODE_UPDATE_PIPE | + MODE_UPDATE_PORT; + } else { + update_flags = MODE_UPDATE_PORT; + } + ret = mode_update_plane_pipe_ports(display, DC_PORT_NUMBER(dc, p), + timing_info, fb_info, pt_info, update_flags); + if (ret) { + /* + * This could happen if there was no memory for the + * framebuffer or the FB was an invalid format. The + * first is a too bad failure. The second should have + * been checked by the IAL. + */ + OS_ERROR_EXIT("mode_update_plane_pipe_ports returned error " + "%d", ret); + port->pt_info->flags &= ~IGD_DISPLAY_ENABLE; + return ret; + } + + /* Program the port registers */ + if(seamless == TRUE) { + /* Don't have to program the registers, Since it's + * all updated. Just return 0 + */ + ret = 0; + } else { + ret = mode_context->dispatch->program_port(display, + DC_PORT_NUMBER(dc, p), TRUE); + } + if (ret == 0) { + port->inuse = 1; + } else { + port->pt_info->flags &= ~IGD_DISPLAY_ENABLE; + } + } + } + OS_DEBUG("done - turn on displays plane_pipe_ports %d", p); + + /* Clear the Framebuffer after the planes, pipes and ports are + * disabled and before they are enabled. */ + if (flags & IGD_CLEAR_FB) { + OPT_MICRO_VOID_CALL(full_clear_fb(mode_context, fb_info)); + } + + /* program the pipe/plane/port if seamless is FALSE */ + if(seamless == FALSE) { + + OS_DEBUG("Seamless is FALSE"); + + /* turn on pipe */ + mode_context->dispatch->program_pipe(display, TRUE); + + /* turn on plane */ + mode_context->dispatch->program_plane(display, TRUE); + + /* turn on port */ + for (p = pn; p > p0; p--) { + if (DC_PORT_NUMBER(dc, p)) { + ret = mode_context->dispatch->post_program_port(display, + DC_PORT_NUMBER(dc, p), 0); + } + } + + } +#ifndef CONFIG_MICRO + else { /* Seamless is TRUE */ + + /* Updating the plane registers, does not require us to + * turn-off the pipe and we can still have seamless + * because the display is not turned-off + */ + + OS_DEBUG(" Seamless is TRUE"); + if(mode_context->fw_info->program_plane == 1) { + + /* This means we have to update the plane registers + * with the new values.eg. Change in pitch size between + * firmware values and driver values. But we MUST also + * update the palette registers for this to work and + * palette registers are programmed when pipe is programmed. + * This means we program the pipe , followed by the plane. + */ + + /* By doing this, we update the palette */ + mode_context->dispatch->program_pipe(display, TRUE); + + /* update the plane registers */ + mode_context->dispatch->program_plane(display, TRUE); + } + } +#endif + + OS_TRACE_EXIT; + return 0; +} + + +#ifndef CONFIG_MICRO + +/*! + * This function checks whether all the ports on the primary pipe of a dc are + * moving to a secondary pipe on a new dc. + * + * @param current_dc current_dc the system is in. + * @param dc new requested dc. + * + * @return 0 if not all the ports are moving + * @return 1 if all the ports are moving + */ +int all_ports_moving(unsigned long current_dc, unsigned long dc) +{ + unsigned long index, index2, port; + int found_port; + int result = 1; + + /* + * We need to look for each of the primary ports on the current dc, + * and see if they exist on the secondary port of the new dc. + */ + for (index = IGD_DC_IDX_PRIMARY_MASTER; + index <= IGD_DC_IDX_PRIMARY_TWIN3; index++) { + found_port = 0; + port = IGD_DC_PORT_NUMBER(current_dc, index); + /* If there is a port, let's look for it. */ + if (port) { + /* Try to find this port on the secondary pipe */ + for (index2 = IGD_DC_IDX_SECONDARY_MASTER; + index2 <= IGD_DC_IDX_SECONDARY_TWIN2; index2++) { + /* + * We found the port, let's stop looking for this port and + * move on to the next port + */ + if (port == IGD_DC_PORT_NUMBER(dc, index2)) { + found_port = 1; + break; + } + } + /* As soon as there is a port that we don't find, we can exit */ + if (!found_port) { + result = 0; + break; + } + } + } + + return result; +} + +/*! + * This function checks whether a specified port exists in a dc, and if it does + * it returns the pipe master index for the pipe which contained the port. + * + * @param dc the dc to check for a port. + * @param port the port to check for. + * + * @return 0 if the specified does not exist + * @return IGD_DC_IDX_PRIMARY_MASTER if the port was found on the primary pipe + * @return IGD_DC_IDX_SECONDARY_MASTER if the port was found on the secondary + * pipe + */ +int dc_contains_port_type(unsigned long dc, unsigned long port) +{ + unsigned long index; + int result = 0; + + for (index = IGD_DC_IDX_PRIMARY_MASTER; + index <= IGD_DC_IDX_PRIMARY_TWIN3; index++) { + + if (IGD_DC_PORT_NUMBER(dc, index) == port) { + result = IGD_DC_IDX_PRIMARY_MASTER; + break; + } + } + + for (index = IGD_DC_IDX_SECONDARY_MASTER; + index <= IGD_DC_IDX_SECONDARY_TWIN2; index++) { + + if (IGD_DC_PORT_NUMBER(dc, index) == port) { + result = IGD_DC_IDX_SECONDARY_MASTER; + break; + } + } + + return result; +} + +/*! + * This function checks whether a frame buffer swap and cursor + * swap is required based on given current_dc and new_dc. + * + * @param current_dc current_dc the system is in. + * @param dc new requested dc. + * @param dsp pointer to a display context pointer + * + * @return 0 if no swap is required + * @return 1 if swap is required + */ +int swap_required( + unsigned long current_dc, + unsigned long dc, + igd_display_context_t **dsp) +{ + + /* + * Note: Preserve the order of conditions as is. Changing the order + * of below conditions require relook into the whole function to + * make sure sematics match to return right value. + */ + + /* Do not swap if no dc or current_dc */ + if (!dc || !current_dc) { + return 0; + } + + /* + * Do NOT swap the frame buffer and cursor if dc is going + * from twin to extended and not all the ports are moving to the other + * pipe. If all the ports are moving to the other pipe, then DO swap + * the frame buffer and cursor. + * We also need to make sure we are not in the special case where our + * extended mode contains LVDS and we are on a platform which does not + * support LVDS on PIPE A. In this case we do not want to swap here because + * we will not be swapping later since the twin configuration will stay on + * PIPE A so that the LVDS can move to PIPE B. + */ + if (IGD_DC_TWIN(current_dc) && IGD_DC_EXTENDED(dc)) { + if (dsp && *dsp && all_ports_moving(current_dc, dc) && + !(dc_contains_port_type(dc, IGD_PORT_TYPE_LVDS) && + !(PIPE(*dsp)->pipe_features & IGD_PORT_SHARE_LVDS))) { + return 1; + } else { + return 0; + } + } + + /* + * Do NOT swap if dc is changing from Single to clone or + * vice versa. In this case there is only 1 fb and no swap is required + * and it stays with primary display. + */ + if ((IGD_DC_SINGLE(current_dc) && IGD_DC_CLONE(dc)) || + (IGD_DC_CLONE(current_dc) && IGD_DC_SINGLE(dc))) { + return 0; + } + + /* + * If secondary master port is moving to primary master or + * primary master is moving to secondary master, try + * and keep the framebuffer address and cursor the same. + */ + if (DC_PORT_NUMBER(current_dc, 5) == DC_PORT_NUMBER(dc, 1) || + (DC_PORT_NUMBER(current_dc, 1) == DC_PORT_NUMBER(dc, 5))) { + /* + Note: This was previosuly return 1 to indicate swap required, which will cause + a frame buffer swap when changing display from twin to clone. If the display is + in extended mode before changing from twin to clone, then both Plane A and Plane B + will point to the secondary frame buffer offset adress in clone mode and cause + blank screen (. + */ + return 0; + } + return 0; +} +#endif + +/*! + * This function sets up planes, pipes, and ports + * with the configuration passed in and returnes either one + * or two display handle lists. + * + * @param driver_handle from igd_init_driver(). + * @param primary on return, this points to a list of displays. + * @param primary_ptinfo incoming timing info for the primary. + * @param primary_fbinfo incoming framebuffer info. + * @param secondary on return, this points to a list of displays. + * @param secondary_fbinfo incoming framebuffer info. + * @param dc display configuration + * @param flags modify function behavior + * + * @return 0 on success + * @return -IGD_INVAL on failure + */ +int igd_alter_displays( + igd_driver_h driver_handle, + igd_display_h *_primary, + igd_display_info_t *primary_pt_info, + igd_framebuffer_info_t *primary_fb_info, + igd_display_h *_secondary, + igd_display_info_t *secondary_pt_info, + igd_framebuffer_info_t *secondary_fb_info, + unsigned long dc, + unsigned long flags) +{ + igd_context_t *context = (igd_context_t *)driver_handle; + igd_display_context_t **primary = (igd_display_context_t **)_primary; + igd_display_context_t **secondary = (igd_display_context_t **)_secondary; + igd_framebuffer_info_t *fb_info = NULL; + igd_display_context_t *display = NULL,*tv_display=NULL; + int p; + int ret; + unsigned short tv_port_num=0; + int p_chng = 1, s_chng = 1; + unsigned char disable_plane_pipe = 0; + unsigned long current_dc; + +#if 0 /* Ian Elliott is taking this out ... see comment below */ +#ifndef CONFIG_MICRO + igd_framebuffer_info_t *plane_fb_info = NULL; +#endif +#endif /* 0 -- Ian is taking this out */ + + OS_TRACE_ENTER; + + /* + * Make sure the DC is valid + * + * vBIOS won't be able to do this every time, for now only have + * the drivers's do the check. + */ +#ifndef CONFIG_MICRO + if (dc && !dsp_valid_dc(dc, 0)) { + OS_ERROR_EXIT("Invalid display configuration: 0x%08lx", dc); + return -IGD_ERROR_INVAL; + } +#endif + + + /* + * Can all display_info's and fb_info's be NULL? I.E. make this + * function do an alloc of display handles only? If so, then + * check for that condition and return without error. Otherwise + * return an error. + */ + if (dc && (!primary_pt_info && !primary_fb_info) && + (!secondary_pt_info && !secondary_fb_info)) { + OS_ERROR_EXIT("Invalid timing and framebuffer info"); + return -IGD_ERROR_INVAL; + } + +#ifndef CONFIG_MICRO + /* FIXME: GDK Change this to dispatch->idle() */ + if (dsp_wait_rb(mode_context->context) != 0) { + return -IGD_ERROR_INVAL; + } +#endif + + /* If seamless request is NOT set , then do reset_plane_pipe_ports + * else delay it until we cannot support it. + * If seamless is requested by the user and we CAN support it + * then we need to make sure reset_plane_pipe_ports is NOT + * called. That's the whole point anyway. Not to reset anything + * during seamless transition + */ + if(mode_context->seamless != TRUE) { + + /* Reset planes/pipes/ports before doing first alter display */ + if (mode_context->first_alter) { + mode_context->dispatch->reset_plane_pipe_ports( + mode_context->context); + mode_context->first_alter = FALSE; + } + } + + current_dc = *(context->mod_dispatch.dsp_current_dc); + + /* + * Turn off the planes, pipes, and ports associated with the current + * DC. However, limit the change to the primary if the secondary + * display handle is NULL or limit the change to the secondary if the + * the pimary display handle is NULL. + */ + for (p = 7; p > 0; p--) { + if (p > 4) { + display = NULL; + if (DC_PORT_NUMBER(current_dc, p)) { + display = context->mod_dispatch. + dsp_display_list[IGD_DC_SECONDARY(current_dc)]; + s_chng = TIMING_CHANGED(display, dc, current_dc, + secondary_pt_info, secondary_fb_info, + (unsigned long)0xfff00000, flags); + } + + if (s_chng && display && secondary) { + /* if the port is TV, then don't set the power to S3 as this causes + * blank screen and system hang on LVDS on FSDOS, probably because the + * external clock needs to be on till the pipes and + * DPLLs are off + */ + if(PORT(display,DC_PORT_NUMBER(current_dc, p))->pd_type == + PD_DISPLAY_TVOUT) { + tv_display = display; + tv_port_num = DC_PORT_NUMBER(current_dc, p); + } else { + ret = mode_context->dispatch->program_port(display, + DC_PORT_NUMBER(current_dc, p), FALSE); + } + /* The secondary pipe master */ + if (p == 5) { + disable_plane_pipe = 1; + } + } + } else { + display = NULL; + if (DC_PORT_NUMBER(current_dc, p)) { + display = context->mod_dispatch. + dsp_display_list[IGD_DC_PRIMARY(current_dc)]; + p_chng = TIMING_CHANGED(display, dc, current_dc, + primary_pt_info, primary_fb_info, + (unsigned long)0x000ffff0, flags); + } + + if (p_chng && display && primary) { + /* if the port is TV, then don't set the power to S3 as this causes + * blank screen and system hang on LVDS on FSDOS, probably because the + * external clock needs to be on till the pipes and + * DPLLs are off + */ + if(PORT(display,DC_PORT_NUMBER(current_dc, p))->pd_type == + PD_DISPLAY_TVOUT) { + tv_display = display; + tv_port_num = DC_PORT_NUMBER(current_dc, p); + } else { + ret = mode_context->dispatch->program_port(display, + DC_PORT_NUMBER(current_dc, p), FALSE); + } + /* The primary pipe master */ + if (p == 1) { + disable_plane_pipe = 1; + } + } + } + + /* Disable plane and pipe after disabling the ports */ + if (disable_plane_pipe) { + if(mode_context->dispatch->full) { + mode_context->dispatch->full->program_cursor(display, FALSE); + } + mode_context->dispatch->program_plane(display, FALSE); + mode_context->dispatch->program_pipe(display, FALSE); + /*pipes and dplls are off, now turn off tv port */ + if(tv_display) { + ret = mode_context->dispatch->program_port(tv_display, + tv_port_num, FALSE); + tv_display = NULL; + } + disable_plane_pipe = 0; + } + } + +#ifndef CONFIG_MICRO + /* If DC is zero, then return here. A zero dc turns everything off */ + /* This never happens for VBIOS since it only always calls * + * alter_displays at the same point with the same valid DC */ + if (!dc) { + int i; + mode_context->dispatch->reset_plane_pipe_ports(mode_context->context); + /* Should de-allocate everything here */ + dsp_alloc(driver_handle, dc, flags); + /* + * FIXME: This should be done inside dsp alloc, mode module does + * not own this information. + * When dc = 0, set all displays allocated to 0. + */ + for (i=0; imod_dispatch.dsp_display_list[i]) { + context->mod_dispatch.dsp_display_list[i]->allocated = 0; + } + context->mod_dispatch.dsp_display_list[i] = NULL; + } + + return 0; + } +#endif + + /* + * Check the DC (display configuration). If it is the same as the + * current configuration, then don't change any allocations, only + * modify the framebuffers and timings. + */ + if (dc != current_dc) { + OS_DEBUG("Allocate display handles based on DC"); + +#ifndef CONFIG_MICRO + if (swap_required(current_dc, dc, primary)) { + swap_fb_cursor(); + } +#endif + /* + * This function should never be called after VBIOS initialization * + * The dsp_alloc is discarded after VBIOS init and is over- * + * written by font tables. Thus in VBIOS IAL, alter_displays * + * is never get called with a different DC from the 1st time * + */ + dsp_alloc(driver_handle, dc, flags); + + } + + /* Attach the displays to the caller's pointers */ + if (primary) { + *primary = context->mod_dispatch.dsp_display_list[IGD_DC_PRIMARY(dc)]; +#ifndef CONFIG_MICRO + if (*primary && context->mod_dispatch.alloc_queues) { + ret = context->mod_dispatch.alloc_queues(driver_handle, + (*primary)->pipe, flags); + if (ret) { + OS_ERROR("unable to allocate command queues"); + } + } +#endif + } + if (secondary) { + OS_DEBUG("Attaching display 1 to secondary pointer"); + *secondary = context->mod_dispatch. + dsp_display_list[IGD_DC_SECONDARY(dc)]; +#ifndef CONFIG_MICRO + if (*secondary && context->mod_dispatch.alloc_queues) { + ret = context->mod_dispatch.alloc_queues(driver_handle, + (*secondary)->pipe, flags); + if (ret) { + OS_ERROR("unable to allocate command queues"); + } + } +#endif + } + + /* + * Configure the primary display. This configures the timings and the + * framebuffer. Once configured, it turns everythying on. + */ + if(primary && *primary && (primary_pt_info || primary_fb_info) && p_chng) { + OS_DEBUG("Configure primary timings"); + /* make framebuffer changes */ + if (primary_fb_info) { + /* set up new frame buffer info */ + fb_info = primary_fb_info; + } else { + fb_info = PLANE(*primary)->fb_info; + } + + ret = configure_display(driver_handle, + (igd_display_context_t *)(*primary), primary_pt_info, + fb_info, dc, 0, 4, flags); + if (ret) { + OS_DEBUG("Primary display disabled."); + } + } + + /* + * Configure the secondary display. This configures the timings and the + * framebuffer. Once configured, it turns everythying on. + * + * How close is this code to the code for the primary? Could this + * be moved to a separate function? + */ + if (secondary != NULL) { + +#ifndef CONFIG_MICRO + /* + * In the case where we are in extended or clone and our pipe is not + * turned on, we need to turn the pipes on. + * We can run into this situation on pre-Cantiga Gen platforms on Linux + * where LVDS was the primary display and was assigned PIPE B. Then we + * are switching from LVDS to another display and that other display + * wants to take PIPE A. In this case PIPE B will be turned on, the + * display's new port will take PIPE A and turn on PIPE A. The second + * display thinks it is still PIPE A and nothing has changed for it. + * In this case where our pipe is not turned on, we need to let the + * system know that something has changed. + */ + if ((IGD_DC_CLONE(dc) || IGD_DC_EXTENDED(dc)) + && !(OS_READ32(MMIO(*secondary) + PIPE(*secondary)->pipe_reg) + & 0x80000000)) { + s_chng = 1; + } +#endif + + OS_DEBUG("Starting secondary pipe programming"); + if ((*secondary != NULL) && (secondary_pt_info || secondary_fb_info) && + s_chng){ + /* + * Configure the framebuffer. For clone, it is the same + * as the primary. For DIH, it is a unique fb. + */ + OS_DEBUG("configure secondary framebuffer"); + if (dc & IGD_DISPLAY_CONFIG_CLONE) { + fb_info = PLANE(*primary)->fb_info; + } else { + if (secondary_fb_info) { + fb_info = secondary_fb_info; + } else { + fb_info = PLANE(*secondary)->fb_info; + } + } + + ret = configure_display(driver_handle, + (igd_display_context_t *)(*secondary), secondary_pt_info, + fb_info, dc, 4, 7, flags); + if (ret) { + OS_DEBUG("Secondary display disabled."); + OS_ERROR("Secondary display disabled."); + } + } + } else { + OS_DEBUG("Skipped secondary programming, NULL handle"); + } + + /* + * Workaround: wait for Vblank to avoid people accessing display + * plane registers before the register is updated properly. + */ + if (primary && *primary) { + OS_DEBUG("Wait for vblank on primary display (%p)", primary); + OS_DEBUG("Wait for vblank on primary display (%p)", *primary); + mode_context->dispatch->wait_vblank(*primary); + } else if (secondary && *secondary) { + OS_DEBUG("Wait for vblank on secondary display"); + mode_context->dispatch->wait_vblank(*secondary); + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * This function sets the power state for the passed + * display handle. This only updates the power state for the + * display/port. The pipe, plane, and ringbuffer are left in + * the same power state. There is also no need to + * alter_display, since only the port is modified. + * + * @param driver_handle from igd_init(). + * @param port_number + * @param power_state + * + * @return 0 on success + * @return -IGD_INVAL on failure + */ +int igd_power_display(igd_driver_h driver_handle, + unsigned short port_number, + unsigned int power_state) +{ + igd_context_t *context = (igd_context_t *)driver_handle; + igd_display_context_t *display; + + OS_TRACE_ENTER; + OS_DEBUG("Requested power state = %d", power_state); + + /* Get the display context that is currently using this port. */ + display = context->mod_dispatch.dsp_display_list[port_number]; + if(!display) { + return -IGD_ERROR_INVAL; + } + + /* If this display is allocated, but has not been altered, return + * an error. */ + if (!PORT(display, port_number)->pt_info || !PIPE(display)->timing) { + OS_TRACE_EXIT; + return -IGD_ERROR_INVAL; + } + + /* Set the desired power state to the display handle and let program_port + * take care of the rest + */ + PORT(display, port_number)->power_state = (unsigned long)power_state; + + switch(power_state) { + case IGD_POWERSTATE_D0: + mode_context->dispatch->program_port(display, port_number, TRUE); + mode_context->dispatch->post_program_port(display, port_number, 0); + break; + case IGD_POWERSTATE_D1: + case IGD_POWERSTATE_D2: + case IGD_POWERSTATE_D3: + mode_context->dispatch->program_port(display, port_number, TRUE); + break; + default: + break; + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param driver_handle from igd_init(). + * @param port_number + * @param edid_ptr + * @param block_number + * + * @return 0 on success + * @return -IGD_ERROR_INVAL or -IGD_ERROR_EDID on failure + */ +/* FIXME: Move this to PI */ +static int igd_get_EDID_block(igd_driver_h driver_handle, + unsigned short port_number, + unsigned char FAR *edid_ptr, + unsigned char block_number) +{ + igd_context_t *context = (igd_context_t *)driver_handle; + igd_display_port_t *port; + int ret; + + OS_TRACE_ENTER; + + OS_ASSERT(driver_handle, "Null driver_handle", -IGD_ERROR_INVAL); + OS_ASSERT(edid_ptr, "Null edid_ptr", -IGD_ERROR_INVAL); + + port = context->mod_dispatch.dsp_port_list[port_number]; + if(!port) { + OS_TRACE_EXIT; + return -IGD_ERROR_INVAL; + } + /* Read EDID */ + ret = context->mod_dispatch.i2c_read_regs( + context, + port->ddc_reg, + 10, /* DDC speed 10 KHz */ + port->ddc_dab, + 128*block_number, + edid_ptr, + 128); + + if (ret) { + OS_TRACE_EXIT; + return -IGD_ERROR_EDID; + } + + OS_TRACE_EXIT; + return 0; +} /* end igd_get_EDID_block() */ + +/*! + * Return either a pointer to the live mode list or a copy of the mode list + * for the requested display. This will be the mode list for the master port + * on the pipe. + * + * @note Currently (AS of 3.3 development) the mode list is + * described as a igd_display_info_t. However IT IS NOT, this + * pointer must be cast to a igd_timing_info_t to be used. After + * 3.3 the igd_display_info_t will be altered to match the + * igd_timing_info_t with the exception of the private pointers. + * + * @param driver_handle handle returned from a successful call to + * igd_driver_init(). + * @param dc Display configuration that will determine which port + * controlls the pipe timings and thus, which set of timings to return. + * @param mode_list The returned mode list. This data may be LIVE. If + * a live list is returned, care should be taken to not free or alter + * the data. + * @param flags The flags will determine which display to query (primary + * or secondary) and if the mode list returned should be the live list. + * + * @return 0 on success. + * @return -IGD_INVAL if an error occured (memory allocation failed) + */ +int igd_query_mode_list(igd_driver_h driver_handle, + unsigned long dc, + igd_display_info_t **mode_list, + unsigned long flags) +{ + igd_context_t *context; + unsigned short port_number; + igd_display_port_t *port; + + OS_TRACE_ENTER; + + context = (igd_context_t *)driver_handle; + *mode_list = NULL; + + /* given the DC and flags, which port number to check? */ + port_number = (flags & IGD_QUERY_SECONDARY_MODES) ? DC_PORT_NUMBER(dc, 5) : + DC_PORT_NUMBER(dc, 1); + + port = context->mod_dispatch.dsp_port_list[port_number]; + if (port) { + if (flags & IGD_QUERY_LIVE_MODES) { + /* + * FIXME: + * timing_table is not an igd_dislay_info_t structure but + * eventually it will be? + */ + *mode_list = (igd_display_info_t *)port->timing_table; + } else { + OPT_MICRO_CALL(full_mode_query(driver_handle, dc, mode_list, + port)); + } + } + + if (*mode_list == NULL) { + OS_DEBUG("No port on requested pipe"); + return -IGD_ERROR_INVAL; + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * This function is used to initialize any module/dsp + * module specific structures or tables etc. + * + * @param context SS level igd_context. + * + * @return 0 on success. + * @return -IGD_INVAL or -IGD_ERROR_NODEV on failure + */ +int mode_init(igd_context_t *context) +{ + igd_dispatch_t *dispatch = &context->dispatch; + inter_module_dispatch_t *md; + + OS_TRACE_ENTER; + + OS_DEBUG("Allocating a mode context..."); + + /* Clear the allocated memory for mode context */ + OS_MEMSET((void *)mode_context, 0, sizeof(mode_context_t)); + + /* Set the pointer to igd level context */ + mode_context->context = context; + mode_context->first_alter = TRUE; + mode_context->display_color = + context->mod_dispatch.init_params->display_color; + + /* Get mode's dispatch table */ + mode_context->dispatch = (mode_dispatch_t *) + dispatch_acquire(context, mode_dispatch); + if(!mode_context->dispatch) { + OS_ERROR_EXIT("Unsupported Device"); + return -IGD_ERROR_NODEV; + } + + md = &context->mod_dispatch; + + /* Set the fw_info to 0 */ + mode_context->fw_info = NULL; + + /* Hook up the IGD dispatch table entires for mode */ + dispatch->get_EDID_block = igd_get_EDID_block; + dispatch->power_display = igd_power_display; + dispatch->query_mode_list = igd_query_mode_list; + dispatch->alter_displays = igd_alter_displays; + + OPT_MICRO_CALL(full_mode_init(context, mode_context)); + + /* Hook up inter-module dispatch functions */ + md->mode_get_gpio_sets = mode_context->dispatch->get_gpio_sets; + md->mode_reset_plane_pipe_ports = + mode_context->dispatch->reset_plane_pipe_ports; + md->filter_modes = mode_context->dispatch->filter_modes; + + /* Hook up Core specific IGD dispatch table entries */ + dispatch->set_palette_entries = + mode_context->dispatch->full->set_palette_entries; + dispatch->set_palette_entry = mode_context->dispatch->set_palette_entry; + dispatch->get_palette_entry = mode_context->dispatch->get_palette_entry; + dispatch->wait_vblank = mode_context->dispatch->wait_vblank; + + /* Initialize dsp module */ + if (dsp_init(context)) { + OS_ERROR("dsp_init() failed."); + return -IGD_INVAL; + } + + /* Initialze port interface (pi) module */ + if (pi_init(context)) { + OS_ERROR_EXIT("pi_init() failed."); + if(md->dsp_shutdown) { + md->dsp_shutdown(context); + } + return -IGD_ERROR_INVAL; + } + + if (mode_context->dispatch->full && md->reg_get_mod_state) { + /* Save mode state */ + module_state_h *state = NULL; + unsigned long *flags = NULL; + md->reg_get_mod_state(REG_MODE_STATE, &state, &flags); + md->mode_save(context, state, flags); + } + + /* Initialize the Display Configuration List */ + /* FIXME: This should be done in dsp init */ + dsp_dc_init(context); + + OS_TRACE_EXIT; + return 0; +} diff --git a/drivers/gpu/drm/emgd/emgd/display/mode/cmn/mode_dispatch.h b/drivers/gpu/drm/emgd/emgd/display/mode/cmn/mode_dispatch.h new file mode 100644 index 0000000..dc6d754 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/mode/cmn/mode_dispatch.h @@ -0,0 +1,163 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: mode_dispatch.h + * $Revision: 1.3 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * This header file defined the interface between the DI layer of the mode + * module and the DD layer. Additionally it defines the interface between + * the different DI object files within the mode module. + *----------------------------------------------------------------------------- + */ + +#ifndef _MODE_DISPATCH_H +#define _MODE_DISPATCH_H + +#include + +typedef struct _mode_full_dispatch { + int (*alter_cursor_pos)(igd_display_h display_handle, + igd_cursor_info_t *cursor_info); + int (*set_palette_entries)(igd_display_h display_handle, + unsigned long *palette_colors, unsigned int start_index, + unsigned int count); + int (*wait_vsync)(igd_display_h display_handle); + int (*query_in_vblank)(igd_display_h display_handle); + int (*get_scanline)(igd_display_h display_handle, int *scanline); + int (*set_display_base)(igd_display_context_t *display, + igd_framebuffer_info_t *fb, unsigned long *x, unsigned long *y); + void (*program_cursor)(igd_display_context_t *display, + unsigned long status); + int (*set_color_correct)(igd_display_context_t *display); + int (*get_surface)(igd_display_h display_handle, igd_buffertype_t type, + igd_surface_t *surface, igd_appcontext_h appcontext); + int (*set_surface)(igd_display_h display_handle, int priority, + igd_buffertype_t type, igd_surface_t *surface, + igd_appcontext_h appcontext, unsigned long flags); + int (*query_event)(igd_display_h display_handle, igd_event_t event, + unsigned long *status); + + int (*set_flip_pending)(unsigned char *mmio, + unsigned long pipe_status_reg); + int (*check_flip_pending)(unsigned char *mmio, + unsigned long pipe_status_reg); + + int (*get_plane_info)(void); /* dispatch routines that gets fw info */ + int (*get_pipe_info)(void); + int (*get_port_info)(void); +} mode_full_dispatch_t; + +typedef struct _mode_dispatch { + int (*set_palette_entry)(igd_display_h display_handle, + unsigned long palette_entry, unsigned long palette_color); + int (*get_palette_entry)(igd_display_h display_handle, + unsigned long palette_entry, unsigned long *palette_color); + int (*wait_vblank)(igd_display_h display_handle); + void (*program_plane)(igd_display_context_t *display, + unsigned long status); + void (*program_pipe)(igd_display_context_t *display, unsigned long status); + int (*program_port)(igd_display_context_t *display, + unsigned short port_number, unsigned long status); + int (*post_program_port)(igd_display_context_t *display, + unsigned short port_number, unsigned long status); + int (*program_clock)(igd_display_context_t *display, + igd_clock_t *clock, unsigned long dclk); + void (*reset_plane_pipe_ports)(igd_context_t *context); + unsigned long (*get_gpio_sets)(unsigned long **); + void (*filter_modes)(igd_context_t *context, + igd_display_port_t *port, pd_timing_t *in_list); + mode_full_dispatch_t *full; +} mode_dispatch_t; + + +/* + * Firmware(VBIOS or EFI Video Driver) related information + * that needs to be populated before the driver re-programs + * the Hardware Registers. This information is needed to provide + * seamless transition from firmware to driver. + */ +typedef struct _fw_info { + + /* TODO: Fill this up */ + unsigned long fw_dc; /* The dsp module already has this value */ + + /* Plane information */ + igd_framebuffer_info_t fb_info[2]; /* one for each plane */ + + /* Pipe information */ + igd_display_info_t timing_arr[2]; /* one for each pipe */ + + /* Port information */ + + /* if the plane registers needs an update, set this field to 1 */ + int program_plane; + +} fw_info_t; + +typedef struct _mode_context { + /* + * All of the below values will be initialized in mode module + * init function mode_init(). + */ + unsigned long first_alter; + mode_dispatch_t *dispatch; + + igd_context_t *context; + unsigned long display_color; + fw_info_t* fw_info; /* This needs to be zero for VBIOS */ + + /* quickboot options */ + unsigned long quickboot; + int seamless; + unsigned long video_input; + int splash; +} mode_context_t; + +extern int full_mode_init(igd_context_t *context, + mode_context_t *mode_context); + +extern int full_mode_query(igd_driver_h driver_handle, unsigned long dc, + igd_display_info_t **mode_list, igd_display_port_t *port); + +extern void full_clear_fb(mode_context_t *mode_context, + igd_framebuffer_info_t *fb_info); + +extern int query_seamless(unsigned long dc, + int index, + igd_timing_info_t *pt, + igd_framebuffer_info_t *pf, + unsigned long flags); + +extern void swap_fb_cursor( void ); + +extern int set_color_correct(igd_display_context_t *display, + const igd_range_attr_t *attr_to_set); + +extern mode_context_t mode_context[]; + +/* + * NOTE: Some of these externs are declared with the struct name because the + * contents of that struct are unavailable at the DI layer. The symbol + * is used as the generic mode_dispatch_t which is a subset. + */ + + +extern mode_dispatch_t mode_dispatch_plb; +extern mode_dispatch_t mode_dispatch_tnc; + +#endif diff --git a/drivers/gpu/drm/emgd/emgd/display/mode/cmn/vga_mode.c b/drivers/gpu/drm/emgd/emgd/display/mode/cmn/vga_mode.c new file mode 100644 index 0000000..592ab7f --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/mode/cmn/vga_mode.c @@ -0,0 +1,1285 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: vga_mode.c + * $Revision: 1.3 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * This file contains VGA plane/pipe programming functions that can + * be used on any VGA compatible hardware. Hardware specific functions + * should put the device in VGA compatible mode prior to calling thses + * functions. + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.mode + +#include + +#include + +#include + +#include +#include +#include + +/*! + * @addtogroup display_group + * @{ + */ + +/* + * For mono modes this is 0 (CRTC is at 0x3b4) + * For other modes it is 0x20 (CRTC is at 0x3d4) + */ +unsigned char vga_port_offset = 0x20; + +/* This is a global variable used by the vBIOS to override the mode table + * if a User Defined Mode Table is set. */ +vga_mode_data_t FAR (*vga_mode_data_ptr)[]=&vga_mode_data; + +/* This is a global variable used by the vBIOS to enable/disable the + * loading of the palette during a mode change. A global variable is + * the best choice, since this is not really an OAL interface. + * 0=Do load the default palette on a mode change. + * 1=Do NOT load the default palette on a mode change. */ +unsigned char vga_disable_default_palette_load = 0; + +/*! + * + * @param mmio + * @param port + * @param index + * @param value + * + * @return void + */ +void write_vga_reg(unsigned char *mmio, unsigned short port, + unsigned char index, unsigned char value) +{ + WRITE_VGA(mmio, port, index, value); +} + +/*! + * + * @param display + * @param timings + * + * @return void + */ +void program_plane_vga(igd_display_context_t *display, + igd_timing_info_t *timings) +{ + unsigned char *mmio; + + OS_DEBUG("Enter program_plane_vga"); + + mmio = (unsigned char *)MMIO(display); + /* Set Bit 5 so the plane remains off. It will be turned on + * in the IAL. This is necessary, so the clear screen can occur + * before the mode is enabled. */ + write_vga_reg(mmio, SR_PORT, 0x01, + (*vga_mode_data_ptr)[timings->mode_number].sr_regs[0] | 0x20); + OS_SLEEP(1000); + + return; +} + +unsigned char mono_colors[] = {0x00, 0x2a, 0x00, 0x3f}; +unsigned char normal_colors[] = {0x00, 0x2a, 0x15, 0x3f}; + +unsigned char mono_color_bits[] = {8,16,8,16,8,16}; +unsigned char p16_color_bits[] = {4,16,2,16,1,16}; +unsigned char p64_color_bits[] = {4,32,2,16,1,8}; + +/*! + * + * @param mmio + * @param n + * + * @return void + */ +void set_3f_palette(unsigned char *mmio, int n) +{ + int i; + for(i=0; i=0; h--) { + OS_WRITE8( *bottom + (pattern_number[h]*adder + 1)/4, + OS_MMIO(mmio) + 0x3c9); + } + pattern_number[changing_pattern] += diff; + } + diff = -diff; + changing_pattern++; + changing_pattern %= 3; + } + bottom++; + } + top++; + } + set_3f_palette(mmio, 8); +} + +static unsigned char next_ar; +static unsigned char next_cr; +static unsigned char next_gr; +static unsigned char *g_mmio; + +/*! + * This is a little trick to save some space. Write these registers + * sequentially to save us a little bit of data space. + * + * @param value + * + * @return void + */ +void write_next_ar_reg(unsigned char value) +{ + WRITE_AR(g_mmio, next_ar, value); + next_ar++; +} + +/*! + * This is a little trick to save some space. Write these registers + * sequentially to save us a little bit of data space. + * + * @param value + * + * @return void + */ +void write_next_cr_reg(unsigned char value) +{ + write_vga_reg(g_mmio, CR_PORT, next_cr, value); + next_cr++; +} + +/*! + * This is a little trick to save some space. Write these registers + * sequentially to save us a little bit of data space. + * + * @param value + * + * @return void + */ +void write_next_gr_reg(unsigned char value) +{ + write_vga_reg(g_mmio, GR_PORT, next_gr, value); + next_gr++; +} + +/*! + * This function programs the Timing registers and clock registers and + * other control registers for PIPE. + * + * @param display + * @param timings + * + * @return void + */ +void program_pipe_vga(igd_display_context_t *display, + igd_timing_info_t *timings) +{ + unsigned char *mmio, i; + unsigned char *colors=0; + unsigned char palette_hack=0; + unsigned char *color_bits = 0; + int mode_index; + unsigned char msr_temp; + + /* This is a mapping from the HAL mode number to the type of Palette + * being programmed for this mode. */ + char palette_type[] = { + /* 9=Don't care. + * 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + 1, 1, 1, 1, 1, 1, 1, 2, 9, 9, 9, 9, 9, 1, 1, 9, + 9, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 4 }; + + OS_DEBUG("Enter program_pipe_vga"); + + mmio = (unsigned char *)MMIO(display); + g_mmio = mmio; + mode_index = timings->mode_number; + + OS_DEBUG("IGD Mode#:0x%x", mode_index); + + /* Disable Group 0 Protection */ + write_vga_reg(mmio, CR_PORT, 0x11, 0x00); + + /* + * Note: for monochrome modes this will cause the IO port to change + * for the CRTC and the Status regs. + */ + msr_temp = (*vga_mode_data_ptr)[mode_index].misc_reg; + +#ifdef CONFIG_GN4 + /* + * According to Chrontel the VGA By-pass requires the HSYNC and VSYNC to be + * of positive polarity. In the MSR - Miscellaneous Output register + * Bit 7 is CRT VSYNC polarity (0 = Positive, 1 = Negative) + * Bit 6 is CRT HSYNC polarity (0 = Positive, 1 = Negative) + */ + { + igd_display_port_t *port; + port = PORT_OWNER(display); + if (port->port_type == IGD_PORT_DIGITAL) { + msr_temp &= (~(BIT(7)|BIT(6))); + } + } +#endif + OS_WRITE8(msr_temp, OS_MMIO(mmio) + 0x3c2); + + if((*vga_mode_data_ptr)[mode_index].misc_reg & 1) { + vga_port_offset = 0x20; + } else { + vga_port_offset = 0; + } + + /* Sequencer registers */ + /* + * Note: Most specs say 0 in SR00 scratch bits but in practice seems + * that everyone uses 3. + */ + write_vga_reg(mmio, SR_PORT, 0x00, 0x03); + /* SR01 is on/off and done in program plane */ + for (i=2; i<=4; i++) { + write_vga_reg(mmio, SR_PORT, i, + /* The SR Regs in the table are from SR01-SR04, there is + * no SR00 in the table, so -1. */ + (*vga_mode_data_ptr)[mode_index].sr_regs[i-1]); + } + + /* Graphics control registers 0x0-0x8,0x10 */ + next_gr = 0; + for(i=0; i<=0x8; i++) { + write_next_gr_reg((*vga_mode_data_ptr)[mode_index].gr_regs[i]); + } + /* + * GR10 is a non-standard register that controls the mapping of + * 0xa000 to MMIO or GTT memory. + */ + next_gr = 0x10; + write_next_gr_reg(0x0); + + next_ar = 0; + for(i=0; i<=0x13; i++) { + write_next_ar_reg((*vga_mode_data_ptr)[mode_index].ar_regs[i]); + } + /* Spec says 0x8 for text modes, not done in practice */ + write_next_ar_reg(0x00); + + /* Ensure the Pixel Data Mask Register does not mask the pixel data */ + OS_WRITE8(0xFF, OS_MMIO(mmio) + 0x3c6); + + /* set DAC data value */ + OS_WRITE8(0, OS_MMIO(mmio) + 0x3c8); + + /* Load RAMDAC*/ + switch(palette_type[mode_index]){ + case 0: + color_bits = p64_color_bits; + colors = normal_colors; + palette_hack = 0; + break; + case 1: + color_bits = p16_color_bits; + colors = normal_colors; + palette_hack = 1; + break; + case 2: + color_bits = mono_color_bits; + colors = mono_colors; + palette_hack = 0; + break; + default: + break; + } + /* Program the Palette based on the mode. */ + if (!vga_disable_default_palette_load) { + if (color_bits) { + set_palette_vga(mmio, 64, color_bits, colors, palette_hack); + set_3f_palette(mmio, 192); + } else { + set_256_palette(mmio); + } + } + + /* Timings */ + next_cr = 0; + for(i=0; i<=0x18; i++) { + write_next_cr_reg((*vga_mode_data_ptr)[mode_index].crtc_regs[i]); + } + + return; +} + +/* + * The HAL mode numbers match up to VGA modes in this way: + * VGA Mode : HAL Mode + * 00 00 + * 01 01 + * 02 02 + * 03 03 + * 04 04 + * 05 05 + * 06 06 + * 07 07 + * 0d 0d + * 0e 0e + * 0f 11 + * 10 12 + * 00* 13 + * 01* 14 + * 02* 15 + * 03* 16 + * 00+ 17 + * 01+ 17 + * 02+ 18 + * 03+ 18 + * 07+ 19 + * 11 1A + * 12 1B + * 13 1C + */ + +/* This can not be a static, since the vBIOS will use this as a global */ +vga_mode_data_t VB_CODE_SEG vga_mode_data[] = { + /*============================================================================*/ + /* Modes 00h (Text 40 x 25 Colors 16 gray Font 8 x 8) - Table Entry 00h */ + /*----------------------------------------------------------------------------*/ + { + 0x28,0x18,0x08, /* Text Columns Rows Font */ + 0x0800, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x09,0x03,0x00,0x02}, + + /* Miscellaneous output register value. */ + 0x63, + + /* CRT Controller register values. */ + {0x2D,0x27,0x28,0x90,0x2B,0xA0,0xBF,0x1F, + 0x00,0xC7,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x14,0x1F,0x96,0xB9,0xA3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x10,0x0E,0x00, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 01h (Text 40 x 25 Colors 16 gray Font 8 x 8) - Table Entry 01h */ + /*----------------------------------------------------------------------------*/ + { + 0x28,0x18,0x08, /* Text Columns Rows Font */ + 0x0800, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x09,0x03,0x00,0x02}, + + /* Miscellaneous output register value. */ + 0x63, + + /* CRT Controller register values. */ + {0x2D,0x27,0x28,0x90,0x2B,0xA0,0xBF,0x1F, + 0x00,0xC7,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x14,0x1F,0x96,0xB9,0xA3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x10,0x0E,0x00, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 02h (Text 80 x 25 Colors 16 gray Font 8 x 8) - Table Entry 02h */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x18,0x08, /* Text Columns Rows Font */ + 0x1000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x01,0x03,0x00,0x02}, + + /* Miscellaneous output register value. */ + 0x63, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x55,0x81,0xBF,0x1F, + 0x00,0xC7,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x28,0x1F,0x96,0xB9,0xA3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x10,0x0E,0x00, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 03h (Text 80 x 25 Colors 16 Font 8 x 8) - Table Entry 03h */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x18,0x08, /* Text Columns Rows Font */ + 0x1000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x01,0x03,0x00,0x02}, + + /* Miscellaneous output register value. */ + 0x63, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x55,0x81,0xBF,0x1F, + 0x00,0xC7,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x28,0x1F,0x96,0xB9,0xA3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x10,0x0E,0x00, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 04h (Graphics 320 x 200 Colors 4 Font 8 x 8) - Table Entry 04h */ + /*----------------------------------------------------------------------------*/ + { + 0x28,0x18,0x08, /* Text Columns Rows Font */ + 0x4000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x09,0x03,0x00,0x02}, + + /* Miscellaneous output register value. */ + 0x63, + + /* CRT Controller register values. */ + {0x2D,0x27,0x28,0x90,0x2B,0x80,0xBF,0x1F, + 0x00,0xC1,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x14,0x00,0x96,0xB9,0xA2, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x01,0x00,0x03,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x30,0x0F,0x00, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 05h (Graphics 320 x 200 Colors 4 gray Font 8 x 8) - Table 05h */ + /*----------------------------------------------------------------------------*/ + { + 0x28,0x18,0x08, /* Text Columns Rows Font */ + 0x4000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x09,0x03,0x00,0x02}, + + /* Miscellaneous output register value. */ + 0x63, + + /* CRT Controller register values. */ + {0x2D,0x27,0x28,0x90,0x2B,0x80,0xBF,0x1F, + 0x00,0xC1,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x14,0x00,0x96,0xB9,0xA2, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x01,0x00,0x03,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x30,0x0F,0x00, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 06h (Graphics 640 x 200 Colors 2 Font 8 x 8) - Table Entry 06h */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x18,0x08, /* Text Columns Rows Font */ + 0x4000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x01,0x01,0x00,0x06}, + + /* Miscellaneous output register value. */ + 0x63, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x54,0x80,0xBF,0x1F, + 0x00,0xC1,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x28,0x00,0x96,0xB9,0xC2, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17, + 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17, + 0x01,0x00,0x01,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x00, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 07h (Text 80 x 25 Colors 2 Font 9 x 14) - Table Entry 07h */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x18,0x0E, /* Text Columns Rows Font */ + 0x1000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x00,0x03,0x00,0x03}, + + /* Miscellaneous output register value. */ + 0xA6, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x55,0x81,0xBF,0x1F, + 0x00,0x4D,0x0B,0x0C,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5D,0x28,0x0D,0x63,0xBA,0xA3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + 0x0E,0x00,0x0F,0x08}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x10,0x0A,0x00, + 0xFF}, + }, + + /*============================================================================*/ + /* Blank Entry - Table Entry 08h */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x18,0x10, /* Text Columns Rows Font */ + 0x7D00, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x21,0x0F,0x00,0x06}, + + /* Miscellaneous output register value. */ + 0x63, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x55,0x81,0xBF,0x1F, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x28,0x1F,0x96,0xB9,0xE3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0x01,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0F, + 0xFF}, + }, + + /*============================================================================*/ + /* Blank Entry - Table Entry 09h */ + /*----------------------------------------------------------------------------*/ + { + 0x00,0x00,0x00, /* Text Columns Rows Font */ + 0x0000, /* Page size */ + + /* Sequencer register values. */ + {0x00,0x00,0x00,0x00}, + + /* Miscellaneous output register value. */ + 0x00, + + /* CRT Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00}, + + /* Attribute Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00}, + }, + + /*============================================================================*/ + /* Blank Entry - Table Entry 0Ah */ + /*----------------------------------------------------------------------------*/ + { + 0x28,0x18,0x08, /* Text Columns Rows Font */ + 0x4000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x00,0x00,0x00,0x03}, + + /* Miscellaneous output register value. */ + 0x23, + + /* CRT Controller register values. */ + {0x37,0x27,0x2D,0x37,0x31,0x15,0x04,0x11, + 0x00,0x47,0x06,0x07,0x00,0x00,0x00,0x00, + 0xE1,0x24,0xC7,0x14,0x08,0xE0,0xF0,0xA3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x08,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x10,0x0E,0x00, + 0xFF}, + }, + + /*============================================================================*/ + /* Blank Entry - Table Entry 0Bh */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x00,0x00, /* Text Columns Rows Font */ + 0x0000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x29,0x0F,0x00,0x06}, + + /* Miscellaneous output register value. */ + 0x62, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x55,0x81,0xBF,0x1F, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x28,0x1F,0x96,0xB9,0xE3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F, + 0x01,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x0F,0x00,0x00,0x08,0x05,0x0F, + 0xFF}, + }, + + /*============================================================================*/ + /* Blank Entry - Table Entry 0Ch */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x00,0x00, /* Text Columns Rows Font */ + 0x0000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x29,0x0F,0x00,0x06}, + + /* Miscellaneous output register value. */ + 0x63, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x55,0x81,0xBF,0x1F, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x28,0x1F,0x96,0xB9,0xE3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F, + 0x01,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x0F,0x00,0x00,0x08,0x05,0x0F, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 0Dh (Graphics 320 x 200 Colors 16 Font 8 x 8) - Table Entry 0Dh */ + /*----------------------------------------------------------------------------*/ + { + 0x28,0x18,0x08, /* Text Columns Rows Font */ + 0x2000, /* Page size */ + + /* Sequencer register values. */ + {0x09,0x0F,0x00,0x06}, + + /* Miscellaneous output register value. */ + 0x63, + + /* CRT Controller register values. */ + {0x2D,0x27,0x28,0x90,0x2B,0x80,0xBF,0x1F, + 0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x14,0x00,0x96,0xB9,0xE3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x01,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0F, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 0Eh (Graphics 640 x 200 Colors 16 Font 8 x 8) - Table Entry 0Eh */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x18,0x08, /* Text Columns Rows Font */ + 0x4000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x01,0x0F,0x00,0x06}, + + /* Miscellaneous output register value. */ + 0x63, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x54,0x80,0xBF,0x1F, + 0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x28,0x00,0x96,0xB9,0xE3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x01,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0F, + 0xFF}, + }, + + /*============================================================================*/ + /* Blank Entry - Table Entry 0Fh */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x18,0x0E, /* Text Columns Rows Font */ + 0x8000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x05,0x0F,0x00,0x00}, + + /* Miscellaneous output register value. */ + 0xA2, + + /* CRT Controller register values. */ + {0x60,0x4F,0x56,0x1A,0x50,0xE0,0x70,0x1F, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x5E,0x2E,0x5D,0x14,0x00,0x5E,0x6E,0x8B, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x08,0x00,0x00,0x18,0x18,0x00,0x00, + 0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00, + 0x0B,0x00,0x05,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x10,0x07,0x0F, + 0xFF}, + }, + + /*============================================================================*/ + /* Blank Entry - Table Entry 10h */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x18,0x0E, /* Text Columns Rows Font */ + 0x8000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x05,0x0F,0x00,0x00}, + + /* Miscellaneous output register value. */ + 0xA7, + + /* CRT Controller register values. */ + {0x5B,0x4F,0x53,0x17,0x50,0xBA,0x6C,0x1F, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x5E,0x2B,0x5D,0x14,0x0F,0x5F,0x0A,0x8B, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x00,0x00,0x04,0x07,0x00,0x00, + 0x00,0x01,0x00,0x00,0x04,0x07,0x00,0x00, + 0x01,0x00,0x05,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x10,0x07,0x0F, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 0Fh; (Graphics 640 x 350 Colors 2 Font 8 x 14) - Table Entry 11h */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x18,0x0E, /* Text Columns Rows Font */ + 0x8000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x01,0x0F,0x00,0x06}, + + /* Miscellaneous output register value. */ + 0xA2, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x54,0x80,0xBF,0x1F, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5D,0x28,0x0F,0x63,0xBA,0xE3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x08,0x00,0x00,0x18,0x18,0x00,0x00, + 0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00, + 0x0B,0x00,0x05,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x05, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 10h; (Graphics 640 x 350 Colors 16 Font 8 x 14) - Table Entry 12h */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x18,0x0E, /* Text Columns Rows Font */ + 0x8000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x01,0x0F,0x00,0x06}, + + /* Miscellaneous output register value. */ + 0xA3, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x54,0x80,0xBF,0x1F, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5D,0x28,0x0F,0x63,0xBA,0xE3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0x01,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0F, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 00h; (Text 40 x 25 Colors 16 gray Font 8 x 14) - Table Entry 13h */ + /*----------------------------------------------------------------------------*/ + { + 0x28,0x18,0x0E, /* Text Columns Rows Font */ + 0x0800, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x09,0x03,0x00,0x02}, + + /* Miscellaneous output register value. */ + 0xA3, + + /* CRT Controller register values. */ + {0x2D,0x27,0x28,0x90,0x2B,0xA0,0xBF,0x1F, + 0x00,0x4D,0x0B,0x0C,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5D,0x14,0x1F,0x63,0xBA,0xA3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0x08,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x10,0x0E,0x00, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 01h; (Text 40 x 25 Colors 16 Font 8 x 14) - Table Entry 14h */ + /*----------------------------------------------------------------------------*/ + { + 0x28,0x18,0x0E, /* Text Columns Rows Font */ + 0x0800, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x09,0x03,0x00,0x02}, + + /* Miscellaneous output register value. */ + 0xA3, + + /* CRT Controller register values. */ + {0x2D,0x27,0x28,0x90,0x2B,0xA0,0xBF,0x1F, + 0x00,0x4D,0x0B,0x0C,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5D,0x14,0x1F,0x63,0xBA,0xA3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0x08,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x10,0x0E,0x00, + 0xFF}, + }, + + /*============================================================================*/ +// ; Modes 02h; (Text 80 x 25 Colors 16 gray Font 8 x 14) - Table Entry 15h // + /*----------------------------------------------------------------------------*/ + { + 0x50,0x18,0x0E, /* Text Columns Rows Font */ + 0x1000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x01,0x03,0x00,0x02}, + + /* Miscellaneous output register value. */ + 0xA3, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x55,0x81,0xBF,0x1F, + 0x00,0x4D,0x0B,0x0C,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5D,0x28,0x1F,0x63,0xBA,0xA3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0x08,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x10,0x0E,0x00, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 03h; (Text 80 x 25 Colors 16 Font 8 x 14) - Table Entry 16h */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x18,0x0E, /* Text Columns Rows Font */ + 0x1000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x01,0x03,0x00,0x02}, + + /* Miscellaneous output register value. */ + 0xA3, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x55,0x81,0xBF,0x1F, + 0x00,0x4D,0x0B,0x0C,0x00,0x00,0x00,0x00, + 0x83,0x85,0x5D,0x28,0x1F,0x63,0xBA,0xA3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0x08,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x10,0x0E,0x00, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 00h+ ; 01h+ (Text 40 x 25 Colors 16 Font 9 x 16) - Table 17h */ + /*----------------------------------------------------------------------------*/ + { + 0x28,0x18,0x10, /* Text Columns Rows Font */ + 0x0800, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x08,0x03,0x00,0x02}, + + /* Miscellaneous output register value. */ + 0x67, + + /* CRT Controller register values. */ + {0x2D,0x27,0x28,0x90,0x2B,0xA0,0xBF,0x1F, + 0x00,0x4F,0x0D,0x0E,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x14,0x1F,0x96,0xB9,0xA3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0x0C,0x00,0x0F,0x08}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x10,0x0E,0x00, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 02h+ ; 03h+ (Text 80 x 25 Colors 16 Font 9 x 16) - Table 18h */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x18,0x10, /* Text Columns Rows Font */ + 0x1000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x00,0x03,0x00,0x02}, + + /* Miscellaneous output register value. */ + 0x67, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x55,0x81,0xBF,0x1F, + 0x00,0x4F,0x0D,0x0E,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x28,0x1F,0x96,0xB9,0xA3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0x0C,0x00,0x0F,0x08}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x10,0x0E,0x00, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 07h+ (Text 80 x 25 Colors 2 Font 9 x 16) - Table Entry 19h */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x18,0x10, /* Text Columns Rows Font */ + 0x1000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x00,0x03,0x00,0x02}, + + /* Miscellaneous output register value. */ + 0x66, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x55,0x81,0xBF,0x1F, + 0x00,0x4F,0x0D,0x0E,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x28,0x0F,0x96,0xB9,0xA3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08, + 0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + 0x0E,0x00,0x0F,0x08}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x10,0x0A,0x00, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 11h (Graphics 640 x 480 Colors 2 Font 8 x 16) - Table Entry 1Ah */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x1D,0x10, /* Text Columns Rows Font */ + 0xA000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x01,0x0F,0x00,0x06}, + + /* Miscellaneous output register value. */ + 0xE3, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x54,0x80,0x0B,0x3E, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0xEA,0x8C,0xDF,0x28,0x00,0xE7,0x04,0xC3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, + 0x01,0x00,0x01,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x01, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 12h (Graphics 640 x 480 Colors 16 Font 8 x 16) - Table Entry 1Bh */ + /*----------------------------------------------------------------------------*/ + { + 0x50,0x1D,0x10, /* Text Columns Rows Font */ + 0xA000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x01,0x0F,0x00,0x06}, + + /* Miscellaneous output register value. */ + 0xE3, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x54,0x80,0x0B,0x3E, + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0xEA,0x8C,0xDF,0x28,0x00,0xE7,0x04,0xE3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07, + 0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0x01,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0F, + 0xFF}, + }, + + /*============================================================================*/ + /* Modes 13h (Graphics 320 x 200 Colors 256 Font 8 x 8) - Table Entry 1Ch */ + /*----------------------------------------------------------------------------*/ + { + 0x28,0x18,0x08, /* Text Columns Rows Font */ + 0x2000, /* Page size */ + + /* Sequencer register values, SR01-SR04. */ + {0x01,0x0F,0x00,0x0E}, + + /* Miscellaneous output register value. */ + 0x63, + + /* CRT Controller register values. */ + {0x5F,0x4F,0x50,0x82,0x54,0x80,0xBF,0x1F, + 0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x28,0x40,0x96,0xB9,0xA3, + 0xFF}, + + /* Attribute Controller register values. */ + {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, + 0x41,0x00,0x0F,0x00}, + + /* Graphics Controller register values. */ + {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F, + 0xFF} + }, +}; + diff --git a/drivers/gpu/drm/emgd/emgd/display/mode/plb/clocks_plb.c b/drivers/gpu/drm/emgd/emgd/display/mode/plb/clocks_plb.c new file mode 100644 index 0000000..fe70e5f --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/mode/plb/clocks_plb.c @@ -0,0 +1,512 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: clocks_plb.c + * $Revision: 1.3 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.mode + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +/*! + * @addtogroup display_group + * @{ + */ + +/*=========================================================================== +; File Global Data +;--------------------------------------------------------------------------*/ +typedef struct _fixed_clock { + unsigned long dclk; + unsigned long n; + unsigned long m1; + unsigned long m2; + unsigned long p; +}fixed_clock_t; + +static fixed_clock_t fixed_clock_table[] = { + /* Clock N M1 M2 Post Div */ + { 43163, 0x03, 0x12, 0x06, 0x84}, /* 43.163 GTF for 640x480 @ 100Hz */ + { 81624, 0x03, 0x18, 0x04, 0x82}, /* 81.624MHz */ + {0xffffffff, 0x00, 0x00, 0x00, 0x00} +}; + +/*! + * This function translates from the calculated M value to the M1, M2 + * register values. + * + * @param m + * @param *m1 + * @param *m2 + * + * @return 0 on success + * @return 1 on failure + */ +static int calculate_m1_m2(unsigned long m, + unsigned long *m1, + unsigned long *m2) +{ + unsigned long current_m1, current_m2; + + OS_DEBUG("Enter calculate_m1_m2 %d", 1); + + /* ori was in steps of 2*/ + for(current_m1 = (10+2); current_m1 <= (20+2); current_m1 += 1) { + for(current_m2 = (5+2); current_m2 <= (9+2); current_m2++) { + if((current_m1 * 5 + current_m2) == m) { + *m1 = current_m1 - 2; + *m2 = current_m2 - 2; + return 0; + } + + } + } + + OS_DEBUG("M1, M2 not found for M == %ld", m); + return 1; +} + +#define MAX_M 120 //216 +#define MIN_M 70 //96 + +#define MAX_N 8 //16 +#define MIN_N 3 + +#define MAX_P 80 //126 +#define MIN_P 5 //2 + +#define LVDS_MAX_P 98 +#define LVDS_MIN_P 7 + +#define FIX_P2_LO 5 //126 +#define FIX_P2_HI 10 //2 + +#define MAX_P1 8 //126 +#define MIN_P1 1 //2 + +#define REF_FREQ 96000 //48000 +#define MAX_VCO 2800000 //1400000 +#define MAX_FP 200000 +/* For LVDS port */ +#define LVDS_FIX_P2_LO 7 +#define LVDS_FIX_P2_HI 14 + +/*! + * + * @param dclk + * @param ref_freq + * @param m1 + * @param m2 + * @param n + * @param p + * @param min_vco + * @param target_error + * @param port_type + * @param dual_channel + * + * @return 0 on success + * @return 1 on failure + */ +static int calculate_clock(unsigned long dclk, + unsigned long ref_freq, + unsigned long *m1, + unsigned long *m2, + unsigned long *n, + unsigned long *p, + unsigned long min_vco, + unsigned long target_error, + unsigned long port_type, + unsigned long dual_channel) + +{ + unsigned long p1; + unsigned long p2; + /* Parameters */ + unsigned long freqmult_p2; + + /* Intermidiate variables */ + unsigned long pdiv; + unsigned long target_vco, actual_freq, actual_vco; + long freq_error, min_error; + + unsigned long current_m, current_n, current_p1; + unsigned long best_m = 0; + unsigned long best_n = 0; + unsigned long best_p1 = 0; + + + OS_DEBUG("Enter calculate_clock"); + + min_error = 100000; + + if (dclk > MAX_FP) { + freqmult_p2 = FIX_P2_LO; + } else { + freqmult_p2 = FIX_P2_HI; + } + + /* For LVDS port */ + if(port_type==IGD_PORT_LVDS){ + /* Test if we are dual channel */ + if(dual_channel){ + freqmult_p2=LVDS_FIX_P2_LO; + } else{ + freqmult_p2=LVDS_FIX_P2_HI; + } + + } + + for(current_m = MIN_M; current_m <= MAX_M; current_m++) { + for(current_n = MIN_N; current_n < MAX_N; current_n++) { + for(current_p1 = MIN_P1; current_p1 <= MAX_P1; current_p1++) { + + pdiv = freqmult_p2 * current_p1; + target_vco = dclk * pdiv; + + if ((target_vco <= MAX_VCO) && (target_vco >= min_vco)) { + actual_freq = (ref_freq * current_m) / + (current_n * pdiv); + actual_vco = actual_freq * pdiv; + freq_error = 10000 - (dclk * 10000 / actual_freq); + + if (freq_error < 0) { + freq_error = -freq_error; + } + if (freq_error < min_error) { + best_n = current_n; + best_m = current_m; + best_p1 = current_p1; + min_error = freq_error; + } + if (min_error == 0) { + break; + } + } + } + if (min_error == 0) { + break; + } + } + if (min_error == 0) { + break; + } + } + /* + * No clock found that meets error requirement + */ + if (min_error > (long)target_error) { + return 1; + } + + + /* Translate M,N,P to m1,m2,n,p register values */ + *n = best_n - 2; + if(calculate_m1_m2(best_m, m1, m2)) { + /* No M1, M2 match for M */ + return 1; + } + + p1 = (1 << (best_p1-1)); + if((freqmult_p2-5)) { + p2 = 0x0; + } + else { + p2 = 0x1; + } + /* Set p2 for LVDS */ + if(port_type==IGD_PORT_LVDS){ + if(dual_channel){ + p2=0x1; + }else{ + p2=0x0; + } + + } + *p = ( p1 | (p2<<8) ); + + return 0; +} + +#define MIN_VCO_PASS1 2000000 //1000000 +#define MIN_VCO_PASS2 1400000 //930000 + +/*! + * + * @param dclk + * @param ref_freq + * @param m1 + * @param m2 + * @param n + * @param p + * @param target_error + * @param port_type + * @param dual_channel + * + * @return 0 on success + * @return 1 on failure + */ +static int get_clock(unsigned long dclk, + unsigned long ref_freq, + unsigned long *m1, + unsigned long *m2, + unsigned long *n, + unsigned long *p, + unsigned long target_error, + unsigned long port_type, + unsigned long dual_channel) +{ + fixed_clock_t *fixed = fixed_clock_table; + + OS_DEBUG("Enter get_clock"); + + /* + * First check for a fixed clock from the table. These are ones that + * can't be calculated correctly. + */ + while(fixed->dclk != 0xffffffff) { + if(fixed->dclk == dclk) { + OS_DEBUG("Using Fixed Clock From table for clock %ld", dclk); + *m1 = fixed->m1; + *m2 = fixed->m2; + *n = fixed->n; + *p = fixed->p; + return 0; + } + fixed++; + } + + + /* + * No fixed clock found so calculate one. + */ + OS_DEBUG("Calculating dynamic clock for clock %ld", dclk); + + /* + * First pass try to find a clock with min_vco at 1000000. + * If a clock doesn't come out then try 930000. + */ + if(calculate_clock(dclk, ref_freq, m1, m2, n, p, MIN_VCO_PASS1, + target_error,port_type,dual_channel)) { + if(calculate_clock(dclk, ref_freq, m1, m2, n, p, MIN_VCO_PASS2, + target_error,port_type,dual_channel)) { + /* No usable clock */ + OS_ERROR("Could not calculate clock %ld, returning default.", + dclk); + *m1 = 0x14; + *m2 = 0xc; + *n = 0x3; + *p = 0x82; + return 1; + } + } + + return 0; +} + +#define TARGET_ERROR 46 + +/*! + * + * @param display + * @param clock + * @param dclk + * + * @return 0 on success + * @return 1 on failure + */ +int program_clock_plb(igd_display_context_t *display, + igd_clock_t *clock, + unsigned long dclk) +{ + unsigned long m1, m2, n, p; + unsigned long control; + unsigned long ref_freq; + int ret; + igd_display_port_t *port; + unsigned long port_mult, vga_mult; + unsigned long dual_channel = 0; + unsigned long index; + + OS_DEBUG("Enter program_clock"); + + port=PORT_OWNER(display); + + if (dclk > 100000) { /* 100-200 MHz */ + + port_mult = 1; + } + else if (dclk > 50000) { /* 50-100 Mhz */ + + port_mult = 2; + } + else { /* 25-50 Mhz */ + + port_mult = 4; + } + + /* + * Clock Multiplier : sDVO ports on all plb chipsets + */ + if (port->port_type == IGD_PORT_DIGITAL) { + + dclk *= port_mult; + } + + vga_mult = READ_MMIO_REG(display, clock->dpll_control) & 0x3; + + /* For Int-LVDS need to find out if its dual channel and pass + * that info into caluculating for p2. Apperently halving + * of dot-clock is also required by Ch7017 when operating in + * dual channel + */ + if (port->port_type == IGD_PORT_LVDS) { + /* Find PD_ATTR_ID_2_CHANNEL_PANEL attr value*/ + pi_pd_find_attr_and_value(PORT_OWNER(display), + PD_ATTR_ID_2_CHANNEL_PANEL, + 0/*no PD_FLAG for 2_channel*/, + NULL, + &dual_channel); + } + + /* For external clock sources always use ref_clock == dclk */ + if(port->pd_flags & PD_FLAG_CLK_SOURCE) { + ref_freq = dclk; + } else { + ref_freq = 96000; + } + /* LVDS reference clock can be 96 or 100 MHz. However there + * are no mention in the specification to specify which register + * to select/set this. + */ + + /* When the clock source is provided externally by the port driver, + * the allowed error range is 0. */ + if(port->pd_flags & PD_FLAG_CLK_SOURCE) { + ret = get_clock(dclk, ref_freq, &m1, &m2, &n, &p, 0 + ,port->port_type,dual_channel); + } else { + ret = get_clock(dclk, ref_freq, &m1, &m2, &n, &p, TARGET_ERROR + ,port->port_type,dual_channel); + } + + if(ret) { + OS_ERROR("Clock %ld could not be programmed", dclk); + return ret; + } + + /* Disable DPLL, Write an 0x80 into P for saftey */ + control = 0x10000000 | (0x80<p_shift) | BIT26 | vga_mult; + WRITE_MMIO_REG(display, clock->dpll_control, control); + + /* Program N, M1,and M2 */ + WRITE_MMIO_REG(display, clock->mnp, (n<<16) | (m1<<8) | m2); + + /* Enable DPLL, Disable VGAm Mode and sitck in new P values */ + if(port->port_type==IGD_PORT_LVDS){ + /* If LVDS set the appropriate bits for mode select */ + control = (BIT31 | BIT28 | BIT27 ) + | (p<p_shift) | vga_mult; + + if(port->attr_list) { + + for(index = 0; index < port->attr_list->num_attrs; index++) { + + /* Set spread spectrum and pulse phase */ + if(port->attr_list->attr[index].id == PD_ATTR_ID_SSC) { + + /* + * Pulse Phase for Poulsbo only has valid values between + * 3 and 9 + */ + if(port->attr_list->attr[index].value >= 3 && + port->attr_list->attr[index].value <= 9) { + + control |= BIT13 | BIT14; + /* + * Set the Pulse Phase to the clock phase specified by + * the user + */ + control |= (port->attr_list->attr[index].value<<9); + } + break; + } + } + } + } else{ + /* else DAC/SDVO */ + control = (BIT31 | BIT28 | BIT26) | (p<p_shift) | vga_mult; + } + /* + * Poulsbo has high speed clock on always + */ + control |= BIT30; + + + + /* Set the clock source correctly based on PD settings */ + if(port->pd_flags & PD_FLAG_CLK_SOURCE) { + control |= port->clock_bits; + } else { + control |= port->clock_bits & ~0x00006000; + } + + /* sDVO Multiplier bits[7:0] */ + if (port->port_type == IGD_PORT_DIGITAL) { + + if (port_mult == 2) { + + control |= (1 << 4); + + } else if (port_mult == 4) { + + control |= (3 << 4); + } + } + + WRITE_MMIO_REG(display, clock->dpll_control, control); + + /* We must wait for 150 us for the dpll clock to warm up */ + OS_SLEEP(150); + + return 0; +} + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: clocks_plb.c,v 1.3 2010/04/27 20:33:49 bpaauwe Exp $ + * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/mode/plb/clocks_plb.c,v $ + *---------------------------------------------------------------------------- + */ diff --git a/drivers/gpu/drm/emgd/emgd/display/mode/plb/micro_mode_plb.c b/drivers/gpu/drm/emgd/emgd/display/mode/plb/micro_mode_plb.c new file mode 100644 index 0000000..3dc062b --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/mode/plb/micro_mode_plb.c @@ -0,0 +1,1393 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: micro_mode_plb.c + * $Revision: 1.9 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * Napa Core implementations for the mode dispatch functions. + * NOTE: This file is designed to produce tiny code and is used in the + * vbios port. Make sure that all MMIO reads and writes do all mmio + * calculation within the OS_READ and OS_WRITE macros so that this code + * will be correctly removed. + * This is OK -> OS_READ32( MMIO(display) + foo_offset ) + * This is NOT OK -> mmio = MMIO(display) + * OS_READ32(mmio + foo_offset) + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.mode + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../cmn/match.h" +#include "../cmn/mode_dispatch.h" + +/*! + * @addtogroup display_group + * @{ + */ + +#ifdef CONFIG_PLB + +typedef struct _mode_data_plb { + unsigned long plane_a_preserve; + unsigned long plane_b_c_preserve; + unsigned long pipe_preserve; + unsigned long port_preserve; + unsigned long fw_blc1; + unsigned long fw_blc2; + unsigned long fw_blc3; + unsigned long fw_self; + unsigned long mem_mode; + unsigned long dsp_arb; +}mode_data_plb_t; + +/* + * Exports from the other components of this module. + */ +extern int program_clock_plb(igd_display_context_t *display, + igd_clock_t *clock, unsigned long dclk); +extern mode_full_dispatch_t mode_full_dispatch_plb; + +static unsigned long gpio_plb[] = { + 0x5010, + 0x5014, + 0x5018, + 0x501c, + 0x5020, + 0x5024, + 0x5028 +}; + +static mode_data_plb_t device_data[1] = { + { + 0x000b0000, /* plane a preservation */ + 0x00000000, /* plane b/c preservation */ + 0x01000000, /* pipe preservation */ + 0, /* port preservation */ + 0x490A010A, /* watermark/burst length 1 */ + 0x14100D0A, /* watermark/burst length 2*/ + 0x00007770, /* watermark/burst length 3 */ + 0x0B0C9812, /* watermark/burst length self */ + 0, /* mem_mode */ + 0x00001D9C, /* dsp arb */ + } +}; + +/*! + * + * @param mmio + * + * @return void + */ +static void disable_vga_plb (unsigned char *mmio) +{ + unsigned long temp; + unsigned char sr01; + + OS_TRACE_ENTER; + + /* Disable VGA plane if it is enabled. */ + temp = OS_READ32(OS_MMIO(mmio) + VGACNTRL); + if ((temp & BIT31) == 0) { + /* Read SR01 */ + READ_VGA(mmio, SR_PORT, 0x01, sr01); + + /* Turn on SR01 bit 5 */ + WRITE_VGA(mmio, SR_PORT, 0x01, sr01|BIT(5)); + /* Wait for 30us */ + OS_SLEEP(30); + + temp |= BIT31; /* set bit 31 to disable */ + temp &= ~BIT30; /* clear bit 30 to get VGA display in normal size */ + OS_WRITE32(temp, OS_MMIO(mmio) + VGACNTRL); + } + /* + * When turing off the VGA plane the palette sometimes gets stuck. + * if we do a couple reads to the palette it will unstuck. + */ + if((1L<<31) & OS_READ32( OS_MMIO(mmio) + PIPEA_CONF )) { + OS_DEBUG("VGA Palette workaround"); + OS_READ32(OS_MMIO(mmio) + DPALETTE_A); + OS_READ32(OS_MMIO(mmio) + DPALETTE_A); + } + if((1L<<31) & OS_READ32( OS_MMIO(mmio) + PIPEB_CONF )) { + OS_DEBUG("VGA Palette workaround"); + OS_READ32(OS_MMIO(mmio) + DPALETTE_B); + OS_READ32(OS_MMIO(mmio) + DPALETTE_B); + } + + OS_TRACE_EXIT; +} + +/*! + * + * @param display_handle + * @param palette_entry + * @param palette_color + * + * @return 0 on success + * @return -IGD_INVAL on failure + */ +static int igd_set_palette_entry_plb( + igd_display_h display_handle, + unsigned long palette_entry, + unsigned long palette_color) +{ + /* Too Slow For Tracing */ + + /* Return if Pipe is not on */ + if(!((1L<<31) & OS_READ32(MMIO(display_handle) + + PIPE(display_handle)->pipe_reg))) { + return -IGD_INVAL; + } + /* + OS_DEBUG("%x : %ld : %lx", display_handle, + palette_entry, palette_color); + */ + OS_WRITE32(palette_color, MMIO(display_handle) + + PIPE(display_handle)->palette_reg + palette_entry * 4); + + return 0; +} + +/*! + * + * @param display_handle + * @param palette_entry + * @param palette_color + * + * @return 0 on success + * @return -IGD_INVAL on failure + */ +static int igd_get_palette_entry_plb( + igd_display_h display_handle, + unsigned long palette_entry, + unsigned long *palette_color) +{ + /* Too Slow For Tracing */ + + /* Return if Pipe is not on */ + if(!((1L<<31) & OS_READ32(MMIO(display_handle) + + PIPE(display_handle)->pipe_reg))) { + return -IGD_INVAL; + } + + *palette_color = 0xffffff & OS_READ32(MMIO(display_handle) + + PIPE(display_handle)->palette_reg + palette_entry * 4); + return 0; +} + +/*! + * + * @param mmio + * @param pipe_reg + * @param time_interval + * + * @return 0 on success + * @return 1 on failure + */ +int wait_for_vblank_timeout_plb( + unsigned char *mmio, + unsigned long pipe_reg, + unsigned long time_interval) +{ +#ifndef CONFIG_MICRO + platform_context_plb_t *plb_context = + (platform_context_plb_t *)mode_context->context->platform_context; + + inter_module_dispatch_t *md = &mode_context->context->mod_dispatch; + int ret; +#endif + unsigned long pipe_status_reg = pipe_reg + PIPE_STATUS_OFFSET; + unsigned long tmp; + os_alarm_t timeout; + + OS_TRACE_ENTER; + + OS_DEBUG("MMIO = %p, pipe_reg = %lx", mmio, pipe_reg); + + /* If pipe is off then just return */ + if(!((1L<<31) & OS_READ32(OS_MMIO(mmio) + pipe_reg))) { + OS_DEBUG("Pipe disabled/Off"); + OS_TRACE_EXIT; + return 1; + } + + /* + * When VGA plane is on the normal wait for vblank won't work + * so just skip it. + */ + if(!(OS_READ32(OS_MMIO(mmio) + 0x71400) & 0x80000000)) { + OS_DEBUG("VGA Plane On"); + OS_TRACE_EXIT; + return 1; + } + + /* If a flip is in progress, then the VBlank interrupt is already + * enabled. + * NOTE: There is a small race condition where after this check + * is made, the VBlank occurs, the other thread sees the VBlank, + * and then starts another VBlank check. This should be rare and + * would likely only miss 1 VBlank in this wait_for_vblank. */ +#ifndef CONFIG_MICRO + ret = OS_PTHREAD_MUTEX_LOCK(&plb_context->flip_mutex); + ret = 0; + OPT_MICRO_CALL_RET(ret, md->check_flip_pending(mmio, pipe_status_reg)); + if (!ret) { +#endif + /* 1. Disable VBlank interrupt */ + tmp = OS_READ32(OS_MMIO(mmio) + pipe_status_reg); + OS_WRITE32 (tmp & ~VBLANK_STS_EN, + OS_MMIO(mmio) + pipe_status_reg); + + /* 2. Clear VBlank interrupt status (by writing a 1) */ + tmp = OS_READ32(OS_MMIO(mmio) + pipe_status_reg); + OS_WRITE32 (tmp | VBLANK_STS, OS_MMIO(mmio) + pipe_status_reg); + + /* 3. Enable VBlank interrupt */ + tmp = OS_READ32(OS_MMIO(mmio) + pipe_status_reg); + OS_WRITE32 (tmp | VBLANK_STS_EN, OS_MMIO(mmio) + pipe_status_reg); +#ifndef CONFIG_MICRO + } + OS_PTHREAD_MUTEX_UNLOCK(&plb_context->flip_mutex); +#endif + + /* + * 4. Wait for VBlank about 20 msec. + * Check for timeout + * Ideally, it would be best if a flip was pending, to set + * flip_pending=0, since it is now done. However, this would + * require a lock around the entire wait which seems excessive. + * So instead, the flip_pending will be set equal to 0 on the + * next call to check_flip_pending_plb. + */ + timeout = OS_SET_ALARM(time_interval); + do { + OS_SCHEDULE(); + tmp = OS_READ32(OS_MMIO(mmio) + pipe_status_reg) & VBLANK_STS; + } while ((tmp == 0x00) && (!OS_TEST_ALARM(timeout))); + if (tmp == 0) { + OS_ERROR_EXIT("Timeout waiting for VBLANK"); + return 0; + } + + OS_TRACE_EXIT; + return 1; +} + +/*! + * + * @param mmio + * @param pipe_reg + * + * @return 0 on success + * @return 1 on failure + */ +int wait_for_vblank_plb(unsigned char *mmio, + unsigned long pipe_reg) +{ + return wait_for_vblank_timeout_plb(mmio, pipe_reg, 100); +} /* wait_for_vblank_plb */ + +/*! + * This procedure waits for the next vertical blanking (vertical retrace) + * period. If the display is already in a vertical blanking period, this + * procedure exits. + * + * Note: A timeout is included to prevent an endless loop. + * + * @param display_handle + * + * @return FALSE if timed out + */ +static int igd_wait_vblank_plb(igd_display_h display_handle) +{ + + return wait_for_vblank_plb(MMIO(display_handle), + PIPE(display_handle)->pipe_reg); + +} /* wait_vblank */ + + +/*! + * Get the stride and stereo values based on the display. This is also used + * by the MI instructions. + * + * @param display Pointer to hardware device instance data + * @param stride + * @param stereo + * @param flags Should the stereo be for the frontbuffer or backbuffer? + * + * @return stride - Stride of the display + * @return stereo - Stereo address of the display + */ +static int mode_get_stride_stereo_plb(igd_display_context_t *display, + unsigned long *stride, + unsigned long *stereo, + unsigned long flags) +{ + unsigned long pitch = PLANE(display)->fb_info->screen_pitch; + igd_timing_info_t *timing = PIPE(display)->timing; + unsigned long base_offset; + + base_offset = PLANE(display)->fb_info->visible_offset; + + *stride = pitch; + *stereo = 0; + + /* For field replication, valid for interlaced modes only + * set stereo = fb_base, + * stride = pitch + */ + if (timing->mode_info_flags & IGD_SCAN_INTERLACE) { + + if(timing->mode_info_flags & IGD_LINE_DOUBLE) { + /* Interlaced + Line double flags means field replication. + * same lines are sent for both fields. Program the + * second eye to be same as the first. + */ + *stereo = base_offset; + } else { + /* Regular interlaced. Second eye starts on line 2. + * Skip every other line. + */ + *stereo = base_offset + pitch; + *stride = pitch * 2; + } + } + + return 0; +} + +/*! + * + * @param display Pointer to hardware device instance data + * + * @return void + */ +static void program_pipe_vga_plb( + igd_display_context_t *display) +{ + igd_timing_info_t *timing; + unsigned long vga_control; + unsigned long upscale = 0; + int centering = 1; + + OS_TRACE_ENTER; + +#ifdef CONFIG_MICRO + /* + * We cannot set a VGA mode unless the display planes are turned off. + * This becomes evident during a Windows BSOD. Since neither Windows + * nor IEGD got a chance to turn off these registers, and the VGA mode was + * set by the VBIOS, the screen gets corrupted. In order to fix this + * problem, we will turn the cursor and display planes here. + * + * Note: Removing previous partial-fix in favor of this complete one. + */ + /* Cursor A */ + WRITE_MMIO_REG(display, 0x70080, 0); + WRITE_MMIO_REG(display, 0x70084, 0); + /* Cursor B */ + WRITE_MMIO_REG(display, 0x700C0, 0); + WRITE_MMIO_REG(display, 0x700C4, 0); + /* Display A */ + WRITE_MMIO_REG(display, 0x70180, 0); + WRITE_MMIO_REG(display, 0x70184, 0); + /* Display B */ + WRITE_MMIO_REG(display, 0x71180, 0); + WRITE_MMIO_REG(display, 0x71184, 0); + /* Display C */ + WRITE_MMIO_REG(display, 0x72180, 0); + WRITE_MMIO_REG(display, 0x72184, 0); +#endif + + /* + * VGA Plane can attach to only one pipe at a time. LVDS can + * only attach to pipe B. We need to use the display passed to + * determine the pipe number to use. (Plba is same as Alm). + */ + + /* + * We can come here with following cases: + * 1. magic->vga CRT, DVI type displays + * 2. native->vga int-lvds, and up-scaling lvds displays + * 3. pipe->vga TV and other unscaled-lvds displays + */ + vga_control = READ_MMIO_REG(display, 0x71400); + vga_control &= 0x18e3ff00; + vga_control |= 0x8e; + + timing = PIPE(display)->timing; + if(!timing->extn_ptr) { + OS_ERROR_EXIT("No Extension pointer in program_pipe_vga_plb"); + return; + } + + /* + * FIXME: For CONFIG_NEW_MATCH this should be replaced with a simple + * check of fp_native_dtd. Do not query the attribute. + */ + + /* Find UPSCALING attr value*/ + pi_pd_find_attr_and_value(PORT_OWNER(display), + PD_ATTR_ID_PANEL_FIT, + 0,/*no PD_FLAG for UPSCALING */ + NULL, /* dont need the attr ptr*/ + &upscale); + /* this PI func will not modify value of upscale if attr does not exist */ + + /* magic->vga or native->vga cases */ + if ((timing->width == 720 && timing->height == 400) || upscale) { + centering = 0; + } + + /* Enable border */ + if((timing->width >= 800) && !upscale) { + OS_DEBUG("Enable VGA Border"); + vga_control |= (1L<<26); + } + + if(timing->width == 640) { + OS_DEBUG("Enable Nine Dot Disable"); + vga_control |= (1L<<18); + } + + if(centering) { + OS_DEBUG("Enable VGA Center Centering"); + vga_control |= 1L<<24; + + if(timing->height >= 960) { + if(timing->width >= 1280) { + OS_DEBUG("Enable VGA 2x (Nine Dot Disable)"); + vga_control |= (1L<<30) | (1L<<18); + } + } + } else { + if(PORT_OWNER(display)->port_type == IGD_PORT_LVDS) { + OS_DEBUG("Enable VGA Upper-Left Centering & Nine Dot Disable"); + vga_control |= (1L<<25 | (1L<<18)); + } else if (upscale) { + OS_DEBUG("Enable VGA Center Upper-left for upscale ports"); + vga_control |= 1L<<25; + } + } + + if(PIPE(display)->pipe_num) { + vga_control |= 1L<<29; + } + + program_pipe_vga(display, (igd_timing_info_t *)timing->extn_ptr); + WRITE_MMIO_REG(display, 0x71400, vga_control); + + OS_TRACE_EXIT; + return; +} + + +/*! + * Program Display Plane Values. + * + * @param display Pointer to hardware device instance data + * @param status + * + * @return void + */ +static void program_plane_plb(igd_display_context_t *display, + unsigned long status) +{ + unsigned long stereo; + unsigned long stride; + unsigned long size; + unsigned long plane_control; + igd_timing_info_t *timing; + igd_framebuffer_info_t *fb_info = PLANE(display)->fb_info; + unsigned long plane_reg = PLANE(display)->plane_reg; + unsigned long start_addr_reg = DSPAADDR; + + OS_TRACE_ENTER; + + OS_DEBUG("Program Plane: %s", status?"ENABLE":"DISABLE"); + OS_DEBUG("Device power state: D%ld", GET_DEVICE_POWER_STATE(display)); + + igd_wait_vblank_plb((igd_display_h)display); + + plane_control = OS_READ32(MMIO(display) + plane_reg); + if(PLANE(display)->plane_reg == DSPACNTR) { + plane_control &= device_data->plane_a_preserve; + } + else { /* if it's plane b or plane c */ + plane_control &= device_data->plane_b_c_preserve; + start_addr_reg = 0x71184; + } + + if((status == FALSE) || + (GET_DEVICE_POWER_STATE(display) != IGD_POWERSTATE_D0)) { + + /* + * Note: The vga programming code does not have an "off". So + * when programming the plane to off we make sure VGA is off + * as well. + */ + disable_vga_plb(MMIO(display)); + + /* + * To turn off plane A or B, the program have to triger the plane A or B + * start register. Or else, it will not work. + */ + OS_WRITE32(plane_control, MMIO(display) + plane_reg); + OS_WRITE32(OS_READ32(MMIO(display) + start_addr_reg), + MMIO(display) + start_addr_reg); + + igd_wait_vblank_plb((igd_display_h)display); + return; + } + /* + * Note: The very first pass through this function will be with + * status false and timings == NULL. Don't use the timings before + * the check above. + */ + timing = PIPE(display)->timing; + /* There is a special case code for legacy VGA modes */ + while (timing->extn_ptr) { + timing = (igd_timing_info_t *)timing->extn_ptr; + } + if(MODE_IS_VGA(timing)) { + program_plane_vga(display, timing); + return; + } + + disable_vga_plb(MMIO(display)); + + size = (((unsigned long)timing->height - 1)<<16) | + (unsigned long)(timing->width - 1); + + /* enable plane, select pipe, enable gamma correction logic */ + plane_control |= 0x80000000 | (PIPE(display)->pipe_num<<24); + PIPE(display)->plane = PLANE(display); +#ifndef CONFIG_MICRO + plane_control |= (1<<30); +#endif + + /* Here the settings: + * If line + pixel dbling, set 21,20 to 01b, and set Horz Multiply + * If line dbling only, set 21,20 to 11b + * If pixel dbling only, set 21,20 to 00b, but set Horz Multiply + * If no doubling, set 21,20 to 00b (no Horz Multiply) + * For pixel doubling + * --> both progressive/interlaced modes + * For Line doubling + * --> progressive modes only + */ + + if (!(timing->mode_info_flags & IGD_SCAN_INTERLACE)) { + /* Line doubling in progressive mode requires special bits */ + if (timing->mode_info_flags & IGD_LINE_DOUBLE) { + /* BIT 20 for line & pixel doubling*/ + plane_control |= BIT20; + /* check later, if no pixel doubling, set bit 21 too*/ + } + } + if (timing->mode_info_flags & IGD_PIXEL_DOUBLE) { + /* Horz pixel multiply must be set for double */ + plane_control |= BIT11; + /* TODO -> Plba can more than double, + It can 3X, 4X etc. These arent exposed now */ + } + else if(plane_control & BIT20){ + /* For line ONLY doubling, set bit 21 also '1' */ + plane_control |= BIT21; + } + + mode_get_stride_stereo_plb(display, &stride, &stereo, 0); + + /* set color depth */ + switch (IGD_PF_DEPTH(fb_info->pixel_format)) { + case PF_DEPTH_8: + plane_control |= BIT27 | BIT30; + break; + case PF_DEPTH_16: + plane_control |= BIT28 | BIT26; + break; + default: + case PF_DEPTH_32: + plane_control |= BIT28 | BIT27; + break; + } + + if(fb_info->flags & IGD_ENABLE_DISPLAY_GAMMA) { + plane_control |= (BIT30); + } + + OS_DEBUG(" Plane Control = 0x%lx", plane_control); + OS_DEBUG(" Plane Base = 0x%lx", fb_info->visible_offset); + OS_DEBUG(" Plane Pitch = 0x%lx", stride); + OS_DEBUG(" Plane Size = 0x%lx", size); + + OS_WRITE32(stride, MMIO(display) + plane_reg + DSP_STRIDE_OFFSET); + /* + * In reality this only exists for plane B. It doesn't seem to hurt + * plane A so just do it anyway and save us another case. + */ + OS_WRITE32(size, MMIO(display) + plane_reg + DSP_SIZE_OFFSET); + + /*OS_WRITE32(stereo, MMIO(display) + plane_reg + DSP_STEREO_OFFSET); + - This register is Reserved ON plba */ + OS_WRITE32(fb_info->visible_offset, + MMIO(display) + plane_reg + DSP_START_OFFSET); + + /* It seems we need push or trigger plane A/B to start to work + * on Poulsbo, especially for sDVO port. Let's write plane control + * register and start address register at last. + */ + OS_WRITE32(plane_control, MMIO(display) + plane_reg); + OS_WRITE32(OS_READ32(MMIO(display) + start_addr_reg), + MMIO(display) + start_addr_reg); + + igd_wait_vblank_plb((igd_display_h)display); + + OS_TRACE_EXIT; + return; +} + +/*! + * This function programs the Timing registers and clock registers and + * other control registers for PIPE. + * + * @param display + * @param status + * + * @return void + */ +static void program_pipe_plb(igd_display_context_t *display, + unsigned long status) +{ + unsigned long timing_reg; + unsigned long pipe_conf; + unsigned long hactive, vactive; + igd_timing_info_t *pTimings; + unsigned long temp; +#ifndef CONFIG_MICRO + igd_display_port_t *port; + int i; +#endif + + OS_TRACE_ENTER; + OS_DEBUG("Program Pipe: %s", status?"ENABLE":"DISABLE"); + OS_DEBUG("Device power state: D%ld", GET_DEVICE_POWER_STATE(display)); + + pipe_conf = device_data->pipe_preserve & + OS_READ32(MMIO(display) + PIPE(display)->pipe_reg); + + /* Reset the plane of this pipe back to NULL, it will be set on the + * call to program_plane, which is ok, since program_pipe occurs + * before program_plane */ + PIPE(display)->plane = NULL; + + if((status == FALSE) || + (GET_DEVICE_POWER_STATE(display) == IGD_POWERSTATE_D3)) { + /* Disable pipe */ + OS_WRITE32(pipe_conf & (~0x80000000), + MMIO(display) + PIPE(display)->pipe_reg); + + return; + } + + pTimings = PIPE(display)->timing; + + /* + * If the mode is VGA and the PD says it handles all VGA modes without + * reprogramming then just set the mode and leave centering off. + */ + if(pTimings->mode_info_flags & IGD_MODE_VESA) { + if (pTimings->mode_number <= VGA_MODE_NUM_MAX) { + /* Pipe timings and clocks are not used but it must be on anyway */ + OS_WRITE32(pipe_conf | 0x80000000, + MMIO(display) + PIPE(display)->pipe_reg); + program_pipe_vga_plb(display); + return; + } else { +#ifdef CONFIG_MICRO + set_256_palette(MMIO(display)); +#endif + } + } + + /* Program dot clock divisors. */ + program_clock_plb(display, PIPE(display)->clock_reg, pTimings->dclk); + + /* Program timing registers for the pipe */ + timing_reg = PIPE(display)->timing_reg; + if (pTimings->mode_info_flags & IGD_PIXEL_DOUBLE) { + hactive = (unsigned long)pTimings->width*2 - 1; + } else { + hactive = (unsigned long)pTimings->width - 1; + } + + if (pTimings->mode_info_flags & IGD_LINE_DOUBLE) { + if (pTimings->mode_info_flags & IGD_SCAN_INTERLACE) { + vactive = (unsigned long)pTimings->height - 1; + } else { + vactive = (unsigned long)pTimings->height*2 - 1; + } + } else { + if (pTimings->mode_info_flags & IGD_SCAN_INTERLACE) { + vactive = (unsigned long)pTimings->height/2 - 1; + } else { + vactive = (unsigned long)pTimings->height - 1; + } + } + + /* + * DPLL should be on at this point which is required for touching + * the palette. + */ +#ifndef CONFIG_MICRO + /* reset the palette */ + for (i = 0; i < 256; i++) { + OS_WRITE32(((i<<16) | (i<<8) | i), + MMIO(display) + PIPE(display)->palette_reg + i*4); + } + + /* apply color correction */ + port = PORT_OWNER(display); + for( i = 0; PD_ATTR_LIST_END != port->attributes[i].id; i++ ) { + + if ((PD_ATTR_ID_FB_GAMMA == (port->attributes[i].id)) || + (PD_ATTR_ID_FB_BRIGHTNESS == (port->attributes[i].id)) || + (PD_ATTR_ID_FB_BRIGHTNESS == (port->attributes[i].id))) { + + mode_context->dispatch->full->set_color_correct(display); + } + } +#endif + + /* + * NOTE: For size reasons the timng table contains unsigned short + * values. Don't shift them past 16. Use a temp instead. + * All register offsets and bit shift are verified for Napa + */ + temp = ((unsigned long)pTimings->htotal << 16) | hactive; + OS_WRITE32(temp, MMIO(display) + timing_reg); + + temp = ((unsigned long)pTimings->hblank_end << 16) | + (unsigned long)pTimings->hblank_start; + OS_WRITE32(temp, MMIO(display) + timing_reg + 0x04); + + temp = ((unsigned long)pTimings->hsync_end << 16) | + (unsigned long)pTimings->hsync_start; + OS_WRITE32(temp, MMIO(display) + timing_reg + 0x08); + + temp = ((unsigned long)pTimings->vtotal << 16) | vactive; + OS_WRITE32(temp, MMIO(display) + timing_reg + 0x0C); + + temp = ((unsigned long)pTimings->vblank_end << 16) | + (unsigned long)pTimings->vblank_start; + OS_WRITE32(temp, MMIO(display) + timing_reg + 0x10); + + temp = ((unsigned long)pTimings->vsync_end << 16) | + (unsigned long)pTimings->vsync_start; + OS_WRITE32(temp, MMIO(display) + timing_reg + 0x14); + + /* + * If there is a linked mode it is either the VGA or a scaled + * mode. If it is scaled then we need to use it as the source size. + */ + if(pTimings->extn_ptr) { + igd_timing_info_t *scaled_timings = + (igd_timing_info_t *)pTimings->extn_ptr; + if((scaled_timings->mode_info_flags & IGD_MODE_VESA) && + (scaled_timings->mode_number <= VGA_MODE_NUM_MAX)) { + temp = (hactive << 16) | vactive; + } else { + temp = (unsigned long)scaled_timings->width - 1; + temp = (temp << 16) | + (unsigned long)(scaled_timings->height - 1); + } + } else { + temp = (hactive << 16) | vactive; + } + OS_WRITE32(temp, MMIO(display) + timing_reg + 0x1C); + + /* Set other registers */ + + /* + * FIXME: max_dclk needs to be determined from core clock + * at init time. 915 etc has several skus with different + * clocks for the same device ID. + * + */ + + /* These values are derived from the Poulsbo B-Spec as + * the suggested values */ + WRITE_MMIO_REG (display, FW_BLC1, device_data->fw_blc1); + WRITE_MMIO_REG (display, FW_BLC2, device_data->fw_blc2); + WRITE_MMIO_REG (display, FW_BLC3, device_data->fw_blc3); + WRITE_MMIO_REG (display, FW_BLC_SELF, device_data->fw_self); + WRITE_MMIO_REG (display, DSP_ARB, device_data->dsp_arb); + + /* The SGX 2D engine can saturate the memory bus and starve + * the display engine causing visible screen tearing. + * This reduces the priority of the SGX vs. display engine + */ + temp = READ_MMIO_REG (display, G_DEBUG); + WRITE_MMIO_REG (display, G_DEBUG, (temp | (1 << 11))); + + pipe_conf |= PIPE_ENABLE; + WRITE_MMIO_REG(display, PIPE(display)->pipe_reg, pipe_conf); + + /* + * Set the VGA address range to 0xa0000 so that a normal (not VGA) + * mode can be accessed through 0xa0000 in a 16bit world. + */ + WRITE_AR(MMIO(display), 0x10, 0xb); + WRITE_VGA(MMIO(display), GR_PORT, 0x06, 0x5); + WRITE_VGA(MMIO(display), GR_PORT, 0x10, 0x1); + + if(pTimings->extn_ptr) { + /* This means either internal scaling (LVDS) or centered VGA */ + pTimings = pTimings->extn_ptr; + if(pTimings->extn_ptr) { + /* This is both the scaled and centered VGA */ + pTimings = pTimings->extn_ptr; + } + if(pTimings->mode_info_flags & IGD_MODE_VESA) { + if (pTimings->mode_number <= VGA_MODE_NUM_MAX) { + program_pipe_vga_plb(display); + } else { +#ifdef CONFIG_MICRO + set_256_palette(MMIO(display)); +#endif + } + } + } + + OS_TRACE_EXIT; + return; +} + +/*! + * + * @param context + * + * @return void + */ +static void reset_plane_pipe_ports_plb(igd_context_t *context) +{ + igd_plane_t *plane; + igd_display_pipe_t *pipe; + igd_display_port_t *port,*tv_port=NULL; + unsigned long temp; + unsigned long i; + unsigned char *mmio; + inter_module_dispatch_t *md; + + OS_TRACE_ENTER; + + /* + * Disable all plane, pipe and port registers because the + * bios may have been using a different set. Only unset the + * enable bit. + */ + mmio = OS_MMIO(context->device_context.virt_mmadr); + md = &context->mod_dispatch; + + disable_vga_plb(OS_MMIO(mmio)); + + /* Turn off ports */ + port = NULL; + while((port = md->dsp_get_next_port(context, port, 0)) != NULL) { + /* if the port is TV, then don't set the power to S3 as this causes + * blank screen on analog port after killx or cosole mode, + * probably because the external clock needs to be on till the pipes and + * DPLLs are off + */ + if (port->pd_driver) { +#ifndef CONFIG_FASTBOOT + if(port->pd_type == PD_DISPLAY_TVOUT) { + tv_port = port; + }else { + port->pd_driver->set_power(port->pd_context, IGD_POWERSTATE_D3); + } +#endif + } + + /* Disable WRITE protection on PIPE B for parts with Int-LVDS*/ + /* This should never happen as the panel power was set to D3 above */ + if (port->port_reg == LVDSCNTR) { + if(OS_READ32(OS_MMIO(mmio) + LVDS_PNL_PWR_CTL) & 0x1) { + OS_WRITE32(0xABCD0000, OS_MMIO(mmio) + LVDS_PNL_PWR_CTL); + i=0; + while(i++ < 0x10) { + OS_SLEEP(10); + if((OS_READ32(OS_MMIO(mmio)+LVDS_PNL_PWR_STS)&BIT(31))==0) { + break; + } + } + } + } + + temp = OS_READ32(OS_MMIO(mmio) + port->port_reg); + OS_WRITE32((temp & ~BIT31), OS_MMIO(mmio) + port->port_reg); + } + + plane = NULL; + while ((plane = md->dsp_get_next_plane(context, plane, 1)) != NULL) { + /* Only display display planes. + * Leave cursor, VGA, overlay, sprite planes alone since they will + * need a different disable bit/sequence. + */ + temp = OS_READ32(OS_MMIO(mmio) + plane->plane_reg); + if ((plane->plane_features & IGD_PLANE_DISPLAY)) { + if ( temp & BIT31 ) { + if(plane->plane_reg == DSPACNTR) { + OS_WRITE32((temp & device_data->plane_a_preserve), + OS_MMIO(mmio) + plane->plane_reg); + } + else { /* if it's plane b or plane c */ + OS_WRITE32((temp & device_data->plane_b_c_preserve), + OS_MMIO(mmio) + plane->plane_reg); + } + OS_WRITE32(0, OS_MMIO(mmio) + plane->plane_reg+4); + } + } else if ((plane->plane_features & IGD_PLANE_CURSOR)) { + OS_WRITE32((temp & 0xffffffe8), + OS_MMIO(mmio) + plane->plane_reg); + OS_WRITE32(0, OS_MMIO(mmio) + plane->plane_reg+4); + } + } + + /* Turn off pipes */ + pipe = NULL; + while ((pipe = md->dsp_get_next_pipe(context, pipe, 0))) { + wait_for_vblank_plb(OS_MMIO(mmio), pipe->pipe_reg); + temp = OS_READ32(OS_MMIO(mmio) + pipe->pipe_reg); + if ( temp & BIT31 ) { + OS_WRITE32((temp & device_data->pipe_preserve), + OS_MMIO(mmio) + pipe->pipe_reg); + } + } + /* pipes and DPLLs are off, now set the power for TV */ + if(tv_port && tv_port->pd_driver) { + tv_port->pd_driver->set_power(tv_port->pd_context, IGD_POWERSTATE_D3); + } + OS_TRACE_EXIT; + +} /* end reset_plane_pipe_ports */ + +/*! + * + * @param display + * @param port_number + * @param status + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ +static int program_port_plb(igd_display_context_t *display, + unsigned short port_number, + unsigned long status) +{ + unsigned long pipe_number; + unsigned long port_control; + unsigned long port_control_analog = 0; + unsigned long mult_port_control; + unsigned long pd_powerstate = 0; + unsigned long upscale = 0; + pd_timing_t *timing; + pd_timing_t local_timing; + unsigned long port_type; + int ret; + + /* get the pipe number */ + pipe_number = PIPE(display)->pipe_num; + + /* get the timings */ + timing = PIPE(display)->timing; + + /* keep the port type as local as we access it frequently */ + port_type = PORT(display, port_number)->port_type; + + /* Reading the preservation bits */ + port_control = PORT(display, port_number)->preserve & + READ_MMIO_REG(display, PORT(display, port_number)->port_reg); + + /* Reading the preservation bits for SDVO Gang Mode */ + mult_port_control = PORT(display, port_number)->mult_preserve & + READ_MMIO_REG(display, PORT(display, port_number)->port_reg); + + /* If status is false, quickly disable the display */ + if(status == FALSE) { + ret = PORT(display, port_number)->pd_driver->set_power( + PORT(display, port_number)->pd_context, PD_POWER_MODE_D3); + + if (ret) { + OS_ERROR_EXIT("PD set_power() returned: 0x%x", ret); + return -IGD_ERROR_INVAL; + } + + if(port_type == IGD_PORT_DIGITAL) { + WRITE_MMIO_REG(display, PORT(display, port_number)->port_reg, + port_control); + + if(PORT(display, port_number)->mult_port) { + /* either gang mode or RGBA */ + WRITE_MMIO_REG(display, + PORT(display, port_number)->mult_port->port_reg, + mult_port_control); + } + } else if (port_type == IGD_PORT_ANALOG) { + port_control |= (BIT11 | BIT10); /* put in D3 state */ + WRITE_MMIO_REG(display, PORT(display, port_number)->port_reg, + port_control); + + return 0; + } + return 0; + } + + OS_DEBUG("status isn't false, Check port enabled"); + + if(! (PORT(display, port_number)->pt_info->flags & IGD_DISPLAY_ENABLE)) { + return 0; + } + + /* + * Is this is the magic mode then turn on VGA syncs + */ + OS_DEBUG("Check vga_sync"); + if(PORT(display, port_number)->vga_sync == 1) { + /* + * Is this is the magic mode then turn on VGA syncs + */ + OS_DEBUG("VGA sync true, is width x height 720 x 400?"); + if((timing->width == 720) && (timing->height == 400)) { + OS_DEBUG("Modify port control and multi_port_control"); + port_control |= (1L<<15); + mult_port_control |= (1L<<15); + } + } + + OS_DEBUG("Check analog port"); + if(port_type == IGD_PORT_ANALOG) { + port_control |= (0x80000000 | (pipe_number<<30)); + if(timing->mode_info_flags & IGD_VSYNC_HIGH) { + port_control |= (1L<<4); + } + if(timing->mode_info_flags & IGD_HSYNC_HIGH) { + port_control |= (1L<<3); + } + /* To differentiate between analog and other ports */ + port_control_analog = port_control; + } + + OS_DEBUG("Get power state"); + OS_DEBUG("power state = %ld ", GET_DISPLAY_POWER_STATE(display, port_number)); + switch(GET_DISPLAY_POWER_STATE(display, port_number)) { + case IGD_POWERSTATE_D0: + OS_DEBUG("Power State is D0"); + pi_pd_find_attr_and_value(PORT(display, port_number), + PD_ATTR_ID_PANEL_FIT, + 0, /*no PD_FLAG for UPSCALING */ + NULL, /* dont need the attr ptr*/ + &upscale); + if(port_type == IGD_PORT_DIGITAL) { + /* Reach the end timing if upscaling is enabled */ + if (timing->extn_ptr && upscale) { + timing = (pd_timing_t *)timing->extn_ptr; + } + + local_timing = *timing; + if (upscale) { + /* For timings smaller than width 360 and height 200, + * double the size. This is because the active area of the mode + * is double the size of the resolution for these modes + * - Very tricky huh */ + if (local_timing.width <= 360) { + local_timing.width <<= 1; + } + if (local_timing.height <= 200) { + local_timing.height <<= 1; + } + } + + ret = PORT(display, port_number)->pd_driver->set_mode( + PORT(display, port_number)->pd_context, &local_timing, 0); + if (ret) { + OS_ERROR_EXIT("PD set_mode returned: 0x%x", ret); + return -IGD_ERROR_INVAL; + } + + /* in Plba B-Speecs, there are no bits, * + * for the polarity of the H-sync/V-sync */ + + /* in Plba B-Speecs, there are no bits, * + * for data ordering/format for DVO data */ + /* Gang-Mode and RGBA models are "exclusive-or" */ + if((PORT(display, port_number)->pd_driver->flags) & + PD_FLAG_GANG_MODE) { + mult_port_control |= (1L<<16); + } else if(PORT(display, port_number)->pd_type == PD_DISPLAY_RGBA) { + mult_port_control |= (1L<<2); + } + + timing = PIPE(display)->timing; + + if(timing->dclk > 100000) { + /* 100MPs < pixel rate < 200MPs */ + /* SDVO clock rate multiplier = 1x */ + /* + port_control &= ~BIT23; + mult_port_control |= ~BIT23; + redundant code since BIT23 is + already 0 at this point + */ + } else if(timing->dclk > 50000) { + /* 50MPs < pixel rate < 100MPs */ + /* SDVO clock rate multiplier = 2x */ + port_control |= (1L<<23); + mult_port_control |= (1L<<23); + } else { + /* 25MPs < pixel rate < 50MPs */ + /* SDVO clock rate multiplier = 4x */ + port_control |= (3L<<23); + mult_port_control |= (3L<<23); + } + + /* + * BIT7 = enable the border + * Do we need to disable the SDVO border for native + * VGA timings(i.e., use DE)? + * BIT22->BIT19 = setup the clock phase-9 + * BIT29 = enable the stall + * Only set stall on DVO-B for gang mode + * BIT30 = pipe number + * BIT31 = port enable + */ + port_control |= ( ( pipe_number<<30 ) | (BIT31) | ((0x9l) << 19) | + (BIT29) | (BIT7) ); + mult_port_control |= ( (BIT31) | ((0x9l) << 19) | (BIT7) ); + + WRITE_MMIO_REG(display, PORT(display, port_number)->port_reg, + port_control); + + if(PORT(display, port_number)->mult_port) { /* gang mode or rgba*/ + WRITE_MMIO_REG(display, + PORT(display, port_number)->mult_port->port_reg, + mult_port_control); + } + return 0; + } else if(port_type == IGD_PORT_LVDS) { + /* + * There is a special case for LVDS scaling. If the timing is + * the native one and the extension points to another non-vga + * mode then send the extension pointer. + */ + /* Reach the end timing to get user requested mode */ + if(timing->extn_ptr) { + timing = (pd_timing_t *)timing->extn_ptr; + } + } + /* set mode will take care of port control */ + ret = PORT(display, port_number)->pd_driver->set_mode( + PORT(display, port_number)->pd_context, (pd_timing_t *)timing, + 1<pipe_num); + if (ret) { + OS_ERROR_EXIT("PD set_mode returned: 0x%x",ret); + return -IGD_INVAL; + } + break; + case IGD_POWERSTATE_D1: + port_control_analog &= ~0x80000000; + port_control_analog |= 0x00000800 & + ~(PORT(display, port_number)->preserve); + pd_powerstate =PD_POWER_MODE_D1; + break; + case IGD_POWERSTATE_D2: + port_control_analog &= ~0x80000000; + port_control_analog |= 0x00000400 & + ~(PORT(display, port_number)->preserve); + pd_powerstate = PD_POWER_MODE_D2; + break; + case IGD_POWERSTATE_D3: + port_control_analog &= ~0x80000000; + port_control_analog |= 0x00003c00 & + ~(PORT(display, port_number)->preserve); + pd_powerstate = PD_POWER_MODE_D3; + break; + default: + OS_ERROR_EXIT("Invalid power state: 0x%lx", + GET_DISPLAY_POWER_STATE(display, port_number)); + return -IGD_ERROR_INVAL; + } + + ret = PORT(display, port_number)->pd_driver->set_power( + PORT(display, port_number)->pd_context, pd_powerstate); + if (ret) { + OS_ERROR_EXIT("PD set_power returned: 0x%x", ret); + return -IGD_ERROR_INVAL; + } + + if(port_type == IGD_PORT_DIGITAL) { + OS_DEBUG("Port_control = 0x%lx", port_control); + + WRITE_MMIO_REG(display, PORT(display, port_number)->port_reg, + port_control); + if(PORT(display, port_number)->mult_port) { /* gang mode or rgba*/ + WRITE_MMIO_REG(display, + PORT(display, port_number)->mult_port->port_reg, + mult_port_control); + } + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * Status is currently not used + * + * @param display + * @param port_number + * @param status + * + * @return 0 on success + * @return 1 on failure + */ +static int post_program_port_plb(igd_display_context_t *display, + unsigned short port_number, + unsigned long status) +{ + int ret; + igd_display_port_t *port; + igd_timing_info_t *timings; + unsigned long portreg; + + OS_TRACE_ENTER; + + port = PORT(display, port_number); + timings = PIPE(display)->timing; + + /* + * Writing the sDVO control register here works around a problem + * where the sDVO port is not turning on when using a CH7308 + * card in a 915 GM based system and the port order is 5200. + * + * In addition, post_set_mode() below, will report that the + * "inputs are not trained", however, this does not seem to + * have any negative effects. + */ + portreg = READ_MMIO_REG(display, port->port_reg); + WRITE_MMIO_REG(display, port->port_reg, (portreg & ~BIT31)); + WRITE_MMIO_REG(display, port->port_reg, portreg); + + /* Reenable/Redisable other port */ + if (port->port_reg == 0x61140) { + WRITE_MMIO_REG(display, 0x61160, READ_MMIO_REG(display, + 0x61160)); + } else { + WRITE_MMIO_REG(display, 0x61140, + READ_MMIO_REG(display, 0x61140)); + } + + /* + * Added for Lakeport A0 + * Port clock multiplier bits 4-7, needs to be rewritten + */ + WRITE_MMIO_REG(display, PIPE(display)->clock_reg->dpll_control, + READ_MMIO_REG(display, PIPE(display)->clock_reg->dpll_control)); + + /* We must wait for 150 us for the dpll clock to warm up */ + OS_SLEEP(150); + + ret = 0; + /* call post_set_mode() if exists */ + if (port->pd_driver->post_set_mode) { + ret = port->pd_driver->post_set_mode(port->pd_context, timings, + 1<pipe_num); + if (ret) { + OS_ERROR("PD post_set_mode returned: 0x%x", ret); + } + } + + OS_TRACE_EXIT; + return ret; +} + +/*! + * + * @param gpio + * + * @return size + */ +static unsigned long get_gpio_sets_plb(unsigned long **gpio) +{ + *gpio = gpio_plb; + return sizeof(gpio_plb)/sizeof(unsigned long); +} + +/*! + * + * @param context + * @param in_list + * + * @return void - To small to trace + */ +static void filter_modes_plb(igd_context_t *context, igd_display_port_t *port, + pd_timing_t *in_list) +{ + + return; +} + + +mode_dispatch_t mode_dispatch_plb = { + igd_set_palette_entry_plb, + igd_get_palette_entry_plb, + igd_wait_vblank_plb, + program_plane_plb, + program_pipe_plb, + program_port_plb, + post_program_port_plb, + program_clock_plb, + reset_plane_pipe_ports_plb, + get_gpio_sets_plb, + filter_modes_plb, + OPT_MICRO_VALUE(&mode_full_dispatch_plb, NULL) +}; + +#endif diff --git a/drivers/gpu/drm/emgd/emgd/display/mode/plb/mode_plb.c b/drivers/gpu/drm/emgd/emgd/display/mode/plb/mode_plb.c new file mode 100644 index 0000000..4be011f --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/mode/plb/mode_plb.c @@ -0,0 +1,1434 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: mode_plb.c + * $Revision: 1.20 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * Almador Core implementations for the mode dispatch functions. + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.mode + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../cmn/match.h" +#include "../cmn/mode_dispatch.h" + +int set_flip_pending_plb(unsigned char *mmio, unsigned long pipe_status_reg); +int check_flip_pending_plb(unsigned char *mmio, unsigned long pipe_status_reg); + +/*! + * @addtogroup display_group + * @{ + */ +int wait_for_vblank_plb(unsigned char *mmio, unsigned long pipe_reg); + +/*! + * + * @param display + * + * @return 0 on success + * @return -IGD_ERROR_INVAL if color attributes not found + */ +static int set_color_correct_plb(igd_display_context_t *display) +{ + const int MID_PIXEL_VAL = 125; + const int MAX_PIXEL_VAL = 255; + const int NUM_PALETTE_ENTRIES = 256; + + unsigned int gamma_r_max_24i_8f, gamma_r_min_24i_8f; + unsigned int gamma_g_max_24i_8f, gamma_g_min_24i_8f; + unsigned int gamma_b_max_24i_8f, gamma_b_min_24i_8f; + unsigned int new_gamma_r_24i_8f, new_gamma_g_24i_8f; + unsigned int new_gamma_b_24i_8f; + unsigned int gamma_normal_r_24i_8f, gamma_normal_g_24i_8f; + unsigned int gamma_normal_b_24i_8f; + int brightness_factor_r, brightness_factor_g; + int brightness_factor_b; + int contrast_factor_r, contrast_factor_g; + int contrast_factor_b; + + unsigned int *palette; + unsigned int i; + + igd_range_attr_t *gamma_attr = NULL, *contrast_attr = NULL; + igd_range_attr_t *brightness_attr = NULL; + igd_attr_t *hal_attr_list = PORT_OWNER(display)->attributes; + + + /* Using OS_ALLOC to avoid using > 1024 on stack (frame size warning ) */ + palette = OS_ALLOC(sizeof (unsigned int) * NUM_PALETTE_ENTRIES); + + /* start with a fresh palette */ + for (i = 0; i < NUM_PALETTE_ENTRIES; i++) { + palette[i] = (i << 16) | (i << 8) | i; + } + + /* get a pointer to gamma, contrast, and brightness attr */ + i = 0; + + while (PD_ATTR_LIST_END != hal_attr_list[i].id) { + switch (hal_attr_list[i].id) { + case PD_ATTR_ID_FB_GAMMA: + gamma_attr = (igd_range_attr_t *) &hal_attr_list[i]; + break; + + case PD_ATTR_ID_FB_BRIGHTNESS: + brightness_attr = (igd_range_attr_t *) &hal_attr_list[i]; + break; + + case PD_ATTR_ID_FB_CONTRAST: + contrast_attr = (igd_range_attr_t *) &hal_attr_list[i]; + break; + + default: + break; + } + + i++; + } + + if(!gamma_attr || !brightness_attr || !contrast_attr) { + OS_ERROR("Color Correction Atrributes not found!"); + return -IGD_ERROR_INVAL; + } + + /* Get the max and min */ + gamma_r_max_24i_8f = ((gamma_attr->max >> 16) & 0xFF) << 3; + gamma_g_max_24i_8f = ((gamma_attr->max >> 8) & 0xFF) << 3; + gamma_b_max_24i_8f = (gamma_attr->max & 0xFF) << 3; + + gamma_r_min_24i_8f = ((gamma_attr->min >> 16) & 0xFF) << 3; + gamma_g_min_24i_8f = ((gamma_attr->min >> 8) & 0xFF) << 3; + gamma_b_min_24i_8f = (gamma_attr->min & 0xFF) << 3; + + /* The new gamma values are in 3i.5f format, but we must convert it + * to 24i.8f format before passing it to OS_POW_FIX + */ + new_gamma_r_24i_8f = ((gamma_attr->current_value >> 16) & 0xFF) << 3; + new_gamma_g_24i_8f = ((gamma_attr->current_value >> 8) & 0xFF) << 3; + new_gamma_b_24i_8f = (gamma_attr->current_value & 0xFF) << 3; + + /* make sure the new gamma is within range */ + new_gamma_r_24i_8f = OS_MIN(gamma_r_max_24i_8f, new_gamma_r_24i_8f); + new_gamma_r_24i_8f = OS_MAX(gamma_r_min_24i_8f, new_gamma_r_24i_8f); + new_gamma_g_24i_8f = OS_MIN(gamma_g_max_24i_8f, new_gamma_g_24i_8f); + new_gamma_g_24i_8f = OS_MAX(gamma_g_min_24i_8f, new_gamma_g_24i_8f); + new_gamma_b_24i_8f = OS_MIN(gamma_b_max_24i_8f, new_gamma_b_24i_8f); + new_gamma_b_24i_8f = OS_MAX(gamma_b_min_24i_8f, new_gamma_b_24i_8f); + + + gamma_normal_r_24i_8f = + OS_POW_FIX(MAX_PIXEL_VAL, (1<<16)/new_gamma_r_24i_8f); + + gamma_normal_g_24i_8f = + OS_POW_FIX(MAX_PIXEL_VAL, (1<<16)/new_gamma_g_24i_8f); + + gamma_normal_b_24i_8f = + OS_POW_FIX(MAX_PIXEL_VAL, (1<<16)/new_gamma_b_24i_8f); + + for( i = 0; i < NUM_PALETTE_ENTRIES; i++ ) { + unsigned int new_gamma; + unsigned int cur_color; + unsigned int cur_palette = palette[i]; + + /* Note that we do not try to calculate the gamma if it + * is 1.0, e.g. 0x100. This is to avoid round-off errors + */ + + /* red: calculate and make sure the result is within range */ + if (0x100 != new_gamma_r_24i_8f) { + cur_color = (cur_palette >> 16) & 0xFF; + new_gamma = OS_POW_FIX(cur_color, (1<<16)/new_gamma_r_24i_8f); + new_gamma = (MAX_PIXEL_VAL * new_gamma)/gamma_normal_r_24i_8f; + palette[i] &= 0x00FFFF; + palette[i] |= + (OS_MIN(new_gamma, (unsigned) MAX_PIXEL_VAL) & 0xFF) << 16; + } + + /* green: calculate and make sure the result is within range */ + if (0x100 != new_gamma_g_24i_8f) { + cur_color = (cur_palette >> 8) & 0xFF; + new_gamma = OS_POW_FIX(cur_color, (1<<16)/new_gamma_g_24i_8f); + new_gamma = (MAX_PIXEL_VAL * new_gamma)/gamma_normal_g_24i_8f; + palette[i] &= 0xFF00FF; + palette[i] |= + (OS_MIN(new_gamma, (unsigned) MAX_PIXEL_VAL) & 0xFF) << 8; + } + + /* blue: calculate and make sure the result is within range */ + if (0x100 != new_gamma_b_24i_8f) { + cur_color = cur_palette & 0xFF; + new_gamma = OS_POW_FIX(cur_color, (1<<16)/new_gamma_b_24i_8f); + new_gamma = (MAX_PIXEL_VAL * new_gamma)/gamma_normal_b_24i_8f; + palette[i] &= 0xFFFF00; + palette[i] |= + (OS_MIN(new_gamma, (unsigned) MAX_PIXEL_VAL) & 0xFF); + } + } + + + /* Brightness correction */ + brightness_factor_r = (brightness_attr->current_value >> 16) & 0xFF; + brightness_factor_g = (brightness_attr->current_value >> 8) & 0xFF; + brightness_factor_b = brightness_attr->current_value & 0xFF; + + /* The factors are offset by 0x80 because 0x80 is 0 correction */ + brightness_factor_r -= 0x80; + brightness_factor_g -= 0x80; + brightness_factor_b -= 0x80; + + for( i = 0; i < NUM_PALETTE_ENTRIES; i++ ) { + int new_pixel_val; + unsigned int cur_color; + unsigned int cur_palette = palette[i]; + + /* red: calculate and make sure the result is within range */ + cur_color = (cur_palette >> 16) & 0xFF; + new_pixel_val = cur_color + brightness_factor_r; + new_pixel_val = OS_MIN(new_pixel_val, MAX_PIXEL_VAL); + palette[i] &= 0x00FFFF; + palette[i] |= (OS_MAX(new_pixel_val, 0) & 0xFF) << 16; + + /* green: calculate and make sure the result is within range */ + cur_color = (cur_palette >> 8) & 0xFF; + new_pixel_val = cur_color + brightness_factor_g; + new_pixel_val = OS_MIN(new_pixel_val, MAX_PIXEL_VAL); + palette[i] &= 0xFF00FF; + palette[i] |= (OS_MAX(new_pixel_val, 0) & 0xFF) << 8; + + /* blue: calculate and make sure the result is within range */ + cur_color = cur_palette & 0xFF; + new_pixel_val = cur_color + brightness_factor_b; + new_pixel_val = OS_MIN(new_pixel_val, MAX_PIXEL_VAL); + palette[i] &= 0xFFFF00; + palette[i] |= OS_MAX(new_pixel_val, 0) & 0xFF; + } + + + /* contrast correction */ + contrast_factor_r = (contrast_attr->current_value >> 16) & 0xFF; + contrast_factor_g = (contrast_attr->current_value >> 8) & 0xFF; + contrast_factor_b = contrast_attr->current_value & 0xFF; + + /* make sure values are within range */ + contrast_factor_r -= 0x80; + contrast_factor_g -= 0x80; + contrast_factor_b -= 0x80; + + + /* We're doing integer division in this loop using 16i.16f + * integers. The result will then be converted back into a + * regular, 32-bit integer + */ + for( i = 0; i < NUM_PALETTE_ENTRIES; i++ ) { + int new_pixel_val; + unsigned int cur_color; + unsigned int cur_palette = palette[i]; + + /* red: calculate and make sure the result is within range */ + if (0 != contrast_factor_r ) { + cur_color = (cur_palette >> 16) & 0xFF; + new_pixel_val = + (MAX_PIXEL_VAL << 16) / (MAX_PIXEL_VAL - contrast_factor_r); + new_pixel_val = new_pixel_val * (cur_color - MID_PIXEL_VAL); + new_pixel_val >>= 16; /* convert back to 32i format */ + new_pixel_val += MID_PIXEL_VAL; + new_pixel_val = OS_MIN(new_pixel_val, MAX_PIXEL_VAL); + palette[i] &= 0x00FFFF; /* clear out the R color */ + palette[i] |= (OS_MAX(new_pixel_val, 0) & 0xFF) << 16; + } + + /* green: calculate and make sure the result is within range */ + if (0 != contrast_factor_g ) { + cur_color = (cur_palette >> 8) & 0xFF; + new_pixel_val = + (MAX_PIXEL_VAL << 16) / (MAX_PIXEL_VAL - contrast_factor_g); + new_pixel_val = new_pixel_val * (cur_color - MID_PIXEL_VAL); + new_pixel_val >>= 16; /* convert back to 32i format */ + new_pixel_val += MID_PIXEL_VAL; + new_pixel_val = OS_MIN(new_pixel_val, MAX_PIXEL_VAL); + palette[i] &= 0xFF00FF; /* clear out the G color */ + palette[i] |= (OS_MAX(new_pixel_val, 0) & 0xFF) << 8; + } + + /* blue: calculate and make sure the result is within range */ + if (0 != contrast_factor_b) { + cur_color = cur_palette & 0xFF; + new_pixel_val = + (MAX_PIXEL_VAL << 16) / (MAX_PIXEL_VAL - contrast_factor_b); + new_pixel_val = new_pixel_val * (cur_color - MID_PIXEL_VAL); + new_pixel_val >>= 16; /* convert back to 32i format */ + new_pixel_val += MID_PIXEL_VAL; + new_pixel_val = OS_MIN(new_pixel_val, MAX_PIXEL_VAL); + palette[i] &= 0xFFFF00; /* clear out the B color */ + palette[i] |= OS_MAX(new_pixel_val, 0) & 0xFF; + } + } + + + /* write the new values in the palette */ + for (i = 0; i < NUM_PALETTE_ENTRIES; i++) { + OS_WRITE32(palette[i], MMIO(display) + + PIPE(display)->palette_reg + i*4); + } + OS_FREE(palette); + + return 0; +} + +/*! + * Note: When panning in clone mode, the clone must be panned seperatly + * because it may (probably does) have a different x,y offset. + * + * @param display + * @param fb + * @param x + * @param y + * + * @return 0 + */ +static int set_display_base_plb(igd_display_context_t *display, + igd_framebuffer_info_t *fb, unsigned long *x, unsigned long *y) +{ + unsigned long base; + + /* FIXME/TODO: Compare the difference between the plb/tnc versions of this + * function, as the plb code adds-in the offset of the frame buffer. + */ + base = fb->visible_offset; + + base += ((*y * fb->screen_pitch) + (*x * IGD_PF_BYPP(fb->pixel_format))); + + WRITE_MMIO_REG(display, PLANE(display)->plane_reg + + DSP_START_OFFSET, base); + +#if 0 + /* If this plane is a mirrored plane, then update the other plane offset */ + if (PLANE(display)->mirror) { + WRITE_MMIO_REG(display, PLANE(display)->mirror->plane_reg + + DSP_START_OFFSET, base); + } +#endif + + return 0; +} + +/*! + * This function alters the position parameters associated with a cursor. + * + * @param display_handle + * @param cursor_info + * + * @return 0 + */ +static int igd_alter_cursor_pos_plb(igd_display_h display_handle, + igd_cursor_info_t *cursor_info) +{ + unsigned long cursor_reg; + unsigned long new_pos; + unsigned long cursor_base; + + igd_display_context_t *display = (igd_display_context_t *) display_handle; + cursor_reg = PIPE(display)->cursor->cursor_reg; + + if (0x27 & READ_MMIO_REG(display, cursor_reg)) { + /* unlike almador, for plba, u must program the base offset + to trigger the position update. However, this also means we + accidentally enable an invalid cursor surface if the cursor + was not enabled already. So do this check first */ + + /* + * Encode the cursor position in the format required for the + * cursor position register. + */ + if(cursor_info->y_offset >= 0) { + new_pos = (cursor_info->y_offset << 16); + } else { + new_pos = ((-(cursor_info->y_offset)) << 16) | 0x80000000; + } + if(cursor_info->x_offset >= 0) { + new_pos |= (cursor_info->x_offset); + } else { + new_pos |= (-(cursor_info->x_offset)) | 0x00008000; + } + + cursor_base = READ_MMIO_REG(display, cursor_reg + CUR_BASE_OFFSET); + + WRITE_MMIO_REG(display, cursor_reg + CUR_POS_OFFSET, new_pos); + WRITE_MMIO_REG(display, cursor_reg + CUR_BASE_OFFSET, cursor_base); + } + + return 0; +} + +/*! + * The assumption here is that palette_colors points to index 0 and + * this function indexes into the palette_colors array by start_index + * + * @param display_handle + * @param palette_colors + * @param start_index + * @param count + * + * @return 0 + */ +static int igd_set_palette_entries_plb( + igd_display_h display_handle, + unsigned long *palette_colors, + unsigned int start_index, + unsigned int count) +{ + unsigned int i; + + for(i=start_index; ipalette_reg + i*4); + } + + return 0; +} + +/*! + * This procedure waits for the next vertical sync + * period. If the display is already in a vertical sync period, this + * procedure exits. + * + * Note: A timeout is included to prevent an endless loop. + * + * @param display_handle + * @param palette_colors + * @param start_index + * @param count + * + * @return FALSE - if timed out + */ +static int igd_wait_vsync_plb(igd_display_h display_handle) +{ + long i = 0; /* General counter */ + unsigned long tmp; + unsigned char *Status_Reg; + igd_display_context_t *display = (igd_display_context_t *)display_handle; + unsigned char *mmio = MMIO(display); + + Status_Reg = mmio + PIPE(display)->pipe_reg + PIPE_STATUS_OFFSET; + + /* If pipe is off then just return */ + if(!((1<<31) & OS_READ32(mmio + PIPE(display)->pipe_reg))) { + return 1; + } + + /* 1. Disable VSync interrupt */ + tmp = OS_READ32(Status_Reg); + OS_WRITE32 (tmp & ~(1<<25), Status_Reg); + + /* 2. Clear interrupt status (by writing a 1) */ + tmp = OS_READ32(Status_Reg); + OS_WRITE32 (tmp | (1<<9), Status_Reg); + + /* 3. Enable VSync interrupt */ + tmp = OS_READ32(Status_Reg); + OS_WRITE32 (tmp | (1<<25), Status_Reg); + + /* 4. Wait for VSync */ + while ((i++ < 0x1000000) && /* Check for timeout */ + ((OS_READ32(Status_Reg) & (1<<9)) == 0x00)) { + ; + } + + if (i >= 0x10000000) + return (0); + + return (1); +} /* igd_wait_vsync*/ + + +/*! + * + * @param display_handle + * @param scanline + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ + +static int igd_get_scanline_plb(igd_display_h display_handle, int *scanline) +{ + unsigned int tmp; + unsigned char *reg; + igd_display_context_t *display = (igd_display_context_t *)display_handle; + unsigned long fb_height = PLANE(display)->fb_info->height; + unsigned long dp_height = PIPE(display)->timing->height; + + /* Scanline reg is -8 from control reg */ + reg = MMIO(display) + PIPE(display)->pipe_reg - 0x8; + + tmp = OS_READ32(reg); + + if(!(PORT_OWNER(display)->pt_info->flags & IGD_DISPLAY_ENABLE)) { + return -IGD_ERROR_INVAL; + } + + tmp = (tmp * fb_height) / dp_height; + + if(tmp >= fb_height) { + *scanline = IGD_IN_VBLANK; + } else { + *scanline = (int)tmp; + } + return 0; +} /* end igd_get_scanline() */ + +/*! + * + * @param display_handle + * + * @return 1 if TRUE + * @return 0 if FALSE + */ +static int igd_query_in_vblank_plb(igd_display_h display_handle) +{ + int sl; + + igd_get_scanline_plb(display_handle, &sl); + if (sl == IGD_IN_VBLANK) { + return 1; /*TRUE*/ + } else { + return 0; /*FALSE*/ + } +} + +/*! + * This function programs the cursor registers for Grantsdale + * + * @param display + * @param status + * + * @return void + */ +static void program_cursor_plb(igd_display_context_t *display, + unsigned long status) +{ + unsigned long cursor_reg; + unsigned long cursor_control = 0x00000000; + unsigned long cursor_pos; + unsigned long cursor_base; + igd_cursor_info_t *cursor_info; + int i; + + OS_DEBUG("Enter program_cursor: %s", status?"ENABLE":"DISABLE"); + OS_DEBUG("Device power state: D%ld", GET_DEVICE_POWER_STATE(display)); + + if (!(PIPE(display)->cursor)) { + return; + } + + cursor_reg = PIPE(display)->cursor->cursor_reg; + cursor_info = PIPE(display)->cursor->cursor_info; + + /* Turn off cursor before changing anything */ + cursor_base = READ_MMIO_REG(display, cursor_reg + CUR_BASE_OFFSET); + + WRITE_MMIO_REG(display, cursor_reg, cursor_control); + WRITE_MMIO_REG(display, cursor_reg + CUR_BASE_OFFSET, cursor_base); + + if(cursor_info->flags & IGD_CURSOR_GAMMA) { + cursor_control |= BIT26; + } + + cursor_info->argb_pitch = 64*4; + cursor_info->xor_pitch = 16; + + /* Setting the cursor format/pitch */ + switch(cursor_info->pixel_format) { + case IGD_PF_ARGB32: + cursor_control |= BIT5 | 0x7; + break; + case IGD_PF_RGB_XOR_2: + cursor_control |= 0x5; + break; + case IGD_PF_RGB_T_2: + cursor_control |= 0x4; + break; + case IGD_PF_RGB_2: + cursor_control |= 0x6; + break; + default: + return; + } + + switch(cursor_info->pixel_format) { + case IGD_PF_ARGB32: + if(display->context->dispatch.gmm_virt_to_phys( + cursor_info->argb_offset, &cursor_base)) { + OS_ERROR("No Phys pointer available for ARGB cursor"); + return; + } + break; + default: + if(display->context->dispatch.gmm_virt_to_phys( + cursor_info->xor_offset, &cursor_base)) { + OS_ERROR("No Phys pointer available for XOR cursor"); + return; + } + break; + } + + /* If status is FALSE return with the cursor off */ + if((!status) || + (GET_DEVICE_POWER_STATE(display) == IGD_POWERSTATE_D3)) { + return; + } + + if(cursor_info->y_offset >= 0) { + cursor_pos = cursor_info->y_offset << 16; + } else { + cursor_pos = ((-(cursor_info->y_offset)) << 16) | 0x80000000; + } + if(cursor_info->x_offset >= 0) { + cursor_pos |= cursor_info->x_offset; + } else { + cursor_pos |= (-(cursor_info->x_offset)) | 0x00008000; + } + + WRITE_MMIO_REG(display, cursor_reg + CUR_POS_OFFSET, + cursor_pos); + + for(i=0; i<4; i++) { + WRITE_MMIO_REG(display, cursor_reg + CUR_PAL0_OFFSET + i*4, + cursor_info->palette[i]); + } + + WRITE_MMIO_REG(display, cursor_reg, + cursor_control | (PIPE(display)->pipe_num<<28)); + WRITE_MMIO_REG(display, cursor_reg + CUR_BASE_OFFSET, cursor_base); +} + +/*! + * + * @param display_handle + * @param type + * @param surface + * @param appcontext + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ +static int igd_get_surface_plb(igd_display_h display_handle, + igd_buffertype_t type, + igd_surface_t *surface, + igd_appcontext_h appcontext) +{ +#if 0 + igd_display_context_t *display = (igd_display_context_t *)display_handle; + state3d_plb_t *state = STATE3D_PLB(appcontext); + + if(!surface) { + return -IGD_ERROR_INVAL; + } + + switch(type) { + case IGD_BUFFER_DISPLAY: + surface->offset = PLANE(display)->fb_info->visible_offset; + surface->pitch = PLANE(display)->fb_info->screen_pitch; + surface->width = PLANE(display)->fb_info->width; + surface->height = PLANE(display)->fb_info->height; + surface->u_offset = 0; + surface->u_pitch = 0; + surface->v_offset = 0; + surface->v_pitch = 0; + surface->pixel_format = PLANE(display)->fb_info->pixel_format; + surface->palette_info = 0; + surface->flags = PLANE(display)->fb_info->flags; + surface->logic_ops = 0; + surface->render_ops = 0; + surface->alpha = 0; + surface->diffuse = 0; + surface->chroma_high = 0; + surface->chroma_low = 0; + return 0; + case IGD_BUFFER_COLOR: + OS_MEMCPY(surface, &state->color_buffer, + sizeof(igd_surface_t)); + return 0; + case IGD_BUFFER_DEPTH: + OS_MEMCPY(surface, &state->depth_buffer, + sizeof(igd_surface_t)); + return 0; + default: + OS_ERROR("Invalid type in get_surface"); + break; + } + + return -IGD_ERROR_INVAL; +#else + return 0; +#endif +} + +/*! + * + * @param display_handle + * @param type + * @param surface + * @param appcontext + * @param flags + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ +static int igd_set_surface_plb(igd_display_h display_handle, + int priority, + igd_buffertype_t type, + igd_surface_t *surface, + igd_appcontext_h appcontext, + unsigned long flags) +{ + igd_display_context_t *display = (igd_display_context_t *)display_handle; + unsigned int dsp_current; + unsigned long async; + static unsigned long async_prev[2]; + unsigned long cmd_wait; + unsigned long plane_reg; + unsigned long plane_control; + unsigned long surface_offset; +#if 0 /* BP - Removing command queue code */ + cmd_queue_plb_t *queue; + unsigned long size; +#else + platform_context_plb_t *plb_context = + (platform_context_plb_t *) mode_context->context->platform_context; + int ret; +#endif + + OS_TRACE_ENTER; + if(!surface) { + return -IGD_ERROR_INVAL; + } + + switch(type) { + case IGD_BUFFER_DISPLAY: + if(! (surface->flags & IGD_SURFACE_DISPLAY)) { + OS_ERROR_EXIT("Surface is not a display surface"); + return -IGD_ERROR_INVAL; + } + +#if 0 /* BP - Removing command queue code */ + queue = CMD_GET_QUEUE_PLB(display, priority); +#endif + + if (PLANE(display)->plane_reg == DSPACNTR) { + OS_DEBUG("About to flip a buffer for display/pipe A"); + dsp_current = 0; + cmd_wait = CMD_WAIT_FLIP_A_PLB; + } else { + OS_DEBUG("About to flip a buffer for display/pipe B"); + dsp_current = 1; + cmd_wait = CMD_WAIT_FLIP_B_PLB; + } + + /* If the previous set_surface was synchronous (!async) + * then wait for it before issueing a new one. */ + if (!async_prev[dsp_current]) { + /* Wait for previous flip */ +#if 0 /* BP - Removing command queue code */ + if(!queue) { + OS_ERROR_EXIT("Queue Not Found"); + return -IGD_ERROR_INVAL; + } + size = 1; + if (cmd_reserve_plb(queue, size, VCOMMAND_WAIT_PLB)) { + OS_ERROR_EXIT("Queue reservation failed"); + return -IGD_ERROR_INVAL; + } + INSTR_WRITE(cmd_wait, queue->current_node); + cmd_update_plb(queue); +#else + int bailout; + OS_DEBUG("Must wait for previous synchronous flip"); + for (bailout=64 ; bailout > 0 ; bailout--) { + + ret = OS_PTHREAD_MUTEX_LOCK(&plb_context->flip_mutex); + ret = check_flip_pending_plb(MMIO(display), + (!dsp_current) ? 0x70024 : 0x71024); + OS_PTHREAD_MUTEX_UNLOCK(&plb_context->flip_mutex); + if (0 == ret) { + break; + } else { + /* Sleep for 1msec: */ + OS_SLEEP(1000); + } + } +#endif + } + + if(flags & IGD_BUFFER_WAIT) { + /* If this is just a wait for flip, so return */ + return 0; + } + + /* Get async flag */ + async = (flags & IGD_BUFFER_ASYNC) ? 1 : 0; + OS_DEBUG("async flag set to %lu", async); + /* + * Async flips only work when the pitch is the same. + */ + if(PLANE(display)->fb_info->screen_pitch != surface->pitch) { + OS_ERROR("Set surface w/diff pitch not handled in Poulsbo yet"); + async = 0; + } + /* + * Async flips only work when the offset is on a 256kb boundary. + */ + if(PLANE(display)->fb_info->visible_offset & 0x3ffff) { + OS_ERROR("FB offset must be 256kb aligned in Poulsbo"); + async = 0; + } + + /* Save new fb_info */ + PLANE(display)->fb_info->visible_offset = surface->offset; + PLANE(display)->fb_info->screen_pitch = surface->pitch; + PLANE(display)->fb_info->width = surface->width; + PLANE(display)->fb_info->height = surface->height; + PLANE(display)->fb_info->pixel_format = surface->pixel_format; + PLANE(display)->fb_info->flags = surface->flags; + + /* Get the correct stride and stereo */ + /* TODO - Does Poulsbo flip need to handle stereo mode? */ + /*mode_get_stride_stereo_plb(display, &stride, &stereo, 0);*/ + + /* calculate the real offset, taking panning into account */ + surface_offset = surface->offset; + surface_offset += + (PORT_OWNER(display)->pt_info->y_offset * surface->pitch) + + (PORT_OWNER(display)->pt_info->x_offset * + IGD_PF_BYPP(surface->pixel_format)); + OS_DEBUG("surface_offset = 0x%08lx", surface_offset); + + plane_reg = PLANE(display)->plane_reg; + plane_control = OS_READ32(MMIO(display) + plane_reg); + +#if 0 /* BP - Removing command queue code */ + /* Put flip in the command queue */ + size = 4; + if (cmd_reserve_plb(queue, size, VCOMMAND_REG_PLB)) { + OS_ERROR_EXIT("Queue reservation failed"); + return -IGD_ERROR_INVAL; + } + INSTR_WRITE(plane_reg, queue->current_node); + INSTR_WRITE(plane_control, queue->current_node); + if (async) { + INSTR_WRITE(plane_reg - 4, queue->current_node); + async_prev[dsp_current] = 1; + } else { + INSTR_WRITE(plane_reg + DSP_START_OFFSET, queue->current_node); + async_prev[dsp_current] = 0; + } + INSTR_WRITE(surface_offset, queue->current_node); + cmd_update_plb(queue); +#endif + /* Perform the flip by doing the following: + * + * Write the current plan_control value to the plan_reg + * Write the surface offset to either: + * 1) the plan_reg - 4 if async + * 2) plane_reg + DSP_START_OFFSET if not async + */ + OS_WRITE32(plane_control, MMIO(display) + plane_reg); + if (async) { + OS_WRITE32(surface_offset, MMIO(display) + plane_reg - 4); + async_prev[dsp_current] = 1; + } else { + OS_WRITE32(surface_offset, + MMIO(display) + plane_reg + DSP_START_OFFSET); + async_prev[dsp_current] = 0; + ret = OS_PTHREAD_MUTEX_LOCK(&plb_context->flip_mutex); + set_flip_pending_plb(MMIO(display), + (!dsp_current) ? 0x70024 : 0x71024); + OS_PTHREAD_MUTEX_UNLOCK(&plb_context->flip_mutex); + } + + OS_TRACE_EXIT; + return 0; + case IGD_BUFFER_COLOR: + OS_TRACE_EXIT; + return 0; + case IGD_BUFFER_DEPTH: + OS_TRACE_EXIT; + return 0; + default: + OS_ERROR("Invalid type in set_surface"); + break; + } + + OS_TRACE_EXIT; + return 0; +} + +/* Poulsbo does not support a flip pending, since there is no + * Display Buffer Info instruction. So this must be done with vBlank. + * However, a wait_for_vblank can be given while a flip is also in + * progress, so a semaphore is required when changing flip_pending or + * when modifying the vBlank interrupt bits. + * + * This function should only be called with a flip_mutex around it */ +int set_flip_pending_plb(unsigned char *mmio, unsigned long pipe_status_reg) +{ + platform_context_plb_t *plb_context = + (platform_context_plb_t *)mode_context->context->platform_context; + unsigned long tmp; + + OS_TRACE_ENTER; + OS_ASSERT((pipe_status_reg == 0x70024) || (pipe_status_reg == 0x71024), + "Invalid pipe_status_reg", 0); + + /* 1. Disable VBlank interrupt */ + tmp = OS_READ32(OS_MMIO(mmio) + pipe_status_reg); + OS_WRITE32 (tmp & ~VBLANK_STS_EN, + OS_MMIO(mmio) + pipe_status_reg); + + /* 2. Clear VBlank interrupt status (by writing a 1) */ + tmp = OS_READ32(OS_MMIO(mmio) + pipe_status_reg); + OS_WRITE32 (tmp | VBLANK_STS, OS_MMIO(mmio) + pipe_status_reg); + + /* 3. Enable VBlank interrupt */ + tmp = OS_READ32(OS_MMIO(mmio) + pipe_status_reg); + OS_WRITE32 (tmp | VBLANK_STS_EN, OS_MMIO(mmio) + pipe_status_reg); + + if (pipe_status_reg == 0x70024) { + plb_context->flip_pending |= PLB_FLIP_PIPE_A_PENDING; + } else { + plb_context->flip_pending |= PLB_FLIP_PIPE_B_PENDING; + } + + OS_TRACE_EXIT; + return 0; +} + +/* This function should only be called with a flip_mutex around it */ +int check_flip_pending_plb(unsigned char *mmio, + unsigned long pipe_status_reg) +{ + platform_context_plb_t *plb_context = + (platform_context_plb_t *)mode_context->context->platform_context; + unsigned long tmp; + unsigned int flip_pending; + + OS_TRACE_ENTER; + OS_ASSERT((pipe_status_reg == 0x70024) || (pipe_status_reg == 0x71024), + "Invalid pipe_status_reg", 0); + + if (pipe_status_reg == 0x70024) { + flip_pending = + plb_context->flip_pending & PLB_FLIP_PIPE_A_PENDING; + } else { + flip_pending = + plb_context->flip_pending & PLB_FLIP_PIPE_B_PENDING; + } + + if (flip_pending) { + tmp = OS_READ32(mmio + pipe_status_reg) & VBLANK_STS; + if (tmp != 0) { + /* VBlank occured, flip complete */ + plb_context->flip_pending &= ~flip_pending; + OS_DEBUG("returning 0 after checking register"); + return 0; + } else { + /* VBlank not done, flip still in progress */ + OS_DEBUG("returning 1"); + return 1; + } + } else { + /* No flip pending, so it must have completed */ + OS_DEBUG("returning 0"); + return 0; + } +} + +/*! + * + * @param display_handle + * @param event + * @param status + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ +static int igd_query_event_plb(igd_display_h display_handle, + igd_event_t event, unsigned long *status) +{ + platform_context_plb_t *plb_context = + (platform_context_plb_t *)mode_context->context->platform_context; + unsigned char *mmio = MMIO(display_handle); + unsigned long pipe_status_reg = + (PLANE(display_handle)->plane_reg == DSPACNTR) ? 0x70024 : 0x71024; + int ret; + + OS_TRACE_ENTER; + OS_DEBUG("mmio=0x%p, pipe_status_reg=0x%08lx", mmio, pipe_status_reg); + + switch (event) { + case IGD_EVENT_FLIP_PENDING: + ret = OS_PTHREAD_MUTEX_LOCK(&plb_context->flip_mutex); + *status = check_flip_pending_plb(mmio, pipe_status_reg); + OS_PTHREAD_MUTEX_UNLOCK(&plb_context->flip_mutex); + break; + default: + return -IGD_ERROR_INVAL; + } + + OS_DEBUG("Returning status=%lu", *status); + return IGD_SUCCESS; +} + +/*! + * Function gets the width, height and pitch of the framebuffer. + * + * @param void + * + * @return 0 + */ +static int get_plane_info_plb(void) +{ + igd_framebuffer_info_t *buffer_info; + unsigned char* mmio = NULL; + unsigned long plane_control = 0; + unsigned long reg = 0; + + OS_TRACE_ENTER; + + mmio = OS_MMIO(mode_context->context->device_context.virt_mmadr); + /* Check that plane A is active and process it */ + plane_control = OS_READ32(mmio + DSPACNTR); + if(plane_control & PLANE_ENABLE){ + buffer_info = &mode_context->fw_info->fb_info[0]; + + /* get the DSPASIZE register value */ + reg = (unsigned long)OS_READ32(mmio + DSPACNTR + DSP_SIZE_OFFSET); + buffer_info[0].height = (reg >> 16) & 0xFFF; + buffer_info[0].width = reg & 0xFFF; + + /* get the DSPASTRIDE register value */ + buffer_info[0].screen_pitch = + (unsigned int)OS_READ32(mmio + DSPACNTR + DSP_STRIDE_OFFSET); + + /* Following are NOT offset by 1 in fb info */ + buffer_info[0].width++; + buffer_info[0].height++; + } + + /* Check that plane B is active and process it */ + plane_control = OS_READ32(mmio + DSPBCNTR); + if(plane_control & PLANE_ENABLE){ + buffer_info = &mode_context->fw_info->fb_info[0]; + + /* get the DSPBSIZE register value */ + reg = (unsigned long)OS_READ32(mmio + DSPBCNTR + DSP_SIZE_OFFSET); + buffer_info[1].height = (reg >> 16) & 0xFFF; + buffer_info[1].width = reg & 0xFFF; + + /* get the DSPBSTRIDE register value */ + buffer_info[1].screen_pitch = + (unsigned int)OS_READ32(mmio + DSPBCNTR + DSP_STRIDE_OFFSET); + + /* Following are NOT offset by 1 in fb info */ + buffer_info[1].width++; + buffer_info[1].height++; + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param void + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ +static int get_pipe_info_plb(void) +{ + unsigned char *mmio = NULL; + unsigned long pipe_conf = 0; + igd_display_info_t *timing; + unsigned long reg = 0; + + OS_TRACE_ENTER; + + mmio = OS_MMIO(mode_context->context->device_context.virt_mmadr); + pipe_conf = OS_READ32(mmio + PIPEA_CONF); + + if(pipe_conf & BIT(31)) { /* pipe A is active */ + timing = &mode_context->fw_info->timing_arr[0]; + + reg = OS_READ32(mmio + HTOTAL_A); + timing[0].htotal = (unsigned short)(reg >> 16) & 0x1FFF; + timing[0].width = (unsigned short)reg & 0xFFF; + + reg = OS_READ32(mmio + HBLANK_A); + timing[0].hblank_start = (unsigned short)reg & 0x1FFF; + timing[0].hblank_end = (unsigned short)(reg >> 16) & 0x1FFF; + + reg = OS_READ32(mmio + HSYNC_A); + timing[0].hsync_start = (unsigned short)reg & 0x1FFF; + timing[0].hsync_end = (unsigned short)(reg >> 16) & 0x1FFF; + + reg = OS_READ32(mmio + VTOTAL_A); + timing[0].vtotal = (unsigned short)(reg >> 16) & 0x1FFF; + timing[0].height = (unsigned short)reg & 0xFFF; + + reg = OS_READ32(mmio + VBLANK_A); + timing[0].vblank_start = (unsigned short)reg & 0x1FFF; + timing[0].vblank_end = (unsigned short)(reg >> 16) & 0x1FFF; + + reg = OS_READ32(mmio + VSYNC_A); + timing[0].vsync_start = (unsigned short)reg & 0x1FFF; + timing[0].vsync_end = (unsigned short)(reg >> 16) & 0x1FFF; + + /* Following are not offset by 1 in ptinfo */ + timing[0].width++; + timing[0].height++; + + OS_DEBUG("Pipe A timing width = %d", timing[0].width); + OS_DEBUG("Pipe A timing width = %d", timing[0].height); + + { + /* Calculate the firmware programmed dot clock */ + unsigned long dplla, fpa0, fpa1; + unsigned long ma1, ma2, na, pa1, pa2, plla_select; + unsigned long ref_freq = 0, dclk; + unsigned long temp; /* To store intermediate values b4 dclk */ + int j; + + dplla = OS_READ32(mmio + DPLLACNTR); + fpa0 = OS_READ32(mmio + FPA0); + fpa1 = OS_READ32(mmio + FPA1); + + if(dplla & BIT(31)) { + + ma1 = (fpa0 >> 8) & 0x3F; /* M1 is bits 13:8 */ + ma2 = (fpa0) & 0x1F; /* M1 is bits 5:0 */ + na = (fpa0 >> 16) & 0x3F; /* N is bits 21:16 */ + pa1 = (dplla >> 16) & 0xFF; /* P1 is bits 23:16 */ + + /* Check for illegal values of P1 + * The bit representation MUST be power of 2 + * All other values are illegal including zero. + */ + if( (pa1 == 0) || + ( (pa1 & (pa1-1)) != 0 ) ) { + + OS_ERROR("Invalid P1 bits set"); + return -IGD_ERROR_INVAL; + } + for(j = 0; j < 8; j++) { + if(pa1 & BIT(j)) { /* P1 is divide by 1 to 8 */ + pa1 = j+1; + break; + } + } + pa2 = (dplla >> 24) & 0x3; /* P2 is bits 25:24 */ + + /* The post divisor values are different if the + * attached port is internal LVDS. Since Pipe A + * does not support internal LVDS, we just follow + * the normal divisor values + */ + if(pa2 == 0) { + pa2 = 10; + } else if(pa2 == 1) { + pa2 = 5; + } else { + OS_ERROR("Invalid P2 bits set = 0x%lx", pa2); + } + plla_select = (dplla >> 13) & 0x3; /* PLL Ref I/P Select */ + + /* Equation that calculates the dot clk + * ------------------------------------- + * + * pll_freq_factor = ((float)(5 * (ma1+2)+(ma2+2))/(na+2))/ + * ((pa1*pa2)); + * + * fdclk = pll_freq_factor * ref_freq * 1000000; + * + * Support for FPU in Kernel Code is not straightforward + * we will just stick to int operations. We will just re- + * arrange the factors. + */ + if(plla_select == 0) { + ref_freq = 96; /* 96MHz */ + } else if( (plla_select == 1) || (plla_select == 3) ) { + + OS_ERROR("Invalid PLL Reference Input Select Reserved"); + return -IGD_ERROR_INVAL; + + } else if(plla_select == 2) { + OS_DEBUG("PLL ref is SDVO TV CLK"); + /* TODO: How to handle this value? */ + ref_freq = 0; + } + + /* First let's multiply by 1000 * 1000 + * so that we don't get zero during integer + * division + */ + temp = 1000 * 1000; + temp = temp * (5 * (ma1+2) + (ma2+2)); + temp = temp/(na+2); + temp = temp/(pa1*pa2); + + dclk = temp * ref_freq; + + if( (dclk == 0) || (ref_freq == 0) ) { + OS_ERROR(" Dot Clock/Ref Frequency is Zero!!!"); + return -IGD_ERROR_INVAL; + } + OS_DEBUG("Ref frequency = %lu", ref_freq); + OS_DEBUG("Pipe A constructed Dot clock is = %lu", dclk); + timing[0].dclk = dclk/1000; /* Make it to KHz */ + OS_DEBUG("Pipe A Dot clock in KHz = %lu", timing[0].dclk); + + timing[0].refresh = (unsigned short)(dclk/ + ((timing[0].htotal+1)*(timing[0].vtotal+1))); + + OS_DEBUG("Pipe A refresh = %u", timing[0].refresh); + } /* if DPLL A active */ + } /* dot clock code block */ + } /* if Pipe A active */ + + pipe_conf = OS_READ32(mmio + PIPEB_CONF); + + if(pipe_conf & BIT(31)) { /* pipe B is active */ + timing = &mode_context->fw_info->timing_arr[0]; + + reg = OS_READ32(mmio + HTOTAL_B); + timing[1].htotal = (unsigned short)(reg >> 16) & 0x1FFF; + timing[1].width = (unsigned short)reg & 0xFFF; + + reg = OS_READ32(mmio + HBLANK_B); + timing[1].hblank_start = (unsigned short)reg & 0x1FFF; + timing[1].hblank_end = (unsigned short)(reg >> 16) & 0x1FFF; + + reg = OS_READ32(mmio + HSYNC_B); + timing[1].hsync_start = (unsigned short)reg & 0x1FFF; + timing[1].hsync_end = (unsigned short)(reg >> 16) & 0x1FFF; + + reg = OS_READ32(mmio + VTOTAL_B); + timing[1].vtotal = (unsigned short)(reg >> 16) & 0x1FFF; + timing[1].height = (unsigned short)reg & 0xFFF; + + reg = OS_READ32(mmio + VBLANK_B); + timing[1].vblank_start = (unsigned short)reg & 0x1FFF; + timing[1].vblank_end = (unsigned short)(reg >> 16) & 0x1FFF; + + OS_READ32(mmio + VSYNC_B); + timing[1].vsync_start = (unsigned short)reg & 0x1FFF; + timing[1].vsync_end = (unsigned short)(reg >> 16) & 0x1FFF; + + /* Following are not offset by 1 in ptinfo */ + timing[1].width++; + timing[1].height++; + + OS_DEBUG("Pipe B timing width = %d", timing[1].width); + OS_DEBUG("Pipe B timing width = %d", timing[1].height); + + { + /* Calculate the firmware programmed dot clock */ + unsigned long dpllb, fpb0, fpb1; + unsigned long mb1, mb2, nb, pb1, pb2, pllb_select; + unsigned long ref_freq = 0, dclk; + unsigned long temp; /* To store intermediate values b4 dclk */ + int j; + unsigned long lvds_port; + + dpllb = OS_READ32(mmio + DPLLBCNTR); + fpb0 = OS_READ32(mmio + FPB0); + fpb1 = OS_READ32(mmio + FPB1); + /* Note: Only Pipe B supports LVDS */ + lvds_port = OS_READ32(mmio + LVDSCNTR); + + if(dpllb & BIT(31)) { + + mb1 = (fpb0 >> 8) & 0x3F; /* M1 is bits 13:8 */ + mb2 = (fpb0) & 0x1F; /* M1 is bits 5:0 */ + nb = (fpb0 >> 16) & 0x3F; /* N is bits 21:16 */ + pb1 = (dpllb >> 16) & 0xFF; /* P1 is bits 23:16 */ + + /* Check for illegal values of P1 + * The bit representation MUST be power of 2 + * All other values are illegal including zero. + */ + if( (pb1 == 0) || + ( (pb1 & (pb1-1)) != 0 ) ) { + OS_ERROR("Invalid P1 bits set"); + return -IGD_ERROR_INVAL; + } + + for(j = 0; j < 8; j++) { + if(pb1 & BIT(j)) { /* P1 is divide by 1 to 8 */ + pb1 = j+1; + break; + } + } + + pb2 = (dpllb >> 24) & 0x3; /* P2 is bits 25:24 */ + + /* For LVDS port, the post divisor factors are different */ + if((lvds_port & 0xC0000000) == 0xC0000000) { + /* Pipe is used for LVDS port */ + if(pb2 == 0) { + pb2 = 14; + } else if(pb2 == 1) { + pb2 = 7; + } else { + OS_ERROR("Invalid P2 bits set = 0x%lx", pb2); + return -IGD_ERROR_HWERROR; + } + + } else { + /* Pipe is used for Non-LVDS port */ + if(pb2 == 0) { + pb2 = 10; + } else if(pb2 == 1) { + pb2 = 5; + } else { + OS_ERROR(":Invalid P2 bits set = 0x%lx", pb2); + return -IGD_ERROR_HWERROR; + } + + } + + pllb_select = (dpllb >> 13) & 0x3; /* PLL Ref I/P Select */ + + /* Equation that calculates the dot clk + * ------------------------------------- + * + * pll_freq_factor = ((float)(5 * (mb1+2)+(mb2+2))/(nb+2))/ + * ((pb1*pb2)); + * + * fdclk = pll_freq_factor * ref_freq * 1000000; + * + * Support for FPU in Kernel Code is not straightforward + * we will just stick to int operations. We will just re- + * arrange the factors. + */ + if(pllb_select == 0) { + ref_freq = 96; /* 96MHz */ + + } else if( (pllb_select == 1) || (pllb_select == 3) ) { + + OS_ERROR("Invalid PLL Reference Input Select Reserved"); + return -IGD_ERROR_INVAL; + + } else if(pllb_select == 2) { + OS_DEBUG("PLL ref is SDVO TV CLK"); + /* TODO: How to handle this value? */ + return -IGD_ERROR_INVAL; + } + + /* First let's multiply by 1000 * 1000 + * so that we don't end up in zero during + * integer division + */ + temp = 1000 * 1000; + temp = temp * (5 * (mb1+2) + (mb2+2)); + temp = temp /(nb+2); + dclk = temp/(pb1*pb2); + + dclk = temp * ref_freq; + + if( (dclk == 0) || (ref_freq == 0) ) { + OS_ERROR("Dot Clock/Ref Frequency is Zero!!!"); + return -IGD_ERROR_INVAL; + } + + OS_DEBUG("Ref frequency = %lu", ref_freq); + OS_DEBUG("Pipe B constructed Dot clock is = %lu", dclk); + timing[1].dclk = dclk/1000; /* Make it to KHz */ + OS_DEBUG("Pipe B Dot clock in KHz = %lu", timing[1].dclk); + + timing[1].refresh = (unsigned short) (dclk/ + ((timing[1].htotal+1)*(timing[1].vtotal+1))); + + OS_DEBUG("Pipe B refresh = %u", timing[1].refresh); + } /* if DPLL B active */ + } /* dot clock code block */ + } /* if Pipe B is active */ + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param void + * + * @return 0 + */ +static int get_port_info_plb(void) +{ + /* TODO: Any port related info that needs to be populated ? */ + OS_TRACE_ENTER; + + OS_TRACE_EXIT; + return 0; +} + +mode_full_dispatch_t mode_full_dispatch_plb = { + igd_alter_cursor_pos_plb, + igd_set_palette_entries_plb, + igd_wait_vsync_plb, + igd_query_in_vblank_plb, + igd_get_scanline_plb, + set_display_base_plb, + program_cursor_plb, + set_color_correct_plb, + igd_get_surface_plb, + igd_set_surface_plb, + igd_query_event_plb, + set_flip_pending_plb, + check_flip_pending_plb, + get_plane_info_plb, + get_pipe_info_plb, + get_port_info_plb, +}; + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: mode_plb.c,v 1.20 2010/04/27 20:33:49 bpaauwe Exp $ + *---------------------------------------------------------------------------- + */ diff --git a/drivers/gpu/drm/emgd/emgd/display/mode/tnc/clocks_tnc.c b/drivers/gpu/drm/emgd/emgd/display/mode/tnc/clocks_tnc.c new file mode 100644 index 0000000..abc54b9 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/mode/tnc/clocks_tnc.c @@ -0,0 +1,559 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: clocks_tnc.c + * $Revision: 1.6 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * Clock programming for Tunnel Creek + * program clocks used for LVDS port based on Lincroft + * program clocks used for SDVO port based on Tunnel Creek overlay + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.mode + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +/*! + * @addtogroup display_group + * @{ + */ + +/* Enable this if calculated values are wrong and required fixed table */ +#define CONFIG_FIXED_TABLE 0 + +#ifdef CONFIG_TNC + +extern int program_clock_sdvo_tnc(igd_display_context_t *display, + igd_clock_t *clock, unsigned long dclk); + +/*=========================================================================== +; File Global Data +;--------------------------------------------------------------------------*/ +#if CONFIG_FIXED_TABLE +typedef struct _fixed_clock { + unsigned long dclk; + unsigned long n; + unsigned long m; + unsigned long p1; +} fixed_clock_t; + +/* set mmio register required values */ +static fixed_clock_t lvds_fixed_clock_table[] = { + /* Clock N M P1 */ + { 65000, 0x01, 0x00, 0x00 }, + { 0xffffffff, 0x01, 0x00, 0x00} +}; + +/* set mmio register required values */ +static fixed_clock_t sdvo_fixed_clock_table[] = { + /* Clock N M P1 */ + { 65000, 0x00, 0x00, 0x00 }, + { 0xffffffff, 0x00, 0x00, 0x00} +}; +#endif + +#define LVDS_M_MIN 10 + +static const unsigned long lvds_m_converts[] = { + 0x2B, 0x15, 0x2A, 0x35, 0x1A, 0x0D, 0x26, 0x33, 0x19, 0x2C, + 0x36, 0x3B, 0x1D, 0x2E, 0x37, 0x1B, 0x2D, 0x16, 0x0B, 0x25, + 0x12, 0x09, 0x24, 0x32, 0x39, 0x1c, +}; + +#define TARGET_ERROR 46 + +typedef const struct _tnc_limits { + unsigned long ref_freq; + unsigned long min_m; + unsigned long max_m; + + unsigned long min_n; + unsigned long max_n; + + unsigned long min_p1; + unsigned long max_p1; + + unsigned long min_p2; + unsigned long max_p2; + + unsigned long min_vco; + unsigned long max_vco; +} tnc_limits_t; + +/* m, n, p value limits: + * source: http://moss.amr.ith.intel.com/sites/LCD/LNC/HAS/Secured + * %20Documents/LNC%20HAS%20work%20area/Lincroft%20DPLL_1.2_ww31_08.docx + * + * Note: + * VCO range for 100L is not given: so put a range big enough to go through + * calculations for the for loop. + */ +static tnc_limits_t tnc_lvds_limits[] = +{ + /* reffreq m n p1 p2 vco */ + { 200000, 10, 17, 1, 1, 2, 8, 14, 14, 2000000, 3400000}, /* SKU 100 */ + { 100000, 20, 34, 1, 1, 2, 8, 14, 14, 1000000, 3400000}, /* SKU 100L */ + { 166000, 12, 20, 1, 1, 2, 7, 14, 14, 2000000, 3333333}, /* SKU 83 */ +}; + +static tnc_limits_t tnc_sdvo_limits[] = +{ + /* reffreq m n p1 p2 vco */ + { 96000, 80,137, 3, 7, 1, 2, 10, 10, 1600000, 3456000}, /* SDVO */ +}; + +/*! + * + * @param dclk + * @param ref_freq + * @param limits + * @param m + * @param n + * @param p + * @param target_error + * + * @return 0 on success + * @return 1 on failure + */ +static int calculate_clock(unsigned long dclk, + unsigned long ref_freq, + tnc_limits_t *l, + unsigned long *m, + unsigned long *n, + unsigned long *p1, + unsigned long target_error) +{ + unsigned long pdiv; + unsigned long target_vco, actual_freq; + long freq_error, min_error; + unsigned long dclk_10000; + + unsigned long current_m, current_n, current_p1; + + OS_TRACE_ENTER; + + min_error = 100000; + + *m = 0; + *n = 0; + *p1 = 0; + + /* dclk * 10000, so it does not have to be calculated within the + * loop */ + dclk_10000 = dclk * 10000; + + for(current_m = l->min_m; current_m <= l->max_m; current_m++) { + for(current_n = l->min_n; current_n <= l->max_n; current_n++) { + for(current_p1 = l->min_p1; current_p1 <= l->max_p1; current_p1++) { + + /* For both LVDS/SDVO ports min_p2 and max_p2 are same, + * so assign use either min/max p2 */ + pdiv = current_p1 * l->min_p2; + target_vco = dclk * pdiv; + + if (target_vco > l->max_vco) { + /* target_vco continues to increase, so start with + * next current_n */ + break; + } + + if (target_vco >= l->min_vco) { + actual_freq = (ref_freq * current_m) / (current_n*pdiv); + freq_error = 10000 - (dclk_10000 / actual_freq); + + if (freq_error < -min_error) { + /* freq_error continues to decrease once this + * point is reached, so start with next + * current_n */ + break; + } + + if (freq_error < 0) { + freq_error = -freq_error; + } + if (freq_error < min_error) { + *n = current_n; + *m = current_m; + *p1 = current_p1; + min_error = freq_error; + } + } + } + } + if (min_error == 0) { + break; + } + } + /* + * No clock found that meets error requirement + */ + if (min_error > (long)target_error) { + OS_TRACE_EXIT; + return 1; + } + + OS_DEBUG("dclk = (ref*m)/(n*p1*p2) => %lu = (%lu*%lu)/(%lu*%lu*%lu) = %lu", + dclk, ref_freq, *m, *n, *p1, l->min_p2, + (ref_freq*(*m))/((*n)*(*p1)*l->min_p2)); + OS_DEBUG("min_error:%ld", min_error); + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param dclk + * @param ref_freq + * @param limits + * @param m + * @param n + * @param p + * @param target_error + * @param port_type + * + * @return 0 on success + * @return 1 on failure + */ +static int get_clock(unsigned long dclk, + unsigned long ref_freq, + tnc_limits_t *l, + unsigned long *m, + unsigned long *n, + unsigned long *p1, + unsigned long target_error, + unsigned long port_type) +{ + +#if CONFIG_FIXED_TABLE + fixed_clock_t *fixed; + OS_TRACE_ENTER; + /* Enable this if calculated values are wrong and required fixed table */ + if (port_type == IGD_PORT_LVDS) { + fixed = lvds_fixed_clock_table; + } else { + fixed = sdvo_fixed_clock_table; + } + + /* First check for a fixed clock from the table. These are ones that + * can't be calculated correctly. */ + while (fixed->dclk != 0xffffffff) { + if (fixed->dclk == dclk) { + OS_DEBUG("Using Fixed Clock From table for clock %ld", dclk); + *m = fixed->m; + *n = fixed->n; + *p1 = fixed->p1; + OS_TRACE_EXIT; + return 0; + } + fixed++; + } +#endif + + OS_TRACE_ENTER; + /* No fixed clock found so calculate one. */ + OS_DEBUG("Calculating dynamic clock for clock %ld", dclk); + + if (calculate_clock(dclk, ref_freq, l, m, n, p1, target_error)) { + /* No usable clock. Cannot use 640x480@60 as default, because + * there are several vcos and several reference clocks. */ + OS_ERROR("Could not calculate clock %ld, returning default.", dclk); + OS_TRACE_EXIT; + return 1; + } + + /* Translate returned values to m,n,p1 register values */ + /* No change required for *n value */ + if (port_type == IGD_PORT_SDVO) { + *p1 = (1L << (*p1 - 1)); + *m -= 2; + *n = (1L << (*n -1)); + } else { + *p1 = (1L << (*p1 - 2)); + *m = lvds_m_converts[*m - LVDS_M_MIN]; + } + + OS_DEBUG("reg m=%lu n=%lu p1=%lu p2=%lu", *m, *n, *p1, l->min_p2); + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param display + * @param clock + * @param dclk + * + * @return 0 on success + * @return 1 on failure + */ +int program_clock_lvds_tnc(igd_display_context_t *display, + igd_clock_t *clock, + unsigned long dclk) +{ + int ret; + unsigned long m, n, p1; + unsigned long control; + unsigned long ref_freq; + igd_display_port_t *port; + tnc_limits_t *l = NULL; + unsigned long count; + + OS_TRACE_ENTER; + + port = PORT_OWNER(display); + + /* LNC ref_freq is determined by SKU, convert to KHz */ +#if 0 + ref_freq = display->context->device_context.gfx_freq * 1000L; +#else + ref_freq = display->context->device_context.core_freq; + ref_freq = ref_freq * 1000; +#endif + +#if 0 + /* Find m,n,p,vco limits */ + if (ref_freq == 200000) { + l = &tnc_lvds_limits[0]; + } else if (ref_freq == 100000) { + l = &tnc_lvds_limits[1]; + } else if (ref_freq == 166000) { + l = &tnc_lvds_limits[2]; + } +#endif + + for(count=0; count<3; count++){ + if (tnc_lvds_limits[count].ref_freq == ref_freq){ + l = &tnc_lvds_limits[count]; + break; + } + } + +/* PO Debug */ +#if 0 + /* WRITE_PORT80(0xED); */ + + if(ref_freq == 166000){ + WRITE_PORT80(0xEF); + } + + if (!l){ + /* FATAL ERROR */ + DEAD_LOOP(0xDD); + } +#endif + + /* Per UMG, there is no defined target_error for LVDS, it supposed to + * work for all expected dclks. */ +#if 1 + ret = get_clock(dclk, ref_freq, l, &m, &n, &p1, dclk /* target_error */, + port->port_type); + if (ret) { + OS_ERROR_EXIT("Clock %ld could not be programmed", dclk); + /* DEAD_LOOP(0xFF); */ + return ret; + } +#else + /* Hard code the values for now */ + m = 0x2D; // ITP uses 0x2E, should change + p1 = 2; + +#endif + +#if 0 + /* If clocks are already running at required clocks, just return */ + if (PIPE(display)->dclk == dclk) { + return 0; + } +#endif + + /* Disable DPLL */ +#if 0 + control = BIT28 | (1<p_shift); //Why are we shifting 1 to P1, GMA carry over??? +#else + control = BIT28; +#endif + WRITE_MMIO_REG(display, clock->dpll_control, control); + OS_DEBUG("lvds: OS_WRITE32: 0x%lx = 0x%lx", + clock->dpll_control, control); + + /* Program M */ + WRITE_MMIO_REG(display, clock->mnp, (m<<8)); + + WRITE_MMIO_REG(display, 0xF044, (m<<8)); //BUGBUG + + OS_DEBUG("lvds: OS_WRITE32: 0x%lx = 0x%lx", + clock->mnp, (m<<8)); + + /* Enable DPLL */ + control = (BIT31 | BIT28 | BIT27) | (p1<p_shift); + +/* PO Debug..*/ +#if 0 + /* set VCO select */ + if (ref_freq == 166000) { + control |= BIT16; + } +#endif + + + WRITE_MMIO_REG(display, clock->dpll_control, control); + OS_DEBUG("lvds: OS_WRITE32: 0x%lx = 0x%lx", + clock->dpll_control, control); + + /* Wait 150us for the DPLL to stabilize */ + OS_SLEEP(150); + PIPE(display)->dclk = dclk; + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param display + * @param clock + * @param dclk + * + * @return 0 on success + * @return 1 on failure + */ +int program_clock_sdvo_tnc(igd_display_context_t *display, + igd_clock_t *clock, + unsigned long dclk) +{ + int ret; + unsigned long m, n, p1; + unsigned long control; + unsigned long ref_freq; + unsigned long port_mult, vga_mult; + unsigned long target_error; + igd_display_port_t *port; + tnc_limits_t *l; + + OS_DEBUG("Enter program_clock"); + + port = PORT_OWNER(display); + + /* FIXME: No info available in EAS and waiting for info. */ + if (dclk > 100000) { /* 100-200 MHz */ + port_mult = 1; + } else if (dclk > 50000) { /* 50-100 Mhz */ + port_mult = 2; + } else { /* 25-50 Mhz */ + port_mult = 4; + } + dclk *= port_mult; + + l = &tnc_sdvo_limits[0]; + ref_freq = l->ref_freq; + + vga_mult = READ_MMIO_REG_TNC(IGD_PORT_SDVO, clock->dpll_control) & 0x3; + + target_error = TARGET_ERROR; + + /* For external clock sources always use ref_clock == dclk */ + if(port->pd_flags & PD_FLAG_CLK_SOURCE) { + ref_freq = dclk; + /* When clock source sdvo device, allowed error is 0. */ + target_error = 0; + } + + ret = get_clock(dclk, ref_freq, l, &m, &n, &p1, target_error, + IGD_PORT_SDVO); + + if (ret) { + OS_ERROR("Clock %ld could not be programmed", dclk); + return ret; + } + + /* Disable DPLL, Write 2 into P for saftey */ + control = BIT28 | (2<p_shift) | vga_mult; + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, clock->dpll_control, control); + OS_DEBUG("sdvo: OS_WRITE32: 0x%lx = 0x%lx", + clock->dpll_control, control); + + /* Program N, M */ + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, clock->mnp, (n<<16) | m); + OS_DEBUG("sdvo: OS_WRITE32: 0x%lx = 0x%lx", + clock->mnp, (n<<16)|m); + + /* Enable DPLL, Disable VGA mode and sitck in new P values */ + control = BIT31 | BIT30 | BIT28 | (p1<p_shift) | vga_mult; + + /* Set the clock source correctly based on PD settings */ + if(port->pd_flags & PD_FLAG_CLK_SOURCE) { + control |= port->clock_bits; + } + + /* sDVO Multiplier bits[7:0] */ + if (port_mult == 2) { + control |= (1 << 4); + } else if (port_mult == 3) { + control |= (2 << 4); + } else if (port_mult == 4) { + control |= (3 << 4); + } + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, clock->dpll_control, control); + OS_DEBUG("sdvo: OS_WRITE32: 0x%lx = 0x%lx", + clock->dpll_control, control); + + /* We must wait for 150 us for the dpll clock to warm up */ + OS_SLEEP(150); + + return 0; +} + +int program_clock_tnc(igd_display_context_t *display, + igd_clock_t *clock, + unsigned long dclk) +{ + OS_TRACE_ENTER; + + if (PORT_TYPE(display) == IGD_PORT_LVDS) { + OS_TRACE_EXIT; + return program_clock_lvds_tnc(display, clock, dclk); + } else { + OS_TRACE_EXIT; + return program_clock_sdvo_tnc(display, clock, dclk); + } +} +#endif + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: clocks_tnc.c,v 1.6 2010/04/27 20:33:49 bpaauwe Exp $ + * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/mode/tnc/clocks_tnc.c,v $ + *---------------------------------------------------------------------------- + */ diff --git a/drivers/gpu/drm/emgd/emgd/display/mode/tnc/micro_mode_tnc.c b/drivers/gpu/drm/emgd/emgd/display/mode/tnc/micro_mode_tnc.c new file mode 100644 index 0000000..eb65b63 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/mode/tnc/micro_mode_tnc.c @@ -0,0 +1,1842 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: micro_mode_tnc.c + * $Revision: 1.11 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * 1) Tunnel Creek Core implementations for the mode dispatch functions. + * 2) 0:2:0 = Device2 = LNC VGA + * 0:3:0 = Device3 = TNC overlay + * 3) For MMIO access: + * Dev2 only: Use OS_READ32(), OS_WRITE32(): less code + * Dev2/3: Use READ_MMIO_REG_TNC(), WRITE_MMIO_REG_TNC(): more code + * For code optimization sake use the right macro. + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.mode + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../cmn/match.h" +#include "../cmn/mode_dispatch.h" + +#ifndef CONFIG_MICRO +/* Turning on FIB part workaround for all OS except vBIOS due to + * code size + */ +#define CDVO_WORKAROUND +#endif +/*! + * @addtogroup display_group + * @{ + */ + +/* + * Exports from the other components of this module. + */ + +#ifdef CONFIG_TNC + +extern int program_clock_tnc(igd_display_context_t *display, + igd_clock_t *clock, unsigned long dclk); + +extern mode_full_dispatch_t mode_full_dispatch_tnc; + +typedef struct _mode_data_tnc { + unsigned long plane_a_preserve; + unsigned long plane_b_c_preserve; + unsigned long pipe_preserve; + unsigned long dsp_arb; + unsigned long fifo_watermark1; + unsigned long fifo_watermark2; + unsigned long fifo_watermark3; +} mode_data_tnc_t; + +static mode_data_tnc_t device_data[1] = { + { + 0x000b0000, /* plane a preservation */ + 0x00000000, /* plane b c preservation */ + 0x60000000, /* pipe preservation */ + 0x00003232, /* DSP FIFO Size A=50 B=50 C=28 May require fine tuning*/ + 0x3f8f0f0f, /* FIFO watermark control1 */ + 0x0b060f0f, /* FIFO watermark control2 */ + 0x00000000, /* FIFO watermark control3 */ + } +}; + +/* Do not change the order */ +static const unsigned long ports_tnc[2] = {IGD_PORT_LVDS, IGD_PORT_SDVO}; + +/* Extern defines for Device2, device3 and device31 iobases. + * For Tunnel Creek all devices are always io_mapped. */ +extern unsigned char io_mapped; +extern unsigned short io_base; +extern unsigned char io_mapped_lvds; +extern unsigned short io_base_lvds; +extern unsigned char io_mapped_sdvo; +extern unsigned short io_base_sdvo; +extern unsigned char io_mapped_lpc; +extern unsigned short io_base_lpc; + +#ifdef CDVO_WORKAROUND +igd_timing_info_t lnc_timings[] = +{ + { + 1024, 768, /* width, height */ + 60, 0, /* refresh, dot clock */ + 1344, /* htotal */ + 1024, 1344, /* hblank_start, hblank_end */ + 1048, 1184, /* hsync_start, hsync_end */ + 805, /* vtotal */ + 768, 805, /* vblank_start, vblank_end */ + 770, 772, /* vsync_start, vsync_end */ + 0x1C, /* mode number */ + IGD_MODE_VESA, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { + 1280, 1024, /* width, height */ + 85, 0, /* refresh, dot clock */ + 1476, /* htotal */ + 1024, 1476, /* hblank_start, hblank_end */ + 1295, 1439, /* hsync_start, hsync_end */ + 1065, /* vtotal */ + 1024, 1065, /* vblank_start, vblank_end */ + 1024, 1027, /* vsync_start, vsync_end */ + 0x1C, /* mode number */ + IGD_MODE_VESA, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { + 1920, 1080, /* width, height */ + 60, 0, /* refresh, dot clock */ + 2200, /* htotal */ + 1920, 2200, /* hblank_start, hblank_end */ + 2008, 2052, /* hsync_start, hsync_end */ + 1080, /* vtotal */ + 1090, 1080, /* vblank_start, vblank_end */ + 1084, 1088, /* vsync_start, vsync_end */ + 0x1C, /* mode number */ + IGD_MODE_VESA, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + + PD_TIMING_TABLE_END +}; + +igd_timing_info_t ovl_timings[] = +{ + { + 1024, 768, /* width, height */ + 60, 0, /* refresh, dot clock */ + 1344, /* htotal */ + 1024, 1344, /* hblank_start, hblank_end */ + 1048, 1184, /* hsync_start, hsync_end */ + 853, /* vtotal */ + 768, 853, /* vblank_start, vblank_end */ + 770, 772, /* vsync_start, vsync_end */ + 0x1C, /* mode number */ + IGD_MODE_VESA, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { + 1280, 1024, /* width, height */ + 85, 0, /* refresh, dot clock */ + 1476, /* htotal */ + 1024, 1476, /* hblank_start, hblank_end */ + 1295, 1439, /* hsync_start, hsync_end */ + 1267, /* vtotal */ + 1024, 1267, /* vblank_start, vblank_end */ + 1024, 1027, /* vsync_start, vsync_end */ + 0x1C, /* mode number */ + IGD_MODE_VESA, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { + 1920, 1080, /* width, height */ + 60, 0, /* refresh, dot clock */ + 2200, /* htotal */ + 1920, 2200, /* hblank_start, hblank_end */ + 2008, 2052, /* hsync_start, hsync_end */ + 1191, /* vtotal */ + 1024, 1191, /* vblank_start, vblank_end */ + 1084, 1088, /* vsync_start, vsync_end */ + 0x1C, /* mode number */ + IGD_MODE_VESA, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + + PD_TIMING_TABLE_END +}; + +int alt_timing_size = sizeof(lnc_timings)/sizeof(igd_timing_info_t); +/*! + * cDVO programming based on ITP script + * @return void + * + */ +int run_cheat_sheet = 1; + +void program_cdvo(void) +{ +#if 0 + /* These are original cheat sequence kept for backup purposes */ + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x6102c, 0xf); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x61); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x700c, 0x388b400); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7010, 0x02000200); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00000800); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00004800); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00000000); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x60); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00004000); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x61170, 0x20022160); + + + //programmable cdvo stall + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x6102c, 0xf); + + // High + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00004800); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x700c, 0x38cb4ff); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x61170, 0x20022160);//enable sdvo + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7010, 0x06000200);//pause; + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x700c, 0x0080000);//pause; + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x700c, 0x388b400);//pause; + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x700c, 0x388b4ff); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x61); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x60); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7010, 0x02000200);//gtl gtl + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00004000);//ODT + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x61170, 0x20022160);//enable sdvo + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7010, 0x02000200);//gtl gtl + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00000800); + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00004800); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00000000); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x60); + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00004000); + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x61170, 0x20022160); + + /* SV new workaround */ + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x700c, 0x8b400); +#endif + + //programmable cdvo stall + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x6102c, 0xf); + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x61); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x60); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x61); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x60); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x61); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x60); + + // High + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00004800); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x700c, 0x000BB4FF); //strobe data tuning default + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x61170, 0x20022160);//enable sdvo + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7010, 0x06000200);//pause; + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x700c, 0x00008000);//pause; + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x700c, 0x0008B400);//pause; + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x700c, 0x0008B4FF); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x61); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x60); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7010, 0x02000200);//gtl gtl + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00004000);//ODT + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x61170, 0x20022160);//enable sdvo + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7010, 0x02000200);//gtl gtl + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00000800); + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00004800); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00000000); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x60); + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7014, 0x00004000); + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x61170, 0x20022160); + + run_cheat_sheet = 0; +} + + +void tuning_probe(void) +{ + long tune = 0; + long temp_val1 = 0; + long temp_val2 = 0; + long bail_out = 0; + /* Tuning */ + for(tune=0; tune<16; tune++) + { + + temp_val1 = tune << 22; + temp_val2 = READ_MMIO_REG_TNC(IGD_PORT_SDVO,0x700c); + temp_val2 = temp_val2 & 0xF83FFFFF; + temp_val2 = temp_val1 | temp_val2; + //temp_val2 = temp_val2 | 0x04000000 //data tuning + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO,0x7000,0x61); + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO,0x700c,temp_val2); + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO,0x7010,0x02060200); //gtl gtl + //dword(MADR3+0x7010)p = 0x02000200 //cmos gtl + + //dword(MADR3+0x7014)p = 0x00004800 + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO,0x7014,0x00000800); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO,0x7014,0x00000000); // + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO,0x7014,0x00004000); //ODT + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO,0x7014,0x00004800); // rcomp + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO,0x7014,0x00000000); // + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO,0x7000,0x60); //enable cdvo + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO,0x7014,10); + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO,0x7014,0x00004000); //ODT + + //WRITE_MMIO_REG_TNC(IGD_PORT_SDVO,0x700c,) + + if(bail_out){ + break; + } + } +} + +#endif +/*! + * + * @param mmio dev2 mmio + * + * @return void + */ +static void disable_vga_tnc (unsigned char *mmio) +{ + unsigned long temp; + unsigned char sr01; + + OS_TRACE_ENTER; + + /* Disable VGA plane if it is enabled. */ + temp = OS_READ32(OS_MMIO(mmio) + VGACNTRL); + if ((temp & BIT31) == 0) { + /* Read SR01 */ + READ_VGA(mmio, SR_PORT, SR01, sr01); + + /* Turn on SR01 bit 5 */ + WRITE_VGA(mmio, SR_PORT, SR01, sr01|BIT(5)); + + /* Wait for 30us */ + OS_SLEEP(30); + + temp |= BIT31; /* set bit 31 to disable */ + temp &= ~BIT30; /* clear bit 30 to get VGA display in normal size */ + OS_WRITE32(temp, OS_MMIO(mmio) + VGACNTRL); + + } + + OS_TRACE_EXIT; +} + +/*! + * + * @param display_handle + * @param palette_entry + * @param palette_color + * + * @return 0 on success + * @return -IGD_INVAL on failure + */ +int igd_set_palette_entry_tnc( + igd_display_h display_handle, + unsigned long palette_entry, + unsigned long palette_color) +{ + /* Return if Pipe is not on */ + if(!((1L<<31) & READ_MMIO_REG_TNC(PORT_TYPE_DH(display_handle), + PIPE(display_handle)->pipe_reg))) { + return -IGD_INVAL; + } + /* Palette can is only on 0:2:0 so use _TNC IGD_PORT_LVDS */ + WRITE_MMIO_REG_TNC(IGD_PORT_LVDS, + PIPE(display_handle)->palette_reg + palette_entry * 4, + palette_color); + + return 0; +} + +/*! + * + * @param display_handle + * @param palette_entry + * @param palette_color + * + * @return 0 on success + * @return -IGD_INVAL on failure + */ +int igd_get_palette_entry_tnc( + igd_display_h display_handle, + unsigned long palette_entry, + unsigned long *palette_color) +{ + /* Return if Pipe is not on */ + if(!((1L<<31) & READ_MMIO_REG_TNC( + PORT_TYPE_DH(display_handle), + PIPE(display_handle)->pipe_reg))) { + return -IGD_INVAL; + } + /* Palette can is only on 0:2:0 so use _TNC IGD_PORT_LVDS */ + *palette_color = 0xffffff & READ_MMIO_REG_TNC( + IGD_PORT_LVDS, + PIPE(display_handle)->palette_reg + palette_entry * 4); + return 0; +} + +/*! + * + * @param mmio + * @param pipe_reg + * + * @return 0 on success + * @return 1 on failure + */ +int wait_for_vblank_tnc(unsigned long pipe_reg) +{ + unsigned long pipe_status_reg = pipe_reg + PIPE_STATUS_OFFSET; + unsigned long tmp; + unsigned long port_type = IGD_PORT_LVDS; + os_alarm_t timeout; + + OS_TRACE_ENTER; + + /* PIPE B means display using SDVO 0:3:0 device */ + if (pipe_reg == 0x71008) { + /* use SDVO mmio */ + port_type = IGD_PORT_SDVO; + } + OS_DEBUG("pipe_reg = %lx", pipe_reg); + + /* If pipe is off then just return */ + if(!((1L<<31) & READ_MMIO_REG_TNC(port_type, pipe_reg))) { + OS_DEBUG("Pipe disabled/Off"); + OS_TRACE_EXIT; + return 1; + } + + /* + * When VGA plane is on the normal wait for vblank won't work + * so just skip it. VGA plane is on 0:2:0 so no need to use _TNC macros. + */ + if(!(OS_READ32(MMIO_TNC(port_type) + 0x71400) & 0x80000000)) { + OS_DEBUG("VGA Plane On"); + OS_TRACE_EXIT; + return 1; + } + + /* 1. Disable VBlank interrupt */ + tmp = READ_MMIO_REG_TNC(port_type, pipe_status_reg); + WRITE_MMIO_REG_TNC(port_type, pipe_status_reg, tmp & ~VBLANK_STS_EN); + + /* 2. Clear VBlank interrupt status (by writing a 1) */ + tmp = READ_MMIO_REG_TNC(port_type, pipe_status_reg); + WRITE_MMIO_REG_TNC(port_type, pipe_status_reg, tmp | VBLANK_STS); + + /* 3. Enable VBlank interrupt */ + tmp = READ_MMIO_REG_TNC(port_type, pipe_status_reg); + WRITE_MMIO_REG_TNC(port_type, pipe_status_reg, tmp | VBLANK_STS_EN); + + /* 4. Wait for VBlank about 50 msec (20Hz). */ + timeout = OS_SET_ALARM(50); + do { + OS_SCHEDULE(); + tmp = READ_MMIO_REG_TNC(port_type, pipe_status_reg) & VBLANK_STS; + } while ((tmp == 0x00) && (!OS_TEST_ALARM(timeout))); /* Check for timeout */ + + if (tmp == 0) { + OS_ERROR_EXIT("Timeout waiting for VBLANK"); + return 0; + } + + OS_TRACE_EXIT; + return 1; +} /* wait_for_vblank_tnc */ + +/*! + * This procedure waits for the next vertical blanking (vertical retrace) + * period. If the display is already in a vertical blanking period, this + * procedure exits. + * + * Note: A timeout is included to prevent an endless loop. + * + * @param display_handle + * + * @return FALSE if timed out + */ +int igd_wait_vblank_tnc(igd_display_h display_handle) +{ + + return wait_for_vblank_tnc(PIPE(display_handle)->pipe_reg); + +} + +/*! + * Get the stride and stereo values based on the display. This is also used + * by the MI instructions. + * + * @param display Pointer to hardware device instance data + * @param flags Should the stereo be for the frontbuffer or backbuffer? + * + * @return stride - Stride of the display + * @return stereo - Stereo address of the display + */ +int mode_get_stride_stereo_tnc(igd_display_context_t *display, + unsigned long *stride, + unsigned long *stereo, + unsigned long flags) +{ + unsigned long pitch = PLANE(display)->fb_info->screen_pitch; + igd_timing_info_t *timing = PIPE(display)->timing; + unsigned long base_offset; + + OS_TRACE_ENTER; + + base_offset = PLANE(display)->fb_info->visible_offset; + *stride = pitch; + *stereo = 0; + + /* For field replication, valid for interlaced modes only + * set stereo = fb_base + * stride = pitch + */ + if (timing->mode_info_flags & IGD_SCAN_INTERLACE) { + + if(timing->mode_info_flags & IGD_LINE_DOUBLE) { + /* Interlaced + Line double flags means field replication. + * same lines are sent for both fields. Program the + * second eye to be same as the first + */ + *stereo = base_offset; + } else { + /* Regular interlaced. Second eye starts on line 2. + * Skip every other line. + */ + *stereo = base_offset + pitch; + *stride = pitch * 2; + } + } + + OS_TRACE_EXIT; + return 0; +} + +/* + * TNC LVDS display: Mode switch sequence + * + * 1. Enable sequence + * + * Program power on delay, power off delay, power cycle delay registers + * Program backlight control register to set appropriate backlight value + * Pipe A must be completely off at this point + * Write PIPEACONF bits[19:18] = 00 + * Write DSPACNTR bit[31] = 1 + * Write DSPASURF = 0x00000000 + * Write DSPACNTR bit[31] = 0 + * Write DSPASURF = 0x00000000 + * Restore PIPEACONF bits[19:18]  to original value + * Program DPLL + * Enable DPLL + * Wait for DPLL warm up 10us and check for DPLL lock bit in Pipe A config reg + * (Wait ensures clock is running smoothly before enabling pipe) + * Program pipe timings (Can be done before DPLL programming) + * Enable panel fitter as needed (Can be done before DPLL and/or + * pipe timing programming) + * Enable pipe + * Enable planes (VGA or HiRes) + * Enable ports + * Enable panel power (Can be done before DPLL programming) + * + * 2. Disable sequence + * + * Disable panel backlight + * Disable panel power (for AOAC standby) + * Disable ports + * Disable planes (VGA or hires) + * Disable pipe + * Disable VGA display in 0x71400 bit 31 + * (Disable VGA display done after disable pipe to allow pipe to turn off + * when no vblank is available in native VGA mode) + * Wait for pipe off status + * (Wait ensures planes and pipe have completely turned off prior to + * disabling panelfitter then DPLL) + * Disable panelfitter + * Disable DPLL + * Pipe timings change or change between VGA native or VGA center/upperleft + * or HiRes + * Use complete disable sequence followed by complete enable sequence with + * new mode programmings. + * + * + * TNC SDVO display: Display Pipe B Enable/Disable sequence: + * + * 1. Enable sequence + * + * Program LNC and LNW DPLL + * Write all planes, port, power control registers on both LNC and LNW + * 1st Enable LNC pipe + * 2nd Enable LNW pipe + * + * 2. Disable Sequence + * + * Disable panel power + * Disable ports + * Disable planes + * 1st Disable LNC pipe + * 2nd Disable TNC_SDVO pipe + * Disable panel fitter + * Disable DPLL + */ + +/*! + * + * @param display Pointer to hardware device instance data + * + * @return void + */ +void program_pipe_vga_tnc( + igd_display_context_t *display) +{ + igd_timing_info_t *timing; + unsigned long vga_control; + unsigned long upscale = 0; + int centering = 1; + + OS_TRACE_ENTER; + + /* + * VGA Plane can attach to only one pipe at a time. LVDS can + * only attach to pipe B. We need to use the display passed to + * determine the pipe number to use. (Napa is same as Alm). + */ + + /* + * We can come here with following cases: + * 1. magic->vga CRT, DVI type displays + * 2. native->vga int-lvds, and up-scaling lvds displays + * 3. pipe->vga TV and other unscaled-lvds displays + */ + vga_control = OS_READ32(MMIO(display) + 0x71400); + vga_control &= 0x18e3ff00; + vga_control |= 0x8e; + + timing = PIPE(display)->timing; + if(!timing->extn_ptr) { + OS_ERROR_EXIT("No Extension pointer in program_pipe_vga_tnc"); + return; + } + + /* Find UPSCALING attr value*/ + pi_pd_find_attr_and_value(PORT_OWNER(display), + PD_ATTR_ID_PANEL_FIT, + 0,/*no PD_FLAG for UPSCALING */ + NULL, /* dont need the attr ptr*/ + &upscale); + /* this PI func will not modify value of upscale if attr does not exist */ + + /* magic->vga || native->vga cases, centering isn't required */ + if ((timing->width == 720 && timing->height == 400) || upscale) { + centering = 0; + } + + /* Enable border */ + if((timing->width >= 800) && !upscale) { + OS_DEBUG("Enable VGA Border"); + vga_control |= (1L<<26); + } + + if(timing->width == 640) { + OS_DEBUG("Enable Nine Dot Disable"); + vga_control |= (1L<<18); + } + + if(centering) { + OS_DEBUG("Enable VGA Center Centering"); + vga_control |= 1L<<24; + + if(timing->height >= 960) { + if(timing->width >= 1280) { + OS_DEBUG("Enable VGA 2x (Nine Dot Disable)"); + vga_control |= (1L<<30) | (1L<<18); + } + } + } else { + if(PORT_OWNER(display)->port_type == IGD_PORT_LVDS) { + OS_DEBUG("Enable VGA Upper-Left Centering & Nine Dot Disable"); + vga_control |= (1L<<25 | (1L<<18)); + } else if (upscale) { + OS_DEBUG("Enable VGA Center Upper-left for upscale ports"); + vga_control |= 1L<<25; + } + } + + if(PIPE(display)->pipe_num) { + vga_control |= 1L<<29; + } + + program_pipe_vga(display, (igd_timing_info_t *)timing->extn_ptr); + OS_WRITE32(vga_control, MMIO(display) + 0x71400); + + OS_TRACE_EXIT; + return; +} + +/*! + * Program Display Plane Values. + * + * @param display Pointer to hardware device instance data + * @param status + * + * @return void + */ +void program_plane_tnc(igd_display_context_t *display, + unsigned long status) +{ + unsigned long stride; + unsigned long stereo; + unsigned long plane_control; + igd_timing_info_t *timing; + igd_framebuffer_info_t *fb_info = PLANE(display)->fb_info; + unsigned long plane_reg = PLANE(display)->plane_reg; + + OS_TRACE_ENTER; + + OS_DEBUG("Program Plane: %s", status?"ENABLE":"DISABLE"); + OS_DEBUG("Device power state: D%ld", GET_DEVICE_POWER_STATE(display)); + + igd_wait_vblank_tnc((igd_display_h)display); + + plane_control = OS_READ32(MMIO(display) + plane_reg); + if(PLANE(display)->plane_reg == DSPACNTR) { + plane_control &= device_data->plane_a_preserve; + } else { /* if it's plane b or plane c */ + plane_control &= device_data->plane_b_c_preserve; + } + + /* TODO: Bspec: For EagleLake this Trickle Feed must always disable */ + + if((status == FALSE) || + (GET_DEVICE_POWER_STATE(display) != IGD_POWERSTATE_D0)) { + + /* + * Note: The vga programming code does not have an "off". So + * when programming the plane to off we make sure VGA is off + * as well. + */ + disable_vga_tnc(MMIO(display)); + + /* + * To turn off plane A or B, the program have to triger the plane A or B + * start register. Or else, it will not work. + */ + OS_WRITE32(plane_control, MMIO(display) + plane_reg); + OS_WRITE32(OS_READ32(MMIO(display) + plane_reg + DSP_START_OFFSET), + MMIO(display) + plane_reg + DSP_START_OFFSET); + + igd_wait_vblank_tnc((igd_display_h)display); + OS_TRACE_EXIT; + return; + } + /* + * Note: The very first pass through this function will be with + * status false and timings == NULL. Don't use the timings before + * the check above. + */ + timing = PIPE(display)->timing; + /* There is a special case code for legacy VGA modes */ + while (timing->extn_ptr) { + timing = (igd_timing_info_t *)timing->extn_ptr; + } + if(MODE_IS_VGA(timing)) { + program_plane_vga(display, timing); + OS_TRACE_EXIT; + return; + } + + disable_vga_tnc(MMIO(display)); + + /* enable plane, select pipe, enable gamma correction logic */ + plane_control |= 0x80000000 | (PIPE(display)->pipe_num<<24); + PIPE(display)->plane = PLANE(display); +#ifndef CONFIG_MICRO + plane_control |= (1<<30); +#endif + + /* Here the settings: + * If line + pixel dbling, set 21,20 to 01b, and set Horz Multiply + * If line dbling only, set 21,20 to 11b + * If pixel dbling only, set 21,20 to 00b, but set Horz Multiply + * If no doubling, set 21,20 to 00b (no Horz Multiply) + * For pixel doubling + * --> both progressive/interlaced modes + * For Line doubling + * --> progressive modes only + */ + + if (!(timing->mode_info_flags & IGD_SCAN_INTERLACE)) { + /* Line doubling in progressive mode requires special bits */ + if (timing->mode_info_flags & IGD_LINE_DOUBLE) { + /* BIT 20 for line & pixel doubling*/ + plane_control |= BIT20; + /* check later, if no pixel doubling, set bit 21 too*/ + } + } + if (timing->mode_info_flags & IGD_PIXEL_DOUBLE) { + /* For line ONLY doubling, set bit 21 also '1' */ + plane_control |= BIT21; + } + + mode_get_stride_stereo_tnc(display, &stride, &stereo, 0); + + /* set color depth */ + switch (IGD_PF_DEPTH(fb_info->pixel_format)) { + case PF_DEPTH_8: + plane_control |= BIT27 | BIT30; + break; + case PF_DEPTH_16: + plane_control |= BIT28 | BIT26; + break; + default: + case PF_DEPTH_32: + plane_control |= BIT28 | BIT27; + break; + } + + if(fb_info->flags & IGD_ENABLE_DISPLAY_GAMMA) { + plane_control |= (BIT30); + } + + if(fb_info->flags & IGD_SURFACE_TILED) { + plane_control |= (BIT10); + } + + /* Set watermark for TNC */ +#ifndef CONFIG_MICRO + OS_WRITE32(device_data->dsp_arb, MMIO(display) + DSP_ARB); +/* OS_WRITE32(device_data->fifo_watermark1, MMIO(display) + FW_1); + OS_WRITE32(device_data->fifo_watermark2, MMIO(display) + FW_2); + OS_WRITE32(device_data->fifo_watermark3, MMIO(display) + FW_3); +*/ +#else + /* ITP Script is doing this and so go ahead */ + /* The DSP_ARB set fixed the issue with 32bit vesa modes */ + OS_WRITE32(0x00001FBF, MMIO(display) + DSP_ARB); + OS_WRITE32(0x3F8F0F18, MMIO(display) + FW_1); +#endif + /* FIXME: Not required for TNC. + * The B-Spec states that rendering will be slower if the fences are not + * a power of 2. So for now, always use a power of 2. */ + /* OS_WRITE32(0x04000400, MMIO(display) + 0x209c); */ + + OS_DEBUG(" Plane Control: 0x%lx", plane_control); + OS_DEBUG(" Plane Base: 0x%lx", fb_info->visible_offset); + OS_DEBUG(" Plane Pitch: 0x%lx", stride); + + OS_WRITE32(plane_control, MMIO(display) + plane_reg); + OS_WRITE32(stride, MMIO(display) + plane_reg + DSP_STRIDE_OFFSET); + /* Both of these registers are Reserved on Gen4 */ + /*OS_WRITE32(size, MMIO(display) + plane_reg + DSP_SIZE_OFFSET);*/ + /*OS_WRITE32(stereo, MMIO(display) + plane_reg + DSP_STEREO_OFFSET);*/ + OS_WRITE32(0, MMIO(display) + plane_reg + DSP_LINEAR_OFFSET); + OS_WRITE32(0, MMIO(display) + plane_reg + 0x24); + OS_WRITE32(fb_info->visible_offset, + MMIO(display) + plane_reg + DSP_START_OFFSET); + + igd_wait_vblank_tnc((igd_display_h)display); + + OS_TRACE_EXIT; +} + +/*! + * PGen4 can check when the pipe is enabled or disabled. + * This function waits for the pipe to be enabled or disabled. + * check_on_off = 0 to wait for the pipe to disable. + * check_on_off = 0x40000000 to wait for the pipe to enable. + * + * @param mmio + * @param pipe_reg + * @param check_on_off + * + * @return void + */ +static void wait_pipe(unsigned long pipe_reg, unsigned long check_on_off) +{ + unsigned long temp; + os_alarm_t timeout; + + OS_TRACE_ENTER; + + /* 0:3:0 doesn't wait pipe, only LNC device does. */ + if (pipe_reg == 0x71008) { + return; + } + + /* Wait for Pipe enable/disable, about 50 msec (20Hz). */ + timeout = OS_SET_ALARM(50); + do { + OS_SCHEDULE(); + temp = OS_READ32(MMIO_TNC(IGD_PORT_LVDS) + pipe_reg) & 0x40000000; + /* Check for timeout */ + } while ((temp != check_on_off) && (!OS_TEST_ALARM(timeout))); + + if (temp != check_on_off) { + OS_ERROR_EXIT("Timeout waiting for pipe enable/disable"); + } + + OS_TRACE_EXIT; + return; +} + +/*! + * This function programs the Timing registers and clock registers and + * other control registers for PIPE. + * + * @param display + * @param status + * + * @return void + */ +void program_pipe_tnc(igd_display_context_t *display, + unsigned long status) +{ + unsigned long timing_reg; + unsigned long pipe_conf; + unsigned long hactive, vactive; + igd_timing_info_t *pTimings; + igd_display_port_t *port; + unsigned long temp; + unsigned long pt = PORT_TYPE(display); + int i; +#ifdef CDVO_WORKAROUND + int j; +#endif + OS_TRACE_ENTER; + + OS_DEBUG("Program Pipe: %s", status?"ENABLE":"DISABLE"); + OS_DEBUG("Device power state: D%ld", GET_DEVICE_POWER_STATE(display)); + + pipe_conf = device_data->pipe_preserve & + READ_MMIO_REG_TNC(pt, PIPE(display)->pipe_reg); + + if((status == FALSE) || + (GET_DEVICE_POWER_STATE(display) == IGD_POWERSTATE_D3)) { + /* For SDVO disable both pipe Bs in 0:2:0 and 0:3:0 */ + if (pt == IGD_PORT_SDVO) { + WRITE_MMIO_REG_TNC(IGD_PORT_LVDS, PIPE(display)->pipe_reg, + pipe_conf & (~0x80000000L)); + } + /* Disable pipe */ + WRITE_MMIO_REG_TNC(pt, PIPE(display)->pipe_reg, + pipe_conf & (~0x80000000L)); + + /* check when the pipe is disabled. */ + wait_pipe(PIPE(display)->pipe_reg, 0); + + /* Disable DPLL */ + WRITE_MMIO_REG_TNC(pt, PIPE(display)->clock_reg->dpll_control, + READ_MMIO_REG_TNC(pt, + PIPE(display)->clock_reg->dpll_control) & ~0x80000000L); + + OS_TRACE_EXIT; + return; + } + +#ifdef CDVO_WORKAROUND + if(run_cheat_sheet && pt == IGD_PORT_SDVO){ + /* Disable pipe */ + WRITE_MMIO_REG_TNC(pt, PIPE(display)->pipe_reg, + pipe_conf & (~0x80000000L)); + + /* check when the pipe is disabled. */ + wait_pipe(PIPE(display)->pipe_reg, 0); + + /* Disable DPLL */ + WRITE_MMIO_REG_TNC(pt, PIPE(display)->clock_reg->dpll_control, + READ_MMIO_REG_TNC(pt, + PIPE(display)->clock_reg->dpll_control) & ~0x80000000L); + + program_cdvo(); + } +#endif + port = PORT_OWNER(display); + pTimings = PIPE(display)->timing; + + { + /* Debug messages */ + pd_timing_t *vga_timing = (pd_timing_t *)pTimings->extn_ptr; + OS_DEBUG("pTimings %ux%u mode_number = %u mode_info_flags = 0x%lx", + pTimings->width, + pTimings->height, + pTimings->mode_number, + pTimings->mode_info_flags); + if (vga_timing) { + OS_DEBUG("ext_timing %ux%u mode_number = %u mode_info_flags= 0x%lx", + vga_timing->width, + vga_timing->height, + vga_timing->mode_number, + vga_timing->mode_info_flags); + } + } + + /* + * If the mode is VGA and the PD says it handles all VGA modes without + * reprogramming then just set the mode and leave centering off. + */ + if(pTimings->mode_info_flags & IGD_MODE_VESA) { + if (pTimings->mode_number <= VGA_MODE_NUM_MAX) { + /* Pipe timings and clocks no longer need to be set since + * the VGA timings will be used. + WRITE_MMIO_REG_TNC(pt, PIPE(display)->pipe_reg, + pipe_conf | 0x80000000); */ + + /* Gen4 can check when the pipe is enabled. No longer needed + * since pipe not enabled and VGA timings are used. + wait_pipe(PIPE(display)->pipe_reg, 0x40000000);*/ + + program_pipe_vga_tnc(display); + OS_TRACE_EXIT; + return; + } else { +#ifdef CONFIG_MICRO + set_256_palette( + MMIO_TNC(PORT(display, display->port_number)->port_type)); +#endif + } + } + + /* Program dot clock divisors. */ + program_clock_tnc(display, PIPE(display)->clock_reg, pTimings->dclk); + + /* Program timing registers for the pipe */ + timing_reg = PIPE(display)->timing_reg; + if (pTimings->mode_info_flags & IGD_PIXEL_DOUBLE) { + hactive = (unsigned long)pTimings->width*2 - 1; + } else { + hactive = (unsigned long)pTimings->width - 1; + } + + if (pTimings->mode_info_flags & IGD_LINE_DOUBLE) { + vactive = (unsigned long)pTimings->height*2 - 1; + } else { + /* For tnc Hardware will automatically divide by 2 to + get the number of line in each field */ + vactive = (unsigned long)pTimings->height - 1; + } + +#ifndef CONFIG_MICRO + /* reset the palette */ + for (i = 0; i < 256; i++) { + WRITE_MMIO_REG_TNC(IGD_PORT_LVDS, PIPE(display)->palette_reg, + ((i<<16) | (i<<8) | i)); + } + + + /* apply color correction */ + for( i = 0; PD_ATTR_LIST_END != port->attributes[i].id; i++ ) { + + if ((PD_ATTR_ID_FB_GAMMA == (port->attributes[i].id)) || + (PD_ATTR_ID_FB_BRIGHTNESS == (port->attributes[i].id)) || + (PD_ATTR_ID_FB_BRIGHTNESS == (port->attributes[i].id))) { + + mode_context->dispatch->full->set_color_correct(display); + } + } +#endif + + /* + * NOTE: For size reasons the timng table contains unsigned short + * values. Don't shift them past 16. Use a temp instead. + * All register offsets and bit shift are verified for Gen4 + * + * For SDVO display: + * Write values into pipe B registers in both 0:2:0 and 0:3:0 + */ + for (i=0; i<2; i++) { + temp = ((unsigned long)pTimings->htotal << 16) | hactive; + WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg, temp); + + temp = ((unsigned long)pTimings->hblank_end << 16) | + (unsigned long)pTimings->hblank_start; + WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x04, temp); + + temp = ((unsigned long)pTimings->hsync_end << 16) | + (unsigned long)pTimings->hsync_start; + WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x08, temp); + + temp = ((unsigned long)pTimings->vtotal << 16) | vactive; + WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x0C, temp); + + temp = ((unsigned long)pTimings->vblank_end << 16) | + (unsigned long)pTimings->vblank_start; + WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x10, temp); + + temp = ((unsigned long)pTimings->vsync_end << 16) | + (unsigned long)pTimings->vsync_start; + WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x14, temp); + + /* + * If there is a linked mode it is either the VGA or a scaled + * mode. If it is scaled then we need to use it as the source size. + */ + if(pTimings->extn_ptr) { + igd_timing_info_t *scaled_timings = + (igd_timing_info_t *)pTimings->extn_ptr; + if((scaled_timings->mode_info_flags & IGD_MODE_VESA) && + (scaled_timings->mode_number <= VGA_MODE_NUM_MAX)) { + temp = (hactive << 16) | vactive; + } else { + temp = (unsigned long)scaled_timings->width - 1; + temp = (temp << 16) | + (unsigned long)(scaled_timings->height - 1); + } + } else { + temp = (hactive << 16) | vactive; + } + WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x1C, temp); + + /* Enable pipe */ + pipe_conf |= PIPE_ENABLE; + + /* Put pipe in interlaced mode if requested: + * should only happen for LVDS display if at all. */ + if (pTimings->mode_info_flags & IGD_SCAN_INTERLACE) { + pipe_conf |= (INTERLACE_EN); + } else { + pipe_conf &= ~(INTERLACE_EN); + } + + WRITE_MMIO_REG_TNC(ports_tnc[i], PIPE(display)->pipe_reg, pipe_conf); + + /* For LVDS port, don't touch dev3 registers stop after 1st iteration */ + if (pt == IGD_PORT_LVDS) { + break; + } + } +#ifdef CDVO_WORKAROUND + for(j=0; jwidth == lnc_timings[j].width && + pTimings->height == lnc_timings[j].height && + pTimings->refresh == lnc_timings[j].refresh && + pt == IGD_PORT_SDVO){ + + for(i=0; i<2; i++) { + igd_timing_info_t *tmpTimings; + if(i == 0){ + tmpTimings = &lnc_timings[j]; + }else{ + tmpTimings = &ovl_timings[j]; + } + + temp = ((unsigned long)tmpTimings->htotal << 16) | hactive; + WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg, temp); + + temp = ((unsigned long)tmpTimings->hblank_end << 16) | + (unsigned long)tmpTimings->hblank_start; + WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x04, temp); + + temp = ((unsigned long)tmpTimings->hsync_end << 16) | + (unsigned long)tmpTimings->hsync_start; + WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x08, temp); + + temp = ((unsigned long)tmpTimings->vtotal << 16) | vactive; + WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x0C, temp); + + temp = ((unsigned long)tmpTimings->vblank_end << 16) | + (unsigned long)tmpTimings->vblank_start; + WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x10, temp); + + temp = ((unsigned long)tmpTimings->vsync_end << 16) | + (unsigned long)tmpTimings->vsync_start; + WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x14, temp); + + temp = (hactive << 16) | vactive; + + WRITE_MMIO_REG_TNC(ports_tnc[i], timing_reg + 0x1C, temp); + + /* Enable pipe */ + pipe_conf |= PIPE_ENABLE; + + WRITE_MMIO_REG_TNC(ports_tnc[i], PIPE(display)->pipe_reg, pipe_conf); + } + break; + } + } +#endif + /* Gen4 can check when the pipe is enabled. */ + wait_pipe(PIPE(display)->pipe_reg, 0x40000000); + + /* + * Set the VGA address range to 0xa0000 so that a normal (not VGA) + * mode can be accessed through 0xa0000 in a 16bit world. + */ + WRITE_AR(MMIO(display), 0x10, 0xb); + WRITE_VGA(MMIO(display), GR_PORT, 0x06, 0x5); + WRITE_VGA(MMIO(display), GR_PORT, 0x10, 0x1); + + if(pTimings->extn_ptr) { + /* This means either internal scaling (LVDS) or centered VGA */ + pTimings = pTimings->extn_ptr; + if(pTimings->extn_ptr) { + /* This is both the scaled and centered VGA */ + pTimings = pTimings->extn_ptr; + } + if (pTimings->mode_info_flags & IGD_MODE_VESA) { + if (pTimings->mode_number <= VGA_MODE_NUM_MAX) { + program_pipe_vga_tnc(display); + } else { +#ifdef CONFIG_MICRO + /* + * FIXME: This is not appropriate. This assumes that + * CONFIG_MICRO means "This is vBIOS" and programs + * the palette. vBIOS IAL should probably just set the + * palette itself?? + */ + set_256_palette( + MMIO_TNC(PORT(display, display->port_number)->port_type)); +#endif + } + } + } +#ifdef CDVO_WORKAROUND + if (pt == IGD_PORT_SDVO) { + /* Reset the cDVO once we programmed the pipe */ + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x61); + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x7000, 0x60); + } +#endif + OS_TRACE_EXIT; + return; +} + +/*! + * + * @param context + * + * @return void + */ +void reset_plane_pipe_ports_tnc(igd_context_t *context) +{ + igd_plane_t *plane; + igd_display_pipe_t *pipe; + igd_display_port_t *port,*tv_port=NULL; + unsigned long temp; + unsigned long i, j; + unsigned char *mmio; + inter_module_dispatch_t *md; + + OS_TRACE_ENTER; + + /* + * Disable all plane, pipe and port registers because the + * bios may have been using a different set. Only unset the + * enable bit. + */ + mmio = OS_MMIO(context->device_context.virt_mmadr); + md = &context->mod_dispatch; + + /* Turn off LVDS and SDVO ports */ + port = NULL; + while((port = md->dsp_get_next_port(context, port, 0)) != NULL) { + /* if the port is TV, then don't set the power to S3 as this causes + * blank screen on analog port after killx or cosole mode, + * probably because the external clock needs to be on till the pipes and + * DPLLs are off + */ + if (port->pd_driver) { + if(port->pd_type == PD_DISPLAY_TVOUT) { + tv_port = port; + }else { + port->pd_driver->set_power(port->pd_context, IGD_POWERSTATE_D3); + } + } + + /* Disable WRITE protection on PIPE B for parts with Int-LVDS*/ + /* This should never happen as the panel power was set to D3 above */ + if (port->port_reg == LVDSCNTR) { + if(OS_READ32(OS_MMIO(mmio) + LVDS_PNL_PWR_CTL) & 0x1) { + OS_WRITE32(0xABCD0000, OS_MMIO(mmio) + LVDS_PNL_PWR_CTL); + i=0; + while(i++ < 0x10) { + OS_SLEEP(10); + if((OS_READ32(OS_MMIO(mmio)+LVDS_PNL_PWR_STS)&BIT(31))==0) { + break; + } + } + } + } + if (port->pd_driver) { + temp = READ_MMIO_REG_TNC(port->port_type, port->port_reg); + WRITE_MMIO_REG_TNC(port->port_type, port->port_reg, (temp & ~BIT31)); + } + } + + /* + * Gen4 appears to require that plane B be shut off prior to + * shutting off plane A. The normal get_next_plane returns them + * in order. We need to read the list backwards. + */ + plane = NULL; + while ((plane = md->dsp_get_next_plane(context, plane, 1)) != NULL) { + /* This section only deals with display planes. + * Leave cursor, VGA, overlay, sprite planes alone since they will + * need a different disable bit/sequence. + */ + temp = OS_READ32(OS_MMIO(mmio) + plane->plane_reg); + if ((plane->plane_features & IGD_PLANE_DISPLAY)) { + i = 0x71008; /* PIPE B */ + if (temp & BIT31) { + if(plane->plane_reg == DSPACNTR) { + temp = temp & device_data->plane_a_preserve; + i = 0x70008; /* use i as pipe_reg */ + } + OS_WRITE32((temp & ~BIT31), OS_MMIO(mmio) + plane->plane_reg); + + /* The B-Spec is ambiguous on which register is the trigger. + * Testing has shown the the surface start address is the + * correct trigger to disable the plane. + */ + OS_WRITE32(0, OS_MMIO(mmio)+plane->plane_reg+DSP_START_OFFSET); + + /* Wait for VBLANK to ensure that the plane is really off */ + wait_for_vblank_tnc(i); + + OS_DEBUG("Plane disabled 0x%lx", plane->plane_reg); + } + } else if ((plane->plane_features & IGD_PLANE_CURSOR)) { + OS_WRITE32((temp & 0xffffffe8), + OS_MMIO(mmio) + plane->plane_reg); + OS_WRITE32(0, OS_MMIO(mmio) + plane->plane_reg+4); + } + + } + + /* Turn off pipes */ + pipe = NULL; + while ((pipe = md->dsp_get_next_pipe(context, pipe, 0)) != NULL) { + j = 0; + + /* Is this really required? Just waited for vblank above 2 times */ + wait_for_vblank_tnc(pipe->pipe_reg); + + for (i = 0; i < 2; i++) { + temp = READ_MMIO_REG_TNC(ports_tnc[i], pipe->pipe_reg); + + if (temp & BIT31) { + /* Do not turn off Pipe B when shutting down */ + if((context->device_context.power_state + == IGD_POWERSTATE_UNDEFINED) && + (pipe->pipe_reg == PIPEB_CONF)){ + continue; + } + WRITE_MMIO_REG_TNC(ports_tnc[i], pipe->pipe_reg, + (temp & device_data->pipe_preserve)); + + /* Gen4 can check when the pipe is disabled. */ + wait_pipe(pipe->pipe_reg, 0); + + /* Disable VGA display */ + disable_vga_tnc(OS_MMIO(mmio)); + + } + + /* If current pipe is for sDVO, then iterate for PIPE B in + * both 0:2:0 LNC and 0:3:0 TNC devices */ + if (pipe->pipe_reg == 0x70008L) { + break; + } + } + /* Disable DPLL: + * LVDS: LNC 0xF014 + * SDVO: TNC 0x6018 */ + temp = READ_MMIO_REG_TNC(ports_tnc[j], pipe->clock_reg->dpll_control); + + if (temp & BIT31) { + WRITE_MMIO_REG_TNC(ports_tnc[j], pipe->clock_reg->dpll_control, + temp & ~BIT31); + } + j++; + } + /* pipes and DPLLs are off, now set the power for TV */ + if(tv_port && tv_port->pd_driver) { + tv_port->pd_driver->set_power(tv_port->pd_context, IGD_POWERSTATE_D3); + } + + OS_TRACE_EXIT; +} /* end reset_plane_pipe_ports */ + +/*! + * Status is currently not used + * + * @param display + * @param port_number + * @param status + * + * @return 0 on success + * @return 1 on failure + */ +int post_program_port_tnc(igd_display_context_t *display, + unsigned short port_number, + unsigned long status) +{ + int ret; + igd_display_port_t *port; + igd_timing_info_t *timings; + unsigned long portreg; +#ifdef CDVO_WORKAROUND + unsigned long pt = PORT_TYPE(display); +#endif + OS_TRACE_ENTER; + + port = PORT(display, port_number); + timings = PIPE(display)->timing; + + /* + * The programming found in the common code for all chipsets + * has the device programming sequence as follows: + * Port + * Pipe + * Post Port + * Plane + * On Gen4, if the port is enabled before the pipe, there is a 10% + * chance that the port will not turn on properly. + * Due to compatability requires with other chipsets, this workaround + * fixes this issue + */ + portreg = READ_MMIO_REG_TNC(port->port_type, port->port_reg); + WRITE_MMIO_REG_TNC(port->port_type, port->port_reg, portreg & ~BIT31); + WRITE_MMIO_REG_TNC(port->port_type, port->port_reg, portreg); + + ret = 0; + /* call post_set_mode() if exists */ + if (port->pd_driver->post_set_mode) { + ret = port->pd_driver->post_set_mode(port->pd_context, timings, + 1<pipe_num); + if (ret) { + OS_ERROR_EXIT("PD post_set_mode returned: 0x%x", ret); + } + } +#ifdef CDVO_WORKAROUND + if (pt == IGD_PORT_SDVO) { + /* CDVO Tuning, for experimental purposes only + */ + //tuning_probe(); + } +#endif + OS_TRACE_EXIT; + return ret; +} + +/*! + * + * @param display + * @param port_number + * @param status + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ +int program_port_sdvo_tnc(igd_display_context_t *display, + unsigned short port_number, + unsigned long status) +{ + unsigned long port_control; + unsigned long pd_powerstate = PD_POWER_MODE_D3; + unsigned long preserve = 0; + unsigned long upscale = 0; + igd_timing_info_t local_timing; + igd_timing_info_t *timing; + unsigned long temp; + int ret; + + OS_TRACE_ENTER; + + OS_DEBUG("Program Port: (%s)", status?"ENABLE":"DISABLE"); + OS_DEBUG("pd_flags: 0x%lx", PORT(display, port_number)->pd_flags); + + timing = PIPE(display)->timing; + + port_control = preserve & READ_MMIO_REG_TNC(IGD_PORT_SDVO, + PORT(display, port_number)->port_reg); + + if (status == TRUE) { + if (!(PORT(display, port_number)->pt_info->flags & + IGD_DISPLAY_ENABLE)) { + OS_TRACE_EXIT; + return 0; + } + + /* Enable VGA syncs for native vga modes */ + if (PORT(display, port_number)->vga_sync == 1) { + OS_DEBUG("VGA sync true, is width x height 720 x 400?"); + if((timing->width == 720) && (timing->height == 400)) { + OS_DEBUG("Modify port control and multi_port_control"); + port_control |= (1L<<15); + } + } + + /* Fact that both IGD_ powerstates and PD_ powermodes have + * same definitions */ + pd_powerstate = GET_DISPLAY_POWER_STATE(display, port_number); + + if (pd_powerstate == IGD_POWERSTATE_D0) { + OS_DEBUG("Power State: D0"); + /* Upscale */ + pi_pd_find_attr_and_value(PORT(display, port_number), + PD_ATTR_ID_PANEL_FIT, + 0, /*no PD_FLAG for UPSCALING */ + NULL, /* dont need the attr ptr*/ + &upscale); + + /* Reach the end timing if upscaling is enabled */ + if (timing->extn_ptr && upscale) { + timing = (pd_timing_t *)timing->extn_ptr; + } + + local_timing = *timing; + if (upscale) { + /* For timings smaller than width 360 and height 200, + * double the size. This is because the active area of the mode + * is double the size of the resolution for these modes + * - Very tricky huh */ + if (local_timing.width <= 360) { + local_timing.width <<= 1; + } + if (local_timing.height <= 200) { + local_timing.height <<= 1; + } + } + + /* BIT31 - Enable + * BIT30 - PIPE B + * BIT29 - Stall + * BIT7 - Border + */ + port_control |= BIT31|BIT30|BIT29|BIT7; + + /* Program cDVO registers: + * Keep default values for + * 7000h - cDVO control register + * 7004h - cDVO slew rate register + * 7008h - cDVO strength register + * 700Ch - cDVO RCOMP update register + * 6102Ch - cDVO stall register = 0xA. + * Note: Though EAS says 6102Ch default value is 6, it is a typo + * in the spec, based on Si DE hw default value is 10 (0xA), + * so no need to program explicitly. This saves few bytes for + * micro. + */ + + /* Enable Current Source */ + temp = READ_MMIO_REG_TNC(IGD_PORT_SDVO, 0x61170); + temp |= 0x2000; + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, 0x61170, temp); + } + } + + if (pd_powerstate == PD_POWER_MODE_D0) { + ret = PORT(display, port_number)->pd_driver->set_mode( + PORT(display, port_number)->pd_context, &local_timing, 0); + } else { + ret = PORT(display, port_number)->pd_driver->set_power( + PORT(display, port_number)->pd_context, pd_powerstate); + } + + if (ret) { + OS_ERROR_EXIT("PD set_%s returned: 0x%x", + (pd_powerstate == PD_POWER_MODE_D0)?"mode":"power", ret); + return -IGD_ERROR_INVAL; + } + + OS_DEBUG("Port_control: 0x%lx", port_control); + + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, + PORT(display, port_number)->port_reg, port_control); + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param display + * @param port_number + * @param status + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ +int program_port_lvds_tnc(igd_display_context_t *display, + unsigned short port_number, + unsigned long status) +{ + int ret = 0; + unsigned long powerstate = PD_POWER_MODE_D3; + pd_timing_t *timing; + + OS_TRACE_ENTER; + + OS_DEBUG("Program LVDS: (%s)", status?"ENABLE":"DISABLE"); + + if (status == TRUE) { + if(!(PORT(display, port_number)->pt_info->flags & IGD_DISPLAY_ENABLE)) { + OS_TRACE_EXIT; + return 0; + } + + powerstate = GET_DISPLAY_POWER_STATE(display,port_number); + if (powerstate == IGD_POWERSTATE_D0) { + OS_DEBUG("Power State: D0"); + timing = (pd_timing_t *)PIPE(display)->timing; + /* Reach end timing to get user resolution and pass it to pd */ + if(timing->extn_ptr) { + timing = (pd_timing_t *)timing->extn_ptr; + } + /* set mode will take care of port control */ + ret = PORT(display, port_number)->pd_driver->set_mode( + PORT(display, port_number)->pd_context, + timing, + 1<pipe_num); + } + } + + /* either status == FALSE, or status == TRUE, but powerstate is D1/D2/D3 */ + if (powerstate != IGD_POWERSTATE_D0) { + ret = PORT(display, port_number)->pd_driver->set_power( + PORT(display, port_number)->pd_context, + PD_POWER_MODE_D3); + } + + if (ret) { + OS_ERROR_EXIT("PD set_%s returned: 0x%x", + (powerstate == IGD_POWERSTATE_D0)?"mode":"power", ret); + return -IGD_ERROR_INVAL; + } + + OS_TRACE_EXIT; + return ret; +} + + +/*! + * + * @param display + * @param port_number + * @param status + * + * @return program_port_lvds_gen4() + * @return program_port_sdvo_gen4() + * @return -IGD_ERROR_INVAL on failure + */ +int program_port_tnc(igd_display_context_t *display, + unsigned short port_number, + unsigned long status) +{ + OS_TRACE_ENTER; + + if (PORT(display, port_number)->port_type == IGD_PORT_LVDS) { + OS_TRACE_EXIT; + return program_port_lvds_tnc(display, port_number, status); + } else { + OS_TRACE_EXIT; + return program_port_sdvo_tnc(display, port_number, status); + } +} + +/*! + * + * @param gpio + * + * @return size + */ +unsigned long get_gpio_sets_tnc(unsigned long **gpio) +{ + /* To small to trace */ + return 0; +} + +/*! + * + * @param context + * @param in_list + * + * @return void - To small to trace + */ +void filter_modes_tnc(igd_context_t *context, igd_display_port_t *port, + pd_timing_t *in_list) +{ + while (in_list->width != IGD_TIMING_TABLE_END) { + /* TC LVDS: + * supports from 19.75MHz to 79.MHz + * TC SDVO: + * supports from 25 MHz to 160 MHz and progressive only. + */ + if (port->port_type == IGD_PORT_SDVO) { + if (in_list->mode_info_flags & IGD_SCAN_INTERLACE || + in_list->dclk < 25000 || in_list->dclk > 160000) { + in_list->mode_info_flags &= ~IGD_MODE_SUPPORTED; + } + } + if (port->port_type == IGD_PORT_LVDS) { + if (in_list->dclk < 19750 || in_list->dclk > 79500) { + in_list->mode_info_flags &= ~IGD_MODE_SUPPORTED; + } + } + in_list++; + if (in_list->width == IGD_TIMING_TABLE_END && in_list->extn_ptr) { + in_list = in_list->extn_ptr; + } + } + return; +} + +mode_dispatch_t mode_dispatch_tnc = { + igd_set_palette_entry_tnc, + igd_get_palette_entry_tnc, + igd_wait_vblank_tnc, + program_plane_tnc, + program_pipe_tnc, + program_port_tnc, + post_program_port_tnc, + program_clock_tnc, + reset_plane_pipe_ports_tnc, + get_gpio_sets_tnc, + filter_modes_tnc, + OPT_MICRO_VALUE(&mode_full_dispatch_tnc, NULL) +}; + + +unsigned char *get_mmio_tnc(unsigned long port_type) +{ + unsigned char *virt_mmio; + if (port_type == IGD_PORT_LVDS) { + virt_mmio = mode_context->context->device_context.virt_mmadr; + } else if (port_type == IGD_PORT_SDVO) { + virt_mmio = mode_context->context->device_context.virt_mmadr_sdvo; + } else { + /* i2c_bitbash will use the else condition by passing in port_type + * as '0' */ + virt_mmio = mode_context->context->device_context.virt_gpio_bar; + } + return virt_mmio; +} + +/* Function to read Tunnel Creek 0:2:0, 0:3:0 and 0:31:0 mmio registers */ +unsigned long read_mmio_reg_tnc(unsigned long port_type, unsigned long reg) +{ + unsigned long value; + unsigned char *mmio; + /* to avoid updating or having another set of read/write macros for + * vbios, overwrite io_base to properly read from 0:2:0/0:3:0/0:31:0 + * io_base and set it back after reading */ + if (port_type == IGD_PORT_LVDS) { + io_base = io_base_lvds; + } else if (port_type == IGD_PORT_SDVO) { + io_base = io_base_sdvo; + } else if (port_type == IGD_PORT_LPC) { + io_base = io_base_lpc; + } + mmio = get_mmio_tnc(port_type); + if (port_type == IGD_PORT_LPC) { + value = OS_READ_PORT32(io_base_lpc + reg); + } else { + value = OS_READ32(OS_MMIO(mmio) + reg); + } + + io_base = io_base_lvds; + return value; +} + +/* Function to write Tunnel Creek 0:2:0 and 0:3:0 mmio registers */ +void write_mmio_reg_tnc(unsigned long port_type, unsigned long reg, + unsigned long value) +{ + unsigned char *mmio; + + /* to avoid updating or having another set of read/write macros for + * vbios, overwrite io_base to properly read from 0:2:0/0:3:0 io_base + * and set it back after writing */ + if (port_type == IGD_PORT_LVDS) { + io_base = io_base_lvds; + } else if (port_type == IGD_PORT_SDVO) { + io_base = io_base_sdvo; + } else if (port_type == IGD_PORT_LPC) { + io_base = io_base_lpc; + } + mmio = get_mmio_tnc(port_type); + if (port_type == IGD_PORT_LPC) { + OS_WRITE_PORT32(io_base_lpc + reg, value); + } else { + OS_WRITE32(value, OS_MMIO(mmio) + reg); + } + io_base = io_base_lvds; + return; +} + +#endif diff --git a/drivers/gpu/drm/emgd/emgd/display/mode/tnc/mode_tnc.c b/drivers/gpu/drm/emgd/emgd/display/mode/tnc/mode_tnc.c new file mode 100644 index 0000000..fdaa86c --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/mode/tnc/mode_tnc.c @@ -0,0 +1,1479 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: mode_tnc.c + * $Revision: 1.18 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * Tunnel Creek implementations for the mode dispatch functions. + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.mode + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../cmn/match.h" +#include "../cmn/mode_dispatch.h" + +int set_flip_pending_tnc(unsigned char *mmio, unsigned long pipe_status_reg); +int check_flip_pending_tnc(unsigned char *mmio, unsigned long pipe_status_reg); + +/*! + * @addtogroup display_group + * @{ + */ + +int mode_get_stride_stereo_tnc(igd_display_context_t *display, + unsigned long *stride, unsigned long *stereo, unsigned long flags); + +/*! + * + * @param display + * + * @return 0 on success + * @return -IGD_ERROR_INVAL if color attributes not found + */ +static int set_color_correct_tnc(igd_display_context_t *display) +{ + const int MID_PIXEL_VAL = 125; + const int MAX_PIXEL_VAL = 255; + const int NUM_PALETTE_ENTRIES = 256; + + unsigned int gamma_r_max_24i_8f, gamma_r_min_24i_8f; + unsigned int gamma_g_max_24i_8f, gamma_g_min_24i_8f; + unsigned int gamma_b_max_24i_8f, gamma_b_min_24i_8f; + unsigned int new_gamma_r_24i_8f, new_gamma_g_24i_8f; + unsigned int new_gamma_b_24i_8f; + unsigned int gamma_normal_r_24i_8f, gamma_normal_g_24i_8f; + unsigned int gamma_normal_b_24i_8f; + int brightness_factor_r, brightness_factor_g; + int brightness_factor_b; + int contrast_factor_r, contrast_factor_g; + int contrast_factor_b; + + unsigned int *palette; + unsigned int i; + + igd_range_attr_t *gamma_attr = NULL, *contrast_attr = NULL; + igd_range_attr_t *brightness_attr = NULL; + igd_attr_t *hal_attr_list = PORT_OWNER(display)->attributes; + + OS_TRACE_ENTER; + + /* Using OS_ALLOC to avoid using > 1024 on stack (frame size warning ) */ + palette = OS_ALLOC(sizeof (unsigned int) * NUM_PALETTE_ENTRIES); + + /* start with a fresh palette */ + for (i = 0; i < NUM_PALETTE_ENTRIES; i++) { + palette[i] = (i << 16) | (i << 8) | i; + } + + /* get a pointer to gamma, contrast, and brightness attr */ + i = 0; + + while (PD_ATTR_LIST_END != hal_attr_list[i].id) { + switch (hal_attr_list[i].id) { + case PD_ATTR_ID_FB_GAMMA: + gamma_attr = (igd_range_attr_t *) &hal_attr_list[i]; + break; + + case PD_ATTR_ID_FB_BRIGHTNESS: + brightness_attr = (igd_range_attr_t *) &hal_attr_list[i]; + break; + + case PD_ATTR_ID_FB_CONTRAST: + contrast_attr = (igd_range_attr_t *) &hal_attr_list[i]; + break; + + default: + break; + } + + i++; + } + + if(!gamma_attr || !brightness_attr || !contrast_attr) { + OS_ERROR_EXIT("Color Correction Atrributes not found!"); + return -IGD_ERROR_INVAL; + } + + /* Get the max and min */ + gamma_r_max_24i_8f = ((gamma_attr->max >> 16) & 0xFF) << 3; + gamma_g_max_24i_8f = ((gamma_attr->max >> 8) & 0xFF) << 3; + gamma_b_max_24i_8f = (gamma_attr->max & 0xFF) << 3; + + gamma_r_min_24i_8f = ((gamma_attr->min >> 16) & 0xFF) << 3; + gamma_g_min_24i_8f = ((gamma_attr->min >> 8) & 0xFF) << 3; + gamma_b_min_24i_8f = (gamma_attr->min & 0xFF) << 3; + + /* The new gamma values are in 3i.5f format, but we must convert it + * to 24i.8f format before passing it to OS_POW_FIX + */ + new_gamma_r_24i_8f = ((gamma_attr->current_value >> 16) & 0xFF) << 3; + new_gamma_g_24i_8f = ((gamma_attr->current_value >> 8) & 0xFF) << 3; + new_gamma_b_24i_8f = (gamma_attr->current_value & 0xFF) << 3; + + /* make sure the new gamma is within range */ + new_gamma_r_24i_8f = OS_MIN(gamma_r_max_24i_8f, new_gamma_r_24i_8f); + new_gamma_r_24i_8f = OS_MAX(gamma_r_min_24i_8f, new_gamma_r_24i_8f); + new_gamma_g_24i_8f = OS_MIN(gamma_g_max_24i_8f, new_gamma_g_24i_8f); + new_gamma_g_24i_8f = OS_MAX(gamma_g_min_24i_8f, new_gamma_g_24i_8f); + new_gamma_b_24i_8f = OS_MIN(gamma_b_max_24i_8f, new_gamma_b_24i_8f); + new_gamma_b_24i_8f = OS_MAX(gamma_b_min_24i_8f, new_gamma_b_24i_8f); + + + gamma_normal_r_24i_8f = + OS_POW_FIX(MAX_PIXEL_VAL, (1<<16)/new_gamma_r_24i_8f); + + gamma_normal_g_24i_8f = + OS_POW_FIX(MAX_PIXEL_VAL, (1<<16)/new_gamma_g_24i_8f); + + gamma_normal_b_24i_8f = + OS_POW_FIX(MAX_PIXEL_VAL, (1<<16)/new_gamma_b_24i_8f); + + for( i = 0; i < NUM_PALETTE_ENTRIES; i++ ) { + unsigned int new_gamma; + unsigned int cur_color; + unsigned int cur_palette = palette[i]; + + /* Note that we do not try to calculate the gamma if it + * is 1.0, e.g. 0x100. This is to avoid round-off errors + */ + + /* red: calculate and make sure the result is within range */ + if (0x100 != new_gamma_r_24i_8f) { + cur_color = (cur_palette >> 16) & 0xFF; + new_gamma = OS_POW_FIX(cur_color, (1<<16)/new_gamma_r_24i_8f); + new_gamma = (MAX_PIXEL_VAL * new_gamma)/gamma_normal_r_24i_8f; + palette[i] &= 0x00FFFF; + palette[i] |= + (OS_MIN(new_gamma, (unsigned) MAX_PIXEL_VAL) & 0xFF) << 16; + } + + /* green: calculate and make sure the result is within range */ + if (0x100 != new_gamma_g_24i_8f) { + cur_color = (cur_palette >> 8) & 0xFF; + new_gamma = OS_POW_FIX(cur_color, (1<<16)/new_gamma_g_24i_8f); + new_gamma = (MAX_PIXEL_VAL * new_gamma)/gamma_normal_g_24i_8f; + palette[i] &= 0xFF00FF; + palette[i] |= + (OS_MIN(new_gamma, (unsigned) MAX_PIXEL_VAL) & 0xFF) << 8; + } + + /* blue: calculate and make sure the result is within range */ + if (0x100 != new_gamma_b_24i_8f) { + cur_color = cur_palette & 0xFF; + new_gamma = OS_POW_FIX(cur_color, (1<<16)/new_gamma_b_24i_8f); + new_gamma = (MAX_PIXEL_VAL * new_gamma)/gamma_normal_b_24i_8f; + palette[i] &= 0xFFFF00; + palette[i] |= + (OS_MIN(new_gamma, (unsigned) MAX_PIXEL_VAL) & 0xFF); + } + } + + + /* Brightness correction */ + brightness_factor_r = (brightness_attr->current_value >> 16) & 0xFF; + brightness_factor_g = (brightness_attr->current_value >> 8) & 0xFF; + brightness_factor_b = brightness_attr->current_value & 0xFF; + + /* The factors are offset by 0x80 because 0x80 is 0 correction */ + brightness_factor_r -= 0x80; + brightness_factor_g -= 0x80; + brightness_factor_b -= 0x80; + + for( i = 0; i < NUM_PALETTE_ENTRIES; i++ ) { + int new_pixel_val; + unsigned int cur_color; + unsigned int cur_palette = palette[i]; + + /* red: calculate and make sure the result is within range */ + cur_color = (cur_palette >> 16) & 0xFF; + new_pixel_val = cur_color + brightness_factor_r; + new_pixel_val = OS_MIN(new_pixel_val, MAX_PIXEL_VAL); + palette[i] &= 0x00FFFF; + palette[i] |= (OS_MAX(new_pixel_val, 0) & 0xFF) << 16; + + /* green: calculate and make sure the result is within range */ + cur_color = (cur_palette >> 8) & 0xFF; + new_pixel_val = cur_color + brightness_factor_g; + new_pixel_val = OS_MIN(new_pixel_val, MAX_PIXEL_VAL); + palette[i] &= 0xFF00FF; + palette[i] |= (OS_MAX(new_pixel_val, 0) & 0xFF) << 8; + + /* blue: calculate and make sure the result is within range */ + cur_color = cur_palette & 0xFF; + new_pixel_val = cur_color + brightness_factor_b; + new_pixel_val = OS_MIN(new_pixel_val, MAX_PIXEL_VAL); + palette[i] &= 0xFFFF00; + palette[i] |= OS_MAX(new_pixel_val, 0) & 0xFF; + } + + + /* contrast correction */ + contrast_factor_r = (contrast_attr->current_value >> 16) & 0xFF; + contrast_factor_g = (contrast_attr->current_value >> 8) & 0xFF; + contrast_factor_b = contrast_attr->current_value & 0xFF; + + /* make sure values are within range */ + contrast_factor_r -= 0x80; + contrast_factor_g -= 0x80; + contrast_factor_b -= 0x80; + + + /* We're doing integer division in this loop using 16i.16f + * integers. The result will then be converted back into a + * regular, 32-bit integer + */ + for( i = 0; i < NUM_PALETTE_ENTRIES; i++ ) { + int new_pixel_val; + unsigned int cur_color; + unsigned int cur_palette = palette[i]; + + /* red: calculate and make sure the result is within range */ + if (0 != contrast_factor_r ) { + cur_color = (cur_palette >> 16) & 0xFF; + new_pixel_val = + (MAX_PIXEL_VAL << 16) / (MAX_PIXEL_VAL - contrast_factor_r); + new_pixel_val = new_pixel_val * (cur_color - MID_PIXEL_VAL); + new_pixel_val >>= 16; /* convert back to 32i format */ + new_pixel_val += MID_PIXEL_VAL; + new_pixel_val = OS_MIN(new_pixel_val, MAX_PIXEL_VAL); + palette[i] &= 0x00FFFF; /* clear out the R color */ + palette[i] |= (OS_MAX(new_pixel_val, 0) & 0xFF) << 16; + } + + /* green: calculate and make sure the result is within range */ + if (0 != contrast_factor_g ) { + cur_color = (cur_palette >> 8) & 0xFF; + new_pixel_val = + (MAX_PIXEL_VAL << 16) / (MAX_PIXEL_VAL - contrast_factor_g); + new_pixel_val = new_pixel_val * (cur_color - MID_PIXEL_VAL); + new_pixel_val >>= 16; /* convert back to 32i format */ + new_pixel_val += MID_PIXEL_VAL; + new_pixel_val = OS_MIN(new_pixel_val, MAX_PIXEL_VAL); + palette[i] &= 0xFF00FF; /* clear out the G color */ + palette[i] |= (OS_MAX(new_pixel_val, 0) & 0xFF) << 8; + } + + /* blue: calculate and make sure the result is within range */ + if (0 != contrast_factor_b) { + cur_color = cur_palette & 0xFF; + new_pixel_val = + (MAX_PIXEL_VAL << 16) / (MAX_PIXEL_VAL - contrast_factor_b); + new_pixel_val = new_pixel_val * (cur_color - MID_PIXEL_VAL); + new_pixel_val >>= 16; /* convert back to 32i format */ + new_pixel_val += MID_PIXEL_VAL; + new_pixel_val = OS_MIN(new_pixel_val, MAX_PIXEL_VAL); + palette[i] &= 0xFFFF00; /* clear out the B color */ + palette[i] |= OS_MAX(new_pixel_val, 0) & 0xFF; + } + } + + + /* write the new values in the palette */ + for (i = 0; i < NUM_PALETTE_ENTRIES; i++) { + /* SDVO palette register is not accesible */ + OS_WRITE32(palette[i], + MMIO_TNC(IGD_PORT_LVDS) + + PIPE(display)->palette_reg + i*4); + } + + OS_FREE(palette); + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param display + * @param fb + * @param x + * @param y + * + * @return 0 + */ +static int set_display_base_tnc(igd_display_context_t *display, + igd_framebuffer_info_t *fb, unsigned long *x, unsigned long *y) +{ + unsigned long base; + + OS_TRACE_ENTER; + + OS_DEBUG ("Pan linear"); + + /* FIXME/TODO: Compare the difference between the plb/tnc versions of this + * function, as the plb code adds-in the offset of the frame buffer. + */ + base = ((*y * fb->screen_pitch) + (*x * IGD_PF_BYPP(fb->pixel_format))); + + /* Plane registers are always on 0:2:0 */ + WRITE_MMIO_REG(display, PLANE(display)->plane_reg+DSP_LINEAR_OFFSET, base); + + OS_TRACE_EXIT; + return 0; +} + +/*! + * This function alters the position parameters associated with a cursor. + * + * @param display_handle + * @param cursor_info + * + * @return 0 + */ +static int igd_alter_cursor_pos_tnc(igd_display_h display_handle, + igd_cursor_info_t *cursor_info) +{ + unsigned long cursor_reg; + unsigned long new_pos; + unsigned long cursor_base; + + igd_display_context_t *display = (igd_display_context_t *) display_handle; + cursor_reg = PIPE(display)->cursor->cursor_reg; + + /* To Fast For Tracing */ + + /* Plane registers are always on 0:2:0 device */ + if (0x27 & READ_MMIO_REG(display, cursor_reg)) { + /* unlike almador, for Gen4, u must program the base offset + to trigger the position update. However, this also means we + accidentally enable an invalid cursor surface if the cursor + was not enabled already. So do this check first */ + + /* + * Encode the cursor position in the format required for the + * cursor position register. + */ + if(cursor_info->y_offset >= 0) { + new_pos = (cursor_info->y_offset << 16); + } else { + new_pos = ((-(cursor_info->y_offset)) << 16) | 0x80000000; + } + if(cursor_info->x_offset >= 0) { + new_pos |= (cursor_info->x_offset); + } else { + new_pos |= (-(cursor_info->x_offset)) | 0x00008000; + } + + cursor_base = READ_MMIO_REG(display, cursor_reg + CUR_BASE_OFFSET); + + WRITE_MMIO_REG(display, cursor_reg + CUR_POS_OFFSET, new_pos); + WRITE_MMIO_REG(display, cursor_reg + CUR_BASE_OFFSET, cursor_base); + } + + return 0; +} + +/*! + * The assumption here is that palette_colors points to index 0 and + * this function indexes into the palette_colors array by start_index + * + * @param display_handle + * @param palette_colors + * @param start_index + * @param count + * + * @return 0 + */ +static int igd_set_palette_entries_tnc( + igd_display_h display_handle, + unsigned long *palette_colors, + unsigned int start_index, + unsigned int count) +{ + unsigned int i; + + OS_TRACE_ENTER; + + for(i=start_index; ipalette_reg + i*4, palette_colors[i]); + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * This procedure waits for the next vertical sync + * period. If the display is already in a vertical sync period, this + * procedure exits. + * + * Note: A timeout is included to prevent an endless loop. + * + * @param display_handle + * @param palette_colors + * @param start_index + * @param count + * + * @return FALSE - if timed out + */ +static int igd_wait_vsync_tnc(igd_display_h display_handle) +{ + unsigned long tmp; + unsigned long status_reg; + os_alarm_t timeout; + igd_display_context_t *display = (igd_display_context_t *)display_handle; + + OS_TRACE_ENTER; + + status_reg = PIPE(display)->pipe_reg + PIPE_STATUS_OFFSET; + + /* If pipe is off then just return */ + if(!((1<<31) & READ_MMIO_REG_TNC(PORT_TYPE(display), + PIPE(display)->pipe_reg))) { + OS_TRACE_EXIT; + return 1; + } + + /* 1. Disable VSync interrupt */ + tmp = READ_MMIO_REG_TNC(PORT_TYPE(display), status_reg); + WRITE_MMIO_REG_TNC(PORT_TYPE(display), status_reg, tmp & ~(1<<25)); + + /* 2. Clear interrupt status (by writing a 1) */ + tmp = READ_MMIO_REG_TNC(PORT_TYPE(display), status_reg); + WRITE_MMIO_REG_TNC(PORT_TYPE(display), status_reg, tmp | (1<<9)); + + /* 3. Enable VSync interrupt */ + tmp = READ_MMIO_REG_TNC(PORT_TYPE(display), status_reg); + WRITE_MMIO_REG_TNC(PORT_TYPE(display), status_reg, tmp | (1<<25)); + + /* 4. Wait for VSync about 50 msec (20Hz) */ + timeout = OS_SET_ALARM(50); + do { + OS_SCHEDULE(); + /* Check for timeout */ + } while (((READ_MMIO_REG_TNC(PORT_TYPE(display), status_reg) & (1<<9)) == + 0x00) && + (!OS_TEST_ALARM(timeout))); + + if (((READ_MMIO_REG_TNC(PORT_TYPE(display), status_reg) & (1<<9)) == + 0x00)) { + OS_ERROR_EXIT("Timeout waiting for VSYNC"); + return 0; + } + + OS_TRACE_EXIT; + return 1; +} /* igd_wait_vsync*/ + +/*! + * + * @param display_handle + * @param scanline + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ +static int igd_get_scanline_tnc(igd_display_h display_handle, int *scanline) +{ + unsigned int tmp; + unsigned long reg; + igd_display_context_t *display = (igd_display_context_t *)display_handle; + unsigned long fb_height = PLANE(display)->fb_info->height; + unsigned long dp_height = PIPE(display)->timing->height; + + OS_TRACE_ENTER; + + /* Scanline reg is -8 from control reg */ + reg = PIPE(display)->pipe_reg - 0x8; + + tmp = READ_MMIO_REG_TNC(PORT_TYPE_DH(display_handle), reg); + + if(!(PORT_OWNER(display)->pt_info->flags & IGD_DISPLAY_ENABLE)) { + OS_DEBUG("Port off, can not get scanline"); + OS_TRACE_EXIT; + return -IGD_ERROR_INVAL; + } + + tmp = (tmp * fb_height) / dp_height; + + if(tmp >= fb_height) { + *scanline = IGD_IN_VBLANK; + } else { + *scanline = (int)tmp; + } + + OS_TRACE_EXIT; + return 0; +} /* end igd_get_scanline() */ + +/*! + * + * @param display_handle + * + * @return 1 if TRUE + * @return 0 if FALSE + */ +static int igd_query_in_vblank_tnc(igd_display_h display_handle) +{ + int sl; + + /* To small for Tracing */ + + igd_get_scanline_tnc(display_handle, &sl); + if (sl == IGD_IN_VBLANK) { + return 1; /*TRUE*/ + } else { + return 0; /*FALSE*/ + } +} + +/*! + * This function programs the cursor registers for Grantsdale + * + * @param display + * @param status + * + * @return void + */ +static void program_cursor_tnc(igd_display_context_t *display, + unsigned long status) +{ + unsigned long cursor_reg; + unsigned long cursor_control = 0x00000000; + unsigned long cursor_pos; + unsigned long cursor_base; + igd_cursor_info_t *cursor_info; + int i; + + OS_TRACE_ENTER; + OS_DEBUG("Program Cursor: %s", status?"ENABLE":"DISABLE"); + OS_DEBUG("Device power state: D%ld", GET_DEVICE_POWER_STATE(display)); + + cursor_reg = PIPE(display)->cursor->cursor_reg; + cursor_info = PIPE(display)->cursor->cursor_info; + + /* Turn off cursor before changing anything */ + /* planes are always on 0:2:0 device, so no need to use _TNC macros */ + cursor_base = READ_MMIO_REG(display, cursor_reg + CUR_BASE_OFFSET); + + WRITE_MMIO_REG(display, cursor_reg, cursor_control); + WRITE_MMIO_REG(display, cursor_reg + CUR_BASE_OFFSET, cursor_base); + + if(cursor_info->flags & IGD_CURSOR_GAMMA) { + cursor_control |= BIT26; + } + + cursor_info->argb_pitch = 64*4; + cursor_info->xor_pitch = 16; + + /* Setting the cursor format/pitch */ + switch(cursor_info->pixel_format) { + case IGD_PF_ARGB32: + cursor_control |= BIT5 | 0x7; + break; + case IGD_PF_RGB_XOR_2: + cursor_control |= 0x5; + break; + case IGD_PF_RGB_T_2: + cursor_control |= 0x4; + break; + case IGD_PF_RGB_2: + cursor_control |= 0x6; + break; + default: + OS_ERROR_EXIT("Invalid Pixel Format"); + return; + } + + switch(cursor_info->pixel_format) { + case IGD_PF_ARGB32: + cursor_base = cursor_info->argb_offset; + break; + default: + cursor_base = cursor_info->xor_offset; + break; + } + + /* If status is FALSE return with the cursor off */ + if((!status) || (GET_DEVICE_POWER_STATE(display) == IGD_POWERSTATE_D3)) { + OS_TRACE_EXIT; + return; + } + + if(cursor_info->y_offset >= 0) { + cursor_pos = cursor_info->y_offset << 16; + } else { + cursor_pos = ((-(cursor_info->y_offset)) << 16) | 0x80000000; + } + if(cursor_info->x_offset >= 0) { + cursor_pos |= cursor_info->x_offset; + } else { + cursor_pos |= (-(cursor_info->x_offset)) | 0x00008000; + } + + WRITE_MMIO_REG(display, cursor_reg + CUR_POS_OFFSET, + cursor_pos); + + for(i=0; i<4; i++) { + WRITE_MMIO_REG(display, cursor_reg + CUR_PAL0_OFFSET + i*4, + cursor_info->palette[i]); + } + + cursor_control = cursor_control | (PIPE(display)->pipe_num<<28); + + WRITE_MMIO_REG(display, cursor_reg, cursor_control); + WRITE_MMIO_REG(display, cursor_reg + CUR_BASE_OFFSET, cursor_base); + + OS_TRACE_EXIT; +} + +/*! + * + * @param display_handle + * @param type + * @param surface + * @param appcontext + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ +static int igd_get_surface_tnc(igd_display_h display_handle, + igd_buffertype_t type, + igd_surface_t *surface, + igd_appcontext_h appcontext) +{ +#if 0 + igd_display_context_t *display = (igd_display_context_t *)display_handle; + state3d_tnc_t *state = STATE3D_TNC(appcontext); + + OS_TRACE_ENTER; + + if(!surface) { + OS_ERROR_EXIT("Surface is NULL"); + return -IGD_ERROR_INVAL; + } + + switch(type) { + case IGD_BUFFER_DISPLAY: + surface->offset = PLANE(display)->fb_info->visible_offset; + surface->pitch = PLANE(display)->fb_info->screen_pitch; + surface->width = PLANE(display)->fb_info->width; + surface->height = PLANE(display)->fb_info->height; + surface->u_offset = 0; + surface->u_pitch = 0; + surface->v_offset = 0; + surface->v_pitch = 0; + surface->pixel_format = PLANE(display)->fb_info->pixel_format; + surface->palette_info = 0; + surface->flags = PLANE(display)->fb_info->flags; + surface->logic_ops = 0; + surface->render_ops = 0; + surface->alpha = 0; + surface->diffuse = 0; + surface->chroma_high = 0; + surface->chroma_low = 0; + OS_TRACE_EXIT; + return 0; + case IGD_BUFFER_COLOR: + OS_MEMCPY(surface, &state->color_buffer, + sizeof(igd_surface_t)); + OS_TRACE_EXIT; + return 0; + case IGD_BUFFER_DEPTH: + OS_MEMCPY(surface, &state->depth_buffer, + sizeof(igd_surface_t)); + OS_TRACE_EXIT; + return 0; + default: + OS_ERROR("Invalid type in get_surface"); + break; + } + + OS_TRACE_EXIT; + return -IGD_ERROR_INVAL; +#else + return 0; +#endif +} + +/*! + * + * @param display_handle + * @param type + * @param surface + * @param appcontext + * @param flags + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ +static int igd_set_surface_tnc(igd_display_h display_handle, + int priority, + igd_buffertype_t type, + igd_surface_t *surface, + igd_appcontext_h appcontext, + unsigned long flags) +{ + igd_display_context_t *display = (igd_display_context_t *)display_handle; + unsigned int dsp_current; + unsigned long async; + static unsigned long async_prev[2]; + unsigned long cmd_wait; + unsigned long plane_reg; + unsigned long plane_control; + unsigned long surface_offset; +#if 0 /* BP - removing command queue code */ + cmd_queue_plb_t *queue; + unsigned long size; +#else + platform_context_tnc_t *tnc_context = + (platform_context_tnc_t *) mode_context->context->platform_context; + int ret; +#endif + + OS_TRACE_ENTER; + if(!surface) { + return -IGD_ERROR_INVAL; + } + + switch(type) { + case IGD_BUFFER_DISPLAY: + if(! (surface->flags & IGD_SURFACE_DISPLAY)) { + OS_ERROR_EXIT("Surface is not a display surface"); + return -IGD_ERROR_INVAL; + } + +#if 0 /* BP - removing command queue code */ + queue = CMD_GET_QUEUE_PLB(display, priority); +#endif + + if (PLANE(display)->plane_reg == DSPACNTR) { + OS_DEBUG("About to flip a buffer for display/pipe A"); + dsp_current = 0; + cmd_wait = CMD_WAIT_FLIP_A_PLB; + } else { + OS_DEBUG("About to flip a buffer for display/pipe B"); + dsp_current = 1; + cmd_wait = CMD_WAIT_FLIP_B_PLB; + } + + /* If the previous set_surface was synchronous (!async) + * then wait for it before issueing a new one. */ + if (!async_prev[dsp_current]) { + /* Wait for previous flip */ +#if 0 /* BP - removing command queue code */ + if(!queue) { + OS_ERROR_EXIT("Queue Not Found"); + return -IGD_ERROR_INVAL; + } + size = 1; + if (cmd_reserve_plb(queue, size, VCOMMAND_WAIT_PLB)) { + OS_ERROR_EXIT("Queue reservation failed"); + return -IGD_ERROR_INVAL; + } + INSTR_WRITE(cmd_wait, queue->current_node); + cmd_update_plb(queue); +#else + int bailout; + OS_DEBUG("Must wait for previous synchronous flip"); + for (bailout=64 ; bailout > 0 ; bailout--) { + + ret = OS_PTHREAD_MUTEX_LOCK(&tnc_context->flip_mutex); + ret = check_flip_pending_tnc(MMIO(display), + (!dsp_current) ? 0x70024 : 0x71024); + OS_PTHREAD_MUTEX_UNLOCK(&tnc_context->flip_mutex); + if (0 == ret) { + break; + } else { + /* Sleep for 1msec: */ + OS_SLEEP(1000); + } + } +#endif + } + + if(flags & IGD_BUFFER_WAIT) { + /* If this is just a wait for flip, so return */ + return 0; + } + + /* Get async flag */ + async = (flags & IGD_BUFFER_ASYNC) ? 1 : 0; + OS_DEBUG("async flag set to %lu", async); + /* + * Async flips only work when the pitch is the same. + */ + if(PLANE(display)->fb_info->screen_pitch != surface->pitch) { + OS_ERROR("Set surface w/diff pitch not handled in Poulsbo yet"); + async = 0; + } + /* + * Async flips only work when the offset is on a 256kb boundary. + */ + if(PLANE(display)->fb_info->visible_offset & 0x3ffff) { + OS_ERROR("FB offset must be 256kb aligned in Poulsbo"); + async = 0; + } + + /* Save new fb_info */ + PLANE(display)->fb_info->visible_offset = surface->offset; + PLANE(display)->fb_info->screen_pitch = surface->pitch; + PLANE(display)->fb_info->width = surface->width; + PLANE(display)->fb_info->height = surface->height; + PLANE(display)->fb_info->pixel_format = surface->pixel_format; + PLANE(display)->fb_info->flags = surface->flags; + + /* Get the correct stride and stereo */ + /* TODO - Does TNC flip need to handle stereo mode? */ + /*mode_get_stride_stereo_tnc(display, &stride, &stereo, 0);*/ + + /* calculate the real offset, taking panning into account */ + surface_offset = surface->offset; + surface_offset += + (PORT_OWNER(display)->pt_info->y_offset * surface->pitch) + + (PORT_OWNER(display)->pt_info->x_offset * + IGD_PF_BYPP(surface->pixel_format)); + OS_DEBUG("surface_offset = 0x%08lx", surface_offset); + + /* plane registers are always on 0:2:0, so no need to use _TNC macros */ + plane_reg = PLANE(display)->plane_reg; + plane_control = OS_READ32(MMIO(display) + plane_reg); + +#if 0 /* BP - removing command queue code */ + /* Put flip in the command queue */ + size = 4; + if (cmd_reserve_plb(queue, size, VCOMMAND_REG_PLB)) { + OS_ERROR_EXIT("Queue reservation failed"); + return -IGD_ERROR_INVAL; + } + INSTR_WRITE(plane_reg, queue->current_node); + INSTR_WRITE(plane_control, queue->current_node); + if (async) { + INSTR_WRITE(plane_reg - 4, queue->current_node); + async_prev[dsp_current] = 1; + } else { + INSTR_WRITE(plane_reg + DSP_LINEAR_OFFSET, queue->current_node); + async_prev[dsp_current] = 0; + } + INSTR_WRITE(surface_offset, queue->current_node); + cmd_update_plb(queue); +#endif + /* Perform the flip by doing the following: + * + * Write the current plan_control value to the plan_reg + * Write the surface offset to either: + * 1) the plan_reg - 4 if async + * 2) plane_reg + DSP_LINEAR_OFFSET if not async + */ + OS_WRITE32(plane_control, MMIO(display) + plane_reg); + if (async) { + OS_WRITE32(surface_offset, MMIO(display) + plane_reg - 4); + async_prev[dsp_current] = 1; + } else { + OS_WRITE32(surface_offset, + MMIO(display) + plane_reg + DSP_START_OFFSET); + async_prev[dsp_current] = 0; + ret = OS_PTHREAD_MUTEX_LOCK(&tnc_context->flip_mutex); + set_flip_pending_tnc(MMIO(display), + (!dsp_current) ? 0x70024 : 0x71024); + OS_PTHREAD_MUTEX_UNLOCK(&tnc_context->flip_mutex); + } + + OS_TRACE_EXIT; + return 0; + case IGD_BUFFER_COLOR: + OS_TRACE_EXIT; + return 0; + case IGD_BUFFER_DEPTH: + OS_TRACE_EXIT; + return 0; + default: + OS_ERROR("Invalid type in set_surface"); + break; + } + + OS_TRACE_EXIT; + return 0; +} + +/* Tunnel Creek does not support a flip pending, since there is no + * Display Buffer Info instruction. So this must be done with vBlank. + * However, a wait_for_vblank can be given while a flip is also in + * progress, so a semaphore is required when changing flip_pending or + * when modifying the vBlank interrupt bits. + * + * This function should only be called with a flip_mutex around it */ +int set_flip_pending_tnc(unsigned char *mmio, unsigned long pipe_status_reg) +{ + platform_context_tnc_t *tnc_context = + (platform_context_tnc_t *)mode_context->context->platform_context; + unsigned long tmp; + + OS_TRACE_ENTER; + OS_ASSERT((pipe_status_reg == 0x70024) || (pipe_status_reg == 0x71024), + "Invalid pipe_status_reg", 0); + + /* NOTE: This function never called for VBIOS, so no need to set and reset + * io_base registers by calling WRITE_MMIO_REG_TNC. But make sure + * use right mmio of device 0:2:0 or 0:3:0. So, get pipe B mmio offset + * (device 0:3:0) from device_context */ + if (pipe_status_reg == 0x71024) { + mmio = mode_context->context->device_context.virt_mmadr_sdvo; + } + + /* 1. Disable VBlank interrupt */ + tmp = OS_READ32(OS_MMIO(mmio) + pipe_status_reg); + OS_WRITE32 (tmp & ~VBLANK_STS_EN, + OS_MMIO(mmio) + pipe_status_reg); + + /* 2. Clear VBlank interrupt status (by writing a 1) */ + tmp = OS_READ32(OS_MMIO(mmio) + pipe_status_reg); + OS_WRITE32 (tmp | VBLANK_STS, OS_MMIO(mmio) + pipe_status_reg); + + /* 3. Enable VBlank interrupt */ + tmp = OS_READ32(OS_MMIO(mmio) + pipe_status_reg); + OS_WRITE32 (tmp | VBLANK_STS_EN, OS_MMIO(mmio) + pipe_status_reg); + + if (pipe_status_reg == 0x70024) { + tnc_context->flip_pending |= PLB_FLIP_PIPE_A_PENDING; + } else { + tnc_context->flip_pending |= PLB_FLIP_PIPE_B_PENDING; + } + + OS_TRACE_EXIT; + return 0; +} + +/* This function should only be called with a flip_mutex around it */ +int check_flip_pending_tnc(unsigned char *mmio, + unsigned long pipe_status_reg) +{ + platform_context_tnc_t *tnc_context = + (platform_context_tnc_t *)mode_context->context->platform_context; + unsigned long tmp; + unsigned int flip_pending; + + OS_TRACE_ENTER; + OS_ASSERT((pipe_status_reg == 0x70024) || (pipe_status_reg == 0x71024), + "Invalid pipe_status_reg", 0); + + /* This function never called for VBIOS, so no need to set and reset + * io_base registers by calling WRITE_MMIO_REG_TNC. But make sure + * use right mmio of device 0:2:0 or 0:3:0. So, get pipe B mmio offset + * (device 0:3:0) from device_context */ + if (pipe_status_reg == 0x71024) { + mmio = mode_context->context->device_context.virt_mmadr_sdvo; + } + + if (pipe_status_reg == 0x70024) { + flip_pending = + tnc_context->flip_pending & PLB_FLIP_PIPE_A_PENDING; + } else { + flip_pending = + tnc_context->flip_pending & PLB_FLIP_PIPE_B_PENDING; + } + + if (flip_pending) { + tmp = OS_READ32(mmio + pipe_status_reg) & VBLANK_STS; + if (tmp != 0) { + /* VBlank occured, flip complete */ + tnc_context->flip_pending &= ~flip_pending; + OS_DEBUG("returning 0 after checking register"); + return 0; + } else { + /* VBlank not done, flip still in progress */ + OS_DEBUG("returning 1"); + return 1; + } + } else { + /* No flip pending, so it must have completed */ + OS_DEBUG("returning 0"); + return 0; + } +} + +/*! + * + * @param display_handle + * @param event + * @param status + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ +static int igd_query_event_tnc(igd_display_h display_handle, + igd_event_t event, unsigned long *status) +{ + platform_context_tnc_t *tnc_context = + (platform_context_tnc_t *)mode_context->context->platform_context; + unsigned char *mmio = MMIO(display_handle); + unsigned long pipe_status_reg = + (PLANE(display_handle)->plane_reg == DSPACNTR) ? 0x70024 : 0x71024; + int ret; + + OS_TRACE_ENTER; + OS_DEBUG("mmio=0x%p, pipe_status_reg=0x%08lx", mmio, pipe_status_reg); + + switch (event) { + case IGD_EVENT_FLIP_PENDING: + ret = OS_PTHREAD_MUTEX_LOCK(&tnc_context->flip_mutex); + *status = check_flip_pending_tnc(mmio, pipe_status_reg); + OS_PTHREAD_MUTEX_UNLOCK(&tnc_context->flip_mutex); + break; + default: + return -IGD_ERROR_INVAL; + } + + OS_DEBUG("Returning status=%lu", *status); + return IGD_SUCCESS; +} + +/*! + * + * @param void + * + * @return 0 + */ +static int get_plane_info_tnc(void) +{ + igd_framebuffer_info_t *buffer_info; + unsigned char* mmio = NULL; + unsigned long plane_control = 0; + unsigned long reg = 0; + + OS_TRACE_ENTER; + + mmio = OS_MMIO(mode_context->context->device_context.virt_mmadr); + /* Check that plane A is active and process it */ + plane_control = OS_READ32(mmio + DSPACNTR); + if(plane_control & PLANE_ENABLE){ + buffer_info = &mode_context->fw_info->fb_info[0]; + + /* get the DSPASIZE register value */ + reg = (unsigned long)OS_READ32(mmio + DSPACNTR + DSP_SIZE_OFFSET); + buffer_info[0].height = (reg >> 16) & 0xFFF; + buffer_info[0].width = reg & 0xFFF; + + /* get the DSPASTRIDE register value */ + buffer_info[0].screen_pitch = + (unsigned int)OS_READ32(mmio + DSPACNTR + DSP_STRIDE_OFFSET); + + /* Following are NOT offset by 1 in fb info */ + buffer_info[0].width++; + buffer_info[0].height++; + } + + /* Check that plane B is active and process it */ + plane_control = OS_READ32(mmio + DSPBCNTR); + if(plane_control & PLANE_ENABLE){ + buffer_info = &mode_context->fw_info->fb_info[0]; + + /* get the DSPBSIZE register value */ + reg = (unsigned long)OS_READ32(mmio + DSPBCNTR + DSP_SIZE_OFFSET); + buffer_info[1].height = (reg >> 16) & 0xFFF; + buffer_info[1].width = reg & 0xFFF; + + /* get the DSPBSTRIDE register value */ + buffer_info[1].screen_pitch = + (unsigned int)OS_READ32(mmio + DSPBCNTR + DSP_STRIDE_OFFSET); + + /* Following are NOT offset by 1 in fb info */ + buffer_info[1].width++; + buffer_info[1].height++; + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param void + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ +static int get_pipe_info_tnc(void) +{ + unsigned char *mmio = NULL; + unsigned char *mmio_sdvo = NULL; + unsigned long pipe_conf = 0; + igd_display_info_t *timing; + unsigned long reg = 0; + + OS_TRACE_ENTER; + + mmio = OS_MMIO(mode_context->context->device_context.virt_mmadr); + mmio_sdvo = + OS_MMIO(mode_context->context->device_context.virt_mmadr_sdvo); + + /* + * On TNC only + * PIPE A + LVDS and + * PIPE B + SDVO are valid. + * + * Read both VGA_TNC(0:2:0) and SDVO_TNC(0:3:0) mmio reg values in + * determining the current timing + * + * [FIXME] + * 1) Reading both device mmio regs in determining FW timings + * 2) Update dclk equation as it changed for TNC. + */ + pipe_conf = OS_READ32(mmio + PIPEA_CONF); + if(pipe_conf & BIT(31)) { /* pipe A is active */ + timing = &mode_context->fw_info->timing_arr[0]; + + reg = OS_READ32(mmio + HTOTAL_A); + timing[0].htotal = (unsigned short)(reg >> 16) & 0x1FFF; + timing[0].width = (unsigned short)reg & 0xFFF; + + reg = OS_READ32(mmio + HBLANK_A); + timing[0].hblank_start = (unsigned short)reg & 0x1FFF; + timing[0].hblank_end = (unsigned short)(reg >> 16) & 0x1FFF; + + reg = OS_READ32(mmio + HSYNC_A); + timing[0].hsync_start = (unsigned short)reg & 0x1FFF; + timing[0].hsync_end = (unsigned short)(reg >> 16) & 0x1FFF; + + reg = OS_READ32(mmio + VTOTAL_A); + timing[0].vtotal = (unsigned short)(reg >> 16) & 0x1FFF; + timing[0].height = (unsigned short)reg & 0xFFF; + + reg = OS_READ32(mmio + VBLANK_A); + timing[0].vblank_start = (unsigned short)reg & 0x1FFF; + timing[0].vblank_end = (unsigned short)(reg >> 16) & 0x1FFF; + + reg = OS_READ32(mmio + VSYNC_A); + timing[0].vsync_start = (unsigned short)reg & 0x1FFF; + timing[0].vsync_end = (unsigned short)(reg >> 16) & 0x1FFF; + + /* Following are not offset by 1 in ptinfo */ + timing[0].width++; + timing[0].height++; + + OS_DEBUG("Pipe A timing width = %d", timing[0].width); + OS_DEBUG("Pipe A timing width = %d", timing[0].height); + + { + /* Calculate the firmware programmed dot clock */ + unsigned long dplla, fpa0, fpa1; + unsigned long ma1, ma2, na, pa1, pa2, plla_select; + unsigned long ref_freq = 0, dclk; + unsigned long temp; /* To store intermediate values b4 dclk */ + int j; + unsigned long lvds_port; + + dplla = OS_READ32(mmio + DPLLACNTR); + fpa0 = OS_READ32(mmio + FPA0); + fpa1 = OS_READ32(mmio + FPA1); + /* Note: Only Pipe A supports LVDS */ + lvds_port = OS_READ32(mmio + LVDSCNTR); + + if(dplla & BIT(31)) { + + ma1 = (fpa0 >> 8) & 0x3F; /* M1 is bits 13:8 */ + ma2 = (fpa0) & 0x1F; /* M1 is bits 5:0 */ + na = (fpa0 >> 16) & 0x3F; /* N is bits 21:16 */ + pa1 = (dplla >> 16) & 0xFF; /* P1 is bits 23:16 */ + + /* Check for illegal values of P1 + * The bit representation MUST be power of 2 + * All other values are illegal including zero. + */ + if( (pa1 == 0) || + ( (pa1 & (pa1-1)) != 0 ) ) { + + OS_ERROR_EXIT("Invalid P1 bits set"); + return -IGD_ERROR_INVAL; + } + for(j = 0; j < 8; j++) { + if(pa1 & BIT(j)) { /* P1 is divide by 1 to 8 */ + pa1 = j+1; + break; + } + } + pa2 = (dplla >> 24) & 0x3; /* P2 is bits 25:24 */ + + /* For LVDS port, the post divisor factors are different */ + if((lvds_port & 0x80000000) == 0x80000000) { + /* Pipe is used for LVDS port */ + if(pa2 == 0) { + pa2 = 14; + } else if(pa2 == 1) { + pa2 = 7; + } else { + OS_ERROR_EXIT("Invalid P2 bits set = 0x%lx", pa2); + return -IGD_ERROR_HWERROR; + } + } else { + /* Pipe A cannot be used other than LVDS port */ + } + + plla_select = (dplla >> 13) & 0x3; /* PLL Ref I/P Select */ + + /* Equation that calculates the dot clk + * ------------------------------------- + * + * pll_freq_factor = ((float)(5 * (ma1+2)+(ma2+2))/(na+2))/ + * ((pa1*pa2)); + * + * fdclk = pll_freq_factor * ref_freq * 1000000; + * + * Support for FPU in Kernel Code is not straightforward + * we will just stick to int operations. We will just re- + * arrange the factors. + */ + if(plla_select == 0) { + ref_freq = 96; /* 96MHz */ + } else if( (plla_select == 1) || (plla_select == 3) ) { + + OS_ERROR_EXIT("PLL Reference Input Select Reserved"); + return -IGD_ERROR_INVAL; + + } else if(plla_select == 2) { + OS_DEBUG("PLL ref is SDVO TV CLK"); + /* TODO: How to handle this value? */ + ref_freq = 0; + } + + /* First let's multiply by 1000 * 1000 + * so that we don't get zero during integer + * division + */ + temp = 1000 * 1000; + temp = temp * (5 * (ma1+2) + (ma2+2)); + temp = temp/(na+2); + temp = temp/(pa1*pa2); + + dclk = temp * ref_freq; + + if( (dclk == 0) || (ref_freq == 0) ) { + OS_ERROR_EXIT(" Dot Clock/Ref Frequency is Zero!!!"); + return -IGD_ERROR_INVAL; + } + OS_DEBUG("Ref frequency = %lu", ref_freq); + OS_DEBUG("Pipe A constructed Dot clock is = %lu", dclk); + timing[0].dclk = dclk/1000; /* Make it to KHz */ + OS_DEBUG("Pipe A Dot clock in KHz = %lu", timing[0].dclk); + + timing[0].refresh = (unsigned short)(dclk/ + ((timing[0].htotal+1)*(timing[0].vtotal+1))); + + OS_DEBUG("Pipe A refresh = %u", timing[0].refresh); + } /* if DPLL A active */ + } /* dot clock code block */ + } /* if Pipe A active */ + + /* For 2nd display pipe, pipe b registers in both 0:2:0 and 0:3:0 + * supposed to be programmed to same values. So these values can be + * read from either devices */ + pipe_conf = OS_READ32(mmio_sdvo + PIPEB_CONF); + + if(pipe_conf & BIT(31)) { /* pipe B is active */ + timing = &mode_context->fw_info->timing_arr[0]; + + reg = OS_READ32(mmio_sdvo + HTOTAL_B); + timing[1].htotal = (unsigned short)(reg >> 16) & 0x1FFF; + timing[1].width = (unsigned short)reg & 0xFFF; + + reg = OS_READ32(mmio + HBLANK_B); + timing[1].hblank_start = (unsigned short)reg & 0x1FFF; + timing[1].hblank_end = (unsigned short)(reg >> 16) & 0x1FFF; + + reg = OS_READ32(mmio + HSYNC_B); + timing[1].hsync_start = (unsigned short)reg & 0x1FFF; + timing[1].hsync_end = (unsigned short)(reg >> 16) & 0x1FFF; + + reg = OS_READ32(mmio + VTOTAL_B); + timing[1].vtotal = (unsigned short)(reg >> 16) & 0x1FFF; + timing[1].height = (unsigned short)reg & 0xFFF; + + reg = OS_READ32(mmio + VBLANK_B); + timing[1].vblank_start = (unsigned short)reg & 0x1FFF; + timing[1].vblank_end = (unsigned short)(reg >> 16) & 0x1FFF; + + OS_READ32(mmio + VSYNC_B); + timing[1].vsync_start = (unsigned short)reg & 0x1FFF; + timing[1].vsync_end = (unsigned short)(reg >> 16) & 0x1FFF; + + /* Following are not offset by 1 in ptinfo */ + timing[1].width++; + timing[1].height++; + + { + /* Calculate the firmware programmed dot clock */ + unsigned long dpllb, fpb0, fpb1; + unsigned long mb1, mb2, nb, pb1, pb2, pllb_select; + unsigned long ref_freq = 0, dclk; + unsigned long temp; /* To store intermediate values b4 dclk */ + int j; + + dpllb = OS_READ32(mmio_sdvo + DPLLBCNTR); + fpb0 = OS_READ32(mmio_sdvo + FPB0); + fpb1 = OS_READ32(mmio_sdvo + FPB1); + + if(dpllb & BIT(31)) { + + mb1 = (fpb0 >> 8) & 0x3F; /* M1 is bits 13:8 */ + mb2 = (fpb0) & 0x1F; /* M1 is bits 5:0 */ + nb = (fpb0 >> 16) & 0x3F; /* N is bits 21:16 */ + pb1 = (dpllb >> 16) & 0xFF; /* P1 is bits 23:16 */ + + /* Check for illegal values of P1 + * The bit representation MUST be power of 2 + * All other values are illegal including zero. + */ + if( (pb1 == 0) || + ( (pb1 & (pb1-1)) != 0 ) ) { + OS_ERROR_EXIT("Invalid P1 bits set"); + return -IGD_ERROR_INVAL; + } + + for(j = 0; j < 8; j++) { + if(pb1 & BIT(j)) { /* P1 is divide by 1 to 8 */ + pb1 = j+1; + break; + } + } + + pb2 = (dpllb >> 24) & 0x3; /* P2 is bits 25:24 */ + + /* Since Pipe B does not support internal LVDS, we just + * follow the normal divisor values + */ + if(pb2 == 0) { + pb2 = 10; + } else if(pb2 == 1) { + pb2 = 5; + } else { + OS_ERROR("Invalid P2 bits set = 0x%lx", pb2); + } + + pllb_select = (dpllb >> 13) & 0x3; /* PLL Ref I/P Select */ + + /* Equation that calculates the dot clk + * ------------------------------------- + * + * pll_freq_factor = ((float)(5 * (mb1+2)+(mb2+2))/(nb+2))/ + * ((pb1*pb2)); + * + * fdclk = pll_freq_factor * ref_freq * 1000000; + * + * Support for FPU in Kernel Code is not straightforward + * we will just stick to int operations. We will just re- + * arrange the factors. + */ + if(pllb_select == 0) { + ref_freq = 96; /* 96MHz */ + + } else if( (pllb_select == 1) || (pllb_select == 3) ) { + + OS_ERROR_EXIT("PLL Reference Input Select Reserved"); + return -IGD_ERROR_INVAL; + + } else if(pllb_select == 2) { + OS_ERROR_EXIT("PLL ref is SDVO TV CLK"); + /* TODO: How to handle this value? */ + return -IGD_ERROR_INVAL; + } + + /* First let's multiply by 1000 * 1000 + * so that we don't end up in zero during + * integer division + */ + temp = 1000 * 1000; + temp = temp * (5 * (mb1+2) + (mb2+2)); + temp = temp /(nb+2); + dclk = temp/(pb1*pb2); + + dclk = temp * ref_freq; + + if( (dclk == 0) || (ref_freq == 0) ) { + OS_ERROR_EXIT("Dot Clock/Ref Frequency is Zero!!!"); + return -IGD_ERROR_INVAL; + } + + OS_DEBUG("Ref frequency = %lu", ref_freq); + OS_DEBUG("Pipe B constructed Dot clock is = %lu", dclk); + timing[1].dclk = dclk/1000; /* Make it to KHz */ + OS_DEBUG("Pipe B Dot clock in KHz = %lu", timing[1].dclk); + + timing[1].refresh = (unsigned short) (dclk/ + ((timing[1].htotal+1)*(timing[1].vtotal+1))); + + OS_DEBUG("Pipe B refresh = %u", timing[1].refresh); + } /* if DPLL B active */ + } /* dot clock code block */ + } /* if Pipe B is active */ + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param void + * + * @return 0 + */ +static int get_port_info_tnc(void) +{ + /* TODO: Any port related info that needs to be populated ? */ + OS_TRACE_ENTER; + + OS_TRACE_EXIT; + return 0; + +} +mode_full_dispatch_t mode_full_dispatch_tnc = { + igd_alter_cursor_pos_tnc, + igd_set_palette_entries_tnc, + igd_wait_vsync_tnc, + igd_query_in_vblank_tnc, + igd_get_scanline_tnc, + set_display_base_tnc, + program_cursor_tnc, + set_color_correct_tnc, + igd_get_surface_tnc, + igd_set_surface_tnc, + igd_query_event_tnc, + set_flip_pending_tnc, + check_flip_pending_tnc, + get_plane_info_tnc, + get_pipe_info_tnc, + get_port_info_tnc, +}; + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: mode_tnc.c,v 1.18 2010/05/21 00:20:49 btay1 Exp $ + *---------------------------------------------------------------------------- + */ diff --git a/drivers/gpu/drm/emgd/emgd/display/pd/cmn/pd.c b/drivers/gpu/drm/emgd/emgd/display/pd/cmn/pd.c new file mode 100755 index 0000000..834b11b --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/pd/cmn/pd.c @@ -0,0 +1,517 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: pd.c + * $Revision: 1.5 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * This file contains all the necessary common functions for port driver + * module. These functions are called only from hardware specific port + * drivers. These are exported via pd.h. + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.dpd + +#include + +#include +#include + +#include +#include +#include + +/*! + * @addtogroup display_group + * @{ + */ + +/*! + * + * @param size + * + * @return void + */ +void *pd_malloc(unsigned long size) +{ + return OS_ALLOC(size); +} /* end pd_malloc */ + +/*! + * + * @param address + * @param c + * @size + * + * @return void + */ +void *pd_memset(void *address, int c, unsigned long size) +{ + return OS_MEMSET(address, c, size); +} /* end pd_memset */ + +/*! + * + * @param dst + * @param src + * @param size + * + * @return void + */ +void *pd_memcpy(void *dst, void *src, unsigned long size) +{ + return OS_MEMCPY(dst, src, size); +} /* end pd_memcpy */ + +/*! + * + * @param size + * + * @return void + */ +void pd_free(void *ptr) +{ + OS_FREE(ptr); +} /* end pd_free */ + +/*! + * + * @param usec + * + * @return void + */ +void pd_usleep(unsigned long usec) +{ + + if (usec <= 1000) { + OS_SLEEP(usec); + } else { + os_alarm_t alarm = OS_SET_ALARM((usec+999)/1000); + do { + OS_SCHEDULE(); + } while (!OS_TEST_ALARM(alarm)); + } + +} + +/*! + * + * @param usec + * + * @return void + */ +void pd_ui_usleep(unsigned long usec) +{ + OS_UISLEEP(usec); + +} + +/*! + * + * @param dest + * @param src + * + * @return dest + */ +char *pd_strcpy(char *dest, const char *src) +{ + int i = 0; + /* This can be optimized by assigning 32 bit quantities instead + * of 8 bit quantities. This requires knowing the length first then + * move the quantities. For now, this is OK. */ + while (src[i] != '\0') { + dest[i] = src[i]; + i++; + } + dest[i] = '\0'; + return (dest); +} + +/*! + * + * @param handle + * @param driver + * + * @return pi_pd_register() + */ +int pd_register(void *handle, pd_driver_t *driver) +{ + return (pi_pd_register(driver)); +} /* end pd_register */ + +/*! + * + * @param curr + * @param in + * + * @return PD_SUCCESS on success + * @return PD_ERR_INVALID_ATTR or PD_ERR_INCORR_ATTR_VALUE on failure + */ +int pd_check_attr(pd_attr_t *curr, pd_attr_t *in) +{ + if (!curr || !in) { + return PD_ERR_NULL_PTR; + } + + if (curr->id != in->id) { + return PD_ERR_INVALID_ATTR; + } + + switch (curr->type) { + case PD_ATTR_TYPE_RANGE: + if ((in->current_value < RATTR(curr)->min) || + (in->current_value > RATTR(curr)->max)) { + return PD_ERR_INCORR_ATTR_VALUE; + } + break; + case PD_ATTR_TYPE_LIST: + if ((in->current_value < 1) || + (in->current_value > LHATTR(curr)->num_entries)) { + return PD_ERR_INCORR_ATTR_VALUE; + } + break; + case PD_ATTR_TYPE_BOOL: + if ((in->current_value != TRUE) && + (in->current_value != FALSE)) { + return PD_ERR_INCORR_ATTR_VALUE; + } + break; + default: + return PD_ERR_INVALID_ATTR; + } + return PD_SUCCESS; +} + +/*! + * This function searches for the requested attr_id in the attribute list + * and returns the pointer. + * + * In case of LIST attribute, it will return the proper list entry. + * + * @param attr_list + * @param num_attr + * @param attr_id + * @param flag + * + * @return pd_attr_t on success + * @return NULL on failure + */ +pd_attr_t *pd_get_attr(pd_attr_t *attr_list, unsigned long num_attrs, + unsigned long attr_id, unsigned long flag) +{ + unsigned long i; + + if (!attr_list) { + return NULL; + } + + for (i = 0; i < num_attrs; i++) { + if (attr_list[i].id == attr_id) { + if (attr_list[i].type == PD_ATTR_TYPE_LIST) { + if (flag == PD_GET_ATTR_LIST_ENTRY) { + return (&(attr_list[i+attr_list[i].current_value])); + } else { + return (&(attr_list[i])); + } + } + return (&(attr_list[i])); + } + } + return NULL; +} /* end pd_get_attr() */ + +/*! + * Common mode filter algorithm for all port drivers + * + * @param call_back + * @param in_list + * @param out_list + * @param dvo_info + * @param display_info + * + * @return PD_SUCCESS on success + * @return PD_ERR_NULL_PTR or PD_ERR_NOMEM on failure + */ +int pd_filter_timings( + void *callback_context, + pd_timing_t *in_list, + pd_timing_t **out_list, + pd_dvo_info_t *dvo_info, + pd_display_info_t *display_info) +{ + igd_display_port_t *port = (igd_display_port_t *)callback_context; + pd_timing_t *timing = NULL, *native_dtd = NULL; + int j; + int count = 0; + unsigned short fp_refresh = 60; + pd_timing_t *olist = NULL; + unsigned long fixed_timing = 0; + int i, ret; + + if (!port || !in_list || !out_list) { + return PD_ERR_NULL_PTR; + } + + /* Start with fixed_res = 0 */ + display_info->fixed_res = 0; + + /* DisplayID FP width are specified */ + if (port->firmware_type == PI_FIRMWARE_DISPLAYID) { + display_info->width = port->displayid->display_params.horz_pixels; + display_info->height = port->displayid->display_params.vert_pixels; + fixed_timing = port->displayid->display_params.fixed_timing; + display_info->fixed_res = port->displayid->display_params.fixed_res; + } + + /* Overwrite DisplayID FP values with config fpinfo, later + * these will be overwritten by native DTD width, height */ + if (port->fp_info) { + /* This is done for backward compatibility: + * Set width, height from display port fp_info + * This also required dropping fp_info width and height attributes + * from all port drivers */ + display_info->width = (unsigned short) port->fp_info->fp_width; + display_info->height = (unsigned short) port->fp_info->fp_height; + /* Backward compatibility: If width and height are specified, + * that means it is a fixed resolution panel */ + if (port->fp_info->fp_width && port->fp_info->fp_height) { + display_info->fixed_res = 1; + fp_refresh = 60; + } + } + + /* If fixed timing also comes from user attributes then override DisplayID + * fixed timing and fpinfo values */ + ret = pi_get_port_init_attr(port, PD_ATTR_ID_FIXED_TIMING, &fixed_timing); + if (fixed_timing) { + display_info->fixed_res = 1; + fp_refresh = 60; + } + + /* Do gmch filtering: + * There is no way to get the mode context inorder to reach the + * gmch filtering function */ + + /* First find the native resolution */ + get_native_dtd(in_list, PI_SUPPORTED_TIMINGS, + &display_info->native_dtd, PD_MODE_DTD_FP_NATIVE); + + /* If no FP Native DTD provided, then get the native DTD + * either user DTD or edid DTD */ + if (!display_info->native_dtd) { + get_native_dtd(in_list, PI_SUPPORTED_TIMINGS, + &display_info->native_dtd, PD_MODE_DTD_USER); + } + if (!display_info->native_dtd) { + get_native_dtd(in_list, PI_SUPPORTED_TIMINGS, + &display_info->native_dtd, PD_MODE_DTD); + } + + /* Set up the fp width, height and refresh for the comparison */ + if (display_info->native_dtd) { +#ifndef CONFIG_MICRO + /* If fp width, height doesn' match with native width and height, + * Configuration isn't correct */ + if ((display_info->width && + (display_info->width != display_info->native_dtd->width)) && + (display_info->height && + (display_info->height != display_info->native_dtd->height))) { + OS_DEBUG("FP Width Height doesn't match with Native DTD."); + } +#endif + /* Overwrite native width height as panel width and height */ + display_info->width = display_info->native_dtd->width; + display_info->height = display_info->native_dtd->height; + fp_refresh = display_info->native_dtd->refresh; + } else if (ret && + port->firmware_type != PI_FIRMWARE_DISPLAYID && + dvo_info->upscale) { + /* TODO: + * For time being this function has to assume all upscaling encoders + * are connected to a fixed timing panel if no fixed_timing is + * specified. + * + * Once fixed_timing init-time attribute becomes mandatory, below check + * can be removed. + * + * If customer uses old config system and didn't specified init time + * fixed_timing attribute, then driver assumes it is a fixed-resolution + * panel. If user do specifies fixed_timing attribute, then above check + * will fail, and algorithm continues with whatever value set to + * fixed_res attr. + * + * ret != 0 means no fixed_timing user attribute + * firmware_type == DISPLAYID means firmware provided fixed_timing, + * so don't change it. + */ + display_info->fixed_res = 1; + } + + /* Check native_dtd for fixed_res display */ + if (display_info->fixed_res && !display_info->native_dtd) { + /* This happens if user provides fp_width, fp_height and didn't set + * fixed res parameter. In this case native_dtd will be set as part + * of the while loop while filtering the modes */ + OS_DEBUG("pd_filter_timings: No native dtd for fixed_resolution"); + } + + if (!display_info->width && !display_info->height) { + /* If fp width and height isn't known, then enable all modes as + * non-fixed res display */ + display_info->fixed_res = 0; + } + + OS_DEBUG("fixed_res = %u fixed_timing = %lu", + display_info->fixed_res, fixed_timing); + OS_DEBUG("fp_width = %u, fp_height = %u, fp_refresh = %u", + display_info->width, display_info->height, fp_refresh); + OS_DEBUG("min_dclk = %lu, max_dclk = %lu", + dvo_info->min_dclk, dvo_info->max_dclk); + + /* This function can be called with following + * --------------------------------------------------------------- + * DVO device PanelFit Display AvailableModes + * DOWN UP Fixed? + * -------------------------------------------------------- + * 0 0 0 0 All supported modes + * 1 0 0 0 All supported modes + * 0 1 0 0 All supported modes + * 1 1 0 0 All supported modes + * 0 0 1 0 All supported modes + * 1 0 1 0 All supported modes + * 0 1 1 0 All supported modes + * 1 1 1 0 All supported modes + * + * 0 0 0 Y Only one mode + * 1 0 0 Y Only one mode + * 0 1 0 Y Only one mode + * 1 1 0 Y Only one mode + * 0 0 1 Y Only one mode + * + * 0 1 1 Y All upscalable modes + * 1 0 1 Y All downscalable modes + * + * 1 1 1 Y All UP & DOWN scalable modes + * ------------------------------------------------------------------------- + */ + + for (i = 0; i < 2; ++i) { + j = 0; + timing = in_list; + while(timing->width != PD_TIMING_LIST_END) { + /* If mode supported and dclk is within the range */ + if ((timing->mode_info_flags & PD_MODE_SUPPORTED) && + ((!dvo_info->max_dclk || (timing->dclk <= dvo_info->max_dclk))&& + (!dvo_info->min_dclk || (timing->dclk >= dvo_info->min_dclk)))){ + + if ( + /* fixed_res = 0 */ + !display_info->fixed_res || + + /* no panel fit */ + (!display_info->panel_fit && + timing->refresh == fp_refresh && + timing->width == display_info->width && + timing->height == display_info->height) || + + /* panel fit and upscale or downscale */ + (display_info->panel_fit && + timing->refresh == fp_refresh && + ((dvo_info->upscale && + timing->width <= display_info->width && + timing->height <= display_info->height && + (!dvo_info->upscale_min_width || + timing->width >= dvo_info->upscale_min_width) && + (!dvo_info->upscale_min_height || + timing->height >= dvo_info->upscale_min_height)) +#if 0 + || + (dvo_info->downscale && + timing->width >= display_info->width && + timing->height >= display_info->height && + (!dvo_info->downscale_max_width || + timing->width <= dvo_info->downscale_max_width) && + (!dvo_info->downscale_max_height || + timing->height >= dvo_info->downscale_max_height)) +#endif + ))) { + + if(!i){ + count++; + } else { + /* copy timing */ + olist[j] = *timing; + + /* save the native_dtd timing */ + if ((timing->width == display_info->width) && + (timing->height == display_info->height) && + (timing->refresh == fp_refresh)) { + native_dtd = &(olist[j]); + } + + /* The native DTD pointer is pointing in the in_list, + * reset this pointer to point in the out_list */ + if (timing == display_info->native_dtd) { + display_info->native_dtd = &olist[j]; + } + + j++; + } + } + } + timing++; + if ((timing->width == PD_TIMING_LIST_END) && timing->extn_ptr) { + timing = timing->extn_ptr; + } + } + if(!i) { + count++; + olist = (pd_timing_t *) pd_malloc(count * sizeof(pd_timing_t)); + if(!olist) { + return PD_ERR_NOMEM; + } + } else { + /* Copy the END of LIST entry */ + olist[j] = *timing; + } + } + + /* If there is no native_dtd, then use the first matching + * resolution with fp width and height as native dtd */ + if (!display_info->native_dtd) { + display_info->native_dtd = native_dtd; + } + if (display_info->native_dtd) { + OS_DEBUG("pd_filter_timings: NativeDTD: %ux%u@%u", + display_info->native_dtd->width, + display_info->native_dtd->height, + display_info->native_dtd->refresh); + display_info->native_dtd->mode_info_flags |= PD_MODE_DTD_FP_NATIVE; + } + + *out_list = olist; + return PD_SUCCESS; +} + + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: pd.c,v 1.5 2010/05/18 16:18:27 achrisan Exp $ + * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/pd/cmn/pd.c,v $ + *---------------------------------------------------------------------------- + */ diff --git a/drivers/gpu/drm/emgd/emgd/display/pi/cmn/displayid.c b/drivers/gpu/drm/emgd/emgd/display/pi/cmn/displayid.c new file mode 100644 index 0000000..48baee1 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/pi/cmn/displayid.c @@ -0,0 +1,1058 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: displayid.c + * $Revision: 1.4 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * This file contains functions to parse DisplayID into a data strucuture. + * Supported DisplayID versions: + * VESA DisplayID Standard Verion 1 12/13/2007 + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.dpd + +#include +#include + +#include + +#include +#include + +/*! + * @addtogroup display_group + * @{ + */ + +#ifndef CONFIG_NO_DISPLAYID + +/* IMP NOTE: + * Keep the order of datablocks as it is. + * DisplayID parser directly access the offset using tag as an index. + */ +unsigned short db_offset[] = { +#ifdef CONFIG_MICRO + OS_OFFSETOF(displayid_t, dummy_db), /* PRODUCTID 0x00 */ + OS_OFFSETOF(displayid_t, display_params), /* DISPLAY_PARAMS 0x01 */ + OS_OFFSETOF(displayid_t, dummy_db), /* COLOR_CHARS 0x02 */ + OS_OFFSETOF(displayid_t, dummy_db), /* TIMING_1_DETAIL 0x03 */ + OS_OFFSETOF(displayid_t, dummy_db), /* TIMING_2_DETAIL 0x04 */ + OS_OFFSETOF(displayid_t, dummy_db), /* TIMING_3_SHORT 0x05 */ + OS_OFFSETOF(displayid_t, dummy_db), /* TIMING_4_DMTID 0x06 */ + OS_OFFSETOF(displayid_t, dummy_db), /* VESA_TIMING_STD 0x07 */ + OS_OFFSETOF(displayid_t, dummy_db), /* CEA_TIMING_STD 0x08 */ + OS_OFFSETOF(displayid_t, timing_range), /* VIDEO_RANGE 0x09 */ + OS_OFFSETOF(displayid_t, dummy_db), /* SERIAL_NUMBER 0x0A */ + OS_OFFSETOF(displayid_t, dummy_db), /* ASCII_STRING 0x0B */ + OS_OFFSETOF(displayid_t, display_dev), /* DISPLAY_DEVICE 0x0C */ + OS_OFFSETOF(displayid_t, lvds), /* LVDS_INTERFACE 0x0D */ + OS_OFFSETOF(displayid_t, dummy_db), /* TRANSFER_CHAR 0x0E */ + OS_OFFSETOF(displayid_t, display_intf), /* DISPLAY_INTF 0x0F */ + OS_OFFSETOF(displayid_t, dummy_db), /* STEREO_INTF 0x10 */ +#else + OS_OFFSETOF(displayid_t, productid), /* PRODUCTID 0x00 */ + OS_OFFSETOF(displayid_t, display_params), /* DISPLAY_PARAMS 0x01 */ + OS_OFFSETOF(displayid_t, color_char), /* COLOR_CHARS 0x02 */ + OS_OFFSETOF(displayid_t, dummy_db), /* TIMING_1_DETAIL 0x03 */ + OS_OFFSETOF(displayid_t, dummy_db), /* TIMING_2_DETAIL 0x04 */ + OS_OFFSETOF(displayid_t, dummy_db), /* TIMING_3_SHORT 0x05 */ + OS_OFFSETOF(displayid_t, dummy_db), /* TIMING_4_DMTID 0x06 */ + OS_OFFSETOF(displayid_t, dummy_db), /* VESA_TIMING_STD 0x07 */ + OS_OFFSETOF(displayid_t, dummy_db), /* CEA_TIMING_STD 0x08 */ + OS_OFFSETOF(displayid_t, timing_range), /* VIDEO_RANGE 0x09 */ + OS_OFFSETOF(displayid_t, serial_num), /* SERIAL_NUMBER 0x0A */ + OS_OFFSETOF(displayid_t, general_string), /* ASCII_STRING 0x0B */ + OS_OFFSETOF(displayid_t, display_dev), /* DISPLAY_DEVICE 0x0C */ + OS_OFFSETOF(displayid_t, lvds), /* LVDS_INTERFACE 0x0D */ + OS_OFFSETOF(displayid_t, transfer_char), /* TRANSFER_CHAR 0x0E */ + OS_OFFSETOF(displayid_t, display_intf), /* DISPLAY_INTF 0x0F */ + OS_OFFSETOF(displayid_t, stereo_intf), /* STEREO_INTF 0x10 */ +#endif + + +#if 0 + /* Vendor specific tag is out of order, so it cannot be here. See + * case DATABLOCK_VENDOR_SPECIFIC for implementation. */ + OS_OFFSETOF(displayid_t, vendor), /* VENDOR_SPECIFIC 0x7F */ +#endif +}; + +type_std_t vesa_std_lookup[] = +{ + /* width height refresh flags */ + /* byte 0 bit 0->7 */ + { 640, 350, 85, 0 }, /* bit 0 */ + { 640, 400, 85, 0 }, /* bit 1 */ + { 720, 400, 85, 0 }, /* bit 2 */ + { 640, 480, 60, 0 }, /* bit 3 */ + { 640, 480, 72, 0 }, /* bit 4 */ + { 640, 480, 75, 0 }, /* bit 5 */ + { 640, 480, 85, 0 }, /* bit 6 */ + { 800, 600, 56, 0 }, /* bit 7 */ + + /* byte 1 bit 0->7 */ + { 800, 600, 60, 0 }, /* bit 0 */ + { 800, 600, 72, 0 }, /* bit 1 */ + { 800, 600, 75, 0 }, /* bit 2 */ + { 800, 600, 85, 0 }, /* bit 3 */ + { 800, 600, 120, PD_MODE_RB }, /* bit 4 */ + { 848, 480, 60, 0 }, /* bit 5 */ + { 1024, 768, 43, PD_SCAN_INTERLACE }, /* bit 6 */ + { 1024, 768, 60, 0 }, /* bit 7 */ + + /* byte 2 bit 0->7 */ + { 1024, 768, 70, 0 }, /* bit 0 */ + { 1024, 768, 75, 0 }, /* bit 1 */ + { 1024, 768, 85, 0 }, /* bit 2 */ + { 1024, 768, 120, PD_MODE_RB }, /* bit 3 */ + { 1152, 864, 75, 0 }, /* bit 4 */ + { 1280, 768, 60, PD_MODE_RB }, /* bit 5 */ + { 1280, 768, 60, 0 }, /* bit 6 */ + { 1280, 768, 75, 0 }, /* bit 7 */ + + /* byte 3 bit 0->7 */ + { 1280, 768, 85, 0 }, /* bit 0 */ + { 1280, 768, 120, PD_MODE_RB }, /* bit 1 */ + { 1280, 800, 60, PD_MODE_RB }, /* bit 2 */ + { 1280, 800, 60, 0 }, /* bit 3 */ + { 1280, 800, 75, 0 }, /* bit 4 */ + { 1280, 800, 85, 0 }, /* bit 5 */ + { 1280, 800, 120, PD_MODE_RB }, /* bit 6 */ + { 1280, 960, 60, 0 }, /* bit 7 */ + + /* byte 4 bit 0->7 */ + { 1280, 960, 85, 0 }, /* bit 0 */ + { 1280, 960, 120, PD_MODE_RB }, /* bit 1 */ + { 1280, 1024, 60, 0 }, /* bit 2 */ + { 1280, 1024, 75, 0 }, /* bit 3 */ + { 1280, 1024, 85, 0 }, /* bit 4 */ + { 1280, 1024, 120, PD_MODE_RB }, /* bit 5 */ + { 1360, 768, 60, 0 }, /* bit 6 */ + { 1360, 768, 120, PD_MODE_RB }, /* bit 7 */ + + /* byte 5 bit 0->7 */ + { 1400, 1050, 60, PD_MODE_RB }, /* bit 0 */ + { 1400, 1050, 60, 0 }, /* bit 1 */ + { 1400, 1050, 75, 0 }, /* bit 2 */ + { 1400, 1050, 85, 0 }, /* bit 3 */ + { 1400, 1050, 120, PD_MODE_RB }, /* bit 4 */ + { 1440, 900, 60, PD_MODE_RB }, /* bit 5 */ + { 1440, 900, 60, 0 }, /* bit 6 */ + { 1440, 900, 75, 0 }, /* bit 7 */ + + /* byte 6 bit 0->7 */ + { 1440, 900, 85, 0 }, /* bit 0 */ + { 1440, 900, 120, PD_MODE_RB }, /* bit 1 */ + { 1600, 1200, 60, 0 }, /* bit 2 */ + { 1600, 1200, 65, 0 }, /* bit 3 */ + { 1600, 1200, 70, 0 }, /* bit 4 */ + { 1600, 1200, 75, 0 }, /* bit 5 */ + { 1600, 1200, 85, 0 }, /* bit 6 */ + { 1600, 1200, 120, PD_MODE_RB }, /* bit 7 */ + + /* byte 7 bit 0->7 */ + { 1680, 1050, 60, PD_MODE_RB }, /* bit 0 */ + { 1680, 1050, 60, 0 }, /* bit 1 */ + { 1680, 1050, 75, 0 }, /* bit 2 */ + { 1680, 1050, 85, 0 }, /* bit 3 */ + { 1680, 1050, 120, PD_MODE_RB }, /* bit 4 */ + { 1792, 1344, 60, 0 }, /* bit 5 */ + { 1792, 1344, 75, 0 }, /* bit 6 */ + { 1792, 1344, 120, PD_MODE_RB }, /* bit 7 */ + + /* byte 8 bit 0->7 */ + { 1856, 1392, 60, 0 }, /* bit 0 */ + { 1856, 1392, 75, 0 }, /* bit 1 */ + { 1856, 1392, 120, PD_MODE_RB }, /* bit 2 */ + { 1920, 1200, 60, PD_MODE_RB }, /* bit 3 */ + { 1920, 1200, 60, 0 }, /* bit 4 */ + { 1920, 1200, 75, 0 }, /* bit 5 */ + { 1920, 1200, 85, 0 }, /* bit 6 */ + { 1920, 1200, 120, PD_MODE_RB }, /* bit 7 */ + + /* byte 9 bit 0->7 */ + { 1920, 1440, 60, 0 }, /* bit 0 */ + { 1920, 1440, 75, 0 }, /* bit 1 */ + { 1920, 1440, 120, PD_MODE_RB }, /* bit 2 */ + { 2560, 1600, 60, PD_MODE_RB }, /* bit 3 */ + { 2560, 1600, 60, 0 }, /* bit 4 */ + { 2560, 1600, 75, 0 }, /* bit 5 */ + { 2560, 1600, 85, 0 }, /* bit 6 */ + { 2560, 1600, 120, PD_MODE_RB }, /* bit 7 */ +}; + +#ifndef CONFIG_MICRO +/*! + * Function to replace common timings in 1st list with 2nd list, 2nd list + * is unchanged. + * + * @param dtds1 + * @param dtds2 + * + * @return void + */ +void replace_vesa_dtds_with_cea_dtds(igd_timing_info_t *dtds1, + igd_timing_info_t *dtds2) +{ + igd_timing_info_t *temp; + + if (!dtds2 || !dtds1) { + return; + } + + while (dtds1->width != IGD_TIMING_TABLE_END) { + temp = dtds2; + + while (temp->width != IGD_TIMING_TABLE_END) { + if ((temp->width == dtds1->width) && + (temp->height == dtds1->height) && + (temp->refresh == dtds1->refresh)) { + dtds1->mode_info_flags &= ~PD_MODE_SUPPORTED; + } + temp++; + } + dtds1++; + } +} +#endif + +#ifdef DEBUG_FIRMWARE +/*! + * + * @param db + * + * @return void + */ +void displayid_print_datablock(datablock_t *db) +{ + unsigned char payload_string[800]; + unsigned char i, j; + + /* Get the payload data into a string */ + OS_MEMSET(payload_string, 0, sizeof(payload_string)); + for (i=0, j=0; ipayload; i++,j+=5) { + payload_string[j] = '0'; + payload_string[j+1] = 'x'; + if ((db->payload_data[i]>>4) <= 0x9) { + payload_string[j+2] = '0' + (db->payload_data[i]>>4); + } else { + payload_string[j+2] = 'A' + (db->payload_data[i]>>4) - 0xA; + } + if ((db->payload_data[i] & 0x0F) <= 0x9) { + payload_string[j+3] = '0' + (db->payload_data[i]&0x0F); + } else { + payload_string[j+3] = 'A' + (db->payload_data[i]&0x0F) - 0xA; + } + payload_string[j+4] = ' '; + } + payload_string[j] = '\0'; + + OS_DEBUG("Tag = %u", db->tag); + OS_DEBUG("Version = %u", db->revision); + OS_DEBUG("Payload = %u", db->payload); + OS_DEBUG("Payload data = %s", payload_string); +} + +/*! + * + * @param buffer + * @param did + * + * @return void + */ +void displayid_print(unsigned char *buffer, displayid_t *did) +{ + unsigned short i; + display_params_t *dp = &did->display_params; + timing_range_t *tr = &did->timing_range; + lvds_display_t *ld = &did->lvds; + display_dev_t *dd = &did->display_dev; + display_intf_t *di = &did->display_intf; +#ifndef CONFIG_MICRO + productid_t *pi = &did->productid; + color_char_t *cc = &did->color_char; + serial_number_t *sn = &did->serial_num; + general_string_t *gs = &did->general_string; + transfer_char_t *tc = &did->transfer_char; + stereo_intf_t *si = &did->stereo_intf; + vendor_t *vi = &did->vendor; +#endif + + DISPLAYID_PRINT_LINE(); + OS_DEBUG("DisplayID Version: %d", did->version); + OS_DEBUG("DisplayID Revision: %d", did->revision); + DISPLAYID_PRINT_LINE(); + OS_DEBUG("Size of different structures:"); + DISPLAYID_PRINT_LINE(); + OS_DEBUG(" displayid_t = %d", sizeof(displayid_t)); + OS_DEBUG("display_params_t = %d", sizeof(display_params_t)); + OS_DEBUG(" type1_dtd_t = %d", sizeof(type1_dtd_t)); + OS_DEBUG(" type2_dtd_t = %d", sizeof(type2_dtd_t)); + OS_DEBUG(" type3_cvt_t = %d", sizeof(type3_cvt_t)); + OS_DEBUG(" type_std_t = %d", sizeof(type_std_t)); + OS_DEBUG(" timing_range_t = %d", sizeof(timing_range_t)); + OS_DEBUG(" display_dev_t = %d", sizeof(display_dev_t)); + OS_DEBUG(" lvds_display_t = %d", sizeof(lvds_display_t)); + OS_DEBUG(" display_intf_t = %d", sizeof(display_intf_t)); + OS_DEBUG(" dummy_db = %d", 256); + OS_DEBUG(" timings = %d", + sizeof(pd_timing_t)*DISPLAYID_MAX_NUM_TIMINGS); + OS_DEBUG(" attrs = %d", + sizeof(pd_attr_t)*DISPLAYID_MAX_ATTRS); + +#ifndef CONFIG_MICRO + OS_DEBUG(" productid_t = %d", sizeof(productid_t)); + OS_DEBUG(" color_char_t = %d", sizeof(color_char_t)); + OS_DEBUG(" serial_number_t = %d", sizeof(serial_number_t)); + OS_DEBUG("general_string_t = %d", sizeof(general_string_t)); + OS_DEBUG(" transfer_char_t = %d", sizeof(transfer_char_t)); + OS_DEBUG(" stereo_intf_t = %d", sizeof(stereo_intf_t)); + OS_DEBUG(" vendor_t = %d", sizeof(vendor_t)); + + DISPLAYID_PRINT_LINE(); + OS_DEBUG("PRODUCT ID DATA BLOCK"); + DISPLAYID_PRINT_LINE(); + displayid_print_datablock((datablock_t *)pi); + OS_DEBUG(" vendor = %c%c%c", + pi->vendor[0], pi->vendor[1], pi->vendor[2]); + OS_DEBUG(" product_code = %u", pi->product_code); + OS_DEBUG("serial_number = %lu", pi->serial_number); + OS_DEBUG(" manf_week = %u", pi->manf_week); + OS_DEBUG(" manf_year = %u", pi->manf_year+2000); + OS_DEBUG(" string_len = %u", pi->string_size); + OS_DEBUG(" string = %s", pi->string); + + DISPLAYID_PRINT_LINE(); + OS_DEBUG("COLOR CHARACTERISTICS DATA BLOCK"); + DISPLAYID_PRINT_LINE(); + displayid_print_datablock((datablock_t *)cc); + + DISPLAYID_PRINT_LINE(); + OS_DEBUG("SERIAL NUMBER DATA BLOCK"); + DISPLAYID_PRINT_LINE(); + displayid_print_datablock((datablock_t *)sn); + + DISPLAYID_PRINT_LINE(); + OS_DEBUG("GENERAL PURPOSE ASCII STRING DATA BLOCK"); + DISPLAYID_PRINT_LINE(); + displayid_print_datablock((datablock_t *)gs); + + DISPLAYID_PRINT_LINE(); + OS_DEBUG("TRANSFER CHARACTERISTICS DATA BLOCK"); + DISPLAYID_PRINT_LINE(); + displayid_print_datablock((datablock_t *)tc); + + DISPLAYID_PRINT_LINE(); + OS_DEBUG("STEREO INTERFACE DATA BLOCK"); + DISPLAYID_PRINT_LINE(); + displayid_print_datablock((datablock_t *)si); + + DISPLAYID_PRINT_LINE(); + OS_DEBUG("VENDOR SPECIFIC DATA BLOCK"); + DISPLAYID_PRINT_LINE(); + displayid_print_datablock((datablock_t *)vi); +#endif + + DISPLAYID_PRINT_LINE(); + OS_DEBUG("DISPLAY PARAMETERS DATA BLOCK"); + DISPLAYID_PRINT_LINE(); + displayid_print_datablock((datablock_t *)dp); + OS_DEBUG("horz_image_size = %u", dp->horz_image_size); + OS_DEBUG("vert_image_size = %u", dp->vert_image_size); + OS_DEBUG(" horz_pixels = %u", dp->horz_pixels); + OS_DEBUG(" vert_pixels = %u", dp->vert_pixels); + OS_DEBUG(" deinterlacable = %u", dp->deinterlacing); + OS_DEBUG(" fixed_timing = %u", dp->fixed_timing); + OS_DEBUG(" fixed_res = %u", dp->fixed_res); + OS_DEBUG(" aspect_ratio = %u", dp->aspect_ratio); + OS_DEBUG(" native_color_depth(bppc) = %u", dp->native_color_depth+1); + OS_DEBUG("overall_color_depth(bppc) = %u", dp->overall_color_depth+1); + + DISPLAYID_PRINT_LINE(); + OS_DEBUG("VIDEO TIMING RANGESS DATA BLOCK"); + DISPLAYID_PRINT_LINE(); + displayid_print_datablock((datablock_t *)tr); + OS_DEBUG(" min_dclk = %lu KHz", tr->min_dclk); + OS_DEBUG(" max_dclk = %lu KHz", tr->max_dclk); + OS_DEBUG(" min_hrate = %u KHz", tr->min_hrate); + OS_DEBUG(" max_hrate = %u KHz", tr->max_hrate); + OS_DEBUG("min_hblank = %u pixels", tr->min_hblank); + OS_DEBUG(" min_vrate = %u Hz", tr->min_vrate); + OS_DEBUG(" max_vrate = %u Hz", tr->max_vrate); + OS_DEBUG("min_vblank = %u lines", tr->min_vblank); + + DISPLAYID_PRINT_LINE(); + OS_DEBUG("LVDS DISPLAY DATA BLOCK"); + DISPLAYID_PRINT_LINE(); + displayid_print_datablock((datablock_t *)ld); + OS_DEBUG("min_T1 = %u ms", ld->min_t1/10); + OS_DEBUG("max_T1 = %u ms", ld->max_t1*2); + OS_DEBUG("max_T2 = %u ms", ld->max_t2*2); + OS_DEBUG("max_T3 = %u ms", ld->max_t3*2); + OS_DEBUG("min_T4 = %u ms", ld->min_t4*10); + OS_DEBUG("min_T5 = %u ms", ld->min_t5*10); + OS_DEBUG("min_T6 = %u ms", ld->min_t6*10); + + DISPLAYID_PRINT_LINE(); + OS_DEBUG("DISPLAY DEVICE DATA BLOCK"); + DISPLAYID_PRINT_LINE(); + displayid_print_datablock((datablock_t *)dd); + OS_DEBUG(" horz_pixel_count = %u", dd->horz_pixel_count); + OS_DEBUG(" vert_pixel_count = %u", dd->vert_pixel_count); + OS_DEBUG("display_color_depth = %u", dd->display_color_depth); + + DISPLAYID_PRINT_LINE(); + OS_DEBUG("DISPLAY INTERFACE DATA BLOCK"); + DISPLAYID_PRINT_LINE(); + displayid_print_datablock((datablock_t *)di); + OS_DEBUG(" num_channels = %u", di->num_channels); + OS_DEBUG(" intf_type = %u", di->intf_type); + OS_DEBUG(" RGB_color_depth = %u", di->rgb_color_depth); + OS_DEBUG("YCrCb_444_color_depth = %u", di->ycbcr_444_color_depth); + OS_DEBUG("YCrCb_422_color_depth = %u", di->ycbcr_422_color_depth); + if(di->intf_type == INTERFACE_LVDS) { + OS_DEBUG(" openldi = %u", di->lvds.openldi); + } + + DISPLAYID_PRINT_LINE(); + OS_DEBUG("Detailed Timing Descriptors"); + DISPLAYID_PRINT_LINE(); + + for (i=0; inum_timings; i++) { + OS_DEBUG("DTD: %u", i+1); + OS_DEBUG(" dclk = %lu", did->timings[i].dclk); + OS_DEBUG(" hactive = %u", did->timings[i].width); + OS_DEBUG(" htotal = %u", did->timings[i].htotal); + OS_DEBUG(" hblank_start = %u", did->timings[i].hblank_start); + OS_DEBUG(" hsync_start = %u", did->timings[i].hsync_start); + OS_DEBUG(" hsync_end = %u", did->timings[i].hsync_end); + OS_DEBUG(" hblank_end = %u", did->timings[i].hblank_end); + OS_DEBUG(" vactive = %u", did->timings[i].height); + OS_DEBUG(" vtotal = %u", did->timings[i].vtotal); + OS_DEBUG(" vblank_start = %u", did->timings[i].vblank_start); + OS_DEBUG(" vsync_start = %u", did->timings[i].vsync_start); + OS_DEBUG(" vsync_end = %u", did->timings[i].vsync_end); + OS_DEBUG(" vblank_end = %u", did->timings[i].vblank_end); + OS_DEBUG(" native = %u", + (did->timings[i].mode_info_flags&PD_MODE_DTD_FP_NATIVE)?1:0); + OS_DEBUG(" interlace = %u", + (did->timings[i].mode_info_flags&PD_SCAN_INTERLACE)?1:0); + OS_DEBUG("hsync_polarity = %s", + (did->timings[i].mode_info_flags & PD_HSYNC_HIGH)? + "ACTIVE HIGH":"ACTIVE LOW"); + OS_DEBUG("vsync_polarity = %s", + (did->timings[i].mode_info_flags & PD_VSYNC_HIGH)? + "ACTIVE HIGH":"ACTIVE LOW"); + DISPLAYID_PRINT_LINE(); + } + + /* Print the attributes */ + if (did->num_attrs) { + OS_DEBUG("\tAttr\tID\tVALUE"); + OS_DEBUG("----------------------"); + for (i=0; inum_attrs; i++) { + OS_DEBUG("\t%u\t%lu\t%lu", i+1, did->attr_list[i].id, + did->attr_list[i].current_value); + } + OS_DEBUG("----------------------"); + } +} +#endif + +/*! + * Function to convert Type I - Detailed to pd_timing_t + * + * @param timing + * @param dtd + * + * @return void + */ +void convert_type1_to_pd(pd_timing_t *timing, type1_dtd_t *dtd) +{ + unsigned long refresh; + timing->dclk = /* change to KHz */ + ((unsigned long)dtd->dclk.lsb_dclk| + ((unsigned long)dtd->dclk.msb_dclk<<16))*10; + + /* DisplayID fields are 0 based but should be interpreted as 1-based. + * For example hsync_width value can be read as 0-65,535 pixels but + * interpreted as 1-65,536. So, to get the right value add 1. + * But pd_timing_t values are 0 based except width and height, + * so care should be taken while converting DisplayID fields into + * pd_timing_t values */ + timing->hblank_start = dtd->hactive; + timing->width = dtd->hactive + 1; + timing->hblank_end = timing->hblank_start + dtd->hblank + 1; + timing->hsync_start = timing->hblank_start + dtd->hsync_offset + 1; + timing->hsync_end = timing->hsync_start + dtd->hsync_width + 1; + timing->htotal = timing->hblank_end; + + timing->vblank_start = dtd->vactive; + timing->height = dtd->vactive + 1; + timing->vblank_end = timing->vblank_start + dtd->vblank + 1; + timing->vsync_start = timing->vblank_start + dtd->vsync_offset + 1; + timing->vsync_end = timing->vsync_start + dtd->vsync_width + 1; + timing->vtotal = timing->vblank_end; + + refresh = ((timing->dclk * 1000L)/timing->htotal)/timing->vtotal; + timing->refresh = (unsigned short) refresh; + + timing->mode_info_flags = PD_MODE_DTD|PD_MODE_SUPPORTED; + if (dtd->hsync_polarity) { + timing->mode_info_flags |= PD_HSYNC_HIGH; + } + if (dtd->vsync_polarity) { + timing->mode_info_flags |= PD_VSYNC_HIGH; + } + if (dtd->interlaced) { + timing->mode_info_flags |= PD_SCAN_INTERLACE; + } + if (dtd->preferred) { + timing->mode_info_flags |= PD_MODE_DTD_FP_NATIVE; + } +} + +/*! + * Function to convert Type II - Detailed to pd_timing_t + * + * @param timing + * @param dtd + * + * @return void + */ +void convert_type2_to_pd(pd_timing_t *timing, type2_dtd_t *dtd) +{ + unsigned long refresh; + timing->dclk = /* change to KHz */ + ((unsigned long)dtd->dclk.lsb_dclk| + ((unsigned long)dtd->dclk.msb_dclk<<16))*10; + + /* DisplayID fields are 0 based but should be interpreted as 1-based. + * For example hsync_width value can be read as 0-15 OCTETs but + * interpreted as 1-16 OCTETs. So, to get the right value add 1. + * But pd_timing_t values are 0 based except width and height, + * so care should be taken while converting DisplayID fields into + * pd_timing_t values */ + timing->width = (dtd->hactive + 1) * 8; /* change to pixels */ + timing->hblank_start = timing->width - 1; + timing->hblank_end = timing->hblank_start + (dtd->hblank + 1) * 8; + timing->hsync_start = timing->hblank_start + (dtd->hsync_offset + 1) * 8; + timing->hsync_end = timing->hsync_start + (dtd->hsync_width + 1) * 8; + timing->htotal = timing->hblank_end; + + timing->vblank_start = dtd->vactive; + timing->height = dtd->vactive + 1; + timing->vblank_end = timing->vblank_start + dtd->vblank + 1; + timing->vsync_start = timing->vblank_start + dtd->vsync_offset + 1; + timing->vsync_end = timing->vsync_start + dtd->vsync_width + 1; + timing->vtotal = timing->vblank_end; + + refresh = ((timing->dclk * 1000L)/timing->htotal)/timing->vtotal; + timing->refresh = (unsigned short) refresh; + + timing->mode_info_flags = PD_MODE_DTD|PD_MODE_SUPPORTED; + if (dtd->interlaced) { + timing->mode_info_flags |= PD_SCAN_INTERLACE; + } + if (dtd->preferred) { + timing->mode_info_flags |= PD_MODE_DTD_FP_NATIVE; + } +} + +/*! + * Function to filter timing table based on range block + * + * @param tt + * @param range + * @param firmware_type + * + * @return void + */ +void displayid_filter_range_timings(pd_timing_t *tt, timing_range_t *range, + unsigned char firmware_type) +{ + unsigned short hfreq; + +#define _HUNDRETHS(_n, _d) ((100*_n)/_d)-((100*_n_d)/100), + + #ifdef DEBUG_FIRMWARE + char result_str[60]; + unsigned char pass_count = 0; + unsigned char fail_count = 0; + + OS_DEBUG("Range limits:"); + OS_DEBUG("\tmin_dclk = %lu KHz max_dclk = %lu KHz", + range->min_dclk, range->max_dclk); + OS_DEBUG("\t h_min = %u h_max = %u KHz", + range->min_hrate, range->max_hrate); + OS_DEBUG("\t v_min = %u v_max = %u", + range->min_vrate,range->max_vrate); + OS_DEBUG("WIDTH\tHEIGHT\tREFRESH\tH-FREQ\tDOTCLOCK\tRESULT"); + OS_DEBUG(" \t \t (Hz) \t (KHz)\t (MHz) \t "); + OS_DEBUG("=====\t======\t=======\t======\t========\t======"); +#endif + + /* If the display is a discreate frequency display, don't enable any + * intermediate timings. Only continuous frequency displays requires + * enabling range timings */ + if (range->discrete_display) { + OS_DEBUG("Discrete display: Ranges aren't used."); + return; + } + + /* If no timing table return */ + if (tt == NULL) { + return; + } + + /* Mark the timings that fall in the ranges */ + /* Compare + * dclk in KHz + * hfreq in KHz + * vfreq in Hz */ + while(tt->width != IGD_TIMING_TABLE_END) { + hfreq = (unsigned short)(tt->dclk/(unsigned long)tt->htotal); /* KHz */ + if ((tt->dclk >= (unsigned long)range->min_dclk)&& /* compare KHz */ + (tt->dclk <= (unsigned long)range->max_dclk)&& /* compare KHz */ + (tt->refresh >= range->min_vrate) && /* compare Hz */ + (tt->refresh <= range->max_vrate) && /* compare Hz */ + (hfreq >= range->min_hrate) && /* compare KHz */ + (hfreq <= range->max_hrate) && /* compare KHz */ + (tt->hblank_end - tt->hblank_start) > range->min_hblank && + (tt->vblank_end - tt->vblank_start) > range->min_vblank) { + tt->mode_info_flags |= PD_MODE_SUPPORTED; +#ifdef DEBUG_FIRMWARE + if (tt->mode_info_flags & PD_MODE_SUPPORTED) { + OS_DEBUG("%5u\t%6u\t%7u\t%6u.%2u\t%8u.%2u\tPASSED", + tt->width, tt->height, tt->refresh, + tt->dclk/tt->htotal, + _HUNDRETHS(tt->dclk,tt->htotal), + tt->dclk/1000, + _HUNDRETHS(tt->dclk,1000); + + pass_count++; + } else { + } +#endif + } else { + /* Unmark the mode that falls out of range */ + /* DTD, FACTORY and NATIVE timings are "GOLD" even if they + * fall outside the range limits */ + if (!(tt->mode_info_flags & + (PD_MODE_DTD|PD_MODE_FACTORY|PD_MODE_DTD_FP_NATIVE))) { +#ifdef DEBUG_FIRMWARE + if ((tt->dclk < /* compare KHz */ + (unsigned long)range->min_dclk)|| + (tt->dclk > + (unsigned long)range->max_dclk)) { + OS_MEMCPY(result_str, "FAILED DCLK \0", 16); + fail_count++; + } else if ((tt->refresh > range->max_vrate) || + (tt->refresh < range->min_vrate)) { + OS_MEMCPY(result_str, "FAILED REFRESH \0", 16); + fail_count++; + } else if ((hfreq < range->min_hrate) || + (hfreq > range->max_hrate)) { + OS_MEMCPY(result_str, "FAILED H-FREQ \0", 16); + fail_count++; + } else if ((tt->hblank_end-tt->hblank_start) < + range->min_hblank){ + OS_MEMCPY(result_str, "FAILED MIN_HBLK\0", 16); + } else if ((tt->vblank_end-tt->vblank_start) < + range->min_vblank){ + OS_MEMCPY(result_str, "FAILED MIN_VBLK\0", 16); + } + OS_DEBUG("%5u\t%6u\t%7u\t%6u.%2u\t%8u.%2u\t%s", + tt->width, tt->height, tt->refresh, + tt->dclk/tt->htotal, + _HUNDRETHS(tt->dclk,tt->htotal), + tt->dclk/1000, + _HUNDRETHS(tt->dclk,1000), + result_str); + ((float) tt->dclk)/1000, result_str); + + /* TODO: For multiple range blocks, don't disable the modes + * that are outside the range. We already started with + * an "empty supported table" */ + + /* But above assertion of "empty supported table" broke + * if EDID ETF rules were met to enable all timings. + * See edid.c for ETF conditions. So below line + * cannot be commented out to support multiple range + * blocks for DisplayID. */ +#endif + tt->mode_info_flags &= ~PD_MODE_SUPPORTED; + } + } + tt++; + if (tt->width == IGD_TIMING_TABLE_END && tt->extn_ptr) { + tt = tt->extn_ptr; + } + } +#ifdef DEBUG_FIRMWARE + OS_DEBUG("pass count = %u, fail count = %u total = %u", + pass_count, fail_count, pass_count+fail_count); +#endif +} /* end displayid_filter_range_timings() */ + +#define VESA_STD 1 +#define CEA_STD 2 + +/*! + * Function to enable std timings: VESA STD or CEA STD + * + * @param tt1 + * @param db_data + * @param lookup + * @param num_lookup + * @param std_type + * + * @return void + */ +void displayid_enable_std_timings(pd_timing_t *tt1, unsigned char *db_data, + type_std_t *lookup, unsigned short num_lookup, unsigned char std_type) +{ + unsigned short i; + pd_timing_t *tt; + /* If no timing table return. This can happen if no edid_avail set not to + * use std timings */ + if (!tt1) { + return; + } + + /* For every factory supported mode, enable it in the timing table */ + for (i = 0; i < num_lookup; i++) { + tt = tt1; + /* i>>3 is nothing but dividing by 8, that gives the byte number, + * i&0x7 is nothing but getting the bit position in that byte */ + if (db_data[i>>3] & 1<<(i&0x7)) { + while(tt->width != IGD_TIMING_TABLE_END) { + if (lookup[i].width == tt->width && + lookup[i].height == tt->height && +#if 0 + (!((lookup[i].flags & (PD_SCAN_INTERLACE|PD_MODE_RB)) ^ + (tt->mode_info_flags & (PD_SCAN_INTERLACE|PD_MODE_RB)))) && +#endif + (!((lookup[i].flags & PD_SCAN_INTERLACE) ^ + (tt->mode_info_flags & PD_SCAN_INTERLACE))) && + (!((lookup[i].flags & PD_ASPECT_16_9) ^ + (tt->mode_info_flags & PD_ASPECT_16_9))) && + lookup[i].refresh == tt->refresh) { + tt->mode_info_flags |= (PD_MODE_FACTORY|PD_MODE_SUPPORTED); + break; + } + tt++; + if (tt->width == IGD_TIMING_TABLE_END && tt->extn_ptr) { + tt = tt->extn_ptr; + } + } + } + } +} + +/*! + * Function to parse DisplayID + * + * @param buffer + * @param did + * @param timing_table + * @param count + * @param upscale + * + * @return void + */ +int displayid_parse( + unsigned char *buffer, + displayid_t *did, + pd_timing_t *timing_table, + int count, + unsigned char upscale) +{ + //unsigned char e = 0; + unsigned char checksum = 0, bytes_left; + unsigned short i; + unsigned short did_size; +#ifndef CONFIG_MICRO + pd_timing_t *cea_tmg_table; +#endif + /* Read 4 bytes: (DisplayID Header) + * version, revision + * payload + * display product type identifier + * number of extensions */ + *(unsigned long *) did = *(unsigned long *)buffer; + + /* Check for version and revision */ + if (did->version != 1 && did->revision != 0) { + OS_DEBUG("DisplayID Version %d.%d Unknown. Will Ignore.", + did->version, did->revision); + return DISPLAYID_NOT_SUPPORTED; + } + + if (did->payload > 251) { + OS_DEBUG("DispID: Error: payload = %u not in [0..251]", did->payload); + return DISPLAYID_ERROR_PARSE; + } + + /* Check sum check */ + /* +5 is for 5 mandatory bytes */ + did_size = (unsigned short) (did->payload + 5); + OS_DEBUG("DisplayID size = %u", did_size); + for (i = 0; i < did_size; i++) { + checksum += buffer[i]; + } + + /* bytes_left starts without DisplayID header */ + bytes_left = did->payload; + /* current pointer is at 4 not at 5, because checksum byte is at the end */ + buffer += 4; + + if (checksum) { + OS_DEBUG("DisplayID checksum is incorrect! Will ignore."); + return DISPLAYID_ERROR_PARSE; + } + + /* DisplayID parsing should start by disabling all modes. + * Based on DisplayID data blocks modes will be enabled. */ + enable_disable_timings(timing_table, 0); + + /* Repeat for all extensions */ + //e = did->num_extensions; + //while (e) { + { + //if (e != did->num_extensions) { + /* TODO: If there aren't enough bytes left in the buffer, + * call I2C read function to read next DisplayID section */ + + /* Skip next section header 4 bytes */ + //bytes_left -= 4; + //break; + //} + + /* Parse Data Blocks */ + /* Check minimum number of bytes required for Data Block were left */ + while ((bytes_left > 3) && (bytes_left >= (buffer[2]+3))) { + unsigned char *db_data; + unsigned char payload = buffer[2] + 3; + + /* displayid->datablock = buffer (for payload bytes) */ + if (buffer[0] < sizeof(db_offset)/sizeof(unsigned short)) { + OS_MEMCPY(((unsigned char*)did) + db_offset[buffer[0]], + buffer, payload); + } + + /* db_data points to payload data after db header (3 bytes), + * Note: dummy_db offset is used for some DATA BLOCKS. See + * db_offset table above. */ + db_data = (unsigned char *) &did->dummy_db[3]; + + switch (buffer[0]) { + /* Supported in Driver and VBIOS */ + case DATABLOCK_DISPLAY_PARAMS: + /* Use following fields for fp_info: + * embedded use: fixed timing + * horizontal pixels: fp_width + * vertical pixels: fp_height */ + did->attr_list[did->num_attrs].id = PD_ATTR_ID_PANEL_DEPTH; + did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED; + did->attr_list[did->num_attrs++].current_value = + (did->display_params.overall_color_depth+1)*3; + break; + + case DATABLOCK_TIMING_1_DETAIL: + /* One Type I block can have multiple DTDs */ + while (payload>=20&&did->num_timingstimings[did->num_timings++], + (type1_dtd_t *)db_data); + db_data += 20; + payload -= 20; + bytes_left -= 20; + buffer += 20; + } + /* Mark the end of the list */ + did->timings[did->num_timings].width = IGD_TIMING_TABLE_END; + break; + + case DATABLOCK_TIMING_2_DETAIL: + /* One Type II block can have multiple DTDs */ + while (payload>=11&&did->num_timingstimings[did->num_timings++], + (type2_dtd_t *)db_data); + db_data += 11; + payload -= 11; + bytes_left -= 11; + buffer += 11; + } + did->timings[did->num_timings].width = IGD_TIMING_TABLE_END; + break; + + case DATABLOCK_VESA_TIMING_STD: + /* VESA Standard Timings */ + displayid_enable_std_timings( + timing_table, + db_data, + vesa_std_lookup, + sizeof(vesa_std_lookup)/sizeof(type_std_t), + VESA_STD); + break; + + case DATABLOCK_VIDEO_RANGE: + /* convert from Hz/10,000 -> KHz by multiplying by 10 */ + did->timing_range.min_dclk = + ((unsigned long)did->timing_range.mindclk.lsb_min_dclk| + ((unsigned long)did->timing_range.mindclk.msb_min_dclk + <<16))*10; + + did->timing_range.max_dclk = + ((unsigned long)did->timing_range.maxdclk.lsb_max_dclk| + ((unsigned long)did->timing_range.maxdclk.msb_max_dclk + <<16))*10; + displayid_filter_range_timings(timing_table,&did->timing_range, + PI_FIRMWARE_DISPLAYID); + break; + + case DATABLOCK_DISPLAY_DEVICE: + /* Get panel color depth */ + did->attr_list[did->num_attrs].id = PD_ATTR_ID_PANEL_DEPTH; + did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED; + did->attr_list[did->num_attrs++].current_value = + (did->display_dev.display_color_depth+1)*3; + break; + + case DATABLOCK_LVDS_INTERFACE: + /* Get T1-T5 values */ + did->attr_list[did->num_attrs].id = PD_ATTR_ID_FP_PWR_T1; + did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED; + did->attr_list[did->num_attrs++].current_value = + did->lvds.max_t1*2 + did->lvds.max_t2*2; + + did->attr_list[did->num_attrs].id = PD_ATTR_ID_FP_PWR_T2; + did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED; + did->attr_list[did->num_attrs++].current_value = + did->lvds.min_t5*10; + + did->attr_list[did->num_attrs].id = PD_ATTR_ID_FP_PWR_T3; + did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED; + did->attr_list[did->num_attrs++].current_value = + did->lvds.min_t6*10; + + did->attr_list[did->num_attrs].id = PD_ATTR_ID_FP_PWR_T4; + did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED; + did->attr_list[did->num_attrs++].current_value = + did->lvds.max_t3*2; + + did->attr_list[did->num_attrs].id = PD_ATTR_ID_FP_PWR_T5; + did->attr_list[did->num_attrs].flags=PD_ATTR_FLAG_VALUE_CHANGED; + did->attr_list[did->num_attrs++].current_value = + did->lvds.min_t4*10 + did->lvds.max_t1*2; + break; + + case DATABLOCK_DISPLAY_INTF: + if (did->display_intf.intf_type == INTERFACE_LVDS) { + /* Get number of channels: 0=singlechannel 1=dualchannel */ + did->attr_list[did->num_attrs].id = + PD_ATTR_ID_2_CHANNEL_PANEL; + did->attr_list[did->num_attrs].flags = + PD_ATTR_FLAG_VALUE_CHANGED; + if (did->display_intf.num_channels == 2) { + did->attr_list[did->num_attrs++].current_value = 1; + } + + /* Get panel type value: 0=normal 1=OpenLDI */ + did->attr_list[did->num_attrs].id = + PD_ATTR_ID_LVDS_PANEL_TYPE; + did->attr_list[did->num_attrs].flags = + PD_ATTR_FLAG_VALUE_CHANGED; + did->attr_list[did->num_attrs++].current_value = + did->display_intf.lvds.openldi; + } + + break; + +#ifndef CONFIG_MICRO + /* Support in Driver only */ + case DATABLOCK_PRODUCTID: + break; + + case DATABLOCK_SERIAL_NUMBER: + break; + + case DATABLOCK_ASCII_STRING: + break; + + case DATABLOCK_VENDOR_SPECIFIC: + /* Because vendor specific datablock tag is out-of-order, + * copy data from buffer to vendor structure */ + OS_MEMCPY(&did->vendor, buffer, buffer[2] + 3); + break; + + /* Future support in Driver and VBIOS */ + case DATABLOCK_TIMING_3_SHORT: + break; + + case DATABLOCK_TIMING_4_DMTID: + break; + + /* Future support in Driver */ + case DATABLOCK_COLOR_CHARS: + break; + + case DATABLOCK_CEA_TIMING_STD: + cea_tmg_table = (igd_timing_info_t *) + OS_ALLOC(cea_timing_table_size); + OS_MEMCPY(cea_tmg_table, cea_timing_table, + cea_timing_table_size); + /* Disable the CEA timings */ + enable_disable_timings(cea_tmg_table, 0); + displayid_enable_std_timings( + cea_tmg_table, + db_data, + cea_std_lookup, + (unsigned short)cea_std_lookup_size, + CEA_STD); + + replace_vesa_dtds_with_cea_dtds(timing_table, cea_tmg_table); + cea_tmg_table[cea_timing_table_size-1].extn_ptr = + (void *)timing_table; + timing_table = cea_tmg_table; + break; +#endif + case DATABLOCK_TRANSFER_CHAR: + break; + } + + /* Subtract data block payload */ + bytes_left -= payload; + buffer += payload; + } + /* Extension count */ + //e--; + } + + return 0; +} + +#endif + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: displayid.c,v 1.4 2010/04/27 20:33:49 bpaauwe Exp $ + * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/pi/cmn/displayid.c,v $ + *---------------------------------------------------------------------------- + */ diff --git a/drivers/gpu/drm/emgd/emgd/display/pi/cmn/edid.c b/drivers/gpu/drm/emgd/emgd/display/pi/cmn/edid.c new file mode 100644 index 0000000..cf9127e --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/pi/cmn/edid.c @@ -0,0 +1,1185 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: edid.c + * $Revision: 1.4 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * This file is contains all necessary functions for EDID reading and + * parsing into a data strucutures. + * Supported EDID versions: + * EDID 1.3 (backward compatible with 1.1, 1.2) + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.dpd + +#include + +#include + +#include +#include +#include +#include + +/*! + * @addtogroup display_group + * @{ + */ + +/* Function to read EDID */ +/* Local functions */ +static void edid_mark_standard_timings( + unsigned char *buffer, + pd_timing_t *timings, + int established); + +static void edid_mark_detailed_timings( + unsigned char *buffer, + edid_t *edid, + pd_timing_t *timings, + unsigned char upscale); + +static void edid_parse_monitor_name( + unsigned char *buffer, + char *name); + +/* Edid Releated Constants */ + +static const unsigned char name_blockid[] = {0x00, 0x00, 0x00, 0xfc}; +static const unsigned char range_blockid[] = {0x00, 0x00, 0x00, 0xfd}; +static const unsigned char st_blockid[] = {0x00, 0x00, 0x00, 0xfa}; +static const unsigned char timings_mask[] = {0xff, 0xff, 0xff, 0x00}; +extern igd_timing_info_t cea_timing_table[]; +/* + * Translation from the "Established" bit field position to a + * hactive, vactive, refresh that can be searched for in the + * timings list. + */ +static unsigned char established_table[] = { + /* 800x600 @ 60Hz */ + 0x20, 0x03, 0x58, 0x02, 0x3c, 0x00, + /* 800x600 @ 56Hz */ + 0x20, 0x03, 0x58, 0x02, 0x38, 0x00, + /* 640x480 @ 75Hz */ + 0x80, 0x02, 0xe0, 0x01, 0x4b, 0x00, + /* 640x480 @ 72Hz */ + 0x80, 0x02, 0xe0, 0x01, 0x48, 0x00, + /* 640x480 @ 67Hz */ + 0x80, 0x02, 0xe0, 0x01, 0x43, 0x00, + /* 640x480 @ 60Hz */ + 0x80, 0x02, 0xe0, 0x01, 0x3c, 0x00, + /* 720x400 @ 88Hz */ + 0xd0, 0x02, 0x90, 0x01, 0x58, 0x00, + /* 720x400 @ 70Hz */ + 0xd0, 0x02, 0x90, 0x01, 0x46, 0x00, + + /* 1280x1024 @ 75Hz */ + 0x00, 0x05, 0x00, 0x04, 0x4b, 0x00, + /* 1024x768 @ 75Hz */ + 0x00, 0x04, 0x00, 0x03, 0x4b, 0x00, + /* 1024x768 @ 70Hz */ + 0x00, 0x04, 0x00, 0x03, 0x46, 0x00, + /* 1024x768 @ 60Hz */ + 0x00, 0x04, 0x00, 0x03, 0x3c, 0x00, + /* 1024x768 @ 43Hz (i) */ + 0x00, 0x04, 0x00, 0x03, 0x2b, 0x00, + /* 832x624 @ 75Hz */ + 0x40, 0x03, 0x70, 0x02, 0x4b, 0x00, + /* 800x600 @ 75Hz */ + 0x20, 0x03, 0x58, 0x02, 0x4b, 0x00, + /* 800x600 @ 72Hz */ + 0x20, 0x03, 0x58, 0x02, 0x48, 0x00, + + /* 1152x870 @ 75Hz */ + 0x80, 0x04, 0x66, 0x03, 0x4b, 0x00 +}; + +#ifdef DEBUG_FIRMWARE +/*! + * + * @param timing + * @param edid + * + * @return void + */ +static void print_supported_timings( + pd_timing_t *timing, edid_t *edid) +{ + unsigned short i, count = 0; + if (timing != NULL) { + while (timing->width != IGD_TIMING_TABLE_END) { + if (timing->mode_info_flags & PD_MODE_SUPPORTED) { + OS_DEBUG("\t%4u\t%4u\t%4u", timing->width, + timing->height, timing->refresh); + count++; + } + + timing++; + if (timing->width == IGD_TIMING_TABLE_END && timing->extn_ptr) { + timing = timing->extn_ptr; + } + } + } + + if (edid && edid->num_timings) { + for (i=0; inum_timings; i++) { + if (edid->timings[i].mode_info_flags & PD_MODE_SUPPORTED) { + OS_DEBUG("\t%4u\t%4u\t%4u", edid->timings[i].width, + edid->timings[i].height, edid->timings[i].refresh); + count++; + } + } + } + OS_DEBUG("Total supported timings = %u", count); +} + +/*! + * Dump the EDID to the kernel messages for debug + * + * @param buffer + * @param size + * + * @return void + */ +void firmware_dump(unsigned char *buffer, unsigned short size) +{ + unsigned short i; + OS_DEBUG("---------------------------------------------------------"); + if (*(unsigned long *) &buffer[0] == 0xFFFFFF00 && + *(unsigned long *) &buffer[4] == 0x00FFFFFF) { + size = 128; + OS_DEBUG("EDID DUMP (size = %u):", size); + } else { + /* For DisplayID payload is at byte 2 */ + /* +5 is for 5 mandatory bytes */ + size = buffer[1]+5; + OS_DEBUG("DisplayID DUMP (size = %u):", size); + } + OS_DEBUG("-------+-------------------------------------------------"); + OS_DEBUG("Offset | Data....."); + OS_DEBUG("-------+-------------------------------------------------"); + + for (i=0; isize) { + OS_DEBUG("Note: Ignore last row last %u bytes.", i-size); + } + OS_DEBUG("-------+-------------------------------------------------"); + OS_DEBUG(" "); +} /* edid_dump() */ + +/*! + * Print the EDID Structure + * + * @param buffer + * @param size + * + * @return void + */ +void edid_print(edid_t *edid) +{ + int i; + + OS_DEBUG("EDID Version: %d", edid->version); + OS_DEBUG("EDID Revision: %d", edid->revision); + OS_DEBUG("Vendor %s", edid->vendor); + OS_DEBUG("Model: %s", edid->name); + OS_DEBUG("Product Code: %ld", edid->product_code); + OS_DEBUG("Serial Number: %lu", edid->serial_number); + OS_DEBUG("Manufactored week: %d", edid->manf_week); + OS_DEBUG("Manufactored year: %ld", edid->manf_year); + OS_DEBUG("DPMS Flags: 0x%u", edid->dpms); + OS_DEBUG("Max Pixel Clock: %lu KHz", edid->range.max_dclk); + OS_DEBUG("H Range: %u - %u KHz", + edid->range.min_hrate, edid->range.max_hrate); + OS_DEBUG("V Range: %u - %u Hz", + edid->range.min_vrate, edid->range.max_vrate); + + for (i=0; inum_timings; i++) { + OS_DEBUG("Detailied Timing Descriptor(DTD) %u", i+1); + OS_DEBUG(" dclk = %lu", edid->timings[i].dclk); + OS_DEBUG(" hactive = %u", edid->timings[i].width); + OS_DEBUG(" htotal = %u", edid->timings[i].htotal); + OS_DEBUG(" hblank_start = %u", edid->timings[i].hblank_start); + OS_DEBUG(" hsync_start = %u", edid->timings[i].hsync_start); + OS_DEBUG(" hsync_end = %u", edid->timings[i].hsync_end); + OS_DEBUG(" hblank_end = %u", edid->timings[i].hblank_end); + OS_DEBUG(" vactive = %u", edid->timings[i].height); + OS_DEBUG(" vtotal = %u", edid->timings[i].vtotal); + OS_DEBUG(" vblank_start = %u", edid->timings[i].vblank_start); + OS_DEBUG(" vsync_start = %u", edid->timings[i].vsync_start); + OS_DEBUG(" vsync_end = %u", edid->timings[i].vsync_end); + OS_DEBUG(" vblank_end = %u", edid->timings[i].vblank_end); + OS_DEBUG(" interlace = %u", + (edid->timings[i].mode_info_flags&PD_SCAN_INTERLACE)?1:0); + OS_DEBUG("hsync_polarity = %s", + (edid->timings[i].mode_info_flags & PD_HSYNC_HIGH)? + "ACTIVE HIGH":"ACTIVE LOW"); + OS_DEBUG("vsync_polarity = %s", + (edid->timings[i].mode_info_flags & PD_VSYNC_HIGH)? + "ACTIVE HIGH":"ACTIVE LOW"); + } +} /* edid_print() */ +#endif + +/*! + * Function to disable all timings before marking supportecd timings + * + * @param timing + * @param enable + * + * @return void + */ +void enable_disable_timings(pd_timing_t *timing, unsigned char enable) +{ + if (!timing) { + return; + } + + while(timing->width != IGD_TIMING_TABLE_END) { + if (enable) { + timing->mode_info_flags |= PD_MODE_SUPPORTED; + } else { + timing->mode_info_flags &= ~PD_MODE_SUPPORTED; + } + timing++; + if (timing->width == IGD_TIMING_TABLE_END && timing->extn_ptr) { + timing = timing->extn_ptr; + } + } +} + +/*! + * Function to enable timings based on port driver flags + * + * @param timing + * @param enable + * + * @return void + */ +void enable_scaled_timings(pd_timing_t *timing, pd_timing_t *dtd, + unsigned char upscale) +{ + + if (!upscale || !dtd || !timing) { + return; + } + + /* If port driver supports up scaling, enable all smaller modes. */ + while(timing->width != IGD_TIMING_TABLE_END) { + if ((timing->width <= dtd->width) && + (timing->height <= dtd->height) && + (timing->refresh <= dtd->refresh)) { + timing->mode_info_flags |= IGD_MODE_SUPPORTED; + } + timing++; + + /* If reached the first table END, + * then check for the added modes */ + if (timing->width == IGD_TIMING_TABLE_END && + timing->extn_ptr) { + timing = timing->extn_ptr; + } + } +} + +/*! + * Parse an Edid Structure from a provided 128 byte buffer of data. + * This function will return EDID_READ_AGAIN if the driver should + * read another 128 bytes and call this function again. This will + * happen with EDID structures with one or more extended 128 byte regions. + * count is 0 on the first call and incremented with each extra 128 + * byte buffer. + * + * This parser skips information that is not important to the driver. + * There should be an interface to provide the whole EDID to userspace + * where more advanced parsing can happen. If you need something exotic + * out of the EDID consider having a user app do it instead of making + * This in-kernel EDID parser large. + * + * Timings found in the "Established" and "Standard" bitfields or + * extension blocks will be looked up in the provided timings list. + * If a match is found the timings will be marked with + * PD_MODE_SUPPORTED. + * + * If the EDID provides frequency ranges all timings within the range will + * be marked with PD_MODE_SUPPORTED in timing_table. + * + * If a driver uses a single timings list for multiple displays the driver + * will have to copy the flags mentioned above into a bit range specific + * to each display (in the driver specific bit range). + * + * @param buffer + * @param edid + * @param timing_table + * @param count + * @param upscale + * + * @return 0 on success + * @return EDID_ERROR_PARSE on failure + */ +int edid_parse( + unsigned char *buffer, + edid_t *edid, + pd_timing_t *timing_table, + int count, + unsigned char upscale) +{ + int chksum = 0, i, j; + unsigned long version, vendor, temp32; + pd_timing_t *timing; + + if (!edid || !buffer) { + return EDID_ERROR_PARSE; + } + + /* No count means, edid_parse() called for first time */ + if (!count) { + OS_MEMSET(edid, 0, sizeof(edid_t)); + } + + /* Check the checksum */ + for (i=0; i<128; i++) { + chksum += buffer[i]; + } + + if ((chksum & 0xff) != 0) { + OS_DEBUG("EDID checksum is incorrect! Will ignore."); + return EDID_ERROR_PARSE; + } + + /* FIXME: Verify this, I think extra EDID blocks have no header */ + if (count) { + /* goto BLOCKS; */ + return EDID_ERROR_PARSE; + } + + /* Header already checked. Skip 8 bytes */ + buffer+=8; + + /* Vendor Name */ + vendor = (buffer[0]<<8) | buffer[1]; + *(unsigned long *)edid->vendor = ((vendor>>10) + 0x40) + + ((((vendor>>5) & 0x1f) + 0x40)<<8) + + ((unsigned long)((vendor & 0x1f) + 0x40)<<16); + buffer+=2; + + /* Product Code */ + edid->product_code = (buffer[1]<<8) | buffer[0]; + buffer+=2; + + /* Serial Number 4 bytes (SKIP)*/ + edid->serial_number = buffer[0] | + (buffer[1]<<8) | + ((unsigned long)(buffer[2])<<16) | + ((unsigned long)(buffer[3])<<24); + buffer += 4; + + /* Manufactured Week 1 byte (SKIP) */ + edid->manf_week = buffer[0]; + buffer++; + + /* Manufactured Year 1 byte (SKIP) */ + edid->manf_year = 1990 + buffer[0]; + buffer++; + + /* EDID Version/Revision 0x12-0x13 */ + version = (buffer[0]<<8) | buffer[1]; + edid->version = buffer[0]; + edid->revision = buffer[1]; + buffer += 2; + + switch(version) { + case 0x0: + case 0x0101: + case 0x0102: + case 0x0103: + /* Possibly do something based on this */ + break; + default: + OS_DEBUG("EDID Version %d.%d Unknown. Will Ignore.", + edid->version, edid->revision); + return EDID_ERROR_PARSE; + break; + } + + /* Basic Display Params (SKIP) */ + buffer+=4; + + /* DPMS and Features 1 byte */ + edid->dpms = (buffer[0]>>5); + edid->display_type = (buffer[0]>>3) & 0x3; + edid->standard_color = (buffer[0]>>2) & 0x1; + edid->preferred_timing = (buffer[0]>>1) & 0x1; + edid->gtf = (buffer[0] & 0x1); + buffer++; + + /* Color 10 bytes (SKIP)*/ + buffer+=10; + + /* EDID parsing should start by disabling all modes. + * Based on EDID data, modes will be enabled. */ + enable_disable_timings(timing_table, 0); + + /* Based on the established timings provided in the EDID, mark the + * timings in the table as below (as per meeting with MikeD on 7/11/03): + * + * 1. If all VESA ETF and 640x480 modes are supported, + * then mark all modes in the table as supported + DTD modes + * 2. If all VESA ETF 60Hz modes are supported, + * then mark all 60Hz modes in the table as supported + DTD modes + * 3. Default: + * Enable only ETF modes in the table + DTD modes + * + * Established Timings 3 bytes (SKIP bits 6:0 of byte 3 which contains + * manufactorer's proprietary timings), so there are 17 established + * timings. */ + + /* Move byte2 bit7 to byte2 bit0. This is done to maintain + * continuation along with other 16 established timings */ + temp32 = buffer[0] | ((unsigned long)(buffer[1])<<8) | + ((unsigned long)(buffer[2]>>7)<<16); + + /* Here are the bit definitions: + * Byte 0 + * bit 0 - 800 x 600 @ 60Hz VESA + * bit 1 - 800 x 600 @ 56Hz VESA + * bit 2 - 640 x 480 @ 75Hz VESA + * bit 3 - 640 x 480 @ 72Hz VESA + * bit 4 - 640 x 480 @ 67Hz Apple, Mac II + * bit 5 - 640 x 480 @ 60Hz IBM, VGA + * bit 6 - 720 x 400 @ 88Hz IBM, XGA2 + * bit 7 - 720 x 400 @ 70Hz IBM, VGA + * Byte 1 + * bit 0 - 1280 x 1024 @ 75Hz VESA + * bit 1 - 1024 x 768 @ 75Hz VESA + * bit 2 - 1024 x 768 @ 70Hz VESA + * bit 3 - 1024 x 768 @ 60Hz VESA + * bit 4 - 1024 x 768 @ 87Hz IBM (Interlaced) + * bit 5 - 832 x 624 @ 75Hz Apple, Mac II + * bit 6 - 800 x 600 @ 75Hz VESA + * bit 7 - 800 x 600 @ 72Hz VESA + * Byte 2 + * bit 0 - 1152 x 870 @ 75Hz Apple, Mac II + * + * Note: + * Byte2 bit 0 used to be at Byte 2 bit 7 but moved to bit 0 for sake of + * continuality. + */ + for (i=0; i<=16; i++) { + if (temp32 & (1L<width != IGD_TIMING_TABLE_END) { + if ((temp32 & 0xCF2F) == 0xCF2F) { /* Case 1 */ + timing->mode_info_flags |= PD_MODE_SUPPORTED; + } else if (((temp32 & 0xCF2F) == 0x821) && /* Case 2 */ + (timing->refresh == 60)) { + timing->mode_info_flags |= PD_MODE_SUPPORTED; + } + + timing++; + if (timing->width == IGD_TIMING_TABLE_END && timing->extn_ptr) { + timing = timing->extn_ptr; + } + } + } + + buffer+=3; + + /* Standard Timings 16 bytes, Look these up in the standard + * timings table to find the match. Skip any that are not found + * in the table. + */ + for (i=0; i<8; i++) { + /* First 8 standard timings */ + edid_mark_standard_timings(buffer, timing_table, 0); + buffer+=2; + } + +#ifdef DEBUG_FIRMWARE + OS_DEBUG("Supported timings after SECOND established timings."); + print_supported_timings(timing_table, edid); +#endif + + /* BLOCKS: */ + /* Blocks of Data */ + for (i=0; i<4; i++) { + if (*(unsigned long *)buffer == *(unsigned long *)name_blockid) { + /* Monitor Name */ + edid_parse_monitor_name(&buffer[5], edid->name); + buffer+=18; + continue; + } + if (*(unsigned long *)buffer == *(unsigned long *)range_blockid) { + /* Monitor Limits */ + edid->range_set = 1; + edid->range.min_vrate = buffer[5]; /* Hz */ + edid->range.max_vrate = buffer[6]; /* Hz */ + edid->range.min_hrate = buffer[7]; /* KHz */ + edid->range.max_hrate = buffer[8]; /* KHz */ + edid->range.max_dclk = + (unsigned long)buffer[9]*10000L; /* convert from MHz/10->KHz */ + /* Following are always zero: + * edid->range.min_dclk + * edid->range->min_hblank + * edid->range->min_vblank */ + + /* Call common function to filter timings based on range limits */ + displayid_filter_range_timings(timing_table, &edid->range, + PI_FIRMWARE_EDID); + + /* Fixme GTF */ + buffer+=18; + continue; + } + if (*(unsigned long *)buffer == *(unsigned long *)st_blockid) { + /* Additional 6 Standard Timings */ + buffer+=5; + for (j=0; j<12; j+=2) { + edid_mark_standard_timings(&buffer[j], timing_table, 0); + } + buffer+=13; + continue; + } + if (*(unsigned long *)buffer & *(unsigned long *)timings_mask) { + /* Detailed Timings */ + if (edid->num_timings >= NUM_TIMINGS-1) { + continue; + } + edid_mark_detailed_timings(buffer, edid, timing_table, upscale); + buffer+=18; + continue; + } + /* Don't handle Block types that don't matter */ + buffer+=18; + } /* end for loop */ + +#ifdef DEBUG_FIRMWARE + OS_DEBUG("FINAL supported timings ."); + print_supported_timings(timing_table, edid); +#endif + + /* Extensions */ + if (*buffer) { + return EDID_READ_AGAIN; + } + + return 0; +} /* end edid_parse() */ + +/*! + * Given the two byte Standard Timings Identifier, Mark the timing + * that matches in the timings array. + * If "established" is set, the two byte "EDID id" will be used, + * otherwise the buffer should contain the hactive, followed by + * the vactive followed by the refresh, all in 16 bit LSB format. + * + * @param buffer + * @param timings + * @param established + * + * @return void + */ +static void edid_mark_standard_timings( + unsigned char *buffer, + pd_timing_t *timings, + int established) +{ + int hactive, vactive=0, refresh, aspect; + + if ((!established) && (buffer[0] == 0x01) && (buffer[1] == 0x01)) { + return; + } + if (established) { + hactive = buffer[0] | (buffer[1]<<8); + vactive = buffer[2] | (buffer[3]<<8); + refresh = buffer[4] | (buffer[5]<<8); + } + else { + hactive = (buffer[0] + 31)<<3; + refresh = (buffer[1] & 0x1f) + 60; + aspect = buffer[1]>>6; + switch(aspect) { + case 0x0: + vactive = (hactive*10)>>4; + break; + case 0x1: + vactive = (hactive*3)>>2; + break; + case 0x2: + vactive = (hactive<<2)/5; + break; + case 0x3: + vactive = (hactive*9)>>4; + break; + default: + OS_ERROR("Invalid aspect ratio in EDID."); + return; + } + } + + if (timings != NULL) { + /* Look for mode in table */ + while (timings->width != IGD_TIMING_TABLE_END) { + /* By default no mode is supported. */ + if ((timings->refresh == refresh) && + (timings->width == hactive) && + (timings->height == vactive)) { + timings->mode_info_flags |= PD_MODE_SUPPORTED; + return; + } + + timings++; + + if (timings->width == IGD_TIMING_TABLE_END && timings->extn_ptr) { + timings = timings->extn_ptr; + } + } + } + + return; +} /* end edid_mark_standard_timings() */ + +/*! + * Parse a detailed timing block from the buffer provided and set the + * data in the pd_timing_t structure provided. + * + * @param buffer + * @param edid + * @param timing_table + * @param upscale + * + * @return void + */ +static void edid_mark_detailed_timings( + unsigned char *buffer, + edid_t *edid, + pd_timing_t *timing_table, + unsigned char upscale) +{ + unsigned long temp; + pd_timing_t *timings = &(edid->timings[edid->num_timings]); + + timings->dclk = ((unsigned long)(buffer[1]<<8) | buffer[0]) * 10; /* KHz */ + timings->width = ((buffer[4] & 0xf0)<<4) | buffer[2]; + if (timings->width == 0) { + /* Bail out as DTD is invalid. This happens as we are estimating the + * amount of availabel DTD since manufacturer does not follow CEA + * format */ + timings->width = IGD_TIMING_TABLE_END; + return; + } + timings->hblank_start = timings->width - 1; + timings->hblank_end = timings->width + + (((buffer[4]& 0xf)<<8) | buffer[3]) - 1; + timings->height = ((buffer[7] & 0xf0)<<4) | buffer[5]; + timings->vblank_start = timings->height - 1; + timings->vblank_end = timings->height + + (((buffer[7]& 0xf)<<8)| buffer[6]) - 1; + timings->hsync_start = timings->hblank_start + + (((buffer[11] & 0xc0)<<2) | buffer[8]); + timings->hsync_end = timings->hsync_start + + (((buffer[11] & 0x30)<<4) | buffer[9]); + timings->vsync_start = timings->vblank_start + + (((buffer[11] & 0xc)<<2) | (buffer[10]>>4)); + timings->vsync_end = timings->vsync_start + + (((buffer[11] & 0x3)<<4) | (buffer[10] & 0xf)); + timings->htotal = timings->hblank_end; + timings->vtotal = timings->vblank_end; + + /* SKIP BORDER */ + timings->mode_info_flags |= (buffer[17] & 0x80)?PD_SCAN_INTERLACE:0; + + /* Need to divide width by 2 and set PIXEL_DOUBLE flag in order to properly */ + /* handle clock doubled modes like 1440(720)x480i and 1440(720)x576i */ + if( (timings->mode_info_flags & PD_SCAN_INTERLACE) && (timings->width == 1440) && + ((timings->height == 480) || (timings->height == 576)) ) + { + timings->width /= 2; + timings->mode_info_flags |= IGD_PIXEL_DOUBLE; + }else if((timings->mode_info_flags & PD_SCAN_INTERLACE)){ + /* The height needs to be multiplied by 2 here so OS would prepare the + correct frame buffer size. Pipe programming needs to be aware of this */ + timings->height *= 2; + timings->vtotal *= 2; + timings->vblank_start *= 2; + timings->vblank_end *= 2; + timings->vsync_start *= 2; + timings->vsync_end *= 2; + } + + /* Set sync polarities */ + if((buffer[17] & 0x18)==0x18) { /* Bit 4 and 3 above = 11*/ + /* if Bit 2 = 1, then vsync polarity = positive */ + timings->mode_info_flags |= (buffer[17] & 0x04)? IGD_VSYNC_HIGH: 0; + /* if Bit 1 = 1, then hsync polarity = positive */ + timings->mode_info_flags |= (buffer[17] & 0x02)? IGD_HSYNC_HIGH: 0; + } + + if((buffer[17] & 0x18)==0x10) { /* Bit 4 and 3 above = 10*/ + /* if Bit 1 = 1, then hsync polarity = positive */ + timings->mode_info_flags |= (buffer[17] & 0x02)? IGD_HSYNC_HIGH: 0; + } + + if (timings->dclk == 0) { + timings->dclk = 1; + } + if (timings->htotal == 0) { + timings->htotal = 1; + } + if (timings->vtotal == 0) { + timings->vtotal = 1; + } + + temp = (unsigned long)timings->htotal * (unsigned long)timings->vtotal; + timings->refresh = (unsigned short)((timings->dclk * 1000)/temp); + timings->mode_info_flags |= (PD_MODE_SUPPORTED | PD_MODE_DTD); + + /* Save in the detailed timings of EDID */ + edid->num_timings++; + /* Mark the end of the list */ + edid->timings[edid->num_timings].width = IGD_TIMING_TABLE_END; + + /* Enable scale timings */ + enable_scaled_timings(timing_table, timings, upscale); +} /* end edid_mark_detailed_timings() */ + +/*! + * Get the 13 (or less) character Monitor name from the buffer and + * pad with nulls. + * + * @param buffer + * @param name + * + * @return void + */ +static void edid_parse_monitor_name(unsigned char *buffer, char *name) +{ + int i; + for (i=0; i<13; i++) { + if (buffer[i] == 0x0a) { + name[i] = 0; + break; + } + name[i] = buffer[i]; + } + while (i<14) { + name[i] = 0; + i++; + } +} /* edid_parse_monitor_name() */ + +#ifndef CONFIG_MICRO +/*! + * + * @param edid + * + * @return 0 + */ +int parse_audio_block(edid_t *edid) +{ + int i; + cea_audio_format_t *tmp_audio; + + for(i=0; i<(edid->cea->total_short_audio_desc); i++){ + tmp_audio = edid->cea->short_audio_desc + i; + if(tmp_audio->audio_format_code == CEA_AUDIO_LPCM){ + if(tmp_audio->_48khz){ + edid->cea->audio_cap[0].max_channels = tmp_audio->max_channels; + edid->cea->audio_cap[0]._20bit = tmp_audio->_20bit; + edid->cea->audio_cap[0]._24bit = tmp_audio->_24bit; + } + if(tmp_audio->_96khz){ + edid->cea->audio_cap[1].max_channels = tmp_audio->max_channels; + edid->cea->audio_cap[1]._20bit = tmp_audio->_20bit; + edid->cea->audio_cap[1]._24bit = tmp_audio->_24bit; + if(tmp_audio->_88khz){ + edid->cea->_44ms = 1; + } + } + if(tmp_audio->_192khz){ + edid->cea->audio_cap[2].max_channels = tmp_audio->max_channels; + edid->cea->audio_cap[2]._20bit = tmp_audio->_20bit; + edid->cea->audio_cap[2]._24bit = tmp_audio->_24bit; + if(tmp_audio->_176khz){ + edid->cea->_44ms = 1; + } + } + } + } + return 0; +} + +/*! + * + * @param buffer + * @param list + * @param block_size + * @param total_bytes + * + * @return 0 no read will happen + * @return total_blocks + */ +int read_data_block_collection(unsigned char *buffer, + char **list, + unsigned int block_size,/* Block size in byte */ + unsigned int total_bytes) +{ + unsigned int total_blocks; + unsigned int i; + + total_blocks = total_bytes/block_size; + if(total_bytes <= 0 ){ + /* No read will happen */ + return 0; + } + + if(*list !=NULL){ + OS_FREE(*list); + } + + *list = OS_ALLOC((sizeof(char)*total_bytes)); + for(i=0;icea == NULL){ + edid->cea = (cea_extension_t *) OS_ALLOC(sizeof(cea_extension_t)); + } + if(edid->cea == NULL){ + OS_ERROR("Run out of memory"); + return 1; + } + OS_MEMSET(edid->cea, 0 , (sizeof(cea_extension_t))); + edid->cea->rev_number = buffer [1]; + edid->cea->caps = buffer [3]; + + if(offset == 0){ + OS_ERROR("No data block and no DTD "); + return 1; + } + + /* General Format of CEA Data Block Collection + // -----------+--------------------+--------------------------------------+ + // |Byte# |Bits5-7 | Bits 0-4 | + // -----------|--------------------+--------------------------------------+ + // | 1 | Video Tag |Length = total #of video | + // | | Code |bytes following this byte (L1) | + // |--------------------+--------------------------------------+ + // Video | 2 | CEA Short Video Descriptor 1 | + // Data |--------+--------------------------------------------------| + // Block | 3 | CEA Short Video Descriptor 2 | + // |--------+--------------------------------------------------| + // | ... | ... | + // |-----------------------------------------------------------+ + // | 1+L1 | CEA Short Video Descriptor L1 | + // -----------+--------------------+--------------------------------------+ + // | 2+L1 | Audio Tag |Length = total #of audio bytes | + // | | Code |following this byte (L2) | + // |--------------------+--------------------------------------+ + // Audio | 3+L1 | | + // Data |--------+ | + // Block | 4+L1 | CEA Short Audio Descriptor 1 | + // |--------+ | + // | 5+L1 | | + // |-----------------------------------------------------------+ + // | ... | | + // | | | + // | | | + // | ... | | + // |------------------------------------------------------------ + // |L1+L2 | | + // |--------| | + // |1+L1+L2 | CEA Short Audio Descriptor L2/3 | + // |--------| | + // |2+L1+L2 | | + // -----------+-----------------------------------------------------------+ + // |3+L1+L2 | Speaker |Length = total #of SA bytes following | + // | | Tag Code |this byte (L1) | + // Speaker |-----------------------------------------------------------+ + // Allocation|4+L1+L2 | | + // Data |--------| | + // Block |5+L1+L2 | Speaker Allocation Data Block Payload(3 bytes) | + // |--------| | + // |6+L1+L2 | | + // -----------+-----------------------------------------------------------+ + // |7+L1+L2 | VSDB Tag |Length = total #of VSDB bytes | + // | | Code |following this byte (L1) | + // Vendor |-----------------------------------------------------------+ + // Specific |8+L1+L2 | | + // Data |--------| | + // Block |9+L1+L2 | 24-bit IEEE Registration Identifier (LSB first) | + // |--------| | + // |10+L1+L2| | + // |-----------------------------------------------------------+ + // | ... | Vendor Specific Data block Payload | + // -----------+-----------------------------------------------------------+*/ + data_block_buffer=&buffer[4]; + /* Start reading data block collection */ + while(icea->total_short_video_desc =read_data_block_collection + (data_block_buffer, + (char **)&edid->cea->short_video_desc, + 1,/* Block size in byte */ + total_bytes); + break; + case CEA_AUDIO_DATA_BLOCK: + /* Reading Short Audio Descriptor block */ + edid->cea->total_short_audio_desc = read_data_block_collection + (data_block_buffer, + (char **)&edid->cea->short_audio_desc, + 3,/* Block size in byte */ + total_bytes); + /* uncomment this codes if this info is requred in the future */ + /*for(j=0; jcea->misc_data[j], + (edid->cea->short_audio_desc + (j/3)), + sizeof(cea_audio_format_t)); + } + edid->cea->sadc = (unsigned char) + edid->cea->total_short_audio_desc; */ + break; + case CEA_VENDOR_DATA_BLOCK: + /* Reading Vendor Specific Descriptor block */ + edid->cea->vendor_block.vendor_block_size = (unsigned char)total_bytes; + OS_MEMCPY(edid->cea->vendor_block.vendor_ieee_id, data_block_buffer, 3); + read_data_block_collection + (data_block_buffer, + (char **)&edid->cea->vendor_data_block, + 3, + total_bytes); + break; + case CEA_SPEAKER_DATA_BLOCK: + /* Reading Speaker Data Descriptor block */ + for(j=0; j<3; j++){ + edid->cea->speaker_alloc_block[j] = data_block_buffer[j]; + } + break; + default: + /* Ignore unknown block? */ + OS_ERROR("Unknown Tag Code! : CEA extended data block"); + break; + } + data_block_buffer+=(total_bytes); + i+=(total_bytes); + }; + + /* DPG codes show that they are manufacturer who doesn't follow the spec + Calculate the maximum possible DTD from whatever empty space left. + The Maximum DTD is 6*/ + i=(unsigned int)(128-offset-1)/18; + i = (i>6)?6:i; + + buffer+=offset; + while(i>0){ + if (edid->num_timings >= NUM_TIMINGS-1) { + break; + } + edid_mark_detailed_timings(buffer, edid, timings, upscale); + buffer+=18; + i--; + }; + + /* Parse audio block to know panel audio capability */ + parse_audio_block(edid); + + cea_timings = (igd_timing_info_t *) OS_ALLOC(cea_timing_table_size); + OS_MEMCPY(cea_timings, cea_timing_table, cea_timing_table_size); + + for(i=0; i<(unsigned int)edid->cea->total_short_video_desc; i++){ + OS_DEBUG("Video Code %d",(int)(edid->cea->short_video_desc + i)->code); + temp_timings = cea_timings; + timing_in_edid = 0; + while (temp_timings->width != IGD_TIMING_TABLE_END){ + /* Look for matching tag code */ + if((edid->cea->short_video_desc + i)->code == temp_timings->mode_number){ + j=0; + while(jnum_timings){ + /* Ignore if we have already read the timng through DTD + dclk would be sufficient to differentiate between progressive + and interlace */ + if(temp_timings->width == edid->timings[j].width && + temp_timings->height == edid->timings[j].height && + temp_timings->refresh == edid->timings[j].refresh && + temp_timings->dclk == edid->timings[j].dclk){ + timing_in_edid = 1; + break; + } + j++; + } + /* Add the timing if we have not done so through DTD */ + if(!(timing_in_edid)){ + if (edid->num_timings >= NUM_TIMINGS-1) { + break; + } + OS_MEMCPY(&edid->timings[edid->num_timings], + temp_timings, sizeof(pd_timing_t)); + edid->timings[edid->num_timings].mode_number = 0; + edid->timings[edid->num_timings].mode_info_flags + |= (PD_MODE_SUPPORTED | PD_MODE_DTD); + edid->num_timings++; + edid->timings[edid->num_timings].width = IGD_TIMING_TABLE_END; + /*enable_scaled_timings(timings, + &edid->timings[edid->num_timings], upscale);*/ + } + break; + } + temp_timings++; + } + } + + OS_FREE(cea_timings); + +#ifdef DEBUG_FIRMWARE + OS_ERROR("FINAL supported timings after CEA ."); + print_supported_timings(timings, edid); +#endif + return 0; +} +#endif + +/*! + * + * @param buffer + * @param edid + * @param timings + * @param count + * @param upscale + * + * @return 0 on success + * @return 1 on failure + */ +int edid_ext_parse( + unsigned char *buffer, + edid_t *edid, + pd_timing_t *timings, + int count, + unsigned char upscale) +{ + unsigned int timing_in_edid = 0, j; +#ifndef CONFIG_MICRO + if(edid_parse_cea(buffer, edid, timings, count, upscale)){ + OS_ERROR("Reading cea extension ERROR!"); + return 1; + } +#endif + + /* Check to see if 640x480 is part of EDID timing if not add it in. + CEA panels does not support standard timing 640x480 */ + for(j=0; jnum_timings; j++){ + if(edid->timings[j].width == 640 && + edid->timings[j].height == 480 && + edid->timings[j].refresh == 60 ){ + timing_in_edid = 1; + break; + } + } + if((!timing_in_edid) && (edid->num_timings < NUM_TIMINGS-1)){ + OS_MEMCPY(&edid->timings[edid->num_timings], + cea_timing_table, sizeof(pd_timing_t)); + edid->timings[edid->num_timings].mode_number = 0x101; + edid->timings[edid->num_timings].mode_info_flags + |= (PD_MODE_SUPPORTED | PD_MODE_DTD); + edid->num_timings++; + edid->timings[edid->num_timings].width = IGD_TIMING_TABLE_END; + } + + return 0; +}/* end edid_parse_ext() */ + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: edid.c,v 1.4 2010/04/27 20:33:49 bpaauwe Exp $ + * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/pi/cmn/edid.c,v $ + *---------------------------------------------------------------------------- + */ diff --git a/drivers/gpu/drm/emgd/emgd/display/pi/cmn/i2c_dispatch.h b/drivers/gpu/drm/emgd/emgd/display/pi/cmn/i2c_dispatch.h new file mode 100755 index 0000000..4b49ffb --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/pi/cmn/i2c_dispatch.h @@ -0,0 +1,70 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: i2c_dispatch.h + * $Revision: 1.2 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * + *----------------------------------------------------------------------------- + */ + +#ifndef _I2C_DISPATCH_H +#define _I2C_DISPATCH_H + +/* + * IO.h is needed to resolve the FAR define + * context.h is needed for the igd_display_context_t + */ + +#include +#include +#include + +#include + +#define I2C_DEFAULT_SPEED 100 /* Default I2C bus speed in KHz */ +#define DDC_DEFAULT_SPEED 10 /* Default DDC bus speed in KHz */ + +/* + * Flags for Write Reg List + * + * Serial Write: Write a Reg Value, Data Value repeatedly within one + * write cycle. + */ +#define IGD_I2C_SERIAL_WRITE 0x1 + +typedef struct _i2c_dispatch { + int (*i2c_read_regs)( + igd_context_t *context, + unsigned long i2c_bus, + unsigned long i2c_speed, + unsigned long dab, + unsigned char reg, + unsigned char FAR *buffer, + unsigned long num_bytes); + int (*i2c_write_reg_list)( + igd_context_t *context, + unsigned long i2c_bus, + unsigned long i2c_speed, + unsigned long dab, + pd_reg_t *reg_list, + unsigned long flags); +} i2c_dispatch_t; + +#endif + diff --git a/drivers/gpu/drm/emgd/emgd/display/pi/cmn/igd_pi.c b/drivers/gpu/drm/emgd/emgd/display/pi/cmn/igd_pi.c new file mode 100644 index 0000000..51b5cea --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/pi/cmn/igd_pi.c @@ -0,0 +1,260 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: igd_pi.c + * $Revision: 1.3 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * Callback functions to give to port drivers. All functions are provided + * to port driver as callback functions. Only port driver should call + * these functions. + *----------------------------------------------------------------------------- + */ + +#include + +#include +#include + +/* #include */ +#include + +#include +#include + +/*! + * @addtogroup display_group + * @{ + */ + +/*! + * Function to register with main driver. + * + * @param handle + * @param pd_driver + * + * @return pi_pd_register() + */ +int igd_pd_register(void *handle, void *pd_driver) +{ + return pi_pd_register(pd_driver); +} /* igd_pd_register */ + +/*! + * Function to allocate memory + * + * @param handle + * @param pd_driver + * + * @return void + */ +void *igd_pd_malloc(unsigned long size) +{ + return OS_ALLOC(size); +} /* end igd_pd_malloc */ + +/*! + * Function to set the memory + * + * @param address + * @param c + * @param size + * + * @return void + */ +void *igd_pd_memset(void *address, int c, unsigned long size) +{ + return OS_MEMSET(address, c, size); +} /* end igd_pd_memset */ + +/*! + * Function to copy block of memory + * + * @param dst + * @param src + * @param size + * + * @return void + */ +void *igd_pd_memcpy(void *dst, void *src, unsigned long size) +{ + return OS_MEMCPY(dst, src, size); +} /* end igd_pd_memcpy */ + +/* Functions to free memory */ +void igd_pd_free(void *ptr) +{ + OS_FREE(ptr); +} /* end igd_pd_free */ + +/*! + * Function to sleep in micro seconds. This can be called with millisecond + * ranges. + * + * @param usec + * + * @return void + */ +void igd_pd_usleep(unsigned long usec) +{ + if (usec <= 1000) { + OS_SLEEP(usec); + } else { + os_alarm_t alarm = OS_SET_ALARM((usec+999)/1000); + do { + OS_SCHEDULE(); + } while (!OS_TEST_ALARM(alarm)); + } +} /* end igd_pd_usleep() */ + +/*! + * Function to do a string copy + * + * @param dest + * @param src + * + * @return dest + */ +char *igd_pd_strcpy(char *dest, char const *src) +{ + int i = 0; + /* This can be optimized by assigning 32 bit quantities instead + * of 8 bit quantities. This requires knowing the length first then + * move the quantities. For now, this is OK. */ + while (src[i] != '\0') { + dest[i] = src[i]; + i++; + } + dest[i] = '\0'; + return (dest); +} /* end igd_pd_strcpy() */ + +/*! + * Function to check value of an attribute + * + * @param curr + * @param in + * + * @return PD_SUCCESS on success + * @return PD_ERR_NULL_PTR,PD_ERR_INVALID_ATTR, or PD_ERR_INCORR_ATTR_VALUE + * on failure + */ +int igd_pd_check_attr(pd_attr_t *curr, pd_attr_t *in) +{ + if (!curr || !in) { + return PD_ERR_NULL_PTR; + } + + if (curr->id != in->id) { + return PD_ERR_INVALID_ATTR; + } + + switch (curr->type) { + case PD_ATTR_TYPE_RANGE: + if ((in->current_value < RATTR(curr)->min) || + (in->current_value > RATTR(curr)->max)) { + return PD_ERR_INCORR_ATTR_VALUE; + } + break; + case PD_ATTR_TYPE_LIST: + if ((in->current_value < 1) || + (in->current_value > LHATTR(curr)->num_entries)) { + return PD_ERR_INCORR_ATTR_VALUE; + } + break; + case PD_ATTR_TYPE_BOOL: + if ((in->current_value != TRUE) && + (in->current_value != FALSE)) { + return PD_ERR_INCORR_ATTR_VALUE; + } + break; + default: + return PD_ERR_INVALID_ATTR; + } + return PD_SUCCESS; +} /* end igd_pd_check_attr() */ + +/*! + * This function searches for the requested attr_id in the attribute list + * and returns the pointer. + * + * In case of LIST attribute, it will return the proper list entry. + * + * @param attr_list + * @param num_attrs + * @param attr_id + * @param flag + * + * @return attr_list on success + * @return NULL on failure + */ +pd_attr_t *igd_pd_get_attr(pd_attr_t *attr_list, unsigned long num_attrs, + unsigned long attr_id, unsigned long flag) +{ + unsigned long i; + + if (!attr_list) { + return NULL; + } + + for (i = 0; i < num_attrs; i++) { + if (attr_list[i].id == attr_id) { + if (attr_list[i].type == PD_ATTR_TYPE_LIST) { + if (flag == PD_GET_ATTR_LIST_ENTRY) { + return (&(attr_list[i+attr_list[i].current_value])); + } else { + return (&(attr_list[i])); + } + } + return (&(attr_list[i])); + } + } + return NULL; +} /* end igd_pd_get_attr() */ + +/*! + * Common mode filter algorithm for all port drivers + * + * @param context + * @param ilist + * @param olist + * @param dvo + * @param display + * + * @return pd_filter_timings() + */ +int igd_pd_filter_timings( + void *context, + pd_timing_t *ilist, + pd_timing_t **olist, + pd_dvo_info_t *dvo, + pd_display_info_t *display) +{ + return pd_filter_timings(context, ilist, olist, dvo, display); +} + +igd_debug_t *igd_pd_get_igd_debug( void ) +{ + return igd_debug; +} + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: igd_pi.c,v 1.3 2010/04/27 20:33:49 bpaauwe Exp $ + * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/pi/cmn/igd_pi.c,v $ + *---------------------------------------------------------------------------- + */ diff --git a/drivers/gpu/drm/emgd/emgd/display/pi/cmn/mode_table.c b/drivers/gpu/drm/emgd/emgd/display/pi/cmn/mode_table.c new file mode 100644 index 0000000..791356d --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/pi/cmn/mode_table.c @@ -0,0 +1,2436 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: mode_table.c + * $Revision: 1.2 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * This file contains the mode resolution parameters. + *----------------------------------------------------------------------------- + */ + +#define TRUE 1 +#define FALSE 0 + +#include +#include + +/* + * If CONFIG_LIMIT_MODES is not defined then ALL modes should be included. + * Keep the defines here so that when adding new modes it is apparent that + * you should add it to the list below. + */ +#ifndef CONFIG_LIMIT_MODES +#define CONFIG_MODE_640x480x60 +#define CONFIG_MODE_640x480x70 +#define CONFIG_MODE_640x480x72 +#define CONFIG_MODE_640x480x75 +#define CONFIG_MODE_640x480x85 +#define CONFIG_MODE_640x480x100 +#define CONFIG_MODE_640x480x120 +#define CONFIG_MODE_720x480x60 +#define CONFIG_MODE_720x576x50 +#define CONFIG_MODE_800x480x60 +#define CONFIG_MODE_800x600x60 +#define CONFIG_MODE_800x600x70 +#define CONFIG_MODE_800x600x72 +#define CONFIG_MODE_800x600x75 +#define CONFIG_MODE_800x600x85 +#define CONFIG_MODE_800x600x100 +#define CONFIG_MODE_800x600x120 +#define CONFIG_MODE_960x540x60 +#define CONFIG_MODE_1024x768x60 +#define CONFIG_MODE_1024x768x70 +#define CONFIG_MODE_1024x768x75 +#define CONFIG_MODE_1024x768x85 +#define CONFIG_MODE_1024x768x100 +#define CONFIG_MODE_1024x768x120 +#define CONFIG_MODE_1152x864x60 +#define CONFIG_MODE_1152x864x70 +#define CONFIG_MODE_1152x864x72 +#define CONFIG_MODE_1152x864x75 +#define CONFIG_MODE_1152x864x85 +#define CONFIG_MODE_1152x864x100 +#define CONFIG_MODE_1280x720x60 +#define CONFIG_MODE_1280x720x75 +#define CONFIG_MODE_1280x720x85 +#define CONFIG_MODE_1280x720x100 +#define CONFIG_MODE_1280x768x60 +#define CONFIG_MODE_1280x768x75 +#define CONFIG_MODE_1280x768x85 +#define CONFIG_MODE_1280x960x60 +#define CONFIG_MODE_1280x960x75 +#define CONFIG_MODE_1280x960x85 +#define CONFIG_MODE_1280x1024x60 +#define CONFIG_MODE_1280x1024x70 +#define CONFIG_MODE_1280x1024x72 +#define CONFIG_MODE_1280x1024x75 +#define CONFIG_MODE_1280x1024x85 +#define CONFIG_MODE_1280x1024x100 +#define CONFIG_MODE_1280x1024x120 +#define CONFIG_MODE_1366x768x60 +#define CONFIG_MODE_1400x1050x60 +#define CONFIG_MODE_1400x1050x75 +#define CONFIG_MODE_1400x1050x85 +#define CONFIG_MODE_1600x900x60 +#define CONFIG_MODE_1600x900x75 +#define CONFIG_MODE_1600x900x85 +#define CONFIG_MODE_1600x900x100 +#define CONFIG_MODE_1600x900x120 +#define CONFIG_MODE_1600x1200x60 +#define CONFIG_MODE_1600x1200x65 +#define CONFIG_MODE_1600x1200x70 +#define CONFIG_MODE_1600x1200x72 +#define CONFIG_MODE_1600x1200x75 +#define CONFIG_MODE_1600x1200x85 +#define CONFIG_MODE_1600x1200x100 +#define CONFIG_MODE_1600x1200x120 +#define CONFIG_MODE_1856x1392x60 +#define CONFIG_MODE_1856x1392x75 +#define CONFIG_MODE_1920x1080x50 +#define CONFIG_MODE_1920x1080x60 +#define CONFIG_MODE_1920x1080x75 +#define CONFIG_MODE_1920x1080x85 +#define CONFIG_MODE_1920x1080x100 +#define CONFIG_MODE_1920x1200x60 +#define CONFIG_MODE_1920x1200x75 +#define CONFIG_MODE_1920x1440x60 +#define CONFIG_MODE_1920x1440x75 +#define CONFIG_MODE_1920x1440x85 +#define CONFIG_MODE_2048x1536x60 +#define CONFIG_MODE_2048x1536x75 +/* CEA timings */ +#define CONFIG_CEA_MODE_640x480px60 +#ifndef CONFIG_MICRO +/* These are timings that has duplicate except the difference in aspect + ratio. Since IEGD does not support diffrent aspect ratio removing + these CEA timings for now */ +/* +#define CONFIG_CEA_MODE_720x480px60 +#define CONFIG_CEA_MODE_720x576px50*/ +#define CONFIG_CEA_MODE_720x480p_ax60 +#define CONFIG_CEA_MODE_720x576p_ax50 +#define CONFIG_CEA_MODE_1280x720p_ax50 +#define CONFIG_CEA_MODE_1280x720p_ax60 +#define CONFIG_CEA_MODE_1920x1080p_ax50 +#define CONFIG_CEA_MODE_1920x1080p_ax60 +#define CONFIG_CEA_MODE_1920x1080i_ax50 +#define CONFIG_CEA_MODE_1920x1080i_ax60 +#endif /* CONFIG_MICRO */ + +#endif + +/*--------------------------------------------------------------------------- + * Timing tables for CRT modes. + *--------------------------------------------------------------------------- + */ + +igd_timing_info_t crt_timing_table[] = +{ +/* TODO: Add VESA standard REDUCED BLANKING (RB) timings to the table */ +#ifdef CONFIG_MODE_640x480x60 + { + 640, 480, /* width, height */ + 60, 25175, /* refresh, dot clock */ + 799, /* htotal */ + 647, 791, /* hblank_start, hblank_end */ + 655, 751, /* hsync_start, hsync_end */ + 524, /* vtotal */ + 487, 516, /* vblank_start, vblank_end */ + 489, 491, /* vsync_start, vsync_end */ + 0x101, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* mode extenstion pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_640x480x70 + { + 640, 480, /* width, height */ + 70, 28560, /* refresh, dot clock */ + 815, /* htotal */ + 639, 815, /* hblank_start, hblank_end */ + 663, 727, /* hsync_start, hsync_end */ + 499, /* vtotal */ + 479, 499, /* vblank_start, vblank_end */ + 480, 483, /* vsync_start, vsync_end */ + 0x101, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_640x480x72 + { + 640, 480, /* width, height */ + 72, 31500, /* refresh, dot clock */ + 831, /* htotal */ + 647, 823, /* hblank_start, hblank_end */ + 663, 703, /* hsync_start, hsync_end */ + 519, /* vtotal */ + 487, 511, /* vblank_start, vblank_end */ + 488, 491, /* vsync_start, vsync_end */ + 0x101, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_640x480x75 + { + 640, 480, /* width, height */ + 75, 31500, /* refresh, dot clock */ + 839, /* htotal */ + 639, 839, /* hblank_start, hblank_end */ + 655, 719, /* hsync_start, hsync_end */ + 499, /* vtotal */ + 479, 499, /* vblank_start, vblank_end */ + 480, 483, /* vsync_start, vsync_end */ + 0x101, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_640x480x85 + { + 640, 480, /* width, height */ + 85, 36000, /* refresh, dot clock */ + 831, /* htotal */ + 639, 831, /* hblank_start, hblank_end */ + 695, 751, /* hsync_start, hsync_end */ + 508, /* vtotal */ + 479, 508, /* vblank_start, vblank_end */ + 480, 483, /* vsync_start, vsync_end */ + 0x101, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_640x480x100 + { + 640, 480, /* width, height */ + 100, 43163, /* refresh, dot clock */ + 847, /* htotal */ + 639, 847, /* hblank_start, hblank_end */ + 679, 743, /* hsync_start, hsync_end */ + 508, /* vtotal */ + 479, 508, /* vblank_start, vblank_end */ + 480, 483, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_640x480x120 + { + 640, 480, /* width, height */ + 120, 52406, /* refresh, dot clock */ + 847, /* htotal */ + 639, 847, /* hblank_start, hblank_end */ + 679, 743, /* hsync_start, hsync_end */ + 514, /* vtotal */ + 479, 514, /* vblank_start, vblank_end */ + 480, 483, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_720x400x70 + /* NOTE: The above define is not auto-enabled. This is the VGA magic mode */ + { /* VGA Mode 2+,3+ */ + 720, 400, /* width, height */ + 70, 28322, /* refresh, dot clock */ + 899, /* htotal */ + 719, 899, /* hblank_start, hblank_end */ + 773, 881, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 399, 448, /* vblank_start, vblank_end */ + 412, 414, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_VSYNC_HIGH | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_720x480x60 + { + 720, 480, /* width, height */ + 60, 27000, /* refresh, dot clock */ + 857, /* htotal */ + 719, 857, /* hblank_start, hblank_end */ + 735, 797, /* hsync_start, hsync_end */ + 524, /* vtotal */ + 479, 524, /* vblank_start, vblank_end */ + 488, 494, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_720x576x50 + { + 720, 576, /* width, height */ + 50, 27500, /* refresh, dot clock */ + 864, /* htotal */ + 719, 864, /* hblank_start, hblank_end */ + 732, 795, /* hsync_start, hsync_end */ + 625, /* vtotal */ + 575, 625, /* vblank_start, vblank_end */ + 581, 587, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif + /* OFF BY Default, enable when PLB is merged */ +#ifdef CONFIG_MODE_800x480x60 + { + 800, 480, /* width, height */ + 60, 33231, /* refresh, dot clock */ + 1055, /* htotal */ + 799, 1055, /* hblank_start, hblank_end */ + 863, 991, /* hsync_start, hsync_end */ + 524, /* vtotal */ + 479, 524, /* vblank_start, vblank_end */ + 500, 502, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_800x600x60 + { + 800, 600, /* width, height */ + 60, 40000, /* refresh, dot clock */ + 1055, /* htotal */ + 799, 1055, /* hblank_start, hblank_end */ + 839, 967, /* hsync_start, hsync_end */ + 627, /* vtotal */ + 599, 627, /* vblank_start, vblank_end */ + 600, 604, /* vsync_start, vsync_end */ + 0x103, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_800x600x70 + { + 800, 600, /* width, height */ + 70, 45500, /* refresh, dot clock */ + 1039, /* htotal */ + 799, 1039, /* hblank_start, hblank_end */ + 839, 919, /* hsync_start, hsync_end */ + 624, /* vtotal */ + 599, 624, /* vblank_start, vblank_end */ + 600, 603, /* vsync_start, vsync_end */ + 0x103, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_800x600x72 + { + 800, 600, /* width, height */ + 72, 50000, /* refresh, dot clock */ + 1039, /* htotal */ + 799, 1039, /* hblank_start, hblank_end */ + 855, 975, /* hsync_start, hsync_end */ + 665, /* vtotal */ + 599, 665, /* vblank_start, vblank_end */ + 636, 642, /* vsync_start, vsync_end */ + 0x103, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_800x600x75 + { + 800, 600, /* width, height */ + 75, 49500, /* refresh, dot clock */ + 1055, /* htotal */ + 799, 1055, /* hblank_start, hblank_end */ + 815, 895, /* hsync_start, hsync_end */ + 624, /* vtotal */ + 599, 624, /* vblank_start, vblank_end */ + 600, 603, /* vsync_start, vsync_end */ + 0x103, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_800x600x85 + { + 800, 600, /* width, height */ + 85, 56250, /* refresh, dot clock */ + 1047, /* htotal */ + 799, 1047, /* hblank_start, hblank_end */ + 831, 895, /* hsync_start, hsync_end */ + 630, /* vtotal */ + 599, 630, /* vblank_start, vblank_end */ + 600, 603, /* vsync_start, vsync_end */ + 0x103, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_800x600x100 + { + 800, 600, /* width, height */ + 100, 68179, /* refresh, dot clock */ + 1071, /* htotal */ + 799, 1071, /* hblank_start, hblank_end */ + 847, 935, /* hsync_start, hsync_end */ + 635, /* vtotal */ + 599, 635, /* vblank_start, vblank_end */ + 600, 603, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_800x600x120 + { + 800, 600, /* width, height */ + 120, 83950, /* refresh, dot clock */ + 1087, /* htotal */ + 799, 1087, /* hblank_start, hblank_end */ + 855, 943, /* hsync_start, hsync_end */ + 642, /* vtotal */ + 599, 642, /* vblank_start, vblank_end */ + 600, 603, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_960x540x60 + { + 960, 540, /* width, height */ + 60, 40785, /* refresh, dot clock */ + 1215, /* htotal */ + 959, 1215, /* hblank_start, hblank_end */ + 991, 1087, /* hsync_start, hsync_end */ + 558, /* vtotal */ + 539, 558, /* vblank_start, vblank_end */ + 540, 543, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1024x768x60 + { + 1024, 768, /* width, height */ + 60, 65000, /* refresh, dot clock */ + 1343, /* htotal */ + 1023, 1343, /* hblank_start, hblank_end */ + 1047, 1183, /* hsync_start, hsync_end */ + 805, /* vtotal */ + 767, 805, /* vblank_start, vblank_end */ + 770, 776, /* vsync_start, vsync_end */ + 0x105, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1024x768x70 + { + 1024, 768, /* width, height */ + 70, 75000, /* refresh, dot clock */ + 1327, /* htotal */ + 1023, 1327, /* hblank_start, hblank_end */ + 1047, 1183, /* hsync_start, hsync_end */ + 805, /* vtotal */ + 767, 805, /* vblank_start, vblank_end */ + 770, 776, /* vsync_start, vsync_end */ + 0x105, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1024x768x75 + { + 1024, 768, /* width, height */ + 75, 78750, /* refresh, dot clock */ + 1311, /* htotal */ + 1023, 1311, /* hblank_start, hblank_end */ + 1039, 1135, /* hsync_start, hsync_end */ + 799, /* vtotal */ + 767, 799, /* vblank_start, vblank_end */ + 768, 771, /* vsync_start, vsync_end */ + 0x105, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1024x768x85 + { + 1024, 768, /* width, height */ + 85, 94500, /* refresh, dot clock */ + 1375, /* htotal */ + 1023, 1375, /* hblank_start, hblank_end */ + 1071, 1167, /* hsync_start, hsync_end */ + 807, /* vtotal */ + 767, 807, /* vblank_start, vblank_end */ + 768, 771, /* vsync_start, vsync_end */ + 0x105, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1024x768x100 + { + 1024, 768, /* width, height */ + 100, 113310, /* refresh, dot clock */ + 1391, /* htotal */ + 1023, 1391, /* hblank_start, hblank_end */ + 1095, 1207, /* hsync_start, hsync_end */ + 813, /* vtotal */ + 767, 813, /* vblank_start, vblank_end */ + 768, 771, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1024x768x120 + { + 1024, 768, /* width, height */ + 120, 139050, /* refresh, dot clock */ + 1407, /* htotal */ + 1023, 1407, /* hblank_start, hblank_end */ + 1103, 1215, /* hsync_start, hsync_end */ + 822, /* vtotal */ + 767, 822, /* vblank_start, vblank_end */ + 768, 771, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity H+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1152x864x60 + { + 1152, 864, /* width, height */ + 60, 81624, /* refresh, dot clock */ + 1519, /* htotal */ + 1151, 1519, /* hblank_start, hblank_end */ + 1215, 1335, /* hsync_start, hsync_end */ + 894, /* vtotal */ + 863, 894, /* vblank_start, vblank_end */ + 864, 867, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1152x864x70 + { + 1152, 864, /* width, height */ + 70, 97000, /* refresh, dot clock */ + 1535, /* htotal */ + 1151, 1535, /* hblank_start, hblank_end */ + 1223, 1343, /* hsync_start, hsync_end */ + 899, /* vtotal */ + 863, 899, /* vblank_start, vblank_end */ + 864, 867, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1152x864x72 + { + 1152, 864, /* width, height */ + 72, 100000, /* refresh, dot clock */ + 1535, /* htotal */ + 1151, 1535, /* hblank_start, hblank_end */ + 1223, 1343, /* hsync_start, hsync_end */ + 900, /* vtotal */ + 863, 900, /* vblank_start, vblank_end */ + 864, 867, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1152x864x75 + { + 1152, 864, /* width, height */ + 75, 108000, /* refresh, dot clock */ + 1599, /* htotal */ + 1151, 1599, /* hblank_start, hblank_end */ + 1215, 1343, /* hsync_start, hsync_end */ + 899, /* vtotal */ + 863, 899, /* vblank_start, vblank_end */ + 864, 867, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1152x864x85 + { + 1152, 864, /* width, height */ + 85, 120000, /* refresh, dot clock */ + 1551, /* htotal */ + 1151, 1551, /* hblank_start, hblank_end */ + 1223, 1351, /* hsync_start, hsync_end */ + 906, /* vtotal */ + 863, 906, /* vblank_start, vblank_end */ + 864, 867, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1152x864x100 + { + 1152, 864, /* width, height */ + 100, 144000, /* refresh, dot clock */ + 1567, /* htotal */ + 1151, 1567, /* hblank_start, hblank_end */ + 1231, 1359, /* hsync_start, hsync_end */ + 914, /* vtotal */ + 863, 914, /* vblank_start, vblank_end */ + 864, 867, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x720x60 + { + 1280, 720, /* width, height */ + 60, 74481, /* refresh, dot clock */ + 1663, /* htotal */ + 1279, 1663, /* hblank_start, hblank_end */ + 1335, 1471, /* hsync_start, hsync_end */ + 745, /* vtotal */ + 719, 745, /* vblank_start, vblank_end */ + 720, 723, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x720x75 + { + 1280, 720, /* width, height */ + 75, 96000, /* refresh, dot clock */ + 1695, /* htotal */ + 1279, 1695, /* hblank_start, hblank_end */ + 1351, 1487, /* hsync_start, hsync_end */ + 751, /* vtotal */ + 719, 751, /* vblank_start, vblank_end */ + 720, 723, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x720x85 + { + 1280, 720, /* width, height */ + 85, 110000, /* refresh, dot clock */ + 1711, /* htotal */ + 1279, 1711, /* hblank_start, hblank_end */ + 1359, 1495, /* hsync_start, hsync_end */ + 755, /* vtotal */ + 719, 755, /* vblank_start, vblank_end */ + 720, 723, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x720x100 + { + 1280, 720, /* width, height */ + 100, 131850, /* refresh, dot clock */ + 1727, /* htotal */ + 1279, 1727, /* hblank_start, hblank_end */ + 1367, 1503, /* hsync_start, hsync_end */ + 762, /* vtotal */ + 719, 762, /* vblank_start, vblank_end */ + 720, 723, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x768x60 + { + 1280, 768, /* width, height */ + 60, 80136, /* refresh, dot clock */ + 1679, /* htotal */ + 1279, 1679, /* hblank_start, hblank_end */ + 1343, 1479, /* hsync_start, hsync_end */ + 794, /* vtotal */ + 767, 794, /* vblank_start, vblank_end */ + 768, 771, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x768x75 + { + 1280, 768, /* width, height */ + 75, 102977, /* refresh, dot clock */ + 1711, /* htotal */ + 1279, 1711, /* hblank_start, hblank_end */ + 1359, 1495, /* hsync_start, hsync_end */ + 801, /* vtotal */ + 767, 801, /* vblank_start, vblank_end */ + 768, 771, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x768x85 + { + 1280, 768, /* width, height */ + 85, 118532, /* refresh, dot clock */ + 1727, /* htotal */ + 1279, 1727, /* hblank_start, hblank_end */ + 1367, 1503, /* hsync_start, hsync_end */ + 806, /* vtotal */ + 767, 806, /* vblank_start, vblank_end */ + 768, 771, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x960x60 + { + 1280, 960, /* width, height */ + 60, 108000, /* refresh, dot clock */ + 1799, /* htotal */ + 1279, 1799, /* hblank_start, hblank_end */ + 1375, 1487, /* hsync_start, hsync_end */ + 999, /* vtotal */ + 959, 999, /* vblank_start, vblank_end */ + 960, 963, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x960x75 + { + 1280, 960, /* width, height */ + 75, 129859, /* refresh, dot clock */ + 1727, /* htotal */ + 1279, 1727, /* hblank_start, hblank_end */ + 1367, 1503, /* hsync_start, hsync_end */ + 1001, /* vtotal */ + 959, 1001, /* vblank_start, vblank_end */ + 960, 963, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x960x85 + { + 1280, 960, /* width, height */ + 85, 148500, /* refresh, dot clock */ + 1727, /* htotal */ + 1279, 1727, /* hblank_start, hblank_end */ + 1343, 1503, /* hsync_start, hsync_end */ + 1010, /* vtotal */ + 959, 1010, /* vblank_start, vblank_end */ + 960, 963, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x1024x60 + { + 1280, 1024, /* width, height */ + 60, 108000, /* refresh, dot clock */ + 1687, /* htotal */ + 1279, 1687, /* hblank_start, hblank_end */ + 1327, 1439, /* hsync_start, hsync_end */ + 1065, /* vtotal */ + 1023, 1065, /* vblank_start, vblank_end */ + 1024, 1027, /* vsync_start, vsync_end */ + 0x107, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x1024x70 + { + 1280, 1024, /* width, height */ + 70, 129000, /* refresh, dot clock */ + 1727, /* htotal */ + 1279, 1727, /* hblank_start, hblank_end */ + 1367, 1503, /* hsync_start, hsync_end */ + 1065, /* vtotal */ + 1023, 1065, /* vblank_start, vblank_end */ + 1024, 1027, /* vsync_start, vsync_end */ + 0x107, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x1024x72 + { + 1280, 1024, /* width, height */ + 72, 133000, /* refresh, dot clock */ + 1727, /* htotal */ + 1279, 1727, /* hblank_start, hblank_end */ + 1367, 1503, /* hsync_start, hsync_end */ + 1066, /* vtotal */ + 1023, 1066, /* vblank_start, vblank_end */ + 1024, 1027, /* vsync_start, vsync_end */ + 0x107, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x1024x75 + { + 1280, 1024, /* width, height */ + 75, 135000, /* refresh, dot clock */ + 1687, /* htotal */ + 1279, 1687, /* hblank_start, hblank_end */ + 1295, 1439, /* hsync_start, hsync_end */ + 1065, /* vtotal */ + 1023, 1065, /* vblank_start, vblank_end */ + 1024, 1027, /* vsync_start, vsync_end */ + 0x107, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x1024x85 + { + 1280, 1024, /* width, height */ + 85, 157500, /* refresh, dot clock */ + 1727, /* htotal */ + 1279, 1727, /* hblank_start, hblank_end */ + 1343, 1503, /* hsync_start, hsync_end */ + 1071, /* vtotal */ + 1023, 1071, /* vblank_start, vblank_end */ + 1024, 1027, /* vsync_start, vsync_end */ + 0x107, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x1024x100 + { + 1280, 1024, /* width, height */ + 100, 190960, /* refresh, dot clock */ + 1759, /* htotal */ + 1279, 1759, /* hblank_start, hblank_end */ + 1375, 1519, /* hsync_start, hsync_end */ + 1084, /* vtotal */ + 1023, 1084, /* vblank_start, vblank_end */ + 1024, 1027, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1280x1024x120 + { + 1280, 1024, /* width, height */ + 120, 233790, /* refresh, dot clock */ + 1775, /* htotal */ + 1279, 1775, /* hblank_start, hblank_end */ + 1383, 1527, /* hsync_start, hsync_end */ + 1096, /* vtotal */ + 1023, 1096, /* vblank_start, vblank_end */ + 1024, 1027, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1366x768x60 + { + 1366, 768, /* width, height */ + 60, 74057, /* refresh, dot clock */ + 1663, /* htotal */ + 1365, 1663, /* hblank_start, hblank_end */ + 1429, 1557, /* hsync_start, hsync_end */ + 775, /* vtotal */ + 767, 775, /* vblank_start, vblank_end */ + 768, 769, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH | /* polarity V+ */ + IGD_HSYNC_HIGH, /* polarity H+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif + +#ifdef CONFIG_MODE_1400x1050x60 + { + 1400, 1050, /* width, height */ + 60, 122000, /* refresh, dot clock */ + 1879, /* htotal */ + 1399, 1879, /* hblank_start, hblank_end */ + 1487, 1639, /* hsync_start, hsync_end */ + 1086, /* vtotal */ + 1049, 1086, /* vblank_start, vblank_end */ + 1050, 1053, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1400x1050x75 + { + 1400, 1050, /* width, height */ + 75, 155851, /* refresh, dot clock */ + 1895, /* htotal */ + 1399, 1895, /* hblank_start, hblank_end */ + 1495, 1647, /* hsync_start, hsync_end */ + 1095, /* vtotal */ + 1049, 1095, /* vblank_start, vblank_end */ + 1050, 1053, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1400x1050x85 + { + 1400, 1050, /* width, height */ + 85, 179260, /* refresh, dot clock */ + 1911, /* htotal */ + 1399, 1911, /* hblank_start, hblank_end */ + 1503, 1655, /* hsync_start, hsync_end */ + 1102, /* vtotal */ + 1049, 1102, /* vblank_start, vblank_end */ + 1050, 1053, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1600x900x60 + { + 1600, 900, /* width, height */ + 60, 119000, /* refresh, dot clock */ + 2127, /* htotal */ + 1599, 2127, /* hblank_start, hblank_end */ + 1695, 1863, /* hsync_start, hsync_end */ + 931, /* vtotal */ + 899, 931, /* vblank_start, vblank_end */ + 900, 903, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1600x900x75 + { + 1600, 900, /* width, height */ + 75, 152000, /* refresh, dot clock */ + 2159, /* htotal */ + 1599, 2159, /* hblank_start, hblank_end */ + 1703, 1879, /* hsync_start, hsync_end */ + 939, /* vtotal */ + 899, 939, /* vblank_start, vblank_end */ + 900, 903, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1600x900x85 + { + 1600, 900, /* width, height */ + 85, 175000, /* refresh, dot clock */ + 2175, /* htotal */ + 1599, 2175, /* hblank_start, hblank_end */ + 1711, 1887, /* hsync_start, hsync_end */ + 944, /* vtotal */ + 899, 944, /* vblank_start, vblank_end */ + 900, 903, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1600x900x100 + { + 1600, 900, /* width, height */ + 100, 208900, /* refresh, dot clock */ + 2191, /* htotal */ + 1599, 2191, /* hblank_start, hblank_end */ + 1719, 1895, /* hsync_start, hsync_end */ + 952, /* vtotal */ + 899, 952, /* vblank_start, vblank_end */ + 900, 903, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1600x900x120 + { + 1600, 900, /* width, height */ + 120, 255686, /* refresh, dot clock */ + 2207, /* htotal */ + 1599, 2207, /* hblank_start, hblank_end */ + 1727, 1903, /* hsync_start, hsync_end */ + 964, /* vtotal */ + 899, 964, /* vblank_start, vblank_end */ + 900, 903, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1600x1200x60 + { + 1600, 1200, /* width, height */ + 60, 162000, /* refresh, dot clock */ + 2159, /* htotal */ + 1599, 2159, /* hblank_start, hblank_end */ + 1663, 1855, /* hsync_start, hsync_end */ + 1249, /* vtotal */ + 1199, 1249, /* vblank_start, vblank_end */ + 1200, 1203, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1600x1200x65 + { + 1600, 1200, /* width, height */ + 65, 175500, /* refresh, dot clock */ + 2159, /* htotal */ + 1599, 2159, /* hblank_start, hblank_end */ + 1663, 1855, /* hsync_start, hsync_end */ + 1249, /* vtotal */ + 1199, 1249, /* vblank_start, vblank_end */ + 1200, 1203, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1600x1200x70 + { + 1600, 1200, /* width, height */ + 70, 189000, /* refresh, dot clock */ + 2159, /* htotal */ + 1599, 2159, /* hblank_start, hblank_end */ + 1663, 1855, /* hsync_start, hsync_end */ + 1249, /* vtotal */ + 1199, 1249, /* vblank_start, vblank_end */ + 1200, 1203, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1600x1200x72 + { + 1600, 1200, /* width, height */ + 72, 195000, /* refresh, dot clock */ + 2175, /* htotal */ + 1599, 2175, /* hblank_start, hblank_end */ + 1711, 1887, /* hsync_start, hsync_end */ + 1250, /* vtotal */ + 1199, 1250, /* vblank_start, vblank_end */ + 1200, 1203, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1600x1200x75 + { + 1600, 1200, /* width, height */ + 75, 202500, /* refresh, dot clock */ + 2159, /* htotal */ + 1599, 2159, /* hblank_start, hblank_end */ + 1663, 1855, /* hsync_start, hsync_end */ + 1249, /* vtotal */ + 1199, 1249, /* vblank_start, vblank_end */ + 1200, 1203, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1600x1200x85 + { + 1600, 1200, /* width, height */ + 85, 229500, /* refresh, dot clock */ + 2159, /* htotal */ + 1599, 2159, /* hblank_start, hblank_end */ + 1663, 1855, /* hsync_start, hsync_end */ + 1249, /* vtotal */ + 1199, 1249, /* vblank_start, vblank_end */ + 1200, 1203, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_HSYNC_HIGH| /* polarity H+ */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1600x1200x100 + { + 1600, 1200, /* width, height */ + 100, 280640, /* refresh, dot clock */ + 2207, /* htotal */ + 1599, 2207, /* hblank_start, hblank_end */ + 1727, 1903, /* hsync_start, hsync_end */ + 1270, /* vtotal */ + 1199, 1270, /* vblank_start, vblank_end */ + 1200, 1203, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1600x1200x120 + { + 1600, 1200, /* width, height */ + 120, 343210, /* refresh, dot clock */ + 2223, /* htotal */ + 1599, 2223, /* hblank_start, hblank_end */ + 1735, 1911, /* hsync_start, hsync_end */ + 1285, /* vtotal */ + 1199, 1285, /* vblank_start, vblank_end */ + 1200, 1203, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1856x1392x60 + { + 1856, 1392, /* width, height */ + 60, 218250, /* refresh, dot clock */ + 2527, /* htotal */ + 1855, 2527, /* hblank_start, hblank_end */ + 1951, 2175, /* hsync_start, hsync_end */ + 1438, /* vtotal */ + 1391, 1438, /* vblank_start, vblank_end */ + 1392, 1395, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1856x1392x75 + { + 1856, 1392, /* width, height */ + 75, 288000, /* refresh, dot clock */ + 2559, /* htotal */ + 1855, 2559, /* hblank_start, hblank_end */ + 1983, 2207, /* hsync_start, hsync_end */ + 1499, /* vtotal */ + 1391, 1499, /* vblank_start, vblank_end */ + 1392, 1395, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1920x1080x50 + { + 1920, 1080, /* width, height */ + 50, 141446, /* refresh, dot clock */ + 2543, /* htotal */ + 1919, 2543, /* hblank_start, hblank_end */ + 2031, 2231, /* hsync_start, hsync_end */ + 1111, /* vtotal */ + 1079, 1111, /* vblank_start, vblank_end */ + 1080, 1083, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1920x1080x60 + { + 1920, 1080, /* width, height */ + 60, 172800, /* refresh, dot clock */ + 2575, /* htotal */ + 1919, 2575, /* hblank_start, hblank_end */ + 2039, 2247, /* hsync_start, hsync_end */ + 1117, /* vtotal */ + 1079, 1117, /* vblank_start, vblank_end */ + 1080, 1083, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1920x1080x75 + { + 1920, 1080, /* width, height */ + 75, 220640, /* refresh, dot clock */ + 2607, /* htotal */ + 1919, 2607, /* hblank_start, hblank_end */ + 2055, 2263, /* hsync_start, hsync_end */ + 1127, /* vtotal */ + 1079, 1127, /* vblank_start, vblank_end */ + 1080, 1083, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1920x1080x85 + { + 1920, 1080, /* width, height */ + 85, 252930, /* refresh, dot clock */ + 2623, /* htotal */ + 1919, 2623, /* hblank_start, hblank_end */ + 2063, 2271, /* hsync_start, hsync_end */ + 1133, /* vtotal */ + 1079, 1133, /* vblank_start, vblank_end */ + 1080, 1083, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1920x1080x100 + { + 1920, 1080, /* width, height */ + 100, 302020, /* refresh, dot clock */ + 2639, /* htotal */ + 1919, 2639, /* hblank_start, hblank_end */ + 2071, 2279, /* hsync_start, hsync_end */ + 1143, /* vtotal */ + 1079, 1143, /* vblank_start, vblank_end */ + 1080, 1083, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1920x1200x60 + { + 1920, 1200, /* width, height */ + 60, 193156, /* refresh, dot clock */ + 2591, /* htotal */ + 1919, 2591, /* hblank_start, hblank_end */ + 2047, 2255, /* hsync_start, hsync_end */ + 1241, /* vtotal */ + 1199, 1241, /* vblank_start, vblank_end */ + 1200, 1203, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1920x1200x75 + { + 1920, 1200, /* width, height */ + 75, 246590, /* refresh, dot clock */ + 2623, /* htotal */ + 1919, 2623, /* hblank_start, hblank_end */ + 2063, 2271, /* hsync_start, hsync_end */ + 1252, /* vtotal */ + 1199, 1252, /* vblank_start, vblank_end */ + 1200, 1203, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1920x1440x60 + { + 1920, 1440, /* width, height */ + 60, 234000, /* refresh, dot clock */ + 2599, /* htotal */ + 1919, 2599, /* hblank_start, hblank_end */ + 2047, 2255, /* hsync_start, hsync_end */ + 1499, /* vtotal */ + 1439, 1499, /* vblank_start, vblank_end */ + 1440, 1443, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1920x1440x75 + { + 1920, 1440, /* width, height */ + 75, 297000, /* refresh, dot clock */ + 2639, /* htotal */ + 1919, 2639, /* hblank_start, hblank_end */ + 2063, 2287, /* hsync_start, hsync_end */ + 1499, /* vtotal */ + 1439, 1499, /* vblank_start, vblank_end */ + 1440, 1443, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_1920x1440x85 + { + 1920, 1440, /* width, height */ + 85, 341350, /* refresh, dot clock */ + 2655, /* htotal */ + 1919, 2655, /* hblank_start, hblank_end */ + 2071, 2287, /* hsync_start, hsync_end */ + 1511, /* vtotal */ + 1439, 1511, /* vblank_start, vblank_end */ + 1440, 1443, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_2048x1536x60 + { + 2048, 1536, /* width, height */ + 60, 266950, /* refresh, dot clock */ + 2799, /* htotal */ + 2047, 2799, /* hblank_start, hblank_end */ + 2199, 2423, /* hsync_start, hsync_end */ + 1588, /* vtotal */ + 1535, 1588, /* vblank_start, vblank_end */ + 1536, 1539, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_MODE_2048x1536x75 + { + 2048, 1536, /* width, height */ + 75, 340480, /* refresh, dot clock */ + 2831, /* htotal */ + 2047, 2831, /* hblank_start, hblank_end */ + 2215, 2439, /* hsync_start, hsync_end */ + 1602, /* vtotal */ + 1535, 1602, /* vblank_start, vblank_end */ + 1536, 1539, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE| /* mode info flags */ + IGD_VSYNC_HIGH, /* polarity V+ */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif + PD_TIMING_TABLE_END +}; + +int crt_timing_table_size = sizeof(crt_timing_table); + +#ifndef CONFIG_NEW_MATCH +/*--------------------------------------------------------------------------- + * Timing tables for VGA modes + *--------------------------------------------------------------------------- + */ +igd_timing_info_t vga_timing_table[] = +{ + { /* VGA Mode 0 */ + 320, 200, /* width, height */ + 60, 25175, /* refresh, dot clock */ + 399, /* htotal */ + 319, 383, /* hblank_start, hblank_end */ + 343, 383, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 405, 440, /* vblank_start, vblank_end */ + 411, 413, /* vsync_start, vsync_end */ + 0x00, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_MODE_TEXT | + IGD_LINE_DOUBLE | + IGD_PIXEL_DOUBLE | + IGD_VSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 1 */ + 320, 200, /* width, height */ + 60, 25175, /* refresh, dot clock */ + 399, /* htotal */ + 319, 383, /* hblank_start, hblank_end */ + 343, 383, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 405, 440, /* vblank_start, vblank_end */ + 411, 413, /* vsync_start, vsync_end */ + 0x01, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_MODE_TEXT | + IGD_LINE_DOUBLE | + IGD_PIXEL_DOUBLE | + IGD_VSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 2 */ + 640, 200, /* width, height */ + 70, 25175, /* refresh, dot clock */ + 799, /* htotal */ + 639, 783, /* hblank_start, hblank_end */ + 679, 775, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 405, 440, /* vblank_start, vblank_end */ + 411, 413, /* vsync_start, vsync_end */ + 0x02, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_MODE_TEXT | + IGD_LINE_DOUBLE | + IGD_VSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 3 */ + 640, 200, /* width, height */ + 70, 25175, /* refresh, dot clock */ + 799, /* htotal */ + 639, 783, /* hblank_start, hblank_end */ + 679, 775, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 405, 440, /* vblank_start, vblank_end */ + 411, 413, /* vsync_start, vsync_end */ + 0x03, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_MODE_TEXT | + IGD_LINE_DOUBLE | + IGD_VSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 4 */ + 320, 200, /* width, height */ + 60, 25175, /* refresh, dot clock */ + 399, /* htotal */ + 319, 383, /* hblank_start, hblank_end */ + 343, 383, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 405, 440, /* vblank_start, vblank_end */ + 411, 413, /* vsync_start, vsync_end */ + 0x04, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_LINE_DOUBLE | + IGD_VSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 5 */ + 320, 200, /* width, height */ + 60, 25175, /* refresh, dot clock */ + 399, /* htotal */ + 319, 383, /* hblank_start, hblank_end */ + 343, 383, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 405, 440, /* vblank_start, vblank_end */ + 411, 413, /* vsync_start, vsync_end */ + 0x05, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_LINE_DOUBLE | + IGD_VSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 6 */ + 640, 200, /* width, height */ + 60, 25175, /* refresh, dot clock */ + 799, /* htotal */ + 639, 784, /* hblank_start, hblank_end */ + 671, 767, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 405, 440, /* vblank_start, vblank_end */ + 411, 413, /* vsync_start, vsync_end */ + 0x06, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_LINE_DOUBLE | + IGD_VSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 7 */ + 720, 350, /* width, height */ + 60, 28322, /* refresh, dot clock */ + 899, /* htotal */ + 719, 881, /* hblank_start, hblank_end */ + 764, 872, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 354, 441, /* vblank_start, vblank_end */ + 386, 388, /* vsync_start, vsync_end */ + 0x07, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_MODE_TEXT | + IGD_HSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode d */ + 320, 200, /* width, height */ + 60, 25175, /* refresh, dot clock */ + 399, /* htotal */ + 319, 383, /* hblank_start, hblank_end */ + 343, 383, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 405, 440, /* vblank_start, vblank_end */ + 411, 413, /* vsync_start, vsync_end */ + 0x0d, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_LINE_DOUBLE | + IGD_PIXEL_DOUBLE | + IGD_VSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode e */ + 640, 200, /* width, height */ + 60, 25175, /* refresh, dot clock */ + 799, /* htotal */ + 639, 783, /* hblank_start, hblank_end */ + 671, 767, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 405, 440, /* vblank_start, vblank_end */ + 411, 413, /* vsync_start, vsync_end */ + 0x0e, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_LINE_DOUBLE | + IGD_VSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode f */ + 640, 350, /* width, height */ + 60, 25175, /* refresh, dot clock */ + 799, /* htotal */ + 639, 783, /* hblank_start, hblank_end */ + 671, 767, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 354, 441, /* vblank_start, vblank_end */ + 386, 388, /* vsync_start, vsync_end */ + 0x11, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_HSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 10 */ + 640, 350, /* width, height */ + 60, 25175, /* refresh, dot clock */ + 799, /* htotal */ + 639, 783, /* hblank_start, hblank_end */ + 671, 767, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 354, 441, /* vblank_start, vblank_end */ + 386, 388, /* vsync_start, vsync_end */ + 0x12, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_HSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 0* */ + 320, 350, /* width, height */ + 60, 25175, /* refresh, dot clock */ + 399, /* htotal */ + 319, 383, /* hblank_start, hblank_end */ + 343, 383, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 354, 441, /* vblank_start, vblank_end */ + 386, 388, /* vsync_start, vsync_end */ + 0x13, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_PIXEL_DOUBLE | + IGD_MODE_TEXT | + IGD_HSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 1* */ + 320, 350, /* width, height */ + 60, 25175, /* refresh, dot clock */ + 399, /* htotal */ + 319, 383, /* hblank_start, hblank_end */ + 343, 383, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 354, 441, /* vblank_start, vblank_end */ + 386, 388, /* vsync_start, vsync_end */ + 0x14, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_PIXEL_DOUBLE | + IGD_MODE_TEXT | + IGD_HSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 2* */ + 640, 350, /* width, height */ + 70, 25175, /* refresh, dot clock */ + 799, /* htotal */ + 639, 783, /* hblank_start, hblank_end */ + 679, 775, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 354, 441, /* vblank_start, vblank_end */ + 386, 388, /* vsync_start, vsync_end */ + 0x15, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_MODE_TEXT | + IGD_HSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 3* */ + 640, 350, /* width, height */ + 70, 25175, /* refresh, dot clock */ + 799, /* htotal */ + 639, 783, /* hblank_start, hblank_end */ + 679, 775, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 354, 441, /* vblank_start, vblank_end */ + 386, 388, /* vsync_start, vsync_end */ + 0x16, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_MODE_TEXT | + IGD_HSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 0+,1+ */ + 360, 400, /* width, height */ + 60, 28322, /* refresh, dot clock */ + 449, /* htotal */ + 359, 431, /* hblank_start, hblank_end */ + 386, 431, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 405, 440, /* vblank_start, vblank_end */ + 411, 413, /* vsync_start, vsync_end */ + 0x17, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_PIXEL_DOUBLE | + IGD_MODE_TEXT | + IGD_VSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 2+,3+ */ + 720, 400, /* width, height */ + 70, 28322, /* refresh, dot clock */ + 899, /* htotal */ + 719, 881, /* hblank_start, hblank_end */ + 764, 872, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 405, 440, /* vblank_start, vblank_end */ + 411, 413, /* vsync_start, vsync_end */ + 0x18, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_MODE_TEXT | + IGD_VSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 7+ */ + 720, 400, /* width, height */ + 60, 28322, /* refresh, dot clock */ + 899, /* htotal */ + 719, 881, /* hblank_start, hblank_end */ + 764, 872, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 405, 440, /* vblank_start, vblank_end */ + 411, 413, /* vsync_start, vsync_end */ + 0x19, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_MODE_TEXT | + IGD_VSYNC_HIGH | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 11 */ + 640, 480, /* width, height */ + 60, 25175, /* refresh, dot clock */ + 799, /* htotal */ + 639, 783, /* hblank_start, hblank_end */ + 671, 767, /* hsync_start, hsync_end */ + 524, /* vtotal */ + 486, 515, /* vblank_start, vblank_end */ + 489, 491, /* vsync_start, vsync_end */ + 0x1A, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 12 */ + 640, 480, /* width, height */ + 60, 25175, /* refresh, dot clock */ + 799, /* htotal */ + 639, 783, /* hblank_start, hblank_end */ + 671, 767, /* hsync_start, hsync_end */ + 524, /* vtotal */ + 486, 515, /* vblank_start, vblank_end */ + 489, 491, /* vsync_start, vsync_end */ + 0x1B, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + { /* VGA Mode 13 */ + 320, 200, /* width, height */ + 60, 25175, /* refresh, dot clock */ + 799, /* htotal */ + 639, 783, /* hblank_start, hblank_end */ + 671, 767, /* hsync_start, hsync_end */ + 448, /* vtotal */ + 405, 440, /* vblank_start, vblank_end */ + 411, 413, /* vsync_start, vsync_end */ + 0x1C, /* mode number */ + IGD_MODE_VESA | /* VESA/VGA mode */ + IGD_LINE_DOUBLE | + IGD_PIXEL_DOUBLE | + IGD_MODE_SUPPORTED | + IGD_SCAN_PROGRESSIVE, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, + + PD_TIMING_TABLE_END +}; +#endif + +/* CEA standard timings: Get them from CEA-861. This is following DPG. + We will replace the mode number to CEA*/ +igd_timing_info_t cea_timing_table[] = +{ +#ifdef CONFIG_CEA_MODE_640x480px60 + { + 640, 480, /* width, height */ + 60, 25200, /* refresh, dot clock */ + 800, /* htotal */ + 640, 799, /* hblank_start, hblank_end */ + 656, 751, /* hsync_start, hsync_end */ + 525, /* vtotal */ + 480, 524, /* vblank_start, vblank_end */ + 490, 491, /* vsync_start, vsync_end */ + 1, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE | + PD_MODE_CEA, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* mode extenstion pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_CEA_MODE_720x480px60 + { + 720, 480, /* width, height */ + 60, 27000, /* refresh, dot clock */ + 858, /* htotal */ + 720, 857, /* hblank_start, hblank_end */ + 736, 797, /* hsync_start, hsync_end */ + 525, /* vtotal */ + 480, 524, /* vblank_start, vblank_end */ + 489, 494, /* vsync_start, vsync_end */ + 2, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE | + PD_MODE_CEA, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_CEA_MODE_720x480p_ax60 + { + 720, 480, /* width, height */ + 60, 27000, /* refresh, dot clock */ + 858, /* htotal */ + 720, 857, /* hblank_start, hblank_end */ + 736, 797, /* hsync_start, hsync_end */ + 525, /* vtotal */ + 480, 524, /* vblank_start, vblank_end */ + 489, 494, /* vsync_start, vsync_end */ + 3, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE | + PD_MODE_CEA | /* mode info flags */ + PD_ASPECT_16_9, /* Aspect ratio 16:9 */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_CEA_MODE_720x576px50 + { + 720, 576, /* width, height */ + 50, 27000, /* refresh, dot clock */ + 864, /* htotal */ + 720, 863, /* hblank_start, hblank_end */ + 732, 795, /* hsync_start, hsync_end */ + 625, /* vtotal */ + 575, 624, /* vblank_start, vblank_end */ + 581, 585, /* vsync_start, vsync_end */ + 17, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE | + PD_MODE_CEA, /* mode info flags */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_CEA_MODE_720x576p_ax50 + { + 720, 576, /* width, height */ + 50, 27000, /* refresh, dot clock */ + 864, /* htotal */ + 720, 863, /* hblank_start, hblank_end */ + 732, 795, /* hsync_start, hsync_end */ + 625, /* vtotal */ + 575, 624, /* vblank_start, vblank_end */ + 581, 585, /* vsync_start, vsync_end */ + 18, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE | + PD_MODE_CEA | /* mode info flags */ + PD_ASPECT_16_9, /* Aspect ratio 16:9 */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_CEA_MODE_1280x720p_ax50 + { + 1280, 720, /* width, height */ + 50, 74250, /* refresh, dot clock */ + 1980, /* htotal */ + 1280, 1979, /* hblank_start, hblank_end */ + 1720, 1759, /* hsync_start, hsync_end */ + 750, /* vtotal */ + 720, 749, /* vblank_start, vblank_end */ + 725, 729, /* vsync_start, vsync_end */ + 19, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE | + PD_MODE_CEA | /* mode info flags */ + PD_ASPECT_16_9, /* Aspect ratio 16:9 */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_CEA_MODE_1280x720p_ax60 + { + 1280, 720, /* width, height */ + 60, 74250, /* refresh, dot clock */ + 1650, /* htotal */ + 1280, 1649, /* hblank_start, hblank_end */ + 1390, 1429, /* hsync_start, hsync_end */ + 750, /* vtotal */ + 720, 749, /* vblank_start, vblank_end */ + 725, 729, /* vsync_start, vsync_end */ + 4, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE | /* mode info flags */ + IGD_VSYNC_HIGH | + PD_MODE_CEA | /* polarity V+ */ + PD_ASPECT_16_9, /* Aspect ratio 16:9 */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +/* KIV. Not proper timimgs, rerefer to DPG updates */ +#ifdef CONFIG_CEA_MODE_1920x1080p_ax50 + { + 1920, 1080, /* width, height */ + 50, 148500, /* refresh, dot clock */ + 2640, /* htotal */ + 1920, 2639, /* hblank_start, hblank_end */ + 2448, 2491, /* hsync_start, hsync_end */ + 1125, /* vtotal */ + 1080, 1124, /* vblank_start, vblank_end */ + 1084, 1088, /* vsync_start, vsync_end */ + 31, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE | /* mode info flags */ + IGD_VSYNC_HIGH | + PD_MODE_CEA | /* polarity V+ */ + PD_ASPECT_16_9, /* Aspect ratio 16:9 */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_CEA_MODE_1920x1080p_ax60 + { + 1920, 1080, /* width, height */ + 60, 148500, /* refresh, dot clock */ + 2200, /* htotal */ + 1920, 2199, /* hblank_start, hblank_end */ + 2008, 2051, /* hsync_start, hsync_end */ + 1125, /* vtotal */ + 1080, 1124, /* vblank_start, vblank_end */ + 1084, 1088, /* vsync_start, vsync_end */ + 16, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_PROGRESSIVE | /* mode info flags */ + IGD_VSYNC_HIGH | + PD_MODE_CEA | /* polarity V+ */ + PD_ASPECT_16_9, /* Aspect ratio 16:9 */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_CEA_MODE_1920x1080i_ax50 + { + 1920, 1080, /* width, height */ + 25, 74250, /* refresh, dot clock */ + 2640, /* htotal */ + 1920, 2639, /* hblank_start, hblank_end */ + 2448, 2491, /* hsync_start, hsync_end */ + 1124, /* vtotal */ + 1080, 1123, /* vblank_start, vblank_end */ + 1084, 1093, /* vsync_start, vsync_end */ + 20, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_INTERLACE | /* mode info flags */ + IGD_VSYNC_HIGH | + PD_MODE_CEA | /* polarity V+ */ + PD_ASPECT_16_9, /* Aspect ratio 16:9 */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif +#ifdef CONFIG_CEA_MODE_1920x1080i_ax60 + { + 1920, 1080, /* width, height */ + 30, 74250, /* refresh, dot clock */ + 2200, /* htotal */ + 1920, 2199, /* hblank_start, hblank_end */ + 2008, 2051, /* hsync_start, hsync_end */ + 1124, /* vtotal */ + 1080, 1123, /* vblank_start, vblank_end */ + 1084, 1093, /* vsync_start, vsync_end */ + 5, /* mode number */ + PD_MODE_SUPPORTED | /* enable the mode */ + IGD_SCAN_INTERLACE | /* mode info flags */ + IGD_VSYNC_HIGH | + PD_MODE_CEA | /* polarity V+ */ + PD_ASPECT_16_9, /* Aspect ratio 16:9 */ + 0, 0, /* x, y offset */ + NULL, /* pd extension pointer */ + NULL /* mode extenstion pointer */ + }, +#endif + PD_TIMING_TABLE_END +}; + +#ifndef CONFIG_MICRO +int cea_timing_table_size = sizeof(cea_timing_table); + +/* CEA timings for parsing purpose */ +type_std_t cea_std_lookup[] = +{ + { 640, 400, 60, 0 }, + { 720, 480, 60, 0 }, + { 720, 480, 60, PD_ASPECT_16_9 }, + { 1280, 720, 60, PD_ASPECT_16_9 }, + { 1920, 1080, 60, PD_SCAN_INTERLACE | PD_ASPECT_16_9 }, + { 720, 480, 60, PD_SCAN_INTERLACE }, + { 720, 480, 60, PD_SCAN_INTERLACE | PD_ASPECT_16_9 }, + { 720, 240, 60, 0 }, + + { 720, 240, 60, PD_ASPECT_16_9 }, + { 2880, 480, 60, PD_SCAN_INTERLACE }, + { 2880, 480, 60, PD_SCAN_INTERLACE | PD_ASPECT_16_9 }, + { 2880, 240, 60, 0 }, + { 2880, 240, 60, PD_ASPECT_16_9 }, + { 1440, 480, 60, 0 }, + { 1440, 480, 60, PD_ASPECT_16_9 }, + { 1920, 1080, 60, PD_ASPECT_16_9 }, + + { 720, 576, 50, 0 }, + { 720, 576, 50, PD_ASPECT_16_9 }, + { 1280, 720, 50, PD_ASPECT_16_9 }, + { 1920, 1080, 50, PD_SCAN_INTERLACE | PD_ASPECT_16_9 }, + { 720, 576, 50, PD_SCAN_INTERLACE }, + { 720, 576, 50, PD_SCAN_INTERLACE | PD_ASPECT_16_9 }, + { 720, 288, 50, 0 }, + { 720, 288, 50, PD_ASPECT_16_9 }, + + { 2880, 576, 50, PD_SCAN_INTERLACE }, + { 2880, 576, 50, PD_SCAN_INTERLACE | PD_ASPECT_16_9 }, + { 2880, 288, 50, 0 }, + { 2880, 288, 50, PD_ASPECT_16_9 }, + { 1440, 576, 50, 0 }, + { 1440, 576, 50, PD_ASPECT_16_9 }, + { 1920, 1080, 50, PD_ASPECT_16_9 }, + { 1920, 1080, 24, PD_ASPECT_16_9 }, + + { 1920, 1080, 25, PD_ASPECT_16_9 }, + { 1920, 1080, 30, PD_ASPECT_16_9 }, + { 2880, 480, 60, 0 }, + { 2880, 480, 60, PD_ASPECT_16_9 }, + { 2880, 576, 50, 0 }, + { 2880, 576, 50, PD_ASPECT_16_9 }, + { 1920, 1080, 50, PD_SCAN_INTERLACE | PD_ASPECT_16_9 }, + { 1920, 1080, 100, PD_SCAN_INTERLACE | PD_ASPECT_16_9 }, + + { 1280, 720, 100, PD_ASPECT_16_9 }, + { 720, 576, 100, 0 }, + { 720, 576, 100, PD_ASPECT_16_9 }, + { 720, 576, 100, PD_SCAN_INTERLACE }, + { 720, 576, 100, PD_SCAN_INTERLACE | PD_ASPECT_16_9 }, + { 1920, 1080, 120, PD_SCAN_INTERLACE | PD_ASPECT_16_9 }, + { 1280, 720, 120, PD_ASPECT_16_9 }, + { 720, 480, 120, 0 }, + + { 720, 480, 120, PD_ASPECT_16_9 }, + { 720, 480, 120, PD_SCAN_INTERLACE }, + { 720, 480, 120, PD_SCAN_INTERLACE | PD_ASPECT_16_9 }, + { 720, 576, 200, 0 }, + { 720, 576, 200, PD_ASPECT_16_9 }, + { 720, 576, 200, PD_SCAN_INTERLACE }, + { 720, 576, 200, PD_SCAN_INTERLACE | PD_ASPECT_16_9 }, + { 720, 480, 240, 0 }, + + { 720, 480, 240, PD_ASPECT_16_9 }, + { 720, 480, 240, PD_SCAN_INTERLACE }, + { 720, 480, 240, PD_SCAN_INTERLACE | PD_ASPECT_16_9 }, + { 1280, 720, 24, PD_ASPECT_16_9 }, + { 1280, 720, 25, PD_ASPECT_16_9 }, + { 1280, 720, 30, PD_ASPECT_16_9 }, +}; + +int cea_std_lookup_size = sizeof(cea_std_lookup)/sizeof(type_std_t); + +#endif +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: mode_table.c,v 1.2 2010/04/27 20:33:49 bpaauwe Exp $ + * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/pi/cmn/mode_table.c,v $ + *---------------------------------------------------------------------------- + */ + diff --git a/drivers/gpu/drm/emgd/emgd/display/pi/cmn/pd_init_all.c b/drivers/gpu/drm/emgd/emgd/display/pi/cmn/pd_init_all.c new file mode 100644 index 0000000..64d9537 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/pi/cmn/pd_init_all.c @@ -0,0 +1,199 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: pd_init_all.c + * $Revision: 1.2 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * This file controls the port drivers that are initialized as part of + * the HAL init. These must be statically linked with the HAL. + * NOTE: This file is visible to customers. It is used in source form as + * part of the vBIOS build procedure. + *----------------------------------------------------------------------------- + */ + +#include "config.h" + +/*! + * @addtogroup display_group + * @{ + */ + +/* Enable Analog (CRT) port driver */ +#ifdef CONFIG_LINK_PD_ANALOG +extern int analog_init(void *handle); +#define ANALOG_INIT(handle) analog_init(handle) +#else +#define ANALOG_INIT(handle) 0 +#endif + +/* Enable Silicon Image 154/164 FP port driver */ +#ifdef CONFIG_LINK_PD_SII164 +extern int sii164_init(void *handle); +#define SII164_INIT(handle) sii164_init(handle) +#else +#define SII164_INIT(handle) 0 +#endif + +/* Enable Texas Instruments 410 FP port driver */ +#ifdef CONFIG_LINK_PD_TI410 +extern int ti410_init(void *handle); +#define TI410_INIT(handle) ti410_init(handle) +#else +#define TI410_INIT(handle) 0 +#endif + +/* Enable Chrontel 7009 TMDS & TVOut port driver */ +#ifdef CONFIG_LINK_PD_CH7009 +extern int ch7009_init(void *handle); +#define CH7009_INIT(handle) ch7009_init(handle) +#else +#define CH7009_INIT(handle) 0 +#endif + +/* Enable National Semiconductor 2501 LVDS port driver */ +#ifdef CONFIG_LINK_PD_NS2501 +extern int ns2501_init(void *handle); +#define NS2501_INIT(handle) ns2501_init(handle) +#else +#define NS2501_INIT(handle) 0 +#endif + +/* Enable TL955 port driver */ +#ifdef CONFIG_LINK_PD_TL955 +extern int tl955_init(void *handle); +#define TL955_INIT(handle) tl955_init(handle) +#else +#define TL955_INIT(handle) 0 +#endif + +/* Enable Th164 port driver */ +#ifdef CONFIG_LINK_PD_TH164 +extern int th164_init(void *handle); +#define TH164_INIT(handle) th164_init(handle) +#else +#define TH164_INIT(handle) 0 +#endif + +/* Enable FS454 port driver */ +#ifdef CONFIG_LINK_PD_FS454 +extern int fs454_init(void *handle); +#define FS454_INIT(handle) fs454_init(handle) +#else +#define FS454_INIT(handle) 0 +#endif + +/* Enable NS387/389 port driver */ +#ifdef CONFIG_LINK_PD_NS387 +extern int ns387_init(void *handle); +#define NS387_INIT(handle) ns387_init(handle) +#else +#define NS387_INIT(handle) 0 +#endif + +/* Enable connexant port driver */ +#ifdef CONFIG_LINK_PD_CX873 +extern int cx873_init(void *handle); +#define CX873_INIT(handle) cx873_init(handle) +#else +#define CX873_INIT(handle) 0 +#endif + +/* Enable Internal LVDS port driver */ +#ifdef CONFIG_LINK_PD_LVDS +extern int lvds_init(void *handle); +#define LVDS_INIT(handle) lvds_init(handle) +#else +#define LVDS_INIT(handle) 0 +#endif + +/* Enable SDVO port driver */ +#ifdef CONFIG_LINK_PD_SDVO +extern int sdvo_init(void *handle); +#define SDVO_INIT(handle) sdvo_init(handle) +#else +#define SDVO_INIT(handle) 0 +#endif + +/* Enable Integrated TV port driver for NAPA */ +#ifdef CONFIG_LINK_PD_TV +extern int tv_init(void *handle); +#define TV_INIT(handle) tv_init(handle) +#else +#define TV_INIT(handle) 0 +#endif + +/* Enable FS460 port driver */ +#ifdef CONFIG_LINK_PD_FS460 +extern int fs460_init(void *handle); +#define FS460_INIT(handle) fs460_init(handle) +#else +#define FS460_INIT(handle) 0 +#endif + +/* Enable FS450 port driver */ +#ifdef CONFIG_LINK_PD_FS450 +extern int fs450_init(void *handle); +#define FS450_INIT(handle) fs450_init(handle) +#else +#define FS450_INIT(handle) 0 +#endif + +/* Enable Chrontel 7017 LVDS & TVOut port driver */ +#ifdef CONFIG_LINK_PD_CH7017 +extern int ch7017_init(void *handle); +#define CH7017_INIT(handle) ch7017_init(handle) +#else +#define CH7017_INIT(handle) 0 +#endif + +/* Enable internal HDMI port driver */ +#ifdef CONFIG_LINK_PD_HDMI +extern int hdmi_init(void *handle); +#define HDMI_INIT(handle) hdmi_init(handle) +#else +#define HDMI_INIT(handle) 0 +#endif + +/*! + * + * @param handle + * + * @return 0 + */ +int pi_init_all(void *handle) +{ + int ret; + + ret = ANALOG_INIT(handle); + ret = CH7009_INIT(handle); + ret = SII164_INIT(handle); + ret = NS2501_INIT(handle); + ret = TH164_INIT(handle); + ret = NS387_INIT(handle); + ret = FS454_INIT(handle); + ret = CH7017_INIT(handle); + ret = LVDS_INIT(handle); + ret = SDVO_INIT(handle); + ret = TI410_INIT(handle); + ret = TV_INIT(handle); + ret = HDMI_INIT(handle); + /* ret = PD000_INIT(handle); */ + + return 0; +} + diff --git a/drivers/gpu/drm/emgd/emgd/display/pi/cmn/pi.c b/drivers/gpu/drm/emgd/emgd/display/pi/cmn/pi.c new file mode 100755 index 0000000..65c1c42 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/pi/cmn/pi.c @@ -0,0 +1,1723 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: pi.c + * $Revision: 1.7 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * This file contains all the necessary functions for port interface + * module. This module abstracts all hardware port interfaces and + * manages them. + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.dpd + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2c_dispatch.h" + +/*! + * @addtogroup display_group + * @{ + */ + +typedef struct _pi_context { + igd_context_t *igd_context; + i2c_dispatch_t *i2c_dispatch; + unsigned long num_pi_drivers; +} pi_context_t; + +/* Function to filter the modes using EDID or DisplayID*/ +int get_firmware_timings(igd_display_port_t *port, + unsigned char *firmware_data, pd_timing_t *timing_table); + +int pi_pd_init(igd_display_port_t *port, unsigned long port_feature, + unsigned long second_port_feature, int drm_load_time); +unsigned long get_magic_cookie(pd_driver_t *pd_driver); +void assign_dynamic_numbers(igd_timing_info_t *timing_table); +int update_attrs(igd_display_port_t *port); +pd_timing_t *get_user_timings(igd_param_dtd_list_t *in_list); + + +extern int pi_init_all(void *handle); + + +extern i2c_dispatch_t i2c_dispatch_plb; +extern i2c_dispatch_t i2c_dispatch_tnc; + +int null_func( void ) +{ + return -IGD_ERROR_NODEV; +} +/* Not currently used +static i2c_dispatch_t i2c_dispatch_null = { + (void *)null_func, + (void *)null_func, + (void *)null_func, + (void *)null_func +}; */ + + +static dispatch_table_t i2c_dispatch_list[] = { + +#ifdef CONFIG_PLB + {PCI_DEVICE_ID_VGA_PLB, &i2c_dispatch_plb}, +#endif +#ifdef CONFIG_TNC + {PCI_DEVICE_ID_VGA_TNC, &i2c_dispatch_tnc}, +#endif + + {0, NULL} +}; + +static unsigned char firmware_data[256]; + +static pi_context_t pi_context[1]; + +/*---------------------------------------------------------------------- + * FUNCTION DEFINITIONS + *----------------------------------------------------------------------*/ +#ifndef CONFIG_MICRO +/*! + * + * @param context + * + * @return void + */ +static void pi_shutdown(igd_context_t *context) +{ + igd_display_port_t *port; + + OS_TRACE_ENTER; + + if (pi_context->igd_context == NULL) { + return; + } + + /* Close the port drivers */ + port = NULL; + while ((port = context->mod_dispatch.dsp_get_next_port(context, port, 0)) != NULL) { + if (port->pd_driver) { + port->pd_driver->pd_close(port->pd_context); + /* pd_context is freed by port driver */ + port->pd_context = NULL; + port->timing_table = NULL; + port->num_timing = 0; + if (port->fp_info) { + OS_FREE(port->fp_info); + port->fp_info = NULL; + } + if (port->callback) { + OS_FREE(port->callback); + port->callback = NULL; + } + } + } + + OS_TRACE_EXIT; + return; +} + +/*! + * + * @param context + * + * @return 0 + */ +int pi_full_init(igd_context_t *context) +{ + /* Optional Inter-module interfaces */ + context->mod_dispatch.pi_shutdown = pi_shutdown; + return 0; +} + +#endif + +/*! + * + * @param context + * @param config_info + * + * @return 0 + */ +static int pi_get_config_info(igd_context_t *context, + igd_config_info_t *config_info) +{ + OS_TRACE_ENTER; + + OS_ASSERT(context, "Null context", -IGD_ERROR_INVAL); + OS_ASSERT(config_info, "Null config_info", -IGD_ERROR_INVAL); + + config_info->num_act_dsp_ports = pi_context->num_pi_drivers; + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param context + * + * @return 0 + */ +int pi_init(igd_context_t *context) +{ + i2c_dispatch_t *i2c_dispatch; + + OS_TRACE_ENTER; + + OS_MEMSET(pi_context, 0, sizeof(pi_context_t)); + + /* Save igd_context in local_igd_context. */ + pi_context->igd_context = context; + + /* Get I2C dispatch table */ + i2c_dispatch = (i2c_dispatch_t *)dispatch_acquire(context, + i2c_dispatch_list); + if(!i2c_dispatch) { + OS_DEBUG("No i2c Dispatch available for PI module"); + } + pi_context->i2c_dispatch = i2c_dispatch; + + /* + * If Dynamic Port drivers are not used then init the static drivers + * now. + */ +#ifndef IGD_DPD_ENABLED + { + void *handle = NULL; + int ret; + ret = pi_init_all(handle); + } +#endif + + /* Inter-module dispatch functions */ + context->mod_dispatch.i2c_read_regs = i2c_dispatch->i2c_read_regs; + context->mod_dispatch.i2c_write_reg_list = + i2c_dispatch->i2c_write_reg_list; + context->mod_dispatch.pi_get_config_info = pi_get_config_info; + + OPT_MICRO_CALL(pi_full_init(context)); + + OS_TRACE_EXIT; + return 0; +} + +/*! + * Get a port with the requested feature set from the list. Don't allocate + * it just return it. Only consider ports that aren't already in use. + * + * @param feature + * @param last + * + * @return port on success + * @return NULL on failure + */ +igd_display_port_t *pi_get_feature_port(unsigned long feature, + igd_display_port_t *last) +{ + igd_display_port_t *port; + inter_module_dispatch_t *md = &pi_context->igd_context->mod_dispatch; + + while ((port = md->dsp_get_next_port(pi_context->igd_context, last, 0))) { + if (!port->inuse) { + if (feature) { + if (port->port_features & feature) { + return port; + } + } else { + return port; + } + } + last = port; + } + + return NULL; +} + +/*! + * Function to register port driver with display driver + * + * @param pd_driver + * + * @return PD_SUCCESS on success + * @return PD_ERR_NULL_PTR, PD_ERR_VER_MISMATCH, PD_ERR_DISPLAY_TYPE, + * PD_ERR_NOMEM on failure + */ +int pi_pd_register(pd_driver_t *pd_driver) +{ + igd_display_port_t *port; + igd_param_t *init_params; + unsigned long prev_dab = 0, prev_i2c_speed = 0; + unsigned long port_type, port_feature, second_port_feature = 0; + unsigned long cookie_sent, cookie_rcvd; + unsigned long num_instances = 0; + unsigned long prev_instance_dab = 0, prev_instance_i2c_reg = 0; + unsigned long dab_index = 0; + int ret = PD_SUCCESS; + + OS_TRACE_ENTER; + + if (!pd_driver) { + OS_ERROR_EXIT("Null pd_driver received."); + return PD_ERR_NULL_PTR; + } + + /* Check the PD SDK version (interface version between main and + * port drivers Rightnow this check is useful only for XFree86. + * XP and CE already done this checking. */ + if (pd_driver->pd_sdk_version != PD_SDK_VERSION) { + OS_ERROR("PD SDK version mismatch between main driver" + "and %s. %u.%u != %u.%u", pd_driver->name, + (unsigned short) PD_SDK_VERSION>>8, + (unsigned short) PD_SDK_VERSION & 0xFF, + (unsigned short) pd_driver->pd_sdk_version>>8, + (unsigned short) pd_driver->pd_sdk_version & 0xFF); + return PD_ERR_VER_MISMATCH; + } + + /* Do magic cookie hand shaking */ + cookie_sent = get_magic_cookie(pd_driver); + cookie_rcvd = pd_driver->validate(cookie_sent); + if (cookie_sent != cookie_rcvd) { + /* TODO: Do this check once we comeup with handshake algorithm. */ + /* + OS_ERROR("Error, magic cookie handshaking failed."); + return PD_ERR_HAND_SHAKE; + */ + } + + init_params = pi_context->igd_context->mod_dispatch.init_params; + + port_feature = 0; + /* Get the port features based on the display types */ + if (pd_driver->type == PD_DISPLAY_CRT) { + /* Allocate GMCH onboard CRT port */ + port_type = IGD_PORT_ANALOG; + } else if (pd_driver->type == PD_DISPLAY_LVDS_INT) { + /* Allocate GMCH onboard LVDS port */ + port_type = IGD_PORT_LVDS; + } else if (pd_driver->type == PD_DISPLAY_TVOUT_INT) { + /* Allocate GMCH onboard TV port */ + port_type = IGD_PORT_TV; + } else if (pd_driver->type & + (PD_DISPLAY_TVOUT | PD_DISPLAY_FP | PD_DISPLAY_CRT_EXT | + PD_DISPLAY_LVDS_EXT | PD_DISPLAY_HDMI_EXT| PD_DISPLAY_HDMI_INT| + PD_DISPLAY_DRGB)) { + + /* Allocate DVO port which is the only kind of port exported to + * 3rd party encoders */ + port_type = IGD_PORT_DIGITAL; + + if (pd_driver->flags & PD_FLAG_GANG_MODE) { + igd_display_port_t *portb; + unsigned long user_gang = 0; + /* Get DVO Port B */ + pi_context->igd_context->mod_dispatch.dsp_get_display(2, + NULL, &portb, 0); + if(portb) { + if (portb->attr_list && portb->attr_list->num_attrs != 0) { + unsigned long i; + for (i = 0; i < portb->attr_list->num_attrs; i++) { + if (portb->attr_list->attr[i].id==PD_ATTR_ID_GANG_MODE){ + user_gang = portb->attr_list->attr[i].value; + } + } + } + } + /* If both user attribute and port driver flag are set to GANG MODE, + * then allocate a gang display port */ + if (user_gang) { + port_feature = IGD_PORT_GANG; + second_port_feature = IGD_PORT_GANG; + } + } + } else if (pd_driver->type == PD_DISPLAY_RGBA) { + port_type = IGD_PORT_DIGITAL; + port_feature = IGD_RGBA_COLOR; + second_port_feature = IGD_RGBA_ALPHA; + } else { + OS_ERROR_EXIT("Invalid display type."); + return PD_ERR_DISPLAY_TYPE; + } + + /* Get the port entry */ + port = NULL; + while((port = pi_get_feature_port(port_feature, port))) { + dab_index = 0; + + + /* This port already has a port driver, + * don't search device on this port. */ + if (port->pd_driver || (port->port_type != port_type)) { + continue; + } + + /* allocate memory for callback */ + port->callback = (pd_callback_t *)OS_ALLOC(sizeof(pd_callback_t)); + if (port->callback == NULL) { + OS_ERROR_EXIT("Unable to alloc memory for callback context."); + return PD_ERR_NOMEM; + } + /* Fill entries in pd_callback_t */ + port->callback->callback_context = port; + port->callback->read_regs = pi_read_regs; + port->callback->write_regs = pi_write_regs; + port->callback->eld = NULL; /* Insert when edid is initialize */ + + /* SDVO port driver needs the port number */ + port->callback->port_num = port->port_number; + + /* now save the pd_driver in port entry */ + port->pd_driver = pd_driver; + + /* preference is to user specified i2c_speed */ + prev_dab = port->dab; + prev_i2c_speed = port->i2c_speed; + if (!port->i2c_speed) { + port->i2c_speed = pd_driver->i2c_speed?pd_driver->i2c_speed: + I2C_DEFAULT_SPEED; + } + + /* Try detecting the encoder by calling port driver open() */ + if (port->dab || + ((port->dab == 0) && (pd_driver->dab_list[0] == PD_DAB_LIST_END))) { + + /* Workaround for not to detect 2 encoders if only 1 encoder + * is present and both DVOB and DVOC are using same I2C bus */ + if ((init_params->display_flags & IGD_DISPLAY_MULTI_DVO) && + (num_instances > 0) && + (prev_instance_dab == port->dab) && + (prev_instance_i2c_reg == port->i2c_reg)) { + /* Print this msg, because user explicitly mentioned DAB/I2C + * bus details which are same as previous encoder's DAB/I2C bus + * details. */ + OS_DEBUG("1+ encoders have same I2C bus and DAB"); + ret = -1; + } else { + /* Call open() only once if either user provides a DAB + * or + * no required to open an encoder. ex: analog, rgba, lvds etc. + */ + OS_DEBUG("Looking for \"%s\" on port 0x%lx with DAB 0x%lx", + pd_driver->name, port->port_reg, port->dab); + ret = pd_driver->open(port->callback, &(port->pd_context)); + } + } else { + + /* Call open() for each DAB */ + while (pd_driver->dab_list[dab_index] != PD_DAB_LIST_END) { + port->dab = pd_driver->dab_list[dab_index]; + + /* Workaround for not to detect 2 encoders if only 1 encoder + * is present and both DVOB and DVOC are using same I2C bus */ + if ((init_params->display_flags & IGD_DISPLAY_MULTI_DVO) && + (num_instances > 0) && + (prev_instance_dab == port->dab) && + (prev_instance_i2c_reg == port->i2c_reg)) { + /* Don't print the debug msg, because this is a valid case. + * Example, + * Algorithm is detecting for multiple encoders with + * same DAB and same I2C bus on different ports. + * If this case arises, simply continue + */ + /* OS_DEBUG("1+ encoders have same I2C bus and DAB"); */ + if (pd_driver->flags & PD_FLAG_DUAL_DVO) { + /* If this flag is set, that means port driver is + * explicityly requesting to be loaded on + * both DVO B & DVO C with same DAB. Example: CH7017. + * + * In this case open the port driver again. */ + } else { + ret = -1; + port->pd_context = NULL; + dab_index++; + continue; + } + } + + OS_DEBUG("Looking for \"%s\" on port 0x%lx with DAB 0x%lx", + pd_driver->name, port->port_reg, port->dab); + ret = pd_driver->open(port->callback, &(port->pd_context)); + if (ret == 0) { + break; + } else { + + dab_index++; + } + } + } + + if (ret == 0) { + /* Initialize our port entry */ + ret = pi_pd_init(port, port_feature, second_port_feature, TRUE); + if (ret) { + port->pd_driver = NULL; + port->pd_context = NULL; + port->dab = prev_dab; + port->i2c_speed = prev_i2c_speed; + port->mult_port = NULL; + port->timing_table = NULL; + port->num_timing = 0; + if (port->callback) { + OS_FREE(port->callback); + port->callback = NULL; + } + } else { + OS_DEBUG("Device found on %s port for \"%s\"", port->port_name, + pd_driver->name); + num_instances++; + prev_instance_dab = port->dab; + prev_instance_i2c_reg = port->i2c_reg; + } + + /* If Multi-DVO support is enabled then detect next encoder of + * same kind */ + if (init_params->display_flags & IGD_DISPLAY_MULTI_DVO){ + /* Continue to find next encoder */ + continue; + } else { + /* Found one encoder and return to port driver */ + break; + } + } else { + port->pd_driver = NULL; + port->pd_context = NULL; + port->dab = prev_dab; + port->i2c_speed = prev_i2c_speed;; + if (port->callback) { + OS_FREE(port->callback); + port->callback = NULL; + } + } + } /* end while(port == feature_port()) */ + + if (num_instances == 0) { + OS_DEBUG("No device found for \"%s\"", pd_driver->name); + return PD_ERR_NOPORT_AVAIL; + } + + OS_TRACE_EXIT; + return PD_SUCCESS; +} /* end pi_pd_register() */ + +/* Function to replace common timings in 1st list with 2nd list, 2nd list + * is unchanged. */ +void replace_common_dtds(igd_timing_info_t *dtds1, + igd_timing_info_t *dtds2) +{ + igd_timing_info_t *temp; + int index; + + if (!dtds2 || !dtds1) { + return; + } + + while (dtds1->width != IGD_TIMING_TABLE_END) { + temp = dtds2; + index = 0; + + while (temp->width != IGD_TIMING_TABLE_END && index < NUM_TIMINGS) { + /* Replace modes that have common width, height and + refresh rate. Removed Dot clock comparison since + EDID(CEA modes) may differ in dot clock value. + causing duplicate mode. + All ial would do a match mode by height, width + and refresh rate. + */ + if ((temp->width == dtds1->width) && + (temp->height == dtds1->height) && + (temp->refresh == dtds1->refresh) && + ((temp->mode_info_flags & PD_SCAN_INTERLACE) == + (dtds1->mode_info_flags & PD_SCAN_INTERLACE))) { + dtds1->mode_info_flags &= ~PD_MODE_SUPPORTED; + } + temp++; + index++; + } + dtds1++; + } +} + +/*! + * + * @param port + * + * @return 0 + */ +int check_port_attrs(igd_display_port_t *port) +{ + int ret; + unsigned long attr_value = 0; +#ifndef CONFIG_MICRO + pd_attr_t out_list,*temp_list; + temp_list = &out_list; +#endif + /* Attempt to see if the port driver has this attibutes so it can update + the port driver value. For now this is required for internal HDMI which + has a different i2c bus and port name from the standard SDVO port driver. + DP would most likely use this attribute assuming it uese the same port + number as well*/ + ret = pi_pd_find_attr_and_value(port, PD_ATTR_ID_PORT_DDC_REG, + PD_ATTR_FLAG_GENERAL, NULL, &attr_value); + if(!ret){ + OS_DEBUG("ddr_reg value unique = %ld.", attr_value); + port->ddc_reg = attr_value; + } +#ifndef CONFIG_MICRO + ret = pi_pd_find_attr_and_value(port, PD_ATTR_ID_PORT_NAME, + PD_ATTR_FLAG_GENERAL, &(temp_list), &attr_value); + if(!ret){ + OS_DEBUG("ddr_reg value unique = %ld.", attr_value); + pd_strcpy(port->port_name, temp_list->name); + } +#endif + return 0; + +} + + +/*! + * Function to initialize port driver related members in port table entry + * + * @param port + * @param port_feature + * @param second_port_feature + * @param drm_load_time + * + * @return PD_SUCCESS on success + * @return 1 on failure + */ +int pi_pd_init(igd_display_port_t *port, + unsigned long port_feature, + unsigned long second_port_feature, + int drm_load_time) +{ + igd_display_port_t *second_port; + pd_timing_t *user_timings = NULL; + pd_timing_t *std_timings = NULL; + pd_timing_t *firmware_timings = NULL; + pd_timing_t *final_timings = NULL; + pd_timing_t *pd_timing_table = NULL; + mode_state_t *mstate; + int i, ret = PD_SUCCESS; + unsigned long edid_flags; + unsigned char num_firmware_timings = 0; + igd_display_params_t *display_params = NULL; + igd_param_t *init_params; + + OS_TRACE_ENTER; + + mstate = NULL; + + /* If the display device is a ganged mode device or RGBA mode, then hook + * up second port pointer in first port */ + if (second_port_feature) { + second_port = pi_get_feature_port(second_port_feature, port); + + /* If second_port is N/A, or second port was already taken by + * other port driver, then release main port and return error */ + if (second_port == NULL || second_port->pd_driver) { + OS_ERROR_EXIT("Second ganged/RGBA port N/A or already allocated."); + return PD_ERR_NOPORT_AVAIL; + } + /* now link second port to first one */ + port->mult_port = second_port; + } + + /* Check port attributes to overwrite port value is any available */ + check_port_attrs(port); + /* Implementation notes to get the timing list: + * Any port timing table consists of + * EDID DTDS + * USER DTDS + * STD TIMINGS + * based on edid_flags. + * + * If there are no flags, then it defaults to use STD TIMINGS + EDID DTDs + */ + + /* Get the display params for this port */ + init_params = pi_context->igd_context->mod_dispatch.init_params; + + for (i = 0; i < 5; i++) { + if (port->port_number == init_params->display_params[i].port_number) { + display_params = &init_params->display_params[i]; + break; + } + } + + /* Start with STD TIMINGS */ + edid_flags = IGD_DISPLAY_USE_STD_TIMINGS; + + /* If there is EDID, then default to use EDID */ + if (!display_params || (display_params->flags & IGD_DISPLAY_READ_EDID)) { + /* Read firmware (EDID/DisplayID) on I2C */ + ret = pi_context->i2c_dispatch->i2c_read_regs( + pi_context->igd_context, + port->ddc_reg, /* DDC register */ + port->ddc_speed, /* DDC speed */ + port->ddc_dab, /* Data Addr Byte*/ + 0, /* Register */ + firmware_data, /* Values */ + 128); /* Num bytes to read */ + + /* If EDID is present then use EDID. + * edid_flags will be corrected later if display_params are present */ + if (ret == 0) { + edid_flags |= IGD_DISPLAY_USE_EDID; + } + } + + /* Check for display params */ + if (display_params) { + if (edid_flags & IGD_DISPLAY_USE_EDID) { + /* Adjust edid_flags to use edid_avail + * if both edid is present and edid_avail is not 0 */ + if (display_params->edid_avail) { + edid_flags = display_params->edid_avail; + OS_DEBUG("EDID_Avail: 0x%lx", edid_flags); + } + } else { + /* Adjust edid_flags to use edid_not_avail + * if edid is not present and edid_not_avail is not 0 */ + if (display_params->edid_not_avail) { + edid_flags = + display_params->edid_not_avail & ~IGD_DISPLAY_USE_EDID; + OS_DEBUG("EDID_Not_Avail: 0x%lx", edid_flags); + } + } + } + + /* Make a copy of crt_timing_table */ + /* All crt timings are already enabled in mode_table.c */ + std_timings = (igd_timing_info_t *) OS_ALLOC(crt_timing_table_size); + OS_MEMCPY(std_timings, crt_timing_table, crt_timing_table_size); + + /* Include Standard built-in modes */ + if (edid_flags & IGD_DISPLAY_USE_STD_TIMINGS) { + OS_DEBUG("Using STD TIMINGS "); + final_timings = std_timings; + } + + /* Include user DTDs */ + if (edid_flags & IGD_DISPLAY_USE_USERDTDS) { + OS_DEBUG("Using USER-DTDs "); + user_timings = get_user_timings(port->dtd_list); + + if (user_timings) { + /* Add user DTDs at the begining of the final timings */ + user_timings[port->dtd_list->num_dtds].extn_ptr = final_timings; + final_timings = user_timings; + } + } + + /* Include EDID timings and filter modes */ + if (edid_flags & IGD_DISPLAY_USE_EDID) { + OS_DEBUG("Using EDID-DTDs "); + ret = get_firmware_timings(port, firmware_data, final_timings); + if (port->firmware_type == PI_FIRMWARE_EDID) { + firmware_timings = port->edid->timings; + num_firmware_timings = port->edid->num_timings; + } else if (port->firmware_type == PI_FIRMWARE_DISPLAYID) { + firmware_timings = port->displayid->timings; + num_firmware_timings = port->displayid->num_timings; + } + if (ret == 0 && num_firmware_timings) { + /* Add EDID DTDs at the begining of the final timings */ + firmware_timings[num_firmware_timings].extn_ptr = + (void *)final_timings; + final_timings = firmware_timings; + } + } + + /* Replace any common timings */ + replace_common_dtds(std_timings, firmware_timings); + replace_common_dtds(std_timings, user_timings); + replace_common_dtds(firmware_timings, user_timings); + + /* Count the number of timings in final_timings. If the above functions + * result in an empty timing list, then use std_timings as default. + */ + if (!get_native_dtd(final_timings, PI_SUPPORTED_TIMINGS, NULL, 0)) { + OS_DEBUG("User options resulted in 0 timings; using std timings."); + final_timings = std_timings; + enable_disable_timings(final_timings, 1); + } + + /* Update port driver attributes */ + update_attrs(port); + + /* Now get the timing list filtered by PORT DRIVER */ + ret = port->pd_driver->get_timing_list(port->pd_context, + final_timings, &pd_timing_table); + + if (ret || !pd_timing_table) { + OS_ERROR_EXIT("port driver: get timing list error."); + return PD_ERR_NO_TIMINGS; + } + + /* Delete temporary lists and buffers */ + if (user_timings) { + OS_FREE(user_timings); + } + if (std_timings) { + OS_FREE(std_timings); + } + + /* Filter modes based on chipset type */ + pi_context->igd_context->mod_dispatch.filter_modes(pi_context->igd_context, + port, pd_timing_table); + + /* Now save the timings in port */ + port->timing_table = pd_timing_table; + port->num_timing = get_native_dtd(pd_timing_table, + PI_SUPPORTED_TIMINGS, &port->fp_native_dtd, PD_MODE_DTD_FP_NATIVE); + + assign_dynamic_numbers(port->timing_table); + +#ifdef DEBUG_FIRMWARE + { + int ti; + OS_DEBUG("Supported timings for \"%s\" (%lu)", + port->pd_driver->name, port->num_timing); + ti = 0; + while (port->timing_table[ti].width != PD_TIMING_LIST_END) { + if (port->timing_table[ti].mode_info_flags & PD_MODE_SUPPORTED) { + OS_DEBUG("\t%ux%u@%u dclk=%lu mode_num=%d hsync=%luKHz " + "vsync=%luHz flags=0x%lx", + port->timing_table[ti].width, + port->timing_table[ti].height, + port->timing_table[ti].refresh, + port->timing_table[ti].dclk, + port->timing_table[ti].mode_number, + port->timing_table[ti].dclk/port->timing_table[ti].htotal, + ((port->timing_table[ti].dclk * 1000)/ + port->timing_table[ti].htotal)/ + port->timing_table[ti].vtotal, + port->timing_table[ti].mode_info_flags); + } + ti++; + } + } +#endif + + + /* + * Exit early when called by emgd_driver_pre_init to poke the X driver's + * (i.e. "xorg.conf") DTDs and attr's into the port drivers (done above). + */ + if (!drm_load_time) { + OS_TRACE_EXIT; + return PD_SUCCESS; + } + + +#ifndef CONFIG_MICRO + if(pi_context->igd_context->mod_dispatch.reg_get_mod_state) { + module_state_h *state = NULL; + unsigned long *flags = NULL; + pi_context->igd_context->mod_dispatch.reg_get_mod_state( + REG_MODE_STATE, + &state, + &flags); + + if (state) { + mstate = (mode_state_t *)(*state); + } + } + + /* If mode state is present in register context, + * then call save() function to save the port driver's state */ + if (mstate) { + ret = port->pd_driver->pd_save(port->pd_context, + &(mstate->pd_state[pi_context->num_pi_drivers].state), 0); + if (ret) { + OS_ERROR_EXIT("port driver: reg saving error. ret = %d", ret); + return ret; + } + mstate->pd_state[pi_context->num_pi_drivers].port = port; + } +#endif + + if(port->displayid != NULL){ + /* Driver to init audio if cea extension available */ + if(port->firmware_type == PI_FIRMWARE_EDID){ + port->callback->eld = &(port->edid->cea); + } + /* Displayid unsupported for now. Uncomment this code when audio + information is available for Display ID + else if(port->firmware_type == PI_FIRMWARE_EDID){ + port->callback->eld = &(port->displayid->cea); + } + */ + else{ + port->callback->eld = NULL; + } + } + ret = port->pd_driver->init_device(port->pd_context); + if (ret) { +#ifndef CONFIG_MICRO + /* TODO: Restore the pd state? */ + OS_ERROR_EXIT("port driver: init_device error. ret = %d", ret); + if (mstate) { + mstate->pd_state[pi_context->num_pi_drivers].port = NULL; + mstate->pd_state[pi_context->num_pi_drivers].state = NULL; + } +#endif + return ret; + } + + /* Increment the number of port drivers */ + pi_context->num_pi_drivers++; + + /* save the port driver display type & flags in port. These additions are + * required to support different types displays by same port driver. */ + port->pd_type = port->pd_driver->type; + port->pd_flags = port->pd_driver->flags; + + OS_TRACE_EXIT; + return PD_SUCCESS; +} /* end pi_pd_init */ + +/*! + * Function to read registers + * + * @param context + * @param list + * @param type + * + * @return PD_SUCCESS on success + * @return PD_ERR_NULL_PTR, PD_ERR_I2C_READ, PD_ERR_UNSUCCESSFUL on failure + */ +int pi_read_regs(void *callback_context, pd_reg_t *list, unsigned long type) +{ + int ret; + igd_display_port_t *port = callback_context; + unsigned char *mmio; + + /*OS_TRACE_EXIT;*/ + + if (!port) { + OS_ERROR_EXIT("Null callback context passed."); + return PD_ERR_NULL_PTR; + } + + if (!port->pd_driver) { + OS_ERROR_EXIT("Null pd_driver in port entry."); + return PD_ERR_NULL_PTR; + } + + mmio = OS_MMIO(pi_context->igd_context->device_context.virt_mmadr); + + /* Based on the port type either read GMCH registers or I2C registers */ + switch (type) { + case PD_REG_I2C: + ret = 0; + while (list->reg != PD_REG_LIST_END) { + ret = pi_context->i2c_dispatch->i2c_read_regs( + pi_context->igd_context, + port->i2c_reg, + port->i2c_speed, + port->dab, + (unsigned char)list->reg, + (unsigned char *)&list->value, 1); + if (ret) { + OS_DEBUG("i2c_read_reg: 0x%lx failed.", list->reg); + break; + } + list++; + } + if (ret) { + return PD_ERR_I2C_READ; + } + break; + case PD_REG_DDC: + ret = 0; + while (list->reg != PD_REG_LIST_END) { + ret = pi_context->i2c_dispatch->i2c_read_regs( + pi_context->igd_context, + port->ddc_reg, + port->ddc_speed, + port->ddc_dab, + (unsigned char)list->reg, + (unsigned char *)&list->value, 1); + if (ret) { + OS_DEBUG("i2c_read_reg: 0x%lx failed.", list->reg); + break; + } + list++; + } + if (ret) { + return PD_ERR_I2C_READ; + } + break; + case PD_REG_PIO8: + while (list->reg != PD_REG_LIST_END) { + list->value = OS_READ_PORT8(list->reg); + list++; + } + break; + case PD_REG_PIO16: + while (list->reg != PD_REG_LIST_END) { + list->value = OS_READ_PORT16(list->reg); + list++; + } + break; + case PD_REG_PIO32: + while (list->reg != PD_REG_LIST_END) { + list->value = OS_READ_PORT32(list->reg); + list++; + } + break; + case PD_REG_MIO : + case PD_REG_MIO8 : + if ((port->port_type == IGD_PORT_ANALOG) || + (port->port_type == IGD_PORT_TV) || /* For Integrated TV */ + (port->port_type == IGD_PORT_LVDS) || + (port->port_type == IGD_PORT_DIGITAL)) { + while (list->reg != PD_REG_LIST_END) { + if (type == PD_REG_MIO) { + if (BIT31 & list->reg) { +#ifdef CONFIG_TNC + /* Tunnel Creek si hack: Si folks defined LVDS (0:2:0) + * related register in 0:3:0 (sdvo device) as they + * are afraid to touch Lincroft hardmacro. + * This triggered LVDS port driver to touch 0:3:0 + * registers for its operation. As this is done for + * LVDS operation and LVDS port driver is internal, + * BIT31 is defined to access 0:3:0 device. */ + list->value = READ_MMIO_REG_TNC(IGD_PORT_SDVO, + list->reg); +#endif + } else { + list->value = OS_READ32(OS_MMIO(mmio) + list->reg); + } + } else { + list->value = OS_READ8(OS_MMIO(mmio) + list->reg); + } + list++; + } + } + break; +#ifdef CONFIG_TNC + case PD_REG_LPC: + if (port->port_type == IGD_PORT_LVDS) { + while (list->reg != PD_REG_LIST_END) { + list->value = READ_MMIO_REG_TNC(IGD_PORT_LPC, list->reg); + list++; + } + } + break; +#endif + case PD_REG_PCI: + /* Rightnow this is only to provide the device id */ + while (list->reg != PD_REG_LIST_END) { +#if 0 + /* Assume IGD at bus=0, dev=2, func=0 */ + OS_WRITE_PORT32(0xCF8, + (0x80000000 | (0L << 16) | (2L << 11) | (0L << 8) | + (list->reg & 0xFC))); + list->value = OS_READ_PORT32(0xCFC + (list->reg & 0x03)); +#endif + list->value = pi_context->igd_context->device_context.did; + list++; + } + break; + case PD_REG_BRIDGE_OPCODE: + /* right now, we only return the graphics frequency to calculate the + * PWM Backlight modulation frequency. This is only available for pouslbo */ + while (list->reg != PD_REG_LIST_END) { + list->value = pi_context->igd_context->device_context.gfx_freq; + list++; + } + + break; + default: + OS_ERROR_EXIT("Unknown reg type (0x%lx).", type); + return PD_ERR_UNSUCCESSFUL; + break; + } + + /*OS_TRACE_EXIT;*/ + return PD_SUCCESS; +} /* end pi_read_regs */ + +/*! + * Function to write registers + * + * @param context + * @param list + * @param type + * + * @return 0 on success + * @return PD_ERR_NULL_PTR, PD_ERR_I2C_WRITE, PD_ERR_UNSUCCESSFUL on failure + */ +extern unsigned short io_base_sdvo; +extern unsigned short io_base; + +int pi_write_regs(void *callback_context, pd_reg_t *list, unsigned long type) +{ + igd_display_port_t *port = callback_context; + int ret; + unsigned char *mmio; + + /*OS_TRACE_ENTER;*/ + + if (!port) { + OS_ERROR_EXIT("Null callback context passed."); + return PD_ERR_NULL_PTR; + } + + if (!port->pd_driver) { + OS_ERROR_EXIT("Null pd_driver."); + return PD_ERR_NULL_PTR; + } + + mmio = OS_MMIO(pi_context->igd_context->device_context.virt_mmadr); + + /* Based on the port type either write GMCH registers or I2C registers */ + switch (type) { + case PD_REG_I2C: + ret = pi_context->i2c_dispatch->i2c_write_reg_list( + pi_context->igd_context, + port->i2c_reg, + port->i2c_speed, + port->dab, + list, + 0); + if (ret) { + OS_DEBUG("i2c_write_reg: 0x%lx = 0x%lx failed.", + list->reg, list->value); + return PD_ERR_I2C_WRITE; + } + break; + case PD_REG_PIO8: + while (list->reg != PD_REG_LIST_END) { + OS_WRITE_PORT8(list->reg, list->value); + list++; + } + break; + case PD_REG_PIO16: + while (list->reg != PD_REG_LIST_END) { + OS_WRITE_PORT16(list->reg, list->value); + list++; + } + break; + case PD_REG_PIO32: + while (list->reg != PD_REG_LIST_END) { + OS_WRITE_PORT32(list->reg, list->value); + list++; + } + break; + case PD_REG_MIO : + case PD_REG_MIO8 : + if ((port->port_type == IGD_PORT_ANALOG) || + (port->port_type == IGD_PORT_TV) || /* For Integrated TV */ + (port->port_type == IGD_PORT_LVDS) || + (port->port_type == IGD_PORT_DIGITAL)) { + while (list->reg != PD_REG_LIST_END) { + if (type == PD_REG_MIO) { + if (BIT31 & list->reg) { +#ifdef CONFIG_TNC + /* BIT31 indicates write to 0:3:0 SDVO device */ + WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, list->reg, + list->value); +#endif + } else { + OS_WRITE32(list->value, OS_MMIO(mmio) + list->reg); + } + } else { + OS_WRITE8(list->value, OS_MMIO(mmio) + list->reg); + } + list++; + } + } + break; +#ifdef CONFIG_TNC + case PD_REG_LPC: + if (port->port_type == IGD_PORT_LVDS) { + while (list->reg != PD_REG_LIST_END) { + WRITE_MMIO_REG_TNC(IGD_PORT_LPC, list->reg, list->value); + list++; + } + } + break; +#endif + default: + OS_ERROR_EXIT("Unknown reg type (0x%lx).", type); + return PD_ERR_UNSUCCESSFUL; + break; + } + + /*OS_TRACE_EXIT;*/ + return 0; +} /* end pi_write_regs */ + +/*! + * Depending on the parameters, this function does multiple things. It always + * counts and returns the number of [supported] timings. If desired, it also + * finds the timing with a desired "mode_info_flags" that has the largest value + * of width, height, OR refresh rate, which it sets to the "native_dtd" + * parameter. + * + * @param timing + * @param flags + * @param native_dtd + * @param nflags + * + * @return 0 on failure + * @return native dtd on success + */ +unsigned long get_native_dtd(igd_timing_info_t *timing, + unsigned long flags, pd_timing_t **native_dtd, unsigned long nflags) +{ + unsigned long entries = 0; + + OS_TRACE_EXIT; + + if (!timing) { + return 0; + } + if (native_dtd) { + *native_dtd = NULL; + } + while (timing->width != IGD_TIMING_TABLE_END) { + if (flags & PI_SUPPORTED_TIMINGS) { + if (timing->mode_info_flags & PD_MODE_SUPPORTED) { + entries++; + } + if ((native_dtd) && + (timing->mode_info_flags & nflags)) { + /* Native Resolution is defined as the largest resolution the + * panel can display. However, some panels contain more than one + * DTD in its EDID. We will choose the largest resolution + * available from EDID */ + if(((*native_dtd) && (nflags == PD_MODE_DTD)) && + (((pd_timing_t*)(*native_dtd))->width > timing->width || + ((pd_timing_t*)(*native_dtd))->height > timing->height || + ((pd_timing_t*)(*native_dtd))->refresh > timing->refresh)){ + /* do nothing */ + } else { + *native_dtd = timing; + } + } + } else { + entries++; + } + + timing++; + if ((timing->width == PD_TIMING_LIST_END) && timing->extn_ptr) { + timing = timing->extn_ptr; + } + } + + OS_TRACE_EXIT; + return entries; +} + +unsigned long get_magic_cookie(pd_driver_t *pd_driver) +{ + /* FIXME: Implement cookie checking */ + return 0; +} + +/*! + * Function to filter modes based on EDID or DisplayID + * + * @param port + * @param firmware_data + * @param timing_table + * + * @return 0 on success + * @return -IGD_ERROR_EDID, -IGD_ERROR_NOMEM on failure + */ +int get_firmware_timings(igd_display_port_t *port, + unsigned char *firmware_data, igd_timing_info_t *timing_table) +{ + edid_t *edid; + displayid_t *displayid; + int ret = -1; + + OS_TRACE_ENTER; + + if (!firmware_data) { + return -IGD_ERROR_EDID; + } + + if (!port->displayid) { + /* EDID and DisplayID use same memory */ + displayid = (displayid_t *) OS_ALLOC(sizeof(displayid_t)); + if (!displayid) { + return -IGD_ERROR_NOMEM; + } + edid = (edid_t *) displayid; + } else { + displayid = port->displayid; + edid = (edid_t *) displayid; + } + OS_MEMSET(displayid, 0, sizeof(displayid_t)); + + /* Now parse the EDID or DisplayID */ + /* Check the header to determine whether the data is EDID or DisplayID */ + /* EDID header first 8 bytes = + * byte 0, 1, 2, 3: 00 ff ff ff = unsigned long 0xFFFFFF00 + * byte 4, 5, 6, 7: ff ff ff 00 = unsigned long 0x00FFFFFF */ + if (*(unsigned long *) &firmware_data[0] == 0xFFFFFF00 && + *(unsigned long *) &firmware_data[4] == 0x00FFFFFF) { +#ifdef DEBUG_FIRMWARE + firmware_dump(firmware_data, 256); +#endif + /* This is EDID data */ + ret = edid_parse(firmware_data, edid, timing_table, 0, + (unsigned char) (port->pd_driver->flags&PD_FLAG_UP_SCALING?1:0)); + if (ret == EDID_READ_AGAIN) { + /* Check to see if there is an extension block */ + if((firmware_data[0x7e] == 0x1)){ + ret = pi_context->i2c_dispatch->i2c_read_regs( + pi_context->igd_context, + port->ddc_reg, /* DDC register */ + port->ddc_speed, /* DDC speed */ + port->ddc_dab, /* Data Addr Byte*/ + 0x80, /* Register */ + &firmware_data[128], /* Values */ + 128); /* next 128 bytes include extension */ + ret = edid_ext_parse(&firmware_data[128], edid, timing_table,0, + (unsigned char)(port->pd_driver->flags& + PD_FLAG_UP_SCALING?1:0)); + /* Parse next 128 bytes of EDID block */ + }else{ + ret = 0; + } + } else if (ret) { + OS_FREE(edid); + return -IGD_ERROR_EDID; + } + + port->firmware_type = PI_FIRMWARE_EDID; +#ifdef DEBUG_FIRMWARE + edid_print(edid); +#endif + +#ifndef CONFIG_NO_DISPLAYID + } else { + /* size = payload + 5 */ + /* +5 is for the 5 mandatory bytes not included in payload */ + unsigned short displayid_size = firmware_data[1] + 5; + if (displayid_size > 256) { + OS_DEBUG("Invalid DisplayID size = %u (incl 5 mand bytes) > 256", + displayid_size); + return -IGD_ERROR_EDID; + } + + /* If the DisplayID is greater than 128 bytes */ + if (displayid_size > 128) { + ret = pi_context->i2c_dispatch->i2c_read_regs( + pi_context->igd_context, + port->ddc_reg, /* DDC register */ + port->ddc_speed, /* DDC speed */ + port->ddc_dab, /* Data Addr Byte*/ + 0, /* Register */ + firmware_data, /* Values */ + displayid_size); /* Num bytes to read */ + } + +#ifdef DEBUG_FIRMWARE + firmware_dump(firmware_data, 256); +#endif + /* This is DisplayID data */ + ret = displayid_parse(firmware_data, displayid, timing_table, 0, + (unsigned char) (port->pd_driver->flags&PD_FLAG_UP_SCALING?1:0)); + if (!ret) { + port->firmware_type = PI_FIRMWARE_DISPLAYID; + } else { + OS_FREE(displayid); + } + +#ifdef DEBUG_FIRMWARE + displayid_print(firmware_data, displayid); +#endif +#else + /* If DisplayID isn't enabled then print a debug message and return error */ + } else { + OS_ERROR_EXIT("EDID header is wrong! Will ignore"); + return -IGD_ERROR_EDID; +#endif + } + + port->edid = edid; + + OS_TRACE_EXIT; + return ret; +} /* end get_firmware_timings() */ + +/*! + * Update port driver attributes with incoming values from IAL + * + * @param in_list attributes in this list are used to update corresponding + * attributes in out_list + * @param fp_info flat panel attributes used to update ocrresponding + * attributes in out_list + * @param out_num_attrs size of out_list + * @param out_list contains a list of attributes to be updated + * + * @return 0 + */ +int update_attrs(igd_display_port_t *port) +{ + int ret; + unsigned int i = 0; + + igd_param_attr_list_t *in_list = port->attr_list; + igd_param_fp_info_t *fp_info = port->fp_info; + + /* Initial 5 attributes are for fp_info, + * Note: If both igd_param_fp_info_t and fp_info attributes + * were specified then fp_info values takes the precedence */ + unsigned long out_num_attrs = 5; + pd_attr_t *out_list; + + OS_TRACE_ENTER; + + /* if: there's something in in_list */ + if (in_list) { + out_num_attrs += in_list->num_attrs; + } + + out_list = OS_ALLOC(sizeof(pd_attr_t) * out_num_attrs); + if (!out_list) { + OS_DEBUG("No memory to make attr_list."); + return 0; + } + OS_MEMSET(out_list, 0, sizeof(pd_attr_t) * out_num_attrs); + + /* Pass user specified attributes */ + if (in_list) { + /* For every incoming attr, make a pd_attr_t */ + for (i = 0; i < in_list->num_attrs; i++) { + /* This will work for all kinds of attributes: + * in_list->attr[i].value = + * actual value for range attributes + * index for list attributes + * value for boolean attributes. + * This works because + * pd_attr_t, pd_range_attr_t, pd_list_attr_t, + * pd_boolean_attr_t all have save offsets for + * default values. */ + out_list[i].id = in_list->attr[i].id; + out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED; + out_list[i].current_value = in_list->attr[i].value; + } + } /* if: there's something in in_list */ + + /* Pass flat panel attributes to the port driver, if necessary */ + if (fp_info) { + /* Initialize flat panel attributes */ + /* Update FP attributes */ + if (fp_info->fp_pwr_method == IGD_PARAM_FP_PWR_METHOD_PD) { + /* The only thing remaining is the FP_PWR_Tx, so check + * to ensure it is for an FP_PWR_METHOD_PD */ + out_list[i].id = PD_ATTR_ID_FP_PWR_T1; + out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED; + out_list[i++].current_value = fp_info->fp_pwr_t1; + + out_list[i].id = PD_ATTR_ID_FP_PWR_T2; + out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED; + out_list[i++].current_value = fp_info->fp_pwr_t2; + + out_list[i].id = PD_ATTR_ID_FP_PWR_T3; + out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED; + out_list[i++].current_value = fp_info->fp_pwr_t3; + + out_list[i].id = PD_ATTR_ID_FP_PWR_T4; + out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED; + out_list[i++].current_value = fp_info->fp_pwr_t4; + + out_list[i].id = PD_ATTR_ID_FP_PWR_T5; + out_list[i].flags = PD_ATTR_FLAG_VALUE_CHANGED; + out_list[i++].current_value = fp_info->fp_pwr_t5; + } + } + +#ifndef CONFIG_NO_DISPLAYID + /* Based on our architecture, any user-defined config option will override + * firmware options. i.e., First send the DisplayID attributes + * then send the config attributes to port drivers. */ + if (port->firmware_type == PI_FIRMWARE_DISPLAYID) { + ret = port->pd_driver->set_attrs(port->pd_context, + port->displayid->num_attrs, + port->displayid->attr_list); + } +#endif + ret = port->pd_driver->set_attrs(port->pd_context, i, out_list); + if (ret) { + OS_DEBUG("Attribute update failed. ret = %d.", ret); + } + OS_FREE(out_list); + + OS_TRACE_EXIT; + return 0; +} /* update_attrs */ + +/* Add user defined timings to big timing table */ +pd_timing_t *get_user_timings(igd_param_dtd_list_t *in_list) +{ + pd_timing_t *t = NULL, *timing = NULL; + igd_display_info_t *dtd; + unsigned long i; + + OS_TRACE_ENTER; + + if (!in_list || !(in_list->num_dtds) || !(in_list->dtd)) { + return NULL; + } + + t = (pd_timing_t *)OS_ALLOC((in_list->num_dtds + 1) + * sizeof(pd_timing_t)); + if (!t) { + return NULL; + } + + OS_MEMSET(t, 0, (in_list->num_dtds + 1) * sizeof(pd_timing_t)); + timing = t; + dtd = in_list->dtd; + + /* + * OPTIMIZEME: When igd_display_info_t goes away there will be no reason + * to copy this data. A Rule can be imposed that anything passed to + * the HAL during init must remain in scope until the HAL is shut + * down. The HAL can then just use this directly. + */ + for (i = 0; i < in_list->num_dtds; i++) { + OS_MEMCPY(t, dtd, sizeof(igd_display_info_t)); + t->mode_info_flags = dtd->flags | PD_MODE_DTD_USER | PD_MODE_SUPPORTED; + /* Assume there is no border, then htotal and vtotal are the same as + * hblank_end and vblank_end */ + t->htotal = t->hblank_end; + t->vtotal = t->vblank_end; + if (dtd->refresh) { + t->refresh = (unsigned short)dtd->refresh; + } else if (t->htotal && t->vtotal) { + t->refresh = (unsigned short) + ((unsigned long)((unsigned long)(t->dclk) * 1000) / + ((unsigned long)(t->htotal) * + (unsigned long)(t->vtotal))); + } + + t->pd_extn_ptr = NULL; + t->extn_ptr = NULL; + + t++; + dtd++; + } + + /* End the table with end marker */ + t->width = IGD_TIMING_TABLE_END; + + OS_TRACE_EXIT; + + return timing; +} + +/*! + * Assign dynamic VBE numbers to the modes that do not already have + * VESA defined numbers. + * + * @param timing_table + * + * @return void + */ +#define FIRST_DYNAMIC_MODE_NUMBER 0x120 +void assign_dynamic_numbers(igd_timing_info_t *timing_table) +{ + unsigned short next_number = FIRST_DYNAMIC_MODE_NUMBER; + unsigned int i; + unsigned short vesa_mode_table[] = { + 640, 480, 0x101, + 800, 600, 0x103, + 1024, 768, 0x105, + 1280, 1024, 0x107, + 0xffff, 0xffff, 0xffff, + }; + + OS_TRACE_ENTER; + + while(timing_table->width != IGD_TIMING_TABLE_END) { + if((timing_table->mode_info_flags & IGD_MODE_SUPPORTED) && + !(timing_table->mode_info_flags & IGD_MODE_VESA)) { + + for (i=0; vesa_mode_table[i] != 0xffff; i+=3) { + if ((timing_table->width == vesa_mode_table[i]) && + (timing_table->height == vesa_mode_table[i+1])) { + /* This is a VESA Standard mode, so assign it to the + * correct VESA mode number. This can occur with + * modes added either through User Defined DTDs or + * potentially EDID. */ + timing_table->mode_number = vesa_mode_table[i+2]; + timing_table->mode_info_flags |= IGD_MODE_VESA; + break; + } + } + if (vesa_mode_table[i] == 0xffff) { + /* Assign this mode a Dynamic number, if it is not + * a VESA Standard mode. */ + timing_table->mode_number = next_number; + /* VBE modes use lower 2 bits for depth so next mode is += 4 */ + next_number += 4; + timing_table->mode_info_flags |= IGD_MODE_VESA; + } + } + timing_table++; + + /* If reached the first table END, + * then check for the added modes */ + if (timing_table->width == IGD_TIMING_TABLE_END && + timing_table->extn_ptr) { + timing_table = timing_table->extn_ptr; + } + } + + OS_TRACE_EXIT; + return; +} + +/*! + * This is a utility function that can be used througout the HAL. + * It can be used to get a ptr to an attr structure and/or the + * actual current_value of that attribute. + * According to usage modal at time of creation of this function: + * - the *caller_pd_attr must be NULL if the attr was not found. + * - the *attr_value is only changed if the attr was found + * + * @param port + * @param attr_id + * @param flag + * @param caller_pd_attr + * @param attr_value + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ +int pi_pd_find_attr_and_value(igd_display_port_t *port, + unsigned long attr_id, + unsigned long flag, + pd_attr_t **caller_pd_attr, + unsigned long *attr_value) +{ + unsigned long pd_attr_length = 0; + pd_attr_t *pd_attr_list = NULL; + pd_attr_t *found_pd_attr = NULL; + + OS_TRACE_ENTER; + + if(!port || !(port->pd_driver)) { + return -IGD_ERROR_INVAL; + } + + if(flag == PD_ATTR_FLAG_GENERAL){ + pd_attr_length = PD_QUERY_GENERAL_ATTR; + } + port->pd_driver->get_attrs(port->pd_context, &pd_attr_length, + &pd_attr_list); + if(!pd_attr_length) { + return -IGD_ERROR_INVAL; + } + + found_pd_attr = pd_get_attr(pd_attr_list, pd_attr_length, attr_id, flag); + + if (!found_pd_attr) { + if(caller_pd_attr) { + *caller_pd_attr = NULL; + } + return -IGD_INVAL; + } + if(caller_pd_attr) { + *caller_pd_attr = found_pd_attr; + } + if(attr_value) { + *attr_value = found_pd_attr->current_value; + } + + OS_TRACE_EXIT; + return 0; +} + +/*! + * + * @param port + * @param id + * @param value + * + * @return 0 on success + * @return -IGD_ERROR_INVAL on failure + */ +int pi_get_port_init_attr(igd_display_port_t *port, + unsigned long id, + unsigned long *value) +{ + unsigned short i; + + OS_TRACE_ENTER; + + if (!port || !port->attr_list) { + return -IGD_ERROR_INVAL; + } + + for (i = 0; i < (unsigned short) port->attr_list->num_attrs; i++) { + if (port->attr_list->attr[i].id == id) { + *value = port->attr_list->attr[i].value; + OS_TRACE_EXIT; + return 0; + } + } + + OS_DEBUG("Attribute (0x%ld) Not Found", id); + OS_TRACE_EXIT; + return -IGD_ERROR_INVAL; +} + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: pi.c,v 1.7 2010/04/29 19:31:33 iaelliox Exp $ + * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/pi/cmn/pi.c,v $ + *---------------------------------------------------------------------------- + */ diff --git a/drivers/gpu/drm/emgd/emgd/display/pi/plb/i2c_plb.c b/drivers/gpu/drm/emgd/emgd/display/pi/plb/i2c_plb.c new file mode 100644 index 0000000..37ba616 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/pi/plb/i2c_plb.c @@ -0,0 +1,940 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: i2c_plb.c + * $Revision: 1.7 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.dpd + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include "../cmn/i2c_dispatch.h" + +/*! + * @addtogroup display_group + * @{ + */ + +/*......................................................................... */ +extern igd_display_port_t dvob_port_plb; + +/*......................................................................... */ +static int i2c_read_regs_plb( + igd_context_t *context, + unsigned long i2c_bus, + unsigned long i2c_speed, + unsigned long dab, + unsigned char reg, + unsigned char FAR *buffer, + unsigned long num_bytes); + +static int i2c_write_reg_list_plb( + igd_context_t *context, + unsigned long i2c_bus, + unsigned long i2c_speed, + unsigned long dab, + pd_reg_t *reg_list, + unsigned long flags); + +i2c_dispatch_t i2c_dispatch_plb = { + i2c_read_regs_plb, + i2c_write_reg_list_plb, +}; + + +/*.......................................................................... */ +typedef enum { + + GMBUS_SPEED_50K = 0x0100, + GMBUS_SPEED_100K = 0x0000, + GMBUS_SPEED_400K = 0x0200, + GMBUS_SPEED_1000K = 0x0300, + +} gmbus_speed_t; + +typedef enum { + + SDVOB_ADDR = 0x70, + SDVOC_ADDR = 0x72, + +} sdvo_dev_addr_t; + +typedef enum { + + DDC1_ADDR = 0xA0, + DDC2_ADDR = 0xA2, + +} gmbus_ddc_addr_t; + + +typedef enum { + + GMBUS_PINS_DEDICATED = 1, /* Dedicated Control/GMBUS Pins */ + /* LCTRCLKA, LCTRLCLKB SSC Clock Device */ + GMBUS_PINS_ANALOG = 2, /* Analog DDC */ + GMBUS_PINS_INT_LVDS = 3, /* Alviso : Integrated Digital Panel */ + GMBUS_PINS_SDVO = 5, /* SDVO Registers, DDC, PROM */ + +} gmbus_pins_pair_t; + + +typedef enum { + + I2C_WRITE = 0, + I2C_READ = 1, + +} i2c_bus_dir_t; + +/*.......................................................................... */ +typedef enum { + + SDVO_BUS_PROM = BIT(0), + SDVO_BUS_DDC1 = BIT(1), + SDVO_BUS_DDC2 = BIT(2), + +} sdvo_bus_switch_t; + +#define SDVO_OPCODE_BUS_SWITCH 0x7A + +#define SDVO_INDEX_PARAM_1 0x07 +#define SDVO_INDEX_OPCODE 0x08 +#define SDVO_INDEX_STATUS 0x09 + +#define SDVO_STATUS_SUCCESS 0x01 +#define SDVO_STATUS_PENDING 0x04 + +/*.......................................................................... */ +/* + * In 16-bit, the mmio is a 16-bit pointer, the watcom 1.2 compiler will have + * error if directly convert it to unsigned long. Normally, have to cast it to + * unsigned short first then cast again to unsigned long; then, it will be + * correct. But this type of casting may cause some error in the 32 and 64 bit + * code. Since mmio will be equal to zero for 16-bit code. Add the checking + * for MICRO definition code to correct the macro by remove mmio. + */ +#define READ_GMCH_REG(reg) OS_READ32(OS_MMIO(mmio) + reg) +#define WRITE_GMCH_REG(reg, data) OS_WRITE32(data, OS_MMIO(mmio) + reg) + +static int gmbus_init(unsigned char *mmio, unsigned long i2c_bus, + unsigned long i2c_speed); + +static int gmbus_read_edid(unsigned char *mmio, + unsigned long ddc_addr, + unsigned long slave_addr, + unsigned long index, + unsigned long num_bytes, + unsigned char FAR *buffer); + +static int gmbus_read_reg(unsigned char *mmio, + unsigned long slave_addr, + unsigned long index, + unsigned char FAR *data); + +static int gmbus_write_reg(unsigned char *mmio, + unsigned long slave_addr, + unsigned long index, + unsigned char data); + +static int gmbus_set_control_bus_switch(unsigned char *mmio, + unsigned long slave_addr, + gmbus_ddc_addr_t ddc_addr); + +static int gmbus_wait_event_one(unsigned char *mmio, unsigned long bit); +static int gmbus_wait_event_zero(unsigned char *mmio, unsigned long bit); +static int gmbus_error_handler(unsigned char *mmio); + +/*! + * i2c_read_regs_plb is called to read Edid or a single sDVO register + * + * @param context + * @param i2c_bus port->ddc_reg, port->i2c_reg + * @param i2c_speed 50, 100, 400, 1000 (Khz) + * @param dab 0x70/0x72 (sDVO Regs), 0xA0/0xA2 (sDVO/Analog DDC) + * @param reg I2C Reg Index + * @param num_bytes <= 508 + * @param buffer Data read + * + * @return 0 on success + * @return 1 on failure + */ +static int i2c_read_regs_plb(igd_context_t *context, + unsigned long i2c_bus, + unsigned long i2c_speed, + unsigned long dab, + unsigned char reg, + unsigned char FAR *buffer, + unsigned long num_bytes) +{ + unsigned char *mmio = OS_MMIO(context->device_context.virt_mmadr); + unsigned long slave_addr; + + if (! gmbus_init(mmio, i2c_bus, i2c_speed)) { + OS_DEBUG("Error ! i2c_read_regs_plb : gmbus_init() failed"); + return 1; + } + + /* If the request is to read Edid from sDVO display, find out the */ + /* i2c addres of the sDVO device */ + if (i2c_bus == GMBUS_DVOB_DDC) { + slave_addr = dvob_port_plb.dab; + + } else { + slave_addr = 0; + + } + + switch (i2c_bus) { + case GMBUS_ANALOG_DDC : + case GMBUS_INT_LVDS_DDC : + case GMBUS_DVOB_DDC : + case GMBUS_DVOC_DDC : + if (! gmbus_read_edid(mmio, dab, slave_addr, reg, num_bytes, buffer)) { + + OS_DEBUG("Error ! i2c_read_regs_plb : gmbus_read_edid() failed"); + return 1; + } + break; + + case GMBUS_DVO_REG : + if (! gmbus_read_reg(mmio, dab, reg, buffer)) { + + OS_DEBUG("Error ! i2c_read_regs_plb : gmbus_read_reg() failed"); + return 1; + } + break; + + default : + OS_ERROR("Error ! i2c_read_regs_plb : Invalid i2c_bus=0x%lx", + i2c_bus); + return 1; + } + + return 0; +} + +/*! + * i2c_write_reg_list_plb is called to write a list of i2c registers to sDVO + * device + * + * @param context + * @param i2c_bus NAP_GMBUS_DVOB_DDC/NAP_GMBUS_DVOC_DDC + * @param i2c_speed 1000 Khz + * @param dab 0x70/0x72 + * @param reg_list List of i2c indexes and data, terminated with register index + * set to PD_REG_LIST_END + * + * @return 0 on success + * @return 1 on failure + */ +static int i2c_write_reg_list_plb(igd_context_t *context, + unsigned long i2c_bus, + unsigned long i2c_speed, + unsigned long dab, + pd_reg_t *reg_list, + unsigned long flags) +{ + unsigned char *mmio = OS_MMIO(context->device_context.virt_mmadr); + unsigned long reg_num = 0, ddc_addr = 0, slave_addr = 0; + + if (! gmbus_init(mmio, i2c_bus, i2c_speed)) { + + OS_DEBUG("Error ! i2c_write_reg_list_plb : gmbus_init() failed"); + return 1; + } + /*If it is SDVO Make sure we issue SDVO command to enable DDC access*/ + if ((i2c_bus == GMBUS_DVOB_DDC) || (i2c_bus == GMBUS_DVOC_DDC)) { + if (i2c_bus == GMBUS_DVOB_DDC) { + slave_addr = dvob_port_plb.dab; + }else if (i2c_bus == GMBUS_DVOC_DDC) { + /* Is DVOC available in PLB? */ + //slave_addr = dvoc_port_plb.dab; + slave_addr = 0; + } + ddc_addr = 0; + if (! gmbus_set_control_bus_switch(mmio, slave_addr, ddc_addr)) { + OS_DEBUG("Error ! i2c_write_reg_list_plb : gmbus_set_control_bus_switch()" + " failed"); + return 1; + } + while (reg_list[reg_num].reg != PD_REG_LIST_END) { + + if (! gmbus_write_reg(mmio, dab, reg_list[reg_num].reg, + (unsigned char)reg_list[reg_num].value)) { + + OS_DEBUG("Error ! i2c_write_reg_list_plb : gmbus_write_reg() failed, reg_num=%lu", + reg_num); + + return 1; + } + reg_num++; + } + /*...................................................................... */ + /* Issue a Stop Command */ + gmbus_wait_event_one(mmio, HW_WAIT); + WRITE_GMCH_REG(GMBUS1, STO | SW_RDY | ddc_addr); + gmbus_wait_event_one(mmio, HW_RDY); + gmbus_wait_event_zero(mmio, GA); + gmbus_error_handler(mmio); + WRITE_GMCH_REG(GMBUS1, SW_RDY); + WRITE_GMCH_REG(GMBUS1, SW_CLR_INT); + WRITE_GMCH_REG(GMBUS1, 0); + WRITE_GMCH_REG(GMBUS5, 0); + WRITE_GMCH_REG(GMBUS0, 0); + /*...................................................................... */ + return 0; + } + while (reg_list[reg_num].reg != PD_REG_LIST_END) { + + if (! gmbus_write_reg(mmio, dab, reg_list[reg_num].reg, + (unsigned char)reg_list[reg_num].value)) { + + OS_DEBUG("Error ! i2c_write_reg_list_plb : gmbus_write_reg() failed, reg_num=%lu", + reg_num); + + return 1; + } + + reg_num++; + } + + return 0; +} + +/*! + * gmbus_init initializes the GMBUS controller with specified bus and speed + * + * @param mmio + * @param i2c_bus sDVO B/C Reg/DDC or Analog DDC + * @param i2c_speed 50/100/400/1000 Khz + * + * @return TRUE(1) on success + * @return FALSE(0) on failure + */ +static int gmbus_init(unsigned char *mmio, unsigned long i2c_bus, + unsigned long i2c_speed) +{ + gmbus_pins_pair_t pin_pair; + gmbus_speed_t bus_speed; + + switch (i2c_bus) { + + case GMBUS_DVO_REG : + case GMBUS_DVOB_DDC : + case GMBUS_DVOC_DDC : + pin_pair = GMBUS_PINS_SDVO; + break; + + case GMBUS_ANALOG_DDC : + pin_pair = GMBUS_PINS_ANALOG; + break; + + case GMBUS_INT_LVDS_DDC : + pin_pair = GMBUS_PINS_INT_LVDS; + break; + + default : + OS_ERROR("Error ! gmbus_init : Invalid i2c_bus=0x%lx", i2c_bus); + return 0; + } + + switch (i2c_speed) { + + case 50 : /* Slow speed */ + bus_speed = GMBUS_SPEED_50K; + break; + + case 400 : /* SPD */ + bus_speed = GMBUS_SPEED_400K; + break; + + case 1000 : /* sDVO Registers */ + bus_speed = GMBUS_SPEED_1000K; + break; + + case 100 : /* DDC */ + default : + bus_speed = GMBUS_SPEED_100K; + break; + } + + WRITE_GMCH_REG(GMBUS5, 0); /* Clear the word index reg */ + WRITE_GMCH_REG(GMBUS0, pin_pair | bus_speed); + + return 1; +} + +/*! + * gmbus_wait_event_zero waits for specified GMBUS2 register bit to be deasserted + * + * @param mmio + * @param bit + * + * @return TRUE(1) on success. The bit was deasserted in the specified timeout period + * @return FALSE(0) on failure + */ +static int gmbus_wait_event_zero(unsigned char *mmio, unsigned long bit) +{ + unsigned long i; + unsigned long status; + + for (i = 0; i < 0x1000; i++) { + + status = READ_GMCH_REG(GMBUS2); + + if ((status & bit) == 0) { + + return 1; + } + } + + OS_DEBUG("Error ! gmbus_wait_event_zero : Failed : bit=0x%lx, status=0x%lx, forcing reset", + bit, status); + + /* If we are here, that means that the GBMUS is busy or in a bad + * state, the situation was observed + * that the GMBUS never becomes available (idle state) after S3. + * This results in the driver never being able to set the display. + * + * To fix this, we force force a reset of the GMBUS. + */ + WRITE_GMCH_REG(GMBUS1, SW_RDY); + WRITE_GMCH_REG(GMBUS1, SW_CLR_INT); + WRITE_GMCH_REG(GMBUS1, 0); + + return 1; +} + +/*! + * gmbus_wait_event_one wait for specified GMBUS2 register bits to be asserted + * + * @param mmio + * @param bit + * + * @return TRUE(1) on success. The bit was asserted in the specified timeout period + * @return FALSE(0) on failure + */ +static int gmbus_wait_event_one(unsigned char *mmio, unsigned long bit) +{ + unsigned long i; + unsigned long status; + + for (i = 0; i < 0x10000; i++) { + + status = READ_GMCH_REG(GMBUS2); + if ((status & bit) != 0) { + + return 1; + } + } + + OS_DEBUG("Error ! gmbus_wait_event_one : Failed : bit=0x%lx, status=0x%lx", + bit, status); + + return 0; +} + +/*! + * gmbus_error_handler attempts to recover from timeout error + * + * @param mmio + * + * @return TRUE(1) error was detected and handled + * @return FALSE(0) there was no error + */ +static int gmbus_error_handler(unsigned char *mmio) +{ + unsigned long status = READ_GMCH_REG(GMBUS2); + + /* Clear the SW_INT, wait for HWRDY and GMBus active (GA) */ + if ((status & HW_BUS_ERR) || (status & HW_TMOUT)) { + + OS_DEBUG("Error ! gmbus_error_handler : Resolving error=0x%lx", + status); + + WRITE_GMCH_REG(GMBUS1, SW_RDY); + WRITE_GMCH_REG(GMBUS1, SW_CLR_INT); + WRITE_GMCH_REG(GMBUS1, 0); + + gmbus_wait_event_zero(mmio, GA); + + return 1; /* Handled the error */ + } + + return 0; /* There was no error */ +} + +/*! + * Assemble 32 bit GMBUS1 command + * + * @param slave_addr 0x70/0x72 + * @param index 0 - 256 + * @param num_bytes Bytes to transfer + * @param flags Bits 25-31 of GMBUS1 + * @param i2c_dir I2C_READ / I2C_WRITE + * + * @return The assembled command + */ +static unsigned long gmbus_assemble_command(unsigned long slave_addr, unsigned long index, + unsigned long num_bytes, unsigned long flags, + i2c_bus_dir_t i2c_dir) +{ + unsigned long cmd = flags | ENIDX | ENT | (num_bytes << 16) | (index << 8) | + slave_addr | i2c_dir; + + return cmd; +} + +/*! + * gmbus_send_pkt transmits a block a data to specified i2c slave device + * + * @param mmio + * @param slave_addr I2C device address + * @param index Starting i2c register index + * @param pkt_size 1 - 508 bytes + * @param pkt Bytes to send + * + * @return TRUE(1) if successful in sending the specified number of bytes + * @return FALSE(0) on failure + */ +static int gmbus_send_pkt(unsigned char *mmio, + unsigned long slave_addr, unsigned long index, + unsigned long pkt_size, void *pkt) +{ + unsigned long gmbus1_cmd; + unsigned long bytes_sent; + unsigned long *data; + + if ((pkt_size == 0) || (pkt == NULL) || (pkt_size > 508)) { + + return 0; + } + + data = (unsigned long *)pkt; + + /*...................................................................... */ + gmbus_error_handler(mmio); + + gmbus1_cmd = gmbus_assemble_command(slave_addr, index, pkt_size, + STA, I2C_WRITE); + if (pkt_size <= 4) { + + gmbus1_cmd |= SW_RDY; + } + + /*...................................................................... */ + bytes_sent = 0; + + do { + + WRITE_GMCH_REG(GMBUS3, *data); + + if (bytes_sent == 0) { + + WRITE_GMCH_REG(GMBUS1, gmbus1_cmd); + } + + if (! gmbus_wait_event_one(mmio, HW_RDY)) { + + OS_DEBUG("Error ! gmbus_send_pkt : Failed to get HW_RDY, bytes_sent=%ld", + bytes_sent); + + return 0; + } + + if (gmbus_error_handler(mmio)) { + + OS_DEBUG("Error ! gmbus_send_pkt : gmbus error, bytes_sent=%ld", + bytes_sent); + + return 0; + } + + data++; + + if (pkt_size >= 4) { + bytes_sent += 4; + + } else { + bytes_sent += pkt_size; + } + + } while (bytes_sent < pkt_size); + + /*...................................................................... */ + if (bytes_sent != pkt_size) { + + return 0; + + } else { + + return 1; + } +} + +/*! + * gmbus_recv_pkt reads a block of data from specified i2c slave device + * + * @param mmio + * @param slave_addr I2C device address + * @param index Starting i2c register index + * @param pkt_size 1 - 508 bytes + * @param pkt Bytes to send + * + * @return TRUE(1) if successful in receiving specified number of bytes + * @return FALSE(0) on failure + */ +static int gmbus_recv_pkt(unsigned char *mmio, + unsigned long slave_addr, unsigned long index, + unsigned long pkt_size, void FAR *pkt) +{ + unsigned long gmbus1_cmd; + unsigned long bytes_rcvd; + unsigned long FAR *data; + + if ((pkt_size == 0) || (pkt == NULL) || (pkt_size > 508)) { + + return 0; + } + + data = (unsigned long FAR *)pkt; + + /*...................................................................... */ + gmbus_error_handler(mmio); + + /* Program the command */ + gmbus1_cmd = gmbus_assemble_command(slave_addr, index, pkt_size, + STA | SW_RDY, I2C_READ); + WRITE_GMCH_REG(GMBUS1, gmbus1_cmd); + + /*...................................................................... */ + bytes_rcvd = 0; + do { + + unsigned long gmbus3_data; + unsigned long bytes_left = pkt_size - bytes_rcvd; + + if (! gmbus_wait_event_one(mmio, HW_RDY)) { + + OS_DEBUG("Error ! gmbus_recv_pkt : Failed to get HW_RDY, " + "bytes_rcvd=%ld", bytes_rcvd); + break; + } + + if (gmbus_error_handler(mmio)) { + + OS_DEBUG("Error ! gmbus_recv_pkt : gmbus error, bytes_rcvd=%ld", + bytes_rcvd); + break; + } + + gmbus3_data = READ_GMCH_REG(GMBUS3); + + switch (bytes_left) { + + case 1 : + *(unsigned char *)data = (unsigned char)gmbus3_data; + break; + + case 2 : + *(unsigned short *)data = (unsigned short)gmbus3_data; + break; + + case 3 : + { + unsigned char *dest = (unsigned char *)data; + unsigned char *src = (unsigned char *)&(gmbus3_data); + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + + break; + } + + default : /* >= 4 */ + *data = gmbus3_data; + break; + } + + if (bytes_left > 4) { + bytes_rcvd += 4; + data++; + + } else { + bytes_rcvd += bytes_left; + + } + + } while (bytes_rcvd < pkt_size); + + /*...................................................................... */ + if (bytes_rcvd < pkt_size) { + return 0; + + } else { + return 1; + } +} + +/*! + * gmbus_set_control_bus_switch sends sDVO command to switch i2c bus to read EDID + * or SPD data + * + * @param mmio + * @param slave_addr sDVO device address (0x70/0x72) + * @param ddc_addr DDC1_ADDR/DDC2_ADDR + * + * @return TRUE(1) if successful in sending the opcode + * @return FALSE(0) on failure + */ +static int gmbus_set_control_bus_switch(unsigned char *mmio, + unsigned long slave_addr, + gmbus_ddc_addr_t ddc_addr) +{ + unsigned char data; + sdvo_bus_switch_t bus_switch; + int retry; + + bus_switch = SDVO_BUS_DDC1; + + /*...................................................................... */ + /* Transmit the Arguments */ + if (! gmbus_send_pkt(mmio, slave_addr, SDVO_INDEX_PARAM_1, 1, &bus_switch)) { + + OS_DEBUG("Error ! gmbus_set_control_bus_switch : gmbus_send_pkt() failed"); + + return 0; + } + + /*...................................................................... */ + /* Generate I2C stop cycle */ + gmbus_wait_event_one(mmio, HW_WAIT); + WRITE_GMCH_REG(GMBUS1, STO | SW_RDY | slave_addr); + gmbus_wait_event_one(mmio, HW_RDY); + gmbus_wait_event_zero(mmio, GA); + + /*...................................................................... */ + /* Transmit the Opcode */ + data = SDVO_OPCODE_BUS_SWITCH; + if (! gmbus_send_pkt(mmio, slave_addr, SDVO_INDEX_OPCODE, 1, &data)) { + + OS_DEBUG("Error ! gmbus_set_control_bus_switch : gmbus_send_pkt(Opcode)" + " failed"); + + return 0; + } + + /*...................................................................... */ + /* Read Status */ + for (retry = 0; retry < 3; retry++) { + if (! gmbus_recv_pkt(mmio, slave_addr, SDVO_INDEX_STATUS, 1, &data)) { + + continue; + } + + if (data != SDVO_STATUS_PENDING) { + + break; + } + } + + /*...................................................................... */ + /* Send Stop */ + gmbus_wait_event_one(mmio, HW_WAIT); + WRITE_GMCH_REG(GMBUS1, STO | SW_RDY | slave_addr); + gmbus_wait_event_one(mmio, HW_RDY); + gmbus_wait_event_zero(mmio, GA); + + /*...................................................................... */ + if (data != SDVO_STATUS_SUCCESS) { + + OS_DEBUG("Error ! gmbus_set_control_bus_switch : Opcode Bus Switch failed"); + + return 0; + } + + return 1; +} + +/*! + * gmbus_read_edid reads specified number of Edid data bytes + * + * @param mmio + * @param ddc_addr 0xA0/0xA2 (DDC1/DDC2) + * @param slave_addr 0x70/0x72 (sDVOB, sDVOC), 0 Analog + * @param index i2c register index + * @param num_bytes <= 508 + * @param buffer Edid data read from the display + * + * @return TRUE(1) if successful in reading Edid + * @return FALSE(0) on failure + */ +static int gmbus_read_edid(unsigned char *mmio, + unsigned long ddc_addr, + unsigned long slave_addr, + unsigned long index, + unsigned long num_bytes, + unsigned char FAR *buffer) +{ + int status; + + if ((slave_addr == SDVOB_ADDR) || (slave_addr == SDVOC_ADDR)) { + + if (! gmbus_set_control_bus_switch(mmio, slave_addr, ddc_addr)) { + + OS_DEBUG("Error ! gmbus_read_edid : gmbus_set_control_bus_switch()" + " failed"); + + return 0; + } + } else { + /* Reset the bus */ + gmbus_recv_pkt(mmio, ddc_addr, 0, 1, buffer); + } + + status = gmbus_recv_pkt(mmio, ddc_addr, index, num_bytes, buffer); + if (! status) { + + OS_DEBUG("Error ! gmbus_read_edid : gmbus_recv_pkt() failed"); + } + + /*...................................................................... */ + /* Issue a Stop Command */ + + gmbus_wait_event_one(mmio, HW_WAIT); + WRITE_GMCH_REG(GMBUS1, STO | SW_RDY | ddc_addr); + gmbus_wait_event_one(mmio, HW_RDY); + + gmbus_wait_event_zero(mmio, GA); + + gmbus_error_handler(mmio); + WRITE_GMCH_REG(GMBUS1, SW_RDY); + WRITE_GMCH_REG(GMBUS1, SW_CLR_INT); + WRITE_GMCH_REG(GMBUS1, 0); + WRITE_GMCH_REG(GMBUS5, 0); + WRITE_GMCH_REG(GMBUS0, 0); + + /*...................................................................... */ + return status; +} + +/*! + * gmbus_read_reg reads one i2c register + * + * @param mmio + * @param slave_addr 0x70/0x72 (sDVOB, sDVOC) + * @param index i2c register index + * @param data register data + * + * @return TRUE(1) if successful in reading the i2c register + * @return FALSE(0) on failure + */ +static int gmbus_read_reg(unsigned char *mmio, + unsigned long slave_addr, + unsigned long index, + unsigned char FAR *data) +{ + unsigned long gmbus1_cmd; + + WRITE_GMCH_REG(GMBUS5, 0x0); /* Clear Word Index register */ + + if (! gmbus_wait_event_zero(mmio, GA)) { + + OS_DEBUG("Error ! gmbus_read_reg : Failed to get GA(1)"); + + return 0; + } + + gmbus1_cmd = gmbus_assemble_command(slave_addr, index, 1, + STO | STA, I2C_READ); + WRITE_GMCH_REG(GMBUS1, gmbus1_cmd); + + if (! gmbus_wait_event_zero(mmio, GA)) { + + OS_DEBUG("Error ! gmbus_read_reg : Failed to get GA(2)"); + + return 0; + } + + *data = (unsigned char)READ_GMCH_REG(GMBUS3); + + return 1; +} + +/*! + * gmbus_write_reg writes one i2c register + * + * @param mmio + * @param slave_addr 0x70/0x72 (sDVOB, sDVOC) + * @param index i2c register index + * @param data register data + * + * @return TRUE(1) if successful in updating the i2c register + * @return FALSE(0) if failed to update the register + */ +static int gmbus_write_reg(unsigned char *mmio, + unsigned long slave_addr, + unsigned long index, + unsigned char data) +{ + unsigned long gmbus1_cmd; + + WRITE_GMCH_REG(GMBUS5, 0x0); /* Clear Word Index register */ + + if (! gmbus_wait_event_zero(mmio, GA)) { + + OS_DEBUG("Error ! gmbus_write_reg : Failed to get GA(1)"); + + return 0; + } + + WRITE_GMCH_REG(GMBUS3, data); + + gmbus1_cmd = gmbus_assemble_command(slave_addr, index, 1, + STO | STA, I2C_WRITE); + WRITE_GMCH_REG(GMBUS1, gmbus1_cmd); + + if (! gmbus_wait_event_zero(mmio, GA)) { + + OS_DEBUG("Error ! gmbus_write_reg : Failed to get GA(2)"); + return 0; + } + + return 1; +} + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: i2c_plb.c,v 1.7 2010/05/17 21:05:15 achrisan Exp $ + * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/pi/plb/i2c_plb.c,v $ + *---------------------------------------------------------------------------- + */ diff --git a/drivers/gpu/drm/emgd/emgd/display/pi/tnc/i2c_bitbash_tnc.c b/drivers/gpu/drm/emgd/emgd/display/pi/tnc/i2c_bitbash_tnc.c new file mode 100644 index 0000000..f431580 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/pi/tnc/i2c_bitbash_tnc.c @@ -0,0 +1,588 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: i2c_bitbash_tnc.c + * $Revision: 1.3 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * Bitbash to read GPIO pins are done on LPC device 0:31:0. So do not + * use OS_READ32 and OS_WRITE32 macros for read/write to device 31. These + * macros do mmio only on device2. + * To properly read/write mmio on device 31, use + * READ_MMIO_REG_TNC(port_type, reg) and + * WRITE_MMIO_REG_TNC(port_type, reg, data). + * These macros properly set to work for all OSes including VBIOS, but + * generate more code compared to OS_READ32 and OS_WRITE32. So use as + * necessary. + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.dpd + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include + +#include "../cmn/i2c_dispatch.h" + +/*! + * @addtogroup display_group + * @{ + */ + +static int i2c_error_recovery_tnc( + unsigned long hold_time); + +static int i2c_write_byte_tnc( + unsigned char value, + unsigned long hold_time); + +static int i2c_read_byte_tnc( + unsigned char *value, + unsigned char ack, + unsigned long hold_time); + +int i2c_read_regs_gpio( + igd_context_t *context, + unsigned long i2c_bus, + unsigned long i2c_speed, + unsigned long dab, + unsigned char reg, + unsigned char FAR *buffer, + unsigned long num_bytes); + +int i2c_write_reg_list_gpio( + igd_context_t *context, + unsigned long i2c_bus, + unsigned long i2c_speed, + unsigned long dab, + pd_reg_t *reg_list, + unsigned long flags); + +/* The LVDS GPIO clock lines are GPIOSUS[3] + * The LVDS GPIO data lines are GPIOSUS[4] + */ +#define GPIO_CLOCK 0x08 +#define GPIO_DATA 0x10 + +/*! + * + * @param context + * + * @return void + */ +#if 0 +static void enable_gpio_tnc(igd_context_t *context) +{ + /* + * NOTE: This really should be a system BIOS job. + * The driver would not touch these register anymore since + * it would cause the 13x7 panel fail to start. + */ + + /* Enabling LVDS Data and LVDS Clock */ + unsigned long temp; + + temp = READ_MMIO_REG_TNC(IGD_PORT_LPC, RGEN); + temp |= (GPIO_DATA | GPIO_CLOCK); + WRITE_MMIO_REG_TNC(IGD_PORT_LPC, RGEN, temp); + + return; +} +#endif + +/*! + * + * @param clock + * @param data + * + * @return void + */ +static void i2c_get(unsigned long *clock, + unsigned long *data) +{ + unsigned long temp; + /* Set Data as Input */ + temp = READ_MMIO_REG_TNC(IGD_PORT_LPC, RGIO); + temp |= (GPIO_DATA); + WRITE_MMIO_REG_TNC(IGD_PORT_LPC, RGIO, temp); + /* Read Data */ + *data = (READ_MMIO_REG_TNC(IGD_PORT_LPC, RGLVL) & GPIO_DATA) ? 1:0; + *clock = (READ_MMIO_REG_TNC(IGD_PORT_LPC, RGLVL) & GPIO_CLOCK) ? 1:0; + +#if 0 + OS_WRITE32(0, OS_MMIO(mmio) + i2c_bus); + c = OS_READ32(OS_MMIO(mmio) + i2c_bus)>>4; + *data = (c>>8) & 1; + *clock &= 1; +#endif +} + +/*! + * + * @param data + * @param hold_time + * + * @return void + */ +static void i2c_set_data(int data, + unsigned long hold_time) +{ + unsigned long temp; + /* The LVDS GPIO data lines are GPIOSUS[4] */ + /* Set as Output */ + temp = READ_MMIO_REG_TNC(IGD_PORT_LPC, RGIO); + temp &= ~GPIO_DATA; + WRITE_MMIO_REG_TNC(IGD_PORT_LPC, RGIO, temp); + /* Read status register */ + temp = READ_MMIO_REG_TNC(IGD_PORT_LPC, RGLVL); + + if(data){ + /* Set level to High */ + temp |= GPIO_DATA; + } else { + /* Set level to low */ + temp &= ~GPIO_DATA; + } + WRITE_MMIO_REG_TNC(IGD_PORT_LPC, RGLVL, temp); + + OS_SLEEP(hold_time); + +#if 0 + /* Implementation using Display GPIO + * For alm, the default data value "could" be 0 + */ + /* + * Simplified definition for the bits + * 11: GPIO data Value + * 10: GPIO Data Mask + * 9: GPIO Data Direction Value + * 8: GPIO Data Direction Mask + */ + OS_WRITE32(data ? 0x500 : 0x700, OS_MMIO(mmio) + i2c_bus); + OS_WRITE32(data ? 0x400 : 0x600, OS_MMIO(mmio) + i2c_bus); + OS_SLEEP(hold_time); +#endif +} + +/*! + * + * @param clock + * @param hold_time + * + * @return void + */ +static void i2c_set_clock(int clock, + unsigned long hold_time) +{ + unsigned long temp; + /* The LVDS GPIO clock lines are GPIOSUS[3] */ + /* Set as Output */ + temp = READ_MMIO_REG_TNC(IGD_PORT_LPC, RGIO); + temp &= ~GPIO_CLOCK; + WRITE_MMIO_REG_TNC(IGD_PORT_LPC, RGIO, temp); + /* Read Status Register */ + temp = READ_MMIO_REG_TNC(IGD_PORT_LPC, RGLVL); + + if(clock){ + /* Set level to High */ + temp |= GPIO_CLOCK; + + } else { + /* Set level to low */ + temp &= ~GPIO_CLOCK; + } + WRITE_MMIO_REG_TNC(IGD_PORT_LPC, RGLVL, temp); + + OS_SLEEP(hold_time); + +#if 0 + /* + * Simplified definition for the bits + * 3: GPIO Clock Value + * 2: GPIO Clock Mask + * 1: GPIO Clock Direction Value + * 0: GPIO Clock Direction Mask + */ + + OS_WRITE32(clock ? 0x5 : 0x7, OS_MMIO(mmio) + i2c_bus); + OS_WRITE32(clock ? 0x4 : 0x6, OS_MMIO(mmio) + i2c_bus); + OS_SLEEP(hold_time); +#endif +} + +/*! + * + * @param hold_time + * + * @return 0 on success + * @return 1 on failure + */ +static int i2c_start_tnc(unsigned long hold_time) +{ + unsigned long sc, sd; + + /* set sd high */ + i2c_set_data(1, hold_time); + + /* set clock high */ + i2c_set_clock(1, hold_time); + + /* Start condition happens when sd goes high to low when sc is high */ + i2c_get(&sc, &sd); + + if( 0 == sc ) { + // Data must be high + i2c_error_recovery_tnc(hold_time); + return 1; + } + + i2c_set_data(0, hold_time); + i2c_set_clock(0, hold_time); + + return 0; +} /* end i2c_start */ + +/*! + * + * @param hold_time + * + * @return 0 + */ +static int i2c_stop_tnc(unsigned long hold_time) +{ + /* Stop condition happens when sd goes low to high when sc is high */ + unsigned long sc,sd; + + i2c_set_clock(0, hold_time); + i2c_set_data(0, hold_time); + + i2c_set_clock(1, hold_time); + + i2c_get(&sc, &sd); + /* Try another time */ + if (sc == 0) { + i2c_set_clock(1, hold_time); + } + i2c_set_data(1, hold_time); + + return 0; +} /* end i2c_stop */ + +/*! + * + * @param hold_time + * + * @return 0 on success + * @return 1 on failure + */ +static int i2c_error_recovery_tnc(unsigned long hold_time) +{ + unsigned char max_retries = 9; + unsigned long sc, sd; + + while (max_retries--) { + i2c_get(&sc, &sd); + if (sd == 1 && sc == 1) { + return 0; + } else { + i2c_stop_tnc(hold_time); + } + } + OS_ERROR("Cannot recover I2C error."); + + return 1; +} + +/*! + * + * @param value + * @param hold_time + * + * @return 0 on success + * @return 1 on failure + */ +static int i2c_write_byte_tnc(unsigned char value, + unsigned long hold_time) +{ + int i; + unsigned long sc,sd; + + /* I2C_DEBUG("i2c_write_byte"); */ + for(i=7; i>=0; i--) { + i2c_set_clock(0, hold_time); + i2c_set_data(value>>i & 1, hold_time); + + i2c_set_clock(1, hold_time); + } + + /* Get ACK */ + i2c_set_clock(0, hold_time); + /* Set data low. Possible inteference in some lvds panel */ + i2c_set_data(0, hold_time); + i2c_set_clock(1, hold_time); + OS_SLEEP(hold_time); + + i2c_get(&sc, &sd); + + i2c_set_clock(0, hold_time); + + if (sd != 0) { + OS_ERROR("No ACK for byte 0x%x", value); + i2c_error_recovery_tnc(hold_time); + return 1; + } + + return 0; + +} /* end i2c_write_byte */ + +/*! + * + * @param value + * @param ack + * @param hold_time + * + * @return 0 on success + * @return 1 on failure + */ +static int i2c_read_byte_tnc(unsigned char *value, + unsigned char ack, + unsigned long hold_time) +{ + int i; + unsigned long sc, sd, temp; + + *value = 0; + for(i=7; i>=0; i--) { + i2c_set_clock(1, hold_time); + i2c_get(&sc, &sd); + OS_SLEEP(hold_time); + if(!sc) { + OS_DEBUG("Clock low on read %d", i); + i2c_error_recovery_tnc(hold_time); + return 1; + } + *value |= (sd & 1)<reg != PD_REG_LIST_END) { + if (i2c_start_tnc(hold_time)) { + OS_DEBUG("Start failed"); + return 1; + } + + if (i2c_write_byte_tnc((unsigned char)dab & 0xFE, + hold_time)) { + OS_DEBUG("DAB(W) failed"); + return 1; + } + + /* Register Address */ + if (i2c_write_byte_tnc((unsigned char)reg_list->reg, hold_time)) { + OS_DEBUG("RAB failed"); + return 1; + } + + do { + /* New Value */ + if (i2c_write_byte_tnc((unsigned char)reg_list->value, hold_time)) { + OS_DEBUG("Data failed"); + return 1; + } + + if(reg_list[1].reg != (reg_list[0].reg + 1)) { + reg_list++; + break; + } + + OS_DEBUG("I2C Multi-Write Reg[%x] = 0x%x", + (unsigned short)reg_list->reg, + (unsigned short)reg_list->value); + reg_list++; + } while(flags & IGD_I2C_SERIAL_WRITE); + + + i2c_stop_tnc(hold_time); + i2c_stop_tnc(hold_time); + } + + return 0; +} + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: i2c_bitbash_tnc.c,v 1.3 2010/04/27 20:33:49 bpaauwe Exp $ + * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/pi/tnc/i2c_bitbash_tnc.c,v $ + *---------------------------------------------------------------------------- + */ diff --git a/drivers/gpu/drm/emgd/emgd/display/pi/tnc/i2c_gmbus_tnc.c b/drivers/gpu/drm/emgd/emgd/display/pi/tnc/i2c_gmbus_tnc.c new file mode 100644 index 0000000..b1e3373 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/display/pi/tnc/i2c_gmbus_tnc.c @@ -0,0 +1,925 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: i2c_gmbus_tnc.c + * $Revision: 1.6 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.dpd + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include "../cmn/i2c_dispatch.h" + +/*! + * @addtogroup display_group + * @{ + */ + +/*......................................................................... */ +extern igd_display_port_t dvob_port_tnc; + +/*......................................................................... */ +static int i2c_read_regs_tnc( + igd_context_t *context, + unsigned long i2c_bus, + unsigned long i2c_speed, + unsigned long dab, + unsigned char reg, + unsigned char FAR *buffer, + unsigned long num_bytes); + +static int i2c_write_reg_list_tnc( + igd_context_t *context, + unsigned long i2c_bus, + unsigned long i2c_speed, + unsigned long dab, + pd_reg_t *reg_list, + unsigned long flags); + +i2c_dispatch_t i2c_dispatch_tnc = { + i2c_read_regs_tnc, + i2c_write_reg_list_tnc, +}; + + +/*.......................................................................... */ +typedef enum { + + GMBUS_SPEED_50K = 0x0100, + GMBUS_SPEED_100K = 0x0000, + GMBUS_SPEED_400K = 0x0200, + GMBUS_SPEED_1000K = 0x0300, + +} gmbus_speed_t; + +typedef enum { + + SDVOB_ADDR = 0x70, + +} sdvo_dev_addr_t; + +typedef enum { + + DDC1_ADDR = 0xA0, + DDC2_ADDR = 0xA2, + +} gmbus_ddc_addr_t; + + +typedef enum { + + GMBUS_PINS_DEDICATED = 1, /* Dedicated Control/GMBUS Pins */ + GMBUS_PINS_SDVO = 5, /* SDVO Registers, DDC, PROM */ + +} gmbus_pins_pair_t; + + +typedef enum { + + I2C_WRITE = 0, + I2C_READ = 1, + +} i2c_bus_dir_t; + +/*.......................................................................... */ +typedef enum { + + SDVO_BUS_PROM = BIT(0), + SDVO_BUS_DDC1 = BIT(1), + SDVO_BUS_DDC2 = BIT(2), + +} sdvo_bus_switch_t; + +#define SDVO_OPCODE_BUS_SWITCH 0x7A + +#define SDVO_INDEX_PARAM_1 0x07 +#define SDVO_INDEX_OPCODE 0x08 +#define SDVO_INDEX_STATUS 0x09 + +#define SDVO_STATUS_SUCCESS 0x01 +#define SDVO_STATUS_PENDING 0x04 + +/*.......................................................................... */ +/* + * In 16-bit, the mmio is a 16-bit pointer, the watcom 1.2 compiler will have + * error if directly convert it to unsigned long. Normally, have to cast it to + * unsigned short first then cast again to unsigned long; then, it will be + * correct. But this type of casting may cause some error in the 32 and 64 bit + * code. Since mmio will be equal to zero for 16-bit code. Add the checking + * for MICRO definition code to correct the macro by remove mmio. + */ +#define READ_GMCH_REG(reg) READ_MMIO_REG_TNC(IGD_PORT_SDVO, reg) +#define WRITE_GMCH_REG(reg, data) WRITE_MMIO_REG_TNC(IGD_PORT_SDVO, reg, data) + +static int gmbus_init(unsigned long i2c_bus, + unsigned long i2c_speed); + +static int gmbus_read_edid(unsigned long ddc_addr, + unsigned long slave_addr, + unsigned long index, + unsigned long num_bytes, + unsigned char FAR *buffer); + +static int gmbus_read_reg(unsigned long slave_addr, + unsigned long index, + unsigned char FAR *data); + +static int gmbus_write_reg(unsigned long slave_addr, + unsigned long index, + unsigned char data); + +static int gmbus_set_control_bus_switch(unsigned long slave_addr, + gmbus_ddc_addr_t ddc_addr); + +static int gmbus_wait_event_one(unsigned long bit); +static int gmbus_wait_event_zero(unsigned long bit); +static int gmbus_error_handler(void); + +/*.......................................................................... */ +extern int i2c_read_regs_gpio( + igd_context_t *context, + unsigned long i2c_bus, + unsigned long i2c_speed, + unsigned long dab, + unsigned char reg, + unsigned char FAR *buffer, + unsigned long num_bytes); + +extern int i2c_write_reg_list_gpio( + igd_context_t *context, + unsigned long i2c_bus, + unsigned long i2c_speed, + unsigned long dab, + pd_reg_t *reg_list, + unsigned long flags); + + +/*! + * i2c_read_regs_tnc is called to read Edid or a single sDVO register + * + * @param context + * @param i2c_bus port->ddc_reg, port->i2c_reg + * @param i2c_speed 50, 100, 400, 1000 (Khz) + * @param dab 0x70/0x72 (sDVO Regs), 0xA0/0xA2 (sDVO/Analog DDC) + * @param reg I2C Reg Index + * @param num_bytes <= 508 + * @param buffer Data read + * + * @return 0 on success + * @return 1 on failure + */ +static int i2c_read_regs_tnc(igd_context_t *context, + unsigned long i2c_bus, + unsigned long i2c_speed, + unsigned long dab, + unsigned char reg, + unsigned char FAR *buffer, + unsigned long num_bytes) +{ + unsigned long slave_addr = 0; + + if(i2c_bus == I2C_INT_LVDS_DDC){ + /* + * Tunnel Creek LVDS does not have GMBUS support. To read DDC register, we bit bash. + * The i2c_speed is necessary to calculate the hold time. But i2c_bus is not needed. + */ + + OS_DEBUG("i2c_read_regs_tnc : Using GPIO to read DDC"); + return i2c_read_regs_gpio(context, i2c_bus, i2c_speed, dab, reg, buffer, num_bytes); + + } else { + + if (! gmbus_init(i2c_bus, i2c_speed)) { + OS_DEBUG("Error ! i2c_read_regs_tnc : gmbus_init() failed"); + return 1; + } + + /* If the request is to read Edid from sDVO display, find out the */ + /* i2c addres of the sDVO device */ + if (i2c_bus == GMBUS_DVOB_DDC) { + slave_addr = dvob_port_tnc.dab; + } + + switch (i2c_bus) { + case GMBUS_DVOB_DDC : + if (! gmbus_read_edid(dab, slave_addr, reg, num_bytes, buffer)) { + + OS_DEBUG("Error ! i2c_read_regs_tnc : gmbus_read_edid() failed"); + return 1; + } + break; + + case GMBUS_DVO_REG : + if (! gmbus_read_reg(dab, reg, buffer)) { + + OS_DEBUG("Error ! i2c_read_regs_tnc : gmbus_read_reg() failed"); + return 1; + } + break; + + default : + OS_ERROR("Error ! i2c_read_regs_tnc : Invalid i2c_bus=0x%lx", + i2c_bus); + return 1; + } + } + + return 0; +} + +/*! + * i2c_write_reg_list_tnc is called to write a list of i2c registers to sDVO + * device + * + * @param context + * @param i2c_bus NAP_GMBUS_DVOB_DDC/NAP_GMBUS_DVOC_DDC + * @param i2c_speed 1000 Khz + * @param dab 0x70/0x72 + * @param reg_list List of i2c indexes and data, terminated with register index + * set to PD_REG_LIST_END + * + * @return 0 on success + * @return 1 on failure + */ +static int i2c_write_reg_list_tnc(igd_context_t *context, + unsigned long i2c_bus, + unsigned long i2c_speed, + unsigned long dab, + pd_reg_t *reg_list, + unsigned long flags) +{ + unsigned long reg_num = 0, ddc_addr = 0, slave_addr = 0; + + if(i2c_bus == I2C_INT_LVDS_DDC){ + /* There are no GMBUS pins for internal LVDS on Tunnel Creek. + * Forcing us to use bit bashing */ + /* FIXME: determine which GPIO pin is used for bit bashing + * i2c_bus is not defined + */ + OS_DEBUG("i2c_write_reg_list_tnc : Using GPIO to write DDC"); + return i2c_write_reg_list_gpio(context, i2c_bus, i2c_speed, dab, reg_list, flags); + + } else { + + if (! gmbus_init(i2c_bus, i2c_speed)) { + + OS_DEBUG("Error ! i2c_write_reg_list_tnc : gmbus_init() failed"); + return 1; + } + /*If it is SDVO Make sure we issue SDVO command to enable DDC access*/ + if (i2c_bus == GMBUS_DVOB_DDC) { + slave_addr = dvob_port_tnc.dab; + ddc_addr = 0; + + if (! gmbus_set_control_bus_switch(slave_addr, ddc_addr)) { + OS_DEBUG("Error ! i2c_write_reg_list_tnc : gmbus_set_control_bus_switch()" + " failed"); + return 1; + } + while (reg_list[reg_num].reg != PD_REG_LIST_END) { + + if (! gmbus_write_reg(dab, reg_list[reg_num].reg, + (unsigned char)reg_list[reg_num].value)) { + + OS_DEBUG("Error ! i2c_write_reg_list_tnc : gmbus_write_reg() failed, reg_num=%lu", + reg_num); + + return 1; + } + reg_num++; + } + /*...................................................................... */ + /* Issue a Stop Command */ + gmbus_wait_event_one(HW_WAIT); + WRITE_GMCH_REG(GMBUS1, STO | SW_RDY | ddc_addr); + gmbus_wait_event_one(HW_RDY); + gmbus_wait_event_zero(GA); + gmbus_error_handler(); + WRITE_GMCH_REG(GMBUS1, SW_RDY); + WRITE_GMCH_REG(GMBUS1, SW_CLR_INT); + WRITE_GMCH_REG(GMBUS1, 0); + WRITE_GMCH_REG(GMBUS5, 0); + WRITE_GMCH_REG(GMBUS0, 0); + /*...................................................................... */ + return 0; + } + while (reg_list[reg_num].reg != PD_REG_LIST_END) { + + if (! gmbus_write_reg(dab, reg_list[reg_num].reg, + (unsigned char)reg_list[reg_num].value)) { + + OS_DEBUG("Error ! i2c_write_reg_list_tnc : gmbus_write_reg() failed, reg_num=%lu", + reg_num); + + return 1; + } + + reg_num++; + } + } + + return 0; +} + +/*! + * gmbus_init initializes the GMBUS controller with specified bus and speed + * + * @param i2c_bus sDVO B/C Reg/DDC or Analog DDC + * @param i2c_speed 50/100/400/1000 Khz + * + * @return TRUE(1) on success + * @return FALSE(0) on failure + */ +static int gmbus_init(unsigned long i2c_bus, + unsigned long i2c_speed) +{ + gmbus_pins_pair_t pin_pair; + gmbus_speed_t bus_speed; + + switch (i2c_bus) { + + case GMBUS_DVO_REG : + case GMBUS_DVOB_DDC : + pin_pair = GMBUS_PINS_SDVO; + break; + + default : + OS_ERROR("Error ! gmbus_init : Invalid i2c_bus=0x%lx", i2c_bus); + return 0; + } + + switch (i2c_speed) { + + case 50 : /* Slow speed */ + bus_speed = GMBUS_SPEED_50K; + break; + + case 400 : /* SPD */ + bus_speed = GMBUS_SPEED_400K; + break; + + case 1000 : /* sDVO Registers */ + bus_speed = GMBUS_SPEED_1000K; + break; + + case 100 : /* DDC */ + default : + bus_speed = GMBUS_SPEED_100K; + break; + } + + WRITE_GMCH_REG(GMBUS5, 0); /* Clear the word index reg */ + WRITE_GMCH_REG(GMBUS0, pin_pair | bus_speed); + + return 1; +} + +/*! + * gmbus_wait_event_zero waits for specified GMBUS2 register bit to be deasserted + * + * @param bit + * + * @return TRUE(1) on success. The bit was deasserted in the specified timeout period + * @return FALSE(0) on failure + */ +static int gmbus_wait_event_zero(unsigned long bit) +{ + unsigned long i; + unsigned long status; + + for (i = 0; i < 0x1000; i++) { + + status = READ_GMCH_REG(GMBUS2); + + if ((status & bit) == 0) { + + return 1; + } + } + + OS_DEBUG("Error ! gmbus_wait_event_zero : Failed : bit=0x%lx, status=0x%lx", + bit, status); + + return 0; +} + +/*! + * gmbus_wait_event_one wait for specified GMBUS2 register bits to be asserted + * + * @param bit + * + * @return TRUE(1) on success. The bit was asserted in the specified timeout period + * @return FALSE(0) on failure + */ +static int gmbus_wait_event_one(unsigned long bit) +{ + unsigned long i; + unsigned long status; + + for (i = 0; i < 0x10000; i++) { + + status = READ_GMCH_REG(GMBUS2); + if ((status & bit) != 0) { + + return 1; + } + } + + OS_DEBUG("Error ! gmbus_wait_event_one : Failed : bit=0x%lx, status=0x%lx", + bit, status); + + return 0; +} + +/*! + * gmbus_error_handler attempts to recover from timeout error + * + * + * @return TRUE(1) error was detected and handled + * @return FALSE(0) there was no error + */ +static int gmbus_error_handler(void) +{ + unsigned long status = READ_GMCH_REG(GMBUS2); + + /* Clear the SW_INT, wait for HWRDY and GMBus active (GA) */ + if ((status & HW_BUS_ERR) || (status & HW_TMOUT)) { + + OS_DEBUG("Error ! gmbus_error_handler : Resolving error=0x%lx", + status); + + WRITE_GMCH_REG(GMBUS1, SW_RDY); + WRITE_GMCH_REG(GMBUS1, SW_CLR_INT); + WRITE_GMCH_REG(GMBUS1, 0); + + gmbus_wait_event_zero(GA); + + return 1; /* Handled the error */ + } + + return 0; /* There was no error */ +} + +/*! + * Assemble 32 bit GMBUS1 command + * + * @param slave_addr 0x70/0x72 + * @param index 0 - 256 + * @param num_bytes Bytes to transfer + * @param flags Bits 25-31 of GMBUS1 + * @param i2c_dir I2C_READ / I2C_WRITE + * + * @return The assembled command + */ +static unsigned long gmbus_assemble_command(unsigned long slave_addr, unsigned long index, + unsigned long num_bytes, unsigned long flags, + i2c_bus_dir_t i2c_dir) +{ + unsigned long cmd = flags | ENIDX | ENT | (num_bytes << 16) | (index << 8) | + slave_addr | i2c_dir; + + return cmd; +} + +/*! + * gmbus_send_pkt transmits a block a data to specified i2c slave device + * + * @param slave_addr I2C device address + * @param index Starting i2c register index + * @param pkt_size 1 - 508 bytes + * @param pkt Bytes to send + * + * @return TRUE(1) if successful in sending the specified number of bytes + * @return FALSE(0) on failure + */ +static int gmbus_send_pkt(unsigned long slave_addr, unsigned long index, + unsigned long pkt_size, void *pkt) +{ + unsigned long gmbus1_cmd; + unsigned long bytes_sent; + unsigned long *data; + + if ((pkt_size == 0) || (pkt == NULL) || (pkt_size > 508)) { + + return 0; + } + + data = (unsigned long *)pkt; + + /*...................................................................... */ + gmbus_error_handler(); + + gmbus1_cmd = gmbus_assemble_command(slave_addr, index, pkt_size, + STA, I2C_WRITE); + if (pkt_size <= 4) { + + gmbus1_cmd |= SW_RDY; + } + + /*...................................................................... */ + bytes_sent = 0; + + do { + + WRITE_GMCH_REG(GMBUS3, *data); + + if (bytes_sent == 0) { + + WRITE_GMCH_REG(GMBUS1, gmbus1_cmd); + } + + if (! gmbus_wait_event_one(HW_RDY)) { + + OS_DEBUG("Error ! gmbus_send_pkt : Failed to get HW_RDY, bytes_sent=%ld", + bytes_sent); + + return 0; + } + + if (gmbus_error_handler()) { + + OS_DEBUG("Error ! gmbus_send_pkt : gmbus error, bytes_sent=%ld", + bytes_sent); + + return 0; + } + + data++; + + if (pkt_size >= 4) { + bytes_sent += 4; + + } else { + bytes_sent += pkt_size; + } + + } while (bytes_sent < pkt_size); + + /*...................................................................... */ + if (bytes_sent != pkt_size) { + + return 0; + + } else { + + return 1; + } +} + +/*! + * gmbus_recv_pkt reads a block of data from specified i2c slave device + * + * @param slave_addr I2C device address + * @param index Starting i2c register index + * @param pkt_size 1 - 508 bytes + * @param pkt Bytes to send + * + * @return TRUE(1) if successful in receiving specified number of bytes + * @return FALSE(0) on failure + */ +static int gmbus_recv_pkt(unsigned long slave_addr, unsigned long index, + unsigned long pkt_size, void FAR *pkt) +{ + unsigned long gmbus1_cmd; + unsigned long bytes_rcvd; + unsigned long FAR *data; + + if ((pkt_size == 0) || (pkt == NULL) || (pkt_size > 508)) { + + return 0; + } + + data = (unsigned long FAR *)pkt; + + /*...................................................................... */ + gmbus_error_handler(); + + /* Program the command */ + gmbus1_cmd = gmbus_assemble_command(slave_addr, index, pkt_size, + STA | SW_RDY, I2C_READ); + WRITE_GMCH_REG(GMBUS1, gmbus1_cmd); + + /*...................................................................... */ + bytes_rcvd = 0; + do { + + unsigned long gmbus3_data; + unsigned long bytes_left = pkt_size - bytes_rcvd; + + if (! gmbus_wait_event_one(HW_RDY)) { + + OS_DEBUG("Error ! gmbus_recv_pkt : Failed to get HW_RDY, " + "bytes_rcvd=%ld", bytes_rcvd); + break; + } + + if (gmbus_error_handler()) { + + OS_DEBUG("Error ! gmbus_recv_pkt : gmbus error, bytes_rcvd=%ld", + bytes_rcvd); + break; + } + + gmbus3_data = READ_GMCH_REG(GMBUS3); + + switch (bytes_left) { + + case 1 : + *(unsigned char *)data = (unsigned char)gmbus3_data; + break; + + case 2 : + *(unsigned short *)data = (unsigned short)gmbus3_data; + break; + + case 3 : + { + unsigned char *dest = (unsigned char *)data; + unsigned char *src = (unsigned char *)&(gmbus3_data); + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + + break; + } + + default : /* >= 4 */ + *data = gmbus3_data; + break; + } + + if (bytes_left > 4) { + bytes_rcvd += 4; + data++; + + } else { + bytes_rcvd += bytes_left; + + } + + } while (bytes_rcvd < pkt_size); + + /*...................................................................... */ + if (bytes_rcvd < pkt_size) { + return 0; + + } else { + return 1; + } +} + +/*! + * gmbus_set_control_bus_switch sends sDVO command to switch i2c bus to read EDID + * or SPD data + * + * @param slave_addr sDVO device address (0x70/0x72) + * @param ddc_addr DDC1_ADDR/DDC2_ADDR + * + * @return TRUE(1) if successful in sending the opcode + * @return FALSE(0) on failure + */ +static int gmbus_set_control_bus_switch(unsigned long slave_addr, + gmbus_ddc_addr_t ddc_addr) +{ + unsigned char data; + sdvo_bus_switch_t bus_switch; + int retry; + + bus_switch = SDVO_BUS_DDC1; + + /*...................................................................... */ + /* Transmit the Arguments */ + if (! gmbus_send_pkt(slave_addr, SDVO_INDEX_PARAM_1, 1, &bus_switch)) { + + OS_DEBUG("Error ! gmbus_set_control_bus_switch : gmbus_send_pkt() failed"); + + return 0; + } + + /*...................................................................... */ + /* Generate I2C stop cycle */ + gmbus_wait_event_one(HW_WAIT); + WRITE_GMCH_REG(GMBUS1, STO | SW_RDY | slave_addr); + gmbus_wait_event_one(HW_RDY); + gmbus_wait_event_zero(GA); + + /*...................................................................... */ + /* Transmit the Opcode */ + data = SDVO_OPCODE_BUS_SWITCH; + if (! gmbus_send_pkt(slave_addr, SDVO_INDEX_OPCODE, 1, &data)) { + + OS_DEBUG("Error ! gmbus_set_control_bus_switch : gmbus_send_pkt(Opcode)" + " failed"); + + return 0; + } + + /*...................................................................... */ + /* Read Status */ + for (retry = 0; retry < 3; retry++) { + if (! gmbus_recv_pkt(slave_addr, SDVO_INDEX_STATUS, 1, &data)) { + + continue; + } + + if (data != SDVO_STATUS_PENDING) { + + break; + } + } + + /*...................................................................... */ + /* Send Stop */ + gmbus_wait_event_one(HW_WAIT); + WRITE_GMCH_REG(GMBUS1, STO | SW_RDY | slave_addr); + gmbus_wait_event_one(HW_RDY); + gmbus_wait_event_zero(GA); + + /*...................................................................... */ + if (data != SDVO_STATUS_SUCCESS) { + + OS_DEBUG("Error ! gmbus_set_control_bus_switch : Opcode Bus Switch failed"); + + return 0; + } + + return 1; +} + +/*! + * gmbus_read_edid reads specified number of Edid data bytes + * + * @param ddc_addr 0xA0/0xA2 (DDC1/DDC2) + * @param slave_addr 0x70/0x72 (sDVOB, sDVOC), 0 Analog + * @param index i2c register index + * @param num_bytes <= 508 + * @param buffer Edid data read from the display + * + * @return TRUE(1) if successful in reading Edid + * @return FALSE(0) on failure + */ +static int gmbus_read_edid(unsigned long ddc_addr, + unsigned long slave_addr, + unsigned long index, + unsigned long num_bytes, + unsigned char FAR *buffer) +{ + int status; + + if (slave_addr == SDVOB_ADDR) { + + if (! gmbus_set_control_bus_switch(slave_addr, ddc_addr)) { + + OS_DEBUG("Error ! gmbus_read_edid : gmbus_set_control_bus_switch()" + " failed"); + + return 0; + } + } else { + /* Reset the bus */ + gmbus_recv_pkt(ddc_addr, 0, 1, buffer); + } + + status = gmbus_recv_pkt(ddc_addr, index, num_bytes, buffer); + if (! status) { + + OS_DEBUG("Error ! gmbus_read_edid : gmbus_recv_pkt() failed"); + } + + /*...................................................................... */ + /* Issue a Stop Command */ + + gmbus_wait_event_one(HW_WAIT); + WRITE_GMCH_REG(GMBUS1, STO | SW_RDY | ddc_addr); + gmbus_wait_event_one(HW_RDY); + + gmbus_wait_event_zero(GA); + + gmbus_error_handler(); + WRITE_GMCH_REG(GMBUS1, SW_RDY); + WRITE_GMCH_REG(GMBUS1, SW_CLR_INT); + WRITE_GMCH_REG(GMBUS1, 0); + WRITE_GMCH_REG(GMBUS5, 0); + WRITE_GMCH_REG(GMBUS0, 0); + + /*...................................................................... */ + return status; +} + +/*! + * gmbus_read_reg reads one i2c register + * + * @param slave_addr 0x70/0x72 (sDVOB, sDVOC) + * @param index i2c register index + * @param data register data + * + * @return TRUE(1) if successful in reading the i2c register + * @return FALSE(0) on failure + */ +static int gmbus_read_reg(unsigned long slave_addr, + unsigned long index, + unsigned char FAR *data) +{ + unsigned long gmbus1_cmd; + + WRITE_GMCH_REG(GMBUS5, 0x0); /* Clear Word Index register */ + + if (! gmbus_wait_event_zero(GA)) { + + OS_DEBUG("Error ! gmbus_read_reg : Failed to get GA(1)"); + + return 0; + } + + gmbus1_cmd = gmbus_assemble_command(slave_addr, index, 1, + STO | STA, I2C_READ); + WRITE_GMCH_REG(GMBUS1, gmbus1_cmd); + + if (! gmbus_wait_event_zero(GA)) { + + OS_DEBUG("Error ! gmbus_read_reg : Failed to get GA(2)"); + + return 0; + } + + *data = (unsigned char)READ_GMCH_REG(GMBUS3); + + return 1; +} + +/*! + * gmbus_write_reg writes one i2c register + * + * @param slave_addr 0x70/0x72 (sDVOB, sDVOC) + * @param index i2c register index + * @param data register data + * + * @return TRUE(1) if successful in updating the i2c register + * @return FALSE(0) if failed to update the register + */ +static int gmbus_write_reg(unsigned long slave_addr, + unsigned long index, + unsigned char data) +{ + unsigned long gmbus1_cmd; + + WRITE_GMCH_REG(GMBUS5, 0x0); /* Clear Word Index register */ + + if (! gmbus_wait_event_zero(GA)) { + + OS_DEBUG("Error ! gmbus_write_reg : Failed to get GA(1)"); + + return 0; + } + + WRITE_GMCH_REG(GMBUS3, data); + + gmbus1_cmd = gmbus_assemble_command(slave_addr, index, 1, + STO | STA, I2C_WRITE); + WRITE_GMCH_REG(GMBUS1, gmbus1_cmd); + + if (! gmbus_wait_event_zero(GA)) { + + OS_DEBUG("Error ! gmbus_write_reg : Failed to get GA(2)"); + return 0; + } + + return 1; +} + +/*---------------------------------------------------------------------------- + * File Revision History + * $Id: i2c_gmbus_tnc.c,v 1.6 2010/04/27 20:33:49 bpaauwe Exp $ + * $Source: /nfs/fm/proj/eia/cvsroot/koheo/linux/egd_drm/emgd/display/pi/tnc/i2c_gmbus_tnc.c,v $ + *---------------------------------------------------------------------------- + */ diff --git a/drivers/gpu/drm/emgd/emgd/drm/drm_emgd_private.h b/drivers/gpu/drm/emgd/emgd/drm/drm_emgd_private.h new file mode 100644 index 0000000..d29c6ba --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/drm/drm_emgd_private.h @@ -0,0 +1,138 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: drm_emgd_private.h + * $Revision: 1.14 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * This file contains the EMGD-specific drm_device.dev_private structure, + * which is used to share data with the EMGD-specific, IMG 3rd-Party Display + * Driver (3DD, implimented in the + * "egd_drm/pvr/services4/3rdparty/emgd_displayclass" directory). + *----------------------------------------------------------------------------- + */ +#ifndef _DRM_EMGD_PRIVATE_H_ +#define _DRM_EMGD_PRIVATE_H_ + +#include +#include +#include "context.h" + + + +/** + * This enum is used to record the currently-saved register state (e.g. for VT + * switching)--either the Linux console's state is saved (i.e. the X server is + * active), or the X server's state is saved (i.e. the Linux console is + * active). + */ +typedef enum _drm_emgd_saved_state { + CONSOLE_STATE_SAVED = 0, + X_SERVER_STATE_SAVED = 1, +} drm_emgd_saved_state; + + +/** + * This structure allows the EMGD-proper code to communicate information and + * function pointers to the IMG 3rd-Party Display Driver (mrstlfb). + */ +typedef struct _drm_emgd_private { + /** Non-zero if the HAL is running */ + int hal_running; + + /** + * Which register state is currently saved for VT switches (X or the + * console; note: the opposite is what's actively installed in the + * hardware) + */ + drm_emgd_saved_state saved_registers; + + /** + * Saved state of the console, when suspending (or hibernating) the system. + * emgd_driver_suspend() allocates this, and emgd_driver_resume() frees + * this. + */ + void *suspended_state; + + /** + * A flag which emgd_driver_pre_init() sets and emgd_alter_displays() + * clears. If set (i.e. to 1), this indicates that emgd_alter_displays() + * must power on the port drivers' hardware. + */ + int must_power_on_ports; + + /** Non-zero if the X server is running (i.e. PVR can't do mode changes) */ + int xserver_running; + + /** Non-zero if emgd_start_pvrsrv() started the PVR services, else zero. */ + int pvrsrv_started; + + /** + * Function to re-initialize the 3DD's data structures, after calls to + * alter_displays() + */ + int (*reinit_3dd)(struct drm_device *dev); + + + /** The context is set during the DRM module load function. */ + igd_context_t *context; + + /* The selected DC is copied to here each time alter_displays() is called + * via an ioctl. + */ + unsigned long dc; + + /** + * The port number of the primary display handle is copied to here each + * time alter_displays() is called via an ioctl. + */ + unsigned short primary_port_number; + + /** + * The primary display handle is copied to here each time alter_displays() + * is called via an ioctl. + */ + igd_display_h primary; + + /** + * The port number of the secondary display handle is copied to here each + * time alter_displays() is called via an ioctl. + */ + unsigned short secondary_port_number; + + /** + * The secondary display handle is copied to here each time alter_displays() + * is called via an ioctl. + */ + igd_display_h secondary; + + /** + * Store the device information so it can be passed back to userspace + * callers via an ioctl. + */ + igd_init_info_t *init_info; + + + /** TODO: May use this in future. + * MSVDX + */ + void *msvdx_private; + + +} drm_emgd_private; + +#endif diff --git a/drivers/gpu/drm/emgd/emgd/drm/emgd_drv.c b/drivers/gpu/drm/emgd/emgd/drm/emgd_drv.c new file mode 100644 index 0000000..1330c89 --- /dev/null +++ b/drivers/gpu/drm/emgd/emgd/drm/emgd_drv.c @@ -0,0 +1,1725 @@ +/* -*- pse-c -*- + *----------------------------------------------------------------------------- + * Filename: emgd_drv.c + * $Revision: 1.106 $ + *----------------------------------------------------------------------------- + * Copyright © 2002-2010, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + *----------------------------------------------------------------------------- + * Description: + * The main part of the kernel module. This part gets everything going and + * connected, and then the rest can function. + *----------------------------------------------------------------------------- + */ + +#define MODULE_NAME hal.oal + +#include +#include +#include "drm_emgd_private.h" +#include "user_config.h" +#include "emgd_drv.h" +#include "emgd_drm.h" +#include "memory.h" +#include "io.h" +#include "mode_dispatch.h" + +/* + * Imagination includes. + */ +#include +#include +#include +#include +#include + +extern void emgd_set_real_handle(igd_driver_h drm_handle); +extern void emgd_set_real_dispatch(igd_dispatch_t *drm_dispatch); +extern void emgd_ms_init(struct drm_device *dev); +extern int msvdx_pre_init_plb(struct drm_device *dev); +extern emgd_drm_config_t config_drm; + + +int drm_emgd_debug = 0xFFFF; +EXPORT_SYMBOL(drm_emgd_debug); + +MODULE_PARM_DESC(debug, "Enable debug output"); +module_param_named(debug, drm_emgd_debug, int, 0600); + + +/* Note: The following module paramter values are advertised to the root user, + * via the files in the /sys/module/emgd/parameters directory (e.g. the "init" + * file contains the value of the "init" module parameter), and so we keep + * these values up to date. + * + * Note: The initial values are all set to -1, so that we can tell if the user + * set them. + */ +int drm_emgd_portorder[IGD_MAX_PORTS] = {-1, -1, -1, -1, -1}; +int drm_emgd_numports; +int drm_emgd_configid = -1; +int drm_emgd_init = -1; +int drm_emgd_dc = -1; +int drm_emgd_width = -1; +int drm_emgd_height = -1; +int drm_emgd_refresh = -1; +MODULE_PARM_DESC(portorder, "Display port order (e.g. \"4,2,0,0,0\")"); +MODULE_PARM_DESC(configid, "Which defined configuration number to use (e.g. " + "\"1\")"); +MODULE_PARM_DESC(init, "Whether to initialize the display at startup (1=yes, " + "0=no)"); +MODULE_PARM_DESC(dc, "Display configuration (i.e. 1=single, 2=clone)"); +MODULE_PARM_DESC(width, "Display resolution's width (e.g. \"1024\")"); +MODULE_PARM_DESC(height, "Display resolution's height (e.g. \"768\")"); +MODULE_PARM_DESC(refresh, "Monitor refresh rate (e.g. 60, as in 60Hz)"); +module_param_array_named(portorder, drm_emgd_portorder, int, &drm_emgd_numports, + 0600); +module_param_named(configid, drm_emgd_configid, int, 0600); +module_param_named(init, drm_emgd_init, int, 0600); +module_param_named(dc, drm_emgd_dc, int, 0600); +module_param_named(width, drm_emgd_width, int, 0600); +module_param_named(height, drm_emgd_height, int, 0600); +module_param_named(refresh, drm_emgd_refresh, int, 0600); + + +/** The DC to use when the DRM module [re-]initializes the display. */ +static unsigned long *desired_dc = NULL; +/** The DC to use when the DRM module [re-]initializes the display. */ +static unsigned short port_number = 0; +/** The mode to use when the DRM module [re-]initializes the display. */ +static igd_display_info_t *desired_mode = NULL; +/** + * The primary fb_info to use when the DRM module [re-]initializes the display. + */ +igd_framebuffer_info_t primary_fb_info; +/** + * The secondary fb_info to use when the DRM module [re-]initializes the + * display. + */ +igd_framebuffer_info_t secondary_fb_info; +/** + * The primary display structure (filled in by alter_displays()) to use when + * the DRM module [re-]initializes the display. + */ +igd_display_h primary; +/** + * The secondary display structure (filled in by alter_displays()) to use when + * the DRM module [re-]initializes the display. + */ +igd_display_h secondary; +/** + * The display information to use when the DRM module [re-]initializes the + * display. + */ +igd_display_info_t pt_info; +extern mode_context_t mode_context[1]; + +/* Note: This macro is #define'd in "oal/os/memory.h" */ +#ifdef INSTRUMENT_KERNEL_ALLOCS +os_allocd_mem *list_head = NULL; +os_allocd_mem *list_tail = NULL; +#endif + + +#define emgd_PCI_IDS \ + {0x8086, 0x8108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PSB_8108}, \ + {0x8086, 0x8109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PSB_8109}, \ + {0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TC_4108}, \ + {0, 0, 0} + +static struct pci_device_id pciidlist[] = { + emgd_PCI_IDS +}; + +/* + * To use DRM_IOCTL_DEF, the first arg should be the local (zero based) + * IOCTL number, not the global number. + */ +#define EMGD_IOCTL_DEF(ioctl, _func, _flags) \ + [DRM_IOCTL_NR(ioctl) - DRM_COMMAND_BASE] = \ + {.cmd = ioctl, .func = _func, .flags = _flags} + +static struct drm_ioctl_desc emgd_ioctl[] = { + /* NOTE: The "DRM_ROOT_ONLY" flag value (last parameter) below indicates + * that the ioctl will only work for "root" (super-user) processes (e.g. X + * server). We don't use the other flag values, because we only want these + * ioctls to be used by the X driver code, running within the X server. + */ + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_ALTER_CURSOR, emgd_alter_cursor, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_ALTER_CURSOR_POS, emgd_alter_cursor_pos, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_ALTER_DISPLAYS, emgd_alter_displays, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_ALTER_OVL, emgd_alter_ovl, DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_ALTER_OVL2, emgd_alter_ovl2, DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_APPCTX_ALLOC, emgd_appcontext_alloc, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_APPCTX_FREE, emgd_appcontext_free, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_DRIVER_SAVE_RESTORE, emgd_driver_save_restore, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_ENABLE_PORT, emgd_enable_port, DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_GET_ATTRS, emgd_get_attrs, DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_GET_DISPLAY, emgd_get_display, DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_GET_DRM_CONFIG, emgd_get_drm_config, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_GET_EDID_BLOCK, emgd_get_EDID_block, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_GET_EDID_INFO, emgd_get_EDID_info, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_GET_PIXELFORMATS, emgd_get_pixelformats, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_GET_PORT_INFO, emgd_get_port_info, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_GMM_ALLOC_REGION, emgd_gmm_alloc_region, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_GMM_ALLOC_SURFACE, emgd_gmm_alloc_surface, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_GMM_FREE, emgd_gmm_free, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_GMM_FLUSH_CACHE, emgd_gmm_flush_cache, + DRM_ROOT_ONLY), + /* + * Externally handled IOCTL's. These are routed to the Imagination Tech + * kernel services. + * function prototypes in services4/srvkm/env/linux/pvr_drm.h + */ + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_RESERVED_1, PVRSRV_BridgeDispatchKM, 0), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_RESERVED_2, PVRDRM_Dummy_ioctl, 0), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_RESERVED_3, PVRDRM_Dummy_ioctl, 0), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_RESERVED_4, PVRDRMIsMaster, DRM_MASTER), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_RESERVED_5, PVRDRMUnprivCmd, 0), + + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_PAN_DISPLAY, emgd_pan_display, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_POWER_DISPLAY, emgd_power_display, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_PWR_ALTER, emgd_pwr_alter, DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_QUERY_DC, emgd_query_dc, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_QUERY_MAX_SIZE_OVL, emgd_query_max_size_ovl, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_QUERY_OVL, emgd_query_ovl, DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_QUERY_MODE_LIST, emgd_query_mode_list, + DRM_ROOT_ONLY), + /* + * For PDUMP + */ +#if defined(PDUMP) + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_RESERVED_6, dbgdrv_ioctl, 0), +#else + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_RESERVED_6, NULL, 0), +#endif + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_SET_ATTRS, emgd_set_attrs, DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_SET_PALETTE_ENTRY, emgd_set_palette_entry, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_SET_SURFACE, emgd_set_surface, DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_SYNC, emgd_sync, DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_DRIVER_PRE_INIT, emgd_driver_pre_init, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_DRIVER_GET_PORTS, emgd_driver_get_ports, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_GET_OVL_INIT_PARAMS, emgd_get_ovl_init_params, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_GET_PAGE_LIST, emgd_get_page_list, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_START_PVRSRV, emgd_start_pvrsrv, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_TEST_PVRSRV, emgd_test_pvrsrv, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_GET_CHIPSET_INFO, emgd_get_chipset_info, + DRM_ROOT_ONLY), + + + /* + * For VIDEO (MSVDX/TOPAZ + */ + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_VIDEO_CMD_BUF, emgd_video_cmd_buf, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_INIT_VIDEO, emgd_init_video, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_GET_DEVICE_INFO, emgd_get_device_info, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_VIDEO_GET_INFO, emgd_video_get_info, + DRM_ROOT_ONLY), + EMGD_IOCTL_DEF(DRM_IOCTL_IGD_VIDEO_FLUSH_TLB, emgd_video_flush_tlb, + DRM_ROOT_ONLY), +}; + +static int emgd_max_ioctl = DRM_ARRAY_SIZE(emgd_ioctl); + + + +/* + * NOTE: The next part of this file are EMGD-specific DRM functions, exported to + * the generic DRM code via the drm_driver struct: + */ + + +extern igd_driver_h handle; +/** This is the dispatch table for the HAL. It is cached for quick access. */ +extern igd_dispatch_t *dispatch; + + +/** + * The driver handle for talking with the HAL, within the DRM/kernel code. + * + * This is a "real handle" as opposed to the "fake handle" in user-space. + * Notice that there's only one handle, as the secondary device shares this + * handle. + */ +static igd_driver_h drm_HAL_handle = NULL; + +/** + * This is the drm_HAL_handle cast to an igd_context_t. It is cached for quick + * access. + */ +static igd_context_t *drm_HAL_context = NULL; + +/** + * This is the dispatch table for the HAL. It is cached for quick access. + */ +static igd_dispatch_t *drm_HAL_dispatch = NULL; + + +/** + * A helper function that prints the igd_param_t struct. + * + * @param params (IN) The the igd_param_t struct to print + */ +void emgd_print_params(igd_param_t *params) +{ + int i; + + OS_DEBUG("Values of params:"); + OS_DEBUG(" page_request = %lu = 0x%lx", params->page_request, + params->page_request); + OS_DEBUG(" max_fb_size = %lu = 0x%lx", params->max_fb_size, + params->max_fb_size); + OS_DEBUG(" preserve_regs = %u", params->preserve_regs); + OS_DEBUG(" display_flags = %lu = 0x%lx", params->display_flags, + params->display_flags); + OS_DEBUG(" port_order:"); + for (i = 0 ; i < IGD_MAX_PORTS; i++) { + OS_DEBUG(" port number %d = %lu", i, params->port_order[i]); + } + OS_DEBUG(" display_params:"); + for (i = 0 ; i < IGD_MAX_PORTS; i++) { + int j; + + OS_DEBUG(" port_number = %lu", params->display_params[i].port_number); + OS_DEBUG(" present_params = %lu = 0x%lx", + params->display_params[i].present_params, + params->display_params[i].present_params); + OS_DEBUG(" flags = %lu = 0x%lx", + params->display_params[i].flags, + params->display_params[i].flags); + OS_DEBUG(" edid_avail = %u = 0x%x", + params->display_params[i].edid_avail, + params->display_params[i].edid_avail); + OS_DEBUG(" edid_not_avail = %u = 0x%x", + params->display_params[i].edid_not_avail, + params->display_params[i].edid_not_avail); + OS_DEBUG(" ddc_gpio = %lu", params->display_params[i].ddc_gpio); + OS_DEBUG(" ddc_speed = %lu", params->display_params[i].ddc_speed); + OS_DEBUG(" ddc_dab = %lu", params->display_params[i].ddc_dab); + OS_DEBUG(" i2c_gpio = %lu", params->display_params[i].i2c_gpio); + OS_DEBUG(" i2c_speed = %lu", params->display_params[i].i2c_speed); + OS_DEBUG(" i2c_dab = %lu", params->display_params[i].i2c_dab); + OS_DEBUG(" fp_info.fp_width = %lu", + params->display_params[i].fp_info.fp_width); + OS_DEBUG(" fp_info.fp_height = %lu", + params->display_params[i].fp_info.fp_height); + OS_DEBUG(" fp_info.fp_pwr_method = %lu", + params->display_params[i].fp_info.fp_pwr_method); + OS_DEBUG(" fp_info.fp_pwr_t1 = %lu", + params->display_params[i].fp_info.fp_pwr_t1); + OS_DEBUG(" fp_info.fp_pwr_t2 = %lu", + params->display_params[i].fp_info.fp_pwr_t2); + OS_DEBUG(" fp_info.fp_pwr_t3 = %lu", + params->display_params[i].fp_info.fp_pwr_t3); + OS_DEBUG(" fp_info.fp_pwr_t4 = %lu", + params->display_params[i].fp_info.fp_pwr_t4); + OS_DEBUG(" fp_info.fp_pwr_t5 = %lu", + params->display_params[i].fp_info.fp_pwr_t5); + OS_DEBUG(" dtd_list:"); + OS_DEBUG(" num_dtds = %lu", + params->display_params[i].dtd_list.num_dtds); + for (j = 0 ; j < params->display_params[i].dtd_list.num_dtds; j++) { + OS_DEBUG(" *dtd[%d].width = %u", j, + params->display_params[i].dtd_list.dtd[j].width); + OS_DEBUG(" dtd[%d].height = %u", j, + params->display_params[i].dtd_list.dtd[j].height); + OS_DEBUG(" dtd[%d].refresh = %u", j, + params->display_params[i].dtd_list.dtd[j].refresh); + OS_DEBUG(" dtd[%d].dclk = %lu = 0x%lx", j, + params->display_params[i].dtd_list.dtd[j].dclk, + params->display_params[i].dtd_list.dtd[j].dclk); + OS_DEBUG(" dtd[%d].htotal = %u", j, + params->display_params[i].dtd_list.dtd[j].htotal); + OS_DEBUG(" dtd[%d].hblank_start = %u", j, + params->display_params[i].dtd_list.dtd[j].hblank_start); + OS_DEBUG(" dtd[%d].hblank_end = %u", j, + params->display_params[i].dtd_list.dtd[j].hblank_end); + OS_DEBUG(" dtd[%d].hsync_start = %u", j, + params->display_params[i].dtd_list.dtd[j].hsync_start); + OS_DEBUG(" dtd[%d].hsync_end = %u", j, + params->display_params[i].dtd_list.dtd[j].hsync_end); + OS_DEBUG(" dtd[%d].vtotal = %u", j, + params->display_params[i].dtd_list.dtd[j].vtotal); + OS_DEBUG(" dtd[%d].vblank_start = %u", j, + params->display_params[i].dtd_list.dtd[j].vblank_start); + OS_DEBUG(" dtd[%d].vblank_end = %u", j, + params->display_params[i].dtd_list.dtd[j].vblank_end); + OS_DEBUG(" dtd[%d].vsync_start = %u", j, + params->display_params[i].dtd_list.dtd[j].vsync_start); + OS_DEBUG(" dtd[%d].vsync_end = %u", j, + params->display_params[i].dtd_list.dtd[j].vsync_end); + OS_DEBUG(" dtd[%d].mode_number = %d", j, + params->display_params[i].dtd_list.dtd[j].mode_number); + OS_DEBUG(" dtd[%d].flags = %lu = 0x%lx", j, + params->display_params[i].dtd_list.dtd[j].flags, + params->display_params[i].dtd_list.dtd[j].flags); + OS_DEBUG(" dtd[%d].x_offset = %u", j, + params->display_params[i].dtd_list.dtd[j].x_offset); + OS_DEBUG(" dtd[%d].y_offset = %u", j, + params->display_params[i].dtd_list.dtd[j].y_offset); + OS_DEBUG(" dtd[%d].pd_private_ptr = 0x%p", j, + params->display_params[i].dtd_list.dtd[j].pd_private_ptr); + OS_DEBUG(" dtd[%d].private_ptr = 0x%p", j, + params->display_params[i].dtd_list.dtd[j].private_ptr); + } + OS_DEBUG(" attr_list:"); + OS_DEBUG(" num_attrs = %lu", + params->display_params[i].attr_list.num_attrs); + for (j = 0 ; j < params->display_params[i].attr_list.num_attrs; j++) { + OS_DEBUG(" attr[%d].id = %lu = 0x%lx", j, + params->display_params[i].attr_list.attr[j].id, + params->display_params[i].attr_list.attr[j].id); + OS_DEBUG(" attr[%d].value = %lu = 0x%lx", j, + params->display_params[i].attr_list.attr[j].value, + params->display_params[i].attr_list.attr[j].value); + } + } + OS_DEBUG(" display_color = %lu = 0x%lx", params->display_color, + params->display_color); + OS_DEBUG(" quickboot = %lu", params->quickboot); + OS_DEBUG(" qb_seamless = %d", params->qb_seamless); + OS_DEBUG(" qb_video_input = %lu", params->qb_video_input); + OS_DEBUG(" qb_splash = %d", params->qb_splash); + OS_DEBUG(" polling = %d", params->polling); +} /* emgd_print_params() */ + + +/** + * A helper function that starts, initializes and configures the HAL. This + * will be called during emgd_driver_load() if the display is to be initialized + * at module load time. Otherwise, this is deferred till the X driver loads + * and calls emgd_driver_pre_init(). + * + * @param dev (IN) DRM per-device (e.g. one GMA) struct (in "drmP.h"). + * @param params (IN) The the igd_param_t struct to give to the HAL. + * + * @return 0 on Success + * @return <0 on Error + */ +int emgd_startup_hal(struct drm_device *dev, igd_param_t *params) +{ + drm_emgd_private *priv = dev->dev_private; + int err = 0; + + EMGD_DRM_TRACE_ENTER; + + + /* Initialize the various HAL modules: */ + OS_DEBUG("Calling igd_module_init()"); + err = igd_module_init(drm_HAL_handle, &drm_HAL_dispatch, params); + if (err != 0) { + return -EIO; + } + + /* Give the dispatch table to the ioctl-handling "bridge" code: */ + emgd_set_real_dispatch(drm_HAL_dispatch); + + /* Hook up the drm framebuffer */ + OS_DEBUG("Calling emgd_ms_init()"); + emgd_ms_init(dev); + + /* Record that the HAL is running now: */ + priv->hal_running = 1; + /* Record that the console's state is saved: */ + priv->saved_registers = CONSOLE_STATE_SAVED; + + + EMGD_DRM_TRACE_EXIT; + + return 0; +} /* emgd_startup_hal() */ + + +/** + * A helper function that initializes the display, and potentially merges the + * module parameters with the pre-compiled parameters. + * + * @param merge_mod_params (IN) non-zero if the module parameters should be + * merged with the pre-compiled parameters. + * + */ +void emgd_init_display(int merge_mod_params) +{ + int err = 0; + igd_display_info_t *mode_list = NULL; + igd_display_info_t *mode = NULL; + int mode_flags = IGD_QUERY_LIVE_MODES; + + + EMGD_DRM_TRACE_ENTER; + + + if (merge_mod_params) { + OS_DEBUG("Checking other module parameters before initializing the " + "display"); + + /************************************* + * Get the desired display display config: + *************************************/ + if (-1 != drm_emgd_dc) { + /* Validate and potentially use the module parameter: */ + OS_DEBUG("Value of module parameter \"dc\" = \"%d\"", drm_emgd_dc); + if ((drm_emgd_dc == 1) || (drm_emgd_dc == 2) || + (drm_emgd_dc == 8)) { + /* Use validated value to override compile-time value: */ + config_drm.dc = drm_emgd_dc; + } else if (drm_emgd_dc == 4) { + /* Use validated value to override compile-time value: */ + OS_DEBUG("Module parameter \"dc\" contains unsupported value " + "%d.", drm_emgd_dc); + OS_DEBUG("Overriding and making it 1 (single display)."); + drm_emgd_dc = 1; + config_drm.dc = drm_emgd_dc; + } else { + /* Use compile-time value: */ + EMGD_DRM_ERROR("Module parameter \"dc\" contains invalid value " + "%d (must be 1, 2, or 8).", drm_emgd_dc); + if (config_drm.dc == 4) { + OS_DEBUG("Compile-time setting for module parameter " + "\"dc\" contains unsupported value %d.", config_drm.dc); + OS_DEBUG("Overriding and making it 1 (single display)."); + config_drm.dc = 1; + } else { + EMGD_DRM_ERROR("Will use compile-time setting %d instead " + "of invalid value %d.\n", config_drm.dc, drm_emgd_dc); + } + drm_emgd_dc = config_drm.dc; + } + } else { + /* Check and potentially use the compile-time value: */ + if ((config_drm.dc == 1) || (config_drm.dc == 2) || + (config_drm.dc == 8)) { + /* Report the compile-time value: */ + OS_DEBUG("Using compile-time setting for the module parameter " + "\"dc\" = \"%d\"", config_drm.dc); + } else if (config_drm.dc == 4) { + OS_DEBUG("Compile-time setting for module parameter " + "\"dc\" contains unsupported value %d.", config_drm.dc); + OS_DEBUG("Overriding and making it 1 (single display)."); + config_drm.dc = 1; + } else { + OS_DEBUG("Compile-time setting for module parameter " + "\"dc\" contains invalid value %d.", config_drm.dc); + OS_DEBUG("Must be 1, 2, or 8. Making it 1 (single display)."); + config_drm.dc = 1; + } + drm_emgd_dc = config_drm.dc; + } + } + + /************************************* + * Query the DC list (use first one): + *************************************/ + OS_DEBUG("Calling query_dc()"); + err = drm_HAL_dispatch->query_dc(drm_HAL_handle, drm_emgd_dc, + &desired_dc, IGD_QUERY_DC_INIT); + OS_DEBUG("query_dc() returned %d", err); + if (err) { + EMGD_DRM_ERROR_EXIT("Cannot initialize the display as requested.\n" + "The query_dc() function returned %d.", err); + return; + } + port_number = (*desired_dc & 0xf0) >> 4; + OS_DEBUG("Using DC 0x%lx with port number %d", + *desired_dc, port_number); + + /************************************* + * Query the mode list: + *************************************/ + OS_DEBUG("Calling query_mode_list()"); + err = drm_HAL_dispatch->query_mode_list(drm_HAL_handle, *desired_dc, + &mode_list, mode_flags); + OS_DEBUG("query_mode_list() returned %d", err); + if (err) { + EMGD_DRM_ERROR_EXIT("Cannot initialize the display as requested\n" + "The query_mode_list() function returned %d.", err); + return; + } + + if (merge_mod_params) { + /************************************* + * Get the desired display "width": + *************************************/ + if (-1 != drm_emgd_width) { + /* Override the compile-time value with the module parameter: */ + OS_DEBUG("Using the \"width\" module parameter: \"%d\"", + drm_emgd_width); + config_drm.width = drm_emgd_width; + } else { + /* Use the compile-time value: */ + drm_emgd_width = config_drm.width; + OS_DEBUG("Using the compile-time \"width\" value: \"%d\"", + drm_emgd_width); + } + + /************************************* + * Get the desired display "height": + *************************************/ + if (-1 != drm_emgd_height) { + /* Override the compile-time value with the module parameter: */ + OS_DEBUG("Using the \"height\" module parameter: \"%d\"", + drm_emgd_height); + config_drm.height = drm_emgd_height; + } else { + /* Use the compile-time value: */ + drm_emgd_height = config_drm.height; + OS_DEBUG("Using the compile-time \"height\" value: \"%d\"", + drm_emgd_height); + } + + /************************************* + * Get the desired display "refresh": + *************************************/ + if (-1 != drm_emgd_refresh) { + /* Override the compile-time value with the module parameter: */ + OS_DEBUG("Using the \"refresh\" module parameter: \"%d\"", + drm_emgd_refresh); + config_drm.refresh = drm_emgd_refresh; + } else { + /* Use the compile-time value: */ + drm_emgd_refresh = config_drm.refresh; + OS_DEBUG("Using the compile-time \"refresh\" value: \"%d\"", + drm_emgd_refresh); + } + } + + /************************************* + * Find the desired mode from the list: + *************************************/ + OS_DEBUG("Comparing the mode list with the desired width, height, and " + "refresh rate..."); + mode = mode_list; + while (mode && (mode->width != IGD_TIMING_TABLE_END)) { + OS_DEBUG(" ... Found a mode with width=%d, height=%d, refresh=%d;", + mode->width, mode->height, mode->refresh); + if ((mode->width == drm_emgd_width) && + (mode->height == drm_emgd_height) && + (mode->refresh == drm_emgd_refresh)) { + OS_DEBUG(" ... This mode is a match!"); + desired_mode = mode; + break; + } + mode++; + } + if (NULL == desired_mode) { + EMGD_DRM_ERROR("Cannot initialize the display as requested."); + EMGD_DRM_ERROR("No mode matching the desired width (%d), height " + "(%d), and refresh rate (%d) was found.", + drm_emgd_width, drm_emgd_height, drm_emgd_refresh); + return; + } else { + /* Must set this in order to get the timings setup: */ + desired_mode->flags |= IGD_DISPLAY_ENABLE; + } + + /************************************* + * Call alter_displays(): + *************************************/ + primary_fb_info.width = desired_mode->width; + primary_fb_info.height = desired_mode->height; + primary_fb_info.pixel_format = IGD_PF_ARGB32; + primary_fb_info.flags = 0; + primary_fb_info.allocated = 0; + memcpy(&secondary_fb_info, &primary_fb_info, + sizeof(igd_framebuffer_info_t)); + + OS_DEBUG("Calling alter_displays()"); + err = drm_HAL_dispatch->alter_displays(drm_HAL_handle, + &primary, desired_mode, &primary_fb_info, + &secondary, desired_mode, &secondary_fb_info, + *desired_dc, 0); + OS_DEBUG("alter_displays() returned %d", err); + if (err) { + EMGD_DRM_ERROR_EXIT("Cannot initialize the display as requested.\n" + "The alter_displays() function returned %d.", err); + return; + } + + /************************************* + * Call get_display(): + *************************************/ + OS_DEBUG("Calling get_display()"); + err = drm_HAL_dispatch->get_display(primary, port_number, + &primary_fb_info, &pt_info, 0); + OS_DEBUG("get_display() returned %d", err); + if (err) { + EMGD_DRM_ERROR_EXIT("Cannot initialize the display as requested\n" + "The get_display() function returned %d.", err); + return; + } + + /************************************* + * Set the framebuffer to the background color: + *************************************/ + OS_DEBUG("Calling full_clear_fb()"); + full_clear_fb(mode_context, &primary_fb_info); + + /************************************* + * Display a splash screen if requested by user + *************************************/ + if(config_drm.ss_data->width && + config_drm.ss_data->height) { + + /* Display a splash screen */ + OS_DEBUG("Calling disp_splash_screen()"); + disp_splash_screen(config_drm.ss_data); + } + + /************************************* + * Display a splash video if requested by user + *************************************/ + if(config_drm.sv_data->pixel_format && + config_drm.sv_data->src_width && + config_drm.sv_data->src_height && + config_drm.sv_data->src_pitch && + config_drm.sv_data->dst_width && + config_drm.sv_data->dst_height) { + + /* Display a splash video */ + OS_DEBUG("Calling disp_splash_video()"); + disp_splash_video(config_drm.sv_data); + } + + EMGD_DRM_TRACE_EXIT; +} /* emgd_init_display() */ + + +/** + * Function to display a splash screen to the user. The splash screen must be + * accessible to the kernel mode driver as it has to be displayed immediately + * after setting the mode (if requested by the user through config options). + * + * @param ss_data (IN) a non null pointer to splash screen information like + * width, height etc. + * + * @return 0 on Success + * @return <0 on Error + */ +int disp_splash_screen(emgd_drm_splash_screen_t *ss_data) +{ + + return 0; +} + +/** + * Function to display a splash video to the user. The splash video data must be + * provided to the kernel mode driver by another entity (like a driver or FPGA + * HW). Splash video will be display after setting the mode (if requested by + * the user through config options). + * + * @param sv_data (IN) a non null pointer to splash video information like + * width, height etc. + * + * @return 0 on Success + * @return <0 on Error + */ +int disp_splash_video(emgd_drm_splash_video_t *sv_data) +{ + igd_surface_t surface; + igd_rect_t ovl_rect, surf_rect; + igd_ovl_info_t ovl_info; + unsigned int tmp; + + surface.offset = sv_data->offset; + surface.pitch = sv_data->src_pitch; + surface.width = s