From ea83ad971e877ef8e9b1304f2678469c2fc74c67 Mon Sep 17 00:00:00 2001 From: Tim Yamin Date: Sun, 26 Apr 2009 18:58:30 -0700 Subject: [PATCH] Merge in tidspbridge from git://gitorious.org/tidspbridge/mainline.git revisions fe30e75..20f5ca. Made a few changes so this compiles clean against a 2.6.29 non-PM tree. Signed-off-by: Tim Yamin --- Documentation/tidspbridge/README | 70 + arch/arm/Kconfig | 2 + arch/arm/mach-omap2/Makefile | 2 + arch/arm/mach-omap2/dspbridge.c | 74 + arch/arm/mach-omap2/io.c | 3 + arch/arm/plat-omap/devices.c | 28 + arch/arm/plat-omap/include/dspbridge/_chnl_sm.h | 212 ++ arch/arm/plat-omap/include/dspbridge/_dcd.h | 187 + arch/arm/plat-omap/include/dspbridge/brddefs.h | 54 + arch/arm/plat-omap/include/dspbridge/cfg.h | 339 ++ arch/arm/plat-omap/include/dspbridge/cfgdefs.h | 126 + arch/arm/plat-omap/include/dspbridge/chnl.h | 170 + arch/arm/plat-omap/include/dspbridge/chnl_sm.h | 168 + arch/arm/plat-omap/include/dspbridge/chnldefs.h | 92 + arch/arm/plat-omap/include/dspbridge/chnlpriv.h | 136 + arch/arm/plat-omap/include/dspbridge/clk.h | 155 + arch/arm/plat-omap/include/dspbridge/cmm.h | 420 +++ arch/arm/plat-omap/include/dspbridge/cmmdefs.h | 135 + arch/arm/plat-omap/include/dspbridge/cod.h | 433 +++ arch/arm/plat-omap/include/dspbridge/csl.h | 135 + arch/arm/plat-omap/include/dspbridge/dbc.h | 66 + arch/arm/plat-omap/include/dspbridge/dbdcd.h | 388 +++ arch/arm/plat-omap/include/dspbridge/dbdcddef.h | 94 + arch/arm/plat-omap/include/dspbridge/dbdefs.h | 580 ++++ arch/arm/plat-omap/include/dspbridge/dbg.h | 110 + arch/arm/plat-omap/include/dspbridge/dbl.h | 354 ++ arch/arm/plat-omap/include/dspbridge/dbldefs.h | 155 + arch/arm/plat-omap/include/dspbridge/dbll.h | 70 + arch/arm/plat-omap/include/dspbridge/dblldefs.h | 509 +++ arch/arm/plat-omap/include/dspbridge/dbof.h | 117 + arch/arm/plat-omap/include/dspbridge/dbreg.h | 113 + arch/arm/plat-omap/include/dspbridge/dbtype.h | 103 + arch/arm/plat-omap/include/dspbridge/dehdefs.h | 42 + arch/arm/plat-omap/include/dspbridge/dev.h | 785 +++++ arch/arm/plat-omap/include/dspbridge/devdefs.h | 35 + arch/arm/plat-omap/include/dspbridge/disp.h | 236 ++ arch/arm/plat-omap/include/dspbridge/dispdefs.h | 45 + arch/arm/plat-omap/include/dspbridge/dmm.h | 85 + arch/arm/plat-omap/include/dspbridge/dpc.h | 167 + arch/arm/plat-omap/include/dspbridge/drv.h | 449 +++ arch/arm/plat-omap/include/dspbridge/drvdefs.h | 34 + arch/arm/plat-omap/include/dspbridge/dspdrv.h | 106 + .../plat-omap/include/dspbridge/dynamic_loader.h | 505 +++ arch/arm/plat-omap/include/dspbridge/errbase.h | 509 +++ arch/arm/plat-omap/include/dspbridge/gb.h | 85 + arch/arm/plat-omap/include/dspbridge/getsection.h | 118 + arch/arm/plat-omap/include/dspbridge/gh.h | 37 + arch/arm/plat-omap/include/dspbridge/gs.h | 64 + arch/arm/plat-omap/include/dspbridge/gt.h | 315 ++ arch/arm/plat-omap/include/dspbridge/host_os.h | 96 + arch/arm/plat-omap/include/dspbridge/io.h | 132 + arch/arm/plat-omap/include/dspbridge/io_sm.h | 335 ++ arch/arm/plat-omap/include/dspbridge/iodefs.h | 45 + arch/arm/plat-omap/include/dspbridge/kfile.h | 216 ++ arch/arm/plat-omap/include/dspbridge/ldr.h | 51 + arch/arm/plat-omap/include/dspbridge/list.h | 296 ++ arch/arm/plat-omap/include/dspbridge/mbx_sh.h | 213 ++ arch/arm/plat-omap/include/dspbridge/mem.h | 340 ++ arch/arm/plat-omap/include/dspbridge/memdefs.h | 52 + arch/arm/plat-omap/include/dspbridge/mgr.h | 234 ++ arch/arm/plat-omap/include/dspbridge/mgrpriv.h | 55 + arch/arm/plat-omap/include/dspbridge/msg.h | 106 + arch/arm/plat-omap/include/dspbridge/msgdefs.h | 43 + arch/arm/plat-omap/include/dspbridge/nldr.h | 81 + arch/arm/plat-omap/include/dspbridge/nldrdefs.h | 307 ++ arch/arm/plat-omap/include/dspbridge/node.h | 619 ++++ arch/arm/plat-omap/include/dspbridge/nodedefs.h | 40 + arch/arm/plat-omap/include/dspbridge/nodepriv.h | 202 ++ arch/arm/plat-omap/include/dspbridge/ntfy.h | 146 + arch/arm/plat-omap/include/dspbridge/proc.h | 648 ++++ arch/arm/plat-omap/include/dspbridge/procpriv.h | 35 + arch/arm/plat-omap/include/dspbridge/pwr.h | 129 + arch/arm/plat-omap/include/dspbridge/pwr_sh.h | 41 + arch/arm/plat-omap/include/dspbridge/reg.h | 257 ++ .../plat-omap/include/dspbridge/resourcecleanup.h | 88 + arch/arm/plat-omap/include/dspbridge/rmm.h | 199 ++ arch/arm/plat-omap/include/dspbridge/rms_sh.h | 125 + arch/arm/plat-omap/include/dspbridge/rmstypes.h | 40 + arch/arm/plat-omap/include/dspbridge/services.h | 63 + arch/arm/plat-omap/include/dspbridge/std.h | 143 + arch/arm/plat-omap/include/dspbridge/strm.h | 441 +++ arch/arm/plat-omap/include/dspbridge/strmdefs.h | 57 + arch/arm/plat-omap/include/dspbridge/sync.h | 340 ++ arch/arm/plat-omap/include/dspbridge/util.h | 122 + arch/arm/plat-omap/include/dspbridge/utildefs.h | 51 + arch/arm/plat-omap/include/dspbridge/uuidutil.h | 74 + arch/arm/plat-omap/include/dspbridge/wcd.h | 61 + arch/arm/plat-omap/include/dspbridge/wcdioctl.h | 519 +++ arch/arm/plat-omap/include/dspbridge/wmd.h | 1193 +++++++ arch/arm/plat-omap/include/dspbridge/wmdchnl.h | 90 + arch/arm/plat-omap/include/dspbridge/wmddeh.h | 64 + arch/arm/plat-omap/include/dspbridge/wmdio.h | 53 + arch/arm/plat-omap/include/dspbridge/wmdioctl.h | 91 + arch/arm/plat-omap/include/dspbridge/wmdmsg.h | 70 + drivers/Makefile | 1 + drivers/dsp/bridge/Kbuild | 39 + drivers/dsp/bridge/Kconfig | 36 + drivers/dsp/bridge/dynload/cload.c | 1854 ++++++++++ drivers/dsp/bridge/dynload/dlclasses_hdr.h | 41 + drivers/dsp/bridge/dynload/dload_internal.h | 237 ++ drivers/dsp/bridge/dynload/doff.h | 347 ++ drivers/dsp/bridge/dynload/getsection.c | 412 +++ drivers/dsp/bridge/dynload/header.h | 59 + drivers/dsp/bridge/dynload/module_list.h | 161 + drivers/dsp/bridge/dynload/params.h | 231 ++ drivers/dsp/bridge/dynload/reloc.c | 425 +++ drivers/dsp/bridge/dynload/reloc_table.h | 102 + drivers/dsp/bridge/dynload/reloc_table_c6000.c | 258 ++ drivers/dsp/bridge/gen/_gt_para.c | 107 + drivers/dsp/bridge/gen/gb.c | 182 + drivers/dsp/bridge/gen/gh.c | 191 ++ drivers/dsp/bridge/gen/gs.c | 108 + drivers/dsp/bridge/gen/gt.c | 348 ++ drivers/dsp/bridge/gen/uuidutil.c | 238 ++ drivers/dsp/bridge/hw/EasiGlobal.h | 42 + drivers/dsp/bridge/hw/GlobalTypes.h | 325 ++ drivers/dsp/bridge/hw/IPIAccInt.h | 41 + drivers/dsp/bridge/hw/IVA2RegAcM.h | 28 + drivers/dsp/bridge/hw/MLBAccInt.h | 132 + drivers/dsp/bridge/hw/MLBRegAcM.h | 200 ++ drivers/dsp/bridge/hw/MMUAccInt.h | 76 + drivers/dsp/bridge/hw/MMURegAcM.h | 253 ++ drivers/dsp/bridge/hw/PRCMAccInt.h | 300 ++ drivers/dsp/bridge/hw/PRCMRegAcM.h | 669 ++++ drivers/dsp/bridge/hw/hw_defs.h | 73 + drivers/dsp/bridge/hw/hw_dspssC64P.c | 55 + drivers/dsp/bridge/hw/hw_dspssC64P.h | 48 + drivers/dsp/bridge/hw/hw_mbox.c | 244 ++ drivers/dsp/bridge/hw/hw_mbox.h | 323 ++ drivers/dsp/bridge/hw/hw_mmu.c | 598 ++++ drivers/dsp/bridge/hw/hw_mmu.h | 177 + drivers/dsp/bridge/hw/hw_prcm.c | 167 + drivers/dsp/bridge/hw/hw_prcm.h | 168 + drivers/dsp/bridge/pmgr/chnl.c | 260 ++ drivers/dsp/bridge/pmgr/chnlobj.h | 71 + drivers/dsp/bridge/pmgr/cmm.c | 1291 +++++++ drivers/dsp/bridge/pmgr/cod.c | 683 ++++ drivers/dsp/bridge/pmgr/dbl.c | 1385 ++++++++ drivers/dsp/bridge/pmgr/dbll.c | 1564 +++++++++ drivers/dsp/bridge/pmgr/dev.c | 1476 ++++++++ drivers/dsp/bridge/pmgr/dmm.c | 692 ++++ drivers/dsp/bridge/pmgr/io.c | 205 ++ drivers/dsp/bridge/pmgr/ioobj.h | 52 + drivers/dsp/bridge/pmgr/msg.c | 173 + drivers/dsp/bridge/pmgr/msgobj.h | 52 + drivers/dsp/bridge/pmgr/wcd.c | 1647 +++++++++ drivers/dsp/bridge/rmgr/dbdcd.c | 1573 +++++++++ drivers/dsp/bridge/rmgr/disp.c | 916 +++++ drivers/dsp/bridge/rmgr/drv.c | 1893 +++++++++++ drivers/dsp/bridge/rmgr/drv_interface.c | 777 +++++ drivers/dsp/bridge/rmgr/drv_interface.h | 40 + drivers/dsp/bridge/rmgr/dspdrv.c | 276 ++ drivers/dsp/bridge/rmgr/mgr.c | 491 +++ drivers/dsp/bridge/rmgr/nldr.c | 1967 +++++++++++ drivers/dsp/bridge/rmgr/node.c | 3544 ++++++++++++++++++++ drivers/dsp/bridge/rmgr/proc.c | 1985 +++++++++++ drivers/dsp/bridge/rmgr/pwr.c | 184 + drivers/dsp/bridge/rmgr/rmm.c | 604 ++++ drivers/dsp/bridge/rmgr/strm.c | 1066 ++++++ drivers/dsp/bridge/services/cfg.c | 483 +++ drivers/dsp/bridge/services/clk.c | 375 +++ drivers/dsp/bridge/services/csl.c | 173 + drivers/dsp/bridge/services/dbg.c | 119 + drivers/dsp/bridge/services/dpc.c | 274 ++ drivers/dsp/bridge/services/kfile.c | 338 ++ drivers/dsp/bridge/services/list.c | 285 ++ drivers/dsp/bridge/services/mem.c | 599 ++++ drivers/dsp/bridge/services/ntfy.c | 329 ++ drivers/dsp/bridge/services/reg.c | 196 ++ drivers/dsp/bridge/services/regsup.c | 368 ++ drivers/dsp/bridge/services/regsup.h | 58 + drivers/dsp/bridge/services/services.c | 193 ++ drivers/dsp/bridge/services/sync.c | 602 ++++ drivers/dsp/bridge/wmd/_cmm.h | 59 + drivers/dsp/bridge/wmd/_deh.h | 46 + drivers/dsp/bridge/wmd/_msg_sm.h | 158 + drivers/dsp/bridge/wmd/_tiomap.h | 384 +++ drivers/dsp/bridge/wmd/_tiomap_mmu.h | 53 + drivers/dsp/bridge/wmd/_tiomap_pwr.h | 102 + drivers/dsp/bridge/wmd/_tiomap_util.h | 46 + drivers/dsp/bridge/wmd/chnl_sm.c | 1100 ++++++ drivers/dsp/bridge/wmd/io_sm.c | 2011 +++++++++++ drivers/dsp/bridge/wmd/mmu_fault.c | 172 + drivers/dsp/bridge/wmd/mmu_fault.h | 45 + drivers/dsp/bridge/wmd/msg_sm.c | 643 ++++ drivers/dsp/bridge/wmd/tiomap3430.c | 2149 ++++++++++++ drivers/dsp/bridge/wmd/tiomap3430_pwr.c | 731 ++++ drivers/dsp/bridge/wmd/tiomap_io.c | 427 +++ drivers/dsp/bridge/wmd/tiomap_io.h | 112 + drivers/dsp/bridge/wmd/tiomap_sm.c | 195 ++ drivers/dsp/bridge/wmd/ue_deh.c | 329 ++ 191 files changed, 65137 insertions(+), 0 deletions(-) create mode 100644 Documentation/tidspbridge/README create mode 100644 arch/arm/mach-omap2/dspbridge.c create mode 100644 arch/arm/plat-omap/include/dspbridge/_chnl_sm.h create mode 100644 arch/arm/plat-omap/include/dspbridge/_dcd.h create mode 100644 arch/arm/plat-omap/include/dspbridge/brddefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/cfg.h create mode 100644 arch/arm/plat-omap/include/dspbridge/cfgdefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/chnl.h create mode 100644 arch/arm/plat-omap/include/dspbridge/chnl_sm.h create mode 100644 arch/arm/plat-omap/include/dspbridge/chnldefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/chnlpriv.h create mode 100644 arch/arm/plat-omap/include/dspbridge/clk.h create mode 100644 arch/arm/plat-omap/include/dspbridge/cmm.h create mode 100644 arch/arm/plat-omap/include/dspbridge/cmmdefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/cod.h create mode 100644 arch/arm/plat-omap/include/dspbridge/csl.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dbc.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dbdcd.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dbdcddef.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dbdefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dbg.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dbl.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dbldefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dbll.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dblldefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dbof.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dbreg.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dbtype.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dehdefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dev.h create mode 100644 arch/arm/plat-omap/include/dspbridge/devdefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/disp.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dispdefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dmm.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dpc.h create mode 100644 arch/arm/plat-omap/include/dspbridge/drv.h create mode 100644 arch/arm/plat-omap/include/dspbridge/drvdefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dspdrv.h create mode 100644 arch/arm/plat-omap/include/dspbridge/dynamic_loader.h create mode 100644 arch/arm/plat-omap/include/dspbridge/errbase.h create mode 100644 arch/arm/plat-omap/include/dspbridge/gb.h create mode 100644 arch/arm/plat-omap/include/dspbridge/getsection.h create mode 100644 arch/arm/plat-omap/include/dspbridge/gh.h create mode 100644 arch/arm/plat-omap/include/dspbridge/gs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/gt.h create mode 100644 arch/arm/plat-omap/include/dspbridge/host_os.h create mode 100644 arch/arm/plat-omap/include/dspbridge/io.h create mode 100644 arch/arm/plat-omap/include/dspbridge/io_sm.h create mode 100644 arch/arm/plat-omap/include/dspbridge/iodefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/kfile.h create mode 100644 arch/arm/plat-omap/include/dspbridge/ldr.h create mode 100644 arch/arm/plat-omap/include/dspbridge/list.h create mode 100644 arch/arm/plat-omap/include/dspbridge/mbx_sh.h create mode 100644 arch/arm/plat-omap/include/dspbridge/mem.h create mode 100644 arch/arm/plat-omap/include/dspbridge/memdefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/mgr.h create mode 100644 arch/arm/plat-omap/include/dspbridge/mgrpriv.h create mode 100644 arch/arm/plat-omap/include/dspbridge/msg.h create mode 100644 arch/arm/plat-omap/include/dspbridge/msgdefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/nldr.h create mode 100644 arch/arm/plat-omap/include/dspbridge/nldrdefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/node.h create mode 100644 arch/arm/plat-omap/include/dspbridge/nodedefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/nodepriv.h create mode 100644 arch/arm/plat-omap/include/dspbridge/ntfy.h create mode 100644 arch/arm/plat-omap/include/dspbridge/proc.h create mode 100644 arch/arm/plat-omap/include/dspbridge/procpriv.h create mode 100644 arch/arm/plat-omap/include/dspbridge/pwr.h create mode 100644 arch/arm/plat-omap/include/dspbridge/pwr_sh.h create mode 100644 arch/arm/plat-omap/include/dspbridge/reg.h create mode 100644 arch/arm/plat-omap/include/dspbridge/resourcecleanup.h create mode 100644 arch/arm/plat-omap/include/dspbridge/rmm.h create mode 100644 arch/arm/plat-omap/include/dspbridge/rms_sh.h create mode 100644 arch/arm/plat-omap/include/dspbridge/rmstypes.h create mode 100644 arch/arm/plat-omap/include/dspbridge/services.h create mode 100644 arch/arm/plat-omap/include/dspbridge/std.h create mode 100644 arch/arm/plat-omap/include/dspbridge/strm.h create mode 100644 arch/arm/plat-omap/include/dspbridge/strmdefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/sync.h create mode 100644 arch/arm/plat-omap/include/dspbridge/util.h create mode 100644 arch/arm/plat-omap/include/dspbridge/utildefs.h create mode 100644 arch/arm/plat-omap/include/dspbridge/uuidutil.h create mode 100644 arch/arm/plat-omap/include/dspbridge/wcd.h create mode 100644 arch/arm/plat-omap/include/dspbridge/wcdioctl.h create mode 100644 arch/arm/plat-omap/include/dspbridge/wmd.h create mode 100644 arch/arm/plat-omap/include/dspbridge/wmdchnl.h create mode 100644 arch/arm/plat-omap/include/dspbridge/wmddeh.h create mode 100644 arch/arm/plat-omap/include/dspbridge/wmdio.h create mode 100644 arch/arm/plat-omap/include/dspbridge/wmdioctl.h create mode 100644 arch/arm/plat-omap/include/dspbridge/wmdmsg.h create mode 100644 drivers/dsp/bridge/Kbuild create mode 100644 drivers/dsp/bridge/Kconfig create mode 100644 drivers/dsp/bridge/dynload/cload.c create mode 100644 drivers/dsp/bridge/dynload/dlclasses_hdr.h create mode 100644 drivers/dsp/bridge/dynload/dload_internal.h create mode 100644 drivers/dsp/bridge/dynload/doff.h create mode 100644 drivers/dsp/bridge/dynload/getsection.c create mode 100644 drivers/dsp/bridge/dynload/header.h create mode 100644 drivers/dsp/bridge/dynload/module_list.h create mode 100644 drivers/dsp/bridge/dynload/params.h create mode 100644 drivers/dsp/bridge/dynload/reloc.c create mode 100644 drivers/dsp/bridge/dynload/reloc_table.h create mode 100644 drivers/dsp/bridge/dynload/reloc_table_c6000.c create mode 100644 drivers/dsp/bridge/gen/_gt_para.c create mode 100644 drivers/dsp/bridge/gen/gb.c create mode 100644 drivers/dsp/bridge/gen/gh.c create mode 100644 drivers/dsp/bridge/gen/gs.c create mode 100644 drivers/dsp/bridge/gen/gt.c create mode 100644 drivers/dsp/bridge/gen/uuidutil.c create mode 100644 drivers/dsp/bridge/hw/EasiGlobal.h create mode 100644 drivers/dsp/bridge/hw/GlobalTypes.h create mode 100644 drivers/dsp/bridge/hw/IPIAccInt.h create mode 100644 drivers/dsp/bridge/hw/IVA2RegAcM.h create mode 100644 drivers/dsp/bridge/hw/MLBAccInt.h create mode 100644 drivers/dsp/bridge/hw/MLBRegAcM.h create mode 100644 drivers/dsp/bridge/hw/MMUAccInt.h create mode 100644 drivers/dsp/bridge/hw/MMURegAcM.h create mode 100644 drivers/dsp/bridge/hw/PRCMAccInt.h create mode 100644 drivers/dsp/bridge/hw/PRCMRegAcM.h create mode 100644 drivers/dsp/bridge/hw/hw_defs.h create mode 100644 drivers/dsp/bridge/hw/hw_dspssC64P.c create mode 100644 drivers/dsp/bridge/hw/hw_dspssC64P.h create mode 100644 drivers/dsp/bridge/hw/hw_mbox.c create mode 100644 drivers/dsp/bridge/hw/hw_mbox.h create mode 100644 drivers/dsp/bridge/hw/hw_mmu.c create mode 100644 drivers/dsp/bridge/hw/hw_mmu.h create mode 100644 drivers/dsp/bridge/hw/hw_prcm.c create mode 100644 drivers/dsp/bridge/hw/hw_prcm.h create mode 100644 drivers/dsp/bridge/pmgr/chnl.c create mode 100644 drivers/dsp/bridge/pmgr/chnlobj.h create mode 100644 drivers/dsp/bridge/pmgr/cmm.c create mode 100644 drivers/dsp/bridge/pmgr/cod.c create mode 100644 drivers/dsp/bridge/pmgr/dbl.c create mode 100644 drivers/dsp/bridge/pmgr/dbll.c create mode 100644 drivers/dsp/bridge/pmgr/dev.c create mode 100644 drivers/dsp/bridge/pmgr/dmm.c create mode 100644 drivers/dsp/bridge/pmgr/io.c create mode 100644 drivers/dsp/bridge/pmgr/ioobj.h create mode 100644 drivers/dsp/bridge/pmgr/msg.c create mode 100644 drivers/dsp/bridge/pmgr/msgobj.h create mode 100644 drivers/dsp/bridge/pmgr/wcd.c create mode 100644 drivers/dsp/bridge/rmgr/dbdcd.c create mode 100644 drivers/dsp/bridge/rmgr/disp.c create mode 100644 drivers/dsp/bridge/rmgr/drv.c create mode 100644 drivers/dsp/bridge/rmgr/drv_interface.c create mode 100644 drivers/dsp/bridge/rmgr/drv_interface.h create mode 100644 drivers/dsp/bridge/rmgr/dspdrv.c create mode 100644 drivers/dsp/bridge/rmgr/mgr.c create mode 100644 drivers/dsp/bridge/rmgr/nldr.c create mode 100644 drivers/dsp/bridge/rmgr/node.c create mode 100644 drivers/dsp/bridge/rmgr/proc.c create mode 100644 drivers/dsp/bridge/rmgr/pwr.c create mode 100644 drivers/dsp/bridge/rmgr/rmm.c create mode 100644 drivers/dsp/bridge/rmgr/strm.c create mode 100644 drivers/dsp/bridge/services/cfg.c create mode 100644 drivers/dsp/bridge/services/clk.c create mode 100644 drivers/dsp/bridge/services/csl.c create mode 100644 drivers/dsp/bridge/services/dbg.c create mode 100644 drivers/dsp/bridge/services/dpc.c create mode 100644 drivers/dsp/bridge/services/kfile.c create mode 100644 drivers/dsp/bridge/services/list.c create mode 100644 drivers/dsp/bridge/services/mem.c create mode 100644 drivers/dsp/bridge/services/ntfy.c create mode 100644 drivers/dsp/bridge/services/reg.c create mode 100644 drivers/dsp/bridge/services/regsup.c create mode 100644 drivers/dsp/bridge/services/regsup.h create mode 100644 drivers/dsp/bridge/services/services.c create mode 100644 drivers/dsp/bridge/services/sync.c create mode 100644 drivers/dsp/bridge/wmd/_cmm.h create mode 100644 drivers/dsp/bridge/wmd/_deh.h create mode 100644 drivers/dsp/bridge/wmd/_msg_sm.h create mode 100644 drivers/dsp/bridge/wmd/_tiomap.h create mode 100644 drivers/dsp/bridge/wmd/_tiomap_mmu.h create mode 100644 drivers/dsp/bridge/wmd/_tiomap_pwr.h create mode 100644 drivers/dsp/bridge/wmd/_tiomap_util.h create mode 100644 drivers/dsp/bridge/wmd/chnl_sm.c create mode 100644 drivers/dsp/bridge/wmd/io_sm.c create mode 100644 drivers/dsp/bridge/wmd/mmu_fault.c create mode 100644 drivers/dsp/bridge/wmd/mmu_fault.h create mode 100644 drivers/dsp/bridge/wmd/msg_sm.c create mode 100644 drivers/dsp/bridge/wmd/tiomap3430.c create mode 100644 drivers/dsp/bridge/wmd/tiomap3430_pwr.c create mode 100644 drivers/dsp/bridge/wmd/tiomap_io.c create mode 100644 drivers/dsp/bridge/wmd/tiomap_io.h create mode 100644 drivers/dsp/bridge/wmd/tiomap_sm.c create mode 100644 drivers/dsp/bridge/wmd/ue_deh.c diff --git a/Documentation/tidspbridge/README b/Documentation/tidspbridge/README new file mode 100644 index 0000000..df6d371 --- /dev/null +++ b/Documentation/tidspbridge/README @@ -0,0 +1,70 @@ + Linux DSP/BIOS Bridge release + +DSP/BIOS Bridge overview +======================== + +DSP/BIOS Bridge is designed for platforms that contain a GPP and one or more +attached DSPs. The GPP is considered the master or "host" processor, and the +attached DSPs are processing resources that can be utilized by applications +and drivers running on the GPP. + +The abstraction that DSP/BIOS Bridge supplies, is a direct link between a GPP +program and a DSP task. This communication link is partitioned into two +types of sub-links: messaging (short, fixed-length packets) and data +streaming (multiple, large buffers). Each sub-link operates independently, +and features in-order delivery of data, meaning that messages are delivered +in the order they were submitted to the message link, and stream buffers are +delivered in the order they were submitted to the stream link. + +In addition, a GPP client can specify what inputs and outputs a DSP task +uses. DSP tasks typically use message objects for passing control and status +information and stream objects for efficient streaming of real-time data. + +GPP Software Architecture +========================= + +A GPP application communicates with its associated DSP task running on the +DSP subsystem using the DSP/BIOS Bridge API. For example, a GPP audio +application can use the API to pass messages to a DSP task that is managing +data flowing from analog-to-digital converters (ADCs) to digital-to-analog +converters (DACs). + +From the perspective of the GPP OS, the DSP is treated as just another +peripheral device. Most high level GPP OS typically support a device driver +model, whereby applications can safely access and share a hardware peripheral +through standard driver interfaces. Therefore, to allow multiple GPP +applications to share access to the DSP, the GPP side of DSP/BIOS Bridge +implements a device driver for the DSP. + +Since driver interfaces are not always standard across GPP OS, and to provide +some level of interoperability of application code using DSP/BIOS Bridge +between GPP OS, DSP/BIOS Bridge provides a standard library of APIs which +wrap calls into the device driver. So, rather than calling GPP OS specific +driver interfaces, applications (and even other device drivers) can use the +standard API library directly. + +DSP Software Architecture +========================= + +For DSP/BIOS, DSP/BIOS Bridge adds a device-independent streaming I/O (STRM) +interface, a messaging interface (NODE), and a Resource Manager (RM) Server. +The RM Server runs as a task of DSP/BIOS and is subservient to commands +and queries from the GPP. It executes commands to start and stop DSP signal +processing nodes in response to GPP programs making requests through the +(GPP-side) API. + +DSP tasks started by the RM Server are similar to any other DSP task with two +important differences: they must follow a specific task model consisting of +three C-callable functions (node create, execute, and delete), with specific +sets of arguments, and they have a pre-defined task environment established +by the RM Server. + +Tasks started by the RM Server communicate using the STRM and NODE interfaces +and act as servers for their corresponding GPP clients, performing signal +processing functions as requested by messages sent by their GPP client. +Typically, a DSP task moves data from source devices to sink devices using +device independent I/O streams, performing application-specific processing +and transformations on the data while it is moved. For example, an audio +task might perform audio decompression (ADPCM, MPEG, CELP) on data received +from a GPP audio driver and then send the decompressed linear samples to a +digital-to-analog converter. diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e7fb201..2060772 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1331,6 +1331,8 @@ if ARCH_OMAP source "drivers/cbus/Kconfig" endif +source "drivers/dsp/bridge/Kconfig" + endmenu source "fs/Kconfig" diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 9b270d8..e52e01e 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -34,6 +34,8 @@ obj-$(CONFIG_OMAP_SMARTREFLEX) += smartreflex.o obj-$(CONFIG_ARCH_OMAP2) += clock24xx.o obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o +obj-$(CONFIG_MPU_BRIDGE) += dspbridge.o + # DSP obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o mailbox_mach-objs := mailbox.o diff --git a/arch/arm/mach-omap2/dspbridge.c b/arch/arm/mach-omap2/dspbridge.c new file mode 100644 index 0000000..221e8ff --- /dev/null +++ b/arch/arm/mach-omap2/dspbridge.c @@ -0,0 +1,74 @@ +/* + * TI's dspbridge platform device registration + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * Copyright (C) 2009 Nokia Corporation + * + * Written by Hiroshi DOYU + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include + +static struct platform_device *dspbridge_pdev; + +#ifdef CONFIG_BRIDGE_DVFS +#include +static struct dspbridge_platform_data dspbridge_pdata __initdata = { + .dsp_set_min_opp = omap_pm_dsp_set_min_opp, + .dsp_get_opp = omap_pm_dsp_get_opp, + .cpu_set_freq = omap_pm_cpu_set_freq, + .cpu_get_freq = omap_pm_cpu_get_freq, +}; +#else +static struct dspbridge_platform_data dspbridge_pdata; +#endif + +static int __init dspbridge_init(void) +{ + struct platform_device *pdev; + int err = -ENOMEM; + struct dspbridge_platform_data *pdata = &dspbridge_pdata; + + pdata->phys_mempool_base = dspbridge_get_mempool_base(); + + if (pdata->phys_mempool_base) { + pdata->phys_mempool_size = CONFIG_BRIDGE_MEMPOOL_SIZE; + pr_info("%s: %x bytes @ %x\n", __func__, + pdata->phys_mempool_size, pdata->phys_mempool_base); + } + + pdev = platform_device_alloc("C6410", -1); + if (!pdev) + goto err_out; + + err = platform_device_add_data(pdev, pdata, sizeof(*pdata)); + if (err) + goto err_out; + + err = platform_device_add(pdev); + if (err) + goto err_out; + + dspbridge_pdev = pdev; + return 0; + +err_out: + platform_device_put(pdev); + return err; +} +module_init(dspbridge_init); + +static void __exit dspbridge_exit(void) +{ + platform_device_unregister(dspbridge_pdev); +} +module_exit(dspbridge_exit); + +MODULE_AUTHOR("Hiroshi DOYU"); +MODULE_DESCRIPTION("TI's dspbridge platform device registration"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index a04e3ee..40488ae 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -38,6 +38,8 @@ #include #include "clockdomains.h" +#include + /* * The machine specific code may provide the extra mapping besides the * default mapping provided here. @@ -192,6 +194,7 @@ void __init omap2_map_common_io(void) omap2_check_revision(); omap_sram_init(); omapfb_reserve_sdram(); + dspbridge_reserve_sdram(); } void __init omap2_init_common_hw(struct omap_sdrc_params *sp) diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c index 6b742a8..e66dd8a 100644 --- a/arch/arm/plat-omap/devices.c +++ b/arch/arm/plat-omap/devices.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -89,6 +90,33 @@ EXPORT_SYMBOL(dsp_kfunc_device_register); static inline void omap_init_dsp(void) { } #endif /* CONFIG_OMAP_DSP */ +#if defined(CONFIG_MPU_BRIDGE) || defined(CONFIG_MPU_BRIDGE_MODULE) + +static unsigned long dspbridge_phys_mempool_base; + +void dspbridge_reserve_sdram(void) +{ + void *va; + unsigned long size = CONFIG_BRIDGE_MEMPOOL_SIZE; + + if (!size) + return; + + va = __alloc_bootmem_nopanic(size, SZ_1M, 0); + if (!va) { + pr_err("%s: Failed to bootmem allocation(%lu bytes)\n", + __func__, size); + return; + } + dspbridge_phys_mempool_base = virt_to_phys(va); +} + +unsigned long dspbridge_get_mempool_base(void) +{ + return dspbridge_phys_mempool_base; +} +EXPORT_SYMBOL(dspbridge_get_mempool_base); +#endif /*-------------------------------------------------------------------------*/ #if defined(CONFIG_KEYBOARD_OMAP) || defined(CONFIG_KEYBOARD_OMAP_MODULE) diff --git a/arch/arm/plat-omap/include/dspbridge/_chnl_sm.h b/arch/arm/plat-omap/include/dspbridge/_chnl_sm.h new file mode 100644 index 0000000..28af799 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/_chnl_sm.h @@ -0,0 +1,212 @@ +/* + * _chnl_sm.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== _chnl_sm.h ======== + * Description: + * Private header file defining channel manager and channel objects for + * a shared memory channel driver. + * + * Public Functions: + * None. + * + * Notes: + * Shared between the modules implementing the shared memory channel class + * library. + * + *! Revision History: + *! ================ + *! 15-Oct-2002 kc Removed legacy PERF code. + *! 12-Jan-2002 ag Removed unused gppReqIO & ddmaChnlId DDMA fields. + *! Added zero-copy chnl descriptor array: zchnldesc. + *! 21-Dec-2001 ag Moved descPaGpp to private chnl obj from chnl descriptor. + *! 20-May-2001 ag/jeh Removed fShmSyms field from CHNL_MGR. + *! 04-Feb-2001 ag DSP-DMA support added. + *! 26-Oct-2000 jeh Added arg and resvd to SHM control structure. Added dwArg + *! to CHNL_IRP. + *! 16-Oct-2000 jeh Removed #ifdef DEBUG from around channel object's cIOCs + *! field, added cIOReqs. + *! 20-Jan-2000 ag: Incorporated code review comments. + *! 05-Jan-2000 ag: Text format cleanup. + *! 03-Nov-1999 ag: Added szEventName[] to CHNL object for name event support. + *! 02-Nov-1999 ag: _SHM_BEG & _END Syms from COFF now used for IO and SM CLASS. + *! 27-Oct-1999 jeh Define SHM structure to work for 16-bit targets. + *! 25-May-1999 jg: Added target side symbol names for share memory buffer + *! 03-Jan-1997 gp: Added fSharedIRQ field. + *! 22-Oct-1996 gp: Made dwProcessID a handle. + *! 09-Sep-1996 gp: Added dwProcessID field to CHNL_OBJECT. + *! 13-Aug-1996 gp: Created. + */ + +#ifndef _CHNL_SM_ +#define _CHNL_SM_ + +#include +#include +#include + +#include +#include + +/* + * These target side symbols define the beginning and ending addresses + * of shared memory buffer. They are defined in the *cfg.cmd file by + * cdb code. + */ +#define CHNL_SHARED_BUFFER_BASE_SYM "_SHM_BEG" +#define CHNL_SHARED_BUFFER_LIMIT_SYM "_SHM_END" +#define BRIDGEINIT_BIOSGPTIMER "_BRIDGEINIT_BIOSGPTIMER" +#define BRIDGEINIT_LOADMON_GPTIMER "_BRIDGEINIT_LOADMON_GPTIMER" + +#ifndef _CHNL_WORDSIZE +#define _CHNL_WORDSIZE 4 /* default _CHNL_WORDSIZE is 2 bytes/word */ +#endif + +#define MAXOPPS 16 + +struct oppTableEntry { + u32 voltage; + u32 frequency; + u32 minFreq; + u32 maxFreq; +} ; + +struct oppStruct { + u32 currOppPt; + u32 numOppPts; + struct oppTableEntry oppPoint[MAXOPPS]; +} ; + +/* Request to MPU */ +struct oppRqstStruct { + u32 rqstDspFreq; + u32 rqstOppPt; +}; + +/* Info to MPU */ +struct loadMonStruct { + u32 currDspLoad; + u32 currDspFreq; + u32 predDspLoad; + u32 predDspFreq; +}; + + enum SHM_DESCTYPE { + SHM_CURROPP = 0, + SHM_OPPINFO = 1, + SHM_GETOPP = 2, /* Get DSP requested OPP info */ + } ; + +/* Structure in shared between DSP and PC for communication.*/ + struct SHM { + u32 dspFreeMask; /* Written by DSP, read by PC. */ + u32 hostFreeMask; /* Written by PC, read by DSP */ + + u32 inputFull; /* Input channel has unread data. */ + u32 inputId; /* Channel for which input is available. */ + u32 inputSize; /* Size of data block (in DSP words). */ + + u32 outputFull; /* Output channel has unread data. */ + u32 outputId; /* Channel for which output is available. */ + u32 outputSize; /* Size of data block (in DSP words). */ + + u32 arg; /* Arg for Issue/Reclaim (23 bits for 55x). */ + u32 resvd; /* Keep structure size even for 32-bit DSPs */ + + /* Operating Point structure */ + struct oppStruct oppTableStruct; + /* Operating Point Request structure */ + struct oppRqstStruct oppRequest; + /* load monitor information structure*/ + struct loadMonStruct loadMonInfo; + char dummy[184]; /* padding to 256 byte boundary */ + u32 shm_dbg_var[64]; /* shared memory debug variables */ + } ; + + /* Channel Manager: only one created per board: */ + struct CHNL_MGR { + u32 dwSignature; /* Used for object validation */ + /* Function interface to WMD */ + struct WMD_DRV_INTERFACE *pIntfFxns; + struct IO_MGR *hIOMgr; /* IO manager */ + /* Device this board represents */ + struct DEV_OBJECT *hDevObject; + + /* These fields initialized in WMD_CHNL_Create(): */ + u32 dwOutputMask; /* Host output channels w/ full buffers */ + u32 dwLastOutput; /* Last output channel fired from DPC */ + /* Critical section object handle */ + struct SYNC_CSOBJECT *hCSObj; + u32 uWordSize; /* Size in bytes of DSP word */ + u32 cChannels; /* Total number of channels */ + u32 cOpenChannels; /* Total number of open channels */ + struct CHNL_OBJECT **apChannel; /* Array of channels */ + u32 dwType; /* Type of channel class library */ + /* If no SHM syms, return for CHNL_Open */ + DSP_STATUS chnlOpenStatus; + } ; + +/* + * Channel: up to CHNL_MAXCHANNELS per board or if DSP-DMA supported then + * up to CHNL_MAXCHANNELS + CHNL_MAXDDMACHNLS per board. + */ + struct CHNL_OBJECT { + u32 dwSignature; /* Used for object validation */ + /* Pointer back to channel manager */ + struct CHNL_MGR *pChnlMgr; + u32 uId; /* Channel id */ + u32 dwState; /* Current channel state */ + u32 uMode; /* Chnl mode and attributes */ + /* Chnl I/O completion event (user mode) */ + HANDLE hUserEvent; + /* Abstract syncronization object */ + struct SYNC_OBJECT *hSyncEvent; + /* Name of Sync event */ + char szEventName[SYNC_MAXNAMELENGTH + 1]; + u32 hProcess; /* Process which created this channel */ + u32 pCBArg; /* Argument to use with callback */ + struct LST_LIST *pIORequests; /* List of IOR's to driver */ + s32 cIOCs; /* Number of IOC's in queue */ + s32 cIOReqs; /* Number of IORequests in queue */ + s32 cChirps; /* Initial number of free Irps */ + /* List of IOC's from driver */ + struct LST_LIST *pIOCompletions; + struct LST_LIST *pFreeList; /* List of free Irps */ + struct NTFY_OBJECT *hNtfy; + u32 cBytesMoved; /* Total number of bytes transfered */ + + /* For DSP-DMA */ + + /* Type of chnl transport:CHNL_[PCPY][DDMA] */ + u32 uChnlType; + } ; + +/* I/O Request/completion packet: */ + struct CHNL_IRP { + struct LST_ELEM link; /* Link to next CHIRP in queue. */ + /* Buffer to be filled/emptied. (User) */ + u8 *pHostUserBuf; + /* Buffer to be filled/emptied. (System) */ + u8 *pHostSysBuf; + u32 dwArg; /* Issue/Reclaim argument. */ + u32 uDspAddr; /* Transfer address on DSP side. */ + u32 cBytes; /* Bytes transferred. */ + u32 cBufSize; /* Actual buffer size when allocated. */ + u32 status; /* Status of IO completion. */ + } ; + +#endif /* _CHNL_SM_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/_dcd.h b/arch/arm/plat-omap/include/dspbridge/_dcd.h new file mode 100644 index 0000000..b6a8d9e --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/_dcd.h @@ -0,0 +1,187 @@ +/* + * _dcd.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== _dcd.h ======== + * Description: + * Includes the wrapper functions called directly by the + * DeviceIOControl interface. + * + * Public Functions: + * WCD_CallDevIOCtl + * WCD_Init + * WCD_InitComplete2 + * WCD_Exit + * WRAP_* + * + * Notes: + * Compiled with CDECL calling convention. + * + *! Revision History: + *! ================ + *! 19-Apr-2004 sb Aligned DMM definitions with Symbian + *! 08-Mar-2004 sb Added the Dynamic Memory Mapping feature + *! 30-Jan-2002 ag Renamed CMMWRAP_AllocBuf to CMMWRAP_CallocBuf. + *! 22-Nov-2000 kc: Added MGRWRAP_GetPerf_Data to acquire PERF stats. + *! 27-Oct-2000 jeh Added NODEWRAP_AllocMsgBuf, NODEWRAP_FreeMsgBuf. Removed + *! NODEWRAP_GetMessageStream. + *! 10-Oct-2000 ag: Added user CMM wrappers. + *! 04-Aug-2000 rr: MEMWRAP and UTIL_Wrap added. + *! 27-Jul-2000 rr: NODEWRAP, STRMWRAP added. + *! 27-Jun-2000 rr: MGRWRAP fxns added.IFDEF to build for PM or DSP/BIOS Bridge + *! 03-Dec-1999 rr: WCD_InitComplete2 enabled for BRD_AutoStart. + *! 09-Nov-1999 kc: Added MEMRY. + *! 02-Nov-1999 ag: Added CHNL. + *! 08-Oct-1999 rr: Utilwrap_Testdll fxn added + *! 24-Sep-1999 rr: header changed from _wcd.h to _dcd.h + *! 09-Sep-1997 gp: Created. + */ + +#ifndef _WCD_ +#define _WCD_ + +#include + +/* + * ======== WCD_CallDevIOCtl ======== + * Purpose: + * Call the (wrapper) function for the corresponding WCD IOCTL. + * Parameters: + * cmd: IOCTL id, base 0. + * args: Argument structure. + * pResult: + * Returns: + * DSP_SOK if command called; DSP_EINVALIDARG if command not in IOCTL + * table. + * Requires: + * Ensures: + */ + extern DSP_STATUS WCD_CallDevIOCtl(unsigned int cmd, + union Trapped_Args *args, + u32 *pResult); + +/* + * ======== WCD_Init ======== + * Purpose: + * Initialize WCD modules, and export WCD services to WMD's. + * This procedure is called when the class driver is loaded. + * Parameters: + * Returns: + * TRUE if success; FALSE otherwise. + * Requires: + * Ensures: + */ + extern bool WCD_Init(void); + +/* + * ======== WCD_InitComplete2 ======== + * Purpose: + * Perform any required WCD, and WMD initialization which + * cannot not be performed in WCD_Init(void) or DEV_StartDevice() due + * to the fact that some services are not yet + * completely initialized. + * Parameters: + * Returns: + * DSP_SOK: Allow this device to load + * DSP_EFAIL: Failure. + * Requires: + * WCD initialized. + * Ensures: + */ + extern DSP_STATUS WCD_InitComplete2(void); + +/* + * ======== WCD_Exit ======== + * Purpose: + * Exit all modules initialized in WCD_Init(void). + * This procedure is called when the class driver is unloaded. + * Parameters: + * Returns: + * Requires: + * WCD_Init(void) was previously called. + * Ensures: + * Resources acquired in WCD_Init(void) are freed. + */ + extern void WCD_Exit(void); + +/* MGR wrapper functions */ + extern u32 MGRWRAP_EnumNode_Info(union Trapped_Args *args); + extern u32 MGRWRAP_EnumProc_Info(union Trapped_Args *args); + extern u32 MGRWRAP_RegisterObject(union Trapped_Args *args); + extern u32 MGRWRAP_UnregisterObject(union Trapped_Args *args); + extern u32 MGRWRAP_WaitForBridgeEvents(union Trapped_Args *args); + +#ifndef RES_CLEANUP_DISABLE + extern u32 MGRWRAP_GetProcessResourcesInfo(union Trapped_Args *args); +#endif + + +/* CPRC (Processor) wrapper Functions */ + extern u32 PROCWRAP_Attach(union Trapped_Args *args); + extern u32 PROCWRAP_Ctrl(union Trapped_Args *args); + extern u32 PROCWRAP_Detach(union Trapped_Args *args); + extern u32 PROCWRAP_EnumNode_Info(union Trapped_Args *args); + extern u32 PROCWRAP_EnumResources(union Trapped_Args *args); + extern u32 PROCWRAP_GetState(union Trapped_Args *args); + extern u32 PROCWRAP_GetTrace(union Trapped_Args *args); + extern u32 PROCWRAP_Load(union Trapped_Args *args); + extern u32 PROCWRAP_RegisterNotify(union Trapped_Args *args); + extern u32 PROCWRAP_Start(union Trapped_Args *args); + extern u32 PROCWRAP_ReserveMemory(union Trapped_Args *args); + extern u32 PROCWRAP_UnReserveMemory(union Trapped_Args *args); + extern u32 PROCWRAP_Map(union Trapped_Args *args); + extern u32 PROCWRAP_UnMap(union Trapped_Args *args); + extern u32 PROCWRAP_FlushMemory(union Trapped_Args *args); + extern u32 PROCWRAP_Stop(union Trapped_Args *args); + extern u32 PROCWRAP_InvalidateMemory(union Trapped_Args *args); + +/* NODE wrapper functions */ + extern u32 NODEWRAP_Allocate(union Trapped_Args *args); + extern u32 NODEWRAP_AllocMsgBuf(union Trapped_Args *args); + extern u32 NODEWRAP_ChangePriority(union Trapped_Args *args); + extern u32 NODEWRAP_Connect(union Trapped_Args *args); + extern u32 NODEWRAP_Create(union Trapped_Args *args); + extern u32 NODEWRAP_Delete(union Trapped_Args *args); + extern u32 NODEWRAP_FreeMsgBuf(union Trapped_Args *args); + extern u32 NODEWRAP_GetAttr(union Trapped_Args *args); + extern u32 NODEWRAP_GetMessage(union Trapped_Args *args); + extern u32 NODEWRAP_Pause(union Trapped_Args *args); + extern u32 NODEWRAP_PutMessage(union Trapped_Args *args); + extern u32 NODEWRAP_RegisterNotify(union Trapped_Args *args); + extern u32 NODEWRAP_Run(union Trapped_Args *args); + extern u32 NODEWRAP_Terminate(union Trapped_Args *args); + extern u32 NODEWRAP_GetUUIDProps(union Trapped_Args *args); + +/* STRM wrapper functions */ + extern u32 STRMWRAP_AllocateBuffer(union Trapped_Args *args); + extern u32 STRMWRAP_Close(union Trapped_Args *args); + extern u32 STRMWRAP_FreeBuffer(union Trapped_Args *args); + extern u32 STRMWRAP_GetEventHandle(union Trapped_Args *args); + extern u32 STRMWRAP_GetInfo(union Trapped_Args *args); + extern u32 STRMWRAP_Idle(union Trapped_Args *args); + extern u32 STRMWRAP_Issue(union Trapped_Args *args); + extern u32 STRMWRAP_Open(union Trapped_Args *args); + extern u32 STRMWRAP_Reclaim(union Trapped_Args *args); + extern u32 STRMWRAP_RegisterNotify(union Trapped_Args *args); + extern u32 STRMWRAP_Select(union Trapped_Args *args); + + extern u32 CMMWRAP_CallocBuf(union Trapped_Args *args); + extern u32 CMMWRAP_FreeBuf(union Trapped_Args *args); + extern u32 CMMWRAP_GetHandle(union Trapped_Args *args); + extern u32 CMMWRAP_GetInfo(union Trapped_Args *args); + +#endif /* _WCD_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/brddefs.h b/arch/arm/plat-omap/include/dspbridge/brddefs.h new file mode 100644 index 0000000..c62388c --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/brddefs.h @@ -0,0 +1,54 @@ +/* + * brddefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== brddefs.h ======== + * Description: + * Global BRD constants and types, shared between WSX, WCD, and WMD. + * + *! Revision History: + *! ================ + *! 31-Jan-2000 rr: Comment Exec changed to Monitor + *! 22-Jul-1999 jeh Added BRD_LOADED state. + *! 26-Mar-1997 gp: Added BRD_SYNCINIT state. + *! 11-Dec-1996 cr: Added BRD_LASTSTATE definition. + *! 11-Jul-1996 gp: Added missing u32 callback argument to BRD_CALLBACK. + *! 10-Jun-1996 gp: Created from board.h and brd.h. + */ + +#ifndef BRDDEFS_ +#define BRDDEFS_ + +/* platform status values */ +#define BRD_STOPPED 0x0 /* No Monitor Loaded, Not running. */ +#define BRD_IDLE 0x1 /* Monitor Loaded, but suspended. */ +#define BRD_RUNNING 0x2 /* Monitor loaded, and executing. */ +#define BRD_UNKNOWN 0x3 /* Board state is indeterminate. */ +#define BRD_SYNCINIT 0x4 +#define BRD_LOADED 0x5 +#define BRD_LASTSTATE BRD_LOADED /* Set to highest legal board state. */ +#define BRD_SLEEP_TRANSITION 0x6 /* Sleep transition in progress */ +#define BRD_HIBERNATION 0x7 /* MPU initiated hibernation */ +#define BRD_RETENTION 0x8 /* Retention mode */ +#define BRD_DSP_HIBERNATION 0x9 /* DSP initiated hibernation */ +#define BRD_ERROR 0xA /* Board state is Error */ + typedef u32 BRD_STATUS; + +/* BRD Object */ + struct BRD_OBJECT; + +#endif /* BRDDEFS_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/cfg.h b/arch/arm/plat-omap/include/dspbridge/cfg.h new file mode 100644 index 0000000..68db842 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/cfg.h @@ -0,0 +1,339 @@ +/* + * cfg.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== cfg.h ======== + * Purpose: + * PM Configuration module. + * + * Private Functions: + * CFG_Exit + * CFG_GetAutoStart + * CFG_GetCDVersion + * CFG_GetDevObject + * CFG_GetDSPResources + * CFG_GetExecFile + * CFG_GetHostResources + * CFG_GetObject + * CFG_GetPerfValue + * CFG_GetWMDFileName + * CFG_GetZLFile + * CFG_Init + * CFG_SetDevObject + * CFG_SetObject + * + *! Revision History: + *! ================= + *! 26-Feb-2003 kc Removed unused CFG fxns. + *! 28-Aug-2001 jeh Added CFG_GetLoaderName. + *! 26-Jul-2000 rr: Added CFG_GetDCDName to retrieve the DCD Dll name. + *! 13-Jul-2000 rr: Added CFG_GetObject & CFG_SetObject. + *! 13-Jan-2000 rr: CFG_Get/SetPrivateDword renamed to CFG_Get/SetDevObject. + *! CFG_GetWinBRIDGEDir/Directory,CFG_GetSearchPath removed. + *! 15-Jan-1998 cr: Code review cleanup. + *! 16-Aug-1997 cr: Added explicit cdecl identifiers. + *! 12-Dec-1996 gp: Moved CFG_FindInSearchPath to CSP module. + *! 13-Sep-1996 gp: Added CFG_GetBoardName(). + *! 22-Jul-1996 gp: Added CFG_GetTraceStr, to retrieve an initial GT trace. + *! 26-Jun-1996 cr: Added CFG_FindInSearchPath. + *! 25-Jun-1996 cr: Added CFG_GetWinSPOXDir. + *! 17-Jun-1996 cr: Added CFG_GetDevNode. + *! 11-Jun-1996 cr: Cleaned up for code review. + *! 07-Jun-1996 cr: Added CFG_GetExecFile and CFG_GetZLFileName functions. + *! 04-Jun-1996 gp: Added AutoStart regkey and accessor function. Placed + *! OUT parameters in accessor function param. lists at end. + *! 29-May-1996 gp: Moved DEV_HDEVNODE to here and renamed CFG_HDEVNODE. + *! 22-May-1996 cr: Added GetHostResources, GetDSPResources, and + *! GetWMDFileName services. + *! 18-May-1996 gp: Created. + */ + +#ifndef CFG_ +#define CFG_ +#include +#include + +/* + * ======== CFG_Exit ======== + * Purpose: + * Discontinue usage of the CFG module. + * Parameters: + * Returns: + * Requires: + * CFG_Init(void) was previously called. + * Ensures: + * Resources acquired in CFG_Init(void) are freed. + */ + extern void CFG_Exit(void); + +/* + * ======== CFG_GetAutoStart ======== + * Purpose: + * Retreive the autostart mask, if any, for this board. + * Parameters: + * hDevNode: Handle to the DevNode who's WMD we are querying. + * pdwAutoStart: Ptr to location for 32 bit autostart mask. + * Returns: + * DSP_SOK: Success. + * CFG_E_INVALIDHDEVNODE: hDevNode is invalid. + * CFG_E_RESOURCENOTAVAIL: Unable to retreive resource. + * Requires: + * CFG initialized. + * Ensures: + * DSP_SOK: *pdwAutoStart contains autostart mask for this devnode. + */ + extern DSP_STATUS CFG_GetAutoStart(IN struct CFG_DEVNODE *hDevNode, + OUT u32 *pdwAutoStart); + +/* + * ======== CFG_GetCDVersion ======== + * Purpose: + * Retrieves the version of the PM Class Driver. + * Parameters: + * pdwVersion: Ptr to u32 to contain version number upon return. + * Returns: + * DSP_SOK: Success. pdwVersion contains Class Driver version in + * the form: 0xAABBCCDD where AABB is Major version and + * CCDD is Minor. + * DSP_EFAIL: Failure. + * Requires: + * CFG initialized. + * Ensures: + * DSP_SOK: Success. + * else: *pdwVersion is NULL. + */ + extern DSP_STATUS CFG_GetCDVersion(OUT u32 *pdwVersion); + +/* + * ======== CFG_GetDevObject ======== + * Purpose: + * Retrieve the Device Object handle for a given devnode. + * Parameters: + * hDevNode: Platform's DevNode handle from which to retrieve value. + * pdwValue: Ptr to location to store the value. + * Returns: + * DSP_SOK: Success. + * CFG_E_INVALIDHDEVNODE: hDevNode is invalid. + * CFG_E_INVALIDPOINTER: phDevObject is invalid. + * CFG_E_RESOURCENOTAVAIL: The resource is not available. + * Requires: + * CFG initialized. + * Ensures: + * DSP_SOK: *pdwValue is set to the retrieved u32. + * else: *pdwValue is set to 0L. + */ + extern DSP_STATUS CFG_GetDevObject(IN struct CFG_DEVNODE *hDevNode, + OUT u32 *pdwValue); + +/* + * ======== CFG_GetDSPResources ======== + * Purpose: + * Get the DSP resources available to a given device. + * Parameters: + * hDevNode: Handle to the DEVNODE who's resources we are querying. + * pDSPResTable: Ptr to a location to store the DSP resource table. + * Returns: + * DSP_SOK: On success. + * CFG_E_INVALIDHDEVNODE: hDevNode is invalid. + * CFG_E_RESOURCENOTAVAIL: The DSP Resource information is not + * available + * Requires: + * CFG initialized. + * Ensures: + * DSP_SOK: pDSPResTable points to a filled table of resources allocated + * for the specified WMD. + */ + extern DSP_STATUS CFG_GetDSPResources(IN struct CFG_DEVNODE *hDevNode, + OUT struct CFG_DSPRES *pDSPResTable); + + +/* + * ======== CFG_GetExecFile ======== + * Purpose: + * Retreive the default executable, if any, for this board. + * Parameters: + * hDevNode: Handle to the DevNode who's WMD we are querying. + * cBufSize: Size of buffer. + * pstrExecFile: Ptr to character buf to hold ExecFile. + * Returns: + * DSP_SOK: Success. + * CFG_E_INVALIDHDEVNODE: hDevNode is invalid. + * CFG_E_INVALIDPOINTER: pstrExecFile is invalid. + * CFG_E_RESOURCENOTAVAIL: The resource is not available. + * Requires: + * CFG initialized. + * Ensures: + * DSP_SOK: Not more than cBufSize bytes were copied into pstrExecFile, + * and *pstrExecFile contains default executable for this + * devnode. + */ + extern DSP_STATUS CFG_GetExecFile(IN struct CFG_DEVNODE *hDevNode, + IN u32 cBufSize, + OUT char *pstrExecFile); + +/* + * ======== CFG_GetHostResources ======== + * Purpose: + * Get the Host PC allocated resources assigned to a given device. + * Parameters: + * hDevNode: Handle to the DEVNODE who's resources we are querying. + * pHostResTable: Ptr to a location to store the host resource table. + * Returns: + * DSP_SOK: On success. + * CFG_E_INVALIDPOINTER: pHostResTable is invalid. + * CFG_E_INVALIDHDEVNODE: hDevNode is invalid. + * CFG_E_RESOURCENOTAVAIL: The resource is not available. + * Requires: + * CFG initialized. + * Ensures: + * DSP_SOK: pHostResTable points to a filled table of resources + * allocated for the specified WMD. + * + */ + extern DSP_STATUS CFG_GetHostResources(IN struct CFG_DEVNODE *hDevNode, + OUT struct CFG_HOSTRES *pHostResTable); + +/* + * ======== CFG_GetObject ======== + * Purpose: + * Retrieve the Driver Object handle From the Registry + * Parameters: + * pdwValue: Ptr to location to store the value. + * dwType Type of Object to Get + * Returns: + * DSP_SOK: Success. + * Requires: + * CFG initialized. + * Ensures: + * DSP_SOK: *pdwValue is set to the retrieved u32(non-Zero). + * else: *pdwValue is set to 0L. + */ + extern DSP_STATUS CFG_GetObject(OUT u32 *pdwValue, u32 dwType); + +/* + * ======== CFG_GetPerfValue ======== + * Purpose: + * Retrieve a flag indicating whether PERF should log statistics for the + * PM class driver. + * Parameters: + * pfEnablePerf: Location to store flag. 0 indicates the key was + * not found, or had a zero value. A nonzero value + * means the key was found and had a nonzero value. + * Returns: + * Requires: + * pfEnablePerf != NULL; + * Ensures: + */ + extern void CFG_GetPerfValue(OUT bool *pfEnablePerf); + +/* + * ======== CFG_GetWMDFileName ======== + * Purpose: + * Get the mini-driver file name for a given device. + * Parameters: + * hDevNode: Handle to the DevNode who's WMD we are querying. + * cBufSize: Size of buffer. + * pWMDFileName: Ptr to a character buffer to hold the WMD filename. + * Returns: + * DSP_SOK: On success. + * CFG_E_INVALIDHDEVNODE: hDevNode is invalid. + * CFG_E_RESOURCENOTAVAIL: The filename is not available. + * Requires: + * CFG initialized. + * Ensures: + * DSP_SOK: Not more than cBufSize bytes were copied + * into pWMDFileName. + * + */ + extern DSP_STATUS CFG_GetWMDFileName(IN struct CFG_DEVNODE *hDevNode, + IN u32 cBufSize, + OUT char *pWMDFileName); + +/* + * ======== CFG_GetZLFile ======== + * Purpose: + * Retreive the ZLFile, if any, for this board. + * Parameters: + * hDevNode: Handle to the DevNode who's WMD we are querying. + * cBufSize: Size of buffer. + * pstrZLFileName: Ptr to character buf to hold ZLFileName. + * Returns: + * DSP_SOK: Success. + * CFG_E_INVALIDPOINTER: pstrZLFileName is invalid. + * CFG_E_INVALIDHDEVNODE: hDevNode is invalid. + * CFG_E_RESOURCENOTAVAIL: couldn't find the ZLFileName. + * Requires: + * CFG initialized. + * Ensures: + * DSP_SOK: Not more than cBufSize bytes were copied into + * pstrZLFileName, and *pstrZLFileName contains ZLFileName + * for this devnode. + */ + extern DSP_STATUS CFG_GetZLFile(IN struct CFG_DEVNODE *hDevNode, + IN u32 cBufSize, + OUT char *pstrZLFileName); + +/* + * ======== CFG_Init ======== + * Purpose: + * Initialize the CFG module's private state. + * Parameters: + * Returns: + * TRUE if initialized; FALSE if error occured. + * Requires: + * Ensures: + * A requirement for each of the other public CFG functions. + */ + extern bool CFG_Init(void); + +/* + * ======== CFG_SetDevObject ======== + * Purpose: + * Store the Device Object handle for a given devnode. + * Parameters: + * hDevNode: Platform's DevNode handle we are storing value with. + * dwValue: Arbitrary value to store. + * Returns: + * DSP_SOK: Success. + * CFG_E_INVALIDHDEVNODE: hDevNode is invalid. + * DSP_EFAIL: Internal Error. + * Requires: + * CFG initialized. + * Ensures: + * DSP_SOK: The Private u32 was successfully set. + */ + extern DSP_STATUS CFG_SetDevObject(IN struct CFG_DEVNODE *hDevNode, + IN u32 dwValue); + +/* + * ======== CFG_SetDrvObject ======== + * Purpose: + * Store the Driver Object handle. + * Parameters: + * dwValue: Arbitrary value to store. + * dwType Type of Object to Store + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Internal Error. + * Requires: + * CFG initialized. + * Ensures: + * DSP_SOK: The Private u32 was successfully set. + */ + extern DSP_STATUS CFG_SetObject(IN u32 dwValue, IN u32 dwType); + +#endif /* CFG_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/cfgdefs.h b/arch/arm/plat-omap/include/dspbridge/cfgdefs.h new file mode 100644 index 0000000..4f78d82 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/cfgdefs.h @@ -0,0 +1,126 @@ +/* + * cfgdefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== cfgdefs.h ======== + * Purpose: + * Global CFG constants and types, shared between class and mini driver. + * + *! Revision History: + *! ================ + *! 24-Feb-2003 kc Removed wIOPort* in CFG_HOSTRES. + *! 06-Sep-2000 jeh Added channel info to CFG_HOSTRES. + *! 09-May-2000 rr: CFG_HOSTRES now support multiple windows for PCI support. + *! 31-Jan-2000 rr: Comments changed after code review. + *! 06-Jan-2000 rr: Bus Type included in CFG_HOSTRES. + *! 12-Nov-1999 rr: CFG_HOSTRES member names changed. + *! 25-Oct-1999 rr: Modified the CFG_HOSTRES Structure + *! PCMCIA ISR Register/Unregister fxn removed.. + *! New flag PCCARD introduced during compile time. + *! 10-Sep-1999 ww: Added PCMCIA ISR Register/Unregister fxn. + *! 01-Sep-1999 ag: Removed NT/95 specific fields in CFG_HOSTRES + *! 27-Oct-1997 cr: Updated CFG_HOSTRES struct to support 1+ IRQs per board. + *! 17-Sep-1997 gp: Tacked some NT config info to end of CFG_HOSTRES structure. + *! 12-Dec-1996 cr: Cleaned up after code review. + *! 14-Nov-1996 gp: Renamed from wsxcfg.h + *! 19-Jun-1996 cr: Created. + */ + +#ifndef CFGDEFS_ +#define CFGDEFS_ + +/* Maximum length of module search path. */ +#define CFG_MAXSEARCHPATHLEN 255 + +/* Maximum length of general paths. */ +#define CFG_MAXPATH 255 + +/* Host Resources: */ +#define CFG_MAXMEMREGISTERS 9 +#define CFG_MAXIOPORTS 20 +#define CFG_MAXIRQS 7 +#define CFG_MAXDMACHANNELS 7 + +/* IRQ flag */ +#define CFG_IRQSHARED 0x01 /* IRQ can be shared */ + +/* DSP Resources: */ +#define CFG_DSPMAXMEMTYPES 10 +#define CFG_DEFAULT_NUM_WINDOWS 1 /* We support only one window. */ + +/* A platform-related device handle: */ + struct CFG_DEVNODE; + +/* + * Host resource structure. + */ + struct CFG_HOSTRES { + u32 wNumMemWindows; /* Set to default */ + /* This is the base.memory */ + u32 dwMemBase[CFG_MAXMEMREGISTERS]; /* SHM virtual address */ + u32 dwMemLength[CFG_MAXMEMREGISTERS]; /* Length of the Base */ + u32 dwMemPhys[CFG_MAXMEMREGISTERS]; /* SHM Physical address */ + u8 bIRQRegisters; /* IRQ Number */ + u8 bIRQAttrib; /* IRQ Attribute */ + u32 dwOffsetForMonitor; /* The Shared memory starts from + * dwMemBase + this offset */ + u32 dwBusType; /* Bus type for this device */ + u32 dwProgBase; /* DSP ProgBase */ + u32 dwProgLength; /* DSP ProgBase Length */ + u32 dwRegBase; /* DSP memory mapped register base */ + u32 dwRegLength; /* DSP Register Base Length */ + u32 ClientHandle; /* Client Handle */ + u32 SocketHandle; /* Socket and Function Pair */ + u32 CardInfo; /* This will be used as a context data in + * in the CardRequestIRQ */ + /* + * Info needed by NODE for allocating channels to communicate with RMS: + * dwChnlOffset: Offset of RMS channels. Lower channels are + * reserved. + * dwChnlBufSize: Size of channel buffer to send to RMS + * dwNumChnls: Total number of channels (including reserved). + */ + u32 dwChnlOffset; + u32 dwChnlBufSize; + u32 dwNumChnls; + u32 dwPrmBase; + u32 dwCmBase; + u32 dwPerBase; + u32 dwPerPmBase; + u32 dwCorePmBase; + u32 dwWdTimerDspBase; + u32 dwMboxBase; + u32 dwDmmuBase; + u32 dwDipiBase; + u32 dwSysCtrlBase; + } ; + + struct CFG_DSPMEMDESC { + u32 uMemType; /* Type of memory. */ + u32 ulMin; /* Minimum amount of memory of this type. */ + u32 ulMax; /* Maximum amount of memory of this type. */ + } ; + + struct CFG_DSPRES { + u32 uChipType; /* DSP chip type. */ + u32 uWordSize; /* Number of bytes in a word */ + u32 cChips; /* Number of chips. */ + u32 cMemTypes; /* Types of memory. */ + struct CFG_DSPMEMDESC aMemDesc[CFG_DSPMAXMEMTYPES]; + /* DSP Memory types */ + } ; + +#endif /* CFGDEFS_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/chnl.h b/arch/arm/plat-omap/include/dspbridge/chnl.h new file mode 100644 index 0000000..f39e3f4 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/chnl.h @@ -0,0 +1,170 @@ +/* + * chnl.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== chnl.h ======== + * Description: + * WCD channel interface: multiplexes data streams through the single + * physical link managed by a mini-driver. + * + * Public Functions: + * CHNL_AddIOReq + * CHNL_AllocBuffer + * CHNL_CancelIO + * CHNL_Close + * CHNL_CloseOrphans + * CHNL_Create + * CHNL_Destroy + * CHNL_Exit + * CHNL_FlushIO + * CHNL_FreeBuffer + * CHNL_GetEventHandle + * CHNL_GetHandle + * CHNL_GetIOCompletion + * CHNL_GetId + * CHNL_GetMgr + * CHNL_GetMode + * CHNL_GetPosition + * CHNL_GetProcessHandle + * CHNL_Init + * CHNL_Open + * + * Notes: + * See DSP API chnl.h for more details. + * + *! Revision History: + *! ================ + *! 14-Jan-1997 gp: Updated based on code review feedback. + *! 24-Oct-1996 gp: Move CloseOrphans into here from dspsys. + *! 09-Sep-1996 gp: Added CHNL_GetProcessID() and CHNL_GetHandle(). + *! 10-Jul-1996 gp: Created. + */ + +#ifndef CHNL_ +#define CHNL_ + +#include + +/* + * ======== CHNL_Close ======== + * Purpose: + * Ensures all pending I/O on this channel is cancelled, discards all + * queued I/O completion notifications, then frees the resources allocated + * for this channel, and makes the corresponding logical channel id + * available for subsequent use. + * Parameters: + * hChnl: Channel object handle. + * Returns: + * DSP_SOK: Success; + * DSP_EHANDLE: Invalid hChnl. + * Requires: + * CHNL_Init(void) called. + * No thread must be blocked on this channel's I/O completion event. + * Ensures: + * DSP_SOK: The I/O completion event for this channel is freed. + * hChnl is no longer valid. + */ + extern DSP_STATUS CHNL_Close(struct CHNL_OBJECT *hChnl); + + +/* + * ======== CHNL_Create ======== + * Purpose: + * Create a channel manager object, responsible for opening new channels + * and closing old ones for a given board. + * Parameters: + * phChnlMgr: Location to store a channel manager object on output. + * hDevObject: Handle to a device object. + * pMgrAttrs: Channel manager attributes. + * pMgrAttrs->cChannels: Max channels + * pMgrAttrs->bIRQ: Channel's I/O IRQ number. + * pMgrAttrs->fShared: TRUE if the IRQ is shareable. + * pMgrAttrs->uWordSize: DSP Word size in equivalent PC bytes.. + * Returns: + * DSP_SOK: Success; + * DSP_EHANDLE: hDevObject is invalid. + * DSP_EINVALIDARG: cChannels is 0. + * DSP_EMEMORY: Insufficient memory for requested resources. + * CHNL_E_ISR: Unable to plug channel ISR for configured IRQ. + * CHNL_E_MAXCHANNELS: This manager cannot handle this many channels. + * CHNL_E_INVALIDIRQ: Invalid IRQ number. Must be 0 <= bIRQ <= 15. + * CHNL_E_INVALIDWORDSIZE: Invalid DSP word size. Must be > 0. + * CHNL_E_INVALIDMEMBASE: Invalid base address for DSP communications. + * CHNL_E_MGREXISTS: Channel manager already exists for this device. + * Requires: + * CHNL_Init(void) called. + * phChnlMgr != NULL. + * pMgrAttrs != NULL. + * Ensures: + * DSP_SOK: Subsequent calls to CHNL_Create() for the same + * board without an intervening call to + * CHNL_Destroy() will fail. + */ + extern DSP_STATUS CHNL_Create(OUT struct CHNL_MGR **phChnlMgr, + struct DEV_OBJECT *hDevObject, + IN CONST struct CHNL_MGRATTRS *pMgrAttrs); + +/* + * ======== CHNL_Destroy ======== + * Purpose: + * Close all open channels, and destroy the channel manager. + * Parameters: + * hChnlMgr: Channel manager object. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: hChnlMgr was invalid. + * Requires: + * CHNL_Init(void) called. + * Ensures: + * DSP_SOK: Cancels I/O on each open channel. + * Closes each open channel. + * CHNL_Create may subsequently be called for the + * same board. + */ + extern DSP_STATUS CHNL_Destroy(struct CHNL_MGR *hChnlMgr); + +/* + * ======== CHNL_Exit ======== + * Purpose: + * Discontinue usage of the CHNL module. + * Parameters: + * Returns: + * Requires: + * CHNL_Init(void) previously called. + * Ensures: + * Resources, if any acquired in CHNL_Init(void), are freed when the last + * client of CHNL calls CHNL_Exit(void). + */ + extern void CHNL_Exit(void); + + +/* + * ======== CHNL_Init ======== + * Purpose: + * Initialize the CHNL module's private state. + * Parameters: + * Returns: + * TRUE if initialized; FALSE if error occurred. + * Requires: + * Ensures: + * A requirement for each of the other public CHNL functions. + */ + extern bool CHNL_Init(void); + + + +#endif /* CHNL_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/chnl_sm.h b/arch/arm/plat-omap/include/dspbridge/chnl_sm.h new file mode 100644 index 0000000..789b9bd --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/chnl_sm.h @@ -0,0 +1,168 @@ +/* + * chnl_sm.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== chnl_sm.h ======== + * Description: + * Prototypes for channel lower edge functions for a WinBRIDGE mini driver + * implementing data transfer via shared memory. + * + * Public Functions: + * CHNLSM_DisableInterrupt; + * CHNLSM_EnableInterrupt; + * CHNLSM_ISR; + * CHNLSM_Read; + * CHNLSM_UpdateSHMLength; + * CHNLSM_Write; + * + * Notes: + * These lower edge functions must be implemented by the WMD writer. + * Currently, CHNLSM_Read() and CHNLSM_Write() are not called, but must + * be defined to link. + * + */ + +#ifndef CHNLSM_ +#define CHNLSM_ + +#include + +/* + * ======== CHNLSM_DisableInterrupt ======== + * Purpose: + * Disable interrupts from the DSP board to the PC. + * Parameters: + * hDevContext: Handle to mini-driver defined device info. + * Returns: + * Requires: + * Ensures: + */ + extern DSP_STATUS CHNLSM_DisableInterrupt(struct WMD_DEV_CONTEXT* + hDevContext); + +/* + * ======== CHNLSM_EnableInterrupt ======== + * Purpose: + * Enable interrupts from the DSP board to the PC. + * Parameters: + * hDevContext: Handle to mini-driver defined device info. + * Returns: + * Requires: + * Ensures: + */ + extern DSP_STATUS CHNLSM_EnableInterrupt(struct WMD_DEV_CONTEXT* + hDevContext); + +/* + * ======== CHNLSM_InterruptDSP2 ======== + * Purpose: + * Set interrupt value & send an interrupt to the DSP processor(s). + * This is typicaly used when mailbox interrupt mechanisms allow data + * to be associated with interrupt such as for OMAP's CMD/DATA regs. + * Parameters: + * hDevContext: Handle to mini-driver defined device info. + * wMbVal: Value associated with interrupt(e.g. mailbox value). + * Returns: + * DSP_SOK: Interrupt sent; + * else: Unable to send interrupt. + * Requires: + * Ensures: + */ + extern DSP_STATUS CHNLSM_InterruptDSP2(struct WMD_DEV_CONTEXT* + hDevContext, u16 wMbVal); + +/* + * ======== CHNLSM_ISR ======== + * Purpose: + * Mini-driver's ISR, called by WCD when the board interrupts the host. + * Parameters: + * hDevContext: Handle to the mini-driver defined device info. + * pfSchedDPC: Set to TRUE to schedule a deferred procedure call + * to advance the channel protocol. The channel class + * library will call the WMD's CHNLSM_DPC routine during + * its own DPC, before dispatching I/O. + * The channel class library should ignore *pfSchedDPC when + * CHNLSM_ISR returns FALSE. + * pwMBRegVal: Value of mailbox register. + * Returns: + * TRUE if this interrupt is was generated by the DSP board. + * FALSE otherwise. + * Requires: + * Interrupts to the host processor are disabled on entry. + * Must only call functions which are in page locked memory. + * Must only call asynchronous OS services. + * The EOI for this interrupt has already been sent to the PIC. + * Ensures: + * If the interrupt is *not* shared, this routine must return TRUE. + */ + extern bool CHNLSM_ISR(struct WMD_DEV_CONTEXT *hDevContext, + OUT bool *pfSchedDPC, + OUT u16 *pwIntrVal); + +/* + * ======== CHNLSM_Read ======== + * Purpose: + * Read data from DSP board memory into a Host buffer. + * Parameters: + * hDevContext: Handle to mini-driver defined device info. + * pHostBuf: Pointer to host buffer (Destination). + * dwDSPAddr: Address on DSP board (Source). + * ulNumBytes: Number of bytes to transfer. + * Returns: + * Requires: + * Ensures: + */ + extern DSP_STATUS CHNLSM_Read(struct WMD_DEV_CONTEXT *hDevContext, + OUT u8 *pHostBuf, + u32 dwDSPAddr, u32 ulNumBytes); + +/* + * ======== CHNLSM_UpdateSHMLength ======== + * Purpose: + * Allow the minidriver a chance to override the SHM length as reported + * to the mini driver (chnl_sm.lib) by Windows Plug and Play. + * Parameters: + * hDevContext: Handle to mini-driver defined device info. + * pSHMLength: Pointer to size of SHM window (in DSP words). + * Returns: + * TRUE if pSHMLength updated; FALSE otherwise. + * Requires: + * pSHMLength != NULL. + * Ensures: + * No more than sizeof(u32) bytes written to *pSHMLength + */ + extern bool CHNLSM_UpdateSHMLength(struct WMD_DEV_CONTEXT *hDevContext, + IN OUT u32 *pSHMLength); + +/* + * ======== CHNLSM_Write ======== + * Purpose: + * Write data from a Host buffer to DSP board memory. + * Parameters: + * hDevContext: Handle to mini-driver defined device info. + * pHostBuf: Pointer to host buffer (Source). + * dwDSPAddr: Address on DSP board (Destination). + * ulNumBytes: Number of bytes to transfer. + * Returns: + * Requires: + * Ensures: + */ + extern DSP_STATUS CHNLSM_Write(struct WMD_DEV_CONTEXT *hDevContext, + IN u8 *pHostBuf, + u32 dwDSPAddr, u32 ulNumBytes); + +#endif /* CHNLSM_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/chnldefs.h b/arch/arm/plat-omap/include/dspbridge/chnldefs.h new file mode 100644 index 0000000..9f59229 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/chnldefs.h @@ -0,0 +1,92 @@ +/* + * chnldefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== chnldefs.h ======== + * Purpose: + * System-wide channel objects and constants. + * + *! Revision History: + *! ================ + *! 19-Jan-2002 ag Added cBufSize to IOC. + *! 05-Jan-2000 ag: Text format cleanup. + *! 02-Dec-1999 ag: Added new chnl attribute pstrEventName. + *! 12-Nov-1999 kc: Enabled hEvent attribute for tests. + *! 01-Nov-1999 ag: hEvent attribute not supported(yet). + *! 16-Jan-1997 gp: Moved private stuff into chnlpriv.h + *! 14-Jan-1997 gp: Updated based on code review feedback: + *! Removed CHNL_MODENOWAIT, CHNL_MODEDIRECT, + *! 03-Jan-1997 gp: Added channel class library types. + *! 14-Dec-1996 gp: Moved uChnlId field from CHNL_ATTRS to CHNL_Open(). + *! 10-Dec-1996 gp: Added CHNL_IsTimedOut() macro. + *! 14-Nov-1996 gp: Renamed from wsxchnl.h. + *! 09-Sep-1996 gp: Added hReserved2 field to CHNL_ATTRS. Updated CHNL_INFO. + *! 10-Jul-1996 gp: Created from channel.h. + */ + +#ifndef CHNLDEFS_ +#define CHNLDEFS_ + +/* Channel id option. */ +#define CHNL_PICKFREE (~0UL) /* Let manager pick a free channel. */ + +/* Channel manager limits: */ +#define CHNL_INITIOREQS 4 /* Default # of I/O requests. */ + +/* Channel modes */ +#define CHNL_MODETODSP 0x0000 /* Data streaming to the DSP. */ +#define CHNL_MODEFROMDSP 0x0001 /* Data streaming from the DSP. */ + +/* GetIOCompletion flags */ +#define CHNL_IOCINFINITE 0xffffffff /* Wait forever for IO completion. */ +#define CHNL_IOCNOWAIT 0x0 /* Dequeue an IOC, if available. */ + +/* IO Completion Record status: */ +#define CHNL_IOCSTATCOMPLETE 0x0000 /* IO Completed. */ +#define CHNL_IOCSTATCANCEL 0x0002 /* IO was cancelled */ +#define CHNL_IOCSTATTIMEOUT 0x0008 /* Wait for IOC timed out. */ +#define CHNL_IOCSTATEOS 0x8000 /* End Of Stream reached. */ + +/* Macros for checking I/O Completion status: */ +#define CHNL_IsEOS(ioc) (ioc.status & CHNL_IOCSTATEOS) +#define CHNL_IsIOComplete(ioc) (!(ioc.status & ~CHNL_IOCSTATEOS)) +#define CHNL_IsIOCancelled(ioc) (ioc.status & CHNL_IOCSTATCANCEL) +#define CHNL_IsTimedOut(ioc) (ioc.status & CHNL_IOCSTATTIMEOUT) + +/* CHNL types: */ + typedef u32 CHNL_MODE; /* Channel transfer mode. */ + +/* Channel attributes: */ + struct CHNL_ATTRS { + u32 uIOReqs; /* Max # of preallocated I/O requests. */ + HANDLE hEvent; /* User supplied auto-reset event object. */ + char *pstrEventName; /* Ptr to name of user event object. */ + HANDLE hReserved1; /* Reserved for future use. */ + u32 hReserved2; /* Reserved for future use. */ + + }; + +/* I/O completion record: */ + struct CHNL_IOC { + void *pBuf; /* Buffer to be filled/emptied. */ + u32 cBytes; /* Bytes transferred. */ + u32 cBufSize; /* Actual buffer size in bytes */ + u32 status; /* Status of IO completion. */ + u32 dwArg; /* User argument associated with pBuf. */ + } ; + +#endif /* CHNLDEFS_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/chnlpriv.h b/arch/arm/plat-omap/include/dspbridge/chnlpriv.h new file mode 100644 index 0000000..fdcda24 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/chnlpriv.h @@ -0,0 +1,136 @@ +/* + * chnlpriv.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== chnlpriv.h ======== + * Description: + * Private channel header shared between DSPSYS, WCD and WMD modules. + * + * Public Functions: + * None. + * + * Notes: + * + *! Revision History: + *! ================ + *! 05-Jan-2002 ag Added cChannels(total # of chnls) to CHNL_MGRINFO struct. + *! Added private CHNL_[PCPY][ZCPY][DDMA]. + *! 17-Nov-2000 jeh Removed IRQ, shared memory from CHNL_MGRATTRS, since these + *! now belong to IO_ATTRS. + *! 21-Jan-2000 ag: Code review comments added. + *! 05-Jan-2000 ag: Text format cleanup. + *! 11-Dec-1999 ag: Added CHNL_MAXLOCKPAGES for CHNL_PrepareBuffer(). + *! 04-Dec-1999 ag: Added CHNL_MAXEVTNAMELEN for i/o compl named event support. + *! 01-Nov-1999 ag: CHNL_MAXCHANNELS set to 16 for 16-bit DSPs. + *! 27-Oct-1997 cr: Expanded CHNL_MAXIRQ from 0x0f to 0xff. + *! 16-Jan-1997 gp: Moved symbols into here from chnldefs.h. + *! 03-Jan-1997 gp: Added CHNL_MAXIRQ define. + *! 09-Dec-1996 gp: Removed CHNL_STATEIDLE. + *! 15-Jul-1996 gp: Created. + */ + +#ifndef CHNLPRIV_ +#define CHNLPRIV_ + +#include +#include +#include + +/* CHNL Object validation signatures: */ +#define CHNL_MGRSIGNATURE 0x52474D43 /* "CMGR" (in reverse). */ +#define CHNL_SIGNATURE 0x4C4E4843 /* "CHNL" (in reverse). */ + +/* Channel manager limits: */ +#define CHNL_MAXCHANNELS 32 /* Max channels available per transport */ + + +/* + * Trans port channel Id definitions:(must match dsp-side). + * + * For CHNL_MAXCHANNELS = 16: + * + * ChnlIds: + * 0-15 (PCPY) - transport 0) + * 16-31 (DDMA) - transport 1) + * 32-47 (ZCPY) - transport 2) + */ +#define CHNL_PCPY 0 /* Proc-copy transport 0 */ + +#define CHNL_MAXIRQ 0xff /* Arbitrarily large number. */ + +/* The following modes are private: */ +#define CHNL_MODEUSEREVENT 0x1000 /* User provided the channel event. */ +#define CHNL_MODEMASK 0x1001 + +/* Higher level channel states: */ +#define CHNL_STATEREADY 0x0000 /* Channel ready for I/O. */ +#define CHNL_STATECANCEL 0x0001 /* I/O was cancelled. */ +#define CHNL_STATEEOS 0x0002 /* End Of Stream reached. */ + +/* Determine if user supplied an event for this channel: */ +#define CHNL_IsUserEvent(mode) (mode & CHNL_MODEUSEREVENT) + +/* Macros for checking mode: */ +#define CHNL_IsInput(mode) (mode & CHNL_MODEFROMDSP) +#define CHNL_IsOutput(mode) (!CHNL_IsInput(mode)) + +/* Types of channel class libraries: */ +#define CHNL_TYPESM 1 /* Shared memory driver. */ +#define CHNL_TYPEBM 2 /* Bus Mastering driver. */ + +/* Max string length of channel I/O completion event name - change if needed */ +#define CHNL_MAXEVTNAMELEN 32 + +/* Max memory pages lockable in CHNL_PrepareBuffer() - change if needed */ +#define CHNL_MAXLOCKPAGES 64 + +/* Channel info. */ + struct CHNL_INFO { + struct CHNL_MGR *hChnlMgr; /* Owning channel manager. */ + u32 dwID; /* Channel ID. */ + HANDLE hEvent; /* Channel I/O completion event. */ + /*Abstraction of I/O completion event.*/ + struct SYNC_OBJECT *hSyncEvent; + u32 dwMode; /* Channel mode. */ + u32 dwState; /* Current channel state. */ + u32 cPosition; /* Total bytes transferred. */ + u32 cIOCs; /* Number of IOCs in queue. */ + u32 cIOReqs; /* Number of IO Requests in queue. */ + u32 hProcess; /* Process owning this channel. */ + /* + * Name of channel I/O completion event. Not required in Linux + */ + char szEventName[CHNL_MAXEVTNAMELEN + 1]; + } ; + +/* Channel manager info: */ + struct CHNL_MGRINFO { + u32 dwType; /* Type of channel class library. */ + /* Channel handle, given the channel id. */ + struct CHNL_OBJECT *hChnl; + u32 cOpenChannels; /* Number of open channels. */ + u32 cChannels; /* total # of chnls supported */ + } ; + +/* Channel Manager Attrs: */ + struct CHNL_MGRATTRS { + /* Max number of channels this manager can use. */ + u32 cChannels; + u32 uWordSize; /* DSP Word size. */ + } ; + +#endif /* CHNLPRIV_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/clk.h b/arch/arm/plat-omap/include/dspbridge/clk.h new file mode 100644 index 0000000..4a23dab --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/clk.h @@ -0,0 +1,155 @@ +/* + * clk.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== clk.h ======== + * Purpose: Provides Clock functions. + * + *! Revision History: + *! ================ + *! 08-May-2007 rg: Moved all clock functions from sync module. + */ + +#ifndef _CLK_H +#define _CLK_H + + /* Generic TIMER object: */ + struct TIMER_OBJECT; + enum SERVICES_ClkId { + SERVICESCLK_iva2_ck = 0, + SERVICESCLK_mailbox_ick, + SERVICESCLK_gpt5_fck, + SERVICESCLK_gpt5_ick, + SERVICESCLK_gpt6_fck, + SERVICESCLK_gpt6_ick, + SERVICESCLK_gpt7_fck, + SERVICESCLK_gpt7_ick, + SERVICESCLK_gpt8_fck, + SERVICESCLK_gpt8_ick, + SERVICESCLK_wdt3_fck, + SERVICESCLK_wdt3_ick, + SERVICESCLK_mcbsp1_fck, + SERVICESCLK_mcbsp1_ick, + SERVICESCLK_mcbsp2_fck, + SERVICESCLK_mcbsp2_ick, + SERVICESCLK_mcbsp3_fck, + SERVICESCLK_mcbsp3_ick, + SERVICESCLK_mcbsp4_fck, + SERVICESCLK_mcbsp4_ick, + SERVICESCLK_mcbsp5_fck, + SERVICESCLK_mcbsp5_ick, + SERVICESCLK_ssi_fck, + SERVICESCLK_ssi_ick, + SERVICESCLK_sys_32k_ck, + SERVICESCLK_sys_ck, + SERVICESCLK_NOT_DEFINED + } ; + +/* + * ======== CLK_Exit ======== + * Purpose: + * Discontinue usage of module; free resources when reference count + * reaches 0. + * Parameters: + * Returns: + * Requires: + * CLK initialized. + * Ensures: + * Resources used by module are freed when cRef reaches zero. + */ + extern void CLK_Exit(void); + +/* + * ======== CLK_Init ======== + * Purpose: + * Initializes private state of CLK module. + * Parameters: + * Returns: + * TRUE if initialized; FALSE if error occured. + * Requires: + * Ensures: + * CLK initialized. + */ + extern bool CLK_Init(void); + + +/* + * ======== CLK_Enable ======== + * Purpose: + * Enables the clock requested. + * Parameters: + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Error occured while enabling the clock. + * Requires: + * Ensures: + */ + extern DSP_STATUS CLK_Enable(IN enum SERVICES_ClkId clk_id); + +/* + * ======== CLK_Disable ======== + * Purpose: + * Disables the clock requested. + * Parameters: + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Error occured while disabling the clock. + * Requires: + * Ensures: + */ + extern DSP_STATUS CLK_Disable(IN enum SERVICES_ClkId clk_id); + +/* + * ======== CLK_GetRate ======== + * Purpose: + * Get the clock rate of requested clock. + * Parameters: + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Error occured while Getting the clock rate. + * Requires: + * Ensures: + */ + extern DSP_STATUS CLK_GetRate(IN enum SERVICES_ClkId clk_id, + u32 *speedMhz); +/* + * ======== CLK_Set_32KHz ======== + * Purpose: + * Set the requested clock to 32KHz. + * Parameters: + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Error occured while setting the clock parent to 32KHz. + * Requires: + * Ensures: + */ + extern DSP_STATUS CLK_Set_32KHz(IN enum SERVICES_ClkId clk_id); + extern void SSI_Clk_Prepare(bool FLAG); + +/* + * ======== CLK_Get_RefCnt ======== + * Purpose: + * get the reference count for the clock. + * Parameters: + * Returns: + * s32: Reference Count for the clock. + * DSP_EFAIL: Error occured while getting the reference count of a clock. + * Requires: + * Ensures: + */ + extern s32 CLK_Get_UseCnt(IN enum SERVICES_ClkId clk_id); + +#endif /* _SYNC_H */ diff --git a/arch/arm/plat-omap/include/dspbridge/cmm.h b/arch/arm/plat-omap/include/dspbridge/cmm.h new file mode 100644 index 0000000..0df8b83 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/cmm.h @@ -0,0 +1,420 @@ +/* + * cmm.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== cmm.h ======== + * Purpose: + * The Communication Memory Management(CMM) module provides shared memory + * management services for DSP/BIOS Bridge data streaming and messaging. + * Multiple shared memory segments can be registered with CMM. Memory is + * coelesced back to the appropriate pool when a buffer is freed. + * + * The CMM_Xlator[xxx] functions are used for node messaging and data + * streaming address translation to perform zero-copy inter-processor + * data transfer(GPP<->DSP). A "translator" object is created for a node or + * stream object that contains per thread virtual address information. This + * translator info is used at runtime to perform SM address translation + * to/from the DSP address space. + * + * + * Public Functions: + * CMM_CallocBuf + * CMM_Create + * CMM_Destroy + * CMM_Exit + * CMM_FreeBuf + * CMM_GetHandle + * CMM_GetInfo + * CMM_Init + * CMM_RegisterGPPSMSeg + * CMM_UnRegisterGPPSMSeg + * CMM_XlatorAllocBuf (Note #1 below) + * CMM_XlatorCreate " + * CMM_XlatorDelete " + * CMM_XlatorFreeBuf " + * CMM_XlatorTranslate " + * + * + * Notes: + * #1: Used by Node and Stream modules for SM address translation. + * + *! Revision History: + *! ================ + *! 30-Jan-2002 ag Removed unused CMM_Alloc[Free]Desc & CMM_XlatorRegisterPa. + *! Renamed CMM_AllocBuf() to CMM_CallocBuf(). + *! 29-Aug-2001 ag: Added dsp virt base and size to CMM_RegisterGPPSMSeg(). + *! 12-Aug-2001 ag: Added CMM_UnRegisterGPP[DSP}SMSeg[s](). + *! 05-Dec-2000 ag: Added param to CMM_XlatorDelete() to force buf cleanup. + *! 30-Oct-2000 ag: Added conversion factor to CMM_RegisterDSP[GPP]SMSeg(). + *! 12-Oct-2000 ag: Added CMM_Xlator[xxx] functions. + *! 10-Aug-2000 ag: Created. + *! + */ + +#ifndef CMM_ +#define CMM_ + +#include + +#include +#include + +/* + * ======== CMM_CallocBuf ======== + * Purpose: + * Allocate memory buffers that can be used for data streaming or + * messaging. + * Parameters: + * hCmmMgr: Cmm Mgr handle. + * uSize: Number of bytes to allocate. + * pAttr: Attributes of memory to allocate. + * ppBufVA: Address of where to place VA. + * Returns: + * Pointer to a zero'd block of SM memory; + * NULL if memory couldn't be allocated, + * or if cBytes == 0, + * Requires: + * Valid hCmmMgr. + * CMM initialized. + * Ensures: + * The returned pointer, if not NULL, points to a valid memory block of + * the size requested. + * + */ + extern void *CMM_CallocBuf(struct CMM_OBJECT *hCmmMgr, + u32 uSize, struct CMM_ATTRS *pAttrs, + OUT void **ppBufVA); + +/* + * ======== CMM_Create ======== + * Purpose: + * Create a communication memory manager object. + * Parameters: + * phCmmMgr: Location to store a communication manager handle on output. + * hDevObject: Handle to a device object. + * pMgrAttrs: Comm mem manager attributes. + * Returns: + * DSP_SOK: Success; + * DSP_EMEMORY: Insufficient memory for requested resources. + * DSP_EFAIL: Failed to initialize critical sect sync object. + * + * Requires: + * CMM_Init(void) called. + * phCmmMgr != NULL. + * pMgrAttrs->ulMinBlockSize >= 4 bytes. + * Ensures: + * + */ + extern DSP_STATUS CMM_Create(OUT struct CMM_OBJECT **phCmmMgr, + struct DEV_OBJECT *hDevObject, + IN CONST struct CMM_MGRATTRS *pMgrAttrs); + +/* + * ======== CMM_Destroy ======== + * Purpose: + * Destroy the communication memory manager object. + * Parameters: + * hCmmMgr: Cmm Mgr handle. + * bForce: Force deallocation of all cmm memory immediately if set TRUE. + * If FALSE, and outstanding allocations will return DSP_EFAIL + * status. + * Returns: + * DSP_SOK: CMM object & resources deleted. + * DSP_EFAIL: Unable to free CMM object due to outstanding allocation. + * DSP_EHANDLE: Unable to free CMM due to bad handle. + * Requires: + * CMM is initialized. + * hCmmMgr != NULL. + * Ensures: + * Memory resources used by Cmm Mgr are freed. + */ + extern DSP_STATUS CMM_Destroy(struct CMM_OBJECT *hCmmMgr, bool bForce); + +/* + * ======== CMM_Exit ======== + * Purpose: + * Discontinue usage of module. Cleanup CMM module if CMM cRef reaches zero. + * Parameters: + * n/a + * Returns: + * n/a + * Requires: + * CMM is initialized. + * Ensures: + */ + extern void CMM_Exit(void); + +/* + * ======== CMM_FreeBuf ======== + * Purpose: + * Free the given buffer. + * Parameters: + * hCmmMgr: Cmm Mgr handle. + * pBuf: Pointer to memory allocated by CMM_CallocBuf(). + * ulSegId: SM segment Id used in CMM_Calloc() attrs. + * Set to 0 to use default segment. + * Returns: + * DSP_SOK + * DSP_EFAIL + * Requires: + * CMM initialized. + * pBufPA != NULL + * Ensures: + * + */ + extern DSP_STATUS CMM_FreeBuf(struct CMM_OBJECT *hCmmMgr, + void *pBufPA, u32 ulSegId); + +/* + * ======== CMM_GetHandle ======== + * Purpose: + * Return the handle to the cmm mgr for the given device obj. + * Parameters: + * hProcessor: Handle to a Processor. + * phCmmMgr: Location to store the shared memory mgr handle on output. + * + * Returns: + * DSP_SOK: Cmm Mgr opaque handle returned. + * DSP_EHANDLE: Invalid handle. + * Requires: + * phCmmMgr != NULL + * hDevObject != NULL + * Ensures: + */ + extern DSP_STATUS CMM_GetHandle(DSP_HPROCESSOR hProcessor, + OUT struct CMM_OBJECT **phCmmMgr); + +/* + * ======== CMM_GetInfo ======== + * Purpose: + * Return the current SM and VM utilization information. + * Parameters: + * hCmmMgr: Handle to a Cmm Mgr. + * pCmmInfo: Location to store the Cmm information on output. + * + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid handle. + * DSP_EINVALIDARG Invalid input argument. + * Requires: + * Ensures: + * + */ + extern DSP_STATUS CMM_GetInfo(struct CMM_OBJECT *hCmmMgr, + OUT struct CMM_INFO *pCmmInfo); + +/* + * ======== CMM_Init ======== + * Purpose: + * Initializes private state of CMM module. + * Parameters: + * Returns: + * TRUE if initialized; FALSE if error occured. + * Requires: + * Ensures: + * CMM initialized. + */ + extern bool CMM_Init(void); + +/* + * ======== CMM_RegisterGPPSMSeg ======== + * Purpose: + * Register a block of SM with the CMM. + * Parameters: + * hCmmMgr: Handle to a Cmm Mgr. + * lpGPPBasePA: GPP Base Physical address. + * ulSize: Size in GPP bytes. + * dwDSPAddrOffset GPP PA to DSP PA Offset. + * cFactor: Add offset if CMM_ADDTODSPPA, sub if CMM_SUBFROMDSPPA. + * dwDSPBase: DSP virtual base byte address. + * ulDSPSize: Size of DSP segment in bytes. + * pulSegId: Address to store segment Id. + * + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hCmmMgr handle. + * DSP_EINVALIDARG: Invalid input argument. + * DSP_EFAIL: Unable to register. + * - On success *pulSegId is a valid SM segment ID. + * Requires: + * ulSize > 0 + * pulSegId != NULL + * dwGPPBasePA != 0 + * cFactor = CMM_ADDTODSPPA || cFactor = CMM_SUBFROMDSPPA + * Ensures: + * + */ + extern DSP_STATUS CMM_RegisterGPPSMSeg(struct CMM_OBJECT *hCmmMgr, + unsigned int dwGPPBasePA, + u32 ulSize, + u32 dwDSPAddrOffset, + enum CMM_CNVTTYPE cFactor, + unsigned int dwDSPBase, + u32 ulDSPSize, + u32 *pulSegId, + u32 dwGPPBaseBA); + +/* + * ======== CMM_UnRegisterGPPSMSeg ======== + * Purpose: + * Unregister the given memory segment that was previously registered + * by CMM_RegisterGPPSMSeg. + * Parameters: + * hCmmMgr: Handle to a Cmm Mgr. + * ulSegId Segment identifier returned by CMM_RegisterGPPSMSeg. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid handle. + * DSP_EINVALIDARG: Invalid ulSegId. + * DSP_EFAIL: Unable to unregister for unknown reason. + * Requires: + * Ensures: + * + */ + extern DSP_STATUS CMM_UnRegisterGPPSMSeg(struct CMM_OBJECT *hCmmMgr, + u32 ulSegId); + +/* + * ======== CMM_XlatorAllocBuf ======== + * Purpose: + * Allocate the specified SM buffer and create a local memory descriptor. + * Place on the descriptor on the translator's HaQ (Host Alloc'd Queue). + * Parameters: + * hXlator: Handle to a Xlator object. + * pVaBuf: Virtual address ptr(client context) + * uPaSize: Size of SM memory to allocate. + * Returns: + * Ptr to valid physical address(Pa) of uPaSize bytes, NULL if failed. + * Requires: + * pVaBuf != 0. + * uPaSize != 0. + * Ensures: + * + */ + extern void *CMM_XlatorAllocBuf(struct CMM_XLATOROBJECT *hXlator, + void *pVaBuf, u32 uPaSize); + +/* + * ======== CMM_XlatorCreate ======== + * Purpose: + * Create a translator(xlator) object used for process specific Va<->Pa + * address translation. Node messaging and streams use this to perform + * inter-processor(GPP<->DSP) zero-copy data transfer. + * Parameters: + * phXlator: Address to place handle to a new Xlator handle. + * hCmmMgr: Handle to Cmm Mgr associated with this translator. + * pXlatorAttrs: Translator attributes used for the client NODE or STREAM. + * Returns: + * DSP_SOK: Success. + * DSP_EINVALIDARG: Bad input Attrs. + * DSP_EMEMORY: Insufficient memory(local) for requested resources. + * Requires: + * phXlator != NULL + * hCmmMgr != NULL + * pXlatorAttrs != NULL + * Ensures: + * + */ + extern DSP_STATUS CMM_XlatorCreate(OUT struct CMM_XLATOROBJECT **phXlator, + struct CMM_OBJECT *hCmmMgr, + struct CMM_XLATORATTRS *pXlatorAttrs); + +/* + * ======== CMM_XlatorDelete ======== + * Purpose: + * Delete translator resources + * Parameters: + * hXlator: handle to translator. + * bForce: bForce = TRUE will free XLators SM buffers/dscriptrs. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Bad translator handle. + * DSP_EFAIL: Unable to free translator resources. + * Requires: + * cRefs > 0 + * Ensures: + * + */ + extern DSP_STATUS CMM_XlatorDelete(struct CMM_XLATOROBJECT *hXlator, + bool bForce); + +/* + * ======== CMM_XlatorFreeBuf ======== + * Purpose: + * Free SM buffer and descriptor. + * Does not free client process VM. + * Parameters: + * hXlator: handle to translator. + * pBufVa Virtual address of PA to free. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Bad translator handle. + * Requires: + * Ensures: + * + */ + extern DSP_STATUS CMM_XlatorFreeBuf(struct CMM_XLATOROBJECT *hXlator, + void *pBufVa); + +/* + * ======== CMM_XlatorInfo ======== + * Purpose: + * Set/Get process specific "translator" address info. + * This is used to perform fast virtaul address translation + * for shared memory buffers between the GPP and DSP. + * Parameters: + * hXlator: handle to translator. + * pAddr: Virtual base address of segment. + * ulSize: Size in bytes. + * uSegId: Segment identifier of SM segment(s) + * bSetInfo Set xlator fields if TRUE, else return base addr + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Bad translator handle. + * Requires: + * (cRefs > 0) + * (pAddr != NULL) + * (ulSize > 0) + * Ensures: + * + */ + extern DSP_STATUS CMM_XlatorInfo(struct CMM_XLATOROBJECT *hXlator, + IN OUT u8 **pAddr, + u32 ulSize, u32 uSegId, + bool bSetInfo); + +/* + * ======== CMM_XlatorTranslate ======== + * Purpose: + * Perform address translation VA<->PA for the specified stream or + * message shared memory buffer. + * Parameters: + * hXlator: handle to translator. + * pAddr address of buffer to translate. + * xType Type of address xlation. CMM_PA2VA or CMM_VA2PA. + * Returns: + * Valid address on success, else NULL. + * Requires: + * cRefs > 0 + * pAddr != NULL + * xType >= CMM_VA2PA) && (xType <= CMM_DSPPA2PA) + * Ensures: + * + */ + extern void *CMM_XlatorTranslate(struct CMM_XLATOROBJECT *hXlator, + void *pAddr, enum CMM_XLATETYPE xType); + +#endif /* CMM_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/cmmdefs.h b/arch/arm/plat-omap/include/dspbridge/cmmdefs.h new file mode 100644 index 0000000..a779377 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/cmmdefs.h @@ -0,0 +1,135 @@ +/* + * cmmdefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== cmmdefs.h ======== + * Purpose: + * Global MEM constants and types. + * + *! Revision History: + *! ================ + *! 12-Nov-2001 ag CMM_KERNMAPTYPE added for dsp<->device process addr map'n. + *! This allows addr conversion from drvr process <-> DSP addr. + *! 29-Aug-2001 ag Added CMM_ALLSEGMENTS. + *! 08-Dec-2000 ag Added bus address conversion type CMM_POMAPEMIF2DSPBUS. + *! 05-Dec-2000 ag Added default CMM_DEFLTCONVFACTOR & CMM_DEFLTDSPADDROFFSET. + *! 29-Oct-2000 ag Added converstion factor for GPP DSP Pa translation. + *! 15-Oct-2000 ag Added address translator attributes and defaults. + *! 12-Jul-2000 ag Created. + */ + +#ifndef CMMDEFS_ +#define CMMDEFS_ + +#include + +/* Cmm attributes used in CMM_Create() */ + struct CMM_MGRATTRS { + /* Minimum SM allocation; default 32 bytes. */ + u32 ulMinBlockSize; + } ; + +/* Attributes for CMM_AllocBuf() & CMM_AllocDesc() */ + struct CMM_ATTRS { + u32 ulSegId; /* 1,2... are SM segments. 0 is not. */ + u32 ulAlignment; /* 0,1,2,4....ulMinBlockSize */ + } ; + +/* + * DSPPa to GPPPa Conversion Factor. + * + * For typical platforms: + * converted Address = PaDSP + ( cFactor * addressToConvert). + */ + enum CMM_CNVTTYPE { + CMM_SUBFROMDSPPA = -1, + /* PreOMAP is special case: not simple offset */ + CMM_POMAPEMIF2DSPBUS = 0, + CMM_ADDTODSPPA = 1 + } ; + +#define CMM_DEFLTDSPADDROFFSET 0 +#define CMM_DEFLTCONVFACTOR CMM_POMAPEMIF2DSPBUS /* PreOMAP DSPBUS<->EMIF */ +#define CMM_ALLSEGMENTS 0xFFFFFF /* All SegIds */ +#define CMM_MAXGPPSEGS 1 /* Maximum # of SM segs */ + +/* + * SMSEGs are SM segments the DSP allocates from. + * + * This info is used by the GPP to xlate DSP allocated PAs. + */ + + struct CMM_SEGINFO { + u32 dwSegBasePa; /* Start Phys address of SM segment */ + /* Total size in bytes of segment: DSP+GPP */ + u32 ulTotalSegSize; + u32 dwGPPBasePA; /* Start Phys addr of Gpp SM seg */ + u32 ulGPPSize; /* Size of Gpp SM seg in bytes */ + u32 dwDSPBaseVA; /* DSP virt base byte address */ + u32 ulDSPSize; /* DSP seg size in bytes */ + /* # of current GPP allocations from this segment */ + u32 ulInUseCnt; + u32 dwSegBaseVa; /* Start Virt address of SM seg */ + + } ; + +/* CMM useful information */ + struct CMM_INFO { + /* # of SM segments registered with this Cmm. */ + u32 ulNumGPPSMSegs; + /* Total # of allocations outstanding for CMM */ + u32 ulTotalInUseCnt; + /* Min SM block size allocation from CMM_Create() */ + u32 ulMinBlockSize; + /* Info per registered SM segment. */ + struct CMM_SEGINFO segInfo[CMM_MAXGPPSEGS]; + } ; + +/* XlatorCreate attributes */ + struct CMM_XLATORATTRS { + u32 ulSegId; /* segment Id used for SM allocations */ + u32 dwDSPBufs; /* # of DSP-side bufs */ + u32 dwDSPBufSize; /* size of DSP-side bufs in GPP bytes */ + /* Vm base address alloc'd in client process context */ + void *pVmBase; + /* dwVmSize must be >= (dwMaxNumBufs * dwMaxSize) */ + u32 dwVmSize; + } ; + +/* + * Cmm translation types. Use to map SM addresses to process context. + */ + enum CMM_XLATETYPE { + CMM_VA2PA = 0, /* Virtual to GPP physical address xlation */ + CMM_PA2VA = 1, /* GPP Physical to virtual */ + CMM_VA2DSPPA = 2, /* Va to DSP Pa */ + CMM_PA2DSPPA = 3, /* GPP Pa to DSP Pa */ + CMM_DSPPA2PA = 4, /* DSP Pa to GPP Pa */ + } ; + +/* + * Used to "map" between device process virt addr and dsp addr. + */ + enum CMM_KERNMAPTYPE { + CMM_KERNVA2DSP = 0, /* Device process context to dsp address. */ + CMM_DSP2KERNVA = 1, /* Dsp address to device process context. */ + } ; + + struct CMM_OBJECT; + struct CMM_XLATOROBJECT; + +#endif /* CMMDEFS_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/cod.h b/arch/arm/plat-omap/include/dspbridge/cod.h new file mode 100644 index 0000000..a8a12c6 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/cod.h @@ -0,0 +1,433 @@ +/* + * cod.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== cod.h ======== + * Description: + * Code management module for DSPs. This module provides an interface + * interface for loading both static and dynamic code objects onto DSP + * systems. + * + * Public Functions: + * COD_Close + * COD_Create + * COD_Delete + * COD_Exit + * COD_GetBaseLib + * COD_GetBaseName + * COD_GetLoader + * COD_GetSection + * COD_GetSymValue + * COD_Init + * COD_LoadBase + * COD_Open + * COD_OpenBase + * COD_ReadSection + * COD_UnloadSection + * + * Note: + * Currently, only static loading is supported. + * + *! Revision History + *! ================ + *! 08-Apr-2003 map: Changed DBL to DBLL + *! 07-Aug-2002 jeh: Added COD_GetBaseName(). + *! 17-Jul-2002 jeh: Added COD_Open(), COD_Close(). + *! 15-Mar-2002 jeh: Added DBL_Flags param to COD_OpenBase(). + *! 19-Oct-2001 jeh: Added COD_GetBaseLib, COD_GetLoader, (left in + *! COD_LoadSection(), COD_UnloadSection(), since they + *! may be needed for BridgeLite). + *! 07-Sep-2001 jeh: Added COD_LoadSection(), COD_UnloadSection(). + *! 11-Jan-2001 jeh: Added COD_OpenBase. + *! 29-Sep-2000 kc: Added size param to COD_ReadSection for input buffer + *! validation. + *! 02-Aug-2000 kc: Added COD_ReadSection. + *! 04-Sep-1997 gp: Added CDECL identifier to COD_WRITEFXN (for NT).. + *! 18-Aug-1997 cr: Added explicit CDECL identifier. + *! 28-Oct-1996 gp: Added COD_GetSection. + *! 30-Jul-1996 gp: Added envp[] argument to COD_LoadBase(). + *! 12-Jun-1996 gp: Moved OUT param first in _Create(). Updated _Create() + *! call to take a ZLFileName. Moved COD_ processor types + *! to CFG. + *! 29-May-1996 gp: Changed WCD_STATUS to DSP_STATUS. Removed include's. + *! 07-May-1996 mg: Created. + * + */ + +#ifndef COD_ +#define COD_ + +#include + +#define COD_MAXPATHLENGTH 255 +#define COD_TRACEBEG "SYS_PUTCBEG" +#define COD_TRACEEND "SYS_PUTCEND" +#define COD_TRACESECT "trace" +#define COD_TRACEBEGOLD "PUTCBEG" +#define COD_TRACEENDOLD "PUTCEND" + +#define COD_NOLOAD DBLL_NOLOAD +#define COD_SYMB DBLL_SYMB + +/* Flags passed to COD_Open */ + typedef DBLL_Flags COD_FLAGS; + +/* COD code manager handle */ + struct COD_MANAGER; + +/* COD library handle */ + struct COD_LIBRARYOBJ; + +/* COD attributes */ + struct COD_ATTRS { + u32 ulReserved; + } ; + +/* + * Function prototypes for writing memory to a DSP system, allocating + * and freeing DSP memory. + */ + typedef u32(*COD_WRITEFXN) (void *pPrivRef, u32 ulDspAddr, + void *pBuf, u32 ulNumBytes, + u32 nMemSpace); + + +/* + * ======== COD_Close ======== + * Purpose: + * Close a library opened with COD_Open(). + * Parameters: + * lib - Library handle returned by COD_Open(). + * Returns: + * None. + * Requires: + * COD module initialized. + * valid lib. + * Ensures: + * + */ + extern void COD_Close(struct COD_LIBRARYOBJ *lib); + +/* + * ======== COD_Create ======== + * Purpose: + * Create an object to manage code on a DSP system. This object can be + * used to load an initial program image with arguments that can later + * be expanded with dynamically loaded object files. + * Symbol table information is managed by this object and can be retrieved + * using the COD_GetSymValue() function. + * Parameters: + * phManager: created manager object + * pstrZLFile: ZL DLL filename, of length < COD_MAXPATHLENGTH. + * attrs: attributes to be used by this object. A NULL value + * will cause default attrs to be used. + * Returns: + * DSP_SOK: Success. + * COD_E_NOZLFUNCTIONS: Could not initialize ZL functions. + * COD_E_ZLCREATEFAILED: ZL_Create failed. + * DSP_ENOTIMPL: attrs was not NULL. We don't yet support + * non default values of attrs. + * Requires: + * COD module initialized. + * pstrZLFile != NULL + * Ensures: + */ + extern DSP_STATUS COD_Create(OUT struct COD_MANAGER **phManager, + char *pstrZLFile, + IN OPTIONAL CONST struct COD_ATTRS *attrs); + +/* + * ======== COD_Delete ======== + * Purpose: + * Delete a code manager object. + * Parameters: + * hManager: handle of manager to be deleted + * Returns: + * None. + * Requires: + * COD module initialized. + * valid hManager. + * Ensures: + */ + extern void COD_Delete(struct COD_MANAGER *hManager); + +/* + * ======== COD_Exit ======== + * Purpose: + * Discontinue usage of the COD module. + * Parameters: + * None. + * Returns: + * None. + * Requires: + * COD initialized. + * Ensures: + * Resources acquired in COD_Init(void) are freed. + */ + extern void COD_Exit(void); + +/* + * ======== COD_GetBaseLib ======== + * Purpose: + * Get handle to the base image DBL library. + * Parameters: + * hManager: handle of manager to be deleted + * plib: location to store library handle on output. + * Returns: + * DSP_SOK: Success. + * Requires: + * COD module initialized. + * valid hManager. + * plib != NULL. + * Ensures: + */ + extern DSP_STATUS COD_GetBaseLib(struct COD_MANAGER *hManager, + struct DBLL_LibraryObj **plib); + +/* + * ======== COD_GetBaseName ======== + * Purpose: + * Get the name of the base image DBL library. + * Parameters: + * hManager: handle of manager to be deleted + * pszName: location to store library name on output. + * uSize: size of name buffer. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Buffer too small. + * Requires: + * COD module initialized. + * valid hManager. + * pszName != NULL. + * Ensures: + */ + extern DSP_STATUS COD_GetBaseName(struct COD_MANAGER *hManager, + char *pszName, u32 uSize); + +/* + * ======== COD_GetEntry ======== + * Purpose: + * Retrieve the entry point of a loaded DSP program image + * Parameters: + * hManager: handle of manager to be deleted + * pulEntry: pointer to location for entry point + * Returns: + * DSP_SOK: Success. + * Requires: + * COD module initialized. + * valid hManager. + * pulEntry != NULL. + * Ensures: + */ + extern DSP_STATUS COD_GetEntry(struct COD_MANAGER *hManager, + u32 *pulEntry); + +/* + * ======== COD_GetLoader ======== + * Purpose: + * Get handle to the DBL loader. + * Parameters: + * hManager: handle of manager to be deleted + * phLoader: location to store loader handle on output. + * Returns: + * DSP_SOK: Success. + * Requires: + * COD module initialized. + * valid hManager. + * phLoader != NULL. + * Ensures: + */ + extern DSP_STATUS COD_GetLoader(struct COD_MANAGER *hManager, + struct DBLL_TarObj **phLoader); + +/* + * ======== COD_GetSection ======== + * Purpose: + * Retrieve the starting address and length of a section in the COFF file + * given the section name. + * Parameters: + * lib Library handle returned from COD_Open(). + * pstrSect: name of the section, with or without leading "." + * puAddr: Location to store address. + * puLen: Location to store length. + * Returns: + * DSP_SOK: Success + * COD_E_NOSYMBOLSLOADED: Symbols have not been loaded onto the board. + * COD_E_SYMBOLNOTFOUND: The symbol could not be found. + * Requires: + * COD module initialized. + * valid hManager. + * pstrSect != NULL; + * puAddr != NULL; + * puLen != NULL; + * Ensures: + * DSP_SOK: *puAddr and *puLen contain the address and length of the + * section. + * else: *puAddr == 0 and *puLen == 0; + * + */ + extern DSP_STATUS COD_GetSection(struct COD_LIBRARYOBJ *lib, + IN char *pstrSect, + OUT u32 *puAddr, + OUT u32 *puLen); + +/* + * ======== COD_GetSymValue ======== + * Purpose: + * Retrieve the value for the specified symbol. The symbol is first + * searched for literally and then, if not found, searched for as a + * C symbol. + * Parameters: + * lib: library handle returned from COD_Open(). + * pstrSymbol: name of the symbol + * value: value of the symbol + * Returns: + * DSP_SOK: Success. + * COD_E_NOSYMBOLSLOADED: Symbols have not been loaded onto the board. + * COD_E_SYMBOLNOTFOUND: The symbol could not be found. + * Requires: + * COD module initialized. + * Valid hManager. + * pstrSym != NULL. + * pulValue != NULL. + * Ensures: + */ + extern DSP_STATUS COD_GetSymValue(struct COD_MANAGER *hManager, + IN char *pstrSym, + OUT u32 *pulValue); + +/* + * ======== COD_Init ======== + * Purpose: + * Initialize the COD module's private state. + * Parameters: + * None. + * Returns: + * TRUE if initialized; FALSE if error occured. + * Requires: + * Ensures: + * A requirement for each of the other public COD functions. + */ + extern bool COD_Init(void); + +/* + * ======== COD_LoadBase ======== + * Purpose: + * Load the initial program image, optionally with command-line arguments, + * on the DSP system managed by the supplied handle. The program to be + * loaded must be the first element of the args array and must be a fully + * qualified pathname. + * Parameters: + * hMgr: manager to load the code with + * nArgc: number of arguments in the args array + * args: array of strings for arguments to DSP program + * writeFxn: board-specific function to write data to DSP system + * pArb: arbitrary pointer to be passed as first arg to writeFxn + * envp: array of environment strings for DSP exec. + * Returns: + * DSP_SOK: Success. + * COD_E_OPENFAILED: Failed to open target code. + * COD_E_LOADFAILED: Failed to load code onto target. + * Requires: + * COD module initialized. + * hMgr is valid. + * nArgc > 0. + * aArgs != NULL. + * aArgs[0] != NULL. + * pfnWrite != NULL. + * Ensures: + */ + extern DSP_STATUS COD_LoadBase(struct COD_MANAGER *hManager, + u32 nArgc, char *aArgs[], + COD_WRITEFXN pfnWrite, void *pArb, + char *envp[]); + + +/* + * ======== COD_Open ======== + * Purpose: + * Open a library for reading sections. Does not load or set the base. + * Parameters: + * hMgr: manager to load the code with + * pszCoffPath: Coff file to open. + * flags: COD_NOLOAD (don't load symbols) or COD_SYMB (load + * symbols). + * pLib: Handle returned that can be used in calls to COD_Close + * and COD_GetSection. + * Returns: + * S_OK: Success. + * COD_E_OPENFAILED: Failed to open target code. + * Requires: + * COD module initialized. + * hMgr is valid. + * flags == COD_NOLOAD || flags == COD_SYMB. + * pszCoffPath != NULL. + * Ensures: + */ + extern DSP_STATUS COD_Open(struct COD_MANAGER *hMgr, + IN char *pszCoffPath, + COD_FLAGS flags, + OUT struct COD_LIBRARYOBJ **pLib); + +/* + * ======== COD_OpenBase ======== + * Purpose: + * Open base image for reading sections. Does not load the base. + * Parameters: + * hMgr: manager to load the code with + * pszCoffPath: Coff file to open. + * flags: Specifies whether to load symbols. + * Returns: + * DSP_SOK: Success. + * COD_E_OPENFAILED: Failed to open target code. + * Requires: + * COD module initialized. + * hMgr is valid. + * pszCoffPath != NULL. + * Ensures: + */ +extern DSP_STATUS COD_OpenBase(struct COD_MANAGER *hMgr, IN char *pszCoffPath, + DBLL_Flags flags); + +/* + * ======== COD_ReadSection ======== + * Purpose: + * Retrieve the content of a code section given the section name. + * Parameters: + * hManager - manager in which to search for the symbol + * pstrSect - name of the section, with or without leading "." + * pstrContent - buffer to store content of the section. + * Returns: + * DSP_SOK: on success, error code on failure + * COD_E_NOSYMBOLSLOADED: Symbols have not been loaded onto the board. + * COD_E_READFAILED: Failed to read content of code section. + * Requires: + * COD module initialized. + * valid hManager. + * pstrSect != NULL; + * pstrContent != NULL; + * Ensures: + * DSP_SOK: *pstrContent stores the content of the named section. + */ + extern DSP_STATUS COD_ReadSection(struct COD_LIBRARYOBJ *lib, + IN char *pstrSect, + OUT char *pstrContent, + IN u32 cContentSize); + + + +#endif /* COD_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/csl.h b/arch/arm/plat-omap/include/dspbridge/csl.h new file mode 100644 index 0000000..b90d6ff --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/csl.h @@ -0,0 +1,135 @@ +/* + * csl.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== csl.h ======== + * Purpose: + * Platform independent C Standard library functions. + * + * Public Functions: + * CSL_AnsiToWchar + * CSL_ByteSwap + * CSL_Exit + * CSL_Init + * CSL_NumToAscii + * CSL_Strtok + * CSL_Strtokr + * CSL_WcharToAnsi + * + *! Revision History: + *! ================ + *! 07-Aug-2002 jeh: Added CSL_Strtokr(). + *! 21-Sep-2001 jeh: Added CSL_Strncmp. + *! 22-Nov-2000 map: Added CSL_Atoi and CSL_Strtok + *! 19-Nov-2000 kc: Added CSL_ByteSwap(). + *! 09-Nov-2000 kc: Added CSL_Strncat. + *! 29-Oct-1999 kc: Added CSL_Wstrlen(). + *! 20-Sep-1999 ag: Added CSL_Wchar2Ansi(). + *! 19-Jan-1998 cr: Code review cleanup (mostly documentation fixes). + *! 29-Dec-1997 cr: Changed CSL_lowercase to CSL_Uppercase, added + *! CSL_AnsiToWchar. + *! 30-Sep-1997 cr: Added explicit cdecl descriptors to fxn definitions. + *! 25-Jun-1997 cr: Added CSL_strcmp. + *! 12-Jun-1996 gp: Created. + */ + +#ifndef CSL_ +#define CSL_ + +#include + +/* + * ======== CSL_Exit ======== + * Purpose: + * Discontinue usage of the CSL module. + * Parameters: + * Returns: + * Requires: + * CSL initialized. + * Ensures: + * Resources acquired in CSL_Init(void) are freed. + */ + extern void CSL_Exit(void); + +/* + * ======== CSL_Init ======== + * Purpose: + * Initialize the CSL module's private state. + * Parameters: + * Returns: + * TRUE if initialized; FALSE if error occured. + * Requires: + * Ensures: + * A requirement for each of the other public CSL functions. + */ + extern bool CSL_Init(void); + +/* + * ======== CSL_NumToAscii ======== + * Purpose: + * Convert a 1 or 2 digit number to a 2 digit string. + * Parameters: + * pstrNumber: Buffer to store converted string. + * dwNum: Number to convert. + * Returns: + * Requires: + * pstrNumber must be able to hold at least three characters. + * Ensures: + * pstrNumber will be null terminated. + */ + extern void CSL_NumToAscii(OUT char *pstrNumber, IN u32 dwNum); + + +/* + * ======== CSL_Strtok ======== + * Purpose: + * Tokenize a NULL terminated string + * Parameters: + * ptstrSrc: pointer to string. + * szSeparators: pointer to a string of seperators + * Returns: + * char * + * Requires: + * CSL initialized. + * ptstrSrc is a valid string pointer. + * szSeparators is a valid string pointer. + * Ensures: + */ + extern char *CSL_Strtok(IN char *ptstrSrc, + IN CONST char *szSeparators); + +/* + * ======== CSL_Strtokr ======== + * Purpose: + * Re-entrant version of strtok. + * Parameters: + * pstrSrc: Pointer to string. May be NULL on subsequent calls. + * szSeparators: Pointer to a string of seperators + * ppstrCur: Location to store start of string for next call to + * to CSL_Strtokr. + * Returns: + * char * (the token) + * Requires: + * CSL initialized. + * szSeparators != NULL + * ppstrCur != NULL + * Ensures: + */ + extern char *CSL_Strtokr(IN char *pstrSrc, + IN CONST char *szSeparators, + OUT char **ppstrCur); + +#endif /* CSL_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/dbc.h b/arch/arm/plat-omap/include/dspbridge/dbc.h new file mode 100644 index 0000000..0e6a67d --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dbc.h @@ -0,0 +1,66 @@ +/* + * dbc.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== dbc.h ======== + * Purpose: + * "Design by Contract" programming macros. + * + * Public Functions: + * DBC_Assert + * DBC_Require + * DBC_Ensure + * + * Notes: + * Requires that the GT->ERROR function has been defaulted to a valid + * error handler for the given execution environment. + * + * Does not require that GT_init() be called. + * + *! Revision History: + *! ================ + *! 11-Aug-2000 ag: Removed include + *! 22-Apr-1996 gp: Created. + */ + +#ifndef DBC_ +#define DBC_ + +#ifndef GT_TRACE +#define GT_TRACE 0 /* 0 = "trace compiled out"; 1 = "trace active" */ +#endif + +/* Assertion Macros: */ +#if GT_TRACE + +#include + +#define DBC_Assert(exp) \ + if (!(exp)) \ + printk("%s, line %d: Assertion (" #exp ") failed.\n", \ + __FILE__, __LINE__) +#define DBC_Require DBC_Assert /* Function Precondition. */ +#define DBC_Ensure DBC_Assert /* Function Postcondition. */ + +#else + +#define DBC_Assert(exp) +#define DBC_Require(exp) +#define DBC_Ensure(exp) + +#endif /* DEBUG */ + +#endif /* DBC_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/dbdcd.h b/arch/arm/plat-omap/include/dspbridge/dbdcd.h new file mode 100644 index 0000000..fbc3870 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dbdcd.h @@ -0,0 +1,388 @@ +/* + * dbdcd.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== dbdcd.h ======== + * Description: + * Defines the DSP/BIOS Bridge Configuration Database (DCD) API. + * + *! Revision History + *! ================ + *! 03-Dec-2003 map Changed DCD_OBJTYPE to DSP_DCDOBJTYPE + *! 24-Feb-2003 kc Updated DCD_AutoUnregister and DCD_GetObjects to simplify + *! DCD implementation. + *! 05-Aug-2002 jeh Added DCD_GetObjects(). + *! 11-Jul-2002 jeh Added DCD_GetDepLibs(), DCD_GetNumDepLibs(). + *! 22-Apr-2002 jeh Added DCD_GetLibraryName(). + *! 03-Apr-2001 sg Changed error names to have DCD_E* format. + *! 13-Feb-2001 kc Name changed from dcdbs.h to dbdcd.h. + *! 12-Dec-2000 kc Added DCD_AutoUnregister. + *! 09-Nov-2000 kc Updated usage of DCD_EnumerateObject. + *! 30-Oct-2000 kc Added DCD_AutoRegister. Updated error DCD error codes. + *! 29-Sep-2000 kc Incorporated code review comments. See + *! /src/reviews/dcd_review.txt. + *! 26-Jul-2000 kc Created. + *! + */ + +#ifndef DBDCD_ +#define DBDCD_ + +#include +#include +#include + +/* + * ======== DCD_AutoRegister ======== + * Purpose: + * This function automatically registers DCD objects specified in a + * special COFF section called ".dcd_register" + * Parameters: + * hDcdMgr: A DCD manager handle. + * pszCoffPath: Pointer to name of COFF file containing DCD + * objects to be registered. + * Returns: + * DSP_SOK: Success. + * DSP_EDCDNOAUTOREGISTER: Unable to find auto-registration section. + * DSP_EDCDREADSECT: Unable to read object code section. + * DSP_EDCDLOADBASE: Unable to load code base. + * DSP_EHANDLE: Invalid DCD_HMANAGER handle.. + * Requires: + * DCD initialized. + * Ensures: + * Note: + * Due to the DCD database construction, it is essential for a DCD-enabled + * COFF file to contain the right COFF sections, especially + * ".dcd_register", which is used for auto registration. + */ + extern DSP_STATUS DCD_AutoRegister(IN struct DCD_MANAGER *hDcdMgr, + IN char *pszCoffPath); + +/* + * ======== DCD_AutoUnregister ======== + * Purpose: + * This function automatically unregisters DCD objects specified in a + * special COFF section called ".dcd_register" + * Parameters: + * hDcdMgr: A DCD manager handle. + * pszCoffPath: Pointer to name of COFF file containing + * DCD objects to be unregistered. + * Returns: + * DSP_SOK: Success. + * DSP_EDCDNOAUTOREGISTER: Unable to find auto-registration section. + * DSP_EDCDREADSECT: Unable to read object code section. + * DSP_EDCDLOADBASE: Unable to load code base. + * DSP_EHANDLE: Invalid DCD_HMANAGER handle.. + * Requires: + * DCD initialized. + * Ensures: + * Note: + * Due to the DCD database construction, it is essential for a DCD-enabled + * COFF file to contain the right COFF sections, especially + * ".dcd_register", which is used for auto unregistration. + */ + extern DSP_STATUS DCD_AutoUnregister(IN struct DCD_MANAGER *hDcdMgr, + IN char *pszCoffPath); + +/* + * ======== DCD_CreateManager ======== + * Purpose: + * This function creates a DCD module manager. + * Parameters: + * pszZlDllName: Pointer to a DLL name string. + * phDcdMgr: A pointer to a DCD manager handle. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Unable to allocate memory for DCD manager handle. + * DSP_EFAIL: General failure. + * Requires: + * DCD initialized. + * pszZlDllName is non-NULL. + * phDcdMgr is non-NULL. + * Ensures: + * A DCD manager handle is created. + */ + extern DSP_STATUS DCD_CreateManager(IN char *pszZlDllName, + OUT struct DCD_MANAGER **phDcdMgr); + +/* + * ======== DCD_DestroyManager ======== + * Purpose: + * This function destroys a DCD module manager. + * Parameters: + * hDcdMgr: A DCD manager handle. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid DCD manager handle. + * Requires: + * DCD initialized. + * Ensures: + */ + extern DSP_STATUS DCD_DestroyManager(IN struct DCD_MANAGER *hDcdMgr); + +/* + * ======== DCD_EnumerateObject ======== + * Purpose: + * This function enumerates currently visible DSP/BIOS Bridge objects + * and returns the UUID and type of each enumerated object. + * Parameters: + * cIndex: The object enumeration index. + * objType: Type of object to enumerate. + * pUuid: Pointer to a DSP_UUID object. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Unable to enumerate through the DCD database. + * DSP_SENUMCOMPLETE: Enumeration completed. This is not an error code. + * Requires: + * DCD initialized. + * pUuid is a valid pointer. + * Ensures: + * Details: + * This function can be used in conjunction with DCD_GetObjectDef to + * retrieve object properties. + */ + extern DSP_STATUS DCD_EnumerateObject(IN s32 cIndex, + IN enum DSP_DCDOBJTYPE objType, + OUT struct DSP_UUID *pUuid); + +/* + * ======== DCD_Exit ======== + * Purpose: + * This function cleans up the DCD module. + * Parameters: + * Returns: + * Requires: + * DCD initialized. + * Ensures: + */ + extern void DCD_Exit(void); + +/* + * ======== DCD_GetDepLibs ======== + * Purpose: + * Given the uuid of a library and size of array of uuids, this function + * fills the array with the uuids of all dependent libraries of the input + * library. + * Parameters: + * hDcdMgr: A DCD manager handle. + * pUuid: Pointer to a DSP_UUID for a library. + * numLibs: Size of uuid array (number of library uuids). + * pDepLibUuids: Array of dependent library uuids to be filled in. + * pPersistentDepLibs: Array indicating if corresponding lib is persistent. + * phase: phase to obtain correct input library + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Memory allocation failure. + * DSP_EDCDREADSECT: Failure to read section containing library info. + * DSP_EFAIL: General failure. + * Requires: + * DCD initialized. + * Valid hDcdMgr. + * pUuid != NULL + * pDepLibUuids != NULL. + * Ensures: + */ + extern DSP_STATUS DCD_GetDepLibs(IN struct DCD_MANAGER *hDcdMgr, + IN struct DSP_UUID *pUuid, + u16 numLibs, + OUT struct DSP_UUID *pDepLibUuids, + OUT bool *pPersistentDepLibs, + IN enum NLDR_PHASE phase); + +/* + * ======== DCD_GetNumDepLibs ======== + * Purpose: + * Given the uuid of a library, determine its number of dependent + * libraries. + * Parameters: + * hDcdMgr: A DCD manager handle. + * pUuid: Pointer to a DSP_UUID for a library. + * pNumLibs: Size of uuid array (number of library uuids). + * pNumPersLibs: number of persistent dependent library. + * phase: Phase to obtain correct input library + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Memory allocation failure. + * DSP_EDCDREADSECT: Failure to read section containing library info. + * DSP_EFAIL: General failure. + * Requires: + * DCD initialized. + * Valid hDcdMgr. + * pUuid != NULL + * pNumLibs != NULL. + * Ensures: + */ + extern DSP_STATUS DCD_GetNumDepLibs(IN struct DCD_MANAGER *hDcdMgr, + IN struct DSP_UUID *pUuid, + OUT u16 *pNumLibs, + OUT u16 *pNumPersLibs, + IN enum NLDR_PHASE phase); + +/* + * ======== DCD_GetLibraryName ======== + * Purpose: + * This function returns the name of a (dynamic) library for a given + * UUID. + * Parameters: + * hDcdMgr: A DCD manager handle. + * pUuid: Pointer to a DSP_UUID that represents a unique DSP/BIOS + * Bridge object. + * pstrLibName: Buffer to hold library name. + * pdwSize: Contains buffer size. Set to string size on output. + * phase: Which phase to load + * fPhaseSplit: Are phases in multiple libraries + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: General failure. + * Requires: + * DCD initialized. + * Valid hDcdMgr. + * pstrLibName != NULL. + * pUuid != NULL + * pdwSize != NULL. + * Ensures: + */ + extern DSP_STATUS DCD_GetLibraryName(IN struct DCD_MANAGER *hDcdMgr, + IN struct DSP_UUID *pUuid, + IN OUT char *pstrLibName, + IN OUT u32 *pdwSize, + IN enum NLDR_PHASE phase, + OUT bool *fPhaseSplit); + +/* + * ======== DCD_GetObjectDef ======== + * Purpose: + * This function returns the properties/attributes of a DSP/BIOS Bridge + * object. + * Parameters: + * hDcdMgr: A DCD manager handle. + * pUuid: Pointer to a DSP_UUID that represents a unique + * DSP/BIOS Bridge object. + * objType: The type of DSP/BIOS Bridge object to be + * referenced (node, processor, etc). + * pObjDef: Pointer to an object definition structure. A + * union of various possible DCD object types. + * Returns: + * DSP_SOK: Success. + * DSP_EDCDPARSESECT: Unable to parse content of object code section. + * DSP_EDCDREADSECT: Unable to read object code section. + * DSP_EDCDGETSECT: Unable to access object code section. + * DSP_EDCDLOADBASE: Unable to load code base. + * DSP_EFAIL: General failure. + * DSP_EHANDLE: Invalid DCD_HMANAGER handle. + * Requires: + * DCD initialized. + * pObjUuid is non-NULL. + * pObjDef is non-NULL. + * Ensures: + */ + extern DSP_STATUS DCD_GetObjectDef(IN struct DCD_MANAGER *hDcdMgr, + IN struct DSP_UUID *pObjUuid, + IN enum DSP_DCDOBJTYPE objType, + OUT struct DCD_GENERICOBJ *pObjDef); + +/* + * ======== DCD_GetObjects ======== + * Purpose: + * This function finds all DCD objects specified in a special + * COFF section called ".dcd_register", and for each object, + * call a "register" function. The "register" function may perform + * various actions, such as 1) register nodes in the node database, 2) + * unregister nodes from the node database, and 3) add overlay nodes. + * Parameters: + * hDcdMgr: A DCD manager handle. + * pszCoffPath: Pointer to name of COFF file containing DCD + * objects. + * registerFxn: Callback fxn to be applied on each located + * DCD object. + * handle: Handle to pass to callback. + * Returns: + * DSP_SOK: Success. + * DSP_EDCDNOAUTOREGISTER: Unable to find .dcd_register section. + * DSP_EDCDREADSECT: Unable to read object code section. + * DSP_EDCDLOADBASE: Unable to load code base. + * DSP_EHANDLE: Invalid DCD_HMANAGER handle.. + * Requires: + * DCD initialized. + * Ensures: + * Note: + * Due to the DCD database construction, it is essential for a DCD-enabled + * COFF file to contain the right COFF sections, especially + * ".dcd_register", which is used for auto registration. + */ + extern DSP_STATUS DCD_GetObjects(IN struct DCD_MANAGER *hDcdMgr, + IN char *pszCoffPath, + DCD_REGISTERFXN registerFxn, + void *handle); + +/* + * ======== DCD_Init ======== + * Purpose: + * This function initializes DCD. + * Parameters: + * Returns: + * FALSE: Initialization failed. + * TRUE: Initialization succeeded. + * Requires: + * Ensures: + * DCD initialized. + */ + extern bool DCD_Init(void); + +/* + * ======== DCD_RegisterObject ======== + * Purpose: + * This function registers a DSP/BIOS Bridge object in the DCD database. + * Parameters: + * pUuid: Pointer to a DSP_UUID that identifies a DSP/BIOS + * Bridge object. + * objType: Type of object. + * pszPathName: Path to the object's COFF file. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Failed to register object. + * Requires: + * DCD initialized. + * pUuid and szPathName are non-NULL values. + * objType is a valid type value. + * Ensures: + */ + extern DSP_STATUS DCD_RegisterObject(IN struct DSP_UUID *pUuid, + IN enum DSP_DCDOBJTYPE objType, + IN char *pszPathName); + +/* + * ======== DCD_UnregisterObject ======== + * Purpose: + * This function de-registers a valid DSP/BIOS Bridge object from the DCD + * database. + * Parameters: + * pUuid: Pointer to a DSP_UUID that identifies a DSP/BIOS Bridge + * object. + * objType: Type of object. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Unable to de-register the specified object. + * Requires: + * DCD initialized. + * pUuid is a non-NULL value. + * objType is a valid type value. + * Ensures: + */ + extern DSP_STATUS DCD_UnregisterObject(IN struct DSP_UUID *pUuid, + IN enum DSP_DCDOBJTYPE objType); + +#endif /* _DBDCD_H */ diff --git a/arch/arm/plat-omap/include/dspbridge/dbdcddef.h b/arch/arm/plat-omap/include/dspbridge/dbdcddef.h new file mode 100644 index 0000000..91b1c45 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dbdcddef.h @@ -0,0 +1,94 @@ +/* + * dbdcddef.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dbdcddef.h ======== + * Description: + * DCD (DSP/BIOS Bridge Configuration Database) constants and types. + * + *! Revision History: + *! ================ + *! 03-Dec-2003 map Moved and renamed DCD_OBJTYPE to DSP_DCDOBJTYPE in dbdefs.h + *! 05-Dec-2002 map Added DCD_CREATELIBTYPE, DCD_EXECUTELIBTYPE, + * DCD_DELETELIBTYPE + *! 24-Feb-2003 kc Updated REG entry names to DspBridge. + *! 22-Nov-2002 gp Cleaned up comments, formatting. + *! 05-Aug-2002 jeh Added DCD_REGISTERFXN. + *! 19-Apr-2002 jeh Added DCD_LIBRARYTYPE to DCD_OBJTYPE, dynamic load + *! properties to DCD_NODEPROPS. + *! 29-Jul-2001 ag Added extended procObj. + *! 13-Feb-2001 kc: Named changed from dcdbsdef.h dbdcddef.h. + *! 12-Dec-2000 jeh Added DAIS iAlg name to DCD_NODEPROPS. + *! 30-Oct-2000 kc: Added #defines for DCD_AutoRegister function. + *! 05-Sep-2000 jeh Added DCD_NODEPROPS. + *! 12-Aug-2000 kc: Incoroporated the use of types defined in . + *! 29-Jul-2000 kc: Created. + */ + +#ifndef DBDCDDEF_ +#define DBDCDDEF_ + +#include +#include /* for MGR_PROCESSOREXTINFO */ + +/* + * The following defines are critical elements for the DCD module: + * + * - DCD_REGKEY enables DCD functions to locate registered DCD objects. + * - DCD_REGISTER_SECTION identifies the COFF section where the UUID of + * registered DCD objects are stored. + */ +#define DCD_REGKEY "Software\\TexasInstruments\\DspBridge\\DCD" +#define DCD_REGISTER_SECTION ".dcd_register" + +/* DCD Manager Object */ + struct DCD_MANAGER; + +/* DCD Node Properties */ + struct DCD_NODEPROPS { + struct DSP_NDBPROPS ndbProps; + u32 uMsgSegid; + u32 uMsgNotifyType; + char *pstrCreatePhaseFxn; + char *pstrDeletePhaseFxn; + char *pstrExecutePhaseFxn; + char *pstrIAlgName; + + /* Dynamic load properties */ + u16 usLoadType; /* Static, dynamic, overlay */ + u32 ulDataMemSegMask; /* Data memory requirements */ + u32 ulCodeMemSegMask; /* Code memory requirements */ + } ; + +/* DCD Generic Object Type */ + struct DCD_GENERICOBJ { + union dcdObjUnion { + struct DCD_NODEPROPS nodeObj; /* node object. */ + /* processor object. */ + struct DSP_PROCESSORINFO procObj; + /* extended proc object (private) */ + struct MGR_PROCESSOREXTINFO extProcObj; + } objData; + } ; + +/* DCD Internal Callback Type */ + typedef DSP_STATUS(*DCD_REGISTERFXN) (IN struct DSP_UUID *pUuid, + IN enum DSP_DCDOBJTYPE objType, + IN void *handle); + +#endif /* DBDCDDEF_ */ + diff --git a/arch/arm/plat-omap/include/dspbridge/dbdefs.h b/arch/arm/plat-omap/include/dspbridge/dbdefs.h new file mode 100644 index 0000000..9782693 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dbdefs.h @@ -0,0 +1,580 @@ +/* + * dbdefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== dbdefs.h ======== + * Description: + * Global definitions and constants for DSP/BIOS Bridge. + * + *! Revision History: + *! ================ + *! 19-Apr-2004 sb Aligned DMM definitions with Symbian + *! 08-Mar-2004 sb Added MAPATTR & ELEM_SIZE for Dynamic Memory Mapping feature + *! 09-Feb-2004 vp Added processor ID numbers for DSP and IVA + *! 06-Feb-2003 kc Removed DSP_POSTMESSAGE. Updated IsValid*Event macros. + *! 22-Nov-2002 gp Cleaned up comments, formatting. + *! Removed unused DSP_ENUMLASTNODE define. + *! 13-Feb-2002 jeh Added uSysStackSize to DSP_NDBPROPS. + *! 23-Jan-2002 ag Added #define DSP_SHMSEG0. + *! 12-Dec-2001 ag Added DSP_ESTRMMODE error code. + *! 04-Dec-2001 jeh Added DSP_ENOTCONNECTED error code. + *! 10-Dec-2001 kc: Modified macros and definitions to disable DSP_POSTMESSAGE. + *! 01-Nov-2001 jeh Added DSP_EOVERLAYMEMORY. + *! 18-Oct-2001 ag Added DSP_STRMMODE type. + *! Added DSP_ENOTSHAREDMEM. + *! 21-Sep-2001 ag Added additional error codes. + *! 07-Jun-2001 sg Made DSPStream_AllocateBuffer fxn name plural. + *! 11-May-2001 jeh Changed DSP_NODE_MIN_PRIORITY from 0 to 1. Removed hNode + *! from DSP_NODEINFO. + *! 02-Apr-2001 sg Added missing error codes, rearranged codes, switched to + *! hex offsets, renamed some codes to match API spec. + *! 16-Jan-2001 jeh Added DSP_ESYMBOL, DSP_EUUID. + *! 13-Feb-2001 kc: DSP/BIOS Bridge name updates. + *! 05-Dec-2000 ag: Added DSP_RMSxxx user available message command codes. + *! 09-Nov-2000 rr: Added DSP_PROCEESORRESTART define; Removed DSP_PBUFFER. + *! Added DSP_DCD_ENOAUTOREGISTER, DSP_EUSER1-16, DSP_ESTRMFUL + *! Removed DSP_EDONE. Macros's modified. + *! 23-Oct-2000 jeh Replaced DSP_STREAMSTATECHANGE with DSP_STREAMDONE. + *! 09-Oct-2000 jeh Updated to version 0.9 DSP Bridge API spec. + *! 29-Sep-2000 kc Added error codes for DCD and REG to simplify use of + *! these codes within the RM module. + *! 27-Sep-2000 jeh Added segid, alignment, uNumBufs to DSP_STREAMATTRIN. + *! 29-Aug-2000 jeh Added DSP_NODETYPE enum, changed DSP_EALREADYATTACHED to + *! DSP_EALREADYCONNECTED. Changed scStreamConnection[1] + *! to scStreamConnection[16] in DSP_NODEINFO structure. + *! Added DSP_NOTIFICATION, DSP_STRMATTR. PSTRING changed + *! back to TCHAR * and moved to dbtype.h. + *! 11-Aug-2000 rr: Macros to check valid events and notify masks added. + *! 09-Aug-2000 rr: Changed PSTRING to *s8 + *! 07-Aug-2000 rr: PROC_IDLE/SYNCINIT/UNKNOWN state removed. + *! 20-Jul-2000 rr: Updated to version 0.8 + *! 17-Jul-2000 rr: New PROC states added to the DSP_PROCSTATE. + *! 27-Jun-2000 rr: Created from dspapi.h + */ + +#ifndef DBDEFS_ +#define DBDEFS_ + +#include + +#include /* GPP side type definitions */ +#include /* DSP/BIOS type definitions */ +#include /* Types shared between GPP and DSP */ + +#define PG_SIZE_4K 4096 +#define PG_MASK(pg_size) (~((pg_size)-1)) +#define PG_ALIGN_LOW(addr, pg_size) ((addr) & PG_MASK(pg_size)) +#define PG_ALIGN_HIGH(addr, pg_size) (((addr)+(pg_size)-1) & PG_MASK(pg_size)) + +/* API return value and calling convention */ +#define DBAPI DSP_STATUS + +/* Infinite time value for the uTimeout parameter to DSPStream_Select() */ +#define DSP_FOREVER (-1) + +/* Maximum length of node name, used in DSP_NDBPROPS */ +#define DSP_MAXNAMELEN 32 + +/* uNotifyType values for the RegisterNotify() functions. */ +#define DSP_SIGNALEVENT 0x00000001 + +/* Types of events for processors */ +#define DSP_PROCESSORSTATECHANGE 0x00000001 +#define DSP_PROCESSORATTACH 0x00000002 +#define DSP_PROCESSORDETACH 0x00000004 +#define DSP_PROCESSORRESTART 0x00000008 + +/* DSP exception events (DSP/BIOS and DSP MMU fault) */ +#define DSP_MMUFAULT 0x00000010 +#define DSP_SYSERROR 0x00000020 +#define DSP_EXCEPTIONABORT 0x00000300 + +/* IVA exception events (IVA MMU fault) */ +#define IVA_MMUFAULT 0x00000040 +/* Types of events for nodes */ +#define DSP_NODESTATECHANGE 0x00000100 +#define DSP_NODEMESSAGEREADY 0x00000200 + +/* Types of events for streams */ +#define DSP_STREAMDONE 0x00001000 +#define DSP_STREAMIOCOMPLETION 0x00002000 + +/* Handle definition representing the GPP node in DSPNode_Connect() calls */ +#define DSP_HGPPNODE 0xFFFFFFFF + +/* Node directions used in DSPNode_Connect() */ +#define DSP_TONODE 1 +#define DSP_FROMNODE 2 + +/* Define Node Minimum and Maximum Priorities */ +#define DSP_NODE_MIN_PRIORITY 1 +#define DSP_NODE_MAX_PRIORITY 15 + +/* Pre-Defined Message Command Codes available to user: */ +#define DSP_RMSUSERCODESTART RMS_USER /* Start of RMS user cmd codes */ +/* end of user codes */ +#define DSP_RMSUSERCODEEND (RMS_USER + RMS_MAXUSERCODES); +#define DSP_RMSBUFDESC RMS_BUFDESC /* MSG contains SM buffer description */ + +/* Shared memory identifier for MEM segment named "SHMSEG0" */ +#define DSP_SHMSEG0 (u32)(-1) + +/* Processor ID numbers */ +#define DSP_UNIT 0 +#define IVA_UNIT 1 + +#define DSPWORD unsigned char +#define DSPWORDSIZE sizeof(DSPWORD) + +/* Success & Failure macros */ +#define DSP_SUCCEEDED(Status) likely((s32)(Status) >= 0) +#define DSP_FAILED(Status) unlikely((s32)(Status) < 0) + +/* Power control enumerations */ +#define PROC_PWRCONTROL 0x8070 + +#define PROC_PWRMGT_ENABLE (PROC_PWRCONTROL + 0x3) +#define PROC_PWRMGT_DISABLE (PROC_PWRCONTROL + 0x4) + +/* Bridge Code Version */ +#define BRIDGE_VERSION_CODE 333 + +#define MAX_PROFILES 16 + +/* Types defined for 'Bridge API */ + typedef u32 DSP_STATUS; /* API return code type */ + + typedef HANDLE DSP_HNODE; /* Handle to a DSP Node object */ + typedef HANDLE DSP_HPROCESSOR; /* Handle to a Processor object */ + typedef HANDLE DSP_HSTREAM; /* Handle to a Stream object */ + + typedef u32 DSP_PROCFAMILY; /* Processor family */ + typedef u32 DSP_PROCTYPE; /* Processor type (w/in family) */ + typedef u32 DSP_RTOSTYPE; /* Type of DSP RTOS */ + +/* Handy Macros */ +#define IsValidProcEvent(x) (((x) == 0) || (((x) & (DSP_PROCESSORSTATECHANGE | \ + DSP_PROCESSORATTACH | \ + DSP_PROCESSORDETACH | \ + DSP_PROCESSORRESTART | \ + DSP_NODESTATECHANGE | \ + DSP_STREAMDONE | \ + DSP_STREAMIOCOMPLETION | \ + DSP_MMUFAULT | \ + DSP_SYSERROR)) && \ + !((x) & ~(DSP_PROCESSORSTATECHANGE | \ + DSP_PROCESSORATTACH | \ + DSP_PROCESSORDETACH | \ + DSP_PROCESSORRESTART | \ + DSP_NODESTATECHANGE | \ + DSP_STREAMDONE | \ + DSP_STREAMIOCOMPLETION | \ + DSP_MMUFAULT | \ + DSP_SYSERROR)))) + +#define IsValidNodeEvent(x) (((x) == 0) || (((x) & (DSP_NODESTATECHANGE | \ + DSP_NODEMESSAGEREADY)) && \ + !((x) & ~(DSP_NODESTATECHANGE | \ + DSP_NODEMESSAGEREADY)))) + +#define IsValidStrmEvent(x) (((x) == 0) || (((x) & (DSP_STREAMDONE | \ + DSP_STREAMIOCOMPLETION)) && \ + !((x) & ~(DSP_STREAMDONE | \ + DSP_STREAMIOCOMPLETION)))) + +#define IsValidNotifyMask(x) ((x) & DSP_SIGNALEVENT) + +/* The Node UUID structure */ + struct DSP_UUID { + u32 ulData1; + u16 usData2; + u16 usData3; + u8 ucData4; + u8 ucData5; + u8 ucData6[6]; + }; + +/* DCD types */ + enum DSP_DCDOBJTYPE { + DSP_DCDNODETYPE, + DSP_DCDPROCESSORTYPE, + DSP_DCDLIBRARYTYPE, + DSP_DCDCREATELIBTYPE, + DSP_DCDEXECUTELIBTYPE, + DSP_DCDDELETELIBTYPE + } ; + +/* Processor states */ + enum DSP_PROCSTATE { + PROC_STOPPED, + PROC_LOADED, + PROC_RUNNING, + PROC_ERROR + } ; + +/* + * Node types: Message node, task node, xDAIS socket node, and + * device node. _NODE_GPP is used when defining a stream connection + * between a task or socket node and the GPP. + * + */ + enum NODE_TYPE { + NODE_DEVICE, + NODE_TASK, + NODE_DAISSOCKET, + NODE_MESSAGE, + NODE_GPP + } ; + +/* + * ======== NODE_STATE ======== + * Internal node states. + */ + enum NODE_STATE { + NODE_ALLOCATED, + NODE_CREATED, + NODE_RUNNING, + NODE_PAUSED, + NODE_DONE, + NODE_CREATING, + NODE_STARTING, + NODE_PAUSING, + NODE_TERMINATING, + NODE_DELETING, + } ; + +/* Stream states */ + enum DSP_STREAMSTATE { + STREAM_IDLE, + STREAM_READY, + STREAM_PENDING, + STREAM_DONE + } ; + +/* Stream connect types */ + enum DSP_CONNECTTYPE { + CONNECTTYPE_NODEOUTPUT, + CONNECTTYPE_GPPOUTPUT, + CONNECTTYPE_NODEINPUT, + CONNECTTYPE_GPPINPUT + } ; + +/* Stream mode types */ + enum DSP_STRMMODE { + STRMMODE_PROCCOPY, /* Processor(s) copy stream data payloads */ + STRMMODE_ZEROCOPY, /* Strm buffer ptrs swapped no data copied */ + STRMMODE_LDMA, /* Local DMA : OMAP's System-DMA device */ + STRMMODE_RDMA /* Remote DMA: OMAP's DSP-DMA device */ + } ; + +/* Resource Types */ + enum DSP_RESOURCEINFOTYPE { + DSP_RESOURCE_DYNDARAM = 0, + DSP_RESOURCE_DYNSARAM, + DSP_RESOURCE_DYNEXTERNAL, + DSP_RESOURCE_DYNSRAM, + DSP_RESOURCE_PROCLOAD + } ; + +/* Memory Segment Types */ + enum DSP_MEMTYPE { + DSP_DYNDARAM = 0, + DSP_DYNSARAM, + DSP_DYNEXTERNAL, + DSP_DYNSRAM + } ; + +/* Memory Flush Types */ + enum DSP_FLUSHTYPE { + PROC_INVALIDATE_MEM = 0, + PROC_WRITEBACK_MEM, + PROC_WRITEBACK_INVALIDATE_MEM, + } ; + +/* Memory Segment Status Values */ + struct DSP_MEMSTAT { + u32 ulSize; + u32 ulTotalFreeSize; + u32 ulLenMaxFreeBlock; + u32 ulNumFreeBlocks; + u32 ulNumAllocBlocks; + } ; + +/* Processor Load information Values */ + struct DSP_PROCLOADSTAT { + u32 uCurrLoad; + u32 uPredictedLoad; + u32 uCurrDspFreq; + u32 uPredictedFreq; + } ; + +/* Attributes for STRM connections between nodes */ + struct DSP_STRMATTR { + u32 uSegid; /* Memory segment on DSP to allocate buffers */ + u32 uBufsize; /* Buffer size (DSP words) */ + u32 uNumBufs; /* Number of buffers */ + u32 uAlignment; /* Buffer alignment */ + u32 uTimeout; /* Timeout for blocking STRM calls */ + enum DSP_STRMMODE lMode; /* mode of stream when opened */ + /* DMA chnl id if DSP_STRMMODE is LDMA or RDMA */ + u32 uDMAChnlId; + u32 uDMAPriority; /* DMA channel priority 0=lowest, >0=high */ + } ; + +/* The DSP_CBDATA structure */ + struct DSP_CBDATA { + u32 cbData; + u8 cData[1]; + } ; + +/* The DSP_MSG structure */ + struct DSP_MSG { + u32 dwCmd; + u32 dwArg1; + u32 dwArg2; + } ; + +/* The DSP_RESOURCEREQMTS structure for node's resource requirements */ + struct DSP_RESOURCEREQMTS { + u32 cbStruct; + u32 uStaticDataSize; + u32 uGlobalDataSize; + u32 uProgramMemSize; + u32 uWCExecutionTime; + u32 uWCPeriod; + u32 uWCDeadline; + u32 uAvgExectionTime; + u32 uMinimumPeriod; + } ; + +/* + * The DSP_STREAMCONNECT structure describes a stream connection + * between two nodes, or between a node and the GPP + */ + struct DSP_STREAMCONNECT { + u32 cbStruct; + enum DSP_CONNECTTYPE lType; + u32 uThisNodeStreamIndex; + DSP_HNODE hConnectedNode; + struct DSP_UUID uiConnectedNodeID; + u32 uConnectedNodeStreamIndex; + } ; + + struct DSP_NODEPROFS { + u32 ulHeapSize; + } ; + +/* The DSP_NDBPROPS structure reports the attributes of a node */ + struct DSP_NDBPROPS { + u32 cbStruct; + struct DSP_UUID uiNodeID; + char acName[DSP_MAXNAMELEN]; + enum NODE_TYPE uNodeType; + u32 bCacheOnGPP; + struct DSP_RESOURCEREQMTS dspResourceReqmts; + s32 iPriority; + u32 uStackSize; + u32 uSysStackSize; + u32 uStackSeg; + u32 uMessageDepth; + u32 uNumInputStreams; + u32 uNumOutputStreams; + u32 uTimeout; + u32 uCountProfiles; /* Number of supported profiles */ + /* Array of profiles */ + struct DSP_NODEPROFS aProfiles[MAX_PROFILES]; + u32 uStackSegName; /* Stack Segment Name */ + } ; + + /* The DSP_NODEATTRIN structure describes the attributes of a + * node client */ + struct DSP_NODEATTRIN { + u32 cbStruct; + s32 iPriority; + u32 uTimeout; + u32 uProfileID; + /* Reserved, for Bridge Internal use only */ + u32 uHeapSize; + void *pGPPVirtAddr; /* Reserved, for Bridge Internal use only */ + } ; + + /* The DSP_NODEINFO structure is used to retrieve information + * about a node */ + struct DSP_NODEINFO { + u32 cbStruct; + struct DSP_NDBPROPS nbNodeDatabaseProps; + u32 uExecutionPriority; + enum NODE_STATE nsExecutionState; + DSP_HNODE hDeviceOwner; + u32 uNumberStreams; + struct DSP_STREAMCONNECT scStreamConnection[16]; + u32 uNodeEnv; + } ; + + /* The DSP_NODEATTR structure describes the attributes of a node */ + struct DSP_NODEATTR { + u32 cbStruct; + struct DSP_NODEATTRIN inNodeAttrIn; + u32 uInputs; + u32 uOutputs; + struct DSP_NODEINFO iNodeInfo; + } ; + +/* + * Notification type: either the name of an opened event, or an event or + * window handle. + */ + struct DSP_NOTIFICATION { + char *psName; + HANDLE handle; + } ; + +/* The DSP_PROCESSORATTRIN structure describes the attributes of a processor */ + struct DSP_PROCESSORATTRIN{ + u32 cbStruct; + u32 uTimeout; + } ; + + enum chipTypes { + DSPTYPE_55 = 6, + IVA_ARM7 = 0x97, + DSPTYPE_64 = 0x99 + }; + +/* + * The DSP_PROCESSORINFO structure describes basic capabilities of a + * DSP processor + */ + struct DSP_PROCESSORINFO { + u32 cbStruct; + DSP_PROCFAMILY uProcessorFamily; + DSP_PROCTYPE uProcessorType; + u32 uClockRate; + u32 ulInternalMemSize; + u32 ulExternalMemSize; + u32 uProcessorID; + DSP_RTOSTYPE tyRunningRTOS; + s32 nNodeMinPriority; + s32 nNodeMaxPriority; + } ; + +/* Error information of last DSP exception signalled to the GPP */ + struct DSP_ERRORINFO { + u32 dwErrMask; + u32 dwVal1; + u32 dwVal2; + u32 dwVal3; + } ; + +/* The DSP_PROCESSORSTATE structure describes the state of a DSP processor */ + struct DSP_PROCESSORSTATE { + u32 cbStruct; + enum DSP_PROCSTATE iState; + struct DSP_ERRORINFO errInfo; + } ; + +/* + * The DSP_RESOURCEINFO structure is used to retrieve information about a + * processor's resources + */ + struct DSP_RESOURCEINFO { + u32 cbStruct; + enum DSP_RESOURCEINFOTYPE uResourceType; + union { + u32 ulResource; + struct DSP_MEMSTAT memStat; + struct DSP_PROCLOADSTAT procLoadStat; + } result; + } ; + +/* + * The DSP_STREAMATTRIN structure describes the attributes of a stream, + * including segment and alignment of data buffers allocated with + * DSPStream_AllocateBuffers(), if applicable + */ + struct DSP_STREAMATTRIN { + u32 cbStruct; + u32 uTimeout; + u32 uSegment; + u32 uAlignment; + u32 uNumBufs; + enum DSP_STRMMODE lMode; + u32 uDMAChnlId; + u32 uDMAPriority; + } ; + +/* The DSP_BUFFERATTR structure describes the attributes of a data buffer */ + struct DSP_BUFFERATTR { + u32 cbStruct; + u32 uSegment; + u32 uAlignment; + } ; + +/* + * The DSP_STREAMINFO structure is used to retrieve information + * about a stream. + */ + struct DSP_STREAMINFO { + u32 cbStruct; + u32 uNumberBufsAllowed; + u32 uNumberBufsInStream; + u32 ulNumberBytes; + HANDLE hSyncObjectHandle; + enum DSP_STREAMSTATE ssStreamState; + } ; + +/* DMM MAP attributes +It is a bit mask with each bit value indicating a specific attribute +bit 0 - GPP address type (user virtual=0, physical=1) +bit 1 - MMU Endianism (Big Endian=1, Little Endian=0) +bit 2 - MMU mixed page attribute (Mixed/ CPUES=1, TLBES =0) +bit 3 - MMU element size = 8bit (valid only for non mixed page entries) +bit 4 - MMU element size = 16bit (valid only for non mixed page entries) +bit 5 - MMU element size = 32bit (valid only for non mixed page entries) +bit 6 - MMU element size = 64bit (valid only for non mixed page entries) +*/ + +/* Types of mapping attributes */ + +/* MPU address is virtual and needs to be translated to physical addr */ +#define DSP_MAPVIRTUALADDR 0x00000000 +#define DSP_MAPPHYSICALADDR 0x00000001 + +/* Mapped data is big endian */ +#define DSP_MAPBIGENDIAN 0x00000002 +#define DSP_MAPLITTLEENDIAN 0x00000000 + +/* Element size is based on DSP r/w access size */ +#define DSP_MAPMIXEDELEMSIZE 0x00000004 + +/* + * Element size for MMU mapping (8, 16, 32, or 64 bit) + * Ignored if DSP_MAPMIXEDELEMSIZE enabled + */ +#define DSP_MAPELEMSIZE8 0x00000008 +#define DSP_MAPELEMSIZE16 0x00000010 +#define DSP_MAPELEMSIZE32 0x00000020 +#define DSP_MAPELEMSIZE64 0x00000040 + +#define DSP_MAPVMALLOCADDR 0x00000080 + +#define DSP_MAPDONOTLOCK 0x00000100 + + +#define GEM_CACHE_LINE_SIZE 128 +#define GEM_L1P_PREFETCH_SIZE 128 + +#endif /* DBDEFS_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/dbg.h b/arch/arm/plat-omap/include/dspbridge/dbg.h new file mode 100644 index 0000000..7f44ff9 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dbg.h @@ -0,0 +1,110 @@ +/* + * dbg.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== dbg.h ======== + * Purpose: + * Provide debugging services for 'Bridge Mini Drivers. + * + * Public Functions: + * DBG_Exit + * DBG_Init + * DBG_Printf + * DBG_Trace + * + * Notes: + * WMD's must not call DBG_Init or DBG_Exit. + * + *! Revision History: + *! ================ + *! 03-Feb-2000 rr: DBG Levels redefined. + *! 29-Oct-1999 kc: Cleaned up for code review. + *! 10-Oct-1997 cr: Added DBG_Printf service. + *! 29-May-1996 gp: Removed WCD_ prefix. + *! 15-May-1996 gp: Created. + */ + +#ifndef DBG_ +#define DBG_ +#include +#include + +/* Levels of trace debug messages: */ +#define DBG_ENTER (u8)(0x01) /* Function entry point. */ +#define DBG_LEVEL1 (u8)(0x02) /* Display debugging state/varibles */ +#define DBG_LEVEL2 (u8)(0x04) /* Display debugging state/varibles */ +#define DBG_LEVEL3 (u8)(0x08) /* Display debugging state/varibles */ +#define DBG_LEVEL4 (u8)(0x10) /* Display debugging state/varibles */ +#define DBG_LEVEL5 (u8)(0x20) /* Module Init, Exit */ +#define DBG_LEVEL6 (u8)(0x40) /* Warn SERVICES Failures */ +#define DBG_LEVEL7 (u8)(0x80) /* Warn Critical Errors */ + +#if (defined(DEBUG) || defined(DDSP_DEBUG_PRODUCT)) && GT_TRACE + +/* + * ======== DBG_Exit ======== + * Purpose: + * Discontinue usage of module; free resources when reference count + * reaches 0. + * Parameters: + * Returns: + * Requires: + * DBG initialized. + * Ensures: + * Resources used by module are freed when cRef reaches zero. + */ + extern void DBG_Exit(void); + +/* + * ======== DBG_Init ======== + * Purpose: + * Initializes private state of DBG module. + * Parameters: + * Returns: + * TRUE if initialized; FALSE if error occured. + * Requires: + * Ensures: + */ + extern bool DBG_Init(void); + +/* + * ======== DBG_Trace ======== + * Purpose: + * Output a trace message to the debugger, if the given trace level + * is unmasked. + * Parameters: + * bLevel: Trace level. + * pstrFormat: sprintf-style format string. + * ...: Arguments for format string. + * Returns: + * DSP_SOK: Success, or trace level masked. + * DSP_EFAIL: On Error. + * Requires: + * DBG initialized. + * Ensures: + * Debug message is printed to debugger output window, if trace level + * is unmasked. + */ + extern DSP_STATUS DBG_Trace(IN u8 bLevel, IN char *pstrFormat, ...); +#else + +#define DBG_Exit(void) +#define DBG_Init(void) true +#define DBG_Trace(bLevel, pstrFormat, args...) + +#endif /* (defined(DEBUG) || defined(DDSP_DEBUG_PRODUCT)) && GT_TRACE */ + +#endif /* DBG_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/dbl.h b/arch/arm/plat-omap/include/dspbridge/dbl.h new file mode 100644 index 0000000..19847f9 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dbl.h @@ -0,0 +1,354 @@ +/* + * dbl.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dbl.h ======== + * + *! Revision History + *! ================ + *! 19-Mar-2002 jeh Pass DBL_Symbol pointer to DBL_getAddr, DBL_getCAddr + *! to accomodate dynamic loader library. + *! 20-Nov-2001 jeh Removed DBL_loadArgs(). + *! 24-Sep-2001 jeh Code review changes. + *! 07-Sep-2001 jeh Added DBL_LoadSect(), DBL_UnloadSect(). + *! 05-Jun-2001 jeh Created based on zl.h. + */ + +#ifndef DBL_ +#define DBL_ + +#include +#include + +/* + * ======== DBL_close ======== + * Close library opened with DBL_open. + * Parameters: + * lib - Handle returned from DBL_open(). + * Returns: + * Requires: + * DBL initialized. + * Valid lib. + * Ensures: + */ + extern void DBL_close(struct DBL_LibraryObj *lib); + +/* + * ======== DBL_create ======== + * Create a target object by specifying the alloc, free, and write + * functions for the target. + * Parameters: + * pTarget - Location to store target handle on output. + * pAttrs - Attributes. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Memory allocation failed. + * Requires: + * DBL initialized. + * pAttrs != NULL. + * pTarget != NULL; + * Ensures: + * Success: *pTarget != NULL. + * Failure: *pTarget == NULL. + */ + extern DSP_STATUS DBL_create(struct DBL_TargetObj **pTarget, + struct DBL_Attrs *pAttrs); + +/* + * ======== DBL_delete ======== + * Delete target object and free resources for any loaded libraries. + * Parameters: + * target - Handle returned from DBL_Create(). + * Returns: + * Requires: + * DBL initialized. + * Valid target. + * Ensures: + */ + extern void DBL_delete(struct DBL_TargetObj *target); + +/* + * ======== DBL_exit ======== + * Discontinue use of DBL module. + * Parameters: + * Returns: + * Requires: + * cRefs > 0. + * Ensures: + * cRefs >= 0. + */ + extern void DBL_exit(void); + +/* + * ======== DBL_getAddr ======== + * Get address of name in the specified library. + * Parameters: + * lib - Handle returned from DBL_open(). + * name - Name of symbol + * ppSym - Location to store symbol address on output. + * Returns: + * TRUE: Success. + * FALSE: Symbol not found. + * Requires: + * DBL initialized. + * Valid lib. + * name != NULL. + * pAddr != NULL. + * Ensures: + */ + extern bool DBL_getAddr(struct DBL_LibraryObj *lib, char *name, + struct DBL_Symbol **ppSym); + +/* + * ======== DBL_getAttrs ======== + * Retrieve the attributes of the target. + * Parameters: + * target - Handle returned from DBL_Create(). + * pAttrs - Location to store attributes on output. + * Returns: + * Requires: + * DBL initialized. + * Valid target. + * pAttrs != NULL. + * Ensures: + */ + extern void DBL_getAttrs(struct DBL_TargetObj *target, + struct DBL_Attrs *pAttrs); + +/* + * ======== DBL_getCAddr ======== + * Get address of "C" name in the specified library. + * Parameters: + * lib - Handle returned from DBL_open(). + * name - Name of symbol + * ppSym - Location to store symbol address on output. + * Returns: + * TRUE: Success. + * FALSE: Symbol not found. + * Requires: + * DBL initialized. + * Valid lib. + * name != NULL. + * pAddr != NULL. + * Ensures: + */ + extern bool DBL_getCAddr(struct DBL_LibraryObj *lib, char *name, + struct DBL_Symbol **ppSym); + +/* + * ======== DBL_getEntry ======== + * Get program entry point. + * + * Parameters: + * lib - Handle returned from DBL_open(). + * pEntry - Location to store entry address on output. + * Returns: + * TRUE: Success. + * FALSE: Failure. + * Requires: + * DBL initialized. + * Valid lib. + * pEntry != NULL. + * Ensures: + */ + extern bool DBL_getEntry(struct DBL_LibraryObj *lib, u32 *pEntry); + +/* + * ======== DBL_getSect ======== + * Get address and size of a named section. + * Parameters: + * lib - Library handle returned from DBL_open(). + * name - Name of section. + * pAddr - Location to store section address on output. + * pSize - Location to store section size on output. + * Returns: + * DSP_SOK: Success. + * DSP_ENOSECT: Section not found. + * Requires: + * DBL initialized. + * Valid lib. + * name != NULL. + * pAddr != NULL; + * pSize != NULL. + * Ensures: + */ + extern DSP_STATUS DBL_getSect(struct DBL_LibraryObj *lib, char *name, + u32 *pAddr, u32 *pSize); + +/* + * ======== DBL_init ======== + * Initialize DBL module. + * Parameters: + * Returns: + * TRUE: Success. + * FALSE: Failure. + * Requires: + * cRefs >= 0. + * Ensures: + * Success: cRefs > 0. + * Failure: cRefs >= 0. + */ + extern bool DBL_init(void); + +/* + * ======== DBL_load ======== + * Add symbols/code/data defined in file to that already present on + * the target. + * + * Parameters: + * lib - Library handle returned from DBL_open(). + * flags - Specifies whether loading code, data, and/or symbols. + * attrs - May contain write, alloc, and free functions. + * pulEntry - Location to store program entry on output. + * Returns: + * DSP_SOK: Success. + * DSP_EFREAD: File read failed. + * DSP_EFWRITE: Write to target failed. + * Requires: + * DBL initialized. + * Valid lib. + * pEntry != NULL. + * Ensures: + */ + extern DSP_STATUS DBL_load(struct DBL_LibraryObj *lib, DBL_Flags flags, + struct DBL_Attrs *attrs, u32 *pEntry); + +/* + * ======== DBL_loadSect ======== + * Load a named section from an library (for overlay support). + * Parameters: + * lib - Handle returned from DBL_open(). + * sectName - Name of section to load. + * attrs - Contains write function and handle to pass to it. + * Returns: + * DSP_SOK: Success. + * DSP_ENOSECT: Section not found. + * DSP_EFWRITE: Write function failed. + * Requires: + * Valid lib. + * sectName != NULL. + * attrs != NULL. + * attrs->write != NULL. + * Ensures: + */ + extern DSP_STATUS DBL_loadSect(struct DBL_LibraryObj *lib, + char *sectName, + struct DBL_Attrs *attrs); + +/* + * ======== DBL_open ======== + * DBL_open() returns a library handle that can be used to load/unload + * the symbols/code/data via DBL_load()/DBL_unload(). + * Parameters: + * target - Handle returned from DBL_create(). + * file - Name of file to open. + * flags - Specifies whether to load symbols now. + * pLib - Location to store library handle on output. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Memory allocation failure. + * DSP_EFOPEN: File open failure. + * DSP_EFREAD: File read failure. + * DSP_ECORRUPTFILE: Unable to determine target type. + * Requires: + * DBL initialized. + * Valid target. + * file != NULL. + * pLib != NULL. + * struct DBL_Attrs fopen function non-NULL. + * Ensures: + * Success: Valid *pLib. + * Failure: *pLib == NULL. + */ + extern DSP_STATUS DBL_open(struct DBL_TargetObj *target, char *file, + DBL_Flags flags, + struct DBL_LibraryObj **pLib); + +/* + * ======== DBL_readSect ======== + * Read COFF section into a character buffer. + * Parameters: + * lib - Library handle returned from DBL_open(). + * name - Name of section. + * pBuf - Buffer to write section contents into. + * size - Buffer size + * Returns: + * DSP_SOK: Success. + * DSP_ENOSECT: Named section does not exists. + * Requires: + * DBL initialized. + * Valid lib. + * name != NULL. + * pBuf != NULL. + * size != 0. + * Ensures: + */ + extern DSP_STATUS DBL_readSect(struct DBL_LibraryObj *lib, char *name, + char *pBuf, u32 size); + +/* + * ======== DBL_setAttrs ======== + * Set the attributes of the target. + * Parameters: + * target - Handle returned from DBL_create(). + * pAttrs - New attributes. + * Returns: + * Requires: + * DBL initialized. + * Valid target. + * pAttrs != NULL. + * Ensures: + */ + extern void DBL_setAttrs(struct DBL_TargetObj *target, + struct DBL_Attrs *pAttrs); + +/* + * ======== DBL_unload ======== + * Remove the symbols/code/data corresponding to the library lib. + * Parameters: + * lib - Handle returned from DBL_open(). + * attrs - Contains free() function and handle to pass to it. + * Returns: + * Requires: + * DBL initialized. + * Valid lib. + * Ensures: + */ + extern void DBL_unload(struct DBL_LibraryObj *lib, + struct DBL_Attrs *attrs); + +/* + * ======== DBL_unloadSect ======== + * Unload a named section from an library (for overlay support). + * Parameters: + * lib - Handle returned from DBL_open(). + * sectName - Name of section to load. + * attrs - Contains free() function and handle to pass to it. + * Returns: + * DSP_SOK: Success. + * DSP_ENOSECT: Named section not found. + * Requires: + * DBL initialized. + * Valid lib. + * sectName != NULL. + * Ensures: + */ + extern DSP_STATUS DBL_unloadSect(struct DBL_LibraryObj *lib, + char *sectName, + struct DBL_Attrs *attrs); + +#endif /* DBL_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/dbldefs.h b/arch/arm/plat-omap/include/dspbridge/dbldefs.h new file mode 100644 index 0000000..79b9e54 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dbldefs.h @@ -0,0 +1,155 @@ +/* + * dbldefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dbldefs.h ======== + * + *! Revision History + *! ================ + *! 19-Mar-2002 jeh Added DBL_Fxns type (to make it easier to switch + *! between different loaders). + *! 28-Sep-2001 jeh Created from zl.h. + */ +#ifndef DBLDEFS_ +#define DBLDEFS_ + +/* + * Bit masks for DBL_Flags. + */ +#define DBL_NOLOAD 0x0 /* Don't load symbols, code, or data */ +#define DBL_SYMB 0x1 /* load symbols */ +#define DBL_CODE 0x2 /* load code */ +#define DBL_DATA 0x4 /* load data */ +#define DBL_DYNAMIC 0x8 /* dynamic load */ +#define DBL_BSS 0x20 /* Unitialized section */ + +#define DBL_MAXPATHLENGTH 255 + + + +/* + * ======== DBL_Flags ======== + * Specifies whether to load code, data, or symbols + */ +typedef s32 DBL_Flags; + +/* + * ======== DBL_SectInfo ======== + * For collecting info on overlay sections + */ +struct DBL_SectInfo { + const char *name; /* name of section */ + u32 runAddr; /* run address of section */ + u32 loadAddr; /* load address of section */ + u32 size; /* size of section (target MAUs) */ + DBL_Flags type; /* Code, data, or BSS */ +} ; + +/* + * ======== DBL_Symbol ======== + * (Needed for dynamic load library) + */ +struct DBL_Symbol { + u32 value; +}; + +/* + * ======== DBL_AllocFxn ======== + * Allocate memory function. Allocate or reserve (if reserved == TRUE) + * "size" bytes of memory from segment "space" and return the address in + * *dspAddr (or starting at *dspAddr if reserve == TRUE). Returns 0 on + * success, or an error code on failure. + */ +typedef s32(*DBL_AllocFxn) (void *hdl, s32 space, u32 size, u32 align, + u32 *dspAddr, s32 segId, s32 req, bool reserved); + + + +/* + * ======== DBL_FreeFxn ======== + * Free memory function. Free, or unreserve (if reserved == TRUE) "size" + * bytes of memory from segment "space" + */ +typedef bool(*DBL_FreeFxn) (void *hdl, u32 addr, s32 space, u32 size, + bool reserved); + +/* + * ======== DBL_LogWriteFxn ======== + * Function to call when writing data from a section, to log the info. + * Can be NULL if no logging is required. + */ +typedef DSP_STATUS(*DBL_LogWriteFxn) (void *handle, struct DBL_SectInfo *sect, + u32 addr, u32 nBytes); + + +/* + * ======== DBL_SymLookup ======== + * Symbol lookup function - Find the symbol name and return its value. + * + * Parameters: + * handle - Opaque handle + * pArg - Opaque argument. + * name - Name of symbol to lookup. + * sym - Location to store address of symbol structure. + * + * Returns: + * TRUE: Success (symbol was found). + * FALSE: Failed to find symbol. + */ +typedef bool(*DBL_SymLookup) (void *handle, void *pArg, void *rmmHandle, + const char *name, struct DBL_Symbol **sym); + + +/* + * ======== DBL_WriteFxn ======== + * Write memory function. Write "n" HOST bytes of memory to segment "mtype" + * starting at address "dspAddr" from the buffer "buf". The buffer is + * formatted as an array of words appropriate for the DSP. + */ +typedef s32(*DBL_WriteFxn) (void *hdl, u32 dspAddr, void *buf, + u32 n, s32 mtype); + +/* + * ======== DBL_Attrs ======== + */ +struct DBL_Attrs { + DBL_AllocFxn alloc; + DBL_FreeFxn free; + void *rmmHandle; /* Handle to pass to alloc, free functions */ + DBL_WriteFxn write; + void *wHandle; /* Handle to pass to write, cinit function */ + + DBL_LogWriteFxn logWrite; + void *logWriteHandle; + + /* Symbol matching function and handle to pass to it */ + DBL_SymLookup symLookup; + void *symHandle; + void *symArg; + + /* + * These file manipulation functions should be compatible with the + * "C" run time library functions of the same name. + */ + s32(*fread) (void *, size_t, size_t, void *); + s32(*fseek) (void *, long, int); + s32(*ftell) (void *); + s32(*fclose) (void *); + void *(*fopen) (const char *, const char *); +} ; + +#endif /* DBLDEFS_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/dbll.h b/arch/arm/plat-omap/include/dspbridge/dbll.h new file mode 100644 index 0000000..c3aa212 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dbll.h @@ -0,0 +1,70 @@ +/* + * dbll.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dbll.h ======== + * DSP/BIOS Bridge Dynamic load library module interface. Function header + * comments are in the file dblldefs.h. + * + *! Revision History + *! ================ + *! 31-Jul-2002 jeh Removed function comments (now in dblldefs.h). + *! 17-Apr-2002 jeh Created based on zl.h. + */ + +#ifndef DBLL_ +#define DBLL_ + +#include +#include + + extern void DBLL_close(struct DBLL_LibraryObj *lib); + extern DSP_STATUS DBLL_create(struct DBLL_TarObj **pTarget, + struct DBLL_Attrs *pAttrs); + extern void DBLL_delete(struct DBLL_TarObj *target); + extern void DBLL_exit(void); + extern bool DBLL_getAddr(struct DBLL_LibraryObj *lib, char *name, + struct DBLL_Symbol **ppSym); + extern void DBLL_getAttrs(struct DBLL_TarObj *target, + struct DBLL_Attrs *pAttrs); + extern bool DBLL_getCAddr(struct DBLL_LibraryObj *lib, char *name, + struct DBLL_Symbol **ppSym); + extern DSP_STATUS DBLL_getSect(struct DBLL_LibraryObj *lib, char *name, + u32 *pAddr, u32 *pSize); + extern bool DBLL_init(void); + extern DSP_STATUS DBLL_load(struct DBLL_LibraryObj *lib, + DBLL_Flags flags, + struct DBLL_Attrs *attrs, u32 *pEntry); + extern DSP_STATUS DBLL_loadSect(struct DBLL_LibraryObj *lib, + char *sectName, + struct DBLL_Attrs *attrs); + extern DSP_STATUS DBLL_open(struct DBLL_TarObj *target, char *file, + DBLL_Flags flags, + struct DBLL_LibraryObj **pLib); + extern DSP_STATUS DBLL_readSect(struct DBLL_LibraryObj *lib, + char *name, + char *pBuf, u32 size); + extern void DBLL_setAttrs(struct DBLL_TarObj *target, + struct DBLL_Attrs *pAttrs); + extern void DBLL_unload(struct DBLL_LibraryObj *lib, + struct DBLL_Attrs *attrs); + extern DSP_STATUS DBLL_unloadSect(struct DBLL_LibraryObj *lib, + char *sectName, + struct DBLL_Attrs *attrs); + +#endif /* DBLL_ */ + diff --git a/arch/arm/plat-omap/include/dspbridge/dblldefs.h b/arch/arm/plat-omap/include/dspbridge/dblldefs.h new file mode 100644 index 0000000..2361ce8 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dblldefs.h @@ -0,0 +1,509 @@ +/* + * dblldefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dblldefs.h ======== + * + *! Revision History + *! ================ + *! 08-Apr-2003 map Consolidated DBL into DBLL name + *! 19-Mar-2002 jeh Added DBL_Fxns type (to make it easier to switch + *! between different loaders). + *! 28-Sep-2001 jeh Created from zl.h. + */ +#ifndef DBLLDEFS_ +#define DBLLDEFS_ + +/* + * Bit masks for DBL_Flags. + */ +#define DBLL_NOLOAD 0x0 /* Don't load symbols, code, or data */ +#define DBLL_SYMB 0x1 /* load symbols */ +#define DBLL_CODE 0x2 /* load code */ +#define DBLL_DATA 0x4 /* load data */ +#define DBLL_DYNAMIC 0x8 /* dynamic load */ +#define DBLL_BSS 0x20 /* Unitialized section */ + +#define DBLL_MAXPATHLENGTH 255 + + +/* + * ======== DBLL_Target ======== + * + */ +struct DBLL_TarObj; + +/* + * ======== DBLL_Flags ======== + * Specifies whether to load code, data, or symbols + */ +typedef s32 DBLL_Flags; + +/* + * ======== DBLL_Library ======== + * + */ +struct DBLL_LibraryObj; + +/* + * ======== DBLL_SectInfo ======== + * For collecting info on overlay sections + */ +struct DBLL_SectInfo { + const char *name; /* name of section */ + u32 runAddr; /* run address of section */ + u32 loadAddr; /* load address of section */ + u32 size; /* size of section (target MAUs) */ + DBLL_Flags type; /* Code, data, or BSS */ +} ; + +/* + * ======== DBLL_Symbol ======== + * (Needed for dynamic load library) + */ +struct DBLL_Symbol { + u32 value; +}; + +/* + * ======== DBLL_AllocFxn ======== + * Allocate memory function. Allocate or reserve (if reserved == TRUE) + * "size" bytes of memory from segment "space" and return the address in + * *dspAddr (or starting at *dspAddr if reserve == TRUE). Returns 0 on + * success, or an error code on failure. + */ +typedef s32(*DBLL_AllocFxn) (void *hdl, s32 space, u32 size, u32 align, + u32 *dspAddr, s32 segId, s32 req, + bool reserved); + +/* + * ======== DBLL_CloseFxn ======== + */ +typedef s32(*DBLL_FCloseFxn) (void *); + +/* + * ======== DBLL_FreeFxn ======== + * Free memory function. Free, or unreserve (if reserved == TRUE) "size" + * bytes of memory from segment "space" + */ +typedef bool(*DBLL_FreeFxn) (void *hdl, u32 addr, s32 space, u32 size, + bool reserved); + +/* + * ======== DBLL_FOpenFxn ======== + */ +typedef void *(*DBLL_FOpenFxn) (const char *, const char *); + +/* + * ======== DBLL_LogWriteFxn ======== + * Function to call when writing data from a section, to log the info. + * Can be NULL if no logging is required. + */ +typedef DSP_STATUS(*DBLL_LogWriteFxn)(void *handle, struct DBLL_SectInfo *sect, + u32 addr, u32 nBytes); + +/* + * ======== DBLL_ReadFxn ======== + */ +typedef s32(*DBLL_ReadFxn) (void *, size_t, size_t, void *); + +/* + * ======== DBLL_SeekFxn ======== + */ +typedef s32(*DBLL_SeekFxn) (void *, long, int); + +/* + * ======== DBLL_SymLookup ======== + * Symbol lookup function - Find the symbol name and return its value. + * + * Parameters: + * handle - Opaque handle + * pArg - Opaque argument. + * name - Name of symbol to lookup. + * sym - Location to store address of symbol structure. + * + * Returns: + * TRUE: Success (symbol was found). + * FALSE: Failed to find symbol. + */ +typedef bool(*DBLL_SymLookup) (void *handle, void *pArg, void *rmmHandle, + const char *name, struct DBLL_Symbol **sym); + +/* + * ======== DBLL_TellFxn ======== + */ +typedef s32(*DBLL_TellFxn) (void *); + +/* + * ======== DBLL_WriteFxn ======== + * Write memory function. Write "n" HOST bytes of memory to segment "mtype" + * starting at address "dspAddr" from the buffer "buf". The buffer is + * formatted as an array of words appropriate for the DSP. + */ +typedef s32(*DBLL_WriteFxn) (void *hdl, u32 dspAddr, void *buf, + u32 n, s32 mtype); + +/* + * ======== DBLL_Attrs ======== + */ +struct DBLL_Attrs { + DBLL_AllocFxn alloc; + DBLL_FreeFxn free; + void *rmmHandle; /* Handle to pass to alloc, free functions */ + DBLL_WriteFxn write; + void *wHandle; /* Handle to pass to write, cinit function */ + bool baseImage; + DBLL_LogWriteFxn logWrite; + void *logWriteHandle; + + /* Symbol matching function and handle to pass to it */ + DBLL_SymLookup symLookup; + void *symHandle; + void *symArg; + + /* + * These file manipulation functions should be compatible with the + * "C" run time library functions of the same name. + */ + s32(*fread) (void *, size_t, size_t, void *); + s32(*fseek) (void *, long, int); + s32(*ftell) (void *); + s32(*fclose) (void *); + void *(*fopen) (const char *, const char *); +} ; + +/* + * ======== DBLL_close ======== + * Close library opened with DBLL_open. + * Parameters: + * lib - Handle returned from DBLL_open(). + * Returns: + * Requires: + * DBL initialized. + * Valid lib. + * Ensures: + */ +typedef void(*DBLL_CloseFxn) (struct DBLL_LibraryObj *library); + +/* + * ======== DBLL_create ======== + * Create a target object, specifying the alloc, free, and write functions. + * Parameters: + * pTarget - Location to store target handle on output. + * pAttrs - Attributes. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Memory allocation failed. + * Requires: + * DBL initialized. + * pAttrs != NULL. + * pTarget != NULL; + * Ensures: + * Success: *pTarget != NULL. + * Failure: *pTarget == NULL. + */ +typedef DSP_STATUS(*DBLL_CreateFxn)(struct DBLL_TarObj **pTarget, + struct DBLL_Attrs *attrs); + +/* + * ======== DBLL_delete ======== + * Delete target object and free resources for any loaded libraries. + * Parameters: + * target - Handle returned from DBLL_Create(). + * Returns: + * Requires: + * DBL initialized. + * Valid target. + * Ensures: + */ +typedef void(*DBLL_DeleteFxn) (struct DBLL_TarObj *target); + +/* + * ======== DBLL_exit ======== + * Discontinue use of DBL module. + * Parameters: + * Returns: + * Requires: + * cRefs > 0. + * Ensures: + * cRefs >= 0. + */ +typedef void(*DBLL_ExitFxn) (void); + +/* + * ======== DBLL_getAddr ======== + * Get address of name in the specified library. + * Parameters: + * lib - Handle returned from DBLL_open(). + * name - Name of symbol + * ppSym - Location to store symbol address on output. + * Returns: + * TRUE: Success. + * FALSE: Symbol not found. + * Requires: + * DBL initialized. + * Valid library. + * name != NULL. + * ppSym != NULL. + * Ensures: + */ +typedef bool(*DBLL_GetAddrFxn) (struct DBLL_LibraryObj *lib, char *name, + struct DBLL_Symbol **ppSym); + +/* + * ======== DBLL_getAttrs ======== + * Retrieve the attributes of the target. + * Parameters: + * target - Handle returned from DBLL_Create(). + * pAttrs - Location to store attributes on output. + * Returns: + * Requires: + * DBL initialized. + * Valid target. + * pAttrs != NULL. + * Ensures: + */ +typedef void(*DBLL_GetAttrsFxn) (struct DBLL_TarObj *target, + struct DBLL_Attrs *attrs); + +/* + * ======== DBLL_getCAddr ======== + * Get address of "C" name on the specified library. + * Parameters: + * lib - Handle returned from DBLL_open(). + * name - Name of symbol + * ppSym - Location to store symbol address on output. + * Returns: + * TRUE: Success. + * FALSE: Symbol not found. + * Requires: + * DBL initialized. + * Valid target. + * name != NULL. + * ppSym != NULL. + * Ensures: + */ +typedef bool(*DBLL_GetCAddrFxn) (struct DBLL_LibraryObj *lib, char *name, + struct DBLL_Symbol **ppSym); + +/* + * ======== DBLL_getSect ======== + * Get address and size of a named section. + * Parameters: + * lib - Library handle returned from DBLL_open(). + * name - Name of section. + * pAddr - Location to store section address on output. + * pSize - Location to store section size on output. + * Returns: + * DSP_SOK: Success. + * DSP_ENOSECT: Section not found. + * Requires: + * DBL initialized. + * Valid lib. + * name != NULL. + * pAddr != NULL; + * pSize != NULL. + * Ensures: + */ +typedef DSP_STATUS(*DBLL_GetSectFxn) (struct DBLL_LibraryObj *lib, char *name, + u32 *addr, u32 *size); + +/* + * ======== DBLL_init ======== + * Initialize DBL module. + * Parameters: + * Returns: + * TRUE: Success. + * FALSE: Failure. + * Requires: + * cRefs >= 0. + * Ensures: + * Success: cRefs > 0. + * Failure: cRefs >= 0. + */ +typedef bool(*DBLL_InitFxn) (void); + +/* + * ======== DBLL_load ======== + * Load library onto the target. + * + * Parameters: + * lib - Library handle returned from DBLL_open(). + * flags - Load code, data and/or symbols. + * attrs - May contain alloc, free, and write function. + * pulEntry - Location to store program entry on output. + * Returns: + * DSP_SOK: Success. + * DSP_EFREAD: File read failed. + * DSP_EFWRITE: Write to target failed. + * DSP_EDYNLOAD: Failure in dynamic loader library. + * Requires: + * DBL initialized. + * Valid lib. + * pEntry != NULL. + * Ensures: + */ +typedef DSP_STATUS(*DBLL_LoadFxn) (struct DBLL_LibraryObj *lib, + DBLL_Flags flags, + struct DBLL_Attrs *attrs, u32 *entry); + +/* + * ======== DBLL_loadSect ======== + * Load a named section from an library (for overlay support). + * Parameters: + * lib - Handle returned from DBLL_open(). + * sectName - Name of section to load. + * attrs - Contains write function and handle to pass to it. + * Returns: + * DSP_SOK: Success. + * DSP_ENOSECT: Section not found. + * DSP_EFWRITE: Write function failed. + * DSP_ENOTIMPL: Function not implemented. + * Requires: + * Valid lib. + * sectName != NULL. + * attrs != NULL. + * attrs->write != NULL. + * Ensures: + */ +typedef DSP_STATUS(*DBLL_LoadSectFxn) (struct DBLL_LibraryObj *lib, + char *pszSectName, + struct DBLL_Attrs *attrs); + +/* + * ======== DBLL_open ======== + * DBLL_open() returns a library handle that can be used to load/unload + * the symbols/code/data via DBLL_load()/DBLL_unload(). + * Parameters: + * target - Handle returned from DBLL_create(). + * file - Name of file to open. + * flags - If flags & DBLL_SYMB, load symbols. + * pLib - Location to store library handle on output. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Memory allocation failure. + * DSP_EFOPEN: File open failure. + * DSP_EFREAD: File read failure. + * DSP_ECORRUPTFILE: Unable to determine target type. + * Requires: + * DBL initialized. + * Valid target. + * file != NULL. + * pLib != NULL. + * DBLL_Attrs fopen function non-NULL. + * Ensures: + * Success: Valid *pLib. + * Failure: *pLib == NULL. + */ +typedef DSP_STATUS(*DBLL_OpenFxn) (struct DBLL_TarObj *target, char *file, + DBLL_Flags flags, + struct DBLL_LibraryObj **pLib); + +/* + * ======== DBLL_readSect ======== + * Read COFF section into a character buffer. + * Parameters: + * lib - Library handle returned from DBLL_open(). + * name - Name of section. + * pBuf - Buffer to write section contents into. + * size - Buffer size + * Returns: + * DSP_SOK: Success. + * DSP_ENOSECT: Named section does not exists. + * Requires: + * DBL initialized. + * Valid lib. + * name != NULL. + * pBuf != NULL. + * size != 0. + * Ensures: + */ +typedef DSP_STATUS(*DBLL_ReadSectFxn) (struct DBLL_LibraryObj *lib, char *name, + char *content, u32 uContentSize); + +/* + * ======== DBLL_setAttrs ======== + * Set the attributes of the target. + * Parameters: + * target - Handle returned from DBLL_create(). + * pAttrs - New attributes. + * Returns: + * Requires: + * DBL initialized. + * Valid target. + * pAttrs != NULL. + * Ensures: + */ +typedef void(*DBLL_SetAttrsFxn)(struct DBLL_TarObj *target, + struct DBLL_Attrs *attrs); + +/* + * ======== DBLL_unload ======== + * Unload library loaded with DBLL_load(). + * Parameters: + * lib - Handle returned from DBLL_open(). + * attrs - Contains free() function and handle to pass to it. + * Returns: + * Requires: + * DBL initialized. + * Valid lib. + * Ensures: + */ +typedef void(*DBLL_UnloadFxn) (struct DBLL_LibraryObj *library, + struct DBLL_Attrs *attrs); + +/* + * ======== DBLL_unloadSect ======== + * Unload a named section from an library (for overlay support). + * Parameters: + * lib - Handle returned from DBLL_open(). + * sectName - Name of section to load. + * attrs - Contains free() function and handle to pass to it. + * Returns: + * DSP_SOK: Success. + * DSP_ENOSECT: Named section not found. + * DSP_ENOTIMPL + * Requires: + * DBL initialized. + * Valid lib. + * sectName != NULL. + * Ensures: + */ +typedef DSP_STATUS(*DBLL_UnloadSectFxn) (struct DBLL_LibraryObj *lib, + char *pszSectName, + struct DBLL_Attrs *attrs); + +struct DBLL_Fxns { + DBLL_CloseFxn closeFxn; + DBLL_CreateFxn createFxn; + DBLL_DeleteFxn deleteFxn; + DBLL_ExitFxn exitFxn; + DBLL_GetAttrsFxn getAttrsFxn; + DBLL_GetAddrFxn getAddrFxn; + DBLL_GetCAddrFxn getCAddrFxn; + DBLL_GetSectFxn getSectFxn; + DBLL_InitFxn initFxn; + DBLL_LoadFxn loadFxn; + DBLL_LoadSectFxn loadSectFxn; + DBLL_OpenFxn openFxn; + DBLL_ReadSectFxn readSectFxn; + DBLL_SetAttrsFxn setAttrsFxn; + DBLL_UnloadFxn unloadFxn; + DBLL_UnloadSectFxn unloadSectFxn; +} ; + +#endif /* DBLDEFS_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/dbof.h b/arch/arm/plat-omap/include/dspbridge/dbof.h new file mode 100644 index 0000000..54f4250 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dbof.h @@ -0,0 +1,117 @@ +/* + * dbof.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dbof.h ======== + * Description: + * Defines and typedefs for DSP/BIOS Bridge Object File Format (DBOF). + * + *! Revision History + *! ================ + *! 12-Jul-2002 jeh Added defines for DBOF_SectHdr page. + *! 12-Oct-2001 jeh Converted to std.h format. + *! 07-Sep-2001 jeh Added overlay support. + *! 06-Jul-2001 jeh Created. + */ + +#ifndef DBOF_ +#define DBOF_ + +/* Enough to hold DCD section names: 32 digit ID + underscores */ +#define DBOF_DCDSECTNAMELEN 40 + +/* Values for DBOF_SectHdr page field. */ +#define DBOF_PROGRAM 0 +#define DBOF_DATA 1 +#define DBOF_CINIT 2 + +/* + * ======== DBOF_FileHdr ======== + */ + struct DBOF_FileHdr { + u32 magic; /* COFF magic number */ + u32 entry; /* Program entry point */ + u16 numSymbols; /* Number of bridge symbols */ + u16 numDCDSects; /* Number of DCD sections */ + u16 numSects; /* Number of sections to load */ + u16 numOvlySects; /* Number of overlay sections */ + u32 symOffset; /* Offset in file to symbols */ + u32 dcdSectOffset; /* Offset to DCD sections */ + u32 loadSectOffset; /* Offset to loadable sections */ + u32 ovlySectOffset; /* Offset to overlay data */ + u16 version; /* DBOF version number */ + u16 resvd; /* Reserved for future use */ + } ; + +/* + * ======== DBOF_DCDSectHdr ======== + */ + struct DBOF_DCDSectHdr { + u32 size; /* Sect size (target MAUs) */ + char name[DBOF_DCDSECTNAMELEN]; /* DCD section name */ + } ; + +/* + * ======== DBOF_OvlySectHdr ======== + */ + struct DBOF_OvlySectHdr { + u16 nameLen; /* Length of section name */ + u16 numCreateSects; /* # of sects loaded for create phase */ + u16 numDeleteSects; /* # of sects loaded for delete phase */ + u16 numExecuteSects; /* # of sects loaded for execute phase */ + + /* + * Number of sections where load/unload phase is not specified. + * These sections will be loaded when create phase sects are + * loaded, and unloaded when the delete phase is unloaded. + */ + u16 numOtherSects; + u16 resvd; /* Reserved for future use */ + }; + +/* + * ======== DBOF_OvlySectData ======== + */ + struct DBOF_OvlySectData { + u32 loadAddr; /* Section load address */ + u32 runAddr; /* Section run address */ + u32 size; /* Section size (target MAUs) */ + u16 page; /* Memory page number */ + u16 resvd; /* Reserved */ + } ; + +/* + * ======== DBOF_SectHdr ======== + */ + struct DBOF_SectHdr { + u32 addr; /* Section address */ + u32 size; /* Section size (target MAUs) */ + u16 page; /* Page number */ + u16 resvd; /* Reserved for future use */ + } ; + +/* + * ======== DBOF_SymbolHdr ======== + */ + struct DBOF_SymbolHdr { + u32 value; /* Symbol value */ + u16 nameLen; /* Length of symbol name */ + u16 resvd; /* Reserved for future use */ + } ; + +#endif /* DBOF_ */ + diff --git a/arch/arm/plat-omap/include/dspbridge/dbreg.h b/arch/arm/plat-omap/include/dspbridge/dbreg.h new file mode 100644 index 0000000..d311b88 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dbreg.h @@ -0,0 +1,113 @@ +/* + * dbreg.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dbreg.h ======== + * Purpose: + * Registry keys for use in Linux. This is the clearinghouse for + * registry definitions, hopefully eliminating overlapping between + * modules. + * + *! Revision History: + *! ================ + *! 10-Apr-2003 vp: Added macro for subkey TCWORDSWAP. + *! 21-Mar-2003 sb: Added macro for subkey SHMSize + *! 27-Aug-2001 jeh Added WSXREG_LOADERFILENAME. + *! 13-Feb-2001 kc: DSP/BIOS Bridge name updates. + *! 29-Nov-2000 rr: Added WSXREG_DSPTYPE_55 as 6. + *! 06-Sep-2000 jeh: Added WSXREG_CHNLOFFSET, WSXREG_NUMCHNLS, + *! WSXREG_CHNLBUFSIZE. + *! 26-Aug-2000 rr: MEMBASE expanded to 9 entries. + *! 26-Jul-2000 rr: Added WSXREG_DCDNAME for the DCD Dll name. It will + *! live under WSXREG_WINSPOXCONFIG. + *! 17-Jul-2000 rr: REG_MGR_OBJECT and REG_DRV_OBJECT defined. They + *! are stored in the Registrty under WSXREG_WINSPOXCONFIG + *! when they are created in DSP_Init. WSXREG_DEVOBJECT + *! and WSXREG_MGROBJECT defined. + *! 11-Dec-1999 ag: Renamed Isa to IsaBus due to conflict with ceddk.h. + *! 12-Nov-1999 rr: New Registry Defnitions. + *! 15-Oct-1999 rr: New entry for DevObject created. WSXREG_DEVOBJECT + *! under WSXREG_DDSPDRIVERPATH + *! 10-Nov-1997 cr: Added WSXREG_INFPATH, WSXREG_WINDEVICEPATH, + *! WSXREG_WINCURVERSION + *! 21-Oct-1997 cr: Added WSXREG_BUSTYPE. + *! 08-Sep-1997 cr: Added WSXREG_SERVICES, WSXREG_SERVICENAME and + *! WSXREG_CLASSINDEX. + *! 30-Aug-1997 cr: Added WSXREG_SOFTWAREPATHNT & WSXREG_WBCLASSGUID. + *! 24-Mar-1997 gp: Added MAXCHIPINFOSUBKEY def. + *! 18-Feb-1997 cr: Changed Version1.1 -> Version1.0 + *! 12-Feb-1997 cr: Changed WinSPOX -> WinBRIDGE. + *! 11-Dec-1996 gp: Added Perf key name in WinSPOX Config. + *! 22-Jul-1996 gp: Added Trace key name. + *! 30-May-1996 cr: Created. + */ + +#ifndef DBREG_ +#define DBREG_ 1 /* Defined as "1" so InstallShield programs compile. */ + +#define REG_MGR_OBJECT 1 +#define REG_DRV_OBJECT 2 +/* general registry definitions */ +#define MAXREGPATHLENGTH 255 /* Max registry path length. Also the + max registry value length. */ +#define DSPTYPE_55 6 /* This is the DSP Chip type for 55 */ +#define DSPTYPE_64 0x99 +#define IVA_ARM7 0x97 /* This is the DSP Chip type for IVA/ARM7 */ + +#define DSPPROCTYPE_C55 5510 +#define DSPPROCTYPE_C64 6410 +#define IVAPROCTYPE_ARM7 470 +/* registry */ +#define DEVNODESTRING "DevNode" /* u32 devnode */ +#define CONFIG "Software\\TexasInstruments\\DirectDSP\\Config" +#define DRVOBJECT "DrvObject" +#define MGROBJECT "MgrObject" +#define CLASS "Device" /* device class */ +#define TRACE "Trace" /* GT Trace settings. */ +#define PERFR "Perf" /* Enable perf bool. */ +#define ROOT "Root" /* root dir */ + +/* MiniDriver related definitions */ +/* The following definitions are under "Drivers\\DirectDSP\\Device\\XXX " + * Where XXX is the device or board name */ + +#define WMDFILENAME "MiniDriver" /* WMD entry name */ +#define CHIPTYPE "ChipType" /* Chip type */ +#define CHIPNUM "NumChips" /* Number of chips */ +#define NUMPROCS "NumOfProcessors" /* Number of processors */ +#define DEFEXEC "DefaultExecutable" /* Default executable */ +#define AUTOSTART "AutoStart" /* Statically load flag */ +#define IVAAUTOSTART "IvaAutoStart" /* Statically load flag */ +#define BOARDNAME "BoardName" /* Name of the Board */ +#define UNITNUMBER "UnitNumber" /* Unit # of the Board */ +#define BUSTYPE "BusType" /* Bus type board is on */ +#define BUSNUMBER "BusNumber" /* Bus number board is on */ +#define CURRENTCONFIG "CurrentConfig" /* Current resources */ +#define PCIVENDEVID "VendorDeviceId" /* The board's id */ +#define INFPATH "InfPath" /* wmd's inf filename */ +#define DEVOBJECT "DevObject" +#define ZLFILENAME "ZLFileName" /* Name of ZL file */ +#define WORDSIZE "WordSize" /* NumBytes in DSP Word */ +#define SHMSIZE "SHMSize" /* Size of SHM reservd on MPU */ +#define IVAEXTMEMSIZE "IVAEXTMEMSize" /* IVA External Memeory size */ +#define TCWORDSWAP "TCWordSwap" /* Traffic Contoller Word Swap */ +#define DSPRESOURCES "DspTMSResources" /* C55 DSP resurces on OMAP */ +#define IVA1RESOURCES "ARM7IvaResources" /* ARM7 IVA resurces on OMAP */ +#define PHYSMEMPOOLBASE "PhysicalMemBase" /* Physical mem passed to driver */ +#define PHYSMEMPOOLSIZE "PhysicalMemSize" /* Physical mem passed to driver */ + +#endif /* DBREG_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/dbtype.h b/arch/arm/plat-omap/include/dspbridge/dbtype.h new file mode 100644 index 0000000..b4953a0 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dbtype.h @@ -0,0 +1,103 @@ +/* + * dbtype.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== dbtype.h ======== + * Description: + * This header defines data types for DSP/BIOS Bridge APIs and device + * driver modules. It also defines the Hungarian + * prefix to use for each base type. + * + * + *! Revision History: + *! ================= + *! 23-Nov-2002 gp: Purpose -> Description in file header. + *! 13-Feb-2001 kc: Name changed from ddsptype.h dbtype.h. + *! 09-Oct-2000 jeh Added CHARACTER. + *! 11-Aug-2000 ag: Added 'typedef void void'. + *! 08-Apr-2000 ww: Cloned. + */ + +#ifndef DBTYPE_ +#define DBTYPE_ + +/*============================================================================*/ +/* Argument specification syntax */ +/*============================================================================*/ + +#ifndef IN +#define IN /* Following parameter is for input. */ +#endif + +#ifndef OUT +#define OUT /* Following parameter is for output. */ +#endif + +#ifndef OPTIONAL +#define OPTIONAL /* Function may optionally use previous parameter. */ +#endif + +#ifndef CONST +#define CONST const +#endif + +/*============================================================================*/ +/* Boolean constants */ +/*============================================================================*/ + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +/*============================================================================*/ +/* NULL (Definition is language specific) */ +/*============================================================================*/ + +#ifndef NULL +#define NULL ((void *)0) /* Null pointer. */ +#endif + +/*============================================================================*/ +/* NULL character (normally used for string termination) */ +/*============================================================================*/ + +#ifndef NULL_CHAR +#define NULL_CHAR '\0' /* Null character. */ +#endif + +/*============================================================================*/ +/* Basic Type definitions (with Prefixes for Hungarian notation) */ +/*============================================================================*/ + +#ifndef OMAPBRIDGE_TYPES +#define OMAPBRIDGE_TYPES +typedef volatile unsigned short REG_UWORD16; +#endif + +typedef void *HANDLE; /* h */ + +#define TEXT(x) x + +#define DLLIMPORT +#define DLLEXPORT + +/* Define DSPAPIDLL correctly in dspapi.h */ +#define _DSPSYSDLL32_ + +#endif /* DBTYPE_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/dehdefs.h b/arch/arm/plat-omap/include/dspbridge/dehdefs.h new file mode 100644 index 0000000..06e5582 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dehdefs.h @@ -0,0 +1,42 @@ +/* + * dehdefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== dehdefs.h ======== + * Purpose: + * Definition for mini-driver module DEH. + * + *! Revision History: + *! ================ + *! 17-Dec-2001 ag: added #include for shared mailbox codes. + *! 10-Dec-2001 kc: added DEH error base value and error max value. + *! 11-Sep-2001 kc: created. + */ + +#ifndef DEHDEFS_ +#define DEHDEFS_ + +#include /* shared mailbox codes */ + +/* DEH object manager */ + struct DEH_MGR; + +/* Magic code used to determine if DSP signaled exception. */ +#define DEH_BASE MBX_DEH_BASE +#define DEH_USERS_BASE MBX_DEH_USERS_BASE +#define DEH_LIMIT MBX_DEH_LIMIT + +#endif /* _DEHDEFS_H */ diff --git a/arch/arm/plat-omap/include/dspbridge/dev.h b/arch/arm/plat-omap/include/dspbridge/dev.h new file mode 100644 index 0000000..5f468c9 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dev.h @@ -0,0 +1,785 @@ +/* + * dev.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dev.h ======== + * Description: + * 'Bridge Mini-driver device operations. + * + * Public Functions: + * DEV_BrdWriteFxn + * DEV_CreateDevice + * DEV_Create2 + * DEV_Destroy2 + * DEV_DestroyDevice + * DEV_GetChnlMgr + * DEV_GetCmmMgr + * DEV_GetCodMgr + * DEV_GetDehMgr + * DEV_GetDevNode + * DEV_GetDSPWordSize + * DEV_GetFirst + * DEV_GetIntfFxns + * DEV_GetIOMgr + * DEV_GetMsgMgr + * DEV_GetNext + * DEV_GetNodeManager + * DEV_GetSymbol + * DEV_GetWMDContext + * DEV_Exit + * DEV_Init + * DEV_InsertProcObject + * DEV_IsLocked + * DEV_NotifyClient + * DEV_RegisterNotify + * DEV_ReleaseCodMgr + * DEV_RemoveDevice + * DEV_RemoveProcObject + * DEV_SetChnlMgr + * DEV_SetMsgMgr + * DEV_SetLockOwner + * DEV_StartDevice + * + *! Revision History: + *! ================ + *! 08-Mar-2004 sb Added the Dynamic Memory Mapping feature - Dev_GetDmmMgr + *! 09-Feb-2004 vp Added functions required for IVA + *! 25-Feb-2003 swa PMGR Code Review changes incorporated + *! 05-Nov-2001 kc: Added DEV_GetDehMgr. + *! 05-Dec-2000 jeh Added DEV_SetMsgMgr. + *! 29-Nov-2000 rr: Incorporated code review changes. + *! 17-Nov-2000 jeh Added DEV_GetMsgMgr. + *! 05-Oct-2000 rr: DEV_Create2 & DEV_Destroy2 Added. + *! 02-Oct-2000 rr: Added DEV_GetNodeManager. + *! 11-Aug-2000 ag: Added DEV_GetCmmMgr() for shared memory management. + *! 10-Aug-2000 rr: DEV_InsertProcObject/RemoveProcObject added. + *! 06-Jun-2000 jeh Added DEV_GetSymbol(). + *! 05-Nov-1999 kc: Updated function prototypes. + *! 08-Oct-1997 cr: Added explicit CDECL function identifiers. + *! 07-Nov-1996 gp: Updated for code review. + *! 22-Oct-1996 gp: Added DEV_CleanupProcessState(). + *! 29-May-1996 gp: Changed DEV_HDEVNODE --> CFG_HDEVNODE. + *! 18-May-1996 gp: Created. + */ + +#ifndef DEV_ +#define DEV_ + +/* ----------------------------------- Module Dependent Headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* ----------------------------------- This */ +#include + + +/* + * ======== DEV_BrdWriteFxn ======== + * Purpose: + * Exported function to be used as the COD write function. This function + * is passed a handle to a DEV_hObject by ZL in pArb, then calls the + * device's WMD_BRD_Write() function. + * Parameters: + * pArb: Handle to a Device Object. + * hDevContext: Handle to mini-driver defined device info. + * dwDSPAddr: Address on DSP board (Destination). + * pHostBuf: Pointer to host buffer (Source). + * ulNumBytes: Number of bytes to transfer. + * ulMemType: Memory space on DSP to which to transfer. + * Returns: + * Number of bytes written. Returns 0 if the DEV_hObject passed in via + * pArb is invalid. + * Requires: + * DEV Initialized. + * pHostBuf != NULL + * Ensures: + */ + extern u32 DEV_BrdWriteFxn(void *pArb, + u32 ulDspAddr, + void *pHostBuf, + u32 ulNumBytes, u32 nMemSpace); + +/* + * ======== DEV_CreateDevice ======== + * Purpose: + * Called by the operating system to load the 'Bridge Mini Driver for a + * 'Bridge device. + * Parameters: + * phDevObject: Ptr to location to receive the device object handle. + * pstrWMDFileName: Name of WMD PE DLL file to load. If the absolute + * path is not provided, the file is loaded through + * 'Bridge's module search path. + * pHostConfig: Host configuration information, to be passed down + * to the WMD when WMD_DEV_Create() is called. + * pDspConfig: DSP resources, to be passed down to the WMD when + * WMD_DEV_Create() is called. + * hDevNode: Platform (Windows) specific device node. + * Returns: + * DSP_SOK: Module is loaded, device object has been created + * DSP_EMEMORY: Insufficient memory to create needed resources. + * DEV_E_NEWWMD: The WMD was compiled for a newer version of WCD. + * DEV_E_NULLWMDINTF: WMD passed back a NULL Fxn Interface Struct Ptr + * DEV_E_NOCODMODULE: No ZL file name was specified in the registry + * for this hDevNode. + * LDR_E_FILEUNABLETOOPEN: Unable to open the specified WMD. + * LDR_E_NOMEMORY: PELDR is out of resources. + * DSP_EFAIL: Unable to find WMD entry point function. + * COD_E_NOZLFUNCTIONS: One or more ZL functions exports not found. + * COD_E_ZLCREATEFAILED: Unable to load ZL DLL. + * Requires: + * DEV Initialized. + * phDevObject != NULL. + * pstrWMDFileName != NULL. + * pHostConfig != NULL. + * pDspConfig != NULL. + * Ensures: + * DSP_SOK: *phDevObject will contain handle to the new device object. + * Otherwise, does not create the device object, ensures the WMD module is + * unloaded, and sets *phDevObject to NULL. + */ + extern DSP_STATUS DEV_CreateDevice(OUT struct DEV_OBJECT + **phDevObject, + IN CONST char *pstrWMDFileName, + IN CONST struct CFG_HOSTRES + *pHostConfig, + IN CONST struct CFG_DSPRES + *pDspConfig, + struct CFG_DEVNODE *hDevNode); + +/* + * ======== DEV_CreateIVADevice ======== + * Purpose: + * Called by the operating system to load the 'Bridge Mini Driver for IVA. + * Parameters: + * phDevObject: Ptr to location to receive the device object handle. + * pstrWMDFileName: Name of WMD PE DLL file to load. If the absolute + * path is not provided, the file is loaded through + * 'Bridge's module search path. + * pHostConfig: Host configuration information, to be passed down + * to the WMD when WMD_DEV_Create() is called. + * pDspConfig: DSP resources, to be passed down to the WMD when + * WMD_DEV_Create() is called. + * hDevNode: Platform (Windows) specific device node. + * Returns: + * DSP_SOK: Module is loaded, device object has been created + * DSP_EMEMORY: Insufficient memory to create needed resources. + * DEV_E_NEWWMD: The WMD was compiled for a newer version of WCD. + * DEV_E_NULLWMDINTF: WMD passed back a NULL Fxn Interface Struct Ptr + * DEV_E_NOCODMODULE: No ZL file name was specified in the registry + * for this hDevNode. + * LDR_E_FILEUNABLETOOPEN: Unable to open the specified WMD. + * LDR_E_NOMEMORY: PELDR is out of resources. + * DSP_EFAIL: Unable to find WMD entry point function. + * COD_E_NOZLFUNCTIONS: One or more ZL functions exports not found. + * COD_E_ZLCREATEFAILED: Unable to load ZL DLL. + * Requires: + * DEV Initialized. + * phDevObject != NULL. + * pstrWMDFileName != NULL. + * pHostConfig != NULL. + * pDspConfig != NULL. + * Ensures: + * DSP_SOK: *phDevObject will contain handle to the new device object. + * Otherwise, does not create the device object, ensures the WMD module is + * unloaded, and sets *phDevObject to NULL. + */ + extern DSP_STATUS DEV_CreateIVADevice(OUT struct DEV_OBJECT + **phDevObject, + IN CONST char *pstrWMDFileName, + IN CONST struct CFG_HOSTRES *pHostConfig, + IN CONST struct CFG_DSPRES *pDspConfig, + struct CFG_DEVNODE *hDevNode); + +/* + * ======== DEV_Create2 ======== + * Purpose: + * After successful loading of the image from WCD_InitComplete2 + * (PROC Auto_Start) or PROC_Load this fxn is called. This creates + * the Node Manager and updates the DEV Object. + * Parameters: + * hDevObject: Handle to device object created with DEV_CreateDevice(). + * Returns: + * DSP_SOK: Successful Creation of Node Manager + * DSP_EFAIL: Some Error Occurred. + * Requires: + * DEV Initialized + * Valid hDevObject + * Ensures: + * DSP_SOK and hDevObject->hNodeMgr != NULL + * else hDevObject->hNodeMgr == NULL + */ + extern DSP_STATUS DEV_Create2(IN struct DEV_OBJECT *hDevObject); + +/* + * ======== DEV_Destroy2 ======== + * Purpose: + * Destroys the Node manager for this device. + * Parameters: + * hDevObject: Handle to device object created with DEV_CreateDevice(). + * Returns: + * DSP_SOK: Successful Creation of Node Manager + * DSP_EFAIL: Some Error Occurred. + * Requires: + * DEV Initialized + * Valid hDevObject + * Ensures: + * DSP_SOK and hDevObject->hNodeMgr == NULL + * else DSP_EFAIL. + */ + extern DSP_STATUS DEV_Destroy2(IN struct DEV_OBJECT *hDevObject); + +/* + * ======== DEV_DestroyDevice ======== + * Purpose: + * Destroys the channel manager for this device, if any, calls + * WMD_DEV_Destroy(), and then attempts to unload the WMD module. + * Parameters: + * hDevObject: Handle to device object created with + * DEV_CreateDevice(). + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hDevObject. + * DSP_EFAIL: The WMD failed it's WMD_DEV_Destroy() function. + * Requires: + * DEV Initialized. + * Ensures: + */ + extern DSP_STATUS DEV_DestroyDevice(struct DEV_OBJECT + *hDevObject); + +/* + * ======== DEV_GetChnlMgr ======== + * Purpose: + * Retrieve the handle to the channel manager created for this device. + * Parameters: + * hDevObject: Handle to device object created with + * DEV_CreateDevice(). + * *phMgr: Ptr to location to store handle. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hDevObject. + * Requires: + * phMgr != NULL. + * DEV Initialized. + * Ensures: + * DSP_SOK: *phMgr contains a handle to a channel manager object, + * or NULL. + * else: *phMgr is NULL. + */ + extern DSP_STATUS DEV_GetChnlMgr(struct DEV_OBJECT *hDevObject, + OUT struct CHNL_MGR **phMgr); + +/* + * ======== DEV_GetCmmMgr ======== + * Purpose: + * Retrieve the handle to the shared memory manager created for this + * device. + * Parameters: + * hDevObject: Handle to device object created with + * DEV_CreateDevice(). + * *phMgr: Ptr to location to store handle. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hDevObject. + * Requires: + * phMgr != NULL. + * DEV Initialized. + * Ensures: + * DSP_SOK: *phMgr contains a handle to a channel manager object, + * or NULL. + * else: *phMgr is NULL. + */ + extern DSP_STATUS DEV_GetCmmMgr(struct DEV_OBJECT *hDevObject, + OUT struct CMM_OBJECT **phMgr); + +/* + * ======== DEV_GetDmmMgr ======== + * Purpose: + * Retrieve the handle to the dynamic memory manager created for this + * device. + * Parameters: + * hDevObject: Handle to device object created with + * DEV_CreateDevice(). + * *phMgr: Ptr to location to store handle. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hDevObject. + * Requires: + * phMgr != NULL. + * DEV Initialized. + * Ensures: + * DSP_SOK: *phMgr contains a handle to a channel manager object, + * or NULL. + * else: *phMgr is NULL. + */ + extern DSP_STATUS DEV_GetDmmMgr(struct DEV_OBJECT *hDevObject, + OUT struct DMM_OBJECT **phMgr); + +/* + * ======== DEV_GetCodMgr ======== + * Purpose: + * Retrieve the COD manager create for this device. + * Parameters: + * hDevObject: Handle to device object created with + * DEV_CreateDevice(). + * *phCodMgr: Ptr to location to store handle. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hDevObject. + * Requires: + * phCodMgr != NULL. + * DEV Initialized. + * Ensures: + * DSP_SOK: *phCodMgr contains a handle to a COD manager object. + * else: *phCodMgr is NULL. + */ + extern DSP_STATUS DEV_GetCodMgr(struct DEV_OBJECT *hDevObject, + OUT struct COD_MANAGER **phCodMgr); + +/* + * ======== DEV_GetDehMgr ======== + * Purpose: + * Retrieve the DEH manager created for this device. + * Parameters: + * hDevObject: Handle to device object created with DEV_CreateDevice(). + * *phDehMgr: Ptr to location to store handle. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hDevObject. + * Requires: + * phDehMgr != NULL. + * DEH Initialized. + * Ensures: + * DSP_SOK: *phDehMgr contains a handle to a DEH manager object. + * else: *phDehMgr is NULL. + */ + extern DSP_STATUS DEV_GetDehMgr(struct DEV_OBJECT *hDevObject, + OUT struct DEH_MGR **phDehMgr); + +/* + * ======== DEV_GetDevNode ======== + * Purpose: + * Retrieve the platform specific device ID for this device. + * Parameters: + * hDevObject: Handle to device object created with + * DEV_CreateDevice(). + * phDevNode: Ptr to location to get the device node handle. + * Returns: + * DSP_SOK: In Win95, returns a DEVNODE in *hDevNode; In NT, ??? + * DSP_EHANDLE: Invalid hDevObject. + * Requires: + * phDevNode != NULL. + * DEV Initialized. + * Ensures: + * DSP_SOK: *phDevNode contains a platform specific device ID; + * else: *phDevNode is NULL. + */ + extern DSP_STATUS DEV_GetDevNode(struct DEV_OBJECT *hDevObject, + OUT struct CFG_DEVNODE **phDevNode); + +/* + * ======== DEV_GetDevType ======== + * Purpose: + * Retrieve the platform specific device ID for this device. + * Parameters: + * hDevObject: Handle to device object created with + * DEV_CreateDevice(). + * phDevNode: Ptr to location to get the device node handle. + * Returns: + * DSP_SOK: Success + * DSP_EHANDLE: Invalid hDevObject. + * Requires: + * phDevNode != NULL. + * DEV Initialized. + * Ensures: + * DSP_SOK: *phDevNode contains a platform specific device ID; + * else: *phDevNode is NULL. + */ + extern DSP_STATUS DEV_GetDevType(struct DEV_OBJECT *hdevObject, + u32 *devType); + +/* + * ======== DEV_GetFirst ======== + * Purpose: + * Retrieve the first Device Object handle from an internal linked list of + * of DEV_OBJECTs maintained by DEV. + * Parameters: + * Returns: + * NULL if there are no device objects stored; else + * a valid DEV_HOBJECT. + * Requires: + * No calls to DEV_CreateDevice or DEV_DestroyDevice (which my modify the + * internal device object list) may occur between calls to DEV_GetFirst + * and DEV_GetNext. + * Ensures: + * The DEV_HOBJECT returned is valid. + * A subsequent call to DEV_GetNext will return the next device object in + * the list. + */ + extern struct DEV_OBJECT *DEV_GetFirst(void); + +/* + * ======== DEV_GetIntfFxns ======== + * Purpose: + * Retrieve the WMD interface function structure for the loaded WMD. + * Parameters: + * hDevObject: Handle to device object created with + * DEV_CreateDevice(). + * *ppIntfFxns: Ptr to location to store fxn interface. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hDevObject. + * Requires: + * ppIntfFxns != NULL. + * DEV Initialized. + * Ensures: + * DSP_SOK: *ppIntfFxns contains a pointer to the WMD interface; + * else: *ppIntfFxns is NULL. + */ + extern DSP_STATUS DEV_GetIntfFxns(struct DEV_OBJECT *hDevObject, + OUT struct WMD_DRV_INTERFACE **ppIntfFxns); + +/* + * ======== DEV_GetIOMgr ======== + * Purpose: + * Retrieve the handle to the IO manager created for this device. + * Parameters: + * hDevObject: Handle to device object created with + * DEV_CreateDevice(). + * *phMgr: Ptr to location to store handle. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hDevObject. + * Requires: + * phMgr != NULL. + * DEV Initialized. + * Ensures: + * DSP_SOK: *phMgr contains a handle to an IO manager object. + * else: *phMgr is NULL. + */ + extern DSP_STATUS DEV_GetIOMgr(struct DEV_OBJECT *hDevObject, + OUT struct IO_MGR **phMgr); + +/* + * ======== DEV_GetNext ======== + * Purpose: + * Retrieve the next Device Object handle from an internal linked list of + * of DEV_OBJECTs maintained by DEV, after having previously called + * DEV_GetFirst() and zero or more DEV_GetNext + * Parameters: + * hDevObject: Handle to the device object returned from a previous + * call to DEV_GetFirst() or DEV_GetNext(). + * Returns: + * NULL if there are no further device objects on the list or hDevObject + * was invalid; + * else the next valid DEV_HOBJECT in the list. + * Requires: + * No calls to DEV_CreateDevice or DEV_DestroyDevice (which my modify the + * internal device object list) may occur between calls to DEV_GetFirst + * and DEV_GetNext. + * Ensures: + * The DEV_HOBJECT returned is valid. + * A subsequent call to DEV_GetNext will return the next device object in + * the list. + */ + extern struct DEV_OBJECT *DEV_GetNext(struct DEV_OBJECT + *hDevObject); + +/* + * ========= DEV_GetMsgMgr ======== + * Purpose: + * Retrieve the MSG Manager Handle from the DevObject. + * Parameters: + * hDevObject: Handle to the Dev Object + * phMsgMgr: Location where MSG Manager handle will be returned. + * Returns: + * Requires: + * DEV Initialized. + * Valid hDevObject. + * phNodeMgr != NULL. + * Ensures: + */ + extern void DEV_GetMsgMgr(struct DEV_OBJECT *hDevObject, + OUT struct MSG_MGR **phMsgMgr); + +/* + * ========= DEV_GetNodeManager ======== + * Purpose: + * Retrieve the Node Manager Handle from the DevObject. It is an + * accessor function + * Parameters: + * hDevObject: Handle to the Dev Object + * phNodeMgr: Location where Handle to the Node Manager will be + * returned.. + * Returns: + * DSP_SOK: Success + * DSP_EHANDLE: Invalid Dev Object handle. + * Requires: + * DEV Initialized. + * phNodeMgr is not null + * Ensures: + * DSP_SOK: *phNodeMgr contains a handle to a Node manager object. + * else: *phNodeMgr is NULL. + */ + extern DSP_STATUS DEV_GetNodeManager(struct DEV_OBJECT + *hDevObject, + OUT struct NODE_MGR **phNodeMgr); + +/* + * ======== DEV_GetSymbol ======== + * Purpose: + * Get the value of a symbol in the currently loaded program. + * Parameters: + * hDevObject: Handle to device object created with + * DEV_CreateDevice(). + * pstrSym: Name of symbol to look up. + * pulValue: Ptr to symbol value. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hDevObject. + * COD_E_NOSYMBOLSLOADED: Symbols have not been loaded onto the board. + * COD_E_SYMBOLNOTFOUND: The symbol could not be found. + * Requires: + * pstrSym != NULL. + * pulValue != NULL. + * DEV Initialized. + * Ensures: + * DSP_SOK: *pulValue contains the symbol value; + */ + extern DSP_STATUS DEV_GetSymbol(struct DEV_OBJECT *hDevObject, + IN CONST char *pstrSym, + OUT u32 *pulValue); + +/* + * ======== DEV_GetWMDContext ======== + * Purpose: + * Retrieve the WMD Context handle, as returned by the WMD_Create fxn. + * Parameters: + * hDevObject: Handle to device object created with DEV_CreateDevice() + * *phWmdContext: Ptr to location to store context handle. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hDevObject. + * Requires: + * phWmdContext != NULL. + * DEV Initialized. + * Ensures: + * DSP_SOK: *phWmdContext contains context handle; + * else: *phWmdContext is NULL; + */ + extern DSP_STATUS DEV_GetWMDContext(struct DEV_OBJECT *hDevObject, + OUT struct WMD_DEV_CONTEXT **phWmdContext); + +/* + * ======== DEV_Exit ======== + * Purpose: + * Decrement reference count, and free resources when reference count is + * 0. + * Parameters: + * Returns: + * Requires: + * DEV is initialized. + * Ensures: + * When reference count == 0, DEV's private resources are freed. + */ + extern void DEV_Exit(void); + +/* + * ======== DEV_Init ======== + * Purpose: + * Initialize DEV's private state, keeping a reference count on each call. + * Parameters: + * Returns: + * TRUE if initialized; FALSE if error occured. + * Requires: + * Ensures: + * TRUE: A requirement for the other public DEV functions. + */ + extern bool DEV_Init(void); + +/* + * ======== DEV_IsLocked ======== + * Purpose: + * Predicate function to determine if the device has been + * locked by a client for exclusive access. + * Parameters: + * hDevObject: Handle to device object created with + * DEV_CreateDevice(). + * Returns: + * DSP_SOK: TRUE: device has been locked. + * DSP_SFALSE: FALSE: device not locked. + * DSP_EHANDLE: hDevObject was invalid. + * Requires: + * DEV Initialized. + * Ensures: + */ + extern DSP_STATUS DEV_IsLocked(IN struct DEV_OBJECT *hDevObject); + +/* + * ======== DEV_InsertProcObject ======== + * Purpose: + * Inserts the Processor Object into the List of PROC Objects + * kept in the DEV Object + * Parameters: + * hProcObject: Handle to the Proc Object + * hDevObject Handle to the Dev Object + * bAttachedNew Specifies if there are already processors attached + * Returns: + * DSP_SOK: Successfully inserted into the list + * Requires: + * hProcObject is not NULL + * hDevObject is a valid handle to the DEV. + * DEV Initialized. + * List(of Proc object in Dev) Exists. + * Ensures: + * DSP_SOK & the PROC Object is inserted and the list is not empty + * Details: + * If the List of Proc Object is empty bAttachedNew is TRUE, it indicated + * this is the first Processor attaching. + * If it is False, there are already processors attached. + */ + extern DSP_STATUS DEV_InsertProcObject(IN struct DEV_OBJECT + *hDevObject, + IN u32 hProcObject, + OUT bool * + pbAlreadyAttached); + +/* + * ======== DEV_RemoveProcObject ======== + * Purpose: + * Search for and remove a Proc object from the given list maintained + * by the DEV + * Parameters: + * pProcObject: Ptr to ProcObject to insert. + * pDevObject: Ptr to Dev Object where the list is. + * pbAlreadyAttached: Ptr to return the bool + * Returns: + * DSP_SOK: If successful. + * DSP_EFAIL Failure to Remove the PROC Object from the list + * Requires: + * DevObject is Valid + * hProcObject != 0 + * pDevObject->procList != NULL + * !LST_IsEmpty(pDevObject->procList) + * pbAlreadyAttached !=NULL + * Ensures: + * Details: + * List will be deleted when the DEV is destroyed. + * + */ + extern DSP_STATUS DEV_RemoveProcObject(struct DEV_OBJECT + *hDevObject, + u32 hProcObject); + +/* + * ======== DEV_NotifyClients ======== + * Purpose: + * Notify all clients of this device of a change in device status. + * Clients may include multiple users of BRD, as well as CHNL. + * This function is asychronous, and may be called by a timer event + * set up by a watchdog timer. + * Parameters: + * hDevObject: Handle to device object created with DEV_CreateDevice(). + * ulStatus: A status word, most likely a BRD_STATUS. + * Returns: + * DSP_SOK: All registered clients were asynchronously notified. + * DSP_EINVALIDARG: Invalid hDevObject. + * Requires: + * DEV Initialized. + * Ensures: + * DSP_SOK: Notifications are queued by the operating system to be + * delivered to clients. This function does not ensure that + * the notifications will ever be delivered. + */ + extern DSP_STATUS DEV_NotifyClients(struct DEV_OBJECT *hDevObject, + u32 ulStatus); + + + +/* + * ======== DEV_RemoveDevice ======== + * Purpose: + * Destroys the Device Object created by DEV_StartDevice. + * Parameters: + * hDevNode: Device node as it is know to OS. + * Returns: + * DSP_SOK: If success; + * Otherwise. + * Requires: + * Ensures: + */ + extern DSP_STATUS DEV_RemoveDevice(struct CFG_DEVNODE *hDevNode); + +/* + * ======== DEV_SetChnlMgr ======== + * Purpose: + * Set the channel manager for this device. + * Parameters: + * hDevObject: Handle to device object created with + * DEV_CreateDevice(). + * hMgr: Handle to a channel manager, or NULL. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hDevObject. + * Requires: + * DEV Initialized. + * Ensures: + */ + extern DSP_STATUS DEV_SetChnlMgr(struct DEV_OBJECT *hDevObject, + struct CHNL_MGR *hMgr); + +/* + * ======== DEV_SetMsgMgr ======== + * Purpose: + * Set the Message manager for this device. + * Parameters: + * hDevObject: Handle to device object created with DEV_CreateDevice(). + * hMgr: Handle to a message manager, or NULL. + * Returns: + * Requires: + * DEV Initialized. + * Ensures: + */ + extern void DEV_SetMsgMgr(struct DEV_OBJECT *hDevObject, + struct MSG_MGR *hMgr); + +/* + * ======== DEV_StartDevice ======== + * Purpose: + * Initializes the new device with the WinBRIDGE environment. This + * involves querying CM for allocated resources, querying the registry + * for necessary dsp resources (requested in the INF file), and using + * this information to create a WinBRIDGE device object. + * Parameters: + * hDevNode: Device node as it is know to OS. + * Returns: + * DSP_SOK: If success; + * Otherwise. + * Requires: + * DEV initialized. + * Ensures: + */ + extern DSP_STATUS DEV_StartDevice(struct CFG_DEVNODE *hDevNode); + +#endif /* DEV_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/devdefs.h b/arch/arm/plat-omap/include/dspbridge/devdefs.h new file mode 100644 index 0000000..e9ff725 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/devdefs.h @@ -0,0 +1,35 @@ +/* + * devdefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== devdefs.h ======== + * Purpose: + * Definition of common include typedef between wmd.h and dev.h. Required + * to break circular dependency between WMD and DEV include files. + * + *! Revision History: + *! ================ + *! 12-Nov-1996 gp: Renamed from dev1.h. + *! 30-May-1996 gp: Broke out from dev.h + */ + +#ifndef DEVDEFS_ +#define DEVDEFS_ + +/* WCD Device Object */ + struct DEV_OBJECT; + +#endif /* DEVDEFS_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/disp.h b/arch/arm/plat-omap/include/dspbridge/disp.h new file mode 100644 index 0000000..e116734 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/disp.h @@ -0,0 +1,236 @@ +/* + * disp.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== disp.h ======== + * + * Description: + * DSP/BIOS Bridge Node Dispatcher. + * + * Public Functions: + * DISP_Create + * DISP_Delete + * DISP_Exit + * DISP_Init + * DISP_NodeChangePriority + * DISP_NodeCreate + * DISP_NodeDelete + * DISP_NodeRun + * + *! Revision History: + *! ================= + *! 28-Jan-2003 map Removed DISP_DoCinit(). + *! 15-May-2002 jeh Added DISP_DoCinit(). + *! 24-Apr-2002 jeh Added DISP_MemWrite(). + *! 07-Sep-2001 jeh Added DISP_MemCopy(). + *! 10-May-2001 jeh Code review cleanup. + *! 08-Aug-2000 jeh Removed DISP_NodeTerminate since it no longer uses RMS. + *! 17-Jul-2000 jeh Updates to function headers. + *! 19-Jun-2000 jeh Created. + */ + +#ifndef DISP_ +#define DISP_ + +#include +#include +#include +#include + +/* + * ======== DISP_Create ======== + * Create a NODE Dispatcher object. This object handles the creation, + * deletion, and execution of nodes on the DSP target, through communication + * with the Resource Manager Server running on the target. Each NODE + * Manager object should have exactly one NODE Dispatcher. + * + * Parameters: + * phDispObject: Location to store node dispatcher object on output. + * hDevObject: Device for this processor. + * pDispAttrs: Node dispatcher attributes. + * Returns: + * DSP_SOK: Success; + * DSP_EMEMORY: Insufficient memory for requested resources. + * DSP_EFAIL: Unable to create dispatcher. + * Requires: + * DISP_Init(void) called. + * pDispAttrs != NULL. + * hDevObject != NULL. + * phDispObject != NULL. + * Ensures: + * DSP_SOK: IsValid(*phDispObject). + * error: *phDispObject == NULL. + */ + extern DSP_STATUS DISP_Create(OUT struct DISP_OBJECT **phDispObject, + struct DEV_OBJECT *hDevObject, + IN CONST struct DISP_ATTRS *pDispAttrs); + +/* + * ======== DISP_Delete ======== + * Delete the NODE Dispatcher. + * + * Parameters: + * hDispObject: Node Dispatcher object. + * Returns: + * Requires: + * DISP_Init(void) called. + * Valid hDispObject. + * Ensures: + * hDispObject is invalid. + */ + extern void DISP_Delete(struct DISP_OBJECT *hDispObject); + +/* + * ======== DISP_Exit ======== + * Discontinue usage of DISP module. + * + * Parameters: + * Returns: + * Requires: + * DISP_Init(void) previously called. + * Ensures: + * Any resources acquired in DISP_Init(void) will be freed when last DISP + * client calls DISP_Exit(void). + */ + extern void DISP_Exit(void); + +/* + * ======== DISP_Init ======== + * Initialize the DISP module. + * + * Parameters: + * Returns: + * TRUE if initialization succeeded, FALSE otherwise. + * Ensures: + */ + extern bool DISP_Init(void); + +/* + * ======== DISP_NodeChangePriority ======== + * Change the priority of a node currently running on the target. + * + * Parameters: + * hDispObject: Node Dispatcher object. + * hNode: Node object representing a node currently + * allocated or running on the DSP. + * ulFxnAddress: Address of RMS function for changing priority. + * nodeEnv: Address of node's environment structure. + * nPriority: New priority level to set node's priority to. + * Returns: + * DSP_SOK: Success. + * DSP_ETIMEOUT: A timeout occurred before the DSP responded. + * Requires: + * DISP_Init(void) called. + * Valid hDispObject. + * hNode != NULL. + * Ensures: + */ + extern DSP_STATUS DISP_NodeChangePriority(struct DISP_OBJECT + *hDispObject, + struct NODE_OBJECT *hNode, + u32 ulFxnAddr, + NODE_ENV nodeEnv, + s32 nPriority); + +/* + * ======== DISP_NodeCreate ======== + * Create a node on the DSP by remotely calling the node's create function. + * + * Parameters: + * hDispObject: Node Dispatcher object. + * hNode: Node handle obtained from NODE_Allocate(). + * ulFxnAddr: Address or RMS create node function. + * ulCreateFxn: Address of node's create function. + * pArgs: Arguments to pass to RMS node create function. + * pNodeEnv: Location to store node environment pointer on + * output. + * Returns: + * DSP_SOK: Success. + * DSP_ETASK: Unable to create the node's task or process on the DSP. + * DSP_ESTREAM: Stream creation failure on the DSP. + * DSP_ETIMEOUT: A timeout occurred before the DSP responded. + * DSP_EUSER: A user-defined failure occurred. + * DSP_EFAIL: A failure occurred, unable to create node. + * Requires: + * DISP_Init(void) called. + * Valid hDispObject. + * pArgs != NULL. + * hNode != NULL. + * pNodeEnv != NULL. + * NODE_GetType(hNode) != NODE_DEVICE. + * Ensures: + */ + extern DSP_STATUS DISP_NodeCreate(struct DISP_OBJECT *hDispObject, + struct NODE_OBJECT *hNode, + u32 ulFxnAddr, + u32 ulCreateFxn, + IN CONST struct NODE_CREATEARGS + *pArgs, + OUT NODE_ENV *pNodeEnv); + +/* + * ======== DISP_NodeDelete ======== + * Delete a node on the DSP by remotely calling the node's delete function. + * + * Parameters: + * hDispObject: Node Dispatcher object. + * hNode: Node object representing a node currently + * loaded on the DSP. + * ulFxnAddr: Address or RMS delete node function. + * ulDeleteFxn: Address of node's delete function. + * nodeEnv: Address of node's environment structure. + * Returns: + * DSP_SOK: Success. + * DSP_ETIMEOUT: A timeout occurred before the DSP responded. + * Requires: + * DISP_Init(void) called. + * Valid hDispObject. + * hNode != NULL. + * Ensures: + */ + extern DSP_STATUS DISP_NodeDelete(struct DISP_OBJECT *hDispObject, + struct NODE_OBJECT *hNode, + u32 ulFxnAddr, + u32 ulDeleteFxn, NODE_ENV nodeEnv); + +/* + * ======== DISP_NodeRun ======== + * Start execution of a node's execute phase, or resume execution of a node + * that has been suspended (via DISP_NodePause()) on the DSP. + * + * Parameters: + * hDispObject: Node Dispatcher object. + * hNode: Node object representing a node to be executed + * on the DSP. + * ulFxnAddr: Address or RMS node execute function. + * ulExecuteFxn: Address of node's execute function. + * nodeEnv: Address of node's environment structure. + * Returns: + * DSP_SOK: Success. + * DSP_ETIMEOUT: A timeout occurred before the DSP responded. + * Requires: + * DISP_Init(void) called. + * Valid hDispObject. + * hNode != NULL. + * Ensures: + */ + extern DSP_STATUS DISP_NodeRun(struct DISP_OBJECT *hDispObject, + struct NODE_OBJECT *hNode, + u32 ulFxnAddr, + u32 ulExecuteFxn, NODE_ENV nodeEnv); + +#endif /* DISP_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/dispdefs.h b/arch/arm/plat-omap/include/dspbridge/dispdefs.h new file mode 100644 index 0000000..401ad4f --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dispdefs.h @@ -0,0 +1,45 @@ +/* + * dispdefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dispdefs.h ======== + * Description: + * Global DISP constants and types, shared by PROCESSOR, NODE, and DISP. + * + *! Revision History + *! ================ + *! 08-Aug-2000 jeh Added fields to DISP_ATTRS. + *! 06-Jul-2000 jeh Created. + */ + +#ifndef DISPDEFS_ +#define DISPDEFS_ + + struct DISP_OBJECT; + +/* Node Dispatcher attributes */ + struct DISP_ATTRS { + u32 ulChnlOffset; /* Offset of channel ids reserved for RMS */ + /* Size of buffer for sending data to RMS */ + u32 ulChnlBufSize; + DSP_PROCFAMILY procFamily; /* eg, 5000 */ + DSP_PROCTYPE procType; /* eg, 5510 */ + HANDLE hReserved1; /* Reserved for future use. */ + u32 hReserved2; /* Reserved for future use. */ + } ; + +#endif /* DISPDEFS_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/dmm.h b/arch/arm/plat-omap/include/dspbridge/dmm.h new file mode 100644 index 0000000..ef37668 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dmm.h @@ -0,0 +1,85 @@ +/* + * dmm.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dmm.h ======== + * Purpose: + * The Dynamic Memory Mapping(DMM) module manages the DSP Virtual address + * space that can be directly mapped to any MPU buffer or memory region + * + * Public Functions: + * + *! Revision History: + *! ================ + *! 20-Feb-2004 sb: Created. + *! + */ + +#ifndef DMM_ +#define DMM_ + +#include + + struct DMM_OBJECT; + +/* DMM attributes used in DMM_Create() */ + struct DMM_MGRATTRS { + u32 reserved; + } ; + +#define DMMPOOLSIZE 0x4000000 + +/* + * ======== DMM_GetHandle ======== + * Purpose: + * Return the dynamic memory manager object for this device. + * This is typically called from the client process. + */ + + extern DSP_STATUS DMM_GetHandle(DSP_HPROCESSOR hProcessor, + OUT struct DMM_OBJECT **phDmmMgr); + + extern DSP_STATUS DMM_ReserveMemory(struct DMM_OBJECT *hDmmMgr, + u32 size, + u32 *pRsvAddr); + + extern DSP_STATUS DMM_UnReserveMemory(struct DMM_OBJECT *hDmmMgr, + u32 rsvAddr); + + extern DSP_STATUS DMM_MapMemory(struct DMM_OBJECT *hDmmMgr, u32 addr, + u32 size); + + extern DSP_STATUS DMM_UnMapMemory(struct DMM_OBJECT *hDmmMgr, + u32 addr, + u32 *pSize); + + extern DSP_STATUS DMM_Destroy(struct DMM_OBJECT *hDmmMgr); + + extern DSP_STATUS DMM_DeleteTables(struct DMM_OBJECT *hDmmMgr); + + extern DSP_STATUS DMM_Create(OUT struct DMM_OBJECT **phDmmMgr, + struct DEV_OBJECT *hDevObject, + IN CONST struct DMM_MGRATTRS *pMgrAttrs); + + extern bool DMM_Init(void); + + extern void DMM_Exit(void); + + extern DSP_STATUS DMM_CreateTables(struct DMM_OBJECT *hDmmMgr, + u32 addr, u32 size); + extern u32 *DMM_GetPhysicalAddrTable(void); +#endif /* DMM_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/dpc.h b/arch/arm/plat-omap/include/dspbridge/dpc.h new file mode 100644 index 0000000..8c20506 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dpc.h @@ -0,0 +1,167 @@ +/* + * dpc.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dpc.h ======== + * Purpose: + * Deferred Procedure Call(DPC) Services. + * + * Public Functions: + * DPC_Cancel + * DPC_Create + * DPC_Destroy + * DPC_Exit + * DPC_Init + * DPC_Schedule + * + *! Revision History: + *! ================ + *! 31-Jan-2000 rr: DPC_Destroy ensures Suceess and DPC Object is NULL. + *! 21-Jan-2000 ag: Updated comments per code review. + *! 06-Jan-2000 ag: Removed DPC_[Lower|Raise]IRQL[From|To]DispatchLevel. + *! 14-Jan-1998 gp: Added DPC_[Lower|Raise]IRQL[From|To]DispatchLevel. + *! 18-Aug-1997 cr: Added explicit CDECL identifiers. + *! 28-Jul-1996 gp: Created. + */ + +#ifndef DPC_ +#define DPC_ + + struct DPC_OBJECT; + +/* + * ======== DPC_PROC ======== + * Purpose: + * Deferred processing routine. Typically scheduled from an ISR to + * complete I/O processing. + * Parameters: + * pRefData: Ptr to user data: passed in via ISR_ScheduleDPC. + * Returns: + * Requires: + * The DPC should not block, or otherwise acquire resources. + * Interrupts to the processor are enabled. + * DPC_PROC executes in a critical section. + * Ensures: + * This DPC will not be reenterred on the same thread. + * However, the DPC may take hardware interrupts during execution. + * Interrupts to the processor are enabled. + */ + typedef void(*DPC_PROC) (void *pRefData); + +/* + * ======== DPC_Cancel ======== + * Purpose: + * Cancel a DPC previously scheduled by DPC_Schedule. + * Parameters: + * hDPC: A DPC object handle created in DPC_Create(). + * Returns: + * DSP_SOK: Scheduled DPC, if any, is cancelled. + * DSP_SFALSE: No DPC is currently scheduled for execution. + * DSP_EHANDLE: Invalid hDPC. + * Requires: + * Ensures: + * If the DPC has already executed, is executing, or was not yet + * scheduled, this function will have no effect. + */ + extern DSP_STATUS DPC_Cancel(IN struct DPC_OBJECT *hDPC); + +/* + * ======== DPC_Create ======== + * Purpose: + * Create a DPC object, allowing a client's own DPC procedure to be + * scheduled for a call with client reference data. + * Parameters: + * phDPC: Pointer to location to store DPC object. + * pfnDPC: Client's DPC procedure. + * pRefData: Pointer to user-defined reference data. + * Returns: + * DSP_SOK: DPC object created. + * DSP_EPOINTER: phDPC == NULL or pfnDPC == NULL. + * DSP_EMEMORY: Insufficient memory. + * Requires: + * Must not be called at interrupt time. + * Ensures: + * DSP_SOK: DPC object is created; + * else: *phDPC is set to NULL. + */ + extern DSP_STATUS DPC_Create(OUT struct DPC_OBJECT **phDPC, + IN DPC_PROC pfnDPC, + IN void *pRefData); + +/* + * ======== DPC_Destroy ======== + * Purpose: + * Cancel the last scheduled DPC, and deallocate a DPC object previously + * allocated with DPC_Create().Frees the Object only if the thread and + * the events are terminated successfuly. + * Parameters: + * hDPC: A DPC object handle created in DPC_Create(). + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hDPC. + * Requires: + * All DPC's scheduled for the DPC object must have completed their + * processing. + * Ensures: + * (SUCCESS && hDPC is NULL) or DSP_EFAILED status + */ + extern DSP_STATUS DPC_Destroy(IN struct DPC_OBJECT *hDPC); + +/* + * ======== DPC_Exit ======== + * Purpose: + * Discontinue usage of the DPC module. + * Parameters: + * Returns: + * Requires: + * DPC_Init(void) was previously called. + * Ensures: + * Resources acquired in DPC_Init(void) are freed. + */ + extern void DPC_Exit(void); + +/* + * ======== DPC_Init ======== + * Purpose: + * Initialize the DPC module's private state. + * Parameters: + * Returns: + * TRUE if initialized; FALSE if error occured. + * Requires: + * Ensures: + * A requirement for each of the other public DPC functions. + */ + extern bool DPC_Init(void); + +/* + * ======== DPC_Schedule ======== + * Purpose: + * Schedule a deferred procedure call to be executed at a later time. + * Latency and order of DPC execution is platform specific. + * Parameters: + * hDPC: A DPC object handle created in DPC_Create(). + * Returns: + * DSP_SOK: An event is scheduled for deferred processing. + * DSP_EHANDLE: Invalid hDPC. + * Requires: + * See requirements for DPC_PROC. + * Ensures: + * DSP_SOK: The DPC will not be called before this function returns. + */ + extern DSP_STATUS DPC_Schedule(IN struct DPC_OBJECT *hDPC); + +#endif /* DPC_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/drv.h b/arch/arm/plat-omap/include/dspbridge/drv.h new file mode 100644 index 0000000..c468461 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/drv.h @@ -0,0 +1,449 @@ +/* + * drv.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== drv.h ======== + * Purpose: + * DRV Resource allocation module. Driver Object gets Created + * at the time of Loading. It holds the List of Device Objects + * in the Syste, + * + * Public Functions: + * DRV_Create + * DRV_Destroy + * DRV_Exit + * DRV_GetDevObject + * DRV_GetDevExtension + * DRV_GetFirstDevObject + * DRV_GetNextDevObject + * DRV_GetNextDevExtension + * DRV_Init + * DRV_InsertDevObject + * DRV_RemoveDevObject + * DRV_RequestResources + * DRV_ReleaseResources + * + *! Revision History + *! ================ + *! 10-Feb-2004 vp: Added OMAP24xx specific definitions. + *! 14-Aug-2000 rr: Cleaned up. + *! 27-Jul-2000 rr: DRV_RequestResources split into two(Request and Release) + *! Device extension created to hold the DevNodeString. + *! 17-Jul-2000 rr: Driver Object holds the list of Device Objects. + *! Added DRV_Create, DRV_Destroy, DRV_GetDevObject, + *! DRV_GetFirst/NextDevObject, DRV_Insert/RemoveDevObject. + *! 12-Nov-1999 rr: New Flag defines for DRV_ASSIGN and DRV_RELEASE + *! 25-Oct-1999 rr: Resource Structure removed. + *! 15-Oct-1999 rr: New Resource structure created. + *! 05-Oct-1999 rr: Added DRV_RequestResources + *! Removed fxn'sDRV_RegisterMiniDriver(), + *! DRV_UnRegisterMiniDriver() + *! Removed Structures DSP_DRIVER & DRV_EXTENSION. + *! + *! 24-Sep-1999 rr: Added DRV_EXTENSION and DSP_DRIVER structures. + *! + */ + +#ifndef DRV_ +#define DRV_ + +#include + +#include + +#define DRV_ASSIGN 1 +#define DRV_RELEASE 0 + +/* Provide the DSP Internal memory windows that can be accessed from L3 address + * space */ + +#define OMAP_GEM_BASE 0x107F8000 +#define OMAP_DSP_SIZE 0x00720000 + +/* MEM1 is L2 RAM + L2 Cache space */ +#define OMAP_DSP_MEM1_BASE 0x5C7F8000 +#define OMAP_DSP_MEM1_SIZE 0x18000 +#define OMAP_DSP_GEM1_BASE 0x107F8000 + + +/* MEM2 is L1P RAM/CACHE space */ +#define OMAP_DSP_MEM2_BASE 0x5CE00000 +#define OMAP_DSP_MEM2_SIZE 0x8000 +#define OMAP_DSP_GEM2_BASE 0x10E00000 + +/* MEM3 is L1D RAM/CACHE space */ +#define OMAP_DSP_MEM3_BASE 0x5CF04000 +#define OMAP_DSP_MEM3_SIZE 0x14000 +#define OMAP_DSP_GEM3_BASE 0x10F04000 + + +#define OMAP_IVA2_PRM_BASE 0x48306000 +#define OMAP_IVA2_PRM_SIZE 0x1000 + +#define OMAP_IVA2_CM_BASE 0x48004000 +#define OMAP_IVA2_CM_SIZE 0x1000 + +#define OMAP_PER_CM_BASE 0x48005000 +#define OMAP_PER_CM_SIZE 0x1000 + +#define OMAP_PER_PRM_BASE 0x48307000 +#define OMAP_PER_PRM_SIZE 0x1000 + +#define OMAP_CORE_PRM_BASE 0x48306A00 +#define OMAP_CORE_PRM_SIZE 0x1000 + +#define OMAP_SYSC_BASE 0x48002000 +#define OMAP_SYSC_SIZE 0x1000 + +#define OMAP_MBOX_BASE 0x48094000 +#define OMAP_MBOX_SIZE 0x1000 + +#define OMAP_DMMU_BASE 0x5D000000 +#define OMAP_DMMU_SIZE 0x1000 + +#define OMAP_PRCM_VDD1_DOMAIN 1 +#define OMAP_PRCM_VDD2_DOMAIN 2 + +#ifndef RES_CLEANUP_DISABLE + +/* GPP PROCESS CLEANUP Data structures */ + +/* New structure (member of process context) abstracts NODE resource info */ +struct NODE_RES_OBJECT { + DSP_HNODE hNode; + s32 nodeAllocated; /* Node status */ + s32 heapAllocated; /* Heap status */ + s32 streamsAllocated; /* Streams status */ + struct NODE_RES_OBJECT *next; +} ; + +/* New structure (member of process context) abstracts DMM resource info */ +struct DMM_RES_OBJECT { + s32 dmmAllocated; /* DMM status */ + u32 ulMpuAddr; + u32 ulDSPAddr; + u32 ulDSPResAddr; + u32 dmmSize; + HANDLE hProcessor; + struct DMM_RES_OBJECT *next; +} ; + +/* New structure (member of process context) abstracts DMM resource info */ +struct DSPHEAP_RES_OBJECT { + s32 heapAllocated; /* DMM status */ + u32 ulMpuAddr; + u32 ulDSPAddr; + u32 ulDSPResAddr; + u32 heapSize; + HANDLE hProcessor; + struct DSPHEAP_RES_OBJECT *next; +} ; + +/* New structure (member of process context) abstracts stream resource info */ +struct STRM_RES_OBJECT { + s32 streamAllocated; /* Stream status */ + DSP_HSTREAM hStream; + u32 uNumBufs; + u32 uDir; + struct STRM_RES_OBJECT *next; +} ; + +/* Overall Bridge process resource usage state */ +enum GPP_PROC_RES_STATE { + PROC_RES_ALLOCATED, + PROC_RES_FREED +} ; + +/* Process Context */ +struct PROCESS_CONTEXT{ + /* Process State */ + enum GPP_PROC_RES_STATE resState; + + /* Process ID (Same as UNIX process ID) */ + u32 pid; + + /* Pointer to next process context + * (To maintain a linked list of process contexts) */ + struct PROCESS_CONTEXT *next; + + /* Processor info to which the process is related */ + DSP_HPROCESSOR hProcessor; + + /* DSP Node resources */ + struct NODE_RES_OBJECT *pNodeList; + + /* DMM resources */ + struct DMM_RES_OBJECT *pDMMList; + + /* DSP Heap resources */ + struct DSPHEAP_RES_OBJECT *pDSPHEAPList; + + /* Stream resources */ + struct STRM_RES_OBJECT *pSTRMList; +} ; +#endif + +/* + * ======== DRV_Create ======== + * Purpose: + * Creates the Driver Object. This is done during the driver loading. + * There is only one Driver Object in the DSP/BIOS Bridge. + * Parameters: + * phDrvObject: Location to store created DRV Object handle. + * Returns: + * DSP_SOK: Sucess + * DSP_EMEMORY: Failed in Memory allocation + * DSP_EFAIL: General Failure + * Requires: + * DRV Initialized (cRefs > 0 ) + * phDrvObject != NULL. + * Ensures: + * DSP_SOK: - *phDrvObject is a valid DRV interface to the device. + * - List of DevObject Created and Initialized. + * - List of DevNode String created and intialized. + * - Registry is updated with the DRV Object. + * !DSP_SOK: DRV Object not created + * Details: + * There is one Driver Object for the Driver representing + * the driver itself. It contains the list of device + * Objects and the list of Device Extensions in the system. + * Also it can hold other neccessary + * information in its storage area. + */ + extern DSP_STATUS DRV_Create(struct DRV_OBJECT **phDrvObject); + +/* + * ======== DRV_Destroy ======== + * Purpose: + * destroys the Dev Object list, DrvExt list + * and destroy the DRV object + * Called upon driver unLoading.or unsuccesful loading of the driver. + * Parameters: + * hDrvObject: Handle to Driver object . + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Failed to destroy DRV Object + * Requires: + * DRV Initialized (cRegs > 0 ) + * hDrvObject is not NULL and a valid DRV handle . + * List of DevObject is Empty. + * List of DrvExt is Empty + * Ensures: + * DSP_SOK: - DRV Object destroyed and hDrvObject is not a valid + * DRV handle. + * - Registry is updated with "0" as the DRV Object. + */ + extern DSP_STATUS DRV_Destroy(struct DRV_OBJECT *hDrvObject); + +/* + * ======== DRV_Exit ======== + * Purpose: + * Exit the DRV module, freeing any modules initialized in DRV_Init. + * Parameters: + * Returns: + * Requires: + * Ensures: + */ + extern void DRV_Exit(void); + +/* + * ======== DRV_GetFirstDevObject ======== + * Purpose: + * Returns the Ptr to the FirstDev Object in the List + * Parameters: + * Requires: + * DRV Initialized + * Returns: + * dwDevObject: Ptr to the First Dev Object as a u32 + * 0 if it fails to retrieve the First Dev Object + * Ensures: + */ + extern u32 DRV_GetFirstDevObject(void); + +/* + * ======== DRV_GetFirstDevExtension ======== + * Purpose: + * Returns the Ptr to the First Device Extension in the List + * Parameters: + * Requires: + * DRV Initialized + * Returns: + * dwDevExtension: Ptr to the First Device Extension as a u32 + * 0: Failed to Get the Device Extension + * Ensures: + */ + extern u32 DRV_GetFirstDevExtension(void); + +/* + * ======== DRV_GetDevObject ======== + * Purpose: + * Given a index, returns a handle to DevObject from the list + * Parameters: + * hDrvObject: Handle to the Manager + * phDevObject: Location to store the Dev Handle + * Requires: + * DRV Initialized + * uIndex >= 0 + * hDrvObject is not NULL and Valid DRV Object + * phDevObject is not NULL + * Device Object List not Empty + * Returns: + * DSP_SOK: Success + * DSP_EFAIL: Failed to Get the Dev Object + * Ensures: + * DSP_SOK: *phDevObject != NULL + * DSP_EFAIL: *phDevObject = NULL + */ + extern DSP_STATUS DRV_GetDevObject(u32 uIndex, + struct DRV_OBJECT *hDrvObject, + struct DEV_OBJECT **phDevObject); + +/* + * ======== DRV_GetNextDevObject ======== + * Purpose: + * Returns the Ptr to the Next Device Object from the the List + * Parameters: + * hDevObject: Handle to the Device Object + * Requires: + * DRV Initialized + * hDevObject != 0 + * Returns: + * dwDevObject: Ptr to the Next Dev Object as a u32 + * 0: If it fail to get the next Dev Object. + * Ensures: + */ + extern u32 DRV_GetNextDevObject(u32 hDevObject); + +/* + * ======== DRV_GetNextDevExtension ======== + * Purpose: + * Returns the Ptr to the Next Device Extension from the the List + * Parameters: + * hDevExtension: Handle to the Device Extension + * Requires: + * DRV Initialized + * hDevExtension != 0. + * Returns: + * dwDevExtension: Ptr to the Next Dev Extension + * 0: If it fail to Get the next Dev Extension + * Ensures: + */ + extern u32 DRV_GetNextDevExtension(u32 hDevExtension); + +/* + * ======== DRV_Init ======== + * Purpose: + * Initialize the DRV module. + * Parameters: + * Returns: + * TRUE if success; FALSE otherwise. + * Requires: + * Ensures: + */ + extern DSP_STATUS DRV_Init(void); + +/* + * ======== DRV_InsertDevObject ======== + * Purpose: + * Insert a DeviceObject into the list of Driver object. + * Parameters: + * hDrvObject: Handle to DrvObject + * hDevObject: Handle to DeviceObject to insert. + * Returns: + * DSP_SOK: If successful. + * DSP_EFAIL: General Failure: + * Requires: + * hDrvObject != NULL and Valid DRV Handle. + * hDevObject != NULL. + * Ensures: + * DSP_SOK: Device Object is inserted and the List is not empty. + */ + extern DSP_STATUS DRV_InsertDevObject(struct DRV_OBJECT *hDrvObject, + struct DEV_OBJECT *hDevObject); + +/* + * ======== DRV_RemoveDevObject ======== + * Purpose: + * Search for and remove a Device object from the given list of Device Obj + * objects. + * Parameters: + * hDrvObject: Handle to DrvObject + * hDevObject: Handle to DevObject to Remove + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Unable to find pDevObject. + * Requires: + * hDrvObject != NULL and a Valid DRV Handle. + * hDevObject != NULL. + * List exists and is not empty. + * Ensures: + * List either does not exist (NULL), or is not empty if it does exist. +*/ + extern DSP_STATUS DRV_RemoveDevObject(struct DRV_OBJECT *hDrvObject, + struct DEV_OBJECT *hDevObject); + +/* + * ======== DRV_RequestResources ======== + * Purpose: + * Assigns the Resources or Releases them. + * Parameters: + * dwContext: Path to the driver Registry Key. + * pDevNodeString: Ptr to DevNode String stored in the Device Ext. + * Returns: + * TRUE if success; FALSE otherwise. + * Requires: + * Ensures: + * The Resources are assigned based on Bus type. + * The hardware is initialized. Resource information is + * gathered from the Registry(ISA, PCMCIA)or scanned(PCI) + * Resource structure is stored in the registry which will be + * later used by the CFG module. + */ + extern DSP_STATUS DRV_RequestResources(IN u32 dwContext, + OUT u32 *pDevNodeString); + +/* + * ======== DRV_ReleaseResources ======== + * Purpose: + * Assigns the Resources or Releases them. + * Parameters: + * dwContext: Path to the driver Registry Key. + * hDrvObject: Handle to the Driver Object. + * Returns: + * TRUE if success; FALSE otherwise. + * Requires: + * Ensures: + * The Resources are released based on Bus type. + * Resource structure is deleted from the registry + */ + extern DSP_STATUS DRV_ReleaseResources(IN u32 dwContext, + struct DRV_OBJECT *hDrvObject); + +/* + * ======== DRV_ProcFreeDMMRes ======== + * Purpose: + * Actual DMM De-Allocation. + * Parameters: + * hPCtxt: Path to the driver Registry Key. + * Returns: + * DSP_SOK if success; + */ + + + extern DSP_STATUS DRV_ProcFreeDMMRes(HANDLE hPCtxt); + +#endif /* DRV_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/drvdefs.h b/arch/arm/plat-omap/include/dspbridge/drvdefs.h new file mode 100644 index 0000000..ed86010 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/drvdefs.h @@ -0,0 +1,34 @@ +/* + * drvdefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== drvdefs.h ======== + * Purpose: + * Definition of common include typedef between wmd.h and drv.h. + * + *! Revision History: + *! ================ + *! 17-Jul-2000 rr: Created + */ + +#ifndef DRVDEFS_ +#define DRVDEFS_ + +/* WCD Driver Object */ + struct DRV_OBJECT; + +#endif /* DRVDEFS_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/dspdrv.h b/arch/arm/plat-omap/include/dspbridge/dspdrv.h new file mode 100644 index 0000000..f500ffb --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dspdrv.h @@ -0,0 +1,106 @@ +/* + * dspdrv.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dspdrv.h ======== + * Purpose: + * This is the Stream Interface for the DDSP Class driver. + * All Device operations are performed via DeviceIOControl. + * Read, Seek and Write not used. + * + * Public Functions + * DSP_Close + * DSP_Deinit + * DSP_Init + * DSP_IOControl + * DSP_Open + * DSP_PowerUp + * DSP_PowerDown + * + *! Revision History + *! ================ + *! 28-Jan-2000 rr: Type void changed to Void. + *! 02-Dec-1999 rr: MAX_DEV define moved from wcdce.c file.Code cleaned up. + *! 12-Nov-1999 rr: "#include removed. + *! 05-Oct-1999 rr Renamed the file name to wcdce.h Removed Bus Specific + *! code and #defines to PCCARD.h. + *! 24-Sep-1999 rr Changed the DSP_COMMON_WINDOW_SIZE to 0x4000(16k) for the + *! Memory windows. + *! 16-Jul-1999 ag Adapted from rkw's CAC Bullet driver. + *! + */ + +#if !defined __DSPDRV_h__ +#define __DSPDRV_h__ + +#define MAX_DEV 10 /* Max support of 10 devices */ + +/* + * ======== DSP_Close ======== + * Purpose: + * Called when the client application/driver unloads the DDSP DLL. Upon + * unloading, the DDSP DLL will call CloseFile(). + * Parameters: + * dwDeviceContext: Handle returned by XXX_Open used to identify + * the open context of the device + * Returns: + * TRUE indicates the device is successfully closed. FALSE indicates + * otherwise. + * Requires: + * dwOpenContext!= NULL. + * Ensures:The Application instance owned objects are cleaned up. + */ +extern bool DSP_Close(u32 dwDeviceContext); + +/* + * ======== DSP_Deinit ======== + * Purpose: + * This function is called by Device Manager to de-initialize a device. + * This function is not called by applications. + * Parameters: + * dwDeviceContext:Handle to the device context. The XXX_Init function + * creates and returns this identifier. + * Returns: + * TRUE indicates the device successfully de-initialized. Otherwise it + * returns FALSE. + * Requires: + * dwDeviceContext!= NULL. For a built in device this should never + * get called. + * Ensures: + */ +extern bool DSP_Deinit(u32 dwDeviceContext); + +/* + * ======== DSP_Init ======== + * Purpose: + * This function is called by Device Manager to initialize a device. + * This function is not called by applications + * Parameters: + * dwContext: Specifies a pointer to a string containing the registry + * path to the active key for the stream interface driver. + * HKEY_LOCAL_MACHINE\Drivers\Active + * Returns: + * Returns a handle to the device context created. This is the our actual + * Device Object representing the DSP Device instance. + * Requires: + * Ensures: + * Succeeded: device context > 0 + * Failed: device Context = 0 + */ +extern u32 DSP_Init(OUT u32 *initStatus); + +#endif diff --git a/arch/arm/plat-omap/include/dspbridge/dynamic_loader.h b/arch/arm/plat-omap/include/dspbridge/dynamic_loader.h new file mode 100644 index 0000000..ea5f77f --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/dynamic_loader.h @@ -0,0 +1,505 @@ +/* + * dynamic_loader.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + + +#ifndef _DYNAMIC_LOADER_H_ +#define _DYNAMIC_LOADER_H_ +#include +#include + +/* + * Dynamic Loader + * + * The function of the dynamic loader is to load a "module" containing + * instructions for a "target" processor into that processor. In the process + * it assigns memory for the module, resolves symbol references made by the + * module, and remembers symbols defined by the module. + * + * The dynamic loader is parameterized for a particular system by 4 classes + * that supply the module and system specific functions it requires + */ + /* The read functions for the module image to be loaded */ + struct Dynamic_Loader_Stream; + + /* This class defines "host" symbol and support functions */ + struct Dynamic_Loader_Sym; + + /* This class defines the allocator for "target" memory */ + struct Dynamic_Loader_Allocate; + + /* This class defines the copy-into-target-memory functions */ + struct Dynamic_Loader_Initialize; + +/* + * Option flags to modify the behavior of module loading + */ +#define DLOAD_INITBSS 0x1 /* initialize BSS sections to zero */ +#define DLOAD_BIGEND 0x2 /* require big-endian load module */ +#define DLOAD_LITTLE 0x4 /* require little-endian load module */ + + typedef void *DLOAD_mhandle; /* module handle for loaded modules */ + +/***************************************************************************** + * Procedure Dynamic_Load_Module + * + * Parameters: + * module The input stream that supplies the module image + * syms Host-side symbol table and malloc/free functions + * alloc Target-side memory allocation + * init Target-side memory initialization, or NULL for symbol read only + * options Option flags DLOAD_* + * mhandle A module handle for use with Dynamic_Unload + * + * Effect: + * The module image is read using *module. Target storage for the new image is + * obtained from *alloc. Symbols defined and referenced by the module are + * managed using *syms. The image is then relocated and references resolved + * as necessary, and the resulting executable bits are placed into target memory + * using *init. + * + * Returns: + * On a successful load, a module handle is placed in *mhandle, and zero is + * returned. On error, the number of errors detected is returned. Individual + * errors are reported during the load process using syms->Error_Report(). + *****************************************************************************/ + extern int Dynamic_Load_Module( + /* the source for the module image*/ + struct Dynamic_Loader_Stream *module, + /* host support for symbols and storage*/ + struct Dynamic_Loader_Sym *syms, + /* the target memory allocator*/ + struct Dynamic_Loader_Allocate *alloc, + /* the target memory initializer*/ + struct Dynamic_Loader_Initialize *init, + unsigned options, /* option flags*/ + /* the returned module handle*/ + DLOAD_mhandle *mhandle + ); + +/***************************************************************************** + * Procedure Dynamic_Open_Module + * + * Parameters: + * module The input stream that supplies the module image + * syms Host-side symbol table and malloc/free functions + * alloc Target-side memory allocation + * init Target-side memory initialization, or NULL for symbol read only + * options Option flags DLOAD_* + * mhandle A module handle for use with Dynamic_Unload + * + * Effect: + * The module image is read using *module. Target storage for the new image is + * obtained from *alloc. Symbols defined and referenced by the module are + * managed using *syms. The image is then relocated and references resolved + * as necessary, and the resulting executable bits are placed into target memory + * using *init. + * + * Returns: + * On a successful load, a module handle is placed in *mhandle, and zero is + * returned. On error, the number of errors detected is returned. Individual + * errors are reported during the load process using syms->Error_Report(). + *****************************************************************************/ + extern int Dynamic_Open_Module( + /* the source for the module image */ + struct Dynamic_Loader_Stream *module, + /* host support for symbols and storage */ + struct Dynamic_Loader_Sym *syms, + /* the target memory allocator */ + struct Dynamic_Loader_Allocate *alloc, + /* the target memory initializer */ + struct Dynamic_Loader_Initialize *init, + unsigned options, /* option flags */ + /* the returned module handle */ + DLOAD_mhandle *mhandle + ); + +/***************************************************************************** + * Procedure Dynamic_Unload_Module + * + * Parameters: + * mhandle A module handle from Dynamic_Load_Module + * syms Host-side symbol table and malloc/free functions + * alloc Target-side memory allocation + * + * Effect: + * The module specified by mhandle is unloaded. Unloading causes all + * target memory to be deallocated, all symbols defined by the module to + * be purged, and any host-side storage used by the dynamic loader for + * this module to be released. + * + * Returns: + * Zero for success. On error, the number of errors detected is returned. + * Individual errors are reported using syms->Error_Report(). + *****************************************************************************/ + extern int Dynamic_Unload_Module(DLOAD_mhandle mhandle, /* the module + * handle*/ + /* host support for symbols and + * storage */ + struct Dynamic_Loader_Sym *syms, + /* the target memory allocator*/ + struct Dynamic_Loader_Allocate *alloc, + /* the target memory initializer*/ + struct Dynamic_Loader_Initialize *init + ); + +/***************************************************************************** + ***************************************************************************** + * A class used by the dynamic loader for input of the module image + ***************************************************************************** + *****************************************************************************/ + struct Dynamic_Loader_Stream { +/* public: */ + /************************************************************************* + * read_buffer + * + * PARAMETERS : + * buffer Pointer to the buffer to fill + * bufsiz Amount of data desired in sizeof() units + * + * EFFECT : + * Reads the specified amount of data from the module input stream + * into the specified buffer. Returns the amount of data read in sizeof() + * units (which if less than the specification, represents an error). + * + * NOTES: + * In release 1 increments the file position by the number of bytes read + * + *************************************************************************/ + int (*read_buffer) (struct Dynamic_Loader_Stream *thisptr, + void *buffer, unsigned bufsiz); + + /************************************************************************* + * set_file_posn (release 1 only) + * + * PARAMETERS : + * posn Desired file position relative to start of file in sizeof() units. + * + * EFFECT : + * Adjusts the internal state of the stream object so that the next + * read_buffer call will begin to read at the specified offset from + * the beginning of the input module. Returns 0 for success, non-zero + * for failure. + * + *************************************************************************/ + int (*set_file_posn) (struct Dynamic_Loader_Stream *thisptr, + /* to be eliminated in release 2*/ + unsigned int posn); + + }; + +/***************************************************************************** + ***************************************************************************** + * A class used by the dynamic loader for symbol table support and + * miscellaneous host-side functions + ***************************************************************************** + *****************************************************************************/ + + typedef u32 LDR_ADDR; + +/* + * the structure of a symbol known to the dynamic loader + */ + struct dynload_symbol { + LDR_ADDR value; + } ; + + struct Dynamic_Loader_Sym { +/* public: */ + /************************************************************************* + * Find_Matching_Symbol + * + * PARAMETERS : + * name The name of the desired symbol + * + * EFFECT : + * Locates a symbol matching the name specified. A pointer to the + * symbol is returned if it exists; 0 is returned if no such symbol is + * found. + * + *************************************************************************/ + struct dynload_symbol *(*Find_Matching_Symbol) + (struct Dynamic_Loader_Sym * + thisptr, + const char *name); + + /************************************************************************* + * Add_To_Symbol_Table + * + * PARAMETERS : + * nname Pointer to the name of the new symbol + * moduleid An opaque module id assigned by the dynamic loader + * + * EFFECT : + * The new symbol is added to the table. A pointer to the symbol is + * returned, or NULL is returned for failure. + * + * NOTES: + * It is permissible for this function to return NULL; the effect is that + * the named symbol will not be available to resolve references in + * subsequent loads. Returning NULL will not cause the current load + * to fail. + *************************************************************************/ + struct dynload_symbol *(*Add_To_Symbol_Table) + (struct Dynamic_Loader_Sym * + thisptr, + const char *nname, + unsigned moduleid); + + /************************************************************************* + * Purge_Symbol_Table + * + * PARAMETERS : + * moduleid An opaque module id assigned by the dynamic loader + * + * EFFECT : + * Each symbol in the symbol table whose moduleid matches the argument + * is removed from the table. + *************************************************************************/ + void (*Purge_Symbol_Table) (struct Dynamic_Loader_Sym *thisptr, + unsigned moduleid); + + /************************************************************************* + * Allocate + * + * PARAMETERS : + * memsiz size of desired memory in sizeof() units + * + * EFFECT : + * Returns a pointer to some "host" memory for use by the dynamic + * loader, or NULL for failure. + * This function is serves as a replaceable form of "malloc" to + * allow the user to configure the memory usage of the dynamic loader. + *************************************************************************/ + void *(*Allocate) (struct Dynamic_Loader_Sym *thisptr, + unsigned memsiz); + + /************************************************************************* + * Deallocate + * + * PARAMETERS : + * memptr pointer to previously allocated memory + * + * EFFECT : + * Releases the previously allocated "host" memory. + *************************************************************************/ + void (*Deallocate) (struct Dynamic_Loader_Sym *thisptr, + void *memptr); + + /************************************************************************* + * Error_Report + * + * PARAMETERS : + * errstr pointer to an error string + * args additional arguments + * + * EFFECT : + * This function provides an error reporting interface for the dynamic + * loader. The error string and arguments are designed as for the + * library function vprintf. + *************************************************************************/ + void (*Error_Report) (struct Dynamic_Loader_Sym *thisptr, + const char *errstr, va_list args); + + }; /* class Dynamic_Loader_Sym */ + +/***************************************************************************** + ***************************************************************************** + * A class used by the dynamic loader to allocate and deallocate target memory. + ***************************************************************************** + *****************************************************************************/ + + struct LDR_SECTION_INFO { + /* Name of the memory section assigned at build time */ + const char *name; + LDR_ADDR run_addr; /* execution address of the section */ + LDR_ADDR load_addr; /* load address of the section */ + LDR_ADDR size; /* size of the section in addressable units */ +#ifndef _BIG_ENDIAN + u16 page; /* memory page or view */ + u16 type; /* one of the section types below */ +#else + u16 type; /* one of the section types below */ + u16 page; /* memory page or view */ +#endif + /* a context field for use by Dynamic_Loader_Allocate; + * ignored but maintained by the dynamic loader */ + u32 context; + } ; + +/* use this macro to extract type of section from LDR_SECTION_INFO.type field */ +#define DLOAD_SECTION_TYPE(typeinfo) (typeinfo & 0xF) + +/* type of section to be allocated */ +#define DLOAD_TEXT 0 +#define DLOAD_DATA 1 +#define DLOAD_BSS 2 + /* internal use only, run-time cinit will be of type DLOAD_DATA */ +#define DLOAD_CINIT 3 + + struct Dynamic_Loader_Allocate { +/* public: */ + + /************************************************************************* + * Function allocate + * + * Parameters: + * info A pointer to an information block for the section + * align The alignment of the storage in target AUs + * + * Effect: + * Allocates target memory for the specified section and fills in the + * load_addr and run_addr fields of the section info structure. Returns TRUE + * for success, FALSE for failure. + * + * Notes: + * Frequently load_addr and run_addr are the same, but if they are not + * load_addr is used with Dynamic_Loader_Initialize, and run_addr is + * used for almost all relocations. This function should always initialize + * both fields. + *************************************************************************/ + int (*Allocate) (struct Dynamic_Loader_Allocate *thisptr, + struct LDR_SECTION_INFO *info, unsigned align); + + /************************************************************************* + * Function deallocate + * + * Parameters: + * info A pointer to an information block for the section + * + * Effect: + * Releases the target memory previously allocated. + * + * Notes: + * The content of the info->name field is undefined on call to this function. + *************************************************************************/ + void (*Deallocate) (struct Dynamic_Loader_Allocate *thisptr, + struct LDR_SECTION_INFO *info); + + }; /* class Dynamic_Loader_Allocate */ + +/***************************************************************************** + ***************************************************************************** + * A class used by the dynamic loader to load data into a target. This class + * provides the interface-specific functions needed to load data. + ***************************************************************************** + *****************************************************************************/ + + struct Dynamic_Loader_Initialize { +/* public: */ + /************************************************************************* + * Function connect + * + * Parameters: + * none + * + * Effect: + * Connect to the initialization interface. Returns TRUE for success, + * FALSE for failure. + * + * Notes: + * This function is called prior to use of any other functions in + * this interface. + *************************************************************************/ + int (*connect) (struct Dynamic_Loader_Initialize *thisptr); + + /************************************************************************* + * Function readmem + * + * Parameters: + * bufr Pointer to a word-aligned buffer for the result + * locn Target address of first data element + * info Section info for the section in which the address resides + * bytsiz Size of the data to be read in sizeof() units + * + * Effect: + * Fills the specified buffer with data from the target. Returns TRUE for + * success, FALSE for failure. + *************************************************************************/ + int (*readmem) (struct Dynamic_Loader_Initialize *thisptr, + void *bufr, + LDR_ADDR locn, + struct LDR_SECTION_INFO *info, + unsigned bytsiz); + + /************************************************************************* + * Function writemem + * + * Parameters: + * bufr Pointer to a word-aligned buffer of data + * locn Target address of first data element to be written + * info Section info for the section in which the address resides + * bytsiz Size of the data to be written in sizeof() units + * + * Effect: + * Writes the specified buffer to the target. Returns TRUE for success, + * FALSE for failure. + *************************************************************************/ + int (*writemem) (struct Dynamic_Loader_Initialize *thisptr, + void *bufr, + LDR_ADDR locn, + struct LDR_SECTION_INFO *info, + unsigned bytsiz); + + /************************************************************************* + * Function fillmem + * + * Parameters: + * locn Target address of first data element to be written + * info Section info for the section in which the address resides + * bytsiz Size of the data to be written in sizeof() units + * val Value to be written in each byte + * Effect: + * Fills the specified area of target memory. Returns TRUE for success, + * FALSE for failure. + *************************************************************************/ + int (*fillmem) (struct Dynamic_Loader_Initialize *thisptr, + LDR_ADDR locn, struct LDR_SECTION_INFO *info, + unsigned bytsiz, unsigned val); + + /************************************************************************* + * Function execute + * + * Parameters: + * start Starting address + * + * Effect: + * The target code at the specified starting address is executed. + * + * Notes: + * This function is called at the end of the dynamic load process + * if the input module has specified a starting address. + *************************************************************************/ + int (*execute) (struct Dynamic_Loader_Initialize *thisptr, + LDR_ADDR start); + + /************************************************************************* + * Function release + * + * Parameters: + * none + * + * Effect: + * Releases the connection to the load interface. + * + * Notes: + * This function is called at the end of the dynamic load process. + *************************************************************************/ + void (*release) (struct Dynamic_Loader_Initialize *thisptr); + + }; /* class Dynamic_Loader_Initialize */ + +#endif /* _DYNAMIC_LOADER_H_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/errbase.h b/arch/arm/plat-omap/include/dspbridge/errbase.h new file mode 100644 index 0000000..f04c005 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/errbase.h @@ -0,0 +1,509 @@ +/* + * errbase.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== errbase.h ======== + * Description: + * Central repository for DSP/BIOS Bridge error and status code. + * + * Error codes are of the form: + * []_E + * + * Success codes are of the form: + * []_S + * + *! Revision History: + *! ================ + *! 24-Jan-2003 map Added DSP_SALREADYLOADED for persistent library checking + *! 23-Nov-2002 gp: Minor comment cleanup. + *! 13-May-2002 sg Added DSP_SALREADYASLEEP and DSP_SALREADYWAKE. + *! 18-Feb-2002 mk: Added DSP_EOVERLAYMEMORY, EFWRITE, ENOSECT. + *! 31-Jan-2002 mk: Added definitions of DSP_STRUE and DSP_SFALSE. + *! 29-Jan-2002 mk: Added definition of CFG_E_INSUFFICIENTBUFSIZE. + *! 24-Oct-2001 sp: Consolidated all the error codes into this file. + *! 24-Jul-2001 mk: Type-casted all definitions of WSX_STATUS types for + *! removal of compile warnings. + *! 22-Nov-1999 kc: Changes from code review. + *! 18-Aug-1999 rr: Ported From WSX. + *! 29-May-1996 gp: Removed WCD_ and WMD_ error ranges. Redefined format of + *! error codes. + *! 10-May-1996 gp: Created. + */ + +#ifndef ERRBASE_ +#define ERRBASE_ + +/* Base of generic errors and component errors */ +#define DSP_SBASE (DSP_STATUS)0x00008000 +#define DSP_EBASE (DSP_STATUS)0x80008000 + +#define DSP_COMP_EBASE (DSP_STATUS)0x80040200 +#define DSP_COMP_ELAST (DSP_STATUS)0x80047fff + +/* SUCCESS Codes */ + +/* Generic success code */ +#define DSP_SOK (DSP_SBASE + 0) + +/* GPP is already attached to this DSP processor */ +#define DSP_SALREADYATTACHED (DSP_SBASE + 1) + +/* This is the last object available for enumeration. */ +#define DSP_SENUMCOMPLETE (DSP_SBASE + 2) + +/* The DSP is already asleep. */ +#define DSP_SALREADYASLEEP (DSP_SBASE + 3) + +/* The DSP is already awake. */ +#define DSP_SALREADYAWAKE (DSP_SBASE + 4) + +/* TRUE */ +#define DSP_STRUE (DSP_SBASE + 5) + +/* FALSE */ +#define DSP_SFALSE (DSP_SBASE + 6) + +/* A library contains no dependent library references */ +#define DSP_SNODEPENDENTLIBS (DSP_SBASE + 7) + +/* A persistent library is already loaded by the dynamic loader */ +#define DSP_SALREADYLOADED (DSP_SBASE + 8) + +/* Some error occured, but it is OK to continue */ +#define DSP_OKTO_CONTINUE (DSP_SBASE + 9) + +/* FAILURE Codes */ + +/* The caller does not have access privileges to call this function */ +#define DSP_EACCESSDENIED (DSP_EBASE + 0) + +/* The Specified Connection already exists */ +#define DSP_EALREADYCONNECTED (DSP_EBASE + 1) + +/* The GPP must be detached from the DSP before this function is called */ +#define DSP_EATTACHED (DSP_EBASE + 2) + +/* During enumeration a change in the number or properties of the objects + * has occurred. */ +#define DSP_ECHANGEDURINGENUM (DSP_EBASE + 3) + +/* An error occurred while parsing the DSP executable file */ +#define DSP_ECORRUPTFILE (DSP_EBASE + 4) + +/* A failure occurred during a delete operation */ +#define DSP_EDELETE (DSP_EBASE + 5) + +/* The specified direction is invalid */ +#define DSP_EDIRECTION (DSP_EBASE + 6) + +/* A stream has been issued the maximum number of buffers allowed in the + * stream at once ; buffers must be reclaimed from the stream before any + * more can be issued. */ +#define DSP_ESTREAMFULL (DSP_EBASE + 7) + +/* A general failure occurred */ +#define DSP_EFAIL (DSP_EBASE + 8) + +/* The specified executable file could not be found. */ +#define DSP_EFILE (DSP_EBASE + 9) + +/* The specified handle is invalid. */ +#define DSP_EHANDLE (DSP_EBASE + 0xa) + +/* An invalid argument was specified. */ +#define DSP_EINVALIDARG (DSP_EBASE + 0xb) + +/* A memory allocation failure occurred. */ +#define DSP_EMEMORY (DSP_EBASE + 0xc) + +/* The requested operation is invalid for this node type. */ +#define DSP_ENODETYPE (DSP_EBASE + 0xd) + +/* No error text was found for the specified error code. */ +#define DSP_ENOERRTEXT (DSP_EBASE + 0xe) + +/* No more connections can be made for this node. */ +#define DSP_ENOMORECONNECTIONS (DSP_EBASE + 0xf) + +/* The indicated operation is not supported. */ +#define DSP_ENOTIMPL (DSP_EBASE + 0x10) + +/* I/O is currently pending. */ +#define DSP_EPENDING (DSP_EBASE + 0x11) + +/* An invalid pointer was specified. */ +#define DSP_EPOINTER (DSP_EBASE + 0x12) + +/* A parameter is specified outside its valid range. */ +#define DSP_ERANGE (DSP_EBASE + 0x13) + +/* An invalid size parameter was specified. */ +#define DSP_ESIZE (DSP_EBASE + 0x14) + +/* A stream creation failure occurred on the DSP. */ +#define DSP_ESTREAM (DSP_EBASE + 0x15) + +/* A task creation failure occurred on the DSP. */ +#define DSP_ETASK (DSP_EBASE + 0x16) + +/* A timeout occurred before the requested operation could complete. */ + +#define DSP_ETIMEOUT (DSP_EBASE + 0x17) + +/* A data truncation occurred, e.g., when requesting a descriptive error + * string, not enough space was allocated for the complete error message. */ + +#define DSP_ETRUNCATED (DSP_EBASE + 0x18) + +/* A parameter is invalid. */ +#define DSP_EVALUE (DSP_EBASE + 0x1a) + +/* The state of the specified object is incorrect for the requested + * operation. */ +#define DSP_EWRONGSTATE (DSP_EBASE + 0x1b) + +/* Symbol not found in the COFF file. DSPNode_Create will return this if + * the iAlg function table for an xDAIS socket is not found in the COFF file. + * In this case, force the symbol to be linked into the COFF file. + * DSPNode_Create, DSPNode_Execute, and DSPNode_Delete will return this if + * the create, execute, or delete phase function, respectively, could not be + * found in the COFF file. */ +#define DSP_ESYMBOL (DSP_EBASE + 0x1c) + +/* UUID not found in registry. */ +#define DSP_EUUID (DSP_EBASE + 0x1d) + +/* Unable to read content of DCD data section ; this is typically caused by + * improperly configured nodes. */ +#define DSP_EDCDREADSECT (DSP_EBASE + 0x1e) + +/* Unable to decode DCD data section content ; this is typically caused by + * changes to DSP/BIOS Bridge data structures. */ +#define DSP_EDCDPARSESECT (DSP_EBASE + 0x1f) + +/* Unable to get pointer to DCD data section ; this is typically caused by + * improperly configured UUIDs. */ +#define DSP_EDCDGETSECT (DSP_EBASE + 0x20) + +/* Unable to load file containing DCD data section ; this is typically + * caused by a missing COFF file. */ +#define DSP_EDCDLOADBASE (DSP_EBASE + 0x21) + +/* The specified COFF file does not contain a valid node registration + * section. */ +#define DSP_EDCDNOAUTOREGISTER (DSP_EBASE + 0x22) + +/* A requested resource is not available. */ +#define DSP_ERESOURCE (DSP_EBASE + 0x28) + +/* A critical error has occurred, and the DSP is being re-started. */ +#define DSP_ERESTART (DSP_EBASE + 0x29) + +/* A DSP memory free operation failed. */ +#define DSP_EFREE (DSP_EBASE + 0x2a) + +/* A DSP I/O free operation failed. */ +#define DSP_EIOFREE (DSP_EBASE + 0x2b) + +/* Multiple instances are not allowed. */ +#define DSP_EMULINST (DSP_EBASE + 0x2c) + +/* A specified entity was not found. */ +#define DSP_ENOTFOUND (DSP_EBASE + 0x2d) + +/* A DSP I/O resource is not available. */ +#define DSP_EOUTOFIO (DSP_EBASE + 0x2e) + +/* A shared memory buffer contained in a message or stream could not be + * mapped to the GPP client process's virtual space. */ +#define DSP_ETRANSLATE (DSP_EBASE + 0x2f) + +/* File or section load write function failed to write to DSP */ +#define DSP_EFWRITE (DSP_EBASE + 0x31) + +/* Unable to find a named section in DSP executable */ +#define DSP_ENOSECT (DSP_EBASE + 0x32) + +/* Unable to open file */ +#define DSP_EFOPEN (DSP_EBASE + 0x33) + +/* Unable to read file */ +#define DSP_EFREAD (DSP_EBASE + 0x34) + +/* A non-existent memory segment identifier was specified */ +#define DSP_EOVERLAYMEMORY (DSP_EBASE + 0x37) + +/* Invalid segment ID */ +#define DSP_EBADSEGID (DSP_EBASE + 0x38) + +/* Invalid alignment */ +#define DSP_EALIGNMENT (DSP_EBASE + 0x39) + +/* Invalid stream mode */ +#define DSP_ESTRMMODE (DSP_EBASE + 0x3a) + +/* Nodes not connected */ +#define DSP_ENOTCONNECTED (DSP_EBASE + 0x3b) + +/* Not shared memory */ +#define DSP_ENOTSHAREDMEM (DSP_EBASE + 0x3c) + +/* Error occurred in a dynamic loader library function */ +#define DSP_EDYNLOAD (DSP_EBASE + 0x3d) + +/* Device in 'sleep/suspend' mode due to DPM */ +#define DSP_EDPMSUSPEND (DSP_EBASE + 0x3e) + +/* A node-specific error has occurred. */ +#define DSP_EUSER1 (DSP_EBASE + 0x40) +#define DSP_EUSER2 (DSP_EBASE + 0x41) +#define DSP_EUSER3 (DSP_EBASE + 0x42) +#define DSP_EUSER4 (DSP_EBASE + 0x43) +#define DSP_EUSER5 (DSP_EBASE + 0x44) +#define DSP_EUSER6 (DSP_EBASE + 0x45) +#define DSP_EUSER7 (DSP_EBASE + 0x46) +#define DSP_EUSER8 (DSP_EBASE + 0x47) +#define DSP_EUSER9 (DSP_EBASE + 0x48) +#define DSP_EUSER10 (DSP_EBASE + 0x49) +#define DSP_EUSER11 (DSP_EBASE + 0x4a) +#define DSP_EUSER12 (DSP_EBASE + 0x4b) +#define DSP_EUSER13 (DSP_EBASE + 0x4c) +#define DSP_EUSER14 (DSP_EBASE + 0x4d) +#define DSP_EUSER15 (DSP_EBASE + 0x4e) +#define DSP_EUSER16 (DSP_EBASE + 0x4f) + +/* FAILURE Codes : DEV */ +#define DEV_EBASE (DSP_COMP_EBASE + 0x000) + +/* The mini-driver expected a newer version of the class driver. */ +#define DEV_E_NEWWMD (DEV_EBASE + 0x00) + +/* WMD_DRV_Entry function returned a NULL function interface table. */ +#define DEV_E_NULLWMDINTF (DEV_EBASE + 0x01) + +/* FAILURE Codes : LDR */ +#define LDR_EBASE (DSP_COMP_EBASE + 0x100) + +/* Insufficient memory to export class driver services. */ +#define LDR_E_NOMEMORY (LDR_EBASE + 0x00) + +/* Unable to find WMD file in system directory. */ +#define LDR_E_FILEUNABLETOOPEN (LDR_EBASE + 0x01) + +/* FAILURE Codes : CFG */ +#define CFG_EBASE (DSP_COMP_EBASE + 0x200) + +/* Invalid pointer passed into a configuration module function */ +#define CFG_E_INVALIDPOINTER (CFG_EBASE + 0x00) + +/* Invalid device node handle passed into a configuration module function. */ +#define CFG_E_INVALIDHDEVNODE (CFG_EBASE + 0x01) + +/* Unable to retrieve resource information from the registry. */ +#define CFG_E_RESOURCENOTAVAIL (CFG_EBASE + 0x02) + +/* Unable to find board name key in registry. */ +#define CFG_E_INVALIDBOARDNAME (CFG_EBASE + 0x03) + +/* Unable to find a device node in registry with given unit number. */ +#define CFG_E_INVALIDUNITNUM (CFG_EBASE + 0x04) + +/* Insufficient buffer size */ +#define CFG_E_INSUFFICIENTBUFSIZE (CFG_EBASE + 0x05) + +/* FAILURE Codes : BRD */ +#define BRD_EBASE (DSP_COMP_EBASE + 0x300) + +/* Board client does not have sufficient access rights for this operation. */ +#define BRD_E_ACCESSDENIED (BRD_EBASE + 0x00) + +/* Unable to find trace buffer symbols in the DSP executable COFF file. */ +#define BRD_E_NOTRACEBUFFER (BRD_EBASE + 0x01) + +/* Attempted to auto-start board, but no default DSP executable configured. */ +#define BRD_E_NOEXEC (BRD_EBASE + 0x02) + +/* The operation failed because it was started from a wrong state */ +#define BRD_E_WRONGSTATE (BRD_EBASE + 0x03) + +/* FAILURE Codes : COD */ +#define COD_EBASE (DSP_COMP_EBASE + 0x400) + +/* No symbol table is loaded for this board. */ +#define COD_E_NOSYMBOLSLOADED (COD_EBASE + 0x00) + +/* Symbol not found in for this board. */ +#define COD_E_SYMBOLNOTFOUND (COD_EBASE + 0x01) + +/* ZL DLL module is not exporting the correct function interface. */ +#define COD_E_NOZLFUNCTIONS (COD_EBASE + 0x02) + +/* Unable to initialize the ZL COFF parsing module. */ +#define COD_E_ZLCREATEFAILED (COD_EBASE + 0x03) + +/* Unable to open DSP executable COFF file. */ +#define COD_E_OPENFAILED (COD_EBASE + 0x04) + +/* Unable to parse DSP executable COFF file. */ +#define COD_E_LOADFAILED (COD_EBASE + 0x05) + +/* Unable to read DSP executable COFF file. */ +#define COD_E_READFAILED (COD_EBASE + 0x06) + +/* FAILURE Codes : CHNL */ +#define CHNL_EBASE (DSP_COMP_EBASE + 0x500) + +/* Attempt to created channel manager with too many channels. */ +#define CHNL_E_MAXCHANNELS (CHNL_EBASE + 0x00) + +/* No channel manager exists for this mini-driver. */ +#define CHNL_E_NOMGR (CHNL_EBASE + 0x01) + +/* No free channels are available. */ +#define CHNL_E_OUTOFSTREAMS (CHNL_EBASE + 0x02) + +/* Channel ID is out of range. */ +#define CHNL_E_BADCHANID (CHNL_EBASE + 0x03) + +/* Channel is already in use. */ +#define CHNL_E_CHANBUSY (CHNL_EBASE + 0x04) + +/* Invalid channel mode argument. */ +#define CHNL_E_BADMODE (CHNL_EBASE + 0x05) + +/* dwTimeOut parameter was CHNL_IOCNOWAIT, yet no I/O completions were + * queued. */ +#define CHNL_E_NOIOC (CHNL_EBASE + 0x06) + +/* I/O has been cancelled on this channel. */ +#define CHNL_E_CANCELLED (CHNL_EBASE + 0x07) + +/* End of stream was already requested on this output channel. */ +#define CHNL_E_EOS (CHNL_EBASE + 0x09) + +/* Unable to create the channel event object. */ +#define CHNL_E_CREATEEVENT (CHNL_EBASE + 0x0A) + +/* Board name and unit number do not identify a valid board name. */ +#define CHNL_E_BRDID (CHNL_EBASE + 0x0B) + +/* Invalid IRQ configured for this WMD for this system. */ +#define CHNL_E_INVALIDIRQ (CHNL_EBASE + 0x0C) + +/* DSP word size of zero configured for this device. */ +#define CHNL_E_INVALIDWORDSIZE (CHNL_EBASE + 0x0D) + +/* A zero length memory base was specified for a shared memory class driver. */ +#define CHNL_E_INVALIDMEMBASE (CHNL_EBASE + 0x0E) + +/* Memory map is not configured, or unable to map physical to linear + * address. */ +#define CHNL_E_NOMEMMAP (CHNL_EBASE + 0x0F) + +/* Attempted to create a channel manager when one already exists. */ +#define CHNL_E_MGREXISTS (CHNL_EBASE + 0x10) + +/* Unable to plug channel ISR for configured IRQ. */ +#define CHNL_E_ISR (CHNL_EBASE + 0x11) + +/* No free I/O request packets are available. */ +#define CHNL_E_NOIORPS (CHNL_EBASE + 0x12) + +/* Buffer size is larger than the size of physical channel. */ +#define CHNL_E_BUFSIZE (CHNL_EBASE + 0x13) + +/* User cannot mark end of stream on an input channel. */ +#define CHNL_E_NOEOS (CHNL_EBASE + 0x14) + +/* Wait for flush operation on an output channel timed out. */ +#define CHNL_E_WAITTIMEOUT (CHNL_EBASE + 0x15) + +/* User supplied hEvent must be specified with pstrEventName attribute */ +#define CHNL_E_BADUSEREVENT (CHNL_EBASE + 0x16) + +/* Illegal user event name specified */ +#define CHNL_E_USEREVENTNAME (CHNL_EBASE + 0x17) + +/* Unable to prepare buffer specified */ +#define CHNL_E_PREPFAILED (CHNL_EBASE + 0x18) + +/* Unable to Unprepare buffer specified */ +#define CHNL_E_UNPREPFAILED (CHNL_EBASE + 0x19) + +/* FAILURE Codes : SYNC */ +#define SYNC_EBASE (DSP_COMP_EBASE + 0x600) + +/* Wait on a kernel event failed. */ +#define SYNC_E_FAIL (SYNC_EBASE + 0x00) + +/* Timeout expired while waiting for event to be signalled. */ +#define SYNC_E_TIMEOUT (SYNC_EBASE + 0x01) + +/* FAILURE Codes : WMD */ +#define WMD_EBASE (DSP_COMP_EBASE + 0x700) + +/* A test of hardware assumptions or integrity failed. */ +#define WMD_E_HARDWARE (WMD_EBASE + 0x00) + +/* One or more configuration parameters violated WMD hardware assumptions. */ +#define WMD_E_BADCONFIG (WMD_EBASE + 0x01) + +/* Timeout occurred waiting for a response from the hardware. */ +#define WMD_E_TIMEOUT (WMD_EBASE + 0x02) + +/* FAILURE Codes : REG */ +#define REG_EBASE (DSP_COMP_EBASE + 0x800) + +/* Invalid subkey parameter. */ +#define REG_E_INVALIDSUBKEY (REG_EBASE + 0x00) + +/* Invalid entry parameter. */ +#define REG_E_INVALIDENTRY (REG_EBASE + 0x01) + +/* No more registry values. */ +#define REG_E_NOMOREITEMS (REG_EBASE + 0x02) + +/* Insufficient space to hold data in registry value. */ +#define REG_E_MOREDATA (REG_EBASE + 0x03) + +/* FAILURE Codes : KFILE */ +#define KFILE_EBASE (DSP_COMP_EBASE + 0x900) + +/* Invalid file handle. */ +#define E_KFILE_INVALIDHANDLE (KFILE_EBASE + 0x01) + +/* Bad file name. */ +#define E_KFILE_BADFILENAME (KFILE_EBASE + 0x02) + +/* Invalid file mode. */ +#define E_KFILE_INVALIDMODE (KFILE_EBASE + 0x03) + +/* No resources available. */ +#define E_KFILE_NORESOURCES (KFILE_EBASE + 0x04) + +/* Invalid file buffer . */ +#define E_KFILE_INVALIDBUFFER (KFILE_EBASE + 0x05) + +/* Bad origin argument. */ +#define E_KFILE_BADORIGINFLAG (KFILE_EBASE + 0x06) + +/* Invalid file offset value. */ +#define E_KFILE_INVALIDOFFSET (KFILE_EBASE + 0x07) + +/* General KFILE error condition */ +#define E_KFILE_ERROR (KFILE_EBASE + 0x08) + +#endif /* ERRBASE_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/gb.h b/arch/arm/plat-omap/include/dspbridge/gb.h new file mode 100644 index 0000000..f147751 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/gb.h @@ -0,0 +1,85 @@ +/* + * gb.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== gb.h ======== + * Generic bitmap manager. + * + *! Revision History + *! ================ + */ + +#ifndef GB_ +#define GB_ + +#define GB_NOBITS (~0) +#include +typedef s32 GB_BitNum; +struct GB_TMap; + +/* + * ======== GB_clear ======== + * Clear the bit in position bitn in the bitmap map. Bit positions are + * zero based. + */ + +extern void GB_clear(struct GB_TMap *map, GB_BitNum bitn); + +/* + * ======== GB_create ======== + * Create a bit map with len bits. Initially all bits are cleared. + */ + +extern struct GB_TMap *GB_create(GB_BitNum len); + +/* + * ======== GB_delete ======== + * Delete previously created bit map + */ + +extern void GB_delete(struct GB_TMap *map); + +/* + * ======== GB_findandset ======== + * Finds a clear bit, sets it, and returns the position + */ + +extern GB_BitNum GB_findandset(struct GB_TMap *map); + +/* + * ======== GB_minclear ======== + * GB_minclear returns the minimum clear bit position. If no bit is + * clear, GB_minclear returns -1. + */ +extern GB_BitNum GB_minclear(struct GB_TMap *map); + +/* + * ======== GB_set ======== + * Set the bit in position bitn in the bitmap map. Bit positions are + * zero based. + */ + +extern void GB_set(struct GB_TMap *map, GB_BitNum bitn); + +/* + * ======== GB_test ======== + * Returns TRUE if the bit in position bitn is set in map; otherwise + * GB_test returns FALSE. Bit positions are zero based. + */ + +extern bool GB_test(struct GB_TMap *map, GB_BitNum bitn); + +#endif /*GB_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/getsection.h b/arch/arm/plat-omap/include/dspbridge/getsection.h new file mode 100644 index 0000000..33ff50d --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/getsection.h @@ -0,0 +1,118 @@ +/* + * getsection.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +#ifndef _GETSECTION_H_ +#define _GETSECTION_H_ + + +#include "dynamic_loader.h" + +/* + * Get Section Information + * + * This file provides an API add-on to the dynamic loader that allows the user + * to query section information and extract section data from dynamic load + * modules. + * + * NOTE: + * Functions in this API assume that the supplied Dynamic_Loader_Stream object + * supports the set_file_posn method. + */ + + /* opaque handle for module information */ + typedef void *DLOAD_module_info; + +/* + * Procedure DLOAD_module_open + * + * Parameters: + * module The input stream that supplies the module image + * syms Host-side malloc/free and error reporting functions. + * Other methods are unused. + * + * Effect: + * Reads header information from a dynamic loader module using the specified + * stream object, and returns a handle for the module information. This + * handle may be used in subsequent query calls to obtain information + * contained in the module. + * + * Returns: + * NULL if an error is encountered, otherwise a module handle for use + * in subsequent operations. + */ + extern DLOAD_module_info DLOAD_module_open(struct Dynamic_Loader_Stream + *module, + struct Dynamic_Loader_Sym + *syms); + +/* + * Procedure DLOAD_GetSectionInfo + * + * Parameters: + * minfo Handle from DLOAD_module_open for this module + * sectionName Pointer to the string name of the section desired + * sectionInfo Address of a section info structure pointer to be initialized + * + * Effect: + * Finds the specified section in the module information, and fills in + * the provided LDR_SECTION_INFO structure. + * + * Returns: + * TRUE for success, FALSE for section not found + */ + extern int DLOAD_GetSectionInfo(DLOAD_module_info minfo, + const char *sectionName, + const struct LDR_SECTION_INFO + ** const sectionInfo); + +/* + * Procedure DLOAD_GetSection + * + * Parameters: + * minfo Handle from DLOAD_module_open for this module + * sectionInfo Pointer to a section info structure for the desired section + * sectionData Buffer to contain the section initialized data + * + * Effect: + * Copies the initialized data for the specified section into the + * supplied buffer. + * + * Returns: + * TRUE for success, FALSE for section not found + */ + extern int DLOAD_GetSection(DLOAD_module_info minfo, + const struct LDR_SECTION_INFO *sectionInfo, + void *sectionData); + +/* + * Procedure DLOAD_module_close + * + * Parameters: + * minfo Handle from DLOAD_module_open for this module + * + * Effect: + * Releases any storage associated with the module handle. On return, + * the module handle is invalid. + * + * Returns: + * Zero for success. On error, the number of errors detected is returned. + * Individual errors are reported using syms->Error_Report(), where syms was + * an argument to DLOAD_module_open + */ + extern void DLOAD_module_close(DLOAD_module_info minfo); + +#endif /* _GETSECTION_H_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/gh.h b/arch/arm/plat-omap/include/dspbridge/gh.h new file mode 100644 index 0000000..089a042 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/gh.h @@ -0,0 +1,37 @@ +/* + * gh.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== gh.h ======== + * + *! Revision History + *! ================ + */ + +#ifndef GH_ +#define GH_ +#include + +extern struct GH_THashTab *GH_create(u16 maxBucket, u16 valSize, + u16(*hash) (void *, u16), bool(*match) (void *, void *), + void(*delete) (void *)); +extern void GH_delete(struct GH_THashTab *hashTab); +extern void GH_exit(void); +extern void *GH_find(struct GH_THashTab *hashTab, void *key); +extern void GH_init(void); +extern void *GH_insert(struct GH_THashTab *hashTab, void *key, void *value); +#endif /* GH_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/gs.h b/arch/arm/plat-omap/include/dspbridge/gs.h new file mode 100644 index 0000000..fd5ef27 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/gs.h @@ -0,0 +1,64 @@ +/* + * gs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== gs.h ======== + * Memory allocation/release wrappers. This module allows clients to + * avoid OS spacific issues related to memory allocation. It also provides + * simple diagnostic capabilities to assist in the detection of memory + * leaks. + *! Revision History + *! ================ + */ + +#ifndef GS_ +#define GS_ + +/* + * ======== GS_alloc ======== + * Alloc size bytes of space. Returns pointer to space + * allocated, otherwise NULL. + */ +extern void *GS_alloc(u32 size); + +/* + * ======== GS_exit ======== + * Module exit. Do not change to "#define GS_init()"; in + * some environments this operation must actually do some work! + */ +extern void GS_exit(void); + +/* + * ======== GS_free ======== + * Free space allocated by GS_alloc() or GS_calloc(). + */ +extern void GS_free(void *ptr); + +/* + * ======== GS_frees ======== + * Free space allocated by GS_alloc() or GS_calloc() and assert that + * the size of the allocation is size bytes. + */ +extern void GS_frees(void *ptr, u32 size); + +/* + * ======== GS_init ======== + * Module initialization. Do not change to "#define GS_init()"; in + * some environments this operation must actually do some work! + */ +extern void GS_init(void); + +#endif /*GS_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/gt.h b/arch/arm/plat-omap/include/dspbridge/gt.h new file mode 100644 index 0000000..456c866 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/gt.h @@ -0,0 +1,315 @@ +/* + * gt.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== gt.h ======== + * Purpose: + * There are two definitions that affect which portions of trace + * are acutally compiled into the client: GT_TRACE and GT_ASSERT. If + * GT_TRACE is set to 0 then all trace statements (except for assertions) + * will be compiled out of the client. If GT_ASSERT is set to 0 then + * assertions will be compiled out of the client. GT_ASSERT can not be + * set to 0 unless GT_TRACE is also set to 0 (i.e. GT_TRACE == 1 implies + * GT_ASSERT == 1). + * + *! Revision History + *! ================ + *! 02-Feb-2000 rr: Renamed this file to gtce.h. GT CLASS and trace definitions + *! are WinCE Specific. + *! 03-Jan-1997 ge Replaced "GT_" prefix to GT_Config structure members + *! to eliminate preprocessor confusion with other macros. + */ +#include +#ifndef GT_ +#define GT_ + +#ifndef GT_TRACE +#define GT_TRACE 0 /* 0 = "trace compiled out"; 1 = "trace active" */ +#endif + +#include + +#if !defined(GT_ASSERT) || GT_TRACE +#define GT_ASSERT 1 +#endif + +struct GT_Config { + Fxn PRINTFXN; + Fxn PIDFXN; + Fxn TIDFXN; + Fxn ERRORFXN; +}; + +extern struct GT_Config *GT; + +struct GT_Mask { + char *modName; + u8 *flags; +} ; + +/* + * New GT Class defenitions. + * + * The following are the explanations and how it could be used in the code + * + * - GT_ENTER On Entry to Functions + * + * - GT_1CLASS Display level of debugging status- Object/Automatic + * variables + * - GT_2CLASS ---- do ---- + * + * - GT_3CLASS ---- do ---- + It can be used(recommended) for debug + * status in the ISR, IST + * - GT_4CLASS ---- do ---- + * + * - GT_5CLASS Display entry for module init/exit functions + * + * - GT_6CLASS Warn whenever SERVICES function fails + * + * - GT_7CLASS Warn failure of Critical failures + * + */ + +#define GT_ENTER ((u8)0x01) +#define GT_1CLASS ((u8)0x02) +#define GT_2CLASS ((u8)0x04) +#define GT_3CLASS ((u8)0x08) +#define GT_4CLASS ((u8)0x10) +#define GT_5CLASS ((u8)0x20) +#define GT_6CLASS ((u8)0x40) +#define GT_7CLASS ((u8)0x80) + +#ifdef _LINT_ + +/* LINTLIBRARY */ + +/* + * ======== GT_assert ======== + */ +/* ARGSUSED */ +void GT_assert(struct GT_Mask mask, s32 expr) +{ +} + +/* + * ======== GT_config ======== + */ +/* ARGSUSED */ +void GT_config(struct GT_Config config) +{ +} + +/* + * ======== GT_create ======== + */ +/* ARGSUSED */ +void GT_create(struct GT_Mask *mask, char *modName) +{ +} + +/* + * ======== GT_curLine ======== + * Purpose: + * Returns the current source code line number. Is useful for performing + * branch testing using trace. For example, + * + * GT_1trace(curTrace, GT_1CLASS, + * "in module XX_mod, executing line %u\n", GT_curLine()); + */ +/* ARGSUSED */ +u16 GT_curLine(void) +{ + return (u16)NULL; +} + +/* + * ======== GT_exit ======== + */ +/* ARGSUSED */ +void GT_exit(void) +{ +} + +/* + * ======== GT_init ======== + */ +/* ARGSUSED */ +void GT_init(void) +{ +} + +/* + * ======== GT_query ======== + */ +/* ARGSUSED */ +bool GT_query(struct GT_Mask mask, u8 class) +{ + return false; +} + +/* + * ======== GT_set ======== + * sets trace mask according to settings + */ + +/* ARGSUSED */ +void GT_set(char *settings) +{ +} + +/* + * ======== GT_setprintf ======== + * sets printf function + */ + +/* ARGSUSED */ +void GT_setprintf(Fxn fxn) +{ +} + +/* ARGSUSED */ +void GT_0trace(struct GT_Mask mask, u8 class, char *format) +{ +} + +/* ARGSUSED */ +void GT_1trace(struct GT_Mask mask, u8 class, char *format, ...) +{ +} + +/* ARGSUSED */ +void GT_2trace(struct GT_Mask mask, u8 class, char *format, ...) +{ +} + +/* ARGSUSED */ +void GT_3trace(struct GT_Mask mask, u8 class, char *format, ...) +{ +} + +/* ARGSUSED */ +void GT_4trace(struct GT_Mask mask, u8 class, char *format, ...) +{ +} + +/* ARGSUSED */ +void GT_5trace(struct GT_Mask mask, u8 class, char *format, ...) +{ +} + +/* ARGSUSED */ +void GT_6trace(struct GT_Mask mask, u8 class, char *format, ...) +{ +} + +#else + +#define GT_BOUND 26 /* 26 letters in alphabet */ + +extern void _GT_create(struct GT_Mask *mask, char *modName); + +#define GT_exit() + +extern void GT_init(void); +extern void _GT_set(char *str); +extern s32 _GT_trace(struct GT_Mask *mask, char *format, ...); + +#if GT_ASSERT == 0 + +#define GT_assert(mask, expr) +#define GT_config(config) +#define GT_configInit(config) +#define GT_seterror(fxn) + +#else + +extern struct GT_Config _GT_params; + +#define GT_assert(mask, expr) \ + (!(expr) ? \ + printk("assertion violation: %s, line %d\n", \ + __FILE__, __LINE__), NULL : NULL) + +#define GT_config(config) (_GT_params = *(config)) +#define GT_configInit(config) (*(config) = _GT_params) +#define GT_seterror(fxn) (_GT_params.ERRORFXN = (Fxn)(fxn)) + +#endif + +#if GT_TRACE == 0 + +#define GT_curLine() ((u16)__LINE__) +#define GT_create(mask, modName) +#define GT_exit() +#define GT_init() +#define GT_set(settings) +#define GT_setprintf(fxn) + +#define GT_query(mask, class) false + +#define GT_0trace(mask, class, format) +#define GT_1trace(mask, class, format, arg1) +#define GT_2trace(mask, class, format, arg1, arg2) +#define GT_3trace(mask, class, format, arg1, arg2, arg3) +#define GT_4trace(mask, class, format, arg1, arg2, arg3, arg4) +#define GT_5trace(mask, class, format, arg1, arg2, arg3, arg4, arg5) +#define GT_6trace(mask, class, format, arg1, arg2, arg3, arg4, arg5, arg6) + +#else /* GT_TRACE == 1 */ + + +#define GT_create(mask, modName) _GT_create((mask), (modName)) +#define GT_curLine() ((u16)__LINE__) +#define GT_set(settings) _GT_set(settings) +#define GT_setprintf(fxn) (_GT_params.PRINTFXN = (Fxn)(fxn)) + +#define GT_query(mask, class) ((*(mask).flags & (class))) + +#define GT_0trace(mask, class, format) \ + ((*(mask).flags & (class)) ? \ + _GT_trace(&(mask), (format)) : 0) + +#define GT_1trace(mask, class, format, arg1) \ + ((*(mask).flags & (class)) ? \ + _GT_trace(&(mask), (format), (arg1)) : 0) + +#define GT_2trace(mask, class, format, arg1, arg2) \ + ((*(mask).flags & (class)) ? \ + _GT_trace(&(mask), (format), (arg1), (arg2)) : 0) + +#define GT_3trace(mask, class, format, arg1, arg2, arg3) \ + ((*(mask).flags & (class)) ? \ + _GT_trace(&(mask), (format), (arg1), (arg2), (arg3)) : 0) + +#define GT_4trace(mask, class, format, arg1, arg2, arg3, arg4) \ + ((*(mask).flags & (class)) ? \ + _GT_trace(&(mask), (format), (arg1), (arg2), (arg3), (arg4)) : 0) + +#define GT_5trace(mask, class, format, arg1, arg2, arg3, arg4, arg5) \ + ((*(mask).flags & (class)) ? \ + _GT_trace(&(mask), (format), (arg1), (arg2), (arg3), (arg4), (arg5)) : 0) + +#define GT_6trace(mask, class, format, arg1, arg2, arg3, arg4, arg5, arg6) \ + ((*(mask).flags & (class)) ? \ + _GT_trace(&(mask), (format), (arg1), (arg2), (arg3), (arg4), (arg5), \ + (arg6)) : 0) + +#endif /* GT_TRACE */ + +#endif /* _LINT_ */ + +#endif /* GTCE_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/host_os.h b/arch/arm/plat-omap/include/dspbridge/host_os.h new file mode 100644 index 0000000..f539bd0 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/host_os.h @@ -0,0 +1,96 @@ +/* + * host_os.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== windows.h ======== + * + *! Revision History + *! ================ + *! 08-Mar-2004 sb Added cacheflush.h to support Dynamic Memory Mapping feature + *! 16-Feb-2004 sb Added headers required for consistent_alloc + */ + +#ifndef _HOST_OS_H_ +#define _HOST_OS_H_ + +#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 +#include +#include +#include + +/* ----------------------------------- Macros */ + +#define SEEK_SET 0 /* Seek from beginning of file. */ +#define SEEK_CUR 1 /* Seek from current position. */ +#define SEEK_END 2 /* Seek from end of file. */ + +/* TODO -- Remove, once BP defines them */ +#define INT_MAIL_MPU_IRQ 26 +#define INT_DSP_MMU_IRQ 28 + +struct dspbridge_platform_data { + void (*dsp_set_min_opp)(u8 opp_id); + u8 (*dsp_get_opp)(void); + void (*cpu_set_freq)(unsigned long f); + unsigned long (*cpu_get_freq)(void); + unsigned long mpu_speed[6]; + + u32 phys_mempool_base; + u32 phys_mempool_size; +}; + +#define PRCM_VDD1 1 + +extern struct platform_device *omap_dspbridge_dev; + +#if defined(CONFIG_MPU_BRIDGE) || defined(CONFIG_MPU_BRIDGE_MODULE) +extern void dspbridge_reserve_sdram(void); +#else +static inline void dspbridge_reserve_sdram(void) {} +#endif + +extern unsigned long dspbridge_get_mempool_base(void); +#endif + diff --git a/arch/arm/plat-omap/include/dspbridge/io.h b/arch/arm/plat-omap/include/dspbridge/io.h new file mode 100644 index 0000000..6dc63f2 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/io.h @@ -0,0 +1,132 @@ +/* + * io.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== io.h ======== + * Description: + * The io module manages IO between CHNL and MSG. + * + * Public Functions: + * IO_Create + * IO_Destroy + * IO_Exit + * IO_Init + * IO_OnLoaded + * + * + *! Revision History: + *! ================ + *! 07-Nov-2000 jeh Created. + */ + +#ifndef IO_ +#define IO_ + +#include +#include + +#include + +/* + * ======== IO_Create ======== + * Purpose: + * Create an IO manager object, responsible for managing IO between + * CHNL and MSG. + * Parameters: + * phChnlMgr: Location to store a channel manager object on + * output. + * hDevObject: Handle to a device object. + * pMgrAttrs: IO manager attributes. + * pMgrAttrs->bIRQ: I/O IRQ number. + * pMgrAttrs->fShared: TRUE if the IRQ is shareable. + * pMgrAttrs->uWordSize: DSP Word size in equivalent PC bytes.. + * Returns: + * DSP_SOK: Success; + * DSP_EMEMORY: Insufficient memory for requested resources. + * CHNL_E_ISR: Unable to plug channel ISR for configured IRQ. + * CHNL_E_INVALIDIRQ: Invalid IRQ number. Must be 0 <= bIRQ <= 15. + * CHNL_E_INVALIDWORDSIZE: Invalid DSP word size. Must be > 0. + * CHNL_E_INVALIDMEMBASE: Invalid base address for DSP communications. + * Requires: + * IO_Init(void) called. + * phIOMgr != NULL. + * pMgrAttrs != NULL. + * Ensures: + */ + extern DSP_STATUS IO_Create(OUT struct IO_MGR **phIOMgr, + struct DEV_OBJECT *hDevObject, + IN CONST struct IO_ATTRS *pMgrAttrs); + +/* + * ======== IO_Destroy ======== + * Purpose: + * Destroy the IO manager. + * Parameters: + * hIOMgr: IOmanager object. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: hIOMgr was invalid. + * Requires: + * IO_Init(void) called. + * Ensures: + */ + extern DSP_STATUS IO_Destroy(struct IO_MGR *hIOMgr); + +/* + * ======== IO_Exit ======== + * Purpose: + * Discontinue usage of the IO module. + * Parameters: + * Returns: + * Requires: + * IO_Init(void) previously called. + * Ensures: + * Resources, if any acquired in IO_Init(void), are freed when the last + * client of IO calls IO_Exit(void). + */ + extern void IO_Exit(void); + +/* + * ======== IO_Init ======== + * Purpose: + * Initialize the IO module's private state. + * Parameters: + * Returns: + * TRUE if initialized; FALSE if error occurred. + * Requires: + * Ensures: + * A requirement for each of the other public CHNL functions. + */ + extern bool IO_Init(void); + +/* + * ======== IO_OnLoaded ======== + * Purpose: + * Called when a program is loaded so IO manager can update its + * internal state. + * Parameters: + * hIOMgr: IOmanager object. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: hIOMgr was invalid. + * Requires: + * IO_Init(void) called. + * Ensures: + */ + extern DSP_STATUS IO_OnLoaded(struct IO_MGR *hIOMgr); + +#endif /* CHNL_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/io_sm.h b/arch/arm/plat-omap/include/dspbridge/io_sm.h new file mode 100644 index 0000000..3dcbf74 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/io_sm.h @@ -0,0 +1,335 @@ +/* + * io_sm.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== io_sm.h ======== + * Description: + * IO dispatcher for a shared memory channel driver. + * Also, includes macros to simulate SHM via port io calls. + * + * Public Functions: + * IO_Dispatch + * IO_DPC + * IO_ISR + * IO_RequestChnl + * + * Notes: + * + *! Revision History: + *! ================ + *! 01-Mar-2004 vp: Added IVA releated functions. + *! 23-Apr-2003 sb: Fixed mailbox deadlock + *! 06-Feb-2003 kc Added IO_DDMAClearChnlDesc and IO_DDZCClearChnlDesc. + *! 21-Dec-2001 ag Removed unused param in IO_DDMAInitChnlDesc(). + * Updated comments. Removed #ifdef CHNL_NOIPCINTR. + *! 05-Nov-2001 kc Updated IO_CALLISR macro. + *! 01-May-2001 jeh Removed IO_RequestMsg. + *! 29-Mar-2001 ag Added #ifdef CHNL_NOIPCINTR. + *! 04-Dec-2000 jeh Added IO_RequestMsg. + *! 26-Oct-2000 jeh Added IO_GetLong, IO_SetLong, IO_ReadValueLong, and + *! IO_WriteValueLong, for passing arg in SHM structure. + *! 20-Jan-2000 ag: Updated header comments per code review. + *! 05-Jan-2000 ag: Text format clean-up. + *! 02-Nov-1999 ag: Updated header descriptions. + *! 25-May-1999 jg: Removed assumption of 4 bytes / word. + *! 12-Aug-1996 gp: Created. + */ + +#ifndef IOSM_ +#define IOSM_ + +#include +#include + +#include + +#define IO_INPUT 0 +#define IO_OUTPUT 1 +#define IO_SERVICE 2 +#define IO_MAXSERVICE IO_SERVICE + +#define IO_MGRSIGNATURE 0x494f4D43 /* "IOGR" */ + +#define DSPFieldAddr(type, field, base, wordsize) \ + ((((s32)&(((type *)0)->field)) / wordsize) + (u32)base) + +/* Access can be different SM access word size (e.g. 16/32 bit words) */ +#define IO_SetValue(pContext, type, base, field, value) (base->field = value) +#define IO_GetValue(pContext, type, base, field) (base->field) +#define IO_OrValue(pContext, type, base, field, value) (base->field |= value) +#define IO_AndValue(pContext, type, base, field, value) (base->field &= value) +#define IO_SetLong(pContext, type, base, field, value) (base->field = value) +#define IO_GetLong(pContext, type, base, field) (base->field) + +#define IO_DisableInterrupt(h) CHNLSM_DisableInterrupt(h) +#define IO_EnableInterrupt(h) CHNLSM_EnableInterrupt(h) +#define IO_CALLISR(h, pFlag, pwMBRegVal) CHNLSM_ISR(h, pFlag, pwMBRegVal) + +/* + * ======== IO_CancelChnl ======== + * Purpose: + * Cancel IO on a given channel. + * Parameters: + * hIOMgr: IO Manager. + * ulChnl: Index of channel to cancel IO on. + * Returns: + * Requires: + * Valid hIOMgr. + * Ensures: + */ + extern void IO_CancelChnl(struct IO_MGR *hIOMgr, u32 ulChnl); + +/* + * ======== IO_DPC ======== + * Purpose: + * Deferred procedure call for shared memory channel driver ISR. Carries + * out the dispatch of I/O. + * Parameters: + * pRefData: Pointer to reference data registered via a call to + * DPC_Create(). + * Returns: + * Requires: + * Must not block. + * Must not acquire resources. + * All data touched must be locked in memory if running in kernel mode. + * Ensures: + * Non-preemptible (but interruptible). + */ + extern void IO_DPC(IN OUT void *pRefData); + +/* + * ======== IO_ISR ======== + * Purpose: + * Main interrupt handler for the shared memory WMD channel manager. + * Calls the WMD's CHNLSM_ISR to determine if this interrupt is ours, then + * schedules a DPC to dispatch I/O.. + * Parameters: + * pRefData: Pointer to the channel manager object for this board. + * Set in an initial call to ISR_Install(). + * Returns: + * TRUE if interrupt handled; FALSE otherwise. + * Requires: + * Must be in locked memory if executing in kernel mode. + * Must only call functions which are in locked memory if Kernel mode. + * Must only call asynchronous services. + * Interrupts are disabled and EOI for this interrupt has been sent. + * Ensures: + */ + irqreturn_t IO_ISR(int irq, IN void *pRefData); +/* + * ======== IO_RequestChnl ======== + * Purpose: + * Request I/O from the DSP. Sets flags in shared memory, then interrupts + * the DSP. + * Parameters: + * hIOMgr: IO manager handle. + * pChnl: Ptr to the channel requesting I/O. + * iMode: Mode of channel: {IO_INPUT | IO_OUTPUT}. + * Returns: + * Requires: + * pChnl != NULL + * Ensures: + */ + extern void IO_RequestChnl(struct IO_MGR *hIOMgr, + struct CHNL_OBJECT *pChnl, + u32 iMode, OUT u16 *pwMbVal); + +/* + * ======== IO_Schedule ======== + * Purpose: + * Schedule DPC for IO. + * Parameters: + * pIOMgr: Ptr to a I/O manager. + * Returns: + * Requires: + * pChnl != NULL + * Ensures: + */ + extern void IO_Schedule(struct IO_MGR *hIOMgr); + +/* + * DSP-DMA IO functions + */ + +/* + * ======== IO_DDMAInitChnlDesc ======== + * Purpose: + * Initialize DSP DMA channel descriptor. + * Parameters: + * hIOMgr: Handle to a I/O manager. + * uDDMAChnlId: DDMA channel identifier. + * uNumDesc: Number of buffer descriptors(equals # of IOReqs & + * Chirps) + * pDsp: Dsp address; + * Returns: + * Requires: + * uDDMAChnlId < DDMA_MAXDDMACHNLS + * uNumDesc > 0 + * pVa != NULL + * pDspPa != NULL + * + * Ensures: + */ + extern void IO_DDMAInitChnlDesc(struct IO_MGR *hIOMgr, u32 uDDMAChnlId, + u32 uNumDesc, void *pDsp); + +/* + * ======== IO_DDMAClearChnlDesc ======== + * Purpose: + * Clear DSP DMA channel descriptor. + * Parameters: + * hIOMgr: Handle to a I/O manager. + * uDDMAChnlId: DDMA channel identifier. + * Returns: + * Requires: + * uDDMAChnlId < DDMA_MAXDDMACHNLS + * Ensures: + */ + extern void IO_DDMAClearChnlDesc(struct IO_MGR *hIOMgr, + u32 uDDMAChnlId); + +/* + * ======== IO_DDMARequestChnl ======== + * Purpose: + * Request channel DSP-DMA from the DSP. Sets up SM descriptors and + * control fields in shared memory. + * Parameters: + * hIOMgr: Handle to a I/O manager. + * pChnl: Ptr to channel object + * pChirp: Ptr to channel i/o request packet. + * Returns: + * Requires: + * pChnl != NULL + * pChnl->cIOReqs > 0 + * pChirp != NULL + * Ensures: + */ + extern void IO_DDMARequestChnl(struct IO_MGR *hIOMgr, + struct CHNL_OBJECT *pChnl, + struct CHNL_IRP *pChirp, + OUT u16 *pwMbVal); + +/* + * Zero-copy IO functions + */ + +/* + * ======== IO_DDZCInitChnlDesc ======== + * Purpose: + * Initialize ZCPY channel descriptor. + * Parameters: + * hIOMgr: Handle to a I/O manager. + * uZId: zero-copy channel identifier. + * Returns: + * Requires: + * uDDMAChnlId < DDMA_MAXZCPYCHNLS + * hIOMgr != Null + * Ensures: + */ + extern void IO_DDZCInitChnlDesc(struct IO_MGR *hIOMgr, u32 uZId); + +/* + * ======== IO_DDZCClearChnlDesc ======== + * Purpose: + * Clear DSP ZC channel descriptor. + * Parameters: + * hIOMgr: Handle to a I/O manager. + * uChnlId: ZC channel identifier. + * Returns: + * Requires: + * hIOMgr is valid + * uChnlId < DDMA_MAXZCPYCHNLS + * Ensures: + */ + extern void IO_DDZCClearChnlDesc(struct IO_MGR *hIOMgr, u32 uChnlId); + +/* + * ======== IO_DDZCRequestChnl ======== + * Purpose: + * Request zero-copy channel transfer. Sets up SM descriptors and + * control fields in shared memory. + * Parameters: + * hIOMgr: Handle to a I/O manager. + * pChnl: Ptr to channel object + * pChirp: Ptr to channel i/o request packet. + * Returns: + * Requires: + * pChnl != NULL + * pChnl->cIOReqs > 0 + * pChirp != NULL + * Ensures: + */ + extern void IO_DDZCRequestChnl(struct IO_MGR *hIOMgr, + struct CHNL_OBJECT *pChnl, + struct CHNL_IRP *pChirp, + OUT u16 *pwMbVal); + +/* + * ======== IO_SHMsetting ======== + * Purpose: + * Sets the shared memory setting + * Parameters: + * hIOMgr: Handle to a I/O manager. + * desc: Shared memory type + * pArgs: Ptr to SHM setting + * Returns: + * Requires: + * hIOMgr != NULL + * pArgs != NULL + * Ensures: + */ + extern DSP_STATUS IO_SHMsetting(IN struct IO_MGR *hIOMgr, + IN enum SHM_DESCTYPE desc, + IN void *pArgs); + +/* + * Misc functions for the CHNL_IO shared memory library: + */ + +/* Maximum channel bufsize that can be used. */ + extern u32 IO_BufSize(struct IO_MGR *hIOMgr); + + extern u32 IO_ReadValue(struct WMD_DEV_CONTEXT *hDevContext, + u32 dwDSPAddr); + + extern void IO_WriteValue(struct WMD_DEV_CONTEXT *hDevContext, + u32 dwDSPAddr, u32 dwValue); + + extern u32 IO_ReadValueLong(struct WMD_DEV_CONTEXT *hDevContext, + u32 dwDSPAddr); + + extern void IO_WriteValueLong(struct WMD_DEV_CONTEXT *hDevContext, + u32 dwDSPAddr, u32 dwValue); + + extern void IO_OrSetValue(struct WMD_DEV_CONTEXT *hDevContext, + u32 dwDSPAddr, u32 dwValue); + + extern void IO_AndSetValue(struct WMD_DEV_CONTEXT *hDevContext, + u32 dwDSPAddr, u32 dwValue); + + extern void IO_IntrDSP2(IN struct IO_MGR *pIOMgr, IN u16 wMbVal); + + extern void IO_SM_init(void); + +/* + * ========PrintDspTraceBuffer ======== + * Print DSP tracebuffer. + */ + extern DSP_STATUS PrintDspTraceBuffer(struct WMD_DEV_CONTEXT + *hWmdContext); + +#endif /* IOSM_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/iodefs.h b/arch/arm/plat-omap/include/dspbridge/iodefs.h new file mode 100644 index 0000000..f45890a --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/iodefs.h @@ -0,0 +1,45 @@ +/* + * iodefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== iodefs.h ======== + * Description: + * System-wide channel objects and constants. + * + *! Revision History: + *! ================ + *! 07-Nov-2000 jeh Created. + */ + +#ifndef IODEFS_ +#define IODEFS_ + +#define IO_MAXIRQ 0xff /* Arbitrarily large number. */ + +/* IO Objects: */ + struct IO_MGR; + +/* IO manager attributes: */ + struct IO_ATTRS { + u8 bIRQ; /* Channel's I/O IRQ number. */ + bool fShared; /* TRUE if the IRQ is shareable. */ + u32 uWordSize; /* DSP Word size. */ + u32 dwSMBase; /* Physical base address of shared memory. */ + u32 uSMLength; /* Size (in bytes) of shared memory. */ + } ; + +#endif /* IODEFS_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/kfile.h b/arch/arm/plat-omap/include/dspbridge/kfile.h new file mode 100644 index 0000000..23c89b0 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/kfile.h @@ -0,0 +1,216 @@ +/* + * kfile.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== kfile.h ======== + * Purpose: + * Provide file I/O management capabilities. + * + * Public Functions: + * KFILE_Close + * KFILE_Exit + * KFILE_Init + * KFILE_Open + * KFILE_Read + * KFILE_Seek + * KFILE_Tell + * KFILE_Write + * + * Notes: + * The KFILE module is not like most of the other DSP/BIOS Bridge modules + * in that it doesn't return WSX_STATUS type values. Rather, it's + * prototypes are meant to match the stdio file prototypes + * (ie, fopen, fclose, etc.). + * + *! Revision History + *! ================ + *! 29-Oct-1999 kc: Clean up for code review. + *! 07-Jan-1998 cr: Clean up for code review. + *! 15-Aug-1997 cr: Added E_KFILE_ERROR for general error condition. + *! 04-Aug-1997 cr: Added explicit CDECL descriptions. + *! 11-Nov-1996 cr: Implemented changes based on code review. + *! 05-Nov-1996 cr: Cleaned up for code review. + *! 29-May-1996 gp: Added requirement that size != 0 in _Write() and _Read(). + *! 28-May-1996 mg: Changed return values for Read/Write. + *! 14-Dec-1995 cr: Created. + */ + +#ifndef KFILE_ +#define KFILE_ + +/* + * Constants for KFILE_Seek. Note that these MUST be the same definitions as + * those defined for fseek. + */ +#define KFILE_SEEK_SET 0x00 /* seek from beginning of file */ +#define KFILE_SEEK_CUR 0x01 /* seek from current position */ +#define KFILE_SEEK_END 0x02 /* seek from end of file */ + + struct KFILE_FileObj; + +/* + * ======== KFILE_Close ======== + * Purpose: + * This function closes a file's stream. + * Parameters: + * hFile: Handle of the file stream returned by KFILE_Open. + * Returns: + * E_KFILE_INVALIDHANDLE: bad handle. + * 0: success. + * E_KFILE_ERROR: unable to close specified handle. + * Requires: + * KFILE initialized. + * Ensures: + */ + extern s32 KFILE_Close(IN struct KFILE_FileObj *hFile); + +/* + * ======== KFILE_Exit ======== + * Purpose: + * Discontinue usage of module; free resources when reference count + * reaches 0. + * Parameters: + * Returns: + * Requires: + * KFILE initialized. + * Ensures: + * Resources used by module are freed when cRef reaches zero. + */ + extern void KFILE_Exit(void); + +/* + * ======== KFILE_Init ======== + * Purpose: + * Initializes private state of KFILE module. + * Parameters: + * Returns: + * TRUE if success, else FALSE. + * Requires: + * Ensures: + * KFILE initialized. + */ + extern bool KFILE_Init(void); + +/* + * ======== KFILE_Open ======== + * Purpose: + * Opens a file for use. + * Parameters: + * pszFileName: Full path to name of the file to open. + * pszMode: String containing open status. Only the first + * character of the string is examined, for either + * "r" (read) or "w" (write) mode. + * Returns: + * A valid file handle if success, else NULL. + * Requires: + * - KFILE initialized. + * - pszMode != NULL. + * - pszFileName != NULL. + * Ensures: + */ + extern struct KFILE_FileObj *KFILE_Open(IN CONST char *filename, + IN CONST char *mode); + +/* + * ======== KFILE_Read ======== + * Purpose: + * This function reads a specified number of bytes into a buffer. + * Parameters: + * pBuffer: Array to which the file data is copied. + * cSize: Number of characters in each object. + * cCount: Number of objects to read in. + * hFile: Handle of the file stream returned by KFILE_Open. + * Returns: + * E_KFILE_INVALIDHANDLE: bad file handle. + * E_KFILE_ERROR: general failure. + * > 0: success; # of objects read from file. + * Requires: + * KFILE initialized. + * pBuffer is a valid pointer. + * Ensures: + */ + extern s32 KFILE_Read(OUT void __user*buffer, + IN s32 size, IN s32 count, + IN struct KFILE_FileObj *hFile); + +/* + * ======== KFILE_Seek ======== + * Purpose: + * This function sets the file position indicator. NOTE: we don't + * support seeking beyond the boundaries of a file. + * Parameters: + * hFile: Handle of the file stream returned by KFILE_Open. + * offset: Number of bytes from the origin to move. + * origin: File reference point, one of the following values: + * KFILE_SEEK_SET: Seek from beginning of file. + * KFILE_SEEK_CUR: Seek from current position. + * KFILE_SEEK_END: Seek from end of file. + * Returns: + * 0: success. + * E_KFILE_INVALIDHANDLE: bad handle. + * E_KFILE_BADORIGIN: invalid origin paramater. + * E_KFILE_ERROR: general failure. + * Requires: + * KFILE initialized. + * Ensures: + */ + extern s32 KFILE_Seek(IN struct KFILE_FileObj *hFile, + IN s32 offset, IN s32 origin); + +/* + * ======== KFILE_Tell ======== + * Purpose: + * This function reports the current value of the position indicator. + * Parameters: + * hFile: Handle of the file stream returned by KFILE_Open. + * Return value: + * > 0: success; returns # of bytes the position indicator is from + * beginning of file. + * E_KFILE_ERROR: general failure. + * E_KFILE_INVALIDHANDLE: bad file handle. + * Requires: + * KFILE initialized. + * Ensures: + */ + extern s32 KFILE_Tell(IN struct KFILE_FileObj *hFile); + +/* + * ======== KFILE_Write ======== + * Purpose: + * This function writes a number of objects to the stream. + * Parameters: + * pBuffer: Array from which the file data is written. + * cSize: Number of characters in each object. + * cCount: Number of objects to write out. + * hFile: Handle of the file stream returned by KFILE_Open. + * Returns: + * E_KFILE_INVALIDHANDLE: bad file handle. + * E_KFILE_ERROR: general failure. + * > 0: success; # of objects written to file. + * Requires: + * KFILE initialized. + * pBuffer != NULL. + * Postcondition: + * The file position indicator is advanced by the number of + * characters written. + */ + extern s32 KFILE_Write(OUT void *buffer, + IN s32 size, + IN s32 count, + IN struct KFILE_FileObj *hFile); + +#endif /* KFILE_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/ldr.h b/arch/arm/plat-omap/include/dspbridge/ldr.h new file mode 100644 index 0000000..7e13c93 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/ldr.h @@ -0,0 +1,51 @@ +/* + * ldr.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== ldr.h ======== + * Purpose: + * Provide module loading services and symbol export services. + * + * Public Functions: + * LDR_Exit + * LDR_FreeModule + * LDR_GetProcAddress + * LDR_Init + * LDR_LoadModule + * + * Notes: + * This service is meant to be used by modules of the DSP/BIOS Bridge + * class driver. + * + *! Revision History: + *! ================ + *! 22-Nov-1999 kc: Changes from code review. + *! 12-Nov-1999 kc: Removed declaration of unused loader object. + *! 29-Oct-1999 kc: Cleaned up for code review. + *! 12-Jan-1998 cr: Cleaned up for code review. + *! 04-Aug-1997 cr: Added explicit CDECL identifiers. + *! 11-Nov-1996 cr: Cleaned up for code review. + *! 16-May-1996 gp: Created. + */ + +#ifndef LDR_ +#define LDR_ + +/* Loader objects: */ + struct LDR_MODULE; + +#endif /* LDR_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/list.h b/arch/arm/plat-omap/include/dspbridge/list.h new file mode 100644 index 0000000..2e3f995 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/list.h @@ -0,0 +1,296 @@ +/* + * list.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== list.h ======== + * Purpose: + * Declarations of list management control structures and definitions + * of inline list management functions. + * + * Public Functions: + * LST_Create + * LST_Delete + * LST_Exit + * LST_First + * LST_GetHead + * LST_InitElem + * LST_Init + * LST_InsertBefore + * LST_IsEmpty + * LST_Next + * LST_PutTail + * LST_RemoveElem + * + * Notes: + * + *! Revision History + *! ================ + *! 10-Aug-2000 ag: Added LST_InsertBefore(). + *! 29-Oct-1999 kc: Cleaned up for code review. + *! 16-Aug-1997 cr: added explicit identifiers. + *! 10-Aug-1996 gp: Acquired from SMM for WinSPOX v.1.1; renamed identifiers. + *! 21-Oct-1994 dh4: Cleaned / commented for code review. + *! 08-Jun-1994 dh4: Converted to SPM (added extern "C"). + */ + +#ifndef LIST_ +#define LIST_ + +#include + +#define LST_IsEmpty(l) (((l)->head.next == &(l)->head)) + + struct LST_ELEM { + struct LST_ELEM *next; + struct LST_ELEM *prev; + struct LST_ELEM *self; + } ; + + struct LST_LIST { + struct LST_ELEM head; + } ; + +/* + * ======== LST_Create ======== + * Purpose: + * Allocates and initializes a circular list. + * Details: + * Uses portable MEM_Calloc() function to allocate a list containing + * a single element and initializes that element to indicate that it + * is the "end of the list" (i.e., the list is empty). + * An empty list is indicated by the "next" pointer in the element + * at the head of the list pointing to the head of the list, itself. + * Parameters: + * Returns: + * Pointer to beginning of created list (success) + * NULL --> Allocation failed + * Requires: + * LST initialized. + * Ensures: + * Notes: + * The created list contains a single element. This element is the + * "empty" element, because its "next" and "prev" pointers point at + * the same location (the element itself). + */ + extern struct LST_LIST *LST_Create(void); + +/* + * ======== LST_Delete ======== + * Purpose: + * Removes a list by freeing its control structure's memory space. + * Details: + * Uses portable MEM_Free() function to deallocate the memory + * block pointed at by the input parameter. + * Parameters: + * pList: Pointer to list control structure of list to be deleted + * Returns: + * Void + * Requires: + * - LST initialized. + * - pList != NULL. + * Ensures: + * Notes: + * Must ONLY be used for empty lists, because it does not walk the + * chain of list elements. Calling this function on a non-empty list + * will cause a memory leak. + */ + extern void LST_Delete(IN struct LST_LIST *pList); + +/* + * ======== LST_Exit ======== + * Purpose: + * Discontinue usage of module; free resources when reference count + * reaches 0. + * Parameters: + * Returns: + * Requires: + * LST initialized. + * Ensures: + * Resources used by module are freed when cRef reaches zero. + */ + extern void LST_Exit(void); + +/* + * ======== LST_First ======== + * Purpose: + * Returns a pointer to the first element of the list, or NULL if the list + * is empty. + * Parameters: + * pList: Pointer to list control structure. + * Returns: + * Pointer to first list element, or NULL. + * Requires: + * - LST initialized. + * - pList != NULL. + * Ensures: + */ + extern struct LST_ELEM *LST_First(IN struct LST_LIST *pList); + +/* + * ======== LST_GetHead ======== + * Purpose: + * Pops the head off the list and returns a pointer to it. + * Details: + * If the list is empty, returns NULL. + * Else, removes the element at the head of the list, making the next + * element the head of the list. + * The head is removed by making the tail element of the list point its + * "next" pointer at the next element after the head, and by making the + * "prev" pointer of the next element after the head point at the tail + * element. So the next element after the head becomes the new head of + * the list. + * Parameters: + * pList: Pointer to list control structure of list whose head + * element is to be removed + * Returns: + * Pointer to element that was at the head of the list (success) + * NULL No elements in list + * Requires: + * - head.self must be correctly set to &head. + * - LST initialized. + * - pList != NULL. + * Ensures: + * Notes: + * Because the tail of the list points forward (its "next" pointer) to + * the head of the list, and the head of the list points backward (its + * "prev" pointer) to the tail of the list, this list is circular. + */ + extern struct LST_ELEM *LST_GetHead(IN struct LST_LIST *pList); + +/* + * ======== LST_Init ======== + * Purpose: + * Initializes private state of LST module. + * Parameters: + * Returns: + * TRUE if initialized; FALSE otherwise. + * Requires: + * Ensures: + * LST initialized. + */ + extern bool LST_Init(void); + +/* + * ======== LST_InitElem ======== + * Purpose: + * Initializes a list element to default (cleared) values + * Details: + * Parameters: + * pElem: Pointer to list element to be reset + * Returns: + * Requires: + * LST initialized. + * Ensures: + * Notes: + * This function must not be called to "reset" an element in the middle + * of a list chain -- that would break the chain. + * + */ + extern void LST_InitElem(IN struct LST_ELEM *pListElem); + +/* + * ======== LST_InsertBefore ======== + * Purpose: + * Insert the element before the existing element. + * Parameters: + * pList: Pointer to list control structure. + * pElem: Pointer to element in list to insert. + * pElemExisting: Pointer to existing list element. + * Returns: + * Requires: + * - LST initialized. + * - pList != NULL. + * - pElem != NULL. + * - pElemExisting != NULL. + * Ensures: + */ + extern void LST_InsertBefore(IN struct LST_LIST *pList, + IN struct LST_ELEM *pElem, + IN struct LST_ELEM *pElemExisting); + +/* + * ======== LST_Next ======== + * Purpose: + * Returns a pointer to the next element of the list, or NULL if the next + * element is the head of the list or the list is empty. + * Parameters: + * pList: Pointer to list control structure. + * pCurElem: Pointer to element in list to remove. + * Returns: + * Pointer to list element, or NULL. + * Requires: + * - LST initialized. + * - pList != NULL. + * - pCurElem != NULL. + * Ensures: + */ + extern struct LST_ELEM *LST_Next(IN struct LST_LIST *pList, + IN struct LST_ELEM *pCurElem); + +/* + * ======== LST_PutTail ======== + * Purpose: + * Adds the specified element to the tail of the list + * Details: + * Sets new element's "prev" pointer to the address previously held by + * the head element's prev pointer. This is the previous tail member of + * the list. + * Sets the new head's prev pointer to the address of the element. + * Sets next pointer of the previous tail member of the list to point to + * the new element (rather than the head, which it had been pointing at). + * Sets new element's next pointer to the address of the head element. + * Sets head's prev pointer to the address of the new element. + * Parameters: + * pList: Pointer to list control structure to which *pElem will be + * added + * pElem: Pointer to list element to be added + * Returns: + * Void + * Requires: + * *pElem and *pList must both exist. + * pElem->self = pElem before pElem is passed to this function. + * LST initialized. + * Ensures: + * Notes: + * Because the tail is always "just before" the head of the list (the + * tail's "next" pointer points at the head of the list, and the head's + * "prev" pointer points at the tail of the list), the list is circular. + * Warning: if pElem->self is not set beforehand, LST_GetHead() will + * return an erroneous pointer when it is called for this element. + */ + extern void LST_PutTail(IN struct LST_LIST *pList, + IN struct LST_ELEM *pListElem); + +/* + * ======== LST_RemoveElem ======== + * Purpose: + * Removes (unlinks) the given element from the list, if the list is not + * empty. Does not free the list element. + * Parameters: + * pList: Pointer to list control structure. + * pCurElem: Pointer to element in list to remove. + * Returns: + * Requires: + * - LST initialized. + * - pList != NULL. + * - pCurElem != NULL. + * Ensures: + */ +extern void LST_RemoveElem(IN struct LST_LIST *pList, + IN struct LST_ELEM *pCurElem); + +#endif /* LIST_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/mbx_sh.h b/arch/arm/plat-omap/include/dspbridge/mbx_sh.h new file mode 100644 index 0000000..be0909e --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/mbx_sh.h @@ -0,0 +1,213 @@ +/* + * mbx_sh.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== mbx_sh.h ======== + * Definitions for shared mailbox cmd/data values.(used on both + * the GPP and DSP sides). + * + * Bridge usage of OMAP mailbox 1 is determined by the "class" of the + * mailbox interrupt's cmd value received. The class value are defined + * as a bit (10 thru 15) being set. + * + * Note: Only 16 bits of each is used. Other 16 bit data reg available. + * + * 16 bit Mbx bit defns: + * + * A). Exception/Error handling (Module DEH) : class = 0. + * + * 15 10 0 + * --------------------------------- + * |0|0|0|0|0|0|x|x|x|x|x|x|x|x|x|x| + * --------------------------------- + * | (class) | (module specific) | + * + * + * + * B: DSP-DMA link driver channels (DDMA) : class = 1. + * + * 15 10 0 + * --------------------------------- + * |0|0|0|0|0|1|b|b|b|b|b|c|c|c|c|c| + * --------------------------------- + * | (class) | (module specific) | + * + * where b -> buffer index (32 DDMA buffers/chnl max) + * c -> channel Id (32 DDMA chnls max) + * + * + * + * + * C: Proc-copy link driver channels (PCPY) : class = 2. + * + * 15 10 0 + * --------------------------------- + * |0|0|0|0|1|0|x|x|x|x|x|x|x|x|x|x| + * --------------------------------- + * | (class) | (module specific) | + * + * + * D: Zero-copy link driver channels (DDZC) : class = 4. + * + * 15 10 0 + * --------------------------------- + * |0|0|0|1|0|0|x|x|x|x|x|c|c|c|c|c| + * --------------------------------- + * | (class) | (module specific) | + * + * where x -> not used + * c -> channel Id (32 ZCPY chnls max) + * + * + * E: Power management : class = 8. + * + * 15 10 0 + * --------------------------------- + * |0|0|1|0|0|0|x|x|x|x|x|c|c|c|c|c| + + * 0010 00xx xxxc cccc + * 0010 00nn pppp qqqq + * nn: + * 00 = reserved + * 01 = pwr state change + * 10 = opp pre-change + * 11 = opp post-change + * + * if nn = pwr state change: + * pppp = don't care + * qqqq: + * 0010 = hibernate + * 0010 0001 0000 0010 + * 0110 = retention + * 0010 0001 0000 0110 + * others reserved + * + * if nn = opp pre-change: + * pppp = current opp + * qqqq = next opp + * + * if nn = opp post-change: + * pppp = prev opp + * qqqq = current opp + * + * --------------------------------- + * | (class) | (module specific) | + * + * where x -> not used + * c -> Power management command + * + * + * + *! Revision History: + *! ================ + *! 19-Sep-2002 mr Added DEH reset const + *! 24-Apr-2002 sg Added more PM commands. + *! 04-Mar-2002 gv Added MBX_PM_CLASS + *! 22-Jan-2002 ag Bug fix in MBX_SETZCPYVAL(x) macro. + *! 21-Dec-2001 ag Added bit masks defns. + *! 17-Dec-2001 ag: created. + */ + +#ifndef _MBX_SH_H +#define _MBX_SH_H + +#define MBX_CLASS_MSK 0xFC00 /* Class bits are 10 thru 15 */ +#define MBX_VALUE_MSK 0x03FF /* Value is 0 thru 9 */ + +#define MBX_DEH_CLASS 0x0000 /* DEH owns Mbx INTR */ +#define MBX_DDMA_CLASS 0x0400 /* DSP-DMA link drvr chnls owns INTR */ +#define MBX_PCPY_CLASS 0x0800 /* PROC-COPY " */ +#define MBX_ZCPY_CLASS 0x1000 /* ZERO-COPY " */ +#define MBX_PM_CLASS 0x2000 /* Power Management */ +#define MBX_DBG_CLASS 0x4000 /* For debugging purpose */ + +/* + * Exception Handler codes + * Magic code used to determine if DSP signaled exception. + */ +#define MBX_DEH_BASE 0x0 +#define MBX_DEH_USERS_BASE 0x100 /* 256 */ +#define MBX_DEH_LIMIT 0x3FF /* 1023 */ +#define MBX_DEH_RESET 0x101 /* DSP RESET (DEH) */ +#define MBX_DEH_EMMU 0X103 /*DSP MMU FAULT RECOVERY*/ + +/* + * Link driver command/status codes. + */ +/* DSP-DMA */ +#define MBX_DDMA_NUMCHNLBITS 5 /* # chnl Id: # bits available */ +#define MBX_DDMA_CHNLSHIFT 0 /* # of bits to shift */ +#define MBX_DDMA_CHNLMSK 0x01F /* bits 0 thru 4 */ + +#define MBX_DDMA_NUMBUFBITS 5 /* buffer index: # of bits avail */ +#define MBX_DDMA_BUFSHIFT (MBX_DDMA_NUMCHNLBITS + MBX_DDMA_CHNLSHIFT) +#define MBX_DDMA_BUFMSK 0x3E0 /* bits 5 thru 9 */ + +/* Zero-Copy */ +#define MBX_ZCPY_NUMCHNLBITS 5 /* # chnl Id: # bits available */ +#define MBX_ZCPY_CHNLSHIFT 0 /* # of bits to shift */ +#define MBX_ZCPY_CHNLMSK 0x01F /* bits 0 thru 4 */ + +/* Power Management Commands */ +#define MBX_PM_DSPIDLE (MBX_PM_CLASS + 0x0) +#define MBX_PM_DSPWAKEUP (MBX_PM_CLASS + 0x1) +#define MBX_PM_EMERGENCYSLEEP (MBX_PM_CLASS + 0x2) +#define MBX_PM_SLEEPUNTILRESTART (MBX_PM_CLASS + 0x3) +#define MBX_PM_DSPGLOBALIDLE_OFF (MBX_PM_CLASS + 0x4) +#define MBX_PM_DSPGLOBALIDLE_ON (MBX_PM_CLASS + 0x5) +#define MBX_PM_SETPOINT_PRENOTIFY (MBX_PM_CLASS + 0x6) +#define MBX_PM_SETPOINT_POSTNOTIFY (MBX_PM_CLASS + 0x7) +#define MBX_PM_DSPRETN (MBX_PM_CLASS + 0x8) +#define MBX_PM_DSPRETENTION (MBX_PM_CLASS + 0x8) +#define MBX_PM_DSPHIBERNATE (MBX_PM_CLASS + 0x9) +#define MBX_PM_HIBERNATE_EN (MBX_PM_CLASS + 0xA) +#define MBX_PM_OPP_REQ (MBX_PM_CLASS + 0xB) +#define MBX_PM_OPP_CHG (MBX_PM_CLASS + 0xC) + +#define MBX_PM_TYPE_MASK 0x0300 +#define MBX_PM_TYPE_PWR_CHNG 0x0100 +#define MBX_PM_TYPE_OPP_PRECHNG 0x0200 +#define MBX_PM_TYPE_OPP_POSTCHNG 0x0300 +#define MBX_PM_TYPE_OPP_MASK 0x0300 +#define MBX_PM_OPP_PRECHNG (MBX_PM_CLASS | MBX_PM_TYPE_OPP_PRECHNG) +/* DSP to MPU */ +#define MBX_PM_OPP_CHNG(OPP) (MBX_PM_CLASS | MBX_PM_TYPE_OPP_PRECHNG | (OPP)) +#define MBX_PM_RET (MBX_PM_CLASS | MBX_PM_TYPE_PWR_CHNG | 0x0006) +#define MBX_PM_HIB (MBX_PM_CLASS | MBX_PM_TYPE_PWR_CHNG | 0x0002) +#define MBX_PM_OPP_1 0 +#define MBX_PM_OPP_2 1 +#define MBX_PM_OPP_3 2 +#define MBX_PM_OPP_4 3 +#define MBX_OLDOPP_EXTRACT(OPPMSG) ((0x00F0 & (OPPMSG)) >> 4) +#define MBX_NEWOPP_EXTRACT(OPPMSG) (0x000F & (OPPMSG)) +#define MBX_PREVOPP_EXTRACT(OPPMSG) ((0x00F0 & (OPPMSG)) >> 4) +#define MBX_CUROPP_EXTRACT(OPPMSG) (0x000F & (OPPMSG)) + +/* Bridge Debug Commands */ +#define MBX_DBG_SYSPRINTF (MBX_DBG_CLASS + 0x0) + +/* + * Useful macros + */ +/* DSP-DMA channel */ +#define MBX_SETDDMAVAL(x, y) (MBX_DDMA_CLASS | (x << MBX_DDMA_BUFSHIFT) | \ + (y << MBX_DDMA_CHNLSHIFT)) + +/* Zero-Copy channel */ +#define MBX_SETZCPYVAL(x) (MBX_ZCPY_CLASS | (x << MBX_ZCPY_CHNLSHIFT)) + +#endif /* _MBX_SH_H */ diff --git a/arch/arm/plat-omap/include/dspbridge/mem.h b/arch/arm/plat-omap/include/dspbridge/mem.h new file mode 100644 index 0000000..535ac3a --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/mem.h @@ -0,0 +1,340 @@ +/* + * mem.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== mem.h ======== + * Purpose: + * Memory management and address mapping services for the DSP/BIOS Bridge + * class driver and mini-driver. + * + * Public Functions: + * MEM_Alloc + * MEM_AllocObject + * MEM_AllocPhysMem + * MEM_Calloc + * MEM_Exit + * MEM_FlushCache + * MEM_Free + * MEM_FreeObject + * MEM_FreePhysMem + * MEM_GetNumPages + * MEM_Init + * MEM_IsValidHandle + * MEM_LinearAddress + * MEM_PageLock + * MEM_PageUnlock + * MEM_UnMapLinearAddress + * MEM_VirtualToPhysical + * + * Notes: + * + *! Revision History: + *! ================ + *! 19-Apr-2004 sb: Added Alloc/Free PhysMem, FlushCache, VirtualToPhysical + *! 01-Sep-2001 ag: Cleaned up notes for MEM_LinearAddress() does not + *! require phys address to be page aligned! + *! 02-Dec-1999 rr: stdwin.h included for retail build + *! 12-Nov-1999 kc: Added warning about use of MEM_LinearAddress. + *! 29-Oct-1999 kc: Cleaned up for code review. + *! 10-Aug-1999 kc: Based on wsx-c18. + *! 07-Jan-1998 gp: Added MEM_AllocUMB and MEM_UMBFree for User Mapped Buffers + *! used by WMD_CHNL. + *! 23-Dec-1997 cr: Code review cleanup, removed dead Ring 3 code. + *! 04-Aug-1997 cr: Added explicit CDECL identifiers. + *! 01-Nov-1996 gp: Updated based on code review. + *! 04-Sep-1996 gp: Added MEM_PageLock() and MEM_PageUnlock() services. + *! 14-Aug-1996 mg: Added MEM_GetPhysAddr() and MEM_GetNumPages() + *! 25-Jul-1996 gp: Added MEM_IsValidHandle() macro. + *! 10-May-1996 gp: Added MEM_Calloc(). + *! 25-Apr-1996 gp: Added MEM_PhysicalAddress() + *! 17-Apr-1996 gp: Added MEM_Exit function; updated to latest naming standard. + *! 08-Apr-1996 gp: Created. + */ + +#ifndef MEM_ +#define MEM_ + +#include +#include + +/* + * ======== MEM_Alloc ======== + * Purpose: + * Allocate memory from the paged or non-paged pools. + * Parameters: + * cBytes: Number of bytes to allocate. + * type: Type of memory to allocate; one of: + * MEM_PAGED: Allocate from pageable memory. + * MEM_NONPAGED: Allocate from page locked memory. + * Returns: + * Pointer to a block of memory; + * NULL if memory couldn't be allocated, if cBytes == 0, or if type is + * not one of MEM_PAGED or MEM_NONPAGED. + * Requires: + * MEM initialized. + * Ensures: + * The returned pointer, if not NULL, points to a valid memory block of + * the size requested. + */ + extern void *MEM_Alloc(IN u32 cBytes, IN enum MEM_POOLATTRS type); + +/* + * ======== MEM_AllocObject ======== + * Purpose: + * Allocate an object, and set it's signature. + * Parameters: + * pObj: Pointer to the new object. + * Obj: Type of the object to allocate. + * Signature: Magic field value. Must be non-zero. + * Returns: + * Requires: + * Same requirements as MEM_Calloc(); and + * The object structure has a dwSignature field. The compiler ensures + * this requirement. + * Ensures: + * A subsequent call to MEM_IsValidHandle() will succeed for this object. + */ +#define MEM_AllocObject(pObj, Obj, Signature) \ +{ \ + pObj = MEM_Calloc(sizeof(Obj), MEM_NONPAGED); \ + if (pObj) { \ + pObj->dwSignature = Signature; \ + } \ +} + +/* ======== MEM_AllocPhysMem ======== + * Purpose: + * Allocate physically contiguous, uncached memory + * Parameters: + * cBytes: Number of bytes to allocate. + * ulAlign: Alignment Mask. + * pPhysicalAddress: Physical address of allocated memory. + * Returns: + * Pointer to a block of memory; + * NULL if memory couldn't be allocated, or if cBytes == 0. + * Requires: + * MEM initialized. + * Ensures: + * The returned pointer, if not NULL, points to a valid memory block of + * the size requested. Returned physical address refers to physical + * location of memory. + */ + extern void *MEM_AllocPhysMem(IN u32 cBytes, + IN u32 ulAlign, + OUT u32 *pPhysicalAddress); + +/* + * ======== MEM_Calloc ======== + * Purpose: + * Allocate zero-initialized memory from the paged or non-paged pools. + * Parameters: + * cBytes: Number of bytes to allocate. + * type: Type of memory to allocate; one of: + * MEM_PAGED: Allocate from pageable memory. + * MEM_NONPAGED: Allocate from page locked memory. + * Returns: + * Pointer to a block of zeroed memory; + * NULL if memory couldn't be allocated, if cBytes == 0, or if type is + * not one of MEM_PAGED or MEM_NONPAGED. + * Requires: + * MEM initialized. + * Ensures: + * The returned pointer, if not NULL, points to a valid memory block + * of the size requested. + */ + extern void *MEM_Calloc(IN u32 cBytes, IN enum MEM_POOLATTRS type); + +/* + * ======== MEM_Exit ======== + * Purpose: + * Discontinue usage of module; free resources when reference count + * reaches 0. + * Parameters: + * Returns: + * Requires: + * MEM is initialized. + * Ensures: + * Resources used by module are freed when cRef reaches zero. + */ + extern void MEM_Exit(void); + +/* + * ======== MEM_FlushCache ======== + * Purpose: + * Performs system cache sync with discard + * Parameters: + * pMemBuf: Pointer to memory region to be flushed. + * pMemBuf: Size of the memory region to be flushed. + * Returns: + * Requires: + * MEM is initialized. + * Ensures: + * Cache is synchronized + */ + extern void MEM_FlushCache(void *pMemBuf, u32 cBytes, s32 FlushType); + +/* + * ======== MEM_Free ======== + * Purpose: + * Free the given block of system memory. + * Parameters: + * pMemBuf: Pointer to memory allocated by MEM_Calloc/Alloc(). + * Returns: + * Requires: + * MEM initialized. + * pMemBuf is a valid memory address returned by MEM_Calloc/Alloc(). + * Ensures: + * pMemBuf is no longer a valid pointer to memory. + */ + extern void MEM_Free(IN void *pMemBuf); + +/* + * ======== MEM_FreePhysMem ======== + * Purpose: + * Free the given block of physically contiguous memory. + * Parameters: + * pVirtualAddress: Pointer to virtual memory region allocated + * by MEM_AllocPhysMem(). + * pPhysicalAddress: Pointer to physical memory region allocated + * by MEM_AllocPhysMem(). + * cBytes: Size of the memory region allocated by MEM_AllocPhysMem(). + * Returns: + * Requires: + * MEM initialized. + * pVirtualAddress is a valid memory address returned by + * MEM_AllocPhysMem() + * Ensures: + * pVirtualAddress is no longer a valid pointer to memory. + */ + extern void MEM_FreePhysMem(void *pVirtualAddress, + u32 pPhysicalAddress, u32 cBytes); + +/* + * ======== MEM_FreeObject ======== + * Purpose: + * Utility macro to invalidate an object's signature, and deallocate it. + * Parameters: + * pObj: Pointer to the object to free. + * Returns: + * Requires: + * Same requirements as MEM_Free(). + * Ensures: + * A subsequent call to MEM_IsValidHandle() will fail for this object. + */ +#define MEM_FreeObject(pObj) \ +{ \ + pObj->dwSignature = 0x00; \ + MEM_Free(pObj); \ +} + +/* + * ======== MEM_GetNumPages ======== + * Purpose: + * Calculate the number of pages corresponding to the supplied buffer. + * Parameters: + * pAddr: Linear (virtual) address of the buffer. + * cBytes: Number of bytes in the buffer. + * Returns: + * Number of pages. + * Requires: + * MEM initialized. + * Ensures: + * If cBytes > 0, number of pages returned > 0. + */ + extern s32 MEM_GetNumPages(IN void *pAddr, IN u32 cBytes); + +/* + * ======== MEM_Init ======== + * Purpose: + * Initializes private state of MEM module. + * Parameters: + * Returns: + * TRUE if initialized; FALSE if error occured. + * Requires: + * Ensures: + * MEM initialized. + */ + extern bool MEM_Init(void); + +/* + * ======== MEM_IsValidHandle ======== + * Purpose: + * Validate the object handle. + * Parameters: + * hObj: Handle to object created with MEM_AllocObject(). + * Sig: Expected signature u32. + * Returns: + * TRUE if handle is valid; FALSE otherwise. + * Requires: + * The object structure has a dwSignature field. Ensured by compiler. + * Ensures: + */ +#define MEM_IsValidHandle(hObj, Sig) \ + ((hObj != NULL) && (hObj->dwSignature == Sig)) + +/* + * ======== MEM_LinearAddress ======== + * Purpose: + * Get the linear address corresponding to the given physical address. + * Parameters: + * pPhysAddr: Physical address to be mapped. + * cBytes: Number of bytes in physical range to map. + * Returns: + * The corresponding linear address, or NULL if unsuccessful. + * Requires: + * MEM initialized. + * Ensures: + * Notes: + * If valid linear address is returned, be sure to call + * MEM_UnmapLinearAddress(). + */ +#define MEM_LinearAddress(pPhyAddr, cBytes) pPhyAddr + +/* + * ======== MEM_UnmapLinearAddress ======== + * Purpose: + * Unmap the linear address mapped in MEM_LinearAddress. + * Parameters: + * pBaseAddr: Ptr to mapped memory (as returned by MEM_LinearAddress()). + * Returns: + * Requires: + * - MEM initialized. + * - pBaseAddr is a valid linear address mapped in MEM_LinearAddress. + * Ensures: + * - pBaseAddr no longer points to a valid linear address. + */ +#define MEM_UnmapLinearAddress(pBaseAddr) + +/* + * ======== MEM_ExtPhysPoolInit ======== + * Purpose: + * Uses the physical memory chunk passed for internal consitent memory + * allocations. + * physical address based on the page frame address. + * Parameters: + * poolPhysBase starting address of the physical memory pool. + * poolSize size of the physical memory pool. + * Returns: + * none. + * Requires: + * - MEM initialized. + * - valid physical address for the base and size > 0 + */ + extern void MEM_ExtPhysPoolInit(IN u32 poolPhysBase, + IN u32 poolSize); + +#endif /* MEM_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/memdefs.h b/arch/arm/plat-omap/include/dspbridge/memdefs.h new file mode 100644 index 0000000..a5bb259 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/memdefs.h @@ -0,0 +1,52 @@ +/* + * memdefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== memdefs.h ======== + * Purpose: + * Global MEM constants and types, shared between WSX, WCD, and WMD. + * + *! Revision History: + *! ================ + *! 28-Aug-2001 ag: Added MEM_[SET][GET]VIRTUALSEGID. + *! 10-Aug-1999 kc: Based on wsx-c18. + *! 15-Nov-1996 gp: Renamed from wsxmem.h and moved to kwinos. + *! 21-Aug-1996 cr: Created from mem.h. + */ + +#ifndef MEMDEFS_ +#define MEMDEFS_ + +/* Memory Pool Attributes: */ + enum MEM_POOLATTRS { + MEM_PAGED = 0, + MEM_NONPAGED = 1, + MEM_LARGEVIRTMEM = 2 + } ; + +/* + * MEM_VIRTUALSEGID is used by Node & Strm to access virtual address space in + * the correct client process context. + */ +#define MEM_SETVIRTUALSEGID 0x10000000 +#define MEM_GETVIRTUALSEGID 0x20000000 +#define MEM_MASKVIRTUALSEGID (MEM_SETVIRTUALSEGID | MEM_GETVIRTUALSEGID) + +#define TO_VIRTUAL_UNCACHED(x) x +#define INTREG_TO_VIRTUAL_UNCACHED(x) x + +#endif /* MEMDEFS_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/mgr.h b/arch/arm/plat-omap/include/dspbridge/mgr.h new file mode 100644 index 0000000..24c4472 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/mgr.h @@ -0,0 +1,234 @@ +/* + * mgr.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== mgr.h ======== + * Description: + * This is the Class driver RM module interface. + * + * Public Functions: + * MGR_Create + * MGR_Destroy + * MGR_EnumNodeInfo + * MGR_EnumProcessorInfo + * MGR_Exit + * MGR_GetDCDHandle + * MGR_Init + * + * Notes: + * + *! Revision History: + *! ================ + *! 15-Oct-2002 kc: Removed legacy PERF definitions. + *! 11-Jul-2001 jeh Added CFG_HDEVNODE parameter to MGR_Create(). + *! 22-Nov-2000 kc: Added MGR_GetPerfData for acquiring PERF stats. + *! 03-Nov-2000 rr: Added MGR_GetDCDHandle. Modified after code review. + *! 25-Sep-2000 rr: Updated to Version 0.9 + *! 14-Aug-2000 rr: Cleaned up. + *! 07-Aug-2000 rr: MGR_Create does the job of Loading DCD Dll. + *! 27-Jul-2000 rr: Updated to ver 0.8 of DSPAPI(types). + *! 20-Jun-2000 rr: Created. + */ + +#ifndef MGR_ +#define MGR_ + +#include + +#define MAX_EVENTS 32 + +/* + * ======== MGR_WaitForBridgeEvents ======== + * Purpose: + * Block on any Bridge event(s) + * Parameters: + * aNotifications : array of pointers to notification objects. + * uCount : number of elements in above array + * puIndex : index of signaled event object + * uTimeout : timeout interval in milliseocnds + * Returns: + * DSP_SOK : Success. + * DSP_ETIMEOUT : Wait timed out. *puIndex is undetermined. + * Details: + */ + + DSP_STATUS MGR_WaitForBridgeEvents(struct DSP_NOTIFICATION + **aNotifications, + u32 uCount, OUT u32 *puIndex, + u32 uTimeout); + +/* + * ======== MGR_Create ======== + * Purpose: + * Creates the Manager Object. This is done during the driver loading. + * There is only one Manager Object in the DSP/BIOS Bridge. + * Parameters: + * phMgrObject: Location to store created MGR Object handle. + * hDevNode: Device object as known to Windows system. + * Returns: + * DSP_SOK: Success + * DSP_EMEMORY: Failed to Create the Object + * DSP_EFAIL: General Failure + * Requires: + * MGR Initialized (cRefs > 0 ) + * phMgrObject != NULL. + * Ensures: + * DSP_SOK: *phMgrObject is a valid MGR interface to the device. + * MGR Object stores the DCD Manager Handle. + * MGR Object stored in the Regsitry. + * !DSP_SOK: MGR Object not created + * Details: + * DCD Dll is loaded and MGR Object stores the handle of the DLL. + */ + extern DSP_STATUS MGR_Create(OUT struct MGR_OBJECT **hMgrObject, + struct CFG_DEVNODE *hDevNode); + +/* + * ======== MGR_Destroy ======== + * Purpose: + * Destroys the MGR object. Called upon driver unloading. + * Parameters: + * hMgrObject: Handle to Manager object . + * Returns: + * DSP_SOK: Success. + * DCD Manager freed; MGR Object destroyed; + * MGR Object deleted from the Registry. + * DSP_EFAIL: Failed to destroy MGR Object + * Requires: + * MGR Initialized (cRefs > 0 ) + * hMgrObject is a valid MGR handle . + * Ensures: + * DSP_SOK: MGR Object destroyed and hMgrObject is Invalid MGR + * Handle. + */ + extern DSP_STATUS MGR_Destroy(struct MGR_OBJECT *hMgrObject); + +/* + * ======== MGR_EnumNodeInfo ======== + * Purpose: + * Enumerate and get configuration information about nodes configured + * in the node database. + * Parameters: + * uNode: The node index (base 0). + * pNDBProps: Ptr to the DSP_NDBPROPS structure for output. + * uNDBPropsSize: Size of the DSP_NDBPROPS structure. + * puNumNodes: Location where the number of nodes configured + * in the database will be returned. + * Returns: + * DSP_SOK: Success. + * DSP_EINVALIDARG: Parameter uNode is > than the number of nodes. + * configutred in the system + * DSP_ECHANGEDURINGENUM: During Enumeration there has been a change in + * the number of nodes configured or in the + * the properties of the enumerated nodes. + * DSP_EFAIL: Failed to querry the Node Data Base + * Requires: + * pNDBPROPS is not null + * uNDBPropsSize >= sizeof(DSP_NDBPROPS) + * puNumNodes is not null + * MGR Initialized (cRefs > 0 ) + * Ensures: + * SUCCESS on successful retreival of data and *puNumNodes > 0 OR + * DSP_FAILED && *puNumNodes == 0. + * Details: + */ + extern DSP_STATUS MGR_EnumNodeInfo(u32 uNode, + OUT struct DSP_NDBPROPS *pNDBProps, + u32 uNDBPropsSize, + OUT u32 *puNumNodes); + +/* + * ======== MGR_EnumProcessorInfo ======== + * Purpose: + * Enumerate and get configuration information about available DSP + * processors + * Parameters: + * uProcessor: The processor index (zero-based). + * pProcessorInfo: Ptr to the DSP_PROCESSORINFO structure . + * uProcessorInfoSize: Size of DSP_PROCESSORINFO structure. + * puNumProcs: Location where the number of DSPs configured + * in the database will be returned + * Returns: + * DSP_SOK: Success. + * DSP_EINVALIDARG: Parameter uProcessor is > than the number of + * DSP Processors in the system. + * DSP_EFAIL: Failed to querry the Node Data Base + * Requires: + * pProcessorInfo is not null + * puNumProcs is not null + * uProcessorInfoSize >= sizeof(DSP_PROCESSORINFO) + * MGR Initialized (cRefs > 0 ) + * Ensures: + * SUCCESS on successful retreival of data and *puNumProcs > 0 OR + * DSP_FAILED && *puNumProcs == 0. + * Details: + */ + extern DSP_STATUS MGR_EnumProcessorInfo(u32 uProcessor, + OUT struct DSP_PROCESSORINFO * + pProcessorInfo, + u32 uProcessorInfoSize, + OUT u32 *puNumProcs); +/* + * ======== MGR_Exit ======== + * Purpose: + * Decrement reference count, and free resources when reference count is + * 0. + * Parameters: + * Returns: + * Requires: + * MGR is initialized. + * Ensures: + * When reference count == 0, MGR's private resources are freed. + */ + extern void MGR_Exit(void); + +/* + * ======== MGR_GetDCDHandle ======== + * Purpose: + * Retrieves the MGR handle. Accessor Function + * Parameters: + * hMGRHandle: Handle to the Manager Object + * phDCDHandle: Ptr to receive the DCD Handle. + * Returns: + * DSP_SOK: Sucess + * DSP_EFAIL: Failure to get the Handle + * Requires: + * MGR is initialized. + * phDCDHandle != NULL + * Ensures: + * DSP_SOK and *phDCDHandle != NULL || + * DSP_EFAIL and *phDCDHandle == NULL + */ + extern DSP_STATUS MGR_GetDCDHandle(IN struct MGR_OBJECT + *hMGRHandle, + OUT u32 *phDCDHandle); + +/* + * ======== MGR_Init ======== + * Purpose: + * Initialize MGR's private state, keeping a reference count on each + * call. Intializes the DCD. + * Parameters: + * Returns: + * TRUE if initialized; FALSE if error occured. + * Requires: + * Ensures: + * TRUE: A requirement for the other public MGR functions. + */ + extern bool MGR_Init(void); + +#endif /* MGR_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/mgrpriv.h b/arch/arm/plat-omap/include/dspbridge/mgrpriv.h new file mode 100644 index 0000000..4a34086 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/mgrpriv.h @@ -0,0 +1,55 @@ +/* + * mgrpriv.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== mgrpriv.h ======== + * Description: + * Global MGR constants and types, shared by PROC, MGR, and WCD. + * + *! Revision History: + *! ================ + *! 29-July-2001 ag: added MGR_PROCESSOREXTINFO. + *! 05-July-2000 rr: Created + */ + +#ifndef MGRPRIV_ +#define MGRPRIV_ + +/* + * OMAP1510 specific + */ +#define MGR_MAXTLBENTRIES 32 + +/* RM MGR Object */ + struct MGR_OBJECT; + + struct MGR_TLBENTRY { + u32 ulDspVirt; /* DSP virtual address */ + u32 ulGppPhys; /* GPP physical address */ + } ; + +/* + * The DSP_PROCESSOREXTINFO structure describes additional extended + * capabilities of a DSP processor not exposed to user. + */ + struct MGR_PROCESSOREXTINFO { + struct DSP_PROCESSORINFO tyBasic; /* user processor info */ + /* private dsp mmu entries */ + struct MGR_TLBENTRY tyTlb[MGR_MAXTLBENTRIES]; + } ; + +#endif /* MGRPRIV_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/msg.h b/arch/arm/plat-omap/include/dspbridge/msg.h new file mode 100644 index 0000000..f2872cc --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/msg.h @@ -0,0 +1,106 @@ +/* + * msg.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== msg.h ======== + * Description: + * DSP/BIOS Bridge MSG Module. + * + * Public Functions: + * MSG_Create + * MSG_Delete + * MSG_Exit + * MSG_Init + * + * Notes: + * + *! Revision History: + *! ================= + *! 17-Nov-2000 jeh Removed MSG_Get, MSG_Put, MSG_CreateQueue, + *! MSG_DeleteQueue, and MSG_RegisterNotify, since these + *! are now part of mini-driver. + *! 12-Sep-2000 jeh Created. + */ + +#ifndef MSG_ +#define MSG_ + +#include +#include + +/* + * ======== MSG_Create ======== + * Purpose: + * Create an object to manage message queues. Only one of these objects + * can exist per device object. The MSG manager must be created before + * the IO Manager. + * Parameters: + * phMsgMgr: Location to store MSG manager handle on output. + * hDevObject: The device object. + * msgCallback: Called whenever an RMS_EXIT message is received. + * Returns: + * Requires: + * MSG_Init(void) called. + * phMsgMgr != NULL. + * hDevObject != NULL. + * msgCallback != NULL. + * Ensures: + */ + extern DSP_STATUS MSG_Create(OUT struct MSG_MGR **phMsgMgr, + struct DEV_OBJECT *hDevObject, + MSG_ONEXIT msgCallback); + +/* + * ======== MSG_Delete ======== + * Purpose: + * Delete a MSG manager allocated in MSG_Create(). + * Parameters: + * hMsgMgr: Handle returned from MSG_Create(). + * Returns: + * Requires: + * MSG_Init(void) called. + * Valid hMsgMgr. + * Ensures: + */ + extern void MSG_Delete(struct MSG_MGR *hMsgMgr); + +/* + * ======== MSG_Exit ======== + * Purpose: + * Discontinue usage of MSG module. + * Parameters: + * Returns: + * Requires: + * MSG_Init(void) successfully called before. + * Ensures: + * Any resources acquired in MSG_Init(void) will be freed when last MSG + * client calls MSG_Exit(void). + */ + extern void MSG_Exit(void); + +/* + * ======== MSG_Init ======== + * Purpose: + * Initialize the MSG module. + * Parameters: + * Returns: + * TRUE if initialization succeeded, FALSE otherwise. + * Ensures: + */ + extern bool MSG_Init(void); + +#endif /* MSG_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/msgdefs.h b/arch/arm/plat-omap/include/dspbridge/msgdefs.h new file mode 100644 index 0000000..8ea4551 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/msgdefs.h @@ -0,0 +1,43 @@ +/* + * msgdefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== msgdefs.h ======== + * Description: + * Global MSG constants and types. + * + *! Revision History + *! ================ + *! 09-May-2001 jeh Removed MSG_TODSP, MSG_FROMDSP. + *! 17-Nov-2000 jeh Added MSGMGR_SIGNATURE. + *! 12-Sep-2000 jeh Created. + */ + +#ifndef MSGDEFS_ +#define MSGDEFS_ + +#define MSGMGR_SIGNATURE 0x4d47534d /* "MGSM" */ + +/* MSG Objects: */ + struct MSG_MGR; + struct MSG_QUEUE; + +/* Function prototype for callback to be called on RMS_EXIT message received */ + typedef void(*MSG_ONEXIT) (HANDLE h, s32 nStatus); + +#endif /* MSGDEFS_ */ + diff --git a/arch/arm/plat-omap/include/dspbridge/nldr.h b/arch/arm/plat-omap/include/dspbridge/nldr.h new file mode 100644 index 0000000..0915846 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/nldr.h @@ -0,0 +1,81 @@ +/* + * nldr.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== nldr.h ======== + * + * Description: + * DSP/BIOS Bridge dynamic loader interface. See the file dldrdefs.h + * for a description of these functions. + * + * Public Functions: + * NLDR_Allocate + * NLDR_Create + * NLDR_Delete + * NLDR_Exit + * NLDR_Free + * NLDR_GetFxnAddr + * NLDR_Init + * NLDR_Load + * NLDR_Unload + * + * Notes: + * + *! Revision History + *! ================ + *! 31-Jul-2002 jeh Removed function header comments. + *! 17-Apr-2002 jeh Created. + */ + +#include +#include +#include +#include +#include + +#ifndef NLDR_ +#define NLDR_ + + extern DSP_STATUS NLDR_Allocate(struct NLDR_OBJECT *hNldr, + void *pPrivRef, + IN CONST struct DCD_NODEPROPS + *pNodeProps, + OUT struct NLDR_NODEOBJECT **phNldrNode, + IN bool *pfPhaseSplit); + + extern DSP_STATUS NLDR_Create(OUT struct NLDR_OBJECT **phNldr, + struct DEV_OBJECT *hDevObject, + IN CONST struct NLDR_ATTRS *pAttrs); + + extern void NLDR_Delete(struct NLDR_OBJECT *hNldr); + extern void NLDR_Exit(void); + extern void NLDR_Free(struct NLDR_NODEOBJECT *hNldrNode); + + extern DSP_STATUS NLDR_GetFxnAddr(struct NLDR_NODEOBJECT *hNldrNode, + char *pstrFxn, u32 *pulAddr); + + extern DSP_STATUS NLDR_GetRmmManager(struct NLDR_OBJECT *hNldrObject, + OUT struct RMM_TargetObj + **phRmmMgr); + + extern bool NLDR_Init(void); + extern DSP_STATUS NLDR_Load(struct NLDR_NODEOBJECT *hNldrNode, + enum NLDR_PHASE phase); + extern DSP_STATUS NLDR_Unload(struct NLDR_NODEOBJECT *hNldrNode, + enum NLDR_PHASE phase); + +#endif /* NLDR_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/nldrdefs.h b/arch/arm/plat-omap/include/dspbridge/nldrdefs.h new file mode 100644 index 0000000..84b36a3 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/nldrdefs.h @@ -0,0 +1,307 @@ +/* + * nldrdefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== nldrdefs.h ======== + * Description: + * Global Dynamic + static/overlay Node loader (NLDR) constants and types. + * + *! Revision History + *! ================ + *! 07-Apr-2003 map Consolidated dldrdefs.h into nldrdefs.h + *! 05-Aug-2002 jeh Created. + */ + +#ifndef NLDRDEFS_ +#define NLDRDEFS_ + +#include +#include + +#define NLDR_MAXPATHLENGTH 255 +/* NLDR Objects: */ + struct NLDR_OBJECT; + struct NLDR_NODEOBJECT; + +/* + * ======== NLDR_LOADTYPE ======== + * Load types for a node. Must match values in node.h55. + */ + enum NLDR_LOADTYPE { + NLDR_STATICLOAD, /* Linked in base image, not overlay */ + NLDR_DYNAMICLOAD, /* Dynamically loaded node */ + NLDR_OVLYLOAD /* Linked in base image, overlay node */ + } ; + +/* + * ======== NLDR_OVLYFXN ======== + * Causes code or data to be copied from load address to run address. This + * is the "COD_WRITEFXN" that gets passed to the DBLL_Library and is used as + * the ZL write function. + * + * Parameters: + * pPrivRef: Handle to identify the node. + * ulDspRunAddr: Run address of code or data. + * ulDspLoadAddr: Load address of code or data. + * ulNumBytes: Number of (GPP) bytes to copy. + * nMemSpace: RMS_CODE or RMS_DATA. + * Returns: + * ulNumBytes: Success. + * 0: Failure. + * Requires: + * Ensures: + */ + typedef u32(*NLDR_OVLYFXN) (void *pPrivRef, u32 ulDspRunAddr, + u32 ulDspLoadAddr, + u32 ulNumBytes, u32 nMemSpace); + +/* + * ======== NLDR_WRITEFXN ======== + * Write memory function. Used for dynamic load writes. + * Parameters: + * pPrivRef: Handle to identify the node. + * ulDspAddr: Address of code or data. + * pBuf: Code or data to be written + * ulNumBytes: Number of (GPP) bytes to write. + * nMemSpace: DBLL_DATA or DBLL_CODE. + * Returns: + * ulNumBytes: Success. + * 0: Failure. + * Requires: + * Ensures: + */ + typedef u32(*NLDR_WRITEFXN) (void *pPrivRef, + u32 ulDspAddr, void *pBuf, + u32 ulNumBytes, u32 nMemSpace); + +/* + * ======== NLDR_ATTRS ======== + * Attributes passed to NLDR_Create function. + */ + struct NLDR_ATTRS { + NLDR_OVLYFXN pfnOvly; + NLDR_WRITEFXN pfnWrite; + u16 usDSPWordSize; + u16 usDSPMauSize; + } ; + +/* + * ======== NLDR_PHASE ======== + * Indicates node create, delete, or execute phase function. + */ + enum NLDR_PHASE { + NLDR_CREATE, + NLDR_DELETE, + NLDR_EXECUTE, + NLDR_NOPHASE + } ; + +/* + * Typedefs of loader functions imported from a DLL, or defined in a + * function table. + */ + +/* + * ======== NLDR_Allocate ======== + * Allocate resources to manage the loading of a node on the DSP. + * + * Parameters: + * hNldr: Handle of loader that will load the node. + * pPrivRef: Handle to identify the node. + * pNodeProps: Pointer to a DCD_NODEPROPS for the node. + * phNldrNode: Location to store node handle on output. This handle + * will be passed to NLDR_Load/NLDR_Unload. + * pfPhaseSplit: pointer to boolean variable referenced in node.c + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Insufficient memory on GPP. + * Requires: + * NLDR_Init(void) called. + * Valid hNldr. + * pNodeProps != NULL. + * phNldrNode != NULL. + * Ensures: + * DSP_SOK: IsValidNode(*phNldrNode). + * error: *phNldrNode == NULL. + */ + typedef DSP_STATUS(*NLDR_ALLOCATEFXN) (struct NLDR_OBJECT *hNldr, + void *pPrivRef, + IN CONST struct DCD_NODEPROPS + *pNodeProps, + OUT struct NLDR_NODEOBJECT + **phNldrNode, + OUT bool *pfPhaseSplit); + +/* + * ======== NLDR_Create ======== + * Create a loader object. This object handles the loading and unloading of + * create, delete, and execute phase functions of nodes on the DSP target. + * + * Parameters: + * phNldr: Location to store loader handle on output. + * hDevObject: Device for this processor. + * pAttrs: Loader attributes. + * Returns: + * DSP_SOK: Success; + * DSP_EMEMORY: Insufficient memory for requested resources. + * Requires: + * NLDR_Init(void) called. + * phNldr != NULL. + * hDevObject != NULL. + * pAttrs != NULL. + * Ensures: + * DSP_SOK: Valid *phNldr. + * error: *phNldr == NULL. + */ + typedef DSP_STATUS(*NLDR_CREATEFXN) (OUT struct NLDR_OBJECT **phNldr, + struct DEV_OBJECT *hDevObject, + IN CONST struct NLDR_ATTRS + *pAttrs); + +/* + * ======== NLDR_Delete ======== + * Delete the NLDR loader. + * + * Parameters: + * hNldr: Node manager object. + * Returns: + * Requires: + * NLDR_Init(void) called. + * Valid hNldr. + * Ensures: + * hNldr invalid + */ + typedef void(*NLDR_DELETEFXN) (struct NLDR_OBJECT *hNldr); + +/* + * ======== NLDR_Exit ======== + * Discontinue usage of NLDR module. + * + * Parameters: + * Returns: + * Requires: + * NLDR_Init(void) successfully called before. + * Ensures: + * Any resources acquired in NLDR_Init(void) will be freed when last NLDR + * client calls NLDR_Exit(void). + */ + typedef void(*NLDR_EXITFXN) (void); + +/* + * ======== NLDR_Free ======== + * Free resources allocated in NLDR_Allocate. + * + * Parameters: + * hNldrNode: Handle returned from NLDR_Allocate(). + * Returns: + * Requires: + * NLDR_Init(void) called. + * Valid hNldrNode. + * Ensures: + */ + typedef void(*NLDR_FREEFXN) (struct NLDR_NODEOBJECT *hNldrNode); + +/* + * ======== NLDR_GetFxnAddr ======== + * Get address of create, delete, or execute phase function of a node on + * the DSP. + * + * Parameters: + * hNldrNode: Handle returned from NLDR_Allocate(). + * pstrFxn: Name of function. + * pulAddr: Location to store function address. + * Returns: + * DSP_SOK: Success. + * DSP_ESYMBOL: Address of function not found. + * Requires: + * NLDR_Init(void) called. + * Valid hNldrNode. + * pulAddr != NULL; + * pstrFxn != NULL; + * Ensures: + */ + typedef DSP_STATUS(*NLDR_GETFXNADDRFXN) (struct NLDR_NODEOBJECT + *hNldrNode, + char *pstrFxn, u32 *pulAddr); + +/* + * ======== NLDR_Init ======== + * Initialize the NLDR module. + * + * Parameters: + * Returns: + * TRUE if initialization succeeded, FALSE otherwise. + * Ensures: + */ + typedef bool(*NLDR_INITFXN) (void); + +/* + * ======== NLDR_Load ======== + * Load create, delete, or execute phase function of a node on the DSP. + * + * Parameters: + * hNldrNode: Handle returned from NLDR_Allocate(). + * phase: Type of function to load (create, delete, or execute). + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Insufficient memory on GPP. + * DSP_EOVERLAYMEMORY: Can't overlay phase because overlay memory + * is already in use. + * DSP_EDYNLOAD: Failure in dynamic loader library. + * DSP_EFWRITE: Failed to write phase's code or date to target. + * Requires: + * NLDR_Init(void) called. + * Valid hNldrNode. + * Ensures: + */ + typedef DSP_STATUS(*NLDR_LOADFXN) (struct NLDR_NODEOBJECT *hNldrNode, + enum NLDR_PHASE phase); + +/* + * ======== NLDR_Unload ======== + * Unload create, delete, or execute phase function of a node on the DSP. + * + * Parameters: + * hNldrNode: Handle returned from NLDR_Allocate(). + * phase: Node function to unload (create, delete, or execute). + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Insufficient memory on GPP. + * Requires: + * NLDR_Init(void) called. + * Valid hNldrNode. + * Ensures: + */ + typedef DSP_STATUS(*NLDR_UNLOADFXN) (struct NLDR_NODEOBJECT *hNldrNode, + enum NLDR_PHASE phase); + +/* + * ======== NLDR_FXNS ======== + */ + struct NLDR_FXNS { + NLDR_ALLOCATEFXN pfnAllocate; + NLDR_CREATEFXN pfnCreate; + NLDR_DELETEFXN pfnDelete; + NLDR_EXITFXN pfnExit; + NLDR_FREEFXN pfnFree; + NLDR_GETFXNADDRFXN pfnGetFxnAddr; + NLDR_INITFXN pfnInit; + NLDR_LOADFXN pfnLoad; + NLDR_UNLOADFXN pfnUnload; + } ; + +#endif /* NLDRDEFS_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/node.h b/arch/arm/plat-omap/include/dspbridge/node.h new file mode 100644 index 0000000..d253962 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/node.h @@ -0,0 +1,619 @@ +/* + * node.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== node.h ======== + * Description: + * DSP/BIOS Bridge Node Manager. + * + * Public Functions: + * NODE_Allocate + * NODE_AllocMsgBuf + * NODE_ChangePriority + * NODE_Connect + * NODE_Create + * NODE_CreateMgr + * NODE_Delete + * NODE_DeleteMgr + * NODE_EnumNodes + * NODE_Exit + * NODE_FreeMsgBuf + * NODE_GetAttr + * NODE_GetMessage + * NODE_GetProcessor + * NODE_Init + * NODE_OnExit + * NODE_Pause + * NODE_PutMessage + * NODE_RegisterNotify + * NODE_Run + * NODE_Terminate + * + * Notes: + * + *! Revision History: + *! ================= + *! 23-Apr-2001 jeh Updated with code review changes. + *! 16-Jan-2001 jeh Added DSP_ESYMBOL, DSP_EUUID to return codes. + *! 17-Nov-2000 jeh Added NODE_OnExit(). + *! 27-Oct-2000 jeh Added timeouts to NODE_GetMessage, NODE_PutMessage. + *! 12-Oct-2000 jeh Changed NODE_EnumNodeInfo to NODE_EnumNodes. Removed + *! NODE_RegisterAllNodes(). + *! 07-Sep-2000 jeh Changed type HANDLE in NODE_RegisterNotify to + *! DSP_HNOTIFICATION. Added DSP_STRMATTR param to + *! NODE_Connect(). Removed NODE_GetMessageStream(). + *! 17-Jul-2000 jeh Updated function header descriptions. + *! 19-Jun-2000 jeh Created. + */ + +#ifndef NODE_ +#define NODE_ + +#include + +#include +#include +#include + +/* + * ======== NODE_Allocate ======== + * Purpose: + * Allocate GPP resources to manage a node on the DSP. + * Parameters: + * hProcessor: Handle of processor that is allocating the node. + * pNodeId: Pointer to a DSP_UUID for the node. + * pArgs: Optional arguments to be passed to the node. + * pAttrIn: Optional pointer to node attributes (priority, + * timeout...) + * phNode: Location to store node handle on output. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Insufficient memory on GPP. + * DSP_EUUID: Node UUID has not been registered. + * DSP_ESYMBOL: iAlg functions not found for a DAIS node. + * DSP_ERANGE: pAttrIn != NULL and pAttrIn->iPriority out of + * range. + * DSP_EFAIL: A failure occured, unable to allocate node. + * DSP_EWRONGSTATE: Proccessor is not in the running state. + * Requires: + * NODE_Init(void) called. + * hProcessor != NULL. + * pNodeId != NULL. + * phNode != NULL. + * Ensures: + * DSP_SOK: IsValidNode(*phNode). + * error: *phNode == NULL. + */ + extern DSP_STATUS NODE_Allocate(struct PROC_OBJECT *hProcessor, + IN CONST struct DSP_UUID *pNodeId, + OPTIONAL IN CONST struct DSP_CBDATA + *pArgs, + OPTIONAL IN CONST struct DSP_NODEATTRIN + *pAttrIn, + OUT struct NODE_OBJECT **phNode); + +/* + * ======== NODE_AllocMsgBuf ======== + * Purpose: + * Allocate and Prepare a buffer whose descriptor will be passed to a + * Node within a (DSP_MSG)message + * Parameters: + * hNode: The node handle. + * uSize: The size of the buffer to be allocated. + * pAttr: Pointer to a DSP_BUFFERATTR structure. + * pBuffer: Location to store the address of the allocated + * buffer on output. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid node handle. + * DSP_EMEMORY: Insufficent memory. + * DSP_EFAIL: General Failure. + * DSP_ESIZE: Invalid Size. + * Requires: + * NODE_Init(void) called. + * pBuffer != NULL. + * Ensures: + */ + extern DSP_STATUS NODE_AllocMsgBuf(struct NODE_OBJECT *hNode, + u32 uSize, + OPTIONAL struct DSP_BUFFERATTR + *pAttr, + OUT u8 **pBuffer); + +/* + * ======== NODE_ChangePriority ======== + * Purpose: + * Change the priority of an allocated node. + * Parameters: + * hNode: Node handle returned from NODE_Allocate. + * nPriority: New priority level to set node's priority to. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hNode. + * DSP_ERANGE: nPriority is out of range. + * DSP_ENODETYPE: The specified node is not a task node. + * DSP_EWRONGSTATE: Node is not in the NODE_ALLOCATED, NODE_PAUSED, + * or NODE_RUNNING state. + * DSP_ETIMEOUT: A timeout occurred before the DSP responded. + * DSP_ERESTART: A critical error has occurred and the DSP is + * being restarted. + * DSP_EFAIL: Unable to change node's runtime priority level. + * Requires: + * NODE_Init(void) called. + * Ensures: + * DSP_SOK && (Node's current priority == nPriority) + */ + extern DSP_STATUS NODE_ChangePriority(struct NODE_OBJECT *hNode, + s32 nPriority); + +/* + * ======== NODE_CloseOrphans ======== + * Purpose: + * Delete all nodes whose owning processor is being destroyed. + * Parameters: + * hNodeMgr: Node manager object. + * hProc: Handle to processor object being destroyed. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Unable to delete all nodes belonging to hProc. + * Requires: + * Valid hNodeMgr. + * hProc != NULL. + * Ensures: + */ + extern DSP_STATUS NODE_CloseOrphans(struct NODE_MGR *hNodeMgr, + struct PROC_OBJECT *hProc); + +/* + * ======== NODE_Connect ======== + * Purpose: + * Connect two nodes on the DSP, or a node on the DSP to the GPP. In the + * case that the connnection is being made between a node on the DSP and + * the GPP, one of the node handles (either hNode1 or hNode2) must be + * the constant NODE_HGPPNODE. + * Parameters: + * hNode1: Handle of first node to connect to second node. If + * this is a connection from the GPP to hNode2, hNode1 + * must be the constant NODE_HGPPNODE. Otherwise, hNode1 + * must be a node handle returned from a successful call + * to Node_Allocate(). + * hNode2: Handle of second node. Must be either NODE_HGPPNODE + * if this is a connection from DSP node to GPP, or a + * node handle returned from a successful call to + * NODE_Allocate(). + * uStream1: Output stream index on first node, to be connected + * to second node's input stream. Value must range from + * 0 <= uStream1 < number of output streams. + * uStream2: Input stream index on second node. Value must range + * from 0 <= uStream2 < number of input streams. + * pAttrs: Stream attributes (NULL ==> use defaults). + * pConnParam: A pointer to a DSP_CBDATA structure that defines + * connection parameter for device nodes to pass to DSP + * side. + * If the value of this parameter is NULL, then this API + * behaves like DSPNode_Connect. This parameter will have + * length of the string and the null terminated string in + * DSP_CBDATA struct. This can be extended in future tp + * pass binary data. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hNode1 or hNode2. + * DSP_EMEMORY: Insufficient host memory. + * DSP_EVALUE: A stream index parameter is invalid. + * DSP_EALREADYCONNECTED: A connection already exists for one of the + * indices uStream1 or uStream2. + * DSP_EWRONGSTATE: Either hNode1 or hNode2 is not in the + * NODE_ALLOCATED state. + * DSP_ENOMORECONNECTIONS: No more connections available. + * DSP_EFAIL: Attempt to make an illegal connection (eg, + * Device node to device node, or device node to + * GPP), the two nodes are on different DSPs. + * Requires: + * NODE_Init(void) called. + * Ensures: + */ + extern DSP_STATUS NODE_Connect(struct NODE_OBJECT *hNode1, + u32 uStream1, + struct NODE_OBJECT *hNode2, + u32 uStream2, + OPTIONAL IN struct DSP_STRMATTR *pAttrs, + OPTIONAL IN struct DSP_CBDATA + *pConnParam); + +/* + * ======== NODE_Create ======== + * Purpose: + * Create a node on the DSP by remotely calling the node's create + * function. If necessary, load code that contains the node's create + * function. + * Parameters: + * hNode: Node handle returned from NODE_Allocate(). + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hNode. + * DSP_ESYMBOL: Create function not found in the COFF file. + * DSP_EWRONGSTATE: Node is not in the NODE_ALLOCATED state. + * DSP_EMEMORY: Memory allocation failure on the DSP. + * DSP_ETASK: Unable to create node's task or process on the DSP. + * DSP_ESTREAM: Stream creation failure on the DSP. + * DSP_ETIMEOUT: A timeout occurred before the DSP responded. + * DSP_EUSER1-16: A user-defined failure occurred on the DSP. + * DSP_EFAIL: A failure occurred, unable to create node. + * Requires: + * NODE_Init(void) called. + * Ensures: + */ + extern DSP_STATUS NODE_Create(struct NODE_OBJECT *hNode); + +/* + * ======== NODE_CreateMgr ======== + * Purpose: + * Create a NODE Manager object. This object handles the creation, + * deletion, and execution of nodes on the DSP target. The NODE Manager + * also maintains a pipe map of used and available node connections. + * Each DEV object should have exactly one NODE Manager object. + * + * Parameters: + * phNodeMgr: Location to store node manager handle on output. + * hDevObject: Device for this processor. + * Returns: + * DSP_SOK: Success; + * DSP_EMEMORY: Insufficient memory for requested resources. + * DSP_EFAIL: General failure. + * Requires: + * NODE_Init(void) called. + * phNodeMgr != NULL. + * hDevObject != NULL. + * Ensures: + * DSP_SOK: Valide *phNodeMgr. + * error: *phNodeMgr == NULL. + */ + extern DSP_STATUS NODE_CreateMgr(OUT struct NODE_MGR **phNodeMgr, + struct DEV_OBJECT *hDevObject); + +/* + * ======== NODE_Delete ======== + * Purpose: + * Delete resources allocated in NODE_Allocate(). If the node was + * created, delete the node on the DSP by remotely calling the node's + * delete function. Loads the node's delete function if necessary. + * GPP side resources are freed after node's delete function returns. + * Parameters: + * hNode: Node handle returned from NODE_Allocate(). + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hNode. + * DSP_ETIMEOUT: A timeout occurred before the DSP responded. + * DSP_EDELETE: A deletion failure occurred. + * DSP_EUSER1-16: Node specific failure occurred on the DSP. + * DSP_EFAIL: A failure occurred in deleting the node. + * DSP_ESYMBOL: Delete function not found in the COFF file. + * Requires: + * NODE_Init(void) called. + * Ensures: + * DSP_SOK: hNode is invalid. + */ + extern DSP_STATUS NODE_Delete(struct NODE_OBJECT *hNode); + +/* + * ======== NODE_DeleteMgr ======== + * Purpose: + * Delete the NODE Manager. + * Parameters: + * hNodeMgr: Node manager object. + * Returns: + * DSP_SOK: Success. + * Requires: + * NODE_Init(void) called. + * Valid hNodeMgr. + * Ensures: + */ + extern DSP_STATUS NODE_DeleteMgr(struct NODE_MGR *hNodeMgr); + +/* + * ======== NODE_EnumNodes ======== + * Purpose: + * Enumerate the nodes currently allocated for the DSP. + * Parameters: + * hNodeMgr: Node manager returned from NODE_CreateMgr(). + * aNodeTab: Array to copy node handles into. + * uNodeTabSize: Number of handles that can be written to aNodeTab. + * puNumNodes: Location where number of node handles written to + * aNodeTab will be written. + * puAllocated: Location to write total number of allocated nodes. + * Returns: + * DSP_SOK: Success. + * DSP_ESIZE: aNodeTab is too small to hold all node handles. + * Requires: + * Valid hNodeMgr. + * aNodeTab != NULL || uNodeTabSize == 0. + * puNumNodes != NULL. + * puAllocated != NULL. + * Ensures: + * - (DSP_ESIZE && *puNumNodes == 0) + * - || (DSP_SOK && *puNumNodes <= uNodeTabSize) && + * (*puAllocated == *puNumNodes) + */ + extern DSP_STATUS NODE_EnumNodes(struct NODE_MGR *hNodeMgr, + IN DSP_HNODE *aNodeTab, + u32 uNodeTabSize, + OUT u32 *puNumNodes, + OUT u32 *puAllocated); + +/* + * ======== NODE_Exit ======== + * Purpose: + * Discontinue usage of NODE module. + * Parameters: + * Returns: + * Requires: + * NODE_Init(void) successfully called before. + * Ensures: + * Any resources acquired in NODE_Init(void) will be freed when last NODE + * client calls NODE_Exit(void). + */ + extern void NODE_Exit(void); + +/* + * ======== NODE_FreeMsgBuf ======== + * Purpose: + * Free a message buffer previously allocated with NODE_AllocMsgBuf. + * Parameters: + * hNode: The node handle. + * pBuffer: (Address) Buffer allocated by NODE_AllocMsgBuf. + * pAttr: Same buffer attributes passed to NODE_AllocMsgBuf. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid node handle. + * DSP_EFAIL: Failure to free the buffer. + * Requires: + * NODE_Init(void) called. + * pBuffer != NULL. + * Ensures: + */ + extern DSP_STATUS NODE_FreeMsgBuf(struct NODE_OBJECT *hNode, + IN u8 *pBuffer, + OPTIONAL struct DSP_BUFFERATTR + *pAttr); + +/* + * ======== NODE_GetAttr ======== + * Purpose: + * Copy the current attributes of the specified node into a DSP_NODEATTR + * structure. + * Parameters: + * hNode: Node object allocated from NODE_Allocate(). + * pAttr: Pointer to DSP_NODEATTR structure to copy node's + * attributes. + * uAttrSize: Size of pAttr. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hNode. + * Requires: + * NODE_Init(void) called. + * pAttr != NULL. + * Ensures: + * DSP_SOK: *pAttrs contains the node's current attributes. + */ + extern DSP_STATUS NODE_GetAttr(struct NODE_OBJECT *hNode, + OUT struct DSP_NODEATTR *pAttr, + u32 uAttrSize); + +/* + * ======== NODE_GetMessage ======== + * Purpose: + * Retrieve a message from a node on the DSP. The node must be either a + * message node, task node, or XDAIS socket node. + * If a message is not available, this function will block until a + * message is available, or the node's timeout value is reached. + * Parameters: + * hNode: Node handle returned from NODE_Allocate(). + * pMessage: Pointer to DSP_MSG structure to copy the + * message into. + * uTimeout: Timeout in milliseconds to wait for message. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hNode. + * DSP_ENODETYPE: Cannot retrieve messages from this type of node. + * DSP_ETIMEOUT: Timeout occurred and no message is available. + * DSP_EFAIL: Error occurred while trying to retrieve a message. + * Requires: + * NODE_Init(void) called. + * pMessage != NULL. + * Ensures: + */ + extern DSP_STATUS NODE_GetMessage(struct NODE_OBJECT *hNode, + OUT struct DSP_MSG *pMessage, + u32 uTimeout); + +/* + * ======== NODE_GetNldrObj ======== + * Purpose: + * Retrieve the Nldr manager + * Parameters: + * hNodeMgr: Node Manager + * phNldrObj: Pointer to a Nldr manager handle + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hNode. + * Ensures: + */ + extern DSP_STATUS NODE_GetNldrObj(struct NODE_MGR *hNodeMgr, + OUT struct NLDR_OBJECT **phNldrObj); + +/* + * ======== NODE_Init ======== + * Purpose: + * Initialize the NODE module. + * Parameters: + * Returns: + * TRUE if initialization succeeded, FALSE otherwise. + * Ensures: + */ + extern bool NODE_Init(void); + +/* + * ======== NODE_OnExit ======== + * Purpose: + * Gets called when RMS_EXIT is received for a node. PROC needs to pass + * this function as a parameter to MSG_Create(). This function then gets + * called by the mini-driver when an exit message for a node is received. + * Parameters: + * hNode: Handle of the node that the exit message is for. + * nStatus: Return status of the node's execute phase. + * Returns: + * Ensures: + */ + void NODE_OnExit(struct NODE_OBJECT *hNode, s32 nStatus); + +/* + * ======== NODE_Pause ======== + * Purpose: + * Suspend execution of a node currently running on the DSP. + * Parameters: + * hNode: Node object representing a node currently + * running on the DSP. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hNode. + * DSP_ENODETYPE: Node is not a task or socket node. + * DSP_ETIMEOUT: A timeout occurred before the DSP responded. + * DSP_EWRONGSTSATE: Node is not in NODE_RUNNING state. + * DSP_EFAIL: Failed to pause node. + * Requires: + * NODE_Init(void) called. + * Ensures: + */ + extern DSP_STATUS NODE_Pause(struct NODE_OBJECT *hNode); + +/* + * ======== NODE_PutMessage ======== + * Purpose: + * Send a message to a message node, task node, or XDAIS socket node. + * This function will block until the message stream can accommodate + * the message, or a timeout occurs. The message will be copied, so Msg + * can be re-used immediately after return. + * Parameters: + * hNode: Node handle returned by NODE_Allocate(). + * pMsg: Location of message to be sent to the node. + * uTimeout: Timeout in msecs to wait. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hNode. + * DSP_ENODETYPE: Messages can't be sent to this type of node. + * DSP_ETIMEOUT: Timeout occurred before message could be set. + * DSP_EWRONGSTATE: Node is in invalid state for sending messages. + * DSP_EFAIL: Unable to send message. + * Requires: + * NODE_Init(void) called. + * pMsg != NULL. + * Ensures: + */ + extern DSP_STATUS NODE_PutMessage(struct NODE_OBJECT *hNode, + IN CONST struct DSP_MSG *pMsg, + u32 uTimeout); + +/* + * ======== NODE_RegisterNotify ======== + * Purpose: + * Register to be notified on specific events for this node. + * Parameters: + * hNode: Node handle returned by NODE_Allocate(). + * uEventMask: Mask of types of events to be notified about. + * uNotifyType: Type of notification to be sent. + * hNotification: Handle to be used for notification. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hNode. + * DSP_EMEMORY: Insufficient memory on GPP. + * DSP_EVALUE: uEventMask is invalid. + * DSP_ENOTIMPL: Notification type specified by uNotifyType is not + * supported. + * Requires: + * NODE_Init(void) called. + * hNotification != NULL. + * Ensures: + */ + extern DSP_STATUS NODE_RegisterNotify(struct NODE_OBJECT *hNode, + u32 uEventMask, u32 uNotifyType, + struct DSP_NOTIFICATION + *hNotification); + +/* + * ======== NODE_Run ======== + * Purpose: + * Start execution of a node's execute phase, or resume execution of + * a node that has been suspended (via NODE_Pause()) on the DSP. Load + * the node's execute function if necessary. + * Parameters: + * hNode: Node object representing a node currently + * running on the DSP. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hNode. + * DSP_ENODETYPE: hNode doesn't represent a message, task or dais + * socket node. + * DSP_ETIMEOUT: A timeout occurred before the DSP responded. + * DSP_EWRONGSTSATE: Node is not in NODE_PAUSED or NODE_CREATED state. + * DSP_EFAIL: Unable to start or resume execution. + * DSP_ESYMBOL: Execute function not found in the COFF file. + * Requires: + * NODE_Init(void) called. + * Ensures: + */ + extern DSP_STATUS NODE_Run(struct NODE_OBJECT *hNode); + +/* + * ======== NODE_Terminate ======== + * Purpose: + * Signal a node running on the DSP that it should exit its execute + * phase function. + * Parameters: + * hNode: Node object representing a node currently + * running on the DSP. + * pStatus: Location to store execute-phase function return + * value (DSP_EUSER1-16). + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hNode. + * DSP_ETIMEOUT: A timeout occurred before the DSP responded. + * DSP_ENODETYPE: Type of node specified cannot be terminated. + * DSP_EWRONGSTATE: Operation not valid for the current node state. + * DSP_EFAIL: Unable to terminate the node. + * Requires: + * NODE_Init(void) called. + * pStatus != NULL. + * Ensures: + */ + extern DSP_STATUS NODE_Terminate(struct NODE_OBJECT *hNode, + OUT DSP_STATUS *pStatus); + + + +/* + * ======== NODE_GetUUIDProps ======== + * Purpose: + * Fetch Node properties given the UUID + * Parameters: + * + */ + extern DSP_STATUS NODE_GetUUIDProps(DSP_HPROCESSOR hProcessor, + IN CONST struct DSP_UUID *pNodeId, + OUT struct DSP_NDBPROPS + *pNodeProps); + +#endif /* NODE_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/nodedefs.h b/arch/arm/plat-omap/include/dspbridge/nodedefs.h new file mode 100644 index 0000000..cdc0c4b --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/nodedefs.h @@ -0,0 +1,40 @@ +/* + * nodedefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== nodedefs.h ======== + * Description: + * Global NODE constants and types, shared by PROCESSOR, NODE, and DISP. + * + *! Revision History + *! ================ + *! 23-Apr-2001 jeh Removed NODE_MGRATTRS. + *! 21-Sep-2000 jeh Removed NODE_TYPE enum. + *! 17-Jul-2000 jeh Changed order of node types to match rms_sh.h. + *! 20-Jun-2000 jeh Created. + */ + +#ifndef NODEDEFS_ +#define NODEDEFS_ + +#define NODE_SUSPENDEDPRI -1 + +/* NODE Objects: */ + struct NODE_MGR; + struct NODE_OBJECT; + +#endif /* NODEDEFS_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/nodepriv.h b/arch/arm/plat-omap/include/dspbridge/nodepriv.h new file mode 100644 index 0000000..d28b29b --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/nodepriv.h @@ -0,0 +1,202 @@ +/* + * nodepriv.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== nodepriv.h ======== + * Description: + * Private node header shared by NODE and DISP. + * + * Public Functions: + * NODE_GetChannelId + * NODE_GetStrmMgr + * NODE_GetTimeout + * NODE_GetType + * NODE_GetLoadType + * + *! Revision History + *! ================ + *! 19-Nov-2002 map Added NODE_GetLoadType + *! 13-Feb-2002 jeh Added uSysStackSize to NODE_TASKARGS. + *! 23-Apr-2001 jeh Removed unused typedefs, defines. + *! 10-Oct-2000 jeh Added alignment to NODE_STRMDEF. + *! 20-Jun-2000 jeh Created. + */ + +#ifndef NODEPRIV_ +#define NODEPRIV_ + +#include +#include +#include + +/* DSP address of node environment structure */ + typedef u32 NODE_ENV; + +/* + * Node create structures + */ + +/* Message node */ + struct NODE_MSGARGS { + u32 uMaxMessages; /* Max # of simultaneous messages for node */ + u32 uSegid; /* Segment for allocating message buffers */ + u32 uNotifyType; /* Notify type (SEM_post, SWI_post, etc.) */ + u32 uArgLength; /* Length in 32-bit words of arg data block */ + u8 *pData; /* Argument data for node */ + } ; + + struct NODE_STRMDEF { + u32 uBufsize; /* Size of buffers for SIO stream */ + u32 uNumBufs; /* max # of buffers in SIO stream at once */ + u32 uSegid; /* Memory segment id to allocate buffers */ + u32 uTimeout; /* Timeout for blocking SIO calls */ + u32 uAlignment; /* Buffer alignment */ + char *szDevice; /* Device name for stream */ + } ; + +/* Task node */ + struct NODE_TASKARGS { + struct NODE_MSGARGS msgArgs; + s32 nPriority; + u32 uStackSize; + u32 uSysStackSize; + u32 uStackSeg; + u32 uDSPHeapResAddr; /* DSP virtual heap address */ + u32 uDSPHeapAddr; /* DSP virtual heap address */ + u32 uHeapSize; /* Heap size */ + u32 uGPPHeapAddr; /* GPP virtual heap address */ + u32 uProfileID; /* Profile ID */ + u32 uNumInputs; + u32 uNumOutputs; + u32 ulDaisArg; /* Address of iAlg object */ + struct NODE_STRMDEF *strmInDef; + struct NODE_STRMDEF *strmOutDef; + } ; + +/* + * ======== NODE_CREATEARGS ======== + */ + struct NODE_CREATEARGS { + union { + struct NODE_MSGARGS msgArgs; + struct NODE_TASKARGS taskArgs; + } asa; + } ; + +/* + * ======== NODE_GetChannelId ======== + * Purpose: + * Get the channel index reserved for a stream connection between the + * host and a node. This index is reserved when NODE_Connect() is called + * to connect the node with the host. This index should be passed to + * the CHNL_Open function when the stream is actually opened. + * Parameters: + * hNode: Node object allocated from NODE_Allocate(). + * uDir: Input (DSP_TONODE) or output (DSP_FROMNODE). + * uIndex: Stream index. + * pulId: Location to store channel index. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hNode. + * DSP_ENODETYPE: Not a task or DAIS socket node. + * DSP_EVALUE: The node's stream corresponding to uIndex and uDir + * is not a stream to or from the host. + * Requires: + * NODE_Init(void) called. + * Valid uDir. + * pulId != NULL. + * Ensures: + */ + extern DSP_STATUS NODE_GetChannelId(struct NODE_OBJECT *hNode, + u32 uDir, + u32 uIndex, OUT u32 *pulId); + +/* + * ======== NODE_GetStrmMgr ======== + * Purpose: + * Get the STRM manager for a node. + * Parameters: + * hNode: Node allocated with NODE_Allocate(). + * phStrmMgr: Location to store STRM manager on output. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hNode. + * Requires: + * phStrmMgr != NULL. + * Ensures: + */ + extern DSP_STATUS NODE_GetStrmMgr(struct NODE_OBJECT *hNode, + struct STRM_MGR **phStrmMgr); + +/* + * ======== NODE_GetTimeout ======== + * Purpose: + * Get the timeout value of a node. + * Parameters: + * hNode: Node allocated with NODE_Allocate(), or DSP_HGPPNODE. + * Returns: + * Node's timeout value. + * Requires: + * Valid hNode. + * Ensures: + */ + extern u32 NODE_GetTimeout(struct NODE_OBJECT *hNode); + +/* + * ======== NODE_GetType ======== + * Purpose: + * Get the type (device, message, task, or XDAIS socket) of a node. + * Parameters: + * hNode: Node allocated with NODE_Allocate(), or DSP_HGPPNODE. + * Returns: + * Node type: NODE_DEVICE, NODE_TASK, NODE_XDAIS, or NODE_GPP. + * Requires: + * Valid hNode. + * Ensures: + */ + extern enum NODE_TYPE NODE_GetType(struct NODE_OBJECT *hNode); + +/* + * ======== GetNodeInfo ======== + * Purpose: + * Get node information without holding semaphore. + * Parameters: + * hNode: Node allocated with NODE_Allocate(), or DSP_HGPPNODE. + * Returns: + * Node info: priority, device owner, no. of streams, execution state + * NDB properties. + * Requires: + * Valid hNode. + * Ensures: + */ + extern void GetNodeInfo(struct NODE_OBJECT *hNode, + struct DSP_NODEINFO *pNodeInfo); + +/* + * ======== NODE_GetLoadType ======== + * Purpose: + * Get the load type (dynamic, overlay, static) of a node. + * Parameters: + * hNode: Node allocated with NODE_Allocate(), or DSP_HGPPNODE. + * Returns: + * Node type: NLDR_DYNAMICLOAD, NLDR_OVLYLOAD, NLDR_STATICLOAD + * Requires: + * Valid hNode. + * Ensures: + */ + extern enum NLDR_LOADTYPE NODE_GetLoadType(struct NODE_OBJECT *hNode); + +#endif /* NODEPRIV_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/ntfy.h b/arch/arm/plat-omap/include/dspbridge/ntfy.h new file mode 100644 index 0000000..5a0992a --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/ntfy.h @@ -0,0 +1,146 @@ +/* + * ntfy.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== ntfy.h ======== + * Purpose: + * Manage lists of notification events. + * + * Public Functions: + * NTFY_Create + * NTFY_Delete + * NTFY_Exit + * NTFY_Init + * NTFY_Notify + * NTFY_Register + * + *! Revision History: + *! ================= + *! 05-Nov-2001 kc: Updated NTFY_Register. + *! 07-Sep-2000 jeh Created. + */ + +#ifndef NTFY_ +#define NTFY_ + + struct NTFY_OBJECT; + +/* + * ======== NTFY_Create ======== + * Purpose: + * Create an empty list of notifications. + * Parameters: + * phNtfy: Location to store handle on output. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Memory allocation failure. + * Requires: + * NTFY_Init(void) called. + * phNtfy != NULL. + * Ensures: + * DSP_SUCCEEDED(status) <==> IsValid(*phNtfy). + */ + extern DSP_STATUS NTFY_Create(OUT struct NTFY_OBJECT **phNtfy); + +/* + * ======== NTFY_Delete ======== + * Purpose: + * Free resources allocated in NTFY_Create. + * Parameters: + * hNtfy: Handle returned from NTFY_Create(). + * Returns: + * Requires: + * NTFY_Init(void) called. + * IsValid(hNtfy). + * Ensures: + */ + extern void NTFY_Delete(IN struct NTFY_OBJECT *hNtfy); + +/* + * ======== NTFY_Exit ======== + * Purpose: + * Discontinue usage of NTFY module. + * Parameters: + * Returns: + * Requires: + * NTFY_Init(void) successfully called before. + * Ensures: + */ + extern void NTFY_Exit(void); + +/* + * ======== NTFY_Init ======== + * Purpose: + * Initialize the NTFY module. + * Parameters: + * Returns: + * TRUE if initialization succeeded, FALSE otherwise. + * Ensures: + */ + extern bool NTFY_Init(void); + +/* + * ======== NTFY_Notify ======== + * Purpose: + * Execute notify function (signal event or post message) for every + * element in the notification list that is to be notified about the + * event specified in uEventMask. + * Parameters: + * hNtfy: Handle returned from NTFY_Create(). + * uEventMask: The type of event that has occurred. + * Returns: + * Requires: + * NTFY_Init(void) called. + * IsValid(hNtfy). + * Ensures: + */ + extern void NTFY_Notify(IN struct NTFY_OBJECT *hNtfy, + IN u32 uEventMask); + +/* + * ======== NTFY_Register ======== + * Purpose: + * Add a notification element to the list. If the notification is already + * registered, and uEventMask != 0, the notification will get posted for + * events specified in the new event mask. If the notification is already + * registered and uEventMask == 0, the notification will be unregistered. + * Parameters: + * hNtfy: Handle returned from NTFY_Create(). + * hNotification: Handle to a DSP_NOTIFICATION object. + * uEventMask: Events to be notified about. + * uNotifyType: Type of notification: DSP_SIGNALEVENT. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Insufficient memory. + * DSP_EVALUE: uEventMask is 0 and hNotification was not + * previously registered. + * DSP_EHANDLE: NULL hNotification, hNotification event name + * too long, or hNotification event name NULL. + * Requires: + * NTFY_Init(void) called. + * IsValid(hNtfy). + * hNotification != NULL. + * uNotifyType is DSP_SIGNALEVENT + * Ensures: + */ + extern DSP_STATUS NTFY_Register(IN struct NTFY_OBJECT *hNtfy, + IN struct DSP_NOTIFICATION + *hNotification, + IN u32 uEventMask, + IN u32 uNotifyType); + +#endif /* NTFY_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/proc.h b/arch/arm/plat-omap/include/dspbridge/proc.h new file mode 100644 index 0000000..486652e --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/proc.h @@ -0,0 +1,648 @@ +/* + * proc.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== proc.h ======== + * Description: + * This is the Class driver RM module interface. + * + * Public Functions: + * PROC_Attach + * PROC_Create + * PROC_Ctrl (OEM-function) + * PROC_Destroy + * PROC_Detach + * PROC_EnumNodes + * PROC_Exit + * PROC_FlushMemory + * PROC_GetDevObject (OEM-function) + * PROC_GetResourceInfo + * PROC_GetState + * PROC_GetProcessorId + * PROC_GetTrace (OEM-function) + * PROC_Init + * PROC_Load (OEM-function) + * PROC_Map + * PROC_NotifyAllclients + * PROC_NotifyClients (OEM-function) + * PROC_RegisterNotify + * PROC_ReserveMemory + * PROC_Start (OEM-function) + * PROC_UnMap + * PROC_UnReserveMemory + * + * Notes: + * + *! Revision History: + *! ================ + *! 19-Apr-2004 sb Aligned DMM definitions with Symbian + *! 08-Mar-2004 sb Added the Dynamic Memory Mapping APIs + *! 09-Feb-2003 vp: Added PROC_GetProcessorID function + *! 29-Nov-2000 rr: Incorporated code review changes. + *! 28-Sep-2000 rr: Updated to Version 0.9. + *! 10-Aug-2000 rr: PROC_NotifyClients, PROC_GetProcessorHandle Added + *! 27-Jul-2000 rr: Updated to ver 0.8 of DSPAPI(types). GetTrace added. + *! 27-Jun-2000 rr: Created from dspapi.h + */ + +#ifndef PROC_ +#define PROC_ + +#include +#include + +/* + * ======== PROC_Attach ======== + * Purpose: + * Prepare for communication with a particular DSP processor, and return + * a handle to the processor object. The PROC Object gets created + * Parameters: + * uProcessor : The processor index (zero-based). + * hMgrObject : Handle to the Manager Object + * pAttrIn : Ptr to the DSP_PROCESSORATTRIN structure. + * A NULL value means use default values. + * phProcessor : Ptr to location to store processor handle. + * Returns: + * DSP_SOK : Success. + * DSP_EFAIL : General failure. + * DSP_EHANDLE : Invalid processor handle. + * DSP_SALREADYATTACHED: Success; Processor already attached. + * Requires: + * phProcessor != NULL. + * PROC Initialized. + * Ensures: + * DSP_EFAIL, and *phProcessor == NULL, OR + * Success and *phProcessor is a Valid Processor handle OR + * DSP_SALREADYATTACHED and *phProcessor is a Valid Processor. + * Details: + * When pAttrIn is NULL, the default timeout value is 10 seconds. + */ + extern DSP_STATUS PROC_Attach(u32 uProcessor, + OPTIONAL CONST struct DSP_PROCESSORATTRIN + *pAttrIn, + OUT DSP_HPROCESSOR *phProcessor); + +/* + * ======== PROC_AutoStart ========= + * Purpose: + * A Particular device gets loaded with the default image + * if the AutoStart flag is set. + * Parameters: + * hDevObject : Handle to the Device + * Returns: + * DSP_SOK : On Successful Loading + * DSP_EFILE : No DSP exec file found. + * DSP_EFAIL : General Failure + * Requires: + * hDevObject != NULL. + * hDevNode != NULL. + * PROC Initialized. + * Ensures: + */ + extern DSP_STATUS PROC_AutoStart(struct CFG_DEVNODE *hDevNode, + struct DEV_OBJECT *hDevObject); + +/* + * ======== PROC_Ctrl ======== + * Purpose: + * Pass control information to the GPP device driver managing the DSP + * processor. This will be an OEM-only function, and not part of the + * 'Bridge application developer's API. + * Parameters: + * hProcessor : The processor handle. + * dwCmd : Private driver IOCTL cmd ID. + * pArgs : Ptr to an driver defined argument structure. + * Returns: + * DSP_SOK : SUCCESS + * DSP_EHANDLE : Invalid processor handle. + * DSP_ETIMEOUT: A Timeout Occured before the Control information + * could be sent. + * DSP_EACCESSDENIED: Client does not have the access rights required + * to call this function. + * DSP_ERESTART: A Critical error has occured and the DSP is being + * restarted. + * DSP_EFAIL : General Failure. + * Requires: + * PROC Initialized. + * Ensures + * Details: + * This function Calls WMD_BRD_Ioctl. + */ + extern DSP_STATUS PROC_Ctrl(DSP_HPROCESSOR hProcessor, + u32 dwCmd, IN struct DSP_CBDATA *pArgs); + +/* + * ======== PROC_Detach ======== + * Purpose: + * Close a DSP processor and de-allocate all (GPP) resources reserved + * for it. The Processor Object is deleted. + * Parameters: + * hProcessor : The processor handle. + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : InValid Handle. + * DSP_EFAIL : General failure. + * Requires: + * PROC Initialized. + * Ensures: + * PROC Object is destroyed. + */ + extern DSP_STATUS PROC_Detach(DSP_HPROCESSOR hProcessor); + +/* + * ======== PROC_EnumNodes ======== + * Purpose: + * Enumerate the nodes currently allocated on a processor. + * Parameters: + * hProcessor : The processor handle. + * aNodeTab : The first Location of an array allocated for node + * handles. + * uNodeTabSize: The number of (DSP_HNODE) handles that can be held + * to the memory the client has allocated for aNodeTab + * puNumNodes : Location where DSPProcessor_EnumNodes will return + * the number of valid handles written to aNodeTab + * puAllocated : Location where DSPProcessor_EnumNodes will return + * the number of nodes that are allocated on the DSP. + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : Invalid processor handle. + * DSP_ESIZE : The amount of memory allocated for aNodeTab is + * insufficent. That is the number of nodes actually + * allocated on the DSP is greater than the value + * specified for uNodeTabSize. + * DSP_EFAIL : Unable to get Resource Information. + * Details: + * Requires + * puNumNodes is not NULL. + * puAllocated is not NULL. + * aNodeTab is not NULL. + * PROC Initialized. + * Ensures: + * Details: + */ + extern DSP_STATUS PROC_EnumNodes(DSP_HPROCESSOR hProcessor, + IN DSP_HNODE *aNodeTab, + IN u32 uNodeTabSize, + OUT u32 *puNumNodes, + OUT u32 *puAllocated); + +/* + * ======== PROC_GetResourceInfo ======== + * Purpose: + * Enumerate the resources currently available on a processor. + * Parameters: + * hProcessor : The processor handle. + * uResourceType: Type of resource . + * pResourceInfo: Ptr to the DSP_RESOURCEINFO structure. + * uResourceInfoSize: Size of the structure. + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : Invalid processor handle. + * DSP_EWRONGSTATE: The processor is not in the PROC_RUNNING state. + * DSP_ETIMEOUT: A timeout occured before the DSP responded to the + * querry. + * DSP_ERESTART: A Critical error has occured and the DSP is being + * restarted. + * DSP_EFAIL : Unable to get Resource Information + * Requires: + * pResourceInfo is not NULL. + * Parameter uResourceType is Valid.[TBD] + * uResourceInfoSize is >= sizeof DSP_RESOURCEINFO struct. + * PROC Initialized. + * Ensures: + * Details: + * This function currently returns + * DSP_ENOTIMPL, and does not write any data to the pResourceInfo struct. + */ + extern DSP_STATUS PROC_GetResourceInfo(DSP_HPROCESSOR hProcessor, + u32 uResourceType, + OUT struct DSP_RESOURCEINFO * + pResourceInfo, + u32 uResourceInfoSize); + +/* + * ======== PROC_Exit ======== + * Purpose: + * Decrement reference count, and free resources when reference count is + * 0. + * Parameters: + * Returns: + * Requires: + * PROC is initialized. + * Ensures: + * When reference count == 0, PROC's private resources are freed. + */ + extern void PROC_Exit(void); + +/* + * ======== PROC_GetDevObject ========= + * Purpose: + * Returns the DEV Hanlde for a given Processor handle + * Parameters: + * hProcessor : Processor Handle + * phDevObject : Location to store the DEV Handle. + * Returns: + * DSP_SOK : Success; *phDevObject has Dev handle + * DSP_EFAIL : Failure; *phDevObject is zero. + * Requires: + * phDevObject is not NULL + * PROC Initialized. + * Ensures: + * DSP_SOK : *phDevObject is not NULL + * DSP_EFAIL : *phDevObject is NULL. + */ + extern DSP_STATUS PROC_GetDevObject(DSP_HPROCESSOR hProcessor, + struct DEV_OBJECT **phDevObject); + +/* + * ======== PROC_Init ======== + * Purpose: + * Initialize PROC's private state, keeping a reference count on each + * call. + * Parameters: + * Returns: + * TRUE if initialized; FALSE if error occured. + * Requires: + * Ensures: + * TRUE: A requirement for the other public PROC functions. + */ + extern bool PROC_Init(void); + +/* + * ======== PROC_GetState ======== + * Purpose: + * Report the state of the specified DSP processor. + * Parameters: + * hProcessor : The processor handle. + * pProcStatus : Ptr to location to store the DSP_PROCESSORSTATE + * structure. + * uStateInfoSize: Size of DSP_PROCESSORSTATE. + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : Invalid processor handle. + * DSP_EFAIL : General failure while querying processor state. + * Requires: + * pProcStatus is not NULL + * uStateInfoSize is >= than the size of DSP_PROCESSORSTATE structure. + * PROC Initialized. + * Ensures: + * Details: + */ + extern DSP_STATUS PROC_GetState(DSP_HPROCESSOR hProcessor, + OUT struct DSP_PROCESSORSTATE + *pProcStatus, + u32 uStateInfoSize); + +/* + * ======== PROC_GetProcessorID ======== + * Purpose: + * Report the state of the specified DSP processor. + * Parameters: + * hProcessor : The processor handle. + * procID : Processor ID + * + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : Invalid processor handle. + * DSP_EFAIL : General failure while querying processor state. + * Requires: + * pProcStatus is not NULL + * uStateInfoSize is >= than the size of DSP_PROCESSORSTATE structure. + * PROC Initialized. + * Ensures: + * Details: + */ + extern DSP_STATUS PROC_GetProcessorId(DSP_HPROCESSOR hProcessor, + u32 *procID); + +/* + * ======== PROC_GetTrace ======== + * Purpose: + * Retrieve the trace buffer from the specified DSP processor. + * Parameters: + * hProcessor : The processor handle. + * pBuf : Ptr to buffer to hold trace output. + * uMaxSize : Maximum size of the output buffer. + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : Invalid processor handle. + * DSP_EFAIL : General failure while retireving processor trace + * Buffer. + * Requires: + * pBuf is not NULL + * uMaxSize is > 0. + * PROC Initialized. + * Ensures: + * Details: + */ + extern DSP_STATUS PROC_GetTrace(DSP_HPROCESSOR hProcessor, u8 *pBuf, + u32 uMaxSize); + +/* + * ======== PROC_Load ======== + * Purpose: + * Reset a processor and load a new base program image. + * This will be an OEM-only function. + * Parameters: + * hProcessor : The processor handle. + * iArgc : The number of Arguments(strings)in the aArgV[] + * aArgv : An Array of Arguments(Unicode Strings) + * aEnvp : An Array of Environment settings(Unicode Strings) + * Returns: + * DSP_SOK : Success. + * DSP_EFILE : The DSP Execuetable was not found. + * DSP_EHANDLE : Invalid processor handle. + * DSP_ECORRUTFILE: Unable to Parse the DSP Execuetable + * DSP_EATTACHED: Abort because a GPP Client is attached to the + * specified Processor + * DSP_EACCESSDENIED: Client does not have the required access rights + * to reset and load the Processor + * DSP_EFAIL : Unable to Load the Processor + * Requires: + * aArgv is not NULL + * iArgc is > 0 + * PROC Initialized. + * Ensures: + * Success and ProcState == PROC_LOADED + * or DSP_FAILED status. + * Details: + * Does not implement access rights to control which GPP application + * can load the processor. + */ + extern DSP_STATUS PROC_Load(DSP_HPROCESSOR hProcessor, + IN CONST s32 iArgc, IN CONST char **aArgv, + IN CONST char **aEnvp); + +/* + * ======== PROC_RegisterNotify ======== + * Purpose: + * Register to be notified of specific processor events + * Parameters: + * hProcessor : The processor handle. + * uEventMask : Mask of types of events to be notified about. + * uNotifyType : Type of notification to be sent. + * hNotification: Handle to be used for notification. + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : Invalid processor handle or hNotification. + * DSP_EVALUE : Parameter uEventMask is Invalid + * DSP_ENOTIMP : The notification type specified in uNotifyMask + * is not supported. + * DSP_EFAIL : Unable to register for notification. + * Requires: + * hNotification is not NULL + * PROC Initialized. + * Ensures: + * Details: + */ + extern DSP_STATUS PROC_RegisterNotify(DSP_HPROCESSOR hProcessor, + u32 uEventMask, u32 uNotifyType, + struct DSP_NOTIFICATION + *hNotification); + +/* + * ======== PROC_NotifyClients ======== + * Purpose: + * Notify the Processor Clients + * Parameters: + * hProc : The processor handle. + * uEvents : Event to be notified about. + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : Invalid processor handle. + * DSP_EFAIL : Failure to Set or Reset the Event + * Requires: + * uEvents is Supported or Valid type of Event + * hProc is a valid handle + * PROC Initialized. + * Ensures: + */ + extern DSP_STATUS PROC_NotifyClients(DSP_HPROCESSOR hProc, + u32 uEvents); + +/* + * ======== PROC_NotifyAllClients ======== + * Purpose: + * Notify the Processor Clients + * Parameters: + * hProc : The processor handle. + * uEvents : Event to be notified about. + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : Invalid processor handle. + * DSP_EFAIL : Failure to Set or Reset the Event + * Requires: + * uEvents is Supported or Valid type of Event + * hProc is a valid handle + * PROC Initialized. + * Ensures: + * Details: + * NODE And STRM would use this function to notify their clients + * about the state changes in NODE or STRM. + */ + extern DSP_STATUS PROC_NotifyAllClients(DSP_HPROCESSOR hProc, + u32 uEvents); + +/* + * ======== PROC_Start ======== + * Purpose: + * Start a processor running. + * Processor must be in PROC_LOADED state. + * This will be an OEM-only function, and not part of the 'Bridge + * application developer's API. + * Parameters: + * hProcessor : The processor handle. + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : Invalid processor handle. + * DSP_EWRONGSTATE: Processor is not in PROC_LOADED state. + * DSP_EFAIL : Unable to start the processor. + * Requires: + * PROC Initialized. + * Ensures: + * Success and ProcState == PROC_RUNNING or DSP_FAILED status. + * Details: + */ + extern DSP_STATUS PROC_Start(DSP_HPROCESSOR hProcessor); + +/* + * ======== PROC_Stop ======== + * Purpose: + * Start a processor running. + * Processor must be in PROC_LOADED state. + * This will be an OEM-only function, and not part of the 'Bridge + * application developer's API. + * Parameters: + * hProcessor : The processor handle. + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : Invalid processor handle. + * DSP_EWRONGSTATE: Processor is not in PROC_LOADED state. + * DSP_EFAIL : Unable to start the processor. + * Requires: + * PROC Initialized. + * Ensures: + * Success and ProcState == PROC_RUNNING or DSP_FAILED status. + * Details: + */ + extern DSP_STATUS PROC_Stop(DSP_HPROCESSOR hProcessor); + +/* + * ======== PROC_FlushMemory ======== + * Purpose: + * Flushes a buffer from the MPU data cache. + * Parameters: + * hProcessor : The processor handle. + * pMpuAddr : Buffer start address + * ulSize : Buffer size + * ulFlags : Reserved. + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : Invalid processor handle. + * DSP_EFAIL : General failure. + * Requires: + * PROC Initialized. + * Ensures: + * Details: + * All the arguments are currently ignored. + */ + extern DSP_STATUS PROC_FlushMemory(DSP_HPROCESSOR hProcessor, + void *pMpuAddr, + u32 ulSize, u32 ulFlags); + + +/* + * ======== PROC_InvalidateMemory ======== + * Purpose: + * Invalidates a buffer from the MPU data cache. + * Parameters: + * hProcessor : The processor handle. + * pMpuAddr : Buffer start address + * ulSize : Buffer size + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : Invalid processor handle. + * DSP_EFAIL : General failure. + * Requires: + * PROC Initialized. + * Ensures: + * Details: + * All the arguments are currently ignored. + */ + extern DSP_STATUS PROC_InvalidateMemory(DSP_HPROCESSOR hProcessor, + void *pMpuAddr, + u32 ulSize); + +/* + * ======== PROC_Map ======== + * Purpose: + * Maps a MPU buffer to DSP address space. + * Parameters: + * hProcessor : The processor handle. + * pMpuAddr : Starting address of the memory region to map. + * ulSize : Size of the memory region to map. + * pReqAddr : Requested DSP start address. Offset-adjusted actual + * mapped address is in the last argument. + * ppMapAddr : Ptr to DSP side mapped u8 address. + * ulMapAttr : Optional endianness attributes, virt to phys flag. + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : Invalid processor handle. + * DSP_EFAIL : General failure. + * DSP_EMEMORY : MPU side memory allocation error. + * DSP_ENOTFOUND : Cannot find a reserved region starting with this + * : address. + * Requires: + * pMpuAddr is not NULL + * ulSize is not zero + * ppMapAddr is not NULL + * PROC Initialized. + * Ensures: + * Details: + */ + extern DSP_STATUS PROC_Map(DSP_HPROCESSOR hProcessor, + void *pMpuAddr, + u32 ulSize, + void *pReqAddr, + void **ppMapAddr, u32 ulMapAttr); + +/* + * ======== PROC_ReserveMemory ======== + * Purpose: + * Reserve a virtually contiguous region of DSP address space. + * Parameters: + * hProcessor : The processor handle. + * ulSize : Size of the address space to reserve. + * ppRsvAddr : Ptr to DSP side reserved u8 address. + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : Invalid processor handle. + * DSP_EFAIL : General failure. + * DSP_EMEMORY : Cannot reserve chunk of this size. + * Requires: + * ppRsvAddr is not NULL + * PROC Initialized. + * Ensures: + * Details: + */ + extern DSP_STATUS PROC_ReserveMemory(DSP_HPROCESSOR hProcessor, + u32 ulSize, void **ppRsvAddr); + +/* + * ======== PROC_UnMap ======== + * Purpose: + * Removes a MPU buffer mapping from the DSP address space. + * Parameters: + * hProcessor : The processor handle. + * pMapAddr : Starting address of the mapped memory region. + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : Invalid processor handle. + * DSP_EFAIL : General failure. + * DSP_ENOTFOUND : Cannot find a mapped region starting with this + * : address. + * Requires: + * pMapAddr is not NULL + * PROC Initialized. + * Ensures: + * Details: + */ + extern DSP_STATUS PROC_UnMap(DSP_HPROCESSOR hProcessor, void *pMapAddr); + +/* + * ======== PROC_UnReserveMemory ======== + * Purpose: + * Frees a previously reserved region of DSP address space. + * Parameters: + * hProcessor : The processor handle. + * pRsvAddr : Ptr to DSP side reservedBYTE address. + * Returns: + * DSP_SOK : Success. + * DSP_EHANDLE : Invalid processor handle. + * DSP_EFAIL : General failure. + * DSP_ENOTFOUND : Cannot find a reserved region starting with this + * : address. + * Requires: + * pRsvAddr is not NULL + * PROC Initialized. + * Ensures: + * Details: + */ + extern DSP_STATUS PROC_UnReserveMemory(DSP_HPROCESSOR hProcessor, + void *pRsvAddr); + +#endif /* PROC_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/procpriv.h b/arch/arm/plat-omap/include/dspbridge/procpriv.h new file mode 100644 index 0000000..21d4b3e --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/procpriv.h @@ -0,0 +1,35 @@ +/* + * procpriv.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== procpriv.h ======== + * Description: + * Global PROC constants and types, shared by PROC, MGR, and WCD. + * + *! Revision History: + *! ================ + *! 05-July-2000 rr: Created + */ + +#ifndef PROCPRIV_ +#define PROCPRIV_ + +/* RM PROC Object */ + struct PROC_OBJECT; + +#endif /* PROCPRIV_ */ + diff --git a/arch/arm/plat-omap/include/dspbridge/pwr.h b/arch/arm/plat-omap/include/dspbridge/pwr.h new file mode 100644 index 0000000..a6645ca --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/pwr.h @@ -0,0 +1,129 @@ +/* + * pwr.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== pwr.h ======== + * + * Public Functions: + * + * PWR_SleepDSP + * PWR_WakeDSP + * + * Notes: + * + *! Revision History: + *! ================ + *! 06-Jun-2002 sg Replaced dspdefs.h with includes of dbdefs.h and errbase.h. + *! 13-May-2002 sg Added DSP_SAREADYASLEEP and DSP_SALREADYAWAKE. + *! 09-May-2002 sg Updated, added timeouts. + *! 02-May-2002 sg Initial. + */ + +#ifndef PWR_ +#define PWR_ + +#include +#include +#include + +/* + * ======== PWR_SleepDSP ======== + * Signal the DSP to go to sleep. + * + * Parameters: + * sleepCode: New sleep state for DSP. (Initially, valid codes + * are PWR_DEEPSLEEP or PWR_EMERGENCYDEEPSLEEP; both of + * these codes will simply put the DSP in deep sleep.) + * + * timeout: Maximum time (msec) that PWR should wait for + * confirmation that the DSP sleep state has been + * reached. If PWR should simply send the command to + * the DSP to go to sleep and then return (i.e., + * asynchrounous sleep), the timeout should be + * specified as zero. + * + * Returns: + * DSP_SOK: Success. + * DSP_SALREADYASLEEP: Success, but the DSP was already asleep. + * DSP_EINVALIDARG: The specified sleepCode is not supported. + * DSP_ETIMEOUT: A timeout occured while waiting for DSP sleep + * confirmation. + * DSP_EFAIL: General failure, unable to send sleep command to + * the DSP. + */ + extern DSP_STATUS PWR_SleepDSP(IN CONST u32 sleepCode, + IN CONST u32 timeout); + +/* + * ======== PWR_WakeDSP ======== + * Signal the DSP to wake from sleep. + * + * Parameters: + * timeout: Maximum time (msec) that PWR should wait for + * confirmation that the DSP is awake. If PWR should + * simply send a command to the DSP to wake and then + * return (i.e., asynchrounous wake), timeout should + * be specified as zero. + * + * Returns: + * DSP_SOK: Success. + * DSP_SALREADYAWAKE: Success, but the DSP was already awake. + * DSP_ETIMEOUT: A timeout occured while waiting for wake + * confirmation. + * DSP_EFAIL: General failure, unable to send wake command to + * the DSP. + */ + extern DSP_STATUS PWR_WakeDSP(IN CONST u32 timeout); + +/* + * ======== PWR_PM_PreScale ======== + * Prescale notification to DSP. + * + * Parameters: + * voltage_domain: The voltage domain for which notification is sent + * level: The level of voltage domain + * + * Returns: + * DSP_SOK: Success. + * DSP_SALREADYAWAKE: Success, but the DSP was already awake. + * DSP_ETIMEOUT: A timeout occured while waiting for wake + * confirmation. + * DSP_EFAIL: General failure, unable to send wake command to + * the DSP. + */ + extern DSP_STATUS PWR_PM_PreScale(IN u16 voltage_domain, u32 level); + +/* + * ======== PWR_PM_PostScale ======== + * PostScale notification to DSP. + * + * Parameters: + * voltage_domain: The voltage domain for which notification is sent + * level: The level of voltage domain + * + * Returns: + * DSP_SOK: Success. + * DSP_SALREADYAWAKE: Success, but the DSP was already awake. + * DSP_ETIMEOUT: A timeout occured while waiting for wake + * confirmation. + * DSP_EFAIL: General failure, unable to send wake command to + * the DSP. + */ + extern DSP_STATUS PWR_PM_PostScale(IN u16 voltage_domain, + u32 level); + +#endif /* PWR_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/pwr_sh.h b/arch/arm/plat-omap/include/dspbridge/pwr_sh.h new file mode 100644 index 0000000..40f1b84 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/pwr_sh.h @@ -0,0 +1,41 @@ +/* + * pwr_sh.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== pwr_sh.h ======== + * + * Power Manager shared definitions (used on both GPP and DSP sides). + * + *! Revision History + *! ================ + *! 17-Apr-2002 sg: Initial. + */ + +#ifndef PWR_SH_ +#define PWR_SH_ + +#include + +/* valid sleep command codes that can be sent by GPP via mailbox: */ +#define PWR_DEEPSLEEP MBX_PM_DSPIDLE +#define PWR_EMERGENCYDEEPSLEEP MBX_PM_EMERGENCYSLEEP +#define PWR_SLEEPUNTILRESTART MBX_PM_SLEEPUNTILRESTART +#define PWR_WAKEUP MBX_PM_DSPWAKEUP +#define PWR_AUTOENABLE MBX_PM_PWRENABLE +#define PWR_AUTODISABLE MBX_PM_PWRDISABLE +#define PWR_RETENTION MBX_PM_DSPRETN + +#endif /* PWR_SH_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/reg.h b/arch/arm/plat-omap/include/dspbridge/reg.h new file mode 100644 index 0000000..5b34952 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/reg.h @@ -0,0 +1,257 @@ +/* + * reg.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== reg.h ======== + * Purpose: + * Provide registry functions. + * + * Public Functions: + * REG_DeleteValue + * REG_EnumKey + * REG_EnumValue + * REG_Exit + * REG_GetValue + * REG_Init + * REG_SetValue + * + *! Revision History: + *! ================= + *! 30-Oct-2000 kc: Updated REG_SetValue & REG_GetValue; renamed + *! REG_DeleteEntry to REG_DeleteValue. + *! 29-Sep-2000 kc: Updated a REG functions for code review. + *! 12-Aug-2000 kc: Renamed REG_EnumValue to REG_EnumKey. Re-implemented + *! REG_EnumValue. + *! 03-Feb-2000 rr: REG_EnumValue Fxn Added + *! 13-Dec-1999 rr: windows.h removed + *! 02-Dec-1999 rr: windows.h included for retail build + *! 22-Nov-1999 kc: Changes from code review. + *! 29-Dec-1997 cr: Changes from code review. + *! 27-Oct-1997 cr: Added REG_DeleteValue. + *! 20-Oct-1997 cr: Added ability to pass bValue = NULL to REG_GetValue + *! and return size of reg entry in pdwValueSize. + *! 29-Sep-1997 cr: Added REG_SetValue + *! 29-Aug-1997 cr: Created. + */ + +#ifndef _REG_H +#define _REG_H + +#include + +/* ------------------------- Defines, Data Structures, Typedefs for Linux */ +#ifndef UNDER_CE + +#ifndef REG_SZ +#define REG_SZ 1 +#endif + +#ifndef REG_BINARY +#define REG_BINARY 3 +#endif + +#ifndef REG_DWORD +#define REG_DWORD 4 +#endif + +#endif /* UNDER_CE */ + +#define REG_MAXREGPATHLENGTH 255 + +/* + * ======== REG_DeleteValue ======== + * Purpose: + * Deletes a registry entry. NOTE: A registry entry is not the same as + * a registry key. + * Parameters: + * phKey: Currently reserved; must be NULL. + * pstrSubkey: Path to key to open. + * pstrValue: Name of entry to delete. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: General failure. + * Requires: + * - REG initialized. + * - pstrSubkey & pstrValue are non-NULL values. + * - phKey is NULL. + * - length of pstrSubkey < REG_MAXREGPATHLENGTH. + * - length of pstrValue < REG_MAXREGPATHLENGTH. + * Ensures: + * Details: + */ + extern DSP_STATUS REG_DeleteValue(OPTIONAL IN HANDLE *phKey, + IN CONST char *pstrSubkey, + IN CONST char *pstrValue); + +/* + * ======== REG_EnumKey ======== + * Purpose: + * Enumerates subkeys of the specified path to the registry key + * Retrieves the name of the subkey(given the index) and + * appends with the orignal path to form the full path. + * Parameters: + * phKey: Currently reserved; must be NULL. + * pstrKey The name of the registry key to be enumerated. + * dwIndex Specifies the index of the subkey to retrieve. + * pstrSubkey: Pointer to buffer that receives full path name of the + * specified key + the sub-key + * pdwValueSize: Specifies bytes of memory pstrSubkey points to on input, + * on output, specifies actual memory bytes written into. + * If there is no sub key,pdwValueSize returns NULL. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: General failure. + * Requires: + * - REG initialized. + * - pstrKey is non-NULL value. + * - pdwValueSize is a valid pointer. + * - phKey is NULL. + * - length of pstrKey < REG_MAXREGPATHLENGTH. + * Ensures: + * - strlen(pstrSubkey) is > strlen(pstrKey) && + * - strlen(pstrSubkey) is < REG_MAXREGPATHLENGTH + */ + extern DSP_STATUS REG_EnumKey(OPTIONAL IN HANDLE *phKey, + IN u32 dwIndex, IN CONST char *pstrKey, + IN OUT char *pstrSubkey, + IN OUT u32 *pdwValueSize); + +/* + * ======== REG_EnumValue ======== + * Purpose: + * Enumerates values of a specified key. Retrieves each value name and + * the data associated with the value. + * Parameters: + * phKey: Currently reserved; must be NULL. + * dwIndex: Specifies the index of the value to retrieve. + * pstrKey: The name of the registry key to be enumerated. + * pstrValue: Pointer to buffer that receives the name of the value. + * pdwValueSize: Specifies bytes of memory pstrValue points to on input, + * On output, specifies actual memory bytes written into. + * If there is no value, pdwValueSize returns NULL + * pstrData: Pointer to buffer that receives the data of a value. + * pdwDataSize: Specifies bytes of memory in pstrData on input and + * bytes of memory written into pstrData on output. + * If there is no data, pdwDataSize returns NULL. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: General failure. + * Requires: + * REG initialized. + * phKey is NULL. + * pstrKey is a non-NULL value. + * pstrValue, pstrData, pdwValueSize and pdwDataSize are valid pointers. + * Length of pstrKey is less than REG_MAXREGPATHLENGTH. + * Ensures: + */ + extern DSP_STATUS REG_EnumValue(IN HANDLE *phKey, + IN u32 dwIndex, + IN CONST char *pstrKey, + IN OUT char *pstrValue, + IN OUT u32 *pdwValueSize, + IN OUT char *pstrData, + IN OUT u32 *pdwDataSize); + +/* + * ======== REG_Exit ======== + * Purpose: + * Discontinue usage of module; free resources when reference count + * reaches 0. + * Parameters: + * Returns: + * Requires: + * REG initialized. + * Ensures: + * Resources used by module are freed when cRef reaches zero. + */ + extern void REG_Exit(void); + +/* + * ======== REG_GetValue ======== + * Purpose: + * Retrieve a value from the registry. + * Parameters: + * phKey: Currently reserved; must be NULL. + * pstrSubkey: Path to key to open. + * pstrEntry: Name of entry to retrieve. + * pbValue: Upon return, points to retrieved value. + * pdwValueSize: Specifies bytes of memory pbValue points to on input, + * on output, specifies actual memory bytes written into. + * If pbValue is NULL, pdwValueSize reports the size of + * the entry in pstrEntry. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: General failure. + * Requires: + * - REG initialized. + * - pstrSubkey & pstrEntry are non-NULL values. + * - pbValue is a valid pointer. + * - phKey is NULL. + * - length of pstrSubkey < REG_MAXREGPATHLENGTH. + * - length of pstrEntry < REG_MAXREGPATHLENGTH. + * Ensures: + */ + extern DSP_STATUS REG_GetValue(OPTIONAL IN HANDLE *phKey, + IN CONST char *pstrSubkey, + IN CONST char *pstrEntry, + OUT u8 *pbValue, + IN OUT u32 *pdwValueSize); + +/* + * ======== REG_Init ======== + * Purpose: + * Initializes private state of REG module. + * Parameters: + * Returns: + * TRUE if initialized; FALSE if error occured. + * Requires: + * Ensures: + * REG initialized. + */ + extern bool REG_Init(void); + +/* + * ======== REG_SetValue ======== + * Purpose: + * Set a value in the registry. + * Parameters: + * phKey: Handle to open reg key, or NULL if pSubkey is full path. + * pstrSubkey: Path to key to open, could be based on phKey. + * pstrEntry: Name of entry to set. + * dwType: Data type of new registry value. + * pbValue: Points to buffer containing new data. + * dwValueSize: Specifies bytes of memory bValue points to. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: General failure. + * Requires: + * - REG initialized. + * - pstrSubkey & pstrEntry are non-NULL values. + * - pbValue is a valid pointer. + * - phKey is NULL. + * - dwValuSize > 0. + * - length of pstrSubkey < REG_MAXREGPATHLENGTH. + * - length of pstrEntry < REG_MAXREGPATHLENGTH. + * Ensures: + */ + extern DSP_STATUS REG_SetValue(OPTIONAL IN HANDLE *phKey, + IN CONST char *pstrSubKey, + IN CONST char *pstrEntry, + IN CONST u32 dwType, + IN u8 *pbValue, IN u32 dwValueSize); + +#endif /* _REG_H */ diff --git a/arch/arm/plat-omap/include/dspbridge/resourcecleanup.h b/arch/arm/plat-omap/include/dspbridge/resourcecleanup.h new file mode 100644 index 0000000..b43fa16 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/resourcecleanup.h @@ -0,0 +1,88 @@ +/* + * resourcecleanup.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef RES_CLEANUP_DISABLE + +#include +#include + + +extern DSP_STATUS DRV_GetProcCtxtList(struct PROCESS_CONTEXT **pPctxt, + struct DRV_OBJECT *hDrvObject); + +extern DSP_STATUS DRV_InsertProcContext(struct DRV_OBJECT *hDrVObject, + HANDLE hPCtxt); + +extern DSP_STATUS DRV_RemoveAllDMMResElements(HANDLE pCtxt); + +extern DSP_STATUS DRV_RemoveAllNodeResElements(HANDLE pCtxt); + +extern DSP_STATUS DRV_ProcUpdatestate(HANDLE pCtxt, + enum GPP_PROC_RES_STATE resState); + +extern DSP_STATUS DRV_ProcSetPID(HANDLE pCtxt, s32 hProcess); + +extern DSP_STATUS DRV_GetProcContext(u32 phProcess, + struct DRV_OBJECT *hDrvObject, + HANDLE hPCtxt, DSP_HNODE hNode, + u32 pMapAddr); + +extern DSP_STATUS DRV_RemoveAllResources(HANDLE pPctxt); + +extern DSP_STATUS DRV_RemoveProcContext(struct DRV_OBJECT *hDRVObject, + HANDLE hPCtxt, HANDLE hProcess); + +extern DSP_STATUS DRV_GetNodeResElement(HANDLE hNode, HANDLE nodeRes, + HANDLE pCtxt); + +extern DSP_STATUS DRV_InsertNodeResElement(HANDLE hNode, HANDLE nodeRes, + HANDLE pCtxt); + +extern void DRV_ProcNodeUpdateHeapStatus(HANDLE hNodeRes, s32 status); + +extern DSP_STATUS DRV_RemoveNodeResElement(HANDLE nodeRes, HANDLE status); + +extern void DRV_ProcNodeUpdateStatus(HANDLE hNodeRes, s32 status); + +extern DSP_STATUS DRV_UpdateDMMResElement(HANDLE dmmRes, u32 pMpuAddr, + u32 ulSize, u32 pReqAddr, + u32 ppMapAddr, HANDLE hProcesso); + +extern DSP_STATUS DRV_InsertDMMResElement(HANDLE dmmRes, HANDLE pCtxt); + +extern DSP_STATUS DRV_GetDMMResElement(u32 pMapAddr, HANDLE dmmRes, + HANDLE pCtxt); + +extern DSP_STATUS DRV_RemoveDMMResElement(HANDLE dmmRes, HANDLE pCtxt); + +extern DSP_STATUS DRV_ProcUpdateSTRMRes(u32 uNumBufs, HANDLE STRMRes, + HANDLE pCtxt); + +extern DSP_STATUS DRV_ProcInsertSTRMResElement(HANDLE hStrm, HANDLE STRMRes, + HANDLE pPctxt); + +extern DSP_STATUS DRV_GetSTRMResElement(HANDLE hStrm, HANDLE STRMRes, + HANDLE pCtxt); + +extern DSP_STATUS DRV_ProcRemoveSTRMResElement(HANDLE STRMRes, HANDLE pCtxt); + +extern DSP_STATUS DRV_RemoveAllSTRMResElements(HANDLE pCtxt); + +extern DSP_STATUS DRV_ProcDisplayResInfo(u8 *pBuf, u32 *pSize); + +extern enum NODE_STATE NODE_GetState(HANDLE hNode); + +#endif diff --git a/arch/arm/plat-omap/include/dspbridge/rmm.h b/arch/arm/plat-omap/include/dspbridge/rmm.h new file mode 100644 index 0000000..5b14b8f --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/rmm.h @@ -0,0 +1,199 @@ +/* + * rmm.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== rmm.h ======== + * + * This memory manager provides general heap management and arbitrary + * alignment for any number of memory segments, and management of overlay + * memory. + * + * Public functions: + * RMM_alloc + * RMM_create + * RMM_delete + * RMM_exit + * RMM_free + * RMM_init + * + *! Revision History + *! ================ + *! 25-Jun-2002 jeh Added RMM_Addr. Removed RMM_reserve, RMM_stat. + *! 15-Oct-2001 jeh Based on rm.h in gen tree. + */ + +#ifndef RMM_ +#define RMM_ + +/* + * ======== RMM_Addr ======== + * DSP address + segid + */ +struct RMM_Addr { + u32 addr; + s32 segid; +} ; + +/* + * ======== RMM_Segment ======== + * Memory segment on the DSP available for remote allocations. + */ +struct RMM_Segment { + u32 base; /* Base of the segment */ + u32 length; /* Size of the segment (target MAUs) */ + s32 space; /* Code or data */ + u32 number; /* Number of Allocated Blocks */ +} ; + +/* + * ======== RMM_Target ======== + */ +struct RMM_TargetObj; + +/* + * ======== RMM_alloc ======== + * + * RMM_alloc is used to remotely allocate or reserve memory on the DSP. + * + * Parameters: + * target - Target returned from RMM_create(). + * segid - Memory segment to allocate from. + * size - Size (target MAUS) to allocate. + * align - alignment. + * dspAddr - If reserve is FALSE, the location to store allocated + * address on output, otherwise, the DSP address to + * reserve. + * reserve - If TRUE, reserve the memory specified by dspAddr. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Memory allocation on GPP failed. + * DSP_EOVERLAYMEMORY: Cannot "allocate" overlay memory because it's + * already in use. + * Requires: + * RMM initialized. + * Valid target. + * dspAddr != NULL. + * size > 0 + * reserve || target->numSegs > 0. + * Ensures: + */ +extern DSP_STATUS RMM_alloc(struct RMM_TargetObj *target, u32 segid, u32 size, + u32 align, u32 *dspAdr, bool reserve); + +/* + * ======== RMM_create ======== + * Create a target object with memory segments for remote allocation. If + * segTab == NULL or numSegs == 0, memory can only be reserved through + * RMM_alloc(). + * + * Parameters: + * pTarget: - Location to store target on output. + * segTab: - Table of memory segments. + * numSegs: - Number of memory segments. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Memory allocation failed. + * Requires: + * RMM initialized. + * pTarget != NULL. + * numSegs == 0 || segTab != NULL. + * Ensures: + * Success: Valid *pTarget. + * Failure: *pTarget == NULL. + */ +extern DSP_STATUS RMM_create(struct RMM_TargetObj **pTarget, + struct RMM_Segment segTab[], u32 numSegs); + +/* + * ======== RMM_delete ======== + * Delete target allocated in RMM_create(). + * + * Parameters: + * target - Target returned from RMM_create(). + * Returns: + * Requires: + * RMM initialized. + * Valid target. + * Ensures: + */ +extern void RMM_delete(struct RMM_TargetObj *target); + +/* + * ======== RMM_exit ======== + * Exit the RMM module + * + * Parameters: + * Returns: + * Requires: + * RMM_init successfully called. + * Ensures: + */ +extern void RMM_exit(void); + +/* + * ======== RMM_free ======== + * Free or unreserve memory allocated through RMM_alloc(). + * + * Parameters: + * target: - Target returned from RMM_create(). + * segid: - Segment of memory to free. + * dspAddr: - Address to free or unreserve. + * size: - Size of memory to free or unreserve. + * reserved: - TRUE if memory was reserved only, otherwise FALSE. + * Returns: + * Requires: + * RMM initialized. + * Valid target. + * reserved || segid < target->numSegs. + * reserve || [dspAddr, dspAddr + size] is a valid memory range. + * Ensures: + */ +extern bool RMM_free(struct RMM_TargetObj *target, u32 segid, u32 dspAddr, + u32 size, bool reserved); + +/* + * ======== RMM_init ======== + * Initialize the RMM module + * + * Parameters: + * Returns: + * TRUE: Success. + * FALSE: Failure. + * Requires: + * Ensures: + */ +extern bool RMM_init(void); + +/* + * ======== RMM_stat ======== + * Obtain memory segment status + * + * Parameters: + * segid: Segment ID of the dynamic loading segment. + * pMemStatBuf: Pointer to allocated buffer into which memory stats are + * placed. + * Returns: + * TRUE: Success. + * FALSE: Failure. + * Requires: + * segid < target->numSegs + * Ensures: + */ +extern bool RMM_stat(struct RMM_TargetObj *target, enum DSP_MEMTYPE segid, + struct DSP_MEMSTAT *pMemStatBuf); + +#endif /* RMM_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/rms_sh.h b/arch/arm/plat-omap/include/dspbridge/rms_sh.h new file mode 100644 index 0000000..5d4b49a --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/rms_sh.h @@ -0,0 +1,125 @@ +/* + * rms_sh.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== rms_sh.h ======== + * + * DSP/BIOS Bridge Resource Manager Server shared definitions (used on both + * GPP and DSP sides). + * + *! Revision History + *! ================ + *! 24-Mar-2003 vp Merged updates required for CCS2.2 transition. + *! 24-Feb-2003 kc Rearranged order of node types to temporarily support + *! legacy message node code + *! 23-Nov-2002 gp Converted tabs -> spaces, to fix formatting. + *! 13-Feb-2002 jeh Added sysstacksize element to RMS_MoreTaskArgs. + *! 11-Dec-2000 sg Added 'misc' element to RMS_MoreTaskArgs. + *! 04-Dec-2000 ag Added RMS_BUFDESC command code. + *! C/R code value changed to allow ORing of system/user codes. + *! 10-Oct-2000 sg Added 'align' field to RMS_StrmDef. + *! 09-Oct-2000 sg Moved pre-defined message codes here from rmsdefs.h. + *! 02-Oct-2000 sg Changed ticks to msec. + *! 24-Aug-2000 sg Moved definitions that will be exposed to app developers + *! to a separate file, rmsdefs.h. + *! 10-Aug-2000 sg Added RMS_COMMANDBUFSIZE and RMS_RESPONSEBUFSIZE; added + *! pre-defined command/response codes; more comments. + *! 09-Aug-2000 sg Added RMS_ETASK. + *! 08-Aug-2000 jeh Define RMS_WORD for GPP, rename DSP_MSG to RMS_DSPMSG. + *! Added RMS_MsgArgs, RMS_MoreTaskArgs. + *! 25-Jul-2000 sg: Changed SIO to STRM. + *! 30-Jun-2000 sg: Initial. + */ + +#ifndef RMS_SH_ +#define RMS_SH_ + +#include + +/* Node Types: */ +#define RMS_TASK 1 /* Task node */ +#define RMS_DAIS 2 /* xDAIS socket node */ +#define RMS_MSG 3 /* Message node */ + +/* Memory Types: */ +#define RMS_CODE 0 /* Program space */ +#define RMS_DATA 1 /* Data space */ +#define RMS_IO 2 /* I/O space */ + +/* RM Server Command and Response Buffer Sizes: */ +#define RMS_COMMANDBUFSIZE 256 /* Size of command buffer */ +#define RMS_RESPONSEBUFSIZE 16 /* Size of response buffer */ + +/* Pre-Defined Command/Response Codes: */ +#define RMS_EXIT 0x80000000 /* GPP->Node: shutdown */ +#define RMS_EXITACK 0x40000000 /* Node->GPP: ack shutdown */ +#define RMS_BUFDESC 0x20000000 /* Arg1 SM buf, Arg2 is SM size */ +#define RMS_KILLTASK 0x10000000 /* GPP->Node: Kill Task */ +#define RMS_USER 0x0 /* Start of user-defined msg codes */ +#define RMS_MAXUSERCODES 0xfff /* Maximum user defined C/R Codes */ + + +/* RM Server RPC Command Structure: */ + struct RMS_Command { + RMS_WORD fxn; /* Server function address */ + RMS_WORD arg1; /* First argument */ + RMS_WORD arg2; /* Second argument */ + RMS_WORD data; /* Function-specific data array */ + } ; + +/* + * The RMS_StrmDef structure defines the parameters for both input and output + * streams, and is passed to a node's create function. + */ + struct RMS_StrmDef { + RMS_WORD bufsize; /* Buffer size (in DSP words) */ + RMS_WORD nbufs; /* Max number of bufs in stream */ + RMS_WORD segid; /* Segment to allocate buffers */ + RMS_WORD align; /* Alignment for allocated buffers */ + RMS_WORD timeout; /* Timeout (msec) for blocking calls */ + RMS_CHAR name[1]; /* Device Name (terminated by '\0') */ + } ; + +/* Message node create args structure: */ + struct RMS_MsgArgs { + RMS_WORD maxMessages; /* Max # simultaneous msgs to node */ + RMS_WORD segid; /* Mem segment for NODE_allocMsgBuf */ + RMS_WORD notifyType; /* Type of message notification */ + RMS_WORD argLength; /* Length (in DSP chars) of arg data */ + RMS_WORD argData; /* Arg data for node */ + } ; + +/* Partial task create args structure */ + struct RMS_MoreTaskArgs { + RMS_WORD priority; /* Task's runtime priority level */ + RMS_WORD stackSize; /* Task's stack size */ + RMS_WORD sysstackSize; /* Task's system stack size (55x) */ + RMS_WORD stackSeg; /* Memory segment for task's stack */ + RMS_WORD heapAddr; /* base address of the node memory heap in + * external memory (DSP virtual address) */ + RMS_WORD heapSize; /* size in MAUs of the node memory heap in + * external memory */ + RMS_WORD misc; /* Misc field. Not used for 'normal' + * task nodes; for xDAIS socket nodes + * specifies the IALG_Fxn pointer. + */ + /* # input STRM definition structures */ + RMS_WORD numInputStreams; + } ; + +#endif /* RMS_SH_ */ + diff --git a/arch/arm/plat-omap/include/dspbridge/rmstypes.h b/arch/arm/plat-omap/include/dspbridge/rmstypes.h new file mode 100644 index 0000000..13d752e --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/rmstypes.h @@ -0,0 +1,40 @@ +/* + * rmstypes.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== rmstypes.h ======== + * + * DSP/BIOS Bridge Resource Manager Server shared data type definitions. + * + *! Revision History + *! ================ + *! 06-Oct-2000 sg Added LgFxn type. + *! 05-Oct-2000 sg Changed RMS_STATUS to LgUns. + *! 31-Aug-2000 sg Added RMS_DSPMSG. + *! 25-Aug-2000 sg Initial. + */ + +#ifndef RMSTYPES_ +#define RMSTYPES_ +#include +/* + * DSP-side definitions. + */ +#include +typedef u32 RMS_WORD; +typedef char RMS_CHAR; + +#endif /* RMSTYPES_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/services.h b/arch/arm/plat-omap/include/dspbridge/services.h new file mode 100644 index 0000000..35bab0d --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/services.h @@ -0,0 +1,63 @@ +/* + * services.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== services.h ======== + * Purpose: + * Provide loading and unloading of SERVICES modules. + * + * Public Functions: + * SERVICES_Exit(void) + * SERVICES_Init(void) + * + *! Revision History: + *! ================ + *! 01-Feb-2000 kc: Created. + */ + +#ifndef SERVICES_ +#define SERVICES_ + +#include +/* + * ======== SERVICES_Exit ======== + * Purpose: + * Discontinue usage of module; free resources when reference count + * reaches 0. + * Parameters: + * Returns: + * Requires: + * SERVICES initialized. + * Ensures: + * Resources used by module are freed when cRef reaches zero. + */ + extern void SERVICES_Exit(void); + +/* + * ======== SERVICES_Init ======== + * Purpose: + * Initializes SERVICES modules. + * Parameters: + * Returns: + * TRUE if all modules initialized; otherwise FALSE. + * Requires: + * Ensures: + * SERVICES modules initialized. + */ + extern bool SERVICES_Init(void); + +#endif /* SERVICES_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/std.h b/arch/arm/plat-omap/include/dspbridge/std.h new file mode 100644 index 0000000..ec849f4 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/std.h @@ -0,0 +1,143 @@ +/* + * std.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== std.h ======== + * + *! Revision History + *! ================ + *! 16-Feb-2004 vp GNU compiler 3.x defines inline keyword. Added + *! appropriate macros not to redefine inline keyword in + *! this file. + *! 24-Oct-2002 ashu defined _TI_ and _FIXED_ symbols for 28x. + *! 24-Oct-2002 ashu defined _TI_ for 24x. + *! 01-Mar-2002 kln changed LARGE_MODEL and Arg definition for 28x + *! 01-Feb-2002 kln added definitions for 28x + *! 08-Dec-2000 kw: added 'ArgToInt' and 'ArgToPtr' macros + *! 30-Nov-2000 mf: Added _64_, _6x_; removed _7d_ + *! 30-May-2000 srid: Added __TMS320C55X__ for 55x; Arg is void * for 55 . + *! 18-Jun-1999 dr: Added '_TI_', fixed __inline for SUN4, added inline + *! 10-Feb-1999 rt: Added '55' support, changed 54's symbol to _TMS320C5XX + *! 29-Aug-1998 mf: fixed typo, removed obsolete targets + *! 08-Jun-1998 mf: _67_ is synonym for _7d_ + *! 10-Oct-1997 rt; added _7d_ for Raytheon C7DSP triggered by _TMS320C6700 + *! 04-Aug-1997 cc: added _29_ for _TMS320C2XX + *! 11-Jul-1997 dlr: _5t_, and STD_SPOXTASK keyword for Tasking + *! 12-Jun-1997 mf: _TMS320C60 -> _TMS320C6200 + *! 13-Feb-1997 mf: _62_, with 32-bit LgInt + *! 26-Nov-1996 kw: merged bios-c00's and wsx-a27's changes + *! *and* revision history + *! 12-Sep-1996 kw: added C54x #ifdef's + *! 21-Aug-1996 mf: removed #define main smain for _21_ + *! 14-May-1996 gp: def'd out INT, FLOAT, and COMPLEX defines for WSX. + *! 11-Apr-1996 kw: define _W32_ based on _WIN32 (defined by MS compiler) + *! 07-Mar-1996 mg: added Win32 support + *! 06-Sep-1995 dh: added _77_ dynamic stack support via fxns77.h + *! 27-Jun-1995 dh: added _77_ support + *! 16-Mar-1995 mf: for _21_: #define main smain + *! 01-Mar-1995 mf: set _20_ and _60_ (as well as _21_ for both) + *! 22-Feb-1995 mf: Float is float for _SUN_ and _80_ + *! 22-Dec-1994 mf: Added _80_ definition, for PP or MP. + *! 09-Dec-1994 mf: Added _53_ definition. + *! Added definitions of _30_, etc. + *! 23-Aug-1994 dh removed _21_ special case (kw) + *! 17-Aug-1994 dh added _51_ support + *! 03-Aug-1994 kw updated _80_ support + *! 30-Jun-1994 kw added _80_ support + *! 05-Apr-1994 kw: Added _SUN_ to _FLOAT_ definition + *! 01-Mar-1994 kw: Made Bool an int (was u16) for _56_ (more efficient). + *! Added _53_ support. + */ + +#ifndef STD_ +#define STD_ + +#include + +/* + * ======== _TI_ ======== + * _TI_ is defined for all TI targets + */ +#if defined(_29_) || defined(_30_) || defined(_40_) || defined(_50_) || \ + defined(_54_) || defined(_55_) || defined(_6x_) || defined(_80_) || \ + defined(_28_) || defined(_24_) +#define _TI_ 1 +#endif + +/* + * ======== _FLOAT_ ======== + * _FLOAT_ is defined for all targets that natively support floating point + */ +#if defined(_SUN_) || defined(_30_) || defined(_40_) || defined(_67_) || \ + defined(_80_) +#define _FLOAT_ 1 +#endif + +/* + * ======== _FIXED_ ======== + * _FIXED_ is defined for all fixed point target architectures + */ +#if defined(_29_) || defined(_50_) || defined(_54_) || defined(_55_) || \ + defined(_62_) || defined(_64_) || defined(_28_) +#define _FIXED_ 1 +#endif + +/* + * ======== _TARGET_ ======== + * _TARGET_ is defined for all target architectures (as opposed to + * host-side software) + */ +#if defined(_FIXED_) || defined(_FLOAT_) +#define _TARGET_ 1 +#endif + +/* + * 8, 16, 32-bit type definitions + * + * Sm* - 8-bit type + * Md* - 16-bit type + * Lg* - 32-bit type + * + * *s32 - signed type + * *u32 - unsigned type + * *Bits - unsigned type (bit-maps) + */ + +/* + * Aliases for standard C types + */ + +typedef s32(*Fxn) (void); /* generic function type */ + +#ifndef NULL +#define NULL 0 +#endif + + +/* + * These macros are used to cast 'Arg' types to 's32' or 'Ptr'. + * These macros were added for the 55x since Arg is not the same + * size as s32 and Ptr in 55x large model. + */ +#if defined(_28l_) || defined(_55l_) +#define ArgToInt(A) ((s32)((long)(A) & 0xffff)) +#define ArgToPtr(A) ((Ptr)(A)) +#else +#define ArgToInt(A) ((s32)(A)) +#define ArgToPtr(A) ((Ptr)(A)) +#endif + +#endif /* STD_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/strm.h b/arch/arm/plat-omap/include/dspbridge/strm.h new file mode 100644 index 0000000..5825615 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/strm.h @@ -0,0 +1,441 @@ +/* + * strm.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== strm.h ======== + * Description: + * DSPBridge Stream Manager. + * + * Public Functions: + * STRM_AllocateBuffer + * STRM_Close + * STRM_Create + * STRM_Delete + * STRM_Exit + * STRM_FreeBuffer + * STRM_GetEventHandle + * STRM_GetInfo + * STRM_Idle + * STRM_Init + * STRM_Issue + * STRM_Open + * STRM_PrepareBuffer + * STRM_Reclaim + * STRM_RegisterNotify + * STRM_Select + * STRM_UnprepareBuffer + * + * Notes: + * + *! Revision History: + *! ================= + *! 15-Nov-2001 ag Changed DSP_STREAMINFO to STRM_INFO in STRM_GetInfo(). + *! Added DSP_ESIZE error to STRM_AllocateBuffer(). + *! 07-Jun-2001 sg Made DSPStream_AllocateBuffer fxn name plural. + *! 10-May-2001 jeh Code review cleanup. + *! 13-Feb-2001 kc DSP/BIOS Bridge name updates. + *! 06-Feb-2001 kc Updated DBC_Ensure for STRM_Select(). + *! 23-Oct-2000 jeh Allow NULL STRM_ATTRS passed to STRM_Open(). + *! 25-Sep-2000 jeh Created. + */ + +#ifndef STRM_ +#define STRM_ + +#include + +#include + +/* + * ======== STRM_AllocateBuffer ======== + * Purpose: + * Allocate data buffer(s) for use with a stream. + * Parameter: + * hStrm: Stream handle returned from STRM_Open(). + * uSize: Size (GPP bytes) of the buffer(s). + * uNumBufs: Number of buffers to allocate. + * apBuffer: Array to hold buffer addresses. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hStrm. + * DSP_EMEMORY: Insufficient memory. + * DSP_EFAIL: Failure occurred, unable to allocate buffers. + * DSP_ESIZE: uSize must be > 0 bytes. + * Requires: + * STRM_Init(void) called. + * apBuffer != NULL. + * Ensures: + */ + extern DSP_STATUS STRM_AllocateBuffer(struct STRM_OBJECT *hStrm, + u32 uSize, + OUT u8 **apBuffer, + u32 uNumBufs); + +/* + * ======== STRM_Close ======== + * Purpose: + * Close a stream opened with STRM_Open(). + * Parameter: + * hStrm: Stream handle returned from STRM_Open(). + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hStrm. + * DSP_EPENDING: Some data buffers issued to the stream have not + * been reclaimed. + * DSP_EFAIL: Failure to close stream. + * Requires: + * STRM_Init(void) called. + * Ensures: + */ + extern DSP_STATUS STRM_Close(struct STRM_OBJECT *hStrm); + +/* + * ======== STRM_Create ======== + * Purpose: + * Create a STRM manager object. This object holds information about the + * device needed to open streams. + * Parameters: + * phStrmMgr: Location to store handle to STRM manager object on + * output. + * hDev: Device for this processor. + * Returns: + * DSP_SOK: Success; + * DSP_EMEMORY: Insufficient memory for requested resources. + * DSP_EFAIL: General failure. + * Requires: + * STRM_Init(void) called. + * phStrmMgr != NULL. + * hDev != NULL. + * Ensures: + * DSP_SOK: Valid *phStrmMgr. + * error: *phStrmMgr == NULL. + */ + extern DSP_STATUS STRM_Create(OUT struct STRM_MGR **phStrmMgr, + struct DEV_OBJECT *hDev); + +/* + * ======== STRM_Delete ======== + * Purpose: + * Delete the STRM Object. + * Parameters: + * hStrmMgr: Handle to STRM manager object from STRM_Create. + * Returns: + * Requires: + * STRM_Init(void) called. + * Valid hStrmMgr. + * Ensures: + * hStrmMgr is not valid. + */ + extern void STRM_Delete(struct STRM_MGR *hStrmMgr); + +/* + * ======== STRM_Exit ======== + * Purpose: + * Discontinue usage of STRM module. + * Parameters: + * Returns: + * Requires: + * STRM_Init(void) successfully called before. + * Ensures: + */ + extern void STRM_Exit(void); + +/* + * ======== STRM_FreeBuffer ======== + * Purpose: + * Free buffer(s) allocated with STRM_AllocateBuffer. + * Parameter: + * hStrm: Stream handle returned from STRM_Open(). + * apBuffer: Array containing buffer addresses. + * uNumBufs: Number of buffers to be freed. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid stream handle. + * DSP_EFAIL: Failure occurred, unable to free buffers. + * Requires: + * STRM_Init(void) called. + * apBuffer != NULL. + * Ensures: + */ + extern DSP_STATUS STRM_FreeBuffer(struct STRM_OBJECT *hStrm, + u8 **apBuffer, u32 uNumBufs); + +/* + * ======== STRM_GetEventHandle ======== + * Purpose: + * Get stream's user event handle. This function is used when closing + * a stream, so the event can be closed. + * Parameter: + * hStrm: Stream handle returned from STRM_Open(). + * phEvent: Location to store event handle on output. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hStrm. + * Requires: + * STRM_Init(void) called. + * phEvent != NULL. + * Ensures: + */ + extern DSP_STATUS STRM_GetEventHandle(struct STRM_OBJECT *hStrm, + OUT HANDLE *phEvent); + +/* + * ======== STRM_GetInfo ======== + * Purpose: + * Get information about a stream. User's DSP_STREAMINFO is contained + * in STRM_INFO struct. STRM_INFO also contains Bridge private info. + * Parameters: + * hStrm: Stream handle returned from STRM_Open(). + * pStreamInfo: Location to store stream info on output. + * uSteamInfoSize: Size of user's DSP_STREAMINFO structure. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hStrm. + * DSP_ESIZE: uStreamInfoSize < sizeof(DSP_STREAMINFO). + * DSP_EFAIL: Unable to get stream info. + * Requires: + * STRM_Init(void) called. + * pStreamInfo != NULL. + * Ensures: + */ + extern DSP_STATUS STRM_GetInfo(struct STRM_OBJECT *hStrm, + OUT struct STRM_INFO *pStreamInfo, + u32 uStreamInfoSize); + +/* + * ======== STRM_Idle ======== + * Purpose: + * Idle a stream and optionally flush output data buffers. + * If this is an output stream and fFlush is TRUE, all data currently + * enqueued will be discarded. + * If this is an output stream and fFlush is FALSE, this function + * will block until all currently buffered data is output, or the timeout + * specified has been reached. + * After a successful call to STRM_Idle(), all buffers can immediately + * be reclaimed. + * Parameters: + * hStrm: Stream handle returned from STRM_Open(). + * fFlush: If TRUE, discard output buffers. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hStrm. + * DSP_ETIMEOUT: A timeout occurred before the stream could be idled. + * DSP_ERESTART: A critical error occurred, DSP is being restarted. + * DSP_EFAIL: Unable to idle stream. + * Requires: + * STRM_Init(void) called. + * Ensures: + */ + extern DSP_STATUS STRM_Idle(struct STRM_OBJECT *hStrm, bool fFlush); + +/* + * ======== STRM_Init ======== + * Purpose: + * Initialize the STRM module. + * Parameters: + * Returns: + * TRUE if initialization succeeded, FALSE otherwise. + * Requires: + * Ensures: + */ + extern bool STRM_Init(void); + +/* + * ======== STRM_Issue ======== + * Purpose: + * Send a buffer of data to a stream. + * Parameters: + * hStrm: Stream handle returned from STRM_Open(). + * pBuf: Pointer to buffer of data to be sent to the stream. + * ulBytes: Number of bytes of data in the buffer. + * ulBufSize: Actual buffer size in bytes. + * dwArg: A user argument that travels with the buffer. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hStrm. + * DSP_ESTREAMFULL: The stream is full. + * DSP_EFAIL: Failure occurred, unable to issue buffer. + * Requires: + * STRM_Init(void) called. + * pBuf != NULL. + * Ensures: + */ + extern DSP_STATUS STRM_Issue(struct STRM_OBJECT *hStrm, IN u8 *pBuf, + u32 ulBytes, u32 ulBufSize, + IN u32 dwArg); + +/* + * ======== STRM_Open ======== + * Purpose: + * Open a stream for sending/receiving data buffers to/from a task of + * DAIS socket node on the DSP. + * Parameters: + * hNode: Node handle returned from NODE_Allocate(). + * uDir: DSP_TONODE or DSP_FROMNODE. + * uIndex: Stream index. + * pAttr: Pointer to structure containing attributes to be + * applied to stream. Cannot be NULL. + * phStrm: Location to store stream handle on output. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hNode. + * DSP_EDIRECTION: Invalid uDir. + * DSP_EVALUE: Invalid uIndex. + * DSP_ENODETYPE: hNode is not a task or DAIS socket node. + * DSP_EFAIL: Unable to open stream. + * Requires: + * STRM_Init(void) called. + * phStrm != NULL. + * pAttr != NULL. + * Ensures: + * DSP_SOK: *phStrm is valid. + * error: *phStrm == NULL. + */ + extern DSP_STATUS STRM_Open(struct NODE_OBJECT *hNode, u32 uDir, + u32 uIndex, IN struct STRM_ATTR *pAttr, + OUT struct STRM_OBJECT **phStrm); + +/* + * ======== STRM_PrepareBuffer ======== + * Purpose: + * Prepare a data buffer not allocated by DSPStream_AllocateBuffers() + * for use with a stream. + * Parameter: + * hStrm: Stream handle returned from STRM_Open(). + * uSize: Size (GPP bytes) of the buffer. + * pBuffer: Buffer address. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hStrm. + * DSP_EFAIL: Failure occurred, unable to prepare buffer. + * Requires: + * STRM_Init(void) called. + * pBuffer != NULL. + * Ensures: + */ + extern DSP_STATUS STRM_PrepareBuffer(struct STRM_OBJECT *hStrm, + u32 uSize, + u8 *pBuffer); + +/* + * ======== STRM_Reclaim ======== + * Purpose: + * Request a buffer back from a stream. + * Parameters: + * hStrm: Stream handle returned from STRM_Open(). + * pBufPtr: Location to store pointer to reclaimed buffer. + * pulBytes: Location where number of bytes of data in the + * buffer will be written. + * pulBufSize: Location where actual buffer size will be written. + * pdwArg: Location where user argument that travels with + * the buffer will be written. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hStrm. + * DSP_ETIMEOUT: A timeout occurred before a buffer could be + * retrieved. + * DSP_EFAIL: Failure occurred, unable to reclaim buffer. + * Requires: + * STRM_Init(void) called. + * pBufPtr != NULL. + * pulBytes != NULL. + * pdwArg != NULL. + * Ensures: + */ + extern DSP_STATUS STRM_Reclaim(struct STRM_OBJECT *hStrm, + OUT u8 **pBufPtr, u32 *pulBytes, + u32 *pulBufSize, u32 *pdwArg); + +/* + * ======== STRM_RegisterNotify ======== + * Purpose: + * Register to be notified on specific events for this stream. + * Parameters: + * hStrm: Stream handle returned by STRM_Open(). + * uEventMask: Mask of types of events to be notified about. + * uNotifyType: Type of notification to be sent. + * hNotification: Handle to be used for notification. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hStrm. + * DSP_EMEMORY: Insufficient memory on GPP. + * DSP_EVALUE: uEventMask is invalid. + * DSP_ENOTIMPL: Notification type specified by uNotifyType is not + * supported. + * Requires: + * STRM_Init(void) called. + * hNotification != NULL. + * Ensures: + */ + extern DSP_STATUS STRM_RegisterNotify(struct STRM_OBJECT *hStrm, + u32 uEventMask, u32 uNotifyType, + struct DSP_NOTIFICATION + *hNotification); + +/* + * ======== STRM_Select ======== + * Purpose: + * Select a ready stream. + * Parameters: + * aStrmTab: Array of stream handles returned from STRM_Open(). + * nStrms: Number of stream handles in array. + * pMask: Location to store mask of ready streams on output. + * uTimeout: Timeout value (milliseconds). + * Returns: + * DSP_SOK: Success. + * DSP_ERANGE: nStrms out of range. + + * DSP_EHANDLE: Invalid stream handle in array. + * DSP_ETIMEOUT: A timeout occurred before a stream became ready. + * DSP_EFAIL: Failure occurred, unable to select a stream. + * Requires: + * STRM_Init(void) called. + * aStrmTab != NULL. + * nStrms > 0. + * pMask != NULL. + * Ensures: + * DSP_SOK: *pMask != 0 || uTimeout == 0. + * Error: *pMask == 0. + */ + extern DSP_STATUS STRM_Select(IN struct STRM_OBJECT **aStrmTab, + u32 nStrms, + OUT u32 *pMask, u32 uTimeout); + +/* + * ======== STRM_UnprepareBuffer ======== + * Purpose: + * Unprepare a data buffer that was previously prepared for a stream + * with DSPStream_PrepareBuffer(), and that will no longer be used with + * the stream. + * Parameter: + * hStrm: Stream handle returned from STRM_Open(). + * uSize: Size (GPP bytes) of the buffer. + * pBuffer: Buffer address. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hStrm. + * DSP_EFAIL: Failure occurred, unable to unprepare buffer. + * Requires: + * STRM_Init(void) called. + * pBuffer != NULL. + * Ensures: + */ + extern DSP_STATUS STRM_UnprepareBuffer(struct STRM_OBJECT *hStrm, + u32 uSize, + u8 *pBuffer); + +#endif /* STRM_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/strmdefs.h b/arch/arm/plat-omap/include/dspbridge/strmdefs.h new file mode 100644 index 0000000..44d217a --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/strmdefs.h @@ -0,0 +1,57 @@ +/* + * strmdefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== strmdefs.h ======== + * Purpose: + * Global STRM constants and types. + * + *! Revision History + *! ================ + *! 19-Nov-2001 ag Added STRM_INFO.. + *! 25-Sep-2000 jeh Created. + */ + +#ifndef STRMDEFS_ +#define STRMDEFS_ + +#define STRM_MAXEVTNAMELEN 32 + + struct STRM_MGR; + + struct STRM_OBJECT; + + struct STRM_ATTR { + HANDLE hUserEvent; + char *pstrEventName; + void *pVirtBase; /* Process virtual base address of + * mapped SM */ + u32 ulVirtSize; /* Size of virtual space in bytes */ + struct DSP_STREAMATTRIN *pStreamAttrIn; + } ; + + struct STRM_INFO { + enum DSP_STRMMODE lMode; /* transport mode of + * stream(DMA, ZEROCOPY..) */ + u32 uSegment; /* Segment strm allocs from. 0 is local mem */ + void *pVirtBase; /* " " Stream'process virt base */ + struct DSP_STREAMINFO *pUser; /* User's stream information + * returned */ + } ; + +#endif /* STRMDEFS_ */ + diff --git a/arch/arm/plat-omap/include/dspbridge/sync.h b/arch/arm/plat-omap/include/dspbridge/sync.h new file mode 100644 index 0000000..fa3ff8d --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/sync.h @@ -0,0 +1,340 @@ +/* + * sync.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== sync.h ======== + * Purpose: + * Provide synchronization services. + * + * Public Functions: + * SYNC_CloseEvent + * SYNC_DeleteCS + * SYNC_EnterCS + * SYNC_Exit + * SYNC_Init + * SYNC_InitializeCS + * SYNC_LeaveCS + * SYNC_OpenEvent + * SYNC_PostMessage + * SYNC_ResetEvent + * SYNC_SetEvent + * SYNC_WaitOnEvent + * SYNC_WaitOnMultipleEvents + * + *! Revision History: + *! ================ + *! 05-Oct-2000 jeh Added SYNC_WaitOnMultipleEvents(). + *! 01-Dec-1999 ag: Added #define SYNC_MAXNAMELENGTH. + *! 04-Nov-1999 kc: Added critical section functions and objects to SYNC. + *! 29-Oct-1999 kc: Cleaned up for code review. + *! 24-Sep-1999 kc: Added WinCE notes. + *! 20-Oct-1997 gp: Removed unused SYNC_ critical section and must complete fxns + *! Added SYNC_HOBJECT, SYNC_ATTRS, and object validation, and + *! merged SYNC_DestroyEvent into SYNC_CloseEvent, and merged + *! SYNC_CreateEvent into SYNC_OpenEvent. + *! 07-Oct-1997 gp: Added SYNC_Create/DestroyEvent (for NT testing). + *! 06-Oct-1997 gp: Added SYNC_OpenEvent. + *! 03-Jun-1997 gp: Added SYNC_{Begin|End}CritSection() functions. + *! 03-Jan-1997 gp: Added SYNC_INFINITE define. + *! 05-Aug-1996 gp: Created. + */ + +#ifndef _SYNC_H +#define _SYNC_H + +#define SIGNATURECS 0x53435953 /* "SYCS" (in reverse) */ +#define SIGNATUREDPCCS 0x53445953 /* "SYDS" (in reverse) */ + +/* Special timeout value indicating an infinite wait: */ +#define SYNC_INFINITE 0xffffffff + +/* Maximum string length of a named event */ +#define SYNC_MAXNAMELENGTH 32 + +/* Generic SYNC object: */ + struct SYNC_OBJECT; + +/* Generic SYNC CS object: */ +struct SYNC_CSOBJECT { + u32 dwSignature; /* used for object validation */ + struct semaphore sem; +} ; + +/* SYNC object attributes: */ + struct SYNC_ATTRS { + HANDLE hUserEvent; /* Platform's User Mode synch. object. */ + HANDLE hKernelEvent; /* Platform's Kernel Mode sync. object. */ + u32 dwReserved1; /* For future expansion. */ + u32 dwReserved2; /* For future expansion. */ + } ; + +/* + * ======== SYNC_CloseEvent ======== + * Purpose: + * Close this event handle, freeing resources allocated in SYNC_OpenEvent + * if necessary. + * Parameters: + * hEvent: Handle to a synchronization event, created/opened in + * SYNC_OpenEvent. + * Returns: + * DSP_SOK: Success; + * DSP_EFAIL: Failed to close event handle. + * DSP_EHANDLE: Invalid handle. + * Requires: + * SYNC initialized. + * Ensures: + * Any subsequent usage of hEvent would be invalid. + */ + extern DSP_STATUS SYNC_CloseEvent(IN struct SYNC_OBJECT *hEvent); + +/* + * ======== SYNC_DeleteCS ======== + * Purpose: + * Delete a critical section. + * Parameters: + * hCSObj: critical section handle. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid handle. + * Requires: + * Ensures: + */ + extern DSP_STATUS SYNC_DeleteCS(IN struct SYNC_CSOBJECT *hCSObj); + +/* + * ======== SYNC_EnterCS ======== + * Purpose: + * Enter the critical section. + * Parameters: + * hCSObj: critical section handle. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid handle. + * Requires: + * Ensures: + */ + extern DSP_STATUS SYNC_EnterCS(IN struct SYNC_CSOBJECT *hCSObj); + +/* + * ======== SYNC_Exit ======== + * Purpose: + * Discontinue usage of module; free resources when reference count + * reaches 0. + * Parameters: + * Returns: + * Requires: + * SYNC initialized. + * Ensures: + * Resources used by module are freed when cRef reaches zero. + */ + extern void SYNC_Exit(void); + +/* + * ======== SYNC_Init ======== + * Purpose: + * Initializes private state of SYNC module. + * Parameters: + * Returns: + * TRUE if initialized; FALSE if error occured. + * Requires: + * Ensures: + * SYNC initialized. + */ + extern bool SYNC_Init(void); + +/* + * ======== SYNC_InitializeCS ======== + * Purpose: + * Initialize the critical section. + * Parameters: + * hCSObj: critical section handle. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Out of memory. + * Requires: + * Ensures: + */ + extern DSP_STATUS SYNC_InitializeCS(OUT struct SYNC_CSOBJECT **phCSObj); + +/* + * ======== SYNC_InitializeDPCCS ======== + * Purpose: + * Initialize the critical section between process context and DPC. + * Parameters: + * hCSObj: critical section handle. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Out of memory. + * Requires: + * Ensures: + */ + extern DSP_STATUS SYNC_InitializeDPCCS(OUT struct SYNC_CSOBJECT + **phCSObj); + +/* + * ======== SYNC_LeaveCS ======== + * Purpose: + * Leave the critical section. + * Parameters: + * hCSObj: critical section handle. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid handle. + * Requires: + * Ensures: + */ + extern DSP_STATUS SYNC_LeaveCS(IN struct SYNC_CSOBJECT *hCSObj); + +/* + * ======== SYNC_OpenEvent ======== + * Purpose: + * Create/open and initialize an event object for thread synchronization, + * which is initially in the non-signalled state. + * Parameters: + * phEvent: Pointer to location to receive the event object handle. + * pAttrs: Pointer to SYNC_ATTRS object containing initial SYNC + * SYNC_OBJECT attributes. If this pointer is NULL, then + * SYNC_OpenEvent will create and manage an OS specific + * syncronization object. + * pAttrs->hUserEvent: Platform's User Mode synchronization object. + * + * The behaviour of the SYNC methods depend on the value of + * the hUserEvent attr: + * + * 1. (hUserEvent == NULL): + * A user mode event is created. + * 2. (hUserEvent != NULL): + * A user mode event is supplied by the caller of SYNC_OpenEvent(). + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Unable to create user mode event. + * DSP_EMEMORY: Insufficient memory. + * DSP_EINVALIDARG SYNC_ATTRS values are invalid. + * Requires: + * - SYNC initialized. + * - phEvent != NULL. + * Ensures: + * If function succeeded, pEvent->hEvent must be a valid event handle. + */ + extern DSP_STATUS SYNC_OpenEvent(OUT struct SYNC_OBJECT **phEvent, + IN OPTIONAL struct SYNC_ATTRS + *pAttrs); + +/* + * ========= SYNC_PostMessage ======== + * Purpose: + * To post a windows message + * Parameters: + * hWindow: Handle to the window + * uMsg: Message to be posted + * Returns: + * DSP_SOK: Success + * DSP_EFAIL: Post message failed + * DSP_EHANDLE: Invalid Window handle + * Requires: + * SYNC initialized + * Ensures + */ + extern DSP_STATUS SYNC_PostMessage(IN HANDLE hWindow, IN u32 uMsg); + +/* + * ======== SYNC_ResetEvent ======== + * Purpose: + * Reset a syncronization event object state to non-signalled. + * Parameters: + * hEvent: Handle to a sync event. + * Returns: + * DSP_SOK: Success; + * DSP_EFAIL: Failed to reset event. + * DSP_EHANDLE: Invalid handle. + * Requires: + * SYNC initialized. + * Ensures: + */ + extern DSP_STATUS SYNC_ResetEvent(IN struct SYNC_OBJECT *hEvent); + +/* + * ======== SYNC_SetEvent ======== + * Purpose: + * Signal the event. Will unblock one waiting thread. + * Parameters: + * hEvent: Handle to an event object. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Failed to signal event. + * DSP_EHANDLE: Invalid handle. + * Requires: + * SYNC initialized. + * Ensures: + */ + extern DSP_STATUS SYNC_SetEvent(IN struct SYNC_OBJECT *hEvent); + +/* + * ======== SYNC_WaitOnEvent ======== + * Purpose: + * Wait for an event to be signalled, up to the specified timeout. + * Parameters: + * hEvent: Handle to an event object. + * dwTimeOut: The time-out interval, in milliseconds. + * The function returns if the interval elapses, even if + * the object's state is nonsignaled. + * If zero, the function tests the object's state and + * returns immediately. + * If SYNC_INFINITE, the function's time-out interval + * never elapses. + * Returns: + * DSP_SOK: The object was signalled. + * DSP_EHANDLE: Invalid handle. + * SYNC_E_FAIL: Wait failed, possibly because the process terminated. + * SYNC_E_TIMEOUT: Timeout expired while waiting for event to be signalled. + * Requires: + * Ensures: + */ + extern DSP_STATUS SYNC_WaitOnEvent(IN struct SYNC_OBJECT *hEvent, + IN u32 dwTimeOut); + +/* + * ======== SYNC_WaitOnMultipleEvents ======== + * Purpose: + * Wait for any of an array of events to be signalled, up to the + * specified timeout. + * Note: dwTimeOut must be SYNC_INFINITE to signal infinite wait. + * Parameters: + * hSyncEvents: Array of handles to event objects. + * uCount: Number of event handles. + * dwTimeOut: The time-out interval, in milliseconds. + * The function returns if the interval elapses, even if + * no event is signalled. + * If zero, the function tests the object's state and + * returns immediately. + * If SYNC_INFINITE, the function's time-out interval + * never elapses. + * puIndex: Location to store index of event that was signalled. + * Returns: + * DSP_SOK: The object was signalled. + * SYNC_E_FAIL: Wait failed, possibly because the process terminated. + * SYNC_E_TIMEOUT: Timeout expired before event was signalled. + * DSP_EMEMORY: Memory allocation failed. + * Requires: + * Ensures: + */ + extern DSP_STATUS SYNC_WaitOnMultipleEvents(IN struct SYNC_OBJECT + **hSyncEvents, + IN u32 uCount, + IN u32 dwTimeout, + OUT u32 *puIndex); + +#endif /* _SYNC_H */ diff --git a/arch/arm/plat-omap/include/dspbridge/util.h b/arch/arm/plat-omap/include/dspbridge/util.h new file mode 100644 index 0000000..e6815ca --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/util.h @@ -0,0 +1,122 @@ +/* + * util.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== util.h ======== + * Purpose: + * Provide general purpose utility functions. + * + * Public Functions: + * UTIL_CDTestDll + * UTIL_CmdLineToArgs + * UTIL_Exit + * UTIL_GetSysInfo + * UTIL_Init + */ + +#ifndef _UTIL_H +#define _UTIL_H + +#include +#include + +#include + +/* + * ======== UTIL_CDTestDll ======== + * Purpose: + * Provides test entry point in class driver context. + * Parameters: + * cArgc: test module command line input count. + * ppArgv: test module command line args. + * Returns: + * 0 if successful, a negative value otherwise. + * Requires: + * UTIL initialized. + * Ensures: + */ + extern u32 UTIL_CDTestDll(IN s32 cArgc, IN char **ppArgv); + +/* + * ======== UTIL_CmdLineToArgs ======== + * Purpose: + * This function re-creates C-style cmd line argc & argv from WinMain() + * cmd line args. + * Parameters: + * s8 *pszProgName - The name of the program currently being executed. + * s8 *argv[] - The argument vector. + * s8 *pCmdLine - The pointer to the command line. + * bool fHasProgName - Indicats whether a program name is supplied. + * Returns: + * Returns the number of arguments found. + * Requires: + * UTIL initialized. + * Ensures: + */ + extern s32 UTIL_CmdLineToArgs(IN char *pszProgName, + IN char *argv[UTIL_MAXARGVS], + IN char *pCmdLine, IN bool fHasProgName); + +/* + * ======== UTIL_Exit ======== + * Purpose: + * Discontinue usage of module; free resources when reference count + * reaches 0. + * Parameters: + * Returns: + * Requires: + * UTIL initialized. + * Ensures: + * Resources used by module are freed when cRef reaches zero. + */ + extern inline void UTIL_Exit(void) + { + } +/* + * ======== UTIL_GetSysInfo ======== + * Purpose: + * This function return platform specific system information. + * + * Parameters: + * pSysInfo - address to store the system information. + * Returns: + * DSP_SOK + * S_FAIL + * Requires: + * UTIL initialized. + * pSysInfo != NULL + * Ensures: + */ + extern DSP_STATUS UTIL_GetSysInfo(OUT struct UTIL_SYSINFO *pSysInfo); + +/* + * ======== UTIL_Init ======== + * Purpose: + * Initializes private state of UTIL module. + * Parameters: + * Returns: + * TRUE if success, else FALSE. + * Requires: + * Ensures: + * UTIL initialized. + */ + extern inline bool UTIL_Init(void) + { + return true; + } + +#endif /* _UTIL_H */ diff --git a/arch/arm/plat-omap/include/dspbridge/utildefs.h b/arch/arm/plat-omap/include/dspbridge/utildefs.h new file mode 100644 index 0000000..bd53a5a --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/utildefs.h @@ -0,0 +1,51 @@ +/* + * utildefs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== utildefs.h ======== + * Purpose: + * Global UTIL constants and types, shared between WCD and DSPSYS. + * + *! Revision History: + *! ================ + *! 24-Feb-2003 kc Removed wIOPort* entries from UTIL_HOSTCONFIG. + *! 12-Aug-2000 ag Added UTIL_SYSINFO typedef. + *! 08-Oct-1999 rr Adopted for WinCE where test fxns will be added in util.h + *! 26-Dec-1996 cr Created. + */ + +#ifndef UTILDEFS_ +#define UTILDEFS_ + +/* constants taken from configmg.h */ +#define UTIL_MAXMEMREGS 9 +#define UTIL_MAXIOPORTS 20 +#define UTIL_MAXIRQS 7 +#define UTIL_MAXDMACHNLS 7 + +/* misc. constants */ +#define UTIL_MAXARGVS 10 + +/* Platform specific important info */ + struct UTIL_SYSINFO { + /* Granularity of page protection; usually 1k or 4k */ + u32 dwPageSize; + u32 dwAllocationGranularity; /* VM granularity, usually 64K */ + u32 dwNumberOfProcessors; /* Used as sanity check */ + } ; + +#endif /* UTILDEFS_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/uuidutil.h b/arch/arm/plat-omap/include/dspbridge/uuidutil.h new file mode 100644 index 0000000..af4aaec --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/uuidutil.h @@ -0,0 +1,74 @@ +/* + * uuidutil.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== uuidutil.h ======== + * Description: + * This file contains the specification of UUID helper functions. + * + *! Revision History + *! ================ + *! 09-Nov-2000 kc: Modified description of UUID utility functions. + *! 29-Sep-2000 kc: Appended "UUID_" prefix to UUID helper functions. + *! 10-Aug-2000 kc: Created. + *! + */ + +#ifndef UUIDUTIL_ +#define UUIDUTIL_ + +#define MAXUUIDLEN 37 + +/* + * ======== UUID_UuidToString ======== + * Purpose: + * Converts a DSP_UUID to an ANSI string. + * Parameters: + * pUuid: Pointer to a DSP_UUID object. + * pszUuid: Pointer to a buffer to receive a NULL-terminated UUID + * string. + * size: Maximum size of the pszUuid string. + * Returns: + * Requires: + * pUuid & pszUuid are non-NULL values. + * Ensures: + * Lenghth of pszUuid is less than MAXUUIDLEN. + * Details: + * UUID string limit currently set at MAXUUIDLEN. + */ + void UUID_UuidToString(IN struct DSP_UUID *pUuid, OUT char *pszUuid, + s32 size); + +/* + * ======== UUID_UuidFromString ======== + * Purpose: + * Converts an ANSI string to a DSP_UUID. + * Parameters: + * pszUuid: Pointer to a string that represents a DSP_UUID object. + * pUuid: Pointer to a DSP_UUID object. + * Returns: + * Requires: + * pUuid & pszUuid are non-NULL values. + * Ensures: + * Details: + * We assume the string representation of a UUID has the following format: + * "12345678_1234_1234_1234_123456789abc". + */ + extern void UUID_UuidFromString(IN char *pszUuid, + OUT struct DSP_UUID *pUuid); + +#endif /* UUIDUTIL_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/wcd.h b/arch/arm/plat-omap/include/dspbridge/wcd.h new file mode 100644 index 0000000..5a7d47a --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/wcd.h @@ -0,0 +1,61 @@ +/* + * wcd.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== wcd.h ======== + * Description: + * 'Bridge class driver library functions, object definitions, and + * return error/status codes. To be included by 'Bridge mini drivers. + * + * Public Functions: + * See mem.h and dbg.h. + * + * Notes: + * 'Bridge Class Driver services exported to WMD's are initialized by the + * WCD on behalf of the WMD. WMD's must not call module Init/Exit + * functions. + * + * To ensure WMD binary compatibility across different platforms, + * for the same processor, a WMD must restrict its usage of system + * services to those exported by the 'Bridge class library. + * + *! Revision History: + *! ================ + *! 07-Jun-2000 jeh Added dev.h + *! 01-Nov-1999 ag: #WINCE# WCD_MAJOR_VERSION=8 & WCD_MINOR_VERSION=0 to match + *! dll stamps. + *! 0.80 - 0.89 Alpha, 0.90 - 0.99 Beta, 1.00 - 1.10 FCS. + *! 17-Sep-1997 gp: Changed size of CFG_HOSTRES structure; and ISR_Install API; + *! Changed WCD_MINOR_VERSION 3 -> 4. + *! 15-Sep-1997 gp: Moved WCD_(Un)registerMinidriver to drv. + *! 25-Jul-1997 cr: Added WCD_UnregisterMinidriver. + *! 22-Jul-1997 cr: Added WCD_RegisterMinidriver, WCD_MINOR_VERSION 2 -> 3. + *! 12-Nov-1996 gp: Defined port io macros. + *! 07-Nov-1996 gp: Updated for code review. + *! 16-Jul-1996 gp: Added CHNL fxns; updated WCD lib version to 2. + *! 10-May-1996 gp: Separated WMD def.s' into wmd.h. + *! 03-May-1996 gp: Created. + */ + +#ifndef WCD_ +#define WCD_ + +/* This WCD Library Version: */ +#define WCD_MAJOR_VERSION (u32)8 /* .8x - Alpha, .9x - Beta, 1.x FCS */ +#define WCD_MINOR_VERSION (u32)0 + +#endif /* WCD_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/wcdioctl.h b/arch/arm/plat-omap/include/dspbridge/wcdioctl.h new file mode 100644 index 0000000..04b13ab --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/wcdioctl.h @@ -0,0 +1,519 @@ +/* + * wcdioctl.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== wcdioctl.h ======== + * Purpose: + * Contains structures and commands that are used for interaction + * between the DDSP API and class driver. + * + *! Revision History + *! ================ + *! 19-Apr-2004 sb Aligned DMM definitions with Symbian + *! 08-Mar-2004 sb Added the Dynamic Memory Mapping structs & offsets + *! 15-Oct-2002 kc Updated definitions for private PERF module. + *! 16-Aug-2002 map Added ARGS_MGR_REGISTEROBJECT & ARGS_MGR_UNREGISTEROBJECT + *! Added CMD_MGR_REGISTEROBJECT_OFFSET & + *! CMD_MGR_UNREGISTEROBJECT_OFFSET + *! 15-Jan-2002 ag Added actaul bufSize to ARGS_STRM_[RECLAIM][ISSUE]. + *! 15-Nov-2001 ag change to STRMINFO in ARGS_STRM_GETINFO. + *! 11-Sep-2001 ag ARGS_CMM_GETHANDLE defn uses DSP_HPROCESSOR. + *! 23-Apr-2001 jeh Added pStatus to NODE_TERMINATE args. + *! 13-Feb-2001 kc DSP/BIOS Bridge name updates. + *! 22-Nov-2000 kc: Added CMD_MGR_GETPERF_DATA_OFFSET for acquiring PERF stats. + *! 27-Oct-2000 jeh Added timeouts to NODE_GETMESSAGE, NODE_PUTMESSAGE args. + *! Removed NODE_GETMESSAGESTRM args. + *! 11-Oct-2000 ag: Added SM mgr(CMM) args. + *! 27-Sep-2000 jeh Removed struct DSP_BUFFERATTR param from + *! ARGS_STRM_ALLOCATEBUFFER. + *! 25-Sep-2000 rr: Updated to Version 0.9 + *! 07-Sep-2000 jeh Changed HANDLE to DSP_HNOTIFICATION in RegisterNotify args. + *! Added DSP_STRMATTR to DSPNode_Connect args. + *! 04-Aug-2000 rr: MEM and UTIL added to RM. + *! 27-Jul-2000 rr: NODE, MGR,STRM and PROC added + *! 27-Jun-2000 rr: Modifed to Use either PM or DSP/BIOS Bridge + *! IFDEF to build for PM or DSP/BIOS Bridge + *! 28-Jan-2000 rr: NT_CMD_FROM_OFFSET moved out to dsptrap.h + *! 24-Jan-2000 rr: Merged with Scott's code. + *! 21-Jan-2000 sg: In ARGS_CHNL_GETMODE changed mode to be u32 to be + *! consistent with chnldefs.h. + *! 11-Jan-2000 rr: CMD_CFG_GETCDVERSION_OFFSET added. + *! 12-Nov-1999 rr: CMD_BRD_MONITOR_OFFSET added + *! 09-Nov-1999 kc: Added MEMRY and enabled CMD_BRD_IOCTL_OFFSET. + *! 05-Nov-1999 ag: Added CHNL. + *! 02-Nov-1999 kc: Removed field from ARGS_UTIL_TESTDLL. + *! 29-Oct-1999 kc: Cleaned up for code review. + *! 08-Oct-1999 rr: Util control offsets added. + *! 13-Sep-1999 kc: Added ARGS_UTIL_TESTDLL for PM test infrastructure. + *! 19-Aug-1999 rr: Created from WSX. Minimal Implementaion of BRD_Start and BRD + *! and BRD_Stop. IOCTL Offsets and CTRL Code. + */ + +#ifndef WCDIOCTL_ +#define WCDIOCTL_ + +#include +#include +#include +#include + +union Trapped_Args { + + /* MGR Module */ + struct { + u32 uNode; + struct DSP_NDBPROPS __user *pNDBProps; + u32 uNDBPropsSize; + u32 __user *puNumNodes; + } ARGS_MGR_ENUMNODE_INFO; + + struct { + u32 uProcessor; + struct DSP_PROCESSORINFO __user *pProcessorInfo; + u32 uProcessorInfoSize; + u32 __user *puNumProcs; + } ARGS_MGR_ENUMPROC_INFO; + + struct { + struct DSP_UUID *pUuid; + enum DSP_DCDOBJTYPE objType; + char *pszPathName; + } ARGS_MGR_REGISTEROBJECT; + + struct { + struct DSP_UUID *pUuid; + enum DSP_DCDOBJTYPE objType; + } ARGS_MGR_UNREGISTEROBJECT; + + struct { + struct DSP_NOTIFICATION __user*__user *aNotifications; + u32 uCount; + u32 __user *puIndex; + u32 uTimeout; + } ARGS_MGR_WAIT; + + /* PROC Module */ + struct { + u32 uProcessor; + struct DSP_PROCESSORATTRIN __user *pAttrIn; + DSP_HPROCESSOR __user *phProcessor; + } ARGS_PROC_ATTACH; + + struct { + DSP_HPROCESSOR hProcessor; + u32 dwCmd; + struct DSP_CBDATA __user *pArgs; + } ARGS_PROC_CTRL; + + struct { + DSP_HPROCESSOR hProcessor; + } ARGS_PROC_DETACH; + + struct { + DSP_HPROCESSOR hProcessor; + DSP_HNODE __user *aNodeTab; + u32 uNodeTabSize; + u32 __user *puNumNodes; + u32 __user *puAllocated; + } ARGS_PROC_ENUMNODE_INFO; + + struct { + DSP_HPROCESSOR hProcessor; + u32 uResourceType; + struct DSP_RESOURCEINFO *pResourceInfo; + u32 uResourceInfoSize; + } ARGS_PROC_ENUMRESOURCES; + + struct { + DSP_HPROCESSOR hProcessor; + struct DSP_PROCESSORSTATE __user *pProcStatus; + u32 uStateInfoSize; + } ARGS_PROC_GETSTATE; + + struct { + DSP_HPROCESSOR hProcessor; + u8 __user *pBuf; + + #ifndef RES_CLEANUP_DISABLE + u8 __user *pSize; + #endif + u32 uMaxSize; + } ARGS_PROC_GETTRACE; + + struct { + DSP_HPROCESSOR hProcessor; + s32 iArgc; + char __user*__user *aArgv; + char *__user *aEnvp; + } ARGS_PROC_LOAD; + + struct { + DSP_HPROCESSOR hProcessor; + u32 uEventMask; + u32 uNotifyType; + struct DSP_NOTIFICATION __user *hNotification; + } ARGS_PROC_REGISTER_NOTIFY; + + struct { + DSP_HPROCESSOR hProcessor; + } ARGS_PROC_START; + + struct { + DSP_HPROCESSOR hProcessor; + u32 ulSize; + void *__user *ppRsvAddr; + } ARGS_PROC_RSVMEM; + + struct { + DSP_HPROCESSOR hProcessor; + u32 ulSize; + void *pRsvAddr; + } ARGS_PROC_UNRSVMEM; + + struct { + DSP_HPROCESSOR hProcessor; + void *pMpuAddr; + u32 ulSize; + void *pReqAddr; + void *__user *ppMapAddr; + u32 ulMapAttr; + } ARGS_PROC_MAPMEM; + + struct { + DSP_HPROCESSOR hProcessor; + u32 ulSize; + void *pMapAddr; + } ARGS_PROC_UNMAPMEM; + + struct { + DSP_HPROCESSOR hProcessor; + void *pMpuAddr; + u32 ulSize; + u32 ulFlags; + } ARGS_PROC_FLUSHMEMORY; + + struct { + DSP_HPROCESSOR hProcessor; + } ARGS_PROC_STOP; + + struct { + DSP_HPROCESSOR hProcessor; + void *pMpuAddr; + u32 ulSize; + } ARGS_PROC_INVALIDATEMEMORY; + + + /* NODE Module */ + struct { + DSP_HPROCESSOR hProcessor; + struct DSP_UUID __user *pNodeID; + struct DSP_CBDATA __user *pArgs; + struct DSP_NODEATTRIN __user *pAttrIn; + DSP_HNODE __user *phNode; + } ARGS_NODE_ALLOCATE; + + struct { + DSP_HNODE hNode; + u32 uSize; + struct DSP_BUFFERATTR __user *pAttr; + u8 *__user *pBuffer; + } ARGS_NODE_ALLOCMSGBUF; + + struct { + DSP_HNODE hNode; + s32 iPriority; + } ARGS_NODE_CHANGEPRIORITY; + + struct { + DSP_HNODE hNode; + u32 uStream; + DSP_HNODE hOtherNode; + u32 uOtherStream; + struct DSP_STRMATTR __user *pAttrs; + struct DSP_CBDATA __user *pConnParam; + } ARGS_NODE_CONNECT; + + struct { + DSP_HNODE hNode; + } ARGS_NODE_CREATE; + + struct { + DSP_HNODE hNode; + } ARGS_NODE_DELETE; + + struct { + DSP_HNODE hNode; + struct DSP_BUFFERATTR __user *pAttr; + u8 *pBuffer; + } ARGS_NODE_FREEMSGBUF; + + struct { + DSP_HNODE hNode; + struct DSP_NODEATTR __user *pAttr; + u32 uAttrSize; + } ARGS_NODE_GETATTR; + + struct { + DSP_HNODE hNode; + struct DSP_MSG __user *pMessage; + u32 uTimeout; + } ARGS_NODE_GETMESSAGE; + + struct { + DSP_HNODE hNode; + } ARGS_NODE_PAUSE; + + struct { + DSP_HNODE hNode; + struct DSP_MSG __user *pMessage; + u32 uTimeout; + } ARGS_NODE_PUTMESSAGE; + + struct { + DSP_HNODE hNode; + u32 uEventMask; + u32 uNotifyType; + struct DSP_NOTIFICATION __user *hNotification; + } ARGS_NODE_REGISTERNOTIFY; + + struct { + DSP_HNODE hNode; + } ARGS_NODE_RUN; + + struct { + DSP_HNODE hNode; + DSP_STATUS __user *pStatus; + } ARGS_NODE_TERMINATE; + + struct { + DSP_HPROCESSOR hProcessor; + struct DSP_UUID __user *pNodeID; + struct DSP_NDBPROPS __user *pNodeProps; + } ARGS_NODE_GETUUIDPROPS; + + /* STRM module */ + + struct { + DSP_HSTREAM hStream; + u32 uSize; + u8 *__user *apBuffer; + u32 uNumBufs; + } ARGS_STRM_ALLOCATEBUFFER; + + struct { + DSP_HSTREAM hStream; + } ARGS_STRM_CLOSE; + + struct { + DSP_HSTREAM hStream; + u8 *__user *apBuffer; + u32 uNumBufs; + } ARGS_STRM_FREEBUFFER; + + struct { + DSP_HSTREAM hStream; + HANDLE *phEvent; + } ARGS_STRM_GETEVENTHANDLE; + + struct { + DSP_HSTREAM hStream; + struct STRM_INFO __user *pStreamInfo; + u32 uStreamInfoSize; + } ARGS_STRM_GETINFO; + + struct { + DSP_HSTREAM hStream; + bool bFlush; + } ARGS_STRM_IDLE; + + struct { + DSP_HSTREAM hStream; + u8 *pBuffer; + u32 dwBytes; + u32 dwBufSize; + u32 dwArg; + } ARGS_STRM_ISSUE; + + struct { + DSP_HNODE hNode; + u32 uDirection; + u32 uIndex; + struct STRM_ATTR __user *pAttrIn; + DSP_HSTREAM __user *phStream; + } ARGS_STRM_OPEN; + + struct { + DSP_HSTREAM hStream; + u8 *__user *pBufPtr; + u32 __user *pBytes; + u32 __user *pBufSize; + u32 __user *pdwArg; + } ARGS_STRM_RECLAIM; + + struct { + DSP_HSTREAM hStream; + u32 uEventMask; + u32 uNotifyType; + struct DSP_NOTIFICATION __user *hNotification; + } ARGS_STRM_REGISTERNOTIFY; + + struct { + DSP_HSTREAM __user *aStreamTab; + u32 nStreams; + u32 __user *pMask; + u32 uTimeout; + } ARGS_STRM_SELECT; + + /* CMM Module */ + struct { + struct CMM_OBJECT *hCmmMgr; + u32 uSize; + struct CMM_ATTRS *pAttrs; + OUT void **ppBufVA; + } ARGS_CMM_ALLOCBUF; + + struct { + struct CMM_OBJECT *hCmmMgr; + void *pBufPA; + u32 ulSegId; + } ARGS_CMM_FREEBUF; + + struct { + DSP_HPROCESSOR hProcessor; + struct CMM_OBJECT *__user *phCmmMgr; + } ARGS_CMM_GETHANDLE; + + struct { + struct CMM_OBJECT *hCmmMgr; + struct CMM_INFO __user *pCmmInfo; + } ARGS_CMM_GETINFO; + + /* MEM Module */ + struct { + u32 cBytes; + enum MEM_POOLATTRS type; + void *pMem; + } ARGS_MEM_ALLOC; + + struct { + u32 cBytes; + enum MEM_POOLATTRS type; + void *pMem; + } ARGS_MEM_CALLOC; + + struct { + void *pMem; + } ARGS_MEM_FREE; + + struct { + void *pBuffer; + u32 cSize; + void *pLockedBuffer; + } ARGS_MEM_PAGELOCK; + + struct { + void *pBuffer; + u32 cSize; + } ARGS_MEM_PAGEUNLOCK; + + /* UTIL module */ + struct { + s32 cArgc; + char **ppArgv; + } ARGS_UTIL_TESTDLL; +} ; + +#define CMD_BASE 1 + +/* MGR module offsets */ +#define CMD_MGR_BASE_OFFSET CMD_BASE +#define CMD_MGR_ENUMNODE_INFO_OFFSET (CMD_MGR_BASE_OFFSET + 0) +#define CMD_MGR_ENUMPROC_INFO_OFFSET (CMD_MGR_BASE_OFFSET + 1) +#define CMD_MGR_REGISTEROBJECT_OFFSET (CMD_MGR_BASE_OFFSET + 2) +#define CMD_MGR_UNREGISTEROBJECT_OFFSET (CMD_MGR_BASE_OFFSET + 3) +#define CMD_MGR_WAIT_OFFSET (CMD_MGR_BASE_OFFSET + 4) + +#ifndef RES_CLEANUP_DISABLE +#define CMD_MGR_RESOUCES_OFFSET (CMD_MGR_BASE_OFFSET + 5) +#define CMD_MGR_END_OFFSET CMD_MGR_RESOUCES_OFFSET +#else +#define CMD_MGR_END_OFFSET CMD_MGR_WAIT_OFFSET +#endif + +#define CMD_PROC_BASE_OFFSET (CMD_MGR_END_OFFSET + 1) +#define CMD_PROC_ATTACH_OFFSET (CMD_PROC_BASE_OFFSET + 0) +#define CMD_PROC_CTRL_OFFSET (CMD_PROC_BASE_OFFSET + 1) +#define CMD_PROC_DETACH_OFFSET (CMD_PROC_BASE_OFFSET + 2) +#define CMD_PROC_ENUMNODE_OFFSET (CMD_PROC_BASE_OFFSET + 3) +#define CMD_PROC_ENUMRESOURCES_OFFSET (CMD_PROC_BASE_OFFSET + 4) +#define CMD_PROC_GETSTATE_OFFSET (CMD_PROC_BASE_OFFSET + 5) +#define CMD_PROC_GETTRACE_OFFSET (CMD_PROC_BASE_OFFSET + 6) +#define CMD_PROC_LOAD_OFFSET (CMD_PROC_BASE_OFFSET + 7) +#define CMD_PROC_REGISTERNOTIFY_OFFSET (CMD_PROC_BASE_OFFSET + 8) +#define CMD_PROC_START_OFFSET (CMD_PROC_BASE_OFFSET + 9) +#define CMD_PROC_RSVMEM_OFFSET (CMD_PROC_BASE_OFFSET + 10) +#define CMD_PROC_UNRSVMEM_OFFSET (CMD_PROC_BASE_OFFSET + 11) +#define CMD_PROC_MAPMEM_OFFSET (CMD_PROC_BASE_OFFSET + 12) +#define CMD_PROC_UNMAPMEM_OFFSET (CMD_PROC_BASE_OFFSET + 13) +#define CMD_PROC_FLUSHMEMORY_OFFSET (CMD_PROC_BASE_OFFSET + 14) +#define CMD_PROC_STOP_OFFSET (CMD_PROC_BASE_OFFSET + 15) +#define CMD_PROC_INVALIDATEMEMORY_OFFSET (CMD_PROC_BASE_OFFSET + 16) +#define CMD_PROC_END_OFFSET CMD_PROC_INVALIDATEMEMORY_OFFSET + + +#define CMD_NODE_BASE_OFFSET (CMD_PROC_END_OFFSET + 1) +#define CMD_NODE_ALLOCATE_OFFSET (CMD_NODE_BASE_OFFSET + 0) +#define CMD_NODE_ALLOCMSGBUF_OFFSET (CMD_NODE_BASE_OFFSET + 1) +#define CMD_NODE_CHANGEPRIORITY_OFFSET (CMD_NODE_BASE_OFFSET + 2) +#define CMD_NODE_CONNECT_OFFSET (CMD_NODE_BASE_OFFSET + 3) +#define CMD_NODE_CREATE_OFFSET (CMD_NODE_BASE_OFFSET + 4) +#define CMD_NODE_DELETE_OFFSET (CMD_NODE_BASE_OFFSET + 5) +#define CMD_NODE_FREEMSGBUF_OFFSET (CMD_NODE_BASE_OFFSET + 6) +#define CMD_NODE_GETATTR_OFFSET (CMD_NODE_BASE_OFFSET + 7) +#define CMD_NODE_GETMESSAGE_OFFSET (CMD_NODE_BASE_OFFSET + 8) +#define CMD_NODE_PAUSE_OFFSET (CMD_NODE_BASE_OFFSET + 9) +#define CMD_NODE_PUTMESSAGE_OFFSET (CMD_NODE_BASE_OFFSET + 10) +#define CMD_NODE_REGISTERNOTIFY_OFFSET (CMD_NODE_BASE_OFFSET + 11) +#define CMD_NODE_RUN_OFFSET (CMD_NODE_BASE_OFFSET + 12) +#define CMD_NODE_TERMINATE_OFFSET (CMD_NODE_BASE_OFFSET + 13) +#define CMD_NODE_GETUUIDPROPS_OFFSET (CMD_NODE_BASE_OFFSET + 14) +#define CMD_NODE_END_OFFSET CMD_NODE_GETUUIDPROPS_OFFSET + +#define CMD_STRM_BASE_OFFSET (CMD_NODE_END_OFFSET + 1) +#define CMD_STRM_ALLOCATEBUFFER_OFFSET (CMD_STRM_BASE_OFFSET + 0) +#define CMD_STRM_CLOSE_OFFSET (CMD_STRM_BASE_OFFSET + 1) +#define CMD_STRM_FREEBUFFER_OFFSET (CMD_STRM_BASE_OFFSET + 2) +#define CMD_STRM_GETEVENTHANDLE_OFFSET (CMD_STRM_BASE_OFFSET + 3) +#define CMD_STRM_GETINFO_OFFSET (CMD_STRM_BASE_OFFSET + 4) +#define CMD_STRM_IDLE_OFFSET (CMD_STRM_BASE_OFFSET + 5) +#define CMD_STRM_ISSUE_OFFSET (CMD_STRM_BASE_OFFSET + 6) +#define CMD_STRM_OPEN_OFFSET (CMD_STRM_BASE_OFFSET + 7) +#define CMD_STRM_RECLAIM_OFFSET (CMD_STRM_BASE_OFFSET + 8) +#define CMD_STRM_REGISTERNOTIFY_OFFSET (CMD_STRM_BASE_OFFSET + 9) +#define CMD_STRM_SELECT_OFFSET (CMD_STRM_BASE_OFFSET + 10) +#define CMD_STRM_END_OFFSET CMD_STRM_SELECT_OFFSET + +/* Communication Memory Manager (UCMM) */ +#define CMD_CMM_BASE_OFFSET (CMD_STRM_END_OFFSET + 1) +#define CMD_CMM_ALLOCBUF_OFFSET (CMD_CMM_BASE_OFFSET + 0) +#define CMD_CMM_FREEBUF_OFFSET (CMD_CMM_BASE_OFFSET + 1) +#define CMD_CMM_GETHANDLE_OFFSET (CMD_CMM_BASE_OFFSET + 2) +#define CMD_CMM_GETINFO_OFFSET (CMD_CMM_BASE_OFFSET + 3) +#define CMD_CMM_END_OFFSET CMD_CMM_GETINFO_OFFSET + +#define CMD_BASE_END_OFFSET CMD_CMM_END_OFFSET +#endif /* WCDIOCTL_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/wmd.h b/arch/arm/plat-omap/include/dspbridge/wmd.h new file mode 100644 index 0000000..f584038 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/wmd.h @@ -0,0 +1,1193 @@ +/* + * wmd.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== wmd.h ======== + * Purpose: + * 'Bridge mini driver entry point and interface function declarations. + * + * Public Functions: + * WMD_DRV_Entry + * + * Notes: + * The 'Bridge class driver obtains it's function interface to + * the 'Bridge mini driver via a call to WMD_DRV_Entry(). + * + * 'Bridge Class Driver services exported to WMD's are initialized by the + * WCD on behalf of the WMD. + * + * WMD function DBC Requires and Ensures are also made by the WCD on + * behalf of the WMD, to simplify the WMD code. + * + *! Revision History: + *! ================ + *! 19-Apr-2004 sb Aligned DMM definitions with Symbian + *! 08-Mar-2004 sb Added the Dynamic Memory Mapping APIs - WMD_BRD_MemMap/UnMap + *! 01-Mar-2004 vp Added filename argument to WMD_DRV_Entry function. + *! 29-Aug-2002 map Added WMD_BRD_MemWrite() + *! 26-Aug-2002 map Added WMD_BRD_MemCopy() + *! 07-Jan-2002 ag Added cBufSize to WMD_CHNL_AddIOReq(). + *! 05-Nov-2001 kc: Added error handling DEH functions. + *! 06-Dec-2000 jeh Added uEventMask to WMD_MSG_RegisterNotify(). + *! 17-Nov-2000 jeh Added WMD_MSG and WMD_IO definitions. + *! 01-Nov-2000 jeh Added more error codes to WMD_CHNL_RegisterNotify(). + *! 13-Oct-2000 jeh Added dwArg to WMD_CHNL_AddIOReq(), added WMD_CHNL_IDLE + *! and WMD_CHNL_RegisterNotify for DSPStream support. + *! 17-Jan-2000 rr: WMD_BRD_SETSTATE Added. + *! 30-Jul-1997 gp: Split wmd IOCTL space into reserved and private. + *! 07-Nov-1996 gp: Updated for code review. + *! 18-Oct-1996 gp: Added WMD_E_HARDWARE return code from WMD_BRD_Monitor. + *! 09-Sep-1996 gp: Subtly altered the semantics of WMD_CHNL_GetInfo(). + *! 02-Aug-1996 gp: Ensured on BRD_Start that interrupts to the PC are enabled. + *! 11-Jul-1996 gp: Added CHNL interface. Note stronger DBC_Require conditions. + *! 29-May-1996 gp: Removed WCD_ prefix from functions imported from WCD.LIB. + *! 29-May-1996 gp: Made OUT param first in WMD_DEV_Create(). + *! 09-May-1996 gp: Created. + */ + +#ifndef WMD_ +#define WMD_ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Any IOCTLS at or above this value are reserved for standard WMD + * interfaces. + */ +#define WMD_RESERVEDIOCTLBASE 0x8000 + +/* Handle to mini-driver's private device context. */ + struct WMD_DEV_CONTEXT; + +/*---------------------------------------------------------------------------*/ +/* 'Bridge MINI DRIVER FUNCTION TYPES */ +/*---------------------------------------------------------------------------*/ + +/* + * ======== WMD_BRD_Monitor ======== + * Purpose: + * Bring the board to the BRD_IDLE (monitor) state. + * Parameters: + * hDevContext: Handle to mini-driver defined device context. + * Returns: + * DSP_SOK: Success. + * WMD_E_HARDWARE: A test of hardware assumptions/integrity failed. + * WMD_E_TIMEOUT: Timeout occured waiting for a response from hardware. + * DSP_EFAIL: Other, unspecified error. + * Requires: + * hDevContext != NULL + * Ensures: + * DSP_SOK: Board is in BRD_IDLE state; + * else: Board state is indeterminate. + */ + typedef DSP_STATUS( + *WMD_BRD_MONITOR) (struct WMD_DEV_CONTEXT + *hDevContext); + +/* + * ======== WMD_BRD_SETSTATE ======== + * Purpose: + * Sets the Mini driver state + * Parameters: + * hDevContext: Handle to mini-driver defined device info. + * ulBrdState: Board state + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Other, unspecified error. + * Requires: + * hDevContext != NULL; + * ulBrdState <= BRD_LASTSTATE. + * Ensures: + * ulBrdState <= BRD_LASTSTATE. + * Update the Board state to the specified state. + */ + typedef DSP_STATUS( + *WMD_BRD_SETSTATE) (struct WMD_DEV_CONTEXT + *hDevContext, u32 ulBrdState); + +/* + * ======== WMD_BRD_Start ======== + * Purpose: + * Bring board to the BRD_RUNNING (start) state. + * Parameters: + * hDevContext: Handle to mini-driver defined device context. + * dwDSPAddr: DSP address at which to start execution. + * Returns: + * DSP_SOK: Success. + * WMD_E_TIMEOUT: Timeout occured waiting for a response from hardware. + * DSP_EFAIL: Other, unspecified error. + * Requires: + * hDevContext != NULL + * Board is in monitor (BRD_IDLE) state. + * Ensures: + * DSP_SOK: Board is in BRD_RUNNING state. + * Interrupts to the PC are enabled. + * else: Board state is indeterminate. + */ + typedef DSP_STATUS(*WMD_BRD_START) (struct WMD_DEV_CONTEXT + *hDevContext, u32 dwDSPAddr); + +/* + * ======== WMD_BRD_MemCopy ======== + * Purpose: + * Copy memory from one DSP address to another + * Parameters: + * pDevContext: Pointer to context handle + * ulDspDestAddr: DSP address to copy to + * ulDspSrcAddr: DSP address to copy from + * ulNumBytes: Number of bytes to copy + * ulMemType: What section of memory to copy to + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Other, unspecified error. + * Requires: + * pDevContext != NULL + * Ensures: + * DSP_SOK: Board is in BRD_RUNNING state. + * Interrupts to the PC are enabled. + * else: Board state is indeterminate. + */ + typedef DSP_STATUS(*WMD_BRD_MEMCOPY) (struct WMD_DEV_CONTEXT + *hDevContext, + u32 ulDspDestAddr, + u32 ulDspSrcAddr, + u32 ulNumBytes, u32 ulMemType); +/* + * ======== WMD_BRD_MemWrite ======== + * Purpose: + * Write a block of host memory into a DSP address, into a given memory + * space. Unlike WMD_BRD_Write, this API does reset the DSP + * Parameters: + * hDevContext: Handle to mini-driver defined device info. + * dwDSPAddr: Address on DSP board (Destination). + * pHostBuf: Pointer to host buffer (Source). + * ulNumBytes: Number of bytes to transfer. + * ulMemType: Memory space on DSP to which to transfer. + * Returns: + * DSP_SOK: Success. + * WMD_E_TIMEOUT: Timeout occured waiting for a response from hardware. + * DSP_EFAIL: Other, unspecified error. + * Requires: + * hDevContext != NULL; + * pHostBuf != NULL. + * Ensures: + */ + typedef DSP_STATUS(*WMD_BRD_MEMWRITE) (struct WMD_DEV_CONTEXT + *hDevContext, + IN u8 *pHostBuf, + u32 dwDSPAddr, u32 ulNumBytes, + u32 ulMemType); + +/* + * ======== WMD_BRD_MemMap ======== + * Purpose: + * Map a MPU memory region to a DSP/IVA memory space + * Parameters: + * hDevContext: Handle to mini-driver defined device info. + * ulMpuAddr: MPU memory region start address. + * ulVirtAddr: DSP/IVA memory region u8 address. + * ulNumBytes: Number of bytes to map. + * mapAttrs: Mapping attributes (e.g. endianness). + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Other, unspecified error. + * Requires: + * hDevContext != NULL; + * Ensures: + */ + typedef DSP_STATUS(*WMD_BRD_MEMMAP) (struct WMD_DEV_CONTEXT + *hDevContext, u32 ulMpuAddr, + u32 ulVirtAddr, u32 ulNumBytes, + u32 ulMapAttrs); + +/* + * ======== WMD_BRD_MemUnMap ======== + * Purpose: + * UnMap an MPU memory region from DSP/IVA memory space + * Parameters: + * hDevContext: Handle to mini-driver defined device info. + * ulVirtAddr: DSP/IVA memory region u8 address. + * ulNumBytes: Number of bytes to unmap. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Other, unspecified error. + * Requires: + * hDevContext != NULL; + * Ensures: + */ + typedef DSP_STATUS(*WMD_BRD_MEMUNMAP) (struct WMD_DEV_CONTEXT + *hDevContext, + u32 ulVirtAddr, + u32 ulNumBytes); + +/* + * ======== WMD_BRD_Stop ======== + * Purpose: + * Bring board to the BRD_STOPPED state. + * Parameters: + * hDevContext: Handle to mini-driver defined device context. + * Returns: + * DSP_SOK: Success. + * WMD_E_TIMEOUT: Timeout occured waiting for a response from hardware. + * DSP_EFAIL: Other, unspecified error. + * Requires: + * hDevContext != NULL + * Ensures: + * DSP_SOK: Board is in BRD_STOPPED (stop) state; + * Interrupts to the PC are disabled. + * else: Board state is indeterminate. + */ + typedef DSP_STATUS(*WMD_BRD_STOP) (struct WMD_DEV_CONTEXT + *hDevContext); + +/* + * ======== WMD_BRD_Status ======== + * Purpose: + * Report the current state of the board. + * Parameters: + * hDevContext: Handle to mini-driver defined device context. + * pdwState: Ptr to BRD status variable. + * Returns: + * DSP_SOK: + * Requires: + * pdwState != NULL; + * hDevContext != NULL + * Ensures: + * *pdwState is one of {BRD_STOPPED, BRD_IDLE, BRD_RUNNING, BRD_UNKNOWN}; + */ + typedef DSP_STATUS(* + WMD_BRD_STATUS) (struct WMD_DEV_CONTEXT *hDevContext, + OUT BRD_STATUS * pdwState); + +/* + * ======== WMD_BRD_Read ======== + * Purpose: + * Read a block of DSP memory, from a given memory space, into a host + * buffer. + * Parameters: + * hDevContext: Handle to mini-driver defined device info. + * pHostBuf: Pointer to host buffer (Destination). + * dwDSPAddr: Address on DSP board (Source). + * ulNumBytes: Number of bytes to transfer. + * ulMemType: Memory space on DSP from which to transfer. + * Returns: + * DSP_SOK: Success. + * WMD_E_TIMEOUT: Timeout occured waiting for a response from hardware. + * DSP_EFAIL: Other, unspecified error. + * Requires: + * hDevContext != NULL; + * pHostBuf != NULL. + * Ensures: + * Will not write more than ulNumBytes bytes into pHostBuf. + */ +typedef DSP_STATUS(*WMD_BRD_READ) (struct WMD_DEV_CONTEXT *hDevContext, + OUT u8 *pHostBuf, + u32 dwDSPAddr, + u32 ulNumBytes, + u32 ulMemType); + +/* + * ======== WMD_BRD_Write ======== + * Purpose: + * Write a block of host memory into a DSP address, into a given memory + * space. + * Parameters: + * hDevContext: Handle to mini-driver defined device info. + * dwDSPAddr: Address on DSP board (Destination). + * pHostBuf: Pointer to host buffer (Source). + * ulNumBytes: Number of bytes to transfer. + * ulMemType: Memory space on DSP to which to transfer. + * Returns: + * DSP_SOK: Success. + * WMD_E_TIMEOUT: Timeout occured waiting for a response from hardware. + * DSP_EFAIL: Other, unspecified error. + * Requires: + * hDevContext != NULL; + * pHostBuf != NULL. + * Ensures: + */ +typedef DSP_STATUS(*WMD_BRD_WRITE)(struct WMD_DEV_CONTEXT *hDevContext, + IN u8 *pHostBuf, + u32 dwDSPAddr, + u32 ulNumBytes, + u32 ulMemType); + +/* + * ======== WMD_CHNL_Create ======== + * Purpose: + * Create a channel manager object, responsible for opening new channels + * and closing old ones for a given 'Bridge board. + * Parameters: + * phChnlMgr: Location to store a channel manager object on output. + * hDevObject: Handle to a device object. + * pMgrAttrs: Channel manager attributes. + * pMgrAttrs->cChannels: Max channels + * pMgrAttrs->bIRQ: Channel's I/O IRQ number. + * pMgrAttrs->fShared: TRUE if the IRQ is shareable. + * pMgrAttrs->uWordSize: DSP Word size in equivalent PC bytes.. + * pMgrAttrs->dwSMBase: Base physical address of shared memory, if any. + * pMgrAttrs->uSMLength: Bytes of shared memory block. + * Returns: + * DSP_SOK: Success; + * DSP_EMEMORY: Insufficient memory for requested resources. + * CHNL_E_ISR: Unable to plug ISR for given IRQ. + * CHNL_E_NOMEMMAP: Couldn't map physical address to a virtual one. + * Requires: + * phChnlMgr != NULL. + * pMgrAttrs != NULL + * pMgrAttrs field are all valid: + * 0 < cChannels <= CHNL_MAXCHANNELS. + * bIRQ <= 15. + * uWordSize > 0. + * IsValidHandle(hDevObject) + * No channel manager exists for this board. + * Ensures: + */ + typedef DSP_STATUS(*WMD_CHNL_CREATE)(OUT struct CHNL_MGR + **phChnlMgr, + struct DEV_OBJECT + *hDevObject, + IN CONST struct + CHNL_MGRATTRS *pMgrAttrs); + +/* + * ======== WMD_CHNL_Destroy ======== + * Purpose: + * Close all open channels, and destroy the channel manager. + * Parameters: + * hChnlMgr: Channel manager object. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: hChnlMgr was invalid. + * Requires: + * Ensures: + * DSP_SOK: Cancels I/O on each open channel. Closes each open channel. + * CHNL_Create may subsequently be called for the same device. + */ + typedef DSP_STATUS(*WMD_CHNL_DESTROY) (struct CHNL_MGR + *hChnlMgr); +/* + * ======== WMD_DEH_Notify ======== + * Purpose: + * When notified of DSP error, take appropriate action. + * Parameters: + * hDehMgr: Handle to DEH manager object. + * ulEventMask: Indicate the type of exception + * dwErrInfo: Error information + * Returns: + * + * Requires: + * hDehMgr != NULL; + * ulEventMask with a valid exception + * Ensures: + */ + typedef void (*WMD_DEH_NOTIFY)(struct DEH_MGR *hDehMgr, + u32 ulEventMask, u32 dwErrInfo); + + +/* + * ======== WMD_CHNL_Open ======== + * Purpose: + * Open a new half-duplex channel to the DSP board. + * Parameters: + * phChnl: Location to store a channel object handle. + * hChnlMgr: Handle to channel manager, as returned by CHNL_GetMgr(). + * uMode: One of {CHNL_MODETODSP, CHNL_MODEFROMDSP} specifies + * direction of data transfer. + * uChnlId: If CHNL_PICKFREE is specified, the channel manager will + * select a free channel id (default); + * otherwise this field specifies the id of the channel. + * pAttrs: Channel attributes. Attribute fields are as follows: + * pAttrs->uIOReqs: Specifies the maximum number of I/O requests which can + * be pending at any given time. All request packets are + * preallocated when the channel is opened. + * pAttrs->hEvent: This field allows the user to supply an auto reset + * event object for channel I/O completion notifications. + * It is the responsibility of the user to destroy this + * object AFTER closing the channel. + * This channel event object can be retrieved using + * CHNL_GetEventHandle(). + * pAttrs->hReserved: The kernel mode handle of this event object. + * + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: hChnlMgr is invalid. + * DSP_EMEMORY: Insufficient memory for requested resources. + * DSP_EINVALIDARG: Invalid number of IOReqs. + * CHNL_E_OUTOFSTREAMS: No free channels available. + * CHNL_E_BADCHANID: Channel ID is out of range. + * CHNL_E_CHANBUSY: Channel is in use. + * CHNL_E_NOIORPS: No free IO request packets available for + * queuing. + * Requires: + * phChnl != NULL. + * pAttrs != NULL. + * pAttrs->hEvent is a valid event handle. + * pAttrs->hReserved is the kernel mode handle for pAttrs->hEvent. + * Ensures: + * DSP_SOK: *phChnl is a valid channel. + * else: *phChnl is set to NULL if (phChnl != NULL); + */ + typedef DSP_STATUS(*WMD_CHNL_OPEN) (OUT struct CHNL_OBJECT + **phChnl, + struct CHNL_MGR *hChnlMgr, + CHNL_MODE uMode, + u32 uChnlId, + CONST IN OPTIONAL struct + CHNL_ATTRS *pAttrs); + +/* + * ======== WMD_CHNL_Close ======== + * Purpose: + * Ensures all pending I/O on this channel is cancelled, discards all + * queued I/O completion notifications, then frees the resources allocated + * for this channel, and makes the corresponding logical channel id + * available for subsequent use. + * Parameters: + * hChnl: Handle to a channel object. + * Returns: + * DSP_SOK: Success; + * DSP_EHANDLE: Invalid hChnl. + * Requires: + * No thread must be blocked on this channel's I/O completion event. + * Ensures: + * DSP_SOK: hChnl is no longer valid. + */ + typedef DSP_STATUS(*WMD_CHNL_CLOSE) (struct CHNL_OBJECT *hChnl); + +/* + * ======== WMD_CHNL_AddIOReq ======== + * Purpose: + * Enqueue an I/O request for data transfer on a channel to the DSP. + * The direction (mode) is specified in the channel object. Note the DSP + * address is specified for channels opened in direct I/O mode. + * Parameters: + * hChnl: Channel object handle. + * pHostBuf: Host buffer address source. + * cBytes: Number of PC bytes to transfer. A zero value indicates + * that this buffer is the last in the output channel. + * A zero value is invalid for an input channel. + *! cBufSize: Actual buffer size in host bytes. + * dwDspAddr: DSP address for transfer. (Currently ignored). + * dwArg: A user argument that travels with the buffer. + * Returns: + * DSP_SOK: Success; + * DSP_EHANDLE: Invalid hChnl. + * DSP_EPOINTER: pHostBuf is invalid. + * CHNL_E_NOEOS: User cannot mark EOS on an input channel. + * CHNL_E_CANCELLED: I/O has been cancelled on this channel. No further + * I/O is allowed. + * CHNL_E_EOS: End of stream was already marked on a previous + * IORequest on this channel. No further I/O is expected. + * CHNL_E_BUFSIZE: Buffer submitted to this output channel is larger than + * the size of the physical shared memory output window. + * Requires: + * Ensures: + * DSP_SOK: The buffer will be transferred if the channel is ready; + * otherwise, will be queued for transfer when the channel becomes + * ready. In any case, notifications of I/O completion are + * asynchronous. + * If cBytes is 0 for an output channel, subsequent CHNL_AddIOReq's + * on this channel will fail with error code CHNL_E_EOS. The + * corresponding IOC for this I/O request will have its status flag + * set to CHNL_IOCSTATEOS. + */ + typedef DSP_STATUS(*WMD_CHNL_ADDIOREQ) (struct CHNL_OBJECT + *hChnl, + void *pHostBuf, + u32 cBytes, + u32 cBufSize, + OPTIONAL u32 dwDspAddr, + u32 dwArg); + +/* + * ======== WMD_CHNL_GetIOC ======== + * Purpose: + * Dequeue an I/O completion record, which contains information about the + * completed I/O request. + * Parameters: + * hChnl: Channel object handle. + * dwTimeOut: A value of CHNL_IOCNOWAIT will simply dequeue the + * first available IOC. + * pIOC: On output, contains host buffer address, bytes + * transferred, and status of I/O completion. + * pIOC->status: See chnldefs.h. + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hChnl. + * DSP_EPOINTER: pIOC is invalid. + * CHNL_E_NOIOC: CHNL_IOCNOWAIT was specified as the dwTimeOut parameter + * yet no I/O completions were queued. + * Requires: + * dwTimeOut == CHNL_IOCNOWAIT. + * Ensures: + * DSP_SOK: if there are any remaining IOC's queued before this call + * returns, the channel event object will be left in a signalled + * state. + */ + typedef DSP_STATUS(*WMD_CHNL_GETIOC) (struct CHNL_OBJECT *hChnl, + u32 dwTimeOut, + OUT struct CHNL_IOC *pIOC); + +/* + * ======== WMD_CHNL_CancelIO ======== + * Purpose: + * Return all I/O requests to the client which have not yet been + * transferred. The channel's I/O completion object is + * signalled, and all the I/O requests are queued as IOC's, with the + * status field set to CHNL_IOCSTATCANCEL. + * This call is typically used in abort situations, and is a prelude to + * CHNL_Close(); + * Parameters: + * hChnl: Channel object handle. + * Returns: + * DSP_SOK: Success; + * DSP_EHANDLE: Invalid hChnl. + * Requires: + * Ensures: + * Subsequent I/O requests to this channel will not be accepted. + */ + typedef DSP_STATUS(*WMD_CHNL_CANCELIO) (struct CHNL_OBJECT + *hChnl); + +/* + * ======== WMD_CHNL_FlushIO ======== + * Purpose: + * For an output stream (to the DSP), indicates if any IO requests are in + * the output request queue. For input streams (from the DSP), will + * cancel all pending IO requests. + * Parameters: + * hChnl: Channel object handle. + * dwTimeOut: Timeout value for flush operation. + * Returns: + * DSP_SOK: Success; + * S_CHNLIOREQUEST: Returned if any IORequests are in the output queue. + * DSP_EHANDLE: Invalid hChnl. + * Requires: + * Ensures: + * DSP_SOK: No I/O requests will be pending on this channel. + */ + typedef DSP_STATUS(*WMD_CHNL_FLUSHIO) (struct CHNL_OBJECT *hChnl, + u32 dwTimeOut); + +/* + * ======== WMD_CHNL_GetInfo ======== + * Purpose: + * Retrieve information related to a channel. + * Parameters: + * hChnl: Handle to a valid channel object, or NULL. + * pInfo: Location to store channel info. + * Returns: + * DSP_SOK: Success; + * DSP_EHANDLE: Invalid hChnl. + * DSP_EPOINTER: pInfo == NULL. + * Requires: + * Ensures: + * DSP_SOK: pInfo points to a filled in CHNL_INFO struct, + * if (pInfo != NULL). + */ + typedef DSP_STATUS(*WMD_CHNL_GETINFO) (struct CHNL_OBJECT *hChnl, + OUT struct CHNL_INFO + *pChnlInfo); + +/* + * ======== WMD_CHNL_GetMgrInfo ======== + * Purpose: + * Retrieve information related to the channel manager. + * Parameters: + * hChnlMgr: Handle to a valid channel manager, or NULL. + * uChnlID: Channel ID. + * pMgrInfo: Location to store channel manager info. + * Returns: + * DSP_SOK: Success; + * DSP_EHANDLE: Invalid hChnlMgr. + * DSP_EPOINTER: pMgrInfo == NULL. + * CHNL_E_BADCHANID: Invalid channel ID. + * Requires: + * Ensures: + * DSP_SOK: pMgrInfo points to a filled in CHNL_MGRINFO + * struct, if (pMgrInfo != NULL). + */ + typedef DSP_STATUS(*WMD_CHNL_GETMGRINFO) (struct CHNL_MGR + *hChnlMgr, + u32 uChnlID, + OUT struct CHNL_MGRINFO + *pMgrInfo); + +/* + * ======== WMD_CHNL_Idle ======== + * Purpose: + * Idle a channel. If this is an input channel, or if this is an output + * channel and fFlush is TRUE, all currently enqueued buffers will be + * dequeued (data discarded for output channel). + * If this is an output channel and fFlush is FALSE, this function + * will block until all currently buffered data is output, or the timeout + * specified has been reached. + * + * Parameters: + * hChnl: Channel object handle. + * dwTimeOut: If output channel and fFlush is FALSE, timeout value + * to wait for buffers to be output. (Not used for + * input channel). + * fFlush: If output channel and fFlush is TRUE, discard any + * currently buffered data. If FALSE, wait for currently + * buffered data to be output, or timeout, whichever + * occurs first. fFlush is ignored for input channel. + * Returns: + * DSP_SOK: Success; + * DSP_EHANDLE: Invalid hChnl. + * CHNL_E_WAITTIMEOUT: Timeout occured before channel could be idled. + * Requires: + * Ensures: + */ + typedef DSP_STATUS(*WMD_CHNL_IDLE) (struct CHNL_OBJECT *hChnl, + u32 dwTimeOut, + bool fFlush); + +/* + * ======== WMD_CHNL_RegisterNotify ======== + * Purpose: + * Register for notification of events on a channel. + * Parameters: + * hChnl: Channel object handle. + * uEventMask: Type of events to be notified about: IO completion + * (DSP_STREAMIOCOMPLETION) or end of stream + * (DSP_STREAMDONE). + * uNotifyType: DSP_SIGNALEVENT. + * hNotification: Handle of a DSP_NOTIFICATION object. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Insufficient memory. + * DSP_EVALUE: uEventMask is 0 and hNotification was not + * previously registered. + * DSP_EHANDLE: NULL hNotification, hNotification event name + * too long, or hNotification event name NULL. + * Requires: + * Valid hChnl. + * hNotification != NULL. + * (uEventMask & ~(DSP_STREAMIOCOMPLETION | DSP_STREAMDONE)) == 0. + * uNotifyType == DSP_SIGNALEVENT. + * Ensures: + */ + typedef DSP_STATUS(*WMD_CHNL_REGISTERNOTIFY) + (struct CHNL_OBJECT *hChnl, + u32 uEventMask, + u32 uNotifyType, + struct DSP_NOTIFICATION *hNotification); + +/* + * ======== WMD_DEV_Create ======== + * Purpose: + * Complete creation of the device object for this board. + * Parameters: + * phDevContext: Ptr to location to store a WMD device context. + * hDevObject: Handle to a Device Object, created and managed by WCD. + * pConfig: Ptr to configuration parameters provided by the Windows + * Configuration Manager during device loading. + * pDspConfig: DSP resources, as specified in the registry key for this + * device. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Unable to allocate memory for device context. + * WMD_E_BADCONFIG: One or more of the host or DSP configuration + * parameters did not satisfy hardware assumptions + * made by this WMD. + * Requires: + * phDevContext != NULL; + * hDevObject != NULL; + * pConfig != NULL; + * pDspConfig != NULL; + * Fields in pConfig and pDspConfig contain valid values. + * Ensures: + * DSP_SOK: All mini-driver specific DSP resource and other + * board context has been allocated. + * DSP_EMEMORY: WMD failed to allocate resources. + * Any acquired resources have been freed. The WCD will + * not call WMD_DEV_Destroy() if WMD_DEV_Create() fails. + * Details: + * Called during the CONFIGMG's Device_Init phase. Based on host and + * DSP configuration information, create a board context, a handle to + * which is passed into other WMD BRD and CHNL functions. The + * board context contains state information for the device. Since the + * addresses of all IN pointer parameters may be invalid when this + * function returns, they must not be stored into the device context + * structure. + */ + typedef DSP_STATUS(*WMD_DEV_CREATE) (OUT struct WMD_DEV_CONTEXT + **phDevContext, + struct DEV_OBJECT + *hDevObject, + IN CONST struct CFG_HOSTRES + *pConfig, + IN CONST struct CFG_DSPRES + *pDspConfig); + +/* + * ======== WMD_DEV_Ctrl ======== + * Purpose: + * Mini-driver specific interface. + * Parameters: + * hDevContext: Handle to mini-driver defined device info. + * dwCmd: WMD defined command code. + * pArgs: Pointer to an arbitrary argument structure. + * Returns: + * DSP_SOK or DSP_EFAIL. Actual command error codes should be passed back + * in the pArgs structure, and are defined by the WMD implementor. + * Requires: + * All calls are currently assumed to be synchronous. There are no + * IOCTL completion routines provided. + * Ensures: + */ +typedef DSP_STATUS(*WMD_DEV_CTRL)(struct WMD_DEV_CONTEXT *hDevContext, + u32 dwCmd, + IN OUT void *pArgs); + +/* + * ======== WMD_DEV_Destroy ======== + * Purpose: + * Deallocate WMD device extension structures and all other resources + * acquired by the mini-driver. + * No calls to other mini driver functions may subsequently + * occur, except for WMD_DEV_Create(). + * Parameters: + * hDevContext: Handle to mini-driver defined device information. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Failed to release a resource previously acquired. + * Requires: + * hDevContext != NULL; + * Ensures: + * DSP_SOK: Device context is freed. + */ + typedef DSP_STATUS(*WMD_DEV_DESTROY) (struct WMD_DEV_CONTEXT + *hDevContext); + +/* + * ======== WMD_DEH_Create ======== + * Purpose: + * Create an object that manages DSP exceptions from the GPP. + * Parameters: + * phDehMgr: Location to store DEH manager on output. + * hDevObject: Handle to DEV object. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Memory allocation failure. + * DSP_EFAIL: Creation failed. + * Requires: + * hDevObject != NULL; + * phDehMgr != NULL; + * Ensures: + */ + typedef DSP_STATUS(*WMD_DEH_CREATE) (OUT struct DEH_MGR + **phDehMgr, + struct DEV_OBJECT + *hDevObject); + +/* + * ======== WMD_DEH_Destroy ======== + * Purpose: + * Destroy the DEH object. + * Parameters: + * hDehMgr: Handle to DEH manager object. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Destroy failed. + * Requires: + * hDehMgr != NULL; + * Ensures: + */ + typedef DSP_STATUS(*WMD_DEH_DESTROY) (struct DEH_MGR *hDehMgr); + +/* + * ======== WMD_DEH_RegisterNotify ======== + * Purpose: + * Register for DEH event notification. + * Parameters: + * hDehMgr: Handle to DEH manager object. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Destroy failed. + * Requires: + * hDehMgr != NULL; + * Ensures: + */ + typedef DSP_STATUS(*WMD_DEH_REGISTERNOTIFY) + (struct DEH_MGR *hDehMgr, + u32 uEventMask, u32 uNotifyType, + struct DSP_NOTIFICATION *hNotification); + +/* + * ======== WMD_DEH_GetInfo ======== + * Purpose: + * Get DSP exception info. + * Parameters: + * phDehMgr: Location to store DEH manager on output. + * pErrInfo: Ptr to error info structure. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Creation failed. + * Requires: + * phDehMgr != NULL; + * pErrorInfo != NULL; + * Ensures: + */ + typedef DSP_STATUS(*WMD_DEH_GETINFO) (struct DEH_MGR *phDehMgr, + struct DSP_ERRORINFO *pErrInfo); + +/* + * ======== WMD_IO_Create ======== + * Purpose: + * Create an object that manages I/O between CHNL and MSG. + * Parameters: + * phIOMgr: Location to store IO manager on output. + * hChnlMgr: Handle to channel manager. + * hMsgMgr: Handle to message manager. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Memory allocation failure. + * DSP_EFAIL: Creation failed. + * Requires: + * hDevObject != NULL; + * Channel manager already created; + * Message manager already created; + * pMgrAttrs != NULL; + * phIOMgr != NULL; + * Ensures: + */ + typedef DSP_STATUS(*WMD_IO_CREATE) (OUT struct IO_MGR **phIOMgr, + struct DEV_OBJECT *hDevObject, + IN CONST struct IO_ATTRS *pMgrAttrs); + +/* + * ======== WMD_IO_Destroy ======== + * Purpose: + * Destroy object created in WMD_IO_Create. + * Parameters: + * hIOMgr: IO Manager. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Memory allocation failure. + * DSP_EFAIL: Creation failed. + * Requires: + * Valid hIOMgr; + * Ensures: + */ + typedef DSP_STATUS(*WMD_IO_DESTROY) (struct IO_MGR *hIOMgr); + +/* + * ======== WMD_IO_OnLoaded ======== + * Purpose: + * Called whenever a program is loaded to update internal data. For + * example, if shared memory is used, this function would update the + * shared memory location and address. + * Parameters: + * hIOMgr: IO Manager. + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Internal failure occurred. + * Requires: + * Valid hIOMgr; + * Ensures: + */ + typedef DSP_STATUS(*WMD_IO_ONLOADED) (struct IO_MGR *hIOMgr); + +/* + * ======== WMD_IO_GETPROCLOAD ======== + * Purpose: + * Called to get the Processor's current and predicted load + * Parameters: + * hIOMgr: IO Manager. + * pProcLoadStat Processor Load statistics + * Returns: + * DSP_SOK: Success. + * DSP_EFAIL: Internal failure occurred. + * Requires: + * Valid hIOMgr; + * Ensures: + */ + typedef DSP_STATUS(*WMD_IO_GETPROCLOAD)(struct IO_MGR *hIOMgr, + struct DSP_PROCLOADSTAT *pProcLoadStat); + +/* + * ======== WMD_MSG_Create ======== + * Purpose: + * Create an object to manage message queues. Only one of these objects + * can exist per device object. + * Parameters: + * phMsgMgr: Location to store MSG manager on output. + * hDevObject: Handle to a device object. + * msgCallback: Called whenever an RMS_EXIT message is received. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Insufficient memory. + * Requires: + * phMsgMgr != NULL. + * msgCallback != NULL. + * hDevObject != NULL. + * Ensures: + */ + typedef DSP_STATUS(*WMD_MSG_CREATE) + (OUT struct MSG_MGR **phMsgMgr, + struct DEV_OBJECT *hDevObject, + MSG_ONEXIT msgCallback); + +/* + * ======== WMD_MSG_CreateQueue ======== + * Purpose: + * Create a MSG queue for sending or receiving messages from a Message + * node on the DSP. + * Parameters: + * hMsgMgr: MSG queue manager handle returned from + * WMD_MSG_Create. + * phMsgQueue: Location to store MSG queue on output. + * dwId: Identifier for messages (node environment pointer). + * uMaxMsgs: Max number of simultaneous messages for the node. + * h: Handle passed to hMsgMgr->msgCallback(). + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Insufficient memory. + * Requires: + * phMsgQueue != NULL. + * h != NULL. + * uMaxMsgs > 0. + * Ensures: + * phMsgQueue !=NULL <==> DSP_SOK. + */ + typedef DSP_STATUS(*WMD_MSG_CREATEQUEUE) + (struct MSG_MGR *hMsgMgr, + OUT struct MSG_QUEUE **phMsgQueue, + u32 dwId, u32 uMaxMsgs, HANDLE h); + +/* + * ======== WMD_MSG_Delete ======== + * Purpose: + * Delete a MSG manager allocated in WMD_MSG_Create(). + * Parameters: + * hMsgMgr: Handle returned from WMD_MSG_Create(). + * Returns: + * Requires: + * Valid hMsgMgr. + * Ensures: + */ + typedef void(*WMD_MSG_DELETE) (struct MSG_MGR *hMsgMgr); + +/* + * ======== WMD_MSG_DeleteQueue ======== + * Purpose: + * Delete a MSG queue allocated in WMD_MSG_CreateQueue. + * Parameters: + * hMsgQueue: Handle to MSG queue returned from + * WMD_MSG_CreateQueue. + * Returns: + * Requires: + * Valid hMsgQueue. + * Ensures: + */ + typedef void(*WMD_MSG_DELETEQUEUE) (struct MSG_QUEUE *hMsgQueue); + +/* + * ======== WMD_MSG_Get ======== + * Purpose: + * Get a message from a MSG queue. + * Parameters: + * hMsgQueue: Handle to MSG queue returned from + * WMD_MSG_CreateQueue. + * pMsg: Location to copy message into. + * uTimeout: Timeout to wait for a message. + * Returns: + * DSP_SOK: Success. + * DSP_ETIMEOUT: Timeout occurred. + * DSP_EFAIL: No frames available for message (uMaxMessages too + * small). + * Requires: + * Valid hMsgQueue. + * pMsg != NULL. + * Ensures: + */ + typedef DSP_STATUS(*WMD_MSG_GET) (struct MSG_QUEUE *hMsgQueue, + struct DSP_MSG *pMsg, + u32 uTimeout); + +/* + * ======== WMD_MSG_Put ======== + * Purpose: + * Put a message onto a MSG queue. + * Parameters: + * hMsgQueue: Handle to MSG queue returned from + * WMD_MSG_CreateQueue. + * pMsg: Pointer to message. + * uTimeout: Timeout to wait for a message. + * Returns: + * DSP_SOK: Success. + * DSP_ETIMEOUT: Timeout occurred. + * DSP_EFAIL: No frames available for message (uMaxMessages too + * small). + * Requires: + * Valid hMsgQueue. + * pMsg != NULL. + * Ensures: + */ + typedef DSP_STATUS(*WMD_MSG_PUT) (struct MSG_QUEUE *hMsgQueue, + IN CONST struct DSP_MSG *pMsg, + u32 uTimeout); + +/* + * ======== WMD_MSG_RegisterNotify ======== + * Purpose: + * Register notification for when a message is ready. + * Parameters: + * hMsgQueue: Handle to MSG queue returned from + * WMD_MSG_CreateQueue. + * uEventMask: Type of events to be notified about: Must be + * DSP_NODEMESSAGEREADY, or 0 to unregister. + * uNotifyType: DSP_SIGNALEVENT. + * hNotification: Handle of notification object. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Insufficient memory. + * Requires: + * Valid hMsgQueue. + * hNotification != NULL. + * uNotifyType == DSP_SIGNALEVENT. + * uEventMask == DSP_NODEMESSAGEREADY || uEventMask == 0. + * Ensures: + */ + typedef DSP_STATUS(*WMD_MSG_REGISTERNOTIFY) + (struct MSG_QUEUE *hMsgQueue, + u32 uEventMask, u32 uNotifyType, + struct DSP_NOTIFICATION *hNotification); + +/* + * ======== WMD_MSG_SetQueueId ======== + * Purpose: + * Set message queue id to node environment. Allows WMD_MSG_CreateQueue + * to be called in NODE_Allocate, before the node environment is known. + * Parameters: + * hMsgQueue: Handle to MSG queue returned from + * WMD_MSG_CreateQueue. + * dwId: Node environment pointer. + * Returns: + * Requires: + * Valid hMsgQueue. + * dwId != 0. + * Ensures: + */ + typedef void(*WMD_MSG_SETQUEUEID) (struct MSG_QUEUE *hMsgQueue, + u32 dwId); + +/* + * 'Bridge Mini Driver (WMD) interface function table. + * + * The information in this table is filled in by the specific mini-driver, + * and copied into the 'Bridge class driver's own space. If any interface + * function field is set to a value of NULL, then the class driver will + * consider that function not implemented, and return the error code + * DSP_ENOTIMPL when a WMD client attempts to call that function. + * + * This function table contains WCD version numbers, which are used by the + * WMD loader to help ensure backwards compatility between older WMD's and a + * newer 'Bridge Class Driver. These must be set to WCD_MAJOR_VERSION + * and WCD_MINOR_VERSION, respectively. + * + * A mini-driver need not export a CHNL interface. In this case, *all* of + * the WMD_CHNL_* entries must be set to NULL. + */ + struct WMD_DRV_INTERFACE { + u32 dwWCDMajorVersion; /* Set to WCD_MAJOR_VERSION. */ + u32 dwWCDMinorVersion; /* Set to WCD_MINOR_VERSION. */ + WMD_DEV_CREATE pfnDevCreate; /* Create device context */ + WMD_DEV_DESTROY pfnDevDestroy; /* Destroy device context */ + WMD_DEV_CTRL pfnDevCntrl; /* Optional vendor interface */ + WMD_BRD_MONITOR pfnBrdMonitor; /* Load and/or start monitor */ + WMD_BRD_START pfnBrdStart; /* Start DSP program. */ + WMD_BRD_STOP pfnBrdStop; /* Stop/reset board. */ + WMD_BRD_STATUS pfnBrdStatus; /* Get current board status. */ + WMD_BRD_READ pfnBrdRead; /* Read board memory */ + WMD_BRD_WRITE pfnBrdWrite; /* Write board memory. */ + WMD_BRD_SETSTATE pfnBrdSetState; /* Sets the Board State */ + WMD_BRD_MEMCOPY pfnBrdMemCopy; /* Copies DSP Memory */ + WMD_BRD_MEMWRITE pfnBrdMemWrite; /* Write DSP Memory w/o halt */ + WMD_BRD_MEMMAP pfnBrdMemMap; /* Maps MPU mem to DSP mem */ + WMD_BRD_MEMUNMAP pfnBrdMemUnMap; /* Unmaps MPU mem to DSP mem */ + WMD_CHNL_CREATE pfnChnlCreate; /* Create channel manager. */ + WMD_CHNL_DESTROY pfnChnlDestroy; /* Destroy channel manager. */ + WMD_CHNL_OPEN pfnChnlOpen; /* Create a new channel. */ + WMD_CHNL_CLOSE pfnChnlClose; /* Close a channel. */ + WMD_CHNL_ADDIOREQ pfnChnlAddIOReq; /* Req I/O on a channel. */ + WMD_CHNL_GETIOC pfnChnlGetIOC; /* Wait for I/O completion. */ + WMD_CHNL_CANCELIO pfnChnlCancelIO; /* Cancl I/O on a channel. */ + WMD_CHNL_FLUSHIO pfnChnlFlushIO; /* Flush I/O. */ + WMD_CHNL_GETINFO pfnChnlGetInfo; /* Get channel specific info */ + /* Get channel manager info. */ + WMD_CHNL_GETMGRINFO pfnChnlGetMgrInfo; + WMD_CHNL_IDLE pfnChnlIdle; /* Idle the channel */ + /* Register for notif. */ + WMD_CHNL_REGISTERNOTIFY pfnChnlRegisterNotify; + WMD_DEH_CREATE pfnDehCreate; /* Create DEH manager */ + WMD_DEH_DESTROY pfnDehDestroy; /* Destroy DEH manager */ + WMD_DEH_NOTIFY pfnDehNotify; /* Notify of DSP error */ + /* register for deh notif. */ + WMD_DEH_REGISTERNOTIFY pfnDehRegisterNotify; + WMD_DEH_GETINFO pfnDehGetInfo; /* register for deh notif. */ + WMD_IO_CREATE pfnIOCreate; /* Create IO manager */ + WMD_IO_DESTROY pfnIODestroy; /* Destroy IO manager */ + WMD_IO_ONLOADED pfnIOOnLoaded; /* Notify of program loaded */ + /* Get Processor's current and predicted load */ + WMD_IO_GETPROCLOAD pfnIOGetProcLoad; + WMD_MSG_CREATE pfnMsgCreate; /* Create message manager */ + /* Create message queue */ + WMD_MSG_CREATEQUEUE pfnMsgCreateQueue; + WMD_MSG_DELETE pfnMsgDelete; /* Delete message manager */ + /* Delete message queue */ + WMD_MSG_DELETEQUEUE pfnMsgDeleteQueue; + WMD_MSG_GET pfnMsgGet; /* Get a message */ + WMD_MSG_PUT pfnMsgPut; /* Send a message */ + /* Register for notif. */ + WMD_MSG_REGISTERNOTIFY pfnMsgRegisterNotify; + /* Set message queue id */ + WMD_MSG_SETQUEUEID pfnMsgSetQueueId; + } ; + +/* + * ======== WMD_DRV_Entry ======== + * Purpose: + * Registers WMD functions with the class driver. Called only once + * by the WCD. The caller will first check WCD version compatibility, and + * then copy the interface functions into its own memory space. + * Parameters: + * ppDrvInterface Pointer to a location to receive a pointer to the + * mini driver interface. + * Returns: + * Requires: + * The code segment this function resides in must expect to be discarded + * after completion. + * Ensures: + * ppDrvInterface pointer initialized to WMD's function interface. + * No system resources are acquired by this function. + * Details: + * Win95: Called during the Device_Init phase. + */ + void WMD_DRV_Entry(OUT struct WMD_DRV_INTERFACE **ppDrvInterface, + IN CONST char *pstrWMDFileName); + +#endif /* WMD_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/wmdchnl.h b/arch/arm/plat-omap/include/dspbridge/wmdchnl.h new file mode 100644 index 0000000..2c1f072 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/wmdchnl.h @@ -0,0 +1,90 @@ +/* + * wmdchnl.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== wmdchnl.h ======== + * Description: + * Declares the upper edge channel class library functions required by + * all WMD / WCD driver interface tables. These functions are implemented + * by every class of WMD channel library. + * + * Public Functions: + * + * Notes: + * The function comment headers reside with the function typedefs in wmd.h. + * + *! Revision History: + *! ================ + *! 07-Jan-2002 ag Added cBufSize to WMD_CHNL_AddIOReq(). + *! 13-Oct-2000 jeh Added dwArg parameter to WMD_CHNL_AddIOReq(), added + *! WMD_CHNL_Idle and WMD_CHNL_RegisterNotify for DSPStream + *! support. + *! 11-Jul-1996 gp: Created. + */ + +#ifndef WMDCHNL_ +#define WMDCHNL_ + + extern DSP_STATUS WMD_CHNL_Create(OUT struct CHNL_MGR **phChnlMgr, + struct DEV_OBJECT *hDevObject, + IN CONST struct CHNL_MGRATTRS + *pMgrAttrs); + + extern DSP_STATUS WMD_CHNL_Destroy(struct CHNL_MGR *hChnlMgr); + + extern DSP_STATUS WMD_CHNL_Open(OUT struct CHNL_OBJECT **phChnl, + struct CHNL_MGR *hChnlMgr, + CHNL_MODE uMode, + u32 uChnlId, + CONST IN OPTIONAL struct CHNL_ATTRS + *pAttrs); + + extern DSP_STATUS WMD_CHNL_Close(struct CHNL_OBJECT *hChnl); + + extern DSP_STATUS WMD_CHNL_AddIOReq(struct CHNL_OBJECT *hChnl, + void *pHostBuf, + u32 cBytes, u32 cBufSize, + OPTIONAL u32 dwDspAddr, + u32 dwArg); + + extern DSP_STATUS WMD_CHNL_GetIOC(struct CHNL_OBJECT *hChnl, + u32 dwTimeOut, + OUT struct CHNL_IOC *pIOC); + + extern DSP_STATUS WMD_CHNL_CancelIO(struct CHNL_OBJECT *hChnl); + + extern DSP_STATUS WMD_CHNL_FlushIO(struct CHNL_OBJECT *hChnl, + u32 dwTimeOut); + + extern DSP_STATUS WMD_CHNL_GetInfo(struct CHNL_OBJECT *hChnl, + OUT struct CHNL_INFO *pInfo); + + extern DSP_STATUS WMD_CHNL_GetMgrInfo(struct CHNL_MGR *hChnlMgr, + u32 uChnlID, + OUT struct CHNL_MGRINFO + *pMgrInfo); + + extern DSP_STATUS WMD_CHNL_Idle(struct CHNL_OBJECT *hChnl, + u32 dwTimeOut, bool fFlush); + + extern DSP_STATUS WMD_CHNL_RegisterNotify(struct CHNL_OBJECT *hChnl, + u32 uEventMask, + u32 uNotifyType, + struct DSP_NOTIFICATION + *hNotification); + +#endif /* WMDCHNL_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/wmddeh.h b/arch/arm/plat-omap/include/dspbridge/wmddeh.h new file mode 100644 index 0000000..dd50a3a --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/wmddeh.h @@ -0,0 +1,64 @@ +/* + * wmddeh.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== wmddeh.h ======== + * Description: + * Defines upper edge DEH functions required by all WMD/WCD driver + * interface tables. + * + * Public Functions: + * WMD_DEH_Create + * IVA_DEH_Create + * WMD_DEH_Destroy + * WMD_DEH_GetInfo + * WMD_DEH_RegisterNotify + * WMD_DEH_Notify + * + * Notes: + * Function comment headers reside with the function typedefs in wmd.h. + * + *! Revision History: + *! ================ + *! 26-Dec-2004 hn: added IVA_DEH_Create. + *! 13-Sep-2001 kc: created. + */ + +#ifndef WMDDEH_ +#define WMDDEH_ + +#include + +#include + + extern DSP_STATUS WMD_DEH_Create(OUT struct DEH_MGR **phDehMgr, + struct DEV_OBJECT *hDevObject); + + extern DSP_STATUS WMD_DEH_Destroy(struct DEH_MGR *hDehMgr); + + extern DSP_STATUS WMD_DEH_GetInfo(struct DEH_MGR *hDehMgr, + struct DSP_ERRORINFO *pErrInfo); + + extern DSP_STATUS WMD_DEH_RegisterNotify(struct DEH_MGR *hDehMgr, + u32 uEventMask, + u32 uNotifyType, + struct DSP_NOTIFICATION + *hNotification); + + extern void WMD_DEH_Notify(struct DEH_MGR *hDehMgr, + u32 ulEventMask, u32 dwErrInfo); +#endif /* WMDDEH_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/wmdio.h b/arch/arm/plat-omap/include/dspbridge/wmdio.h new file mode 100644 index 0000000..8525474 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/wmdio.h @@ -0,0 +1,53 @@ +/* + * wmdio.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== wmdio.h ======== + * Description: + * Declares the upper edge IO functions required by + * all WMD / WCD driver interface tables. + * + * Public Functions: + * + * Notes: + * Function comment headers reside with the function typedefs in wmd.h. + * + *! Revision History: + *! ================ + *! 27-Feb-2004 vp Added IVA releated function. + *! 06-Nov-2000 jeh Created. + */ + +#ifndef WMDIO_ +#define WMDIO_ + +#include +#include + + extern DSP_STATUS WMD_IO_Create(OUT struct IO_MGR **phIOMgr, + struct DEV_OBJECT *hDevObject, + IN CONST struct IO_ATTRS *pMgrAttrs); + + extern DSP_STATUS WMD_IO_Destroy(struct IO_MGR *hIOMgr); + + extern DSP_STATUS WMD_IO_OnLoaded(struct IO_MGR *hIOMgr); + + extern DSP_STATUS IVA_IO_OnLoaded(struct IO_MGR *hIOMgr); + extern DSP_STATUS WMD_IO_GetProcLoad(IN struct IO_MGR *hIOMgr, + OUT struct DSP_PROCLOADSTAT *pProcStat); + +#endif /* WMDIO_ */ diff --git a/arch/arm/plat-omap/include/dspbridge/wmdioctl.h b/arch/arm/plat-omap/include/dspbridge/wmdioctl.h new file mode 100644 index 0000000..a41c61a --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/wmdioctl.h @@ -0,0 +1,91 @@ +/* + * wmdioctl.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== wmdioctl.h ======== + * Description: + * BRIDGE Minidriver BRD_IOCtl reserved command definitions. + * + *! Revision History + *! ================ + *! 19-Apr-2004 sb Updated HW typedefs + *! 16-Feb-2004 vp Added MMU endianness attributes to WMDIOCTL_EXTPROC + *! 21-Mar-2003 sb Changed WMDIOCTL_NUMOFMMUTLB from 7 to 32 + *! 14-May-2001 sg Added codes for PWR. + *! 10-Aug-2001 ag Added _SETMMUCONFIG ioctl used for DSP-MMU init. + *! 16-Nov-1999 rajesh ? + *! 18-Jun-1998 ag Moved EMIF, SDRAM_C, & CE space init to ENBLEXTMEM ioctl. + *! Added ENBLEXTMEM, RESETDSP, UNRESETDSP & ASSERTSIG ioctls. + *! 07-Jun-1998 ag Added JTAG_SELECT, MAP_TBC, GET_CONFIGURATION ioctls. + *! 26-Jan-1998 jeh: Added START, RECV, and SEND ioctls. + *! 07-Nov-1997 nn: Added command to interrupt DSP for interrupt test. + *! 20-Oct-1997 nn: Added commands for getting and resetting interrupt count. + *! 17-Oct-1997 gp: Moved to src/wmd. Standardized prefix. + *! 08-Oct-1997 nn: Created. + */ + +#ifndef WMDIOCTL_ +#define WMDIOCTL_ + +/* ------------------------------------ Hardware Abstraction Layer */ +#include +#include + +/* Any IOCTLS at or above this value are reserved for standard WMD interfaces.*/ +#define WMDIOCTL_RESERVEDBASE 0x8000 + +#define WMDIOCTL_CHNLREAD (WMDIOCTL_RESERVEDBASE + 0x10) +#define WMDIOCTL_CHNLWRITE (WMDIOCTL_RESERVEDBASE + 0x20) +#define WMDIOCTL_GETINTRCOUNT (WMDIOCTL_RESERVEDBASE + 0x30) +#define WMDIOCTL_RESETINTRCOUNT (WMDIOCTL_RESERVEDBASE + 0x40) +#define WMDIOCTL_INTERRUPTDSP (WMDIOCTL_RESERVEDBASE + 0x50) +#define WMDIOCTL_SETMMUCONFIG (WMDIOCTL_RESERVEDBASE + 0x60) /* DMMU */ +#define WMDIOCTL_PWRCONTROL (WMDIOCTL_RESERVEDBASE + 0x70) /* PWR */ + +/* attention, modifiers: + * Some of these control enumerations are made visible to user for power + * control, so any changes to this list, should also be updated in the user + * header file 'dbdefs.h' ***/ +/* These ioctls are reserved for PWR power commands for the DSP */ +#define WMDIOCTL_DEEPSLEEP (WMDIOCTL_PWRCONTROL + 0x0) +#define WMDIOCTL_EMERGENCYSLEEP (WMDIOCTL_PWRCONTROL + 0x1) +#define WMDIOCTL_WAKEUP (WMDIOCTL_PWRCONTROL + 0x2) +#define WMDIOCTL_PWRENABLE (WMDIOCTL_PWRCONTROL + 0x3) +#define WMDIOCTL_PWRDISABLE (WMDIOCTL_PWRCONTROL + 0x4) +#define WMDIOCTL_CLK_CTRL (WMDIOCTL_PWRCONTROL + 0x7) +#define WMDIOCTL_PWR_HIBERNATE (WMDIOCTL_PWRCONTROL + 0x8) /*DSP Initiated + * Hibernate*/ +#define WMDIOCTL_PRESCALE_NOTIFY (WMDIOCTL_PWRCONTROL + 0x9) +#define WMDIOCTL_POSTSCALE_NOTIFY (WMDIOCTL_PWRCONTROL + 0xA) +#define WMDIOCTL_CONSTRAINT_REQUEST (WMDIOCTL_PWRCONTROL + 0xB) + +/* Number of actual DSP-MMU TLB entrries */ +#define WMDIOCTL_NUMOFMMUTLB 32 + +struct WMDIOCTL_EXTPROC { + u32 ulDspVa; /* DSP virtual address */ + u32 ulGppPa; /* GPP physical address */ + /* GPP virtual address. __va does not work for ioremapped addresses */ + u32 ulGppVa; + u32 ulSize; /* Size of the mapped memory in bytes */ + enum HW_Endianism_t endianism; + enum HW_MMUMixedSize_t mixedMode; + enum HW_ElementSize_t elemSize; +}; + +#endif /* WMDIOCTL_ */ + diff --git a/arch/arm/plat-omap/include/dspbridge/wmdmsg.h b/arch/arm/plat-omap/include/dspbridge/wmdmsg.h new file mode 100644 index 0000000..81198d4 --- /dev/null +++ b/arch/arm/plat-omap/include/dspbridge/wmdmsg.h @@ -0,0 +1,70 @@ +/* + * wmdmsg.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== wmdmsg.h ======== + * Description: + * Declares the upper edge message class library functions required by + * all WMD / WCD driver interface tables. These functions are + * implemented by every class of WMD channel library. + * + * Public Functions: + * + * Notes: + * Function comment headers reside with the function typedefs in wmd.h. + * + *! Revision History: + *! ================ + *! 06-Dec-2000 jeh Added uEventMask to WMD_MSG_RegisterNotify(). Added + *! WMD_MSG_SetQueueId(). + *! 17-Nov-2000 jeh Created. + */ + +#ifndef WMDMSG_ +#define WMDMSG_ + +#include + + extern DSP_STATUS WMD_MSG_Create(OUT struct MSG_MGR **phMsgMgr, + struct DEV_OBJECT *hDevObject, + MSG_ONEXIT msgCallback); + + extern DSP_STATUS WMD_MSG_CreateQueue(struct MSG_MGR *hMsgMgr, + OUT struct MSG_QUEUE **phMsgQueue, + u32 dwId, u32 uMaxMsgs, + HANDLE h); + + extern void WMD_MSG_Delete(struct MSG_MGR *hMsgMgr); + + extern void WMD_MSG_DeleteQueue(struct MSG_QUEUE *hMsgQueue); + + extern DSP_STATUS WMD_MSG_Get(struct MSG_QUEUE *hMsgQueue, + struct DSP_MSG *pMsg, u32 uTimeout); + + extern DSP_STATUS WMD_MSG_Put(struct MSG_QUEUE *hMsgQueue, + IN CONST struct DSP_MSG *pMsg, + u32 uTimeout); + + extern DSP_STATUS WMD_MSG_RegisterNotify(struct MSG_QUEUE *hMsgQueue, + u32 uEventMask, + u32 uNotifyType, + struct DSP_NOTIFICATION + *hNotification); + + extern void WMD_MSG_SetQueueId(struct MSG_QUEUE *hMsgQueue, u32 dwId); + +#endif /* WMDMSG_ */ diff --git a/drivers/Makefile b/drivers/Makefile index fec4d8e..6fcee09 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_PARPORT) += parport/ obj-y += base/ block/ misc/ mfd/ net/ media/ obj-y += i2c/ obj-y += cbus/ +obj-$(CONFIG_MPU_BRIDGE) += dsp/bridge/ obj-$(CONFIG_NUBUS) += nubus/ obj-$(CONFIG_ATM) += atm/ obj-y += macintosh/ diff --git a/drivers/dsp/bridge/Kbuild b/drivers/dsp/bridge/Kbuild new file mode 100644 index 0000000..3432ff2 --- /dev/null +++ b/drivers/dsp/bridge/Kbuild @@ -0,0 +1,39 @@ +obj-$(CONFIG_MPU_BRIDGE) += bridgedriver.o + +libgen = gen/gb.o gen/gt.o gen/gs.o gen/gh.o gen/_gt_para.o gen/uuidutil.o +libservices = services/csl.o services/mem.o services/list.o services/dpc.o \ + services/kfile.o services/sync.o \ + services/clk.o services/cfg.o services/reg.o \ + services/regsup.o services/ntfy.o \ + services/dbg.o services/services.o +libwmd = wmd/chnl_sm.o wmd/msg_sm.o wmd/io_sm.o wmd/tiomap3430.o \ + wmd/tiomap3430_pwr.o wmd/tiomap_sm.o wmd/tiomap_io.o \ + wmd/mmu_fault.o wmd/ue_deh.o +libpmgr = pmgr/chnl.o pmgr/io.o pmgr/msg.o pmgr/cod.o pmgr/dev.o pmgr/wcd.o \ + pmgr/dmm.o pmgr/cmm.o pmgr/dbll.o +librmgr = rmgr/dbdcd.o rmgr/disp.o rmgr/drv.o rmgr/mgr.o rmgr/node.o \ + rmgr/proc.o rmgr/pwr.o rmgr/rmm.o rmgr/strm.o rmgr/dspdrv.o \ + rmgr/nldr.o rmgr/drv_interface.o +libdload = dynload/cload.o dynload/getsection.o dynload/reloc.o +libhw = hw/hw_prcm.o hw/hw_dspssC64P.o hw/hw_mmu.o hw/hw_mbox.o + +bridgedriver-objs = $(libgen) $(libservices) $(libwmd) $(libpmgr) $(librmgr) \ + $(libdload) $(libhw) + +# Debug +ifeq ($(CONFIG_BRIDGE_DEBUG),y) +ccflags-y += -DGT_TRACE -DDEBUG +endif + +#Machine dependent +ccflags-y += -D_TI_ -D_DB_TIOMAP -DTMS32060 \ + -DTICFG_PROC_VER -DTICFG_EVM_TYPE -DCHNL_SMCLASS \ + -DCHNL_MESSAGES -DUSE_LEVEL_1_MACROS + +#Header files +ccflags-y += -Idrivers/dsp/bridge/services +ccflags-y += -Idrivers/dsp/bridge/wmd +ccflags-y += -Idrivers/dsp/bridge/pmgr +ccflags-y += -Idrivers/dsp/bridge/rmgr +ccflags-y += -Idrivers/dsp/bridge/hw +ccflags-y += -Iarch/arm diff --git a/drivers/dsp/bridge/Kconfig b/drivers/dsp/bridge/Kconfig new file mode 100644 index 0000000..2fed82c --- /dev/null +++ b/drivers/dsp/bridge/Kconfig @@ -0,0 +1,36 @@ +# +# DSP Bridge Driver Support +# + +menuconfig MPU_BRIDGE + tristate "DSP Bridge driver" + default n + help + DSP/BIOS Bridge is designed for platforms that contain a GPP and + one or more attached DSPs. The GPP is considered the master or + "host" processor, and the attached DSPs are processing resources + that can be utilized by applications and drivers running on the GPP. + +config BRIDGE_DVFS + bool "Enable Bridge Dynamic Voltage and Frequency Scaling (DVFS)" + depends on MPU_BRIDGE && OMAP_PM_SRF + default n + help + DVFS allows DSP Bridge to initiate the operating point change to + scale the chip voltage and frequency in order to match the + performance and power consumption to the current processing + requirements. + +config BRIDGE_MEMPOOL_SIZE + hex "Physical memory pool size (Byte)" + depends on MPU_BRIDGE + default 0x600000 + help + Allocate specified size of memory at booting time to avoid allocation + failure under heavy memory fragmentation after some use time. + +config BRIDGE_DEBUG + bool "DSP Bridge Debug Support" + depends on MPU_BRIDGE + help + Say Y to enable Bridge debugging capabilities diff --git a/drivers/dsp/bridge/dynload/cload.c b/drivers/dsp/bridge/dynload/cload.c new file mode 100644 index 0000000..271ab81 --- /dev/null +++ b/drivers/dsp/bridge/dynload/cload.c @@ -0,0 +1,1854 @@ +/* + * cload.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "header.h" + +#include "module_list.h" +#define LINKER_MODULES_HEADER ("_" MODULES_HEADER) + +/* + * we use the fact that DOFF section records are shaped just like + * LDR_SECTION_INFO to reduce our section storage usage. This macro marks + * the places where that assumption is made + */ +#define DOFFSEC_IS_LDRSEC(pdoffsec) ((struct LDR_SECTION_INFO *)(pdoffsec)) + +/* + * forward references + */ +static void dload_symbols(struct dload_state *dlthis); +static void dload_data(struct dload_state *dlthis); +static void allocate_sections(struct dload_state *dlthis); +static void string_table_free(struct dload_state *dlthis); +static void symbol_table_free(struct dload_state *dlthis); +static void section_table_free(struct dload_state *dlthis); +static void init_module_handle(struct dload_state *dlthis); +#if BITS_PER_AU > BITS_PER_BYTE +static char *unpack_name(struct dload_state *dlthis, u32 soffset); +#endif + +static const char CINITNAME[] = { ".cinit" }; +static const char LOADER_DLLVIEW_ROOT[] = { "?DLModules?" }; + +/* + * Error strings + */ +static const char E_READSTRM[] = { "Error reading %s from input stream" }; +static const char E_ALLOC[] = { "Syms->Allocate( %d ) failed" }; +static const char E_TGTALLOC[] = + { "Target memory allocate failed, section %s size " FMT_UI32 }; +static const char E_INITFAIL[] = { "%s to target address " FMT_UI32 " failed" }; +static const char E_DLVWRITE[] = { "Write to DLLview list failed" }; +static const char E_ICONNECT[] = { "Connect call to init interface failed" }; +static const char E_CHECKSUM[] = { "Checksum failed on %s" }; + +/************************************************************************* + * Procedure dload_error + * + * Parameters: + * errtxt description of the error, printf style + * ... additional information + * + * Effect: + * Reports or records the error as appropriate. + ************************************************************************/ +void dload_error(struct dload_state *dlthis, const char *errtxt, ...) +{ + va_list args; + + va_start(args, errtxt); + dlthis->mysym->Error_Report(dlthis->mysym, errtxt, args); + va_end(args); + dlthis->dload_errcount += 1; + +} /* dload_error */ + +#define DL_ERROR(zza, zzb) dload_error(dlthis, zza, zzb) + +/************************************************************************* + * Procedure dload_syms_error + * + * Parameters: + * errtxt description of the error, printf style + * ... additional information + * + * Effect: + * Reports or records the error as appropriate. + ************************************************************************/ +void dload_syms_error(struct Dynamic_Loader_Sym *syms, const char *errtxt, ...) +{ + va_list args; + + va_start(args, errtxt); + syms->Error_Report(syms, errtxt, args); + va_end(args); +} + +/************************************************************************* + * Procedure Dynamic_Load_Module + * + * Parameters: + * module The input stream that supplies the module image + * syms Host-side symbol table and malloc/free functions + * alloc Target-side memory allocation + * init Target-side memory initialization + * options Option flags DLOAD_* + * mhandle A module handle for use with Dynamic_Unload + * + * Effect: + * The module image is read using *module. Target storage for the new + * image is + * obtained from *alloc. Symbols defined and referenced by the module are + * managed using *syms. The image is then relocated and references + * resolved as necessary, and the resulting executable bits are placed + * into target memory using *init. + * + * Returns: + * On a successful load, a module handle is placed in *mhandle, + * and zero is returned. On error, the number of errors detected is + * returned. Individual errors are reported during the load process + * using syms->Error_Report(). + ***********************************************************************/ +int Dynamic_Load_Module(struct Dynamic_Loader_Stream *module, + struct Dynamic_Loader_Sym *syms , + struct Dynamic_Loader_Allocate *alloc, + struct Dynamic_Loader_Initialize *init, + unsigned options, DLOAD_mhandle *mhandle) +{ + register unsigned *dp, sz; + struct dload_state dl_state; /* internal state for this call */ + + /* blast our internal state */ + dp = (unsigned *)&dl_state; + for (sz = sizeof(dl_state) / sizeof(unsigned); sz > 0; sz -= 1) + *dp++ = 0; + + /* Enable _only_ BSS initialization if enabled by user */ + if ((options & DLOAD_INITBSS) == DLOAD_INITBSS) + dl_state.myoptions = DLOAD_INITBSS; + + /* Check that mandatory arguments are present */ + if (!module || !syms) { + dload_error(&dl_state, "Required parameter is NULL"); + } else { + dl_state.strm = module; + dl_state.mysym = syms; + dload_headers(&dl_state); + if (!dl_state.dload_errcount) + dload_strings(&dl_state, false); + if (!dl_state.dload_errcount) + dload_sections(&dl_state); + + if (init && !dl_state.dload_errcount) { + if (init->connect(init)) { + dl_state.myio = init; + dl_state.myalloc = alloc; + /* do now, before reducing symbols */ + allocate_sections(&dl_state); + } else + dload_error(&dl_state, E_ICONNECT); + } + + if (!dl_state.dload_errcount) { + /* fix up entry point address */ + unsigned sref = dl_state.dfile_hdr.df_entry_secn - 1; + if (sref < dl_state.allocated_secn_count) + dl_state.dfile_hdr.df_entrypt += + dl_state.ldr_sections[sref].run_addr; + + dload_symbols(&dl_state); + } + + if (init && !dl_state.dload_errcount) + dload_data(&dl_state); + + init_module_handle(&dl_state); + + if (dl_state.myio) { + if ((!dl_state.dload_errcount) && + (dl_state.dfile_hdr.df_entry_secn != DN_UNDEF)) { + if (init != NULL) { + if (!init->execute(init, + dl_state.dfile_hdr.df_entrypt)) + dload_error(&dl_state, + "Init->Execute Failed"); + } else { + dload_error(&dl_state, "init is NULL"); + } + } + init->release(init); + } + + symbol_table_free(&dl_state); + section_table_free(&dl_state); + string_table_free(&dl_state); + + if (dl_state.dload_errcount) { + Dynamic_Unload_Module(dl_state.myhandle, syms, alloc, + init); + dl_state.myhandle = NULL; + } + } + + if (mhandle) + *mhandle = dl_state.myhandle; /* give back the handle */ + + return dl_state.dload_errcount; +} /* DLOAD_File */ + +/************************************************************************* + * Procedure Dynamic_Open_Module + * + * Parameters: + * module The input stream that supplies the module image + * syms Host-side symbol table and malloc/free functions + * alloc Target-side memory allocation + * init Target-side memory initialization + * options Option flags DLOAD_* + * mhandle A module handle for use with Dynamic_Unload + * + * Effect: + * The module image is read using *module. Target storage for the new + * image is + * obtained from *alloc. Symbols defined and referenced by the module are + * managed using *syms. The image is then relocated and references + * resolved as necessary, and the resulting executable bits are placed + * into target memory using *init. + * + * Returns: + * On a successful load, a module handle is placed in *mhandle, + * and zero is returned. On error, the number of errors detected is + * returned. Individual errors are reported during the load process + * using syms->Error_Report(). + ***********************************************************************/ +int +Dynamic_Open_Module(struct Dynamic_Loader_Stream *module, + struct Dynamic_Loader_Sym *syms, + struct Dynamic_Loader_Allocate *alloc, + struct Dynamic_Loader_Initialize *init, + unsigned options, DLOAD_mhandle *mhandle) +{ + register unsigned *dp, sz; + struct dload_state dl_state; /* internal state for this call */ + + /* blast our internal state */ + dp = (unsigned *)&dl_state; + for (sz = sizeof(dl_state) / sizeof(unsigned); sz > 0; sz -= 1) + *dp++ = 0; + + /* Enable _only_ BSS initialization if enabled by user */ + if ((options & DLOAD_INITBSS) == DLOAD_INITBSS) + dl_state.myoptions = DLOAD_INITBSS; + + /* Check that mandatory arguments are present */ + if (!module || !syms) { + dload_error(&dl_state, "Required parameter is NULL"); + } else { + dl_state.strm = module; + dl_state.mysym = syms; + dload_headers(&dl_state); + if (!dl_state.dload_errcount) + dload_strings(&dl_state, false); + if (!dl_state.dload_errcount) + dload_sections(&dl_state); + + if (init && !dl_state.dload_errcount) { + if (init->connect(init)) { + dl_state.myio = init; + dl_state.myalloc = alloc; + /* do now, before reducing symbols */ + allocate_sections(&dl_state); + } else + dload_error(&dl_state, E_ICONNECT); + } + + if (!dl_state.dload_errcount) { + /* fix up entry point address */ + unsigned sref = dl_state.dfile_hdr.df_entry_secn - 1; + if (sref < dl_state.allocated_secn_count) + dl_state.dfile_hdr.df_entrypt += + dl_state.ldr_sections[sref].run_addr; + + dload_symbols(&dl_state); + } + + init_module_handle(&dl_state); + + if (dl_state.myio) { + if ((!dl_state.dload_errcount) + && (dl_state.dfile_hdr.df_entry_secn != DN_UNDEF)) + if (!init->execute(init, + dl_state.dfile_hdr.df_entrypt)) + dload_error(&dl_state, + "Init->Execute Failed"); + init->release(init); + } + + symbol_table_free(&dl_state); + section_table_free(&dl_state); + string_table_free(&dl_state); + + if (dl_state.dload_errcount) { + Dynamic_Unload_Module(dl_state.myhandle, syms, alloc, + init); + dl_state.myhandle = NULL; + } + } + + if (mhandle) + *mhandle = dl_state.myhandle; /* give back the handle */ + + return dl_state.dload_errcount; +} /* DLOAD_File */ + +/************************************************************************* + * Procedure dload_headers + * + * Parameters: + * none + * + * Effect: + * Loads the DOFF header and verify record. Deals with any byte-order + * issues and checks them for validity. + ************************************************************************/ +#define COMBINED_HEADER_SIZE (sizeof(struct doff_filehdr_t)+ \ + sizeof(struct doff_verify_rec_t)) + +void dload_headers(struct dload_state *dlthis) +{ + u32 map; + + /* Read the header and the verify record as one. If we don't get it + all, we're done */ + if (dlthis->strm->read_buffer(dlthis->strm, &dlthis->dfile_hdr, + COMBINED_HEADER_SIZE) != COMBINED_HEADER_SIZE) { + DL_ERROR(E_READSTRM, "File Headers"); + return; + } + /* + * Verify that we have the byte order of the file correct. + * If not, must fix it before we can continue + */ + map = REORDER_MAP(dlthis->dfile_hdr.df_byte_reshuffle); + if (map != REORDER_MAP(BYTE_RESHUFFLE_VALUE)) { + /* input is either byte-shuffled or bad */ + if ((map & 0xFCFCFCFC) == 0) { /* no obviously bogus bits */ + dload_reorder(&dlthis->dfile_hdr, COMBINED_HEADER_SIZE, + map); + } + if (dlthis->dfile_hdr.df_byte_reshuffle != + BYTE_RESHUFFLE_VALUE) { + /* didn't fix the problem, the byte swap map is bad */ + dload_error(dlthis, + "Bad byte swap map " FMT_UI32 " in header", + dlthis->dfile_hdr.df_byte_reshuffle); + return; + } + dlthis->reorder_map = map; /* keep map for future use */ + } + + /* + * Verify checksum of header and verify record + */ + if (~dload_checksum(&dlthis->dfile_hdr, + sizeof(struct doff_filehdr_t)) || + ~dload_checksum(&dlthis->verify, + sizeof(struct doff_verify_rec_t))) { + DL_ERROR(E_CHECKSUM, "header or verify record"); + return; + } +#if HOST_ENDIANNESS + dlthis->dfile_hdr.df_byte_reshuffle = map; /* put back for later */ +#endif + + /* Check for valid target ID */ + if ((dlthis->dfile_hdr.df_target_id != TARGET_ID) && + -(dlthis->dfile_hdr.df_target_id != TMS470_ID)) { + dload_error(dlthis, "Bad target ID 0x%x and TARGET_ID 0x%x", + dlthis->dfile_hdr.df_target_id, TARGET_ID); + return; + } + /* Check for valid file format */ + if ((dlthis->dfile_hdr.df_doff_version != DOFF0)) { + dload_error(dlthis, "Bad DOFF version 0x%x", + dlthis->dfile_hdr.df_doff_version); + return; + } + + /* + * Apply reasonableness checks to count fields + */ + if (dlthis->dfile_hdr.df_strtab_size > MAX_REASONABLE_STRINGTAB) { + dload_error(dlthis, "Excessive string table size " FMT_UI32, + dlthis->dfile_hdr.df_strtab_size); + return; + } + if (dlthis->dfile_hdr.df_no_scns > MAX_REASONABLE_SECTIONS) { + dload_error(dlthis, "Excessive section count 0x%x", + dlthis->dfile_hdr.df_no_scns); + return; + } +#ifndef TARGET_ENDIANNESS + /* + * Check that endianness does not disagree with explicit specification + */ + if ((dlthis->dfile_hdr.df_flags >> ALIGN_COFF_ENDIANNESS) & + dlthis->myoptions & ENDIANNESS_MASK) { + dload_error(dlthis, + "Input endianness disagrees with specified option"); + return; + } + dlthis->big_e_target = dlthis->dfile_hdr.df_flags & DF_BIG; +#endif + +} /* dload_headers */ + +/* COFF Section Processing + * + * COFF sections are read in and retained intact. Each record is embedded + * in a new structure that records the updated load and + * run addresses of the section */ + +static const char SECN_ERRID[] = { "section" }; + +/************************************************************************* + * Procedure dload_sections + * + * Parameters: + * none + * + * Effect: + * Loads the section records into an internal table. + ************************************************************************/ +void +dload_sections(struct dload_state *dlthis) +{ + s16 siz; + struct doff_scnhdr_t *shp; + unsigned nsecs = dlthis->dfile_hdr.df_no_scns; + + /* allocate space for the DOFF section records */ + siz = nsecs * sizeof(struct doff_scnhdr_t); + shp = (struct doff_scnhdr_t *)dlthis->mysym->Allocate(dlthis->mysym, + siz); + if (!shp) { /* not enough storage */ + DL_ERROR(E_ALLOC, siz); + return; + } + dlthis->sect_hdrs = shp; + + /* read in the section records */ + if (dlthis->strm->read_buffer(dlthis->strm, shp, siz) != siz) { + DL_ERROR(E_READSTRM, SECN_ERRID); + return; + } + + /* if we need to fix up byte order, do it now */ + if (dlthis->reorder_map) + dload_reorder(shp, siz, dlthis->reorder_map); + + /* check for validity */ + if (~dload_checksum(dlthis->sect_hdrs, siz) != + dlthis->verify.dv_scn_rec_checksum) { + DL_ERROR(E_CHECKSUM, SECN_ERRID); + return; + } + +} /* dload_sections */ + +/***************************************************************************** + * Procedure allocate_sections + * + * Parameters: + * alloc target memory allocator class + * + * Effect: + * Assigns new (target) addresses for sections + *****************************************************************************/ +static void allocate_sections(struct dload_state *dlthis) +{ + u16 curr_sect, nsecs, siz; + struct doff_scnhdr_t *shp; + struct LDR_SECTION_INFO *asecs; + struct my_handle *hndl; + nsecs = dlthis->dfile_hdr.df_no_scns; + if (!nsecs) + return; + if ((dlthis->myalloc == NULL) && + (dlthis->dfile_hdr.df_target_scns > 0)) { + DL_ERROR("Arg 3 (alloc) required but NULL", 0); + return; + } + /* allocate space for the module handle, which we will + * keep for unload purposes */ + siz = dlthis->dfile_hdr.df_target_scns * + sizeof(struct LDR_SECTION_INFO) + MY_HANDLE_SIZE; + hndl = (struct my_handle *)dlthis->mysym->Allocate(dlthis->mysym, siz); + if (!hndl) { /* not enough storage */ + DL_ERROR(E_ALLOC, siz); + return; + } + /* initialize the handle header */ + hndl->dm.hnext = hndl->dm.hprev = hndl; /* circular list */ + hndl->dm.hroot = NULL; + hndl->dm.dbthis = 0; + dlthis->myhandle = hndl; /* save away for return */ + /* pointer to the section list of allocated sections */ + dlthis->ldr_sections = asecs = hndl->secns; + /* * Insert names into all sections, make copies of + the sections we allocate */ + shp = dlthis->sect_hdrs; + for (curr_sect = 0; curr_sect < nsecs; curr_sect++) { + u32 soffset = shp->ds_offset; +#if BITS_PER_AU <= BITS_PER_BYTE + /* attempt to insert the name of this section */ + if (soffset < dlthis->dfile_hdr.df_strtab_size) + DOFFSEC_IS_LDRSEC(shp)->name = dlthis->str_head + + soffset; + else { + dload_error(dlthis, "Bad name offset in section %d", + curr_sect); + DOFFSEC_IS_LDRSEC(shp)->name = NULL; + } +#endif + /* allocate target storage for sections that require it */ + if (DS_NEEDS_ALLOCATION(shp)) { + *asecs = *DOFFSEC_IS_LDRSEC(shp); + asecs->context = 0; /* zero the context field */ +#if BITS_PER_AU > BITS_PER_BYTE + asecs->name = unpack_name(dlthis, soffset); + dlthis->debug_string_size = soffset + dlthis->temp_len; +#else + dlthis->debug_string_size = soffset; +#endif + if (dlthis->myalloc != NULL) { + if (!dlthis->myalloc->Allocate(dlthis->myalloc, asecs, + DS_ALIGNMENT(asecs->type))) { + dload_error(dlthis, E_TGTALLOC, asecs->name, + asecs->size); + return; + } + } + /* keep address deltas in original section table */ + shp->ds_vaddr = asecs->load_addr - shp->ds_vaddr; + shp->ds_paddr = asecs->run_addr - shp->ds_paddr; + dlthis->allocated_secn_count += 1; + } /* allocate target storage */ + shp += 1; + asecs += 1; + } +#if BITS_PER_AU <= BITS_PER_BYTE + dlthis->debug_string_size += + strlen(dlthis->str_head + dlthis->debug_string_size) + 1; +#endif +} /* allocate sections */ + +/************************************************************************* + * Procedure section_table_free + * + * Parameters: + * none + * + * Effect: + * Frees any state used by the symbol table. + * + * WARNING: + * This routine is not allowed to declare errors! + ************************************************************************/ +static void section_table_free(struct dload_state *dlthis) +{ + struct doff_scnhdr_t *shp; + + shp = dlthis->sect_hdrs; + if (shp) + dlthis->mysym->Deallocate(dlthis->mysym, shp); + +} /* section_table_free */ + +/************************************************************************* + * Procedure dload_strings + * + * Parameters: + * sec_names_only If true only read in the "section names" + * portion of the string table + * + * Effect: + * Loads the DOFF string table into memory. DOFF keeps all strings in a + * big unsorted array. We just read that array into memory in bulk. + ************************************************************************/ +static const char S_STRINGTBL[] = { "string table" }; +void dload_strings(struct dload_state *dlthis, boolean sec_names_only) +{ + u32 ssiz; + char *strbuf; + + if (sec_names_only) { + ssiz = BYTE_TO_HOST(DOFF_ALIGN + (dlthis->dfile_hdr.df_scn_name_size)); + } else { + ssiz = BYTE_TO_HOST(DOFF_ALIGN + (dlthis->dfile_hdr.df_strtab_size)); + } + if (ssiz == 0) + return; + + /* get some memory for the string table */ +#if BITS_PER_AU > BITS_PER_BYTE + strbuf = (char *)dlthis->mysym->Allocate(dlthis->mysym, ssiz + + dlthis->dfile_hdr.df_max_str_len); +#else + strbuf = (char *)dlthis->mysym->Allocate(dlthis->mysym, ssiz); +#endif + if (strbuf == NULL) { + DL_ERROR(E_ALLOC, ssiz); + return; + } + dlthis->str_head = strbuf; +#if BITS_PER_AU > BITS_PER_BYTE + dlthis->str_temp = strbuf + ssiz; +#endif + /* read in the strings and verify them */ + if ((unsigned)(dlthis->strm->read_buffer(dlthis->strm, strbuf, + ssiz)) != ssiz) { + DL_ERROR(E_READSTRM, S_STRINGTBL); + } + /* if we need to fix up byte order, do it now */ +#ifndef _BIG_ENDIAN + if (dlthis->reorder_map) + dload_reorder(strbuf, ssiz, dlthis->reorder_map); + + if ((!sec_names_only) && (~dload_checksum(strbuf, ssiz) != + dlthis->verify.dv_str_tab_checksum)) { + DL_ERROR(E_CHECKSUM, S_STRINGTBL); + } +#else + if (dlthis->dfile_hdr.df_byte_reshuffle != + HOST_BYTE_ORDER(REORDER_MAP(BYTE_RESHUFFLE_VALUE))) { + /* put strings in big-endian order, not in PC order */ + dload_reorder(strbuf, ssiz, HOST_BYTE_ORDER(dlthis->dfile_hdr. + df_byte_reshuffle)); + } + if ((!sec_names_only) && (~dload_reverse_checksum(strbuf, ssiz) != + dlthis->verify.dv_str_tab_checksum)) { + DL_ERROR(E_CHECKSUM, S_STRINGTBL); + } +#endif +} /* dload_strings */ + +/************************************************************************* + * Procedure string_table_free + * + * Parameters: + * none + * + * Effect: + * Frees any state used by the string table. + * + * WARNING: + * This routine is not allowed to declare errors! + *************************************************************************/ +static void string_table_free(struct dload_state *dlthis) +{ + if (dlthis->str_head) + dlthis->mysym->Deallocate(dlthis->mysym, dlthis->str_head); + +} /* string_table_free */ + +/* + * Symbol Table Maintenance Functions + * + * COFF symbols are read by dload_symbols(), which is called after + * sections have been allocated. Symbols which might be used in + * relocation (ie, not debug info) are retained in an internal temporary + * compressed table (type Local_Symbol). A particular symbol is recovered + * by index by calling dload_find_symbol(). dload_find_symbol + * reconstructs a more explicit representation (type SLOTVEC) which is + * used by reloc.c + */ +/* real size of debug header */ +#define DBG_HDR_SIZE (sizeof(struct dll_module) - sizeof(struct dll_sect)) + +static const char SYM_ERRID[] = { "symbol" }; + +/************************************************************************** + * Procedure dload_symbols + * + * Parameters: + * none + * + * Effect: + * Reads in symbols and retains ones that might be needed for relocation + * purposes. + ************************************************************************/ +/* size of symbol buffer no bigger than target data buffer, to limit stack + * usage*/ +#define MY_SYM_BUF_SIZ (BYTE_TO_HOST(IMAGE_PACKET_SIZE)/\ + sizeof(struct doff_syment_t)) + +static void dload_symbols(struct dload_state *dlthis) +{ + u32 s_count, siz, dsiz, symbols_left; + u32 checks; + struct Local_Symbol *sp; + struct dynload_symbol *symp; + struct dynload_symbol *newsym; + + s_count = dlthis->dfile_hdr.df_no_syms; + if (s_count == 0) + return; + + /* We keep a local symbol table for all of the symbols in the input. + * This table contains only section & value info, as we do not have + * to do any name processing for locals. We reuse this storage + * as a temporary for .dllview record construction. + * Allocate storage for the whole table.*/ + siz = s_count * sizeof(struct Local_Symbol); + dsiz = DBG_HDR_SIZE + + (sizeof(struct dll_sect) * dlthis->allocated_secn_count) + + BYTE_TO_HOST_ROUND(dlthis->debug_string_size + 1); + if (dsiz > siz) + siz = dsiz; /* larger of symbols and .dllview temp */ + sp = (struct Local_Symbol *)dlthis->mysym->Allocate(dlthis->mysym, siz); + if (!sp) { + DL_ERROR(E_ALLOC, siz); + return; + } + dlthis->local_symtab = sp; + /* Read the symbols in the input, store them in the table, and post any + * globals to the global symbol table. In the process, externals + become defined from the global symbol table */ + checks = dlthis->verify.dv_sym_tab_checksum; + symbols_left = s_count; + do { /* read all symbols */ + char *sname; + u32 val; + s32 delta; + struct doff_syment_t *input_sym; + unsigned syms_in_buf; + struct doff_syment_t my_sym_buf[MY_SYM_BUF_SIZ]; + input_sym = my_sym_buf; + syms_in_buf = symbols_left > MY_SYM_BUF_SIZ ? + MY_SYM_BUF_SIZ : symbols_left; + siz = syms_in_buf * sizeof(struct doff_syment_t); + if (dlthis->strm->read_buffer(dlthis->strm, input_sym, siz) != + siz) { + DL_ERROR(E_READSTRM, SYM_ERRID); + return; + } + if (dlthis->reorder_map) + dload_reorder(input_sym, siz, dlthis->reorder_map); + + checks += dload_checksum(input_sym, siz); + do { /* process symbols in buffer */ + symbols_left -= 1; + /* attempt to derive the name of this symbol */ + sname = NULL; + if (input_sym->dn_offset > 0) { +#if BITS_PER_AU <= BITS_PER_BYTE + if ((u32) input_sym->dn_offset < + dlthis->dfile_hdr.df_strtab_size) + sname = dlthis->str_head + + BYTE_TO_HOST(input_sym->dn_offset); + else + dload_error(dlthis, + "Bad name offset in symbol %d", + symbols_left); +#else + sname = unpack_name(dlthis, + input_sym->dn_offset); +#endif + } + val = input_sym->dn_value; + delta = 0; + sp->sclass = input_sym->dn_sclass; + sp->secnn = input_sym->dn_scnum; + /* if this is an undefined symbol, + * define it (or fail) now */ + if (sp->secnn == DN_UNDEF) { + /* pointless for static undefined */ + if (input_sym->dn_sclass != DN_EXT) + goto loop_cont; + + /* try to define symbol from previously + * loaded images */ + symp = dlthis->mysym->Find_Matching_Symbol + (dlthis->mysym, sname); + if (!symp) { + DL_ERROR + ("Undefined external symbol %s", + sname); + goto loop_cont; + } + val = delta = symp->value; + goto loop_cont; + } + /* symbol defined by this module */ + if (sp->secnn > 0) { /* symbol references a section */ + if ((unsigned)sp->secnn <= + dlthis->allocated_secn_count) { + /* section was allocated */ + struct doff_scnhdr_t *srefp = + &dlthis->sect_hdrs + [sp->secnn - 1]; + + if (input_sym->dn_sclass == + DN_STATLAB || + input_sym->dn_sclass == DN_EXTLAB){ + /* load */ + delta = srefp->ds_vaddr; + } else { + /* run */ + delta = srefp->ds_paddr; + } + val += delta; + } + goto loop_itr; + } + /* This symbol is an absolute symbol */ + if (sp->secnn == DN_ABS && ((sp->sclass == DN_EXT) || + (sp->sclass == DN_EXTLAB))) { + symp = dlthis->mysym->Find_Matching_Symbol + (dlthis->mysym, sname); + if (!symp) + goto loop_itr; + /* This absolute symbol is already defined. */ + if (symp->value == input_sym->dn_value) { + /* If symbol values are equal, continue + * but don't add to the global symbol + * table */ + sp->value = val; + sp->delta = delta; + sp += 1; + input_sym += 1; + continue; + } else { + /* If symbol values are not equal, + * return with redefinition error */ + DL_ERROR("Absolute symbol %s is " + "defined multiple times with " + "different values", sname); + return; + } + } +loop_itr: + /* if this is a global symbol, post it to the + * global table */ + if (input_sym->dn_sclass == DN_EXT || + input_sym->dn_sclass == DN_EXTLAB) { + /* Keep this global symbol for subsequent + * modules. Don't complain on error, to allow + * symbol API to suppress global symbols */ + if (!sname) + goto loop_cont; + + newsym = dlthis->mysym->Add_To_Symbol_Table + (dlthis->mysym, sname, + (unsigned)dlthis->myhandle); + if (newsym) + newsym->value = val; + + } /* global */ +loop_cont: + sp->value = val; + sp->delta = delta; + sp += 1; + input_sym += 1; + } while ((syms_in_buf -= 1) > 0); /* process sym in buffer */ + } while (symbols_left > 0); /* read all symbols */ + if (~checks) + dload_error(dlthis, "Checksum of symbols failed"); + +} /* dload_symbols */ + +/***************************************************************************** + * Procedure symbol_table_free + * + * Parameters: + * none + * + * Effect: + * Frees any state used by the symbol table. + * + * WARNING: + * This routine is not allowed to declare errors! + *****************************************************************************/ +static void symbol_table_free(struct dload_state *dlthis) +{ + if (dlthis->local_symtab) { + if (dlthis->dload_errcount) { /* blow off our symbols */ + dlthis->mysym->Purge_Symbol_Table(dlthis->mysym, + (unsigned)dlthis->myhandle); + } + dlthis->mysym->Deallocate(dlthis->mysym, dlthis->local_symtab); + } +} /* symbol_table_free */ + +/* .cinit Processing + * + * The dynamic loader does .cinit interpretation. cload_cinit() + * acts as a special write-to-target function, in that it takes relocated + * data from the normal data flow, and interprets it as .cinit actions. + * Because the normal data flow does not necessarily process the whole + * .cinit section in one buffer, cload_cinit() must be prepared to + * interpret the data piecemeal. A state machine is used for this + * purpose. + */ + +/* The following are only for use by reloc.c and things it calls */ +static const struct LDR_SECTION_INFO CINIT_INFO_INIT = { CINITNAME, 0, 0, + (LDR_ADDR) -1, 0, DLOAD_BSS, 0 }; + +/************************************************************************* + * Procedure cload_cinit + * + * Parameters: + * ipacket Pointer to data packet to be loaded + * + * Effect: + * Interprets the data in the buffer as .cinit data, and performs the + * appropriate initializations. + ************************************************************************/ +static void cload_cinit(struct dload_state *dlthis, + struct image_packet_t *ipacket) +{ +#if TDATA_TO_HOST(CINIT_COUNT)*BITS_PER_AU > 16 + s32 init_count, left; +#else + s16 init_count, left; +#endif + unsigned char *pktp = ipacket->i_bits; + unsigned char *pktend = pktp + + BYTE_TO_HOST_ROUND(ipacket->i_packet_size); + int temp; + LDR_ADDR atmp; + struct LDR_SECTION_INFO cinit_info; + + /* PROCESS ALL THE INITIALIZATION RECORDS IN THE BUFFER. */ + while (true) { + left = pktend - pktp; + switch (dlthis->cinit_state) { + case CI_count: /* count field */ + if (left < TDATA_TO_HOST(CINIT_COUNT)) + goto loopexit; + temp = dload_unpack(dlthis, (TgtAU_t *)pktp, + CINIT_COUNT * TDATA_AU_BITS, 0, + ROP_SGN); + pktp += TDATA_TO_HOST(CINIT_COUNT); + /* negative signifies BSS table, zero means done */ + if (temp <= 0) { + dlthis->cinit_state = CI_done; + break; + } + dlthis->cinit_count = temp; + dlthis->cinit_state = CI_address; + break; +#if CINIT_ALIGN < CINIT_ADDRESS + case CI_partaddress: + pktp -= TDATA_TO_HOST(CINIT_ALIGN); + /* back up pointer into space courtesy of caller */ + *(uint16_t *)pktp = dlthis->cinit_addr; + /* stuff in saved bits !! FALL THRU !! */ +#endif + case CI_address: /* Address field for a copy packet */ + if (left < TDATA_TO_HOST(CINIT_ADDRESS)) { +#if CINIT_ALIGN < CINIT_ADDRESS + if (left == TDATA_TO_HOST(CINIT_ALIGN)) { + /* address broken into halves */ + dlthis->cinit_addr = *(uint16_t *)pktp; + /* remember 1st half */ + dlthis->cinit_state = CI_partaddress; + left = 0; + } +#endif + goto loopexit; + } + atmp = dload_unpack(dlthis, (TgtAU_t *)pktp, + CINIT_ADDRESS * TDATA_AU_BITS, 0, + ROP_UNS); + pktp += TDATA_TO_HOST(CINIT_ADDRESS); +#if CINIT_PAGE_BITS > 0 + dlthis->cinit_page = atmp & + ((1 << CINIT_PAGE_BITS) - 1); + atmp >>= CINIT_PAGE_BITS; +#else + dlthis->cinit_page = CINIT_DEFAULT_PAGE; +#endif + dlthis->cinit_addr = atmp; + dlthis->cinit_state = CI_copy; + break; + case CI_copy: /* copy bits to the target */ + init_count = HOST_TO_TDATA(left); + if (init_count > dlthis->cinit_count) + init_count = dlthis->cinit_count; + if (init_count == 0) + goto loopexit; /* get more bits */ + cinit_info = CINIT_INFO_INIT; + cinit_info.page = dlthis->cinit_page; + if (!dlthis->myio->writemem(dlthis->myio, pktp, + TDATA_TO_TADDR(dlthis->cinit_addr), + &cinit_info, + TDATA_TO_HOST(init_count))) { + dload_error(dlthis, E_INITFAIL, "write", + dlthis->cinit_addr); + } + dlthis->cinit_count -= init_count; + if (dlthis->cinit_count <= 0) { + dlthis->cinit_state = CI_count; + init_count = (init_count + CINIT_ALIGN - 1) & + -CINIT_ALIGN; + /* align to next init */ + } + pktp += TDATA_TO_HOST(init_count); + dlthis->cinit_addr += init_count; + break; + case CI_done: /* no more .cinit to do */ + return; + } /* switch (cinit_state) */ + } /* while */ + +loopexit: + if (left > 0) { + dload_error(dlthis, "%d bytes left over in cinit packet", left); + dlthis->cinit_state = CI_done; /* left over bytes are bad */ + } +} /* cload_cinit */ + +/* Functions to interface to reloc.c + * + * reloc.c is the relocation module borrowed from the linker, with + * minimal (we hope) changes for our purposes. cload_sect_data() invokes + * this module on a section to relocate and load the image data for that + * section. The actual read and write actions are supplied by the global + * routines below. + */ + +/************************************************************************ + * Procedure relocate_packet + * + * Parameters: + * ipacket Pointer to an image packet to relocate + * + * Effect: + * Performs the required relocations on the packet. Returns a checksum + * of the relocation operations. + ************************************************************************/ +#define MY_RELOC_BUF_SIZ 8 +/* careful! exists at the same time as the image buffer*/ +static int relocate_packet(struct dload_state *dlthis, + struct image_packet_t *ipacket, u32 *checks) +{ + u32 rnum; + + rnum = ipacket->i_num_relocs; + do { /* all relocs */ + unsigned rinbuf; + int siz; + struct reloc_record_t *rp, rrec[MY_RELOC_BUF_SIZ]; + rp = rrec; + rinbuf = rnum > MY_RELOC_BUF_SIZ ? MY_RELOC_BUF_SIZ : rnum; + siz = rinbuf * sizeof(struct reloc_record_t); + if (dlthis->strm->read_buffer(dlthis->strm, rp, siz) != siz) { + DL_ERROR(E_READSTRM, "relocation"); + return 0; + } + /* reorder the bytes if need be */ + if (dlthis->reorder_map) + dload_reorder(rp, siz, dlthis->reorder_map); + + *checks += dload_checksum(rp, siz); + do { + /* perform the relocation operation */ + dload_relocate(dlthis, (TgtAU_t *) ipacket->i_bits, rp); + rp += 1; + rnum -= 1; + } while ((rinbuf -= 1) > 0); + } while (rnum > 0); /* all relocs */ + return 1; +} /* dload_read_reloc */ + +#define IPH_SIZE (sizeof(struct image_packet_t) - sizeof(u32)) + +/* VERY dangerous */ +static const char IMAGEPAK[] = { "image packet" }; + +/************************************************************************* + * Procedure dload_data + * + * Parameters: + * none + * + * Effect: + * Read image data from input file, relocate it, and download it to the + * target. + ************************************************************************/ +static void dload_data(struct dload_state *dlthis) +{ + u16 curr_sect; + struct doff_scnhdr_t *sptr = dlthis->sect_hdrs; + struct LDR_SECTION_INFO *lptr = dlthis->ldr_sections; +#ifdef OPT_ZERO_COPY_LOADER + boolean bZeroCopy = false; +#endif + u8 *pDest; + + struct { + struct image_packet_t ipacket; + u8 bufr[BYTE_TO_HOST(IMAGE_PACKET_SIZE)]; + } ibuf; + + /* Indicates whether CINIT processing has occurred */ + boolean cinit_processed = false; + + /* Loop through the sections and load them one at a time. + */ + for (curr_sect = 0; curr_sect < dlthis->dfile_hdr.df_no_scns; + curr_sect += 1) { + if (DS_NEEDS_DOWNLOAD(sptr)) { + s32 nip; + LDR_ADDR image_offset = 0; + /* set relocation info for this section */ + if (curr_sect < dlthis->allocated_secn_count) + dlthis->delta_runaddr = sptr->ds_paddr; + else { + lptr = DOFFSEC_IS_LDRSEC(sptr); + dlthis->delta_runaddr = 0; + } + dlthis->image_secn = lptr; +#if BITS_PER_AU > BITS_PER_BYTE + lptr->name = unpack_name(dlthis, sptr->ds_offset); +#endif + nip = sptr->ds_nipacks; + while ((nip -= 1) >= 0) { /* process packets */ + + s32 ipsize; + u32 checks; + /* get the fixed header bits */ + if (dlthis->strm->read_buffer(dlthis->strm, + &ibuf.ipacket, IPH_SIZE) != IPH_SIZE) { + DL_ERROR(E_READSTRM, IMAGEPAK); + return; + } + /* reorder the header if need be */ + if (dlthis->reorder_map) { + dload_reorder(&ibuf.ipacket, IPH_SIZE, + dlthis->reorder_map); + } + /* now read the rest of the packet */ + ipsize = + BYTE_TO_HOST(DOFF_ALIGN + (ibuf.ipacket.i_packet_size)); + if (ipsize > BYTE_TO_HOST(IMAGE_PACKET_SIZE)) { + DL_ERROR("Bad image packet size %d", + ipsize); + return; + } + pDest = ibuf.bufr; +#ifdef OPT_ZERO_COPY_LOADER + bZeroCopy = false; + if (DLOAD_SECT_TYPE(sptr) != DLOAD_CINIT) { + dlthis->myio->writemem(dlthis->myio, + &pDest, lptr->load_addr + + image_offset, lptr, 0); + bZeroCopy = (pDest != ibuf.bufr); + } +#endif + /* End of determination */ + + if (dlthis->strm->read_buffer(dlthis->strm, + ibuf.bufr, ipsize) != ipsize) { + DL_ERROR(E_READSTRM, IMAGEPAK); + return; + } + ibuf.ipacket.i_bits = pDest; + + /* reorder the bytes if need be */ +#if !defined(_BIG_ENDIAN) || (TARGET_AU_BITS > 16) + if (dlthis->reorder_map) { + dload_reorder(pDest, ipsize, + dlthis->reorder_map); + } + checks = dload_checksum(pDest, ipsize); +#else + if (dlthis->dfile_hdr.df_byte_reshuffle != + TARGET_ORDER(REORDER_MAP + (BYTE_RESHUFFLE_VALUE))) { + /* put image bytes in big-endian order, + * not PC order */ + dload_reorder(pDest, ipsize, + TARGET_ORDER + (dlthis->dfile_hdr.df_byte_reshuffle)); + } +#if TARGET_AU_BITS > 8 + checks = dload_reverse_checksum_16(pDest, + ipsize); +#else + checks = dload_reverse_checksum(pDest, + ipsize); +#endif +#endif + + checks += dload_checksum(&ibuf.ipacket, + IPH_SIZE); + /* relocate the image bits as needed */ + if (ibuf.ipacket.i_num_relocs) { + dlthis->image_offset = image_offset; + if (!relocate_packet(dlthis, + &ibuf.ipacket, &checks)) + return; /* serious error */ + } + if (~checks) + DL_ERROR(E_CHECKSUM, IMAGEPAK); + /* stuff the result into target memory */ + if (DLOAD_SECT_TYPE(sptr) == DLOAD_CINIT) { + cload_cinit(dlthis, &ibuf.ipacket); + cinit_processed = true; + } else { +#ifdef OPT_ZERO_COPY_LOADER + if (!bZeroCopy) { +#endif + + if (!dlthis->myio->writemem + (dlthis->myio, ibuf.bufr, + lptr->load_addr + image_offset, lptr, + BYTE_TO_HOST + (ibuf.ipacket.i_packet_size))) { + DL_ERROR( + "Write to " FMT_UI32 " failed", + lptr->load_addr + image_offset); + } +#ifdef OPT_ZERO_COPY_LOADER + } +#endif + + } + image_offset += + BYTE_TO_TADDR(ibuf.ipacket.i_packet_size); + } /* process packets */ + /* if this is a BSS section, we may want to fill it */ + if (DLOAD_SECT_TYPE(sptr) != DLOAD_BSS) + goto loop_cont; + + if (!(dlthis->myoptions & DLOAD_INITBSS)) + goto loop_cont; + + if (cinit_processed) { + /* Don't clear BSS after load-time + * initialization */ + DL_ERROR + ("Zero-initialization at " FMT_UI32 " after " + "load-time initialization!", lptr->load_addr); + goto loop_cont; + } + /* fill the .bss area */ + dlthis->myio->fillmem(dlthis->myio, + TADDR_TO_HOST(lptr->load_addr), + lptr, TADDR_TO_HOST(lptr->size), + dload_fill_bss); + goto loop_cont; + } /* if DS_DOWNLOAD_MASK */ + /* If not loading, but BSS, zero initialize */ + if (DLOAD_SECT_TYPE(sptr) != DLOAD_BSS) + goto loop_cont; + + if (!(dlthis->myoptions & DLOAD_INITBSS)) + goto loop_cont; + + if (curr_sect >= dlthis->allocated_secn_count) + lptr = DOFFSEC_IS_LDRSEC(sptr); + + if (cinit_processed) { + /*Don't clear BSS after load-time initialization */ + DL_ERROR( + "Zero-initialization at " FMT_UI32 " attempted after " + "load-time initialization!", lptr->load_addr); + goto loop_cont; + } + /* fill the .bss area */ + dlthis->myio->fillmem(dlthis->myio, + TADDR_TO_HOST(lptr->load_addr), lptr, + TADDR_TO_HOST(lptr->size), dload_fill_bss); +loop_cont: + sptr += 1; + lptr += 1; + } /* load sections */ +} /* dload_data */ + +/************************************************************************* + * Procedure dload_reorder + * + * Parameters: + * data 32-bit aligned pointer to data to be byte-swapped + * dsiz size of the data to be reordered in sizeof() units. + * map 32-bit map defining how to reorder the data. Value + * must be REORDER_MAP() of some permutation + * of 0x00 01 02 03 + * + * Effect: + * Re-arranges the bytes in each word according to the map specified. + * + ************************************************************************/ +/* mask for byte shift count */ +#define SHIFT_COUNT_MASK (3 << LOG_BITS_PER_BYTE) + +void dload_reorder(void *data, int dsiz, unsigned int map) +{ + register u32 tmp, tmap, datv; + u32 *dp = (u32 *)data; + + map <<= LOG_BITS_PER_BYTE; /* align map with SHIFT_COUNT_MASK */ + do { + tmp = 0; + datv = *dp; + tmap = map; + do { + tmp |= (datv & BYTE_MASK) << (tmap & SHIFT_COUNT_MASK); + tmap >>= BITS_PER_BYTE; + } while (datv >>= BITS_PER_BYTE); + *dp++ = tmp; + } while ((dsiz -= sizeof(u32)) > 0); +} /* dload_reorder */ + +/************************************************************************* + * Procedure dload_checksum + * + * Parameters: + * data 32-bit aligned pointer to data to be checksummed + * siz size of the data to be checksummed in sizeof() units. + * + * Effect: + * Returns a checksum of the specified block + * + ************************************************************************/ +u32 dload_checksum(void *data, unsigned siz) +{ + u32 sum; + u32 *dp; + int left; + + sum = 0; + dp = (u32 *)data; + for (left = siz; left > 0; left -= sizeof(u32)) + sum += *dp++; + return sum; +} /* dload_checksum */ + +#if HOST_ENDIANNESS +/************************************************************************* + * Procedure dload_reverse_checksum + * + * Parameters: + * data 32-bit aligned pointer to data to be checksummed + * siz size of the data to be checksummed in sizeof() units. + * + * Effect: + * Returns a checksum of the specified block, which is assumed to be bytes + * in big-endian order. + * + * Notes: + * In a big-endian host, things like the string table are stored as bytes + * in host order. But dllcreate always checksums in little-endian order. + * It is most efficient to just handle the difference a word at a time. + * + ***********************************************************************/ +u32 dload_reverse_checksum(void *data, unsigned siz) +{ + u32 sum, temp; + u32 *dp; + int left; + + sum = 0; + dp = (u32 *)data; + + for (left = siz; left > 0; left -= sizeof(u32)) { + temp = *dp++; + sum += temp << BITS_PER_BYTE * 3; + sum += temp >> BITS_PER_BYTE * 3; + sum += (temp >> BITS_PER_BYTE) & (BYTE_MASK << BITS_PER_BYTE); + sum += (temp & (BYTE_MASK << BITS_PER_BYTE)) << BITS_PER_BYTE; + } + + return sum; +} /* dload_reverse_checksum */ + +#if (TARGET_AU_BITS > 8) && (TARGET_AU_BITS < 32) +u32 dload_reverse_checksum_16(void *data, unsigned siz) +{ + uint_fast32_t sum, temp; + u32 *dp; + int left; + + sum = 0; + dp = (u32 *)data; + + for (left = siz; left > 0; left -= sizeof(u32)) { + temp = *dp++; + sum += temp << BITS_PER_BYTE * 2; + sum += temp >> BITS_PER_BYTE * 2; + } + + return sum; +} /* dload_reverse_checksum_16 */ +#endif +#endif + +/************************************************************************* + * Procedure swap_words + * + * Parameters: + * data 32-bit aligned pointer to data to be swapped + * siz size of the data to be swapped. + * bitmap Bit map of how to swap each 32-bit word; 1 => 2 shorts, + * 0 => 1 long + * + * Effect: + * Swaps the specified data according to the specified map + * + ************************************************************************/ +static void swap_words(void *data, unsigned siz, unsigned bitmap) +{ + register int i; +#if TARGET_AU_BITS < 16 + register u16 *sp; +#endif + register u32 *lp; + + siz /= sizeof(u16); + +#if TARGET_AU_BITS < 16 + /* pass 1: do all the bytes */ + i = siz; + sp = (u16 *) data; + do { + register u16 tmp; + tmp = *sp; + *sp++ = SWAP16BY8(tmp); + } while ((i -= 1) > 0); +#endif + +#if TARGET_AU_BITS < 32 + /* pass 2: fixup the 32-bit words */ + i = siz >> 1; + lp = (u32 *) data; + do { + if ((bitmap & 1) == 0) { + register u32 tmp; + tmp = *lp; + *lp = SWAP32BY16(tmp); + } + lp += 1; + bitmap >>= 1; + } while ((i -= 1) > 0); +#endif +} /* swap_words */ + +/************************************************************************* + * Procedure copy_tgt_strings + * + * Parameters: + * dstp Destination address. Assumed to be 32-bit aligned + * srcp Source address. Assumed to be 32-bit aligned + * charcount Number of characters to copy. + * + * Effect: + * Copies strings from the source (which is in usual .dof file order on + * the loading processor) to the destination buffer (which should be in proper + * target addressable unit order). Makes sure the last string in the + * buffer is NULL terminated (for safety). + * Returns the first unused destination address. + ************************************************************************/ +static char *copy_tgt_strings(void *dstp, void *srcp, unsigned charcount) +{ + register TgtAU_t *src = (TgtAU_t *)srcp; + register TgtAU_t *dst = (TgtAU_t *)dstp; + register int cnt = charcount; + do { +#if TARGET_AU_BITS <= BITS_PER_AU + /* byte-swapping issues may exist for strings on target */ + *dst++ = *src++; +#elif TARGET_ENDIANNESS_DIFFERS(TARGET_BIG_ENDIAN) + register TgtAU_t tmp; + tmp = *src++; + *dst++ = SWAP16BY8(tmp); /* right for TARGET_AU_BITS == 16 */ +#else + *dst++ = *src++; +#endif + } while ((cnt -= (sizeof(TgtAU_t) * BITS_PER_AU / BITS_PER_BYTE)) > 0); + /*apply force to make sure that the string table has null terminator */ +#if (BITS_PER_AU == BITS_PER_BYTE) && (TARGET_AU_BITS == BITS_PER_BYTE) + dst[-1] = 0; +#elif TARGET_BIG_ENDIAN + dst[-1] &= ~BYTE_MASK; /* big-endian */ +#else + dst[-1] &= (1 << (BITS_PER_AU - BITS_PER_BYTE)) - 1; /* little endian */ +#endif + return (char *)dst; +} /* copy_tgt_strings */ + +/************************************************************************* + * Procedure init_module_handle + * + * Parameters: + * none + * + * Effect: + * Initializes the module handle we use to enable unloading, and installs + * the debug information required by the target. + * + * Notes: + * The handle returned from Dynamic_Load_Module needs to encapsulate all the + * allocations done for the module, and enable them plus the modules symbols to + * be deallocated. + * + ************************************************************************/ +#ifndef _BIG_ENDIAN +static const struct LDR_SECTION_INFO DLLVIEW_INFO_INIT = { ".dllview", 0, 0, + (LDR_ADDR) -1, DBG_LIST_PAGE, DLOAD_DATA, 0 }; +#else +static const struct LDR_SECTION_INFO DLLVIEW_INFO_INIT = { ".dllview", 0, 0, + (LDR_ADDR) -1, DLOAD_DATA, DBG_LIST_PAGE, 0 }; +#endif +static void init_module_handle(struct dload_state *dlthis) +{ + struct my_handle *hndl; + u16 curr_sect; + struct LDR_SECTION_INFO *asecs; + struct dll_module *dbmod; + struct dll_sect *dbsec; + struct dbg_mirror_root *mlist; + register char *cp; + struct modules_header mhdr; + struct LDR_SECTION_INFO dllview_info; + struct dynload_symbol *debug_mirror_sym; + hndl = dlthis->myhandle; + if (!hndl) + return; /* must be errors detected, so forget it */ + hndl->secn_count = dlthis->allocated_secn_count << 1; +#ifndef TARGET_ENDIANNESS + if (dlthis->big_e_target) + hndl->secn_count += 1; /* flag for big-endian */ +#endif + if (dlthis->dload_errcount) + return; /* abandon if errors detected */ + /* Locate the symbol that names the header for the CCS debug list + of modules. If not found, we just don't generate the debug record. + If found, we create our modules list. We make sure to create the + LOADER_DLLVIEW_ROOT even if there is no relocation info to record, + just to try to put both symbols in the same symbol table and + module.*/ + debug_mirror_sym = dlthis->mysym->Find_Matching_Symbol(dlthis->mysym, + LOADER_DLLVIEW_ROOT); + if (!debug_mirror_sym) { + struct dynload_symbol *dlmodsym; + struct dbg_mirror_root *mlst; + + /* our root symbol is not yet present; + check if we have DLModules defined */ + dlmodsym = dlthis->mysym->Find_Matching_Symbol(dlthis->mysym, + LINKER_MODULES_HEADER); + if (!dlmodsym) + return; /* no DLModules list so no debug info */ + /* if we have DLModules defined, construct our header */ + mlst = (struct dbg_mirror_root *) + dlthis->mysym->Allocate(dlthis->mysym, + sizeof(struct dbg_mirror_root)); + if (!mlst) { + DL_ERROR(E_ALLOC, sizeof(struct dbg_mirror_root)); + return; + } + mlst->hnext = NULL; + mlst->changes = 0; + mlst->refcount = 0; + mlst->dbthis = TDATA_TO_TADDR(dlmodsym->value); + /* add our root symbol */ + debug_mirror_sym = dlthis->mysym->Add_To_Symbol_Table + (dlthis->mysym, LOADER_DLLVIEW_ROOT, + (unsigned)dlthis->myhandle); + if (!debug_mirror_sym) { + /* failed, recover memory */ + dlthis->mysym->Deallocate(dlthis->mysym, mlst); + return; + } + debug_mirror_sym->value = (u32)mlst; + } + /* First create the DLLview record and stuff it into the buffer. + Then write it to the DSP. Record pertinent locations in our hndl, + and add it to the per-processor list of handles with debug info.*/ +#ifndef DEBUG_HEADER_IN_LOADER + mlist = (struct dbg_mirror_root *)debug_mirror_sym->value; + if (!mlist) + return; +#else + mlist = (struct dbg_mirror_root *)&debug_list_header; +#endif + hndl->dm.hroot = mlist; /* set pointer to root into our handle */ + if (!dlthis->allocated_secn_count) + return; /* no load addresses to be recorded */ + /* reuse temporary symbol storage */ + dbmod = (struct dll_module *) dlthis->local_symtab; + /* Create the DLLview record in the memory we retain for our handle*/ + dbmod->num_sects = dlthis->allocated_secn_count; + dbmod->timestamp = dlthis->verify.dv_timdat; + dbmod->version = INIT_VERSION; + dbmod->verification = VERIFICATION; + asecs = dlthis->ldr_sections; + dbsec = dbmod->sects; + for (curr_sect = dlthis->allocated_secn_count; + curr_sect > 0; curr_sect -= 1) { + dbsec->sect_load_adr = asecs->load_addr; + dbsec->sect_run_adr = asecs->run_addr; + dbsec += 1; + asecs += 1; + } + /* now cram in the names */ + cp = copy_tgt_strings(dbsec, dlthis->str_head, + dlthis->debug_string_size); + + /* round off the size of the debug record, and remember same */ + hndl->dm.dbsiz = HOST_TO_TDATA_ROUND(cp - (char *)dbmod); + *cp = 0; /* strictly to make our test harness happy */ + dllview_info = DLLVIEW_INFO_INIT; + dllview_info.size = TDATA_TO_TADDR(hndl->dm.dbsiz); + /* Initialize memory context to default heap */ + dllview_info.context = 0; + hndl->dm.context = 0; + /* fill in next pointer and size */ + if (mlist->hnext) { + dbmod->next_module = TADDR_TO_TDATA(mlist->hnext->dm.dbthis); + dbmod->next_module_size = mlist->hnext->dm.dbsiz; + } else { + dbmod->next_module_size = 0; + dbmod->next_module = 0; + } + /* allocate memory for on-DSP DLLview debug record */ + if (!dlthis->myalloc) + return; + if (!dlthis->myalloc->Allocate(dlthis->myalloc, &dllview_info, + HOST_TO_TADDR(sizeof(u32)))) { + return; + } + /* Store load address of .dllview section */ + hndl->dm.dbthis = dllview_info.load_addr; + /* Store memory context (segid) in which .dllview section + * was allocated */ + hndl->dm.context = dllview_info.context; + mlist->refcount += 1; + /* swap bytes in the entire debug record, but not the string table */ + if (TARGET_ENDIANNESS_DIFFERS(TARGET_BIG_ENDIAN)) { + swap_words(dbmod, (char *)dbsec - (char *)dbmod, + DLL_MODULE_BITMAP); + } + /* Update the DLLview list on the DSP write new record */ + if (!dlthis->myio->writemem(dlthis->myio, dbmod, + dllview_info.load_addr, &dllview_info, + TADDR_TO_HOST(dllview_info.size))) { + return; + } + /* write new header */ + mhdr.first_module_size = hndl->dm.dbsiz; + mhdr.first_module = TADDR_TO_TDATA(dllview_info.load_addr); + /* swap bytes in the module header, if needed */ + if (TARGET_ENDIANNESS_DIFFERS(TARGET_BIG_ENDIAN)) { + swap_words(&mhdr, sizeof(struct modules_header) - sizeof(u16), + MODULES_HEADER_BITMAP); + } + dllview_info = DLLVIEW_INFO_INIT; + if (!dlthis->myio->writemem(dlthis->myio, &mhdr, mlist->dbthis, + &dllview_info, sizeof(struct modules_header) - + sizeof(u16))) { + return; + } + /* Add the module handle to this processor's list + of handles with debug info */ + hndl->dm.hnext = mlist->hnext; + if (hndl->dm.hnext) + hndl->dm.hnext->dm.hprev = hndl; + hndl->dm.hprev = (struct my_handle *) mlist; + mlist->hnext = hndl; /* insert after root*/ +} /* init_module_handle */ + +/************************************************************************* + * Procedure Dynamic_Unload_Module + * + * Parameters: + * mhandle A module handle from Dynamic_Load_Module + * syms Host-side symbol table and malloc/free functions + * alloc Target-side memory allocation + * + * Effect: + * The module specified by mhandle is unloaded. Unloading causes all + * target memory to be deallocated, all symbols defined by the module to + * be purged, and any host-side storage used by the dynamic loader for + * this module to be released. + * + * Returns: + * Zero for success. On error, the number of errors detected is returned. + * Individual errors are reported using syms->Error_Report(). + ************************************************************************/ +int Dynamic_Unload_Module(DLOAD_mhandle mhandle, + struct Dynamic_Loader_Sym *syms, + struct Dynamic_Loader_Allocate *alloc, + struct Dynamic_Loader_Initialize *init) +{ + s16 curr_sect; + struct LDR_SECTION_INFO *asecs; + struct my_handle *hndl; + struct dbg_mirror_root *root; + unsigned errcount = 0; + struct LDR_SECTION_INFO dllview_info = DLLVIEW_INFO_INIT; + struct modules_header mhdr; + + hndl = (struct my_handle *)mhandle; + if (!hndl) + return 0; /* if handle is null, nothing to do */ + /* Clear out the module symbols + * Note that if this is the module that defined MODULES_HEADER + (the head of the target debug list) + * then this operation will blow away that symbol. + It will therefore be impossible for subsequent + * operations to add entries to this un-referenceable list.*/ + if (!syms) + return 1; + syms->Purge_Symbol_Table(syms, (unsigned) hndl); + /* Deallocate target memory for sections */ + asecs = hndl->secns; + if (alloc) + for (curr_sect = (hndl->secn_count >> 1); curr_sect > 0; + curr_sect -= 1) { + asecs->name = NULL; + alloc->Deallocate(alloc, asecs++); + } + root = hndl->dm.hroot; + if (!root) { + /* there is a debug list containing this module */ + goto func_end; + } + if (!hndl->dm.dbthis) { /* target-side dllview record exists */ + goto loop_end; + } + /* Retrieve memory context in which .dllview was allocated */ + dllview_info.context = hndl->dm.context; + if (hndl->dm.hprev == hndl) + goto exitunltgt; + + /* target-side dllview record is in list */ + /* dequeue this record from our GPP-side mirror list */ + hndl->dm.hprev->dm.hnext = hndl->dm.hnext; + if (hndl->dm.hnext) + hndl->dm.hnext->dm.hprev = hndl->dm.hprev; + /* Update next_module of previous entry in target list + * We are using mhdr here as a surrogate for either a + struct modules_header or a dll_module */ + if (hndl->dm.hnext) { + mhdr.first_module = TADDR_TO_TDATA(hndl->dm.hnext->dm.dbthis); + mhdr.first_module_size = hndl->dm.hnext->dm.dbsiz; + } else { + mhdr.first_module = 0; + mhdr.first_module_size = 0; + } + if (!init) + goto exitunltgt; + + if (!init->connect(init)) { + dload_syms_error(syms, E_ICONNECT); + errcount += 1; + goto exitunltgt; + } + /* swap bytes in the module header, if needed */ + if (TARGET_ENDIANNESS_DIFFERS(hndl->secn_count & 0x1)) { + swap_words(&mhdr, sizeof(struct modules_header) - sizeof(u16), + MODULES_HEADER_BITMAP); + } + if (!init->writemem(init, &mhdr, hndl->dm.hprev->dm.dbthis, + &dllview_info, sizeof(struct modules_header) - + sizeof(mhdr.update_flag))) { + dload_syms_error(syms, E_DLVWRITE); + errcount += 1; + } + /* update change counter */ + root->changes += 1; + if (!init->writemem(init, &(root->changes), + root->dbthis + HOST_TO_TADDR + (sizeof(mhdr.first_module) + + sizeof(mhdr.first_module_size)), + &dllview_info, + sizeof(mhdr.update_flag))) { + dload_syms_error(syms, E_DLVWRITE); + errcount += 1; + } + init->release(init); +exitunltgt: + /* release target storage */ + dllview_info.size = TDATA_TO_TADDR(hndl->dm.dbsiz); + dllview_info.load_addr = hndl->dm.dbthis; + if (alloc) + alloc->Deallocate(alloc, &dllview_info); + root->refcount -= 1; + /* target-side dllview record exists */ +loop_end: +#ifndef DEBUG_HEADER_IN_LOADER + if (root->refcount <= 0) { + /* if all references gone, blow off the header */ + /* our root symbol may be gone due to the Purge above, + but if not, do not destroy the root */ + if (syms->Find_Matching_Symbol + (syms, LOADER_DLLVIEW_ROOT) == NULL) + syms->Deallocate(syms, root); + } +#endif +func_end: + /* there is a debug list containing this module */ + syms->Deallocate(syms, mhandle); /* release our storage */ + return errcount; +} /* Dynamic_Unload_Module */ + +#if BITS_PER_AU > BITS_PER_BYTE +/************************************************************************* + * Procedure unpack_name + * + * Parameters: + * soffset Byte offset into the string table + * + * Effect: + * Returns a pointer to the string specified by the offset supplied, or + * NULL for error. + * + ************************************************************************/ +static char *unpack_name(struct dload_state *dlthis, u32 soffset) +{ + u8 tmp, *src; + char *dst; + + if (soffset >= dlthis->dfile_hdr.df_strtab_size) { + dload_error(dlthis, "Bad string table offset " FMT_UI32, + soffset); + return NULL; + } + src = (uint_least8_t *)dlthis->str_head + + (soffset >> (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE)); + dst = dlthis->str_temp; + if (soffset & 1) + *dst++ = *src++; /* only 1 character in first word */ + do { + tmp = *src++; + *dst = (tmp >> BITS_PER_BYTE); + if (!(*dst++)) + break; + } while ((*dst++ = tmp & BYTE_MASK)); + dlthis->temp_len = dst - dlthis->str_temp; + /* squirrel away length including terminating null */ + return dlthis->str_temp; +} /* unpack_name */ +#endif diff --git a/drivers/dsp/bridge/dynload/dlclasses_hdr.h b/drivers/dsp/bridge/dynload/dlclasses_hdr.h new file mode 100644 index 0000000..04f136e --- /dev/null +++ b/drivers/dsp/bridge/dynload/dlclasses_hdr.h @@ -0,0 +1,41 @@ +/* + * dlclasses_hdr.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + + +#ifndef _DLCLASSES_HDR_H +#define _DLCLASSES_HDR_H + +/***************************************************************************** + ***************************************************************************** + * + * DLCLASSES_HDR.H + * + * Sample classes in support of the dynamic loader + * + * These are just concrete derivations of the virtual ones in dynamic_loader.h + * with a few additional interfaces for init, etc. + ***************************************************************************** + *****************************************************************************/ + +#include + +#include "DLstream.h" +#include "DLsymtab.h" +#include "DLalloc.h" +#include "DLinit.h" + +#endif /* _DLCLASSES_HDR_H */ diff --git a/drivers/dsp/bridge/dynload/dload_internal.h b/drivers/dsp/bridge/dynload/dload_internal.h new file mode 100644 index 0000000..78f5058 --- /dev/null +++ b/drivers/dsp/bridge/dynload/dload_internal.h @@ -0,0 +1,237 @@ +/* + * dload_internal.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + + +#ifndef __DLOAD_INTERNAL__ +#define __DLOAD_INTERNAL__ + +#include + +/* + * Internal state definitions for the dynamic loader + */ + +#define TRUE 1 +#define FALSE 0 +typedef int boolean; + + +/* type used for relocation intermediate results */ +typedef s32 RVALUE; + +/* unsigned version of same; must have at least as many bits */ +typedef u32 URVALUE; + +/* + * Dynamic loader configuration constants + */ +/* error issued if input has more sections than this limit */ +#define REASONABLE_SECTION_LIMIT 100 + +/* (Addressable unit) value used to clear BSS section */ +#define dload_fill_bss 0 + +/* + * Reorder maps explained (?) + * + * The doff file format defines a 32-bit pattern used to determine the + * byte order of an image being read. That value is + * BYTE_RESHUFFLE_VALUE == 0x00010203 + * For purposes of the reorder routine, we would rather have the all-is-OK + * for 32-bits pattern be 0x03020100. This first macro makes the + * translation from doff file header value to MAP value: */ +#define REORDER_MAP(rawmap) ((rawmap) ^ 0x3030303) +/* This translation is made in dload_headers. Thereafter, the all-is-OK + * value for the maps stored in dlthis is REORDER_MAP(BYTE_RESHUFFLE_VALUE). + * But sadly, not all bits of the doff file are 32-bit integers. + * The notable exceptions are strings and image bits. + * Strings obey host byte order: */ +#if defined(_BIG_ENDIAN) +#define HOST_BYTE_ORDER(cookedmap) ((cookedmap) ^ 0x3030303) +#else +#define HOST_BYTE_ORDER(cookedmap) (cookedmap) +#endif +/* Target bits consist of target AUs (could be bytes, or 16-bits, + * or 32-bits) stored as an array in host order. A target order + * map is defined by: */ +#if !defined(_BIG_ENDIAN) || TARGET_AU_BITS > 16 +#define TARGET_ORDER(cookedmap) (cookedmap) +#elif TARGET_AU_BITS > 8 +#define TARGET_ORDER(cookedmap) ((cookedmap) ^ 0x2020202) +#else +#define TARGET_ORDER(cookedmap) ((cookedmap) ^ 0x3030303) +#endif + +/* forward declaration for handle returned by dynamic loader */ +struct my_handle; + +/* + * a list of module handles, which mirrors the debug list on the target + */ +struct dbg_mirror_root { + /* must be same as dbg_mirror_list; __DLModules address on target */ + u32 dbthis; + struct my_handle *hnext; /* must be same as dbg_mirror_list */ + u16 changes; /* change counter */ + u16 refcount; /* number of modules referencing this root */ +} ; + +struct dbg_mirror_list { + u32 dbthis; + struct my_handle *hnext, *hprev; + struct dbg_mirror_root *hroot; + u16 dbsiz; + u32 context; /* Save context for .dllview memory allocation */ +} ; + +#define VARIABLE_SIZE 1 +/* + * the structure we actually return as an opaque module handle + */ +struct my_handle { + struct dbg_mirror_list dm; /* !!! must be first !!! */ + /* sections following << 1, LSB is set for big-endian target */ + u16 secn_count; + struct LDR_SECTION_INFO secns[VARIABLE_SIZE]; +} ; +#define MY_HANDLE_SIZE (sizeof(struct my_handle) -\ + sizeof(struct LDR_SECTION_INFO)) +/* real size of my_handle */ + +/* + * reduced symbol structure used for symbols during relocation + */ +struct Local_Symbol { + s32 value; /* Relocated symbol value */ + s32 delta; /* Original value in input file */ + s16 secnn; /* section number */ + s16 sclass; /* symbol class */ +} ; + +/* + * States of the .cinit state machine + */ +enum cinit_mode { + CI_count = 0, /* expecting a count */ + CI_address, /* expecting an address */ +#if CINIT_ALIGN < CINIT_ADDRESS /* handle case of partial address field */ + CI_partaddress, /* have only part of the address */ +#endif + CI_copy, /* in the middle of copying data */ + CI_done /* end of .cinit table */ +}; + +/* + * The internal state of the dynamic loader, which is passed around as + * an object + */ +struct dload_state { + struct Dynamic_Loader_Stream *strm; /* The module input stream */ + struct Dynamic_Loader_Sym *mysym; /* Symbols for this session */ + struct Dynamic_Loader_Allocate *myalloc; /* target memory allocator */ + struct Dynamic_Loader_Initialize *myio; /* target memory initializer */ + unsigned myoptions; /* Options parameter Dynamic_Load_Module */ + + char *str_head; /* Pointer to string table */ +#if BITS_PER_AU > BITS_PER_BYTE + char *str_temp; /* Pointer to temporary buffer for strings */ + /* big enough to hold longest string */ + unsigned temp_len; /* length of last temporary string */ + char *xstrings; /* Pointer to buffer for expanded */ + /* strings for sec names */ +#endif + /* Total size of strings for DLLView section names */ + unsigned debug_string_size; + /* Pointer to parallel section info for allocated sections only */ + struct doff_scnhdr_t *sect_hdrs; /* Pointer to section table */ + struct LDR_SECTION_INFO *ldr_sections; +#if TMS32060 + /* The address of the start of the .bss section */ + LDR_ADDR bss_run_base; +#endif + struct Local_Symbol *local_symtab; /* Relocation symbol table */ + + /* pointer to DL section info for the section being relocated */ + struct LDR_SECTION_INFO *image_secn; + /* change in run address for current section during relocation */ + LDR_ADDR delta_runaddr; + LDR_ADDR image_offset; /* offset of current packet in section */ + enum cinit_mode cinit_state; /* current state of cload_cinit() */ + int cinit_count; /* the current count */ + LDR_ADDR cinit_addr; /* the current address */ + s16 cinit_page; /* the current page */ + /* Handle to be returned by Dynamic_Load_Module */ + struct my_handle *myhandle; + unsigned dload_errcount; /* Total # of errors reported so far */ + /* Number of target sections that require allocation and relocation */ + unsigned allocated_secn_count; +#ifndef TARGET_ENDIANNESS + boolean big_e_target; /* Target data in big-endian format */ +#endif + /* map for reordering bytes, 0 if not needed */ + u32 reorder_map; + struct doff_filehdr_t dfile_hdr; /* DOFF file header structure */ + struct doff_verify_rec_t verify; /* Verify record */ + + int relstkidx; /* index into relocation value stack */ + /* relocation value stack used in relexp.c */ + RVALUE relstk[STATIC_EXPR_STK_SIZE]; + +} ; + +#ifdef TARGET_ENDIANNESS +#define TARGET_BIG_ENDIAN TARGET_ENDIANNESS +#else +#define TARGET_BIG_ENDIAN (dlthis->big_e_target) +#endif + +/* + * Exports from cload.c to rest of the world + */ +extern void dload_error(struct dload_state *dlthis, const char *errtxt, ...); +extern void dload_syms_error(struct Dynamic_Loader_Sym *syms, + const char *errtxt, ...); +extern void dload_headers(struct dload_state *dlthis); +extern void dload_strings(struct dload_state *dlthis, boolean sec_names_only); +extern void dload_sections(struct dload_state *dlthis); +extern void dload_reorder(void *data, int dsiz, u32 map); +extern u32 dload_checksum(void *data, unsigned siz); + +#if HOST_ENDIANNESS +extern uint32_t dload_reverse_checksum(void *data, unsigned siz); +#if (TARGET_AU_BITS > 8) && (TARGET_AU_BITS < 32) +extern uint32_t dload_reverse_checksum_16(void *data, unsigned siz); +#endif +#endif + +#define is_data_scn(zzz) (DLOAD_SECTION_TYPE((zzz)->type) != DLOAD_TEXT) +#define is_data_scn_num(zzz) \ + (DLOAD_SECT_TYPE(&dlthis->sect_hdrs[(zzz)-1]) != DLOAD_TEXT) + +/* + * exported by reloc.c + */ +extern void dload_relocate(struct dload_state *dlthis, TgtAU_t *data, + struct reloc_record_t *rp); + +extern RVALUE dload_unpack(struct dload_state *dlthis, TgtAU_t *data, + int fieldsz, int offset, unsigned sgn); + +extern int dload_repack(struct dload_state *dlthis, RVALUE val, TgtAU_t *data, + int fieldsz, int offset, unsigned sgn); + +#endif /* __DLOAD_INTERNAL__ */ diff --git a/drivers/dsp/bridge/dynload/doff.h b/drivers/dsp/bridge/dynload/doff.h new file mode 100644 index 0000000..2b8fc37 --- /dev/null +++ b/drivers/dsp/bridge/dynload/doff.h @@ -0,0 +1,347 @@ +/* + * doff.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/*****************************************************************************/ +/* DOFF.H - Structures & definitions used for dynamically */ +/* loaded modules file format. This format is a reformatted */ +/* version of COFF.(see coff.h for details) It optimizes the */ +/* layout for the dynamic loader. */ +/* */ +/* .dof files, when viewed as a sequence of 32-bit integers, look the same */ +/* on big-endian and little-endian machines. */ +/*****************************************************************************/ +#ifndef _DOFF_H +#define _DOFF_H + +#ifndef UINT32_C +#define UINT32_C(zzz) ((u32)zzz) +#endif + +#define BYTE_RESHUFFLE_VALUE UINT32_C(0x00010203) + +/* DOFF file header containing fields categorizing the remainder of the file */ +struct doff_filehdr_t { + + /* string table size, including filename, in bytes */ + u32 df_strtab_size; + + /* entry point if one exists */ + u32 df_entrypt; + + /* identifies byte ordering of file; + * always set to BYTE_RESHUFFLE_VALUE */ + u32 df_byte_reshuffle; + + /* Size of the string table up to and including the last section name */ + /* Size includes the name of the COFF file also */ + u32 df_scn_name_size; + +#ifndef _BIG_ENDIAN + /* number of symbols */ + u16 df_no_syms; + + /* length in bytes of the longest string, including terminating NULL */ + /* excludes the name of the file */ + u16 df_max_str_len; + + /* total number of sections including no-load ones */ + u16 df_no_scns; + + /* number of sections containing target code allocated or downloaded */ + u16 df_target_scns; + + /* unique id for dll file format & version */ + u16 df_doff_version; + + /* identifies ISA */ + u16 df_target_id; + + /* useful file flags */ + u16 df_flags; + + /* section reference for entry point, N_UNDEF for none, */ + /* N_ABS for absolute address */ + s16 df_entry_secn; +#else + /* length of the longest string, including terminating NULL */ + u16 df_max_str_len; + + /* number of symbols */ + u16 df_no_syms; + + /* number of sections containing target code allocated or downloaded */ + u16 df_target_scns; + + /* total number of sections including no-load ones */ + u16 df_no_scns; + + /* identifies ISA */ + u16 df_target_id; + + /* unique id for dll file format & version */ + u16 df_doff_version; + + /* section reference for entry point, N_UNDEF for none, */ + /* N_ABS for absolute address */ + s16 df_entry_secn; + + /* useful file flags */ + u16 df_flags; +#endif + /* checksum for file header record */ + u32 df_checksum; + +} ; + +/* flags in the df_flags field */ +#define DF_LITTLE 0x100 +#define DF_BIG 0x200 +#define DF_BYTE_ORDER (DF_LITTLE | DF_BIG) + +/* Supported processors */ +#define TMS470_ID 0x97 +#define LEAD_ID 0x98 +#define TMS32060_ID 0x99 +#define LEAD3_ID 0x9c + +/* Primary processor for loading */ +#if TMS32060 +#define TARGET_ID TMS32060_ID +#endif + +/* Verification record containing values used to test integrity of the bits */ +struct doff_verify_rec_t { + + /* time and date stamp */ + u32 dv_timdat; + + /* checksum for all section records */ + u32 dv_scn_rec_checksum; + + /* checksum for string table */ + u32 dv_str_tab_checksum; + + /* checksum for symbol table */ + u32 dv_sym_tab_checksum; + + /* checksum for verification record */ + u32 dv_verify_rec_checksum; + +} ; + +/* String table is an array of null-terminated strings. The first entry is + * the filename, which is added by DLLcreate. No new structure definitions + * are required. + */ + +/* Section Records including information on the corresponding image packets */ +/* + * !!WARNING!! + * + * This structure is expected to match in form LDR_SECTION_INFO in + * dynamic_loader.h + */ + +struct doff_scnhdr_t { + + s32 ds_offset; /* offset into string table of name */ + s32 ds_paddr; /* RUN address, in target AU */ + s32 ds_vaddr; /* LOAD address, in target AU */ + s32 ds_size; /* section size, in target AU */ +#ifndef _BIG_ENDIAN + u16 ds_page; /* memory page id */ + u16 ds_flags; /* section flags */ +#else + u16 ds_flags; /* section flags */ + u16 ds_page; /* memory page id */ +#endif + u32 ds_first_pkt_offset; + /* Absolute byte offset into the file */ + /* where the first image record resides */ + + s32 ds_nipacks; /* number of image packets */ + +}; + +/* Symbol table entry */ +struct doff_syment_t { + + s32 dn_offset; /* offset into string table of name */ + s32 dn_value; /* value of symbol */ +#ifndef _BIG_ENDIAN + s16 dn_scnum; /* section number */ + s16 dn_sclass; /* storage class */ +#else + s16 dn_sclass; /* storage class */ + s16 dn_scnum; /* section number, 1-based */ +#endif + +} ; + +/* special values for dn_scnum */ +#define DN_UNDEF 0 /* undefined symbol */ +#define DN_ABS (-1) /* value of symbol is absolute */ +/* special values for dn_sclass */ +#define DN_EXT 2 +#define DN_STATLAB 20 +#define DN_EXTLAB 21 + +/* Default value of image bits in packet */ +/* Configurable by user on the command line */ +#define IMAGE_PACKET_SIZE 1024 + +/* An image packet contains a chunk of data from a section along with */ +/* information necessary for its processing. */ +struct image_packet_t { + + s32 i_num_relocs; /* number of relocations for */ + /* this packet */ + + s32 i_packet_size; /* number of bytes in array */ + /* "bits" occupied by */ + /* valid data. Could be */ + /* < IMAGE_PACKET_SIZE to */ + /* prevent splitting a */ + /* relocation across packets. */ + /* Last packet of a section */ + /* will most likely contain */ + /* < IMAGE_PACKET_SIZE bytes */ + /* of valid data */ + + s32 i_checksum; /* Checksum for image packet */ + /* and the corresponding */ + /* relocation records */ + + u8 *i_bits; /* Actual data in section */ + +}; + +/* The relocation structure definition matches the COFF version. Offsets */ +/* however are relative to the image packet base not the section base. */ +struct reloc_record_t { + + s32 r_vaddr; + + /* expressed in target AUs */ + + union { + struct { +#ifndef _BIG_ENDIAN + u8 _offset; /* bit offset of rel fld */ + u8 _fieldsz; /* size of rel fld */ + u8 _wordsz; /* # bytes containing rel fld */ + u8 _dum1; + u16 _dum2; + u16 _type; +#else + unsigned _dum1:8; + unsigned _wordsz:8; /* # bytes containing rel fld */ + unsigned _fieldsz:8; /* size of rel fld */ + unsigned _offset:8; /* bit offset of rel fld */ + u16 _type; + u16 _dum2; +#endif + } _r_field; + + struct { + u32 _spc; /* image packet relative PC */ +#ifndef _BIG_ENDIAN + u16 _dum; + u16 _type; /* relocation type */ +#else + u16 _type; /* relocation type */ + u16 _dum; +#endif + } _r_spc; + + struct { + u32 _uval; /* constant value */ +#ifndef _BIG_ENDIAN + u16 _dum; + u16 _type; /* relocation type */ +#else + u16 _type; /* relocation type */ + u16 _dum; +#endif + } _r_uval; + + struct { + s32 _symndx; /* 32-bit sym tbl index */ +#ifndef _BIG_ENDIAN + u16 _disp; /* extra addr encode data */ + u16 _type; /* relocation type */ +#else + u16 _type; /* relocation type */ + u16 _disp; /* extra addr encode data */ +#endif + } _r_sym; + } _u_reloc; + +} ; + +/* abbreviations for convenience */ +#ifndef r_type +#define r_type _u_reloc._r_sym._type +#define r_uval _u_reloc._r_uval._uval +#define r_symndx _u_reloc._r_sym._symndx +#define r_offset _u_reloc._r_field._offset +#define r_fieldsz _u_reloc._r_field._fieldsz +#define r_wordsz _u_reloc._r_field._wordsz +#define r_disp _u_reloc._r_sym._disp +#endif + +/*****************************************************************************/ +/* */ +/* Important DOFF macros used for file processing */ +/* */ +/*****************************************************************************/ + +/* DOFF Versions */ +#define DOFF0 0 + +/* Return the address/size >= to addr that is at a 32-bit boundary */ +/* This assumes that a byte is 8 bits */ +#define DOFF_ALIGN(addr) (((addr) + 3) & ~UINT32_C(3)) + +/*****************************************************************************/ +/* */ +/* The DOFF section header flags field is laid out as follows: */ +/* */ +/* Bits 0-3 : Section Type */ +/* Bit 4 : Set when section requires target memory to be allocated by DL */ +/* Bit 5 : Set when section requires downloading */ +/* Bits 8-11: Alignment, same as COFF */ +/* */ +/*****************************************************************************/ + +/* Enum for DOFF section types (bits 0-3 of flag): See dynamic_loader.h */ + +/* Macros to help processing of sections */ +#define DLOAD_SECT_TYPE(s_hdr) ((s_hdr)->ds_flags & 0xF) + +/* DS_ALLOCATE indicates whether a section needs space on the target */ +#define DS_ALLOCATE_MASK 0x10 +#define DS_NEEDS_ALLOCATION(s_hdr) ((s_hdr)->ds_flags & DS_ALLOCATE_MASK) + +/* DS_DOWNLOAD indicates that the loader needs to copy bits */ +#define DS_DOWNLOAD_MASK 0x20 +#define DS_NEEDS_DOWNLOAD(s_hdr) ((s_hdr)->ds_flags & DS_DOWNLOAD_MASK) + +/* Section alignment requirement in AUs */ +#define DS_ALIGNMENT(ds_flags) (1 << (((ds_flags) >> 8) & 0xF)) + +#endif /* _DOFF_H */ diff --git a/drivers/dsp/bridge/dynload/getsection.c b/drivers/dsp/bridge/dynload/getsection.c new file mode 100644 index 0000000..78a301a --- /dev/null +++ b/drivers/dsp/bridge/dynload/getsection.c @@ -0,0 +1,412 @@ +/* + * getsection.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + + +#include +#include "header.h" + +/* + * Error strings + */ +static const char E_READSTRM[] = { "Error reading %s from input stream" }; +static const char E_SEEK[] = { "Set file position to %d failed" }; +static const char E_ISIZ[] = { "Bad image packet size %d" }; +static const char E_CHECKSUM[] = { "Checksum failed on %s" }; +static const char E_RELOC[] = { "DLOAD_GetSection unable to read" + "sections containing relocation entries"}; +#if BITS_PER_AU > BITS_PER_BYTE +static const char E_ALLOC[] = { "Syms->Allocate( %d ) failed" }; +static const char E_STBL[] = { "Bad string table offset " FMT_UI32 }; +#endif + +/* + * we use the fact that DOFF section records are shaped just like + * LDR_SECTION_INFO to reduce our section storage usage. These macros + * marks the places where that assumption is made + */ +#define DOFFSEC_IS_LDRSEC(pdoffsec) ((struct LDR_SECTION_INFO *)(pdoffsec)) +#define LDRSEC_IS_DOFFSEC(ldrsec) ((struct doff_scnhdr_t *)(ldrsec)) + +/***************************************************************/ +/********************* SUPPORT FUNCTIONS ***********************/ +/***************************************************************/ + +#if BITS_PER_AU > BITS_PER_BYTE +/************************************************************************** + * Procedure unpack_sec_name + * + * Parameters: + * dlthis Handle from DLOAD_module_open for this module + * soffset Byte offset into the string table + * dst Place to store the expanded string + * + * Effect: + * Stores a string from the string table into the destination, expanding + * it in the process. Returns a pointer just past the end of the stored + * string on success, or NULL on failure. + * + *************************************************************************/ +static char *unpack_sec_name(struct dload_state *dlthis, + u32 soffset, char *dst) +{ + u8 tmp, *src; + + if (soffset >= dlthis->dfile_hdr.df_scn_name_size) { + dload_error(dlthis, E_STBL, soffset); + return NULL; + } + src = (u8 *)dlthis->str_head + + (soffset >> (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE)); + if (soffset & 1) + *dst++ = *src++; /* only 1 character in first word */ + do { + tmp = *src++; + *dst = (tmp >> BITS_PER_BYTE) + if (!(*dst++)) + break; + } while ((*dst++ = tmp & BYTE_MASK)); + + return dst; +} + +/************************************************************************** + * Procedure expand_sec_names + * + * Parameters: + * dlthis Handle from DLOAD_module_open for this module + * + * Effect: + * Allocates a buffer, unpacks and copies strings from string table into it. + * Stores a pointer to the buffer into a state variable. + **************************************************************************/ +static void expand_sec_names(struct dload_state *dlthis) +{ + char *xstrings, *curr, *next; + u32 xsize; + u16 sec; + struct LDR_SECTION_INFO *shp; + /* assume worst-case size requirement */ + xsize = dlthis->dfile_hdr.df_max_str_len * dlthis->dfile_hdr.df_no_scns; + xstrings = (char *)dlthis->mysym->Allocate(dlthis->mysym, xsize); + if (xstrings == NULL) { + dload_error(dlthis, E_ALLOC, xsize); + return; + } + dlthis->xstrings = xstrings; + /* For each sec, copy and expand its name */ + curr = xstrings; + for (sec = 0; sec < dlthis->dfile_hdr.df_no_scns; sec++) { + shp = DOFFSEC_IS_LDRSEC(&dlthis->sect_hdrs[sec]); + next = unpack_sec_name(dlthis, *(u32 *) &shp->name, curr); + if (next == NULL) + break; /* error */ + shp->name = curr; + curr = next; + } +} + +#endif + +/***************************************************************/ +/********************* EXPORTED FUNCTIONS **********************/ +/***************************************************************/ + +/************************************************************************** + * Procedure DLOAD_module_open + * + * Parameters: + * module The input stream that supplies the module image + * syms Host-side malloc/free and error reporting functions. + * Other methods are unused. + * + * Effect: + * Reads header information from a dynamic loader module using the + specified + * stream object, and returns a handle for the module information. This + * handle may be used in subsequent query calls to obtain information + * contained in the module. + * + * Returns: + * NULL if an error is encountered, otherwise a module handle for use + * in subsequent operations. + **************************************************************************/ +DLOAD_module_info DLOAD_module_open(struct Dynamic_Loader_Stream *module, + struct Dynamic_Loader_Sym *syms) +{ + struct dload_state *dlthis; /* internal state for this call */ + unsigned *dp, sz; + u32 sec_start; +#if BITS_PER_AU <= BITS_PER_BYTE + u16 sec; +#endif + + /* Check that mandatory arguments are present */ + if (!module || !syms) { + if (syms != NULL) + dload_syms_error(syms, "Required parameter is NULL"); + + return NULL; + } + + dlthis = (struct dload_state *) + syms->Allocate(syms, sizeof(struct dload_state)); + if (!dlthis) { + /* not enough storage */ + dload_syms_error(syms, "Can't allocate module info"); + return NULL; + } + + /* clear our internal state */ + dp = (unsigned *)dlthis; + for (sz = sizeof(struct dload_state) / sizeof(unsigned); + sz > 0; sz -= 1) + *dp++ = 0; + + dlthis->strm = module; + dlthis->mysym = syms; + + /* read in the doff image and store in our state variable */ + dload_headers(dlthis); + + if (!dlthis->dload_errcount) + dload_strings(dlthis, true); + + /* skip ahead past the unread portion of the string table */ + sec_start = sizeof(struct doff_filehdr_t) + + sizeof(struct doff_verify_rec_t) + + BYTE_TO_HOST(DOFF_ALIGN(dlthis->dfile_hdr.df_strtab_size)); + + if (dlthis->strm->set_file_posn(dlthis->strm, sec_start) != 0) { + dload_error(dlthis, E_SEEK, sec_start); + return NULL; + } + + if (!dlthis->dload_errcount) + dload_sections(dlthis); + + if (dlthis->dload_errcount) { + DLOAD_module_close(dlthis); /* errors, blow off our state */ + dlthis = NULL; + return NULL; + } +#if BITS_PER_AU > BITS_PER_BYTE + /* Expand all section names from the string table into the */ + /* state variable, and convert section names from a relative */ + /* string table offset to a pointers to the expanded string. */ + expand_sec_names(dlthis); +#else + /* Convert section names from a relative string table offset */ + /* to a pointer into the string table. */ + for (sec = 0; sec < dlthis->dfile_hdr.df_no_scns; sec++) { + struct LDR_SECTION_INFO *shp = + DOFFSEC_IS_LDRSEC(&dlthis->sect_hdrs[sec]); + shp->name = dlthis->str_head + *(u32 *)&shp->name; + } +#endif + + return dlthis; +} + +/*************************************************************************** + * Procedure DLOAD_GetSectionInfo + * + * Parameters: + * minfo Handle from DLOAD_module_open for this module + * sectionName Pointer to the string name of the section desired + * sectionInfo Address of a section info structure pointer to be + * initialized + * + * Effect: + * Finds the specified section in the module information, and initializes + * the provided struct LDR_SECTION_INFO pointer. + * + * Returns: + * true for success, false for section not found + **************************************************************************/ +int DLOAD_GetSectionInfo(DLOAD_module_info minfo, const char *sectionName, + const struct LDR_SECTION_INFO **const sectionInfo) +{ + struct dload_state *dlthis; + struct LDR_SECTION_INFO *shp; + u16 sec; + + dlthis = (struct dload_state *)minfo; + if (!dlthis) + return false; + + for (sec = 0; sec < dlthis->dfile_hdr.df_no_scns; sec++) { + shp = DOFFSEC_IS_LDRSEC(&dlthis->sect_hdrs[sec]); + if (strcmp(sectionName, shp->name) == 0) { + *sectionInfo = shp; + return true; + } + } + + return false; +} + +#define IPH_SIZE (sizeof(struct image_packet_t) - sizeof(u32)) +#define REVERSE_REORDER_MAP(rawmap) ((rawmap) ^ 0x3030303) + +/************************************************************************** + * Procedure DLOAD_GetSection + * + * Parameters: + * minfo Handle from DLOAD_module_open for this module + * sectionInfo Pointer to a section info structure for the desired + * section + * sectionData Buffer to contain the section initialized data + * + * Effect: + * Copies the initialized data for the specified section into the + * supplied buffer. + * + * Returns: + * true for success, false for section not found + **************************************************************************/ +int DLOAD_GetSection(DLOAD_module_info minfo, + const struct LDR_SECTION_INFO *sectionInfo, void *sectionData) +{ + struct dload_state *dlthis; + u32 pos; + struct doff_scnhdr_t *sptr = NULL; + s32 nip; + struct image_packet_t ipacket; + s32 ipsize; + u32 checks; + s8 *dest = (s8 *)sectionData; + + dlthis = (struct dload_state *)minfo; + if (!dlthis) + return false; + sptr = LDRSEC_IS_DOFFSEC(sectionInfo); + if (sptr == NULL) + return false; + + /* skip ahead to the start of the first packet */ + pos = BYTE_TO_HOST(DOFF_ALIGN((u32) sptr->ds_first_pkt_offset)); + if (dlthis->strm->set_file_posn(dlthis->strm, pos) != 0) { + dload_error(dlthis, E_SEEK, pos); + return false; + } + + nip = sptr->ds_nipacks; + while ((nip -= 1) >= 0) { /* for each packet */ + /* get the fixed header bits */ + if (dlthis->strm-> + read_buffer(dlthis->strm, &ipacket, IPH_SIZE) != IPH_SIZE) { + dload_error(dlthis, E_READSTRM, "image packet"); + return false; + } + /* reorder the header if need be */ + if (dlthis->reorder_map) + dload_reorder(&ipacket, IPH_SIZE, dlthis->reorder_map); + + /* Now read the packet image bits. Note: round the size up to + * the next multiple of 4 bytes; this is what checksum + * routines want. */ + ipsize = BYTE_TO_HOST(DOFF_ALIGN(ipacket.i_packet_size)); + if (ipsize > BYTE_TO_HOST(IMAGE_PACKET_SIZE)) { + dload_error(dlthis, E_ISIZ, ipsize); + return false; + } + if (dlthis->strm->read_buffer + (dlthis->strm, dest, ipsize) != ipsize) { + dload_error(dlthis, E_READSTRM, "image packet"); + return false; + } + /* reorder the bytes if need be */ +#if !defined(_BIG_ENDIAN) || (TARGET_AU_BITS > 16) + if (dlthis->reorder_map) + dload_reorder(dest, ipsize, dlthis->reorder_map); + + checks = dload_checksum(dest, ipsize); +#else + if (dlthis->dfile_hdr.df_byte_reshuffle != + TARGET_ORDER(REORDER_MAP(BYTE_RESHUFFLE_VALUE))) { + /* put image bytes in big-endian order, not PC order */ + dload_reorder(dest, ipsize, + TARGET_ORDER(dlthis->dfile_hdr. + df_byte_reshuffle)); + } +#if TARGET_AU_BITS > 8 + checks = dload_reverse_checksum_16(dest, ipsize); +#else + checks = dload_reverse_checksum(dest, ipsize); +#endif +#endif + checks += dload_checksum(&ipacket, IPH_SIZE); + + /* NYI: unable to handle relocation entries here. Reloc + * entries referring to fields that span the packet boundaries + * may result in packets of sizes that are not multiple of + * 4 bytes. Our checksum implementation works on 32-bit words + * only. */ + if (ipacket.i_num_relocs != 0) { + dload_error(dlthis, E_RELOC, ipsize); + return false; + } + + if (~checks) { + dload_error(dlthis, E_CHECKSUM, "image packet"); + return false; + } + + /*Advance destination ptr by the size of the just-read packet*/ + dest += ipsize; + } + + return true; +} + +/*************************************************************************** + * Procedure DLOAD_module_close + * + * Parameters: + * minfo Handle from DLOAD_module_open for this module + * + * Effect: + * Releases any storage associated with the module handle. On return, + * the module handle is invalid. + * + * Returns: + * Zero for success. On error, the number of errors detected is returned. + * Individual errors are reported using syms->Error_Report(), where syms was + * an argument to DLOAD_module_open + **************************************************************************/ +void DLOAD_module_close(DLOAD_module_info minfo) +{ + struct dload_state *dlthis; + + dlthis = (struct dload_state *)minfo; + if (!dlthis) + return; + + if (dlthis->str_head) + dlthis->mysym->Deallocate(dlthis->mysym, dlthis->str_head); + + if (dlthis->sect_hdrs) + dlthis->mysym->Deallocate(dlthis->mysym, dlthis->sect_hdrs); + +#if BITS_PER_AU > BITS_PER_BYTE + if (dlthis->xstrings) + dlthis->mysym->Deallocate(dlthis->mysym, dlthis->xstrings); + +#endif + + dlthis->mysym->Deallocate(dlthis->mysym, dlthis); +} diff --git a/drivers/dsp/bridge/dynload/header.h b/drivers/dsp/bridge/dynload/header.h new file mode 100644 index 0000000..0de744b --- /dev/null +++ b/drivers/dsp/bridge/dynload/header.h @@ -0,0 +1,59 @@ +/* + * header.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + + +#define TRUE 1 +#define FALSE 0 +#ifndef NULL +#define NULL 0 +#endif + +#include +#define DL_STRCMP strcmp + +/* maximum parenthesis nesting in relocation stack expressions */ +#define STATIC_EXPR_STK_SIZE 10 + +#include +typedef unsigned int uint_least32_t; +typedef unsigned short int uint_least16_t; + +#include "doff.h" +#include +#include "params.h" +#include "dload_internal.h" +#include "reloc_table.h" + +/* + * Plausibility limits + * + * These limits are imposed upon the input DOFF file as a check for validity. + * They are hard limits, in that the load will fail if they are exceeded. + * The numbers selected are arbitrary, in that the loader implementation does + * not require these limits. + */ + +/* maximum number of bytes in string table */ +#define MAX_REASONABLE_STRINGTAB (0x100000) +/* maximum number of code,data,etc. sections */ +#define MAX_REASONABLE_SECTIONS (200) +/* maximum number of linker symbols */ +#define MAX_REASONABLE_SYMBOLS (100000) + +/* shift count to align F_BIG with DLOAD_LITTLE */ +#define ALIGN_COFF_ENDIANNESS 7 +#define ENDIANNESS_MASK (DF_BYTE_ORDER >> ALIGN_COFF_ENDIANNESS) diff --git a/drivers/dsp/bridge/dynload/module_list.h b/drivers/dsp/bridge/dynload/module_list.h new file mode 100644 index 0000000..9c4876a --- /dev/null +++ b/drivers/dsp/bridge/dynload/module_list.h @@ -0,0 +1,161 @@ +/* + * dspbridge/mpu_driver/src/dynload/module_list.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/*============================================================================ + Filename: module_list.h + + Copyright (C) 2002 Texas Instruments Incorporated + + + This C header file gives the layout of the data structure created by the + dynamic loader to describe the set of modules loaded into the DSP. + + Linked List Structure: + ---------------------- + The data structure defined here is a singly-linked list. The list + represents the set of modules which are currently loaded in the DSP memory. + The first entry in the list is a header record which contains a flag + representing the state of the list. The rest of the entries in the list + are module records. + + Global symbol _DLModules designates the first record in the list (i.e. the + header record). This symbol must be defined in any program that wishes to + use DLLview plug-in. + + String Representation: + ---------------------- + The string names of the module and its sections are stored in a block of + memory which follows the module record itself. The strings are ordered: + module name first, followed by section names in order from the first + section to the last. String names are tightly packed arrays of 8-bit + characters (two characters per 16-bit word on the C55x). Strings are + zero-byte-terminated. + + Creating and updating the list: +------------------------------- + Upon loading a new module into the DSP memory the dynamic loader inserts a +new module record as the first module record in the list. The fields of + this module record are initialized to reflect the properties of the module. + The dynamic loader does NOT increment the flag/counter in the list's header + record. + + Upon unloading a module from the DSP memory the dynamic loader removes the +module's record from this list. The dynamic loader also increments the + flag/counter in the list's header record to indicate that the list has been + changed. + +============================================================================*/ + +#ifndef _MODULE_LIST_H_ +#define _MODULE_LIST_H_ + +#include + +/* Global pointer to the modules_header structure*/ +#define MODULES_HEADER "_DLModules" +#define MODULES_HEADER_NO_UNDERSCORE "DLModules" + +/* Initial version number*/ +#define INIT_VERSION 1 + +/* Verification number -- to be recorded in each module record */ +#define VERIFICATION 0x79 + +/* forward declarations */ +struct dll_module; +struct dll_sect; + +/* the first entry in the list is the modules_header record; + * its address is contained in the global _DLModules pointer */ +struct modules_header { + + /* Address of the first dll_module record in the list or NULL. + Note: for C55x this is a word address (C55x data is word-addressable)*/ + u32 first_module; + + /* Combined storage size (in target addressable units) of the + * dll_module record which follows this header record, or zero + * if the list is empty. This size includes the module's string table. + * Note: for C55x the unit is a 16-bit word */ + u16 first_module_size; + + /* Counter is incremented whenever a module record is removed from + * the list */ + u16 update_flag; + +} ; + +/* for each 32-bits in above structure, a bitmap, LSB first, whose bits are: + * 0 => a 32-bit value, 1 => 2 16-bit values */ +#define MODULES_HEADER_BITMAP 0x2 /* swapping bitmap for type modules_header */ + +/* information recorded about each section in a module */ +struct dll_sect { + + /* Load-time address of the section. + * Note: for C55x this is a byte address for program sections, and + * a word address for data sections. C55x program memory is + * byte-addressable, while data memory is word-addressable. */ + u32 sect_load_adr; + + /* Run-time address of the section. + * Note 1: for C55x this is a byte address for program sections, and + * a word address for data sections. + * Note 2: for C55x two most significant bits of this field indicate + * the section type: '00' for a code section, '11' for a data section + * (C55 addresses are really only 24-bits wide). */ + u32 sect_run_adr; + +} ; + +/* the rest of the entries in the list are module records */ +struct dll_module { + + /* Address of the next dll_module record in the list, or 0 if this is + * the last record in the list. + * Note: for C55x this is a word address (C55x data is + * word-addressable) */ + u32 next_module; + + /* Combined storage size (in target addressable units) of the + * dll_module record which follows this one, or zero if this is the + * last record in the list. This size includes the module's string + * table. + * Note: for C55x the unit is a 16-bit word. */ + u16 next_module_size; + + /* version number of the tooling; set to INIT_VERSION for Phase 1 */ + u16 version; + + /* the verification word; set to VERIFICATION */ + u16 verification; + + /* Number of sections in the sects array */ + u16 num_sects; + + /* Module's "unique" id; copy of the timestamp from the host + * COFF file */ + u32 timestamp; + + /* Array of num_sects elements of the module's section records */ + struct dll_sect sects[1]; +} ; + +/* for each 32 bits in above structure, a bitmap, LSB first, whose bits are: + * 0 => a 32-bit value, 1 => 2 16-bit values */ +#define DLL_MODULE_BITMAP 0x6 /* swapping bitmap for type dll_module */ + +#endif /* _MODULE_LIST_H_ */ diff --git a/drivers/dsp/bridge/dynload/params.h b/drivers/dsp/bridge/dynload/params.h new file mode 100644 index 0000000..ade430d --- /dev/null +++ b/drivers/dsp/bridge/dynload/params.h @@ -0,0 +1,231 @@ +/* + * params.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + + +/****************************************************************************** + * + * This file defines host and target properties for all machines + * supported by the dynamic loader. To be tedious... + * + * host == the machine on which the dynamic loader runs + * target == the machine that the dynamic loader is loading + * + * Host and target may or may not be the same, depending upon the particular + * use. + *****************************************************************************/ + +/****************************************************************************** + * + * Host Properties + * + *****************************************************************************/ + +#define BITS_PER_BYTE 8 /* bits in the standard PC/SUN byte */ +#define LOG_BITS_PER_BYTE 3 /* log base 2 of same */ +#define BYTE_MASK ((1U<> 16)) +#define SWAP16BY8(zz) (((zz) << 8) | ((zz) >> 8)) + +/* !! don't be tempted to insert type definitions here; use !! */ + +/****************************************************************************** + * + * Target Properties + * + *****************************************************************************/ + + +/*--------------------------------------------------------------------------*/ +/* TMS320C6x Target Specific Parameters (byte-addressable) */ +/*--------------------------------------------------------------------------*/ +#if TMS32060 +#define MEMORG 0x0L /* Size of configured memory */ +#define MEMSIZE 0x0L /* (full address space) */ + +#define CINIT_ALIGN 8 /* alignment of cinit record in TDATA AUs */ +#define CINIT_COUNT 4 /* width of count field in TDATA AUs */ +#define CINIT_ADDRESS 4 /* width of address field in TDATA AUs */ +#define CINIT_PAGE_BITS 0 /* Number of LSBs of address that + * are page number */ + +#define LENIENT_SIGNED_RELEXPS 0 /* DOES SIGNED ALLOW MAX UNSIGNED */ + +#undef TARGET_ENDIANNESS /* may be big or little endian */ + +/* align a target address to a word boundary */ +#define TARGET_WORD_ALIGN(zz) (((zz) + 0x3) & -0x4) +#endif + + +/*-------------------------------------------------------------------------- + * + * DEFAULT SETTINGS and DERIVED PROPERTIES + * + * This section establishes defaults for values not specified above + *--------------------------------------------------------------------------*/ +#ifndef TARGET_AU_BITS +#define TARGET_AU_BITS 8 /* width of the target addressable unit */ +#define LOG_TARGET_AU_BITS 3 /* log2 of same */ +#endif + +#ifndef CINIT_DEFAULT_PAGE +#define CINIT_DEFAULT_PAGE 0 /* default .cinit page number */ +#endif + +#ifndef DATA_RUN2LOAD +#define DATA_RUN2LOAD(zz) (zz) /* translate data run address to load address */ +#endif + +#ifndef DBG_LIST_PAGE +#define DBG_LIST_PAGE 0 /* page number for .dllview section */ +#endif + +#ifndef TARGET_WORD_ALIGN +/* align a target address to a word boundary */ +#define TARGET_WORD_ALIGN(zz) (zz) +#endif + +#ifndef TDATA_TO_TADDR +#define TDATA_TO_TADDR(zz) (zz) /* target data address to target AU address */ +#define TADDR_TO_TDATA(zz) (zz) /* target AU address to target data address */ +#define TDATA_AU_BITS TARGET_AU_BITS /* bits per data AU */ +#define LOG_TDATA_AU_BITS LOG_TARGET_AU_BITS +#endif + +/* + * + * Useful properties and conversions derived from the above + * + */ + +/* + * Conversions between host and target addresses + */ +#if LOG_BITS_PER_AU == LOG_TARGET_AU_BITS +/* translate target addressable unit to host address */ +#define TADDR_TO_HOST(x) (x) +/* translate host address to target addressable unit */ +#define HOST_TO_TADDR(x) (x) +#elif LOG_BITS_PER_AU > LOG_TARGET_AU_BITS +#define TADDR_TO_HOST(x) ((x) >> (LOG_BITS_PER_AU-LOG_TARGET_AU_BITS)) +#define HOST_TO_TADDR(x) ((x) << (LOG_BITS_PER_AU-LOG_TARGET_AU_BITS)) +#else +#define TADDR_TO_HOST(x) ((x) << (LOG_TARGET_AU_BITS-LOG_BITS_PER_AU)) +#define HOST_TO_TADDR(x) ((x) >> (LOG_TARGET_AU_BITS-LOG_BITS_PER_AU)) +#endif + +#if LOG_BITS_PER_AU == LOG_TDATA_AU_BITS +/* translate target addressable unit to host address */ +#define TDATA_TO_HOST(x) (x) +/* translate host address to target addressable unit */ +#define HOST_TO_TDATA(x) (x) +/* translate host address to target addressable unit, round up */ +#define HOST_TO_TDATA_ROUND(x) (x) +/* byte offset to host offset, rounded up for TDATA size */ +#define BYTE_TO_HOST_TDATA_ROUND(x) BYTE_TO_HOST_ROUND(x) +#elif LOG_BITS_PER_AU > LOG_TDATA_AU_BITS +#define TDATA_TO_HOST(x) ((x) >> (LOG_BITS_PER_AU-LOG_TDATA_AU_BITS)) +#define HOST_TO_TDATA(x) ((x) << (LOG_BITS_PER_AU-LOG_TDATA_AU_BITS)) +#define HOST_TO_TDATA_ROUND(x) ((x) << (LOG_BITS_PER_AU-LOG_TDATA_AU_BITS)) +#define BYTE_TO_HOST_TDATA_ROUND(x) BYTE_TO_HOST_ROUND(x) +#else +#define TDATA_TO_HOST(x) ((x) << (LOG_TDATA_AU_BITS-LOG_BITS_PER_AU)) +#define HOST_TO_TDATA(x) ((x) >> (LOG_TDATA_AU_BITS-LOG_BITS_PER_AU)) +#define HOST_TO_TDATA_ROUND(x) (((x) +\ + (1<<(LOG_TDATA_AU_BITS-LOG_BITS_PER_AU))-1) >>\ + (LOG_TDATA_AU_BITS-LOG_BITS_PER_AU)) +#define BYTE_TO_HOST_TDATA_ROUND(x) (BYTE_TO_HOST((x) +\ + (1<<(LOG_TDATA_AU_BITS-LOG_BITS_PER_BYTE))-1) &\ + -(TDATA_AU_BITS/BITS_PER_AU)) +#endif + +/* + * Input in DOFF format is always expresed in bytes, regardless of loading host + * so we wind up converting from bytes to target and host units even when the + * host is not a byte machine. + */ +#if LOG_BITS_PER_AU == LOG_BITS_PER_BYTE +#define BYTE_TO_HOST(x) (x) +#define BYTE_TO_HOST_ROUND(x) (x) +#define HOST_TO_BYTE(x) (x) +#elif LOG_BITS_PER_AU >= LOG_BITS_PER_BYTE +#define BYTE_TO_HOST(x) ((x) >> (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE)) +#define BYTE_TO_HOST_ROUND(x) ((x + (BITS_PER_AU/BITS_PER_BYTE-1)) >>\ + (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE)) +#define HOST_TO_BYTE(x) ((x) << (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE)) +#else +/* lets not try to deal with sub-8-bit byte machines */ +#endif + +#if LOG_TARGET_AU_BITS == LOG_BITS_PER_BYTE +/* translate target addressable unit to byte address */ +#define TADDR_TO_BYTE(x) (x) +/* translate byte address to target addressable unit */ +#define BYTE_TO_TADDR(x) (x) +#elif LOG_TARGET_AU_BITS > LOG_BITS_PER_BYTE +#define TADDR_TO_BYTE(x) ((x) << (LOG_TARGET_AU_BITS-LOG_BITS_PER_BYTE)) +#define BYTE_TO_TADDR(x) ((x) >> (LOG_TARGET_AU_BITS-LOG_BITS_PER_BYTE)) +#else +/* lets not try to deal with sub-8-bit byte machines */ +#endif + +#ifdef _BIG_ENDIAN +#define HOST_ENDIANNESS 1 +#else +#define HOST_ENDIANNESS 0 +#endif + +#ifdef TARGET_ENDIANNESS +#define TARGET_ENDIANNESS_DIFFERS(rtend) (HOST_ENDIANNESS^TARGET_ENDIANNESS) +#elif HOST_ENDIANNESS +#define TARGET_ENDIANNESS_DIFFERS(rtend) (!(rtend)) +#else +#define TARGET_ENDIANNESS_DIFFERS(rtend) (rtend) +#endif + +/* the unit in which we process target image data */ +#if TARGET_AU_BITS <= 8 +typedef u8 TgtAU_t; +#elif TARGET_AU_BITS <= 16 +typedef u16 TgtAU_t; +#else +typedef u32 TgtAU_t; +#endif + +/* size of that unit */ +#if TARGET_AU_BITS < BITS_PER_AU +#define TGTAU_BITS BITS_PER_AU +#define LOG_TGTAU_BITS LOG_BITS_PER_AU +#else +#define TGTAU_BITS TARGET_AU_BITS +#define LOG_TGTAU_BITS LOG_TARGET_AU_BITS +#endif diff --git a/drivers/dsp/bridge/dynload/reloc.c b/drivers/dsp/bridge/dynload/reloc.c new file mode 100644 index 0000000..54e460e --- /dev/null +++ b/drivers/dsp/bridge/dynload/reloc.c @@ -0,0 +1,425 @@ +/* + * reloc.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "header.h" + +#if TMS32060 +/* the magic symbol for the start of BSS */ +static const char BSSSYMBOL[] = {".bss"}; +#endif + +#if TMS32060 +#include "reloc_table_c6000.c" +#endif + +#if TMS32060 +/* From coff.h - ignore these relocation operations */ +#define R_C60ALIGN 0x76 /* C60: Alignment info for compressor */ +#define R_C60FPHEAD 0x77 /* C60: Explicit assembly directive */ +#define R_C60NOCMP 0x100 /* C60: Don't compress this code scn */ +#endif + +/************************************************************************** + * Procedure dload_unpack + * + * Parameters: + * data pointer to storage unit containing lowest host address of + * image data + * fieldsz Size of bit field, 0 < fieldsz <= sizeof(RVALUE)*BITS_PER_AU + * offset Offset from LSB, 0 <= offset < BITS_PER_AU + * sgn Signedness of the field (ROP_SGN, ROP_UNS, ROP_MAX, ROP_ANY) + * + * Effect: + * Extracts the specified field and returns it. + **************************************************************************/ +RVALUE dload_unpack(struct dload_state *dlthis, TgtAU_t *data, int fieldsz, + int offset, unsigned sgn) +{ + register RVALUE objval; + register int shift, direction; + register TgtAU_t *dp = data; + + fieldsz -= 1; /* avoid nastiness with 32-bit shift of 32-bit value*/ + /* * collect up enough bits to contain the desired field */ + if (TARGET_BIG_ENDIAN) { + dp += (fieldsz + offset) >> LOG_TGTAU_BITS; + direction = -1; + } else + direction = 1; + objval = *dp >> offset; + shift = TGTAU_BITS - offset; + while (shift <= fieldsz) { + dp += direction; + objval += (RVALUE)*dp << shift; + shift += TGTAU_BITS; + } + + /* * sign or zero extend the value appropriately */ + if (sgn == ROP_UNS) + objval &= (2 << fieldsz) - 1; + else { + shift = sizeof(RVALUE) * BITS_PER_AU-1 - fieldsz; + objval = (objval << shift) >> shift; + } + + return objval; + +} /* dload_unpack */ + + +/************************************************************************** + * Procedure dload_repack + * + * Parameters: + * val Value to insert + * data Pointer to storage unit containing lowest host address of + * image data + * fieldsz Size of bit field, 0 < fieldsz <= sizeof(RVALUE)*BITS_PER_AU + * offset Offset from LSB, 0 <= offset < BITS_PER_AU + * sgn Signedness of the field (ROP_SGN, ROP_UNS, ROP_MAX, ROP_ANY) + * + * Effect: + * Stuffs the specified value in the specified field. Returns 0 for + * success + * or 1 if the value will not fit in the specified field according to the + * specified signedness rule. + **************************************************************************/ +static const unsigned char ovf_limit[] = {1, 2, 2}; +int dload_repack(struct dload_state *dlthis, RVALUE val, TgtAU_t *data, + int fieldsz, int offset, unsigned sgn) +{ + register URVALUE objval, mask; + register int shift, direction; + register TgtAU_t *dp = data; + + + fieldsz -= 1; /* avoid nastiness with 32-bit shift of 32-bit value */ + /* clip the bits */ + mask = ((UINT32_C(2) << fieldsz) - 1); + objval = (val & mask); + /* * store the bits through the specified mask */ + if (TARGET_BIG_ENDIAN) { + dp += (fieldsz + offset) >> LOG_TGTAU_BITS; + direction = -1; + } else + direction = 1; + + /* insert LSBs */ + *dp = (*dp & ~(mask << offset)) + (objval << offset); + shift = TGTAU_BITS-offset; + /* align mask and objval with AU boundary */ + objval >>= shift; + mask >>= shift; + + while (mask) { + dp += direction; + *dp = (*dp & ~mask) + objval; + objval >>= TGTAU_BITS; + mask >>= TGTAU_BITS; + } + + /* + * check for overflow + */ + if (sgn) { + unsigned tmp = (val >> fieldsz) + (sgn & 0x1); + if (tmp > ovf_limit[sgn-1]) + return 1; + } + return 0; + +} /* dload_repack */ + +/* lookup table for the scaling amount in a C6x instruction */ +#if TMS32060 +#define SCALE_BITS 4 /* there are 4 bits in the scale field */ +#define SCALE_MASK 0x7 /* we really only use the bottom 3 bits */ +static const u8 C60_Scale[SCALE_MASK+1] = { + 1, 0, 0, 0, 1, 1, 2, 2 +}; +#endif + +/************************************************************************** + * Procedure dload_relocate + * + * Parameters: + * data Pointer to base of image data + * rp Pointer to relocation operation + * + * Effect: + * Performs the specified relocation operation + **************************************************************************/ +void dload_relocate(struct dload_state *dlthis, TgtAU_t *data, + struct reloc_record_t *rp) +{ + RVALUE val = 0; + RVALUE reloc_amt = 0; + unsigned int fieldsz = 0; + unsigned int offset = 0; + unsigned int reloc_info = 0; + unsigned int reloc_action = 0; + register int rx = 0; + RVALUE *stackp = NULL; + int top; + struct Local_Symbol *svp = NULL; +#ifdef RFV_SCALE + unsigned int scale = 0; +#endif + + rx = HASH_FUNC(rp->r_type); + while (rop_map1[rx] != rp->r_type) { + rx = HASH_L(rop_map2[rx]); + if (rx < 0) { +#if TMS32060 + switch (rp->r_type) { + case R_C60ALIGN: + case R_C60NOCMP: + case R_C60FPHEAD: + /* Ignore these reloc types and return */ + break; + default: + /* Unknown reloc type, print error and return */ + dload_error(dlthis, "Bad coff operator 0x%x", rp->r_type); + } +#else + dload_error(dlthis, "Bad coff operator 0x%x", rp->r_type); +#endif + return; + } + } + rx = HASH_I(rop_map2[rx]); + if ((rx < (sizeof(rop_action)/sizeof(uint_least16_t))) + && (rx < (sizeof(rop_info)/sizeof(uint_least16_t))) && (rx > 0)) { + reloc_action = rop_action[rx]; reloc_info = rop_info[rx]; + } else { + dload_error(dlthis, "Buffer Overflow - Array Index Out of Bounds"); + } + + /* Compute the relocation amount for the referenced symbol, if any */ + reloc_amt = rp->r_uval; + if (RFV_SYM(reloc_info)) { /* relocation uses a symbol reference */ + if ((u32)rp->r_symndx < dlthis->dfile_hdr.df_no_syms) { + /* real symbol reference */ + svp = &dlthis->local_symtab[rp->r_symndx]; + reloc_amt = (RFV_SYM(reloc_info) == ROP_SYMD) ? + svp->delta : svp->value; + } + /* reloc references current section */ + else if (rp->r_symndx == -1) + reloc_amt = (RFV_SYM(reloc_info) == ROP_SYMD) ? + dlthis->delta_runaddr : dlthis->image_secn->run_addr; + } /* relocation uses a symbol reference */ + /* Handle stack adjustment */ + val = 0; + top = RFV_STK(reloc_info); + if (top) { + top += dlthis->relstkidx - RSTK_UOP; + if (top >= STATIC_EXPR_STK_SIZE) { + dload_error(dlthis, + "Expression stack overflow in %s at offset " + FMT_UI32, dlthis->image_secn->name, + rp->r_vaddr + dlthis->image_offset); + return; + } + val = dlthis->relstk[dlthis->relstkidx]; + dlthis->relstkidx = top; + stackp = &dlthis->relstk[top]; + } + /* Derive field position and size, if we need them */ + if (reloc_info & ROP_RW) { /* read or write action in our future */ + fieldsz = RFV_WIDTH(reloc_action); + if (fieldsz) { /* field info from table */ + offset = RFV_POSN(reloc_action); + if (TARGET_BIG_ENDIAN) + /* make sure r_vaddr is the lowest target + * address containing bits */ + rp->r_vaddr += RFV_BIGOFF(reloc_info); + } else { /* field info from relocation op */ + fieldsz = rp->r_fieldsz; offset = rp->r_offset; + if (TARGET_BIG_ENDIAN) + /* make sure r_vaddr is the lowest target + address containing bits */ + rp->r_vaddr += (rp->r_wordsz - offset - fieldsz) + >> LOG_TARGET_AU_BITS; + } + data = (TgtAU_t *)((char *)data + TADDR_TO_HOST(rp->r_vaddr)); + /* compute lowest host location of referenced data */ +#if BITS_PER_AU > TARGET_AU_BITS + /* conversion from target address to host address may lose + address bits; add loss to offset */ + if (TARGET_BIG_ENDIAN) { + offset += -((rp->r_vaddr << LOG_TARGET_AU_BITS) + + offset + fieldsz) & + (BITS_PER_AU-TARGET_AU_BITS); + } else { + offset += (rp->r_vaddr << LOG_TARGET_AU_BITS) & + (BITS_PER_AU-1); + } +#endif +#ifdef RFV_SCALE + scale = RFV_SCALE(reloc_info); +#endif + } + /* read the object value from the current image, if so ordered */ + if (reloc_info & ROP_R) { /* relocation reads current image value */ + val = dload_unpack(dlthis, data, fieldsz, offset, + RFV_SIGN(reloc_info)); +#ifdef RFV_SCALE + val <<= scale; +#endif + } + /* perform the necessary arithmetic */ + switch (RFV_ACTION(reloc_action)) { /* relocation actions */ + case RACT_VAL: + break; + case RACT_ASGN: + val = reloc_amt; + break; + case RACT_ADD: + val += reloc_amt; + break; + case RACT_PCR: + /*----------------------------------------------------------- + * Handle special cases of jumping from absolute sections + * (special reloc type) or to absolute destination + * (symndx == -1). In either case, set the appropriate + * relocation amount to 0. + *-----------------------------------------------------------*/ + if (rp->r_symndx == -1) + reloc_amt = 0; + val += reloc_amt - dlthis->delta_runaddr; + break; + case RACT_ADDISP: + val += rp->r_disp + reloc_amt; + break; + case RACT_ASGPC: + val = dlthis->image_secn->run_addr + reloc_amt; + break; + case RACT_PLUS: + if (stackp != NULL) + val += *stackp; + break; + case RACT_SUB: + if (stackp != NULL) + val = *stackp - val; + break; + case RACT_NEG: + val = -val; + break; + case RACT_MPY: + if (stackp != NULL) + val *= *stackp; + break; + case RACT_DIV: + if (stackp != NULL) + val = *stackp / val; + break; + case RACT_MOD: + if (stackp != NULL) + val = *stackp % val; + break; + case RACT_SR: + if (val >= sizeof(RVALUE) * BITS_PER_AU) + val = 0; + else if (stackp != NULL) + val = (URVALUE)*stackp >> val; + break; + case RACT_ASR: + if (val >= sizeof(RVALUE)*BITS_PER_AU) + val = sizeof(RVALUE)*BITS_PER_AU - 1; + else if (stackp != NULL) + val = *stackp >> val; + break; + case RACT_SL: + if (val >= sizeof(RVALUE)*BITS_PER_AU) + val = 0; + else if (stackp != NULL) + val = *stackp << val; + break; + case RACT_AND: + if (stackp != NULL) + val &= *stackp; + break; + case RACT_OR: + if (stackp != NULL) + val |= *stackp; + break; + case RACT_XOR: + if (stackp != NULL) + val ^= *stackp; + break; + case RACT_NOT: + val = ~val; + break; +#if TMS32060 + case RACT_C6SECT: + /* actually needed address of secn containing symbol */ + if (svp != NULL) { + if (rp->r_symndx >= 0) + if (svp->secnn > 0) + reloc_amt = dlthis->ldr_sections + [svp->secnn-1].run_addr; + } + /* !!! FALL THRU !!! */ + case RACT_C6BASE: + if (dlthis->bss_run_base == 0) { + struct dynload_symbol *symp; + symp = dlthis->mysym->Find_Matching_Symbol + (dlthis->mysym, BSSSYMBOL); + /* lookup value of global BSS base */ + if (symp) + dlthis->bss_run_base = symp->value; + else + dload_error(dlthis, + "Global BSS base referenced in %s offset"\ + FMT_UI32 " but not defined", + dlthis->image_secn->name, + rp->r_vaddr + dlthis->image_offset); + } + reloc_amt -= dlthis->bss_run_base; + /* !!! FALL THRU !!! */ + case RACT_C6DSPL: + /* scale factor determined by 3 LSBs of field */ + scale = C60_Scale[val & SCALE_MASK]; + offset += SCALE_BITS; + fieldsz -= SCALE_BITS; + val >>= SCALE_BITS; /* ignore the scale field hereafter */ + val <<= scale; + val += reloc_amt; /* do the usual relocation */ + if (((1 << scale)-1) & val) + dload_error(dlthis, + "Unaligned reference in %s offset " FMT_UI32, + dlthis->image_secn->name, + rp->r_vaddr + dlthis->image_offset); + break; +#endif + } /* relocation actions */ + /* * Put back result as required */ + if (reloc_info & ROP_W) { /* relocation writes image value */ +#ifdef RFV_SCALE + val >>= scale; +#endif + if (dload_repack(dlthis, val, data, fieldsz, offset, + RFV_SIGN(reloc_info))) { + dload_error(dlthis, "Relocation value " FMT_UI32 + " overflows %d bits in %s offset " FMT_UI32, val, + fieldsz, dlthis->image_secn->name, + dlthis->image_offset + rp->r_vaddr); + } + } else if (top) + *stackp = val; +} /* reloc_value */ + diff --git a/drivers/dsp/bridge/dynload/reloc_table.h b/drivers/dsp/bridge/dynload/reloc_table.h new file mode 100644 index 0000000..6326146 --- /dev/null +++ b/drivers/dsp/bridge/dynload/reloc_table.h @@ -0,0 +1,102 @@ +/* + * reloc_table.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + + +#ifndef __RELOC_TABLE_H__ +#define __RELOC_TABLE_H__ +/* + * Table of relocation operator properties + */ +#include + +/* How does this relocation operation access the program image? */ +#define ROP_N 0 /* does not access image */ +#define ROP_R 1 /* read from image */ +#define ROP_W 2 /* write to image */ +#define ROP_RW 3 /* read from and write to image */ + +/* For program image access, what are the overflow rules for the bit field? */ +/* Beware! Procedure repack depends on this encoding */ +#define ROP_ANY 0 /* no overflow ever, just truncate the value */ +#define ROP_SGN 1 /* signed field */ +#define ROP_UNS 2 /* unsigned field */ +#define ROP_MAX 3 /* allow maximum range of either signed or unsigned */ + +/* How does the relocation operation use the symbol reference */ +#define ROP_IGN 0 /* no symbol is referenced */ +#define ROP_LIT 0 /* use rp->r_uval literal field */ +#define ROP_SYM 1 /* symbol value is used in relocation */ +#define ROP_SYMD 2 /* delta value vs last link is used */ + +/* How does the reloc op use the stack? */ +#define RSTK_N 0 /* Does not use */ +#define RSTK_POP 1 /* Does a POP */ +#define RSTK_UOP 2 /* Unary op, stack position unaffected */ +#define RSTK_PSH 3 /* Does a push */ + +/* + * Computational actions performed by the dynamic loader + */ +enum Dload_Actions { + RACT_VAL, /* don't alter the current val (from stack or mem fetch) */ + RACT_ASGN, /* set value to reference amount (from symbol reference) */ + RACT_ADD, /* add reference to value */ + RACT_PCR, /* add reference minus PC delta to value */ + RACT_ADDISP, /* add reference plus r_disp */ + RACT_ASGPC, /* set value to section address plus reference */ + + RACT_PLUS, /* stack + */ + RACT_SUB, /* stack - */ + RACT_NEG, /* stack unary - */ + + RACT_MPY, /* stack * */ + RACT_DIV, /* stack / */ + RACT_MOD, /* stack % */ + + RACT_SR, /* stack unsigned >> */ + RACT_ASR, /* stack signed >> */ + RACT_SL, /* stack << */ + RACT_AND, /* stack & */ + RACT_OR, /* stack | */ + RACT_XOR, /* stack ^ */ + RACT_NOT, /* stack ~ */ + RACT_C6SECT, /* for C60 R_SECT op */ + RACT_C6BASE, /* for C60 R_BASE op */ + RACT_C6DSPL, /* for C60 scaled 15-bit displacement */ + RACT_PCR23T /* for ARM Thumb long branch */ +}; + +/* + * macros used to extract values + */ +#define RFV_POSN(aaa) ((aaa) & 0xF) +#define RFV_WIDTH(aaa) (((aaa) >> 4) & 0x3F) +#define RFV_ACTION(aaa) ((aaa) >> 10) + +#define RFV_SIGN(iii) (((iii) >> 2) & 0x3) +#define RFV_SYM(iii) (((iii) >> 4) & 0x3) +#define RFV_STK(iii) (((iii) >> 6) & 0x3) +#define RFV_ACCS(iii) ((iii) & 0x3) + +#if (TMS32060) +#define RFV_SCALE(iii) ((iii) >> 11) +#define RFV_BIGOFF(iii) (((iii) >> 8) & 0x7) +#else +#define RFV_BIGOFF(iii) ((iii) >> 8) +#endif + +#endif /* __RELOC_TABLE_H__ */ diff --git a/drivers/dsp/bridge/dynload/reloc_table_c6000.c b/drivers/dsp/bridge/dynload/reloc_table_c6000.c new file mode 100644 index 0000000..978834c --- /dev/null +++ b/drivers/dsp/bridge/dynload/reloc_table_c6000.c @@ -0,0 +1,258 @@ +/* + * reloc_table_c6000.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* Tables generated for c6000 */ + +#define HASH_FUNC(zz) (((((zz) + 1) * UINT32_C(1845)) >> 11) & 63) +#define HASH_L(zz) ((zz) >> 8) +#define HASH_I(zz) ((zz) & 0xFF) + +static const u16 rop_map1[] = { + 0, + 1, + 2, + 20, + 4, + 5, + 6, + 15, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 17, + 18, + 19, + 21, + 16, + 16394, + 16404, + 65535, + 65535, + 65535, + 65535, + 65535, + 65535, + 32, + 65535, + 65535, + 65535, + 65535, + 65535, + 65535, + 40, + 112, + 113, + 65535, + 16384, + 16385, + 16386, + 16387, + 16388, + 16389, + 16390, + 16391, + 16392, + 16393, + 16395, + 16396, + 16397, + 16398, + 16399, + 16400, + 16401, + 16402, + 16403, + 16405, + 16406, + 65535, + 65535, + 65535 +}; + +static const s16 rop_map2[] = { + -256, + -255, + -254, + -245, + -253, + -252, + -251, + -250, + -241, + -240, + -239, + -238, + -237, + -236, + 1813, + 5142, + -248, + -247, + 778, + -244, + -249, + -221, + -211, + -1, + -1, + -1, + -1, + -1, + -1, + -243, + -1, + -1, + -1, + -1, + -1, + -1, + -242, + -233, + -232, + -1, + -231, + -230, + -229, + -228, + -227, + -226, + -225, + -224, + -223, + 5410, + -220, + -219, + -218, + -217, + -216, + -215, + -214, + -213, + 5676, + -210, + -209, + -1, + -1, + -1 +}; + +static const u16 rop_action[] = { + 2560, + 2304, + 2304, + 2432, + 2432, + 2560, + 2176, + 2304, + 2560, + 3200, + 3328, + 3584, + 3456, + 2304, + 4208, + 20788, + 21812, + 3415, + 3245, + 2311, + 4359, + 19764, + 2311, + 3191, + 3280, + 6656, + 7680, + 8704, + 9728, + 10752, + 11776, + 12800, + 13824, + 14848, + 15872, + 16896, + 17920, + 18944, + 0, + 0, + 0, + 0, + 1536, + 1536, + 1536, + 5632, + 512, + 0 +}; + +static const u16 rop_info[] = { + 0, + 35, + 35, + 35, + 35, + 35, + 35, + 35, + 35, + 39, + 39, + 39, + 39, + 35, + 34, + 283, + 299, + 4135, + 4391, + 291, + 33059, + 283, + 295, + 4647, + 4135, + 64, + 64, + 128, + 64, + 64, + 64, + 64, + 64, + 64, + 64, + 64, + 64, + 128, + 201, + 197, + 74, + 70, + 208, + 196, + 200, + 192, + 192, + 66 +}; diff --git a/drivers/dsp/bridge/gen/_gt_para.c b/drivers/dsp/bridge/gen/_gt_para.c new file mode 100644 index 0000000..181fe41 --- /dev/null +++ b/drivers/dsp/bridge/gen/_gt_para.c @@ -0,0 +1,107 @@ +/* + * _gt_para.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== _gt_para.c ======== + * Description: + * Configuration parameters for GT. This file is separated from + * gt.c so that GT_assert() can reference the error function without + * forcing the linker to include all the code for GT_set(), GT_init(), + * etc. into a fully bound image. Thus, GT_assert() can be retained in + * a program for which GT_?trace() has been compiled out. + * + *! Revision History: + *! ================ + *! 24-Feb-2003 vp: Code Review Updates. + *! 18-Oct-2002 sb: Ported to Linux platform. + *! 03-Jul-2001 rr: Removed kfuncs.h because of build errors. + *! 07-Dec-1999 ag: Fxn error now causes a WinCE DebugBreak; + *! 30-Aug-1999 ag: Now uses GP_printf for printf and error. + *! + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include + +/* ----------------------------------- Trace & Debug */ +#include + +/* ----------------------------------- Function Prototypes */ +static void error(char *msg, ...); +static s32 GT_nop(void); + +/* ----------------------------------- Defines, Data Structures, Typedefs */ + +struct GT_Config _GT_params = { + (Fxn) printk, /* printf */ + (Fxn) NULL, /* procid */ + (Fxn) GT_nop, /* taskid */ + (Fxn) error, /* error */ +}; + +/* ----------------------------------- Globals */ +struct GT_Config *GT = &_GT_params; + +/* + * ======== GT_nop ======== + */ +static s32 GT_nop(void) +{ + return 0; +} + +/* + * ======== error ======== + * purpose: + * Prints error onto the standard output. + */ +static void error(char *fmt, ...) +{ + s32 arg1, arg2, arg3, arg4, arg5, arg6; + + va_list va; + + va_start(va, fmt); + + arg1 = va_arg(va, s32); + arg2 = va_arg(va, s32); + arg3 = va_arg(va, s32); + arg4 = va_arg(va, s32); + arg5 = va_arg(va, s32); + arg6 = va_arg(va, s32); + + va_end(va); + + printk("ERROR: "); + printk(fmt, arg1, arg2, arg3, arg4, arg5, arg6); + +#if defined(DEBUG) || defined(DDSP_DEBUG_PRODUCT) + if (in_interrupt()) { + printk(KERN_INFO "Not stopping after error since ISR/DPC " + "are disabled\n"); + } else { + set_current_state(TASK_INTERRUPTIBLE); + flush_signals(current); + schedule(); + flush_signals(current); + printk(KERN_INFO "Signaled in error function\n"); + } +#endif +} diff --git a/drivers/dsp/bridge/gen/gb.c b/drivers/dsp/bridge/gen/gb.c new file mode 100644 index 0000000..1d21e97 --- /dev/null +++ b/drivers/dsp/bridge/gen/gb.c @@ -0,0 +1,182 @@ +/* + * gb.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== gb.c ======== + * Description: Generic bitmap operations. + * + *! Revision History + *! ================ + *! 24-Feb-2003 vp Code review updates. + *! 17-Dec-2002 map Fixed GB_minset(), GB_empty(), and GB_full(), + *! to ensure only 'len' bits are considered in the map + *! 18-Oct-2002 sb Ported to Linux platform. + *! 06-Dec-2001 jeh Fixed bug in GB_minclear(). + *! + */ + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +/* ----------------------------------- This */ +#include +#include + +typedef GB_BitNum GB_WordNum; + +struct GB_TMap { + GB_BitNum len; + GB_WordNum wcnt; + u32 *words; +}; + +/* + * ======== GB_clear ======== + * purpose: + * Clears a bit in the bit map. + */ + +void GB_clear(struct GB_TMap *map, GB_BitNum bitn) +{ + u32 mask; + + mask = 1L << (bitn % BITS_PER_LONG); + map->words[bitn / BITS_PER_LONG] &= ~mask; +} + +/* + * ======== GB_create ======== + * purpose: + * Creates a bit map. + */ + +struct GB_TMap *GB_create(GB_BitNum len) +{ + struct GB_TMap *map; + GB_WordNum i; + map = (struct GB_TMap *)GS_alloc(sizeof(struct GB_TMap)); + if (map != NULL) { + map->len = len; + map->wcnt = len / BITS_PER_LONG + 1; + map->words = (u32 *)GS_alloc(map->wcnt * sizeof(u32)); + if (map->words != NULL) { + for (i = 0; i < map->wcnt; i++) + map->words[i] = 0L; + + } else { + GS_frees(map, sizeof(struct GB_TMap)); + map = NULL; + } + } + + return map; +} + +/* + * ======== GB_delete ======== + * purpose: + * Frees a bit map. + */ + +void GB_delete(struct GB_TMap *map) +{ + GS_frees(map->words, map->wcnt * sizeof(u32)); + GS_frees(map, sizeof(struct GB_TMap)); +} + +/* + * ======== GB_findandset ======== + * purpose: + * Finds a free bit and sets it. + */ +GB_BitNum GB_findandset(struct GB_TMap *map) +{ + GB_BitNum bitn; + + bitn = GB_minclear(map); + + if (bitn != GB_NOBITS) + GB_set(map, bitn); + + return bitn; +} + +/* + * ======== GB_minclear ======== + * purpose: + * returns the location of the first unset bit in the bit map. + */ +GB_BitNum GB_minclear(struct GB_TMap *map) +{ + GB_BitNum bit_location = 0; + GB_BitNum bitAcc = 0; + GB_WordNum i; + GB_BitNum bit; + u32 *word; + + for (word = map->words, i = 0; i < map->wcnt; word++, i++) { + if (~*word) { + for (bit = 0; bit < BITS_PER_LONG; bit++, bitAcc++) { + if (bitAcc == map->len) + return GB_NOBITS; + + if (~*word & (1L << bit)) { + bit_location = i * BITS_PER_LONG + bit; + return bit_location; + } + + } + } else { + bitAcc += BITS_PER_LONG; + } + } + + return GB_NOBITS; +} + +/* + * ======== GB_set ======== + * purpose: + * Sets a bit in the bit map. + */ + +void GB_set(struct GB_TMap *map, GB_BitNum bitn) +{ + u32 mask; + + mask = 1L << (bitn % BITS_PER_LONG); + map->words[bitn / BITS_PER_LONG] |= mask; +} + +/* + * ======== GB_test ======== + * purpose: + * Returns true if the bit is set in the specified location. + */ + +bool GB_test(struct GB_TMap *map, GB_BitNum bitn) +{ + bool state; + u32 mask; + u32 word; + + mask = 1L << (bitn % BITS_PER_LONG); + word = map->words[bitn / BITS_PER_LONG]; + state = word & mask ? TRUE : FALSE; + + return state; +} diff --git a/drivers/dsp/bridge/gen/gh.c b/drivers/dsp/bridge/gen/gh.c new file mode 100644 index 0000000..a20ae16 --- /dev/null +++ b/drivers/dsp/bridge/gen/gh.c @@ -0,0 +1,191 @@ +/* + * gh.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== gh.c ======== + */ + +#include + +#include + +#include + +#include + +struct Elem { + struct Elem *next; + u8 data[1]; +}; + +struct GH_THashTab { + u16 maxBucket; + u16 valSize; + struct Elem **buckets; + u16(*hash) (void *, u16); + bool(*match) (void *, void *); + void(*delete) (void *); +}; + +static void Nop(void *p); +static s32 curInit; +static void myfree(void *ptr, s32 size); + +/* + * ======== GH_create ======== + */ + +struct GH_THashTab *GH_create(u16 maxBucket, u16 valSize, + u16(*hash)(void *, u16), bool(*match)(void *, void *), + void(*delete)(void *)) +{ + struct GH_THashTab *hashTab; + u16 i; + hashTab = (struct GH_THashTab *)GS_alloc(sizeof(struct GH_THashTab)); + if (hashTab == NULL) + return NULL; + hashTab->maxBucket = maxBucket; + hashTab->valSize = valSize; + hashTab->hash = hash; + hashTab->match = match; + hashTab->delete = delete == NULL ? Nop : delete; + + hashTab->buckets = (struct Elem **) + GS_alloc(sizeof(struct Elem *) * maxBucket); + if (hashTab->buckets == NULL) { + GH_delete(hashTab); + return NULL; + } + + for (i = 0; i < maxBucket; i++) + hashTab->buckets[i] = NULL; + + return hashTab; +} + +/* + * ======== GH_delete ======== + */ +void GH_delete(struct GH_THashTab *hashTab) +{ + struct Elem *elem, *next; + u16 i; + + if (hashTab != NULL) { + if (hashTab->buckets != NULL) { + for (i = 0; i < hashTab->maxBucket; i++) { + for (elem = hashTab->buckets[i]; elem != NULL; + elem = next) { + next = elem->next; + (*hashTab->delete) (elem->data); + myfree(elem, sizeof(struct Elem) - 1 + + hashTab->valSize); + } + } + + myfree(hashTab->buckets, sizeof(struct Elem *) + * hashTab->maxBucket); + } + + myfree(hashTab, sizeof(struct GH_THashTab)); + } +} + +/* + * ======== GH_exit ======== + */ + +void GH_exit(void) +{ + if (curInit-- == 1) + GS_exit(); + +} + +/* + * ======== GH_find ======== + */ + +void *GH_find(struct GH_THashTab *hashTab, void *key) +{ + struct Elem *elem; + + elem = hashTab->buckets[(*hashTab->hash)(key, hashTab->maxBucket)]; + + for (; elem; elem = elem->next) { + if ((*hashTab->match)(key, elem->data)) + return elem->data; + } + + return NULL; +} + +/* + * ======== GH_init ======== + */ + +void GH_init(void) +{ + if (curInit++ == 0) + GS_init(); +} + +/* + * ======== GH_insert ======== + */ + +void *GH_insert(struct GH_THashTab *hashTab, void *key, void *value) +{ + struct Elem *elem; + u16 i; + char *src, *dst; + + elem = (struct Elem *)GS_alloc(sizeof(struct Elem) - 1 + + hashTab->valSize); + if (elem != NULL) { + + dst = (char *)elem->data; + src = (char *)value; + for (i = 0; i < hashTab->valSize; i++) + *dst++ = *src++; + + i = (*hashTab->hash)(key, hashTab->maxBucket); + elem->next = hashTab->buckets[i]; + hashTab->buckets[i] = elem; + + return elem->data; + } + + return NULL; +} + +/* + * ======== Nop ======== + */ +/* ARGSUSED */ +static void Nop(void *p) +{ + p = p; /* stifle compiler warning */ +} + +/* + * ======== myfree ======== + */ +static void myfree(void *ptr, s32 size) +{ + GS_free(ptr); +} diff --git a/drivers/dsp/bridge/gen/gs.c b/drivers/dsp/bridge/gen/gs.c new file mode 100644 index 0000000..ef5f923 --- /dev/null +++ b/drivers/dsp/bridge/gen/gs.c @@ -0,0 +1,108 @@ +/* + * gs.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== gs.c ======== + * Description: + * General storage memory allocator services. + * + *! Revision History + *! ================ + *! 29-Sep-1999 ag: Un-commented MEM_Init in GS_init(). + *! 14-May-1997 mg: Modified to use new GS API for GS_free() and GS_frees(). + *! 06-Nov-1996 gp: Re-commented MEM_Init in GS_init(). GS needs GS_Exit(). + *! 21-Oct-1996 db: Un-commented MEM_Init in GS_init(). + *! 21-May-1996 mg: Created from original stdlib implementation. + */ + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include +/* ----------------------------------- OS Adaptation Layer */ +#include + +/* ----------------------------------- This */ +#include + +/* ----------------------------------- Globals */ +static u32 cumsize; + +/* + * ======== GS_alloc ======== + * purpose: + * Allocates memory of the specified size. + */ +void *GS_alloc(u32 size) +{ + void *p; + + p = MEM_Calloc(size, MEM_PAGED); + if (p == NULL) + return NULL; + cumsize += size; + return p; +} + +/* + * ======== GS_exit ======== + * purpose: + * Discontinue the usage of the GS module. + */ +void GS_exit(void) +{ + MEM_Exit(); +} + +/* + * ======== GS_free ======== + * purpose: + * Frees the memory. + */ +void GS_free(void *ptr) +{ + MEM_Free(ptr); + /* ack! no size info */ + /* cumsize -= size; */ +} + +/* + * ======== GS_frees ======== + * purpose: + * Frees the memory. + */ +void GS_frees(void *ptr, u32 size) +{ + MEM_Free(ptr); + cumsize -= size; +} + +/* + * ======== GS_init ======== + * purpose: + * Initializes the GS module. + */ +void GS_init(void) +{ + static bool curInit; + + if (curInit == false) { + curInit = true; + + MEM_Init(); + } +} diff --git a/drivers/dsp/bridge/gen/gt.c b/drivers/dsp/bridge/gen/gt.c new file mode 100644 index 0000000..452d6e6 --- /dev/null +++ b/drivers/dsp/bridge/gen/gt.c @@ -0,0 +1,348 @@ +/* + * gt.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== gt.c ======== + * Description: This module implements the trace mechanism for bridge. + * + *! Revision History + *! ================ + *! 16-May-1997 dr Changed GT_Config member names to conform to coding + *! standards. + *! 23-Apr-1997 ge Check for GT->TIDFXN for NULL before calling it. + *! 03-Jan-1997 ge Changed GT_Config structure member names to eliminate + *! preprocessor confusion with other macros. + */ + +/* ----------------------------------- DSP/BIOS Bridge */ +#include + +/* ----------------------------------- This */ +#include + +#define GT_WILD '*' + +#define GT_CLEAR '=' +#define GT_ON '+' +#define GT_OFF '-' + +enum GT_State { + GT_SEP, + GT_FIRST, + GT_SECOND, + GT_OP, + GT_DIGITS +} ; + +#ifdef CONFIG_BRIDGE_DEBUG +static char *GT_1format = "%s - %d: "; +static char *GT_2format = "%s - %d(%d): "; +#endif /* CONFIG_BRIDGE_DEBUG */ + +static unsigned char *GT_tMask[GT_BOUND]; + +static bool curInit; +static char *separator; +static unsigned char tabMem[GT_BOUND][sizeof(unsigned char) * GT_BOUND]; + +static void error(char *string); +static void setMask(s16 index1, s16 index2, char op, unsigned char mask); + +/* + * ======== _GT_create ======== + * purpose: + * Creates GT mask. + */ +void _GT_create(struct GT_Mask *mask, char *modName) +{ + mask->modName = modName; + mask->flags = &(GT_tMask[modName[0] - 'A'][modName[1] - 'A']); +} + +/* + * ======== GT_init ======== + * purpose: + * Initializes GT module. + */ +#ifdef GT_init +#undef GT_init +#endif +void GT_init(void) +{ + register unsigned char index1; + register unsigned char index2; + + if (!curInit) { + curInit = true; + + separator = " ,;/"; + + for (index1 = 0; index1 < GT_BOUND; index1++) { + GT_tMask[index1] = tabMem[index1]; + for (index2 = 0; index2 < GT_BOUND; index2++) { + /* no tracing */ + GT_tMask[index1][index2] = 0x00; + } + } + } +} + +/* + * ======== _GT_set ======== + * purpose: + * Sets the trace string format. + */ + +void _GT_set(char *str) +{ + enum GT_State state; + char *sep; + s16 index1 = GT_BOUND; /* indicates all values */ + s16 index2 = GT_BOUND; /* indicates all values */ + char op = GT_CLEAR; + bool maskValid; + s16 digit; + register unsigned char mask = 0x0; /* no tracing */ + + if (str == NULL) + return; + + maskValid = false; + state = GT_SEP; + while (*str != '\0') { + switch ((s32) state) { + case (s32) GT_SEP: + maskValid = false; + sep = separator; + while (*sep != '\0') { + if (*str == *sep) { + str++; + break; + } else { + sep++; + } + } + if (*sep == '\0') + state = GT_FIRST; + + break; + case (s32) GT_FIRST: + if (*str == GT_WILD) { + /* indicates all values */ + index1 = GT_BOUND; + /* indicates all values */ + index2 = GT_BOUND; + state = GT_OP; + } else { + if (*str >= 'a') + index1 = (s16) (*str - 'a'); + else + index1 = (s16) (*str - 'A'); + if ((index1 >= 0) && (index1 < GT_BOUND)) + state = GT_SECOND; + else + state = GT_SEP; + } + str++; + break; + case (s32) GT_SECOND: + if (*str == GT_WILD) { + index2 = GT_BOUND; /* indicates all values */ + state = GT_OP; + str++; + } else { + if (*str >= 'a') + index2 = (s16) (*str - 'a'); + else + index2 = (s16) (*str - 'A'); + if ((index2 >= 0) && (index2 < GT_BOUND)) { + state = GT_OP; + str++; + } else { + state = GT_SEP; + } + } + break; + case (s32) GT_OP: + op = *str; + mask = 0x0; /* no tracing */ + switch (op) { + case (s32) GT_CLEAR: + maskValid = true; + case (s32) GT_ON: + case (s32) GT_OFF: + state = GT_DIGITS; + str++; + break; + default: + state = GT_SEP; + break; + } + break; + case (s32) GT_DIGITS: + digit = (s16) (*str - '0'); + if ((digit >= 0) && (digit <= 7)) { + mask |= (0x01 << digit); + maskValid = true; + str++; + } else { + if (maskValid == true) { + setMask(index1, index2, op, mask); + maskValid = false; + } + state = GT_SEP; + } + break; + default: + error("illegal trace mask"); + break; + } + } + + if (maskValid) + setMask(index1, index2, op, mask); +} + +/* + * ======== _GT_trace ======== + * purpose: + * Prints the input string onto standard output + */ + +s32 _GT_trace(struct GT_Mask *mask, char *format, ...) +{ + s32 arg1, arg2, arg3, arg4, arg5, arg6; + va_list va; + + va_start(va, format); + + arg1 = va_arg(va, s32); + arg2 = va_arg(va, s32); + arg3 = va_arg(va, s32); + arg4 = va_arg(va, s32); + arg5 = va_arg(va, s32); + arg6 = va_arg(va, s32); + + va_end(va); +#ifdef DEBUG + if (GT->PIDFXN == NULL) { + printk(GT_1format, mask->modName, GT->TIDFXN ? + (*GT->TIDFXN)() : 0); + } else { + printk(GT_2format, mask->modName, (*GT->PIDFXN)(), + GT->TIDFXN ? (*GT->TIDFXN)() : 0); + } +#endif + printk(format, arg1, arg2, arg3, arg4, arg5, arg6); + + return 0; +} + +/* + * ======== error ======== + * purpose: + * Prints errors onto the standard output. + */ +static void error(char *string) +{ + printk("GT: %s", string); +} + +/* + * ======== setmask ======== + * purpose: + * Sets mask for the GT module. + */ + +static void setMask(s16 index1, s16 index2, char op, u8 mask) +{ + register s16 index; + + if (index1 < GT_BOUND) { + if (index2 < GT_BOUND) { + switch (op) { + case (s32) GT_CLEAR: + GT_tMask[index1][index2] = mask; + break; + case (s32) GT_ON: + GT_tMask[index1][index2] |= mask; + break; + case (s32) GT_OFF: + GT_tMask[index1][index2] &= ~mask; + break; + default: + error("illegal trace mask"); + break; + } + } else { + for (index2--; index2 >= 0; index2--) { + switch (op) { + case (s32) GT_CLEAR: + GT_tMask[index1][index2] = mask; + break; + case (s32) GT_ON: + GT_tMask[index1][index2] |= mask; + break; + case (s32) GT_OFF: + GT_tMask[index1][index2] &= ~mask; + break; + default: + error("illegal trace mask"); + break; + } + } + } + } else { + for (index1--; index1 >= 0; index1--) { + if (index2 < GT_BOUND) { + switch (op) { + case (s32) GT_CLEAR: + GT_tMask[index1][index2] = mask; + break; + case (s32) GT_ON: + GT_tMask[index1][index2] |= mask; + break; + case (s32) GT_OFF: + GT_tMask[index1][index2] &= ~mask; + break; + default: + error("illegal trace mask"); + break; + } + } else { + index = GT_BOUND; + for (index--; index >= 0; index--) { + switch (op) { + case (s32) GT_CLEAR: + GT_tMask[index1][index] = mask; + break; + case (s32) GT_ON: + GT_tMask[index1][index] |= mask; + break; + case (s32) GT_OFF: + GT_tMask[index1][index] &= + ~mask; + break; + default: + error("illegal trace mask"); + break; + } + } + } + } + } +} diff --git a/drivers/dsp/bridge/gen/uuidutil.c b/drivers/dsp/bridge/gen/uuidutil.c new file mode 100644 index 0000000..a45f448 --- /dev/null +++ b/drivers/dsp/bridge/gen/uuidutil.c @@ -0,0 +1,238 @@ +/* + * uuidutil.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== uuidutil.c ======== + * Description: + * This file contains the implementation of UUID helper functions. + * + *! Revision History + *! ================ + *! 23-Feb-2003 vp: Code review updates. + *! 18-Oct-2003 vp: Ported to Linux platform. + *! 31-Aug-2000 rr: UUID_UuidFromString bug fixed. + *! 29-Aug-2000 rr: Modified UUID_UuidFromString. + *! 09-Nov-2000 kc: Modified UUID_UuidFromString to simplify implementation. + *! 30-Oct-2000 kc: Modified UUID utility module function prefix. + *! 10-Aug-2000 kc: Created. + *! + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include + +/* ----------------------------------- This */ +#include + +/* + * ======== UUID_UuidToString ======== + * Purpose: + * Converts a struct DSP_UUID to a string. + * Note: snprintf format specifier is: + * %[flags] [width] [.precision] [{h | l | I64 | L}]type + */ +void UUID_UuidToString(IN struct DSP_UUID *pUuid, OUT char *pszUuid, + IN s32 size) +{ + s32 i; /* return result from snprintf. */ + + DBC_Require(pUuid && pszUuid); + + i = snprintf(pszUuid, size, + "%.8X_%.4X_%.4X_%.2X%.2X_%.2X%.2X%.2X%.2X%.2X%.2X", + pUuid->ulData1, pUuid->usData2, pUuid->usData3, + pUuid->ucData4, pUuid->ucData5, pUuid->ucData6[0], + pUuid->ucData6[1], pUuid->ucData6[2], pUuid->ucData6[3], + pUuid->ucData6[4], pUuid->ucData6[5]); + + DBC_Ensure(i != -1); +} + +/* + * ======== htoi ======== + * Purpose: + * Converts a hex value to a decimal integer. + */ + +static int htoi(char c) +{ + switch (c) { + case '0': + return 0; + case '1': + return 1; + case '2': + return 2; + case '3': + return 3; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + case 'A': + return 10; + case 'B': + return 11; + case 'C': + return 12; + case 'D': + return 13; + case 'E': + return 14; + case 'F': + return 15; + case 'a': + return 10; + case 'b': + return 11; + case 'c': + return 12; + case 'd': + return 13; + case 'e': + return 14; + case 'f': + return 15; + } + return 0; +} + +/* + * ======== UUID_UuidFromString ======== + * Purpose: + * Converts a string to a struct DSP_UUID. + */ +void UUID_UuidFromString(IN char *pszUuid, OUT struct DSP_UUID *pUuid) +{ + char c; + s32 i, j; + s32 result; + char *temp = pszUuid; + + result = 0; + for (i = 0; i < 8; i++) { + /* Get first character in string */ + c = *temp; + + /* Increase the results by new value */ + result *= 16; + result += htoi(c); + + /* Go to next character in string */ + temp++; + } + pUuid->ulData1 = result; + + /* Step over underscore */ + temp++; + + result = 0; + for (i = 0; i < 4; i++) { + /* Get first character in string */ + c = *temp; + + /* Increase the results by new value */ + result *= 16; + result += htoi(c); + + /* Go to next character in string */ + temp++; + } + pUuid->usData2 = (u16)result; + + /* Step over underscore */ + temp++; + + result = 0; + for (i = 0; i < 4; i++) { + /* Get first character in string */ + c = *temp; + + /* Increase the results by new value */ + result *= 16; + result += htoi(c); + + /* Go to next character in string */ + temp++; + } + pUuid->usData3 = (u16)result; + + /* Step over underscore */ + temp++; + + result = 0; + for (i = 0; i < 2; i++) { + /* Get first character in string */ + c = *temp; + + /* Increase the results by new value */ + result *= 16; + result += htoi(c); + + /* Go to next character in string */ + temp++; + } + pUuid->ucData4 = (u8)result; + + result = 0; + for (i = 0; i < 2; i++) { + /* Get first character in string */ + c = *temp; + + /* Increase the results by new value */ + result *= 16; + result += htoi(c); + + /* Go to next character in string */ + temp++; + } + pUuid->ucData5 = (u8)result; + + /* Step over underscore */ + temp++; + + for (j = 0; j < 6; j++) { + result = 0; + for (i = 0; i < 2; i++) { + /* Get first character in string */ + c = *temp; + + /* Increase the results by new value */ + result *= 16; + result += htoi(c); + + /* Go to next character in string */ + temp++; + } + pUuid->ucData6[j] = (u8)result; + } +} diff --git a/drivers/dsp/bridge/hw/EasiGlobal.h b/drivers/dsp/bridge/hw/EasiGlobal.h new file mode 100644 index 0000000..b023826 --- /dev/null +++ b/drivers/dsp/bridge/hw/EasiGlobal.h @@ -0,0 +1,42 @@ +/* + * EasiGlobal.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef __EASIGLOBAL_H +#define __EASIGLOBAL_H +#include + +/* + * DEFINE: READ_ONLY, WRITE_ONLY & READ_WRITE + * + * DESCRIPTION: Defines used to describe register types for EASI-checker tests. + */ + +#define READ_ONLY 1 +#define WRITE_ONLY 2 +#define READ_WRITE 3 + +/* + * MACRO: _DEBUG_LEVEL_1_EASI + * + * DESCRIPTION: A MACRO which can be used to indicate that a particular beach + * register access function was called. + * + * NOTE: We currently dont use this functionality. + */ +#define _DEBUG_LEVEL_1_EASI(easiNum) ((void)0) + +#endif /* __EASIGLOBAL_H */ + diff --git a/drivers/dsp/bridge/hw/GlobalTypes.h b/drivers/dsp/bridge/hw/GlobalTypes.h new file mode 100644 index 0000000..9004a37 --- /dev/null +++ b/drivers/dsp/bridge/hw/GlobalTypes.h @@ -0,0 +1,325 @@ +/* + * GlobalTypes.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== GlobalTypes.h ======== + * Description: + * Global HW definitions + * + *! Revision History: + *! ================ + *! 16 Feb 2003 sb: Initial version + */ +#ifndef __GLOBALTYPES_H +#define __GLOBALTYPES_H + +/* + * Definition: TRUE, FALSE + * + * DESCRIPTION: Boolean Definitions + */ +#ifndef TRUE +#define FALSE 0 +#define TRUE (!(FALSE)) +#endif + +/* + * Definition: NULL + * + * DESCRIPTION: Invalid pointer + */ +#ifndef NULL +#define NULL (void *)0 +#endif + +/* + * Definition: RET_CODE_BASE + * + * DESCRIPTION: Base value for return code offsets + */ +#define RET_CODE_BASE 0 + +/* + * Definition: *BIT_OFFSET + * + * DESCRIPTION: offset in bytes from start of 32-bit word. + */ +#define LOWER_16BIT_OFFSET 0 +#define UPPER_16BIT_OFFSET 2 + +#define LOWER_8BIT_OFFSET 0 +#define LOWER_MIDDLE_8BIT_OFFSET 1 +#define UPPER_MIDDLE_8BIT_OFFSET 2 +#define UPPER_8BIT_OFFSET 3 + +#define LOWER_8BIT_OF16_OFFSET 0 +#define UPPER_8BIT_OF16_OFFSET 1 + +/* + * Definition: *BIT_SHIFT + * + * DESCRIPTION: offset in bits from start of 32-bit word. + */ +#define LOWER_16BIT_SHIFT 0 +#define UPPER_16BIT_SHIFT 16 + +#define LOWER_8BIT_SHIFT 0 +#define LOWER_MIDDLE_8BIT_SHIFT 8 +#define UPPER_MIDDLE_8BIT_SHIFT 16 +#define UPPER_8BIT_SHIFT 24 + +#define LOWER_8BIT_OF16_SHIFT 0 +#define UPPER_8BIT_OF16_SHIFT 8 + + +/* + * Definition: LOWER_16BIT_MASK + * + * DESCRIPTION: 16 bit mask used for inclusion of lower 16 bits i.e. mask out + * the upper 16 bits + */ +#define LOWER_16BIT_MASK 0x0000FFFF + + +/* + * Definition: LOWER_8BIT_MASK + * + * DESCRIPTION: 8 bit masks used for inclusion of 8 bits i.e. mask out + * the upper 16 bits + */ +#define LOWER_8BIT_MASK 0x000000FF + +/* + * Definition: RETURN_32BITS_FROM_16LOWER_AND_16UPPER(lower16Bits, upper16Bits) + * + * DESCRIPTION: Returns a 32 bit value given a 16 bit lower value and a 16 + * bit upper value + */ +#define RETURN_32BITS_FROM_16LOWER_AND_16UPPER(lower16Bits,upper16Bits)\ + (((((u32)lower16Bits) & LOWER_16BIT_MASK)) | \ + (((((u32)upper16Bits) & LOWER_16BIT_MASK) << UPPER_16BIT_SHIFT))) + +/* + * Definition: RETURN_16BITS_FROM_8LOWER_AND_8UPPER(lower16Bits, upper16Bits) + * + * DESCRIPTION: Returns a 16 bit value given a 8 bit lower value and a 8 + * bit upper value + */ +#define RETURN_16BITS_FROM_8LOWER_AND_8UPPER(lower8Bits,upper8Bits)\ + (((((u32)lower8Bits) & LOWER_8BIT_MASK)) | \ + (((((u32)upper8Bits) & LOWER_8BIT_MASK) << UPPER_8BIT_OF16_SHIFT))) + +/* + * Definition: RETURN_32BITS_FROM_4_8BIT_VALUES(lower8Bits, lowerMiddle8Bits, + * lowerUpper8Bits, upper8Bits) + * + * DESCRIPTION: Returns a 32 bit value given four 8 bit values + */ +#define RETURN_32BITS_FROM_4_8BIT_VALUES(lower8Bits, lowerMiddle8Bits,\ + lowerUpper8Bits, upper8Bits)\ + (((((u32)lower8Bits) & LOWER_8BIT_MASK)) | \ + (((((u32)lowerMiddle8Bits) & LOWER_8BIT_MASK) <<\ + LOWER_MIDDLE_8BIT_SHIFT)) | \ + (((((u32)lowerUpper8Bits) & LOWER_8BIT_MASK) <<\ + UPPER_MIDDLE_8BIT_SHIFT)) | \ + (((((u32)upper8Bits) & LOWER_8BIT_MASK) <<\ + UPPER_8BIT_SHIFT))) + +/* + * Definition: READ_LOWER_16BITS_OF_32(value32bits) + * + * DESCRIPTION: Returns a 16 lower bits of 32bit value + */ +#define READ_LOWER_16BITS_OF_32(value32bits)\ + ((u16)((u32)(value32bits) & LOWER_16BIT_MASK)) + +/* + * Definition: READ_UPPER_16BITS_OF_32(value32bits) + * + * DESCRIPTION: Returns a 16 lower bits of 32bit value + */ +#define READ_UPPER_16BITS_OF_32(value32bits)\ + (((u16)((u32)(value32bits) >> UPPER_16BIT_SHIFT)) &\ + LOWER_16BIT_MASK) + + +/* + * Definition: READ_LOWER_8BITS_OF_32(value32bits) + * + * DESCRIPTION: Returns a 8 lower bits of 32bit value + */ +#define READ_LOWER_8BITS_OF_32(value32bits)\ + ((u8)((u32)(value32bits) & LOWER_8BIT_MASK)) + +/* + * Definition: READ_LOWER_MIDDLE_8BITS_OF_32(value32bits) + * + * DESCRIPTION: Returns a 8 lower middle bits of 32bit value + */ +#define READ_LOWER_MIDDLE_8BITS_OF_32(value32bits)\ + (((u8)((u32)(value32bits) >> LOWER_MIDDLE_8BIT_SHIFT)) &\ + LOWER_8BIT_MASK) + +/* + * Definition: READ_LOWER_MIDDLE_8BITS_OF_32(value32bits) + * + * DESCRIPTION: Returns a 8 lower middle bits of 32bit value + */ +#define READ_UPPER_MIDDLE_8BITS_OF_32(value32bits)\ + (((u8)((u32)(value32bits) >> LOWER_MIDDLE_8BIT_SHIFT)) &\ + LOWER_8BIT_MASK) + +/* + * Definition: READ_UPPER_8BITS_OF_32(value32bits) + * + * DESCRIPTION: Returns a 8 upper bits of 32bit value + */ +#define READ_UPPER_8BITS_OF_32(value32bits)\ + (((u8)((u32)(value32bits) >> UPPER_8BIT_SHIFT)) & LOWER_8BIT_MASK) + + +/* + * Definition: READ_LOWER_8BITS_OF_16(value16bits) + * + * DESCRIPTION: Returns a 8 lower bits of 16bit value + */ +#define READ_LOWER_8BITS_OF_16(value16bits)\ + ((u8)((u16)(value16bits) & LOWER_8BIT_MASK)) + +/* + * Definition: READ_UPPER_8BITS_OF_16(value32bits) + * + * DESCRIPTION: Returns a 8 upper bits of 16bit value + */ +#define READ_UPPER_8BITS_OF_16(value16bits)\ + (((u8)((u32)(value16bits) >> UPPER_8BIT_SHIFT)) & LOWER_8BIT_MASK) + + + +/* UWORD16: 16 bit tpyes */ + + +/* REG_UWORD8, REG_WORD8: 8 bit register types */ +typedef volatile unsigned char REG_UWORD8; +typedef volatile signed char REG_WORD8; + +/* REG_UWORD16, REG_WORD16: 16 bit register types */ +#ifndef OMAPBRIDGE_TYPES +typedef volatile unsigned short REG_UWORD16; +#endif +typedef volatile short REG_WORD16; + +/* REG_UWORD32, REG_WORD32: 32 bit register types */ +typedef volatile unsigned long REG_UWORD32; + +/* FLOAT + * + * Type to be used for floating point calculation. Note that floating point + * calculation is very CPU expensive, and you should only use if you + * absolutely need this. */ + + +/* boolean_t: Boolean Type True, False */ +/* ReturnCode_t: Return codes to be returned by all library functions */ +typedef enum ReturnCode_label { + RET_OK = 0, + RET_FAIL = -1, + RET_BAD_NULL_PARAM = -2, + RET_PARAM_OUT_OF_RANGE = -3, + RET_INVALID_ID = -4, + RET_EMPTY = -5, + RET_FULL = -6, + RET_TIMEOUT = -7, + RET_INVALID_OPERATION = -8, + + /* Add new error codes at end of above list */ + + RET_NUM_RET_CODES /* this should ALWAYS be LAST entry */ +} ReturnCode_t, *pReturnCode_t; + +/* MACRO: RD_MEM_8, WR_MEM_8 + * + * DESCRIPTION: 32 bit memory access macros + */ +#define RD_MEM_8(addr) ((u8)(*((u8 *)(addr)))) +#define WR_MEM_8(addr, data) (*((u8 *)(addr)) = (u8)(data)) + +/* MACRO: RD_MEM_8_VOLATILE, WR_MEM_8_VOLATILE + * + * DESCRIPTION: 8 bit register access macros + */ +#define RD_MEM_8_VOLATILE(addr) ((u8)(*((REG_UWORD8 *)(addr)))) +#define WR_MEM_8_VOLATILE(addr, data) (*((REG_UWORD8 *)(addr)) = (u8)(data)) + + +/* + * MACRO: RD_MEM_16, WR_MEM_16 + * + * DESCRIPTION: 16 bit memory access macros + */ +#define RD_MEM_16(addr) ((u16)(*((u16 *)(addr)))) +#define WR_MEM_16(addr, data) (*((u16 *)(addr)) = (u16)(data)) + +/* + * MACRO: RD_MEM_16_VOLATILE, WR_MEM_16_VOLATILE + * + * DESCRIPTION: 16 bit register access macros + */ +#define RD_MEM_16_VOLATILE(addr) ((u16)(*((REG_UWORD16 *)(addr)))) +#define WR_MEM_16_VOLATILE(addr, data) (*((REG_UWORD16 *)(addr)) =\ + (u16)(data)) + +/* + * MACRO: RD_MEM_32, WR_MEM_32 + * + * DESCRIPTION: 32 bit memory access macros + */ +#define RD_MEM_32(addr) ((u32)(*((u32 *)(addr)))) +#define WR_MEM_32(addr, data) (*((u32 *)(addr)) = (u32)(data)) + +/* + * MACRO: RD_MEM_32_VOLATILE, WR_MEM_32_VOLATILE + * + * DESCRIPTION: 32 bit register access macros + */ +#define RD_MEM_32_VOLATILE(addr) ((u32)(*((REG_UWORD32 *)(addr)))) +#define WR_MEM_32_VOLATILE(addr, data) (*((REG_UWORD32 *)(addr)) =\ + (u32)(data)) + +/* Not sure if this all belongs here */ + +#define CHECK_RETURN_VALUE(actualValue, expectedValue, returnCodeIfMismatch,\ + spyCodeIfMisMatch) +#define CHECK_RETURN_VALUE_RET(actualValue, expectedValue, returnCodeIfMismatch) +#define CHECK_RETURN_VALUE_RES(actualValue, expectedValue, spyCodeIfMisMatch) +#define CHECK_RETURN_VALUE_RET_VOID(actualValue, expectedValue,\ + spyCodeIfMisMatch) + +#define CHECK_INPUT_PARAM(actualValue, invalidValue, returnCodeIfMismatch,\ + spyCodeIfMisMatch) +#define CHECK_INPUT_PARAM_NO_SPY(actualValue, invalidValue,\ + returnCodeIfMismatch) +#define CHECK_INPUT_RANGE(actualValue, minValidValue, maxValidValue,\ + returnCodeIfMismatch, spyCodeIfMisMatch) +#define CHECK_INPUT_RANGE_NO_SPY(actualValue, minValidValue, maxValidValue,\ + returnCodeIfMismatch) +#define CHECK_INPUT_RANGE_MIN0(actualValue, maxValidValue,\ + returnCodeIfMismatch, spyCodeIfMisMatch) +#define CHECK_INPUT_RANGE_NO_SPY_MIN0(actualValue, maxValidValue,\ + returnCodeIfMismatch) + +#endif /* __GLOBALTYPES_H */ diff --git a/drivers/dsp/bridge/hw/IPIAccInt.h b/drivers/dsp/bridge/hw/IPIAccInt.h new file mode 100644 index 0000000..b88a58c --- /dev/null +++ b/drivers/dsp/bridge/hw/IPIAccInt.h @@ -0,0 +1,41 @@ +/* + * IPIAccInt.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef _IPI_ACC_INT_H +#define _IPI_ACC_INT_H + +/* Bitfield mask and offset declarations */ +#define SYSC_IVA2BOOTMOD_OFFSET 0x404 +#define SYSC_IVA2BOOTADDR_OFFSET 0x400 +#define SYSC_IVA2BOOTADDR_MASK 0xfffffc00 + + +/* The following represent the enumerated values for each bitfield */ + +enum IPIIPI_SYSCONFIGAutoIdleE { + IPIIPI_SYSCONFIGAutoIdleclkfree = 0x0000, + IPIIPI_SYSCONFIGAutoIdleautoclkgate = 0x0001 +} ; + +enum IPIIPI_ENTRYElemSizeValueE { + IPIIPI_ENTRYElemSizeValueElemSz8b = 0x0000, + IPIIPI_ENTRYElemSizeValueElemSz16b = 0x0001, + IPIIPI_ENTRYElemSizeValueElemSz32b = 0x0002, + IPIIPI_ENTRYElemSizeValueReserved = 0x0003 +} ; + +#endif /* _IPI_ACC_INT_H */ +/* EOF */ diff --git a/drivers/dsp/bridge/hw/IVA2RegAcM.h b/drivers/dsp/bridge/hw/IVA2RegAcM.h new file mode 100644 index 0000000..6c1e300 --- /dev/null +++ b/drivers/dsp/bridge/hw/IVA2RegAcM.h @@ -0,0 +1,28 @@ +/* + * IVA1RegAcM.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + + +#ifndef _IVA2_REG_ACM_H +#define _IVA2_REG_ACM_H + +#include +#include + +#define SYSC_IVA2BOOTMOD_OFFSET 0x404 +#define SYSC_IVA2BOOTADDR_OFFSET 0x400 + +#endif diff --git a/drivers/dsp/bridge/hw/MLBAccInt.h b/drivers/dsp/bridge/hw/MLBAccInt.h new file mode 100644 index 0000000..7a03c6a --- /dev/null +++ b/drivers/dsp/bridge/hw/MLBAccInt.h @@ -0,0 +1,132 @@ +/* + * MLBAccInt.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +#ifndef _MLB_ACC_INT_H +#define _MLB_ACC_INT_H + +/* Mappings of level 1 EASI function numbers to function names */ + +#define EASIL1_MLBMAILBOX_SYSCONFIGReadRegister32 (MLB_BASE_EASIL1 + 3) +#define EASIL1_MLBMAILBOX_SYSCONFIGWriteRegister32 (MLB_BASE_EASIL1 + 4) +#define EASIL1_MLBMAILBOX_SYSCONFIGSIdleModeRead32 (MLB_BASE_EASIL1 + 7) +#define EASIL1_MLBMAILBOX_SYSCONFIGSIdleModeWrite32 (MLB_BASE_EASIL1 + 17) +#define EASIL1_MLBMAILBOX_SYSCONFIGSoftResetWrite32 (MLB_BASE_EASIL1 + 29) +#define EASIL1_MLBMAILBOX_SYSCONFIGAutoIdleRead32 \ + (MLB_BASE_EASIL1 + 33) +#define EASIL1_MLBMAILBOX_SYSCONFIGAutoIdleWrite32 (MLB_BASE_EASIL1 + 39) +#define EASIL1_MLBMAILBOX_SYSSTATUSResetDoneRead32 (MLB_BASE_EASIL1 + 44) +#define EASIL1_MLBMAILBOX_MESSAGE___0_15ReadRegister32 \ + (MLB_BASE_EASIL1 + 50) +#define EASIL1_MLBMAILBOX_MESSAGE___0_15WriteRegister32 \ + (MLB_BASE_EASIL1 + 51) +#define EASIL1_MLBMAILBOX_FIFOSTATUS___0_15ReadRegister32 \ + (MLB_BASE_EASIL1 + 56) +#define EASIL1_MLBMAILBOX_FIFOSTATUS___0_15FifoFullMBmRead32 \ + (MLB_BASE_EASIL1 + 57) +#define EASIL1_MLBMAILBOX_MSGSTATUS___0_15NbOfMsgMBmRead32 \ + (MLB_BASE_EASIL1 + 60) +#define EASIL1_MLBMAILBOX_IRQSTATUS___0_3ReadRegister32 \ + (MLB_BASE_EASIL1 + 62) +#define EASIL1_MLBMAILBOX_IRQSTATUS___0_3WriteRegister32 \ + (MLB_BASE_EASIL1 + 63) +#define EASIL1_MLBMAILBOX_IRQENABLE___0_3ReadRegister32 \ + (MLB_BASE_EASIL1 + 192) +#define EASIL1_MLBMAILBOX_IRQENABLE___0_3WriteRegister32 \ + (MLB_BASE_EASIL1 + 193) + +/* Register set MAILBOX_MESSAGE___REGSET_0_15 address offset, bank address + * increment and number of banks */ + +#define MLB_MAILBOX_MESSAGE___REGSET_0_15_OFFSET (u32)(0x0040) +#define MLB_MAILBOX_MESSAGE___REGSET_0_15_STEP (u32)(0x0004) + +/* Register offset address definitions relative to register set + * MAILBOX_MESSAGE___REGSET_0_15 */ + +#define MLB_MAILBOX_MESSAGE___0_15_OFFSET (u32)(0x0) + + +/* Register set MAILBOX_FIFOSTATUS___REGSET_0_15 address offset, bank address + * increment and number of banks */ + +#define MLB_MAILBOX_FIFOSTATUS___REGSET_0_15_OFFSET (u32)(0x0080) +#define MLB_MAILBOX_FIFOSTATUS___REGSET_0_15_STEP (u32)(0x0004) + +/* Register offset address definitions relative to register set + * MAILBOX_FIFOSTATUS___REGSET_0_15 */ + +#define MLB_MAILBOX_FIFOSTATUS___0_15_OFFSET (u32)(0x0) + + +/* Register set MAILBOX_MSGSTATUS___REGSET_0_15 address offset, bank address + * increment and number of banks */ + +#define MLB_MAILBOX_MSGSTATUS___REGSET_0_15_OFFSET (u32)(0x00c0) +#define MLB_MAILBOX_MSGSTATUS___REGSET_0_15_STEP (u32)(0x0004) + +/* Register offset address definitions relative to register set + * MAILBOX_MSGSTATUS___REGSET_0_15 */ + +#define MLB_MAILBOX_MSGSTATUS___0_15_OFFSET (u32)(0x0) + + +/* Register set MAILBOX_IRQSTATUS___REGSET_0_3 address offset, bank address + * increment and number of banks */ + +#define MLB_MAILBOX_IRQSTATUS___REGSET_0_3_OFFSET (u32)(0x0100) +#define MLB_MAILBOX_IRQSTATUS___REGSET_0_3_STEP (u32)(0x0008) + +/* Register offset address definitions relative to register set + * MAILBOX_IRQSTATUS___REGSET_0_3 */ + +#define MLB_MAILBOX_IRQSTATUS___0_3_OFFSET (u32)(0x0) + + +/* Register set MAILBOX_IRQENABLE___REGSET_0_3 address offset, bank address + * increment and number of banks */ + +#define MLB_MAILBOX_IRQENABLE___REGSET_0_3_OFFSET (u32)(0x0104) +#define MLB_MAILBOX_IRQENABLE___REGSET_0_3_STEP (u32)(0x0008) + +/* Register offset address definitions relative to register set + * MAILBOX_IRQENABLE___REGSET_0_3 */ + +#define MLB_MAILBOX_IRQENABLE___0_3_OFFSET (u32)(0x0) + + +/* Register offset address definitions */ + +#define MLB_MAILBOX_SYSCONFIG_OFFSET (u32)(0x10) +#define MLB_MAILBOX_SYSSTATUS_OFFSET (u32)(0x14) + + +/* Bitfield mask and offset declarations */ + +#define MLB_MAILBOX_SYSCONFIG_SIdleMode_MASK (u32)(0x18) +#define MLB_MAILBOX_SYSCONFIG_SIdleMode_OFFSET (u32)(3) +#define MLB_MAILBOX_SYSCONFIG_SoftReset_MASK (u32)(0x2) +#define MLB_MAILBOX_SYSCONFIG_SoftReset_OFFSET (u32)(1) +#define MLB_MAILBOX_SYSCONFIG_AutoIdle_MASK (u32)(0x1) +#define MLB_MAILBOX_SYSCONFIG_AutoIdle_OFFSET (u32)(0) +#define MLB_MAILBOX_SYSSTATUS_ResetDone_MASK (u32)(0x1) +#define MLB_MAILBOX_SYSSTATUS_ResetDone_OFFSET (u32)(0) +#define MLB_MAILBOX_FIFOSTATUS___0_15_FifoFullMBm_MASK (u32)(0x1) +#define MLB_MAILBOX_FIFOSTATUS___0_15_FifoFullMBm_OFFSET (u32)(0) +#define MLB_MAILBOX_MSGSTATUS___0_15_NbOfMsgMBm_MASK (u32)(0x7f) +#define MLB_MAILBOX_MSGSTATUS___0_15_NbOfMsgMBm_OFFSET (u32)(0) + +#endif /* _MLB_ACC_INT_H */ diff --git a/drivers/dsp/bridge/hw/MLBRegAcM.h b/drivers/dsp/bridge/hw/MLBRegAcM.h new file mode 100644 index 0000000..747a2e1 --- /dev/null +++ b/drivers/dsp/bridge/hw/MLBRegAcM.h @@ -0,0 +1,200 @@ +/* + * MLBRegAcM.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef _MLB_REG_ACM_H +#define _MLB_REG_ACM_H + +#include +#include +#include "MLBAccInt.h" + +#if defined(USE_LEVEL_1_MACROS) + +#define MLBMAILBOX_SYSCONFIGReadRegister32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MLBMAILBOX_SYSCONFIGReadRegister32),\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+ \ + MLB_MAILBOX_SYSCONFIG_OFFSET)) + + +#define MLBMAILBOX_SYSCONFIGWriteRegister32(baseAddress, value)\ +{\ + const u32 offset = MLB_MAILBOX_SYSCONFIG_OFFSET;\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_MLBMAILBOX_SYSCONFIGWriteRegister32);\ + WR_MEM_32_VOLATILE(((u32)(baseAddress))+offset, newValue);\ +} + + +#define MLBMAILBOX_SYSCONFIGSIdleModeRead32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MLBMAILBOX_SYSCONFIGSIdleModeRead32),\ + (((RD_MEM_32_VOLATILE((((u32)(baseAddress))+\ + (MLB_MAILBOX_SYSCONFIG_OFFSET)))) &\ + MLB_MAILBOX_SYSCONFIG_SIdleMode_MASK) >>\ + MLB_MAILBOX_SYSCONFIG_SIdleMode_OFFSET)) + + +#define MLBMAILBOX_SYSCONFIGSIdleModeWrite32(baseAddress, value)\ +{\ + const u32 offset = MLB_MAILBOX_SYSCONFIG_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE(((u32)(baseAddress)) +\ + offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_MLBMAILBOX_SYSCONFIGSIdleModeWrite32);\ + data &= ~(MLB_MAILBOX_SYSCONFIG_SIdleMode_MASK);\ + newValue <<= MLB_MAILBOX_SYSCONFIG_SIdleMode_OFFSET;\ + newValue &= MLB_MAILBOX_SYSCONFIG_SIdleMode_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define MLBMAILBOX_SYSCONFIGSoftResetWrite32(baseAddress, value)\ +{\ + const u32 offset = MLB_MAILBOX_SYSCONFIG_OFFSET;\ + register u32 data =\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_MLBMAILBOX_SYSCONFIGSoftResetWrite32);\ + data &= ~(MLB_MAILBOX_SYSCONFIG_SoftReset_MASK);\ + newValue <<= MLB_MAILBOX_SYSCONFIG_SoftReset_OFFSET;\ + newValue &= MLB_MAILBOX_SYSCONFIG_SoftReset_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define MLBMAILBOX_SYSCONFIGAutoIdleRead32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MLBMAILBOX_SYSCONFIGAutoIdleRead32),\ + (((RD_MEM_32_VOLATILE((((u32)(baseAddress))+\ + (MLB_MAILBOX_SYSCONFIG_OFFSET)))) &\ + MLB_MAILBOX_SYSCONFIG_AutoIdle_MASK) >>\ + MLB_MAILBOX_SYSCONFIG_AutoIdle_OFFSET)) + + +#define MLBMAILBOX_SYSCONFIGAutoIdleWrite32(baseAddress, value)\ +{\ + const u32 offset = MLB_MAILBOX_SYSCONFIG_OFFSET;\ + register u32 data =\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_MLBMAILBOX_SYSCONFIGAutoIdleWrite32);\ + data &= ~(MLB_MAILBOX_SYSCONFIG_AutoIdle_MASK);\ + newValue <<= MLB_MAILBOX_SYSCONFIG_AutoIdle_OFFSET;\ + newValue &= MLB_MAILBOX_SYSCONFIG_AutoIdle_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define MLBMAILBOX_SYSSTATUSResetDoneRead32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MLBMAILBOX_SYSSTATUSResetDoneRead32),\ + (((RD_MEM_32_VOLATILE((((u32)(baseAddress))+\ + (MLB_MAILBOX_SYSSTATUS_OFFSET)))) &\ + MLB_MAILBOX_SYSSTATUS_ResetDone_MASK) >>\ + MLB_MAILBOX_SYSSTATUS_ResetDone_OFFSET)) + + +#define MLBMAILBOX_MESSAGE___0_15ReadRegister32(baseAddress, bank)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MLBMAILBOX_MESSAGE___0_15ReadRegister32),\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+\ + (MLB_MAILBOX_MESSAGE___REGSET_0_15_OFFSET +\ + MLB_MAILBOX_MESSAGE___0_15_OFFSET+(\ + (bank)*MLB_MAILBOX_MESSAGE___REGSET_0_15_STEP)))) + + +#define MLBMAILBOX_MESSAGE___0_15WriteRegister32(baseAddress, bank, value)\ +{\ + const u32 offset = MLB_MAILBOX_MESSAGE___REGSET_0_15_OFFSET +\ + MLB_MAILBOX_MESSAGE___0_15_OFFSET +\ + ((bank)*MLB_MAILBOX_MESSAGE___REGSET_0_15_STEP);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_MLBMAILBOX_MESSAGE___0_15WriteRegister32);\ + WR_MEM_32_VOLATILE(((u32)(baseAddress))+offset, newValue);\ +} + + +#define MLBMAILBOX_FIFOSTATUS___0_15ReadRegister32(baseAddress, bank)\ + (_DEBUG_LEVEL_1_EASI(\ + EASIL1_MLBMAILBOX_FIFOSTATUS___0_15ReadRegister32),\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+\ + (MLB_MAILBOX_FIFOSTATUS___REGSET_0_15_OFFSET +\ + MLB_MAILBOX_FIFOSTATUS___0_15_OFFSET+\ + ((bank)*MLB_MAILBOX_FIFOSTATUS___REGSET_0_15_STEP)))) + + +#define MLBMAILBOX_FIFOSTATUS___0_15FifoFullMBmRead32(baseAddress, bank)\ + (_DEBUG_LEVEL_1_EASI(\ + EASIL1_MLBMAILBOX_FIFOSTATUS___0_15FifoFullMBmRead32),\ + (((RD_MEM_32_VOLATILE(((u32)(baseAddress))+\ + (MLB_MAILBOX_FIFOSTATUS___REGSET_0_15_OFFSET +\ + MLB_MAILBOX_FIFOSTATUS___0_15_OFFSET+\ + ((bank)*MLB_MAILBOX_FIFOSTATUS___REGSET_0_15_STEP)))) &\ + MLB_MAILBOX_FIFOSTATUS___0_15_FifoFullMBm_MASK) >>\ + MLB_MAILBOX_FIFOSTATUS___0_15_FifoFullMBm_OFFSET)) + + +#define MLBMAILBOX_MSGSTATUS___0_15NbOfMsgMBmRead32(baseAddress, bank)\ + (_DEBUG_LEVEL_1_EASI(\ + EASIL1_MLBMAILBOX_MSGSTATUS___0_15NbOfMsgMBmRead32),\ + (((RD_MEM_32_VOLATILE(((u32)(baseAddress))+\ + (MLB_MAILBOX_MSGSTATUS___REGSET_0_15_OFFSET +\ + MLB_MAILBOX_MSGSTATUS___0_15_OFFSET+\ + ((bank)*MLB_MAILBOX_MSGSTATUS___REGSET_0_15_STEP)))) &\ + MLB_MAILBOX_MSGSTATUS___0_15_NbOfMsgMBm_MASK) >>\ + MLB_MAILBOX_MSGSTATUS___0_15_NbOfMsgMBm_OFFSET)) + + +#define MLBMAILBOX_IRQSTATUS___0_3ReadRegister32(baseAddress, bank)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MLBMAILBOX_IRQSTATUS___0_3ReadRegister32),\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+\ + (MLB_MAILBOX_IRQSTATUS___REGSET_0_3_OFFSET +\ + MLB_MAILBOX_IRQSTATUS___0_3_OFFSET+\ + ((bank)*MLB_MAILBOX_IRQSTATUS___REGSET_0_3_STEP)))) + + +#define MLBMAILBOX_IRQSTATUS___0_3WriteRegister32(baseAddress, bank, value)\ +{\ + const u32 offset = MLB_MAILBOX_IRQSTATUS___REGSET_0_3_OFFSET +\ + MLB_MAILBOX_IRQSTATUS___0_3_OFFSET +\ + ((bank)*MLB_MAILBOX_IRQSTATUS___REGSET_0_3_STEP);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_MLBMAILBOX_IRQSTATUS___0_3WriteRegister32);\ + WR_MEM_32_VOLATILE(((u32)(baseAddress))+offset, newValue);\ +} + + +#define MLBMAILBOX_IRQENABLE___0_3ReadRegister32(baseAddress, bank)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MLBMAILBOX_IRQENABLE___0_3ReadRegister32),\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+\ + (MLB_MAILBOX_IRQENABLE___REGSET_0_3_OFFSET +\ + MLB_MAILBOX_IRQENABLE___0_3_OFFSET+\ + ((bank)*MLB_MAILBOX_IRQENABLE___REGSET_0_3_STEP)))) + + +#define MLBMAILBOX_IRQENABLE___0_3WriteRegister32(baseAddress, bank, value)\ +{\ + const u32 offset = MLB_MAILBOX_IRQENABLE___REGSET_0_3_OFFSET +\ + MLB_MAILBOX_IRQENABLE___0_3_OFFSET +\ + ((bank)*MLB_MAILBOX_IRQENABLE___REGSET_0_3_STEP);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_MLBMAILBOX_IRQENABLE___0_3WriteRegister32);\ + WR_MEM_32_VOLATILE(((u32)(baseAddress))+offset, newValue);\ +} + + +#endif /* USE_LEVEL_1_MACROS */ + +#endif /* _MLB_REG_ACM_H */ diff --git a/drivers/dsp/bridge/hw/MMUAccInt.h b/drivers/dsp/bridge/hw/MMUAccInt.h new file mode 100644 index 0000000..6ca1573 --- /dev/null +++ b/drivers/dsp/bridge/hw/MMUAccInt.h @@ -0,0 +1,76 @@ +/* + * MMUAccInt.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef _MMU_ACC_INT_H +#define _MMU_ACC_INT_H + +/* Mappings of level 1 EASI function numbers to function names */ + +#define EASIL1_MMUMMU_SYSCONFIGReadRegister32 (MMU_BASE_EASIL1 + 3) +#define EASIL1_MMUMMU_SYSCONFIGIdleModeWrite32 (MMU_BASE_EASIL1 + 17) +#define EASIL1_MMUMMU_SYSCONFIGAutoIdleWrite32 (MMU_BASE_EASIL1 + 39) +#define EASIL1_MMUMMU_IRQSTATUSWriteRegister32 (MMU_BASE_EASIL1 + 51) +#define EASIL1_MMUMMU_IRQENABLEReadRegister32 (MMU_BASE_EASIL1 + 102) +#define EASIL1_MMUMMU_IRQENABLEWriteRegister32 (MMU_BASE_EASIL1 + 103) +#define EASIL1_MMUMMU_WALKING_STTWLRunningRead32 (MMU_BASE_EASIL1 + 156) +#define EASIL1_MMUMMU_CNTLTWLEnableRead32 (MMU_BASE_EASIL1 + 174) +#define EASIL1_MMUMMU_CNTLTWLEnableWrite32 (MMU_BASE_EASIL1 + 180) +#define EASIL1_MMUMMU_CNTLMMUEnableWrite32 (MMU_BASE_EASIL1 + 190) +#define EASIL1_MMUMMU_FAULT_ADReadRegister32 (MMU_BASE_EASIL1 + 194) +#define EASIL1_MMUMMU_TTBWriteRegister32 (MMU_BASE_EASIL1 + 198) +#define EASIL1_MMUMMU_LOCKReadRegister32 (MMU_BASE_EASIL1 + 203) +#define EASIL1_MMUMMU_LOCKWriteRegister32 (MMU_BASE_EASIL1 + 204) +#define EASIL1_MMUMMU_LOCKBaseValueRead32 (MMU_BASE_EASIL1 + 205) +#define EASIL1_MMUMMU_LOCKCurrentVictimRead32 (MMU_BASE_EASIL1 + 209) +#define EASIL1_MMUMMU_LOCKCurrentVictimWrite32 (MMU_BASE_EASIL1 + 211) +#define EASIL1_MMUMMU_LOCKCurrentVictimSet32 (MMU_BASE_EASIL1 + 212) +#define EASIL1_MMUMMU_LD_TLBReadRegister32 (MMU_BASE_EASIL1 + 213) +#define EASIL1_MMUMMU_LD_TLBWriteRegister32 (MMU_BASE_EASIL1 + 214) +#define EASIL1_MMUMMU_CAMWriteRegister32 (MMU_BASE_EASIL1 + 226) +#define EASIL1_MMUMMU_RAMWriteRegister32 (MMU_BASE_EASIL1 + 268) +#define EASIL1_MMUMMU_FLUSH_ENTRYWriteRegister32 (MMU_BASE_EASIL1 + 322) + +/* Register offset address definitions */ +#define MMU_MMU_SYSCONFIG_OFFSET 0x10 +#define MMU_MMU_IRQSTATUS_OFFSET 0x18 +#define MMU_MMU_IRQENABLE_OFFSET 0x1c +#define MMU_MMU_WALKING_ST_OFFSET 0x40 +#define MMU_MMU_CNTL_OFFSET 0x44 +#define MMU_MMU_FAULT_AD_OFFSET 0x48 +#define MMU_MMU_TTB_OFFSET 0x4c +#define MMU_MMU_LOCK_OFFSET 0x50 +#define MMU_MMU_LD_TLB_OFFSET 0x54 +#define MMU_MMU_CAM_OFFSET 0x58 +#define MMU_MMU_RAM_OFFSET 0x5c +#define MMU_MMU_GFLUSH_OFFSET 0x60 +#define MMU_MMU_FLUSH_ENTRY_OFFSET 0x64 +/* Bitfield mask and offset declarations */ +#define MMU_MMU_SYSCONFIG_IdleMode_MASK 0x18 +#define MMU_MMU_SYSCONFIG_IdleMode_OFFSET 3 +#define MMU_MMU_SYSCONFIG_AutoIdle_MASK 0x1 +#define MMU_MMU_SYSCONFIG_AutoIdle_OFFSET 0 +#define MMU_MMU_WALKING_ST_TWLRunning_MASK 0x1 +#define MMU_MMU_WALKING_ST_TWLRunning_OFFSET 0 +#define MMU_MMU_CNTL_TWLEnable_MASK 0x4 +#define MMU_MMU_CNTL_TWLEnable_OFFSET 2 +#define MMU_MMU_CNTL_MMUEnable_MASK 0x2 +#define MMU_MMU_CNTL_MMUEnable_OFFSET 1 +#define MMU_MMU_LOCK_BaseValue_MASK 0xfc00 +#define MMU_MMU_LOCK_BaseValue_OFFSET 10 +#define MMU_MMU_LOCK_CurrentVictim_MASK 0x3f0 +#define MMU_MMU_LOCK_CurrentVictim_OFFSET 4 + +#endif /* _MMU_ACC_INT_H */ diff --git a/drivers/dsp/bridge/hw/MMURegAcM.h b/drivers/dsp/bridge/hw/MMURegAcM.h new file mode 100644 index 0000000..e46fdcb --- /dev/null +++ b/drivers/dsp/bridge/hw/MMURegAcM.h @@ -0,0 +1,253 @@ +/* + * MMURegAcM.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +#ifndef _MMU_REG_ACM_H +#define _MMU_REG_ACM_H + +#include + +#include + +#include "MMUAccInt.h" + +#if defined(USE_LEVEL_1_MACROS) + + +#define MMUMMU_SYSCONFIGReadRegister32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_SYSCONFIGReadRegister32),\ + RD_MEM_32_VOLATILE((baseAddress)+MMU_MMU_SYSCONFIG_OFFSET)) + + +#define MMUMMU_SYSCONFIGIdleModeWrite32(baseAddress, value)\ +{\ + const u32 offset = MMU_MMU_SYSCONFIG_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((baseAddress)+offset);\ + register u32 newValue = (value);\ + _DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_SYSCONFIGIdleModeWrite32);\ + data &= ~(MMU_MMU_SYSCONFIG_IdleMode_MASK);\ + newValue <<= MMU_MMU_SYSCONFIG_IdleMode_OFFSET;\ + newValue &= MMU_MMU_SYSCONFIG_IdleMode_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE(baseAddress+offset, newValue);\ +} + + +#define MMUMMU_SYSCONFIGAutoIdleWrite32(baseAddress, value)\ +{\ + const u32 offset = MMU_MMU_SYSCONFIG_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((baseAddress)+offset);\ + register u32 newValue = (value);\ + _DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_SYSCONFIGAutoIdleWrite32);\ + data &= ~(MMU_MMU_SYSCONFIG_AutoIdle_MASK);\ + newValue <<= MMU_MMU_SYSCONFIG_AutoIdle_OFFSET;\ + newValue &= MMU_MMU_SYSCONFIG_AutoIdle_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE(baseAddress+offset, newValue);\ +} + + +#define MMUMMU_IRQSTATUSReadRegister32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_IRQSTATUSReadRegister32),\ + RD_MEM_32_VOLATILE((baseAddress)+MMU_MMU_IRQSTATUS_OFFSET)) + + +#define MMUMMU_IRQSTATUSWriteRegister32(baseAddress, value)\ +{\ + const u32 offset = MMU_MMU_IRQSTATUS_OFFSET;\ + register u32 newValue = (value);\ + _DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_IRQSTATUSWriteRegister32);\ + WR_MEM_32_VOLATILE((baseAddress)+offset, newValue);\ +} + + +#define MMUMMU_IRQENABLEReadRegister32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_IRQENABLEReadRegister32),\ + RD_MEM_32_VOLATILE((baseAddress)+MMU_MMU_IRQENABLE_OFFSET)) + + +#define MMUMMU_IRQENABLEWriteRegister32(baseAddress, value)\ +{\ + const u32 offset = MMU_MMU_IRQENABLE_OFFSET;\ + register u32 newValue = (value);\ + _DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_IRQENABLEWriteRegister32);\ + WR_MEM_32_VOLATILE((baseAddress)+offset, newValue);\ +} + + +#define MMUMMU_WALKING_STTWLRunningRead32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_WALKING_STTWLRunningRead32),\ + (((RD_MEM_32_VOLATILE(((baseAddress)+(MMU_MMU_WALKING_ST_OFFSET))))\ + & MMU_MMU_WALKING_ST_TWLRunning_MASK) >>\ + MMU_MMU_WALKING_ST_TWLRunning_OFFSET)) + + +#define MMUMMU_CNTLTWLEnableRead32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_CNTLTWLEnableRead32),\ + (((RD_MEM_32_VOLATILE(((baseAddress)+(MMU_MMU_CNTL_OFFSET)))) &\ + MMU_MMU_CNTL_TWLEnable_MASK) >>\ + MMU_MMU_CNTL_TWLEnable_OFFSET)) + + +#define MMUMMU_CNTLTWLEnableWrite32(baseAddress, value)\ +{\ + const u32 offset = MMU_MMU_CNTL_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((baseAddress)+offset);\ + register u32 newValue = (value);\ + _DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_CNTLTWLEnableWrite32);\ + data &= ~(MMU_MMU_CNTL_TWLEnable_MASK);\ + newValue <<= MMU_MMU_CNTL_TWLEnable_OFFSET;\ + newValue &= MMU_MMU_CNTL_TWLEnable_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE(baseAddress+offset, newValue);\ +} + + +#define MMUMMU_CNTLMMUEnableWrite32(baseAddress, value)\ +{\ + const u32 offset = MMU_MMU_CNTL_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((baseAddress)+offset);\ + register u32 newValue = (value);\ + _DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_CNTLMMUEnableWrite32);\ + data &= ~(MMU_MMU_CNTL_MMUEnable_MASK);\ + newValue <<= MMU_MMU_CNTL_MMUEnable_OFFSET;\ + newValue &= MMU_MMU_CNTL_MMUEnable_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE(baseAddress+offset, newValue);\ +} + + +#define MMUMMU_FAULT_ADReadRegister32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_FAULT_ADReadRegister32),\ + RD_MEM_32_VOLATILE((baseAddress)+MMU_MMU_FAULT_AD_OFFSET)) + + +#define MMUMMU_TTBWriteRegister32(baseAddress, value)\ +{\ + const u32 offset = MMU_MMU_TTB_OFFSET;\ + register u32 newValue = (value);\ + _DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_TTBWriteRegister32);\ + WR_MEM_32_VOLATILE((baseAddress)+offset, newValue);\ +} + + +#define MMUMMU_LOCKReadRegister32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_LOCKReadRegister32),\ + RD_MEM_32_VOLATILE((baseAddress)+MMU_MMU_LOCK_OFFSET)) + + +#define MMUMMU_LOCKWriteRegister32(baseAddress, value)\ +{\ + const u32 offset = MMU_MMU_LOCK_OFFSET;\ + register u32 newValue = (value);\ + _DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_LOCKWriteRegister32);\ + WR_MEM_32_VOLATILE((baseAddress)+offset, newValue);\ +} + + +#define MMUMMU_LOCKBaseValueRead32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_LOCKBaseValueRead32),\ + (((RD_MEM_32_VOLATILE(((baseAddress)+(MMU_MMU_LOCK_OFFSET)))) &\ + MMU_MMU_LOCK_BaseValue_MASK) >>\ + MMU_MMU_LOCK_BaseValue_OFFSET)) + + +#define MMUMMU_LOCKBaseValueWrite32(baseAddress, value)\ +{\ + const u32 offset = MMU_MMU_LOCK_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((baseAddress)+offset);\ + register u32 newValue = (value);\ + _DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_LOCKBaseValueWrite32);\ + data &= ~(MMU_MMU_LOCK_BaseValue_MASK);\ + newValue <<= MMU_MMU_LOCK_BaseValue_OFFSET;\ + newValue &= MMU_MMU_LOCK_BaseValue_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE(baseAddress+offset, newValue);\ +} + + +#define MMUMMU_LOCKCurrentVictimRead32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_LOCKCurrentVictimRead32),\ + (((RD_MEM_32_VOLATILE(((baseAddress)+(MMU_MMU_LOCK_OFFSET)))) &\ + MMU_MMU_LOCK_CurrentVictim_MASK) >>\ + MMU_MMU_LOCK_CurrentVictim_OFFSET)) + + +#define MMUMMU_LOCKCurrentVictimWrite32(baseAddress, value)\ +{\ + const u32 offset = MMU_MMU_LOCK_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((baseAddress)+offset);\ + register u32 newValue = (value);\ + _DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_LOCKCurrentVictimWrite32);\ + data &= ~(MMU_MMU_LOCK_CurrentVictim_MASK);\ + newValue <<= MMU_MMU_LOCK_CurrentVictim_OFFSET;\ + newValue &= MMU_MMU_LOCK_CurrentVictim_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE(baseAddress+offset, newValue);\ +} + + +#define MMUMMU_LOCKCurrentVictimSet32(var, value)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_LOCKCurrentVictimSet32),\ + (((var) & ~(MMU_MMU_LOCK_CurrentVictim_MASK)) |\ + (((value) << MMU_MMU_LOCK_CurrentVictim_OFFSET) &\ + MMU_MMU_LOCK_CurrentVictim_MASK))) + + +#define MMUMMU_LD_TLBReadRegister32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_LD_TLBReadRegister32),\ + RD_MEM_32_VOLATILE((baseAddress)+MMU_MMU_LD_TLB_OFFSET)) + + +#define MMUMMU_LD_TLBWriteRegister32(baseAddress, value)\ +{\ + const u32 offset = MMU_MMU_LD_TLB_OFFSET;\ + register u32 newValue = (value);\ + _DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_LD_TLBWriteRegister32);\ + WR_MEM_32_VOLATILE((baseAddress)+offset, newValue);\ +} + + +#define MMUMMU_CAMWriteRegister32(baseAddress, value)\ +{\ + const u32 offset = MMU_MMU_CAM_OFFSET;\ + register u32 newValue = (value);\ + _DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_CAMWriteRegister32);\ + WR_MEM_32_VOLATILE((baseAddress)+offset, newValue);\ +} + + +#define MMUMMU_RAMWriteRegister32(baseAddress, value)\ +{\ + const u32 offset = MMU_MMU_RAM_OFFSET;\ + register u32 newValue = (value);\ + _DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_RAMWriteRegister32);\ + WR_MEM_32_VOLATILE((baseAddress)+offset, newValue);\ +} + + +#define MMUMMU_FLUSH_ENTRYWriteRegister32(baseAddress, value)\ +{\ + const u32 offset = MMU_MMU_FLUSH_ENTRY_OFFSET;\ + register u32 newValue = (value);\ + _DEBUG_LEVEL_1_EASI(EASIL1_MMUMMU_FLUSH_ENTRYWriteRegister32);\ + WR_MEM_32_VOLATILE((baseAddress)+offset, newValue);\ +} + + +#endif /* USE_LEVEL_1_MACROS */ + +#endif /* _MMU_REG_ACM_H */ diff --git a/drivers/dsp/bridge/hw/PRCMAccInt.h b/drivers/dsp/bridge/hw/PRCMAccInt.h new file mode 100644 index 0000000..42baa68 --- /dev/null +++ b/drivers/dsp/bridge/hw/PRCMAccInt.h @@ -0,0 +1,300 @@ +/* + * PRCMAccInt.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef _PRCM_ACC_INT_H +#define _PRCM_ACC_INT_H + +/* Mappings of level 1 EASI function numbers to function names */ + +#define EASIL1_PRCMPRCM_CLKCFG_CTRLValid_configWriteClk_valid32 \ + (PRCM_BASE_EASIL1 + 349) +#define EASIL1_PRCMCM_FCLKEN1_COREReadRegister32 (PRCM_BASE_EASIL1 + 743) +#define EASIL1_PRCMCM_FCLKEN1_COREEN_GPT8Write32 (PRCM_BASE_EASIL1 + 951) +#define EASIL1_PRCMCM_FCLKEN1_COREEN_GPT7Write32 (PRCM_BASE_EASIL1 + 961) +#define EASIL1_PRCMCM_ICLKEN1_COREReadRegister32 \ + (PRCM_BASE_EASIL1 + 1087) +#define EASIL1_PRCMCM_ICLKEN1_COREEN_MAILBOXESWrite32 \ + (PRCM_BASE_EASIL1 + 1105) +#define EASIL1_PRCMCM_ICLKEN1_COREEN_GPT8Write32 \ + (PRCM_BASE_EASIL1 + 1305) +#define EASIL1_PRCMCM_ICLKEN1_COREEN_GPT7Write32 \ + (PRCM_BASE_EASIL1 + 1315) +#define EASIL1_PRCMCM_CLKSEL1_CORECLKSEL_L3ReadIssel132 \ + (PRCM_BASE_EASIL1 + 2261) +#define EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT8Write32k32 \ + (PRCM_BASE_EASIL1 + 2364) +#define EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT8WriteSys32 \ + (PRCM_BASE_EASIL1 + 2365) +#define EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT8WriteExt32 \ + (PRCM_BASE_EASIL1 + 2366) +#define EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT7Write32k32 \ + (PRCM_BASE_EASIL1 + 2380) +#define EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT7WriteSys32 \ + (PRCM_BASE_EASIL1 + 2381) +#define EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT7WriteExt32 \ + (PRCM_BASE_EASIL1 + 2382) +#define EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT6WriteSys32 \ + (PRCM_BASE_EASIL1 + 2397) +#define EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT6WriteExt32 \ + (PRCM_BASE_EASIL1 + 2398) +#define EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT5WriteSys32 \ + (PRCM_BASE_EASIL1 + 2413) +#define EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT5WriteExt32 \ + (PRCM_BASE_EASIL1 + 2414) +#define EASIL1_PRCMCM_CLKSEL1_PLLAPLLs_ClkinRead32 \ + (PRCM_BASE_EASIL1 + 3747) +#define EASIL1_PRCMCM_FCLKEN_DSPEN_DSPWrite32 (PRCM_BASE_EASIL1 + 3834) +#define EASIL1_PRCMCM_ICLKEN_DSPEN_DSP_IPIWrite32 \ + (PRCM_BASE_EASIL1 + 3846) +#define EASIL1_PRCMCM_IDLEST_DSPReadRegister32 (PRCM_BASE_EASIL1 + 3850) +#define EASIL1_PRCMCM_IDLEST_DSPST_IPIRead32 (PRCM_BASE_EASIL1 + 3857) +#define EASIL1_PRCMCM_IDLEST_DSPST_DSPRead32 (PRCM_BASE_EASIL1 + 3863) +#define EASIL1_PRCMCM_AUTOIDLE_DSPAUTO_DSP_IPIWrite32 \ + (PRCM_BASE_EASIL1 + 3877) +#define EASIL1_PRCMCM_CLKSEL_DSPSYNC_DSPWrite32 (PRCM_BASE_EASIL1 + 3927) +#define EASIL1_PRCMCM_CLKSEL_DSPCLKSEL_DSP_IFWrite32 \ + (PRCM_BASE_EASIL1 + 3941) +#define EASIL1_PRCMCM_CLKSEL_DSPCLKSEL_DSPWrite32 \ + (PRCM_BASE_EASIL1 + 3965) +#define EASIL1_PRCMCM_CLKSTCTRL_DSPAutostate_DSPRead32 \ + (PRCM_BASE_EASIL1 + 3987) +#define EASIL1_PRCMCM_CLKSTCTRL_DSPAutostate_DSPWrite32 \ + (PRCM_BASE_EASIL1 + 3993) +#define EASIL1_PRCMRM_RSTCTRL_DSPReadRegister32 (PRCM_BASE_EASIL1 + 3997) +#define EASIL1_PRCMRM_RSTCTRL_DSPRST1_DSPWrite32 \ + (PRCM_BASE_EASIL1 + 4025) +#define EASIL1_PRCMRM_RSTST_DSPReadRegister32 (PRCM_BASE_EASIL1 + 4029) +#define EASIL1_PRCMRM_RSTST_DSPWriteRegister32 (PRCM_BASE_EASIL1 + 4030) +#define EASIL1_PRCMPM_PWSTCTRL_DSPForceStateWrite32 \ + (PRCM_BASE_EASIL1 + 4165) +#define EASIL1_PRCMPM_PWSTCTRL_DSPPowerStateWriteRET32 \ + (PRCM_BASE_EASIL1 + 4193) +#define EASIL1_PRCMPM_PWSTST_DSPReadRegister32 (PRCM_BASE_EASIL1 + 4197) +#define EASIL1_PRCMPM_PWSTST_DSPInTransitionRead32 \ + (PRCM_BASE_EASIL1 + 4198) +#define EASIL1_PRCMPM_PWSTST_DSPPowerStateStGet32 \ + (PRCM_BASE_EASIL1 + 4235) +#define EASIL1_CM_FCLKEN_PER_GPT5WriteRegister32 \ + (PRCM_BASE_EASIL1 + 4368) +#define EASIL1_CM_ICLKEN_PER_GPT5WriteRegister32 \ + (PRCM_BASE_EASIL1 + 4370) +#define EASIL1_CM_CLKSEL_PER_GPT5Write32k32 (PRCM_BASE_EASIL1 + 4372) +#define EASIL1_CM_CLKSEL_PER_GPT6Write32k32 (PRCM_BASE_EASIL1 + 4373) +#define EASIL1_PRCMCM_CLKSTCTRL_IVA2WriteRegister32 \ + (PRCM_BASE_EASIL1 + 4374) +#define EASIL1_PRCMPM_PWSTCTRL_IVA2PowerStateWriteON32 \ + (PRCM_BASE_EASIL1 + 4375) +#define EASIL1_PRCMPM_PWSTCTRL_IVA2PowerStateWriteOFF32 \ + (PRCM_BASE_EASIL1 + 4376) +#define EASIL1_PRCMPM_PWSTST_IVA2InTransitionRead32 \ + (PRCM_BASE_EASIL1 + 4377) +#define EASIL1_PRCMPM_PWSTST_IVA2PowerStateStGet32 \ + (PRCM_BASE_EASIL1 + 4378) +#define EASIL1_PRCMPM_PWSTST_IVA2ReadRegister32 (PRCM_BASE_EASIL1 + 4379) + +/* Register offset address definitions */ + +#define PRCM_PRCM_CLKCFG_CTRL_OFFSET (u32)(0x80) +#define PRCM_CM_FCLKEN1_CORE_OFFSET (u32)(0x200) +#define PRCM_CM_ICLKEN1_CORE_OFFSET (u32)(0x210) +#define PRCM_CM_CLKSEL2_CORE_OFFSET (u32)(0x244) +#define PRCM_CM_CLKSEL1_PLL_OFFSET (u32)(0x540) +#define PRCM_CM_ICLKEN_DSP_OFFSET (u32)(0x810) +#define PRCM_CM_IDLEST_DSP_OFFSET (u32)(0x820) +#define PRCM_CM_AUTOIDLE_DSP_OFFSET (u32)(0x830) +#define PRCM_CM_CLKSEL_DSP_OFFSET (u32)(0x840) +#define PRCM_CM_CLKSTCTRL_DSP_OFFSET (u32)(0x848) +#define PRCM_RM_RSTCTRL_DSP_OFFSET (u32)(0x850) +#define PRCM_RM_RSTST_DSP_OFFSET (u32)(0x858) +#define PRCM_PM_PWSTCTRL_DSP_OFFSET (u32)(0x8e0) +#define PRCM_PM_PWSTST_DSP_OFFSET (u32)(0x8e4) +#define PRCM_PM_PWSTST_IVA2_OFFSET (u32)(0xE4) +#define PRCM_PM_PWSTCTRL_IVA2_OFFSET (u32)(0xE0) +#define PRCM_CM_CLKSTCTRL_IVA2_OFFSET (u32)(0x48) +#define CM_CLKSEL_PER_OFFSET (u32)(0x40) + +/* Bitfield mask and offset declarations */ + +#define PRCM_PRCM_CLKCFG_CTRL_Valid_config_MASK (u32)(0x1) +#define PRCM_PRCM_CLKCFG_CTRL_Valid_config_OFFSET (u32)(0) + +#define PRCM_CM_FCLKEN1_CORE_EN_GPT8_MASK (u32)(0x400) +#define PRCM_CM_FCLKEN1_CORE_EN_GPT8_OFFSET (u32)(10) + +#define PRCM_CM_FCLKEN1_CORE_EN_GPT7_MASK (u32)(0x200) +#define PRCM_CM_FCLKEN1_CORE_EN_GPT7_OFFSET (u32)(9) + +#define PRCM_CM_ICLKEN1_CORE_EN_GPT8_MASK (u32)(0x400) +#define PRCM_CM_ICLKEN1_CORE_EN_GPT8_OFFSET (u32)(10) + +#define PRCM_CM_ICLKEN1_CORE_EN_GPT7_MASK (u32)(0x200) +#define PRCM_CM_ICLKEN1_CORE_EN_GPT7_OFFSET (u32)(9) + +#define PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT8_MASK (u32)(0xc000) +#define PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT8_OFFSET (u32)(14) + +#define PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT7_MASK (u32)(0x3000) +#define PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT7_OFFSET (u32)(12) + +#define PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT6_MASK (u32)(0xc00) +#define PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT6_OFFSET (u32)(10) + +#define PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT5_MASK (u32)(0x300) +#define PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT5_OFFSET (u32)(8) + +#define PRCM_CM_CLKSEL1_PLL_APLLs_Clkin_MASK (u32)(0x3800000) +#define PRCM_CM_CLKSEL1_PLL_APLLs_Clkin_OFFSET (u32)(23) + +#define PRCM_CM_ICLKEN_DSP_EN_DSP_IPI_MASK (u32)(0x2) +#define PRCM_CM_ICLKEN_DSP_EN_DSP_IPI_OFFSET (u32)(1) + +#define PRCM_CM_IDLEST_DSP_ST_IPI_MASK (u32)(0x2) +#define PRCM_CM_IDLEST_DSP_ST_IPI_OFFSET (u32)(1) + +#define PRCM_CM_AUTOIDLE_DSP_AUTO_DSP_IPI_MASK (u32)(0x2) +#define PRCM_CM_AUTOIDLE_DSP_AUTO_DSP_IPI_OFFSET (u32)(1) + +#define PRCM_CM_CLKSEL_DSP_SYNC_DSP_MASK (u32)(0x80) +#define PRCM_CM_CLKSEL_DSP_SYNC_DSP_OFFSET (u32)(7) + +#define PRCM_CM_CLKSEL_DSP_CLKSEL_DSP_IF_MASK (u32)(0x60) +#define PRCM_CM_CLKSEL_DSP_CLKSEL_DSP_IF_OFFSET (u32)(5) + +#define PRCM_CM_CLKSEL_DSP_CLKSEL_DSP_MASK (u32)(0x1f) +#define PRCM_CM_CLKSEL_DSP_CLKSEL_DSP_OFFSET (u32)(0) + +#define PRCM_CM_CLKSTCTRL_DSP_Autostate_DSP_MASK (u32)(0x1) +#define PRCM_CM_CLKSTCTRL_DSP_Autostate_DSP_OFFSET (u32)(0) + +#define PRCM_PM_PWSTCTRL_DSP_ForceState_MASK (u32)(0x40000) +#define PRCM_PM_PWSTCTRL_DSP_ForceState_OFFSET (u32)(18) + +#define PRCM_PM_PWSTCTRL_DSP_PowerState_MASK (u32)(0x3) +#define PRCM_PM_PWSTCTRL_DSP_PowerState_OFFSET (u32)(0) + +#define PRCM_PM_PWSTCTRL_IVA2_PowerState_MASK (u32)(0x3) +#define PRCM_PM_PWSTCTRL_IVA2_PowerState_OFFSET (u32)(0) + +#define PRCM_PM_PWSTST_DSP_InTransition_MASK (u32)(0x100000) +#define PRCM_PM_PWSTST_DSP_InTransition_OFFSET (u32)(20) + +#define PRCM_PM_PWSTST_IVA2_InTransition_MASK (u32)(0x100000) +#define PRCM_PM_PWSTST_IVA2_InTransition_OFFSET (u32)(20) + +#define PRCM_PM_PWSTST_DSP_PowerStateSt_MASK (u32)(0x3) +#define PRCM_PM_PWSTST_DSP_PowerStateSt_OFFSET (u32)(0) + +#define PRCM_PM_PWSTST_IVA2_PowerStateSt_MASK (u32)(0x3) +#define PRCM_PM_PWSTST_IVA2_PowerStateSt_OFFSET (u32)(0) + +#define CM_FCLKEN_PER_OFFSET (u32)(0x0) +#define CM_FCLKEN_PER_GPT5_OFFSET (u32)(6) +#define CM_FCLKEN_PER_GPT5_MASK (u32)(0x40) + +#define CM_FCLKEN_PER_GPT6_OFFSET (u32)(7) +#define CM_FCLKEN_PER_GPT6_MASK (u32)(0x80) + +#define CM_ICLKEN_PER_OFFSET (u32)(0x10) +#define CM_ICLKEN_PER_GPT5_OFFSET (u32)(6) +#define CM_ICLKEN_PER_GPT5_MASK (u32)(0x40) + +#define CM_ICLKEN_PER_GPT6_OFFSET (u32)(7) +#define CM_ICLKEN_PER_GPT6_MASK (u32)(0x80) + +#define CM_CLKSEL_PER_GPT5_OFFSET (u32)(3) +#define CM_CLKSEL_PER_GPT5_MASK (u32)(0x8) + +#define CM_CLKSEL_PER_GPT6_OFFSET (u32)(4) +#define CM_CLKSEL_PER_GPT6_MASK (u32)(0x10) + + +#define CM_FCLKEN_IVA2_OFFSET (u32)(0x0) +#define CM_FCLKEN_IVA2_EN_MASK (u32)(0x1) +#define CM_FCLKEN_IVA2_EN_OFFSET (u32)(0x0) + +#define CM_IDLEST_IVA2_OFFSET (u32)(0x20) +#define CM_IDLEST_IVA2_ST_IVA2_MASK (u32) (0x01) +#define CM_IDLEST_IVA2_ST_IVA2_OFFSET (u32) (0x00) + +#define CM_FCLKEN1_CORE_OFFSET (u32)(0xA00) + +#define CM_ICLKEN1_CORE_OFFSET (u32)(0xA10) +#define CM_ICLKEN1_CORE_EN_MAILBOXES_MASK (u32)(0x00000080) /* bit 7 */ +#define CM_ICLKEN1_CORE_EN_MAILBOXES_OFFSET (u32)(7) + +#define CM_CLKSTCTRL_IVA2_OFFSET (u32)(0x0) +#define CM_CLKSTCTRL_IVA2_MASK (u32)(0x3) + + +#define PRM_RSTCTRL_IVA2_OFFSET (u32)(0x50) +#define PRM_RSTCTRL_IVA2_RST1_MASK (u32)(0x1) +#define PRM_RSTCTRL_IVA2_RST1_OFFSET (u32)(0x0) +#define PRM_RSTCTRL_IVA2_RST2_MASK (u32)(0x2) +#define PRM_RSTCTRL_IVA2_RST2_OFFSET (u32)(0x1) +#define PRM_RSTCTRL_IVA2_RST3_MASK (u32)(0x4) +#define PRM_RSTCTRL_IVA2_RST3_OFFSET (u32)(0x2) + + +/* The following represent the enumerated values for each bitfield */ + +enum PRCMPRCM_CLKCFG_CTRLValid_configE { + PRCMPRCM_CLKCFG_CTRLValid_configUpdated = 0x0000, + PRCMPRCM_CLKCFG_CTRLValid_configClk_valid = 0x0001 +} ; + +enum PRCMCM_CLKSEL2_CORECLKSEL_GPT8E { + PRCMCM_CLKSEL2_CORECLKSEL_GPT832k = 0x0000, + PRCMCM_CLKSEL2_CORECLKSEL_GPT8Sys = 0x0001, + PRCMCM_CLKSEL2_CORECLKSEL_GPT8Ext = 0x0002, + PRCMCM_CLKSEL2_CORECLKSEL_GPT8Reserved = 0x0003 +} ; + +enum PRCMCM_CLKSEL2_CORECLKSEL_GPT7E { + PRCMCM_CLKSEL2_CORECLKSEL_GPT732k = 0x0000, + PRCMCM_CLKSEL2_CORECLKSEL_GPT7Sys = 0x0001, + PRCMCM_CLKSEL2_CORECLKSEL_GPT7Ext = 0x0002, + PRCMCM_CLKSEL2_CORECLKSEL_GPT7Reserved = 0x0003 +} ; + +enum PRCMCM_CLKSEL2_CORECLKSEL_GPT6E { + PRCMCM_CLKSEL2_CORECLKSEL_GPT632k = 0x0000, + PRCMCM_CLKSEL2_CORECLKSEL_GPT6Sys = 0x0001, + PRCMCM_CLKSEL2_CORECLKSEL_GPT6Ext = 0x0002, + PRCMCM_CLKSEL2_CORECLKSEL_GPT6Reserved = 0x0003 +} ; + +enum PRCMCM_CLKSEL2_CORECLKSEL_GPT5E { + PRCMCM_CLKSEL2_CORECLKSEL_GPT532k = 0x0000, + PRCMCM_CLKSEL2_CORECLKSEL_GPT5Sys = 0x0001, + PRCMCM_CLKSEL2_CORECLKSEL_GPT5Ext = 0x0002, + PRCMCM_CLKSEL2_CORECLKSEL_GPT5Reserved = 0x0003 +} ; + +enum PRCMPM_PWSTCTRL_DSPPowerStateE { + PRCMPM_PWSTCTRL_DSPPowerStateON = 0x0000, + PRCMPM_PWSTCTRL_DSPPowerStateRET = 0x0001, + PRCMPM_PWSTCTRL_DSPPowerStateReserved = 0x0002, + PRCMPM_PWSTCTRL_DSPPowerStateOFF = 0x0003 +} ; + +enum PRCMPM_PWSTCTRL_IVA2PowerStateE { + PRCMPM_PWSTCTRL_IVA2PowerStateON = 0x0003, + PRCMPM_PWSTCTRL_IVA2PowerStateRET = 0x0001, + PRCMPM_PWSTCTRL_IVA2PowerStateReserved = 0x0002, + PRCMPM_PWSTCTRL_IVA2PowerStateOFF = 0x0000 +} ; + +#endif /* _PRCM_ACC_INT_H */ diff --git a/drivers/dsp/bridge/hw/PRCMRegAcM.h b/drivers/dsp/bridge/hw/PRCMRegAcM.h new file mode 100644 index 0000000..91cb33c --- /dev/null +++ b/drivers/dsp/bridge/hw/PRCMRegAcM.h @@ -0,0 +1,669 @@ +/* + * PRCMRegAcM.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef _PRCM_REG_ACM_H +#define _PRCM_REG_ACM_H + +#include + +#include + +#include "PRCMAccInt.h" + +#if defined(USE_LEVEL_1_MACROS) + +#define PRCMPRCM_CLKCFG_CTRLValid_configWriteClk_valid32(baseAddress)\ +{\ + const u32 offset = PRCM_PRCM_CLKCFG_CTRL_OFFSET;\ + const u32 newValue = \ + (u32)PRCMPRCM_CLKCFG_CTRLValid_configClk_valid <<\ + PRCM_PRCM_CLKCFG_CTRL_Valid_config_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((u32)(baseAddress)+offset);\ + _DEBUG_LEVEL_1_EASI(\ + EASIL1_PRCMPRCM_CLKCFG_CTRLValid_configWriteClk_valid32);\ + data &= ~(PRCM_PRCM_CLKCFG_CTRL_Valid_config_MASK);\ + data |= newValue;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, data);\ +} + + +#define CM_FCLKEN_PERReadRegister32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_FCLKEN1_COREReadRegister32),\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+CM_FCLKEN_PER_OFFSET)) + + +#define CM_ICLKEN_PERReadRegister32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_FCLKEN1_COREReadRegister32),\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+CM_ICLKEN_PER_OFFSET)) + + +#define CM_FCLKEN_PER_GPT5WriteRegister32(baseAddress,value)\ +{\ + const u32 offset = CM_FCLKEN_PER_OFFSET;\ + register u32 data = \ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_CM_FCLKEN_PER_GPT5WriteRegister32);\ + data &= ~(CM_FCLKEN_PER_GPT5_MASK);\ + newValue <<= CM_FCLKEN_PER_GPT5_OFFSET;\ + newValue &= CM_FCLKEN_PER_GPT5_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE(((u32)(baseAddress))+offset, newValue);\ +} + + +#define CM_FCLKEN_PER_GPT6WriteRegister32(baseAddress,value)\ +{\ + const u32 offset = CM_FCLKEN_PER_OFFSET;\ + register u32 data =\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_CM_FCLKEN_PER_GPT5WriteRegister32);\ + data &= ~(CM_FCLKEN_PER_GPT6_MASK);\ + newValue <<= CM_FCLKEN_PER_GPT6_OFFSET;\ + newValue &= CM_FCLKEN_PER_GPT6_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE(((u32)(baseAddress))+offset, newValue);\ +} + + +#define CM_ICLKEN_PER_GPT5WriteRegister32(baseAddress,value)\ +{\ + const u32 offset = CM_ICLKEN_PER_OFFSET;\ + register u32 data = \ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_CM_ICLKEN_PER_GPT5WriteRegister32);\ + data &= ~(CM_ICLKEN_PER_GPT5_MASK);\ + newValue <<= CM_ICLKEN_PER_GPT5_OFFSET;\ + newValue &= CM_ICLKEN_PER_GPT5_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE(((u32)(baseAddress))+offset, newValue);\ +} + + +#define CM_ICLKEN_PER_GPT6WriteRegister32(baseAddress,value)\ +{\ + const u32 offset = CM_ICLKEN_PER_OFFSET;\ + register u32 data = \ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_CM_ICLKEN_PER_GPT5WriteRegister32);\ + data &= ~(CM_ICLKEN_PER_GPT6_MASK);\ + newValue <<= CM_ICLKEN_PER_GPT6_OFFSET;\ + newValue &= CM_ICLKEN_PER_GPT6_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE(((u32)(baseAddress))+offset, newValue);\ +} + + +#define CM_FCLKEN1_COREReadRegister32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_FCLKEN1_COREReadRegister32),\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+CM_FCLKEN1_CORE_OFFSET)) + + +#define PRCMCM_FCLKEN1_COREEN_GPT8Write32(baseAddress,value)\ +{\ + const u32 offset = PRCM_CM_FCLKEN1_CORE_OFFSET;\ + register u32 data = \ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_FCLKEN1_COREEN_GPT8Write32);\ + data &= ~(PRCM_CM_FCLKEN1_CORE_EN_GPT8_MASK);\ + newValue <<= PRCM_CM_FCLKEN1_CORE_EN_GPT8_OFFSET;\ + newValue &= PRCM_CM_FCLKEN1_CORE_EN_GPT8_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define PRCMCM_FCLKEN1_COREEN_GPT7Write32(baseAddress,value)\ +{\ + const u32 offset = PRCM_CM_FCLKEN1_CORE_OFFSET;\ + register u32 data = \ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_FCLKEN1_COREEN_GPT7Write32);\ + data &= ~(PRCM_CM_FCLKEN1_CORE_EN_GPT7_MASK);\ + newValue <<= PRCM_CM_FCLKEN1_CORE_EN_GPT7_OFFSET;\ + newValue &= PRCM_CM_FCLKEN1_CORE_EN_GPT7_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define CM_ICLKEN1_COREReadRegister32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_ICLKEN1_COREReadRegister32),\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+CM_ICLKEN1_CORE_OFFSET)) + + +#define CM_ICLKEN1_COREEN_MAILBOXESWrite32(baseAddress, value)\ +{\ + const u32 offset = CM_ICLKEN1_CORE_OFFSET;\ + register u32 data = \ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_ICLKEN1_COREEN_MAILBOXESWrite32);\ + data &= ~(CM_ICLKEN1_CORE_EN_MAILBOXES_MASK);\ + newValue <<= CM_ICLKEN1_CORE_EN_MAILBOXES_OFFSET;\ + newValue &= CM_ICLKEN1_CORE_EN_MAILBOXES_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define PRCMCM_ICLKEN1_COREEN_GPT8Write32(baseAddress, value)\ +{\ + const u32 offset = PRCM_CM_ICLKEN1_CORE_OFFSET;\ + register u32 data = \ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_ICLKEN1_COREEN_GPT8Write32);\ + data &= ~(PRCM_CM_ICLKEN1_CORE_EN_GPT8_MASK);\ + newValue <<= PRCM_CM_ICLKEN1_CORE_EN_GPT8_OFFSET;\ + newValue &= PRCM_CM_ICLKEN1_CORE_EN_GPT8_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define PRCMCM_ICLKEN1_COREEN_GPT7Write32(baseAddress, value)\ +{\ + const u32 offset = PRCM_CM_ICLKEN1_CORE_OFFSET;\ + register u32 data =\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_ICLKEN1_COREEN_GPT7Write32);\ + data &= ~(PRCM_CM_ICLKEN1_CORE_EN_GPT7_MASK);\ + newValue <<= PRCM_CM_ICLKEN1_CORE_EN_GPT7_OFFSET;\ + newValue &= PRCM_CM_ICLKEN1_CORE_EN_GPT7_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define PRCMCM_CLKSEL2_CORECLKSEL_GPT8Write32k32(baseAddress)\ +{\ + const u32 offset = PRCM_CM_CLKSEL2_CORE_OFFSET;\ + const u32 newValue = (u32)PRCMCM_CLKSEL2_CORECLKSEL_GPT832k <<\ + PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT8_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((u32)(baseAddress)+offset);\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT8Write32k32);\ + data &= ~(PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT8_MASK);\ + data |= newValue;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, data);\ +} + + +#define PRCMCM_CLKSEL2_CORECLKSEL_GPT8WriteSys32(baseAddress)\ +{\ + const u32 offset = PRCM_CM_CLKSEL2_CORE_OFFSET;\ + const u32 newValue = (u32)PRCMCM_CLKSEL2_CORECLKSEL_GPT8Sys <<\ + PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT8_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((u32)(baseAddress)+offset);\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT8WriteSys32);\ + data &= ~(PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT8_MASK);\ + data |= newValue;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, data);\ +} + + +#define PRCMCM_CLKSEL2_CORECLKSEL_GPT8WriteExt32(baseAddress)\ +{\ + const u32 offset = PRCM_CM_CLKSEL2_CORE_OFFSET;\ + const u32 newValue = (u32)PRCMCM_CLKSEL2_CORECLKSEL_GPT8Ext <<\ + PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT8_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((u32)(baseAddress)+offset);\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT8WriteExt32);\ + data &= ~(PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT8_MASK);\ + data |= newValue;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, data);\ +} + + +#define PRCMCM_CLKSEL2_CORECLKSEL_GPT7Write32k32(baseAddress)\ +{\ + const u32 offset = PRCM_CM_CLKSEL2_CORE_OFFSET;\ + const u32 newValue = (u32)PRCMCM_CLKSEL2_CORECLKSEL_GPT732k <<\ + PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT7_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((u32)(baseAddress)+offset);\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT7Write32k32);\ + data &= ~(PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT7_MASK);\ + data |= newValue;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, data);\ +} + + +#define PRCMCM_CLKSEL2_CORECLKSEL_GPT7WriteSys32(baseAddress)\ +{\ + const u32 offset = PRCM_CM_CLKSEL2_CORE_OFFSET;\ + const u32 newValue = (u32)PRCMCM_CLKSEL2_CORECLKSEL_GPT7Sys <<\ + PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT7_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((u32)(baseAddress)+offset);\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT7WriteSys32);\ + data &= ~(PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT7_MASK);\ + data |= newValue;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, data);\ +} + + +#define PRCMCM_CLKSEL2_CORECLKSEL_GPT7WriteExt32(baseAddress)\ +{\ + const u32 offset = PRCM_CM_CLKSEL2_CORE_OFFSET;\ + const u32 newValue = (u32)PRCMCM_CLKSEL2_CORECLKSEL_GPT7Ext <<\ + PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT7_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((u32)(baseAddress)+offset);\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT7WriteExt32);\ + data &= ~(PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT7_MASK);\ + data |= newValue;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, data);\ +} + + +#define PRCMCM_CLKSEL2_CORECLKSEL_GPT6WriteSys32(baseAddress)\ +{\ + const u32 offset = PRCM_CM_CLKSEL2_CORE_OFFSET;\ + const u32 newValue = (u32)PRCMCM_CLKSEL2_CORECLKSEL_GPT6Sys <<\ + PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT6_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((u32)(baseAddress)+offset);\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT6WriteSys32);\ + data &= ~(PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT6_MASK);\ + data |= newValue;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, data);\ +} + + +#define PRCMCM_CLKSEL2_CORECLKSEL_GPT6WriteExt32(baseAddress)\ +{\ + const u32 offset = PRCM_CM_CLKSEL2_CORE_OFFSET;\ + const u32 newValue = (u32)PRCMCM_CLKSEL2_CORECLKSEL_GPT6Ext <<\ + PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT6_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((u32)(baseAddress)+offset);\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT6WriteExt32);\ + data &= ~(PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT6_MASK);\ + data |= newValue;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, data);\ +} + + +#define CM_CLKSEL_PER_GPT5Write32k32(baseAddress)\ +{\ + const u32 offset = CM_CLKSEL_PER_OFFSET;\ + const u32 newValue = (u32)PRCMCM_CLKSEL2_CORECLKSEL_GPT532k <<\ + CM_CLKSEL_PER_GPT5_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((u32)(baseAddress)+offset);\ + _DEBUG_LEVEL_1_EASI(EASIL1_CM_CLKSEL_PER_GPT5Write32k32);\ + data &= ~(CM_CLKSEL_PER_GPT5_MASK);\ + data |= newValue;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, data);\ +} + + +#define CM_CLKSEL_PER_GPT6Write32k32(baseAddress)\ +{\ + const u32 offset = CM_CLKSEL_PER_OFFSET;\ + const u32 newValue = (u32)PRCMCM_CLKSEL2_CORECLKSEL_GPT532k <<\ + CM_CLKSEL_PER_GPT6_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((u32)(baseAddress)+offset);\ + _DEBUG_LEVEL_1_EASI(EASIL1_CM_CLKSEL_PER_GPT6Write32k32);\ + data &= ~(CM_CLKSEL_PER_GPT6_MASK);\ + data |= newValue;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, data);\ +} + + +#define PRCMCM_CLKSEL2_CORECLKSEL_GPT5WriteSys32(baseAddress)\ +{\ + const u32 offset = PRCM_CM_CLKSEL2_CORE_OFFSET;\ + const u32 newValue = (u32)PRCMCM_CLKSEL2_CORECLKSEL_GPT5Sys <<\ + PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT5_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((u32)(baseAddress)+offset);\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT5WriteSys32);\ + data &= ~(PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT5_MASK);\ + data |= newValue;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, data);\ +} + + +#define PRCMCM_CLKSEL2_CORECLKSEL_GPT5WriteExt32(baseAddress)\ +{\ + const u32 offset = PRCM_CM_CLKSEL2_CORE_OFFSET;\ + const u32 newValue = (u32)PRCMCM_CLKSEL2_CORECLKSEL_GPT5Ext <<\ + PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT5_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((u32)(baseAddress)+offset);\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSEL2_CORECLKSEL_GPT5WriteExt32);\ + data &= ~(PRCM_CM_CLKSEL2_CORE_CLKSEL_GPT5_MASK);\ + data |= newValue;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, data);\ +} + + +#define PRCMCM_CLKSEL1_PLLAPLLs_ClkinRead32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSEL1_PLLAPLLs_ClkinRead32),\ + (((RD_MEM_32_VOLATILE((((u32)(baseAddress))+\ + (PRCM_CM_CLKSEL1_PLL_OFFSET)))) &\ + PRCM_CM_CLKSEL1_PLL_APLLs_Clkin_MASK) >>\ + PRCM_CM_CLKSEL1_PLL_APLLs_Clkin_OFFSET)) + + +#define CM_FCLKEN_IVA2EN_DSPWrite32(baseAddress,value)\ +{\ + const u32 offset = CM_FCLKEN_IVA2_OFFSET;\ + register u32 data = \ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_FCLKEN_DSPEN_DSPWrite32);\ + data &= ~(CM_FCLKEN_IVA2_EN_MASK);\ + newValue <<= CM_FCLKEN_IVA2_EN_OFFSET;\ + newValue &= CM_FCLKEN_IVA2_EN_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define PRCMCM_ICLKEN_DSPEN_DSP_IPIWrite32(baseAddress, value)\ +{\ + const u32 offset = PRCM_CM_ICLKEN_DSP_OFFSET;\ + register u32 data = \ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_ICLKEN_DSPEN_DSP_IPIWrite32);\ + data &= ~(PRCM_CM_ICLKEN_DSP_EN_DSP_IPI_MASK);\ + newValue <<= PRCM_CM_ICLKEN_DSP_EN_DSP_IPI_OFFSET;\ + newValue &= PRCM_CM_ICLKEN_DSP_EN_DSP_IPI_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define PRCMCM_IDLEST_DSPReadRegister32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_IDLEST_DSPReadRegister32),\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+PRCM_CM_IDLEST_DSP_OFFSET)) + + +#define PRCMCM_IDLEST_DSPST_IPIRead32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_IDLEST_DSPST_IPIRead32),\ + (((RD_MEM_32_VOLATILE((((u32)(baseAddress))+\ + (PRCM_CM_IDLEST_DSP_OFFSET)))) &\ + PRCM_CM_IDLEST_DSP_ST_IPI_MASK) >>\ + PRCM_CM_IDLEST_DSP_ST_IPI_OFFSET)) + + +#define PRM_IDLEST_IVA2ST_IVA2Read32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_IDLEST_DSPST_DSPRead32),\ + (((RD_MEM_32_VOLATILE((((u32)(baseAddress))+\ + (CM_IDLEST_IVA2_OFFSET)))) &\ + CM_IDLEST_IVA2_ST_IVA2_MASK) >>\ + CM_IDLEST_IVA2_ST_IVA2_OFFSET)) + + +#define PRCMCM_AUTOIDLE_DSPAUTO_DSP_IPIWrite32(baseAddress, value)\ +{\ + const u32 offset = PRCM_CM_AUTOIDLE_DSP_OFFSET;\ + register u32 data =\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_AUTOIDLE_DSPAUTO_DSP_IPIWrite32);\ + data &= ~(PRCM_CM_AUTOIDLE_DSP_AUTO_DSP_IPI_MASK);\ + newValue <<= PRCM_CM_AUTOIDLE_DSP_AUTO_DSP_IPI_OFFSET;\ + newValue &= PRCM_CM_AUTOIDLE_DSP_AUTO_DSP_IPI_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define PRCMCM_CLKSEL_DSPSYNC_DSPWrite32(baseAddress,value)\ +{\ + const u32 offset = PRCM_CM_CLKSEL_DSP_OFFSET;\ + register u32 data = \ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSEL_DSPSYNC_DSPWrite32);\ + data &= ~(PRCM_CM_CLKSEL_DSP_SYNC_DSP_MASK);\ + newValue <<= PRCM_CM_CLKSEL_DSP_SYNC_DSP_OFFSET;\ + newValue &= PRCM_CM_CLKSEL_DSP_SYNC_DSP_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define PRCMCM_CLKSEL_DSPCLKSEL_DSP_IFWrite32(baseAddress, value)\ +{\ + const u32 offset = PRCM_CM_CLKSEL_DSP_OFFSET;\ + register u32 data = \ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSEL_DSPCLKSEL_DSP_IFWrite32);\ + data &= ~(PRCM_CM_CLKSEL_DSP_CLKSEL_DSP_IF_MASK);\ + newValue <<= PRCM_CM_CLKSEL_DSP_CLKSEL_DSP_IF_OFFSET;\ + newValue &= PRCM_CM_CLKSEL_DSP_CLKSEL_DSP_IF_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define PRCMCM_CLKSEL_DSPCLKSEL_DSPWrite32(baseAddress, value)\ +{\ + const u32 offset = PRCM_CM_CLKSEL_DSP_OFFSET;\ + register u32 data = \ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSEL_DSPCLKSEL_DSPWrite32);\ + data &= ~(PRCM_CM_CLKSEL_DSP_CLKSEL_DSP_MASK);\ + newValue <<= PRCM_CM_CLKSEL_DSP_CLKSEL_DSP_OFFSET;\ + newValue &= PRCM_CM_CLKSEL_DSP_CLKSEL_DSP_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define PRCMCM_CLKSTCTRL_IVA2WriteRegister32(baseAddress, value)\ +{\ + const u32 offset = PRCM_CM_CLKSTCTRL_IVA2_OFFSET;\ + register u32 data = \ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSTCTRL_IVA2WriteRegister32);\ + data &= ~(CM_CLKSTCTRL_IVA2_MASK);\ + newValue <<= CM_CLKSTCTRL_IVA2_OFFSET;\ + newValue &= CM_CLKSTCTRL_IVA2_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define PRCMCM_CLKSTCTRL_DSPAutostate_DSPRead32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSTCTRL_DSPAutostate_DSPRead32),\ + (((RD_MEM_32_VOLATILE((((u32)(baseAddress))+\ + (PRCM_CM_CLKSTCTRL_DSP_OFFSET)))) &\ + PRCM_CM_CLKSTCTRL_DSP_Autostate_DSP_MASK) >>\ + PRCM_CM_CLKSTCTRL_DSP_Autostate_DSP_OFFSET)) + + +#define PRCMCM_CLKSTCTRL_DSPAutostate_DSPWrite32(baseAddress, value)\ +{\ + const u32 offset = PRCM_CM_CLKSTCTRL_DSP_OFFSET;\ + register u32 data = \ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMCM_CLKSTCTRL_DSPAutostate_DSPWrite32);\ + data &= ~(PRCM_CM_CLKSTCTRL_DSP_Autostate_DSP_MASK);\ + newValue <<= PRCM_CM_CLKSTCTRL_DSP_Autostate_DSP_OFFSET;\ + newValue &= PRCM_CM_CLKSTCTRL_DSP_Autostate_DSP_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define PRCMRM_RSTCTRL_DSPReadRegister32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMRM_RSTCTRL_DSPReadRegister32),\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+PRCM_RM_RSTCTRL_DSP_OFFSET)) + + +#define PRM_RSTCTRL_IVA2RST1_DSPWrite32(baseAddress,value)\ +{\ + const u32 offset = PRM_RSTCTRL_IVA2_OFFSET;\ + register u32 data =\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMRM_RSTCTRL_DSPRST1_DSPWrite32);\ + data &= ~(PRM_RSTCTRL_IVA2_RST1_MASK);\ + newValue <<= PRM_RSTCTRL_IVA2_RST1_OFFSET;\ + newValue &= PRM_RSTCTRL_IVA2_RST1_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define PRM_RSTCTRL_IVA2RST2_DSPWrite32(baseAddress,value)\ +{\ + const u32 offset = PRM_RSTCTRL_IVA2_OFFSET;\ + register u32 data =\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMRM_RSTCTRL_DSPRST1_DSPWrite32);\ + data &= ~(PRM_RSTCTRL_IVA2_RST2_MASK);\ + newValue <<= PRM_RSTCTRL_IVA2_RST2_OFFSET;\ + newValue &= PRM_RSTCTRL_IVA2_RST2_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define PRM_RSTCTRL_IVA2RST3_DSPWrite32(baseAddress,value)\ +{\ + const u32 offset = PRM_RSTCTRL_IVA2_OFFSET;\ + register u32 data =\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMRM_RSTCTRL_DSPRST1_DSPWrite32);\ + data &= ~(PRM_RSTCTRL_IVA2_RST3_MASK);\ + newValue <<= PRM_RSTCTRL_IVA2_RST3_OFFSET;\ + newValue &= PRM_RSTCTRL_IVA2_RST3_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define PRCMRM_RSTST_DSPReadRegister32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMRM_RSTST_DSPReadRegister32),\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+PRCM_RM_RSTST_DSP_OFFSET)) + + +#define PRCMRM_RSTST_DSPWriteRegister32(baseAddress,value)\ +{\ + const u32 offset = PRCM_RM_RSTST_DSP_OFFSET;\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMRM_RSTST_DSPWriteRegister32);\ + WR_MEM_32_VOLATILE(((u32)(baseAddress))+offset, newValue);\ +} + + +#define PRCMPM_PWSTCTRL_DSPForceStateWrite32(baseAddress, value)\ +{\ + const u32 offset = PRCM_PM_PWSTCTRL_DSP_OFFSET;\ + register u32 data = \ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+offset);\ + register u32 newValue = ((u32)(value));\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMPM_PWSTCTRL_DSPForceStateWrite32);\ + data &= ~(PRCM_PM_PWSTCTRL_DSP_ForceState_MASK);\ + newValue <<= PRCM_PM_PWSTCTRL_DSP_ForceState_OFFSET;\ + newValue &= PRCM_PM_PWSTCTRL_DSP_ForceState_MASK;\ + newValue |= data;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, newValue);\ +} + + +#define PRCMPM_PWSTCTRL_IVA2PowerStateWriteON32(baseAddress)\ +{\ + const u32 offset = PRCM_PM_PWSTCTRL_IVA2_OFFSET;\ + const u32 newValue = (u32)PRCMPM_PWSTCTRL_IVA2PowerStateON <<\ + PRCM_PM_PWSTCTRL_IVA2_PowerState_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((u32)(baseAddress)+offset);\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMPM_PWSTCTRL_IVA2PowerStateWriteON32);\ + data &= ~(PRCM_PM_PWSTCTRL_IVA2_PowerState_MASK);\ + data |= newValue;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, data);\ +} + + +#define PRCMPM_PWSTCTRL_IVA2PowerStateWriteOFF32(baseAddress)\ +{\ + const u32 offset = PRCM_PM_PWSTCTRL_IVA2_OFFSET;\ + const u32 newValue = (u32)PRCMPM_PWSTCTRL_IVA2PowerStateOFF <<\ + PRCM_PM_PWSTCTRL_IVA2_PowerState_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((u32)(baseAddress)+offset);\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMPM_PWSTCTRL_IVA2PowerStateWriteOFF32);\ + data &= ~(PRCM_PM_PWSTCTRL_IVA2_PowerState_MASK);\ + data |= newValue;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, data);\ +} + + +#define PRCMPM_PWSTCTRL_DSPPowerStateWriteRET32(baseAddress)\ +{\ + const u32 offset = PRCM_PM_PWSTCTRL_DSP_OFFSET;\ + const u32 newValue = (u32)PRCMPM_PWSTCTRL_DSPPowerStateRET <<\ + PRCM_PM_PWSTCTRL_DSP_PowerState_OFFSET;\ + register u32 data = RD_MEM_32_VOLATILE((u32)(baseAddress)+offset);\ + _DEBUG_LEVEL_1_EASI(EASIL1_PRCMPM_PWSTCTRL_DSPPowerStateWriteRET32);\ + data &= ~(PRCM_PM_PWSTCTRL_DSP_PowerState_MASK);\ + data |= newValue;\ + WR_MEM_32_VOLATILE((u32)(baseAddress)+offset, data);\ +} + + +#define PRCMPM_PWSTST_DSPReadRegister32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMPM_PWSTST_DSPReadRegister32),\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+PRCM_PM_PWSTST_DSP_OFFSET)) + + +#define PRCMPM_PWSTST_IVA2ReadRegister32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMPM_PWSTST_IVA2ReadRegister32),\ + RD_MEM_32_VOLATILE(((u32)(baseAddress))+PRCM_PM_PWSTST_IVA2_OFFSET)) + + +#define PRCMPM_PWSTST_DSPInTransitionRead32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMPM_PWSTST_DSPInTransitionRead32),\ + (((RD_MEM_32_VOLATILE((((u32)(baseAddress))+\ + (PRCM_PM_PWSTST_DSP_OFFSET)))) &\ + PRCM_PM_PWSTST_DSP_InTransition_MASK) >>\ + PRCM_PM_PWSTST_DSP_InTransition_OFFSET)) + + +#define PRCMPM_PWSTST_IVA2InTransitionRead32(baseAddress)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMPM_PWSTST_IVA2InTransitionRead32),\ + (((RD_MEM_32_VOLATILE((((u32)(baseAddress))+\ + (PRCM_PM_PWSTST_IVA2_OFFSET)))) &\ + PRCM_PM_PWSTST_IVA2_InTransition_MASK) >>\ + PRCM_PM_PWSTST_IVA2_InTransition_OFFSET)) + + +#define PRCMPM_PWSTST_DSPPowerStateStGet32(var)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMPM_PWSTST_DSPPowerStateStGet32),\ + (u32)((((u32)(var)) & PRCM_PM_PWSTST_DSP_PowerStateSt_MASK) >>\ + PRCM_PM_PWSTST_DSP_PowerStateSt_OFFSET)) + + +#define PRCMPM_PWSTST_IVA2PowerStateStGet32(var)\ + (_DEBUG_LEVEL_1_EASI(EASIL1_PRCMPM_PWSTST_IVA2PowerStateStGet32),\ + (u32)((((u32)(var)) & PRCM_PM_PWSTST_IVA2_PowerStateSt_MASK) >>\ + PRCM_PM_PWSTST_IVA2_PowerStateSt_OFFSET)) + + +#endif /* USE_LEVEL_1_MACROS */ + +#endif /* _PRCM_REG_ACM_H */ diff --git a/drivers/dsp/bridge/hw/hw_defs.h b/drivers/dsp/bridge/hw/hw_defs.h new file mode 100644 index 0000000..a973f5c --- /dev/null +++ b/drivers/dsp/bridge/hw/hw_defs.h @@ -0,0 +1,73 @@ +/* + * hw_defs.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== hw_defs.h ======== + * Description: + * Global HW definitions + * + *! Revision History: + *! ================ + *! 19 Apr 2004 sb: Added generic page size, endianness and element size defns + *! 16 Feb 2003 sb: Initial version + */ +#ifndef __HW_DEFS_H +#define __HW_DEFS_H + +#include + +/* Page size */ +#define HW_PAGE_SIZE_4KB 0x1000 +#define HW_PAGE_SIZE_64KB 0x10000 +#define HW_PAGE_SIZE_1MB 0x100000 +#define HW_PAGE_SIZE_16MB 0x1000000 + +/* HW_STATUS: return type for HW API */ +typedef long HW_STATUS; + +/* HW_SetClear_t: Enumerated Type used to set and clear any bit */ +enum HW_SetClear_t { + HW_CLEAR, + HW_SET +} ; + +/* HW_Endianism_t: Enumerated Type used to specify the endianism + * Do NOT change these values. They are used as bit fields. */ +enum HW_Endianism_t { + HW_LITTLE_ENDIAN, + HW_BIG_ENDIAN + +} ; + +/* HW_ElementSize_t: Enumerated Type used to specify the element size + * Do NOT change these values. They are used as bit fields. */ +enum HW_ElementSize_t { + HW_ELEM_SIZE_8BIT, + HW_ELEM_SIZE_16BIT, + HW_ELEM_SIZE_32BIT, + HW_ELEM_SIZE_64BIT + +} ; + +/* HW_IdleMode_t: Enumerated Type used to specify Idle modes */ + enum HW_IdleMode_t { + HW_FORCE_IDLE, + HW_NO_IDLE, + HW_SMART_IDLE + } ; + +#endif /* __HW_DEFS_H */ diff --git a/drivers/dsp/bridge/hw/hw_dspssC64P.c b/drivers/dsp/bridge/hw/hw_dspssC64P.c new file mode 100644 index 0000000..a4b7c30 --- /dev/null +++ b/drivers/dsp/bridge/hw/hw_dspssC64P.c @@ -0,0 +1,55 @@ +/* + * hw_dspss64P.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== hw_dspss64P.c ======== + * Description: + * API definitions to configure DSP Subsystem modules like IPI + * + *! Revision History: + *! ================ + *! 19 Apr 2004 sb: Implemented HW_DSPSS_IPIEndianismSet + *! 16 Feb 2003 sb: Initial version + */ + +/* PROJECT SPECIFIC INCLUDE FILES */ +#include +#include +#include +#include +#include + +/* HW FUNCTIONS */ +HW_STATUS HW_DSPSS_BootModeSet(const u32 baseAddress, + enum HW_DSPSYSC_BootMode_t bootMode, + const u32 bootAddress) +{ + HW_STATUS status = RET_OK; + u32 offset = SYSC_IVA2BOOTMOD_OFFSET; + u32 alignedBootAddr; + + /* if Boot mode it DIRECT BOOT, check that the bootAddress is + * aligned to atleast 1K :: TODO */ + WR_MEM_32_VOLATILE((baseAddress) + offset, bootMode); + + offset = SYSC_IVA2BOOTADDR_OFFSET; + + alignedBootAddr = bootAddress & SYSC_IVA2BOOTADDR_MASK; + + WR_MEM_32_VOLATILE((baseAddress) + offset, alignedBootAddr); + + return status; +} diff --git a/drivers/dsp/bridge/hw/hw_dspssC64P.h b/drivers/dsp/bridge/hw/hw_dspssC64P.h new file mode 100644 index 0000000..493effd --- /dev/null +++ b/drivers/dsp/bridge/hw/hw_dspssC64P.h @@ -0,0 +1,48 @@ +/* + * hw_dspssC64P.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== hw_dspss.h ======== + * Description: + * DSP Subsystem API declarations + * + *! Revision History: + *! ================ + *! 19-Apr-2004 sb: Removed redundant argument from HW_DSPSS_IPIEndianismSet + *! Moved endianness and element size to generic hw_defs.h + *! 16 Feb 2003 sb: Initial version + */ + +#ifndef __HW_DSPSS_H +#define __HW_DSPSS_H +#include + + enum HW_DSPSYSC_BootMode_t { + HW_DSPSYSC_DIRECTBOOT = 0x0, + HW_DSPSYSC_IDLEBOOT = 0x1, + HW_DSPSYSC_SELFLOOPBOOT = 0x2, + HW_DSPSYSC_USRBOOTSTRAP = 0x3, + HW_DSPSYSC_DEFAULTRESTORE = 0x4 + } ; + +#define HW_DSP_IDLEBOOT_ADDR 0x007E0000 + + extern HW_STATUS HW_DSPSS_BootModeSet(const u32 baseAddress, + enum HW_DSPSYSC_BootMode_t bootMode, + const u32 bootAddress); + +#endif /* __HW_DSPSS_H */ diff --git a/drivers/dsp/bridge/hw/hw_mbox.c b/drivers/dsp/bridge/hw/hw_mbox.c new file mode 100644 index 0000000..9f14f34 --- /dev/null +++ b/drivers/dsp/bridge/hw/hw_mbox.c @@ -0,0 +1,244 @@ +/* + * hw_mbox.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== hw_mbox.c ======== + * Description: + * Mailbox messaging & configuration API definitions + * + *! Revision History: + *! ================ + *! 16 Feb 2003 sb: Initial version + */ + +#include +#include "MLBRegAcM.h" +#include +#include + +/* width in bits of MBOX Id */ +#define HW_MBOX_ID_WIDTH 2 + +struct MAILBOX_CONTEXT mboxsetting = {0x4, 0x1, 0x1}; + +/* Saves the mailbox context */ +HW_STATUS HW_MBOX_saveSettings(u32 baseAddress) +{ + HW_STATUS status = RET_OK; + + mboxsetting.sysconfig = MLBMAILBOX_SYSCONFIGReadRegister32(baseAddress); + /* Get current enable status */ + mboxsetting.irqEnable0 = MLBMAILBOX_IRQENABLE___0_3ReadRegister32 + (baseAddress, HW_MBOX_U0_ARM); + mboxsetting.irqEnable1 = MLBMAILBOX_IRQENABLE___0_3ReadRegister32 + (baseAddress, HW_MBOX_U1_DSP1); + return status; +} + +/* Restores the mailbox context */ +HW_STATUS HW_MBOX_restoreSettings(u32 baseAddress) +{ + HW_STATUS status = RET_OK; + /* Restor IRQ enable status */ + MLBMAILBOX_IRQENABLE___0_3WriteRegister32(baseAddress, HW_MBOX_U0_ARM, + mboxsetting.irqEnable0); + MLBMAILBOX_IRQENABLE___0_3WriteRegister32(baseAddress, HW_MBOX_U1_DSP1, + mboxsetting.irqEnable1); + /* Restore Sysconfig register */ + MLBMAILBOX_SYSCONFIGWriteRegister32(baseAddress, mboxsetting.sysconfig); + return status; +} + +/* Reads a u32 from the sub module message box Specified. if there are no + * messages in the mailbox then and error is returned. */ +HW_STATUS HW_MBOX_MsgRead(const u32 baseAddress, const HW_MBOX_Id_t mailBoxId, + u32 *const pReadValue) +{ + HW_STATUS status = RET_OK; + + /* Check input parameters */ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, RES_MBOX_BASE + + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_PARAM(pReadValue, NULL, RET_BAD_NULL_PARAM, RES_MBOX_BASE + + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(mailBoxId, HW_MBOX_ID_MAX, RET_INVALID_ID, + RES_MBOX_BASE + RES_INVALID_INPUT_PARAM); + + /* Read 32-bit message in mail box */ + *pReadValue = MLBMAILBOX_MESSAGE___0_15ReadRegister32(baseAddress, + (u32)mailBoxId); + + return status; +} + +/* Writes a u32 from the sub module message box Specified. */ +HW_STATUS HW_MBOX_MsgWrite(const u32 baseAddress, const HW_MBOX_Id_t mailBoxId, + const u32 writeValue) +{ + HW_STATUS status = RET_OK; + + /* Check input parameters */ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, RES_MBOX_BASE + + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(mailBoxId, HW_MBOX_ID_MAX, RET_INVALID_ID, + RES_MBOX_BASE + RES_INVALID_INPUT_PARAM); + + /* Write 32-bit value to mailbox */ + MLBMAILBOX_MESSAGE___0_15WriteRegister32(baseAddress, (u32)mailBoxId, + (u32)writeValue); + + return status; +} + +/* Gets number of messages in a specified mailbox. */ +HW_STATUS HW_MBOX_NumMsgGet(const u32 baseAddress, const HW_MBOX_Id_t mailBoxId, + u32 *const pNumMsg) +{ + HW_STATUS status = RET_OK; + + /* Check input parameters */ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, RES_MBOX_BASE + + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_PARAM(pNumMsg, NULL, RET_BAD_NULL_PARAM, RES_MBOX_BASE + + RES_INVALID_INPUT_PARAM); + + CHECK_INPUT_RANGE_MIN0(mailBoxId, HW_MBOX_ID_MAX, RET_INVALID_ID, + RES_MBOX_BASE + RES_INVALID_INPUT_PARAM); + + /* Get number of messages available for MailBox */ + *pNumMsg = MLBMAILBOX_MSGSTATUS___0_15NbOfMsgMBmRead32(baseAddress, + (u32)mailBoxId); + + return status; +} + +/* Enables the specified IRQ. */ +HW_STATUS HW_MBOX_EventEnable(const u32 baseAddress, + const HW_MBOX_Id_t mailBoxId, + const HW_MBOX_UserId_t userId, + const u32 events) +{ + HW_STATUS status = RET_OK; + u32 irqEnableReg; + + /* Check input parameters */ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, RES_MBOX_BASE + + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(mailBoxId, HW_MBOX_ID_MAX, RET_INVALID_ID, + RES_MBOX_BASE + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(enableIrq, HW_MBOX_INT_MAX, RET_INVALID_ID, + RES_MBOX_BASE + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(userId, HW_MBOX_USER_MAX, RET_INVALID_ID, + RES_MBOX_BASE + RES_INVALID_INPUT_PARAM); + + /* Get current enable status */ + irqEnableReg = MLBMAILBOX_IRQENABLE___0_3ReadRegister32(baseAddress, + (u32)userId); + + /* update enable value */ + irqEnableReg |= ((u32)(events)) << (((u32)(mailBoxId)) * + HW_MBOX_ID_WIDTH); + + /* write new enable status */ + MLBMAILBOX_IRQENABLE___0_3WriteRegister32(baseAddress, (u32)userId, + (u32)irqEnableReg); + + mboxsetting.sysconfig = MLBMAILBOX_SYSCONFIGReadRegister32(baseAddress); + /* Get current enable status */ + mboxsetting.irqEnable0 = MLBMAILBOX_IRQENABLE___0_3ReadRegister32 + (baseAddress, HW_MBOX_U0_ARM); + mboxsetting.irqEnable1 = MLBMAILBOX_IRQENABLE___0_3ReadRegister32 + (baseAddress, HW_MBOX_U1_DSP1); + return status; +} + +/* Disables the specified IRQ. */ +HW_STATUS HW_MBOX_EventDisable(const u32 baseAddress, + const HW_MBOX_Id_t mailBoxId, + const HW_MBOX_UserId_t userId, + const u32 events) +{ + HW_STATUS status = RET_OK; + u32 irqDisableReg; + + /* Check input parameters */ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, RES_MBOX_BASE + + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(mailBoxId, HW_MBOX_ID_MAX, RET_INVALID_ID, + RES_MBOX_BASE + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(disableIrq, HW_MBOX_INT_MAX, RET_INVALID_ID, + RES_MBOX_BASE + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(userId, HW_MBOX_USER_MAX, RET_INVALID_ID, + RES_MBOX_BASE + RES_INVALID_INPUT_PARAM); + + /* Get current enable status */ + irqDisableReg = MLBMAILBOX_IRQENABLE___0_3ReadRegister32(baseAddress, + (u32)userId); + + /* update enable value */ + irqDisableReg &= ~(((u32)(events)) << (((u32)(mailBoxId)) * + HW_MBOX_ID_WIDTH)); + + /* write new enable status */ + MLBMAILBOX_IRQENABLE___0_3WriteRegister32(baseAddress, (u32)userId, + (u32)irqDisableReg); + + return status; +} + +/* Sets the status of the specified IRQ. */ +HW_STATUS HW_MBOX_EventAck(const u32 baseAddress, const HW_MBOX_Id_t mailBoxId, + const HW_MBOX_UserId_t userId, const u32 event) +{ + HW_STATUS status = RET_OK; + u32 irqStatusReg; + + /* Check input parameters */ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, RES_MBOX_BASE + + RES_INVALID_INPUT_PARAM); + + CHECK_INPUT_RANGE_MIN0(irqStatus, HW_MBOX_INT_MAX, RET_INVALID_ID, + RES_MBOX_BASE + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(mailBoxId, HW_MBOX_ID_MAX, RET_INVALID_ID, + RES_MBOX_BASE + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(userId, HW_MBOX_USER_MAX, RET_INVALID_ID, + RES_MBOX_BASE + RES_INVALID_INPUT_PARAM); + + /* calculate status to write */ + irqStatusReg = ((u32)event) << (((u32)(mailBoxId)) * + HW_MBOX_ID_WIDTH); + + /* clear Irq Status for specified mailbox/User Id */ + MLBMAILBOX_IRQSTATUS___0_3WriteRegister32(baseAddress, (u32)userId, + (u32)irqStatusReg); + + /* + * FIXME: Replace all this custom register access with standard + * __raw_read/write(). + * + * FIXME: Replace all interrupt handlers with standard linux style + * interrupt handlers. + * + * FIXME: Replace direct access to PRCM registers with omap standard + * PRCM register access. + * + * Flush posted write for the irq status to avoid spurious interrupts. + */ + MLBMAILBOX_IRQSTATUS___0_3ReadRegister32(baseAddress, (u32)userId); + + return status; +} diff --git a/drivers/dsp/bridge/hw/hw_mbox.h b/drivers/dsp/bridge/hw/hw_mbox.h new file mode 100644 index 0000000..d2981d3 --- /dev/null +++ b/drivers/dsp/bridge/hw/hw_mbox.h @@ -0,0 +1,323 @@ +/* + * hw_mbox.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== hw_mbox.h ======== + * Description: + * HW Mailbox API and types definitions + * + *! Revision History: + *! ================ + *! 16 Feb 2003 sb: Initial version + */ +#ifndef __MBOX_H +#define __MBOX_H + +/* Bitmasks for Mailbox interrupt sources */ +#define HW_MBOX_INT_NEW_MSG 0x1 +#define HW_MBOX_INT_NOT_FULL 0x2 +#define HW_MBOX_INT_ALL 0x3 + +/* Maximum number of messages that mailbox can hald at a time. */ +#define HW_MBOX_MAX_NUM_MESSAGES 4 + +/* HW_MBOX_Id_t: Enumerated Type used to specify Mailbox Sub Module Id Number */ +typedef enum HW_MBOX_Id_label { + HW_MBOX_ID_0, + HW_MBOX_ID_1, + HW_MBOX_ID_2, + HW_MBOX_ID_3, + HW_MBOX_ID_4, + HW_MBOX_ID_5 + +} HW_MBOX_Id_t, *pHW_MBOX_Id_t; + +/* HW_MBOX_UserId_t: Enumerated Type used to specify Mail box User Id */ +typedef enum HW_MBOX_UserId_label { + HW_MBOX_U0_ARM, + HW_MBOX_U1_DSP1, + HW_MBOX_U2_DSP2, + HW_MBOX_U3_ARM + +} HW_MBOX_UserId_t, *pHW_MBOX_UserId_t; + +/* Mailbox context settings */ +struct MAILBOX_CONTEXT { + u32 sysconfig; + u32 irqEnable0; + u32 irqEnable1; +}; + +/* +* FUNCTION : HW_MBOX_MsgRead +* +* INPUTS: +* +* Identifier : baseAddress +* Type : const u32 +* Description : Base Address of instance of Mailbox module +* +* Identifier : mailBoxId +* Type : const HW_MBOX_Id_t +* Description : Mail Box Sub module Id to read +* +* OUTPUTS: +* +* Identifier : pReadValue +* Type : u32 *const +* Description : Value read from MailBox +* +* RETURNS: +* +* Type : ReturnCode_t +* Description : RET_OK No errors occured +* RET_BAD_NULL_PARAM Address/ptr Paramater was set to 0/NULL +* RET_INVALID_ID Invalid Id used +* RET_EMPTY Mailbox empty +* +* PURPOSE: : this function reads a u32 from the sub module message +* box Specified. if there are no messages in the mailbox +* then and error is returned. +*/ +extern HW_STATUS HW_MBOX_MsgRead(const u32 baseAddress, + const HW_MBOX_Id_t mailBoxId, + u32 *const pReadValue); + +/* +* FUNCTION : HW_MBOX_MsgWrite +* +* INPUTS: +* +* Identifier : baseAddress +* Type : const u32 +* Description : Base Address of instance of Mailbox module +* +* Identifier : mailBoxId +* Type : const HW_MBOX_Id_t +* Description : Mail Box Sub module Id to write +* +* Identifier : writeValue +* Type : const u32 +* Description : Value to write to MailBox +* +* RETURNS: +* +* Type : ReturnCode_t +* Description : RET_OK No errors occured +* RET_BAD_NULL_PARAM Address/pointer Paramater was set to 0/NULL +* RET_INVALID_ID Invalid Id used +* +* PURPOSE: : this function writes a u32 from the sub module message +* box Specified. +*/ +extern HW_STATUS HW_MBOX_MsgWrite( + const u32 baseAddress, + const HW_MBOX_Id_t mailBoxId, + const u32 writeValue + ); + +/* +* FUNCTION : HW_MBOX_NumMsgGet +* +* INPUTS: +* +* Identifier : baseAddress +* Type : const u32 +* Description : Base Address of instance of Mailbox module +* +* Identifier : mailBoxId +* Type : const HW_MBOX_Id_t +* Description : Mail Box Sub module Id to get num messages +* +* OUTPUTS: +* +* Identifier : pNumMsg +* Type : u32 *const +* Description : Number of messages in mailbox +* +* RETURNS: +* +* Type : ReturnCode_t +* Description : RET_OK No errors occured +* RET_BAD_NULL_PARAM Address/pointer Paramater was set to 0/NULL +* RET_INVALID_ID Inavlid ID input at parameter +* +* PURPOSE: : this function gets number of messages in a specified mailbox. +*/ +extern HW_STATUS HW_MBOX_NumMsgGet( + const u32 baseAddress, + const HW_MBOX_Id_t mailBoxId, + u32 *const pNumMsg + ); + +/* +* FUNCTION : HW_MBOX_EventEnable +* +* INPUTS: +* +* Identifier : baseAddress +* Type : const u32 +* RET_BAD_NULL_PARAM Address/pointer Paramater was set to 0/NULL +* +* Identifier : mailBoxId +* Type : const HW_MBOX_Id_t +* Description : Mail Box Sub module Id to enable +* +* Identifier : userId +* Type : const HW_MBOX_UserId_t +* Description : Mail box User Id to enable +* +* Identifier : enableIrq +* Type : const u32 +* Description : Irq value to enable +* +* RETURNS: +* +* Type : ReturnCode_t +* Description : RET_OK No errors occured +* RET_BAD_NULL_PARAM A Pointer Paramater was set to NULL +* RET_INVALID_ID Invalid Id used +* +* PURPOSE: : this function enables the specified IRQ. +*/ +extern HW_STATUS HW_MBOX_EventEnable( + const u32 baseAddress, + const HW_MBOX_Id_t mailBoxId, + const HW_MBOX_UserId_t userId, + const u32 events + ); + +/* +* FUNCTION : HW_MBOX_EventDisable +* +* INPUTS: +* +* Identifier : baseAddress +* Type : const u32 +* RET_BAD_NULL_PARAM Address/pointer Paramater was set to 0/NULL +* +* Identifier : mailBoxId +* Type : const HW_MBOX_Id_t +* Description : Mail Box Sub module Id to disable +* +* Identifier : userId +* Type : const HW_MBOX_UserId_t +* Description : Mail box User Id to disable +* +* Identifier : enableIrq +* Type : const u32 +* Description : Irq value to disable +* +* RETURNS: +* +* Type : ReturnCode_t +* Description : RET_OK No errors occured +* RET_BAD_NULL_PARAM A Pointer Paramater was set to NULL +* RET_INVALID_ID Invalid Id used +* +* PURPOSE: : this function disables the specified IRQ. +*/ +extern HW_STATUS HW_MBOX_EventDisable( + const u32 baseAddress, + const HW_MBOX_Id_t mailBoxId, + const HW_MBOX_UserId_t userId, + const u32 events + ); + +/* +* FUNCTION : HW_MBOX_EventAck +* +* INPUTS: +* +* Identifier : baseAddress +* Type : const u32 +* Description : Base Address of instance of Mailbox module +* +* Identifier : mailBoxId +* Type : const HW_MBOX_Id_t +* Description : Mail Box Sub module Id to set +* +* Identifier : userId +* Type : const HW_MBOX_UserId_t +* Description : Mail box User Id to set +* +* Identifier : irqStatus +* Type : const u32 +* Description : The value to write IRQ status +* +* OUTPUTS: +* +* RETURNS: +* +* Type : ReturnCode_t +* Description : RET_OK No errors occured +* RET_BAD_NULL_PARAM Address Paramater was set to 0 +* RET_INVALID_ID Invalid Id used +* +* PURPOSE: : this function sets the status of the specified IRQ. +*/ +extern HW_STATUS HW_MBOX_EventAck( + const u32 baseAddress, + const HW_MBOX_Id_t mailBoxId, + const HW_MBOX_UserId_t userId, + const u32 event + ); + +/* +* FUNCTION : HW_MBOX_saveSettings +* +* INPUTS: +* +* Identifier : baseAddress +* Type : const u32 +* Description : Base Address of instance of Mailbox module +* +* +* RETURNS: +* +* Type : ReturnCode_t +* Description : RET_OK No errors occured +* RET_BAD_NULL_PARAM Address/pointer Paramater was set to 0/NULL +* RET_INVALID_ID Invalid Id used +* RET_EMPTY Mailbox empty +* +* PURPOSE: : this function saves the context of mailbox +*/ +extern HW_STATUS HW_MBOX_saveSettings(u32 baseAddres); + +/* +* FUNCTION : HW_MBOX_restoreSettings +* +* INPUTS: +* +* Identifier : baseAddress +* Type : const u32 +* Description : Base Address of instance of Mailbox module +* +* +* RETURNS: +* +* Type : ReturnCode_t +* Description : RET_OK No errors occured +* RET_BAD_NULL_PARAM Address/pointer Paramater was set to 0/NULL +* RET_INVALID_ID Invalid Id used +* RET_EMPTY Mailbox empty +* +* PURPOSE: : this function restores the context of mailbox +*/ +extern HW_STATUS HW_MBOX_restoreSettings(u32 baseAddres); + +#endif /* __MBOX_H */ diff --git a/drivers/dsp/bridge/hw/hw_mmu.c b/drivers/dsp/bridge/hw/hw_mmu.c new file mode 100644 index 0000000..ab65de0 --- /dev/null +++ b/drivers/dsp/bridge/hw/hw_mmu.c @@ -0,0 +1,598 @@ +/* + * hw_mmu.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== hw_mmu.c ======== + * Description: + * API definitions to setup MMU TLB and PTE + * + *! Revision History: + *! ================ + *! 19-Apr-2004 sb TLBAdd and TLBFlush input the page size in bytes instead + of an enum. TLBAdd inputs mapping attributes struct instead + of individual arguments. + Removed MMU.h and other cosmetic updates. + *! 08-Mar-2004 sb Added the Page Table Management APIs + *! 16 Feb 2003 sb: Initial version + */ + +#include +#include "MMURegAcM.h" +#include +#include +#include + +#define MMU_BASE_VAL_MASK 0xFC00 +#define MMU_PAGE_MAX 3 +#define MMU_ELEMENTSIZE_MAX 3 +#define MMU_ADDR_MASK 0xFFFFF000 +#define MMU_TTB_MASK 0xFFFFC000 +#define MMU_SECTION_ADDR_MASK 0xFFF00000 +#define MMU_SSECTION_ADDR_MASK 0xFF000000 +#define MMU_PAGE_TABLE_MASK 0xFFFFFC00 +#define MMU_LARGE_PAGE_MASK 0xFFFF0000 +#define MMU_SMALL_PAGE_MASK 0xFFFFF000 + +#define MMU_LOAD_TLB 0x00000001 + +/* HW_MMUPageSize_t: Enumerated Type used to specify the MMU Page Size(SLSS) */ +enum HW_MMUPageSize_t { + HW_MMU_SECTION, + HW_MMU_LARGE_PAGE, + HW_MMU_SMALL_PAGE, + HW_MMU_SUPERSECTION +} ; + +/* +* FUNCTION : MMU_FlushEntry +* +* INPUTS: +* +* Identifier : baseAddress +* Type : const u32 +* Description : Base Address of instance of MMU module +* +* RETURNS: +* +* Type : HW_STATUS +* Description : RET_OK -- No errors occured +* RET_BAD_NULL_PARAM -- A Pointer +* Paramater was set to NULL +* +* PURPOSE: : Flush the TLB entry pointed by the +* lock counter register +* even if this entry is set protected +* +* METHOD: : Check the Input parameter and Flush a +* single entry in the TLB. +*/ +static HW_STATUS MMU_FlushEntry(const u32 baseAddress); + +/* +* FUNCTION : MMU_SetCAMEntry +* +* INPUTS: +* +* Identifier : baseAddress +* TypE : const u32 +* Description : Base Address of instance of MMU module +* +* Identifier : pageSize +* TypE : const u32 +* Description : It indicates the page size +* +* Identifier : preservedBit +* Type : const u32 +* Description : It indicates the TLB entry is preserved entry +* or not +* +* Identifier : validBit +* Type : const u32 +* Description : It indicates the TLB entry is valid entry or not +* +* +* Identifier : virtualAddrTag +* Type : const u32 +* Description : virtual Address +* +* RETURNS: +* +* Type : HW_STATUS +* Description : RET_OK -- No errors occured +* RET_BAD_NULL_PARAM -- A Pointer Paramater +* was set to NULL +* RET_PARAM_OUT_OF_RANGE -- Input Parameter out +* of Range +* +* PURPOSE: : Set MMU_CAM reg +* +* METHOD: : Check the Input parameters and set the CAM entry. +*/ +static HW_STATUS MMU_SetCAMEntry(const u32 baseAddress, + const u32 pageSize, + const u32 preservedBit, + const u32 validBit, + const u32 virtualAddrTag); + +/* +* FUNCTION : MMU_SetRAMEntry +* +* INPUTS: +* +* Identifier : baseAddress +* Type : const u32 +* Description : Base Address of instance of MMU module +* +* Identifier : physicalAddr +* Type : const u32 +* Description : Physical Address to which the corresponding +* virtual Address shouldpoint +* +* Identifier : endianism +* Type : HW_Endianism_t +* Description : endianism for the given page +* +* Identifier : elementSize +* Type : HW_ElementSize_t +* Description : The element size ( 8,16, 32 or 64 bit) +* +* Identifier : mixedSize +* Type : HW_MMUMixedSize_t +* Description : Element Size to follow CPU or TLB +* +* RETURNS: +* +* Type : HW_STATUS +* Description : RET_OK -- No errors occured +* RET_BAD_NULL_PARAM -- A Pointer Paramater +* was set to NULL +* RET_PARAM_OUT_OF_RANGE -- Input Parameter +* out of Range +* +* PURPOSE: : Set MMU_CAM reg +* +* METHOD: : Check the Input parameters and set the RAM entry. +*/ +static HW_STATUS MMU_SetRAMEntry(const u32 baseAddress, + const u32 physicalAddr, + enum HW_Endianism_t endianism, + enum HW_ElementSize_t elementSize, + enum HW_MMUMixedSize_t mixedSize); + +/* HW FUNCTIONS */ + +HW_STATUS HW_MMU_Enable(const u32 baseAddress) +{ + HW_STATUS status = RET_OK; + + MMUMMU_CNTLMMUEnableWrite32(baseAddress, HW_SET); + + return status; +} + +HW_STATUS HW_MMU_Disable(const u32 baseAddress) +{ + HW_STATUS status = RET_OK; + + MMUMMU_CNTLMMUEnableWrite32(baseAddress, HW_CLEAR); + + return status; +} + +HW_STATUS HW_MMU_NumLockedSet(const u32 baseAddress, + u32 numLockedEntries) +{ + HW_STATUS status = RET_OK; + + MMUMMU_LOCKBaseValueWrite32(baseAddress, numLockedEntries); + + return status; +} + +HW_STATUS HW_MMU_VictimNumSet(const u32 baseAddress, + u32 victimEntryNum) +{ + HW_STATUS status = RET_OK; + + MMUMMU_LOCKCurrentVictimWrite32(baseAddress, victimEntryNum); + + return status; +} + +HW_STATUS HW_MMU_EventAck(const u32 baseAddress, u32 irqMask) +{ + HW_STATUS status = RET_OK; + + MMUMMU_IRQSTATUSWriteRegister32(baseAddress, irqMask); + + return status; +} + +HW_STATUS HW_MMU_EventDisable(const u32 baseAddress, + u32 irqMask) +{ + HW_STATUS status = RET_OK; + u32 irqReg; + + irqReg = MMUMMU_IRQENABLEReadRegister32(baseAddress); + + MMUMMU_IRQENABLEWriteRegister32(baseAddress, irqReg & ~irqMask); + + return status; +} + +HW_STATUS HW_MMU_EventEnable(const u32 baseAddress, u32 irqMask) +{ + HW_STATUS status = RET_OK; + u32 irqReg; + + irqReg = MMUMMU_IRQENABLEReadRegister32(baseAddress); + + MMUMMU_IRQENABLEWriteRegister32(baseAddress, irqReg | irqMask); + + return status; +} + + +HW_STATUS HW_MMU_EventStatus(const u32 baseAddress, u32 *irqMask) +{ + HW_STATUS status = RET_OK; + + *irqMask = MMUMMU_IRQSTATUSReadRegister32(baseAddress); + + return status; +} + + +HW_STATUS HW_MMU_FaultAddrRead(const u32 baseAddress, u32 *addr) +{ + HW_STATUS status = RET_OK; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + + /* read values from register */ + *addr = MMUMMU_FAULT_ADReadRegister32(baseAddress); + + return status; +} + +HW_STATUS HW_MMU_TTBSet(const u32 baseAddress, u32 TTBPhysAddr) +{ + HW_STATUS status = RET_OK; + u32 loadTTB; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + + loadTTB = TTBPhysAddr & ~0x7FUL; + /* write values to register */ + MMUMMU_TTBWriteRegister32(baseAddress, loadTTB); + + return status; +} + +HW_STATUS HW_MMU_TWLEnable(const u32 baseAddress) +{ + HW_STATUS status = RET_OK; + + MMUMMU_CNTLTWLEnableWrite32(baseAddress, HW_SET); + + return status; +} + +HW_STATUS HW_MMU_TWLDisable(const u32 baseAddress) +{ + HW_STATUS status = RET_OK; + + MMUMMU_CNTLTWLEnableWrite32(baseAddress, HW_CLEAR); + + return status; +} + +HW_STATUS HW_MMU_TLBFlush(const u32 baseAddress, u32 virtualAddr, + u32 pageSize) +{ + HW_STATUS status = RET_OK; + u32 virtualAddrTag; + enum HW_MMUPageSize_t pgSizeBits; + + switch (pageSize) { + case HW_PAGE_SIZE_4KB: + pgSizeBits = HW_MMU_SMALL_PAGE; + break; + + case HW_PAGE_SIZE_64KB: + pgSizeBits = HW_MMU_LARGE_PAGE; + break; + + case HW_PAGE_SIZE_1MB: + pgSizeBits = HW_MMU_SECTION; + break; + + case HW_PAGE_SIZE_16MB: + pgSizeBits = HW_MMU_SUPERSECTION; + break; + + default: + return RET_FAIL; + } + + /* Generate the 20-bit tag from virtual address */ + virtualAddrTag = ((virtualAddr & MMU_ADDR_MASK) >> 12); + + MMU_SetCAMEntry(baseAddress, pgSizeBits, 0, 0, virtualAddrTag); + + MMU_FlushEntry(baseAddress); + + return status; +} + +HW_STATUS HW_MMU_TLBAdd(const u32 baseAddress, + u32 physicalAddr, + u32 virtualAddr, + u32 pageSize, + u32 entryNum, + struct HW_MMUMapAttrs_t *mapAttrs, + enum HW_SetClear_t preservedBit, + enum HW_SetClear_t validBit) +{ + HW_STATUS status = RET_OK; + u32 lockReg; + u32 virtualAddrTag; + enum HW_MMUPageSize_t mmuPgSize; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(pageSize, MMU_PAGE_MAX, RET_PARAM_OUT_OF_RANGE, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(mapAttrs->elementSize, MMU_ELEMENTSIZE_MAX, + RET_PARAM_OUT_OF_RANGE, RES_MMU_BASE + + RES_INVALID_INPUT_PARAM); + + switch (pageSize) { + case HW_PAGE_SIZE_4KB: + mmuPgSize = HW_MMU_SMALL_PAGE; + break; + + case HW_PAGE_SIZE_64KB: + mmuPgSize = HW_MMU_LARGE_PAGE; + break; + + case HW_PAGE_SIZE_1MB: + mmuPgSize = HW_MMU_SECTION; + break; + + case HW_PAGE_SIZE_16MB: + mmuPgSize = HW_MMU_SUPERSECTION; + break; + + default: + return RET_FAIL; + } + + lockReg = MMUMMU_LOCKReadRegister32(baseAddress); + + /* Generate the 20-bit tag from virtual address */ + virtualAddrTag = ((virtualAddr & MMU_ADDR_MASK) >> 12); + + /* Write the fields in the CAM Entry Register */ + MMU_SetCAMEntry(baseAddress, mmuPgSize, preservedBit, validBit, + virtualAddrTag); + + /* Write the different fields of the RAM Entry Register */ + /* endianism of the page,Element Size of the page (8, 16, 32, 64 bit)*/ + MMU_SetRAMEntry(baseAddress, physicalAddr, mapAttrs->endianism, + mapAttrs->elementSize, mapAttrs->mixedSize); + + /* Update the MMU Lock Register */ + /* currentVictim between lockedBaseValue and (MMU_Entries_Number - 1)*/ + MMUMMU_LOCKCurrentVictimWrite32(baseAddress, entryNum); + + /* Enable loading of an entry in TLB by writing 1 + into LD_TLB_REG register */ + MMUMMU_LD_TLBWriteRegister32(baseAddress, MMU_LOAD_TLB); + + + MMUMMU_LOCKWriteRegister32(baseAddress, lockReg); + + return status; +} + +HW_STATUS HW_MMU_PteSet(const u32 pgTblVa, + u32 physicalAddr, + u32 virtualAddr, + u32 pageSize, + struct HW_MMUMapAttrs_t *mapAttrs) +{ + HW_STATUS status = RET_OK; + u32 pteAddr, pteVal; + s32 numEntries = 1; + + switch (pageSize) { + case HW_PAGE_SIZE_4KB: + pteAddr = HW_MMU_PteAddrL2(pgTblVa, + virtualAddr & MMU_SMALL_PAGE_MASK); + pteVal = ((physicalAddr & MMU_SMALL_PAGE_MASK) | + (mapAttrs->endianism << 9) | + (mapAttrs->elementSize << 4) | + (mapAttrs->mixedSize << 11) | 2 + ); + break; + + case HW_PAGE_SIZE_64KB: + numEntries = 16; + pteAddr = HW_MMU_PteAddrL2(pgTblVa, + virtualAddr & MMU_LARGE_PAGE_MASK); + pteVal = ((physicalAddr & MMU_LARGE_PAGE_MASK) | + (mapAttrs->endianism << 9) | + (mapAttrs->elementSize << 4) | + (mapAttrs->mixedSize << 11) | 1 + ); + break; + + case HW_PAGE_SIZE_1MB: + pteAddr = HW_MMU_PteAddrL1(pgTblVa, + virtualAddr & MMU_SECTION_ADDR_MASK); + pteVal = ((((physicalAddr & MMU_SECTION_ADDR_MASK) | + (mapAttrs->endianism << 15) | + (mapAttrs->elementSize << 10) | + (mapAttrs->mixedSize << 17)) & + ~0x40000) | 0x2 + ); + break; + + case HW_PAGE_SIZE_16MB: + numEntries = 16; + pteAddr = HW_MMU_PteAddrL1(pgTblVa, + virtualAddr & MMU_SSECTION_ADDR_MASK); + pteVal = (((physicalAddr & MMU_SSECTION_ADDR_MASK) | + (mapAttrs->endianism << 15) | + (mapAttrs->elementSize << 10) | + (mapAttrs->mixedSize << 17) + ) | 0x40000 | 0x2 + ); + break; + + case HW_MMU_COARSE_PAGE_SIZE: + pteAddr = HW_MMU_PteAddrL1(pgTblVa, + virtualAddr & MMU_SECTION_ADDR_MASK); + pteVal = (physicalAddr & MMU_PAGE_TABLE_MASK) | 1; + break; + + default: + return RET_FAIL; + } + + while (--numEntries >= 0) + ((u32 *)pteAddr)[numEntries] = pteVal; + + return status; +} + +HW_STATUS HW_MMU_PteClear(const u32 pgTblVa, + u32 virtualAddr, + u32 pgSize) +{ + HW_STATUS status = RET_OK; + u32 pteAddr; + s32 numEntries = 1; + + switch (pgSize) { + case HW_PAGE_SIZE_4KB: + pteAddr = HW_MMU_PteAddrL2(pgTblVa, + virtualAddr & MMU_SMALL_PAGE_MASK); + break; + + case HW_PAGE_SIZE_64KB: + numEntries = 16; + pteAddr = HW_MMU_PteAddrL2(pgTblVa, + virtualAddr & MMU_LARGE_PAGE_MASK); + break; + + case HW_PAGE_SIZE_1MB: + case HW_MMU_COARSE_PAGE_SIZE: + pteAddr = HW_MMU_PteAddrL1(pgTblVa, + virtualAddr & MMU_SECTION_ADDR_MASK); + break; + + case HW_PAGE_SIZE_16MB: + numEntries = 16; + pteAddr = HW_MMU_PteAddrL1(pgTblVa, + virtualAddr & MMU_SSECTION_ADDR_MASK); + break; + + default: + return RET_FAIL; + } + + while (--numEntries >= 0) + ((u32 *)pteAddr)[numEntries] = 0; + + return status; +} + +/* MMU_FlushEntry */ +static HW_STATUS MMU_FlushEntry(const u32 baseAddress) +{ + HW_STATUS status = RET_OK; + u32 flushEntryData = 0x1; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + + /* write values to register */ + MMUMMU_FLUSH_ENTRYWriteRegister32(baseAddress, flushEntryData); + + return status; +} + +/* MMU_SetCAMEntry */ +static HW_STATUS MMU_SetCAMEntry(const u32 baseAddress, + const u32 pageSize, + const u32 preservedBit, + const u32 validBit, + const u32 virtualAddrTag) +{ + HW_STATUS status = RET_OK; + u32 mmuCamReg; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + + mmuCamReg = (virtualAddrTag << 12); + mmuCamReg = (mmuCamReg) | (pageSize) | (validBit << 2) | + (preservedBit << 3) ; + + /* write values to register */ + MMUMMU_CAMWriteRegister32(baseAddress, mmuCamReg); + + return status; +} + +/* MMU_SetRAMEntry */ +static HW_STATUS MMU_SetRAMEntry(const u32 baseAddress, + const u32 physicalAddr, + enum HW_Endianism_t endianism, + enum HW_ElementSize_t elementSize, + enum HW_MMUMixedSize_t mixedSize) +{ + HW_STATUS status = RET_OK; + u32 mmuRamReg; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(elementSize, MMU_ELEMENTSIZE_MAX, + RET_PARAM_OUT_OF_RANGE, RES_MMU_BASE + + RES_INVALID_INPUT_PARAM); + + + mmuRamReg = (physicalAddr & MMU_ADDR_MASK); + mmuRamReg = (mmuRamReg) | ((endianism << 9) | (elementSize << 7) | + (mixedSize << 6)); + + /* write values to register */ + MMUMMU_RAMWriteRegister32(baseAddress, mmuRamReg); + + return status; + +} diff --git a/drivers/dsp/bridge/hw/hw_mmu.h b/drivers/dsp/bridge/hw/hw_mmu.h new file mode 100644 index 0000000..a3dd2a8 --- /dev/null +++ b/drivers/dsp/bridge/hw/hw_mmu.h @@ -0,0 +1,177 @@ +/* + * hw_mmu.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== hw_mmu.h ======== + * Description: + * MMU types and API declarations + * + *! Revision History: + *! ================ + *! 19-Apr-2004 sb Moved & renamed endianness, page size, element size + TLBAdd takes in MMUMapAttrs instead of separate arguments + *! 08-Mar-2004 sb Added the Page Table management APIs + *! 16 Feb 2003 sb: Initial version + */ +#ifndef __HW_MMU_H +#define __HW_MMU_H + +#include + +/* Bitmasks for interrupt sources */ +#define HW_MMU_TRANSLATION_FAULT 0x2 +#define HW_MMU_ALL_INTERRUPTS 0x1F + +#define HW_MMU_COARSE_PAGE_SIZE 0x400 + +/* HW_MMUMixedSize_t: Enumerated Type used to specify whether to follow + CPU/TLB Element size */ +enum HW_MMUMixedSize_t { + HW_MMU_TLBES, + HW_MMU_CPUES + +} ; + +/* HW_MMUMapAttrs_t: Struct containing MMU mapping attributes */ +struct HW_MMUMapAttrs_t { + enum HW_Endianism_t endianism; + enum HW_ElementSize_t elementSize; + enum HW_MMUMixedSize_t mixedSize; + bool donotlockmpupage; +} ; + +extern HW_STATUS HW_MMU_Enable(const u32 baseAddress); + +extern HW_STATUS HW_MMU_Disable(const u32 baseAddress); + +extern HW_STATUS HW_MMU_NumLockedSet(const u32 baseAddress, + u32 numLockedEntries); + +extern HW_STATUS HW_MMU_VictimNumSet(const u32 baseAddress, + u32 victimEntryNum); + +/* For MMU faults */ +extern HW_STATUS HW_MMU_EventAck(const u32 baseAddress, + u32 irqMask); + +extern HW_STATUS HW_MMU_EventDisable(const u32 baseAddress, + u32 irqMask); + +extern HW_STATUS HW_MMU_EventEnable(const u32 baseAddress, + u32 irqMask); + +extern HW_STATUS HW_MMU_EventStatus(const u32 baseAddress, + u32 *irqMask); + +extern HW_STATUS HW_MMU_FaultAddrRead(const u32 baseAddress, + u32 *addr); + +/* Set the TT base address */ +extern HW_STATUS HW_MMU_TTBSet(const u32 baseAddress, + u32 TTBPhysAddr); + +extern HW_STATUS HW_MMU_TWLEnable(const u32 baseAddress); + +extern HW_STATUS HW_MMU_TWLDisable(const u32 baseAddress); + +extern HW_STATUS HW_MMU_TLBFlush(const u32 baseAddress, + u32 virtualAddr, + u32 pageSize); + +extern HW_STATUS HW_MMU_TLBAdd(const u32 baseAddress, + u32 physicalAddr, + u32 virtualAddr, + u32 pageSize, + u32 entryNum, + struct HW_MMUMapAttrs_t *mapAttrs, + enum HW_SetClear_t preservedBit, + enum HW_SetClear_t validBit); + + +/* For PTEs */ +extern HW_STATUS HW_MMU_PteSet(const u32 pgTblVa, + u32 physicalAddr, + u32 virtualAddr, + u32 pageSize, + struct HW_MMUMapAttrs_t *mapAttrs); + +extern HW_STATUS HW_MMU_PteClear(const u32 pgTblVa, + u32 pgSize, + u32 virtualAddr); + +static inline u32 HW_MMU_PteAddrL1(u32 L1_base, u32 va) +{ + u32 pteAddr; + u32 VA_31_to_20; + + VA_31_to_20 = va >> (20 - 2); /* Left-shift by 2 here itself */ + VA_31_to_20 &= 0xFFFFFFFCUL; + pteAddr = L1_base + VA_31_to_20; + + return pteAddr; +} + +static inline u32 HW_MMU_PteAddrL2(u32 L2_base, u32 va) +{ + u32 pteAddr; + + pteAddr = (L2_base & 0xFFFFFC00) | ((va >> 10) & 0x3FC); + + return pteAddr; +} + +static inline u32 HW_MMU_PteCoarseL1(u32 pteVal) +{ + u32 pteCoarse; + + pteCoarse = pteVal & 0xFFFFFC00; + + return pteCoarse; +} + +static inline u32 HW_MMU_PteSizeL1(u32 pteVal) +{ + u32 pteSize = 0; + + if ((pteVal & 0x3) == 0x1) { + /* Points to L2 PT */ + pteSize = HW_MMU_COARSE_PAGE_SIZE; + } + + if ((pteVal & 0x3) == 0x2) { + if (pteVal & (1 << 18)) + pteSize = HW_PAGE_SIZE_16MB; + else + pteSize = HW_PAGE_SIZE_1MB; + } + + return pteSize; +} + +static inline u32 HW_MMU_PteSizeL2(u32 pteVal) +{ + u32 pteSize = 0; + + if (pteVal & 0x2) + pteSize = HW_PAGE_SIZE_4KB; + else if (pteVal & 0x1) + pteSize = HW_PAGE_SIZE_64KB; + + return pteSize; +} + +#endif /* __HW_MMU_H */ diff --git a/drivers/dsp/bridge/hw/hw_prcm.c b/drivers/dsp/bridge/hw/hw_prcm.c new file mode 100644 index 0000000..61ff08f --- /dev/null +++ b/drivers/dsp/bridge/hw/hw_prcm.c @@ -0,0 +1,167 @@ +/* + * hw_prcm.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== hw_prcm.c ======== + * Description: + * API definitions to configure PRCM (Power, Reset & Clocks Manager) + * + *! Revision History: + *! ================ + *! 16 Feb 2003 sb: Initial version + */ + +#include +#include "PRCMRegAcM.h" +#include +#include + +static HW_STATUS HW_RST_WriteVal(const u32 baseAddress, + enum HW_RstModule_t r, + enum HW_SetClear_t val); + +HW_STATUS HW_RST_Reset(const u32 baseAddress, enum HW_RstModule_t r) +{ + return HW_RST_WriteVal(baseAddress, r, HW_SET); +} + +HW_STATUS HW_RST_UnReset(const u32 baseAddress, enum HW_RstModule_t r) +{ + return HW_RST_WriteVal(baseAddress, r, HW_CLEAR); +} + +static HW_STATUS HW_RST_WriteVal(const u32 baseAddress, + enum HW_RstModule_t r, + enum HW_SetClear_t val) +{ + HW_STATUS status = RET_OK; + + switch (r) { + case HW_RST1_IVA2: + PRM_RSTCTRL_IVA2RST1_DSPWrite32(baseAddress, val); + break; + case HW_RST2_IVA2: + PRM_RSTCTRL_IVA2RST2_DSPWrite32(baseAddress, val); + break; + case HW_RST3_IVA2: + PRM_RSTCTRL_IVA2RST3_DSPWrite32(baseAddress, val); + break; + default: + status = RET_FAIL; + break; + } + return status; +} + +HW_STATUS HW_PWR_IVA2StateGet(const u32 baseAddress, enum HW_PwrModule_t p, + enum HW_PwrState_t *value) +{ + HW_STATUS status = RET_OK; + u32 temp; + + switch (p) { + case HW_PWR_DOMAIN_DSP: + /* wait until Transition is complete */ + do { + /* mdelay(1); */ + temp = PRCMPM_PWSTST_IVA2InTransitionRead32 + (baseAddress); + + } while (temp); + + temp = PRCMPM_PWSTST_IVA2ReadRegister32(baseAddress); + *value = PRCMPM_PWSTST_IVA2PowerStateStGet32(temp); + break; + + default: + status = RET_FAIL; + break; + } + return status; +} + +HW_STATUS HW_PWRST_IVA2RegGet(const u32 baseAddress, u32 *value) +{ + HW_STATUS status = RET_OK; + + *value = PRCMPM_PWSTST_IVA2ReadRegister32(baseAddress); + + return status; +} + + +HW_STATUS HW_PWR_IVA2PowerStateSet(const u32 baseAddress, + enum HW_PwrModule_t p, + enum HW_PwrState_t value) +{ + HW_STATUS status = RET_OK; + + switch (p) { + case HW_PWR_DOMAIN_DSP: + switch (value) { + case HW_PWR_STATE_ON: + PRCMPM_PWSTCTRL_IVA2PowerStateWriteON32(baseAddress); + break; + case HW_PWR_STATE_RET: + PRCMPM_PWSTCTRL_DSPPowerStateWriteRET32(baseAddress); + break; + case HW_PWR_STATE_OFF: + PRCMPM_PWSTCTRL_IVA2PowerStateWriteOFF32(baseAddress); + break; + default: + status = RET_FAIL; + break; + } + break; + + default: + status = RET_FAIL; + break; + } + + return status; +} + +HW_STATUS HW_PWR_CLKCTRL_IVA2RegSet(const u32 baseAddress, + enum HW_TransitionState_t val) +{ + HW_STATUS status = RET_OK; + + PRCMCM_CLKSTCTRL_IVA2WriteRegister32(baseAddress, val); + + return status; + +} + +HW_STATUS HW_RSTST_RegGet(const u32 baseAddress, enum HW_RstModule_t m, + u32 *value) +{ + HW_STATUS status = RET_OK; + + *value = PRCMRM_RSTST_DSPReadRegister32(baseAddress); + + return status; +} + +HW_STATUS HW_RSTCTRL_RegGet(const u32 baseAddress, enum HW_RstModule_t m, + u32 *value) +{ + HW_STATUS status = RET_OK; + + *value = PRCMRM_RSTCTRL_DSPReadRegister32(baseAddress); + + return status; +} diff --git a/drivers/dsp/bridge/hw/hw_prcm.h b/drivers/dsp/bridge/hw/hw_prcm.h new file mode 100644 index 0000000..928486c --- /dev/null +++ b/drivers/dsp/bridge/hw/hw_prcm.h @@ -0,0 +1,168 @@ +/* + * hw_prcm.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== hw_prcm.h ======== + * Description: + * PRCM types and API declarations + * + *! Revision History: + *! ================ + *! 16 Feb 2003 sb: Initial version + */ + +#ifndef __HW_PRCM_H +#define __HW_PRCM_H + +/* HW_ClkModule: Enumerated Type used to specify the clock domain */ + +enum HW_ClkModule_t { +/* DSP Domain */ + HW_CLK_DSP_CPU, + HW_CLK_DSP_IPI_MMU, + HW_CLK_IVA_ARM, + HW_CLK_IVA_COP, /* IVA Coprocessor */ + +/* Core Domain */ + HW_CLK_FN_WDT4, /* Functional Clock */ + HW_CLK_FN_WDT3, + HW_CLK_FN_UART2, + HW_CLK_FN_UART1, + HW_CLK_GPT5, + HW_CLK_GPT6, + HW_CLK_GPT7, + HW_CLK_GPT8, + + HW_CLK_IF_WDT4, /* Interface Clock */ + HW_CLK_IF_WDT3, + HW_CLK_IF_UART2, + HW_CLK_IF_UART1, + HW_CLK_IF_MBOX + +} ; + +enum HW_ClkSubsys_t { + HW_CLK_DSPSS, + HW_CLK_IVASS +} ; + +/* HW_GPtimers: General purpose timers */ +enum HW_GPtimer_t { + HW_GPT5 = 5, + HW_GPT6 = 6, + HW_GPT7 = 7, + HW_GPT8 = 8 +} ; + + +/* GP timers Input clock type: General purpose timers */ +enum HW_Clocktype_t { + HW_CLK_32KHz = 0, + HW_CLK_SYS = 1, + HW_CLK_EXT = 2 +} ; + +/* HW_ClkDiv: Clock divisors */ +enum HW_ClkDiv_t { + HW_CLK_DIV_1 = 0x1, + HW_CLK_DIV_2 = 0x2, + HW_CLK_DIV_3 = 0x3, + HW_CLK_DIV_4 = 0x4, + HW_CLK_DIV_6 = 0x6, + HW_CLK_DIV_8 = 0x8, + HW_CLK_DIV_12 = 0xC +} ; + +/* HW_RstModule: Enumerated Type used to specify the module to be reset */ +enum HW_RstModule_t { + HW_RST1_IVA2, /* Reset the DSP */ + HW_RST2_IVA2, /* Reset MMU and LEON HWa */ + HW_RST3_IVA2 /* Reset LEON sequencer */ +} ; + +/* HW_PwrModule: Enumerated Type used to specify the power domain */ +enum HW_PwrModule_t { +/* Domains */ + HW_PWR_DOMAIN_CORE, + HW_PWR_DOMAIN_MPU, + HW_PWR_DOMAIN_WAKEUP, + HW_PWR_DOMAIN_DSP, + +/* Sub-domains */ + HW_PWR_DSP_IPI, /* IPI = Intrusive Port Interface */ + HW_PWR_IVA_ISP /* ISP = Intrusive Slave Port */ +} ; + +enum HW_PwrState_t { + HW_PWR_STATE_OFF, + HW_PWR_STATE_RET, + HW_PWR_STATE_INACT, + HW_PWR_STATE_ON = 3 +} ; + +enum HW_ForceState_t { + HW_FORCE_OFF, + HW_FORCE_ON +} ; + +enum HW_IdleState_t { + HW_ACTIVE, + HW_STANDBY + +} ; + +enum HW_TransitionState_t { + HW_AUTOTRANS_DIS, + HW_SW_SUP_SLEEP, + HW_SW_SUP_WAKEUP, + HW_AUTOTRANS_EN +} ; + + +extern HW_STATUS HW_RST_Reset(const u32 baseAddress, + enum HW_RstModule_t r); + +extern HW_STATUS HW_RST_UnReset(const u32 baseAddress, + enum HW_RstModule_t r); + +extern HW_STATUS HW_RSTCTRL_RegGet(const u32 baseAddress, + enum HW_RstModule_t p, + u32 *value); +extern HW_STATUS HW_RSTST_RegGet(const u32 baseAddress, + enum HW_RstModule_t p, u32 *value); + +extern HW_STATUS HW_PWR_PowerStateSet(const u32 baseAddress, + enum HW_PwrModule_t p, + enum HW_PwrState_t value); + +extern HW_STATUS HW_CLK_SetInputClock(const u32 baseAddress, + enum HW_GPtimer_t gpt, + enum HW_Clocktype_t c); + +extern HW_STATUS HW_PWR_IVA2StateGet(const u32 baseAddress, + enum HW_PwrModule_t p, + enum HW_PwrState_t *value); + +extern HW_STATUS HW_PWRST_IVA2RegGet(const u32 baseAddress, u32 *value); + +extern HW_STATUS HW_PWR_IVA2PowerStateSet(const u32 baseAddress, + enum HW_PwrModule_t p, + enum HW_PwrState_t value); + +extern HW_STATUS HW_PWR_CLKCTRL_IVA2RegSet(const u32 baseAddress, + enum HW_TransitionState_t val); + +#endif /* __HW_PRCM_H */ diff --git a/drivers/dsp/bridge/pmgr/chnl.c b/drivers/dsp/bridge/pmgr/chnl.c new file mode 100644 index 0000000..6b5a0d9 --- /dev/null +++ b/drivers/dsp/bridge/pmgr/chnl.c @@ -0,0 +1,260 @@ +/* + * chnl.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== chnl.c ======== + * Description: + * WCD channel interface: multiplexes data streams through the single + * physical link managed by a 'Bridge mini-driver. + * + * Public Functions: + * CHNL_Close + * CHNL_CloseOrphans + * CHNL_Create + * CHNL_Destroy + * CHNL_Exit + * CHNL_GetHandle + * CHNL_GetProcessHandle + * CHNL_Init + * CHNL_Open + * + * Notes: + * This interface is basically a pass through to the WMD CHNL functions, + * except for the CHNL_Get() accessor functions which call + * WMD_CHNL_GetInfo(). + * + *! Revision History: + *! ================ + *! 24-Feb-2003 swa PMGR Code review comments incorporated. + *! 07-Jan-2002 ag CHNL_CloseOrphans() now closes supported # of channels. + *! 17-Nov-2000 jeh Removed IRQ, shared memory stuff from CHNL_Create. + *! 28-Feb-2000 rr: New GT USage Implementation + *! 03-Feb-2000 rr: GT and Module init/exit Changes.(Done up front from + *! SERVICES) + *! 21-Jan-2000 ag: Added code review comments. + *! 13-Jan-2000 rr: CFG_Get/SetPrivateDword renamed to CFG_Get/SetDevObject. + *! 08-Dec-1999 ag: CHNL_[Alloc|Free]Buffer bufs taken from client process heap. + *! 02-Dec-1999 ag: Implemented CHNL_GetEventHandle(). + *! 17-Nov-1999 ag: CHNL_AllocBuffer() allocs extra word for process mapping. + *! 28-Oct-1999 ag: WinCE port. Search for "WinCE" for changes(TBR). + *! 07-Jan-1998 gp: CHNL_[Alloc|Free]Buffer now call MEM_UMB functions. + *! 22-Oct-1997 gp: Removed requirement in CHNL_Open that hReserved1 != NULL. + *! 30-Aug-1997 cr: Renamed cfg.h wbwcd.h b/c of WINNT file name collision. + *! 10-Mar-1997 gp: Added GT trace. + *! 14-Jan-1997 gp: Updated based on code review feedback. + *! 03-Jan-1997 gp: Moved CHNL_AllocBuffer/CHNL_FreeBuffer code from udspsys. + *! 14-Dec-1996 gp: Added uChnlId parameter to CHNL_Open(). + *! 09-Sep-1996 gp: Added CHNL_GetProcessHandle(). + *! 15-Jul-1996 gp: Created. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include +#include +#include + +/* ----------------------------------- Platform Manager */ +#include +#include + +/* ----------------------------------- Others */ +#include +#include + +/* ----------------------------------- This */ +#include + +/* ----------------------------------- Globals */ +static u32 cRefs; +#if GT_TRACE +static struct GT_Mask CHNL_DebugMask = { NULL, NULL }; /* WCD CHNL Mask */ +#endif + + + +/* + * ======== CHNL_Create ======== + * Purpose: + * Create a channel manager object, responsible for opening new channels + * and closing old ones for a given 'Bridge board. + */ +DSP_STATUS CHNL_Create(OUT struct CHNL_MGR **phChnlMgr, + struct DEV_OBJECT *hDevObject, + IN CONST struct CHNL_MGRATTRS *pMgrAttrs) +{ + DSP_STATUS status; + struct CHNL_MGR *hChnlMgr; + struct CHNL_MGR_ *pChnlMgr = NULL; + + DBC_Require(cRefs > 0); + DBC_Require(phChnlMgr != NULL); + DBC_Require(pMgrAttrs != NULL); + + GT_3trace(CHNL_DebugMask, GT_ENTER, + "Entered CHNL_Create: phChnlMgr: 0x%x\t" + "hDevObject: 0x%x\tpMgrAttrs:0x%x\n", + phChnlMgr, hDevObject, pMgrAttrs); + + *phChnlMgr = NULL; + + /* Validate args: */ + if ((0 < pMgrAttrs->cChannels) && + (pMgrAttrs->cChannels <= CHNL_MAXCHANNELS)) { + status = DSP_SOK; + } else if (pMgrAttrs->cChannels == 0) { + status = DSP_EINVALIDARG; + GT_0trace(CHNL_DebugMask, GT_7CLASS, + "CHNL_Create:Invalid Args\n"); + } else { + status = CHNL_E_MAXCHANNELS; + GT_0trace(CHNL_DebugMask, GT_7CLASS, + "CHNL_Create:Error Max Channels\n"); + } + if (pMgrAttrs->uWordSize == 0) { + status = CHNL_E_INVALIDWORDSIZE; + GT_0trace(CHNL_DebugMask, GT_7CLASS, + "CHNL_Create:Invalid Word size\n"); + } + if (DSP_SUCCEEDED(status)) { + status = DEV_GetChnlMgr(hDevObject, &hChnlMgr); + if (DSP_SUCCEEDED(status) && hChnlMgr != NULL) + status = CHNL_E_MGREXISTS; + + } + + if (DSP_SUCCEEDED(status)) { + struct WMD_DRV_INTERFACE *pIntfFxns; + DEV_GetIntfFxns(hDevObject, &pIntfFxns); + /* Let WMD channel module finish the create: */ + status = (*pIntfFxns->pfnChnlCreate)(&hChnlMgr, hDevObject, + pMgrAttrs); + if (DSP_SUCCEEDED(status)) { + /* Fill in WCD channel module's fields of the + * CHNL_MGR structure */ + pChnlMgr = (struct CHNL_MGR_ *)hChnlMgr; + pChnlMgr->pIntfFxns = pIntfFxns; + /* Finally, return the new channel manager handle: */ + *phChnlMgr = hChnlMgr; + GT_1trace(CHNL_DebugMask, GT_1CLASS, + "CHNL_Create: Success pChnlMgr:" + "0x%x\n", pChnlMgr); + } + } + + GT_2trace(CHNL_DebugMask, GT_ENTER, + "Exiting CHNL_Create: pChnlMgr: 0x%x," + "status: 0x%x\n", pChnlMgr, status); + DBC_Ensure(DSP_FAILED(status) || CHNL_IsValidMgr(pChnlMgr)); + + return status; +} + +/* + * ======== CHNL_Destroy ======== + * Purpose: + * Close all open channels, and destroy the channel manager. + */ +DSP_STATUS CHNL_Destroy(struct CHNL_MGR *hChnlMgr) +{ + struct CHNL_MGR_ *pChnlMgr = (struct CHNL_MGR_ *)hChnlMgr; + struct WMD_DRV_INTERFACE *pIntfFxns; + DSP_STATUS status; + + DBC_Require(cRefs > 0); + + GT_1trace(CHNL_DebugMask, GT_ENTER, + "Entered CHNL_Destroy: hChnlMgr: 0x%x\n", hChnlMgr); + if (CHNL_IsValidMgr(pChnlMgr)) { + pIntfFxns = pChnlMgr->pIntfFxns; + /* Let WMD channel module destroy the CHNL_MGR: */ + status = (*pIntfFxns->pfnChnlDestroy)(hChnlMgr); + } else { + GT_0trace(CHNL_DebugMask, GT_7CLASS, + "CHNL_Destroy:Invalid Handle\n"); + status = DSP_EHANDLE; + } + + GT_2trace(CHNL_DebugMask, GT_ENTER, + "Exiting CHNL_Destroy: pChnlMgr: 0x%x," + " status:0x%x\n", pChnlMgr, status); + DBC_Ensure(DSP_FAILED(status) || !CHNL_IsValidMgr(pChnlMgr)); + + return status; +} + +/* + * ======== CHNL_Exit ======== + * Purpose: + * Discontinue usage of the CHNL module. + */ +void CHNL_Exit(void) +{ + DBC_Require(cRefs > 0); + + cRefs--; + + GT_1trace(CHNL_DebugMask, GT_5CLASS, + "Entered CHNL_Exit, ref count: 0x%x\n", cRefs); + + DBC_Ensure(cRefs >= 0); +} + + +/* + * ======== CHNL_Init ======== + * Purpose: + * Initialize the CHNL module's private state. + */ +bool CHNL_Init(void) +{ + bool fRetval = true; + + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { + DBC_Assert(!CHNL_DebugMask.flags); + GT_create(&CHNL_DebugMask, "CH"); /* "CH" for CHannel */ + } + + if (fRetval) + cRefs++; + + GT_1trace(CHNL_DebugMask, GT_5CLASS, + "Entered CHNL_Init, ref count: 0x%x\n", + cRefs); + + DBC_Ensure((fRetval && (cRefs > 0)) || (!fRetval && (cRefs >= 0))); + + return fRetval; +} + + diff --git a/drivers/dsp/bridge/pmgr/chnlobj.h b/drivers/dsp/bridge/pmgr/chnlobj.h new file mode 100644 index 0000000..da74c96 --- /dev/null +++ b/drivers/dsp/bridge/pmgr/chnlobj.h @@ -0,0 +1,71 @@ +/* + * chnlobj.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== chnlobj.h ======== + * Description: + * Structure subcomponents of channel class library channel objects which + * are exposed to class driver from mini-driver. + * + * Public Functions: + * None. + * + *! Revision History: + *! ================ + *! 24-Feb-2003 swa PMGR Code review comments incorporated. + *! 17-Nov-2000 jeh Removed some fields from CHNL_MGR_ to match CHNL_MGR + *! structure defined in _chnl_sm.h. + *! 16-Jan-1997 gp: Created from chnlpriv.h + */ + +#ifndef CHNLOBJ_ +#define CHNLOBJ_ + +#include +#include + +/* Object validateion macros: */ +#define CHNL_IsValidMgr(h) \ + ((h != NULL) && ((h)->dwSignature == CHNL_MGRSIGNATURE)) + +#define CHNL_IsValidChnl(h)\ + ((h != NULL) && ((h)->dwSignature == CHNL_SIGNATURE)) + +/* + * This struct is the first field in a CHNL_MGR struct, as implemented in + * a WMD channel class library. Other, implementation specific fields + * follow this structure in memory. + */ +struct CHNL_MGR_ { + /* These must be the first fields in a CHNL_MGR struct: */ + u32 dwSignature; /* Used for object validation. */ + struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD. */ +} ; + +/* + * This struct is the first field in a CHNL_OBJECT struct, as implemented in + * a WMD channel class library. Other, implementation specific fields + * follow this structure in memory. + */ +struct CHNL_OBJECT_ { + /* These must be the first fields in a CHNL_OBJECT struct: */ + u32 dwSignature; /* Used for object validation. */ + struct CHNL_MGR_ *pChnlMgr; /* Pointer back to channel manager. */ +} ; + +#endif /* CHNLOBJ_ */ + diff --git a/drivers/dsp/bridge/pmgr/cmm.c b/drivers/dsp/bridge/pmgr/cmm.c new file mode 100644 index 0000000..99a2432 --- /dev/null +++ b/drivers/dsp/bridge/pmgr/cmm.c @@ -0,0 +1,1291 @@ +/* + * cmm.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== cmm.c ======== + * Purpose: + * The Communication(Shared) Memory Management(CMM) module provides + * shared memory management services for DSP/BIOS Bridge data streaming + * and messaging. + * + * Multiple shared memory segments can be registered with CMM. + * Each registered SM segment is represented by a SM "allocator" that + * describes a block of physically contiguous shared memory used for + * future allocations by CMM. + * + * Memory is coelesced back to the appropriate heap when a buffer is + * freed. + * + * Public Functions: + * CMM_CallocBuf + * CMM_Create + * CMM_Destroy + * CMM_Exit + * CMM_FreeBuf + * CMM_GetHandle + * CMM_GetInfo + * CMM_Init + * CMM_RegisterGPPSMSeg + * CMM_UnRegisterGPPSMSeg + * + * The CMM_Xlator[xxx] routines below are used by Node and Stream + * to perform SM address translation to the client process address space. + * A "translator" object is created by a node/stream for each SM seg used. + * + * Translator Routines: + * CMM_XlatorAllocBuf + * CMM_XlatorCreate + * CMM_XlatorDelete + * CMM_XlatorFreeBuf + * CMM_XlatorInfo + * CMM_XlatorTranslate + * + * Private Functions: + * AddToFreeList + * GetAllocator + * GetFreeBlock + * GetNode + * GetSlot + * UnRegisterGPPSMSeg + * + * Notes: + * Va: Virtual address. + * Pa: Physical or kernel system address. + * + *! Revision History: + *! ================ + *! 24-Feb-2003 swa PMGR Code review comments incorporated. + *! 16-Feb-2002 ag Code review cleanup. + *! PreOMAP address translation no longner supported. + *! 30-Jan-2002 ag Updates to CMM_XlatorTranslate() per TII, ANSI C++ + *! warnings. + *! 27-Jan-2002 ag Removed unused CMM_[Alloc][Free]Desc() & #ifdef USELOOKUP, + *! & unused VALIDATECMM and VaPaConvert(). + *! Removed bFastXlate from CMM_XLATOR. Always fast lookup. + *! 03-Jan-2002 ag Clear SM in CMM_AllocBuf(). Renamed to CMM_CallocBuf(). + *! 13-Nov-2001 ag Now delete pNodeFreeListHead and nodes in CMM_Destroy(). + *! 28-Aug-2001 ag CMM_GetHandle() returns CMM Mgr hndle given HPROCESSOR. + *! Removed unused CMM_[Un]RegisterDSPSMSeg() & + * CMM_[Un}ReserveVirtSpace fxns. Some cleanup. + *! 12-Aug-2001 ag Exposed CMM_UnRegisterGPP[DSP]SMSeg. + *! 13-Feb-2001 kc DSP/BIOS Bridge name update. + *! 21-Dec-2000 rr GetFreeBlock checks for pAllocator. + *! 09-Dec-2000 ag Added GPPPA2DSPPA, DSPPA2GPPPA macros. + *! 05-Dec-2000 ag CMM_XlatorDelete() optionally frees SM bufs and descriptors. + *! 30-Oct-2000 ag Buf size bug fixed in CMM_AllocBuf() causing leak. + *! Revamped XlatorTranslate() routine. + *! 10-Oct-2000 ag Added CMM_Xlator[xxx] functions. + *! 02-Aug-2000 ag Created. + *! + */ + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include +#include + +/* ----------------------------------- Platform Manager */ +#include +#include + +/* ----------------------------------- This */ +#include + +/* ----------------------------------- Defines, Data Structures, Typedefs */ +/* Object signatures */ +#define CMMSIGNATURE 0x004d4d43 /* "CMM" (in reverse) */ +#define SMEMSIGNATURE 0x4D454D53 /* "SMEM" SM space */ +#define CMMXLATESIGNATURE 0x584d4d43 /* "CMMX" CMM Xlator */ + +#define NEXT_PA(pNode) (pNode->dwPA + pNode->ulSize) + +/* Other bus/platform translations */ +#define DSPPA2GPPPA(base, x, y) ((x)+(y)) +#define GPPPA2DSPPA(base, x, y) ((x)-(y)) + +/* + * Allocators define a block of contiguous memory used for future allocations. + * + * sma - shared memory allocator. + * vma - virtual memory allocator.(not used). + */ +struct CMM_ALLOCATOR { /* sma */ + u32 dwSignature; /* SMA allocator signature SMEMSIGNATURE */ + unsigned int dwSmBase; /* Start of physical SM block */ + u32 ulSmSize; /* Size of SM block in bytes */ + unsigned int dwVmBase; /* Start of VM block. (Dev driver + * context for 'sma') */ + u32 dwDSPPhysAddrOffset; /* DSP PA to GPP PA offset for this + * SM space */ + /* CMM_ADDTO[SUBFROM]DSPPA, _POMAPEMIF2DSPBUS */ + enum CMM_CNVTTYPE cFactor; + unsigned int dwDSPBase; /* DSP virt base byte address */ + u32 ulDSPSize; /* DSP seg size in bytes */ + struct CMM_OBJECT *hCmmMgr; /* back ref to parent mgr */ + struct LST_LIST *pFreeListHead; /* node list of available memory */ + struct LST_LIST *pInUseListHead; /* node list of memory in use */ +} ; + +struct CMM_XLATOR { /* Pa<->Va translator object */ + u32 dwSignature; /* "CMMX" */ + struct CMM_OBJECT *hCmmMgr; /* CMM object this translator associated */ + /* + * Client process virtual base address that corresponds to phys SM + * base address for translator's ulSegId. + * Only 1 segment ID currently supported. + */ + unsigned int dwVirtBase; /* virtual base address */ + u32 ulVirtSize; /* size of virt space in bytes */ + u32 ulSegId; /* Segment Id */ +} ; + +/* CMM Mgr */ +struct CMM_OBJECT { + u32 dwSignature; /* Used for object validation */ + /* + * Cmm Lock is used to serialize access mem manager for multi-threads. + */ + struct SYNC_CSOBJECT *hCmmLock; /* Lock to access cmm mgr */ + struct LST_LIST *pNodeFreeListHead; /* Free list of memory nodes */ + u32 ulMinBlockSize; /* Min SM block; default 16 bytes */ + u32 dwPageSize; /* Memory Page size (1k/4k) */ + /* GPP SM segment ptrs */ + struct CMM_ALLOCATOR *paGPPSMSegTab[CMM_MAXGPPSEGS]; +} ; + +/* Default CMM Mgr attributes */ +static struct CMM_MGRATTRS CMM_DFLTMGRATTRS = { + 16 /* ulMinBlockSize, min block size(bytes) allocated by cmm mgr */ +}; + +/* Default allocation attributes */ +static struct CMM_ATTRS CMM_DFLTALCTATTRS = { + 1 /* ulSegId, default segment Id for allocator */ +}; + +/* Address translator default attrs */ +static struct CMM_XLATORATTRS CMM_DFLTXLATORATTRS = { + 1, /* ulSegId, does not have to match CMM_DFLTALCTATTRS ulSegId */ + 0, /* dwDSPBufs */ + 0, /* dwDSPBufSize */ + NULL, /* pVmBase */ + 0, /* dwVmSize */ +}; + +/* SM node representing a block of memory. */ +struct CMM_MNODE { + struct LST_ELEM link; /* must be 1st element */ + u32 dwPA; /* Phys addr */ + u32 dwVA; /* Virtual address in device process context */ + u32 ulSize; /* SM block size in bytes */ + u32 hClientProc; /* Process that allocated this mem block */ +} ; + + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask CMM_debugMask = { NULL, NULL }; /* GT trace variable */ +#endif + +static u32 cRefs; /* module reference count */ + +/* ----------------------------------- Function Prototypes */ +static void AddToFreeList(struct CMM_ALLOCATOR *pAllocator, + struct CMM_MNODE *pNode); +static struct CMM_ALLOCATOR *GetAllocator(struct CMM_OBJECT *pCmmMgr, + u32 ulSegId); +static struct CMM_MNODE *GetFreeBlock(struct CMM_ALLOCATOR *pAllocator, + u32 uSize); +static struct CMM_MNODE *GetNode(struct CMM_OBJECT *pCmmMgr, u32 dwPA, + u32 dwVA, u32 ulSize); +/* get available slot for new allocator */ +static s32 GetSlot(struct CMM_OBJECT *hCmmMgr); +static void UnRegisterGPPSMSeg(struct CMM_ALLOCATOR *pSMA); + +/* + * ======== CMM_CallocBuf ======== + * Purpose: + * Allocate a SM buffer, zero contents, and return the physical address + * and optional driver context virtual address(ppBufVA). + * + * The freelist is sorted in increasing size order. Get the first + * block that satifies the request and sort the remaining back on + * the freelist; if large enough. The kept block is placed on the + * inUseList. + */ +void *CMM_CallocBuf(struct CMM_OBJECT *hCmmMgr, u32 uSize, + struct CMM_ATTRS *pAttrs, OUT void **ppBufVA) +{ + struct CMM_OBJECT *pCmmMgr = (struct CMM_OBJECT *)hCmmMgr; + void *pBufPA = NULL; + struct CMM_MNODE *pNode = NULL; + struct CMM_MNODE *pNewNode = NULL; + struct CMM_ALLOCATOR *pAllocator = NULL; + u32 uDeltaSize; + u8 *pByte = NULL; + s32 cnt; + + if (pAttrs == NULL) + pAttrs = &CMM_DFLTALCTATTRS; + + if (ppBufVA != NULL) + *ppBufVA = NULL; + + if ((MEM_IsValidHandle(pCmmMgr, CMMSIGNATURE)) && (uSize != 0)) { + if (pAttrs->ulSegId > 0) { + /* SegId > 0 is SM */ + /* get the allocator object for this segment id */ + pAllocator = GetAllocator(pCmmMgr, pAttrs->ulSegId); + /* keep block size a multiple of ulMinBlockSize */ + uSize = ((uSize - 1) & ~(pCmmMgr->ulMinBlockSize - 1)) + + pCmmMgr->ulMinBlockSize; + SYNC_EnterCS(pCmmMgr->hCmmLock); + pNode = GetFreeBlock(pAllocator, uSize); + } + if (pNode) { + uDeltaSize = (pNode->ulSize - uSize); + if (uDeltaSize >= pCmmMgr->ulMinBlockSize) { + /* create a new block with the leftovers and + * add to freelist */ + pNewNode = GetNode(pCmmMgr, pNode->dwPA + uSize, + pNode->dwVA + uSize, + (u32)uDeltaSize); + /* leftovers go free */ + AddToFreeList(pAllocator, pNewNode); + /* adjust our node's size */ + pNode->ulSize = uSize; + } + /* Tag node with client process requesting allocation + * We'll need to free up a process's alloc'd SM if the + * client process goes away. + */ + /* Return PID instead of process handle */ + pNode->hClientProc = current->pid; + + /* put our node on InUse list */ + LST_PutTail(pAllocator->pInUseListHead, + (struct LST_ELEM *)pNode); + pBufPA = (void *)pNode->dwPA; /* physical address */ + /* clear mem */ + pByte = (u8 *)pNode->dwVA; + for (cnt = 0; cnt < (s32) uSize; cnt++, pByte++) + *pByte = 0; + + if (ppBufVA != NULL) { + /* Virtual address */ + *ppBufVA = (void *)pNode->dwVA; + } + } + GT_3trace(CMM_debugMask, GT_3CLASS, + "CMM_CallocBuf dwPA %x, dwVA %x uSize" + "%x\n", pNode->dwPA, pNode->dwVA, uSize); + SYNC_LeaveCS(pCmmMgr->hCmmLock); + } + return pBufPA; +} + +/* + * ======== CMM_Create ======== + * Purpose: + * Create a communication memory manager object. + */ +DSP_STATUS CMM_Create(OUT struct CMM_OBJECT **phCmmMgr, + struct DEV_OBJECT *hDevObject, + IN CONST struct CMM_MGRATTRS *pMgrAttrs) +{ + struct CMM_OBJECT *pCmmObject = NULL; + DSP_STATUS status = DSP_SOK; + struct UTIL_SYSINFO sysInfo; + + DBC_Require(cRefs > 0); + DBC_Require(phCmmMgr != NULL); + + GT_3trace(CMM_debugMask, GT_ENTER, + "CMM_Create: phCmmMgr: 0x%x\thDevObject: " + "0x%x\tpMgrAttrs: 0x%x\n", phCmmMgr, hDevObject, pMgrAttrs); + *phCmmMgr = NULL; + /* create, zero, and tag a cmm mgr object */ + MEM_AllocObject(pCmmObject, struct CMM_OBJECT, CMMSIGNATURE); + if (pCmmObject != NULL) { + if (pMgrAttrs == NULL) + pMgrAttrs = &CMM_DFLTMGRATTRS; /* set defaults */ + + /* 4 bytes minimum */ + DBC_Assert(pMgrAttrs->ulMinBlockSize >= 4); + /* save away smallest block allocation for this cmm mgr */ + pCmmObject->ulMinBlockSize = pMgrAttrs->ulMinBlockSize; + /* save away the systems memory page size */ + sysInfo.dwPageSize = PAGE_SIZE; + sysInfo.dwAllocationGranularity = PAGE_SIZE; + sysInfo.dwNumberOfProcessors = 1; + if (DSP_SUCCEEDED(status)) { + GT_1trace(CMM_debugMask, GT_5CLASS, + "CMM_Create: Got system page size" + "= 0x%x\t\n", sysInfo.dwPageSize); + pCmmObject->dwPageSize = sysInfo.dwPageSize; + } else { + GT_0trace(CMM_debugMask, GT_7CLASS, + "CMM_Create: failed to get system" + "page size\n"); + pCmmObject->dwPageSize = 0; + status = DSP_EFAIL; + } + /* Note: DSP SM seg table(aDSPSMSegTab[]) zero'd by + * MEM_AllocObject */ + if (DSP_SUCCEEDED(status)) { + /* create node free list */ + pCmmObject->pNodeFreeListHead = LST_Create(); + if (pCmmObject->pNodeFreeListHead == NULL) { + GT_0trace(CMM_debugMask, GT_7CLASS, + "CMM_Create: LST_Create() " + "failed \n"); + status = DSP_EMEMORY; + } + } + if (DSP_SUCCEEDED(status)) + status = SYNC_InitializeCS(&pCmmObject->hCmmLock); + + if (DSP_SUCCEEDED(status)) + *phCmmMgr = pCmmObject; + else + CMM_Destroy(pCmmObject, true); + + } else { + GT_0trace(CMM_debugMask, GT_6CLASS, + "CMM_Create: Object Allocation " + "Failure(CMM Object)\n"); + status = DSP_EMEMORY; + } + return status; +} + +/* + * ======== CMM_Destroy ======== + * Purpose: + * Release the communication memory manager resources. + */ +DSP_STATUS CMM_Destroy(struct CMM_OBJECT *hCmmMgr, bool bForce) +{ + struct CMM_OBJECT *pCmmMgr = (struct CMM_OBJECT *)hCmmMgr; + struct CMM_INFO tempInfo; + DSP_STATUS status = DSP_SOK; + s32 nSlot; + struct CMM_MNODE *pNode; + + DBC_Require(cRefs > 0); + if (!MEM_IsValidHandle(hCmmMgr, CMMSIGNATURE)) { + status = DSP_EHANDLE; + return status; + } + SYNC_EnterCS(pCmmMgr->hCmmLock); + /* If not force then fail if outstanding allocations exist */ + if (!bForce) { + /* Check for outstanding memory allocations */ + status = CMM_GetInfo(hCmmMgr, &tempInfo); + if (DSP_SUCCEEDED(status)) { + if (tempInfo.ulTotalInUseCnt > 0) { + /* outstanding allocations */ + status = DSP_EFAIL; + } + } + } + if (DSP_SUCCEEDED(status)) { + /* UnRegister SM allocator */ + for (nSlot = 0; nSlot < CMM_MAXGPPSEGS; nSlot++) { + if (pCmmMgr->paGPPSMSegTab[nSlot] != NULL) { + UnRegisterGPPSMSeg(pCmmMgr-> + paGPPSMSegTab[nSlot]); + /* Set slot to NULL for future reuse */ + pCmmMgr->paGPPSMSegTab[nSlot] = NULL; + } + } + } + if (pCmmMgr->pNodeFreeListHead != NULL) { + /* Free the free nodes */ + while (!LST_IsEmpty(pCmmMgr->pNodeFreeListHead)) { + /* (struct LST_ELEM*) pNode = + * LST_GetHead(pCmmMgr->pNodeFreeListHead);*/ + pNode = (struct CMM_MNODE *)LST_GetHead(pCmmMgr-> + pNodeFreeListHead); + MEM_Free(pNode); + } + /* delete NodeFreeList list */ + LST_Delete(pCmmMgr->pNodeFreeListHead); + } + SYNC_LeaveCS(pCmmMgr->hCmmLock); + if (DSP_SUCCEEDED(status)) { + /* delete CS & cmm mgr object */ + SYNC_DeleteCS(pCmmMgr->hCmmLock); + MEM_FreeObject(pCmmMgr); + } + return status; +} + +/* + * ======== CMM_Exit ======== + * Purpose: + * Discontinue usage of module; free resources when reference count + * reaches 0. + */ +void CMM_Exit(void) +{ + DBC_Require(cRefs > 0); + + cRefs--; + + GT_1trace(CMM_debugMask, GT_ENTER, + "exiting CMM_Exit,ref count:0x%x\n", cRefs); +} + +/* + * ======== CMM_FreeBuf ======== + * Purpose: + * Free the given buffer. + */ +DSP_STATUS CMM_FreeBuf(struct CMM_OBJECT *hCmmMgr, void *pBufPA, u32 ulSegId) +{ + struct CMM_OBJECT *pCmmMgr = (struct CMM_OBJECT *)hCmmMgr; + DSP_STATUS status = DSP_EPOINTER; + struct CMM_MNODE *pCurNode = NULL; + struct CMM_ALLOCATOR *pAllocator = NULL; + struct CMM_ATTRS *pAttrs; + + DBC_Require(cRefs > 0); + DBC_Require(pBufPA != NULL); + GT_1trace(CMM_debugMask, GT_ENTER, "CMM_FreeBuf pBufPA %x\n", pBufPA); + if (ulSegId == 0) { + pAttrs = &CMM_DFLTALCTATTRS; + ulSegId = pAttrs->ulSegId; + } + if (!(MEM_IsValidHandle(hCmmMgr, CMMSIGNATURE)) || !(ulSegId > 0)) { + status = DSP_EHANDLE; + return status; + } + /* get the allocator for this segment id */ + pAllocator = GetAllocator(pCmmMgr, ulSegId); + if (pAllocator != NULL) { + SYNC_EnterCS(pCmmMgr->hCmmLock); + pCurNode = (struct CMM_MNODE *)LST_First(pAllocator-> + pInUseListHead); + while (pCurNode) { + if ((u32)pBufPA == pCurNode->dwPA) { + /* Found it */ + LST_RemoveElem(pAllocator->pInUseListHead, + (struct LST_ELEM *)pCurNode); + /* back to freelist */ + AddToFreeList(pAllocator, pCurNode); + status = DSP_SOK; /* all right! */ + break; + } + /* next node. */ + pCurNode = (struct CMM_MNODE *)LST_Next(pAllocator-> + pInUseListHead, (struct LST_ELEM *)pCurNode); + } + SYNC_LeaveCS(pCmmMgr->hCmmLock); + } + return status; +} + +/* + * ======== CMM_GetHandle ======== + * Purpose: + * Return the communication memory manager object for this device. + * This is typically called from the client process. + */ +DSP_STATUS CMM_GetHandle(DSP_HPROCESSOR hProcessor, + OUT struct CMM_OBJECT **phCmmMgr) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *hDevObject; + + DBC_Require(cRefs > 0); + DBC_Require(phCmmMgr != NULL); + if (hProcessor != NULL) + status = PROC_GetDevObject(hProcessor, &hDevObject); + else + hDevObject = DEV_GetFirst(); /* default */ + + if (DSP_SUCCEEDED(status)) + status = DEV_GetCmmMgr(hDevObject, phCmmMgr); + + return status; +} + +/* + * ======== CMM_GetInfo ======== + * Purpose: + * Return the current memory utilization information. + */ +DSP_STATUS CMM_GetInfo(struct CMM_OBJECT *hCmmMgr, + OUT struct CMM_INFO *pCmmInfo) +{ + struct CMM_OBJECT *pCmmMgr = (struct CMM_OBJECT *)hCmmMgr; + u32 ulSeg; + DSP_STATUS status = DSP_SOK; + struct CMM_ALLOCATOR *pAltr; + struct CMM_MNODE *pCurNode = NULL; + + DBC_Require(pCmmInfo != NULL); + + if (!MEM_IsValidHandle(hCmmMgr, CMMSIGNATURE)) { + status = DSP_EHANDLE; + return status; + } + SYNC_EnterCS(pCmmMgr->hCmmLock); + pCmmInfo->ulNumGPPSMSegs = 0; /* # of SM segments */ + pCmmInfo->ulTotalInUseCnt = 0; /* Total # of outstanding alloc */ + pCmmInfo->ulMinBlockSize = pCmmMgr->ulMinBlockSize; /* min block size */ + /* check SM memory segments */ + for (ulSeg = 1; ulSeg <= CMM_MAXGPPSEGS; ulSeg++) { + /* get the allocator object for this segment id */ + pAltr = GetAllocator(pCmmMgr, ulSeg); + if (pAltr != NULL) { + pCmmInfo->ulNumGPPSMSegs++; + pCmmInfo->segInfo[ulSeg - 1].dwSegBasePa = + pAltr->dwSmBase - pAltr->ulDSPSize; + pCmmInfo->segInfo[ulSeg - 1].ulTotalSegSize = + pAltr->ulDSPSize + pAltr->ulSmSize; + pCmmInfo->segInfo[ulSeg - 1].dwGPPBasePA = + pAltr->dwSmBase; + pCmmInfo->segInfo[ulSeg - 1].ulGPPSize = + pAltr->ulSmSize; + pCmmInfo->segInfo[ulSeg - 1].dwDSPBaseVA = + pAltr->dwDSPBase; + pCmmInfo->segInfo[ulSeg - 1].ulDSPSize = + pAltr->ulDSPSize; + pCmmInfo->segInfo[ulSeg - 1].dwSegBaseVa = + pAltr->dwVmBase - pAltr->ulDSPSize; + pCmmInfo->segInfo[ulSeg - 1].ulInUseCnt = 0; + pCurNode = (struct CMM_MNODE *)LST_First(pAltr-> + pInUseListHead); + /* Count inUse blocks */ + while (pCurNode) { + pCmmInfo->ulTotalInUseCnt++; + pCmmInfo->segInfo[ulSeg - 1].ulInUseCnt++; + /* next node. */ + pCurNode = (struct CMM_MNODE *)LST_Next(pAltr-> + pInUseListHead, + (struct LST_ELEM *)pCurNode); + } + } + } /* end for */ + SYNC_LeaveCS(pCmmMgr->hCmmLock); + return status; +} + +/* + * ======== CMM_Init ======== + * Purpose: + * Initializes private state of CMM module. + */ +bool CMM_Init(void) +{ + bool fRetval = true; + + DBC_Require(cRefs >= 0); + if (cRefs == 0) { + /* Set the Trace mask */ + /* "CM" for Comm Memory manager */ + GT_create(&CMM_debugMask, "CM"); + } + if (fRetval) + cRefs++; + + GT_1trace(CMM_debugMask, GT_ENTER, + "Entered CMM_Init,ref count:0x%x\n", cRefs); + + DBC_Ensure((fRetval && (cRefs > 0)) || (!fRetval && (cRefs >= 0))); + + return fRetval; +} + +/* + * ======== CMM_RegisterGPPSMSeg ======== + * Purpose: + * Register a block of SM with the CMM to be used for later GPP SM + * allocations. + */ +DSP_STATUS CMM_RegisterGPPSMSeg(struct CMM_OBJECT *hCmmMgr, u32 dwGPPBasePA, + u32 ulSize, u32 dwDSPAddrOffset, + enum CMM_CNVTTYPE cFactor, u32 dwDSPBase, + u32 ulDSPSize, u32 *pulSegId, + u32 dwGPPBaseVA) +{ + struct CMM_OBJECT *pCmmMgr = (struct CMM_OBJECT *)hCmmMgr; + struct CMM_ALLOCATOR *pSMA = NULL; + DSP_STATUS status = DSP_SOK; + struct CMM_MNODE *pNewNode; + s32 nSlot; + + DBC_Require(ulSize > 0); + DBC_Require(pulSegId != NULL); + DBC_Require(dwGPPBasePA != 0); + DBC_Require(dwGPPBaseVA != 0); + DBC_Require((cFactor <= CMM_ADDTODSPPA) && + (cFactor >= CMM_SUBFROMDSPPA)); + GT_6trace(CMM_debugMask, GT_ENTER, + "CMM_RegisterGPPSMSeg dwGPPBasePA %x " + "ulSize %x dwDSPAddrOffset %x dwDSPBase %x ulDSPSize %x " + "dwGPPBaseVA %x\n", dwGPPBasePA, ulSize, dwDSPAddrOffset, + dwDSPBase, ulDSPSize, dwGPPBaseVA); + if (!MEM_IsValidHandle(hCmmMgr, CMMSIGNATURE)) { + status = DSP_EHANDLE; + return status; + } + /* make sure we have room for another allocator */ + SYNC_EnterCS(pCmmMgr->hCmmLock); + nSlot = GetSlot(pCmmMgr); + if (nSlot < 0) { + /* get a slot number */ + status = DSP_EFAIL; + goto func_end; + } + /* Check if input ulSize is big enough to alloc at least one block */ + if (DSP_SUCCEEDED(status)) { + if (ulSize < pCmmMgr->ulMinBlockSize) { + GT_0trace(CMM_debugMask, GT_7CLASS, + "CMM_RegisterGPPSMSeg: " + "ulSize too small\n"); + status = DSP_EINVALIDARG; + goto func_end; + } + } + if (DSP_SUCCEEDED(status)) { + /* create, zero, and tag an SM allocator object */ + MEM_AllocObject(pSMA, struct CMM_ALLOCATOR, SMEMSIGNATURE); + } + if (pSMA != NULL) { + pSMA->hCmmMgr = hCmmMgr; /* ref to parent */ + pSMA->dwSmBase = dwGPPBasePA; /* SM Base phys */ + pSMA->ulSmSize = ulSize; /* SM segment size in bytes */ + pSMA->dwVmBase = dwGPPBaseVA; + pSMA->dwDSPPhysAddrOffset = dwDSPAddrOffset; + pSMA->cFactor = cFactor; + pSMA->dwDSPBase = dwDSPBase; + pSMA->ulDSPSize = ulDSPSize; + if (pSMA->dwVmBase == 0) { + GT_0trace(CMM_debugMask, GT_7CLASS, + "CMM_RegisterGPPSMSeg: Error" + "MEM_LinearAddress()\n"); + status = DSP_EFAIL; + goto func_end; + } + if (DSP_SUCCEEDED(status)) { + /* return the actual segment identifier */ + *pulSegId = (u32) nSlot + 1; + /* create memory free list */ + pSMA->pFreeListHead = LST_Create(); + if (pSMA->pFreeListHead == NULL) { + GT_0trace(CMM_debugMask, GT_7CLASS, + "CMM_RegisterGPPSMSeg: " + "Out Of Memory \n"); + status = DSP_EMEMORY; + goto func_end; + } + } + if (DSP_SUCCEEDED(status)) { + /* create memory in-use list */ + pSMA->pInUseListHead = LST_Create(); + if (pSMA->pInUseListHead == NULL) { + GT_0trace(CMM_debugMask, GT_7CLASS, + "CMM_RegisterGPPSMSeg: " + "LST_Create failed\n"); + status = DSP_EMEMORY; + goto func_end; + } + } + if (DSP_SUCCEEDED(status)) { + /* Get a mem node for this hunk-o-memory */ + pNewNode = GetNode(pCmmMgr, dwGPPBasePA, + pSMA->dwVmBase, ulSize); + /* Place node on the SM allocator's free list */ + if (pNewNode) { + LST_PutTail(pSMA->pFreeListHead, + (struct LST_ELEM *)pNewNode); + } else { + status = DSP_EMEMORY; + goto func_end; + } + } + if (DSP_FAILED(status)) { + /* Cleanup allocator */ + UnRegisterGPPSMSeg(pSMA); + } + } else { + GT_0trace(CMM_debugMask, GT_6CLASS, + "CMM_RegisterGPPSMSeg: SMA Object " + "Allocation Failure\n"); + status = DSP_EMEMORY; + goto func_end; + } + /* make entry */ + if (DSP_SUCCEEDED(status)) + pCmmMgr->paGPPSMSegTab[nSlot] = pSMA; + +func_end: + SYNC_LeaveCS(pCmmMgr->hCmmLock); + return status; +} + +/* + * ======== CMM_UnRegisterGPPSMSeg ======== + * Purpose: + * UnRegister GPP SM segments with the CMM. + */ +DSP_STATUS CMM_UnRegisterGPPSMSeg(struct CMM_OBJECT *hCmmMgr, u32 ulSegId) +{ + struct CMM_OBJECT *pCmmMgr = (struct CMM_OBJECT *)hCmmMgr; + DSP_STATUS status = DSP_SOK; + struct CMM_ALLOCATOR *pSMA; + u32 ulId = ulSegId; + + DBC_Require(ulSegId > 0); + if (MEM_IsValidHandle(hCmmMgr, CMMSIGNATURE)) { + if (ulSegId == CMM_ALLSEGMENTS) + ulId = 1; + + if ((ulId > 0) && (ulId <= CMM_MAXGPPSEGS)) { + while (ulId <= CMM_MAXGPPSEGS) { + SYNC_EnterCS(pCmmMgr->hCmmLock); + /* slot = segId-1 */ + pSMA = pCmmMgr->paGPPSMSegTab[ulId - 1]; + if (pSMA != NULL) { + UnRegisterGPPSMSeg(pSMA); + /* Set alctr ptr to NULL for future + * reuse */ + pCmmMgr->paGPPSMSegTab[ulId - 1] = NULL; + } else if (ulSegId != CMM_ALLSEGMENTS) { + status = DSP_EFAIL; + } + SYNC_LeaveCS(pCmmMgr->hCmmLock); + if (ulSegId != CMM_ALLSEGMENTS) + break; + + ulId++; + } /* end while */ + } else { + status = DSP_EINVALIDARG; + GT_0trace(CMM_debugMask, GT_7CLASS, + "CMM_UnRegisterGPPSMSeg: Bad " + "segment Id\n"); + } + } else { + status = DSP_EHANDLE; + } + return status; +} + +/* + * ======== UnRegisterGPPSMSeg ======== + * Purpose: + * UnRegister the SM allocator by freeing all its resources and + * nulling cmm mgr table entry. + * Note: + * This routine is always called within cmm lock crit sect. + */ +static void UnRegisterGPPSMSeg(struct CMM_ALLOCATOR *pSMA) +{ + struct CMM_MNODE *pCurNode = NULL; + struct CMM_MNODE *pNextNode = NULL; + + DBC_Require(pSMA != NULL); + if (pSMA->pFreeListHead != NULL) { + /* free nodes on free list */ + pCurNode = (struct CMM_MNODE *)LST_First(pSMA->pFreeListHead); + while (pCurNode) { + pNextNode = (struct CMM_MNODE *)LST_Next(pSMA-> + pFreeListHead, + (struct LST_ELEM *)pCurNode); + LST_RemoveElem(pSMA->pFreeListHead, + (struct LST_ELEM *)pCurNode); + MEM_Free((void *) pCurNode); + /* next node. */ + pCurNode = pNextNode; + } + LST_Delete(pSMA->pFreeListHead); /* delete freelist */ + /* free nodes on InUse list */ + pCurNode = (struct CMM_MNODE *)LST_First(pSMA->pInUseListHead); + while (pCurNode) { + pNextNode = (struct CMM_MNODE *)LST_Next(pSMA-> + pInUseListHead, + (struct LST_ELEM *)pCurNode); + LST_RemoveElem(pSMA->pInUseListHead, + (struct LST_ELEM *)pCurNode); + MEM_Free((void *) pCurNode); + /* next node. */ + pCurNode = pNextNode; + } + LST_Delete(pSMA->pInUseListHead); /* delete InUse list */ + } + if ((void *) pSMA->dwVmBase != NULL) + MEM_UnmapLinearAddress((void *) pSMA->dwVmBase); + + /* Free allocator itself */ + MEM_FreeObject(pSMA); +} + +/* + * ======== GetSlot ======== + * Purpose: + * An available slot # is returned. Returns negative on failure. + */ +static s32 GetSlot(struct CMM_OBJECT *pCmmMgr) +{ + s32 nSlot = -1; /* neg on failure */ + DBC_Require(pCmmMgr != NULL); + /* get first available slot in cmm mgr SMSegTab[] */ + for (nSlot = 0; nSlot < CMM_MAXGPPSEGS; nSlot++) { + if (pCmmMgr->paGPPSMSegTab[nSlot] == NULL) + break; + + } + if (nSlot == CMM_MAXGPPSEGS) { + GT_0trace(CMM_debugMask, GT_7CLASS, + "CMM_RegisterGPPSMSeg: Allocator " + "entry failure, max exceeded\n"); + nSlot = -1; /* failed */ + } + return nSlot; +} + +/* + * ======== GetNode ======== + * Purpose: + * Get a memory node from freelist or create a new one. + */ +static struct CMM_MNODE *GetNode(struct CMM_OBJECT *pCmmMgr, u32 dwPA, + u32 dwVA, u32 ulSize) +{ + struct CMM_MNODE *pNode = NULL; + + DBC_Require(pCmmMgr != NULL); + DBC_Require(dwPA != 0); + DBC_Require(dwVA != 0); + DBC_Require(ulSize != 0); + /* Check cmm mgr's node freelist */ + if (LST_IsEmpty(pCmmMgr->pNodeFreeListHead)) { + pNode = (struct CMM_MNODE *)MEM_Calloc(sizeof(struct CMM_MNODE), + MEM_PAGED); + } else { + /* surely a valid element */ + /* (struct LST_ELEM*) pNode = LST_GetHead(pCmmMgr-> + * pNodeFreeListHead);*/ + pNode = (struct CMM_MNODE *)LST_GetHead(pCmmMgr-> + pNodeFreeListHead); + } + if (pNode == NULL) { + GT_0trace(CMM_debugMask, GT_7CLASS, "GetNode: Out Of Memory\n"); + } else { + LST_InitElem((struct LST_ELEM *) pNode); /* set self */ + pNode->dwPA = dwPA; /* Physical addr of start of block */ + pNode->dwVA = dwVA; /* Virtual " " */ + pNode->ulSize = ulSize; /* Size of block */ + } + return pNode; +} + +/* + * ======== DeleteNode ======== + * Purpose: + * Put a memory node on the cmm nodelist for later use. + * Doesn't actually delete the node. Heap thrashing friendly. + */ +static void DeleteNode(struct CMM_OBJECT *pCmmMgr, struct CMM_MNODE *pNode) +{ + DBC_Require(pNode != NULL); + LST_InitElem((struct LST_ELEM *) pNode); /* init .self ptr */ + LST_PutTail(pCmmMgr->pNodeFreeListHead, (struct LST_ELEM *) pNode); +} + +/* + * ====== GetFreeBlock ======== + * Purpose: + * Scan the free block list and return the first block that satisfies + * the size. + */ +static struct CMM_MNODE *GetFreeBlock(struct CMM_ALLOCATOR *pAllocator, + u32 uSize) +{ + if (pAllocator) { + struct CMM_MNODE *pCurNode = (struct CMM_MNODE *) + LST_First(pAllocator->pFreeListHead); + while (pCurNode) { + if (uSize <= (u32) pCurNode->ulSize) { + LST_RemoveElem(pAllocator->pFreeListHead, + (struct LST_ELEM *)pCurNode); + return pCurNode; + } + /* next node. */ + pCurNode = (struct CMM_MNODE *)LST_Next(pAllocator-> + pFreeListHead, (struct LST_ELEM *)pCurNode); + } + } + return NULL; +} + +/* + * ======== AddToFreeList ======== + * Purpose: + * Coelesce node into the freelist in ascending size order. + */ +static void AddToFreeList(struct CMM_ALLOCATOR *pAllocator, + struct CMM_MNODE *pNode) +{ + struct CMM_MNODE *pNodePrev = NULL; + struct CMM_MNODE *pNodeNext = NULL; + struct CMM_MNODE *pCurNode; + u32 dwThisPA; + u32 dwNextPA; + + DBC_Require(pNode != NULL); + DBC_Require(pAllocator != NULL); + dwThisPA = pNode->dwPA; + dwNextPA = NEXT_PA(pNode); + pCurNode = (struct CMM_MNODE *)LST_First(pAllocator->pFreeListHead); + while (pCurNode) { + if (dwThisPA == NEXT_PA(pCurNode)) { + /* found the block ahead of this one */ + pNodePrev = pCurNode; + } else if (dwNextPA == pCurNode->dwPA) { + pNodeNext = pCurNode; + } + if ((pNodePrev == NULL) || (pNodeNext == NULL)) { + /* next node. */ + pCurNode = (struct CMM_MNODE *)LST_Next(pAllocator-> + pFreeListHead, (struct LST_ELEM *)pCurNode); + } else { + /* got 'em */ + break; + } + } /* while */ + if (pNodePrev != NULL) { + /* combine with previous block */ + LST_RemoveElem(pAllocator->pFreeListHead, + (struct LST_ELEM *)pNodePrev); + /* grow node to hold both */ + pNode->ulSize += pNodePrev->ulSize; + pNode->dwPA = pNodePrev->dwPA; + pNode->dwVA = pNodePrev->dwVA; + /* place node on mgr nodeFreeList */ + DeleteNode((struct CMM_OBJECT *)pAllocator->hCmmMgr, pNodePrev); + } + if (pNodeNext != NULL) { + /* combine with next block */ + LST_RemoveElem(pAllocator->pFreeListHead, + (struct LST_ELEM *)pNodeNext); + /* grow da node */ + pNode->ulSize += pNodeNext->ulSize; + /* place node on mgr nodeFreeList */ + DeleteNode((struct CMM_OBJECT *)pAllocator->hCmmMgr, pNodeNext); + } + /* Now, let's add to freelist in increasing size order */ + pCurNode = (struct CMM_MNODE *)LST_First(pAllocator->pFreeListHead); + while (pCurNode) { + if (pNode->ulSize <= pCurNode->ulSize) + break; + + /* next node. */ + pCurNode = (struct CMM_MNODE *)LST_Next(pAllocator-> + pFreeListHead, (struct LST_ELEM *)pCurNode); + } + /* if pCurNode is NULL then add our pNode to the end of the freelist */ + if (pCurNode == NULL) { + LST_PutTail(pAllocator->pFreeListHead, + (struct LST_ELEM *)pNode); + } else { + /* insert our node before the current traversed node */ + LST_InsertBefore(pAllocator->pFreeListHead, + (struct LST_ELEM *)pNode, + (struct LST_ELEM *)pCurNode); + } +} + +/* + * ======== GetAllocator ======== + * Purpose: + * Return the allocator for the given SM Segid. + * SegIds: 1,2,3..max. + */ +static struct CMM_ALLOCATOR *GetAllocator(struct CMM_OBJECT *pCmmMgr, + u32 ulSegId) +{ + struct CMM_ALLOCATOR *pAllocator = NULL; + + DBC_Require(pCmmMgr != NULL); + DBC_Require((ulSegId > 0) && (ulSegId <= CMM_MAXGPPSEGS)); + pAllocator = pCmmMgr->paGPPSMSegTab[ulSegId - 1]; + if (pAllocator != NULL) { + /* make sure it's for real */ + if (!MEM_IsValidHandle(pAllocator, SMEMSIGNATURE)) { + pAllocator = NULL; + DBC_Assert(false); + } + } + return pAllocator; +} + +/* + * ======== CMM_XlatorCreate ======== + * Purpose: + * Create an address translator object. + */ +DSP_STATUS CMM_XlatorCreate(OUT struct CMM_XLATOROBJECT **phXlator, + struct CMM_OBJECT *hCmmMgr, + struct CMM_XLATORATTRS *pXlatorAttrs) +{ + struct CMM_XLATOR *pXlatorObject = NULL; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(phXlator != NULL); + DBC_Require(hCmmMgr != NULL); + GT_3trace(CMM_debugMask, GT_ENTER, + "CMM_XlatorCreate: phXlator: 0x%x\t" + "phCmmMgr: 0x%x\tpXlAttrs: 0x%x\n", phXlator, + hCmmMgr, pXlatorAttrs); + *phXlator = NULL; + if (pXlatorAttrs == NULL) + pXlatorAttrs = &CMM_DFLTXLATORATTRS; /* set defaults */ + + MEM_AllocObject(pXlatorObject, struct CMM_XLATOR, CMMXLATESIGNATURE); + if (pXlatorObject != NULL) { + pXlatorObject->hCmmMgr = hCmmMgr; /* ref back to CMM */ + pXlatorObject->ulSegId = pXlatorAttrs->ulSegId; /* SM segId */ + } else { + GT_0trace(CMM_debugMask, GT_6CLASS, + "CMM_XlatorCreate: Object Allocation" + "Failure(CMM Xlator)\n"); + status = DSP_EMEMORY; + } + if (DSP_SUCCEEDED(status)) + *phXlator = (struct CMM_XLATOROBJECT *) pXlatorObject; + + return status; +} + +/* + * ======== CMM_XlatorDelete ======== + * Purpose: + * Free the Xlator resources. + * VM gets freed later. + */ +DSP_STATUS CMM_XlatorDelete(struct CMM_XLATOROBJECT *hXlator, bool bForce) +{ + struct CMM_XLATOR *pXlator = (struct CMM_XLATOR *)hXlator; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + + if (MEM_IsValidHandle(pXlator, CMMXLATESIGNATURE)) { + MEM_FreeObject(pXlator); + } else { + status = DSP_EHANDLE; + } + + return status; +} + +/* + * ======== CMM_XlatorAllocBuf ======== + */ +void *CMM_XlatorAllocBuf(struct CMM_XLATOROBJECT *hXlator, void *pVaBuf, + u32 uPaSize) +{ + struct CMM_XLATOR *pXlator = (struct CMM_XLATOR *)hXlator; + void *pBuf = NULL; + struct CMM_ATTRS attrs; + + DBC_Require(cRefs > 0); + DBC_Require(hXlator != NULL); + DBC_Require(pXlator->hCmmMgr != NULL); + DBC_Require(pVaBuf != NULL); + DBC_Require(uPaSize > 0); + DBC_Require(pXlator->ulSegId > 0); + + if (MEM_IsValidHandle(pXlator, CMMXLATESIGNATURE)) { + attrs.ulSegId = pXlator->ulSegId; + *(volatile u32 *)pVaBuf = 0; + /* Alloc SM */ + pBuf = CMM_CallocBuf(pXlator->hCmmMgr, uPaSize, &attrs, NULL); + if (pBuf) { + /* convert to translator(node/strm) process Virtual + * address */ + *(volatile u32 **)pVaBuf = + (u32 *)CMM_XlatorTranslate(hXlator, + pBuf, CMM_PA2VA); + } + } + return pBuf; +} + +/* + * ======== CMM_XlatorFreeBuf ======== + * Purpose: + * Free the given SM buffer and descriptor. + * Does not free virtual memory. + */ +DSP_STATUS CMM_XlatorFreeBuf(struct CMM_XLATOROBJECT *hXlator, void *pBufVa) +{ + struct CMM_XLATOR *pXlator = (struct CMM_XLATOR *)hXlator; + DSP_STATUS status = DSP_EFAIL; + void *pBufPa = NULL; + + DBC_Require(cRefs > 0); + DBC_Require(pBufVa != NULL); + DBC_Require(pXlator->ulSegId > 0); + + if (MEM_IsValidHandle(pXlator, CMMXLATESIGNATURE)) { + /* convert Va to Pa so we can free it. */ + pBufPa = CMM_XlatorTranslate(hXlator, pBufVa, CMM_VA2PA); + if (pBufPa) { + status = CMM_FreeBuf(pXlator->hCmmMgr, pBufPa, + pXlator->ulSegId); + if (DSP_FAILED(status)) { + /* Uh oh, this shouldn't happen. Descriptor + * gone! */ + GT_2trace(CMM_debugMask, GT_7CLASS, + "Cannot free DMA/ZCPY buffer" + "not allocated by MPU. PA %x, VA %x\n", + pBufPa, pBufVa); + DBC_Assert(false); /* CMM is leaking mem! */ + } + } + } + return status; +} + +/* + * ======== CMM_XlatorInfo ======== + * Purpose: + * Set/Get translator info. + */ +DSP_STATUS CMM_XlatorInfo(struct CMM_XLATOROBJECT *hXlator, IN OUT u8 **pAddr, + u32 ulSize, u32 uSegId, bool bSetInfo) +{ + struct CMM_XLATOR *pXlator = (struct CMM_XLATOR *)hXlator; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(pAddr != NULL); + DBC_Require((uSegId > 0) && (uSegId <= CMM_MAXGPPSEGS)); + + if (MEM_IsValidHandle(pXlator, CMMXLATESIGNATURE)) { + if (bSetInfo) { + /* set translators virtual address range */ + pXlator->dwVirtBase = (u32)*pAddr; + pXlator->ulVirtSize = ulSize; + GT_2trace(CMM_debugMask, GT_3CLASS, + "pXlator->dwVirtBase %x, " + "ulVirtSize %x\n", pXlator->dwVirtBase, + pXlator->ulVirtSize); + } else { /* return virt base address */ + *pAddr = (u8 *)pXlator->dwVirtBase; + } + } else { + status = DSP_EHANDLE; + } + return status; +} + +/* + * ======== CMM_XlatorTranslate ======== + */ +void *CMM_XlatorTranslate(struct CMM_XLATOROBJECT *hXlator, void *pAddr, + enum CMM_XLATETYPE xType) +{ + u32 dwAddrXlate = 0; + struct CMM_XLATOR *pXlator = (struct CMM_XLATOR *)hXlator; + struct CMM_OBJECT *pCmmMgr = NULL; + struct CMM_ALLOCATOR *pAlctr = NULL; + u32 dwOffset = 0; + + DBC_Require(cRefs > 0); + DBC_Require(pAddr != NULL); + DBC_Require((xType >= CMM_VA2PA) && (xType <= CMM_DSPPA2PA)); + + if (!MEM_IsValidHandle(pXlator, CMMXLATESIGNATURE)) + goto loop_cont; + + pCmmMgr = (struct CMM_OBJECT *)pXlator->hCmmMgr; + /* get this translator's default SM allocator */ + DBC_Assert(pXlator->ulSegId > 0); + pAlctr = pCmmMgr->paGPPSMSegTab[pXlator->ulSegId - 1]; + if (!MEM_IsValidHandle(pAlctr, SMEMSIGNATURE)) + goto loop_cont; + + if ((xType == CMM_VA2DSPPA) || (xType == CMM_VA2PA) || + (xType == CMM_PA2VA)) { + if (xType == CMM_PA2VA) { + /* Gpp Va = Va Base + offset */ + dwOffset = (u8 *)pAddr - (u8 *)(pAlctr->dwSmBase - + pAlctr->ulDSPSize); + dwAddrXlate = pXlator->dwVirtBase + dwOffset; + /* Check if translated Va base is in range */ + if ((dwAddrXlate < pXlator->dwVirtBase) || + (dwAddrXlate >= + (pXlator->dwVirtBase + pXlator->ulVirtSize))) { + dwAddrXlate = 0; /* bad address */ + GT_0trace(CMM_debugMask, GT_7CLASS, + "CMM_XlatorTranslate: " + "Virt addr out of range\n"); + } + } else { + /* Gpp PA = Gpp Base + offset */ + dwOffset = (u8 *)pAddr - (u8 *)pXlator->dwVirtBase; + dwAddrXlate = pAlctr->dwSmBase - pAlctr->ulDSPSize + + dwOffset; + } + } else { + dwAddrXlate = (u32)pAddr; + } + /*Now convert address to proper target physical address if needed*/ + if ((xType == CMM_VA2DSPPA) || (xType == CMM_PA2DSPPA)) { + /* Got Gpp Pa now, convert to DSP Pa */ + dwAddrXlate = GPPPA2DSPPA((pAlctr->dwSmBase - pAlctr-> + ulDSPSize), dwAddrXlate, + pAlctr->dwDSPPhysAddrOffset * + pAlctr->cFactor); + } else if (xType == CMM_DSPPA2PA) { + /* Got DSP Pa, convert to GPP Pa */ + dwAddrXlate = DSPPA2GPPPA(pAlctr->dwSmBase - pAlctr->ulDSPSize, + dwAddrXlate, + pAlctr->dwDSPPhysAddrOffset * + pAlctr->cFactor); + } +loop_cont: + if (!dwAddrXlate) { + GT_2trace(CMM_debugMask, GT_7CLASS, + "CMM_XlatorTranslate: Can't translate" + " address: 0x%x xType %x\n", pAddr, xType); + } else { + GT_3trace(CMM_debugMask, GT_3CLASS, + "CMM_XlatorTranslate: pAddr %x, xType" + " %x, dwAddrXlate %x\n", pAddr, xType, dwAddrXlate); + } + return (void *)dwAddrXlate; +} diff --git a/drivers/dsp/bridge/pmgr/cod.c b/drivers/dsp/bridge/pmgr/cod.c new file mode 100644 index 0000000..6363f1e --- /dev/null +++ b/drivers/dsp/bridge/pmgr/cod.c @@ -0,0 +1,683 @@ +/* + * cod.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== cod.c ======== + * This module implements DSP code management for the DSP/BIOS Bridge + * environment. It is mostly a thin wrapper. + * + * This module provides an interface for loading both static and + * dynamic code objects onto DSP systems. + * + *! Revision History + *! ================ + *! 08-Apr-2003 map: Consolidated DBL to DBLL loader name + *! 24-Feb-2003 swa: PMGR Code review comments incorporated. + *! 18-Apr-2002 jeh: Added DBL function tables. + *! 20-Nov-2001 jeh: Removed call to ZL_loadArgs function. + *! 19-Oct-2001 jeh: Access DBL as a static library. Added COD_GetBaseLib, + *! COD_GetLoader, removed COD_LoadSection, COD_UnloadSection. + *! 07-Sep-2001 jeh: Added COD_LoadSection(), COD_UnloadSection(). + *! 07-Aug-2001 rr: hMgr->baseLib is updated after zlopen in COD_LoadBase. + *! 18-Apr-2001 jeh: Check for fLoaded flag before ZL_unload, to allow + *! COD_OpenBase to be used. + *! 11-Jan-2001 jeh: Added COD_OpenBase (not used yet, since there is an + *! occasional crash). + *! 02-Aug-2000 kc: Added COD_ReadSection to COD module. Incorporates use + *! of ZL_readSect (new function in ZL module). + *! 28-Feb-2000 rr: New GT Usage Implementation + *! 08-Dec-1999 ag: Removed x86 specific __asm int 3. + *! 02-Oct-1999 ag: Added #ifdef DEBUGINT3COD for debug. + *! 20-Sep-1999 ag: Removed call to GT_set(). + *! 04-Jun-1997 cr: Added validation of argc/argv pair in COD_LoadBase, as it + *! is a requirement to ZL_loadArgs. + *! 31-May-1997 cr: Changed COD_LoadBase argc value from u32 to int, added + *! DSP_ENOTIMPL return value to COD_Create when attrs != NULL. + *! 29-May-1997 cr: Added debugging support. + *! 24-Oct-1996 gp: Added COD_GetSection(). + *! 18-Jun-1996 gp: Updated GetSymValue() to check for lib; updated E_ codes. + *! 12-Jun-1996 gp: Imported CSL_ services for strcpyn(); Added ref counting. + *! 20-May-1996 mg: Adapted for new MEM and LDR modules. + *! 08-May-1996 mg: Created. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include + +/* ----------------------------------- Platform Manager */ +/* Include appropriate loader header file */ +#include + +/* ----------------------------------- This */ +#include + +/* magic number for handle validation */ +#define MAGIC 0xc001beef + +/* macro to validate COD manager handles */ +#define IsValid(h) ((h) != NULL && (h)->ulMagic == MAGIC) + +/* + * ======== COD_MANAGER ======== + */ +struct COD_MANAGER { + struct DBLL_TarObj *target; + struct DBLL_LibraryObj *baseLib; + bool fLoaded; /* Base library loaded? */ + u32 ulEntry; + struct LDR_MODULE *hDll; + struct DBLL_Fxns fxns; + struct DBLL_Attrs attrs; + char szZLFile[COD_MAXPATHLENGTH]; + u32 ulMagic; +} ; + +/* + * ======== COD_LIBRARYOBJ ======== + */ +struct COD_LIBRARYOBJ { + struct DBLL_LibraryObj *dbllLib; + struct COD_MANAGER *hCodMgr; +} ; + +static u32 cRefs = 0L; + +#if GT_TRACE +static struct GT_Mask COD_debugMask = { NULL, NULL }; +#endif + +static struct DBLL_Fxns dbllFxns = { + (DBLL_CloseFxn) DBLL_close, + (DBLL_CreateFxn) DBLL_create, + (DBLL_DeleteFxn) DBLL_delete, + (DBLL_ExitFxn) DBLL_exit, + (DBLL_GetAttrsFxn) DBLL_getAttrs, + (DBLL_GetAddrFxn) DBLL_getAddr, + (DBLL_GetCAddrFxn) DBLL_getCAddr, + (DBLL_GetSectFxn) DBLL_getSect, + (DBLL_InitFxn) DBLL_init, + (DBLL_LoadFxn) DBLL_load, + (DBLL_LoadSectFxn) DBLL_loadSect, + (DBLL_OpenFxn) DBLL_open, + (DBLL_ReadSectFxn) DBLL_readSect, + (DBLL_SetAttrsFxn) DBLL_setAttrs, + (DBLL_UnloadFxn) DBLL_unload, + (DBLL_UnloadSectFxn) DBLL_unloadSect, +}; + +static bool NoOp(void); + +/* + * ======== COD_Close ======== + */ +void COD_Close(struct COD_LIBRARYOBJ *lib) +{ + struct COD_MANAGER *hMgr; + + DBC_Require(cRefs > 0); + DBC_Require(lib != NULL); + DBC_Require(IsValid(((struct COD_LIBRARYOBJ *)lib)->hCodMgr)); + + hMgr = lib->hCodMgr; + hMgr->fxns.closeFxn(lib->dbllLib); + + MEM_Free(lib); +} + +/* + * ======== COD_Create ======== + * Purpose: + * Create an object to manage code on a DSP system. + * This object can be used to load an initial program image with + * arguments that can later be expanded with + * dynamically loaded object files. + * + */ +DSP_STATUS COD_Create(OUT struct COD_MANAGER **phMgr, char *pstrDummyFile, + IN OPTIONAL CONST struct COD_ATTRS *attrs) +{ + struct COD_MANAGER *hMgrNew; + struct DBLL_Attrs zlAttrs; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(phMgr != NULL); + + GT_3trace(COD_debugMask, GT_ENTER, + "Entered COD_Create, Args: \t\nphMgr: " + "0x%x\t\npstrDummyFile: 0x%x\t\nattr: 0x%x\n", + phMgr, pstrDummyFile, attrs); + /* assume failure */ + *phMgr = NULL; + + /* we don't support non-default attrs yet */ + if (attrs != NULL) + return DSP_ENOTIMPL; + + hMgrNew = MEM_Calloc(sizeof(struct COD_MANAGER), MEM_NONPAGED); + if (hMgrNew == NULL) { + GT_0trace(COD_debugMask, GT_7CLASS, + "COD_Create: Out Of Memory\n"); + return DSP_EMEMORY; + } + + hMgrNew->ulMagic = MAGIC; + + /* Set up loader functions */ + hMgrNew->fxns = dbllFxns; + + /* initialize the ZL module */ + hMgrNew->fxns.initFxn(); + + zlAttrs.alloc = (DBLL_AllocFxn)NoOp; + zlAttrs.free = (DBLL_FreeFxn)NoOp; + zlAttrs.fread = (DBLL_ReadFxn)KFILE_Read; + zlAttrs.fseek = (DBLL_SeekFxn)KFILE_Seek; + zlAttrs.ftell = (DBLL_TellFxn)KFILE_Tell; + zlAttrs.fclose = (DBLL_FCloseFxn)KFILE_Close; + zlAttrs.fopen = (DBLL_FOpenFxn)KFILE_Open; + zlAttrs.symLookup = NULL; + zlAttrs.baseImage = true; + zlAttrs.logWrite = NULL; + zlAttrs.logWriteHandle = NULL; + zlAttrs.write = NULL; + zlAttrs.rmmHandle = NULL; + zlAttrs.wHandle = NULL; + zlAttrs.symHandle = NULL; + zlAttrs.symArg = NULL; + + hMgrNew->attrs = zlAttrs; + + status = hMgrNew->fxns.createFxn(&hMgrNew->target, &zlAttrs); + + if (DSP_FAILED(status)) { + COD_Delete(hMgrNew); + GT_1trace(COD_debugMask, GT_7CLASS, + "COD_Create:ZL Create Failed: 0x%x\n", status); + return COD_E_ZLCREATEFAILED; + } + + /* return the new manager */ + *phMgr = hMgrNew; + GT_1trace(COD_debugMask, GT_1CLASS, + "COD_Create: Success CodMgr: 0x%x\n", *phMgr); + return DSP_SOK; +} + +/* + * ======== COD_Delete ======== + * Purpose: + * Delete a code manager object. + */ +void COD_Delete(struct COD_MANAGER *hMgr) +{ + DBC_Require(cRefs > 0); + DBC_Require(IsValid(hMgr)); + + GT_1trace(COD_debugMask, GT_ENTER, "COD_Delete:hMgr 0x%x\n", hMgr); + if (hMgr->baseLib) { + if (hMgr->fLoaded) + hMgr->fxns.unloadFxn(hMgr->baseLib, &hMgr->attrs); + + hMgr->fxns.closeFxn(hMgr->baseLib); + } + if (hMgr->target) { + hMgr->fxns.deleteFxn(hMgr->target); + hMgr->fxns.exitFxn(); + } + hMgr->ulMagic = ~MAGIC; + MEM_Free(hMgr); +} + +/* + * ======== COD_Exit ======== + * Purpose: + * Discontinue usage of the COD module. + * + */ +void COD_Exit(void) +{ + DBC_Require(cRefs > 0); + + cRefs--; + + GT_1trace(COD_debugMask, GT_ENTER, + "Entered COD_Exit, ref count: 0x%x\n", cRefs); + + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== COD_GetBaseLib ======== + * Purpose: + * Get handle to the base image DBL library. + */ +DSP_STATUS COD_GetBaseLib(struct COD_MANAGER *hManager, + struct DBLL_LibraryObj **plib) +{ + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(IsValid(hManager)); + DBC_Require(plib != NULL); + + *plib = (struct DBLL_LibraryObj *) hManager->baseLib; + + return status; +} + +/* + * ======== COD_GetBaseName ======== + */ +DSP_STATUS COD_GetBaseName(struct COD_MANAGER *hManager, char *pszName, + u32 uSize) +{ + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(IsValid(hManager)); + DBC_Require(pszName != NULL); + + if (uSize <= COD_MAXPATHLENGTH) + strncpy(pszName, hManager->szZLFile, uSize); + else + status = DSP_EFAIL; + + return status; +} + +/* + * ======== COD_GetEntry ======== + * Purpose: + * Retrieve the entry point of a loaded DSP program image + * + */ +DSP_STATUS COD_GetEntry(struct COD_MANAGER *hManager, u32 *pulEntry) +{ + DBC_Require(cRefs > 0); + DBC_Require(IsValid(hManager)); + DBC_Require(pulEntry != NULL); + + *pulEntry = hManager->ulEntry; + + GT_1trace(COD_debugMask, GT_ENTER, "COD_GetEntry:ulEntr 0x%x\n", + *pulEntry); + + return DSP_SOK; +} + +/* + * ======== COD_GetLoader ======== + * Purpose: + * Get handle to the DBLL loader. + */ +DSP_STATUS COD_GetLoader(struct COD_MANAGER *hManager, + struct DBLL_TarObj **phLoader) +{ + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(IsValid(hManager)); + DBC_Require(phLoader != NULL); + + *phLoader = (struct DBLL_TarObj *)hManager->target; + + return status; +} + +/* + * ======== COD_GetSection ======== + * Purpose: + * Retrieve the starting address and length of a section in the COFF file + * given the section name. + */ +DSP_STATUS COD_GetSection(struct COD_LIBRARYOBJ *lib, IN char *pstrSect, + OUT u32 *puAddr, OUT u32 *puLen) +{ + struct COD_MANAGER *hManager; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(lib != NULL); + DBC_Require(IsValid(lib->hCodMgr)); + DBC_Require(pstrSect != NULL); + DBC_Require(puAddr != NULL); + DBC_Require(puLen != NULL); + + GT_4trace(COD_debugMask, GT_ENTER, + "Entered COD_GetSection Args \t\n lib: " + "0x%x\t\npstrsect: 0x%x\t\npuAddr: 0x%x\t\npuLen: 0x%x\n", + lib, pstrSect, puAddr, puLen); + *puAddr = 0; + *puLen = 0; + if (lib != NULL) { + hManager = lib->hCodMgr; + status = hManager->fxns.getSectFxn(lib->dbllLib, pstrSect, + puAddr, puLen); + if (DSP_FAILED(status)) { + GT_1trace(COD_debugMask, GT_7CLASS, + "COD_GetSection: Section %s not" + "found\n", pstrSect); + } + } else { + status = COD_E_NOSYMBOLSLOADED; + GT_0trace(COD_debugMask, GT_7CLASS, + "COD_GetSection:No Symbols loaded\n"); + } + + DBC_Ensure(DSP_SUCCEEDED(status) || ((*puAddr == 0) && (*puLen == 0))); + + return status; +} + +/* + * ======== COD_GetSymValue ======== + * Purpose: + * Retrieve the value for the specified symbol. The symbol is first + * searched for literally and then, if not found, searched for as a + * C symbol. + * + */ +DSP_STATUS COD_GetSymValue(struct COD_MANAGER *hMgr, char *pstrSym, + u32 *pulValue) +{ + struct DBLL_Symbol *pSym; + + DBC_Require(cRefs > 0); + DBC_Require(IsValid(hMgr)); + DBC_Require(pstrSym != NULL); + DBC_Require(pulValue != NULL); + + GT_3trace(COD_debugMask, GT_ENTER, "Entered COD_GetSymValue Args \t\n" + "hMgr: 0x%x\t\npstrSym: 0x%x\t\npulValue: 0x%x\n", + hMgr, pstrSym, pulValue); + if (hMgr->baseLib) { + if (!hMgr->fxns.getAddrFxn(hMgr->baseLib, pstrSym, &pSym)) { + if (!hMgr->fxns.getCAddrFxn(hMgr->baseLib, pstrSym, + &pSym)) { + GT_0trace(COD_debugMask, GT_7CLASS, + "COD_GetSymValue: " + "Symbols not found\n"); + return COD_E_SYMBOLNOTFOUND; + } + } + } else { + GT_0trace(COD_debugMask, GT_7CLASS, "COD_GetSymValue: " + "No Symbols loaded\n"); + return COD_E_NOSYMBOLSLOADED; + } + + *pulValue = pSym->value; + + return DSP_SOK; +} + +/* + * ======== COD_Init ======== + * Purpose: + * Initialize the COD module's private state. + * + */ +bool COD_Init(void) +{ + bool fRetVal = true; + + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { + DBC_Assert(!COD_debugMask.flags); + GT_create(&COD_debugMask, "CO"); + } + + if (fRetVal) + cRefs++; + + + GT_1trace(COD_debugMask, GT_1CLASS, + "Entered COD_Init, ref count: 0x%x\n", cRefs); + DBC_Ensure((fRetVal && cRefs > 0) || (!fRetVal && cRefs >= 0)); + return fRetVal; +} + +/* + * ======== COD_LoadBase ======== + * Purpose: + * Load the initial program image, optionally with command-line arguments, + * on the DSP system managed by the supplied handle. The program to be + * loaded must be the first element of the args array and must be a fully + * qualified pathname. + * Details: + * if nArgc doesn't match the number of arguments in the aArgs array, the + * aArgs array is searched for a NULL terminating entry, and argc is + * recalculated to reflect this. In this way, we can support NULL + * terminating aArgs arrays, if nArgc is very large. + */ +DSP_STATUS COD_LoadBase(struct COD_MANAGER *hMgr, u32 nArgc, char *aArgs[], + COD_WRITEFXN pfnWrite, void *pArb, char *envp[]) +{ + DBLL_Flags flags; + struct DBLL_Attrs saveAttrs; + struct DBLL_Attrs newAttrs; + DSP_STATUS status; + u32 i; + + DBC_Require(cRefs > 0); + DBC_Require(IsValid(hMgr)); + DBC_Require(nArgc > 0); + DBC_Require(aArgs != NULL); + DBC_Require(aArgs[0] != NULL); + DBC_Require(pfnWrite != NULL); + DBC_Require(hMgr->baseLib != NULL); + + GT_6trace(COD_debugMask, GT_ENTER, + "Entered COD_LoadBase, hMgr: 0x%x\n \t" + "nArgc: 0x%x\n\taArgs: 0x%x\n\tpfnWrite: 0x%x\n\tpArb:" + " 0x%x\n \tenvp: 0x%x\n", hMgr, nArgc, aArgs, pfnWrite, + pArb, envp); + /* + * Make sure every argv[] stated in argc has a value, or change argc to + * reflect true number in NULL terminated argv array. + */ + for (i = 0; i < nArgc; i++) { + if (aArgs[i] == NULL) { + nArgc = i; + break; + } + } + + /* set the write function for this operation */ + hMgr->fxns.getAttrsFxn(hMgr->target, &saveAttrs); + + newAttrs = saveAttrs; + newAttrs.write = (DBLL_WriteFxn)pfnWrite; + newAttrs.wHandle = pArb; + newAttrs.alloc = (DBLL_AllocFxn)NoOp; + newAttrs.free = (DBLL_FreeFxn)NoOp; + newAttrs.logWrite = NULL; + newAttrs.logWriteHandle = NULL; + + /* Load the image */ + flags = DBLL_CODE | DBLL_DATA | DBLL_SYMB; + status = hMgr->fxns.loadFxn(hMgr->baseLib, flags, &newAttrs, + &hMgr->ulEntry); + if (DSP_FAILED(status)) { + hMgr->fxns.closeFxn(hMgr->baseLib); + GT_1trace(COD_debugMask, GT_7CLASS, + "COD_LoadBase: COD Load failed: " + "0x%x\n", status); + } + if (DSP_SUCCEEDED(status)) + hMgr->fLoaded = true; + else + hMgr->baseLib = NULL; + + return status; +} + +/* + * ======== COD_Open ======== + * Open library for reading sections. + */ +DSP_STATUS COD_Open(struct COD_MANAGER *hMgr, IN char *pszCoffPath, + COD_FLAGS flags, struct COD_LIBRARYOBJ **pLib) +{ + DSP_STATUS status = DSP_SOK; + struct COD_LIBRARYOBJ *lib = NULL; + + DBC_Require(cRefs > 0); + DBC_Require(IsValid(hMgr)); + DBC_Require(pszCoffPath != NULL); + DBC_Require(flags == COD_NOLOAD || flags == COD_SYMB); + DBC_Require(pLib != NULL); + + GT_4trace(COD_debugMask, GT_ENTER, "Entered COD_Open, hMgr: 0x%x\n\t " + "pszCoffPath: 0x%x\tflags: 0x%x\tlib: 0x%x\n", hMgr, + pszCoffPath, flags, pLib); + + *pLib = NULL; + + lib = MEM_Calloc(sizeof(struct COD_LIBRARYOBJ), MEM_NONPAGED); + if (lib == NULL) { + GT_0trace(COD_debugMask, GT_7CLASS, + "COD_Open: Out Of Memory\n"); + status = DSP_EMEMORY; + } + + if (DSP_SUCCEEDED(status)) { + lib->hCodMgr = hMgr; + status = hMgr->fxns.openFxn(hMgr->target, pszCoffPath, flags, + &lib->dbllLib); + if (DSP_FAILED(status)) { + GT_1trace(COD_debugMask, GT_7CLASS, + "COD_Open failed: 0x%x\n", status); + } else { + *pLib = lib; + } + } + + return status; +} + +/* + * ======== COD_OpenBase ======== + * Purpose: + * Open base image for reading sections. + */ +DSP_STATUS COD_OpenBase(struct COD_MANAGER *hMgr, IN char *pszCoffPath, + DBLL_Flags flags) +{ + DSP_STATUS status = DSP_SOK; + struct DBLL_LibraryObj *lib; + + DBC_Require(cRefs > 0); + DBC_Require(IsValid(hMgr)); + DBC_Require(pszCoffPath != NULL); + + GT_2trace(COD_debugMask, GT_ENTER, + "Entered COD_OpenBase, hMgr: 0x%x\n\t" + "pszCoffPath: 0x%x\n", hMgr, pszCoffPath); + + /* if we previously opened a base image, close it now */ + if (hMgr->baseLib) { + if (hMgr->fLoaded) { + GT_0trace(COD_debugMask, GT_7CLASS, + "Base Image is already loaded. " + "Unloading it...\n"); + hMgr->fxns.unloadFxn(hMgr->baseLib, &hMgr->attrs); + hMgr->fLoaded = false; + } + hMgr->fxns.closeFxn(hMgr->baseLib); + hMgr->baseLib = NULL; + } else { + GT_0trace(COD_debugMask, GT_1CLASS, + "COD_OpenBase: Opening the base image ...\n"); + } + status = hMgr->fxns.openFxn(hMgr->target, pszCoffPath, flags, &lib); + if (DSP_FAILED(status)) { + GT_0trace(COD_debugMask, GT_7CLASS, + "COD_OpenBase: COD Open failed\n"); + } else { + /* hang onto the library for subsequent sym table usage */ + hMgr->baseLib = lib; + strncpy(hMgr->szZLFile, pszCoffPath, COD_MAXPATHLENGTH); + } + + return status; +} + +/* + * ======== COD_ReadSection ======== + * Purpose: + * Retrieve the content of a code section given the section name. + */ +DSP_STATUS COD_ReadSection(struct COD_LIBRARYOBJ *lib, IN char *pstrSect, + OUT char *pstrContent, IN u32 cContentSize) +{ + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(lib != NULL); + DBC_Require(IsValid(lib->hCodMgr)); + DBC_Require(pstrSect != NULL); + DBC_Require(pstrContent != NULL); + + GT_4trace(COD_debugMask, GT_ENTER, "Entered COD_ReadSection Args: 0x%x," + " 0x%x, 0x%x, 0x%x\n", lib, pstrSect, pstrContent, + cContentSize); + + if (lib != NULL) { + status = lib->hCodMgr->fxns.readSectFxn(lib->dbllLib, pstrSect, + pstrContent, + cContentSize); + if (DSP_FAILED(status)) { + GT_1trace(COD_debugMask, GT_7CLASS, + "COD_ReadSection failed: 0x%lx\n", status); + } + } else { + status = COD_E_NOSYMBOLSLOADED; + GT_0trace(COD_debugMask, GT_7CLASS, + "COD_ReadSection: No Symbols loaded\n"); + } + return status; +} + +/* + * ======== NoOp ======== + * Purpose: + * No Operation. + * + */ +static bool NoOp(void) +{ + return true; +} + diff --git a/drivers/dsp/bridge/pmgr/dbl.c b/drivers/dsp/bridge/pmgr/dbl.c new file mode 100644 index 0000000..641b011 --- /dev/null +++ b/drivers/dsp/bridge/pmgr/dbl.c @@ -0,0 +1,1385 @@ +/* + * dbl.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dbl.c ======== + * Dynamic BOF Loader library. Contains functions related to + * loading and unloading symbols/code/data on DSP. + * Also contains other support functions. + * + *! Revision History + *! ================ + *! 24-Feb-2003 swa PMGR Code review comments incorporated. + *! 24-May-2002 jeh Free DCD sects in DBL_close(). + *! 19-Mar-2002 jeh Changes made to match dynamic loader (dbll.c): Pass + *! DBL_Library to DBL_getAddr() instead of DBL_Target, + *! eliminate scope param, use DBL_Symbol. Pass attrs to + *! DBL_load(), DBL_unload(). + *! 20-Nov-2001 jeh Removed DBL_loadArgs(). + *! 07-Sep-2001 jeh Added overlay support. + *! 31-Jul-2001 jeh Include windows.h. + *! 06-Jun-2001 jeh Created. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include + +/* ----------------------------------- This */ +#include +#include + +#define DBL_TARGSIGNATURE 0x544c4244 /* "TLBD" */ +#define DBL_LIBSIGNATURE 0x4c4c4244 /* "LLBD" */ + +#define C54TARG 0 +#define C55TARG 1 +#define NUMTARGS 2 + +#define C54MAGIC 0x98 /* Magic number for TI C54 COF */ +#define C55MAGIC 0x9c /* Magic number for LEAD3 (C55) COF */ + +/* Three task phases */ +#define CREATEPHASE 0 +#define DELETEPHASE 1 +#define EXECUTEPHASE 2 +#define NONE 3 /* For overlay section with phase not specified */ + +/* Default load buffer size */ +#define LOADBUFSIZE 0x800 + +#define SWAPLONG(x) ((((x) << 24) & 0xFF000000) | (((x) << 8) & 0xFF0000L) | \ + (((x) >> 8) & 0xFF00L) | (((x) >> 24) & 0xFF)) + +#define SWAPWORD(x) ((((x) << 8) & 0xFF00) | (((x) >> 8) & 0xFF)) + +/* + * Macros for accessing the following types of overlay data within a + * structure of type OvlyData: + * - Overlay data not associated with a particular phase + * - Create phase overlay data + * - Delete phase overlay data + * - Execute phase overlay data + */ +#define numOtherSects(pOvlyData) ((pOvlyData)->hdr.dbofHdr.numOtherSects) +#define numCreateSects(pOvlyData) ((pOvlyData)->hdr.dbofHdr.numCreateSects) +#define numDeleteSects(pOvlyData) ((pOvlyData)->hdr.dbofHdr.numDeleteSects) +#define numExecuteSects(pOvlyData) ((pOvlyData)->hdr.dbofHdr.numExecuteSects) +#define otherOffset(pOvlyData) 0 +#define createOffset(pOvlyData) ((pOvlyData)->hdr.dbofHdr.numOtherSects) +#define deleteOffset(pOvlyData) (createOffset(pOvlyData) + \ + (pOvlyData->hdr.dbofHdr.numCreateSects)) +#define executeOffset(pOvlyData) (deleteOffset(pOvlyData) + \ + (pOvlyData->hdr.dbofHdr.numDeleteSects)) +/* + * ======== OvlyHdr ======== + */ +struct OvlyHdr { + struct DBOF_OvlySectHdr dbofHdr; + char *pName; /* Name of overlay section */ + u16 createRef; /* Reference count for create phase */ + u16 deleteRef; /* Reference count for delete phase */ + u16 executeRef; /* Execute phase ref count */ + u16 otherRef; /* Unspecified phase ref count */ +} ; + +/* + * ======== OvlyData ======== + */ +struct OvlyData { + struct OvlyHdr hdr; + struct DBOF_OvlySectData data[1]; +} ; + +/* + * ======== Symbol ======== + */ +struct Symbol { + struct DBL_Symbol sym; + char *pSymName; +}; + +/* + * ======== DCDSect ======== + */ +struct DCDSect { + struct DBOF_DCDSectHdr sectHdr; + char *pData; +} ; + +/* + * ======== DBL_TargetObj ======== + */ +struct DBL_TargetObj { + u32 dwSignature; /* For object validation */ + struct DBL_Attrs dblAttrs; /* file read, write, etc. functions */ + char *pBuf; /* Load buffer */ +}; + +/* + * ======== TargetInfo ======== + */ +struct TargetInfo { + u16 dspType; /* eg, C54TARG, C55TARG */ + u32 magic; /* COFF magic number, identifies target type */ + u16 wordSize; /* Size of a DSP word */ + u16 mauSize; /* Size of minimum addressable unit */ + u16 charSize; /* For C55x, mausize = 1, but charsize = 2 */ +} ; + +/* + * ======== DBL_LibraryObj ======== + * Represents a library loaded on a target. + */ +struct DBL_LibraryObj { + u32 dwSignature; /* For object validation */ + struct DBL_TargetObj *pTarget; /* Target for this library */ + struct KFILE_FileObj *file; /* DBOF file handle */ + bool byteSwapped; /* Are bytes swapped? */ + struct DBOF_FileHdr fileHdr; /* Header of DBOF file */ + u16 nSymbols; /* Number of DSP/Bridge symbols */ + struct Symbol *symbols; /* Table of DSP/Bridge symbols */ + u16 nDCDSects; /* Number of DCD sections */ + u16 nOvlySects; /* Number of overlay nodes */ + struct DCDSect *dcdSects; /* DCD section data */ + struct OvlyData **ppOvlyData; /* Array of overlay section data */ + struct TargetInfo *pTargetInfo; /* Entry in targetTab[] below */ +} ; + +#if GT_TRACE +static struct GT_Mask DBL_debugMask = { NULL, NULL }; /* GT trace variable */ +#endif + +static u32 cRefs; /* module reference count */ + +static u32 magicTab[NUMTARGS] = { C54MAGIC, C55MAGIC }; + +static struct TargetInfo targetTab[] = { + /* targ magic wordsize mausize charsize */ + {C54TARG, C54MAGIC, 2, 2, 2}, /* C54 */ + {C55TARG, C55MAGIC, 2, 1, 2}, /* C55 */ +}; + +static void freeSects(struct DBL_TargetObj *dbl, struct OvlyData *pOvlyData, + s32 offset, s32 nSects); +static DSP_STATUS loadSect(struct DBL_TargetObj *dbl, + struct DBL_LibraryObj *pdblLib); +static DSP_STATUS readDCDSects(struct DBL_TargetObj *dbl, + struct DBL_LibraryObj *pdblLib); +static DSP_STATUS readHeader(struct DBL_TargetObj *dbl, + struct DBL_LibraryObj *pdblLib); +static DSP_STATUS readOvlySects(struct DBL_TargetObj *dbl, + struct DBL_LibraryObj *pdblLib); +static DSP_STATUS readSymbols(struct DBL_TargetObj *dbl, + struct DBL_LibraryObj *pdblLib); + +/* + * ======== DBL_close ======== + * Purpose: + * Close library opened with DBL_open. + */ +void DBL_close(struct DBL_LibraryObj *lib) +{ + struct DBL_LibraryObj *pdblLib = (struct DBL_LibraryObj *)lib; + u16 i; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(pdblLib, DBL_LIBSIGNATURE)); + + GT_1trace(DBL_debugMask, GT_ENTER, "DBL_close: lib: 0x%x\n", lib); + + /* Free symbols */ + if (pdblLib->symbols) { + for (i = 0; i < pdblLib->nSymbols; i++) { + if (pdblLib->symbols[i].pSymName) + MEM_Free(pdblLib->symbols[i].pSymName); + + } + MEM_Free(pdblLib->symbols); + } + + /* Free DCD sects */ + if (pdblLib->dcdSects) { + for (i = 0; i < pdblLib->nDCDSects; i++) { + if (pdblLib->dcdSects[i].pData) + MEM_Free(pdblLib->dcdSects[i].pData); + + } + MEM_Free(pdblLib->dcdSects); + } + + /* Free overlay sects */ + if (pdblLib->ppOvlyData) { + for (i = 0; i < pdblLib->nOvlySects; i++) { + if (pdblLib->ppOvlyData[i]) { + if (pdblLib->ppOvlyData[i]->hdr.pName) { + MEM_Free(pdblLib->ppOvlyData[i]-> + hdr.pName); + } + MEM_Free(pdblLib->ppOvlyData[i]); + } + } + MEM_Free(pdblLib->ppOvlyData); + } + + /* Close the file */ + if (pdblLib->file) + (*pdblLib->pTarget->dblAttrs.fclose) (pdblLib->file); + + + MEM_FreeObject(pdblLib); +} + +/* + * ======== DBL_create ======== + * Purpose: + * Create a target object by specifying the alloc, free, and + * write functions for the target. + */ +DSP_STATUS DBL_create(struct DBL_TargetObj **pTarget, struct DBL_Attrs *pAttrs) +{ + struct DBL_TargetObj *pdblTarget = NULL; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(pAttrs != NULL); + DBC_Require(pTarget != NULL); + + GT_2trace(DBL_debugMask, GT_ENTER, + "DBL_create: pTarget: 0x%x pAttrs: 0x%x\n", + pTarget, pAttrs); + /* Allocate DBL target object */ + MEM_AllocObject(pdblTarget, struct DBL_TargetObj, DBL_TARGSIGNATURE); + if (pdblTarget == NULL) { + GT_0trace(DBL_debugMask, GT_6CLASS, + "DBL_create: Memory allocation failed\n"); + status = DSP_EMEMORY; + } else { + pdblTarget->dblAttrs = *pAttrs; + /* Allocate buffer for loading target */ + pdblTarget->pBuf = MEM_Calloc(LOADBUFSIZE, MEM_PAGED); + if (pdblTarget->pBuf == NULL) + status = DSP_EMEMORY; + + } + if (DSP_SUCCEEDED(status)) { + *pTarget = pdblTarget; + } else { + *pTarget = NULL; + if (pdblTarget) + DBL_delete(pdblTarget); + + } + DBC_Ensure(DSP_SUCCEEDED(status) && + ((MEM_IsValidHandle((*pTarget), DBL_TARGSIGNATURE)) || + (DSP_FAILED(status) && *pTarget == NULL))); + return status; +} + +/* + * ======== DBL_delete ======== + * Purpose: + * Delete target object and free resources for any loaded libraries. + */ +void DBL_delete(struct DBL_TargetObj *target) +{ + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(target, DBL_TARGSIGNATURE)); + + GT_1trace(DBL_debugMask, GT_ENTER, + "DBL_delete: target: 0x%x\n", target); + + if (target->pBuf) + MEM_Free(target->pBuf); + + MEM_FreeObject(target); +} + +/* + * ======== DBL_exit ======== + * Purpose + * Discontinue usage of DBL module. + */ +void DBL_exit() +{ + DBC_Require(cRefs > 0); + cRefs--; + GT_1trace(DBL_debugMask, GT_5CLASS, + "DBL_exit() ref count: 0x%x\n", cRefs); + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== DBL_getAddr ======== + * Purpose: + * Get address of name in the specified library. + */ +bool DBL_getAddr(struct DBL_LibraryObj *lib, char *name, + struct DBL_Symbol **ppSym) +{ + bool retVal = false; + struct Symbol *symbol; + u16 i; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(lib, DBL_LIBSIGNATURE)); + DBC_Require(name != NULL); + DBC_Require(ppSym != NULL); + + GT_3trace(DBL_debugMask, GT_ENTER, + "DBL_getAddr: libt: 0x%x name: %s pAddr: " + "0x%x\n", lib, name, ppSym); + for (i = 0; i < lib->nSymbols; i++) { + symbol = &lib->symbols[i]; + if (CSL_Strcmp(name, symbol->pSymName) == 0) { + /* Found it */ + *ppSym = &lib->symbols[i].sym; + retVal = true; + break; + } + } + return retVal; +} + +/* + * ======== DBL_getAttrs ======== + * Purpose: + * Retrieve the attributes of the target. + */ +void DBL_getAttrs(struct DBL_TargetObj *target, struct DBL_Attrs *pAttrs) +{ + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(target, DBL_TARGSIGNATURE)); + DBC_Require(pAttrs != NULL); + GT_2trace(DBL_debugMask, GT_ENTER, "DBL_getAttrs: target: 0x%x pAttrs: " + "0x%x\n", target, pAttrs); + *pAttrs = target->dblAttrs; +} + +/* + * ======== DBL_getCAddr ======== + * Purpose: + * Get address of "C" name in the specified library. + */ +bool DBL_getCAddr(struct DBL_LibraryObj *lib, char *name, + struct DBL_Symbol **ppSym) +{ + bool retVal = false; + struct Symbol *symbol; + u16 i; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(lib, DBL_LIBSIGNATURE)); + DBC_Require(name != NULL); + DBC_Require(ppSym != NULL); + + GT_3trace(DBL_debugMask, GT_ENTER, + "DBL_getCAddr: target: 0x%x name:%s pAddr:" + " 0x%x\n", lib, name, ppSym); + for (i = 0; i < lib->nSymbols; i++) { + symbol = &lib->symbols[i]; + if ((CSL_Strcmp(name, symbol->pSymName) == 0) || + (CSL_Strcmp(name, symbol->pSymName + 1) == 0 && + symbol->pSymName[0] == '_')) { + /* Found it */ + *ppSym = &lib->symbols[i].sym; + retVal = true; + break; + } + } + return retVal; +} + +/* + * ======== DBL_getEntry ======== + * Purpose: + * Get program entry point. + * + */ +bool DBL_getEntry(struct DBL_LibraryObj *lib, u32 *pEntry) +{ + struct DBL_LibraryObj *pdblLib = (struct DBL_LibraryObj *)lib; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(pdblLib, DBL_LIBSIGNATURE)); + DBC_Require(pEntry != NULL); + + GT_2trace(DBL_debugMask, GT_ENTER, + "DBL_getEntry: lib: 0x%x pEntry: 0x%x\n", lib, pEntry); + *pEntry = pdblLib->fileHdr.entry; + + return true; +} + +/* + * ======== DBL_getSect ======== + * Purpose: + * Get address and size of a named section. + */ +DSP_STATUS DBL_getSect(struct DBL_LibraryObj *lib, char *name, u32 *pAddr, + u32 *pSize) +{ + struct DBL_LibraryObj *pdblLib = (struct DBL_LibraryObj *)lib; + u16 i; + DSP_STATUS status = DSP_ENOSECT; + + DBC_Require(cRefs > 0); + DBC_Require(name != NULL); + DBC_Require(pAddr != NULL); + DBC_Require(pSize != NULL); + DBC_Require(MEM_IsValidHandle(pdblLib, DBL_LIBSIGNATURE)); + + GT_4trace(DBL_debugMask, GT_ENTER, + "DBL_getSect: lib: 0x%x name: %s pAddr:" + " 0x%x pSize: 0x%x\n", lib, name, pAddr, pSize); + + /* + * Check for DCD and overlay sections. Overlay loader uses DBL_getSect + * to determine whether or not a node has overlay sections. + * DCD section names begin with '.' + */ + if (name[0] == '.') { + /* Get DCD section size (address is 0, since it's a NOLOAD). */ + for (i = 0; i < pdblLib->nDCDSects; i++) { + if (CSL_Strcmp(pdblLib->dcdSects[i].sectHdr.name, + name) == 0) { + *pAddr = 0; + *pSize = pdblLib->dcdSects[i].sectHdr.size * + pdblLib->pTargetInfo->mauSize; + status = DSP_SOK; + break; + } + } + } else { + /* Check for overlay section */ + for (i = 0; i < pdblLib->nOvlySects; i++) { + if (CSL_Strcmp(pdblLib->ppOvlyData[i]->hdr.pName, + name) == 0) { + /* Address and size are meaningless */ + *pAddr = 0; + *pSize = 0; + status = DSP_SOK; + break; + } + } + } + + return status; +} + +/* + * ======== DBL_init ======== + * Purpose: + * Initialize DBL module. + */ +bool DBL_init(void) +{ + bool retVal = true; + + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { + DBC_Assert(!DBL_debugMask.flags); + GT_create(&DBL_debugMask, "BL"); /* "BL" for dBL */ + + } + + if (retVal) + cRefs++; + + + GT_1trace(DBL_debugMask, GT_5CLASS, "DBL_init(), ref count: 0x%x\n", + cRefs); + + DBC_Ensure((retVal && (cRefs > 0)) || (!retVal && (cRefs >= 0))); + + return retVal; +} + +/* + * ======== DBL_load ======== + * Purpose: + * Add symbols/code/data defined in file to that already present + * on the target. + */ +DSP_STATUS DBL_load(struct DBL_LibraryObj *lib, DBL_Flags flags, + struct DBL_Attrs *attrs, u32 *pEntry) +{ + struct DBL_LibraryObj *pdblLib = (struct DBL_LibraryObj *)lib; + struct DBL_TargetObj *dbl; + u16 i; + u16 nSects; + DSP_STATUS status = DSP_EFAIL; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(pdblLib, DBL_LIBSIGNATURE)); + DBC_Require(pEntry != NULL); + DBC_Require(attrs != NULL); + + GT_4trace(DBL_debugMask, GT_ENTER, "DBL_load: lib: 0x%x flags: " + "0x%x attrs: 0x%x pEntry: 0x%x\n", lib, flags, attrs, pEntry); + + dbl = pdblLib->pTarget; + *pEntry = pdblLib->fileHdr.entry; + nSects = pdblLib->fileHdr.numSects; + dbl->dblAttrs = *attrs; + + for (i = 0; i < nSects; i++) { + /* Load the section at the current file offset */ + status = loadSect(dbl, lib); + if (DSP_FAILED(status)) + break; + + } + + /* Done with file, we can close it */ + if (pdblLib->file) { + (*pdblLib->pTarget->dblAttrs.fclose) (pdblLib->file); + pdblLib->file = NULL; + } + return status; +} + +/* + * ======== DBL_loadSect ======== + * Purpose: + * Load a named section from an library (for overlay support). + */ +DSP_STATUS DBL_loadSect(struct DBL_LibraryObj *lib, char *sectName, + struct DBL_Attrs *attrs) +{ + struct DBL_TargetObj *dbl; + s32 i; + s32 phase; + s32 offset = -1; + s32 nSects = -1; + s32 allocdSects = 0; + u32 loadAddr; + u32 runAddr; + u32 size; + u32 space; + u32 ulBytes; + u16 mauSize; + u16 wordSize; + u16 *phaseRef = NULL; + u16 *otherRef = NULL; + char *name = NULL; + struct OvlyData *pOvlyData; + DSP_STATUS status = DSP_ENOSECT; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(lib, DBL_LIBSIGNATURE)); + DBC_Require(sectName != NULL); + DBC_Require(attrs != NULL); + DBC_Require(attrs->write != NULL); + GT_3trace(DBL_debugMask, GT_ENTER, + "DBL_loadSect: lib: 0x%x sectName: %s " + "attrs: 0x%x\n", lib, sectName, attrs); + dbl = lib->pTarget; + mauSize = lib->pTargetInfo->mauSize; + wordSize = lib->pTargetInfo->wordSize; + /* Check for match of sect name in overlay table */ + for (i = 0; i < lib->nOvlySects; i++) { + name = lib->ppOvlyData[i]->hdr.pName; + if (!CSL_Strncmp(name, sectName, CSL_Strlen(name))) { + /* Match found */ + status = DSP_SOK; + break; + } + } + if (DSP_SUCCEEDED(status)) { + DBC_Assert(i < lib->nOvlySects); + pOvlyData = lib->ppOvlyData[i]; + /* + * If node overlay, phase will be encoded in name. If not node + * overlay, set phase to NONE. + */ + phase = (CSL_Strcmp(name, sectName)) ? + CSL_Atoi(sectName + CSL_Strlen(sectName) - 1) : NONE; + /* Get reference count of node phase to be loaded, offset into + * overlay data array, and number of sections to overlay. */ + switch (phase) { + case NONE: + /* Not a node overlay */ + phaseRef = &pOvlyData->hdr.otherRef; + nSects = numOtherSects(pOvlyData); + offset = otherOffset(pOvlyData); + break; + case CREATEPHASE: + phaseRef = &pOvlyData->hdr.createRef; + otherRef = &pOvlyData->hdr.otherRef; + if (*otherRef) { + /* The overlay sections where node phase was + * not specified, have already been loaded. */ + nSects = numCreateSects(pOvlyData); + offset = createOffset(pOvlyData); + } else { + /* Overlay sections where node phase was not + * specified get loaded at create time, along + * with create sects. */ + nSects = numCreateSects(pOvlyData) + + numOtherSects(pOvlyData); + offset = otherOffset(pOvlyData); + } + break; + case DELETEPHASE: + phaseRef = &pOvlyData->hdr.deleteRef; + nSects = numDeleteSects(pOvlyData); + offset = deleteOffset(pOvlyData); + break; + case EXECUTEPHASE: + phaseRef = &pOvlyData->hdr.executeRef; + nSects = numExecuteSects(pOvlyData); + offset = executeOffset(pOvlyData); + break; + default: + /* ERROR */ + DBC_Assert(false); + break; + } + /* Do overlay if reference count is 0 */ + if (!(*phaseRef)) { + /* "Allocate" all sections */ + for (i = 0; i < nSects; i++) { + runAddr = pOvlyData->data[offset + i].runAddr; + size = pOvlyData->data[offset + i].size; + space = pOvlyData->data[offset + i].page; + status = (dbl->dblAttrs.alloc)(dbl->dblAttrs. + rmmHandle, space, size, 0, + &runAddr, true); + if (DSP_FAILED(status)) + break; + + allocdSects++; + } + if (DSP_SUCCEEDED(status)) { + /* Load sections */ + for (i = 0; i < nSects; i++) { + loadAddr = pOvlyData->data[offset + i]. + loadAddr; + runAddr = pOvlyData->data[offset + i]. + runAddr; + size = pOvlyData->data[offset + i]. + size; + space = pOvlyData->data[offset + i]. + page; + /* Convert to word address, call + * write function */ + loadAddr /= (wordSize / mauSize); + runAddr /= (wordSize / mauSize); + ulBytes = size * mauSize; + if ((*attrs->write)(attrs->wHandle, + runAddr, (void *)loadAddr, ulBytes, + space) != ulBytes) { + GT_0trace(DBL_debugMask, + GT_6CLASS, + "DBL_loadSect: write" + " failed\n"); + status = DSP_EFWRITE; + break; + } + } + } + /* Free sections on failure */ + if (DSP_FAILED(status)) + freeSects(dbl, pOvlyData, offset, allocdSects); + + } + } + if (DSP_SUCCEEDED(status)) { + /* Increment reference counts */ + if (otherRef) + *otherRef = *otherRef + 1; + + *phaseRef = *phaseRef + 1; + } + return status; +} + +/* + * ======== DBL_open ======== + * Purpose: + * DBL_open() returns a library handle that can be used to + * load/unload the symbols/code/data via DBL_load()/DBL_unload(). + */ +DSP_STATUS DBL_open(struct DBL_TargetObj *target, char *file, DBL_Flags flags, + struct DBL_LibraryObj **pLib) +{ + struct DBL_LibraryObj *pdblLib = NULL; + u16 nSymbols; + u16 nDCDSects; + DSP_STATUS status = DSP_SOK; + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(target, DBL_TARGSIGNATURE)); + DBC_Require(target->dblAttrs.fopen != NULL); + DBC_Require(file != NULL); + DBC_Require(pLib != NULL); + + GT_3trace(DBL_debugMask, GT_ENTER, "DBL_open: target: 0x%x file: %s " + "pLib: 0x%x\n", target, file, pLib); + /* Allocate DBL library object */ + MEM_AllocObject(pdblLib, struct DBL_LibraryObj, DBL_LIBSIGNATURE); + if (pdblLib == NULL) + status = DSP_EMEMORY; + + /* Open the file */ + if (DSP_SUCCEEDED(status)) { + pdblLib->pTarget = target; + pdblLib->file = (*target->dblAttrs.fopen)(file, "rb"); + if (pdblLib->file == NULL) + status = DSP_EFOPEN; + + } + /* Read file header */ + if (DSP_SUCCEEDED(status)) { + status = readHeader(target, pdblLib); + if (DSP_FAILED(status)) { + GT_0trace(DBL_debugMask, GT_6CLASS, + "DBL_open(): Failed to read file header\n"); + } + } + /* Allocate symbol table */ + if (DSP_SUCCEEDED(status)) { + nSymbols = pdblLib->nSymbols = pdblLib->fileHdr.numSymbols; + pdblLib->symbols = MEM_Calloc(nSymbols * sizeof(struct Symbol), + MEM_PAGED); + if (pdblLib->symbols == NULL) + status = DSP_EMEMORY; + + } + /* Read all the symbols */ + if (DSP_SUCCEEDED(status)) { + status = readSymbols(target, pdblLib); + if (DSP_FAILED(status)) { + GT_0trace(DBL_debugMask, GT_6CLASS, + "DBL_open(): Failed to read symbols\n"); + } + } + /* Allocate DCD sect table */ + if (DSP_SUCCEEDED(status)) { + nDCDSects = pdblLib->nDCDSects = pdblLib->fileHdr.numDCDSects; + pdblLib->dcdSects = MEM_Calloc(nDCDSects * + sizeof(struct DCDSect), MEM_PAGED); + if (pdblLib->dcdSects == NULL) + status = DSP_EMEMORY; + + } + /* Read DCD sections */ + if (DSP_SUCCEEDED(status)) { + status = readDCDSects(target, pdblLib); + if (DSP_FAILED(status)) { + GT_0trace(DBL_debugMask, GT_6CLASS, + "DBL_open(): Failed to read DCD sections\n"); + } + } + /* Read overlay sections */ + if (DSP_SUCCEEDED(status)) { + status = readOvlySects(target, pdblLib); + if (DSP_FAILED(status)) { + GT_0trace(DBL_debugMask, GT_6CLASS, + "DBL_open(): Failed to read " + "overlay sections\n"); + } + } + if (DSP_FAILED(status)) { + *pLib = NULL; + if (pdblLib != NULL) + DBL_close((struct DBL_LibraryObj *) pdblLib); + + } else { + *pLib = pdblLib; + } + DBC_Ensure((DSP_SUCCEEDED(status) && + (MEM_IsValidHandle((*pLib), DBL_LIBSIGNATURE))) || + (DSP_FAILED(status) && *pLib == NULL)); + return status; +} + +/* + * ======== DBL_readSect ======== + * Purpose: + * Read COFF section into a character buffer. + */ +DSP_STATUS DBL_readSect(struct DBL_LibraryObj *lib, char *name, char *pContent, + u32 size) +{ + struct DBL_LibraryObj *pdblLib = (struct DBL_LibraryObj *)lib; + u16 i; + u32 mauSize; + u32 max; + DSP_STATUS status = DSP_ENOSECT; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(pdblLib, DBL_LIBSIGNATURE)); + DBC_Require(name != NULL); + DBC_Require(pContent != NULL); + DBC_Require(size != 0); + GT_4trace(DBL_debugMask, GT_ENTER, "DBL_readSect: lib: 0x%x name: %s " + "pContent: 0x%x size: 0x%x\n", lib, name, pContent, size); + + mauSize = pdblLib->pTargetInfo->mauSize; + + /* Attempt to find match with DCD section names. */ + for (i = 0; i < pdblLib->nDCDSects; i++) { + if (CSL_Strcmp(pdblLib->dcdSects[i].sectHdr.name, name) == 0) { + /* Match found */ + max = pdblLib->dcdSects[i].sectHdr.size * mauSize; + max = (max > size) ? size : max; + memcpy(pContent, pdblLib->dcdSects[i].pData, max); + status = DSP_SOK; + break; + } + } + + return status; +} + +/* + * ======== DBL_setAttrs ======== + * Purpose: + * Set the attributes of the target. + */ +void DBL_setAttrs(struct DBL_TargetObj *target, struct DBL_Attrs *pAttrs) +{ + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(target, DBL_TARGSIGNATURE)); + DBC_Require(pAttrs != NULL); + + GT_2trace(DBL_debugMask, GT_ENTER, "DBL_setAttrs: target: 0x%x pAttrs: " + "0x%x\n", target, pAttrs); + + target->dblAttrs = *pAttrs; +} + +/* + * ======== DBL_unload ======== + * Purpose: + * Remove the symbols/code/data corresponding to the library lib. + */ +void DBL_unload(struct DBL_LibraryObj *lib, struct DBL_Attrs *attrs) +{ + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(lib, DBL_LIBSIGNATURE)); + + GT_1trace(DBL_debugMask, GT_ENTER, "DBL_unload: lib: 0x%x\n", lib); + + /* Nothing to do for static loading */ +} + +/* + * ======== DBL_unloadSect ======== + * Purpose: + * Unload a named section from an library (for overlay support). + */ +DSP_STATUS DBL_unloadSect(struct DBL_LibraryObj *lib, char *sectName, + struct DBL_Attrs *attrs) +{ + struct DBL_TargetObj *dbl; + s32 i; + s32 phase; + s32 offset = -1; + s32 nSects = -1; + u16 *phaseRef = NULL; + u16 *otherRef = NULL; + char *pName = NULL; + struct OvlyData *pOvlyData; + DSP_STATUS status = DSP_ENOSECT; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(lib, DBL_LIBSIGNATURE)); + DBC_Require(sectName != NULL); + + GT_2trace(DBL_debugMask, GT_ENTER, + "DBL_unloadSect: lib: 0x%x sectName: %s\n", lib, sectName); + dbl = lib->pTarget; + /* Check for match of sect name in overlay table */ + for (i = 0; i < lib->nOvlySects; i++) { + pName = lib->ppOvlyData[i]->hdr.pName; + if (!CSL_Strncmp(pName, sectName, CSL_Strlen(pName))) { + /* Match found */ + status = DSP_SOK; + break; + } + } + if (DSP_SUCCEEDED(status)) { + DBC_Assert(i < lib->nOvlySects); + pOvlyData = lib->ppOvlyData[i]; + /* If node overlay, phase will be encoded in name. */ + phase = (CSL_Strcmp(pName, sectName)) ? + CSL_Atoi(sectName + CSL_Strlen(sectName) - 1) : NONE; + switch (phase) { + case NONE: + nSects = numOtherSects(pOvlyData); + phaseRef = &pOvlyData->hdr.otherRef; + offset = otherOffset(pOvlyData); + break; + case CREATEPHASE: + nSects = numCreateSects(pOvlyData); + offset = createOffset(pOvlyData); + phaseRef = &pOvlyData->hdr.createRef; + break; + case DELETEPHASE: + nSects = numDeleteSects(pOvlyData); + offset = deleteOffset(pOvlyData); + phaseRef = &pOvlyData->hdr.deleteRef; + otherRef = &pOvlyData->hdr.otherRef; + break; + case EXECUTEPHASE: + nSects = numExecuteSects(pOvlyData); + offset = executeOffset(pOvlyData); + phaseRef = &pOvlyData->hdr.executeRef; + break; + default: + /* ERROR */ + DBC_Assert(false); + break; + } + if (*phaseRef) { + *phaseRef = *phaseRef - 1; + if (*phaseRef == 0) { + /* Unload overlay sections for phase */ + freeSects(dbl, pOvlyData, offset, nSects); + } + if (phase == DELETEPHASE) { + DBC_Assert(*otherRef); + *otherRef = *otherRef - 1; + if (*otherRef == 0) { + /* Unload other overlay sections */ + nSects = numOtherSects(pOvlyData); + offset = otherOffset(pOvlyData); + freeSects(dbl, pOvlyData, offset, + nSects); + } + } + } + } + + return status; +} + +/* + * ======== freeSects ======== + * Purpose: + * Free section + */ +static void freeSects(struct DBL_TargetObj *dbl, struct OvlyData *pOvlyData, + s32 offset, s32 nSects) +{ + u32 runAddr; + u32 size; + u32 space; + s32 i; + + for (i = 0; i < nSects; i++) { + runAddr = pOvlyData->data[offset + i].runAddr; + size = pOvlyData->data[offset + i].size; + space = pOvlyData->data[offset + i].page; + if (!(dbl->dblAttrs.free) + (dbl->dblAttrs.rmmHandle, space, runAddr, size, true)) { + /* + * Free function will not fail for overlay, unless + * address passed in is bad. + */ + DBC_Assert(false); + } + } +} + +/* + * ======== loadSect ======== + * Purpose: + * Load section to target + */ +static DSP_STATUS loadSect(struct DBL_TargetObj *dbl, + struct DBL_LibraryObj *pdblLib) +{ + struct DBOF_SectHdr sectHdr; + char *pBuf; + struct KFILE_FileObj *file; + u32 space; + u32 addr; + u32 total; + u32 nWords = 0; + u32 nBytes = 0; + u16 mauSize; + u32 bufSize; + DSP_STATUS status = DSP_SOK; + + file = pdblLib->file; + mauSize = pdblLib->pTargetInfo->mauSize; + bufSize = LOADBUFSIZE / mauSize; + pBuf = dbl->pBuf; + + /* Read the section header */ + if ((*dbl->dblAttrs.fread)(§Hdr, sizeof(struct DBOF_SectHdr), + 1, file) != 1) { + GT_0trace(DBL_debugMask, GT_6CLASS, + "Failed to read DCD sect header\n"); + status = DSP_EFREAD; + } else { + if (pdblLib->byteSwapped) { + sectHdr.size = SWAPLONG(sectHdr.size); + sectHdr.addr = SWAPLONG(sectHdr.addr); + sectHdr.page = SWAPWORD(sectHdr.page); + } + } + if (DSP_SUCCEEDED(status)) { + addr = sectHdr.addr; + space = sectHdr.page; + for (total = sectHdr.size; total > 0; total -= nWords) { + nWords = min(total, bufSize); + nBytes = nWords * mauSize; + /* Read section data */ + if ((*dbl->dblAttrs.fread)(pBuf, nBytes, 1, + file) != 1) { + GT_0trace(DBL_debugMask, GT_6CLASS, + "Failed to read DCD sect header\n"); + status = DSP_EFREAD; + break; + } + /* Write section to target */ + if (!(*dbl->dblAttrs.write)(dbl->dblAttrs.wHandle, + addr, pBuf, nBytes, space)) { + GT_0trace(DBL_debugMask, GT_6CLASS, + "Failed to write section data\n"); + status = DSP_EFWRITE; + break; + } + addr += nWords; + } + } + return status; +} + +/* + * ======== readDCDSects ======== + * Purpose: + * Read DCD sections. + */ +static DSP_STATUS readDCDSects(struct DBL_TargetObj *dbl, + struct DBL_LibraryObj *pdblLib) +{ + struct DBOF_DCDSectHdr *pSectHdr; + struct DCDSect *pSect; + struct KFILE_FileObj *file; + u16 nSects; + u16 i; + u16 mauSize; + DSP_STATUS status = DSP_SOK; + + file = pdblLib->file; + mauSize = pdblLib->pTargetInfo->mauSize; + nSects = pdblLib->fileHdr.numDCDSects; + for (i = 0; i < nSects; i++) { + pSect = &pdblLib->dcdSects[i]; + pSectHdr = &pdblLib->dcdSects[i].sectHdr; + /* Read sect header */ + if ((*dbl->dblAttrs.fread)(pSectHdr, + sizeof(struct DBOF_DCDSectHdr), 1, file) != 1) { + GT_0trace(DBL_debugMask, GT_6CLASS, + "Failed to read DCD sect header\n"); + status = DSP_EFREAD; + break; + } + if (pdblLib->byteSwapped) + pSectHdr->size = SWAPLONG(pSectHdr->size); + + pSect->pData = (char *)MEM_Calloc(pSectHdr->size * + mauSize, MEM_PAGED); + if (pSect->pData == NULL) { + GT_2trace(DBL_debugMask, GT_6CLASS, + "Memory allocation for sect %s " + "data failed: Size: 0x%lx\n", pSectHdr->name, + pSectHdr->size); + status = DSP_EMEMORY; + break; + } + /* Read DCD sect data */ + if ((*dbl->dblAttrs.fread)(pSect->pData, mauSize, + pSectHdr->size, file) != pSectHdr->size) { + GT_0trace(DBL_debugMask, GT_6CLASS, + "Failed to read DCD sect data\n"); + status = DSP_EFREAD; + break; + } + } + + return status; +} + +/* + * ======== readHeader ======== + * Purpose: + * Read Header. + */ +static DSP_STATUS readHeader(struct DBL_TargetObj *dbl, + struct DBL_LibraryObj *pdblLib) +{ + struct KFILE_FileObj *file; + s32 i; + struct DBOF_FileHdr *pHdr; + u32 swapMagic; + DSP_STATUS status = DSP_SOK; + + pdblLib->byteSwapped = false; + file = pdblLib->file; + pHdr = &pdblLib->fileHdr; + if ((*dbl->dblAttrs.fread)(pHdr, sizeof(struct DBOF_FileHdr), 1, + file) != 1) { + GT_0trace(DBL_debugMask, GT_6CLASS, + "readHeader: Failed to read file header\n"); + status = DSP_EFREAD; + } + + if (DSP_SUCCEEDED(status)) { + /* Determine if byte swapped */ + for (i = 0; i < NUMTARGS; i++) { + swapMagic = SWAPLONG(pHdr->magic); + if (pHdr->magic == magicTab[i] || swapMagic == + magicTab[i]) { + if (swapMagic == magicTab[i]) { + pdblLib->byteSwapped = true; + pHdr->magic = SWAPLONG(pHdr->magic); + pHdr->entry = SWAPLONG(pHdr->entry); + pHdr->symOffset = SWAPLONG(pHdr-> + symOffset); + pHdr->dcdSectOffset = SWAPLONG(pHdr-> + dcdSectOffset); + pHdr->loadSectOffset = SWAPLONG(pHdr-> + loadSectOffset); + pHdr->ovlySectOffset = SWAPLONG(pHdr-> + ovlySectOffset); + pHdr->numSymbols = SWAPWORD(pHdr-> + numSymbols); + pHdr->numDCDSects = SWAPWORD(pHdr-> + numDCDSects); + pHdr->numSects = SWAPWORD(pHdr-> + numSects); + pHdr->numOvlySects = SWAPWORD(pHdr-> + numOvlySects); + } + break; + } + } + if (i == NUMTARGS) { + GT_0trace(DBL_debugMask, GT_6CLASS, + "readHeader: Failed to determine" + " target type\n"); + status = DSP_ECORRUPTFILE; + } else { + pdblLib->pTargetInfo = &targetTab[i]; + GT_1trace(DBL_debugMask, GT_ENTER, + "COF type: 0x%lx\n", pHdr->magic); + GT_1trace(DBL_debugMask, GT_ENTER, + "Entry point:0x%lx\n", pHdr->entry); + } + } + return status; +} + +/* + * ======== readOvlySects ======== + * Purpose: + * Read Overlay Sections + */ +static DSP_STATUS readOvlySects(struct DBL_TargetObj *dbl, + struct DBL_LibraryObj *pdblLib) +{ + struct DBOF_OvlySectHdr hdr; + struct DBOF_OvlySectData *pData; + struct OvlyData *pOvlyData; + char *pName; + struct KFILE_FileObj *file; + u16 i, j; + u16 nSects; + u16 n; + DSP_STATUS status = DSP_SOK; + + pdblLib->nOvlySects = nSects = pdblLib->fileHdr.numOvlySects; + file = pdblLib->file; + if (nSects > 0) { + pdblLib->ppOvlyData = MEM_Calloc(nSects * sizeof(OvlyData *), + MEM_PAGED); + if (pdblLib->ppOvlyData == NULL) { + GT_0trace(DBL_debugMask, GT_7CLASS, + "Failed to allocatate overlay " + "data memory\n"); + status = DSP_EMEMORY; + } + } + if (DSP_SUCCEEDED(status)) { + /* Read overlay data for each node */ + for (i = 0; i < nSects; i++) { + /* Read overlay section header */ + if ((*dbl->dblAttrs.fread)(&hdr, + sizeof(struct DBOF_OvlySectHdr), 1, file) != 1) { + GT_0trace(DBL_debugMask, GT_6CLASS, + "Failed to read overlay sect" + " header\n"); + status = DSP_EFREAD; + break; + } + if (pdblLib->byteSwapped) { + hdr.nameLen = SWAPWORD(hdr.nameLen); + hdr.numCreateSects = + SWAPWORD(hdr.numCreateSects); + hdr.numDeleteSects = + SWAPWORD(hdr.numDeleteSects); + hdr.numExecuteSects = + SWAPWORD(hdr.numExecuteSects); + hdr.numOtherSects = + SWAPWORD(hdr.numOtherSects); + hdr.resvd = SWAPWORD(hdr.resvd); + } + n = hdr.numCreateSects + hdr.numDeleteSects + + hdr.numExecuteSects + hdr.numOtherSects; + + /* Allocate memory for node's overlay data */ + pOvlyData = (struct OvlyData *)MEM_Calloc + (sizeof(struct OvlyHdr) + + n * sizeof(struct DBOF_OvlySectData), + MEM_PAGED); + if (pOvlyData == NULL) { + GT_0trace(DBL_debugMask, GT_7CLASS, + "Failed to allocatate ovlyay" + " data memory\n"); + status = DSP_EMEMORY; + break; + } + pOvlyData->hdr.dbofHdr = hdr; + pdblLib->ppOvlyData[i] = pOvlyData; + /* Allocate memory for section name */ + pName = (char *)MEM_Calloc(hdr.nameLen + 1, MEM_PAGED); + if (pName == NULL) { + GT_0trace(DBL_debugMask, GT_7CLASS, + "Failed to allocatate ovlyay" + " section name\n"); + status = DSP_EMEMORY; + break; + } + pOvlyData->hdr.pName = pName; + /* Read the overlay section name */ + if ((*dbl->dblAttrs.fread)(pName, sizeof(char), + hdr.nameLen, file) != hdr.nameLen) { + GT_0trace(DBL_debugMask, GT_7CLASS, + "readOvlySects: Unable to " + "read overlay name.\n"); + status = DSP_EFREAD; + break; + } + /* Read the overlay section data */ + pData = pOvlyData->data; + if ((*dbl->dblAttrs.fread)(pData, + sizeof(struct DBOF_OvlySectData), n, file) != n) { + GT_0trace(DBL_debugMask, GT_7CLASS, + "readOvlySects: Unable to " + "read overlay data.\n"); + status = DSP_EFREAD; + break; + } + /* Swap overlay data, if necessary */ + if (pdblLib->byteSwapped) { + for (j = 0; j < n; j++) { + pData[j].loadAddr = + SWAPLONG(pData[j].loadAddr); + pData[j].runAddr = + SWAPLONG(pData[j].runAddr); + pData[j].size = + SWAPLONG(pData[j].size); + pData[j].page = + SWAPWORD(pData[j].page); + } + } + } + } + return status; +} + +/* + * ======== readSymbols ======== + * Purpose: + * Read Symbols + */ +static DSP_STATUS readSymbols(struct DBL_TargetObj *dbl, + struct DBL_LibraryObj *pdblLib) +{ + struct DBOF_SymbolHdr symHdr; + struct KFILE_FileObj *file; + u16 i; + u16 nSymbols; + u16 len; + char *pName = NULL; + DSP_STATUS status = DSP_SOK; + + file = pdblLib->file; + + nSymbols = pdblLib->fileHdr.numSymbols; + + for (i = 0; i < nSymbols; i++) { + /* Read symbol value */ + if ((*dbl->dblAttrs.fread)(&symHdr, + sizeof(struct DBOF_SymbolHdr), 1, file) != 1) { + GT_0trace(DBL_debugMask, GT_6CLASS, + "Failed to read symbol value\n"); + status = DSP_EFREAD; + break; + } + if (pdblLib->byteSwapped) { + symHdr.nameLen = SWAPWORD(symHdr.nameLen); + symHdr.value = SWAPLONG(symHdr.value); + } + /* Allocate buffer for symbol name */ + len = symHdr.nameLen; + pName = (char *)MEM_Calloc(len + 1, MEM_PAGED); + if (pName == NULL) { + GT_0trace(DBL_debugMask, GT_6CLASS, + "Memory allocation failed\n"); + status = DSP_EMEMORY; + break; + } + pdblLib->symbols[i].pSymName = pName; + pdblLib->symbols[i].sym.value = symHdr.value; + /* Read symbol name */ + if ((*dbl->dblAttrs.fread) (pName, sizeof(char), len, file) != + len) { + GT_0trace(DBL_debugMask, GT_6CLASS, + "Failed to read symbol value\n"); + status = DSP_EFREAD; + break; + } else { + pName[len] = '\0'; + GT_2trace(DBL_debugMask, GT_ENTER, + "Symbol: %s Value: 0x%lx\n", + pName, symHdr.value); + } + } + return status; +} + diff --git a/drivers/dsp/bridge/pmgr/dbll.c b/drivers/dsp/bridge/pmgr/dbll.c new file mode 100644 index 0000000..82430a3 --- /dev/null +++ b/drivers/dsp/bridge/pmgr/dbll.c @@ -0,0 +1,1564 @@ +/* + * dbll.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== dbll.c ======== + * + *! Revision History + *! ================ + *! 25-Apr-2030 map: Fixed symbol redefinition bug + unload and return error + *! 08-Apr-2003 map: Consolidated DBL with DBLL loader name + *! 24-Mar-2003 map: Updated findSymbol to support dllview update + *! 23-Jan-2003 map: Updated rmmAlloc to support memory granularity + *! 21-Nov-2002 map: Combine fopen and DLOAD_module_open to increase + *! performance on start. + *! 04-Oct-2002 map: Integrated new TIP dynamic loader w/ DOF api. + *! 27-Sep-2002 map: Changed handle passed to RemoteFree, instead of + *! RMM_free; added GT_trace to rmmDealloc + *! 20-Sep-2002 map: Updated from Code Review + *! 08-Aug-2002 jeh: Updated to support overlays. + *! 25-Jun-2002 jeh: Pass RMM_Addr object to alloc function in rmmAlloc(). + *! 20-Mar-2002 jeh: Created. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include + +/* Dynamic loader library interface */ +#include +#include + +/* ----------------------------------- This */ +#include +#include + +#define DBLL_TARGSIGNATURE 0x544c4c44 /* "TLLD" */ +#define DBLL_LIBSIGNATURE 0x4c4c4c44 /* "LLLD" */ + +/* Number of buckets for symbol hash table */ +#define MAXBUCKETS 211 + +/* Max buffer length */ +#define MAXEXPR 128 + +#ifndef UINT32_C +#define UINT32_C(zzz) ((uint32_t)zzz) +#endif +#define DOFF_ALIGN(x) (((x) + 3) & ~UINT32_C(3)) + +/* + * ======== struct DBLL_TarObj* ======== + * A target may have one or more libraries of symbols/code/data loaded + * onto it, where a library is simply the symbols/code/data contained + * in a DOFF file. + */ +/* + * ======== DBLL_TarObj ======== + */ +struct DBLL_TarObj { + u32 dwSignature; /* For object validation */ + struct DBLL_Attrs attrs; + struct DBLL_LibraryObj *head; /* List of all opened libraries */ +} ; + +/* + * The following 4 typedefs are "super classes" of the dynamic loader + * library types used in dynamic loader functions (dynamic_loader.h). + */ +/* + * ======== DBLLStream ======== + * Contains Dynamic_Loader_Stream + */ +struct DBLLStream { + struct Dynamic_Loader_Stream dlStream; + struct DBLL_LibraryObj *lib; +} ; + +/* + * ======== DBLLSymbol ======== + */ +struct DBLLSymbol { + struct Dynamic_Loader_Sym dlSymbol; + struct DBLL_LibraryObj *lib; +} ; + +/* + * ======== DBLLAlloc ======== + */ + struct DBLLAlloc { + struct Dynamic_Loader_Allocate dlAlloc; + struct DBLL_LibraryObj *lib; +} ; + +/* + * ======== DBLLInit ======== + */ +struct DBLLInit { + struct Dynamic_Loader_Initialize dlInit; + struct DBLL_LibraryObj *lib; +}; + +/* + * ======== DBLL_Library ======== + * A library handle is returned by DBLL_Open() and is passed to DBLL_load() + * to load symbols/code/data, and to DBLL_unload(), to remove the + * symbols/code/data loaded by DBLL_load(). + */ + +/* + * ======== DBLL_LibraryObj ======== + */ + struct DBLL_LibraryObj { + u32 dwSignature; /* For object validation */ + struct DBLL_LibraryObj *next; /* Next library in target's list */ + struct DBLL_LibraryObj *prev; /* Previous in the list */ + struct DBLL_TarObj *pTarget; /* target for this library */ + + /* Objects needed by dynamic loader */ + struct DBLLStream stream; + struct DBLLSymbol symbol; + struct DBLLAlloc allocate; + struct DBLLInit init; + DLOAD_mhandle mHandle; + + char *fileName; /* COFF file name */ + void *fp; /* Opaque file handle */ + u32 entry; /* Entry point */ + DLOAD_mhandle desc; /* desc of DOFF file loaded */ + u32 openRef; /* Number of times opened */ + u32 loadRef; /* Number of times loaded */ + struct GH_THashTab *symTab; /* Hash table of symbols */ + u32 ulPos; +} ; + +/* + * ======== Symbol ======== + */ +struct Symbol { + struct DBLL_Symbol value; + char *name; +} ; +extern bool bSymbolsReloaded; + +static void dofClose(struct DBLL_LibraryObj *zlLib); +static DSP_STATUS dofOpen(struct DBLL_LibraryObj *zlLib); +static s32 NoOp(struct Dynamic_Loader_Initialize *thisptr, void *bufr, + LDR_ADDR locn, struct LDR_SECTION_INFO *info, unsigned bytsiz); + +/* + * Functions called by dynamic loader + * + */ +/* Dynamic_Loader_Stream */ +static int readBuffer(struct Dynamic_Loader_Stream *this, void *buffer, + unsigned bufsize); +static int setFilePosn(struct Dynamic_Loader_Stream *this, unsigned int pos); +/* Dynamic_Loader_Sym */ +static struct dynload_symbol *findSymbol(struct Dynamic_Loader_Sym *this, + const char *name); +static struct dynload_symbol *addToSymbolTable(struct Dynamic_Loader_Sym *this, + const char *name, + unsigned moduleId); +static struct dynload_symbol *findInSymbolTable(struct Dynamic_Loader_Sym *this, + const char *name, + unsigned moduleid); +static void purgeSymbolTable(struct Dynamic_Loader_Sym *this, + unsigned moduleId); +static void *allocate(struct Dynamic_Loader_Sym *this, unsigned memsize); +static void deallocate(struct Dynamic_Loader_Sym *this, void *memPtr); +static void errorReport(struct Dynamic_Loader_Sym *this, const char *errstr, + va_list args); +/* Dynamic_Loader_Allocate */ +static int rmmAlloc(struct Dynamic_Loader_Allocate *this, + struct LDR_SECTION_INFO *info, unsigned align); +static void rmmDealloc(struct Dynamic_Loader_Allocate *this, + struct LDR_SECTION_INFO *info); + +/* Dynamic_Loader_Initialize */ +static int connect(struct Dynamic_Loader_Initialize *this); +static int readMem(struct Dynamic_Loader_Initialize *this, void *buf, + LDR_ADDR addr, struct LDR_SECTION_INFO *info, + unsigned nbytes); +static int writeMem(struct Dynamic_Loader_Initialize *this, void *buf, + LDR_ADDR addr, struct LDR_SECTION_INFO *info, + unsigned nbytes); +static int fillMem(struct Dynamic_Loader_Initialize *this, LDR_ADDR addr, + struct LDR_SECTION_INFO *info, unsigned nbytes, + unsigned val); +static int execute(struct Dynamic_Loader_Initialize *this, LDR_ADDR start); +static void release(struct Dynamic_Loader_Initialize *this); + +/* symbol table hash functions */ +static u16 nameHash(void *name, u16 maxBucket); +static bool nameMatch(void *name, void *sp); +static void symDelete(void *sp); + +#if GT_TRACE +static struct GT_Mask DBLL_debugMask = { NULL, NULL }; /* GT trace variable */ +#endif + +static u32 cRefs; /* module reference count */ + +/* Symbol Redefinition */ +static int bRedefinedSymbol; +static int bGblSearch = 1; + +/* + * ======== DBLL_close ======== + */ +void DBLL_close(struct DBLL_LibraryObj *zlLib) +{ + struct DBLL_TarObj *zlTarget; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(zlLib, DBLL_LIBSIGNATURE)); + DBC_Require(zlLib->openRef > 0); + zlTarget = zlLib->pTarget; + GT_1trace(DBLL_debugMask, GT_ENTER, "DBLL_close: lib: 0x%x\n", zlLib); + zlLib->openRef--; + if (zlLib->openRef == 0) { + /* Remove library from list */ + if (zlTarget->head == zlLib) + zlTarget->head = zlLib->next; + + if (zlLib->prev) + (zlLib->prev)->next = zlLib->next; + + if (zlLib->next) + (zlLib->next)->prev = zlLib->prev; + + /* Free DOF resources */ + dofClose(zlLib); + if (zlLib->fileName) + MEM_Free(zlLib->fileName); + + /* remove symbols from symbol table */ + if (zlLib->symTab) + GH_delete(zlLib->symTab); + + /* remove the library object itself */ + MEM_FreeObject(zlLib); + zlLib = NULL; + } +} + +/* + * ======== DBLL_create ======== + */ +DSP_STATUS DBLL_create(struct DBLL_TarObj **pTarget, struct DBLL_Attrs *pAttrs) +{ + struct DBLL_TarObj *pzlTarget; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(pAttrs != NULL); + DBC_Require(pTarget != NULL); + + GT_2trace(DBLL_debugMask, GT_ENTER, + "DBLL_create: pTarget: 0x%x pAttrs: " + "0x%x\n", pTarget, pAttrs); + /* Allocate DBL target object */ + MEM_AllocObject(pzlTarget, struct DBLL_TarObj, DBLL_TARGSIGNATURE); + if (pTarget != NULL) { + if (pzlTarget == NULL) { + GT_0trace(DBLL_debugMask, GT_6CLASS, + "DBLL_create: Memory allocation" + " failed\n"); + *pTarget = NULL; + status = DSP_EMEMORY; + } else { + pzlTarget->attrs = *pAttrs; + *pTarget = (struct DBLL_TarObj *)pzlTarget; + } + DBC_Ensure((DSP_SUCCEEDED(status) && + MEM_IsValidHandle(((struct DBLL_TarObj *)(*pTarget)), + DBLL_TARGSIGNATURE)) || (DSP_FAILED(status) && + *pTarget == NULL)); + } + + return status; +} + +/* + * ======== DBLL_delete ======== + */ +void DBLL_delete(struct DBLL_TarObj *target) +{ + struct DBLL_TarObj *zlTarget = (struct DBLL_TarObj *)target; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(zlTarget, DBLL_TARGSIGNATURE)); + + GT_1trace(DBLL_debugMask, GT_ENTER, "DBLL_delete: target: 0x%x\n", + target); + + if (zlTarget != NULL) + MEM_FreeObject(zlTarget); + +} + +/* + * ======== DBLL_exit ======== + * Discontinue usage of DBL module. + */ +void DBLL_exit(void) +{ + DBC_Require(cRefs > 0); + + cRefs--; + + GT_1trace(DBLL_debugMask, GT_5CLASS, "DBLL_exit() ref count: 0x%x\n", + cRefs); + + if (cRefs == 0) { + MEM_Exit(); + CSL_Exit(); + GH_exit(); +#if GT_TRACE + DBLL_debugMask.flags = NULL; +#endif + } + + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== DBLL_getAddr ======== + * Get address of name in the specified library. + */ +bool DBLL_getAddr(struct DBLL_LibraryObj *zlLib, char *name, + struct DBLL_Symbol **ppSym) +{ + struct Symbol *sym; + bool status = false; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(zlLib, DBLL_LIBSIGNATURE)); + DBC_Require(name != NULL); + DBC_Require(ppSym != NULL); + DBC_Require(zlLib->symTab != NULL); + + GT_3trace(DBLL_debugMask, GT_ENTER, + "DBLL_getAddr: lib: 0x%x name: %s pAddr:" + " 0x%x\n", zlLib, name, ppSym); + sym = (struct Symbol *)GH_find(zlLib->symTab, name); + if (sym != NULL) { + *ppSym = &sym->value; + status = true; + } + return status; +} + +/* + * ======== DBLL_getAttrs ======== + * Retrieve the attributes of the target. + */ +void DBLL_getAttrs(struct DBLL_TarObj *target, struct DBLL_Attrs *pAttrs) +{ + struct DBLL_TarObj *zlTarget = (struct DBLL_TarObj *)target; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(zlTarget, DBLL_TARGSIGNATURE)); + DBC_Require(pAttrs != NULL); + + if ((pAttrs != NULL) && (zlTarget != NULL)) + *pAttrs = zlTarget->attrs; + +} + +/* + * ======== DBLL_getCAddr ======== + * Get address of a "C" name in the specified library. + */ +bool DBLL_getCAddr(struct DBLL_LibraryObj *zlLib, char *name, + struct DBLL_Symbol **ppSym) +{ + struct Symbol *sym; + char cname[MAXEXPR + 1]; + bool status = false; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(zlLib, DBLL_LIBSIGNATURE)); + DBC_Require(ppSym != NULL); + DBC_Require(zlLib->symTab != NULL); + DBC_Require(name != NULL); + + cname[0] = '_'; + + strncpy(cname + 1, name, sizeof(cname) - 2); + cname[MAXEXPR] = '\0'; /* insure '\0' string termination */ + + /* Check for C name, if not found */ + sym = (struct Symbol *)GH_find(zlLib->symTab, cname); + + if (sym != NULL) { + *ppSym = &sym->value; + status = true; + } + + return status; +} + +/* + * ======== DBLL_getSect ======== + * Get the base address and size (in bytes) of a COFF section. + */ +DSP_STATUS DBLL_getSect(struct DBLL_LibraryObj *lib, char *name, u32 *pAddr, + u32 *pSize) +{ + u32 uByteSize; + bool fOpenedDoff = false; + const struct LDR_SECTION_INFO *sect = NULL; + struct DBLL_LibraryObj *zlLib = (struct DBLL_LibraryObj *)lib; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(name != NULL); + DBC_Require(pAddr != NULL); + DBC_Require(pSize != NULL); + DBC_Require(MEM_IsValidHandle(zlLib, DBLL_LIBSIGNATURE)); + + GT_4trace(DBLL_debugMask, GT_ENTER, + "DBLL_getSect: lib: 0x%x name: %s pAddr:" + " 0x%x pSize: 0x%x\n", lib, name, pAddr, pSize); + /* If DOFF file is not open, we open it. */ + if (zlLib != NULL) { + if (zlLib->fp == NULL) { + status = dofOpen(zlLib); + if (DSP_SUCCEEDED(status)) + fOpenedDoff = true; + + } else { + (*(zlLib->pTarget->attrs.fseek))(zlLib->fp, + zlLib->ulPos, SEEK_SET); + } + } + if (DSP_SUCCEEDED(status)) { + uByteSize = 1; + if (DLOAD_GetSectionInfo(zlLib->desc, name, §)) { + *pAddr = sect->load_addr; + *pSize = sect->size * uByteSize; + /* Make sure size is even for good swap */ + if (*pSize % 2) + (*pSize)++; + + /* Align size */ + *pSize = DOFF_ALIGN(*pSize); + } else { + status = DSP_ENOSECT; + } + } + if (fOpenedDoff) { + dofClose(zlLib); + fOpenedDoff = false; + } + + return status; +} + +/* + * ======== DBLL_init ======== + */ +bool DBLL_init(void) +{ + bool retVal = true; + + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { + DBC_Assert(!DBLL_debugMask.flags); + GT_create(&DBLL_debugMask, "DL"); /* "DL" for dbDL */ + GH_init(); + CSL_Init(); + retVal = MEM_Init(); + if (!retVal) + MEM_Exit(); + + } + + if (retVal) + cRefs++; + + + GT_1trace(DBLL_debugMask, GT_5CLASS, "DBLL_init(), ref count: 0x%x\n", + cRefs); + + DBC_Ensure((retVal && (cRefs > 0)) || (!retVal && (cRefs >= 0))); + + return retVal; +} + +/* + * ======== DBLL_load ======== + */ +DSP_STATUS DBLL_load(struct DBLL_LibraryObj *lib, DBLL_Flags flags, + struct DBLL_Attrs *attrs, u32 *pEntry) +{ + struct DBLL_LibraryObj *zlLib = (struct DBLL_LibraryObj *)lib; + struct DBLL_TarObj *dbzl; + bool gotSymbols = true; + s32 err; + DSP_STATUS status = DSP_SOK; + bool fOpenedDoff = false; + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(zlLib, DBLL_LIBSIGNATURE)); + DBC_Require(pEntry != NULL); + DBC_Require(attrs != NULL); + + GT_4trace(DBLL_debugMask, GT_ENTER, + "DBLL_load: lib: 0x%x flags: 0x%x pEntry:" + " 0x%x\n", lib, flags, attrs, pEntry); + /* + * Load if not already loaded. + */ + if (zlLib->loadRef == 0 || !(flags & DBLL_DYNAMIC)) { + dbzl = zlLib->pTarget; + dbzl->attrs = *attrs; + /* Create a hash table for symbols if not already created */ + if (zlLib->symTab == NULL) { + gotSymbols = false; + zlLib->symTab = GH_create(MAXBUCKETS, + sizeof(struct Symbol), + nameHash, + nameMatch, symDelete); + if (zlLib->symTab == NULL) + status = DSP_EMEMORY; + + } + /* + * Set up objects needed by the dynamic loader + */ + /* Stream */ + zlLib->stream.dlStream.read_buffer = readBuffer; + zlLib->stream.dlStream.set_file_posn = setFilePosn; + zlLib->stream.lib = zlLib; + /* Symbol */ + zlLib->symbol.dlSymbol.Find_Matching_Symbol = findSymbol; + if (gotSymbols) { + zlLib->symbol.dlSymbol.Add_To_Symbol_Table = + findInSymbolTable; + } else { + zlLib->symbol.dlSymbol.Add_To_Symbol_Table = + addToSymbolTable; + } + zlLib->symbol.dlSymbol.Purge_Symbol_Table = purgeSymbolTable; + zlLib->symbol.dlSymbol.Allocate = allocate; + zlLib->symbol.dlSymbol.Deallocate = deallocate; + zlLib->symbol.dlSymbol.Error_Report = errorReport; + zlLib->symbol.lib = zlLib; + /* Allocate */ + zlLib->allocate.dlAlloc.Allocate = rmmAlloc; + zlLib->allocate.dlAlloc.Deallocate = rmmDealloc; + zlLib->allocate.lib = zlLib; + /* Init */ + zlLib->init.dlInit.connect = connect; + zlLib->init.dlInit.readmem = readMem; + zlLib->init.dlInit.writemem = writeMem; + zlLib->init.dlInit.fillmem = fillMem; + zlLib->init.dlInit.execute = execute; + zlLib->init.dlInit.release = release; + zlLib->init.lib = zlLib; + /* If COFF file is not open, we open it. */ + if (zlLib->fp == NULL) { + status = dofOpen(zlLib); + if (DSP_SUCCEEDED(status)) + fOpenedDoff = true; + + } + if (DSP_SUCCEEDED(status)) { + zlLib->ulPos = (*(zlLib->pTarget->attrs.ftell)) + (zlLib->fp); + /* Reset file cursor */ + (*(zlLib->pTarget->attrs.fseek))(zlLib->fp, (long)0, + SEEK_SET); + bSymbolsReloaded = true; + /* The 5th argument, DLOAD_INITBSS, tells the DLL + * module to zero-init all BSS sections. In general, + * this is not necessary and also increases load time. + * We may want to make this configurable by the user */ + err = Dynamic_Load_Module(&zlLib->stream.dlStream, + &zlLib->symbol.dlSymbol, &zlLib->allocate.dlAlloc, + &zlLib->init.dlInit, DLOAD_INITBSS, + &zlLib->mHandle); + + if (err != 0) { + GT_1trace(DBLL_debugMask, GT_6CLASS, + "DBLL_load: " + "Dynamic_Load_Module failed: 0x%lx\n", + err); + status = DSP_EDYNLOAD; + } else if (bRedefinedSymbol) { + zlLib->loadRef++; + DBLL_unload(zlLib, (struct DBLL_Attrs *) attrs); + bRedefinedSymbol = false; + status = DSP_EDYNLOAD; + } else { + *pEntry = zlLib->entry; + } + } + } + if (DSP_SUCCEEDED(status)) + zlLib->loadRef++; + + /* Clean up DOFF resources */ + if (fOpenedDoff) + dofClose(zlLib); + + DBC_Ensure(DSP_FAILED(status) || zlLib->loadRef > 0); + return status; +} + +/* + * ======== DBLL_loadSect ======== + * Not supported for COFF. + */ +DSP_STATUS DBLL_loadSect(struct DBLL_LibraryObj *zlLib, char *sectName, + struct DBLL_Attrs *attrs) +{ + DBC_Require(MEM_IsValidHandle(zlLib, DBLL_LIBSIGNATURE)); + + return DSP_ENOTIMPL; +} + +/* + * ======== DBLL_open ======== + */ +DSP_STATUS DBLL_open(struct DBLL_TarObj *target, char *file, DBLL_Flags flags, + struct DBLL_LibraryObj **pLib) +{ + struct DBLL_TarObj *zlTarget = (struct DBLL_TarObj *)target; + struct DBLL_LibraryObj *zlLib = NULL; + s32 err; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(zlTarget, DBLL_TARGSIGNATURE)); + DBC_Require(zlTarget->attrs.fopen != NULL); + DBC_Require(file != NULL); + DBC_Require(pLib != NULL); + + GT_3trace(DBLL_debugMask, GT_ENTER, + "DBLL_open: target: 0x%x file: %s pLib:" + " 0x%x\n", target, file, pLib); + zlLib = zlTarget->head; + while (zlLib != NULL) { + if (strcmp(zlLib->fileName, file) == 0) { + /* Library is already opened */ + zlLib->openRef++; + break; + } + zlLib = zlLib->next; + } + if (zlLib == NULL) { + /* Allocate DBL library object */ + MEM_AllocObject(zlLib, struct DBLL_LibraryObj, + DBLL_LIBSIGNATURE); + if (zlLib == NULL) { + GT_0trace(DBLL_debugMask, GT_6CLASS, + "DBLL_open: Memory allocation failed\n"); + status = DSP_EMEMORY; + } else { + zlLib->ulPos = 0; + /* Increment ref count to allow close on failure + * later on */ + zlLib->openRef++; + zlLib->pTarget = zlTarget; + /* Keep a copy of the file name */ + zlLib->fileName = MEM_Calloc(strlen(file) + 1, + MEM_PAGED); + if (zlLib->fileName == NULL) { + GT_0trace(DBLL_debugMask, GT_6CLASS, + "DBLL_open: Memory " + "allocation failed\n"); + status = DSP_EMEMORY; + } else { + strncpy(zlLib->fileName, file, + strlen(file) + 1); + } + zlLib->symTab = NULL; + } + } + /* + * Set up objects needed by the dynamic loader + */ + if (DSP_FAILED(status)) + goto func_cont; + + /* Stream */ + zlLib->stream.dlStream.read_buffer = readBuffer; + zlLib->stream.dlStream.set_file_posn = setFilePosn; + zlLib->stream.lib = zlLib; + /* Symbol */ + zlLib->symbol.dlSymbol.Add_To_Symbol_Table = addToSymbolTable; + zlLib->symbol.dlSymbol.Find_Matching_Symbol = findSymbol; + zlLib->symbol.dlSymbol.Purge_Symbol_Table = purgeSymbolTable; + zlLib->symbol.dlSymbol.Allocate = allocate; + zlLib->symbol.dlSymbol.Deallocate = deallocate; + zlLib->symbol.dlSymbol.Error_Report = errorReport; + zlLib->symbol.lib = zlLib; + /* Allocate */ + zlLib->allocate.dlAlloc.Allocate = rmmAlloc; + zlLib->allocate.dlAlloc.Deallocate = rmmDealloc; + zlLib->allocate.lib = zlLib; + /* Init */ + zlLib->init.dlInit.connect = connect; + zlLib->init.dlInit.readmem = readMem; + zlLib->init.dlInit.writemem = writeMem; + zlLib->init.dlInit.fillmem = fillMem; + zlLib->init.dlInit.execute = execute; + zlLib->init.dlInit.release = release; + zlLib->init.lib = zlLib; + if (DSP_SUCCEEDED(status) && zlLib->fp == NULL) + status = dofOpen(zlLib); + + zlLib->ulPos = (*(zlLib->pTarget->attrs.ftell)) (zlLib->fp); + (*(zlLib->pTarget->attrs.fseek))(zlLib->fp, (long) 0, SEEK_SET); + /* Create a hash table for symbols if flag is set */ + if (zlLib->symTab != NULL || !(flags & DBLL_SYMB)) + goto func_cont; + + zlLib->symTab = GH_create(MAXBUCKETS, sizeof(struct Symbol), nameHash, + nameMatch, symDelete); + if (zlLib->symTab == NULL) { + status = DSP_EMEMORY; + } else { + /* Do a fake load to get symbols - set write function to NoOp */ + zlLib->init.dlInit.writemem = NoOp; + err = Dynamic_Open_Module(&zlLib->stream.dlStream, + &zlLib->symbol.dlSymbol, + &zlLib->allocate.dlAlloc, + &zlLib->init.dlInit, 0, + &zlLib->mHandle); + if (err != 0) { + GT_1trace(DBLL_debugMask, GT_6CLASS, "DBLL_open: " + "Dynamic_Load_Module failed: 0x%lx\n", err); + status = DSP_EDYNLOAD; + } else { + /* Now that we have the symbol table, we can unload */ + err = Dynamic_Unload_Module(zlLib->mHandle, + &zlLib->symbol.dlSymbol, + &zlLib->allocate.dlAlloc, + &zlLib->init.dlInit); + if (err != 0) { + GT_1trace(DBLL_debugMask, GT_6CLASS, + "DBLL_open: " + "Dynamic_Unload_Module failed: 0x%lx\n", + err); + status = DSP_EDYNLOAD; + } + zlLib->mHandle = NULL; + } + } +func_cont: + if (DSP_SUCCEEDED(status)) { + if (zlLib->openRef == 1) { + /* First time opened - insert in list */ + if (zlTarget->head) + (zlTarget->head)->prev = zlLib; + + zlLib->prev = NULL; + zlLib->next = zlTarget->head; + zlTarget->head = zlLib; + } + *pLib = (struct DBLL_LibraryObj *)zlLib; + } else { + *pLib = NULL; + if (zlLib != NULL) + DBLL_close((struct DBLL_LibraryObj *)zlLib); + + } + DBC_Ensure((DSP_SUCCEEDED(status) && (zlLib->openRef > 0) && + MEM_IsValidHandle(((struct DBLL_LibraryObj *)(*pLib)), + DBLL_LIBSIGNATURE)) || (DSP_FAILED(status) && *pLib == NULL)); + return status; +} + +/* + * ======== DBLL_readSect ======== + * Get the content of a COFF section. + */ +DSP_STATUS DBLL_readSect(struct DBLL_LibraryObj *lib, char *name, + char *pContent, u32 size) +{ + struct DBLL_LibraryObj *zlLib = (struct DBLL_LibraryObj *)lib; + bool fOpenedDoff = false; + u32 uByteSize; /* size of bytes */ + u32 ulSectSize; /* size of section */ + const struct LDR_SECTION_INFO *sect = NULL; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(zlLib, DBLL_LIBSIGNATURE)); + DBC_Require(name != NULL); + DBC_Require(pContent != NULL); + DBC_Require(size != 0); + + GT_4trace(DBLL_debugMask, GT_ENTER, + "DBLL_readSect: lib: 0x%x name: %s " + "pContent: 0x%x size: 0x%x\n", lib, name, pContent, size); + /* If DOFF file is not open, we open it. */ + if (zlLib != NULL) { + if (zlLib->fp == NULL) { + status = dofOpen(zlLib); + if (DSP_SUCCEEDED(status)) + fOpenedDoff = true; + + } else { + (*(zlLib->pTarget->attrs.fseek))(zlLib->fp, + zlLib->ulPos, SEEK_SET); + } + } + + if (DSP_FAILED(status)) + goto func_cont; + + uByteSize = 1; + if (!DLOAD_GetSectionInfo(zlLib->desc, name, §)) { + status = DSP_ENOSECT; + goto func_cont; + } + /* + * Ensure the supplied buffer size is sufficient to store + * the section content to be read. + */ + ulSectSize = sect->size * uByteSize; + /* Make sure size is even for good swap */ + if (ulSectSize % 2) + ulSectSize++; + + /* Align size */ + ulSectSize = DOFF_ALIGN(ulSectSize); + if (ulSectSize > size) { + status = DSP_EFAIL; + } else { + if (!DLOAD_GetSection(zlLib->desc, sect, pContent)) + status = DSP_EFREAD; + + } +func_cont: + if (fOpenedDoff) { + dofClose(zlLib); + fOpenedDoff = false; + } + return status; +} + +/* + * ======== DBLL_setAttrs ======== + * Set the attributes of the target. + */ +void DBLL_setAttrs(struct DBLL_TarObj *target, struct DBLL_Attrs *pAttrs) +{ + struct DBLL_TarObj *zlTarget = (struct DBLL_TarObj *)target; + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(zlTarget, DBLL_TARGSIGNATURE)); + DBC_Require(pAttrs != NULL); + GT_2trace(DBLL_debugMask, GT_ENTER, + "DBLL_setAttrs: target: 0x%x pAttrs: " + "0x%x\n", target, pAttrs); + if ((pAttrs != NULL) && (zlTarget != NULL)) + zlTarget->attrs = *pAttrs; + +} + +/* + * ======== DBLL_unload ======== + */ +void DBLL_unload(struct DBLL_LibraryObj *lib, struct DBLL_Attrs *attrs) +{ + struct DBLL_LibraryObj *zlLib = (struct DBLL_LibraryObj *)lib; + s32 err = 0; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(zlLib, DBLL_LIBSIGNATURE)); + DBC_Require(zlLib->loadRef > 0); + GT_1trace(DBLL_debugMask, GT_ENTER, "DBLL_unload: lib: 0x%x\n", lib); + zlLib->loadRef--; + /* Unload only if reference count is 0 */ + if (zlLib->loadRef != 0) + goto func_end; + + zlLib->pTarget->attrs = *attrs; + if (zlLib != NULL) { + if (zlLib->mHandle) { + err = Dynamic_Unload_Module(zlLib->mHandle, + &zlLib->symbol.dlSymbol, + &zlLib->allocate.dlAlloc, &zlLib->init.dlInit); + if (err != 0) { + GT_1trace(DBLL_debugMask, GT_5CLASS, + "Dynamic_Unload_Module " + "failed: 0x%x\n", err); + } + } + /* remove symbols from symbol table */ + if (zlLib->symTab != NULL) { + GH_delete(zlLib->symTab); + zlLib->symTab = NULL; + } + /* delete DOFF desc since it holds *lots* of host OS + * resources */ + dofClose(zlLib); + } +func_end: + DBC_Ensure(zlLib->loadRef >= 0); +} + +/* + * ======== DBLL_unloadSect ======== + * Not supported for COFF. + */ +DSP_STATUS DBLL_unloadSect(struct DBLL_LibraryObj *lib, char *sectName, + struct DBLL_Attrs *attrs) +{ + DBC_Require(cRefs > 0); + DBC_Require(sectName != NULL); + GT_2trace(DBLL_debugMask, GT_ENTER, + "DBLL_unloadSect: lib: 0x%x sectName: " + "%s\n", lib, sectName); + return DSP_ENOTIMPL; +} + +/* + * ======== dofClose ======== + */ +static void dofClose(struct DBLL_LibraryObj *zlLib) +{ + if (zlLib->desc) { + DLOAD_module_close(zlLib->desc); + zlLib->desc = NULL; + } + /* close file */ + if (zlLib->fp) { + (zlLib->pTarget->attrs.fclose) (zlLib->fp); + zlLib->fp = NULL; + } +} + +/* + * ======== dofOpen ======== + */ +static DSP_STATUS dofOpen(struct DBLL_LibraryObj *zlLib) +{ + void *open = *(zlLib->pTarget->attrs.fopen); + DSP_STATUS status = DSP_SOK; + + /* First open the file for the dynamic loader, then open COF */ + zlLib->fp = (void *)((DBLL_FOpenFxn)(open))(zlLib->fileName, "rb"); + + /* Open DOFF module */ + if (zlLib->fp && zlLib->desc == NULL) { + (*(zlLib->pTarget->attrs.fseek))(zlLib->fp, (long)0, SEEK_SET); + zlLib->desc = DLOAD_module_open(&zlLib->stream.dlStream, + &zlLib->symbol.dlSymbol); + if (zlLib->desc == NULL) { + (zlLib->pTarget->attrs.fclose)(zlLib->fp); + zlLib->fp = NULL; + status = DSP_EFOPEN; + } + } else { + status = DSP_EFOPEN; + } + + return status; +} + +/* + * ======== nameHash ======== + */ +static u16 nameHash(void *key, u16 maxBucket) +{ + u16 ret; + u16 hash; + char *name = (char *)key; + + DBC_Require(name != NULL); + + hash = 0; + + while (*name) { + hash <<= 1; + hash ^= *name++; + } + + ret = hash % maxBucket; + + return ret; +} + +/* + * ======== nameMatch ======== + */ +static bool nameMatch(void *key, void *value) +{ + DBC_Require(key != NULL); + DBC_Require(value != NULL); + + if ((key != NULL) && (value != NULL)) { + if (strcmp((char *)key, ((struct Symbol *)value)->name) == 0) + return true; + } + return false; +} + +/* + * ======== NoOp ======== + */ +static int NoOp(struct Dynamic_Loader_Initialize *thisptr, void *bufr, + LDR_ADDR locn, struct LDR_SECTION_INFO *info, unsigned bytsize) +{ + return 1; +} + +/* + * ======== symDelete ======== + */ +static void symDelete(void *value) +{ + struct Symbol *sp = (struct Symbol *)value; + + MEM_Free(sp->name); +} + +/* + * Dynamic Loader Functions + */ + +/* Dynamic_Loader_Stream */ +/* + * ======== readBuffer ======== + */ +static int readBuffer(struct Dynamic_Loader_Stream *this, void *buffer, + unsigned bufsize) +{ + struct DBLLStream *pStream = (struct DBLLStream *)this; + struct DBLL_LibraryObj *lib; + int bytesRead = 0; + + DBC_Require(this != NULL); + lib = pStream->lib; + DBC_Require(MEM_IsValidHandle(lib, DBLL_LIBSIGNATURE)); + + if (lib != NULL) { + bytesRead = (*(lib->pTarget->attrs.fread))(buffer, 1, bufsize, + lib->fp); + } + return bytesRead; +} + +/* + * ======== setFilePosn ======== + */ +static int setFilePosn(struct Dynamic_Loader_Stream *this, unsigned int pos) +{ + struct DBLLStream *pStream = (struct DBLLStream *)this; + struct DBLL_LibraryObj *lib; + int status = 0; /* Success */ + + DBC_Require(this != NULL); + lib = pStream->lib; + DBC_Require(MEM_IsValidHandle(lib, DBLL_LIBSIGNATURE)); + + if (lib != NULL) { + status = (*(lib->pTarget->attrs.fseek))(lib->fp, (long)pos, + SEEK_SET); + } + + return status; +} + +/* Dynamic_Loader_Sym */ + +/* + * ======== findSymbol ======== + */ +static struct dynload_symbol *findSymbol(struct Dynamic_Loader_Sym *this, + const char *name) +{ + struct dynload_symbol *retSym; + struct DBLLSymbol *pSymbol = (struct DBLLSymbol *)this; + struct DBLL_LibraryObj *lib; + struct DBLL_Symbol *pSym = NULL; + bool status = false; /* Symbol not found yet */ + + DBC_Require(this != NULL); + lib = pSymbol->lib; + DBC_Require(MEM_IsValidHandle(lib, DBLL_LIBSIGNATURE)); + + if (lib != NULL) { + if (lib->pTarget->attrs.symLookup) { + /* Check current lib + base lib + dep lib + + * persistent lib */ + status = (*(lib->pTarget->attrs.symLookup)) + (lib->pTarget->attrs.symHandle, + lib->pTarget->attrs.symArg, + lib->pTarget->attrs.rmmHandle, name, &pSym); + } else { + /* Just check current lib for symbol */ + status = DBLL_getAddr((struct DBLL_LibraryObj *)lib, + (char *)name, &pSym); + if (!status) { + status = + DBLL_getCAddr((struct DBLL_LibraryObj *)lib, + (char *)name, &pSym); + } + } + } + + if (!status && bGblSearch) { + GT_1trace(DBLL_debugMask, GT_6CLASS, + "findSymbol: Symbol not found: %s\n", name); + } + + DBC_Assert((status && (pSym != NULL)) || (!status && (pSym == NULL))); + + retSym = (struct dynload_symbol *)pSym; + return retSym; +} + +/* + * ======== findInSymbolTable ======== + */ +static struct dynload_symbol *findInSymbolTable(struct Dynamic_Loader_Sym *this, + const char *name, + unsigned moduleid) +{ + struct dynload_symbol *retSym; + struct DBLLSymbol *pSymbol = (struct DBLLSymbol *)this; + struct DBLL_LibraryObj *lib; + struct Symbol *sym; + + DBC_Require(this != NULL); + lib = pSymbol->lib; + DBC_Require(MEM_IsValidHandle(lib, DBLL_LIBSIGNATURE)); + DBC_Require(lib->symTab != NULL); + + sym = (struct Symbol *)GH_find(lib->symTab, (char *) name); + + retSym = (struct dynload_symbol *)&sym->value; + return retSym; +} + +/* + * ======== addToSymbolTable ======== + */ +static struct dynload_symbol *addToSymbolTable(struct Dynamic_Loader_Sym *this, + const char *name, + unsigned moduleId) +{ + struct Symbol *symPtr = NULL; + struct Symbol symbol; + struct dynload_symbol *pSym = NULL; + struct DBLLSymbol *pSymbol = (struct DBLLSymbol *)this; + struct DBLL_LibraryObj *lib; + struct dynload_symbol *retVal; + + DBC_Require(this != NULL); + DBC_Require(name); + lib = pSymbol->lib; + DBC_Require(MEM_IsValidHandle(lib, DBLL_LIBSIGNATURE)); + + /* Check to see if symbol is already defined in symbol table */ + if (!(lib->pTarget->attrs.baseImage)) { + bGblSearch = false; + pSym = findSymbol(this, name); + bGblSearch = true; + if (pSym) { + bRedefinedSymbol = true; + GT_1trace(DBLL_debugMask, GT_6CLASS, + "Symbol already defined in " + "symbol table: %s\n", name); + return NULL; + } + } + /* Allocate string to copy symbol name */ + symbol.name = (char *)MEM_Calloc(strlen((char *const)name) + 1, + MEM_PAGED); + if (symbol.name == NULL) + return NULL; + + if (symbol.name != NULL) { + /* Just copy name (value will be filled in by dynamic loader) */ + strncpy(symbol.name, (char *const)name, + strlen((char *const)name) + 1); + + /* Add symbol to symbol table */ + symPtr = (struct Symbol *)GH_insert(lib->symTab, (void *)name, + (void *)&symbol); + if (symPtr == NULL) + MEM_Free(symbol.name); + + } + if (symPtr != NULL) + retVal = (struct dynload_symbol *)&symPtr->value; + else + retVal = NULL; + + return retVal; +} + +/* + * ======== purgeSymbolTable ======== + */ +static void purgeSymbolTable(struct Dynamic_Loader_Sym *this, unsigned moduleId) +{ + struct DBLLSymbol *pSymbol = (struct DBLLSymbol *)this; + struct DBLL_LibraryObj *lib; + + DBC_Require(this != NULL); + lib = pSymbol->lib; + DBC_Require(MEM_IsValidHandle(lib, DBLL_LIBSIGNATURE)); + + /* May not need to do anything */ +} + +/* + * ======== allocate ======== + */ +static void *allocate(struct Dynamic_Loader_Sym *this, unsigned memsize) +{ + struct DBLLSymbol *pSymbol = (struct DBLLSymbol *)this; + struct DBLL_LibraryObj *lib; + void *buf; + + DBC_Require(this != NULL); + lib = pSymbol->lib; + DBC_Require(MEM_IsValidHandle(lib, DBLL_LIBSIGNATURE)); + + buf = MEM_Calloc(memsize, MEM_PAGED); + + return buf; +} + +/* + * ======== deallocate ======== + */ +static void deallocate(struct Dynamic_Loader_Sym *this, void *memPtr) +{ + struct DBLLSymbol *pSymbol = (struct DBLLSymbol *)this; + struct DBLL_LibraryObj *lib; + + DBC_Require(this != NULL); + lib = pSymbol->lib; + DBC_Require(MEM_IsValidHandle(lib, DBLL_LIBSIGNATURE)); + + MEM_Free(memPtr); +} + +/* + * ======== errorReport ======== + */ +static void errorReport(struct Dynamic_Loader_Sym *this, const char *errstr, + va_list args) +{ + struct DBLLSymbol *pSymbol = (struct DBLLSymbol *)this; + struct DBLL_LibraryObj *lib; + char tempBuf[MAXEXPR]; + + DBC_Require(this != NULL); + lib = pSymbol->lib; + DBC_Require(MEM_IsValidHandle(lib, DBLL_LIBSIGNATURE)); + vsnprintf((char *)tempBuf, MAXEXPR, (char *)errstr, args); + GT_1trace(DBLL_debugMask, GT_5CLASS, "%s\n", tempBuf); +} + +/* Dynamic_Loader_Allocate */ + +/* + * ======== rmmAlloc ======== + */ +static int rmmAlloc(struct Dynamic_Loader_Allocate *this, + struct LDR_SECTION_INFO *info, unsigned align) +{ + struct DBLLAlloc *pAlloc = (struct DBLLAlloc *)this; + struct DBLL_LibraryObj *lib; + DSP_STATUS status = DSP_SOK; + u32 memType; + struct RMM_Addr rmmAddr; + s32 retVal = TRUE; + unsigned stype = DLOAD_SECTION_TYPE(info->type); + char *pToken = NULL; + char *szSecLastToken = NULL; + char *szLastToken = NULL; + char *szSectName = NULL; + char *pszCur; + s32 tokenLen = 0; + s32 segId = -1; + s32 req = -1; + s32 count = 0; + u32 allocSize = 0; + + DBC_Require(this != NULL); + lib = pAlloc->lib; + DBC_Require(MEM_IsValidHandle(lib, DBLL_LIBSIGNATURE)); + + memType = (stype == DLOAD_TEXT) ? DBLL_CODE : (stype == DLOAD_BSS) ? + DBLL_BSS : DBLL_DATA; + + /* Attempt to extract the segment ID and requirement information from + the name of the section */ + DBC_Require(info->name); + tokenLen = strlen((char *)(info->name)) + 1; + + szSectName = MEM_Calloc(tokenLen, MEM_PAGED); + szLastToken = MEM_Calloc(tokenLen, MEM_PAGED); + szSecLastToken = MEM_Calloc(tokenLen, MEM_PAGED); + + if (szSectName == NULL || szSecLastToken == NULL || + szLastToken == NULL) { + status = DSP_EMEMORY; + goto func_cont; + } + strncpy(szSectName, (char *)(info->name), tokenLen); + pszCur = szSectName; + while ((pToken = strsep(&pszCur, ":")) && *pToken != '\0') { + strncpy(szSecLastToken, szLastToken, strlen(szLastToken) + 1); + strncpy(szLastToken, pToken, strlen(pToken) + 1); + pToken = strsep(&pszCur, ":"); + count++; /* optimizes processing*/ + } + /* If pToken is 0 or 1, and szSecLastToken is DYN_DARAM or DYN_SARAM, + or DYN_EXTERNAL, then mem granularity information is present + within the section name - only process if there are at least three + tokens within the section name (just a minor optimization)*/ + if (count >= 3) + strict_strtol(szLastToken, 10, (long *)&req); + + if ((req == 0) || (req == 1)) { + if (strcmp(szSecLastToken, "DYN_DARAM") == 0) { + segId = 0; + } else { + if (strcmp(szSecLastToken, "DYN_SARAM") == 0) { + segId = 1; + } else { + if (strcmp(szSecLastToken, + "DYN_EXTERNAL") == 0) { + segId = 2; + } + } + } + if (segId != -1) { + GT_2trace(DBLL_debugMask, GT_5CLASS, + "Extracted values for memory" + " granularity req [%d] segId [%d]\n", + req, segId); + } + } + MEM_Free(szSectName); + szSectName = NULL; + MEM_Free(szLastToken); + szLastToken = NULL; + MEM_Free(szSecLastToken); + szSecLastToken = NULL; +func_cont: + if (memType == DBLL_CODE) + allocSize = info->size + GEM_L1P_PREFETCH_SIZE; + else + allocSize = info->size; + /* TODO - ideally, we can pass the alignment requirement also + * from here */ + if (lib != NULL) { + status = (lib->pTarget->attrs.alloc)(lib->pTarget-> + attrs.rmmHandle, memType, allocSize, align, + (u32 *)&rmmAddr, segId, req, FALSE); + } + if (DSP_FAILED(status)) { + retVal = false; + } else { + /* RMM gives word address. Need to convert to byte address */ + info->load_addr = rmmAddr.addr * DSPWORDSIZE; + info->run_addr = info->load_addr; + info->context = (u32)rmmAddr.segid; + GT_3trace(DBLL_debugMask, GT_5CLASS, + "Remote alloc: %s base = 0x%lx len" + "= 0x%lx\n", info->name, info->load_addr / DSPWORDSIZE, + info->size / DSPWORDSIZE); + } + return retVal; +} + +/* + * ======== rmmDealloc ======== + */ +static void rmmDealloc(struct Dynamic_Loader_Allocate *this, + struct LDR_SECTION_INFO *info) +{ + struct DBLLAlloc *pAlloc = (struct DBLLAlloc *)this; + struct DBLL_LibraryObj *lib; + u32 segid; + DSP_STATUS status = DSP_SOK; + unsigned stype = DLOAD_SECTION_TYPE(info->type); + u32 memType; + u32 freeSize = 0; + + memType = (stype == DLOAD_TEXT) ? DBLL_CODE : (stype == DLOAD_BSS) ? + DBLL_BSS : DBLL_DATA; + DBC_Require(this != NULL); + lib = pAlloc->lib; + DBC_Require(MEM_IsValidHandle(lib, DBLL_LIBSIGNATURE)); + /* segid was set by alloc function */ + segid = (u32)info->context; + if (memType == DBLL_CODE) + freeSize = info->size + GEM_L1P_PREFETCH_SIZE; + else + freeSize = info->size; + if (lib != NULL) { + status = (lib->pTarget->attrs.free)(lib->pTarget-> + attrs.symHandle, segid, info->load_addr / DSPWORDSIZE, + freeSize, false); + } + if (DSP_SUCCEEDED(status)) { + GT_2trace(DBLL_debugMask, GT_5CLASS, + "Remote dealloc: base = 0x%lx len =" + "0x%lx\n", info->load_addr / DSPWORDSIZE, + freeSize / DSPWORDSIZE); + } +} + +/* Dynamic_Loader_Initialize */ +/* + * ======== connect ======== + */ +static int connect(struct Dynamic_Loader_Initialize *this) +{ + return true; +} + +/* + * ======== readMem ======== + * This function does not need to be implemented. + */ +static int readMem(struct Dynamic_Loader_Initialize *this, void *buf, + LDR_ADDR addr, struct LDR_SECTION_INFO *info, + unsigned nbytes) +{ + struct DBLLInit *pInit = (struct DBLLInit *)this; + struct DBLL_LibraryObj *lib; + int bytesRead = 0; + + DBC_Require(this != NULL); + lib = pInit->lib; + DBC_Require(MEM_IsValidHandle(lib, DBLL_LIBSIGNATURE)); + /* Need WMD_BRD_Read function */ + return bytesRead; +} + +/* + * ======== writeMem ======== + */ +static int writeMem(struct Dynamic_Loader_Initialize *this, void *buf, + LDR_ADDR addr, struct LDR_SECTION_INFO *info, + unsigned nBytes) +{ + struct DBLLInit *pInit = (struct DBLLInit *)this; + struct DBLL_LibraryObj *lib; + struct DBLL_SectInfo sectInfo; + u32 memType; + bool retVal = true; + + DBC_Require(this != NULL); + lib = pInit->lib; + DBC_Require(MEM_IsValidHandle(lib, DBLL_LIBSIGNATURE)); + + memType = (DLOAD_SECTION_TYPE(info->type) == DLOAD_TEXT) ? DBLL_CODE : + DBLL_DATA; + if (lib != NULL) { + retVal = (*lib->pTarget->attrs.write)(lib->pTarget-> + attrs.wHandle, addr, buf, nBytes, memType); + } + if (lib->pTarget->attrs.logWrite) { + sectInfo.name = info->name; + sectInfo.runAddr = info->run_addr; + sectInfo.loadAddr = info->load_addr; + sectInfo.size = info->size; + sectInfo.type = memType; + /* Pass the information about what we've written to + * another module */ + (*lib->pTarget->attrs.logWrite)(lib->pTarget-> + attrs.logWriteHandle, §Info, addr, nBytes); + } + return retVal; +} + +/* + * ======== fillMem ======== + * Fill nBytes of memory at a given address with a given value by + * writing from a buffer containing the given value. Write in + * sets of MAXEXPR (128) bytes to avoid large stack buffer issues. + */ +static int fillMem(struct Dynamic_Loader_Initialize *this, LDR_ADDR addr, + struct LDR_SECTION_INFO *info, unsigned nBytes, + unsigned val) +{ + bool retVal = true; + char *pBuf; + struct DBLL_LibraryObj *lib; + struct DBLLInit *pInit = (struct DBLLInit *)this; + + DBC_Require(this != NULL); + lib = pInit->lib; + pBuf = NULL; + /* Pass the NULL pointer to writeMem to get the start address of Shared + memory. This is a trick to just get the start address, there is no + writing taking place with this Writemem + */ + if ((lib->pTarget->attrs.write) != (DBLL_WriteFxn)NoOp) + writeMem(this, &pBuf, addr, info, 0); + if (pBuf) + memset(pBuf, val, nBytes); + + return retVal; +} + +/* + * ======== execute ======== + */ +static int execute(struct Dynamic_Loader_Initialize *this, LDR_ADDR start) +{ + struct DBLLInit *pInit = (struct DBLLInit *)this; + struct DBLL_LibraryObj *lib; + bool retVal = true; + + DBC_Require(this != NULL); + lib = pInit->lib; + DBC_Require(MEM_IsValidHandle(lib, DBLL_LIBSIGNATURE)); + /* Save entry point */ + if (lib != NULL) + lib->entry = (u32)start; + + return retVal; +} + +/* + * ======== release ======== + */ +static void release(struct Dynamic_Loader_Initialize *this) +{ +} + diff --git a/drivers/dsp/bridge/pmgr/dev.c b/drivers/dsp/bridge/pmgr/dev.c new file mode 100644 index 0000000..1c2f7d5 --- /dev/null +++ b/drivers/dsp/bridge/pmgr/dev.c @@ -0,0 +1,1476 @@ +/* + * dev.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dev.c ======== + * Description: + * Implementation of 'Bridge Mini-driver device operations. + * + * Public Functions: + * DEV_BrdWriteFxn + * DEV_CreateDevice + * DEV_Create2 + * DEV_Destroy2 + * DEV_DestroyDevice + * DEV_GetChnlMgr + * DEV_GetCmmMgr + * DEV_GetCodMgr + * DEV_GetDehMgr + * DEV_GetDevNode + * DEV_GetDSPWordSize + * DEV_GetFirst + * DEV_GetIntfFxns + * DEV_GetIOMgr + * DEV_GetNext + * DEV_GetNodeManager + * DEV_GetSymbol + * DEV_GetWMDContext + * DEV_Exit + * DEV_Init + * DEV_InsertProcObject + * DEV_IsLocked + * DEV_NotifyClient + * DEV_RegisterNotify + * DEV_ReleaseCodMgr + * DEV_RemoveDevice + * DEV_RemoveProcObject + * DEV_SetChnlMgr + * DEV_SetMsgMgr + * DEV_SetLockOwner + * DEV_StartDevice + * + * Private Functions: + * FxnNotImplemented + * InitCodMgr + * InsertDevObject + * IsValidHandle + * RemoveDevObject + * StoreInterfaceFxns + * + *! Revision History: + *! ================ + *! 03-Jan-2005 hn Support for IVA DEH + *! 08-Mar-2004 sb Added the Dynamic Memory Mapping feature + *! 09-Feb-2004 vp Updated to support IVA. + *! 24-Feb-2003 swa PMGR Code review comments incorporated. + *! 29-Nov-2001 jeh Check for DSP_ENOTIMPL status of DEH create function. + *! 05-Nov-2001 kc Added support for DEH module. + *! 05-Aug-2001 ag Shared memory registration moved to WMD_IO_OnLoaded(). + *! 11-Jul-2001 jeh Moved MGR_Create() from DSP_Init() to DEV_StartDevice(). + *! 11-Apr-2001 rr: Removed CMM_RegisterGPPSMSeg. + *! 02-Apr-2001 rr: CHNL_Create failure is printed out. + *! 15-Jan-2001 jeh Removed call to IO_OnLoaded() from DEV_Create2(). + *! 13-Feb-2001 kc: DSP/BIOS Bridge name update. + *! 15-Dec-2000 rr: Dev_Create2 returns error if NODE_CreateMgr fails. + *! 05-Dec-2000 jeh Moved IO_OnLoaded() to PROC_Load. Added DEV_SetMsgMgr. + *! 05-Dev-2000 ag SM Heap for messaging registered via CMM_RegisterGPPSMSeg(). + *! SM heap base and size currently taken from registry. + *! 29-Nov-2000 rr: Incorporated code review changes. + *! 17-Nov-2000 jeh Added calls to get IO manager (IO_Create), IO_OnLoaded(). + *! 06-Oct-2000 rr: DEV_Destroy2 and DEV_Create2 added. + *! 02-Oct-2000 rr: DEV_GetNodeManager added. + *! 11-Aug-2000 ag: Added DEV_GetCmmMgr(), CMM_Init() & CMM_Exit(). + *! Removed & , added + *! 10-Aug-2000 rr: DEV_InsertProcObject/RemoveProcObject added. + *! DEV_Cleanup calls PROC_Detach if it is a matching process. + *! 27-Jul-2000 rr: DEV is in new directoy DEV and produces devlib.lib + *! 17-Jul-2000 rr: DRV Object holds the list of Dev Objects. DEV gets + *! the List and Next devices through DRV. + *! DEV object has a back pointer to DRV Object. + *! 06-Jun-2000 jeh Added DEV_GetSymbol(). + *! 09-May-2000 rr: dwMemBase has index for multiple windows need. + *! 28-Feb-2000 rr: New GT Usage implemented. + *! 03-Feb-2000 rr: GT and Module init/exit Changes.(Done up front from + *! SERVICES) + *! 31-Jan-2000 rr: Comments changed after code review. + *! 21-Jan-2000 rr: windows.h, tchar.h, HMODULE removed. FreeLibrary replaced + *! with LDR_FreeModule + *! 17-Jan-2000 rr: CFG_Get/SetPrivateDword renamed to CFG_Get/SetDevObject. + *! StoreInterfaceFxns stores the new fxn WMD_BRD_SETSTATE. + *! 20-Nov-1999 ag: Actual uSMLength = total - monitor offset. + *! 12-Nov-1999 rr: bIRQ and IRQAttrib taken from the struct CFG_HOSTRES. + *! dMemBase is added with offset for monitor taken from + *! registry. + *! 31-Oct-1999 ag: Added CHNL support. + *! 10-Sep-1999 rr: GT Enabled. DEV_Create will Load the Mini Driver and will + *! find its fxn table. Right now lot of things are hardcoded + *! as the REG is not ready. + *! 10-Jun-1996 rr: Created from WSX + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include +#include + +/* ----------------------------------- Platform Manager */ +#include +#include +#include +#include + +/* ----------------------------------- Resource Manager */ +#include +#include + +/* ----------------------------------- Others */ +#include +#include /* WCD version info. */ + +#include +#include +#include +#include + +/* ----------------------------------- This */ +#include + +/* ----------------------------------- Defines, Data Structures, Typedefs */ + +#define SIGNATURE 0x5f564544 /* "DEV_" (in reverse) */ +#define MAKEVERSION(major, minor) (major * 10 + minor) +#define WCDVERSION MAKEVERSION(WCD_MAJOR_VERSION, WCD_MINOR_VERSION) + +/* The WMD device object: */ +struct DEV_OBJECT { + /* LST requires "link" to be first field! */ + struct LST_ELEM link; /* Link to next DEV_OBJECT. */ + u32 devType; /* Device Type */ + u32 dwSignature; /* Used for object validation. */ + struct CFG_DEVNODE *hDevNode; /* Platform specific device id */ + struct WMD_DEV_CONTEXT *hWmdContext; /* WMD Context Handle */ + struct WMD_DRV_INTERFACE intfFxns; /* Function interface to WMD. */ + struct BRD_OBJECT *lockOwner; /* Client with exclusive access. */ + struct COD_MANAGER *hCodMgr; /* Code manager handle. */ + struct CHNL_MGR *hChnlMgr; /* Channel manager. */ + struct DEH_MGR *hDehMgr; /* DEH manager. */ + struct MSG_MGR *hMsgMgr; /* Message manager. */ + struct IO_MGR *hIOMgr; /* IO manager (CHNL, MSG) */ + struct CMM_OBJECT *hCmmMgr; /* SM memory manager. */ + struct DMM_OBJECT *hDmmMgr; /* Dynamic memory manager. */ + struct LDR_MODULE *hModule; /* WMD Module handle. */ + u32 uWordSize; /* DSP word size: quick access. */ + struct DRV_OBJECT *hDrvObject; /* Driver Object */ + struct LST_LIST *procList; /* List of Proceeosr attached to + * this device */ + struct NODE_MGR *hNodeMgr; +} ; + +/* ----------------------------------- Globals */ +static u32 cRefs; /* Module reference count */ +#if GT_TRACE +static struct GT_Mask debugMask = { NULL, NULL }; /* For debugging */ +#endif + +/* ----------------------------------- Function Prototypes */ +static DSP_STATUS FxnNotImplemented(int arg, ...); +static DSP_STATUS InitCodMgr(struct DEV_OBJECT *pDevObject); +static bool IsValidHandle(struct DEV_OBJECT *hObj); +static void StoreInterfaceFxns(struct WMD_DRV_INTERFACE *pDrvFxns, + OUT struct WMD_DRV_INTERFACE *pIntfFxns); +/* + * ======== DEV_BrdWriteFxn ======== + * Purpose: + * Exported function to be used as the COD write function. This function + * is passed a handle to a DEV_hObject, then calls the + * device's WMD_BRD_Write() function. + */ +u32 DEV_BrdWriteFxn(void *pArb, u32 ulDspAddr, void *pHostBuf, + u32 ulNumBytes, u32 nMemSpace) +{ + struct DEV_OBJECT *pDevObject = (struct DEV_OBJECT *)pArb; + u32 ulWritten = 0; + DSP_STATUS status; + + DBC_Require(cRefs > 0); + DBC_Require(pHostBuf != NULL); /* Required of BrdWrite(). */ + GT_5trace(debugMask, GT_ENTER, + "Entered DEV_BrdWriteFxn, pArb: 0x%x\n\t\t" + "ulDspAddr: 0x%x\n\t\tpHostBuf: 0x%x\n \t\tulNumBytes: 0x%x\n" + "\t\tnMemSpace: 0x%x\n", pArb, ulDspAddr, pHostBuf, + ulNumBytes, nMemSpace); + if (IsValidHandle(pDevObject)) { + /* Require of BrdWrite() */ + DBC_Assert(pDevObject->hWmdContext != NULL); + status = (*pDevObject->intfFxns.pfnBrdWrite)(pDevObject-> + hWmdContext, pHostBuf, ulDspAddr, ulNumBytes, + nMemSpace); + /* Special case of getting the address only */ + if (ulNumBytes == 0) + ulNumBytes = 1; + if (DSP_SUCCEEDED(status)) + ulWritten = ulNumBytes; + + } + GT_1trace(debugMask, GT_ENTER, "Exit DEV_BrdWriteFxn ulWritten: 0x%x\n", + ulWritten); + return ulWritten; +} + +/* + * ======== DEV_CreateDevice ======== + * Purpose: + * Called by the operating system to load the PM Mini Driver for a + * PM board (device). + */ +DSP_STATUS DEV_CreateDevice(OUT struct DEV_OBJECT **phDevObject, + IN CONST char *pstrWMDFileName, + IN CONST struct CFG_HOSTRES *pHostConfig, + IN CONST struct CFG_DSPRES *pDspConfig, + struct CFG_DEVNODE *hDevNode) +{ + struct LDR_MODULE *hModule = NULL; + struct WMD_DRV_INTERFACE *pDrvFxns = NULL; + struct DEV_OBJECT *pDevObject = NULL; + struct CHNL_MGRATTRS mgrAttrs; + struct IO_ATTRS ioMgrAttrs; + u32 uNumWindows; + struct DRV_OBJECT *hDrvObject = NULL; + DSP_STATUS status = DSP_SOK; + DBC_Require(cRefs > 0); + DBC_Require(phDevObject != NULL); + DBC_Require(pstrWMDFileName != NULL); + DBC_Require(pHostConfig != NULL); + DBC_Require(pDspConfig != NULL); + + GT_5trace(debugMask, GT_ENTER, + "Entered DEV_CreateDevice, phDevObject: 0x%x\n" + "\t\tpstrWMDFileName: 0x%x\n\t\tpHostConfig:0x%x\n\t\t" + "pDspConfig: 0x%x\n\t\tnhDevNode: 0x%x\n", phDevObject, + pstrWMDFileName, pHostConfig, pDspConfig, hDevNode); + /* Get the WMD interface functions*/ + WMD_DRV_Entry(&pDrvFxns, pstrWMDFileName); + if (DSP_FAILED(CFG_GetObject((u32 *) &hDrvObject, REG_DRV_OBJECT))) { + /* don't propogate CFG errors from this PROC function */ + GT_0trace(debugMask, GT_7CLASS, + "Failed to get the DRV Object \n"); + status = DSP_EFAIL; + } + /* Create the device object, and pass a handle to the WMD for + * storage. */ + if (DSP_SUCCEEDED(status)) { + DBC_Assert(pDrvFxns); + MEM_AllocObject(pDevObject, struct DEV_OBJECT, SIGNATURE); + if (pDevObject) { + /* Fill out the rest of the Dev Object structure: */ + pDevObject->hDevNode = hDevNode; + pDevObject->hModule = hModule; + pDevObject->hCodMgr = NULL; + pDevObject->hChnlMgr = NULL; + pDevObject->hDehMgr = NULL; + pDevObject->lockOwner = NULL; + pDevObject->uWordSize = pDspConfig->uWordSize; + pDevObject->hDrvObject = hDrvObject; + pDevObject->devType = DSP_UNIT; + /* Store this WMD's interface functions, based on its + * version. */ + StoreInterfaceFxns(pDrvFxns, &pDevObject->intfFxns); + /* Call WMD_DEV_CREATE() to get the WMD's device + * context handle. */ + status = (pDevObject->intfFxns.pfnDevCreate) + (&pDevObject->hWmdContext, pDevObject, + pHostConfig, pDspConfig); + /* Assert WMD_DEV_Create()'s ensure clause: */ + DBC_Assert(DSP_FAILED(status) || (pDevObject-> + hWmdContext != NULL)); + } else { + GT_0trace(debugMask, GT_7CLASS, + "DEV_Create: Out Of Memory"); + status = DSP_EMEMORY; + } + } + /* Attempt to create the COD manager for this device: */ + if (DSP_SUCCEEDED(status)) + status = InitCodMgr(pDevObject); + + /* Attempt to create the channel manager for this device: */ + if (DSP_SUCCEEDED(status)) { + mgrAttrs.cChannels = CHNL_MAXCHANNELS; + ioMgrAttrs.bIRQ = pHostConfig->bIRQRegisters; + ioMgrAttrs.fShared = (pHostConfig->bIRQAttrib & CFG_IRQSHARED); + ioMgrAttrs.uWordSize = pDspConfig->uWordSize; + mgrAttrs.uWordSize = pDspConfig->uWordSize; + uNumWindows = pHostConfig->wNumMemWindows; + if (uNumWindows) { + /* Assume last memory window is for CHNL */ + ioMgrAttrs.dwSMBase = pHostConfig->dwMemBase[1] + + pHostConfig->dwOffsetForMonitor; + ioMgrAttrs.uSMLength = pHostConfig->dwMemLength[1] - + pHostConfig->dwOffsetForMonitor; + } else { + ioMgrAttrs.dwSMBase = 0; + ioMgrAttrs.uSMLength = 0; + GT_0trace(debugMask, GT_7CLASS, + "**There is no memory reserved for " + "shared structures**\n"); + } + status = CHNL_Create(&pDevObject->hChnlMgr, pDevObject, + &mgrAttrs); + if (status == DSP_ENOTIMPL) { + /* It's OK for a device not to have a channel + * manager: */ + status = DSP_SOK; + } + /* Create CMM mgr even if Msg Mgr not impl. */ + status = CMM_Create(&pDevObject->hCmmMgr, + (struct DEV_OBJECT *)pDevObject, NULL); + if (DSP_FAILED(status)) { + GT_0trace(debugMask, GT_7CLASS, + "DEV_Create: Failed to Create SM " + "Manager\n"); + } + /* Only create IO manager if we have a channel manager */ + if (DSP_SUCCEEDED(status) && pDevObject->hChnlMgr) { + status = IO_Create(&pDevObject->hIOMgr, pDevObject, + &ioMgrAttrs); + } + /* Only create DEH manager if we have an IO manager */ + if (DSP_SUCCEEDED(status)) { + /* Instantiate the DEH module */ + status = (*pDevObject->intfFxns.pfnDehCreate) + (&pDevObject->hDehMgr, pDevObject); + } + /* Create DMM mgr . */ + status = DMM_Create(&pDevObject->hDmmMgr, + (struct DEV_OBJECT *)pDevObject, NULL); + if (DSP_FAILED(status)) { + GT_0trace(debugMask, GT_7CLASS, + "DEV_Create: Failed to Create DMM " + "Manager\n"); + } + } + /* Add the new DEV_Object to the global list: */ + if (DSP_SUCCEEDED(status)) { + LST_InitElem(&pDevObject->link); + status = DRV_InsertDevObject(hDrvObject, pDevObject); + } + /* Create the Processor List */ + if (DSP_SUCCEEDED(status)) { + pDevObject->procList = LST_Create(); + if (!(pDevObject->procList)) { + status = DSP_EFAIL; + GT_0trace(debugMask, GT_7CLASS, "DEV_Create: " + "Failed to Create Proc List"); + } + } + /* If all went well, return a handle to the dev object; + * else, cleanup and return NULL in the OUT parameter. */ + if (DSP_SUCCEEDED(status)) { + *phDevObject = pDevObject; + GT_1trace(debugMask, GT_1CLASS, + "DEV_CreateDevice Succeeded \nDevObject " + "0x%x\n", pDevObject); + } else { + if (pDevObject && pDevObject->procList) + LST_Delete(pDevObject->procList); + + if (pDevObject && pDevObject->hCodMgr) + COD_Delete(pDevObject->hCodMgr); + + if (pDevObject && pDevObject->hDmmMgr) + DMM_Destroy(pDevObject->hDmmMgr); + + if (pDevObject) + MEM_FreeObject(pDevObject); + + *phDevObject = NULL; + GT_0trace(debugMask, GT_7CLASS, "DEV_CreateDevice Failed\n"); + } + GT_1trace(debugMask, GT_1CLASS, "Exiting DEV_Create: DevObject 0x%x\n", + *phDevObject); + DBC_Ensure((DSP_SUCCEEDED(status) && IsValidHandle(*phDevObject)) || + (DSP_FAILED(status) && !*phDevObject)); + return status; +} + +/* + * ======== DEV_Create2 ======== + * Purpose: + * After successful loading of the image from WCD_InitComplete2 + * (PROC Auto_Start) or PROC_Load this fxn is called. This creates + * the Node Manager and updates the DEV Object. + */ +DSP_STATUS DEV_Create2(struct DEV_OBJECT *hDevObject) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *pDevObject = hDevObject; + + DBC_Require(cRefs > 0); + DBC_Require(IsValidHandle(hDevObject)); + + GT_1trace(debugMask, GT_ENTER, + "Entered DEV_Create2, hDevObject: 0x%x\n", hDevObject); + /* There can be only one Node Manager per DEV object */ + DBC_Assert(!pDevObject->hNodeMgr); + status = NODE_CreateMgr(&pDevObject->hNodeMgr, hDevObject); + if (DSP_FAILED(status)) { + GT_1trace(debugMask, GT_7CLASS, + "DEV_Create2: NODE_CreateMgr failed, " + "0x%x!\n", status); + pDevObject->hNodeMgr = NULL; + GT_0trace(debugMask, GT_7CLASS, "DEV_Create2: Failed!!\n"); + } + DBC_Ensure((DSP_SUCCEEDED(status) && pDevObject->hNodeMgr != NULL) + || (DSP_FAILED(status) && pDevObject->hNodeMgr == NULL)); + GT_2trace(debugMask, GT_ENTER, + "Exiting DEV_Create2, hNodeMgr: 0x%x, status:" + " 0x%x\n", pDevObject->hNodeMgr, status); + return status; +} + +/* + * ======== DEV_Destroy2 ======== + * Purpose: + * Destroys the Node manager for this device. + */ +DSP_STATUS DEV_Destroy2(struct DEV_OBJECT *hDevObject) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *pDevObject = hDevObject; + + DBC_Require(cRefs > 0); + DBC_Require(IsValidHandle(hDevObject)); + + GT_1trace(debugMask, GT_ENTER, + "Entered DEV_Destroy2, hDevObject: 0x%x\n", + hDevObject); + if (pDevObject->hNodeMgr) { + if (DSP_FAILED(NODE_DeleteMgr(pDevObject->hNodeMgr))) + status = DSP_EFAIL; + else + pDevObject->hNodeMgr = NULL; + + } + if (DSP_FAILED(status)) + GT_0trace(debugMask, GT_7CLASS, "DEV_Destroy2 failed!!\n"); + + DBC_Ensure((DSP_SUCCEEDED(status) && pDevObject->hNodeMgr == NULL) || + DSP_FAILED(status)); + GT_2trace(debugMask, GT_ENTER, + "Exiting DEV_Destroy2, hNodeMgr: 0x%x, status" + " = 0x%x\n", pDevObject->hNodeMgr, status); + return status; +} + +/* + * ======== DEV_DestroyDevice ======== + * Purpose: + * Destroys the channel manager for this device, if any, calls + * WMD_DEV_Destroy(), and then attempts to unload the WMD module. + */ +DSP_STATUS DEV_DestroyDevice(struct DEV_OBJECT *hDevObject) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *pDevObject = hDevObject; + + DBC_Require(cRefs > 0); + + GT_1trace(debugMask, GT_ENTER, "Entered DEV_DestroyDevice, hDevObject: " + "0x%x\n", hDevObject); + if (IsValidHandle(hDevObject)) { + if (pDevObject->hCodMgr) + COD_Delete(pDevObject->hCodMgr); + + if (pDevObject->hNodeMgr) + NODE_DeleteMgr(pDevObject->hNodeMgr); + + /* Free the io, channel, and message managers for this board: */ + if (pDevObject->hIOMgr) { + IO_Destroy(pDevObject->hIOMgr); + pDevObject->hIOMgr = NULL; + } + if (pDevObject->hChnlMgr) { + CHNL_Destroy(pDevObject->hChnlMgr); + pDevObject->hChnlMgr = NULL; + } + if (pDevObject->hMsgMgr) + MSG_Delete(pDevObject->hMsgMgr); + + if (pDevObject->hDehMgr) { + /* Uninitialize DEH module. */ + (*pDevObject->intfFxns.pfnDehDestroy) + (pDevObject->hDehMgr); + } + if (pDevObject->hCmmMgr) + CMM_Destroy(pDevObject->hCmmMgr, true); + + if (pDevObject->hDmmMgr) + DMM_Destroy(pDevObject->hDmmMgr); + + /* Call the driver's WMD_DEV_Destroy() function: */ + /* Require of DevDestroy */ + DBC_Assert(pDevObject->hWmdContext != NULL); + status = (*pDevObject->intfFxns.pfnDevDestroy) + (pDevObject->hWmdContext); + if (DSP_SUCCEEDED(status)) { + if (pDevObject->procList) + LST_Delete(pDevObject->procList); + + /* Remove this DEV_Object from the global list: */ + DRV_RemoveDevObject(pDevObject->hDrvObject, pDevObject); + /* Free The library * LDR_FreeModule + * (pDevObject->hModule);*/ + /* Free this dev object: */ + MEM_FreeObject(pDevObject); + } + } else { + GT_0trace(debugMask, GT_7CLASS, "DEV_Destroy: Invlaid handle"); + status = DSP_EHANDLE; + } + GT_1trace(debugMask, GT_ENTER, "Exit DEV_destroy: status 0x%x\n", + status); + return status; +} + +/* + * ======== DEV_GetChnlMgr ======== + * Purpose: + * Retrieve the handle to the channel manager handle created for this + * device. + */ +DSP_STATUS DEV_GetChnlMgr(struct DEV_OBJECT *hDevObject, + OUT struct CHNL_MGR **phMgr) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *pDevObject = hDevObject; + + DBC_Require(cRefs > 0); + DBC_Require(phMgr != NULL); + + GT_2trace(debugMask, GT_ENTER, + "Entered DEV_GetChnlMgr, hDevObject: 0x%x\n\t" + "\tphMgr: 0x%x\n", hDevObject, phMgr); + if (IsValidHandle(hDevObject)) { + *phMgr = pDevObject->hChnlMgr; + } else { + *phMgr = NULL; + status = DSP_EHANDLE; + GT_0trace(debugMask, GT_7CLASS, + "DEV_GetChnlMgr: Invalid handle"); + } + GT_2trace(debugMask, GT_ENTER, + "Exit DEV_GetChnlMgr: status 0x%x\t\n hMgr: " + "0x%x\n", status, *phMgr); + DBC_Ensure(DSP_SUCCEEDED(status) || ((phMgr != NULL) && + (*phMgr == NULL))); + return status; +} + +/* + * ======== DEV_GetCmmMgr ======== + * Purpose: + * Retrieve the handle to the shared memory manager created for this + * device. + */ +DSP_STATUS DEV_GetCmmMgr(struct DEV_OBJECT *hDevObject, + OUT struct CMM_OBJECT **phMgr) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *pDevObject = hDevObject; + + DBC_Require(cRefs > 0); + DBC_Require(phMgr != NULL); + GT_2trace(debugMask, GT_ENTER, + "Entered DEV_GetCmmMgr, hDevObject: 0x%x\n\t" + "\tphMgr: 0x%x\n", hDevObject, phMgr); + if (IsValidHandle(hDevObject)) { + *phMgr = pDevObject->hCmmMgr; + } else { + *phMgr = NULL; + status = DSP_EHANDLE; + GT_0trace(debugMask, GT_7CLASS, + "DEV_GetCmmMgr: Invalid handle"); + } + GT_2trace(debugMask, GT_ENTER, + "Exit DEV_GetCmmMgr: status 0x%x\t\nhMgr: " + "0x%x\n", status, *phMgr); + DBC_Ensure(DSP_SUCCEEDED(status) || ((phMgr != NULL) && + (*phMgr == NULL))); + return status; +} + +/* + * ======== DEV_GetDmmMgr ======== + * Purpose: + * Retrieve the handle to the dynamic memory manager created for this + * device. + */ +DSP_STATUS DEV_GetDmmMgr(struct DEV_OBJECT *hDevObject, + OUT struct DMM_OBJECT **phMgr) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *pDevObject = hDevObject; + + DBC_Require(cRefs > 0); + DBC_Require(phMgr != NULL); + + GT_2trace(debugMask, GT_ENTER, "Entered DEV_GetDmmMgr, hDevObject: " + "0x%x\n\t\tphMgr: 0x%x\n", hDevObject, phMgr); + if (IsValidHandle(hDevObject)) { + *phMgr = pDevObject->hDmmMgr; + } else { + *phMgr = NULL; + status = DSP_EHANDLE; + GT_0trace(debugMask, GT_7CLASS, + "DEV_GetDmmMgr: Invalid handle"); + } + GT_2trace(debugMask, GT_ENTER, + "Exit DEV_GetDmmMgr: status 0x%x\t\n hMgr: " + "0x%x\n", status, *phMgr); + DBC_Ensure(DSP_SUCCEEDED(status) || ((phMgr != NULL) && + (*phMgr == NULL))); + return status; +} + +/* + * ======== DEV_GetCodMgr ======== + * Purpose: + * Retrieve the COD manager create for this device. + */ +DSP_STATUS DEV_GetCodMgr(struct DEV_OBJECT *hDevObject, + OUT struct COD_MANAGER **phCodMgr) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *pDevObject = hDevObject; + + DBC_Require(cRefs > 0); + DBC_Require(phCodMgr != NULL); + + GT_2trace(debugMask, GT_ENTER, + "Entered DEV_GetCodMgr, hDevObject: 0x%x\n\t\t" + "phCodMgr: 0x%x\n", hDevObject, phCodMgr); + if (IsValidHandle(hDevObject)) { + *phCodMgr = pDevObject->hCodMgr; + } else { + *phCodMgr = NULL; + status = DSP_EHANDLE; + GT_1trace(debugMask, GT_7CLASS, + "DEV_GetCodMgr, invalid handle: 0x%x\n", + hDevObject); + } + GT_2trace(debugMask, GT_ENTER, + "Exit DEV_GetCodMgr: status 0x%x\t\n hCodMgr:" + " 0x%x\n", status, *phCodMgr); + DBC_Ensure(DSP_SUCCEEDED(status) || ((phCodMgr != NULL) && + (*phCodMgr == NULL))); + return status; +} + +/* + * ========= DEV_GetDehMgr ======== + */ +DSP_STATUS DEV_GetDehMgr(struct DEV_OBJECT *hDevObject, + OUT struct DEH_MGR **phDehMgr) +{ + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(phDehMgr != NULL); + DBC_Require(MEM_IsValidHandle(hDevObject, SIGNATURE)); + if (IsValidHandle(hDevObject)) { + *phDehMgr = hDevObject->hDehMgr; + } else { + *phDehMgr = NULL; + status = DSP_EHANDLE; + GT_0trace(debugMask, GT_7CLASS, + "DEV_GetDehMgr: Invalid handle"); + } + return status; +} + +/* + * ======== DEV_GetDevNode ======== + * Purpose: + * Retrieve the platform specific device ID for this device. + */ +DSP_STATUS DEV_GetDevNode(struct DEV_OBJECT *hDevObject, + OUT struct CFG_DEVNODE **phDevNode) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *pDevObject = hDevObject; + + DBC_Require(cRefs > 0); + DBC_Require(phDevNode != NULL); + + GT_2trace(debugMask, GT_ENTER, + "Entered DEV_GetDevNode, hDevObject: 0x%x\n\t" + "\tphDevNode: 0x%x\n", hDevObject, phDevNode); + if (IsValidHandle(hDevObject)) { + *phDevNode = pDevObject->hDevNode; + } else { + *phDevNode = NULL; + status = DSP_EHANDLE; + GT_0trace(debugMask, GT_7CLASS, + "DEV_GetDevNode: Invalid handle"); + } + GT_2trace(debugMask, GT_ENTER, + "Exit DEV_GetDevNode: status 0x%x\t\nhDevNode:" + "0x%x\n", status, *phDevNode); + DBC_Ensure(DSP_SUCCEEDED(status) || ((phDevNode != NULL) && + (*phDevNode == NULL))); + return status; +} + +/* + * ======== DEV_GetFirst ======== + * Purpose: + * Retrieve the first Device Object handle from an internal linked list + * DEV_OBJECTs maintained by DEV. + */ +struct DEV_OBJECT *DEV_GetFirst(void) +{ + struct DEV_OBJECT *pDevObject = NULL; + + pDevObject = (struct DEV_OBJECT *)DRV_GetFirstDevObject(); + + DBC_Ensure((pDevObject == NULL) || IsValidHandle(pDevObject)); + + return pDevObject; +} + +/* + * ======== DEV_GetIntfFxns ======== + * Purpose: + * Retrieve the WMD interface function structure for the loaded WMD. + * ppIntfFxns != NULL. + */ +DSP_STATUS DEV_GetIntfFxns(struct DEV_OBJECT *hDevObject, + OUT struct WMD_DRV_INTERFACE **ppIntfFxns) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *pDevObject = hDevObject; + + DBC_Require(cRefs > 0); + DBC_Require(ppIntfFxns != NULL); + + GT_2trace(debugMask, GT_ENTER, + "Entered DEV_GetIntfFxns, hDevObject: 0x%x\n\t" + "\tppIntfFxns: 0x%x\n", hDevObject, ppIntfFxns); + if (IsValidHandle(hDevObject)) { + *ppIntfFxns = &pDevObject->intfFxns; + } else { + *ppIntfFxns = NULL; + status = DSP_EHANDLE; + GT_0trace(debugMask, GT_7CLASS, + "DEV_GetIntDxns: Invalid handle"); + } + GT_2trace(debugMask, GT_ENTER, "Exit DEV_GetIntFxns: status 0x%x\t\n" + "ppIntFxns: 0x%x\n", status, *ppIntfFxns); + DBC_Ensure(DSP_SUCCEEDED(status) || ((ppIntfFxns != NULL) && + (*ppIntfFxns == NULL))); + return status; +} + +/* + * ========= DEV_GetIOMgr ======== + */ +DSP_STATUS DEV_GetIOMgr(struct DEV_OBJECT *hDevObject, + OUT struct IO_MGR **phIOMgr) +{ + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(phIOMgr != NULL); + DBC_Require(MEM_IsValidHandle(hDevObject, SIGNATURE)); + + if (IsValidHandle(hDevObject)) { + *phIOMgr = hDevObject->hIOMgr; + } else { + *phIOMgr = NULL; + status = DSP_EHANDLE; + GT_0trace(debugMask, GT_7CLASS, "DEV_GetIOMgr: Invalid handle"); + } + + return status; +} + +/* + * ======== DEV_GetNext ======== + * Purpose: + * Retrieve the next Device Object handle from an internal linked list + * of DEV_OBJECTs maintained by DEV, after having previously called + * DEV_GetFirst() and zero or more DEV_GetNext + */ +struct DEV_OBJECT *DEV_GetNext(struct DEV_OBJECT *hDevObject) +{ + struct DEV_OBJECT *pNextDevObject = NULL; + + if (IsValidHandle(hDevObject)) { + pNextDevObject = (struct DEV_OBJECT *) + DRV_GetNextDevObject((u32)hDevObject); + } + DBC_Ensure((pNextDevObject == NULL) || IsValidHandle(pNextDevObject)); + return pNextDevObject; +} + +/* + * ========= DEV_GetMsgMgr ======== + */ +void DEV_GetMsgMgr(struct DEV_OBJECT *hDevObject, + OUT struct MSG_MGR **phMsgMgr) +{ + DBC_Require(cRefs > 0); + DBC_Require(phMsgMgr != NULL); + DBC_Require(MEM_IsValidHandle(hDevObject, SIGNATURE)); + + *phMsgMgr = hDevObject->hMsgMgr; +} + +/* + * ======== DEV_GetNodeManager ======== + * Purpose: + * Retrieve the Node Manager Handle + */ +DSP_STATUS DEV_GetNodeManager(struct DEV_OBJECT *hDevObject, + OUT struct NODE_MGR **phNodeMgr) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *pDevObject = hDevObject; + + DBC_Require(cRefs > 0); + DBC_Require(phNodeMgr != NULL); + + GT_2trace(debugMask, GT_ENTER, + "Entered DEV_GetNodeManager, hDevObject: 0x%x" + "\n\t\tphNodeMgr: 0x%x\n", hDevObject, phNodeMgr); + if (IsValidHandle(hDevObject)) { + *phNodeMgr = pDevObject->hNodeMgr; + } else { + *phNodeMgr = NULL; + status = DSP_EHANDLE; + GT_1trace(debugMask, GT_7CLASS, + "DEV_GetNodeManager, invalid handle: 0x" + "%x\n", hDevObject); + } + GT_2trace(debugMask, GT_ENTER, + "Exit DEV_GetNodeManager: status 0x%x\t\nhMgr:" + " 0x%x\n", status, *phNodeMgr); + DBC_Ensure(DSP_SUCCEEDED(status) || ((phNodeMgr != NULL) && + (*phNodeMgr == NULL))); + return status; +} + +/* + * ======== DEV_GetSymbol ======== + */ +DSP_STATUS DEV_GetSymbol(struct DEV_OBJECT *hDevObject, + IN CONST char *pstrSym, OUT u32 *pulValue) +{ + DSP_STATUS status = DSP_SOK; + struct COD_MANAGER *hCodMgr; + + DBC_Require(cRefs > 0); + DBC_Require(pstrSym != NULL && pulValue != NULL); + + GT_3trace(debugMask, GT_ENTER, + "Entered DEV_GetSymbol, hDevObject: 0x%x\n\t\t" + "pstrSym: 0x%x\n\t\tpulValue: 0x%x\n", hDevObject, pstrSym, + pulValue); + if (IsValidHandle(hDevObject)) { + status = DEV_GetCodMgr(hDevObject, &hCodMgr); + if (DSP_SUCCEEDED(status)) { + DBC_Assert(hCodMgr != NULL); + status = COD_GetSymValue(hCodMgr, (char *)pstrSym, + pulValue); + } + } else { + status = DSP_EHANDLE; + GT_0trace(debugMask, GT_7CLASS, + "DEV_GetSymbol: Invalid handle"); + } + GT_2trace(debugMask, GT_ENTER, "Exit DEV_GetSymbol: status 0x%x\t\n" + "hWmdContext: 0x%x\n", status, *pulValue); + return status; +} + +/* + * ======== DEV_GetWMDContext ======== + * Purpose: + * Retrieve the WMD Context handle, as returned by the WMD_Create fxn. + */ +DSP_STATUS DEV_GetWMDContext(struct DEV_OBJECT *hDevObject, + OUT struct WMD_DEV_CONTEXT **phWmdContext) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *pDevObject = hDevObject; + + DBC_Require(cRefs > 0); + DBC_Require(phWmdContext != NULL); + GT_2trace(debugMask, GT_ENTER, + "Entered DEV_GetWMDContext, hDevObject: 0x%x\n" + "\t\tphWmdContext: 0x%x\n", hDevObject, phWmdContext); + if (IsValidHandle(hDevObject)) { + *phWmdContext = pDevObject->hWmdContext; + } else { + *phWmdContext = NULL; + status = DSP_EHANDLE; + GT_0trace(debugMask, GT_7CLASS, + "DEV_GetWMDContext: Invalid handle"); + } + + GT_2trace(debugMask, GT_ENTER, + "Exit DEV_GetWMDContext: status 0x%x\t\n" + "hWmdContext: 0x%x\n", status, *phWmdContext); + DBC_Ensure(DSP_SUCCEEDED(status) || ((phWmdContext != NULL) && + (*phWmdContext == NULL))); + return status; +} + +/* + * ======== DEV_Exit ======== + * Purpose: + * Decrement reference count, and free resources when reference count is + * 0. + */ +void DEV_Exit(void) +{ + DBC_Require(cRefs > 0); + + cRefs--; + + if (cRefs == 0) { + CMM_Exit(); + DMM_Exit(); + } + + GT_1trace(debugMask, GT_5CLASS, "Entered DEV_Exit, ref count: 0x%x\n", + cRefs); + + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== DEV_Init ======== + * Purpose: + * Initialize DEV's private state, keeping a reference count on each call. + */ +bool DEV_Init(void) +{ + bool fCmm, fDmm, fRetval = true; + + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { + /* Set the Trace mask */ + DBC_Assert(!debugMask.flags); + GT_create(&debugMask, "DV"); /* "DV" for DeVice */ + fCmm = CMM_Init(); + fDmm = DMM_Init(); + + fRetval = fCmm && fDmm; + + if (!fRetval) { + if (fCmm) + CMM_Exit(); + + + if (fDmm) + DMM_Exit(); + + } + } + + if (fRetval) + cRefs++; + + + GT_1trace(debugMask, GT_5CLASS, "Entered DEV_Init, ref count: 0x%x\n", + cRefs); + + DBC_Ensure((fRetval && (cRefs > 0)) || (!fRetval && (cRefs >= 0))); + + return fRetval; +} + +/* + * ======== DEV_NotifyClients ======== + * Purpose: + * Notify all clients of this device of a change in device status. + */ +DSP_STATUS DEV_NotifyClients(struct DEV_OBJECT *hDevObject, u32 ulStatus) +{ + DSP_STATUS status = DSP_SOK; + + struct DEV_OBJECT *pDevObject = hDevObject; + DSP_HPROCESSOR hProcObject; + + GT_2trace(debugMask, GT_ENTER, + "Entered DEV_NotifyClients, hDevObject: 0x%x\n" + "\t\tulStatus: 0x%x\n", hDevObject, ulStatus); + for (hProcObject = (DSP_HPROCESSOR)LST_First(pDevObject->procList); + hProcObject != NULL; + hProcObject = (DSP_HPROCESSOR)LST_Next(pDevObject->procList, + (struct LST_ELEM *)hProcObject)) + PROC_NotifyClients(hProcObject, (u32) ulStatus); + + return status; +} + +/* + * ======== DEV_RemoveDevice ======== + */ +DSP_STATUS DEV_RemoveDevice(struct CFG_DEVNODE *hDevNode) +{ + struct DEV_OBJECT *hDevObject; /* handle to device object */ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *pDevObject; + + GT_1trace(debugMask, GT_ENTER, + "Entered DEV_RemoveDevice, hDevNode: 0x%x\n", hDevNode); + /* Retrieve the device object handle originaly stored with + * the DevNode: */ + status = CFG_GetDevObject(hDevNode, (u32 *)&hDevObject); + if (DSP_SUCCEEDED(status)) { + /* Remove the Processor List */ + pDevObject = (struct DEV_OBJECT *)hDevObject; + /* Destroy the device object. */ + status = DEV_DestroyDevice(hDevObject); + if (DSP_SUCCEEDED(status)) { + /* Null out the handle stored with the DevNode. */ + GT_0trace(debugMask, GT_1CLASS, + "DEV_RemoveDevice, success"); + } + } + GT_1trace(debugMask, GT_ENTER, "Exit DEV_RemoveDevice, status: 0x%x\n", + status); + return status; +} + +/* + * ======== DEV_SetChnlMgr ======== + * Purpose: + * Set the channel manager for this device. + */ +DSP_STATUS DEV_SetChnlMgr(struct DEV_OBJECT *hDevObject, struct CHNL_MGR *hMgr) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *pDevObject = hDevObject; + + DBC_Require(cRefs > 0); + + GT_2trace(debugMask, GT_ENTER, + "Entered DEV_SetChnlMgr, hDevObject: 0x%x\n\t" + "\thMgr:0x%x\n", hDevObject, hMgr); + if (IsValidHandle(hDevObject)) { + pDevObject->hChnlMgr = hMgr; + } else { + status = DSP_EHANDLE; + GT_0trace(debugMask, GT_7CLASS, + "DEV_SetChnlMgr, Invalid handle\n"); + } + DBC_Ensure(DSP_FAILED(status) || (pDevObject->hChnlMgr == hMgr)); + return status; +} + +/* + * ======== DEV_SetMsgMgr ======== + * Purpose: + * Set the message manager for this device. + */ +void DEV_SetMsgMgr(struct DEV_OBJECT *hDevObject, struct MSG_MGR *hMgr) +{ + DBC_Require(cRefs > 0); + DBC_Require(IsValidHandle(hDevObject)); + GT_2trace(debugMask, GT_ENTER, + "Entered DEV_SetMsgMgr, hDevObject: 0x%x\n\t\t" + "hMgr: 0x%x\n", hDevObject, hMgr); + hDevObject->hMsgMgr = hMgr; +} + +/* + * ======== DEV_StartDevice ======== + * Purpose: + * Initializes the new device with the BRIDGE environment. + */ +DSP_STATUS DEV_StartDevice(struct CFG_DEVNODE *hDevNode) +{ + struct DEV_OBJECT *hDevObject = NULL; /* handle to 'Bridge Device */ + struct CFG_HOSTRES hostRes; /* resources struct. */ + struct CFG_DSPRES dspRes; /* DSP resources struct */ + char szWMDFileName[CFG_MAXSEARCHPATHLEN] = "UMA"; /* wmd filename */ + DSP_STATUS status; + struct MGR_OBJECT *hMgrObject = NULL; + + DBC_Require(cRefs > 0); + + GT_1trace(debugMask, GT_ENTER, + "Entered DEV_StartDevice, hDevObject: 0x%x\n", hDevNode); + status = CFG_GetHostResources(hDevNode, &hostRes); + if (DSP_SUCCEEDED(status)) { + /* Get DSP resources of device from Registry: */ + status = CFG_GetDSPResources(hDevNode, &dspRes); + if (DSP_FAILED(status)) { + GT_1trace(debugMask, GT_7CLASS, + "Failed to get WMD DSP resources" + " from registry: 0x%x ", status); + } + } else { + GT_1trace(debugMask, GT_7CLASS, + "Failed to get WMD Host resources " + "from registry: 0x%x ", status); + } + if (DSP_SUCCEEDED(status)) { + /* Given all resources, create a device object. */ + status = DEV_CreateDevice(&hDevObject, szWMDFileName, &hostRes, + &dspRes, hDevNode); + if (DSP_SUCCEEDED(status)) { + /* Store away the hDevObject with the DEVNODE */ + status = CFG_SetDevObject(hDevNode, (u32)hDevObject); + if (DSP_FAILED(status)) { + /* Clean up */ + GT_1trace(debugMask, GT_7CLASS, + "Failed to set DevObject in the " + "Registry: 0x%x", status); + DEV_DestroyDevice(hDevObject); + hDevObject = NULL; + } + } else { + GT_1trace(debugMask, GT_7CLASS, + "Failed to Create Device: 0x%x", + status); + } + } + if (DSP_SUCCEEDED(status)) { + /* Create the Manager Object */ + status = MGR_Create(&hMgrObject, hDevNode); + } + if (DSP_FAILED(status)) { + GT_1trace(debugMask, GT_7CLASS, "Failed to MGR object: 0x%x", + status); + status = DSP_EFAIL; + } + if (DSP_FAILED(status)) { + if (hDevObject) + DEV_DestroyDevice(hDevObject); + + /* Ensure the device extension is NULL */ + CFG_SetDevObject(hDevNode, 0L); + } + GT_1trace(debugMask, GT_ENTER, "Exiting DEV_StartDevice status 0x%x\n", + status); + return status; +} + +/* + * ======== FxnNotImplemented ======== + * Purpose: + * Takes the place of a WMD Null Function. + * Parameters: + * Multiple, optional. + * Returns: + * DSP_ENOTIMPL: Always. + */ +static DSP_STATUS FxnNotImplemented(int arg, ...) +{ + DBG_Trace(DBG_LEVEL1, + "WARNING: Calling a non-implemented WMD function.\n"); + + return DSP_ENOTIMPL; +} + +/* + * ======== IsValidHandle ======== + * Purpose: + * Validate the device object handle. + * Parameters: + * hDevObject: Handle to device object created with + * DEV_CreateDevice(). + * Returns: + * true if handle is valid; false otherwise. + * Requires: + * Ensures: + */ +static bool IsValidHandle(struct DEV_OBJECT *hObj) +{ + bool retVal; + + retVal = (hObj != NULL) && (hObj->dwSignature == SIGNATURE); + + return retVal; +} + +/* + * ======== InitCodMgr ======== + * Purpose: + * Create a COD manager for this device. + * Parameters: + * pDevObject: Pointer to device object created with + * DEV_CreateDevice() + * Returns: + * DSP_SOK: Success. + * DSP_EHANDLE: Invalid hDevObject. + * Requires: + * Should only be called once by DEV_CreateDevice() for a given DevObject. + * Ensures: + */ +static DSP_STATUS InitCodMgr(struct DEV_OBJECT *pDevObject) +{ + DSP_STATUS status = DSP_SOK; + char *szDummyFile = "dummy"; + + DBC_Require(cRefs > 0); + DBC_Require(!IsValidHandle(pDevObject) || + (pDevObject->hCodMgr == NULL)); + GT_1trace(debugMask, GT_ENTER, "Entering InitCodMgr pDevObject: 0x%x", + pDevObject); + status = COD_Create(&pDevObject->hCodMgr, szDummyFile, NULL); + GT_1trace(debugMask, GT_ENTER, "Exiting InitCodMgr status 0x%x\n ", + status); + return status; +} + +/* + * ======== DEV_InsertProcObject ======== + * Purpose: + * Insert a ProcObject into the list maintained by DEV. + * Parameters: + * pProcObject: Ptr to ProcObject to insert. + * pDevObject: Ptr to Dev Object where the list is. + * pbAlreadyAttached: Ptr to return the bool + * Returns: + * DSP_SOK: If successful. + * Requires: + * List Exists + * hDevObject is Valid handle + * DEV Initialized + * pbAlreadyAttached != NULL + * hProcObject != 0 + * Ensures: + * DSP_SOK and List is not Empty. + */ +DSP_STATUS DEV_InsertProcObject(struct DEV_OBJECT *hDevObject, + u32 hProcObject, + OUT bool *pbAlreadyAttached) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *pDevObject = (struct DEV_OBJECT *)hDevObject; + + GT_2trace(debugMask, GT_ENTER, + "Entering DEV_InsetProcObject pProcObject 0x%x" + "pDevObject 0x%x\n", hProcObject, hDevObject); + DBC_Require(cRefs > 0); + DBC_Require(IsValidHandle(pDevObject)); + DBC_Require(hProcObject != 0); + DBC_Require(pDevObject->procList != NULL); + DBC_Require(pbAlreadyAttached != NULL); + if (!LST_IsEmpty(pDevObject->procList)) + *pbAlreadyAttached = true; + + /* Add DevObject to tail. */ + LST_PutTail(pDevObject->procList, (struct LST_ELEM *)hProcObject); + + GT_1trace(debugMask, GT_ENTER, + "Exiting DEV_InsetProcObject status 0x%x\n", status); + DBC_Ensure(DSP_SUCCEEDED(status) && !LST_IsEmpty(pDevObject->procList)); + + return status; +} + +/* + * ======== DEV_RemoveProcObject ======== + * Purpose: + * Search for and remove a Proc object from the given list maintained + * by the DEV + * Parameters: + * pProcObject: Ptr to ProcObject to insert. + * pDevObject Ptr to Dev Object where the list is. + * Returns: + * DSP_SOK: If successful. + * Requires: + * List exists and is not empty + * hProcObject != 0 + * hDevObject is a valid Dev handle. + * Ensures: + * Details: + * List will be deleted when the DEV is destroyed. + */ +DSP_STATUS DEV_RemoveProcObject(struct DEV_OBJECT *hDevObject, + u32 hProcObject) +{ + DSP_STATUS status = DSP_EFAIL; + struct LST_ELEM *pCurElem; + struct DEV_OBJECT *pDevObject = (struct DEV_OBJECT *)hDevObject; + + DBC_Require(IsValidHandle(pDevObject)); + DBC_Require(hProcObject != 0); + DBC_Require(pDevObject->procList != NULL); + DBC_Require(!LST_IsEmpty(pDevObject->procList)); + + GT_1trace(debugMask, GT_ENTER, + "Entering DEV_RemoveProcObject hDevObject " + "0x%x\n", hDevObject); + /* Search list for pDevObject: */ + for (pCurElem = LST_First(pDevObject->procList); pCurElem != NULL; + pCurElem = LST_Next(pDevObject->procList, pCurElem)) { + /* If found, remove it. */ + if ((u32)pCurElem == hProcObject) { + LST_RemoveElem(pDevObject->procList, pCurElem); + status = DSP_SOK; + break; + } + } + GT_1trace(debugMask, GT_ENTER, "DEV_RemoveProcObject returning 0x%x\n", + status); + return status; +} + +DSP_STATUS DEV_GetDevType(struct DEV_OBJECT *hdevObject, u32 *devType) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *pDevObject = (struct DEV_OBJECT *)hdevObject; + + *devType = pDevObject->devType; + + return status; +} + +/* + * ======== StoreInterfaceFxns ======== + * Purpose: + * Copy the WMD's interface functions into the device object, + * ensuring that FxnNotImplemented() is set for: + * + * 1. All WMD function pointers which are NULL; and + * 2. All function slots in the struct DEV_OBJECT structure which have no + * corresponding slots in the the WMD's interface, because the WMD + * is of an *older* version. + * Parameters: + * pIntfFxns: Interface Fxn Structure of the WCD's Dev Object. + * pDrvFxns: Interface Fxns offered by the WMD during DEV_Create(). + * Returns: + * Requires: + * Input pointers are valid. + * WMD is *not* written for a newer WCD. + * Ensures: + * All function pointers in the dev object's Fxn interface are not NULL. + */ +static void StoreInterfaceFxns(struct WMD_DRV_INTERFACE *pDrvFxns, + OUT struct WMD_DRV_INTERFACE *pIntfFxns) +{ + u32 dwWMDVersion; + + /* Local helper macro: */ +#define StoreFxn(cast, pfn) \ + (pIntfFxns->pfn = ((pDrvFxns->pfn != NULL) ? pDrvFxns->pfn : \ + (cast)FxnNotImplemented)) + + DBC_Require(pIntfFxns != NULL); + DBC_Require(pDrvFxns != NULL); + DBC_Require(MAKEVERSION(pDrvFxns->dwWCDMajorVersion, + pDrvFxns->dwWCDMinorVersion) <= WCDVERSION); + dwWMDVersion = MAKEVERSION(pDrvFxns->dwWCDMajorVersion, + pDrvFxns->dwWCDMinorVersion); + pIntfFxns->dwWCDMajorVersion = pDrvFxns->dwWCDMajorVersion; + pIntfFxns->dwWCDMinorVersion = pDrvFxns->dwWCDMinorVersion; + /* Install functions up to WCD version .80 (first alpha): */ + if (dwWMDVersion > 0) { + StoreFxn(WMD_DEV_CREATE, pfnDevCreate); + StoreFxn(WMD_DEV_DESTROY, pfnDevDestroy); + StoreFxn(WMD_DEV_CTRL, pfnDevCntrl); + StoreFxn(WMD_BRD_MONITOR, pfnBrdMonitor); + StoreFxn(WMD_BRD_START, pfnBrdStart); + StoreFxn(WMD_BRD_STOP, pfnBrdStop); + StoreFxn(WMD_BRD_STATUS, pfnBrdStatus); + StoreFxn(WMD_BRD_READ, pfnBrdRead); + StoreFxn(WMD_BRD_WRITE, pfnBrdWrite); + StoreFxn(WMD_BRD_SETSTATE, pfnBrdSetState); + StoreFxn(WMD_BRD_MEMCOPY, pfnBrdMemCopy); + StoreFxn(WMD_BRD_MEMWRITE, pfnBrdMemWrite); + StoreFxn(WMD_BRD_MEMMAP, pfnBrdMemMap); + StoreFxn(WMD_BRD_MEMUNMAP, pfnBrdMemUnMap); + StoreFxn(WMD_CHNL_CREATE, pfnChnlCreate); + StoreFxn(WMD_CHNL_DESTROY, pfnChnlDestroy); + StoreFxn(WMD_CHNL_OPEN, pfnChnlOpen); + StoreFxn(WMD_CHNL_CLOSE, pfnChnlClose); + StoreFxn(WMD_CHNL_ADDIOREQ, pfnChnlAddIOReq); + StoreFxn(WMD_CHNL_GETIOC, pfnChnlGetIOC); + StoreFxn(WMD_CHNL_CANCELIO, pfnChnlCancelIO); + StoreFxn(WMD_CHNL_FLUSHIO, pfnChnlFlushIO); + StoreFxn(WMD_CHNL_GETINFO, pfnChnlGetInfo); + StoreFxn(WMD_CHNL_GETMGRINFO, pfnChnlGetMgrInfo); + StoreFxn(WMD_CHNL_IDLE, pfnChnlIdle); + StoreFxn(WMD_CHNL_REGISTERNOTIFY, pfnChnlRegisterNotify); + StoreFxn(WMD_DEH_CREATE, pfnDehCreate); + StoreFxn(WMD_DEH_DESTROY, pfnDehDestroy); + StoreFxn(WMD_DEH_NOTIFY, pfnDehNotify); + StoreFxn(WMD_DEH_REGISTERNOTIFY, pfnDehRegisterNotify); + StoreFxn(WMD_DEH_GETINFO, pfnDehGetInfo); + StoreFxn(WMD_IO_CREATE, pfnIOCreate); + StoreFxn(WMD_IO_DESTROY, pfnIODestroy); + StoreFxn(WMD_IO_ONLOADED, pfnIOOnLoaded); + StoreFxn(WMD_IO_GETPROCLOAD, pfnIOGetProcLoad); + StoreFxn(WMD_MSG_CREATE, pfnMsgCreate); + StoreFxn(WMD_MSG_CREATEQUEUE, pfnMsgCreateQueue); + StoreFxn(WMD_MSG_DELETE, pfnMsgDelete); + StoreFxn(WMD_MSG_DELETEQUEUE, pfnMsgDeleteQueue); + StoreFxn(WMD_MSG_GET, pfnMsgGet); + StoreFxn(WMD_MSG_PUT, pfnMsgPut); + StoreFxn(WMD_MSG_REGISTERNOTIFY, pfnMsgRegisterNotify); + StoreFxn(WMD_MSG_SETQUEUEID, pfnMsgSetQueueId); + } + /* Add code for any additional functions in newer WMD versions here: */ + /* Ensure postcondition: */ + DBC_Ensure(pIntfFxns->pfnDevCreate != NULL); + DBC_Ensure(pIntfFxns->pfnDevDestroy != NULL); + DBC_Ensure(pIntfFxns->pfnDevCntrl != NULL); + DBC_Ensure(pIntfFxns->pfnBrdMonitor != NULL); + DBC_Ensure(pIntfFxns->pfnBrdStart != NULL); + DBC_Ensure(pIntfFxns->pfnBrdStop != NULL); + DBC_Ensure(pIntfFxns->pfnBrdStatus != NULL); + DBC_Ensure(pIntfFxns->pfnBrdRead != NULL); + DBC_Ensure(pIntfFxns->pfnBrdWrite != NULL); + DBC_Ensure(pIntfFxns->pfnChnlCreate != NULL); + DBC_Ensure(pIntfFxns->pfnChnlDestroy != NULL); + DBC_Ensure(pIntfFxns->pfnChnlOpen != NULL); + DBC_Ensure(pIntfFxns->pfnChnlClose != NULL); + DBC_Ensure(pIntfFxns->pfnChnlAddIOReq != NULL); + DBC_Ensure(pIntfFxns->pfnChnlGetIOC != NULL); + DBC_Ensure(pIntfFxns->pfnChnlCancelIO != NULL); + DBC_Ensure(pIntfFxns->pfnChnlFlushIO != NULL); + DBC_Ensure(pIntfFxns->pfnChnlGetInfo != NULL); + DBC_Ensure(pIntfFxns->pfnChnlGetMgrInfo != NULL); + DBC_Ensure(pIntfFxns->pfnChnlIdle != NULL); + DBC_Ensure(pIntfFxns->pfnChnlRegisterNotify != NULL); + DBC_Ensure(pIntfFxns->pfnDehCreate != NULL); + DBC_Ensure(pIntfFxns->pfnDehDestroy != NULL); + DBC_Ensure(pIntfFxns->pfnDehNotify != NULL); + DBC_Ensure(pIntfFxns->pfnDehRegisterNotify != NULL); + DBC_Ensure(pIntfFxns->pfnDehGetInfo != NULL); + DBC_Ensure(pIntfFxns->pfnIOCreate != NULL); + DBC_Ensure(pIntfFxns->pfnIODestroy != NULL); + DBC_Ensure(pIntfFxns->pfnIOOnLoaded != NULL); + DBC_Ensure(pIntfFxns->pfnIOGetProcLoad != NULL); + DBC_Ensure(pIntfFxns->pfnMsgSetQueueId != NULL); + +#undef StoreFxn +} + diff --git a/drivers/dsp/bridge/pmgr/dmm.c b/drivers/dsp/bridge/pmgr/dmm.c new file mode 100644 index 0000000..803de93 --- /dev/null +++ b/drivers/dsp/bridge/pmgr/dmm.c @@ -0,0 +1,692 @@ +/* + * dmm.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== dmm.c ======== + * Purpose: + * The Dynamic Memory Manager (DMM) module manages the DSP Virtual address + * space that can be directly mapped to any MPU buffer or memory region + * + * Public Functions: + * DMM_CreateTables + * DMM_Create + * DMM_Destroy + * DMM_Exit + * DMM_Init + * DMM_MapMemory + * DMM_Reset + * DMM_ReserveMemory + * DMM_UnMapMemory + * DMM_UnReserveMemory + * + * Private Functions: + * AddRegion + * CreateRegion + * GetRegion + * GetFreeRegion + * GetMappedRegion + * + * Notes: + * Region: Generic memory entitiy having a start address and a size + * Chunk: Reserved region + * + * + *! Revision History: + *! ================ + *! 04-Jun-2008 Hari K : Optimized DMM implementation. Removed linked list + *! and instead used Table approach. + *! 19-Apr-2004 sb: Integrated Alan's code review updates. + *! 17-Mar-2004 ap: Fixed GetRegion for size=0 using tighter bound. + *! 20-Feb-2004 sb: Created. + *! + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include + +/* ----------------------------------- Platform Manager */ +#include +#include + +/* ----------------------------------- This */ +#include + +/* ----------------------------------- Defines, Data Structures, Typedefs */ +/* Object signatures */ +#define DMMSIGNATURE 0x004d4d44 /* "DMM" (in reverse) */ + +#define DMM_ADDR_VIRTUAL(a) \ + (((struct MapPage *)(a) - pVirtualMappingTable) * PG_SIZE_4K +\ + dynMemMapBeg) +#define DMM_ADDR_TO_INDEX(a) (((a) - dynMemMapBeg) / PG_SIZE_4K) + +/* DMM Mgr */ +struct DMM_OBJECT { + u32 dwSignature; /* Used for object validation */ + /* Dmm Lock is used to serialize access mem manager for + * multi-threads. */ + struct SYNC_CSOBJECT *hDmmLock; /* Lock to access dmm mgr */ +}; + + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask DMM_debugMask = { NULL, NULL }; /* GT trace variable */ +#endif + +static u32 cRefs; /* module reference count */ +struct MapPage { + u32 RegionSize:15; + u32 MappedSize:15; + u32 bReserved:1; + u32 bMapped:1; +}; + +/* Create the free list */ +static struct MapPage *pVirtualMappingTable; +static u32 iFreeRegion; /* The index of free region */ +static u32 iFreeSize; +static u32 *pPhysicalAddrTable; /* Physical address of MPU buffer */ +static u32 dynMemMapBeg; /* The Beginning of dynamic memory mapping */ +static u32 TableSize;/* The size of virtual and physical pages tables */ + +/* ----------------------------------- Function Prototypes */ +static struct MapPage *GetRegion(u32 addr); +static struct MapPage *GetFreeRegion(u32 aSize); +static struct MapPage *GetMappedRegion(u32 aAddr); +#ifdef DSP_DMM_DEBUG +u32 DMM_MemMapDump(struct DMM_OBJECT *hDmmMgr); +#endif + +/* ======== DMM_CreateTables ======== + * Purpose: + * Create table to hold the information of physical address + * the buffer pages that is passed by the user, and the table + * to hold the information of the virtual memory that is reserved + * for DSP. + */ +DSP_STATUS DMM_CreateTables(struct DMM_OBJECT *hDmmMgr, u32 addr, u32 size) +{ + struct DMM_OBJECT *pDmmObj = (struct DMM_OBJECT *)hDmmMgr; + DSP_STATUS status = DSP_SOK; + + GT_3trace(DMM_debugMask, GT_ENTER, + "Entered DMM_CreateTables () hDmmMgr %x, addr" + " %x, size %x\n", hDmmMgr, addr, size); + status = DMM_DeleteTables(pDmmObj); + if (DSP_SUCCEEDED(status)) { + SYNC_EnterCS(pDmmObj->hDmmLock); + dynMemMapBeg = addr; + TableSize = (size/PG_SIZE_4K) + 1; + /* Create the free list */ + pVirtualMappingTable = (struct MapPage *) MEM_Calloc + (TableSize*sizeof(struct MapPage), MEM_NONPAGED); + if (pVirtualMappingTable == NULL) + status = DSP_EMEMORY; + else { + /* This table will be used + * to store the virtual to physical + * address translations + */ + pPhysicalAddrTable = (u32 *)MEM_Calloc + (TableSize*sizeof(u32), MEM_NONPAGED); + GT_1trace(DMM_debugMask, GT_4CLASS, + "DMM_CreateTables: Allocate" + "memory for pPhysicalAddrTable=%d entries\n", + TableSize); + if (pPhysicalAddrTable == NULL) { + status = DSP_EMEMORY; + GT_0trace(DMM_debugMask, GT_7CLASS, + "DMM_CreateTables: Memory allocation for " + "pPhysicalAddrTable failed\n"); + } else { + /* On successful allocation, + * all entries are zero ('free') */ + iFreeRegion = 0; + iFreeSize = TableSize*PG_SIZE_4K; + pVirtualMappingTable[0].RegionSize = TableSize; + } + } + SYNC_LeaveCS(pDmmObj->hDmmLock); + } else + GT_0trace(DMM_debugMask, GT_7CLASS, + "DMM_CreateTables: DMM_DeleteTables" + "Failure\n"); + + GT_1trace(DMM_debugMask, GT_4CLASS, "Leaving DMM_CreateTables status" + "0x%x\n", status); + return status; +} + +/* + * ======== DMM_Create ======== + * Purpose: + * Create a dynamic memory manager object. + */ +DSP_STATUS DMM_Create(OUT struct DMM_OBJECT **phDmmMgr, + struct DEV_OBJECT *hDevObject, + IN CONST struct DMM_MGRATTRS *pMgrAttrs) +{ + struct DMM_OBJECT *pDmmObject = NULL; + DSP_STATUS status = DSP_SOK; + DBC_Require(cRefs > 0); + DBC_Require(phDmmMgr != NULL); + + GT_3trace(DMM_debugMask, GT_ENTER, + "DMM_Create: phDmmMgr: 0x%x hDevObject: " + "0x%x pMgrAttrs: 0x%x\n", phDmmMgr, hDevObject, pMgrAttrs); + *phDmmMgr = NULL; + /* create, zero, and tag a cmm mgr object */ + MEM_AllocObject(pDmmObject, struct DMM_OBJECT, DMMSIGNATURE); + if (pDmmObject != NULL) { + status = SYNC_InitializeCS(&pDmmObject->hDmmLock); + if (DSP_SUCCEEDED(status)) + *phDmmMgr = pDmmObject; + else + DMM_Destroy(pDmmObject); + } else { + GT_0trace(DMM_debugMask, GT_7CLASS, + "DMM_Create: Object Allocation " + "Failure(DMM Object)\n"); + status = DSP_EMEMORY; + } + GT_2trace(DMM_debugMask, GT_4CLASS, + "Leaving DMM_Create status %x pDmmObject %x\n", + status, pDmmObject); + + return status; +} + +/* + * ======== DMM_Destroy ======== + * Purpose: + * Release the communication memory manager resources. + */ +DSP_STATUS DMM_Destroy(struct DMM_OBJECT *hDmmMgr) +{ + struct DMM_OBJECT *pDmmObj = (struct DMM_OBJECT *)hDmmMgr; + DSP_STATUS status = DSP_SOK; + + GT_1trace(DMM_debugMask, GT_ENTER, + "Entered DMM_Destroy () hDmmMgr %x\n", hDmmMgr); + DBC_Require(cRefs > 0); + if (MEM_IsValidHandle(hDmmMgr, DMMSIGNATURE)) { + status = DMM_DeleteTables(pDmmObj); + if (DSP_SUCCEEDED(status)) { + /* Delete CS & dmm mgr object */ + SYNC_DeleteCS(pDmmObj->hDmmLock); + MEM_FreeObject(pDmmObj); + } else + GT_0trace(DMM_debugMask, GT_7CLASS, + "DMM_Destroy: DMM_DeleteTables " + "Failure\n"); + } else + status = DSP_EHANDLE; + GT_1trace(DMM_debugMask, GT_4CLASS, "Leaving DMM_Destroy status %x\n", + status); + return status; +} + + +/* + * ======== DMM_DeleteTables ======== + * Purpose: + * Delete DMM Tables. + */ +DSP_STATUS DMM_DeleteTables(struct DMM_OBJECT *hDmmMgr) +{ + struct DMM_OBJECT *pDmmObj = (struct DMM_OBJECT *)hDmmMgr; + DSP_STATUS status = DSP_SOK; + + GT_1trace(DMM_debugMask, GT_ENTER, + "Entered DMM_DeleteTables () hDmmMgr %x\n", hDmmMgr); + DBC_Require(cRefs > 0); + if (MEM_IsValidHandle(hDmmMgr, DMMSIGNATURE)) { + /* Delete all DMM tables */ + SYNC_EnterCS(pDmmObj->hDmmLock); + + if (pVirtualMappingTable != NULL) + MEM_Free(pVirtualMappingTable); + + if (pPhysicalAddrTable != NULL) + MEM_Free(pPhysicalAddrTable); + + SYNC_LeaveCS(pDmmObj->hDmmLock); + } else + status = DSP_EHANDLE; + GT_1trace(DMM_debugMask, GT_4CLASS, + "Leaving DMM_DeleteTables status %x\n", status); + return status; +} + + + + +/* + * ======== DMM_Exit ======== + * Purpose: + * Discontinue usage of module; free resources when reference count + * reaches 0. + */ +void DMM_Exit(void) +{ + DBC_Require(cRefs > 0); + + cRefs--; + + GT_1trace(DMM_debugMask, GT_ENTER, + "exiting DMM_Exit, ref count:0x%x\n", cRefs); +} + +/* + * ======== DMM_GetHandle ======== + * Purpose: + * Return the dynamic memory manager object for this device. + * This is typically called from the client process. + */ +DSP_STATUS DMM_GetHandle(DSP_HPROCESSOR hProcessor, + OUT struct DMM_OBJECT **phDmmMgr) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *hDevObject; + + GT_2trace(DMM_debugMask, GT_ENTER, + "DMM_GetHandle: hProcessor %x, phDmmMgr" + "%x\n", hProcessor, phDmmMgr); + DBC_Require(cRefs > 0); + DBC_Require(phDmmMgr != NULL); + if (hProcessor != NULL) + status = PROC_GetDevObject(hProcessor, &hDevObject); + else + hDevObject = DEV_GetFirst(); /* default */ + + if (DSP_SUCCEEDED(status)) + status = DEV_GetDmmMgr(hDevObject, phDmmMgr); + + GT_2trace(DMM_debugMask, GT_4CLASS, "Leaving DMM_GetHandle status %x, " + "*phDmmMgr %x\n", status, phDmmMgr ? *phDmmMgr : NULL); + return status; +} + +/* + * ======== DMM_Init ======== + * Purpose: + * Initializes private state of DMM module. + */ +bool DMM_Init(void) +{ + bool fRetval = true; + + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { + /* Set the Trace mask */ + /*"DM" for Dymanic Memory Manager */ + GT_create(&DMM_debugMask, "DM"); + } + + if (fRetval) + cRefs++; + + GT_1trace(DMM_debugMask, GT_ENTER, + "Entered DMM_Init, ref count:0x%x\n", cRefs); + + DBC_Ensure((fRetval && (cRefs > 0)) || (!fRetval && (cRefs >= 0))); + + pVirtualMappingTable = NULL ; + pPhysicalAddrTable = NULL ; + TableSize = 0; + + return fRetval; +} + +/* + * ======== DMM_MapMemory ======== + * Purpose: + * Add a mapping block to the reserved chunk. DMM assumes that this block + * will be mapped in the DSP/IVA's address space. DMM returns an error if a + * mapping overlaps another one. This function stores the info that will be + * required later while unmapping the block. + */ +DSP_STATUS DMM_MapMemory(struct DMM_OBJECT *hDmmMgr, u32 addr, u32 size) +{ + struct DMM_OBJECT *pDmmObj = (struct DMM_OBJECT *)hDmmMgr; + struct MapPage *chunk; + DSP_STATUS status = DSP_SOK; + + GT_3trace(DMM_debugMask, GT_ENTER, + "Entered DMM_MapMemory () hDmmMgr %x, " + "addr %x, size %x\n", hDmmMgr, addr, size); + SYNC_EnterCS(pDmmObj->hDmmLock); + /* Find the Reserved memory chunk containing the DSP block to + * be mapped */ + chunk = (struct MapPage *)GetRegion(addr); + if (chunk != NULL) { + /* Mark the region 'mapped', leave the 'reserved' info as-is */ + chunk->bMapped = true; + chunk->MappedSize = (size/PG_SIZE_4K); + } else + status = DSP_ENOTFOUND; + SYNC_LeaveCS(pDmmObj->hDmmLock); + GT_2trace(DMM_debugMask, GT_4CLASS, + "Leaving DMM_MapMemory status %x, chunk %x\n", + status, chunk); + return status; +} + +/* + * ======== DMM_ReserveMemory ======== + * Purpose: + * Reserve a chunk of virtually contiguous DSP/IVA address space. + */ +DSP_STATUS DMM_ReserveMemory(struct DMM_OBJECT *hDmmMgr, u32 size, + u32 *pRsvAddr) +{ + DSP_STATUS status = DSP_SOK; + struct DMM_OBJECT *pDmmObj = (struct DMM_OBJECT *)hDmmMgr; + struct MapPage *node; + u32 rsvAddr = 0; + u32 rsvSize = 0; + + GT_3trace(DMM_debugMask, GT_ENTER, + "Entered DMM_ReserveMemory () hDmmMgr %x, " + "size %x, pRsvAddr %x\n", hDmmMgr, size, pRsvAddr); + SYNC_EnterCS(pDmmObj->hDmmLock); + + /* Try to get a DSP chunk from the free list */ + node = GetFreeRegion(size); + if (node != NULL) { + /* DSP chunk of given size is available. */ + rsvAddr = DMM_ADDR_VIRTUAL(node); + /* Calculate the number entries to use */ + rsvSize = size/PG_SIZE_4K; + if (rsvSize < node->RegionSize) { + /* Mark remainder of free region */ + node[rsvSize].bMapped = false; + node[rsvSize].bReserved = false; + node[rsvSize].RegionSize = node->RegionSize - rsvSize; + node[rsvSize].MappedSize = 0; + } + /* GetRegion will return first fit chunk. But we only use what + is requested. */ + node->bMapped = false; + node->bReserved = true; + node->RegionSize = rsvSize; + node->MappedSize = 0; + /* Return the chunk's starting address */ + *pRsvAddr = rsvAddr; + } else + /*dSP chunk of given size is not available */ + status = DSP_EMEMORY; + + SYNC_LeaveCS(pDmmObj->hDmmLock); + GT_3trace(DMM_debugMask, GT_4CLASS, + "Leaving ReserveMemory status %x, rsvAddr" + " %x, rsvSize %x\n", status, rsvAddr, rsvSize); + return status; +} + + +/* + * ======== DMM_UnMapMemory ======== + * Purpose: + * Remove the mapped block from the reserved chunk. + */ +DSP_STATUS DMM_UnMapMemory(struct DMM_OBJECT *hDmmMgr, u32 addr, u32 *pSize) +{ + struct DMM_OBJECT *pDmmObj = (struct DMM_OBJECT *)hDmmMgr; + struct MapPage *chunk; + DSP_STATUS status = DSP_SOK; + + GT_3trace(DMM_debugMask, GT_ENTER, + "Entered DMM_UnMapMemory () hDmmMgr %x, " + "addr %x, pSize %x\n", hDmmMgr, addr, pSize); + SYNC_EnterCS(pDmmObj->hDmmLock); + chunk = GetMappedRegion(addr) ; + if (chunk == NULL) + status = DSP_ENOTFOUND ; + + if (DSP_SUCCEEDED(status)) { + /* Unmap the region */ + *pSize = chunk->MappedSize * PG_SIZE_4K; + chunk->bMapped = false; + chunk->MappedSize = 0; + } + SYNC_LeaveCS(pDmmObj->hDmmLock); + GT_3trace(DMM_debugMask, GT_ENTER, + "Leaving DMM_UnMapMemory status %x, chunk" + " %x, *pSize %x\n", status, chunk, *pSize); + + return status; +} + +/* + * ======== DMM_UnReserveMemory ======== + * Purpose: + * Free a chunk of reserved DSP/IVA address space. + */ +DSP_STATUS DMM_UnReserveMemory(struct DMM_OBJECT *hDmmMgr, u32 rsvAddr) +{ + struct DMM_OBJECT *pDmmObj = (struct DMM_OBJECT *)hDmmMgr; + struct MapPage *chunk; + u32 i; + DSP_STATUS status = DSP_SOK; + u32 chunkSize; + + GT_2trace(DMM_debugMask, GT_ENTER, + "Entered DMM_UnReserveMemory () hDmmMgr " + "%x, rsvAddr %x\n", hDmmMgr, rsvAddr); + + SYNC_EnterCS(pDmmObj->hDmmLock); + + /* Find the chunk containing the reserved address */ + chunk = GetMappedRegion(rsvAddr); + if (chunk == NULL) + status = DSP_ENOTFOUND; + + if (DSP_SUCCEEDED(status)) { + /* Free all the mapped pages for this reserved region */ + i = 0; + while (i < chunk->RegionSize) { + if (chunk[i].bMapped) { + /* Remove mapping from the page tables. */ + chunkSize = chunk[i].MappedSize; + /* Clear the mapping flags */ + chunk[i].bMapped = false; + chunk[i].MappedSize = 0; + i += chunkSize; + } else + i++; + } + /* Clear the flags (mark the region 'free') */ + chunk->bReserved = false; + /* NOTE: We do NOT coalesce free regions here. + * Free regions are coalesced in GetRegion(), as it traverses + *the whole mapping table + */ + } + SYNC_LeaveCS(pDmmObj->hDmmLock); + GT_2trace(DMM_debugMask, GT_ENTER, + "Leaving DMM_UnReserveMemory status %x" + " chunk %x\n", status, chunk); + return status; +} + + +/* + * ======== GetRegion ======== + * Purpose: + * Returns a region containing the specified memory region + */ +static struct MapPage *GetRegion(u32 aAddr) +{ + struct MapPage *currRegion = NULL; + u32 i = 0; + + GT_1trace(DMM_debugMask, GT_ENTER, "Entered GetRegion () " + " aAddr %x\n", aAddr); + + if (pVirtualMappingTable != NULL) { + /* find page mapped by this address */ + i = DMM_ADDR_TO_INDEX(aAddr); + if (i < TableSize) + currRegion = pVirtualMappingTable + i; + } + GT_3trace(DMM_debugMask, GT_4CLASS, + "Leaving GetRegion currRegion %x, iFreeRegion %d\n," + "iFreeSize %d\n", currRegion, iFreeRegion, iFreeSize) ; + return currRegion; +} + +/* + * ======== GetFreeRegion ======== + * Purpose: + * Returns the requested free region + */ +static struct MapPage *GetFreeRegion(u32 aSize) +{ + struct MapPage *currRegion = NULL; + u32 i = 0; + u32 RegionSize = 0; + u32 nextI = 0; + GT_1trace(DMM_debugMask, GT_ENTER, "Entered GetFreeRegion () " + "aSize 0x%x\n", aSize); + + if (pVirtualMappingTable == NULL) + return currRegion; + if (aSize > iFreeSize) { + /* Find the largest free region + * (coalesce during the traversal) */ + while (i < TableSize) { + RegionSize = pVirtualMappingTable[i].RegionSize; + nextI = i+RegionSize; + if (pVirtualMappingTable[i].bReserved == false) { + /* Coalesce, if possible */ + if (nextI < TableSize && + pVirtualMappingTable[nextI].bReserved + == false) { + pVirtualMappingTable[i].RegionSize += + pVirtualMappingTable[nextI].RegionSize; + continue; + } + RegionSize *= PG_SIZE_4K; + if (RegionSize > iFreeSize) { + iFreeRegion = i; + iFreeSize = RegionSize; + } + } + i = nextI; + } + } + if (aSize <= iFreeSize) { + currRegion = pVirtualMappingTable + iFreeRegion; + iFreeRegion += (aSize / PG_SIZE_4K); + iFreeSize -= aSize; + } + return currRegion; +} + +/* + * ======== GetMappedRegion ======== + * Purpose: + * Returns the requestedmapped region + */ +static struct MapPage *GetMappedRegion(u32 aAddr) +{ + u32 i = 0; + struct MapPage *currRegion = NULL; + GT_1trace(DMM_debugMask, GT_ENTER, "Entered GetMappedRegion () " + "aAddr 0x%x\n", aAddr); + + if (pVirtualMappingTable == NULL) + return currRegion; + + i = DMM_ADDR_TO_INDEX(aAddr); + if (i < TableSize && (pVirtualMappingTable[i].bMapped || + pVirtualMappingTable[i].bReserved)) + currRegion = pVirtualMappingTable + i; + return currRegion; +} + +/* + * ======== DMM_GetPhysicalAddrTable ======== + * Purpose: + * Returns the physical table address + */ +u32 *DMM_GetPhysicalAddrTable(void) +{ + GT_1trace(DMM_debugMask, GT_ENTER, "Entered " + "DMM_GetPhysicalAddrTable()- pPhysicalAddrTable 0x%x\n", + pPhysicalAddrTable); + return pPhysicalAddrTable; +} + +#ifdef DSP_DMM_DEBUG +u32 DMM_MemMapDump(struct DMM_OBJECT *hDmmMgr) +{ + struct MapPage *curNode = NULL; + u32 i; + u32 freemem = 0; + u32 bigsize = 0; + + SYNC_EnterCS(hDmmMgr->hDmmLock); + + if (pVirtualMappingTable != NULL) { + for (i = 0; i < TableSize; i += + pVirtualMappingTable[i].RegionSize) { + curNode = pVirtualMappingTable + i; + if (curNode->bReserved == TRUE) { + /*printk("RESERVED size = 0x%x, " + "Map size = 0x%x\n", + (curNode->RegionSize * PG_SIZE_4K), + (curNode->bMapped == false) ? 0 : + (curNode->MappedSize * PG_SIZE_4K)); +*/ + } else { +/* printk("UNRESERVED size = 0x%x\n", + (curNode->RegionSize * PG_SIZE_4K)); +*/ + freemem += (curNode->RegionSize * PG_SIZE_4K); + if (curNode->RegionSize > bigsize) + bigsize = curNode->RegionSize; + } + } + } + printk(KERN_INFO "Total DSP VA FREE memory = %d Mbytes\n", + freemem/(1024*1024)); + printk(KERN_INFO "Total DSP VA USED memory= %d Mbytes \n", + (((TableSize * PG_SIZE_4K)-freemem))/(1024*1024)); + printk(KERN_INFO "DSP VA - Biggest FREE block = %d Mbytes \n\n", + (bigsize*PG_SIZE_4K/(1024*1024))); + SYNC_LeaveCS(hDmmMgr->hDmmLock); + + return 0; +} +#endif diff --git a/drivers/dsp/bridge/pmgr/io.c b/drivers/dsp/bridge/pmgr/io.c new file mode 100644 index 0000000..cdfe0dc --- /dev/null +++ b/drivers/dsp/bridge/pmgr/io.c @@ -0,0 +1,205 @@ +/* + * io.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== io.c ======== + * Description: + * IO manager interface: Manages IO between CHNL and MSG. + * + * Public Functions: + * IO_Create + * IO_Destroy + * IO_Exit + * IO_Init + * IO_OnLoaded + * + * Notes: + * This interface is basically a pass through to the WMD IO functions. + * + *! Revision History: + *! ================ + *! 24-Feb-2003 swa PMGR Code review comments incorporated. + *! 04-Apr-2001 rr WSX_STATUS initialized in IO_Create. + *! 07-Nov-2000 jeh Created. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include + +/* ----------------------------------- Platform Manager */ +#include + +/* ----------------------------------- This */ +#include +#include +#include + +/* ----------------------------------- Globals */ +static u32 cRefs; + +#if GT_TRACE +static struct GT_Mask IO_DebugMask = { NULL, NULL }; /* WCD IO Mask */ +#endif + +/* + * ======== IO_Create ======== + * Purpose: + * Create an IO manager object, responsible for managing IO between + * CHNL and MSG + */ +DSP_STATUS IO_Create(OUT struct IO_MGR **phIOMgr, struct DEV_OBJECT *hDevObject, + IN CONST struct IO_ATTRS *pMgrAttrs) +{ + struct WMD_DRV_INTERFACE *pIntfFxns; + struct IO_MGR *hIOMgr = NULL; + struct IO_MGR_ *pIOMgr = NULL; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(phIOMgr != NULL); + DBC_Require(pMgrAttrs != NULL); + + GT_3trace(IO_DebugMask, GT_ENTER, "Entered IO_Create: phIOMgr: 0x%x\t " + "hDevObject: 0x%x\tpMgrAttrs: 0x%x\n", + phIOMgr, hDevObject, pMgrAttrs); + + *phIOMgr = NULL; + + /* A memory base of 0 implies no memory base: */ + if ((pMgrAttrs->dwSMBase != 0) && (pMgrAttrs->uSMLength == 0)) { + status = CHNL_E_INVALIDMEMBASE; + GT_0trace(IO_DebugMask, GT_7CLASS, + "IO_Create:Invalid Mem Base\n"); + } + + if (pMgrAttrs->uWordSize == 0) { + status = CHNL_E_INVALIDWORDSIZE; + GT_0trace(IO_DebugMask, GT_7CLASS, + "IO_Create:Invalid Word size\n"); + } + + if (DSP_SUCCEEDED(status)) { + DEV_GetIntfFxns(hDevObject, &pIntfFxns); + + /* Let WMD channel module finish the create: */ + status = (*pIntfFxns->pfnIOCreate)(&hIOMgr, hDevObject, + pMgrAttrs); + + if (DSP_SUCCEEDED(status)) { + pIOMgr = (struct IO_MGR_ *) hIOMgr; + pIOMgr->pIntfFxns = pIntfFxns; + pIOMgr->hDevObject = hDevObject; + + /* Return the new channel manager handle: */ + *phIOMgr = hIOMgr; + GT_1trace(IO_DebugMask, GT_1CLASS, + "IO_Create: Success hIOMgr: 0x%x\n", + hIOMgr); + } + } + + GT_2trace(IO_DebugMask, GT_ENTER, + "Exiting IO_Create: hIOMgr: 0x%x, status:" + " 0x%x\n", hIOMgr, status); + + return status; +} + +/* + * ======== IO_Destroy ======== + * Purpose: + * Delete IO manager. + */ +DSP_STATUS IO_Destroy(struct IO_MGR *hIOMgr) +{ + struct WMD_DRV_INTERFACE *pIntfFxns; + struct IO_MGR_ *pIOMgr = (struct IO_MGR_ *)hIOMgr; + DSP_STATUS status; + + DBC_Require(cRefs > 0); + + GT_1trace(IO_DebugMask, GT_ENTER, "Entered IO_Destroy: hIOMgr: 0x%x\n", + hIOMgr); + + pIntfFxns = pIOMgr->pIntfFxns; + + /* Let WMD channel module destroy the IO_MGR: */ + status = (*pIntfFxns->pfnIODestroy) (hIOMgr); + + GT_2trace(IO_DebugMask, GT_ENTER, + "Exiting IO_Destroy: pIOMgr: 0x%x, status:" + " 0x%x\n", pIOMgr, status); + return status; +} + +/* + * ======== IO_Exit ======== + * Purpose: + * Discontinue usage of the IO module. + */ +void IO_Exit(void) +{ + DBC_Require(cRefs > 0); + + cRefs--; + + GT_1trace(IO_DebugMask, GT_5CLASS, + "Entered IO_Exit, ref count: 0x%x\n", cRefs); + + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== IO_Init ======== + * Purpose: + * Initialize the IO module's private state. + */ +bool IO_Init(void) +{ + bool fRetval = true; + + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { + DBC_Assert(!IO_DebugMask.flags); + GT_create(&IO_DebugMask, "IO"); /* "IO" for IO */ + } + + if (fRetval) + cRefs++; + + + GT_1trace(IO_DebugMask, GT_5CLASS, + "Entered IO_Init, ref count: 0x%x\n", cRefs); + + DBC_Ensure((fRetval && (cRefs > 0)) || (!fRetval && (cRefs >= 0))); + + return fRetval; +} diff --git a/drivers/dsp/bridge/pmgr/ioobj.h b/drivers/dsp/bridge/pmgr/ioobj.h new file mode 100644 index 0000000..f473a63 --- /dev/null +++ b/drivers/dsp/bridge/pmgr/ioobj.h @@ -0,0 +1,52 @@ +/* + * ioobj.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== ioobj.h ======== + * Description: + * Structure subcomponents of channel class library IO objects which + * are exposed to class driver from mini-driver. + * + * Public Functions: + * None. + * + *! Revision History: + *! ================ + *! 24-Feb-2003 swa PMGR Code review comments incorporated. + *! 01/16/97 gp: Created from chnlpriv.h + */ + +#ifndef IOOBJ_ +#define IOOBJ_ + +#include +#include + +/* + * This struct is the first field in a IO_MGR struct, as implemented in + * a WMD channel class library. Other, implementation specific fields + * follow this structure in memory. + */ +struct IO_MGR_ { + /* These must be the first fields in a IO_MGR struct: */ + u32 dwSignature; /* Used for object validation. */ + struct WMD_DEV_CONTEXT *hWmdContext; /* WMD device context. */ + struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD. */ + struct DEV_OBJECT *hDevObject; /* Device this board represents. */ +} ; + +#endif /* IOOBJ_ */ diff --git a/drivers/dsp/bridge/pmgr/msg.c b/drivers/dsp/bridge/pmgr/msg.c new file mode 100644 index 0000000..bbf5174 --- /dev/null +++ b/drivers/dsp/bridge/pmgr/msg.c @@ -0,0 +1,173 @@ +/* + * msg.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== msg.c ======== + * Description: + * DSP/BIOS Bridge MSG Module. + * + * Public Functions: + * MSG_Create + * MSG_Delete + * MSG_Exit + * MSG_Init + * + *! Revision History: + *! ================= + *! 24-Feb-2003 swa PMGR Code review comments incorporated. + *! 15-May-2001 ag Changed SUCCEEDED to DSP_SUCCEEDED. + *! 16-Feb-2001 jeh Fixed some comments. + *! 15-Dec-2000 rr MSG_Create returns DSP_EFAIL if pfnMsgCreate fails. + *! 12-Sep-2000 jeh Created. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include + +/* ----------------------------------- Mini Driver */ +#include + +/* ----------------------------------- Platform Manager */ +#include + +/* ----------------------------------- This */ +#include +#include + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask MSG_debugMask = { NULL, NULL }; /* GT trace variable */ +#endif +static u32 cRefs; /* module reference count */ + +/* + * ======== MSG_Create ======== + * Purpose: + * Create an object to manage message queues. Only one of these objects + * can exist per device object. + */ +DSP_STATUS MSG_Create(OUT struct MSG_MGR **phMsgMgr, + struct DEV_OBJECT *hDevObject, MSG_ONEXIT msgCallback) +{ + struct WMD_DRV_INTERFACE *pIntfFxns; + struct MSG_MGR_ *pMsgMgr; + struct MSG_MGR *hMsgMgr; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(phMsgMgr != NULL); + DBC_Require(msgCallback != NULL); + DBC_Require(hDevObject != NULL); + + GT_3trace(MSG_debugMask, GT_ENTER, "MSG_Create: phMsgMgr: 0x%x\t" + "hDevObject: 0x%x\tmsgCallback: 0x%x\n", + phMsgMgr, hDevObject, msgCallback); + + *phMsgMgr = NULL; + + DEV_GetIntfFxns(hDevObject, &pIntfFxns); + + /* Let WMD message module finish the create: */ + status = (*pIntfFxns->pfnMsgCreate)(&hMsgMgr, hDevObject, msgCallback); + + if (DSP_SUCCEEDED(status)) { + /* Fill in WCD message module's fields of the MSG_MGR + * structure */ + pMsgMgr = (struct MSG_MGR_ *)hMsgMgr; + pMsgMgr->pIntfFxns = pIntfFxns; + + /* Finally, return the new message manager handle: */ + *phMsgMgr = hMsgMgr; + GT_1trace(MSG_debugMask, GT_1CLASS, + "MSG_Create: Success pMsgMgr: 0x%x\n", pMsgMgr); + } else { + status = DSP_EFAIL; + } + return status; +} + +/* + * ======== MSG_Delete ======== + * Purpose: + * Delete a MSG manager allocated in MSG_Create(). + */ +void MSG_Delete(struct MSG_MGR *hMsgMgr) +{ + struct MSG_MGR_ *pMsgMgr = (struct MSG_MGR_ *)hMsgMgr; + struct WMD_DRV_INTERFACE *pIntfFxns; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(pMsgMgr, MSGMGR_SIGNATURE)); + + GT_1trace(MSG_debugMask, GT_ENTER, "MSG_Delete: hMsgMgr: 0x%x\n", + hMsgMgr); + + pIntfFxns = pMsgMgr->pIntfFxns; + + /* Let WMD message module destroy the MSG_MGR: */ + (*pIntfFxns->pfnMsgDelete)(hMsgMgr); + + DBC_Ensure(!MEM_IsValidHandle(pMsgMgr, MSGMGR_SIGNATURE)); +} + +/* + * ======== MSG_Exit ======== + */ +void MSG_Exit(void) +{ + DBC_Require(cRefs > 0); + cRefs--; + GT_1trace(MSG_debugMask, GT_5CLASS, + "Entered MSG_Exit, ref count: 0x%x\n", cRefs); + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== MSG_Init ======== + */ +bool MSG_Init(void) +{ + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { + DBC_Assert(!MSG_debugMask.flags); + GT_create(&MSG_debugMask, "MG"); /* "MG" for MsG */ + } + + cRefs++; + + GT_1trace(MSG_debugMask, GT_5CLASS, "MSG_Init(), ref count: 0x%x\n", + cRefs); + + DBC_Ensure(cRefs >= 0); + + return true; +} + diff --git a/drivers/dsp/bridge/pmgr/msgobj.h b/drivers/dsp/bridge/pmgr/msgobj.h new file mode 100644 index 0000000..63d025b --- /dev/null +++ b/drivers/dsp/bridge/pmgr/msgobj.h @@ -0,0 +1,52 @@ +/* + * msgobj.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== msgobj.h ======== + * Description: + * Structure subcomponents of channel class library MSG objects which + * are exposed to class driver from mini-driver. + * + * Public Functions: + * None. + * + *! Revision History: + *! ================ + *! 24-Feb-2003 swa PMGR Code review comments incorporated. + *! 17-Nov-2000 jeh Created. + */ + +#ifndef MSGOBJ_ +#define MSGOBJ_ + +#include + +#include + +/* + * This struct is the first field in a MSG_MGR struct, as implemented in + * a WMD channel class library. Other, implementation specific fields + * follow this structure in memory. + */ +struct MSG_MGR_ { + /* The first two fields must match those in msgobj.h */ + u32 dwSignature; + struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD. */ +}; + +#endif /* MSGOBJ_ */ + diff --git a/drivers/dsp/bridge/pmgr/wcd.c b/drivers/dsp/bridge/pmgr/wcd.c new file mode 100644 index 0000000..859043d --- /dev/null +++ b/drivers/dsp/bridge/pmgr/wcd.c @@ -0,0 +1,1647 @@ +/* + * wcd.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== wcd.c ======== + * Description: + * Common WCD functions, also includes the wrapper + * functions called directly by the DeviceIOControl interface. + * + * Public Functions: + * WCD_CallDevIOCtl + * WCD_Init + * WCD_InitComplete2 + * WCD_Exit + * WRAP_* + * + *! Revision History: + *! ================ + *! 29-Apr-2004 hp Call PROC_AutoStart only for DSP device + *! 19-Apr-2004 sb Aligned DMM definitions with Symbian + *! 08-Mar-2004 sb Added the Dynamic Memory Mapping APIs + *! 03-Apr-2003 sb Process environment pointer in PROCWRAP_Load + *! 24-Feb-2003 swa PMGR Code review comments incorporated. + *! 30-Jan-2002 ag CMMWRAP_AllocBuf name changed to CMMWRAP_CallocBuf + *! 15-Jan-2002 ag Added actual bufSize param to STRMWRAP_Reclaim[issue]. + *! 14-Dec-2001 rr ARGS_NODE_CONNECT maps the pAttr. + *! 03-Oct-2001 rr ARGS_NODE_ALLOCMSGBUF/FREEMSGBUF maps the pAttr. + *! 10-Sep-2001 ag Added CMD_CMM_GETHANDLE. + *! 23-Apr-2001 jeh Pass pStatus to NODE_Terminate. + *! 11-Apr-2001 jeh STRMWRAP_Reclaim embedded pointer is mapped and unmapped. + *! 13-Feb-2001 kc: DSP/BIOS Bridge name updates. + *! 06-Dec-2000 jeh WRAP_MAP2CALLER pointers in RegisterNotify calls. + *! 05-Dec-2000 ag: Removed MAP2CALLER in NODEWRAP_FreeMsgBuf(). + *! 22-Nov-2000 kc: Added MGRWRAP_GetPerf_Data(). + *! 20-Nov-2000 jeh Added MSG_Init()/MSG_Exit(), IO_Init()/IO_Exit(). + *! WRAP pointers to handles for PROC_Attach, NODE_Allocate. + *! 27-Oct-2000 jeh Added NODEWRAP_AllocMsgBuf, NODEWRAP_FreeMsgBuf. Removed + *! NODEWRAP_GetMessageStream. + *! 12-Oct-2000 ag: Added user CMM wrappers. + *! 05-Oct-2000 rr: WcdInitComplete2 will fail even if one BRD or PROC + *! AutoStart fails. + *! 25-Sep-2000 rr: Updated to Version 0.9 + *! 13-Sep-2000 jeh Pass ARGS_NODE_CONNECT.pAttrs to NODE_Connect(). + *! 11-Aug-2000 rr: Part of node enabled. + *! 31-Jul-2000 rr: UTIL_Wrap and MEM_Wrap added to RM. + *! 27-Jul-2000 rr: PROCWRAP, NODEWRAP and STRMWRAP implemented. + *! STRM and some NODE Wrappers are not implemented. + *! 27-Jun-2000 rr: MGRWRAP fxns added.IFDEF to build for PM or DSP/BIOS Bridge + *! 08-Feb-2000 rr File name changed to wcd.c + *! 03-Feb-2000 rr: Module initialization are done by SERVICES init. GT Class + *! changes for module init/exit fxns. + *! 24-Jan-2000 rr: Merged with Scott's code. + *! 21-Jan-1999 sg: Changed ARGS_CHNL_GETMODE field name from pdwMode to pMode. + *! 17-Jan-2000 rr: BRD_GetStatus does WRAP_MAP2CALLER for state. + *! 14-Dec-1999 ag: Removed _MAP2CALLER in CHNL_GetMgr(). + *! 13-Dec-1999 rr: BRDWRAP_GetSymbol, BRDWRAP_GetTrace uses WRAP_MAP2CALLER + *! macros.BRDWRAP_Load maps and unmaps embedded pointers. + *! 10-Dec-1999 ag: User CHNL bufs mapped in _AddIOReq & _GetIOCompletion. + *! 09-Dec-1999 rr: BRDWRAP_Open and CHNLWRAP_GetMgr does not map + *! pointer as there was a change in config.c + *! 06-Dec-1999 rr: BRD_Read and Write Maps the buf pointers. + *! 03-Dec-1999 rr: CHNLWRAP_GetMgr and BRDWRAP_Open maps hDevNode pointer. + *! WCD_InitComplete2 Included for BRD_AutoStart. + *! 16-Nov-1999 ag: Map buf to process in CHNLWRAP_AllocBuffer(). + *! CHNL_GetMgr() Mapping Fix. + *! 10-Nov-1999 ag: Removed unnecessary calls to WRAP_MAP2CALLER. + *! 08-Nov-1999 kc: Added MEMRY & enabled BRD_IOCtl for tests. + *! 29-Oct-1999 ag: Added CHNL. + *! 29-Oct-1999 kc: Added trace statements; added ptr mapping; updated + *! use of UTIL module API. + *! 29-Oct-1999 rr: Wrapper functions does the Mapping of the Pointers. + *! in WinCE all the explicit pointers will be converted + *! by the OS during interprocess but not the embedded pointers. + *! 16-Oct-1999 kc: Code review cleanup. + *! 07-Oct-1999 kc: Added UTILWRAP_TestDll() to run PM test harness. See + *! /src/doc/pmtest.doc for more detail. + *! 09-Sep-1999 rr: After exactly two years(!). Adopted for WinCE. GT Enabled. + *! 09-Sep-1997 gp: Created. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include +#include + +/* ----------------------------------- Platform Manager */ +#include +#include +#include + +#include +#include + +/* ----------------------------------- Resource Manager */ +#include +#include +#include +#include + + +/* ----------------------------------- Others */ +#include +#include +#include + +/* ----------------------------------- This */ +#include +#include + +#ifndef RES_CLEANUP_DISABLE +#include +#endif + +/* ----------------------------------- Defines, Data Structures, Typedefs */ +#define MAX_TRACEBUFLEN 255 +#define MAX_LOADARGS 16 +#define MAX_NODES 64 +#define MAX_STREAMS 16 +#define MAX_BUFS 64 + +/* Following two macros should ideally have do{}while(0) */ + +#define cp_fm_usr(dest, src, status, elements) \ + if (DSP_SUCCEEDED(status)) {\ + if (unlikely(src == NULL) || \ + unlikely(copy_from_user(dest, src, elements * sizeof(*(dest))))) { \ + GT_1trace(WCD_debugMask, GT_7CLASS, \ + "copy_from_user failed, src=0x%x\n", src); \ + status = DSP_EPOINTER ; \ + } \ + } + +#define cp_to_usr(dest, src, status, elements) \ + if (DSP_SUCCEEDED(status)) {\ + if (unlikely(dest == NULL) || \ + unlikely(copy_to_user(dest, src, elements * sizeof(*(src))))) { \ + GT_1trace(WCD_debugMask, GT_7CLASS, \ + "copy_to_user failed, dest=0x%x\n", dest); \ + status = DSP_EPOINTER ;\ + } \ + } + +/* Device IOCtl function pointer */ +struct WCD_Cmd { + u32(*fxn)(union Trapped_Args *args); + u32 dwIndex; +} ; + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask WCD_debugMask = { NULL, NULL }; /* Core VxD Mask */ +#endif +static u32 WCD_cRefs; + +/* + * Function table. + * The order of these functions MUST be the same as the order of the command + * numbers defined in wcdioctl.h This is how an IOCTL number in user mode + * turns into a function call in kernel mode. + */ +static struct WCD_Cmd WCD_cmdTable[] = { + /* MGR module */ + {MGRWRAP_EnumNode_Info, CMD_MGR_ENUMNODE_INFO_OFFSET}, + {MGRWRAP_EnumProc_Info, CMD_MGR_ENUMPROC_INFO_OFFSET}, + {MGRWRAP_RegisterObject, CMD_MGR_REGISTEROBJECT_OFFSET}, + {MGRWRAP_UnregisterObject, CMD_MGR_UNREGISTEROBJECT_OFFSET}, + {MGRWRAP_WaitForBridgeEvents, CMD_MGR_WAIT_OFFSET}, +#ifndef RES_CLEANUP_DISABLE + {MGRWRAP_GetProcessResourcesInfo, CMD_MGR_RESOUCES_OFFSET}, +#endif + /* PROC Module */ + {PROCWRAP_Attach, CMD_PROC_ATTACH_OFFSET}, + {PROCWRAP_Ctrl, CMD_PROC_CTRL_OFFSET}, + {PROCWRAP_Detach, CMD_PROC_DETACH_OFFSET}, + {PROCWRAP_EnumNode_Info, CMD_PROC_ENUMNODE_OFFSET}, + {PROCWRAP_EnumResources, CMD_PROC_ENUMRESOURCES_OFFSET}, + {PROCWRAP_GetState, CMD_PROC_GETSTATE_OFFSET}, + {PROCWRAP_GetTrace, CMD_PROC_GETTRACE_OFFSET}, + {PROCWRAP_Load, CMD_PROC_LOAD_OFFSET}, + {PROCWRAP_RegisterNotify, CMD_PROC_REGISTERNOTIFY_OFFSET}, + {PROCWRAP_Start, CMD_PROC_START_OFFSET}, + {PROCWRAP_ReserveMemory, CMD_PROC_RSVMEM_OFFSET}, + {PROCWRAP_UnReserveMemory, CMD_PROC_UNRSVMEM_OFFSET}, + {PROCWRAP_Map, CMD_PROC_MAPMEM_OFFSET}, + {PROCWRAP_UnMap, CMD_PROC_UNMAPMEM_OFFSET}, + {PROCWRAP_FlushMemory, CMD_PROC_FLUSHMEMORY_OFFSET}, + {PROCWRAP_Stop, CMD_PROC_STOP_OFFSET}, + {PROCWRAP_InvalidateMemory, CMD_PROC_INVALIDATEMEMORY_OFFSET}, + /* NODE Module */ + {NODEWRAP_Allocate, CMD_NODE_ALLOCATE_OFFSET}, + {NODEWRAP_AllocMsgBuf, CMD_NODE_ALLOCMSGBUF_OFFSET}, + {NODEWRAP_ChangePriority, CMD_NODE_CHANGEPRIORITY_OFFSET}, + {NODEWRAP_Connect, CMD_NODE_CONNECT_OFFSET}, + {NODEWRAP_Create, CMD_NODE_CREATE_OFFSET}, + {NODEWRAP_Delete, CMD_NODE_DELETE_OFFSET}, + {NODEWRAP_FreeMsgBuf, CMD_NODE_FREEMSGBUF_OFFSET}, + {NODEWRAP_GetAttr, CMD_NODE_GETATTR_OFFSET}, + {NODEWRAP_GetMessage, CMD_NODE_GETMESSAGE_OFFSET}, + {NODEWRAP_Pause, CMD_NODE_PAUSE_OFFSET}, + {NODEWRAP_PutMessage, CMD_NODE_PUTMESSAGE_OFFSET}, + {NODEWRAP_RegisterNotify, CMD_NODE_REGISTERNOTIFY_OFFSET}, + {NODEWRAP_Run, CMD_NODE_RUN_OFFSET}, + {NODEWRAP_Terminate, CMD_NODE_TERMINATE_OFFSET}, + {NODEWRAP_GetUUIDProps, CMD_NODE_GETUUIDPROPS_OFFSET}, + /* STRM wrapper functions */ + {STRMWRAP_AllocateBuffer, CMD_STRM_ALLOCATEBUFFER_OFFSET}, + {STRMWRAP_Close, CMD_STRM_CLOSE_OFFSET}, + {STRMWRAP_FreeBuffer, CMD_STRM_FREEBUFFER_OFFSET}, + {STRMWRAP_GetEventHandle, CMD_STRM_GETEVENTHANDLE_OFFSET}, + {STRMWRAP_GetInfo, CMD_STRM_GETINFO_OFFSET}, + {STRMWRAP_Idle, CMD_STRM_IDLE_OFFSET}, + {STRMWRAP_Issue, CMD_STRM_ISSUE_OFFSET}, + {STRMWRAP_Open, CMD_STRM_OPEN_OFFSET}, + {STRMWRAP_Reclaim, CMD_STRM_RECLAIM_OFFSET}, + {STRMWRAP_RegisterNotify, CMD_STRM_REGISTERNOTIFY_OFFSET}, + {STRMWRAP_Select, CMD_STRM_SELECT_OFFSET}, + /* CMM module */ + {CMMWRAP_CallocBuf, CMD_CMM_ALLOCBUF_OFFSET}, + {CMMWRAP_FreeBuf, CMD_CMM_FREEBUF_OFFSET}, + {CMMWRAP_GetHandle, CMD_CMM_GETHANDLE_OFFSET}, + {CMMWRAP_GetInfo, CMD_CMM_GETINFO_OFFSET} +}; + +/* + * ======== WCD_CallDevIOCtl ======== + * Purpose: + * Call the (wrapper) function for the corresponding WCD IOCTL. + */ +inline DSP_STATUS WCD_CallDevIOCtl(u32 cmd, union Trapped_Args *args, + u32 *pResult) +{ + if ((cmd < (sizeof(WCD_cmdTable) / sizeof(struct WCD_Cmd)))) { + /* make the fxn call via the cmd table */ + *pResult = (*WCD_cmdTable[cmd].fxn) (args); + return DSP_SOK; + } else { + return DSP_EINVALIDARG; + } +} + +/* + * ======== WCD_Exit ======== + */ +void WCD_Exit(void) +{ + DBC_Require(WCD_cRefs > 0); + WCD_cRefs--; + GT_1trace(WCD_debugMask, GT_5CLASS, + "Entered WCD_Exit, ref count: 0x%x\n", WCD_cRefs); + if (WCD_cRefs == 0) { + /* Release all WCD modules initialized in WCD_Init(). */ + COD_Exit(); + DEV_Exit(); + CHNL_Exit(); + MSG_Exit(); + IO_Exit(); + STRM_Exit(); + NTFY_Exit(); + DISP_Exit(); + NODE_Exit(); + PROC_Exit(); + MGR_Exit(); + RMM_exit(); + DRV_Exit(); + SERVICES_Exit(); + } + DBC_Ensure(WCD_cRefs >= 0); +} + +/* + * ======== WCD_Init ======== + * Purpose: + * Module initialization is done by SERVICES Init. + */ +bool WCD_Init(void) +{ + bool fInit = true; + bool fDRV, fDEV, fCOD, fSERVICES, fCHNL, fMSG, fIO; + bool fMGR, fPROC, fNODE, fDISP, fNTFY, fSTRM, fRMM; +#ifdef DEBUG + /* runtime check of Device IOCtl array. */ + u32 i; + for (i = 1; i < (sizeof(WCD_cmdTable) / sizeof(struct WCD_Cmd)); i++) + DBC_Assert(WCD_cmdTable[i - 1].dwIndex == i); + +#endif + if (WCD_cRefs == 0) { + /* initialize all SERVICES modules */ + fSERVICES = SERVICES_Init(); + /* initialize debugging module */ + DBC_Assert(!WCD_debugMask.flags); + GT_create(&WCD_debugMask, "CD"); /* CD for class driver */ + /* initialize class driver and other modules */ + fDRV = DRV_Init(); + fMGR = MGR_Init(); + fPROC = PROC_Init(); + fNODE = NODE_Init(); + fDISP = DISP_Init(); + fNTFY = NTFY_Init(); + fSTRM = STRM_Init(); + fRMM = RMM_init(); + fCHNL = CHNL_Init(); + fMSG = MSG_Init(); + fIO = IO_Init(); + fDEV = DEV_Init(); + fCOD = COD_Init(); + fInit = fSERVICES && fDRV && fDEV && fCHNL && fCOD && + fMSG && fIO; + fInit = fInit && fMGR && fPROC && fRMM; + if (!fInit) { + if (fSERVICES) + SERVICES_Exit(); + + if (fDRV) + DRV_Exit(); + + if (fMGR) + MGR_Exit(); + + if (fSTRM) + STRM_Exit(); + + if (fPROC) + PROC_Exit(); + + if (fNODE) + NODE_Exit(); + + if (fDISP) + DISP_Exit(); + + if (fNTFY) + NTFY_Exit(); + + if (fCHNL) + CHNL_Exit(); + + if (fMSG) + MSG_Exit(); + + if (fIO) + IO_Exit(); + + if (fDEV) + DEV_Exit(); + + if (fCOD) + COD_Exit(); + + if (fRMM) + RMM_exit(); + + } + } + if (fInit) + WCD_cRefs++; + + GT_1trace(WCD_debugMask, GT_5CLASS, + "Entered WCD_Init, ref count: 0x%x\n", WCD_cRefs); + return fInit; +} + +/* + * ======== WCD_InitComplete2 ======== + * Purpose: + * Perform any required WCD, and WMD initialization which + * cannot not be performed in WCD_Init() or DEV_StartDevice() due + * to the fact that some services are not yet + * completely initialized. + * Parameters: + * Returns: + * DSP_SOK: Allow this device to load + * DSP_EFAIL: Failure. + * Requires: + * WCD initialized. + * Ensures: + */ +DSP_STATUS WCD_InitComplete2(void) +{ + DSP_STATUS status = DSP_SOK; + struct CFG_DEVNODE *DevNode; + struct DEV_OBJECT *hDevObject; + u32 devType; + + DBC_Require(WCD_cRefs > 0); + GT_0trace(WCD_debugMask, GT_ENTER, "Entered WCD_InitComplete\n"); + /* Walk the list of DevObjects, get each devnode, and attempting to + * autostart the board. Note that this requires COF loading, which + * requires KFILE. */ + for (hDevObject = DEV_GetFirst(); hDevObject != NULL; + hDevObject = DEV_GetNext(hDevObject)) { + if (DSP_FAILED(DEV_GetDevNode(hDevObject, &DevNode))) + continue; + + if (DSP_FAILED(DEV_GetDevType(hDevObject, &devType))) + continue; + + if ((devType == DSP_UNIT) || (devType == IVA_UNIT)) { + if (DSP_FAILED(PROC_AutoStart(DevNode, hDevObject))) { + GT_0trace(WCD_debugMask, GT_1CLASS, + "WCD_InitComplete2 Failed\n"); + status = DSP_EFAIL; + /* break; */ + } + } else + GT_1trace(WCD_debugMask, GT_ENTER, + "Ignoring PROC_AutoStart " + "for Device Type = 0x%x \n", devType); + } /* End For Loop */ + GT_1trace(WCD_debugMask, GT_ENTER, + "Exiting WCD_InitComplete status 0x%x\n", status); + return status; +} + +/* + * ======== MGRWRAP_EnumNode_Info ======== + */ +u32 MGRWRAP_EnumNode_Info(union Trapped_Args *args) +{ + u8 *pNDBProps; + u32 uNumNodes; + DSP_STATUS status = DSP_SOK; + u32 size = args->ARGS_MGR_ENUMNODE_INFO.uNDBPropsSize; + + GT_4trace(WCD_debugMask, GT_ENTER, + "MGR_EnumNodeInfo: entered args:\n0x%x" + " uNode: 0x%x\tpNDBProps: 0x%x\tuNDBPropsSize: " + "0x%x\tpuNumNodes\n", args->ARGS_MGR_ENUMNODE_INFO.uNode, + args->ARGS_MGR_ENUMNODE_INFO.pNDBProps, + args->ARGS_MGR_ENUMNODE_INFO.uNDBPropsSize, + args->ARGS_MGR_ENUMNODE_INFO.puNumNodes); + pNDBProps = MEM_Alloc(size, MEM_NONPAGED); + if (pNDBProps == NULL) + status = DSP_EMEMORY; + + if (DSP_SUCCEEDED(status)) { + status = MGR_EnumNodeInfo(args->ARGS_MGR_ENUMNODE_INFO.uNode, + (struct DSP_NDBPROPS *)pNDBProps, + size, &uNumNodes); + } + cp_to_usr(args->ARGS_MGR_ENUMNODE_INFO.pNDBProps, pNDBProps, status, + size); + cp_to_usr(args->ARGS_MGR_ENUMNODE_INFO.puNumNodes, &uNumNodes, status, + 1); + if (pNDBProps) + MEM_Free(pNDBProps); + + return status; +} + +/* + * ======== MGRWRAP_EnumProc_Info ======== + */ +u32 MGRWRAP_EnumProc_Info(union Trapped_Args *args) +{ + u8 *pProcessorInfo; + u32 uNumProcs; + DSP_STATUS status = DSP_SOK; + u32 size = args->ARGS_MGR_ENUMPROC_INFO.uProcessorInfoSize; + + GT_4trace(WCD_debugMask, GT_ENTER, + "MGRWRAP_EnumProc_Info: entered args:\n" + "0x%x uProcessor: 0x%x\tpProcessorInfo: 0x%x\t" + "uProcessorInfoSize: 0x%x\tpuNumProcs \n", + args->ARGS_MGR_ENUMPROC_INFO.uProcessor, + args->ARGS_MGR_ENUMPROC_INFO.pProcessorInfo, + args->ARGS_MGR_ENUMPROC_INFO.uProcessorInfoSize, + args->ARGS_MGR_ENUMPROC_INFO.puNumProcs); + pProcessorInfo = MEM_Alloc(size, MEM_NONPAGED); + if (pProcessorInfo == NULL) + status = DSP_EMEMORY; + + if (DSP_SUCCEEDED(status)) { + status = MGR_EnumProcessorInfo(args-> + ARGS_MGR_ENUMPROC_INFO.uProcessor, + (struct DSP_PROCESSORINFO *)pProcessorInfo, + size, &uNumProcs); + } + cp_to_usr(args->ARGS_MGR_ENUMPROC_INFO.pProcessorInfo, pProcessorInfo, + status, size); + cp_to_usr(args->ARGS_MGR_ENUMPROC_INFO.puNumProcs, &uNumProcs, + status, 1); + if (pProcessorInfo) + MEM_Free(pProcessorInfo); + + return status; +} + +#define WRAP_MAP2CALLER(x) x +/* + * ======== MGRWRAP_RegisterObject ======== + */ +u32 MGRWRAP_RegisterObject(union Trapped_Args *args) +{ + u32 retVal; + + GT_1trace(WCD_debugMask, GT_ENTER, + "MGRWRAP_RegisterObject: entered pg2hMsg " + "0x%x\n", args->ARGS_MGR_REGISTEROBJECT.pUuid); + retVal = DCD_RegisterObject(WRAP_MAP2CALLER + (args->ARGS_MGR_REGISTEROBJECT.pUuid), + args->ARGS_MGR_REGISTEROBJECT.objType, + WRAP_MAP2CALLER(args->ARGS_MGR_REGISTEROBJECT.pszPathName)); + return retVal; +} + +/* + * ======== MGRWRAP_UnregisterObject ======== + */ +u32 MGRWRAP_UnregisterObject(union Trapped_Args *args) +{ + u32 retVal; + + GT_1trace(WCD_debugMask, GT_ENTER, + "MGRWRAP_UnregisterObject: entered pg2hMsg" + " 0x%x\n", args->ARGS_MGR_UNREGISTEROBJECT.pUuid); + retVal = DCD_UnregisterObject(WRAP_MAP2CALLER + (args->ARGS_MGR_UNREGISTEROBJECT.pUuid), + args->ARGS_MGR_UNREGISTEROBJECT.objType); + + return retVal; +} + +/* + * ======== MGRWRAP_WaitForBridgeEvents ======== + */ +u32 MGRWRAP_WaitForBridgeEvents(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + struct DSP_NOTIFICATION *aNotifications[MAX_EVENTS]; + struct DSP_NOTIFICATION notifications[MAX_EVENTS]; + u32 uIndex, i; + u32 uCount = args->ARGS_MGR_WAIT.uCount; + + GT_0trace(WCD_debugMask, GT_ENTER, + "MGRWRAP_WaitForBridgeEvents: entered\n"); + + if (uCount > MAX_EVENTS) + status = DSP_EINVALIDARG; + + /* get the array of pointers to user structures */ + cp_fm_usr(aNotifications, args->ARGS_MGR_WAIT.aNotifications, + status, uCount); + /* get the events */ + for (i = 0; i < uCount; i++) { + cp_fm_usr(¬ifications[i], aNotifications[i], status, 1); + if (DSP_SUCCEEDED(status)) { + /* set the array of pointers to kernel structures*/ + aNotifications[i] = ¬ifications[i]; + } + } + if (DSP_SUCCEEDED(status)) { + status = MGR_WaitForBridgeEvents(aNotifications, uCount, + &uIndex, args->ARGS_MGR_WAIT.uTimeout); + } + cp_to_usr(args->ARGS_MGR_WAIT.puIndex, &uIndex, status, 1); + return status; +} + + +#ifndef RES_CLEANUP_DISABLE +/* + * ======== MGRWRAP_GetProcessResourceInfo ======== + */ +u32 MGRWRAP_GetProcessResourcesInfo(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + u32 uSize = 0; + u8 *pBuf = MEM_Alloc(8092, MEM_NONPAGED); + status = DRV_ProcDisplayResInfo(pBuf, &uSize); + GT_1trace(WCD_debugMask, GT_ENTER, + "MGRWRAP_GetProcessResourcesInfo:uSize=%d :\n", uSize); + cp_to_usr(args->ARGS_PROC_GETTRACE.pBuf, pBuf, status, uSize); + GT_0trace(WCD_debugMask, GT_ENTER, "\n***********" + "123MGRWRAP_GetProcessResourcesInfo:**************\n"); + GT_0trace(WCD_debugMask, GT_ENTER, "\n***********" + "456MGRWRAP_GetProcessResourcesInfo:**************\n"); + cp_to_usr(args->ARGS_PROC_GETTRACE.pSize, &uSize, status, 1); + MEM_Free(pBuf); + return status; +} +#endif + + +/* + * ======== PROCWRAP_Attach ======== + */ +u32 PROCWRAP_Attach(union Trapped_Args *args) +{ + DSP_HPROCESSOR processor; + DSP_STATUS status = DSP_SOK; + struct DSP_PROCESSORATTRIN attrIn, *pAttrIn = NULL; + + GT_3trace(WCD_debugMask, GT_ENTER, + "PROCWRAP_Attach: entered args:\n" "0x%x" + " uProcessor: 0x%x\tpAttrIn: 0x%x\tphProcessor \n", + args->ARGS_PROC_ATTACH.uProcessor, + args->ARGS_PROC_ATTACH.pAttrIn, + args->ARGS_PROC_ATTACH.phProcessor); + /* Optional argument */ + if (args->ARGS_PROC_ATTACH.pAttrIn) { + cp_fm_usr(&attrIn, args->ARGS_PROC_ATTACH.pAttrIn, status, 1); + if (DSP_SUCCEEDED(status)) + pAttrIn = &attrIn; + + } + status = PROC_Attach(args->ARGS_PROC_ATTACH.uProcessor, pAttrIn, + &processor); + cp_to_usr(args->ARGS_PROC_ATTACH.phProcessor, &processor, status, 1); + return status; +} + +/* + * ======== PROCWRAP_Ctrl ======== + */ +u32 PROCWRAP_Ctrl(union Trapped_Args *args) +{ + u32 cbDataSize, __user *pSize = (u32 __user *) + args->ARGS_PROC_CTRL.pArgs; + u8 *pArgs = NULL; + DSP_STATUS status = DSP_SOK; + + GT_3trace(WCD_debugMask, GT_ENTER, + "PROCWRAP_Ctrl: entered args:\n 0x%x" + " uProcessor: 0x%x\tdwCmd: 0x%x\tpArgs \n", + args->ARGS_PROC_CTRL.hProcessor, + args->ARGS_PROC_CTRL.dwCmd, + args->ARGS_PROC_CTRL.pArgs); + if (pSize) { + if (get_user(cbDataSize, pSize)) + status = DSP_EFAIL; + + cbDataSize += sizeof(u32); + if (DSP_SUCCEEDED(status)) { + pArgs = MEM_Alloc(cbDataSize, MEM_NONPAGED); + if (pArgs == NULL) + status = DSP_EMEMORY; + + } + cp_fm_usr(pArgs, args->ARGS_PROC_CTRL.pArgs, status, + cbDataSize); + } + if (DSP_SUCCEEDED(status)) { + status = PROC_Ctrl(args->ARGS_PROC_CTRL.hProcessor, + args->ARGS_PROC_CTRL.dwCmd, + (struct DSP_CBDATA *)pArgs); + } + + /* cp_to_usr(args->ARGS_PROC_CTRL.pArgs, pArgs, status, 1);*/ + if (pArgs) + MEM_Free(pArgs); + + return status; +} + +/* + * ======== PROCWRAP_Detach ======== + */ +u32 PROCWRAP_Detach(union Trapped_Args *args) +{ + u32 retVal; + + GT_1trace(WCD_debugMask, GT_ENTER, + "PROCWRAP_Detach: entered args\n0x%x " + "hProceesor \n", args->ARGS_PROC_DETACH.hProcessor); + retVal = PROC_Detach(args->ARGS_PROC_DETACH.hProcessor); + + return retVal; +} + +/* + * ======== PROCWRAP_EnumNode_Info ======== + */ +u32 PROCWRAP_EnumNode_Info(union Trapped_Args *args) +{ + DSP_STATUS status; + DSP_HNODE aNodeTab[MAX_NODES]; + u32 uNumNodes; + u32 uAllocated; + + GT_5trace(WCD_debugMask, GT_ENTER, + "PROCWRAP_EnumNode_Info:entered args:\n0x" + "%xhProcessor:0x%x\taNodeTab:0x%x\tuNodeTabSize:" + "%0x%x\tpuNumNodes%\n0x%x puAllocated: \n", + args->ARGS_PROC_ENUMNODE_INFO.hProcessor, + args->ARGS_PROC_ENUMNODE_INFO.aNodeTab, + args->ARGS_PROC_ENUMNODE_INFO.uNodeTabSize, + args->ARGS_PROC_ENUMNODE_INFO.puNumNodes, + args->ARGS_PROC_ENUMNODE_INFO.puAllocated); + DBC_Require(args->ARGS_PROC_ENUMNODE_INFO.uNodeTabSize <= MAX_NODES); + status = PROC_EnumNodes(args->ARGS_PROC_ENUMNODE_INFO.hProcessor, + aNodeTab, + args->ARGS_PROC_ENUMNODE_INFO.uNodeTabSize, + &uNumNodes, &uAllocated); + cp_to_usr(args->ARGS_PROC_ENUMNODE_INFO.aNodeTab, aNodeTab, status, + uNumNodes); + cp_to_usr(args->ARGS_PROC_ENUMNODE_INFO.puNumNodes, &uNumNodes, + status, 1); + cp_to_usr(args->ARGS_PROC_ENUMNODE_INFO.puAllocated, &uAllocated, + status, 1); + return status; +} + +/* + * ======== PROCWRAP_FlushMemory ======== + */ +u32 PROCWRAP_FlushMemory(union Trapped_Args *args) +{ + DSP_STATUS status; + + GT_0trace(WCD_debugMask, GT_ENTER, "PROCWRAP_FlushMemory: entered\n"); + + status = PROC_FlushMemory(args->ARGS_PROC_FLUSHMEMORY.hProcessor, + args->ARGS_PROC_FLUSHMEMORY.pMpuAddr, + args->ARGS_PROC_FLUSHMEMORY.ulSize, + args->ARGS_PROC_FLUSHMEMORY.ulFlags); + return status; +} + + +/* + * ======== PROCWRAP_InvalidateMemory ======== + */ +u32 PROCWRAP_InvalidateMemory(union Trapped_Args *args) +{ + DSP_STATUS status; + + GT_0trace(WCD_debugMask, GT_ENTER, + "PROCWRAP_InvalidateMemory:entered\n"); + + status = PROC_InvalidateMemory( + args->ARGS_PROC_INVALIDATEMEMORY.hProcessor, + args->ARGS_PROC_INVALIDATEMEMORY.pMpuAddr, + args->ARGS_PROC_INVALIDATEMEMORY.ulSize); + return status; +} + + +/* + * ======== PROCWRAP_EnumResources ======== + */ +u32 PROCWRAP_EnumResources(union Trapped_Args *args) +{ + u32 retVal; + + GT_4trace(WCD_debugMask, GT_ENTER, + "PROCWRAP_EnumResources: entered args:\n" + "0x%x hProcessor: 0x%x\tuResourceMask: 0x%x\tpResourceInfo" + " 0x%x\tuResourceInfoSixe \n", + args->ARGS_PROC_ENUMRESOURCES.hProcessor, + args->ARGS_PROC_ENUMRESOURCES.uResourceType, + args->ARGS_PROC_ENUMRESOURCES.pResourceInfo, + args->ARGS_PROC_ENUMRESOURCES.uResourceInfoSize); + retVal = PROC_GetResourceInfo(args->ARGS_PROC_ENUMRESOURCES.hProcessor, + args->ARGS_PROC_ENUMRESOURCES.uResourceType, + WRAP_MAP2CALLER(args->ARGS_PROC_ENUMRESOURCES. + pResourceInfo), args->ARGS_PROC_ENUMRESOURCES. + uResourceInfoSize); + + return retVal; +} + +/* + * ======== PROCWRAP_GetState ======== + */ +u32 PROCWRAP_GetState(union Trapped_Args *args) +{ + DSP_STATUS status; + struct DSP_PROCESSORSTATE procStatus; + GT_0trace(WCD_debugMask, GT_ENTER, "PROCWRAP_GetState: entered\n"); + status = PROC_GetState(args->ARGS_PROC_GETSTATE.hProcessor, &procStatus, + args->ARGS_PROC_GETSTATE.uStateInfoSize); + cp_to_usr(args->ARGS_PROC_GETSTATE.pProcStatus, &procStatus, status, 1); + return status; + +} + +/* + * ======== PROCWRAP_GetTrace ======== + */ +u32 PROCWRAP_GetTrace(union Trapped_Args *args) +{ + DSP_STATUS status; + u8 *pBuf; + + GT_0trace(WCD_debugMask, GT_ENTER, "PROCWRAP_GetTrace: entered\n"); + + DBC_Require(args->ARGS_PROC_GETTRACE.uMaxSize <= MAX_TRACEBUFLEN); + + pBuf = MEM_Calloc(args->ARGS_PROC_GETTRACE.uMaxSize, MEM_NONPAGED); + if (pBuf != NULL) { + status = PROC_GetTrace(args->ARGS_PROC_GETTRACE.hProcessor, + pBuf, args->ARGS_PROC_GETTRACE.uMaxSize); + } else { + status = DSP_EMEMORY; + } + cp_to_usr(args->ARGS_PROC_GETTRACE.pBuf, pBuf, status, + args->ARGS_PROC_GETTRACE.uMaxSize); + if (pBuf) + MEM_Free(pBuf); + + return status; +} + +/* + * ======== PROCWRAP_Load ======== + */ +u32 PROCWRAP_Load(union Trapped_Args *args) +{ + s32 i, len; + DSP_STATUS status = DSP_SOK; + char *temp; + s32 argc = args->ARGS_PROC_LOAD.iArgc; + u8 **argv, **envp = NULL; + + + DBC_Require(argc > 0); + DBC_Require(argc <= MAX_LOADARGS); + + argv = MEM_Alloc(argc * sizeof(u8 *), MEM_NONPAGED); + if (argv == NULL) + status = DSP_EMEMORY; + + cp_fm_usr(argv, args->ARGS_PROC_LOAD.aArgv, status, argc); + for (i = 0; DSP_SUCCEEDED(status) && (i < argc); i++) { + if (argv[i] != NULL) { + /* User space pointer to argument */ + temp = (char *) argv[i]; + len = strlen_user((char *)temp); + /* Kernel space pointer to argument */ + argv[i] = MEM_Alloc(len, MEM_NONPAGED); + if (argv[i] == NULL) { + status = DSP_EMEMORY; + break; + } + cp_fm_usr(argv[i], temp, status, len); + } + } + /* TODO: validate this */ + if (args->ARGS_PROC_LOAD.aEnvp != NULL) { + /* number of elements in the envp array including NULL */ + len = 0; + do { + len++; + get_user(temp, args->ARGS_PROC_LOAD.aEnvp); + } while (temp); + envp = MEM_Alloc(len * sizeof(u8 *), MEM_NONPAGED); + if (envp == NULL) + status = DSP_EMEMORY; + + cp_fm_usr(envp, args->ARGS_PROC_LOAD.aEnvp, status, len); + for (i = 0; DSP_SUCCEEDED(status) && (envp[i] != NULL); i++) { + /* User space pointer to argument */ + temp = (char *)envp[i]; + len = strlen_user((char *)temp); + /* Kernel space pointer to argument */ + envp[i] = MEM_Alloc(len, MEM_NONPAGED); + if (envp[i] == NULL) { + status = DSP_EMEMORY; + break; + } + cp_fm_usr(envp[i], temp, status, len); + } + } + GT_5trace(WCD_debugMask, GT_ENTER, + "PROCWRAP_Load, hProcessor: 0x%x\n\tiArgc:" + "0x%x\n\taArgv: 0x%x\n\taArgv[0]: %s\n\taEnvp: 0x%0x\n", + args->ARGS_PROC_LOAD.hProcessor, + args->ARGS_PROC_LOAD.iArgc, args->ARGS_PROC_LOAD.aArgv, + argv[0], args->ARGS_PROC_LOAD.aEnvp); + if (DSP_SUCCEEDED(status)) { + status = PROC_Load(args->ARGS_PROC_LOAD.hProcessor, + args->ARGS_PROC_LOAD.iArgc, + (CONST char **)argv, (CONST char **)envp); + } + if (envp != NULL) { + i = 0; + while (envp[i] != NULL) + MEM_Free(envp[i++]); + + MEM_Free(envp); + } + if (argv != NULL) { + for (i = 0; i < argc; i++) { + if (argv[i] != NULL) + MEM_Free(argv[i]); + + } + MEM_Free(argv); + } + return status; +} + +/* + * ======== PROCWRAP_Map ======== + */ +u32 PROCWRAP_Map(union Trapped_Args *args) +{ + DSP_STATUS status; + void *pMapAddr; + + GT_0trace(WCD_debugMask, GT_ENTER, "PROCWRAP_Map: entered\n"); + status = PROC_Map(args->ARGS_PROC_MAPMEM.hProcessor, + args->ARGS_PROC_MAPMEM.pMpuAddr, + args->ARGS_PROC_MAPMEM.ulSize, + args->ARGS_PROC_MAPMEM.pReqAddr, &pMapAddr, + args->ARGS_PROC_MAPMEM.ulMapAttr); + if (DSP_SUCCEEDED(status)) { + if (put_user(pMapAddr, args->ARGS_PROC_MAPMEM.ppMapAddr)) + status = DSP_EINVALIDARG; + + } + return status; +} + +/* + * ======== PROCWRAP_RegisterNotify ======== + */ +u32 PROCWRAP_RegisterNotify(union Trapped_Args *args) +{ + DSP_STATUS status; + struct DSP_NOTIFICATION notification; + + GT_0trace(WCD_debugMask, GT_ENTER, + "PROCWRAP_RegisterNotify: entered\n"); + + /* Initialize the notification data structure */ + notification.psName = NULL; + notification.handle = NULL; + + status = PROC_RegisterNotify(args->ARGS_PROC_REGISTER_NOTIFY.hProcessor, + args->ARGS_PROC_REGISTER_NOTIFY.uEventMask, + args->ARGS_PROC_REGISTER_NOTIFY.uNotifyType, + ¬ification); + cp_to_usr(args->ARGS_PROC_REGISTER_NOTIFY.hNotification, ¬ification, + status, 1); + return status; +} + +/* + * ======== PROCWRAP_ReserveMemory ======== + */ +u32 PROCWRAP_ReserveMemory(union Trapped_Args *args) +{ + DSP_STATUS status; + void *pRsvAddr; + + GT_0trace(WCD_debugMask, GT_ENTER, "PROCWRAP_ReserveMemory: entered\n"); + status = PROC_ReserveMemory(args->ARGS_PROC_RSVMEM.hProcessor, + args->ARGS_PROC_RSVMEM.ulSize, &pRsvAddr); + if (put_user(pRsvAddr, args->ARGS_PROC_RSVMEM.ppRsvAddr)) + status = DSP_EINVALIDARG; + + return status; +} + +/* + * ======== PROCWRAP_Start ======== + */ +u32 PROCWRAP_Start(union Trapped_Args *args) +{ + u32 retVal; + + GT_0trace(WCD_debugMask, GT_ENTER, "PROCWRAP_Start: entered\n"); + retVal = PROC_Start(args->ARGS_PROC_START.hProcessor); + return retVal; +} + +/* + * ======== PROCWRAP_UnMap ======== + */ +u32 PROCWRAP_UnMap(union Trapped_Args *args) +{ + DSP_STATUS status; + + GT_0trace(WCD_debugMask, GT_ENTER, "PROCWRAP_UnMap: entered\n"); + status = PROC_UnMap(args->ARGS_PROC_UNMAPMEM.hProcessor, + args->ARGS_PROC_UNMAPMEM.pMapAddr); + return status; +} + +/* + * ======== PROCWRAP_UnReserveMemory ======== + */ +u32 PROCWRAP_UnReserveMemory(union Trapped_Args *args) +{ + DSP_STATUS status; + + GT_0trace(WCD_debugMask, GT_ENTER, + "PROCWRAP_UnReserveMemory: entered\n"); + status = PROC_UnReserveMemory(args->ARGS_PROC_UNRSVMEM.hProcessor, + args->ARGS_PROC_UNRSVMEM.pRsvAddr); + return status; +} + +/* + * ======== PROCWRAP_Stop ======== + */ +u32 PROCWRAP_Stop(union Trapped_Args *args) +{ + u32 retVal; + + GT_0trace(WCD_debugMask, GT_ENTER, "PROCWRAP_Stop: entered\n"); + retVal = PROC_Stop(args->ARGS_PROC_STOP.hProcessor); + + return retVal; +} + +/* + * ======== NODEWRAP_Allocate ======== + */ +u32 NODEWRAP_Allocate(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + struct DSP_UUID nodeId; + u32 cbDataSize; + u32 __user *pSize = (u32 __user *)args->ARGS_NODE_ALLOCATE.pArgs; + u8 *pArgs = NULL; + struct DSP_NODEATTRIN attrIn, *pAttrIn = NULL; + struct NODE_OBJECT *hNode; + + GT_0trace(WCD_debugMask, GT_ENTER, "NODEWRAP_Allocate: entered\n"); + + /* Optional argument */ + if (pSize) { + if (get_user(cbDataSize, pSize)) + status = DSP_EFAIL; + + cbDataSize += sizeof(u32); + if (DSP_SUCCEEDED(status)) { + pArgs = MEM_Alloc(cbDataSize, MEM_NONPAGED); + if (pArgs == NULL) + status = DSP_EMEMORY; + + } + cp_fm_usr(pArgs, args->ARGS_NODE_ALLOCATE.pArgs, status, + cbDataSize); + } + cp_fm_usr(&nodeId, args->ARGS_NODE_ALLOCATE.pNodeID, status, 1); + /* Optional argument */ + if (args->ARGS_NODE_ALLOCATE.pAttrIn) { + cp_fm_usr(&attrIn, args->ARGS_NODE_ALLOCATE.pAttrIn, status, 1); + if (DSP_SUCCEEDED(status)) + pAttrIn = &attrIn; + + } + if (DSP_SUCCEEDED(status)) { + status = NODE_Allocate(args->ARGS_NODE_ALLOCATE.hProcessor, + &nodeId, (struct DSP_CBDATA *)pArgs, + pAttrIn, &hNode); + } + cp_to_usr(args->ARGS_NODE_ALLOCATE.phNode, &hNode, status, 1); + if (pArgs) + MEM_Free(pArgs); + + return status; +} + +/* + * ======== NODEWRAP_AllocMsgBuf ======== + */ +u32 NODEWRAP_AllocMsgBuf(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + struct DSP_BUFFERATTR *pAttr = NULL; + struct DSP_BUFFERATTR attr; + u8 *pBuffer = NULL; + + if (args->ARGS_NODE_ALLOCMSGBUF.pAttr) { /* Optional argument */ + cp_fm_usr(&attr, args->ARGS_NODE_ALLOCMSGBUF.pAttr, status, 1); + if (DSP_SUCCEEDED(status)) + pAttr = &attr; + + } + /* IN OUT argument */ + cp_fm_usr(&pBuffer, args->ARGS_NODE_ALLOCMSGBUF.pBuffer, status, 1); + if (DSP_SUCCEEDED(status)) { + status = NODE_AllocMsgBuf(args->ARGS_NODE_ALLOCMSGBUF.hNode, + args->ARGS_NODE_ALLOCMSGBUF.uSize, + pAttr, &pBuffer); + } + cp_to_usr(args->ARGS_NODE_ALLOCMSGBUF.pBuffer, &pBuffer, status, 1) + return status; +} + +/* + * ======== NODEWRAP_ChangePriority ======== + */ +u32 NODEWRAP_ChangePriority(union Trapped_Args *args) +{ + u32 retVal; + + GT_0trace(WCD_debugMask, GT_ENTER, + "NODEWRAP_ChangePriority: entered\n"); + retVal = NODE_ChangePriority(args->ARGS_NODE_CHANGEPRIORITY.hNode, + args->ARGS_NODE_CHANGEPRIORITY.iPriority); + + return retVal; +} + +/* + * ======== NODEWRAP_Connect ======== + */ +u32 NODEWRAP_Connect(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + struct DSP_STRMATTR attrs; + struct DSP_STRMATTR *pAttrs = NULL; + u32 cbDataSize; + u32 __user *pSize = (u32 __user *)args->ARGS_NODE_CONNECT.pConnParam; + u8 *pArgs = NULL; + + GT_0trace(WCD_debugMask, GT_ENTER, "NODEWRAP_Connect: entered\n"); + + /* Optional argument */ + if (pSize) { + if (get_user(cbDataSize, pSize)) + status = DSP_EFAIL; + + cbDataSize += sizeof(u32); + if (DSP_SUCCEEDED(status)) { + pArgs = MEM_Alloc(cbDataSize, MEM_NONPAGED); + if (pArgs == NULL) + status = DSP_EMEMORY; + + } + cp_fm_usr(pArgs, args->ARGS_NODE_CONNECT.pConnParam, status, + cbDataSize); + } + if (args->ARGS_NODE_CONNECT.pAttrs) { /* Optional argument */ + cp_fm_usr(&attrs, args->ARGS_NODE_CONNECT.pAttrs, status, 1); + if (DSP_SUCCEEDED(status)) + pAttrs = &attrs; + + } + if (DSP_SUCCEEDED(status)) { + status = NODE_Connect(args->ARGS_NODE_CONNECT.hNode, + args->ARGS_NODE_CONNECT.uStream, + args->ARGS_NODE_CONNECT.hOtherNode, + args->ARGS_NODE_CONNECT.uOtherStream, + pAttrs, (struct DSP_CBDATA *)pArgs); + } + if (pArgs) + MEM_Free(pArgs); + + return status; +} + +/* + * ======== NODEWRAP_Create ======== + */ +u32 NODEWRAP_Create(union Trapped_Args *args) +{ + u32 retVal; + + GT_0trace(WCD_debugMask, GT_ENTER, "NODEWRAP_Create: entered\n"); + retVal = NODE_Create(args->ARGS_NODE_CREATE.hNode); + + return retVal; +} + +/* + * ======== NODEWRAP_Delete ======== + */ +u32 NODEWRAP_Delete(union Trapped_Args *args) +{ + u32 retVal; + + GT_0trace(WCD_debugMask, GT_ENTER, "NODEWRAP_Delete: entered\n"); + retVal = NODE_Delete(args->ARGS_NODE_DELETE.hNode); + + return retVal; +} + +/* + * ======== NODEWRAP_FreeMsgBuf ======== + */ +u32 NODEWRAP_FreeMsgBuf(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + struct DSP_BUFFERATTR *pAttr = NULL; + struct DSP_BUFFERATTR attr; + if (args->ARGS_NODE_FREEMSGBUF.pAttr) { /* Optional argument */ + cp_fm_usr(&attr, args->ARGS_NODE_FREEMSGBUF.pAttr, status, 1); + if (DSP_SUCCEEDED(status)) + pAttr = &attr; + + } + if (DSP_SUCCEEDED(status)) { + status = NODE_FreeMsgBuf(args->ARGS_NODE_FREEMSGBUF.hNode, + args->ARGS_NODE_FREEMSGBUF.pBuffer, + pAttr); + } + + return status; +} + +/* + * ======== NODEWRAP_GetAttr ======== + */ +u32 NODEWRAP_GetAttr(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + struct DSP_NODEATTR attr; + + GT_0trace(WCD_debugMask, GT_ENTER, "NODEWRAP_GetAttr: entered\n"); + + status = NODE_GetAttr(args->ARGS_NODE_GETATTR.hNode, &attr, + args->ARGS_NODE_GETATTR.uAttrSize); + cp_to_usr(args->ARGS_NODE_GETATTR.pAttr, &attr, status, 1); + + return status; +} + +/* + * ======== NODEWRAP_GetMessage ======== + */ +u32 NODEWRAP_GetMessage(union Trapped_Args *args) +{ + DSP_STATUS status; + struct DSP_MSG msg; + + GT_0trace(WCD_debugMask, GT_ENTER, "NODEWRAP_GetMessage: entered\n"); + + status = NODE_GetMessage(args->ARGS_NODE_GETMESSAGE.hNode, &msg, + args->ARGS_NODE_GETMESSAGE.uTimeout); + + cp_to_usr(args->ARGS_NODE_GETMESSAGE.pMessage, &msg, status, 1); + + return status; +} + +/* + * ======== NODEWRAP_Pause ======== + */ +u32 NODEWRAP_Pause(union Trapped_Args *args) +{ + u32 retVal; + + GT_0trace(WCD_debugMask, GT_ENTER, "NODEWRAP_Pause: entered\n"); + retVal = NODE_Pause(args->ARGS_NODE_PAUSE.hNode); + + return retVal; +} + +/* + * ======== NODEWRAP_PutMessage ======== + */ +u32 NODEWRAP_PutMessage(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + struct DSP_MSG msg; + + GT_0trace(WCD_debugMask, GT_ENTER, "NODEWRAP_PutMessage: entered\n"); + + cp_fm_usr(&msg, args->ARGS_NODE_PUTMESSAGE.pMessage, status, 1); + + if (DSP_SUCCEEDED(status)) { + status = NODE_PutMessage(args->ARGS_NODE_PUTMESSAGE.hNode, &msg, + args->ARGS_NODE_PUTMESSAGE.uTimeout); + } + + return status; +} + +/* + * ======== NODEWRAP_RegisterNotify ======== + */ +u32 NODEWRAP_RegisterNotify(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + struct DSP_NOTIFICATION notification; + + GT_0trace(WCD_debugMask, GT_ENTER, + "NODEWRAP_RegisterNotify: entered\n"); + + /* Initialize the notification data structure */ + notification.psName = NULL; + notification.handle = NULL; + + status = NODE_RegisterNotify(args->ARGS_NODE_REGISTERNOTIFY.hNode, + args->ARGS_NODE_REGISTERNOTIFY.uEventMask, + args->ARGS_NODE_REGISTERNOTIFY.uNotifyType, + ¬ification); + cp_to_usr(args->ARGS_NODE_REGISTERNOTIFY.hNotification, ¬ification, + status, 1); + return status; +} + +/* + * ======== NODEWRAP_Run ======== + */ +u32 NODEWRAP_Run(union Trapped_Args *args) +{ + u32 retVal; + + GT_0trace(WCD_debugMask, GT_ENTER, "NODEWRAP_Run: entered\n"); + retVal = NODE_Run(args->ARGS_NODE_RUN.hNode); + + return retVal; +} + +/* + * ======== NODEWRAP_Terminate ======== + */ +u32 NODEWRAP_Terminate(union Trapped_Args *args) +{ + DSP_STATUS status; + DSP_STATUS tempstatus; + + GT_0trace(WCD_debugMask, GT_ENTER, "NODEWRAP_Terminate: entered\n"); + + status = NODE_Terminate(args->ARGS_NODE_TERMINATE.hNode, &tempstatus); + + cp_to_usr(args->ARGS_NODE_TERMINATE.pStatus, &tempstatus, status, 1); + + return status; +} + + +/* + * ======== NODEWRAP_GetUUIDProps ======== + */ +u32 NODEWRAP_GetUUIDProps(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + struct DSP_UUID nodeId; + struct DSP_NDBPROPS *pnodeProps = NULL; + + GT_0trace(WCD_debugMask, GT_ENTER, + "NODEWRAP_GetUUIDPropste: entered\n"); + + + cp_fm_usr(&nodeId, args->ARGS_NODE_GETUUIDPROPS.pNodeID, status, 1); + pnodeProps = MEM_Alloc(sizeof(struct DSP_NDBPROPS), MEM_NONPAGED); + if (pnodeProps != NULL) { + status = NODE_GetUUIDProps(args-> + ARGS_NODE_GETUUIDPROPS.hProcessor, + &nodeId, pnodeProps); + cp_to_usr(args->ARGS_NODE_GETUUIDPROPS.pNodeProps, pnodeProps, + status, 1); + } else + status = DSP_EMEMORY; + if (pnodeProps) + MEM_Free(pnodeProps); + return status; +} + +/* + * ======== STRMWRAP_AllocateBuffer ======== + */ +u32 STRMWRAP_AllocateBuffer(union Trapped_Args *args) +{ + DSP_STATUS status; + u8 **apBuffer = NULL; + u32 uNumBufs = args->ARGS_STRM_ALLOCATEBUFFER.uNumBufs; + + DBC_Require(uNumBufs <= MAX_BUFS); + + apBuffer = MEM_Alloc((uNumBufs * sizeof(u8 *)), MEM_NONPAGED); + + status = STRM_AllocateBuffer(args->ARGS_STRM_ALLOCATEBUFFER.hStream, + args->ARGS_STRM_ALLOCATEBUFFER.uSize, + apBuffer, uNumBufs); + cp_to_usr(args->ARGS_STRM_ALLOCATEBUFFER.apBuffer, apBuffer, status, + uNumBufs); + if (apBuffer) + MEM_Free(apBuffer); + + return status; +} + +/* + * ======== STRMWRAP_Close ======== + */ +u32 STRMWRAP_Close(union Trapped_Args *args) +{ + u32 retVal; + + retVal = STRM_Close(args->ARGS_STRM_CLOSE.hStream); + + return retVal; +} + +/* + * ======== STRMWRAP_FreeBuffer ======== + */ +u32 STRMWRAP_FreeBuffer(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + u8 **apBuffer = NULL; + u32 uNumBufs = args->ARGS_STRM_FREEBUFFER.uNumBufs; + + DBC_Require(uNumBufs <= MAX_BUFS); + + apBuffer = MEM_Alloc((uNumBufs * sizeof(u8 *)), MEM_NONPAGED); + + cp_fm_usr(apBuffer, args->ARGS_STRM_FREEBUFFER.apBuffer, status, + uNumBufs); + + if (DSP_SUCCEEDED(status)) { + status = STRM_FreeBuffer(args->ARGS_STRM_FREEBUFFER.hStream, + apBuffer, uNumBufs); + } + cp_to_usr(args->ARGS_STRM_FREEBUFFER.apBuffer, apBuffer, status, + uNumBufs); + if (apBuffer) + MEM_Free(apBuffer); + + return status; +} + +/* + * ======== STRMWRAP_GetEventHandle ======== + */ +u32 STRMWRAP_GetEventHandle(union Trapped_Args *args) +{ + return DSP_ENOTIMPL; +} + +/* + * ======== STRMWRAP_GetInfo ======== + */ +u32 STRMWRAP_GetInfo(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + struct STRM_INFO strmInfo; + struct DSP_STREAMINFO user; + struct DSP_STREAMINFO *temp; + + cp_fm_usr(&strmInfo, args->ARGS_STRM_GETINFO.pStreamInfo, status, 1); + temp = strmInfo.pUser; + + strmInfo.pUser = &user; + + if (DSP_SUCCEEDED(status)) { + status = STRM_GetInfo(args->ARGS_STRM_GETINFO.hStream, + &strmInfo, args->ARGS_STRM_GETINFO.uStreamInfoSize); + } + cp_to_usr(temp, strmInfo.pUser, status, 1); + strmInfo.pUser = temp; + cp_to_usr(args->ARGS_STRM_GETINFO.pStreamInfo, &strmInfo, status, 1); + return status; +} + +/* + * ======== STRMWRAP_Idle ======== + */ +u32 STRMWRAP_Idle(union Trapped_Args *args) +{ + u32 retVal; + + retVal = STRM_Idle(args->ARGS_STRM_IDLE.hStream, + args->ARGS_STRM_IDLE.bFlush); + + return retVal; +} + +/* + * ======== STRMWRAP_Issue ======== + */ +u32 STRMWRAP_Issue(union Trapped_Args *args) +{ + u32 retVal; + + retVal = STRM_Issue(args->ARGS_STRM_ISSUE.hStream, + args->ARGS_STRM_ISSUE.pBuffer, + args->ARGS_STRM_ISSUE.dwBytes, + args->ARGS_STRM_ISSUE.dwBufSize, + args->ARGS_STRM_ISSUE.dwArg); + + /* This is a user space pointer */ + return retVal; +} + +/* + * ======== STRMWRAP_Open ======== + */ +u32 STRMWRAP_Open(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + struct STRM_ATTR attr; + struct STRM_OBJECT *pStrm; + struct DSP_STREAMATTRIN strmAttrIn; + + cp_fm_usr(&attr, args->ARGS_STRM_OPEN.pAttrIn, status, 1); + + if (attr.pStreamAttrIn != NULL) { /* Optional argument */ + cp_fm_usr(&strmAttrIn, attr.pStreamAttrIn, status, 1); + if (DSP_SUCCEEDED(status)) + attr.pStreamAttrIn = &strmAttrIn; + + } + status = STRM_Open(args->ARGS_STRM_OPEN.hNode, + args->ARGS_STRM_OPEN.uDirection, + args->ARGS_STRM_OPEN.uIndex, &attr, &pStrm); + cp_to_usr(args->ARGS_STRM_OPEN.phStream, &pStrm, status, 1); + return status; +} + +/* + * ======== STRMWRAP_Reclaim ======== + */ +u32 STRMWRAP_Reclaim(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + u8 *pBufPtr; + u32 ulBytes; + u32 dwArg; + u32 ulBufSize; + + status = STRM_Reclaim(args->ARGS_STRM_RECLAIM.hStream, &pBufPtr, + &ulBytes, &ulBufSize, &dwArg); + cp_to_usr(args->ARGS_STRM_RECLAIM.pBufPtr, &pBufPtr, status, 1); + cp_to_usr(args->ARGS_STRM_RECLAIM.pBytes, &ulBytes, status, 1); + cp_to_usr(args->ARGS_STRM_RECLAIM.pdwArg, &dwArg, status, 1); + + if (args->ARGS_STRM_RECLAIM.pBufSize != NULL) { + cp_to_usr(args->ARGS_STRM_RECLAIM.pBufSize, &ulBufSize, + status, 1); + } + + return status; +} + +/* + * ======== STRMWRAP_RegisterNotify ======== + */ +u32 STRMWRAP_RegisterNotify(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + struct DSP_NOTIFICATION notification; + + GT_0trace(WCD_debugMask, GT_ENTER, + "NODEWRAP_RegisterNotify: entered\n"); + + /* Initialize the notification data structure */ + notification.psName = NULL; + notification.handle = NULL; + + status = STRM_RegisterNotify(args->ARGS_STRM_REGISTERNOTIFY.hStream, + args->ARGS_STRM_REGISTERNOTIFY.uEventMask, + args->ARGS_STRM_REGISTERNOTIFY.uNotifyType, + ¬ification); + cp_to_usr(args->ARGS_STRM_REGISTERNOTIFY.hNotification, ¬ification, + status, 1); + + return status; +} + +/* + * ======== STRMWRAP_Select ======== + */ +u32 STRMWRAP_Select(union Trapped_Args *args) +{ + u32 mask; + struct STRM_OBJECT *aStrmTab[MAX_STREAMS]; + DSP_STATUS status = DSP_SOK; + + DBC_Require(args->ARGS_STRM_SELECT.nStreams <= MAX_STREAMS); + + cp_fm_usr(aStrmTab, args->ARGS_STRM_SELECT.aStreamTab, status, + args->ARGS_STRM_SELECT.nStreams); + if (DSP_SUCCEEDED(status)) { + status = STRM_Select(aStrmTab, args->ARGS_STRM_SELECT.nStreams, + &mask, args->ARGS_STRM_SELECT.uTimeout); + } + cp_to_usr(args->ARGS_STRM_SELECT.pMask, &mask, status, 1); + return status; +} + +/* CMM */ + +/* + * ======== CMMWRAP_CallocBuf ======== + */ +u32 CMMWRAP_CallocBuf(union Trapped_Args *args) +{ + /* This operation is done in kernel */ + return DSP_ENOTIMPL; +} + +/* + * ======== CMMWRAP_FreeBuf ======== + */ +u32 CMMWRAP_FreeBuf(union Trapped_Args *args) +{ + /* This operation is done in kernel */ + return DSP_ENOTIMPL; +} + +/* + * ======== CMMWRAP_GetHandle ======== + */ +u32 CMMWRAP_GetHandle(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + struct CMM_OBJECT *hCmmMgr; + + status = CMM_GetHandle(args->ARGS_CMM_GETHANDLE.hProcessor, &hCmmMgr); + + cp_to_usr(args->ARGS_CMM_GETHANDLE.phCmmMgr, &hCmmMgr, status, 1); + + return status; +} + +/* + * ======== CMMWRAP_GetInfo ======== + */ +u32 CMMWRAP_GetInfo(union Trapped_Args *args) +{ + DSP_STATUS status = DSP_SOK; + struct CMM_INFO cmmInfo; + + status = CMM_GetInfo(args->ARGS_CMM_GETINFO.hCmmMgr, &cmmInfo); + + cp_to_usr(args->ARGS_CMM_GETINFO.pCmmInfo, &cmmInfo, status, 1); + + return status; +} diff --git a/drivers/dsp/bridge/rmgr/dbdcd.c b/drivers/dsp/bridge/rmgr/dbdcd.c new file mode 100644 index 0000000..c5ec8f9 --- /dev/null +++ b/drivers/dsp/bridge/rmgr/dbdcd.c @@ -0,0 +1,1573 @@ +/* + * dbdcd.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dbdcd.c ======== + * Description: + * This file contains the implementation of the DSP/BIOS Bridge + * Configuration Database (DCD). + * + * Notes: + * The fxn DCD_GetObjects can apply a callback fxn to each DCD object + * that is located in a specified COFF file. At the moment, + * DCD_AutoRegister, DCD_AutoUnregister, and NLDR module all use + * DCD_GetObjects. + * + *! Revision History + *! ================ + *! 03-Dec-2003 map Changed DCD_OBJTYPE to DSP_DCDOBJTYPE + *! 17-Dec-2002 map Modified DCD_GetDepLibs, DCD_GetNumDepLibs, GetDepLibInfo + *! to include phase information + *! 02-Dec-2002 map Modified DCD_GetLibraryName for phases in different + *! libraries + *! 26-Feb-2003 kc Updated DCD_AutoUnregister and DCD_GetObjects to simplify + *! DCD implementation. + *! 17-Jul-2002 jeh Call COD_Open() instead of COD_OpenBase(), call COD_Close() + *! 11-Jul-2002 jeh Added DCD_GetDepLibs(), DCD_GetNumDepLibs(). + *! 18-Feb-2003 vp Code review updates + *! 18-Oct-2002 vp Ported to Linux platform + *! 15-Mar-2002 jeh Read dynamic loading memory requirements into node object + *! data. Added DCD_GetLibraryName(). + *! 13-Feb-2002 jeh Get system stack size in GetAttrsFromBuf(). + *! 01-Aug-2001 ag: Added check for PROC "extended" attributes used for + *! DSP-MMU setup. These are private attributes. + *! 18-Apr-2001 jeh Use COD_OpenBase instead of COD_LoadBase. + *! 03-Apr-2001 sg: Changed error names to DSP_EDCD* format. + *! 11-Jan-2001 jeh Changes to DCD_GetObjectDef to match node.cdb, proc.cdb. + *! 12-Dec-2000 kc: Added DCD_AutoUnregister. MSGNODE, DAISNODE added in + *! GetAttrsFromBuf + *! 22-Nov-2000 kc: Replaced sprintf() calls with strncat. + *! 09-Nov-2000 kc: Optimized DCD module. + *! 30-Oct-2000 kc: Added DCD_AutoRegister function; changed local var. names. + *! 29-Sep-2000 kc: Added code review changes (src/reviews/dcd_reviews.txt). + *! 06-Sep-2000 jeh Get message segid, message notification type. Added Atoi() + *! to replace atoi(), until cdb generation can output in + *! decimal format. + *! 26-Jul-2000 kc: Created. + *! + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include + +/* ----------------------------------- Platform Manager */ +#include + +/* ----------------------------------- Others */ +#include + +/* ----------------------------------- This */ +#include + +/* ----------------------------------- Global defines. */ +#define SIGNATURE 0x5f444344 /* "DCD_" (in reverse). */ + +#define IsValidHandle(h) (((h) != NULL) && (h->dwSignature == SIGNATURE)) + +#define MAX_INT2CHAR_LENGTH 16 /* Maximum int2char len of 32 bit int. */ + +/* Name of section containing dependent libraries */ +#define DEPLIBSECT ".dspbridge_deplibs" + +/* DCD specific structures. */ +struct DCD_MANAGER { + u32 dwSignature; /* Used for object validation. */ + struct COD_MANAGER *hCodMgr; /* Handle to COD manager object. */ +}; + +/* Global reference variables. */ +static u32 cRefs; +static u32 cEnumRefs; + +extern struct GT_Mask curTrace; + +/* helper function prototypes. */ +static s32 Atoi(char *pszBuf); + +static DSP_STATUS GetAttrsFromBuf(char *pszBuf, u32 ulBufSize, + enum DSP_DCDOBJTYPE objType, + struct DCD_GENERICOBJ *pGenObj); + +static void CompressBuf(char *pszBuf, u32 ulBufSize, s32 cCharSize); + +static char DspChar2GppChar(char *pWord, s32 cDspCharSize); + +static DSP_STATUS GetDepLibInfo(IN struct DCD_MANAGER *hDcdMgr, + IN struct DSP_UUID *pUuid, + IN OUT u16 *pNumLibs, + OPTIONAL OUT u16 *pNumPersLibs, + OPTIONAL OUT struct DSP_UUID *pDepLibUuids, + OPTIONAL OUT bool *pPersistentDepLibs, + IN enum NLDR_PHASE phase); + +/* + * ======== DCD_AutoRegister ======== + * Purpose: + * Parses the supplied image and resigsters with DCD. + */ + +DSP_STATUS DCD_AutoRegister(IN struct DCD_MANAGER *hDcdMgr, + IN char *pszCoffPath) +{ + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + + GT_1trace(curTrace, GT_ENTER, "DCD_AutoRegister: hDcdMgr 0x%x\n", + hDcdMgr); + + if (IsValidHandle(hDcdMgr)) { + status = DCD_GetObjects(hDcdMgr, pszCoffPath, + (DCD_REGISTERFXN)DCD_RegisterObject, + (void *)pszCoffPath); + } else { + status = DSP_EHANDLE; + GT_0trace(curTrace, GT_6CLASS, + "DCD_AutoRegister: invalid DCD manager handle.\n"); + } + + return status; +} + +/* + * ======== DCD_AutoUnregister ======== + * Purpose: + * Parses the supplied DSP image and unresiters from DCD. + */ +DSP_STATUS DCD_AutoUnregister(IN struct DCD_MANAGER *hDcdMgr, + IN char *pszCoffPath) +{ + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + + GT_1trace(curTrace, GT_ENTER, "DCD_AutoUnregister: hDcdMgr 0x%x\n", + hDcdMgr); + + if (IsValidHandle(hDcdMgr)) { + status = DCD_GetObjects(hDcdMgr, pszCoffPath, + (DCD_REGISTERFXN)DCD_RegisterObject, + NULL); + } else { + status = DSP_EHANDLE; + GT_0trace(curTrace, GT_6CLASS, + "DCD_AutoUnregister: invalid DCD manager" + " handle.\n"); + } + + return status; +} + +/* + * ======== DCD_CreateManager ======== + * Purpose: + * Creates DCD manager. + */ +DSP_STATUS DCD_CreateManager(IN char *pszZlDllName, + OUT struct DCD_MANAGER **phDcdMgr) +{ + struct COD_MANAGER *hCodMgr; /* COD manager handle */ + struct DCD_MANAGER *pDcdMgr = NULL; /* DCD Manager pointer */ + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs >= 0); + DBC_Require(phDcdMgr); + + GT_1trace(curTrace, GT_ENTER, "DCD_CreateManager: phDcdMgr 0x%x\n", + phDcdMgr); + + status = COD_Create(&hCodMgr, pszZlDllName, NULL); + if (DSP_SUCCEEDED(status)) { + + /* Create a DCD object. */ + MEM_AllocObject(pDcdMgr, struct DCD_MANAGER, SIGNATURE); + if (pDcdMgr != NULL) { + + /* Fill out the object. */ + pDcdMgr->hCodMgr = hCodMgr; + + /* Return handle to this DCD interface. */ + *phDcdMgr = pDcdMgr; + + GT_2trace(curTrace, GT_5CLASS, + "DCD_CreateManager: pDcdMgr 0x%x, " + " hCodMgr 0x%x", pDcdMgr, hCodMgr); + } else { + status = DSP_EMEMORY; + + /* + * If allocation of DcdManager object failed, delete the + * COD manager. + */ + COD_Delete(hCodMgr); + + GT_0trace(curTrace, GT_6CLASS, + "DCD_CreateManager: MEM_AllocObject failed\n"); + } + } else { + status = DSP_EFAIL; + GT_0trace(curTrace, GT_6CLASS, + "DCD_CreateManager: COD_Create failed\n"); + } + + DBC_Ensure((DSP_SUCCEEDED(status)) || ((hCodMgr == NULL) && + (status == DSP_EFAIL)) || ((pDcdMgr == NULL) && + (status == DSP_EMEMORY))); + + return status; +} + +/* + * ======== DCD_DestroyManager ======== + * Purpose: + * Frees DCD Manager object. + */ +DSP_STATUS DCD_DestroyManager(IN struct DCD_MANAGER *hDcdMgr) +{ + struct DCD_MANAGER *pDcdMgr = hDcdMgr; + DSP_STATUS status = DSP_EHANDLE; + + DBC_Require(cRefs >= 0); + + GT_1trace(curTrace, GT_ENTER, "DCD_DestroyManager: hDcdMgr 0x%x\n", + hDcdMgr); + + if (IsValidHandle(hDcdMgr)) { + + /* Delete the COD manager. */ + COD_Delete(pDcdMgr->hCodMgr); + + /* Deallocate a DCD manager object. */ + MEM_FreeObject(pDcdMgr); + + status = DSP_SOK; + } else { + GT_0trace(curTrace, GT_6CLASS, + "DCD_DestroyManager: invalid DCD manager handle.\n"); + } + + return status; +} + +/* + * ======== DCD_EnumerateObject ======== + * Purpose: + * Enumerates objects in the DCD. + */ +DSP_STATUS DCD_EnumerateObject(IN s32 cIndex, IN enum DSP_DCDOBJTYPE objType, + OUT struct DSP_UUID *pUuid) +{ + DSP_STATUS status = DSP_SOK; + char szRegKey[REG_MAXREGPATHLENGTH]; + char szValue[REG_MAXREGPATHLENGTH]; + char szData[REG_MAXREGPATHLENGTH]; + u32 dwValueSize; + u32 dwDataSize; + struct DSP_UUID dspUuid; + char szObjType[MAX_INT2CHAR_LENGTH]; /* str. rep. of objType. */ + u32 dwKeyLen = 0; + + DBC_Require(cRefs >= 0); + DBC_Require(cIndex >= 0); + DBC_Require(pUuid != NULL); + + GT_3trace(curTrace, GT_ENTER, + "DCD_EnumerateObject: cIndex %d, objType %d, " + " pUuid 0x%x\n", cIndex, objType, pUuid); + + if ((cIndex != 0) && (cEnumRefs == 0)) { + /* + * If an enumeration is being performed on an index greater + * than zero, then the current cEnumRefs must have been + * incremented to greater than zero. + */ + status = DSP_ECHANGEDURINGENUM; + } else { + /* Enumerate a specific key in the registry by index. */ + dwValueSize = REG_MAXREGPATHLENGTH; + dwDataSize = REG_MAXREGPATHLENGTH; + + /* + * Pre-determine final key length. It's length of DCD_REGKEY + + * "_\0" + length of szObjType string + terminating NULL. + */ + dwKeyLen = strlen(DCD_REGKEY) + 1 + sizeof(szObjType) + 1; + DBC_Assert(dwKeyLen < REG_MAXREGPATHLENGTH); + + /* Create proper REG key; concatenate DCD_REGKEY with + * objType. */ + strncpy(szRegKey, DCD_REGKEY, strlen(DCD_REGKEY) + 1); + if ((strlen(szRegKey) + strlen("_\0")) < + REG_MAXREGPATHLENGTH) { + strncat(szRegKey, "_\0", 2); + } else { + status = DSP_EFAIL; + } + + /* This snprintf is guaranteed not to exceed max size of an + * integer. */ + status = snprintf(szObjType, MAX_INT2CHAR_LENGTH, "%d", + objType); + + if (status == -1) { + status = DSP_EFAIL; + } else { + status = DSP_SOK; + if ((strlen(szRegKey) + strlen(szObjType)) < + REG_MAXREGPATHLENGTH) { + strncat(szRegKey, szObjType, + strlen(szObjType) + 1); + } else { + status = DSP_EFAIL; + } + } + + if (DSP_SUCCEEDED(status)) { + status = REG_EnumValue(NULL, cIndex, szRegKey, szValue, + &dwValueSize, szData, + &dwDataSize); + } + + if (DSP_SUCCEEDED(status)) { + /* Create UUID value using string retrieved from + * registry. */ + UUID_UuidFromString(szValue, &dspUuid); + + *pUuid = dspUuid; + + /* Increment cEnumRefs to update reference count. */ + cEnumRefs++; + + status = DSP_SOK; + } else if (status == REG_E_NOMOREITEMS) { + /* At the end of enumeration. Reset cEnumRefs. */ + cEnumRefs = 0; + + status = DSP_SENUMCOMPLETE; + } else { + status = DSP_EFAIL; + GT_1trace(curTrace, GT_6CLASS, + "DCD_EnumerateObject: REG_EnumValue" + " failed, status = 0x%x\n", status); + } + } + + DBC_Ensure(pUuid || (status == DSP_EFAIL)); + + return status; +} + +/* + * ======== DCD_Exit ======== + * Purpose: + * Discontinue usage of the DCD module. + */ +void DCD_Exit(void) +{ + DBC_Require(cRefs > 0); + + GT_1trace(curTrace, GT_5CLASS, "DCD_Exit: cRefs 0x%x\n", cRefs); + + cRefs--; + if (cRefs == 0) { + REG_Exit(); + COD_Exit(); + MEM_Exit(); + } + + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== DCD_GetDepLibs ======== + */ +DSP_STATUS DCD_GetDepLibs(IN struct DCD_MANAGER *hDcdMgr, + IN struct DSP_UUID *pUuid, + u16 numLibs, OUT struct DSP_UUID *pDepLibUuids, + OUT bool *pPersistentDepLibs, IN enum NLDR_PHASE phase) +{ + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(IsValidHandle(hDcdMgr)); + DBC_Require(pUuid != NULL); + DBC_Require(pDepLibUuids != NULL); + DBC_Require(pPersistentDepLibs != NULL); + + GT_1trace(curTrace, GT_ENTER, "DCD_GetDepLibs: hDcdMgr 0x%x\n", + hDcdMgr); + + status = GetDepLibInfo(hDcdMgr, pUuid, &numLibs, NULL, pDepLibUuids, + pPersistentDepLibs, phase); + + return status; +} + +/* + * ======== DCD_GetNumDepLibs ======== + */ +DSP_STATUS DCD_GetNumDepLibs(IN struct DCD_MANAGER *hDcdMgr, + IN struct DSP_UUID *pUuid, OUT u16 *pNumLibs, + OUT u16 *pNumPersLibs, IN enum NLDR_PHASE phase) +{ + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(IsValidHandle(hDcdMgr)); + DBC_Require(pNumLibs != NULL); + DBC_Require(pNumPersLibs != NULL); + DBC_Require(pUuid != NULL); + + GT_1trace(curTrace, GT_ENTER, "DCD_GetNumDepLibs: hDcdMgr 0x%x\n", + hDcdMgr); + + status = GetDepLibInfo(hDcdMgr, pUuid, pNumLibs, pNumPersLibs, + NULL, NULL, phase); + + return status; +} + +/* + * ======== DCD_GetObjectDef ======== + * Purpose: + * Retrieves the properties of a node or processor based on the UUID and + * object type. + */ +DSP_STATUS DCD_GetObjectDef(IN struct DCD_MANAGER *hDcdMgr, + IN struct DSP_UUID *pObjUuid, + IN enum DSP_DCDOBJTYPE objType, + OUT struct DCD_GENERICOBJ *pObjDef) +{ + struct DCD_MANAGER *pDcdMgr = hDcdMgr; /* pointer to DCD manager */ + struct COD_LIBRARYOBJ *lib = NULL; + DSP_STATUS status = DSP_SOK; + u32 ulAddr = 0; /* Used by COD_GetSection */ + u32 ulLen = 0; /* Used by COD_GetSection */ + u32 dwBufSize; /* Used by REG functions */ + char szRegKey[REG_MAXREGPATHLENGTH]; + char *szUuid; /*[MAXUUIDLEN];*/ + char szRegData[REG_MAXREGPATHLENGTH]; + char szSectName[MAXUUIDLEN + 2]; /* ".[UUID]\0" */ + char *pszCoffBuf; + u32 dwKeyLen; /* Len of REG key. */ + char szObjType[MAX_INT2CHAR_LENGTH]; /* str. rep. of objType. */ + + DBC_Require(cRefs > 0); + DBC_Require(pObjDef != NULL); + DBC_Require(pObjUuid != NULL); + + GT_4trace(curTrace, GT_ENTER, + "DCD_GetObjectDef: hDcdMgr 0x%x, " "objUuid" + " 0x%x, objType 0x%x, pObjDef 0x%x\n", hDcdMgr, pObjUuid, + objType, pObjDef); + szUuid = (char *)MEM_Calloc(MAXUUIDLEN, MEM_PAGED); + if (!szUuid) + return status = DSP_EMEMORY; + + if (!IsValidHandle(hDcdMgr)) { + status = DSP_EHANDLE; + GT_0trace(curTrace, GT_6CLASS, "DCD_GetObjectDef: invalid " + "DCD manager handle.\n"); + goto func_end; + } + /* Pre-determine final key length. It's length of DCD_REGKEY + + * "_\0" + length of szObjType string + terminating NULL */ + dwKeyLen = strlen(DCD_REGKEY) + 1 + sizeof(szObjType) + 1; + DBC_Assert(dwKeyLen < REG_MAXREGPATHLENGTH); + /* Create proper REG key; concatenate DCD_REGKEY with objType. */ + strncpy(szRegKey, DCD_REGKEY, strlen(DCD_REGKEY) + 1); + + if ((strlen(szRegKey) + strlen("_\0")) < REG_MAXREGPATHLENGTH) + strncat(szRegKey, "_\0", 2); + else + status = DSP_EFAIL; + + status = snprintf(szObjType, MAX_INT2CHAR_LENGTH, "%d", objType); + if (status == -1) { + status = DSP_EFAIL; + } else { + status = DSP_SOK; + + if ((strlen(szRegKey) + strlen(szObjType)) < + REG_MAXREGPATHLENGTH) { + strncat(szRegKey, szObjType, strlen(szObjType) + 1); + } else { + status = DSP_EFAIL; + } + /* Create UUID value to set in registry. */ + UUID_UuidToString(pObjUuid, szUuid, MAXUUIDLEN); + + if ((strlen(szRegKey) + MAXUUIDLEN) < REG_MAXREGPATHLENGTH) + strncat(szRegKey, szUuid, MAXUUIDLEN); + else + status = DSP_EFAIL; + + /* Retrieve paths from the registry based on struct DSP_UUID */ + dwBufSize = REG_MAXREGPATHLENGTH; + } + if (DSP_SUCCEEDED(status)) { + status = REG_GetValue(NULL, szRegKey, szRegKey, (u8 *)szRegData, + &dwBufSize); + } + if (DSP_FAILED(status)) { + status = DSP_EUUID; + GT_0trace(curTrace, GT_6CLASS, "DCD_GetObjectDef: " + "REG_GetValue() failed\n"); + goto func_end; + } + /* Open COFF file. */ + status = COD_Open(pDcdMgr->hCodMgr, szRegData, COD_NOLOAD, &lib); + if (DSP_FAILED(status)) { + status = DSP_EDCDLOADBASE; + GT_0trace(curTrace, GT_6CLASS, "DCD_GetObjectDef: " + "COD_OpenBase() failed\n"); + goto func_end; + } + /* Ensure szUuid + 1 is not greater than sizeof szSectName. */ + DBC_Assert((strlen(szUuid) + 1) < sizeof(szSectName)); + /* Create section name based on node UUID. A period is + * pre-pended to the UUID string to form the section name. + * I.e. ".24BC8D90_BB45_11d4_B756_006008BDB66F" */ + strncpy(szSectName, ".", 2); + strncat(szSectName, szUuid, strlen(szUuid)); + /* Get section information. */ + status = COD_GetSection(lib, szSectName, &ulAddr, &ulLen); + if (DSP_FAILED(status)) { + status = DSP_EDCDGETSECT; + GT_0trace(curTrace, GT_6CLASS, "DCD_GetObjectDef:" + " COD_GetSection() failed\n"); + goto func_end; + } + /* Allocate zeroed buffer. */ + pszCoffBuf = MEM_Calloc(ulLen + 4, MEM_PAGED); +#ifdef _DB_TIOMAP + if (strstr(szRegData, "iva") == NULL) { + /* Locate section by objectID and read its content. */ + status = COD_ReadSection(lib, szSectName, pszCoffBuf, ulLen); + } else { + status = COD_ReadSection(lib, szSectName, pszCoffBuf, ulLen); + GT_0trace(curTrace, GT_4CLASS, + "Skipped Byte swap for IVA !!\n"); + } +#else + status = COD_ReadSection(lib, szSectName, pszCoffBuf, ulLen); +#endif + if (DSP_SUCCEEDED(status)) { + /* Compres DSP buffer to conform to PC format. */ + if (strstr(szRegData, "iva") == NULL) { + CompressBuf(pszCoffBuf, ulLen, DSPWORDSIZE); + } else { + CompressBuf(pszCoffBuf, ulLen, 1); + GT_0trace(curTrace, GT_4CLASS, "Compressing IVA " + "COFF buffer by 1 for IVA !!\n"); + } + /* Parse the content of the COFF buffer. */ + status = GetAttrsFromBuf(pszCoffBuf, ulLen, objType, pObjDef); + if (DSP_FAILED(status)) { + status = DSP_EDCDPARSESECT; + GT_0trace(curTrace, GT_6CLASS, "DCD_GetObjectDef: " + "GetAttrsFromBuf() failed\n"); + } + } else { + status = DSP_EDCDREADSECT; + GT_0trace(curTrace, GT_6CLASS, "DCD_GetObjectDef: " + "COD_ReadSection() failed\n"); + } + /* Free the previously allocated dynamic buffer. */ + MEM_Free(pszCoffBuf); +func_end: + if (lib) + COD_Close(lib); + + if (szUuid) + MEM_Free(szUuid); + return status; +} + +/* + * ======== DCD_GetObjects ======== + */ +DSP_STATUS DCD_GetObjects(IN struct DCD_MANAGER *hDcdMgr, IN char *pszCoffPath, + DCD_REGISTERFXN registerFxn, void *handle) +{ + struct DCD_MANAGER *pDcdMgr = hDcdMgr; /* pointer to DCD manager */ + DSP_STATUS status = DSP_SOK; + char *pszCoffBuf; + char *pszCur; + struct COD_LIBRARYOBJ *lib = NULL; + u32 ulAddr = 0; /* Used by COD_GetSection */ + u32 ulLen = 0; /* Used by COD_GetSection */ + char seps[] = ":, "; + char *pToken = NULL; + struct DSP_UUID dspUuid; + s32 cObjectType; + + DBC_Require(cRefs > 0); + GT_1trace(curTrace, GT_ENTER, + "DCD_GetObjects: hDcdMgr 0x%x\n", hDcdMgr); + if (!IsValidHandle(hDcdMgr)) { + status = DSP_EHANDLE; + GT_0trace(curTrace, GT_6CLASS, + "DCD_GetObjects: invalid DCD manager handle.\n"); + goto func_end; + } + /* Open DSP coff file, don't load symbols. */ + status = COD_Open(pDcdMgr->hCodMgr, pszCoffPath, COD_NOLOAD, &lib); + if (DSP_FAILED(status)) { + status = DSP_EDCDLOADBASE; + GT_0trace(curTrace, GT_6CLASS, + "DCD_AutoRegister: COD_Open() failed\n"); + goto func_cont; + } + /* Get DCD_RESIGER_SECTION section information. */ + status = COD_GetSection(lib, DCD_REGISTER_SECTION, &ulAddr, &ulLen); + if (DSP_FAILED(status) || !(ulLen > 0)) { + status = DSP_EDCDNOAUTOREGISTER; + GT_0trace(curTrace, GT_6CLASS, + "DCD_GetObjects: COD_GetSection() " + "- no auto register section\n"); + goto func_cont; + } + /* Allocate zeroed buffer. */ + pszCoffBuf = MEM_Calloc(ulLen + 4, MEM_PAGED); +#ifdef _DB_TIOMAP + if (strstr(pszCoffPath, "iva") == NULL) { + /* Locate section by objectID and read its content. */ + status = COD_ReadSection(lib, DCD_REGISTER_SECTION, + pszCoffBuf, ulLen); + } else { + GT_0trace(curTrace, GT_4CLASS, "Skipped Byte swap for IVA!!\n"); + status = COD_ReadSection(lib, DCD_REGISTER_SECTION, + pszCoffBuf, ulLen); + } +#else + status = COD_ReadSection(lib, DCD_REGISTER_SECTION, pszCoffBuf, ulLen); +#endif + if (DSP_SUCCEEDED(status)) { + /* Compress DSP buffer to conform to PC format. */ + GT_0trace(curTrace, GT_4CLASS, + "Successfully read section !!\n"); + if (strstr(pszCoffPath, "iva") == NULL) { + CompressBuf(pszCoffBuf, ulLen, DSPWORDSIZE); + } else { + CompressBuf(pszCoffBuf, ulLen, 1); + GT_0trace(curTrace, GT_4CLASS, "Compress COFF buffer " + "with 1 word for IVA !!\n"); + } + /* Read from buffer and register object in buffer. */ + pszCur = pszCoffBuf; + while ((pToken = strsep(&pszCur, seps)) && *pToken != '\0') { + /* Retrieve UUID string. */ + UUID_UuidFromString(pToken, &dspUuid); + /* Retrieve object type */ + pToken = strsep(&pszCur, seps); + /* Retrieve object type */ + cObjectType = Atoi(pToken); + /* + * Apply registerFxn to the found DCD object. + * Possible actions include: + * + * 1) Register found DCD object. + * 2) Unregister found DCD object (when handle == NULL) + * 3) Add overlay node. + */ + GT_1trace(curTrace, GT_4CLASS, "Registering objtype " + "%d \n", cObjectType); + status = registerFxn(&dspUuid, cObjectType, handle); + if (DSP_SUCCEEDED(status)) { + GT_1trace(curTrace, GT_5CLASS, + "DCD_GetObjects: status 0x%x\n", + status); + } else { + GT_0trace(curTrace, GT_6CLASS, + "DCD_GetObjects: " + "registration() failed\n"); + /* if error occurs, break from while loop. */ + break; + } + } + } else { + status = DSP_EDCDREADSECT; + GT_0trace(curTrace, GT_6CLASS, "DCD_GetObjects: " + "COD_ReadSection() failed\n"); + } + /* Free the previously allocated dynamic buffer. */ + MEM_Free(pszCoffBuf); +func_cont: + if (lib) + COD_Close(lib); + +func_end: + return status; +} + +/* + * ======== DCD_GetLibraryName ======== + * Purpose: + * Retrieves the library name for the given UUID. + * + */ +DSP_STATUS DCD_GetLibraryName(IN struct DCD_MANAGER *hDcdMgr, + IN struct DSP_UUID *pUuid, + IN OUT char *pstrLibName, IN OUT u32 *pdwSize, + enum NLDR_PHASE phase, OUT bool *fPhaseSplit) +{ + char szRegKey[REG_MAXREGPATHLENGTH]; + char szUuid[MAXUUIDLEN]; + u32 dwKeyLen; /* Len of REG key. */ + char szObjType[MAX_INT2CHAR_LENGTH]; /* str. rep. of objType. */ + DSP_STATUS status = DSP_SOK; + + DBC_Require(pUuid != NULL); + DBC_Require(pstrLibName != NULL); + DBC_Require(pdwSize != NULL); + DBC_Require(IsValidHandle(hDcdMgr)); + + GT_4trace(curTrace, GT_ENTER, + "DCD_GetLibraryName: hDcdMgr 0x%x, pUuid 0x%x, " + " pstrLibName 0x%x, pdwSize 0x%x\n", hDcdMgr, pUuid, + pstrLibName, pdwSize); + /* + * Pre-determine final key length. It's length of DCD_REGKEY + + * "_\0" + length of szObjType string + terminating NULL. + */ + dwKeyLen = strlen(DCD_REGKEY) + 1 + sizeof(szObjType) + 1; + DBC_Assert(dwKeyLen < REG_MAXREGPATHLENGTH); + /* Create proper REG key; concatenate DCD_REGKEY with objType. */ + strncpy(szRegKey, DCD_REGKEY, strlen(DCD_REGKEY) + 1); + if ((strlen(szRegKey) + strlen("_\0")) < REG_MAXREGPATHLENGTH) + strncat(szRegKey, "_\0", 2); + else + status = DSP_EFAIL; + + switch (phase) { + case NLDR_CREATE: + /* create phase type */ + sprintf(szObjType, "%d", DSP_DCDCREATELIBTYPE); + break; + case NLDR_EXECUTE: + /* execute phase type */ + sprintf(szObjType, "%d", DSP_DCDEXECUTELIBTYPE); + break; + case NLDR_DELETE: + /* delete phase type */ + sprintf(szObjType, "%d", DSP_DCDDELETELIBTYPE); + break; + case NLDR_NOPHASE: + /* known to be a dependent library */ + sprintf(szObjType, "%d", DSP_DCDLIBRARYTYPE); + break; + default: + status = -1; + DBC_Assert(false); + } + if (status == -1) { + status = DSP_EFAIL; + } else { + status = DSP_SOK; + if ((strlen(szRegKey) + strlen(szObjType)) + < REG_MAXREGPATHLENGTH) { + strncat(szRegKey, szObjType, strlen(szObjType) + 1); + } else { + status = DSP_EFAIL; + } + /* Create UUID value to find match in registry. */ + UUID_UuidToString(pUuid, szUuid, MAXUUIDLEN); + if ((strlen(szRegKey) + MAXUUIDLEN) < + REG_MAXREGPATHLENGTH) { + strncat(szRegKey, szUuid, MAXUUIDLEN); + } else { + status = DSP_EFAIL; + } + } + if (DSP_SUCCEEDED(status)) { + /* Retrieve path from the registry based on DSP_UUID */ + status = REG_GetValue(NULL, szRegKey, szRegKey, + (u8 *)pstrLibName, pdwSize); + } + /* If can't find, phases might be registered as generic LIBRARYTYPE */ + if (DSP_FAILED(status) && phase != NLDR_NOPHASE) { + if (fPhaseSplit) + *fPhaseSplit = false; + + strncpy(szRegKey, DCD_REGKEY, strlen(DCD_REGKEY) + 1); + if ((strlen(szRegKey) + strlen("_\0")) < + REG_MAXREGPATHLENGTH) { + strncat(szRegKey, "_\0", 2); + } else { + status = DSP_EFAIL; + } + sprintf(szObjType, "%d", DSP_DCDLIBRARYTYPE); + if ((strlen(szRegKey) + strlen(szObjType)) + < REG_MAXREGPATHLENGTH) { + strncat(szRegKey, szObjType, strlen(szObjType) + 1); + } else { + status = DSP_EFAIL; + } + UUID_UuidToString(pUuid, szUuid, MAXUUIDLEN); + if ((strlen(szRegKey) + MAXUUIDLEN) < REG_MAXREGPATHLENGTH) + strncat(szRegKey, szUuid, MAXUUIDLEN); + else + status = DSP_EFAIL; + + status = REG_GetValue(NULL, szRegKey, szRegKey, + (u8 *)pstrLibName, pdwSize); + } + + return status; +} + +/* + * ======== DCD_Init ======== + * Purpose: + * Initialize the DCD module. + */ +bool DCD_Init(void) +{ + bool fInitMEM; + bool fInitREG; + bool fInitCOD; + bool fInit = true; + + DBC_Require(cRefs >= 0); + + GT_1trace(curTrace, GT_ENTER, "DCD_Init: (on enter) cRefs = 0x%x\n", + cRefs); + + if (cRefs == 0) { + + /* Initialize required modules. */ + fInitMEM = MEM_Init(); + fInitCOD = COD_Init(); + fInitREG = REG_Init(); + if (!fInitMEM || !fInitCOD || !fInitREG) { + fInit = false; + GT_0trace(curTrace, GT_6CLASS, "DCD_Init failed\n"); + /* Exit initialized modules. */ + if (fInitMEM) + MEM_Exit(); + + if (fInitCOD) + COD_Exit(); + + if (fInitREG) + REG_Exit(); + + } + } + + if (fInit) + cRefs++; + + + GT_1trace(curTrace, GT_5CLASS, "DCD_Init: (on exit) cRefs = 0x%x\n", + cRefs); + + DBC_Ensure((fInit && (cRefs > 0)) || (!fInit && (cRefs == 0))); + + return fInit; +} + +/* + * ======== DCD_RegisterObject ======== + * Purpose: + * Registers a node or a processor with the DCD. + * If pszPathName == NULL, unregister the specified DCD object. + */ +DSP_STATUS DCD_RegisterObject(IN struct DSP_UUID *pUuid, + IN enum DSP_DCDOBJTYPE objType, + IN char *pszPathName) +{ + DSP_STATUS status = DSP_SOK; + char szRegKey[REG_MAXREGPATHLENGTH]; + char szUuid[MAXUUIDLEN + 1]; + u32 dwPathSize = 0; + u32 dwKeyLen; /* Len of REG key. */ + char szObjType[MAX_INT2CHAR_LENGTH]; /* str. rep. of objType. */ + + DBC_Require(cRefs > 0); + DBC_Require(pUuid != NULL); + DBC_Require((objType == DSP_DCDNODETYPE) || + (objType == DSP_DCDPROCESSORTYPE) || + (objType == DSP_DCDLIBRARYTYPE) || + (objType == DSP_DCDCREATELIBTYPE) || + (objType == DSP_DCDEXECUTELIBTYPE) || + (objType == DSP_DCDDELETELIBTYPE)); + + GT_3trace(curTrace, GT_ENTER, "DCD_RegisterObject: object UUID 0x%x, " + "objType %d, szPathName %s\n", pUuid, objType, pszPathName); + /* + * Pre-determine final key length. It's length of DCD_REGKEY + + * "_\0" + length of szObjType string + terminating NULL. + */ + dwKeyLen = strlen(DCD_REGKEY) + 1 + sizeof(szObjType) + 1; + DBC_Assert(dwKeyLen < REG_MAXREGPATHLENGTH); + /* Create proper REG key; concatenate DCD_REGKEY with objType. */ + strncpy(szRegKey, DCD_REGKEY, strlen(DCD_REGKEY) + 1); + if ((strlen(szRegKey) + strlen("_\0")) < REG_MAXREGPATHLENGTH) + strncat(szRegKey, "_\0", 2); + else + status = DSP_EFAIL; + + status = snprintf(szObjType, MAX_INT2CHAR_LENGTH, "%d", objType); + if (status == -1) { + status = DSP_EFAIL; + } else { + status = DSP_SOK; + if ((strlen(szRegKey) + strlen(szObjType)) < + REG_MAXREGPATHLENGTH) { + strncat(szRegKey, szObjType, strlen(szObjType) + 1); + } else { + status = DSP_EFAIL; + } + /* Create UUID value to set in registry. */ + UUID_UuidToString(pUuid, szUuid, MAXUUIDLEN); + if ((strlen(szRegKey) + MAXUUIDLEN) < REG_MAXREGPATHLENGTH) + strncat(szRegKey, szUuid, MAXUUIDLEN); + else + status = DSP_EFAIL; + + } + + if (DSP_SUCCEEDED(status)) { + /* + * If pszPathName != NULL, perform registration, otherwise, + * perform unregistration. + */ + if (pszPathName) { + /* Add new reg value (UUID+objType) with COFF path + * info. */ + dwPathSize = strlen(pszPathName) + 1; + status = REG_SetValue(NULL, szRegKey, szRegKey, REG_SZ, + (u8 *)pszPathName, dwPathSize); + GT_3trace(curTrace, GT_6CLASS, + "REG_SetValue REG_SZ=%d, " + "(u8 *)pszPathName=%s, dwPathSize=%d\n", + REG_SZ, pszPathName, dwPathSize); + if (DSP_FAILED(status)) { + status = DSP_EFAIL; + GT_0trace(curTrace, GT_6CLASS, + "DCD_RegisterObject: REG_SetValue failed!\n"); + } + } else { + /* Deregister an existing object. */ + status = REG_DeleteValue(NULL, szRegKey, szRegKey); + if (DSP_FAILED(status)) { + status = DSP_EFAIL; + GT_0trace(curTrace, GT_6CLASS, + "DCD_UnregisterObject: " + "REG_DeleteValue failed!\n"); + } + } + } + + if (DSP_SUCCEEDED(status)) { + /* + * Because the node database has been updated through a + * successful object registration/de-registration operation, + * we need to reset the object enumeration counter to allow + * current enumerations to reflect this update in the node + * database. + */ + + cEnumRefs = 0; + } + + return status; +} + +/* + * ======== DCD_UnregisterObject ======== + * Call DCD_Register object with pszPathName set to NULL to + * perform actual object de-registration. + */ +DSP_STATUS DCD_UnregisterObject(IN struct DSP_UUID *pUuid, + IN enum DSP_DCDOBJTYPE objType) +{ + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(pUuid != NULL); + DBC_Require((objType == DSP_DCDNODETYPE) || + (objType == DSP_DCDPROCESSORTYPE) || + (objType == DSP_DCDLIBRARYTYPE) || + (objType == DSP_DCDCREATELIBTYPE) || + (objType == DSP_DCDEXECUTELIBTYPE) || + (objType == DSP_DCDDELETELIBTYPE)); + + GT_2trace(curTrace, GT_ENTER, + "DCD_UnregisterObject: object UUID 0x%x, " + "objType %d\n", pUuid, objType); + + /* + * When DCD_RegisterObject is called with NULL as pathname, + * it indicates an unregister object operation. + */ + status = DCD_RegisterObject(pUuid, objType, NULL); + + return status; +} + +/* + ********************************************************************** + * DCD Helper Functions + ********************************************************************** + */ + +/* + * ======== Atoi ======== + * Purpose: + * This function converts strings in decimal or hex format to integers. + */ +static s32 Atoi(char *pszBuf) +{ + s32 result = 0; + char *pch = pszBuf; + char c; + char first; + s32 base = 10; + s32 len; + + while (isspace(*pch)) + pch++; + + first = *pch; + if (first == '-' || first == '+') { + pch++; + } else { + /* Determine if base 10 or base 16 */ + len = strlen(pch); + if (len > 1) { + c = pch[1]; + if ((*pch == '0' && (c == 'x' || c == 'X'))) { + base = 16; + pch += 2; + } + c = pch[len - 1]; + if (c == 'h' || c == 'H') + base = 16; + + } + } + + while (isdigit(c = *pch) || ((base == 16) && isxdigit(c))) { + result *= base; + if ('A' <= c && c <= 'F') { + c = c - 'A' + 10; + } else { + if ('a' <= c && c <= 'f') + c = c - 'a' + 10; + else + c -= '0'; + + } + result += c; + ++pch; + } + + return result; +} + +/* + * ======== GetAttrsFromBuf ======== + * Purpose: + * Parse the content of a buffer filled with DSP-side data and + * retrieve an object's attributes from it. IMPORTANT: Assume the + * buffer has been converted from DSP format to GPP format. + */ +static DSP_STATUS GetAttrsFromBuf(char *pszBuf, u32 ulBufSize, + enum DSP_DCDOBJTYPE objType, + struct DCD_GENERICOBJ *pGenObj) +{ + DSP_STATUS status = DSP_SOK; + char seps[] = ", "; + char *pszCur; + char *token; + s32 cLen = 0; + u32 i = 0; +#ifdef _DB_TIOMAP + s32 iEntry; +#endif + + DBC_Require(pszBuf != NULL); + DBC_Require(ulBufSize != 0); + DBC_Require((objType == DSP_DCDNODETYPE) + || (objType == DSP_DCDPROCESSORTYPE)); + DBC_Require(pGenObj != NULL); + + + switch (objType) { + case DSP_DCDNODETYPE: + /* + * Parse COFF sect buffer to retrieve individual tokens used + * to fill in object attrs. + */ + pszCur = pszBuf; + token = strsep(&pszCur, seps); + + /* u32 cbStruct */ + pGenObj->objData.nodeObj.ndbProps.cbStruct = + (u32) Atoi(token); + token = strsep(&pszCur, seps); + + /* DSP_UUID uiNodeID */ + UUID_UuidFromString(token, + &pGenObj->objData.nodeObj.ndbProps.uiNodeID); + token = strsep(&pszCur, seps); + + /* acName */ + DBC_Require(token); + cLen = strlen(token); + if (cLen > DSP_MAXNAMELEN - 1) + cLen = DSP_MAXNAMELEN - 1; + + strncpy(pGenObj->objData.nodeObj.ndbProps.acName, + token, cLen); + pGenObj->objData.nodeObj.ndbProps.acName[cLen] = '\0'; + token = strsep(&pszCur, seps); + /* u32 uNodeType */ + pGenObj->objData.nodeObj.ndbProps.uNodeType = Atoi(token); + token = strsep(&pszCur, seps); + /* u32 bCacheOnGPP */ + pGenObj->objData.nodeObj.ndbProps.bCacheOnGPP = Atoi(token); + token = strsep(&pszCur, seps); + /* DSP_RESOURCEREQMTS dspResourceReqmts */ + pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts.cbStruct = + (u32) Atoi(token); + token = strsep(&pszCur, seps); + + pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts. + uStaticDataSize = Atoi(token); + token = strsep(&pszCur, seps); + pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts. + uGlobalDataSize = Atoi(token); + token = strsep(&pszCur, seps); + pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts. + uProgramMemSize = Atoi(token); + token = strsep(&pszCur, seps); + pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts. + uWCExecutionTime = Atoi(token); + token = strsep(&pszCur, seps); + pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts. + uWCPeriod = Atoi(token); + token = strsep(&pszCur, seps); + + pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts. + uWCDeadline = Atoi(token); + token = strsep(&pszCur, seps); + + pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts. + uAvgExectionTime = Atoi(token); + token = strsep(&pszCur, seps); + + pGenObj->objData.nodeObj.ndbProps.dspResourceReqmts. + uMinimumPeriod = Atoi(token); + token = strsep(&pszCur, seps); + + /* s32 iPriority */ + pGenObj->objData.nodeObj.ndbProps.iPriority = Atoi(token); + token = strsep(&pszCur, seps); + + /* u32 uStackSize */ + pGenObj->objData.nodeObj.ndbProps.uStackSize = Atoi(token); + token = strsep(&pszCur, seps); + + /* u32 uSysStackSize */ + pGenObj->objData.nodeObj.ndbProps.uSysStackSize = Atoi(token); + token = strsep(&pszCur, seps); + + /* u32 uStackSeg */ + pGenObj->objData.nodeObj.ndbProps.uStackSeg = Atoi(token); + token = strsep(&pszCur, seps); + + /* u32 uMessageDepth */ + pGenObj->objData.nodeObj.ndbProps.uMessageDepth = Atoi(token); + token = strsep(&pszCur, seps); + + /* u32 uNumInputStreams */ + pGenObj->objData.nodeObj.ndbProps.uNumInputStreams = + Atoi(token); + token = strsep(&pszCur, seps); + + /* u32 uNumOutputStreams */ + pGenObj->objData.nodeObj.ndbProps.uNumOutputStreams = + Atoi(token); + token = strsep(&pszCur, seps); + + /* u32 uTimeout */ + pGenObj->objData.nodeObj.ndbProps.uTimeout = + Atoi(token); + token = strsep(&pszCur, seps); + + /* char * pstrCreatePhaseFxn */ + DBC_Require(token); + cLen = strlen(token); + pGenObj->objData.nodeObj.pstrCreatePhaseFxn = + MEM_Calloc(cLen + 1, MEM_PAGED); + strncpy(pGenObj->objData.nodeObj.pstrCreatePhaseFxn, + token, cLen); + pGenObj->objData.nodeObj.pstrCreatePhaseFxn[cLen] = '\0'; + token = strsep(&pszCur, seps); + + /* char * pstrExecutePhaseFxn */ + DBC_Require(token); + cLen = strlen(token); + pGenObj->objData.nodeObj.pstrExecutePhaseFxn = + MEM_Calloc(cLen + 1, MEM_PAGED); + strncpy(pGenObj->objData.nodeObj.pstrExecutePhaseFxn, + token, cLen); + pGenObj->objData.nodeObj.pstrExecutePhaseFxn[cLen] = '\0'; + token = strsep(&pszCur, seps); + + /* char * pstrDeletePhaseFxn */ + DBC_Require(token); + cLen = strlen(token); + pGenObj->objData.nodeObj.pstrDeletePhaseFxn = + MEM_Calloc(cLen + 1, MEM_PAGED); + strncpy(pGenObj->objData.nodeObj.pstrDeletePhaseFxn, + token, cLen); + pGenObj->objData.nodeObj.pstrDeletePhaseFxn[cLen] = '\0'; + token = strsep(&pszCur, seps); + + /* Segment id for message buffers */ + pGenObj->objData.nodeObj.uMsgSegid = Atoi(token); + token = strsep(&pszCur, seps); + + /* Message notification type */ + pGenObj->objData.nodeObj.uMsgNotifyType = Atoi(token); + token = strsep(&pszCur, seps); + + /* char * pstrIAlgName */ + if (token) { + cLen = strlen(token); + pGenObj->objData.nodeObj.pstrIAlgName = + MEM_Calloc(cLen + 1, MEM_PAGED); + strncpy(pGenObj->objData.nodeObj.pstrIAlgName, + token, cLen); + pGenObj->objData.nodeObj.pstrIAlgName[cLen] = '\0'; + token = strsep(&pszCur, seps); + } + + /* Load type (static, dynamic, or overlay) */ + if (token) { + pGenObj->objData.nodeObj.usLoadType = Atoi(token); + token = strsep(&pszCur, seps); + } + + /* Dynamic load data requirements */ + if (token) { + pGenObj->objData.nodeObj.ulDataMemSegMask = Atoi(token); + token = strsep(&pszCur, seps); + } + + /* Dynamic load code requirements */ + if (token) { + pGenObj->objData.nodeObj.ulCodeMemSegMask = Atoi(token); + token = strsep(&pszCur, seps); + } + + /* Extract node profiles into node properties */ + if (token) { + + pGenObj->objData.nodeObj.ndbProps.uCountProfiles = + Atoi(token); + for (i = 0; i < pGenObj->objData.nodeObj.ndbProps. + uCountProfiles; i++) { + token = strsep(&pszCur, seps); + if (token) { + /* Heap Size for the node */ + pGenObj->objData.nodeObj.ndbProps. + aProfiles[i].ulHeapSize = + Atoi(token); + } + } + } + token = strsep(&pszCur, seps); + if (token) { + pGenObj->objData.nodeObj.ndbProps.uStackSegName = + (u32)(token); + } + + break; + + case DSP_DCDPROCESSORTYPE: + /* + * Parse COFF sect buffer to retrieve individual tokens used + * to fill in object attrs. + */ + pszCur = pszBuf; + token = strsep(&pszCur, seps); + + pGenObj->objData.procObj.cbStruct = Atoi(token); + token = strsep(&pszCur, seps); + + pGenObj->objData.procObj.uProcessorFamily = Atoi(token); + token = strsep(&pszCur, seps); + + pGenObj->objData.procObj.uProcessorType = Atoi(token); + token = strsep(&pszCur, seps); + + pGenObj->objData.procObj.uClockRate = Atoi(token); + token = strsep(&pszCur, seps); + + pGenObj->objData.procObj.ulInternalMemSize = Atoi(token); + token = strsep(&pszCur, seps); + + pGenObj->objData.procObj.ulExternalMemSize = Atoi(token); + token = strsep(&pszCur, seps); + + pGenObj->objData.procObj.uProcessorID = Atoi(token); + token = strsep(&pszCur, seps); + + pGenObj->objData.procObj.tyRunningRTOS = Atoi(token); + token = strsep(&pszCur, seps); + + pGenObj->objData.procObj.nNodeMinPriority = Atoi(token); + token = strsep(&pszCur, seps); + + pGenObj->objData.procObj.nNodeMaxPriority = Atoi(token); + +#ifdef _DB_TIOMAP + /* Proc object may contain additional(extended) attributes. */ + /* attr must match proc.hxx */ + for (iEntry = 0; iEntry < 7; iEntry++) { + token = strsep(&pszCur, seps); + pGenObj->objData.extProcObj.tyTlb[iEntry].ulGppPhys = + Atoi(token); + + token = strsep(&pszCur, seps); + pGenObj->objData.extProcObj.tyTlb[iEntry].ulDspVirt = + Atoi(token); + } +#endif + + break; + + default: + status = DSP_EFAIL; + break; + } + + return status; +} + +/* + * ======== CompressBuffer ======== + * Purpose: + * Compress the DSP buffer, if necessary, to conform to PC format. + */ +static void CompressBuf(char *pszBuf, u32 ulBufSize, s32 cCharSize) +{ + char *p; + char ch; + char *q; + + p = pszBuf; + if (p == NULL) + return; + + for (q = pszBuf; q < (pszBuf + ulBufSize);) { + + ch = DspChar2GppChar(q, cCharSize); + if (ch == '\\') { + q += cCharSize; + ch = DspChar2GppChar(q, cCharSize); + switch (ch) { + case 't': + *p = '\t'; + break; + + case 'n': + *p = '\n'; + break; + + case 'r': + *p = '\r'; + break; + + case '0': + *p = '\0'; + break; + + default: + *p = ch; + break; + } + } else { + *p = ch; + } + p++; + q += cCharSize; + } + + /* NULL out remainder of buffer. */ + while (p < q) + *p++ = '\0'; + +} + +/* + * ======== DspChar2GppChar ======== + * Purpose: + * Convert DSP char to host GPP char in a portable manner + */ +static char DspChar2GppChar(char *pWord, s32 cDspCharSize) +{ + char ch = '\0'; + char *chSrc; + s32 i; + + for (chSrc = pWord, i = cDspCharSize; i > 0; i--) + ch |= *chSrc++; + + return ch; +} + +/* + * ======== GetDepLibInfo ======== + */ +static DSP_STATUS GetDepLibInfo(IN struct DCD_MANAGER *hDcdMgr, + IN struct DSP_UUID *pUuid, + IN OUT u16 *pNumLibs, + OPTIONAL OUT u16 *pNumPersLibs, + OPTIONAL OUT struct DSP_UUID *pDepLibUuids, + OPTIONAL OUT bool *pPersistentDepLibs, + enum NLDR_PHASE phase) +{ + struct DCD_MANAGER *pDcdMgr = hDcdMgr; /* pointer to DCD manager */ + char *pszCoffBuf = NULL; + char *pszCur; + char *pszFileName = NULL; + struct COD_LIBRARYOBJ *lib = NULL; + u32 ulAddr = 0; /* Used by COD_GetSection */ + u32 ulLen = 0; /* Used by COD_GetSection */ + u32 dwDataSize = COD_MAXPATHLENGTH; + char seps[] = ", "; + char *pToken = NULL; + bool fGetUuids = (pDepLibUuids != NULL); + u16 nDepLibs = 0; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + + DBC_Require(IsValidHandle(hDcdMgr)); + DBC_Require(pNumLibs != NULL); + DBC_Require(pUuid != NULL); + + GT_1trace(curTrace, GT_ENTER, "DCD_GetNumDepLibs: hDcdMgr 0x%x\n", + hDcdMgr); + + /* Initialize to 0 dependent libraries, if only counting number of + * dependent libraries */ + if (!fGetUuids) { + *pNumLibs = 0; + *pNumPersLibs = 0; + } + + /* Allocate a buffer for file name */ + pszFileName = MEM_Calloc(dwDataSize, MEM_PAGED); + if (pszFileName == NULL) { + status = DSP_EMEMORY; + } else { + /* Get the name of the library */ + status = DCD_GetLibraryName(hDcdMgr, pUuid, pszFileName, + &dwDataSize, phase, NULL); + } + /* Open the library */ + if (DSP_SUCCEEDED(status)) { + status = COD_Open(pDcdMgr->hCodMgr, pszFileName, + COD_NOLOAD, &lib); + } + if (DSP_SUCCEEDED(status)) { + /* Get dependent library section information. */ + status = COD_GetSection(lib, DEPLIBSECT, &ulAddr, &ulLen); + + if (DSP_FAILED(status)) { + /* Ok, no dependent libraries */ + ulLen = 0; + status = DSP_SNODEPENDENTLIBS; + } + } + + if (DSP_FAILED(status) || !(ulLen > 0)) + goto func_cont; + + /* Allocate zeroed buffer. */ + pszCoffBuf = MEM_Calloc(ulLen, MEM_PAGED); + if (pszCoffBuf == NULL) + status = DSP_EMEMORY; + + /* Read section contents. */ + status = COD_ReadSection(lib, DEPLIBSECT, pszCoffBuf, ulLen); + if (DSP_FAILED(status)) + goto func_cont; + + /* Compress and format DSP buffer to conform to PC format. */ + CompressBuf(pszCoffBuf, ulLen, DSPWORDSIZE); + /* Read from buffer */ + pszCur = pszCoffBuf; + while ((pToken = strsep(&pszCur, seps)) && *pToken != '\0') { + if (fGetUuids) { + if (nDepLibs >= *pNumLibs) { + /* Gone beyond the limit */ + break; + } else { + /* Retrieve UUID string. */ + UUID_UuidFromString(pToken, + &(pDepLibUuids[nDepLibs])); + /* Is this library persistent? */ + pToken = strsep(&pszCur, seps); + pPersistentDepLibs[nDepLibs] = Atoi(pToken); + nDepLibs++; + } + } else { + /* Advanc to next token */ + pToken = strsep(&pszCur, seps); + if (Atoi(pToken)) + (*pNumPersLibs)++; + + /* Just counting number of dependent libraries */ + (*pNumLibs)++; + } + } +func_cont: + if (lib) + COD_Close(lib); + + /* Free previously allocated dynamic buffers. */ + if (pszFileName) + MEM_Free(pszFileName); + + if (pszCoffBuf) + MEM_Free(pszCoffBuf); + + return status; +} + diff --git a/drivers/dsp/bridge/rmgr/disp.c b/drivers/dsp/bridge/rmgr/disp.c new file mode 100644 index 0000000..3fbbf01 --- /dev/null +++ b/drivers/dsp/bridge/rmgr/disp.c @@ -0,0 +1,916 @@ +/* + * disp.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== disp.c ======== + * + * Description: + * Node Dispatcher interface. Communicates with Resource Manager Server + * (RMS) on DSP. Access to RMS is synchronized in NODE. + * + * Public Functions: + * DISP_Create + * DISP_Delete + * DISP_Exit + * DISP_Init + * DISP_NodeChangePriority + * DISP_NodeCreate + * DISP_NodeDelete + * DISP_NodePause + * DISP_NodeRun + * + *! Revision History: + *! ================= + *! 18-Feb-2003 vp Code review updates + *! 18-Oct-2002 vp Ported to Linux platform + *! 16-May-2002 jeh Added DISP_DoCinit(). + *! 24-Apr-2002 jeh Added DISP_MemWrite(). + *! 13-Feb-2002 jeh Pass system stack size to RMS. + *! 16-Jan-2002 ag Added bufsize param to _ChnlAddIOReq() fxn + *! 10-May-2001 jeh Code Review cleanup. + *! 26-Sep-2000 jeh Fixed status values in SendMessage(). + *! 19-Jun-2000 jeh Created. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include + +/* ----------------------------------- Link Driver */ +#include + +/* ----------------------------------- Platform Manager */ +#include +#include + +/* ----------------------------------- Resource Manager */ +#include +#include +#include + +/* ----------------------------------- This */ +#include + +#define DISP_SIGNATURE 0x50534944 /* "PSID" */ + +/* Size of a reply from RMS */ +#define REPLYSIZE (3 * sizeof(RMS_WORD)) + +/* Reserved channel offsets for communication with RMS */ +#define CHNLTORMSOFFSET 0 +#define CHNLFROMRMSOFFSET 1 + +#define CHNLIOREQS 1 + +#define SwapWord(x) (((u32)(x) >> 16) | ((u32)(x) << 16)) + +/* + * ======== DISP_OBJECT ======== + */ +struct DISP_OBJECT { + u32 dwSignature; /* Used for object validation */ + struct DEV_OBJECT *hDevObject; /* Device for this processor */ + struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD */ + struct CHNL_MGR *hChnlMgr; /* Channel manager */ + struct CHNL_OBJECT *hChnlToDsp; /* Channel for commands to RMS */ + struct CHNL_OBJECT *hChnlFromDsp; /* Channel for replies from RMS */ + u8 *pBuf; /* Buffer for commands, replies */ + u32 ulBufsize; /* pBuf size in bytes */ + u32 ulBufsizeRMS; /* pBuf size in RMS words */ + u32 uCharSize; /* Size of DSP character */ + u32 uWordSize; /* Size of DSP word */ + u32 uDataMauSize; /* Size of DSP Data MAU */ +}; + +static u32 cRefs; + +/* Debug msgs: */ +#if GT_TRACE +static struct GT_Mask DISP_DebugMask = { NULL, NULL }; +#endif + +static void DeleteDisp(struct DISP_OBJECT *hDisp); +static DSP_STATUS FillStreamDef(RMS_WORD *pdwBuf, u32 *ptotal, u32 offset, + struct NODE_STRMDEF strmDef, u32 max, + u32 uCharsInRMSWord); +static DSP_STATUS SendMessage(struct DISP_OBJECT *hDisp, u32 dwTimeout, + u32 ulBytes, OUT u32 *pdwArg); + +/* + * ======== DISP_Create ======== + * Create a NODE Dispatcher object. + */ +DSP_STATUS DISP_Create(OUT struct DISP_OBJECT **phDispObject, + struct DEV_OBJECT *hDevObject, + IN CONST struct DISP_ATTRS *pDispAttrs) +{ + struct DISP_OBJECT *pDisp; + struct WMD_DRV_INTERFACE *pIntfFxns; + u32 ulChnlId; + struct CHNL_ATTRS chnlAttrs; + DSP_STATUS status = DSP_SOK; + u32 devType; + + DBC_Require(cRefs > 0); + DBC_Require(phDispObject != NULL); + DBC_Require(pDispAttrs != NULL); + DBC_Require(hDevObject != NULL); + + GT_3trace(DISP_DebugMask, GT_ENTER, "DISP_Create: phDispObject: 0x%x\t" + "hDevObject: 0x%x\tpDispAttrs: 0x%x\n", phDispObject, + hDevObject, pDispAttrs); + + *phDispObject = NULL; + + /* Allocate Node Dispatcher object */ + MEM_AllocObject(pDisp, struct DISP_OBJECT, DISP_SIGNATURE); + if (pDisp == NULL) { + status = DSP_EMEMORY; + GT_0trace(DISP_DebugMask, GT_6CLASS, + "DISP_Create: MEM_AllocObject() failed!\n"); + } else { + pDisp->hDevObject = hDevObject; + } + + /* Get Channel manager and WMD function interface */ + if (DSP_SUCCEEDED(status)) { + status = DEV_GetChnlMgr(hDevObject, &(pDisp->hChnlMgr)); + if (DSP_SUCCEEDED(status)) { + (void) DEV_GetIntfFxns(hDevObject, &pIntfFxns); + pDisp->pIntfFxns = pIntfFxns; + } else { + GT_1trace(DISP_DebugMask, GT_6CLASS, + "DISP_Create: Failed to get " + "channel manager! status = 0x%x\n", status); + } + } + + /* check device type and decide if streams or messag'ing is used for + * RMS/EDS */ + if (DSP_FAILED(status)) + goto func_cont; + + status = DEV_GetDevType(hDevObject, &devType); + GT_1trace(DISP_DebugMask, GT_6CLASS, "DISP_Create: Creating DISP for " + "device = 0x%x\n", devType); + if (DSP_FAILED(status)) + goto func_cont; + + if (devType != DSP_UNIT) { + GT_0trace(DISP_DebugMask, GT_6CLASS, + "DISP_Create: Unkown device " + "type in Device object !! \n"); + status = DSP_EFAIL; + goto func_cont; + } + if (DSP_SUCCEEDED(status)) { + pDisp->uCharSize = DSPWORDSIZE; + pDisp->uWordSize = DSPWORDSIZE; + pDisp->uDataMauSize = DSPWORDSIZE; + /* Open channels for communicating with the RMS */ + chnlAttrs.uIOReqs = CHNLIOREQS; + chnlAttrs.hEvent = NULL; + ulChnlId = pDispAttrs->ulChnlOffset + CHNLTORMSOFFSET; + status = (*pIntfFxns->pfnChnlOpen)(&(pDisp->hChnlToDsp), + pDisp->hChnlMgr, CHNL_MODETODSP, ulChnlId, &chnlAttrs); + if (DSP_FAILED(status)) { + GT_2trace(DISP_DebugMask, GT_6CLASS, + "DISP_Create: Channel to RMS " + "open failed, chnl id = %d, status = 0x%x\n", + ulChnlId, status); + } + } + if (DSP_SUCCEEDED(status)) { + ulChnlId = pDispAttrs->ulChnlOffset + CHNLFROMRMSOFFSET; + status = (*pIntfFxns->pfnChnlOpen)(&(pDisp->hChnlFromDsp), + pDisp->hChnlMgr, CHNL_MODEFROMDSP, ulChnlId, + &chnlAttrs); + if (DSP_FAILED(status)) { + GT_2trace(DISP_DebugMask, GT_6CLASS, + "DISP_Create: Channel from RMS " + "open failed, chnl id = %d, status = 0x%x\n", + ulChnlId, status); + } + } + if (DSP_SUCCEEDED(status)) { + /* Allocate buffer for commands, replies */ + pDisp->ulBufsize = pDispAttrs->ulChnlBufSize; + pDisp->ulBufsizeRMS = RMS_COMMANDBUFSIZE; + pDisp->pBuf = MEM_Calloc(pDisp->ulBufsize, MEM_PAGED); + if (pDisp->pBuf == NULL) { + status = DSP_EMEMORY; + GT_0trace(DISP_DebugMask, GT_6CLASS, + "DISP_Create: Failed " + "to allocate channel buffer!\n"); + } + } +func_cont: + if (DSP_SUCCEEDED(status)) + *phDispObject = pDisp; + else + DeleteDisp(pDisp); + + DBC_Ensure(((DSP_FAILED(status)) && ((*phDispObject == NULL))) || + ((DSP_SUCCEEDED(status)) && + (MEM_IsValidHandle((*phDispObject), DISP_SIGNATURE)))); + return status; +} + +/* + * ======== DISP_Delete ======== + * Delete the NODE Dispatcher. + */ +void DISP_Delete(struct DISP_OBJECT *hDisp) +{ + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(hDisp, DISP_SIGNATURE)); + + GT_1trace(DISP_DebugMask, GT_ENTER, + "DISP_Delete: hDisp: 0x%x\n", hDisp); + + DeleteDisp(hDisp); + + DBC_Ensure(!MEM_IsValidHandle(hDisp, DISP_SIGNATURE)); +} + +/* + * ======== DISP_Exit ======== + * Discontinue usage of DISP module. + */ +void DISP_Exit(void) +{ + DBC_Require(cRefs > 0); + + cRefs--; + + GT_1trace(DISP_DebugMask, GT_5CLASS, + "Entered DISP_Exit, ref count: 0x%x\n", cRefs); + + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== DISP_Init ======== + * Initialize the DISP module. + */ +bool DISP_Init(void) +{ + bool fRetVal = true; + + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { + DBC_Assert(!DISP_DebugMask.flags); + GT_create(&DISP_DebugMask, "DI"); /* "DI" for DIspatcher */ + } + + if (fRetVal) + cRefs++; + + GT_1trace(DISP_DebugMask, GT_5CLASS, + "DISP_Init(), ref count: 0x%x\n", cRefs); + + DBC_Ensure((fRetVal && (cRefs > 0)) || (!fRetVal && (cRefs >= 0))); + return fRetVal; +} + +/* + * ======== DISP_NodeChangePriority ======== + * Change the priority of a node currently running on the target. + */ +DSP_STATUS DISP_NodeChangePriority(struct DISP_OBJECT *hDisp, + struct NODE_OBJECT *hNode, + u32 ulRMSFxn, NODE_ENV nodeEnv, + s32 nPriority) +{ + u32 dwArg; + struct RMS_Command *pCommand; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(hDisp, DISP_SIGNATURE)); + DBC_Require(hNode != NULL); + + GT_5trace(DISP_DebugMask, GT_ENTER, "DISP_NodeChangePriority: hDisp: " + "0x%x\thNode: 0x%x\tulRMSFxn: 0x%x\tnodeEnv: 0x%x\tnPriority\n", + hDisp, hNode, ulRMSFxn, nodeEnv, nPriority); + + /* Send message to RMS to change priority */ + pCommand = (struct RMS_Command *)(hDisp->pBuf); + pCommand->fxn = (RMS_WORD)(ulRMSFxn); + pCommand->arg1 = (RMS_WORD)nodeEnv; + pCommand->arg2 = nPriority; + status = SendMessage(hDisp, NODE_GetTimeout(hNode), + sizeof(struct RMS_Command), &dwArg); + if (DSP_FAILED(status)) { + GT_1trace(DISP_DebugMask, GT_6CLASS, + "DISP_NodeChangePriority failed! " + "status = 0x%x\n", status); + } + return status; +} + +/* + * ======== DISP_NodeCreate ======== + * Create a node on the DSP by remotely calling the node's create function. + */ +DSP_STATUS DISP_NodeCreate(struct DISP_OBJECT *hDisp, struct NODE_OBJECT *hNode, + u32 ulRMSFxn, u32 ulCreateFxn, + IN CONST struct NODE_CREATEARGS *pArgs, + OUT NODE_ENV *pNodeEnv) +{ + struct NODE_MSGARGS msgArgs; + struct NODE_TASKARGS taskArgs; + struct RMS_Command *pCommand; + struct RMS_MsgArgs *pMsgArgs; + struct RMS_MoreTaskArgs *pMoreTaskArgs; + enum NODE_TYPE nodeType; + u32 dwLength; + RMS_WORD *pdwBuf = NULL; + u32 ulBytes; + u32 i; + u32 total; + u32 uCharsInRMSWord; + s32 taskArgsOffset; + s32 sioInDefOffset; + s32 sioOutDefOffset; + s32 sioDefsOffset; + s32 argsOffset = -1; + s32 offset; + struct NODE_STRMDEF strmDef; + u32 max; + DSP_STATUS status = DSP_SOK; + struct DSP_NODEINFO nodeInfo; + u32 devType; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(hDisp, DISP_SIGNATURE)); + DBC_Require(hNode != NULL); + DBC_Require(NODE_GetType(hNode) != NODE_DEVICE); + DBC_Require(pNodeEnv != NULL); + + GT_6trace(DISP_DebugMask, GT_ENTER, + "DISP_NodeCreate: hDisp: 0x%x\thNode:" + " 0x%x\tulRMSFxn: 0x%x\tulCreateFxn: 0x%x\tpArgs: 0x%x\tpNodeEnv:" + " 0x%x\n", hDisp, hNode, ulRMSFxn, ulCreateFxn, pArgs, pNodeEnv); + + status = DEV_GetDevType(hDisp->hDevObject, &devType); + + GT_1trace(DISP_DebugMask, GT_6CLASS, "DISP_Create: Creating DISP " + "for device = 0x%x\n", devType); + + if (DSP_FAILED(status)) + goto func_end; + + if (devType != DSP_UNIT) { + GT_1trace(DISP_DebugMask, GT_7CLASS, + "DISP_NodeCreate unknown device " + "type = 0x%x\n", devType); + goto func_end; + } + DBC_Require(pArgs != NULL); + nodeType = NODE_GetType(hNode); + msgArgs = pArgs->asa.msgArgs; + max = hDisp->ulBufsizeRMS; /*Max # of RMS words that can be sent */ + DBC_Assert(max == RMS_COMMANDBUFSIZE); + uCharsInRMSWord = sizeof(RMS_WORD) / hDisp->uCharSize; + /* Number of RMS words needed to hold arg data */ + dwLength = (msgArgs.uArgLength + uCharsInRMSWord - 1) / uCharsInRMSWord; + /* Make sure msg args and command fit in buffer */ + total = sizeof(struct RMS_Command) / sizeof(RMS_WORD) + + sizeof(struct RMS_MsgArgs) + / sizeof(RMS_WORD) - 1 + dwLength; + if (total >= max) { + status = DSP_EFAIL; + GT_2trace(DISP_DebugMask, GT_6CLASS, + "DISP_NodeCreate: Message args too" + " large for buffer! Message args size = %d, max = %d\n", + total, max); + } + /* + * Fill in buffer to send to RMS. + * The buffer will have the following format: + * + * RMS command: + * Address of RMS_CreateNode() + * Address of node's create function + * dummy argument + * node type + * + * Message Args: + * max number of messages + * segid for message buffer allocation + * notification type to use when message is received + * length of message arg data + * message args data + * + * Task Args (if task or socket node): + * priority + * stack size + * system stack size + * stack segment + * misc + * number of input streams + * pSTRMInDef[] - offsets of STRM definitions for input streams + * number of output streams + * pSTRMOutDef[] - offsets of STRM definitions for output + * streams + * STRMInDef[] - array of STRM definitions for input streams + * STRMOutDef[] - array of STRM definitions for output streams + * + * Socket Args (if DAIS socket node): + * + */ + if (DSP_SUCCEEDED(status)) { + total = 0; /* Total number of words in buffer so far */ + pdwBuf = (RMS_WORD *)hDisp->pBuf; + pCommand = (struct RMS_Command *)pdwBuf; + pCommand->fxn = (RMS_WORD)(ulRMSFxn); + pCommand->arg1 = (RMS_WORD)(ulCreateFxn); + if (NODE_GetLoadType(hNode) == NLDR_DYNAMICLOAD) { + /* Flush ICACHE on Load */ + pCommand->arg2 = 1; /* dummy argument */ + } else { + /* Do not flush ICACHE */ + pCommand->arg2 = 0; /* dummy argument */ + } + pCommand->data = NODE_GetType(hNode); + /* + * argsOffset is the offset of the data field in struct + * RMS_Command structure. We need this to calculate stream + * definition offsets. + */ + argsOffset = 3; + total += sizeof(struct RMS_Command) / sizeof(RMS_WORD); + /* Message args */ + pMsgArgs = (struct RMS_MsgArgs *) (pdwBuf + total); + pMsgArgs->maxMessages = msgArgs.uMaxMessages; + pMsgArgs->segid = msgArgs.uSegid; + pMsgArgs->notifyType = msgArgs.uNotifyType; + pMsgArgs->argLength = msgArgs.uArgLength; + total += sizeof(struct RMS_MsgArgs) / sizeof(RMS_WORD) - 1; + memcpy(pdwBuf + total, msgArgs.pData, msgArgs.uArgLength); + total += dwLength; + } + if (DSP_FAILED(status)) + goto func_end; + + /* If node is a task node, copy task create arguments into buffer */ + if (nodeType == NODE_TASK || nodeType == NODE_DAISSOCKET) { + taskArgs = pArgs->asa.taskArgs; + taskArgsOffset = total; + total += sizeof(struct RMS_MoreTaskArgs) / sizeof(RMS_WORD) + + 1 + taskArgs.uNumInputs + taskArgs.uNumOutputs; + /* Copy task arguments */ + if (total < max) { + total = taskArgsOffset; + pMoreTaskArgs = (struct RMS_MoreTaskArgs *)(pdwBuf + + total); + /* + * Get some important info about the node. Note that we + * don't just reach into the hNode struct because + * that would break the node object's abstraction. + */ + GetNodeInfo(hNode, &nodeInfo); + GT_2trace(DISP_DebugMask, GT_ENTER, + "uExecutionPriority %x, nPriority %x\n", + nodeInfo.uExecutionPriority, + taskArgs.nPriority); + pMoreTaskArgs->priority = nodeInfo.uExecutionPriority; + pMoreTaskArgs->stackSize = taskArgs.uStackSize; + pMoreTaskArgs->sysstackSize = taskArgs.uSysStackSize; + pMoreTaskArgs->stackSeg = taskArgs.uStackSeg; + pMoreTaskArgs->heapAddr = taskArgs.uDSPHeapAddr; + pMoreTaskArgs->heapSize = taskArgs.uHeapSize; + pMoreTaskArgs->misc = taskArgs.ulDaisArg; + pMoreTaskArgs->numInputStreams = taskArgs.uNumInputs; + total += + sizeof(struct RMS_MoreTaskArgs) / sizeof(RMS_WORD); + GT_2trace(DISP_DebugMask, GT_7CLASS, + "DISP::::uDSPHeapAddr %x, " + "uHeapSize %x\n", taskArgs.uDSPHeapAddr, + taskArgs.uHeapSize); + /* Keep track of pSIOInDef[] and pSIOOutDef[] + * positions in the buffer, since this needs to be + * filled in later. */ + sioInDefOffset = total; + total += taskArgs.uNumInputs; + pdwBuf[total++] = taskArgs.uNumOutputs; + sioOutDefOffset = total; + total += taskArgs.uNumOutputs; + sioDefsOffset = total; + /* Fill SIO defs and offsets */ + offset = sioDefsOffset; + for (i = 0; i < taskArgs.uNumInputs; i++) { + if (DSP_FAILED(status)) + break; + + pdwBuf[sioInDefOffset + i] = + (offset - argsOffset) + * (sizeof(RMS_WORD) / DSPWORDSIZE); + strmDef = taskArgs.strmInDef[i]; + status = FillStreamDef(pdwBuf, &total, offset, + strmDef, max, uCharsInRMSWord); + offset = total; + } + for (i = 0; (i < taskArgs.uNumOutputs) && + (DSP_SUCCEEDED(status)); i++) { + pdwBuf[sioOutDefOffset + i] = + (offset - argsOffset) + * (sizeof(RMS_WORD) / DSPWORDSIZE); + strmDef = taskArgs.strmOutDef[i]; + status = FillStreamDef(pdwBuf, &total, offset, + strmDef, max, uCharsInRMSWord); + offset = total; + } + if (DSP_FAILED(status)) { + GT_2trace(DISP_DebugMask, GT_6CLASS, + "DISP_NodeCreate: Message" + " args to large for buffer! Message args" + " size = %d, max = %d\n", total, max); + } + } else { + /* Args won't fit */ + status = DSP_EFAIL; + GT_2trace(DISP_DebugMask, GT_6CLASS, + "DISP_NodeCreate: Message args " + " too large for buffer! Message args size = %d" + ", max = %d\n", total, max); + } + } + if (DSP_SUCCEEDED(status)) { + ulBytes = total * sizeof(RMS_WORD); + DBC_Assert(ulBytes < (RMS_COMMANDBUFSIZE * sizeof(RMS_WORD))); + status = SendMessage(hDisp, NODE_GetTimeout(hNode), + ulBytes, pNodeEnv); + if (DSP_FAILED(status)) { + GT_1trace(DISP_DebugMask, GT_6CLASS, + "DISP_NodeCreate failed! " + "status = 0x%x\n", status); + } else { + /* + * Message successfully received from RMS. + * Return the status of the Node's create function + * on the DSP-side + */ + status = (((RMS_WORD *)(hDisp->pBuf))[0]); + if (DSP_FAILED(status)) { + GT_1trace(DISP_DebugMask, GT_6CLASS, + "DISP_NodeCreate, " + "DSP-side Node Create failed: 0x%x\n", + status); + } + + } + } +func_end: + return status; +} + +/* + * ======== DISP_NodeDelete ======== + * purpose: + * Delete a node on the DSP by remotely calling the node's delete function. + * + */ +DSP_STATUS DISP_NodeDelete(struct DISP_OBJECT *hDisp, struct NODE_OBJECT *hNode, + u32 ulRMSFxn, u32 ulDeleteFxn, NODE_ENV nodeEnv) +{ + u32 dwArg; + struct RMS_Command *pCommand; + DSP_STATUS status = DSP_SOK; + u32 devType; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(hDisp, DISP_SIGNATURE)); + DBC_Require(hNode != NULL); + + GT_5trace(DISP_DebugMask, GT_ENTER, + "DISP_NodeDelete: hDisp: 0x%xthNode: " + "0x%x\tulRMSFxn: 0x%x\tulDeleteFxn: 0x%x\tnodeEnv: 0x%x\n", + hDisp, hNode, ulRMSFxn, ulDeleteFxn, nodeEnv); + + status = DEV_GetDevType(hDisp->hDevObject, &devType); + + if (DSP_SUCCEEDED(status)) { + + if (devType == DSP_UNIT) { + + /* + * Fill in buffer to send to RMS + */ + pCommand = (struct RMS_Command *)hDisp->pBuf; + pCommand->fxn = (RMS_WORD)(ulRMSFxn); + pCommand->arg1 = (RMS_WORD)nodeEnv; + pCommand->arg2 = (RMS_WORD)(ulDeleteFxn); + pCommand->data = NODE_GetType(hNode); + + status = SendMessage(hDisp, NODE_GetTimeout(hNode), + sizeof(struct RMS_Command), &dwArg); + if (DSP_FAILED(status)) { + GT_1trace(DISP_DebugMask, GT_6CLASS, + "DISP_NodeDelete failed!" + "status = 0x%x\n", status); + } else { + /* + * Message successfully received from RMS. + * Return the status of the Node's delete + * function on the DSP-side + */ + status = (((RMS_WORD *)(hDisp->pBuf))[0]); + if (DSP_FAILED(status)) { + GT_1trace(DISP_DebugMask, GT_6CLASS, + "DISP_NodeDelete, " + "DSP-side Node Delete failed: 0x%x\n", + status); + } + } + + + } + } + return status; +} + +/* + * ======== DISP_NodeRun ======== + * purpose: + * Start execution of a node's execute phase, or resume execution of a node + * that has been suspended (via DISP_NodePause()) on the DSP. + */ +DSP_STATUS DISP_NodeRun(struct DISP_OBJECT *hDisp, struct NODE_OBJECT *hNode, + u32 ulRMSFxn, u32 ulExecuteFxn, NODE_ENV nodeEnv) +{ + u32 dwArg; + struct RMS_Command *pCommand; + DSP_STATUS status = DSP_SOK; + u32 devType; + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(hDisp, DISP_SIGNATURE)); + DBC_Require(hNode != NULL); + + GT_5trace(DISP_DebugMask, GT_ENTER, "DISP_NodeRun: hDisp: 0x%xthNode: \ + 0x%x\tulRMSFxn: 0x%x\tulExecuteFxn: 0x%x\tnodeEnv: 0x%x\n", \ + hDisp, hNode, ulRMSFxn, ulExecuteFxn, nodeEnv); + + status = DEV_GetDevType(hDisp->hDevObject, &devType); + + if (DSP_SUCCEEDED(status)) { + + if (devType == DSP_UNIT) { + + /* + * Fill in buffer to send to RMS. + */ + pCommand = (struct RMS_Command *) hDisp->pBuf; + pCommand->fxn = (RMS_WORD) (ulRMSFxn); + pCommand->arg1 = (RMS_WORD) nodeEnv; + pCommand->arg2 = (RMS_WORD) (ulExecuteFxn); + pCommand->data = NODE_GetType(hNode); + + status = SendMessage(hDisp, NODE_GetTimeout(hNode), + sizeof(struct RMS_Command), &dwArg); + if (DSP_FAILED(status)) { + GT_1trace(DISP_DebugMask, GT_6CLASS, + "DISP_NodeRun failed!" + "status = 0x%x\n", status); + } else { + /* + * Message successfully received from RMS. + * Return the status of the Node's execute + * function on the DSP-side + */ + status = (((RMS_WORD *)(hDisp->pBuf))[0]); + if (DSP_FAILED(status)) { + GT_1trace(DISP_DebugMask, GT_6CLASS, + "DISP_NodeRun, DSP-side Node " + "Execute failed: 0x%x\n", + status); + } + } + + } + } + + return status; +} + +/* + * ======== DeleteDisp ======== + * purpose: + * Frees the resources allocated for the dispatcher. + */ +static void DeleteDisp(struct DISP_OBJECT *hDisp) +{ + DSP_STATUS status = DSP_SOK; + struct WMD_DRV_INTERFACE *pIntfFxns; + + if (MEM_IsValidHandle(hDisp, DISP_SIGNATURE)) { + pIntfFxns = hDisp->pIntfFxns; + + /* Free Node Dispatcher resources */ + if (hDisp->hChnlFromDsp) { + /* Channel close can fail only if the channel handle + * is invalid. */ + status = (*pIntfFxns->pfnChnlClose) + (hDisp->hChnlFromDsp); + if (DSP_FAILED(status)) { + GT_1trace(DISP_DebugMask, GT_6CLASS, + "DISP_Delete: Failed to " + "close channel from RMS: 0x%x\n", + status); + } + } + if (hDisp->hChnlToDsp) { + status = (*pIntfFxns->pfnChnlClose)(hDisp->hChnlToDsp); + if (DSP_FAILED(status)) { + GT_1trace(DISP_DebugMask, GT_6CLASS, + "DISP_Delete: Failed to " + "close channel to RMS: 0x%x\n", + status); + } + } + if (hDisp->pBuf) + MEM_Free(hDisp->pBuf); + + MEM_FreeObject(hDisp); + } +} + +/* + * ======== FillStreamDef ======== + * purpose: + * Fills stream definitions. + */ +static DSP_STATUS FillStreamDef(RMS_WORD *pdwBuf, u32 *ptotal, u32 offset, + struct NODE_STRMDEF strmDef, u32 max, + u32 uCharsInRMSWord) +{ + struct RMS_StrmDef *pStrmDef; + u32 total = *ptotal; + u32 uNameLen; + u32 dwLength; + DSP_STATUS status = DSP_SOK; + + if (total + sizeof(struct RMS_StrmDef) / sizeof(RMS_WORD) >= max) { + status = DSP_EFAIL; + } else { + pStrmDef = (struct RMS_StrmDef *)(pdwBuf + total); + pStrmDef->bufsize = strmDef.uBufsize; + pStrmDef->nbufs = strmDef.uNumBufs; + pStrmDef->segid = strmDef.uSegid; + pStrmDef->align = strmDef.uAlignment; + pStrmDef->timeout = strmDef.uTimeout; + } + + if (DSP_SUCCEEDED(status)) { + /* + * Since we haven't added the device name yet, subtract + * 1 from total. + */ + total += sizeof(struct RMS_StrmDef) / sizeof(RMS_WORD) - 1; + DBC_Require(strmDef.szDevice); + dwLength = strlen(strmDef.szDevice) + 1; + + /* Number of RMS_WORDS needed to hold device name */ + uNameLen = (dwLength + uCharsInRMSWord - 1) / uCharsInRMSWord; + + if (total + uNameLen >= max) { + status = DSP_EFAIL; + } else { + /* + * Zero out last word, since the device name may not + * extend to completely fill this word. + */ + pdwBuf[total + uNameLen - 1] = 0; + /** TODO USE SERVICES **/ + memcpy(pdwBuf + total, strmDef.szDevice, dwLength); + total += uNameLen; + *ptotal = total; + } + } + + return status; +} + +/* + * ======== SendMessage ====== + * Send command message to RMS, get reply from RMS. + */ +static DSP_STATUS SendMessage(struct DISP_OBJECT *hDisp, u32 dwTimeout, + u32 ulBytes, u32 *pdwArg) +{ + struct WMD_DRV_INTERFACE *pIntfFxns; + struct CHNL_OBJECT *hChnl; + u32 dwArg = 0; + u8 *pBuf; + struct CHNL_IOC chnlIOC; + DSP_STATUS status = DSP_SOK; + + DBC_Require(pdwArg != NULL); + + *pdwArg = (u32) NULL; + pIntfFxns = hDisp->pIntfFxns; + hChnl = hDisp->hChnlToDsp; + pBuf = hDisp->pBuf; + + /* Send the command */ + status = (*pIntfFxns->pfnChnlAddIOReq) (hChnl, pBuf, ulBytes, 0, + 0L, dwArg); + + if (DSP_FAILED(status)) { + GT_1trace(DISP_DebugMask, GT_6CLASS, + "SendMessage: Channel AddIOReq to" + " RMS failed! Status = 0x%x\n", status); + goto func_cont; + } + status = (*pIntfFxns->pfnChnlGetIOC) (hChnl, dwTimeout, &chnlIOC); + if (DSP_SUCCEEDED(status)) { + if (!CHNL_IsIOComplete(chnlIOC)) { + if (CHNL_IsTimedOut(chnlIOC)) { + status = DSP_ETIMEOUT; + } else { + GT_1trace(DISP_DebugMask, GT_6CLASS, + "SendMessage failed! " + "Channel IOC status = 0x%x\n", + chnlIOC.status); + status = DSP_EFAIL; + } + } + } else { + GT_1trace(DISP_DebugMask, GT_6CLASS, + "SendMessage: Channel GetIOC to" + " RMS failed! Status = 0x%x\n", status); + } +func_cont: + /* Get the reply */ + if (DSP_FAILED(status)) + goto func_end; + + hChnl = hDisp->hChnlFromDsp; + ulBytes = REPLYSIZE; + status = (*pIntfFxns->pfnChnlAddIOReq)(hChnl, pBuf, ulBytes, + 0, 0L, dwArg); + if (DSP_FAILED(status)) { + GT_1trace(DISP_DebugMask, GT_6CLASS, + "SendMessage: Channel AddIOReq " + "from RMS failed! Status = 0x%x\n", status); + goto func_end; + } + status = (*pIntfFxns->pfnChnlGetIOC) (hChnl, dwTimeout, &chnlIOC); + if (DSP_SUCCEEDED(status)) { + if (CHNL_IsTimedOut(chnlIOC)) { + status = DSP_ETIMEOUT; + } else if (chnlIOC.cBytes < ulBytes) { + /* Did not get all of the reply from the RMS */ + GT_1trace(DISP_DebugMask, GT_6CLASS, + "SendMessage: Did not get all" + "of reply from RMS! Bytes received: %d\n", + chnlIOC.cBytes); + status = DSP_EFAIL; + } else { + if (CHNL_IsIOComplete(chnlIOC)) { + DBC_Assert(chnlIOC.pBuf == pBuf); + status = (*((RMS_WORD *)chnlIOC.pBuf)); + *pdwArg = (((RMS_WORD *)(chnlIOC.pBuf))[1]); + } else { + status = DSP_EFAIL; + } + } + } else { + /* GetIOC failed */ + GT_1trace(DISP_DebugMask, GT_6CLASS, + "SendMessage: Failed to get " + "reply from RMS! Status = 0x%x\n", status); + } +func_end: + return status; +} diff --git a/drivers/dsp/bridge/rmgr/drv.c b/drivers/dsp/bridge/rmgr/drv.c new file mode 100644 index 0000000..256ce12 --- /dev/null +++ b/drivers/dsp/bridge/rmgr/drv.c @@ -0,0 +1,1893 @@ +/* + * drv.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== drv.c ======== + * Description: + * DSP/BIOS Bridge resource allocation module. + * + * Public Functions: + * DRV_Create + * DRV_Destroy + * DRV_Exit + * DRV_GetDevObject + * DRV_GetDevExtension + * DRV_GetFirstDevObject + * DRV_GetNextDevObject + * DRV_GetNextDevExtension + * DRV_Init + * DRV_InsertDevObject + * DRV_RemoveDevObject + * DRV_RequestResources + * DRV_ReleaseResources + * + *! Revision History + *! ======== ======== + *! 19-Apr-2004 sb: Replaced OS specific APIs with MEM_AllocPhysMem and + MEM_FreePhysMem. Fixed warnings. Cosmetic updates. + *! 12-Apr-2004 hp: IVA clean up during bridge-uninstall + *! 05-Jan-2004 vp: Updated for 24xx platform + *! 21-Mar-2003 sb: Get SHM size from registry + *! 10-Feb-2003 vp: Code review updates + *! 18-Oct-2002 vp: Ported to Linux platform + *! 30-Oct-2000 kc: Modified usage of REG_SetValue. + *! 06-Sep-2000 jeh Read channel info into struct CFG_HOSTRES in + *! RequestISAResources() + *! 21-Sep-2000 rr: numwindows is calculated instead of default value in + *! RequestISAResources. + *! 07-Aug-2000 rr: static list of dev objects removed. + *! 27-Jul-2000 rr: RequestResources split into two(Request and Release) + *! Device extension created to hold the DevNodeString. + *! 17-Jul-2000 rr: Driver Object holds the list of Device Objects. + *! Added DRV_Create, DRV_Destroy, DRV_GetDevObject, + *! DRV_GetFirst/NextDevObject, DRV_Insert/RemoveDevObject. + *! 09-May-2000 rr: PCI Support is not L301 specific.Use of MEM_Calloc + *! instead of MEM_Alloc. + *! 28-Mar-2000 rr: PCI Support added. L301 Specific. TBD. + *! 03-Feb-2000 rr: GT and Module Init/exit Changes. Merged with kc. + *! 19-Jan-2000 rr: DBC_Ensure in RequestPCMCIA moved within PCCARD ifdef + *! 29-Dec-1999 rr: PCCard support for any slot.Bus type stored in the + *! struct CFG_HOSTRES Structure. + *! 17-Dec-1999 rr: if PCCARD_Init fails we return DSP_EFAIL. + *! DBC_Ensure checks for sucess and pDevice != NULL + *! 11-Dec-1999 ag: #define "Isa" renamed to "IsaBus". + *! 09-Dec-1999 rr: windows.h included to remove warnings. + *! 02-Dec-1999 rr: struct GT_Mask is with in if DEBUG. Request resources checks + *! status while making call to Reg functions. + *! 23-Nov-1999 rr: windows.h included + *! 19-Nov-1999 rr: DRV_RELEASE bug while setting the registry to zero. + *! fixed. + *! 12-Nov-1999 rr: RequestResources() reads values from the registry. + *! Hardcoded bIRQRegister define removed. + *! 05-Nov-1999 rr: Added hardcoded device interrupt. + *! 25-Oct-1999 rr: Resource structure removed. Now it uses the Host + *! Resource structure directly. + *! 15-Oct-1999 rr: Resource Structure modified. See drv.h + *! dwBusType taken from the registry.Hard coded + *! registry entries removed. + *! 05-Oct-1999 rr: Calling DEV_StartDevice moved to wcdce.c. DRV_Register + *! MiniDriver has been renamed to DRV_RequestResources. + *! DRV_UnRegisterMiniDriver fxn removed. + *! 24-Sep-1999 rr: Significant changes to the RegisterMiniDriver fxns. + *! Now it is simpler. IT stores the dev node in the + *! registry, assign resources and calls the DEV_Start. + *! 10-Sep-1999 rr: Register Minidriver modified. + *! - Resource structure follows the NT model + *! 08-Aug-1999 rr: Adopted for WinCE. Exports Fxns removed. Hull Created. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include +#include + +/* ----------------------------------- Others */ +#include + +/* ----------------------------------- This */ +#include +#include + +#ifndef RES_CLEANUP_DISABLE +#include +#include +#include +#include +#include +#include +#endif + +/* ----------------------------------- Defines, Data Structures, Typedefs */ +#define SIGNATURE 0x5f52474d /* "DRV_" (in reverse) */ + +struct DRV_OBJECT { + u32 dwSignature; + struct LST_LIST *devList; + struct LST_LIST *devNodeString; +#ifndef RES_CLEANUP_DISABLE + struct PROCESS_CONTEXT *procCtxtList; +#endif +}; + +/* + * This is the Device Extension. Named with the Prefix + * DRV_ since it is living in this module + */ +struct DRV_EXT { + struct LST_ELEM link; + char szString[MAXREGPATHLENGTH]; +}; + +/* ----------------------------------- Globals */ +static s32 cRefs; + +#if GT_TRACE +extern struct GT_Mask curTrace; +#endif + +/* ----------------------------------- Function Prototypes */ +static DSP_STATUS RequestBridgeResources(u32 dwContext, s32 fRequest); +static DSP_STATUS RequestBridgeResourcesDSP(u32 dwContext, s32 fRequest); + +#ifndef RES_CLEANUP_DISABLE +/* GPP PROCESS CLEANUP CODE */ + +static DSP_STATUS PrintProcessInformation(void); +static DSP_STATUS DRV_ProcFreeNodeRes(HANDLE hPCtxt); +static DSP_STATUS DRV_ProcFreeSTRMRes(HANDLE hPCtxt); +extern enum NODE_STATE NODE_GetState(HANDLE hNode); + +/* Get the process context list from driver object */ + +/* Set the Process ID */ +DSP_STATUS DRV_ProcSetPID(HANDLE hPCtxt, s32 hProcess) +{ + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + DSP_STATUS status = DSP_SOK; + + DBC_Assert(hPCtxt != NULL); + + pCtxt->pid = hProcess; + return status; +} + + +/* Getting the head of the process context list */ +DSP_STATUS DRV_GetProcCtxtList(struct PROCESS_CONTEXT **pPctxt, + struct DRV_OBJECT *hDrvObject) +{ + DSP_STATUS status = DSP_SOK; + struct DRV_OBJECT *pDrvObject = (struct DRV_OBJECT *)hDrvObject; + + DBC_Assert(hDrvObject != NULL); + GT_2trace(curTrace, GT_ENTER, + "DRV_GetProcCtxtList: 2 *pPctxt:%x, pDrvObject" + ":%x", *pPctxt, pDrvObject); + *pPctxt = pDrvObject->procCtxtList; + GT_2trace(curTrace, GT_ENTER, + "DRV_GetProcCtxtList: 3 *pPctxt:%x, pDrvObject" + ":%x", *pPctxt, pDrvObject); + return status; +} + + + +/* Get a particular process context based on process handle (phProcess) */ +DSP_STATUS DRV_GetProcContext(u32 phProcess, + struct DRV_OBJECT *hDrvObject, + HANDLE hPCtxt, DSP_HNODE hNode, + u32 pMapAddr) +{ + struct PROCESS_CONTEXT **pCtxt = (struct PROCESS_CONTEXT **)hPCtxt; + DSP_STATUS status = DSP_SOK; + struct PROCESS_CONTEXT *pCtxtList = NULL; + struct DRV_OBJECT *pDrvObject = (struct DRV_OBJECT *)hDrvObject; + struct NODE_RES_OBJECT *pTempNode2 = NULL; + struct NODE_RES_OBJECT *pTempNode = NULL; + struct DMM_RES_OBJECT *pTempDMM2 = NULL; + struct DMM_RES_OBJECT *pTempDMM = NULL; + s32 pCtxtFound = 0; + + DBC_Assert(pDrvObject != NULL); + pCtxtList = pDrvObject->procCtxtList; + GT_0trace(curTrace, GT_ENTER, "2DRV_GetProcContext: 2"); + while ((pCtxtList != NULL) && (pCtxtList->pid != phProcess)) { + pCtxtList = pCtxtList->next; + GT_0trace(curTrace, GT_ENTER, "2DRV_GetProcContext: 3"); + } + if (pCtxtList == NULL) { + if (hNode != NULL) { + pCtxtList = pDrvObject->procCtxtList; + while ((pCtxtList != NULL) && (pCtxtFound == 0)) { + pTempNode = pCtxtList->pNodeList; + while ((pTempNode != NULL) && + (pTempNode->hNode != hNode)) { + pTempNode2 = pTempNode; + pTempNode = pTempNode->next; + } + if (pTempNode != NULL) { + pCtxtFound = 1; + status = DSP_SOK; + } else { + pCtxtList = pCtxtList->next; + } + } + } else if ((pMapAddr != 0) && (pCtxtFound == 0)) { + pCtxtList = pDrvObject->procCtxtList; + while ((pCtxtList != NULL) && (pCtxtFound == 0)) { + pTempDMM = pCtxtList->pDMMList; + while ((pTempDMM != NULL) && + (pTempDMM->ulDSPAddr != pMapAddr)) { + pTempDMM2 = pTempDMM; + pTempDMM = pTempDMM->next; + } + if (pTempDMM != NULL) { + pCtxtFound = 1; + status = DSP_SOK; + } else { + pCtxtList = pCtxtList->next; + } + } + if (pCtxtList == NULL) + status = DSP_ENOTFOUND; + + } + } else{ + status = DSP_SOK; + } + GT_0trace(curTrace, GT_ENTER, "2DRV_GetProcContext: 4"); + *pCtxt = pCtxtList; + return status; +} + + +/* Add a new process context to process context list */ +DSP_STATUS DRV_InsertProcContext(struct DRV_OBJECT *hDrVObject, HANDLE hPCtxt) +{ + struct PROCESS_CONTEXT **pCtxt = (struct PROCESS_CONTEXT **)hPCtxt; + DSP_STATUS status = DSP_SOK; + struct PROCESS_CONTEXT *pCtxtList = NULL; + struct DRV_OBJECT *hDRVObject; + + GT_0trace(curTrace, GT_ENTER, "\n In DRV_InsertProcContext\n"); + status = CFG_GetObject((u32 *)&hDRVObject, REG_DRV_OBJECT); + DBC_Assert(hDRVObject != NULL); + *pCtxt = MEM_Calloc(1 * sizeof(struct PROCESS_CONTEXT), MEM_PAGED); + GT_0trace(curTrace, GT_ENTER, + "\n In DRV_InsertProcContext Calling " + "DRV_GetProcCtxtList\n"); + DRV_GetProcCtxtList(&pCtxtList, hDRVObject); + GT_0trace(curTrace, GT_ENTER, + "\n In DRV_InsertProcContext After Calling " + "DRV_GetProcCtxtList\n"); + if (pCtxtList != NULL) { + GT_0trace(curTrace, GT_ENTER, + "\n In DRV_InsertProcContext and pCtxt is " + "not Null\n"); + while (pCtxtList->next != NULL) + pCtxtList = pCtxtList->next; + + pCtxtList->next = *pCtxt; + } else { + GT_0trace(curTrace, GT_ENTER, + "\n In DRV_InsertProcContext and " + "pCtxt is Null\n"); + hDRVObject->procCtxtList = *pCtxt; + } + return status; +} + +/* Delete a process context from process resource context list */ +DSP_STATUS DRV_RemoveProcContext(struct DRV_OBJECT *hDRVObject, + HANDLE hPCtxt, HANDLE hProcess) +{ + DSP_STATUS status = DSP_SOK; + struct PROCESS_CONTEXT *pCtxt2 = NULL; + struct PROCESS_CONTEXT *pTmp = NULL; + struct PROCESS_CONTEXT *pCtxtList = NULL; + + DBC_Assert(hDRVObject != NULL); + DRV_GetProcContext((u32)hProcess, hDRVObject, &pCtxt2, NULL, 0); + + GT_0trace(curTrace, GT_ENTER, "DRV_RemoveProcContext: 12"); + DRV_GetProcCtxtList(&pCtxtList, hDRVObject); + GT_0trace(curTrace, GT_ENTER, "DRV_RemoveProcContext: 13"); + pTmp = pCtxtList; + while ((pCtxtList != NULL) && (pCtxtList != pCtxt2)) { + pTmp = pCtxtList; + pCtxtList = pCtxtList->next; + GT_0trace(curTrace, GT_ENTER, + "DRV_RemoveProcContext: 2"); + } + GT_0trace(curTrace, GT_ENTER, "DRV_RemoveProcContext: 3"); + if (hDRVObject->procCtxtList == pCtxt2) + hDRVObject->procCtxtList = pCtxt2->next; + + if (pCtxtList == NULL) + return DSP_ENOTFOUND; + else if (pTmp->next != NULL) + pTmp->next = pTmp->next->next; + + MEM_Free(pCtxt2); + GT_0trace(curTrace, GT_ENTER, "DRV_RemoveProcContext: 7"); + + return status; +} + +/* Update the state of process context */ +DSP_STATUS DRV_ProcUpdatestate(HANDLE hPCtxt, enum GPP_PROC_RES_STATE status) +{ + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + DSP_STATUS status1 = DSP_SOK; + if (pCtxt != NULL) { + pCtxt->resState = status; + } else { + GT_0trace(curTrace, GT_ENTER, + "DRV_ProcUpdatestate: Failed to update " + "process state"); + } + return status1; +} + +/* Allocate and add a node resource element +* This function is called from .Node_Allocate. */ +DSP_STATUS DRV_InsertNodeResElement(HANDLE hNode, HANDLE hNodeRes, + HANDLE hPCtxt) +{ + struct NODE_RES_OBJECT **pNodeRes = (struct NODE_RES_OBJECT **)hNodeRes; + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + DSP_STATUS status = DSP_SOK; + struct NODE_RES_OBJECT *pTempNodeRes = NULL; + GT_0trace(curTrace, GT_ENTER, "DRV_InsertNodeResElement: 1"); + *pNodeRes = (struct NODE_RES_OBJECT *)MEM_Calloc + (1 * sizeof(struct NODE_RES_OBJECT), MEM_PAGED); + DBC_Assert(hPCtxt != NULL); + if ((*pNodeRes == NULL) || (hPCtxt == NULL)) { + GT_0trace(curTrace, GT_ENTER, "DRV_InsertNodeResElement: 12"); + status = DSP_EHANDLE; + } + if (DSP_SUCCEEDED(status)) { + (*pNodeRes)->hNode = hNode; + if (pCtxt->pNodeList != NULL) { + pTempNodeRes = pCtxt->pNodeList; + while (pTempNodeRes->next != NULL) + pTempNodeRes = pTempNodeRes->next; + + pTempNodeRes->next = *pNodeRes; + GT_0trace(curTrace, GT_ENTER, + "DRV_InsertNodeResElement: 2"); + } else { + pCtxt->pNodeList = *pNodeRes; + GT_0trace(curTrace, GT_ENTER, + "DRV_InsertNodeResElement: 3"); + } + } + GT_0trace(curTrace, GT_ENTER, "DRV_InsertNodeResElement: 4"); + return status; +} + +/* Release all Node resources and its context +* This is called from .Node_Delete. */ +DSP_STATUS DRV_RemoveNodeResElement(HANDLE hNodeRes, HANDLE hPCtxt) +{ + struct NODE_RES_OBJECT *pNodeRes = (struct NODE_RES_OBJECT *)hNodeRes; + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + DSP_STATUS status = DSP_SOK; + struct NODE_RES_OBJECT *pTempNode2 = pCtxt->pNodeList; + struct NODE_RES_OBJECT *pTempNode = pCtxt->pNodeList; + + DBC_Assert(hPCtxt != NULL); + GT_0trace(curTrace, GT_ENTER, "\nDRV_RemoveNodeResElement: 1\n"); + while ((pTempNode != NULL) && (pTempNode != pNodeRes)) { + pTempNode2 = pTempNode; + pTempNode = pTempNode->next; + } + if (pCtxt->pNodeList == pNodeRes) + pCtxt->pNodeList = pNodeRes->next; + + if (pTempNode == NULL) + return DSP_ENOTFOUND; + else if (pTempNode2->next != NULL) + pTempNode2->next = pTempNode2->next->next; + + MEM_Free(pTempNode); + return status; +} + +/* Actual Node De-Allocation */ +static DSP_STATUS DRV_ProcFreeNodeRes(HANDLE hPCtxt) +{ + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + DSP_STATUS status = DSP_SOK; + struct NODE_RES_OBJECT *pNodeList = NULL; + struct NODE_RES_OBJECT *pNodeRes = NULL; + u32 nState; + + DBC_Assert(hPCtxt != NULL); + pNodeList = pCtxt->pNodeList; + while (pNodeList != NULL) { + GT_0trace(curTrace, GT_ENTER, "DRV_ProcFreeNodeRes: 1"); + pNodeRes = pNodeList; + pNodeList = pNodeList->next; + if (pNodeRes->nodeAllocated) { + nState = NODE_GetState(pNodeRes->hNode) ; + GT_1trace(curTrace, GT_5CLASS, + "DRV_ProcFreeNodeRes: Node state %x\n", nState); + if (nState <= NODE_DELETING) { + if ((nState == NODE_RUNNING) || + (nState == NODE_PAUSED) || + (nState == NODE_TERMINATING)) { + GT_1trace(curTrace, GT_5CLASS, + "Calling Node_Terminate for Node:" + " 0x%x\n", pNodeRes->hNode); + status = NODE_Terminate + (pNodeRes->hNode, &status); + GT_1trace(curTrace, GT_5CLASS, + "Calling Node_Delete for Node:" + " 0x%x\n", pNodeRes->hNode); + status = NODE_Delete(pNodeRes->hNode); + GT_1trace(curTrace, GT_5CLASS, + "the status after the NodeDelete %x\n", + status); + } else if ((nState == NODE_ALLOCATED) + || (nState == NODE_CREATED)) + status = NODE_Delete(pNodeRes->hNode); + } + } + pNodeRes->nodeAllocated = 0; + } + return status; +} + +/* Allocate the DMM resource element +* This is called from Proc_Map. after the actual resource is allocated */ +DSP_STATUS DRV_InsertDMMResElement(HANDLE hDMMRes, HANDLE hPCtxt) +{ + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + struct DMM_RES_OBJECT **pDMMRes = (struct DMM_RES_OBJECT **)hDMMRes; + DSP_STATUS status = DSP_SOK; + struct DMM_RES_OBJECT *pTempDMMRes = NULL; + + *pDMMRes = (struct DMM_RES_OBJECT *) + MEM_Calloc(1 * sizeof(struct DMM_RES_OBJECT), MEM_PAGED); + DBC_Assert(hPCtxt != NULL); + GT_0trace(curTrace, GT_ENTER, "DRV_InsertDMMResElement: 1"); + if ((*pDMMRes == NULL) || (hPCtxt == NULL)) { + GT_0trace(curTrace, GT_5CLASS, "DRV_InsertDMMResElement: 2"); + status = DSP_EHANDLE; + } + if (DSP_SUCCEEDED(status)) { + if (pCtxt->pDMMList != NULL) { + GT_0trace(curTrace, GT_5CLASS, + "DRV_InsertDMMResElement: 3"); + pTempDMMRes = pCtxt->pDMMList; + while (pTempDMMRes->next != NULL) + pTempDMMRes = pTempDMMRes->next; + + pTempDMMRes->next = *pDMMRes; + } else { + pCtxt->pDMMList = *pDMMRes; + GT_0trace(curTrace, GT_5CLASS, + "DRV_InsertDMMResElement: 4"); + } + } + GT_0trace(curTrace, GT_ENTER, "DRV_InsertDMMResElement: 5"); + return status; +} + + + +/* Release DMM resource element context +* This is called from Proc_UnMap. after the actual resource is freed */ +DSP_STATUS DRV_RemoveDMMResElement(HANDLE hDMMRes, HANDLE hPCtxt) +{ + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + struct DMM_RES_OBJECT *pDMMRes = (struct DMM_RES_OBJECT *)hDMMRes; + DSP_STATUS status = DSP_SOK; + struct DMM_RES_OBJECT *pTempDMMRes2 = NULL; + struct DMM_RES_OBJECT *pTempDMMRes = NULL; + + DBC_Assert(hPCtxt != NULL); + pTempDMMRes2 = pCtxt->pDMMList; + pTempDMMRes = pCtxt->pDMMList; + GT_0trace(curTrace, GT_ENTER, "DRV_RemoveDMMResElement: 1"); + while ((pTempDMMRes != NULL) && (pTempDMMRes != pDMMRes)) { + GT_0trace(curTrace, GT_ENTER, "DRV_RemoveDMMResElement: 2"); + pTempDMMRes2 = pTempDMMRes; + pTempDMMRes = pTempDMMRes->next; + } + GT_0trace(curTrace, GT_ENTER, "DRV_RemoveDMMResElement: 3"); + if (pCtxt->pDMMList == pTempDMMRes) + pCtxt->pDMMList = pTempDMMRes->next; + + if (pTempDMMRes == NULL) + return DSP_ENOTFOUND; + else if (pTempDMMRes2->next != NULL) + pTempDMMRes2->next = pTempDMMRes2->next->next; + + MEM_Free(pDMMRes); + GT_0trace(curTrace, GT_ENTER, "DRV_RemoveDMMResElement: 4"); + return status; +} + +/* Update DMM resource status */ +DSP_STATUS DRV_UpdateDMMResElement(HANDLE hDMMRes, u32 pMpuAddr, u32 ulSize, + u32 pReqAddr, u32 pMapAddr, + HANDLE hProcessor) +{ + struct DMM_RES_OBJECT *pDMMRes = (struct DMM_RES_OBJECT *)hDMMRes; + DSP_STATUS status = DSP_SOK; + + DBC_Assert(hDMMRes != NULL); + pDMMRes->ulMpuAddr = pMpuAddr; + pDMMRes->ulDSPAddr = pMapAddr; + pDMMRes->ulDSPResAddr = pReqAddr; + pDMMRes->dmmSize = ulSize; + pDMMRes->hProcessor = hProcessor; + pDMMRes->dmmAllocated = 1; + + return status; +} + +/* Actual DMM De-Allocation */ +DSP_STATUS DRV_ProcFreeDMMRes(HANDLE hPCtxt) +{ + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + DSP_STATUS status = DSP_SOK; + struct DMM_RES_OBJECT *pDMMList = pCtxt->pDMMList; + struct DMM_RES_OBJECT *pDMMRes = NULL; + + DBC_Assert(hPCtxt != NULL); + GT_0trace(curTrace, GT_ENTER, "\nDRV_ProcFreeDMMRes: 1\n"); + while (pDMMList != NULL) { + pDMMRes = pDMMList; + pDMMList = pDMMList->next; + if (pDMMRes->dmmAllocated) { + status = PROC_UnMap(pDMMRes->hProcessor, + (void *)pDMMRes->ulDSPResAddr); + status = PROC_UnReserveMemory(pDMMRes->hProcessor, + (void *)pDMMRes->ulDSPResAddr); + pDMMRes->dmmAllocated = 0; + } + } + return status; +} + + +/* Release all DMM resources and its context +* This is called from .bridge_release. */ +DSP_STATUS DRV_RemoveAllDMMResElements(HANDLE hPCtxt) +{ + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + DSP_STATUS status = DSP_SOK; + struct DMM_RES_OBJECT *pTempDMMRes2 = NULL; + struct DMM_RES_OBJECT *pTempDMMRes = NULL; + + DBC_Assert(pCtxt != NULL); + DRV_ProcFreeDMMRes(pCtxt); + pTempDMMRes = pCtxt->pDMMList; + while (pTempDMMRes != NULL) { + pTempDMMRes2 = pTempDMMRes; + pTempDMMRes = pTempDMMRes->next; + MEM_Free(pTempDMMRes2); + } + pCtxt->pDMMList = NULL; + return status; +} + +DSP_STATUS DRV_GetDMMResElement(u32 pMapAddr, HANDLE hDMMRes, HANDLE hPCtxt) +{ + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + struct DMM_RES_OBJECT **pDMMRes = (struct DMM_RES_OBJECT **)hDMMRes; + DSP_STATUS status = DSP_SOK; + struct DMM_RES_OBJECT *pTempDMM2 = NULL; + struct DMM_RES_OBJECT *pTempDMM = NULL; + + DBC_Assert(hPCtxt != NULL); + pTempDMM = pCtxt->pDMMList; + while ((pTempDMM != NULL) && (pTempDMM->ulDSPAddr != pMapAddr)) { + GT_3trace(curTrace, GT_ENTER, + "DRV_GetDMMResElement: 2 pTempDMM:%x " + "pTempDMM->ulDSPAddr:%x pMapAddr:%x\n", pTempDMM, + pTempDMM->ulDSPAddr, pMapAddr); + pTempDMM2 = pTempDMM; + pTempDMM = pTempDMM->next; + } + if (pTempDMM != NULL) { + GT_0trace(curTrace, GT_ENTER, "DRV_GetDMMResElement: 3"); + *pDMMRes = pTempDMM; + } else { + status = DSP_ENOTFOUND; + } GT_0trace(curTrace, GT_ENTER, "DRV_GetDMMResElement: 4"); + return status; +} + +/* Update Node allocation status */ +void DRV_ProcNodeUpdateStatus(HANDLE hNodeRes, s32 status) +{ + struct NODE_RES_OBJECT *pNodeRes = (struct NODE_RES_OBJECT *)hNodeRes; + DBC_Assert(hNodeRes != NULL); + pNodeRes->nodeAllocated = status; +} + +/* Update Node Heap status */ +void DRV_ProcNodeUpdateHeapStatus(HANDLE hNodeRes, s32 status) +{ + struct NODE_RES_OBJECT *pNodeRes = (struct NODE_RES_OBJECT *)hNodeRes; + DBC_Assert(hNodeRes != NULL); + pNodeRes->heapAllocated = status; +} + +/* Release all Node resources and its context +* This is called from .bridge_release. +*/ +DSP_STATUS DRV_RemoveAllNodeResElements(HANDLE hPCtxt) +{ + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + DSP_STATUS status = DSP_SOK; + struct NODE_RES_OBJECT *pTempNode2 = NULL; + struct NODE_RES_OBJECT *pTempNode = NULL; + + DBC_Assert(hPCtxt != NULL); + DRV_ProcFreeNodeRes(pCtxt); + pTempNode = pCtxt->pNodeList; + while (pTempNode != NULL) { + pTempNode2 = pTempNode; + pTempNode = pTempNode->next; + MEM_Free(pTempNode2); + } + pCtxt->pNodeList = NULL; + return status; +} + +/* Getting the node resource element */ + +DSP_STATUS DRV_GetNodeResElement(HANDLE hNode, HANDLE hNodeRes, HANDLE hPCtxt) +{ + struct NODE_RES_OBJECT **nodeRes = (struct NODE_RES_OBJECT **)hNodeRes; + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + DSP_STATUS status = DSP_SOK; + struct NODE_RES_OBJECT *pTempNode2 = NULL; + struct NODE_RES_OBJECT *pTempNode = NULL; + + DBC_Assert(hPCtxt != NULL); + pTempNode = pCtxt->pNodeList; + GT_0trace(curTrace, GT_ENTER, "DRV_GetNodeResElement: 1"); + while ((pTempNode != NULL) && (pTempNode->hNode != hNode)) { + pTempNode2 = pTempNode; + pTempNode = pTempNode->next; + } + if (pTempNode != NULL) + *nodeRes = pTempNode; + else + status = DSP_ENOTFOUND; + + return status; +} + + + +/* Allocate the STRM resource element +* This is called after the actual resource is allocated +*/ +DSP_STATUS DRV_ProcInsertSTRMResElement(HANDLE hStreamHandle, HANDLE hSTRMRes, + HANDLE hPCtxt) +{ + struct STRM_RES_OBJECT **pSTRMRes = (struct STRM_RES_OBJECT **)hSTRMRes; + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + DSP_STATUS status = DSP_SOK; + struct STRM_RES_OBJECT *pTempSTRMRes = NULL; + DBC_Assert(hPCtxt != NULL); + + *pSTRMRes = (struct STRM_RES_OBJECT *) + MEM_Calloc(1 * sizeof(struct STRM_RES_OBJECT), MEM_PAGED); + if ((*pSTRMRes == NULL) || (hPCtxt == NULL)) { + GT_0trace(curTrace, GT_ENTER, "DRV_InsertSTRMResElement: 2"); + status = DSP_EHANDLE; + } + if (DSP_SUCCEEDED(status)) { + (*pSTRMRes)->hStream = hStreamHandle; + if (pCtxt->pSTRMList != NULL) { + GT_0trace(curTrace, GT_ENTER, + "DRV_InsertiSTRMResElement: 3"); + pTempSTRMRes = pCtxt->pSTRMList; + while (pTempSTRMRes->next != NULL) + pTempSTRMRes = pTempSTRMRes->next; + + pTempSTRMRes->next = *pSTRMRes; + } else { + pCtxt->pSTRMList = *pSTRMRes; + GT_0trace(curTrace, GT_ENTER, + "DRV_InsertSTRMResElement: 4"); + } + } + return status; +} + + + +/* Release Stream resource element context +* This function called after the actual resource is freed +*/ +DSP_STATUS DRV_ProcRemoveSTRMResElement(HANDLE hSTRMRes, HANDLE hPCtxt) +{ + struct STRM_RES_OBJECT *pSTRMRes = (struct STRM_RES_OBJECT *)hSTRMRes; + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + DSP_STATUS status = DSP_SOK; + struct STRM_RES_OBJECT *pTempSTRMRes2 = pCtxt->pSTRMList; + struct STRM_RES_OBJECT *pTempSTRMRes = pCtxt->pSTRMList; + + DBC_Assert(hPCtxt != NULL); + while ((pTempSTRMRes != NULL) && (pTempSTRMRes != pSTRMRes)) { + pTempSTRMRes2 = pTempSTRMRes; + pTempSTRMRes = pTempSTRMRes->next; + } + if (pCtxt->pSTRMList == pTempSTRMRes) + pCtxt->pSTRMList = pTempSTRMRes->next; + + if (pTempSTRMRes == NULL) + status = DSP_ENOTFOUND; + else if (pTempSTRMRes2->next != NULL) + pTempSTRMRes2->next = pTempSTRMRes2->next->next; + + MEM_Free(pSTRMRes); + return status; +} + + +/* Actual Stream De-Allocation */ +static DSP_STATUS DRV_ProcFreeSTRMRes(HANDLE hPCtxt) +{ + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + DSP_STATUS status = DSP_SOK; + DSP_STATUS status1 = DSP_SOK; + u8 **apBuffer = NULL; + struct STRM_RES_OBJECT *pSTRMList = NULL; + struct STRM_RES_OBJECT *pSTRMRes = NULL; + u8 *pBufPtr; + u32 ulBytes; + u32 dwArg; + s32 ulBufSize; + + + DBC_Assert(hPCtxt != NULL); + pSTRMList = pCtxt->pSTRMList; + while (pSTRMList != NULL) { + pSTRMRes = pSTRMList; + pSTRMList = pSTRMList->next; + if (pSTRMRes->uNumBufs != 0) { + apBuffer = MEM_Alloc((pSTRMRes->uNumBufs * + sizeof(u8 *)), MEM_NONPAGED); + status = STRM_FreeBuffer(pSTRMRes->hStream, apBuffer, + pSTRMRes->uNumBufs); + MEM_Free(apBuffer); + } + status = STRM_Close(pSTRMRes->hStream); + if (DSP_FAILED(status)) { + if (status == DSP_EPENDING) { + status = STRM_Reclaim(pSTRMRes->hStream, + &pBufPtr, &ulBytes, + (u32 *)&ulBufSize, &dwArg); + if (DSP_SUCCEEDED(status)) + status = STRM_Close(pSTRMRes->hStream); + + } + } + } + return status1; +} + +/* Release all Stream resources and its context +* This is called from .bridge_release. +*/ +DSP_STATUS DRV_RemoveAllSTRMResElements(HANDLE hPCtxt) +{ + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + DSP_STATUS status = DSP_SOK; + struct STRM_RES_OBJECT *pTempSTRMRes2 = NULL; + struct STRM_RES_OBJECT *pTempSTRMRes = NULL; + + DBC_Assert(hPCtxt != NULL); + DRV_ProcFreeSTRMRes(pCtxt); + pTempSTRMRes = pCtxt->pSTRMList; + while (pTempSTRMRes != NULL) { + pTempSTRMRes2 = pTempSTRMRes; + pTempSTRMRes = pTempSTRMRes->next; + MEM_Free(pTempSTRMRes2); + } + pCtxt->pSTRMList = NULL; + return status; +} + + +/* Getting the stream resource element */ +DSP_STATUS DRV_GetSTRMResElement(HANDLE hStrm, HANDLE hSTRMRes, HANDLE hPCtxt) +{ + struct STRM_RES_OBJECT **STRMRes = (struct STRM_RES_OBJECT **)hSTRMRes; + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + DSP_STATUS status = DSP_SOK; + struct STRM_RES_OBJECT *pTempSTRM2 = NULL; + struct STRM_RES_OBJECT *pTempSTRM = pCtxt->pSTRMList; + + DBC_Assert(hPCtxt != NULL); + while ((pTempSTRM != NULL) && (pTempSTRM->hStream != hStrm)) { + GT_0trace(curTrace, GT_ENTER, "DRV_GetSTRMResElement: 2"); + pTempSTRM2 = pTempSTRM; + pTempSTRM = pTempSTRM->next; + } + if (pTempSTRM != NULL) { + GT_0trace(curTrace, GT_ENTER, "DRV_GetSTRMResElement: 3"); + *STRMRes = pTempSTRM; + } else { + GT_0trace(curTrace, GT_ENTER, "DRV_GetSTRMResElement: 4"); + status = DSP_ENOTFOUND; + } + GT_0trace(curTrace, GT_ENTER, "DRV_GetSTRMResElement: 5"); + return status; +} + +/* Updating the stream resource element */ +DSP_STATUS DRV_ProcUpdateSTRMRes(u32 uNumBufs, HANDLE hSTRMRes, HANDLE hPCtxt) +{ + DSP_STATUS status = DSP_SOK; + struct STRM_RES_OBJECT **STRMRes = (struct STRM_RES_OBJECT **)hSTRMRes; + + DBC_Assert(hPCtxt != NULL); + (*STRMRes)->uNumBufs = uNumBufs; + return status; +} + +/* Displaying the resources allocated by a process */ +DSP_STATUS DRV_ProcDisplayResInfo(u8 *pBuf1, u32 *pSize) +{ + struct PROCESS_CONTEXT *pCtxt = NULL; + struct NODE_RES_OBJECT *pNodeRes = NULL; + struct DMM_RES_OBJECT *pDMMRes = NULL; + struct STRM_RES_OBJECT *pSTRMRes = NULL; + struct DSPHEAP_RES_OBJECT *pDSPHEAPRes = NULL; + u32 tempCount = 1; + HANDLE hDrvObject = NULL; + void *pBuf = pBuf1; + u8 pTempBuf[250]; + u32 tempStrLen = 0, tempStrLen2 = 0; + DSP_STATUS status = DSP_SOK; + + CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); + DRV_GetProcCtxtList(&pCtxt, (struct DRV_OBJECT *)hDrvObject); + GT_0trace(curTrace, GT_ENTER, "*********************" + "DRV_ProcDisplayResourceInfo:*\n"); + while (pCtxt != NULL) { + tempStrLen2 = sprintf((char *)pTempBuf, + "-------------------------------------" + "-----------------------------------\n"); + tempStrLen2 += 2; + memmove(pBuf+tempStrLen, pTempBuf, tempStrLen2); + tempStrLen += tempStrLen2; + if (pCtxt->resState == PROC_RES_ALLOCATED) { + tempStrLen2 = sprintf((char *)pTempBuf, + "GPP Process Resource State: " + "pCtxt->resState = PROC_RES_ALLOCATED, " + " Process ID: %d\n", pCtxt->pid); + tempStrLen2 += 2; + memmove(pBuf+tempStrLen, pTempBuf, tempStrLen2); + tempStrLen += tempStrLen2; + } else { + tempStrLen2 = sprintf((char *)pTempBuf, + "GPP Resource State: pCtxt->resState" + " = PROC_RES_DEALLOCATED, Process ID:%d\n", + pCtxt->pid); + tempStrLen2 += 2; + memmove(pBuf+tempStrLen, pTempBuf, tempStrLen2); + tempStrLen += tempStrLen2; + } + pNodeRes = pCtxt->pNodeList; + tempCount = 1; + while (pNodeRes != NULL) { + GT_2trace(curTrace, GT_ENTER, + "DRV_ProcDisplayResourceInfo: #:%d " + "pCtxt->pNodeList->hNode:%x\n", + tempCount, pNodeRes->hNode); + tempStrLen2 = sprintf((char *)pTempBuf, + "Node Resource Information: Node #" + " %d Node Handle hNode:0X%x\n", + tempCount, (u32)pNodeRes->hNode); + pNodeRes = pNodeRes->next; + tempStrLen2 += 2; + memmove(pBuf+tempStrLen, pTempBuf, tempStrLen2); + tempStrLen += tempStrLen2; + tempCount++; + } + tempCount = 1; + pDSPHEAPRes = pCtxt->pDSPHEAPList; + while (pDSPHEAPRes != NULL) { + GT_2trace(curTrace, GT_ENTER, + "DRV_ProcDisplayResourceInfo: #:%d " + "pCtxt->pDSPHEAPRList->ulMpuAddr:%x\n", + tempCount, pDSPHEAPRes->ulMpuAddr); + tempStrLen2 = sprintf((char *)pTempBuf, + "DSP Heap Resource Info: HEAP # %d" + " Mapped GPP Address: 0x%x, size: 0x%x\n", + tempCount, (u32)pDSPHEAPRes->ulMpuAddr, + (u32)pDSPHEAPRes->heapSize); + pDSPHEAPRes = pDSPHEAPRes->next; + tempStrLen2 += 2; + memmove(pBuf+tempStrLen, pTempBuf, tempStrLen2); + tempStrLen += tempStrLen2; + tempCount++; + } + tempCount = 1; + pDMMRes = pCtxt->pDMMList; + while (pDMMRes != NULL) { + GT_2trace(curTrace, GT_ENTER, + "DRV_ProcDisplayResourceInfo: #:%d " + " pCtxt->pDMMList->ulMpuAddr:%x\n", + tempCount, + pDMMRes->ulMpuAddr); + tempStrLen2 = sprintf((char *)pTempBuf, + "DMM Resource Info: DMM # %d Mapped" + " GPP Address: 0x%x, size: 0x%x\n", + tempCount, (u32)pDMMRes->ulMpuAddr, + (u32)pDMMRes->dmmSize); + pDMMRes = pDMMRes->next; + tempStrLen2 += 2; + memmove(pBuf+tempStrLen, pTempBuf, tempStrLen2); + tempStrLen += tempStrLen2; + tempCount++; + } + tempCount = 1; + pSTRMRes = pCtxt->pSTRMList; + while (pSTRMRes != NULL) { + GT_2trace(curTrace, GT_ENTER, + "DRV_ProcDisplayResourceInfo: #:%d " + "pCtxt->pSTRMList->hStream:%x\n", tempCount, + pSTRMRes->hStream); + tempStrLen2 = sprintf((char *)pTempBuf, + "Stream Resource info: STRM # %d " + "Stream Handle: 0x%x \n", + tempCount, (u32)pSTRMRes->hStream); + pSTRMRes = pSTRMRes->next; + tempStrLen2 += 2; + memmove(pBuf+tempStrLen, pTempBuf, tempStrLen2); + tempStrLen += tempStrLen2; + tempCount++; + } + pCtxt = pCtxt->next; + } + *pSize = tempStrLen; + status = PrintProcessInformation(); + GT_0trace(curTrace, GT_ENTER, "*********************" + "DRV_ProcDisplayResourceInfo:**\n"); + return status; +} + +/* + * ======== PrintProcessInformation ======== + * Purpose: + * This function prints the Process's information stored in + * the process context list. Some of the information that + * it displays is Process's state, Node, Stream, DMM, and + * Heap information. + */ +static DSP_STATUS PrintProcessInformation(void) +{ + struct DRV_OBJECT *hDrvObject = NULL; + struct PROCESS_CONTEXT *pCtxtList = NULL; + struct NODE_RES_OBJECT *pNodeRes = NULL; + struct DMM_RES_OBJECT *pDMMRes = NULL; + struct STRM_RES_OBJECT *pSTRMRes = NULL; + struct DSPHEAP_RES_OBJECT *pDSPHEAPRes = NULL; + DSP_STATUS status = DSP_SOK; + u32 tempCount; + u32 procID; + + /* Get the Process context list */ + CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); + DRV_GetProcCtxtList(&pCtxtList, hDrvObject); + GT_0trace(curTrace, GT_4CLASS, "\n### Debug information" + " for DSP bridge ##\n"); + GT_0trace(curTrace, GT_4CLASS, " \n ###The processes" + " information is as follows ### \n") ; + GT_0trace(curTrace, GT_4CLASS, " =====================" + "============ \n"); + /* Go through the entries in the Process context list */ + while (pCtxtList != NULL) { + GT_1trace(curTrace, GT_4CLASS, "\nThe process" + " id is %d\n", pCtxtList->pid); + GT_0trace(curTrace, GT_4CLASS, " -------------------" + "---------\n"); + if (pCtxtList->resState == PROC_RES_ALLOCATED) { + GT_0trace(curTrace, GT_4CLASS, " \nThe Process" + " is in Allocated state\n"); + } else { + GT_0trace(curTrace, GT_4CLASS, "\nThe Process" + " is in DeAllocated state\n"); + } + GT_1trace(curTrace, GT_4CLASS, "\nThe hProcessor" + " handle is: 0X%x\n", + (u32)pCtxtList->hProcessor); + if (pCtxtList->hProcessor != NULL) { + PROC_GetProcessorId(pCtxtList->hProcessor, &procID); + if (procID == DSP_UNIT) { + GT_0trace(curTrace, GT_4CLASS, + "\nProcess connected to" + " DSP Processor\n"); + } else if (procID == IVA_UNIT) { + GT_0trace(curTrace, GT_4CLASS, + "\nProcess connected to" + " IVA Processor\n"); + } else { + GT_0trace(curTrace, GT_7CLASS, + "\n***ERROR:Invalid Processor Id***\n"); + } + } + pNodeRes = pCtxtList->pNodeList; + tempCount = 1; + while (pNodeRes != NULL) { + if (tempCount == 1) + GT_0trace(curTrace, GT_4CLASS, + "\n***The Nodes allocated by" + " this Process are***\n"); + GT_2trace(curTrace, GT_4CLASS, + "Node # %d Node Handle hNode:0x%x\n", + tempCount, (u32)pNodeRes->hNode); + pNodeRes = pNodeRes->next; + tempCount++; + } + if (tempCount == 1) + GT_0trace(curTrace, GT_4CLASS, + "\n ***There are no Nodes" + " allocated by this Process***\n"); + tempCount = 1; + pDSPHEAPRes = pCtxtList->pDSPHEAPList; + while (pDSPHEAPRes != NULL) { + if (tempCount == 1) + GT_0trace(curTrace, GT_4CLASS, + "\n***The Heaps allocated by" + " this Process are***\n"); + GT_3trace(curTrace, GT_4CLASS, + "DSP Heap Resource Info: HEAP # %d " + "Mapped GPP Address:0x%x, Size: 0x%lx\n", + tempCount, (u32)pDSPHEAPRes->ulMpuAddr, + pDSPHEAPRes->heapSize); + pDSPHEAPRes = pDSPHEAPRes->next; + tempCount++; + } + if (tempCount == 1) + GT_0trace(curTrace, GT_4CLASS, + "\n ***There are no Heaps allocated" + " by this Process***\n"); + tempCount = 1; + pDMMRes = pCtxtList->pDMMList; + while (pDMMRes != NULL) { + if (tempCount == 1) + GT_0trace(curTrace, GT_4CLASS, + "\n ***The DMM resources allocated by" + " this Process are***\n"); + GT_3trace(curTrace, GT_4CLASS, + "DMM Resource Info: DMM # %d " + "Mapped GPP Address:0X%lx, Size: 0X%lx\n", + tempCount, pDMMRes->ulMpuAddr, + pDMMRes->dmmSize); + pDMMRes = pDMMRes->next; + tempCount++; + } + if (tempCount == 1) + GT_0trace(curTrace, GT_4CLASS, + "\n ***There are no DMM resources" + " allocated by this Process***\n"); + tempCount = 1; + pSTRMRes = pCtxtList->pSTRMList; + while (pSTRMRes != NULL) { + if (tempCount == 1) + GT_0trace(curTrace, GT_4CLASS, + "\n***The Stream resources allocated by" + " this Process are***\n"); + GT_2trace(curTrace, GT_4CLASS, + "Stream Resource info: STRM # %d" + "Stream Handle:0X%x\n", tempCount, + (u32)pSTRMRes->hStream); + pSTRMRes = pSTRMRes->next; + tempCount++; + } + if (tempCount == 1) + GT_0trace(curTrace, GT_4CLASS, + "\n ***There are no Stream resources" + "allocated by this Process***\n"); + pCtxtList = pCtxtList->next; + } + return status; +} + +/* GPP PROCESS CLEANUP CODE END */ +#endif + +/* + * ======== = DRV_Create ======== = + * Purpose: + * DRV Object gets created only once during Driver Loading. + */ +DSP_STATUS DRV_Create(OUT struct DRV_OBJECT **phDRVObject) +{ + DSP_STATUS status = DSP_SOK; + struct DRV_OBJECT *pDRVObject = NULL; + + DBC_Require(phDRVObject != NULL); + DBC_Require(cRefs > 0); + GT_1trace(curTrace, GT_ENTER, "Entering DRV_Create" + " phDRVObject 0x%x\n", phDRVObject); + MEM_AllocObject(pDRVObject, struct DRV_OBJECT, SIGNATURE); + if (pDRVObject) { + /* Create and Initialize List of device objects */ + pDRVObject->devList = LST_Create(); + if (pDRVObject->devList) { + /* Create and Initialize List of device Extension */ + pDRVObject->devNodeString = LST_Create(); + if (!(pDRVObject->devNodeString)) { + status = DSP_EFAIL; + GT_0trace(curTrace, GT_7CLASS, + "Failed to Create DRV_EXT list "); + MEM_FreeObject(pDRVObject); + } + } else { + status = DSP_EFAIL; + GT_0trace(curTrace, GT_7CLASS, + "Failed to Create Dev List "); + MEM_FreeObject(pDRVObject); + } + } else { + status = DSP_EFAIL; + GT_0trace(curTrace, GT_7CLASS, + "Failed to Allocate Memory for DRV Obj"); + } + if (DSP_SUCCEEDED(status)) { + /* Store the DRV Object in the Registry */ + if (DSP_SUCCEEDED + (CFG_SetObject((u32) pDRVObject, REG_DRV_OBJECT))) { + GT_1trace(curTrace, GT_1CLASS, + "DRV Obj Created pDrvObject 0x%x\n ", + pDRVObject); + *phDRVObject = pDRVObject; + } else { + /* Free the DRV Object */ + status = DSP_EFAIL; + MEM_Free(pDRVObject); + GT_0trace(curTrace, GT_7CLASS, + "Failed to update the Registry with " + "DRV Object "); + } + } + GT_2trace(curTrace, GT_ENTER, + "Exiting DRV_Create: phDRVObject: 0x%x\tstatus:" + "0x%x\n", phDRVObject, status); + DBC_Ensure(DSP_FAILED(status) || + MEM_IsValidHandle(pDRVObject, SIGNATURE)); + return status; +} + +/* + * ======== DRV_Exit ======== + * Purpose: + * Discontinue usage of the DRV module. + */ +void DRV_Exit(void) +{ + DBC_Require(cRefs > 0); + + GT_0trace(curTrace, GT_5CLASS, "Entering DRV_Exit \n"); + + cRefs--; + + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== = DRV_Destroy ======== = + * purpose: + * Invoked during bridge de-initialization + */ +DSP_STATUS DRV_Destroy(struct DRV_OBJECT *hDRVObject) +{ + DSP_STATUS status = DSP_SOK; + struct DRV_OBJECT *pDRVObject = (struct DRV_OBJECT *)hDRVObject; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(pDRVObject, SIGNATURE)); + + GT_1trace(curTrace, GT_ENTER, "Entering DRV_Destroy" + " hDRVObject 0x%x\n", hDRVObject); + /* + * Delete the List if it exists.Should not come here + * as the DRV_RemoveDevObject and the Last DRV_RequestResources + * removes the list if the lists are empty. + */ + if (pDRVObject->devList) { + /* Could assert if the list is not empty */ + LST_Delete(pDRVObject->devList); + } + if (pDRVObject->devNodeString) { + /* Could assert if the list is not empty */ + LST_Delete(pDRVObject->devNodeString); + } + MEM_FreeObject(pDRVObject); + /* Update the DRV Object in Registry to be 0 */ + (void)CFG_SetObject(0, REG_DRV_OBJECT); + GT_2trace(curTrace, GT_ENTER, + "Exiting DRV_Destroy: hDRVObject: 0x%x\tstatus:" + "0x%x\n", hDRVObject, status); + DBC_Ensure(!MEM_IsValidHandle(pDRVObject, SIGNATURE)); + return status; +} + +/* + * ======== DRV_GetDevObject ======== + * Purpose: + * Given a index, returns a handle to DevObject from the list. + */ +DSP_STATUS DRV_GetDevObject(u32 uIndex, struct DRV_OBJECT *hDrvObject, + struct DEV_OBJECT **phDevObject) +{ + DSP_STATUS status = DSP_SOK; +#if GT_TRACE /* pDrvObject is used only for Assertions and debug messages.*/ + struct DRV_OBJECT *pDrvObject = (struct DRV_OBJECT *)hDrvObject; +#endif + struct DEV_OBJECT *pDevObject; + u32 i; + DBC_Require(MEM_IsValidHandle(pDrvObject, SIGNATURE)); + DBC_Require(phDevObject != NULL); + DBC_Require(uIndex >= 0); + DBC_Require(cRefs > 0); + DBC_Assert(!(LST_IsEmpty(pDrvObject->devList))); + GT_3trace(curTrace, GT_ENTER, + "Entered DRV_GetDevObject, args:\n\tuIndex: " + "0x%x\n\thDrvObject: 0x%x\n\tphDevObject: 0x%x\n", + uIndex, hDrvObject, phDevObject); + pDevObject = (struct DEV_OBJECT *)DRV_GetFirstDevObject(); + for (i = 0; i < uIndex; i++) { + pDevObject = + (struct DEV_OBJECT *)DRV_GetNextDevObject((u32)pDevObject); + } + if (pDevObject) { + *phDevObject = (struct DEV_OBJECT *) pDevObject; + status = DSP_SOK; + } else { + *phDevObject = NULL; + status = DSP_EFAIL; + GT_0trace(curTrace, GT_7CLASS, + "DRV: Could not get the DevObject\n"); + } + GT_2trace(curTrace, GT_ENTER, + "Exiting Drv_GetDevObject\n\tstatus: 0x%x\n\t" + "hDevObject: 0x%x\n", status, *phDevObject); + return status; +} + +/* + * ======== DRV_GetFirstDevObject ======== + * Purpose: + * Retrieve the first Device Object handle from an internal linked list of + * of DEV_OBJECTs maintained by DRV. + */ +u32 DRV_GetFirstDevObject(void) +{ + u32 dwDevObject = 0; + struct DRV_OBJECT *pDrvObject; + + if (DSP_SUCCEEDED + (CFG_GetObject((u32 *)&pDrvObject, REG_DRV_OBJECT))) { + if ((pDrvObject->devList != NULL) && + !LST_IsEmpty(pDrvObject->devList)) + dwDevObject = (u32) LST_First(pDrvObject->devList); + } + + return dwDevObject; +} + +/* + * ======== DRV_GetFirstDevNodeString ======== + * Purpose: + * Retrieve the first Device Extension from an internal linked list of + * of Pointer to DevNode Strings maintained by DRV. + */ +u32 DRV_GetFirstDevExtension(void) +{ + u32 dwDevExtension = 0; + struct DRV_OBJECT *pDrvObject; + + if (DSP_SUCCEEDED + (CFG_GetObject((u32 *)&pDrvObject, REG_DRV_OBJECT))) { + + if ((pDrvObject->devNodeString != NULL) && + !LST_IsEmpty(pDrvObject->devNodeString)) { + dwDevExtension = (u32)LST_First(pDrvObject-> + devNodeString); + } + } + + return dwDevExtension; +} + +/* + * ======== DRV_GetNextDevObject ======== + * Purpose: + * Retrieve the next Device Object handle from an internal linked list of + * of DEV_OBJECTs maintained by DRV, after having previously called + * DRV_GetFirstDevObject() and zero or more DRV_GetNext. + */ +u32 DRV_GetNextDevObject(u32 hDevObject) +{ + u32 dwNextDevObject = 0; + struct DRV_OBJECT *pDrvObject; + + DBC_Require(hDevObject != 0); + + if (DSP_SUCCEEDED + (CFG_GetObject((u32 *)&pDrvObject, REG_DRV_OBJECT))) { + + if ((pDrvObject->devList != NULL) && + !LST_IsEmpty(pDrvObject->devList)) { + dwNextDevObject = (u32)LST_Next(pDrvObject->devList, + (struct LST_ELEM *)hDevObject); + } + } + return dwNextDevObject; +} + +/* + * ======== DRV_GetNextDevExtension ======== + * Purpose: + * Retrieve the next Device Extension from an internal linked list of + * of pointer to DevNodeString maintained by DRV, after having previously + * called DRV_GetFirstDevExtension() and zero or more + * DRV_GetNextDevExtension(). + */ +u32 DRV_GetNextDevExtension(u32 hDevExtension) +{ + u32 dwDevExtension = 0; + struct DRV_OBJECT *pDrvObject; + + DBC_Require(hDevExtension != 0); + + if (DSP_SUCCEEDED(CFG_GetObject((u32 *)&pDrvObject, + REG_DRV_OBJECT))) { + if ((pDrvObject->devNodeString != NULL) && + !LST_IsEmpty(pDrvObject->devNodeString)) { + dwDevExtension = (u32)LST_Next(pDrvObject-> + devNodeString, + (struct LST_ELEM *)hDevExtension); + } + } + + return dwDevExtension; +} + +/* + * ======== DRV_Init ======== + * Purpose: + * Initialize DRV module private state. + */ +DSP_STATUS DRV_Init(void) +{ + s32 fRetval = 1; /* function return value */ + + DBC_Require(cRefs >= 0); + + if (fRetval) + cRefs++; + + GT_1trace(curTrace, GT_5CLASS, "Entering DRV_Entry crefs 0x%x \n", + cRefs); + + DBC_Ensure((fRetval && (cRefs > 0)) || (!fRetval && (cRefs >= 0))); + + return fRetval; +} + +/* + * ======== DRV_InsertDevObject ======== + * Purpose: + * Insert a DevObject into the list of Manager object. + */ +DSP_STATUS DRV_InsertDevObject(struct DRV_OBJECT *hDRVObject, + struct DEV_OBJECT *hDevObject) +{ + DSP_STATUS status = DSP_SOK; + struct DRV_OBJECT *pDRVObject = (struct DRV_OBJECT *)hDRVObject; + + DBC_Require(cRefs > 0); + DBC_Require(hDevObject != NULL); + DBC_Require(MEM_IsValidHandle(pDRVObject, SIGNATURE)); + DBC_Assert(pDRVObject->devList); + + GT_2trace(curTrace, GT_ENTER, + "Entering DRV_InsertProcObject hDRVObject " + "0x%x\n, hDevObject 0x%x\n", hDRVObject, hDevObject); + + LST_PutTail(pDRVObject->devList, (struct LST_ELEM *)hDevObject); + + GT_1trace(curTrace, GT_ENTER, + "Exiting InsertDevObject status 0x%x\n", status); + + DBC_Ensure(DSP_SUCCEEDED(status) && !LST_IsEmpty(pDRVObject->devList)); + + return status; +} + +/* + * ======== DRV_RemoveDevObject ======== + * Purpose: + * Search for and remove a DeviceObject from the given list of DRV + * objects. + */ +DSP_STATUS DRV_RemoveDevObject(struct DRV_OBJECT *hDRVObject, + struct DEV_OBJECT *hDevObject) +{ + DSP_STATUS status = DSP_EFAIL; + struct DRV_OBJECT *pDRVObject = (struct DRV_OBJECT *)hDRVObject; + struct LST_ELEM *pCurElem; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(pDRVObject, SIGNATURE)); + DBC_Require(hDevObject != NULL); + + DBC_Require(pDRVObject->devList != NULL); + DBC_Require(!LST_IsEmpty(pDRVObject->devList)); + + GT_2trace(curTrace, GT_ENTER, + "Entering DRV_RemoveDevObject hDevObject " + "0x%x\n, hDRVObject 0x%x\n", hDevObject, hDRVObject); + /* Search list for pProcObject: */ + for (pCurElem = LST_First(pDRVObject->devList); pCurElem != NULL; + pCurElem = LST_Next(pDRVObject->devList, pCurElem)) { + /* If found, remove it. */ + if ((struct DEV_OBJECT *) pCurElem == hDevObject) { + LST_RemoveElem(pDRVObject->devList, pCurElem); + status = DSP_SOK; + break; + } + } + /* Remove list if empty. */ + if (LST_IsEmpty(pDRVObject->devList)) { + LST_Delete(pDRVObject->devList); + pDRVObject->devList = NULL; + } + DBC_Ensure((pDRVObject->devList == NULL) || + !LST_IsEmpty(pDRVObject->devList)); + GT_1trace(curTrace, GT_ENTER, + "DRV_RemoveDevObject returning 0x%x\n", status); + return status; +} + +/* + * ======== DRV_RequestResources ======== + * Purpose: + * Requests resources from the OS. + */ +DSP_STATUS DRV_RequestResources(u32 dwContext, u32 *pDevNodeString) +{ + DSP_STATUS status = DSP_SOK; + struct DRV_OBJECT *pDRVObject; + struct DRV_EXT *pszdevNode; + + DBC_Require(dwContext != 0); + DBC_Require(pDevNodeString != NULL); + GT_0trace(curTrace, GT_ENTER, "Entering DRV_RequestResources\n"); + /* + * Allocate memory to hold the string. This will live untill + * it is freed in the Release resources. Update the driver object + * list. + */ + if (DSP_SUCCEEDED(CFG_GetObject((u32 *)&pDRVObject, + REG_DRV_OBJECT))) { + pszdevNode = MEM_Calloc(sizeof(struct DRV_EXT), MEM_NONPAGED); + if (pszdevNode) { + LST_InitElem(&pszdevNode->link); + strncpy((char *) pszdevNode->szString, + (char *)dwContext, MAXREGPATHLENGTH); + /* Update the Driver Object List */ + *pDevNodeString = (u32)pszdevNode->szString; + LST_PutTail(pDRVObject->devNodeString, + (struct LST_ELEM *)pszdevNode); + } else { + GT_0trace(curTrace, GT_7CLASS, + "Failed to Allocate Memory devNodeString "); + status = DSP_EFAIL; + *pDevNodeString = 0; + } + } else { + status = DSP_EFAIL; + GT_0trace(curTrace, GT_7CLASS, + "Failed to get Driver Object from Registry"); + *pDevNodeString = 0; + } + + if (!(strcmp((char *) dwContext, "TIOMAP1510"))) { + GT_0trace(curTrace, GT_1CLASS, + " Allocating resources for UMA \n"); + status = RequestBridgeResourcesDSP(dwContext, DRV_ASSIGN); + } else { + status = DSP_EFAIL; + GT_0trace(curTrace, GT_7CLASS, "Unknown Device "); + } + + if (DSP_FAILED(status)) { + GT_0trace(curTrace, GT_7CLASS, + "Failed to reserve bridge resources "); + } + DBC_Ensure((DSP_SUCCEEDED(status) && pDevNodeString != NULL && + !LST_IsEmpty(pDRVObject->devNodeString)) || + (DSP_FAILED(status) && *pDevNodeString == 0)); + + return status; +} + +/* + * ======== DRV_ReleaseResources ======== + * Purpose: + * Releases resources from the OS. + */ +DSP_STATUS DRV_ReleaseResources(u32 dwContext, struct DRV_OBJECT *hDrvObject) +{ + DSP_STATUS status = DSP_SOK; + struct DRV_OBJECT *pDRVObject = (struct DRV_OBJECT *)hDrvObject; + struct DRV_EXT *pszdevNode; + + GT_0trace(curTrace, GT_ENTER, "Entering DRV_Release Resources\n"); + + if (!(strcmp((char *)((struct DRV_EXT *)dwContext)->szString, + "TIOMAP1510"))) { + GT_0trace(curTrace, GT_1CLASS, + " Releasing DSP-Bridge resources \n"); + status = RequestBridgeResources(dwContext, DRV_RELEASE); + } else { + GT_0trace(curTrace, GT_1CLASS, " Unknown device\n"); + } + + if (DSP_SUCCEEDED(status)) { + GT_0trace(curTrace, GT_1CLASS, + "Failed to relese bridge resources\n"); + } + + /* + * Irrespective of the status go ahead and clean it + * The following will over write the status. + */ + for (pszdevNode = (struct DRV_EXT *)DRV_GetFirstDevExtension(); + pszdevNode != NULL; pszdevNode = (struct DRV_EXT *) + DRV_GetNextDevExtension((u32)pszdevNode)) { + if ((u32)pszdevNode == dwContext) { + /* Found it */ + /* Delete from the Driver object list */ + LST_RemoveElem(pDRVObject->devNodeString, + (struct LST_ELEM *)pszdevNode); + MEM_Free((void *) pszdevNode); + break; + } + /* Delete the List if it is empty */ + if (LST_IsEmpty(pDRVObject->devNodeString)) { + LST_Delete(pDRVObject->devNodeString); + pDRVObject->devNodeString = NULL; + } + } + return status; +} + +/* + * ======== RequestBridgeResources ======== + * Purpose: + * Reserves shared memory for bridge. + */ +static DSP_STATUS RequestBridgeResources(u32 dwContext, s32 bRequest) +{ + DSP_STATUS status = DSP_SOK; + struct CFG_HOSTRES *pResources; + u32 dwBuffSize; + + struct DRV_EXT *driverExt; + u32 shm_size; + + DBC_Require(dwContext != 0); + + GT_0trace(curTrace, GT_ENTER, "->RequestBridgeResources \n"); + + if (!bRequest) { + driverExt = (struct DRV_EXT *)dwContext; + /* Releasing resources by deleting the registry key */ + dwBuffSize = sizeof(struct CFG_HOSTRES); + pResources = MEM_Calloc(dwBuffSize, MEM_NONPAGED); + if (DSP_FAILED(REG_GetValue(NULL, (char *)driverExt->szString, + CURRENTCONFIG, (u8 *)pResources, &dwBuffSize))) { + status = CFG_E_RESOURCENOTAVAIL; + GT_0trace(curTrace, GT_1CLASS, + "REG_GetValue Failed \n"); + } else { + GT_0trace(curTrace, GT_1CLASS, + "REG_GetValue Succeeded \n"); + } + + if (pResources != NULL) { + dwBuffSize = sizeof(shm_size); + status = REG_GetValue(NULL, CURRENTCONFIG, SHMSIZE, + (u8 *)&shm_size, &dwBuffSize); + if (DSP_SUCCEEDED(status)) { + if ((pResources->dwMemBase[1]) && + (pResources->dwMemPhys[1])) { + MEM_FreePhysMem((void *)pResources-> + dwMemBase[1], pResources->dwMemPhys[1], + shm_size); + } + } else { + GT_1trace(curTrace, GT_7CLASS, + "Error getting SHM size from registry: " + "%x. Not calling MEM_FreePhysMem\n", + status); + } + pResources->dwMemBase[1] = 0; + pResources->dwMemPhys[1] = 0; + + if (pResources->dwPrmBase) + iounmap((void *)pResources->dwPrmBase); + if (pResources->dwCmBase) + iounmap((void *)pResources->dwCmBase); + if (pResources->dwMboxBase) + iounmap((void *)pResources->dwMboxBase); + if (pResources->dwMemBase[0]) + iounmap((void *)pResources->dwMemBase[0]); + if (pResources->dwMemBase[2]) + iounmap((void *)pResources->dwMemBase[2]); + if (pResources->dwMemBase[3]) + iounmap((void *)pResources->dwMemBase[3]); + if (pResources->dwMemBase[4]) + iounmap((void *)pResources->dwMemBase[4]); + if (pResources->dwWdTimerDspBase) + iounmap((void *)pResources->dwWdTimerDspBase); + if (pResources->dwDmmuBase) + iounmap((void *)pResources->dwDmmuBase); + if (pResources->dwPerBase) + iounmap((void *)pResources->dwPerBase); + if (pResources->dwPerPmBase) + iounmap((void *)pResources->dwPerPmBase); + if (pResources->dwCorePmBase) + iounmap((void *)pResources->dwCorePmBase); + if (pResources->dwSysCtrlBase) { + iounmap((void *)pResources->dwSysCtrlBase); + /* don't set pResources->dwSysCtrlBase to null + * as it is used in BOARD_Stop */ + } + pResources->dwPrmBase = (u32) NULL; + pResources->dwCmBase = (u32) NULL; + pResources->dwMboxBase = (u32) NULL; + pResources->dwMemBase[0] = (u32) NULL; + pResources->dwMemBase[2] = (u32) NULL; + pResources->dwMemBase[3] = (u32) NULL; + pResources->dwMemBase[4] = (u32) NULL; + pResources->dwWdTimerDspBase = (u32) NULL; + pResources->dwDmmuBase = (u32) NULL; + + dwBuffSize = sizeof(struct CFG_HOSTRES); + status = REG_SetValue(NULL, (char *)driverExt->szString, + CURRENTCONFIG, REG_BINARY, (u8 *)pResources, + (u32)dwBuffSize); + /* Set all the other entries to NULL */ + MEM_Free(pResources); + } + GT_0trace(curTrace, GT_ENTER, " <- RequestBridgeResources \n"); + return status; + } + dwBuffSize = sizeof(struct CFG_HOSTRES); + pResources = MEM_Calloc(dwBuffSize, MEM_NONPAGED); + if (pResources != NULL) { + /* wNumMemWindows must not be more than CFG_MAXMEMREGISTERS */ + pResources->wNumMemWindows = 2; + /* First window is for DSP internal memory */ + + pResources->dwPrmBase = (u32)ioremap(OMAP_IVA2_PRM_BASE, + OMAP_IVA2_PRM_SIZE); + pResources->dwCmBase = (u32)ioremap(OMAP_IVA2_CM_BASE, + OMAP_IVA2_CM_SIZE); + pResources->dwMboxBase = (u32)ioremap(OMAP_MBOX_BASE, + OMAP_MBOX_SIZE); + pResources->dwSysCtrlBase = (u32)ioremap(OMAP_SYSC_BASE, + OMAP_SYSC_SIZE); + GT_1trace(curTrace, GT_2CLASS, "dwMemBase[0] 0x%x\n", + pResources->dwMemBase[0]); + GT_1trace(curTrace, GT_2CLASS, "dwMemBase[3] 0x%x\n", + pResources->dwMemBase[3]); + GT_1trace(curTrace, GT_2CLASS, "dwPrmBase 0x%x\n", + pResources->dwPrmBase); + GT_1trace(curTrace, GT_2CLASS, "dwCmBase 0x%x\n", + pResources->dwCmBase); + GT_1trace(curTrace, GT_2CLASS, "dwWdTimerDspBase 0x%x\n", + pResources->dwWdTimerDspBase); + GT_1trace(curTrace, GT_2CLASS, "dwMboxBase 0x%x\n", + pResources->dwMboxBase); + GT_1trace(curTrace, GT_2CLASS, "dwDmmuBase 0x%x\n", + pResources->dwDmmuBase); + + /* for 24xx base port is not mapping the mamory for DSP + * internal memory TODO Do a ioremap here */ + /* Second window is for DSP external memory shared with MPU */ + if (DSP_SUCCEEDED(status)) { + /* for Linux, these are hard-coded values */ + pResources->dwBusType = 0; + pResources->bIRQRegisters = 0; + pResources->bIRQAttrib = 0; + pResources->dwOffsetForMonitor = 0; + pResources->dwChnlOffset = 0; + /* CHNL_MAXCHANNELS */ + pResources->dwNumChnls = CHNL_MAXCHANNELS; + pResources->dwChnlBufSize = 0x400; + dwBuffSize = sizeof(struct CFG_HOSTRES); + status = REG_SetValue(NULL, (char *) dwContext, + CURRENTCONFIG, REG_BINARY, + (u8 *)pResources, + sizeof(struct CFG_HOSTRES)); + if (DSP_SUCCEEDED(status)) { + GT_0trace(curTrace, GT_1CLASS, + " Successfully set the registry " + "value for CURRENTCONFIG\n"); + } else { + GT_0trace(curTrace, GT_7CLASS, + " Failed to set the registry " + "value for CURRENTCONFIG\n"); + } + } + MEM_Free(pResources); + } + /* End Mem alloc */ + return status; +} + +/* + * ======== RequestBridgeResourcesDSP ======== + * Purpose: + * Reserves shared memory for bridge. + */ +static DSP_STATUS RequestBridgeResourcesDSP(u32 dwContext, s32 bRequest) +{ + DSP_STATUS status = DSP_SOK; + struct CFG_HOSTRES *pResources; + u32 dwBuffSize; + u32 dmaAddr; + u32 shm_size; + + DBC_Require(dwContext != 0); + + GT_0trace(curTrace, GT_ENTER, "->RequestBridgeResourcesDSP \n"); + + dwBuffSize = sizeof(struct CFG_HOSTRES); + + pResources = MEM_Calloc(dwBuffSize, MEM_NONPAGED); + + if (pResources != NULL) { + if (DSP_FAILED(CFG_GetHostResources((struct CFG_DEVNODE *) + dwContext, pResources))) { + /* Call CFG_GetHostResources to get reserve resouces */ + status = RequestBridgeResources(dwContext, bRequest); + if (DSP_SUCCEEDED(status)) { + status = CFG_GetHostResources + ((struct CFG_DEVNODE *) dwContext, + pResources); + } + } + /* wNumMemWindows must not be more than CFG_MAXMEMREGISTERS */ + pResources->wNumMemWindows = 4; + + pResources->dwMemBase[0] = 0; + pResources->dwMemBase[2] = (u32)ioremap(OMAP_DSP_MEM1_BASE, + OMAP_DSP_MEM1_SIZE); + pResources->dwMemBase[3] = (u32)ioremap(OMAP_DSP_MEM2_BASE, + OMAP_DSP_MEM2_SIZE); + pResources->dwMemBase[4] = (u32)ioremap(OMAP_DSP_MEM3_BASE, + OMAP_DSP_MEM3_SIZE); + pResources->dwPerBase = (u32)ioremap(OMAP_PER_CM_BASE, + OMAP_PER_CM_SIZE); + pResources->dwPerPmBase = (u32)ioremap(OMAP_PER_PRM_BASE, + OMAP_PER_PRM_SIZE); + pResources->dwCorePmBase = (u32)ioremap(OMAP_CORE_PRM_BASE, + OMAP_CORE_PRM_SIZE); + pResources->dwDmmuBase = (u32)ioremap(OMAP_DMMU_BASE, + OMAP_DMMU_SIZE); + pResources->dwWdTimerDspBase = 0; + + GT_1trace(curTrace, GT_2CLASS, "dwMemBase[0] 0x%x\n", + pResources->dwMemBase[0]); + GT_1trace(curTrace, GT_2CLASS, "dwMemBase[1] 0x%x\n", + pResources->dwMemBase[1]); + GT_1trace(curTrace, GT_2CLASS, "dwMemBase[2] 0x%x\n", + pResources->dwMemBase[2]); + GT_1trace(curTrace, GT_2CLASS, "dwMemBase[3] 0x%x\n", + pResources->dwMemBase[3]); + GT_1trace(curTrace, GT_2CLASS, "dwMemBase[4] 0x%x\n", + pResources->dwMemBase[4]); + GT_1trace(curTrace, GT_2CLASS, "dwPrmBase 0x%x\n", + pResources->dwPrmBase); + GT_1trace(curTrace, GT_2CLASS, "dwCmBase 0x%x\n", + pResources->dwCmBase); + GT_1trace(curTrace, GT_2CLASS, "dwWdTimerDspBase 0x%x\n", + pResources->dwWdTimerDspBase); + GT_1trace(curTrace, GT_2CLASS, "dwMboxBase 0x%x\n", + pResources->dwMboxBase); + GT_1trace(curTrace, GT_2CLASS, "dwDmmuBase 0x%x\n", + pResources->dwDmmuBase); + dwBuffSize = sizeof(shm_size); + status = REG_GetValue(NULL, CURRENTCONFIG, SHMSIZE, + (u8 *)&shm_size, &dwBuffSize); + if (DSP_SUCCEEDED(status)) { + /* Allocate Physically contiguous, + * non-cacheable memory */ + pResources->dwMemBase[1] = + (u32)MEM_AllocPhysMem(shm_size, 0x100000, + &dmaAddr); + if (pResources->dwMemBase[1] == 0) { + status = DSP_EMEMORY; + GT_0trace(curTrace, GT_7CLASS, + "SHM reservation Failed\n"); + } else { + pResources->dwMemLength[1] = shm_size; + pResources->dwMemPhys[1] = dmaAddr; + + GT_3trace(curTrace, GT_1CLASS, + "Bridge SHM address 0x%x dmaAddr" + " %x size %x\n", + pResources->dwMemBase[1], + dmaAddr, shm_size); + } + } + if (DSP_SUCCEEDED(status)) { + /* for Linux, these are hard-coded values */ + pResources->dwBusType = 0; + pResources->bIRQRegisters = 0; + pResources->bIRQAttrib = 0; + pResources->dwOffsetForMonitor = 0; + pResources->dwChnlOffset = 0; + /* CHNL_MAXCHANNELS */ + pResources->dwNumChnls = CHNL_MAXCHANNELS; + pResources->dwChnlBufSize = 0x400; + dwBuffSize = sizeof(struct CFG_HOSTRES); + status = REG_SetValue(NULL, (char *)dwContext, + CURRENTCONFIG, REG_BINARY, + (u8 *)pResources, + sizeof(struct CFG_HOSTRES)); + if (DSP_SUCCEEDED(status)) { + GT_0trace(curTrace, GT_1CLASS, + " Successfully set the registry" + " value for CURRENTCONFIG\n"); + } else { + GT_0trace(curTrace, GT_7CLASS, + " Failed to set the registry value" + " for CURRENTCONFIG\n"); + } + } + MEM_Free(pResources); + } + /* End Mem alloc */ + return status; +} diff --git a/drivers/dsp/bridge/rmgr/drv_interface.c b/drivers/dsp/bridge/rmgr/drv_interface.c new file mode 100644 index 0000000..4aa7de6 --- /dev/null +++ b/drivers/dsp/bridge/rmgr/drv_interface.c @@ -0,0 +1,777 @@ +/* + * drv_interface.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== linux_driver.c ======== + * Description: + * DSP/BIOS Bridge driver interface. + * + * Public Functions: + * driver_init + * driver_exit + * driver_open + * driver_release + * driver_ioctl + * driver_mmap + * + *! Revision History + *! ================ + *! 21-Apr-2004 map Deprecated use of MODULE_PARM for kernel versions + *! greater than 2.5, use module_param. + *! 08-Mar-2004 sb Added the dsp_debug argument, which keeps the DSP in self + *! loop after image load and waits in a loop for DSP to start + *! 16-Feb-2004 vp Deprecated the usage of MOD_INC_USE_COUNT and + *! MOD_DEC_USE_COUNT + *! for kernel versions greater than 2.5 + *! 20-May-2003 vp Added unregister functions for the DPM. + *! 24-Mar-2003 sb Pass pid instead of driverContext to DSP_Close + *! 24-Mar-2003 vp Added Power Management support. + *! 21-Mar-2003 sb Configure SHM size using insmod argument shm_size + *! 10-Feb-2003 vp Updated based on code review comments + *! 18-Oct-2002 sb Created initial version + */ + +/* ----------------------------------- Host OS */ + +#include +#include +#include + +#ifdef MODULE +#include +#endif + +#include +#include +#include +#include + +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include + +/* ----------------------------------- Platform Manager */ +#include +#include +#include +#include + +/* ----------------------------------- Resource Manager */ +#include + +/* ----------------------------------- This */ +#include + +#ifndef RES_CLEANUP_DISABLE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#ifdef CONFIG_BRIDGE_DVFS +#include +#include +#endif + +#define BRIDGE_NAME "C6410" +/* ----------------------------------- Globals */ +#define DRIVER_NAME "DspBridge" +#define DRIVER_MAJOR 0 /* Linux assigns our Major device number */ +#define DRIVER_MINOR 0 /* Linux assigns our Major device number */ +s32 dsp_debug; + +struct platform_device *omap_dspbridge_dev; + +struct bridge_dev { + struct cdev cdev; +}; + +static struct bridge_dev *bridge_device; + +static struct class *bridge_class; + +static u32 driverContext; +#ifdef CONFIG_BRIDGE_DEBUG +static char *GT_str; +#endif /* CONFIG_BRIDGE_DEBUG */ +static s32 driver_major = DRIVER_MAJOR; +static s32 driver_minor = DRIVER_MINOR; +static char *base_img; +char *iva_img; +static char *num_procs = "C55=1"; +static s32 shm_size = 0x400000; /* 4 MB */ +static u32 phys_mempool_base; +static u32 phys_mempool_size; +static int tc_wordswapon; /* Default value is always false */ + +#ifdef CONFIG_PM +struct omap34xx_bridge_suspend_data { + int suspended; + wait_queue_head_t suspend_wq; +}; + +static struct omap34xx_bridge_suspend_data bridge_suspend_data; + +static int omap34xxbridge_suspend_lockout( + struct omap34xx_bridge_suspend_data *s, struct file *f) +{ + if ((s)->suspended) { + if ((f)->f_flags & O_NONBLOCK) + return DSP_EDPMSUSPEND; + wait_event_interruptible((s)->suspend_wq, (s)->suspended == 0); + } + return 0; +} + +#endif + +#ifdef DEBUG +module_param(GT_str, charp, 0); +MODULE_PARM_DESC(GT_str, "GT string, default = NULL"); + +module_param(dsp_debug, int, 0); +MODULE_PARM_DESC(dsp_debug, "Wait after loading DSP image. default = false"); +#endif + +module_param(driver_major, int, 0); /* Driver's major number */ +MODULE_PARM_DESC(driver_major, "Major device number, default = 0 (auto)"); + +module_param(driver_minor, int, 0); /* Driver's major number */ +MODULE_PARM_DESC(driver_minor, "Minor device number, default = 0 (auto)"); + +module_param(base_img, charp, 0); +MODULE_PARM_DESC(base_img, "DSP base image, default = NULL"); + +module_param(shm_size, int, 0); +MODULE_PARM_DESC(shm_size, "SHM size, default = 4 MB, minimum = 64 KB"); + +module_param(phys_mempool_base, uint, 0); +MODULE_PARM_DESC(phys_mempool_base, + "Physical memory pool base passed to driver"); + +module_param(phys_mempool_size, uint, 0); +MODULE_PARM_DESC(phys_mempool_size, + "Physical memory pool size passed to driver"); +module_param(tc_wordswapon, int, 0); +MODULE_PARM_DESC(tc_wordswapon, "TC Word Swap Option. default = 0"); + +MODULE_AUTHOR("Texas Instruments"); +MODULE_LICENSE("GPL"); + +static char *driver_name = DRIVER_NAME; + +#ifdef CONFIG_BRIDGE_DEBUG +static struct GT_Mask driverTrace; +#endif /* CONFIG_BRIDGE_DEBUG */ + +static struct file_operations bridge_fops = { + .open = bridge_open, + .release = bridge_release, + .ioctl = bridge_ioctl, + .mmap = bridge_mmap, +}; + +#ifdef CONFIG_PM +static u32 timeOut = 1000; +#ifdef CONFIG_BRIDGE_DVFS +static struct clk *clk_handle; +s32 dsp_max_opps = VDD1_OPP3; +#endif + +/* Maximum Opps that can be requested by IVA*/ +/*vdd1 rate table*/ +#ifdef CONFIG_BRIDGE_DVFS +const struct omap_opp vdd1_rate_table_bridge[] = { + {0, 0, 0}, + /*OPP1*/ + {S125M, VDD1_OPP1, 0}, + /*OPP2*/ + {S250M, VDD1_OPP2, 0}, + /*OPP3*/ + {S500M, VDD1_OPP3, 0}, + /*OPP4*/ + {S550M, VDD1_OPP4, 0}, + /*OPP5*/ + {S600M, VDD1_OPP5, 0}, +}; +#endif +#endif + +struct dspbridge_platform_data *omap_dspbridge_pdata; + +u32 vdd1_dsp_freq[6][4] = { + {0, 0, 0, 0}, + /*OPP1*/ + {0, 90000, 0, 86000}, + /*OPP2*/ + {0, 180000, 80000, 170000}, + /*OPP3*/ + {0, 360000, 160000, 340000}, + /*OPP4*/ + {0, 396000, 325000, 376000}, + /*OPP5*/ + {0, 430000, 355000, 430000}, +}; + +#ifdef CONFIG_BRIDGE_DVFS +static int dspbridge_post_scale(struct notifier_block *op, unsigned long level, + void *ptr) +{ + PWR_PM_PostScale(PRCM_VDD1, level); + return 0; +} + +static struct notifier_block iva_clk_notifier = { + .notifier_call = dspbridge_post_scale, + NULL, +}; +#endif + +static int __devinit omap34xx_bridge_probe(struct platform_device *pdev) +{ + int status; + u32 initStatus; + u32 temp; + dev_t dev = 0 ; + int result; +#ifdef CONFIG_BRIDGE_DVFS + int i = 0; +#endif + struct dspbridge_platform_data *pdata = pdev->dev.platform_data; + + omap_dspbridge_dev = pdev; + + /* use 2.6 device model */ + if (driver_major) { + dev = MKDEV(driver_major, driver_minor); + result = register_chrdev_region(dev, 1, driver_name); + } else { + result = alloc_chrdev_region(&dev, driver_minor, 1, + driver_name); + driver_major = MAJOR(dev); + } + + if (result < 0) { + GT_1trace(driverTrace, GT_7CLASS, "bridge_init: " + "Can't get Major %d \n", driver_major); + return result; + } + + bridge_device = kmalloc(sizeof(struct bridge_dev), GFP_KERNEL); + if (!bridge_device) { + result = -ENOMEM; + unregister_chrdev_region(dev, 1); + return result; + } + memset(bridge_device, 0, sizeof(struct bridge_dev)); + cdev_init(&bridge_device->cdev, &bridge_fops); + bridge_device->cdev.owner = THIS_MODULE; + bridge_device->cdev.ops = &bridge_fops; + + status = cdev_add(&bridge_device->cdev, dev, 1); + + if (status) { + GT_0trace(driverTrace, GT_7CLASS, + "Failed to add the bridge device \n"); + return status; + } + + /* udev support */ + bridge_class = class_create(THIS_MODULE, "ti_bridge"); + + if (IS_ERR(bridge_class)) + GT_0trace(driverTrace, GT_7CLASS, + "Error creating bridge class \n"); + + device_create(bridge_class, NULL, MKDEV(driver_major, driver_minor), + NULL, "DspBridge"); + + GT_init(); + GT_create(&driverTrace, "LD"); + +#ifdef DEBUG + if (GT_str) + GT_set(GT_str); +#elif defined(DDSP_DEBUG_PRODUCT) && GT_TRACE + GT_set("**=67"); +#endif + + GT_0trace(driverTrace, GT_ENTER, "-> driver_init\n"); + +#ifdef CONFIG_PM + /* Initialize the wait queue */ + if (!status) { + bridge_suspend_data.suspended = 0; + init_waitqueue_head(&bridge_suspend_data.suspend_wq); + } +#endif + + SERVICES_Init(); + + /* Autostart flag. This should be set to true if the DSP image should + * be loaded and run during bridge module initialization */ + + if (base_img) { + temp = true; + REG_SetValue(NULL, NULL, AUTOSTART, REG_DWORD, (u8 *)&temp, + sizeof(temp)); + REG_SetValue(NULL, NULL, DEFEXEC, REG_SZ, (u8 *)base_img, + strlen(base_img) + 1); + } else { + temp = false; + REG_SetValue(NULL, NULL, AUTOSTART, REG_DWORD, (u8 *)&temp, + sizeof(temp)); + REG_SetValue(NULL, NULL, DEFEXEC, REG_SZ, (u8 *) "\0", (u32)2); + } + REG_SetValue(NULL, NULL, NUMPROCS, REG_SZ, (u8 *) num_procs, + strlen(num_procs) + 1); + + if (shm_size >= 0x10000) { /* 64 KB */ + initStatus = REG_SetValue(NULL, NULL, SHMSIZE, REG_DWORD, + (u8 *)&shm_size, sizeof(shm_size)); + } else { + initStatus = DSP_EINVALIDARG; + status = -1; + GT_0trace(driverTrace, GT_7CLASS, + "SHM size must be at least 64 KB\n"); + } + GT_1trace(driverTrace, GT_7CLASS, + "requested shm_size = 0x%x\n", shm_size); + + if (pdata->phys_mempool_base && pdata->phys_mempool_size) { + phys_mempool_base = pdata->phys_mempool_base; + phys_mempool_size = pdata->phys_mempool_size; + } + + if (phys_mempool_base > 0x0) { + initStatus = REG_SetValue(NULL, NULL, PHYSMEMPOOLBASE, + REG_DWORD, (u8 *)&phys_mempool_base, + sizeof(phys_mempool_base)); + } + GT_1trace(driverTrace, GT_7CLASS, "phys_mempool_base = 0x%x \n", + phys_mempool_base); + + if (phys_mempool_size > 0x0) { + initStatus = REG_SetValue(NULL, NULL, PHYSMEMPOOLSIZE, + REG_DWORD, (u8 *)&phys_mempool_size, + sizeof(phys_mempool_size)); + } + GT_1trace(driverTrace, GT_7CLASS, "phys_mempool_size = 0x%x\n", + phys_mempool_base); + if ((phys_mempool_base > 0x0) && (phys_mempool_size > 0x0)) + MEM_ExtPhysPoolInit(phys_mempool_base, phys_mempool_size); + if (tc_wordswapon) { + GT_0trace(driverTrace, GT_7CLASS, "TC Word Swap is enabled\n"); + REG_SetValue(NULL, NULL, TCWORDSWAP, REG_DWORD, + (u8 *)&tc_wordswapon, sizeof(tc_wordswapon)); + } else { + GT_0trace(driverTrace, GT_7CLASS, "TC Word Swap is disabled\n"); + REG_SetValue(NULL, NULL, TCWORDSWAP, + REG_DWORD, (u8 *)&tc_wordswapon, + sizeof(tc_wordswapon)); + } + if (DSP_SUCCEEDED(initStatus)) { +#ifdef CONFIG_BRIDGE_DVFS + for (i = 0; i < 6; i++) + pdata->mpu_speed[i] = vdd1_rate_table_bridge[i].rate; + + clk_handle = clk_get(NULL, "iva2_ck"); + if (!clk_handle) { + GT_0trace(driverTrace, GT_7CLASS, + "clk_get failed to get iva2_ck \n"); + } else { + GT_0trace(driverTrace, GT_7CLASS, + "clk_get PASS to get iva2_ck \n"); + } + if (!clk_notifier_register(clk_handle, &iva_clk_notifier)) { + GT_0trace(driverTrace, GT_7CLASS, + "clk_notifier_register PASS for iva2_ck \n"); + } else { + GT_0trace(driverTrace, GT_7CLASS, + "clk_notifier_register FAIL for iva2_ck \n"); + } +#endif + driverContext = DSP_Init(&initStatus); + if (DSP_FAILED(initStatus)) { + status = -1; + GT_0trace(driverTrace, GT_7CLASS, + "DSP/BIOS Bridge initialization Failed\n"); + } else { + GT_0trace(driverTrace, GT_5CLASS, + "DSP/BIOS Bridge driver loaded\n"); + } + } + + DBC_Assert(status == 0); + DBC_Assert(DSP_SUCCEEDED(initStatus)); + GT_0trace(driverTrace, GT_ENTER, " <- driver_init\n"); + return status; +} + +static int __devexit omap34xx_bridge_remove(struct platform_device *pdev) +{ + dev_t devno; + bool ret; + DSP_STATUS dsp_status = DSP_SOK; + HANDLE hDrvObject = NULL; + struct PROCESS_CONTEXT *pTmp = NULL; + struct PROCESS_CONTEXT *pCtxtclosed = NULL; + struct PROCESS_CONTEXT *pCtxttraverse = NULL; + + GT_0trace(driverTrace, GT_ENTER, "-> driver_exit\n"); + + dsp_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); + DRV_GetProcCtxtList(&pCtxtclosed, (struct DRV_OBJECT *)hDrvObject); + while (pCtxtclosed != NULL) { + DRV_RemoveAllResources(pCtxtclosed); + if (pCtxtclosed->hProcessor != NULL) { + DRV_GetProcCtxtList(&pCtxttraverse, + (struct DRV_OBJECT *)hDrvObject); + if (pCtxttraverse->next == NULL) { + PROC_Detach(pCtxtclosed->hProcessor); + goto func_cont; + } + if ((pCtxtclosed->pid == pCtxttraverse->pid) && + (pCtxttraverse->next != NULL)) { + pCtxttraverse = pCtxttraverse->next; + } + while ((pCtxttraverse != NULL) && + (pCtxtclosed->hProcessor + != pCtxttraverse->hProcessor)) { + pCtxttraverse = pCtxttraverse->next; + if ((pCtxttraverse != NULL) && + (pCtxtclosed->pid == pCtxttraverse->pid)) { + pCtxttraverse = pCtxttraverse->next; + } + } + if (pCtxttraverse == NULL) + PROC_Detach(pCtxtclosed->hProcessor); + } +func_cont: + pTmp = pCtxtclosed->next; + DRV_RemoveProcContext((struct DRV_OBJECT *)hDrvObject, + pCtxtclosed, (void *)pCtxtclosed->pid); + pCtxtclosed = pTmp; + } + + /* unregister the clock notifier */ +#ifdef CONFIG_BRIDGE_DVFS + if (!clk_notifier_unregister(clk_handle, &iva_clk_notifier)) { + GT_0trace(driverTrace, GT_7CLASS, + "clk_notifier_unregister PASS for iva2_ck \n"); + } else { + GT_0trace(driverTrace, GT_7CLASS, + "clk_notifier_unregister PASS for iva2_ck \n"); + } + + clk_put(clk_handle); + clk_handle = NULL; +#endif /* #ifdef CONFIG_BRIDGE_DVFS */ + + if (driverContext) { + ret = DSP_Deinit(driverContext); + driverContext = 0; + + DBC_Assert(ret == true); + } + SERVICES_Exit(); + GT_exit(); + + devno = MKDEV(driver_major, driver_minor); + if (bridge_device) { + cdev_del(&bridge_device->cdev); + kfree(bridge_device); + } + unregister_chrdev_region(devno, 1); + if (bridge_class) { + /* remove the device from sysfs */ + device_destroy(bridge_class, MKDEV(driver_major, driver_minor)); + class_destroy(bridge_class); + + } + return 0; +} + + +#ifdef CONFIG_PM +static int bridge_suspend(struct platform_device *pdev, pm_message_t state) +{ + u32 status; + u32 command = PWR_EMERGENCYDEEPSLEEP; + + status = PWR_SleepDSP(command, timeOut); + if (DSP_FAILED(status)) + return -1; + + bridge_suspend_data.suspended = 1; + return 0; +} + +static int bridge_resume(struct platform_device *pdev) +{ + u32 status; + + status = PWR_WakeDSP(timeOut); + if (DSP_FAILED(status)) + return -1; + + bridge_suspend_data.suspended = 0; + wake_up(&bridge_suspend_data.suspend_wq); + return 0; +} +#else +#define bridge_suspend NULL +#define bridge_resume NULL +#endif + +static struct platform_driver bridge_driver = { + .driver = { + .name = BRIDGE_NAME, + }, + .probe = omap34xx_bridge_probe, + .remove = __devexit_p(omap34xx_bridge_remove), + .suspend = bridge_suspend, + .resume = bridge_resume, +}; + +static int __init bridge_init(void) +{ + return platform_driver_register(&bridge_driver); +} + +static void __exit bridge_exit(void) +{ + platform_driver_unregister(&bridge_driver); +} + +/* This function is called when an application opens handle to the + * bridge driver. */ + +static int bridge_open(struct inode *ip, struct file *filp) +{ + int status = 0; +#ifndef RES_CLEANUP_DISABLE + u32 hProcess; + DSP_STATUS dsp_status = DSP_SOK; + HANDLE hDrvObject = NULL; + struct PROCESS_CONTEXT *pPctxt = NULL; + struct PROCESS_CONTEXT *next_node = NULL; + struct PROCESS_CONTEXT *pCtxtclosed = NULL; + struct PROCESS_CONTEXT *pCtxttraverse = NULL; + struct task_struct *tsk = NULL; + GT_0trace(driverTrace, GT_ENTER, "-> driver_open\n"); + dsp_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); + + /* Checking weather task structure for all process existing + * in the process context list If not removing those processes*/ + if (DSP_FAILED(dsp_status)) + goto func_cont; + + DRV_GetProcCtxtList(&pCtxtclosed, (struct DRV_OBJECT *)hDrvObject); + while (pCtxtclosed != NULL) { + tsk = find_task_by_vpid(pCtxtclosed->pid); + next_node = pCtxtclosed->next; + + if ((tsk == NULL) || (tsk->exit_state == EXIT_ZOMBIE)) { + + GT_1trace(driverTrace, GT_5CLASS, + "***Task structure not existing for " + "process***%d\n", pCtxtclosed->pid); + DRV_RemoveAllResources(pCtxtclosed); + if (pCtxtclosed->hProcessor != NULL) { + DRV_GetProcCtxtList(&pCtxttraverse, + (struct DRV_OBJECT *)hDrvObject); + if (pCtxttraverse->next == NULL) { + PROC_Detach(pCtxtclosed->hProcessor); + } else { + if ((pCtxtclosed->pid == + pCtxttraverse->pid) && + (pCtxttraverse->next != NULL)) { + pCtxttraverse = + pCtxttraverse->next; + } + while ((pCtxttraverse != NULL) && + (pCtxtclosed->hProcessor + != pCtxttraverse->hProcessor)) { + pCtxttraverse = + pCtxttraverse->next; + if ((pCtxttraverse != NULL) && + (pCtxtclosed->pid == + pCtxttraverse->pid)) { + pCtxttraverse = + pCtxttraverse->next; + } + } + if (pCtxttraverse == NULL) { + PROC_Detach + (pCtxtclosed->hProcessor); + } + } + } + DRV_RemoveProcContext((struct DRV_OBJECT *)hDrvObject, + pCtxtclosed, + (void *)pCtxtclosed->pid); + } + pCtxtclosed = next_node; + } +func_cont: + dsp_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); + if (DSP_SUCCEEDED(dsp_status)) + dsp_status = DRV_InsertProcContext( + (struct DRV_OBJECT *)hDrvObject, &pPctxt); + + if (pPctxt != NULL) { + /* Return PID instead of process handle */ + hProcess = current->pid; + + DRV_ProcUpdatestate(pPctxt, PROC_RES_ALLOCATED); + DRV_ProcSetPID(pPctxt, hProcess); + } +#endif + + GT_0trace(driverTrace, GT_ENTER, " <- driver_open\n"); + return status; +} + +/* This function is called when an application closes handle to the bridge + * driver. */ +static int bridge_release(struct inode *ip, struct file *filp) +{ + int status; + u32 pid; + + GT_0trace(driverTrace, GT_ENTER, "-> driver_release\n"); + + /* Return PID instead of process handle */ + pid = current->pid; + + status = DSP_Close(pid); + + + (status == true) ? (status = 0) : (status = -1); + + GT_0trace(driverTrace, GT_ENTER, " <- driver_release\n"); + + return status; +} + +/* This function provides IO interface to the bridge driver. */ +static int bridge_ioctl(struct inode *ip, struct file *filp, unsigned int code, + unsigned long args) +{ + int status; + u32 retval = DSP_SOK; + union Trapped_Args pBufIn; + + DBC_Require(filp != NULL); +#ifdef CONFIG_PM + status = omap34xxbridge_suspend_lockout(&bridge_suspend_data, filp); + if (status != 0) + return status; +#endif + + GT_0trace(driverTrace, GT_ENTER, " -> driver_ioctl\n"); + + /* Deduct one for the CMD_BASE. */ + code = (code - 1); + + status = copy_from_user(&pBufIn, (union Trapped_Args *)args, + sizeof(union Trapped_Args)); + + if (status >= 0) { + status = WCD_CallDevIOCtl(code, &pBufIn, &retval); + + if (DSP_SUCCEEDED(status)) { + status = retval; + } else { + GT_1trace(driverTrace, GT_7CLASS, + "IOCTL Failed, code : 0x%x\n", code); + status = -1; + } + + } + + GT_0trace(driverTrace, GT_ENTER, " <- driver_ioctl\n"); + + return status; +} + +/* This function maps kernel space memory to user space memory. */ +static int bridge_mmap(struct file *filp, struct vm_area_struct *vma) +{ +#if GT_TRACE + u32 offset = vma->vm_pgoff << PAGE_SHIFT; +#endif + u32 status; + + DBC_Assert(vma->vm_start < vma->vm_end); + + vma->vm_flags |= VM_RESERVED | VM_IO; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + GT_6trace(driverTrace, GT_3CLASS, + "vm filp %p offset %lx start %lx end %lx" + " page_prot %lx flags %lx\n", filp, offset, vma->vm_start, + vma->vm_end, vma->vm_page_prot, vma->vm_flags); + + status = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + vma->vm_end - vma->vm_start, vma->vm_page_prot); + if (status != 0) + status = -EAGAIN; + + return status; +} + +#ifndef RES_CLEANUP_DISABLE +/* To remove all process resources before removing the process from the + * process context list*/ +DSP_STATUS DRV_RemoveAllResources(HANDLE hPCtxt) +{ + DSP_STATUS status = DSP_SOK; + struct PROCESS_CONTEXT *pCtxt = (struct PROCESS_CONTEXT *)hPCtxt; + if (pCtxt != NULL) { + DRV_RemoveAllSTRMResElements(pCtxt); + DRV_RemoveAllNodeResElements(pCtxt); + DRV_RemoveAllDMMResElements(pCtxt); + DRV_ProcUpdatestate(pCtxt, PROC_RES_FREED); + } + return status; +} +#endif + +/* Bridge driver initialization and de-initialization functions */ +module_init(bridge_init); +module_exit(bridge_exit); + diff --git a/drivers/dsp/bridge/rmgr/drv_interface.h b/drivers/dsp/bridge/rmgr/drv_interface.h new file mode 100644 index 0000000..f5b068e --- /dev/null +++ b/drivers/dsp/bridge/rmgr/drv_interface.h @@ -0,0 +1,40 @@ +/* + * drv_interface.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== drv_interface.h ======== + * + *! Revision History + *! ================ + *! 24-Mar-2003 vp Added hooks for Power Management Test + *! 18-Feb-2003 vp Code review updates + *! 18-Oct-2002 sb Created initial version + + */ + +#ifndef _DRV_INTERFACE_H_ +#define _DRV_INTERFACE_H_ + +/* Prototypes for all functions in this bridge */ +static int __init bridge_init(void); /* Initialize bridge */ +static void __exit bridge_exit(void); /* Opposite of initialize */ +static int bridge_open(struct inode *, struct file *); /* Open */ +static int bridge_release(struct inode *, struct file *); /* Release */ +static int bridge_ioctl(struct inode *, struct file *, unsigned int, + unsigned long); +static int bridge_mmap(struct file *filp, struct vm_area_struct *vma); +#endif /* ifndef _DRV_INTERFACE_H_ */ diff --git a/drivers/dsp/bridge/rmgr/dspdrv.c b/drivers/dsp/bridge/rmgr/dspdrv.c new file mode 100644 index 0000000..a7a74fc --- /dev/null +++ b/drivers/dsp/bridge/rmgr/dspdrv.c @@ -0,0 +1,276 @@ +/* + * dspdrv.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dspdrv.c ======== + * Description: + * Interface to allocate and free bridge resources. + * + *! Revision History + *! ================ + *! 12-Apr-2004 hp: Compile IVA only for 24xx. + *! 09-Feb-2004 vp: Updated to support IVA. + *! 10-Feb-2003 vp: Code review updates. + *! 18-oct-2002 vp: Ported to the Linux platform. + *! 03-Mar-2002 rr: DSP_Deinit bug fixed (gets the Mgrhandle from registry + *! before calling MGR_Destroy. + *! 11-Jul-2001 jeh Moved MGR_Create() from DSP_Init() to DEV_StartDevice(). + *! 02-Apr-2001 rr: WCD_InitComplete2 return value is not checked thus + *! sllowing the class driver to load irrespective of + *! the image load. + *! 30-Oct-2000 kc: Made changes w.r.t. usage of REG_SetValue. + *! 05-Oct-2000 rr: WCD_InitComplete2 return value checked for RM. + *! Failure in WCD_InitComplete2 will cause the + *! DSP_Init to fail. + *! 12-Aug-2000 kc: Changed REG_EnumValue to REG_EnumKey. + *! 07-Aug-2000 rr: MGR_Create does the job of loading the DCD Dll. + *! 26-Jul-2000 rr: Driver Object holds the DevNodeStrings for each + *! DevObjects. Static variables removed. Returns + *! the Driver Object in DSP_Init. + *! 17-Jul-2000 rr: Driver Object is created in DSP_Init and that holds + *! the list of Device objects. + *! 07-Jul-2000 rr: RM implementaion started. + *! 24-May-2000 ag: Cleaned up debug msgs. + *! 02-May-2000 rr: DSP_Open returns GetCallerProcess as dwOpenContext. + *! 03-Feb-2000 rr: GT Changes. + *! 28-Jan-2000 rr: Code Cleaned up.Type void changed to void. + *! DSP_Deinit checks return values.dwCode in + *! DSP_IO_CONTROL is decoded(not hard coded) + *! 27-Jan-2000 rr: REG_EnumValue Used .EnumerateKey fxn removed. + *! 13-Jan-2000 rr: CFG_GetPrivateDword renamed to CFG_GetDevObject. + *! 29-Dec-1999 rr: Code Cleaned up + *! 09-Dec-1999 rr: EnumerateKey changed for retail build. + *! 06-Dec-1999 rr: ArrayofInstalledNode, index and ArrayofInstalledDev + *! is Global.DevObject stores this pointer as hDevNode. + *! 02-Dec-1999 rr: DBG_SetGT and RetailMSG conditionally included. + *! Comments changed.Deinit handled.Code cleaned up. + *! DSP_IOControl, Close, Deinit returns bool values. + *! Calls WCD_InitComplete2 for Board AutoStart. + *! 29-Nov-1999 rr: DSP_IOControl returns the result through pBufOut. + *! Global Arrays keeps track of installed devices. + *! 19-Nov-1999 rr: DSP_Init handles multiple drivers. + *! 12-Nov-1999 rr: GetDriverKey and EnumerateKey functions added. + *! for multiple mini driver support.PCCARD flag + *! checking to include PCMCIA related stuff. + *! 25-Oct-1999 rr: GT_Init is called within the Process Attach. + *! return value initalized to S_OK upfront in the + *! Process Attach. + *! 15-Oct-1999 rr: DSP_DeInit handles the return values + *! 05-Oct-1999 rr: All the PCMCIA related functions are now in PCCARD.c + *! DRV_Request Resources is used instead of the + *! RegisterMiniDriver as it sounds close to what we are doing. + *! 24-Sep-1999 rr: DRV_RegisterMiniDriver is being called from here. Only + *! neccessaryPCMCIA fxns are here. Soon they will move out + *! either to a seperate file for bus specific inits. + *! 10-Sep-1999 rr: GT Enabled. Considerably changed the driver structure as + *! - This is the Class driver. After successfully initialized + *! the Class driver will attempt to load the Mini driver. + *! - Need to seperate the PCMCIA stuff based on bus type. + *! - Changed the name of the file to wcdce.c + *! - Made the Media Handle as Global again + *! + *! 19-Aug-1999 rr: Removed the Global hbhMediaHandle. Included the MemTest. + *! Modified the DSP_Init, now three windows are opened. + *! Split the driver into PDD so that hardware dependent + *! functions will reside in PDD. + *! 16-Jul-1999 ag Adapted from rkw's CAC Bullet card driver. + *! + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include + +/* ----------------------------------- Platform Manager */ +#include +#include +#include + +/* ----------------------------------- Resource Manager */ +#include + +/* ----------------------------------- Others */ +#include + +/* ----------------------------------- This */ +#include + +/* ----------------------------------- Globals */ +struct GT_Mask curTrace; + +/* + * ======== DSP_Init ======== + * Allocates bridge resources. Loads a base image onto DSP, if specified. + */ +u32 DSP_Init(OUT u32 *initStatus) +{ + char devNode[MAXREGPATHLENGTH] = "TIOMAP1510"; + DSP_STATUS status = DSP_EFAIL; + struct DRV_OBJECT *drvObject = NULL; + u32 index = 0; + u32 deviceNode; + u32 deviceNodeString; + + GT_create(&curTrace, "DD"); + + GT_0trace(curTrace, GT_ENTER, "Entering DSP_Init \r\n"); + + if (DSP_FAILED(WCD_Init())) { + GT_0trace(curTrace, GT_7CLASS, "DSP_Init Failed \n"); + goto func_cont; + } /* End WCD_Exit */ + if (DSP_FAILED(DRV_Create(&drvObject))) { + GT_0trace(curTrace, GT_7CLASS, "DSP_Init:DRV_Create Failed \n"); + WCD_Exit(); + goto func_cont; + } /* End DRV_Create */ + GT_0trace(curTrace, GT_5CLASS, "DSP_Init:DRV Created \r\n"); + + /* Request Resources */ + if (DSP_SUCCEEDED(DRV_RequestResources((u32)&devNode, + &deviceNodeString))) { + /* Attempt to Start the Device */ + if (DSP_SUCCEEDED(DEV_StartDevice( + (struct CFG_DEVNODE *)deviceNodeString))) { + /* Retreive the DevObject from the Registry */ + GT_2trace(curTrace, GT_1CLASS, + "DSP_Init Succeeded for Device1:" + "%d: value: %x\n", index, deviceNodeString); + status = DSP_SOK; + } else { + GT_0trace(curTrace, GT_7CLASS, + "DSP_Init:DEV_StartDevice Failed\n"); + (void)DRV_ReleaseResources + ((u32) deviceNodeString, drvObject); + status = DSP_EFAIL; + } + } else { + GT_0trace(curTrace, GT_7CLASS, + "DSP_Init:DRV_RequestResources Failed \r\n"); + status = DSP_EFAIL; + } /* DRV_RequestResources */ + index++; + + /* Unwind whatever was loaded */ + if (DSP_FAILED(status)) { + /* irrespective of the status of DEV_RemoveDevice we conitinue + * unloading. Get the Driver Object iterate through and remove. + * Reset the status to E_FAIL to avoid going through + * WCD_InitComplete2. */ + status = DSP_EFAIL; + for (deviceNode = DRV_GetFirstDevExtension(); deviceNode != 0; + deviceNode = DRV_GetNextDevExtension(deviceNode)) { + (void)DEV_RemoveDevice + ((struct CFG_DEVNODE *)deviceNode); + (void)DRV_ReleaseResources((u32)deviceNode, + drvObject); + } + /* Remove the Driver Object */ + (void)DRV_Destroy(drvObject); + drvObject = NULL; + WCD_Exit(); + GT_0trace(curTrace, GT_7CLASS, + "DSP_Init:Logical device Failed to Load\n"); + } /* Unwinding the loaded drivers */ +func_cont: + /* Attempt to Start the Board */ + if (DSP_SUCCEEDED(status)) { + /* BRD_AutoStart could fail if the dsp execuetable is not the + * correct one. We should not propagate that error + * into the device loader. */ + (void)WCD_InitComplete2(); + GT_0trace(curTrace, GT_1CLASS, "DSP_Init Succeeded\n"); + } else { + GT_0trace(curTrace, GT_7CLASS, "DSP_Init Failed\n"); + } /* End WCD_InitComplete2 */ + DBC_Ensure((DSP_SUCCEEDED(status) && drvObject != NULL) || + (DSP_FAILED(status) && drvObject == NULL)); + *initStatus = status; + /* Return the Driver Object */ + return (u32)drvObject; +} + +/* + * ======== DSP_Deinit ======== + * Frees the resources allocated for bridge. + */ +bool DSP_Deinit(u32 deviceContext) +{ + bool retVal = true; + u32 deviceNode; + struct MGR_OBJECT *mgrObject = NULL; + + GT_0trace(curTrace, GT_ENTER, "Entering DSP_Deinit \r\n"); + + while ((deviceNode = DRV_GetFirstDevExtension()) != 0) { + (void)DEV_RemoveDevice((struct CFG_DEVNODE *)deviceNode); + + (void)DRV_ReleaseResources((u32)deviceNode, + (struct DRV_OBJECT *)deviceContext); + } + + (void) DRV_Destroy((struct DRV_OBJECT *) deviceContext); + + /* Get the Manager Object from Registry + * MGR Destroy will unload the DCD dll */ + if (DSP_SUCCEEDED(CFG_GetObject((u32 *)&mgrObject, REG_MGR_OBJECT))) + (void)MGR_Destroy(mgrObject); + + WCD_Exit(); + + return retVal; +} + +/* + * ======== DSP_Close ======== + * The Calling Process handle is passed to DEV_CleanupProcesState + * for cleaning up of any resources used by the application + */ +bool DSP_Close(u32 dwOpenContext) +{ + bool retVal = false; + + DBC_Require(dwOpenContext != 0); + + GT_0trace(curTrace, GT_ENTER, "Entering DSP_Close\n"); + +#ifdef RES_CLEANUP_DISABLE + + if (DSP_SUCCEEDED(DEV_CleanupProcessState((HANDLE) dwOpenContext))) { + GT_0trace(curTrace, GT_1CLASS, "DSP_Close Succeeded \r\n"); + retVal = true; + } else { + GT_0trace(curTrace, GT_7CLASS, "DSP_Close failed \r\n"); + } +#endif + + return retVal; +} diff --git a/drivers/dsp/bridge/rmgr/mgr.c b/drivers/dsp/bridge/rmgr/mgr.c new file mode 100644 index 0000000..943cf93 --- /dev/null +++ b/drivers/dsp/bridge/rmgr/mgr.c @@ -0,0 +1,491 @@ +/* + * mgr.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== mgr.c ======== + * Description: + * Implementation of Manager interface to the device object at the + * driver level. This queries the NDB data base and retrieves the + * data about Node and Processor. + * + * + *! Revision History: + *! ================ + *! 12-Feb-2003 vp: Code review updates. + *! 18-Oct-2002 vp: Ported to Linux platform + *! 01-Aug-2001 ag: Added extended info for DSP-MMU setup support. + *! 13-Feb-2001 kc: DSP/BIOS Bridge name updates. + *! 22-Nov-2000 kc: Added MGR_GetPerfData. + *! 03-Nov-2000 rr: Updated after code review. + *! 25-Sep-2000 rr: Updated to Version 0.9 + *! 10-Aug-2000 rr: dwSignature is not specifically inserted in MGR Obj + *! as it is taken care by MEM_AllocObject. stdwin.h added + *! for retail build to succeed. + *! 07-Aug-2000 rr: MGR_Create does the job of Loading DCD Dll. + *! 26-Jul-2000 rr: MGR_Destroy releases the hNDBDll. + *! 20-Jun-2000 rr: Created. + */ + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include + +/* ----------------------------------- Others */ +#include +#include +#include +#include + +/* ----------------------------------- This */ +#include + +/* ----------------------------------- Defines, Data Structures, Typedefs */ +#define ZLDLLNAME "" +#define SIGNATURE 0x5f52474d /* "MGR_" (in reverse) */ + +struct MGR_OBJECT { + u32 dwSignature; + struct DCD_MANAGER *hDcdMgr; /* Proc/Node data manager */ +}; + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask MGR_DebugMask = { NULL, NULL }; +#endif + +static u32 cRefs; + +/* + * ========= MGR_Create ========= + * Purpose: + * MGR Object gets created only once during driver Loading. + */ +DSP_STATUS MGR_Create(OUT struct MGR_OBJECT **phMgrObject, + struct CFG_DEVNODE *hDevNode) +{ + DSP_STATUS status = DSP_SOK; + struct MGR_OBJECT *pMgrObject = NULL; + + DBC_Require(phMgrObject != NULL); + DBC_Require(cRefs > 0); + GT_1trace(MGR_DebugMask, GT_ENTER, + "Entering MGR_Create phMgrObject 0x%x\n ", + phMgrObject); + MEM_AllocObject(pMgrObject, struct MGR_OBJECT, SIGNATURE); + if (pMgrObject) { + if (DSP_SUCCEEDED(DCD_CreateManager(ZLDLLNAME, + &pMgrObject->hDcdMgr))) { + /* If succeeded store the handle in the MGR Object */ + if (DSP_SUCCEEDED(CFG_SetObject((u32)pMgrObject, + REG_MGR_OBJECT))) { + *phMgrObject = pMgrObject; + GT_0trace(MGR_DebugMask, GT_1CLASS, + "MGR_Create:MGR Created\r\n"); + } else { + status = DSP_EFAIL; + GT_0trace(MGR_DebugMask, GT_7CLASS, + "MGR_Create:CFG_SetObject " + "Failed\r\n"); + DCD_DestroyManager(pMgrObject->hDcdMgr); + MEM_FreeObject(pMgrObject); + } + } else { + /* failed to Create DCD Manager */ + status = DSP_EFAIL; + GT_0trace(MGR_DebugMask, GT_7CLASS, + "MGR_Create:DCD_ManagerCreate Failed\r\n"); + MEM_FreeObject(pMgrObject); + } + } else { + status = DSP_EMEMORY; + GT_0trace(MGR_DebugMask, GT_7CLASS, + "MGR_Create DSP_FAILED to allocate memory \n"); + } + GT_2trace(MGR_DebugMask, GT_ENTER, + "Exiting MGR_Create: phMgrObject: 0x%x\t" + "status: 0x%x\n", phMgrObject, status); + DBC_Ensure(DSP_FAILED(status) || + MEM_IsValidHandle(pMgrObject, SIGNATURE)); + return status; +} + +/* + * ========= MGR_Destroy ========= + * This function is invoked during bridge driver unloading.Frees MGR object. + */ +DSP_STATUS MGR_Destroy(struct MGR_OBJECT *hMgrObject) +{ + DSP_STATUS status = DSP_SOK; + struct MGR_OBJECT *pMgrObject = (struct MGR_OBJECT *)hMgrObject; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(hMgrObject, SIGNATURE)); + + GT_1trace(MGR_DebugMask, GT_ENTER, + "Entering MGR_Destroy hMgrObject 0x%x\n", hMgrObject); + /* Free resources */ + if (hMgrObject->hDcdMgr) + DCD_DestroyManager(hMgrObject->hDcdMgr); + + MEM_FreeObject(pMgrObject); + /* Update the Registry with NULL for MGR Object */ + (void)CFG_SetObject(0, REG_MGR_OBJECT); + + GT_2trace(MGR_DebugMask, GT_ENTER, + "Exiting MGR_Destroy: hMgrObject: 0x%x\t" + "status: 0x%x\n", hMgrObject, status); + + DBC_Ensure(DSP_FAILED(status) || + !MEM_IsValidHandle(hMgrObject, SIGNATURE)); + + return status; +} + +/* + * ======== MGR_EnumNodeInfo ======== + * Enumerate and get configuration information about nodes configured + * in the node database. + */ +DSP_STATUS MGR_EnumNodeInfo(u32 uNode, OUT struct DSP_NDBPROPS *pNDBProps, + u32 uNDBPropsSize, OUT u32 *puNumNodes) +{ + DSP_STATUS status = DSP_SOK; + DSP_STATUS status1 = DSP_SOK; + struct DSP_UUID Uuid, uTempUuid; + u32 uTempIndex = 0; + u32 uNodeIndex = 0; + struct DCD_GENERICOBJ GenObj; + struct MGR_OBJECT *pMgrObject = NULL; + + DBC_Require(pNDBProps != NULL); + DBC_Require(puNumNodes != NULL); + DBC_Require(uNDBPropsSize >= sizeof(struct DSP_NDBPROPS)); + DBC_Require(cRefs > 0); + + GT_4trace(MGR_DebugMask, GT_ENTER, "Entered Manager_EnumNodeInfo, " + "args:\n\t uNode: 0x%x\n\tpNDBProps: 0x%x\n\tuNDBPropsSize:" + "0x%x\tpuNumNodes: 0x%x\n", uNode, pNDBProps, + uNDBPropsSize, puNumNodes); + *puNumNodes = 0; + /* Get The Manager Object from the Registry */ + if (DSP_FAILED(CFG_GetObject((u32 *)&pMgrObject, + REG_MGR_OBJECT))) { + GT_0trace(MGR_DebugMask, GT_7CLASS, + "Manager_EnumNodeInfo:Failed To Get" + " MGR Object from Registry\r\n"); + goto func_cont; + } + DBC_Assert(MEM_IsValidHandle(pMgrObject, SIGNATURE)); + /* Forever loop till we hit failed or no more items in the + * Enumeration. We will exit the loop other than DSP_SOK; */ + while (status == DSP_SOK) { + status = DCD_EnumerateObject(uTempIndex++, DSP_DCDNODETYPE, + &uTempUuid); + if (status == DSP_SOK) { + uNodeIndex++; + if (uNode == (uNodeIndex - 1)) + Uuid = uTempUuid; + + } + } + if (DSP_SUCCEEDED(status)) { + if (uNode > (uNodeIndex - 1)) { + status = DSP_EINVALIDARG; + GT_0trace(MGR_DebugMask, GT_7CLASS, + "Manager_EnumNodeInfo: uNode" + " is Invalid \r\n"); + } else { + status1 = DCD_GetObjectDef(pMgrObject->hDcdMgr, + (struct DSP_UUID *)&Uuid, + DSP_DCDNODETYPE, &GenObj); + if (DSP_SUCCEEDED(status1)) { + /* Get the Obj def */ + *pNDBProps = GenObj.objData.nodeObj.ndbProps; + *puNumNodes = uNodeIndex; + status = DSP_SOK; + } else { + GT_0trace(MGR_DebugMask, GT_7CLASS, + "Manager_EnumNodeInfo: " + "Failed to Get Node Info \r\n"); + status = DSP_EFAIL; + } + } + } else { + /* This could be changed during enum, EFAIL ... */ + GT_0trace(MGR_DebugMask, GT_7CLASS, "Manager_EnumNodeInfo: " + "Enumeration failure\r\n"); + status = DSP_EFAIL; + } +func_cont: + GT_4trace(MGR_DebugMask, GT_ENTER, + "Exiting Manager_EnumNodeInfo, args:\n\t" + "uNode: 0x%x\n\tpNDBProps: 0x%x\n\tuNDBPropsSize:" + " 0x%x\tuNumNodes: 0x%x\n", uNode, pNDBProps, + uNDBPropsSize, *puNumNodes); + DBC_Ensure((DSP_SUCCEEDED(status) && *puNumNodes > 0) || + (DSP_FAILED(status) && *puNumNodes == 0)); + + return status; +} + +/* + * ======== MGR_EnumProcessorInfo ======== + * Enumerate and get configuration information about available + * DSP processors. + */ +DSP_STATUS MGR_EnumProcessorInfo(u32 uProcessor, + OUT struct DSP_PROCESSORINFO *pProcessorInfo, + u32 uProcessorInfoSize, OUT u32 *puNumProcs) +{ + DSP_STATUS status = DSP_SOK; + DSP_STATUS status1 = DSP_SOK; + DSP_STATUS status2 = DSP_SOK; + struct DSP_UUID uTempUuid; + u32 uTempIndex = 0; + u32 uProcIndex = 0; + struct DCD_GENERICOBJ GenObj; + struct MGR_OBJECT *pMgrObject = NULL; + struct MGR_PROCESSOREXTINFO *pExtInfo; + struct DEV_OBJECT *hDevObject; + struct DRV_OBJECT *hDrvObject; + s32 devType; + struct CFG_DEVNODE *devNode; + struct CFG_DSPRES chipResources; + bool procDetect = false; + + DBC_Require(pProcessorInfo != NULL); + DBC_Require(puNumProcs != NULL); + DBC_Require(uProcessorInfoSize >= sizeof(struct DSP_PROCESSORINFO)); + DBC_Require(cRefs > 0); + + GT_4trace(MGR_DebugMask, GT_ENTER, + "Entered Manager_EnumProcessorInfo, " + "args:\n\tuProcessor: 0x%x\n\tpProcessorInfo: 0x%x\n\t" + "uProcessorInfoSize: 0x%x\tpuNumProcs: 0x%x\n", uProcessor, + pProcessorInfo, uProcessorInfoSize, puNumProcs); + *puNumProcs = 0; + status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); + if (DSP_SUCCEEDED(status)) { + status = DRV_GetDevObject(uProcessor, hDrvObject, &hDevObject); + if (DSP_SUCCEEDED(status)) { + status = DEV_GetDevType(hDevObject, (u32 *) &devType); + status = DEV_GetDevNode(hDevObject, &devNode); + if (devType == DSP_UNIT) { + status = CFG_GetDSPResources(devNode, + &chipResources); + } else { + status = DSP_EFAIL; + GT_1trace(MGR_DebugMask, GT_7CLASS, + "Unsupported dev type gotten" + "from device object %d\n", devType); + } + if (DSP_SUCCEEDED(status)) { + pProcessorInfo->uProcessorType = + chipResources.uChipType; + } + } + } + if (DSP_FAILED(status)) + goto func_end; + + /* Get The Manager Object from the Registry */ + if (DSP_FAILED(CFG_GetObject((u32 *)&pMgrObject, + REG_MGR_OBJECT))) { + GT_0trace(MGR_DebugMask, GT_7CLASS, + "Manager_EnumProcessorInfo: " + "Failed To Get MGR Object from Registry\r\n"); + goto func_end; + } + DBC_Assert(MEM_IsValidHandle(pMgrObject, SIGNATURE)); + /* Forever loop till we hit no more items in the + * Enumeration. We will exit the loop other than DSP_SOK; */ + while (status1 == DSP_SOK) { + status1 = DCD_EnumerateObject(uTempIndex++, + DSP_DCDPROCESSORTYPE, + &uTempUuid); + if (status1 != DSP_SOK) + break; + + uProcIndex++; + /* Get the Object properties to find the Device/Processor + * Type */ + if (procDetect != false) + continue; + + status2 = DCD_GetObjectDef(pMgrObject->hDcdMgr, + (struct DSP_UUID *)&uTempUuid, + DSP_DCDPROCESSORTYPE, + &GenObj); + if (DSP_SUCCEEDED(status2)) { + /* Get the Obj def */ + if (uProcessorInfoSize < + sizeof(struct MGR_PROCESSOREXTINFO)) { + *pProcessorInfo = GenObj.objData.procObj; + } else { + /* extended info */ + pExtInfo = (struct MGR_PROCESSOREXTINFO *) + pProcessorInfo; + *pExtInfo = GenObj.objData.extProcObj; + } + GT_1trace(MGR_DebugMask, GT_7CLASS, + "Manager_EnumProcessorInfo: Got" + " Proctype from DCD %x \r\n", + pProcessorInfo->uProcessorType); + /* See if we got the needed processor */ + if (devType == DSP_UNIT) { + if (pProcessorInfo->uProcessorType == + DSPPROCTYPE_C64) + procDetect = true; + } else if (devType == IVA_UNIT) { + if (pProcessorInfo->uProcessorType == + IVAPROCTYPE_ARM7) + procDetect = true; + } + /* User applciatiuons aonly check for chip type, so + * this clumsy overwrite */ + pProcessorInfo->uProcessorType = + chipResources.uChipType; + } else { + GT_1trace(MGR_DebugMask, GT_7CLASS, + "Manager_EnumProcessorInfo: " + "Failed to Get DCD Processor Info %x \r\n", + status2); + status = DSP_EFAIL; + } + } + *puNumProcs = uProcIndex; + if (procDetect == false) { + GT_0trace(MGR_DebugMask, GT_7CLASS, + "Manager_EnumProcessorInfo: Failed" + " to get Proc info from DCD , so use CFG registry\n"); + pProcessorInfo->uProcessorType = chipResources.uChipType; + } +func_end: + return status; +} + +/* + * ======== MGR_Exit ======== + * Decrement reference count, and free resources when reference count is + * 0. + */ +void MGR_Exit(void) +{ + DBC_Require(cRefs > 0); + cRefs--; + if (cRefs == 0) + DCD_Exit(); + + GT_1trace(MGR_DebugMask, GT_5CLASS, + "Entered MGR_Exit, ref count: 0x%x\n", cRefs); + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== MGR_GetDCDHandle ======== + * Retrieves the MGR handle. Accessor Function. + */ +DSP_STATUS MGR_GetDCDHandle(struct MGR_OBJECT *hMGRHandle, + OUT u32 *phDCDHandle) +{ + DSP_STATUS status = DSP_EFAIL; + struct MGR_OBJECT *pMgrObject = (struct MGR_OBJECT *)hMGRHandle; + + DBC_Require(cRefs > 0); + DBC_Require(phDCDHandle != NULL); + + *phDCDHandle = (u32)NULL; + if (MEM_IsValidHandle(pMgrObject, SIGNATURE)) { + *phDCDHandle = (u32) pMgrObject->hDcdMgr; + status = DSP_SOK; + } + DBC_Ensure((DSP_SUCCEEDED(status) && *phDCDHandle != (u32)NULL) || + (DSP_FAILED(status) && *phDCDHandle == (u32)NULL)); + + return status; +} + +/* + * ======== MGR_Init ======== + * Initialize MGR's private state, keeping a reference count on each call. + */ +bool MGR_Init(void) +{ + bool fRetval = true; + bool fInitDCD = false; + + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { + + /* Set the Trace mask */ + DBC_Assert(!MGR_DebugMask.flags); + + GT_create(&MGR_DebugMask, "MG"); /* "MG" for Manager */ + fInitDCD = DCD_Init(); /* DCD Module */ + + if (!fInitDCD) { + fRetval = false; + GT_0trace(MGR_DebugMask, GT_6CLASS, + "MGR_Init failed\n"); + } + } + + if (fRetval) + cRefs++; + + + GT_1trace(MGR_DebugMask, GT_5CLASS, + "Entered MGR_Init, ref count: 0x%x\n", cRefs); + DBC_Ensure((fRetval && (cRefs > 0)) || (!fRetval && (cRefs >= 0))); + + return fRetval; +} + +/* + * ======== MGR_WaitForBridgeEvents ======== + * Block on any Bridge event(s) + */ +DSP_STATUS MGR_WaitForBridgeEvents(struct DSP_NOTIFICATION **aNotifications, + u32 uCount, OUT u32 *puIndex, u32 uTimeout) +{ + DSP_STATUS status; + struct SYNC_OBJECT *hSyncEvents[MAX_EVENTS]; + u32 i; + + DBC_Require(uCount < MAX_EVENTS); + + for (i = 0; i < uCount; i++) + hSyncEvents[i] = aNotifications[i]->handle; + + status = SYNC_WaitOnMultipleEvents(hSyncEvents, uCount, uTimeout, + puIndex); + + return status; + +} + diff --git a/drivers/dsp/bridge/rmgr/nldr.c b/drivers/dsp/bridge/rmgr/nldr.c new file mode 100644 index 0000000..f3c429c --- /dev/null +++ b/drivers/dsp/bridge/rmgr/nldr.c @@ -0,0 +1,1967 @@ +/* + * nldr.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== nldr.c ======== + * Description: + * DSP/BIOS Bridge dynamic + overlay Node loader. + * + * Public Functions: + * NLDR_Allocate + * NLDR_Create + * NLDR_Delete + * NLDR_Exit + * NLDR_Free + * NLDR_GetFxnAddr + * NLDR_Init + * NLDR_Load + * NLDR_Unload + * + * Notes: + * + *! Revision History + *! ================ + *! 07-Apr-2003 map Removed references to dead DLDR module + *! 23-Jan-2003 map Updated RemoteAlloc to support memory granularity + *! 20-Jan-2003 map Updated to maintain persistent dependent libraries + *! 15-Jan-2003 map Adapted for use with multiple dynamic phase libraries + *! 19-Dec-2002 map Fixed overlay bug in AddOvlySect for overlay + *! sections > 1024 bytes. + *! 13-Dec-2002 map Fixed NLDR_GetFxnAddr bug by searching dependent + *! libs for symbols + *! 27-Sep-2002 map Added RemoteFree to convert size to words for + *! correct deallocation + *! 16-Sep-2002 map Code Review Cleanup(from dldr.c) + *! 29-Aug-2002 map Adjusted for ARM-side overlay copy + *! 05-Aug-2002 jeh Created. + */ + +#include + +#include +#include +#include + +#include +#include +#ifdef DEBUG +#include +#endif + +/* OS adaptation layer */ +#include +#include + +/* Platform manager */ +#include +#include + +/* Resource manager */ +#include +#include +#include +#include + +#include + +#define NLDR_SIGNATURE 0x52444c4e /* "RDLN" */ +#define NLDR_NODESIGNATURE 0x4e444c4e /* "NDLN" */ + +/* Name of section containing dynamic load mem */ +#define DYNMEMSECT ".dspbridge_mem" + +/* Name of section containing dependent library information */ +#define DEPLIBSECT ".dspbridge_deplibs" + +/* Max depth of recursion for loading node's dependent libraries */ +#define MAXDEPTH 5 + +/* Max number of persistent libraries kept by a node */ +#define MAXLIBS 5 + +/* + * Defines for extracting packed dynamic load memory requirements from two + * masks. + * These defines must match node.cdb and dynm.cdb + * Format of data/code mask is: + * uuuuuuuu|fueeeeee|fudddddd|fucccccc| + * where + * u = unused + * cccccc = prefered/required dynamic mem segid for create phase data/code + * dddddd = prefered/required dynamic mem segid for delete phase data/code + * eeeeee = prefered/req. dynamic mem segid for execute phase data/code + * f = flag indicating if memory is preferred or required: + * f = 1 if required, f = 0 if preferred. + * + * The 6 bits of the segid are interpreted as follows: + * + * If the 6th bit (bit 5) is not set, then this specifies a memory segment + * between 0 and 31 (a maximum of 32 dynamic loading memory segments). + * If the 6th bit (bit 5) is set, segid has the following interpretation: + * segid = 32 - Any internal memory segment can be used. + * segid = 33 - Any external memory segment can be used. + * segid = 63 - Any memory segment can be used (in this case the + * required/preferred flag is irrelevant). + * + */ +/* Maximum allowed dynamic loading memory segments */ +#define MAXMEMSEGS 32 + +#define MAXSEGID 3 /* Largest possible (real) segid */ +#define MEMINTERNALID 32 /* Segid meaning use internal mem */ +#define MEMEXTERNALID 33 /* Segid meaning use external mem */ +#define NULLID 63 /* Segid meaning no memory req/pref */ +#define FLAGBIT 7 /* 7th bit is pref./req. flag */ +#define SEGMASK 0x3f /* Bits 0 - 5 */ + +#define CREATEBIT 0 /* Create segid starts at bit 0 */ +#define DELETEBIT 8 /* Delete segid starts at bit 8 */ +#define EXECUTEBIT 16 /* Execute segid starts at bit 16 */ + +/* + * Masks that define memory type. Must match defines in dynm.cdb. + */ +#define DYNM_CODE 0x2 +#define DYNM_DATA 0x4 +#define DYNM_CODEDATA (DYNM_CODE | DYNM_DATA) +#define DYNM_INTERNAL 0x8 +#define DYNM_EXTERNAL 0x10 + +/* + * Defines for packing memory requirement/preference flags for code and + * data of each of the node's phases into one mask. + * The bit is set if the segid is required for loading code/data of the + * given phase. The bit is not set, if the segid is preferred only. + * + * These defines are also used as indeces into a segid array for the node. + * eg node's segid[CREATEDATAFLAGBIT] is the memory segment id that the + * create phase data is required or preferred to be loaded into. + */ +#define CREATEDATAFLAGBIT 0 +#define CREATECODEFLAGBIT 1 +#define EXECUTEDATAFLAGBIT 2 +#define EXECUTECODEFLAGBIT 3 +#define DELETEDATAFLAGBIT 4 +#define DELETECODEFLAGBIT 5 +#define MAXFLAGS 6 + +#define IsInternal(hNldr, segid) (((segid) <= MAXSEGID && \ + hNldr->segTable[(segid)] & DYNM_INTERNAL) || \ + (segid) == MEMINTERNALID) + +#define IsExternal(hNldr, segid) (((segid) <= MAXSEGID && \ + hNldr->segTable[(segid)] & DYNM_EXTERNAL) || \ + (segid) == MEMEXTERNALID) + +#define SWAPLONG(x) ((((x) << 24) & 0xFF000000) | (((x) << 8) & 0xFF0000L) | \ + (((x) >> 8) & 0xFF00L) | (((x) >> 24) & 0xFF)) + +#define SWAPWORD(x) ((((x) << 8) & 0xFF00) | (((x) >> 8) & 0xFF)) + + /* + * These names may be embedded in overlay sections to identify which + * node phase the section should be overlayed. + */ +#define PCREATE "create" +#define PDELETE "delete" +#define PEXECUTE "execute" + +#define IsEqualUUID(uuid1, uuid2) (\ + ((uuid1).ulData1 == (uuid2).ulData1) && \ + ((uuid1).usData2 == (uuid2).usData2) && \ + ((uuid1).usData3 == (uuid2).usData3) && \ + ((uuid1).ucData4 == (uuid2).ucData4) && \ + ((uuid1).ucData5 == (uuid2).ucData5) && \ + (strncmp((void *)(uuid1).ucData6, (void *)(uuid2).ucData6, 6)) == 0) + + /* + * ======== MemInfo ======== + * Format of dynamic loading memory segment info in coff file. + * Must match dynm.h55. + */ +struct MemInfo { + u32 segid; /* Dynamic loading memory segment number */ + u32 base; + u32 len; + u32 type; /* Mask of DYNM_CODE, DYNM_INTERNAL, etc. */ +}; + +/* + * ======== LibNode ======== + * For maintaining a tree of library dependencies. + */ +struct LibNode { + struct DBLL_LibraryObj *lib; /* The library */ + u16 nDepLibs; /* Number of dependent libraries */ + struct LibNode *pDepLibs; /* Dependent libraries of lib */ +}; + +/* + * ======== OvlySect ======== + * Information needed to overlay a section. + */ +struct OvlySect { + struct OvlySect *pNextSect; + u32 loadAddr; /* Load address of section */ + u32 runAddr; /* Run address of section */ + u32 size; /* Size of section */ + u16 page; /* DBL_CODE, DBL_DATA */ +}; + +/* + * ======== OvlyNode ======== + * For maintaining a list of overlay nodes, with sections that need to be + * overlayed for each of the nodes phases. + */ +struct OvlyNode { + struct DSP_UUID uuid; + char *pNodeName; + struct OvlySect *pCreateSects; + struct OvlySect *pDeleteSects; + struct OvlySect *pExecuteSects; + struct OvlySect *pOtherSects; + u16 nCreateSects; + u16 nDeleteSects; + u16 nExecuteSects; + u16 nOtherSects; + u16 createRef; + u16 deleteRef; + u16 executeRef; + u16 otherRef; +}; + +/* + * ======== NLDR_OBJECT ======== + * Overlay loader object. + */ +struct NLDR_OBJECT { + u32 dwSignature; /* For object validation */ + struct DEV_OBJECT *hDevObject; /* Device object */ + struct DCD_MANAGER *hDcdMgr; /* Proc/Node data manager */ + struct DBLL_TarObj *dbll; /* The DBL loader */ + struct DBLL_LibraryObj *baseLib; /* Base image library */ + struct RMM_TargetObj *rmm; /* Remote memory manager for DSP */ + struct DBLL_Fxns dbllFxns; /* Loader function table */ + struct DBLL_Attrs dbllAttrs; /* attrs to pass to loader functions */ + NLDR_OVLYFXN ovlyFxn; /* "write" for overlay nodes */ + NLDR_WRITEFXN writeFxn; /* "write" for dynamic nodes */ + struct OvlyNode *ovlyTable; /* Table of overlay nodes */ + u16 nOvlyNodes; /* Number of overlay nodes in base */ + u16 nNode; /* Index for tracking overlay nodes */ + u16 nSegs; /* Number of dynamic load mem segs */ + u32 *segTable; /* memtypes of dynamic memory segs + * indexed by segid + */ + u16 usDSPMauSize; /* Size of DSP MAU */ + u16 usDSPWordSize; /* Size of DSP word */ +}; + +/* + * ======== NLDR_NODEOBJECT ======== + * Dynamic node object. This object is created when a node is allocated. + */ +struct NLDR_NODEOBJECT { + u32 dwSignature; /* For object validation */ + struct NLDR_OBJECT *pNldr; /* Dynamic loader handle */ + void *pPrivRef; /* Handle to pass to DBL_WriteFxn */ + struct DSP_UUID uuid; /* Node's UUID */ + bool fDynamic; /* Dynamically loaded node? */ + bool fOverlay; /* Overlay node? */ + bool *pfPhaseSplit; /* Multiple phase libraries? */ + struct LibNode root; /* Library containing node phase */ + struct LibNode createLib; /* Library containing create phase lib */ + struct LibNode executeLib; /* Library containing execute phase lib */ + struct LibNode deleteLib; /* Library containing delete phase lib */ + struct LibNode persLib[MAXLIBS]; /* libs remain loaded until Delete */ + s32 nPersLib; /* Number of persistent libraries */ + /* Path in lib dependency tree */ + struct DBLL_LibraryObj *libPath[MAXDEPTH + 1]; + enum NLDR_PHASE phase; /* Node phase currently being loaded */ + + /* + * Dynamic loading memory segments for data and code of each phase. + */ + u16 segId[MAXFLAGS]; + + /* + * Mask indicating whether each mem segment specified in segId[] + * is preferred or required. + * For example if (codeDataFlagMask & (1 << EXECUTEDATAFLAGBIT)) != 0, + * then it is required to load execute phase data into the memory + * specified by segId[EXECUTEDATAFLAGBIT]. + */ + u32 codeDataFlagMask; +}; + +/* Dynamic loader function table */ +static struct DBLL_Fxns dbllFxns = { + (DBLL_CloseFxn) DBLL_close, + (DBLL_CreateFxn) DBLL_create, + (DBLL_DeleteFxn) DBLL_delete, + (DBLL_ExitFxn) DBLL_exit, + (DBLL_GetAttrsFxn) DBLL_getAttrs, + (DBLL_GetAddrFxn) DBLL_getAddr, + (DBLL_GetCAddrFxn) DBLL_getCAddr, + (DBLL_GetSectFxn) DBLL_getSect, + (DBLL_InitFxn) DBLL_init, + (DBLL_LoadFxn) DBLL_load, + (DBLL_LoadSectFxn) DBLL_loadSect, + (DBLL_OpenFxn) DBLL_open, + (DBLL_ReadSectFxn) DBLL_readSect, + (DBLL_SetAttrsFxn) DBLL_setAttrs, + (DBLL_UnloadFxn) DBLL_unload, + (DBLL_UnloadSectFxn) DBLL_unloadSect, +}; + +static struct GT_Mask NLDR_debugMask = { NULL, NULL }; /* GT trace variable */ +static u32 cRefs; /* module reference count */ + +static DSP_STATUS AddOvlyInfo(void *handle, struct DBLL_SectInfo *sectInfo, + u32 addr, u32 nBytes); +static DSP_STATUS AddOvlyNode(struct DSP_UUID *pUuid, + enum DSP_DCDOBJTYPE objType, + IN void *handle); +static DSP_STATUS AddOvlySect(struct NLDR_OBJECT *hNldr, + struct OvlySect **pList, + struct DBLL_SectInfo *pSectInfo, bool *pExists, + u32 addr, u32 nBytes); +static s32 fakeOvlyWrite(void *handle, u32 dspAddr, void *buf, u32 nBytes, + s32 mtype); +static void FreeSects(struct NLDR_OBJECT *hNldr, struct OvlySect *pPhaseSects, + u16 nAlloc); +static bool GetSymbolValue(void *handle, void *pArg, void *rmmHandle, + char *symName, struct DBLL_Symbol **sym); +static DSP_STATUS LoadLib(struct NLDR_NODEOBJECT *hNldrNode, + struct LibNode *root, struct DSP_UUID uuid, + bool rootPersistent, struct DBLL_LibraryObj **libPath, + enum NLDR_PHASE phase, u16 depth); +static DSP_STATUS LoadOvly(struct NLDR_NODEOBJECT *hNldrNode, + enum NLDR_PHASE phase); +static DSP_STATUS RemoteAlloc(void **pRef, u16 memType, u32 size, + u32 align, u32 *dspAddr, + OPTIONAL s32 segmentId, OPTIONAL s32 req, + bool reserve); +static DSP_STATUS RemoteFree(void **pRef, u16 space, u32 dspAddr, + u32 size, bool reserve); + +static void UnloadLib(struct NLDR_NODEOBJECT *hNldrNode, struct LibNode *root); +static void UnloadOvly(struct NLDR_NODEOBJECT *hNldrNode, + enum NLDR_PHASE phase); +static bool findInPersistentLibArray(struct NLDR_NODEOBJECT *hNldrNode, + struct DBLL_LibraryObj *lib); +static u32 findLcm(u32 a, u32 b); +static u32 findGcf(u32 a, u32 b); + +/* + * ======== NLDR_Allocate ======== + */ +DSP_STATUS NLDR_Allocate(struct NLDR_OBJECT *hNldr, void *pPrivRef, + IN CONST struct DCD_NODEPROPS *pNodeProps, + OUT struct NLDR_NODEOBJECT **phNldrNode, + IN bool *pfPhaseSplit) +{ + struct NLDR_NODEOBJECT *pNldrNode = NULL; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(pNodeProps != NULL); + DBC_Require(phNldrNode != NULL); + DBC_Require(MEM_IsValidHandle(hNldr, NLDR_SIGNATURE)); + + GT_5trace(NLDR_debugMask, GT_ENTER, "NLDR_Allocate(0x%x, 0x%x, 0x%x, " + "0x%x, 0x%x)\n", hNldr, pPrivRef, pNodeProps, phNldrNode, + pfPhaseSplit); + + /* Initialize handle in case of failure */ + *phNldrNode = NULL; + /* Allocate node object */ + MEM_AllocObject(pNldrNode, struct NLDR_NODEOBJECT, NLDR_NODESIGNATURE); + + if (pNldrNode == NULL) { + GT_0trace(NLDR_debugMask, GT_6CLASS, "NLDR_Allocate: " + "Memory allocation failed\n"); + status = DSP_EMEMORY; + } else { + pNldrNode->pfPhaseSplit = pfPhaseSplit; + pNldrNode->nPersLib = 0; + pNldrNode->pNldr = hNldr; + pNldrNode->pPrivRef = pPrivRef; + /* Save node's UUID. */ + pNldrNode->uuid = pNodeProps->ndbProps.uiNodeID; + /* + * Determine if node is a dynamically loaded node from + * ndbProps. + */ + if (pNodeProps->usLoadType == NLDR_DYNAMICLOAD) { + /* Dynamic node */ + pNldrNode->fDynamic = true; + /* + * Extract memory requirements from ndbProps masks + */ + /* Create phase */ + pNldrNode->segId[CREATEDATAFLAGBIT] = (u16) + (pNodeProps->ulDataMemSegMask >> CREATEBIT) & + SEGMASK; + pNldrNode->codeDataFlagMask |= + ((pNodeProps->ulDataMemSegMask >> + (CREATEBIT + FLAGBIT)) & 1) << + CREATEDATAFLAGBIT; + pNldrNode->segId[CREATECODEFLAGBIT] = (u16) + (pNodeProps->ulCodeMemSegMask >> + CREATEBIT) & SEGMASK; + pNldrNode->codeDataFlagMask |= + ((pNodeProps->ulCodeMemSegMask >> + (CREATEBIT + FLAGBIT)) & 1) << + CREATECODEFLAGBIT; + /* Execute phase */ + pNldrNode->segId[EXECUTEDATAFLAGBIT] = (u16) + (pNodeProps->ulDataMemSegMask >> + EXECUTEBIT) & SEGMASK; + pNldrNode->codeDataFlagMask |= + ((pNodeProps->ulDataMemSegMask >> + (EXECUTEBIT + FLAGBIT)) & 1) << + EXECUTEDATAFLAGBIT; + pNldrNode->segId[EXECUTECODEFLAGBIT] = (u16) + (pNodeProps->ulCodeMemSegMask >> + EXECUTEBIT) & SEGMASK; + pNldrNode->codeDataFlagMask |= + ((pNodeProps->ulCodeMemSegMask >> + (EXECUTEBIT + FLAGBIT)) & 1) << + EXECUTECODEFLAGBIT; + /* Delete phase */ + pNldrNode->segId[DELETEDATAFLAGBIT] = (u16) + (pNodeProps->ulDataMemSegMask >> DELETEBIT) & + SEGMASK; + pNldrNode->codeDataFlagMask |= + ((pNodeProps->ulDataMemSegMask >> + (DELETEBIT + FLAGBIT)) & 1) << + DELETEDATAFLAGBIT; + pNldrNode->segId[DELETECODEFLAGBIT] = (u16) + (pNodeProps->ulCodeMemSegMask >> + DELETEBIT) & SEGMASK; + pNldrNode->codeDataFlagMask |= + ((pNodeProps->ulCodeMemSegMask >> + (DELETEBIT + FLAGBIT)) & 1) << + DELETECODEFLAGBIT; + } else { + /* Non-dynamically loaded nodes are part of the + * base image */ + pNldrNode->root.lib = hNldr->baseLib; + /* Check for overlay node */ + if (pNodeProps->usLoadType == NLDR_OVLYLOAD) + pNldrNode->fOverlay = true; + + } + *phNldrNode = (struct NLDR_NODEOBJECT *) pNldrNode; + } + /* Cleanup on failure */ + if (DSP_FAILED(status) && pNldrNode) + NLDR_Free((struct NLDR_NODEOBJECT *) pNldrNode); + + DBC_Ensure((DSP_SUCCEEDED(status) && + MEM_IsValidHandle(((struct NLDR_NODEOBJECT *)(*phNldrNode)), + NLDR_NODESIGNATURE)) || (DSP_FAILED(status) && + *phNldrNode == NULL)); + return status; +} + +/* + * ======== NLDR_Create ======== + */ +DSP_STATUS NLDR_Create(OUT struct NLDR_OBJECT **phNldr, + struct DEV_OBJECT *hDevObject, + IN CONST struct NLDR_ATTRS *pAttrs) +{ + struct COD_MANAGER *hCodMgr; /* COD manager */ + char *pszCoffBuf = NULL; + char szZLFile[COD_MAXPATHLENGTH]; + struct NLDR_OBJECT *pNldr = NULL; + struct DBLL_Attrs saveAttrs; + struct DBLL_Attrs newAttrs; + DBLL_Flags flags; + u32 ulEntry; + u16 nSegs = 0; + struct MemInfo *pMemInfo; + u32 ulLen = 0; + u32 ulAddr; + struct RMM_Segment *rmmSegs = NULL; + u16 i; + DSP_STATUS status = DSP_SOK; + DBC_Require(cRefs > 0); + DBC_Require(phNldr != NULL); + DBC_Require(hDevObject != NULL); + DBC_Require(pAttrs != NULL); + DBC_Require(pAttrs->pfnOvly != NULL); + DBC_Require(pAttrs->pfnWrite != NULL); + GT_3trace(NLDR_debugMask, GT_ENTER, "NLDR_Create(0x%x, 0x%x, 0x%x)\n", + phNldr, hDevObject, pAttrs); + /* Allocate dynamic loader object */ + MEM_AllocObject(pNldr, struct NLDR_OBJECT, NLDR_SIGNATURE); + if (pNldr) { + pNldr->hDevObject = hDevObject; + /* warning, lazy status checking alert! */ + status = DEV_GetCodMgr(hDevObject, &hCodMgr); + DBC_Assert(DSP_SUCCEEDED(status)); + status = COD_GetLoader(hCodMgr, &pNldr->dbll); + DBC_Assert(DSP_SUCCEEDED(status)); + status = COD_GetBaseLib(hCodMgr, &pNldr->baseLib); + DBC_Assert(DSP_SUCCEEDED(status)); + status = COD_GetBaseName(hCodMgr, szZLFile, COD_MAXPATHLENGTH); + DBC_Assert(DSP_SUCCEEDED(status)); + status = DSP_SOK; + /* end lazy status checking */ + pNldr->usDSPMauSize = pAttrs->usDSPMauSize; + pNldr->usDSPWordSize = pAttrs->usDSPWordSize; + pNldr->dbllFxns = dbllFxns; + if (!(pNldr->dbllFxns.initFxn())) + status = DSP_EMEMORY; + + } else { + GT_0trace(NLDR_debugMask, GT_6CLASS, "NLDR_Create: " + "Memory allocation failed\n"); + status = DSP_EMEMORY; + } + /* Create the DCD Manager */ + if (DSP_SUCCEEDED(status)) + status = DCD_CreateManager(NULL, &pNldr->hDcdMgr); + + /* Get dynamic loading memory sections from base lib */ + if (DSP_SUCCEEDED(status)) { + status = pNldr->dbllFxns.getSectFxn(pNldr->baseLib, DYNMEMSECT, + &ulAddr, &ulLen); + if (DSP_SUCCEEDED(status)) { + pszCoffBuf = MEM_Calloc(ulLen * pNldr->usDSPMauSize, + MEM_PAGED); + if (!pszCoffBuf) { + GT_0trace(NLDR_debugMask, GT_6CLASS, + "NLDR_Create: Memory " + "allocation failed\n"); + status = DSP_EMEMORY; + } + } else { + /* Ok to not have dynamic loading memory */ + status = DSP_SOK; + ulLen = 0; + GT_1trace(NLDR_debugMask, GT_6CLASS, + "NLDR_Create: DBLL_getSect " + "failed (no dynamic loading mem segments): " + "0x%lx\n", status); + } + } + if (DSP_SUCCEEDED(status) && ulLen > 0) { + /* Read section containing dynamic load mem segments */ + status = pNldr->dbllFxns.readSectFxn(pNldr->baseLib, DYNMEMSECT, + pszCoffBuf, ulLen); + if (DSP_FAILED(status)) { + GT_1trace(NLDR_debugMask, GT_6CLASS, + "NLDR_Create: DBLL_read Section" + "failed: 0x%lx\n", status); + } + } + if (DSP_SUCCEEDED(status) && ulLen > 0) { + /* Parse memory segment data */ + nSegs = (u16)(*((u32 *)pszCoffBuf)); + if (nSegs > MAXMEMSEGS) { + GT_1trace(NLDR_debugMask, GT_6CLASS, + "NLDR_Create: Invalid number of " + "dynamic load mem segments: 0x%lx\n", nSegs); + status = DSP_ECORRUPTFILE; + } + } + /* Parse dynamic load memory segments */ + if (DSP_SUCCEEDED(status) && nSegs > 0) { + rmmSegs = MEM_Calloc(sizeof(struct RMM_Segment) * nSegs, + MEM_PAGED); + pNldr->segTable = MEM_Calloc(sizeof(u32) * nSegs, MEM_PAGED); + if (rmmSegs == NULL || pNldr->segTable == NULL) { + status = DSP_EMEMORY; + } else { + pNldr->nSegs = nSegs; + pMemInfo = (struct MemInfo *)(pszCoffBuf + + sizeof(u32)); + for (i = 0; i < nSegs; i++) { + rmmSegs[i].base = (pMemInfo + i)->base; + rmmSegs[i].length = (pMemInfo + i)->len; + rmmSegs[i].space = 0; + pNldr->segTable[i] = (pMemInfo + i)->type; +#ifdef DEBUG + DBG_Trace(DBG_LEVEL7, + "** (proc) DLL MEMSEGMENT: %d, Base: 0x%x, " + "Length: 0x%x\n", i, rmmSegs[i].base, + rmmSegs[i].length); +#endif + } + } + } + /* Create Remote memory manager */ + if (DSP_SUCCEEDED(status)) + status = RMM_create(&pNldr->rmm, rmmSegs, nSegs); + + if (DSP_SUCCEEDED(status)) { + /* set the alloc, free, write functions for loader */ + pNldr->dbllFxns.getAttrsFxn(pNldr->dbll, &saveAttrs); + newAttrs = saveAttrs; + newAttrs.alloc = (DBLL_AllocFxn) RemoteAlloc; + newAttrs.free = (DBLL_FreeFxn) RemoteFree; + newAttrs.symLookup = (DBLL_SymLookup) GetSymbolValue; + newAttrs.symHandle = pNldr; + newAttrs.write = (DBLL_WriteFxn) pAttrs->pfnWrite; + pNldr->ovlyFxn = pAttrs->pfnOvly; + pNldr->writeFxn = pAttrs->pfnWrite; + pNldr->dbllAttrs = newAttrs; + } + if (rmmSegs) + MEM_Free(rmmSegs); + + if (pszCoffBuf) + MEM_Free(pszCoffBuf); + + /* Get overlay nodes */ + if (DSP_SUCCEEDED(status)) { + status = COD_GetBaseName(hCodMgr, szZLFile, COD_MAXPATHLENGTH); + /* lazy check */ + DBC_Assert(DSP_SUCCEEDED(status)); + /* First count number of overlay nodes */ + status = DCD_GetObjects(pNldr->hDcdMgr, szZLFile, AddOvlyNode, + (void *) pNldr); + /* Now build table of overlay nodes */ + if (DSP_SUCCEEDED(status) && pNldr->nOvlyNodes > 0) { + /* Allocate table for overlay nodes */ + pNldr->ovlyTable = + MEM_Calloc(sizeof(struct OvlyNode) * pNldr->nOvlyNodes, + MEM_PAGED); + /* Put overlay nodes in the table */ + pNldr->nNode = 0; + status = DCD_GetObjects(pNldr->hDcdMgr, szZLFile, + AddOvlyNode, + (void *) pNldr); + } + } + /* Do a fake reload of the base image to get overlay section info */ + if (DSP_SUCCEEDED(status) && pNldr->nOvlyNodes > 0) { + saveAttrs.write = fakeOvlyWrite; + saveAttrs.logWrite = AddOvlyInfo; + saveAttrs.logWriteHandle = pNldr; + flags = DBLL_CODE | DBLL_DATA | DBLL_SYMB; + status = pNldr->dbllFxns.loadFxn(pNldr->baseLib, flags, + &saveAttrs, &ulEntry); + } + if (DSP_SUCCEEDED(status)) { + *phNldr = (struct NLDR_OBJECT *) pNldr; + } else { + if (pNldr) + NLDR_Delete((struct NLDR_OBJECT *) pNldr); + + *phNldr = NULL; + } + /* FIXME:Temp. Fix. Must be removed */ + DBC_Ensure((DSP_SUCCEEDED(status) && + MEM_IsValidHandle(((struct NLDR_OBJECT *)*phNldr), + NLDR_SIGNATURE)) + || (DSP_FAILED(status) && (*phNldr == NULL))); + return status; +} + +/* + * ======== NLDR_Delete ======== + */ +void NLDR_Delete(struct NLDR_OBJECT *hNldr) +{ + struct OvlySect *pSect; + struct OvlySect *pNext; + u16 i; + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(hNldr, NLDR_SIGNATURE)); + GT_1trace(NLDR_debugMask, GT_ENTER, "NLDR_Delete(0x%x)\n", hNldr); + hNldr->dbllFxns.exitFxn(); + if (hNldr->rmm) + RMM_delete(hNldr->rmm); + + if (hNldr->segTable) + MEM_Free(hNldr->segTable); + + if (hNldr->hDcdMgr) + DCD_DestroyManager(hNldr->hDcdMgr); + + /* Free overlay node information */ + if (hNldr->ovlyTable) { + for (i = 0; i < hNldr->nOvlyNodes; i++) { + pSect = hNldr->ovlyTable[i].pCreateSects; + while (pSect) { + pNext = pSect->pNextSect; + MEM_Free(pSect); + pSect = pNext; + } + pSect = hNldr->ovlyTable[i].pDeleteSects; + while (pSect) { + pNext = pSect->pNextSect; + MEM_Free(pSect); + pSect = pNext; + } + pSect = hNldr->ovlyTable[i].pExecuteSects; + while (pSect) { + pNext = pSect->pNextSect; + MEM_Free(pSect); + pSect = pNext; + } + pSect = hNldr->ovlyTable[i].pOtherSects; + while (pSect) { + pNext = pSect->pNextSect; + MEM_Free(pSect); + pSect = pNext; + } + } + MEM_Free(hNldr->ovlyTable); + } + MEM_FreeObject(hNldr); + DBC_Ensure(!MEM_IsValidHandle(hNldr, NLDR_SIGNATURE)); +} + +/* + * ======== NLDR_Exit ======== + * Discontinue usage of NLDR module. + */ +void NLDR_Exit(void) +{ + DBC_Require(cRefs > 0); + + cRefs--; + + GT_1trace(NLDR_debugMask, GT_5CLASS, + "Entered NLDR_Exit, ref count: 0x%x\n", cRefs); + + if (cRefs == 0) { + RMM_exit(); + NLDR_debugMask.flags = NULL; + } + + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== NLDR_Free ======== + */ +void NLDR_Free(struct NLDR_NODEOBJECT *hNldrNode) +{ + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(hNldrNode, NLDR_NODESIGNATURE)); + + GT_1trace(NLDR_debugMask, GT_ENTER, "NLDR_Free(0x%x)\n", hNldrNode); + + MEM_FreeObject(hNldrNode); +} + +/* + * ======== NLDR_GetFxnAddr ======== + */ +DSP_STATUS NLDR_GetFxnAddr(struct NLDR_NODEOBJECT *hNldrNode, char *pstrFxn, + u32 *pulAddr) +{ + struct DBLL_Symbol *pSym; + struct NLDR_OBJECT *hNldr; + DSP_STATUS status = DSP_SOK; + bool status1 = false; + s32 i = 0; + struct LibNode root = { NULL, 0, NULL }; + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(hNldrNode, NLDR_NODESIGNATURE)); + DBC_Require(pulAddr != NULL); + DBC_Require(pstrFxn != NULL); + GT_3trace(NLDR_debugMask, GT_ENTER, "NLDR_GetFxnAddr(0x%x, %s, 0x%x)\n", + hNldrNode, pstrFxn, pulAddr); + + hNldr = hNldrNode->pNldr; + /* Called from NODE_Create(), NODE_Delete(), or NODE_Run(). */ + if (hNldrNode->fDynamic && *hNldrNode->pfPhaseSplit) { + switch (hNldrNode->phase) { + case NLDR_CREATE: + root = hNldrNode->createLib; + break; + case NLDR_EXECUTE: + root = hNldrNode->executeLib; + break; + case NLDR_DELETE: + root = hNldrNode->deleteLib; + break; + default: + DBC_Assert(false); + break; + } + } else { + /* for Overlay nodes or non-split Dynamic nodes */ + root = hNldrNode->root; + } + status1 = hNldr->dbllFxns.getCAddrFxn(root.lib, pstrFxn, &pSym); + if (!status1) + status1 = hNldr->dbllFxns.getAddrFxn(root.lib, pstrFxn, &pSym); + + /* If symbol not found, check dependent libraries */ + if (!status1) { + for (i = 0; i < root.nDepLibs; i++) { + status1 = hNldr->dbllFxns.getAddrFxn(root.pDepLibs[i]. + lib, pstrFxn, &pSym); + if (!status1) { + status1 = hNldr->dbllFxns.getCAddrFxn(root. + pDepLibs[i].lib, pstrFxn, &pSym); + } + if (status1) { + /* Symbol found */ + break; + } + } + } + /* Check persistent libraries */ + if (!status1) { + for (i = 0; i < hNldrNode->nPersLib; i++) { + status1 = hNldr->dbllFxns.getAddrFxn(hNldrNode-> + persLib[i].lib, pstrFxn, &pSym); + if (!status1) { + status1 = + hNldr->dbllFxns.getCAddrFxn(hNldrNode-> + persLib[i].lib, pstrFxn, &pSym); + } + if (status1) { + /* Symbol found */ + break; + } + } + } + + if (status1) { + *pulAddr = pSym->value; + } else { + GT_1trace(NLDR_debugMask, GT_6CLASS, + "NLDR_GetFxnAddr: Symbol not found: " + "%s\n", pstrFxn); + status = DSP_ESYMBOL; + } + + return status; +} + +/* + * ======== NLDR_GetRmmManager ======== + * Given a NLDR object, retrieve RMM Manager Handle + */ +DSP_STATUS NLDR_GetRmmManager(struct NLDR_OBJECT *hNldrObject, + OUT struct RMM_TargetObj **phRmmMgr) +{ + DSP_STATUS status = DSP_SOK; + struct NLDR_OBJECT *pNldrObject = hNldrObject; + DBC_Require(phRmmMgr != NULL); + GT_2trace(NLDR_debugMask, GT_ENTER, "NLDR_GetRmmManager(0x%x, 0x%x)\n", + hNldrObject, phRmmMgr); + if (MEM_IsValidHandle(hNldrObject, NLDR_SIGNATURE)) { + *phRmmMgr = pNldrObject->rmm; + } else { + *phRmmMgr = NULL; + status = DSP_EHANDLE; + GT_0trace(NLDR_debugMask, GT_7CLASS, + "NLDR_GetRmmManager:Invalid handle"); + } + + GT_2trace(NLDR_debugMask, GT_ENTER, "Exit NLDR_GetRmmManager: status " + "0x%x\n\tphRmmMgr: 0x%x\n", status, *phRmmMgr); + + DBC_Ensure(DSP_SUCCEEDED(status) || ((phRmmMgr != NULL) && + (*phRmmMgr == NULL))); + + return status; +} + +/* + * ======== NLDR_Init ======== + * Initialize the NLDR module. + */ +bool NLDR_Init(void) +{ + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { + DBC_Assert(!NLDR_debugMask.flags); + GT_create(&NLDR_debugMask, "DL"); /* "DL" for DLdr */ + + RMM_init(); + } + + cRefs++; + + GT_1trace(NLDR_debugMask, GT_5CLASS, "NLDR_Init(), ref count: 0x%x\n", + cRefs); + + DBC_Ensure(cRefs > 0); + return true; +} + +/* + * ======== NLDR_Load ======== + */ +DSP_STATUS NLDR_Load(struct NLDR_NODEOBJECT *hNldrNode, enum NLDR_PHASE phase) +{ + struct NLDR_OBJECT *hNldr; + struct DSP_UUID libUUID; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(hNldrNode, NLDR_NODESIGNATURE)); + + hNldr = hNldrNode->pNldr; + + GT_2trace(NLDR_debugMask, GT_ENTER, "NLDR_Load(0x%x, 0x%x)\n", + hNldrNode, phase); + + if (hNldrNode->fDynamic) { + hNldrNode->phase = phase; + + libUUID = hNldrNode->uuid; + + /* At this point, we may not know if node is split into + * different libraries. So we'll go ahead and load the + * library, and then save the pointer to the appropriate + * location after we know. */ + + status = LoadLib(hNldrNode, &hNldrNode->root, libUUID, false, + hNldrNode->libPath, phase, 0); + + if (DSP_SUCCEEDED(status)) { + if (*hNldrNode->pfPhaseSplit) { + switch (phase) { + case NLDR_CREATE: + hNldrNode->createLib = hNldrNode->root; + break; + + case NLDR_EXECUTE: + hNldrNode->executeLib = hNldrNode->root; + break; + + case NLDR_DELETE: + hNldrNode->deleteLib = hNldrNode->root; + break; + + default: + DBC_Assert(false); + break; + } + } + } + } else { + if (hNldrNode->fOverlay) + status = LoadOvly(hNldrNode, phase); + + } + + return status; +} + +/* + * ======== NLDR_Unload ======== + */ +DSP_STATUS NLDR_Unload(struct NLDR_NODEOBJECT *hNldrNode, enum NLDR_PHASE phase) +{ + DSP_STATUS status = DSP_SOK; + struct LibNode *pRootLib = NULL; + s32 i = 0; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(hNldrNode, NLDR_NODESIGNATURE)); + GT_2trace(NLDR_debugMask, GT_ENTER, "NLDR_Unload(0x%x, 0x%x)\n", + hNldrNode, phase); + if (hNldrNode != NULL) { + if (hNldrNode->fDynamic) { + if (*hNldrNode->pfPhaseSplit) { + switch (phase) { + case NLDR_CREATE: + pRootLib = &hNldrNode->createLib; + break; + case NLDR_EXECUTE: + pRootLib = &hNldrNode->executeLib; + break; + case NLDR_DELETE: + pRootLib = &hNldrNode->deleteLib; + /* Unload persistent libraries */ + for (i = 0; i < hNldrNode->nPersLib; + i++) { + UnloadLib(hNldrNode, + &hNldrNode->persLib[i]); + } + hNldrNode->nPersLib = 0; + break; + default: + DBC_Assert(false); + break; + } + } else { + /* Unload main library */ + pRootLib = &hNldrNode->root; + } + UnloadLib(hNldrNode, pRootLib); + } else { + if (hNldrNode->fOverlay) + UnloadOvly(hNldrNode, phase); + + } + } + return status; +} + +/* + * ======== AddOvlyInfo ======== + */ +static DSP_STATUS AddOvlyInfo(void *handle, struct DBLL_SectInfo *sectInfo, + u32 addr, u32 nBytes) +{ + char *pNodeName; + char *pSectName = (char *)sectInfo->name; + bool fExists = false; + char seps = ':'; + char *pch; + u16 i; + struct NLDR_OBJECT *hNldr = (struct NLDR_OBJECT *)handle; + DSP_STATUS status = DSP_SOK; + + /* Is this an overlay section (load address != run address)? */ + if (sectInfo->loadAddr == sectInfo->runAddr) + goto func_end; + + /* Find the node it belongs to */ + for (i = 0; i < hNldr->nOvlyNodes; i++) { + pNodeName = hNldr->ovlyTable[i].pNodeName; + DBC_Require(pNodeName); + if (strncmp(pNodeName, pSectName + 1, + strlen(pNodeName)) == 0) { + /* Found the node */ + break; + } + } + if (!(i < hNldr->nOvlyNodes)) + goto func_end; + + /* Determine which phase this section belongs to */ + for (pch = pSectName + 1; *pch && *pch != seps; pch++) + ;; + + if (*pch) { + pch++; /* Skip over the ':' */ + if (strncmp(pch, PCREATE, strlen(PCREATE)) == 0) { + status = AddOvlySect(hNldr, &hNldr->ovlyTable[i]. + pCreateSects, sectInfo, &fExists, addr, nBytes); + if (DSP_SUCCEEDED(status) && !fExists) + hNldr->ovlyTable[i].nCreateSects++; + + } else + if (strncmp(pch, PDELETE, strlen(PDELETE)) == 0) { + status = AddOvlySect(hNldr, &hNldr->ovlyTable[i]. + pDeleteSects, sectInfo, &fExists, + addr, nBytes); + if (DSP_SUCCEEDED(status) && !fExists) + hNldr->ovlyTable[i].nDeleteSects++; + + } else + if (strncmp(pch, PEXECUTE, strlen(PEXECUTE)) == 0) { + status = AddOvlySect(hNldr, &hNldr->ovlyTable[i]. + pExecuteSects, sectInfo, &fExists, + addr, nBytes); + if (DSP_SUCCEEDED(status) && !fExists) + hNldr->ovlyTable[i].nExecuteSects++; + + } else { + /* Put in "other" sectins */ + status = AddOvlySect(hNldr, &hNldr->ovlyTable[i]. + pOtherSects, sectInfo, &fExists, + addr, nBytes); + if (DSP_SUCCEEDED(status) && !fExists) + hNldr->ovlyTable[i].nOtherSects++; + + } + } +func_end: + return status; +} + +/* + * ======== AddOvlyNode ========= + * Callback function passed to DCD_GetObjects. + */ +static DSP_STATUS AddOvlyNode(struct DSP_UUID *pUuid, + enum DSP_DCDOBJTYPE objType, + IN void *handle) +{ + struct NLDR_OBJECT *hNldr = (struct NLDR_OBJECT *)handle; + char *pNodeName = NULL; + char *pBuf = NULL; + u32 uLen; + struct DCD_GENERICOBJ objDef; + DSP_STATUS status = DSP_SOK; + + if (objType != DSP_DCDNODETYPE) + goto func_end; + + status = DCD_GetObjectDef(hNldr->hDcdMgr, pUuid, objType, &objDef); + if (DSP_FAILED(status)) + goto func_end; + + /* If overlay node, add to the list */ + if (objDef.objData.nodeObj.usLoadType == NLDR_OVLYLOAD) { + if (hNldr->ovlyTable == NULL) { + hNldr->nOvlyNodes++; + } else { + /* Add node to table */ + hNldr->ovlyTable[hNldr->nNode].uuid = *pUuid; + DBC_Require(objDef.objData.nodeObj.ndbProps.acName); + uLen = strlen(objDef.objData.nodeObj.ndbProps.acName); + pNodeName = objDef.objData.nodeObj.ndbProps.acName; + pBuf = MEM_Calloc(uLen + 1, MEM_PAGED); + if (pBuf == NULL) { + status = DSP_EMEMORY; + } else { + strncpy(pBuf, pNodeName, uLen); + hNldr->ovlyTable[hNldr->nNode].pNodeName = pBuf; + hNldr->nNode++; + } + } + } + /* These were allocated in DCD_GetObjectDef */ + if (objDef.objData.nodeObj.pstrCreatePhaseFxn) + MEM_Free(objDef.objData.nodeObj.pstrCreatePhaseFxn); + + if (objDef.objData.nodeObj.pstrExecutePhaseFxn) + MEM_Free(objDef.objData.nodeObj.pstrExecutePhaseFxn); + + if (objDef.objData.nodeObj.pstrDeletePhaseFxn) + MEM_Free(objDef.objData.nodeObj.pstrDeletePhaseFxn); + + if (objDef.objData.nodeObj.pstrIAlgName) + MEM_Free(objDef.objData.nodeObj.pstrIAlgName); + +func_end: + return status; +} + +/* + * ======== AddOvlySect ======== + */ +static DSP_STATUS AddOvlySect(struct NLDR_OBJECT *hNldr, + struct OvlySect **pList, + struct DBLL_SectInfo *pSectInfo, bool *pExists, + u32 addr, u32 nBytes) +{ + struct OvlySect *pNewSect = NULL; + struct OvlySect *pLastSect; + struct OvlySect *pSect; + DSP_STATUS status = DSP_SOK; + + pSect = pLastSect = *pList; + *pExists = false; + while (pSect) { + /* + * Make sure section has not already been added. Multiple + * 'write' calls may be made to load the section. + */ + if (pSect->loadAddr == addr) { + /* Already added */ + *pExists = true; + break; + } + pLastSect = pSect; + pSect = pSect->pNextSect; + } + + if (!pSect) { + /* New section */ + pNewSect = MEM_Calloc(sizeof(struct OvlySect), MEM_PAGED); + if (pNewSect == NULL) { + status = DSP_EMEMORY; + } else { + pNewSect->loadAddr = addr; + pNewSect->runAddr = pSectInfo->runAddr + + (addr - pSectInfo->loadAddr); + pNewSect->size = nBytes; + pNewSect->page = pSectInfo->type; + } + + /* Add to the list */ + if (DSP_SUCCEEDED(status)) { + if (*pList == NULL) { + /* First in the list */ + *pList = pNewSect; + } else { + pLastSect->pNextSect = pNewSect; + } + } + } + + return status; +} + +/* + * ======== fakeOvlyWrite ======== + */ +static s32 fakeOvlyWrite(void *handle, u32 dspAddr, void *buf, u32 nBytes, + s32 mtype) +{ + return (s32)nBytes; +} + +/* + * ======== FreeSects ======== + */ +static void FreeSects(struct NLDR_OBJECT *hNldr, struct OvlySect *pPhaseSects, + u16 nAlloc) +{ + struct OvlySect *pSect = pPhaseSects; + u16 i = 0; + bool fRet; + + while (pSect && i < nAlloc) { + /* 'Deallocate' */ + /* segid - page not supported yet */ + /* Reserved memory */ + fRet = RMM_free(hNldr->rmm, 0, pSect->runAddr, pSect->size, + true); + DBC_Assert(fRet); + pSect = pSect->pNextSect; + i++; + } +} + +/* + * ======== GetSymbolValue ======== + * Find symbol in library's base image. If not there, check dependent + * libraries. + */ +static bool GetSymbolValue(void *handle, void *pArg, void *rmmHandle, + char *name, struct DBLL_Symbol **sym) +{ + struct NLDR_OBJECT *hNldr = (struct NLDR_OBJECT *)handle; + struct NLDR_NODEOBJECT *hNldrNode = (struct NLDR_NODEOBJECT *)rmmHandle; + struct LibNode *root = (struct LibNode *)pArg; + u16 i; + bool status = false; + + /* check the base image */ + status = hNldr->dbllFxns.getAddrFxn(hNldr->baseLib, name, sym); + if (!status) + status = hNldr->dbllFxns.getCAddrFxn(hNldr->baseLib, name, sym); + + /* + * Check in root lib itself. If the library consists of + * multiple object files linked together, some symbols in the + * library may need to be resolved. + */ + if (!status) { + status = hNldr->dbllFxns.getAddrFxn(root->lib, name, sym); + if (!status) { + status = + hNldr->dbllFxns.getCAddrFxn(root->lib, name, sym); + } + } + + /* + * Check in root lib's dependent libraries, but not dependent + * libraries' dependents. + */ + if (!status) { + for (i = 0; i < root->nDepLibs; i++) { + status = hNldr->dbllFxns.getAddrFxn(root->pDepLibs[i]. + lib, name, sym); + if (!status) { + status = hNldr->dbllFxns.getCAddrFxn(root-> + pDepLibs[i].lib, name, sym); + } + if (status) { + /* Symbol found */ + break; + } + } + } + /* + * Check in persistent libraries + */ + if (!status) { + for (i = 0; i < hNldrNode->nPersLib; i++) { + status = hNldr->dbllFxns.getAddrFxn(hNldrNode-> + persLib[i].lib, name, sym); + if (!status) { + status = hNldr->dbllFxns.getCAddrFxn + (hNldrNode->persLib[i].lib, name, sym); + } + if (status) { + /* Symbol found */ + break; + } + } + } + + return status; +} + +/* + * ======== LoadLib ======== + * Recursively load library and all its dependent libraries. The library + * we're loading is specified by a uuid. + */ +static DSP_STATUS LoadLib(struct NLDR_NODEOBJECT *hNldrNode, + struct LibNode *root, struct DSP_UUID uuid, + bool rootPersistent, struct DBLL_LibraryObj **libPath, + enum NLDR_PHASE phase, u16 depth) +{ + struct NLDR_OBJECT *hNldr = hNldrNode->pNldr; + u16 nLibs = 0; /* Number of dependent libraries */ + u16 nPLibs = 0; /* Number of persistent libraries */ + u16 nLoaded = 0; /* Number of dep. libraries loaded */ + u16 i; + u32 entry; + u32 dwBufSize = NLDR_MAXPATHLENGTH; + DBLL_Flags flags = DBLL_SYMB | DBLL_CODE | DBLL_DATA | DBLL_DYNAMIC; + struct DBLL_Attrs newAttrs; + char *pszFileName = NULL; + struct DSP_UUID *depLibUUIDs = NULL; + bool *persistentDepLibs = NULL; + DSP_STATUS status = DSP_SOK; + bool fStatus = false; + struct LibNode *pDepLib; + + if (depth > MAXDEPTH) { + /* Error */ + DBC_Assert(false); + } + root->lib = NULL; + /* Allocate a buffer for library file name of size DBL_MAXPATHLENGTH */ + pszFileName = MEM_Calloc(DBLL_MAXPATHLENGTH, MEM_PAGED); + if (pszFileName == NULL) + status = DSP_EMEMORY; + + if (DSP_SUCCEEDED(status)) { + /* Get the name of the library */ + if (depth == 0) { + status = DCD_GetLibraryName(hNldrNode->pNldr->hDcdMgr, + &uuid, pszFileName, &dwBufSize, phase, + hNldrNode->pfPhaseSplit); + } else { + /* Dependent libraries are registered with a phase */ + status = DCD_GetLibraryName(hNldrNode->pNldr->hDcdMgr, + &uuid, pszFileName, &dwBufSize, NLDR_NOPHASE, + NULL); + } + } + if (DSP_SUCCEEDED(status)) { + /* Open the library, don't load symbols */ + status = hNldr->dbllFxns.openFxn(hNldr->dbll, pszFileName, + DBLL_NOLOAD, &root->lib); + } + /* Done with file name */ + if (pszFileName) + MEM_Free(pszFileName); + + /* Check to see if library not already loaded */ + if (DSP_SUCCEEDED(status) && rootPersistent) { + fStatus = findInPersistentLibArray(hNldrNode, root->lib); + /* Close library */ + if (fStatus) { + hNldr->dbllFxns.closeFxn(root->lib); + return DSP_SALREADYLOADED; + } + } + if (DSP_SUCCEEDED(status)) { + /* Check for circular dependencies. */ + for (i = 0; i < depth; i++) { + if (root->lib == libPath[i]) { + /* This condition could be checked by a + * tool at build time. */ + status = DSP_EDYNLOAD; + } + } + } + if (DSP_SUCCEEDED(status)) { + /* Add library to current path in dependency tree */ + libPath[depth] = root->lib; + depth++; + /* Get number of dependent libraries */ + status = DCD_GetNumDepLibs(hNldrNode->pNldr->hDcdMgr, &uuid, + &nLibs, &nPLibs, phase); + } + DBC_Assert(nLibs >= nPLibs); + if (DSP_SUCCEEDED(status)) { + if (!(*hNldrNode->pfPhaseSplit)) + nPLibs = 0; + + /* nLibs = #of dependent libraries */ + root->nDepLibs = nLibs - nPLibs; + if (nLibs > 0) { + depLibUUIDs = MEM_Calloc(sizeof(struct DSP_UUID) * + nLibs, MEM_PAGED); + persistentDepLibs = + MEM_Calloc(sizeof(bool) * nLibs, MEM_PAGED); + if (!depLibUUIDs || !persistentDepLibs) + status = DSP_EMEMORY; + + if (root->nDepLibs > 0) { + /* Allocate arrays for dependent lib UUIDs, + * lib nodes */ + root->pDepLibs = MEM_Calloc + (sizeof(struct LibNode) * + (root->nDepLibs), MEM_PAGED); + if (!(root->pDepLibs)) + status = DSP_EMEMORY; + + } + + if (DSP_SUCCEEDED(status)) { + /* Get the dependent library UUIDs */ + status = DCD_GetDepLibs(hNldrNode->pNldr-> + hDcdMgr, &uuid, nLibs, depLibUUIDs, + persistentDepLibs, phase); + } + } + } + + /* + * Recursively load dependent libraries. + */ + if (DSP_SUCCEEDED(status) && persistentDepLibs) { + for (i = 0; i < nLibs; i++) { + /* If root library is NOT persistent, and dep library + * is, then record it. If root library IS persistent, + * the deplib is already included */ + if (!rootPersistent && persistentDepLibs[i] && + *hNldrNode->pfPhaseSplit) { + if ((hNldrNode->nPersLib) > MAXLIBS) { + status = DSP_EDYNLOAD; + break; + } + + /* Allocate library outside of phase */ + pDepLib = &hNldrNode->persLib[hNldrNode-> + nPersLib]; + } else { + if (rootPersistent) + persistentDepLibs[i] = true; + + + /* Allocate library within phase */ + pDepLib = &root->pDepLibs[nLoaded]; + } + + if (depLibUUIDs) { + status = LoadLib(hNldrNode, pDepLib, + depLibUUIDs[i], + persistentDepLibs[i], libPath, + phase, + depth); + } else { + status = DSP_EMEMORY; + } + + if (DSP_SUCCEEDED(status)) { + if ((status != DSP_SALREADYLOADED) && + !rootPersistent && persistentDepLibs[i] && + *hNldrNode->pfPhaseSplit) { + (hNldrNode->nPersLib)++; + } else { + if (!persistentDepLibs[i] || + !(*hNldrNode->pfPhaseSplit)) { + nLoaded++; + } + } + } else { + break; + } + } + } + + /* Now we can load the root library */ + if (DSP_SUCCEEDED(status)) { + newAttrs = hNldr->dbllAttrs; + newAttrs.symArg = root; + newAttrs.rmmHandle = hNldrNode; + newAttrs.wHandle = hNldrNode->pPrivRef; + newAttrs.baseImage = false; + + status = hNldr->dbllFxns.loadFxn(root->lib, flags, &newAttrs, + &entry); + } + + /* + * In case of failure, unload any dependent libraries that + * were loaded, and close the root library. + * (Persistent libraries are unloaded from the very top) + */ + if (DSP_FAILED(status)) { + if (phase != NLDR_EXECUTE) { + for (i = 0; i < hNldrNode->nPersLib; i++) + UnloadLib(hNldrNode, &hNldrNode->persLib[i]); + + hNldrNode->nPersLib = 0; + } + for (i = 0; i < nLoaded; i++) + UnloadLib(hNldrNode, &root->pDepLibs[i]); + + if (root->lib) + hNldr->dbllFxns.closeFxn(root->lib); + + } + + /* Going up one node in the dependency tree */ + depth--; + + if (depLibUUIDs) { + MEM_Free(depLibUUIDs); + depLibUUIDs = NULL; + } + + if (persistentDepLibs) { + MEM_Free(persistentDepLibs); + persistentDepLibs = NULL; + } + + return status; +} + +/* + * ======== LoadOvly ======== + */ +static DSP_STATUS LoadOvly(struct NLDR_NODEOBJECT *hNldrNode, + enum NLDR_PHASE phase) +{ + struct NLDR_OBJECT *hNldr = hNldrNode->pNldr; + struct OvlyNode *pONode = NULL; + struct OvlySect *pPhaseSects = NULL; + struct OvlySect *pOtherSects = NULL; + u16 i; + u16 nAlloc = 0; + u16 nOtherAlloc = 0; + u16 *pRefCount = NULL; + u16 *pOtherRef = NULL; + u32 nBytes; + struct OvlySect *pSect; + DSP_STATUS status = DSP_SOK; + + /* Find the node in the table */ + for (i = 0; i < hNldr->nOvlyNodes; i++) { + if (IsEqualUUID(hNldrNode->uuid, hNldr->ovlyTable[i].uuid)) { + /* Found it */ + pONode = &(hNldr->ovlyTable[i]); + break; + } + } + + DBC_Assert(i < hNldr->nOvlyNodes); + switch (phase) { + case NLDR_CREATE: + pRefCount = &(pONode->createRef); + pOtherRef = &(pONode->otherRef); + pPhaseSects = pONode->pCreateSects; + pOtherSects = pONode->pOtherSects; + break; + + case NLDR_EXECUTE: + pRefCount = &(pONode->executeRef); + pPhaseSects = pONode->pExecuteSects; + break; + + case NLDR_DELETE: + pRefCount = &(pONode->deleteRef); + pPhaseSects = pONode->pDeleteSects; + break; + + default: + DBC_Assert(false); + break; + } + + DBC_Assert(pRefCount != NULL); + if (DSP_FAILED(status)) + goto func_end; + + if (pRefCount == NULL) + goto func_end; + + if (*pRefCount != 0) + goto func_end; + + /* 'Allocate' memory for overlay sections of this phase */ + pSect = pPhaseSects; + while (pSect) { + /* allocate */ /* page not supported yet */ + /* reserve */ /* align */ + status = RMM_alloc(hNldr->rmm, 0, pSect->size, 0, + &(pSect->runAddr), true); + if (DSP_SUCCEEDED(status)) { + pSect = pSect->pNextSect; + nAlloc++; + } else { + break; + } + } + if (pOtherRef && *pOtherRef == 0) { + /* 'Allocate' memory for other overlay sections + * (create phase) */ + if (DSP_SUCCEEDED(status)) { + pSect = pOtherSects; + while (pSect) { + /* page not supported */ /* align */ + /* reserve */ + status = RMM_alloc(hNldr->rmm, 0, pSect->size, + 0, &(pSect->runAddr), true); + if (DSP_SUCCEEDED(status)) { + pSect = pSect->pNextSect; + nOtherAlloc++; + } else { + break; + } + } + } + } + if (*pRefCount == 0) { + if (DSP_SUCCEEDED(status)) { + /* Load sections for this phase */ + pSect = pPhaseSects; + while (pSect && DSP_SUCCEEDED(status)) { + nBytes = (*hNldr->ovlyFxn)(hNldrNode->pPrivRef, + pSect->runAddr, pSect->loadAddr, + pSect->size, pSect->page); + if (nBytes != pSect->size) + status = DSP_EFAIL; + + pSect = pSect->pNextSect; + } + } + } + if (pOtherRef && *pOtherRef == 0) { + if (DSP_SUCCEEDED(status)) { + /* Load other sections (create phase) */ + pSect = pOtherSects; + while (pSect && DSP_SUCCEEDED(status)) { + nBytes = (*hNldr->ovlyFxn)(hNldrNode->pPrivRef, + pSect->runAddr, pSect->loadAddr, + pSect->size, pSect->page); + if (nBytes != pSect->size) + status = DSP_EFAIL; + + pSect = pSect->pNextSect; + } + } + } + if (DSP_FAILED(status)) { + /* 'Deallocate' memory */ + FreeSects(hNldr, pPhaseSects, nAlloc); + FreeSects(hNldr, pOtherSects, nOtherAlloc); + } +func_end: + if (DSP_SUCCEEDED(status) && (pRefCount != NULL)) { + *pRefCount += 1; + if (pOtherRef) + *pOtherRef += 1; + + } + + return status; +} + +/* + * ======== RemoteAlloc ======== + */ +static DSP_STATUS RemoteAlloc(void **pRef, u16 space, u32 size, + u32 align, u32 *dspAddr, + OPTIONAL s32 segmentId, OPTIONAL s32 req, + bool reserve) +{ + struct NLDR_NODEOBJECT *hNode = (struct NLDR_NODEOBJECT *)pRef; + struct NLDR_OBJECT *hNldr; + struct RMM_TargetObj *rmm; + u16 memPhaseBit = MAXFLAGS; + u16 segid = 0; + u16 i; + u16 memType; + u32 nWords; + struct RMM_Addr *pRmmAddr = (struct RMM_Addr *)dspAddr; + bool fReq = false; + DSP_STATUS status = DSP_EMEMORY; /* Set to fail */ + DBC_Require(MEM_IsValidHandle(hNode, NLDR_NODESIGNATURE)); + DBC_Require(space == DBLL_CODE || space == DBLL_DATA || + space == DBLL_BSS); + hNldr = hNode->pNldr; + rmm = hNldr->rmm; + /* Convert size to DSP words */ + nWords = (size + hNldr->usDSPWordSize - 1) / hNldr->usDSPWordSize; + /* Modify memory 'align' to account for DSP cache line size */ + align = findLcm(GEM_CACHE_LINE_SIZE, align); + GT_1trace(NLDR_debugMask, GT_7CLASS, + "RemoteAlloc: memory align to 0x%x \n", align); + if (segmentId != -1) { + pRmmAddr->segid = segmentId; + segid = segmentId; + fReq = req; + } else { + switch (hNode->phase) { + case NLDR_CREATE: + memPhaseBit = CREATEDATAFLAGBIT; + break; + case NLDR_DELETE: + memPhaseBit = DELETEDATAFLAGBIT; + break; + case NLDR_EXECUTE: + memPhaseBit = EXECUTEDATAFLAGBIT; + break; + default: + DBC_Assert(false); + break; + } + if (space == DBLL_CODE) + memPhaseBit++; + + if (memPhaseBit < MAXFLAGS) + segid = hNode->segId[memPhaseBit]; + + /* Determine if there is a memory loading requirement */ + if ((hNode->codeDataFlagMask >> memPhaseBit) & 0x1) + fReq = true; + + } + memType = (space == DBLL_CODE) ? DYNM_CODE : DYNM_DATA; + + /* Find an appropriate segment based on space */ + if (segid == NULLID) { + /* No memory requirements of preferences */ + DBC_Assert(!fReq); + goto func_cont; + } + if (segid <= MAXSEGID) { + DBC_Assert(segid < hNldr->nSegs); + /* Attempt to allocate from segid first. */ + pRmmAddr->segid = segid; + status = RMM_alloc(rmm, segid, nWords, align, dspAddr, false); + if (DSP_FAILED(status)) { + GT_1trace(NLDR_debugMask, GT_6CLASS, + "RemoteAlloc:Unable allocate " + "from segment %d.\n", segid); + } + } else { + /* segid > MAXSEGID ==> Internal or external memory */ + DBC_Assert(segid == MEMINTERNALID || segid == MEMEXTERNALID); + /* Check for any internal or external memory segment, + * depending on segid.*/ + memType |= segid == MEMINTERNALID ? + DYNM_INTERNAL : DYNM_EXTERNAL; + for (i = 0; i < hNldr->nSegs; i++) { + if ((hNldr->segTable[i] & memType) != memType) + continue; + + status = RMM_alloc(rmm, i, nWords, align, dspAddr, + false); + if (DSP_SUCCEEDED(status)) { + /* Save segid for freeing later */ + pRmmAddr->segid = i; + break; + } + } + } +func_cont: + /* Haven't found memory yet, attempt to find any segment that works */ + if (status == DSP_EMEMORY && !fReq) { + GT_0trace(NLDR_debugMask, GT_6CLASS, + "RemoteAlloc: Preferred segment " + "unavailable, trying another segment.\n"); + for (i = 0; i < hNldr->nSegs; i++) { + /* All bits of memType must be set */ + if ((hNldr->segTable[i] & memType) != memType) + continue; + + status = RMM_alloc(rmm, i, nWords, align, dspAddr, + false); + if (DSP_SUCCEEDED(status)) { + /* Save segid */ + pRmmAddr->segid = i; + break; + } + } + } + + return status; +} + +static DSP_STATUS RemoteFree(void **pRef, u16 space, u32 dspAddr, + u32 size, bool reserve) +{ + struct NLDR_OBJECT *hNldr = (struct NLDR_OBJECT *)pRef; + struct RMM_TargetObj *rmm; + u32 nWords; + DSP_STATUS status = DSP_EMEMORY; /* Set to fail */ + + DBC_Require(MEM_IsValidHandle(hNldr, NLDR_SIGNATURE)); + + rmm = hNldr->rmm; + + /* Convert size to DSP words */ + nWords = (size + hNldr->usDSPWordSize - 1) / hNldr->usDSPWordSize; + + if (RMM_free(rmm, space, dspAddr, nWords, reserve)) + status = DSP_SOK; + + return status; +} + +/* + * ======== UnloadLib ======== + */ +static void UnloadLib(struct NLDR_NODEOBJECT *hNldrNode, struct LibNode *root) +{ + struct DBLL_Attrs newAttrs; + struct NLDR_OBJECT *hNldr = hNldrNode->pNldr; + u16 i; + + DBC_Assert(root != NULL); + + /* Unload dependent libraries */ + for (i = 0; i < root->nDepLibs; i++) + UnloadLib(hNldrNode, &root->pDepLibs[i]); + + root->nDepLibs = 0; + + newAttrs = hNldr->dbllAttrs; + newAttrs.rmmHandle = hNldr->rmm; + newAttrs.wHandle = hNldrNode->pPrivRef; + newAttrs.baseImage = false; + newAttrs.symArg = root; + + if (root->lib) { + /* Unload the root library */ + hNldr->dbllFxns.unloadFxn(root->lib, &newAttrs); + hNldr->dbllFxns.closeFxn(root->lib); + } + + /* Free dependent library list */ + if (root->pDepLibs) { + MEM_Free(root->pDepLibs); + root->pDepLibs = NULL; + } +} + +/* + * ======== UnloadOvly ======== + */ +static void UnloadOvly(struct NLDR_NODEOBJECT *hNldrNode, enum NLDR_PHASE phase) +{ + struct NLDR_OBJECT *hNldr = hNldrNode->pNldr; + struct OvlyNode *pONode = NULL; + struct OvlySect *pPhaseSects = NULL; + struct OvlySect *pOtherSects = NULL; + u16 i; + u16 nAlloc = 0; + u16 nOtherAlloc = 0; + u16 *pRefCount = NULL; + u16 *pOtherRef = NULL; + DSP_STATUS status = DSP_SOK; + + /* Find the node in the table */ + for (i = 0; i < hNldr->nOvlyNodes; i++) { + if (IsEqualUUID(hNldrNode->uuid, hNldr->ovlyTable[i].uuid)) { + /* Found it */ + pONode = &(hNldr->ovlyTable[i]); + break; + } + } + + DBC_Assert(i < hNldr->nOvlyNodes); + switch (phase) { + case NLDR_CREATE: + pRefCount = &(pONode->createRef); + pPhaseSects = pONode->pCreateSects; + nAlloc = pONode->nCreateSects; + break; + case NLDR_EXECUTE: + pRefCount = &(pONode->executeRef); + pPhaseSects = pONode->pExecuteSects; + nAlloc = pONode->nExecuteSects; + break; + case NLDR_DELETE: + pRefCount = &(pONode->deleteRef); + pOtherRef = &(pONode->otherRef); + pPhaseSects = pONode->pDeleteSects; + /* 'Other' overlay sections are unloaded in the delete phase */ + pOtherSects = pONode->pOtherSects; + nAlloc = pONode->nDeleteSects; + nOtherAlloc = pONode->nOtherSects; + break; + default: + DBC_Assert(false); + break; + } + if (DSP_SUCCEEDED(status)) { + DBC_Assert(pRefCount && (*pRefCount > 0)); + if (pRefCount && (*pRefCount > 0)) { + *pRefCount -= 1; + if (pOtherRef) { + DBC_Assert(*pOtherRef > 0); + *pOtherRef -= 1; + } + } + } + if (pRefCount && (*pRefCount == 0)) { + /* 'Deallocate' memory */ + FreeSects(hNldr, pPhaseSects, nAlloc); + } + if (pOtherRef && *pOtherRef == 0) + FreeSects(hNldr, pOtherSects, nOtherAlloc); + +} + +/* + * ======== findInPersistentLibArray ======== + */ +static bool findInPersistentLibArray(struct NLDR_NODEOBJECT *hNldrNode, + struct DBLL_LibraryObj *lib) +{ + s32 i = 0; + + for (i = 0; i < hNldrNode->nPersLib; i++) { + if (lib == hNldrNode->persLib[i].lib) + return true; + + } + + return false; +} + +/* + * ================ Find LCM (Least Common Multiplier === + */ +static u32 findLcm(u32 a, u32 b) +{ + u32 retVal; + + retVal = a * b / findGcf(a, b); + + return retVal; +} + +/* + * ================ Find GCF (Greatest Common Factor ) === + */ +static u32 findGcf(u32 a, u32 b) +{ + u32 c; + + /* Get the GCF (Greatest common factor between the numbers, + * using Euclidian Algo */ + while ((c = (a % b))) { + a = b; + b = c; + } + return b; +} + diff --git a/drivers/dsp/bridge/rmgr/node.c b/drivers/dsp/bridge/rmgr/node.c new file mode 100644 index 0000000..178b802 --- /dev/null +++ b/drivers/dsp/bridge/rmgr/node.c @@ -0,0 +1,3544 @@ +/* + * node.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== node.c ======== + * + * Description: + * DSP/BIOS Bridge Node Manager. + * + * Public Functions: + * NODE_Allocate + * NODE_AllocMsgBuf + * NODE_ChangePriority + * NODE_Connect + * NODE_Create + * NODE_CreateMgr + * NODE_Delete + * NODE_DeleteMgr + * NODE_EnumNodes + * NODE_Exit + * NODE_FreeMsgBuf + * NODE_GetAttr + * NODE_GetChannelId + * NODE_GetMessage + * NODE_GetStrmMgr + * NODE_Init + * NODE_OnExit + * NODE_Pause + * NODE_PutMessage + * NODE_RegisterNotify + * NODE_Run + * NODE_Terminate + * + *! Revision History: + *! ================= + *! 12-Apr-2004 hp Compile IVA only for 24xx + *! 09-Feb-2004 vp Updated to support IVA. + *! 07-Apr-2003 map Eliminated references to old DLDR + *! 26-Mar-2003 vp Commented the call to DSP deep sleep in Node_Delete + *! function. + *! 18-Feb-2003 vp Code review updates. + *! 06-Feb-2003 kc Fixed FreeStream to release streams correctly. + *! 23-Jan-2003 map Removed call to DISP_DoCinit within Write() + *! 03-Jan-2003 map Only unload code after phase has executed if + *! overlay or split dynload phases + *! 18-Oct-2002 vp Ported to Linux platform. + *! 06-Nov-2002 map Fixed NODE_Run on NODE_PAUSED bug + *! 12-Oct-2002 map Fixed DeleteNode bug in NODE_Create + *! 11-Sep-2002 rr DeleteNode frees the memory for strmConnect and dcd obj + *! 29-Aug-2002 map Modified Ovly and Write to use ARM-side copy + *! 22-May-2002 sg Changed use of cbData for PWR calls. + *! 17-May-2002 jeh Removed LoadLoaderFxns(). Get address of RMS_cinit() + *! function. Call DISP_DoCinit() from Write(), if .cinit. + *! 13-May-2002 sg Added timeout to wake/sleep calls. + *! 02-May-2002 sg Added wake/sleep of DSP to support "nap" mode. + *! 18-Apr-2002 jeh Use dynamic loader if compile flag is set. + *! 13-Feb-2002 jeh Get uSysStackSize from DSP_NDBPROPS. + *! 07-Jan-2002 ag STRMMODE_ZEROCOPY(shared memory buffer swap) enabled. + *! 17-Dec-2001 ag STRMMODE_RDMA(DDMA) enabled. + *! 12-Dec-2001 ag Check for valid stream mode in NODE_Connect(). + *! 04-Dec-2001 jeh Check for node sufficiently connected in NODE_Create(). + *! 15-Nov-2001 jeh Removed DBC_Require(pNode->hXlator != NULL) from + *! NODE_AllocMsgBuf(), and check node type != NODE_DEVICE. + *! 11-Sep-2001 ag Zero-copy messaging support. + *! 28-Aug-2001 jeh Overlay/dynamic loader infrastructure added. Removed + *! NODE_GetDispatcher, excess node states. + *! 07-Aug-2001 jeh Removed critical section for dispatcher. + *! 26-Jul-2001 jeh Get ZL dll name through CFG. + *! 05-Jun-2001 jeh Assume DSP_STRMATTRS.uBufsize in GPP bytes. + *! 11-May-2001 jeh Some code review cleanup. + *! 13-Feb-2001 kc: DSP/BIOS Bridge name updates. + *! 15-Dec-2000 sg Convert IALG_Fxn address from byte addr to word addr. + *! 04-Dec-2000 jeh Call MSG Get and Put functions. + *! 04-Dec-2000 ag Added SM support for node messaging. + *! 10-Nov-2000 rr: NODE_MIN/MAX Priority is defined in dspdefs.h. + *! 27-Oct-2000 jeh Added NODE_AllocMsgBuf(), NODE_FreeMsgBuf(). + *! 11-Oct-2000 jeh Changed NODE_EnumNodeInfo to NODE_EnumNodes. Added + *! NODE_CloseOrphans(). Remove NODE_RegisterNotifyAllNodes + *! 19-Jun-2000 jeh Created. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* ----------------------------------- Platform Manager */ +#include +#include +#include +#include + +/* ----------------------------------- Resource Manager */ +#include +#include +#include + +/* ----------------------------------- Link Driver */ +#include +#include + +/* ----------------------------------- Others */ +#include +#ifdef DEBUG +#include +#include +#endif + +/* ----------------------------------- This */ +#include +#include + +/* Static/Dynamic Loader includes */ +#include +#include + +#ifndef RES_CLEANUP_DISABLE +#include +#include +#include +#include +#endif + + +#define NODE_SIGNATURE 0x45444f4e /* "EDON" */ +#define NODEMGR_SIGNATURE 0x52474d4e /* "RGMN" */ + +#define HOSTPREFIX "/host" +#define PIPEPREFIX "/dbpipe" + +#define MaxInputs(h) ((h)->dcdProps.objData.nodeObj.ndbProps.uNumInputStreams) +#define MaxOutputs(h) ((h)->dcdProps.objData.nodeObj.ndbProps.uNumOutputStreams) + +#define NODE_GetPriority(h) ((h)->nPriority) +#define NODE_SetPriority(hNode, nPriority) ((hNode)->nPriority = nPriority) +#define NODE_SetState(hNode, state) ((hNode)->nState = state) + +#define MAXPIPES 100 /* Max # of /pipe connections (CSL limit) */ +#define MAXDEVSUFFIXLEN 2 /* Max(Log base 10 of MAXPIPES, MAXSTREAMS) */ + +#define PIPENAMELEN (sizeof(PIPEPREFIX) + MAXDEVSUFFIXLEN) +#define HOSTNAMELEN (sizeof(HOSTPREFIX) + MAXDEVSUFFIXLEN) + +#define MAXDEVNAMELEN 32 /* DSP_NDBPROPS.acName size */ +#define CREATEPHASE 1 +#define EXECUTEPHASE 2 +#define DELETEPHASE 3 + +/* Define default STRM parameters */ +/* + * TBD: Put in header file, make global DSP_STRMATTRS with defaults, + * or make defaults configurable. + */ +#define DEFAULTBUFSIZE 32 +#define DEFAULTNBUFS 2 +#define DEFAULTSEGID 0 +#define DEFAULTALIGNMENT 0 +#define DEFAULTTIMEOUT 10000 + +#define RMSQUERYSERVER 0 +#define RMSCONFIGURESERVER 1 +#define RMSCREATENODE 2 +#define RMSEXECUTENODE 3 +#define RMSDELETENODE 4 +#define RMSCHANGENODEPRIORITY 5 +#define RMSREADMEMORY 6 +#define RMSWRITEMEMORY 7 +#define RMSCOPY 8 +#define MAXTIMEOUT 2000 + +#define NUMRMSFXNS 9 + +#define PWR_TIMEOUT 500 /* default PWR timeout in msec */ + +#define STACKSEGLABEL "L1DSRAM_HEAP" /* Label for DSP Stack Segment Address */ + +/* + * ======== NODE_MGR ======== + */ +struct NODE_MGR { + u32 dwSignature; /* For object validation */ + struct DEV_OBJECT *hDevObject; /* Device object */ + struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD */ + struct DCD_MANAGER *hDcdMgr; /* Proc/Node data manager */ + struct DISP_OBJECT *hDisp; /* Node dispatcher */ + struct LST_LIST *nodeList; /* List of all allocated nodes */ + u32 uNumNodes; /* Number of nodes in nodeList */ + u32 uNumCreated; /* Number of nodes *created* on DSP */ + struct GB_TMap *pipeMap; /* Pipe connection bit map */ + struct GB_TMap *pipeDoneMap; /* Pipes that are half free */ + struct GB_TMap *chnlMap; /* Channel allocation bit map */ + struct GB_TMap *dmaChnlMap; /* DMA Channel allocation bit map */ + struct GB_TMap *zChnlMap; /* Zero-Copy Channel alloc bit map */ + struct NTFY_OBJECT *hNtfy; /* Manages registered notifications */ + struct SYNC_CSOBJECT *hSync; /* For critical sections */ + u32 ulFxnAddrs[NUMRMSFXNS]; /* RMS function addresses */ + struct MSG_MGR *hMsg; + + /* Processor properties needed by Node Dispatcher */ + u32 ulNumChnls; /* Total number of channels */ + u32 ulChnlOffset; /* Offset of chnl ids rsvd for RMS */ + u32 ulChnlBufSize; /* Buffer size for data to RMS */ + DSP_PROCFAMILY procFamily; /* eg, 5000 */ + DSP_PROCTYPE procType; /* eg, 5510 */ + u32 uDSPWordSize; /* Size of DSP word on host bytes */ + u32 uDSPDataMauSize; /* Size of DSP data MAU */ + u32 uDSPMauSize; /* Size of MAU */ + s32 nMinPri; /* Minimum runtime priority for node */ + s32 nMaxPri; /* Maximum runtime priority for node */ + + struct STRM_MGR *hStrmMgr; /* STRM manager */ + + /* Loader properties */ + struct NLDR_OBJECT *hNldr; /* Handle to loader */ + struct NLDR_FXNS nldrFxns; /* Handle to loader functions */ + bool fLoaderInit; /* Loader Init function succeeded? */ +}; + +/* + * ======== CONNECTTYPE ======== + */ +enum CONNECTTYPE { + NOTCONNECTED = 0, + NODECONNECT, + HOSTCONNECT, + DEVICECONNECT, +} ; + +/* + * ======== STREAM ======== + */ +struct STREAM { + enum CONNECTTYPE type; /* Type of stream connection */ + u32 devId; /* pipe or channel id */ +}; + +/* + * ======== NODE_OBJECT ======== + */ +struct NODE_OBJECT { + struct LST_ELEM listElem; + u32 dwSignature; /* For object validation */ + struct NODE_MGR *hNodeMgr; /* The manager of this node */ + struct PROC_OBJECT *hProcessor; /* Back pointer to processor */ + struct DSP_UUID nodeId; /* Node's ID */ + s32 nPriority; /* Node's current priority */ + u32 uTimeout; /* Timeout for blocking NODE calls */ + u32 uHeapSize; /* Heap Size */ + u32 uDSPHeapVirtAddr; /* Heap Size */ + u32 uGPPHeapVirtAddr; /* Heap Size */ + enum NODE_TYPE nType; /* Type of node: message, task, etc */ + enum NODE_STATE nState; /* NODE_ALLOCATED, NODE_CREATED, ... */ + u32 uNumInputs; /* Current number of inputs */ + u32 uNumOutputs; /* Current number of outputs */ + u32 uMaxInputIndex; /* Current max input stream index */ + u32 uMaxOutputIndex; /* Current max output stream index */ + struct STREAM *inputs; /* Node's input streams */ + struct STREAM *outputs; /* Node's output streams */ + struct NODE_CREATEARGS createArgs; /* Args for node create function */ + NODE_ENV nodeEnv; /* Environment returned by RMS */ + struct DCD_GENERICOBJ dcdProps; /* Node properties from DCD */ + struct DSP_CBDATA *pArgs; /* Optional args to pass to node */ + struct NTFY_OBJECT *hNtfy; /* Manages registered notifications */ + char *pstrDevName; /* device name, if device node */ + struct SYNC_OBJECT *hSyncDone; /* Synchronize NODE_Terminate */ + s32 nExitStatus; /* execute function return status */ + + /* Information needed for NODE_GetAttr() */ + DSP_HNODE hDeviceOwner; /* If dev node, task that owns it */ + u32 uNumGPPInputs; /* Current # of from GPP streams */ + u32 uNumGPPOutputs; /* Current # of to GPP streams */ + /* Current stream connections */ + struct DSP_STREAMCONNECT *streamConnect; + + /* Message queue */ + struct MSG_QUEUE *hMsgQueue; + + /* These fields used for SM messaging */ + struct CMM_XLATOROBJECT *hXlator; /* Node's SM address translator */ + + /* Handle to pass to dynamic loader */ + struct NLDR_NODEOBJECT *hNldrNode; + bool fLoaded; /* Code is (dynamically) loaded */ + bool fPhaseSplit; /* Phases split in many libs or ovly */ + +} ; + +/* Default buffer attributes */ +static struct DSP_BUFFERATTR NODE_DFLTBUFATTRS = { + 0, /* cbStruct */ + 1, /* uSegment */ + 0, /* uAlignment */ +}; + +static void DeleteNode(struct NODE_OBJECT *hNode); +static void DeleteNodeMgr(struct NODE_MGR *hNodeMgr); +static void FillStreamConnect(struct NODE_OBJECT *hNode1, + struct NODE_OBJECT *hNode2, u32 uStream1, + u32 uStream2); +static void FillStreamDef(struct NODE_OBJECT *hNode, + struct NODE_STRMDEF *pstrmDef, + struct DSP_STRMATTR *pAttrs); +static void FreeStream(struct NODE_MGR *hNodeMgr, struct STREAM stream); +static DSP_STATUS GetFxnAddress(struct NODE_OBJECT *hNode, u32 *pulFxnAddr, + u32 uPhase); +static DSP_STATUS GetNodeProps(struct DCD_MANAGER *hDcdMgr, + struct NODE_OBJECT *hNode, + CONST struct DSP_UUID *pNodeId, + struct DCD_GENERICOBJ *pdcdProps); +static DSP_STATUS GetProcProps(struct NODE_MGR *hNodeMgr, + struct DEV_OBJECT *hDevObject); +static DSP_STATUS GetRMSFxns(struct NODE_MGR *hNodeMgr); +static u32 Ovly(void *pPrivRef, u32 ulDspRunAddr, u32 ulDspLoadAddr, + u32 ulNumBytes, u32 nMemSpace); +static u32 Write(void *pPrivRef, u32 ulDspAddr, void *pBuf, + u32 ulNumBytes, u32 nMemSpace); + +#if GT_TRACE +static struct GT_Mask NODE_debugMask = { NULL, NULL }; /* GT trace variable */ +#endif + +#ifdef DSP_DMM_DEBUG +extern u32 DMM_MemMapDump(struct DMM_OBJECT *hDmmMgr); +#endif + +static u32 cRefs; /* module reference count */ + +/* Dynamic loader functions. */ +static struct NLDR_FXNS nldrFxns = { + NLDR_Allocate, + NLDR_Create, + NLDR_Delete, + NLDR_Exit, + NLDR_Free, + NLDR_GetFxnAddr, + NLDR_Init, + NLDR_Load, + NLDR_Unload, +}; + +enum NODE_STATE NODE_GetState(HANDLE hNode) +{ + struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode; + if (!MEM_IsValidHandle(pNode, NODE_SIGNATURE)) { + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_GetState:hNode 0x%x\n", pNode); + return -1; + } else + return pNode->nState; + +} + +/* + * ======== NODE_Allocate ======== + * Purpose: + * Allocate GPP resources to manage a node on the DSP. + */ +DSP_STATUS NODE_Allocate(struct PROC_OBJECT *hProcessor, + IN CONST struct DSP_UUID *pNodeId, + OPTIONAL IN CONST struct DSP_CBDATA *pArgs, + OPTIONAL IN CONST struct DSP_NODEATTRIN *pAttrIn, + OUT struct NODE_OBJECT **phNode) +{ + struct NODE_MGR *hNodeMgr; + struct DEV_OBJECT *hDevObject; + struct NODE_OBJECT *pNode = NULL; + enum NODE_TYPE nodeType = NODE_TASK; + struct NODE_MSGARGS *pmsgArgs; + struct NODE_TASKARGS *ptaskArgs; + u32 uNumStreams; + struct WMD_DRV_INTERFACE *pIntfFxns; + DSP_STATUS status = DSP_SOK; + struct CMM_OBJECT *hCmmMgr = NULL; /* Shared memory manager hndl */ + u32 procId; + char *label; + u32 pulValue; + u32 dynextBase; + u32 offSet = 0; + u32 ulStackSegAddr, ulStackSegVal; + u32 ulGppMemBase; + struct CFG_HOSTRES hostRes; + u32 pMappedAddr = 0; + u32 mapAttrs = 0x0; + struct DSP_PROCESSORSTATE procStatus; +#ifdef DSP_DMM_DEBUG + struct DMM_OBJECT *hDmmMgr; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor; +#endif + +#ifndef RES_CLEANUP_DISABLE + HANDLE hDrvObject; + HANDLE nodeRes; + u32 hProcess; + struct PROCESS_CONTEXT *pPctxt = NULL; + DSP_STATUS res_status = DSP_SOK; +#endif + + DBC_Require(cRefs > 0); + DBC_Require(hProcessor != NULL); + DBC_Require(phNode != NULL); + DBC_Require(pNodeId != NULL); + + GT_5trace(NODE_debugMask, GT_ENTER, "NODE_Allocate: \thProcessor: " + "0x%x\tpNodeId: 0x%x\tpArgs: 0x%x\tpAttrIn: " + "0x%x\tphNode: 0x%x\n", hProcessor, pNodeId, pArgs, pAttrIn, + phNode); + + *phNode = NULL; + + status = PROC_GetProcessorId(hProcessor, &procId); + + status = PROC_GetDevObject(hProcessor, &hDevObject); + if (DSP_SUCCEEDED(status)) { + status = DEV_GetNodeManager(hDevObject, &hNodeMgr); + if (hNodeMgr == NULL) + status = DSP_EFAIL; + + } + if (procId != DSP_UNIT) + goto func_cont; + + if (DSP_FAILED(status)) + goto func_cont; + + status = PROC_GetState(hProcessor, &procStatus, + sizeof(struct DSP_PROCESSORSTATE)); + if (DSP_FAILED(status)) + goto func_end; + /* If processor is in error state then don't attempt + to send the message */ + if (procStatus.iState == PROC_ERROR) { + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_Allocate: proc Status 0x%x\n", + procStatus.iState); + status = DSP_EFAIL; + goto func_end; + } + + /* Assuming that 0 is not a valid function address */ + if (hNodeMgr->ulFxnAddrs[0] == 0) { + /* No RMS on target - we currently can't handle this */ + GT_0trace(NODE_debugMask, GT_5CLASS, "No RMS functions in base " + "image. Node allocation fails.\n"); + status = DSP_EFAIL; + } else { + /* Validate pAttrIn fields, if non-NULL */ + if (pAttrIn) { + /* Check if pAttrIn->iPriority is within range */ + if (pAttrIn->iPriority < hNodeMgr->nMinPri || + pAttrIn->iPriority > hNodeMgr->nMaxPri) + status = DSP_ERANGE; + } + } +func_cont: + /* Allocate node object and fill in */ + if (DSP_FAILED(status)) + goto func_cont2; + + MEM_AllocObject(pNode, struct NODE_OBJECT, NODE_SIGNATURE); + if (pNode == NULL) { + status = DSP_EMEMORY; + goto func_cont1; + } + pNode->hNodeMgr = hNodeMgr; + /* This critical section protects GetNodeProps */ + status = SYNC_EnterCS(hNodeMgr->hSync); + if (procId != DSP_UNIT) + goto func_cont3; + + /* Get DSP_NDBPROPS from node database */ + status = GetNodeProps(hNodeMgr->hDcdMgr, pNode, pNodeId, + &(pNode->dcdProps)); + if (DSP_FAILED(status)) + goto func_cont3; + + pNode->nodeId = *pNodeId; + pNode->hProcessor = hProcessor; + pNode->nType = pNode->dcdProps.objData.nodeObj.ndbProps.uNodeType; + pNode->uTimeout = pNode->dcdProps.objData.nodeObj.ndbProps.uTimeout; + pNode->nPriority = pNode->dcdProps.objData.nodeObj.ndbProps.iPriority; + + /* Currently only C64 DSP builds support Node Dynamic * heaps */ + /* Allocate memory for node heap */ + pNode->createArgs.asa.taskArgs.uHeapSize = 0; + pNode->createArgs.asa.taskArgs.uDSPHeapAddr = 0; + pNode->createArgs.asa.taskArgs.uDSPHeapResAddr = 0; + pNode->createArgs.asa.taskArgs.uGPPHeapAddr = 0; + if (!pAttrIn) + goto func_cont3; + + /* Check if we have a user allocated node heap */ + if (!(pAttrIn->pGPPVirtAddr)) + goto func_cont3; + + /* check for page aligned Heap size */ + if (((pAttrIn->uHeapSize) & (PG_SIZE_4K - 1))) { + GT_1trace(NODE_debugMask, GT_7CLASS, + "NODE_Allocate: node heap page size" + " not aligned to 4K page, size=0x%x \n", + pAttrIn->uHeapSize); + status = DSP_EINVALIDARG; + } else { + pNode->createArgs.asa.taskArgs.uHeapSize = pAttrIn->uHeapSize; + pNode->createArgs.asa.taskArgs.uGPPHeapAddr = + (u32)pAttrIn->pGPPVirtAddr; + } + if (DSP_FAILED(status)) + goto func_cont3; + + status = PROC_ReserveMemory(hProcessor, + pNode->createArgs.asa.taskArgs.uHeapSize + PAGE_SIZE, + (void **)&(pNode->createArgs.asa.taskArgs. + uDSPHeapResAddr)); + if (DSP_FAILED(status)) { + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_Allocate:Failed to reserve " + "memory for Heap: 0x%x\n", status); + } else { + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_Allocate: DSPProcessor_Reserve" + " Memory successful: 0x%x\n", status); + } +#ifdef DSP_DMM_DEBUG + status = DMM_GetHandle(pProcObject, &hDmmMgr); + if (DSP_SUCCEEDED(status)) + DMM_MemMapDump(hDmmMgr); +#endif + if (DSP_FAILED(status)) + goto func_cont3; + + mapAttrs |= DSP_MAPLITTLEENDIAN; + mapAttrs |= DSP_MAPELEMSIZE32; + mapAttrs |= DSP_MAPVIRTUALADDR; + status = PROC_Map(hProcessor, (void *)pAttrIn->pGPPVirtAddr, + pNode->createArgs.asa.taskArgs.uHeapSize, + (void *)pNode->createArgs.asa.taskArgs.uDSPHeapResAddr, + (void **)&pMappedAddr, mapAttrs); + if (DSP_FAILED(status)) { + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_Allocate: Failed to map memory" + " for Heap: 0x%x\n", status); + } else { + pNode->createArgs.asa.taskArgs.uDSPHeapAddr = + (u32) pMappedAddr; + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_Allocate:DSPProcessor_Map" + " successful: 0x%x\n", status); + } + +func_cont3: + (void)SYNC_LeaveCS(hNodeMgr->hSync); +func_cont1: + if (pAttrIn != NULL) { + /* Overrides of NBD properties */ + pNode->uTimeout = pAttrIn->uTimeout; + pNode->nPriority = pAttrIn->iPriority; + } +func_cont2: + /* Create object to manage notifications */ + if (DSP_SUCCEEDED(status)) + status = NTFY_Create(&pNode->hNtfy); + + if (DSP_SUCCEEDED(status)) { + nodeType = NODE_GetType(pNode); + /* Allocate DSP_STREAMCONNECT array for device, task, and + * dais socket nodes. */ + if (nodeType != NODE_MESSAGE) { + uNumStreams = MaxInputs(pNode) + MaxOutputs(pNode); + pNode->streamConnect = MEM_Calloc(uNumStreams * + sizeof(struct DSP_STREAMCONNECT), + MEM_PAGED); + if (uNumStreams > 0 && pNode->streamConnect == NULL) + status = DSP_EMEMORY; + + } + if (DSP_SUCCEEDED(status) && (nodeType == NODE_TASK || + nodeType == NODE_DAISSOCKET)) { + /* Allocate arrays for maintainig stream connections */ + pNode->inputs = + MEM_Calloc(MaxInputs(pNode) * + sizeof(struct STREAM), MEM_PAGED); + pNode->outputs = + MEM_Calloc(MaxOutputs(pNode) * + sizeof(struct STREAM), MEM_PAGED); + ptaskArgs = &(pNode->createArgs.asa.taskArgs); + ptaskArgs->strmInDef = + MEM_Calloc(MaxInputs(pNode) * + sizeof(struct NODE_STRMDEF), + MEM_PAGED); + ptaskArgs->strmOutDef = + MEM_Calloc(MaxOutputs(pNode) * + sizeof(struct NODE_STRMDEF), + MEM_PAGED); + if ((MaxInputs(pNode) > 0 && (pNode->inputs == NULL || + ptaskArgs->strmInDef == NULL)) || + (MaxOutputs(pNode) > 0 && (pNode->outputs == NULL || + ptaskArgs->strmOutDef == NULL))) + status = DSP_EMEMORY; + } + } + if (DSP_SUCCEEDED(status) && (nodeType != NODE_DEVICE)) { + /* Create an event that will be posted when RMS_EXIT is + * received. */ + status = SYNC_OpenEvent(&pNode->hSyncDone, NULL); + if (DSP_SUCCEEDED(status)) { + /*Get the shared mem mgr for this nodes dev object */ + status = CMM_GetHandle(hProcessor, &hCmmMgr); + if (DSP_FAILED(status)) { + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_Allocate: Failed to" + " get CMM Mgr handle: 0x%x\n", status); + } else { + /* Allocate a SM addr translator for this node + * w/ deflt attr */ + status = CMM_XlatorCreate(&pNode->hXlator, + hCmmMgr, NULL); + if (DSP_FAILED(status)) { + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_Allocate: Failed" + " to create SM translator: 0x%x\n", + status); + } + } + } + if (DSP_SUCCEEDED(status)) { + /* Fill in message args */ + if ((pArgs != NULL) && (pArgs->cbData > 0)) { + pmsgArgs = &(pNode->createArgs.asa.msgArgs); + pmsgArgs->pData = MEM_Calloc(pArgs->cbData, + MEM_PAGED); + if (pmsgArgs->pData == NULL) { + status = DSP_EMEMORY; + } else { + pmsgArgs->uArgLength = pArgs->cbData; + memcpy(pmsgArgs->pData, pArgs->cData, + pArgs->cbData); + } + } + } + } + + if (DSP_SUCCEEDED(status) && nodeType != NODE_DEVICE) { + /* Create a message queue for this node */ + pIntfFxns = hNodeMgr->pIntfFxns; + status = (*pIntfFxns->pfnMsgCreateQueue)(hNodeMgr->hMsg, + &pNode->hMsgQueue, 0, + pNode->createArgs.asa.msgArgs.uMaxMessages, + pNode); + } + + if (DSP_SUCCEEDED(status)) { + /* Create object for dynamic loading */ + + status = hNodeMgr->nldrFxns.pfnAllocate(hNodeMgr->hNldr, + (void *) pNode, + &pNode->dcdProps.objData.nodeObj, + &pNode->hNldrNode, + &pNode->fPhaseSplit); + if (DSP_FAILED(status)) { + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_Allocate: Failed to " + "allocate NLDR node: 0x%x\n", status); + } + } + + /* Comapare value read from Node Properties and check if it is same as + * STACKSEGLABEL, if yes read the Address of STACKSEGLABEL, calculate + * GPP Address, Read the value in that address and override the + * uStackSeg value in task args */ + if (DSP_SUCCEEDED(status) && + (char *)pNode->dcdProps.objData.nodeObj.ndbProps.uStackSegName != + NULL) { + label = MEM_Calloc(sizeof(STACKSEGLABEL)+1, MEM_PAGED); + strncpy(label, STACKSEGLABEL, sizeof(STACKSEGLABEL)+1); + + if (strcmp((char *)pNode->dcdProps.objData.nodeObj. + ndbProps.uStackSegName, label) == 0) { + status = hNodeMgr->nldrFxns.pfnGetFxnAddr(pNode-> + hNldrNode, "DYNEXT_BEG", &dynextBase); + if (DSP_FAILED(status)) { + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_Allocate: Failed to get Address for " + "DYNEXT_BEG: 0x%x\n", status); + } + + status = hNodeMgr->nldrFxns.pfnGetFxnAddr(pNode-> + hNldrNode, "L1DSRAM_HEAP", &pulValue); + + if (DSP_FAILED(status)) { + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_Allocate: Failed to get Address for " + "L1DSRAM_HEAP: 0x%x\n", status); + } + + status = CFG_GetHostResources((struct CFG_DEVNODE *) + DRV_GetFirstDevExtension(), &hostRes); + + if (DSP_FAILED(status)) { + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_Allocate: Failed to get host resource " + "0x%x\n", status); + } + + ulGppMemBase = hostRes.dwMemBase[1]; + offSet = pulValue - dynextBase; + ulStackSegAddr = ulGppMemBase + offSet; + ulStackSegVal = (u32)*((REG_UWORD32 *) + ((u32)(ulStackSegAddr))); + + GT_1trace(NODE_debugMask, GT_5CLASS, + "StackSegVal =0x%x\n", ulStackSegVal); + GT_1trace(NODE_debugMask, GT_5CLASS, + "ulStackSegAddr = 0x%x\n", ulStackSegAddr); + + pNode->createArgs.asa.taskArgs.uStackSeg = + ulStackSegVal; + + } + + if (label) + MEM_Free(label); + + } + + + if (DSP_SUCCEEDED(status)) { + /* Add the node to the node manager's list of allocated + * nodes. */ + LST_InitElem((struct LST_ELEM *)pNode); + NODE_SetState(pNode, NODE_ALLOCATED); + + status = SYNC_EnterCS(hNodeMgr->hSync); + + if (DSP_SUCCEEDED(status)) { + LST_PutTail(hNodeMgr->nodeList, + (struct LST_ELEM *) pNode); + ++(hNodeMgr->uNumNodes); + } + + /* Exit critical section */ + (void) SYNC_LeaveCS(hNodeMgr->hSync); + + /* Preset this to assume phases are split + * (for overlay and dll) */ + pNode->fPhaseSplit = true; + + if (DSP_SUCCEEDED(status)) + *phNode = pNode; + + + /* Notify all clients registered for DSP_NODESTATECHANGE. */ + PROC_NotifyAllClients(hProcessor, DSP_NODESTATECHANGE); + } else { + /* Cleanup */ + if (pNode) + DeleteNode(pNode); + + } + +#ifndef RES_CLEANUP_DISABLE + if (DSP_SUCCEEDED(status)) { + /* Return PID instead of process handle */ + hProcess = current->pid; + + res_status = CFG_GetObject((u32 *)&hDrvObject, + REG_DRV_OBJECT); + if (DSP_SUCCEEDED(res_status)) { + DRV_GetProcContext(hProcess, + (struct DRV_OBJECT *)hDrvObject, + &pPctxt, *phNode, 0); + if (pPctxt == NULL) { + DRV_InsertProcContext( + (struct DRV_OBJECT *)hDrvObject, + &pPctxt); + if (pPctxt != NULL) { + DRV_ProcUpdatestate(pPctxt, + PROC_RES_ALLOCATED); + DRV_ProcSetPID(pPctxt, hProcess); + pPctxt->hProcessor = + (DSP_HPROCESSOR)hProcessor; + } + } + } + } + if (DSP_SUCCEEDED(status)) { + /* Return PID instead of process handle */ + hProcess = current->pid; + res_status = CFG_GetObject((u32 *)&hDrvObject, + REG_DRV_OBJECT); + if (DSP_SUCCEEDED(res_status)) { + DRV_GetProcContext(hProcess, + (struct DRV_OBJECT *)hDrvObject, + &pPctxt, *phNode, 0); + if (pPctxt != NULL) { + DRV_InsertNodeResElement(*phNode, &nodeRes, + pPctxt); + DRV_ProcNodeUpdateHeapStatus(nodeRes, true); + DRV_ProcNodeUpdateStatus(nodeRes, true); + } + } + } +#endif + DBC_Ensure((DSP_FAILED(status) && (*phNode == NULL)) || + (DSP_SUCCEEDED(status) + && MEM_IsValidHandle((*phNode), NODE_SIGNATURE))); +func_end: + return status; +} + +/* + * ======== NODE_AllocMsgBuf ======== + * Purpose: + * Allocates buffer for zero copy messaging. + */ +DBAPI NODE_AllocMsgBuf(struct NODE_OBJECT *hNode, u32 uSize, + OPTIONAL IN OUT struct DSP_BUFFERATTR *pAttr, + OUT u8 **pBuffer) +{ + struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode; + DSP_STATUS status = DSP_SOK; + bool bVirtAddr = false; + bool bSetInfo; + u32 procId; + + DBC_Require(cRefs > 0); + DBC_Require(pBuffer != NULL); + + DBC_Require(uSize > 0); + + GT_4trace(NODE_debugMask, GT_ENTER, + "NODE_AllocMsgBuf: hNode: 0x%x\tuSize:" + " 0x%x\tpAttr: 0x%x\tpBuffer: %d\n", pNode, uSize, pAttr, + pBuffer); + + if (!MEM_IsValidHandle(pNode, NODE_SIGNATURE)) + status = DSP_EHANDLE; + + if (NODE_GetType(pNode) == NODE_DEVICE) + status = DSP_ENODETYPE; + + if (DSP_FAILED(status)) + goto func_end; + + if (pAttr == NULL) + pAttr = &NODE_DFLTBUFATTRS; /* set defaults */ + + status = PROC_GetProcessorId(pNode->hProcessor, &procId); + if (procId != DSP_UNIT) { + DBC_Assert(NULL); + goto func_end; + } + /* If segment ID includes MEM_SETVIRTUALSEGID then pBuffer is a + * virt address, so set this info in this node's translator + * object for future ref. If MEM_GETVIRTUALSEGID then retrieve + * virtual address from node's translator. */ + if ((pAttr->uSegment & MEM_SETVIRTUALSEGID) || + (pAttr->uSegment & MEM_GETVIRTUALSEGID)) { + bVirtAddr = true; + bSetInfo = (pAttr->uSegment & MEM_SETVIRTUALSEGID) ? + true : false; + pAttr->uSegment &= ~MEM_MASKVIRTUALSEGID; /* clear mask bits */ + /* Set/get this node's translators virtual address base/size */ + status = CMM_XlatorInfo(pNode->hXlator, pBuffer, uSize, + pAttr->uSegment, bSetInfo); + if (DSP_FAILED(status)) { + GT_1trace(NODE_debugMask, GT_7CLASS, + "NODE_AllocMsgBuf " + "failed: 0x%lx\n", status); + } + } + if (DSP_SUCCEEDED(status) && (!bVirtAddr)) { + if (pAttr->uSegment != 1) { + /* Node supports single SM segment only. */ + status = DSP_EBADSEGID; + } + /* Arbitrary SM buffer alignment not supported for host side + * allocs, but guaranteed for the following alignment + * values. */ + switch (pAttr->uAlignment) { + case 0: + case 1: + case 2: + case 4: + break; + default: + /* alignment value not suportted */ + status = DSP_EALIGNMENT; + break; + } + if (DSP_SUCCEEDED(status)) { + /* allocate physical buffer from segId in node's + * translator */ + (void)CMM_XlatorAllocBuf(pNode->hXlator, pBuffer, + uSize); + if (*pBuffer == NULL) { + GT_0trace(NODE_debugMask, GT_7CLASS, + "NODE_AllocMsgBuf: " + "ERROR: Out of shared memory.\n"); + status = DSP_EMEMORY; + } + } + } +func_end: + return status; +} + +/* + * ======== NODE_ChangePriority ======== + * Purpose: + * Change the priority of a node in the allocated state, or that is + * currently running or paused on the target. + */ +DSP_STATUS NODE_ChangePriority(struct NODE_OBJECT *hNode, s32 nPriority) +{ + struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode; + struct NODE_MGR *hNodeMgr = NULL; + enum NODE_TYPE nodeType; + enum NODE_STATE state; + DSP_STATUS status = DSP_SOK; + u32 procId; + + DBC_Require(cRefs > 0); + + GT_2trace(NODE_debugMask, GT_ENTER, "NODE_ChangePriority: " + "hNode: 0x%x\tnPriority: %d\n", hNode, nPriority); + + if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) { + GT_1trace(NODE_debugMask, GT_7CLASS, + "Invalid NODE Handle: 0x%x\n", hNode); + status = DSP_EHANDLE; + } else { + hNodeMgr = hNode->hNodeMgr; + nodeType = NODE_GetType(hNode); + if (nodeType != NODE_TASK && nodeType != NODE_DAISSOCKET) + status = DSP_ENODETYPE; + else if (nPriority < hNodeMgr->nMinPri || + nPriority > hNodeMgr->nMaxPri) + status = DSP_ERANGE; + } + if (DSP_FAILED(status)) + goto func_end; + + /* Enter critical section */ + status = SYNC_EnterCS(hNodeMgr->hSync); + if (DSP_FAILED(status)) + goto func_cont; + + state = NODE_GetState(hNode); + if (state == NODE_ALLOCATED || state == NODE_PAUSED) { + NODE_SetPriority(hNode, nPriority); + } else { + if (state != NODE_RUNNING) { + status = DSP_EWRONGSTATE; + goto func_cont; + } + if (DSP_SUCCEEDED(status)) { + status = PROC_GetProcessorId(pNode->hProcessor, + &procId); + if (procId == DSP_UNIT) { + status = DISP_NodeChangePriority(hNodeMgr-> + hDisp, hNode, + hNodeMgr->ulFxnAddrs[RMSCHANGENODEPRIORITY], + hNode->nodeEnv, nPriority); + } + if (DSP_SUCCEEDED(status)) + NODE_SetPriority(hNode, nPriority); + + } + } +func_cont: + /* Leave critical section */ + (void)SYNC_LeaveCS(hNodeMgr->hSync); +func_end: + return status; +} + +/* + * ======== NODE_Connect ======== + * Purpose: + * Connect two nodes on the DSP, or a node on the DSP to the GPP. + */ +DSP_STATUS NODE_Connect(struct NODE_OBJECT *hNode1, u32 uStream1, + struct NODE_OBJECT *hNode2, + u32 uStream2, OPTIONAL IN struct DSP_STRMATTR *pAttrs, + OPTIONAL IN struct DSP_CBDATA *pConnParam) +{ + struct NODE_MGR *hNodeMgr; + char *pstrDevName = NULL; + enum NODE_TYPE node1Type = NODE_TASK; + enum NODE_TYPE node2Type = NODE_TASK; + struct NODE_STRMDEF *pstrmDef; + struct NODE_STRMDEF *pInput = NULL; + struct NODE_STRMDEF *pOutput = NULL; + struct NODE_OBJECT *hDevNode; + struct NODE_OBJECT *hNode; + struct STREAM *pStream; + GB_BitNum pipeId = GB_NOBITS; + GB_BitNum chnlId = GB_NOBITS; + CHNL_MODE uMode; + u32 dwLength; + DSP_STATUS status = DSP_SOK; + DBC_Require(cRefs > 0); + GT_5trace(NODE_debugMask, GT_ENTER, + "NODE_Connect: hNode1: 0x%x\tuStream1:" + " %d\thNode2: 0x%x\tuStream2: %d\tpAttrs: 0x%x\n", hNode1, + uStream1, hNode2, uStream2, pAttrs); + if (DSP_SUCCEEDED(status)) { + if ((hNode1 != (struct NODE_OBJECT *) DSP_HGPPNODE && + !MEM_IsValidHandle(hNode1, NODE_SIGNATURE)) || + (hNode2 != (struct NODE_OBJECT *) DSP_HGPPNODE && + !MEM_IsValidHandle(hNode2, NODE_SIGNATURE))) + status = DSP_EHANDLE; + } + if (DSP_SUCCEEDED(status)) { + /* The two nodes must be on the same processor */ + if (hNode1 != (struct NODE_OBJECT *)DSP_HGPPNODE && + hNode2 != (struct NODE_OBJECT *)DSP_HGPPNODE && + hNode1->hNodeMgr != hNode2->hNodeMgr) + status = DSP_EFAIL; + /* Cannot connect a node to itself */ + if (hNode1 == hNode2) + status = DSP_EFAIL; + + } + if (DSP_SUCCEEDED(status)) { + /* NODE_GetType() will return NODE_GPP if hNode = + * DSP_HGPPNODE. */ + node1Type = NODE_GetType(hNode1); + node2Type = NODE_GetType(hNode2); + /* Check stream indices ranges */ + if ((node1Type != NODE_GPP && node1Type != NODE_DEVICE && + uStream1 >= MaxOutputs(hNode1)) || (node2Type != NODE_GPP && + node2Type != NODE_DEVICE && uStream2 >= MaxInputs(hNode2))) + status = DSP_EVALUE; + } + if (DSP_SUCCEEDED(status)) { + /* + * Only the following types of connections are allowed: + * task/dais socket < == > task/dais socket + * task/dais socket < == > device + * task/dais socket < == > GPP + * + * ie, no message nodes, and at least one task or dais + * socket node. + */ + if (node1Type == NODE_MESSAGE || node2Type == NODE_MESSAGE || + (node1Type != NODE_TASK && node1Type != NODE_DAISSOCKET && + node2Type != NODE_TASK && node2Type != NODE_DAISSOCKET)) + status = DSP_EFAIL; + } + /* + * Check stream mode. Default is STRMMODE_PROCCOPY. + */ + if (DSP_SUCCEEDED(status) && pAttrs) { + if (pAttrs->lMode != STRMMODE_PROCCOPY) + status = DSP_ESTRMMODE; /* illegal stream mode */ + + } + if (DSP_FAILED(status)) + goto func_end; + + if (node1Type != NODE_GPP) { + hNodeMgr = hNode1->hNodeMgr; + } else { + DBC_Assert(hNode2 != (struct NODE_OBJECT *)DSP_HGPPNODE); + hNodeMgr = hNode2->hNodeMgr; + } + /* Enter critical section */ + status = SYNC_EnterCS(hNodeMgr->hSync); + if (DSP_FAILED(status)) + goto func_cont; + + /* Nodes must be in the allocated state */ + if (node1Type != NODE_GPP && NODE_GetState(hNode1) != NODE_ALLOCATED) + status = DSP_EWRONGSTATE; + + if (node2Type != NODE_GPP && NODE_GetState(hNode2) != NODE_ALLOCATED) + status = DSP_EWRONGSTATE; + + if (DSP_SUCCEEDED(status)) { + /* Check that stream indices for task and dais socket nodes + * are not already be used. (Device nodes checked later) */ + if (node1Type == NODE_TASK || node1Type == NODE_DAISSOCKET) { + pOutput = &(hNode1->createArgs.asa.taskArgs. + strmOutDef[uStream1]); + if (pOutput->szDevice != NULL) + status = DSP_EALREADYCONNECTED; + + } + if (node2Type == NODE_TASK || node2Type == NODE_DAISSOCKET) { + pInput = &(hNode2->createArgs.asa.taskArgs. + strmInDef[uStream2]); + if (pInput->szDevice != NULL) + status = DSP_EALREADYCONNECTED; + + } + } + /* Connecting two task nodes? */ + if (DSP_SUCCEEDED(status) && ((node1Type == NODE_TASK || + node1Type == NODE_DAISSOCKET) && (node2Type == NODE_TASK || + node2Type == NODE_DAISSOCKET))) { + /* Find available pipe */ + pipeId = GB_findandset(hNodeMgr->pipeMap); + if (pipeId == GB_NOBITS) { + status = DSP_ENOMORECONNECTIONS; + } else { + hNode1->outputs[uStream1].type = NODECONNECT; + hNode2->inputs[uStream2].type = NODECONNECT; + hNode1->outputs[uStream1].devId = pipeId; + hNode2->inputs[uStream2].devId = pipeId; + pOutput->szDevice = MEM_Calloc(PIPENAMELEN + 1, + MEM_PAGED); + pInput->szDevice = MEM_Calloc(PIPENAMELEN + 1, + MEM_PAGED); + if (pOutput->szDevice == NULL || + pInput->szDevice == NULL) { + /* Undo the connection */ + if (pOutput->szDevice) + MEM_Free(pOutput->szDevice); + + if (pInput->szDevice) + MEM_Free(pInput->szDevice); + + pOutput->szDevice = NULL; + pInput->szDevice = NULL; + GB_clear(hNodeMgr->pipeMap, pipeId); + status = DSP_EMEMORY; + } else { + /* Copy "/dbpipe" name to device names */ + sprintf(pOutput->szDevice, "%s%d", + PIPEPREFIX, pipeId); + strcpy(pInput->szDevice, pOutput->szDevice); + } + } + } + /* Connecting task node to host? */ + if (DSP_SUCCEEDED(status) && (node1Type == NODE_GPP || + node2Type == NODE_GPP)) { + if (node1Type == NODE_GPP) { + uMode = CHNL_MODETODSP; + } else { + DBC_Assert(node2Type == NODE_GPP); + uMode = CHNL_MODEFROMDSP; + } + /* Reserve a channel id. We need to put the name "/host" + * in the node's createArgs, but the host + * side channel will not be opened until DSPStream_Open is + * called for this node. */ + if (pAttrs) { + if (pAttrs->lMode == STRMMODE_RDMA) { + chnlId = GB_findandset(hNodeMgr->dmaChnlMap); + /* dma chans are 2nd transport chnl set + * ids(e.g. 16-31)*/ + (chnlId != GB_NOBITS) ? + (chnlId = chnlId + hNodeMgr->ulNumChnls) : + chnlId; + } else if (pAttrs->lMode == STRMMODE_ZEROCOPY) { + chnlId = GB_findandset(hNodeMgr->zChnlMap); + /* zero-copy chans are 3nd transport set + * (e.g. 32-47) */ + (chnlId != GB_NOBITS) ? (chnlId = chnlId + + (2 * hNodeMgr->ulNumChnls)) : chnlId; + } else { /* must be PROCCOPY */ + DBC_Assert(pAttrs->lMode == STRMMODE_PROCCOPY); + chnlId = GB_findandset(hNodeMgr->chnlMap); + /* e.g. 0-15 */ + } + } else { + /* default to PROCCOPY */ + chnlId = GB_findandset(hNodeMgr->chnlMap); + } + if (chnlId == GB_NOBITS) { + status = DSP_ENOMORECONNECTIONS; + goto func_cont2; + } + pstrDevName = MEM_Calloc(HOSTNAMELEN + 1, MEM_PAGED); + if (pstrDevName != NULL) + goto func_cont2; + + if (pAttrs) { + if (pAttrs->lMode == STRMMODE_RDMA) { + GB_clear(hNodeMgr->dmaChnlMap, chnlId - + hNodeMgr->ulNumChnls); + } else if (pAttrs->lMode == STRMMODE_ZEROCOPY) { + GB_clear(hNodeMgr->zChnlMap, chnlId - + (2*hNodeMgr->ulNumChnls)); + } else { + DBC_Assert(pAttrs->lMode == STRMMODE_PROCCOPY); + GB_clear(hNodeMgr->chnlMap, chnlId); + } + } else { + GB_clear(hNodeMgr->chnlMap, chnlId); + } + status = DSP_EMEMORY; +func_cont2: + if (DSP_SUCCEEDED(status)) { + if (hNode1 == (struct NODE_OBJECT *) DSP_HGPPNODE) { + hNode2->inputs[uStream2].type = HOSTCONNECT; + hNode2->inputs[uStream2].devId = chnlId; + pInput->szDevice = pstrDevName; + } else { + hNode1->outputs[uStream1].type = HOSTCONNECT; + hNode1->outputs[uStream1].devId = chnlId; + pOutput->szDevice = pstrDevName; + } + sprintf(pstrDevName, "%s%d", HOSTPREFIX, chnlId); + } + } + /* Connecting task node to device node? */ + if (DSP_SUCCEEDED(status) && ((node1Type == NODE_DEVICE) || + (node2Type == NODE_DEVICE))) { + if (node2Type == NODE_DEVICE) { + /* node1 == > device */ + hDevNode = hNode2; + hNode = hNode1; + pStream = &(hNode1->outputs[uStream1]); + pstrmDef = pOutput; + } else { + /* device == > node2 */ + hDevNode = hNode1; + hNode = hNode2; + pStream = &(hNode2->inputs[uStream2]); + pstrmDef = pInput; + } + /* Set up create args */ + pStream->type = DEVICECONNECT; + dwLength = strlen(hDevNode->pstrDevName); + if (pConnParam != NULL) { + pstrmDef->szDevice = MEM_Calloc(dwLength + 1 + + (u32) pConnParam->cbData, + MEM_PAGED); + } else { + pstrmDef->szDevice = MEM_Calloc(dwLength + 1, + MEM_PAGED); + } + if (pstrmDef->szDevice == NULL) { + status = DSP_EMEMORY; + } else { + /* Copy device name */ + strncpy(pstrmDef->szDevice, hDevNode->pstrDevName, + dwLength); + if (pConnParam != NULL) { + strncat(pstrmDef->szDevice, + (char *)pConnParam->cData, + (u32)pConnParam->cbData); + } + hDevNode->hDeviceOwner = hNode; + } + } + if (DSP_SUCCEEDED(status)) { + /* Fill in create args */ + if (node1Type == NODE_TASK || node1Type == NODE_DAISSOCKET) { + hNode1->createArgs.asa.taskArgs.uNumOutputs++; + FillStreamDef(hNode1, pOutput, pAttrs); + } + if (node2Type == NODE_TASK || node2Type == NODE_DAISSOCKET) { + hNode2->createArgs.asa.taskArgs.uNumInputs++; + FillStreamDef(hNode2, pInput, pAttrs); + } + /* Update hNode1 and hNode2 streamConnect */ + if (node1Type != NODE_GPP && node1Type != NODE_DEVICE) { + hNode1->uNumOutputs++; + if (uStream1 > hNode1->uMaxOutputIndex) + hNode1->uMaxOutputIndex = uStream1; + + } + if (node2Type != NODE_GPP && node2Type != NODE_DEVICE) { + hNode2->uNumInputs++; + if (uStream2 > hNode2->uMaxInputIndex) + hNode2->uMaxInputIndex = uStream2; + + } + FillStreamConnect(hNode1, hNode2, uStream1, uStream2); + } +func_cont: + /* end of SYNC_EnterCS */ + /* Exit critical section */ + (void)SYNC_LeaveCS(hNodeMgr->hSync); +func_end: + return status; +} + +/* + * ======== NODE_Create ======== + * Purpose: + * Create a node on the DSP by remotely calling the node's create function. + */ +DSP_STATUS NODE_Create(struct NODE_OBJECT *hNode) +{ + struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode; + struct NODE_MGR *hNodeMgr; + struct WMD_DRV_INTERFACE *pIntfFxns; + u32 ulCreateFxn; + enum NODE_TYPE nodeType; + DSP_STATUS status = DSP_SOK; + DSP_STATUS status1 = DSP_SOK; + bool bJustWokeDSP = false; + struct DSP_CBDATA cbData; + u32 procId = 255; + struct DSP_PROCESSORSTATE procStatus; + struct PROC_OBJECT *hProcessor; +#if defined(CONFIG_BRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ) + struct dspbridge_platform_data *pdata = + omap_dspbridge_dev->dev.platform_data; +#endif + + DBC_Require(cRefs > 0); + GT_1trace(NODE_debugMask, GT_ENTER, "NODE_Create: hNode: 0x%x\n", + hNode); + hProcessor = hNode->hProcessor; + status = PROC_GetState(hProcessor, &procStatus, + sizeof(struct DSP_PROCESSORSTATE)); + if (DSP_FAILED(status)) + goto func_end; + /* If processor is in error state then don't attempt to create + new node */ + if (procStatus.iState == PROC_ERROR) { + GT_1trace(NODE_debugMask, GT_4CLASS, "NODE_Create:" + " proc Status 0x%x\n", procStatus.iState); + status = DSP_EFAIL; + goto func_end; + } + /* create struct DSP_CBDATA struct for PWR calls */ + cbData.cbData = PWR_TIMEOUT; + nodeType = NODE_GetType(hNode); + hNodeMgr = hNode->hNodeMgr; + pIntfFxns = hNodeMgr->pIntfFxns; + /* Get access to node dispatcher */ + status = SYNC_EnterCS(hNodeMgr->hSync); + if (DSP_FAILED(status)) + goto func_cont; + + /* Check node state */ + if (NODE_GetState(hNode) != NODE_ALLOCATED) + status = DSP_EWRONGSTATE; + + if (DSP_SUCCEEDED(status)) + status = PROC_GetProcessorId(pNode->hProcessor, &procId); + + if (DSP_FAILED(status)) + goto func_cont2; + + if (procId != DSP_UNIT) + goto func_cont2; + + /* Make sure streams are properly connected */ + if ((hNode->uNumInputs && hNode->uMaxInputIndex > + hNode->uNumInputs - 1) || + (hNode->uNumOutputs && hNode->uMaxOutputIndex > + hNode->uNumOutputs - 1)) + status = DSP_ENOTCONNECTED; + + if (DSP_SUCCEEDED(status)) { + /* If node's create function is not loaded, load it */ + /* Boost the OPP level to max level that DSP can be requested */ +#if defined(CONFIG_BRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ) + if (pdata->cpu_set_freq) { + (*pdata->cpu_set_freq)(pdata->mpu_speed[VDD1_OPP3]); + + if (pdata->dsp_get_opp) { + GT_1trace(NODE_debugMask, GT_4CLASS, "opp level" + "after setting to VDD1_OPP3 is %d\n", + (*pdata->dsp_get_opp)()); + } + } +#endif + status = hNodeMgr->nldrFxns.pfnLoad(hNode->hNldrNode, + NLDR_CREATE); + /* Get address of node's create function */ + if (DSP_SUCCEEDED(status)) { + hNode->fLoaded = true; + if (nodeType != NODE_DEVICE) { + status = GetFxnAddress(hNode, &ulCreateFxn, + CREATEPHASE); + } + } else { + GT_1trace(NODE_debugMask, GT_ENTER, + "NODE_Create: failed to load" + " create code: 0x%x\n", status); + } + /* Request the lowest OPP level*/ +#if defined(CONFIG_BRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ) + if (pdata->cpu_set_freq) { + (*pdata->cpu_set_freq)(pdata->mpu_speed[VDD1_OPP1]); + + if (pdata->dsp_get_opp) { + GT_1trace(NODE_debugMask, GT_4CLASS, "opp level" + "after setting to VDD1_OPP1 is %d\n", + (*pdata->dsp_get_opp)()); + } + } +#endif + /* Get address of iAlg functions, if socket node */ + if (DSP_SUCCEEDED(status)) { + if (nodeType == NODE_DAISSOCKET) { + status = hNodeMgr->nldrFxns.pfnGetFxnAddr + (hNode->hNldrNode, hNode->dcdProps. + objData.nodeObj.pstrIAlgName, + &hNode->createArgs.asa.taskArgs. + ulDaisArg); + } + } + } + if (DSP_SUCCEEDED(status)) { + if (nodeType != NODE_DEVICE) { + status = DISP_NodeCreate(hNodeMgr->hDisp, hNode, + hNodeMgr->ulFxnAddrs[RMSCREATENODE], + ulCreateFxn, &(hNode->createArgs), + &(hNode->nodeEnv)); + if (DSP_SUCCEEDED(status)) { + /* Set the message queue id to the node env + * pointer */ + pIntfFxns = hNodeMgr->pIntfFxns; + (*pIntfFxns->pfnMsgSetQueueId)(hNode->hMsgQueue, + hNode->nodeEnv); + } + } + } + /* Phase II/Overlays: Create, execute, delete phases possibly in + * different files/sections. */ + if (hNode->fLoaded && hNode->fPhaseSplit) { + /* If create code was dynamically loaded, we can now unload + * it. */ + status1 = hNodeMgr->nldrFxns.pfnUnload(hNode->hNldrNode, + NLDR_CREATE); + hNode->fLoaded = false; + } + if (DSP_FAILED(status1)) { + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_Create: Failed to unload " + "create code: 0x%x\n", status1); + } +func_cont2: + /* Update node state and node manager state */ + if (DSP_SUCCEEDED(status)) { + NODE_SetState(hNode, NODE_CREATED); + hNodeMgr->uNumCreated++; + goto func_cont; + } + if (status != DSP_EWRONGSTATE) { + /* Put back in NODE_ALLOCATED state if error occurred */ + NODE_SetState(hNode, NODE_ALLOCATED); + } + if (procId == DSP_UNIT) { + /* If node create failed, see if should sleep DSP now */ + if (bJustWokeDSP == true) { + /* Check to see if partial create happened on DSP */ + if (hNode->nodeEnv == (u32)NULL) { + /* No environment allocated on DSP, re-sleep + * DSP now */ + PROC_Ctrl(hNode->hProcessor, WMDIOCTL_DEEPSLEEP, + &cbData); + } else { + /* Increment count, sleep later when node fully + * deleted */ + hNodeMgr->uNumCreated++; + } + } + } +func_cont: + /* Free access to node dispatcher */ + (void)SYNC_LeaveCS(hNodeMgr->hSync); +func_end: + if (DSP_SUCCEEDED(status)) { + PROC_NotifyClients(hNode->hProcessor, DSP_NODESTATECHANGE); + NTFY_Notify(hNode->hNtfy, DSP_NODESTATECHANGE); + } + + return status; +} + +/* + * ======== NODE_CreateMgr ======== + * Purpose: + * Create a NODE Manager object. + */ +DSP_STATUS NODE_CreateMgr(OUT struct NODE_MGR **phNodeMgr, + struct DEV_OBJECT *hDevObject) +{ + u32 i; + struct NODE_MGR *pNodeMgr = NULL; + struct DISP_ATTRS dispAttrs; + char *szZLFile = ""; + struct NLDR_ATTRS nldrAttrs; + DSP_STATUS status = DSP_SOK; + u32 devType; + DBC_Require(cRefs > 0); + DBC_Require(phNodeMgr != NULL); + DBC_Require(hDevObject != NULL); + GT_2trace(NODE_debugMask, GT_ENTER, "NODE_CreateMgr: phNodeMgr: 0x%x\t" + "hDevObject: 0x%x\n", phNodeMgr, hDevObject); + *phNodeMgr = NULL; + /* Allocate Node manager object */ + MEM_AllocObject(pNodeMgr, struct NODE_MGR, NODEMGR_SIGNATURE); + if (pNodeMgr) { + pNodeMgr->hDevObject = hDevObject; + pNodeMgr->nodeList = LST_Create(); + pNodeMgr->pipeMap = GB_create(MAXPIPES); + pNodeMgr->pipeDoneMap = GB_create(MAXPIPES); + if (pNodeMgr->nodeList == NULL || pNodeMgr->pipeMap == NULL || + pNodeMgr->pipeDoneMap == NULL) { + status = DSP_EMEMORY; + GT_0trace(NODE_debugMask, GT_6CLASS, + "NODE_CreateMgr: Memory " + "allocation failed\n"); + } else { + status = NTFY_Create(&pNodeMgr->hNtfy); + } + pNodeMgr->uNumCreated = 0; + } else { + GT_0trace(NODE_debugMask, GT_6CLASS, + "NODE_CreateMgr: Memory allocation failed\n"); + status = DSP_EMEMORY; + } + /* get devNodeType */ + if (DSP_SUCCEEDED(status)) + status = DEV_GetDevType(hDevObject, &devType); + + /* Create the DCD Manager */ + if (DSP_SUCCEEDED(status)) { + status = DCD_CreateManager(szZLFile, &pNodeMgr->hDcdMgr); + if (DSP_SUCCEEDED(status)) + status = GetProcProps(pNodeMgr, hDevObject); + + } + /* Create NODE Dispatcher */ + if (DSP_SUCCEEDED(status)) { + dispAttrs.ulChnlOffset = pNodeMgr->ulChnlOffset; + dispAttrs.ulChnlBufSize = pNodeMgr->ulChnlBufSize; + dispAttrs.procFamily = pNodeMgr->procFamily; + dispAttrs.procType = pNodeMgr->procType; + status = DISP_Create(&pNodeMgr->hDisp, hDevObject, &dispAttrs); + } + /* Create a STRM Manager */ + if (DSP_SUCCEEDED(status)) + status = STRM_Create(&pNodeMgr->hStrmMgr, hDevObject); + + if (DSP_SUCCEEDED(status)) { + DEV_GetIntfFxns(hDevObject, &pNodeMgr->pIntfFxns); + /* Get MSG queue manager */ + DEV_GetMsgMgr(hDevObject, &pNodeMgr->hMsg); + status = SYNC_InitializeCS(&pNodeMgr->hSync); + if (DSP_FAILED(status)) + status = DSP_EMEMORY; + } + if (DSP_SUCCEEDED(status)) { + pNodeMgr->chnlMap = GB_create(pNodeMgr->ulNumChnls); + /* dma chnl map. ulNumChnls is # per transport */ + pNodeMgr->dmaChnlMap = GB_create(pNodeMgr->ulNumChnls); + pNodeMgr->zChnlMap = GB_create(pNodeMgr->ulNumChnls); + if ((pNodeMgr->chnlMap == NULL) || + (pNodeMgr->dmaChnlMap == NULL) || + (pNodeMgr->zChnlMap == NULL)) { + status = DSP_EMEMORY; + } else { + /* Block out reserved channels */ + for (i = 0; i < pNodeMgr->ulChnlOffset; i++) + GB_set(pNodeMgr->chnlMap, i); + + /* Block out channels reserved for RMS */ + GB_set(pNodeMgr->chnlMap, pNodeMgr->ulChnlOffset); + GB_set(pNodeMgr->chnlMap, pNodeMgr->ulChnlOffset + 1); + } + } + if (DSP_SUCCEEDED(status)) { + /* NO RM Server on the IVA */ + if (devType != IVA_UNIT) { + /* Get addresses of any RMS functions loaded */ + status = GetRMSFxns(pNodeMgr); + if (DSP_FAILED(status)) { + GT_1trace(NODE_debugMask, GT_6CLASS, + "NODE_CreateMgr: Failed to" + " get RMS functions: status = 0x%x", status); + } + } + } + + /* Get loader functions and create loader */ + if (DSP_SUCCEEDED(status)) { + GT_0trace(NODE_debugMask, GT_1CLASS, + "NODE_CreateMgr: using dynamic loader\n"); + pNodeMgr->nldrFxns = nldrFxns; /* Dynamic loader functions */ + } + if (DSP_SUCCEEDED(status)) { + nldrAttrs.pfnOvly = Ovly; + nldrAttrs.pfnWrite = Write; + nldrAttrs.usDSPWordSize = pNodeMgr->uDSPWordSize; + nldrAttrs.usDSPMauSize = pNodeMgr->uDSPMauSize; + pNodeMgr->fLoaderInit = pNodeMgr->nldrFxns.pfnInit(); + status = pNodeMgr->nldrFxns.pfnCreate(&pNodeMgr->hNldr, + hDevObject, &nldrAttrs); + if (DSP_FAILED(status)) { + GT_1trace(NODE_debugMask, GT_6CLASS, + "NODE_CreateMgr: Failed to " + "create loader: status = 0x%x\n", status); + } + } + if (DSP_SUCCEEDED(status)) + *phNodeMgr = pNodeMgr; + else + DeleteNodeMgr(pNodeMgr); + + DBC_Ensure((DSP_FAILED(status) && (*phNodeMgr == NULL)) || + (DSP_SUCCEEDED(status) && + MEM_IsValidHandle((*phNodeMgr), NODEMGR_SIGNATURE))); + + return status; +} + +/* + * ======== NODE_Delete ======== + * Purpose: + * Delete a node on the DSP by remotely calling the node's delete function. + * Loads the node's delete function if necessary. Free GPP side resources + * after node's delete function returns. + */ +DSP_STATUS NODE_Delete(struct NODE_OBJECT *hNode) +{ + struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode; + struct NODE_MGR *hNodeMgr; + struct PROC_OBJECT *hProcessor; + struct DISP_OBJECT *hDisp; + u32 ulDeleteFxn; + enum NODE_TYPE nodeType; + enum NODE_STATE state; + DSP_STATUS status = DSP_SOK; + DSP_STATUS status1 = DSP_SOK; + struct DSP_CBDATA cbData; + u32 procId; + struct WMD_DRV_INTERFACE *pIntfFxns; + +#ifndef RES_CLEANUP_DISABLE + u32 hProcess; + HANDLE nodeRes; + HANDLE hDrvObject; + struct PROCESS_CONTEXT *pCtxt = NULL; + DSP_STATUS res_status = DSP_SOK; +#endif + struct DSP_PROCESSORSTATE procStatus; + DBC_Require(cRefs > 0); + GT_1trace(NODE_debugMask, GT_ENTER, "NODE_Delete: hNode: 0x%x\n", + hNode); + if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) { + status = DSP_EHANDLE; + goto func_end; + } + /* create struct DSP_CBDATA struct for PWR call */ + cbData.cbData = PWR_TIMEOUT; + hNodeMgr = hNode->hNodeMgr; + hProcessor = hNode->hProcessor; + hDisp = hNodeMgr->hDisp; + nodeType = NODE_GetType(hNode); + pIntfFxns = hNodeMgr->pIntfFxns; + /* Enter critical section */ + status = SYNC_EnterCS(hNodeMgr->hSync); + if (DSP_FAILED(status)) + goto func_end; + + state = NODE_GetState(hNode); + /* Execute delete phase code for non-device node in all cases + * except when the node was only allocated. Delete phase must be + * executed even if create phase was executed, but failed. + * If the node environment pointer is non-NULL, the delete phase + * code must be executed. */ + if (!(state == NODE_ALLOCATED && hNode->nodeEnv == (u32)NULL) && + nodeType != NODE_DEVICE) { + status = PROC_GetProcessorId(pNode->hProcessor, &procId); + if (DSP_FAILED(status)) + goto func_cont1; + + if (procId == DSP_UNIT || procId == IVA_UNIT) { + /* If node has terminated, execute phase code will + * have already been unloaded in NODE_OnExit(). If the + * node is PAUSED, the execute phase is loaded, and it + * is now ok to unload it. If the node is running, we + * will unload the execute phase only after deleting + * the node. */ + if (state == NODE_PAUSED && hNode->fLoaded && + hNode->fPhaseSplit) { + /* Ok to unload execute code as long as node + * is not * running */ + status1 = hNodeMgr->nldrFxns.pfnUnload(hNode-> + hNldrNode, NLDR_EXECUTE); + hNode->fLoaded = false; + NODE_SetState(hNode, NODE_DONE); + } + /* Load delete phase code if not loaded or if haven't + * * unloaded EXECUTE phase */ + if ((!(hNode->fLoaded) || (state == NODE_RUNNING)) && + hNode->fPhaseSplit) { + status = hNodeMgr->nldrFxns.pfnLoad(hNode-> + hNldrNode, NLDR_DELETE); + if (DSP_SUCCEEDED(status)) { + hNode->fLoaded = true; + } else { + GT_1trace(NODE_debugMask, GT_ENTER, + "NODE_Delete: failed to " + "load delete code: 0x%x\n", + status); + } + } + } +func_cont1: + if (DSP_SUCCEEDED(status)) { + /* Unblock a thread trying to terminate the node */ + (void)SYNC_SetEvent(hNode->hSyncDone); + if (procId == DSP_UNIT) { + /* ulDeleteFxn = address of node's delete + * function */ + status = GetFxnAddress(hNode, &ulDeleteFxn, + DELETEPHASE); + } else if (procId == IVA_UNIT) + ulDeleteFxn = (u32)hNode->nodeEnv; + if (DSP_SUCCEEDED(status)) { + status = PROC_GetState(hProcessor, &procStatus, + sizeof(struct DSP_PROCESSORSTATE)); + GT_1trace(NODE_debugMask, GT_4CLASS, + "NODE_Delete: proc Status " + "0x%x\n", procStatus.iState); + if (procStatus.iState != PROC_ERROR) { + status = DISP_NodeDelete(hDisp, hNode, + hNodeMgr->ulFxnAddrs[RMSDELETENODE], + ulDeleteFxn, hNode->nodeEnv); + } else + NODE_SetState(hNode, NODE_DONE); + + /* Unload execute, if not unloaded, and delete + * function */ + if (state == NODE_RUNNING && + hNode->fPhaseSplit) { + status1 = hNodeMgr->nldrFxns.pfnUnload( + hNode->hNldrNode, NLDR_EXECUTE); + } + if (DSP_FAILED(status1)) { + GT_1trace(NODE_debugMask, GT_ENTER, + "NODE_Delete: failed to" + "unload execute code: 0x%x\n", + status1); + } + status1 = hNodeMgr->nldrFxns.pfnUnload( + hNode->hNldrNode, NLDR_DELETE); + hNode->fLoaded = false; + if (DSP_FAILED(status1)) { + GT_1trace(NODE_debugMask, GT_ENTER, + "NODE_Delete: failed to" + "unload delete code: 0x%x\n", + status1); + } + } + } + } + /* Free host side resources even if a failure occurred */ + /* Remove node from hNodeMgr->nodeList */ + LST_RemoveElem(hNodeMgr->nodeList, (struct LST_ELEM *) hNode); + hNodeMgr->uNumNodes--; + /* Decrement count of nodes created on DSP */ + if ((state != NODE_ALLOCATED) || ((state == NODE_ALLOCATED) && + (hNode->nodeEnv != (u32) NULL))) + hNodeMgr->uNumCreated--; + /* Free host-side resources allocated by NODE_Create() + * DeleteNode() fails if SM buffers not freed by client! */ +#ifndef RES_CLEANUP_DISABLE + /* Return PID instead of process handle */ + hProcess = current->pid; + res_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); + if (DSP_FAILED(res_status)) + goto func_cont; + DRV_GetProcContext(0, (struct DRV_OBJECT *)hDrvObject, + &pCtxt, hNode, 0); + if (pCtxt == NULL) + goto func_cont; + if (DRV_GetNodeResElement(hNode, &nodeRes, pCtxt) != DSP_ENOTFOUND) { + GT_0trace(NODE_debugMask, GT_5CLASS, "\nNODE_Delete12:\n"); + DRV_ProcNodeUpdateStatus(nodeRes, false); + } +#endif +func_cont: + GT_0trace(NODE_debugMask, GT_ENTER, "\nNODE_Delete13:\n "); + DeleteNode(hNode); +#ifndef RES_CLEANUP_DISABLE + GT_0trace(NODE_debugMask, GT_5CLASS, "\nNODE_Delete2:\n "); + if (pCtxt != NULL) + DRV_RemoveNodeResElement(nodeRes, (HANDLE)pCtxt); +#endif + GT_0trace(NODE_debugMask, GT_ENTER, "\nNODE_Delete3:\n "); + /* Exit critical section */ + (void)SYNC_LeaveCS(hNodeMgr->hSync); + PROC_NotifyClients(hProcessor, DSP_NODESTATECHANGE); +func_end: + return status; +} + +/* + * ======== NODE_DeleteMgr ======== + * Purpose: + * Delete the NODE Manager. + */ +DSP_STATUS NODE_DeleteMgr(struct NODE_MGR *hNodeMgr) +{ + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(hNodeMgr, NODEMGR_SIGNATURE)); + + GT_1trace(NODE_debugMask, GT_ENTER, "NODE_DeleteMgr: hNodeMgr: 0x%x\n", + hNodeMgr); + DeleteNodeMgr(hNodeMgr); + + return status; +} + +/* + * ======== NODE_EnumNodes ======== + * Purpose: + * Enumerate currently allocated nodes. + */ +DSP_STATUS NODE_EnumNodes(struct NODE_MGR *hNodeMgr, IN DSP_HNODE *aNodeTab, + u32 uNodeTabSize, OUT u32 *puNumNodes, + OUT u32 *puAllocated) +{ + struct NODE_OBJECT *hNode; + u32 i; + DSP_STATUS status = DSP_SOK; + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(hNodeMgr, NODEMGR_SIGNATURE)); + DBC_Require(aNodeTab != NULL || uNodeTabSize == 0); + DBC_Require(puNumNodes != NULL); + DBC_Require(puAllocated != NULL); + GT_5trace(NODE_debugMask, GT_ENTER, "NODE_EnumNodes: hNodeMgr: 0x%x\t" + "aNodeTab: %d\tuNodeTabSize: 0x%x\tpuNumNodes: 0x%x\t" + "puAllocated\n", hNodeMgr, aNodeTab, uNodeTabSize, puNumNodes, + puAllocated); + /* Enter critical section */ + status = SYNC_EnterCS(hNodeMgr->hSync); + if (DSP_SUCCEEDED(status)) { + if (hNodeMgr->uNumNodes > uNodeTabSize) { + *puAllocated = hNodeMgr->uNumNodes; + *puNumNodes = 0; + status = DSP_ESIZE; + } else { + hNode = (struct NODE_OBJECT *)LST_First(hNodeMgr-> + nodeList); + for (i = 0; i < hNodeMgr->uNumNodes; i++) { + DBC_Assert(MEM_IsValidHandle(hNode, + NODE_SIGNATURE)); + aNodeTab[i] = hNode; + hNode = (struct NODE_OBJECT *)LST_Next + (hNodeMgr->nodeList, + (struct LST_ELEM *)hNode); + } + *puAllocated = *puNumNodes = hNodeMgr->uNumNodes; + } + } + /* end of SYNC_EnterCS */ + /* Exit critical section */ + (void)SYNC_LeaveCS(hNodeMgr->hSync); + return status; +} + +/* + * ======== NODE_Exit ======== + * Purpose: + * Discontinue usage of NODE module. + */ +void NODE_Exit(void) +{ + DBC_Require(cRefs > 0); + + cRefs--; + + GT_1trace(NODE_debugMask, GT_5CLASS, + "Entered NODE_Exit, ref count: 0x%x\n", cRefs); + + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== NODE_FreeMsgBuf ======== + * Purpose: + * Frees the message buffer. + */ +DSP_STATUS NODE_FreeMsgBuf(struct NODE_OBJECT *hNode, IN u8 *pBuffer, + OPTIONAL struct DSP_BUFFERATTR *pAttr) +{ + struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode; + DSP_STATUS status = DSP_SOK; + u32 procId; + DBC_Require(cRefs > 0); + DBC_Require(pBuffer != NULL); + DBC_Require(pNode != NULL); + DBC_Require(pNode->hXlator != NULL); + GT_3trace(NODE_debugMask, GT_ENTER, "NODE_FreeMsgBuf: hNode: 0x%x\t" + "pBuffer: 0x%x\tpAttr: 0x%x\n", hNode, pBuffer, pAttr); + if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) + status = DSP_EHANDLE; + + status = PROC_GetProcessorId(pNode->hProcessor, &procId); + if (procId == DSP_UNIT) { + if (DSP_SUCCEEDED(status)) { + if (pAttr == NULL) { + /* set defaults */ + pAttr = &NODE_DFLTBUFATTRS; + } + /* Node supports single SM segment only */ + if (pAttr->uSegment != 1) + status = DSP_EBADSEGID; + + /* pBuffer is clients Va. */ + status = CMM_XlatorFreeBuf(pNode->hXlator, pBuffer); + if (DSP_FAILED(status)) + status = DSP_EFAIL; + else + status = DSP_SOK; + + } + } else { + DBC_Assert(NULL); /* BUG */ + } + return status; +} + +/* + * ======== NODE_GetAttr ======== + * Purpose: + * Copy the current attributes of the specified node into a DSP_NODEATTR + * structure. + */ +DSP_STATUS NODE_GetAttr(struct NODE_OBJECT *hNode, + OUT struct DSP_NODEATTR *pAttr, u32 uAttrSize) +{ + struct NODE_MGR *hNodeMgr; + DSP_STATUS status = DSP_SOK; + DBC_Require(cRefs > 0); + DBC_Require(pAttr != NULL); + DBC_Require(uAttrSize >= sizeof(struct DSP_NODEATTR)); + GT_3trace(NODE_debugMask, GT_ENTER, "NODE_GetAttr: hNode: " + "0x%x\tpAttr: 0x%x \tuAttrSize: 0x%x\n", hNode, pAttr, + uAttrSize); + if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) { + status = DSP_EHANDLE; + } else { + hNodeMgr = hNode->hNodeMgr; + /* Enter hNodeMgr critical section (since we're accessing + * data that could be changed by NODE_ChangePriority() and + * NODE_Connect(). */ + status = SYNC_EnterCS(hNodeMgr->hSync); + if (DSP_SUCCEEDED(status)) { + pAttr->cbStruct = sizeof(struct DSP_NODEATTR); + /* DSP_NODEATTRIN */ + pAttr->inNodeAttrIn.cbStruct = + sizeof(struct DSP_NODEATTRIN); + pAttr->inNodeAttrIn.iPriority = hNode->nPriority; + pAttr->inNodeAttrIn.uTimeout = hNode->uTimeout; + pAttr->inNodeAttrIn.uHeapSize = + hNode->createArgs.asa.taskArgs.uHeapSize; + pAttr->inNodeAttrIn.pGPPVirtAddr = (void *) + hNode->createArgs.asa.taskArgs.uGPPHeapAddr; + pAttr->uInputs = hNode->uNumGPPInputs; + pAttr->uOutputs = hNode->uNumGPPOutputs; + /* DSP_NODEINFO */ + GetNodeInfo(hNode, &(pAttr->iNodeInfo)); + } + /* end of SYNC_EnterCS */ + /* Exit critical section */ + (void)SYNC_LeaveCS(hNodeMgr->hSync); + } + return status; +} + +/* + * ======== NODE_GetChannelId ======== + * Purpose: + * Get the channel index reserved for a stream connection between the + * host and a node. + */ +DSP_STATUS NODE_GetChannelId(struct NODE_OBJECT *hNode, u32 uDir, u32 uIndex, + OUT u32 *pulId) +{ + enum NODE_TYPE nodeType; + DSP_STATUS status = DSP_EVALUE; + DBC_Require(cRefs > 0); + DBC_Require(uDir == DSP_TONODE || uDir == DSP_FROMNODE); + DBC_Require(pulId != NULL); + GT_4trace(NODE_debugMask, GT_ENTER, "NODE_GetChannelId: hNode: " + "0x%x\tuDir: %d\tuIndex: %d\tpulId: 0x%x\n", hNode, uDir, + uIndex, pulId); + if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) { + status = DSP_EHANDLE; + return status; + } + nodeType = NODE_GetType(hNode); + if (nodeType != NODE_TASK && nodeType != NODE_DAISSOCKET) { + status = DSP_ENODETYPE; + return status; + } + if (uDir == DSP_TONODE) { + if (uIndex < MaxInputs(hNode)) { + if (hNode->inputs[uIndex].type == HOSTCONNECT) { + *pulId = hNode->inputs[uIndex].devId; + status = DSP_SOK; + } + } + } else { + DBC_Assert(uDir == DSP_FROMNODE); + if (uIndex < MaxOutputs(hNode)) { + if (hNode->outputs[uIndex].type == HOSTCONNECT) { + *pulId = hNode->outputs[uIndex].devId; + status = DSP_SOK; + } + } + } + return status; +} + +/* + * ======== NODE_GetMessage ======== + * Purpose: + * Retrieve a message from a node on the DSP. + */ +DSP_STATUS NODE_GetMessage(struct NODE_OBJECT *hNode, OUT struct DSP_MSG *pMsg, + u32 uTimeout) +{ + struct NODE_MGR *hNodeMgr; + enum NODE_TYPE nodeType; + struct WMD_DRV_INTERFACE *pIntfFxns; + DSP_STATUS status = DSP_SOK; + void *pTmpBuf; + struct DSP_PROCESSORSTATE procStatus; + struct PROC_OBJECT *hProcessor; + + DBC_Require(cRefs > 0); + DBC_Require(pMsg != NULL); + GT_3trace(NODE_debugMask, GT_ENTER, + "NODE_GetMessage: hNode: 0x%x\tpMsg: " + "0x%x\tuTimeout: 0x%x\n", hNode, pMsg, uTimeout); + hProcessor = hNode->hProcessor; + status = PROC_GetState(hProcessor, &procStatus, + sizeof(struct DSP_PROCESSORSTATE)); + if (DSP_FAILED(status)) + goto func_end; + /* If processor is in error state then don't attempt to get the + message */ + if (procStatus.iState == PROC_ERROR) { + GT_1trace(NODE_debugMask, GT_4CLASS, "NODE_GetMessage:" + " proc Status 0x%x\n", procStatus.iState); + status = DSP_EFAIL; + goto func_end; + } + if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) { + status = DSP_EHANDLE; + goto func_end; + } + hNodeMgr = hNode->hNodeMgr; + nodeType = NODE_GetType(hNode); + if (nodeType != NODE_MESSAGE && nodeType != NODE_TASK && + nodeType != NODE_DAISSOCKET) { + status = DSP_ENODETYPE; + goto func_end; + } + /* This function will block unless a message is available. Since + * DSPNode_RegisterNotify() allows notification when a message + * is available, the system can be designed so that + * DSPNode_GetMessage() is only called when a message is + * available. */ + pIntfFxns = hNodeMgr->pIntfFxns; + status = (*pIntfFxns->pfnMsgGet)(hNode->hMsgQueue, pMsg, uTimeout); + /* Check if message contains SM descriptor */ + if (DSP_FAILED(status) || !(pMsg->dwCmd & DSP_RMSBUFDESC)) + goto func_end; + + /* Translate DSP byte addr to GPP Va. */ + pTmpBuf = CMM_XlatorTranslate(hNode->hXlator, + (void *)(pMsg->dwArg1 * hNode->hNodeMgr->uDSPWordSize), + CMM_DSPPA2PA); + if (pTmpBuf != NULL) { + /* now convert this GPP Pa to Va */ + pTmpBuf = CMM_XlatorTranslate(hNode->hXlator, pTmpBuf, + CMM_PA2VA); + if (pTmpBuf != NULL) { + /* Adjust SM size in msg */ + pMsg->dwArg1 = (u32) pTmpBuf; + pMsg->dwArg2 *= hNode->hNodeMgr->uDSPWordSize; + } else { + GT_0trace(NODE_debugMask, GT_7CLASS, "NODE_GetMessage: " + "Failed SM translation!\n"); + status = DSP_ETRANSLATE; + } + } else { + GT_0trace(NODE_debugMask, GT_7CLASS, "NODE_GetMessage: Failed " + "SM Pa/Pa translation!\n"); + status = DSP_ETRANSLATE; + } +func_end: + return status; +} + +/* + * ======== NODE_GetNldrObj ======== + */ +DSP_STATUS NODE_GetNldrObj(struct NODE_MGR *hNodeMgr, + struct NLDR_OBJECT **phNldrObj) +{ + DSP_STATUS status = DSP_SOK; + struct NODE_MGR *pNodeMgr = hNodeMgr; + DBC_Require(phNldrObj != NULL); + GT_2trace(NODE_debugMask, GT_ENTER, + "Entered NODE_GetNldrObj, hNodeMgr: " + "0x%x\n\tphNldrObj: 0x%x\n", hNodeMgr, phNldrObj); + if (!MEM_IsValidHandle(hNodeMgr, NODEMGR_SIGNATURE)) + status = DSP_EHANDLE; + else + *phNldrObj = pNodeMgr->hNldr; + + GT_2trace(NODE_debugMask, GT_ENTER, + "Exit NODE_GetNldrObj: status 0x%x\n\t" + "phNldrObj: 0x%x\n", status, *phNldrObj); + DBC_Ensure(DSP_SUCCEEDED(status) || ((phNldrObj != NULL) && + (*phNldrObj == NULL))); + return status; +} + +/* + * ======== NODE_GetStrmMgr ======== + * Purpose: + * Returns the Stream manager. + */ +DSP_STATUS NODE_GetStrmMgr(struct NODE_OBJECT *hNode, + struct STRM_MGR **phStrmMgr) +{ + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + + if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) + status = DSP_EHANDLE; + else + *phStrmMgr = hNode->hNodeMgr->hStrmMgr; + + return status; +} + +/* + * ======== NODE_GetLoadType ======== + */ +enum NLDR_LOADTYPE NODE_GetLoadType(struct NODE_OBJECT *hNode) +{ + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(hNode, NODE_SIGNATURE)); + if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) { + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_GetLoadType: Failed. hNode:" + " 0x%x\n", hNode); + return -1; + } else + return hNode->dcdProps.objData.nodeObj.usLoadType; +} + +/* + * ======== NODE_GetTimeout ======== + * Purpose: + * Returns the timeout value for this node. + */ +u32 NODE_GetTimeout(struct NODE_OBJECT *hNode) +{ + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(hNode, NODE_SIGNATURE)); + if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) { + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_GetTimeout: Failed. hNode:" + " 0x%x\n", hNode); + return 0; + } else + return hNode->uTimeout; +} + +/* + * ======== NODE_GetType ======== + * Purpose: + * Returns the node type. + */ +enum NODE_TYPE NODE_GetType(struct NODE_OBJECT *hNode) +{ + enum NODE_TYPE nodeType; + + if (hNode == (struct NODE_OBJECT *) DSP_HGPPNODE) + nodeType = NODE_GPP; + else { + if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) + nodeType = -1; + else + nodeType = hNode->nType; + } + return nodeType; +} + +/* + * ======== NODE_Init ======== + * Purpose: + * Initialize the NODE module. + */ +bool NODE_Init(void) +{ + bool fRetVal = true; + + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { + DBC_Assert(!NODE_debugMask.flags); + GT_create(&NODE_debugMask, "NO"); /* "NO" for NOde */ + } + + if (fRetVal) + cRefs++; + + GT_1trace(NODE_debugMask, GT_5CLASS, "NODE_Init(), ref count: 0x%x\n", + cRefs); + + DBC_Ensure((fRetVal && (cRefs > 0)) || (!fRetVal && (cRefs >= 0))); + return fRetVal; +} + +/* + * ======== NODE_OnExit ======== + * Purpose: + * Gets called when RMS_EXIT is received for a node. + */ +void NODE_OnExit(struct NODE_OBJECT *hNode, s32 nStatus) +{ + DBC_Assert(MEM_IsValidHandle(hNode, NODE_SIGNATURE)); + /* Set node state to done */ + NODE_SetState(hNode, NODE_DONE); + hNode->nExitStatus = nStatus; + if (hNode->fLoaded && hNode->fPhaseSplit) { + (void)hNode->hNodeMgr->nldrFxns.pfnUnload(hNode->hNldrNode, + NLDR_EXECUTE); + hNode->fLoaded = false; + } + /* Unblock call to NODE_Terminate */ + (void) SYNC_SetEvent(hNode->hSyncDone); + /* Notify clients */ + PROC_NotifyClients(hNode->hProcessor, DSP_NODESTATECHANGE); + NTFY_Notify(hNode->hNtfy, DSP_NODESTATECHANGE); +} + +/* + * ======== NODE_Pause ======== + * Purpose: + * Suspend execution of a node currently running on the DSP. + */ +DSP_STATUS NODE_Pause(struct NODE_OBJECT *hNode) +{ + struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode; + enum NODE_TYPE nodeType; + enum NODE_STATE state; + struct NODE_MGR *hNodeMgr; + DSP_STATUS status = DSP_SOK; + u32 procId; + struct DSP_PROCESSORSTATE procStatus; + struct PROC_OBJECT *hProcessor; + + DBC_Require(cRefs > 0); + + GT_1trace(NODE_debugMask, GT_ENTER, "NODE_Pause: hNode: 0x%x\n", hNode); + + if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) { + status = DSP_EHANDLE; + } else { + nodeType = NODE_GetType(hNode); + if (nodeType != NODE_TASK && nodeType != NODE_DAISSOCKET) + status = DSP_ENODETYPE; + + } + + status = PROC_GetProcessorId(pNode->hProcessor, &procId); + + if (procId == IVA_UNIT) + status = DSP_ENOTIMPL; + + if (DSP_SUCCEEDED(status)) { + hNodeMgr = hNode->hNodeMgr; + + /* Enter critical section */ + status = SYNC_EnterCS(hNodeMgr->hSync); + + if (DSP_SUCCEEDED(status)) { + state = NODE_GetState(hNode); + /* Check node state */ + if (state != NODE_RUNNING) + status = DSP_EWRONGSTATE; + + hProcessor = hNode->hProcessor; + status = PROC_GetState(hProcessor, &procStatus, + sizeof(struct DSP_PROCESSORSTATE)); + if (DSP_FAILED(status)) + goto func_end; + /* If processor is in error state then don't attempt + to send the message */ + if (procStatus.iState == PROC_ERROR) { + GT_1trace(NODE_debugMask, GT_4CLASS, + "NODE_Pause: proc Status 0x%x\n", + procStatus.iState); + status = DSP_EFAIL; + goto func_end; + } + if (DSP_SUCCEEDED(status)) { + status = DISP_NodeChangePriority(hNodeMgr-> + hDisp, hNode, + hNodeMgr->ulFxnAddrs[RMSCHANGENODEPRIORITY], + hNode->nodeEnv, NODE_SUSPENDEDPRI); + } + + /* Update state */ + if (DSP_SUCCEEDED(status)) { + NODE_SetState(hNode, NODE_PAUSED); + } else { + GT_1trace(NODE_debugMask, GT_6CLASS, + "NODE_Pause: Failed. hNode:" + " 0x%x\n", hNode); + } + } + /* End of SYNC_EnterCS */ + /* Leave critical section */ + (void)SYNC_LeaveCS(hNodeMgr->hSync); + if (DSP_SUCCEEDED(status)) { + PROC_NotifyClients(hNode->hProcessor, + DSP_NODESTATECHANGE); + NTFY_Notify(hNode->hNtfy, DSP_NODESTATECHANGE); + } + } +func_end: + return status; +} + +/* + * ======== NODE_PutMessage ======== + * Purpose: + * Send a message to a message node, task node, or XDAIS socket node. This + * function will block until the message stream can accommodate the + * message, or a timeout occurs. + */ +DSP_STATUS NODE_PutMessage(struct NODE_OBJECT *hNode, + IN CONST struct DSP_MSG *pMsg, u32 uTimeout) +{ + struct NODE_MGR *hNodeMgr = NULL; + enum NODE_TYPE nodeType; + struct WMD_DRV_INTERFACE *pIntfFxns; + enum NODE_STATE state; + DSP_STATUS status = DSP_SOK; + void *pTmpBuf; + struct DSP_MSG newMsg; + struct DSP_PROCESSORSTATE procStatus; + struct PROC_OBJECT *hProcessor; + + DBC_Require(cRefs > 0); + DBC_Require(pMsg != NULL); + GT_3trace(NODE_debugMask, GT_ENTER, + "NODE_PutMessage: hNode: 0x%x\tpMsg: " + "0x%x\tuTimeout: 0x%x\n", hNode, pMsg, uTimeout); + hProcessor = hNode->hProcessor; + status = PROC_GetState(hProcessor, &procStatus, + sizeof(struct DSP_PROCESSORSTATE)); + if (DSP_FAILED(status)) + goto func_end; + /* If processor is in bad state then don't attempt sending the + message */ + if (procStatus.iState == PROC_ERROR) { + GT_1trace(NODE_debugMask, GT_4CLASS, "NODE_PutMessage:" + " proc Status 0x%x\n", procStatus.iState); + status = DSP_EFAIL; + goto func_end; + } + if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) + status = DSP_EHANDLE; + else { + hNodeMgr = hNode->hNodeMgr; + nodeType = NODE_GetType(hNode); + if (nodeType != NODE_MESSAGE && nodeType != NODE_TASK && + nodeType != NODE_DAISSOCKET) + status = DSP_ENODETYPE; + } + if (DSP_SUCCEEDED(status)) { + /* Check node state. Can't send messages to a node after + * we've sent the RMS_EXIT command. There is still the + * possibility that NODE_Terminate can be called after we've + * checked the state. Could add another SYNC object to + * prevent this (can't use hNodeMgr->hSync, since we don't + * want to block other NODE functions). However, the node may + * still exit on its own, before this message is sent. */ + status = SYNC_EnterCS(hNodeMgr->hSync); + if (DSP_SUCCEEDED(status)) { + state = NODE_GetState(hNode); + if (state == NODE_TERMINATING || state == NODE_DONE) + status = DSP_EWRONGSTATE; + + } + /* end of SYNC_EnterCS */ + (void)SYNC_LeaveCS(hNodeMgr->hSync); + } + if (DSP_FAILED(status)) + goto func_end; + + /* assign pMsg values to new msg */ + newMsg = *pMsg; + /* Now, check if message contains a SM buffer descriptor */ + if (pMsg->dwCmd & DSP_RMSBUFDESC) { + /* Translate GPP Va to DSP physical buf Ptr. */ + pTmpBuf = CMM_XlatorTranslate(hNode->hXlator, + (void *)newMsg.dwArg1, CMM_VA2DSPPA); + if (pTmpBuf != NULL) { + /* got translation, convert to MAUs in msg */ + if (hNode->hNodeMgr->uDSPWordSize != 0) { + newMsg.dwArg1 = + (u32)pTmpBuf / + hNode->hNodeMgr->uDSPWordSize; + /* MAUs */ + newMsg.dwArg2 /= hNode->hNodeMgr->uDSPWordSize; + } else { + GT_0trace(NODE_debugMask, GT_7CLASS, + "NODE_PutMessage: " + "uDSPWordSize is zero!\n"); + status = DSP_EFAIL; /* bad DSPWordSize */ + } + } else { /* failed to translate buffer address */ + GT_0trace(NODE_debugMask, GT_7CLASS, + "NODE_PutMessage: Failed to" + " translate SM address\n"); + status = DSP_ETRANSLATE; + } + } + if (DSP_SUCCEEDED(status)) { + pIntfFxns = hNodeMgr->pIntfFxns; + status = (*pIntfFxns->pfnMsgPut)(hNode->hMsgQueue, + &newMsg, uTimeout); + } +func_end: + return status; +} + +/* + * ======== NODE_RegisterNotify ======== + * Purpose: + * Register to be notified on specific events for this node. + */ +DSP_STATUS NODE_RegisterNotify(struct NODE_OBJECT *hNode, u32 uEventMask, + u32 uNotifyType, + struct DSP_NOTIFICATION *hNotification) +{ + struct WMD_DRV_INTERFACE *pIntfFxns; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(hNotification != NULL); + + GT_4trace(NODE_debugMask, GT_ENTER, + "NODE_RegisterNotify: hNode: 0x%x\t" + "uEventMask: 0x%x\tuNotifyType: 0x%x\thNotification: 0x%x\n", + hNode, uEventMask, uNotifyType, hNotification); + + if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) { + status = DSP_EHANDLE; + } else { + /* Check if event mask is a valid node related event */ + if (uEventMask & ~(DSP_NODESTATECHANGE | + DSP_NODEMESSAGEREADY)) + status = DSP_EVALUE; + + /* Check if notify type is valid */ + if (uNotifyType != DSP_SIGNALEVENT) + status = DSP_EVALUE; + + /* Only one Notification can be registered at a + * time - Limitation */ + if (uEventMask == (DSP_NODESTATECHANGE | + DSP_NODEMESSAGEREADY)) + status = DSP_EVALUE; + } + if (DSP_SUCCEEDED(status)) { + if (uEventMask == DSP_NODESTATECHANGE) { + status = NTFY_Register(hNode->hNtfy, hNotification, + uEventMask & DSP_NODESTATECHANGE, uNotifyType); + } else { + /* Send Message part of event mask to MSG */ + pIntfFxns = hNode->hNodeMgr->pIntfFxns; + status = (*pIntfFxns->pfnMsgRegisterNotify) + (hNode->hMsgQueue, + uEventMask & DSP_NODEMESSAGEREADY, uNotifyType, + hNotification); + } + + } + return status; +} + +/* + * ======== NODE_Run ======== + * Purpose: + * Start execution of a node's execute phase, or resume execution of a node + * that has been suspended (via NODE_NodePause()) on the DSP. Load the + * node's execute function if necessary. + */ +DSP_STATUS NODE_Run(struct NODE_OBJECT *hNode) +{ + struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode; + struct NODE_MGR *hNodeMgr; + enum NODE_TYPE nodeType; + enum NODE_STATE state; + u32 ulExecuteFxn; + u32 ulFxnAddr; + DSP_STATUS status = DSP_SOK; + u32 procId; + struct WMD_DRV_INTERFACE *pIntfFxns; + struct DSP_PROCESSORSTATE procStatus; + struct PROC_OBJECT *hProcessor; + + DBC_Require(cRefs > 0); + GT_1trace(NODE_debugMask, GT_ENTER, "NODE_Run: hNode: 0x%x\n", hNode); + hProcessor = hNode->hProcessor; + status = PROC_GetState(hProcessor, &procStatus, + sizeof(struct DSP_PROCESSORSTATE)); + if (DSP_FAILED(status)) + goto func_end; + /* If processor is in error state then don't attempt to run the node */ + if (procStatus.iState == PROC_ERROR) { + GT_1trace(NODE_debugMask, GT_4CLASS, "NODE_Run:" + " proc Status 0x%x\n", procStatus.iState); + status = DSP_EFAIL; + goto func_end; + } + if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) { + status = DSP_EHANDLE; + } else { + nodeType = NODE_GetType(hNode); + if (nodeType == NODE_DEVICE) + status = DSP_ENODETYPE; + } + if (DSP_FAILED(status)) + goto func_end; + + hNodeMgr = hNode->hNodeMgr; + pIntfFxns = hNodeMgr->pIntfFxns; + /* Enter critical section */ + status = SYNC_EnterCS(hNodeMgr->hSync); + if (DSP_FAILED(status)) + goto func_cont; + + state = NODE_GetState(hNode); + if (state != NODE_CREATED && state != NODE_PAUSED) + status = DSP_EWRONGSTATE; + + if (DSP_SUCCEEDED(status)) + status = PROC_GetProcessorId(pNode->hProcessor, &procId); + + if (DSP_FAILED(status)) + goto func_cont1; + + if ((procId != DSP_UNIT) && (procId != IVA_UNIT)) + goto func_cont1; + + if (state == NODE_CREATED) { + /* If node's execute function is not loaded, load it */ + if (!(hNode->fLoaded) && hNode->fPhaseSplit) { + status = hNodeMgr->nldrFxns.pfnLoad(hNode->hNldrNode, + NLDR_EXECUTE); + if (DSP_SUCCEEDED(status)) { + hNode->fLoaded = true; + } else { + GT_1trace(NODE_debugMask, GT_ENTER, + "NODE_Run: failed to load " + "execute code:0x%x\n", status); + } + } + if (DSP_SUCCEEDED(status)) { + /* Get address of node's execute function */ + if (procId == IVA_UNIT) + ulExecuteFxn = (u32) hNode->nodeEnv; + else { + status = GetFxnAddress(hNode, &ulExecuteFxn, + EXECUTEPHASE); + } + } + if (DSP_SUCCEEDED(status)) { + ulFxnAddr = hNodeMgr->ulFxnAddrs[RMSEXECUTENODE]; + status = DISP_NodeRun(hNodeMgr->hDisp, hNode, ulFxnAddr, + ulExecuteFxn, hNode->nodeEnv); + } + } else if (state == NODE_PAUSED) { + ulFxnAddr = hNodeMgr->ulFxnAddrs[RMSCHANGENODEPRIORITY]; + status = DISP_NodeChangePriority(hNodeMgr->hDisp, hNode, + ulFxnAddr, hNode->nodeEnv, + NODE_GetPriority(hNode)); + } else { + /* We should never get here */ + DBC_Assert(false); + } +func_cont1: + /* Update node state. */ + if (DSP_SUCCEEDED(status)) + NODE_SetState(hNode, NODE_RUNNING); + else /* Set state back to previous value */ + NODE_SetState(hNode, state); + /*End of SYNC_EnterCS */ + /* Exit critical section */ +func_cont: + (void)SYNC_LeaveCS(hNodeMgr->hSync); + if (DSP_SUCCEEDED(status)) { + PROC_NotifyClients(hNode->hProcessor, + DSP_NODESTATECHANGE); + NTFY_Notify(hNode->hNtfy, DSP_NODESTATECHANGE); + } +func_end: + return status; +} + +/* + * ======== NODE_Terminate ======== + * Purpose: + * Signal a node running on the DSP that it should exit its execute phase + * function. + */ +DSP_STATUS NODE_Terminate(struct NODE_OBJECT *hNode, OUT DSP_STATUS *pStatus) +{ + struct NODE_OBJECT *pNode = (struct NODE_OBJECT *)hNode; + struct NODE_MGR *hNodeMgr = NULL; + enum NODE_TYPE nodeType; + struct WMD_DRV_INTERFACE *pIntfFxns; + enum NODE_STATE state; + struct DSP_MSG msg, killmsg; + DSP_STATUS status = DSP_SOK; + u32 procId, killTimeOut; + struct DEH_MGR *hDehMgr; + struct DSP_PROCESSORSTATE procStatus; + + DBC_Require(cRefs > 0); + DBC_Require(pStatus != NULL); + + GT_1trace(NODE_debugMask, GT_ENTER, + "NODE_Terminate: hNode: 0x%x\n", hNode); + + if (pNode->hProcessor == NULL) { + GT_1trace(NODE_debugMask, GT_4CLASS, + "NODE_Terminate: pNode->hProcessor = 0x%x\n", + pNode->hProcessor); + goto func_end; + } + status = PROC_GetProcessorId(pNode->hProcessor, &procId); + + if (DSP_SUCCEEDED(status)) { + hNodeMgr = hNode->hNodeMgr; + + if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) + status = DSP_EHANDLE; + else { + nodeType = NODE_GetType(hNode); + if (nodeType != NODE_TASK && nodeType != + NODE_DAISSOCKET) + status = DSP_ENODETYPE; + } + } + if (DSP_SUCCEEDED(status)) { + /* Check node state */ + status = SYNC_EnterCS(hNodeMgr->hSync); + if (DSP_SUCCEEDED(status)) { + state = NODE_GetState(hNode); + if (state != NODE_RUNNING) { + status = DSP_EWRONGSTATE; + /* Set the exit status if node terminated on + * its own. */ + if (state == NODE_DONE) + *pStatus = hNode->nExitStatus; + + } else { + NODE_SetState(hNode, NODE_TERMINATING); + } + } + /* end of SYNC_EnterCS */ + (void)SYNC_LeaveCS(hNodeMgr->hSync); + } + if (DSP_SUCCEEDED(status)) { + /* + * Send exit message. Do not change state to NODE_DONE + * here. That will be done in callback. + */ + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_Terminate: env = 0x%x\n", hNode->nodeEnv); + + status = PROC_GetState(pNode->hProcessor, &procStatus, + sizeof(struct DSP_PROCESSORSTATE)); + if (DSP_FAILED(status)) + goto func_cont; + /* If processor is in error state then don't attempt to send + * A kill task command */ + if (procStatus.iState == PROC_ERROR) { + GT_1trace(NODE_debugMask, GT_4CLASS, "NODE_Terminate:" + " proc Status 0x%x\n", procStatus.iState); + status = DSP_EFAIL; + goto func_cont; + } + + msg.dwCmd = RMS_EXIT; + msg.dwArg1 = hNode->nodeEnv; + killmsg.dwCmd = RMS_KILLTASK; + killmsg.dwArg1 = hNode->nodeEnv; + pIntfFxns = hNodeMgr->pIntfFxns; + + if (hNode->uTimeout > MAXTIMEOUT) + killTimeOut = MAXTIMEOUT; + else + killTimeOut = (hNode->uTimeout)*2; + + status = (*pIntfFxns->pfnMsgPut)(hNode->hMsgQueue, &msg, + hNode->uTimeout); + if (DSP_SUCCEEDED(status)) { + /* Wait on synchronization object that will be + * posted in the callback on receiving RMS_EXIT + * message, or by NODE_Delete. Check for valid hNode, + * in case posted by NODE_Delete(). */ + status = SYNC_WaitOnEvent(hNode->hSyncDone, + killTimeOut/2); + if (DSP_FAILED(status)) { + if (status == DSP_ETIMEOUT) { + status = (*pIntfFxns->pfnMsgPut) + (hNode->hMsgQueue, &killmsg, + hNode->uTimeout); + if (DSP_SUCCEEDED(status)) { + status = SYNC_WaitOnEvent + (hNode->hSyncDone, + killTimeOut/2); + if (DSP_FAILED(status)) { + /* Here it goes the part + * of the simulation of + * the DSP exception */ + DEV_GetDehMgr(hNodeMgr-> + hDevObject, &hDehMgr); + if (hDehMgr) { + (*pIntfFxns-> + pfnDehNotify)(hDehMgr, + DSP_SYSERROR, + DSP_EXCEPTIONABORT); + status = DSP_EFAIL; + } + } else + status = DSP_SOK; + } + } else + status = DSP_EFAIL; + } else /* Convert SYNC status to DSP status */ + status = DSP_SOK; + } + } +func_cont: + if (DSP_SUCCEEDED(status)) { + /* Enter CS before getting exit status, in case node was + * deleted. */ + status = SYNC_EnterCS(hNodeMgr->hSync); + /* Make sure node wasn't deleted while we blocked */ + if (!MEM_IsValidHandle(hNode, NODE_SIGNATURE)) { + status = DSP_EFAIL; + } else { + *pStatus = hNode->nExitStatus; + GT_1trace(NODE_debugMask, GT_ENTER, + "NODE_Terminate: env = 0x%x " + "succeeded.\n", hNode->nodeEnv); + } + (void)SYNC_LeaveCS(hNodeMgr->hSync); + } /*End of SYNC_EnterCS */ +func_end: + return status; +} + +/* + * ======== DeleteNode ======== + * Purpose: + * Free GPP resources allocated in NODE_Allocate() or NODE_Connect(). + */ +static void DeleteNode(struct NODE_OBJECT *hNode) +{ + struct NODE_MGR *hNodeMgr; + struct CMM_XLATOROBJECT *hXlator; + struct WMD_DRV_INTERFACE *pIntfFxns; + u32 i; + enum NODE_TYPE nodeType; + struct STREAM stream; + struct NODE_MSGARGS msgArgs; + struct NODE_TASKARGS taskArgs; +#ifdef DSP_DMM_DEBUG + struct DMM_OBJECT *hDmmMgr; + struct PROC_OBJECT *pProcObject = + (struct PROC_OBJECT *)hNode->hProcessor; +#endif + DSP_STATUS status; + DBC_Require(MEM_IsValidHandle(hNode, NODE_SIGNATURE)); + hNodeMgr = hNode->hNodeMgr; + if (!MEM_IsValidHandle(hNodeMgr, NODEMGR_SIGNATURE)) + return; + hXlator = hNode->hXlator; + nodeType = NODE_GetType(hNode); + if (nodeType != NODE_DEVICE) { + msgArgs = hNode->createArgs.asa.msgArgs; + if (msgArgs.pData) + MEM_Free(msgArgs.pData); + + /* Free MSG queue */ + if (hNode->hMsgQueue) { + pIntfFxns = hNodeMgr->pIntfFxns; + (*pIntfFxns->pfnMsgDeleteQueue) (hNode->hMsgQueue); + hNode->hMsgQueue = NULL; + + } + if (hNode->hSyncDone) + (void) SYNC_CloseEvent(hNode->hSyncDone); + + /* Free all stream info */ + if (hNode->inputs) { + for (i = 0; i < MaxInputs(hNode); i++) { + stream = hNode->inputs[i]; + FreeStream(hNodeMgr, stream); + } + MEM_Free(hNode->inputs); + hNode->inputs = NULL; + } + if (hNode->outputs) { + for (i = 0; i < MaxOutputs(hNode); i++) { + stream = hNode->outputs[i]; + FreeStream(hNodeMgr, stream); + } + MEM_Free(hNode->outputs); + hNode->outputs = NULL; + } + taskArgs = hNode->createArgs.asa.taskArgs; + if (taskArgs.strmInDef) { + for (i = 0; i < MaxInputs(hNode); i++) { + if (taskArgs.strmInDef[i].szDevice) { + MEM_Free(taskArgs.strmInDef[i]. + szDevice); + taskArgs.strmInDef[i].szDevice = NULL; + } + } + MEM_Free(taskArgs.strmInDef); + taskArgs.strmInDef = NULL; + } + if (taskArgs.strmOutDef) { + for (i = 0; i < MaxOutputs(hNode); i++) { + if (taskArgs.strmOutDef[i].szDevice) { + MEM_Free(taskArgs.strmOutDef[i]. + szDevice); + taskArgs.strmOutDef[i].szDevice = NULL; + } + } + MEM_Free(taskArgs.strmOutDef); + taskArgs.strmOutDef = NULL; + } + if (taskArgs.uDSPHeapResAddr) { + status = PROC_UnMap(hNode->hProcessor, + (void *)taskArgs.uDSPHeapAddr); + if (DSP_SUCCEEDED(status)) { + GT_0trace(NODE_debugMask, GT_5CLASS, + "DSPProcessor_UnMap succeeded.\n"); + } else { + GT_1trace(NODE_debugMask, GT_5CLASS, + "DSPProcessor_UnMap failed." + " Status = 0x%x\n", (u32)status); + } + status = PROC_UnReserveMemory(hNode->hProcessor, + (void *)taskArgs.uDSPHeapResAddr); + if (DSP_SUCCEEDED(status)) { + GT_0trace(NODE_debugMask, GT_5CLASS, + "DSPProcessor_UnReserveMemory " + "succeeded.\n"); + } else { + GT_1trace(NODE_debugMask, GT_5CLASS, + "DSPProcessor_UnReserveMemory " + "failed. Status = 0x%x\n", + (u32)status); + } +#ifdef DSP_DMM_DEBUG + status = DMM_GetHandle(pProcObject, &hDmmMgr); + if (DSP_SUCCEEDED(status)) + DMM_MemMapDump(hDmmMgr); +#endif + } + } + if (nodeType != NODE_MESSAGE) { + if (hNode->streamConnect) { + MEM_Free(hNode->streamConnect); + hNode->streamConnect = NULL; + } + } + if (hNode->pstrDevName) { + MEM_Free(hNode->pstrDevName); + hNode->pstrDevName = NULL; + } + + if (hNode->hNtfy) { + NTFY_Delete(hNode->hNtfy); + hNode->hNtfy = NULL; + } + + /* These were allocated in DCD_GetObjectDef (via NODE_Allocate) */ + if (hNode->dcdProps.objData.nodeObj.pstrCreatePhaseFxn) { + MEM_Free(hNode->dcdProps.objData.nodeObj.pstrCreatePhaseFxn); + hNode->dcdProps.objData.nodeObj.pstrCreatePhaseFxn = NULL; + } + + if (hNode->dcdProps.objData.nodeObj.pstrExecutePhaseFxn) { + MEM_Free(hNode->dcdProps.objData.nodeObj.pstrExecutePhaseFxn); + hNode->dcdProps.objData.nodeObj.pstrExecutePhaseFxn = NULL; + } + + if (hNode->dcdProps.objData.nodeObj.pstrDeletePhaseFxn) { + MEM_Free(hNode->dcdProps.objData.nodeObj.pstrDeletePhaseFxn); + hNode->dcdProps.objData.nodeObj.pstrDeletePhaseFxn = NULL; + } + + if (hNode->dcdProps.objData.nodeObj.pstrIAlgName) { + MEM_Free(hNode->dcdProps.objData.nodeObj.pstrIAlgName); + hNode->dcdProps.objData.nodeObj.pstrIAlgName = NULL; + } + + /* Free all SM address translator resources */ + if (hXlator) { + (void) CMM_XlatorDelete(hXlator, TRUE); /* force free */ + hXlator = NULL; + } + + if (hNode->hNldrNode) { + hNodeMgr->nldrFxns.pfnFree(hNode->hNldrNode); + hNode->hNldrNode = NULL; + } + + MEM_FreeObject(hNode); + hNode = NULL; +} + +/* + * ======== DeleteNodeMgr ======== + * Purpose: + * Frees the node manager. + */ +static void DeleteNodeMgr(struct NODE_MGR *hNodeMgr) +{ + struct NODE_OBJECT *hNode; + + if (MEM_IsValidHandle(hNodeMgr, NODEMGR_SIGNATURE)) { + /* Free resources */ + if (hNodeMgr->hDcdMgr) + DCD_DestroyManager(hNodeMgr->hDcdMgr); + + /* Remove any elements remaining in lists */ + if (hNodeMgr->nodeList) { + while ((hNode = + (struct NODE_OBJECT *)LST_GetHead(hNodeMgr-> + nodeList))) + DeleteNode(hNode); + + DBC_Assert(LST_IsEmpty(hNodeMgr->nodeList)); + LST_Delete(hNodeMgr->nodeList); + } + if (hNodeMgr->hNtfy) + NTFY_Delete(hNodeMgr->hNtfy); + + if (hNodeMgr->pipeMap) + GB_delete(hNodeMgr->pipeMap); + + if (hNodeMgr->pipeDoneMap) + GB_delete(hNodeMgr->pipeDoneMap); + + if (hNodeMgr->chnlMap) + GB_delete(hNodeMgr->chnlMap); + + if (hNodeMgr->dmaChnlMap) + GB_delete(hNodeMgr->dmaChnlMap); + + if (hNodeMgr->zChnlMap) + GB_delete(hNodeMgr->zChnlMap); + + if (hNodeMgr->hDisp) + DISP_Delete(hNodeMgr->hDisp); + + if (hNodeMgr->hSync) + SYNC_DeleteCS(hNodeMgr->hSync); + + if (hNodeMgr->hStrmMgr) + STRM_Delete(hNodeMgr->hStrmMgr); + + /* Delete the loader */ + if (hNodeMgr->hNldr) + hNodeMgr->nldrFxns.pfnDelete(hNodeMgr->hNldr); + + if (hNodeMgr->fLoaderInit) + hNodeMgr->nldrFxns.pfnExit(); + + MEM_FreeObject(hNodeMgr); + } +} + +/* + * ======== FillStreamConnect ======== + * Purpose: + * Fills stream information. + */ +static void FillStreamConnect(struct NODE_OBJECT *hNode1, + struct NODE_OBJECT *hNode2, + u32 uStream1, u32 uStream2) +{ + u32 uStrmIndex; + struct DSP_STREAMCONNECT *pStrm1 = NULL; + struct DSP_STREAMCONNECT *pStrm2 = NULL; + enum NODE_TYPE node1Type = NODE_TASK; + enum NODE_TYPE node2Type = NODE_TASK; + + node1Type = NODE_GetType(hNode1); + node2Type = NODE_GetType(hNode2); + if (hNode1 != (struct NODE_OBJECT *)DSP_HGPPNODE) { + + if (node1Type != NODE_DEVICE) { + uStrmIndex = hNode1->uNumInputs + + hNode1->uNumOutputs - 1; + pStrm1 = &(hNode1->streamConnect[uStrmIndex]); + pStrm1->cbStruct = sizeof(struct DSP_STREAMCONNECT); + pStrm1->uThisNodeStreamIndex = uStream1; + } + + if (hNode2 != (struct NODE_OBJECT *)DSP_HGPPNODE) { + /* NODE == > NODE */ + if (node1Type != NODE_DEVICE) { + pStrm1->hConnectedNode = hNode2; + pStrm1->uiConnectedNodeID = hNode2->nodeId; + pStrm1->uConnectedNodeStreamIndex = uStream2; + pStrm1->lType = CONNECTTYPE_NODEOUTPUT; + } + if (node2Type != NODE_DEVICE) { + uStrmIndex = hNode2->uNumInputs + + hNode2->uNumOutputs - 1; + pStrm2 = &(hNode2->streamConnect[uStrmIndex]); + pStrm2->cbStruct = + sizeof(struct DSP_STREAMCONNECT); + pStrm2->uThisNodeStreamIndex = uStream2; + pStrm2->hConnectedNode = hNode1; + pStrm2->uiConnectedNodeID = hNode1->nodeId; + pStrm2->uConnectedNodeStreamIndex = uStream1; + pStrm2->lType = CONNECTTYPE_NODEINPUT; + } + } else if (node1Type != NODE_DEVICE) + pStrm1->lType = CONNECTTYPE_GPPOUTPUT; + } else { + /* GPP == > NODE */ + DBC_Assert(hNode2 != (struct NODE_OBJECT *)DSP_HGPPNODE); + uStrmIndex = hNode2->uNumInputs + hNode2->uNumOutputs - 1; + pStrm2 = &(hNode2->streamConnect[uStrmIndex]); + pStrm2->cbStruct = sizeof(struct DSP_STREAMCONNECT); + pStrm2->uThisNodeStreamIndex = uStream2; + pStrm2->lType = CONNECTTYPE_GPPINPUT; + } +} + +/* + * ======== FillStreamDef ======== + * Purpose: + * Fills Stream attributes. + */ +static void FillStreamDef(struct NODE_OBJECT *hNode, + struct NODE_STRMDEF *pstrmDef, + struct DSP_STRMATTR *pAttrs) +{ + struct NODE_MGR *hNodeMgr = hNode->hNodeMgr; + + if (pAttrs != NULL) { + pstrmDef->uNumBufs = pAttrs->uNumBufs; + pstrmDef->uBufsize = pAttrs->uBufsize / hNodeMgr-> + uDSPDataMauSize; + pstrmDef->uSegid = pAttrs->uSegid; + pstrmDef->uAlignment = pAttrs->uAlignment; + pstrmDef->uTimeout = pAttrs->uTimeout; + } else { + pstrmDef->uNumBufs = DEFAULTNBUFS; + pstrmDef->uBufsize = DEFAULTBUFSIZE / hNodeMgr-> + uDSPDataMauSize; + pstrmDef->uSegid = DEFAULTSEGID; + pstrmDef->uAlignment = DEFAULTALIGNMENT; + pstrmDef->uTimeout = DEFAULTTIMEOUT; + } +} + +/* + * ======== FreeStream ======== + * Purpose: + * Updates the channel mask and frees the pipe id. + */ +static void FreeStream(struct NODE_MGR *hNodeMgr, struct STREAM stream) +{ + /* Free up the pipe id unless other node has not yet been deleted. */ + if (stream.type == NODECONNECT) { + if (GB_test(hNodeMgr->pipeDoneMap, stream.devId)) { + /* The other node has already been deleted */ + GB_clear(hNodeMgr->pipeDoneMap, stream.devId); + GB_clear(hNodeMgr->pipeMap, stream.devId); + } else { + /* The other node has not been deleted yet */ + GB_set(hNodeMgr->pipeDoneMap, stream.devId); + } + } else if (stream.type == HOSTCONNECT) { + if (stream.devId < hNodeMgr->ulNumChnls) { + GB_clear(hNodeMgr->chnlMap, stream.devId); + } else if (stream.devId < (2 * hNodeMgr->ulNumChnls)) { + /* dsp-dma */ + GB_clear(hNodeMgr->dmaChnlMap, stream.devId - + (1 * hNodeMgr->ulNumChnls)); + } else if (stream.devId < (3 * hNodeMgr->ulNumChnls)) { + /* zero-copy */ + GB_clear(hNodeMgr->zChnlMap, stream.devId - + (2 * hNodeMgr->ulNumChnls)); + } + } +} + +/* + * ======== GetFxnAddress ======== + * Purpose: + * Retrieves the address for create, execute or delete phase for a node. + */ +static DSP_STATUS GetFxnAddress(struct NODE_OBJECT *hNode, u32 *pulFxnAddr, + u32 uPhase) +{ + char *pstrFxnName = NULL; + struct NODE_MGR *hNodeMgr = hNode->hNodeMgr; + DSP_STATUS status = DSP_SOK; + DBC_Require(NODE_GetType(hNode) == NODE_TASK || + NODE_GetType(hNode) == NODE_DAISSOCKET || + NODE_GetType(hNode) == NODE_MESSAGE); + + switch (uPhase) { + case CREATEPHASE: + pstrFxnName = hNode->dcdProps.objData.nodeObj. + pstrCreatePhaseFxn; + break; + case EXECUTEPHASE: + pstrFxnName = hNode->dcdProps.objData.nodeObj. + pstrExecutePhaseFxn; + break; + case DELETEPHASE: + pstrFxnName = hNode->dcdProps.objData.nodeObj. + pstrDeletePhaseFxn; + break; + default: + /* Should never get here */ + DBC_Assert(false); + break; + } + + status = hNodeMgr->nldrFxns.pfnGetFxnAddr(hNode->hNldrNode, pstrFxnName, + pulFxnAddr); + + return status; +} + +/* + * ======== GetNodeInfo ======== + * Purpose: + * Retrieves the node information. + */ +void GetNodeInfo(struct NODE_OBJECT *hNode, struct DSP_NODEINFO *pNodeInfo) +{ + u32 i; + + DBC_Require(MEM_IsValidHandle(hNode, NODE_SIGNATURE)); + DBC_Require(pNodeInfo != NULL); + + pNodeInfo->cbStruct = sizeof(struct DSP_NODEINFO); + pNodeInfo->nbNodeDatabaseProps = hNode->dcdProps.objData.nodeObj. + ndbProps; + pNodeInfo->uExecutionPriority = hNode->nPriority; + pNodeInfo->hDeviceOwner = hNode->hDeviceOwner; + pNodeInfo->uNumberStreams = hNode->uNumInputs + hNode->uNumOutputs; + pNodeInfo->uNodeEnv = hNode->nodeEnv; + + pNodeInfo->nsExecutionState = NODE_GetState(hNode); + + /* Copy stream connect data */ + for (i = 0; i < hNode->uNumInputs + hNode->uNumOutputs; i++) + pNodeInfo->scStreamConnection[i] = hNode->streamConnect[i]; + +} + +/* + * ======== GetNodeProps ======== + * Purpose: + * Retrieve node properties. + */ +static DSP_STATUS GetNodeProps(struct DCD_MANAGER *hDcdMgr, + struct NODE_OBJECT *hNode, + CONST struct DSP_UUID *pNodeId, + struct DCD_GENERICOBJ *pdcdProps) +{ + u32 uLen; + struct NODE_MSGARGS *pMsgArgs; + struct NODE_TASKARGS *pTaskArgs; + enum NODE_TYPE nodeType = NODE_TASK; + struct DSP_NDBPROPS *pndbProps = &(pdcdProps->objData.nodeObj.ndbProps); + DSP_STATUS status = DSP_SOK; +#ifdef DEBUG + char szUuid[MAXUUIDLEN]; +#endif + + status = DCD_GetObjectDef(hDcdMgr, (struct DSP_UUID *)pNodeId, + DSP_DCDNODETYPE, pdcdProps); + + if (DSP_SUCCEEDED(status)) { + hNode->nType = nodeType = pndbProps->uNodeType; + +#ifdef DEBUG + /* Create UUID value to set in registry. */ + UUID_UuidToString((struct DSP_UUID *)pNodeId, szUuid, + MAXUUIDLEN); + DBG_Trace(DBG_LEVEL7, "\n** (node) UUID: %s\n", szUuid); +#endif + + /* Fill in message args that come from NDB */ + if (nodeType != NODE_DEVICE) { + pMsgArgs = &(hNode->createArgs.asa.msgArgs); + pMsgArgs->uSegid = pdcdProps->objData.nodeObj.uMsgSegid; + pMsgArgs->uNotifyType = pdcdProps->objData.nodeObj. + uMsgNotifyType; + pMsgArgs->uMaxMessages = pndbProps->uMessageDepth; +#ifdef DEBUG + DBG_Trace(DBG_LEVEL7, + "** (node) Max Number of Messages: 0x%x\n", + pMsgArgs->uMaxMessages); +#endif + } else { + /* Copy device name */ + DBC_Require(pndbProps->acName); + uLen = strlen(pndbProps->acName); + DBC_Assert(uLen < MAXDEVNAMELEN); + hNode->pstrDevName = MEM_Calloc(uLen + 1, MEM_PAGED); + if (hNode->pstrDevName == NULL) { + status = DSP_EMEMORY; + } else { + strncpy(hNode->pstrDevName, + pndbProps->acName, uLen); + } + } + } + if (DSP_SUCCEEDED(status)) { + /* Fill in create args that come from NDB */ + if (nodeType == NODE_TASK || nodeType == NODE_DAISSOCKET) { + pTaskArgs = &(hNode->createArgs.asa.taskArgs); + pTaskArgs->nPriority = pndbProps->iPriority; + pTaskArgs->uStackSize = pndbProps->uStackSize; + pTaskArgs->uSysStackSize = pndbProps->uSysStackSize; + pTaskArgs->uStackSeg = pndbProps->uStackSeg; +#ifdef DEBUG + DBG_Trace(DBG_LEVEL7, + "** (node) Priority: 0x%x\n" "** (node) Stack" + " Size: 0x%x words\n" "** (node) System Stack" + " Size: 0x%x words\n" "** (node) Stack" + " Segment: 0x%x\n\n", + "** (node) profile count : 0x%x \n \n", + pTaskArgs->nPriority, pTaskArgs->uStackSize, + pTaskArgs->uSysStackSize, + pTaskArgs->uStackSeg, + pndbProps->uCountProfiles); +#endif + } + } + + return status; +} + +/* + * ======== GetProcProps ======== + * Purpose: + * Retrieve the processor properties. + */ +static DSP_STATUS GetProcProps(struct NODE_MGR *hNodeMgr, + struct DEV_OBJECT *hDevObject) +{ + struct CFG_DEVNODE *hDevNode; + struct CFG_HOSTRES hostRes; + DSP_STATUS status = DSP_SOK; + + status = DEV_GetDevNode(hDevObject, &hDevNode); + if (DSP_SUCCEEDED(status)) + status = CFG_GetHostResources(hDevNode, &hostRes); + + if (DSP_SUCCEEDED(status)) { + hNodeMgr->ulChnlOffset = hostRes.dwChnlOffset; + hNodeMgr->ulChnlBufSize = hostRes.dwChnlBufSize; + hNodeMgr->ulNumChnls = hostRes.dwNumChnls; + + /* + * PROC will add an API to get DSP_PROCESSORINFO. + * Fill in default values for now. + */ + /* TODO -- Instead of hard coding, take from registry */ + hNodeMgr->procFamily = 6000; + hNodeMgr->procType = 6410; + hNodeMgr->nMinPri = DSP_NODE_MIN_PRIORITY; + hNodeMgr->nMaxPri = DSP_NODE_MAX_PRIORITY; + hNodeMgr->uDSPWordSize = DSPWORDSIZE; + hNodeMgr->uDSPDataMauSize = DSPWORDSIZE; + hNodeMgr->uDSPMauSize = 1; + + } + return status; +} + + + +/* + * ======== NODE_GetUUIDProps ======== + * Purpose: + * Fetch Node UUID properties from DCD/DOF file. + */ +DSP_STATUS NODE_GetUUIDProps(DSP_HPROCESSOR hProcessor, + IN CONST struct DSP_UUID *pNodeId, + OUT struct DSP_NDBPROPS *pNodeProps) +{ + struct NODE_MGR *hNodeMgr = NULL; + struct DEV_OBJECT *hDevObject; + DSP_STATUS status = DSP_SOK; + struct DCD_NODEPROPS dcdNodeProps; + struct DSP_PROCESSORSTATE procStatus; + + DBC_Require(cRefs > 0); + DBC_Require(hProcessor != NULL); + DBC_Require(pNodeId != NULL); + + if (hProcessor == NULL || pNodeId == NULL) { + status = DSP_EHANDLE; + goto func_end; + } + status = PROC_GetState(hProcessor, &procStatus, + sizeof(struct DSP_PROCESSORSTATE)); + if (DSP_FAILED(status)) + goto func_end; + /* If processor is in error state then don't attempt + to send the message */ + if (procStatus.iState == PROC_ERROR) { + GT_1trace(NODE_debugMask, GT_5CLASS, + "NODE_GetUUIDProps: proc Status 0x%x\n", + procStatus.iState); + status = DSP_EFAIL; + goto func_end; + } + + GT_3trace(NODE_debugMask, GT_ENTER, + "NODE_GetUUIDProps: " "\thProcessor: " + "0x%x\tpNodeId: 0x%x" "\tpNodeProps: 0x%x\n", hProcessor, + pNodeId, pNodeProps); + + status = PROC_GetDevObject(hProcessor, &hDevObject); + if (DSP_SUCCEEDED(status) && hDevObject != NULL) { + status = DEV_GetNodeManager(hDevObject, &hNodeMgr); + if (hNodeMgr == NULL) { + status = DSP_EHANDLE; + goto func_end; + } + } + + /* + * Enter the critical section. This is needed because + * DCD_GetObjectDef will ultimately end up calling DBLL_open/close, + * which needs to be protected in order to not corrupt the zlib manager + * (COD). + */ + status = SYNC_EnterCS(hNodeMgr->hSync); + + if (DSP_SUCCEEDED(status)) { + dcdNodeProps.pstrCreatePhaseFxn = NULL; + dcdNodeProps.pstrExecutePhaseFxn = NULL; + dcdNodeProps.pstrDeletePhaseFxn = NULL; + dcdNodeProps.pstrIAlgName = NULL; + + status = DCD_GetObjectDef(hNodeMgr->hDcdMgr, + (struct DSP_UUID *) pNodeId, + DSP_DCDNODETYPE, + (struct DCD_GENERICOBJ *) &dcdNodeProps); + if (DSP_SUCCEEDED(status)) { + *pNodeProps = dcdNodeProps.ndbProps; + if (dcdNodeProps.pstrCreatePhaseFxn) + MEM_Free(dcdNodeProps.pstrCreatePhaseFxn); + + if (dcdNodeProps.pstrExecutePhaseFxn) + MEM_Free(dcdNodeProps.pstrExecutePhaseFxn); + + if (dcdNodeProps.pstrDeletePhaseFxn) + MEM_Free(dcdNodeProps.pstrDeletePhaseFxn); + + if (dcdNodeProps.pstrIAlgName) + MEM_Free(dcdNodeProps.pstrIAlgName); + } + /* Leave the critical section, we're done. */ + (void)SYNC_LeaveCS(hNodeMgr->hSync); + } +func_end: + return status; +} + +/* + * ======== GetRMSFxns ======== + * Purpose: + * Retrieve the RMS functions. + */ +static DSP_STATUS GetRMSFxns(struct NODE_MGR *hNodeMgr) +{ + s32 i; + struct DEV_OBJECT *hDev = hNodeMgr->hDevObject; + DSP_STATUS status = DSP_SOK; + + static char *pszFxns[NUMRMSFXNS] = { + "RMS_queryServer", /* RMSQUERYSERVER */ + "RMS_configureServer", /* RMSCONFIGURESERVER */ + "RMS_createNode", /* RMSCREATENODE */ + "RMS_executeNode", /* RMSEXECUTENODE */ + "RMS_deleteNode", /* RMSDELETENODE */ + "RMS_changeNodePriority", /* RMSCHANGENODEPRIORITY */ + "RMS_readMemory", /* RMSREADMEMORY */ + "RMS_writeMemory", /* RMSWRITEMEMORY */ + "RMS_copy", /* RMSCOPY */ + }; + + for (i = 0; i < NUMRMSFXNS; i++) { + status = DEV_GetSymbol(hDev, pszFxns[i], + &(hNodeMgr->ulFxnAddrs[i])); + if (DSP_FAILED(status)) { + if (status == COD_E_SYMBOLNOTFOUND) { + /* + * May be loaded dynamically (in the future), + * but return an error for now. + */ + GT_1trace(NODE_debugMask, GT_6CLASS, + "RMS function: %s " + "currently not loaded\n", pszFxns[i]); + } else { + GT_2trace(NODE_debugMask, GT_6CLASS, + "GetRMSFxns: Symbol not " + "found: %s\tstatus = 0x%x\n", + pszFxns[i], status); + break; + } + } + } + + return status; +} + +/* + * ======== Ovly ======== + * Purpose: + * Called during overlay.Sends command to RMS to copy a block of data. + */ +static u32 Ovly(void *pPrivRef, u32 ulDspRunAddr, u32 ulDspLoadAddr, + u32 ulNumBytes, u32 nMemSpace) +{ + struct NODE_OBJECT *hNode = (struct NODE_OBJECT *)pPrivRef; + struct NODE_MGR *hNodeMgr; + u32 ulBytes = 0; + u32 ulSize; + u32 ulTimeout; + DSP_STATUS status = DSP_SOK; + struct WMD_DEV_CONTEXT *hWmdContext; + struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD */ + + DBC_Require(MEM_IsValidHandle(hNode, NODE_SIGNATURE)); + + hNodeMgr = hNode->hNodeMgr; + + ulSize = ulNumBytes / hNodeMgr->uDSPWordSize; + ulTimeout = hNode->uTimeout; + + /* Call new MemCopy function */ + pIntfFxns = hNodeMgr->pIntfFxns; + status = DEV_GetWMDContext(hNodeMgr->hDevObject, &hWmdContext); + status = (*pIntfFxns->pfnBrdMemCopy)(hWmdContext, ulDspRunAddr, + ulDspLoadAddr, ulNumBytes, (u32) nMemSpace); + + if (DSP_SUCCEEDED(status)) + ulBytes = ulNumBytes; + + return ulBytes; +} + +/* + * ======== Write ======== + */ +static u32 Write(void *pPrivRef, u32 ulDspAddr, void *pBuf, + u32 ulNumBytes, u32 nMemSpace) +{ + struct NODE_OBJECT *hNode = (struct NODE_OBJECT *) pPrivRef; + struct NODE_MGR *hNodeMgr; + u16 memType; + u32 ulTimeout; + DSP_STATUS status = DSP_SOK; + struct WMD_DEV_CONTEXT *hWmdContext; + struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD */ + + DBC_Require(MEM_IsValidHandle(hNode, NODE_SIGNATURE)); + DBC_Require(nMemSpace & DBLL_CODE || nMemSpace & DBLL_DATA); + + hNodeMgr = hNode->hNodeMgr; + + ulTimeout = hNode->uTimeout; + memType = (nMemSpace & DBLL_CODE) ? RMS_CODE : RMS_DATA; + + /* Call new MemWrite function */ + pIntfFxns = hNodeMgr->pIntfFxns; + status = DEV_GetWMDContext(hNodeMgr->hDevObject, &hWmdContext); + status = (*pIntfFxns->pfnBrdMemWrite) (hWmdContext, pBuf, ulDspAddr, + ulNumBytes, memType); + + return ulNumBytes; +} + diff --git a/drivers/dsp/bridge/rmgr/proc.c b/drivers/dsp/bridge/rmgr/proc.c new file mode 100644 index 0000000..332e01a --- /dev/null +++ b/drivers/dsp/bridge/rmgr/proc.c @@ -0,0 +1,1985 @@ +/* + * proc.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== proc.c ======== + * Description: + * Processor interface at the driver level. + * + * Public Functions: + * PROC_Attach + * PROC_Ctrl + * PROC_Detach + * PROC_EnumNodes + * PROC_GetResourceInfo + * PROC_Exit + * PROC_FlushMemory + * PROC_GetState + * PROC_GetProcessorId + * PROC_GetTrace + * PROC_Init + * PROC_Load + * PROC_Map + * PROC_NotifyClients + * PROC_RegisterNotify + * PROC_ReserveMemory + * PROC_Start + * PROC_UnMap + * PROC_UnReserveMemory + * PROC_InvalidateMemory + + *! Revision History + *! ======== ======== + *! 04-Apr-2007 sh Added PROC_InvalidateMemory API + *! 19-Apr-2004 sb Aligned DMM definitions with Symbian + *! Used MEM_FlushCache instead of OS specific API + *! Integrated Alan's code review updates + *! 08-Mar-2004 sb Added the Dynamic Memory Mapping feature + *! 08-Mar-2004 vp Added g_pszLastCoff member to PROC_OBJECT. + *! This is required for multiprocessor environment. + *! 09-Feb-2004 vp Added PROC_GetProcessorID function + *! 22-Apr-2003 vp Fixed issue with the string that stores coff file name + *! 03-Apr-2003 sb Fix DEH deregistering bug + *! 26-Mar-2003 vp Commented the call to DSP deep sleep in PROC_Start function. + *! 18-Feb-2003 vp Code review updates. + *! 18-Oct-2002 vp Ported to Linux platform. + *! 22-May-2002 sg Do IOCTL-to-PWR translation before calling PWR_SleepDSP. + *! 14-May-2002 sg Use CSL_Atoi() instead of atoi(). + *! 13-May-2002 sg Propagate PWR return codes upwards. + *! 07-May-2002 sg Added check for, and call to PWR functions in PROC_Ctrl. + *! 02-May-2002 sg Added "nap" mode: put DSP to sleep once booted. + *! 01-Apr-2002 jeh Assume word addresses in PROC_GetTrace(). + *! 29-Nov-2001 jeh Don't call DEH function if hDehMgr == NULL. + *! 05-Nov-2001 kc: Updated PROC_RegisterNotify and PROC_GetState to support + *! DEH module. + *! 09-Oct-2001 jeh Fix number of bytes calculated in PROC_GetTrace(). + *! 11-Sep-2001 jeh Delete MSG manager in PROC_Monitor() to fix memory leak. + *! 29-Aug-2001 rr: DCD_AutoRegister and IOOnLoaded moved before COD_LoadBase + *! to facilitate the external loading. + *! 14-Aug-2001 ag DCD_AutoRegister() now called before IOOnLoaded() fxn. + *! 21-Jun-2001 rr: MSG_Create is done only the first time. + *! 02-May-2001 jeh Return failure in PROC_Load if IOOnLoaded function returns + *! error other than E_NOTIMPL. + *! 03-Apr-2001 sg: Changed DSP_DCD_ENOAUTOREGISTER to DSP_EDCDNOAUTOREGISTER. + *! 13-Feb-2001 kc: DSP/BIOS Bridge name updates. + *! 05-Jan-2001 rr: PROC_LOAD MSG_Create error is checked. + *! 15-Dec-2000 rr: IoOnLoaded is checked for WSX_STATUS. We fail to load + *! if DEV_Create2 fails; ie, no non-RMS targets can be + *! loaded. + *! 12-Dec-2000 rr: PROC_Start's DEV_Create2 is checked for WSX_STATUS. + *! 28-Nov-2000 jeh Added call to IO OnLoaded function to PROC_Load(). + *! 29-Nov-2000 rr: Incorporated code review changes. + *! 03-Nov-2000 rr: Auto_Register happens after PROC_Load. + *! 06-Oct-2000 rr: Updated to ver 0.9. PROC_Start calls DEV_Create2 and + *! WMD_BRD_STOP is always followed by DEV_Destroy2. + *! 05-Sep-2000 rr: PROC_GetTrace calculates the Trace symbol for 55 in a + *! different way. + *! 10-Aug-2000 rr: PROC_NotifyClients, PROC_GetProcessorHandle Added + *! 07-Aug-2000 rr: PROC_IDLE/SYNCINIT/UNKNOWN state removed. + *! WMD fxns are checked for WSX_STATUS. + *! PROC_Attach does not alter the state of the BRD. + *! PROC_Run removed. + *! 04-Aug-2000 rr: All the functions return DSP_EHANDLE if proc handle is + *! invalid + *! 27-Jul-2000 rr: PROC_GetTrace and PROC_Load implemented. Updated to + *! ver 0.8 API. + *! 06-Jul-2000 rr: Created. + */ + +/* ------------------------------------ Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include +#include +#include +/* ----------------------------------- Mini Driver */ +#include + +/* ----------------------------------- Platform Manager */ +#include +#include +#include +#include +#include + +/* ----------------------------------- Resource Manager */ +#include +#include +#include +#include + +/* ----------------------------------- Others */ +#include +#include +#include +#include +#include + +/* ----------------------------------- This */ +#include +#include + +#ifndef RES_CLEANUP_DISABLE +#include +#endif +/* ----------------------------------- Defines, Data Structures, Typedefs */ +#define PROC_SIGNATURE 0x434F5250 /* "PROC" (in reverse). */ +#define MAXCMDLINELEN 255 +#define PROC_ENVPROCID "PROC_ID=%d" +#define MAXPROCIDLEN (8 + 5) +#define PROC_DFLT_TIMEOUT 10000 /* Time out in milliseconds */ +#define PWR_TIMEOUT 500 /* Sleep/wake timout in msec */ +#define EXTEND "_EXT_END" /* Extmem end addr in DSP binary */ + +extern char *iva_img; +/* The PROC_OBJECT structure. */ +struct PROC_OBJECT { + struct LST_ELEM link; /* Link to next PROC_OBJECT */ + u32 dwSignature; /* Used for object validation */ + struct DEV_OBJECT *hDevObject; /* Device this PROC represents */ + u32 hProcess; /* Process owning this Processor */ + struct MGR_OBJECT *hMgrObject; /* Manager Object Handle */ + u32 uAttachCount; /* Processor attach count */ + u32 uProcessor; /* Processor number */ + u32 uTimeout; /* Time out count */ + enum DSP_PROCSTATE sState; /* Processor state */ + u32 ulUnit; /* DDSP unit number */ + bool bIsAlreadyAttached; /* + * True if the Device below has + * GPP Client attached + */ + struct NTFY_OBJECT *hNtfy; /* Manages notifications */ + struct WMD_DEV_CONTEXT *hWmdContext; /* WMD Context Handle */ + struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD */ + char *g_pszLastCoff; +} ; + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask PROC_DebugMask = { NULL, NULL }; /* WCD MGR Mask */ +#endif + +static u32 cRefs; + +struct SYNC_CSOBJECT *hProcLock; /* For critical sections */ + +/* ----------------------------------- Function Prototypes */ +static DSP_STATUS PROC_Monitor(struct PROC_OBJECT *hProcessor); +static s32 GetEnvpCount(char **envp); +static char **PrependEnvp(char **newEnvp, char **envp, s32 cEnvp, s32 cNewEnvp, + char *szVar); + + +/* + * ======== PROC_Attach ======== + * Purpose: + * Prepare for communication with a particular DSP processor, and return + * a handle to the processor object. + */ +DSP_STATUS +PROC_Attach(u32 uProcessor, OPTIONAL CONST struct DSP_PROCESSORATTRIN *pAttrIn, + OUT DSP_HPROCESSOR *phProcessor) +{ + DSP_STATUS status = DSP_SOK; + struct DEV_OBJECT *hDevObject; + struct PROC_OBJECT *pProcObject = NULL; + struct MGR_OBJECT *hMgrObject = NULL; + struct DRV_OBJECT *hDrvObject = NULL; + u32 devType; + +#ifndef RES_CLEANUP_DISABLE + HANDLE hDRVObject; + u32 hProcess; + DSP_STATUS res_status = DSP_SOK; + struct PROCESS_CONTEXT *pPctxt = NULL; +#endif + + DBC_Require(cRefs > 0); + DBC_Require(phProcessor != NULL); + + GT_3trace(PROC_DebugMask, GT_ENTER, "Entered PROC_Attach, args:\n\t" + "uProcessor: 0x%x\n\tpAttrIn: 0x%x\n\tphProcessor:" + "0x%x\n", uProcessor, pAttrIn, phProcessor); + /* Get the Driver and Manager Object Handles */ + status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); + if (DSP_SUCCEEDED(status)) { + status = CFG_GetObject((u32 *)&hMgrObject, REG_MGR_OBJECT); + if (DSP_FAILED(status)) { + /* don't propogate CFG errors from this PROC function */ + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Attach: DSP_FAILED to get" + "the Manager Object.\n", status); + } + } else { + /* don't propogate CFG errors from this PROC function */ + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Attach: failed to get the" + " DriverObject, 0x%x!\n", status); + } + if (DSP_SUCCEEDED(status)) { + /* Get the Device Object */ + status = DRV_GetDevObject(uProcessor, hDrvObject, &hDevObject); + if (DSP_FAILED(status)) { + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Attach: failed to get" + " DevObject, 0x%x!\n", status); + } + } + if (DSP_SUCCEEDED(status)) { + status = DEV_GetDevType(hDevObject, &devType); + if (DSP_FAILED(status)) { + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Attach: failed to get" + " DevType, 0x%x!\n", status); + } + } + if (DSP_FAILED(status)) + goto func_end; + + /* If we made it this far, create the Proceesor object: */ + MEM_AllocObject(pProcObject, struct PROC_OBJECT, PROC_SIGNATURE); + /* Fill out the Processor Object: */ + if (pProcObject == NULL) { + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_Attach:Out of memeory \n"); + status = DSP_EFAIL; + goto func_end; + } + pProcObject->hDevObject = hDevObject; + pProcObject->hMgrObject = hMgrObject; + pProcObject->uProcessor = devType; + /* Get Caller Process and store it */ + /* Return PID instead of process handle */ + pProcObject->hProcess = current->pid; + + if (pAttrIn) + pProcObject->uTimeout = pAttrIn->uTimeout; + else + pProcObject->uTimeout = PROC_DFLT_TIMEOUT; + + status = DEV_GetIntfFxns(hDevObject, &pProcObject->pIntfFxns); + if (DSP_SUCCEEDED(status)) { + status = DEV_GetWMDContext(hDevObject, + &pProcObject->hWmdContext); + if (DSP_FAILED(status)) { + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Attach Could not" + " get the WMD Context.\n", status); + MEM_FreeObject(pProcObject); + } + } else { + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Attach Could not get" + " the DEV_ Interface fxns.\n", status); + MEM_FreeObject(pProcObject); + } + if (DSP_FAILED(status)) + goto func_end; + + /* Create the Notification Object */ + /* This is created with no event mask, no notify mask + * and no valid handle to the notification. They all get + * filled up when PROC_RegisterNotify is called */ + status = NTFY_Create(&pProcObject->hNtfy); + if (DSP_SUCCEEDED(status)) { + /* Insert the Processor Object into the DEV List. + * Return handle to this Processor Object: + * Find out if the Device is already attached to a + * Processor. If so, return AlreadyAttached status */ + LST_InitElem(&pProcObject->link); + status = DEV_InsertProcObject(pProcObject->hDevObject, + (u32)pProcObject, + &pProcObject->bIsAlreadyAttached); + if (DSP_SUCCEEDED(status)) { + if (pProcObject->bIsAlreadyAttached) { + status = DSP_SALREADYATTACHED; + GT_0trace(PROC_DebugMask, GT_1CLASS, + "PROC_Attach: Processor " + "Already Attached!\n"); + } + } else { + if (pProcObject->hNtfy) + NTFY_Delete(pProcObject->hNtfy); + + MEM_FreeObject(pProcObject); + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Attach: failed to insert " + "Proc Object into DEV, 0x%x!\n", status); + } + if (DSP_SUCCEEDED(status)) { + *phProcessor = (DSP_HPROCESSOR)pProcObject; + (void)PROC_NotifyClients(pProcObject, + DSP_PROCESSORATTACH); + GT_0trace(PROC_DebugMask, GT_1CLASS, + "PROC_Attach: Processor " + "Attach Success!\n"); + } + } else { + /* Don't leak memory if DSP_FAILED */ + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_Attach: Could not allocate " + "storage for notification \n"); + MEM_FreeObject(pProcObject); + } +func_end: +#ifndef RES_CLEANUP_DISABLE + if (DSP_FAILED(status)) + goto func_cont; + + /* Return PID instead of process handle */ + hProcess = current->pid; + + res_status = CFG_GetObject((u32 *)&hDRVObject, REG_DRV_OBJECT); + if (DSP_FAILED(res_status)) + goto func_cont; + + DRV_GetProcContext(hProcess, (struct DRV_OBJECT *)hDRVObject, + &pPctxt, NULL, 0); + if (pPctxt == NULL) { + DRV_InsertProcContext((struct DRV_OBJECT *)hDRVObject, &pPctxt); + if (pPctxt != NULL) { + DRV_ProcUpdatestate(pPctxt, PROC_RES_ALLOCATED); + DRV_ProcSetPID(pPctxt, hProcess); + } + } +func_cont: + /* Return PID instead of process handle */ + hProcess = current->pid; + + res_status = CFG_GetObject((u32 *)&hDRVObject, REG_DRV_OBJECT); + if (DSP_SUCCEEDED(res_status)) { + DRV_GetProcContext(hProcess, + (struct DRV_OBJECT *)hDRVObject, &pPctxt, + NULL, 0); + if (pPctxt != NULL) + pPctxt->hProcessor = (DSP_HPROCESSOR)*phProcessor; + + } +#endif + DBC_Ensure((status == DSP_EFAIL && *phProcessor == NULL) || + (DSP_SUCCEEDED(status) && + MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) || + (status == DSP_SALREADYATTACHED && + MEM_IsValidHandle(pProcObject, PROC_SIGNATURE))); + GT_2trace(PROC_DebugMask, GT_ENTER, "Exiting PROC_Attach, results:\n\t" + "status: 0x%x\n\thProcessor: 0x%x\n", status, *phProcessor); + + return status; +} + +static DSP_STATUS GetExecFile(struct CFG_DEVNODE *hDevNode, + struct DEV_OBJECT *hDevObject, + u32 size, char *execFile) +{ + s32 devType; + s32 len; + + DEV_GetDevType(hDevObject, (u32 *) &devType); + if (devType == DSP_UNIT) { + return CFG_GetExecFile(hDevNode, size, execFile); + } else if (devType == IVA_UNIT) { + if (iva_img) { + len = strlen(iva_img); + strncpy(execFile, iva_img, len + 1); + return DSP_SOK; + } + } + return DSP_EFILE; +} + +/* + * ======== PROC_AutoStart ======== = + * Purpose: + * A Particular device gets loaded with the default image + * if the AutoStart flag is set. + * Parameters: + * hDevObject: Handle to the Device + * Returns: + * DSP_SOK: On Successful Loading + * DSP_EFAIL General Failure + * Requires: + * hDevObject != NULL + * Ensures: + */ +DSP_STATUS PROC_AutoStart(struct CFG_DEVNODE *hDevNode, + struct DEV_OBJECT *hDevObject) +{ + DSP_STATUS status = DSP_EFAIL; + u32 dwAutoStart = 0; /* autostart flag */ + struct PROC_OBJECT *pProcObject; + struct PROC_OBJECT *hProcObject; + char szExecFile[MAXCMDLINELEN]; + char *argv[2]; + struct MGR_OBJECT *hMgrObject = NULL; + s32 devType; + + DBC_Require(cRefs > 0); + DBC_Require(hDevNode != NULL); + DBC_Require(hDevObject != NULL); + + GT_2trace(PROC_DebugMask, GT_ENTER, + "Entered PROC_AutoStart, args:\n\t" + "hDevNode: 0x%x\thDevObject: 0x%x\n", hDevNode, hDevObject); + /* Create a Dummy PROC Object */ + if (DSP_FAILED(CFG_GetObject((u32 *)&hMgrObject, + REG_MGR_OBJECT))) { + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_AutoStart: DSP_FAILED to " + "Get MGR Object\n"); + goto func_end; + } + MEM_AllocObject(pProcObject, struct PROC_OBJECT, PROC_SIGNATURE); + if (pProcObject == NULL) { + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_AutoStart: DSP_FAILED " + "to Create a dummy Processor\n"); + goto func_end; + } + GT_0trace(PROC_DebugMask, GT_1CLASS, "NTFY Created \n"); + pProcObject->hDevObject = hDevObject; + pProcObject->hMgrObject = hMgrObject; + hProcObject = pProcObject; + if (DSP_SUCCEEDED(DEV_GetIntfFxns(hDevObject, + &pProcObject->pIntfFxns))) { + if (DSP_SUCCEEDED(DEV_GetWMDContext(hDevObject, + &pProcObject->hWmdContext))) { + status = DSP_SOK; + } else { + MEM_FreeObject(hProcObject); + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_AutoStart: Failed " + "to get WMD Context \n"); + } + } else { + MEM_FreeObject(hProcObject); + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_AutoStart: Failed to " + "get IntFxns \n"); + } + if (DSP_FAILED(status)) + goto func_end; + + /* Stop the Device, put it into standby mode */ + status = PROC_Stop(hProcObject); + if (DSP_FAILED(CFG_GetAutoStart(hDevNode, &dwAutoStart)) || + !dwAutoStart) { + status = DSP_EFAIL; + /* DSP_FAILED to Get s32 Fxn or Wmd Context */ + GT_0trace(PROC_DebugMask, GT_1CLASS, "PROC_AutoStart: " + "CFG_GetAutoStart DSP_FAILED \n"); + goto func_cont; + } + /* Get the default executable for this board... */ + DEV_GetDevType(hDevObject, (u32 *)&devType); + pProcObject->uProcessor = devType; + if (DSP_SUCCEEDED(GetExecFile(hDevNode, hDevObject, + sizeof(szExecFile), szExecFile))) { + argv[0] = szExecFile; + argv[1] = NULL; + /* ...and try to load it: */ + status = PROC_Load(hProcObject, 1, (CONST char **)argv, NULL); + if (DSP_SUCCEEDED(status)) { + status = PROC_Start(hProcObject); + if (DSP_SUCCEEDED(status)) { + GT_0trace(PROC_DebugMask, GT_1CLASS, + "PROC_AutoStart: Processor started " + "running\n"); + } else { + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_AutoStart: DSP_FAILED To " + "Start \n"); + } + } else { + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_AutoStart: DSP_FAILED to Load\n"); + } + } else { + status = DSP_EFILE; + GT_0trace(PROC_DebugMask, GT_7CLASS, "PROC_AutoStart: " + "No Exec file found \n"); + } +func_cont: + MEM_FreeObject(hProcObject); +func_end: + GT_1trace(PROC_DebugMask, GT_ENTER, + "Exiting PROC_AutoStart, status:0x%x\n", status); + return status; +} + +/* + * ======== PROC_Ctrl ======== + * Purpose: + * Pass control information to the GPP device driver managing the + * DSP processor. + * + * This will be an OEM-only function, and not part of the DSP/BIOS Bridge + * application developer's API. + * Call the WMD_ICOTL Fxn with the Argument This is a Synchronous + * Operation. arg can be null. + */ +DSP_STATUS PROC_Ctrl(DSP_HPROCESSOR hProcessor, u32 dwCmd, + IN struct DSP_CBDATA *arg) +{ + DSP_STATUS status = DSP_SOK; + struct PROC_OBJECT *pProcObject = hProcessor; + u32 timeout = 0; + + DBC_Require(cRefs > 0); + GT_3trace(PROC_DebugMask, GT_ENTER, + "Entered PROC_Ctrl, args:\n\thProcessor:" + " 0x%x\n\tdwCmd: 0x%x\n\targ: 0x%x\n", hProcessor, dwCmd, arg); + + if (MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) { + /* intercept PWR deep sleep command */ + if (dwCmd == WMDIOCTL_DEEPSLEEP) { + timeout = arg->cbData; + status = PWR_SleepDSP(PWR_DEEPSLEEP, timeout); + } + /* intercept PWR emergency sleep command */ + else if (dwCmd == WMDIOCTL_EMERGENCYSLEEP) { + timeout = arg->cbData; + status = PWR_SleepDSP(PWR_EMERGENCYDEEPSLEEP, timeout); + } else if (dwCmd == PWR_DEEPSLEEP) { + /* timeout = arg->cbData; */ + status = PWR_SleepDSP(PWR_DEEPSLEEP, timeout); + } + /* intercept PWR wake commands */ + else if (dwCmd == WMDIOCTL_WAKEUP) { + timeout = arg->cbData; + status = PWR_WakeDSP(timeout); + } else if (dwCmd == PWR_WAKEUP) { + /* timeout = arg->cbData; */ + status = PWR_WakeDSP(timeout); + } else + if (DSP_SUCCEEDED + ((*pProcObject->pIntfFxns->pfnDevCntrl) + (pProcObject->hWmdContext, dwCmd, arg))) { + status = DSP_SOK; + } else { + status = DSP_EFAIL; + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_Ctrl: Failed \n"); + } + } else { + status = DSP_EHANDLE; + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_Ctrl: InValid Processor Handle \n"); + } + GT_1trace(PROC_DebugMask, GT_ENTER, "Exiting PROC_Ctrl, 0x%x\n", + status); + return status; +} + +/* + * ======== PROC_Detach ======== + * Purpose: + * Destroys the Processor Object. Removes the notification from the Dev + * List. + */ +DSP_STATUS PROC_Detach(DSP_HPROCESSOR hProcessor) +{ + DSP_STATUS status = DSP_SOK; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor; +#ifndef RES_CLEANUP_DISABLE + HANDLE hDRVObject; + u32 hProcess; + DSP_STATUS res_status = DSP_SOK; + struct PROCESS_CONTEXT *pPctxt = NULL; +#endif + DBC_Require(cRefs > 0); + GT_1trace(PROC_DebugMask, GT_ENTER, "Entered PROC_Detach, args:\n\t" + "hProcessor: 0x%x\n", hProcessor); + + if (MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) { + /* Notify the Client */ + NTFY_Notify(pProcObject->hNtfy, DSP_PROCESSORDETACH); + /* Remove the notification memory */ + if (pProcObject->hNtfy) + NTFY_Delete(pProcObject->hNtfy); + + if (pProcObject->g_pszLastCoff) { + MEM_Free(pProcObject->g_pszLastCoff); + pProcObject->g_pszLastCoff = NULL; + } + +#ifndef RES_CLEANUP_DISABLE + /* Return PID instead of process handle */ + hProcess = current->pid; + + res_status = CFG_GetObject((u32 *)&hDRVObject, REG_DRV_OBJECT); + if (DSP_SUCCEEDED(res_status)) { + DRV_GetProcContext(hProcess, + (struct DRV_OBJECT *)hDRVObject, &pPctxt, + NULL, 0); + if (pPctxt != NULL) { + DRV_ProcFreeDMMRes(pPctxt); + pPctxt->hProcessor = NULL; + } + } +#endif + + /* Remove the Proc from the DEV List */ + (void)DEV_RemoveProcObject(pProcObject->hDevObject, + (u32)pProcObject); + /* Free the Processor Object */ + MEM_FreeObject(pProcObject); + } else { + status = DSP_EHANDLE; + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_Detach: InValid Processor Handle \n"); + } + GT_1trace(PROC_DebugMask, GT_ENTER, "Exiting PROC_Detach, 0x%x\n", + status); + return status; +} + +/* + * ======== PROC_EnumNodes ======== + * Purpose: + * Enumerate and get configuration information about nodes allocated + * on a DSP processor. + */ +DSP_STATUS PROC_EnumNodes(DSP_HPROCESSOR hProcessor, OUT DSP_HNODE *aNodeTab, + IN u32 uNodeTabSize, OUT u32 *puNumNodes, + OUT u32 *puAllocated) +{ + DSP_STATUS status = DSP_EFAIL; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor; + struct NODE_MGR *hNodeMgr = NULL; + + DBC_Require(cRefs > 0); + DBC_Require(aNodeTab != NULL || uNodeTabSize == 0); + DBC_Require(puNumNodes != NULL); + DBC_Require(puAllocated != NULL); + + GT_5trace(PROC_DebugMask, GT_ENTER, "Entered PROC_EnumNodes, args:\n\t" + "hProcessor: 0x%x\n\taNodeTab: 0x%x\n\tuNodeTabSize: " + " 0x%x\n\t puNumNodes 0x%x\n\t puAllocated: 0x%x\n", + hProcessor, aNodeTab, uNodeTabSize, puNumNodes, + puAllocated); + if (MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) { + if (DSP_SUCCEEDED(DEV_GetNodeManager(pProcObject->hDevObject, + &hNodeMgr))) { + if (hNodeMgr) { + status = NODE_EnumNodes(hNodeMgr, aNodeTab, + uNodeTabSize, + puNumNodes, + puAllocated); + } + } + } else { + status = DSP_EHANDLE; + GT_0trace(PROC_DebugMask, GT_7CLASS, "PROC_EnumNodes: " + "InValid Processor Handle \n"); + } + GT_6trace(PROC_DebugMask, GT_ENTER, "Exit PROC_EnumNodes, args:\n\t" + "hProcessor: 0x%x\n\taNodeTab: 0x%x\n\tuNodeTabSize: " + " 0x%x\n\t puNumNodes 0x%x\n\t puAllocated: 0x%x\n\t " + "status: 0x%x \n", hProcessor, aNodeTab, uNodeTabSize, + puNumNodes, puAllocated, status); + + return status; +} + +/* + * ======== PROC_FlushMemory ======== + * Purpose: + * Flush cache + */ +DSP_STATUS PROC_FlushMemory(DSP_HPROCESSOR hProcessor, void *pMpuAddr, + u32 ulSize, u32 ulFlags) +{ + /* Keep STATUS here for future additions to this function */ + DSP_STATUS status = DSP_SOK; + enum DSP_FLUSHTYPE FlushMemType = PROC_WRITEBACK_INVALIDATE_MEM; + DBC_Require(cRefs > 0); + + GT_4trace(PROC_DebugMask, GT_ENTER, + "Entered PROC_FlushMemory, args:\n\t" + "hProcessor: 0x%x pMpuAddr: 0x%x ulSize 0x%x, ulFlags 0x%x\n", + hProcessor, pMpuAddr, ulSize, ulFlags); + /* Critical section */ + (void)SYNC_EnterCS(hProcLock); + MEM_FlushCache(pMpuAddr, ulSize, FlushMemType); + (void)SYNC_LeaveCS(hProcLock); + + GT_1trace(PROC_DebugMask, GT_ENTER, "Leaving PROC_FlushMemory [0x%x]", + status); + return status; +} + + +/* + * ======== PROC_InvalidateMemory ======== + * Purpose: + * Invalidates the memory specified + */ +DSP_STATUS PROC_InvalidateMemory(DSP_HPROCESSOR hProcessor, void *pMpuAddr, + u32 ulSize) +{ + /* Keep STATUS here for future additions to this function */ + DSP_STATUS status = DSP_SOK; + enum DSP_FLUSHTYPE FlushMemType = PROC_INVALIDATE_MEM; + DBC_Require(cRefs > 0); + GT_3trace(PROC_DebugMask, GT_ENTER, + "Entered PROC_InvalidateMemory, args:\n\t" + "hProcessor: 0x%x pMpuAddr: 0x%x ulSize 0x%x\n", hProcessor, + pMpuAddr, ulSize); + (void)SYNC_EnterCS(hProcLock); + MEM_FlushCache(pMpuAddr, ulSize, FlushMemType); + (void)SYNC_LeaveCS(hProcLock); + + GT_1trace(PROC_DebugMask, GT_ENTER, + "Leaving PROC_InvalidateMemory [0x%x]", status); + return status; +} + +/* + * ======== PROC_GetResourceInfo ======== + * Purpose: + * Enumerate the resources currently available on a processor. + */ +DSP_STATUS PROC_GetResourceInfo(DSP_HPROCESSOR hProcessor, u32 uResourceType, + OUT struct DSP_RESOURCEINFO *pResourceInfo, + u32 uResourceInfoSize) +{ + DSP_STATUS status = DSP_EFAIL; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor; + struct NODE_MGR *hNodeMgr = NULL; + struct NLDR_OBJECT *hNldr = NULL; + struct RMM_TargetObj *rmm = NULL; + struct IO_MGR *hIOMgr = NULL; /* IO manager handle */ + + DBC_Require(cRefs > 0); + DBC_Require(pResourceInfo != NULL); + DBC_Require(uResourceInfoSize >= sizeof(struct DSP_RESOURCEINFO)); + + GT_4trace(PROC_DebugMask, GT_ENTER, "Entered PROC_GetResourceInfo,\n\t" + "hProcessor: 0x%x\n\tuResourceType: 0x%x\n\tpResourceInfo:" + " 0x%x\n\t uResourceInfoSize 0x%x\n", hProcessor, + uResourceType, pResourceInfo, uResourceInfoSize); + if (!MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) { + status = DSP_EHANDLE; + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_GetResourceInfo: InValid " + "Processor Handle \n"); + goto func_end; + } + switch (uResourceType) { + case DSP_RESOURCE_DYNDARAM: + case DSP_RESOURCE_DYNSARAM: + case DSP_RESOURCE_DYNEXTERNAL: + case DSP_RESOURCE_DYNSRAM: + if (DSP_FAILED(DEV_GetNodeManager(pProcObject->hDevObject, + &hNodeMgr))) + goto func_end; + + if (DSP_SUCCEEDED(NODE_GetNldrObj(hNodeMgr, &hNldr))) { + if (DSP_SUCCEEDED(NLDR_GetRmmManager(hNldr, &rmm))) { + DBC_Assert(rmm != NULL); + status = DSP_EVALUE; + if (RMM_stat(rmm, + (enum DSP_MEMTYPE)uResourceType, + (struct DSP_MEMSTAT *)&(pResourceInfo-> + result.memStat))) + status = DSP_SOK; + } + } + break; + case DSP_RESOURCE_PROCLOAD: + status = DEV_GetIOMgr(pProcObject->hDevObject, &hIOMgr); + status = pProcObject->pIntfFxns->pfnIOGetProcLoad(hIOMgr, + (struct DSP_PROCLOADSTAT *)&(pResourceInfo-> + result.procLoadStat)); + if (DSP_FAILED(status)) { + GT_1trace(PROC_DebugMask, GT_7CLASS, + "Error in procLoadStat function 0x%x\n", status); + } + break; + default: + status = DSP_EFAIL; + break; + } +func_end: + GT_1trace(PROC_DebugMask, GT_ENTER, "Exiting PROC_GetResourceInfo, " + "status 0x%x\n", status); + return status; +} + +/* + * ======== PROC_Exit ======== + * Purpose: + * Decrement reference count, and free resources when reference count is + * 0. + */ +void PROC_Exit(void) +{ + DBC_Require(cRefs > 0); + + if (hProcLock) + (void)SYNC_DeleteCS(hProcLock); + + cRefs--; + + GT_1trace(PROC_DebugMask, GT_5CLASS, + "Entered PROC_Exit, ref count:0x%x\n", cRefs); + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== PROC_GetDevObject ======== + * Purpose: + * Return the Dev Object handle for a given Processor. + * + */ +DSP_STATUS PROC_GetDevObject(DSP_HPROCESSOR hProcessor, + struct DEV_OBJECT **phDevObject) +{ + DSP_STATUS status = DSP_EFAIL; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor; + + DBC_Require(cRefs > 0); + DBC_Require(phDevObject != NULL); + + if (MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) { + *phDevObject = pProcObject->hDevObject; + status = DSP_SOK; + } else { + *phDevObject = NULL; + } + + DBC_Ensure((DSP_SUCCEEDED(status) && *phDevObject != NULL) || + (DSP_FAILED(status) && *phDevObject == NULL)); + + return status; +} + +/* + * ======== PROC_GetState ======== + * Purpose: + * Report the state of the specified DSP processor. + */ +DSP_STATUS PROC_GetState(DSP_HPROCESSOR hProcessor, + OUT struct DSP_PROCESSORSTATE *pProcStatus, + u32 uStateInfoSize) +{ + DSP_STATUS status = DSP_SOK; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor; + BRD_STATUS brdStatus; + struct DEH_MGR *hDehMgr; + + DBC_Require(cRefs > 0); + DBC_Require(pProcStatus != NULL); + DBC_Require(uStateInfoSize >= sizeof(struct DSP_PROCESSORSTATE)); + + GT_3trace(PROC_DebugMask, GT_ENTER, "Entering PROC_GetState, args:\n\t" + "pProcStatus: 0x%x\n\thProcessor: 0x%x\n\t uStateInfoSize" + " 0x%x\n", pProcStatus, hProcessor, uStateInfoSize); + if (MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) { + /* First, retrieve BRD state information */ + if (DSP_SUCCEEDED((*pProcObject->pIntfFxns->pfnBrdStatus) + (pProcObject->hWmdContext, &brdStatus))) { + switch (brdStatus) { + case BRD_STOPPED: + pProcStatus->iState = PROC_STOPPED; + break; + case BRD_DSP_HIBERNATION: + /* Fall through */ + case BRD_RUNNING: + pProcStatus->iState = PROC_RUNNING; + break; + case BRD_LOADED: + pProcStatus->iState = PROC_LOADED; + break; + case BRD_ERROR: + pProcStatus->iState = PROC_ERROR; + break; + default: + pProcStatus->iState = 0xFF; + status = DSP_EFAIL; + break; + } + } else { + status = DSP_EFAIL; + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_GetState: General Failure" + " to read the PROC Status \n"); + } + /* Next, retrieve error information, if any */ + status = DEV_GetDehMgr(pProcObject->hDevObject, &hDehMgr); + if (DSP_SUCCEEDED(status) && hDehMgr) { + status = (*pProcObject->pIntfFxns->pfnDehGetInfo) + (hDehMgr, &(pProcStatus->errInfo)); + if (DSP_FAILED(status)) { + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_GetState: Failed " + "retrieve exception info.\n"); + } + } else { + status = DSP_EFAIL; + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_GetState: Failed to " + "retrieve DEH handle.\n"); + } + } else { + status = DSP_EHANDLE; + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_GetState:InValid Processor Handle \n"); + } + GT_2trace(PROC_DebugMask, GT_ENTER, + "Exiting PROC_GetState, results:\n\t" + "status: 0x%x\n\tpProcStatus: 0x%x\n", status, + pProcStatus->iState); + return status; +} + +/* + * ======== PROC_GetTrace ======== + * Purpose: + * Retrieve the current contents of the trace buffer, located on the + * Processor. Predefined symbols for the trace buffer must have been + * configured into the DSP executable. + * Details: + * We support using the symbols SYS_PUTCBEG and SYS_PUTCEND to define a + * trace buffer, only. Treat it as an undocumented feature. + * This call is destructive, meaning the processor is placed in the monitor + * state as a result of this function. + */ +DSP_STATUS PROC_GetTrace(DSP_HPROCESSOR hProcessor, u8 *pBuf, u32 uMaxSize) +{ + DSP_STATUS status; + status = DSP_ENOTIMPL; + return status; +} + +/* + * ======== PROC_Init ======== + * Purpose: + * Initialize PROC's private state, keeping a reference count on each call + */ +bool PROC_Init(void) +{ + bool fRetval = true; + + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { + /* Set the Trace mask */ + DBC_Assert(!PROC_DebugMask.flags); + GT_create(&PROC_DebugMask, "PR"); /* "PR" for Processor */ + + (void)SYNC_InitializeCS(&hProcLock); + } + + if (fRetval) + cRefs++; + + GT_1trace(PROC_DebugMask, GT_5CLASS, + "Entered PROC_Init, ref count:0x%x\n", cRefs); + DBC_Ensure((fRetval && (cRefs > 0)) || (!fRetval && (cRefs >= 0))); + + return fRetval; +} + +/* + * ======== PROC_Load ======== + * Purpose: + * Reset a processor and load a new base program image. + * This will be an OEM-only function, and not part of the DSP/BIOS Bridge + * application developer's API. + */ +DSP_STATUS PROC_Load(DSP_HPROCESSOR hProcessor, IN CONST s32 iArgc, + IN CONST char **aArgv, IN CONST char **aEnvp) +{ + DSP_STATUS status = DSP_SOK; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor; + struct IO_MGR *hIOMgr; /* IO manager handle */ + struct MSG_MGR *hMsgMgr; + struct COD_MANAGER *hCodMgr; /* Code manager handle */ + char *pargv0; /* temp argv[0] ptr */ + char **newEnvp; /* Updated envp[] array. */ + char szProcID[MAXPROCIDLEN]; /* Size of "PROC_ID=" */ + s32 cEnvp; /* Num elements in envp[]. */ + s32 cNewEnvp; /* " " in newEnvp[] */ + s32 nProcID = 0; /* Anticipate MP version. */ + struct DCD_MANAGER *hDCDHandle; + struct DMM_OBJECT *hDmmMgr; + u32 dwExtEnd; + u32 uProcId; +#ifdef DEBUG + BRD_STATUS uBrdState; +#endif +#ifdef OPT_LOAD_TIME_INSTRUMENTATION + struct timeval tv1; + struct timeval tv2; +#endif + DBC_Require(cRefs > 0); + DBC_Require(iArgc > 0); + DBC_Require(aArgv != NULL); +#ifdef OPT_LOAD_TIME_INSTRUMENTATION + do_gettimeofday(&tv1); +#endif +#if defined(CONFIG_BRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ) + struct dspbridge_platform_data *pdata = + omap_dspbridge_dev->dev.platform_data; +#endif + GT_2trace(PROC_DebugMask, GT_ENTER, "Entered PROC_Load, args:\n\t" + "hProcessor: 0x%x\taArgv: 0x%x\n", hProcessor, aArgv[0]); + /* Call the WMD_BRD_Load Fxn */ + if (!MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) { + status = DSP_EHANDLE; + GT_0trace(PROC_DebugMask, GT_1CLASS, + "PROC_Load: Invalid Processor Handle..\n"); + goto func_end; + } + if (pProcObject->bIsAlreadyAttached) { + status = DSP_EATTACHED; + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Load Abort becuase a GPP " + "Client is already attached status 0x%x \n", status); + goto func_end; + } + if (DSP_FAILED(DEV_GetCodMgr(pProcObject->hDevObject, &hCodMgr))) { + status = DSP_EFAIL; + GT_1trace(PROC_DebugMask, GT_7CLASS, "PROC_Load: DSP_FAILED in " + "DEV_GetCodMgr status 0x%x \n", status); + goto func_end; + } + status = PROC_Stop(hProcessor); + if (DSP_FAILED(status)) { + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Load: DSP_FAILED to Place the" + " Processor in Stop Mode(PROC_STOP) status 0x%x \n", + status); + goto func_end; + } + /* Place the board in the monitor state. */ + status = PROC_Monitor(hProcessor); + if (DSP_FAILED(status)) { + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Load: DSP_FAILED to Place the" + " Processor in Monitor Mode(PROC_IDLE) status 0x%x\n", + status); + goto func_end; + } + /* Save ptr to original argv[0]. */ + pargv0 = (char *)aArgv[0]; + /*Prepend "PROC_ID="to envp array for target.*/ + cEnvp = GetEnvpCount((char **)aEnvp); + cNewEnvp = (cEnvp ? (cEnvp + 1) : (cEnvp + 2)); + newEnvp = MEM_Calloc(cNewEnvp * sizeof(char **), MEM_PAGED); + if (newEnvp) { + status = snprintf(szProcID, MAXPROCIDLEN, PROC_ENVPROCID, + nProcID); + if (status == -1) { + GT_0trace(PROC_DebugMask, GT_7CLASS, "PROC_Load: " + "Proc ID string overflow \n"); + status = DSP_EFAIL; + } else { + newEnvp = PrependEnvp(newEnvp, (char **)aEnvp, cEnvp, + cNewEnvp, szProcID); + /* Get the DCD Handle */ + status = MGR_GetDCDHandle(pProcObject->hMgrObject, + (u32 *)&hDCDHandle); + if (DSP_SUCCEEDED(status)) { + /* Before proceeding with new load, + * check if a previously registered COFF + * exists. + * If yes, unregister nodes in previously + * registered COFF. If any error occurred, + * set previously registered COFF to NULL. */ + if (pProcObject->g_pszLastCoff != NULL) { + status = DCD_AutoUnregister(hDCDHandle, + pProcObject->g_pszLastCoff); + /* Regardless of auto unregister status, + * free previously allocated + * memory. */ + MEM_Free(pProcObject->g_pszLastCoff); + pProcObject->g_pszLastCoff = NULL; + } + } + /* On success, do COD_OpenBase() */ + status = COD_OpenBase(hCodMgr, (char *)aArgv[0], + COD_SYMB); + if (DSP_FAILED(status)) { + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Load: COD_OpenBase " + "failed (0x%x)\n", status); + } + } + } else { + GT_0trace(PROC_DebugMask, GT_7CLASS, + " PROC_Load:Out of Memory \n"); + status = DSP_EMEMORY; + } + if (DSP_SUCCEEDED(status)) { + /* Auto-register data base */ + /* Get the DCD Handle */ + status = MGR_GetDCDHandle(pProcObject->hMgrObject, + (u32 *)&hDCDHandle); + if (DSP_SUCCEEDED(status)) { + /* Auto register nodes in specified COFF + * file. If registration did not fail, + * (status = DSP_SOK or DSP_EDCDNOAUTOREGISTER) + * save the name of the COFF file for + * de-registration in the future. */ + status = DCD_AutoRegister(hDCDHandle, (char *)aArgv[0]); + if (status == DSP_EDCDNOAUTOREGISTER) { + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_Load: No Auto " + "Register section. Proceeding..\n"); + status = DSP_SOK; + } + if (DSP_FAILED(status)) { + status = DSP_EFAIL; + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_Load: Failed to " + "Auto Register..\n"); + } else { + DBC_Assert(pProcObject->g_pszLastCoff == NULL); + /* Allocate memory for pszLastCoff */ + pProcObject->g_pszLastCoff = MEM_Calloc( + (strlen((char *)aArgv[0]) + 1), + MEM_PAGED); + /* If memory allocated, save COFF file name*/ + if (pProcObject->g_pszLastCoff) { + strncpy(pProcObject->g_pszLastCoff, + (char *)aArgv[0], + (strlen((char *)aArgv[0]) + 1)); + } + } + } + } + /* Update shared memory address and size */ + if (DSP_SUCCEEDED(status)) { + /* Create the message manager. This must be done + * before calling the IOOnLoaded function. */ + DEV_GetMsgMgr(pProcObject->hDevObject, &hMsgMgr); + if (!hMsgMgr) { + status = MSG_Create(&hMsgMgr, pProcObject->hDevObject, + (MSG_ONEXIT)NODE_OnExit); + DBC_Assert(DSP_SUCCEEDED(status)); + DEV_SetMsgMgr(pProcObject->hDevObject, hMsgMgr); + } + if (status == DSP_ENOTIMPL) { + /* It's OK not to have a message manager */ + status = DSP_SOK; + } + } + if (DSP_SUCCEEDED(status)) { + /* Set the Device object's message manager */ + status = DEV_GetIOMgr(pProcObject->hDevObject, &hIOMgr); + DBC_Assert(DSP_SUCCEEDED(status)); + status = (*pProcObject->pIntfFxns->pfnIOOnLoaded)(hIOMgr); + if (status == DSP_ENOTIMPL) { + /* Ok not to implement this function */ + status = DSP_SOK; + } else { + if (DSP_FAILED(status)) { + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Load: Failed to get shared " + "memory or message buffer address " + "from COFF status 0x%x\n", status); + status = DSP_EFAIL; + } + } + } else { + status = DSP_EFAIL; + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Load: DSP_FAILED in " + "MSG_Create status 0x%x\n", status); + } + if (DSP_SUCCEEDED(status)) { + /* Now, attempt to load an exec: */ + + /* Boost the OPP level to Maximum level supported by baseport*/ +#if defined(CONFIG_BRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ) + if (pdata->cpu_set_freq) + (*pdata->cpu_set_freq)(pdata->mpu_speed[VDD1_OPP5]); +#endif + status = COD_LoadBase(hCodMgr, iArgc, (char **)aArgv, + DEV_BrdWriteFxn, + pProcObject->hDevObject, NULL); + if (DSP_FAILED(status)) { + if (status == COD_E_OPENFAILED) { + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_Load:Failure to Load the EXE\n"); + } + if (status == COD_E_SYMBOLNOTFOUND) { + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_Load:Could not parse the file\n"); + } else { + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Load: DSP_FAILED in " + "COD_Load status 0x%x \n", status); + } + } + /* Requesting the lowest opp supported*/ +#if defined(CONFIG_BRIDGE_DVFS) && !defined(CONFIG_CPU_FREQ) + if (pdata->cpu_set_freq) + (*pdata->cpu_set_freq)(pdata->mpu_speed[VDD1_OPP1]); +#endif + + } + if (DSP_SUCCEEDED(status)) { + /* Update the Processor status to loaded */ + status = (*pProcObject->pIntfFxns->pfnBrdSetState) + (pProcObject->hWmdContext, BRD_LOADED); + if (DSP_SUCCEEDED(status)) { + pProcObject->sState = PROC_LOADED; + if (pProcObject->hNtfy) { + PROC_NotifyClients(pProcObject, + DSP_PROCESSORSTATECHANGE); + } + } else { + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Load, pfnBrdSetState " + "failed: 0x%x\n", status); + status = DSP_EFAIL; + } + } + if (DSP_SUCCEEDED(status)) { + status = PROC_GetProcessorId(hProcessor, &uProcId); + if (uProcId == DSP_UNIT) { + /* Use all available DSP address space after EXTMEM + * for DMM */ + if (DSP_SUCCEEDED(status)) { + status = COD_GetSymValue(hCodMgr, EXTEND, + &dwExtEnd); + if (DSP_FAILED(status)) { + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Load: Failed on " + "COD_GetSymValue %s.\n", + EXTEND); + } + } + /* Reset DMM structs and add an initial free chunk*/ + if (DSP_SUCCEEDED(status)) { + status = DEV_GetDmmMgr(pProcObject->hDevObject, + &hDmmMgr); + if (DSP_SUCCEEDED(status)) { + /* Set dwExtEnd to DMM START u8 + * address */ + dwExtEnd = (dwExtEnd + 1) * DSPWORDSIZE; + /* DMM memory is from EXT_END */ + status = DMM_CreateTables(hDmmMgr, + dwExtEnd, DMMPOOLSIZE); + } + } + } + } + /* Restore the original argv[0] */ + MEM_Free(newEnvp); + aArgv[0] = pargv0; +#ifdef DEBUG + if (DSP_SUCCEEDED(status)) { + if (DSP_SUCCEEDED((*pProcObject->pIntfFxns->pfnBrdStatus) + (pProcObject->hWmdContext, &uBrdState))) { + GT_0trace(PROC_DebugMask, GT_1CLASS, + "PROC_Load: Processor Loaded\n"); + DBC_Assert(uBrdState == BRD_LOADED); + } + } +#endif +func_end: +#ifdef DEBUG + if (DSP_FAILED(status)) { + GT_0trace(PROC_DebugMask, GT_1CLASS, "PROC_Load: " + "Processor Load Failed.\n"); + + } +#endif + GT_1trace(PROC_DebugMask, GT_ENTER, + "Exiting PROC_Load, status: 0x%x\n", status); + DBC_Ensure((DSP_SUCCEEDED(status) && pProcObject->sState == PROC_LOADED) + || DSP_FAILED(status)); +#ifdef OPT_LOAD_TIME_INSTRUMENTATION + do_gettimeofday(&tv2); + if (tv2.tv_usec < tv1.tv_usec) { + tv2.tv_usec += 1000000; + tv2.tv_sec--; + } + GT_2trace(PROC_DebugMask, GT_1CLASS, + "Proc_Load: time to load %d sec and %d usec \n", + tv2.tv_sec - tv1.tv_sec, tv2.tv_usec - tv1.tv_usec); +#endif + return status; +} + +/* + * ======== PROC_Map ======== + * Purpose: + * Maps a MPU buffer to DSP address space. + */ +DSP_STATUS PROC_Map(DSP_HPROCESSOR hProcessor, void *pMpuAddr, u32 ulSize, + void *pReqAddr, void **ppMapAddr, u32 ulMapAttr) +{ + u32 vaAlign; + u32 paAlign; + struct DMM_OBJECT *hDmmMgr; + u32 sizeAlign; + DSP_STATUS status = DSP_SOK; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor; + +#ifndef RES_CLEANUP_DISABLE + u32 hProcess; + HANDLE pCtxt = NULL; + HANDLE hDrvObject; + HANDLE dmmRes; + DSP_STATUS res_status = DSP_SOK; +#endif + + GT_6trace(PROC_DebugMask, GT_ENTER, "Entered PROC_Map, args:\n\t" + "hProcessor %x, pMpuAddr %x, ulSize %x, pReqAddr %x, " + "ulMapAttr %x, ppMapAddr %x\n", hProcessor, pMpuAddr, ulSize, + pReqAddr, ulMapAttr, ppMapAddr); + /* Calculate the page-aligned PA, VA and size */ + vaAlign = PG_ALIGN_LOW((u32) pReqAddr, PG_SIZE_4K); + paAlign = PG_ALIGN_LOW((u32) pMpuAddr, PG_SIZE_4K); + sizeAlign = PG_ALIGN_HIGH(ulSize + (u32)pMpuAddr - paAlign, + PG_SIZE_4K); + + GT_3trace(PROC_DebugMask, GT_ENTER, "PROC_Map: vaAlign %x, paAlign %x, " + "sizeAlign %x\n", vaAlign, paAlign, sizeAlign); + + /* Critical section */ + (void)SYNC_EnterCS(hProcLock); + status = DMM_GetHandle(pProcObject, &hDmmMgr); + if (DSP_FAILED(status)) { + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_Map: Failed to get DMM Mgr " + "handle: 0x%x\n", status); + } else { + status = DMM_MapMemory(hDmmMgr, vaAlign, sizeAlign); + } + /* Add mapping to the page tables. */ + if (DSP_SUCCEEDED(status)) { + + status = (*pProcObject->pIntfFxns->pfnBrdMemMap) + (pProcObject->hWmdContext, paAlign, vaAlign, sizeAlign, + ulMapAttr); + } + if (DSP_SUCCEEDED(status)) { + /* Mapped address = MSB of VA | LSB of PA */ + *ppMapAddr = (void *) (vaAlign | ((u32) pMpuAddr & + (PG_SIZE_4K - 1))); + } else { + DMM_UnMapMemory(hDmmMgr, vaAlign, &sizeAlign); + } + (void)SYNC_LeaveCS(hProcLock); + +#ifndef RES_CLEANUP_DISABLE + if (DSP_SUCCEEDED(status)) { + /* Update the node and stream resource status */ + /* Return PID instead of process handle */ + hProcess = current->pid; + + res_status = CFG_GetObject((u32 *)&hDrvObject, + REG_DRV_OBJECT); + if (DSP_SUCCEEDED(res_status)) { + if (DRV_GetProcContext(hProcess, + (struct DRV_OBJECT *)hDrvObject, &pCtxt, NULL, + (u32)pMpuAddr) != DSP_ENOTFOUND) { + DRV_InsertDMMResElement(&dmmRes, pCtxt); + DRV_UpdateDMMResElement(dmmRes, (u32)pMpuAddr, + ulSize, (u32)pReqAddr, + (u32)*ppMapAddr, hProcessor); + } + } + } +#endif + GT_1trace(PROC_DebugMask, GT_ENTER, "Leaving PROC_Map [0x%x]", status); + return status; +} + +/* + * ======== PROC_RegisterNotify ======== + * Purpose: + * Register to be notified of specific processor events. + */ +DSP_STATUS PROC_RegisterNotify(DSP_HPROCESSOR hProcessor, u32 uEventMask, + u32 uNotifyType, struct DSP_NOTIFICATION + *hNotification) +{ + DSP_STATUS status = DSP_SOK; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor; + struct DEH_MGR *hDehMgr; + + DBC_Require(hNotification != NULL); + DBC_Require(cRefs > 0); + + GT_4trace(PROC_DebugMask, GT_ENTER, + "Entered PROC_RegisterNotify, args:\n\t" + "hProcessor: 0x%x\n\tuEventMask: 0x%x\n\tuNotifyMask:" + " 0x%x\n\t hNotification 0x%x\n", hProcessor, uEventMask, + uNotifyType, hNotification); + + /* Check processor handle */ + if (!MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) { + status = DSP_EHANDLE; + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_RegsiterNotify Invalid " + "ProcessorHandle 0x%x\n", hProcessor); + goto func_end; + } + /* Check if event mask is a valid processor related event */ + if (uEventMask & ~(DSP_PROCESSORSTATECHANGE | DSP_PROCESSORATTACH | + DSP_PROCESSORDETACH | DSP_PROCESSORRESTART | DSP_MMUFAULT | + DSP_SYSERROR)) + status = DSP_EVALUE; + + /* Check if notify type is valid */ + if (uNotifyType != DSP_SIGNALEVENT) + status = DSP_EVALUE; + + if (DSP_SUCCEEDED(status)) { + /* * If event mask is not DSP_SYSERROR or DSP_MMUFAULT, + * then register event immediately. */ + if (uEventMask & ~(DSP_SYSERROR | DSP_MMUFAULT)) { + status = NTFY_Register(pProcObject->hNtfy, + hNotification, uEventMask, uNotifyType); + /* * Special case alert, special case alert! + * If we're trying to *deregister* (i.e. uEventMask + * is 0), a DSP_SYSERROR or DSP_MMUFAULT notification, + * we have to deregister with the DEH manager. + * There's no way to know, based on uEventMask which + * manager the notification event was registered with, + * so if we're trying to deregister and NTFY_Register + * failed, we'll give the deh manager a shot. + */ + if ((uEventMask == 0) && DSP_FAILED(status)) { + status = DEV_GetDehMgr(pProcObject->hDevObject, + &hDehMgr); + DBC_Assert(pProcObject->pIntfFxns-> + pfnDehRegisterNotify); + status = (*pProcObject->pIntfFxns-> + pfnDehRegisterNotify) + (hDehMgr, uEventMask, uNotifyType, + hNotification); + } + } else { + status = DEV_GetDehMgr(pProcObject->hDevObject, + &hDehMgr); + DBC_Assert(pProcObject->pIntfFxns-> + pfnDehRegisterNotify); + status = (*pProcObject->pIntfFxns->pfnDehRegisterNotify) + (hDehMgr, uEventMask, uNotifyType, + hNotification); + if (DSP_FAILED(status)) + status = DSP_EFAIL; + + } + } +func_end: + return status; +} + +/* + * ======== PROC_ReserveMemory ======== + * Purpose: + * Reserve a virtually contiguous region of DSP address space. + */ +DSP_STATUS PROC_ReserveMemory(DSP_HPROCESSOR hProcessor, u32 ulSize, + void **ppRsvAddr) +{ + struct DMM_OBJECT *hDmmMgr; + DSP_STATUS status = DSP_SOK; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor; + + GT_3trace(PROC_DebugMask, GT_ENTER, + "Entered PROC_ReserveMemory, args:\n\t" + "hProcessor: 0x%x ulSize: 0x%x ppRsvAddr: 0x%x\n", hProcessor, + ulSize, ppRsvAddr); + status = DMM_GetHandle(pProcObject, &hDmmMgr); + if (DSP_FAILED(status)) { + GT_1trace(PROC_DebugMask, GT_7CLASS, "PROC_ReserveMemory: " + "Failed to get DMM Mgr handle: 0x%x\n", status); + } else + status = DMM_ReserveMemory(hDmmMgr, ulSize, (u32 *)ppRsvAddr); + + GT_1trace(PROC_DebugMask, GT_ENTER, "Leaving PROC_ReserveMemory [0x%x]", + status); + return status; +} + +/* + * ======== PROC_Start ======== + * Purpose: + * Start a processor running. + */ +DSP_STATUS PROC_Start(DSP_HPROCESSOR hProcessor) +{ + DSP_STATUS status = DSP_SOK; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor; + struct COD_MANAGER *hCodMgr; /* Code manager handle */ + u32 dwDspAddr; /* Loaded code's entry point. */ +#ifdef DEBUG + BRD_STATUS uBrdState; +#endif + DBC_Require(cRefs > 0); + GT_1trace(PROC_DebugMask, GT_ENTER, "Entered PROC_Start, args:\n\t" + "hProcessor: 0x%x\n", hProcessor); + if (!MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) { + status = DSP_EHANDLE; + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_Start :InValid Handle \n"); + goto func_end; + } + /* Call the WMD_BRD_Start */ + if (pProcObject->sState != PROC_LOADED) { + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_Start :Wrong state \n"); + status = DSP_EWRONGSTATE; + goto func_end; + } + status = DEV_GetCodMgr(pProcObject->hDevObject, &hCodMgr); + if (DSP_FAILED(status)) { + status = DSP_EFAIL; + GT_1trace(PROC_DebugMask, GT_7CLASS, + "Processor Start DSP_FAILED " + "in Getting DEV_GetCodMgr status 0x%x\n", status); + goto func_cont; + } + status = COD_GetEntry(hCodMgr, &dwDspAddr); + if (DSP_FAILED(status)) { + status = DSP_EFAIL; + GT_1trace(PROC_DebugMask, GT_7CLASS, + "Processor Start DSP_FAILED in " + "Getting COD_GetEntry status 0x%x\n", status); + goto func_cont; + } + status = (*pProcObject->pIntfFxns->pfnBrdStart) + (pProcObject->hWmdContext, dwDspAddr); + if (DSP_FAILED(status)) { + status = DSP_EFAIL; + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_Start Failed to Start the board\n"); + goto func_cont; + } + /* Call DEV_Create2 */ + status = DEV_Create2(pProcObject->hDevObject); + if (DSP_SUCCEEDED(status)) { + pProcObject->sState = PROC_RUNNING; + /* Deep sleep switces off the peripheral clocks. + * we just put the DSP CPU in idle in the idle loop. + * so there is no need to send a command to DSP */ + + if (pProcObject->hNtfy) { + PROC_NotifyClients(pProcObject, + DSP_PROCESSORSTATECHANGE); + } + GT_0trace(PROC_DebugMask, GT_1CLASS, "PROC_Start: Processor " + "Started and running \n"); + } else { + /* Failed to Create Node Manager and DISP Object + * Stop the Processor from running. Put it in STOPPED State */ + (void)(*pProcObject->pIntfFxns->pfnBrdStop)(pProcObject-> + hWmdContext); + status = DSP_EFAIL; + pProcObject->sState = PROC_STOPPED; + GT_0trace(PROC_DebugMask, GT_7CLASS, "PROC_Start " + "Failed to Create the Node Manager\n"); + } +func_cont: +#ifdef DEBUG + if (DSP_SUCCEEDED(status)) { + if (DSP_SUCCEEDED((*pProcObject->pIntfFxns->pfnBrdStatus) + (pProcObject->hWmdContext, &uBrdState))) { + GT_0trace(PROC_DebugMask, GT_1CLASS, + "PROC_Start: Processor State is RUNNING \n"); + DBC_Assert(uBrdState != BRD_HIBERNATION); + } + } +#endif +func_end: + GT_1trace(PROC_DebugMask, GT_ENTER, + "Exiting PROC_Start, status 0x%x\n", status); + DBC_Ensure((DSP_SUCCEEDED(status) && pProcObject->sState == + PROC_RUNNING) || DSP_FAILED(status)); + return status; +} + +/* + * ======== PROC_Stop ======== + * Purpose: + * Stop a processor running. + */ +DSP_STATUS PROC_Stop(DSP_HPROCESSOR hProcessor) +{ + DSP_STATUS status = DSP_SOK; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor; + struct MSG_MGR *hMsgMgr; + struct NODE_MGR *hNodeMgr; + DSP_HNODE hNode; + u32 uNodeTabSize = 1; + u32 uNumNodes = 0; + u32 uNodesAllocated = 0; +#ifdef DEBUG + BRD_STATUS uBrdState; +#endif + DBC_Require(cRefs > 0); + GT_1trace(PROC_DebugMask, GT_ENTER, "Entered PROC_Stop, args:\n\t" + "hProcessor: 0x%x\n", hProcessor); + if (!MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)) { + status = DSP_EHANDLE; + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_Stop :InValid Handle \n"); + goto func_end; + } + /* check if there are any running nodes */ + status = DEV_GetNodeManager(pProcObject->hDevObject, &hNodeMgr); + if (DSP_SUCCEEDED(status) && hNodeMgr) { + status = NODE_EnumNodes(hNodeMgr, &hNode, uNodeTabSize, + &uNumNodes, &uNodesAllocated); + if ((status == DSP_ESIZE) || (uNodesAllocated > 0)) { + GT_1trace(PROC_DebugMask, GT_7CLASS, + "Can't stop device, Active " + "nodes = 0x%x \n", uNodesAllocated); + return DSP_EWRONGSTATE; + } + } + /* Call the WMD_BRD_Stop */ + /* It is OK to stop a device that does n't have nodes OR not started */ + status = (*pProcObject->pIntfFxns->pfnBrdStop)(pProcObject-> + hWmdContext); + if (DSP_SUCCEEDED(status)) { + GT_0trace(PROC_DebugMask, GT_1CLASS, + "PROC_Stop: Processor Stopped, " + "i.e in standby mode \n"); + pProcObject->sState = PROC_STOPPED; + /* Destory the Node Manager, MSG Manager */ + if (DSP_SUCCEEDED(DEV_Destroy2(pProcObject->hDevObject))) { + /* Destroy the MSG by calling MSG_Delete */ + DEV_GetMsgMgr(pProcObject->hDevObject, &hMsgMgr); + if (hMsgMgr) { + MSG_Delete(hMsgMgr); + DEV_SetMsgMgr(pProcObject->hDevObject, NULL); + } +#ifdef DEBUG + if (DSP_SUCCEEDED((*pProcObject->pIntfFxns-> + pfnBrdStatus)(pProcObject->hWmdContext, + &uBrdState))) { + GT_0trace(PROC_DebugMask, GT_1CLASS, + "PROC_Monitor:Processor Stopped \n"); + DBC_Assert(uBrdState == BRD_STOPPED); + } +#endif + } else { + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_Stop Couldn't delete node manager \n"); + } + } else { + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_Stop Failed to Stop the processor/device \n"); + } +func_end: + GT_1trace(PROC_DebugMask, GT_ENTER, "Exiting PROC_Stop, status 0x%x\n", + status); + + return status; +} + +/* + * ======== PROC_UnMap ======== + * Purpose: + * Removes a MPU buffer mapping from the DSP address space. + */ +DSP_STATUS PROC_UnMap(DSP_HPROCESSOR hProcessor, void *pMapAddr) +{ + DSP_STATUS status = DSP_SOK; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor; + struct DMM_OBJECT *hDmmMgr; + u32 vaAlign; + u32 sizeAlign; +#ifndef RES_CLEANUP_DISABLE + u32 hProcess; + HANDLE pCtxt = NULL; + HANDLE hDrvObject; + HANDLE dmmRes; + DSP_STATUS res_status = DSP_SOK; +#endif + GT_2trace(PROC_DebugMask, GT_ENTER, + "Entered PROC_UnMap, args:\n\thProcessor:" + "0x%x pMapAddr: 0x%x\n", hProcessor, pMapAddr); + + vaAlign = PG_ALIGN_LOW((u32) pMapAddr, PG_SIZE_4K); + + status = DMM_GetHandle(hProcessor, &hDmmMgr); + /* Critical section */ + (void)SYNC_EnterCS(hProcLock); + if (DSP_FAILED(status)) { + GT_1trace(PROC_DebugMask, GT_7CLASS, "PROC_UnMap: " + "Failed to get DMM Mgr handle: 0x%x\n", status); + } else { + /* Update DMM structures. Get the size to unmap. + This function returns error if the VA is not mapped */ + status = DMM_UnMapMemory(hDmmMgr, (u32) vaAlign, &sizeAlign); + } + /* Remove mapping from the page tables. */ + if (DSP_SUCCEEDED(status)) { + status = (*pProcObject->pIntfFxns->pfnBrdMemUnMap) + (pProcObject->hWmdContext, vaAlign, sizeAlign); + } + (void)SYNC_LeaveCS(hProcLock); +#ifndef RES_CLEANUP_DISABLE + GT_1trace(PROC_DebugMask, GT_ENTER, + "PROC_UnMap DRV_GetDMMResElement " + "pMapAddr:[0x%x]", pMapAddr); + if (DSP_FAILED(status)) + goto func_end; + + /* Update the node and stream resource status */ + /* Return PID instead of process handle */ + hProcess = current->pid; + + res_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); + if (DSP_FAILED(res_status)) + goto func_end; + + DRV_GetProcContext(hProcess, (struct DRV_OBJECT *)hDrvObject, + &pCtxt, NULL, (u32)pMapAddr); + if (pCtxt != NULL) { + if (DRV_GetDMMResElement((u32)pMapAddr, &dmmRes, pCtxt) != + DSP_ENOTFOUND) + DRV_RemoveDMMResElement(dmmRes, pCtxt); + } +func_end: +#endif + GT_1trace(PROC_DebugMask, GT_ENTER, + "Leaving PROC_UnMap [0x%x]", status); + return status; +} + +/* + * ======== PROC_UnReserveMemory ======== + * Purpose: + * Frees a previously reserved region of DSP address space. + */ +DSP_STATUS PROC_UnReserveMemory(DSP_HPROCESSOR hProcessor, void *pRsvAddr) +{ + struct DMM_OBJECT *hDmmMgr; + DSP_STATUS status = DSP_SOK; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcessor; + + GT_2trace(PROC_DebugMask, GT_ENTER, + "Entered PROC_UnReserveMemory, args:\n\t" + "hProcessor: 0x%x pRsvAddr: 0x%x\n", hProcessor, pRsvAddr); + + status = DMM_GetHandle(pProcObject, &hDmmMgr); + if (DSP_FAILED(status)) + GT_1trace(PROC_DebugMask, GT_7CLASS, + "PROC_UnReserveMemory: Failed to get DMM Mgr " + "handle: 0x%x\n", status); + else + status = DMM_UnReserveMemory(hDmmMgr, (u32) pRsvAddr); + + GT_1trace(PROC_DebugMask, GT_ENTER, + "Leaving PROC_UnReserveMemory [0x%x]", + status); + + return status; +} + +/* + * ======== = PROC_Monitor ======== == + * Purpose: + * Place the Processor in Monitor State. This is an internal + * function and a requirement before Processor is loaded. + * This does a WMD_BRD_Stop, DEV_Destroy2 and WMD_BRD_Monitor. + * In DEV_Destroy2 we delete the node manager. + * Parameters: + * hProcObject: Handle to Processor Object + * Returns: + * DSP_SOK: Processor placed in monitor mode. + * !DSP_SOK: Failed to place processor in monitor mode. + * Requires: + * Valid Processor Handle + * Ensures: + * Success: ProcObject state is PROC_IDLE + */ +static DSP_STATUS PROC_Monitor(struct PROC_OBJECT *hProcObject) +{ + DSP_STATUS status = DSP_EFAIL; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProcObject; + struct MSG_MGR *hMsgMgr; +#ifdef DEBUG + BRD_STATUS uBrdState; +#endif + + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)); + + GT_1trace(PROC_DebugMask, GT_ENTER, "Entered PROC_Monitor, args:\n\t" + "hProcessor: 0x%x\n", hProcObject); + /* This is needed only when Device is loaded when it is + * already 'ACTIVE' */ + /* Destory the Node Manager, MSG Manager */ + if (DSP_SUCCEEDED(DEV_Destroy2(pProcObject->hDevObject))) { + /* Destroy the MSG by calling MSG_Delete */ + DEV_GetMsgMgr(pProcObject->hDevObject, &hMsgMgr); + if (hMsgMgr) { + MSG_Delete(hMsgMgr); + DEV_SetMsgMgr(pProcObject->hDevObject, NULL); + } + } + /* Place the Board in the Monitor State */ + if (DSP_SUCCEEDED((*pProcObject->pIntfFxns->pfnBrdMonitor) + (pProcObject->hWmdContext))) { + status = DSP_SOK; +#ifdef DEBUG + if (DSP_SUCCEEDED((*pProcObject->pIntfFxns->pfnBrdStatus) + (pProcObject->hWmdContext, &uBrdState))) { + GT_0trace(PROC_DebugMask, GT_1CLASS, + "PROC_Monitor:Processor in " + "Monitor State\n"); + DBC_Assert(uBrdState == BRD_IDLE); + } +#endif + } else { + /* Monitor Failure */ + GT_0trace(PROC_DebugMask, GT_7CLASS, + "PROC_Monitor: Processor Could not" + "be put in Monitor mode \n"); + } + GT_1trace(PROC_DebugMask, GT_ENTER, + "Exiting PROC_Monitor, status 0x%x\n", + status); +#ifdef DEBUG + DBC_Ensure((DSP_SUCCEEDED(status) && uBrdState == BRD_IDLE) || + DSP_FAILED(status)); +#endif + return status; +} + +/* + * ======== GetEnvpCount ======== + * Purpose: + * Return the number of elements in the envp array, including the + * terminating NULL element. + */ +static s32 GetEnvpCount(char **envp) +{ + s32 cRetval = 0; + if (envp) { + while (*envp++) + cRetval++; + + cRetval += 1; /* Include the terminating NULL in the count. */ + } + + return cRetval; +} + +/* + * ======== PrependEnvp ======== + * Purpose: + * Prepend an environment variable=value pair to the new envp array, and + * copy in the existing var=value pairs in the old envp array. + */ +static char **PrependEnvp(char **newEnvp, char **envp, s32 cEnvp, s32 cNewEnvp, + char *szVar) +{ + char **ppEnvp = newEnvp; + + DBC_Require(newEnvp); + + /* Prepend new environ var=value string */ + *newEnvp++ = szVar; + + /* Copy user's environment into our own. */ + while (cEnvp--) + *newEnvp++ = *envp++; + + /* Ensure NULL terminates the new environment strings array. */ + if (cEnvp == 0) + *newEnvp = NULL; + + return ppEnvp; +} + +/* + * ======== PROC_NotifyClients ======== + * Purpose: + * Notify the processor the events. + */ +DSP_STATUS PROC_NotifyClients(DSP_HPROCESSOR hProc, u32 uEvents) +{ + DSP_STATUS status = DSP_SOK; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProc; + + DBC_Require(MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)); + DBC_Require(IsValidProcEvent(uEvents)); + DBC_Require(cRefs > 0); + + NTFY_Notify(pProcObject->hNtfy, uEvents); + GT_0trace(PROC_DebugMask, GT_1CLASS, + "PROC_NotifyClients :Signaled. \n"); + + return status; +} + +/* + * ======== PROC_NotifyAllClients ======== + * Purpose: + * Notify the processor the events. This includes notifying all clients + * attached to a particulat DSP. + */ +DSP_STATUS PROC_NotifyAllClients(DSP_HPROCESSOR hProc, u32 uEvents) +{ + DSP_STATUS status = DSP_SOK; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProc; + + DBC_Require(MEM_IsValidHandle(pProcObject, PROC_SIGNATURE)); + DBC_Require(IsValidProcEvent(uEvents)); + DBC_Require(cRefs > 0); + + DEV_NotifyClients(pProcObject->hDevObject, uEvents); + + GT_0trace(PROC_DebugMask, GT_1CLASS, + "PROC_NotifyAllClients :Signaled. \n"); + + return status; +} + +/* + * ======== PROC_GetProcessorId ======== + * Purpose: + * Retrieves the processor ID. + */ +DSP_STATUS PROC_GetProcessorId(DSP_HPROCESSOR hProc, u32 *procID) +{ + DSP_STATUS status = DSP_SOK; + struct PROC_OBJECT *pProcObject = (struct PROC_OBJECT *)hProc; + + *procID = pProcObject->uProcessor; + + return status; +} + diff --git a/drivers/dsp/bridge/rmgr/pwr.c b/drivers/dsp/bridge/rmgr/pwr.c new file mode 100644 index 0000000..50a3f79 --- /dev/null +++ b/drivers/dsp/bridge/rmgr/pwr.c @@ -0,0 +1,184 @@ +/* + * pwr.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== PWR.c ======== + * PWR API for controlling DSP power states. + * + * Public Functions: + * PWR_SleepDSP + * PWR_WakeDSP + * + *! Revision History + *! ================ + *! 18-Feb-2003 vp Code review updates. + *! 18-Oct-2002 vp Ported to Linux platform. + *! 22-May-2002 sg Do PWR-to-IOCTL code mapping in PWR_SleepDSP. + *! 29-Apr-2002 sg Initial. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- This */ +#include + +/* ----------------------------------- Resource Manager */ +#include +#include + +/* ----------------------------------- Platform Manager */ +#include + +/* ----------------------------------- Link Driver */ +#include + +/* + * ======== PWR_SleepDSP ======== + * Send command to DSP to enter sleep state. + */ +DSP_STATUS PWR_SleepDSP(IN CONST u32 sleepCode, IN CONST u32 timeout) +{ + struct WMD_DRV_INTERFACE *pIntfFxns; + struct WMD_DEV_CONTEXT *dwContext; + DSP_STATUS status = DSP_EFAIL; + struct DEV_OBJECT *hDevObject = NULL; + u32 ioctlcode = 0; + u32 arg = timeout; + + for (hDevObject = (struct DEV_OBJECT *)DRV_GetFirstDevObject(); + hDevObject != NULL; + hDevObject = + (struct DEV_OBJECT *)DRV_GetNextDevObject + ((u32)hDevObject)) { + if (DSP_FAILED(DEV_GetWMDContext(hDevObject, + (struct WMD_DEV_CONTEXT **)&dwContext))) { + continue; + } + if (DSP_FAILED(DEV_GetIntfFxns(hDevObject, + (struct WMD_DRV_INTERFACE **)&pIntfFxns))) { + continue; + } + if (sleepCode == PWR_DEEPSLEEP) + ioctlcode = WMDIOCTL_DEEPSLEEP; + else if (sleepCode == PWR_EMERGENCYDEEPSLEEP) + ioctlcode = WMDIOCTL_EMERGENCYSLEEP; + else + status = DSP_EINVALIDARG; + + if (status != DSP_EINVALIDARG) { + status = (*pIntfFxns->pfnDevCntrl)(dwContext, + ioctlcode, (void *)&arg); + } + } + return status; +} + +/* + * ======== PWR_WakeDSP ======== + * Send command to DSP to wake it from sleep. + */ +DSP_STATUS PWR_WakeDSP(IN CONST u32 timeout) +{ + struct WMD_DRV_INTERFACE *pIntfFxns; + struct WMD_DEV_CONTEXT *dwContext; + DSP_STATUS status = DSP_EFAIL; + struct DEV_OBJECT *hDevObject = NULL; + u32 arg = timeout; + + for (hDevObject = (struct DEV_OBJECT *)DRV_GetFirstDevObject(); + hDevObject != NULL; + hDevObject = (struct DEV_OBJECT *)DRV_GetNextDevObject + ((u32)hDevObject)) { + if (DSP_SUCCEEDED(DEV_GetWMDContext(hDevObject, + (struct WMD_DEV_CONTEXT **)&dwContext))) { + if (DSP_SUCCEEDED(DEV_GetIntfFxns(hDevObject, + (struct WMD_DRV_INTERFACE **)&pIntfFxns))) { + status = (*pIntfFxns->pfnDevCntrl)(dwContext, + WMDIOCTL_WAKEUP, (void *)&arg); + } + } + } + return status; +} + +/* + * ======== PWR_PM_PreScale======== + * Sends pre-notification message to DSP. + */ +DSP_STATUS PWR_PM_PreScale(IN u16 voltage_domain, u32 level) +{ + struct WMD_DRV_INTERFACE *pIntfFxns; + struct WMD_DEV_CONTEXT *dwContext; + DSP_STATUS status = DSP_EFAIL; + struct DEV_OBJECT *hDevObject = NULL; + u32 arg[2]; + + arg[0] = voltage_domain; + arg[1] = level; + + for (hDevObject = (struct DEV_OBJECT *)DRV_GetFirstDevObject(); + hDevObject != NULL; + hDevObject = (struct DEV_OBJECT *)DRV_GetNextDevObject + ((u32)hDevObject)) { + if (DSP_SUCCEEDED(DEV_GetWMDContext(hDevObject, + (struct WMD_DEV_CONTEXT **)&dwContext))) { + if (DSP_SUCCEEDED(DEV_GetIntfFxns(hDevObject, + (struct WMD_DRV_INTERFACE **)&pIntfFxns))) { + status = (*pIntfFxns->pfnDevCntrl)(dwContext, + WMDIOCTL_PRESCALE_NOTIFY, + (void *)&arg); + } + } + } + return status; +} + +/* + * ======== PWR_PM_PostScale======== + * Sends post-notification message to DSP. + */ +DSP_STATUS PWR_PM_PostScale(IN u16 voltage_domain, u32 level) +{ + struct WMD_DRV_INTERFACE *pIntfFxns; + struct WMD_DEV_CONTEXT *dwContext; + DSP_STATUS status = DSP_EFAIL; + struct DEV_OBJECT *hDevObject = NULL; + u32 arg[2]; + + arg[0] = voltage_domain; + arg[1] = level; + + for (hDevObject = (struct DEV_OBJECT *)DRV_GetFirstDevObject(); + hDevObject != NULL; + hDevObject = (struct DEV_OBJECT *)DRV_GetNextDevObject + ((u32)hDevObject)) { + if (DSP_SUCCEEDED(DEV_GetWMDContext(hDevObject, + (struct WMD_DEV_CONTEXT **)&dwContext))) { + if (DSP_SUCCEEDED(DEV_GetIntfFxns(hDevObject, + (struct WMD_DRV_INTERFACE **)&pIntfFxns))) { + status = (*pIntfFxns->pfnDevCntrl)(dwContext, + WMDIOCTL_POSTSCALE_NOTIFY, + (void *)&arg); + } + } + } + return status; + +} + + diff --git a/drivers/dsp/bridge/rmgr/rmm.c b/drivers/dsp/bridge/rmgr/rmm.c new file mode 100644 index 0000000..575f675 --- /dev/null +++ b/drivers/dsp/bridge/rmgr/rmm.c @@ -0,0 +1,604 @@ +/* + * rmm.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== rmm.c ======== + * Description: + * + * This memory manager provides general heap management and arbitrary + * alignment for any number of memory segments. + * + * Notes: + * + * Memory blocks are allocated from the end of the first free memory + * block large enough to satisfy the request. Alignment requirements + * are satisfied by "sliding" the block forward until its base satisfies + * the alignment specification; if this is not possible then the next + * free block large enough to hold the request is tried. + * + * Since alignment can cause the creation of a new free block - the + * unused memory formed between the start of the original free block + * and the start of the allocated block - the memory manager must free + * this memory to prevent a memory leak. + * + * Overlay memory is managed by reserving through RMM_alloc, and freeing + * it through RMM_free. The memory manager prevents DSP code/data that is + * overlayed from being overwritten as long as the memory it runs at has + * been allocated, and not yet freed. + * + *! Revision History + *! ================ + *! 18-Feb-2003 vp Code review updates. + *! 18-Oct-2002 vp Ported to Linux Platform. + *! 24-Sep-2002 map Updated from Code Review + *! 25-Jun-2002 jeh Free from segid passed to RMM_free(). + *! 24-Apr-2002 jeh Determine segid based on address in RMM_free(). (No way + *! to keep track of segid with dynamic loader library.) + *! 16-Oct-2001 jeh Based on gen tree rm.c. Added support for overlays. + */ + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include + +/* ----------------------------------- This */ +#include + +#define RMM_TARGSIGNATURE 0x544d4d52 /* "TMMR" */ + +/* + * ======== RMM_Header ======== + * This header is used to maintain a list of free memory blocks. + */ +struct RMM_Header { + struct RMM_Header *next; /* form a free memory link list */ + u32 size; /* size of the free memory */ + u32 addr; /* DSP address of memory block */ +} ; + +/* + * ======== RMM_OvlySect ======== + * Keeps track of memory occupied by overlay section. + */ +struct RMM_OvlySect { + struct LST_ELEM listElem; + u32 addr; /* Start of memory section */ + u32 size; /* Length (target MAUs) of section */ + s32 page; /* Memory page */ +}; + +/* + * ======== RMM_TargetObj ======== + */ +struct RMM_TargetObj { + u32 dwSignature; + struct RMM_Segment *segTab; + struct RMM_Header **freeList; + u32 numSegs; + struct LST_LIST *ovlyList; /* List of overlay memory in use */ +}; + +#if GT_TRACE +static struct GT_Mask RMM_debugMask = { NULL, NULL }; /* GT trace variable */ +#endif + +static u32 cRefs; /* module reference count */ + +static bool allocBlock(struct RMM_TargetObj *target, u32 segid, u32 size, + u32 align, u32 *dspAddr); +static bool freeBlock(struct RMM_TargetObj *target, u32 segid, u32 addr, + u32 size); + +/* + * ======== RMM_alloc ======== + */ +DSP_STATUS RMM_alloc(struct RMM_TargetObj *target, u32 segid, u32 size, + u32 align, u32 *dspAddr, bool reserve) +{ + struct RMM_OvlySect *sect; + struct RMM_OvlySect *prevSect = NULL; + struct RMM_OvlySect *newSect; + u32 addr; + DSP_STATUS status = DSP_SOK; + + DBC_Require(MEM_IsValidHandle(target, RMM_TARGSIGNATURE)); + DBC_Require(dspAddr != NULL); + DBC_Require(size > 0); + DBC_Require(reserve || (target->numSegs > 0)); + DBC_Require(cRefs > 0); + + GT_6trace(RMM_debugMask, GT_ENTER, + "RMM_alloc(0x%lx, 0x%lx, 0x%lx, 0x%lx, " + "0x%lx, 0x%lx)\n", target, segid, size, align, dspAddr, + reserve); + if (!reserve) { + if (!allocBlock(target, segid, size, align, dspAddr)) { + status = DSP_EMEMORY; + } else { + /* Increment the number of allocated blocks in this + * segment */ + target->segTab[segid].number++; + } + goto func_end; + } + /* An overlay section - See if block is already in use. If not, + * insert into the list in ascending address size. */ + addr = *dspAddr; + sect = (struct RMM_OvlySect *)LST_First(target->ovlyList); + /* Find place to insert new list element. List is sorted from + * smallest to largest address. */ + while (sect != NULL) { + if (addr <= sect->addr) { + /* Check for overlap with sect */ + if ((addr + size > sect->addr) || (prevSect && + (prevSect->addr + prevSect->size > addr))) { + status = DSP_EOVERLAYMEMORY; + } + break; + } + prevSect = sect; + sect = (struct RMM_OvlySect *)LST_Next(target->ovlyList, + (struct LST_ELEM *)sect); + } + if (DSP_SUCCEEDED(status)) { + /* No overlap - allocate list element for new section. */ + newSect = MEM_Calloc(sizeof(struct RMM_OvlySect), MEM_PAGED); + if (newSect == NULL) { + status = DSP_EMEMORY; + } else { + LST_InitElem((struct LST_ELEM *)newSect); + newSect->addr = addr; + newSect->size = size; + newSect->page = segid; + if (sect == NULL) { + /* Put new section at the end of the list */ + LST_PutTail(target->ovlyList, + (struct LST_ELEM *)newSect); + } else { + /* Put new section just before sect */ + LST_InsertBefore(target->ovlyList, + (struct LST_ELEM *)newSect, + (struct LST_ELEM *)sect); + } + } + } +func_end: + return status; +} + +/* + * ======== RMM_create ======== + */ +DSP_STATUS RMM_create(struct RMM_TargetObj **pTarget, + struct RMM_Segment segTab[], u32 numSegs) +{ + struct RMM_Header *hptr; + struct RMM_Segment *sptr, *tmp; + struct RMM_TargetObj *target; + s32 i; + DSP_STATUS status = DSP_SOK; + + DBC_Require(pTarget != NULL); + DBC_Require(numSegs == 0 || segTab != NULL); + + GT_3trace(RMM_debugMask, GT_ENTER, + "RMM_create(0x%lx, 0x%lx, 0x%lx)\n", + pTarget, segTab, numSegs); + + /* Allocate DBL target object */ + MEM_AllocObject(target, struct RMM_TargetObj, RMM_TARGSIGNATURE); + + if (target == NULL) { + GT_0trace(RMM_debugMask, GT_6CLASS, + "RMM_create: Memory allocation failed\n"); + status = DSP_EMEMORY; + } + if (DSP_FAILED(status)) + goto func_cont; + + target->numSegs = numSegs; + if (!(numSegs > 0)) + goto func_cont; + + /* Allocate the memory for freelist from host's memory */ + target->freeList = MEM_Calloc(numSegs * sizeof(struct RMM_Header *), + MEM_PAGED); + if (target->freeList == NULL) { + GT_0trace(RMM_debugMask, GT_6CLASS, + "RMM_create: Memory allocation failed\n"); + status = DSP_EMEMORY; + } else { + /* Allocate headers for each element on the free list */ + for (i = 0; i < (s32) numSegs; i++) { + target->freeList[i] = + MEM_Calloc(sizeof(struct RMM_Header), + MEM_PAGED); + if (target->freeList[i] == NULL) { + GT_0trace(RMM_debugMask, GT_6CLASS, + "RMM_create: Memory " + "allocation failed\n"); + status = DSP_EMEMORY; + break; + } + } + /* Allocate memory for initial segment table */ + target->segTab = MEM_Calloc(numSegs * + sizeof(struct RMM_Segment), MEM_PAGED); + if (target->segTab == NULL) { + GT_0trace(RMM_debugMask, GT_6CLASS, + "RMM_create: Memory allocation failed\n"); + status = DSP_EMEMORY; + } else { + /* Initialize segment table and free list */ + sptr = target->segTab; + for (i = 0, tmp = segTab; numSegs > 0; numSegs--, i++) { + *sptr = *tmp; + hptr = target->freeList[i]; + hptr->addr = tmp->base; + hptr->size = tmp->length; + hptr->next = NULL; + tmp++; + sptr++; + } + } + } +func_cont: + /* Initialize overlay memory list */ + if (DSP_SUCCEEDED(status)) { + target->ovlyList = LST_Create(); + if (target->ovlyList == NULL) { + GT_0trace(RMM_debugMask, GT_6CLASS, + "RMM_create: Memory allocation failed\n"); + status = DSP_EMEMORY; + } + } + + if (DSP_SUCCEEDED(status)) { + *pTarget = target; + } else { + *pTarget = NULL; + if (target) + RMM_delete(target); + + } + + DBC_Ensure((DSP_SUCCEEDED(status) && MEM_IsValidHandle((*pTarget), + RMM_TARGSIGNATURE)) || (DSP_FAILED(status) && *pTarget == + NULL)); + + return status; +} + +/* + * ======== RMM_delete ======== + */ +void RMM_delete(struct RMM_TargetObj *target) +{ + struct RMM_OvlySect *pSect; + struct RMM_Header *hptr; + struct RMM_Header *next; + u32 i; + + DBC_Require(MEM_IsValidHandle(target, RMM_TARGSIGNATURE)); + + GT_1trace(RMM_debugMask, GT_ENTER, "RMM_delete(0x%lx)\n", target); + + if (target->segTab != NULL) + MEM_Free(target->segTab); + + if (target->ovlyList) { + while ((pSect = (struct RMM_OvlySect *)LST_GetHead + (target->ovlyList))) { + MEM_Free(pSect); + } + DBC_Assert(LST_IsEmpty(target->ovlyList)); + LST_Delete(target->ovlyList); + } + + if (target->freeList != NULL) { + /* Free elements on freelist */ + for (i = 0; i < target->numSegs; i++) { + hptr = next = target->freeList[i]; + while (next) { + hptr = next; + next = hptr->next; + MEM_Free(hptr); + } + } + MEM_Free(target->freeList); + } + + MEM_FreeObject(target); +} + +/* + * ======== RMM_exit ======== + */ +void RMM_exit(void) +{ + DBC_Require(cRefs > 0); + + cRefs--; + + GT_1trace(RMM_debugMask, GT_5CLASS, "RMM_exit() ref count: 0x%x\n", + cRefs); + + if (cRefs == 0) + MEM_Exit(); + + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== RMM_free ======== + */ +bool RMM_free(struct RMM_TargetObj *target, u32 segid, u32 addr, u32 size, + bool reserved) + +{ + struct RMM_OvlySect *sect; + bool retVal = true; + + DBC_Require(MEM_IsValidHandle(target, RMM_TARGSIGNATURE)); + + DBC_Require(reserved || segid < target->numSegs); + DBC_Require(reserved || (addr >= target->segTab[segid].base && + (addr + size) <= (target->segTab[segid].base + + target->segTab[segid].length))); + + GT_5trace(RMM_debugMask, GT_ENTER, + "RMM_free(0x%lx, 0x%lx, 0x%lx, 0x%lx, " + "0x%lx)\n", target, segid, addr, size, reserved); + /* + * Free or unreserve memory. + */ + if (!reserved) { + retVal = freeBlock(target, segid, addr, size); + if (retVal) + target->segTab[segid].number--; + + } else { + /* Unreserve memory */ + sect = (struct RMM_OvlySect *)LST_First(target->ovlyList); + while (sect != NULL) { + if (addr == sect->addr) { + DBC_Assert(size == sect->size); + /* Remove from list */ + LST_RemoveElem(target->ovlyList, + (struct LST_ELEM *)sect); + MEM_Free(sect); + break; + } + sect = (struct RMM_OvlySect *)LST_Next(target->ovlyList, + (struct LST_ELEM *)sect); + } + if (sect == NULL) + retVal = false; + + } + return retVal; +} + +/* + * ======== RMM_init ======== + */ +bool RMM_init(void) +{ + bool retVal = true; + + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { + DBC_Assert(!RMM_debugMask.flags); + GT_create(&RMM_debugMask, "RM"); /* "RM" for RMm */ + + retVal = MEM_Init(); + + if (!retVal) + MEM_Exit(); + + } + + if (retVal) + cRefs++; + + GT_1trace(RMM_debugMask, GT_5CLASS, + "RMM_init(), ref count: 0x%x\n", + cRefs); + + DBC_Ensure((retVal && (cRefs > 0)) || (!retVal && (cRefs >= 0))); + + return retVal; +} + +/* + * ======== RMM_stat ======== + */ +bool RMM_stat(struct RMM_TargetObj *target, enum DSP_MEMTYPE segid, + struct DSP_MEMSTAT *pMemStatBuf) +{ + struct RMM_Header *head; + bool retVal = false; + u32 maxFreeSize = 0; + u32 totalFreeSize = 0; + u32 freeBlocks = 0; + + DBC_Require(pMemStatBuf != NULL); + DBC_Assert(target != NULL); + + if ((u32) segid < target->numSegs) { + head = target->freeList[segid]; + + /* Collect data from freeList */ + while (head != NULL) { + maxFreeSize = max(maxFreeSize, head->size); + totalFreeSize += head->size; + freeBlocks++; + head = head->next; + } + + /* ulSize */ + pMemStatBuf->ulSize = target->segTab[segid].length; + + /* ulNumFreeBlocks */ + pMemStatBuf->ulNumFreeBlocks = freeBlocks; + + /* ulTotalFreeSize */ + pMemStatBuf->ulTotalFreeSize = totalFreeSize; + + /* ulLenMaxFreeBlock */ + pMemStatBuf->ulLenMaxFreeBlock = maxFreeSize; + + /* ulNumAllocBlocks */ + pMemStatBuf->ulNumAllocBlocks = target->segTab[segid].number; + + retVal = true; + } + + return retVal; +} + +/* + * ======== balloc ======== + * This allocation function allocates memory from the lowest addresses + * first. + */ +static bool allocBlock(struct RMM_TargetObj *target, u32 segid, u32 size, + u32 align, u32 *dspAddr) +{ + struct RMM_Header *head; + struct RMM_Header *prevhead = NULL; + struct RMM_Header *next; + u32 tmpalign; + u32 alignbytes; + u32 hsize; + u32 allocsize; + u32 addr; + + alignbytes = (align == 0) ? 1 : align; + prevhead = NULL; + head = target->freeList[segid]; + + do { + hsize = head->size; + next = head->next; + + addr = head->addr; /* alloc from the bottom */ + + /* align allocation */ + (tmpalign = (u32) addr % alignbytes); + if (tmpalign != 0) + tmpalign = alignbytes - tmpalign; + + allocsize = size + tmpalign; + + if (hsize >= allocsize) { /* big enough */ + if (hsize == allocsize && prevhead != NULL) { + prevhead->next = next; + MEM_Free(head); + } else { + head->size = hsize - allocsize; + head->addr += allocsize; + } + + /* free up any hole created by alignment */ + if (tmpalign) + freeBlock(target, segid, addr, tmpalign); + + *dspAddr = addr + tmpalign; + return true; + } + + prevhead = head; + head = next; + + } while (head != NULL); + + return false; +} + +/* + * ======== freeBlock ======== + * TO DO: freeBlock() allocates memory, which could result in failure. + * Could allocate an RMM_Header in RMM_alloc(), to be kept in a pool. + * freeBlock() could use an RMM_Header from the pool, freeing as blocks + * are coalesced. + */ +static bool freeBlock(struct RMM_TargetObj *target, u32 segid, u32 addr, + u32 size) +{ + struct RMM_Header *head; + struct RMM_Header *thead; + struct RMM_Header *rhead; + bool retVal = true; + + /* Create a memory header to hold the newly free'd block. */ + rhead = MEM_Calloc(sizeof(struct RMM_Header), MEM_PAGED); + if (rhead == NULL) { + retVal = false; + } else { + /* search down the free list to find the right place for addr */ + head = target->freeList[segid]; + + if (addr >= head->addr) { + while (head->next != NULL && addr > head->next->addr) + head = head->next; + + thead = head->next; + + head->next = rhead; + rhead->next = thead; + rhead->addr = addr; + rhead->size = size; + } else { + *rhead = *head; + head->next = rhead; + head->addr = addr; + head->size = size; + thead = rhead->next; + } + + /* join with upper block, if possible */ + if (thead != NULL && (rhead->addr + rhead->size) == + thead->addr) { + head->next = rhead->next; + thead->size = size + thead->size; + thead->addr = addr; + MEM_Free(rhead); + rhead = thead; + } + + /* join with the lower block, if possible */ + if ((head->addr + head->size) == rhead->addr) { + head->next = rhead->next; + head->size = head->size + rhead->size; + MEM_Free(rhead); + } + } + + return retVal; +} + diff --git a/drivers/dsp/bridge/rmgr/strm.c b/drivers/dsp/bridge/rmgr/strm.c new file mode 100644 index 0000000..bd55fd3 --- /dev/null +++ b/drivers/dsp/bridge/rmgr/strm.c @@ -0,0 +1,1066 @@ +/* + * strm.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== strm.c ======== + * Description: + * DSP/BIOS Bridge Stream Manager. + * + * Public Functions: + * STRM_AllocateBuffer + * STRM_Close + * STRM_Create + * STRM_Delete + * STRM_Exit + * STRM_FreeBuffer + * STRM_GetEventHandle + * STRM_GetInfo + * STRM_Idle + * STRM_Init + * STRM_Issue + * STRM_Open + * STRM_PrepareBuffer + * STRM_Reclaim + * STRM_RegisterNotify + * STRM_Select + * STRM_UnprepareBuffer + * + * Notes: + * + *! Revision History: + *! ================= + *! 18-Feb-2003 vp Code review updates. + *! 18-Oct-2002 vp Ported to Linux platform. + *! 13-Mar-2002 map pStrm init'd to NULL in STRM_Open to prevent error + *! 12-Mar-2002 map Changed return var to WSX "wStatus" instead of "status" + *! in DEV and CMM function calls to avoid confusion. + *! Return DSP_SOK instead of S_OK from API fxns. + *! 12-Mar-2002 map Changed FAILED(..) to DSP_FAILED(..) + *! 25-Jan-2002 ag Allow neg seg ids(e.g. DSP_SHMSEG0) to denote SM. + *! 15-Nov-2001 ag Added STRMMODE & SM for DMA/ZCopy streaming. + *! Changed DSP_STREAMINFO to STRM_INFO in STRM_GetInfo(). + *! Use strm timeout value for dma flush timeout. + *! 09-May-2001 jeh Code review cleanup. + *! 06-Feb-2001 kc Updated DBC_Ensure in STRM_Select to check timeout. + *! 23-Oct-2000 jeh Allow NULL STRM_ATTRS passed to STRM_Open() for DLL + *! tests to pass. + *! 25-Sep-2000 jeh Created. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include + +/* ----------------------------------- Mini Driver */ +#include + +/* ----------------------------------- Resource Manager */ +#include + +/* ----------------------------------- Others */ +#include + +/* ----------------------------------- This */ +#include + +#ifndef RES_CLEANUP_DISABLE +#include +#include +#include +#endif + +/* ----------------------------------- Defines, Data Structures, Typedefs */ +#define STRM_SIGNATURE 0x4d525453 /* "MRTS" */ +#define STRMMGR_SIGNATURE 0x5254534d /* "RTSM" */ + +#define DEFAULTTIMEOUT 10000 +#define DEFAULTNUMBUFS 2 + +/* + * ======== STRM_MGR ======== + * The STRM_MGR contains device information needed to open the underlying + * channels of a stream. + */ +struct STRM_MGR { + u32 dwSignature; + struct DEV_OBJECT *hDev; /* Device for this processor */ + struct CHNL_MGR *hChnlMgr; /* Channel manager */ + struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD */ + struct SYNC_CSOBJECT *hSync; /* For critical sections */ +} ; + +/* + * ======== STRM_OBJECT ======== + * This object is allocated in STRM_Open(). + */ + struct STRM_OBJECT { + u32 dwSignature; + struct STRM_MGR *hStrmMgr; + struct CHNL_OBJECT *hChnl; + u32 uDir; /* DSP_TONODE or DSP_FROMNODE */ + u32 uTimeout; + u32 uNumBufs; /* Max # of bufs allowed in stream */ + u32 uNBufsInStrm; /* Current # of bufs in stream */ + u32 ulNBytes; /* bytes transferred since idled */ + enum DSP_STREAMSTATE strmState; /* STREAM_IDLE, STREAM_READY, ... */ + HANDLE hUserEvent; /* Saved for STRM_GetInfo() */ + enum DSP_STRMMODE lMode; /* STRMMODE_[PROCCOPY][ZEROCOPY]... */ + u32 uDMAChnlId; /* DMA chnl id */ + u32 uDMAPriority; /* DMA priority:DMAPRI_[LOW][HIGH] */ + u32 uSegment; /* >0 is SM segment.=0 is local heap */ + u32 uAlignment; /* Alignment for stream bufs */ + struct CMM_XLATOROBJECT *hXlator; /* Stream's SM address translator */ +} ; + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask STRM_debugMask = { NULL, NULL }; /* GT trace variable */ +#endif +static u32 cRefs; /* module reference count */ + +/* ----------------------------------- Function Prototypes */ +static DSP_STATUS DeleteStrm(struct STRM_OBJECT *hStrm); +static void DeleteStrmMgr(struct STRM_MGR *hStrmMgr); + +/* + * ======== STRM_AllocateBuffer ======== + * Purpose: + * Allocates buffers for a stream. + */ +DSP_STATUS STRM_AllocateBuffer(struct STRM_OBJECT *hStrm, u32 uSize, + OUT u8 **apBuffer, u32 uNumBufs) +{ + DSP_STATUS status = DSP_SOK; + u32 uAllocated = 0; + u32 i; + #ifndef RES_CLEANUP_DISABLE + DSP_STATUS res_status = DSP_SOK; + u32 hProcess; + HANDLE pCtxt = NULL; + HANDLE hDrvObject; + HANDLE hSTRMRes; + #endif + DBC_Require(cRefs > 0); + DBC_Require(apBuffer != NULL); + + GT_4trace(STRM_debugMask, GT_ENTER, "STRM_AllocateBuffer: hStrm: 0x%x\t" + "uSize: 0x%x\tapBuffer: 0x%x\tuNumBufs: 0x%x\n", + hStrm, uSize, apBuffer, uNumBufs); + if (MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) { + /* + * Allocate from segment specified at time of stream open. + */ + if (uSize == 0) + status = DSP_ESIZE; + + } + if (DSP_FAILED(status)) { + status = DSP_EHANDLE; + goto func_end; + } + for (i = 0; i < uNumBufs; i++) { + DBC_Assert(hStrm->hXlator != NULL); + (void)CMM_XlatorAllocBuf(hStrm->hXlator, &apBuffer[i], uSize); + if (apBuffer[i] == NULL) { + GT_0trace(STRM_debugMask, GT_7CLASS, + "STRM_AllocateBuffer: " + "DSP_FAILED to alloc shared memory.\n"); + status = DSP_EMEMORY; + uAllocated = i; + break; + } + } + if (DSP_FAILED(status)) + STRM_FreeBuffer(hStrm, apBuffer, uAllocated); + +#ifndef RES_CLEANUP_DISABLE + if (DSP_FAILED(status)) + goto func_end; + + /* Return PID instead of process handle */ + hProcess = current->pid; + + res_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); + if (DSP_FAILED(res_status)) + goto func_end; + + DRV_GetProcContext(hProcess, (struct DRV_OBJECT *)hDrvObject, + &pCtxt, NULL, 0); + if (pCtxt != NULL) { + if (DRV_GetSTRMResElement(hStrm, &hSTRMRes, pCtxt) != + DSP_ENOTFOUND) { + DRV_ProcUpdateSTRMRes(uNumBufs, hSTRMRes, pCtxt); + } + } +#endif +func_end: + return status; +} + +/* + * ======== STRM_Close ======== + * Purpose: + * Close a stream opened with STRM_Open(). + */ +DSP_STATUS STRM_Close(struct STRM_OBJECT *hStrm) +{ + struct WMD_DRV_INTERFACE *pIntfFxns; + struct CHNL_INFO chnlInfo; + DSP_STATUS status = DSP_SOK; + + +#ifndef RES_CLEANUP_DISABLE + u32 hProcess; + HANDLE pCtxt = NULL; + HANDLE hDrvObject; + HANDLE hSTRMRes; + DSP_STATUS res_status = DSP_SOK; +#endif + + + DBC_Require(cRefs > 0); + + GT_1trace(STRM_debugMask, GT_ENTER, "STRM_Close: hStrm: 0x%x\n", hStrm); + + if (!MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) { + status = DSP_EHANDLE; + } else { + /* Have all buffers been reclaimed? If not, return + * DSP_EPENDING */ + pIntfFxns = hStrm->hStrmMgr->pIntfFxns; + status = (*pIntfFxns->pfnChnlGetInfo) (hStrm->hChnl, &chnlInfo); + DBC_Assert(DSP_SUCCEEDED(status)); + + if (chnlInfo.cIOCs > 0 || chnlInfo.cIOReqs > 0) { + status = DSP_EPENDING; + } else { + + status = DeleteStrm(hStrm); + + if (DSP_FAILED(status)) { + /* we already validated the handle. */ + DBC_Assert(status != DSP_EHANDLE); + + /* make sure we return a documented result */ + status = DSP_EFAIL; + } + } + } +#ifndef RES_CLEANUP_DISABLE + if (DSP_FAILED(status)) + goto func_end; + + /* Update the node and stream resource status */ + /* Return PID instead of process handle */ + hProcess = current->pid; + + res_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); + if (DSP_FAILED(res_status)) + goto func_end; + + DRV_GetProcContext(hProcess, (struct DRV_OBJECT *)hDrvObject, + &pCtxt, NULL, 0); + if (pCtxt != NULL) { + if (DRV_GetSTRMResElement(hStrm, &hSTRMRes, pCtxt) != + DSP_ENOTFOUND) { + DRV_ProcRemoveSTRMResElement(hSTRMRes, pCtxt); + } + } +func_end: +#endif + DBC_Ensure(status == DSP_SOK || status == DSP_EHANDLE || + status == DSP_EPENDING || status == DSP_EFAIL); + + return status; +} + +/* + * ======== STRM_Create ======== + * Purpose: + * Create a STRM manager object. + */ +DSP_STATUS STRM_Create(OUT struct STRM_MGR **phStrmMgr, struct DEV_OBJECT *hDev) +{ + struct STRM_MGR *pStrmMgr; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(phStrmMgr != NULL); + DBC_Require(hDev != NULL); + + GT_2trace(STRM_debugMask, GT_ENTER, "STRM_Create: phStrmMgr: " + "0x%x\thDev: 0x%x\n", phStrmMgr, hDev); + *phStrmMgr = NULL; + /* Allocate STRM manager object */ + MEM_AllocObject(pStrmMgr, struct STRM_MGR, STRMMGR_SIGNATURE); + if (pStrmMgr == NULL) { + status = DSP_EMEMORY; + GT_0trace(STRM_debugMask, GT_6CLASS, "STRM_Create: " + "MEM_AllocObject() failed!\n "); + } else { + pStrmMgr->hDev = hDev; + } + /* Get Channel manager and WMD function interface */ + if (DSP_SUCCEEDED(status)) { + status = DEV_GetChnlMgr(hDev, &(pStrmMgr->hChnlMgr)); + if (DSP_SUCCEEDED(status)) { + (void) DEV_GetIntfFxns(hDev, &(pStrmMgr->pIntfFxns)); + DBC_Assert(pStrmMgr->pIntfFxns != NULL); + } else { + GT_1trace(STRM_debugMask, GT_6CLASS, "STRM_Create: " + "Failed to get channel manager! status = " + "0x%x\n", status); + } + } + if (DSP_SUCCEEDED(status)) + status = SYNC_InitializeCS(&pStrmMgr->hSync); + + if (DSP_SUCCEEDED(status)) + *phStrmMgr = pStrmMgr; + else + DeleteStrmMgr(pStrmMgr); + + DBC_Ensure(DSP_SUCCEEDED(status) && + (MEM_IsValidHandle((*phStrmMgr), STRMMGR_SIGNATURE) || + (DSP_FAILED(status) && *phStrmMgr == NULL))); + + return status; +} + +/* + * ======== STRM_Delete ======== + * Purpose: + * Delete the STRM Manager Object. + */ +void STRM_Delete(struct STRM_MGR *hStrmMgr) +{ + DBC_Require(cRefs > 0); + DBC_Require(MEM_IsValidHandle(hStrmMgr, STRMMGR_SIGNATURE)); + + GT_1trace(STRM_debugMask, GT_ENTER, "STRM_Delete: hStrmMgr: 0x%x\n", + hStrmMgr); + + DeleteStrmMgr(hStrmMgr); + + DBC_Ensure(!MEM_IsValidHandle(hStrmMgr, STRMMGR_SIGNATURE)); +} + +/* + * ======== STRM_Exit ======== + * Purpose: + * Discontinue usage of STRM module. + */ +void STRM_Exit(void) +{ + DBC_Require(cRefs > 0); + + cRefs--; + + GT_1trace(STRM_debugMask, GT_5CLASS, + "Entered STRM_Exit, ref count: 0x%x\n", cRefs); + + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== STRM_FreeBuffer ======== + * Purpose: + * Frees the buffers allocated for a stream. + */ +DSP_STATUS STRM_FreeBuffer(struct STRM_OBJECT *hStrm, u8 **apBuffer, + u32 uNumBufs) +{ + DSP_STATUS status = DSP_SOK; + u32 i = 0; + + #ifndef RES_CLEANUP_DISABLE + DSP_STATUS res_status = DSP_SOK; + u32 hProcess; + HANDLE pCtxt = NULL; + HANDLE hDrvObject; + HANDLE hSTRMRes = NULL; + #endif + DBC_Require(cRefs > 0); + DBC_Require(apBuffer != NULL); + + GT_3trace(STRM_debugMask, GT_ENTER, "STRM_FreeBuffer: hStrm: 0x%x\t" + "apBuffer: 0x%x\tuNumBufs: 0x%x\n", hStrm, apBuffer, uNumBufs); + + if (!MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) + status = DSP_EHANDLE; + + if (DSP_SUCCEEDED(status)) { + for (i = 0; i < uNumBufs; i++) { + DBC_Assert(hStrm->hXlator != NULL); + status = CMM_XlatorFreeBuf(hStrm->hXlator, apBuffer[i]); + if (DSP_FAILED(status)) { + GT_0trace(STRM_debugMask, GT_7CLASS, + "STRM_FreeBuffer: DSP_FAILED" + " to free shared memory.\n"); + break; + } + apBuffer[i] = NULL; + } + } +#ifndef RES_CLEANUP_DISABLE + /* Update the node and stream resource status */ + /* Return PID instead of process handle */ + hProcess = current->pid; + + res_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); + if (DSP_SUCCEEDED(res_status)) { + DRV_GetProcContext(hProcess, + (struct DRV_OBJECT *)hDrvObject, &pCtxt, + NULL, 0); + if (pCtxt != NULL) { + if (DRV_GetSTRMResElement(hStrm, hSTRMRes, pCtxt) != + DSP_ENOTFOUND) { + DRV_ProcUpdateSTRMRes(uNumBufs-i, hSTRMRes, + pCtxt); + } + } + } +#endif + return status; +} + +/* + * ======== STRM_GetInfo ======== + * Purpose: + * Retrieves information about a stream. + */ +DSP_STATUS STRM_GetInfo(struct STRM_OBJECT *hStrm, + OUT struct STRM_INFO *pStreamInfo, + u32 uStreamInfoSize) +{ + struct WMD_DRV_INTERFACE *pIntfFxns; + struct CHNL_INFO chnlInfo; + DSP_STATUS status = DSP_SOK; + void *pVirtBase = NULL; /* NULL if no SM used */ + + DBC_Require(cRefs > 0); + DBC_Require(pStreamInfo != NULL); + DBC_Require(uStreamInfoSize >= sizeof(struct STRM_INFO)); + + GT_3trace(STRM_debugMask, GT_ENTER, "STRM_GetInfo: hStrm: 0x%x\t" + "pStreamInfo: 0x%x\tuStreamInfoSize: 0x%x\n", hStrm, + pStreamInfo, uStreamInfoSize); + if (!MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) { + status = DSP_EHANDLE; + } else { + if (uStreamInfoSize < sizeof(struct STRM_INFO)) { + /* size of users info */ + status = DSP_ESIZE; + } + } + if (DSP_FAILED(status)) + goto func_end; + + pIntfFxns = hStrm->hStrmMgr->pIntfFxns; + status = (*pIntfFxns->pfnChnlGetInfo) (hStrm->hChnl, &chnlInfo); + if (DSP_FAILED(status)) + goto func_end; + + if (hStrm->hXlator) { + /* We have a translator */ + DBC_Assert(hStrm->uSegment > 0); + CMM_XlatorInfo(hStrm->hXlator, (u8 **)&pVirtBase, 0, + hStrm->uSegment, false); + } + pStreamInfo->uSegment = hStrm->uSegment; + pStreamInfo->lMode = hStrm->lMode; + pStreamInfo->pVirtBase = pVirtBase; + pStreamInfo->pUser->uNumberBufsAllowed = hStrm->uNumBufs; + pStreamInfo->pUser->uNumberBufsInStream = chnlInfo.cIOCs + + chnlInfo.cIOReqs; + /* # of bytes transferred since last call to DSPStream_Idle() */ + pStreamInfo->pUser->ulNumberBytes = chnlInfo.cPosition; + pStreamInfo->pUser->hSyncObjectHandle = chnlInfo.hEvent; + /* Determine stream state based on channel state and info */ + if (chnlInfo.dwState & CHNL_STATEEOS) { + pStreamInfo->pUser->ssStreamState = STREAM_DONE; + } else { + if (chnlInfo.cIOCs > 0) + pStreamInfo->pUser->ssStreamState = STREAM_READY; + else if (chnlInfo.cIOReqs > 0) + pStreamInfo->pUser->ssStreamState = STREAM_PENDING; + else + pStreamInfo->pUser->ssStreamState = STREAM_IDLE; + + } +func_end: + return status; +} + +/* + * ======== STRM_Idle ======== + * Purpose: + * Idles a particular stream. + */ +DSP_STATUS STRM_Idle(struct STRM_OBJECT *hStrm, bool fFlush) +{ + struct WMD_DRV_INTERFACE *pIntfFxns; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + + GT_2trace(STRM_debugMask, GT_ENTER, "STRM_Idle: hStrm: 0x%x\t" + "fFlush: 0x%x\n", hStrm, fFlush); + + if (!MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) { + status = DSP_EHANDLE; + } else { + pIntfFxns = hStrm->hStrmMgr->pIntfFxns; + + status = (*pIntfFxns->pfnChnlIdle) (hStrm->hChnl, + hStrm->uTimeout, fFlush); + } + return status; +} + +/* + * ======== STRM_Init ======== + * Purpose: + * Initialize the STRM module. + */ +bool STRM_Init(void) +{ + bool fRetVal = true; + + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { +#if GT_TRACE + DBC_Assert(!STRM_debugMask.flags); + GT_create(&STRM_debugMask, "ST"); /* "ST" for STrm */ +#endif + } + + if (fRetVal) + cRefs++; + + GT_1trace(STRM_debugMask, GT_5CLASS, "STRM_Init(), ref count: 0x%x\n", + cRefs); + + DBC_Ensure((fRetVal && (cRefs > 0)) || (!fRetVal && (cRefs >= 0))); + + return fRetVal; +} + +/* + * ======== STRM_Issue ======== + * Purpose: + * Issues a buffer on a stream + */ +DSP_STATUS STRM_Issue(struct STRM_OBJECT *hStrm, IN u8 *pBuf, u32 ulBytes, + u32 ulBufSize, u32 dwArg) +{ + struct WMD_DRV_INTERFACE *pIntfFxns; + DSP_STATUS status = DSP_SOK; + void *pTmpBuf = NULL; + + DBC_Require(cRefs > 0); + DBC_Require(pBuf != NULL); + + GT_4trace(STRM_debugMask, GT_ENTER, "STRM_Issue: hStrm: 0x%x\tpBuf: " + "0x%x\tulBytes: 0x%x\tdwArg: 0x%x\n", hStrm, pBuf, ulBytes, + dwArg); + if (!MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) { + status = DSP_EHANDLE; + } else { + pIntfFxns = hStrm->hStrmMgr->pIntfFxns; + + if (hStrm->uSegment != 0) { + pTmpBuf = CMM_XlatorTranslate(hStrm->hXlator, + (void *)pBuf, CMM_VA2DSPPA); + if (pTmpBuf == NULL) + status = DSP_ETRANSLATE; + + } + if (DSP_SUCCEEDED(status)) { + status = (*pIntfFxns->pfnChnlAddIOReq) + (hStrm->hChnl, pBuf, ulBytes, ulBufSize, + (u32) pTmpBuf, dwArg); + } + if (DSP_FAILED(status)) { + if (status == CHNL_E_NOIORPS) + status = DSP_ESTREAMFULL; + else + status = DSP_EFAIL; + + } + } + return status; +} + +/* + * ======== STRM_Open ======== + * Purpose: + * Open a stream for sending/receiving data buffers to/from a task or + * XDAIS socket node on the DSP. + */ +DSP_STATUS STRM_Open(struct NODE_OBJECT *hNode, u32 uDir, u32 uIndex, + IN struct STRM_ATTR *pAttr, OUT struct STRM_OBJECT **phStrm) +{ + struct STRM_MGR *hStrmMgr; + struct WMD_DRV_INTERFACE *pIntfFxns; + u32 ulChnlId; + struct STRM_OBJECT *pStrm = NULL; + CHNL_MODE uMode; + struct CHNL_ATTRS chnlAttrs; + DSP_STATUS status = DSP_SOK; + struct CMM_OBJECT *hCmmMgr = NULL; /* Shared memory manager hndl */ + + #ifndef RES_CLEANUP_DISABLE + DSP_STATUS res_status = DSP_SOK; + u32 hProcess; + HANDLE pCtxt = NULL; + HANDLE hDrvObject; + HANDLE hSTRMRes; + #endif + DBC_Require(cRefs > 0); + DBC_Require(phStrm != NULL); + DBC_Require(pAttr != NULL); + GT_5trace(STRM_debugMask, GT_ENTER, + "STRM_Open: hNode: 0x%x\tuDir: 0x%x\t" + "uIndex: 0x%x\tpAttr: 0x%x\tphStrm: 0x%x\n", + hNode, uDir, uIndex, pAttr, phStrm); + *phStrm = NULL; + if (uDir != DSP_TONODE && uDir != DSP_FROMNODE) { + status = DSP_EDIRECTION; + } else { + /* Get the channel id from the node (set in NODE_Connect()) */ + status = NODE_GetChannelId(hNode, uDir, uIndex, &ulChnlId); + } + if (DSP_SUCCEEDED(status)) + status = NODE_GetStrmMgr(hNode, &hStrmMgr); + + if (DSP_SUCCEEDED(status)) { + MEM_AllocObject(pStrm, struct STRM_OBJECT, STRM_SIGNATURE); + if (pStrm == NULL) { + status = DSP_EMEMORY; + GT_0trace(STRM_debugMask, GT_6CLASS, + "STRM_Open: MEM_AllocObject() failed!\n "); + } else { + pStrm->hStrmMgr = hStrmMgr; + pStrm->uDir = uDir; + pStrm->strmState = STREAM_IDLE; + pStrm->hUserEvent = pAttr->hUserEvent; + if (pAttr->pStreamAttrIn != NULL) { + pStrm->uTimeout = pAttr->pStreamAttrIn-> + uTimeout; + pStrm->uNumBufs = pAttr->pStreamAttrIn-> + uNumBufs; + pStrm->lMode = pAttr->pStreamAttrIn->lMode; + pStrm->uSegment = pAttr->pStreamAttrIn-> + uSegment; + pStrm->uAlignment = pAttr->pStreamAttrIn-> + uAlignment; + pStrm->uDMAChnlId = pAttr->pStreamAttrIn-> + uDMAChnlId; + pStrm->uDMAPriority = pAttr->pStreamAttrIn-> + uDMAPriority; + chnlAttrs.uIOReqs = pAttr->pStreamAttrIn-> + uNumBufs; + } else { + pStrm->uTimeout = DEFAULTTIMEOUT; + pStrm->uNumBufs = DEFAULTNUMBUFS; + pStrm->lMode = STRMMODE_PROCCOPY; + pStrm->uSegment = 0; /* local memory */ + pStrm->uAlignment = 0; + pStrm->uDMAChnlId = 0; + pStrm->uDMAPriority = 0; + chnlAttrs.uIOReqs = DEFAULTNUMBUFS; + } + chnlAttrs.hReserved1 = NULL; + /* DMA chnl flush timeout */ + chnlAttrs.hReserved2 = pStrm->uTimeout; + chnlAttrs.hEvent = NULL; + if (pAttr->hUserEvent != NULL) + chnlAttrs.hEvent = pAttr->hUserEvent; + + } + } + if (DSP_FAILED(status)) + goto func_cont; + + if ((pAttr->pVirtBase == NULL) || !(pAttr->ulVirtSize > 0)) + goto func_cont; + + DBC_Assert(pStrm->lMode != STRMMODE_LDMA); /* no System DMA */ + /* Get the shared mem mgr for this streams dev object */ + status = DEV_GetCmmMgr(hStrmMgr->hDev, &hCmmMgr); + if (DSP_FAILED(status)) { + GT_1trace(STRM_debugMask, GT_6CLASS, "STRM_Open: Failed to get " + "CMM Mgr handle: 0x%x\n", status); + } else { + /*Allocate a SM addr translator for this strm.*/ + status = CMM_XlatorCreate(&pStrm->hXlator, hCmmMgr, NULL); + if (DSP_FAILED(status)) { + GT_1trace(STRM_debugMask, GT_6CLASS, + "STRM_Open: Failed to " + "create SM translator: 0x%x\n", status); + } else { + DBC_Assert(pStrm->uSegment > 0); + /* Set translators Virt Addr attributes */ + status = CMM_XlatorInfo(pStrm->hXlator, + (u8 **)&pAttr->pVirtBase, pAttr->ulVirtSize, + pStrm->uSegment, true); + if (status != DSP_SOK) { + GT_0trace(STRM_debugMask, GT_6CLASS, + "STRM_Open: ERROR: " + "in setting CMM_XlatorInfo.\n"); + } + } + } +func_cont: + if (DSP_SUCCEEDED(status)) { + /* Open channel */ + uMode = (uDir == DSP_TONODE) ? + CHNL_MODETODSP : CHNL_MODEFROMDSP; + pIntfFxns = hStrmMgr->pIntfFxns; + status = (*pIntfFxns->pfnChnlOpen) (&(pStrm->hChnl), + hStrmMgr->hChnlMgr, uMode, ulChnlId, &chnlAttrs); + if (DSP_FAILED(status)) { + /* + * over-ride non-returnable status codes so we return + * something documented + */ + if (status != DSP_EMEMORY && status != + DSP_EINVALIDARG && status != DSP_EFAIL) { + /* + * We got a status that's not return-able. + * Assert that we got something we were + * expecting (DSP_EHANDLE isn't acceptable, + * hStrmMgr->hChnlMgr better be valid or we + * assert here), and then return DSP_EFAIL. + */ + DBC_Assert(status == CHNL_E_OUTOFSTREAMS || + status == CHNL_E_BADCHANID || + status == CHNL_E_CHANBUSY || + status == CHNL_E_NOIORPS); + status = DSP_EFAIL; + } + GT_2trace(STRM_debugMask, GT_6CLASS, + "STRM_Open: Channel open failed, " + "chnl id = %d, status = 0x%x\n", ulChnlId, + status); + } + } + if (DSP_SUCCEEDED(status)) + *phStrm = pStrm; + else + (void)DeleteStrm(pStrm); + +#ifndef RES_CLEANUP_DISABLE + /* Return PID instead of process handle */ + hProcess = current->pid; + + res_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); + if (DSP_SUCCEEDED(res_status)) { + DRV_GetProcContext(hProcess, + (struct DRV_OBJECT *)hDrvObject, &pCtxt, + hNode, 0); + if (pCtxt != NULL) + DRV_ProcInsertSTRMResElement(*phStrm, &hSTRMRes, pCtxt); + + } +#endif + + /* ensure we return a documented error code */ + DBC_Ensure((DSP_SUCCEEDED(status) && + MEM_IsValidHandle((*phStrm), STRM_SIGNATURE)) || + (*phStrm == NULL && (status == DSP_EHANDLE || + status == DSP_EDIRECTION || status == DSP_EVALUE || + status == DSP_EFAIL))); + return status; +} + +/* + * ======== STRM_Reclaim ======== + * Purpose: + * Relcaims a buffer from a stream. + */ +DSP_STATUS STRM_Reclaim(struct STRM_OBJECT *hStrm, OUT u8 **pBufPtr, + u32 *pulBytes, u32 *pulBufSize, u32 *pdwArg) +{ + struct WMD_DRV_INTERFACE *pIntfFxns; + struct CHNL_IOC chnlIOC; + DSP_STATUS status = DSP_SOK; + void *pTmpBuf = NULL; + + DBC_Require(cRefs > 0); + DBC_Require(pBufPtr != NULL); + DBC_Require(pulBytes != NULL); + DBC_Require(pdwArg != NULL); + + GT_4trace(STRM_debugMask, GT_ENTER, + "STRM_Reclaim: hStrm: 0x%x\tpBufPtr: 0x%x" + "\tpulBytes: 0x%x\tpdwArg: 0x%x\n", hStrm, pBufPtr, pulBytes, + pdwArg); + + if (!MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) { + status = DSP_EHANDLE; + goto func_end; + } + pIntfFxns = hStrm->hStrmMgr->pIntfFxns; + + status = (*pIntfFxns->pfnChnlGetIOC)(hStrm->hChnl, hStrm->uTimeout, + &chnlIOC); + if (DSP_FAILED(status)) { + GT_1trace(STRM_debugMask, GT_6CLASS, + "STRM_Reclaim: GetIOC failed! " + "Status = 0x%x\n", status); + } else { + *pulBytes = chnlIOC.cBytes; + if (pulBufSize) + *pulBufSize = chnlIOC.cBufSize; + + *pdwArg = chnlIOC.dwArg; + if (!CHNL_IsIOComplete(chnlIOC)) { + if (CHNL_IsTimedOut(chnlIOC)) { + status = DSP_ETIMEOUT; + } else { + /* Allow reclaims after idle to succeed */ + if (!CHNL_IsIOCancelled(chnlIOC)) + status = DSP_EFAIL; + + } + } + /* Translate zerocopy buffer if channel not canceled. */ + if (DSP_SUCCEEDED(status) && (!CHNL_IsIOCancelled(chnlIOC)) && + (hStrm->lMode == STRMMODE_ZEROCOPY)) { + /* + * This is a zero-copy channel so chnlIOC.pBuf + * contains the DSP address of SM. We need to + * translate it to a virtual address for the user + * thread to access. + * Note: Could add CMM_DSPPA2VA to CMM in the future. + */ + pTmpBuf = CMM_XlatorTranslate(hStrm->hXlator, + chnlIOC.pBuf, CMM_DSPPA2PA); + if (pTmpBuf != NULL) { + /* now convert this GPP Pa to Va */ + pTmpBuf = CMM_XlatorTranslate(hStrm->hXlator, + pTmpBuf, CMM_PA2VA); + } + if (pTmpBuf == NULL) { + GT_0trace(STRM_debugMask, GT_7CLASS, + "STRM_Reclaim: Failed " + "SM translation!\n"); + status = DSP_ETRANSLATE; + } + chnlIOC.pBuf = pTmpBuf; + } + *pBufPtr = chnlIOC.pBuf; + } +func_end: + /* ensure we return a documented return code */ + DBC_Ensure(DSP_SUCCEEDED(status) || status == DSP_EHANDLE || + status == DSP_ETIMEOUT || status == DSP_ETRANSLATE || + status == DSP_EFAIL); + return status; +} + +/* + * ======== STRM_RegisterNotify ======== + * Purpose: + * Register to be notified on specific events for this stream. + */ +DSP_STATUS STRM_RegisterNotify(struct STRM_OBJECT *hStrm, u32 uEventMask, + u32 uNotifyType, struct DSP_NOTIFICATION + *hNotification) +{ + struct WMD_DRV_INTERFACE *pIntfFxns; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(hNotification != NULL); + + GT_4trace(STRM_debugMask, GT_ENTER, + "STRM_RegisterNotify: hStrm: 0x%x\t" + "uEventMask: 0x%x\tuNotifyType: 0x%x\thNotification: 0x%x\n", + hStrm, uEventMask, uNotifyType, hNotification); + if (!MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) { + status = DSP_EHANDLE; + } else if ((uEventMask & ~((DSP_STREAMIOCOMPLETION) | + DSP_STREAMDONE)) != 0) { + status = DSP_EVALUE; + } else { + if (uNotifyType != DSP_SIGNALEVENT) + status = DSP_ENOTIMPL; + + } + if (DSP_SUCCEEDED(status)) { + pIntfFxns = hStrm->hStrmMgr->pIntfFxns; + + status = (*pIntfFxns->pfnChnlRegisterNotify)(hStrm->hChnl, + uEventMask, uNotifyType, hNotification); + } + /* ensure we return a documented return code */ + DBC_Ensure(DSP_SUCCEEDED(status) || status == DSP_EHANDLE || + status == DSP_ETIMEOUT || status == DSP_ETRANSLATE || + status == DSP_ENOTIMPL || status == DSP_EFAIL); + return status; +} + +/* + * ======== STRM_Select ======== + * Purpose: + * Selects a ready stream. + */ +DSP_STATUS STRM_Select(IN struct STRM_OBJECT **aStrmTab, u32 nStrms, + OUT u32 *pMask, u32 uTimeout) +{ + u32 uIndex; + struct CHNL_INFO chnlInfo; + struct WMD_DRV_INTERFACE *pIntfFxns; + struct SYNC_OBJECT **hSyncEvents = NULL; + u32 i; + DSP_STATUS status = DSP_SOK; + + DBC_Require(cRefs > 0); + DBC_Require(aStrmTab != NULL); + DBC_Require(pMask != NULL); + DBC_Require(nStrms > 0); + + GT_4trace(STRM_debugMask, GT_ENTER, + "STRM_Select: aStrmTab: 0x%x \tnStrms: " + "0x%x\tpMask: 0x%x\tuTimeout: 0x%x\n", aStrmTab, + nStrms, pMask, uTimeout); + *pMask = 0; + for (i = 0; i < nStrms; i++) { + if (!MEM_IsValidHandle(aStrmTab[i], STRM_SIGNATURE)) { + status = DSP_EHANDLE; + break; + } + } + if (DSP_FAILED(status)) + goto func_end; + + /* Determine which channels have IO ready */ + for (i = 0; i < nStrms; i++) { + pIntfFxns = aStrmTab[i]->hStrmMgr->pIntfFxns; + status = (*pIntfFxns->pfnChnlGetInfo)(aStrmTab[i]->hChnl, + &chnlInfo); + if (DSP_FAILED(status)) { + break; + } else { + if (chnlInfo.cIOCs > 0) + *pMask |= (1 << i); + + } + } + if (DSP_SUCCEEDED(status) && uTimeout > 0 && *pMask == 0) { + /* Non-zero timeout */ + hSyncEvents = (struct SYNC_OBJECT **)MEM_Alloc(nStrms * + sizeof(struct SYNC_OBJECT *), MEM_PAGED); + if (hSyncEvents == NULL) { + status = DSP_EMEMORY; + } else { + for (i = 0; i < nStrms; i++) { + pIntfFxns = aStrmTab[i]->hStrmMgr->pIntfFxns; + status = (*pIntfFxns->pfnChnlGetInfo) + (aStrmTab[i]->hChnl, &chnlInfo); + if (DSP_FAILED(status)) + break; + else + hSyncEvents[i] = chnlInfo.hSyncEvent; + + } + } + if (DSP_SUCCEEDED(status)) { + status = SYNC_WaitOnMultipleEvents(hSyncEvents, nStrms, + uTimeout, &uIndex); + if (DSP_SUCCEEDED(status)) { + /* Since we waited on the event, we have to + * reset it */ + SYNC_SetEvent(hSyncEvents[uIndex]); + *pMask = 1 << uIndex; + } + } + } +func_end: + if (hSyncEvents) + MEM_Free(hSyncEvents); + + DBC_Ensure((DSP_SUCCEEDED(status) && (*pMask != 0 || uTimeout == 0)) || + (DSP_FAILED(status) && *pMask == 0)); + + return status; +} + +/* + * ======== DeleteStrm ======== + * Purpose: + * Frees the resources allocated for a stream. + */ +static DSP_STATUS DeleteStrm(struct STRM_OBJECT *hStrm) +{ + struct WMD_DRV_INTERFACE *pIntfFxns; + DSP_STATUS status = DSP_SOK; + + if (MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) { + if (hStrm->hChnl) { + pIntfFxns = hStrm->hStrmMgr->pIntfFxns; + /* Channel close can fail only if the channel handle + * is invalid. */ + status = (*pIntfFxns->pfnChnlClose) (hStrm->hChnl); + /* Free all SM address translator resources */ + if (DSP_SUCCEEDED(status)) { + if (hStrm->hXlator) { + /* force free */ + (void)CMM_XlatorDelete(hStrm->hXlator, + true); + } + } + } + MEM_FreeObject(hStrm); + } else { + status = DSP_EHANDLE; + } + return status; +} + +/* + * ======== DeleteStrmMgr ======== + * Purpose: + * Frees stream manager. + */ +static void DeleteStrmMgr(struct STRM_MGR *hStrmMgr) +{ + if (MEM_IsValidHandle(hStrmMgr, STRMMGR_SIGNATURE)) { + + if (hStrmMgr->hSync) + SYNC_DeleteCS(hStrmMgr->hSync); + + MEM_FreeObject(hStrmMgr); + } +} + diff --git a/drivers/dsp/bridge/services/cfg.c b/drivers/dsp/bridge/services/cfg.c new file mode 100644 index 0000000..67656bf --- /dev/null +++ b/drivers/dsp/bridge/services/cfg.c @@ -0,0 +1,483 @@ +/* + * cfg.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== cfgce.c ======== + * Purpose: + * Implementation of platform specific config services. + * + * Private Functions: + * CFG_Exit + * CFG_GetAutoStart + * CFG_GetDevObject + * CFG_GetDSPResources + * CFG_GetExecFile + * CFG_GetHostResources + * CFG_GetObject + * CFG_Init + * CFG_SetDevObject + * CFG_SetObject + * + * + *! Revision History: + *! ================ + *! 26-Arp-2004 hp Support for handling more than one Device. + *! 26-Feb-2003 kc Removed unused CFG fxns. + *! 10-Nov-2000 rr: CFG_GetBoardName local var initialized. + *! 30-Oct-2000 kc: Changed local var. names to use Hungarian notation. + *! 10-Aug-2000 rr: Cosmetic changes. + *! 26-Jul-2000 rr: Added CFG_GetDCDName. CFG_Get/SetObject(based on a flag) + *! replaces CFG_GetMgrObject & CFG_SetMgrObject. + *! 17-Jul-2000 rr: Added CFG_GetMgrObject & CFG_SetMgrObject. + *! 03-Feb-2000 rr: Module init/exit is handled by SERVICES Init/Exit. + *! GT Changes. + *! 31-Jan-2000 rr: Comments and bugfixes: modified after code review + *! 07-Jan-2000 rr: CFG_GetBoardName Ensure class checks strlen of the + *! read value from the registry against the passed in BufSize; + *! CFG_GetZLFile,CFG_GetWMDFileName and + *! CFG_GetExecFile also modified same way. + *! 06-Jan-2000 rr: CFG_GetSearchPath & CFG_GetWinBRIDGEDir removed. + *! 09-Dec-1999 rr: CFG_SetDevObject stores the DevNodeString pointer. + *! 03-Dec-1999 rr: CFG_GetDevObject reads stored DevObject from Registry. + *! CFG_GetDevNode reads the Devnodestring from the registry. + *! CFG_SetDevObject stores the registry path as + *! DevNodestring in the registry. + *! 02-Dec-1999 rr: CFG_debugMask is declared static now. stdwin.h included + *! 22-Nov-1999 kc: Added windows.h to remove warnings. + *! 25-Oct-1999 rr: CFG_GetHostResources reads the HostResource structure + *! from the registry which was set by the DRV Request + *! Resources. + *! 15-Oct-1999 rr: Changes in CFG_SetPrivateDword & HostResources reflecting + *! changes for drv.h resource structure and wsxreg.h new + *! entry(DevObject) Hard coded entries removed for those items + *! 08-Oct-1999 rr: CFG_SetPrivateDword modified. it sets devobject into the + *! registry. CFG_Get HostResources modified for opening up + *! two mem winodws. + *! 24-Sep-1999 rr: CFG_GetHostResources uses hardcoded Registry calls,uses NT + *! type of Resource Structure. + *! 19-Jul-1999 a0216266: Stubbed from cfgnt.c. + */ + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include + +/* ----------------------------------- Others */ +#include + +/* ----------------------------------- This */ +#include +#include + +struct DRV_EXT { + struct LST_ELEM link; + char szString[MAXREGPATHLENGTH]; +}; + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask CFG_debugMask = { NULL, NULL }; /* CFG debug Mask */ +#endif + +/* + * ======== CFG_Exit ======== + * Purpose: + * Discontinue usage of the CFG module. + */ +void CFG_Exit(void) +{ + GT_0trace(CFG_debugMask, GT_5CLASS, "Entered CFG_Exit\n"); +} + +/* + * ======== CFG_GetAutoStart ======== + * Purpose: + * Retreive the autostart mask, if any, for this board. + */ +DSP_STATUS CFG_GetAutoStart(struct CFG_DEVNODE *hDevNode, + OUT u32 *pdwAutoStart) +{ + DSP_STATUS status = DSP_SOK; + u32 dwBufSize; + GT_2trace(CFG_debugMask, GT_ENTER, + "Entered CFG_GetAutoStart: \n\thDevNode:" + "0x%x\n\tpdwAutoStart: 0x%x\n", hDevNode, pdwAutoStart); + dwBufSize = sizeof(*pdwAutoStart); + if (!hDevNode) + status = CFG_E_INVALIDHDEVNODE; + if (!pdwAutoStart) + status = CFG_E_INVALIDPOINTER; + if (DSP_SUCCEEDED(status)) { + status = REG_GetValue(NULL, (char *)hDevNode, AUTOSTART, + (u8 *)pdwAutoStart, &dwBufSize); + if (DSP_FAILED(status)) + status = CFG_E_RESOURCENOTAVAIL; + } +#ifdef DEBUG + if (DSP_SUCCEEDED(status)) { + GT_0trace(CFG_debugMask, GT_1CLASS, + "CFG_GetAutoStart SUCCESS \n"); + } else { + GT_0trace(CFG_debugMask, GT_6CLASS, + "CFG_GetAutoStart Failed \n"); + } +#endif + DBC_Ensure((status == DSP_SOK && + (*pdwAutoStart == 0 || *pdwAutoStart == 1)) + || status != DSP_SOK); + return status; +} + +/* + * ======== CFG_GetDevObject ======== + * Purpose: + * Retrieve the Device Object handle for a given devnode. + */ +DSP_STATUS CFG_GetDevObject(struct CFG_DEVNODE *hDevNode, OUT u32 *pdwValue) +{ + DSP_STATUS status = DSP_SOK; + u32 dwBufSize; + GT_2trace(CFG_debugMask, GT_ENTER, "Entered CFG_GetDevObject, args: " + "\n\thDevNode: 0x%x\n\tpdwValue: 0x%x\n", hDevNode, + *pdwValue); + if (!hDevNode) + status = CFG_E_INVALIDHDEVNODE; + + if (!pdwValue) + status = CFG_E_INVALIDHDEVNODE; + + dwBufSize = sizeof(pdwValue); + if (DSP_SUCCEEDED(status)) { + + /* check the device string and then call the REG_SetValue*/ + if (!(strcmp((char *)((struct DRV_EXT *)hDevNode)->szString, + "TIOMAP1510"))) { + GT_0trace(CFG_debugMask, GT_1CLASS, + "Fetching DSP Device from " + "Registry \n"); + status = REG_GetValue(NULL, (char *)hDevNode, + "DEVICE_DSP", + (u8 *)pdwValue, &dwBufSize); + } else { + GT_0trace(CFG_debugMask, GT_6CLASS, + "Failed to Identify the Device to Fetch \n"); + } + } +#ifdef DEBUG + if (DSP_SUCCEEDED(status)) { + GT_1trace(CFG_debugMask, GT_1CLASS, + "CFG_GetDevObject SUCCESS DevObject" + ": 0x%x\n ", *pdwValue); + } else { + GT_0trace(CFG_debugMask, GT_6CLASS, + "CFG_GetDevObject Failed \n"); + } +#endif + return status; +} + +/* + * ======== CFG_GetDSPResources ======== + * Purpose: + * Get the DSP resources available to a given device. + */ +DSP_STATUS CFG_GetDSPResources(struct CFG_DEVNODE *hDevNode, + OUT struct CFG_DSPRES *pDSPResTable) +{ + DSP_STATUS status = DSP_SOK; /* return value */ + u32 dwResSize; + GT_2trace(CFG_debugMask, GT_ENTER, + "Entered CFG_GetDSPResources, args: " + "\n\thDevNode: 0x%x\n\tpDSPResTable: 0x%x\n", + hDevNode, pDSPResTable); + if (!hDevNode) { + status = CFG_E_INVALIDHDEVNODE; + } else if (!pDSPResTable) { + status = CFG_E_INVALIDPOINTER; + } else { + status = REG_GetValue(NULL, CONFIG, DSPRESOURCES, + (u8 *)pDSPResTable, + &dwResSize); + } + if (DSP_SUCCEEDED(status)) { + GT_0trace(CFG_debugMask, GT_1CLASS, + "CFG_GetDSPResources SUCCESS\n"); + } else { + status = CFG_E_RESOURCENOTAVAIL; + GT_0trace(CFG_debugMask, GT_6CLASS, + "CFG_GetDSPResources Failed \n"); + } +#ifdef DEBUG + /* assert that resource values are reasonable */ + DBC_Assert(pDSPResTable->uChipType < 256); + DBC_Assert(pDSPResTable->uWordSize > 0); + DBC_Assert(pDSPResTable->uWordSize < 32); + DBC_Assert(pDSPResTable->cChips > 0); + DBC_Assert(pDSPResTable->cChips < 256); +#endif + return status; +} + +/* + * ======== CFG_GetExecFile ======== + * Purpose: + * Retreive the default executable, if any, for this board. + */ +DSP_STATUS CFG_GetExecFile(struct CFG_DEVNODE *hDevNode, u32 ulBufSize, + OUT char *pstrExecFile) +{ + DSP_STATUS status = DSP_SOK; + u32 cExecSize = ulBufSize; + GT_3trace(CFG_debugMask, GT_ENTER, + "Entered CFG_GetExecFile:\n\tthDevNode: " + "0x%x\n\tulBufSize: 0x%x\n\tpstrExecFile: 0x%x\n", hDevNode, + ulBufSize, pstrExecFile); + if (!hDevNode) + status = CFG_E_INVALIDHDEVNODE; + + if (!pstrExecFile) + status = CFG_E_INVALIDPOINTER; + + if (DSP_SUCCEEDED(status)) { + status = REG_GetValue(NULL, (char *)hDevNode, DEFEXEC, + (u8 *)pstrExecFile, &cExecSize); + if (DSP_FAILED(status)) + status = CFG_E_RESOURCENOTAVAIL; + else if (cExecSize > ulBufSize) + status = DSP_ESIZE; + + } +#ifdef DEBUG + if (DSP_SUCCEEDED(status)) { + GT_1trace(CFG_debugMask, GT_1CLASS, + "CFG_GetExecFile SUCCESS Exec File" + "name : %s\n ", pstrExecFile); + } else { + GT_0trace(CFG_debugMask, GT_6CLASS, + "CFG_GetExecFile Failed \n"); + } +#endif + DBC_Ensure(((status == DSP_SOK) && + (strlen(pstrExecFile) <= ulBufSize)) || (status != DSP_SOK)); + return status; +} + +/* + * ======== CFG_GetHostResources ======== + * Purpose: + * Get the Host allocated resources assigned to a given device. + */ +DSP_STATUS CFG_GetHostResources(struct CFG_DEVNODE *hDevNode, + OUT struct CFG_HOSTRES *pHostResTable) +{ + DSP_STATUS status = DSP_SOK; + u32 dwBufSize; + GT_2trace(CFG_debugMask, GT_ENTER, + "Entered CFG_GetHostResources, args:\n\t" + "pHostResTable: 0x%x\n\thDevNode: 0x%x\n", + pHostResTable, hDevNode); + if (!hDevNode) + status = CFG_E_INVALIDHDEVNODE; + + if (!pHostResTable) + status = CFG_E_INVALIDPOINTER; + + if (DSP_SUCCEEDED(status)) { + dwBufSize = sizeof(struct CFG_HOSTRES); + if (DSP_FAILED(REG_GetValue(NULL, (char *)hDevNode, + CURRENTCONFIG, + (u8 *)pHostResTable, &dwBufSize))) { + status = CFG_E_RESOURCENOTAVAIL; + } + } +#ifdef DEBUG + if (DSP_SUCCEEDED(status)) { + GT_0trace(CFG_debugMask, GT_1CLASS, + "CFG_GetHostResources SUCCESS \n"); + } else { + GT_0trace(CFG_debugMask, GT_6CLASS, + "CFG_GetHostResources Failed \n"); + } +#endif + return status; +} + +/* + * ======== CFG_GetObject ======== + * Purpose: + * Retrieve the Object handle from the Registry + */ +DSP_STATUS CFG_GetObject(OUT u32 *pdwValue, u32 dwType) +{ + DSP_STATUS status = DSP_EINVALIDARG; + u32 dwBufSize; + DBC_Require(pdwValue != NULL); + GT_1trace(CFG_debugMask, GT_ENTER, + "Entered CFG_GetObject, args:pdwValue: " + "0x%x\n", *pdwValue); + dwBufSize = sizeof(pdwValue); + switch (dwType) { + case (REG_DRV_OBJECT): + status = REG_GetValue(NULL, CONFIG, DRVOBJECT, + (u8 *)pdwValue, + &dwBufSize); + break; + case (REG_MGR_OBJECT): + status = REG_GetValue(NULL, CONFIG, MGROBJECT, + (u8 *)pdwValue, + &dwBufSize); + break; + default: + break; + } + if (DSP_SUCCEEDED(status)) { + GT_1trace(CFG_debugMask, GT_1CLASS, + "CFG_GetObject SUCCESS DrvObject: " + "0x%x\n ", *pdwValue); + } else { + status = CFG_E_RESOURCENOTAVAIL; + *pdwValue = 0; + GT_0trace(CFG_debugMask, GT_6CLASS, "CFG_GetObject Failed \n"); + } + DBC_Ensure((DSP_SUCCEEDED(status) && *pdwValue != 0) || + (DSP_FAILED(status) && *pdwValue == 0)); + return status; +} + +/* + * ======== CFG_Init ======== + * Purpose: + * Initialize the CFG module's private state. + */ +bool CFG_Init(void) +{ + struct CFG_DSPRES dspResources; + GT_create(&CFG_debugMask, "CF"); /* CF for ConFig */ + GT_0trace(CFG_debugMask, GT_5CLASS, "Entered CFG_Init\n"); + GT_0trace(CFG_debugMask, GT_5CLASS, "Intializing DSP Registry Info \n"); + + dspResources.uChipType = DSPTYPE_64; + dspResources.cChips = 1; + dspResources.uWordSize = DSPWORDSIZE; + dspResources.cMemTypes = 0; + dspResources.aMemDesc[0].uMemType = 0; + dspResources.aMemDesc[0].ulMin = 0; + dspResources.aMemDesc[0].ulMax = 0; + if (DSP_SUCCEEDED(REG_SetValue(NULL, CONFIG, DSPRESOURCES, REG_BINARY, + (u8 *)&dspResources, sizeof(struct CFG_DSPRES)))) { + GT_0trace(CFG_debugMask, GT_5CLASS, + "Initialized DSP resources in " + "Registry \n"); + } else + GT_0trace(CFG_debugMask, GT_5CLASS, + "Failed to Initialize DSP resources" + " in Registry \n"); + return true; +} + +/* + * ======== CFG_SetDevObject ======== + * Purpose: + * Store the Device Object handle and devNode pointer for a given devnode. + */ +DSP_STATUS CFG_SetDevObject(struct CFG_DEVNODE *hDevNode, u32 dwValue) +{ + DSP_STATUS status = DSP_SOK; + u32 dwBuffSize; + GT_2trace(CFG_debugMask, GT_ENTER, + "Entered CFG_SetDevObject, args: \n\t" + "hDevNode: 0x%x\n\tdwValue: 0x%x\n", hDevNode, dwValue); + if (!hDevNode) + status = CFG_E_INVALIDHDEVNODE; + + dwBuffSize = sizeof(dwValue); + if (DSP_SUCCEEDED(status)) { + /* Store the WCD device object in the Registry */ + + if (!(strcmp((char *)hDevNode, "TIOMAP1510"))) { + GT_0trace(CFG_debugMask, GT_1CLASS, + "Registering the DSP Device \n"); + status = REG_SetValue(NULL, (char *)hDevNode, + "DEVICE_DSP", REG_DWORD,\ + (u8 *)&dwValue, dwBuffSize); + if (DSP_SUCCEEDED(status)) { + dwBuffSize = sizeof(hDevNode); + status = REG_SetValue(NULL, + (char *)hDevNode, "DEVNODESTRING_DSP", + REG_DWORD, (u8 *)&hDevNode, + dwBuffSize); + } + } else { + GT_0trace(CFG_debugMask, GT_6CLASS, + "Failed to Register Device \n"); + } + } +#ifdef DEBUG + if (DSP_SUCCEEDED(status)) { + GT_0trace(CFG_debugMask, GT_1CLASS, + "CFG_SetDevObject SUCCESS \n"); + } else { + GT_0trace(CFG_debugMask, GT_6CLASS, + "CFG_SetDevObject Failed \n"); + } +#endif + return status; +} + +/* + * ======== CFG_SetObject ======== + * Purpose: + * Store the Driver Object handle + */ +DSP_STATUS CFG_SetObject(u32 dwValue, u32 dwType) +{ + DSP_STATUS status = DSP_EINVALIDARG; + u32 dwBuffSize; + GT_1trace(CFG_debugMask, GT_ENTER, + "Entered CFG_SetObject, args: dwValue: " + "0x%x\n", dwValue); + dwBuffSize = sizeof(dwValue); + switch (dwType) { + case (REG_DRV_OBJECT): + status = REG_SetValue(NULL, CONFIG, DRVOBJECT, REG_DWORD, + (u8 *)&dwValue, dwBuffSize); + break; + case (REG_MGR_OBJECT): + status = REG_SetValue(NULL, CONFIG, MGROBJECT, REG_DWORD, + (u8 *) &dwValue, dwBuffSize); + break; + default: + break; + } +#ifdef DEBUG + if (DSP_SUCCEEDED(status)) + GT_0trace(CFG_debugMask, GT_1CLASS, "CFG_SetObject SUCCESS \n"); + else + GT_0trace(CFG_debugMask, GT_6CLASS, "CFG_SetObject Failed \n"); + +#endif + return status; +} diff --git a/drivers/dsp/bridge/services/clk.c b/drivers/dsp/bridge/services/clk.c new file mode 100644 index 0000000..b499b14 --- /dev/null +++ b/drivers/dsp/bridge/services/clk.c @@ -0,0 +1,375 @@ +/* + * clk.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== clk.c ======== + * Purpose: + * Clock and Timer services. + * + * Public Functions: + * CLK_Exit + * CLK_Init + * CLK_Enable + * CLK_Disable + * CLK_GetRate + * CLK_Set_32KHz + *! Revision History: + *! ================ + *! 08-May-2007 rg: moved all clock functions from sync module. + * And added CLK_Set_32KHz, CLK_Set_SysClk. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include + +/* ----------------------------------- This */ +#include +#include + + +/* ----------------------------------- Defines, Data Structures, Typedefs */ + +typedef volatile unsigned long REG_UWORD32; + +#define SSI_Base 0x48058000 + +#define SSI_BASE IO_ADDRESS(SSI_Base) + + +struct SERVICES_Clk_t { + struct clk *clk_handle; + const char *clk_name; + int id; +}; + +/* The row order of the below array needs to match with the clock enumerations + * 'SERVICES_ClkId' provided in the header file.. any changes in the + * enumerations needs to be fixed in the array as well */ +static struct SERVICES_Clk_t SERVICES_Clks[] = { + {NULL, "iva2_ck", -1}, + {NULL, "mailboxes_ick", -1}, + {NULL, "gpt5_fck", -1}, + {NULL, "gpt5_ick", -1}, + {NULL, "gpt6_fck", -1}, + {NULL, "gpt6_ick", -1}, + {NULL, "gpt7_fck", -1}, + {NULL, "gpt7_ick", -1}, + {NULL, "gpt8_fck", -1}, + {NULL, "gpt8_ick", -1}, + {NULL, "wdt_fck", 3}, + {NULL, "wdt_ick", 3}, + {NULL, "mcbsp_fck", 1}, + {NULL, "mcbsp_ick", 1}, + {NULL, "mcbsp_fck", 2}, + {NULL, "mcbsp_ick", 2}, + {NULL, "mcbsp_fck", 3}, + {NULL, "mcbsp_ick", 3}, + {NULL, "mcbsp_fck", 4}, + {NULL, "mcbsp_ick", 4}, + {NULL, "mcbsp_fck", 5}, + {NULL, "mcbsp_ick", 5}, + {NULL, "ssi_ssr_sst_fck", -1}, + {NULL, "ssi_ick", -1}, + {NULL, "omap_32k_fck", -1}, + {NULL, "sys_ck", -1}, + {NULL, ""} +}; + +/* Generic TIMER object: */ +struct TIMER_OBJECT { + struct timer_list timer; +}; + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask CLK_debugMask = { NULL, NULL }; /* GT trace variable */ +#endif + +/* + * ======== CLK_Exit ======== + * Purpose: + * Cleanup CLK module. + */ +void CLK_Exit(void) +{ + int i = 0; + + GT_0trace(CLK_debugMask, GT_5CLASS, "CLK_Exit\n"); + /* Relinquish the clock handles */ + while (i < SERVICESCLK_NOT_DEFINED) { + if (SERVICES_Clks[i].clk_handle) + clk_put(SERVICES_Clks[i].clk_handle); + + SERVICES_Clks[i].clk_handle = NULL; + i++; + } + +} + +/* + * ======== CLK_Init ======== + * Purpose: + * Initialize CLK module. + */ +bool CLK_Init(void) +{ + static struct platform_device dspbridge_device; + struct clk *clk_handle; + int i = 0; + GT_create(&CLK_debugMask, "CK"); /* CK for CLK */ + GT_0trace(CLK_debugMask, GT_5CLASS, "CLK_Init\n"); + + dspbridge_device.dev.bus = &platform_bus_type; + + /* Get the clock handles from base port and store locally */ + while (i < SERVICESCLK_NOT_DEFINED) { + /* get the handle from BP */ + dspbridge_device.id = SERVICES_Clks[i].id; + + clk_handle = clk_get(&dspbridge_device.dev, + SERVICES_Clks[i].clk_name); + + if (!clk_handle) { + GT_2trace(CLK_debugMask, GT_7CLASS, + "CLK_Init: failed to get Clk handle %s, " + "CLK dev id = %d\n", + SERVICES_Clks[i].clk_name, + SERVICES_Clks[i].id); + /* should we fail here?? */ + } else { + GT_2trace(CLK_debugMask, GT_7CLASS, + "CLK_Init: PASS and Clk handle %s, " + "CLK dev id = %d\n", + SERVICES_Clks[i].clk_name, + SERVICES_Clks[i].id); + } + SERVICES_Clks[i].clk_handle = clk_handle; + i++; + } + + return true; +} + +/* + * ======== CLK_Enable ======== + * Purpose: + * Enable Clock . + * +*/ +DSP_STATUS CLK_Enable(IN enum SERVICES_ClkId clk_id) +{ + DSP_STATUS status = DSP_SOK; + struct clk *pClk; + + DBC_Require(clk_id < SERVICESCLK_NOT_DEFINED); + GT_2trace(CLK_debugMask, GT_6CLASS, "CLK_Enable: CLK %s, " + "CLK dev id = %d\n", SERVICES_Clks[clk_id].clk_name, + SERVICES_Clks[clk_id].id); + + pClk = SERVICES_Clks[clk_id].clk_handle; + if (pClk) { + if (clk_enable(pClk) == 0x0) { + /* Success ? */ + } else { + pr_err("CLK_Enable: failed to Enable CLK %s, " + "CLK dev id = %d\n", + SERVICES_Clks[clk_id].clk_name, + SERVICES_Clks[clk_id].id); + status = DSP_EFAIL; + } + } else { + pr_err("CLK_Enable: failed to get CLK %s, CLK dev id = %d\n", + SERVICES_Clks[clk_id].clk_name, + SERVICES_Clks[clk_id].id); + status = DSP_EFAIL; + } + /* The SSI module need to configured not to have the Forced idle for + * master interface. If it is set to forced idle, the SSI module is + * transitioning to standby thereby causing the client in the DSP hang + * waiting for the SSI module to be active after enabling the clocks + */ + if (clk_id == SERVICESCLK_ssi_fck) + SSI_Clk_Prepare(true); + + return status; +} +/* + * ======== CLK_Set_32KHz ======== + * Purpose: + * To Set parent of a clock to 32KHz. + */ + +DSP_STATUS CLK_Set_32KHz(IN enum SERVICES_ClkId clk_id) +{ + DSP_STATUS status = DSP_SOK; + struct clk *pClk; + struct clk *pClkParent; + enum SERVICES_ClkId sys_32k_id = SERVICESCLK_sys_32k_ck; + pClkParent = SERVICES_Clks[sys_32k_id].clk_handle; + + DBC_Require(clk_id < SERVICESCLK_NOT_DEFINED); + GT_2trace(CLK_debugMask, GT_6CLASS, "CLK_Set_32KHz: CLK %s, " + "CLK dev id = %d is setting to 32KHz \n", + SERVICES_Clks[clk_id].clk_name, + SERVICES_Clks[clk_id].id); + pClk = SERVICES_Clks[clk_id].clk_handle; + if (pClk) { + if (!(clk_set_parent(pClk, pClkParent) == 0x0)) { + GT_2trace(CLK_debugMask, GT_7CLASS, "CLK_Set_32KHz: " + "Failed to set to 32KHz %s, CLK dev id = %d\n", + SERVICES_Clks[clk_id].clk_name, + SERVICES_Clks[clk_id].id); + status = DSP_EFAIL; + } + } + return status; +} + +/* + * ======== CLK_Disable ======== + * Purpose: + * Disable the clock. + * +*/ +DSP_STATUS CLK_Disable(IN enum SERVICES_ClkId clk_id) +{ + DSP_STATUS status = DSP_SOK; + struct clk *pClk; + s32 clkUseCnt; + + DBC_Require(clk_id < SERVICESCLK_NOT_DEFINED); + GT_2trace(CLK_debugMask, GT_6CLASS, "CLK_Disable: CLK %s, " + "CLK dev id = %d\n", SERVICES_Clks[clk_id].clk_name, + SERVICES_Clks[clk_id].id); + + pClk = SERVICES_Clks[clk_id].clk_handle; + + clkUseCnt = CLK_Get_UseCnt(clk_id); + if (clkUseCnt == -1) { + pr_err("CLK_Disable: failed to get CLK Use count for CLK %s," + "CLK dev id = %d\n", + SERVICES_Clks[clk_id].clk_name, + SERVICES_Clks[clk_id].id); + } else if (clkUseCnt == 0) { + pr_err("CLK_Disable: CLK %s, CLK dev id= %d is already" + "disabled\n", + SERVICES_Clks[clk_id].clk_name, + SERVICES_Clks[clk_id].id); + return status; + } + if (clk_id == SERVICESCLK_ssi_ick) + SSI_Clk_Prepare(false); + + if (pClk) { + clk_disable(pClk); + } else { + pr_err("CLK_Disable: failed to get CLK %s," + "CLK dev id = %d\n", + SERVICES_Clks[clk_id].clk_name, + SERVICES_Clks[clk_id].id); + status = DSP_EFAIL; + } + return status; +} + +/* + * ======== CLK_GetRate ======== + * Purpose: + * GetClock Speed. + * + */ + +DSP_STATUS CLK_GetRate(IN enum SERVICES_ClkId clk_id, u32 *speedKhz) +{ + DSP_STATUS status = DSP_SOK; + struct clk *pClk; + u32 clkSpeedHz; + + DBC_Require(clk_id < SERVICESCLK_NOT_DEFINED); + *speedKhz = 0x0; + + GT_2trace(CLK_debugMask, GT_7CLASS, "CLK_GetRate: CLK %s, " + "CLK dev Id = %d \n", SERVICES_Clks[clk_id].clk_name, + SERVICES_Clks[clk_id].id); + pClk = SERVICES_Clks[clk_id].clk_handle; + if (pClk) { + clkSpeedHz = clk_get_rate(pClk); + *speedKhz = clkSpeedHz / 1000; + GT_2trace(CLK_debugMask, GT_6CLASS, + "CLK_GetRate: clkSpeedHz = %d , " + "speedinKhz=%d\n", clkSpeedHz, *speedKhz); + } else { + GT_2trace(CLK_debugMask, GT_7CLASS, + "CLK_GetRate: failed to get CLK %s, " + "CLK dev Id = %d\n", SERVICES_Clks[clk_id].clk_name, + SERVICES_Clks[clk_id].id); + status = DSP_EFAIL; + } + return status; +} + +s32 CLK_Get_UseCnt(IN enum SERVICES_ClkId clk_id) +{ + DSP_STATUS status = DSP_SOK; + struct clk *pClk; + s32 useCount = -1; + DBC_Require(clk_id < SERVICESCLK_NOT_DEFINED); + + pClk = SERVICES_Clks[clk_id].clk_handle; + + if (pClk) { + useCount = pClk->usecount; /* FIXME: usecount shouldn't be used */ + } else { + GT_2trace(CLK_debugMask, GT_7CLASS, + "CLK_GetRate: failed to get CLK %s, " + "CLK dev Id = %d\n", SERVICES_Clks[clk_id].clk_name, + SERVICES_Clks[clk_id].id); + status = DSP_EFAIL; + } + return useCount; +} + +void SSI_Clk_Prepare(bool FLAG) +{ + u32 ssi_sysconfig; + ssi_sysconfig = __raw_readl((SSI_BASE) + 0x10); + + if (FLAG) { + /* Set Autoidle, SIDLEMode to smart idle, and MIDLEmode to + * no idle + */ + ssi_sysconfig = 0x1011; + } else { + /* Set Autoidle, SIDLEMode to forced idle, and MIDLEmode to + * forced idle + */ + ssi_sysconfig = 0x1; + } + __raw_writel((u32)ssi_sysconfig, SSI_BASE + 0x10); +} diff --git a/drivers/dsp/bridge/services/csl.c b/drivers/dsp/bridge/services/csl.c new file mode 100644 index 0000000..dd33c2d --- /dev/null +++ b/drivers/dsp/bridge/services/csl.c @@ -0,0 +1,173 @@ +/* + * csl.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== cslce.c ======== + * Purpose: + * Provides platform independent C Standard library functions. + * + * Public Functions: + * CSL_Atoi + * CSL_Exit + * CSL_Init + * CSL_NumToAscii + * CSL_Strtokr + * + *! Revision History: + *! ================ + *! 07-Aug-2002 jeh: Added CSL_Strtokr(). + *! 21-Sep-2001 jeh: Added CSL_Strncmp(). Alphabetized functions. + *! 22-Nov-2000 map: Added CSL_Atoi and CSL_Strtok + *! 19-Nov-2000 kc: Added CSL_ByteSwap. + *! 09-Nov-2000 kc: Added CSL_Strncat. + *! 03-Feb-2000 rr: Module init/exit is handled by SERVICES Init/Exit. + *! GT Changes. + *! 15-Dec-1999 ag: Removed incorrect assertion CSL_NumToAscii() + *! 29-Oct-1999 kc: Added CSL_Wstrlen for UNICODE strings. + *! 30-Sep-1999 ag: Removed DBC assertion (!CSL_DebugMask.flags) in + * CSP_Init(). + *! 20-Sep-1999 ag: Added CSL_WcharToAnsi(). + *! Removed call to GT_set(). + *! 19-Jan-1998 cr: Code review cleanup. + *! 29-Dec-1997 cr: Made platform independant, using MS CRT code, and + *! combined csl32.c csl95.c and cslnt.c into csl.c. Also + *! changed CSL_lowercase to CSL_Uppercase. + *! 21-Aug-1997 gp: Fix to CSL_strcpyn to initialize Source string, the NT way. + *! 25-Jun-1997 cr: Created from csl95, added CSL_strcmp. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- This */ +#include + +/* Is character c in the string pstrDelim? */ +#define IsDelimiter(c, pstrDelim) ((c != '\0') && \ + (strchr(pstrDelim, c) != NULL)) + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask CSL_DebugMask = { NULL, NULL }; /* GT trace var. */ +#endif + +/* + * ======== CSL_Exit ======== + * Purpose: + * Discontinue usage of the CSL module. + */ +void CSL_Exit(void) +{ + GT_0trace(CSL_DebugMask, GT_5CLASS, "CSL_Exit\n"); +} + +/* + * ======== CSL_Init ======== + * Purpose: + * Initialize the CSL module's private state. + */ +bool CSL_Init(void) +{ + GT_create(&CSL_DebugMask, "CS"); + + GT_0trace(CSL_DebugMask, GT_5CLASS, "CSL_Init\n"); + + return true; +} + +/* + * ======== CSL_NumToAscii ======== + * Purpose: + * Convert a 1 or 2 digit number to a 2 digit string. + */ +void CSL_NumToAscii(OUT char *pstrNumber, u32 dwNum) +{ + char tens; + + DBC_Require(dwNum < 100); + + if (dwNum < 100) { + tens = (char) dwNum / 10; + dwNum = dwNum % 10; + + if (tens) { + pstrNumber[0] = tens + '0'; + pstrNumber[1] = (char) dwNum + '0'; + pstrNumber[2] = '\0'; + } else { + pstrNumber[0] = (char) dwNum + '0'; + pstrNumber[1] = '\0'; + } + } else { + pstrNumber[0] = '\0'; + } +} + + + + +/* + * ======= CSL_Strtokr ======= + * Purpose: + * Re-entrant version of strtok. + */ +char *CSL_Strtokr(IN char *pstrSrc, IN CONST char *szSeparators, + OUT char **ppstrLast) +{ + char *pstrTemp; + char *pstrToken; + + DBC_Require(szSeparators != NULL); + DBC_Require(ppstrLast != NULL); + DBC_Require(pstrSrc != NULL || *ppstrLast != NULL); + + /* + * Set string location to beginning (pstrSrc != NULL) or to the + * beginning of the next token. + */ + pstrTemp = (pstrSrc != NULL) ? pstrSrc : *ppstrLast; + if (*pstrTemp == '\0') { + pstrToken = NULL; + } else { + pstrToken = pstrTemp; + while (*pstrTemp != '\0' && !IsDelimiter(*pstrTemp, + szSeparators)) { + pstrTemp++; + } + if (*pstrTemp != '\0') { + while (IsDelimiter(*pstrTemp, szSeparators)) { + /* TODO: Shouldn't we do this for + * only 1 char?? */ + *pstrTemp = '\0'; + pstrTemp++; + } + } + + /* Location in string for next call */ + *ppstrLast = pstrTemp; + } + + return pstrToken; +} diff --git a/drivers/dsp/bridge/services/dbg.c b/drivers/dsp/bridge/services/dbg.c new file mode 100644 index 0000000..5e1773f --- /dev/null +++ b/drivers/dsp/bridge/services/dbg.c @@ -0,0 +1,119 @@ +/* + * dbg.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dbgce.c ======== + * Purpose: + * Provide debugging services for DSP/BIOS Bridge Mini Drivers. + * + * Public Functions: + * DBG_Exit + * DBG_Init + * DBG_Trace + * + * Notes: + * Requires gt.h. + * + * This implementation does not create GT masks on a per WMD basis. + * There is currently no facility for a WMD to alter the GT mask. + * + *! Revision History: + *! ================ + *! 15-Feb-2000 rr: DBG_Trace prints based on the DebugZones. + *! 03-Feb-2000 rr: Module init/exit is handled by SERVICES Init/Exit. + *! GT Changes. + *! 29-Oct-1999 kc: Cleaned up for code review. + *! 10-Oct-1997 cr: Added DBG_Printf service. + *! 28-May-1997 cr: Added reference counting. + *! 23-May-1997 cr: Updated DBG_Trace to new gt interface. + *! 29-May-1996 gp: Removed WCD_ prefix. + *! 20-May-1996 gp: Remove DEBUG conditional compilation. + *! 15-May-1996 gp: Created. + */ + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- This */ +#include + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask DBG_debugMask = { NULL, NULL }; /* GT trace var. */ +#endif + +#if (defined(DEBUG) || defined (DDSP_DEBUG_PRODUCT)) && GT_TRACE + +/* + * ======== DBG_Init ======== + * Purpose: + * Ensures trace capability is set up for link drivers. + */ +bool DBG_Init(void) +{ + GT_create(&DBG_debugMask, "WD"); /* for WmD (link driver) debug */ + + GT_0trace(DBG_debugMask, GT_5CLASS, "DBG_Init\n"); + + return true; +} + +/* + * ======== DBG_Trace ======== + * Purpose: + * Output a trace message to the debugger, if the given trace level + * is unmasked. + */ +DSP_STATUS DBG_Trace(u8 bLevel, char *pstrFormat, ...) +{ + s32 arg1, arg2, arg3, arg4, arg5, arg6; + va_list va; + + va_start(va, pstrFormat); + + arg1 = va_arg(va, s32); + arg2 = va_arg(va, s32); + arg3 = va_arg(va, s32); + arg4 = va_arg(va, s32); + arg5 = va_arg(va, s32); + arg6 = va_arg(va, s32); + + va_end(va); + + if (bLevel & *(DBG_debugMask).flags) + printk(pstrFormat, arg1, arg2, arg3, arg4, arg5, arg6); + + return DSP_SOK; +} + +/* + * ======== DBG_Exit ======== + * Purpose: + * Discontinue usage of the DBG module. + */ +void DBG_Exit(void) +{ + GT_0trace(DBG_debugMask, GT_5CLASS, "DBG_Exit\n"); +} + +#endif /* (defined(DEBUG) || defined(DDSP_DEBUG_PRODUCT)) && GT_TRACE */ diff --git a/drivers/dsp/bridge/services/dpc.c b/drivers/dsp/bridge/services/dpc.c new file mode 100644 index 0000000..bd608d1 --- /dev/null +++ b/drivers/dsp/bridge/services/dpc.c @@ -0,0 +1,274 @@ +/* + * dpc.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== dpcce.c ======== + * Purpose: + * Deferred Procedure Call(DPC) Services. + * + * + * Public Functions: + * DPC_Create + * DPC_Destroy + * DPC_Exit + * DPC_Init + * DPC_Schedule + * + *! Revision History: + *! ================ + *! 28-Mar-2001 ag: Added #ifdef CHNL_NOIPCINTR to set DPC thread priority + *! to THREAD_PRIORITY_IDLE for polling IPC. + *! 03-Feb-2000 rr: Module init/exit is handled by SERVICES Init/Exit. + *! GT Changes. + *! 31-Jan-2000 rr: Changes after code review.Terminate thread,handle + *! modified.DPC_Destroy frees the DPC_Object only on + *! Successful termination of the thread and the handle. + *! 06-Jan-1999 ag: Format cleanup for code review. + *! Removed DPC_[Lower|Raise]IRQL[From|To]DispatchLevel. + *! 10-Dec-1999 ag: Added SetProcPermissions in DPC_DeferredProcedure(). + *! (Needed to access client(s) CHNL buffers). + *! 19-Sep-1999 a0216266: Stubbed from dpcnt.c. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include + +/* ----------------------------------- This */ +#include + +/* ----------------------------------- Defines, Data Structures, Typedefs */ +#define SIGNATURE 0x5f435044 /* "DPC_" (in reverse). */ + +/* The DPC object, passed to our priority event callback routine: */ +struct DPC_OBJECT { + u32 dwSignature; /* Used for object validation. */ + void *pRefData; /* Argument for client's DPC. */ + DPC_PROC pfnDPC; /* Client's DPC. */ + u32 numRequested; /* Number of requested DPC's. */ + u32 numScheduled; /* Number of executed DPC's. */ + struct tasklet_struct dpc_tasklet; + +#ifdef DEBUG + u32 cEntryCount; /* Number of times DPC reentered. */ + u32 numRequestedMax; /* Keep track of max pending DPC's. */ +#endif + + spinlock_t dpc_lock; +}; + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask DPC_DebugMask = { NULL, NULL }; /* DPC Debug Mask */ +#endif + +/* ----------------------------------- Function Prototypes */ +static void DPC_DeferredProcedure(IN unsigned long pDeferredContext); + +/* + * ======== DPC_Create ======== + * Purpose: + * Create a DPC object, allowing a client's own DPC procedure to be + * scheduled for a call with client reference data. + */ +DSP_STATUS DPC_Create(OUT struct DPC_OBJECT **phDPC, DPC_PROC pfnDPC, + void *pRefData) +{ + DSP_STATUS status = DSP_SOK; + struct DPC_OBJECT *pDPCObject = NULL; + + if ((phDPC != NULL) && (pfnDPC != NULL)) { + /* + * Allocate a DPC object to store information allowing our DPC + * callback to dispatch to the client's DPC. + */ + MEM_AllocObject(pDPCObject, struct DPC_OBJECT, SIGNATURE); + if (pDPCObject != NULL) { + tasklet_init(&pDPCObject->dpc_tasklet, + DPC_DeferredProcedure, + (u32) pDPCObject); + /* Fill out our DPC Object: */ + pDPCObject->pRefData = pRefData; + pDPCObject->pfnDPC = pfnDPC; + pDPCObject->numRequested = 0; + pDPCObject->numScheduled = 0; +#ifdef DEBUG + pDPCObject->numRequestedMax = 0; + pDPCObject->cEntryCount = 0; +#endif + spin_lock_init(&pDPCObject->dpc_lock); + *phDPC = pDPCObject; + } else { + GT_0trace(DPC_DebugMask, GT_6CLASS, + "DPC_Create: DSP_EMEMORY\n"); + status = DSP_EMEMORY; + } + } else { + GT_0trace(DPC_DebugMask, GT_6CLASS, + "DPC_Create: DSP_EPOINTER\n"); + status = DSP_EPOINTER; + } + DBC_Ensure((DSP_FAILED(status) && (!phDPC || (phDPC && *phDPC == NULL))) + || DSP_SUCCEEDED(status)); + return status; +} + +/* + * ======== DPC_Destroy ======== + * Purpose: + * Cancel the last scheduled DPC, and deallocate a DPC object previously + * allocated with DPC_Create(). Frees the Object only if the thread + * and the event terminated successfuly. + */ +DSP_STATUS DPC_Destroy(struct DPC_OBJECT *hDPC) +{ + DSP_STATUS status = DSP_SOK; + struct DPC_OBJECT *pDPCObject = (struct DPC_OBJECT *)hDPC; + + if (MEM_IsValidHandle(hDPC, SIGNATURE)) { + + /* Free our DPC object: */ + if (DSP_SUCCEEDED(status)) { + tasklet_kill(&pDPCObject->dpc_tasklet); + MEM_FreeObject(pDPCObject); + pDPCObject = NULL; + GT_0trace(DPC_DebugMask, GT_2CLASS, + "DPC_Destroy: SUCCESS\n"); + } + } else { + GT_0trace(DPC_DebugMask, GT_6CLASS, + "DPC_Destroy: DSP_EHANDLE\n"); + status = DSP_EHANDLE; + } + DBC_Ensure((DSP_SUCCEEDED(status) && pDPCObject == NULL) + || DSP_FAILED(status)); + return status; +} + +/* + * ======== DPC_Exit ======== + * Purpose: + * Discontinue usage of the DPC module. + */ +void DPC_Exit(void) +{ + GT_0trace(DPC_DebugMask, GT_5CLASS, "Entered DPC_Exit\n"); +} + +/* + * ======== DPC_Init ======== + * Purpose: + * Initialize the DPC module's private state. + */ +bool DPC_Init(void) +{ + GT_create(&DPC_DebugMask, "DP"); + + GT_0trace(DPC_DebugMask, GT_5CLASS, "Entered DPC_Init\n"); + + return true; +} + +/* + * ======== DPC_Schedule ======== + * Purpose: + * Schedule a deferred procedure call to be executed at a later time. + * Latency and order of DPC execution is platform specific. + */ +DSP_STATUS DPC_Schedule(struct DPC_OBJECT *hDPC) +{ + DSP_STATUS status = DSP_SOK; + struct DPC_OBJECT *pDPCObject = (struct DPC_OBJECT *)hDPC; + unsigned long flags; + + GT_1trace(DPC_DebugMask, GT_ENTER, "DPC_Schedule hDPC %x\n", hDPC); + if (MEM_IsValidHandle(hDPC, SIGNATURE)) { + /* Increment count of DPC's pending. Needs to be protected + * from ISRs since this function is called from process + * context also. */ + spin_lock_irqsave(&hDPC->dpc_lock, flags); + pDPCObject->numRequested++; + spin_unlock_irqrestore(&hDPC->dpc_lock, flags); + tasklet_schedule(&(hDPC->dpc_tasklet)); +#ifdef DEBUG + if (pDPCObject->numRequested > pDPCObject->numScheduled + + pDPCObject->numRequestedMax) { + pDPCObject->numRequestedMax = pDPCObject->numRequested - + pDPCObject->numScheduled; + } +#endif + /* If an interrupt occurs between incrementing numRequested and the + * assertion below, then DPC will get executed while returning from + * ISR, which will complete all requests and make numRequested equal + * to numScheduled, firing this assertion. This happens only when + * DPC is being scheduled in process context */ + } else { + GT_0trace(DPC_DebugMask, GT_6CLASS, + "DPC_Schedule: DSP_EHANDLE\n"); + status = DSP_EHANDLE; + } + GT_1trace(DPC_DebugMask, GT_ENTER, "DPC_Schedule status %x\n", status); + return status; +} + +/* + * ======== DeferredProcedure ======== + * Purpose: + * Main DPC routine. This is called by host OS DPC callback + * mechanism with interrupts enabled. + */ +static void DPC_DeferredProcedure(IN unsigned long pDeferredContext) +{ + struct DPC_OBJECT *pDPCObject = (struct DPC_OBJECT *)pDeferredContext; + /* read numRequested in local variable */ + u32 requested; + u32 serviced; + + DBC_Require(pDPCObject != NULL); + requested = pDPCObject->numRequested; + serviced = pDPCObject->numScheduled; + + GT_1trace(DPC_DebugMask, GT_ENTER, "> DPC_DeferredProcedure " + "pDeferredContext=%x\n", pDeferredContext); + /* Rollover taken care of using != instead of < */ + if (serviced != requested) { + if (pDPCObject->pfnDPC != NULL) { + /* Process pending DPC's: */ + do { + /* Call client's DPC: */ + (*(pDPCObject->pfnDPC))(pDPCObject->pRefData); + serviced++; + } while (serviced != requested); + } + pDPCObject->numScheduled = requested; + } + GT_2trace(DPC_DebugMask, GT_ENTER, + "< DPC_DeferredProcedure requested %d" + " serviced %d\n", requested, serviced); +} + diff --git a/drivers/dsp/bridge/services/kfile.c b/drivers/dsp/bridge/services/kfile.c new file mode 100644 index 0000000..ba1d26f --- /dev/null +++ b/drivers/dsp/bridge/services/kfile.c @@ -0,0 +1,338 @@ +/* + * kfile.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== kfilece.c ======== + * Purpose: + * This module provides file i/o services. + * + * Public Functions: + * KFILE_Close + * KFILE_Exit + * KFILE_Init + * KFILE_Open + * KFILE_Read + * KFILE_Seek + * KFILE_Tell + * + *! Revision History + *! ================ + *! 03-Feb-2000 rr: Module init/exit is handled by SERVICES Init/Exit. + *! GT Changes. + *! 22-Nov-1999 kc: Added changes from code review. + *! 12-Nov-1999 kc: Enabled CSL for UNICODE/ANSI string conversions. + *! 30-Sep-1999 ag: Changed KFILE_Read() GT level from _ENTER to _4CLASS. + *! Removed GT_set(). + *! 25-Aug-1999 ag: Changed MEM_Calloc allocation type to MEM_PAGED. + *! 13-Jul-1999 a0216266(ww - TID): Stubbed from kfilent.c. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include + +/* ----------------------------------- This */ +#include + +/* ----------------------------------- Defines, Data Structures, Typedefs */ +#define SIGNATURE 0x4c49464b /* hex code of KFIL (reversed) */ +#define MAXFILENAMELENGTH 256 +#define GENERAL_FAILURE 0xffffffff /* SetFilePointer error */ + +/* The KFILE_FileObj abstracts the true file handle from a KFILE handle. */ +struct KFILE_FileObj { + u32 dwSignature; + __kernel_pid_t owner_pid; /* PID of process that opened this file */ + char *fileName ; + bool isOpen ; + u32 size ; + u32 curPos ; + long hInternal; /* internal handle of file */ + struct file *fileDesc; + +}; + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask KFILE_debugMask = { NULL, NULL }; /* Debug mask */ +#endif + +/* + * ======== KFILE_Close ======== + * Purpose: + * This function closes a file's stream. + */ +s32 KFILE_Close(struct KFILE_FileObj *hFile) +{ + s32 cRetVal = 0; /* 0 indicates success */ + s32 fRetVal = 0; + __kernel_pid_t curr_pid; + + GT_1trace(KFILE_debugMask, GT_ENTER, "KFILE_Close: hFile 0x%x\n", + hFile); + + /* Check for valid handle */ + if (MEM_IsValidHandle(hFile, SIGNATURE)) { + /* Close file only if opened by the same process (id). Otherwise + * Linux closes all open file handles when process exits.*/ + /* Return PID instead of process handle */ + curr_pid = (__kernel_pid_t)current->pid; + fRetVal = filp_close(hFile->fileDesc, NULL) ; + if (fRetVal) { + cRetVal = E_KFILE_ERROR; + GT_1trace(KFILE_debugMask, GT_6CLASS, + "KFILE_Close: sys_close " + "returned %d\n", fRetVal); + } + MEM_FreeObject(hFile); + } else { + cRetVal = E_KFILE_INVALIDHANDLE; + GT_0trace(KFILE_debugMask, GT_6CLASS, "KFILE_Close: " + "invalid file handle\n"); + } + return cRetVal; +} + +/* + * ======== KFILE_Exit ======== + * Purpose: + * Decrement reference count, and free resources when reference count + * is 0. + */ +void KFILE_Exit(void) +{ + GT_0trace(KFILE_debugMask, GT_5CLASS, "KFILE_Exit\n"); +} + +/* + * ======== KFILE_Init ======== + */ +bool KFILE_Init(void) +{ + GT_create(&KFILE_debugMask, "KF"); /* "KF" for KFile */ + + GT_0trace(KFILE_debugMask, GT_5CLASS, "KFILE_Init\n"); + + return true; +} + +/* + * ======== KFILE_Open ======== + * Purpose: + * Open a file for reading ONLY + */ +struct KFILE_FileObj *KFILE_Open(CONST char *pszFileName, CONST char *pszMode) +{ + struct KFILE_FileObj *hFile; /* file handle */ + DSP_STATUS status; + mm_segment_t fs; + + struct file*fileDesc = NULL; + DBC_Require(pszMode != NULL); + DBC_Require(pszFileName != NULL); + + GT_2trace(KFILE_debugMask, GT_ENTER, + "KFILE_Open: pszFileName %s, pszMode " + "%s\n", pszFileName, pszMode); + + /* create a KFILE object */ + MEM_AllocObject(hFile, struct KFILE_FileObj, SIGNATURE); + + if (hFile) { + fs = get_fs(); + set_fs(get_ds()); + /* Third argument is mode (permissions). Ignored unless creating file */ + fileDesc = filp_open(pszFileName, O_RDONLY, 0); + if ((IS_ERR(fileDesc)) || (fileDesc == NULL) || + (fileDesc->f_op == NULL) || (fileDesc->f_op->read == NULL) + || (fileDesc->f_op->llseek == NULL)) { + status = DSP_EFILE; + } else { + hFile->fileDesc = fileDesc; + hFile->fileName = (char *)pszFileName; + hFile->isOpen = true; + hFile->curPos = 0; + hFile->size = fileDesc->f_op->llseek(fileDesc, 0, + SEEK_END); + fileDesc->f_op->llseek(fileDesc, 0, SEEK_SET); + /* Return PID instead of process handle */ + hFile->owner_pid = current->pid; + + status = DSP_SOK; + } + set_fs(fs); + if (DSP_FAILED(status)) { + /* free memory, and clear handle */ + MEM_FreeObject(hFile); + hFile = NULL; + } + } else { + GT_0trace(KFILE_debugMask, GT_6CLASS, + "KFILE_Open: MEM_AllocObject failed\n"); + status = DSP_EMEMORY; + } + return hFile; +} + +/* + * ======== KFILE_Read ======== + * Purpose: + * Reads a specified number of bytes into a buffer. + */ +s32 +KFILE_Read(void __user*pBuffer, s32 cSize, s32 cCount, + struct KFILE_FileObj *hFile) +{ + u32 dwBytesRead = 0; + s32 cRetVal = 0; + mm_segment_t fs; + + DBC_Require(pBuffer != NULL); + + GT_4trace(KFILE_debugMask, GT_4CLASS, + "KFILE_Read: buffer 0x%x, cSize 0x%x," + "cCount 0x%x, hFile 0x%x\n", pBuffer, cSize, cCount, hFile); + + /* check for valid file handle */ + if (MEM_IsValidHandle(hFile, SIGNATURE)) { + if ((cSize > 0) && (cCount > 0) && pBuffer) { + /* read from file */ + fs = get_fs(); + set_fs(get_ds()); + dwBytesRead = hFile->fileDesc->f_op->read(hFile-> + fileDesc, pBuffer, cSize *cCount, + &(hFile->fileDesc->f_pos)); + set_fs(fs); + if (dwBytesRead) { + cRetVal = dwBytesRead / cSize; + hFile->curPos += dwBytesRead; + DBC_Assert((dwBytesRead / cSize) <= \ + (u32)cCount); + } else { + cRetVal = E_KFILE_ERROR; + GT_0trace(KFILE_debugMask, GT_6CLASS, + "KFILE_Read: sys_read() failed\n"); + } + } else { + cRetVal = DSP_EINVALIDARG; + GT_0trace(KFILE_debugMask, GT_6CLASS, + "KFILE_Read: Invalid argument(s)\n"); + } + } else { + cRetVal = E_KFILE_INVALIDHANDLE; + GT_0trace(KFILE_debugMask, GT_6CLASS, + "KFILE_Read: invalid file handle\n"); + } + + return cRetVal; +} + +/* + * ======== KFILE_Seek ======== + * Purpose: + * Sets the file position indicator. NOTE: we don't support seeking + * beyond the boundaries of a file. + */ +s32 KFILE_Seek(struct KFILE_FileObj *hFile, s32 lOffset, s32 cOrigin) +{ + s32 cRetVal = 0; /* 0 for success */ + u32 dwCurPos = 0; + + struct file *fileDesc = NULL; + + GT_3trace(KFILE_debugMask, GT_ENTER, "KFILE_Seek: hFile 0x%x, " + "lOffset 0x%x, cOrigin 0x%x\n", + hFile, lOffset, cOrigin); + + /* check for valid file handle */ + if (MEM_IsValidHandle(hFile, SIGNATURE)) { + /* based on the origin flag, move the internal pointer */ + + fileDesc = hFile->fileDesc; + switch (cOrigin) { + case KFILE_SEEK_SET: + dwCurPos = hFile->fileDesc->f_op->llseek(hFile-> + fileDesc, lOffset, SEEK_SET); + cRetVal = ((dwCurPos >= 0) ? 0 : E_KFILE_ERROR); + break; + + case KFILE_SEEK_CUR: + dwCurPos = hFile->fileDesc->f_op->llseek(hFile-> + fileDesc, lOffset, SEEK_CUR); + cRetVal = ((dwCurPos >= 0) ? 0 : E_KFILE_ERROR); + break; + case KFILE_SEEK_END: + dwCurPos = hFile->fileDesc->f_op->llseek(hFile-> + fileDesc, lOffset, SEEK_END); + cRetVal = ((dwCurPos >= 0) ? 0 : E_KFILE_ERROR); + break; + default: + cRetVal = E_KFILE_BADORIGINFLAG; + GT_0trace(KFILE_debugMask, GT_6CLASS, + "KFILE_Seek:bad origin flag\n"); + break; + } + } else { + cRetVal = E_KFILE_INVALIDHANDLE; + GT_0trace(KFILE_debugMask, GT_6CLASS, + "KFILE_Seek:invalid file handle\n"); + } + return cRetVal; +} + +/* + * ======== KFILE_Tell ======== + * Purpose: + * Reports the current value of the position indicator. We did not + * consider 64 bit long file size, which implies a 4GB file limit + * (2 to 32 power). + */ +s32 KFILE_Tell(struct KFILE_FileObj *hFile) +{ + u32 dwCurPos = 0; + s32 lRetVal = E_KFILE_ERROR; + + GT_1trace(KFILE_debugMask, GT_ENTER, "KFILE_Tell: hFile 0x%x\n", hFile); + + if (MEM_IsValidHandle(hFile, SIGNATURE)) { + + /* Get current position. */ + dwCurPos = hFile->fileDesc->f_op->llseek(hFile->fileDesc, 0, + SEEK_CUR); + if (dwCurPos >= 0) + lRetVal = dwCurPos; + + } else { + lRetVal = E_KFILE_INVALIDHANDLE; + GT_0trace(KFILE_debugMask, GT_6CLASS, + "KFILE_Seek:invalid file handle\n"); + } + return lRetVal; +} + diff --git a/drivers/dsp/bridge/services/list.c b/drivers/dsp/bridge/services/list.c new file mode 100644 index 0000000..7fa3e76 --- /dev/null +++ b/drivers/dsp/bridge/services/list.c @@ -0,0 +1,285 @@ +/* + * list.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== listce.c ======== + * Purpose + * Provides standard circular list handling functions. + * + * Public Functions: + * LST_Create + * LST_Delete + * LST_Exit + * LST_First + * LST_GetHead + * LST_Init + * LST_InitElem + * LST_InsertBefore + * LST_Next + * LST_PutTail + * LST_RemoveElem + * + *! Revision History + *! ================ + *! 06-Mar-2002 jeh Don't set element self to NULL in LST_RemoveElem(). + *! 10-Aug-2000 ag: Added LST_InsertBefore(). + *! 03-Feb-2000 rr: Module init/exit is handled by SERVICES Init/Exit. + *! GT Changes. + *! 22-Nov-1999 kc: Added changes from code review. + *! 10-Aug-1999 kc: Based on wsx-c18. + *! 16-Jun-1997 gp: Removed unnecessary enabling/disabling of interrupts around + *! list manipulation code. + *! 22-Oct-1996 gp: Added LST_RemoveElem, and LST_First/LST_Next iterators. + *! 10-Aug-1996 gp: Acquired from SMM for WinSPOX v. 1.1; renamed identifiers. + */ + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include + +/* ----------------------------------- This */ +#include + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask LST_debugMask = { NULL, NULL }; /* GT trace var. */ +#endif + +/* + * ======== LST_Create ======== + * Purpose: + * Allocates and initializes a circular list. + */ +struct LST_LIST *LST_Create(void) +{ + struct LST_LIST *pList; + + GT_0trace(LST_debugMask, GT_ENTER, "LST_Create: entered\n"); + + pList = (struct LST_LIST *) MEM_Calloc(sizeof(struct LST_LIST), + MEM_NONPAGED); + if (pList != NULL) { + pList->head.next = &pList->head; + pList->head.prev = &pList->head; + pList->head.self = NULL; + } + + return pList; +} + +/* + * ======== LST_Delete ======== + * Purpose: + * Removes a list by freeing its control structure's memory space. + */ +void LST_Delete(struct LST_LIST *pList) +{ + DBC_Require(pList != NULL); + + GT_1trace(LST_debugMask, GT_ENTER, "LST_Delete: pList 0x%x\n", pList); + + MEM_Free(pList); +} + +/* + * ======== LST_Exit ======== + * Purpose: + * Discontinue usage of the LST module. + */ +void LST_Exit(void) +{ + GT_0trace(LST_debugMask, GT_5CLASS, "LST_Exit\n"); +} + +/* + * ======== LST_First ======== + * Purpose: + * Returns a pointer to the first element of the list, or NULL if the + * list is empty. + */ +struct LST_ELEM *LST_First(struct LST_LIST *pList) +{ + struct LST_ELEM *pElem = NULL; + + DBC_Require(pList != NULL); + + GT_1trace(LST_debugMask, GT_ENTER, "LST_First: pList 0x%x\n", pList); + + if (!LST_IsEmpty(pList)) + pElem = pList->head.next; + + return pElem; +} + +/* + * ======== LST_GetHead ======== + * Purpose: + * "Pops" the head off the list and returns a pointer to it. + */ +struct LST_ELEM *LST_GetHead(struct LST_LIST *pList) +{ + struct LST_ELEM *pElem; + + DBC_Require(pList != NULL); + + GT_1trace(LST_debugMask, GT_ENTER, "LST_GetHead: pList 0x%x\n", pList); + + if (LST_IsEmpty(pList)) + return NULL; + + /* pElem is always valid because the list cannot be empty + * at this point */ + pElem = pList->head.next; + pList->head.next = pElem->next; + pElem->next->prev = &pList->head; + + return pElem->self; +} + +/* + * ======== LST_Init ======== + * Purpose: + * Initialize LST module private state. + */ +bool LST_Init(void) +{ + GT_create(&LST_debugMask, "LS"); /* LS for LSt module */ + + GT_0trace(LST_debugMask, GT_5CLASS, "LST_Init\n"); + + return true; +} + +/* + * ======== LST_InitElem ======== + * Purpose: + * Initializes a list element to default (cleared) values + */ +void LST_InitElem(struct LST_ELEM *pElem) +{ + DBC_Require(pElem != NULL); + + GT_1trace(LST_debugMask, GT_ENTER, "LST_InitElem: pElem 0x%x\n", pElem); + + if (pElem) { + pElem->next = NULL; + pElem->prev = NULL; + pElem->self = pElem; + } +} + +/* + * ======== LST_InsertBefore ======== + * Purpose: + * Insert the element before the existing element. + */ +void LST_InsertBefore(struct LST_LIST *pList, struct LST_ELEM *pElem, + struct LST_ELEM *pElemExisting) +{ + DBC_Require(pList != NULL); + DBC_Require(pElem != NULL); + DBC_Require(pElemExisting != NULL); + + GT_3trace(LST_debugMask, GT_ENTER, "LST_InsertBefore: pList 0x%x, " + "pElem 0x%x pElemExisting 0x%x\n", pList, pElem, + pElemExisting); + + pElemExisting->prev->next = pElem; + pElem->prev = pElemExisting->prev; + pElem->next = pElemExisting; + pElemExisting->prev = pElem; +} + +/* + * ======== LST_Next ======== + * Purpose: + * Returns a pointer to the next element of the list, or NULL if the + * next element is the head of the list or the list is empty. + */ +struct LST_ELEM *LST_Next(struct LST_LIST *pList, struct LST_ELEM *pCurElem) +{ + struct LST_ELEM *pNextElem = NULL; + + DBC_Require(pList != NULL); + DBC_Require(pCurElem != NULL); + + GT_2trace(LST_debugMask, GT_ENTER, + "LST_Next: pList 0x%x, pCurElem 0x%x\n", + pList, pCurElem); + + if (!LST_IsEmpty(pList)) { + if (pCurElem->next != &pList->head) + pNextElem = pCurElem->next; + } + + return pNextElem; +} + +/* + * ======== LST_PutTail ======== + * Purpose: + * Adds the specified element to the tail of the list + */ +void LST_PutTail(struct LST_LIST *pList, struct LST_ELEM *pElem) +{ + DBC_Require(pList != NULL); + DBC_Require(pElem != NULL); + + GT_2trace(LST_debugMask, GT_ENTER, + "LST_PutTail: pList 0x%x, pElem 0x%x\n", + pList, pElem); + + pElem->prev = pList->head.prev; + pElem->next = &pList->head; + pList->head.prev = pElem; + pElem->prev->next = pElem; + + DBC_Ensure(!LST_IsEmpty(pList)); +} + +/* + * ======== LST_RemoveElem ======== + * Purpose: + * Removes (unlinks) the given element from the list, if the list is not + * empty. Does not free the list element. + */ +void LST_RemoveElem(struct LST_LIST *pList, struct LST_ELEM *pCurElem) +{ + DBC_Require(pList != NULL); + DBC_Require(pCurElem != NULL); + + GT_2trace(LST_debugMask, GT_ENTER, + "LST_RemoveElem: pList 0x%x, pCurElem " + "0x%x\n", pList, pCurElem); + + if (!LST_IsEmpty(pList)) { + pCurElem->prev->next = pCurElem->next; + pCurElem->next->prev = pCurElem->prev; + + /* set elem fields to NULL to prevent illegal references */ + pCurElem->next = NULL; + pCurElem->prev = NULL; + } +} + diff --git a/drivers/dsp/bridge/services/mem.c b/drivers/dsp/bridge/services/mem.c new file mode 100644 index 0000000..0a10304 --- /dev/null +++ b/drivers/dsp/bridge/services/mem.c @@ -0,0 +1,599 @@ +/* + * mem.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== mem.c ======== + * Purpose: + * Implementation of platform specific memory services. + * + * Public Functions: + * MEM_Alloc + * MEM_AllocPhysMem + * MEM_Calloc + * MEM_Exit + * MEM_FlushCache + * MEM_Free + * MEM_FreePhysMem + * MEM_Init + * MEM_ExtPhysPoolInit + * + *! Revision History: + *! ================= + *! 18-Jan-2004 hp: Added support for External physical memory pool + *! 19-Apr-2004 sb: Added Alloc/Free PhysMem, FlushCache, VirtualToPhysical + *! 01-Sep-2001 ag: Code cleanup. + *! 02-May-2001 ag: MEM_[UnMap]LinearAddress revamped to align Phys to Virt. + *! Set PAGE_PHYSICAL if phy addr <= 512MB. Opposite uSoft doc! + *! 29-Aug-2000 rr: MEM_LinearAddress does not check for 512MB for non-x86. + *! 28-Mar-2000 rr: MEM_LinearAddress changed.Handles address larger than 512MB + *! 03-Feb-2000 rr: Module init/exit is handled by SERVICES Init/Exit. + *! GT Changes. + *! 22-Nov-1999 kc: Added changes from code review. + *! 16-Aug-1999 kc: modified for WinCE. + *! 20-Mar-1999 ag: SP 4 fix in MEM_UMBCalloc(). + *! Mdl offset now ORed not added to userBuf. + *! 23-Dec-1997 cr: Code review changes. + *! 08-Dec-1997 cr: Prepared for code review. + *! 24-Jun-1997 cr: Created. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- This */ +#include +#include + +/* ----------------------------------- Defines */ +#define MEM_512MB 0x1fffffff +#define memInfoSign 0x464E494D /* "MINF" (in reverse). */ + +#ifdef DEBUG +#define MEM_CHECK /* Use to detect source of memory leaks */ +#endif + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask MEM_debugMask = { NULL, NULL }; /* GT trace variable */ +#endif + +static u32 cRefs; /* module reference count */ + +static bool extPhysMemPoolEnabled; + +struct extPhysMemPool { + u32 physMemBase; + u32 physMemSize; + u32 virtMemBase; + u32 nextPhysAllocPtr; +}; + +static struct extPhysMemPool extMemPool; + +/* Information about each element allocated on heap */ +struct memInfo { + struct LST_ELEM link; /* Must be first */ + size_t size; + void *caller; + u32 dwSignature; /* Should be last */ +}; + +#ifdef MEM_CHECK + +/* + * This structure holds a linked list to all memory elements allocated on + * heap by DSP/BIOS Bridge. This is used to report memory leaks and free + * such elements while removing the DSP/BIOS Bridge driver + */ +struct memMan { + struct LST_LIST lst; + spinlock_t lock; +}; + +static struct memMan mMan; + +/* + * These functions are similar to LST_PutTail and LST_RemoveElem and are + * duplicated here to make MEM independent of LST + */ +static inline void MLST_PutTail(struct LST_LIST *pList, struct LST_ELEM *pElem) +{ + pElem->prev = pList->head.prev; + pElem->next = &pList->head; + pList->head.prev = pElem; + pElem->prev->next = pElem; + pElem->self = pElem; +} + +static inline void MLST_RemoveElem(struct LST_LIST *pList, + struct LST_ELEM *pCurElem) +{ + pCurElem->prev->next = pCurElem->next; + pCurElem->next->prev = pCurElem->prev; + pCurElem->next = NULL; + pCurElem->prev = NULL; +} + +static void MEM_Check(void) +{ + struct memInfo *pMem; + struct LST_ELEM *last = &mMan.lst.head; + struct LST_ELEM *curr = mMan.lst.head.next; + + if (!LST_IsEmpty(&mMan.lst)) { + GT_0trace(MEM_debugMask, GT_7CLASS, "*** MEMORY LEAK ***\n"); + GT_0trace(MEM_debugMask, GT_7CLASS, + "Addr Size Caller\n"); + while (curr != last) { + pMem = (struct memInfo *)curr; + curr = curr->next; + if ((u32)pMem > PAGE_OFFSET && + MEM_IsValidHandle(pMem, memInfoSign)) { + GT_3trace(MEM_debugMask, GT_7CLASS, + "%lx %d\t [<%p>]\n", + (u32) pMem + sizeof(struct memInfo), + pMem->size, pMem->caller); + MLST_RemoveElem(&mMan.lst, + (struct LST_ELEM *) pMem); + kfree(pMem); + } else { + GT_1trace(MEM_debugMask, GT_7CLASS, + "Invalid allocation or " + "Buffer underflow at %x\n", + (u32)pMem + sizeof(struct memInfo)); + break; + } + } + } + DBC_Ensure(LST_IsEmpty(&mMan.lst)); +} + +#endif + +void MEM_ExtPhysPoolInit(u32 poolPhysBase, u32 poolSize) +{ + u32 poolVirtBase; + + /* get the virtual address for the physical memory pool passed */ + poolVirtBase = (u32)ioremap(poolPhysBase, poolSize); + + if ((void **)poolVirtBase == NULL) { + GT_0trace(MEM_debugMask, GT_7CLASS, + "[PHYS_POOL]Mapping External " + "physical memory to virt failed \n"); + extPhysMemPoolEnabled = false; + } else { + extMemPool.physMemBase = poolPhysBase; + extMemPool.physMemSize = poolSize; + extMemPool.virtMemBase = poolVirtBase; + extMemPool.nextPhysAllocPtr = poolPhysBase; + extPhysMemPoolEnabled = true; + GT_3trace(MEM_debugMask, GT_1CLASS, + "ExtMemory Pool details " "Pool" + "Physical mem base = %0x " "Pool Physical mem size " + "= %0x" "Pool Virtual mem base = %0x \n", + poolPhysBase, poolSize, poolVirtBase); + } +} + +static void MEM_ExtPhysPoolRelease(void) +{ + GT_0trace(MEM_debugMask, GT_1CLASS, + "Releasing External memory pool \n"); + if (extPhysMemPoolEnabled) { + iounmap((void *)(extMemPool.virtMemBase)); + extPhysMemPoolEnabled = false; + } +} + +/* + * ======== MEM_ExtPhysMemAlloc ======== + * Purpose: + * Allocate physically contiguous, uncached memory from external memory pool + */ + +static void *MEM_ExtPhysMemAlloc(u32 bytes, u32 align, OUT u32 *pPhysAddr) +{ + u32 newAllocPtr; + u32 offset; + u32 virtAddr; + + GT_2trace(MEM_debugMask, GT_1CLASS, + "Ext Memory Allocation" "bytes=0x%x , " + "align=0x%x \n", bytes, align); + if (align == 0) { + GT_0trace(MEM_debugMask, GT_7CLASS, + "ExtPhysical Memory Allocation " + "No alignment request in allocation call !! \n"); + align = 1; + } + if (bytes > ((extMemPool.physMemBase + extMemPool.physMemSize) + - extMemPool.nextPhysAllocPtr)) { + GT_1trace(MEM_debugMask, GT_7CLASS, + "ExtPhysical Memory Allocation " + "unable to allocate memory for bytes = 0x%x \n", + bytes); + pPhysAddr = NULL; + return NULL; + } else { + offset = (extMemPool.nextPhysAllocPtr & (align - 1)); + if (offset == 0) + newAllocPtr = extMemPool.nextPhysAllocPtr; + else + newAllocPtr = (extMemPool.nextPhysAllocPtr) + + (align - offset); + if ((newAllocPtr + bytes) <= + (extMemPool.physMemBase + extMemPool.physMemSize)) { + /* we can allocate */ + *pPhysAddr = newAllocPtr; + extMemPool.nextPhysAllocPtr = newAllocPtr + bytes; + virtAddr = extMemPool.virtMemBase + (newAllocPtr - + extMemPool.physMemBase); + GT_2trace(MEM_debugMask, GT_1CLASS, + "Ext Memory Allocation succedded " + "phys address=0x%x , virtaddress=0x%x \n", + newAllocPtr, virtAddr); + return (void *)virtAddr; + } else { + *pPhysAddr = 0; + return NULL; + } + } +} + +/* + * ======== MEM_Alloc ======== + * Purpose: + * Allocate memory from the paged or non-paged pools. + */ +void *MEM_Alloc(u32 cBytes, enum MEM_POOLATTRS type) +{ + struct memInfo *pMem = NULL; + + GT_2trace(MEM_debugMask, GT_ENTER, + "MEM_Alloc: cBytes 0x%x\ttype 0x%x\n", cBytes, type); + if (cBytes > 0) { + switch (type) { + case MEM_NONPAGED: + /* If non-paged memory required, see note at top of file. */ + case MEM_PAGED: +#ifndef MEM_CHECK + pMem = kmalloc(cBytes, + (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL); +#else + pMem = kmalloc(cBytes + sizeof(struct memInfo), + (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL); + if (pMem) { + pMem->size = cBytes; + pMem->caller = __builtin_return_address(0); + pMem->dwSignature = memInfoSign; + + spin_lock(&mMan.lock); + MLST_PutTail(&mMan.lst, + (struct LST_ELEM *)pMem); + spin_unlock(&mMan.lock); + + pMem = (void *)((u32)pMem + + sizeof(struct memInfo)); + } +#endif + break; + case MEM_LARGEVIRTMEM: +#ifndef MEM_CHECK + /* FIXME - Replace with 'vmalloc' after BP fix */ + pMem = __vmalloc(cBytes, + (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL, PAGE_KERNEL); +#else + /* FIXME - Replace with 'vmalloc' after BP fix */ + pMem = __vmalloc((cBytes + sizeof(struct memInfo)), + (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL, PAGE_KERNEL); + if (pMem) { + pMem->size = cBytes; + pMem->caller = __builtin_return_address(0); + pMem->dwSignature = memInfoSign; + + spin_lock(&mMan.lock); + MLST_PutTail(&mMan.lst, + (struct LST_ELEM *) pMem); + spin_unlock(&mMan.lock); + + pMem = (void *)((u32)pMem + + sizeof(struct memInfo)); + } +#endif + break; + + default: + GT_0trace(MEM_debugMask, GT_6CLASS, + "MEM_Alloc: unexpected " + "MEM_POOLATTRS value\n"); + break; + } + } + + return pMem; +} + +/* + * ======== MEM_AllocPhysMem ======== + * Purpose: + * Allocate physically contiguous, uncached memory + */ +void *MEM_AllocPhysMem(u32 cBytes, u32 ulAlign, OUT u32 *pPhysicalAddress) +{ + void *pVaMem = NULL; + dma_addr_t paMem; + + DBC_Require(cRefs > 0); + + GT_2trace(MEM_debugMask, GT_ENTER, + "MEM_AllocPhysMem: cBytes 0x%x\tulAlign" + "0x%x\n", cBytes, ulAlign); + + if (cBytes > 0) { + if (extPhysMemPoolEnabled) { + pVaMem = MEM_ExtPhysMemAlloc(cBytes, ulAlign, + (u32 *)&paMem); + } else + pVaMem = dma_alloc_coherent(NULL, cBytes, &paMem, + (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL); + if (pVaMem == NULL) { + *pPhysicalAddress = 0; + GT_1trace(MEM_debugMask, GT_6CLASS, + "MEM_AllocPhysMem failed: " + "0x%x\n", pVaMem); + } else { + *pPhysicalAddress = paMem; + } + } + return pVaMem; +} + +/* + * ======== MEM_Calloc ======== + * Purpose: + * Allocate zero-initialized memory from the paged or non-paged pools. + */ +void *MEM_Calloc(u32 cBytes, enum MEM_POOLATTRS type) +{ + struct memInfo *pMem = NULL; + + GT_2trace(MEM_debugMask, GT_ENTER, + "MEM_Calloc: cBytes 0x%x\ttype 0x%x\n", + cBytes, type); + + if (cBytes > 0) { + switch (type) { + case MEM_NONPAGED: + /* If non-paged memory required, see note at top of file. */ + case MEM_PAGED: +#ifndef MEM_CHECK + pMem = kmalloc(cBytes, + (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL); + if (pMem) + memset(pMem, 0, cBytes); + +#else + pMem = kmalloc(cBytes + sizeof(struct memInfo), + (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL); + if (pMem) { + memset((void *)((u32)pMem + + sizeof(struct memInfo)), 0, cBytes); + pMem->size = cBytes; + pMem->caller = __builtin_return_address(0); + pMem->dwSignature = memInfoSign; + spin_lock(&mMan.lock); + MLST_PutTail(&mMan.lst, + (struct LST_ELEM *) pMem); + spin_unlock(&mMan.lock); + pMem = (void *)((u32)pMem + + sizeof(struct memInfo)); + } +#endif + break; + case MEM_LARGEVIRTMEM: +#ifndef MEM_CHECK + /* FIXME - Replace with 'vmalloc' after BP fix */ + pMem = __vmalloc(cBytes, + (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL, PAGE_KERNEL); + if (pMem) + memset(pMem, 0, cBytes); + +#else + /* FIXME - Replace with 'vmalloc' after BP fix */ + pMem = __vmalloc(cBytes + sizeof(struct memInfo), + (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL, PAGE_KERNEL); + if (pMem) { + memset((void *)((u32)pMem + + sizeof(struct memInfo)), 0, cBytes); + pMem->size = cBytes; + pMem->caller = __builtin_return_address(0); + pMem->dwSignature = memInfoSign; + spin_lock(&mMan.lock); + MLST_PutTail(&mMan.lst, (struct LST_ELEM *) + pMem); + spin_unlock(&mMan.lock); + pMem = (void *)((u32)pMem + + sizeof(struct memInfo)); + } +#endif + break; + default: + GT_1trace(MEM_debugMask, GT_6CLASS, + "MEM_Calloc: unexpected " + "MEM_POOLATTRS value 0x%x\n", type); + break; + } + } + + return pMem; +} + +/* + * ======== MEM_Exit ======== + * Purpose: + * Discontinue usage of the MEM module. + */ +void MEM_Exit(void) +{ + DBC_Require(cRefs > 0); + + GT_1trace(MEM_debugMask, GT_5CLASS, "MEM_Exit: cRefs 0x%x\n", cRefs); + + cRefs--; +#ifdef MEM_CHECK + if (cRefs == 0) + MEM_Check(); + +#endif + MEM_ExtPhysPoolRelease(); + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== MEM_FlushCache ======== + * Purpose: + * Flush cache + */ +void MEM_FlushCache(void *pMemBuf, u32 cBytes, s32 FlushType) +{ + DBC_Require(cRefs > 0); + + switch (FlushType) { + /* invalidate only */ + case PROC_INVALIDATE_MEM: + dmac_inv_range(pMemBuf, pMemBuf + cBytes); + outer_inv_range(__pa((u32)pMemBuf), __pa((u32)pMemBuf + + cBytes)); + break; + /* writeback only */ + case PROC_WRITEBACK_MEM: + dmac_clean_range(pMemBuf, pMemBuf + cBytes); + outer_clean_range(__pa((u32)pMemBuf), __pa((u32)pMemBuf + + cBytes)); + break; + /* writeback and invalidate */ + case PROC_WRITEBACK_INVALIDATE_MEM: + dmac_flush_range(pMemBuf, pMemBuf + cBytes); + outer_flush_range(__pa((u32)pMemBuf), __pa((u32)pMemBuf + + cBytes)); + break; + default: + GT_1trace(MEM_debugMask, GT_6CLASS, "MEM_FlushCache: invalid " + "FlushMemType 0x%x\n", FlushType); + break; + } + +} + + +/* + * ======== MEM_Free ======== + * Purpose: + * Free the given block of system memory. + */ +void MEM_Free(IN void *pMemBuf) +{ +#ifdef MEM_CHECK + struct memInfo *pMem = (void *)((u32)pMemBuf - sizeof(struct memInfo)); +#endif + + DBC_Require(pMemBuf != NULL); + + GT_1trace(MEM_debugMask, GT_ENTER, "MEM_Free: pMemBufs 0x%x\n", + pMemBuf); + + if (pMemBuf) { +#ifndef MEM_CHECK + kfree(pMemBuf); +#else + if (pMem) { + if (pMem->dwSignature == memInfoSign) { + spin_lock(&mMan.lock); + MLST_RemoveElem(&mMan.lst, + (struct LST_ELEM *) pMem); + spin_unlock(&mMan.lock); + pMem->dwSignature = 0; + kfree(pMem); + } else { + GT_1trace(MEM_debugMask, GT_7CLASS, + "Invalid allocation or " + "Buffer underflow at %x\n", + (u32) pMem + sizeof(struct memInfo)); + } + } +#endif + } +} + +/* + * ======== MEM_FreePhysMem ======== + * Purpose: + * Free the given block of physically contiguous memory. + */ +void MEM_FreePhysMem(void *pVirtualAddress, u32 pPhysicalAddress, + u32 cBytes) +{ + DBC_Require(cRefs > 0); + DBC_Require(pVirtualAddress != NULL); + + GT_1trace(MEM_debugMask, GT_ENTER, "MEM_FreePhysMem: pVirtualAddress " + "0x%x\n", pVirtualAddress); + + if (!extPhysMemPoolEnabled) + dma_free_coherent(NULL, cBytes, pVirtualAddress, + pPhysicalAddress); +} + +/* + * ======== MEM_Init ======== + * Purpose: + * Initialize MEM module private state. + */ +bool MEM_Init(void) +{ + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { + GT_create(&MEM_debugMask, "MM"); /* MM for MeM module */ + +#ifdef MEM_CHECK + mMan.lst.head.next = &mMan.lst.head; + mMan.lst.head.prev = &mMan.lst.head; + mMan.lst.head.self = NULL; + spin_lock_init(&mMan.lock); +#endif + + } + + cRefs++; + + GT_1trace(MEM_debugMask, GT_5CLASS, "MEM_Init: cRefs 0x%x\n", cRefs); + + DBC_Ensure(cRefs > 0); + + return true; +} diff --git a/drivers/dsp/bridge/services/ntfy.c b/drivers/dsp/bridge/services/ntfy.c new file mode 100644 index 0000000..2eff3eb --- /dev/null +++ b/drivers/dsp/bridge/services/ntfy.c @@ -0,0 +1,329 @@ +/* + * ntfy.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== ntfyce.c ======== + * Purpose: + * Manage lists of notification events. + * + * Public Functions: + * NTFY_Create + * NTFY_Delete + * NTFY_Exit + * NTFY_Init + * NTFY_Notify + * NTFY_Register + * + *! Revision History: + *! ================= + *! 06-Feb-2003 kc Removed DSP_POSTMESSAGE related code. + *! 05-Nov-2001 kc Updated DSP_HNOTIFICATION structure. + *! 10-May-2001 jeh Removed SERVICES module init/exit from NTFY_Init/Exit. + *! NTFY_Register() returns DSP_ENOTIMPL for all but + *! DSP_SIGNALEVENT. + *! 12-Oct-2000 jeh Use MEM_IsValidHandle(). + *! 07-Sep-2000 jeh Created. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include + +/* ----------------------------------- This */ +#include + +/* ----------------------------------- Defines, Data Structures, Typedefs */ +#define NTFY_SIGNATURE 0x5946544e /* "YFTN" */ + +/* + * ======== NTFY_OBJECT ======== + */ +struct NTFY_OBJECT { + u32 dwSignature; /* For object validation */ + struct LST_LIST *notifyList; /* List of NOTIFICATION objects */ + struct SYNC_CSOBJECT *hSync; /* For critical sections */ +}; + +/* + * ======== NOTIFICATION ======== + * This object will be created when a client registers for events. + */ +struct NOTIFICATION { + struct LST_ELEM listElem; + u32 uEventMask; /* Events to be notified about */ + u32 uNotifyType; /* Type of notification to be sent */ + + /* + * We keep a copy of the event name to check if the event has + * already been registered. (SYNC also keeps a copy of the name). + */ + char *pstrName; /* Name of event */ + HANDLE hEvent; /* Handle for notification */ + struct SYNC_OBJECT *hSync; +}; + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask NTFY_debugMask = { NULL, NULL }; /* GT trace variable */ +#endif + +/* ----------------------------------- Function Prototypes */ +static void DeleteNotify(struct NOTIFICATION *pNotify); + +/* + * ======== NTFY_Create ======== + * Purpose: + * Create an empty list of notifications. + */ +DSP_STATUS NTFY_Create(struct NTFY_OBJECT **phNtfy) +{ + struct NTFY_OBJECT *pNtfy; + DSP_STATUS status = DSP_SOK; + + DBC_Require(phNtfy != NULL); + + *phNtfy = NULL; + MEM_AllocObject(pNtfy, struct NTFY_OBJECT, NTFY_SIGNATURE); + + if (pNtfy) { + + status = SYNC_InitializeDPCCS(&pNtfy->hSync); + if (DSP_SUCCEEDED(status)) { + pNtfy->notifyList = LST_Create(); + if (pNtfy->notifyList == NULL) { + (void) SYNC_DeleteCS(pNtfy->hSync); + MEM_FreeObject(pNtfy); + status = DSP_EMEMORY; + } else { + *phNtfy = pNtfy; + } + } + } else { + status = DSP_EMEMORY; + } + + DBC_Ensure((DSP_FAILED(status) && *phNtfy == NULL) || + (DSP_SUCCEEDED(status) && MEM_IsValidHandle((*phNtfy), + NTFY_SIGNATURE))); + + return status; +} + +/* + * ======== NTFY_Delete ======== + * Purpose: + * Free resources allocated in NTFY_Create. + */ +void NTFY_Delete(struct NTFY_OBJECT *hNtfy) +{ + struct NOTIFICATION *pNotify; + + DBC_Require(MEM_IsValidHandle(hNtfy, NTFY_SIGNATURE)); + + /* Remove any elements remaining in list */ + if (hNtfy->notifyList) { + while ((pNotify = (struct NOTIFICATION *)LST_GetHead(hNtfy-> + notifyList))) { + DeleteNotify(pNotify); + } + DBC_Assert(LST_IsEmpty(hNtfy->notifyList)); + LST_Delete(hNtfy->notifyList); + } + if (hNtfy->hSync) + (void)SYNC_DeleteCS(hNtfy->hSync); + + MEM_FreeObject(hNtfy); +} + +/* + * ======== NTFY_Exit ======== + * Purpose: + * Discontinue usage of NTFY module. + */ +void NTFY_Exit(void) +{ + GT_0trace(NTFY_debugMask, GT_5CLASS, "Entered NTFY_Exit\n"); +} + +/* + * ======== NTFY_Init ======== + * Purpose: + * Initialize the NTFY module. + */ +bool NTFY_Init(void) +{ + GT_create(&NTFY_debugMask, "NY"); /* "NY" for NtfY */ + + GT_0trace(NTFY_debugMask, GT_5CLASS, "NTFY_Init()\n"); + + return true; +} + +/* + * ======== NTFY_Notify ======== + * Purpose: + * Execute notify function (signal event) for every + * element in the notification list that is to be notified about the + * event specified in uEventMask. + */ +void NTFY_Notify(struct NTFY_OBJECT *hNtfy, u32 uEventMask) +{ + struct NOTIFICATION *pNotify; + + DBC_Require(MEM_IsValidHandle(hNtfy, NTFY_SIGNATURE)); + + /* + * Go through notifyList and notify all clients registered for + * uEventMask events. + */ + + (void) SYNC_EnterCS(hNtfy->hSync); + + pNotify = (struct NOTIFICATION *)LST_First(hNtfy->notifyList); + while (pNotify != NULL) { + if (pNotify->uEventMask & uEventMask) { + /* Notify */ + if (pNotify->uNotifyType == DSP_SIGNALEVENT) + (void)SYNC_SetEvent(pNotify->hSync); + + } + pNotify = (struct NOTIFICATION *)LST_Next(hNtfy->notifyList, + (struct LST_ELEM *)pNotify); + } + + (void) SYNC_LeaveCS(hNtfy->hSync); +} + +/* + * ======== NTFY_Register ======== + * Purpose: + * Add a notification element to the list. If the notification is already + * registered, and uEventMask != 0, the notification will get posted for + * events specified in the new event mask. If the notification is already + * registered and uEventMask == 0, the notification will be unregistered. + */ +DSP_STATUS NTFY_Register(struct NTFY_OBJECT *hNtfy, + struct DSP_NOTIFICATION *hNotification, + u32 uEventMask, u32 uNotifyType) +{ + struct NOTIFICATION *pNotify; + struct SYNC_ATTRS syncAttrs; + DSP_STATUS status = DSP_SOK; + + DBC_Require(MEM_IsValidHandle(hNtfy, NTFY_SIGNATURE)); + + if (hNotification == NULL) + status = DSP_EHANDLE; + + /* Return DSP_ENOTIMPL if uNotifyType is not supported */ + if (DSP_SUCCEEDED(status)) { + if (!IsValidNotifyMask(uNotifyType)) + status = DSP_ENOTIMPL; + + } + + if (DSP_FAILED(status)) + return status; + + (void)SYNC_EnterCS(hNtfy->hSync); + + pNotify = (struct NOTIFICATION *)LST_First(hNtfy->notifyList); + while (pNotify != NULL) { + /* If there is more than one notification type, each + * type may require its own handler code. */ + + if (hNotification->handle == pNotify->hSync) { + /* found */ + break; + } + pNotify = (struct NOTIFICATION *)LST_Next(hNtfy->notifyList, + (struct LST_ELEM *)pNotify); + } + if (pNotify == NULL) { + /* Not registered */ + if (uEventMask == 0) { + status = DSP_EVALUE; + } else { + /* Allocate NOTIFICATION object, add to list */ + pNotify = MEM_Calloc(sizeof(struct NOTIFICATION), + MEM_PAGED); + if (pNotify == NULL) + status = DSP_EMEMORY; + + } + if (DSP_SUCCEEDED(status)) { + LST_InitElem((struct LST_ELEM *) pNotify); + /* If there is more than one notification type, each + * type may require its own handler code. */ + status = SYNC_OpenEvent(&pNotify->hSync, &syncAttrs); + hNotification->handle = pNotify->hSync; + + if (DSP_SUCCEEDED(status)) { + pNotify->uEventMask = uEventMask; + pNotify->uNotifyType = uNotifyType; + LST_PutTail(hNtfy->notifyList, + (struct LST_ELEM *)pNotify); + } else { + DeleteNotify(pNotify); + } + } + } else { + /* Found in list */ + if (uEventMask == 0) { + /* Remove from list and free */ + LST_RemoveElem(hNtfy->notifyList, + (struct LST_ELEM *)pNotify); + DeleteNotify(pNotify); + } else { + /* Update notification mask (type shouldn't change) */ + pNotify->uEventMask = uEventMask; + } + } + (void)SYNC_LeaveCS(hNtfy->hSync); + return status; +} + +/* + * ======== DeleteNotify ======== + * Purpose: + * Free the notification object. + */ +static void DeleteNotify(struct NOTIFICATION *pNotify) +{ + if (pNotify->hSync) + (void) SYNC_CloseEvent(pNotify->hSync); + + if (pNotify->pstrName) + MEM_Free(pNotify->pstrName); + + MEM_Free(pNotify); +} + diff --git a/drivers/dsp/bridge/services/reg.c b/drivers/dsp/bridge/services/reg.c new file mode 100644 index 0000000..0d85f41 --- /dev/null +++ b/drivers/dsp/bridge/services/reg.c @@ -0,0 +1,196 @@ +/* + * reg.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== regce.c ======== + * Purpose: + * Provide registry functions. + * + * Public Functions: + * REG_DeleteValue + * REG_EnumValue + * REG_Exit + * REG_GetValue + * REG_Init + * REG_SetValue + * + *! Revision History: + *! ================ + * + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include + +/* ----------------------------------- Others */ +#include + +/* ----------------------------------- This */ +#include +#include + +#if GT_TRACE +struct GT_Mask REG_debugMask = { NULL, NULL }; /* GT trace var. */ +#endif + +/* + * ======== REG_DeleteValue ======== + * Deletes a registry entry value. NOTE: A registry entry value is not the + * same as * a registry key. + */ +DSP_STATUS REG_DeleteValue(OPTIONAL IN HANDLE *phKey, IN CONST char *pstrSubkey, + IN CONST char *pstrValue) +{ + DSP_STATUS status; + DBC_Require(pstrSubkey && pstrValue); + DBC_Require(phKey == NULL); + DBC_Require(strlen(pstrSubkey) < REG_MAXREGPATHLENGTH); + DBC_Require(strlen(pstrValue) < REG_MAXREGPATHLENGTH); + + GT_0trace(REG_debugMask, GT_ENTER, "REG_DeleteValue: entered\n"); + + /* Note that we don't use phKey */ + if (regsupDeleteValue(pstrSubkey, pstrValue) == DSP_SOK) + status = DSP_SOK; + else + status = DSP_EFAIL; + + return status; +} + +/* + * ======== REG_EnumValue ======== + * Enumerates a registry key and retrieve values stored under the key. + * We will assume the input pdwValueSize is smaller than + * REG_MAXREGPATHLENGTH for implementation purposes. + */ +DSP_STATUS REG_EnumValue(IN HANDLE *phKey, IN u32 dwIndex, + IN CONST char *pstrKey, IN OUT char *pstrValue, + IN OUT u32 *pdwValueSize, IN OUT char *pstrData, + IN OUT u32 *pdwDataSize) +{ + DSP_STATUS status; + + DBC_Require(pstrKey && pstrValue && pdwValueSize && pstrData && + pdwDataSize); + DBC_Require(*pdwValueSize <= REG_MAXREGPATHLENGTH); + DBC_Require(phKey == NULL); + DBC_Require(strlen(pstrKey) < REG_MAXREGPATHLENGTH); + + GT_0trace(REG_debugMask, GT_ENTER, "REG_EnumValue: entered\n"); + + status = regsupEnumValue(dwIndex, pstrKey, pstrValue, pdwValueSize, + pstrData, pdwDataSize); + + return status; +} + +/* + * ======== REG_Exit ======== + * Discontinue usage of the REG module. + */ +void REG_Exit(void) +{ + GT_0trace(REG_debugMask, GT_5CLASS, "REG_Exit\n"); + + regsupExit(); +} + +/* + * ======== REG_GetValue ======== + * Retrieve a value from the registry. + */ +DSP_STATUS REG_GetValue(OPTIONAL IN HANDLE *phKey, IN CONST char *pstrSubkey, + IN CONST char *pstrValue, OUT u8 *pbData, + IN OUT u32 *pdwDataSize) +{ + DSP_STATUS status; + + DBC_Require(pstrSubkey && pstrValue && pbData); + DBC_Require(phKey == NULL); + DBC_Require(strlen(pstrSubkey) < REG_MAXREGPATHLENGTH); + DBC_Require(strlen(pstrValue) < REG_MAXREGPATHLENGTH); + + GT_0trace(REG_debugMask, GT_ENTER, "REG_GetValue: entered\n"); + + /* We need to use regsup calls... */ + /* ...for now we don't need the key handle or */ + /* the subkey, all we need is the value to lookup. */ + if (regsupGetValue((char *)pstrValue, pbData, pdwDataSize) == DSP_SOK) + status = DSP_SOK; + else + status = DSP_EFAIL; + + return status; +} + +/* + * ======== REG_Init ======== + * Initialize the REG module's private state. + */ +bool REG_Init(void) +{ + bool fInit; + + GT_create(®_debugMask, "RG"); /* RG for ReG */ + + fInit = regsupInit(); + + GT_0trace(REG_debugMask, GT_5CLASS, "REG_Init\n"); + + return fInit; +} + +/* + * ======== REG_SetValue ======== + * Set a value in the registry. + */ +DSP_STATUS REG_SetValue(OPTIONAL IN HANDLE *phKey, IN CONST char *pstrSubkey, + IN CONST char *pstrValue, IN CONST u32 dwType, + IN u8 *pbData, IN u32 dwDataSize) +{ + DSP_STATUS status; + + DBC_Require(pstrValue && pbData); + DBC_Require(phKey == NULL); + DBC_Require(dwDataSize > 0); + DBC_Require(strlen(pstrValue) < REG_MAXREGPATHLENGTH); + + /* We need to use regsup calls... */ + /* ...for now we don't need the key handle or */ + /* the subkey, all we need is the value to lookup. */ + if (regsupSetValue((char *)pstrValue, pbData, dwDataSize) == DSP_SOK) + status = DSP_SOK; + else + status = DSP_EFAIL; + + return status; +} + diff --git a/drivers/dsp/bridge/services/regsup.c b/drivers/dsp/bridge/services/regsup.c new file mode 100644 index 0000000..5251b68 --- /dev/null +++ b/drivers/dsp/bridge/services/regsup.c @@ -0,0 +1,368 @@ +/* + * regsup.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== regsup.c ======== + * Purpose: + * Provide registry support functions. + * + *! Revision History: + *! ================ + *! 28-May-2002 map: Integrated PSI's dspimage update mechanism + *! 11-May-2002 gp: Turned PERF "on". + *! 21-May-2002 map: Fixed bug in SetValue - if resizing datasize, set + *! new size too + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include + +/* ----------------------------------- This */ +#include + +struct RegValueStruct { + char name[BRIDGE_MAX_NAME_SIZE]; /* Name of a given value entry */ + u32 dataSize; /* Size of the data */ + void *pData; /* Pointer to the actual data */ +}; + +struct RegKeyStruct { + /*The current number of value entries this key has*/ + u32 numValueEntries; + /* Array of value entries */ + struct RegValueStruct values[BRIDGE_MAX_NUM_REG_ENTRIES]; +}; + + +/* Pointer to the registry support key */ +static struct RegKeyStruct *pRegKey; + +#if GT_TRACE +extern struct GT_Mask REG_debugMask; /* GT trace var. */ +/* + * ======== printS ======== + * Purpose: + * Displays printable characters in pBuf, if any. + */ +static inline void printS(void *pBuf) +{ + int pos = 0; + if (*(REG_debugMask).flags & (GT_2CLASS)) { + while (*(u8 *)((pBuf)+pos) >= ' ' && + *(u8 *)((pBuf)+pos) <= '~') { + GT_1trace(REG_debugMask, GT_2CLASS, "%c", + *(u8 *)((pBuf) + pos++)); + } + + GT_0trace(REG_debugMask, GT_2CLASS, "\n"); + } +} +#else +#define printS(pBuf) +#endif + +/* + * ======== regsupInit ======== + * Purpose: + * Initialize the Registry Support module's private state. + */ +bool regsupInit(void) +{ + if (pRegKey != NULL) + return true; + + /* Need to allocate and setup our registry. */ + pRegKey = MEM_Calloc(sizeof(struct RegKeyStruct), MEM_NONPAGED); + if (pRegKey == NULL) + return false; + + return true; +} + +/* + * ======== regsupExit ======== + * Purpose: + * Release all registry support allocations. + */ +void regsupExit(void) +{ + u32 i; + + /* Make sure data has actually been allocated. */ + if (pRegKey == NULL) { + /* Nothing initialized.return! */ + return; + } + + GT_1trace(REG_debugMask, GT_2CLASS, "pRegKey->numValueEntries %d\n", + pRegKey->numValueEntries); + + /* Now go through each entry and free all resources. */ + for (i = 0; ((i < BRIDGE_MAX_NUM_REG_ENTRIES) && + (i < pRegKey->numValueEntries)); i++) { + if (pRegKey->values[i].name[0] != '\0') { + /* We have a valid entry.free it up! */ + if (pRegKey->values[i].pData != NULL) { + GT_3trace(REG_debugMask, GT_2CLASS, + "E %d\t %s DATA %x ", i, + pRegKey->values[i].name, + *(u32 *)pRegKey->values[i].pData); + printS((u8 *)(pRegKey->values[i].pData)); + MEM_Free(pRegKey->values[i].pData); + } + pRegKey->values[i].pData = NULL; + pRegKey->values[i].dataSize = 0; + pRegKey->values[i].name[0] = '\0'; + } + } + + /* Now that all of the resources are freed up, free the main one! */ + MEM_Free(pRegKey); + + /* Don't forget to NULL out the global entry! */ + pRegKey = NULL; +} + +/* + * ======== regsupGetValue ======== + * Purpose: + * Get the value of the entry having the given name. + */ +DSP_STATUS regsupGetValue(char *valName, void *pBuf, u32 *dataSize) +{ + DSP_STATUS retVal = DSP_EFAIL; + u32 i; + + /* Need to search through the entries looking for the right one. */ + for (i = 0; i < pRegKey->numValueEntries; i++) { + /* See if the name matches. */ + if (strncmp(pRegKey->values[i].name, valName, + BRIDGE_MAX_NAME_SIZE) == 0) { + + /* We have a match! Copy out the data. */ + memcpy(pBuf, pRegKey->values[i].pData, + pRegKey->values[i].dataSize); + + /* Get the size for the caller. */ + *dataSize = pRegKey->values[i].dataSize; + + /* Set our status to good and exit. */ + retVal = DSP_SOK; + break; + } + } + + if (DSP_SUCCEEDED(retVal)) { + GT_2trace(REG_debugMask, GT_2CLASS, "G %s DATA %x ", valName, + *(u32 *)pBuf); + printS((u8 *)pBuf); + } else { + GT_1trace(REG_debugMask, GT_3CLASS, "G %s FAILED\n", valName); + } + + return retVal; +} + +/* + * ======== regsupSetValue ======== + * Purpose: + * Sets the value of the entry having the given name. + */ +DSP_STATUS regsupSetValue(char *valName, void *pBuf, u32 dataSize) +{ + DSP_STATUS retVal = DSP_EFAIL; + u32 i; + + GT_2trace(REG_debugMask, GT_2CLASS, "S %s DATA %x ", valName, + *(u32 *)pBuf); + printS((u8 *)pBuf); + + /* Need to search through the entries looking for the right one. */ + for (i = 0; i < pRegKey->numValueEntries; i++) { + /* See if the name matches. */ + if (strncmp(pRegKey->values[i].name, valName, + BRIDGE_MAX_NAME_SIZE) == 0) { + /* Make sure the new data size is the same. */ + if (dataSize != pRegKey->values[i].dataSize) { + /* The caller needs a different data size! */ + MEM_Free(pRegKey->values[i].pData); + pRegKey->values[i].pData = MEM_Alloc(dataSize, + MEM_NONPAGED); + if (pRegKey->values[i].pData == NULL) + break; + + } + + /* We have a match! Copy out the data. */ + memcpy(pRegKey->values[i].pData, pBuf, dataSize); + + /* Reset datasize - overwrite if new or same */ + pRegKey->values[i].dataSize = dataSize; + + /* Set our status to good and exit. */ + retVal = DSP_SOK; + break; + } + } + + /* See if we found a match or if this is a new entry */ + if (i == pRegKey->numValueEntries) { + /* No match, need to make a new entry */ + /* First check to see if we can make any more entries. */ + if (pRegKey->numValueEntries < BRIDGE_MAX_NUM_REG_ENTRIES) { + strncpy(pRegKey->values[pRegKey->numValueEntries].name, + valName, BRIDGE_MAX_NAME_SIZE); + pRegKey->values[pRegKey->numValueEntries].pData = + MEM_Alloc(dataSize, MEM_NONPAGED); + if (pRegKey->values[pRegKey->numValueEntries].pData != + NULL) { + memcpy(pRegKey-> + values[pRegKey->numValueEntries].pData, + pBuf, dataSize); + pRegKey-> + values[pRegKey->numValueEntries].dataSize = + dataSize; + pRegKey->numValueEntries++; + retVal = DSP_SOK; + } + } else { + GT_0trace(REG_debugMask, GT_7CLASS, + "MAX NUM REG ENTRIES REACHED\n"); + } + } + + return retVal; +} + +/* + * ======== regsupEnumValue ======== + * Purpose: + * Returns registry "values" and their "data" under a (sub)key. + */ +DSP_STATUS regsupEnumValue(IN u32 dwIndex, IN CONST char *pstrKey, + IN OUT char *pstrValue, IN OUT u32 *pdwValueSize, + IN OUT char *pstrData, IN OUT u32 *pdwDataSize) +{ + DSP_STATUS retVal = REG_E_INVALIDSUBKEY; + u32 i; + u32 dwKeyLen; + u32 count = 0; + + DBC_Require(pstrKey); + dwKeyLen = strlen(pstrKey); + + /* Need to search through the entries looking for the right one. */ + for (i = 0; i < pRegKey->numValueEntries; i++) { + /* See if the name matches. */ + if ((strncmp(pRegKey->values[i].name, pstrKey, + dwKeyLen) == 0) && count++ == dwIndex) { + /* We have a match! Copy out the data. */ + memcpy(pstrData, pRegKey->values[i].pData, + pRegKey->values[i].dataSize); + /* Get the size for the caller. */ + *pdwDataSize = pRegKey->values[i].dataSize; + *pdwValueSize = strlen(&(pRegKey-> + values[i].name[dwKeyLen])); + strncpy(pstrValue, + &(pRegKey->values[i].name[dwKeyLen]), + *pdwValueSize + 1); + GT_3trace(REG_debugMask, GT_2CLASS, + "E Key %s, Value %s, Data %x ", + pstrKey, pstrValue, *(u32 *)pstrData); + printS((u8 *)pstrData); + /* Set our status to good and exit. */ + retVal = DSP_SOK; + break; + } + } + + if (count && DSP_FAILED(retVal)) + retVal = REG_E_NOMOREITEMS; + + return retVal; +} + +/* + * ======== regsupDeleteValue ======== + */ +DSP_STATUS regsupDeleteValue(IN CONST char *pstrSubkey, + IN CONST char *pstrValue) +{ + DSP_STATUS retVal = DSP_EFAIL; + u32 i; + + for (i = 0; ((i < BRIDGE_MAX_NUM_REG_ENTRIES) && + (i < pRegKey->numValueEntries)); i++) { + /* See if the name matches... */ + if (strncmp(pRegKey->values[i].name, pstrValue, + BRIDGE_MAX_NAME_SIZE) == 0) { + /* We have a match! Delete this key. To delete a + * key, we free all resources associated with this + * key and, if we're not already the last entry in + * the array, we copy that entry into this deleted + * key. + */ + MEM_Free(pRegKey->values[i].pData); + if ((pRegKey->numValueEntries - 1) == i) { + /* we're deleting the last one */ + pRegKey->values[i].name[0] = '\0'; + pRegKey->values[i].dataSize = 0; + pRegKey->values[i].pData = NULL; + } else { + /* move the last one here */ + strncpy(pRegKey->values[i].name, pRegKey-> + values[pRegKey->numValueEntries - 1].name, + BRIDGE_MAX_NAME_SIZE); + pRegKey->values[i].dataSize = + pRegKey-> + values[pRegKey->numValueEntries-1].dataSize; + pRegKey->values[i].pData = + pRegKey-> + values[pRegKey->numValueEntries-1].pData; + /* don't have to do this, but for + * the paranoid... */ + pRegKey-> + values[pRegKey->numValueEntries-1].name[0] = + '\0'; + } + + /* another one bites the dust. */ + pRegKey->numValueEntries--; + + /* Set our status to good and exit... */ + retVal = DSP_SOK; + break; + } + } + return retVal; + +} + diff --git a/drivers/dsp/bridge/services/regsup.h b/drivers/dsp/bridge/services/regsup.h new file mode 100644 index 0000000..011be52 --- /dev/null +++ b/drivers/dsp/bridge/services/regsup.h @@ -0,0 +1,58 @@ +/* + * regsup.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== regsup.h ======== + * + *! Revision History + *! ================ + */ + +#ifndef _REGSUP_H_ +#define _REGSUP_H_ + +#define BRIDGE_MAX_NAME_SIZE MAXREGPATHLENGTH +#define BRIDGE_MAX_NUM_REG_ENTRIES 52 + +/* Init function. MUST be called BEFORE any calls are */ +/* made into this psuedo-registry!!! Returns TRUE/FALSE for SUCCESS/ERROR */ +extern bool regsupInit(void); + +/* Release all registry support allocations. */ +extern void regsupExit(void); + +/* + * ======== regsupDeleteValue ======== + */ +extern DSP_STATUS regsupDeleteValue(IN CONST char *pstrSubkey, + IN CONST char *pstrValue); +/* Get the value of the entry having the given name. Returns DSP_SOK */ +/* if an entry was found and the value retrieved. Returns DSP_EFAIL + * otherwise.*/ +extern DSP_STATUS regsupGetValue(char *valName, void *pBuf, u32 *dataSize); + +/* Sets the value of the entry having the given name. Returns DSP_SOK */ +/* if an entry was found and the value set. Returns DSP_EFAIL otherwise. */ +extern DSP_STATUS regsupSetValue(char *valName, void *pBuf, u32 dataSize); + +/* Returns registry "values" and their "data" under a (sub)key. */ +extern DSP_STATUS regsupEnumValue(IN u32 dwIndex, IN CONST char *pstrKey, + IN OUT char *pstrValue, IN OUT u32 *pdwValueSize, + IN OUT char *pstrData, IN OUT u32 *pdwDataSize); + +#endif + diff --git a/drivers/dsp/bridge/services/services.c b/drivers/dsp/bridge/services/services.c new file mode 100644 index 0000000..346007e --- /dev/null +++ b/drivers/dsp/bridge/services/services.c @@ -0,0 +1,193 @@ +/* + * services.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== services.c ======== + * Purpose: + * Provide SERVICES loading. + * + * Public Functions: + * SERVICES_Exit + * SERVICES_Init + * + * + *! Revision History + *! ================ + *! 20-Nov-2000 rr: NTFY_Init/Exit added. + *! 06-Jul-2000 rr: PROC prefix changed to PRCS to accomodate RM. + *! 01-Feb-2000 kc: Created. + */ + +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* ----------------------------------- This */ +#include + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask SERVICES_debugMask = { NULL, NULL }; /* GT trace var. */ +#endif + +static u32 cRefs; /* SERVICES module reference count */ + +/* + * ======== SERVICES_Exit ======== + * Purpose: + * Discontinue usage of module; free resources when reference count + * reaches 0. + */ +void SERVICES_Exit(void) +{ + DBC_Require(cRefs > 0); + + GT_1trace(SERVICES_debugMask, GT_5CLASS, "SERVICES_Exit: cRefs 0x%x\n", + cRefs); + + cRefs--; + if (cRefs == 0) { + /* Uninitialize all SERVICES modules here */ + NTFY_Exit(); + UTIL_Exit(); + SYNC_Exit(); + CLK_Exit(); + REG_Exit(); + LST_Exit(); + KFILE_Exit(); + DPC_Exit(); + DBG_Exit(); + CSL_Exit(); + CFG_Exit(); + MEM_Exit(); + + GT_exit(); + } + + DBC_Ensure(cRefs >= 0); +} + +/* + * ======== SERVICES_Init ======== + * Purpose: + * Initializes SERVICES modules. + */ +bool SERVICES_Init(void) +{ + bool fInit = true; + bool fCFG, fCSL, fDBG, fDPC, fKFILE, fLST, fMEM; + bool fREG, fSYNC, fCLK, fUTIL, fNTFY; + + DBC_Require(cRefs >= 0); + + if (cRefs == 0) { + + GT_init(); + GT_create(&SERVICES_debugMask, "OS"); /* OS for OSal */ + + GT_0trace(SERVICES_debugMask, GT_ENTER, + "SERVICES_Init: entered\n"); + + /* Perform required initialization of SERVICES modules. */ + fMEM = MEM_Init(); + fREG = REG_Init(); + fCFG = CFG_Init(); + fCSL = CSL_Init(); + fDBG = DBG_Init(); + fDPC = DPC_Init(); + fKFILE = KFILE_Init(); + fLST = LST_Init(); + /* fREG = REG_Init(); */ + fSYNC = SYNC_Init(); + fCLK = CLK_Init(); + fUTIL = UTIL_Init(); + fNTFY = NTFY_Init(); + + fInit = fCFG && fCSL && fDBG && fDPC && fKFILE && + fLST && fMEM && fREG && fSYNC && fCLK && fUTIL; + + if (!fInit) { + if (fNTFY) + NTFY_Exit(); + + if (fUTIL) + UTIL_Exit(); + + if (fSYNC) + SYNC_Exit(); + + if (fCLK) + CLK_Exit(); + + if (fREG) + REG_Exit(); + + if (fLST) + LST_Exit(); + + if (fKFILE) + KFILE_Exit(); + + if (fDPC) + DPC_Exit(); + + if (fDBG) + DBG_Exit(); + + if (fCSL) + CSL_Exit(); + + if (fCFG) + CFG_Exit(); + + if (fMEM) + MEM_Exit(); + + } + } + + if (fInit) + cRefs++; + + GT_1trace(SERVICES_debugMask, GT_5CLASS, "SERVICES_Init: cRefs 0x%x\n", + cRefs); + + DBC_Ensure((fInit && (cRefs > 0)) || (!fInit && (cRefs >= 0))); + + return fInit; +} + diff --git a/drivers/dsp/bridge/services/sync.c b/drivers/dsp/bridge/services/sync.c new file mode 100644 index 0000000..7ab9347 --- /dev/null +++ b/drivers/dsp/bridge/services/sync.c @@ -0,0 +1,602 @@ +/* + * sync.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== sync.c ======== + * Purpose: + * Synchronization services. + * + * Public Functions: + * SYNC_CloseEvent + * SYNC_DeleteCS + * SYNC_EnterCS + * SYNC_Exit + * SYNC_Init + * SYNC_InitializeCS + * SYNC_LeaveCS + * SYNC_OpenEvent + * SYNC_ResetEvent + * SYNC_SetEvent + * SYNC_WaitOnEvent + * SYNC_WaitOnMultipleEvents + * + *! Revision History: + *! ================ + *! 05-Nov-2001 kc: Minor cosmetic changes. + *! 05-Oct-2000 jeh Added SYNC_WaitOnMultipleEvents(). + *! 10-Aug-2000 rr: SYNC_PostMessage added. + *! 10-Jul-2000 jeh Modified SYNC_OpenEvent() to handle NULL attrs. + *! 03-Feb-2000 rr: Module init/exit is handled by SERVICES Init/Exit. + *! GT Changes. + *! 01-Dec-1999 ag: Added optional named event creation in SYNC_OpenEvent(). + *! 22-Nov-1999 kc: Added changes from code review. + *! 22-Sep-1999 kc: Modified from sync95.c. + *! 05-Aug-1996 gp: Created. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include + +/* ----------------------------------- This */ +#include + +/* ----------------------------------- Defines, Data Structures, Typedefs */ +#define SIGNATURE 0x434e5953 /* "SYNC" (in reverse) */ + +enum wait_state { + wo_waiting, + wo_signalled +} ; + +enum sync_state { + so_reset, + so_signalled +} ; + +struct WAIT_OBJECT { + enum wait_state state; + struct SYNC_OBJECT *signalling_event; + struct semaphore sem; +}; + +/* Generic SYNC object: */ +struct SYNC_OBJECT { + u32 dwSignature; /* Used for object validation. */ + enum sync_state state; + spinlock_t sync_lock; + struct WAIT_OBJECT *pWaitObj; +}; + +struct SYNC_DPCCSOBJECT { + u32 dwSignature; /* used for object validation */ + spinlock_t sync_dpccs_lock; + s32 count; +} ; + +/* ----------------------------------- Globals */ +#if GT_TRACE +static struct GT_Mask SYNC_debugMask = { NULL, NULL }; /* GT trace variable */ +#endif + +static int test_and_set(volatile void *ptr, int val) +{ + int ret = val; + asm volatile (" swp %0, %0, [%1]" : "+r" (ret) : "r"(ptr) : "memory"); + return ret; +} + +static void timeout_callback(unsigned long hWaitObj); + +/* + * ======== SYNC_CloseEvent ======== + * Purpose: + * Close an existing SYNC event object. + */ +DSP_STATUS SYNC_CloseEvent(struct SYNC_OBJECT *hEvent) +{ + DSP_STATUS status = DSP_SOK; + struct SYNC_OBJECT *pEvent = (struct SYNC_OBJECT *)hEvent; + + DBC_Require(pEvent != NULL && pEvent->pWaitObj == NULL); + + GT_1trace(SYNC_debugMask, GT_ENTER, "SYNC_CloseEvent: hEvent 0x%x\n", + hEvent); + + if (MEM_IsValidHandle(hEvent, SIGNATURE)) { + if (pEvent->pWaitObj) { + status = DSP_EFAIL; + GT_0trace(SYNC_debugMask, GT_6CLASS, + "SYNC_CloseEvent: Wait object not NULL\n"); + } + MEM_FreeObject(pEvent); + + } else { + status = DSP_EHANDLE; + GT_1trace(SYNC_debugMask, GT_6CLASS, + "SYNC_CloseEvent: invalid " + "hEvent handle 0x%x\n", hEvent); + } + + return status; +} + +/* + * ======== SYNC_Exit ======== + * Purpose: + * Cleanup SYNC module. + */ +void SYNC_Exit(void) +{ + GT_0trace(SYNC_debugMask, GT_5CLASS, "SYNC_Exit\n"); +} + +/* + * ======== SYNC_Init ======== + * Purpose: + * Initialize SYNC module. + */ +bool SYNC_Init(void) +{ + GT_create(&SYNC_debugMask, "SY"); /* SY for SYnc */ + + GT_0trace(SYNC_debugMask, GT_5CLASS, "SYNC_Init\n"); + + return true; +} + +/* + * ======== SYNC_OpenEvent ======== + * Purpose: + * Open a new synchronization event object. + */ +DSP_STATUS SYNC_OpenEvent(OUT struct SYNC_OBJECT **phEvent, + IN OPTIONAL struct SYNC_ATTRS *pAttrs) +{ + struct SYNC_OBJECT *pEvent = NULL; + DSP_STATUS status = DSP_SOK; + + DBC_Require(phEvent != NULL); + + GT_2trace(SYNC_debugMask, GT_ENTER, + "SYNC_OpenEvent: phEvent 0x%x, pAttrs " + "0x%x\n", phEvent, pAttrs); + + /* Allocate memory for sync object */ + MEM_AllocObject(pEvent, struct SYNC_OBJECT, SIGNATURE); + if (pEvent != NULL) { + pEvent->state = so_reset; + pEvent->pWaitObj = NULL; + spin_lock_init(&pEvent->sync_lock); + } else { + status = DSP_EMEMORY; + GT_0trace(SYNC_debugMask, GT_6CLASS, + "SYNC_OpenEvent: MEM_AllocObject failed\n"); + } + + *phEvent = pEvent; + + return status; +} + +/* + * ======== SYNC_ResetEvent ======== + * Purpose: + * Reset an event to non-signalled. + */ +DSP_STATUS SYNC_ResetEvent(struct SYNC_OBJECT *hEvent) +{ + DSP_STATUS status = DSP_SOK; + struct SYNC_OBJECT *pEvent = (struct SYNC_OBJECT *)hEvent; + + GT_1trace(SYNC_debugMask, GT_ENTER, "SYNC_ResetEvent: hEvent 0x%x\n", + hEvent); + + if (MEM_IsValidHandle(hEvent, SIGNATURE)) { + pEvent->state = so_reset; + status = DSP_SOK; + } else { + status = DSP_EHANDLE; + GT_1trace(SYNC_debugMask, GT_6CLASS, + "SYNC_ResetEvent: invalid hEvent " + "handle 0x%x\n", hEvent); + } + + return status; +} + +/* + * ======== SYNC_SetEvent ======== + * Purpose: + * Set an event to signaled and unblock one waiting thread. + * + * This function is called from ISR, DPC and user context. Hence interrupts + * are disabled to ensure atomicity. + */ + +DSP_STATUS SYNC_SetEvent(struct SYNC_OBJECT *hEvent) +{ + DSP_STATUS status = DSP_SOK; + struct SYNC_OBJECT *pEvent = (struct SYNC_OBJECT *)hEvent; + unsigned long flags; + + GT_1trace(SYNC_debugMask, GT_6CLASS, "SYNC_SetEvent: hEvent 0x%x\n", + hEvent); + + if (MEM_IsValidHandle(hEvent, SIGNATURE)) { + spin_lock_irqsave(&hEvent->sync_lock, flags); + GT_1trace(SYNC_debugMask, GT_6CLASS, + "SYNC_SetEvent: pEvent->pWaitObj " + "= 0x%x \n", pEvent->pWaitObj); + if (pEvent->pWaitObj) + GT_1trace(SYNC_debugMask, GT_6CLASS, "SYNC_SetEvent: " + "pEvent->pWaitObj->state = 0x%x \n", + pEvent->pWaitObj->state); + if (pEvent->pWaitObj != NULL && + test_and_set(&pEvent->pWaitObj->state, + wo_signalled) == wo_waiting) { + + pEvent->state = so_reset; + pEvent->pWaitObj->signalling_event = pEvent; + up(&pEvent->pWaitObj->sem); + GT_1trace(SYNC_debugMask, GT_6CLASS, + "SYNC_SetEvent: Unlock " + "Semaphore for hEvent 0x%x\n", hEvent); + } else { + pEvent->state = so_signalled; + } + spin_unlock_irqrestore(&hEvent->sync_lock, flags); + } else { + status = DSP_EHANDLE; + GT_1trace(SYNC_debugMask, GT_6CLASS, + "SYNC_SetEvent: invalid hEvent " + "handle 0x%x\n", hEvent); + } + return status; +} + +/* + * ======== SYNC_WaitOnEvent ======== + * Purpose: + * Wait for an event to be signalled, up to the specified timeout. + * Note: dwTimeOut must be 0xffffffff to signal infinite wait. + */ +DSP_STATUS SYNC_WaitOnEvent(struct SYNC_OBJECT *hEvent, u32 dwTimeout) +{ + DSP_STATUS status = DSP_SOK; + struct SYNC_OBJECT *pEvent = (struct SYNC_OBJECT *)hEvent; + u32 temp; + + GT_2trace(SYNC_debugMask, GT_6CLASS, "SYNC_WaitOnEvent: hEvent 0x%x\n, " + "dwTimeOut 0x%x", hEvent, dwTimeout); + if (MEM_IsValidHandle(hEvent, SIGNATURE)) { + status = SYNC_WaitOnMultipleEvents(&pEvent, 1, dwTimeout, + &temp); + } else { + status = DSP_EHANDLE; + GT_1trace(SYNC_debugMask, GT_6CLASS, + "SYNC_WaitOnEvent: invalid hEvent" + "handle 0x%x\n", hEvent); + } + return status; +} + +/* + * ======== SYNC_WaitOnMultipleEvents ======== + * Purpose: + * Wait for any of an array of events to be signalled, up to the + * specified timeout. + */ +DSP_STATUS SYNC_WaitOnMultipleEvents(struct SYNC_OBJECT **hSyncEvents, + u32 uCount, u32 dwTimeout, + OUT u32 *puIndex) +{ + u32 i; + DSP_STATUS status = DSP_SOK; + u32 curr; + struct WAIT_OBJECT *Wp; + + DBC_Require(uCount > 0); + DBC_Require(hSyncEvents != NULL); + DBC_Require(puIndex != NULL); + + for (i = 0; i < uCount; i++) + DBC_Require(MEM_IsValidHandle(hSyncEvents[i], SIGNATURE)); + + GT_4trace(SYNC_debugMask, GT_6CLASS, + "SYNC_WaitOnMultipleEvents: hSyncEvents:" + "0x%x\tuCount: 0x%x" "\tdwTimeout: 0x%x\tpuIndex: 0x%x\n", + hSyncEvents, uCount, dwTimeout, puIndex); + + Wp = MEM_Calloc(sizeof(struct WAIT_OBJECT), MEM_NONPAGED); + if (Wp == NULL) + return DSP_EMEMORY; + + Wp->state = wo_waiting; + Wp->signalling_event = NULL; + init_MUTEX_LOCKED(&(Wp->sem)); + + for (curr = 0; curr < uCount; curr++) { + hSyncEvents[curr]->pWaitObj = Wp; + if (hSyncEvents[curr]->state == so_signalled) { + GT_0trace(SYNC_debugMask, GT_6CLASS, + "Detected signaled Event !!!\n"); + if (test_and_set(&(Wp->state), wo_signalled) == + wo_waiting) { + GT_0trace(SYNC_debugMask, GT_6CLASS, + "Setting Signal Event!!!\n"); + hSyncEvents[curr]->state = so_reset; + Wp->signalling_event = hSyncEvents[curr]; + } + curr++; /* Will try optimizing later */ + break; + } + } + + curr--; /* Will try optimizing later */ + if (Wp->state != wo_signalled && dwTimeout > 0) { + struct timer_list timeout; + if (dwTimeout != SYNC_INFINITE) { + init_timer(&timeout); + timeout.function = timeout_callback; + timeout.data = (unsigned long)Wp; + timeout.expires = jiffies + dwTimeout * HZ / 1000; + add_timer(&timeout); + } + if (down_interruptible(&(Wp->sem))) { + GT_0trace(SYNC_debugMask, GT_7CLASS, "SYNC: " + "WaitOnMultipleEvents Interrupted by signal\n"); + status = DSP_EFAIL; + } + if (dwTimeout != SYNC_INFINITE) { + if (in_interrupt()) { + if (!del_timer(&timeout)) { + GT_0trace(SYNC_debugMask, GT_7CLASS, + "SYNC: Timer expired\n"); + } + } else { + if (!del_timer_sync(&timeout)) { + GT_0trace(SYNC_debugMask, GT_7CLASS, + "SYNC: Timer expired\n"); + } + } + } + } + for (i = 0; i <= curr; i++) { + if (MEM_IsValidHandle(hSyncEvents[i], SIGNATURE)) { + /* Memory corruption here if hSyncEvents[i] is + * freed before following statememt. */ + hSyncEvents[i]->pWaitObj = NULL; + } + if (hSyncEvents[i] == Wp->signalling_event) + *puIndex = i; + + } + if (Wp->signalling_event == NULL && DSP_SUCCEEDED(status)) { + GT_0trace(SYNC_debugMask, GT_7CLASS, + "SYNC:Signaling Event NULL!!!(:-\n"); + status = DSP_ETIMEOUT; + } + if (Wp) + MEM_Free(Wp); + return status; +} + +static void timeout_callback(unsigned long hWaitObj) +{ + struct WAIT_OBJECT *pWaitObj = (struct WAIT_OBJECT *)hWaitObj; + if (test_and_set(&pWaitObj->state, wo_signalled) == wo_waiting) + up(&pWaitObj->sem); + +} + +/* + * ======== SYNC_DeleteCS ======== + */ +DSP_STATUS SYNC_DeleteCS(struct SYNC_CSOBJECT *hCSObj) +{ + DSP_STATUS status = DSP_SOK; + struct SYNC_CSOBJECT *pCSObj = (struct SYNC_CSOBJECT *)hCSObj; + + GT_0trace(SYNC_debugMask, GT_ENTER, "SYNC_DeleteCS\n"); + + if (MEM_IsValidHandle(hCSObj, SIGNATURECS)) { + if (down_trylock(&pCSObj->sem) != 0) { + GT_1trace(SYNC_debugMask, GT_7CLASS, + "CS in use (locked) while " + "deleting! pCSObj=0x%X", pCSObj); + DBC_Assert(0); + } + MEM_FreeObject(hCSObj); + } else if (MEM_IsValidHandle(hCSObj, SIGNATUREDPCCS)) { + struct SYNC_DPCCSOBJECT *pDPCCSObj = + (struct SYNC_DPCCSOBJECT *)hCSObj; + if (pDPCCSObj->count != 1) { + GT_1trace(SYNC_debugMask, GT_7CLASS, + "DPC CS in use (locked) while " + "deleting! pCSObj=0x%X", pCSObj); + DBC_Assert(0); + } + MEM_FreeObject(pDPCCSObj); + } else { + status = DSP_EHANDLE; + GT_1trace(SYNC_debugMask, GT_6CLASS, + "SYNC_DeleteCS: invalid hCSObj " + "handle 0x%x\n", hCSObj); + } + + return status; +} + +/* + * ======== SYNC_EnterCS ======== + */ +DSP_STATUS SYNC_EnterCS(struct SYNC_CSOBJECT *hCSObj) +{ + DSP_STATUS status = DSP_SOK; + struct SYNC_CSOBJECT *pCSObj = (struct SYNC_CSOBJECT *)hCSObj; + + GT_1trace(SYNC_debugMask, GT_ENTER, "SYNC_EnterCS: hCSObj %p\n", + hCSObj); + if (MEM_IsValidHandle(hCSObj, SIGNATURECS)) { + if (in_interrupt()) { + status = DSP_EFAIL; + GT_0trace(SYNC_debugMask, GT_7CLASS, + "SYNC_EnterCS called from " + "ISR/DPC or with ISR/DPC disabled!"); + DBC_Assert(0); + } else if (down_interruptible(&pCSObj->sem)) { + GT_1trace(SYNC_debugMask, GT_7CLASS, + "CS interrupted by signal! " + "pCSObj=0x%X", pCSObj); + status = DSP_EFAIL; + } + } else if (MEM_IsValidHandle(hCSObj, SIGNATUREDPCCS)) { + struct SYNC_DPCCSOBJECT *pDPCCSObj = + (struct SYNC_DPCCSOBJECT *)hCSObj; + GT_0trace(SYNC_debugMask, GT_ENTER, "SYNC_EnterCS DPC\n"); + spin_lock_bh(&pDPCCSObj->sync_dpccs_lock); + pDPCCSObj->count--; + if (pDPCCSObj->count != 0) { + /* FATAL ERROR : Failed to acquire DPC CS */ + GT_2trace(SYNC_debugMask, GT_7CLASS, + "SYNC_EnterCS DPCCS %x locked," + "count %d", pDPCCSObj, pDPCCSObj->count); + spin_unlock_bh(&pDPCCSObj->sync_dpccs_lock); + DBC_Assert(0); + } + } else { + status = DSP_EHANDLE; + GT_1trace(SYNC_debugMask, GT_6CLASS, + "SYNC_EnterCS: invalid hCSObj " + "handle 0x%x\n", hCSObj); + } + + return status; +} + +/* + * ======== SYNC_InitializeCS ======== + */ +DSP_STATUS SYNC_InitializeCS(OUT struct SYNC_CSOBJECT **phCSObj) +{ + DSP_STATUS status = DSP_SOK; + struct SYNC_CSOBJECT *pCSObj = NULL; + + GT_0trace(SYNC_debugMask, GT_ENTER, "SYNC_InitializeCS\n"); + + /* Allocate memory for sync CS object */ + MEM_AllocObject(pCSObj, struct SYNC_CSOBJECT, SIGNATURECS); + if (pCSObj != NULL) { + init_MUTEX(&pCSObj->sem); + } else { + status = DSP_EMEMORY; + GT_0trace(SYNC_debugMask, GT_6CLASS, + "SYNC_InitializeCS: MEM_AllocObject" + "failed\n"); + } + /* return CS object */ + *phCSObj = pCSObj; + DBC_Assert(DSP_FAILED(status) || (pCSObj)); + return status; +} + +DSP_STATUS SYNC_InitializeDPCCS(OUT struct SYNC_CSOBJECT **phCSObj) +{ + DSP_STATUS status = DSP_SOK; + struct SYNC_DPCCSOBJECT *pCSObj = NULL; + + DBC_Require(phCSObj); + + GT_0trace(SYNC_debugMask, GT_ENTER, "SYNC_InitializeDPCCS\n"); + + if (phCSObj) { + /* Allocate memory for sync CS object */ + MEM_AllocObject(pCSObj, struct SYNC_DPCCSOBJECT, + SIGNATUREDPCCS); + if (pCSObj != NULL) { + pCSObj->count = 1; + spin_lock_init(&pCSObj->sync_dpccs_lock); + } else { + status = DSP_EMEMORY; + GT_0trace(SYNC_debugMask, GT_6CLASS, + "SYNC_InitializeDPCCS: " + "MEM_AllocObject failed\n"); + } + + /* return CS object */ + *phCSObj = (struct SYNC_CSOBJECT *)pCSObj; + } else { + status = DSP_EPOINTER; + } + + GT_1trace(SYNC_debugMask, GT_ENTER, "SYNC_InitializeDPCCS " + "pCSObj %p\n", pCSObj); + DBC_Assert(DSP_FAILED(status) || (pCSObj)); + + return status; +} + +/* + * ======== SYNC_LeaveCS ======== + */ +DSP_STATUS SYNC_LeaveCS(struct SYNC_CSOBJECT *hCSObj) +{ + DSP_STATUS status = DSP_SOK; + struct SYNC_CSOBJECT *pCSObj = (struct SYNC_CSOBJECT *)hCSObj; + + GT_1trace(SYNC_debugMask, GT_ENTER, "SYNC_LeaveCS: hCSObj %p\n", + hCSObj); + + if (MEM_IsValidHandle(hCSObj, SIGNATURECS)) { + up(&pCSObj->sem); + } else if (MEM_IsValidHandle(hCSObj, SIGNATUREDPCCS)) { + struct SYNC_DPCCSOBJECT *pDPCCSObj = + (struct SYNC_DPCCSOBJECT *)hCSObj; + pDPCCSObj->count++; + if (pDPCCSObj->count != 1) { + /* FATAL ERROR : Invalid DPC CS count */ + GT_2trace(SYNC_debugMask, GT_7CLASS, + "SYNC_LeaveCS DPCCS %x, " + "Invalid count %d", pDPCCSObj, + pDPCCSObj->count); + spin_unlock_bh(&pDPCCSObj->sync_dpccs_lock); + DBC_Assert(0); + spin_lock_bh(&pDPCCSObj->sync_dpccs_lock); + } + spin_unlock_bh(&pDPCCSObj->sync_dpccs_lock); + GT_0trace(SYNC_debugMask, GT_ENTER, "SYNC_LeaveCS DPC\n"); + } else { + status = DSP_EHANDLE; + GT_1trace(SYNC_debugMask, GT_6CLASS, + "SYNC_LeaveCS: invalid hCSObj " + "handle 0x%x\n", hCSObj); + } + + return status; +} diff --git a/drivers/dsp/bridge/wmd/_cmm.h b/drivers/dsp/bridge/wmd/_cmm.h new file mode 100644 index 0000000..801b000 --- /dev/null +++ b/drivers/dsp/bridge/wmd/_cmm.h @@ -0,0 +1,59 @@ +/* + * _cmm.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== _cmm.h ======== + * Description: + * Private header file defining CMM manager objects and defines needed + * by IO manager to register shared memory regions when DSP base image + * is loaded(WMD_IO_OnLoaded). + * + * Public Functions: + * None. + * + * Notes: + * + *! Revision History: + *! ================ + *! 24-Aug-2001 ag Created. + */ + +#ifndef _CMM_ +#define _CMM_ + +/* + * These target side symbols define the beginning and ending addresses + * of the section of shared memory used for shared memory manager CMM. + * They are defined in the *cfg.cmd file by cdb code. + */ +#define SHM0_SHARED_BASE_SYM "_SHM0_BEG" +#define SHM0_SHARED_END_SYM "_SHM0_END" +#define SHM0_SHARED_RESERVED_BASE_SYM "_SHM0_RSVDSTRT" + +/* + * Shared Memory Region #0(SHMSEG0) is used in the following way: + * + * |(_SHM0_BEG) | (_SHM0_RSVDSTRT) | (_SHM0_END) + * V V V + * ------------------------------------------------------------ + * | DSP-side allocations | GPP-side allocations | + * ------------------------------------------------------------ + * + * + */ + +#endif /* _CMM_ */ diff --git a/drivers/dsp/bridge/wmd/_deh.h b/drivers/dsp/bridge/wmd/_deh.h new file mode 100644 index 0000000..df281ad --- /dev/null +++ b/drivers/dsp/bridge/wmd/_deh.h @@ -0,0 +1,46 @@ +/* + * _deh.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== _deh.h ======== + * Description: + * Private header for DEH module. + * + *! Revision History: + *! ================ + *! 21-Sep-2001 kc: created. + */ + +#ifndef _DEH_ +#define _DEH_ + +#include +#include +#include + +#define SIGNATURE 0x5f484544 /* "DEH_" backwards */ + +/* DEH Manager: only one created per board: */ +struct DEH_MGR { + u32 dwSignature; /* Used for object validation. */ + struct WMD_DEV_CONTEXT *hWmdContext; /* WMD device context. */ + struct NTFY_OBJECT *hNtfy; /* NTFY object */ + struct DPC_OBJECT *hMmuFaultDpc; /* DPC object handle. */ + struct DSP_ERRORINFO errInfo; /* DSP exception info. */ +} ; + +#endif /* _DEH_ */ diff --git a/drivers/dsp/bridge/wmd/_msg_sm.h b/drivers/dsp/bridge/wmd/_msg_sm.h new file mode 100644 index 0000000..fa5e9ee --- /dev/null +++ b/drivers/dsp/bridge/wmd/_msg_sm.h @@ -0,0 +1,158 @@ +/* + * _msg_sm.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== _msg_sm.h ======== + * Description: + * Private header file defining MSG manager objects and defines needed + * by IO manager. + * + * Public Functions: + * None. + * + * Notes: + * + *! Revision History: + *! ================ + *! 09-May-2001 jeh Code Review cleanup. + *! 08-Nov-2000 jeh Created. + */ + +#ifndef _MSG_SM_ +#define _MSG_SM_ + +#include +#include + +/* + * These target side symbols define the beginning and ending addresses + * of the section of shared memory used for messages. They are + * defined in the *cfg.cmd file by cdb code. + */ +#define MSG_SHARED_BUFFER_BASE_SYM "_MSG_BEG" +#define MSG_SHARED_BUFFER_LIMIT_SYM "_MSG_END" + +#ifndef _CHNL_WORDSIZE +#define _CHNL_WORDSIZE 4 /* default _CHNL_WORDSIZE is 2 bytes/word */ +#endif + +/* + * ======== MSG ======== + * There is a control structure for messages to the DSP, and a control + * structure for messages from the DSP. The shared memory region for + * transferring messages is partitioned as follows: + * + * ---------------------------------------------------------- + * |Control | Messages from DSP | Control | Messages to DSP | + * ---------------------------------------------------------- + * + * MSG control structure for messages to the DSP is used in the following + * way: + * + * bufEmpty - This flag is set to FALSE by the GPP after it has output + * messages for the DSP. The DSP host driver sets it to + * TRUE after it has copied the messages. + * postSWI - Set to 1 by the GPP after it has written the messages, + * set the size, and set bufEmpty to FALSE. + * The DSP Host driver uses SWI_andn of the postSWI field + * when a host interrupt occurs. The host driver clears + * this after posting the SWI. + * size - Number of messages to be read by the DSP. + * + * For messages from the DSP: + * bufEmpty - This flag is set to FALSE by the DSP after it has output + * messages for the GPP. The DPC on the GPP sets it to + * TRUE after it has copied the messages. + * postSWI - Set to 1 the DPC on the GPP after copying the messages. + * size - Number of messages to be read by the GPP. + */ +struct MSG { + u32 bufEmpty; /* to/from DSP buffer is empty */ + u32 postSWI; /* Set to "1" to post MSG SWI */ + u32 size; /* Number of messages to/from the DSP */ + u32 resvd; +} ; + +/* + * ======== MSG_MGR ======== + * The MSG_MGR maintains a list of all MSG_QUEUEs. Each NODE object can + * have MSG_QUEUE to hold all messages that come up from the corresponding + * node on the DSP. The MSG_MGR also has a shared queue of messages + * ready to go to the DSP. + */ +struct MSG_MGR { + /* The first two fields must match those in msgobj.h */ + u32 dwSignature; + struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD. */ + + struct IO_MGR *hIOMgr; /* IO manager */ + struct LST_LIST *queueList; /* List of MSG_QUEUEs */ + struct SYNC_CSOBJECT *hSyncCS; /* For critical sections */ + /* Signalled when MsgFrame is available */ + struct SYNC_OBJECT *hSyncEvent; + struct LST_LIST *msgFreeList; /* Free MsgFrames ready to be filled */ + struct LST_LIST *msgUsedList; /* MsgFrames ready to go to DSP */ + u32 uMsgsPending; /* # of queued messages to go to DSP */ + u32 uMaxMsgs; /* Max # of msgs that fit in buffer */ + MSG_ONEXIT onExit; /* called when RMS_EXIT is received */ +} ; + +/* + * ======== MSG_QUEUE ======== + * Each NODE has a MSG_QUEUE for receiving messages from the + * corresponding node on the DSP. The MSG_QUEUE object maintains a list + * of messages that have been sent to the host, but not yet read (MSG_Get), + * and a list of free frames that can be filled when new messages arrive + * from the DSP. + * The MSG_QUEUE's hSynEvent gets posted when a message is ready. + */ +struct MSG_QUEUE { + struct LST_ELEM listElem; + u32 dwSignature; + struct MSG_MGR *hMsgMgr; + u32 uMaxMsgs; /* Node message depth */ + u32 dwId; /* Node environment pointer */ + struct LST_LIST *msgFreeList; /* Free MsgFrames ready to be filled */ + /* Filled MsgFramess waiting to be read */ + struct LST_LIST *msgUsedList; + HANDLE hArg; /* Handle passed to mgr onExit callback */ + struct SYNC_OBJECT *hSyncEvent; /* Signalled when message is ready */ + struct SYNC_OBJECT *hSyncDone; /* For synchronizing cleanup */ + struct SYNC_OBJECT *hSyncDoneAck; /* For synchronizing cleanup */ + struct NTFY_OBJECT *hNtfy; /* For notification of message ready */ + bool fDone; /* TRUE <==> deleting the object */ + u32 refCount; /* Number of pending MSG_get/put calls */ +}; + +/* + * ======== MSG_DSPMSG ======== + */ +struct MSG_DSPMSG { + struct DSP_MSG msg; + u32 dwId; /* Identifies the node the message goes to */ +} ; + +/* + * ======== MSG_FRAME ======== + */ +struct MSG_FRAME { + struct LST_ELEM listElem; + struct MSG_DSPMSG msgData; +} ; + +#endif /* _MSG_SM_ */ + diff --git a/drivers/dsp/bridge/wmd/_tiomap.h b/drivers/dsp/bridge/wmd/_tiomap.h new file mode 100644 index 0000000..815f695 --- /dev/null +++ b/drivers/dsp/bridge/wmd/_tiomap.h @@ -0,0 +1,384 @@ +/* + * _tiomap.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== _tiomap.h ======== + * Description: + * Definitions and types private to this WMD. + * + */ + +#ifndef _TIOMAP_ +#define _TIOMAP_ + +#include +#include +#include +#include /* for WMDIOCTL_EXTPROC defn */ +#include +#include + +struct MAP_L4PERIPHERAL { + u32 physAddr; + u32 dspVirtAddr; +} ; + +#define ARM_MAILBOX_START 0xfffcf000 +#define ARM_MAILBOX_LENGTH 0x800 + +/* New Registers in OMAP3.1 */ + +#define TESTBLOCK_ID_START 0xfffed400 +#define TESTBLOCK_ID_LENGTH 0xff + +/* ID Returned by OMAP1510 */ +#define TBC_ID_VALUE 0xB47002F + +#define SPACE_LENGTH 0x2000 +#define API_CLKM_DPLL_DMA 0xfffec000 +#define ARM_INTERRUPT_OFFSET 0xb00 + +#define BIOS_24XX + +#define L4_PERIPHERAL_NULL 0x0 +#define DSPVA_PERIPHERAL_NULL 0x0 + +#define MAX_LOCK_TLB_ENTRIES 15 + +#define L4_PERIPHERAL_PRM 0x48306000 /*PRM L4 Peripheral */ +#define DSPVA_PERIPHERAL_PRM 0x1181e000 +#define L4_PERIPHERAL_SCM 0x48002000 /*SCM L4 Peripheral */ +#define DSPVA_PERIPHERAL_SCM 0x1181f000 +#define L4_PERIPHERAL_MMU 0x5D000000 /*MMU L4 Peripheral */ +#define DSPVA_PERIPHERAL_MMU 0x11820000 +#define L4_PERIPHERAL_CM 0x48004000 /* Core L4, Clock Management */ +#define DSPVA_PERIPHERAL_CM 0x1181c000 +#define L4_PERIPHERAL_PER 0x48005000 /* PER */ +#define DSPVA_PERIPHERAL_PER 0x1181d000 + +#define L4_PERIPHERAL_GPIO1 0x48310000 +#define DSPVA_PERIPHERAL_GPIO1 0x11809000 +#define L4_PERIPHERAL_GPIO2 0x49050000 +#define DSPVA_PERIPHERAL_GPIO2 0x1180a000 +#define L4_PERIPHERAL_GPIO3 0x49052000 +#define DSPVA_PERIPHERAL_GPIO3 0x1180b000 +#define L4_PERIPHERAL_GPIO4 0x49054000 +#define DSPVA_PERIPHERAL_GPIO4 0x1180c000 +#define L4_PERIPHERAL_GPIO5 0x49056000 +#define DSPVA_PERIPHERAL_GPIO5 0x1180d000 + +#define L4_PERIPHERAL_IVA2WDT 0x49030000 +#define DSPVA_PERIPHERAL_IVA2WDT 0x1180e000 + +#define L4_PERIPHERAL_DISPLAY 0x48050000 +#define DSPVA_PERIPHERAL_DISPLAY 0x1180f000 + +#define L4_PERIPHERAL_SSI 0x48058000 +#define DSPVA_PERIPHERAL_SSI 0x11804000 +#define L4_PERIPHERAL_GDD 0x48059000 +#define DSPVA_PERIPHERAL_GDD 0x11805000 +#define L4_PERIPHERAL_SS1 0x4805a000 +#define DSPVA_PERIPHERAL_SS1 0x11806000 +#define L4_PERIPHERAL_SS2 0x4805b000 +#define DSPVA_PERIPHERAL_SS2 0x11807000 + +#define L4_PERIPHERAL_CAMERA 0x480BC000 +#define DSPVA_PERIPHERAL_CAMERA 0x11819000 + +#define L4_PERIPHERAL_SDMA 0x48056000 +#define DSPVA_PERIPHERAL_SDMA 0x11810000 /*0x1181d000 conflicts with PER */ + +#define L4_PERIPHERAL_UART1 0x4806a000 +#define DSPVA_PERIPHERAL_UART1 0x11811000 +#define L4_PERIPHERAL_UART2 0x4806c000 +#define DSPVA_PERIPHERAL_UART2 0x11812000 +#define L4_PERIPHERAL_UART3 0x49020000 +#define DSPVA_PERIPHERAL_UART3 0x11813000 + +#define L4_PERIPHERAL_MCBSP1 0x48074000 +#define DSPVA_PERIPHERAL_MCBSP1 0x11814000 +#define L4_PERIPHERAL_MCBSP2 0x49022000 +#define DSPVA_PERIPHERAL_MCBSP2 0x11815000 +#define L4_PERIPHERAL_MCBSP3 0x49024000 +#define DSPVA_PERIPHERAL_MCBSP3 0x11816000 +#define L4_PERIPHERAL_MCBSP4 0x49026000 +#define DSPVA_PERIPHERAL_MCBSP4 0x11817000 +#define L4_PERIPHERAL_MCBSP5 0x48096000 +#define DSPVA_PERIPHERAL_MCBSP5 0x11818000 + +#define L4_PERIPHERAL_GPTIMER5 0x49038000 +#define DSPVA_PERIPHERAL_GPTIMER5 0x11800000 +#define L4_PERIPHERAL_GPTIMER6 0x4903a000 +#define DSPVA_PERIPHERAL_GPTIMER6 0x11801000 +#define L4_PERIPHERAL_GPTIMER7 0x4903c000 +#define DSPVA_PERIPHERAL_GPTIMER7 0x11802000 +#define L4_PERIPHERAL_GPTIMER8 0x4903e000 +#define DSPVA_PERIPHERAL_GPTIMER8 0x11803000 + +#define L4_PERIPHERAL_SPI1 0x48098000 +#define DSPVA_PERIPHERAL_SPI1 0x1181a000 +#define L4_PERIPHERAL_SPI2 0x4809a000 +#define DSPVA_PERIPHERAL_SPI2 0x1181b000 + +#define L4_PERIPHERAL_MBOX 0x48094000 +#define DSPVA_PERIPHERAL_MBOX 0x11808000 + +#define PM_GRPSEL_BASE 0x48307000 +#define DSPVA_GRPSEL_BASE 0x11821000 + +#define L4_PERIPHERAL_SIDETONE_MCBSP2 0x49028000 +#define DSPVA_PERIPHERAL_SIDETONE_MCBSP2 0x11824000 +#define L4_PERIPHERAL_SIDETONE_MCBSP3 0x4902a000 +#define DSPVA_PERIPHERAL_SIDETONE_MCBSP3 0x11825000 + +/* define a static array with L4 mappings */ +static const struct MAP_L4PERIPHERAL L4PeripheralTable[] = { + {L4_PERIPHERAL_MBOX, DSPVA_PERIPHERAL_MBOX}, + {L4_PERIPHERAL_SCM, DSPVA_PERIPHERAL_SCM}, + {L4_PERIPHERAL_MMU, DSPVA_PERIPHERAL_MMU}, + {L4_PERIPHERAL_GPTIMER5, DSPVA_PERIPHERAL_GPTIMER5}, + {L4_PERIPHERAL_GPTIMER6, DSPVA_PERIPHERAL_GPTIMER6}, + {L4_PERIPHERAL_GPTIMER7, DSPVA_PERIPHERAL_GPTIMER7}, + {L4_PERIPHERAL_GPTIMER8, DSPVA_PERIPHERAL_GPTIMER8}, + {L4_PERIPHERAL_GPIO1, DSPVA_PERIPHERAL_GPIO1}, + {L4_PERIPHERAL_GPIO2, DSPVA_PERIPHERAL_GPIO2}, + {L4_PERIPHERAL_GPIO3, DSPVA_PERIPHERAL_GPIO3}, + {L4_PERIPHERAL_GPIO4, DSPVA_PERIPHERAL_GPIO4}, + {L4_PERIPHERAL_GPIO5, DSPVA_PERIPHERAL_GPIO5}, + {L4_PERIPHERAL_IVA2WDT, DSPVA_PERIPHERAL_IVA2WDT}, + {L4_PERIPHERAL_DISPLAY, DSPVA_PERIPHERAL_DISPLAY}, + {L4_PERIPHERAL_SSI, DSPVA_PERIPHERAL_SSI}, + {L4_PERIPHERAL_GDD, DSPVA_PERIPHERAL_GDD}, + {L4_PERIPHERAL_SS1, DSPVA_PERIPHERAL_SS1}, + {L4_PERIPHERAL_SS2, DSPVA_PERIPHERAL_SS2}, + {L4_PERIPHERAL_UART1, DSPVA_PERIPHERAL_UART1}, + {L4_PERIPHERAL_UART2, DSPVA_PERIPHERAL_UART2}, + {L4_PERIPHERAL_UART3, DSPVA_PERIPHERAL_UART3}, + {L4_PERIPHERAL_MCBSP1, DSPVA_PERIPHERAL_MCBSP1}, + {L4_PERIPHERAL_MCBSP2, DSPVA_PERIPHERAL_MCBSP2}, + {L4_PERIPHERAL_MCBSP3, DSPVA_PERIPHERAL_MCBSP3}, + {L4_PERIPHERAL_MCBSP4, DSPVA_PERIPHERAL_MCBSP4}, + {L4_PERIPHERAL_MCBSP5, DSPVA_PERIPHERAL_MCBSP5}, + {L4_PERIPHERAL_CAMERA, DSPVA_PERIPHERAL_CAMERA}, + {L4_PERIPHERAL_SPI1, DSPVA_PERIPHERAL_SPI1}, + {L4_PERIPHERAL_SPI2, DSPVA_PERIPHERAL_SPI2}, + {L4_PERIPHERAL_PRM, DSPVA_PERIPHERAL_PRM}, + {L4_PERIPHERAL_CM, DSPVA_PERIPHERAL_CM}, + {L4_PERIPHERAL_PER, DSPVA_PERIPHERAL_PER}, + {PM_GRPSEL_BASE, DSPVA_GRPSEL_BASE}, + {L4_PERIPHERAL_SIDETONE_MCBSP2, DSPVA_PERIPHERAL_SIDETONE_MCBSP2}, + {L4_PERIPHERAL_SIDETONE_MCBSP3, DSPVA_PERIPHERAL_SIDETONE_MCBSP3}, + {L4_PERIPHERAL_NULL, DSPVA_PERIPHERAL_NULL} +}; + +/* + * 15 10 0 + * --------------------------------- + * |0|0|1|0|0|0|c|c|c|i|i|i|i|i|i|i| + * --------------------------------- + * | (class) | (module specific) | + * + * where c -> Externel Clock Command: Clk & Autoidle Disable/Enable + * i -> External Clock ID Timers 5,6,7,8, McBSP1,2 and WDT3 + */ + +/* MBX_PM_CLK_IDMASK: DSP External clock id mask. */ +#define MBX_PM_CLK_IDMASK 0x7F + +/* MBX_PM_CLK_CMDSHIFT: DSP External clock command shift. */ +#define MBX_PM_CLK_CMDSHIFT 7 + +/* MBX_PM_CLK_CMDMASK: DSP External clock command mask. */ +#define MBX_PM_CLK_CMDMASK 7 + +/* MBX_PM_MAX_RESOURCES: CORE 1 Clock resources. */ +#define MBX_CORE1_RESOURCES 7 + +/* MBX_PM_MAX_RESOURCES: CORE 2 Clock Resources. */ +#define MBX_CORE2_RESOURCES 1 + +/* MBX_PM_MAX_RESOURCES: TOTAL Clock Reosurces. */ +#define MBX_PM_MAX_RESOURCES 11 + +/* Power Management Commands */ +enum BPWR_ExtClockCmd { + BPWR_DisableClock = 0, + BPWR_EnableClock, + BPWR_DisableAutoIdle, + BPWR_EnableAutoIdle +} ; + +/* OMAP242x specific resources */ +enum BPWR_ExtClockId { + BPWR_GPTimer5 = 0x10, + BPWR_GPTimer6, + BPWR_GPTimer7, + BPWR_GPTimer8, + BPWR_WDTimer3, + BPWR_MCBSP1, + BPWR_MCBSP2, + BPWR_MCBSP3, + BPWR_MCBSP4, + BPWR_MCBSP5, + BPWR_SSI = 0x20 +} ; + +static const u32 BPWR_CLKID[] = { + (u32) BPWR_GPTimer5, + (u32) BPWR_GPTimer6, + (u32) BPWR_GPTimer7, + (u32) BPWR_GPTimer8, + (u32) BPWR_WDTimer3, + (u32) BPWR_MCBSP1, + (u32) BPWR_MCBSP2, + (u32) BPWR_MCBSP3, + (u32) BPWR_MCBSP4, + (u32) BPWR_MCBSP5, + (u32) BPWR_SSI +}; + +struct BPWR_Clk_t { + u32 clkId; + enum SERVICES_ClkId funClk; + enum SERVICES_ClkId intClk; +} ; + +static const struct BPWR_Clk_t BPWR_Clks[] = { + {(u32) BPWR_GPTimer5, SERVICESCLK_gpt5_fck, SERVICESCLK_gpt5_ick}, + {(u32) BPWR_GPTimer6, SERVICESCLK_gpt6_fck, SERVICESCLK_gpt6_ick}, + {(u32) BPWR_GPTimer7, SERVICESCLK_gpt7_fck, SERVICESCLK_gpt7_ick}, + {(u32) BPWR_GPTimer8, SERVICESCLK_gpt8_fck, SERVICESCLK_gpt8_ick}, + {(u32) BPWR_WDTimer3, SERVICESCLK_wdt3_fck, SERVICESCLK_wdt3_ick}, + {(u32) BPWR_MCBSP1, SERVICESCLK_mcbsp1_fck, SERVICESCLK_mcbsp1_ick}, + {(u32) BPWR_MCBSP2, SERVICESCLK_mcbsp2_fck, SERVICESCLK_mcbsp2_ick}, + {(u32) BPWR_MCBSP3, SERVICESCLK_mcbsp3_fck, SERVICESCLK_mcbsp3_ick}, + {(u32) BPWR_MCBSP4, SERVICESCLK_mcbsp4_fck, SERVICESCLK_mcbsp4_ick}, + {(u32) BPWR_MCBSP5, SERVICESCLK_mcbsp5_fck, SERVICESCLK_mcbsp5_ick}, + {(u32) BPWR_SSI, SERVICESCLK_ssi_fck, SERVICESCLK_ssi_ick} +}; + +/* Interrupt Register Offsets */ +#define INTH_IT_REG_OFFSET 0x00 /* Interrupt register offset */ +#define INTH_MASK_IT_REG_OFFSET 0x04 /* Mask Interrupt reg offset */ + +#define DSP_MAILBOX1_INT 10 + +/* + * INTH_InterruptKind_t + * Identify the kind of interrupt: either FIQ/IRQ + */ +enum INTH_InterruptKind_t { + INTH_IRQ = 0, + INTH_FIQ = 1 +} ; + +enum INTH_SensitiveEdge_t { + FALLING_EDGE_SENSITIVE = 0, + LOW_LEVEL_SENSITIVE = 1 +} ; + +/* + * Bit definition of Interrupt Level Registers + */ + +/* Mail Box defines */ +#define MB_ARM2DSP1_REG_OFFSET 0x00 + +#define MB_ARM2DSP1B_REG_OFFSET 0x04 + +#define MB_DSP2ARM1B_REG_OFFSET 0x0C + +#define MB_ARM2DSP1_FLAG_REG_OFFSET 0x18 + +#define MB_ARM2DSP_FLAG 0x0001 + +#define MBOX_ARM2DSP HW_MBOX_ID_0 +#define MBOX_DSP2ARM HW_MBOX_ID_1 +#define MBOX_ARM HW_MBOX_U0_ARM +#define MBOX_DSP HW_MBOX_U1_DSP1 + +#define ENABLE true +#define DISABLE false + +#define HIGH_LEVEL true +#define LOW_LEVEL false + +/* Macro's */ +#define REG16(A) (*(REG_UWORD16 *)(A)) + +#define ClearBit(reg, mask) (reg &= ~mask) +#define SetBit(reg, mask) (reg |= mask) + +#define SetGroupBits16(reg, position, width, value) \ + do {\ + reg &= ~((0xFFFF >> (16 - (width))) << (position)) ; \ + reg |= ((value & (0xFFFF >> (16 - (width)))) << (position)); \ + } while (0); + +#define ClearBitIndex(reg, index) (reg &= ~(1 << (index))) + +/* This mini driver's device context: */ +struct WMD_DEV_CONTEXT { + struct DEV_OBJECT *hDevObject; /* Handle to WCD device object. */ + u32 dwDspBaseAddr; /* Arm's API to DSP virtual base addr */ + /* + * DSP External memory prog address as seen virtually by the OS on + * the host side. + */ + u32 dwDspExtBaseAddr; /* See the comment above */ + u32 dwAPIRegBase; /* API memory mapped registers */ + u32 dwDSPMmuBase; /* DSP MMU Mapped registers */ + u32 dwMailBoxBase; /* Mail box mapped registers */ + u32 dwAPIClkBase; /* CLK Registers */ + u32 dwDSPClkM2Base; /* DSP Clock Module m2 */ + u32 dwPublicRhea; /* Pub Rhea */ + u32 dwIntAddr; /* MB INTR reg */ + u32 dwTCEndianism; /* TC Endianism register */ + u32 dwTestBase; /* DSP MMU Mapped registers */ + u32 dwSelfLoop; /* Pointer to the selfloop */ + u32 dwDSPStartAdd; /* API Boot vector */ + u32 dwInternalSize; /* Internal memory size */ + + /* + * Processor specific info is set when prog loaded and read from DCD. + * [See WMD_BRD_Ctrl()] PROC info contains DSP-MMU TLB entries. + */ + /* DMMU TLB entries */ + struct WMDIOCTL_EXTPROC aTLBEntry[WMDIOCTL_NUMOFMMUTLB]; + u32 dwBrdState; /* Last known board state. */ + u32 ulIntMask; /* int mask */ + u16 ioBase; /* Board I/O base */ + u32 numTLBEntries; /* DSP MMU TLB entry counter */ + u32 fixedTLBEntries; /* Fixed DSPMMU TLB entry count */ + + /* TC Settings */ + bool tcWordSwapOn; /* Traffic Controller Word Swap */ + struct PgTableAttrs *pPtAttrs; + u32 uDspPerClks; +} ; + + /* + * ======== WMD_TLB_DspVAToMpuPA ======== + * Given a DSP virtual address, traverse the page table and return + * a corresponding MPU physical address and size. + */ +extern DSP_STATUS WMD_TLB_DspVAToMpuPA(struct WMD_DEV_CONTEXT *pDevContext, + IN u32 ulVirtAddr, + OUT u32 *ulPhysAddr, + OUT u32 *sizeTlb); + +#endif /* _TIOMAP_ */ + diff --git a/drivers/dsp/bridge/wmd/_tiomap_mmu.h b/drivers/dsp/bridge/wmd/_tiomap_mmu.h new file mode 100644 index 0000000..6b21047 --- /dev/null +++ b/drivers/dsp/bridge/wmd/_tiomap_mmu.h @@ -0,0 +1,53 @@ +/* + * _tiomap_mmu.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== _tiomap_mmu.h ======== + * Description: + * Definitions and types for the DSP MMU modules + * + *! Revision History + *! ================ + *! 19-Apr-2004 sb: Renamed HW types. Removed dspMmuTlbEntry + *! 05-Jan-2004 vp: Moved the file to a platform specific folder from common. + *! 21-Mar-2003 sb: Added macro definition TIHEL_LARGEPAGESIZE + *! 08-Oct-2002 rr: Created. + */ + +#ifndef _TIOMAP_MMU_ +#define _TIOMAP_MMU_ + +#include "_tiomap.h" + +/* + * ======== configureDspMmu ======== + * + * Make DSP MMu page table entries. + * Note: Not utilizing Coarse / Fine page tables. + * SECTION = 1MB, LARGE_PAGE = 64KB, SMALL_PAGE = 4KB, TINY_PAGE = 1KB. + * DSP Byte address 0x40_0000 is word addr 0x20_0000. + */ +extern void configureDspMmu(struct WMD_DEV_CONTEXT *pDevContext, + u32 dataBasePhys, + u32 dspBaseVirt, + u32 sizeInBytes, + s32 nEntryStart, + enum HW_Endianism_t endianism, + enum HW_ElementSize_t elemSize, + enum HW_MMUMixedSize_t mixedSize); + +#endif /* _TIOMAP_MMU_ */ diff --git a/drivers/dsp/bridge/wmd/_tiomap_pwr.h b/drivers/dsp/bridge/wmd/_tiomap_pwr.h new file mode 100644 index 0000000..7ebd7b5 --- /dev/null +++ b/drivers/dsp/bridge/wmd/_tiomap_pwr.h @@ -0,0 +1,102 @@ +/* + * _tiomap_pwr.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== _tiomap_pwr.h ======== + * Description: + * Definitions and types for the DSP wake/sleep routines. + * + *! Revision History + *! ================ + *! 08-Oct-2002 rr: Created. + */ + +#ifndef _TIOMAP_PWR_ +#define _TIOMAP_PWR_ + +/* + * ======== WakeDSP ========= + * Wakes up the DSP from DeepSleep + */ +extern DSP_STATUS WakeDSP(struct WMD_DEV_CONTEXT *pDevContext, IN void *pArgs); + +/* + * ======== SleepDSP ========= + * Places the DSP in DeepSleep. + */ +extern DSP_STATUS SleepDSP(struct WMD_DEV_CONTEXT *pDevContext, + IN u32 dwCmd, IN void *pArgs); +/* + * ========InterruptDSP======== + * Sends an interrupt to DSP unconditionally. + */ +extern void InterruptDSP(struct WMD_DEV_CONTEXT *pDevContext, IN u16 wMbVal); + +/* + * ======== WakeDSP ========= + * Wakes up the DSP from DeepSleep + */ +extern DSP_STATUS DSPPeripheralClkCtrl(struct WMD_DEV_CONTEXT *pDevContext, + IN void *pArgs); +/* + * ======== handle_hibernation_fromDSP ======== + * Handle Hibernation requested from DSP + */ +DSP_STATUS handle_hibernation_fromDSP(struct WMD_DEV_CONTEXT *pDevContext); +/* + * ======== PostScale_DSP ======== + * Handle Post Scale notification to DSP + */ +DSP_STATUS PostScale_DSP(struct WMD_DEV_CONTEXT *pDevContext, IN void *pArgs); +/* + * ======== PreScale_DSP ======== + * Handle Pre Scale notification to DSP + */ +DSP_STATUS PreScale_DSP(struct WMD_DEV_CONTEXT *pDevContext, IN void *pArgs); +/* + * ======== handle_constraints_set ======== + * Handle constraints request from DSP + */ +DSP_STATUS handle_constraints_set(struct WMD_DEV_CONTEXT *pDevContext, + IN void *pArgs); +/* + * ======== DSP_PeripheralClocks_Disable ======== + * This function disables all the peripheral clocks that + * were enabled by DSP. Call this function only when + * DSP is entering Hibernation or when DSP is in + * Error state + */ +DSP_STATUS DSP_PeripheralClocks_Disable(struct WMD_DEV_CONTEXT *pDevContext, + IN void *pArgs); + +/* + * ======== DSP_PeripheralClocks_Enable ======== + * This function enables all the peripheral clocks that + * were requested by DSP. + */ +DSP_STATUS DSP_PeripheralClocks_Enable(struct WMD_DEV_CONTEXT *pDevContext, + IN void *pArgs); + +/* + * ======== DSPClkWakeupEventCtrl ======== + * This function sets the group selction bits for while + * enabling/disabling. + */ +void DSPClkWakeupEventCtrl(u32 ClkId, bool enable); + +#endif /* _TIOMAP_PWR_ */ + diff --git a/drivers/dsp/bridge/wmd/_tiomap_util.h b/drivers/dsp/bridge/wmd/_tiomap_util.h new file mode 100644 index 0000000..47e1e5d --- /dev/null +++ b/drivers/dsp/bridge/wmd/_tiomap_util.h @@ -0,0 +1,46 @@ +/* + * _tiomap_util.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== _tiomap_util.h ======== + * Description: + * Definitions and types for the utility routines. + * + *! Revision History + *! ================ + *! 08-Oct-2002 rr: Created. + */ + +#ifndef _TIOMAP_UTIL_ +#define _TIOMAP_UTIL_ + +/* Time out Values in uSeconds*/ +#define TIHELEN_ACKTIMEOUT 10000 + +/* Time delay for HOM->SAM transition. */ +#define WAIT_SAM 1000000 /* in usec (1000 millisec) */ + +/* + * ======== WaitForStart ======== + * Wait for the singal from DSP that it has started, or time out. + * The argument dwSyncAddr is set to 1 before releasing the DSP. + * If the DSP starts running, it will clear this location. + */ +extern bool WaitForStart(struct WMD_DEV_CONTEXT *pDevContext, u32 dwSyncAddr); + +#endif /* _TIOMAP_UTIL_ */ + diff --git a/drivers/dsp/bridge/wmd/chnl_sm.c b/drivers/dsp/bridge/wmd/chnl_sm.c new file mode 100644 index 0000000..e8ffb2f --- /dev/null +++ b/drivers/dsp/bridge/wmd/chnl_sm.c @@ -0,0 +1,1100 @@ +/* + * chnl_sm.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== chnl_sm.c ======== + * Description: + * Implements upper edge functions for WMD channel module. + * + * Public Functions: + * WMD_CHNL_AddIOReq + * WMD_CHNL_CancelIO + * WMD_CHNL_Close + * WMD_CHNL_Create + * WMD_CHNL_Destroy + * WMD_CHNL_FlushIO + * WMD_CHNL_GetInfo + * WMD_CHNL_GetIOC + * WMD_CHNL_GetMgrInfo + * WMD_CHNL_Idle + * WMD_CHNL_Open + * + * Notes: + * The lower edge functions must be implemented by the WMD writer, and + * are declared in chnl_sm.h. + * + * Care is taken in this code to prevent simulataneous access to channel + * queues from + * 1. Threads. + * 2. IO_DPC(), scheduled from the IO_ISR() as an event. + * + * This is done primarily by: + * - Semaphores. + * - state flags in the channel object; and + * - ensuring the IO_Dispatch() routine, which is called from both + * CHNL_AddIOReq() and the DPC(if implemented), is not re-entered. + * + * Channel Invariant: + * There is an important invariant condition which must be maintained per + * channel outside of WMD_CHNL_GetIOC() and IO_Dispatch(), violation of + * which may cause timeouts and/or failure offunction SYNC_WaitOnEvent. + * This invariant condition is: + * + * LST_Empty(pChnl->pIOCompletions) ==> pChnl->hSyncEvent is reset + * and + * !LST_Empty(pChnl->pIOCompletions) ==> pChnl->hSyncEvent is set. + * + *! Revision History: + *! ================ + *! 10-Feb-2004 sb: Consolidated the MAILBOX_IRQ macro at the top of the file. + *! 05-Jan-2004 vp: Updated for 2.6 kernel on 24xx platform. + *! 23-Apr-2003 sb: Fixed mailbox deadlock + *! 24-Feb-2003 vp: Code Review Updates. + *! 18-Oct-2002 vp: Ported to Linux platform + *! 29-Aug-2002 rr Changed the SYNC error code return to DSP error code return + * in WMD_CHNL_GetIOC. + *! 22-Jan-2002 ag Zero-copy support added. + *! CMM_CallocBuf() used for SM allocations. + *! 04-Feb-2001 ag DSP-DMA support added. + *! 22-Nov-2000 kc: Updated usage of PERF_RegisterStat. + *! 06-Nov-2000 jeh Move ISR_Install, DPC_Create from CHNL_Create to IO_Create. + *! 13-Oct-2000 jeh Added dwArg parameter to WMD_CHNL_AddIOReq(), added + *! WMD_CHNL_Idle and WMD_CHNL_RegisterNotify for DSPStream. + *! Remove #ifdef DEBUG from around channel cIOCs field. + *! 21-Sep-2000 rr: PreOMAP chnl class library acts like a IO class library. + *! 25-Sep-2000 ag: MEM_[Unmap]LinearAddress added for #ifdef CHNL_PREOMAP. + *! 07-Sep-2000 rr: Added new channel class for PreOMAP. + *! 11-Jul-2000 jeh Allow NULL user event in WMD_CHNL_Open(). + *! 06-Jul-2000 rr: Changed prefix PROC to PRCS for process module calls. + *! 20-Jan-2000 ag: Incorporated code review comments. + *! 05-Jan-2000 ag: Text format cleanup. + *! 07-Dec-1999 ag: Now setting ChnlMgr fSharedIRQ flag before ISR_Install(). + *! 01-Dec-1999 ag: WMD_CHNL_Open() now accepts named sync event. + *! 14-Nov-1999 ag: DPC_Schedule() uncommented. + *! 28-Oct-1999 ag: CHNL Attrs userEvent not supported. + *! SM addrs taken from COFF(IO) or host resource(SM). + *! 25-May-1999 jg: CHNL_IOCLASS boards now get their shared memory buffer + *! address and length from symbols defined in the currently + *! loaded COFF file. See _chn_sm.h. + *! 18-Jun-1997 gp: Moved waiting back to ring 0 to improve performance. + *! 22-Jan-1998 gp: Update User's pIOC struct in GetIOC at lower IRQL (NT). + *! 16-Jan-1998 gp: Commented out PERF stuff, since it is not all there in NT. + *! 13-Jan-1998 gp: Protect IOCTLs from IO_DPC by raising IRQL to DIRQL (NT). + *! 22-Oct-1997 gp: Call SYNC_OpenEvent in CHNL_Open, for NT support. + *! 18-Jun-1997 gp: Moved waiting back to ring 0 to improve performance. + *! 16-Jun-1997 gp: Added call into lower edge CHNL function to allow override + *! of the SHM window length reported by Windows CM. + *! 05-Jun-1997 gp: Removed unnecessary critical sections. + *! 18-Mar-1997 gp: Ensured CHNL_FlushIO on input leaves channel in READY state. + *! 06-Jan-1997 gp: ifdefed to support the IO variant of SHM channel class lib. + *! 21-Jan-1997 gp: CHNL_Close: set pChnl = NULL for DBC_Ensure(). + *! 14-Jan-1997 gp: Updated based on code review feedback. + *! 03-Jan-1997 gp: Added CHNL_E_WAITTIMEOUT error return code to CHNL_FlushIO() + *! 23-Oct-1996 gp: Tag channel with ring 0 process handle. + *! 13-Sep-1996 gp: Added performance statistics for channel. + *! 09-Sep-1996 gp: Added WMD_CHNL_GetMgrInfo(). + *! 04-Sep-1996 gp: Removed shared memory control struct offset: made zero. + *! 01-Aug-1996 gp: Implemented basic channel manager and channel create/delete. + *! 17-Jul-1996 gp: Started pseudo coding. + *! 11-Jul-1996 gp: Stubbed out. + */ + +/* ----------------------------------- OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include + +/* ----------------------------------- Mini-Driver */ +#include +#include + +/* ----------------------------------- Platform Manager */ +#include + +/* ----------------------------------- Others */ +#include + +/* ----------------------------------- Define for This */ +#define USERMODE_ADDR PAGE_OFFSET + +#define MAILBOX_IRQ INT_MAIL_MPU_IRQ + +/* ----------------------------------- Function Prototypes */ +static struct LST_LIST *CreateChirpList(u32 uChirps); + +static void FreeChirpList(struct LST_LIST *pList); + +static struct CHNL_IRP *MakeNewChirp(void); + +static DSP_STATUS SearchFreeChannel(struct CHNL_MGR *pChnlMgr, + OUT u32 *pdwChnl); + +/* + * ======== WMD_CHNL_AddIOReq ======== + * Enqueue an I/O request for data transfer on a channel to the DSP. + * The direction (mode) is specified in the channel object. Note the DSP + * address is specified for channels opened in direct I/O mode. + */ +DSP_STATUS WMD_CHNL_AddIOReq(struct CHNL_OBJECT *hChnl, void *pHostBuf, + u32 cBytes, u32 cBufSize, + OPTIONAL u32 dwDspAddr, u32 dwArg) +{ + DSP_STATUS status = DSP_SOK; + struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl; + struct CHNL_IRP *pChirp = NULL; + u32 dwState; + bool fIsEOS; + struct CHNL_MGR *pChnlMgr = pChnl->pChnlMgr; + u8 *pHostSysBuf = NULL; + bool fSchedDPC = false; + u16 wMbVal = 0; + + DBG_Trace(DBG_ENTER, + "> WMD_CHNL_AddIOReq pChnl %p CHNL_IsOutput %x uChnlType " + "%x Id %d\n", pChnl, CHNL_IsOutput(pChnl->uMode), + pChnl->uChnlType, pChnl->uId); + + fIsEOS = (cBytes == 0) ? true : false; + + if (pChnl->uChnlType == CHNL_PCPY && pChnl->uId > 1 && pHostBuf) { + if (!(pHostBuf < (void *)USERMODE_ADDR)) { + pHostSysBuf = pHostBuf; + goto func_cont; + } + /* if addr in user mode, then copy to kernel space */ + pHostSysBuf = MEM_Alloc(cBufSize, MEM_NONPAGED); + if (pHostSysBuf == NULL) { + status = DSP_EMEMORY; + DBG_Trace(DBG_LEVEL7, + "No memory to allocate kernel buffer\n"); + goto func_cont; + } + if (CHNL_IsOutput(pChnl->uMode)) { + status = copy_from_user(pHostSysBuf, pHostBuf, + cBufSize); + if (status) { + DBG_Trace(DBG_LEVEL7, + "Error copying user buffer to " + "kernel, %d bytes remaining.\n", + status); + MEM_Free(pHostSysBuf); + pHostSysBuf = NULL; + status = DSP_EPOINTER; + } + } + } +func_cont: + /* Validate args: */ + if (pHostBuf == NULL) { + status = DSP_EPOINTER; + } else if (!MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) { + status = DSP_EHANDLE; + } else if (fIsEOS && CHNL_IsInput(pChnl->uMode)) { + status = CHNL_E_NOEOS; + } else { + /* Check the channel state: only queue chirp if channel state + * allows */ + dwState = pChnl->dwState; + if (dwState != CHNL_STATEREADY) { + if (dwState & CHNL_STATECANCEL) { + status = CHNL_E_CANCELLED; + } else if ((dwState & CHNL_STATEEOS) + && CHNL_IsOutput(pChnl->uMode)) { + status = CHNL_E_EOS; + } else { + /* No other possible states left: */ + DBC_Assert(0); + } + } + } + /* Mailbox IRQ is disabled to avoid race condition with DMA/ZCPY + * channels. DPCCS is held to avoid race conditions with PCPY channels. + * If DPC is scheduled in process context (IO_Schedule) and any + * non-mailbox interrupt occurs, that DPC will run and break CS. Hence + * we disable ALL DPCs. We will try to disable ONLY IO DPC later. */ + SYNC_EnterCS(pChnlMgr->hCSObj); + disable_irq(MAILBOX_IRQ); + if (pChnl->uChnlType == CHNL_PCPY) { + /* This is a processor-copy channel. */ + if (DSP_SUCCEEDED(status) && CHNL_IsOutput(pChnl->uMode)) { + /* Check buffer size on output channels for fit. */ + if (cBytes > IO_BufSize(pChnl->pChnlMgr->hIOMgr)) + status = CHNL_E_BUFSIZE; + + } + } + if (DSP_SUCCEEDED(status)) { + /* Get a free chirp: */ + pChirp = (struct CHNL_IRP *)LST_GetHead(pChnl->pFreeList); + if (pChirp == NULL) + status = CHNL_E_NOIORPS; + + } + if (DSP_SUCCEEDED(status)) { + /* Enqueue the chirp on the chnl's IORequest queue: */ + pChirp->pHostUserBuf = pChirp->pHostSysBuf = pHostBuf; + if (pChnl->uChnlType == CHNL_PCPY && pChnl->uId > 1) + pChirp->pHostSysBuf = pHostSysBuf; + + if (DSP_SUCCEEDED(status)) { + /* Note: for dma chans dwDspAddr contains dsp address + * of SM buffer.*/ + DBC_Assert(pChnlMgr->uWordSize != 0); + /* DSP address */ + pChirp->uDspAddr = dwDspAddr / pChnlMgr->uWordSize; + pChirp->cBytes = cBytes; + pChirp->cBufSize = cBufSize; + /* Only valid for output channel */ + pChirp->dwArg = dwArg; + pChirp->status = (fIsEOS ? CHNL_IOCSTATEOS : + CHNL_IOCSTATCOMPLETE); + LST_PutTail(pChnl->pIORequests, (struct LST_ELEM *) + pChirp); + pChnl->cIOReqs++; + DBC_Assert(pChnl->cIOReqs <= pChnl->cChirps); + /* If end of stream, update the channel state to prevent + * more IOR's: */ + if (fIsEOS) + pChnl->dwState |= CHNL_STATEEOS; + + { + /* Legacy DSM Processor-Copy */ + DBC_Assert(pChnl->uChnlType == CHNL_PCPY); + /* Request IO from the DSP */ + IO_RequestChnl(pChnlMgr->hIOMgr, pChnl, + (CHNL_IsInput(pChnl->uMode) ? + IO_INPUT : IO_OUTPUT), &wMbVal); + fSchedDPC = true; + } + } + } + enable_irq(MAILBOX_IRQ); + SYNC_LeaveCS(pChnlMgr->hCSObj); + if (wMbVal != 0) + IO_IntrDSP2(pChnlMgr->hIOMgr, wMbVal); + + if (fSchedDPC == true) { + /* Schedule a DPC, to do the actual data transfer: */ + IO_Schedule(pChnlMgr->hIOMgr); + } + DBG_Trace(DBG_ENTER, "< WMD_CHNL_AddIOReq pChnl %p\n", pChnl); + return status; +} + +/* + * ======== WMD_CHNL_CancelIO ======== + * Return all I/O requests to the client which have not yet been + * transferred. The channel's I/O completion object is + * signalled, and all the I/O requests are queued as IOC's, with the + * status field set to CHNL_IOCSTATCANCEL. + * This call is typically used in abort situations, and is a prelude to + * CHNL_Close(); + */ +DSP_STATUS WMD_CHNL_CancelIO(struct CHNL_OBJECT *hChnl) +{ + DSP_STATUS status = DSP_SOK; + struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl; + u32 iChnl = -1; + CHNL_MODE uMode; + struct CHNL_IRP *pChirp; + struct CHNL_MGR *pChnlMgr = NULL; + + /* Check args: */ + if (MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) { + iChnl = pChnl->uId; + uMode = pChnl->uMode; + pChnlMgr = pChnl->pChnlMgr; + } else { + status = DSP_EHANDLE; + } + if (DSP_FAILED(status)) + goto func_end; + + /* Mark this channel as cancelled, to prevent further IORequests or + * IORequests or dispatching. */ + SYNC_EnterCS(pChnlMgr->hCSObj); + pChnl->dwState |= CHNL_STATECANCEL; + if (LST_IsEmpty(pChnl->pIORequests)) + goto func_cont; + + if (pChnl->uChnlType == CHNL_PCPY) { + /* Indicate we have no more buffers available for transfer: */ + if (CHNL_IsInput(pChnl->uMode)) { + IO_CancelChnl(pChnlMgr->hIOMgr, iChnl); + } else { + /* Record that we no longer have output buffers + * available: */ + pChnlMgr->dwOutputMask &= ~(1 << iChnl); + } + } + /* Move all IOR's to IOC queue: */ + while (!LST_IsEmpty(pChnl->pIORequests)) { + pChirp = (struct CHNL_IRP *)LST_GetHead(pChnl->pIORequests); + if (pChirp) { + pChirp->cBytes = 0; + pChirp->status |= CHNL_IOCSTATCANCEL; + LST_PutTail(pChnl->pIOCompletions, + (struct LST_ELEM *)pChirp); + pChnl->cIOCs++; + pChnl->cIOReqs--; + DBC_Assert(pChnl->cIOReqs >= 0); + } + } +func_cont: + SYNC_LeaveCS(pChnlMgr->hCSObj); +func_end: + return status; +} + +/* + * ======== WMD_CHNL_Close ======== + * Purpose: + * Ensures all pending I/O on this channel is cancelled, discards all + * queued I/O completion notifications, then frees the resources allocated + * for this channel, and makes the corresponding logical channel id + * available for subsequent use. + */ +DSP_STATUS WMD_CHNL_Close(struct CHNL_OBJECT *hChnl) +{ + DSP_STATUS status; + struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl; + + /* Check args: */ + if (!MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) { + status = DSP_EHANDLE; + goto func_cont; + } + { + /* Cancel IO: this ensures no further IO requests or + * notifications.*/ + status = WMD_CHNL_CancelIO(hChnl); + } +func_cont: + if (DSP_SUCCEEDED(status)) { + /* Assert I/O on this channel is now cancelled: Protects + * from IO_DPC. */ + DBC_Assert((pChnl->dwState & CHNL_STATECANCEL)); + /* Invalidate channel object: Protects from + * CHNL_GetIOCompletion(). */ + pChnl->dwSignature = 0x0000; + /* Free the slot in the channel manager: */ + pChnl->pChnlMgr->apChannel[pChnl->uId] = NULL; + pChnl->pChnlMgr->cOpenChannels -= 1; + if (pChnl->hNtfy) { + NTFY_Delete(pChnl->hNtfy); + pChnl->hNtfy = NULL; + } + /* Reset channel event: (NOTE: hUserEvent freed in user + * context.). */ + if (pChnl->hSyncEvent) { + SYNC_ResetEvent(pChnl->hSyncEvent); + SYNC_CloseEvent(pChnl->hSyncEvent); + pChnl->hSyncEvent = NULL; + } + /* Free I/O request and I/O completion queues: */ + if (pChnl->pIOCompletions) { + FreeChirpList(pChnl->pIOCompletions); + pChnl->pIOCompletions = NULL; + pChnl->cIOCs = 0; + } + if (pChnl->pIORequests) { + FreeChirpList(pChnl->pIORequests); + pChnl->pIORequests = NULL; + pChnl->cIOReqs = 0; + } + if (pChnl->pFreeList) { + FreeChirpList(pChnl->pFreeList); + pChnl->pFreeList = NULL; + } + /* Release channel object. */ + MEM_FreeObject(pChnl); + pChnl = NULL; + } + DBC_Ensure(DSP_FAILED(status) || + !MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)); + return status; +} + +/* + * ======== WMD_CHNL_Create ======== + * Create a channel manager object, responsible for opening new channels + * and closing old ones for a given board. + */ +DSP_STATUS WMD_CHNL_Create(OUT struct CHNL_MGR **phChnlMgr, + struct DEV_OBJECT *hDevObject, + IN CONST struct CHNL_MGRATTRS *pMgrAttrs) +{ + DSP_STATUS status = DSP_SOK; + struct CHNL_MGR *pChnlMgr = NULL; + s32 cChannels; +#ifdef DEBUG + struct CHNL_MGR *hChnlMgr; +#endif + /* Check DBC requirements: */ + DBC_Require(phChnlMgr != NULL); + DBC_Require(pMgrAttrs != NULL); + DBC_Require(pMgrAttrs->cChannels > 0); + DBC_Require(pMgrAttrs->cChannels <= CHNL_MAXCHANNELS); + DBC_Require(pMgrAttrs->uWordSize != 0); +#ifdef DEBUG + /* This for the purposes of DBC_Require: */ + status = DEV_GetChnlMgr(hDevObject, &hChnlMgr); + DBC_Require(status != DSP_EHANDLE); + DBC_Require(hChnlMgr == NULL); +#endif + if (DSP_SUCCEEDED(status)) { + /* Allocate channel manager object: */ + MEM_AllocObject(pChnlMgr, struct CHNL_MGR, CHNL_MGRSIGNATURE); + if (pChnlMgr) { + /* The cChannels attr must equal the # of supported + * chnls for each transport(# chnls for PCPY = DDMA = + * ZCPY): i.e. pMgrAttrs->cChannels = CHNL_MAXCHANNELS = + * DDMA_MAXDDMACHNLS = DDMA_MAXZCPYCHNLS. */ + DBC_Assert(pMgrAttrs->cChannels == CHNL_MAXCHANNELS); + cChannels = (CHNL_MAXCHANNELS + (CHNL_MAXCHANNELS * + CHNL_PCPY)); + /* Create array of channels: */ + pChnlMgr->apChannel = MEM_Calloc( + sizeof(struct CHNL_OBJECT *) * + cChannels, MEM_NONPAGED); + if (pChnlMgr->apChannel) { + /* Initialize CHNL_MGR object: */ + /* Shared memory driver. */ + pChnlMgr->dwType = CHNL_TYPESM; + pChnlMgr->uWordSize = pMgrAttrs->uWordSize; + /* total # chnls supported */ + pChnlMgr->cChannels = cChannels; + pChnlMgr->cOpenChannels = 0; + pChnlMgr->dwOutputMask = 0; + pChnlMgr->dwLastOutput = 0; + pChnlMgr->hDevObject = hDevObject; + if (DSP_SUCCEEDED(status)) { + status = SYNC_InitializeDPCCS + (&pChnlMgr->hCSObj); + } + } else { + status = DSP_EMEMORY; + } + } else { + status = DSP_EMEMORY; + } + } + if (DSP_FAILED(status)) { + WMD_CHNL_Destroy(pChnlMgr); + *phChnlMgr = NULL; + } else { + /* Return channel manager object to caller... */ + *phChnlMgr = pChnlMgr; + } + return status; +} + +/* + * ======== WMD_CHNL_Destroy ======== + * Purpose: + * Close all open channels, and destroy the channel manager. + */ +DSP_STATUS WMD_CHNL_Destroy(struct CHNL_MGR *hChnlMgr) +{ + DSP_STATUS status = DSP_SOK; + struct CHNL_MGR *pChnlMgr = hChnlMgr; + u32 iChnl; + + if (MEM_IsValidHandle(hChnlMgr, CHNL_MGRSIGNATURE)) { + /* Close all open channels: */ + for (iChnl = 0; iChnl < pChnlMgr->cChannels; iChnl++) { + if (DSP_SUCCEEDED + (WMD_CHNL_Close(pChnlMgr->apChannel[iChnl]))) { + DBC_Assert(pChnlMgr->apChannel[iChnl] == NULL); + } + } + /* release critical section */ + if (pChnlMgr->hCSObj) + SYNC_DeleteCS(pChnlMgr->hCSObj); + + /* Free channel manager object: */ + if (pChnlMgr->apChannel) + MEM_Free(pChnlMgr->apChannel); + + /* Set hChnlMgr to NULL in device object. */ + DEV_SetChnlMgr(pChnlMgr->hDevObject, NULL); + /* Free this Chnl Mgr object: */ + MEM_FreeObject(hChnlMgr); + } else { + status = DSP_EHANDLE; + } + return status; +} + +/* + * ======== WMD_CHNL_FlushIO ======== + * purpose: + * Flushes all the outstanding data requests on a channel. + */ +DSP_STATUS WMD_CHNL_FlushIO(struct CHNL_OBJECT *hChnl, u32 dwTimeOut) +{ + DSP_STATUS status = DSP_SOK; + struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl; + CHNL_MODE uMode = -1; + struct CHNL_MGR *pChnlMgr; + struct CHNL_IOC chnlIOC; + /* Check args: */ + if (MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) { + if ((dwTimeOut == CHNL_IOCNOWAIT) + && CHNL_IsOutput(pChnl->uMode)) { + status = DSP_EINVALIDARG; + } else { + uMode = pChnl->uMode; + pChnlMgr = pChnl->pChnlMgr; + } + } else { + status = DSP_EHANDLE; + } + if (DSP_SUCCEEDED(status)) { + /* Note: Currently, if another thread continues to add IO + * requests to this channel, this function will continue to + * flush all such queued IO requests. */ + if (CHNL_IsOutput(uMode) && (pChnl->uChnlType == CHNL_PCPY)) { + /* Wait for IO completions, up to the specified + * timeout: */ + while (!LST_IsEmpty(pChnl->pIORequests) && + DSP_SUCCEEDED(status)) { + status = WMD_CHNL_GetIOC(hChnl, dwTimeOut, + &chnlIOC); + if (DSP_FAILED(status)) + continue; + + if (chnlIOC.status & CHNL_IOCSTATTIMEOUT) + status = CHNL_E_WAITTIMEOUT; + + } + } else { + status = WMD_CHNL_CancelIO(hChnl); + /* Now, leave the channel in the ready state: */ + pChnl->dwState &= ~CHNL_STATECANCEL; + } + } + DBC_Ensure(DSP_FAILED(status) || LST_IsEmpty(pChnl->pIORequests)); + return status; +} + +/* + * ======== WMD_CHNL_GetInfo ======== + * Purpose: + * Retrieve information related to a channel. + */ +DSP_STATUS WMD_CHNL_GetInfo(struct CHNL_OBJECT *hChnl, + OUT struct CHNL_INFO *pInfo) +{ + DSP_STATUS status = DSP_SOK; + struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl; + if (pInfo != NULL) { + if (MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) { + /* Return the requested information: */ + pInfo->hChnlMgr = pChnl->pChnlMgr; + pInfo->hEvent = pChnl->hUserEvent; + pInfo->dwID = pChnl->uId; + pInfo->dwMode = pChnl->uMode; + pInfo->cPosition = pChnl->cBytesMoved; + pInfo->hProcess = pChnl->hProcess; + pInfo->hSyncEvent = pChnl->hSyncEvent; + pInfo->cIOCs = pChnl->cIOCs; + pInfo->cIOReqs = pChnl->cIOReqs; + pInfo->dwState = pChnl->dwState; + } else { + status = DSP_EHANDLE; + } + } else { + status = DSP_EPOINTER; + } + return status; +} + +/* + * ======== WMD_CHNL_GetIOC ======== + * Optionally wait for I/O completion on a channel. Dequeue an I/O + * completion record, which contains information about the completed + * I/O request. + * Note: Ensures Channel Invariant (see notes above). + */ +DSP_STATUS WMD_CHNL_GetIOC(struct CHNL_OBJECT *hChnl, u32 dwTimeOut, + OUT struct CHNL_IOC *pIOC) +{ + DSP_STATUS status = DSP_SOK; + struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl; + struct CHNL_IRP *pChirp; + DSP_STATUS statSync; + bool fDequeueIOC = true; + struct CHNL_IOC ioc = { NULL, 0, 0, 0, 0 }; + u8 *pHostSysBuf = NULL; + + DBG_Trace(DBG_ENTER, "> WMD_CHNL_GetIOC pChnl %p CHNL_IsOutput %x " + "uChnlType %x\n", pChnl, CHNL_IsOutput(pChnl->uMode), + pChnl->uChnlType); + /* Check args: */ + if (pIOC == NULL) { + status = DSP_EPOINTER; + } else if (!MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) { + status = DSP_EHANDLE; + } else if (dwTimeOut == CHNL_IOCNOWAIT) { + if (LST_IsEmpty(pChnl->pIOCompletions)) + status = CHNL_E_NOIOC; + + } + if (DSP_FAILED(status)) + goto func_end; + + ioc.status = CHNL_IOCSTATCOMPLETE; + if (dwTimeOut != CHNL_IOCNOWAIT && LST_IsEmpty(pChnl->pIOCompletions)) { + if (dwTimeOut == CHNL_IOCINFINITE) + dwTimeOut = SYNC_INFINITE; + + statSync = SYNC_WaitOnEvent(pChnl->hSyncEvent, dwTimeOut); + if (statSync == DSP_ETIMEOUT) { + /* No response from DSP */ + ioc.status |= CHNL_IOCSTATTIMEOUT; + fDequeueIOC = false; + } else if (statSync == DSP_EFAIL) { + /* This can occur when the user mode thread is + * aborted (^C), or when _VWIN32_WaitSingleObject() + * fails due to unkown causes. */ + /* Even though Wait failed, there may be something in + * the Q: */ + if (LST_IsEmpty(pChnl->pIOCompletions)) { + ioc.status |= CHNL_IOCSTATCANCEL; + fDequeueIOC = false; + } + } + } + /* See comment in AddIOReq */ + SYNC_EnterCS(pChnl->pChnlMgr->hCSObj); + disable_irq(MAILBOX_IRQ); + if (fDequeueIOC) { + /* Dequeue IOC and set pIOC; */ + DBC_Assert(!LST_IsEmpty(pChnl->pIOCompletions)); + pChirp = (struct CHNL_IRP *)LST_GetHead(pChnl->pIOCompletions); + /* Update pIOC from channel state and chirp: */ + if (pChirp) { + pChnl->cIOCs--; + /* If this is a zero-copy channel, then set IOC's pBuf + * to the DSP's address. This DSP address will get + * translated to user's virtual addr later. */ + { + pHostSysBuf = pChirp->pHostSysBuf; + ioc.pBuf = pChirp->pHostUserBuf; + } + ioc.cBytes = pChirp->cBytes; + ioc.cBufSize = pChirp->cBufSize; + ioc.dwArg = pChirp->dwArg; + ioc.status |= pChirp->status; + /* Place the used chirp on the free list: */ + LST_PutTail(pChnl->pFreeList, (struct LST_ELEM *) + pChirp); + } else { + ioc.pBuf = NULL; + ioc.cBytes = 0; + } + } else { + ioc.pBuf = NULL; + ioc.cBytes = 0; + ioc.dwArg = 0; + ioc.cBufSize = 0; + } + /* Ensure invariant: If any IOC's are queued for this channel... */ + if (!LST_IsEmpty(pChnl->pIOCompletions)) { + /* Since DSPStream_Reclaim() does not take a timeout + * parameter, we pass the stream's timeout value to + * WMD_CHNL_GetIOC. We cannot determine whether or not + * we have waited in User mode. Since the stream's timeout + * value may be non-zero, we still have to set the event. + * Therefore, this optimization is taken out. + * + * if (dwTimeOut == CHNL_IOCNOWAIT) { + * ... ensure event is set.. + * SYNC_SetEvent(pChnl->hSyncEvent); + * } */ + SYNC_SetEvent(pChnl->hSyncEvent); + } else { + /* else, if list is empty, ensure event is reset. */ + SYNC_ResetEvent(pChnl->hSyncEvent); + } + enable_irq(MAILBOX_IRQ); + SYNC_LeaveCS(pChnl->pChnlMgr->hCSObj); + if (fDequeueIOC && (pChnl->uChnlType == CHNL_PCPY && pChnl->uId > 1)) { + if (!(ioc.pBuf < (void *) USERMODE_ADDR)) + goto func_cont; + + /* If the addr is in user mode, then copy it */ + if (!pHostSysBuf || !ioc.pBuf) { + status = DSP_EPOINTER; + DBG_Trace(DBG_LEVEL7, + "System buffer NULL in IO completion.\n"); + goto func_cont; + } + if (!CHNL_IsInput(pChnl->uMode)) + goto func_cont1; + + /*pHostUserBuf */ + status = copy_to_user(ioc.pBuf, pHostSysBuf, ioc.cBytes); +#ifndef RES_CLEANUP_DISABLE + if (status) { + if (current->flags & PF_EXITING) { + DBG_Trace(DBG_LEVEL7, + "\n2current->flags == PF_EXITING, " + " current->flags;0x%x\n", + current->flags); + status = 0; + } else { + DBG_Trace(DBG_LEVEL7, + "\n2current->flags != PF_EXITING, " + " current->flags;0x%x\n", + current->flags); + } + } +#endif + if (status) { + DBG_Trace(DBG_LEVEL7, + "Error copying kernel buffer to user, %d" + " bytes remaining. in_interupt %d\n", + status, in_interrupt()); + status = DSP_EPOINTER; + } +func_cont1: + MEM_Free(pHostSysBuf); + } +func_cont: + /* Update User's IOC block: */ + *pIOC = ioc; +func_end: + DBG_Trace(DBG_ENTER, "< WMD_CHNL_GetIOC pChnl %p\n", pChnl); + return status; +} + +/* + * ======== WMD_CHNL_GetMgrInfo ======== + * Retrieve information related to the channel manager. + */ +DSP_STATUS WMD_CHNL_GetMgrInfo(struct CHNL_MGR *hChnlMgr, u32 uChnlID, + OUT struct CHNL_MGRINFO *pMgrInfo) +{ + DSP_STATUS status = DSP_SOK; + struct CHNL_MGR *pChnlMgr = (struct CHNL_MGR *)hChnlMgr; + + if (pMgrInfo != NULL) { + if (uChnlID <= CHNL_MAXCHANNELS) { + if (MEM_IsValidHandle(hChnlMgr, CHNL_MGRSIGNATURE)) { + /* Return the requested information: */ + pMgrInfo->hChnl = pChnlMgr->apChannel[uChnlID]; + pMgrInfo->cOpenChannels = pChnlMgr-> + cOpenChannels; + pMgrInfo->dwType = pChnlMgr->dwType; + /* total # of chnls */ + pMgrInfo->cChannels = pChnlMgr->cChannels; + } else { + status = DSP_EHANDLE; + } + } else { + status = CHNL_E_BADCHANID; + } + } else { + status = DSP_EPOINTER; + } + + return status; +} + +/* + * ======== WMD_CHNL_Idle ======== + * Idles a particular channel. + */ +DSP_STATUS WMD_CHNL_Idle(struct CHNL_OBJECT *hChnl, u32 dwTimeOut, + bool fFlush) +{ + CHNL_MODE uMode; + struct CHNL_MGR *pChnlMgr; + DSP_STATUS status = DSP_SOK; + + DBC_Require(MEM_IsValidHandle(hChnl, CHNL_SIGNATURE)); + + uMode = hChnl->uMode; + pChnlMgr = hChnl->pChnlMgr; + + if (CHNL_IsOutput(uMode) && !fFlush) { + /* Wait for IO completions, up to the specified timeout: */ + status = WMD_CHNL_FlushIO(hChnl, dwTimeOut); + } else { + status = WMD_CHNL_CancelIO(hChnl); + + /* Reset the byte count and put channel back in ready state. */ + hChnl->cBytesMoved = 0; + hChnl->dwState &= ~CHNL_STATECANCEL; + } + + return status; +} + +/* + * ======== WMD_CHNL_Open ======== + * Open a new half-duplex channel to the DSP board. + */ +DSP_STATUS WMD_CHNL_Open(OUT struct CHNL_OBJECT **phChnl, + struct CHNL_MGR *hChnlMgr, CHNL_MODE uMode, + u32 uChnlId, CONST IN struct CHNL_ATTRS *pAttrs) +{ + DSP_STATUS status = DSP_SOK; + struct CHNL_MGR *pChnlMgr = hChnlMgr; + struct CHNL_OBJECT *pChnl = NULL; + struct SYNC_ATTRS *pSyncAttrs = NULL; + struct SYNC_OBJECT *hSyncEvent = NULL; + /* Ensure DBC requirements: */ + DBC_Require(phChnl != NULL); + DBC_Require(pAttrs != NULL); + *phChnl = NULL; + /* Validate Args: */ + if (pAttrs->uIOReqs == 0) { + status = DSP_EINVALIDARG; + } else { + if (!MEM_IsValidHandle(hChnlMgr, CHNL_MGRSIGNATURE)) { + status = DSP_EHANDLE; + } else { + if (uChnlId != CHNL_PICKFREE) { + if (uChnlId >= pChnlMgr->cChannels) { + status = CHNL_E_BADCHANID; + } else if (pChnlMgr->apChannel[uChnlId] != + NULL) { + status = CHNL_E_CHANBUSY; + } + } else { + /* Check for free channel */ + status = SearchFreeChannel(pChnlMgr, &uChnlId); + } + } + } + if (DSP_FAILED(status)) + goto func_end; + + DBC_Assert(uChnlId < pChnlMgr->cChannels); + /* Create channel object: */ + MEM_AllocObject(pChnl, struct CHNL_OBJECT, 0x0000); + if (!pChnl) { + status = DSP_EMEMORY; + goto func_cont; + } + /* Protect queues from IO_DPC: */ + pChnl->dwState = CHNL_STATECANCEL; + /* Allocate initial IOR and IOC queues: */ + pChnl->pFreeList = CreateChirpList(pAttrs->uIOReqs); + pChnl->pIORequests = CreateChirpList(0); + pChnl->pIOCompletions = CreateChirpList(0); + pChnl->cChirps = pAttrs->uIOReqs; + pChnl->cIOCs = 0; + pChnl->cIOReqs = 0; + status = SYNC_OpenEvent(&hSyncEvent, pSyncAttrs); + if (DSP_SUCCEEDED(status)) { + status = NTFY_Create(&pChnl->hNtfy); + if (DSP_FAILED(status)) { + /* The only failure that could have occurred */ + status = DSP_EMEMORY; + } + } + if (DSP_SUCCEEDED(status)) { + if (pChnl->pIOCompletions && pChnl->pIORequests && + pChnl->pFreeList) { + /* Initialize CHNL object fields: */ + pChnl->pChnlMgr = pChnlMgr; + pChnl->uId = uChnlId; + pChnl->uMode = uMode; + pChnl->hUserEvent = hSyncEvent; /* for Linux */ + pChnl->hSyncEvent = hSyncEvent; + /* get the process handle */ + pChnl->hProcess = current->pid; + pChnl->pCBArg = 0; + pChnl->cBytesMoved = 0; + /* Default to proc-copy */ + pChnl->uChnlType = CHNL_PCPY; + } else { + status = DSP_EMEMORY; + } + } else { + status = DSP_EINVALIDARG; + } + if (DSP_FAILED(status)) { + /* Free memory */ + if (pChnl->pIOCompletions) { + FreeChirpList(pChnl->pIOCompletions); + pChnl->pIOCompletions = NULL; + pChnl->cIOCs = 0; + } + if (pChnl->pIORequests) { + FreeChirpList(pChnl->pIORequests); + pChnl->pIORequests = NULL; + } + if (pChnl->pFreeList) { + FreeChirpList(pChnl->pFreeList); + pChnl->pFreeList = NULL; + } + if (hSyncEvent) { + SYNC_CloseEvent(hSyncEvent); + hSyncEvent = NULL; + } + if (pChnl->hNtfy) { + NTFY_Delete(pChnl->hNtfy); + pChnl->hNtfy = NULL; + } + MEM_FreeObject(pChnl); + } +func_cont: + if (DSP_SUCCEEDED(status)) { + /* Insert channel object in channel manager: */ + pChnlMgr->apChannel[pChnl->uId] = pChnl; + SYNC_EnterCS(pChnlMgr->hCSObj); + pChnlMgr->cOpenChannels++; + SYNC_LeaveCS(pChnlMgr->hCSObj); + /* Return result... */ + pChnl->dwSignature = CHNL_SIGNATURE; + pChnl->dwState = CHNL_STATEREADY; + *phChnl = pChnl; + } +func_end: + DBC_Ensure((DSP_SUCCEEDED(status) && + MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) || + (*phChnl == NULL)); + return status; +} + +/* + * ======== WMD_CHNL_RegisterNotify ======== + * Registers for events on a particular channel. + */ +DSP_STATUS WMD_CHNL_RegisterNotify(struct CHNL_OBJECT *hChnl, u32 uEventMask, + u32 uNotifyType, + struct DSP_NOTIFICATION *hNotification) +{ + DSP_STATUS status = DSP_SOK; + + DBC_Assert(!(uEventMask & ~(DSP_STREAMDONE | DSP_STREAMIOCOMPLETION))); + + status = NTFY_Register(hChnl->hNtfy, hNotification, uEventMask, + uNotifyType); + + return status; +} + +/* + * ======== CreateChirpList ======== + * Purpose: + * Initialize a queue of channel I/O Request/Completion packets. + * Parameters: + * uChirps: Number of Chirps to allocate. + * Returns: + * Pointer to queue of IRPs, or NULL. + * Requires: + * Ensures: + */ +static struct LST_LIST *CreateChirpList(u32 uChirps) +{ + struct LST_LIST *pChirpList; + struct CHNL_IRP *pChirp; + u32 i; + + pChirpList = LST_Create(); + + if (pChirpList) { + /* Make N chirps and place on queue. */ + for (i = 0; (i < uChirps) && ((pChirp = MakeNewChirp()) != + NULL); i++) { + LST_PutTail(pChirpList, (struct LST_ELEM *)pChirp); + } + + /* If we couldn't allocate all chirps, free those allocated: */ + if (i != uChirps) { + FreeChirpList(pChirpList); + pChirpList = NULL; + } + } + + return pChirpList; +} + +/* + * ======== FreeChirpList ======== + * Purpose: + * Free the queue of Chirps. + */ +static void FreeChirpList(struct LST_LIST *pChirpList) +{ + DBC_Require(pChirpList != NULL); + + while (!LST_IsEmpty(pChirpList)) + MEM_Free(LST_GetHead(pChirpList)); + + LST_Delete(pChirpList); +} + +/* + * ======== MakeNewChirp ======== + * Allocate the memory for a new channel IRP. + */ +static struct CHNL_IRP *MakeNewChirp(void) +{ + struct CHNL_IRP *pChirp; + + pChirp = (struct CHNL_IRP *)MEM_Calloc( + sizeof(struct CHNL_IRP), MEM_NONPAGED); + if (pChirp != NULL) { + /* LST_InitElem only resets the list's member values. */ + LST_InitElem(&pChirp->link); + } + + return pChirp; +} + +/* + * ======== SearchFreeChannel ======== + * Search for a free channel slot in the array of channel pointers. + */ +static DSP_STATUS SearchFreeChannel(struct CHNL_MGR *pChnlMgr, + OUT u32 *pdwChnl) +{ + DSP_STATUS status = CHNL_E_OUTOFSTREAMS; + u32 i; + + DBC_Require(MEM_IsValidHandle(pChnlMgr, CHNL_MGRSIGNATURE)); + + for (i = 0; i < pChnlMgr->cChannels; i++) { + if (pChnlMgr->apChannel[i] == NULL) { + status = DSP_SOK; + *pdwChnl = i; + break; + } + } + + return status; +} diff --git a/drivers/dsp/bridge/wmd/io_sm.c b/drivers/dsp/bridge/wmd/io_sm.c new file mode 100644 index 0000000..325f1f1 --- /dev/null +++ b/drivers/dsp/bridge/wmd/io_sm.c @@ -0,0 +1,2011 @@ +/* + * io_sm.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== io_sm.c ======== + * Description: + * IO dispatcher for a shared memory channel driver. + * + * Public Functions: + * WMD_IO_Create + * WMD_IO_Destroy + * WMD_IO_OnLoaded + * IO_AndSetValue + * IO_BufSize + * IO_CancelChnl + * IO_DPC + * IO_ISR + * IO_IVAISR + * IO_OrSetValue + * IO_ReadValue + * IO_ReadValueLong + * IO_RequestChnl + * IO_Schedule + * IO_WriteValue + * IO_WriteValueLong + * + * Channel Invariant: + * There is an important invariant condition which must be maintained per + * channel outside of WMD_CHNL_GetIOC() and IO_Dispatch(), violation of + * which may cause timeouts and/or failure of the WIN32_WaitSingleObject + * function (SYNC_WaitOnEvent). + * + */ + +/* ----------------------------------- Host OS */ +#include +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include +#include +#include + +/* ------------------------------------ Hardware Abstraction Layer */ +#include +#include + +/* ----------------------------------- Mini Driver */ +#include +#include +#include +#include <_tiomap.h> +#include +#include <_tiomap_pwr.h> +#include + +/* ----------------------------------- Platform Manager */ +#include +#include +#include +#include + +/* ----------------------------------- Others */ +#include +#include +#include +#include "_cmm.h" + +/* ----------------------------------- This */ +#include +#include "_msg_sm.h" +#include + +/* ----------------------------------- Defines, Data Structures, Typedefs */ +#define OUTPUTNOTREADY 0xffff +#define NOTENABLED 0xffff /* channel(s) not enabled */ + +#define EXTEND "_EXT_END" + +#define SwapWord(x) (x) +#define ulPageAlignSize 0x10000 /* Page Align Size */ + +#define MAX_PM_REQS 32 + +/* IO Manager: only one created per board: */ +struct IO_MGR { + /* These four fields must be the first fields in a IO_MGR_ struct: */ + u32 dwSignature; /* Used for object validation */ + struct WMD_DEV_CONTEXT *hWmdContext; /* WMD device context */ + struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD */ + struct DEV_OBJECT *hDevObject; /* Device this board represents */ + + /* These fields initialized in WMD_IO_Create(): */ + struct CHNL_MGR *hChnlMgr; + struct SHM *pSharedMem; /* Shared Memory control */ + u8 *pInput; /* Address of input channel */ + u8 *pOutput; /* Address of output channel */ + struct MSG_MGR *hMsgMgr; /* Message manager */ + struct MSG *pMsgInputCtrl; /* Msg control for from DSP messages */ + struct MSG *pMsgOutputCtrl; /* Msg control for to DSP messages */ + u8 *pMsgInput; /* Address of input messages */ + u8 *pMsgOutput; /* Address of output messages */ + u32 uSMBufSize; /* Size of a shared memory I/O channel */ + bool fSharedIRQ; /* Is this IRQ shared? */ + struct DPC_OBJECT *hDPC; /* DPC object handle */ + struct SYNC_CSOBJECT *hCSObj; /* Critical section object handle */ + u32 uWordSize; /* Size in bytes of DSP word */ + u16 wIntrVal; /* interrupt value */ + /* private extnd proc info; mmu setup */ + struct MGR_PROCESSOREXTINFO extProcInfo; + struct CMM_OBJECT *hCmmMgr; /* Shared Mem Mngr */ + struct work_struct io_workq; /*workqueue */ + u32 dQuePowerMbxVal[MAX_PM_REQS]; + u32 iQuePowerHead; + u32 iQuePowerTail; +#ifndef DSP_TRACEBUF_DISABLED + u32 ulTraceBufferBegin; /* Trace message start address */ + u32 ulTraceBufferEnd; /* Trace message end address */ + u32 ulTraceBufferCurrent; /* Trace message current address */ + u32 ulGPPReadPointer; /* GPP Read pointer to Trace buffer */ + u8 *pMsg; + u32 ulGppVa; + u32 ulDspVa; +#endif +} ; + +/* ----------------------------------- Function Prototypes */ +static void IO_DispatchChnl(IN struct IO_MGR *pIOMgr, + IN OUT struct CHNL_OBJECT *pChnl, u32 iMode); +static void IO_DispatchMsg(IN struct IO_MGR *pIOMgr, struct MSG_MGR *hMsgMgr); +static void IO_DispatchPM(struct work_struct *work); +static void NotifyChnlComplete(struct CHNL_OBJECT *pChnl, + struct CHNL_IRP *pChirp); +static void InputChnl(struct IO_MGR *pIOMgr, struct CHNL_OBJECT *pChnl, + u32 iMode); +static void OutputChnl(struct IO_MGR *pIOMgr, struct CHNL_OBJECT *pChnl, + u32 iMode); +static void InputMsg(struct IO_MGR *pIOMgr, struct MSG_MGR *hMsgMgr); +static void OutputMsg(struct IO_MGR *pIOMgr, struct MSG_MGR *hMsgMgr); +static u32 FindReadyOutput(struct CHNL_MGR *pChnlMgr, + struct CHNL_OBJECT *pChnl, u32 dwMask); +static u32 ReadData(struct WMD_DEV_CONTEXT *hDevContext, void *pDest, + void *pSrc, u32 uSize); +static u32 WriteData(struct WMD_DEV_CONTEXT *hDevContext, void *pDest, + void *pSrc, u32 uSize); +static struct workqueue_struct *bridge_workqueue; +#ifndef DSP_TRACEBUF_DISABLED +void PrintDSPDebugTrace(struct IO_MGR *hIOMgr); +#endif + +/* Bus Addr (cached kernel)*/ +static DSP_STATUS registerSHMSegs(struct IO_MGR *hIOMgr, + struct COD_MANAGER *hCodMan, + u32 dwGPPBasePA); + +#ifdef CONFIG_BRIDGE_DVFS +/* The maximum number of OPPs that are supported */ +extern s32 dsp_max_opps; +/* The Vdd1 opp table information */ +extern u32 vdd1_dsp_freq[6][4] ; +#endif + +#if GT_TRACE +static struct GT_Mask dsp_trace_mask = { NULL, NULL }; /* GT trace variable */ +#endif + +/* + * ======== WMD_IO_Create ======== + * Create an IO manager object. + */ +DSP_STATUS WMD_IO_Create(OUT struct IO_MGR **phIOMgr, + struct DEV_OBJECT *hDevObject, + IN CONST struct IO_ATTRS *pMgrAttrs) +{ + DSP_STATUS status = DSP_SOK; + struct IO_MGR *pIOMgr = NULL; + struct SHM *pSharedMem = NULL; + struct WMD_DEV_CONTEXT *hWmdContext = NULL; + struct CFG_HOSTRES hostRes; + struct CFG_DEVNODE *hDevNode; + struct CHNL_MGR *hChnlMgr; + static int ref_count; + u32 devType; + /* Check DBC requirements: */ + DBC_Require(phIOMgr != NULL); + DBC_Require(pMgrAttrs != NULL); + DBC_Require(pMgrAttrs->uWordSize != 0); + /* This for the purposes of DBC_Require: */ + status = DEV_GetChnlMgr(hDevObject, &hChnlMgr); + DBC_Require(status != DSP_EHANDLE); + DBC_Require(hChnlMgr != NULL); + DBC_Require(hChnlMgr->hIOMgr == NULL); + /* Message manager will be created when a file is loaded, since + * size of message buffer in shared memory is configurable in + * the base image. */ + DEV_GetWMDContext(hDevObject, &hWmdContext); + DBC_Assert(hWmdContext); + DEV_GetDevType(hDevObject, &devType); + /* DSP shared memory area will get set properly when + * a program is loaded. They are unknown until a COFF file is + * loaded. I chose the value -1 because it was less likely to be + * a valid address than 0. */ + pSharedMem = (struct SHM *) -1; + if (DSP_FAILED(status)) + goto func_cont; + + /* + * Create a Single Threaded Work Queue + */ + + if (ref_count == 0) + bridge_workqueue = create_workqueue("bridge_work-queue"); + + if (bridge_workqueue <= 0) + DBG_Trace(DBG_LEVEL1, "Workque Create" + " failed 0x%d \n", bridge_workqueue); + + + /* Allocate IO manager object: */ + MEM_AllocObject(pIOMgr, struct IO_MGR, IO_MGRSIGNATURE); + if (pIOMgr == NULL) { + status = DSP_EMEMORY; + goto func_cont; + } + /*Intializing Work Element*/ + if (ref_count == 0) { + INIT_WORK(&pIOMgr->io_workq, (void *)IO_DispatchPM); + ref_count = 1; + } else + PREPARE_WORK(&pIOMgr->io_workq, (void *)IO_DispatchPM); + + /* Initialize CHNL_MGR object: */ +#ifndef DSP_TRACEBUF_DISABLED + pIOMgr->pMsg = NULL; +#endif + pIOMgr->hChnlMgr = hChnlMgr; + pIOMgr->uWordSize = pMgrAttrs->uWordSize; + pIOMgr->pSharedMem = pSharedMem; + if (DSP_SUCCEEDED(status)) + status = SYNC_InitializeCS(&pIOMgr->hCSObj); + + if (devType == DSP_UNIT) { + /* Create a DPC object: */ + status = DPC_Create(&pIOMgr->hDPC, IO_DPC, (void *)pIOMgr); + if (DSP_SUCCEEDED(status)) + status = DEV_GetDevNode(hDevObject, &hDevNode); + + pIOMgr->iQuePowerHead = 0; + pIOMgr->iQuePowerTail = 0; + } + if (DSP_SUCCEEDED(status)) { + status = CFG_GetHostResources((struct CFG_DEVNODE *) + DRV_GetFirstDevExtension() , &hostRes); + } + if (DSP_SUCCEEDED(status)) { + pIOMgr->hWmdContext = hWmdContext; + pIOMgr->fSharedIRQ = pMgrAttrs->fShared; + IO_DisableInterrupt(hWmdContext); + if (devType == DSP_UNIT) { + /* Plug the channel ISR:. */ + if ((request_irq(INT_MAIL_MPU_IRQ, IO_ISR, 0, + "DspBridge\tmailbox", (void *)pIOMgr)) == 0) + status = DSP_SOK; + else + status = DSP_EFAIL; + } + if (DSP_SUCCEEDED(status)) + DBG_Trace(DBG_LEVEL1, "ISR_IRQ Object 0x%x \n", + pIOMgr); + else + status = CHNL_E_ISR; + } else + status = CHNL_E_ISR; +func_cont: + if (DSP_FAILED(status)) { + /* Cleanup: */ + WMD_IO_Destroy(pIOMgr); + *phIOMgr = NULL; + } else { + /* Return IO manager object to caller... */ + hChnlMgr->hIOMgr = pIOMgr; + *phIOMgr = pIOMgr; + } + return status; +} + +/* + * ======== WMD_IO_Destroy ======== + * Purpose: + * Disable interrupts, destroy the IO manager. + */ +DSP_STATUS WMD_IO_Destroy(struct IO_MGR *hIOMgr) +{ + DSP_STATUS status = DSP_SOK; + struct WMD_DEV_CONTEXT *hWmdContext; + if (MEM_IsValidHandle(hIOMgr, IO_MGRSIGNATURE)) { + /* Unplug IRQ: */ + /* Disable interrupts from the board: */ + if (DSP_SUCCEEDED(DEV_GetWMDContext(hIOMgr->hDevObject, + &hWmdContext))) + DBC_Assert(hWmdContext); + (void)CHNLSM_DisableInterrupt(hWmdContext); + destroy_workqueue(bridge_workqueue); + /* Linux function to uninstall ISR */ + free_irq(INT_MAIL_MPU_IRQ, (void *)hIOMgr); + (void)DPC_Destroy(hIOMgr->hDPC); +#ifndef DSP_TRACEBUF_DISABLED + if (hIOMgr->pMsg) + MEM_Free(hIOMgr->pMsg); +#endif + SYNC_DeleteCS(hIOMgr->hCSObj); /* Leak Fix. */ + /* Free this IO manager object: */ + MEM_FreeObject(hIOMgr); + } else + status = DSP_EHANDLE; + + return status; +} + +/* + * ======== WMD_IO_OnLoaded ======== + * Purpose: + * Called when a new program is loaded to get shared memory buffer + * parameters from COFF file. ulSharedBufferBase and ulSharedBufferLimit + * are in DSP address units. + */ +DSP_STATUS WMD_IO_OnLoaded(struct IO_MGR *hIOMgr) +{ + struct COD_MANAGER *hCodMan; + struct CHNL_MGR *hChnlMgr; + struct MSG_MGR *hMsgMgr; + u32 ulShmBase; + u32 ulShmBaseOffset; + u32 ulShmLimit; + u32 ulShmLength = -1; + u32 ulMemLength = -1; + u32 ulMsgBase; + u32 ulMsgLimit; + u32 ulMsgLength = -1; + u32 ulExtEnd; + u32 ulGppPa = 0; + u32 ulGppVa = 0; + u32 ulDspVa = 0; + u32 ulSegSize = 0; + u32 ulPadSize = 0; + u32 i; + DSP_STATUS status = DSP_SOK; + u32 uNumProcs = 0; + s32 ndx = 0; + /* DSP MMU setup table */ + struct WMDIOCTL_EXTPROC aEProc[WMDIOCTL_NUMOFMMUTLB]; + struct CFG_HOSTRES hostRes; + u32 mapAttrs; + u32 ulShm0End; + u32 ulDynExtBase; + u32 ulSeg1Size = 0; + u32 paCurr = 0; + u32 vaCurr = 0; + u32 gppVaCurr = 0; + u32 numBytes = 0; + u32 allBits = 0; + u32 pgSize[] = { HW_PAGE_SIZE_16MB, HW_PAGE_SIZE_1MB, + HW_PAGE_SIZE_64KB, HW_PAGE_SIZE_4KB }; + + status = DEV_GetCodMgr(hIOMgr->hDevObject, &hCodMan); + DBC_Assert(DSP_SUCCEEDED(status)); + hChnlMgr = hIOMgr->hChnlMgr; + /* The message manager is destroyed when the board is stopped. */ + DEV_GetMsgMgr(hIOMgr->hDevObject, &hIOMgr->hMsgMgr); + hMsgMgr = hIOMgr->hMsgMgr; + DBC_Assert(MEM_IsValidHandle(hChnlMgr, CHNL_MGRSIGNATURE)); + DBC_Assert(MEM_IsValidHandle(hMsgMgr, MSGMGR_SIGNATURE)); + if (hIOMgr->pSharedMem) + hIOMgr->pSharedMem = NULL; + + /* Get start and length of channel part of shared memory */ + status = COD_GetSymValue(hCodMan, CHNL_SHARED_BUFFER_BASE_SYM, + &ulShmBase); + if (DSP_FAILED(status)) { + status = CHNL_E_NOMEMMAP; + goto func_cont1; + } + status = COD_GetSymValue(hCodMan, CHNL_SHARED_BUFFER_LIMIT_SYM, + &ulShmLimit); + if (DSP_FAILED(status)) { + status = CHNL_E_NOMEMMAP; + goto func_cont1; + } + if (ulShmLimit <= ulShmBase) { + status = CHNL_E_INVALIDMEMBASE; + } else { + /* get total length in bytes */ + ulShmLength = (ulShmLimit - ulShmBase + 1) * hIOMgr->uWordSize; + /* Calculate size of a PROCCOPY shared memory region */ + DBG_Trace(DBG_LEVEL7, + "**(proc)PROCCOPY SHMMEM SIZE: 0x%x bytes\n", + (ulShmLength - sizeof(struct SHM))); + } +func_cont1: + if (DSP_SUCCEEDED(status)) { + /* Get start and length of message part of shared memory */ + status = COD_GetSymValue(hCodMan, MSG_SHARED_BUFFER_BASE_SYM, + &ulMsgBase); + } + if (DSP_SUCCEEDED(status)) { + status = COD_GetSymValue(hCodMan, MSG_SHARED_BUFFER_LIMIT_SYM, + &ulMsgLimit); + if (DSP_SUCCEEDED(status)) { + if (ulMsgLimit <= ulMsgBase) { + status = CHNL_E_INVALIDMEMBASE; + } else { + /* Length (bytes) of messaging part of shared + * memory */ + ulMsgLength = (ulMsgLimit - ulMsgBase + 1) * + hIOMgr->uWordSize; + /* Total length (bytes) of shared memory: + * chnl + msg */ + ulMemLength = ulShmLength + ulMsgLength; + } + } else { + status = CHNL_E_NOMEMMAP; + } + } + if (DSP_SUCCEEDED(status)) { +#ifndef DSP_TRACEBUF_DISABLED + status = COD_GetSymValue(hCodMan, DSP_TRACESEC_END, &ulShm0End); + DBG_Trace(DBG_LEVEL7, "_BRIDGE_TRACE_END value = %x \n", + ulShm0End); +#else + status = COD_GetSymValue(hCodMan, SHM0_SHARED_END_SYM, + &ulShm0End); + DBG_Trace(DBG_LEVEL7, "_SHM0_END = %x \n", ulShm0End); +#endif + if (DSP_FAILED(status)) + status = CHNL_E_NOMEMMAP; + + } + if (DSP_SUCCEEDED(status)) { + status = COD_GetSymValue(hCodMan, DYNEXTBASE, &ulDynExtBase); + if (DSP_FAILED(status)) + status = CHNL_E_NOMEMMAP; + + } + if (DSP_SUCCEEDED(status)) { + status = COD_GetSymValue(hCodMan, EXTEND, &ulExtEnd); + if (DSP_FAILED(status)) + status = CHNL_E_NOMEMMAP; + + } + if (DSP_SUCCEEDED(status)) { + /* Get memory reserved in host resources */ + (void)MGR_EnumProcessorInfo(0, + (struct DSP_PROCESSORINFO *)&hIOMgr->extProcInfo, + sizeof(struct MGR_PROCESSOREXTINFO), &uNumProcs); + CFG_GetHostResources(( + struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), + &hostRes); + /* The first MMU TLB entry(TLB_0) in DCD is ShmBase. */ + ndx = 0; + ulGppPa = hostRes.dwMemPhys[1]; + ulGppVa = hostRes.dwMemBase[1]; + /* THIS IS THE VIRTUAL UNCACHED IOREMAPPED ADDRESS !!! */ + /* Why can't we directly take the DSPVA from the symbols? */ + ulDspVa = hIOMgr->extProcInfo.tyTlb[0].ulDspVirt; + ulSegSize = (ulShm0End - ulDspVa) * hIOMgr->uWordSize; + ulSeg1Size = (ulExtEnd - ulDynExtBase) * hIOMgr->uWordSize; + ulSeg1Size = (ulSeg1Size + 0xFFF) & (~0xFFFUL); /* 4K align*/ + ulSegSize = (ulSegSize + 0xFFFF) & (~0xFFFFUL); /* 64K align*/ + ulPadSize = ulPageAlignSize - ((ulGppPa + ulSeg1Size) % + ulPageAlignSize); + if (ulPadSize == ulPageAlignSize) + ulPadSize = 0x0; + + DBG_Trace(DBG_LEVEL7, "ulGppPa %x, ulGppVa %x, ulDspVa %x, " + "ulShm0End %x, ulDynExtBase %x, ulExtEnd %x, " + "ulSegSize %x ulSeg1Size %x \n", ulGppPa, ulGppVa, + ulDspVa, ulShm0End, ulDynExtBase, ulExtEnd, ulSegSize, + ulSeg1Size); + + if ((ulSegSize + ulSeg1Size + ulPadSize) > + hostRes.dwMemLength[1]) { + DBG_Trace(DBG_LEVEL7, "ulGppPa %x, ulGppVa %x, ulDspVa " + "%x, ulShm0End %x, ulDynExtBase %x, ulExtEnd " + "%x, ulSegSize %x, ulSeg1Size %x \n", ulGppPa, + ulGppVa, ulDspVa, ulShm0End, ulDynExtBase, + ulExtEnd, ulSegSize, ulSeg1Size); + DBG_Trace(DBG_LEVEL7, "Insufficient SHM Reserved 0x%x. " + "Required 0x%x\n", hostRes.dwMemLength[1], + ulSegSize + ulSeg1Size + ulPadSize); + status = DSP_EMEMORY; + } + } + if (DSP_FAILED(status)) + goto func_cont; + + paCurr = ulGppPa; + vaCurr = ulDynExtBase * hIOMgr->uWordSize; + gppVaCurr = ulGppVa; + numBytes = ulSeg1Size; + + /* + * Try to fit into TLB entries. If not possible, push them to page + * tables. It is quite possible that if sections are not on + * bigger page boundary, we may end up making several small pages. + * So, push them onto page tables, if that is the case. + */ + mapAttrs = 0x00000000; + mapAttrs = DSP_MAPLITTLEENDIAN; + mapAttrs |= DSP_MAPPHYSICALADDR; + mapAttrs |= DSP_MAPELEMSIZE32; + mapAttrs |= DSP_MAPDONOTLOCK; + + while (numBytes && DSP_SUCCEEDED(status)) { + /* To find the max. page size with which both PA & VA are + * aligned */ + allBits = paCurr | vaCurr; + DBG_Trace(DBG_LEVEL1, "allBits %x, paCurr %x, vaCurr %x, " + "numBytes %x\n", allBits, paCurr, vaCurr, numBytes); + for (i = 0; i < 4; i++) { + if ((numBytes >= pgSize[i]) && ((allBits & + (pgSize[i] - 1)) == 0)) { + status = hIOMgr->pIntfFxns->pfnBrdMemMap + (hIOMgr->hWmdContext, paCurr, vaCurr, + pgSize[i], mapAttrs); + DBC_Assert(DSP_SUCCEEDED(status)); + paCurr += pgSize[i]; + vaCurr += pgSize[i]; + gppVaCurr += pgSize[i]; + numBytes -= pgSize[i]; + /* Don't try smaller sizes. Hopefully we have + * reached an address aligned to a bigger page + * size*/ + break; + } + } + } + paCurr += ulPadSize; + vaCurr += ulPadSize; + gppVaCurr += ulPadSize; + + /* configure the TLB entries for the next cacheable segment */ + numBytes = ulSegSize; + vaCurr = ulDspVa * hIOMgr->uWordSize; + allBits = 0x0; + while (numBytes && DSP_SUCCEEDED(status)) { + /* To find the max. page size with which both PA & VA are + * aligned*/ + allBits = paCurr | vaCurr; + DBG_Trace(DBG_LEVEL1, "allBits for Seg1 %x, paCurr %x, " + "vaCurr %x, numBytes %x\n", allBits, paCurr, vaCurr, + numBytes); + for (i = 0; i < 4; i++) { + if (!(numBytes >= pgSize[i]) || + !((allBits & (pgSize[i]-1)) == 0)) + continue; + if (ndx < MAX_LOCK_TLB_ENTRIES) { + /* This is the physical address written to + * DSP MMU */ + aEProc[ndx].ulGppPa = paCurr; + /* THIS IS THE VIRTUAL UNCACHED IOREMAPPED + * ADDRESS!!! */ + aEProc[ndx].ulGppVa = gppVaCurr; + aEProc[ndx].ulDspVa = vaCurr / hIOMgr-> + uWordSize; + aEProc[ndx].ulSize = pgSize[i]; + aEProc[ndx].endianism = HW_LITTLE_ENDIAN; + aEProc[ndx].elemSize = HW_ELEM_SIZE_16BIT; + aEProc[ndx].mixedMode = HW_MMU_CPUES; + DBG_Trace(DBG_LEVEL1, "SHM MMU TLB entry PA %lx" + " VA %lx DSP_VA %lx Size %lx\n", + aEProc[ndx].ulGppPa, + aEProc[ndx].ulGppVa, + aEProc[ndx].ulDspVa * + hIOMgr->uWordSize, pgSize[i]); + ndx++; + } else { + status = hIOMgr->pIntfFxns->pfnBrdMemMap( + hIOMgr->hWmdContext, paCurr, vaCurr, pgSize[i], + mapAttrs); + DBG_Trace(DBG_LEVEL1, "SHM MMU PTE entry PA %lx" + " VA %lx DSP_VA %lx Size %lx\n", + aEProc[ndx].ulGppPa, + aEProc[ndx].ulGppVa, + aEProc[ndx].ulDspVa * + hIOMgr->uWordSize, pgSize[i]); + DBC_Assert(DSP_SUCCEEDED(status)); + } + paCurr += pgSize[i]; + vaCurr += pgSize[i]; + gppVaCurr += pgSize[i]; + numBytes -= pgSize[i]; + /* Don't try smaller sizes. Hopefully we have reached + an address aligned to a bigger page size*/ + break; + } + } + + /* Copy remaining entries from CDB. All entries are 1 MB and should not + * conflict with SHM entries on MPU or DSP side */ + for (i = 3; i < 7 && ndx < WMDIOCTL_NUMOFMMUTLB && + DSP_SUCCEEDED(status); i++) { + if (hIOMgr->extProcInfo.tyTlb[i].ulGppPhys == 0) + continue; + + if ((hIOMgr->extProcInfo.tyTlb[i].ulGppPhys > ulGppPa - 0x100000 + && hIOMgr->extProcInfo.tyTlb[i].ulGppPhys <= + ulGppPa + ulSegSize) + || (hIOMgr->extProcInfo.tyTlb[i].ulDspVirt > ulDspVa - + 0x100000 / hIOMgr->uWordSize && hIOMgr-> + extProcInfo.tyTlb[i].ulDspVirt + <= ulDspVa + ulSegSize / hIOMgr->uWordSize)) { + DBG_Trace(DBG_LEVEL7, "CDB MMU entry %d conflicts with " + "SHM.\n\tCDB: GppPa %x, DspVa %x.\n\tSHM: " + "GppPa %x, DspVa %x, Bytes %x.\n", i, + hIOMgr->extProcInfo.tyTlb[i].ulGppPhys, + hIOMgr->extProcInfo.tyTlb[i].ulDspVirt, + ulGppPa, ulDspVa, ulSegSize); + status = DSP_EFAIL; + } else { + if (ndx < MAX_LOCK_TLB_ENTRIES) { + aEProc[ndx].ulDspVa = hIOMgr->extProcInfo. + tyTlb[i].ulDspVirt; + aEProc[ndx].ulGppPa = hIOMgr->extProcInfo. + tyTlb[i].ulGppPhys; + aEProc[ndx].ulGppVa = 0; + /* Can't convert, so set to zero*/ + aEProc[ndx].ulSize = 0x100000; /* 1 MB*/ + DBG_Trace(DBG_LEVEL1, "SHM MMU entry PA %x " + "DSP_VA 0x%x\n", aEProc[ndx].ulGppPa, + aEProc[ndx].ulDspVa); + ndx++; + } else { + status = hIOMgr->pIntfFxns->pfnBrdMemMap + (hIOMgr->hWmdContext, + hIOMgr->extProcInfo.tyTlb[i].ulGppPhys, + hIOMgr->extProcInfo.tyTlb[i].ulDspVirt, + 0x100000, mapAttrs); + } + } + } + if (i < 7 && DSP_SUCCEEDED(status)) { + /* All CDB entries could not be made*/ + status = DSP_EFAIL; + } +func_cont: + mapAttrs = 0x00000000; + mapAttrs = DSP_MAPLITTLEENDIAN; + mapAttrs |= DSP_MAPPHYSICALADDR; + mapAttrs |= DSP_MAPELEMSIZE32; + mapAttrs |= DSP_MAPDONOTLOCK; + + /* Map the L4 peripherals */ + i = 0; + while (L4PeripheralTable[i].physAddr && DSP_SUCCEEDED(status)) { + status = hIOMgr->pIntfFxns->pfnBrdMemMap + (hIOMgr->hWmdContext, L4PeripheralTable[i].physAddr, + L4PeripheralTable[i].dspVirtAddr, HW_PAGE_SIZE_4KB, + mapAttrs); + if (DSP_FAILED(status)) + break; + i++; + } + + if (DSP_SUCCEEDED(status)) { + for (i = ndx; i < WMDIOCTL_NUMOFMMUTLB; i++) { + aEProc[i].ulDspVa = 0; + aEProc[i].ulGppPa = 0; + aEProc[i].ulGppVa = 0; + aEProc[i].ulSize = 0; + } + /* Set the SHM physical address entry (grayed out in CDB file) + * to the virtual uncached ioremapped address of SHM reserved + * on MPU */ + hIOMgr->extProcInfo.tyTlb[0].ulGppPhys = (ulGppVa + ulSeg1Size + + ulPadSize); + DBG_Trace(DBG_LEVEL1, "*********extProcInfo *********%x \n", + hIOMgr->extProcInfo.tyTlb[0].ulGppPhys); + /* Need SHM Phys addr. IO supports only one DSP for now: + * uNumProcs=1 */ + if ((hIOMgr->extProcInfo.tyTlb[0].ulGppPhys == 0) || + (uNumProcs != 1)) { + status = CHNL_E_NOMEMMAP; + DBC_Assert(false); + } else { + DBC_Assert(aEProc[0].ulDspVa <= ulShmBase); + /* ulShmBase may not be at ulDspVa address */ + ulShmBaseOffset = (ulShmBase - aEProc[0].ulDspVa) * + hIOMgr->uWordSize; + /* WMD_BRD_Ctrl() will set dev context dsp-mmu info. In + * _BRD_Start() the MMU will be re-programed with MMU + * DSPVa-GPPPa pair info while DSP is in a known + * (reset) state. */ + DBC_Assert(hIOMgr->pIntfFxns != NULL); + DBC_Assert(hIOMgr->hWmdContext != NULL); + status = hIOMgr->pIntfFxns->pfnDevCntrl(hIOMgr-> + hWmdContext, WMDIOCTL_SETMMUCONFIG, aEProc); + ulShmBase = hIOMgr->extProcInfo.tyTlb[0].ulGppPhys; + DBG_Trace(DBG_LEVEL1, "extProcInfo.tyTlb[0].ulGppPhys " + "%x \n ", hIOMgr->extProcInfo.tyTlb[0]. + ulGppPhys); + ulShmBase += ulShmBaseOffset; + ulShmBase = (u32)MEM_LinearAddress((void *)ulShmBase, + ulMemLength); + DBC_Assert(ulShmBase != 0); + if (DSP_SUCCEEDED(status)) { + status = registerSHMSegs(hIOMgr, hCodMan, + aEProc[0].ulGppPa); + /* Register SM */ + } + } + } + if (DSP_SUCCEEDED(status)) { + hIOMgr->pSharedMem = (struct SHM *)ulShmBase; + hIOMgr->pInput = (u8 *)hIOMgr->pSharedMem + + sizeof(struct SHM); + hIOMgr->pOutput = hIOMgr->pInput + (ulShmLength - + sizeof(struct SHM))/2; + hIOMgr->uSMBufSize = hIOMgr->pOutput - hIOMgr->pInput; + DBG_Trace(DBG_LEVEL3, + "hIOMgr: pInput %p pOutput %p ulShmLength %x\n", + hIOMgr->pInput, hIOMgr->pOutput, ulShmLength); + DBG_Trace(DBG_LEVEL3, + "pSharedMem %p uSMBufSize %x sizeof(SHM) %x\n", + hIOMgr->pSharedMem, hIOMgr->uSMBufSize, + sizeof(struct SHM)); + /* Set up Shared memory addresses for messaging. */ + hIOMgr->pMsgInputCtrl = (struct MSG *)((u8 *) + hIOMgr->pSharedMem + + ulShmLength); + hIOMgr->pMsgInput = (u8 *)hIOMgr->pMsgInputCtrl + + sizeof(struct MSG); + hIOMgr->pMsgOutputCtrl = (struct MSG *)((u8 *)hIOMgr-> + pMsgInputCtrl + ulMsgLength / 2); + hIOMgr->pMsgOutput = (u8 *)hIOMgr->pMsgOutputCtrl + + sizeof(struct MSG); + hMsgMgr->uMaxMsgs = ((u8 *)hIOMgr->pMsgOutputCtrl - + hIOMgr->pMsgInput) / + sizeof(struct MSG_DSPMSG); + DBG_Trace(DBG_LEVEL7, "IO MGR SHM details : pSharedMem 0x%x, " + "pInput 0x%x, pOutput 0x%x, pMsgInputCtrl 0x%x, " + "pMsgInput 0x%x, pMsgOutputCtrl 0x%x, pMsgOutput " + "0x%x \n", (u8 *)hIOMgr->pSharedMem, + (u8 *)hIOMgr->pInput, (u8 *)hIOMgr->pOutput, + (u8 *)hIOMgr->pMsgInputCtrl, + (u8 *)hIOMgr->pMsgInput, + (u8 *)hIOMgr->pMsgOutputCtrl, + (u8 *)hIOMgr->pMsgOutput); + DBG_Trace(DBG_LEVEL7, "** (proc) MAX MSGS IN SHARED MEMORY: " + "0x%x\n", hMsgMgr->uMaxMsgs); + memset((void *) hIOMgr->pSharedMem, 0, sizeof(struct SHM)); + } +#ifndef DSP_TRACEBUF_DISABLED + if (DSP_SUCCEEDED(status)) { + /* Get the start address of trace buffer */ + if (DSP_SUCCEEDED(status)) { + status = COD_GetSymValue(hCodMan, SYS_PUTCBEG, + &hIOMgr->ulTraceBufferBegin); + if (DSP_FAILED(status)) + status = CHNL_E_NOMEMMAP; + + } + hIOMgr->ulGPPReadPointer = hIOMgr->ulTraceBufferBegin = + (ulGppVa + ulSeg1Size + ulPadSize) + + (hIOMgr->ulTraceBufferBegin - ulDspVa); + /* Get the end address of trace buffer */ + if (DSP_SUCCEEDED(status)) { + status = COD_GetSymValue(hCodMan, SYS_PUTCEND, + &hIOMgr->ulTraceBufferEnd); + if (DSP_FAILED(status)) + status = CHNL_E_NOMEMMAP; + + } + hIOMgr->ulTraceBufferEnd = (ulGppVa + ulSeg1Size + ulPadSize) + + (hIOMgr->ulTraceBufferEnd - ulDspVa); + /* Get the current address of DSP write pointer */ + if (DSP_SUCCEEDED(status)) { + status = COD_GetSymValue(hCodMan, + BRIDGE_SYS_PUTC_current, + &hIOMgr->ulTraceBufferCurrent); + if (DSP_FAILED(status)) + status = CHNL_E_NOMEMMAP; + + } + hIOMgr->ulTraceBufferCurrent = (ulGppVa + ulSeg1Size + + ulPadSize) + (hIOMgr-> + ulTraceBufferCurrent - ulDspVa); + /* Calculate the size of trace buffer */ + if (hIOMgr->pMsg) + MEM_Free(hIOMgr->pMsg); + hIOMgr->pMsg = MEM_Alloc(((hIOMgr->ulTraceBufferEnd - + hIOMgr->ulTraceBufferBegin) * + hIOMgr->uWordSize) + 2, MEM_NONPAGED); + if (!hIOMgr->pMsg) + status = DSP_EMEMORY; + + DBG_Trace(DBG_LEVEL1, "** hIOMgr->pMsg: 0x%x\n", hIOMgr->pMsg); + hIOMgr->ulDspVa = ulDspVa; + hIOMgr->ulGppVa = (ulGppVa + ulSeg1Size + ulPadSize); + } +#endif + IO_EnableInterrupt(hIOMgr->hWmdContext); + return status; +} + +/* + * ======== IO_BufSize ======== + * Size of shared memory I/O channel. + */ +u32 IO_BufSize(struct IO_MGR *hIOMgr) +{ + DBC_Require(MEM_IsValidHandle(hIOMgr, IO_MGRSIGNATURE)); + + return hIOMgr->uSMBufSize; +} + +/* + * ======== IO_CancelChnl ======== + * Cancel IO on a given PCPY channel. + */ +void IO_CancelChnl(struct IO_MGR *hIOMgr, u32 ulChnl) +{ + struct IO_MGR *pIOMgr = (struct IO_MGR *)hIOMgr; + struct SHM *sm; + + DBC_Require(MEM_IsValidHandle(hIOMgr, IO_MGRSIGNATURE)); + sm = hIOMgr->pSharedMem; + + /* Inform DSP that we have no more buffers on this channel: */ + IO_AndValue(pIOMgr->hWmdContext, struct SHM, sm, hostFreeMask, + (~(1 << ulChnl))); + + CHNLSM_InterruptDSP2(pIOMgr->hWmdContext, MBX_PCPY_CLASS); +} + +/* + * ======== IO_DispatchChnl ======== + * Proc-copy chanl dispatch. + */ +static void IO_DispatchChnl(IN struct IO_MGR *pIOMgr, + IN OUT struct CHNL_OBJECT *pChnl, u32 iMode) +{ + DBC_Require(MEM_IsValidHandle(pIOMgr, IO_MGRSIGNATURE)); + + DBG_Trace(DBG_LEVEL3, "Entering IO_DispatchChnl \n"); + + /* See if there is any data available for transfer: */ + DBC_Assert(iMode == IO_SERVICE); + + /* Any channel will do for this mode: */ + InputChnl(pIOMgr, pChnl, iMode); + OutputChnl(pIOMgr, pChnl, iMode); +} + +/* + * ======== IO_DispatchMsg ======== + * Performs I/O dispatch on message queues. + */ +static void IO_DispatchMsg(IN struct IO_MGR *pIOMgr, struct MSG_MGR *hMsgMgr) +{ + DBC_Require(MEM_IsValidHandle(pIOMgr, IO_MGRSIGNATURE)); + + DBG_Trace(DBG_LEVEL3, "Entering IO_DispatchMsg \n"); + + /* We are performing both input and output processing. */ + InputMsg(pIOMgr, hMsgMgr); + OutputMsg(pIOMgr, hMsgMgr); +} + +/* + * ======== IO_DispatchPM ======== + * Performs I/O dispatch on PM related messages from DSP + */ +static void IO_DispatchPM(struct work_struct *work) +{ + struct IO_MGR *pIOMgr = + container_of(work, struct IO_MGR, io_workq); + DSP_STATUS status; + u32 pArg[2]; + + /*DBC_Require(MEM_IsValidHandle(pIOMgr, IO_MGRSIGNATURE));*/ + + DBG_Trace(DBG_LEVEL7, "IO_DispatchPM: Entering IO_DispatchPM : \n"); + + /* Perform Power message processing here */ + while (pIOMgr->iQuePowerHead != pIOMgr->iQuePowerTail) { + pArg[0] = *(u32 *)&(pIOMgr->dQuePowerMbxVal[pIOMgr-> + iQuePowerTail]); + DBG_Trace(DBG_LEVEL7, "IO_DispatchPM - pArg[0] - 0x%x: \n", + pArg[0]); + /* Send the command to the WMD clk/pwr manager to handle */ + if (pArg[0] == MBX_PM_HIBERNATE_EN) { + DBG_Trace(DBG_LEVEL7, "IO_DispatchPM : Hibernate " + "command\n"); + status = pIOMgr->pIntfFxns->pfnDevCntrl(pIOMgr-> + hWmdContext, WMDIOCTL_PWR_HIBERNATE, pArg); + if (DSP_FAILED(status)) { + DBG_Trace(DBG_LEVEL7, "IO_DispatchPM : " + "Hibernation command failed\n"); + } + } else if (pArg[0] == MBX_PM_OPP_REQ) { + pArg[1] = pIOMgr->pSharedMem->oppRequest.rqstOppPt; + DBG_Trace(DBG_LEVEL7, "IO_DispatchPM : Value of OPP " + "value =0x%x \n", pArg[1]); + status = pIOMgr->pIntfFxns->pfnDevCntrl(pIOMgr-> + hWmdContext, WMDIOCTL_CONSTRAINT_REQUEST, + pArg); + if (DSP_FAILED(status)) { + DBG_Trace(DBG_LEVEL7, "IO_DispatchPM : Failed " + "to set constraint = 0x%x \n", + pArg[1]); + } + + } else { + DBG_Trace(DBG_LEVEL7, "IO_DispatchPM - clock control - " + "value of msg = 0x%x: \n", pArg[0]); + status = pIOMgr->pIntfFxns->pfnDevCntrl(pIOMgr-> + hWmdContext, WMDIOCTL_CLK_CTRL, pArg); + if (DSP_FAILED(status)) { + DBG_Trace(DBG_LEVEL7, "IO_DispatchPM : Failed " + "to control the DSP clk = 0x%x \n", + *pArg); + } + } + /* increment the tail count here */ + pIOMgr->iQuePowerTail++; + if (pIOMgr->iQuePowerTail >= MAX_PM_REQS) + pIOMgr->iQuePowerTail = 0; + + } + +} + +/* + * ======== IO_DPC ======== + * Deferred procedure call for shared memory channel driver ISR. Carries + * out the dispatch of I/O as a non-preemptible event.It can only be + * pre-empted by an ISR. + */ +void IO_DPC(IN OUT void *pRefData) +{ + struct IO_MGR *pIOMgr = (struct IO_MGR *)pRefData; + struct CHNL_MGR *pChnlMgr; + struct MSG_MGR *pMsgMgr; + struct DEH_MGR *hDehMgr; + + DBC_Require(MEM_IsValidHandle(pIOMgr, IO_MGRSIGNATURE)); + pChnlMgr = pIOMgr->hChnlMgr; + DEV_GetMsgMgr(pIOMgr->hDevObject, &pMsgMgr); + DEV_GetDehMgr(pIOMgr->hDevObject, &hDehMgr); + DBC_Require(MEM_IsValidHandle(pChnlMgr, CHNL_MGRSIGNATURE)); + DBG_Trace(DBG_LEVEL7, "Entering IO_DPC(0x%x)\n", pRefData); + /* Check value of interrupt register to ensure it is a valid error */ + if ((pIOMgr->wIntrVal > DEH_BASE) && (pIOMgr->wIntrVal < DEH_LIMIT)) { + /* notify DSP/BIOS exception */ + if (hDehMgr) + WMD_DEH_Notify(hDehMgr, DSP_SYSERROR, pIOMgr->wIntrVal); + + } + IO_DispatchChnl(pIOMgr, NULL, IO_SERVICE); +#ifdef CHNL_MESSAGES + if (pMsgMgr) { + DBC_Require(MEM_IsValidHandle(pMsgMgr, MSGMGR_SIGNATURE)); + IO_DispatchMsg(pIOMgr, pMsgMgr); + } +#endif +#ifndef DSP_TRACEBUF_DISABLED + if (pIOMgr->wIntrVal & MBX_DBG_CLASS) { + /* notify DSP Trace message */ + if (pIOMgr->wIntrVal & MBX_DBG_SYSPRINTF) + PrintDSPDebugTrace(pIOMgr); + } +#endif + +#ifndef DSP_TRACEBUF_DISABLED + PrintDSPDebugTrace(pIOMgr); +#endif +} + + +/* + * ======== IO_ISR ======== + * Main interrupt handler for the shared memory IO manager. + * Calls the WMD's CHNL_ISR to determine if this interrupt is ours, then + * schedules a DPC to dispatch I/O. + */ +irqreturn_t IO_ISR(int irq, IN void *pRefData) +{ + struct IO_MGR *hIOMgr = (struct IO_MGR *)pRefData; + bool fSchedDPC; + DBC_Require(irq == INT_MAIL_MPU_IRQ); + DBC_Require(MEM_IsValidHandle(hIOMgr, IO_MGRSIGNATURE)); + DBG_Trace(DBG_LEVEL3, "Entering IO_ISR(0x%x)\n", pRefData); + + /* Call WMD's CHNLSM_ISR() to see if interrupt is ours, and process. */ + if (IO_CALLISR(hIOMgr->hWmdContext, &fSchedDPC, &hIOMgr->wIntrVal)) { + { + DBG_Trace(DBG_LEVEL3, "IO_ISR %x\n", hIOMgr->wIntrVal); + if (hIOMgr->wIntrVal & MBX_PM_CLASS) { + hIOMgr->dQuePowerMbxVal[hIOMgr->iQuePowerHead] = + hIOMgr->wIntrVal; + hIOMgr->iQuePowerHead++; + if (hIOMgr->iQuePowerHead >= MAX_PM_REQS) + hIOMgr->iQuePowerHead = 0; + + queue_work(bridge_workqueue, &hIOMgr->io_workq); + } + if (hIOMgr->wIntrVal == MBX_DEH_RESET) { + DBG_Trace(DBG_LEVEL6, "*** DSP RESET ***\n"); + hIOMgr->wIntrVal = 0; + } else if (fSchedDPC) { + /* PROC-COPY defer i/o */ + DPC_Schedule(hIOMgr->hDPC); + } + } + } else + /* Ensure that, if WMD didn't claim it, the IRQ is shared. */ + DBC_Ensure(hIOMgr->fSharedIRQ); + return IRQ_HANDLED; +} + +/* + * ======== IO_RequestChnl ======== + * Purpose: + * Request chanenel I/O from the DSP. Sets flags in shared memory, then + * interrupts the DSP. + */ +void IO_RequestChnl(struct IO_MGR *pIOMgr, struct CHNL_OBJECT *pChnl, + u32 iMode, OUT u16 *pwMbVal) +{ + struct CHNL_MGR *pChnlMgr; + struct SHM *sm; + DBC_Require(pChnl != NULL); + DBC_Require(pwMbVal != NULL); + pChnlMgr = pIOMgr->hChnlMgr; + sm = pIOMgr->pSharedMem; + if (iMode == IO_INPUT) { + /* Assertion fires if CHNL_AddIOReq() called on a stream + * which was cancelled, or attached to a dead board: */ + DBC_Assert((pChnl->dwState == CHNL_STATEREADY) || + (pChnl->dwState == CHNL_STATEEOS)); + /* Indicate to the DSP we have a buffer available for input: */ + IO_OrValue(pIOMgr->hWmdContext, struct SHM, sm, hostFreeMask, + (1 << pChnl->uId)); + *pwMbVal = MBX_PCPY_CLASS; + } else if (iMode == IO_OUTPUT) { + /* This assertion fails if CHNL_AddIOReq() was called on a + * stream which was cancelled, or attached to a dead board: */ + DBC_Assert((pChnl->dwState & ~CHNL_STATEEOS) == + CHNL_STATEREADY); + /* Record the fact that we have a buffer available for + * output: */ + pChnlMgr->dwOutputMask |= (1 << pChnl->uId); + } else { + DBC_Assert(iMode); /* Shouldn't get here. */ + } +} + +/* + * ======== IO_Schedule ======== + * Schedule DPC for IO. + */ +void IO_Schedule(struct IO_MGR *pIOMgr) +{ + DBC_Require(MEM_IsValidHandle(pIOMgr, IO_MGRSIGNATURE)); + + DPC_Schedule(pIOMgr->hDPC); +} + +/* + * ======== FindReadyOutput ======== + * Search for a host output channel which is ready to send. If this is + * called as a result of servicing the DPC, then implement a round + * robin search; otherwise, this was called by a client thread (via + * IO_Dispatch()), so just start searching from the current channel id. + */ +static u32 FindReadyOutput(struct CHNL_MGR *pChnlMgr, + struct CHNL_OBJECT *pChnl, u32 dwMask) +{ + u32 uRetval = OUTPUTNOTREADY; + u32 id, startId; + u32 shift; + + id = (pChnl != NULL ? pChnl->uId : (pChnlMgr->dwLastOutput + 1)); + id = ((id == CHNL_MAXCHANNELS) ? 0 : id); + DBC_Assert(id < CHNL_MAXCHANNELS); + if (dwMask) { + shift = (1 << id); + startId = id; + do { + if (dwMask & shift) { + uRetval = id; + if (pChnl == NULL) + pChnlMgr->dwLastOutput = id; + + break; + } + id = id + 1; + id = ((id == CHNL_MAXCHANNELS) ? 0 : id); + shift = (1 << id); + } while (id != startId); + } + DBC_Ensure((uRetval == OUTPUTNOTREADY) || (uRetval < CHNL_MAXCHANNELS)); + return uRetval; +} + +/* + * ======== InputChnl ======== + * Dispatch a buffer on an input channel. + */ +static void InputChnl(struct IO_MGR *pIOMgr, struct CHNL_OBJECT *pChnl, + u32 iMode) +{ + struct CHNL_MGR *pChnlMgr; + struct SHM *sm; + u32 chnlId; + u32 uBytes; + struct CHNL_IRP *pChirp = NULL; + u32 dwArg; + bool fClearChnl = false; + bool fNotifyClient = false; + + sm = pIOMgr->pSharedMem; + pChnlMgr = pIOMgr->hChnlMgr; + + DBG_Trace(DBG_LEVEL3, "> InputChnl\n"); + + /* Attempt to perform input.... */ + if (!IO_GetValue(pIOMgr->hWmdContext, struct SHM, sm, inputFull)) + goto func_end; + + uBytes = IO_GetValue(pIOMgr->hWmdContext, struct SHM, sm, inputSize) * + pChnlMgr->uWordSize; + chnlId = IO_GetValue(pIOMgr->hWmdContext, struct SHM, sm, inputId); + dwArg = IO_GetLong(pIOMgr->hWmdContext, struct SHM, sm, arg); + if (!(chnlId >= 0) || !(chnlId < CHNL_MAXCHANNELS)) { + /* Shouldn't be here: would indicate corrupted SHM. */ + DBC_Assert(chnlId); + goto func_end; + } + pChnl = pChnlMgr->apChannel[chnlId]; + if ((pChnl != NULL) && CHNL_IsInput(pChnl->uMode)) { + if ((pChnl->dwState & ~CHNL_STATEEOS) == CHNL_STATEREADY) { + if (!pChnl->pIORequests) + goto func_end; + /* Get the I/O request, and attempt a transfer: */ + pChirp = (struct CHNL_IRP *)LST_GetHead(pChnl-> + pIORequests); + if (pChirp) { + pChnl->cIOReqs--; + DBC_Assert(pChnl->cIOReqs >= 0); + /* Ensure we don't overflow the client's + * buffer: */ + uBytes = min(uBytes, pChirp->cBytes); + /* Transfer buffer from DSP side: */ + uBytes = ReadData(pIOMgr->hWmdContext, + pChirp->pHostSysBuf, + pIOMgr->pInput, uBytes); + pChnl->cBytesMoved += uBytes; + pChirp->cBytes = uBytes; + pChirp->dwArg = dwArg; + pChirp->status = CHNL_IOCSTATCOMPLETE; + DBG_Trace(DBG_LEVEL7, "Input Chnl:status= 0x%x " + "\n", *((RMS_WORD *)(pChirp-> + pHostSysBuf))); + if (uBytes == 0) { + /* This assertion fails if the DSP + * sends EOS more than once on this + * channel: */ + DBC_Assert(!(pChnl->dwState & + CHNL_STATEEOS)); + /* Zero bytes indicates EOS. Update + * IOC status for this chirp, and also + * the channel state: */ + pChirp->status |= CHNL_IOCSTATEOS; + pChnl->dwState |= CHNL_STATEEOS; + /* Notify that end of stream has + * occurred */ + NTFY_Notify(pChnl->hNtfy, + DSP_STREAMDONE); + DBG_Trace(DBG_LEVEL7, "Input Chnl NTFY " + "chnl = 0x%x\n", pChnl); + } + /* Tell DSP if no more I/O buffers available: */ + if (!pChnl->pIORequests) + goto func_end; + if (LST_IsEmpty(pChnl->pIORequests)) { + IO_AndValue(pIOMgr->hWmdContext, + struct SHM, sm, hostFreeMask, + ~(1 << pChnl->uId)); + } + fClearChnl = true; + fNotifyClient = true; + } else { + /* Input full for this channel, but we have no + * buffers available. The channel must be + * "idling". Clear out the physical input + * channel. */ + fClearChnl = true; + } + } else { + /* Input channel cancelled: clear input channel. */ + fClearChnl = true; + } + } else { + /* DPC fired after host closed channel: clear input channel. */ + fClearChnl = true; + } + if (fClearChnl) { + /* Indicate to the DSP we have read the input: */ + IO_SetValue(pIOMgr->hWmdContext, struct SHM, sm, inputFull, 0); + CHNLSM_InterruptDSP2(pIOMgr->hWmdContext, MBX_PCPY_CLASS); + } + if (fNotifyClient) { + /* Notify client with IO completion record: */ + NotifyChnlComplete(pChnl, pChirp); + } +func_end: + DBG_Trace(DBG_LEVEL3, "< InputChnl\n"); +} + +/* + * ======== InputMsg ======== + * Copies messages from shared memory to the message queues. + */ +static void InputMsg(struct IO_MGR *pIOMgr, struct MSG_MGR *hMsgMgr) +{ + u32 uMsgs; + u32 i; + u8 *pMsgInput; + struct MSG_QUEUE *hMsgQueue; + struct MSG_FRAME *pMsg; + struct MSG_DSPMSG msg; + struct MSG *pCtrl; + u32 fInputEmpty; + u32 addr; + + pCtrl = pIOMgr->pMsgInputCtrl; + /* Get the number of input messages to be read. */ + fInputEmpty = IO_GetValue(pIOMgr->hWmdContext, struct MSG, pCtrl, + bufEmpty); + uMsgs = IO_GetValue(pIOMgr->hWmdContext, struct MSG, pCtrl, size); + if (fInputEmpty || uMsgs >= hMsgMgr->uMaxMsgs) + return; + + pMsgInput = pIOMgr->pMsgInput; + for (i = 0; i < uMsgs; i++) { + /* Read the next message */ + addr = (u32)&(((struct MSG_DSPMSG *)pMsgInput)->msg.dwCmd); + msg.msg.dwCmd = ReadExt32BitDspData(pIOMgr->hWmdContext, addr); + addr = (u32)&(((struct MSG_DSPMSG *)pMsgInput)->msg.dwArg1); + msg.msg.dwArg1 = ReadExt32BitDspData(pIOMgr->hWmdContext, addr); + addr = (u32)&(((struct MSG_DSPMSG *)pMsgInput)->msg.dwArg2); + msg.msg.dwArg2 = ReadExt32BitDspData(pIOMgr->hWmdContext, addr); + addr = (u32)&(((struct MSG_DSPMSG *)pMsgInput)->dwId); + msg.dwId = ReadExt32BitDspData(pIOMgr->hWmdContext, addr); + pMsgInput += sizeof(struct MSG_DSPMSG); + if (!hMsgMgr->queueList) + goto func_end; + + /* Determine which queue to put the message in */ + hMsgQueue = (struct MSG_QUEUE *)LST_First(hMsgMgr->queueList); + DBG_Trace(DBG_LEVEL7, "InputMsg RECVD: dwCmd=0x%x dwArg1=0x%x " + "dwArg2=0x%x dwId=0x%x \n", msg.msg.dwCmd, + msg.msg.dwArg1, msg.msg.dwArg2, msg.dwId); + /* Interrupt may occur before shared memory and message + * input locations have been set up. If all nodes were + * cleaned up, hMsgMgr->uMaxMsgs should be 0. */ + if (hMsgQueue && uMsgs > hMsgMgr->uMaxMsgs) + goto func_end; + + while (hMsgQueue != NULL) { + if (msg.dwId == hMsgQueue->dwId) { + /* Found it */ + if (msg.msg.dwCmd == RMS_EXITACK) { + /* The exit message does not get + * queued */ + /* Call the node exit notification */ + /* Node handle */ /* status */ + (*hMsgMgr->onExit)((HANDLE)hMsgQueue-> + hArg, msg.msg.dwArg1); + } else { + /* Not an exit acknowledgement, queue + * the message */ + if (!hMsgQueue->msgFreeList) + goto func_end; + pMsg = (struct MSG_FRAME *)LST_GetHead + (hMsgQueue->msgFreeList); + if (hMsgQueue->msgUsedList && pMsg) { + pMsg->msgData = msg; + LST_PutTail(hMsgQueue-> + msgUsedList, + (struct LST_ELEM *)pMsg); + NTFY_Notify(hMsgQueue->hNtfy, + DSP_NODEMESSAGEREADY); + SYNC_SetEvent(hMsgQueue-> + hSyncEvent); + } else { + /* No free frame to copy the + * message into */ + DBG_Trace(DBG_LEVEL7, "NO FREE " + "MSG FRAMES, DISCARDING" + " MESSAGE\n"); + } + } + break; + } + + if (!hMsgMgr->queueList || !hMsgQueue) + goto func_end; + hMsgQueue = (struct MSG_QUEUE *)LST_Next(hMsgMgr-> + queueList, (struct LST_ELEM *)hMsgQueue); + } + } + /* Set the post SWI flag */ + if (uMsgs > 0) { + /* Tell the DSP we've read the messages */ + IO_SetValue(pIOMgr->hWmdContext, struct MSG, pCtrl, bufEmpty, + true); + IO_SetValue(pIOMgr->hWmdContext, struct MSG, pCtrl, postSWI, + true); + CHNLSM_InterruptDSP2(pIOMgr->hWmdContext, MBX_PCPY_CLASS); + } +func_end: + return; + +} + +/* + * ======== NotifyChnlComplete ======== + * Purpose: + * Signal the channel event, notifying the client that I/O has completed. + */ +static void NotifyChnlComplete(struct CHNL_OBJECT *pChnl, + struct CHNL_IRP *pChirp) +{ + bool fSignalEvent; + + DBC_Require(MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)); + DBC_Require(pChnl->hSyncEvent != NULL); + /* Note: we signal the channel event only if the queue of IO + * completions is empty. If it is not empty, the event is sure to be + * signalled by the only IO completion list consumer: + * WMD_CHNL_GetIOC(). */ + fSignalEvent = LST_IsEmpty(pChnl->pIOCompletions); + /* Enqueue the IO completion info for the client: */ + LST_PutTail(pChnl->pIOCompletions, (struct LST_ELEM *) pChirp); + pChnl->cIOCs++; + DBC_Assert(pChnl->cIOCs <= pChnl->cChirps); + /* Signal the channel event (if not already set) that IO is complete: */ + if (fSignalEvent) + SYNC_SetEvent(pChnl->hSyncEvent); + + /* Notify that IO is complete */ + NTFY_Notify(pChnl->hNtfy, DSP_STREAMIOCOMPLETION); +} + +/* + * ======== OutputChnl ======== + * Purpose: + * Dispatch a buffer on an output channel. + */ +static void OutputChnl(struct IO_MGR *pIOMgr, struct CHNL_OBJECT *pChnl, + u32 iMode) +{ + struct CHNL_MGR *pChnlMgr; + struct SHM *sm; + u32 chnlId; + struct CHNL_IRP *pChirp; + u32 dwDspFMask; + + pChnlMgr = pIOMgr->hChnlMgr; + sm = pIOMgr->pSharedMem; + DBG_Trace(DBG_LEVEL3, "> OutputChnl\n"); + /* Attempt to perform output: */ + if (IO_GetValue(pIOMgr->hWmdContext, struct SHM, sm, outputFull)) + goto func_end; + + if (pChnl && !((pChnl->dwState & ~CHNL_STATEEOS) == CHNL_STATEREADY)) + goto func_end; + + /* Look to see if both a PC and DSP output channel are ready: */ + dwDspFMask = IO_GetValue(pIOMgr->hWmdContext, struct SHM, sm, + dspFreeMask); + chnlId = FindReadyOutput(pChnlMgr, pChnl, (pChnlMgr->dwOutputMask & + dwDspFMask)); + if (chnlId == OUTPUTNOTREADY) + goto func_end; + + pChnl = pChnlMgr->apChannel[chnlId]; + if (!pChnl || !pChnl->pIORequests) { + /* Shouldn't get here: */ + goto func_end; + } + /* Get the I/O request, and attempt a transfer: */ + pChirp = (struct CHNL_IRP *)LST_GetHead(pChnl->pIORequests); + if (!pChirp) + goto func_end; + + pChnl->cIOReqs--; + if (pChnl->cIOReqs < 0 || !pChnl->pIORequests) + goto func_end; + + /* Record fact that no more I/O buffers available: */ + if (LST_IsEmpty(pChnl->pIORequests)) + pChnlMgr->dwOutputMask &= ~(1 << chnlId); + + /* Transfer buffer to DSP side: */ + pChirp->cBytes = WriteData(pIOMgr->hWmdContext, pIOMgr->pOutput, + pChirp->pHostSysBuf, min(pIOMgr->uSMBufSize, pChirp-> + cBytes)); + pChnl->cBytesMoved += pChirp->cBytes; + /* Write all 32 bits of arg */ + IO_SetLong(pIOMgr->hWmdContext, struct SHM, sm, arg, pChirp->dwArg); +#if _CHNL_WORDSIZE == 2 + IO_SetValue(pIOMgr->hWmdContext, struct SHM, sm, outputId, + (u16)chnlId); + IO_SetValue(pIOMgr->hWmdContext, struct SHM, sm, outputSize, + (u16)(pChirp->cBytes + (pChnlMgr->uWordSize-1)) / + (u16)pChnlMgr->uWordSize); +#else + IO_SetValue(pIOMgr->hWmdContext, struct SHM, sm, outputId, chnlId); + IO_SetValue(pIOMgr->hWmdContext, struct SHM, sm, outputSize, + (pChirp->cBytes + (pChnlMgr->uWordSize - 1)) / pChnlMgr-> + uWordSize); +#endif + IO_SetValue(pIOMgr->hWmdContext, struct SHM, sm, outputFull, 1); + /* Indicate to the DSP we have written the output: */ + CHNLSM_InterruptDSP2(pIOMgr->hWmdContext, MBX_PCPY_CLASS); + /* Notify client with IO completion record (keep EOS) */ + pChirp->status &= CHNL_IOCSTATEOS; + NotifyChnlComplete(pChnl, pChirp); + /* Notify if stream is done. */ + if (pChirp->status & CHNL_IOCSTATEOS) + NTFY_Notify(pChnl->hNtfy, DSP_STREAMDONE); + +func_end: + DBG_Trace(DBG_LEVEL3, "< OutputChnl\n"); +} +/* + * ======== OutputMsg ======== + * Copies messages from the message queues to the shared memory. + */ +static void OutputMsg(struct IO_MGR *pIOMgr, struct MSG_MGR *hMsgMgr) +{ + u32 uMsgs = 0; + u32 i; + u8 *pMsgOutput; + struct MSG_FRAME *pMsg; + struct MSG *pCtrl; + u32 fOutputEmpty; + u32 val; + u32 addr; + + pCtrl = pIOMgr->pMsgOutputCtrl; + + /* Check if output has been cleared */ + fOutputEmpty = IO_GetValue(pIOMgr->hWmdContext, struct MSG, pCtrl, + bufEmpty); + if (fOutputEmpty) { + uMsgs = (hMsgMgr->uMsgsPending > hMsgMgr->uMaxMsgs) ? + hMsgMgr->uMaxMsgs : hMsgMgr->uMsgsPending; + pMsgOutput = pIOMgr->pMsgOutput; + /* Copy uMsgs messages into shared memory */ + for (i = 0; i < uMsgs; i++) { + if (!hMsgMgr->msgUsedList) { + DBG_Trace(DBG_LEVEL3, "msgUsedList is NULL\n"); + pMsg = NULL; + goto func_end; + } else + pMsg = (struct MSG_FRAME *)LST_GetHead( + hMsgMgr->msgUsedList); + if (pMsg != NULL) { + val = (pMsg->msgData).dwId; + addr = (u32)&(((struct MSG_DSPMSG *) + pMsgOutput)->dwId); + WriteExt32BitDspData(pIOMgr->hWmdContext, addr, + val); + val = (pMsg->msgData).msg.dwCmd; + addr = (u32)&((((struct MSG_DSPMSG *) + pMsgOutput)->msg).dwCmd); + WriteExt32BitDspData(pIOMgr->hWmdContext, addr, + val); + val = (pMsg->msgData).msg.dwArg1; + addr = + (u32)&((((struct MSG_DSPMSG *) + pMsgOutput)->msg).dwArg1); + WriteExt32BitDspData(pIOMgr->hWmdContext, addr, + val); + val = (pMsg->msgData).msg.dwArg2; + addr = + (u32)&((((struct MSG_DSPMSG *) + pMsgOutput)->msg).dwArg2); + WriteExt32BitDspData(pIOMgr->hWmdContext, addr, + val); + pMsgOutput += sizeof(struct MSG_DSPMSG); + if (!hMsgMgr->msgFreeList) + goto func_end; + LST_PutTail(hMsgMgr->msgFreeList, + (struct LST_ELEM *) pMsg); + SYNC_SetEvent(hMsgMgr->hSyncEvent); + } else { + DBG_Trace(DBG_LEVEL3, "pMsg is NULL\n"); + } + } + + if (uMsgs > 0) { + hMsgMgr->uMsgsPending -= uMsgs; +#if _CHNL_WORDSIZE == 2 + IO_SetValue(pIOMgr->hWmdContext, struct MSG, pCtrl, + size, (u16)uMsgs); +#else + IO_SetValue(pIOMgr->hWmdContext, struct MSG, pCtrl, + size, uMsgs); +#endif + IO_SetValue(pIOMgr->hWmdContext, struct MSG, pCtrl, + bufEmpty, false); + /* Set the post SWI flag */ + IO_SetValue(pIOMgr->hWmdContext, struct MSG, pCtrl, + postSWI, true); + /* Tell the DSP we have written the output. */ + CHNLSM_InterruptDSP2(pIOMgr->hWmdContext, MBX_PCPY_CLASS); + } + } +func_end: + return; + +} + +/* + * ======== registerSHMSegs ======== + * purpose: + * Registers GPP SM segment with CMM. + */ +static DSP_STATUS registerSHMSegs(struct IO_MGR *hIOMgr, + struct COD_MANAGER *hCodMan, + u32 dwGPPBasePA) +{ + DSP_STATUS status = DSP_SOK; + u32 ulShm0_Base = 0; + u32 ulShm0_End = 0; + u32 ulShm0_RsrvdStart = 0; + u32 ulRsrvdSize = 0; + u32 ulGppPhys; + u32 ulDspVirt; + u32 ulShmSegId0 = 0; + u32 dwOffset, dwGPPBaseVA, ulDSPSize; + + /* Read address and size info for first SM region.*/ + /* Get start of 1st SM Heap region */ + status = COD_GetSymValue(hCodMan, SHM0_SHARED_BASE_SYM, &ulShm0_Base); + DBC_Assert(ulShm0_Base != 0); + /* Get end of 1st SM Heap region */ + if (DSP_SUCCEEDED(status)) { + /* Get start and length of message part of shared memory */ + status = COD_GetSymValue(hCodMan, SHM0_SHARED_END_SYM, + &ulShm0_End); + DBC_Assert(ulShm0_End != 0); + } + /* start of Gpp reserved region */ + if (DSP_SUCCEEDED(status)) { + /* Get start and length of message part of shared memory */ + status = COD_GetSymValue(hCodMan, SHM0_SHARED_RESERVED_BASE_SYM, + &ulShm0_RsrvdStart); + DBG_Trace(DBG_LEVEL1, "***ulShm0_RsrvdStart 0x%x \n", + ulShm0_RsrvdStart); + DBC_Assert(ulShm0_RsrvdStart != 0); + } + /* Register with CMM */ + if (DSP_SUCCEEDED(status)) { + status = DEV_GetCmmMgr(hIOMgr->hDevObject, &hIOMgr->hCmmMgr); + if (DSP_SUCCEEDED(status)) { + status = CMM_UnRegisterGPPSMSeg(hIOMgr->hCmmMgr, + CMM_ALLSEGMENTS); + if (DSP_FAILED(status)) { + DBG_Trace(DBG_LEVEL7, "ERROR - Unable to " + "Un-Register SM segments \n"); + } + } else { + DBG_Trace(DBG_LEVEL7, "ERROR - Unable to get CMM " + "Handle \n"); + } + } + /* Register new SM region(s) */ + if (DSP_SUCCEEDED(status) && (ulShm0_End - ulShm0_Base) > 0) { + /* calc size (bytes) of SM the GPP can alloc from */ + ulRsrvdSize = (ulShm0_End - ulShm0_RsrvdStart + 1) * hIOMgr-> + uWordSize; + DBC_Assert(ulRsrvdSize > 0); + /* calc size of SM DSP can alloc from */ + ulDSPSize = (ulShm0_RsrvdStart - ulShm0_Base) * hIOMgr-> + uWordSize; + DBC_Assert(ulDSPSize > 0); + /* First TLB entry reserved for Bridge SM use.*/ + ulGppPhys = hIOMgr->extProcInfo.tyTlb[0].ulGppPhys; + /* get size in bytes */ + ulDspVirt = hIOMgr->extProcInfo.tyTlb[0].ulDspVirt * hIOMgr-> + uWordSize; + /* Calc byte offset used to convert GPP phys <-> DSP byte + * address.*/ + if (dwGPPBasePA > ulDspVirt) + dwOffset = dwGPPBasePA - ulDspVirt; + else + dwOffset = ulDspVirt - dwGPPBasePA; + + DBC_Assert(ulShm0_RsrvdStart * hIOMgr->uWordSize >= ulDspVirt); + /* calc Gpp phys base of SM region */ + /* Linux - this is actually uncached kernel virtual address*/ + dwGPPBaseVA = ulGppPhys + ulShm0_RsrvdStart * hIOMgr->uWordSize + - ulDspVirt; + /* calc Gpp phys base of SM region */ + /* Linux - this is the physical address*/ + dwGPPBasePA = dwGPPBasePA + ulShm0_RsrvdStart * hIOMgr-> + uWordSize - ulDspVirt; + /* Register SM Segment 0.*/ + status = CMM_RegisterGPPSMSeg(hIOMgr->hCmmMgr, dwGPPBasePA, + ulRsrvdSize, dwOffset, (dwGPPBasePA > ulDspVirt) ? + CMM_ADDTODSPPA : CMM_SUBFROMDSPPA, + (u32)(ulShm0_Base * hIOMgr->uWordSize), + ulDSPSize, &ulShmSegId0, dwGPPBaseVA); + if (DSP_FAILED(status)) { + DBG_Trace(DBG_LEVEL7, "ERROR - Failed to register SM " + "Seg 0 \n"); + } + /* first SM region is segId = 1 */ + DBC_Assert(ulShmSegId0 == 1); + } + return status; +} + +/* + * ======== ReadData ======== + * Copies buffers from the shared memory to the host buffer. + */ +static u32 ReadData(struct WMD_DEV_CONTEXT *hDevContext, void *pDest, + void *pSrc, u32 uSize) +{ + memcpy(pDest, pSrc, uSize); + return uSize; +} + +/* + * ======== WriteData ======== + * Copies buffers from the host side buffer to the shared memory. + */ +static u32 WriteData(struct WMD_DEV_CONTEXT *hDevContext, void *pDest, + void *pSrc, u32 uSize) +{ + memcpy(pDest, pSrc, uSize); + return uSize; +} + +/* ZCPY IO routines. */ +void IO_IntrDSP2(IN struct IO_MGR *pIOMgr, IN u16 wMbVal) +{ + CHNLSM_InterruptDSP2(pIOMgr->hWmdContext, wMbVal); +} + +/* + * ======== IO_SHMcontrol ======== + * Sets the requested SHM setting. + */ +DSP_STATUS IO_SHMsetting(IN struct IO_MGR *hIOMgr, IN enum SHM_DESCTYPE desc, + IN void *pArgs) +{ +#ifdef CONFIG_BRIDGE_DVFS + u32 i; + struct dspbridge_platform_data *pdata = + omap_dspbridge_dev->dev.platform_data; + + switch (desc) { + case SHM_CURROPP: + /* Update the shared memory with requested OPP information */ + if (pArgs != NULL) + hIOMgr->pSharedMem->oppTableStruct.currOppPt = + *(u32 *)pArgs; + else + return DSP_EFAIL; + break; + case SHM_OPPINFO: + /* Update the shared memory with the voltage, frequency, + min and max frequency values for an OPP */ + for (i = 0; i <= dsp_max_opps; i++) { + hIOMgr->pSharedMem->oppTableStruct.oppPoint[i].voltage = + vdd1_dsp_freq[i][0]; + DBG_Trace(DBG_LEVEL5, "OPP shared memory -voltage: " + "%d\n", hIOMgr->pSharedMem->oppTableStruct. + oppPoint[i].voltage); + hIOMgr->pSharedMem->oppTableStruct.oppPoint[i]. + frequency = vdd1_dsp_freq[i][1]; + DBG_Trace(DBG_LEVEL5, "OPP shared memory -frequency: " + "%d\n", hIOMgr->pSharedMem->oppTableStruct. + oppPoint[i].frequency); + hIOMgr->pSharedMem->oppTableStruct.oppPoint[i].minFreq = + vdd1_dsp_freq[i][2]; + DBG_Trace(DBG_LEVEL5, "OPP shared memory -min value: " + "%d\n", hIOMgr->pSharedMem->oppTableStruct. + oppPoint[i].minFreq); + hIOMgr->pSharedMem->oppTableStruct.oppPoint[i].maxFreq = + vdd1_dsp_freq[i][3]; + DBG_Trace(DBG_LEVEL5, "OPP shared memory -max value: " + "%d\n", hIOMgr->pSharedMem->oppTableStruct. + oppPoint[i].maxFreq); + } + hIOMgr->pSharedMem->oppTableStruct.numOppPts = dsp_max_opps; + DBG_Trace(DBG_LEVEL5, "OPP shared memory - max OPP number: " + "%d\n", hIOMgr->pSharedMem->oppTableStruct.numOppPts); + /* Update the current OPP number */ + if (pdata->dsp_get_opp) + i = (*pdata->dsp_get_opp)(); + hIOMgr->pSharedMem->oppTableStruct.currOppPt = i; + DBG_Trace(DBG_LEVEL7, "OPP value programmed to shared memory: " + "%d\n", i); + break; + case SHM_GETOPP: + /* Get the OPP that DSP has requested */ + *(u32 *)pArgs = hIOMgr->pSharedMem->oppRequest.rqstOppPt; + break; + default: + break; + + queue_work(bridge_workqueue, + &(hIOMgr->io_workq)); + } +#endif + return DSP_SOK; +} + +/* + * ======== WMD_IO_GetProcLoad ======== + * Gets the Processor's Load information + */ +DSP_STATUS WMD_IO_GetProcLoad(IN struct IO_MGR *hIOMgr, + OUT struct DSP_PROCLOADSTAT *pProcStat) +{ + pProcStat->uCurrLoad = hIOMgr->pSharedMem->loadMonInfo.currDspLoad; + pProcStat->uPredictedLoad = hIOMgr->pSharedMem->loadMonInfo.predDspLoad; + pProcStat->uCurrDspFreq = hIOMgr->pSharedMem->loadMonInfo.currDspFreq; + pProcStat->uPredictedFreq = hIOMgr->pSharedMem->loadMonInfo.predDspFreq; + + DBG_Trace(DBG_LEVEL4, "Curr Load =%d, Pred Load = %d, Curr Freq = %d, " + "Pred Freq = %d\n", pProcStat->uCurrLoad, + pProcStat->uPredictedLoad, pProcStat->uCurrDspFreq, + pProcStat->uPredictedFreq); + return DSP_SOK; +} + +#ifndef DSP_TRACEBUF_DISABLED +void PrintDSPDebugTrace(struct IO_MGR *hIOMgr) +{ + u32 ulNewMessageLength = 0, ulGPPCurPointer; + + GT_0trace(dsp_trace_mask, GT_ENTER, "Entering PrintDSPDebugTrace\n"); + + while (true) { + /* Get the DSP current pointer */ + ulGPPCurPointer = *(u32 *) (hIOMgr->ulTraceBufferCurrent); + ulGPPCurPointer = hIOMgr->ulGppVa + (ulGPPCurPointer - + hIOMgr->ulDspVa); + + /* No new debug messages available yet */ + if (ulGPPCurPointer == hIOMgr->ulGPPReadPointer) + break; + + /* Continuous data */ + else if (ulGPPCurPointer > hIOMgr->ulGPPReadPointer) { + ulNewMessageLength = ulGPPCurPointer - hIOMgr-> + ulGPPReadPointer; + + memcpy(hIOMgr->pMsg, (char *)hIOMgr->ulGPPReadPointer, + ulNewMessageLength); + hIOMgr->pMsg[ulNewMessageLength] = '\0'; + /* Advance the GPP trace pointer to DSP current + * pointer */ + hIOMgr->ulGPPReadPointer += ulNewMessageLength; + /* Print the trace messages */ + GT_0trace(dsp_trace_mask, GT_1CLASS, hIOMgr->pMsg); + } + /* Handle trace buffer wraparound */ + else if (ulGPPCurPointer < hIOMgr->ulGPPReadPointer) { + memcpy(hIOMgr->pMsg, (char *)hIOMgr->ulGPPReadPointer, + hIOMgr->ulTraceBufferEnd - + hIOMgr->ulGPPReadPointer); + ulNewMessageLength = ulGPPCurPointer - + hIOMgr->ulTraceBufferBegin; + memcpy(&hIOMgr->pMsg[hIOMgr->ulTraceBufferEnd - + hIOMgr->ulGPPReadPointer], + (char *)hIOMgr->ulTraceBufferBegin, + ulNewMessageLength); + hIOMgr->pMsg[hIOMgr->ulTraceBufferEnd - + hIOMgr->ulGPPReadPointer + + ulNewMessageLength] = '\0'; + /* Advance the GPP trace pointer to DSP current + * pointer */ + hIOMgr->ulGPPReadPointer = hIOMgr->ulTraceBufferBegin + + ulNewMessageLength; + /* Print the trace messages */ + GT_0trace(dsp_trace_mask, GT_1CLASS, hIOMgr->pMsg); + } + } +} +#endif + +/* + * ======== PackTraceBuffer ======== + * Removes extra nulls from the trace buffer returned from the DSP. + * Works even on buffers that already are packed (null removed); but has + * one bug in that case -- loses the last character (replaces with '\0'). + * Continues through conversion for full set of nBytes input characters. + * Parameters: + * lpBuf: Pointer to input/output buffer + * nBytes: Number of characters in the buffer + * ulNumWords: Number of DSP words in the buffer. Indicates potential + * number of extra carriage returns to generate. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Unable to allocate memory. + * Requires: + * lpBuf must be a fully allocated writable block of at least nBytes. + * There are no more than ulNumWords extra characters needed (the number of + * linefeeds minus the number of NULLS in the input buffer). + */ +#if (defined(DEBUG) || defined(DDSP_DEBUG_PRODUCT)) && GT_TRACE +static DSP_STATUS PackTraceBuffer(char *lpBuf, u32 nBytes, u32 ulNumWords) +{ + DSP_STATUS status = DSP_SOK; + char *lpTmpBuf; + char *lpBufStart; + char *lpTmpStart; + u32 nCnt; + char thisChar; + + /* tmp workspace, 1 KB longer than input buf */ + lpTmpBuf = MEM_Calloc((nBytes + ulNumWords), MEM_PAGED); + if (lpTmpBuf == NULL) { + DBG_Trace(DBG_LEVEL7, "PackTrace buffer:OutofMemory \n"); + status = DSP_EMEMORY; + } + + if (DSP_SUCCEEDED(status)) { + lpBufStart = lpBuf; + lpTmpStart = lpTmpBuf; + for (nCnt = nBytes; nCnt > 0; nCnt--) { + thisChar = *lpBuf++; + switch (thisChar) { + case '\0': /* Skip null bytes */ + break; + case '\n': /* Convert \n to \r\n */ + /* NOTE: do not reverse order; Some OS */ + /* editors control doesn't understand "\n\r" */ + *lpTmpBuf++ = '\r'; + *lpTmpBuf++ = '\n'; + break; + default: /* Copy in the actual ascii byte */ + *lpTmpBuf++ = thisChar; + break; + } + } + *lpTmpBuf = '\0'; /* Make sure tmp buf is null terminated */ + /* Cut output down to input buf size */ + strncpy(lpBufStart, lpTmpStart, nBytes); + /*Make sure output is null terminated */ + lpBufStart[nBytes - 1] = '\0'; + MEM_Free(lpTmpStart); + } + + return status; +} +#endif /* (defined(DEBUG) || defined(DDSP_DEBUG_PRODUCT)) && GT_TRACE */ + +/* + * ======== PrintDspTraceBuffer ======== + * Prints the trace buffer returned from the DSP (if DBG_Trace is enabled). + * Parameters: + * hDehMgr: Handle to DEH manager object + * number of extra carriage returns to generate. + * Returns: + * DSP_SOK: Success. + * DSP_EMEMORY: Unable to allocate memory. + * Requires: + * hDehMgr muse be valid. Checked in WMD_DEH_Notify. + */ +DSP_STATUS PrintDspTraceBuffer(struct WMD_DEV_CONTEXT *hWmdContext) +{ + DSP_STATUS status = DSP_SOK; + +#if (defined(DEBUG) || defined(DDSP_DEBUG_PRODUCT)) && GT_TRACE + struct COD_MANAGER *hCodMgr; + u32 ulTraceEnd; + u32 ulTraceBegin; + u32 ulNumBytes = 0; + u32 ulNumWords = 0; + u32 ulWordSize = 2; + CONST u32 uMaxSize = 512; + char *pszBuf; + u16 *lpszBuf; + + struct WMD_DEV_CONTEXT *pWmdContext = (struct WMD_DEV_CONTEXT *) + hWmdContext; + struct WMD_DRV_INTERFACE *pIntfFxns; + struct DEV_OBJECT *pDevObject = (struct DEV_OBJECT *) + pWmdContext->hDevObject; + + status = DEV_GetCodMgr(pDevObject, &hCodMgr); + if (DSP_FAILED(status)) + GT_0trace(dsp_trace_mask, GT_2CLASS, + "PrintDspTraceBuffer: Failed on DEV_GetCodMgr.\n"); + + if (DSP_SUCCEEDED(status)) { + /* Look for SYS_PUTCBEG/SYS_PUTCEND: */ + status = COD_GetSymValue(hCodMgr, COD_TRACEBEG, &ulTraceBegin); + GT_1trace(dsp_trace_mask, GT_2CLASS, + "PrintDspTraceBuffer: ulTraceBegin Value 0x%x\n", + ulTraceBegin); + if (DSP_FAILED(status)) + GT_0trace(dsp_trace_mask, GT_2CLASS, + "PrintDspTraceBuffer: Failed on " + "COD_GetSymValue.\n"); + } + if (DSP_SUCCEEDED(status)) { + status = COD_GetSymValue(hCodMgr, COD_TRACEEND, &ulTraceEnd); + GT_1trace(dsp_trace_mask, GT_2CLASS, + "PrintDspTraceBuffer: ulTraceEnd Value 0x%x\n", + ulTraceEnd); + if (DSP_FAILED(status)) + GT_0trace(dsp_trace_mask, GT_2CLASS, + "PrintDspTraceBuffer: Failed on " + "COD_GetSymValue.\n"); + } + if (DSP_SUCCEEDED(status)) { + ulNumBytes = (ulTraceEnd - ulTraceBegin) * ulWordSize; + /* If the chip type is 55 then the addresses will be + * byte addresses; convert them to word addresses. */ + if (ulNumBytes > uMaxSize) + ulNumBytes = uMaxSize; + + /* make sure the data we request fits evenly */ + ulNumBytes = (ulNumBytes / ulWordSize) * ulWordSize; + GT_1trace(dsp_trace_mask, GT_2CLASS, "PrintDspTraceBuffer: " + "ulNumBytes 0x%x\n", ulNumBytes); + ulNumWords = ulNumBytes * ulWordSize; + GT_1trace(dsp_trace_mask, GT_2CLASS, "PrintDspTraceBuffer: " + "ulNumWords 0x%x\n", ulNumWords); + status = DEV_GetIntfFxns(pDevObject, &pIntfFxns); + } + + if (DSP_SUCCEEDED(status)) { + pszBuf = MEM_Calloc(uMaxSize, MEM_NONPAGED); + lpszBuf = MEM_Calloc(ulNumBytes * 2, MEM_NONPAGED); + if (pszBuf != NULL) { + /* Read bytes from the DSP trace buffer... */ + status = (*pIntfFxns->pfnBrdRead)(hWmdContext, + (u8 *)pszBuf, (u32)ulTraceBegin, + ulNumBytes, 0); + if (DSP_FAILED(status)) + GT_0trace(dsp_trace_mask, GT_2CLASS, + "PrintDspTraceBuffer: " + "Failed to Read Trace Buffer.\n"); + + if (DSP_SUCCEEDED(status)) { + /* Pack and do newline conversion */ + GT_0trace(dsp_trace_mask, GT_2CLASS, + "PrintDspTraceBuffer: " + "before pack and unpack.\n"); + PackTraceBuffer(pszBuf, ulNumBytes, ulNumWords); + GT_1trace(dsp_trace_mask, GT_1CLASS, + "DSP Trace Buffer:\n%s\n", pszBuf); + } + MEM_Free(pszBuf); + MEM_Free(lpszBuf); + } else { + GT_0trace(dsp_trace_mask, GT_2CLASS, + "PrintDspTraceBuffer: Failed to " + "allocate trace buffer.\n"); + status = DSP_EMEMORY; + } + } +#endif + return status; +} + +void IO_SM_init(void) +{ + + GT_create(&dsp_trace_mask, "DT"); /* DSP Trace Mask */ + +} diff --git a/drivers/dsp/bridge/wmd/mmu_fault.c b/drivers/dsp/bridge/wmd/mmu_fault.c new file mode 100644 index 0000000..5585cdb --- /dev/null +++ b/drivers/dsp/bridge/wmd/mmu_fault.c @@ -0,0 +1,172 @@ +/* + * mmu_fault.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== mmu_fault.c ======== + * Description: + * Implements DSP MMU fault handling functions. + * + *! Revision History: + *! ================ + *! 26-Dec-2004 hn: Support for IVA MMU exception. + *! 06-Mar-2003 sb: Print MMU fault address. Cosmetic changes. + *! 16-Feb-2003 vp: Fixed warning in MMU_FaultIsr + *! 05-Jan-2004 vp: Updated support for 24xx silicon + *! 19-Feb-2003 vp: Code review updates. + *! - Cosmetic changes. + *! 18-Oct-2002 sb: Ported to Linux platform. + *! 10-Sep-2001 kc: created. + */ + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include + +/* ----------------------------------- Link Driver */ +#include + +/* ------------------------------------ Hardware Abstraction Layer */ +#include +#include + +/* ----------------------------------- This */ +#include "_deh.h" +#include +#include "_tiomap_mmu.h" +#include "_tiomap.h" +#include "mmu_fault.h" + +static u32 dmmuEventMask; +u32 faultAddr; + +static bool MMU_CheckIfFault(struct WMD_DEV_CONTEXT *pDevContext); + +/* + * ======== MMU_FaultDpc ======== + * Deferred procedure call to handle DSP MMU fault. + */ +void MMU_FaultDpc(IN void *pRefData) +{ + struct DEH_MGR *hDehMgr = (struct DEH_MGR *)pRefData; + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)hDehMgr; + + DBG_Trace(DBG_LEVEL1, "MMU_FaultDpc Enter: 0x%x\n", pRefData); + + if (pDehMgr) + WMD_DEH_Notify(hDehMgr, DSP_MMUFAULT, 0L); + + DBG_Trace(DBG_LEVEL1, "MMU_FaultDpc Exit: 0x%x\n", pRefData); +} + +/* + * ======== MMU_FaultIsr ======== + * ISR to be triggered by a DSP MMU fault interrupt. + */ +irqreturn_t MMU_FaultIsr(int irq, IN void *pRefData) +{ + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)pRefData; + struct WMD_DEV_CONTEXT *pDevContext; + struct CFG_HOSTRES resources; + DSP_STATUS status = DSP_SOK; + + + DBG_Trace(DBG_LEVEL1, "Entering DEH_DspMmuIsr: 0x%x\n", pRefData); + DBC_Require(irq == INT_DSP_MMU_IRQ); + DBC_Require(MEM_IsValidHandle(pDehMgr, SIGNATURE)); + + if (MEM_IsValidHandle(pDehMgr, SIGNATURE)) { + + pDevContext = (struct WMD_DEV_CONTEXT *)pDehMgr->hWmdContext; + status = CFG_GetHostResources( + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), + &resources); + if (DSP_FAILED(status)) + DBG_Trace(DBG_LEVEL7, + "**Failed to get Host Resources " + "in MMU ISR **\n"); + if (MMU_CheckIfFault(pDevContext)) { + printk(KERN_INFO "***** DSPMMU FAULT ***** IRQStatus " + "0x%x\n", dmmuEventMask); + printk(KERN_INFO "***** DSPMMU FAULT ***** faultAddr " + "0x%x\n", faultAddr); + /* Disable the MMU events, else once we clear it will + * start to raise INTs again */ + /* + * Schedule a DPC directly. In the future, it may be + * necessary to check if DSP MMU fault is intended for + * Bridge. + */ + DPC_Schedule(pDehMgr->hMmuFaultDpc); + /* Reset errInfo structure before use. */ + pDehMgr->errInfo.dwErrMask = DSP_MMUFAULT; + pDehMgr->errInfo.dwVal1 = faultAddr >> 16; + pDehMgr->errInfo.dwVal2 = faultAddr & 0xFFFF; + pDehMgr->errInfo.dwVal3 = 0L; + /* Disable the MMU events, else once we clear it will + * start to raise INTs again */ + HW_MMU_EventDisable(resources.dwDmmuBase, + HW_MMU_TRANSLATION_FAULT); + } else { + DBG_Trace(DBG_LEVEL7, + "***** MMU FAULT ***** faultcode 0x%x\n", + dmmuEventMask); + HW_MMU_EventDisable(resources.dwDmmuBase, + HW_MMU_ALL_INTERRUPTS); + } + } + return IRQ_HANDLED; +} + + +/* + * ======== MMU_CheckIfFault ======== + * Check to see if MMU Fault is valid TLB miss from DSP + * Note: This function is called from an ISR + */ +static bool MMU_CheckIfFault(struct WMD_DEV_CONTEXT *pDevContext) +{ + + + bool retVal = false; + DSP_STATUS status = DSP_SOK; + HW_STATUS hwStatus; + struct CFG_HOSTRES resources; + status = CFG_GetHostResources( + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); + if (DSP_FAILED(status)) + DBG_Trace(DBG_LEVEL7, "**Failed to get Host Resources in " + "MMU_CheckIfFault **\n"); + + hwStatus = HW_MMU_EventStatus(resources.dwDmmuBase, &dmmuEventMask); + if (dmmuEventMask == HW_MMU_TRANSLATION_FAULT) { + HW_MMU_FaultAddrRead(resources.dwDmmuBase, &faultAddr); + DBG_Trace(DBG_LEVEL1, "WMD_DEH_Notify: DSP_MMUFAULT, fault " + "address = 0x%x\n", faultAddr); + retVal = true; + } + return retVal; +} diff --git a/drivers/dsp/bridge/wmd/mmu_fault.h b/drivers/dsp/bridge/wmd/mmu_fault.h new file mode 100644 index 0000000..be59333 --- /dev/null +++ b/drivers/dsp/bridge/wmd/mmu_fault.h @@ -0,0 +1,45 @@ +/* + * mmu_fault.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== mmu_fault.h ======== + * Description: + * Defines DSP MMU fault handling functions. + * + *! Revision History: + *! ================ + *! 26-Dec-2004 hn: IVA MMU handlers. + *! 10-Sep-2001 kc: created. + */ + +#ifndef MMU_FAULT_ +#define MMU_FAULT_ + +/* + * ======== MMU_FaultDpc ======== + * Deferred procedure call to handle DSP MMU fault. + */ + void MMU_FaultDpc(IN void *pRefData); + +/* + * ======== MMU_FaultIsr ======== + * ISR to be triggered by a DSP MMU fault interrupt. + */ +irqreturn_t MMU_FaultIsr(int irq, IN void *pRefData); + +#endif /* MMU_FAULT_ */ + diff --git a/drivers/dsp/bridge/wmd/msg_sm.c b/drivers/dsp/bridge/wmd/msg_sm.c new file mode 100644 index 0000000..b9b2bec --- /dev/null +++ b/drivers/dsp/bridge/wmd/msg_sm.c @@ -0,0 +1,643 @@ +/* + * msg_sm.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== msg_sm.c ======== + * Description: + * Implements upper edge functions for WMD message module. + * + * Public Functions: + * WMD_MSG_Create + * WMD_MSG_CreateQueue + * WMD_MSG_Delete + * WMD_MSG_DeleteQueue + * WMD_MSG_Get + * WMD_MSG_Put + * WMD_MSG_RegisterNotify + * WMD_MSG_SetQueueId + * + *! Revision History: + *! ================= + *! 24-Jul-2002 jeh Release critical section in WMD_MSG_Put() before + *! scheduling DPC. + *! 09-May-2001 jeh Free MSG queue NTFY object, remove unnecessary set/ + *! reset of events. + *! 10-Jan-2001 jeh Set/Reset message manager and message queue events + *! correctly. + *! 04-Dec-2000 jeh Bug fixes. + *! 12-Sep-2000 jeh Created. + */ + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include + +/* ----------------------------------- Platform Manager */ +#include + +/* ----------------------------------- Others */ +#include + +/* ----------------------------------- This */ +#include <_msg_sm.h> +#include + +/* ----------------------------------- Defines, Data Structures, Typedefs */ +#define MSGQ_SIGNATURE 0x5147534d /* "QGSM" */ + +/* ----------------------------------- Function Prototypes */ +static DSP_STATUS AddNewMsg(struct LST_LIST *msgList); +static void DeleteMsgMgr(struct MSG_MGR *hMsgMgr); +static void DeleteMsgQueue(struct MSG_QUEUE *hMsgQueue, u32 uNumToDSP); +static void FreeMsgList(struct LST_LIST *msgList); + +/* + * ======== WMD_MSG_Create ======== + * Create an object to manage message queues. Only one of these objects + * can exist per device object. + */ +DSP_STATUS WMD_MSG_Create(OUT struct MSG_MGR **phMsgMgr, + struct DEV_OBJECT *hDevObject, MSG_ONEXIT msgCallback) +{ + struct MSG_MGR *pMsgMgr; + struct IO_MGR *hIOMgr; + DSP_STATUS status = DSP_SOK; + + DBC_Require(phMsgMgr != NULL); + DBC_Require(msgCallback != NULL); + DBC_Require(hDevObject != NULL); + DEV_GetIOMgr(hDevObject, &hIOMgr); + DBC_Assert(hIOMgr != NULL); + *phMsgMgr = NULL; + /* Allocate MSG manager object */ + MEM_AllocObject(pMsgMgr, struct MSG_MGR, MSGMGR_SIGNATURE); + + if (pMsgMgr) { + pMsgMgr->onExit = msgCallback; + pMsgMgr->hIOMgr = hIOMgr; + /* List of MSG_QUEUEs */ + pMsgMgr->queueList = LST_Create(); + /* Queues of message frames for messages to the DSP. Message + * frames will only be added to the free queue when a + * MSG_QUEUE object is created. */ + pMsgMgr->msgFreeList = LST_Create(); + pMsgMgr->msgUsedList = LST_Create(); + if (pMsgMgr->queueList == NULL || + pMsgMgr->msgFreeList == NULL || + pMsgMgr->msgUsedList == NULL) + status = DSP_EMEMORY; + if (DSP_SUCCEEDED(status)) + status = SYNC_InitializeDPCCS(&pMsgMgr->hSyncCS); + + /* Create an event to be used by WMD_MSG_Put() in waiting + * for an available free frame from the message manager. */ + if (DSP_SUCCEEDED(status)) + status = SYNC_OpenEvent(&pMsgMgr->hSyncEvent, NULL); + + if (DSP_SUCCEEDED(status)) + *phMsgMgr = pMsgMgr; + else + DeleteMsgMgr(pMsgMgr); + + } else { + status = DSP_EMEMORY; + } + return status; +} + +/* + * ======== WMD_MSG_CreateQueue ======== + * Create a MSG_QUEUE for sending/receiving messages to/from a node + * on the DSP. + */ +DSP_STATUS WMD_MSG_CreateQueue(struct MSG_MGR *hMsgMgr, + OUT struct MSG_QUEUE **phMsgQueue, + u32 dwId, u32 uMaxMsgs, HANDLE hArg) +{ + u32 i; + u32 uNumAllocated = 0; + struct MSG_QUEUE *pMsgQ; + DSP_STATUS status = DSP_SOK; + + DBC_Require(MEM_IsValidHandle(hMsgMgr, MSGMGR_SIGNATURE)); + DBC_Require(phMsgQueue != NULL); + + *phMsgQueue = NULL; + /* Allocate MSG_QUEUE object */ + MEM_AllocObject(pMsgQ, struct MSG_QUEUE, MSGQ_SIGNATURE); + if (!pMsgQ) { + status = DSP_EMEMORY; + goto func_end; + } + LST_InitElem((struct LST_ELEM *) pMsgQ); + pMsgQ->uMaxMsgs = uMaxMsgs; + pMsgQ->hMsgMgr = hMsgMgr; + pMsgQ->hArg = hArg; /* Node handle */ + pMsgQ->dwId = dwId; /* Node env (not valid yet) */ + /* Queues of Message frames for messages from the DSP */ + pMsgQ->msgFreeList = LST_Create(); + pMsgQ->msgUsedList = LST_Create(); + if (pMsgQ->msgFreeList == NULL || pMsgQ->msgUsedList == NULL) + status = DSP_EMEMORY; + + /* Create event that will be signalled when a message from + * the DSP is available. */ + if (DSP_SUCCEEDED(status)) + status = SYNC_OpenEvent(&pMsgQ->hSyncEvent, NULL); + + /* Create a notification list for message ready notification. */ + if (DSP_SUCCEEDED(status)) + status = NTFY_Create(&pMsgQ->hNtfy); + + /* Create events that will be used to synchronize cleanup + * when the object is deleted. hSyncDone will be set to + * unblock threads in MSG_Put() or MSG_Get(). hSyncDoneAck + * will be set by the unblocked thread to signal that it + * is unblocked and will no longer reference the object. */ + if (DSP_SUCCEEDED(status)) + status = SYNC_OpenEvent(&pMsgQ->hSyncDone, NULL); + + if (DSP_SUCCEEDED(status)) + status = SYNC_OpenEvent(&pMsgQ->hSyncDoneAck, NULL); + + if (DSP_SUCCEEDED(status)) { + if (!hMsgMgr->msgFreeList) { + status = DSP_EHANDLE; + goto func_end; + } + /* Enter critical section */ + (void)SYNC_EnterCS(hMsgMgr->hSyncCS); + /* Initialize message frames and put in appropriate queues */ + for (i = 0; i < uMaxMsgs && DSP_SUCCEEDED(status); i++) { + status = AddNewMsg(hMsgMgr->msgFreeList); + if (DSP_SUCCEEDED(status)) { + uNumAllocated++; + status = AddNewMsg(pMsgQ->msgFreeList); + } + } + if (DSP_FAILED(status)) { + /* Stay inside CS to prevent others from taking any + * of the newly allocated message frames. */ + DeleteMsgQueue(pMsgQ, uNumAllocated); + } else { + LST_PutTail(hMsgMgr->queueList, + (struct LST_ELEM *)pMsgQ); + *phMsgQueue = pMsgQ; + /* Signal that free frames are now available */ + if (!LST_IsEmpty(hMsgMgr->msgFreeList)) + SYNC_SetEvent(hMsgMgr->hSyncEvent); + + } + /* Exit critical section */ + (void)SYNC_LeaveCS(hMsgMgr->hSyncCS); + } else { + DeleteMsgQueue(pMsgQ, 0); + } +func_end: + return status; +} + +/* + * ======== WMD_MSG_Delete ======== + * Delete a MSG manager allocated in WMD_MSG_Create(). + */ +void WMD_MSG_Delete(struct MSG_MGR *hMsgMgr) +{ + DBC_Require(MEM_IsValidHandle(hMsgMgr, MSGMGR_SIGNATURE)); + + DeleteMsgMgr(hMsgMgr); +} + +/* + * ======== WMD_MSG_DeleteQueue ======== + * Delete a MSG queue allocated in WMD_MSG_CreateQueue. + */ +void WMD_MSG_DeleteQueue(struct MSG_QUEUE *hMsgQueue) +{ + struct MSG_MGR *hMsgMgr = hMsgQueue->hMsgMgr; + u32 refCount; + + DBC_Require(MEM_IsValidHandle(hMsgQueue, MSGQ_SIGNATURE)); + hMsgQueue->fDone = true; + /* Unblock all threads blocked in MSG_Get() or MSG_Put(). */ + refCount = hMsgQueue->refCount; + while (refCount) { + /* Unblock thread */ + SYNC_SetEvent(hMsgQueue->hSyncDone); + /* Wait for acknowledgement */ + SYNC_WaitOnEvent(hMsgQueue->hSyncDoneAck, SYNC_INFINITE); + refCount = hMsgQueue->refCount; + } + /* Remove message queue from hMsgMgr->queueList */ + (void)SYNC_EnterCS(hMsgMgr->hSyncCS); + LST_RemoveElem(hMsgMgr->queueList, (struct LST_ELEM *)hMsgQueue); + /* Free the message queue object */ + DeleteMsgQueue(hMsgQueue, hMsgQueue->uMaxMsgs); + if (!hMsgMgr->msgFreeList) + goto func_cont; + if (LST_IsEmpty(hMsgMgr->msgFreeList)) + SYNC_ResetEvent(hMsgMgr->hSyncEvent); +func_cont: + (void)SYNC_LeaveCS(hMsgMgr->hSyncCS); +} + +/* + * ======== WMD_MSG_Get ======== + * Get a message from a MSG queue. + */ +DSP_STATUS WMD_MSG_Get(struct MSG_QUEUE *hMsgQueue, + struct DSP_MSG *pMsg, u32 uTimeout) +{ + struct MSG_FRAME *pMsgFrame; + struct MSG_MGR *hMsgMgr; + bool fGotMsg = false; + struct SYNC_OBJECT *hSyncs[2]; + u32 uIndex; + DSP_STATUS status = DSP_SOK; + + DBC_Require(MEM_IsValidHandle(hMsgQueue, MSGQ_SIGNATURE)); + DBC_Require(pMsg != NULL); + + hMsgMgr = hMsgQueue->hMsgMgr; + if (!hMsgQueue->msgUsedList) { + status = DSP_EHANDLE; + goto func_end; + } + + /* Enter critical section */ + (void)SYNC_EnterCS(hMsgMgr->hSyncCS); + /* If a message is already there, get it */ + if (!LST_IsEmpty(hMsgQueue->msgUsedList)) { + pMsgFrame = (struct MSG_FRAME *)LST_GetHead(hMsgQueue-> + msgUsedList); + if (pMsgFrame != NULL) { + *pMsg = pMsgFrame->msgData.msg; + LST_PutTail(hMsgQueue->msgFreeList, + (struct LST_ELEM *)pMsgFrame); + if (LST_IsEmpty(hMsgQueue->msgUsedList)) + SYNC_ResetEvent(hMsgQueue->hSyncEvent); + + fGotMsg = true; + } + } else { + if (hMsgQueue->fDone) + status = DSP_EFAIL; + else + hMsgQueue->refCount++; + + } + /* Exit critical section */ + (void)SYNC_LeaveCS(hMsgMgr->hSyncCS); + if (DSP_SUCCEEDED(status) && !fGotMsg) { + /* Wait til message is available, timeout, or done. We don't + * have to schedule the DPC, since the DSP will send messages + * when they are available. */ + hSyncs[0] = hMsgQueue->hSyncEvent; + hSyncs[1] = hMsgQueue->hSyncDone; + status = SYNC_WaitOnMultipleEvents(hSyncs, 2, uTimeout, + &uIndex); + /* Enter critical section */ + (void)SYNC_EnterCS(hMsgMgr->hSyncCS); + if (hMsgQueue->fDone) { + hMsgQueue->refCount--; + /* Exit critical section */ + (void)SYNC_LeaveCS(hMsgMgr->hSyncCS); + /* Signal that we're not going to access hMsgQueue + * anymore, so it can be deleted. */ + (void)SYNC_SetEvent(hMsgQueue->hSyncDoneAck); + status = DSP_EFAIL; + } else { + if (DSP_SUCCEEDED(status)) { + DBC_Assert(!LST_IsEmpty(hMsgQueue-> + msgUsedList)); + /* Get msg from used list */ + pMsgFrame = (struct MSG_FRAME *) + LST_GetHead(hMsgQueue->msgUsedList); + /* Copy message into pMsg and put frame on the + * free list */ + if (pMsgFrame != NULL) { + *pMsg = pMsgFrame->msgData.msg; + LST_PutTail(hMsgQueue->msgFreeList, + (struct LST_ELEM *)pMsgFrame); + } + } + hMsgQueue->refCount--; + /* Reset the event if there are still queued messages */ + if (!LST_IsEmpty(hMsgQueue->msgUsedList)) + SYNC_SetEvent(hMsgQueue->hSyncEvent); + + /* Exit critical section */ + (void)SYNC_LeaveCS(hMsgMgr->hSyncCS); + } + } +func_end: + return status; +} + +/* + * ======== WMD_MSG_Put ======== + * Put a message onto a MSG queue. + */ +DSP_STATUS WMD_MSG_Put(struct MSG_QUEUE *hMsgQueue, + IN CONST struct DSP_MSG *pMsg, u32 uTimeout) +{ + struct MSG_FRAME *pMsgFrame; + struct MSG_MGR *hMsgMgr; + bool fPutMsg = false; + struct SYNC_OBJECT *hSyncs[2]; + u32 uIndex; + DSP_STATUS status = DSP_SOK; + + DBC_Require(MEM_IsValidHandle(hMsgQueue, MSGQ_SIGNATURE)); + DBC_Require(pMsg != NULL); + + hMsgMgr = hMsgQueue->hMsgMgr; + + if (!hMsgMgr->msgFreeList) { + status = DSP_EHANDLE; + goto func_end; + } + + + (void) SYNC_EnterCS(hMsgMgr->hSyncCS); + + /* If a message frame is available, use it */ + if (!LST_IsEmpty(hMsgMgr->msgFreeList)) { + pMsgFrame = (struct MSG_FRAME *)LST_GetHead(hMsgMgr-> + msgFreeList); + if (pMsgFrame != NULL) { + pMsgFrame->msgData.msg = *pMsg; + pMsgFrame->msgData.dwId = hMsgQueue->dwId; + LST_PutTail(hMsgMgr->msgUsedList, (struct LST_ELEM *) + pMsgFrame); + hMsgMgr->uMsgsPending++; + fPutMsg = true; + } + if (LST_IsEmpty(hMsgMgr->msgFreeList)) + SYNC_ResetEvent(hMsgMgr->hSyncEvent); + + /* Release critical section before scheduling DPC */ + (void)SYNC_LeaveCS(hMsgMgr->hSyncCS); + /* Schedule a DPC, to do the actual data transfer: */ + IO_Schedule(hMsgMgr->hIOMgr); + } else { + if (hMsgQueue->fDone) + status = DSP_EFAIL; + else + hMsgQueue->refCount++; + + (void)SYNC_LeaveCS(hMsgMgr->hSyncCS); + } + if (DSP_SUCCEEDED(status) && !fPutMsg) { + /* Wait til a free message frame is available, timeout, + * or done */ + hSyncs[0] = hMsgMgr->hSyncEvent; + hSyncs[1] = hMsgQueue->hSyncDone; + status = SYNC_WaitOnMultipleEvents(hSyncs, 2, uTimeout, + &uIndex); + /* Enter critical section */ + (void)SYNC_EnterCS(hMsgMgr->hSyncCS); + if (hMsgQueue->fDone) { + hMsgQueue->refCount--; + /* Exit critical section */ + (void)SYNC_LeaveCS(hMsgMgr->hSyncCS); + /* Signal that we're not going to access hMsgQueue + * anymore, so it can be deleted. */ + (void)SYNC_SetEvent(hMsgQueue->hSyncDoneAck); + status = DSP_EFAIL; + } else { + if (DSP_SUCCEEDED(status)) { + if (LST_IsEmpty(hMsgMgr->msgFreeList)) { + status = DSP_EPOINTER; + goto func_cont; + } + /* Get msg from free list */ + pMsgFrame = (struct MSG_FRAME *) + LST_GetHead(hMsgMgr->msgFreeList); + /* Copy message into pMsg and put frame on the + * used list */ + if (pMsgFrame != NULL) { + pMsgFrame->msgData.msg = *pMsg; + pMsgFrame->msgData.dwId = + hMsgQueue->dwId; + LST_PutTail(hMsgMgr->msgUsedList, + (struct LST_ELEM *) + pMsgFrame); + hMsgMgr->uMsgsPending++; + /* Schedule a DPC, to do the actual + * data transfer: */ + IO_Schedule(hMsgMgr->hIOMgr); + } + } + hMsgQueue->refCount--; + /* Reset event if there are still frames available */ + if (!LST_IsEmpty(hMsgMgr->msgFreeList)) + SYNC_SetEvent(hMsgMgr->hSyncEvent); +func_cont: + /* Exit critical section */ + (void) SYNC_LeaveCS(hMsgMgr->hSyncCS); + } + } +func_end: + return status; +} + +/* + * ======== WMD_MSG_RegisterNotify ======== + */ +DSP_STATUS WMD_MSG_RegisterNotify(struct MSG_QUEUE *hMsgQueue, u32 uEventMask, + u32 uNotifyType, + struct DSP_NOTIFICATION *hNotification) +{ + DSP_STATUS status = DSP_SOK; + + DBC_Require(MEM_IsValidHandle(hMsgQueue, MSGQ_SIGNATURE)); + DBC_Require(hNotification != NULL); + DBC_Require(uEventMask == DSP_NODEMESSAGEREADY || uEventMask == 0); + DBC_Require(uNotifyType == DSP_SIGNALEVENT); + + status = NTFY_Register(hMsgQueue->hNtfy, hNotification, uEventMask, + uNotifyType); + + if (status == DSP_EVALUE) { + /* Not registered. Ok, since we couldn't have known. Node + * notifications are split between node state change handled + * by NODE, and message ready handled by MSG. */ + status = DSP_SOK; + } + + return status; +} + +/* + * ======== WMD_MSG_SetQueueId ======== + */ +void WMD_MSG_SetQueueId(struct MSG_QUEUE *hMsgQueue, u32 dwId) +{ + DBC_Require(MEM_IsValidHandle(hMsgQueue, MSGQ_SIGNATURE)); + /* DBC_Require(dwId != 0); */ + + /* + * A message queue must be created when a node is allocated, + * so that NODE_RegisterNotify() can be called before the node + * is created. Since we don't know the node environment until the + * node is created, we need this function to set hMsgQueue->dwId + * to the node environment, after the node is created. + */ + hMsgQueue->dwId = dwId; +} + +/* + * ======== AddNewMsg ======== + * Must be called in message manager critical section. + */ +static DSP_STATUS AddNewMsg(struct LST_LIST *msgList) +{ + struct MSG_FRAME *pMsg; + DSP_STATUS status = DSP_SOK; + + pMsg = (struct MSG_FRAME *)MEM_Calloc(sizeof(struct MSG_FRAME), + MEM_PAGED); + if (pMsg != NULL) { + LST_InitElem((struct LST_ELEM *) pMsg); + LST_PutTail(msgList, (struct LST_ELEM *) pMsg); + } else { + status = DSP_EMEMORY; + } + + return status; +} + +/* + * ======== DeleteMsgMgr ======== + */ +static void DeleteMsgMgr(struct MSG_MGR *hMsgMgr) +{ + DBC_Require(MEM_IsValidHandle(hMsgMgr, MSGMGR_SIGNATURE)); + + if (hMsgMgr->queueList) { + if (LST_IsEmpty(hMsgMgr->queueList)) { + LST_Delete(hMsgMgr->queueList); + hMsgMgr->queueList = NULL; + } + } + + if (hMsgMgr->msgFreeList) { + FreeMsgList(hMsgMgr->msgFreeList); + hMsgMgr->msgFreeList = NULL; + } + + if (hMsgMgr->msgUsedList) { + FreeMsgList(hMsgMgr->msgUsedList); + hMsgMgr->msgUsedList = NULL; + } + + if (hMsgMgr->hSyncEvent) + SYNC_CloseEvent(hMsgMgr->hSyncEvent); + + if (hMsgMgr->hSyncCS) + SYNC_DeleteCS(hMsgMgr->hSyncCS); + + MEM_FreeObject(hMsgMgr); +} + +/* + * ======== DeleteMsgQueue ======== + */ +static void DeleteMsgQueue(struct MSG_QUEUE *hMsgQueue, u32 uNumToDSP) +{ + struct MSG_MGR *hMsgMgr; + struct MSG_FRAME *pMsg; + u32 i; + + if (!MEM_IsValidHandle(hMsgQueue, MSGQ_SIGNATURE) + || !hMsgQueue->hMsgMgr || !hMsgQueue->hMsgMgr->msgFreeList) + goto func_end; + hMsgMgr = hMsgQueue->hMsgMgr; + + + /* Pull off uNumToDSP message frames from Msg manager and free */ + for (i = 0; i < uNumToDSP; i++) { + + if (!LST_IsEmpty(hMsgMgr->msgFreeList)) { + pMsg = (struct MSG_FRAME *)LST_GetHead(hMsgMgr-> + msgFreeList); + MEM_Free(pMsg); + } else { + /* Cannot free all of the message frames */ + break; + } + } + + if (hMsgQueue->msgFreeList) { + FreeMsgList(hMsgQueue->msgFreeList); + hMsgQueue->msgFreeList = NULL; + } + + if (hMsgQueue->msgUsedList) { + FreeMsgList(hMsgQueue->msgUsedList); + hMsgQueue->msgUsedList = NULL; + } + + + if (hMsgQueue->hNtfy) + NTFY_Delete(hMsgQueue->hNtfy); + + if (hMsgQueue->hSyncEvent) + SYNC_CloseEvent(hMsgQueue->hSyncEvent); + + if (hMsgQueue->hSyncDone) + SYNC_CloseEvent(hMsgQueue->hSyncDone); + + if (hMsgQueue->hSyncDoneAck) + SYNC_CloseEvent(hMsgQueue->hSyncDoneAck); + + MEM_FreeObject(hMsgQueue); +func_end: + return; + +} + +/* + * ======== FreeMsgList ======== + */ +static void FreeMsgList(struct LST_LIST *msgList) +{ + struct MSG_FRAME *pMsg; + + if (!msgList) + goto func_end; + + while ((pMsg = (struct MSG_FRAME *)LST_GetHead(msgList)) != NULL) + MEM_Free(pMsg); + + DBC_Assert(LST_IsEmpty(msgList)); + + LST_Delete(msgList); +func_end: + return; +} + diff --git a/drivers/dsp/bridge/wmd/tiomap3430.c b/drivers/dsp/bridge/wmd/tiomap3430.c new file mode 100644 index 0000000..2ab585d --- /dev/null +++ b/drivers/dsp/bridge/wmd/tiomap3430.c @@ -0,0 +1,2149 @@ +/* + * tiomap.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== tiomap.c ======== + * Processor Manager Driver for TI OMAP3430 EVM. + * + * Public Function: + * WMD_DRV_Entry + * + *! Revision History: + *! ================ + * 26-March-2008 HK and AL: Added WMD_DEV_WalkTbl funciton. + */ + +/* ----------------------------------- Host OS */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* ------------------------------------ Hardware Abstraction Layer */ +#include +#include +#include +#include +#include + +/* ----------------------------------- Link Driver */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* ----------------------------------- Platform Manager */ +#include +#include +#include + +/* ----------------------------------- Local */ +#include "_tiomap.h" +#include "_tiomap_pwr.h" +#include "_tiomap_mmu.h" +#include "_tiomap_util.h" +#include "tiomap_io.h" + + +/* Offset in shared mem to write to in order to synchronize start with DSP */ +#define SHMSYNCOFFSET 4 /* GPP byte offset */ + +#define BUFFERSIZE 1024 + +#define MMU_SECTION_ADDR_MASK 0xFFF00000 +#define MMU_SSECTION_ADDR_MASK 0xFF000000 +#define MMU_LARGE_PAGE_MASK 0xFFFF0000 +#define MMU_SMALL_PAGE_MASK 0xFFFFF000 +#define PAGES_II_LVL_TABLE 512 +#define phys_to_page(phys) pfn_to_page((phys) >> PAGE_SHIFT) + +#define MMU_GFLUSH 0x60 + +/* Forward Declarations: */ +static DSP_STATUS WMD_BRD_Monitor(struct WMD_DEV_CONTEXT *pDevContext); +static DSP_STATUS WMD_BRD_Read(struct WMD_DEV_CONTEXT *pDevContext, + OUT u8 *pbHostBuf, + u32 dwDSPAddr, u32 ulNumBytes, u32 ulMemType); +static DSP_STATUS WMD_BRD_Start(struct WMD_DEV_CONTEXT *pDevContext, + u32 dwDSPAddr); +static DSP_STATUS WMD_BRD_Status(struct WMD_DEV_CONTEXT *pDevContext, + OUT BRD_STATUS *pdwState); +static DSP_STATUS WMD_BRD_Stop(struct WMD_DEV_CONTEXT *pDevContext); +static DSP_STATUS WMD_BRD_Write(struct WMD_DEV_CONTEXT *pDevContext, + IN u8 *pbHostBuf, + u32 dwDSPAddr, u32 ulNumBytes, u32 ulMemType); +static DSP_STATUS WMD_BRD_SetState(struct WMD_DEV_CONTEXT *hDevContext, + u32 ulBrdState); +static DSP_STATUS WMD_BRD_MemCopy(struct WMD_DEV_CONTEXT *hDevContext, + u32 ulDspDestAddr, u32 ulDspSrcAddr, + u32 ulNumBytes, u32 ulMemType); +static DSP_STATUS WMD_BRD_MemWrite(struct WMD_DEV_CONTEXT *pDevContext, + IN u8 *pbHostBuf, u32 dwDSPAddr, + u32 ulNumBytes, u32 ulMemType); +static DSP_STATUS WMD_BRD_MemMap(struct WMD_DEV_CONTEXT *hDevContext, + u32 ulMpuAddr, u32 ulVirtAddr, u32 ulNumBytes, + u32 ulMapAttr); +static DSP_STATUS WMD_BRD_MemUnMap(struct WMD_DEV_CONTEXT *hDevContext, + u32 ulVirtAddr, u32 ulNumBytes); +static DSP_STATUS WMD_DEV_Create(OUT struct WMD_DEV_CONTEXT **ppDevContext, + struct DEV_OBJECT *hDevObject, + IN CONST struct CFG_HOSTRES *pConfig, + IN CONST struct CFG_DSPRES *pDspConfig); +static DSP_STATUS WMD_DEV_Ctrl(struct WMD_DEV_CONTEXT *pDevContext, u32 dwCmd, + IN OUT void *pArgs); +static DSP_STATUS WMD_DEV_Destroy(struct WMD_DEV_CONTEXT *pDevContext); +static u32 user_va2pa(struct mm_struct *mm, u32 address); +static DSP_STATUS PteUpdate(struct WMD_DEV_CONTEXT *hDevContext, u32 pa, + u32 va, u32 size, + struct HW_MMUMapAttrs_t *mapAttrs); +static DSP_STATUS PteSet(struct PgTableAttrs *pt, u32 pa, u32 va, + u32 size, struct HW_MMUMapAttrs_t *attrs); +static DSP_STATUS MemMapVmalloc(struct WMD_DEV_CONTEXT *hDevContext, + u32 ulMpuAddr, u32 ulVirtAddr, + u32 ulNumBytes, struct HW_MMUMapAttrs_t *hwAttrs); +static DSP_STATUS run_IdleBoot(u32 prcm_base, u32 cm_base, + u32 sysctrl_base); +void GetHWRegs(u32 prcm_base, u32 cm_base); + +/* ----------------------------------- Globals */ + +/* Attributes of L2 page tables for DSP MMU */ +struct PageInfo { + u32 numEntries; /* Number of valid PTEs in the L2 PT */ +} ; + +/* Attributes used to manage the DSP MMU page tables */ +struct PgTableAttrs { + struct SYNC_CSOBJECT *hCSObj; /* Critical section object handle */ + + u32 L1BasePa; /* Physical address of the L1 PT */ + u32 L1BaseVa; /* Virtual address of the L1 PT */ + u32 L1size; /* Size of the L1 PT */ + u32 L1TblAllocPa; + /* Physical address of Allocated mem for L1 table. May not be aligned */ + u32 L1TblAllocVa; + /* Virtual address of Allocated mem for L1 table. May not be aligned */ + u32 L1TblAllocSz; + /* Size of consistent memory allocated for L1 table. + * May not be aligned */ + + u32 L2BasePa; /* Physical address of the L2 PT */ + u32 L2BaseVa; /* Virtual address of the L2 PT */ + u32 L2size; /* Size of the L2 PT */ + u32 L2TblAllocPa; + /* Physical address of Allocated mem for L2 table. May not be aligned */ + u32 L2TblAllocVa; + /* Virtual address of Allocated mem for L2 table. May not be aligned */ + u32 L2TblAllocSz; + /* Size of consistent memory allocated for L2 table. + * May not be aligned */ + + u32 L2NumPages; /* Number of allocated L2 PT */ + struct PageInfo *pgInfo; /* Array [L2NumPages] of L2 PT info structs */ +} ; + +/* + * If dsp_debug is true, do not branch to the DSP entry point and wait for DSP + * to boot + */ +extern s32 dsp_debug; + + +/* + * This mini driver's function interface table. + */ +static struct WMD_DRV_INTERFACE drvInterfaceFxns = { + WCD_MAJOR_VERSION, /* WCD ver. for which this mini driver is built. */ + WCD_MINOR_VERSION, + WMD_DEV_Create, + WMD_DEV_Destroy, + WMD_DEV_Ctrl, + WMD_BRD_Monitor, + WMD_BRD_Start, + WMD_BRD_Stop, + WMD_BRD_Status, + WMD_BRD_Read, + WMD_BRD_Write, + WMD_BRD_SetState, + WMD_BRD_MemCopy, + WMD_BRD_MemWrite, + WMD_BRD_MemMap, + WMD_BRD_MemUnMap, + /* The following CHNL functions are provided by chnl_io.lib: */ + WMD_CHNL_Create, + WMD_CHNL_Destroy, + WMD_CHNL_Open, + WMD_CHNL_Close, + WMD_CHNL_AddIOReq, + WMD_CHNL_GetIOC, + WMD_CHNL_CancelIO, + WMD_CHNL_FlushIO, + WMD_CHNL_GetInfo, + WMD_CHNL_GetMgrInfo, + WMD_CHNL_Idle, + WMD_CHNL_RegisterNotify, + /* The following DEH functions are provided by tihelen_ue_deh.c */ + WMD_DEH_Create, + WMD_DEH_Destroy, + WMD_DEH_Notify, + WMD_DEH_RegisterNotify, + WMD_DEH_GetInfo, + /* The following IO functions are provided by chnl_io.lib: */ + WMD_IO_Create, + WMD_IO_Destroy, + WMD_IO_OnLoaded, + WMD_IO_GetProcLoad, + /* The following MSG functions are provided by chnl_io.lib: */ + WMD_MSG_Create, + WMD_MSG_CreateQueue, + WMD_MSG_Delete, + WMD_MSG_DeleteQueue, + WMD_MSG_Get, + WMD_MSG_Put, + WMD_MSG_RegisterNotify, + WMD_MSG_SetQueueId, +}; + +static inline void tlb_flush_all(const u32 base) +{ + __raw_writeb(__raw_readb(base + MMU_GFLUSH) | 1, base + MMU_GFLUSH); +} + +static inline void flush_all(struct WMD_DEV_CONTEXT *pDevContext) +{ + struct CFG_HOSTRES resources; + u32 temp = 0; + + CFG_GetHostResources((struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); + HW_PWRST_IVA2RegGet(resources.dwPrmBase, &temp); + + if ((temp & HW_PWR_STATE_ON) == HW_PWR_STATE_OFF || + (temp & HW_PWR_STATE_ON) == HW_PWR_STATE_RET) { + CLK_Enable(SERVICESCLK_iva2_ck); + WakeDSP(pDevContext, NULL); + tlb_flush_all(pDevContext->dwDSPMmuBase); + CLK_Disable(SERVICESCLK_iva2_ck); + } else + tlb_flush_all(pDevContext->dwDSPMmuBase); +} + +static void bad_page_dump(u32 pa, struct page *pg) +{ + pr_emerg("DSPBRIDGE: MAP function: COUNT 0 FOR PA 0x%x\n", pa); + pr_emerg("Bad page state in process '%s'\n" + "page:%p flags:0x%0*lx mapping:%p mapcount:%d count:%d\n" + "Backtrace:\n", + current->comm, pg, (int)(2*sizeof(unsigned long)), + (unsigned long)pg->flags, pg->mapping, + page_mapcount(pg), page_count(pg)); + BUG(); +} + +/* + * ======== WMD_DRV_Entry ======== + * purpose: + * Mini Driver entry point. + */ +void WMD_DRV_Entry(OUT struct WMD_DRV_INTERFACE **ppDrvInterface, + IN CONST char *pstrWMDFileName) +{ + + DBC_Require(pstrWMDFileName != NULL); + DBG_Trace(DBG_ENTER, "In the WMD_DRV_Entry \n"); + + IO_SM_init(); /* Initialization of io_sm module */ + + if (strcmp(pstrWMDFileName, "UMA") == 0) + *ppDrvInterface = &drvInterfaceFxns; + else + DBG_Trace(DBG_LEVEL7, "WMD_DRV_Entry Unknown WMD file name"); + +} + +/* + * ======== WMD_BRD_Monitor ======== + * purpose: + * This WMD_BRD_Monitor puts DSP into a Loadable state. + * i.e Application can load and start the device. + * + * Preconditions: + * Device in 'OFF' state. + */ +static DSP_STATUS WMD_BRD_Monitor(struct WMD_DEV_CONTEXT *hDevContext) +{ + DSP_STATUS status = DSP_SOK; + struct WMD_DEV_CONTEXT *pDevContext = hDevContext; + struct CFG_HOSTRES resources; + u32 temp; + enum HW_PwrState_t pwrState; + + DBG_Trace(DBG_ENTER, "Board in the monitor state \n"); + status = CFG_GetHostResources( + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); + if (DSP_FAILED(status)) + goto error_return; + + GetHWRegs(resources.dwPrmBase, resources.dwCmBase); + HW_PWRST_IVA2RegGet(resources.dwPrmBase, &temp); + if ((temp & 0x03) != 0x03 || (temp & 0x03) != 0x02) { + /* IVA2 is not in ON state */ + /* Read and set PM_PWSTCTRL_IVA2 to ON */ + HW_PWR_IVA2PowerStateSet(resources.dwPrmBase, + HW_PWR_DOMAIN_DSP, + HW_PWR_STATE_ON); + /* Set the SW supervised state transition */ + HW_PWR_CLKCTRL_IVA2RegSet(resources.dwCmBase, + HW_SW_SUP_WAKEUP); + /* Wait until the state has moved to ON */ + HW_PWR_IVA2StateGet(resources.dwPrmBase, HW_PWR_DOMAIN_DSP, + &pwrState); + /* Disable Automatic transition */ + HW_PWR_CLKCTRL_IVA2RegSet(resources.dwCmBase, HW_AUTOTRANS_DIS); + } + DBG_Trace(DBG_LEVEL6, "WMD_BRD_Monitor - Middle ****** \n"); + GetHWRegs(resources.dwPrmBase, resources.dwCmBase); + status = run_IdleBoot(resources.dwPrmBase, resources.dwCmBase, + resources.dwSysCtrlBase); + if (DSP_SUCCEEDED(status)) { + /* set the device state to IDLE */ + pDevContext->dwBrdState = BRD_IDLE; + + } +error_return: + DBG_Trace(DBG_LEVEL6, "WMD_BRD_Monitor - End ****** \n"); + GetHWRegs(resources.dwPrmBase, resources.dwCmBase); + return status; +} + +/* + * ======== WMD_BRD_Read ======== + * purpose: + * Reads buffers for DSP memory. + */ +static DSP_STATUS WMD_BRD_Read(struct WMD_DEV_CONTEXT *hDevContext, + OUT u8 *pbHostBuf, u32 dwDSPAddr, + u32 ulNumBytes, u32 ulMemType) +{ + DSP_STATUS status = DSP_SOK; + struct WMD_DEV_CONTEXT *pDevContext = hDevContext; + u32 offset; + u32 dspBaseAddr = hDevContext->dwDspBaseAddr; + + DBG_Trace(DBG_ENTER, "WMD_BRD_Read, pDevContext: 0x%x\n\t\tpbHostBuf:" + " 0x%x\n\t\tdwDSPAddr: 0x%x\n\t\tulNumBytes: 0x%x\n\t\t" + "ulMemType: 0x%x\n", pDevContext, pbHostBuf, + dwDSPAddr, ulNumBytes, ulMemType); + if (dwDSPAddr < pDevContext->dwDSPStartAdd) { + DBG_Trace(DBG_LEVEL7, + "WMD_BRD_Read: DSP address < start address \n "); + status = DSP_EFAIL; + return status; + } + /* change here to account for the 3 bands of the DSP internal memory */ + if ((dwDSPAddr - pDevContext->dwDSPStartAdd) < + pDevContext->dwInternalSize) { + offset = dwDSPAddr - pDevContext->dwDSPStartAdd; + } else { + DBG_Trace(DBG_LEVEL1, + "**** Reading From external memory **** \n "); + status = ReadExtDspData(pDevContext, pbHostBuf, dwDSPAddr, + ulNumBytes, ulMemType); + return status; + } + /* copy the data from DSP memory, */ + memcpy(pbHostBuf, (void *)(dspBaseAddr + offset), ulNumBytes); + return status; +} + +/* + * ======== WMD_BRD_SetState ======== + * purpose: + * This routine updates the Board status. + */ +static DSP_STATUS WMD_BRD_SetState(struct WMD_DEV_CONTEXT *hDevContext, + u32 ulBrdState) +{ + DSP_STATUS status = DSP_SOK; + struct WMD_DEV_CONTEXT *pDevContext = hDevContext; + + DBG_Trace(DBG_ENTER, "WMD_BRD_SetState: Board State: 0x%x \n", + ulBrdState); + pDevContext->dwBrdState = ulBrdState; + return status; +} + +/* + * ======== WMD_BRD_Start ======== + * purpose: + * Initializes DSP MMU and Starts DSP. + * + * Preconditions: + * a) DSP domain is 'ACTIVE'. + * b) DSP_RST1 is asserted. + * b) DSP_RST2 is released. + */ +static DSP_STATUS WMD_BRD_Start(struct WMD_DEV_CONTEXT *hDevContext, + u32 dwDSPAddr) +{ + DSP_STATUS status = DSP_SOK; + struct WMD_DEV_CONTEXT *pDevContext = hDevContext; + u32 dwSyncAddr = 0; + u32 ulShmBase; /* Gpp Phys SM base addr(byte) */ + u32 ulShmBaseVirt; /* Dsp Virt SM base addr */ + u32 ulTLBBaseVirt; /* Base of MMU TLB entry */ + u32 ulShmOffsetVirt; /* offset of ulShmBaseVirt from ulTLBBaseVirt */ + s32 iEntryNdx; + s32 itmpEntryNdx = 0; /* DSP-MMU TLB entry base address */ + struct CFG_HOSTRES resources; + u32 temp; + u32 ulDspClkRate; + u32 ulDspClkAddr; + u32 ulBiosGpTimer; + u32 uClkCmd; + struct IO_MGR *hIOMgr; + u32 ulLoadMonitorTimer; + u32 extClkId = 0; + u32 tmpIndex; + u32 clkIdIndex = MBX_PM_MAX_RESOURCES; + + DBG_Trace(DBG_ENTER, "Entering WMD_BRD_Start:\n hDevContext: 0x%x\n\t " + "dwDSPAddr: 0x%x\n", hDevContext, dwDSPAddr); + + /* The device context contains all the mmu setup info from when the + * last dsp base image was loaded. The first entry is always + * SHMMEM base. */ + /* Get SHM_BEG - convert to byte address */ + (void) DEV_GetSymbol(pDevContext->hDevObject, SHMBASENAME, + &ulShmBaseVirt); + ulShmBaseVirt *= DSPWORDSIZE; + DBC_Assert(ulShmBaseVirt != 0); + /* DSP Virtual address */ + ulTLBBaseVirt = pDevContext->aTLBEntry[0].ulDspVa; + DBC_Assert(ulTLBBaseVirt <= ulShmBaseVirt); + ulShmOffsetVirt = ulShmBaseVirt - (ulTLBBaseVirt * DSPWORDSIZE); + /* Kernel logical address */ + ulShmBase = pDevContext->aTLBEntry[0].ulGppVa + ulShmOffsetVirt; + + DBC_Assert(ulShmBase != 0); + /* 2nd wd is used as sync field */ + dwSyncAddr = ulShmBase + SHMSYNCOFFSET; + /* Write a signature into the SHM base + offset; this will + * get cleared when the DSP program starts. */ + if ((ulShmBaseVirt == 0) || (ulShmBase == 0)) { + DBG_Trace(DBG_LEVEL6, "WMD_BRD_Start: Illegal SM base\n"); + status = DSP_EFAIL; + } else + *((volatile u32 *)dwSyncAddr) = 0xffffffff; + + if (DSP_SUCCEEDED(status)) { + status = CFG_GetHostResources( + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), + &resources); + /* Assert RST1 i.e only the RST only for DSP megacell */ + /* HW_RST_Reset(resources.dwPrcmBase, HW_RST1_IVA2);*/ + if (DSP_SUCCEEDED(status)) { + HW_RST_Reset(resources.dwPrmBase, HW_RST1_IVA2); + if (dsp_debug) { + /* Set the bootmode to self loop */ + DBG_Trace(DBG_LEVEL7, + "Set boot mode to self loop" + " for IVA2 Device\n"); + HW_DSPSS_BootModeSet(resources.dwSysCtrlBase, + HW_DSPSYSC_SELFLOOPBOOT, dwDSPAddr); + } else { + /* Set the bootmode to '0' - direct boot */ + DBG_Trace(DBG_LEVEL7, + "Set boot mode to direct" + " boot for IVA2 Device \n"); + HW_DSPSS_BootModeSet(resources.dwSysCtrlBase, + HW_DSPSYSC_DIRECTBOOT, dwDSPAddr); + } + } + } + if (DSP_SUCCEEDED(status)) { + /* Reset and Unreset the RST2, so that BOOTADDR is copied to + * IVA2 SYSC register */ + HW_RST_Reset(resources.dwPrmBase, HW_RST2_IVA2); + udelay(100); + HW_RST_UnReset(resources.dwPrmBase, HW_RST2_IVA2); + udelay(100); + DBG_Trace(DBG_LEVEL6, "WMD_BRD_Start 0 ****** \n"); + GetHWRegs(resources.dwPrmBase, resources.dwCmBase); + /* Disbale the DSP MMU */ + HW_MMU_Disable(resources.dwDmmuBase); + /* Disable TWL */ + HW_MMU_TWLDisable(resources.dwDmmuBase); + + /* Only make TLB entry if both addresses are non-zero */ + for (iEntryNdx = 0; iEntryNdx < WMDIOCTL_NUMOFMMUTLB; + iEntryNdx++) { + if ((pDevContext->aTLBEntry[iEntryNdx].ulGppPa != 0) && + (pDevContext->aTLBEntry[iEntryNdx].ulDspVa != 0)) { + DBG_Trace(DBG_LEVEL4, "** (proc) MMU %d GppPa:" + " 0x%x DspVa 0x%x Size 0x%x\n", + itmpEntryNdx, + pDevContext->aTLBEntry[iEntryNdx].ulGppPa, + pDevContext->aTLBEntry[iEntryNdx].ulDspVa, + pDevContext->aTLBEntry[iEntryNdx].ulSize); + configureDspMmu(pDevContext, + pDevContext->aTLBEntry[iEntryNdx].ulGppPa, + pDevContext->aTLBEntry[iEntryNdx].ulDspVa * + DSPWORDSIZE, + pDevContext->aTLBEntry[iEntryNdx].ulSize, + itmpEntryNdx, + pDevContext->aTLBEntry[iEntryNdx].endianism, + pDevContext->aTLBEntry[iEntryNdx].elemSize, + pDevContext->aTLBEntry[iEntryNdx]. + mixedMode); + itmpEntryNdx++; + } + } /* end for */ + } + + /* Lock the above TLB entries and get the BIOS and load monitor timer + * information*/ + if (DSP_SUCCEEDED(status)) { + HW_MMU_NumLockedSet(resources.dwDmmuBase, itmpEntryNdx); + HW_MMU_VictimNumSet(resources.dwDmmuBase, itmpEntryNdx); + HW_MMU_TTBSet(resources.dwDmmuBase, + pDevContext->pPtAttrs->L1BasePa); + HW_MMU_TWLEnable(resources.dwDmmuBase); + /* Enable the SmartIdle and AutoIdle bit for MMU_SYSCONFIG */ + + temp = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwDmmuBase) + 0x10)); + temp = (temp & 0xFFFFFFEF) | 0x11; + *((REG_UWORD32 *) ((u32) (resources.dwDmmuBase) + 0x10)) = + (u32) temp; + + /* Let the DSP MMU run */ + HW_MMU_Enable(resources.dwDmmuBase); + + /* Enable the BIOS clock */ + (void)DEV_GetSymbol(pDevContext->hDevObject, + BRIDGEINIT_BIOSGPTIMER, + &ulBiosGpTimer); + DBG_Trace(DBG_LEVEL7, "BIOS GPTimer : 0x%x\n", ulBiosGpTimer); + (void)DEV_GetSymbol(pDevContext->hDevObject, + BRIDGEINIT_LOADMON_GPTIMER, + &ulLoadMonitorTimer); + DBG_Trace(DBG_LEVEL7, "Load Monitor Timer : 0x%x\n", + ulLoadMonitorTimer); + } + + if (DSP_SUCCEEDED(status)) { + if (ulLoadMonitorTimer != 0xFFFF) { + uClkCmd = (BPWR_DisableClock << MBX_PM_CLK_CMDSHIFT) | + ulLoadMonitorTimer; + DBG_Trace(DBG_LEVEL7, + "encoded LoadMonitor cmd for Disable: 0x%x\n", + uClkCmd); + DSPPeripheralClkCtrl(pDevContext, &uClkCmd); + + extClkId = uClkCmd & MBX_PM_CLK_IDMASK; + for (tmpIndex = 0; tmpIndex < MBX_PM_MAX_RESOURCES; + tmpIndex++) { + if (extClkId == BPWR_CLKID[tmpIndex]) { + clkIdIndex = tmpIndex; + break; + } + } + + if (clkIdIndex < MBX_PM_MAX_RESOURCES) + status = CLK_Set_32KHz( + BPWR_Clks[clkIdIndex].funClk); + else + status = DSP_EFAIL; + + if (DSP_FAILED(status)) { + DBG_Trace(DBG_LEVEL7, " Error while setting" + "LM Timer to 32KHz\n"); + } + uClkCmd = (BPWR_EnableClock << MBX_PM_CLK_CMDSHIFT) | + ulLoadMonitorTimer; + DBG_Trace(DBG_LEVEL7, + "encoded LoadMonitor cmd for Enable : 0x%x\n", + uClkCmd); + DSPPeripheralClkCtrl(pDevContext, &uClkCmd); + + } else { + DBG_Trace(DBG_LEVEL7, + "Not able to get the symbol for Load " + "Monitor Timer\n"); + } + } + + if (DSP_SUCCEEDED(status)) { + if (ulBiosGpTimer != 0xFFFF) { + uClkCmd = (BPWR_DisableClock << MBX_PM_CLK_CMDSHIFT) | + ulBiosGpTimer; + DBG_Trace(DBG_LEVEL7, "encoded BIOS GPTimer cmd for" + "Disable: 0x%x\n", uClkCmd); + DSPPeripheralClkCtrl(pDevContext, &uClkCmd); + + extClkId = uClkCmd & MBX_PM_CLK_IDMASK; + + for (tmpIndex = 0; tmpIndex < MBX_PM_MAX_RESOURCES; + tmpIndex++) { + if (extClkId == BPWR_CLKID[tmpIndex]) { + clkIdIndex = tmpIndex; + break; + } + } + + if (clkIdIndex < MBX_PM_MAX_RESOURCES) + status = CLK_Set_32KHz( + BPWR_Clks[clkIdIndex].funClk); + else + status = DSP_EFAIL; + + if (DSP_FAILED(status)) { + DBG_Trace(DBG_LEVEL7, + " Error while setting BIOS Timer to 32KHz\n"); + } + + uClkCmd = (BPWR_EnableClock << MBX_PM_CLK_CMDSHIFT) | + ulBiosGpTimer; + DBG_Trace(DBG_LEVEL7, "encoded BIOS GPTimer cmd :" + "0x%x\n", uClkCmd); + DSPPeripheralClkCtrl(pDevContext, &uClkCmd); + + } else { + DBG_Trace(DBG_LEVEL7, + "Not able to get the symbol for BIOS Timer\n"); + } + } + + if (DSP_SUCCEEDED(status)) { + /* Set the DSP clock rate */ + (void)DEV_GetSymbol(pDevContext->hDevObject, + "_BRIDGEINIT_DSP_FREQ", &ulDspClkAddr); + /*Set Autoidle Mode for IVA2 PLL */ + temp = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwCmBase) + 0x34)); + temp = (temp & 0xFFFFFFFE) | 0x1; + *((REG_UWORD32 *) ((u32) (resources.dwCmBase) + 0x34)) = + (u32) temp; + DBG_Trace(DBG_LEVEL5, "WMD_BRD_Start: _BRIDGE_DSP_FREQ Addr:" + "0x%x \n", ulDspClkAddr); + if ((unsigned int *)ulDspClkAddr != NULL) { + /* Get the clock rate */ + status = CLK_GetRate(SERVICESCLK_iva2_ck, + &ulDspClkRate); + DBG_Trace(DBG_LEVEL5, + "WMD_BRD_Start: DSP clock rate (KHZ): 0x%x \n", + ulDspClkRate); + (void)WMD_BRD_Write(pDevContext, (u8 *)&ulDspClkRate, + ulDspClkAddr, sizeof(u32), 0); + } +/*PM_IVA2GRPSEL_PER = 0xC0;*/ + temp = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerPmBase) + 0xA8)); + temp = (temp & 0xFFFFFF30) | 0xC0; + *((REG_UWORD32 *) ((u32) (resources.dwPerPmBase) + 0xA8)) = + (u32) temp; + +/*PM_MPUGRPSEL_PER &= 0xFFFFFF3F;*/ + temp = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerPmBase) + 0xA4)); + temp = (temp & 0xFFFFFF3F); + *((REG_UWORD32 *) ((u32) (resources.dwPerPmBase) + 0xA4)) = + (u32) temp; +/*CM_SLEEPDEP_PER |= 0x04;*/ + temp = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerBase) + 0x44)); + temp = (temp & 0xFFFFFFFB) | 0x04; + *((REG_UWORD32 *) ((u32) (resources.dwPerBase) + 0x44)) = + (u32) temp; + +/*CM_CLKSTCTRL_IVA2 = 0x00000003 -To Allow automatic transitions*/ + temp = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwCmBase) + 0x48)); + temp = (temp & 0xFFFFFFFC) | 0x03; + *((REG_UWORD32 *) ((u32) (resources.dwCmBase) + 0x48)) = + (u32) temp; + + + /* Enable Mailbox events and also drain any pending + * stale messages */ + (void)CHNLSM_EnableInterrupt(pDevContext); + } + + if (DSP_SUCCEEDED(status)) { + HW_RSTCTRL_RegGet(resources.dwPrmBase, HW_RST1_IVA2, &temp); + DBG_Trace(DBG_LEVEL7, "BRD_Start: RM_RSTCTRL_DSP = 0x%x \n", + temp); + HW_RSTST_RegGet(resources.dwPrmBase, HW_RST1_IVA2, &temp); + DBG_Trace(DBG_LEVEL7, "BRD_Start0: RM_RSTST_DSP = 0x%x \n", + temp); + + /* Let DSP go */ + DBG_Trace(DBG_LEVEL7, "Unreset, WMD_BRD_Start\n"); + /* Enable DSP MMU Interrupts */ + HW_MMU_EventEnable(resources.dwDmmuBase, + HW_MMU_ALL_INTERRUPTS); + /* release the RST1, DSP starts executing now .. */ + HW_RST_UnReset(resources.dwPrmBase, HW_RST1_IVA2); + + HW_RSTST_RegGet(resources.dwPrmBase, HW_RST1_IVA2, &temp); + DBG_Trace(DBG_LEVEL7, "BRD_Start: RM_RSTST_DSP = 0x%x \n", + temp); + HW_RSTCTRL_RegGet(resources.dwPrmBase, HW_RST1_IVA2, &temp); + DBG_Trace(DBG_LEVEL5, "WMD_BRD_Start: CM_RSTCTRL_DSP: 0x%x \n", + temp); + DBG_Trace(DBG_LEVEL7, "Driver waiting for Sync @ 0x%x \n", + dwSyncAddr); + DBG_Trace(DBG_LEVEL7, "DSP c_int00 Address = 0x%x \n", + dwDSPAddr); + if (dsp_debug) + while (*((volatile u16 *)dwSyncAddr)) + ;; + } + + if (DSP_SUCCEEDED(status)) { + /* Wait for DSP to clear word in shared memory */ + /* Read the Location */ + if (!WaitForStart(pDevContext, dwSyncAddr)) { + status = WMD_E_TIMEOUT; + DBG_Trace(DBG_LEVEL7, + "WMD_BRD_Start Failed to Synchronize\n"); + } + status = DEV_GetIOMgr(pDevContext->hDevObject, &hIOMgr); + if (DSP_SUCCEEDED(status)) { + IO_SHMsetting(hIOMgr, SHM_OPPINFO, NULL); + DBG_Trace(DBG_LEVEL7, + "WMD_BRD_Start: OPP information initialzed\n"); + /* Write the synchronization bit to indicate the + * completion of OPP table update to DSP + */ + *((volatile u32 *)dwSyncAddr) = 0XCAFECAFE; + } + if (DSP_SUCCEEDED(status)) { + /* update board state */ + pDevContext->dwBrdState = BRD_RUNNING; + /* (void)CHNLSM_EnableInterrupt(pDevContext);*/ + DBG_Trace(DBG_LEVEL7, "Device Started \n "); + } else { + pDevContext->dwBrdState = BRD_UNKNOWN; + DBG_Trace(DBG_LEVEL7, "Device not Started \n "); + } + } + return status; +} + +/* + * ======== WMD_BRD_Stop ======== + * purpose: + * Puts DSP in self loop. + * + * Preconditions : + * a) None + */ +static DSP_STATUS WMD_BRD_Stop(struct WMD_DEV_CONTEXT *hDevContext) +{ + DSP_STATUS status = DSP_SOK; + struct WMD_DEV_CONTEXT *pDevContext = hDevContext; + struct CFG_HOSTRES resources; + struct PgTableAttrs *pPtAttrs; + u32 dspPwrState; + DSP_STATUS clk_status; + + DBG_Trace(DBG_ENTER, "Entering WMD_BRD_Stop:\nhDevContext: 0x%x\n", + hDevContext); + + /* Disable the mail box interrupts */ + (void)CHNLSM_DisableInterrupt(pDevContext); + + if (pDevContext->dwBrdState == BRD_STOPPED) + return status; + + /* as per TRM, it is advised to first drive the IVA2 to 'Standby' mode, + * before turning off the clocks.. This is to ensure that there are no + * pending L3 or other transactons from IVA2 */ + status = CFG_GetHostResources( + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), + &resources); + if (DSP_FAILED(status)) { + DBG_Trace(DBG_LEVEL7, + "WMD_BRD_Stop: Get Host resources failed \n"); + DBG_Trace(DBG_LEVEL1, "Device Stopp failed \n "); + return DSP_EFAIL; + } + + HW_PWRST_IVA2RegGet(resources.dwPrmBase, &dspPwrState); + if (dspPwrState != HW_PWR_STATE_OFF) { + + CHNLSM_InterruptDSP2(pDevContext, MBX_PM_DSPIDLE); + + mdelay(10); + + GetHWRegs(resources.dwPrmBase, resources.dwCmBase); + + run_IdleBoot(resources.dwPrmBase, resources.dwCmBase, + resources.dwSysCtrlBase); + + udelay(50); + + clk_status = CLK_Disable(SERVICESCLK_iva2_ck); + if (DSP_FAILED(clk_status)) { + DBG_Trace(DBG_LEVEL6, + "\n WMD_BRD_Stop: CLK_Disable failed " + "for iva2_fck\n"); + } + /* IVA2 is not in OFF state */ + /* Set PM_PWSTCTRL_IVA2 to OFF */ + HW_PWR_IVA2PowerStateSet(resources.dwPrmBase, + HW_PWR_DOMAIN_DSP, + HW_PWR_STATE_OFF); + /* Set the SW supervised state transition for Sleep */ + HW_PWR_CLKCTRL_IVA2RegSet(resources.dwCmBase, + HW_SW_SUP_SLEEP); + } else { + clk_status = CLK_Disable(SERVICESCLK_iva2_ck); + if (DSP_FAILED(clk_status)) { + DBG_Trace(DBG_LEVEL6, + "\n WMD_BRD_Stop: Else loop CLK_Disable failed" + " for iva2_fck\n"); + } + } + udelay(10); + /* Release the Ext Base virtual Address as the next DSP Program + * may have a different load address */ + if (pDevContext->dwDspExtBaseAddr) + pDevContext->dwDspExtBaseAddr = 0; + + pDevContext->dwBrdState = BRD_STOPPED; /* update board state */ + DBG_Trace(DBG_LEVEL1, "Device Stopped \n "); + /* This is a good place to clear the MMU page tables as well */ + if (pDevContext->pPtAttrs) { + pPtAttrs = pDevContext->pPtAttrs; + memset((u8 *) pPtAttrs->L1BaseVa, 0x00, pPtAttrs->L1size); + memset((u8 *) pPtAttrs->L2BaseVa, 0x00, pPtAttrs->L2size); + memset((u8 *) pPtAttrs->pgInfo, 0x00, + (pPtAttrs->L2NumPages * sizeof(struct PageInfo))); + } + + DBG_Trace(DBG_LEVEL6, "WMD_BRD_Stop - End ****** \n"); + + return status; +} + + +/* + * ======== WMD_BRD_Delete ======== + * purpose: + * Puts DSP in Low power mode + * + * Preconditions : + * a) None + */ +static DSP_STATUS WMD_BRD_Delete(struct WMD_DEV_CONTEXT *hDevContext) +{ + DSP_STATUS status = DSP_SOK; + struct WMD_DEV_CONTEXT *pDevContext = hDevContext; + struct CFG_HOSTRES resources; + struct PgTableAttrs *pPtAttrs; + DSP_STATUS clk_status; + + DBG_Trace(DBG_ENTER, "Entering WMD_BRD_Delete:\nhDevContext: 0x%x\n", + hDevContext); + + /* Disable the mail box interrupts */ + (void) CHNLSM_DisableInterrupt(pDevContext); + + if (pDevContext->dwBrdState == BRD_STOPPED) + return status; + + /* as per TRM, it is advised to first drive + * the IVA2 to 'Standby' mode, before turning off the clocks.. This is + * to ensure that there are no pending L3 or other transactons from + * IVA2 */ + status = CFG_GetHostResources( + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); + if (DSP_FAILED(status)) { + DBG_Trace(DBG_LEVEL7, + "WMD_BRD_Stop: Get Host resources failed \n"); + DBG_Trace(DBG_LEVEL1, "Device Delete failed \n "); + return DSP_EFAIL; + } + status = SleepDSP(pDevContext, PWR_EMERGENCYDEEPSLEEP, NULL); + clk_status = CLK_Disable(SERVICESCLK_iva2_ck); + if (DSP_FAILED(clk_status)) { + DBG_Trace(DBG_LEVEL6, "\n WMD_BRD_Stop: CLK_Disable failed for" + " iva2_fck\n"); + } + /* Release the Ext Base virtual Address as the next DSP Program + * may have a different load address */ + if (pDevContext->dwDspExtBaseAddr) + pDevContext->dwDspExtBaseAddr = 0; + + pDevContext->dwBrdState = BRD_STOPPED; /* update board state */ + DBG_Trace(DBG_LEVEL1, "Device Stopped \n "); + /* This is a good place to clear the MMU page tables as well */ + if (pDevContext->pPtAttrs) { + pPtAttrs = pDevContext->pPtAttrs; + memset((u8 *)pPtAttrs->L1BaseVa, 0x00, pPtAttrs->L1size); + memset((u8 *)pPtAttrs->L2BaseVa, 0x00, pPtAttrs->L2size); + memset((u8 *)pPtAttrs->pgInfo, 0x00, + (pPtAttrs->L2NumPages * sizeof(struct PageInfo))); + } + DBG_Trace(DBG_LEVEL6, "WMD_BRD_Stop - End ****** \n"); + return status; +} + + +/* + * ======== WMD_BRD_Status ======== + * Returns the board status. + */ +static DSP_STATUS WMD_BRD_Status(struct WMD_DEV_CONTEXT *hDevContext, + OUT BRD_STATUS *pdwState) +{ + struct WMD_DEV_CONTEXT *pDevContext = hDevContext; + *pdwState = pDevContext->dwBrdState; + return DSP_SOK; +} + +/* + * ======== WMD_BRD_Write ======== + * Copies the buffers to DSP internal or external memory. + */ +static DSP_STATUS WMD_BRD_Write(struct WMD_DEV_CONTEXT *hDevContext, + IN u8 *pbHostBuf, u32 dwDSPAddr, + u32 ulNumBytes, u32 ulMemType) +{ + DSP_STATUS status = DSP_SOK; + struct WMD_DEV_CONTEXT *pDevContext = hDevContext; + + DBG_Trace(DBG_ENTER, "WMD_BRD_Write, pDevContext: 0x%x\n\t\t " + "pbHostBuf: 0x%x\n\t\tdwDSPAddr: 0x%x\n\t\tulNumBytes: " + "0x%x\n \t\t ulMemtype: 0x%x\n", pDevContext, pbHostBuf, + dwDSPAddr, ulNumBytes, ulMemType); + if (dwDSPAddr < pDevContext->dwDSPStartAdd) { + DBG_Trace(DBG_LEVEL7, + "WMD_BRD_Write: DSP address < start address \n "); + status = DSP_EFAIL; + return status; + } + if ((dwDSPAddr - pDevContext->dwDSPStartAdd) < + pDevContext->dwInternalSize) { + status = WriteDspData(hDevContext, pbHostBuf, dwDSPAddr, + ulNumBytes, ulMemType); + } else { + status = WriteExtDspData(pDevContext, pbHostBuf, dwDSPAddr, + ulNumBytes, ulMemType, false); + } + + DBG_Trace(DBG_ENTER, "WMD_BRD_Write, memcopy : DspLogicAddr=0x%x \n", + pDevContext->dwDspBaseAddr); + return status; +} + +/* + * ======== WMD_DEV_Create ======== + * Creates a driver object. Puts DSP in self loop. + */ +static DSP_STATUS WMD_DEV_Create(OUT struct WMD_DEV_CONTEXT **ppDevContext, + struct DEV_OBJECT *hDevObject, + IN CONST struct CFG_HOSTRES *pConfig, + IN CONST struct CFG_DSPRES *pDspConfig) +{ + DSP_STATUS status = DSP_SOK; + struct WMD_DEV_CONTEXT *pDevContext = NULL; + s32 iEntryNdx; + s32 tcWordSwap; + u32 tcWordSwapSize = sizeof(tcWordSwap); + struct CFG_HOSTRES resources; + struct PgTableAttrs *pPtAttrs; + u32 pg_tbl_pa; + u32 pg_tbl_va; + u32 align_size; + + DBG_Trace(DBG_ENTER, "WMD_DEV_Create, ppDevContext: 0x%x\n\t\t " + "hDevObject: 0x%x\n\t\tpConfig: 0x%x\n\t\tpDspConfig: 0x%x\n", + ppDevContext, hDevObject, pConfig, pDspConfig); + /* Allocate and initialize a data structure to contain the mini driver + * state, which becomes the context for later calls into this WMD. */ + pDevContext = MEM_Calloc(sizeof(struct WMD_DEV_CONTEXT), MEM_NONPAGED); + if (!pDevContext) { + DBG_Trace(DBG_ENTER, "Failed to allocate mem \n"); + status = DSP_EMEMORY; + goto func_end; + } + status = CFG_GetHostResources( + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); + if (DSP_FAILED(status)) { + DBG_Trace(DBG_ENTER, "Failed to get host resources \n"); + status = DSP_EMEMORY; + goto func_end; + } + + pDevContext->dwDSPStartAdd = (u32)OMAP_GEM_BASE; + pDevContext->dwSelfLoop = (u32)NULL; + pDevContext->uDspPerClks = 0; + pDevContext->dwInternalSize = OMAP_DSP_SIZE; + /* Clear dev context MMU table entries. + * These get set on WMD_BRD_IOCTL() call after program loaded. */ + for (iEntryNdx = 0; iEntryNdx < WMDIOCTL_NUMOFMMUTLB; iEntryNdx++) { + pDevContext->aTLBEntry[iEntryNdx].ulGppPa = + pDevContext->aTLBEntry[iEntryNdx].ulDspVa = 0; + } + pDevContext->numTLBEntries = 0; + pDevContext->dwDspBaseAddr = (u32)MEM_LinearAddress((void *) + (pConfig->dwMemBase[3]), pConfig->dwMemLength[3]); + if (!pDevContext->dwDspBaseAddr) { + status = DSP_EFAIL; + DBG_Trace(DBG_LEVEL7, + "WMD_DEV_Create: failed to Map the API memory\n"); + } + pPtAttrs = MEM_Calloc(sizeof(struct PgTableAttrs), MEM_NONPAGED); + if (pPtAttrs != NULL) { + /* Assuming that we use only DSP's memory map + * until 0x4000:0000 , we would need only 1024 + * L1 enties i.e L1 size = 4K */ + pPtAttrs->L1size = 0x1000; + align_size = pPtAttrs->L1size; + /* Align sizes are expected to be power of 2 */ + /* we like to get aligned on L1 table size */ + pg_tbl_va = (u32)MEM_AllocPhysMem(pPtAttrs->L1size, + align_size, &pg_tbl_pa); + /* Check if the PA is aligned for us */ + if ((pg_tbl_pa) & (align_size-1)) { + /* PA not aligned to page table size , + * try with more allocation and align */ + MEM_FreePhysMem((void *)pg_tbl_va, pg_tbl_pa, pPtAttrs->L1size); + /* we like to get aligned on L1 table size */ + pg_tbl_va = (u32) MEM_AllocPhysMem((pPtAttrs->L1size)*2, + align_size, &pg_tbl_pa); + /* We should be able to get aligned table now */ + pPtAttrs->L1TblAllocPa = pg_tbl_pa; + pPtAttrs->L1TblAllocVa = pg_tbl_va; + pPtAttrs->L1TblAllocSz = pPtAttrs->L1size * 2; + /* Align the PA to the next 'align' boundary */ + pPtAttrs->L1BasePa = ((pg_tbl_pa) + (align_size-1)) & + (~(align_size-1)); + pPtAttrs->L1BaseVa = pg_tbl_va + (pPtAttrs->L1BasePa - + pg_tbl_pa); + } else { + /* We got aligned PA, cool */ + pPtAttrs->L1TblAllocPa = pg_tbl_pa; + pPtAttrs->L1TblAllocVa = pg_tbl_va; + pPtAttrs->L1TblAllocSz = pPtAttrs->L1size; + pPtAttrs->L1BasePa = pg_tbl_pa; + pPtAttrs->L1BaseVa = pg_tbl_va; + } + if (pPtAttrs->L1BaseVa) + memset((u8 *)pPtAttrs->L1BaseVa, 0x00, pPtAttrs->L1size); + + /* number of L2 page tables = DMM pool used + SHMMEM +EXTMEM + + * L4 pages */ + pPtAttrs->L2NumPages = ((DMMPOOLSIZE >> 20) + 6); + pPtAttrs->L2size = HW_MMU_COARSE_PAGE_SIZE * + pPtAttrs->L2NumPages; + align_size = 4; /* Make it u32 aligned */ + /* we like to get aligned on L1 table size */ + pg_tbl_va = (u32)MEM_AllocPhysMem(pPtAttrs->L2size, + align_size, &pg_tbl_pa); + pPtAttrs->L2TblAllocPa = pg_tbl_pa; + pPtAttrs->L2TblAllocVa = pg_tbl_va; + pPtAttrs->L2TblAllocSz = pPtAttrs->L2size; + pPtAttrs->L2BasePa = pg_tbl_pa; + pPtAttrs->L2BaseVa = pg_tbl_va; + + if (pPtAttrs->L2BaseVa) + memset((u8 *)pPtAttrs->L2BaseVa, 0x00, pPtAttrs->L2size); + + pPtAttrs->pgInfo = MEM_Calloc(pPtAttrs->L2NumPages * + sizeof(struct PageInfo), MEM_NONPAGED); + DBG_Trace(DBG_LEVEL1, "L1 pa %x, va %x, size %x\n L2 pa %x, va " + "%x, size %x\n", pPtAttrs->L1BasePa, + pPtAttrs->L1BaseVa, pPtAttrs->L1size, + pPtAttrs->L2BasePa, pPtAttrs->L2BaseVa, + pPtAttrs->L2size); + DBG_Trace(DBG_LEVEL1, "pPtAttrs %x L2 NumPages %x pgInfo %x\n", + pPtAttrs, pPtAttrs->L2NumPages, pPtAttrs->pgInfo); + } + if ((pPtAttrs != NULL) && (pPtAttrs->L1BaseVa != 0) && + (pPtAttrs->L2BaseVa != 0) && (pPtAttrs->pgInfo != NULL)) + pDevContext->pPtAttrs = pPtAttrs; + else + status = DSP_EMEMORY; + + if (DSP_SUCCEEDED(status)) + status = SYNC_InitializeCS(&pPtAttrs->hCSObj); + + if (DSP_SUCCEEDED(status)) { + /* Set the Endianism Register */ /* Need to set this */ + /* Retrieve the TC u16 SWAP Option */ + status = REG_GetValue(NULL, CURRENTCONFIG, TCWORDSWAP, + (u8 *)&tcWordSwap, &tcWordSwapSize); + /* Save the value */ + pDevContext->tcWordSwapOn = tcWordSwap; + } + if (DSP_SUCCEEDED(status)) { + /* Set the Clock Divisor for the DSP module */ + DBG_Trace(DBG_LEVEL7, "WMD_DEV_create:Reset mail box and " + "enable the clock \n"); + status = CLK_Enable(SERVICESCLK_mailbox_ick); + if (DSP_FAILED(status)) { + DBG_Trace(DBG_LEVEL7, + "WMD_DEV_create:Reset mail box and " + "enable the clock Fail\n"); + } + udelay(5); + /* 24xx-Linux MMU address is obtained from the host + * resources struct */ + pDevContext->dwDSPMmuBase = resources.dwDmmuBase; + } + if (DSP_SUCCEEDED(status)) { + pDevContext->hDevObject = hDevObject; + pDevContext->ulIntMask = 0; + /* Store current board state. */ + pDevContext->dwBrdState = BRD_STOPPED; + /* Return this ptr to our device state to the WCD for storage:*/ + *ppDevContext = pDevContext; + DBG_Trace(DBG_ENTER, "Device Created \n"); + } else { + if (pPtAttrs != NULL) { + if (pPtAttrs->hCSObj) + SYNC_DeleteCS(pPtAttrs->hCSObj); + + if (pPtAttrs->pgInfo) + MEM_Free(pPtAttrs->pgInfo); + + if (pPtAttrs->L2TblAllocVa) { + MEM_FreePhysMem((void *)pPtAttrs->L2TblAllocVa, + pPtAttrs->L2TblAllocPa, + pPtAttrs->L2TblAllocSz); + } + if (pPtAttrs->L1TblAllocVa) { + MEM_FreePhysMem((void *)pPtAttrs->L1TblAllocVa, + pPtAttrs->L1TblAllocPa, + pPtAttrs->L1TblAllocSz); + } + } + if (pPtAttrs) + MEM_Free(pPtAttrs); + + if (pDevContext) + MEM_Free(pDevContext); + + DBG_Trace(DBG_LEVEL7, + "WMD_DEV_Create Error Device not created\n"); + } +func_end: + return status; +} + +/* + * ======== WMD_DEV_Ctrl ======== + * Receives device specific commands. + */ +static DSP_STATUS WMD_DEV_Ctrl(struct WMD_DEV_CONTEXT *pDevContext, u32 dwCmd, + IN OUT void *pArgs) +{ + DSP_STATUS status = DSP_SOK; + struct WMDIOCTL_EXTPROC *paExtProc = (struct WMDIOCTL_EXTPROC *)pArgs; + s32 ndx; + + DBG_Trace(DBG_ENTER, "WMD_DEV_Ctrl, pDevContext: 0x%x\n\t\t dwCmd: " + "0x%x\n\t\tpArgs: 0x%x\n", pDevContext, dwCmd, pArgs); + switch (dwCmd) { + case WMDIOCTL_CHNLREAD: + break; + case WMDIOCTL_CHNLWRITE: + break; + case WMDIOCTL_SETMMUCONFIG: + /* store away dsp-mmu setup values for later use */ + for (ndx = 0; ndx < WMDIOCTL_NUMOFMMUTLB; ndx++, paExtProc++) + pDevContext->aTLBEntry[ndx] = *paExtProc; + + break; + case WMDIOCTL_DEEPSLEEP: + case WMDIOCTL_EMERGENCYSLEEP: + /* Currently only DSP Idle is supported Need to update for + * later releases */ + DBG_Trace(DBG_LEVEL5, "WMDIOCTL_DEEPSLEEP\n"); + status = SleepDSP(pDevContext, PWR_DEEPSLEEP, pArgs); + break; + case WMDIOCTL_WAKEUP: + DBG_Trace(DBG_LEVEL5, "WMDIOCTL_WAKEUP\n"); + status = WakeDSP(pDevContext, pArgs); + break; + case WMDIOCTL_CLK_CTRL: + DBG_Trace(DBG_LEVEL5, "WMDIOCTL_CLK_CTRL\n"); + status = DSP_SOK; + /* Looking For Baseport Fix for Clocks */ + status = DSPPeripheralClkCtrl(pDevContext, pArgs); + break; + case WMDIOCTL_PWR_HIBERNATE: + DBG_Trace(DBG_LEVEL5, "WMDIOCTL_PWR_HIBERNATE\n"); + status = handle_hibernation_fromDSP(pDevContext); + break; + case WMDIOCTL_PRESCALE_NOTIFY: + DBG_Trace(DBG_LEVEL5, "WMDIOCTL_PRESCALE_NOTIFY\n"); + status = PreScale_DSP(pDevContext, pArgs); + break; + case WMDIOCTL_POSTSCALE_NOTIFY: + DBG_Trace(DBG_LEVEL5, "WMDIOCTL_POSTSCALE_NOTIFY\n"); + status = PostScale_DSP(pDevContext, pArgs); + break; + case WMDIOCTL_CONSTRAINT_REQUEST: + DBG_Trace(DBG_LEVEL5, "WMDIOCTL_CONSTRAINT_REQUEST\n"); + status = handle_constraints_set(pDevContext, pArgs); + break; + default: + status = DSP_EFAIL; + DBG_Trace(DBG_LEVEL7, "Error in WMD_BRD_Ioctl \n"); + break; + } + return status; +} + +/* + * ======== WMD_DEV_Destroy ======== + * Destroys the driver object. + */ +static DSP_STATUS WMD_DEV_Destroy(struct WMD_DEV_CONTEXT *hDevContext) +{ + struct PgTableAttrs *pPtAttrs; + DSP_STATUS status = DSP_SOK; + struct WMD_DEV_CONTEXT *pDevContext = (struct WMD_DEV_CONTEXT *) + hDevContext; + DBG_Trace(DBG_ENTER, "Entering WMD_DEV_Destroy:n hDevContext ::0x%x\n", + hDevContext); + /* first put the device to stop state */ + WMD_BRD_Delete(pDevContext); + if (pDevContext && pDevContext->pPtAttrs) { + pPtAttrs = pDevContext->pPtAttrs; + if (pPtAttrs->hCSObj) + SYNC_DeleteCS(pPtAttrs->hCSObj); + + if (pPtAttrs->pgInfo) + MEM_Free(pPtAttrs->pgInfo); + + if (pPtAttrs->L2TblAllocVa) { + MEM_FreePhysMem((void *)pPtAttrs->L2TblAllocVa, + pPtAttrs->L2TblAllocPa, pPtAttrs-> + L2TblAllocSz); + } + if (pPtAttrs->L1TblAllocVa) { + MEM_FreePhysMem((void *)pPtAttrs->L1TblAllocVa, + pPtAttrs->L1TblAllocPa, pPtAttrs-> + L1TblAllocSz); + } + if (pPtAttrs) + MEM_Free(pPtAttrs); + + } + /* Free the driver's device context: */ + MEM_Free((void *) hDevContext); + return status; +} + +static DSP_STATUS WMD_BRD_MemCopy(struct WMD_DEV_CONTEXT *hDevContext, + u32 ulDspDestAddr, u32 ulDspSrcAddr, + u32 ulNumBytes, u32 ulMemType) +{ + DSP_STATUS status = DSP_SOK; + u32 srcAddr = ulDspSrcAddr; + u32 destAddr = ulDspDestAddr; + u32 copyBytes = 0; + u32 totalBytes = ulNumBytes; + u8 hostBuf[BUFFERSIZE]; + struct WMD_DEV_CONTEXT *pDevContext = hDevContext; + while ((totalBytes > 0) && DSP_SUCCEEDED(status)) { + copyBytes = totalBytes > BUFFERSIZE ? BUFFERSIZE : totalBytes; + /* Read from External memory */ + status = ReadExtDspData(hDevContext, hostBuf, srcAddr, + copyBytes, ulMemType); + if (DSP_SUCCEEDED(status)) { + if (destAddr < (pDevContext->dwDSPStartAdd + + pDevContext->dwInternalSize)) { + /* Write to Internal memory */ + status = WriteDspData(hDevContext, hostBuf, + destAddr, copyBytes, ulMemType); + } else { + /* Write to External memory */ + status = WriteExtDspData(hDevContext, hostBuf, + destAddr, copyBytes, ulMemType, false); + } + } + totalBytes -= copyBytes; + srcAddr += copyBytes; + destAddr += copyBytes; + } + return status; +} + +/* Mem Write does not halt the DSP to write unlike WMD_BRD_Write */ +static DSP_STATUS WMD_BRD_MemWrite(struct WMD_DEV_CONTEXT *hDevContext, + IN u8 *pbHostBuf, u32 dwDSPAddr, + u32 ulNumBytes, u32 ulMemType) +{ + DSP_STATUS status = DSP_SOK; + struct WMD_DEV_CONTEXT *pDevContext = hDevContext; + u32 ulRemainBytes = 0; + u32 ulBytes = 0; + ulRemainBytes = ulNumBytes; + while (ulRemainBytes > 0 && DSP_SUCCEEDED(status)) { + ulBytes = + ulRemainBytes > BUFFERSIZE ? BUFFERSIZE : ulRemainBytes; + if (dwDSPAddr < (pDevContext->dwDSPStartAdd + + pDevContext->dwInternalSize)) { + status = WriteDspData(hDevContext, pbHostBuf, dwDSPAddr, + ulBytes, ulMemType); + } else { + status = WriteExtDspData(hDevContext, pbHostBuf, + dwDSPAddr, ulBytes, ulMemType, true); + } + ulRemainBytes -= ulBytes; + dwDSPAddr += ulBytes; + pbHostBuf = pbHostBuf + ulBytes; + } + return status; +} + +/* + * ======== WMD_BRD_MemMap ======== + * This function maps MPU buffer to the DSP address space. It performs + * linear to physical address translation if required. It translates each + * page since linear addresses can be physically non-contiguous + * All address & size arguments are assumed to be page aligned (in proc.c) + * + * TODO: Disable MMU while updating the page tables (but that'll stall DSP) + */ +static DSP_STATUS WMD_BRD_MemMap(struct WMD_DEV_CONTEXT *hDevContext, + u32 ulMpuAddr, u32 ulVirtAddr, + u32 ulNumBytes, u32 ulMapAttr) +{ + u32 attrs; + DSP_STATUS status = DSP_SOK; + struct WMD_DEV_CONTEXT *pDevContext = hDevContext; + struct HW_MMUMapAttrs_t hwAttrs; + struct vm_area_struct *vma; + struct mm_struct *mm = current->mm; + u32 write = 0; + u32 numUsrPgs = 0; + struct page *mappedPage, *pg; + s32 pgNum; + u32 va = ulVirtAddr; + struct task_struct *curr_task = current; + u32 pgI = 0; + u32 mpuAddr, pa; + + DBG_Trace(DBG_ENTER, "> WMD_BRD_MemMap hDevContext %x, pa %x, va %x, " + "size %x, ulMapAttr %x\n", hDevContext, ulMpuAddr, ulVirtAddr, + ulNumBytes, ulMapAttr); + if (ulNumBytes == 0) + return DSP_EINVALIDARG; + + if (ulMapAttr != 0) { + attrs = ulMapAttr; + } else { + /* Assign default attributes */ + attrs = DSP_MAPVIRTUALADDR | DSP_MAPELEMSIZE16; + } + /* Take mapping properties */ + if (attrs & DSP_MAPBIGENDIAN) + hwAttrs.endianism = HW_BIG_ENDIAN; + else + hwAttrs.endianism = HW_LITTLE_ENDIAN; + + hwAttrs.mixedSize = (enum HW_MMUMixedSize_t) + ((attrs & DSP_MAPMIXEDELEMSIZE) >> 2); + /* Ignore elementSize if mixedSize is enabled */ + if (hwAttrs.mixedSize == 0) { + if (attrs & DSP_MAPELEMSIZE8) { + /* Size is 8 bit */ + hwAttrs.elementSize = HW_ELEM_SIZE_8BIT; + } else if (attrs & DSP_MAPELEMSIZE16) { + /* Size is 16 bit */ + hwAttrs.elementSize = HW_ELEM_SIZE_16BIT; + } else if (attrs & DSP_MAPELEMSIZE32) { + /* Size is 32 bit */ + hwAttrs.elementSize = HW_ELEM_SIZE_32BIT; + } else if (attrs & DSP_MAPELEMSIZE64) { + /* Size is 64 bit */ + hwAttrs.elementSize = HW_ELEM_SIZE_64BIT; + } else { + /* + * Mixedsize isn't enabled, so size can't be + * zero here + */ + DBG_Trace(DBG_LEVEL7, + "WMD_BRD_MemMap: MMU element size is zero\n"); + return DSP_EINVALIDARG; + } + } + if (attrs & DSP_MAPDONOTLOCK) + hwAttrs.donotlockmpupage = 1; + else + hwAttrs.donotlockmpupage = 0; + + if (attrs & DSP_MAPVMALLOCADDR) { + return MemMapVmalloc(hDevContext, ulMpuAddr, ulVirtAddr, + ulNumBytes, &hwAttrs); + } + /* + * Do OS-specific user-va to pa translation. + * Combine physically contiguous regions to reduce TLBs. + * Pass the translated pa to PteUpdate. + */ + if ((attrs & DSP_MAPPHYSICALADDR)) { + status = PteUpdate(pDevContext, ulMpuAddr, ulVirtAddr, + ulNumBytes, &hwAttrs); + goto func_cont; + } + + /* + * Important Note: ulMpuAddr is mapped from user application process + * to current process - it must lie completely within the current + * virtual memory address space in order to be of use to us here! + */ + down_read(&mm->mmap_sem); + vma = find_vma(mm, ulMpuAddr); + if (vma) + DBG_Trace(DBG_LEVEL6, "VMAfor UserBuf: ulMpuAddr=%x, " + "ulNumBytes=%x, vm_start=%x vm_end=%x vm_flags=%x \n", + ulMpuAddr, ulNumBytes, vma->vm_start, + vma->vm_end, vma->vm_flags); + + /* + * It is observed that under some circumstances, the user buffer is + * spread across several VMAs. So loop through and check if the entire + * user buffer is covered + */ + while ((vma) && (ulMpuAddr + ulNumBytes > vma->vm_end)) { + /* jump to the next VMA region */ + vma = find_vma(mm, vma->vm_end + 1); + DBG_Trace(DBG_LEVEL6, "VMAfor UserBuf ulMpuAddr=%x, " + "ulNumBytes=%x, vm_start=%x vm_end=%x vm_flags=%x\n", + ulMpuAddr, ulNumBytes, vma->vm_start, + vma->vm_end, vma->vm_flags); + } + if (!vma) { + DBG_Trace(DBG_LEVEL7, "Failed to get the VMA region for " + "MPU Buffer !!! \n"); + status = DSP_EINVALIDARG; + up_read(&mm->mmap_sem); + goto func_cont; + } + + if (vma->vm_flags & VM_IO) { + numUsrPgs = ulNumBytes / PG_SIZE_4K; + mpuAddr = ulMpuAddr; + DBG_Trace(DBG_LEVEL4, "WMD_BRD_MemMap:numOfActualTabEntries=%d," + "ulNumBytes= %d\n", numUsrPgs, ulNumBytes); + /* Get the physical addresses for user buffer */ + for (pgI = 0; pgI < numUsrPgs; pgI++) { + pa = user_va2pa(mm, mpuAddr); + if (!pa) { + status = DSP_EFAIL; + pr_err("DSPBRIDGE: VM_IO mapping physical" + "address is invalid\n"); + break; + } + if (pfn_valid(__phys_to_pfn(pa))) { + pg = phys_to_page(pa); + get_page(pg); + if (page_count(pg) < 1) { + pr_err("Bad page in VM_IO buffer\n"); + bad_page_dump(pa, pg); + } + } + status = PteSet(pDevContext->pPtAttrs, pa, + va, HW_PAGE_SIZE_4KB, &hwAttrs); + if (DSP_FAILED(status)) { + DBG_Trace(DBG_LEVEL7, + "WMD_BRD_MemMap: FAILED IN VM_IO" + "PTESET \n"); + break; + } + va += HW_PAGE_SIZE_4KB; + mpuAddr += HW_PAGE_SIZE_4KB; + pa += HW_PAGE_SIZE_4KB; + } + } else { + numUsrPgs = ulNumBytes / PG_SIZE_4K; + if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE)) + write = 1; + + for (pgI = 0; pgI < numUsrPgs; pgI++) { + pgNum = get_user_pages(curr_task, mm, ulMpuAddr, 1, + write, 1, &mappedPage, NULL); + if (pgNum > 0) { + if (page_count(mappedPage) < 1) { + pr_err("Bad page count after doing" + "get_user_pages on" + "user buffer\n"); + bad_page_dump(page_to_phys(mappedPage), + mappedPage); + } + status = PteSet(pDevContext->pPtAttrs, + page_to_phys(mappedPage), va, + HW_PAGE_SIZE_4KB, &hwAttrs); + if (DSP_FAILED(status)) { + DBG_Trace(DBG_LEVEL7, + "WMD_BRD_MemMap: FAILED IN PTESET \n"); + break; + } + va += HW_PAGE_SIZE_4KB; + ulMpuAddr += HW_PAGE_SIZE_4KB; + } else { + pr_err("DSPBRIDGE: get_user_pages FAILED," + "MPU addr = 0x%x," + "vma->vm_flags = 0x%lx," + "get_user_pages Err" + "Value = %d, Buffer" + "size=0x%x\n", ulMpuAddr, + vma->vm_flags, pgNum, + ulNumBytes); + status = DSP_EFAIL; + break; + } + } + } + up_read(&mm->mmap_sem); +func_cont: + /* Don't propogate Linux or HW status to upper layers */ + if (DSP_SUCCEEDED(status)) { + status = DSP_SOK; + } else { + DBG_Trace(DBG_LEVEL7, "< WMD_BRD_MemMap status %x\n", status); + /* + * Roll out the mapped pages incase it failed in middle of + * mapping + */ + if (pgI) { + WMD_BRD_MemUnMap(pDevContext, ulVirtAddr, + (pgI * PG_SIZE_4K)); + } + status = DSP_EFAIL; + } + /* + * In any case, flush the TLB + * This is called from here instead from PteUpdate to avoid unnecessary + * repetition while mapping non-contiguous physical regions of a virtual + * region + */ + flush_all(pDevContext); + DBG_Trace(DBG_ENTER, "< WMD_BRD_MemMap status %x\n", status); + return status; +} + +/* + * ======== WMD_BRD_MemUnMap ======== + * Invalidate the PTEs for the DSP VA block to be unmapped. + * + * PTEs of a mapped memory block are contiguous in any page table + * So, instead of looking up the PTE address for every 4K block, + * we clear consecutive PTEs until we unmap all the bytes + */ +static DSP_STATUS WMD_BRD_MemUnMap(struct WMD_DEV_CONTEXT *hDevContext, + u32 ulVirtAddr, u32 ulNumBytes) +{ + u32 L1BaseVa; + u32 L2BaseVa; + u32 L2BasePa; + u32 L2PageNum; + u32 pteVal; + u32 pteSize; + u32 pteCount; + u32 pteAddrL1; + u32 pteAddrL2 = 0; + u32 remBytes; + u32 remBytesL2; + u32 vaCurr; + struct page *pg = NULL; + DSP_STATUS status = DSP_SOK; + struct WMD_DEV_CONTEXT *pDevContext = hDevContext; + struct PgTableAttrs *pt = pDevContext->pPtAttrs; + u32 pacount = 0; + u32 *pPhysAddrPageTbl = NULL; + u32 temp; + u32 patemp = 0; + u32 pAddr; + u32 numof4KPages = 0; + + DBG_Trace(DBG_ENTER, "> WMD_BRD_MemUnMap hDevContext %x, va %x, " + "NumBytes %x\n", hDevContext, ulVirtAddr, ulNumBytes); + pPhysAddrPageTbl = DMM_GetPhysicalAddrTable(); + vaCurr = ulVirtAddr; + remBytes = ulNumBytes; + remBytesL2 = 0; + L1BaseVa = pt->L1BaseVa; + pteAddrL1 = HW_MMU_PteAddrL1(L1BaseVa, vaCurr); + DBG_Trace(DBG_ENTER, "WMD_BRD_MemUnMap L1BaseVa %x, pteAddrL1 %x " + "vaCurr %x remBytes %x\n", L1BaseVa, pteAddrL1, + vaCurr, remBytes); + while (remBytes && (DSP_SUCCEEDED(status))) { + u32 vaCurrOrig = vaCurr; + /* Find whether the L1 PTE points to a valid L2 PT */ + pteAddrL1 = HW_MMU_PteAddrL1(L1BaseVa, vaCurr); + pteVal = *(u32 *)pteAddrL1; + pteSize = HW_MMU_PteSizeL1(pteVal); + if (pteSize == HW_MMU_COARSE_PAGE_SIZE) { + /* + * Get the L2 PA from the L1 PTE, and find + * corresponding L2 VA + */ + L2BasePa = HW_MMU_PteCoarseL1(pteVal); + L2BaseVa = L2BasePa - pt->L2BasePa + pt->L2BaseVa; + L2PageNum = (L2BasePa - pt->L2BasePa) / + HW_MMU_COARSE_PAGE_SIZE; + /* + * Find the L2 PTE address from which we will start + * clearing, the number of PTEs to be cleared on this + * page, and the size of VA space that needs to be + * cleared on this L2 page + */ + pteAddrL2 = HW_MMU_PteAddrL2(L2BaseVa, vaCurr); + pteCount = pteAddrL2 & (HW_MMU_COARSE_PAGE_SIZE - 1); + pteCount = (HW_MMU_COARSE_PAGE_SIZE - pteCount) / + sizeof(u32); + if (remBytes < (pteCount * PG_SIZE_4K)) + pteCount = remBytes / PG_SIZE_4K; + + remBytesL2 = pteCount * PG_SIZE_4K; + DBG_Trace(DBG_LEVEL1, "WMD_BRD_MemUnMap L2BasePa %x, " + "L2BaseVa %x pteAddrL2 %x, remBytesL2 %x\n", + L2BasePa, L2BaseVa, pteAddrL2, remBytesL2); + /* + * Unmap the VA space on this L2 PT. A quicker way + * would be to clear pteCount entries starting from + * pteAddrL2. However, below code checks that we don't + * clear invalid entries or less than 64KB for a 64KB + * entry. Similar checking is done for L1 PTEs too + * below + */ + while (remBytesL2 && (DSP_SUCCEEDED(status))) { + pteVal = *(u32 *)pteAddrL2; + pteSize = HW_MMU_PteSizeL2(pteVal); + /* vaCurr aligned to pteSize? */ + if ((pteSize != 0) && (remBytesL2 >= pteSize) && + !(vaCurr & (pteSize - 1))) { + /* Collect Physical addresses from VA */ + pAddr = (pteVal & ~(pteSize - 1)); + if (pteSize == HW_PAGE_SIZE_64KB) + numof4KPages = 16; + else + numof4KPages = 1; + temp = 0; + while (temp++ < numof4KPages) { + pPhysAddrPageTbl[pacount++] = + pAddr; + pAddr += HW_PAGE_SIZE_4KB; + } + if (HW_MMU_PteClear(pteAddrL2, + vaCurr, pteSize) == RET_OK) { + status = DSP_SOK; + remBytesL2 -= pteSize; + vaCurr += pteSize; + pteAddrL2 += (pteSize >> 12) * + sizeof(u32); + } else { + status = DSP_EFAIL; + goto EXIT_LOOP; + } + } else { + status = DSP_EFAIL; + } + } + SYNC_EnterCS(pt->hCSObj); + if (remBytesL2 == 0) { + pt->pgInfo[L2PageNum].numEntries -= pteCount; + if (pt->pgInfo[L2PageNum].numEntries == 0) { + /* + * Clear the L1 PTE pointing to the + * L2 PT + */ + if (RET_OK == HW_MMU_PteClear(L1BaseVa, + vaCurrOrig, HW_MMU_COARSE_PAGE_SIZE)) + status = DSP_SOK; + else { + status = DSP_EFAIL; + SYNC_LeaveCS(pt->hCSObj); + goto EXIT_LOOP; + } + } + remBytes -= pteCount * PG_SIZE_4K; + } else { + status = DSP_EFAIL; + } + DBG_Trace(DBG_LEVEL1, "WMD_BRD_MemUnMap L2PageNum %x, " + "numEntries %x, pteCount %x, status: 0x%x\n", + L2PageNum, pt->pgInfo[L2PageNum].numEntries, + pteCount, status); + SYNC_LeaveCS(pt->hCSObj); + } else + /* vaCurr aligned to pteSize? */ + /* pteSize = 1 MB or 16 MB */ + if ((pteSize != 0) && (remBytes >= pteSize) && + !(vaCurr & (pteSize - 1))) { + if (pteSize == HW_PAGE_SIZE_1MB) + numof4KPages = 256; + else + numof4KPages = 4096; + temp = 0; + /* Collect Physical addresses from VA */ + pAddr = (pteVal & ~(pteSize - 1)); + while (temp++ < numof4KPages) { + pPhysAddrPageTbl[pacount++] = pAddr; + pAddr += HW_PAGE_SIZE_4KB; + } + if (HW_MMU_PteClear(L1BaseVa, vaCurr, pteSize) + == RET_OK) { + status = DSP_SOK; + remBytes -= pteSize; + vaCurr += pteSize; + } else { + status = DSP_EFAIL; + goto EXIT_LOOP; + } + } else { + status = DSP_EFAIL; + } + } + /* + * It is better to flush the TLB here, so that any stale old entries + * get flushed + */ +EXIT_LOOP: + flush_all(pDevContext); + for (temp = 0; temp < pacount; temp++) { + patemp = pPhysAddrPageTbl[temp]; + if (pfn_valid(__phys_to_pfn(patemp))) { + pg = phys_to_page(patemp); + if (page_count(pg) < 1) { + pr_info("DSPBRIDGE:UNMAP function: COUNT 0" + "FOR PA 0x%x, size = 0x%x\n", + patemp, ulNumBytes); + bad_page_dump(patemp, pg); + } + SetPageDirty(pg); + page_cache_release(pg); + } + } + DBG_Trace(DBG_LEVEL1, "WMD_BRD_MemUnMap vaCurr %x, pteAddrL1 %x " + "pteAddrL2 %x\n", vaCurr, pteAddrL1, pteAddrL2); + DBG_Trace(DBG_ENTER, "< WMD_BRD_MemUnMap status %x remBytes %x, " + "remBytesL2 %x\n", status, remBytes, remBytesL2); + return status; +} + +/* + * ======== user_va2pa ======== + * Purpose: + * This function walks through the Linux page tables to convert a userland + * virtual address to physical address + */ +static u32 user_va2pa(struct mm_struct *mm, u32 address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *ptep, pte; + + pgd = pgd_offset(mm, address); + if (!(pgd_none(*pgd) || pgd_bad(*pgd))) { + pmd = pmd_offset(pgd, address); + if (!(pmd_none(*pmd) || pmd_bad(*pmd))) { + ptep = pte_offset_map(pmd, address); + if (ptep) { + pte = *ptep; + if (pte_present(pte)) + return pte & PAGE_MASK; + } + } + } + + return 0; +} + + +/* + * ======== PteUpdate ======== + * This function calculates the optimum page-aligned addresses and sizes + * Caller must pass page-aligned values + */ +static DSP_STATUS PteUpdate(struct WMD_DEV_CONTEXT *hDevContext, u32 pa, + u32 va, u32 size, + struct HW_MMUMapAttrs_t *mapAttrs) +{ + u32 i; + u32 allBits; + u32 paCurr = pa; + u32 vaCurr = va; + u32 numBytes = size; + struct WMD_DEV_CONTEXT *pDevContext = hDevContext; + DSP_STATUS status = DSP_SOK; + u32 pgSize[] = { HW_PAGE_SIZE_16MB, HW_PAGE_SIZE_1MB, + HW_PAGE_SIZE_64KB, HW_PAGE_SIZE_4KB }; + DBG_Trace(DBG_ENTER, "> PteUpdate hDevContext %x, pa %x, va %x, " + "size %x, mapAttrs %x\n", hDevContext, pa, va, size, mapAttrs); + while (numBytes && DSP_SUCCEEDED(status)) { + /* To find the max. page size with which both PA & VA are + * aligned */ + allBits = paCurr | vaCurr; + DBG_Trace(DBG_LEVEL1, "allBits %x, paCurr %x, vaCurr %x, " + "numBytes %x ", allBits, paCurr, vaCurr, numBytes); + for (i = 0; i < 4; i++) { + if ((numBytes >= pgSize[i]) && ((allBits & + (pgSize[i] - 1)) == 0)) { + DBG_Trace(DBG_LEVEL1, "pgSize %x\n", pgSize[i]); + status = PteSet(pDevContext->pPtAttrs, paCurr, + vaCurr, pgSize[i], mapAttrs); + paCurr += pgSize[i]; + vaCurr += pgSize[i]; + numBytes -= pgSize[i]; + /* Don't try smaller sizes. Hopefully we have + * reached an address aligned to a bigger page + * size */ + break; + } + } + } + DBG_Trace(DBG_ENTER, "< PteUpdate status %x numBytes %x\n", status, + numBytes); + return status; +} + +/* + * ======== PteSet ======== + * This function calculates PTE address (MPU virtual) to be updated + * It also manages the L2 page tables + */ +static DSP_STATUS PteSet(struct PgTableAttrs *pt, u32 pa, u32 va, + u32 size, struct HW_MMUMapAttrs_t *attrs) +{ + u32 i; + u32 pteVal; + u32 pteAddrL1; + u32 pteSize; + u32 pgTblVa; /* Base address of the PT that will be updated */ + u32 L1BaseVa; + /* Compiler warns that the next three variables might be used + * uninitialized in this function. Doesn't seem so. Working around, + * anyways. */ + u32 L2BaseVa = 0; + u32 L2BasePa = 0; + u32 L2PageNum = 0; + DSP_STATUS status = DSP_SOK; + DBG_Trace(DBG_ENTER, "> PteSet pPgTableAttrs %x, pa %x, va %x, " + "size %x, attrs %x\n", pt, pa, va, size, attrs); + L1BaseVa = pt->L1BaseVa; + pgTblVa = L1BaseVa; + if ((size == HW_PAGE_SIZE_64KB) || (size == HW_PAGE_SIZE_4KB)) { + /* Find whether the L1 PTE points to a valid L2 PT */ + pteAddrL1 = HW_MMU_PteAddrL1(L1BaseVa, va); + if (pteAddrL1 <= (pt->L1BaseVa + pt->L1size)) { + pteVal = *(u32 *)pteAddrL1; + pteSize = HW_MMU_PteSizeL1(pteVal); + } else { + return DSP_EFAIL; + } + SYNC_EnterCS(pt->hCSObj); + if (pteSize == HW_MMU_COARSE_PAGE_SIZE) { + /* Get the L2 PA from the L1 PTE, and find + * corresponding L2 VA */ + L2BasePa = HW_MMU_PteCoarseL1(pteVal); + L2BaseVa = L2BasePa - pt->L2BasePa + pt->L2BaseVa; + L2PageNum = (L2BasePa - pt->L2BasePa) / + HW_MMU_COARSE_PAGE_SIZE; + } else if (pteSize == 0) { + /* L1 PTE is invalid. Allocate a L2 PT and + * point the L1 PTE to it */ + /* Find a free L2 PT. */ + for (i = 0; (i < pt->L2NumPages) && + (pt->pgInfo[i].numEntries != 0); i++) + ;; + if (i < pt->L2NumPages) { + L2PageNum = i; + L2BasePa = pt->L2BasePa + (L2PageNum * + HW_MMU_COARSE_PAGE_SIZE); + L2BaseVa = pt->L2BaseVa + (L2PageNum * + HW_MMU_COARSE_PAGE_SIZE); + /* Endianness attributes are ignored for + * HW_MMU_COARSE_PAGE_SIZE */ + status = HW_MMU_PteSet(L1BaseVa, L2BasePa, va, + HW_MMU_COARSE_PAGE_SIZE, attrs); + } else { + status = DSP_EMEMORY; + } + } else { + /* Found valid L1 PTE of another size. + * Should not overwrite it. */ + status = DSP_EFAIL; + } + if (DSP_SUCCEEDED(status)) { + pgTblVa = L2BaseVa; + if (size == HW_PAGE_SIZE_64KB) + pt->pgInfo[L2PageNum].numEntries += 16; + else + pt->pgInfo[L2PageNum].numEntries++; + DBG_Trace(DBG_LEVEL1, "L2 BaseVa %x, BasePa %x, " + "PageNum %x numEntries %x\n", L2BaseVa, + L2BasePa, L2PageNum, + pt->pgInfo[L2PageNum].numEntries); + } + SYNC_LeaveCS(pt->hCSObj); + } + if (DSP_SUCCEEDED(status)) { + DBG_Trace(DBG_LEVEL1, "PTE pgTblVa %x, pa %x, va %x, size %x\n", + pgTblVa, pa, va, size); + DBG_Trace(DBG_LEVEL1, "PTE endianism %x, elementSize %x, " + "mixedSize %x\n", attrs->endianism, + attrs->elementSize, attrs->mixedSize); + status = HW_MMU_PteSet(pgTblVa, pa, va, size, attrs); + } + DBG_Trace(DBG_ENTER, "< PteSet status %x\n", status); + return status; +} + +/* Memory map kernel VA -- memory allocated with vmalloc */ +static DSP_STATUS MemMapVmalloc(struct WMD_DEV_CONTEXT *pDevContext, + u32 ulMpuAddr, u32 ulVirtAddr, u32 ulNumBytes, + struct HW_MMUMapAttrs_t *hwAttrs) +{ + DSP_STATUS status = DSP_SOK; + struct page *pPage[1]; + u32 i; + u32 paCurr; + u32 paNext; + u32 vaCurr; + u32 sizeCurr; + u32 numPages; + u32 pa; + u32 numOf4KPages; + u32 temp = 0; + + DBG_Trace(DBG_ENTER, "> MemMapVmalloc hDevContext %x, pa %x, va %x, " + "size %x\n", pDevContext, ulMpuAddr, ulVirtAddr, ulNumBytes); + + /* + * Do Kernel va to pa translation. + * Combine physically contiguous regions to reduce TLBs. + * Pass the translated pa to PteUpdate. + */ + numPages = ulNumBytes / PAGE_SIZE; /* PAGE_SIZE = OS page size */ + i = 0; + vaCurr = ulMpuAddr; + pPage[0] = vmalloc_to_page((void *)vaCurr); + paNext = page_to_phys(pPage[0]); + while (DSP_SUCCEEDED(status) && (i < numPages)) { + /* + * Reuse paNext from the previous iteraion to avoid + * an extra va2pa call + */ + paCurr = paNext; + sizeCurr = PAGE_SIZE; + /* + * If the next page is physically contiguous, + * map it with the current one by increasing + * the size of the region to be mapped + */ + while (++i < numPages) { + pPage[0] = vmalloc_to_page((void *)(vaCurr + sizeCurr)); + paNext = page_to_phys(pPage[0]); + DBG_Trace(DBG_LEVEL5, "Xlate Vmalloc VA=0x%x , " + "PA=0x%x \n", (vaCurr + sizeCurr), paNext); + if (paNext == (paCurr + sizeCurr)) + sizeCurr += PAGE_SIZE; + else + break; + + } + if (paNext == 0) { + status = DSP_EMEMORY; + break; + } + pa = paCurr; + numOf4KPages = sizeCurr / HW_PAGE_SIZE_4KB; + while (temp++ < numOf4KPages) { + get_page(phys_to_page(pa)); + pa += HW_PAGE_SIZE_4KB; + } + status = PteUpdate(pDevContext, paCurr, ulVirtAddr + + (vaCurr - ulMpuAddr), sizeCurr, hwAttrs); + vaCurr += sizeCurr; + } + /* Don't propogate Linux or HW status to upper layers */ + if (DSP_SUCCEEDED(status)) { + status = DSP_SOK; + DBG_Trace(DBG_LEVEL7, "< WMD_BRD_MemMap succeeded %x\n", + status); + } else { + DBG_Trace(DBG_LEVEL7, "< WMD_BRD_MemMap status %x\n", status); + status = DSP_EFAIL; + } + /* + * In any case, flush the TLB + * This is called from here instead from PteUpdate to avoid unnecessary + * repetition while mapping non-contiguous physical regions of a virtual + * region + */ + flush_all(pDevContext); + DBG_Trace(DBG_LEVEL7, "< WMD_BRD_MemMap at end status %x\n", status); + return status; +} + +static DSP_STATUS run_IdleBoot(u32 prm_base, u32 cm_base, + u32 sysctrl_base) +{ + u32 temp; + DSP_STATUS status = DSP_SOK; + enum HW_PwrState_t pwrState; + + /* Read PM_PWSTST_IVA2 */ + HW_PWRST_IVA2RegGet(prm_base, &temp); + if ((temp & 0x03) != 0x03 || (temp & 0x03) != 0x02) { + /* IVA2 is not in ON state */ + /* Set PM_PWSTCTRL_IVA2 to ON */ + HW_PWR_IVA2PowerStateSet(prm_base, HW_PWR_DOMAIN_DSP, + HW_PWR_STATE_ON); + /* Set the SW supervised state transition */ + HW_PWR_CLKCTRL_IVA2RegSet(cm_base, HW_SW_SUP_WAKEUP); + /* Wait until the state has moved to ON */ + HW_PWR_IVA2StateGet(prm_base, HW_PWR_DOMAIN_DSP, &pwrState); + } + CLK_Disable(SERVICESCLK_iva2_ck); + udelay(10); + /* Assert IVA2-RST1 and IVA2-RST2 */ + *((REG_UWORD32 *)((u32)(prm_base) + 0x50)) = (u32)0x07; + udelay(30); + /* set the SYSC for Idle Boot */ + *((REG_UWORD32 *)((u32)(sysctrl_base) + 0x404)) = (u32)0x01; + temp = (u32) *((REG_UWORD32 *) + ((u32) (cm_base) + 0x34)); + temp = (temp & 0xFFFFFFFE) | 0x1; + *((REG_UWORD32 *) ((u32) (cm_base) + 0x34)) = + (u32) temp; + temp = (u32) *((REG_UWORD32 *) + ((u32) (cm_base) + 0x4)); + temp = (temp & 0xFFFFFC8) | 0x37; + *((REG_UWORD32 *) ((u32) (cm_base) + 0x4)) = + (u32) temp; + CLK_Enable(SERVICESCLK_iva2_ck); + udelay(20); + GetHWRegs(prm_base, cm_base); + /* Release Reset1 and Reset2 */ + *((REG_UWORD32 *)((u32)(prm_base) + 0x50)) = (u32)0x05; + udelay(20); + *((REG_UWORD32 *)((u32)(prm_base) + 0x50)) = (u32)0x04; + udelay(30); + return status; +} + + +void GetHWRegs(u32 prm_base, u32 cm_base) +{ + u32 temp; + temp = (u32)*((REG_UWORD32 *)((u32)(cm_base) + 0x00)); + DBG_Trace(DBG_LEVEL6, "CM_FCLKEN_IVA2 = 0x%x \n", temp); + temp = (u32)*((REG_UWORD32 *)((u32)(cm_base) + 0x10)); + DBG_Trace(DBG_LEVEL6, "CM_ICLKEN1_IVA2 = 0x%x \n", temp); + temp = (u32)*((REG_UWORD32 *)((u32)(cm_base) + 0x20)); + DBG_Trace(DBG_LEVEL6, "CM_IDLEST_IVA2 = 0x%x \n", temp); + temp = (u32)*((REG_UWORD32 *)((u32)(cm_base) + 0x48)); + DBG_Trace(DBG_LEVEL6, "CM_CLKSTCTRL_IVA2 = 0x%x \n", temp); + temp = (u32)*((REG_UWORD32 *)((u32)(cm_base) + 0x4c)); + DBG_Trace(DBG_LEVEL6, "CM_CLKSTST_IVA2 = 0x%x \n", temp); + temp = (u32)*((REG_UWORD32 *)((u32)(prm_base) + 0x50)); + DBG_Trace(DBG_LEVEL6, "RM_RSTCTRL_IVA2 = 0x%x \n", temp); + temp = (u32)*((REG_UWORD32 *)((u32)(prm_base) + 0x58)); + DBG_Trace(DBG_LEVEL6, "RM_RSTST_IVA2 = 0x%x \n", temp); + temp = (u32)*((REG_UWORD32 *)((u32)(prm_base) + 0xE0)); + DBG_Trace(DBG_LEVEL6, "PM_PWSTCTRL_IVA2 = 0x%x \n", temp); + temp = (u32)*((REG_UWORD32 *)((u32)(prm_base) + 0xE4)); + DBG_Trace(DBG_LEVEL6, "PM_PWSTST_IVA2 = 0x%x \n", temp); + temp = (u32)*((REG_UWORD32 *)((u32)(cm_base) + 0xA10)); + DBG_Trace(DBG_LEVEL6, "CM_ICLKEN1_CORE = 0x%x \n", temp); +} + +/* + * ======== configureDspMmu ======== + * Make DSP MMU page table entries. + */ +void configureDspMmu(struct WMD_DEV_CONTEXT *pDevContext, u32 dataBasePhys, + u32 dspBaseVirt, u32 sizeInBytes, s32 nEntryStart, + enum HW_Endianism_t endianism, + enum HW_ElementSize_t elemSize, + enum HW_MMUMixedSize_t mixedSize) +{ + struct CFG_HOSTRES resources; + struct HW_MMUMapAttrs_t mapAttrs = { endianism, elemSize, mixedSize }; + DSP_STATUS status = DSP_SOK; + + DBC_Require(sizeInBytes > 0); + DBG_Trace(DBG_LEVEL1, + "configureDspMmu entry %x pa %x, va %x, bytes %x ", + nEntryStart, dataBasePhys, dspBaseVirt, sizeInBytes); + + DBG_Trace(DBG_LEVEL1, "endianism %x, elemSize %x, mixedSize %x\n", + endianism, elemSize, mixedSize); + status = CFG_GetHostResources( + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); + status = HW_MMU_TLBAdd(pDevContext->dwDSPMmuBase, dataBasePhys, + dspBaseVirt, sizeInBytes, nEntryStart, + &mapAttrs, HW_SET, HW_SET); +} + +/* + * ======== WaitForStart ======== + * Wait for the singal from DSP that it has started, or time out. + */ +bool WaitForStart(struct WMD_DEV_CONTEXT *pDevContext, u32 dwSyncAddr) +{ + u16 usCount = TIHELEN_ACKTIMEOUT; + + /* Wait for response from board */ + while (*((volatile u16 *)dwSyncAddr) && --usCount) + udelay(10); + + /* If timed out: return FALSE */ + if (!usCount) { + DBG_Trace(DBG_LEVEL7, "Timed out Waiting for DSP to Start\n"); + return FALSE; + } + return TRUE; +} diff --git a/drivers/dsp/bridge/wmd/tiomap3430_pwr.c b/drivers/dsp/bridge/wmd/tiomap3430_pwr.c new file mode 100644 index 0000000..cbf6925 --- /dev/null +++ b/drivers/dsp/bridge/wmd/tiomap3430_pwr.c @@ -0,0 +1,731 @@ +/* + * tiomap_pwr.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007-2008 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== _tiomap_pwr.c ======== + * Description: + * Implementation of DSP wake/sleep routines. + * + *! Revision History + *! ================ + *! 01-Nov-2007 HK: Added Off mode(Hibernation) support and DVFS support + *! 05-Jan-2004 vp: Moved the file to platform specific folder and commented the + *! code. + *! 27-Mar-2003 vp: Added support for DSP boot idle mode. + *! 06-Dec-2002 cring: Added Palm support. + *! 08-Oct-2002 rr: Created. + */ + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include + +/* ----------------------------------- Platform Manager */ +#include +#include +#include + +/* ------------------------------------ Hardware Abstraction Layer */ +#include +#include +#include +#include + +#include + +/* ----------------------------------- specific to this file */ +#include "_tiomap.h" +#include "_tiomap_pwr.h" +#include "_tiomap_util.h" +#include +#include + +#ifdef CONFIG_PM +#include +#endif +extern struct MAILBOX_CONTEXT mboxsetting; +static unsigned short enable_off_mode = 0; +/* + * ======== handle_constraints_set ======== + * Sets new DSP constraint + */ +DSP_STATUS handle_constraints_set(struct WMD_DEV_CONTEXT *pDevContext, + IN void *pArgs) +{ +#ifdef CONFIG_BRIDGE_DVFS + u32 *pConstraintVal; + DSP_STATUS status = DSP_SOK; + struct CFG_HOSTRES resources; + struct dspbridge_platform_data *pdata = + omap_dspbridge_dev->dev.platform_data; + status = CFG_GetHostResources( + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); + + pConstraintVal = (u32 *)(pArgs); + /* Read the target value requested by DSP */ + DBG_Trace(DBG_LEVEL7, "handle_constraints_set:" + "opp requested = 0x%x\n", (u32)*(pConstraintVal+1)); + status = HW_MBOX_saveSettings(resources.dwMboxBase); + + /* Set the new opp value */ + if (pdata->dsp_set_min_opp) + (*pdata->dsp_set_min_opp)((u32)*(pConstraintVal+1)); + return DSP_SOK; +#endif /* #ifdef CONFIG_BRIDGE_DVFS */ + return DSP_SOK; +} + +/* + * ======== handle_hibernation_fromDSP ======== + * Handle Hibernation requested from DSP + */ +DSP_STATUS handle_hibernation_fromDSP(struct WMD_DEV_CONTEXT *pDevContext) +{ + DSP_STATUS status = DSP_SOK; +#ifdef CONFIG_PM + u16 usCount = TIHELEN_ACKTIMEOUT; + struct CFG_HOSTRES resources; + enum HW_PwrState_t pwrState; +#ifdef CONFIG_BRIDGE_DVFS + u32 opplevel; + struct IO_MGR *hIOMgr; + struct dspbridge_platform_data *pdata = + omap_dspbridge_dev->dev.platform_data; +#endif + + status = CFG_GetHostResources( + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); + if (DSP_FAILED(status)) + return status; + + HW_PWR_IVA2StateGet(resources.dwPrmBase, HW_PWR_DOMAIN_DSP, + &pwrState); + /* Wait for DSP to move into Off state, how much time should + * we wait? */ + while ((pwrState != HW_PWR_STATE_OFF) && --usCount) { + udelay(500); + HW_PWR_IVA2StateGet(resources.dwPrmBase, HW_PWR_DOMAIN_DSP, + &pwrState); + } + if (usCount == 0) { + DBG_Trace(DBG_LEVEL7, "Timed out Waiting for DSP Off mode \n"); + status = WMD_E_TIMEOUT; + return status; + } else { + + /* Save mailbox settings */ + status = HW_MBOX_saveSettings(resources.dwMboxBase); + DBG_Trace(DBG_LEVEL6, "MailBoxSettings: SYSCONFIG = 0x%x\n", + mboxsetting.sysconfig); + DBG_Trace(DBG_LEVEL6, "MailBoxSettings: IRQENABLE0 = 0x%x\n", + mboxsetting.irqEnable0); + DBG_Trace(DBG_LEVEL6, "MailBoxSettings: IRQENABLE1 = 0x%x\n", + mboxsetting.irqEnable1); + /* Turn off DSP Peripheral clocks and DSP Load monitor timer */ + status = DSP_PeripheralClocks_Disable(pDevContext, NULL); + + if (DSP_SUCCEEDED(status)) { + /* Update the Bridger Driver state */ + pDevContext->dwBrdState = BRD_DSP_HIBERNATION; +#ifdef CONFIG_BRIDGE_DVFS + status = DEV_GetIOMgr(pDevContext->hDevObject, &hIOMgr); + if (DSP_FAILED(status)) + return status; + IO_SHMsetting(hIOMgr, SHM_GETOPP, &opplevel); + /* Set the OPP to low level before moving to OFF mode */ + if (opplevel != VDD1_OPP1) { + DBG_Trace(DBG_LEVEL5, + "Tiomap_pwr.c - DSP requested" + " OPP = %d, MPU requesting low" + " OPP %d instead\n", opplevel, + VDD1_OPP1); + if (pdata->dsp_set_min_opp) + (*pdata->dsp_set_min_opp)(VDD1_OPP1); + status = DSP_SOK; + } +#endif /* CONFIG_BRIDGE_DVFS */ + } else { + DBG_Trace(DBG_LEVEL7, + "handle_hibernation_fromDSP- FAILED\n"); + } + } +#endif + return status; +} + +/* + * ======== SleepDSP ======== + * Put DSP in low power consuming state. + */ +DSP_STATUS SleepDSP(struct WMD_DEV_CONTEXT *pDevContext, IN u32 dwCmd, + IN void *pArgs) +{ + DSP_STATUS status = DSP_SOK; +#ifdef CONFIG_PM + struct CFG_HOSTRES resources; + u16 usCount = TIHELEN_ACKTIMEOUT; + enum HW_PwrState_t pwrState; + enum HW_PwrState_t targetPwrState; + + status = CFG_GetHostResources( + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); + if (DSP_FAILED(status)) + return status; + DBG_Trace(DBG_LEVEL7, "SleepDSP- Enter function \n"); + + /* next, check if sleep code is valid... */ + if ((dwCmd != PWR_DEEPSLEEP) && (dwCmd != PWR_EMERGENCYDEEPSLEEP)) { + DBG_Trace(DBG_LEVEL7, "SleepDSP- Illegal sleep command\n"); + return DSP_EINVALIDARG; + } + switch (pDevContext->dwBrdState) { + case BRD_RUNNING: + status = HW_MBOX_saveSettings(resources.dwMboxBase); + if (enable_off_mode) { + CHNLSM_InterruptDSP2(pDevContext, + MBX_PM_DSPHIBERNATE); + DBG_Trace(DBG_LEVEL7, + "SleepDSP - Sent hibernate " + "command to DSP\n"); + targetPwrState = HW_PWR_STATE_OFF; + } else { + CHNLSM_InterruptDSP2(pDevContext, + MBX_PM_DSPRETENTION); + targetPwrState = HW_PWR_STATE_RET; + } + break; + case BRD_RETENTION: + status = HW_MBOX_saveSettings(resources.dwMboxBase); + if (enable_off_mode) { + CHNLSM_InterruptDSP2(pDevContext, + MBX_PM_DSPHIBERNATE); + targetPwrState = HW_PWR_STATE_OFF; + } else + return DSP_SOK; + break; + case BRD_HIBERNATION: + case BRD_DSP_HIBERNATION: + status = HW_MBOX_saveSettings(resources.dwMboxBase); + /* Already in Hibernation, so just return */ + DBG_Trace(DBG_LEVEL7, "SleepDSP- DSP already in " + "hibernation\n"); + return DSP_SOK; + case BRD_STOPPED: + DBG_Trace(DBG_LEVEL7, + "SleepDSP- Board in STOP state \n"); + return DSP_SALREADYASLEEP; + default: + DBG_Trace(DBG_LEVEL7, + "SleepDSP- Bridge in Illegal state\n"); + return DSP_EFAIL; + } + /* Get the PRCM DSP power domain status */ + HW_PWR_IVA2StateGet(resources.dwPrmBase, HW_PWR_DOMAIN_DSP, + &pwrState); + /* Wait for DSP to move into Standby state, how much time + * should we wait?*/ + while ((pwrState != targetPwrState) && --usCount) { + udelay(500); + HW_PWR_IVA2StateGet(resources.dwPrmBase, HW_PWR_DOMAIN_DSP, + &pwrState); + } + if (usCount == 0) { + DBG_Trace(DBG_LEVEL7, "SleepDSP: Timed out Waiting for DSP" + " STANDBY %x \n", pwrState); + return WMD_E_TIMEOUT; + } else { + DBG_Trace(DBG_LEVEL7, "SleepDSP: DSP STANDBY Pwr state %x \n", + pwrState); + /* Update the Bridger Driver state */ + if (enable_off_mode) + pDevContext->dwBrdState = BRD_HIBERNATION; + else + pDevContext->dwBrdState = BRD_RETENTION; + /* Turn off DSP Peripheral clocks */ + status = DSP_PeripheralClocks_Disable(pDevContext, NULL); + if (DSP_FAILED(status)) + DBG_Trace(DBG_LEVEL7, "SleepDSP- FAILED\n"); + } +#endif + return status; +} + + +/* + * ======== WakeDSP ======== + * Wake up DSP from sleep. + */ +DSP_STATUS WakeDSP(struct WMD_DEV_CONTEXT *pDevContext, IN void *pArgs) +{ + DSP_STATUS status = DSP_SOK; +#ifdef CONFIG_PM + struct CFG_HOSTRES resources; + enum HW_PwrState_t pwrState; + u32 temp; + + status = CFG_GetHostResources( + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); + if (DSP_FAILED(status)) + return status; + /* check the BRD/WMD state, if it is not 'SLEEP' then return failure */ + if (pDevContext->dwBrdState == BRD_RUNNING || + pDevContext->dwBrdState == BRD_STOPPED || + pDevContext->dwBrdState == BRD_DSP_HIBERNATION) { + /* The Device is in 'RET' or 'OFF' state and WMD state is not + * 'SLEEP', this means state inconsistency, so return */ + status = DSP_SOK; + return status; + } + /* Enable the DSP peripheral clocks and load monitor timer + * before waking the DSP */ + DBG_Trace(DBG_LEVEL6, "WakeDSP: enable DSP Peripheral Clks = 0x%x \n", + pDevContext->uDspPerClks); + status = DSP_PeripheralClocks_Enable(pDevContext, NULL); + + /* Enabling Dppll in lock mode */ + temp = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwCmBase) + 0x34)); + temp = (temp & 0xFFFFFFFE) | 0x1; + *((REG_UWORD32 *) ((u32) (resources.dwCmBase) + 0x34)) = + (u32) temp; + temp = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwCmBase) + 0x4)); + temp = (temp & 0xFFFFFC8) | 0x37; + + *((REG_UWORD32 *) ((u32) (resources.dwCmBase) + 0x4)) = + (u32) temp; + + udelay(10); + if (DSP_SUCCEEDED(status)) { + /* Send a message to DSP to wake up */ + CHNLSM_InterruptDSP2(pDevContext, MBX_PM_DSPWAKEUP); + HW_PWR_IVA2StateGet(resources.dwPrmBase, HW_PWR_DOMAIN_DSP, + &pwrState); + DBG_Trace(DBG_LEVEL7, + "\nWakeDSP: Power State After sending Interrupt " + "to DSP %x\n", pwrState); + /* set the device state to RUNNIG */ + pDevContext->dwBrdState = BRD_RUNNING; + } else { + DBG_Trace(DBG_LEVEL6, "WakeDSP: FAILED\n"); + } +#endif + return status; +} + +/* + * ======== DSPPeripheralClkCtrl ======== + * Enable/Disable the DSP peripheral clocks as needed.. + */ +DSP_STATUS DSPPeripheralClkCtrl(struct WMD_DEV_CONTEXT *pDevContext, + IN void *pArgs) +{ + u32 extClk = 0; + u32 extClkId = 0; + u32 extClkCmd = 0; + u32 clkIdIndex = MBX_PM_MAX_RESOURCES; + u32 tmpIndex; + u32 dspPerClksBefore; + DSP_STATUS status = DSP_SOK; + DSP_STATUS status1 = DSP_SOK; + + DBG_Trace(DBG_ENTER, "Entering DSPPeripheralClkCtrl \n"); + dspPerClksBefore = pDevContext->uDspPerClks; + DBG_Trace(DBG_ENTER, "DSPPeripheralClkCtrl : uDspPerClks = 0x%x \n", + dspPerClksBefore); + + extClk = (u32)*((u32 *)pArgs); + + DBG_Trace(DBG_LEVEL3, "DSPPeripheralClkCtrl : extClk+Cmd = 0x%x \n", + extClk); + + extClkId = extClk & MBX_PM_CLK_IDMASK; + + /* process the power message -- TODO, keep it in a separate function */ + for (tmpIndex = 0; tmpIndex < MBX_PM_MAX_RESOURCES; tmpIndex++) { + if (extClkId == BPWR_CLKID[tmpIndex]) { + clkIdIndex = tmpIndex; + break; + } + } + /* TODO -- Assert may be a too hard restriction here.. May be we should + * just return with failure when the CLK ID does not match */ + /* DBC_Assert(clkIdIndex < MBX_PM_MAX_RESOURCES);*/ + if (clkIdIndex == MBX_PM_MAX_RESOURCES) { + DBG_Trace(DBG_LEVEL7, + "DSPPeripheralClkCtrl : Could n't get clock Id for" + "clkid 0x%x \n", clkIdIndex); + /* return with a more meaningfull error code */ + return DSP_EFAIL; + } + extClkCmd = (extClk >> MBX_PM_CLK_CMDSHIFT) & MBX_PM_CLK_CMDMASK; + switch (extClkCmd) { + case BPWR_DisableClock: + /* Call BP to disable the needed clock */ + DBG_Trace(DBG_LEVEL3, + "DSPPeripheralClkCtrl : Disable CLK for \n"); + status1 = CLK_Disable(BPWR_Clks[clkIdIndex].intClk); + status = CLK_Disable(BPWR_Clks[clkIdIndex].funClk); + DSPClkWakeupEventCtrl(BPWR_Clks[clkIdIndex].clkId, false); + if ((DSP_SUCCEEDED(status)) && (DSP_SUCCEEDED(status1))) { + (pDevContext->uDspPerClks) &= + (~((u32) (1 << clkIdIndex))); + } else { + DBG_Trace(DBG_LEVEL7, "DSPPeripheralClkCtrl : Failed " + "to disable clk\n"); + } + break; + case BPWR_EnableClock: + DBG_Trace(DBG_LEVEL3, + "DSPPeripheralClkCtrl : Enable CLK for \n"); + status1 = CLK_Enable(BPWR_Clks[clkIdIndex].intClk); + status = CLK_Enable(BPWR_Clks[clkIdIndex].funClk); + DSPClkWakeupEventCtrl(BPWR_Clks[clkIdIndex].clkId, true); + if ((DSP_SUCCEEDED(status)) && (DSP_SUCCEEDED(status1))) { + (pDevContext->uDspPerClks) |= (1 << clkIdIndex); + } else { + DBG_Trace(DBG_LEVEL7, + "DSPPeripheralClkCtrl:Failed to Enable clk\n"); + } + break; + default: + DBG_Trace(DBG_LEVEL3, + "DSPPeripheralClkCtrl : Unsupported CMD \n"); + /* unsupported cmd */ + /* TODO -- provide support for AUTOIDLE Enable/Disable + * commands */ + } + return status; +} + +/* + * ========PreScale_DSP======== + * Sends prescale notification to DSP + * + */ +DSP_STATUS PreScale_DSP(struct WMD_DEV_CONTEXT *pDevContext, IN void *pArgs) +{ +#ifdef CONFIG_BRIDGE_DVFS + u32 level; + u32 voltage_domain; + + voltage_domain = *((u32 *)pArgs); + level = *((u32 *)pArgs + 1); + + DBG_Trace(DBG_LEVEL7, "PreScale_DSP: voltage_domain = %x, level = " + "0x%x\n", voltage_domain, level); + if ((pDevContext->dwBrdState == BRD_HIBERNATION) || + (pDevContext->dwBrdState == BRD_RETENTION) || + (pDevContext->dwBrdState == BRD_DSP_HIBERNATION)) { + DBG_Trace(DBG_LEVEL7, "PreScale_DSP: IVA in sleep. " + "No notification to DSP\n"); + return DSP_SOK; + } else if ((pDevContext->dwBrdState == BRD_RUNNING)) { + /* Send a prenotificatio to DSP */ + DBG_Trace(DBG_LEVEL7, + "PreScale_DSP: Sent notification to DSP\n"); + CHNLSM_InterruptDSP2(pDevContext, MBX_PM_SETPOINT_PRENOTIFY); + return DSP_SOK; + } else { + DBG_Trace(DBG_LEVEL7, "PreScale_DSP: Failed - DSP BRD" + " state in wrong state"); + return DSP_EFAIL; + } +#endif /* #ifdef CONFIG_BRIDGE_DVFS */ + return DSP_SOK; +} + +/* + * ========PostScale_DSP======== + * Sends postscale notification to DSP + * + */ +DSP_STATUS PostScale_DSP(struct WMD_DEV_CONTEXT *pDevContext, IN void *pArgs) +{ +#ifdef CONFIG_BRIDGE_DVFS + u32 level; + u32 voltage_domain; + struct IO_MGR *hIOMgr; + DSP_STATUS status = DSP_SOK; + + status = DEV_GetIOMgr(pDevContext->hDevObject, &hIOMgr); + + voltage_domain = *((u32 *)pArgs); + level = *((u32 *)pArgs + 1); + DBG_Trace(DBG_LEVEL7, + "PostScale_DSP: voltage_domain = %x, level = 0x%x\n", + voltage_domain, level); + if ((pDevContext->dwBrdState == BRD_HIBERNATION) || + (pDevContext->dwBrdState == BRD_RETENTION) || + (pDevContext->dwBrdState == BRD_DSP_HIBERNATION)) { + /* Update the OPP value in shared memory */ + IO_SHMsetting(hIOMgr, SHM_CURROPP, &level); + DBG_Trace(DBG_LEVEL7, + "PostScale_DSP: IVA in sleep. Wrote to shared " + "memory \n"); + return DSP_SOK; + } else if ((pDevContext->dwBrdState == BRD_RUNNING)) { + /* Update the OPP value in shared memory */ + IO_SHMsetting(hIOMgr, SHM_CURROPP, &level); + /* Send a post notification to DSP */ + CHNLSM_InterruptDSP2(pDevContext, MBX_PM_SETPOINT_POSTNOTIFY); + DBG_Trace(DBG_LEVEL7, + "PostScale_DSP: Wrote to shared memory Sent post" + " notification to DSP\n"); + return DSP_SOK; + } else { + DBG_Trace(DBG_LEVEL7, "PostScale_DSP: Failed - DSP BRD state " + "in wrong state"); + return DSP_EFAIL; + } +#endif /* #ifdef CONFIG_BRIDGE_DVFS */ + return DSP_SOK; +} + +/* + * ========DSP_PeripheralClocks_Disable======== + * Disables all the peripheral clocks that were requested by DSP + */ +DSP_STATUS DSP_PeripheralClocks_Disable(struct WMD_DEV_CONTEXT *pDevContext, + IN void *pArgs) +{ + + u32 clkIdx; + DSP_STATUS status = DSP_SOK; + + for (clkIdx = 0; clkIdx < MBX_PM_MAX_RESOURCES; clkIdx++) { + if (((pDevContext->uDspPerClks) >> clkIdx) & 0x01) { + /* Disables the interface clock of the peripheral */ + status = CLK_Disable(BPWR_Clks[clkIdx].intClk); + if (DSP_FAILED(status)) { + DBG_Trace(DBG_LEVEL7, + "Failed to Enable the DSP Peripheral" + "Clk 0x%x \n", BPWR_Clks[clkIdx]); + } + /* Disables the functional clock of the periphearl */ + status = CLK_Disable(BPWR_Clks[clkIdx].funClk); + if (DSP_FAILED(status)) { + DBG_Trace(DBG_LEVEL7, + "Failed to Enable the DSP Peripheral" + "Clk 0x%x \n", BPWR_Clks[clkIdx]); + } + } + } + return status; +} + +/* + * ========DSP_PeripheralClocks_Enable======== + * Enables all the peripheral clocks that were requested by DSP + */ +DSP_STATUS DSP_PeripheralClocks_Enable(struct WMD_DEV_CONTEXT *pDevContext, + IN void *pArgs) +{ + u32 clkIdx; + DSP_STATUS int_clk_status = DSP_EFAIL, fun_clk_status = DSP_EFAIL; + + for (clkIdx = 0; clkIdx < MBX_PM_MAX_RESOURCES; clkIdx++) { + if (((pDevContext->uDspPerClks) >> clkIdx) & 0x01) { + /* Enable the interface clock of the peripheral */ + int_clk_status = CLK_Enable(BPWR_Clks[clkIdx].intClk); + /* Enable the functional clock of the periphearl */ + fun_clk_status = CLK_Enable(BPWR_Clks[clkIdx].funClk); + } + } + if ((int_clk_status | fun_clk_status) != DSP_SOK) + return DSP_EFAIL; + return DSP_SOK; +} + +void DSPClkWakeupEventCtrl(u32 ClkId, bool enable) +{ + struct CFG_HOSTRES resources; + DSP_STATUS status = DSP_SOK; + u32 iva2_grpsel; + u32 mpu_grpsel; + + status = CFG_GetHostResources( + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); + if (DSP_FAILED(status)) + return; + + switch (ClkId) { + case BPWR_GPTimer5: + iva2_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerPmBase) + 0xA8)); + mpu_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerPmBase) + 0xA4)); + if (enable) { + iva2_grpsel |= OMAP3430_GRPSEL_GPT5; + mpu_grpsel &= ~OMAP3430_GRPSEL_GPT5; + } else { + mpu_grpsel |= OMAP3430_GRPSEL_GPT5; + iva2_grpsel &= ~OMAP3430_GRPSEL_GPT5; + } + *((REG_UWORD32 *) ((u32) (resources.dwPerPmBase) + 0xA8)) + = iva2_grpsel; + *((REG_UWORD32 *) ((u32) (resources.dwPerPmBase) + 0xA4)) + = mpu_grpsel; + break; + case BPWR_GPTimer6: + iva2_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerPmBase) + 0xA8)); + mpu_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerPmBase) + 0xA4)); + if (enable) { + iva2_grpsel |= OMAP3430_GRPSEL_GPT6; + mpu_grpsel &= ~OMAP3430_GRPSEL_GPT6; + } else { + mpu_grpsel |= OMAP3430_GRPSEL_GPT6; + iva2_grpsel &= ~OMAP3430_GRPSEL_GPT6; + } + *((REG_UWORD32 *) ((u32) (resources.dwPerPmBase) + 0xA8)) + = iva2_grpsel; + *((REG_UWORD32 *) ((u32) (resources.dwPerPmBase) + 0xA4)) + = mpu_grpsel; + break; + case BPWR_GPTimer7: + iva2_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerPmBase) + 0xA8)); + mpu_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerPmBase) + 0xA4)); + if (enable) { + iva2_grpsel |= OMAP3430_GRPSEL_GPT7; + mpu_grpsel &= ~OMAP3430_GRPSEL_GPT7; + } else { + mpu_grpsel |= OMAP3430_GRPSEL_GPT7; + iva2_grpsel &= ~OMAP3430_GRPSEL_GPT7; + } + *((REG_UWORD32 *) ((u32) (resources.dwPerPmBase) + 0xA8)) + = iva2_grpsel; + *((REG_UWORD32 *) ((u32) (resources.dwPerPmBase) + 0xA4)) + = mpu_grpsel; + break; + case BPWR_GPTimer8: + iva2_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerPmBase) + 0xA8)); + mpu_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerPmBase) + 0xA4)); + if (enable) { + iva2_grpsel |= OMAP3430_GRPSEL_GPT8; + mpu_grpsel &= ~OMAP3430_GRPSEL_GPT8; + } else { + mpu_grpsel |= OMAP3430_GRPSEL_GPT8; + iva2_grpsel &= ~OMAP3430_GRPSEL_GPT8; + } + *((REG_UWORD32 *) ((u32) (resources.dwPerPmBase) + 0xA8)) + = iva2_grpsel; + *((REG_UWORD32 *) ((u32) (resources.dwPerPmBase) + 0xA4)) + = mpu_grpsel; + break; + case BPWR_MCBSP1: + iva2_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwCorePmBase) + 0xA8)); + mpu_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwCorePmBase) + 0xA4)); + if (enable) { + iva2_grpsel |= OMAP3430_GRPSEL_MCBSP1; + mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP1; + } else { + mpu_grpsel |= OMAP3430_GRPSEL_MCBSP1; + iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP1; + } + *((REG_UWORD32 *) ((u32) (resources.dwCorePmBase) + 0xA8)) + = iva2_grpsel; + *((REG_UWORD32 *) ((u32) (resources.dwCorePmBase) + 0xA4)) + = mpu_grpsel; + break; + case BPWR_MCBSP2: + iva2_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerPmBase) + 0xA8)); + mpu_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerPmBase) + 0xA4)); + if (enable) { + iva2_grpsel |= OMAP3430_GRPSEL_MCBSP2; + mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP2; + } else { + mpu_grpsel |= OMAP3430_GRPSEL_MCBSP2; + iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP2; + } + *((REG_UWORD32 *) ((u32) (resources.dwPerPmBase) + 0xA8)) + = iva2_grpsel; + *((REG_UWORD32 *) ((u32) (resources.dwPerPmBase) + 0xA4)) + = mpu_grpsel; + break; + case BPWR_MCBSP3: + iva2_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerPmBase) + 0xA8)); + mpu_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerPmBase) + 0xA4)); + if (enable) { + iva2_grpsel |= OMAP3430_GRPSEL_MCBSP3; + mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP3; + } else { + mpu_grpsel |= OMAP3430_GRPSEL_MCBSP3; + iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP3; + } + *((REG_UWORD32 *) ((u32) (resources.dwPerPmBase) + 0xA8)) + = iva2_grpsel; + *((REG_UWORD32 *) ((u32) (resources.dwPerPmBase) + 0xA4)) + = mpu_grpsel; + break; + case BPWR_MCBSP4: + iva2_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerPmBase) + 0xA8)); + mpu_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwPerPmBase) + 0xA4)); + if (enable) { + iva2_grpsel |= OMAP3430_GRPSEL_MCBSP4; + mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP4; + } else { + mpu_grpsel |= OMAP3430_GRPSEL_MCBSP4; + iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP4; + } + *((REG_UWORD32 *) ((u32) (resources.dwPerPmBase) + 0xA8)) + = iva2_grpsel; + *((REG_UWORD32 *) ((u32) (resources.dwPerPmBase) + 0xA4)) + = mpu_grpsel; + break; + case BPWR_MCBSP5: + iva2_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwCorePmBase) + 0xA8)); + mpu_grpsel = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwCorePmBase) + 0xA4)); + if (enable) { + iva2_grpsel |= OMAP3430_GRPSEL_MCBSP5; + mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP5; + } else { + mpu_grpsel |= OMAP3430_GRPSEL_MCBSP5; + iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP5; + } + *((REG_UWORD32 *) ((u32) (resources.dwCorePmBase) + 0xA8)) + = iva2_grpsel; + *((REG_UWORD32 *) ((u32) (resources.dwCorePmBase) + 0xA4)) + = mpu_grpsel; + break; + } +} diff --git a/drivers/dsp/bridge/wmd/tiomap_io.c b/drivers/dsp/bridge/wmd/tiomap_io.c new file mode 100644 index 0000000..6121e8f --- /dev/null +++ b/drivers/dsp/bridge/wmd/tiomap_io.c @@ -0,0 +1,427 @@ +/* + * tiomap_io.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== _tiomap_io.c ======== + * Description: + * Implementation for the io read/write routines. + * + *! Revision History + *! ================ + *! 16-Feb-2004 vp: Fixed warning in WriteDspData function. + *! 16-Apr-2003 vp: Added support for TC word swap + *! 26-Feb-2003 vp: Fixed issue with EXT_BEG and EXT_END address. + *! 24-Feb-2003 vp: Ported to Linux platform + *! 08-Oct-2002 rr: Created. + */ + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- Platform Manager */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include + +/* ----------------------------------- specific to this file */ +#include "_tiomap.h" +#include "_tiomap_pwr.h" +#include "tiomap_io.h" + +static u32 ulExtBase; +static u32 ulExtEnd; + +static u32 ulShm0End; +static u32 ulDynExtBase; +static u32 ulTraceSecBeg; +static u32 ulTraceSecEnd; +static u32 ulShmBaseVirt; + +bool bSymbolsReloaded = true; + +/* + * ======== ReadExtDspData ======== + * Copies DSP external memory buffers to the host side buffers. + */ +DSP_STATUS ReadExtDspData(struct WMD_DEV_CONTEXT *hDevContext, + OUT u8 *pbHostBuf, u32 dwDSPAddr, + u32 ulNumBytes, u32 ulMemType) +{ + DSP_STATUS status = DSP_SOK; + struct WMD_DEV_CONTEXT *pDevContext = hDevContext; + u32 offset; + u32 ulTLBBaseVirt = 0; + u32 ulShmOffsetVirt = 0; + u32 dwExtProgVirtMem; + u32 dwBaseAddr = pDevContext->dwDspExtBaseAddr; + bool bTraceRead = false; + + DBG_Trace(DBG_ENTER, "ReadExtDspData," + "hDevContext: 0x%x\n\t\tpbHostBuf: 0x%x" + "\n\t\tdwDSPAddr: 0x%x\n\t\tulNumBytes: 0x%x\n\t\t" + "ulMemType: 0x%x\n", pDevContext, pbHostBuf, dwDSPAddr, + ulNumBytes, ulMemType); + + if (!ulShmBaseVirt) { + status = DEV_GetSymbol(pDevContext->hDevObject, + SHMBASENAME, &ulShmBaseVirt); + } + DBC_Assert(ulShmBaseVirt != 0); + + /* Check if it is a read of Trace section */ + if (!ulTraceSecBeg) { + status = DEV_GetSymbol(pDevContext->hDevObject, + DSP_TRACESEC_BEG, &ulTraceSecBeg); + } + DBC_Assert(ulTraceSecBeg != 0); + + if (DSP_SUCCEEDED(status) && !ulTraceSecEnd) { + status = DEV_GetSymbol(pDevContext->hDevObject, + DSP_TRACESEC_END, &ulTraceSecEnd); + } + DBC_Assert(ulTraceSecEnd != 0); + + if (DSP_SUCCEEDED(status)) { + if ((dwDSPAddr <= ulTraceSecEnd) && + (dwDSPAddr >= ulTraceSecBeg)) { + DBG_Trace(DBG_LEVEL5, "Reading from DSP Trace" + "section 0x%x \n", dwDSPAddr); + bTraceRead = true; + } + } + + /* If reading from TRACE, force remap/unmap */ + if ((bTraceRead) && dwBaseAddr) { + dwBaseAddr = 0; + pDevContext->dwDspExtBaseAddr = 0; + } + + if (!dwBaseAddr) { + /* Initialize ulExtBase and ulExtEnd */ + ulExtBase = 0; + ulExtEnd = 0; + + /* Get DYNEXT_BEG, EXT_BEG and EXT_END.*/ + if (DSP_SUCCEEDED(status) && !ulDynExtBase) { + status = DEV_GetSymbol(pDevContext->hDevObject, + DYNEXTBASE, &ulDynExtBase); + } + DBC_Assert(ulDynExtBase != 0); + + if (DSP_SUCCEEDED(status)) { + status = DEV_GetSymbol(pDevContext->hDevObject, + EXTBASE, &ulExtBase); + } + DBC_Assert(ulExtBase != 0); + + if (DSP_SUCCEEDED(status)) { + status = DEV_GetSymbol(pDevContext->hDevObject, + EXTEND, &ulExtEnd); + } + DBC_Assert(ulExtEnd != 0); + + /* Trace buffer is right after the SHM SEG0, + * so set the base address to SHMBASE */ + if (bTraceRead) { + ulExtBase = ulShmBaseVirt; + ulExtEnd = ulTraceSecEnd; + } + + DBC_Assert(ulExtEnd != 0); + DBC_Assert(ulExtEnd > ulExtBase); + + if (ulExtEnd < ulExtBase) + status = DSP_EFAIL; + + if (DSP_SUCCEEDED(status)) { + ulTLBBaseVirt = + pDevContext->aTLBEntry[0].ulDspVa * DSPWORDSIZE; + DBC_Assert(ulTLBBaseVirt <= ulShmBaseVirt); + dwExtProgVirtMem = pDevContext->aTLBEntry[0].ulGppVa; + + if (bTraceRead) { + DBG_Trace(DBG_LEVEL7, "ReadExtDspData: " + "GPP VA pointing to SHMMEMBASE 0x%x \n", + dwExtProgVirtMem); + } else { + ulShmOffsetVirt = ulShmBaseVirt - ulTLBBaseVirt; + ulShmOffsetVirt += PG_ALIGN_HIGH(ulExtEnd - + ulDynExtBase + 1, + HW_PAGE_SIZE_64KB); + dwExtProgVirtMem -= ulShmOffsetVirt; + dwExtProgVirtMem += (ulExtBase - ulDynExtBase); + DBG_Trace(DBG_LEVEL7, "ReadExtDspData: " + "GPP VA pointing to EXTMEMBASE 0x%x \n", + dwExtProgVirtMem); + pDevContext->dwDspExtBaseAddr = + dwExtProgVirtMem; + + /* This dwDspExtBaseAddr will get cleared only when the board is + * stopped. */ + if (!pDevContext->dwDspExtBaseAddr) { + status = DSP_EFAIL; + DBG_Trace(DBG_LEVEL7, "ReadExtDspData: " + "failed to Map the program memory\n"); + } + } + + dwBaseAddr = dwExtProgVirtMem; + } + } + + if (!dwBaseAddr || !ulExtBase || !ulExtEnd) { + DBG_Trace(DBG_LEVEL7, + "Symbols missing for Ext Prog reading \n"); + status = DSP_EFAIL; + } + + offset = dwDSPAddr - ulExtBase; + + if (DSP_SUCCEEDED(status)) + memcpy(pbHostBuf, (u8 *)dwBaseAddr+offset, ulNumBytes); + + return status; +} +/* + * ======== WriteDspData ======== + * purpose: + * Copies buffers to the DSP internal/external memory. + */ +DSP_STATUS WriteDspData(struct WMD_DEV_CONTEXT *hDevContext, IN u8 *pbHostBuf, + u32 dwDSPAddr, u32 ulNumBytes, u32 ulMemType) +{ + u32 offset; + u32 dwBaseAddr = hDevContext->dwDspBaseAddr; + struct CFG_HOSTRES resources; + DSP_STATUS status; + u32 base1, base2, base3; + base1 = OMAP_DSP_MEM1_SIZE; + base2 = OMAP_DSP_MEM2_BASE - OMAP_DSP_MEM1_BASE; + base3 = OMAP_DSP_MEM3_BASE - OMAP_DSP_MEM1_BASE; + DBG_Trace(DBG_ENTER, "Entered WriteDspData \n"); + + status = CFG_GetHostResources( + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); + + offset = dwDSPAddr - hDevContext->dwDSPStartAdd; + if (offset < base1) { + dwBaseAddr = MEM_LinearAddress(resources.dwMemBase[2], + resources.dwMemLength[2]); + } else if (offset > base1 && offset < base2+OMAP_DSP_MEM2_SIZE) { + dwBaseAddr = MEM_LinearAddress(resources.dwMemBase[3], + resources.dwMemLength[3]); + offset = offset - base2; + } else if (offset >= base2+OMAP_DSP_MEM2_SIZE && + offset < base3 + OMAP_DSP_MEM3_SIZE) { + dwBaseAddr = MEM_LinearAddress(resources.dwMemBase[4], + resources.dwMemLength[4]); + offset = offset - base3; + } else{ + status = DSP_EFAIL; + return status; + } + if (ulNumBytes) + memcpy((u8 *) (dwBaseAddr+offset), pbHostBuf, ulNumBytes); + else + *((u32 *) pbHostBuf) = dwBaseAddr+offset; + + return status; +} + +/* + * ======== WriteExtDspData ======== + * purpose: + * Copies buffers to the external memory. + * + */ +DSP_STATUS WriteExtDspData(struct WMD_DEV_CONTEXT *pDevContext, + IN u8 *pbHostBuf, u32 dwDSPAddr, u32 ulNumBytes, + u32 ulMemType, bool bDynamicLoad) +{ + u32 dwBaseAddr = pDevContext->dwDspExtBaseAddr; + u32 dwOffset = 0; + u8 bTempByte1, bTempByte2; + u8 remainByte[4]; + s32 i; + DSP_STATUS retVal = DSP_SOK; + u32 dwExtProgVirtMem; + u32 ulTLBBaseVirt = 0; + u32 ulShmOffsetVirt = 0; + struct CFG_HOSTRES hostRes; + bool bTraceLoad = false; + bTempByte1 = 0x0; + bTempByte2 = 0x0; + + DBG_Trace(DBG_ENTER, "Entered WriteExtDspData dwDSPAddr 0x%x " + "ulNumBytes 0x%x \n", dwDSPAddr, ulNumBytes); + if (bSymbolsReloaded) { + /* Check if it is a load to Trace section */ + retVal = DEV_GetSymbol(pDevContext->hDevObject, + DSP_TRACESEC_BEG, &ulTraceSecBeg); + if (DSP_SUCCEEDED(retVal)) + retVal = DEV_GetSymbol(pDevContext->hDevObject, + DSP_TRACESEC_END, &ulTraceSecEnd); + } + if (DSP_SUCCEEDED(retVal)) { + if ((dwDSPAddr <= ulTraceSecEnd) && + (dwDSPAddr >= ulTraceSecBeg)) { + DBG_Trace(DBG_LEVEL5, "Writing to DSP Trace " + "section 0x%x \n", dwDSPAddr); + bTraceLoad = true; + } + } + + /* If dynamic, force remap/unmap */ + if ((bDynamicLoad || bTraceLoad) && dwBaseAddr) { + dwBaseAddr = 0; + MEM_UnmapLinearAddress((void *)pDevContext->dwDspExtBaseAddr); + pDevContext->dwDspExtBaseAddr = 0x0; + } + if (!dwBaseAddr) { + if (bSymbolsReloaded) + /* Get SHM_BEG EXT_BEG and EXT_END. */ + retVal = DEV_GetSymbol(pDevContext->hDevObject, + SHMBASENAME, &ulShmBaseVirt); + DBC_Assert(ulShmBaseVirt != 0); + if (bDynamicLoad) { + if (DSP_SUCCEEDED(retVal)) { + if (bSymbolsReloaded) + retVal = DEV_GetSymbol(pDevContext-> + hDevObject, DYNEXTBASE, + &ulExtBase); + } + DBC_Assert(ulExtBase != 0); + if (DSP_SUCCEEDED(retVal)) { + /* DR OMAPS00013235 : DLModules array may be + * in EXTMEM. It is expected that DYNEXTMEM and + * EXTMEM are contiguous, so checking for the + * upper bound at EXTEND should be Ok. */ + if (bSymbolsReloaded) + retVal = DEV_GetSymbol(pDevContext-> + hDevObject, EXTEND, &ulExtEnd); + } + } else { + if (bSymbolsReloaded) { + if (DSP_SUCCEEDED(retVal)) + retVal = DEV_GetSymbol(pDevContext-> + hDevObject, EXTBASE, + &ulExtBase); + DBC_Assert(ulExtBase != 0); + if (DSP_SUCCEEDED(retVal)) + retVal = DEV_GetSymbol(pDevContext-> + hDevObject, EXTEND, &ulExtEnd); + } + } + /* Trace buffer it right after the SHM SEG0, so set the + * base address to SHMBASE */ + if (bTraceLoad) + ulExtBase = ulShmBaseVirt; + + DBC_Assert(ulExtEnd != 0); + DBC_Assert(ulExtEnd > ulExtBase); + if (ulExtEnd < ulExtBase) + retVal = DSP_EFAIL; + + if (DSP_SUCCEEDED(retVal)) { + ulTLBBaseVirt = pDevContext->aTLBEntry[0].ulDspVa * + DSPWORDSIZE; + DBC_Assert(ulTLBBaseVirt <= ulShmBaseVirt); + + if (bSymbolsReloaded) { + if (DSP_SUCCEEDED(retVal)) { + retVal = DEV_GetSymbol(pDevContext-> + hDevObject, DSP_TRACESEC_END, + &ulShm0End); + } + if (DSP_SUCCEEDED(retVal)) { + retVal = DEV_GetSymbol(pDevContext-> + hDevObject, DYNEXTBASE, + &ulDynExtBase); + } + } + ulShmOffsetVirt = ulShmBaseVirt - ulTLBBaseVirt; + if (bTraceLoad) { + dwExtProgVirtMem = pDevContext->aTLBEntry[0]. + ulGppVa; + } else { + CFG_GetHostResources( + (struct CFG_DEVNODE *) + DRV_GetFirstDevExtension(), &hostRes); + dwExtProgVirtMem = hostRes.dwMemBase[1]; + dwExtProgVirtMem += (ulExtBase - ulDynExtBase); + } + DBG_Trace(DBG_LEVEL7, "WriteExtDspData: GPP VA " + "pointing to EXTMEMBASE 0x%x \n", + dwExtProgVirtMem); + + pDevContext->dwDspExtBaseAddr = + (u32)MEM_LinearAddress((void *) + TO_VIRTUAL_UNCACHED(dwExtProgVirtMem), ulExtEnd + - ulExtBase); + dwBaseAddr += pDevContext->dwDspExtBaseAddr; + /* This dwDspExtBaseAddr will get cleared only when + * the board is stopped. */ + if (!pDevContext->dwDspExtBaseAddr) { + retVal = DSP_EFAIL; + DBG_Trace(DBG_LEVEL7, "WriteExtDspData: failed " + "to Map the program memory\n"); + } + } + } + if (!dwBaseAddr || !ulExtBase || !ulExtEnd) { + DBG_Trace(DBG_LEVEL7, "Symbols missing for Ext Prog loading\n"); + retVal = DSP_EFAIL; + } + if (DSP_SUCCEEDED(retVal)) { + for (i = 0; i < 4; i++) + remainByte[i] = 0x0; + + dwOffset = dwDSPAddr - ulExtBase; + /* Also make sure the dwDSPAddr is < ulExtEnd */ + if (dwDSPAddr > ulExtEnd || dwOffset > dwDSPAddr) { + DBG_Trace(DBG_LEVEL7, "We can not load at this address " + "dwDSPAddr=0x%x, ulExt/DynBase=0x%x, " + "ulExtEnd=0x%x\n", dwDSPAddr, ulExtBase, + ulExtEnd); + retVal = DSP_EFAIL; + } + } + if (DSP_SUCCEEDED(retVal)) { + if (ulNumBytes) + memcpy((u8 *) dwBaseAddr + dwOffset, pbHostBuf, + ulNumBytes); + else + *((u32 *) pbHostBuf) = dwBaseAddr+dwOffset; + } + /* Unmap here to force remap for other Ext loads */ + if ((bDynamicLoad || bTraceLoad) && pDevContext->dwDspExtBaseAddr) { + MEM_UnmapLinearAddress((void *) pDevContext->dwDspExtBaseAddr); + pDevContext->dwDspExtBaseAddr = 0x0; + } + bSymbolsReloaded = false; + return retVal; +} + diff --git a/drivers/dsp/bridge/wmd/tiomap_io.h b/drivers/dsp/bridge/wmd/tiomap_io.h new file mode 100644 index 0000000..84a7553 --- /dev/null +++ b/drivers/dsp/bridge/wmd/tiomap_io.h @@ -0,0 +1,112 @@ +/* + * tiomap_io.h + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== _tiomap_io.h ======== + * Description: + * Definitions, types and function prototypes for the io + * (r/w external mem). + * + *! Revision History + *! ================ + *! 08-Oct-2002 rr: Created. + */ + +#ifndef _TIOMAP_IO_ +#define _TIOMAP_IO_ + +/* + * Symbol that defines beginning of shared memory. + * For OMAP (Helen) this is the DSP Virtual base address of SDRAM. + * This will be used to program DSP MMU to map DSP Virt to GPP phys. + * (see dspMmuTlbEntry()). + */ +#define SHMBASENAME "SHM_BEG" +#define EXTBASE "EXT_BEG" +#define EXTEND "_EXT_END" +#define DYNEXTBASE "_DYNEXT_BEG" +#define DYNEXTEND "_DYNEXT_END" +#define IVAEXTMEMBASE "_IVAEXTMEM_BEG" +#define IVAEXTMEMEND "_IVAEXTMEM_END" + + +#define DSP_TRACESEC_BEG "_BRIDGE_TRACE_BEG" +#define DSP_TRACESEC_END "_BRIDGE_TRACE_END" + +#define SYS_PUTCBEG "_SYS_PUTCBEG" +#define SYS_PUTCEND "_SYS_PUTCEND" +#define BRIDGE_SYS_PUTC_current "_BRIDGE_SYS_PUTC_current" + + +#define WORDSWAP_ENABLE 0x3 /* Enable word swap */ + +/* + * ======== ReadExtDspData ======== + * Reads it from DSP External memory. The external memory for the DSP + * is configured by the combination of DSP MMU and SHM Memory manager in the CDB + */ +extern DSP_STATUS ReadExtDspData(struct WMD_DEV_CONTEXT *pDevContext, + OUT u8 *pbHostBuf, u32 dwDSPAddr, + u32 ulNumBytes, u32 ulMemType); + +/* + * ======== WriteDspData ======== + */ +extern DSP_STATUS WriteDspData(struct WMD_DEV_CONTEXT *pDevContext, + OUT u8 *pbHostBuf, u32 dwDSPAddr, + u32 ulNumBytes, u32 ulMemType); + +/* + * ======== WriteExtDspData ======== + * Writes to the DSP External memory for external program. + * The ext mem for progra is configured by the combination of DSP MMU and + * SHM Memory manager in the CDB + */ +extern DSP_STATUS WriteExtDspData(struct WMD_DEV_CONTEXT *pDevContext, + IN u8 *pbHostBuf, u32 dwDSPAddr, + u32 ulNumBytes, u32 ulMemType, + bool bDynamicLoad); + +/* + * ======== WriteExt32BitDspData ======== + * Writes 32 bit data to the external memory + */ +extern inline void WriteExt32BitDspData(IN const + struct WMD_DEV_CONTEXT *pDevContext, IN u32 dwDSPAddr, + IN u32 val) +{ + *(u32 *)dwDSPAddr = ((pDevContext->tcWordSwapOn) ? (((val << 16) & + 0xFFFF0000) | ((val >> 16) & 0x0000FFFF)) : val); +} + +/* + * ======== ReadExt32BitDspData ======== + * Reads 32 bit data from the external memory + */ +extern inline u32 ReadExt32BitDspData(IN const struct WMD_DEV_CONTEXT + *pDevContext, IN u32 dwDSPAddr) +{ + u32 retVal; + retVal = *(u32 *)dwDSPAddr; + + retVal = ((pDevContext->tcWordSwapOn) ? (((retVal << 16) + & 0xFFFF0000) | ((retVal >> 16) & 0x0000FFFF)) : retVal); + return retVal; +} + +#endif /* _TIOMAP_IO_ */ + diff --git a/drivers/dsp/bridge/wmd/tiomap_sm.c b/drivers/dsp/bridge/wmd/tiomap_sm.c new file mode 100644 index 0000000..a6d5d62 --- /dev/null +++ b/drivers/dsp/bridge/wmd/tiomap_sm.c @@ -0,0 +1,195 @@ +/* + * tiomap_sm.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include +#include + +#include +#include +#include + +#include + +#include "_tiomap.h" +#include "_tiomap_pwr.h" + +#define MAILBOX_FIFOSTATUS(m) (0x80 + 4 * (m)) + +static inline unsigned int fifo_full(void __iomem *mbox_base, int mbox_id) +{ + return __raw_readl(mbox_base + MAILBOX_FIFOSTATUS(mbox_id)) & 0x1; +} + +DSP_STATUS CHNLSM_EnableInterrupt(struct WMD_DEV_CONTEXT *pDevContext) +{ + DSP_STATUS status = DSP_SOK; + u32 numMbxMsg; + u32 mbxValue; + struct CFG_HOSTRES resources; + u32 devType; + struct IO_MGR *hIOMgr; + + DBG_Trace(DBG_ENTER, "CHNLSM_EnableInterrupt(0x%x)\n", pDevContext); + + /* Read the messages in the mailbox until the message queue is empty */ + + CFG_GetHostResources((struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), + &resources); + DEV_GetDevType(pDevContext->hDevObject, &devType); + status = DEV_GetIOMgr(pDevContext->hDevObject, &hIOMgr); + if (devType == DSP_UNIT) { + HW_MBOX_NumMsgGet(resources.dwMboxBase, + MBOX_DSP2ARM, &numMbxMsg); + while (numMbxMsg != 0) { + HW_MBOX_MsgRead(resources.dwMboxBase, + MBOX_DSP2ARM, + &mbxValue); + numMbxMsg--; + } + /* clear the DSP mailbox as well...*/ + HW_MBOX_NumMsgGet(resources.dwMboxBase, + MBOX_ARM2DSP, &numMbxMsg); + while (numMbxMsg != 0) { + HW_MBOX_MsgRead(resources.dwMboxBase, + MBOX_ARM2DSP, &mbxValue); + numMbxMsg--; + udelay(10); + + HW_MBOX_EventAck(resources.dwMboxBase, MBOX_ARM2DSP, + HW_MBOX_U1_DSP1, + HW_MBOX_INT_NEW_MSG); + } + /* Enable the new message events on this IRQ line */ + HW_MBOX_EventEnable(resources.dwMboxBase, + MBOX_DSP2ARM, + MBOX_ARM, + HW_MBOX_INT_NEW_MSG); + } + + return status; +} + +DSP_STATUS CHNLSM_DisableInterrupt(struct WMD_DEV_CONTEXT *pDevContext) +{ + struct CFG_HOSTRES resources; + + DBG_Trace(DBG_ENTER, "CHNLSM_DisableInterrupt(0x%x)\n", pDevContext); + + CFG_GetHostResources((struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), + &resources); + HW_MBOX_EventDisable(resources.dwMboxBase, MBOX_DSP2ARM, + MBOX_ARM, HW_MBOX_INT_NEW_MSG); + return DSP_SOK; +} + +DSP_STATUS CHNLSM_InterruptDSP2(struct WMD_DEV_CONTEXT *pDevContext, + u16 wMbVal) +{ +#ifdef CONFIG_BRIDGE_DVFS + struct dspbridge_platform_data *pdata = + omap_dspbridge_dev->dev.platform_data; + u32 opplevel = 0; +#endif + struct CFG_HOSTRES resources; + DSP_STATUS status = DSP_SOK; + unsigned long timeout; + u32 temp; + + status = CFG_GetHostResources((struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), + &resources); + if (DSP_FAILED(status)) + return DSP_EFAIL; +#ifdef CONFIG_BRIDGE_DVFS + if (pDevContext->dwBrdState == BRD_DSP_HIBERNATION || + pDevContext->dwBrdState == BRD_HIBERNATION) { + if (pdata->dsp_get_opp) + opplevel = (*pdata->dsp_get_opp)(); + if (opplevel == 1) { + if (pdata->dsp_set_min_opp) + (*pdata->dsp_set_min_opp)(opplevel+1); + } + } +#endif + + if (pDevContext->dwBrdState == BRD_DSP_HIBERNATION || + pDevContext->dwBrdState == BRD_HIBERNATION) { + /* Restore mailbox settings */ + /* Restart the peripheral clocks that were disabled only + * in DSP initiated Hibernation case.*/ + if (pDevContext->dwBrdState == BRD_DSP_HIBERNATION) { + DSP_PeripheralClocks_Enable(pDevContext, NULL); + /* Enabling Dpll in lock mode*/ + temp = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwCmBase) + 0x34)); + temp = (temp & 0xFFFFFFFE) | 0x1; + *((REG_UWORD32 *) ((u32) (resources.dwCmBase) + 0x34)) = + (u32) temp; + temp = (u32) *((REG_UWORD32 *) + ((u32) (resources.dwCmBase) + 0x4)); + temp = (temp & 0xFFFFFC8) | 0x37; + + *((REG_UWORD32 *) ((u32) (resources.dwCmBase) + 0x4)) = + (u32) temp; + } + HW_MBOX_restoreSettings(resources.dwMboxBase); + + /* Access MMU SYS CONFIG register to generate a short wakeup */ + temp = (u32) *((REG_UWORD32 *) ((u32) + (resources.dwDmmuBase) + 0x10)); + + pDevContext->dwBrdState = BRD_RUNNING; + } + timeout = jiffies + msecs_to_jiffies(1); + while (fifo_full((void __iomem *) resources.dwMboxBase, 0)) { + if (time_after(jiffies, timeout)) { + printk(KERN_ERR "dspbridge: timed out waiting for mailbox\n"); + return WMD_E_TIMEOUT; + } + } + DBG_Trace(DBG_LEVEL3, "writing %x to Mailbox\n", + wMbVal); + + HW_MBOX_MsgWrite(resources.dwMboxBase, MBOX_ARM2DSP, + wMbVal); + return DSP_SOK; +} + +bool CHNLSM_ISR(struct WMD_DEV_CONTEXT *pDevContext, bool *pfSchedDPC, + u16 *pwIntrVal) +{ + struct CFG_HOSTRES resources; + u32 numMbxMsg; + u32 mbxValue; + + DBG_Trace(DBG_ENTER, "CHNLSM_ISR(0x%x)\n", pDevContext); + + CFG_GetHostResources((struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources); + + HW_MBOX_NumMsgGet(resources.dwMboxBase, MBOX_DSP2ARM, &numMbxMsg); + + if (numMbxMsg > 0) { + HW_MBOX_MsgRead(resources.dwMboxBase, MBOX_DSP2ARM, &mbxValue); + + HW_MBOX_EventAck(resources.dwMboxBase, MBOX_DSP2ARM, + HW_MBOX_U0_ARM, HW_MBOX_INT_NEW_MSG); + + DBG_Trace(DBG_LEVEL3, "Read %x from Mailbox\n", mbxValue); + *pwIntrVal = (u16) mbxValue; + } + /* Set *pfSchedDPC to true; */ + *pfSchedDPC = true; + return true; +} diff --git a/drivers/dsp/bridge/wmd/ue_deh.c b/drivers/dsp/bridge/wmd/ue_deh.c new file mode 100644 index 0000000..d5551cb --- /dev/null +++ b/drivers/dsp/bridge/wmd/ue_deh.c @@ -0,0 +1,329 @@ +/* + * ue_deh.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2005-2006 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + +/* + * ======== ue_deh.c ======== + * Description: + * Implements upper edge DSP exception handling (DEH) functions. + * + *! Revision History: + *! ================ + *! 03-Jan-2005 hn: Support for IVA DEH. + *! 05-Jan-2004 vp: Updated for the 24xx HW library. + *! 19-Feb-2003 vp: Code review updates. + *! - Cosmetic changes. + *! 18-Oct-2002 sb: Ported to Linux platform. + *! 10-Dec-2001 kc: Updated DSP error reporting in DEBUG mode. + *! 10-Sep-2001 kc: created. + */ + +/* ----------------------------------- Host OS */ +#include + +/* ----------------------------------- DSP/BIOS Bridge */ +#include +#include +#include + +/* ----------------------------------- Trace & Debug */ +#include +#include + +/* ----------------------------------- OS Adaptation Layer */ +#include +#include +#include +#include +#include +#include + +/* ----------------------------------- Link Driver */ +#include + +/* ----------------------------------- Platform Manager */ +#include +#include + +/* ------------------------------------ Hardware Abstraction Layer */ +#include +#include + +/* ----------------------------------- This */ +#include "mmu_fault.h" +#include "_tiomap.h" +#include "_deh.h" +#include "_tiomap_mmu.h" +#include "_tiomap_pwr.h" +#include + +static struct HW_MMUMapAttrs_t mapAttrs = { HW_LITTLE_ENDIAN, + HW_ELEM_SIZE_16BIT, + HW_MMU_CPUES} ; +#define VirtToPhys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) +/* + * ======== WMD_DEH_Create ======== + * Creates DEH manager object. + */ +DSP_STATUS WMD_DEH_Create(OUT struct DEH_MGR **phDehMgr, + struct DEV_OBJECT *hDevObject) +{ + DSP_STATUS status = DSP_SOK; + struct DEH_MGR *pDehMgr = NULL; + struct CFG_HOSTRES cfgHostRes; + struct CFG_DEVNODE *hDevNode; + struct WMD_DEV_CONTEXT *hWmdContext = NULL; + + DBG_Trace(DBG_LEVEL1, "Entering DEH_Create: 0x%x\n", phDehMgr); + /* Message manager will be created when a file is loaded, since + * size of message buffer in shared memory is configurable in + * the base image. */ + /* Get WMD context info. */ + DEV_GetWMDContext(hDevObject, &hWmdContext); + DBC_Assert(hWmdContext); + /* Allocate IO manager object: */ + MEM_AllocObject(pDehMgr, struct DEH_MGR, SIGNATURE); + if (pDehMgr == NULL) { + status = DSP_EMEMORY; + } else { + /* Create an NTFY object to manage notifications */ + if (DSP_SUCCEEDED(status)) + status = NTFY_Create(&pDehMgr->hNtfy); + + /* Create a DPC object. */ + status = DPC_Create(&pDehMgr->hMmuFaultDpc, MMU_FaultDpc, + (void *)pDehMgr); + if (DSP_SUCCEEDED(status)) + status = DEV_GetDevNode(hDevObject, &hDevNode); + + if (DSP_SUCCEEDED(status)) + status = CFG_GetHostResources(hDevNode, &cfgHostRes); + + if (DSP_SUCCEEDED(status)) { + /* Fill in context structure */ + pDehMgr->hWmdContext = hWmdContext; + pDehMgr->errInfo.dwErrMask = 0L; + pDehMgr->errInfo.dwVal1 = 0L; + pDehMgr->errInfo.dwVal2 = 0L; + pDehMgr->errInfo.dwVal3 = 0L; + /* Install ISR function for DSP MMU fault */ + if ((request_irq(INT_DSP_MMU_IRQ, MMU_FaultIsr, 0, + "DspBridge\tiommu fault", (void *)pDehMgr)) == 0) + status = DSP_SOK; + else + status = DSP_EFAIL; + } + } + if (DSP_FAILED(status)) { + /* If create failed, cleanup */ + WMD_DEH_Destroy((struct DEH_MGR *)pDehMgr); + *phDehMgr = NULL; + } else { + *phDehMgr = (struct DEH_MGR *)pDehMgr; + DBG_Trace(DBG_LEVEL1, "ISR_IRQ Object 0x%x \n", + pDehMgr); + } + DBG_Trace(DBG_LEVEL1, "Exiting DEH_Create.\n"); + return status; +} + +/* + * ======== WMD_DEH_Destroy ======== + * Destroys DEH manager object. + */ +DSP_STATUS WMD_DEH_Destroy(struct DEH_MGR *hDehMgr) +{ + DSP_STATUS status = DSP_SOK; + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)hDehMgr; + + DBG_Trace(DBG_LEVEL1, "Entering DEH_Destroy: 0x%x\n", pDehMgr); + if (MEM_IsValidHandle(pDehMgr, SIGNATURE)) { + /* If notification object exists, delete it */ + if (pDehMgr->hNtfy) + (void)NTFY_Delete(pDehMgr->hNtfy); + /* Disable DSP MMU fault */ + free_irq(INT_DSP_MMU_IRQ, pDehMgr); + (void)DPC_Destroy(pDehMgr->hMmuFaultDpc); + /* Deallocate the DEH manager object */ + MEM_FreeObject(pDehMgr); + } + DBG_Trace(DBG_LEVEL1, "Exiting DEH_Destroy.\n"); + return status; +} + +/* + * ======== WMD_DEH_RegisterNotify ======== + * Registers for DEH notifications. + */ +DSP_STATUS WMD_DEH_RegisterNotify(struct DEH_MGR *hDehMgr, u32 uEventMask, + u32 uNotifyType, + struct DSP_NOTIFICATION *hNotification) +{ + DSP_STATUS status = DSP_SOK; + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)hDehMgr; + + DBG_Trace(DBG_LEVEL1, "Entering WMD_DEH_RegisterNotify: 0x%x\n", + pDehMgr); + + if (MEM_IsValidHandle(pDehMgr, SIGNATURE)) { + status = NTFY_Register(pDehMgr->hNtfy, hNotification, + uEventMask, uNotifyType); + } + DBG_Trace(DBG_LEVEL1, "Exiting WMD_DEH_RegisterNotify.\n"); + return status; +} + + +/* + * ======== WMD_DEH_Notify ======== + * DEH error notification function. Informs user about the error. + */ +void WMD_DEH_Notify(struct DEH_MGR *hDehMgr, u32 ulEventMask, + u32 dwErrInfo) +{ + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)hDehMgr; + struct WMD_DEV_CONTEXT *pDevContext; + DSP_STATUS status = DSP_SOK; + u32 memPhysical = 0; + u32 HW_MMU_MAX_TLB_COUNT = 31; + u32 extern faultAddr; + struct CFG_HOSTRES resources; + u32 dummyVaAddr; + HW_STATUS hwStatus; + + status = CFG_GetHostResources( + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), + &resources); + if (DSP_FAILED(status)) + DBG_Trace(DBG_LEVEL7, + "**Failed to get Host Resources in MMU ISR **\n"); + + DBG_Trace(DBG_LEVEL1, "Entering WMD_DEH_Notify: 0x%x, 0x%x\n", pDehMgr, + ulEventMask); + if (MEM_IsValidHandle(pDehMgr, SIGNATURE)) { + printk(KERN_INFO "WMD_DEH_Notify: ********** DEVICE EXCEPTION " + "**********\n"); + pDevContext = (struct WMD_DEV_CONTEXT *)pDehMgr->hWmdContext; + + switch (ulEventMask) { + case DSP_SYSERROR: + /* reset errInfo structure before use */ + pDehMgr->errInfo.dwErrMask = DSP_SYSERROR; + pDehMgr->errInfo.dwVal1 = 0L; + pDehMgr->errInfo.dwVal2 = 0L; + pDehMgr->errInfo.dwVal3 = 0L; + pDehMgr->errInfo.dwVal1 = dwErrInfo; + printk(KERN_ERR "WMD_DEH_Notify: DSP_SYSERROR, errInfo " + "= 0x%x\n", dwErrInfo); + break; + case DSP_MMUFAULT: + /* MMU fault routine should have set err info + * structure */ + pDehMgr->errInfo.dwErrMask = DSP_MMUFAULT; + printk(KERN_INFO "WMD_DEH_Notify: DSP_MMUFAULT," + "errInfo = 0x%x\n", dwErrInfo); + printk(KERN_INFO "WMD_DEH_Notify: DSP_MMUFAULT, High " + "Address = 0x%x\n", + (unsigned int)pDehMgr->errInfo.dwVal1); + printk(KERN_INFO "WMD_DEH_Notify: DSP_MMUFAULT, Low " + "Address = 0x%x\n", + (unsigned int)pDehMgr->errInfo.dwVal2); + printk(KERN_INFO "WMD_DEH_Notify: DSP_MMUFAULT, fault " + "address = 0x%x\n", (unsigned int)faultAddr); + dummyVaAddr = (u32)MEM_Calloc(sizeof(char) * 0x1000, + MEM_PAGED); + memPhysical = (u32)MEM_Calloc(sizeof(char) * 0x1000, + MEM_PAGED); + dummyVaAddr = PG_ALIGN_LOW((u32)dummyVaAddr, + PG_SIZE_4K); + memPhysical = VirtToPhys(dummyVaAddr); + DBG_Trace(DBG_LEVEL6, "WMD_DEH_Notify: DSP_MMUFAULT, " + "mem Physical= 0x%x\n", memPhysical); + pDevContext = (struct WMD_DEV_CONTEXT *) + pDehMgr->hWmdContext; + /* Reset the dynamic mmu index to fixed count if it + * exceeds 31. So that the dynmmuindex is always + * between the range of standard/fixed entries + * and 31. */ + if (pDevContext->numTLBEntries > + HW_MMU_MAX_TLB_COUNT) { + pDevContext->numTLBEntries = pDevContext-> + fixedTLBEntries; + } + DBG_Trace(DBG_LEVEL6, "Adding TLB Entry %d: VA: 0x%x, " + "PA: 0x%x\n", pDevContext-> + numTLBEntries, faultAddr, memPhysical); + if (DSP_SUCCEEDED(status)) { + hwStatus = HW_MMU_TLBAdd(resources.dwDmmuBase, + memPhysical, faultAddr, + HW_PAGE_SIZE_4KB, 1, &mapAttrs, + HW_SET, HW_SET); + } + /* send an interrupt to DSP */ + HW_MBOX_MsgWrite(resources.dwMboxBase, MBOX_ARM2DSP, + MBX_DEH_CLASS | MBX_DEH_EMMU); + /* Clear MMU interrupt */ + HW_MMU_EventAck(resources.dwDmmuBase, + HW_MMU_TRANSLATION_FAULT); + break; + default: + DBG_Trace(DBG_LEVEL6, + "WMD_DEH_Notify: Unknown Error, errInfo = " + "0x%x\n", dwErrInfo); + break; + } + /* Set the Board state as ERROR */ + pDevContext->dwBrdState = BRD_ERROR; + /* Disable all the clocks that were enabled by DSP */ + (void)DSP_PeripheralClocks_Disable(pDevContext, NULL); + /* Call DSP Trace Buffer */ + PrintDspTraceBuffer(hDehMgr->hWmdContext); + + /* Signal DSP error/exception event. */ + NTFY_Notify(pDehMgr->hNtfy, ulEventMask); + } + DBG_Trace(DBG_LEVEL1, "Exiting WMD_DEH_Notify\n"); + +} + +/* + * ======== WMD_DEH_GetInfo ======== + * Retrieves error information. + */ +DSP_STATUS WMD_DEH_GetInfo(struct DEH_MGR *hDehMgr, + struct DSP_ERRORINFO *pErrInfo) +{ + DSP_STATUS status = DSP_SOK; + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)hDehMgr; + + DBC_Require(pDehMgr); + DBC_Require(pErrInfo); + + DBG_Trace(DBG_LEVEL1, "Entering WMD_DEH_GetInfo: 0x%x\n", hDehMgr); + + if (MEM_IsValidHandle(pDehMgr, SIGNATURE)) { + /* Copy DEH error info structure to PROC error info + * structure. */ + pErrInfo->dwErrMask = pDehMgr->errInfo.dwErrMask; + pErrInfo->dwVal1 = pDehMgr->errInfo.dwVal1; + pErrInfo->dwVal2 = pDehMgr->errInfo.dwVal2; + pErrInfo->dwVal3 = pDehMgr->errInfo.dwVal3; + } + + DBG_Trace(DBG_LEVEL1, "Exiting WMD_DEH_GetInfo\n"); + + return status; +} -- 1.5.6.3