summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-platform-kim48
-rw-r--r--arch/arm/common/gic.c9
-rw-r--r--arch/arm/configs/omap4_defconfig320
-rw-r--r--arch/arm/include/asm/cacheflush.h27
-rw-r--r--arch/arm/mach-omap2/Makefile11
-rw-r--r--arch/arm/mach-omap2/board-4430sdp.c196
-rw-r--r--arch/arm/mach-omap2/board-omap4panda.c117
-rw-r--r--arch/arm/mach-omap2/devices.c136
-rw-r--r--arch/arm/mach-omap2/hwspinlocks.c82
-rw-r--r--arch/arm/mach-omap2/id.c20
-rw-r--r--arch/arm/mach-omap2/include/mach/dmm.h128
-rw-r--r--arch/arm/mach-omap2/include/mach/tiler.h396
-rw-r--r--arch/arm/mach-omap2/iommu2.c55
-rw-r--r--arch/arm/mach-omap2/ipu_dev.c388
-rw-r--r--arch/arm/mach-omap2/ipu_drv.c375
-rw-r--r--arch/arm/mach-omap2/ipu_utility.c69
-rw-r--r--arch/arm/mach-omap2/mailbox.c131
-rw-r--r--arch/arm/mach-omap2/omap-iommu.c165
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c4
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2420_data.c81
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_44xx_data.c461
-rw-r--r--arch/arm/mach-omap2/powerdomain.c3
-rw-r--r--arch/arm/mach-omap2/remoteproc44xx.c276
-rw-r--r--arch/arm/mm/cache-fa.S6
-rw-r--r--arch/arm/mm/cache-v3.S29
-rw-r--r--arch/arm/mm/cache-v4.S29
-rw-r--r--arch/arm/mm/cache-v4wb.S6
-rw-r--r--arch/arm/mm/cache-v4wt.S15
-rw-r--r--arch/arm/mm/cache-v6.S6
-rw-r--r--arch/arm/mm/cache-v7.S6
-rw-r--r--arch/arm/mm/proc-arm1020.S6
-rw-r--r--arch/arm/mm/proc-arm1020e.S6
-rw-r--r--arch/arm/mm/proc-arm1022.S6
-rw-r--r--arch/arm/mm/proc-arm1026.S6
-rw-r--r--arch/arm/mm/proc-arm920.S6
-rw-r--r--arch/arm/mm/proc-arm922.S6
-rw-r--r--arch/arm/mm/proc-arm925.S6
-rw-r--r--arch/arm/mm/proc-arm926.S6
-rw-r--r--arch/arm/mm/proc-arm940.S6
-rw-r--r--arch/arm/mm/proc-arm946.S6
-rw-r--r--arch/arm/mm/proc-feroceon.S12
-rw-r--r--arch/arm/mm/proc-mohawk.S6
-rw-r--r--arch/arm/mm/proc-xsc3.S6
-rw-r--r--arch/arm/mm/proc-xscale.S8
-rw-r--r--arch/arm/plat-omap/Kconfig13
-rw-r--r--arch/arm/plat-omap/Makefile5
-rw-r--r--arch/arm/plat-omap/devices.c135
-rw-r--r--arch/arm/plat-omap/dmm_user.c288
-rw-r--r--arch/arm/plat-omap/hwspinlock.c335
-rw-r--r--arch/arm/plat-omap/include/plat/display.h14
-rw-r--r--arch/arm/plat-omap/include/plat/dmm_user.h126
-rw-r--r--arch/arm/plat-omap/include/plat/gpu.h33
-rw-r--r--arch/arm/plat-omap/include/plat/hwspinlock.h29
-rw-r--r--arch/arm/plat-omap/include/plat/io.h1
-rw-r--r--arch/arm/plat-omap/include/plat/iommu.h48
-rw-r--r--arch/arm/plat-omap/include/plat/iommu2.h10
-rw-r--r--arch/arm/plat-omap/include/plat/iovmm.h5
-rw-r--r--arch/arm/plat-omap/include/plat/ipu_dev.h107
-rw-r--r--arch/arm/plat-omap/include/plat/irqs.h12
-rw-r--r--arch/arm/plat-omap/include/plat/mailbox.h4
-rw-r--r--arch/arm/plat-omap/include/plat/mcpdm.h30
-rw-r--r--arch/arm/plat-omap/include/plat/mmc.h2
-rw-r--r--arch/arm/plat-omap/include/plat/omap4-keypad.h3
-rw-r--r--arch/arm/plat-omap/include/plat/omap44xx.h6
-rw-r--r--arch/arm/plat-omap/include/plat/omap_hwmod.h6
-rw-r--r--arch/arm/plat-omap/include/plat/remoteproc.h150
-rw-r--r--arch/arm/plat-omap/include/plat/syntm12xx.h18
-rw-r--r--arch/arm/plat-omap/include/syslink/GlobalTypes.h154
-rw-r--r--arch/arm/plat-omap/include/syslink/_listmp.h68
-rw-r--r--arch/arm/plat-omap/include/syslink/_notify.h83
-rw-r--r--arch/arm/plat-omap/include/syslink/_sysmgr.h50
-rw-r--r--arch/arm/plat-omap/include/syslink/atomic_linux.h104
-rw-r--r--arch/arm/plat-omap/include/syslink/drv_notify.h43
-rw-r--r--arch/arm/plat-omap/include/syslink/gate.h76
-rw-r--r--arch/arm/plat-omap/include/syslink/gate_remote.h33
-rw-r--r--arch/arm/plat-omap/include/syslink/gatehwspinlock.h161
-rw-r--r--arch/arm/plat-omap/include/syslink/gatemp.h246
-rw-r--r--arch/arm/plat-omap/include/syslink/gatemp_ioctl.h177
-rw-r--r--arch/arm/plat-omap/include/syslink/gatempdefs.h128
-rw-r--r--arch/arm/plat-omap/include/syslink/gatepeterson.h145
-rw-r--r--arch/arm/plat-omap/include/syslink/gt.h320
-rw-r--r--arch/arm/plat-omap/include/syslink/heap.h96
-rw-r--r--arch/arm/plat-omap/include/syslink/heapbufmp.h253
-rw-r--r--arch/arm/plat-omap/include/syslink/heapbufmp_ioctl.h232
-rw-r--r--arch/arm/plat-omap/include/syslink/heapmemmp.h252
-rw-r--r--arch/arm/plat-omap/include/syslink/heapmemmp_ioctl.h243
-rw-r--r--arch/arm/plat-omap/include/syslink/host_os.h72
-rw-r--r--arch/arm/plat-omap/include/syslink/igatempsupport.h76
-rw-r--r--arch/arm/plat-omap/include/syslink/igateprovider.h123
-rw-r--r--arch/arm/plat-omap/include/syslink/iobject.h176
-rw-r--r--arch/arm/plat-omap/include/syslink/ipc.h189
-rw-r--r--arch/arm/plat-omap/include/syslink/ipc_ioctl.h113
-rw-r--r--arch/arm/plat-omap/include/syslink/listmp.h146
-rw-r--r--arch/arm/plat-omap/include/syslink/listmp_ioctl.h268
-rw-r--r--arch/arm/plat-omap/include/syslink/messageq.h447
-rw-r--r--arch/arm/plat-omap/include/syslink/messageq_ioctl.h266
-rw-r--r--arch/arm/plat-omap/include/syslink/multiproc.h89
-rw-r--r--arch/arm/plat-omap/include/syslink/multiproc_ioctl.h94
-rw-r--r--arch/arm/plat-omap/include/syslink/nameserver.h157
-rw-r--r--arch/arm/plat-omap/include/syslink/nameserver_ioctl.h261
-rw-r--r--arch/arm/plat-omap/include/syslink/nameserver_remote.h39
-rw-r--r--arch/arm/plat-omap/include/syslink/nameserver_remotenotify.h90
-rw-r--r--arch/arm/plat-omap/include/syslink/notify.h146
-rw-r--r--arch/arm/plat-omap/include/syslink/notify_dispatcher.h158
-rw-r--r--arch/arm/plat-omap/include/syslink/notify_driver.h45
-rw-r--r--arch/arm/plat-omap/include/syslink/notify_driverdefs.h137
-rw-r--r--arch/arm/plat-omap/include/syslink/notify_ducatidriver.h141
-rw-r--r--arch/arm/plat-omap/include/syslink/notify_ioctl.h278
-rw-r--r--arch/arm/plat-omap/include/syslink/notify_setup_proxy.h53
-rw-r--r--arch/arm/plat-omap/include/syslink/notifydefs.h94
-rw-r--r--arch/arm/plat-omap/include/syslink/notifyerr.h198
-rw-r--r--arch/arm/plat-omap/include/syslink/platform.h44
-rw-r--r--arch/arm/plat-omap/include/syslink/platform_mem.h136
-rw-r--r--arch/arm/plat-omap/include/syslink/procmgr.h244
-rw-r--r--arch/arm/plat-omap/include/syslink/sharedregion.h244
-rw-r--r--arch/arm/plat-omap/include/syslink/sharedregion_ioctl.h189
-rw-r--r--arch/arm/plat-omap/include/syslink/sysipc_ioctl.h118
-rw-r--r--arch/arm/plat-omap/include/syslink/sysmemmgr.h179
-rw-r--r--arch/arm/plat-omap/include/syslink/sysmemmgr_ioctl.h130
-rw-r--r--arch/arm/plat-omap/include/syslink/sysmgr.h182
-rw-r--r--arch/arm/plat-omap/include/syslink/transportshm.h220
-rw-r--r--arch/arm/plat-omap/include/syslink/transportshm_setup.h47
-rw-r--r--arch/arm/plat-omap/include/syslink/transportshm_setup_proxy.h48
-rw-r--r--arch/arm/plat-omap/iodmm.c1145
-rw-r--r--arch/arm/plat-omap/iommu-debug.c3
-rw-r--r--arch/arm/plat-omap/iommu.c297
-rw-r--r--arch/arm/plat-omap/iovmm.c9
-rw-r--r--arch/arm/plat-omap/mailbox.c84
-rw-r--r--arch/arm/plat-omap/remoteproc.c587
-rw-r--r--drivers/Kconfig3
-rw-r--r--drivers/Makefile9
-rw-r--r--drivers/bluetooth/Kconfig10
-rw-r--r--drivers/bluetooth/Makefile1
-rw-r--r--drivers/bluetooth/btwilink.c395
-rw-r--r--drivers/dsp/syslink/Kconfig116
-rw-r--r--drivers/dsp/syslink/devh/44xx/Kbuild7
-rw-r--r--drivers/dsp/syslink/devh/44xx/devh44xx.c957
-rw-r--r--drivers/dsp/syslink/devh/Kbuild7
-rw-r--r--drivers/dsp/syslink/devh/devh.c273
-rw-r--r--drivers/dsp/syslink/devh/devh.h87
-rw-r--r--drivers/dsp/syslink/ipu_pm/ipu_pm.c3165
-rw-r--r--drivers/dsp/syslink/ipu_pm/ipu_pm.h565
-rw-r--r--drivers/dsp/syslink/multicore_ipc/Kbuild35
-rw-r--r--drivers/dsp/syslink/multicore_ipc/gate.c69
-rw-r--r--drivers/dsp/syslink/multicore_ipc/gate_remote.c39
-rw-r--r--drivers/dsp/syslink/multicore_ipc/gatehwspinlock.c563
-rw-r--r--drivers/dsp/syslink/multicore_ipc/gatemp.c1858
-rw-r--r--drivers/dsp/syslink/multicore_ipc/gatemp_ioctl.c445
-rw-r--r--drivers/dsp/syslink/multicore_ipc/gatepeterson.c1010
-rw-r--r--drivers/dsp/syslink/multicore_ipc/heap.c114
-rw-r--r--drivers/dsp/syslink/multicore_ipc/heapbufmp.c1555
-rw-r--r--drivers/dsp/syslink/multicore_ipc/heapbufmp_ioctl.c550
-rw-r--r--drivers/dsp/syslink/multicore_ipc/heapmemmp.c1666
-rw-r--r--drivers/dsp/syslink/multicore_ipc/heapmemmp_ioctl.c567
-rw-r--r--drivers/dsp/syslink/multicore_ipc/ipc.c1513
-rw-r--r--drivers/dsp/syslink/multicore_ipc/ipc_drv.c448
-rw-r--r--drivers/dsp/syslink/multicore_ipc/ipc_ioctl.c99
-rw-r--r--drivers/dsp/syslink/multicore_ipc/listmp.c1489
-rw-r--r--drivers/dsp/syslink/multicore_ipc/listmp_ioctl.c657
-rw-r--r--drivers/dsp/syslink/multicore_ipc/messageq.c1643
-rw-r--r--drivers/dsp/syslink/multicore_ipc/messageq_ioctl.c745
-rw-r--r--drivers/dsp/syslink/multicore_ipc/multiproc.c315
-rw-r--r--drivers/dsp/syslink/multicore_ipc/multiproc_ioctl.c229
-rw-r--r--drivers/dsp/syslink/multicore_ipc/nameserver.c1530
-rw-r--r--drivers/dsp/syslink/multicore_ipc/nameserver_ioctl.c686
-rw-r--r--drivers/dsp/syslink/multicore_ipc/nameserver_remote.c46
-rw-r--r--drivers/dsp/syslink/multicore_ipc/nameserver_remotenotify.c824
-rw-r--r--drivers/dsp/syslink/multicore_ipc/platform.c1932
-rw-r--r--drivers/dsp/syslink/multicore_ipc/platform_mem.c325
-rw-r--r--drivers/dsp/syslink/multicore_ipc/sharedregion.c1589
-rw-r--r--drivers/dsp/syslink/multicore_ipc/sharedregion_ioctl.c568
-rw-r--r--drivers/dsp/syslink/multicore_ipc/sysipc_ioctl.c305
-rw-r--r--drivers/dsp/syslink/multicore_ipc/sysmemmgr.c458
-rw-r--r--drivers/dsp/syslink/multicore_ipc/sysmemmgr_ioctl.c227
-rw-r--r--drivers/dsp/syslink/multicore_ipc/sysmgr.c846
-rw-r--r--drivers/dsp/syslink/multicore_ipc/transportshm.c1146
-rw-r--r--drivers/dsp/syslink/multicore_ipc/transportshm_setup.c206
-rw-r--r--drivers/dsp/syslink/notify_ducatidriver/notify_ducati.c1370
-rw-r--r--drivers/dsp/syslink/omap_notify/drv_notify.c1005
-rw-r--r--drivers/dsp/syslink/omap_notify/notify.c1094
-rw-r--r--drivers/dsp/syslink/omap_notify/notify_driver.c186
-rw-r--r--drivers/dsp/syslink/omap_notify/plat/omap4_notify_setup.c165
-rw-r--r--drivers/dsp/syslink/procmgr/Kbuild9
-rw-r--r--drivers/dsp/syslink/procmgr/proc4430/Kbuild9
-rw-r--r--drivers/dsp/syslink/procmgr/proc4430/proc4430.c825
-rw-r--r--drivers/dsp/syslink/procmgr/proc4430/proc4430.h133
-rw-r--r--drivers/dsp/syslink/procmgr/proc4430/proc4430_drv.c433
-rw-r--r--drivers/dsp/syslink/procmgr/proc4430/proc4430_drvdefs.h169
-rw-r--r--drivers/dsp/syslink/procmgr/procdefs.h155
-rw-r--r--drivers/dsp/syslink/procmgr/processor.c293
-rw-r--r--drivers/dsp/syslink/procmgr/processor.h70
-rw-r--r--drivers/dsp/syslink/procmgr/procmgr.c784
-rw-r--r--drivers/dsp/syslink/procmgr/procmgr_drv.c730
-rw-r--r--drivers/dsp/syslink/procmgr/procmgr_drvdefs.h491
-rw-r--r--drivers/gpu/drm/drm_drv.c11
-rw-r--r--drivers/gpu/drm/drm_info.c4
-rw-r--r--drivers/gpu/drm/drm_pci.c17
-rw-r--r--drivers/gpu/drm/drm_platform.c7
-rw-r--r--drivers/input/keyboard/omap4-keypad.c4
-rw-r--r--drivers/input/touchscreen/Kconfig11
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/syntm12xx.c3545
-rw-r--r--drivers/media/Kconfig4
-rw-r--r--drivers/media/radio/Kconfig3
-rw-r--r--drivers/media/radio/Makefile1
-rw-r--r--drivers/media/radio/wl128x/Kconfig17
-rw-r--r--drivers/media/radio/wl128x/Makefile6
-rw-r--r--drivers/media/radio/wl128x/fmdrv.h244
-rw-r--r--drivers/media/radio/wl128x/fmdrv_common.c1688
-rw-r--r--drivers/media/radio/wl128x/fmdrv_common.h402
-rw-r--r--drivers/media/radio/wl128x/fmdrv_rx.c847
-rw-r--r--drivers/media/radio/wl128x/fmdrv_rx.h59
-rw-r--r--drivers/media/radio/wl128x/fmdrv_tx.c425
-rw-r--r--drivers/media/radio/wl128x/fmdrv_tx.h37
-rw-r--r--drivers/media/radio/wl128x/fmdrv_v4l2.c580
-rw-r--r--drivers/media/radio/wl128x/fmdrv_v4l2.h33
-rw-r--r--drivers/media/video/Makefile1
-rw-r--r--drivers/media/video/omap/omap_vout.c6
-rw-r--r--drivers/media/video/tiler/Kconfig126
-rw-r--r--drivers/media/video/tiler/Makefile8
-rw-r--r--drivers/media/video/tiler/_tiler.h148
-rw-r--r--drivers/media/video/tiler/dmm.c231
-rw-r--r--drivers/media/video/tiler/tcm.h309
-rw-r--r--drivers/media/video/tiler/tcm/Makefile2
-rw-r--r--drivers/media/video/tiler/tcm/_tcm-sita.h65
-rw-r--r--drivers/media/video/tiler/tcm/tcm-sita.c934
-rw-r--r--drivers/media/video/tiler/tcm/tcm-sita.h39
-rw-r--r--drivers/media/video/tiler/tcm/tcm-utils.h54
-rw-r--r--drivers/media/video/tiler/tiler-geom.c372
-rw-r--r--drivers/media/video/tiler/tiler-iface.c827
-rw-r--r--drivers/media/video/tiler/tiler-main.c1270
-rw-r--r--drivers/media/video/tiler/tiler-reserve.c550
-rw-r--r--drivers/media/video/tiler/tmm-pat.c300
-rw-r--r--drivers/media/video/tiler/tmm.h109
-rw-r--r--drivers/mfd/Kconfig6
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/twl-core.c6
-rw-r--r--drivers/mfd/twl6040-codec.c707
-rw-r--r--drivers/mfd/twl6040-irq.c196
-rw-r--r--drivers/misc/Kconfig6
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/ti-st/st_core.c413
-rw-r--r--drivers/misc/ti-st/st_kim.c491
-rw-r--r--drivers/misc/ti-st/st_ll.c10
-rw-r--r--drivers/misc/twl6040-vib.c255
-rw-r--r--drivers/net/usb/smsc95xx.c56
-rw-r--r--drivers/net/wireless/wl12xx/sdio.c20
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h4
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/ti-st/Kconfig14
-rw-r--r--drivers/staging/ti-st/Makefile5
-rw-r--r--drivers/staging/ti-st/TODO8
-rw-r--r--drivers/staging/ti-st/bt_drv.c509
-rw-r--r--drivers/staging/ti-st/bt_drv.h61
-rw-r--r--drivers/staging/ti-st/sysfs-uim28
-rw-r--r--drivers/usb/musb/musb_core.c12
-rw-r--r--drivers/usb/musb/omap2430.c2
-rw-r--r--drivers/video/omap2/dss/Kconfig1
-rw-r--r--drivers/video/omap2/dss/core.c3
-rw-r--r--drivers/video/omap2/dss/dispc.c10
-rw-r--r--drivers/video/omap2/dss/display.c49
-rw-r--r--drivers/video/omap2/dss/dsi.c643
-rw-r--r--drivers/video/omap2/dss/dss.c122
-rw-r--r--drivers/video/omap2/dss/dss.h6
-rw-r--r--drivers/video/omap2/dss/dss_features.c152
-rw-r--r--drivers/video/omap2/dss/dss_features.h2
-rw-r--r--drivers/video/omap2/dss/hdmi.c400
-rw-r--r--drivers/video/omap2/dss/hdmi.h222
-rw-r--r--drivers/video/omap2/dss/venc.c6
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c97
-rw-r--r--include/drm/drmP.h4
-rw-r--r--include/linux/i2c/twl.h11
-rw-r--r--include/linux/mfd/twl6040-codec.h243
-rw-r--r--include/linux/ti_wilink_st.h78
-rw-r--r--include/linux/twl6040-vib.h30
-rw-r--r--include/net/bluetooth/hci.h1
-rw-r--r--include/sound/omap-abe-dsp.h19
-rw-r--r--include/sound/pcm.h1
-rw-r--r--include/sound/soc-dai.h49
-rw-r--r--include/sound/soc-dapm.h26
-rw-r--r--include/sound/soc.h87
-rw-r--r--net/bluetooth/hci_core.c6
-rw-r--r--net/bluetooth/hci_event.c4
-rw-r--r--sound/core/pcm_lib.c3
-rw-r--r--sound/core/pcm_native.c7
-rw-r--r--sound/soc/atmel/atmel-pcm.c5
-rw-r--r--sound/soc/au1x/dbdma2.c6
-rw-r--r--sound/soc/codecs/Kconfig1
-rw-r--r--sound/soc/codecs/twl6040.c639
-rw-r--r--sound/soc/codecs/twl6040.h118
-rw-r--r--sound/soc/davinci/davinci-pcm.c5
-rw-r--r--sound/soc/ep93xx/ep93xx-pcm.c5
-rw-r--r--sound/soc/imx/imx-pcm-fiq.c7
-rw-r--r--sound/soc/imx/imx-ssi.c6
-rw-r--r--sound/soc/imx/imx-ssi.h3
-rw-r--r--sound/soc/jz4740/jz4740-pcm.c5
-rw-r--r--sound/soc/omap/Kconfig31
-rw-r--r--sound/soc/omap/Makefile10
-rw-r--r--sound/soc/omap/abe/Makefile11
-rw-r--r--sound/soc/omap/abe/abe_api.c2040
-rw-r--r--sound/soc/omap/abe/abe_api.h516
-rw-r--r--sound/soc/omap/abe/abe_cm_addr.h284
-rw-r--r--sound/soc/omap/abe/abe_dat.c862
-rw-r--r--sound/soc/omap/abe/abe_dbg.c197
-rw-r--r--sound/soc/omap/abe/abe_dbg.h149
-rw-r--r--sound/soc/omap/abe/abe_def.h274
-rw-r--r--sound/soc/omap/abe/abe_define.h65
-rw-r--r--sound/soc/omap/abe/abe_dm_addr.h326
-rw-r--r--sound/soc/omap/abe/abe_ext.c228
-rw-r--r--sound/soc/omap/abe/abe_ext.h222
-rw-r--r--sound/soc/omap/abe/abe_firmware.c24119
-rw-r--r--sound/soc/omap/abe/abe_functionsid.h75
-rw-r--r--sound/soc/omap/abe/abe_fw.h379
-rw-r--r--sound/soc/omap/abe/abe_ini.c2279
-rw-r--r--sound/soc/omap/abe/abe_initxxx_labels.h332
-rw-r--r--sound/soc/omap/abe/abe_irq.c62
-rw-r--r--sound/soc/omap/abe/abe_lib.c394
-rw-r--r--sound/soc/omap/abe/abe_lib.h122
-rw-r--r--sound/soc/omap/abe/abe_main.h48
-rw-r--r--sound/soc/omap/abe/abe_mem.c100
-rw-r--r--sound/soc/omap/abe/abe_ref.h158
-rw-r--r--sound/soc/omap/abe/abe_seq.c248
-rw-r--r--sound/soc/omap/abe/abe_sm_addr.h503
-rw-r--r--sound/soc/omap/abe/abe_taskid.h148
-rw-r--r--sound/soc/omap/abe/abe_typ.h679
-rw-r--r--sound/soc/omap/abe/abe_typedef.h199
-rw-r--r--sound/soc/omap/mcpdm.c470
-rw-r--r--sound/soc/omap/mcpdm.h153
-rw-r--r--sound/soc/omap/omap-abe-coef.h200
-rw-r--r--sound/soc/omap/omap-abe-dsp.c2163
-rw-r--r--sound/soc/omap/omap-abe-dsp.h34
-rw-r--r--sound/soc/omap/omap-abe.c1669
-rw-r--r--sound/soc/omap/omap-abe.h59
-rw-r--r--sound/soc/omap/omap-dmic.c668
-rw-r--r--sound/soc/omap/omap-dmic.h103
-rw-r--r--sound/soc/omap/omap-hdmi.c150
-rw-r--r--sound/soc/omap/omap-hdmi.h36
-rw-r--r--sound/soc/omap/omap-mcbsp.c4
-rw-r--r--sound/soc/omap/omap-mcpdm.c832
-rw-r--r--sound/soc/omap/omap-mcpdm.h131
-rw-r--r--sound/soc/omap/omap-pcm.c19
-rw-r--r--sound/soc/omap/omap4-hdmi-card.c89
-rw-r--r--sound/soc/omap/sdp4430.c757
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.c5
-rw-r--r--sound/soc/s6000/s6000-pcm.c5
-rw-r--r--sound/soc/sh/dma-sh7760.c7
-rw-r--r--sound/soc/sh/fsi.c6
-rw-r--r--sound/soc/sh/siu_pcm.c5
-rw-r--r--sound/soc/soc-core.c546
-rw-r--r--sound/soc/soc-dapm.c380
-rw-r--r--sound/soc/txx9/txx9aclc.c5
352 files changed, 114497 insertions, 3758 deletions
diff --git a/Documentation/ABI/testing/sysfs-platform-kim b/Documentation/ABI/testing/sysfs-platform-kim
new file mode 100644
index 00000000000..c1653271872
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-kim
@@ -0,0 +1,48 @@
+What: /sys/devices/platform/kim/dev_name
+Date: January 2010
+KernelVersion: 2.6.38
+Contact: "Pavan Savoy" <pavan_savoy@ti.com>
+Description:
+ Name of the UART device at which the WL128x chip
+ is connected. example: "/dev/ttyS0".
+ The device name flows down to architecture specific board
+ initialization file from the SFI/ATAGS bootloader
+ firmware. The name exposed is read from the user-space
+ dameon and opens the device when install is requested.
+
+What: /sys/devices/platform/kim/baud_rate
+Date: January 2010
+KernelVersion: 2.6.38
+Contact: "Pavan Savoy" <pavan_savoy@ti.com>
+Description:
+ The maximum reliable baud-rate the host can support.
+ Different platforms tend to have different high-speed
+ UART configurations, so the baud-rate needs to be set
+ locally and also sent across to the WL128x via a HCI-VS
+ command. The entry is read and made use by the user-space
+ daemon when the ldisc install is requested.
+
+What: /sys/devices/platform/kim/flow_cntrl
+Date: January 2010
+KernelVersion: 2.6.38
+Contact: "Pavan Savoy" <pavan_savoy@ti.com>
+Description:
+ The WL128x makes use of flow control mechanism, and this
+ entry most often should be 1, the host's UART is required
+ to have the capability of flow-control, or else this
+ entry can be made use of for exceptions.
+
+What: /sys/devices/platform/kim/install
+Date: January 2010
+KernelVersion: 2.6.38
+Contact: "Pavan Savoy" <pavan_savoy@ti.com>
+Description:
+ When one of the protocols Bluetooth, FM or GPS wants to make
+ use of the shared UART transport, it registers to the shared
+ transport driver, which will signal the user-space for opening,
+ configuring baud and install line discipline via this sysfs
+ entry. This entry would be polled upon by the user-space
+ daemon managing the UART, and is notified about the change
+ by the sysfs_notify. The value would be '1' when UART needs
+ to be opened/ldisc installed, and would be '0' when UART
+ is no more required and needs to be closed.
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index cb6b041c39d..74511c29e33 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -269,6 +269,15 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
void __iomem *base = gic->dist_base;
u32 cpumask = 1 << smp_processor_id();
+ /*
+ * HACK: Panda sound does not work with gic_set_type
+ * enabled. Kill it on Omap44xx until a proper fix is
+ * available
+ */
+
+ if (cpu_is_omap44xx())
+ gic_chip.irq_set_type = NULL;
+
cpumask |= cpumask << 8;
cpumask |= cpumask << 16;
diff --git a/arch/arm/configs/omap4_defconfig b/arch/arm/configs/omap4_defconfig
new file mode 100644
index 00000000000..5166b727ba4
--- /dev/null
+++ b/arch/arm/configs/omap4_defconfig
@@ -0,0 +1,320 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_NAMESPACES=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_XZ=y
+CONFIG_RD_LZO=y
+CONFIG_EXPERT=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+# CONFIG_PERF_EVENTS is not set
+CONFIG_PERF_COUNTERS=y
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_ARCH_OMAP=y
+CONFIG_OMAP_SMARTREFLEX=y
+CONFIG_OMAP_SMARTREFLEX_CLASS3=y
+CONFIG_OMAP_MUX_DEBUG=y
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARM_THUMBEE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_HIGHMEM=y
+CONFIG_LEDS=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200"
+CONFIG_KEXEC=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEBUG=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_FPE_NWFPE=y
+CONFIG_BINFMT_MISC=y
+CONFIG_PM_DEBUG=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_WILINK=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_REG_DEBUG=y
+CONFIG_CFG80211_DEBUGFS=y
+CONFIG_LIB80211=y
+CONFIG_MAC80211=y
+CONFIG_MAC80211_MESH=y
+CONFIG_MAC80211_DEBUGFS=y
+CONFIG_MAC80211_DEBUG_MENU=y
+CONFIG_MAC80211_VERBOSE_DEBUG=y
+CONFIG_RFKILL=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_CONNECTOR=y
+CONFIG_MTD=y
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_OOPS=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_ARM_INTEGRATOR=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_OMAP2=y
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+CONFIG_MTD_ONENAND_OMAP2=y
+CONFIG_MTD_UBI=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_MISC_DEVICES=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_NETDEVICES=y
+CONFIG_SMSC_PHY=y
+CONFIG_NET_ETHERNET=y
+CONFIG_SMC91X=y
+CONFIG_SMSC911X=y
+CONFIG_KS8851=y
+CONFIG_KS8851_MLL=y
+# CONFIG_NETDEV_10000 is not set
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_LIBERTAS_DEBUG=y
+CONFIG_WL12XX_MENU=m
+CONFIG_WL12XX=m
+CONFIG_WL12XX_HT=y
+CONFIG_WL12XX_SDIO=m
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_INPUT_JOYDEV=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_OMAP4=y
+CONFIG_KEYBOARD_TWL4030=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_TWL4030_PWRBUTTON=y
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_HW_RANDOM=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_SPI=y
+CONFIG_SPI_OMAP24XX=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_TWL4030=y
+CONFIG_W1=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_OMAP_WATCHDOG=y
+CONFIG_TWL4030_WATCHDOG=y
+CONFIG_REGULATOR_DUMMY=y
+CONFIG_REGULATOR_TWL4030=y
+CONFIG_REGULATOR_TPS65023=y
+CONFIG_REGULATOR_TPS6507X=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_MEDIA_TUNER_SIMPLE is not set
+# CONFIG_MEDIA_TUNER_TDA8290 is not set
+# CONFIG_MEDIA_TUNER_TDA827X is not set
+# CONFIG_MEDIA_TUNER_TDA18271 is not set
+# CONFIG_MEDIA_TUNER_TDA9887 is not set
+# CONFIG_MEDIA_TUNER_TEA5761 is not set
+CONFIG_VIDEO_OMAP2_VOUT=y
+CONFIG_RADIO_WL1273=m
+CONFIG_RADIO_WL128X=y
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+CONFIG_OMAP2_VRAM_SIZE=32
+CONFIG_OMAP2_DSS_DSI=y
+CONFIG_OMAP2_DSS_FAKE_VSYNC=y
+CONFIG_FB_OMAP2=y
+CONFIG_FB_OMAP2_NUM_FBS=2
+CONFIG_PANEL_GENERIC_DPI=y
+CONFIG_PANEL_TAAL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_PLATFORM=y
+CONFIG_DISPLAY_SUPPORT=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_FONT_ACORN_8x8=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_DEBUG=y
+CONFIG_SND_DEBUG_VERBOSE=y
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_SOC=y
+CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_OMAP_SOC_OVERO=y
+CONFIG_SND_OMAP_SOC_OMAP3EVM=y
+CONFIG_SND_OMAP_SOC_AM3517EVM=y
+CONFIG_SND_OMAP_SOC_SDP3430=y
+CONFIG_SND_OMAP_SOC_SDP4430=y
+CONFIG_SND_OMAP_SOC_OMAP4_HDMI=y
+CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=y
+CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE=y
+CONFIG_SND_OMAP_SOC_ZOOM2=y
+CONFIG_SND_OMAP_SOC_IGEP0020=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_MON=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_OMAP2PLUS=y
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_WDM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_TEST=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_SDIO_UART=y
+CONFIG_MMC_OMAP=y
+CONFIG_MMC_OMAP_HS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_TWL4030=y
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_HWSPINLOCK=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_QUOTA=y
+CONFIG_QFMT_V2=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RUBIN=y
+CONFIG_UBIFS_FS=y
+CONFIG_CRAMFS=y
+CONFIG_MINIX_FS=y
+CONFIG_ROMFS_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+CONFIG_SECURITY=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC7=y
+CONFIG_LIBCRC32C=y
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index d5d8d5c7268..8037013e8fd 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -87,6 +87,21 @@
* DMA Cache Coherency
* ===================
*
+ * dma_inv_range(start, end)
+ *
+ * Invalidate (discard) the specified virtual address range.
+ * May not write back any entries. If 'start' or 'end'
+ * are not cache line aligned, those lines must be written
+ * back.
+ * - start - virtual start address
+ * - end - virtual end address
+ *
+ * dma_clean_range(start, end)
+ *
+ * Clean (write back) the specified virtual address range.
+ * - start - virtual start address
+ * - end - virtual end address
+ *
* dma_flush_range(start, end)
*
* Clean and invalidate the specified virtual address range.
@@ -107,6 +122,8 @@ struct cpu_cache_fns {
void (*dma_map_area)(const void *, size_t, int);
void (*dma_unmap_area)(const void *, size_t, int);
+ void (*dma_inv_range)(const void *, const void *);
+ void (*dma_clean_range)(const void *, const void *);
void (*dma_flush_range)(const void *, const void *);
};
@@ -133,6 +150,8 @@ extern struct cpu_cache_fns cpu_cache;
*/
#define dmac_map_area cpu_cache.dma_map_area
#define dmac_unmap_area cpu_cache.dma_unmap_area
+#define dmac_inv_range cpu_cache.dma_inv_range
+#define dmac_clean_range cpu_cache.dma_clean_range
#define dmac_flush_range cpu_cache.dma_flush_range
#else
@@ -151,8 +170,16 @@ extern void __cpuc_flush_dcache_area(void *, size_t);
* is visible to DMA, or data written by DMA to system memory is
* visible to the CPU.
*/
+#define dmac_map_area __glue(_CACHE,_dma_map_area)
+#define dmac_unmap_area __glue(_CACHE,_dma_unmap_area)
+#define dmac_inv_range __glue(_CACHE,_dma_inv_range)
+#define dmac_clean_range __glue(_CACHE,_dma_clean_range)
+#define dmac_flush_range __glue(_CACHE,_dma_flush_range)
+
extern void dmac_map_area(const void *, size_t, int);
extern void dmac_unmap_area(const void *, size_t, int);
+extern void dmac_inv_range(const void *, const void *);
+extern void dmac_clean_range(const void *, const void *);
extern void dmac_flush_range(const void *, const void *);
#endif
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 394190aef27..93f1352f122 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -168,6 +168,15 @@ obj-$(CONFIG_OMAP_IOMMU) += iommu2.o
iommu-$(CONFIG_OMAP_IOMMU) := omap-iommu.o
obj-y += $(iommu-m) $(iommu-y)
+ifeq ($(CONFIG_OMAP_REMOTE_PROC),y)
+#obj-$(CONFIG_ARCH_OMAP2) += remoteproc24xx.o
+#obj-$(CONFIG_ARCH_OMAP3) += remoteproc3xxx.o
+obj-$(CONFIG_ARCH_OMAP4) += remoteproc44xx.o
+obj-$(CONFIG_MPU_SYSLINK_IPC) += ipu_drv.o
+obj-$(CONFIG_MPU_SYSLINK_IPC) += ipu_dev.o
+obj-$(CONFIG_MPU_SYSLINK_IPC) += ipu_utility.o
+endif
+
i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o
obj-y += $(i2c-omap-m) $(i2c-omap-y)
@@ -267,10 +276,10 @@ obj-y += $(nand-m) $(nand-y)
smc91x-$(CONFIG_SMC91X) := gpmc-smc91x.o
obj-y += $(smc91x-m) $(smc91x-y)
+obj-$(CONFIG_ARCH_OMAP4) += hwspinlocks.o
smsc911x-$(CONFIG_SMSC911X) := gpmc-smsc911x.o
obj-y += $(smsc911x-m) $(smsc911x-y)
-obj-$(CONFIG_ARCH_OMAP4) += hwspinlock.o
disp-$(CONFIG_OMAP2_DSS) := display.o
obj-y += $(disp-m) $(disp-y)
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index 56702c5e577..44dc79a33f5 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -37,6 +37,8 @@
#include <plat/mmc.h>
#include <plat/omap4-keypad.h>
#include <plat/display.h>
+#include <plat/nokia-dsi-panel.h>
+#include <plat/syntm12xx.h>
#include "mux.h"
#include "hsmmc.h"
@@ -50,6 +52,10 @@
#define OMAP4_SFH7741_ENABLE_GPIO 188
#define HDMI_GPIO_HPD 60 /* Hot plug pin for HDMI */
#define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */
+#define LCD_BL_GPIO 27
+#define LED_PWM2ON 0x03
+#define LED_PWM2OFF 0x04
+#define TWL6030_TOGGLE3 0x92
static const int sdp4430_keymap[] = {
KEY(0, 0, KEY_E),
@@ -251,6 +257,44 @@ static struct spi_board_info sdp4430_spi_board_info[] __initdata = {
},
};
+/* Begin Synaptic Touchscreen TM-01217 */
+
+static char *tm12xx_idev_names[] = {
+ "Synaptic TM12XX TouchPoint 1",
+ "Synaptic TM12XX TouchPoint 2",
+ "Synaptic TM12XX TouchPoint 3",
+ "Synaptic TM12XX TouchPoint 4",
+ "Synaptic TM12XX TouchPoint 5",
+ "Synaptic TM12XX TouchPoint 6",
+ NULL,
+};
+
+static u8 tm12xx_button_map[] = {
+ KEY_F1,
+ KEY_F2,
+};
+
+static struct tm12xx_ts_platform_data tm12xx_platform_data[] = {
+ { /* Primary Controller */
+ .gpio_intr = 35,
+ .idev_name = tm12xx_idev_names,
+ .button_map = tm12xx_button_map,
+ .num_buttons = ARRAY_SIZE(tm12xx_button_map),
+ .repeat = 0,
+ .swap_xy = 1,
+ },
+ { /* Secondary Controller */
+ .gpio_intr = 36,
+ .idev_name = tm12xx_idev_names,
+ .button_map = tm12xx_button_map,
+ .num_buttons = ARRAY_SIZE(tm12xx_button_map),
+ .repeat = 0,
+ .swap_xy = 1,
+ },
+};
+
+/* End Synaptic Touchscreen TM-01217 */
+
static int omap_ethernet_init(void)
{
int status;
@@ -306,16 +350,55 @@ error1:
return status;
}
-static struct platform_device sdp4430_lcd_device = {
- .name = "sdp4430_lcd",
+int dsi_set_backlight(struct omap_dss_device *dssdev, int level);
+
+static struct nokia_dsi_panel_data dsi1_panel = {
+ .name = "taal",
+ .reset_gpio = 102,
+ .use_ext_te = false,
+ .ext_te_gpio = 101,
+ .use_esd_check = false,
+ .set_backlight = dsi_set_backlight,
+};
+
+static struct omap_dss_device sdp4430_lcd_device = {
+ .name = "lcd",
+ .driver_name = "taal",
+ .type = OMAP_DISPLAY_TYPE_DSI,
+ .data = &dsi1_panel,
+ .phy.dsi = {
+ .clk_lane = 1,
+ .clk_pol = 0,
+ .data1_lane = 2,
+ .data1_pol = 0,
+ .data2_lane = 3,
+ .data2_pol = 0,
+ .div = {
+ .regn = 20, /* 1.92 MHz */
+ .regm = 250, /* 240 MHz */
+ .regm_dispc = 6, /* 160 MHz */
+ .regm_dsi = 6, /* 160 MHz */
+
+ .lp_clk_div = 9, /* 8.88 MHz */
+
+ .lck_div = 1, /* 160 MHz */
+ .pck_div = 4, /* 40 MHz */
+ },
+ },
+ .channel = OMAP_DSS_CHANNEL_LCD,
+};
+
+static struct platform_device sdp4430_hdmi_audio_device = {
+ .name = "hdmi-audio-dai",
.id = -1,
};
static struct platform_device *sdp4430_devices[] __initdata = {
- &sdp4430_lcd_device,
&sdp4430_gpio_keys_device,
&sdp4430_leds_gpio,
&sdp4430_leds_pwm,
+ &sdp4430_lcd_device,
+ &sdp4430_hdmi_audio_device,
};
static struct omap_lcd_config sdp4430_lcd_config __initdata = {
@@ -378,6 +461,10 @@ static struct regulator_consumer_supply sdp4430_vmmc_supply[] = {
.dev_name = "omap_hsmmc.0",
},
};
+static struct regulator_consumer_supply sdp4430_vcxio_supply[] = {
+ REGULATOR_SUPPLY("vdds_dsi", "omapdss_dss"),
+ REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
static int omap4_twl6030_hsmmc_late_init(struct device *dev)
{
@@ -524,7 +611,10 @@ static struct regulator_init_data sdp4430_vcxio = {
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
+ .always_on = true,
},
+ .num_consumer_supplies = ARRAY_SIZE(sdp4430_vcxio_supply),
+ .consumer_supplies = sdp4430_vcxio_supply,
};
static struct regulator_init_data sdp4430_vdac = {
@@ -556,6 +646,27 @@ static struct regulator_init_data sdp4430_clk32kg = {
},
};
+static struct twl4030_codec_audio_data twl6040_audio = {
+ /* single-step ramp for headset and handsfree */
+ .left_step_hs = 0x0f,
+ .right_step_hs = 0x0f,
+ .left_step_hf = 0x1d,
+ .right_step_hf = 0x1d,
+};
+
+static struct twl4030_codec_vibra_data twl6040_vibra = {
+ .max_timeout = 15000,
+ .initial_vibrate = 0,
+};
+
+static struct twl4030_codec_data twl6040_codec = {
+ .audio = &twl6040_audio,
+ .vibra = &twl6040_vibra,
+ .audpwron_gpio = 127,
+ .naudint_irq = OMAP44XX_IRQ_SYS_2N,
+ .irq_base = TWL6040_CODEC_IRQ_BASE,
+};
+
static struct twl4030_platform_data sdp4430_twldata = {
.irq_base = TWL6030_IRQ_BASE,
.irq_end = TWL6030_IRQ_END,
@@ -572,7 +683,10 @@ static struct twl4030_platform_data sdp4430_twldata = {
.vaux2 = &sdp4430_vaux2,
.vaux3 = &sdp4430_vaux3,
.clk32kg = &sdp4430_clk32kg,
- .usb = &omap4_usbphy_data
+ .usb = &omap4_usbphy_data,
+
+ /* children */
+ .codec = &twl6040_codec,
};
static struct i2c_board_info __initdata sdp4430_i2c_boardinfo[] = {
@@ -583,8 +697,18 @@ static struct i2c_board_info __initdata sdp4430_i2c_boardinfo[] = {
.platform_data = &sdp4430_twldata,
},
};
+static struct i2c_board_info __initdata sdp4430_i2c_2_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("tm12xx_ts_primary", 0x4b),
+ .platform_data = &tm12xx_platform_data[0],
+ },
+};
static struct i2c_board_info __initdata sdp4430_i2c_3_boardinfo[] = {
{
+ I2C_BOARD_INFO("tm12xx_ts_secondary", 0x4b),
+ .platform_data = &tm12xx_platform_data[1],
+ },
+ {
I2C_BOARD_INFO("tmp105", 0x48),
},
{
@@ -596,6 +720,7 @@ static struct i2c_board_info __initdata sdp4430_i2c_4_boardinfo[] = {
I2C_BOARD_INFO("hmc5843", 0x1e),
},
};
+
static int __init omap4_i2c_init(void)
{
/*
@@ -604,8 +729,9 @@ static int __init omap4_i2c_init(void)
*/
omap_register_i2c_bus(1, 400, sdp4430_i2c_boardinfo,
ARRAY_SIZE(sdp4430_i2c_boardinfo));
- omap_register_i2c_bus(2, 400, NULL, 0);
- omap_register_i2c_bus(3, 400, sdp4430_i2c_3_boardinfo,
+ omap_register_i2c_bus(2, 400, sdp4430_i2c_2_boardinfo,
+ ARRAY_SIZE(sdp4430_i2c_2_boardinfo));
+ omap_register_i2c_bus(3, 400, sdp4430_i2c_3_boardinfo,
ARRAY_SIZE(sdp4430_i2c_3_boardinfo));
omap_register_i2c_bus(4, 400, sdp4430_i2c_4_boardinfo,
ARRAY_SIZE(sdp4430_i2c_4_boardinfo));
@@ -631,6 +757,52 @@ static void __init omap_sfh7741prox_init(void)
}
}
+int dsi_set_backlight(struct omap_dss_device *dssdev, int level)
+{
+ twl_i2c_write_u8(TWL_MODULE_PWM, 0x7F, LED_PWM2OFF);
+
+ if (level > 1) {
+ if (level == 255)
+ level = 0x7F;
+ else
+ level = (~(level/2)) & 0x7F;
+
+ twl_i2c_write_u8(TWL6030_MODULE_ID1, 0x30, TWL6030_TOGGLE3);
+ twl_i2c_write_u8(TWL_MODULE_PWM, level, LED_PWM2ON);
+ } else if (level <= 1) {
+ twl_i2c_write_u8(TWL6030_MODULE_ID1, 0x08, TWL6030_TOGGLE3);
+ twl_i2c_write_u8(TWL6030_MODULE_ID1, 0x38, TWL6030_TOGGLE3);
+ }
+
+ return 0;
+}
+
+static void sdp4430_lcd_init(void)
+{
+ u32 reg;
+ int status;
+
+ reg = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_DSIPHY);
+ reg |= OMAP4_DSI1_PIPD_MASK | OMAP4_DSI1_LANEENABLE_MASK;
+ omap4_ctrl_pad_writel(reg, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_DSIPHY);
+
+ /* Panel Taal reset and backlight GPIO init */
+ status = gpio_request_one(dsi1_panel.reset_gpio, GPIOF_DIR_OUT,
+ "lcd_reset_gpio");
+ if (status)
+ pr_err("%s: Could not get lcd_reset_gpio\n", __func__);
+
+ if (dsi1_panel.use_ext_te)
+ omap_mux_init_signal("gpmc_ncs4.gpio_101",
+ OMAP_PIN_INPUT_PULLUP);
+
+ status = gpio_request_one(LCD_BL_GPIO, GPIOF_DIR_OUT, "lcd_bl_gpio");
+ if (status)
+ pr_err("%s: Could not get lcd_bl_gpio\n", __func__);
+
+ gpio_set_value(LCD_BL_GPIO, 0);
+}
+
static void sdp4430_hdmi_mux_init(void)
{
/* PAD0_HDMI_HPD_PAD1_HDMI_CEC */
@@ -686,17 +858,19 @@ static struct omap_dss_device sdp4430_hdmi_device = {
};
static struct omap_dss_device *sdp4430_dss_devices[] = {
+ &sdp4430_lcd_device,
&sdp4430_hdmi_device,
};
static struct omap_dss_board_info sdp4430_dss_data = {
.num_devices = ARRAY_SIZE(sdp4430_dss_devices),
.devices = sdp4430_dss_devices,
- .default_device = &sdp4430_hdmi_device,
+ .default_device = &sdp4430_lcd_device,
};
void omap_4430sdp_display_init(void)
{
+ sdp4430_lcd_init();
sdp4430_hdmi_mux_init();
omap_display_init(&sdp4430_dss_data);
}
@@ -797,6 +971,10 @@ static void __init omap_4430sdp_init(void)
usb_musb_init(&musb_board_data);
+ status = omap4_keypad_initialization(&sdp4430_keypad_data);
+ if(status)
+ pr_err("Keypad initialization failed: %d\n", status);
+
status = omap_ethernet_init();
if (status) {
pr_err("Ethernet initialization failed: %d\n", status);
@@ -806,10 +984,6 @@ static void __init omap_4430sdp_init(void)
ARRAY_SIZE(sdp4430_spi_board_info));
}
- status = omap4_keyboard_init(&sdp4430_keypad_data);
- if (status)
- pr_err("Keypad initialization failed: %d\n", status);
-
omap_4430sdp_display_init();
}
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 920b7ba1c45..891a3da88cf 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -30,6 +30,8 @@
#include <linux/wl12xx.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/ti_wilink_st.h>
#include <mach/hardware.h>
#include <mach/omap4-common.h>
@@ -38,6 +40,7 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <plat/display.h>
+#include <plat/panel-generic-dpi.h>
#include <plat/board.h>
#include <plat/common.h>
@@ -50,6 +53,7 @@
#include "control.h"
#include "mux.h"
+
#define GPIO_HUB_POWER 1
#define GPIO_HUB_NRESET 62
#define GPIO_WIFI_PMENA 43
@@ -57,16 +61,6 @@
#define HDMI_GPIO_HPD 60 /* Hot plug pin for HDMI */
#define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */
-/* wl127x BT, FM, GPS connectivity chip */
-static int wl1271_gpios[] = {46, -1, -1};
-static struct platform_device wl1271_device = {
- .name = "kim",
- .id = -1,
- .dev = {
- .platform_data = &wl1271_gpios,
- },
-};
-
static struct gpio_led gpio_leds[] = {
{
.name = "pandaboard::status1",
@@ -93,11 +87,78 @@ static struct platform_device leds_gpio = {
},
};
+static struct platform_device omap4panda_hdmi_audio_device = {
+ .name = "hdmi-audio-dai",
+ .id = -1,
+};
+
+struct ti_st_plat_data wilink_pdata = {
+ .nshutdown_gpio = 46,
+ .dev_name = "/dev/ttyO1",
+ .flow_cntrl = 1,
+ .baud_rate = 3000000,
+};
+static struct platform_device wl128x_device = {
+ .name = "kim",
+ .id = -1,
+ .dev.platform_data = &wilink_pdata,
+};
+static struct platform_device btwilink_device = {
+ .name = "btwilink",
+ .id = -1,
+};
+
static struct platform_device *panda_devices[] __initdata = {
&leds_gpio,
- &wl1271_device,
+ &omap4panda_hdmi_audio_device,
+ &wl128x_device,
+ &btwilink_device,
+};
+
+/* Display DVI */
+#define PANDA_DVI_TFP410_POWER_DOWN_GPIO 0
+
+static int panda_enable_dvi(struct omap_dss_device *dssdev)
+{
+ gpio_set_value(dssdev->reset_gpio, 1);
+ return 0;
+}
+
+static void panda_disable_dvi(struct omap_dss_device *dssdev)
+{
+ gpio_set_value(dssdev->reset_gpio, 0);
+}
+
+/* Using generic display panel */
+static struct panel_generic_dpi_data dvi_panel = {
+ .name = "generic",
+ .platform_enable = panda_enable_dvi,
+ .platform_disable = panda_disable_dvi,
+};
+
+struct omap_dss_device panda_dvi_device = {
+ .type = OMAP_DISPLAY_TYPE_DPI,
+ .name = "dvi",
+ .driver_name = "generic_dpi_panel",
+ .data = &dvi_panel,
+ .phy.dpi.data_lines = 24,
+ .reset_gpio = PANDA_DVI_TFP410_POWER_DOWN_GPIO,
+ .channel = OMAP_DSS_CHANNEL_LCD2,
};
+int __init panda_dvi_init(void)
+{
+ int r;
+
+ /* Requesting TFP410 DVI GPIO and disabling it, at bootup */
+ r = gpio_request_one(panda_dvi_device.reset_gpio,
+ GPIOF_OUT_INIT_LOW, "DVI PD");
+ if (r)
+ pr_err("Failed to get DVI powerdown GPIO\n");
+
+ return r;
+}
+
static void __init omap4_panda_init_early(void)
{
omap2_init_common_infrastructure();
@@ -393,6 +454,20 @@ static struct regulator_init_data omap4_panda_clk32kg = {
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
};
+static struct twl4030_codec_audio_data twl6040_audio = {
+ /* single-step ramp for headset and handsfree */
+ .left_step_hs = 0x0f,
+ .right_step_hs = 0x0f,
+ .left_step_hf = 0x1d,
+ .right_step_hf = 0x1d,
+};
+
+static struct twl4030_codec_data twl6040_codec = {
+ .audio = &twl6040_audio,
+ .audpwron_gpio = 127,
+ .naudint_irq = OMAP44XX_IRQ_SYS_2N,
+ .irq_base = TWL6040_CODEC_IRQ_BASE,
+};
static struct twl4030_platform_data omap4_panda_twldata = {
.irq_base = TWL6030_IRQ_BASE,
@@ -409,6 +484,9 @@ static struct twl4030_platform_data omap4_panda_twldata = {
.vaux3 = &omap4_panda_vaux3,
.clk32kg = &omap4_panda_clk32kg,
.usb = &omap4_usbphy_data,
+
+ /* children */
+ .codec = &twl6040_codec,
};
static struct i2c_board_info __initdata omap4_panda_i2c_boardinfo[] = {
@@ -522,6 +600,19 @@ static struct omap_board_mux board_mux[] __initdata = {
OMAP4_MUX(DPM_EMU18, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
/* dispc2_data0 */
OMAP4_MUX(DPM_EMU19, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* WLAN IRQ - GPIO 53 */
+ OMAP4_MUX(GPMC_NCS3, OMAP_MUX_MODE3 | OMAP_PIN_INPUT),
+ /* WLAN POWER ENABLE - GPIO 43 */
+ OMAP4_MUX(GPMC_A19, OMAP_MUX_MODE3 | OMAP_PIN_OUTPUT),
+ /* WLAN SDIO: MMC5 CMD */
+ OMAP4_MUX(SDMMC5_CMD, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ /* WLAN SDIO: MMC5 CLK */
+ OMAP4_MUX(SDMMC5_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ /* WLAN SDIO: MMC5 DAT[0-3] */
+ OMAP4_MUX(SDMMC5_DAT0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP4_MUX(SDMMC5_DAT1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP4_MUX(SDMMC5_DAT2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP4_MUX(SDMMC5_DAT3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
@@ -696,13 +787,15 @@ static struct omap_dss_device omap4_panda_hdmi_device = {
static struct omap_dss_device *omap4_panda_dss_devices[] = {
&omap4_panda_dvi_device,
+#ifdef CONFIG_OMAP4_DSS_HDMI
&omap4_panda_hdmi_device,
+#endif
};
static struct omap_dss_board_info omap4_panda_dss_data = {
.num_devices = ARRAY_SIZE(omap4_panda_dss_devices),
.devices = omap4_panda_dss_devices,
- .default_device = &omap4_panda_dvi_device,
+ .default_device = &omap4_panda_hdmi_device,
};
void omap4_panda_display_init(void)
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index d478f53f908..81da896271b 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -29,6 +29,7 @@
#include <mach/gpio.h>
#include <plat/mmc.h>
#include <plat/dma.h>
+#include <plat/gpu.h>
#include <plat/omap_hwmod.h>
#include <plat/omap_device.h>
#include <plat/omap4-keypad.h>
@@ -207,6 +208,8 @@ static inline void omap_init_camera(void)
}
#endif
+#ifdef CONFIG_ARCH_OMAP4 /* KEYBOARD */
+
struct omap_device_pm_latency omap_keyboard_latency[] = {
{
.deactivate_func = omap_device_idle_hwmods,
@@ -215,7 +218,44 @@ struct omap_device_pm_latency omap_keyboard_latency[] = {
},
};
-int __init omap4_keyboard_init(struct omap4_keypad_platform_data
+static int omap4_init_keypad(struct omap_hwmod *oh, void *user)
+{
+ struct omap_device *od;
+ struct omap4_keypad_platform_data *sdp4430_keypad_data;
+ unsigned int id = -1;
+ char *name = "omap4-keypad";
+
+ sdp4430_keypad_data = user;
+
+ od = omap_device_build(name, id, oh, sdp4430_keypad_data,
+ sizeof(struct omap4_keypad_platform_data),
+ omap_keyboard_latency,
+ ARRAY_SIZE(omap_keyboard_latency), 0);
+ WARN(IS_ERR(od), "Could not build omap_device for %s %s\n",
+ name, oh->name);
+
+ return 0;
+}
+
+
+#endif /* KEYBOARD CONFIG_ARCH_OMAP4 */
+
+#if defined(CONFIG_OMAP_MBOX_FWK) || defined(CONFIG_OMAP_MBOX_FWK_MODULE)
+
+#define MBOX_REG_SIZE 0x120
+
+#ifdef CONFIG_ARCH_OMAP2
+static struct resource omap2_mbox_resources[] = {
+ {
+ .start = OMAP24XX_MAILBOX_BASE,
+ .end = OMAP24XX_MAILBOX_BASE + MBOX_REG_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+#endif
+
+
+int __init omap4_keypad_initialization(struct omap4_keypad_platform_data
*sdp4430_keypad_data)
{
struct omap_device *od;
@@ -247,7 +287,7 @@ int __init omap4_keyboard_init(struct omap4_keypad_platform_data
return 0;
}
-#if defined(CONFIG_OMAP_MBOX_FWK) || defined(CONFIG_OMAP_MBOX_FWK_MODULE)
+//#if defined(CONFIG_OMAP_MBOX_FWK) || defined(CONFIG_OMAP_MBOX_FWK_MODULE)
static struct omap_device_pm_latency mbox_latencies[] = {
[0] = {
.activate_func = omap_device_enable_hwmods,
@@ -278,6 +318,39 @@ static inline void omap_init_mbox(void) { }
static inline void omap_init_sti(void) {}
+#if defined CONFIG_ARCH_OMAP4
+
+static struct platform_device codec_dmic0 = {
+ .name = "dmic-codec",
+ .id = 0,
+};
+
+static struct platform_device codec_dmic1 = {
+ .name = "dmic-codec",
+ .id = 1,
+};
+
+static struct platform_device codec_dmic2 = {
+ .name = "dmic-codec",
+ .id = 2,
+};
+
+static struct platform_device omap_abe_dai = {
+ .name = "omap-abe-dai",
+ .id = -1,
+};
+
+static inline void omap_init_abe(void)
+{
+ platform_device_register(&codec_dmic0);
+ platform_device_register(&codec_dmic1);
+ platform_device_register(&codec_dmic2);
+ platform_device_register(&omap_abe_dai);
+}
+#else
+static inline void omap_init_abe(void) {}
+#endif
+
#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
static struct platform_device omap_pcm = {
@@ -659,6 +732,63 @@ static void omap_init_vout(void)
static inline void omap_init_vout(void) {}
#endif
+static struct omap_device_pm_latency omap_gpu_latency[] = {
+ [0] = {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ },
+};
+
+static struct platform_device omap_omaplfb_device = {
+ .name = "omaplfb",
+ .id = -1,
+};
+
+
+static void omap_init_gpu(void)
+{
+ struct omap_hwmod *oh;
+ struct omap_device *od;
+ int max_omap_gpu_hwmod_name_len = 16;
+ char oh_name[max_omap_gpu_hwmod_name_len];
+ int l;
+ struct gpu_platform_data *pdata;
+ char *name = "pvrsrvkm";
+
+ l = snprintf(oh_name, max_omap_gpu_hwmod_name_len,
+ "gpu");
+ WARN(l >= max_omap_gpu_hwmod_name_len,
+ "String buffer overflow in GPU device setup\n");
+
+ oh = omap_hwmod_lookup(oh_name);
+ if (!oh) {
+
+ pr_err("omap_init_gpu: Could not look up %s\n", oh_name);
+ return;
+ }
+
+ pdata = kzalloc(sizeof(struct gpu_platform_data),
+ GFP_KERNEL);
+ if (!pdata) {
+ pr_err("omap_init_gpu: Platform data memory allocation failed\n");
+ return;
+ }
+
+ pdata->device_enable = omap_device_enable;
+ pdata->device_idle = omap_device_idle;
+ pdata->device_shutdown = omap_device_shutdown;
+
+ od = omap_device_build(name, 0, oh, pdata,
+ sizeof(struct gpu_platform_data),
+ omap_gpu_latency, ARRAY_SIZE(omap_gpu_latency), 0);
+ WARN(IS_ERR(od), "Could not build omap_device for %s %s\n",
+ name, oh_name);
+
+ kfree(pdata);
+ platform_device_register(&omap_omaplfb_device);
+}
+
/*-------------------------------------------------------------------------*/
static int __init omap2_init_devices(void)
@@ -667,6 +797,7 @@ static int __init omap2_init_devices(void)
* please keep these calls, and their implementations above,
* in alphabetical order so they're easier to sort through.
*/
+ omap_init_abe();
omap_init_audio();
omap_init_camera();
omap_init_mbox();
@@ -677,6 +808,7 @@ static int __init omap2_init_devices(void)
omap_init_sham();
omap_init_aes();
omap_init_vout();
+ omap_init_gpu();
return 0;
}
diff --git a/arch/arm/mach-omap2/hwspinlocks.c b/arch/arm/mach-omap2/hwspinlocks.c
new file mode 100644
index 00000000000..3c71b92a482
--- /dev/null
+++ b/arch/arm/mach-omap2/hwspinlocks.c
@@ -0,0 +1,82 @@
+/*
+ * OMAP hardware spinlock device initialization
+ *
+ * Copyright (C) 2010 Texas Instruments. All rights reserved.
+ *
+ * Contact: Simon Que <sque@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <plat/hwspinlock.h>
+#include <plat/omap_device.h>
+#include <plat/omap_hwmod.h>
+
+/* Spinlock register offsets */
+#define REVISION_OFFSET 0x0000
+#define SYSCONFIG_OFFSET 0x0010
+#define SYSSTATUS_OFFSET 0x0014
+#define LOCK_BASE_OFFSET 0x0800
+#define LOCK_OFFSET(i) (LOCK_BASE_OFFSET + 0x4 * (i))
+
+struct omap_device_pm_latency omap_spinlock_latency[] = {
+ {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ }
+};
+
+/* Initialization function */
+int __init hwspinlocks_init(void)
+{
+ int retval = 0;
+
+ struct hwspinlock_plat_info *pdata;
+ struct omap_hwmod *oh;
+ char *oh_name, *pdev_name;
+
+ if (!cpu_is_omap44xx())
+ return -EINVAL;
+
+ oh_name = "spinlock";
+ oh = omap_hwmod_lookup(oh_name);
+ if (WARN_ON(oh == NULL))
+ return -EINVAL;
+
+ pdev_name = "hwspinlock";
+
+ /* Pass data to device initialization */
+ pdata = kzalloc(sizeof(struct hwspinlock_plat_info), GFP_KERNEL);
+ if (WARN_ON(pdata == NULL))
+ return -ENOMEM;
+ pdata->sysstatus_offset = SYSSTATUS_OFFSET;
+ pdata->lock_base_offset = LOCK_BASE_OFFSET;
+
+ omap_device_build(pdev_name, 0, oh, pdata,
+ sizeof(struct hwspinlock_plat_info), omap_spinlock_latency,
+ ARRAY_SIZE(omap_spinlock_latency), false);
+
+ return retval;
+}
+postcore_initcall(hwspinlocks_init);
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index e46b430c701..8887a5e69b8 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -141,14 +141,14 @@ static void __init omap24xx_check_revision(void)
dev_type = (prod_id >> 16) & 0x0f;
omap_get_die_id(&odi);
- pr_debug("OMAP_TAP_IDCODE 0x%08x REV %i HAWKEYE 0x%04x MANF %03x\n",
+ pr_info("OMAP_TAP_IDCODE 0x%08x REV %i HAWKEYE 0x%04x MANF %03x\n",
idcode, rev, hawkeye, (idcode >> 1) & 0x7ff);
- pr_debug("OMAP_TAP_DIE_ID_0: 0x%08x\n", odi.id_0);
- pr_debug("OMAP_TAP_DIE_ID_1: 0x%08x DEV_REV: %i\n",
+ pr_info("OMAP_TAP_DIE_ID_0: 0x%08x\n", odi.id_0);
+ pr_info("OMAP_TAP_DIE_ID_1: 0x%08x DEV_REV: %i\n",
odi.id_1, (odi.id_1 >> 28) & 0xf);
- pr_debug("OMAP_TAP_DIE_ID_2: 0x%08x\n", odi.id_2);
- pr_debug("OMAP_TAP_DIE_ID_3: 0x%08x\n", odi.id_3);
- pr_debug("OMAP_TAP_PROD_ID_0: 0x%08x DEV_TYPE: %i\n",
+ pr_info("OMAP_TAP_DIE_ID_2: 0x%08x\n", odi.id_2);
+ pr_info("OMAP_TAP_DIE_ID_3: 0x%08x\n", odi.id_3);
+ pr_info("OMAP_TAP_PROD_ID_0: 0x%08x DEV_TYPE: %i\n",
prod_id, dev_type);
/* Check hawkeye ids */
@@ -333,6 +333,14 @@ static void __init omap4_check_revision(void)
u32 idcode;
u16 hawkeye;
u8 rev;
+ struct omap_die_id odi;
+
+ omap_get_die_id(&odi);
+
+ pr_info("OMAP_TAP_DIE_ID_0: 0x%08x\n", odi.id_0);
+ pr_info("OMAP_TAP_DIE_ID_1: 0x%08x\n", odi.id_1);
+ pr_info("OMAP_TAP_DIE_ID_2: 0x%08x\n", odi.id_2);
+ pr_info("OMAP_TAP_DIE_ID_3: 0x%08x\n", odi.id_3);
/*
* The IC rev detection is done with hawkeye and rev.
diff --git a/arch/arm/mach-omap2/include/mach/dmm.h b/arch/arm/mach-omap2/include/mach/dmm.h
new file mode 100644
index 00000000000..68b798a22c4
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/dmm.h
@@ -0,0 +1,128 @@
+/*
+ * dmm.h
+ *
+ * DMM driver support functions for TI DMM-TILER hardware block.
+ *
+ * Author: David Sin <davidsin@ti.com>
+ *
+ * Copyright (C) 2009-2010 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 DMM_H
+#define DMM_H
+
+#define DMM_BASE 0x4E000000
+#define DMM_SIZE 0x800
+
+#define DMM_REVISION 0x000
+#define DMM_HWINFO 0x004
+#define DMM_LISA_HWINFO 0x008
+#define DMM_DMM_SYSCONFIG 0x010
+#define DMM_LISA_LOCK 0x01C
+#define DMM_LISA_MAP__0 0x040
+#define DMM_LISA_MAP__1 0x044
+#define DMM_TILER_HWINFO 0x208
+#define DMM_TILER_OR__0 0x220
+#define DMM_TILER_OR__1 0x224
+#define DMM_PAT_HWINFO 0x408
+#define DMM_PAT_GEOMETRY 0x40C
+#define DMM_PAT_CONFIG 0x410
+#define DMM_PAT_VIEW__0 0x420
+#define DMM_PAT_VIEW__1 0x424
+#define DMM_PAT_VIEW_MAP__0 0x440
+#define DMM_PAT_VIEW_MAP_BASE 0x460
+#define DMM_PAT_IRQ_EOI 0x478
+#define DMM_PAT_IRQSTATUS_RAW 0x480
+#define DMM_PAT_IRQSTATUS 0x490
+#define DMM_PAT_IRQENABLE_SET 0x4A0
+#define DMM_PAT_IRQENABLE_CLR 0x4B0
+#define DMM_PAT_STATUS__0 0x4C0
+#define DMM_PAT_STATUS__1 0x4C4
+#define DMM_PAT_STATUS__2 0x4C8
+#define DMM_PAT_STATUS__3 0x4CC
+#define DMM_PAT_DESCR__0 0x500
+#define DMM_PAT_AREA__0 0x504
+#define DMM_PAT_CTRL__0 0x508
+#define DMM_PAT_DATA__0 0x50C
+#define DMM_PEG_HWINFO 0x608
+#define DMM_PEG_PRIO 0x620
+#define DMM_PEG_PRIO_PAT 0x640
+
+/**
+ * PAT refill programming mode.
+ */
+enum pat_mode {
+ MANUAL,
+ AUTO
+};
+
+/**
+ * Area definition for DMM physical address translator.
+ */
+struct pat_area {
+ s32 x0:8;
+ s32 y0:8;
+ s32 x1:8;
+ s32 y1:8;
+};
+
+/**
+ * DMM physical address translator control.
+ */
+struct pat_ctrl {
+ s32 start:4;
+ s32 dir:4;
+ s32 lut_id:8;
+ s32 sync:12;
+ s32 ini:4;
+};
+
+/**
+ * PAT descriptor.
+ */
+struct pat {
+ struct pat *next;
+ struct pat_area area;
+ struct pat_ctrl ctrl;
+ u32 data;
+};
+
+/**
+ * DMM device data
+ */
+struct dmm {
+ void __iomem *base;
+};
+
+/**
+ * Create and initialize the physical address translator.
+ * @param id PAT id
+ * @return pointer to device data
+ */
+struct dmm *dmm_pat_init(u32 id);
+
+/**
+ * Program the physical address translator.
+ * @param dmm Device data
+ * @param desc PAT descriptor
+ * @param mode programming mode
+ * @return an error status.
+ */
+s32 dmm_pat_refill(struct dmm *dmm, struct pat *desc, enum pat_mode mode);
+
+/**
+ * Clean up the physical address translator.
+ * @param dmm Device data
+ * @return an error status.
+ */
+void dmm_pat_release(struct dmm *dmm);
+
+#endif
diff --git a/arch/arm/mach-omap2/include/mach/tiler.h b/arch/arm/mach-omap2/include/mach/tiler.h
new file mode 100644
index 00000000000..d72f322696c
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/tiler.h
@@ -0,0 +1,396 @@
+/*
+ * tiler.h
+ *
+ * TILER driver support functions for TI TILER hardware block.
+ *
+ * Authors: Lajos Molnar <molnar@ti.com>
+ * David Sin <davidsin@ti.com>
+ *
+ * Copyright (C) 2009-2010 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 TILER_H
+#define TILER_H
+
+#include <linux/mm.h>
+
+/*
+ * ----------------------------- API Definitions -----------------------------
+ */
+
+/* return true if physical address is in the tiler container */
+bool is_tiler_addr(u32 phys);
+
+enum tiler_fmt {
+ TILFMT_MIN = -2,
+ TILFMT_INVALID = -2,
+ TILFMT_NONE = -1,
+ TILFMT_8BIT = 0,
+ TILFMT_16BIT = 1,
+ TILFMT_32BIT = 2,
+ TILFMT_PAGE = 3,
+ TILFMT_MAX = 3,
+ TILFMT_8AND16 = 4, /* used to mark NV12 reserve block */
+};
+
+/* tiler block info */
+struct tiler_block_t {
+ u32 phys; /* system space (L3) tiler addr */
+ u32 width; /* width */
+ u32 height; /* height */
+ u32 key; /* secret key */
+ u32 id; /* unique block ID */
+};
+
+/* tiler (image/video frame) view */
+struct tiler_view_t {
+ u32 tsptr; /* tiler space addr */
+ u32 width; /* width */
+ u32 height; /* height */
+ u32 bpp; /* bytes per pixel */
+ s32 h_inc; /* horizontal increment */
+ s32 v_inc; /* vertical increment */
+};
+
+/* get the tiler format for a physical address or TILFMT_INVALID */
+enum tiler_fmt tiler_fmt(u32 phys);
+
+/* get the modified (1 for page mode) bytes-per-pixel for a tiler block */
+u32 tiler_bpp(const struct tiler_block_t *b);
+
+/* get tiler block physical stride */
+u32 tiler_pstride(const struct tiler_block_t *b);
+
+/* get tiler block virtual stride */
+static inline u32 tiler_vstride(const struct tiler_block_t *b)
+{
+ return PAGE_ALIGN((b->phys & ~PAGE_MASK) + tiler_bpp(b) * b->width);
+}
+
+/* returns the virtual size of the block (for mmap) */
+static inline u32 tiler_size(const struct tiler_block_t *b)
+{
+ return b->height * tiler_vstride(b);
+}
+
+/* Event types */
+#define TILER_DEVICE_CLOSE 0
+
+/**
+ * Registers a notifier block with TILER driver.
+ *
+ * @param nb notifier_block
+ *
+ * @return error status
+ */
+s32 tiler_reg_notifier(struct notifier_block *nb);
+
+/**
+ * Un-registers a notifier block with TILER driver.
+ *
+ * @param nb notifier_block
+ *
+ * @return error status
+ */
+s32 tiler_unreg_notifier(struct notifier_block *nb);
+
+/**
+ * Reserves a 1D or 2D TILER block area and memory for the
+ * current process with group ID 0.
+ *
+ * @param blk pointer to tiler block data. This must be set up ('phys' member
+ * must be 0) with the tiler block information. 'height' must be 1
+ * for 1D block.
+ * @param fmt TILER block format
+ * @param align block alignment (default: normally PAGE_SIZE)
+ * @param offs block offset
+ *
+ * @return error status
+ */
+s32 tiler_alloc(struct tiler_block_t *blk, enum tiler_fmt fmt, u32 align,
+ u32 offs);
+
+/**
+ * Reserves a 1D or 2D TILER block area and memory for a set process and group
+ * ID.
+ *
+ * @param blk pointer to tiler block data. This must be set up ('phys' member
+ * must be 0) with the tiler block information. 'height' must be 1
+ * for 1D block.
+ * @param fmt TILER block format
+ * @param align block alignment (default: normally PAGE_SIZE)
+ * @param offs block offset
+ * @param gid group ID
+ * @param pid process ID
+ *
+ * @return error status
+ */
+s32 tiler_allocx(struct tiler_block_t *blk, enum tiler_fmt fmt, u32 align,
+ u32 offs, u32 gid, pid_t pid);
+
+/**
+ * Mmaps a portion of a tiler block to a virtual address. Use this method in
+ * your driver's mmap function to potentially combine multiple tiler blocks as
+ * one virtual buffer.
+ *
+ * @param blk pointer to tiler block data
+ * @param offs offset from where to map (must be page aligned)
+ * @param size size of area to map (must be page aligned)
+ * @param vma VMM memory area to map to
+ * @param voffs offset (from vm_start) in the VMM memory area to start
+ * mapping at
+ *
+ * @return error status
+ */
+s32 tiler_mmap_blk(struct tiler_block_t *blk, u32 offs, u32 size,
+ struct vm_area_struct *vma, u32 voffs);
+
+/**
+ * Ioremaps a portion of a tiler block. Use this method in your driver instead
+ * of ioremap to potentially combine multiple tiler blocks as one virtual
+ * buffer.
+ *
+ * @param blk pointer to tiler block data
+ * @param offs offset from where to map (must be page aligned)
+ * @param size size of area to map (must be page aligned)
+ * @param addr virtual address
+ * @param mtype ioremap memory type (e.g. MT_DEVICE)
+ *
+ * @return error status
+ */
+s32 tiler_ioremap_blk(struct tiler_block_t *blk, u32 offs, u32 size, u32 addr,
+ u32 mtype);
+
+/**
+ * Maps an existing buffer to a 1D or 2D TILER area for the
+ * current process with group ID 0.
+ *
+ * Currently, only 1D area mapping is supported.
+ *
+ * NOTE: alignment is always PAGE_SIZE and offset is 0 as full pages are mapped
+ * into tiler container.
+ *
+ * @param blk pointer to tiler block data. This must be set up
+ * ('phys' member must be 0) with the tiler block
+ * information. 'height' must be 1 for 1D block.
+ * @param fmt TILER format
+ * @param usr_addr user space address of existing buffer.
+ *
+ * @return error status
+ */
+s32 tiler_map(struct tiler_block_t *blk, enum tiler_fmt fmt, u32 usr_addr);
+
+/**
+ * Maps an existing buffer to a 1D or 2D TILER area for a set process and group
+ * ID.
+ *
+ * Currently, only 1D area mapping is supported.
+ *
+ * NOTE: alignment is always PAGE_SIZE and offset is 0 as full pages are mapped
+ * into tiler container.
+ *
+ * @param blk pointer to tiler block data. This must be set up
+ * ('phys' member must be 0) with the tiler block
+ * information. 'height' must be 1 for 1D block.
+ * @param fmt TILER format
+ * @param gid group ID
+ * @param pid process ID
+ * @param usr_addr user space address of existing buffer.
+ *
+ * @return error status
+ */
+s32 tiler_mapx(struct tiler_block_t *blk, enum tiler_fmt fmt,
+ u32 gid, pid_t pid, u32 usr_addr);
+
+/**
+ * Frees TILER memory. Since there may be multiple references for the same area
+ * if duplicated by tiler_dup, the area is only actually freed if all references
+ * have been freed.
+ *
+ * @param blk pointer to a tiler block data as filled by tiler_alloc,
+ * tiler_map or tiler_dup. 'phys' and 'id' members will be set to
+ * 0 on success.
+ */
+void tiler_free(struct tiler_block_t *blk);
+
+/**
+ * Reserves tiler area for n identical blocks for the current process. Use this
+ * method to get optimal placement of multiple identical tiler blocks; however,
+ * it may not reserve area if tiler_alloc is equally efficient.
+ *
+ * @param n number of identical set of blocks
+ * @param fmt TILER format
+ * @param width block width
+ * @param height block height (must be 1 for 1D)
+ * @param align block alignment (default: PAGE_SIZE)
+ * @param offs block offset
+ */
+void tiler_reserve(u32 n, enum tiler_fmt fmt, u32 width, u32 height, u32 align,
+ u32 offs);
+
+/**
+ * Reserves tiler area for n identical blocks. Use this method to get optimal
+ * placement of multiple identical tiler blocks; however, it may not reserve
+ * area if tiler_alloc is equally efficient.
+ *
+ * @param n number of identical set of blocks
+ * @param fmt TILER bit mode
+ * @param width block width
+ * @param height block height (must be 1 for 1D)
+ * @param align block alignment (default: PAGE_SIZE)
+ * @param offs block offset
+ * @param gid group ID
+ * @param pid process ID
+ */
+void tiler_reservex(u32 n, enum tiler_fmt fmt, u32 width, u32 height,
+ u32 align, u32 offs, u32 gid, pid_t pid);
+
+/**
+ * Reserves tiler area for n identical NV12 blocks for the current process. Use
+ * this method to get optimal placement of multiple identical NV12 tiler blocks;
+ * however, it may not reserve area if tiler_alloc is equally efficient.
+ *
+ * @param n number of identical set of blocks
+ * @param width block width (Y)
+ * @param height block height (Y)
+ * @param align block alignment (default: PAGE_SIZE)
+ * @param offs block offset
+ */
+void tiler_reserve_nv12(u32 n, u32 width, u32 height, u32 align, u32 offs);
+
+/**
+ * Reserves tiler area for n identical NV12 blocks. Use this method to get
+ * optimal placement of multiple identical NV12 tiler blocks; however, it may
+ * not reserve area if tiler_alloc is equally efficient.
+ *
+ * @param n number of identical set of blocks
+ * @param width block width (Y)
+ * @param height block height (Y)
+ * @param align block alignment (default: PAGE_SIZE)
+ * @param offs block offset
+ * @param gid group ID
+ * @param pid process ID
+ */
+void tiler_reservex_nv12(u32 n, u32 width, u32 height, u32 align, u32 offs,
+ u32 gid, pid_t pid);
+
+/**
+ * Create a view based on a tiler address and width and height
+ *
+ * This method should only be used as a last resort, e.g. if tilview object
+ * cannot be passed because of incoherence with other view 2D objects that must
+ * be supported.
+ *
+ * @param view Pointer to a view where the information will be stored
+ * @param ssptr MUST BE a tiler address
+ * @param width view width
+ * @param height view height
+ */
+void tilview_create(struct tiler_view_t *view, u32 phys, u32 width, u32 height);
+
+/**
+ * Obtains the view information for a tiler block
+ *
+ * @param view Pointer to a view where the information will be stored
+ * @param blk Pointer to an existing allocated tiler block
+ */
+void tilview_get(struct tiler_view_t *view, struct tiler_block_t *blk);
+
+/**
+ * Crops a tiler view to a rectangular portion. Crop area must be fully within
+ * the orginal tiler view: 0 <= left <= left + width <= view->width, also:
+ * 0 <= top <= top + height <= view->height.
+ *
+ * @param view Pointer to tiler view to be cropped
+ * @param left x of top-left corner
+ * @param top y of top-left corner
+ * @param width crop width
+ * @param height crop height
+ *
+ * @return error status. The view will be reduced to the crop region if the
+ * crop region is correct. Otherwise, no modifications are made.
+ */
+s32 tilview_crop(struct tiler_view_t *view, u32 left, u32 top, u32 width,
+ u32 height);
+
+/**
+ * Rotates a tiler view clockwise by a specified degree.
+ *
+ * @param view Pointer to tiler view to be cropped
+ * @param rotate Degree of rotation (clockwise). Must be a multiple of
+ * 90.
+ * @return error status. View is not modified on error; otherwise, it is
+ * updated in place.
+ */
+s32 tilview_rotate(struct tiler_view_t *view, s32 rotation);
+
+/**
+ * Mirrors a tiler view horizontally and/or vertically.
+ *
+ * @param view Pointer to tiler view to be cropped
+ * @param flip_x Mirror horizontally (left-to-right)
+ * @param flip_y Mirror vertically (top-to-bottom)
+ *
+ * @return error status. View is not modified on error; otherwise, it is
+ * updated in place.
+ */
+s32 tilview_flip(struct tiler_view_t *view, bool flip_x, bool flip_y);
+
+/*
+ * ---------------------------- IOCTL Definitions ----------------------------
+ */
+
+/* ioctls */
+#define TILIOC_GBLK _IOWR('z', 100, struct tiler_block_info)
+#define TILIOC_FBLK _IOW('z', 101, struct tiler_block_info)
+#define TILIOC_GSSP _IOWR('z', 102, u32)
+#define TILIOC_MBLK _IOWR('z', 103, struct tiler_block_info)
+#define TILIOC_UMBLK _IOW('z', 104, struct tiler_block_info)
+#define TILIOC_QBUF _IOWR('z', 105, struct tiler_buf_info)
+#define TILIOC_RBUF _IOWR('z', 106, struct tiler_buf_info)
+#define TILIOC_URBUF _IOWR('z', 107, struct tiler_buf_info)
+#define TILIOC_QBLK _IOWR('z', 108, struct tiler_block_info)
+#define TILIOC_PRBLK _IOW('z', 109, struct tiler_block_info)
+#define TILIOC_URBLK _IOW('z', 110, u32)
+
+struct area {
+ u16 width;
+ u16 height;
+};
+
+/* userspace tiler block info */
+struct tiler_block_info {
+ enum tiler_fmt fmt;
+ union {
+ struct area area;
+ u32 len;
+ } dim;
+ u32 stride; /* stride is not maintained for 1D blocks */
+ void *ptr; /* userspace address for mapping existing buffer */
+ u32 id;
+ u32 key;
+ u32 group_id;
+ u32 align; /* alignment requirements for ssptr */
+ u32 offs; /* offset (ssptr & (align - 1) will equal offs) */
+ u32 ssptr; /* physical address, may not exposed by default */
+};
+
+#define TILER_MAX_NUM_BLOCKS 16
+
+/* userspace tiler buffer info */
+struct tiler_buf_info {
+ u32 num_blocks;
+ struct tiler_block_info blocks[TILER_MAX_NUM_BLOCKS];
+ u32 offset;
+ u32 length; /* also used as number of buffers for reservation */
+};
+
+#endif
diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c
index adb083e41ac..ae66be2cb59 100644
--- a/arch/arm/mach-omap2/iommu2.c
+++ b/arch/arm/mach-omap2/iommu2.c
@@ -19,6 +19,7 @@
#include <linux/stringify.h>
#include <plat/iommu.h>
+#include <plat/omap_device.h>
/*
* omap2 architecture specific register bit definitions
@@ -84,11 +85,16 @@ static void __iommu_set_twl(struct iommu *obj, bool on)
iommu_write_reg(obj, l, MMU_CNTL);
}
+static u32 omap2_get_version(struct iommu *obj)
+{
+ return iommu_read_reg(obj, MMU_REVISION);
+}
static int omap2_iommu_enable(struct iommu *obj)
{
u32 l, pa;
unsigned long timeout;
+ int ret = 0;
if (!obj->iopgd || !IS_ALIGNED((u32)obj->iopgd, SZ_16K))
return -EINVAL;
@@ -97,6 +103,10 @@ static int omap2_iommu_enable(struct iommu *obj)
if (!IS_ALIGNED(pa, SZ_16K))
return -EINVAL;
+ ret = omap_device_enable(obj->pdev);
+ if (ret)
+ return ret;
+
iommu_write_reg(obj, MMU_SYS_SOFTRESET, MMU_SYSCONFIG);
timeout = jiffies + msecs_to_jiffies(20);
@@ -124,11 +134,16 @@ static int omap2_iommu_enable(struct iommu *obj)
__iommu_set_twl(obj, true);
+ if (cpu_is_omap44xx())
+ iommu_write_reg(obj, 0x1, MMU_GP_REG);
+
return 0;
}
static void omap2_iommu_disable(struct iommu *obj)
{
+ int ret = 0;
+
u32 l = iommu_read_reg(obj, MMU_CNTL);
l &= ~MMU_CNTL_MASK;
@@ -136,6 +151,8 @@ static void omap2_iommu_disable(struct iommu *obj)
iommu_write_reg(obj, MMU_SYS_IDLE_FORCE, MMU_SYSCONFIG);
dev_dbg(obj->dev, "%s is shutting down\n", obj->name);
+ if (omap_device_shutdown(obj->pdev))
+ dev_err(obj->dev, "%s err 0x%x\n", __func__, ret);
}
static void omap2_iommu_set_twl(struct iommu *obj, bool on)
@@ -168,7 +185,8 @@ static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra)
errs |= OMAP_IOMMU_ERR_TBLWALK_FAULT;
if (stat & MMU_IRQ_MULTIHITFAULT)
errs |= OMAP_IOMMU_ERR_MULTIHIT_FAULT;
- iommu_write_reg(obj, stat, MMU_IRQSTATUS);
+
+ iommu_write_reg(obj, 0, MMU_IRQENABLE);
return errs;
}
@@ -276,41 +294,20 @@ static ssize_t omap2_iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t len)
pr_reg(READ_CAM);
pr_reg(READ_RAM);
pr_reg(EMU_FAULT_AD);
+if (cpu_is_omap44xx()) {
+ pr_reg(FAULT_PC);
+ pr_reg(FAULT_STATUS);
+}
out:
return p - buf;
}
-static void omap2_iommu_save_ctx(struct iommu *obj)
-{
- int i;
- u32 *p = obj->ctx;
-
- for (i = 0; i < (MMU_REG_SIZE / sizeof(u32)); i++) {
- p[i] = iommu_read_reg(obj, i * sizeof(u32));
- dev_dbg(obj->dev, "%s\t[%02d] %08x\n", __func__, i, p[i]);
- }
-
- BUG_ON(p[0] != IOMMU_ARCH_VERSION);
-}
-
-static void omap2_iommu_restore_ctx(struct iommu *obj)
-{
- int i;
- u32 *p = obj->ctx;
-
- for (i = 0; i < (MMU_REG_SIZE / sizeof(u32)); i++) {
- iommu_write_reg(obj, p[i], i * sizeof(u32));
- dev_dbg(obj->dev, "%s\t[%02d] %08x\n", __func__, i, p[i]);
- }
-
- BUG_ON(p[0] != IOMMU_ARCH_VERSION);
-}
-
static void omap2_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
{
e->da = cr->cam & MMU_CAM_VATAG_MASK;
e->pa = cr->ram & MMU_RAM_PADDR_MASK;
e->valid = cr->cam & MMU_CAM_V;
+ e->prsvd = cr->cam & MMU_CAM_P;
e->pgsz = cr->cam & MMU_CAM_PGSZ_MASK;
e->endian = cr->ram & MMU_RAM_ENDIAN_MASK;
e->elsz = cr->ram & MMU_RAM_ELSZ_MASK;
@@ -318,7 +315,7 @@ static void omap2_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
}
static const struct iommu_functions omap2_iommu_ops = {
- .version = IOMMU_ARCH_VERSION,
+ .get_version = omap2_get_version,
.enable = omap2_iommu_enable,
.disable = omap2_iommu_disable,
@@ -336,8 +333,6 @@ static const struct iommu_functions omap2_iommu_ops = {
.get_pte_attr = omap2_get_pte_attr,
- .save_ctx = omap2_iommu_save_ctx,
- .restore_ctx = omap2_iommu_restore_ctx,
.dump_ctx = omap2_iommu_dump_ctx,
};
diff --git a/arch/arm/mach-omap2/ipu_dev.c b/arch/arm/mach-omap2/ipu_dev.c
new file mode 100644
index 00000000000..8ffbfc40907
--- /dev/null
+++ b/arch/arm/mach-omap2/ipu_dev.c
@@ -0,0 +1,388 @@
+/**
+ * linux/arch/arm/mach-omap2/ipu_dev.c
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Paul Hunt <hunt@ti.com>
+ *
+ * OMAP4 Image Processing Unit
+ * 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 <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#include <mach/irqs.h>
+#include <plat/omap_hwmod.h>
+#include <plat/common.h>
+#include <plat/omap_device.h>
+#include <plat/omap-pm.h>
+#include <linux/platform_device.h>
+#include <plat/remoteproc.h>
+
+#include <plat/ipu_dev.h>
+
+#include "../../../drivers/dsp/syslink/ipu_pm/ipu_pm.h"
+
+#define IPU_DRIVER_NAME "omap-ipu-pm"
+#define ISS_IPU_BUS_ID 0
+#define IVA_IPU_BUS_ID 1
+
+struct omap_ipupm_mod_platform_data *ipupm_get_plat_data(void);
+
+static char *hwmod_state_strings[] = {
+ "_HWMOD_STATE_UNKNOWN",
+ "_HWMOD_STATE_REGISTERED",
+ "_HWMOD_STATE_CLKS_INITED",
+ "_HWMOD_STATE_INITIALIZED",
+ "_HWMOD_STATE_ENABLED",
+ "_HWMOD_STATE_IDLE",
+ "_HWMOD_STATE_DISABLED",
+};
+static void print_hwmod_state(struct omap_hwmod *oh, char *desc)
+{
+ u32 _state = (u32) oh->_state;
+ pr_debug("HWMOD name = %s\n", oh->name);
+ if (_state > _HWMOD_STATE_LAST)
+ WARN(1, "Illegal hwmod _state = %d\n", _state);
+ else
+ pr_debug("%s state = %s\n", desc, hwmod_state_strings[_state]);
+}
+
+inline int ipu_pm_module_start(unsigned rsrc)
+{
+ int ret;
+ struct omap_ipupm_mod_platform_data *pd;
+
+ pd = ipupm_get_plat_data();
+
+ print_hwmod_state(pd[rsrc].oh, "Previous");
+ ret = omap_device_enable(pd[rsrc].pdev);
+ if (ret)
+ pr_err("device enable failed %s", pd[rsrc].oh_name);
+ print_hwmod_state(pd[rsrc].oh, "New");
+ return ret;
+}
+EXPORT_SYMBOL(ipu_pm_module_start);
+
+inline int ipu_pm_module_stop(unsigned rsrc)
+{
+ int ret;
+ struct omap_ipupm_mod_platform_data *pd;
+
+ pd = ipupm_get_plat_data();
+
+ print_hwmod_state(pd[rsrc].oh, "Previous");
+ ret = omap_device_shutdown(pd[rsrc].pdev);
+ print_hwmod_state(pd[rsrc].oh, "New");
+
+ if (ret)
+ pr_err("device disable failed %s", pd[rsrc].oh_name);
+
+ return ret;
+}
+EXPORT_SYMBOL(ipu_pm_module_stop);
+
+inline int ipu_pm_module_set_rate(unsigned rsrc,
+ unsigned target_rsrc,
+ unsigned rate)
+{
+ int ret = 0;
+ unsigned target;
+ struct device *dp;
+ struct omap_ipupm_mod_platform_data *pd;
+
+ pd = ipupm_get_plat_data();
+
+ if (target_rsrc == IPU_PM_MPU)
+ dp = omap2_get_mpuss_device();
+ else if (target_rsrc == IPU_PM_CORE)
+ dp = omap2_get_l3_device();
+ else {
+ if (target_rsrc == IPU_PM_SELF)
+ target = rsrc;
+ else
+ target = target_rsrc;
+
+ if ((pd[target].caps & IPUPM_CAPS_PERF) == 0) {
+ pr_err("device set rate not supported for %s",
+ pd[target].oh_name);
+ ret = -EINVAL;
+ goto err_ret;
+ } else
+ dp = pd[target].dev;
+ }
+#ifdef CONFIG_OMAP_PM
+ ret = omap_device_set_rate(pd[rsrc].dev, dp, rate);
+#endif
+ if (ret)
+ pr_err("device set rate failed %s", pd[target_rsrc].oh_name);
+err_ret:
+ return ret;
+}
+EXPORT_SYMBOL(ipu_pm_module_set_rate);
+
+inline int ipu_pm_module_set_latency(unsigned rsrc,
+ unsigned target_rsrc,
+ int latency)
+{
+ int ret = 0;
+ unsigned target;
+ struct omap_ipupm_mod_platform_data *pd;
+
+ pd = ipupm_get_plat_data();
+
+ if (target_rsrc == IPU_PM_MPU) {
+#ifdef CONFIG_OMAP_PM
+ ret = omap_pm_set_max_mpu_wakeup_lat(&pd[rsrc].qos_request,
+ latency);
+#endif
+ if (ret)
+ goto err_ret;
+ } else if (target_rsrc == IPU_PM_CORE) {
+#ifdef CONFIG_OMAP_PM
+ ret = omap_pm_set_max_sdma_lat(&pd[rsrc].qos_request,
+ latency);
+#endif
+ if (ret)
+ goto err_ret;
+ } else {
+ if (target_rsrc == IPU_PM_SELF)
+ target = rsrc;
+ else
+ target = target_rsrc;
+
+ if ((pd[target].caps & IPUPM_CAPS_LAT) == 0) {
+ pr_err("device set latency not supported for %s",
+ pd[target].oh_name);
+ ret = -EINVAL;
+ } else {
+#ifdef CONFIG_OMAP_PM
+ ret = omap_pm_set_max_dev_wakeup_lat(pd[rsrc].dev,
+ pd[target].dev,
+ latency);
+#endif
+ }
+ }
+
+ if (ret)
+ pr_err("module set latency failed %s", pd[target].oh_name);
+err_ret:
+ return ret;
+}
+EXPORT_SYMBOL(ipu_pm_module_set_latency);
+
+inline int ipu_pm_module_set_bandwidth(unsigned rsrc,
+ unsigned target_rsrc,
+ int bandwidth)
+{
+ int ret = 0;
+ struct omap_ipupm_mod_platform_data *pd;
+
+ pd = ipupm_get_plat_data();
+
+ if ((pd[target_rsrc].caps & IPUPM_CAPS_BDW) == 0) {
+ pr_err("device set bandwidth not supported for %s",
+ pd[target_rsrc].oh_name);
+ ret = -EINVAL;
+ } else {
+#ifdef CONFIG_OMAP_PM
+ struct device *dp;
+ dp = omap2_get_l3_device();
+ ret = omap_pm_set_min_bus_tput(dp,
+ OCP_INITIATOR_AGENT,
+ bandwidth);
+#endif
+ }
+
+ if (ret)
+ pr_err("module set bandwidth failed %s",
+ pd[target_rsrc].oh_name);
+ return ret;
+}
+EXPORT_SYMBOL(ipu_pm_module_set_bandwidth);
+
+/* FIXME: not in use now
+ * static struct omap_ipupm_mod_ops omap_ipu_ops = {
+ * .start = NULL,
+ * .stop = NULL,
+ * };
+ *
+ * static struct omap_ipupm_mod_ops omap_ipu0_ops = {
+ * .start = NULL,
+ * .stop = NULL,
+ * };
+ *
+ * static struct omap_ipupm_mod_ops omap_ipu1_ops = {
+ * .start = NULL,
+ * .stop = NULL,
+ * };
+ */
+
+/* ipupm generic operations */
+static struct omap_ipupm_mod_ops omap_ipupm_ops = {
+ .start = NULL,
+ .stop = NULL,
+};
+
+static struct omap_ipupm_mod_platform_data omap_ipupm_data[] = {
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "fdif",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
+ | IPUPM_CAPS_PERF | IPUPM_CAPS_LAT,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "ipu",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
+ | IPUPM_CAPS_PERF | IPUPM_CAPS_LAT
+ | IPUPM_CAPS_EXTINIT,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "ipu_c0",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
+ | IPUPM_CAPS_EXTINIT,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "ipu_c1",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
+ | IPUPM_CAPS_EXTINIT,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "iss",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
+ | IPUPM_CAPS_PERF | IPUPM_CAPS_LAT,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "iva",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
+ | IPUPM_CAPS_PERF | IPUPM_CAPS_LAT,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "iva_seq0",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "iva_seq1",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "l3_main_1",
+ .caps = IPUPM_CAPS_LAT | IPUPM_CAPS_BDW
+ | IPUPM_CAPS_EXTINIT,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "mpu",
+ .caps = IPUPM_CAPS_PERF | IPUPM_CAPS_LAT
+ | IPUPM_CAPS_EXTINIT,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "sl2if",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP,
+ .ops = &omap_ipupm_ops,
+ },
+ {
+ .name = "omap-ipu-pm",
+ .oh_name = "dsp",
+ .caps = IPUPM_CAPS_START | IPUPM_CAPS_STOP
+ | IPUPM_CAPS_PERF | IPUPM_CAPS_LAT
+ | IPUPM_CAPS_EXTINIT,
+ .ops = &omap_ipupm_ops,
+ },
+};
+
+struct omap_ipupm_mod_platform_data *ipupm_get_plat_data(void)
+{
+ return omap_ipupm_data;
+}
+EXPORT_SYMBOL(ipupm_get_plat_data);
+
+static struct omap_device_pm_latency omap_ipupm_latency[] = {
+ {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ },
+};
+
+static int __init omap_ipussdev_init(void)
+{
+ int status = -ENODEV;
+ int i;
+ int first = 1;
+ struct omap_hwmod *oh;
+ struct omap_device *od;
+ char *oh_name;
+ char *pdev_name = IPU_DRIVER_NAME;
+ struct omap_device_pm_latency *ohl = omap_ipupm_latency;
+ int ohl_cnt = ARRAY_SIZE(omap_ipupm_latency);
+
+ for (i = 0; i < ARRAY_SIZE(omap_ipupm_data); i++) {
+ oh_name = omap_ipupm_data[i].oh_name;
+
+ if (omap_ipupm_data[i].caps & IPUPM_CAPS_EXTINIT)
+ continue;
+
+ oh = omap_hwmod_lookup(oh_name);
+ if (!oh) {
+ pr_err("%s: could not look up %s\n", __func__, oh_name);
+
+ continue; /* to allow init to continue with other IPs
+ * we probably do not want to completely stop progress
+ * due to one module anyway, but need to be able to
+ * not try to use it if init fails
+ * this was put in to handle disabled hwmods
+ */
+
+ status = -ENODEV;
+ goto err_init;
+ }
+ omap_ipupm_data[i].oh = oh;
+
+ od = omap_device_build(pdev_name, IVA_IPU_BUS_ID+i, oh,
+ &omap_ipupm_data[i],
+ sizeof(struct omap_ipupm_mod_platform_data),
+ ohl, ohl_cnt, false);
+
+ status = IS_ERR(od);
+ WARN(status, "Could not build omap_device for %s %s\n",
+ pdev_name, oh_name);
+ if (!status) {
+ /* Save the id of the first registered dev */
+ if (first) {
+ ipu_pm_first_dev = od->pdev.id;
+ first = 0;
+ }
+ omap_ipupm_data[i].pdev = &od->pdev;
+ omap_ipupm_data[i].dev = &od->pdev.dev;
+ }
+ }
+
+err_init:
+ return status;
+}
+
+arch_initcall(omap_ipussdev_init);
diff --git a/arch/arm/mach-omap2/ipu_drv.c b/arch/arm/mach-omap2/ipu_drv.c
new file mode 100644
index 00000000000..bed6dd75236
--- /dev/null
+++ b/arch/arm/mach-omap2/ipu_drv.c
@@ -0,0 +1,375 @@
+/*
+ * linux/arch/arm/mach-omap2/ipu_drv.c
+ *
+ * OMAP Image Processing Unit Power Management Driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Paul Hunt <hunt@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/sysfs.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/platform_device.h>
+#include <asm/uaccess.h>
+#include <plat/ipu_dev.h>
+
+#define IPU_CLASS_NAME "ipu-power"
+#define IPU_DRIVER_NAME "omap-ipu-pm"
+
+static struct class *omap_ipu_pm_class;
+static dev_t omap_ipu_pm_dev;
+
+int ipu_pm_first_dev;
+int need_resume_notifications;
+
+static struct proc_dir_entry *ipu_pm_proc_entry;
+/* we could iterate over something much more
+ * complicated than a set of lines of text
+ * Just debugging.
+ */
+static char *lines[] = {
+ "This is the first line from ipu_pm_seq",
+ "This is the second line from ipu_pm_seq",
+};
+
+static int ipu_pm_num_procs = ARRAY_SIZE(lines);
+
+static void *ipu_pm_seq_start(struct seq_file *s, loff_t *pos)
+{
+ if (*pos >= ipu_pm_num_procs)
+ return NULL;/* no more to read */
+ return lines[*pos];
+}
+static void *ipu_pm_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ (*pos)++;
+ if (*pos >= ipu_pm_num_procs)
+ return NULL;/* no more to read */
+ return lines[*pos];
+}
+static void ipu_pm_seq_stop(struct seq_file *s, void *v)
+{
+ /* nothing to do */
+}
+static int ipu_pm_seq_show(struct seq_file *s, void *v)
+{
+ seq_printf(s, "IPU_PM: %s\n", (char *) v);
+ return 0;
+}
+static const struct seq_operations ipu_pm_seq_ops = {
+ .start = ipu_pm_seq_start,
+ .next = ipu_pm_seq_next,
+ .stop = ipu_pm_seq_stop,
+ .show = ipu_pm_seq_show,
+};
+static int ipu_pm_proc_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &ipu_pm_seq_ops);
+}
+
+static const struct file_operations ipu_pm_proc_ops = {
+ .owner = THIS_MODULE,
+ .open = ipu_pm_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static void _suspend_stub(void)
+{
+ pr_info("Suspend IOCTL received\n");
+}
+
+static void _resume_stub(void)
+{
+ pr_info("Resume IOCTL received!\n");
+}
+
+/* arg should encode the IPU-managed HWMOD
+ * to be suspended, 0 for system wide
+ */
+static long ipu_pm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ /* struct omap_ipu_pm *ipu_pm = filp->private_data; */
+
+ /* FIXME: check for ipu_pm when requested */
+
+ if (_IOC_TYPE(cmd) != IPU_PM_IOC_MAGIC)
+ return -ENOTTY;
+ if (_IOC_NR(cmd) > IPU_PM_IOC_MAXNR)
+ return -ENOTTY;
+
+ /* FIXME:not using the next two yet, since no args */
+ if (_IOC_DIR(cmd) & _IOC_READ) {
+ if (!access_ok(VERIFY_WRITE,
+ (void __user *)arg,
+ _IOC_SIZE(cmd)))
+ return -EFAULT;
+ } else if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ if (!access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)))
+ return -EFAULT;
+ }
+
+ switch (cmd) {
+ case IPU_PM_IOC_SUSPEND:
+ _suspend_stub();
+ break;
+ case IPU_PM_IOC_RESUME:
+ _resume_stub();
+ break;
+
+ default:
+ return -ENOTTY;
+ }
+
+ return ret;
+}
+
+
+#ifdef ZERO
+static const struct sysfs_ops {
+ ssize_t (*show)(struct kobject *, struct attribute *, char *);
+ ssize_t (*store)(struct kobject *, struct attribute *, const char *,
+ size_t);
+};
+#endif
+
+static int is_driver_init;
+
+static const struct file_operations ipm_pm_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = ipu_pm_ioctl,
+ .open = NULL,
+};
+
+static struct ipu_pm_dev ipu_pm_dev;
+
+static int __devinit ipu_pm_probe(struct platform_device *pdev)
+{
+ /* FIXME: get pdata */
+ /* struct ipu_pm_platform_data *pdata = pdev->dev.platform_data; */
+ /* int id = pdev->id; */
+ /* ivahd.pdev = pdev; */
+
+ need_resume_notifications = 0;
+
+ if (!is_driver_init) {
+ is_driver_init = 1;
+ /* FIXME: maybe needed for multiple dev */
+ /* spin_lock_init(&ipu_pm_lock); */
+ }
+ /* FIXME: add kobjects to kset */
+
+ return 0;
+}
+
+static int ipu_pm_drv_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int retval = 0;
+
+ if (pdev->id == ipu_pm_first_dev) {
+ pr_debug("%s.%d ASKED TO SUSPEND", pdev->name, pdev->id);
+ /* save any local context,
+ * BIOS timers could be saved locally or on Ducati
+ */
+
+ /* FIXME: Currently sending SUSPEND is enough to send
+ * Ducati to hibernate, save ctx can be called at this
+ * point to save ctx and reset remote procs
+ * Currently the save ctx process can be called using
+ * which ever proc_id, maybe this will change when
+ * Tesla support is added.
+ */
+ /* call notification function */
+ if (ipu_pm_get_handle(APP_M3)) {
+ if (!(ipu_pm_get_state(APP_M3) & APP_PROC_DOWN)) {
+ retval = ipu_pm_notifications(APP_M3,
+ PM_SUSPEND, NULL);
+ if (retval)
+ goto error;
+ }
+ }
+ if (ipu_pm_get_handle(SYS_M3)) {
+ if (!(ipu_pm_get_state(SYS_M3) & SYS_PROC_DOWN)) {
+ retval = ipu_pm_notifications(SYS_M3,
+ PM_SUSPEND, NULL);
+ if (retval)
+ goto error;
+ /* sysm3 is handling hibernation of ducati
+ * currently
+ */
+ ipu_pm_save_ctx(SYS_M3);
+ need_resume_notifications = 1;
+ }
+ }
+ /* return result, should be zero if all Ducati clients
+ * returned zero else fail code
+ */
+ }
+error:
+ return retval;
+}
+
+static int ipu_pm_drv_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int retval = 0;
+
+ if (pdev->id == ipu_pm_first_dev) {
+ pr_debug("%s.%d ASKED TO RESUME", pdev->name, pdev->id);
+ /* restore any local context,
+ * BIOS timers could be restored locally or on Ducati
+ */
+
+ /* call our notification function */
+ if (need_resume_notifications) {
+ if (ipu_pm_get_handle(APP_M3)) {
+ retval = ipu_pm_notifications(APP_M3,
+ PM_RESUME, NULL);
+ if (retval)
+ goto error;
+ }
+ if (ipu_pm_get_handle(SYS_M3)) {
+ retval = ipu_pm_notifications(SYS_M3,
+ PM_RESUME, NULL);
+ if (retval)
+ goto error;
+ }
+ need_resume_notifications = 0;
+ }
+
+ /* return result, should be zero if all Ducati clients
+ * returned zero else fail code
+ */
+ }
+error:
+ return retval;
+}
+
+static const struct dev_pm_ops ipu_pm_ops = {
+ .suspend = ipu_pm_drv_suspend,
+ .resume = ipu_pm_drv_resume,
+};
+
+static struct platform_driver ipu_pm_driver = {
+ .probe = ipu_pm_probe,
+ /*.remove = ipu_pm_remove, */
+ .driver = {
+ .name = IPU_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = &ipu_pm_ops,
+ },
+};
+
+static int __init ipu_pm_init(void)
+{
+ int ret;
+ struct device *tmpdev;
+
+ if (!is_driver_init) {
+ is_driver_init = 1;
+ /* FIXME: maybe needed for multiple dev */
+ /* spin_lock_init(&ipu_pm_lock); */
+ }
+
+ ret = alloc_chrdev_region(&omap_ipu_pm_dev, 0, 2, IPU_CLASS_NAME);
+ if (ret) {
+ pr_err("%s: alloc_chrdev_region failed: %d\n", __func__, ret);
+ return ret;
+ }
+
+ /* create device class */
+ omap_ipu_pm_class = class_create(THIS_MODULE, IPU_CLASS_NAME);
+ if (IS_ERR(omap_ipu_pm_class)) {
+ ret = PTR_ERR(omap_ipu_pm_class);
+ pr_err("%s: class_create failed: %d\n", __func__, ret);
+ return ret;
+ }
+
+ /* create an instance of this device class */
+ cdev_init(&ipu_pm_dev.cdev, &ipm_pm_fops);
+ ipu_pm_dev.cdev.owner = THIS_MODULE;
+ ipu_pm_dev.cdev.ops = &ipm_pm_fops;
+ ret = cdev_add(&ipu_pm_dev.cdev, omap_ipu_pm_dev, 1);
+ if (ret)
+ pr_err("%s: cdev_add failed: %d\n", __func__, omap_ipu_pm_dev);
+
+ tmpdev = device_create(omap_ipu_pm_class, NULL,
+ omap_ipu_pm_dev,
+ NULL,
+ "ipu%d",
+ MINOR(omap_ipu_pm_dev));
+
+ if (IS_ERR(tmpdev)) {
+ ret = PTR_ERR(tmpdev);
+ pr_err("%s: device_create failed: %d\n", __func__, ret);
+ /* FIXME: add clean_cdev when error */
+ /*goto clean_cdev;*/
+ }
+ dev_info(tmpdev, "Test of writing to the device message log,"
+ "done from %s\n", __func__);
+
+ pr_info("%s initialized %s, major: %d, minor: %d\n",
+ IPU_CLASS_NAME,
+ /*pdata->name,*/
+ "ipu",
+ MAJOR(omap_ipu_pm_dev),
+ MINOR(omap_ipu_pm_dev));
+
+ /* FIXME:add a kset pointing to this new class */
+ /* omap_ipu_pm_class->dev_kobj */
+
+ /* add proc interface */
+ ipu_pm_proc_entry = create_proc_entry("ipu_proc_loads", 0, NULL);
+ if (ipu_pm_proc_entry)
+ ipu_pm_proc_entry->proc_fops = &ipu_pm_proc_ops;
+ else
+ pr_err("%s: proc entry create failed for: %s\n",
+ __func__, IPU_CLASS_NAME);
+
+ return platform_driver_register(&ipu_pm_driver);
+}
+
+static void __exit ipu_pm_exit(void)
+{
+ platform_driver_unregister(&ipu_pm_driver);
+}
+
+/* early_platform_init("earlytimer", &ipu_pm_driver); */
+module_init(ipu_pm_init);
+module_exit(ipu_pm_exit);
+
+MODULE_DESCRIPTION("OMAP IMAGE PROCESSING UNIT POWER MGMT DRIVER");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" IPU_CLASS_NAME);
+MODULE_AUTHOR("Texas Instruments Inc");
diff --git a/arch/arm/mach-omap2/ipu_utility.c b/arch/arm/mach-omap2/ipu_utility.c
new file mode 100644
index 00000000000..b16b5ad891d
--- /dev/null
+++ b/arch/arm/mach-omap2/ipu_utility.c
@@ -0,0 +1,69 @@
+/*
+ * OMAP IPU_PM utility
+ *
+ * Copyright (C) 2010 Texas Instruments Inc.
+ *
+ * Written by Paul Hunt <hunt@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <asm/io.h>
+#include <plat/io.h>
+
+#define ICONT1_ITCM_BASE 0x5A008000
+#define ICONT2_ITCM_BASE 0x5A018000
+
+static void __iomem *icont_itcm_ptr;
+
+/* Op-codes for simple boot sequence ending in WFI */
+static const u32 ICONT_Boot_WFI[] = {
+ 0xEA000006,
+ 0xEAFFFFFE,
+ 0xEAFFFFFE,
+ 0xEAFFFFFE,
+ 0xEAFFFFFE,
+ 0xEAFFFFFE,
+ 0xEAFFFFFE,
+ 0xEAFFFFFE,
+ 0xE3A00000,
+ 0xEE070F9A,
+ 0xEE070F90,
+ 0xE3A00000,
+ 0xEAFFFFFE,
+ 0xEAFFFFF1,
+};
+
+static const u32 ICONT_Boot_WFI_length = ARRAY_SIZE(ICONT_Boot_WFI);
+
+static void load_ivahd_idle_boot_code(void)
+{
+ int i;
+
+ icont_itcm_ptr = ioremap((u32) ICONT1_ITCM_BASE, 0x1000);
+ for (i = 0; i < ICONT_Boot_WFI_length; i++)
+ __raw_writel(ICONT_Boot_WFI[i], (icont_itcm_ptr + i));
+ iounmap(icont_itcm_ptr);
+
+ icont_itcm_ptr = ioremap((u32) ICONT2_ITCM_BASE, 0x1000);
+ for (i = 0; i < ICONT_Boot_WFI_length; i++)
+ __raw_writel(ICONT_Boot_WFI[i], (icont_itcm_ptr + i));
+ iounmap(icont_itcm_ptr);
+}
+EXPORT_SYMBOL(load_ivahd_idle_boot_code);
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
index 86d564a640b..a2bdb795418 100644
--- a/arch/arm/mach-omap2/mailbox.c
+++ b/arch/arm/mach-omap2/mailbox.c
@@ -15,31 +15,50 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/pm_runtime.h>
+#include <linux/slab.h>
#include <plat/mailbox.h>
#include <mach/irqs.h>
#define MAILBOX_REVISION 0x000
-#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m))
-#define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m))
-#define MAILBOX_MSGSTATUS(m) (0x0c0 + 4 * (m))
-#define MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u))
-#define MAILBOX_IRQENABLE(u) (0x104 + 8 * (u))
-
-#define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 10 * (u))
-#define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 10 * (u))
-#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 10 * (u))
+#define MAILBOX_SYSCONFIG 0x010
+#define MAILBOX_SYSSTATUS 0x014
+#define MAILBOX_MESSAGE(m) (0x040 + 0x4 * (m))
+#define MAILBOX_FIFOSTATUS(m) (0x080 + 0x4 * (m))
+#define MAILBOX_MSGSTATUS(m) (0x0c0 + 0x4 * (m))
+#define MAILBOX_IRQSTATUS(u) (0x100 + 0x8 * (u))
+#define MAILBOX_IRQENABLE(u) (0x104 + 0x8 * (u))
+
+#define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 0x10 * (u))
+#define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 0x10 * (u))
+#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 0x10 * (u))
#define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m)))
#define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1))
#define MBOX_REG_SIZE 0x120
+#define MBOX_NUM_USER 2
+#define OMAP4_MBOX_NUM_USER 3
+
#define OMAP4_MBOX_REG_SIZE 0x130
-#define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32))
-#define OMAP4_MBOX_NR_REGS (OMAP4_MBOX_REG_SIZE / sizeof(u32))
+#define MBOX_NR_REGS 2
+#define OMAP4_MBOX_NR_REGS 3
+
+/* SYSCONFIG: register bit definition */
+#define AUTOIDLE (1 << 0)
+#define SOFTRESET (1 << 1)
+#define SMARTIDLE (2 << 3)
+#define OMAP4_SOFTRESET (1 << 0)
+#define OMAP4_NOIDLE (1 << 2)
+#define OMAP4_SMARTIDLE (2 << 2)
+
+#define RESETDONE (1 << 0)
static void __iomem *mbox_base;
+static u32 *mbox_ctx;
+static int nr_mbox_users;
+static struct clk *mbox_ick_handle;
struct omap_mbox2_fifo {
unsigned long msg;
@@ -54,7 +73,6 @@ struct omap_mbox2_priv {
unsigned long irqstatus;
u32 newmsg_bit;
u32 notfull_bit;
- u32 ctx[OMAP4_MBOX_NR_REGS];
unsigned long irqdisable;
};
@@ -75,12 +93,51 @@ static inline void mbox_write_reg(u32 val, size_t ofs)
static int omap2_mbox_startup(struct omap_mbox *mbox)
{
u32 l;
+ unsigned long timeout;
pm_runtime_enable(mbox->dev->parent);
pm_runtime_get_sync(mbox->dev->parent);
+
+ if (!cpu_is_omap44xx()) {
+ mbox_ick_handle = clk_get(NULL, "mailboxes_ick");
+ if (IS_ERR(mbox_ick_handle)) {
+ printk(KERN_ERR "Could not get mailboxes_ick: %ld\n",
+ PTR_ERR(mbox_ick_handle));
+ return PTR_ERR(mbox_ick_handle);
+ }
+ clk_enable(mbox_ick_handle);
+ }
+
+ if (cpu_is_omap44xx()) {
+ mbox_write_reg(OMAP4_SOFTRESET, MAILBOX_SYSCONFIG);
+ timeout = jiffies + msecs_to_jiffies(20);
+ do {
+ l = mbox_read_reg(MAILBOX_SYSCONFIG);
+ if (!(l & OMAP4_SOFTRESET))
+ break;
+ } while (!time_after(jiffies, timeout));
+
+ if (l & OMAP4_SOFTRESET) {
+ pr_err("Can't take mailbox out of reset\n");
+ return -ENODEV;
+ }
+ } else {
+ mbox_write_reg(SOFTRESET, MAILBOX_SYSCONFIG);
+ timeout = jiffies + msecs_to_jiffies(20);
+ do {
+ l = mbox_read_reg(MAILBOX_SYSSTATUS);
+ if (l & RESETDONE)
+ break;
+ } while (!time_after(jiffies, timeout));
+
+ if (!(l & RESETDONE)) {
+ pr_err("Can't take mailbox out of reset\n");
+ return -ENODEV;
+ }
+ }
l = mbox_read_reg(MAILBOX_REVISION);
- pr_debug("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f));
+ pr_info("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f));
omap2_mbox_enable_irq(mbox, IRQ_RX);
@@ -91,6 +148,12 @@ static void omap2_mbox_shutdown(struct omap_mbox *mbox)
{
pm_runtime_put_sync(mbox->dev->parent);
pm_runtime_disable(mbox->dev->parent);
+
+ if (!cpu_is_omap44xx()) {
+ clk_disable(mbox_ick_handle);
+ clk_put(mbox_ick_handle);
+ mbox_ick_handle = NULL;
+ }
}
/* Mailbox FIFO handle functions */
@@ -171,35 +234,37 @@ static int omap2_mbox_is_irq(struct omap_mbox *mbox,
static void omap2_mbox_save_ctx(struct omap_mbox *mbox)
{
- int i;
- struct omap_mbox2_priv *p = mbox->priv;
- int nr_regs;
- if (cpu_is_omap44xx())
- nr_regs = OMAP4_MBOX_NR_REGS;
- else
- nr_regs = MBOX_NR_REGS;
- for (i = 0; i < nr_regs; i++) {
- p->ctx[i] = mbox_read_reg(i * sizeof(u32));
+ int i, j;
+
+ /* Save irqs per user */
+ for (j = 0, i = 0; j < nr_mbox_users; i++, j++) {
+ if (cpu_is_omap44xx())
+ mbox_ctx[i] = mbox_read_reg(OMAP4_MAILBOX_IRQENABLE(j));
+ else
+ mbox_ctx[i] = mbox_read_reg(MAILBOX_IRQENABLE(j));
dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
- i, p->ctx[i]);
+ i, mbox_ctx[i]);
}
+
+ omap2_mbox_shutdown(mbox);
}
static void omap2_mbox_restore_ctx(struct omap_mbox *mbox)
{
- int i;
- struct omap_mbox2_priv *p = mbox->priv;
- int nr_regs;
- if (cpu_is_omap44xx())
- nr_regs = OMAP4_MBOX_NR_REGS;
- else
- nr_regs = MBOX_NR_REGS;
- for (i = 0; i < nr_regs; i++) {
- mbox_write_reg(p->ctx[i], i * sizeof(u32));
+ int i, j;
+
+ omap2_mbox_startup(mbox);
+
+ /* Restore irqs per user */
+ for (j = 0, i = 0; j < nr_mbox_users; i++, j++) {
+ if (cpu_is_omap44xx())
+ mbox_write_reg(mbox_ctx[i], OMAP4_MAILBOX_IRQENABLE(j));
+ else
+ mbox_write_reg(mbox_ctx[i], MAILBOX_IRQENABLE(j));
dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
- i, p->ctx[i]);
+ i, mbox_ctx[i]);
}
}
diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c
index 3fc5dc7233d..73436e7d5dc 100644
--- a/arch/arm/mach-omap2/omap-iommu.c
+++ b/arch/arm/mach-omap2/omap-iommu.c
@@ -11,9 +11,12 @@
*/
#include <linux/platform_device.h>
-
+#include <linux/err.h>
+#include <linux/slab.h>
#include <plat/iommu.h>
-#include <plat/irqs.h>
+#include <plat/omap_device.h>
+#include <plat/omap_hwmod.h>
+
struct iommu_device {
resource_size_t base;
@@ -21,145 +24,131 @@ struct iommu_device {
struct iommu_platform_data pdata;
struct resource res[2];
};
-static struct iommu_device *devices;
+static struct iommu_platform_data *devices_data;
static int num_iommu_devices;
#ifdef CONFIG_ARCH_OMAP3
-static struct iommu_device omap3_devices[] = {
+static struct iommu_platform_data omap3_devices_data[] = {
{
- .base = 0x480bd400,
- .irq = 24,
- .pdata = {
- .name = "isp",
- .nr_tlb_entries = 8,
- .clk_name = "cam_ick",
- .da_start = 0x0,
- .da_end = 0xFFFFF000,
- },
+ .name = "isp",
+ .oh_name = "isp",
+ .nr_tlb_entries = 8,
},
#if defined(CONFIG_OMAP_IOMMU_IVA2)
{
- .base = 0x5d000000,
- .irq = 28,
- .pdata = {
- .name = "iva2",
- .nr_tlb_entries = 32,
- .clk_name = "iva2_ck",
- .da_start = 0x11000000,
- .da_end = 0xFFFFF000,
- },
+ .name = "iva2",
+ .oh_name = "dsp",
+ .nr_tlb_entries = 32,
},
#endif
};
-#define NR_OMAP3_IOMMU_DEVICES ARRAY_SIZE(omap3_devices)
+#define NR_OMAP3_IOMMU_DEVICES ARRAY_SIZE(omap3_devices_data)
static struct platform_device *omap3_iommu_pdev[NR_OMAP3_IOMMU_DEVICES];
#else
-#define omap3_devices NULL
+#define omap3_devices_data NULL
#define NR_OMAP3_IOMMU_DEVICES 0
-#define omap3_iommu_pdev NULL
+#define omap3_iommu_pdev NULL
#endif
#ifdef CONFIG_ARCH_OMAP4
-static struct iommu_device omap4_devices[] = {
+static struct iommu_platform_data omap4_devices_data[] = {
{
- .base = OMAP4_MMU1_BASE,
- .irq = OMAP44XX_IRQ_DUCATI_MMU,
- .pdata = {
- .name = "ducati",
- .nr_tlb_entries = 32,
- .clk_name = "ducati_ick",
- .da_start = 0x0,
- .da_end = 0xFFFFF000,
- },
+ .name = "ducati",
+ .oh_name = "ipu",
+ .nr_tlb_entries = 32,
},
-#if defined(CONFIG_MPU_TESLA_IOMMU)
{
- .base = OMAP4_MMU2_BASE,
- .irq = INT_44XX_DSP_MMU,
- .pdata = {
- .name = "tesla",
- .nr_tlb_entries = 32,
- .clk_name = "tesla_ick",
- .da_start = 0x0,
- .da_end = 0xFFFFF000,
- },
+ .name = "tesla",
+ .oh_name = "dsp",
+ .nr_tlb_entries = 32,
},
-#endif
};
-#define NR_OMAP4_IOMMU_DEVICES ARRAY_SIZE(omap4_devices)
+#define NR_OMAP4_IOMMU_DEVICES ARRAY_SIZE(omap4_devices_data)
static struct platform_device *omap4_iommu_pdev[NR_OMAP4_IOMMU_DEVICES];
#else
-#define omap4_devices NULL
+#define omap4_devices_data NULL
#define NR_OMAP4_IOMMU_DEVICES 0
-#define omap4_iommu_pdev NULL
+#define omap4_iommu_pdev NULL
#endif
static struct platform_device **omap_iommu_pdev;
+static struct omap_device_pm_latency omap_iommu_latency[] = {
+ [0] = {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ },
+};
+
+int iommu_get_plat_data_size(void)
+{
+ return num_iommu_devices;
+}
+EXPORT_SYMBOL(iommu_get_plat_data_size);
+
static int __init omap_iommu_init(void)
{
- int i, err;
- struct resource res[] = {
- { .flags = IORESOURCE_MEM },
- { .flags = IORESOURCE_IRQ },
- };
+ int i, ohl_cnt;
+ struct omap_hwmod *oh;
+ struct omap_device *od;
+ struct omap_device_pm_latency *ohl;
+ struct platform_device *pdev;
if (cpu_is_omap34xx()) {
- devices = omap3_devices;
- omap_iommu_pdev = omap3_iommu_pdev;
+ devices_data = omap3_devices_data;
num_iommu_devices = NR_OMAP3_IOMMU_DEVICES;
+ omap_iommu_pdev = omap3_iommu_pdev;
} else if (cpu_is_omap44xx()) {
- devices = omap4_devices;
- omap_iommu_pdev = omap4_iommu_pdev;
+ devices_data = omap4_devices_data;
num_iommu_devices = NR_OMAP4_IOMMU_DEVICES;
+ omap_iommu_pdev = omap4_iommu_pdev;
} else
return -ENODEV;
- for (i = 0; i < num_iommu_devices; i++) {
- struct platform_device *pdev;
- const struct iommu_device *d = &devices[i];
+ ohl = omap_iommu_latency;
+ ohl_cnt = ARRAY_SIZE(omap_iommu_latency);
- pdev = platform_device_alloc("omap-iommu", i);
- if (!pdev) {
- err = -ENOMEM;
- goto err_out;
+ for (i = 0; i < num_iommu_devices; i++) {
+ struct iommu_platform_data *data = &devices_data[i];
+
+ oh = omap_hwmod_lookup(data->oh_name);
+ if (oh == NULL)
+ continue;
+ data->io_base = oh->_mpu_rt_va;
+ data->irq = oh->mpu_irqs[0].irq;
+
+ if (!oh) {
+ pr_err("%s: could not look up %s\n", __func__,
+ data->oh_name);
+ continue;
+ }
+ od = omap_device_build("omap-iommu", i, oh,
+ data, sizeof(*data),
+ ohl, ohl_cnt, false);
+ WARN(IS_ERR(od), "Could not build omap_device"
+ "for %s %s\n", "omap-iommu", data->oh_name);
+
+ pdev = platform_device_alloc("omap-iovmm", i);
+ if (pdev) {
+ platform_device_add_data(pdev, data, sizeof(*data));
+ platform_device_add(pdev);
}
-
- res[0].start = d->base;
- res[0].end = d->base + MMU_REG_SIZE - 1;
- res[1].start = res[1].end = d->irq;
-
- err = platform_device_add_resources(pdev, res,
- ARRAY_SIZE(res));
- if (err)
- goto err_out;
- err = platform_device_add_data(pdev, &d->pdata,
- sizeof(d->pdata));
- if (err)
- goto err_out;
- err = platform_device_add(pdev);
- if (err)
- goto err_out;
omap_iommu_pdev[i] = pdev;
}
return 0;
-
-err_out:
- while (i--)
- platform_device_put(omap_iommu_pdev[i]);
- return err;
}
-module_init(omap_iommu_init);
+postcore_initcall(omap_iommu_init);
static void __exit omap_iommu_exit(void)
{
int i;
-
for (i = 0; i < num_iommu_devices; i++)
platform_device_unregister(omap_iommu_pdev[i]);
}
module_exit(omap_iommu_exit);
MODULE_AUTHOR("Hiroshi DOYU");
+MODULE_AUTHOR("Hari Kanigeri");
MODULE_DESCRIPTION("omap iommu: omap device registration");
MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index e03429453ce..15db61543a5 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -1612,6 +1612,8 @@ struct omap_hwmod *omap_hwmod_lookup(const char *name)
return oh;
}
+EXPORT_SYMBOL_GPL(omap_hwmod_lookup);
+
/**
* omap_hwmod_for_each - call function for each registered omap_hwmod
* @fn: pointer to a callback function
@@ -2053,6 +2055,8 @@ void __iomem *omap_hwmod_get_mpu_rt_va(struct omap_hwmod *oh)
return oh->_mpu_rt_va;
}
+EXPORT_SYMBOL_GPL(omap_hwmod_get_mpu_rt_va);
+
/**
* omap_hwmod_add_initiator_dep - add sleepdep from @init_oh to @oh
* @oh: struct omap_hwmod *
diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
index ab738789f65..35f4fac72b7 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
@@ -22,6 +22,7 @@
#include <plat/dmtimer.h>
#include <plat/l3_2xxx.h>
#include <plat/l4_2xxx.h>
+#include <plat/mmc.h>
#include "omap_hwmod_common_data.h"
@@ -54,6 +55,7 @@ static struct omap_hwmod omap2420_gpio4_hwmod;
static struct omap_hwmod omap2420_dma_system_hwmod;
static struct omap_hwmod omap2420_mcspi1_hwmod;
static struct omap_hwmod omap2420_mcspi2_hwmod;
+static struct omap_hwmod omap2420_mmc_hwmod;
/* L3 -> L4_CORE interface */
static struct omap_hwmod_ocp_if omap2420_l3_main__l4_core = {
@@ -156,6 +158,24 @@ static struct omap_hwmod_ocp_if omap2420_l4_core__l4_wkup = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
+/* L4 CORE -> MMC interface */
+static struct omap_hwmod_addr_space omap2420_mmc_addr_space[] = {
+ {
+ .pa_start = 0x4809c000,
+ .pa_end = 0x4809c07f,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap2420_l4_core__mmc = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_mmc_hwmod,
+ .clk = "mmc_ick",
+ .addr = omap2420_mmc_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap2420_mmc_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
/* L4 CORE -> UART1 interface */
static struct omap_hwmod_addr_space omap2420_uart1_addr_space[] = {
{
@@ -257,6 +277,7 @@ static struct omap_hwmod_ocp_if *omap2420_l4_core_slaves[] = {
/* Master interfaces on the L4_CORE interconnect */
static struct omap_hwmod_ocp_if *omap2420_l4_core_masters[] = {
&omap2420_l4_core__l4_wkup,
+ &omap2420_l4_core__mmc,
&omap2_l4_core__uart1,
&omap2_l4_core__uart2,
&omap2_l4_core__uart3,
@@ -1919,6 +1940,17 @@ static struct omap_hwmod_class_sysconfig omap2420_mcspi_sysc = {
.sysc_flags = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+/* MMC/SD/SDIO common */
+
+static struct omap_hwmod_class_sysconfig mmc_sysc = {
+ .rev_offs = 0x3c,
+ .sysc_offs = 0x64,
+ .syss_offs = 0x68,
+ .sysc_flags = (SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -2139,6 +2171,54 @@ static struct omap_hwmod omap2420_mcbsp2_hwmod = {
},
.slaves = omap2420_mcbsp2_slaves,
.slaves_cnt = ARRAY_SIZE(omap2420_mcbsp2_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+
+static struct omap_hwmod_class mmc_class = {
+ .name = "mmc",
+ .sysc = &mmc_sysc,
+};
+
+/* MMC/SD/SDIO1 */
+
+static struct omap_mmc_dev_attr mmc_dev_attr = {
+ .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
+};
+
+static struct omap_hwmod_irq_info mmc_mpu_irqs[] = {
+ { .irq = 83 },
+};
+
+static struct omap_hwmod_dma_info mmc_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 61 }, /* DMA_MMC_TX */
+ { .name = "rx", .dma_req = 62 }, /* DMA_MMC_RX */
+};
+
+static struct omap_hwmod_ocp_if *omap2420_mmc_slaves[] = {
+ &omap2420_l4_core__mmc,
+};
+
+static struct omap_hwmod omap2420_mmc_hwmod = {
+ .name = "mmc_hwmod",
+ .mpu_irqs = mmc_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(mmc_mpu_irqs),
+ .sdma_reqs = mmc_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(mmc_sdma_reqs),
+ .main_clk = "mmc_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP2420_EN_MMC_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP2420_ST_MMC_SHIFT,
+ },
+ },
+ .slaves = omap2420_mmc_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_mmc_slaves),
+ .class = &mmc_class,
+ .dev_attr = &mmc_dev_attr,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
};
@@ -2163,6 +2243,7 @@ static __initdata struct omap_hwmod *omap2420_hwmods[] = {
&omap2420_timer12_hwmod,
&omap2420_wd_timer2_hwmod,
+ &omap2420_mmc_hwmod,
&omap2420_uart1_hwmod,
&omap2420_uart2_hwmod,
&omap2420_uart3_hwmod,
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index c5b67207e3e..782745fca62 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -51,8 +51,10 @@ static struct omap_hwmod omap44xx_dsp_hwmod;
static struct omap_hwmod omap44xx_dss_hwmod;
static struct omap_hwmod omap44xx_emif_fw_hwmod;
static struct omap_hwmod omap44xx_hsi_hwmod;
+static struct omap_hwmod omap44xx_fdif_hwmod;
static struct omap_hwmod omap44xx_ipu_hwmod;
static struct omap_hwmod omap44xx_iss_hwmod;
+static struct omap_hwmod omap44xx_gpu_hwmod;
static struct omap_hwmod omap44xx_iva_hwmod;
static struct omap_hwmod omap44xx_l3_instr_hwmod;
static struct omap_hwmod omap44xx_l3_main_1_hwmod;
@@ -65,6 +67,7 @@ static struct omap_hwmod omap44xx_l4_wkup_hwmod;
static struct omap_hwmod omap44xx_mmc1_hwmod;
static struct omap_hwmod omap44xx_mmc2_hwmod;
static struct omap_hwmod omap44xx_mpu_hwmod;
+static struct omap_hwmod omap44xx_sl2if_hwmod;
static struct omap_hwmod omap44xx_mpu_private_hwmod;
static struct omap_hwmod omap44xx_usb_otg_hs_hwmod;
@@ -310,6 +313,15 @@ static struct omap_hwmod omap44xx_l3_main_1_hwmod = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
+/* fdif -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_fdif__l3_main_2 = {
+ .master = &omap44xx_fdif_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+
/* l3_main_2 interface data */
/* dma_system -> l3_main_2 */
static struct omap_hwmod_ocp_if omap44xx_dma_system__l3_main_2 = {
@@ -322,14 +334,21 @@ static struct omap_hwmod_ocp_if omap44xx_dma_system__l3_main_2 = {
/* hsi -> l3_main_2 */
static struct omap_hwmod_ocp_if omap44xx_hsi__l3_main_2 = {
.master = &omap44xx_hsi_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+/* gpu -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_gpu__l3_main_2 = {
+ .master = &omap44xx_gpu_hwmod,
.slave = &omap44xx_l3_main_2_hwmod,
.clk = "l3_div_ck",
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* ipu -> l3_main_2 */
-static struct omap_hwmod_ocp_if omap44xx_ipu__l3_main_2 = {
- .master = &omap44xx_ipu_hwmod,
+/* iva -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_iva__l3_main_2 = {
+ .master = &omap44xx_iva_hwmod,
.slave = &omap44xx_l3_main_2_hwmod,
.clk = "l3_div_ck",
.user = OCP_USER_MPU | OCP_USER_SDMA,
@@ -343,9 +362,9 @@ static struct omap_hwmod_ocp_if omap44xx_iss__l3_main_2 = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* iva -> l3_main_2 */
-static struct omap_hwmod_ocp_if omap44xx_iva__l3_main_2 = {
- .master = &omap44xx_iva_hwmod,
+/* ipu -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_ipu__l3_main_2 = {
+ .master = &omap44xx_ipu_hwmod,
.slave = &omap44xx_l3_main_2_hwmod,
.clk = "l3_div_ck",
.user = OCP_USER_MPU | OCP_USER_SDMA,
@@ -393,6 +412,8 @@ static struct omap_hwmod_ocp_if *omap44xx_l3_main_2_slaves[] = {
&omap44xx_iss__l3_main_2,
&omap44xx_iva__l3_main_2,
&omap44xx_l3_main_1__l3_main_2,
+ &omap44xx_gpu__l3_main_2,
+ &omap44xx_fdif__l3_main_2,
&omap44xx_l4_cfg__l3_main_2,
&omap44xx_usb_otg_hs__l3_main_2,
};
@@ -500,6 +521,7 @@ static struct omap_hwmod_ocp_if omap44xx_mpu__l4_abe = {
static struct omap_hwmod_ocp_if *omap44xx_l4_abe_slaves[] = {
&omap44xx_aess__l4_abe,
&omap44xx_dsp__l4_abe,
+ &omap44xx_aess__l4_abe,
&omap44xx_l3_main_1__l4_abe,
&omap44xx_mpu__l4_abe,
};
@@ -616,6 +638,7 @@ static struct omap_hwmod omap44xx_mpu_private_hwmod = {
* - They still need to be validated with the driver
* properly adapted to omap_hwmod / omap_device
*
+ * bandgap
* c2c
* c2c_target_fw
* cm_core
@@ -630,11 +653,30 @@ static struct omap_hwmod omap44xx_mpu_private_hwmod = {
* elm
* emif1
* emif2
- * fdif
* gpmc
* gpu
* hdq1w
* hsi
+ * ipu
+ * iss
+ * kbd
+ * mailbox
+ * mcasp
+ * mcbsp1
+ * mcbsp2
+ * mcbsp3
+ * mcbsp4
+ * mcspi1
+ * mcspi2
+ * mcspi3
+ * mcspi4
+ * mmc1
+ * mmc2
+ * mmc3
+ * mmc4
+ * mmc5
+ * mpu_c0
+ * mpu_c1
* ocmc_ram
* ocp2scp_usb_phy
* ocp_wp_noc
@@ -666,8 +708,8 @@ static struct omap_hwmod_class_sysconfig omap44xx_aess_sysc = {
};
static struct omap_hwmod_class omap44xx_aess_hwmod_class = {
- .name = "aess",
- .sysc = &omap44xx_aess_sysc,
+ .name = "omap-aess-audio",
+ .sysc = &omap44xx_aess_sysc,
};
/* aess */
@@ -693,8 +735,8 @@ static struct omap_hwmod_ocp_if *omap44xx_aess_masters[] = {
static struct omap_hwmod_addr_space omap44xx_aess_addrs[] = {
{
- .pa_start = 0x401f1000,
- .pa_end = 0x401f13ff,
+ .pa_start = 0x49000000,
+ .pa_end = 0x491f11ff,
.flags = ADDR_TYPE_RT
},
};
@@ -712,7 +754,7 @@ static struct omap_hwmod_ocp_if omap44xx_l4_abe__aess = {
static struct omap_hwmod_addr_space omap44xx_aess_dma_addrs[] = {
{
.pa_start = 0x490f1000,
- .pa_end = 0x490f13ff,
+ .pa_end = 0x490f11ff,
.flags = ADDR_TYPE_RT
},
};
@@ -734,14 +776,15 @@ static struct omap_hwmod_ocp_if *omap44xx_aess_slaves[] = {
};
static struct omap_hwmod omap44xx_aess_hwmod = {
- .name = "aess",
+ .name = "omap-aess-audio",
.class = &omap44xx_aess_hwmod_class,
.mpu_irqs = omap44xx_aess_irqs,
.mpu_irqs_cnt = ARRAY_SIZE(omap44xx_aess_irqs),
.sdma_reqs = omap44xx_aess_sdma_reqs,
.sdma_reqs_cnt = ARRAY_SIZE(omap44xx_aess_sdma_reqs),
.main_clk = "aess_fck",
- .prcm = {
+ .vdd_name = "iva",
+ .prcm = {
.omap4 = {
.clkctrl_reg = OMAP4430_CM1_ABE_AESS_CLKCTRL,
},
@@ -1045,10 +1088,25 @@ static struct omap_hwmod_ocp_if omap44xx_dsp__iva = {
};
/* dsp master ports */
+/* dsp -> sl2if */
+static struct omap_hwmod_ocp_if omap44xx_dsp__sl2if = {
+ .master = &omap44xx_dsp_hwmod,
+ .slave = &omap44xx_sl2if_hwmod,
+ .clk = "dpll_iva_m5x2_ck",
+};
+
static struct omap_hwmod_ocp_if *omap44xx_dsp_masters[] = {
&omap44xx_dsp__l3_main_1,
&omap44xx_dsp__l4_abe,
&omap44xx_dsp__iva,
+ &omap44xx_dsp__sl2if,
+};
+
+/* iva -> sl2if */
+static struct omap_hwmod_ocp_if omap44xx_iva__sl2if = {
+ .master = &omap44xx_iva_hwmod,
+ .slave = &omap44xx_sl2if_hwmod,
+ .clk = "dpll_iva_m5x2_ck",
};
/* l4_cfg -> dsp */
@@ -2070,6 +2128,43 @@ static struct omap_hwmod_addr_space omap44xx_hsi_addrs[] = {
{
.pa_start = 0x4a058000,
.pa_end = 0x4a05bfff,
+ .flags = ADDR_TYPE_RT
+ }
+};
+
+/*
+ * 'gpu' class
+ * 2d/3d graphics accelerator
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_gpu_sysc = {
+ .rev_offs = 0xfe00,
+ .sysc_offs = 0xfe10,
+ .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_gpu_hwmod_class = {
+ .name = "gpu",
+ .sysc = &omap44xx_gpu_sysc,
+};
+
+/* gpu */
+static struct omap_hwmod_irq_info omap44xx_gpu_irqs[] = {
+ { .irq = 21 + OMAP44XX_IRQ_GIC_START },
+};
+
+/* gpu master ports */
+static struct omap_hwmod_ocp_if *omap44xx_gpu_masters[] = {
+ &omap44xx_gpu__l3_main_2,
+};
+
+static struct omap_hwmod_addr_space omap44xx_gpu_addrs[] = {
+ {
+ .pa_start = 0x56000000,
+ .pa_end = 0x5600ffff,
.flags = ADDR_TYPE_RT
},
};
@@ -2104,6 +2199,41 @@ static struct omap_hwmod omap44xx_hsi_hwmod = {
.slaves_cnt = ARRAY_SIZE(omap44xx_hsi_slaves),
.masters = omap44xx_hsi_masters,
.masters_cnt = ARRAY_SIZE(omap44xx_hsi_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+
+/* l3_main_2 -> gpu */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__gpu = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_gpu_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_gpu_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_gpu_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* gpu slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_gpu_slaves[] = {
+ &omap44xx_l3_main_2__gpu,
+};
+
+static struct omap_hwmod omap44xx_gpu_hwmod = {
+ .name = "gpu",
+ .class = &omap44xx_gpu_hwmod_class,
+ .mpu_irqs = omap44xx_gpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_gpu_irqs),
+ .main_clk = "gpu_fck",
+ .vdd_name = "core",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_GFX_GFX_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_gpu_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_gpu_slaves),
+ .masters = omap44xx_gpu_masters,
+ .masters_cnt = ARRAY_SIZE(omap44xx_gpu_masters),
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -2144,6 +2274,81 @@ static struct omap_hwmod_dma_info omap44xx_i2c1_sdma_reqs[] = {
{ .name = "rx", .dma_req = 27 + OMAP44XX_DMA_REQ_START },
};
+/*
+ * 'fdif' class
+ * face detection hw accelerator module
+ */
+
+/* static struct omap_hwmod_class_sysconfig omap44xx_fdif_sysc = {
+ * .rev_offs = 0x0000,
+ * .sysc_offs = 0x0010,
+ * .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_RESET_STATUS |
+ * SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+ * .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ * MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+ * .sysc_fields = &omap_hwmod_sysc_type2,
+ *};
+ */
+
+static struct omap_hwmod_class omap44xx_fdif_hwmod_class = {
+ .name = "fdif",
+ /* .sysc = &omap44xx_fdif_sysc, */
+};
+
+/* fdif */
+static struct omap_hwmod_irq_info omap44xx_fdif_irqs[] = {
+ { .irq = 69 + OMAP44XX_IRQ_GIC_START },
+};
+
+/* fdif master ports */
+static struct omap_hwmod_ocp_if *omap44xx_fdif_masters[] = {
+ &omap44xx_fdif__l3_main_2,
+};
+
+static struct omap_hwmod_addr_space omap44xx_fdif_addrs[] = {
+ {
+ .pa_start = 0x4a10a000,
+ .pa_end = 0x4a10a1ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_cfg -> fdif */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__fdif = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_fdif_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_fdif_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_fdif_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* fdif slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_fdif_slaves[] = {
+ &omap44xx_l4_cfg__fdif,
+};
+
+static struct omap_hwmod omap44xx_fdif_hwmod = {
+ .name = "fdif",
+ .class = &omap44xx_fdif_hwmod_class,
+ .flags = HWMOD_INIT_NO_RESET,
+ .mpu_irqs = omap44xx_fdif_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_fdif_irqs),
+ .main_clk = "fdif_fck",
+ .vdd_name = "core",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_CAM_FDIF_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_fdif_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_fdif_slaves),
+ .masters = omap44xx_fdif_masters,
+ .masters_cnt = ARRAY_SIZE(omap44xx_fdif_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+
static struct omap_hwmod_addr_space omap44xx_i2c1_addrs[] = {
{
.pa_start = 0x48070000,
@@ -2561,6 +2766,7 @@ static struct omap_hwmod_rst_info omap44xx_iva_seq1_resets[] = {
/* iva master ports */
static struct omap_hwmod_ocp_if *omap44xx_iva_masters[] = {
+ &omap44xx_iva__sl2if,
&omap44xx_iva__l3_main_2,
&omap44xx_iva__l3_instr,
};
@@ -3062,98 +3268,6 @@ static struct omap_hwmod omap44xx_mcbsp4_hwmod = {
};
/*
- * 'mcpdm' class
- * multi channel pdm controller (proprietary interface with phoenix power
- * ic)
- */
-
-static struct omap_hwmod_class_sysconfig omap44xx_mcpdm_sysc = {
- .rev_offs = 0x0000,
- .sysc_offs = 0x0010,
- .sysc_flags = (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
- SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
- .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
- SIDLE_SMART_WKUP),
- .sysc_fields = &omap_hwmod_sysc_type2,
-};
-
-static struct omap_hwmod_class omap44xx_mcpdm_hwmod_class = {
- .name = "mcpdm",
- .sysc = &omap44xx_mcpdm_sysc,
-};
-
-/* mcpdm */
-static struct omap_hwmod omap44xx_mcpdm_hwmod;
-static struct omap_hwmod_irq_info omap44xx_mcpdm_irqs[] = {
- { .irq = 112 + OMAP44XX_IRQ_GIC_START },
-};
-
-static struct omap_hwmod_dma_info omap44xx_mcpdm_sdma_reqs[] = {
- { .name = "up_link", .dma_req = 64 + OMAP44XX_DMA_REQ_START },
- { .name = "dn_link", .dma_req = 65 + OMAP44XX_DMA_REQ_START },
-};
-
-static struct omap_hwmod_addr_space omap44xx_mcpdm_addrs[] = {
- {
- .pa_start = 0x40132000,
- .pa_end = 0x4013207f,
- .flags = ADDR_TYPE_RT
- },
-};
-
-/* l4_abe -> mcpdm */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcpdm = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_mcpdm_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_mcpdm_addrs,
- .addr_cnt = ARRAY_SIZE(omap44xx_mcpdm_addrs),
- .user = OCP_USER_MPU,
-};
-
-static struct omap_hwmod_addr_space omap44xx_mcpdm_dma_addrs[] = {
- {
- .pa_start = 0x49032000,
- .pa_end = 0x4903207f,
- .flags = ADDR_TYPE_RT
- },
-};
-
-/* l4_abe -> mcpdm (dma) */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcpdm_dma = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_mcpdm_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_mcpdm_dma_addrs,
- .addr_cnt = ARRAY_SIZE(omap44xx_mcpdm_dma_addrs),
- .user = OCP_USER_SDMA,
-};
-
-/* mcpdm slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcpdm_slaves[] = {
- &omap44xx_l4_abe__mcpdm,
- &omap44xx_l4_abe__mcpdm_dma,
-};
-
-static struct omap_hwmod omap44xx_mcpdm_hwmod = {
- .name = "mcpdm",
- .class = &omap44xx_mcpdm_hwmod_class,
- .mpu_irqs = omap44xx_mcpdm_irqs,
- .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mcpdm_irqs),
- .sdma_reqs = omap44xx_mcpdm_sdma_reqs,
- .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mcpdm_sdma_reqs),
- .main_clk = "mcpdm_fck",
- .prcm = {
- .omap4 = {
- .clkctrl_reg = OMAP4430_CM1_ABE_PDM_CLKCTRL,
- },
- },
- .slaves = omap44xx_mcpdm_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mcpdm_slaves),
- .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
-};
-
-/*
* 'mcspi' class
* multichannel serial port interface (mcspi) / master/slave synchronous serial
* bus
@@ -4337,23 +4451,122 @@ static struct omap_hwmod_irq_info omap44xx_timer7_irqs[] = {
};
static struct omap_hwmod_addr_space omap44xx_timer7_addrs[] = {
+ {
+ .pa_start = 0x4013c000,
+ .pa_end = 0x4013c07f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+
+/* l4_abe -> timer7 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer7 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer7_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer7_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_timer7_addrs),
+ .user = OCP_USER_MPU,
+};
+
+
+/*
+ * 'mcpdm' class
+ * multi channel pdm controller (proprietary interface with
+ * phoenix audio ic)
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_mcpdm_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .sysc_flags = (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
+ SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_mcpdm_hwmod_class = {
+ .name = "omap-mcpdm-dai",
+ .sysc = &omap44xx_mcpdm_sysc,
+};
+
+/* mcpdm */
+static struct omap_hwmod omap44xx_mcpdm_hwmod;
+static struct omap_hwmod_irq_info omap44xx_mcpdm_irqs[] = {
+ { .irq = 112 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcpdm_sdma_reqs[] = {
+ { .name = "up_link", .dma_req = 64 + OMAP44XX_DMA_REQ_START },
+ { .name = "dn_link", .dma_req = 65 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcpdm_addrs[] = {
{
- .pa_start = 0x4013c000,
- .pa_end = 0x4013c07f,
+ .pa_start = 0x40132000,
+ .pa_end = 0x4013207f,
.flags = ADDR_TYPE_RT
},
};
-/* l4_abe -> timer7 */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer7 = {
+/* l4_abe -> mcpdm */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcpdm = {
.master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_timer7_hwmod,
+ .slave = &omap44xx_mcpdm_hwmod,
.clk = "ocp_abe_iclk",
- .addr = omap44xx_timer7_addrs,
- .addr_cnt = ARRAY_SIZE(omap44xx_timer7_addrs),
+ .addr = omap44xx_mcpdm_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mcpdm_addrs),
.user = OCP_USER_MPU,
};
+static struct omap_hwmod_addr_space omap44xx_mcpdm_dma_addrs[] = {
+ {
+ .pa_start = 0x49032000,
+ .pa_end = 0x4903207f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> mcpdm (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcpdm_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcpdm_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcpdm_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mcpdm_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+/* mcpdm slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mcpdm_slaves[] = {
+ &omap44xx_l4_abe__mcpdm,
+ &omap44xx_l4_abe__mcpdm_dma,
+};
+
+static struct omap_hwmod omap44xx_mcpdm_hwmod = {
+ .name = "omap-mcpdm-dai",
+ .class = &omap44xx_mcpdm_hwmod_class,
+ .mpu_irqs = omap44xx_mcpdm_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mcpdm_irqs),
+ .sdma_reqs = omap44xx_mcpdm_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mcpdm_sdma_reqs),
+ .main_clk = "mcpdm_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM1_ABE_PDM_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_mcpdm_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mcpdm_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'mpu' class
+ * mpu sub-system
+ */
+
static struct omap_hwmod_addr_space omap44xx_timer7_dma_addrs[] = {
{
.pa_start = 0x4903c000,
@@ -4394,6 +4607,7 @@ static struct omap_hwmod omap44xx_timer7_hwmod = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
+
/* timer8 */
static struct omap_hwmod omap44xx_timer8_hwmod;
static struct omap_hwmod_irq_info omap44xx_timer8_irqs[] = {
@@ -5062,7 +5276,7 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
&omap44xx_mpu_private_hwmod,
/* aess class */
-/* &omap44xx_aess_hwmod, */
+ &omap44xx_aess_hwmod,
/* bandgap class */
&omap44xx_bandgap_hwmod,
@@ -5080,6 +5294,9 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
&omap44xx_dsp_hwmod,
&omap44xx_dsp_c0_hwmod,
+ /* fdif class */
+ &omap44xx_fdif_hwmod,
+
/* dss class */
&omap44xx_dss_hwmod,
&omap44xx_dss_dispc_hwmod,
@@ -5100,6 +5317,9 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
/* hsi class */
/* &omap44xx_hsi_hwmod, */
+ /* gpu class */
+ &omap44xx_gpu_hwmod,
+
/* i2c class */
&omap44xx_i2c1_hwmod,
&omap44xx_i2c2_hwmod,
@@ -5112,7 +5332,7 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
&omap44xx_ipu_c1_hwmod,
/* iss class */
-/* &omap44xx_iss_hwmod, */
+ // &omap44xx_iss_hwmod,
/* iva class */
&omap44xx_iva_hwmod,
@@ -5120,7 +5340,7 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
&omap44xx_iva_seq1_hwmod,
/* kbd class */
-/* &omap44xx_kbd_hwmod, */
+ &omap44xx_kbd_hwmod,
/* mailbox class */
&omap44xx_mailbox_hwmod,
@@ -5131,9 +5351,6 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
&omap44xx_mcbsp3_hwmod,
&omap44xx_mcbsp4_hwmod,
- /* mcpdm class */
-/* &omap44xx_mcpdm_hwmod, */
-
/* mcspi class */
&omap44xx_mcspi1_hwmod,
&omap44xx_mcspi2_hwmod,
@@ -5147,9 +5364,15 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
&omap44xx_mmc4_hwmod,
&omap44xx_mmc5_hwmod,
+ /* mcpdm class */
+ &omap44xx_mcpdm_hwmod,
+
/* mpu class */
&omap44xx_mpu_hwmod,
+ /* sl2if class */
+ &omap44xx_sl2if_hwmod,
+
/* smartreflex class */
&omap44xx_smartreflex_core_hwmod,
&omap44xx_smartreflex_iva_hwmod,
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 49c6513e90d..0ef83a1d690 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -14,6 +14,7 @@
*/
#undef DEBUG
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/list.h>
@@ -238,6 +239,8 @@ struct powerdomain *pwrdm_lookup(const char *name)
return pwrdm;
}
+EXPORT_SYMBOL_GPL(pwrdm_lookup);
+
/**
* pwrdm_for_each - call function on each registered clockdomain
* @fn: callback function *
diff --git a/arch/arm/mach-omap2/remoteproc44xx.c b/arch/arm/mach-omap2/remoteproc44xx.c
new file mode 100644
index 00000000000..7549798ff81
--- /dev/null
+++ b/arch/arm/mach-omap2/remoteproc44xx.c
@@ -0,0 +1,276 @@
+/*
+ * Remote Processor machine-specific module for OMAP3
+ *
+ * Copyright (C) 2010 Texas Instruments Inc.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <plat/remoteproc.h>
+#include <plat/dmtimer.h>
+
+#include <plat/omap_device.h>
+#include <plat/omap_hwmod.h>
+
+
+static inline int proc44x_start(struct device *dev, u32 start_addr)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct omap_rproc *obj = (struct omap_rproc *)platform_get_drvdata(
+ to_platform_device(dev));
+ int ret = 0;
+
+ /* Enable the Timer that would be used by co-processor for HIB/WD*/
+ if (obj->timer_hib_id >= 0) {
+ obj->dmtimer =
+ omap_dm_timer_request_specific(obj->timer_hib_id);
+ if (!obj->dmtimer) {
+ ret = -EBUSY;
+ goto err_start;
+ }
+ omap_dm_timer_set_int_enable(obj->dmtimer,
+ OMAP_TIMER_INT_OVERFLOW);
+ omap_dm_timer_set_source(obj->dmtimer, OMAP_TIMER_SRC_SYS_CLK);
+ }
+
+ /* Enable the Timer that would be used by co-processor as Clock*/
+ if (obj->timer_clk_id >= 0) {
+ obj->dmtimer_clk =
+ omap_dm_timer_request_specific(obj->timer_clk_id);
+ if (!obj->dmtimer_clk) {
+ ret = -EBUSY;
+ goto err_start;
+ }
+
+ omap_dm_timer_set_source(obj->dmtimer_clk,
+ OMAP_TIMER_SRC_SYS_CLK);
+ }
+
+ ret = omap_device_enable(pdev);
+ if (ret)
+ goto err_start;
+
+ obj->state = OMAP_RPROC_RUNNING;
+ return 0;
+
+err_start:
+ dev_err(dev, "%s error 0x%x\n", __func__, ret);
+ return ret;
+}
+
+static inline int proc44x_stop(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct omap_rproc *obj = (struct omap_rproc *)platform_get_drvdata(
+ to_platform_device(dev));
+ int ret = 0;
+
+ if (obj->state == OMAP_RPROC_RUNNING) {
+ ret = omap_device_shutdown(pdev);
+ if (ret)
+ dev_err(dev, "%s err 0x%x\n", __func__, ret);
+ }
+
+ if (obj->dmtimer) {
+ omap_dm_timer_free(obj->dmtimer);
+ obj->dmtimer = NULL;
+ }
+
+ if (obj->dmtimer_clk) {
+ omap_dm_timer_free(obj->dmtimer_clk);
+ obj->dmtimer_clk = NULL;
+ }
+
+ obj->state = OMAP_RPROC_STOPPED;
+ return ret;
+}
+
+static inline int proc44x_sleep(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct omap_rproc *obj = (struct omap_rproc *)platform_get_drvdata(
+ to_platform_device(dev));
+ int ret = 0;
+
+ if (obj->state == OMAP_RPROC_RUNNING) {
+ ret = omap_device_shutdown(pdev);
+ if (ret)
+ dev_err(dev, "%s err 0x%x\n", __func__, ret);
+
+ if (obj->dmtimer)
+ omap_dm_timer_stop(obj->dmtimer);
+ if (obj->dmtimer_clk)
+ omap_dm_timer_stop(obj->dmtimer_clk);
+ }
+
+ obj->state = OMAP_RPROC_HIBERNATING;
+ return ret;
+}
+
+static inline int proc44x_wakeup(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct omap_rproc *obj = (struct omap_rproc *)platform_get_drvdata(
+ to_platform_device(dev));
+ int ret = 0;
+
+ if (obj->dmtimer)
+ omap_dm_timer_start(obj->dmtimer);
+ if (obj->dmtimer_clk)
+ omap_dm_timer_start(obj->dmtimer_clk);
+
+ ret = omap_device_enable(pdev);
+ if (ret)
+ goto err_start;
+
+ obj->state = OMAP_RPROC_RUNNING;
+ return 0;
+
+err_start:
+ dev_err(dev, "%s error 0x%x\n", __func__, ret);
+ return ret;
+}
+
+
+static inline int omap4_rproc_get_state(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct omap_device *odev = to_omap_device(pdev);
+
+ return odev->_state;
+}
+
+static struct omap_rproc_ops omap4_ducati0_ops = {
+ .start = proc44x_start,
+ .stop = proc44x_stop,
+ .sleep = proc44x_sleep,
+ .wakeup = proc44x_wakeup,
+ .get_state = omap4_rproc_get_state,
+};
+
+static struct omap_rproc_ops omap4_ducati1_ops = {
+ .start = proc44x_start,
+ .stop = proc44x_stop,
+ .sleep = proc44x_sleep,
+ .wakeup = proc44x_wakeup,
+ .get_state = omap4_rproc_get_state,
+};
+
+static struct omap_rproc_ops omap4_tesla_ops = {
+ .start = proc44x_start,
+ .stop = proc44x_stop,
+ .sleep = proc44x_sleep,
+ .wakeup = proc44x_wakeup,
+ .get_state = omap4_rproc_get_state,
+};
+
+static struct omap_rproc_platform_data omap4_rproc_data[] = {
+ {
+ .name = "tesla",
+ .ops = &omap4_tesla_ops,
+ .oh_name = "dsp_c0",
+ .timer_clk_id = 5,
+ .timer_hib_id = -1,
+ },
+ {
+ .name = "ducati-proc0",
+ .ops = &omap4_ducati0_ops,
+ .oh_name = "ipu_c0",
+ .timer_clk_id = 4,
+#ifdef CONFIG_SYSLINK_IPU_SELF_HIBERNATION
+ .timer_hib_id = 3,
+#else
+ .timer_hib_id = -1,
+#endif
+ },
+ {
+ .name = "ducati-proc1",
+ .ops = &omap4_ducati1_ops,
+ .oh_name = "ipu_c1",
+ .timer_clk_id = 9,
+ .timer_hib_id = -1,
+
+ },
+};
+
+static struct omap_device_pm_latency omap_rproc_latency[] = {
+ {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .deactivate_lat = 1,
+ .activate_lat = 1,
+ },
+};
+
+struct omap_rproc_platform_data *omap4_get_rproc_data(void)
+{
+ return omap4_rproc_data;
+}
+
+
+#define NR_RPROC_DEVICES ARRAY_SIZE(omap4_rproc_data)
+
+static struct omap_device *omap4_rproc_pdev[NR_RPROC_OMAP4_DEVICES];
+
+static int __init omap4_rproc_init(void)
+{
+ struct omap_hwmod *oh;
+ struct omap_device_pm_latency *ohl;
+ char *oh_name, *pdev_name;
+ int ohl_cnt = 0, i;
+ int rproc_data_size;
+ struct omap_rproc_platform_data *rproc_data;
+
+ pdev_name = "omap-remoteproc";
+ ohl = omap_rproc_latency;
+ ohl_cnt = ARRAY_SIZE(omap_rproc_latency);
+
+
+ rproc_data = omap4_get_rproc_data();
+ rproc_data_size = NR_RPROC_OMAP4_DEVICES;
+
+ for (i = 0; i < rproc_data_size; i++) {
+ oh_name = rproc_data[i].oh_name;
+ oh = omap_hwmod_lookup(oh_name);
+ if (!oh) {
+ pr_err("%s: could not look up %s\n", __func__, oh_name);
+ continue;
+ }
+ omap4_rproc_pdev[i] = omap_device_build(pdev_name, i, oh,
+ &rproc_data[i],
+ sizeof(struct omap_rproc_platform_data),
+ ohl, ohl_cnt, false);
+ WARN(IS_ERR(omap4_rproc_pdev[i]), "Could not build omap_device"
+ "for %s %s\n", pdev_name, oh_name);
+ }
+ return 0;
+}
+module_init(omap4_rproc_init);
+
+static void __exit omap4_rproc_exit(void)
+{
+
+}
+module_exit(omap4_rproc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("OMAP4 Remote Processor module");
+MODULE_AUTHOR("Ohad Ben-Cohen <ohad@wizery.com>");
+MODULE_AUTHOR("Hari Kanigeri <h-kanigeri2@ti.com>");
diff --git a/arch/arm/mm/cache-fa.S b/arch/arm/mm/cache-fa.S
index 1fa6f71470d..ad953fe4ef5 100644
--- a/arch/arm/mm/cache-fa.S
+++ b/arch/arm/mm/cache-fa.S
@@ -168,7 +168,7 @@ ENTRY(fa_flush_kern_dcache_area)
* - start - virtual start address
* - end - virtual end address
*/
-fa_dma_inv_range:
+ENTRY(fa_dma_inv_range)
tst r0, #CACHE_DLINESIZE - 1
bic r0, r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c14, 1 @ clean & invalidate D entry
@@ -191,7 +191,7 @@ fa_dma_inv_range:
* - start - virtual start address
* - end - virtual end address
*/
-fa_dma_clean_range:
+ENTRY(fa_dma_clean_range)
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHE_DLINESIZE
@@ -253,5 +253,7 @@ ENTRY(fa_cache_fns)
.long fa_flush_kern_dcache_area
.long fa_dma_map_area
.long fa_dma_unmap_area
+ .long fa_dma_inv_range
+ .long fa_dma_clean_range
.long fa_dma_flush_range
.size fa_cache_fns, . - fa_cache_fns
diff --git a/arch/arm/mm/cache-v3.S b/arch/arm/mm/cache-v3.S
index 2e2bc406a18..64f739eaa4c 100644
--- a/arch/arm/mm/cache-v3.S
+++ b/arch/arm/mm/cache-v3.S
@@ -93,6 +93,20 @@ ENTRY(v3_flush_kern_dcache_area)
/* FALLTHROUGH */
/*
+ * dma_inv_range(start, end)
+ *
+ * Invalidate (discard) the specified virtual address range.
+ * May not write back any entries. If 'start' or 'end'
+ * are not cache line aligned, those lines must be written
+ * back.
+ *
+ * - start - virtual start address
+ * - end - virtual end address
+ */
+ENTRY(v3_dma_inv_range)
+ /* FALLTHROUGH */
+
+/*
* dma_flush_range(start, end)
*
* Clean and invalidate the specified virtual address range.
@@ -103,6 +117,17 @@ ENTRY(v3_flush_kern_dcache_area)
ENTRY(v3_dma_flush_range)
mov r0, #0
mcr p15, 0, r0, c7, c0, 0 @ flush ID cache
+ /* FALLTHROUGH */
+
+/*
+ * dma_clean_range(start, end)
+ *
+ * Clean (write back) the specified virtual address range.
+ *
+ * - start - virtual start address
+ * - end - virtual end address
+ */
+ENTRY(v3_dma_clean_range)
mov pc, lr
/*
@@ -113,7 +138,7 @@ ENTRY(v3_dma_flush_range)
*/
ENTRY(v3_dma_unmap_area)
teq r2, #DMA_TO_DEVICE
- bne v3_dma_flush_range
+ bne v3_dma_inv_range
/* FALLTHROUGH */
/*
@@ -140,5 +165,7 @@ ENTRY(v3_cache_fns)
.long v3_flush_kern_dcache_area
.long v3_dma_map_area
.long v3_dma_unmap_area
+ .long v3_dma_inv_range
+ .long v3_dma_clean_range
.long v3_dma_flush_range
.size v3_cache_fns, . - v3_cache_fns
diff --git a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S
index a8fefb523f1..7824cf6e14a 100644
--- a/arch/arm/mm/cache-v4.S
+++ b/arch/arm/mm/cache-v4.S
@@ -103,6 +103,20 @@ ENTRY(v4_flush_kern_dcache_area)
/* FALLTHROUGH */
/*
+ * dma_inv_range(start, end)
+ *
+ * Invalidate (discard) the specified virtual address range.
+ * May not write back any entries. If 'start' or 'end'
+ * are not cache line aligned, those lines must be written
+ * back.
+ *
+ * - start - virtual start address
+ * - end - virtual end address
+ */
+ENTRY(v4_dma_inv_range)
+ /* FALLTHROUGH */
+
+/*
* dma_flush_range(start, end)
*
* Clean and invalidate the specified virtual address range.
@@ -115,6 +129,17 @@ ENTRY(v4_dma_flush_range)
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 @ flush ID cache
#endif
+ /* FALLTHROUGH */
+
+/*
+ * dma_clean_range(start, end)
+ *
+ * Clean (write back) the specified virtual address range.
+ *
+ * - start - virtual start address
+ * - end - virtual end address
+ */
+ENTRY(v4_dma_clean_range)
mov pc, lr
/*
@@ -125,7 +150,7 @@ ENTRY(v4_dma_flush_range)
*/
ENTRY(v4_dma_unmap_area)
teq r2, #DMA_TO_DEVICE
- bne v4_dma_flush_range
+ bne v4_dma_inv_range
/* FALLTHROUGH */
/*
@@ -152,5 +177,7 @@ ENTRY(v4_cache_fns)
.long v4_flush_kern_dcache_area
.long v4_dma_map_area
.long v4_dma_unmap_area
+ .long v4_dma_inv_range
+ .long v4_dma_clean_range
.long v4_dma_flush_range
.size v4_cache_fns, . - v4_cache_fns
diff --git a/arch/arm/mm/cache-v4wb.S b/arch/arm/mm/cache-v4wb.S
index d3644db467b..57b8a95b8a3 100644
--- a/arch/arm/mm/cache-v4wb.S
+++ b/arch/arm/mm/cache-v4wb.S
@@ -184,7 +184,7 @@ ENTRY(v4wb_coherent_user_range)
* - start - virtual start address
* - end - virtual end address
*/
-v4wb_dma_inv_range:
+ENTRY(v4wb_dma_inv_range)
tst r0, #CACHE_DLINESIZE - 1
bic r0, r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -205,7 +205,7 @@ v4wb_dma_inv_range:
* - start - virtual start address
* - end - virtual end address
*/
-v4wb_dma_clean_range:
+ENTRY(v4wb_dma_clean_range)
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHE_DLINESIZE
@@ -264,5 +264,7 @@ ENTRY(v4wb_cache_fns)
.long v4wb_flush_kern_dcache_area
.long v4wb_dma_map_area
.long v4wb_dma_unmap_area
+ .long v4wb_dma_inv_range
+ .long v4wb_dma_clean_range
.long v4wb_dma_flush_range
.size v4wb_cache_fns, . - v4wb_cache_fns
diff --git a/arch/arm/mm/cache-v4wt.S b/arch/arm/mm/cache-v4wt.S
index 49c2b66cf3d..fe9038dc004 100644
--- a/arch/arm/mm/cache-v4wt.S
+++ b/arch/arm/mm/cache-v4wt.S
@@ -153,12 +153,23 @@ ENTRY(v4wt_flush_kern_dcache_area)
* - start - virtual start address
* - end - virtual end address
*/
-v4wt_dma_inv_range:
+ENTRY(v4wt_dma_inv_range)
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
add r0, r0, #CACHE_DLINESIZE
cmp r0, r1
blo 1b
+ /* FALLTHROUGH */
+
+/*
+ * dma_clean_range(start, end)
+ *
+ * Clean the specified virtual address range.
+ *
+ * - start - virtual start address
+ * - end - virtual end address
+ */
+ENTRY(v4wt_dma_clean_range)
mov pc, lr
/*
@@ -208,5 +219,7 @@ ENTRY(v4wt_cache_fns)
.long v4wt_flush_kern_dcache_area
.long v4wt_dma_map_area
.long v4wt_dma_unmap_area
+ .long v4wt_dma_inv_range
+ .long v4wt_dma_clean_range
.long v4wt_dma_flush_range
.size v4wt_cache_fns, . - v4wt_cache_fns
diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S
index c96fa1b3f49..54f363edc35 100644
--- a/arch/arm/mm/cache-v6.S
+++ b/arch/arm/mm/cache-v6.S
@@ -202,7 +202,7 @@ ENTRY(v6_flush_kern_dcache_area)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-v6_dma_inv_range:
+ENTRY(v6_dma_inv_range)
#ifdef CONFIG_DMA_CACHE_RWFO
ldrb r2, [r0] @ read for ownership
strb r2, [r0] @ write for ownership
@@ -247,7 +247,7 @@ v6_dma_inv_range:
* - start - virtual start address of region
* - end - virtual end address of region
*/
-v6_dma_clean_range:
+ENTRY(v6_dma_clean_range)
bic r0, r0, #D_CACHE_LINE_SIZE - 1
1:
#ifdef CONFIG_DMA_CACHE_RWFO
@@ -340,5 +340,7 @@ ENTRY(v6_cache_fns)
.long v6_flush_kern_dcache_area
.long v6_dma_map_area
.long v6_dma_unmap_area
+ .long v6_dma_inv_range
+ .long v6_dma_clean_range
.long v6_dma_flush_range
.size v6_cache_fns, . - v6_cache_fns
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index 6136e68ce95..4eba077dc4d 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -240,7 +240,7 @@ ENDPROC(v7_flush_kern_dcache_area)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-v7_dma_inv_range:
+ENTRY(v7_dma_inv_range)
dcache_line_size r2, r3
sub r3, r2, #1
tst r0, r3
@@ -264,7 +264,7 @@ ENDPROC(v7_dma_inv_range)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-v7_dma_clean_range:
+ENTRY(v7_dma_clean_range)
dcache_line_size r2, r3
sub r3, r2, #1
bic r0, r0, r3
@@ -334,5 +334,7 @@ ENTRY(v7_cache_fns)
.long v7_flush_kern_dcache_area
.long v7_dma_map_area
.long v7_dma_unmap_area
+ .long v7_dma_inv_range
+ .long v7_dma_clean_range
.long v7_dma_flush_range
.size v7_cache_fns, . - v7_cache_fns
diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S
index 226e3d8351c..31e65cdc12f 100644
--- a/arch/arm/mm/proc-arm1020.S
+++ b/arch/arm/mm/proc-arm1020.S
@@ -275,7 +275,7 @@ ENTRY(arm1020_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-arm1020_dma_inv_range:
+ENTRY(arm1020_dma_inv_range)
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE
tst r0, #CACHE_DLINESIZE - 1
@@ -305,7 +305,7 @@ arm1020_dma_inv_range:
*
* (same as v4wb)
*/
-arm1020_dma_clean_range:
+ENTRY(arm1020_dma_clean_range)
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE
bic r0, r0, #CACHE_DLINESIZE - 1
@@ -374,6 +374,8 @@ ENTRY(arm1020_cache_fns)
.long arm1020_flush_kern_dcache_area
.long arm1020_dma_map_area
.long arm1020_dma_unmap_area
+ .long arm1020_dma_inv_range
+ .long arm1020_dma_clean_range
.long arm1020_dma_flush_range
.align 5
diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S
index 86d9c2cf0bc..6a6838a6977 100644
--- a/arch/arm/mm/proc-arm1020e.S
+++ b/arch/arm/mm/proc-arm1020e.S
@@ -268,7 +268,7 @@ ENTRY(arm1020e_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-arm1020e_dma_inv_range:
+ENTRY(arm1020e_dma_inv_range)
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE
tst r0, #CACHE_DLINESIZE - 1
@@ -294,7 +294,7 @@ arm1020e_dma_inv_range:
*
* (same as v4wb)
*/
-arm1020e_dma_clean_range:
+ENTRY(arm1020e_dma_clean_range)
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE
bic r0, r0, #CACHE_DLINESIZE - 1
@@ -360,6 +360,8 @@ ENTRY(arm1020e_cache_fns)
.long arm1020e_flush_kern_dcache_area
.long arm1020e_dma_map_area
.long arm1020e_dma_unmap_area
+ .long arm1020e_dma_inv_range
+ .long arm1020e_dma_clean_range
.long arm1020e_dma_flush_range
.align 5
diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S
index 83d3dd34f84..c478872a5bd 100644
--- a/arch/arm/mm/proc-arm1022.S
+++ b/arch/arm/mm/proc-arm1022.S
@@ -257,7 +257,7 @@ ENTRY(arm1022_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-arm1022_dma_inv_range:
+ENTRY(arm1022_dma_inv_range)
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE
tst r0, #CACHE_DLINESIZE - 1
@@ -283,7 +283,7 @@ arm1022_dma_inv_range:
*
* (same as v4wb)
*/
-arm1022_dma_clean_range:
+ENTRY(arm1022_dma_clean_range)
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE
bic r0, r0, #CACHE_DLINESIZE - 1
@@ -349,6 +349,8 @@ ENTRY(arm1022_cache_fns)
.long arm1022_flush_kern_dcache_area
.long arm1022_dma_map_area
.long arm1022_dma_unmap_area
+ .long arm1022_dma_inv_range
+ .long arm1022_dma_clean_range
.long arm1022_dma_flush_range
.align 5
diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S
index 686043ee728..9f0b367fa33 100644
--- a/arch/arm/mm/proc-arm1026.S
+++ b/arch/arm/mm/proc-arm1026.S
@@ -251,7 +251,7 @@ ENTRY(arm1026_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-arm1026_dma_inv_range:
+ENTRY(arm1026_dma_inv_range)
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE
tst r0, #CACHE_DLINESIZE - 1
@@ -277,7 +277,7 @@ arm1026_dma_inv_range:
*
* (same as v4wb)
*/
-arm1026_dma_clean_range:
+ENTRY(arm1026_dma_clean_range)
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE
bic r0, r0, #CACHE_DLINESIZE - 1
@@ -343,6 +343,8 @@ ENTRY(arm1026_cache_fns)
.long arm1026_flush_kern_dcache_area
.long arm1026_dma_map_area
.long arm1026_dma_unmap_area
+ .long arm1026_dma_inv_range
+ .long arm1026_dma_clean_range
.long arm1026_dma_flush_range
.align 5
diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S
index 394b623b092..a3a0509e839 100644
--- a/arch/arm/mm/proc-arm920.S
+++ b/arch/arm/mm/proc-arm920.S
@@ -242,7 +242,7 @@ ENTRY(arm920_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-arm920_dma_inv_range:
+ENTRY(arm920_dma_inv_range)
tst r0, #CACHE_DLINESIZE - 1
bic r0, r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -265,7 +265,7 @@ arm920_dma_inv_range:
*
* (same as v4wb)
*/
-arm920_dma_clean_range:
+ENTRY(arm920_dma_clean_range)
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHE_DLINESIZE
@@ -325,6 +325,8 @@ ENTRY(arm920_cache_fns)
.long arm920_flush_kern_dcache_area
.long arm920_dma_map_area
.long arm920_dma_unmap_area
+ .long arm920_dma_inv_range
+ .long arm920_dma_clean_range
.long arm920_dma_flush_range
#endif
diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S
index 36154b1e792..611efc73996 100644
--- a/arch/arm/mm/proc-arm922.S
+++ b/arch/arm/mm/proc-arm922.S
@@ -244,7 +244,7 @@ ENTRY(arm922_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-arm922_dma_inv_range:
+ENTRY(arm922_dma_inv_range)
tst r0, #CACHE_DLINESIZE - 1
bic r0, r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -267,7 +267,7 @@ arm922_dma_inv_range:
*
* (same as v4wb)
*/
-arm922_dma_clean_range:
+ENTRY(arm922_dma_clean_range)
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHE_DLINESIZE
@@ -327,6 +327,8 @@ ENTRY(arm922_cache_fns)
.long arm922_flush_kern_dcache_area
.long arm922_dma_map_area
.long arm922_dma_unmap_area
+ .long arm922_dma_inv_range
+ .long arm922_dma_clean_range
.long arm922_dma_flush_range
#endif
diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S
index 89c5e0009c4..e416f028bf4 100644
--- a/arch/arm/mm/proc-arm925.S
+++ b/arch/arm/mm/proc-arm925.S
@@ -290,7 +290,7 @@ ENTRY(arm925_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-arm925_dma_inv_range:
+ENTRY(arm925_dma_inv_range)
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
tst r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -315,7 +315,7 @@ arm925_dma_inv_range:
*
* (same as v4wb)
*/
-arm925_dma_clean_range:
+ENTRY(arm925_dma_clean_range)
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -382,6 +382,8 @@ ENTRY(arm925_cache_fns)
.long arm925_flush_kern_dcache_area
.long arm925_dma_map_area
.long arm925_dma_unmap_area
+ .long arm925_dma_inv_range
+ .long arm925_dma_clean_range
.long arm925_dma_flush_range
ENTRY(cpu_arm925_dcache_clean_area)
diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S
index 0ed85d930c0..4a6724e3f6f 100644
--- a/arch/arm/mm/proc-arm926.S
+++ b/arch/arm/mm/proc-arm926.S
@@ -253,7 +253,7 @@ ENTRY(arm926_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-arm926_dma_inv_range:
+ENTRY(arm926_dma_inv_range)
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
tst r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -278,7 +278,7 @@ arm926_dma_inv_range:
*
* (same as v4wb)
*/
-arm926_dma_clean_range:
+ENTRY(arm926_dma_clean_range)
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -345,6 +345,8 @@ ENTRY(arm926_cache_fns)
.long arm926_flush_kern_dcache_area
.long arm926_dma_map_area
.long arm926_dma_unmap_area
+ .long arm926_dma_inv_range
+ .long arm926_dma_clean_range
.long arm926_dma_flush_range
ENTRY(cpu_arm926_dcache_clean_area)
diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S
index 26aea3f71c2..9009b55190d 100644
--- a/arch/arm/mm/proc-arm940.S
+++ b/arch/arm/mm/proc-arm940.S
@@ -178,7 +178,7 @@ ENTRY(arm940_flush_kern_dcache_area)
* - start - virtual start address
* - end - virtual end address
*/
-arm940_dma_inv_range:
+ENTRY(arm940_dma_inv_range)
mov ip, #0
mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments
1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
@@ -199,7 +199,7 @@ arm940_dma_inv_range:
* - start - virtual start address
* - end - virtual end address
*/
-arm940_dma_clean_range:
+ENTRY(arm940_dma_clean_range)
ENTRY(cpu_arm940_dcache_clean_area)
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
@@ -274,6 +274,8 @@ ENTRY(arm940_cache_fns)
.long arm940_flush_kern_dcache_area
.long arm940_dma_map_area
.long arm940_dma_unmap_area
+ .long arm940_dma_inv_range
+ .long arm940_dma_clean_range
.long arm940_dma_flush_range
__CPUINIT
diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S
index 8063345406f..ed2234aa88a 100644
--- a/arch/arm/mm/proc-arm946.S
+++ b/arch/arm/mm/proc-arm946.S
@@ -222,7 +222,7 @@ ENTRY(arm946_flush_kern_dcache_area)
* - end - virtual end address
* (same as arm926)
*/
-arm946_dma_inv_range:
+ENTRY(arm946_dma_inv_range)
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
tst r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -247,7 +247,7 @@ arm946_dma_inv_range:
*
* (same as arm926)
*/
-arm946_dma_clean_range:
+ENTRY(arm946_dma_clean_range)
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -316,6 +316,8 @@ ENTRY(arm946_cache_fns)
.long arm946_flush_kern_dcache_area
.long arm946_dma_map_area
.long arm946_dma_unmap_area
+ .long arm946_dma_inv_range
+ .long arm946_dma_clean_range
.long arm946_dma_flush_range
diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S
index d3883eed7a4..1ef5673266a 100644
--- a/arch/arm/mm/proc-feroceon.S
+++ b/arch/arm/mm/proc-feroceon.S
@@ -280,7 +280,7 @@ ENTRY(feroceon_range_flush_kern_dcache_area)
* (same as v4wb)
*/
.align 5
-feroceon_dma_inv_range:
+ENTRY(feroceon_dma_inv_range)
tst r0, #CACHE_DLINESIZE - 1
bic r0, r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -294,7 +294,7 @@ feroceon_dma_inv_range:
mov pc, lr
.align 5
-feroceon_range_dma_inv_range:
+ENTRY(feroceon_range_dma_inv_range)
mrs r2, cpsr
tst r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -320,7 +320,7 @@ feroceon_range_dma_inv_range:
* (same as v4wb)
*/
.align 5
-feroceon_dma_clean_range:
+ENTRY(feroceon_dma_clean_range)
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHE_DLINESIZE
@@ -330,7 +330,7 @@ feroceon_dma_clean_range:
mov pc, lr
.align 5
-feroceon_range_dma_clean_range:
+ENTRY(feroceon_range_dma_clean_range)
mrs r2, cpsr
cmp r1, r0
subne r1, r1, #1 @ top address is inclusive
@@ -421,6 +421,8 @@ ENTRY(feroceon_cache_fns)
.long feroceon_flush_kern_dcache_area
.long feroceon_dma_map_area
.long feroceon_dma_unmap_area
+ .long feroceon_dma_inv_range
+ .long feroceon_dma_clean_range
.long feroceon_dma_flush_range
ENTRY(feroceon_range_cache_fns)
@@ -433,6 +435,8 @@ ENTRY(feroceon_range_cache_fns)
.long feroceon_range_flush_kern_dcache_area
.long feroceon_range_dma_map_area
.long feroceon_dma_unmap_area
+ .long feroceon_range_dma_inv_range
+ .long feroceon_range_dma_clean_range
.long feroceon_range_dma_flush_range
.align 5
diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S
index 9d4f2ae6337..7702f939a65 100644
--- a/arch/arm/mm/proc-mohawk.S
+++ b/arch/arm/mm/proc-mohawk.S
@@ -214,7 +214,7 @@ ENTRY(mohawk_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-mohawk_dma_inv_range:
+ENTRY(mohawk_dma_inv_range)
tst r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
tst r1, #CACHE_DLINESIZE - 1
@@ -237,7 +237,7 @@ mohawk_dma_inv_range:
*
* (same as v4wb)
*/
-mohawk_dma_clean_range:
+ENTRY(mohawk_dma_clean_range)
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHE_DLINESIZE
@@ -297,6 +297,8 @@ ENTRY(mohawk_cache_fns)
.long mohawk_flush_kern_dcache_area
.long mohawk_dma_map_area
.long mohawk_dma_unmap_area
+ .long mohawk_dma_inv_range
+ .long mohawk_dma_clean_range
.long mohawk_dma_flush_range
ENTRY(cpu_mohawk_dcache_clean_area)
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S
index 596213699f3..5c2dc7d68e4 100644
--- a/arch/arm/mm/proc-xsc3.S
+++ b/arch/arm/mm/proc-xsc3.S
@@ -264,7 +264,7 @@ ENTRY(xsc3_flush_kern_dcache_area)
* - start - virtual start address
* - end - virtual end address
*/
-xsc3_dma_inv_range:
+ENTRY(xsc3_dma_inv_range)
tst r0, #CACHELINESIZE - 1
bic r0, r0, #CACHELINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean L1 D line
@@ -285,7 +285,7 @@ xsc3_dma_inv_range:
* - start - virtual start address
* - end - virtual end address
*/
-xsc3_dma_clean_range:
+ENTRY(xsc3_dma_clean_range)
bic r0, r0, #CACHELINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line
add r0, r0, #CACHELINESIZE
@@ -345,6 +345,8 @@ ENTRY(xsc3_cache_fns)
.long xsc3_flush_kern_dcache_area
.long xsc3_dma_map_area
.long xsc3_dma_unmap_area
+ .long xsc3_dma_inv_range
+ .long xsc3_dma_clean_range
.long xsc3_dma_flush_range
ENTRY(cpu_xsc3_dcache_clean_area)
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index ce233bcbf50..61c7dd06022 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -322,7 +322,7 @@ ENTRY(xscale_flush_kern_dcache_area)
* - start - virtual start address
* - end - virtual end address
*/
-xscale_dma_inv_range:
+ENTRY(xscale_dma_inv_range)
tst r0, #CACHELINESIZE - 1
bic r0, r0, #CACHELINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -343,7 +343,7 @@ xscale_dma_inv_range:
* - start - virtual start address
* - end - virtual end address
*/
-xscale_dma_clean_range:
+ENTRY(xscale_dma_clean_range)
bic r0, r0, #CACHELINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHELINESIZE
@@ -417,6 +417,8 @@ ENTRY(xscale_cache_fns)
.long xscale_flush_kern_dcache_area
.long xscale_dma_map_area
.long xscale_dma_unmap_area
+ .long xscale_dma_inv_range
+ .long xscale_dma_clean_range
.long xscale_dma_flush_range
/*
@@ -442,6 +444,8 @@ ENTRY(xscale_80200_A0_A1_cache_fns)
.long xscale_dma_a0_map_area
.long xscale_dma_unmap_area
.long xscale_dma_flush_range
+ .long xscale_dma_clean_range
+ .long xscale_dma_flush_range
ENTRY(cpu_xscale_dcache_clean_area)
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 283f4552d1d..cd97a086ba2 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -72,7 +72,7 @@ config OMAP_SMARTREFLEX_CLASS3
config OMAP_RESET_CLOCKS
bool "Reset unused clocks during boot"
- depends on ARCH_OMAP
+ depends on ARCH_OMAP && BROKEN
help
Say Y if you want to reset unused clocks during boot.
This option saves power, but assumes all drivers are
@@ -132,9 +132,20 @@ config OMAP_MBOX_KFIFO_SIZE
This can also be changed at runtime (via the mbox_kfifo_size
module parameter).
+config OMAP_REMOTE_PROC
+ bool "Remote Processor framework support"
+ depends on ARCH_OMAP
+ help
+ Say Y here if you want to use OMAP Remote Processor framework
+ support for DSP, IVA, Tesla and Ducati (OMAP2/3/4).
+
config OMAP_IOMMU
tristate
+config OMAP_USER_DMM
+ tristate
+ select GENERIC_ALLOCATOR
+
config OMAP_IOMMU_DEBUG
tristate "Export OMAP IOMMU internals in DebugFS"
depends on OMAP_IOMMU && DEBUG_FS
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index ec7862e9149..3e68d194ce8 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -21,6 +21,9 @@ obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
obj-$(CONFIG_OMAP_IOMMU) += iommu.o iovmm.o
obj-$(CONFIG_OMAP_IOMMU_DEBUG) += iommu-debug.o
+obj-$(CONFIG_OMAP_USER_DMM) += dmm_user.o iodmm.o
+
+#obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
obj-$(CONFIG_OMAP_DEBUG_DEVICES) += debug-devices.o
obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o
@@ -29,5 +32,7 @@ obj-y += $(i2c-omap-m) $(i2c-omap-y)
# OMAP mailbox framework
obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o
+obj-$(CONFIG_OMAP_REMOTE_PROC) += remoteproc.o
obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
+obj-$(CONFIG_ARCH_OMAP4) += hwspinlock.o
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index 7d9f815cede..8e28ea448bb 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -16,19 +16,25 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/memblock.h>
+#include <linux/err.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/map.h>
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
#include <plat/tc.h>
#include <plat/board.h>
#include <plat/mmc.h>
#include <mach/gpio.h>
#include <plat/menelaus.h>
#include <plat/mcbsp.h>
+#include <plat/mcpdm.h>
#include <plat/omap44xx.h>
+#include <sound/omap-abe-dsp.h>
+
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_OMAP_MCBSP) || defined(CONFIG_OMAP_MCBSP_MODULE)
@@ -74,34 +80,75 @@ void omap_mcbsp_register_board_cfg(struct resource *res, int res_count,
/*-------------------------------------------------------------------------*/
-#if defined(CONFIG_SND_OMAP_SOC_MCPDM) || \
- defined(CONFIG_SND_OMAP_SOC_MCPDM_MODULE)
+#if defined(CONFIG_SND_OMAP_SOC_DMIC) || \
+ defined(CONFIG_SND_OMAP_SOC_DMIC_MODULE)
-static struct resource mcpdm_resources[] = {
+static struct omap_device_pm_latency omap_dmic_latency[] = {
{
- .name = "mcpdm_mem",
- .start = OMAP44XX_MCPDM_BASE,
- .end = OMAP44XX_MCPDM_BASE + SZ_4K,
- .flags = IORESOURCE_MEM,
- },
- {
- .name = "mcpdm_irq",
- .start = OMAP44XX_IRQ_MCPDM,
- .end = OMAP44XX_IRQ_MCPDM,
- .flags = IORESOURCE_IRQ,
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
},
};
-static struct platform_device omap_mcpdm_device = {
- .name = "omap-mcpdm",
- .id = -1,
- .num_resources = ARRAY_SIZE(mcpdm_resources),
- .resource = mcpdm_resources,
+static void omap_init_dmic(void)
+{
+ struct omap_hwmod *oh;
+ struct omap_device *od;
+
+ oh = omap_hwmod_lookup("dmic");
+ if (!oh) {
+ printk(KERN_ERR "Could not look up dmic hw_mod\n");
+ return;
+ }
+
+ od = omap_device_build("omap-dmic-dai", -1, oh, NULL, 0,
+ omap_dmic_latency,
+ ARRAY_SIZE(omap_dmic_latency), 0);
+ if (IS_ERR(od))
+ printk(KERN_ERR "Could not build omap_device for omap-dmic-dai\n");
+}
+#else
+static inline void omap_init_dmic(void) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#if defined(CONFIG_SND_OMAP_SOC_MCPDM) || \
+ defined(CONFIG_SND_OMAP_SOC_MCPDM_MODULE)
+
+static struct omap_device_pm_latency omap_mcpdm_latency[] = {
+ {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ },
};
static void omap_init_mcpdm(void)
{
- (void) platform_device_register(&omap_mcpdm_device);
+ struct omap_hwmod *oh;
+ struct omap_device *od;
+ struct omap_mcpdm_platform_data *pdata;
+
+ oh = omap_hwmod_lookup("omap-mcpdm-dai");
+ if (!oh) {
+ printk(KERN_ERR "Could not look up mcpdm hw_mod\n");
+ return;
+ }
+
+ pdata = kzalloc(sizeof(struct omap_mcpdm_platform_data), GFP_KERNEL);
+ if (!pdata) {
+ printk(KERN_ERR "Could not allocate platform data\n");
+ return;
+ }
+
+ od = omap_device_build("omap-mcpdm-dai", -1, oh, pdata,
+ sizeof(struct omap_mcpdm_platform_data),
+ omap_mcpdm_latency,
+ ARRAY_SIZE(omap_mcpdm_latency), 0);
+ if (IS_ERR(od))
+ printk(KERN_ERR "Could not build omap_device for omap-mcpdm-dai\n");
}
#else
static inline void omap_init_mcpdm(void) {}
@@ -109,6 +156,54 @@ static inline void omap_init_mcpdm(void) {}
/*-------------------------------------------------------------------------*/
+#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP) || \
+ defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE)
+
+static struct omap_device_pm_latency omap_aess_latency[] = {
+ {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ },
+};
+
+static void omap_init_aess(void)
+{
+ struct omap_hwmod *oh;
+ struct omap_device *od;
+ struct omap4_abe_dsp_pdata *pdata;
+
+ oh = omap_hwmod_lookup("omap-aess-audio");
+ if (!oh) {
+ printk (KERN_ERR "Could not look up aess hw_mod\n");
+ return;
+ }
+
+ pdata = kzalloc(sizeof(struct omap4_abe_dsp_pdata), GFP_KERNEL);
+ if (!pdata) {
+ printk(KERN_ERR "Could not allocate platform data\n");
+ return;
+ }
+
+ /* FIXME: Add correct context loss counter */
+ //pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
+
+ od = omap_device_build("omap-aess-audio", -1, oh, pdata,
+ sizeof(struct omap4_abe_dsp_pdata),
+ omap_aess_latency,
+ ARRAY_SIZE(omap_aess_latency), 0);
+
+ kfree(pdata);
+
+ if (IS_ERR(od))
+ printk(KERN_ERR "Could not build omap_device for omap-aess-audio\n");
+}
+#else
+static inline void omap_init_aess(void) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
@@ -291,7 +386,9 @@ static int __init omap_init_devices(void)
* in alphabetical order so they're easier to sort through.
*/
omap_init_rng();
+ omap_init_dmic();
omap_init_mcpdm();
+ omap_init_aess();
omap_init_uwire();
return 0;
}
diff --git a/arch/arm/plat-omap/dmm_user.c b/arch/arm/plat-omap/dmm_user.c
new file mode 100644
index 00000000000..da4f41579c2
--- /dev/null
+++ b/arch/arm/plat-omap/dmm_user.c
@@ -0,0 +1,288 @@
+/*
+ * OMAP DMM (Dynamic memory mapping) to IOMMU module
+ *
+ * Copyright (C) 2010 Texas Instruments. All rights reserved.
+ *
+ * Authors: Hari Kanigeri <h-kanigeri2@ti.com>
+ * Ramesh Gupta <grgupta@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/swap.h>
+#include <linux/genalloc.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <plat/iommu.h>
+#include <plat/iovmm.h>
+#include <plat/dmm_user.h>
+
+
+#define OMAP_DMM_NAME "iovmm-omap"
+
+static atomic_t num_of_iovmmus;
+static struct class *omap_dmm_class;
+static dev_t omap_dmm_dev;
+
+static long omap_dmm_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long args)
+{
+ struct iodmm_struct *obj;
+ int ret = 0;
+ obj = (struct iodmm_struct *)filp->private_data;
+
+ if (!obj)
+ return -EINVAL;
+
+ if (_IOC_TYPE(cmd) != DMM_IOC_MAGIC)
+ return -ENOTTY;
+
+ switch (cmd) {
+ case DMM_IOCSETTLBENT:
+ /* FIXME: re-visit this check to perform
+ proper permission checks */
+ /* if (!capable(CAP_SYS_ADMIN))
+ return -EPERM; */
+ ret = program_tlb_entry(obj, (const void __user *)args);
+ break;
+ case DMM_IOCCREATEPOOL:
+ /* FIXME: re-visit this check to perform
+ proper permission checks */
+ /* if (!capable(CAP_SYS_ADMIN))
+ return -EPERM; */
+ ret = omap_create_dmm_pool(obj, (const void __user *)args);
+ break;
+ case DMM_IOCMEMMAP:
+ ret = dmm_user(obj, (void __user *)args);
+ break;
+ case DMM_IOCMEMUNMAP:
+ ret = user_un_map(obj, (const void __user *)args);
+ break;
+ case IOMMU_IOCEVENTREG:
+ ret = register_mmufault(obj, (const void __user *)args);
+ break;
+ case IOMMU_IOCEVENTUNREG:
+ ret = unregister_mmufault(obj, (const void __user *)args);
+ break;
+ case DMM_IOCMEMFLUSH:
+ ret = proc_begin_dma(obj, (void __user *)args);
+ break;
+ case DMM_IOCMEMINV:
+ ret = proc_end_dma(obj, (void __user *)args);
+ break;
+ /* This ioctl can be deprecated */
+ case DMM_IOCDELETEPOOL:
+ break;
+ case DMM_IOCDATOPA:
+ default:
+ return -ENOTTY;
+ }
+
+ return ret;
+}
+
+static int omap_dmm_open(struct inode *inode, struct file *filp)
+{
+ struct iodmm_struct *iodmm;
+ struct iovmm_device *obj;
+
+ obj = container_of(inode->i_cdev, struct iovmm_device, cdev);
+ obj->refcount++;
+
+ iodmm = kzalloc(sizeof(struct iodmm_struct), GFP_KERNEL);
+ INIT_LIST_HEAD(&iodmm->map_list);
+
+ iodmm->iovmm = obj;
+ obj->iommu = iommu_get(obj->name);
+ filp->private_data = iodmm;
+
+ return 0;
+}
+
+static int omap_dmm_release(struct inode *inode, struct file *filp)
+{
+ int status = 0;
+ struct iodmm_struct *obj;
+
+ if (!filp->private_data) {
+ status = -EIO;
+ goto err_out;
+ }
+ obj = filp->private_data;
+
+ flush_signals(current);
+
+ status = mutex_lock_interruptible(&obj->iovmm->dmm_map_lock);
+ if (status == 0) {
+ /*
+ * Report to remote Processor of the cleanup of these
+ * resources before cleaning in order to avoid MMU fault
+ * type of behavior
+ */
+ if (!list_empty(&obj->map_list)) {
+ iommu_notify_event(obj->iovmm->iommu, IOMMU_CLOSE,
+ NULL);
+ }
+ mutex_unlock(&obj->iovmm->dmm_map_lock);
+ } else {
+ pr_err("%s mutex_lock_interruptible returned 0x%x\n",
+ __func__, status);
+ }
+
+ user_remove_resources(obj);
+ iommu_put(obj->iovmm->iommu);
+
+ /* Delete all the DMM pools after the reference count goes to zero */
+ if (--obj->iovmm->refcount == 0)
+ omap_delete_dmm_pools(obj);
+
+ kfree(obj);
+
+ filp->private_data = NULL;
+
+err_out:
+ return status;
+}
+
+static const struct file_operations omap_dmm_fops = {
+ .owner = THIS_MODULE,
+ .open = omap_dmm_open,
+ .release = omap_dmm_release,
+ .unlocked_ioctl = omap_dmm_ioctl,
+};
+
+static int __devinit omap_dmm_probe(struct platform_device *pdev)
+{
+ int err = -ENODEV;
+ int major, minor;
+ struct device *tmpdev;
+ struct iommu_platform_data *pdata =
+ (struct iommu_platform_data *)pdev->dev.platform_data;
+ int ret = 0;
+ struct iovmm_device *obj;
+
+ obj = kzalloc(sizeof(struct iovmm_device), GFP_KERNEL);
+
+ major = MAJOR(omap_dmm_dev);
+ minor = atomic_read(&num_of_iovmmus);
+ atomic_inc(&num_of_iovmmus);
+
+ obj->minor = minor;
+ obj->name = pdata->name;
+ INIT_LIST_HEAD(&obj->mmap_pool);
+
+ cdev_init(&obj->cdev, &omap_dmm_fops);
+ obj->cdev.owner = THIS_MODULE;
+ ret = cdev_add(&obj->cdev, MKDEV(major, minor), 1);
+
+ if (ret) {
+ dev_err(&pdev->dev, "%s: cdev_add failed: %d\n", __func__, ret);
+ goto err_cdev;
+ }
+ tmpdev = device_create(omap_dmm_class, NULL,
+ MKDEV(major, minor),
+ NULL,
+ OMAP_DMM_NAME "%d", minor);
+ if (IS_ERR(tmpdev)) {
+ ret = PTR_ERR(tmpdev);
+ pr_err("%s: device_create failed: %d\n", __func__, ret);
+ goto clean_cdev;
+ }
+
+ pr_info("%s initialized %s, major: %d, base-minor: %d\n",
+ OMAP_DMM_NAME,
+ pdata->name,
+ MAJOR(omap_dmm_dev),
+ minor);
+
+ mutex_init(&obj->dmm_map_lock);
+ platform_set_drvdata(pdev, obj);
+ return 0;
+
+clean_cdev:
+ cdev_del(&obj->cdev);
+err_cdev:
+ return err;
+}
+
+static int __devexit omap_dmm_remove(struct platform_device *pdev)
+{
+ struct iovmm_device *obj = platform_get_drvdata(pdev);
+ int major = MAJOR(omap_dmm_dev);
+
+ device_destroy(omap_dmm_class, MKDEV(major, obj->minor));
+ cdev_del(&obj->cdev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(obj);
+
+ return 0;
+
+}
+
+static struct platform_driver omap_dmm_driver = {
+ .probe = omap_dmm_probe,
+ .remove = __devexit_p(omap_dmm_remove),
+ .driver = {
+ .name = "omap-iovmm",
+ },
+};
+
+static int __init dmm_user_init(void)
+{
+ int num, ret;
+
+ num = iommu_get_plat_data_size();
+
+ ret = alloc_chrdev_region(&omap_dmm_dev, 0, num, OMAP_DMM_NAME);
+ if (ret) {
+ pr_err("%s: alloc_chrdev_region failed: %d\n", __func__, ret);
+ goto out;
+ }
+ omap_dmm_class = class_create(THIS_MODULE, OMAP_DMM_NAME);
+ if (IS_ERR(omap_dmm_class)) {
+ ret = PTR_ERR(omap_dmm_class);
+ pr_err("%s: class_create failed: %d\n", __func__, ret);
+ goto unreg_region;
+ }
+ atomic_set(&num_of_iovmmus, 0);
+
+ return platform_driver_register(&omap_dmm_driver);
+unreg_region:
+ unregister_chrdev_region(omap_dmm_dev, num);
+out:
+ return ret;
+}
+module_init(dmm_user_init);
+
+static void __exit dmm_user_exit(void)
+{
+ int num = iommu_get_plat_data_size();
+
+ class_destroy(omap_dmm_class);
+ unregister_chrdev_region(omap_dmm_dev, num);
+ platform_driver_unregister(&omap_dmm_driver);
+}
+module_exit(dmm_user_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Userspace DMM to IOMMU");
+MODULE_AUTHOR("Hari Kanigeri");
+MODULE_AUTHOR("Ramesh Gupta");
diff --git a/arch/arm/plat-omap/hwspinlock.c b/arch/arm/plat-omap/hwspinlock.c
new file mode 100644
index 00000000000..7cfe8774750
--- /dev/null
+++ b/arch/arm/plat-omap/hwspinlock.c
@@ -0,0 +1,335 @@
+/*
+ * OMAP hardware spinlock driver
+ *
+ * Copyright (C) 2010 Texas Instruments. All rights reserved.
+ *
+ * Contact: Simon Que <sque@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * This driver supports:
+ * - Reserved spinlocks for internal use
+ * - Dynamic allocation of unreserved locks
+ * - Lock, unlock, and trylock functions, with or without disabling irqs/preempt
+ * - Registered as a platform device driver
+ *
+ * The device initialization uses hwmod to configure the devices. One device
+ * will be created for each IP. It will pass spinlock register offset info to
+ * the driver. The device initialization file is:
+ * arch/arm/mach-omap2/hwspinlocks.c
+ *
+ * The driver takes in register offset info passed in device initialization.
+ * It uses hwmod to obtain the base address of the hardware spinlock module.
+ * Then it reads info from the registers. The function hwspinlock_probe()
+ * initializes the array of spinlock structures, each containing a spinlock
+ * register address calculated from the base address and lock offsets.
+ *
+ * Here's an API summary:
+ *
+ * int hwspinlock_lock(struct hwspinlock *);
+ * Attempt to lock a hardware spinlock. If it is busy, the function will
+ * keep trying until it succeeds. This is a blocking function.
+ * int hwspinlock_trylock(struct hwspinlock *);
+ * Attempt to lock a hardware spinlock. If it is busy, the function will
+ * return BUSY. If it succeeds in locking, the function will return
+ * ACQUIRED. This is a non-blocking function
+ * int hwspinlock_unlock(struct hwspinlock *);
+ * Unlock a hardware spinlock.
+ *
+ * struct hwspinlock *hwspinlock_request(void);
+ * Provides for "dynamic allocation" of a hardware spinlock. It returns
+ * the handle to the next available (unallocated) spinlock. If no more
+ * locks are available, it returns NULL.
+ * struct hwspinlock *hwspinlock_request_specific(unsigned int);
+ * Provides for "static allocation" of a specific hardware spinlock. This
+ * allows the system to use a specific spinlock, identified by an ID. If
+ * the ID is invalid or if the desired lock is already allocated, this
+ * will return NULL. Otherwise it returns a spinlock handle.
+ * int hwspinlock_free(struct hwspinlock *);
+ * Frees an allocated hardware spinlock (either reserved or unreserved).
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <plat/hwspinlock.h>
+
+/* Spinlock count code */
+#define SPINLOCK_32_REGS 1
+#define SPINLOCK_64_REGS 2
+#define SPINLOCK_128_REGS 4
+#define SPINLOCK_256_REGS 8
+#define SPINLOCK_NUMLOCKS_OFFSET 24
+
+/* for managing a hardware spinlock module */
+struct hwspinlock_state {
+ bool is_init; /* For first-time initialization */
+ int num_locks; /* Total number of locks in system */
+ spinlock_t local_lock; /* Local protection */
+ void __iomem *io_base; /* Mapped base address */
+};
+
+/* Points to the hardware spinlock module */
+static struct hwspinlock_state hwspinlock_state;
+static struct hwspinlock_state *hwspinlock_module = &hwspinlock_state;
+
+/* Spinlock object */
+struct hwspinlock {
+ bool is_init;
+ int id;
+ void __iomem *lock_reg;
+ bool is_allocated;
+ struct platform_device *pdev;
+};
+
+/* Array of spinlocks */
+static struct hwspinlock *hwspinlocks;
+
+/* API functions */
+
+/* Busy loop to acquire a spinlock */
+int hwspinlock_lock(struct hwspinlock *handle)
+{
+ int retval;
+
+ if (WARN_ON(handle == NULL))
+ return -EINVAL;
+
+ if (WARN_ON(in_irq()))
+ return -EPERM;
+
+ if (pm_runtime_get_sync(&handle->pdev->dev) < 0)
+ return -ENODEV;
+
+ /* Attempt to acquire the lock by reading from it */
+ do {
+ retval = readl(handle->lock_reg);
+ } while (retval == HWSPINLOCK_BUSY);
+
+ return 0;
+}
+EXPORT_SYMBOL(hwspinlock_lock);
+
+/* Attempt to acquire a spinlock once */
+int hwspinlock_trylock(struct hwspinlock *handle)
+{
+ int retval = 0;
+
+ if (WARN_ON(handle == NULL))
+ return -EINVAL;
+
+ if (WARN_ON(in_irq()))
+ return -EPERM;
+
+ if (pm_runtime_get_sync(&handle->pdev->dev) < 0)
+ return -ENODEV;
+
+ /* Attempt to acquire the lock by reading from it */
+ retval = readl(handle->lock_reg);
+
+ if (retval == HWSPINLOCK_BUSY)
+ pm_runtime_put_sync(&handle->pdev->dev);
+
+ return retval;
+}
+EXPORT_SYMBOL(hwspinlock_trylock);
+
+/* Release a spinlock */
+int hwspinlock_unlock(struct hwspinlock *handle)
+{
+ if (WARN_ON(handle == NULL))
+ return -EINVAL;
+
+ /* Release it by writing 0 to it */
+ writel(0, handle->lock_reg);
+
+ pm_runtime_put_sync(&handle->pdev->dev);
+
+ return 0;
+}
+EXPORT_SYMBOL(hwspinlock_unlock);
+
+/* Request an unclaimed spinlock */
+struct hwspinlock *hwspinlock_request(void)
+{
+ int i;
+ bool found = false;
+ struct hwspinlock *handle = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hwspinlock_module->local_lock, flags);
+ /* Search for an unclaimed, unreserved lock */
+ for (i = 0; i < hwspinlock_module->num_locks && !found; i++) {
+ if (!hwspinlocks[i].is_allocated) {
+ found = true;
+ handle = &hwspinlocks[i];
+ }
+ }
+ spin_unlock_irqrestore(&hwspinlock_module->local_lock, flags);
+
+ /* Return error if no more locks available */
+ if (!found)
+ return NULL;
+
+ handle->is_allocated = true;
+
+ return handle;
+}
+EXPORT_SYMBOL(hwspinlock_request);
+
+/* Request an unclaimed spinlock by ID */
+struct hwspinlock *hwspinlock_request_specific(unsigned int id)
+{
+ struct hwspinlock *handle = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hwspinlock_module->local_lock, flags);
+
+ if (WARN_ON(hwspinlocks[id].is_allocated))
+ goto exit;
+
+ handle = &hwspinlocks[id];
+ handle->is_allocated = true;
+
+exit:
+ spin_unlock_irqrestore(&hwspinlock_module->local_lock, flags);
+ return handle;
+}
+EXPORT_SYMBOL(hwspinlock_request_specific);
+
+/* Release a claimed spinlock */
+int hwspinlock_free(struct hwspinlock *handle)
+{
+ if (WARN_ON(handle == NULL))
+ return -EINVAL;
+
+ if (WARN_ON(!handle->is_allocated))
+ return -ENOMEM;
+
+ handle->is_allocated = false;
+
+ return 0;
+}
+EXPORT_SYMBOL(hwspinlock_free);
+
+/* Probe function */
+static int __devinit hwspinlock_probe(struct platform_device *pdev)
+{
+ struct hwspinlock_plat_info *pdata = pdev->dev.platform_data;
+ struct resource *res;
+ void __iomem *io_base;
+ int id;
+
+ void __iomem *sysstatus_reg;
+
+ /* Determine number of locks */
+ sysstatus_reg = ioremap(OMAP44XX_SPINLOCK_BASE +
+ pdata->sysstatus_offset, sizeof(u32));
+ switch (readl(sysstatus_reg) >> SPINLOCK_NUMLOCKS_OFFSET) {
+ case SPINLOCK_32_REGS:
+ hwspinlock_module->num_locks = 32;
+ break;
+ case SPINLOCK_64_REGS:
+ hwspinlock_module->num_locks = 64;
+ break;
+ case SPINLOCK_128_REGS:
+ hwspinlock_module->num_locks = 128;
+ break;
+ case SPINLOCK_256_REGS:
+ hwspinlock_module->num_locks = 256;
+ break;
+ default:
+ return -EINVAL; /* Invalid spinlock count code */
+ }
+ iounmap(sysstatus_reg);
+
+ /* Allocate spinlock device objects */
+ hwspinlocks = kmalloc(sizeof(struct hwspinlock) *
+ hwspinlock_module->num_locks, GFP_KERNEL);
+ if (WARN_ON(hwspinlocks == NULL))
+ return -ENOMEM;
+
+ /* Initialize local lock */
+ spin_lock_init(&hwspinlock_module->local_lock);
+
+ /* Get address info */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ /* Map spinlock module address space */
+ io_base = ioremap(res->start, resource_size(res));
+ hwspinlock_module->io_base = io_base;
+
+ /* Set up each individual lock handle */
+ for (id = 0; id < hwspinlock_module->num_locks; id++) {
+ hwspinlocks[id].id = id;
+ hwspinlocks[id].pdev = pdev;
+
+ hwspinlocks[id].is_init = true;
+ hwspinlocks[id].is_allocated = false;
+
+ hwspinlocks[id].lock_reg = io_base + pdata->
+ lock_base_offset + sizeof(u32) * id;
+ }
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+}
+
+static struct platform_driver hwspinlock_driver = {
+ .probe = hwspinlock_probe,
+ .driver = {
+ .name = "hwspinlock",
+ },
+};
+
+/* Initialization function */
+static int __init hwspinlock_init(void)
+{
+ int retval = 0;
+
+ /* Register spinlock driver */
+ retval = platform_driver_register(&hwspinlock_driver);
+
+ return retval;
+}
+postcore_initcall(hwspinlock_init);
+
+/* Cleanup function */
+static void __exit hwspinlock_exit(void)
+{
+ int id;
+
+ platform_driver_unregister(&hwspinlock_driver);
+
+ for (id = 0; id < hwspinlock_module->num_locks; id++)
+ hwspinlocks[id].is_init = false;
+ iounmap(hwspinlock_module->io_base);
+
+ /* Free spinlock device objects */
+ if (hwspinlock_module->is_init)
+ kfree(hwspinlocks);
+}
+module_exit(hwspinlock_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Hardware spinlock driver");
+MODULE_AUTHOR("Simon Que");
+MODULE_AUTHOR("Hari Kanigeri");
diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h
index 5e04ddc18fa..2cba3d38888 100644
--- a/arch/arm/plat-omap/include/plat/display.h
+++ b/arch/arm/plat-omap/include/plat/display.h
@@ -23,6 +23,7 @@
#include <linux/list.h>
#include <linux/kobject.h>
#include <linux/device.h>
+#include <linux/notifier.h>
#include <linux/platform_device.h>
#include <asm/atomic.h>
@@ -459,6 +460,7 @@ struct omap_dss_device {
struct omap_overlay_manager *manager;
enum omap_dss_display_state state;
+ struct blocking_notifier_head notifier;
/* platform specific */
int (*platform_enable)(struct omap_dss_device *dssdev);
@@ -532,6 +534,18 @@ struct omap_dss_device *omap_dss_find_device(void *data,
int omap_dss_start_device(struct omap_dss_device *dssdev);
void omap_dss_stop_device(struct omap_dss_device *dssdev);
+/* the event id of the event that occurred is passed in as the second arg
+ * to the notifier function, and the dssdev is passed as the third.
+ */
+enum omap_dss_event {
+ OMAP_DSS_SIZE_CHANGE
+ /* possibly add additional events, like hot-plug connect/disconnect */
+};
+
+void omap_dss_notify(struct omap_dss_device *dssdev, enum omap_dss_event evt);
+void omap_dss_add_notify(struct omap_dss_device *dssdev, struct notifier_block *nb);
+void omap_dss_remove_notify(struct omap_dss_device *dssdev, struct notifier_block *nb);
+
int omap_dss_get_num_overlay_managers(void);
struct omap_overlay_manager *omap_dss_get_overlay_manager(int num);
diff --git a/arch/arm/plat-omap/include/plat/dmm_user.h b/arch/arm/plat-omap/include/plat/dmm_user.h
new file mode 100644
index 00000000000..c231314810e
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/dmm_user.h
@@ -0,0 +1,126 @@
+/*
+ * omap dmm user: virtual address space management
+ *
+ * Copyright (C) 2010-2011 Texas Instruments
+ *
+ * Written by Hari Kanigeri <h-kanigeri2@ti.com>
+ * Ramesh Gupta <grgupta@ti.com>
+ * 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 <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/dma-mapping.h>
+
+#ifndef __DMM_USER_MMAP_H
+#define __DMM_USER_MMAP_H
+
+
+#define DMM_IOC_MAGIC 'V'
+
+#define DMM_IOCSETTLBENT _IO(DMM_IOC_MAGIC, 0)
+#define DMM_IOCMEMMAP _IO(DMM_IOC_MAGIC, 1)
+#define DMM_IOCMEMUNMAP _IO(DMM_IOC_MAGIC, 2)
+#define DMM_IOCDATOPA _IO(DMM_IOC_MAGIC, 3)
+#define DMM_IOCMEMFLUSH _IO(DMM_IOC_MAGIC, 4)
+#define DMM_IOCMEMINV _IO(DMM_IOC_MAGIC, 5)
+#define DMM_IOCCREATEPOOL _IO(DMM_IOC_MAGIC, 6)
+#define DMM_IOCDELETEPOOL _IO(DMM_IOC_MAGIC, 7)
+#define IOMMU_IOCEVENTREG _IO(DMM_IOC_MAGIC, 10)
+#define IOMMU_IOCEVENTUNREG _IO(DMM_IOC_MAGIC, 11)
+
+#define DMM_DA_ANON 0x1
+#define DMM_DA_PHYS 0x2
+#define DMM_DA_USER 0x4
+
+struct iovmm_pool {
+ u32 pool_id;
+ u32 da_begin;
+ u32 da_end;
+ struct gen_pool *genpool;
+ struct list_head list;
+};
+
+struct iovmm_pool_info {
+ u32 pool_id;
+ u32 da_begin;
+ u32 da_end;
+ u32 size;
+ u32 flags;
+};
+
+/* used to cache dma mapping information */
+struct device_dma_map_info {
+ /* number of elements requested by us */
+ int num_pages;
+ /* list of buffers used in this DMA action */
+ struct scatterlist *sg;
+};
+
+struct dmm_map_info {
+ u32 mpu_addr;
+ u32 *da;
+ u32 num_of_buf;
+ u32 size;
+ u32 pool_id;
+ u32 flags;
+};
+
+struct dmm_dma_info {
+ void *pva;
+ u32 ul_size;
+ enum dma_data_direction dir;
+};
+
+struct dmm_map_object {
+ struct list_head link;
+ u32 da;
+ u32 va;
+ u32 size;
+ u32 num_usr_pgs;
+ struct gen_pool *gen_pool;
+ struct page **pages;
+ struct device_dma_map_info dma_info;
+};
+
+struct iodmm_struct {
+ struct iovmm_device *iovmm;
+ struct list_head map_list;
+ u32 pool_id;
+};
+
+struct iovmm_device {
+ /* iommu object which this belongs to */
+ struct iommu *iommu;
+ const char *name;
+ /* List of memory pool it manages */
+ struct list_head mmap_pool;
+ struct mutex dmm_map_lock;
+ int minor;
+ struct cdev cdev;
+ int refcount;
+};
+
+/* user dmm functions */
+int dmm_user(struct iodmm_struct *obj, void __user *args);
+
+void user_remove_resources(struct iodmm_struct *obj);
+
+int user_un_map(struct iodmm_struct *obj, const void __user *args);
+
+int proc_begin_dma(struct iodmm_struct *obj, const void __user *args);
+
+int proc_end_dma(struct iodmm_struct *obj, const void __user *args);
+
+int omap_create_dmm_pool(struct iodmm_struct *obj, const void __user *args);
+
+int omap_delete_dmm_pools(struct iodmm_struct *obj);
+
+int program_tlb_entry(struct iodmm_struct *obj, const void __user *args);
+
+int register_mmufault(struct iodmm_struct *obj, const void __user *args);
+
+int unregister_mmufault(struct iodmm_struct *obj, const void __user *args);
+#endif
diff --git a/arch/arm/plat-omap/include/plat/gpu.h b/arch/arm/plat-omap/include/plat/gpu.h
new file mode 100644
index 00000000000..70dcc922bcb
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/gpu.h
@@ -0,0 +1,33 @@
+/*
+ * arch/arm/plat-omap/include/plat/gpu.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef OMAP_GPU_H
+#define OMAP_GPU_H
+
+#include <plat/omap-pm.h>
+#include <linux/platform_device.h>
+
+struct gpu_platform_data {
+ void (*set_min_bus_tput)(struct device *dev, u8 agent_id,
+ unsigned long r);
+ int (*device_enable) (struct platform_device *pdev);
+ int (*device_shutdown) (struct platform_device *pdev);
+ int (*device_idle) (struct platform_device *pdev);
+};
+
+#endif
diff --git a/arch/arm/plat-omap/include/plat/hwspinlock.h b/arch/arm/plat-omap/include/plat/hwspinlock.h
new file mode 100644
index 00000000000..8c69ca58545
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/hwspinlock.h
@@ -0,0 +1,29 @@
+/* hwspinlock.h */
+
+#ifndef HWSPINLOCK_H
+#define HWSPINLOCK_H
+
+#include <linux/platform_device.h>
+#include <plat/omap44xx.h>
+
+/* Read values from the spinlock register */
+#define HWSPINLOCK_ACQUIRED 0
+#define HWSPINLOCK_BUSY 1
+
+/* Device data */
+struct hwspinlock_plat_info {
+ u32 sysstatus_offset; /* System status register offset */
+ u32 lock_base_offset; /* Offset of spinlock registers */
+};
+
+struct hwspinlock;
+
+int hwspinlock_lock(struct hwspinlock *handle);
+int hwspinlock_trylock(struct hwspinlock *handle);
+int hwspinlock_unlock(struct hwspinlock *handle);
+
+struct hwspinlock *hwspinlock_request(void);
+struct hwspinlock *hwspinlock_request_specific(unsigned int id);
+int hwspinlock_free(struct hwspinlock *hwspinlock_ptr);
+
+#endif /* HWSPINLOCK_H */
diff --git a/arch/arm/plat-omap/include/plat/io.h b/arch/arm/plat-omap/include/plat/io.h
index d72ec85c97e..b56e1d3e70c 100644
--- a/arch/arm/plat-omap/include/plat/io.h
+++ b/arch/arm/plat-omap/include/plat/io.h
@@ -205,6 +205,7 @@
#define L4_PER_44XX_VIRT (L4_PER_44XX_PHYS + OMAP2_L4_IO_OFFSET)
#define L4_PER_44XX_SIZE SZ_4M
+#define L4_ABE_44XX_BASE 0x49000000
#define L4_ABE_44XX_PHYS L4_ABE_44XX_BASE
/* 0x49000000 --> 0xfb000000 */
#define L4_ABE_44XX_VIRT (L4_ABE_44XX_PHYS + OMAP2_L4_IO_OFFSET)
diff --git a/arch/arm/plat-omap/include/plat/iommu.h b/arch/arm/plat-omap/include/plat/iommu.h
index 174f1b9c8c0..cdccd7a969f 100644
--- a/arch/arm/plat-omap/include/plat/iommu.h
+++ b/arch/arm/plat-omap/include/plat/iommu.h
@@ -13,6 +13,8 @@
#ifndef __MACH_IOMMU_H
#define __MACH_IOMMU_H
+#include <linux/list.h>
+
struct iotlb_entry {
u32 da;
u32 pa;
@@ -28,7 +30,6 @@ struct iotlb_entry {
struct iommu {
const char *name;
struct module *owner;
- struct clk *clk;
void __iomem *regbase;
struct device *dev;
void *isr_priv;
@@ -42,17 +43,20 @@ struct iommu {
*/
u32 *iopgd;
spinlock_t page_table_lock; /* protect iopgd */
-
int nr_tlb_entries;
struct list_head mmap;
struct mutex mmap_lock; /* protect mmap */
-
int (*isr)(struct iommu *obj, u32 da, u32 iommu_errs, void *priv);
- void *ctx; /* iommu context: registres saved area */
+ struct raw_notifier_head notifier;
+
u32 da_start;
u32 da_end;
+ struct iotlb_entry *tlbs_e;/* iommu tlbs context: saved area */
+ struct platform_device *pdev;
+ struct list_head event_list;
+ spinlock_t event_lock;
};
struct cr_regs {
@@ -72,6 +76,12 @@ struct cr_regs {
};
};
+struct iommu_event_ntfy {
+ u32 fd;
+ struct eventfd_ctx *evt_ctx;
+ struct list_head list;
+};
+
struct iotlb_lock {
short base;
short vict;
@@ -79,7 +89,7 @@ struct iotlb_lock {
/* architecture specific functions */
struct iommu_functions {
- unsigned long version;
+ u32 (*get_version)(struct iommu *obj);
int (*enable)(struct iommu *obj);
void (*disable)(struct iommu *obj);
@@ -97,17 +107,22 @@ struct iommu_functions {
u32 (*get_pte_attr)(struct iotlb_entry *e);
- void (*save_ctx)(struct iommu *obj);
- void (*restore_ctx)(struct iommu *obj);
ssize_t (*dump_ctx)(struct iommu *obj, char *buf, ssize_t len);
};
+enum {
+ IOMMU_FAULT,
+ IOMMU_CLOSE,
+};
+
struct iommu_platform_data {
const char *name;
- const char *clk_name;
+ const char *oh_name;
const int nr_tlb_entries;
u32 da_start;
u32 da_end;
+ int irq;
+ void __iomem *io_base;
};
/* IOMMU errors */
@@ -150,11 +165,17 @@ struct iommu_platform_data {
/*
* global functions
*/
-extern u32 iommu_arch_version(void);
+extern u32 iommu_arch_version(struct iommu *obj);
extern void iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e);
extern u32 iotlb_cr_to_virt(struct cr_regs *cr);
+extern int iommu_register_notifier(struct iommu *obj,
+ struct notifier_block *nb);
+extern int iommu_unregister_notifier(struct iommu *obj,
+ struct notifier_block *nb);
+extern int iommu_notify_event(struct iommu *obj, int event, void *data);
+
extern int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e);
extern void iommu_set_twl(struct iommu *obj, bool on);
extern void flush_iotlb_page(struct iommu *obj, u32 da);
@@ -165,6 +186,7 @@ extern int iopgtable_store_entry(struct iommu *obj, struct iotlb_entry *e);
extern void iopgtable_lookup_entry(struct iommu *obj, u32 da, u32 **ppgd,
u32 **ppte);
extern size_t iopgtable_clear_entry(struct iommu *obj, u32 iova);
+extern void iopgtable_clear_entry_all(struct iommu *obj);
extern int iommu_set_da_range(struct iommu *obj, u32 start, u32 end);
extern struct iommu *iommu_get(const char *name);
@@ -174,8 +196,10 @@ extern int iommu_set_isr(const char *name,
void *priv),
void *isr_priv);
-extern void iommu_save_ctx(struct iommu *obj);
-extern void iommu_restore_ctx(struct iommu *obj);
+u32 iommu_save_ctx(struct iommu *obj);
+u32 iommu_restore_ctx(struct iommu *obj);
+u32 iommu_save_tlb_entries(struct iommu *obj);
+u32 iommu_restore_tlb_entries(struct iommu *obj);
extern int install_iommu_arch(const struct iommu_functions *ops);
extern void uninstall_iommu_arch(const struct iommu_functions *ops);
@@ -185,5 +209,5 @@ extern int foreach_iommu_device(void *data,
extern ssize_t iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t len);
extern size_t dump_tlb_entries(struct iommu *obj, char *buf, ssize_t len);
-
+extern int iommu_get_plat_data_size(void);
#endif /* __MACH_IOMMU_H */
diff --git a/arch/arm/plat-omap/include/plat/iommu2.h b/arch/arm/plat-omap/include/plat/iommu2.h
index 10ad05f410e..c1ed038dde6 100644
--- a/arch/arm/plat-omap/include/plat/iommu2.h
+++ b/arch/arm/plat-omap/include/plat/iommu2.h
@@ -36,12 +36,18 @@
#define MMU_READ_CAM 0x68
#define MMU_READ_RAM 0x6c
#define MMU_EMU_FAULT_AD 0x70
-
-#define MMU_REG_SIZE 256
+#define MMU_FAULT_PC 0x80
+#define MMU_FAULT_STATUS 0x84
+#define MMU_GP_REG 0x88
/*
* MMU Register bit definitions
*/
+#define PAGE_SIZE_4KB 0x1000
+#define PAGE_SIZE_64KB 0x10000
+#define PAGE_SIZE_1MB 0x100000
+#define PAGE_SIZE_16MB 0x1000000
+
#define MMU_LOCK_BASE_SHIFT 10
#define MMU_LOCK_BASE_MASK (0x1f << MMU_LOCK_BASE_SHIFT)
#define MMU_LOCK_BASE(x) \
diff --git a/arch/arm/plat-omap/include/plat/iovmm.h b/arch/arm/plat-omap/include/plat/iovmm.h
index 32a2f6c4d39..8cd534fb2b8 100644
--- a/arch/arm/plat-omap/include/plat/iovmm.h
+++ b/arch/arm/plat-omap/include/plat/iovmm.h
@@ -22,7 +22,6 @@ struct iovm_struct {
const struct sg_table *sgt; /* keep 'page' <-> 'da' mapping */
void *va; /* mpu side mapped address */
};
-
/*
* IOVMF_FLAGS: attribute for iommu virtual memory area(iovma)
*
@@ -71,7 +70,8 @@ struct iovm_struct {
#define IOVMF_LINEAR_MASK (3 << (2 + IOVMF_SW_SHIFT))
#define IOVMF_DA_FIXED (1 << (4 + IOVMF_SW_SHIFT))
-
+#define IOVMF_DA_ANON (2 << (4 + IOVMF_SW_SHIFT))
+#define IOVMF_DA_MASK (3 << (4 + IOVMF_SW_SHIFT))
extern struct iovm_struct *find_iovm_area(struct iommu *obj, u32 da);
extern u32 iommu_vmap(struct iommu *obj, u32 da,
@@ -88,5 +88,4 @@ extern u32 iommu_kmalloc(struct iommu *obj, u32 da, size_t bytes,
extern void iommu_kfree(struct iommu *obj, u32 da);
extern void *da_to_va(struct iommu *obj, u32 da);
-
#endif /* __IOMMU_MMAP_H */
diff --git a/arch/arm/plat-omap/include/plat/ipu_dev.h b/arch/arm/plat-omap/include/plat/ipu_dev.h
new file mode 100644
index 00000000000..c7b7959c38b
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/ipu_dev.h
@@ -0,0 +1,107 @@
+/*
+ * OMAP IPU_PM driver
+ *
+ * Copyright (C) 2010 Texas Instruments Inc.
+ *
+ * Written by Paul Hunt <hunt@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef IPU_PM_H
+#define IPU_PM_H
+
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+
+#include "../../../drivers/dsp/syslink/ipu_pm/ipu_pm.h"
+
+#define IPU_PM_IOC_MAGIC (0xDB)
+
+/* magic char is irrelevant until trying to upstream
+ * except for reducing exposure to misdirected ioctls
+ * see Documentation/ioctl/ioctl-number.txt
+ */
+#define IPU_PM_IOC_SUSPEND _IOW(IPU_PM_IOC_MAGIC, 0, int)
+#define IPU_PM_IOC_RESUME _IOW(IPU_PM_IOC_MAGIC, 1, int)
+
+#define IPU_PM_IOC_MAXNR 3
+
+#define IPUPM_CAPS_START_BIT 0
+#define IPUPM_CAPS_STOP_BIT 1
+#define IPUPM_CAPS_PERF_BIT 2
+#define IPUPM_CAPS_LAT_BIT 3
+#define IPUPM_CAPS_BDW_BIT 4
+/* omap_device built elsewhere */
+#define IPUPM_CAPS_EXTINIT_BIT 5
+#define IPUPM_CAPS_START (1 << IPUPM_CAPS_START_BIT)
+#define IPUPM_CAPS_STOP (1 << IPUPM_CAPS_STOP_BIT)
+#define IPUPM_CAPS_PERF (1 << IPUPM_CAPS_PERF_BIT)
+#define IPUPM_CAPS_LAT (1 << IPUPM_CAPS_LAT_BIT)
+#define IPUPM_CAPS_BDW (1 << IPUPM_CAPS_BDW_BIT)
+#define IPUPM_CAPS_EXTINIT (1 << IPUPM_CAPS_EXTINIT_BIT)
+
+#define IPU_PM_SELF 100
+#define IPU_PM_MPU 101
+#define IPU_PM_CORE 102
+
+struct omap_ipupm_mod;
+
+struct omap_ipupm_mod_ops {
+ int (*start)(enum res_type ipupm_modnum);
+ int (*stop)(enum res_type ipupm_modnum);
+};
+
+struct omap_ipupm_mod_platform_data {
+ struct platform_device *pdev;
+ struct device *dev;
+ char *name;
+ char *oh_name;
+ struct omap_hwmod *oh;
+ struct kobject kobj;
+ u32 caps;
+ struct pm_qos_request_list *qos_request;
+ struct omap_ipupm_mod_ops *ops;
+};
+
+struct omap_ipupm_mod {
+ struct device *dev;
+ struct cdev cdev;
+ atomic_t count;
+ int state;
+ int minor;
+};
+
+struct ipu_pm_dev {
+ /* FIXME: maybe more is needed */
+ struct cdev cdev;
+};
+
+extern int ipu_pm_first_dev;
+
+extern int ipu_pm_module_start(unsigned rsrc);
+extern int ipu_pm_module_stop(unsigned rsrc);
+extern int ipu_pm_module_set_rate(unsigned rsrc,
+ unsigned target_rsrc,
+ unsigned rate);
+extern int ipu_pm_module_set_latency(unsigned rsrc,
+ unsigned target_rsrc,
+ int latency);
+extern int ipu_pm_module_set_bandwidth(unsigned rsrc,
+ unsigned target_rsrc,
+ int bandwidth);
+
+#endif /* IPU_PM_H */
diff --git a/arch/arm/plat-omap/include/plat/irqs.h b/arch/arm/plat-omap/include/plat/irqs.h
index 5a25098ea7e..2cfba5149ea 100644
--- a/arch/arm/plat-omap/include/plat/irqs.h
+++ b/arch/arm/plat-omap/include/plat/irqs.h
@@ -407,11 +407,19 @@
#endif
#define TWL6030_IRQ_END (TWL6030_IRQ_BASE + TWL6030_BASE_NR_IRQS)
+#define TWL6040_CODEC_IRQ_BASE TWL6030_IRQ_END
+#ifdef CONFIG_TWL6040_CODEC
+#define TWL6040_CODEC_NR_IRQS 6
+#else
+#define TWL6040_CODEC_NR_IRQS 0
+#endif
+#define TWL6040_CODEC_IRQ_END (TWL6040_CODEC_IRQ_BASE + TWL6040_CODEC_NR_IRQS)
+
/* Total number of interrupts depends on the enabled blocks above */
-#if (TWL4030_GPIO_IRQ_END > TWL6030_IRQ_END)
+#if (TWL4030_GPIO_IRQ_END > TWL6040_CODEC_IRQ_END)
#define TWL_IRQ_END TWL4030_GPIO_IRQ_END
#else
-#define TWL_IRQ_END TWL6030_IRQ_END
+#define TWL_IRQ_END TWL6040_CODEC_IRQ_END
#endif
/* GPMC related */
diff --git a/arch/arm/plat-omap/include/plat/mailbox.h b/arch/arm/plat-omap/include/plat/mailbox.h
index cc3921e9059..4592f830372 100644
--- a/arch/arm/plat-omap/include/plat/mailbox.h
+++ b/arch/arm/plat-omap/include/plat/mailbox.h
@@ -58,7 +58,9 @@ struct omap_mbox {
struct device *dev;
void *priv;
int use_count;
- struct blocking_notifier_head notifier;
+ int nr_mbox_users;
+ int nr_mbox;
+ struct blocking_notifier_head notifier;
};
int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg);
diff --git a/arch/arm/plat-omap/include/plat/mcpdm.h b/arch/arm/plat-omap/include/plat/mcpdm.h
new file mode 100644
index 00000000000..1ed2b8f678c
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/mcpdm.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_PLAT_MCPDM_H__
+#define __OMAP_PLAT_MCPDM_H__
+
+#include <linux/platform_device.h>
+
+struct omap_mcpdm_platform_data {
+ int (*device_enable) (struct platform_device *pdev);
+ int (*device_shutdown) (struct platform_device *pdev);
+ int (*device_idle) (struct platform_device *pdev);
+};
+
+#endif
diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h
index f38fef9f131..131d10fe146 100644
--- a/arch/arm/plat-omap/include/plat/mmc.h
+++ b/arch/arm/plat-omap/include/plat/mmc.h
@@ -31,6 +31,7 @@
#define OMAP_MMC_MAX_SLOTS 2
+/* omap_hwmod integration data */
#define OMAP_HSMMC_SUPPORTS_DUAL_VOLT BIT(1)
struct omap_mmc_dev_attr {
@@ -67,6 +68,7 @@ struct omap_mmc_platform_data {
/* Integrating attributes from the omap_hwmod layer */
u8 controller_flags;
+ struct omap_mmc_dev_attr *dev_attr;
/* Register offset deviation */
u16 reg_offset;
diff --git a/arch/arm/plat-omap/include/plat/omap4-keypad.h b/arch/arm/plat-omap/include/plat/omap4-keypad.h
index 2b1d9bc1eeb..c3ce29561a0 100644
--- a/arch/arm/plat-omap/include/plat/omap4-keypad.h
+++ b/arch/arm/plat-omap/include/plat/omap4-keypad.h
@@ -10,5 +10,6 @@ struct omap4_keypad_platform_data {
u8 cols;
};
-extern int omap4_keyboard_init(struct omap4_keypad_platform_data *);
+extern int omap4_keypad_initialization(struct omap4_keypad_platform_data *);
+
#endif
diff --git a/arch/arm/plat-omap/include/plat/omap44xx.h b/arch/arm/plat-omap/include/plat/omap44xx.h
index ea2b8a6306e..bfc30ee8d0f 100644
--- a/arch/arm/plat-omap/include/plat/omap44xx.h
+++ b/arch/arm/plat-omap/include/plat/omap44xx.h
@@ -22,6 +22,9 @@
#define L4_PER_44XX_BASE 0x48000000
#define L4_EMU_44XX_BASE 0x54000000
#define L3_44XX_BASE 0x44000000
+#define L3_44XX_BASE_CLK1 L3_44XX_BASE
+#define L3_44XX_BASE_CLK2 0x44800000
+#define L3_44XX_BASE_CLK3 0x45000000
#define OMAP44XX_EMIF1_BASE 0x4c000000
#define OMAP44XX_EMIF2_BASE 0x4d000000
#define OMAP44XX_DMM_BASE 0x4e000000
@@ -45,13 +48,16 @@
#define OMAP44XX_WKUPGEN_BASE 0x48281000
#define OMAP44XX_MCPDM_BASE 0x40132000
#define OMAP44XX_MCPDM_L3_BASE 0x49032000
+#define OMAP44XX_DSS_HDMI_L3_BASE 0x58006000
#define OMAP44XX_MAILBOX_BASE (L4_44XX_BASE + 0xF4000)
#define OMAP44XX_HSUSB_OTG_BASE (L4_44XX_BASE + 0xAB000)
+#define OMAP44XX_SPINLOCK_BASE (L4_44XX_BASE + 0xF6000)
#define OMAP4_MMU1_BASE 0x55082000
#define OMAP4_MMU2_BASE 0x4A066000
+#define OMAP44XX_SPINLOCK_BASE (L4_44XX_BASE + 0xF6000)
#define OMAP44XX_USBTLL_BASE (L4_44XX_BASE + 0x62000)
#define OMAP44XX_UHH_CONFIG_BASE (L4_44XX_BASE + 0x64000)
#define OMAP44XX_HSUSB_OHCI_BASE (L4_44XX_BASE + 0x64800)
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 1adea9c6298..ad3a189a7f1 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -430,6 +430,7 @@ struct omap_hwmod_omap4_prcm {
#define _HWMOD_STATE_ENABLED 4
#define _HWMOD_STATE_IDLE 5
#define _HWMOD_STATE_DISABLED 6
+#define _HWMOD_STATE_LAST _HWMOD_STATE_DISABLED
/**
* struct omap_hwmod_class - the type of an IP block
@@ -459,7 +460,8 @@ struct omap_hwmod_class {
const char *name;
struct omap_hwmod_class_sysconfig *sysc;
u32 rev;
- int (*pre_shutdown)(struct omap_hwmod *oh);
+ int (*pre_shutdown)
+ (struct omap_hwmod *oh);
int (*reset)(struct omap_hwmod *oh);
};
@@ -551,6 +553,8 @@ int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data),
int __init omap_hwmod_setup_one(const char *name);
+int __init omap_hwmod_setup_one(const char *name);
+
int omap_hwmod_enable(struct omap_hwmod *oh);
int _omap_hwmod_enable(struct omap_hwmod *oh);
int omap_hwmod_idle(struct omap_hwmod *oh);
diff --git a/arch/arm/plat-omap/include/plat/remoteproc.h b/arch/arm/plat-omap/include/plat/remoteproc.h
new file mode 100644
index 00000000000..5ed9bc8376d
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/remoteproc.h
@@ -0,0 +1,150 @@
+/*
+ * OMAP Remote Processor driver
+ *
+ * Copyright (C) 2010 Texas Instruments Inc.
+ *
+ * Written by Ohad Ben-Cohen <ohad@wizery.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef REMOTEPROC_H
+#define REMOTEPROC_H
+
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+
+#define RPROC_IOC_MAGIC 'P'
+
+#define RPROC_IOCMONITOR _IO(RPROC_IOC_MAGIC, 0)
+#define RPROC_IOCSTART _IO(RPROC_IOC_MAGIC, 1)
+#define RPROC_IOCSTOP _IO(RPROC_IOC_MAGIC, 2)
+#define RPROC_IOCGETSTATE _IOR(RPROC_IOC_MAGIC, 3, int)
+#define RPROC_IOCREGEVENT _IOR(RPROC_IOC_MAGIC, 4, \
+ struct omap_rproc_reg_event_args)
+#define RPROC_IOCUNREGEVENT _IOR(RPROC_IOC_MAGIC, 5, \
+ struct omap_rproc_reg_event_args)
+
+#define RPROC_IOC_MAXNR (5)
+
+#ifdef CONFIG_ARCH_OMAP4
+#define NR_RPROC_OMAP4_DEVICES 3
+#else
+#define NR_RPROC_OMAP4_DEVICES 0
+#endif
+
+struct omap_rproc;
+
+struct omap_rproc_ops {
+ int (*start)(struct device *dev, u32 start_addr);
+ int (*stop)(struct device *dev);
+ int (*sleep)(struct device *dev);
+ int (*wakeup)(struct device *dev);
+ int (*get_state)(struct device *dev);
+};
+
+struct omap_rproc_clk_t {
+ void *clk_handle;
+ const char *dev_id;
+ const char *con_id;
+};
+
+/* RPROC events. */
+enum {
+ OMAP_RPROC_START,
+ OMAP_RPROC_STOP,
+};
+
+/* RPROC states. */
+enum {
+ OMAP_RPROC_STOPPED,
+ OMAP_RPROC_RUNNING,
+ OMAP_RPROC_HIBERNATING,
+};
+
+enum {
+ PROC_ERROR = 1,
+ PROC_STOP,
+ PROC_START,
+};
+
+struct omap_rproc_common_args {
+ int status;
+};
+
+
+struct omap_rproc_platform_data {
+ struct omap_rproc_ops *ops;
+ char *name;
+ char *oh_name;
+ int timer_hib_id;
+ int timer_clk_id;
+};
+
+struct omap_rproc {
+ const char *name;
+ struct device *dev;
+ struct cdev cdev;
+ atomic_t count;
+ int state;
+ int minor;
+ struct blocking_notifier_head notifier;
+ struct mutex lock;
+ int timer_hib_id;
+ int timer_clk_id;
+ struct omap_dm_timer *dmtimer;
+ struct omap_dm_timer *dmtimer_clk;
+ struct list_head event_list;
+ spinlock_t event_lock;
+};
+
+struct omap_rproc_ntfy {
+ struct list_head list;
+ int fd;
+ struct eventfd_ctx *evt_ctx;
+ u32 event;
+};
+
+struct omap_rproc_start_args {
+ u32 start_addr;
+};
+
+struct omap_rproc_reg_event_args {
+ struct omap_rproc_common_args cargs;
+ u16 pro_id;
+ int fd;
+ u32 event;
+};
+
+extern int rproc_start(struct omap_rproc *rproc, const void __user *arg);
+extern int rproc_stop(struct omap_rproc *rproc);
+extern int rproc_sleep(struct omap_rproc *rproc);
+extern int rproc_wakeup(struct omap_rproc *rproc);
+
+extern int omap_rproc_register_notifier(struct omap_rproc *rproc,
+ struct notifier_block *nb);
+extern int omap_rproc_unregister_notifier(struct omap_rproc *rproc,
+ struct notifier_block *nb);
+extern int omap_rproc_notify_event(struct omap_rproc *obj, int event,
+ void *data);
+
+extern struct omap_rproc *omap_rproc_get(const char *name);
+extern void omap_rproc_put(struct omap_rproc *obj);
+
+struct omap_rproc_platform_data *omap3_get_rproc_data(void);
+int omap3_get_rproc_data_size(void);
+struct omap_rproc_platform_data *omap4_get_rproc_data(void);
+#endif /* REMOTEPROC_H */
diff --git a/arch/arm/plat-omap/include/plat/syntm12xx.h b/arch/arm/plat-omap/include/plat/syntm12xx.h
new file mode 100644
index 00000000000..2394839b569
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/syntm12xx.h
@@ -0,0 +1,18 @@
+/*
+ * Platform configuration for Synaptic TM12XX touchscreen driver.
+ */
+
+#ifndef __TM12XX_TS_H
+#define __TM12XX_TS_H
+
+struct tm12xx_ts_platform_data {
+ int gpio_intr;
+
+ char **idev_name; /* Input Device name. */
+ u8 *button_map; /* Button to keycode */
+ unsigned num_buttons; /* Registered buttons */
+ u8 repeat; /* Input dev Repeat enable */
+ u8 swap_xy; /* ControllerX==InputDevY...*/
+};
+
+#endif
diff --git a/arch/arm/plat-omap/include/syslink/GlobalTypes.h b/arch/arm/plat-omap/include/syslink/GlobalTypes.h
new file mode 100644
index 00000000000..6cd959cde95
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/GlobalTypes.h
@@ -0,0 +1,154 @@
+/*
+ * GlobalTypes.h
+ *
+ * Syslink driver support for OMAP Processors.
+ *
+ * Copyright (C) 2008-2009 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 __GLOBALTYPES_H
+#define __GLOBALTYPES_H
+
+#define REG volatile
+
+/*
+ * Definition: RET_CODE_BASE
+ *
+ * DESCRIPTION: Base value for return code offsets
+ *
+ *
+ */
+#define RET_CODE_BASE 0
+
+/*
+ * TYPE: ReturnCode_t
+ *
+ * DESCRIPTION: Return codes to be returned by all library functions
+ *
+ *
+ */
+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 */
+};
+
+
+
+/*
+ * MACRO: RD_MEM_32_VOLATILE, WR_MEM_32_VOLATILE
+ *
+ * DESCRIPTION: 32 bit register access macros
+ *
+ *
+ */
+#define RD_MEM_32_VOLATILE(addr) \
+((unsigned long)(*((REG unsigned long *)(addr))))
+
+#define WR_MEM_32_VOLATILE(addr, data) \
+(*((REG unsigned long *)(addr)) = (unsigned long)(data))
+
+
+
+
+#ifdef CHECK_INPUT_PARAMS
+/*
+ * MACRO: CHECK_INPUT_PARAMS
+ *
+ * DESCRIPTION: Checks an input code and returns a specified value if code is
+ * invalid value, also writes spy value if error found.
+ *
+ * NOTE: Can be disabled to save HW cycles.
+ *
+ *
+ */
+#define CHECK_INPUT_PARAM(actualValue, invalidValue, \
+returnCodeIfMismatch, spyCodeIfMisMatch) do {\
+ if ((invalidValue) == (actualValue)) {\
+ RES_Set((spyCodeIfMisMatch));\
+ return returnCodeIfMismatch; \
+ } \
+} while (0)
+
+/*
+ * MACRO: CHECK_INPUT_RANGE
+ *
+ * DESCRIPTION: Checks an input value and returns a specified value if not in
+ * specified range, also writes spy value if error found.
+ *
+* NOTE: Can be disabled to save HW cycles.
+ *
+ *
+ */
+#define CHECK_INPUT_RANGE(actualValue, minValidValue, maxValidValue, \
+returnCodeIfMismatch, spyCodeIfMisMatch) do {\
+ if (((actualValue) < (minValidValue)) || \
+ ((actualValue) > (maxValidValue))) {\
+ RES_Set((spyCodeIfMisMatch));\
+ return returnCodeIfMismatch; \
+ } \
+} while (0)
+
+/*
+ * MACRO: CHECK_INPUT_RANGE_MIN0
+ *
+ * DESCRIPTION: Checks an input value and returns a
+ * specified value if not in
+ * specified range, also writes spy value if error found.
+ * The minimum
+ * value is 0.
+ *
+ * NOTE: Can be disabled to save HW cycles.
+ *
+ *
+ */
+#define CHECK_INPUT_RANGE_MIN0(actualValue, maxValidValue, \
+returnCodeIfMismatch, spyCodeIfMisMatch) do {\
+ if ((actualValue) > (maxValidValue)) {\
+ RES_Set((spyCodeIfMisMatch));\
+ return returnCodeIfMismatch; \
+ } \
+} while (0)
+
+#else
+
+#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
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __GLOBALTYPES_H */
diff --git a/arch/arm/plat-omap/include/syslink/_listmp.h b/arch/arm/plat-omap/include/syslink/_listmp.h
new file mode 100644
index 00000000000..282d2c8c10e
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/_listmp.h
@@ -0,0 +1,68 @@
+/*
+ * _listmp.h
+ *
+ * Internal definitions for shared memory doubly linked list.
+ *
+ * Copyright (C) 2008-2009 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 __LISTMP_H_
+#define __LISTMP_H_
+
+/* Standard headers */
+#include <linux/types.h>
+#include <linux/list.h>
+
+#include <listmp.h>
+#include <sharedregion.h>
+
+/* Unique module ID. */
+#define LISTMP_MODULEID (0xa413)
+
+/* Created tag */
+#define LISTMP_CREATED 0x12181964
+
+
+/* Structure defining shared memory attributes for the ListMP module. */
+struct listmp_attrs {
+ u32 status;
+ u32 *gatemp_addr;
+ struct listmp_elem head;
+};
+
+/* Structure defining config parameters for the ListMP module. */
+struct listmp_config {
+ uint max_runtime_entries;
+ /* Maximum number of ListMP's that can be dynamically created and
+ added to the NameServer. */
+ uint max_name_len; /* Maximum length of name */
+};
+
+
+/* Structure defining processor related information for the ListMP module. */
+struct listmp_proc_attrs {
+ bool creator; /* Creator or opener */
+ u16 proc_id; /* Processor Identifier */
+ u32 open_count; /* How many times it is opened on a processor */
+};
+
+
+/* Function to get the configuration */
+void listmp_get_config(struct listmp_config *cfg_params);
+
+/* Function to setup the listmp module */
+int listmp_setup(const struct listmp_config *config);
+
+/* Function to destroy the listmp module */
+int listmp_destroy(void);
+
+#endif /* __LISTMP_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/_notify.h b/arch/arm/plat-omap/include/syslink/_notify.h
new file mode 100644
index 00000000000..9f9d8891416
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/_notify.h
@@ -0,0 +1,83 @@
+/*
+ * _notify.h
+ *
+ * The MessageQ module supports the structured sending and receiving of
+ * variable length messages. This module can be used for homogeneous or
+ * heterogeneous multi-processor messaging.
+ *
+ * Copyright (C) 2009 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.
+ */
+
+#if !defined(__NOTIFY_H_)
+#define __NOTIFY_H_
+
+
+/* Module headers */
+#include <syslink/notify.h>
+
+
+/* Module ID for notify. */
+#define NOTIFY_MODULEID ((u16) 0x5F84)
+
+/* Mask to check for event ID. */
+#define NOTIFY_EVENT_MASK ((u16) 0xFFFF)
+
+#define ISRESERVED(event_id, reserved_event) \
+ (((event_id & NOTIFY_EVENT_MASK) >= reserved_event) || \
+ ((event_id >> 16) == NOTIFY_SYSTEMKEY))
+
+/* This structure defines attributes for initialization of the notify module. */
+struct notify_config {
+ u32 num_events;
+ /* Number of events to be supported */
+ u32 send_event_poll_count;
+ /* Poll for specified amount before send_event times out */
+ u32 num_lines;
+ /* Max. number of interrupt lines between a single pair of processors */
+ u32 reserved_events;
+ /* Number of reserved events to be supported */
+};
+
+/* This structure defines the configuration structure for initialization
+ * of the notify object. */
+struct notify_params {
+ u32 reserved; /* Reserved field */
+};
+
+
+/* Function to get the default configuration for the notify module. */
+void notify_get_config(struct notify_config *cfg);
+
+/* Function to setup the notify module */
+int notify_setup(struct notify_config *cfg);
+
+/* Function to destroy the notify module */
+int notify_destroy(void);
+
+/* Function to create an instance of notify driver */
+struct notify_object *notify_create(void *driver_handle, u16 remote_proc_id,
+ u16 line_id, const struct notify_params *params);
+
+/* Function to delete an instance of notify driver */
+int notify_delete(struct notify_object **handle_ptr);
+
+/* Function to call device specific the notify module setup */
+int notify_attach(u16 proc_id, void *shared_addr);
+
+/* Function to destroy the device specific notify module */
+int notify_detach(u16 proc_id);
+
+/* Function registered as callback with the notify driver */
+void notify_exec(struct notify_object *obj, u32 event_id, u32 payload);
+
+
+#endif /* !defined(__NOTIFY_H_) */
diff --git a/arch/arm/plat-omap/include/syslink/_sysmgr.h b/arch/arm/plat-omap/include/syslink/_sysmgr.h
new file mode 100644
index 00000000000..58fbdd37815
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/_sysmgr.h
@@ -0,0 +1,50 @@
+/*
+ * _sysmgr.h
+ *
+ * Defines for system manager functions
+ *
+ * Copyright (C) 2009 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 __SYSMGR_H_
+#define __SYSMGR_H_
+
+/* Structure to retrieve the scalability proc info from the slave */
+struct sysmgr_proc_config {
+ u32 proc_id;
+ u32 use_notify;
+ u32 use_messageq;
+ u32 use_heapbuf;
+ u32 use_frameq;
+ u32 use_ringio;
+ u32 use_listmp;
+ u32 use_nameserver;
+ u32 boot_mode;
+};
+
+/* Function to set the boot load page address for a slave */
+void sysmgr_set_boot_load_page(u16 proc_id, u32 boot_load_page);
+
+/* Function to get configuration values for a host object(component/instance) */
+u32 sysmgr_get_object_config(u16 proc_id, void *config, u32 cmd_id, u32 size);
+
+/* Function to put configuration values for a slave object(component/instance)*/
+u32 sysmgr_put_object_config(u16 proc_id, void *config, u32 cmd_id, u32 size);
+
+/* Function to wait for scalability handshake value. */
+void sysmgr_wait_for_scalability_info(u16 proc_id);
+
+/* Function to wait for slave to complete setup */
+void sysmgr_wait_for_slave_setup(u16 proc_id);
+
+
+#endif /* ifndef __SYSMGR_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/atomic_linux.h b/arch/arm/plat-omap/include/syslink/atomic_linux.h
new file mode 100644
index 00000000000..da4cb21b1ec
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/atomic_linux.h
@@ -0,0 +1,104 @@
+/*
+* atomic_linux.h
+*
+* Atomic operations functions
+*
+* Copyright (C) 2008-2009 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 _ATOMIC_LINUX_H
+#define _ATOMIC_LINUX_H
+
+#include <linux/types.h>
+#include <generated/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/atomic.h>
+
+/*
+ * ======== atomic_cmpmask_and_set ========
+ * Purpose:
+ * This will compare a mask and set if not equal
+ */
+static inline void atomic_cmpmask_and_set(atomic_t *v, u32 mask, u32 val)
+{
+ s32 ret;
+ unsigned long flags;
+ atomic_t *atm = v;
+
+ raw_local_irq_save(flags);
+ ret = atm->counter;
+ if (likely(((ret & mask) != mask)))
+ atm->counter = val;
+ raw_local_irq_restore(flags);
+}
+
+/*
+ * ======== atomic_cmpmask_and_set ========
+ * Purpose:
+ * This will compare a mask and then check current value less than
+ * provided value.
+ */
+static inline bool atomic_cmpmask_and_lt(atomic_t *v, u32 mask, u32 val)
+{
+ bool ret = true;
+ atomic_t *atm = v;
+ s32 cur;
+ unsigned long flags;
+
+ raw_local_irq_save(flags);
+ cur = atm->counter;
+ /* Compare mask, if matches then compare val */
+ if (likely(((cur & mask) == mask))) {
+ if (likely(cur >= val))
+ ret = false;
+ }
+ raw_local_irq_restore(flags);
+
+ /* retval = true if mask matches and current value is less than given
+ * value */
+ /* retval = false either mask doesnot matches or current value is not
+ * less than given value */
+ return ret;
+}
+
+
+/*
+ * ======== atomic_cmpmask_and_set ========
+ * Purpose:
+ * This will compare a mask and then check current value greater than
+ * provided value.
+ */
+static inline bool atomic_cmpmask_and_gt(atomic_t *v, u32 mask, u32 val)
+{
+ bool ret = false;
+ atomic_t *atm = v;
+ s32 cur;
+ unsigned long flags;
+
+ raw_local_irq_save(flags);
+ cur = atm->counter;
+ /* Compare mask, if matches then compare val */
+ if (likely(((cur & mask) == mask))) {
+ if (likely(cur > val))
+ ret = true;
+ }
+
+ raw_local_irq_restore(flags);
+ /* retval = true if mask matches and current value is less than given
+ * value */
+ /* etval =false either mask doesnot matches or current value is not
+ * greater than given value */
+ return ret;
+}
+
+#endif /* if !defined(_ATOMIC_LINUX_H) */
diff --git a/arch/arm/plat-omap/include/syslink/drv_notify.h b/arch/arm/plat-omap/include/syslink/drv_notify.h
new file mode 100644
index 00000000000..c8a783eca4f
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/drv_notify.h
@@ -0,0 +1,43 @@
+/*
+ * drv_notify.h
+ *
+ * Notify driver support for OMAP Processors.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+
+#if !defined _DRV_NOTIFY_H_
+#define _DRV_NOTIFY_H_
+
+
+/* Module includes */
+#include <syslink/notify_driverdefs.h>
+#include <syslink/_notify.h>
+
+
+/* read function for of Notify driver.*/
+int notify_drv_read(struct file *filp, char __user *dst, size_t size,
+ loff_t *offset);
+
+/* Linux driver function to map memory regions to user space. */
+int notify_drv_mmap(struct file *filp, struct vm_area_struct *vma);
+
+/* ioctl function for of Linux Notify driver.*/
+int notify_drv_ioctl(struct inode *inode, struct file *filp, u32 cmd,
+ unsigned long args, bool user);
+
+void _notify_drv_setup(void);
+
+void _notify_drv_destroy(void);
+
+
+#endif /* !defined (_DRV_NOTIFY_H_) */
diff --git a/arch/arm/plat-omap/include/syslink/gate.h b/arch/arm/plat-omap/include/syslink/gate.h
new file mode 100644
index 00000000000..1041f752f46
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/gate.h
@@ -0,0 +1,76 @@
+/*
+ * gate.h
+ *
+ * Critical section support.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+/** ============================================================================
+ * Gates are used by clients to protect concurrent access to critical
+ * data structures. Critical data structures are those that must be
+ * updated by at most one thread at a time. All code that needs access
+ * to a critical data structure "enters" a gate (that's associated with the
+ * data structure) prior to accessing the data, modifies the data structure,
+ * then "leaves" the gate.
+ *
+ * A gate is responsible for ensuring that at most one thread at a time
+ * can enter and execute "inside" the gate. There are several
+ * implementations of gates, with different system executation times and
+ * latency tradoffs. In addition, some gates must not be entered by certain
+ * thread types; e.g., a gate that is implemented via a "blocking" semaphore
+ * must not be called by an interrupt service routine (ISR).
+ *
+ * A module can be declared "gated" by adding the `@Gated` attribute to the
+ * module's XDC spec file. A "gated" module is assigned a module-level gate
+ * at the configuration time, and that gate is then used to protect critical
+ * sections in the module's target code. A module-level gate is an instance of
+ * a module implementing `{@link IGateProvider}` interface. However, gated
+ * modules do not access their module-level gates directly. They use this
+ * module to access transparently their module-level gate.
+ *
+ * Application code that is not a part of any module also has a
+ * module-level gate, configured through the module `{@link Main}`.
+ *
+ * Each gated module can optionally create gates on an adhoc basis at
+ * runtime using the same gate module that was used to create the module
+ * level gate.
+ *
+ * Gates that work by disabling all preemption while inside a gate can be
+ * used to protect data structures accessed by ISRs and other
+ * threads. But, if the time required to update the data structure is not
+ * a small constant, this type of gate may violate a system's real-time
+ * requirements.
+ *
+ * Gates have two orthogonal attributes: "blocking" and "preemptible".
+ * In general, gates that are "blocking" can not be use by code that is
+ * called by ISRs and gates that are not "preemptible" should only be used to
+ * to protect data manipulated by code that has small constant execution
+ * time.
+ * ============================================================================
+ */
+
+
+#ifndef GATE_H_0xAF6F
+#define GATE_H_0xAF6F
+
+#include <igateprovider.h>
+
+extern struct igateprovider_object *gate_system_handle;
+
+/* Function to enter a Gate */
+int *gate_enter_system(void);
+
+/* Function to leave a Gate */
+void gate_leave_system(int *key);
+
+
+#endif /* GATE_H_0xAF6F */
diff --git a/arch/arm/plat-omap/include/syslink/gate_remote.h b/arch/arm/plat-omap/include/syslink/gate_remote.h
new file mode 100644
index 00000000000..5ed6b7f155f
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/gate_remote.h
@@ -0,0 +1,33 @@
+/*
+ * gate_remote.h
+ *
+ * This includes the functions to handle remote gates
+ *
+ * Copyright (C) 2008-2009 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 _NAMESERVER_REMOTE_H_
+#define _GATE_REMOTE_H_
+
+#include <linux/types.h>
+
+/*
+ * This function is used to enter in to a remote gate
+ */
+int gate_remote_enter(void *ghandle, u32 key);
+
+/*
+ * This function is used to leave from a remote gate
+ */
+int gate_remote_leave(void *ghandle, u32 key);
+
+#endif /* _GATE_REMOTE_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/gatehwspinlock.h b/arch/arm/plat-omap/include/syslink/gatehwspinlock.h
new file mode 100644
index 00000000000..209d12bdd6b
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/gatehwspinlock.h
@@ -0,0 +1,161 @@
+/*
+ * gatehwspinlock.h
+ *
+ * Defines for gatehwspinlock.
+ *
+ * Copyright(C) 2009 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 GATEHWSPINLOCK_H_
+#define GATEHWSPINLOCK_H_
+
+/* Module headers */
+#include <multiproc.h>
+#include <gatemp.h>
+#include <igatempsupport.h>
+#include <sharedregion.h>
+
+/* Unique module ID. */
+#define GATEHWSPINLOCK_MODULEID (0xF416)
+
+/* =============================================================================
+ * Module Success and Failure codes
+ * =============================================================================
+ */
+/* Argument passed to a function is invalid. */
+#define GATEHWSPINLOCK_E_INVALIDARG -1
+
+/* Memory allocation failed. */
+#define GATEHWSPINLOCK_E_MEMORY -2
+
+/* the name is already registered or not. */
+#define GATEHWSPINLOCK_E_BUSY -3
+
+/* Generic failure. */
+#define GATEHWSPINLOCK_E_FAIL -4
+
+/* name not found in the nameserver. */
+#define GATEHWSPINLOCK_E_NOTFOUND -5
+
+/* Module is not initialized. */
+#define GATEHWSPINLOCK_E_INVALIDSTATE -6
+
+/* Instance is not created on this processor. */
+#define GATEHWSPINLOCK_E_NOTONWER -7
+
+/* Remote opener of the instance has not closed the instance. */
+#define GATEHWSPINLOCK_E_REMOTEACTIVE -8
+
+/* Indicates that the instance is in use. */
+#define GATEHWSPINLOCK_E_INUSE -9
+
+/* Failure in OS call. */
+#define GATEHWSPINLOCK_E_OSFAILURE -10
+
+/* Version mismatch error. */
+#define GATEHWSPINLOCK_E_VERSION -11
+
+/* Operation successful. */
+#define GATEHWSPINLOCK_S_SUCCESS 0
+
+/* The GATEHWSPINLOCK module has already been setup in this process. */
+#define GATEHWSPINLOCK_S_ALREADYSETUP 1
+
+
+/* =============================================================================
+ * Macros
+ * =============================================================================
+ */
+
+/* Q_BLOCKING */
+#define GATEHWSEM_Q_BLOCKING (1)
+
+/* Q_PREEMPTING */
+#define GATEHWSEM_Q_PREEMPTING (2)
+
+
+/* =============================================================================
+ * Enums & Structures
+ * =============================================================================
+ */
+
+/* Structure defining config parameters for the gatehwspinlock module. */
+struct gatehwspinlock_config {
+ enum gatemp_local_protect default_protection;
+ /* Default module-wide local context protection level. The level of
+ * protection specified here determines which local gate is created
+ * per gatehwspinlock instance for local protection during create.
+ * The instance configuration parameter may be used to override this
+ * module setting per instance. The configuration used here should
+ * reflect both the context in which enter and leave are to be called,
+ * as well as the maximum level protection needed locally.
+ */
+ u32 base_addr;
+ /* Device-specific base address for HW Semaphore subsystem in HOST OS
+ * address space, this is updated in Ipc module */
+ u32 num_locks;
+ /* Device-specific number of semphores in the HW Semaphore subsystem */
+};
+
+/* Structure defining config parameters for the gatehwspinlock instances. */
+struct gatehwspinlock_params {
+ IGATEMPSUPPORT_SUPERPARAMS;
+};
+
+
+/* Inherit everything from IGateMPSupport */
+IGATEMPSUPPORT_INHERIT(gatehwspinlock);
+
+
+/* =============================================================================
+ * APIs
+ * =============================================================================
+ */
+/* Function to get the default configuration for the gatehwspinlock module. */
+void gatehwspinlock_get_config(struct gatehwspinlock_config *config);
+
+/* Function to setup the gatehwspinlock module. */
+int gatehwspinlock_setup(const struct gatehwspinlock_config *config);
+
+/* Function to destroy the gatehwspinlock module */
+int gatehwspinlock_destroy(void);
+
+/* Get the default parameters for the gatehwspinlock instance. */
+void gatehwspinlock_params_init(struct gatehwspinlock_params *params);
+
+/* Function to create an instance of gatehwspinlock */
+void *gatehwspinlock_create(enum igatempsupport_local_protect local_protect,
+ const struct gatehwspinlock_params *params);
+
+/* Function to delete an instance of gatehwspinlock */
+int gatehwspinlock_delete(void **handle_ptr);
+
+/* Function to enter the gatehwspinlock instance */
+int *gatehwspinlock_enter(void *handle);
+
+/* Function to leave the gatehwspinlock instance */
+void gatehwspinlock_leave(void *handle, int *key);
+
+/* Function to return the shared memory requirement for a single instance */
+u32 gatehwspinlock_shared_mem_req(const struct gatehwspinlock_params *params);
+
+/* Function to return the number of instances configured in the module. */
+u32 gatehwspinlock_get_num_instances(void);
+
+/* Function to return the number of instances not controlled by GateMP. */
+u32 gatehwspinlock_get_num_reserved(void);
+
+/* Function to initialize the locks module. */
+void gatehwspinlock_locks_init(void);
+
+#endif /* ifndef GATEHWSPINLOCK_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/gatemp.h b/arch/arm/plat-omap/include/syslink/gatemp.h
new file mode 100644
index 00000000000..d2d2e4714f3
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/gatemp.h
@@ -0,0 +1,246 @@
+/*
+ * gatemp.h
+ *
+ * gatemp wrapper defines
+ *
+ * Copyright (C) 2008-2009 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 _GATEMP_H_
+#define _GATEMP_H_
+
+#include <sharedregion.h>
+
+/* Unique module ID. */
+#define GATEMP_MODULEID (0xAF70)
+
+/* The resource is still in use */
+#define GateMP_S_BUSY 2
+
+/* The module has been already setup */
+#define GateMP_S_ALREADYSETUP 1
+
+/* Operation is successful. */
+#define GateMP_S_SUCCESS 0
+
+/* Generic failure. */
+#define GateMP_E_FAIL -1
+
+/* The specified entity already exists. */
+#define GateMP_E_ALREADYEXISTS -4
+
+/* Unable to find the specified entity. */
+#define GateMP_E_NOTFOUND -5
+
+/* Operation timed out. */
+#define GateMP_E_TIMEOUT -6
+
+/* Module is not initialized. */
+#define GateMP_E_INVALIDSTATE -7
+
+/* A failure occurred in an OS-specific call */
+#define GateMP_E_OSFAILURE -8
+
+/* Specified resource is not available */
+#define GateMP_E_RESOURCE -9
+
+/* Operation was interrupted. Please restart the operation */
+#define GateMP_E_RESTART -10
+
+/* Gate is local gate not remote */
+#define GateMP_E_LOCALGATE -11
+
+
+/*
+ * A set of local context protection levels
+ *
+ * Each member corresponds to a specific local processor gates used for
+ * local protection.
+ *
+ * In linux user mode, the following are the mapping for the constants
+ * - INTERRUPT -> [N/A]
+ * - TASKLET -> [N/A]
+ * - THREAD -> GateMutex
+ * - PROCESS -> GateMutex
+ *
+ * In linux kernel mode, the following are the mapping for the constants
+ * - INTERRUPT -> [Interrupts disabled]
+ * - TASKLET -> GateMutex
+ * - THREAD -> GateMutex
+ * - PROCESS -> GateMutex
+ *
+ * For SYS/BIOS users, the following are the mappings for the constants
+ * - INTERRUPT -> GateHwi: disables interrupts
+ * - TASKLET -> GateSwi: disables Swi's (software interrupts)
+ * - THREAD -> GateMutexPri: based on Semaphores
+ * - PROCESS -> GateMutexPri: based on Semaphores
+ */
+enum gatemp_local_protect {
+ GATEMP_LOCALPROTECT_NONE = 0,
+ /* Use no local protection */
+
+ GATEMP_LOCALPROTECT_INTERRUPT = 1,
+ /* Use the INTERRUPT local protection level */
+
+ GATEMP_LOCALPROTECT_TASKLET = 2,
+ /* Use the TASKLET local protection level */
+
+ GATEMP_LOCALPROTECT_THREAD = 3,
+ /* Use the THREAD local protection level */
+
+ GATEMP_LOCALPROTECT_PROCESS = 4
+ /* Use the PROCESS local protection level */
+};
+
+/*
+ * Type of remote Gate
+ *
+ * Each member corresponds to a specific type of remote gate.
+ * Each enum value corresponds to the following remote protection levels:
+ * - NONE -> No remote protection (the gatemp instance will
+ * exclusively offer local protection configured in
+ * #GateMP_Params::local_protect
+ * - SYSTEM -> Use the SYSTEM remote protection level (default for
+ * remote protection
+ * - CUSTOM1 -> Use the CUSTOM1 remote protection level
+ * - CUSTOM2 -> Use the CUSTOM2 remote protection level
+ */
+enum gatemp_remote_protect {
+ GATEMP_REMOTEPROTECT_NONE = 0,
+ /* No remote protection (the gatemp instance will exclusively
+ * offer local protection configured in #GateMP_Params::local_protect)
+ */
+
+ GATEMP_REMOTEPROTECT_SYSTEM = 1,
+ /* Use the SYSTEM remote protection level (default remote protection) */
+
+ GATEMP_REMOTEPROTECT_CUSTOM1 = 2,
+ /* Use the CUSTOM1 remote protection level */
+
+ GATEMP_REMOTEPROTECT_CUSTOM2 = 3
+ /* Use the CUSTOM2 remote protection level */
+};
+
+/* Structure defining parameters for the gatemp module. */
+struct gatemp_params {
+ char *name;
+ /* Name of this instance.
+ * The name (if not NULL) must be unique among all GateMP
+ * instances in the entire system. When creating a new
+ * heap, it is necessary to supply an instance name.
+ */
+
+ u32 region_id;
+ /* Shared region ID
+ * The index corresponding to the shared region from which shared memory
+ * will be allocated.
+ * If not specified, the default of '0' will be used.
+ */
+
+ void *shared_addr;
+ /* Physical address of the shared memory
+ * This value can be left as 'null' unless it is required to place the
+ * heap at a specific location in shared memory. If sharedAddr is null,
+ * then shared memory for a new instance will be allocated from the
+ * heap belonging to the region identified by #GateMP_Params::region_id.
+ */
+
+ enum gatemp_local_protect local_protect;
+ /* Local protection level.
+ * The default value is #GATEMP_LOCALPROTECT_THREAD */
+
+ enum gatemp_remote_protect remote_protect;
+ /* Remote protection level
+ * The default value is #GATEMP_REMOTEPROTECT_SYSTEM */
+};
+
+/* Structure defining config parameters for the gatemp module. */
+struct gatemp_config {
+ u32 num_resources;
+ /* Maximum number of resources */
+ enum gatemp_local_protect default_protection;
+ u32 max_name_len;
+ u32 max_runtime_entries;
+};
+
+
+/* Close an opened gate */
+int gatemp_close(void **handle_ptr);
+
+/* Create a gatemp instance */
+void *gatemp_create(const struct gatemp_params *params);
+
+/* Delete a created gatemp instance */
+int gatemp_delete(void **handle_ptr);
+
+/* Query the gate */
+bool gatemp_query(int qual);
+
+/* Get the default remote gate */
+void *gatemp_get_default_remote(void);
+
+/* Get the local protect gate. */
+enum gatemp_local_protect gatemp_get_local_protect(void *obj);
+
+/* Get the remote protect gate. */
+enum gatemp_remote_protect gatemp_get_remote_protect(void *obj);
+
+/* Open a created gatemp by name */
+int gatemp_open(char *name, void **handle_ptr);
+
+/* Open a created gatemp by address */
+int gatemp_open_by_addr(void *shared_addr, void **handle_ptr);
+
+/* Initialize a gatemp parameters struct */
+void gatemp_params_init(struct gatemp_params *params);
+
+/* Amount of shared memory required for creation of each instance */
+uint gatemp_shared_mem_req(const struct gatemp_params *params);
+
+/* Enter the gatemp */
+int *gatemp_enter(void *handle);
+
+/* Leave the gatemp */
+void gatemp_leave(void *handle, int *key);
+
+/* Get the default configuration for the gatemp module. */
+void gatemp_get_config(struct gatemp_config *cfg_params);
+
+/* Setup the gatemp module. */
+s32 gatemp_setup(const struct gatemp_config *cfg);
+
+/* Function to destroy the gatemp module. */
+s32 gatemp_destroy(void);
+
+/* Function to attach gatemp to a remote processor */
+int gatemp_attach(u16 remote_proc_id, void *shared_addr);
+
+/* Function to detach gatemp from a remote processor */
+int gatemp_detach(u16 remote_proc_id, void *shared_addr);
+
+/* Function to start gatemp */
+int gatemp_start(void *shared_addr);
+
+/* Function to start gatemp */
+int gatemp_stop(void);
+
+/* Function to create local gatemp */
+void *gatemp_create_local(enum gatemp_local_protect local_protect);
+
+/* Function to return size required in shared region 0 */
+uint gatemp_get_region0_reserved_size(void);
+
+/* Function to get the shared address of a gatemp object */
+u32 *gatemp_get_shared_addr(void *obj);
+
+
+#endif /* _GATEMP_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/gatemp_ioctl.h b/arch/arm/plat-omap/include/syslink/gatemp_ioctl.h
new file mode 100644
index 00000000000..ff99aebf2fc
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/gatemp_ioctl.h
@@ -0,0 +1,177 @@
+/*
+ * gatemp_ioctl.h
+ *
+ * Definitions of gatemp ioctl types and structures.
+ *
+ * Copyright (C) 2008-2009 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 _GATEMP_IOCTL_H_
+#define _GATEMP_IOCTL_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#include <ipc_ioctl.h>
+#include <gatemp.h>
+
+/* =============================================================================
+ * Macros and types
+ * =============================================================================
+ */
+#define GATEMP_IOC_MAGIC IPC_IOC_MAGIC
+/* IOCTL command ID definitions for GateMP */
+enum CMD_GATEMP {
+ GATEMP_GETCONFIG = GATEMP_BASE_CMD,
+ GATEMP_SETUP,
+ GATEMP_DESTROY,
+ GATEMP_PARAMS_INIT,
+ GATEMP_CREATE,
+ GATEMP_DELETE,
+ GATEMP_OPEN,
+ GATEMP_CLOSE,
+ GATEMP_ENTER,
+ GATEMP_LEAVE,
+ GATEMP_SHAREDMEMREQ,
+ GATEMP_OPENBYADDR,
+ GATEMP_GETDEFAULTREMOTE
+};
+
+/*
+ * IOCTL command IDs for GateMP
+ */
+/* Command for gatemp_get_config */
+#define CMD_GATEMP_GETCONFIG _IOWR(GATEMP_IOC_MAGIC, \
+ GATEMP_GETCONFIG, \
+ struct gatemp_cmd_args)
+/* Command for gatemp_setup */
+#define CMD_GATEMP_SETUP _IOWR(GATEMP_IOC_MAGIC, \
+ GATEMP_SETUP, \
+ struct gatemp_cmd_args)
+/* Command for gatemp_destroy */
+#define CMD_GATEMP_DESTROY _IOWR(GATEMP_IOC_MAGIC, \
+ GATEMP_DESTROY, \
+ struct gatemp_cmd_args)
+/* Command for gatemp_params_init */
+#define CMD_GATEMP_PARAMS_INIT _IOWR(GATEMP_IOC_MAGIC, \
+ GATEMP_PARAMS_INIT, \
+ struct gatemp_cmd_args)
+/* Command for gatemp_create */
+#define CMD_GATEMP_CREATE _IOWR(GATEMP_IOC_MAGIC, \
+ GATEMP_CREATE, \
+ struct gatemp_cmd_args)
+/* Command for gatemp_delete */
+#define CMD_GATEMP_DELETE _IOWR(GATEMP_IOC_MAGIC, \
+ GATEMP_DELETE, \
+ struct gatemp_cmd_args)
+/* Command for gatemp_open */
+#define CMD_GATEMP_OPEN _IOWR(GATEMP_IOC_MAGIC, \
+ GATEMP_OPEN, \
+ struct gatemp_cmd_args)
+/* Command for gatemp_close */
+#define CMD_GATEMP_CLOSE _IOWR(GATEMP_IOC_MAGIC, \
+ GATEMP_CLOSE, \
+ struct gatemp_cmd_args)
+/* Command for gatemp_enter */
+#define CMD_GATEMP_ENTER _IOWR(GATEMP_IOC_MAGIC, \
+ GATEMP_ENTER, \
+ struct gatemp_cmd_args)
+/* Command for gatemp_leave */
+#define CMD_GATEMP_LEAVE _IOWR(GATEMP_IOC_MAGIC, \
+ GATEMP_LEAVE, \
+ struct gatemp_cmd_args)
+/* Command for gatemp_shared_mem_req */
+#define CMD_GATEMP_SHAREDMEMREQ _IOWR(GATEMP_IOC_MAGIC, \
+ GATEMP_SHAREDMEMREQ, \
+ struct gatemp_cmd_args)
+/* Command for gatemp_open_by_addr */
+#define CMD_GATEMP_OPENBYADDR _IOWR(GATEMP_IOC_MAGIC, \
+ GATEMP_OPENBYADDR, \
+ struct gatemp_cmd_args)
+/* Command for gatemp_get_default_remote */
+#define CMD_GATEMP_GETDEFAULTREMOTE _IOWR(GATEMP_IOC_MAGIC, \
+ GATEMP_GETDEFAULTREMOTE, \
+ struct gatemp_cmd_args)
+
+/* Command arguments for GateMP */
+struct gatemp_cmd_args {
+ union {
+ struct {
+ struct gatemp_params *params;
+ } params_init;
+
+ struct {
+ struct gatemp_config *config;
+ } get_config;
+
+ struct {
+ struct gatemp_config *config;
+ } setup;
+
+ struct {
+ void *handle;
+ struct gatemp_params *params;
+ u32 name_len;
+ u32 *shared_addr_srptr;
+ } create;
+
+ struct {
+ void *handle;
+ } delete_instance;
+
+ struct {
+ void *handle;
+ char *name;
+ u32 name_len;
+ u32 *shared_addr_srptr;
+ } open;
+
+ struct {
+ void *handle;
+ u32 *shared_addr_srptr;
+ } open_by_addr;
+
+ struct {
+ void *handle;
+ } close;
+
+ struct {
+ void *handle;
+ int *flags;
+ } enter;
+
+ struct {
+ void *handle;
+ int *flags;
+ } leave;
+
+ struct {
+ struct gatemp_params *params;
+ u32 ret_val;
+ } shared_mem_req;
+
+ struct {
+ void *handle;
+ } get_default_remote;
+ } args;
+
+ s32 api_status;
+};
+
+
+/*
+ * ioctl interface function for gatemp
+ */
+int gatemp_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user);
+
+#endif /* _GATEMP_IOCTL_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/gatempdefs.h b/arch/arm/plat-omap/include/syslink/gatempdefs.h
new file mode 100644
index 00000000000..46f83e2c630
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/gatempdefs.h
@@ -0,0 +1,128 @@
+/*
+ * gatemp.h
+ *
+ * Definitions of gatemp support proxies
+ *
+ * Copyright (C) 2008-2009 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 _GATEMPDEFS_H_
+#define _GATEMPDEFS_H_
+
+
+/* Utilities headers */
+#include <gatepeterson.h>
+#include <gatehwspinlock.h>
+/* Enable once ported - GateMPSupportNull may not be needed
+#include <_GateMPSupportNull.h>
+#include <GateMPSupportNull.h>
+*/
+
+#if 1 /* Enable when SpinLock is available */
+#define gatemp_remote_system_proxy_params_init gatehwspinlock_params_init
+#define gatemp_remote_custom1_proxy_params_init gatepeterson_params_init
+#define gatemp_remote_custom2_proxy_params_init gatepeterson_params_init
+#define gatemp_remote_system_proxy_create gatehwspinlock_create
+#define gatemp_remote_custom1_proxy_create gatepeterson_create
+#define gatemp_remote_custom2_proxy_create gatepeterson_create
+#define gatemp_remote_system_proxy_delete gatehwspinlock_delete
+#define gatemp_remote_custom1_proxy_delete gatepeterson_delete
+#define gatemp_remote_custom2_proxy_delete gatepeterson_delete
+#define gatemp_remote_system_proxy_params struct gatehwspinlock_params
+#define gatemp_remote_custom1_proxy_params struct gatepeterson_params
+#define gatemp_remote_custom2_proxy_params struct gatepeterson_params
+#define gatemp_remote_system_proxy_shared_mem_req \
+ gatehwspinlock_shared_mem_req
+#define gatemp_remote_custom1_proxy_shared_mem_req \
+ gatepeterson_shared_mem_req
+#define gatemp_remote_custom2_proxy_shared_mem_req \
+ gatepeterson_shared_mem_req
+#define gatemp_remote_system_proxy_get_num_instances \
+ gatehwspinlock_get_num_instances
+#define gatemp_remote_custom1_proxy_get_num_instances \
+ gatepeterson_get_num_instances
+#define gatemp_remote_custom2_proxy_get_num_instances \
+ gatepeterson_get_num_instances
+#define gatemp_remote_system_proxy_get_num_reserved \
+ gatehwspinlock_get_num_reserved
+#define gatemp_remote_custom1_proxy_get_num_reserved \
+ gatepeterson_get_num_reserved
+#define gatemp_remote_custom2_proxy_get_num_reserved \
+ gatepeterson_get_num_reserved
+#define gatemp_remote_system_proxy_locks_init gatehwspinlock_locks_init
+#define gatemp_remote_custom1_proxy_locks_init gatepeterson_locks_init
+#define gatemp_remote_custom2_proxy_locks_init gatepeterson_locks_init
+#define gatemp_remote_system_proxy_handle void *
+#define gatemp_remote_custom1_proxy_handle void *
+#define gatemp_remote_custom2_proxy_handle void *
+#define gatemp_remote_system_proxy_open_by_addr gatehwspinlock_open_by_addr
+#define gatemp_remote_custom1_proxy_open_by_addr \
+ gatepeterson_open_by_addr
+#define gatemp_remote_custom2_proxy_open_by_addr \
+ gatepeterson_open_by_addr
+#define gatemp_remote_system_proxy_enter gatehwspinlock_enter
+#define gatemp_remote_system_proxy_leave gatehwspinlock_leave
+#define gatemp_remote_custom1_proxy_enter gatepeterson_enter
+#define gatemp_remote_custom1_proxy_leave gatepeterson_leave
+#define gatemp_remote_custom2_proxy_enter gatepeterson_enter
+#define gatemp_remote_custom2_proxy_leave gatepeterson_leave
+#else
+#define gatemp_remote_system_proxy_params_init gatepeterson_params_init
+#define gatemp_remote_custom1_proxy_params_init gatepeterson_params_init
+#define gatemp_remote_custom2_proxy_params_init gatepeterson_params_init
+#define gatemp_remote_system_proxy_create gatepeterson_create
+#define gatemp_remote_custom1_proxy_create gatepeterson_create
+#define gatemp_remote_custom2_proxy_create gatepeterson_create
+#define gatemp_remote_system_proxy_delete gatepeterson_delete
+#define gatemp_remote_custom1_proxy_delete gatepeterson_delete
+#define gatemp_remote_custom2_proxy_delete gatepeterson_delete
+#define gatemp_remote_system_proxy_params struct gatepeterson_params
+#define gatemp_remote_custom1_proxy_params struct gatepeterson_params
+#define gatemp_remote_custom2_proxy_params struct gatepeterson_params
+#define gatemp_remote_system_proxy_shared_mem_req \
+ gatepeterson_shared_mem_req
+#define gatemp_remote_custom1_proxy_shared_mem_req \
+ gatepeterson_shared_mem_req
+#define gatemp_remote_custom2_proxy_shared_mem_req \
+ gatepeterson_shared_mem_req
+#define gatemp_remote_system_proxy_get_num_instances \
+ gatepeterson_get_num_instances
+#define gatemp_remote_custom1_proxy_get_num_instances \
+ gatepeterson_get_num_instances
+#define gatemp_remote_custom2_proxy_get_num_instances \
+ gatepeterson_get_num_instances
+#define gatemp_remote_system_proxy_get_num_reserved \
+ gatepeterson_get_num_reserved
+#define gatemp_remote_custom1_proxy_get_num_reserved \
+ gatepeterson_get_num_reserved
+#define gatemp_remote_custom2_proxy_get_num_reserved \
+ gatepeterson_get_num_reserved
+#define gatemp_remote_system_proxy_locks_init gatepeterson_locks_init
+#define gatemp_remote_custom1_proxy_locks_init gatepeterson_locks_init
+#define gatemp_remote_custom2_proxy_locks_init gatepeterson_locks_init
+#define gatemp_remote_system_proxy_handle void *
+#define gatemp_remote_custom1_proxy_handle void *
+#define gatemp_remote_custom2_proxy_handle void *
+#define gatemp_remote_system_proxy_open_by_addr gatepeterson_open_by_addr
+#define gatemp_remote_custom1_proxy_open_by_addr \
+ gatepeterson_open_by_addr
+#define gatemp_remote_custom2_proxy_open_by_addr \
+ gatepeterson_open_by_addr
+#define gatemp_remote_system_proxy_enter gatepeterson_enter
+#define gatemp_remote_system_proxy_leave gatepeterson_leave
+#define gatemp_remote_custom1_proxy_enter gatepeterson_enter
+#define gatemp_remote_custom1_proxy_leave gatepeterson_leave
+#define gatemp_remote_custom2_proxy_enter gatepeterson_enter
+#define gatemp_remote_custom2_proxy_leave gatepeterson_leave
+#endif
+
+#endif /* _GATEMPDEFS_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/gatepeterson.h b/arch/arm/plat-omap/include/syslink/gatepeterson.h
new file mode 100644
index 00000000000..31e7e7c0ed4
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/gatepeterson.h
@@ -0,0 +1,145 @@
+/*
+ * gatepeterson.h
+ *
+ * The Gate Peterson Algorithm for mutual exclusion of shared memory.
+ * Current implementation works for 2 processors.
+ *
+ * Copyright (C) 2008-2009 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 _GATEPETERSON_H_
+#define _GATEPETERSON_H_
+
+#include <linux/types.h>
+
+#include <igatempsupport.h>
+
+/*
+ * GATEPETERSON_MODULEID
+ * Unique module ID
+ */
+#define GATEPETERSON_MODULEID (0xF415)
+
+/*
+ * A set of context protection levels that each correspond to
+ * single processor gates used for local protection
+ */
+enum gatepeterson_protect {
+ GATEPETERSON_PROTECT_DEFAULT = 0,
+ GATEPETERSON_PROTECT_NONE = 1,
+ GATEPETERSON_PROTECT_INTERRUPT = 2,
+ GATEPETERSON_PROTECT_TASKLET = 3,
+ GATEPETERSON_PROTECT_THREAD = 4,
+ GATEPETERSON_PROTECT_PROCESS = 5,
+ GATEPETERSON_PROTECT_END_VALUE = 6
+};
+
+/*
+ * Structure defining config parameters for the Gate Peterson
+ * module
+ */
+struct gatepeterson_config {
+ enum gatepeterson_protect default_protection;
+ /*!< Default module-wide local context protection level. The level of
+ * protection specified here determines which local gate is created per
+ * GatePeterson instance for local protection during create. The instance
+ * configuration parameter may be usedto override this module setting per
+ * instance. The configuration used here should reflect both the context
+ * in which enter and leave are to be called,as well as the maximum level
+ * of protection needed locally.
+ */
+ u32 num_instances;
+ /*!< Maximum number of instances supported by the GatePeterson module */
+
+};
+
+/*
+ * Structure defining config parameters for the Gate Peterson
+ * instances
+ */
+struct gatepeterson_params {
+ IGATEMPSUPPORT_SUPERPARAMS;
+};
+
+/*
+ * Function to initialize the parameter structure
+ */
+void gatepeterson_get_config(struct gatepeterson_config *config);
+
+/*
+ * Function to initialize GP module
+ */
+int gatepeterson_setup(const struct gatepeterson_config *config);
+
+/*
+ * Function to destroy the GP module
+ */
+int gatepeterson_destroy(void);
+
+/*
+ * Function to initialize the parameter structure
+ */
+void gatepeterson_params_init(struct gatepeterson_params *params);
+
+/*
+ * Function to create an instance of GatePeterson
+ */
+void *gatepeterson_create(enum igatempsupport_local_protect local_protect,
+ const struct gatepeterson_params *params);
+
+/*
+ * Function to delete an instance of GatePeterson
+ */
+int gatepeterson_delete(void **gphandle);
+
+/*
+ * Function to open a previously created instance by address
+ */
+int gatepeterson_open_by_addr(enum igatempsupport_local_protect local_protect,
+ void *shared_addr, void **gphandle);
+
+/*
+ * Function to close a previously opened instance
+ */
+int gatepeterson_close(void **gphandle);
+
+/*
+ * Function to enter the gate peterson
+ */
+int *gatepeterson_enter(void *gphandle);
+
+/*
+ *Function to leave the gate peterson
+ */
+void gatepeterson_leave(void *gphandle, int *key);
+
+/*
+ * Function to return the shared memory requirement
+ */
+u32 gatepeterson_shared_mem_req(const struct gatepeterson_params *params);
+
+/*
+ * Function to return the number of instances configured in the module.
+ */
+u32 gatepeterson_get_num_instances(void);
+
+/*
+ * Function to return the number of instances not controlled by GateMP.
+ */
+u32 gatepeterson_get_num_reserved(void);
+
+/*
+ * Function to initialize the locks module.
+ */
+void gatepeterson_locks_init(void);
+
+#endif /* _GATEPETERSON_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/gt.h b/arch/arm/plat-omap/include/syslink/gt.h
new file mode 100644
index 00000000000..95e3feb18e7
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/gt.h
@@ -0,0 +1,320 @@
+
+/*
+ * 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 <linux/types.h>
+#ifndef GT_
+#define GT_
+
+#ifndef GT_TRACE
+#define GT_TRACE 0 /* 0 = "trace compiled out"; 1 = "trace active" */
+#endif
+
+/* #include <syslink/host_os.h> */
+
+typedef s32(*Fxn)(); /* generic function type */
+
+
+#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)
+#define GT_LEAVE ((u8)0x02)
+
+#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(KERN_ALERT "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/syslink/heap.h b/arch/arm/plat-omap/include/syslink/heap.h
new file mode 100644
index 00000000000..47949ad1cbb
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/heap.h
@@ -0,0 +1,96 @@
+/*
+ * heap.h
+ *
+ * Heap module manages fixed size buffers that can be used
+ * in a multiprocessor system with shared memory.
+ *
+ * Copyright (C) 2008-2009 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 _HEAP_H_
+#define _HEAP_H_
+
+#include <linux/types.h>
+
+/*
+ * Structure defining memory related statistics
+ */
+struct memory_stats{
+ u32 total_size; /* Total memory size */
+ u32 total_free_size; /* Total free memory size */
+ u32 largest_free_size; /* Largest free memory size */
+};
+
+/*!
+ * ======== extendedstats ========
+ * Stats structure for the get_extended_stats API.
+ *
+ * max_allocated_blocks: The maximum number of blocks allocated
+ * from this heap at any single point in time during the lifetime of this
+ * heap instance.
+ *
+ * num_allocated_blocks: The total number of blocks currently
+ * allocated in this Heap instance.
+ */
+struct heap_extended_stats {
+ u32 max_allocated_blocks;
+ u32 num_allocated_blocks;
+};
+
+/*
+ * Structure defining config parameters for the heapbuf module
+ */
+struct heap_config {
+ u32 max_name_len; /* Maximum length of name */
+ bool track_max_allocs; /* Track the max number of allocated blocks */
+};
+
+/*
+ * Structure for the handle for the heap
+ */
+struct heap_object {
+ void* (*alloc) (void *handle, u32 size, u32 align);
+ int (*free) (void *handle, void *block, u32 size);
+ void (*get_stats) (void *handle, struct memory_stats *stats);
+ void (*get_extended_stats) (void *handle,
+ struct heap_extended_stats *stats);
+ bool (*is_blocking) (void *handle);
+ void *obj;
+};
+
+/*
+ * Allocate a block
+ */
+void *sl_heap_alloc(void *handle, u32 size, u32 align);
+
+/*
+ * Frees the block to this Heap
+ */
+int sl_heap_free(void *handle, void *block, u32 size);
+
+/*
+ * Get heap statistics
+ */
+void sl_heap_get_stats(void *handle, struct memory_stats *stats);
+
+/*
+ * Get heap extended statistics
+ */
+void sl_heap_get_extended_stats(void *hphandle,
+ struct heap_extended_stats *stats);
+
+/*
+ * Indicates whether a heap will block on free or alloc
+ */
+bool sl_heap_is_blocking(void *hphandle);
+
+#endif /* _HEAP_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/heapbufmp.h b/arch/arm/plat-omap/include/syslink/heapbufmp.h
new file mode 100644
index 00000000000..51fd65c0c11
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/heapbufmp.h
@@ -0,0 +1,253 @@
+/*
+ * heapbufmp.h
+ *
+ * Heap module manages fixed size buffers that can be used
+ * in a multiprocessor system with shared memory.
+ *
+ * Copyright (C) 2008-2009 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 _HEAPBUFMP_H_
+#define _HEAPBUFMP_H_
+
+#include <linux/types.h>
+#include <heap.h>
+#include <listmp.h>
+
+/*!
+ * @def LISTMP_MODULEID
+ * @brief Unique module ID.
+ */
+#define HEAPBUFMP_MODULEID (0x4cd5)
+
+/*
+ * Creation of Heap Buf succesful.
+*/
+#define HEAPBUFMP_CREATED (0x05251995)
+
+/*
+ * Version.
+ */
+#define HEAPBUFMP_VERSION (1)
+
+/* =============================================================================
+ * All success and failure codes for the module
+ * =============================================================================
+ */
+
+/*!
+ * @def HEAPBUFMP_S_BUSY
+ * @brief The resource is still in use
+ */
+#define HEAPBUFMP_S_BUSY 2
+
+/*!
+ * @def HEAPBUFMP_S_ALREADYSETUP
+ * @brief The module has been already setup
+ */
+#define HEAPBUFMP_S_ALREADYSETUP 1
+
+/*!
+ * @def HEAPBUFMP_S_SUCCESS
+ * @brief Operation is successful.
+ */
+#define HEAPBUFMP_S_SUCCESS 0
+
+/*!
+ * @def HEAPBUFMP_E_FAIL
+ * @brief Generic failure.
+ */
+#define HEAPBUFMP_E_FAIL -1
+
+/*!
+ * @def HEAPBUFMP_E_INVALIDARG
+ * @brief Argument passed to function is invalid.
+ */
+#define HEAPBUFMP_E_INVALIDARG -2
+
+/*!
+ * @def HEAPBUFMP_E_MEMORY
+ * @brief Operation resulted in memory failure.
+ */
+#define HEAPBUFMP_E_MEMORY -3
+
+/*!
+ * @def HEAPBUFMP_E_ALREADYEXISTS
+ * @brief The specified entity already exists.
+ */
+#define HEAPBUFMP_E_ALREADYEXISTS -4
+
+/*!
+ * @def HEAPBUFMP_E_NOTFOUND
+ * @brief Unable to find the specified entity.
+ */
+#define HEAPBUFMP_E_NOTFOUND -5
+
+/*!
+ * @def HEAPBUFMP_E_TIMEOUT
+ * @brief Operation timed out.
+ */
+#define HEAPBUFMP_E_TIMEOUT -6
+
+/*!
+ * @def HEAPBUFMP_E_INVALIDSTATE
+ * @brief Module is not initialized.
+ */
+#define HEAPBUFMP_E_INVALIDSTATE -7
+
+/*!
+ * @def HEAPBUFMP_E_OSFAILURE
+ * @brief A failure occurred in an OS-specific call */
+#define HEAPBUFMP_E_OSFAILURE -8
+
+/*!
+ * @def HEAPBUFMP_E_RESOURCE
+ * @brief Specified resource is not available */
+#define HEAPBUFMP_E_RESOURCE -9
+
+/*!
+ * @def HEAPBUFMP_E_RESTART
+ * @brief Operation was interrupted. Please restart the operation */
+#define HEAPBUFMP_E_RESTART -10
+
+
+/* =============================================================================
+ * Macros
+ * =============================================================================
+ */
+
+
+/* =============================================================================
+ * Structures & Enums
+ * =============================================================================
+ */
+
+/*
+ * Structure defining config parameters for the HeapBuf module.
+ */
+struct heapbufmp_config {
+ u32 max_name_len; /* Maximum length of name */
+ u32 max_runtime_entries; /* Maximum number of heapbufmp instances */
+ /* that can be created */
+ bool track_allocs; /* Track the maximum number of allocated */
+ /* blocks */
+};
+
+/*
+ * Structure defining parameters for the HeapBuf module
+ */
+struct heapbufmp_params {
+ char *name; /* Name of this instance */
+ u16 region_id; /* Shared region ID */
+ void *shared_addr; /* Physical address of the shared memory */
+ u32 block_size; /* Size (in MAUs) of each block */
+ u32 num_blocks; /* Number of fixed-size blocks */
+ u32 align; /* Alignment (in MAUs, power of 2) of each block */
+ bool exact; /* Only allocate on exact match of rquested size */
+ void *gate; /* GateMP used for critical region management of */
+ /* the shared memory */
+};
+
+/*
+ * Stats structure for the getExtendedStats API.
+ */
+struct heapbufmp_extended_stats {
+ u32 max_allocated_blocks;
+ /* maximum number of blocks allocated from this heap instance */
+ u32 num_allocated_blocks;
+ /* total number of blocks currently allocated from this heap instance*/
+};
+
+/* =============================================================================
+ * APIs
+ * =============================================================================
+ */
+
+/*
+ * Function to get default configuration for the heapbufmp module
+ */
+int heapbufmp_get_config(struct heapbufmp_config *cfgparams);
+
+/*
+ * Function to setup the heapbufmp module
+ */
+int heapbufmp_setup(const struct heapbufmp_config *cfg);
+
+/*
+ * Function to destroy the heapbufmp module
+ */
+int heapbufmp_destroy(void);
+
+/* Initialize this config-params structure with supplier-specified
+ * defaults before instance creation
+ */
+void heapbufmp_params_init(struct heapbufmp_params *params);
+
+/*
+ * Creates a new instance of heapbufmp module
+ */
+void *heapbufmp_create(const struct heapbufmp_params *params);
+
+/*
+ * Deletes a instance of heapbufmp module
+ */
+int heapbufmp_delete(void **handle_ptr);
+
+/*
+ * Opens a created instance of heapbufmp module by name
+ */
+int heapbufmp_open(char *name, void **handle_ptr);
+
+/*
+ * Opens a created instance of heapbufmp module by address
+ */
+int heapbufmp_open_by_addr(void *shared_addr, void **handle_ptr);
+
+/*
+ * Closes previously opened/created instance of heapbufmp module
+ */
+int heapbufmp_close(void **handle_ptr);
+
+/*
+ * Returns the amount of shared memory required for creation
+ * of each instance
+ */
+int heapbufmp_shared_mem_req(const struct heapbufmp_params *params);
+
+/*
+ * Allocate a block
+ */
+void *heapbufmp_alloc(void *hphandle, u32 size, u32 align);
+
+/*
+ * Frees the block to this heapbufmp
+ */
+int heapbufmp_free(void *hphandle, void *block, u32 size);
+
+/*
+ * Get memory statistics
+ */
+void heapbufmp_get_stats(void *hphandle, struct memory_stats *stats);
+
+/*
+ * Indicate whether the heap may block during an alloc or free call
+ */
+bool heapbufmp_isblocking(void *handle);
+
+/*
+ * Get extended statistics
+ */
+void heapbufmp_get_extended_stats(void *hphandle,
+ struct heapbufmp_extended_stats *stats);
+
+
+#endif /* _HEAPBUFMP_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/heapbufmp_ioctl.h b/arch/arm/plat-omap/include/syslink/heapbufmp_ioctl.h
new file mode 100644
index 00000000000..f291a5e3d07
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/heapbufmp_ioctl.h
@@ -0,0 +1,232 @@
+/*
+ * heapbufmp_ioctl.h
+ *
+ * Heap module manages fixed size buffers that can be used
+ * in a multiprocessor system with shared memory.
+ *
+ * Copyright (C) 2008-2009 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 _HEAPBUFMP_IOCTL_
+#define _HEAPBUFMP_IOCTL_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#include <ipc_ioctl.h>
+#include <heapbufmp.h>
+
+
+enum CMD_HEAPBUF {
+ HEAPBUFMP_GETCONFIG = HEAPBUFMP_BASE_CMD,
+ HEAPBUFMP_SETUP,
+ HEAPBUFMP_DESTROY,
+ HEAPBUFMP_PARAMS_INIT,
+ HEAPBUFMP_CREATE,
+ HEAPBUFMP_DELETE,
+ HEAPBUFMP_OPEN,
+ HEAPBUFMP_OPENBYADDR,
+ HEAPBUFMP_CLOSE,
+ HEAPBUFMP_ALLOC,
+ HEAPBUFMP_FREE,
+ HEAPBUFMP_SHAREDMEMREQ,
+ HEAPBUFMP_GETSTATS,
+ HEAPBUFMP_GETEXTENDEDSTATS
+};
+
+/*
+ * Command for heapbufmp_get_config
+ */
+#define CMD_HEAPBUFMP_GETCONFIG _IOWR(IPC_IOC_MAGIC, \
+ HEAPBUFMP_GETCONFIG, \
+ struct heapbufmp_cmd_args)
+
+/*
+ * Command for heapbufmp_setup
+ */
+#define CMD_HEAPBUFMP_SETUP _IOWR(IPC_IOC_MAGIC, \
+ HEAPBUFMP_SETUP, \
+ struct heapbufmp_cmd_args)
+/*
+ * Command for heapbufmp_destroy
+ */
+#define CMD_HEAPBUFMP_DESTROY _IOWR(IPC_IOC_MAGIC, \
+ HEAPBUFMP_DESTROY, \
+ struct heapbufmp_cmd_args)
+
+/*
+ * Command for heapbufmp_prams_init
+ */
+#define CMD_HEAPBUFMP_PARAMS_INIT _IOWR(IPC_IOC_MAGIC, \
+ HEAPBUFMP_PARAMS_INIT, \
+ struct heapbufmp_cmd_args)
+
+/*
+ * Command for heapbufmp_create
+ */
+#define CMD_HEAPBUFMP_CREATE _IOWR(IPC_IOC_MAGIC, \
+ HEAPBUFMP_CREATE, \
+ struct heapbufmp_cmd_args)
+
+/*
+ * Command for heapbufmp_delete
+ */
+#define CMD_HEAPBUFMP_DELETE _IOWR(IPC_IOC_MAGIC, \
+ HEAPBUFMP_DELETE, \
+ struct heapbufmp_cmd_args)
+
+/*
+ * Command for heapbufmp_open
+ */
+#define CMD_HEAPBUFMP_OPEN _IOWR(IPC_IOC_MAGIC, \
+ HEAPBUFMP_OPEN, \
+ struct heapbufmp_cmd_args)
+
+/*
+ * Command for heapbufmp_open_by_addr
+ */
+#define CMD_HEAPBUFMP_OPENBYADDR _IOWR(IPC_IOC_MAGIC, \
+ HEAPBUFMP_OPENBYADDR, \
+ struct heapbufmp_cmd_args)
+
+/*
+ * Command for heapbufmp_close
+ */
+#define CMD_HEAPBUFMP_CLOSE _IOWR(IPC_IOC_MAGIC, \
+ HEAPBUFMP_CLOSE, \
+ struct heapbufmp_cmd_args)
+
+/*
+ * Command for heapbufmp_alloc
+ */
+#define CMD_HEAPBUFMP_ALLOC _IOWR(IPC_IOC_MAGIC, \
+ HEAPBUFMP_ALLOC, \
+ struct heapbufmp_cmd_args)
+
+/*
+ * Command for heapbufmp_free
+ */
+#define CMD_HEAPBUFMP_FREE _IOWR(IPC_IOC_MAGIC, \
+ HEAPBUFMP_FREE, \
+ struct heapbufmp_cmd_args)
+
+/*
+ * Command for heapbufmp_shared_mem_req
+ */
+#define CMD_HEAPBUFMP_SHAREDMEMREQ _IOWR(IPC_IOC_MAGIC, \
+ HEAPBUFMP_SHAREDMEMREQ, \
+ struct heapbufmp_cmd_args)
+
+/*
+ * Command for heapbufmp_get_stats
+ */
+#define CMD_HEAPBUFMP_GETSTATS _IOWR(IPC_IOC_MAGIC, \
+ HEAPBUFMP_GETSTATS, \
+ struct heapbufmp_cmd_args)
+
+/*
+ * Command for heapbufmp_get_extended_stats
+ */
+#define CMD_HEAPBUFMP_GETEXTENDEDSTATS _IOWR(IPC_IOC_MAGIC, \
+ HEAPBUFMP_GETEXTENDEDSTATS, \
+ struct heapbufmp_cmd_args)
+
+
+/*
+ * Command arguments for heapbuf
+ */
+union heapbufmp_arg {
+ struct {
+ struct heapbufmp_params *params;
+ } params_init;
+
+ struct {
+ struct heapbufmp_config *config;
+ } get_config;
+
+ struct {
+ struct heapbufmp_config *config;
+ } setup;
+
+ struct {
+ void *handle;
+ struct heapbufmp_params *params;
+ u32 name_len;
+ u32 *shared_addr_srptr;
+ void *knl_gate;
+ } create;
+
+ struct {
+ void *handle;
+ } delete;
+
+ struct {
+ void *handle;
+ char *name;
+ u32 name_len;
+ } open;
+
+ struct {
+ void *handle;
+ u32 *shared_addr_srptr;
+ } open_by_addr;
+
+ struct {
+ void *handle;
+ } close;
+
+ struct {
+ void *handle;
+ u32 size;
+ u32 align;
+ u32 *block_srptr;
+ } alloc;
+
+ struct {
+ void *handle;
+ u32 *block_srptr;
+ u32 size;
+ } free;
+
+ struct {
+ void *handle;
+ struct memory_stats *stats;
+ } get_stats;
+
+ struct {
+ void *handle;
+ struct heapbufmp_extended_stats *stats;
+ } get_extended_stats;
+
+ struct {
+ void *handle;
+ struct heapbufmp_params *params;
+ u32 *shared_addr_srptr;
+ u32 bytes;
+ } shared_mem_req;
+};
+
+/*
+ * Command arguments for heapbuf
+ */
+struct heapbufmp_cmd_args{
+ union heapbufmp_arg args;
+ s32 api_status;
+};
+
+/*
+ * This ioctl interface for heapbuf module
+ */
+int heapbufmp_ioctl(struct inode *pinode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user);
+
+#endif /* _HEAPBUFMP_IOCTL_ */
diff --git a/arch/arm/plat-omap/include/syslink/heapmemmp.h b/arch/arm/plat-omap/include/syslink/heapmemmp.h
new file mode 100644
index 00000000000..bfce85be4b5
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/heapmemmp.h
@@ -0,0 +1,252 @@
+/*
+ * heapmemmp.h
+ *
+ * Heap module manages fixed size buffers that can be used
+ * in a multiprocessor system with shared memory.
+ *
+ * Copyright (C) 2008-2009 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 _HEAPMEMMP_H_
+#define _HEAPMEMMP_H_
+
+#include <linux/types.h>
+#include <heap.h>
+#include <listmp.h>
+
+/*!
+ * @def LISTMP_MODULEID
+ * @brief Unique module ID.
+ */
+#define HEAPMEMMP_MODULEID (0x4cd7)
+
+/*
+ * Creation of Heap Buf succesful.
+*/
+#define HEAPMEMMP_CREATED (0x07041776)
+
+/*
+ * Version.
+ */
+#define HEAPMEMMP_VERSION (1)
+
+/* =============================================================================
+ * All success and failure codes for the module
+ * =============================================================================
+ */
+
+/*!
+ * @def HEAPMEMMP_S_BUSY
+ * @brief The resource is still in use
+ */
+#define HEAPMEMMP_S_BUSY 2
+
+/*!
+ * @def HEAPMEMMP_S_ALREADYSETUP
+ * @brief The module has been already setup
+ */
+#define HEAPMEMMP_S_ALREADYSETUP 1
+
+/*!
+ * @def HEAPMEMMP_S_SUCCESS
+ * @brief Operation is successful.
+ */
+#define HEAPMEMMP_S_SUCCESS 0
+
+/*!
+ * @def HEAPMEMMP_E_FAIL
+ * @brief Generic failure.
+ */
+#define HEAPMEMMP_E_FAIL -1
+
+/*!
+ * @def HEAPMEMMP_E_INVALIDARG
+ * @brief Argument passed to function is invalid.
+ */
+#define HEAPMEMMP_E_INVALIDARG -2
+
+/*!
+ * @def HEAPMEMMP_E_MEMORY
+ * @brief Operation resulted in memory failure.
+ */
+#define HEAPMEMMP_E_MEMORY -3
+
+/*!
+ * @def HEAPMEMMP_E_ALREADYEXISTS
+ * @brief The specified entity already exists.
+ */
+#define HEAPMEMMP_E_ALREADYEXISTS -4
+
+/*!
+ * @def HEAPMEMMP_E_NOTFOUND
+ * @brief Unable to find the specified entity.
+ */
+#define HEAPMEMMP_E_NOTFOUND -5
+
+/*!
+ * @def HEAPMEMMP_E_TIMEOUT
+ * @brief Operation timed out.
+ */
+#define HEAPMEMMP_E_TIMEOUT -6
+
+/*!
+ * @def HEAPMEMMP_E_INVALIDSTATE
+ * @brief Module is not initialized.
+ */
+#define HEAPMEMMP_E_INVALIDSTATE -7
+
+/*!
+ * @def HEAPMEMMP_E_OSFAILURE
+ * @brief A failure occurred in an OS-specific call */
+#define HEAPMEMMP_E_OSFAILURE -8
+
+/*!
+ * @def HEAPMEMMP_E_RESOURCE
+ * @brief Specified resource is not available */
+#define HEAPMEMMP_E_RESOURCE -9
+
+/*!
+ * @def HEAPMEMMP_E_RESTART
+ * @brief Operation was interrupted. Please restart the operation */
+#define HEAPMEMMP_E_RESTART -10
+
+
+/* =============================================================================
+ * Macros
+ * =============================================================================
+ */
+
+
+/* =============================================================================
+ * Structures & Enums
+ * =============================================================================
+ */
+
+/*
+ * Structure defining config parameters for the HeapBuf module.
+ */
+struct heapmemmp_config {
+ u32 max_name_len; /* Maximum length of name */
+ u32 max_runtime_entries; /* Maximum number of heapmemmp instances */
+ /* that can be created */
+};
+
+/*
+ * Structure defining parameters for the HeapBuf module
+ */
+struct heapmemmp_params {
+ char *name; /* Name of this instance */
+ u16 region_id; /* Shared region ID */
+ void *shared_addr; /* Physical address of the shared memory */
+ u32 shared_buf_size; /* Size of shared buffer */
+ void *gate; /* GateMP used for critical region management of the */
+ /* shared memory */
+};
+
+/*
+ * Stats structure for the getExtendedStats API.
+ */
+struct heapmemmp_extended_stats {
+ void *buf;
+ /* Local address of the shared buffer */
+
+ u32 size;
+ /* Size of the shared buffer */
+};
+
+/* =============================================================================
+ * APIs
+ * =============================================================================
+ */
+
+/*
+ * Function to get default configuration for the heapmemmp module
+ */
+int heapmemmp_get_config(struct heapmemmp_config *cfgparams);
+
+/*
+ * Function to setup the heapmemmp module
+ */
+int heapmemmp_setup(const struct heapmemmp_config *cfg);
+
+/*
+ * Function to destroy the heapmemmp module
+ */
+int heapmemmp_destroy(void);
+
+/* Initialize this config-params structure with supplier-specified
+ * defaults before instance creation
+ */
+void heapmemmp_params_init(struct heapmemmp_params *params);
+
+/*
+ * Creates a new instance of heapmemmp module
+ */
+void *heapmemmp_create(const struct heapmemmp_params *params);
+
+/*
+ * Deletes a instance of heapmemmp module
+ */
+int heapmemmp_delete(void **handle_ptr);
+
+/*
+ * Opens a created instance of heapmemmp module by name
+ */
+int heapmemmp_open(char *name, void **handle_ptr);
+
+/*
+ * Opens a created instance of heapmemmp module by address
+ */
+int heapmemmp_open_by_addr(void *shared_addr, void **handle_ptr);
+
+/*
+ * Closes previously opened/created instance of heapmemmp module
+ */
+int heapmemmp_close(void **handle_ptr);
+
+/*
+ * Returns the amount of shared memory required for creation
+ * of each instance
+ */
+int heapmemmp_shared_mem_req(const struct heapmemmp_params *params);
+
+/*
+ * Allocate a block
+ */
+void *heapmemmp_alloc(void *hphandle, u32 size, u32 align);
+
+/*
+ * Frees the block to this heapmemmp
+ */
+int heapmemmp_free(void *hphandle, void *block, u32 size);
+
+/*
+ * Get memory statistics
+ */
+void heapmemmp_get_stats(void *hphandle, struct memory_stats *stats);
+
+/*
+ * Indicate whether the heap may block during an alloc or free call
+ */
+bool heapmemmp_isblocking(void *handle);
+
+/*
+ * Get extended statistics
+ */
+void heapmemmp_get_extended_stats(void *hphandle,
+ struct heapmemmp_extended_stats *stats);
+/*
+ * Restore an instance to it's original created state.
+ */
+void heapmemmp_restore(void *handle);
+
+#endif /* _HEAPMEMMP_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/heapmemmp_ioctl.h b/arch/arm/plat-omap/include/syslink/heapmemmp_ioctl.h
new file mode 100644
index 00000000000..10020148d21
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/heapmemmp_ioctl.h
@@ -0,0 +1,243 @@
+/*
+ * heapmemmp_ioctl.h
+ *
+ * Heap module manages fixed size buffers that can be used
+ * in a multiprocessor system with shared memory.
+ *
+ * Copyright (C) 2008-2009 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 _HEAPMEMMP_IOCTL_
+#define _HEAPMEMMP_IOCTL_
+
+#include <linux/types.h>
+
+#include <ipc_ioctl.h>
+#include <heapmemmp.h>
+
+
+enum CMD_HEAPMEM {
+ HEAPMEMMP_GETCONFIG = HEAPMEMMP_BASE_CMD,
+ HEAPMEMMP_SETUP,
+ HEAPMEMMP_DESTROY,
+ HEAPMEMMP_PARAMS_INIT,
+ HEAPMEMMP_CREATE,
+ HEAPMEMMP_DELETE,
+ HEAPMEMMP_OPEN,
+ HEAPMEMMP_OPENBYADDR,
+ HEAPMEMMP_CLOSE,
+ HEAPMEMMP_ALLOC,
+ HEAPMEMMP_FREE,
+ HEAPMEMMP_SHAREDMEMREQ,
+ HEAPMEMMP_GETSTATS,
+ HEAPMEMMP_GETEXTENDEDSTATS,
+ HEAPMEMMP_RESTORE
+};
+
+/*
+ * Command for heapmemmp_get_config
+ */
+#define CMD_HEAPMEMMP_GETCONFIG _IOWR(IPC_IOC_MAGIC, \
+ HEAPMEMMP_GETCONFIG,\
+ struct heapmemmp_cmd_args)
+
+/*
+ * Command for heapmemmp_setup
+ */
+#define CMD_HEAPMEMMP_SETUP _IOWR(IPC_IOC_MAGIC, \
+ HEAPMEMMP_SETUP, \
+ struct heapmemmp_cmd_args)
+/*
+ * Command for heapmemmp_destroy
+ */
+#define CMD_HEAPMEMMP_DESTROY _IOWR(IPC_IOC_MAGIC, \
+ HEAPMEMMP_DESTROY, \
+ struct heapmemmp_cmd_args)
+
+/*
+ * Command for heapmemmp_prams_init
+ */
+#define CMD_HEAPMEMMP_PARAMS_INIT _IOWR(IPC_IOC_MAGIC, \
+ HEAPMEMMP_PARAMS_INIT, \
+ struct heapmemmp_cmd_args)
+
+/*
+ * Command for heapmemmp_create
+ */
+#define CMD_HEAPMEMMP_CREATE _IOWR(IPC_IOC_MAGIC, \
+ HEAPMEMMP_CREATE, \
+ struct heapmemmp_cmd_args)
+
+/*
+ * Command for heapmemmp_delete
+ */
+#define CMD_HEAPMEMMP_DELETE _IOWR(IPC_IOC_MAGIC, \
+ HEAPMEMMP_DELETE, \
+ struct heapmemmp_cmd_args)
+
+/*
+ * Command for heapmemmp_open
+ */
+#define CMD_HEAPMEMMP_OPEN _IOWR(IPC_IOC_MAGIC, \
+ HEAPMEMMP_OPEN, \
+ struct heapmemmp_cmd_args)
+
+/*
+ * Command for heapmemmp_open_by_addr
+ */
+#define CMD_HEAPMEMMP_OPENBYADDR _IOWR(IPC_IOC_MAGIC, \
+ HEAPMEMMP_OPENBYADDR, \
+ struct heapmemmp_cmd_args)
+
+/*
+ * Command for heapmemmp_close
+ */
+#define CMD_HEAPMEMMP_CLOSE _IOWR(IPC_IOC_MAGIC, \
+ HEAPMEMMP_CLOSE, \
+ struct heapmemmp_cmd_args)
+
+/*
+ * Command for heapmemmp_alloc
+ */
+#define CMD_HEAPMEMMP_ALLOC _IOWR(IPC_IOC_MAGIC, \
+ HEAPMEMMP_ALLOC, \
+ struct heapmemmp_cmd_args)
+
+/*
+ * Command for heapmemmp_free
+ */
+#define CMD_HEAPMEMMP_FREE _IOWR(IPC_IOC_MAGIC, \
+ HEAPMEMMP_FREE, \
+ struct heapmemmp_cmd_args)
+
+/*
+ * Command for heapmemmp_shared_mem_req
+ */
+#define CMD_HEAPMEMMP_SHAREDMEMREQ _IOWR(IPC_IOC_MAGIC, \
+ HEAPMEMMP_SHAREDMEMREQ, \
+ struct heapmemmp_cmd_args)
+
+/*
+ * Command for heapmemmp_get_stats
+ */
+#define CMD_HEAPMEMMP_GETSTATS _IOWR(IPC_IOC_MAGIC, \
+ HEAPMEMMP_GETSTATS, \
+ struct heapmemmp_cmd_args)
+
+/*
+ * Command for heapmemmp_get_extended_stats
+ */
+#define CMD_HEAPMEMMP_GETEXTENDEDSTATS _IOWR(IPC_IOC_MAGIC, \
+ HEAPMEMMP_GETEXTENDEDSTATS, \
+ struct heapmemmp_cmd_args)
+
+/*
+ * Command for heapmemmp_restore
+ */
+#define CMD_HEAPMEMMP_RESTORE _IOWR(IPC_IOC_MAGIC, \
+ HEAPMEMMP_RESTORE, \
+ struct heapmemmp_cmd_args)
+
+
+/*
+ * Command arguments for heapmem
+ */
+union heapmemmp_arg {
+ struct {
+ struct heapmemmp_params *params;
+ } params_init;
+
+ struct {
+ struct heapmemmp_config *config;
+ } get_config;
+
+ struct {
+ struct heapmemmp_config *config;
+ } setup;
+
+ struct {
+ void *handle;
+ struct heapmemmp_params *params;
+ u32 name_len;
+ u32 *shared_addr_srptr;
+ u32 *shared_buf_srptr;
+ void *knl_gate;
+ } create;
+
+ struct {
+ void *handle;
+ } delete;
+
+ struct {
+ void *handle;
+ char *name;
+ u32 name_len;
+ } open;
+
+ struct {
+ void *handle;
+ u32 *shared_addr_srptr;
+ } open_by_addr;
+
+ struct {
+ void *handle;
+ } close;
+
+ struct {
+ void *handle;
+ u32 size;
+ u32 align;
+ u32 *block_srptr;
+ } alloc;
+
+ struct {
+ void *handle;
+ u32 *block_srptr;
+ u32 size;
+ } free;
+
+ struct {
+ void *handle;
+ struct memory_stats *stats;
+ } get_stats;
+
+ struct {
+ void *handle;
+ } restore;
+
+ struct {
+ void *handle;
+ struct heapmemmp_extended_stats *stats;
+ } get_extended_stats;
+
+ struct {
+ struct heapmemmp_params *params;
+ u32 *shared_addr_srptr;
+ u32 bytes;
+ } shared_mem_req;
+};
+
+/*
+ * Command arguments for heapmem
+ */
+struct heapmemmp_cmd_args{
+ union heapmemmp_arg args;
+ s32 api_status;
+};
+
+/*
+ * This ioctl interface for heapmem module
+ */
+int heapmemmp_ioctl(struct inode *pinode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user);
+
+#endif /* _HEAPMEMMP_IOCTL_ */
diff --git a/arch/arm/plat-omap/include/syslink/host_os.h b/arch/arm/plat-omap/include/syslink/host_os.h
new file mode 100644
index 00000000000..2e2164f314f
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/host_os.h
@@ -0,0 +1,72 @@
+
+/*
+ * 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 <generated/autoconf.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <asm/irq.h>
+#include <linux/io.h>
+#include <linux/syscalls.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/device.h>
+#include <linux/vmalloc.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/pagemap.h>
+#include <asm/cacheflush.h>
+#include <linux/dma-mapping.h>
+
+/* ----------------------------------- 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
+
+#endif
diff --git a/arch/arm/plat-omap/include/syslink/igatempsupport.h b/arch/arm/plat-omap/include/syslink/igatempsupport.h
new file mode 100644
index 00000000000..b7c42a746a0
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/igatempsupport.h
@@ -0,0 +1,76 @@
+/*
+ * igatempsupport.h
+ *
+ * Interface implemented by all multiprocessor gates.
+ *
+ * Copyright (C) 2008-2009 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 _IGATEMPSUPPORT_H_
+#define _IGATEMPSUPPORT_H_
+
+
+/* Invalid Igate */
+#define IGATEMPSUPPORT_NULL (void *)0xFFFFFFFF
+
+/* Gates with this "quality" may cause the calling thread to block;
+ * i.e., suspend execution until another thread leaves the gate. */
+#define IGATEMPSUPPORT_Q_BLOCKING 1
+
+/* Gates with this "quality" allow other threads to preempt the thread
+ * that has already entered the gate. */
+#define IGATEMPSUPPORT_Q_PREEMPTING 2
+
+/* Object embedded in other Gate modules. (Inheritance) */
+#define IGATEMPSUPPORT_SUPERPARAMS \
+ u32 resource_id; \
+ bool open_flag; \
+ u16 region_id; \
+ void *shared_addr
+
+/* All other GateMP modules inherit this. */
+#define IGATEMPSUPPORT_INHERIT(X) \
+enum X##_local_protect { \
+ X##_LOCALPROTECT_NONE = 0, \
+ X##_LOCALPROTECT_INTERRUPT = 1, \
+ X##_LOCALPROTECT_TASKLET = 2, \
+ X##_LOCALPROTECT_THREAD = 3, \
+ X##_LOCALPROTECT_PROCESS = 4 \
+};
+
+/* Paramter initializer. */
+#define IGATEMPSUPPORT_PARAMSINTIALIZER(x) \
+ do { \
+ (x)->resource_id = 0; \
+ (x)->open_flag = true; \
+ (x)->region_id = 0; \
+ (x)->shared_addr = NULL; \
+ } while (0)
+
+enum igatempsupport_local_protect {
+ IGATEMPSUPPORT_LOCALPROTECT_NONE = 0,
+ IGATEMPSUPPORT_LOCALPROTECT_INTERRUPT = 1,
+ IGATEMPSUPPORT_LOCALPROTECT_TASKLET = 2,
+ IGATEMPSUPPORT_LOCALPROTECT_THREAD = 3,
+ IGATEMPSUPPORT_LOCALPROTECT_PROCESS = 4
+};
+
+struct igatempsupport_params {
+ u32 resource_id;
+ bool open_flag;
+ u16 region_id;
+ void *shared_addr;
+};
+
+
+#endif /* ifndef __IGATEMPSUPPORT_H__ */
diff --git a/arch/arm/plat-omap/include/syslink/igateprovider.h b/arch/arm/plat-omap/include/syslink/igateprovider.h
new file mode 100644
index 00000000000..c4ac4ab91c9
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/igateprovider.h
@@ -0,0 +1,123 @@
+/*
+ * igateprovider.h
+ *
+ * Interface implemented by all gate providers.
+ *
+ * Copyright (C) 2008-2009 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.
+ *
+ */
+/** ============================================================================
+ * Gates are used serialize access to data structures that are used by more
+ * than one thread.
+ *
+ * Gates are responsible for ensuring that only one out of multiple threads
+ * can access a data structure at a time. There
+ * are important scheduling latency and performance considerations that
+ * affect the "type" of gate used to protect each data structure. For
+ * example, the best way to protect a shared counter is to simply disable
+ * all interrupts before the update and restore the interrupt state after
+ * the update; disabling all interrupts prevents all thread switching, so
+ * the update is guaranteed to be "atomic". Although highly efficient, this
+ * method of creating atomic sections causes serious system latencies when
+ * the time required to update the data structure can't be bounded.
+ *
+ * For example, a memory manager's list of free blocks can grow indefinitely
+ * long during periods of high fragmentation. Searching such a list with
+ * interrupts disabled would cause system latencies to also become unbounded.
+ * In this case, the best solution is to provide a gate that suspends the
+ * execution of threads that try to enter a gate that has already been
+ * entered; i.e., the gate "blocks" the thread until the thread
+ * already in the gate leaves. The time required to enter and leave the
+ * gate is greater than simply enabling and restoring interrupts, but since
+ * the time spent within the gate is relatively large, the overhead caused by
+ * entering and leaving gates will not become a significant percentage of
+ * overall system time. More importantly, threads that do not need to
+ * access the shared data structure are completely unaffected by threads
+ * that do access it.
+ * ============================================================================
+ */
+
+
+#ifndef _IGATEPROVIDER_H_
+#define _IGATEPROVIDER_H_
+
+
+/* Invalid Igate */
+#define IGATEPROVIDER_NULL (struct igateprovider_object *)0xFFFFFFFF
+
+/* Gates with this "quality" may cause the calling thread to block;
+ * i.e., suspend execution until another thread leaves the gate. */
+#define IGateProvider_Q_BLOCKING 1
+
+/* Gates with this "quality" allow other threads to preempt the thread
+ * that has already entered the gate. */
+#define IGateProvider_Q_PREEMPTING 2
+
+/* Object embedded in other Gate modules. (Inheritance) */
+#define IGATEPROVIDER_SUPEROBJECT \
+ int *(*enter)(void *); \
+ void (*leave)(void *, int *)
+
+#define IGATEPROVIDER_OBJECTINITIALIZER(x, y) \
+ do { \
+ ((struct igateprovider_object *)(x))->enter = y##_enter; \
+ ((struct igateprovider_object *)(x))->leave = y##_leave; \
+ } while (0)
+
+
+/* Structure for generic gate instance */
+struct igateprovider_object {
+ IGATEPROVIDER_SUPEROBJECT;
+};
+
+
+/*
+ * Enter this gate
+ *
+ * Each gate provider can implement mutual exclusion using different
+ * algorithms; e.g., disabling all scheduling, disabling the scheduling
+ * of all threads below a specified "priority level", suspending the
+ * caller when the gate has been entered by another thread and
+ * re-enabling it when the the other thread leaves the gate. However,
+ * in all cases, after this method returns that caller has exclusive
+ * access to the data protected by this gate.
+ *
+ * A thread may reenter a gate without blocking or failing.
+ */
+static inline int *igateprovider_enter(struct igateprovider_object *handle)
+{
+ int *key = NULL;
+
+ if (handle != IGATEPROVIDER_NULL)
+ key = (handle->enter)((void *)handle);
+ return key;
+}
+
+
+/*
+ * Leave this gate
+ *
+ * This method is only called by threads that have previously entered
+ * this gate via `{@link #enter}`. After this method returns, the
+ * caller must not access the data structure protected by this gate
+ * (unless the caller has entered the gate more than once and other
+ * calls to `leave` remain to balance the number of previous
+ * calls to `enter`).
+ */
+static inline void igateprovider_leave(struct igateprovider_object *handle,
+ int *key)
+{
+ if (handle != IGATEPROVIDER_NULL)
+ (handle->leave)((void *)handle, key);
+}
+
+#endif /* ifndef _IGATEPROVIDER_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/iobject.h b/arch/arm/plat-omap/include/syslink/iobject.h
new file mode 100644
index 00000000000..4d0c1e6c7e0
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/iobject.h
@@ -0,0 +1,176 @@
+/*
+ * iobject.h
+ *
+ * Interface to provide object creation facilities.
+ *
+ * Copyright (C) 2008-2009 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 _IOBJECT_H_
+#define _IOBJECT_H_
+
+/* ObjType */
+enum ipc_obj_type {
+ IPC_OBJTYPE_CREATESTATIC = 0x1,
+ IPC_OBJTYPE_CREATESTATIC_REGION = 0x2,
+ IPC_OBJTYPE_CREATEDYNAMIC = 0x4,
+ IPC_OBJTYPE_CREATEDYNAMIC_REGION = 0x8,
+ IPC_OBJTYPE_OPENDYNAMIC = 0x10,
+ IPC_OBJTYPE_LOCAL = 0x20
+};
+
+
+/* Object embedded in other module's object */
+#define IOBJECT_SUPEROBJECT \
+ void *next; \
+ int status;
+
+/* Generic macro to define a create/delete function for a module */
+#define IOBJECT_CREATE0(MNAME) \
+static struct MNAME##_object *MNAME##_first_object;\
+\
+\
+void *MNAME##_create(const struct MNAME##_params *params)\
+{ \
+ int *key;\
+ struct MNAME##_object *obj = (struct MNAME##_object *)\
+ kmalloc(sizeof(struct MNAME##_object),\
+ GFP_KERNEL);\
+ if (!obj)\
+ return NULL;\
+ memset(obj, 0, sizeof(struct MNAME##_object));\
+ obj->status = MNAME##_instance_init(obj, params);\
+ if (obj->status == 0) { \
+ key = gate_enter_system();\
+ if (MNAME##_first_object == NULL) { \
+ MNAME##_first_object = obj;\
+ obj->next = NULL;\
+ } else { \
+ obj->next = MNAME##_first_object;\
+ MNAME##_first_object = obj;\
+ } \
+ gate_leave_system(key);\
+ } else { \
+ kfree(obj);\
+ obj = NULL;\
+ } \
+ return obj;\
+} \
+\
+\
+int MNAME##_delete(void **handle)\
+{ \
+ int *key;\
+ struct MNAME##_object *temp;\
+ struct MNAME##_object *obj;\
+ \
+ if (handle == NULL) \
+ return -EINVAL;\
+ if (*handle == NULL) \
+ return -EINVAL;\
+ obj = (struct MNAME##_object *)(*handle);\
+ key = gate_enter_system();\
+ if (obj == MNAME##_first_object) \
+ MNAME##_first_object = obj->next;\
+ else { \
+ temp = MNAME##_first_object;\
+ while (temp) { \
+ if (temp->next == obj) { \
+ temp->next = obj->next;\
+ break;\
+ } else { \
+ temp = temp->next;\
+ } \
+ } \
+ if (temp == NULL) { \
+ gate_leave_system(key);\
+ return -EINVAL;\
+ } \
+ } \
+ gate_leave_system(key);\
+ MNAME##_instance_finalize(obj, obj->status);\
+ kfree(obj);\
+ *handle = NULL;\
+ return 0;\
+}
+
+#define IOBJECT_CREATE1(MNAME, ARG) \
+static struct MNAME##_object *MNAME##_first_object;\
+\
+\
+void *MNAME##_create(ARG arg, const struct MNAME##_params *params)\
+{ \
+ int *key;\
+ struct MNAME##_object *obj = (struct MNAME##_object *) \
+ kmalloc(sizeof(struct MNAME##_object),\
+ GFP_KERNEL);\
+ if (!obj) \
+ return NULL;\
+ memset(obj, 0, sizeof(struct MNAME##_object));\
+ obj->status = MNAME##_instance_init(obj, arg, params);\
+ if (obj->status == 0) { \
+ key = gate_enter_system();\
+ if (MNAME##_first_object == NULL) { \
+ MNAME##_first_object = obj;\
+ obj->next = NULL;\
+ } else { \
+ obj->next = MNAME##_first_object;\
+ MNAME##_first_object = obj;\
+ } \
+ gate_leave_system(key);\
+ } else { \
+ kfree(obj);\
+ obj = NULL;\
+ } \
+ return obj;\
+} \
+\
+\
+int MNAME##_delete(void **handle)\
+{ \
+ int *key;\
+ struct MNAME##_object *temp;\
+ struct MNAME##_object *obj;\
+ \
+ if (handle == NULL) \
+ return -EINVAL;\
+ if (*handle == NULL) \
+ return -EINVAL;\
+ obj = (struct MNAME##_object *)(*handle);\
+ key = gate_enter_system();\
+ if (obj == MNAME##_first_object) \
+ MNAME##_first_object = obj->next;\
+ else { \
+ temp = MNAME##_first_object;\
+ while (temp) { \
+ if (temp->next == obj) { \
+ temp->next = obj->next;\
+ break;\
+ } else { \
+ temp = temp->next;\
+ } \
+ } \
+ if (temp == NULL) { \
+ gate_leave_system(key);\
+ return -EINVAL;\
+ } \
+ } \
+ gate_leave_system(key);\
+ MNAME##_instance_finalize(obj, obj->status);\
+ kfree(obj);\
+ *handle = NULL;\
+ return 0;\
+}
+
+
+#endif /* ifndef _IOBJECT_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/ipc.h b/arch/arm/plat-omap/include/syslink/ipc.h
new file mode 100644
index 00000000000..ceb239219b7
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/ipc.h
@@ -0,0 +1,189 @@
+/*
+ * sysmgr.h
+ *
+ * Defines for System manager.
+ *
+ * Copyright(C) 2009 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 _IPC_H_
+#define _IPC_H_
+
+
+/* Module headers */
+#include <multiproc.h>
+#include <gatepeterson.h>
+#include <sharedregion.h>
+#include <notify.h>
+#include <notify_ducatidriver.h>
+#include <heap.h>
+#include <heapbufmp.h>
+#include <heapmemmp.h>
+
+
+
+/* Unique module ID. */
+#define IPC_MODULEID (0xF086)
+
+
+/* =============================================================================
+ * Module Success and Failure codes
+ * =============================================================================
+ */
+/* The resource is still in use */
+#define IPC_S_BUSY 2
+
+/* The module has been already setup */
+#define IPC_S_ALREADYSETUP 1
+
+/* Operation is successful. */
+#define IPC_S_SUCCESS 0
+
+/* Generic failure. */
+#define IPC_E_FAIL -1
+
+/* Argument passed to function is invalid. */
+#define IPC_E_INVALIDARG -2
+
+/* Operation resulted in memory failure. */
+#define IPC_E_MEMORY -3
+
+/* The specified entity already exists. */
+#define IPC_E_ALREADYEXISTS -4
+
+/* Unable to find the specified entity. */
+#define IPC_E_NOTFOUND -5
+
+/* Operation timed out. */
+#define IPC_E_TIMEOUT -6
+
+/* Module is not initialized. */
+#define IPC_E_INVALIDSTATE -7
+
+/* A failure occurred in an OS-specific call */
+#define IPC_E_OSFAILURE -8
+
+/* Specified resource is not available */
+#define IPC_E_RESOURCE -9
+
+/* Operation was interrupted. Please restart the operation */
+#define IPC_E_RESTART -10
+
+
+/* =============================================================================
+ * Macros
+ * =============================================================================
+ */
+/* IPC_CONTROLCMD_LOADCALLBACK */
+#define IPC_CONTROLCMD_LOADCALLBACK (0xBABE0000)
+
+/* IPC_CONTROLCMD_STARTCALLBACK */
+#define IPC_CONTROLCMD_STARTCALLBACK (0xBABE0001)
+
+/* IPC_CONTROLCMD_STOPCALLBACK */
+#define IPC_CONTROLCMD_STOPCALLBACK (0xBABE0002)
+
+
+/* =============================================================================
+ * Enums & Structures
+ * =============================================================================
+ */
+/* the different options for processor synchronization */
+enum ipc_proc_sync {
+ IPC_PROCSYNC_NONE, /* don't do any processor sync */
+ IPC_PROCSYNC_PAIR, /* sync pair of processors in ipc_attach */
+ IPC_PROCSYNC_ALL /* sync all processors, done in ipc_start */
+};
+
+/* ipc configuration structure. */
+struct ipc_config {
+ enum ipc_proc_sync proc_sync;
+ /* the different options for processor synchronization */
+};
+
+/* ipc configuration structure. */
+struct ipc_params {
+ bool setup_messageq;
+ bool setup_notify;
+ bool setup_ipu_pm;
+ bool slave;
+ enum ipc_proc_sync proc_sync;
+};
+
+/* IPC events. */
+enum {
+ IPC_CLOSE = 0,
+ IPC_START = 1,
+ IPC_STOP = 2,
+};
+
+/* =============================================================================
+ * APIs
+ * =============================================================================
+ */
+/* Attach to remote processor */
+int ipc_attach(u16 remote_proc_id);
+
+/* Detach from the remote processor */
+int ipc_detach(u16 remote_proc_id);
+
+/* Reads the config entry from the config area. */
+int ipc_read_config(u16 remote_proc_id, u32 tag, void *cfg, u32 size);
+
+/* Reserves memory, creates default gatemp and heapmemmp */
+int ipc_start(void);
+
+/* Writes the config entry to the config area. */
+int ipc_write_config(u16 remote_proc_id, u32 tag, void *cfg, u32 size);
+
+/* Returns default configuration values for ipc. */
+void ipc_get_config(struct ipc_config *cfg_params);
+
+/* Sets up ipc for this processor. */
+int ipc_setup(const struct ipc_config *cfg_params);
+
+/* Destroys ipc for this processor. */
+int ipc_destroy(void);
+
+/* Creates a ipc. */
+int ipc_create(u16 proc_id, struct ipc_params *params);
+
+/* Function to control a Ipc instance for a slave */
+int ipc_control(u16 proc_id, u32 cmd_id, void *arg);
+
+/* Function to read configuration information from ipc module */
+int ipc_read_config(u16 remote_proc_id, u32 tag, void *cfg, u32 size);
+
+/* Function to write configuration information to ipc module */
+int ipc_write_config(u16 remote_proc_id, u32 tag, void *cfg, u32 size);
+
+/* Clears memory, deletes default gatemp and heapmemmp */
+int ipc_stop(void);
+
+/* IPC event notifications. */
+int ipc_notify_event(int event, void *data);
+
+/* Register for IPC events. */
+int ipc_register_notifier(struct notifier_block *nb);
+
+/* Un-register for IPC events. */
+int ipc_unregister_notifier(struct notifier_block *nb);
+
+/* check if ipc is in recovery state */
+#ifdef CONFIG_SYSLINK_RECOVERY
+bool ipc_recovering(void);
+#endif
+
+/* Indicate to schedule the recovery mechanism */
+void ipc_recover_schedule(void);
+
+#endif /* ifndef _IPC_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/ipc_ioctl.h b/arch/arm/plat-omap/include/syslink/ipc_ioctl.h
new file mode 100644
index 00000000000..7230baf4ef8
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/ipc_ioctl.h
@@ -0,0 +1,113 @@
+/*
+ * ipc_ioctl.h
+ *
+ * Base file for all TI OMAP IPC ioctl's.
+ * Linux-OMAP IPC has allocated base 0xEE with a range of 0x00-0xFF.
+ * (need to get the real one from open source maintainers)
+ *
+ * Copyright (C) 2008-2009 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 _IPC_IOCTL_H
+#define _IPC_IOCTL_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+
+#define IPC_IOC_MAGIC 0xE0
+#define IPC_IOC_BASE 2
+
+enum ipc_command_count {
+ MULTIPROC_CMD_NOS = 4,
+ NAMESERVER_CMD_NOS = 15,
+ HEAPBUFMP_CMD_NOS = 14,
+ SHAREDREGION_CMD_NOS = 13,
+ GATEMP_CMD_NOS = 13,
+ LISTMP_CMD_NOS = 19,
+ MESSAGEQ_CMD_NOS = 19,
+ IPC_CMD_NOS = 5,
+ SYSMEMMGR_CMD_NOS = 6,
+ HEAPMEMMP_CMD_NOS = 15,
+ NOTIFY_CMD_NOS = 18
+};
+
+enum ipc_command_ranges {
+ MULTIPROC_BASE_CMD = IPC_IOC_BASE,
+ MULTIPROC_END_CMD = (MULTIPROC_BASE_CMD + \
+ MULTIPROC_CMD_NOS - 1),
+
+ NAMESERVER_BASE_CMD = 10,
+ NAMESERVER_END_CMD = (NAMESERVER_BASE_CMD + \
+ NAMESERVER_CMD_NOS - 1),
+
+ HEAPBUFMP_BASE_CMD = 30,
+ HEAPBUFMP_END_CMD = (HEAPBUFMP_BASE_CMD + \
+ HEAPBUFMP_CMD_NOS - 1),
+
+ SHAREDREGION_BASE_CMD = 50,
+ SHAREDREGION_END_CMD = (SHAREDREGION_BASE_CMD + \
+ SHAREDREGION_CMD_NOS - 1),
+
+ GATEMP_BASE_CMD = 70,
+ GATEMP_END_CMD = (GATEMP_BASE_CMD + \
+ GATEMP_CMD_NOS - 1),
+
+ LISTMP_BASE_CMD = 90,
+ LISTMP_END_CMD = (LISTMP_BASE_CMD + \
+ LISTMP_CMD_NOS - 1),
+
+ MESSAGEQ_BASE_CMD = 110,
+ MESSAGEQ_END_CMD = (MESSAGEQ_BASE_CMD + \
+ MESSAGEQ_CMD_NOS - 1),
+
+ IPC_BASE_CMD = 130,
+ IPC_END_CMD = (IPC_BASE_CMD + \
+ IPC_CMD_NOS - 1),
+
+ SYSMEMMGR_BASE_CMD = 140,
+ SYSMEMMGR_END_CMD = (SYSMEMMGR_BASE_CMD + \
+ SYSMEMMGR_CMD_NOS - 1),
+
+ HEAPMEMMP_BASE_CMD = 150,
+ HEAPMEMMP_END_CMD = (HEAPMEMMP_BASE_CMD + \
+ HEAPMEMMP_CMD_NOS - 1),
+
+ NOTIFY_BASE_CMD = 170,
+ NOTIFY_END_CMD = (NOTIFY_BASE_CMD + \
+ NOTIFY_CMD_NOS - 1)
+};
+
+struct resource_info {
+ struct list_head res; /* Pointer to res entry */
+ unsigned int cmd; /* command */
+ void *data; /* Some private data */
+};
+
+/* Process Context */
+struct ipc_process_context {
+ /* List of Resources */
+ struct list_head resources;
+ spinlock_t res_lock;
+
+ struct ipc_device *dev;
+};
+
+void add_pr_res(struct ipc_process_context *pr_ctxt, unsigned int cmd,
+ void *data);
+
+void remove_pr_res(struct ipc_process_context *pr_ctxt,
+ struct resource_info *info);
+
+int ipc_ioc_router(u32 cmd, ulong arg, struct file *filp, bool user);
+
+#endif /* _IPC_IOCTL_H */
diff --git a/arch/arm/plat-omap/include/syslink/listmp.h b/arch/arm/plat-omap/include/syslink/listmp.h
new file mode 100644
index 00000000000..31d2429e851
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/listmp.h
@@ -0,0 +1,146 @@
+/*
+ * listmp.h
+ *
+ * The listmp module defines the shared memory doubly linked list.
+ *
+ * Copyright (C) 2008-2009 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 _LISTMP_H_
+#define _LISTMP_H_
+
+/* Standard headers */
+#include <linux/types.h>
+
+/* Utilities headers */
+#include <linux/list.h>
+/*#include <heap.h>*/
+
+/* =============================================================================
+ * All success and failure codes for the module
+ * =============================================================================
+ */
+/* The resource is still in use */
+#define LISTMP_S_BUSY 2
+
+/* The module has already been setup */
+#define LISTMP_S_ALREADYSETUP 1
+
+/* Operation is successful. */
+#define LISTMP_SUCCESS 0
+
+/* Generic failure. */
+#define LISTMP_E_FAIL -1
+
+/* Argument passed to a function is invalid. */
+#define LISTMP_E_INVALIDARG -2
+
+/* Memory allocation failed. */
+#define LISTMP_E_MEMORY -3
+
+/* The specified entity already exists. */
+#define LISTMP_E_ALREADYEXISTS -4
+
+/* Unable to find the specified entity. */
+#define LISTMP_E_NOTFOUND -5
+
+/* Operation timed out. */
+#define LISTMP_E_TIMEOUT -6
+
+/* Module is not initialized. */
+#define LISTMP_E_INVALIDSTATE -7
+
+/* A failure occurred in an OS-specific call */
+#define LISTMP_E_OSFAILURE -8
+
+/* Specified resource is not available */
+#define LISTMP_E_RESOURCE -9
+
+/* Operation was interrupted. Please restart the operation */
+#define LISTMP_E_RESTART -10
+
+
+/* =============================================================================
+ * Macros and types
+ * =============================================================================
+ */
+#define VOLATILE volatile
+
+/* Structure defining list element for the ListMP. */
+struct listmp_elem {
+ VOLATILE struct listmp_elem *next;
+ VOLATILE struct listmp_elem *prev;
+};
+
+/* Structure defining config parameters for the ListMP instances. */
+struct listmp_params {
+ /* gatemp instance for critical management of shared memory */
+ void *gatemp_handle;
+ void *shared_addr; /* physical address of the shared memory */
+ char *name; /* name of the instance */
+ u16 region_id; /* sharedregion id */
+};
+
+
+/* Function initializes listmp parameters */
+void listmp_params_init(struct listmp_params *params);
+
+/* Function to create an instance of ListMP */
+void *listmp_create(const struct listmp_params *params);
+
+/* Function to delete an instance of ListMP */
+int listmp_delete(void **listmp_handle_ptr);
+
+/* Function to open a previously created instance */
+int listmp_open(char *name, void **listmp_handle_ptr);
+
+/* Function to open a previously created instance */
+int listmp_open_by_addr(void *shared_addr, void **listmp_handle_ptr);
+
+/* Function to close a previously opened instance */
+int listmp_close(void **listmp_handle);
+
+/* Function to check if list is empty */
+bool listmp_empty(void *listmp_handle);
+
+/* Retrieves the GateMP handle associated with the ListMP instance. */
+void *listmp_get_gate(void *listmp_handle);
+
+/* Function to get head element from list */
+void *listmp_get_head(void *listmp_handle);
+
+/* Function to get tail element from list */
+void *listmp_get_tail(void *listmp_handle);
+
+/* Function to insert element into list */
+int listmp_insert(void *listmp_handle, struct listmp_elem *new_elem,
+ struct listmp_elem *cur_elem);
+
+/* Function to traverse to next element in list */
+void *listmp_next(void *listmp_handle, struct listmp_elem *elem);
+
+/* Function to traverse to prev element in list */
+void *listmp_prev(void *listmp_handle, struct listmp_elem *elem);
+
+/* Function to put head element into list */
+int listmp_put_head(void *listmp_handle, struct listmp_elem *elem);
+
+/* Function to put tail element into list */
+int listmp_put_tail(void *listmp_handle, struct listmp_elem *elem);
+
+/* Function to traverse to remove element from list */
+int listmp_remove(void *listmp_handle, struct listmp_elem *elem);
+
+/* Function to get shared memory requirement for the module */
+uint listmp_shared_mem_req(const struct listmp_params *params);
+
+#endif /* _LISTMP_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/listmp_ioctl.h b/arch/arm/plat-omap/include/syslink/listmp_ioctl.h
new file mode 100644
index 00000000000..e4fba2409bc
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/listmp_ioctl.h
@@ -0,0 +1,268 @@
+/*
+ * listmp_ioctl.h
+ *
+ * Definitions of listmp driver types and structures.
+ *
+ * Copyright (C) 2008-2009 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 _LISTMP_IOCTL_H_
+#define _LISTMP_IOCTL_H_
+
+/* Standard headers */
+#include <linux/types.h>
+
+/* Syslink headers */
+#include <ipc_ioctl.h>
+#include <listmp.h>
+#include <sharedregion.h>
+
+/* =============================================================================
+ * Macros and types
+ * =============================================================================
+ */
+/* Base command ID for listmp */
+#define LISTMP_IOC_MAGIC IPC_IOC_MAGIC
+enum listmp_drv_cmd {
+ LISTMP_GETCONFIG = LISTMP_BASE_CMD,
+ LISTMP_SETUP,
+ LISTMP_DESTROY,
+ LISTMP_PARAMS_INIT,
+ LISTMP_CREATE,
+ LISTMP_DELETE,
+ LISTMP_OPEN,
+ LISTMP_CLOSE,
+ LISTMP_ISEMPTY,
+ LISTMP_GETHEAD,
+ LISTMP_GETTAIL,
+ LISTMP_PUTHEAD,
+ LISTMP_PUTTAIL,
+ LISTMP_INSERT,
+ LISTMP_REMOVE,
+ LISTMP_NEXT,
+ LISTMP_PREV,
+ LISTMP_SHAREDMEMREQ,
+ LISTMP_OPENBYADDR
+};
+
+/* ----------------------------------------------------------------------------
+ * IOCTL command IDs for listmp
+ * ----------------------------------------------------------------------------
+ */
+/* Command for listmp_get_config */
+#define CMD_LISTMP_GETCONFIG _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_GETCONFIG, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_setup */
+#define CMD_LISTMP_SETUP _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_SETUP, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_destroy */
+#define CMD_LISTMP_DESTROY _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_DESTROY, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_params_init */
+#define CMD_LISTMP_PARAMS_INIT _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_PARAMS_INIT, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_create */
+#define CMD_LISTMP_CREATE _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_CREATE, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_delete */
+#define CMD_LISTMP_DELETE _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_DELETE, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_open */
+#define CMD_LISTMP_OPEN _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_OPEN, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_close */
+#define CMD_LISTMP_CLOSE _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_CLOSE, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_is_empty */
+#define CMD_LISTMP_ISEMPTY _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_ISEMPTY, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_get_head */
+#define CMD_LISTMP_GETHEAD _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_GETHEAD, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_get_tail */
+#define CMD_LISTMP_GETTAIL _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_GETTAIL, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_put_head */
+#define CMD_LISTMP_PUTHEAD _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_PUTHEAD, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_put_tail */
+#define CMD_LISTMP_PUTTAIL _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_PUTTAIL, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_insert */
+#define CMD_LISTMP_INSERT _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_INSERT, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_remove */
+#define CMD_LISTMP_REMOVE _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_REMOVE, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_next */
+#define CMD_LISTMP_NEXT _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_NEXT, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_prev */
+#define CMD_LISTMP_PREV _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_PREV, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_shared_mem_req */
+#define CMD_LISTMP_SHAREDMEMREQ _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_SHAREDMEMREQ, \
+ struct listmp_cmd_args)
+
+/* Command for listmp_open_by_addr */
+#define CMD_LISTMP_OPENBYADDR _IOWR(LISTMP_IOC_MAGIC, \
+ LISTMP_OPENBYADDR, \
+ struct listmp_cmd_args)
+
+/* Command arguments for listmp */
+struct listmp_cmd_args {
+ union {
+ struct {
+ struct listmp_params *params;
+ } params_init;
+
+ struct {
+ struct listmp_config *config;
+ } get_config;
+
+ struct {
+ struct listmp_config *config;
+ } setup;
+
+ struct {
+ void *listmp_handle;
+ struct listmp_params *params;
+ u32 name_len;
+ u32 shared_addr_srptr;
+ void *knl_gate;
+ } create;
+
+ struct {
+ void *listmp_handle;
+ } delete_instance;
+
+ struct {
+ void *listmp_handle;
+ u32 name_len;
+ char *name;
+ } open;
+
+ struct {
+ void *listmp_handle;
+ u32 shared_addr_srptr;
+ } open_by_addr;
+
+
+ struct {
+ void *listmp_handle;
+ } close;
+
+ struct {
+ void *listmp_handle;
+ bool is_empty;
+ } is_empty;
+
+ struct {
+ void *listmp_handle;
+ u32 *elem_srptr;
+ } get_head;
+
+ struct {
+ void *listmp_handle;
+ u32 *elem_srptr;
+ } get_tail;
+
+ struct {
+ void *listmp_handle;
+ u32 *elem_srptr;
+ } put_head;
+
+ struct {
+ void *listmp_handle;
+ u32 *elem_srptr;
+ } put_tail;
+
+ struct {
+ void *listmp_handle;
+ u32 *new_elem_srptr;
+ u32 *cur_elem_srptr;
+ } insert;
+
+ struct {
+ void *listmp_handle;
+ u32 *elem_srptr;
+ } remove;
+
+ struct {
+ void *listmp_handle;
+ u32 *elem_srptr;
+ u32 *next_elem_srptr;
+ } next;
+
+ struct {
+ void *listmp_handle;
+ u32 *elem_srptr;
+ u32 *prev_elem_srptr;
+ } prev;
+
+ struct {
+ struct listmp_params *params;
+ u32 bytes;
+ void *knl_gate;
+ u32 *shared_addr_srptr;
+ u32 name_len;
+ void *listmp_handle;
+ } shared_mem_req;
+ } args;
+
+ int api_status;
+};
+
+/* ----------------------------------------------------------------------------
+ * IOCTL functions for listmp module
+ * ----------------------------------------------------------------------------
+ */
+/* ioctl interface function for listmp */
+int listmp_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user);
+
+#endif /* _LISTMP_IOCTL_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/messageq.h b/arch/arm/plat-omap/include/syslink/messageq.h
new file mode 100644
index 00000000000..1bfdecd7444
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/messageq.h
@@ -0,0 +1,447 @@
+/*
+ * messageq.h
+ *
+ * The MessageQ module supports the structured sending and receiving of
+ * variable length messages. This module can be used for homogeneous or
+ * heterogeneous multi-processor messaging.
+ *
+ * Copyright (C) 2009 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 _MESSAGEQ_H_
+#define _MESSAGEQ_H_
+
+/* Standard headers */
+#include <linux/types.h>
+
+/* Utilities headers */
+#include <linux/list.h>
+
+/* Syslink headers */
+#include <listmp.h>
+
+/*!
+ * @def MESSAGEQ_MODULEID
+ * @brief Unique module ID.
+ */
+#define MESSAGEQ_MODULEID (0xded2)
+
+
+/* =============================================================================
+ * All success and failure codes for the module
+ * =============================================================================
+ */
+
+/*!
+ * @def MESSAGEQ_S_BUSY
+ * @brief The resource is still in use
+ */
+#define MESSAGEQ_S_BUSY 2
+
+/*!
+ * @def MESSAGEQ_S_ALREADYSETUP
+ * @brief The module has been already setup
+ */
+#define MESSAGEQ_S_ALREADYSETUP 1
+
+/*!
+ * @def MESSAGEQ_S_SUCCESS
+ * @brief Operation is successful.
+ */
+#define MESSAGEQ_S_SUCCESS 0
+
+/*!
+ * @def MESSAGEQ_E_FAIL
+ * @brief Operation is not successful.
+ */
+#define MESSAGEQ_E_FAIL -1
+
+/*!
+ * @def MESSAGEQ_E_INVALIDARG
+ * @brief There is an invalid argument.
+ */
+#define MESSAGEQ_E_INVALIDARG -2
+
+/*!
+ * @def MESSAGEQ_E_MEMORY
+ * @brief Operation resulted in memory failure.
+ */
+#define MESSAGEQ_E_MEMORY -3
+
+/*!
+ * @def MESSAGEQ_E_ALREADYEXISTS
+ * @brief The specified entity already exists.
+ */
+#define MESSAGEQ_E_ALREADYEXISTS -4
+
+/*!
+ * @def MESSAGEQ_E_NOTFOUND
+ * @brief Unable to find the specified entity.
+ */
+#define MESSAGEQ_E_NOTFOUND -5
+
+/*!
+ * @def MESSAGEQ_E_TIMEOUT
+ * @brief Operation timed out.
+ */
+#define MESSAGEQ_E_TIMEOUT -6
+
+/*!
+ * @def MESSAGEQ_E_INVALIDSTATE
+ * @brief Module is not initialized.
+ */
+#define MESSAGEQ_E_INVALIDSTATE -7
+
+/*!
+ * @def MESSAGEQ_E_OSFAILURE
+ * @brief A failure occurred in an OS-specific call
+ */
+#define MESSAGEQ_E_OSFAILURE -8
+
+/*!
+ * @def MESSAGEQ_E_RESOURCE
+ * @brief Specified resource is not available
+ */
+#define MESSAGEQ_E_RESOURCE -9
+
+/*!
+ * @def MESSAGEQ_E_RESTART
+ * @brief Operation was interrupted. Please restart the operation
+ */
+#define MESSAGEQ_E_RESTART -10
+
+/*!
+ * @def MESSAGEQ_E_INVALIDMSG
+ * @brief Operation is successful.
+ */
+#define MESSAGEQ_E_INVALIDMSG -11
+
+/*!
+ * @def MESSAGEQ_E_NOTOWNER
+ * @brief Not the owner
+ */
+#define MESSAGEQ_E_NOTOWNER -12
+
+/*!
+ * @def MESSAGEQ_E_REMOTEACTIVE
+ * @brief Operation is successful.
+ */
+#define MESSAGEQ_E_REMOTEACTIVE -13
+
+/*!
+ * @def MESSAGEQ_E_INVALIDHEAPID
+ * @brief Operation is successful.
+ */
+#define MESSAGEQ_E_INVALIDHEAPID -14
+
+/*!
+ * @def MESSAGEQ_E_INVALIDPROCID
+ * @brief Operation is successful.
+ */
+#define MESSAGEQ_E_INVALIDPROCID -15
+
+/*!
+ * @def MESSAGEQ_E_MAXREACHED
+ * @brief Operation is successful.
+ */
+#define MESSAGEQ_E_MAXREACHED -16
+
+/*!
+ * @def MESSAGEQ_E_UNREGISTEREDHEAPID
+ * @brief Operation is successful.
+ */
+#define MESSAGEQ_E_UNREGISTEREDHEAPID -17
+
+/*!
+ * @def MESSAGEQ_E_CANNOTFREESTATICMSG
+ * @brief Operation is successful.
+ */
+#define MESSAGEQ_E_CANNOTFREESTATICMSG -18
+/*!
+ * @def MESSAGEQ_E_UNBLOCKED
+ * @brief The resource is now unblocked
+ */
+#define MESSAGEQ_E_UNBLOCKED -20
+
+
+/* =============================================================================
+ * Macros and types
+ * =============================================================================
+ */
+/*!
+ * @brief Mask to extract version setting
+ */
+#define MESSAGEQ_HEADERVERSION 0x2000u
+
+/*! Mask to extract Trace setting */
+#define MESSAGEQ_TRACEMASK (uint) 0x1000
+
+/*! Shift for Trace setting */
+#define MESSAGEQ_TRACESHIFT (uint) 12
+
+/*!
+ * @brief Mask to extract priority setting
+ */
+#define MESSAGEQ_PRIORITYMASK 0x3u
+
+/*!
+ * Used as the timeout value to specify wait forever
+ */
+#define MESSAGEQ_FOREVER (~((u32) 0))
+
+/*!
+ * Invalid message id
+ */
+#define MESSAGEQ_INVALIDMSGID 0xFFFF
+
+/*!
+ * Invalid message queue
+ */
+#define MESSAGEQ_INVALIDMESSAGEQ 0xFFFF
+
+/*!
+ * Indicates that if maximum number of message queues are already created,
+ * should allow growth to create additional Message Queue.
+ */
+#define MESSAGEQ_ALLOWGROWTH (~((u32) 0))
+
+/*!
+ * Number of types of priority queues for each transport
+ */
+#define MESSAGEQ_NUM_PRIORITY_QUEUES 2
+
+
+/* =============================================================================
+ * Structures & Enums
+ * =============================================================================
+ */
+/*!
+ * Message priority
+ */
+enum messageq_priority {
+ MESSAGEQ_NORMALPRI = 0,
+ /*!< Normal priority message */
+ MESSAGEQ_HIGHPRI = 1,
+ /*!< High priority message */
+ MESSAGEQ_RESERVEDPRI = 2,
+ /*!< Reserved value for message priority */
+ MESSAGEQ_URGENTPRI = 3
+ /*!< Urgent priority message */
+};
+
+/*! Structure which defines the first field in every message */
+struct msgheader {
+ u32 reserved0;
+ /*!< Reserved field */
+ u32 reserved1;
+ /*!< Reserved field */
+ u32 msg_size;
+ /*!< Size of the message (including header) */
+ u16 flags;
+ /*!< Flags */
+ u16 msg_id;
+ /*!< Maximum length for Message queue names */
+ u16 dst_id;
+ /*!< Maximum length for Message queue names */
+ u16 dst_proc;
+ /*!< Maximum length for Message queue names */
+ u16 reply_id;
+ /*!< Maximum length for Message queue names */
+ u16 reply_proc;
+ /*!< Maximum length for Message queue names */
+ u16 src_proc;
+ /*!< Maximum length for Message queue names */
+ u16 heap_id;
+ /*!< Maximum length for Message queue names */
+ u16 seq_num;
+ /*!< sequence number */
+ u32 reserved;
+ /*!< Reserved field */
+};
+
+/*! Structure which defines the first field in every message */
+#define messageq_msg struct msgheader *
+/*typedef struct msgheader *messageq_msg;*/
+
+
+/*!
+ * @brief Structure defining config parameters for the MessageQ Buf module.
+ */
+struct messageq_config {
+ bool trace_flag;
+ /*!< Trace Flag
+ * This flag allows the configuration of the default module trace
+ * settings.
+ */
+
+ u16 num_heaps;
+ /*!< Number of heapIds in the system
+ * This allows MessageQ to pre-allocate the heaps table.
+ * The heaps table is used when registering heaps.
+ * The default is 1 since generally all systems need at least one heap.
+ * There is no default heap, so unless the system is only using
+ * staticMsgInit, the application must register a heap.
+ */
+
+ u32 max_runtime_entries;
+ /*!
+ * Maximum number of MessageQs that can be dynamically created
+ */
+
+ u32 max_name_len;
+ /*!< Maximum length for Message queue names */
+};
+
+struct messageq_params {
+ void *synchronizer;
+ /*!< Synchronizer instance used to signal IO completion
+ *
+ * The synchronizer is used in the #MessageQ_put and #MessageQ_get calls.
+ * The synchronizer signal is called as part of the #MessageQ_put call.
+ * The synchronizer waits in the #MessageQ_get if there are no messages
+ * present.
+ */
+};
+
+/* =============================================================================
+ * APIs
+ * =============================================================================
+ */
+/* Functions to get the configuration for messageq setup */
+void messageq_get_config(struct messageq_config *cfg);
+
+/* Function to setup the MessageQ module. */
+int messageq_setup(const struct messageq_config *cfg);
+
+/* Function to destroy the MessageQ module. */
+int messageq_destroy(void);
+
+/* Returns the amount of shared memory used by one transport instance.
+ *
+ * The MessageQ module itself does not use any shared memory but the
+ * underlying transport may use some shared memory.
+ */
+uint messageq_shared_mem_req(void *shared_addr);
+
+/* Calls the SetupProxy function to setup the MessageQ transports. */
+int messageq_attach(u16 remote_proc_id, void *shared_addr);
+
+/* Calls the SetupProxy function to detach the MessageQ transports. */
+int messageq_detach(u16 remote_proc_id);
+
+/* Initialize this config-params structure with supplier-specified
+ * defaults before instance creation.
+ */
+void messageq_params_init(struct messageq_params *params);
+
+/* Create a message queue */
+void *messageq_create(char *name, const struct messageq_params *params);
+
+/* Deletes a instance of MessageQ module. */
+int messageq_delete(void **messageq_handleptr);
+
+/* Open a message queue */
+int messageq_open(char *name, u32 *queue_id);
+
+/* Close an opened message queue handle */
+int messageq_close(u32 *queue_id);
+
+/* Allocates a message from the heap */
+messageq_msg messageq_alloc(u16 heapId, u32 size);
+
+/* Frees a message back to the heap */
+int messageq_free(messageq_msg msg);
+
+/* Initializes a message not obtained from MessageQ_alloc */
+void messageq_static_msg_init(messageq_msg msg, u32 size);
+
+/* Place a message onto a message queue */
+int messageq_put(u32 queueId, messageq_msg msg);
+
+/* Gets a message for a message queue and blocks if the queue is empty */
+int messageq_get(void *messageq_handle, messageq_msg *msg, u32 timeout);
+
+/* Register a heap with MessageQ */
+int messageq_register_heap(void *heap_handle, u16 heap_id);
+
+/* Unregister a heap with MessageQ */
+int messageq_unregister_heap(u16 heapId);
+
+/* Returns the number of messages in a message queue */
+int messageq_count(void *messageq_handle);
+
+/* Get the proc Id of the message. */
+u16 messageq_get_proc_id(void *messageq_handle);
+
+/* Get the queue Id of the message. */
+u32 messageq_get_queue_id(void *messageq_handle);
+
+/* Set the destination queue of the message. */
+void messageq_set_reply_queue(void *messageq_handle, messageq_msg msg);
+
+/* Set the tracing of a message */
+void messageq_set_msg_trace(messageq_msg msg, bool trace_flag);
+
+/*
+ * Functions to set Message properties
+ */
+/*!
+ * @brief Returns the MessageQ_Queue handle of the destination
+ * message queue for the specified message.
+ */
+u32 messageq_get_dst_queue(messageq_msg msg);
+
+/*!
+ * @brief Returns the message ID of the specified message.
+ */
+u16 messageq_get_msg_id(messageq_msg msg);
+
+/*!
+ * @brief Returns the size of the specified message.
+ */
+u32 messageq_get_msg_size(messageq_msg msg);
+
+/*!
+ * @brief Gets the message priority of a message
+ */
+u32 messageq_get_msg_pri(messageq_msg msg);
+
+/*!
+ * @brief Returns the MessageQ_Queue handle of the destination
+ * message queue for the specified message.
+ */
+u32 messageq_get_reply_queue(messageq_msg msg);
+
+/*!
+ * @brief Sets the message ID in the specified message.
+ */
+void messageq_set_msg_id(messageq_msg msg, u16 msg_id);
+/*!
+ * @brief Sets the message priority in the specified message.
+ */
+void messageq_set_msg_pri(messageq_msg msg, u32 priority);
+
+/* =============================================================================
+ * APIs called internally by MessageQ transports
+ * =============================================================================
+ */
+/* Register a transport with MessageQ */
+int messageq_register_transport(void *imessageq_transport_handle,
+ u16 proc_id, u32 priority);
+
+/* Unregister a transport with MessageQ */
+void messageq_unregister_transport(u16 proc_id, u32 priority);
+
+/* Unblock messageq to prevent waiting forever */
+int messageq_unblock(void *messageq_handle);
+
+#endif /* _MESSAGEQ_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/messageq_ioctl.h b/arch/arm/plat-omap/include/syslink/messageq_ioctl.h
new file mode 100644
index 00000000000..cbb0087fc0b
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/messageq_ioctl.h
@@ -0,0 +1,266 @@
+/*
+ * messageq_ioctl.h
+ *
+ * Definitions of messageq driver types and structures.
+ *
+ * Copyright (C) 2008-2009 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 _MESSAGEQ_IOCTL_H_
+#define _MESSAGEQ_IOCTL_H_
+
+/* Standard headers */
+#include <linux/types.h>
+
+/* Syslink headers */
+#include <ipc_ioctl.h>
+#include <messageq.h>
+#include <heap.h>
+#include <sharedregion.h>
+
+/* =============================================================================
+ * Macros and types
+ * =============================================================================
+ */
+#define MESSAGEQ_IOC_MAGIC IPC_IOC_MAGIC
+enum messageq_drv_cmd {
+ MESSAGEQ_GETCONFIG = MESSAGEQ_BASE_CMD,
+ MESSAGEQ_SETUP,
+ MESSAGEQ_DESTROY,
+ MESSAGEQ_PARAMS_INIT,
+ MESSAGEQ_CREATE,
+ MESSAGEQ_DELETE,
+ MESSAGEQ_OPEN,
+ MESSAGEQ_CLOSE,
+ MESSAGEQ_COUNT,
+ MESSAGEQ_ALLOC,
+ MESSAGEQ_FREE,
+ MESSAGEQ_PUT,
+ MESSAGEQ_REGISTERHEAP,
+ MESSAGEQ_UNREGISTERHEAP,
+ MESSAGEQ_ATTACH,
+ MESSAGEQ_DETACH,
+ MESSAGEQ_GET,
+ MESSAGEQ_SHAREDMEMREQ,
+ MESSAGEQ_UNBLOCK
+};
+
+/* ----------------------------------------------------------------------------
+ * IOCTL command IDs for messageq
+ * ----------------------------------------------------------------------------
+ */
+/* Base command ID for messageq */
+#define MESSAGEQ_BASE_CMD 0x0
+
+/* Command for messageq_get_config */
+#define CMD_MESSAGEQ_GETCONFIG \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_GETCONFIG, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_setup */
+#define CMD_MESSAGEQ_SETUP \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_SETUP, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_destroy */
+#define CMD_MESSAGEQ_DESTROY \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_DESTROY, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_params_init */
+#define CMD_MESSAGEQ_PARAMS_INIT \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_PARAMS_INIT, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_create */
+#define CMD_MESSAGEQ_CREATE \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_CREATE, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_delete */
+#define CMD_MESSAGEQ_DELETE \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_DELETE, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_open */
+#define CMD_MESSAGEQ_OPEN \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_OPEN, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_close */
+#define CMD_MESSAGEQ_CLOSE \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_CLOSE, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_count */
+#define CMD_MESSAGEQ_COUNT \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_COUNT, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_alloc */
+#define CMD_MESSAGEQ_ALLOC \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_ALLOC, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_free */
+#define CMD_MESSAGEQ_FREE \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_FREE, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_put */
+#define CMD_MESSAGEQ_PUT \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_PUT, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_unblock */
+#define CMD_MESSAGEQ_UNBLOCK \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_UNBLOCK, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_register_heap */
+#define CMD_MESSAGEQ_REGISTERHEAP \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_REGISTERHEAP, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_unregister_heap */
+#define CMD_MESSAGEQ_UNREGISTERHEAP \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_UNREGISTERHEAP, \
+ struct messageq_cmd_args)
+
+
+/* Command for messageq_attach */
+#define CMD_MESSAGEQ_ATTACH \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_ATTACH, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_detach */
+#define CMD_MESSAGEQ_DETACH \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_DETACH, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_get */
+#define CMD_MESSAGEQ_GET \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_GET, \
+ struct messageq_cmd_args)
+
+/* Command for messageq_sharedmem_req */
+#define CMD_MESSAGEQ_SHAREDMEMREQ \
+ _IOWR(MESSAGEQ_IOC_MAGIC, MESSAGEQ_SHAREDMEMREQ, \
+ struct messageq_cmd_args)
+
+/* Command arguments for messageq */
+struct messageq_cmd_args {
+ union {
+ struct {
+ void *messageq_handle;
+ struct messageq_params *params;
+ } params_init;
+
+ struct {
+ struct messageq_config *config;
+ } get_config;
+
+ struct {
+ struct messageq_config *config;
+ } setup;
+
+ struct {
+ void *messageq_handle;
+ char *name;
+ struct messageq_params *params;
+ u32 name_len;
+ u32 queue_id;
+ } create;
+
+ struct {
+ void *messageq_handle;
+ } delete_messageq;
+
+ struct {
+ char *name;
+ u32 queue_id;
+ u32 name_len;
+ } open;
+
+ struct {
+ u32 queue_id;
+ } close;
+
+ struct {
+ void *messageq_handle;
+ u32 timeout;
+ u32 *msg_srptr;
+ } get;
+
+ struct {
+ void *messageq_handle;
+ int count;
+ } count;
+
+ struct {
+ u16 heap_id;
+ u32 size;
+ u32 *msg_srptr;
+ } alloc;
+
+ struct {
+ u32 *msg_srptr;
+ } free;
+
+ struct {
+ u32 queue_id;
+ u32 *msg_srptr;
+ } put;
+
+ struct {
+ void *heap_handle;
+ u16 heap_id;
+ } register_heap;
+
+ struct {
+ u16 heap_id;
+ } unregister_heap;
+
+ struct {
+ u32 *shared_addr_srptr;
+ uint mem_req;
+ } shared_mem_req;
+
+ struct {
+ u16 remote_proc_id;
+ u32 *shared_addr_srptr;
+ } attach;
+
+ struct {
+ u16 remote_proc_id;
+ } detach;
+
+ struct {
+ void *messageq_handle;
+ } unblock;
+
+ } args;
+
+ int api_status;
+};
+
+/* ----------------------------------------------------------------------------
+ * IOCTL functions for messageq module
+ * ----------------------------------------------------------------------------
+ */
+/*
+ * ioctl interface function for messageq
+ */
+int messageq_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user);
+
+#endif /* _MESSAGEQ_IOCTL_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/multiproc.h b/arch/arm/plat-omap/include/syslink/multiproc.h
new file mode 100644
index 00000000000..4d14e8c193c
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/multiproc.h
@@ -0,0 +1,89 @@
+/*
+* multiproc.h
+*
+* Many multi-processor modules have the concept of processor id. multiproc
+* centeralizes the processor id management.
+*
+* Copyright (C) 2008-2009 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 _MULTIPROC_H_
+#define _MULTIPROC_H_
+
+#include <linux/types.h>
+
+
+#define VOLATILE volatile
+
+/*
+ * Unique module ID
+ */
+#define MULTIPROC_MODULEID (u16)0xB522
+
+/* Macro to define invalid processor id */
+#define MULTIPROC_INVALIDID ((u16)0xFFFF)
+
+/*
+ * Maximum number of processors in the system
+ * OMAP4 has 4 processors in single core.
+ */
+#define MULTIPROC_MAXPROCESSORS 4
+
+/*
+ * Max name length for a processor name
+ */
+#define MULTIPROC_MAXNAMELENGTH 32
+
+/*
+ * Configuration structure for multiproc module
+ */
+struct multiproc_config {
+ s32 num_processors; /* Number of procs for particular system */
+ char name_list[MULTIPROC_MAXPROCESSORS][MULTIPROC_MAXNAMELENGTH];
+ /* Name List for processors in the system */
+ u16 id; /* Local Proc ID. This needs to be set before calling any
+ other APIs */
+};
+
+/* =============================================================================
+ * APIs
+ * =============================================================================
+ */
+
+/* Function to get the default configuration for the multiproc module. */
+void multiproc_get_config(struct multiproc_config *cfg);
+
+/* Function to setup the multiproc Module */
+s32 multiproc_setup(struct multiproc_config *cfg);
+
+/* Function to destroy the multiproc module */
+s32 multiproc_destroy(void);
+
+/* Function to set local processor Id */
+int multiproc_set_local_id(u16 proc_id);
+
+/* Function to get processor id from processor name. */
+u16 multiproc_get_id(const char *proc_name);
+
+/* Function to get name from processor id. */
+char *multiproc_get_name(u16 proc_id);
+
+/* Function to get number of processors in the system. */
+u16 multiproc_get_num_processors(void);
+
+/* Return Id of current processor */
+u16 multiproc_self(void);
+
+/* Determines the offset for any two processors. */
+u32 multiproc_get_slot(u16 remote_proc_id);
+
+#endif /* _MULTIPROC_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/multiproc_ioctl.h b/arch/arm/plat-omap/include/syslink/multiproc_ioctl.h
new file mode 100644
index 00000000000..f641f22d13d
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/multiproc_ioctl.h
@@ -0,0 +1,94 @@
+/*
+* multiproc_ioctl.h
+*
+* This provides the ioctl interface for multiproc module
+*
+* Copyright (C) 2008-2009 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 _MULTIPROC_IOCTL_H_
+#define _MULTIPROC_IOCTL_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#include <ipc_ioctl.h>
+#include <multiproc.h>
+
+enum CMD_MULTIPROC {
+ MULTIPROC_SETUP = MULTIPROC_BASE_CMD,
+ MULTIPROC_DESTROY,
+ MULTIPROC_GETCONFIG,
+ MULTIPROC_SETLOCALID
+};
+
+/* ----------------------------------------------------------------------------
+ * IOCTL command IDs for MultiProc
+ * ----------------------------------------------------------------------------
+ */
+
+/*
+ * Command for multiproc_setup
+ */
+#define CMD_MULTIPROC_SETUP _IOWR(IPC_IOC_MAGIC, MULTIPROC_SETUP, \
+ struct multiproc_cmd_args)
+
+/*
+ * Command for multiproc_destroy
+ */
+#define CMD_MULTIPROC_DESTROY _IOWR(IPC_IOC_MAGIC, MULTIPROC_DESTROY, \
+ struct multiproc_cmd_args)
+
+/*
+ * Command for multiproc_get_config
+ */
+#define CMD_MULTIPROC_GETCONFIG _IOWR(IPC_IOC_MAGIC, MULTIPROC_GETCONFIG, \
+ struct multiproc_cmd_args)
+
+/*
+ * Command for multiproc_set_local_id
+ */
+#define CMD_MULTIPROC_SETLOCALID _IOWR(IPC_IOC_MAGIC, MULTIPROC_SETLOCALID, \
+ struct multiproc_cmd_args)
+
+/*
+ * Command arguments for multiproc
+ */
+union multiproc_arg {
+ struct {
+ struct multiproc_config *config;
+ } get_config;
+
+ struct {
+ struct multiproc_config *config;
+ } setup;
+
+ struct {
+ u16 id;
+ } set_local_id;
+};
+
+/*
+ * Command arguments for multiproc
+ */
+struct multiproc_cmd_args {
+ union multiproc_arg args;
+ s32 api_status;
+};
+
+/*
+ * This ioctl interface for multiproc module
+ */
+int multiproc_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user);
+
+#endif /* _MULTIPROC_IOCTL_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/nameserver.h b/arch/arm/plat-omap/include/syslink/nameserver.h
new file mode 100644
index 00000000000..3aeee242bc3
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/nameserver.h
@@ -0,0 +1,157 @@
+/*
+ * nameserver.h
+ *
+ * The nameserver module manages local name/value pairs that
+ * enables an application and other modules to store and retrieve
+ * values based on a name.
+ *
+ * Copyright (C) 2008-2009 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 _NAMESERVER_H_
+#define _NAMESERVER_H_
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+/*
+ * NAMESERVER_MODULEID
+ * Unique module ID
+ */
+#define NAMESERVER_MODULEID (0xF414)
+
+struct nameserver_config {
+ u32 reserved;
+};
+
+/*
+ * Instance config-params object.
+ */
+struct nameserver_params {
+ u32 max_runtime_entries;
+ void *table_heap; /* Table is placed into a section on dyn creates */
+ bool check_existing; /* Prevents duplicate entry add in to the table */
+ u32 max_value_len; /* Length, in MAUs, of the value field */
+ u16 max_name_len; /* Length, in MAUs, of name field */
+};
+
+
+/*
+ * Function to get the default configuration for the nameserver module
+ */
+void nameserver_get_config(struct nameserver_config *cfg);
+
+/*
+ * Function to setup the nameserver module
+ */
+int nameserver_setup(void);
+
+/*
+ * Function to destroy the nameserver module
+ */
+int nameserver_destroy(void);
+
+/*
+ * Function to construct a name server.
+ */
+void nameserver_construct(void *object, const char *name,
+ const struct nameserver_params *params);
+
+/*
+ * Function to destruct a name server
+ */
+void nameserver_destruct(void *object);
+
+/*
+ * Function to register a remote driver
+ */
+int nameserver_register_remote_driver(void *handle, u16 proc_id);
+
+/*
+ * Function to unregister a remote driver
+ */
+int nameserver_unregister_remote_driver(u16 proc_id);
+
+/*
+ * Determines if a remote driver is registered for the specified id.
+ */
+bool nameserver_is_registered(u16 proc_id);
+
+/*
+ * Function to initialize the parameter structure
+ */
+void nameserver_params_init(struct nameserver_params *params);
+
+/*
+ * Function to create a name server
+ */
+void *nameserver_create(const char *name,
+ const struct nameserver_params *params);
+
+/*
+ * Function to delete a name server
+ */
+int nameserver_delete(void **handle);
+
+/*
+ * Function to handle for a name
+ */
+void *nameserver_get_handle(const char *name);
+
+/*
+ * Function to add a variable length value into the local table
+ */
+void *nameserver_add(void *handle, const char *name, void *buf, u32 len);
+
+/*
+ * Function to add a 32 bit value into the local table
+ */
+void *nameserver_add_uint32(void *handle, const char *name, u32 value);
+
+/*
+ * Function to retrieve the value portion of a name/value pair
+ */
+int nameserver_get(void *handle, const char *name, void *buf, u32 *len,
+ u16 procId[]);
+
+/*
+ * Function to retrieve a 32-bit value of a name/value pair
+ */
+int nameserver_get_uint32(void *handle, const char *name, void *buf,
+ u16 procId[]);
+
+/*
+ * Function to get the value portion of a name/value pair from local table
+ */
+int nameserver_get_local(void *handle, const char *name, void *buf, u32 *len);
+
+/*
+ * Function to retrieve a 32-bit value from the local name/value table
+ */
+int nameserver_get_local_uint32(void *handle, const char *name, void *buf);
+
+/*
+ * Function to match the name
+ */
+int nameserver_match(void *handle, const char *name, u32 *value);
+
+/*
+ * Function to removes a value/pair
+ */
+int nameserver_remove(void *handle, const char *name);
+
+/*
+ * Function to remove an entry from the table
+ */
+int nameserver_remove_entry(void *handle, void *entry);
+
+#endif /* _NAMESERVER_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/nameserver_ioctl.h b/arch/arm/plat-omap/include/syslink/nameserver_ioctl.h
new file mode 100644
index 00000000000..5111f46f79a
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/nameserver_ioctl.h
@@ -0,0 +1,261 @@
+/*
+* nameserver_ioctl.h
+*
+* This provides the ioctl interface for nameserver module
+*
+* Copyright (C) 2008-2009 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 _NAMESERVER_IOCTL_H_
+#define _NAMESERVER_IOCTL_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#include <ipc_ioctl.h>
+#include <nameserver.h>
+
+enum CMD_NAMESERVER {
+ NAMESERVER_SETUP = NAMESERVER_BASE_CMD,
+ NAMESERVER_DESTROY,
+ NAMESERVER_PARAMS_INIT,
+ NAMESERVER_CREATE,
+ NAMESERVER_DELETE,
+ NAMESERVER_ADD,
+ NAMESERVER_ADDUINT32,
+ NAMESERVER_GET,
+ NAMESERVER_GETLOCAL,
+ NAMESERVER_MATCH,
+ NAMESERVER_REMOVE,
+ NAMESERVER_REMOVEENTRY,
+ NAMESERVER_GETHANDLE,
+ NAMESERVER_ISREGISTERED,
+ NAMESERVER_GETCONFIG
+};
+
+/*
+ * IOCTL command IDs for nameserver
+ *
+ */
+/*
+ * Command for nameserver_setup
+ */
+#define CMD_NAMESERVER_SETUP _IOWR(IPC_IOC_MAGIC, \
+ NAMESERVER_SETUP, \
+ struct nameserver_cmd_args)
+
+/*
+ * Command for nameserver_destroy
+ */
+#define CMD_NAMESERVER_DESTROY _IOWR(IPC_IOC_MAGIC, \
+ NAMESERVER_DESTROY, \
+ struct nameserver_cmd_args)
+
+/*
+ * Command for nameserver_params_init
+ */
+#define CMD_NAMESERVER_PARAMS_INIT _IOWR(IPC_IOC_MAGIC, \
+ NAMESERVER_PARAMS_INIT, \
+ struct nameserver_cmd_args)
+
+/*
+ * Command for nameserver_create
+ */
+#define CMD_NAMESERVER_CREATE _IOWR(IPC_IOC_MAGIC, \
+ NAMESERVER_CREATE, \
+ struct nameserver_cmd_args)
+
+/*
+ * Command for nameserver_delete
+ */
+#define CMD_NAMESERVER_DELETE _IOWR(IPC_IOC_MAGIC, \
+ NAMESERVER_DELETE, \
+ struct nameserver_cmd_args)
+
+/*
+ * Command for nameserver_add
+ */
+#define CMD_NAMESERVER_ADD _IOWR(IPC_IOC_MAGIC, \
+ NAMESERVER_ADD, \
+ struct nameserver_cmd_args)
+
+/*
+ * Command for nameserver_addu32
+ */
+#define CMD_NAMESERVER_ADDUINT32 _IOWR(IPC_IOC_MAGIC, \
+ NAMESERVER_ADDUINT32, \
+ struct nameserver_cmd_args)
+/*
+ * Command for nameserver_get
+ */
+#define CMD_NAMESERVER_GET _IOWR(IPC_IOC_MAGIC, \
+ NAMESERVER_GET, \
+ struct nameserver_cmd_args)
+
+/*
+ * Command for nameserver_get_local
+ */
+#define CMD_NAMESERVER_GETLOCAL _IOWR(IPC_IOC_MAGIC, \
+ NAMESERVER_GETLOCAL, \
+ struct nameserver_cmd_args)
+
+/*
+ * Command for nameserver_match
+ */
+#define CMD_NAMESERVER_MATCH _IOWR(IPC_IOC_MAGIC, \
+ NAMESERVER_MATCH, \
+ struct nameserver_cmd_args)
+
+/*
+ * Command for nameserver_remove
+ */
+#define CMD_NAMESERVER_REMOVE _IOWR(IPC_IOC_MAGIC, \
+ NAMESERVER_REMOVE, \
+ struct nameserver_cmd_args)
+
+/*
+ * Command for nameserver_remove_entry
+ */
+#define CMD_NAMESERVER_REMOVEENTRY _IOWR(IPC_IOC_MAGIC, \
+ NAMESERVER_REMOVEENTRY, \
+ struct nameserver_cmd_args)
+
+/*
+ * Command for nameserver_get_handle
+ */
+#define CMD_NAMESERVER_GETHANDLE _IOWR(IPC_IOC_MAGIC, \
+ NAMESERVER_GETHANDLE, \
+ struct nameserver_cmd_args)
+
+/*
+ * Command for NameServer_isRegistered
+ */
+#define CMD_NAMESERVER_ISREGISTERED _IOWR(IPC_IOC_MAGIC, \
+ NAMESERVER_ISREGISTERED, \
+ struct nameserver_cmd_args)
+
+/*
+ * Command for NameServer_getConfig
+ */
+#define CMD_NAMESERVER_GETCONFIG _IOWR(IPC_IOC_MAGIC, \
+ NAMESERVER_GETCONFIG, \
+ struct nameserver_cmd_args)
+
+/*
+ * Command arguments for nameserver
+ */
+union nameserver_arg {
+ struct {
+ struct nameserver_config *config;
+ } get_config;
+
+ struct {
+ struct nameserver_config *config;
+ } setup;
+
+ struct {
+ struct nameserver_params *params;
+ } params_init;
+
+ struct {
+ void *handle;
+ char *name;
+ u32 name_len;
+ struct nameserver_params *params;
+ } create;
+
+ struct {
+ void *handle;
+ } delete_instance;
+
+ struct {
+ void *handle;
+ char *name;
+ u32 name_len;
+ void *buf;
+ s32 len;
+ void *entry;
+ void *node;
+ } add;
+
+ struct {
+ void *handle;
+ char *name;
+ u32 name_len;
+ u32 value;
+ void *entry;
+ } addu32;
+
+ struct {
+ void *handle;
+ char *name;
+ u32 name_len;
+ void *value;
+ u32 len;
+ u16 *proc_id;
+ u32 proc_len;
+ } get;
+
+ struct {
+ void *handle;
+ char *name;
+ u32 name_len;
+ void *value;
+ u32 len;
+ } get_local;
+
+ struct {
+ void *handle;
+ char *name;
+ u32 name_len;
+ u32 value;
+ u32 count;
+ } match;
+
+ struct {
+ void *handle;
+ char *name;
+ u32 name_len;
+ } remove;
+
+ struct {
+ void *handle;
+ void *entry;
+ } remove_entry;
+
+ struct {
+ void *handle;
+ char *name;
+ u32 name_len;
+ } get_handle;
+
+ struct {
+ u16 proc_id;
+ bool check;
+ } is_registered;
+};
+
+/*
+ * Command arguments for nameserver
+ */
+struct nameserver_cmd_args {
+ union nameserver_arg args;
+ s32 api_status;
+};
+
+/*
+ * This ioctl interface for nameserver module
+ */
+int nameserver_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user);
+
+#endif /* _NAMESERVER_IOCTL_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/nameserver_remote.h b/arch/arm/plat-omap/include/syslink/nameserver_remote.h
new file mode 100644
index 00000000000..bc0921b08e0
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/nameserver_remote.h
@@ -0,0 +1,39 @@
+/*
+ * nameserver_remote.h
+ *
+ * Copyright (C) 2008-2009 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 _NAMESERVER_REMOTE_H_
+#define _NAMESERVER_REMOTE_H_
+
+#include <linux/types.h>
+
+/*
+ * Structure defining object for the nameserver remote driver
+ */
+struct nameserver_remote_object {
+ int (*get)(const struct nameserver_remote_object *obj,
+ const char *instance_name, const char *name,
+ void *value, u32 *value_len, void *reserved);
+ /* Function to get data from remote nameserver */
+ void *obj; /* Implementation specific object */
+};
+
+/*
+ * Function get data from remote name server
+ */
+int nameserver_remote_get(const struct nameserver_remote_object *handle,
+ const char *instance_name, const char *name,
+ void *value, u32 *value_len, void *reserved);
+
+#endif /* _NAMESERVER_REMOTE_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/nameserver_remotenotify.h b/arch/arm/plat-omap/include/syslink/nameserver_remotenotify.h
new file mode 100644
index 00000000000..cb9b6218930
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/nameserver_remotenotify.h
@@ -0,0 +1,90 @@
+/*
+ * nameserver_remotenotify.h
+ *
+ * The nameserver_remotenotify module provides functionality to get name
+ * value pair from a remote nameserver.
+ *
+ * Copyright (C) 2008-2009 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 _NAMESERVER_REMOTENOTIFY_H_
+#define _NAMESERVER_REMOTENOTIFY_H_
+
+#include <linux/types.h>
+
+/*
+ * NAMESERVERREMOTENOTIFY_MODULEID
+ * Unique module ID
+ */
+#define NAMESERVERREMOTENOTIFY_MODULEID (0x08FD)
+
+/*
+ * Module configuration structure
+ */
+struct nameserver_remotenotify_config {
+ u32 notify_event_id;
+ /* Notify event number */
+};
+
+/*
+ * Module configuration structure
+ */
+struct nameserver_remotenotify_params {
+ void *shared_addr; /* Address of the shared memory */
+ void *gatemp; /* Handle to the gatemp used for protecting the
+ nameserver_remotenotify instance. Using the default
+ value of NULL will result in the default gatemp being
+ used for context protection */
+};
+
+/* Function to get the default configuration for the nameserver_remotenotify
+ * module */
+void nameserver_remotenotify_get_config(
+ struct nameserver_remotenotify_config *cfg);
+
+/* Function to setup the nameserver_remotenotify module */
+int nameserver_remotenotify_setup(struct nameserver_remotenotify_config *cfg);
+
+/* Function to destroy the nameserver_remotenotify module */
+int nameserver_remotenotify_destroy(void);
+
+/* Function to get the current configuration values */
+void nameserver_remotenotify_params_init(
+ struct nameserver_remotenotify_params *params);
+
+/* Function to create the nameserver_remotenotify object */
+void *nameserver_remotenotify_create(u16 remote_proc_id,
+ const struct nameserver_remotenotify_params *params);
+
+/* Function to delete the nameserver_remotenotify object */
+int nameserver_remotenotify_delete(void **handle);
+
+/* Function to get a name/value from remote nameserver */
+int nameserver_remotenotify_get(void *handle,
+ const char *instance_name, const char *name,
+ void *value, u32 *value_len, void *reserved);
+
+/* Get the shared memory requirements for the nameserver_remotenotify */
+uint nameserver_remotenotify_shared_mem_req(
+ const struct nameserver_remotenotify_params *params);
+
+/* Create all the NameServerRemoteNotify drivers. */
+int nameserver_remotenotify_start(void *shared_addr);
+
+/* Attaches to remote processor */
+int nameserver_remotenotify_attach(u16 remote_proc_id, void *shared_addr);
+
+/* Detaches from remote processor */
+int nameserver_remotenotify_detach(u16 remote_proc_id);
+
+
+#endif /* _NAMESERVER_REMOTENOTIFY_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/notify.h b/arch/arm/plat-omap/include/syslink/notify.h
new file mode 100644
index 00000000000..0f9a399e5ce
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/notify.h
@@ -0,0 +1,146 @@
+/*
+ * notify.h
+ *
+ * Notify driver support for OMAP Processors.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+
+#if !defined(_NOTIFY_H_)
+#define _NOTIFY_H_
+
+/* The resource is still in use */
+#define NOTIFY_S_BUSY 2
+
+/* Module already set up */
+#define NOTIFY_S_ALREADYSETUP 1
+
+/* Operation is successful. */
+#define NOTIFY_S_SUCCESS 0
+
+/* Generic failure */
+#define NOTIFY_E_FAIL -1
+
+/* Argument passed to function is invalid.. */
+#define NOTIFY_E_INVALIDARG -2
+
+/* Operation resulted in memory failure. */
+#define NOTIFY_E_MEMORY -3
+
+/* The specified entity already exists. */
+#define NOTIFY_E_ALREADYEXISTS -4
+
+/* Unable to find the specified entity. */
+#define NOTIFY_E_NOTFOUND -5
+
+/* Operation timed out. */
+#define NOTIFY_E_TIMEOUT -6
+
+/* Module is not initialized. */
+#define NOTIFY_E_INVALIDSTATE -7
+
+/* A failure occurred in an OS-specific call */
+#define NOTIFY_E_OSFAILURE -8
+
+/* The module has been already setup */
+#define NOTIFY_E_ALREADYSETUP -9
+
+/* Specified resource is not available */
+#define NOTIFY_E_RESOURCE -10
+
+/* Operation was interrupted. Please restart the operation */
+#define NOTIFY_E_RESTART -11
+
+/* The resource is still in use */
+#define NOTIFY_E_BUSY -12
+
+/* Driver corresponding to the specified eventId is not registered */
+#define NOTIFY_E_DRIVERNOTREGISTERED -13
+
+/* Event not registered */
+#define NOTIFY_E_EVTNOTREGISTERED -14
+
+/* Event is disabled */
+#define NOTIFY_E_EVTDISABLED -15
+
+/* Remote notification is not initialized */
+#define NOTIFY_E_NOTINITIALIZED -16
+
+/* Trying to illegally use a reserved event */
+#define NOTIFY_E_EVTRESERVED -17
+
+/* Macro to make a correct module magic number with refCount */
+#define NOTIFY_MAKE_MAGICSTAMP(x) ((NOTIFY_MODULEID << 12u) | (x))
+
+#define REG volatile
+
+/* Maximum number of events supported by the Notify module */
+#define NOTIFY_MAXEVENTS (u16)32
+
+/* Maximum number of IPC interrupt lines per processor. */
+#define NOTIFY_MAX_INTLINES 4u
+
+/* This key must be provided as the upper 16 bits of the eventNo when
+ * registering for an event, if any reserved event numbers are to be
+ * used. */
+#define NOTIFY_SYSTEMKEY 0xC1D2
+
+
+typedef void (*notify_fn_notify_cbck)(u16 proc_id, u16 line_id, u32 event_id,
+ uint *arg, u32 payload);
+
+extern struct notify_module_object notify_state;
+
+
+/* Function to disable Notify module */
+u32 notify_disable(u16 procId, u16 line_id);
+
+/* Function to disable particular event */
+void notify_disable_event(u16 proc_id, u16 line_id, u32 event_id);
+
+/* Function to enable particular event */
+void notify_enable_event(u16 proc_id, u16 line_id, u32 event_id);
+
+/* Function to find out whether notification via interrupt line has been
+ * registered. */
+bool notify_is_registered(u16 proc_id, u16 line_id);
+
+/* Returns the amount of shared memory used by one Notify instance. */
+uint notify_shared_mem_req(u16 proc_id, void *shared_addr);
+
+/* Function to register an event */
+int notify_register_event(u16 proc_id, u16 line_id, u32 event_id,
+ notify_fn_notify_cbck notify_callback_fxn,
+ void *cbck_arg);
+
+/* Function to register an event */
+int notify_register_event_single(u16 proc_id, u16 line_id, u32 event_id,
+ notify_fn_notify_cbck notify_callback_fxn,
+ void *cbck_arg);
+
+/* Function to restore Notify module state */
+void notify_restore(u16 proc_id, u16 line_id, u32 key);
+
+/* Function to send an event to other processor */
+int notify_send_event(u16 proc_id, u16 line_id, u32 event_id, u32 payload,
+ bool wait_clear);
+
+/* Function to unregister an event */
+int notify_unregister_event(u16 proc_id, u16 line_id, u32 event_id,
+ notify_fn_notify_cbck notify_callback_fxn,
+ void *cbck_arg);
+
+/* Function to unregister an event */
+int notify_unregister_event_single(u16 proc_id, u16 line_id, u32 event_id);
+
+
+#endif /* !defined(_NOTIFY_H_) */
diff --git a/arch/arm/plat-omap/include/syslink/notify_dispatcher.h b/arch/arm/plat-omap/include/syslink/notify_dispatcher.h
new file mode 100644
index 00000000000..efd87315815
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/notify_dispatcher.h
@@ -0,0 +1,158 @@
+/*
+ * notify_dispatcher.h
+ *
+ * Notify driver support for OMAP Processors.
+ *
+ * Copyright (C) 2008-2009 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 __TMBX_H__
+#define __TMBX_H__
+
+
+#include <syslink/notifydefs.h>
+#include <linux/interrupt.h>
+
+#include <syslink/notifyerr.h>
+
+#define MAX_MBOX_MODULES 2
+#define MAX_MBOX_ISRS 32
+#define KErrNone 0
+#define KErrNotSupported 1
+#define KErrNotReady 2
+#define KErrArgument 2
+
+typedef void (*isr_call_back)(void *);
+
+struct mbox_config {
+ unsigned long int mbox_linear_addr;
+ unsigned long int mbox_modules;
+ signed long int interrupt_lines[MAX_MBOX_MODULES];
+ signed long int mailboxes[MAX_MBOX_MODULES];
+};
+
+struct mbox_isrs {
+ signed long int isrNo[MAX_MBOX_MODULES];
+ /* TODO: Remove this - seems to be unused.*/
+ isr_call_back isrs[MAX_MBOX_MODULES][MAX_MBOX_ISRS];
+ void *isr_params[MAX_MBOX_MODULES][MAX_MBOX_ISRS];
+};
+
+extern const unsigned long *linear_address;
+
+irqreturn_t notify_mailbx0_user0_isr(int temp, void *anArg, struct pt_regs *p);
+
+/*
+ *func ntfy_disp_bind_interrupt
+ *
+ * desc Bind an ISR to the HW interrupt line coming into the processor
+ */
+int ntfy_disp_bind_interrupt(int interrupt_no,
+ isr_call_back hw_isr,
+ void *isr_arg);
+
+
+/*
+ * desc Print the mailbox registers and other useful debug information
+ *
+ */
+void ntfy_disp_debug(void);
+
+
+/*
+ * func ntfy_disp_deinit
+ * desc Uninitialize the Mailbox Manager module
+ */
+int ntfy_disp_deinit(void);
+
+
+/*
+ * desc Return the pointer to the Mailbox Manager's configuration object
+ */
+struct mbox_config *ntfy_disp_get_config(void);
+
+
+/*
+ * desc Initialize the Mailbox Manager module
+ */
+int ntfy_disp_init(void);
+
+
+/*
+ * desc Disable a particular IRQ bit on a Mailbox IRQ Enable Register
+ */
+int ntfy_disp_interrupt_disable(unsigned long int mbox_module_no,
+ int a_irq_bit);
+
+
+/*
+ * desc Enable a particular IRQ bit on a Mailbox IRQ Enable Register
+ */
+int ntfy_disp_interrupt_enable(unsigned long int mbox_module_no,
+ int a_irq_bit);
+
+
+/*
+ * desc Read a message on a Mailbox FIFO queue
+ */
+int ntfy_disp_read(unsigned long int mbox_module_no,
+ int a_mbox_no,
+ int *messages,
+ int *num_messages,
+ short int read_all);
+
+
+/*
+ * func ntfy_disp_register
+ * desc Register a ISR callback associated with a particular IRQ bit on a
+ * Mailbox IRQ Enable Register
+ */
+int ntfy_disp_register(unsigned long int mbox_module_no,
+ int a_irq_bit,
+ isr_call_back isr_cbck_fn,
+ void *isrCallbackArgs);
+
+
+/*
+ * func ntfy_disp_send
+ * desc Send a message on a Mailbox FIFO queue
+ */
+int ntfy_disp_send(unsigned long int mbox_module_no,
+ int a_mbox_no,
+ int message);
+
+
+/*
+ * func ntfy_disp_unbind_interrupt
+ * desc Remove the ISR to the HW interrupt line coming into the processor
+ */
+int ntfy_disp_unbind_interrupt(int interrupt_no);
+
+
+/*
+ * func ntfy_disp_unregister
+ * desc Unregister a ISR callback associated with a particular IRQ bit on a
+ * Mailbox IRQ Enable Register
+ */
+int ntfy_disp_unregister(unsigned long int mbox_module_no,
+ int a_irq_bit);
+
+/*
+ * func notify_mailbx0_user0_isr
+ * desc mail ISR
+ *
+ */
+
+irqreturn_t notify_mailbx0_user0_isr(int temp, void *anArg, struct pt_regs *p);
+
+
+#endif
diff --git a/arch/arm/plat-omap/include/syslink/notify_driver.h b/arch/arm/plat-omap/include/syslink/notify_driver.h
new file mode 100644
index 00000000000..95c586b7762
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/notify_driver.h
@@ -0,0 +1,45 @@
+/*
+ * notify_driver.h
+ *
+ * Notify driver support for OMAP Processors.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+
+#if !defined _NOTIFY_DRIVER_H_
+#define _NOTIFY_DRIVER_H_
+
+
+/* Module includes */
+#include <syslink/notify_driverdefs.h>
+#include <syslink/_notify.h>
+
+
+/* Function to register notify driver */
+int notify_register_driver(u16 remote_proc_id,
+ u16 line_id,
+ struct notify_driver_fxn_table *fxn_table,
+ struct notify_driver_object **driver_handle);
+
+/* Function to unregister notify driver */
+int notify_unregister_driver(struct notify_driver_object *drv_handle);
+
+/* Function to set the driver handle */
+int notify_set_driver_handle(u16 remote_proc_id, u16 line_id,
+ struct notify_object *handle);
+
+/* Function to find the driver in the list of drivers */
+struct notify_driver_object *notify_get_driver_handle(u16 remote_proc_id,
+ u16 line_id);
+
+
+#endif /* !defined (_NOTIFY_DRIVER_H_) */
diff --git a/arch/arm/plat-omap/include/syslink/notify_driverdefs.h b/arch/arm/plat-omap/include/syslink/notify_driverdefs.h
new file mode 100644
index 00000000000..56f6b282caf
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/notify_driverdefs.h
@@ -0,0 +1,137 @@
+/*
+ * notify_driverdefs.h
+ *
+ * Notify driver support for OMAP Processors.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+
+#if !defined(_NOTIFY_DRIVERDEFS_H_)
+#define _NOTIFY_DRIVERDEFS_H_
+
+
+/* Module headers */
+#include <syslink/multiproc.h>
+#include <syslink/notify.h>
+#include <syslink/_notify.h>
+
+
+/* Enumerations to indicate types of Driver initialization status */
+enum notify_driver_init_status {
+ NOTIFY_DRIVERINITSTATUS_NOTDONE = 0,
+ /* Driver initialization is not done. */
+ NOTIFY_DRIVERINITSTATUS_DONE = 1,
+ /* Driver initialization is complete. */
+ NOTIFY_DRIVERINITSTATUS_INPROGRESS = 2,
+ /* Driver initialization is in progress. */
+ NOTIFY_DRIVERINITSTATUS_ENDVALUE = 3
+ /* End delimiter indicating start of invalid values for this enum */
+};
+
+struct notify_driver_object;
+
+/* This structure defines the function table interface for the Notify
+ * driver.
+ * This function table interface must be implemented by each Notify
+ * driver and registered with the Notify module. */
+struct notify_driver_fxn_table {
+ int (*register_event)(struct notify_driver_object *handle,
+ u32 event_id);
+ /* interface function register_event */
+ int (*unregister_event)(struct notify_driver_object *handle,
+ u32 event_id);
+ /* interface function unregister_event */
+ int (*send_event)(struct notify_driver_object *handle, u32 event_id,
+ u32 payload, bool wait_clear);
+ /* interface function send_event */
+ u32 (*disable)(struct notify_driver_object *handle);
+ /* interface function disable */
+ void (*enable)(struct notify_driver_object *handle);
+ /* interface function enable */
+ void (*disable_event)(struct notify_driver_object *handle,
+ u32 event_id);
+ /* interface function disable_event */
+ void (*enable_event)(struct notify_driver_object *handle, u32 event_id);
+ /* interface function enable_event */
+};
+
+/* This structure defines the Notify driver object and handle used
+ * internally to contain all information required for the Notify driver
+ * This object contains all information for the Notify module to be
+ * able to identify and interact with the Notify driver. */
+struct notify_driver_object {
+ enum notify_driver_init_status is_init;
+ struct notify_driver_fxn_table fxn_table;
+ struct notify_object *notify_handle;
+};
+
+#if 0
+/*
+ *This structure defines information for all processors supported by
+ *the Notify driver.
+ *An instance of this object is provided for each processor handled by
+ *the Notify driver, when registering itself with the Notify module.
+ *
+ */
+struct notify_driver_proc_info {
+ u32 max_events;
+ u32 reserved_events;
+ bool event_priority;
+ u32 payload_size;
+ u16 proc_id;
+};
+
+/*
+ * This structure defines the structure for specifying Notify driver
+ * attributes to the Notify module.
+ * This structure provides information about the Notify driver to the
+ * Notify module. The information is used by the Notify module mainly
+ * for parameter validation. It may also be used by the Notify module
+ * to take appropriate action if required, based on the characteristics
+ * of the Notify driver.
+ */
+struct notify_driver_attrs {
+ u32 numProc;
+ struct notify_driver_proc_info
+ proc_info[MULTIPROC_MAXPROCESSORS];
+};
+
+union notify_drv_procevents{
+ struct {
+ struct notify_shmdrv_attrs attrs;
+ struct notify_shmdrv_ctrl *ctrl_ptr;
+ } shm_events;
+
+ struct {
+ /*Attributes */
+ unsigned long int num_events;
+ unsigned long int send_event_pollcount;
+ /*Control Paramters */
+ unsigned long int send_init_status ;
+ struct notify_shmdrv_eventreg_mask reg_mask ;
+ } non_shm_events;
+};
+
+struct notify_drv_eventlist {
+ unsigned long int event_handler_count;
+ struct list_head listeners;
+};
+
+struct notify_drv_proc_module {
+ unsigned long int proc_id;
+ struct notify_drv_eventlist *event_list;
+ struct notify_shmdrv_eventreg *reg_chart;
+ union notify_drv_procevents events_obj;
+};
+#endif
+
+#endif /* !defined(_NOTIFY_DRIVERDEFS_H_) */
diff --git a/arch/arm/plat-omap/include/syslink/notify_ducatidriver.h b/arch/arm/plat-omap/include/syslink/notify_ducatidriver.h
new file mode 100644
index 00000000000..81e59e6fd72
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/notify_ducatidriver.h
@@ -0,0 +1,141 @@
+/*
+ * notify_ducatidriver.h
+ *
+ * Syslink driver support for OMAP Processors.
+ *
+ * Copyright (C) 2008-2009 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 NOTIFY_DUCATIDRIVER_H_
+#define NOTIFY_DUCATIDRIVER_H_
+
+
+
+/* Notify*/
+#include <syslink/notify.h>
+#include <syslink/notify_driverdefs.h>
+
+/* Module ID for NotifyDriverShm. */
+#define NOTIFY_DUCATIDRIVER_MODULEID ((u16) 0xb9d4)
+
+#define VOLATILE volatile
+
+extern u32 get_ducati_virt_mem(void);
+extern void unmap_ducati_virt_mem(u32 shm_virt_addr);
+
+
+/* module configuration structure */
+struct notify_ducatidrv_config {
+ u32 reserved;
+};
+
+/* This structure defines the configuration structure for
+ * initialization of the Notify driver. */
+struct notify_ducatidrv_params {
+ void *shared_addr;
+ /* Address in shared memory where this instance will be placed */
+ bool cache_enabled;
+ /* Whether cache operations will be performed */
+ u32 cache_line_size;
+ /* The cache line size of the shared memory */
+ u32 remote_proc_id;
+ /* Processor Id of remote processor required for communication */
+ u32 line_id;
+ /* Line ID for the interrupt */
+ u32 local_int_id;
+ /* Local interrupt ID for interrupt line for incoming interrupts */
+ u32 remote_int_id;
+ /* Remote interrupt ID for interrupt line for outgoing interrupts */
+};
+
+/* Defines the structure of event entry within the event chart.
+ * Each entry contains occured event-specific information.
+ * Used to flag a remote event and determine if a local event has been
+ * flagged. This struct is placed in shared memory. */
+struct notify_ducatidrv_event_entry {
+ VOLATILE u32 flag;
+ /* Flag indicating whether event is set */
+ VOLATILE u32 payload;
+ /* Payload associated with event */
+ VOLATILE u32 reserved;
+ /* Reserved field */
+ /* Padding for cache line alignment */
+};
+
+/* Defines the NotifyDriverShm control structure, which contains all
+ * information for one processor. This structure is shared between the
+ * two processors. */
+struct notify_ducatidrv_proc_ctrl {
+ VOLATILE u32 recv_init_status;
+ /* Initialization status for receiving events */
+ VOLATILE u32 send_init_status;
+ /* Initialization status for sending events */
+ VOLATILE u32 event_reg_mask;
+ /* Event Registered mask */
+ VOLATILE u32 event_enable_mask;
+ /* Event Enabled mask */
+};
+
+
+/* Function to get the default configuration for the notify_ducati driver
+ * module. */
+void notify_ducatidrv_get_config(struct notify_ducatidrv_config *cfg);
+
+/* Function to setup the notify ducati driver with the given configuration*/
+int notify_ducatidrv_setup(struct notify_ducatidrv_config *cfg);
+
+/* Function to destroy the notify ducati driver */
+int notify_ducatidrv_destroy(void);
+
+/*Function to initialize the given parameters */
+void notify_ducatidrv_params_init(struct notify_ducatidrv_params *params);
+
+/* Function to create the ducati driver handle and performs initialization. */
+struct notify_ducatidrv_object *notify_ducatidrv_create(
+ const struct notify_ducatidrv_params *params);
+
+/* Function to delete the ducati driver handle and performs de initialization.*/
+int notify_ducatidrv_delete(struct notify_ducatidrv_object **handle);
+
+/* Get the shared memory requirements for the notify ducati driver. */
+uint notify_ducatidrv_shared_mem_req(
+ const struct notify_ducatidrv_params *params);
+
+
+/* Register a callback for an event with the Notify driver. */
+int notify_ducatidrv_register_event(struct notify_driver_object *handle,
+ u32 event_id);
+
+/* Unregister a callback for an event with the Notify driver. */
+int notify_ducatidrv_unregister_event(struct notify_driver_object *handle,
+ u32 event_id);
+
+/* Send a notification event to the registered users for this
+ notification on the specified processor. */
+int notify_ducatidrv_send_event(struct notify_driver_object *handle,
+ u32 event_id, u32 payload, bool wait_clear);
+
+/* Disable all events for this Notify driver. */
+int notify_ducatidrv_disable(struct notify_driver_object *handle);
+
+/* Restore the Notify driver to the state before the last disable was called. */
+void notify_ducatidrv_enable(struct notify_driver_object *handle);
+
+/* Disable a specific event for this Notify driver. */
+void notify_ducatidrv_disable_event(struct notify_driver_object *handle,
+ u32 event_id);
+
+/* Enable a specific event for this Notify driver. */
+void notify_ducatidrv_enable_event(struct notify_driver_object *handle,
+ u32 event_id);
+
+
+#endif /* !defined NOTIFY_SHMDRIVER_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/notify_ioctl.h b/arch/arm/plat-omap/include/syslink/notify_ioctl.h
new file mode 100644
index 00000000000..9d1dcadd4ba
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/notify_ioctl.h
@@ -0,0 +1,278 @@
+/*
+ * notify_driverdefs.h
+ *
+ * Notify driver support for OMAP Processors.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+
+#if !defined(_NOTIFY_IOCTL_H_)
+#define _NOTIFY_IOCTL_H_
+
+/* Linux headers */
+#include <linux/ioctl.h>
+
+/* Utilities headers */
+#include <syslink/host_os.h>
+
+/* Module headers */
+#include <ipc_ioctl.h>
+#include <syslink/notify.h>
+#include <syslink/notify_ducatidriver.h>
+#include <syslink/notifydefs.h>
+
+
+enum CMD_NOTIFY {
+ NOTIFY_GETCONFIG = NOTIFY_BASE_CMD,
+ NOTIFY_SETUP,
+ NOTIFY_DESTROY,
+ NOTIFY_REGISTEREVENT,
+ NOTIFY_UNREGISTEREVENT,
+ NOTIFY_SENDEVENT,
+ NOTIFY_DISABLE,
+ NOTIFY_RESTORE,
+ NOTIFY_DISABLEEVENT,
+ NOTIFY_ENABLEEVENT,
+ NOTIFY_ATTACH,
+ NOTIFY_DETACH,
+ NOTIFY_THREADATTACH,
+ NOTIFY_THREADDETACH,
+ NOTIFY_ISREGISTERED,
+ NOTIFY_SHAREDMEMREQ,
+ NOTIFY_REGISTEREVENTSINGLE,
+ NOTIFY_UNREGISTEREVENTSINGLE
+};
+
+/* Command for notify_get_config */
+#define CMD_NOTIFY_GETCONFIG _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_GETCONFIG, \
+ struct notify_cmd_args_get_config)
+
+/* Command for notify_setup */
+#define CMD_NOTIFY_SETUP _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_SETUP, \
+ struct notify_cmd_args_setup)
+
+/* Command for notify_destroy */
+#define CMD_NOTIFY_DESTROY _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_DESTROY, \
+ struct notify_cmd_args_destroy)
+
+/* Command for notify_register_event */
+#define CMD_NOTIFY_REGISTEREVENT _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_REGISTEREVENT, \
+ struct notify_cmd_args_register_event)
+
+/* Command for notify_unregister_event */
+#define CMD_NOTIFY_UNREGISTEREVENT _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_UNREGISTEREVENT, \
+ struct notify_cmd_args_unregister_event)
+
+/* Command for notify_send_event */
+#define CMD_NOTIFY_SENDEVENT _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_SENDEVENT, \
+ struct notify_cmd_args_send_event)
+/* Command for notify_disable */
+#define CMD_NOTIFY_DISABLE _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_DISABLE, \
+ struct notify_cmd_args_disable)
+
+/* Command for notify_restore */
+#define CMD_NOTIFY_RESTORE _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_RESTORE, \
+ struct notify_cmd_args_restore)
+
+/* Command for notify_disable_event */
+#define CMD_NOTIFY_DISABLEEVENT _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_DISABLEEVENT, \
+ struct notify_cmd_args_disable_event)
+
+/* Command for notify_enable_event */
+#define CMD_NOTIFY_ENABLEEVENT _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_ENABLEEVENT, \
+ struct notify_cmd_args_enable_event)
+
+/* Command for notify_attach */
+#define CMD_NOTIFY_ATTACH _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_ATTACH, \
+ struct notify_cmd_args_attach)
+
+/* Command for notify_detach */
+#define CMD_NOTIFY_DETACH _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_DETACH, \
+ struct notify_cmd_args_detach)
+
+/* Command for notify_thread_attach */
+#define CMD_NOTIFY_THREADATTACH _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_THREADATTACH, \
+ struct notify_cmd_args)
+
+/* Command for notify_thread_detach */
+#define CMD_NOTIFY_THREADDETACH _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_THREADDETACH, \
+ struct notify_cmd_args)
+
+/* Command for notify_is_registered */
+#define CMD_NOTIFY_ISREGISTERED _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_ISREGISTERED, \
+ struct notify_cmd_args_is_registered)
+
+/* Command for notify_shared_mem_req */
+#define CMD_NOTIFY_SHAREDMEMREQ _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_SHAREDMEMREQ, \
+ struct notify_cmd_args_shared_mem_req)
+/* Command for notify_register_event_single */
+#define CMD_NOTIFY_REGISTEREVENTSINGLE _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_REGISTEREVENTSINGLE, \
+ struct notify_cmd_args_register_event)
+
+/* Command for notify_unregister_event_single */
+#define CMD_NOTIFY_UNREGISTEREVENTSINGLE _IOWR(IPC_IOC_MAGIC, \
+ NOTIFY_UNREGISTEREVENTSINGLE, \
+ struct notify_cmd_args_unregister_event)
+
+
+/*Structure of Event Packet read from notify kernel-side..*/
+struct notify_drv_event_packet {
+ struct list_head element;
+ u32 pid;
+ u32 proc_id;
+ u32 event_id;
+ u16 line_id;
+ u32 data;
+ notify_fn_notify_cbck func;
+ void *param;
+ bool is_exit;
+};
+
+/* Common arguments for all ioctl commands */
+struct notify_cmd_args {
+ int api_status;
+};
+
+/* Command arguments for notify_get_config */
+struct notify_cmd_args_get_config {
+ struct notify_cmd_args common_args;
+ struct notify_config *cfg;
+};
+
+/* Command arguments for notify_setup */
+struct notify_cmd_args_setup {
+ struct notify_cmd_args common_args;
+ struct notify_config *cfg;
+};
+
+/* Command arguments for notify_destroy */
+struct notify_cmd_args_destroy {
+ struct notify_cmd_args common_args;
+};
+
+/* Command arguments for notify_attach */
+struct notify_cmd_args_attach {
+ struct notify_cmd_args common_args;
+ u16 proc_id;
+ void *shared_addr;
+};
+
+/* Command arguments for notify_detach */
+struct notify_cmd_args_detach {
+ struct notify_cmd_args common_args;
+ u16 proc_id;
+};
+
+/* Command arguments for notify_cmd_args_shared_mem_req */
+struct notify_cmd_args_shared_mem_req {
+ struct notify_cmd_args common_args;
+ u16 proc_id;
+ void *shared_addr;
+ uint shared_mem_size;
+};
+
+/* Command arguments for notify_cmd_args_is_registered */
+struct notify_cmd_args_is_registered {
+ struct notify_cmd_args common_args;
+ u16 proc_id;
+ u16 line_id;
+ bool is_registered;
+};
+
+/* Command arguments for notify_register_event */
+struct notify_cmd_args_register_event {
+ struct notify_cmd_args common_args;
+ u16 proc_id;
+ u16 line_id;
+ u32 event_id;
+ notify_fn_notify_cbck fn_notify_cbck;
+ uint *cbck_arg;
+ u32 pid;
+};
+
+/* Command arguments for notify_unregister_event */
+struct notify_cmd_args_unregister_event {
+ struct notify_cmd_args common_args;
+ u16 proc_id;
+ u16 line_id;
+ u32 event_id;
+ notify_fn_notify_cbck fn_notify_cbck;
+ uint *cbck_arg;
+ u32 pid;
+};
+
+/* Command arguments for notify_send_event */
+struct notify_cmd_args_send_event {
+ struct notify_cmd_args common_args;
+ u16 proc_id;
+ u16 line_id;
+ u32 event_id;
+ u32 payload;
+ bool wait_clear;
+};
+
+/* Command arguments for notify_disable */
+struct notify_cmd_args_disable {
+ struct notify_cmd_args common_args;
+ u16 proc_id;
+ u16 line_id;
+ u32 flags;
+};
+
+/* Command arguments for notify_restore */
+struct notify_cmd_args_restore {
+ struct notify_cmd_args common_args;
+ u32 key;
+ u16 proc_id;
+ u16 line_id;
+};
+
+/* Command arguments for notify_disable_event */
+struct notify_cmd_args_disable_event {
+ struct notify_cmd_args common_args;
+ u16 proc_id;
+ u16 line_id;
+ u32 event_id;
+};
+
+/* Command arguments for notify_enable_event */
+struct notify_cmd_args_enable_event {
+ struct notify_cmd_args common_args;
+ u16 proc_id;
+ u16 line_id;
+ u32 event_id;
+};
+
+/* Command arguments for notify_exit */
+struct notify_cmd_args_exit {
+ struct notify_cmd_args common_args;
+};
+
+
+#endif /* !defined(_NOTIFY_IOCTL_H_) */
diff --git a/arch/arm/plat-omap/include/syslink/notify_setup_proxy.h b/arch/arm/plat-omap/include/syslink/notify_setup_proxy.h
new file mode 100644
index 00000000000..383b3150a7d
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/notify_setup_proxy.h
@@ -0,0 +1,53 @@
+/*
+ * notify_setup_proxy.h
+ *
+ * Proxy to connect notify setup to device specific implementation
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+#if !defined(_NOTIFYSETUPPROXY_H_0x5f84)
+#define _NOTIFYSETUPPROXY_H_0x5f84
+
+#if defined(CONFIG_ARCH_OMAP4)
+/* Function that will be called in Notify_attach */
+extern int notify_setup_omap4_attach(u16 proc_id, void *shared_addr);
+#define notify_setup_proxy_attach(proc_id, shared_addr) \
+ notify_setup_omap4_attach(proc_id, shared_addr)
+
+/* Function that will be called in notify_stop */
+extern int notify_setup_omap4_detach(u16 proc_id);
+#define notify_setup_proxy_detach notify_setup_omap4_detach
+
+/* Shared Memory Required for notify setup */
+extern uint notify_setup_omap4_shared_mem_req(u16 proc_id, void *shared_addr);
+#define notify_setup_proxy_shared_mem_req(proc_id, shared_addr) \
+ notify_setup_omap4_shared_mem_req(proc_id, shared_addr)
+
+/* Is interrupt line available? */
+extern bool notify_setup_omap4_int_line_available(u16 remote_proc_id);
+#define notify_setup_proxy_int_line_available(remote_proc_id) \
+ notify_setup_omap4_int_line_available(remote_proc_id)
+#else
+/* Function that will be called in Notify_attach */
+#define notify_setup_proxy_attach(proc_id, shared_addr)
+
+/* Function that will be called in notify_stop */
+#define notify_setup_proxy_detach
+
+/* Shared Memory Required for notify setup */
+#define notify_setup_proxy_shared_mem_req(proc_id, shared_addr)
+
+/* Is interrupt line available? */
+#define notify_setup_proxy_int_line_available(remote_proc_id)
+#endif /* if defined (SYSLINK_PLATFORM_OMAPL1XX) */
+
+#endif /* !defined(_NOTIFYSETUPPROXY_H_0x5f84) */
diff --git a/arch/arm/plat-omap/include/syslink/notifydefs.h b/arch/arm/plat-omap/include/syslink/notifydefs.h
new file mode 100644
index 00000000000..e04b76382ff
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/notifydefs.h
@@ -0,0 +1,94 @@
+/*
+ * notifydefs.h
+ *
+ * Notify driver support for OMAP Processors.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+
+#if !defined(_NOTIFYDEFS_H_)
+#define _NOTIFYDEFS_H_
+
+/* Linux headers */
+#include <linux/list.h>
+
+/* Osal And Utils headers */
+#include <syslink/atomic_linux.h>
+
+/* Module headers */
+#include <syslink/notify.h>
+#include <syslink/_notify.h>
+#include <syslink/notify_driverdefs.h>
+
+
+/*Macro to make a correct module magic number with ref Count */
+#define NOTIFY_MAKE_MAGICSTAMP(x) ((NOTIFY_MODULEID << 12u) | (x))
+
+/* Maximum number of Notify drivers supported. */
+#define NOTIFY_MAX_DRIVERS 4u
+
+/* Mask to check for system key. */
+#define NOTIFY_SYSTEMKEY_MASK ((u16)0xFFFF0000)
+
+
+/* Defines the Event callback information instance */
+struct notify_event_callback {
+ notify_fn_notify_cbck fn_notify_cbck;
+ /* Callback function pointer */
+ uint *cbck_arg;
+ /* Argument associated with callback function */
+};
+
+/* Defines the Notify state object, which contains all the module
+ * specific information. */
+struct notify_module_object {
+ atomic_t ref_count;
+ /* Reference count */
+ struct notify_config cfg;
+ /* Notify configuration structure */
+ struct notify_config def_cfg;
+ /* Default module configuration */
+ struct mutex *gate_handle;
+ /* Handle of gate to be used for local thread safety */
+ struct notify_driver_object
+ drivers[NOTIFY_MAX_DRIVERS][NOTIFY_MAX_INTLINES];
+ /* Array of configured drivers. */
+ u32 local_enable_mask;
+ /* This is used for local/loopback events. Default to enabled (-1) */
+ bool start_complete;
+ /* TRUE if start() was called */
+ bool is_setup;
+ /* Indicates whether the Notify module is setup. */
+ struct notify_object *local_notify_handle;
+ /* Handle to Notify object for local notifications. */
+};
+
+/* Defines the Notify instance object. */
+struct notify_object {
+ uint nesting;
+ /* Disable/restore nesting */
+ void *driver_handle;
+ /* Handle to device specific driver */
+ u16 remote_proc_id;
+ /* Remote MultiProc id */
+ u16 line_id;
+ /* Interrupt line id */
+ struct notify_event_callback callbacks[NOTIFY_MAXEVENTS];
+ /* List of event callbacks registered */
+ struct list_head event_list[NOTIFY_MAXEVENTS];
+ /* List of event listeners registered */
+ struct mutex lock;
+ /* Lock for event_list */
+};
+
+
+#endif /* !defined (_NOTIFYDEFS_H_) */
diff --git a/arch/arm/plat-omap/include/syslink/notifyerr.h b/arch/arm/plat-omap/include/syslink/notifyerr.h
new file mode 100644
index 00000000000..0a14c0edc25
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/notifyerr.h
@@ -0,0 +1,198 @@
+/*
+ * notifyerr.h
+ *
+ * Notify driver support for OMAP Processors.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+
+#if !defined NOTIFYERR_H
+#define NOTIFYERR_H
+
+
+/*
+ * name NOTIFY_SUCCEEDED
+ *
+ * desc Check if the provided status code indicates a success code.
+ *
+ * arg status
+ * Status code to be checked
+ *
+ * ret TRUE
+ * If status code indicates success
+ * FALSE
+ * If status code indicates failure
+ *
+ * enter None.
+ *
+ * leave None.
+ *
+ * see NOTIFY_FAILED
+ *
+ */
+#define NOTIFY_SUCCEEDED(status)\
+(((signed long int) (status) >= (NOTIFY_SBASE)) \
+&& ((signed long int) (status) <= (NOTIFY_SLAST)))
+
+
+/*
+ * @name NOTIFY_FAILED
+ *
+ * @desc Check if the provided status code indicates a failure code.
+ *
+ * @arg status
+ * Status code to be checked
+ *
+ * @ret TRUE
+ * If status code indicates failure
+ * FALSE
+ * If status code indicates success
+ *
+ * @enter None.
+ *
+ * @leave None.
+ *
+ * @see NOTIFY_FAILED
+ *
+ */
+#define NOTIFY_FAILED(status) (!NOTIFY_SUCCEEDED(status))
+
+
+
+/*
+ * name NOTIFY_SBASE, NOTIFY_SLAST
+ *
+ * desc Defines the base and range for the success codes used by the
+ * Notify module
+ *
+ */
+#define NOTIFY_SBASE (signed long int)0x00002000l
+#define NOTIFY_SLAST (signed long int)0x000020FFl
+
+/*
+ * name NOTIFY_EBASE, NOTIFY_ELAST
+ *
+ * desc Defines the base and range for the failure codes used by the
+ * Notify module
+ *
+ */
+#define NOTIFY_EBASE (signed long int)0x80002000l
+#define NOTIFY_ELAST (signed long int)0x800020FFl
+
+
+/*
+ * SUCCESS Codes
+ *
+ */
+
+/* Generic success code for Notify module */
+#define NOTIFY_SOK (NOTIFY_SBASE + 0x01l)
+
+/* Indicates that the Notify module (or driver) has already been initialized
+ * by another client, and this process has now successfully acquired the right
+ * to use the Notify module.
+ */
+#define NOTIFY_SALREADYINIT (NOTIFY_SBASE + 0x02l)
+
+/* Indicates that the Notify module (or driver) is now being finalized, since
+ * the calling client is the last one finalizing the module, and all open
+ * handles to it have been closed.
+ */
+#define NOTIFY_SEXIT (NOTIFY_SBASE + 0x03l)
+
+
+/*
+ * FAILURE Codes
+ *
+ */
+
+/* Generic failure code for Notify module */
+#define NOTIFY_EFAIL (NOTIFY_EBASE + 0x01l)
+
+/* This failure code indicates that an operation has timed out. */
+#define NOTIFY_ETIMEOUT (NOTIFY_EBASE + 0x02l)
+
+/* This failure code indicates a configuration error */
+#define NOTIFY_ECONFIG (NOTIFY_EBASE + 0x03l)
+
+/* This failure code indicates that the Notify module has already been
+ * initialized from the calling client (process).
+ */
+#define NOTIFY_EALREADYINIT (NOTIFY_EBASE + 0x04l)
+
+/* This failure code indicates that the specified entity was not found
+ * The interpretation of this error code depends on the function from which it
+ * was returned.
+ */
+#define NOTIFY_ENOTFOUND (NOTIFY_EBASE + 0x05l)
+
+/* This failure code indicates that the specified feature is not supported
+ * The interpretation of this error code depends on the function from which it
+ * was returned.
+ */
+#define NOTIFY_ENOTSUPPORTED (NOTIFY_EBASE + 0x06l)
+
+/* This failure code indicates that the specified event number is
+ * not supported
+ */
+#define NOTIFY_EINVALIDEVENT (NOTIFY_EBASE + 0x07l)
+
+/* This failure code indicates that the specified pointer is invalid */
+#define NOTIFY_EPOINTER (NOTIFY_EBASE + 0x08l)
+
+/* This failure code indicates that a provided parameter was outside its valid
+ * range.
+ * The interpretation of this error code depends on the function from which it
+ * was returned.
+ */
+#define NOTIFY_ERANGE (NOTIFY_EBASE + 0x09l)
+
+/* This failure code indicates that the specified handle is invalid */
+#define NOTIFY_EHANDLE (NOTIFY_EBASE + 0x0Al)
+
+/* This failure code indicates that an invalid argument was specified */
+#define NOTIFY_EINVALIDARG (NOTIFY_EBASE + 0x0Bl)
+
+/* This failure code indicates a memory related failure */
+#define NOTIFY_EMEMORY (NOTIFY_EBASE + 0x0Cl)
+
+/* This failure code indicates that the Notify module has not been initialized*/
+#define NOTIFY_EINIT (NOTIFY_EBASE + 0x0Dl)
+
+/* This failure code indicates that a resource was not available.
+ * The interpretation of this error code depends on the function from which it
+ * was returned.
+ */
+#define NOTIFY_ERESOURCE (NOTIFY_EBASE + 0x0El)
+
+/* This failure code indicates that there was an attempt to register for a
+ * reserved event.
+ */
+#define NOTIFY_ERESERVEDEVENT (NOTIFY_EBASE + 0x0Fl)
+
+/* This failure code indicates that the specified entity already exists.
+ * The interpretation of this error code depends on the function from which it
+ * was returned.
+ */
+#define NOTIFY_EALREADYEXISTS (NOTIFY_EBASE + 0x10l)
+
+/* This failure code indicates that the Notify driver has not been fully
+ * initialized
+ */
+#define NOTIFY_EDRIVERINIT (NOTIFY_EBASE + 0x11l)
+
+/* This failure code indicates that the other side is not ready to receive
+ * notifications.
+ */
+#define NOTIFY_ENOTREADY (NOTIFY_EBASE + 0x12l)
+
+#endif /* !defined (NOTIFYERR_H) */
diff --git a/arch/arm/plat-omap/include/syslink/platform.h b/arch/arm/plat-omap/include/syslink/platform.h
new file mode 100644
index 00000000000..9dbae5cf152
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/platform.h
@@ -0,0 +1,44 @@
+/*
+ * platform.h
+ *
+ * Defines the platform functions to be used by SysMgr module.
+ *
+ * Copyright (C) 2009 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 _PLATFORM_H_
+#define _PLATFORM_H_
+
+#define PLATFORM_S_SUCCESS 0
+#define PLATFORM_E_FAIL -1
+#define PLATFORM_E_INVALIDARG -2
+
+/* =============================================================================
+ * APIs
+ * =============================================================================
+ */
+/* Function to setup the platform */
+s32 platform_setup(void);
+
+/* Function to destroy the platform */
+s32 platform_destroy(void);
+
+/* Function called when slave is loaded with executable */
+int platform_load_callback(u16 proc_id, void *arg);
+
+/* Function called when slave is in started state*/
+int platform_start_callback(u16 proc_id, void *arg);
+
+/* Function called when slave is stopped state */
+int platform_stop_callback(u16 proc_id, void *arg);
+
+#endif /* ifndef _PLATFORM_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/platform_mem.h b/arch/arm/plat-omap/include/syslink/platform_mem.h
new file mode 100644
index 00000000000..60d2c87d0f0
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/platform_mem.h
@@ -0,0 +1,136 @@
+/*
+ * platform_mem.c
+ *
+ * Target memory management interface implementation.
+ *
+ * This abstracts the Memory management interface in the kernel
+ * code. Allocation, Freeing-up, copy and address translate are
+ * supported for the kernel memory management.
+ *
+ * Copyright (C) 2008-2009 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 _PLATFORM_MEM_H_
+#define _PLATFORM_MEM_H_
+
+#include <linux/types.h>
+
+/*
+ * MEMORYOS_MODULEID
+ * Module ID for platform mem module
+ */
+#define PLATFORM_MEM_MODULEID (u16) 0x97D2
+
+/*
+ * Enumerates the types of caching for memory regions
+ */
+enum platform_mem_cache_flags {
+ PLATFORM_MEM_CACHE_FLAGS_DEFAULT = 0x00000000,
+ /* Default flags - Cached */
+ PLATFORM_MEM_CACHE_FLAGS_CACHED = 0x00010000,
+ /* Cached memory */
+ PLATFORM_MEM_CACHE_FLAGS_UNCACHED = 0x00020000,
+ /* Uncached memory */
+ PLATFORM_MEM_CACHE_FLAGS_END_VALUE = 0x00030000
+ /* End delimiter indicating start of invalid values for this enum */
+};
+
+/*
+ * Enumerates the types of memory allocation
+ */
+enum platform_mem_mtype_flags{
+ PLATFORM_MEM_MTYPE_FLAGS_DEFAULT = 0x00000000,
+ /* Default flags - virtually contiguous */
+ PLATFORM_MEM_MTYPE_FLAGS_PHYSICAL = 0x00000001,
+ /* Physically contiguous */
+ PLATFORM_MEM_MTYPE_FLAGS_DMA = 0x00000002,
+ /* Physically contiguous */
+ PLATFORM_MEM_MTYPE_FLAGS_END_VALUE = 0x00000003
+ /* End delimiter indicating start of invalid values for this enum */
+};
+
+/*
+ * Enumerates the types of translation
+ */
+enum memory_xlt_flags{
+ PLATFORM_MEM_XLT_FLAGS_VIRT2PHYS = 0x00000000,
+ /* Virtual to physical */
+ PLATFORM_MEM_XLT_FLAGS_PHYS2VIRT = 0x00000001,
+ /* Virtual to physical */
+ PLATFORM_MEM_XLT_FLAGS_END_VALUE = 0x00000002
+ /* End delimiter indicating start of invalid values for this enum */
+};
+
+/*
+ * Structure containing information required for mapping a
+ * memory region.
+ */
+struct platform_mem_map_info {
+ u32 src;
+ /* Address to be mapped. */
+ u32 size;
+ /* Size of memory region to be mapped. */
+ u32 dst;
+ /* Mapped address. */
+ bool is_cached;
+ /* Whether the mapping is to a cached area or uncached area. */
+ void *drv_handle;
+ /* Handle to the driver that is implementing the mmap call. Ignored for
+ Kernel-side version. */
+};
+
+/*
+ * Structure containing information required for unmapping a
+ * memory region.
+ */
+struct platform_mem_unmap_info {
+ u32 addr;
+ /* Address to be unmapped.*/
+ u32 size;
+ /* Size of memory region to be unmapped.*/
+ bool is_cached;
+ /* Whether the mapping is to a cached area or uncached area. */
+};
+
+/*
+ * Structure containing information required for mapping a
+ * memory region.
+ */
+#define memory_map_info struct platform_mem_map_info
+
+/*
+ * Structure containing information required for unmapping a
+ * memory region.
+ */
+#define memory_unmap_info struct platform_mem_unmap_info
+
+
+/* =============================================================================
+ * APIs
+ * =============================================================================
+ */
+/* Initialize the platform mem module. */
+int platform_mem_setup(void);
+
+/* Finalize the platform mem module. */
+int platform_mem_destroy(void);
+
+/* Maps a memory area into virtual space. */
+int platform_mem_map(memory_map_info *map_info);
+
+/* Unmaps a memory area into virtual space. */
+int platform_mem_unmap(memory_unmap_info *unmap_info);
+
+/* Translate API */
+void *platform_mem_translate(void *srcAddr, enum memory_xlt_flags flags);
+
+#endif /* ifndef _PLATFORM_MEM_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/procmgr.h b/arch/arm/plat-omap/include/syslink/procmgr.h
new file mode 100644
index 00000000000..5e538658a06
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/procmgr.h
@@ -0,0 +1,244 @@
+/*
+ * procmgr.h
+ *
+ * Syslink driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2009-2010 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 SYSLINK_PROC_MGR_H
+#define SYSLINK_PROC_MGR_H
+
+#include <linux/types.h>
+#include <syslink/multiproc.h>
+
+
+
+#define PROCMGR_MODULEID 0xf2ba
+
+/*
+ * Maximum name length for ProcMgr module strings.
+ */
+#define PROCMGR_MAX_STRLEN 32
+
+/*
+ * Maximum number of memory regions supported by ProcMgr module.
+ */
+#define PROCMGR_MAX_MEMORY_REGIONS 32
+
+/*
+ * IS_VALID_PROCID
+ * Checks if the Processor ID is valid
+ */
+#define IS_VALID_PROCID(id) (id < MULTIPROC_MAXPROCESSORS)
+
+
+/*
+ * Enumerations to indicate Processor states.
+ */
+enum proc_mgr_state {
+ PROC_MGR_STATE_UNKNOWN = 0,
+ /* Unknown Processor state (e.g. at startup or error). */
+ PROC_MGR_STATE_POWERED = 1,
+ /* Indicates the Processor is powered up. */
+ PROC_MGR_STATE_RESET = 2,
+ /* Indicates the Processor is reset. */
+ PROC_MGR_STATE_LOADED = 3,
+ /* Indicates the Processor is loaded. */
+ PROC_MGR_STATE_RUNNNING = 4,
+ /* Indicates the Processor is running. */
+ PROC_MGR_STATE_UNAVAILABLE = 5,
+ /* Indicates the Processor is unavailable to the physical transport. */
+ PROC_MGR_STATE_ENDVALUE = 6
+ /* End delimiter indicating start of invalid values for this enum */
+};
+
+/*
+ * Enumerations to indicate different types of slave boot modes.
+ */
+enum proc_mgr_boot_mode {
+ PROC_MGR_BOOTMODE_BOOT = 0,
+ /* ProcMgr is responsible for loading the slave and its reset control */
+ PROC_MGR_BOOTMODE_NOLOAD = 1,
+ /* ProcMgr is not responsible for loading the slave. It is responsible
+ for reset control of the slave. */
+ PROC_MGR_BOOTMODE_NOBOOT = 2,
+ /* ProcMgr is not responsible for loading or reset control of the slave.
+ The slave either self-boots, or this is done by some entity outside of
+ the ProcMgr module. */
+ PROC_MGR_BOOTMODE_ENDVALUE = 3
+ /* End delimiter indicating start of invalid values for this enum */
+} ;
+
+/*
+ * Enumerations to indicate address types used for translation
+ */
+enum proc_mgr_addr_type{
+ PROC_MGR_ADDRTYPE_MASTERKNLVIRT = 0,
+ /* Kernel Virtual address on master processor */
+ PROC_MGR_ADDRTYPE_MASTERUSRVIRT = 1,
+ /* User Virtual address on master processor */
+ PROC_MGR_ADDRTYPE_SLAVEVIRT = 2,
+ /* Virtual address on slave processor */
+ PROC_MGR_ADDRTYPE_ENDVALUE = 3
+ /* End delimiter indicating start of invalid values for this enum */
+};
+
+/*
+ * Enumerations to indicate types of address mapping
+ */
+enum proc_mgr_map_type {
+ PROC_MGR_MAPTYPE_VIRT = 0,
+ /* Map/unmap to virtual address space (kernel/user) */
+ PROC_MGR_MAPTYPE_SLAVE = 1,
+ /* Map/unmap to slave address space */
+ PROC_MGR_MAPTYPE_ENDVALUE = 2
+ /* End delimiter indicating start of invalid values for this enum */
+};
+
+/*
+ * Module configuration structure.
+ */
+struct proc_mgr_config {
+ void *gate_handle;
+} ;
+
+/*
+ * Configuration parameters specific to the slave ProcMgr instance.
+ */
+struct proc_mgr_params {
+ void *proc_handle;
+ /* void * to the Processor object associated with this ProcMgr. */
+ void *loader_handle;
+ /*!< Handle to the Loader object associated with this ProcMgr. */
+ void *pwr_handle;
+ /*!< Handle to the PwrMgr object associated with this ProcMgr. */
+};
+
+/*
+ * Configuration parameters specific to the slave ProcMgr instance.
+ */
+struct proc_mgr_attach_params {
+ enum proc_mgr_boot_mode boot_mode;
+ /* Boot mode for the slave processor. */
+} ;
+
+
+/*
+ * This structure defines information about memory regions mapped by
+ * the ProcMgr module.
+ */
+struct proc_mgr_addr_info {
+/* bool is_init; */
+ unsigned short is_init;
+ /* Is this memory region initialized? */
+ u32 addr[PROC_MGR_ADDRTYPE_ENDVALUE];
+ /* Addresses for each type of address space */
+ u32 size;
+ /* Size of the memory region in bytes */
+};
+
+/*
+ * Characteristics of the slave processor
+ */
+struct proc_mgr_proc_info {
+ enum proc_mgr_boot_mode boot_mode;
+ /* Boot mode of the processor. */
+ u16 num_mem_entries;
+ /* Number of valid memory entries */
+ struct proc_mgr_addr_info mem_entries[PROCMGR_MAX_MEMORY_REGIONS];
+ /* Configuration of memory regions */
+};
+
+
+/*
+ * Function pointer type that is passed to the proc_mgr_registerNotify function
+*/
+typedef int (*proc_mgr_callback_fxn)(u16 proc_id, void *handle,
+ enum proc_mgr_state from_state, enum proc_mgr_state to_state);
+
+/* Function to get the default configuration for the ProcMgr module. */
+void proc_mgr_get_config(struct proc_mgr_config *cfg);
+
+/* Function to setup the ProcMgr module. */
+int proc_mgr_setup(struct proc_mgr_config *cfg);
+
+/* Function to destroy the ProcMgr module. */
+int proc_mgr_destroy(void);
+
+/* Function to initialize the parameters for the ProcMgr instance. */
+void proc_mgr_params_init(void *handle, struct proc_mgr_params *params);
+
+/* Function to create a ProcMgr object for a specific slave processor. */
+void *proc_mgr_create(u16 proc_id, const struct proc_mgr_params *params);
+
+/* Function to delete a ProcMgr object for a specific slave processor. */
+int proc_mgr_delete(void **handle_ptr);
+
+/* Function to open a handle to an existing ProcMgr object handling the
+ * proc_id.
+ */
+int proc_mgr_open(void **handle, u16 proc_id);
+
+/* Function to close this handle to the ProcMgr instance. */
+int proc_mgr_close(void *handle);
+
+/* Function to initialize the parameters for the ProcMgr attach function. */
+void proc_mgr_get_attach_params(void *handle,
+ struct proc_mgr_attach_params *params);
+
+/* Function to attach the client to the specified slave and also initialize the
+ * slave(if required).
+ */
+int proc_mgr_attach(void *handle, struct proc_mgr_attach_params *params);
+
+/* Function to detach the client from the specified slave and also finalze the
+ * slave(if required).
+ */
+int proc_mgr_detach(void *handle);
+
+/* Function to get the current state of the slave Processor as maintained on
+ * the master Processor state machine.
+ */
+enum proc_mgr_state proc_mgr_get_state(void *handle);
+
+/* Function to read from the slave Processor's memory space. */
+int proc_mgr_read(void *handle, u32 proc_addr, u32 *num_bytes,
+ void *buffer);
+
+/* Function to read from the slave Processor's memory space. */
+int proc_mgr_write(void *handle, u32 proc_addr, u32 *num_bytes, void *buffer);
+
+/* Function that provides a hook for performing device dependent operations on
+ * the slave Processor.
+ */
+int proc_mgr_control(void *handle, int cmd, void *arg);
+
+int proc_mgr_translate_addr(void *handle, void **dst_addr,
+ enum proc_mgr_addr_type dst_addr_type, void *src_addr,
+ enum proc_mgr_addr_type src_addr_type);
+
+/* Function that registers for notification when the slave processor
+ * transitions to any of the states specified.
+ */
+int proc_mgr_register_notify(void *handle, proc_mgr_callback_fxn fxn,
+ void *args, enum proc_mgr_state state[]);
+
+/* Function that returns information about the characteristics of the slave
+ * processor.
+ */
+int proc_mgr_get_proc_info(void *handle, struct proc_mgr_proc_info *proc_info);
+
+/* Function that returns virtual to physical translations
+ */
+int proc_mgr_virt_to_phys(void *handle, u32 da, u32 *mapped_entries,
+ u32 num_of_entries);
+
+#endif
diff --git a/arch/arm/plat-omap/include/syslink/sharedregion.h b/arch/arm/plat-omap/include/syslink/sharedregion.h
new file mode 100644
index 00000000000..ca644e7ebcd
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/sharedregion.h
@@ -0,0 +1,244 @@
+/*
+ * sharedregion.h
+ *
+ * The SharedRegion module is designed to be used in a
+ * multi-processor environment where there are memory regions
+ * that are shared and accessed across different processors
+ *
+ * Copyright (C) 2008-2010 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 _SHAREDREGION_H_
+#define _SHAREDREGION_H_
+
+#include <linux/types.h>
+#include <heapmemmp.h>
+
+/*
+ * SHAREDREGION_MODULEID
+ * Module ID for Shared region manager
+ */
+#define SHAREDREGION_MODULEID (0x5D8A)
+
+/*
+ * Name of the reserved nameserver used for application
+ */
+#define SHAREDREGION_NAMESERVER "SHAREDREGION"
+
+/*
+ * Name of the reserved nameserver used for application
+ */
+#define SHAREDREGION_INVALIDREGIONID ((u16)(~0))
+
+/*!
+ * @def SharedRegion_DEFAULTOWNERID
+ * @brief Default owner processor id
+ */
+#define SHAREDREGION_DEFAULTOWNERID ((u16)(~0))
+
+/*
+ * Name of the reserved nameserver used for application
+ */
+#define SHAREDREGION_INVALIDSRPTR ((u32 *)(~0))
+
+
+struct sharedregion_entry {
+ /* The base address of the region */
+ void *base;
+ /* The length of the region */
+ uint len;
+ /* The MultiProc id of the owner of the region */
+ u16 owner_proc_id;
+ /* Whether the region is valid */
+ bool is_valid;
+ /* Whether to perform cache operations for the region */
+ bool cache_enable;
+ /* The cache line size of the region */
+ uint cache_line_size;
+ /* Whether a heap is created for the region */
+ bool create_heap;
+ /* The name of the region */
+ char *name;
+};
+
+/*
+ * Module configuration structure
+ */
+struct sharedregion_config {
+ uint cache_line_size;
+ /*
+ * Worst-case cache line size
+ *
+ * This is the default system cache line size for all modules.
+ * When a module puts structures in shared memory, this value is
+ * used to make sure items are aligned on a cache line boundary.
+ * If no cacheLineSize is specified for a region, it will use this
+ * value.
+ */
+
+ u16 num_entries;
+ /*
+ * The number of shared region table entries.
+ *
+ * This value is used for calculating the number of bits for the offset.
+ * Note: This value must be the same across all processors in the
+ * system. Increasing this parameter will increase the footprint
+ * and the time for translating a pointer to a SRPtr.
+ */
+
+ bool translate;
+ /*
+ * This configuration parameter should be set to 'true'
+ * if and only if all shared memory regions are the same
+ * for all processors. If 'true', it results in a fast
+ * getPtr and getSRPtr.
+ */
+};
+
+/*
+ * Information stored on a per region basis
+ */
+struct sharedregion_region {
+ struct sharedregion_entry entry;
+ uint reserved_size;
+ struct heapmemmp_object *heap;
+};
+
+
+/*
+ * Function to get the configuration
+ */
+int sharedregion_get_config(struct sharedregion_config *config);
+
+/*
+ * Function to setup the SharedRegion module
+ */
+int sharedregion_setup(const struct sharedregion_config *config);
+
+/*
+ * Function to destroy the SharedRegion module
+ */
+int sharedregion_destroy(void);
+
+/*
+ * Creates a heap by owner of region for each SharedRegion.
+ * Function is called by ipc_start(). Requires that SharedRegion 0
+ * be valid before calling start().
+ */
+int sharedregion_start(void);
+
+/*
+ * Function to stop Shared Region 0
+ */
+int sharedregion_stop(void);
+
+/*
+ * Opens a heap, for non-owner processors, for each SharedRegion.
+ */
+int sharedregion_attach(u16 remote_proc_id);
+
+/*
+ * Closes a heap, for non-owner processors, for each SharedRegion.
+ */
+int sharedregion_detach(u16 remote_proc_id);
+
+/*
+ * Reserve shared region memory
+ */
+void *sharedregion_reserve_memory(u16 id, u32 size);
+
+/*
+ * Reserve shared region memory
+ */
+void sharedregion_unreserve_memory(u16 id, u32 size);
+
+/*
+ * Sets the entry at the specified region id(doesn't create heap)
+ */
+int _sharedregion_set_entry(u16 region_id, struct sharedregion_entry *entry);
+
+/*
+ * Function to clear the reserved memory
+ */
+void sharedregion_clear_reserved_memory(void);
+
+/*
+ * Return the region info
+ */
+void sharedregion_get_region_info(u16 i, struct sharedregion_region *region);
+
+/*
+ * Clears the entry at the specified region id
+ */
+int sharedregion_clear_entry(u16 region_id);
+
+/*
+ * Initializes the entry fields
+ */
+void sharedregion_entry_init(struct sharedregion_entry *entry);
+
+/*
+ * Gets the cache line size for the specified region id
+ */
+uint sharedregion_get_cache_line_size(u16 region_id);
+
+/*
+ * Gets the entry information for the specified region id
+ */
+int sharedregion_get_entry(u16 region_id, struct sharedregion_entry *entry);
+
+/*
+ * Gets the heap associated with the specified region id
+ */
+void *sharedregion_get_heap(u16 region_id);
+
+/*
+ * Gets the region id for the specified address
+ */
+u16 sharedregion_get_id(void *addr);
+
+/*
+ * Gets the id of a region, given the name
+ */
+u16 sharedregion_get_id_by_name(char *name);
+
+/*
+ * Gets the number of regions
+ */
+u16 sharedregion_get_num_regions(void);
+
+/*
+ * Returns the address pointer associated with the shared region pointer
+ */
+void *sharedregion_get_ptr(u32 *srptr);
+
+/*
+ * Returns the shared region pointer
+ */
+u32 *sharedregion_get_srptr(void *addr, u16 index);
+
+/*
+ * whether cache enable was specified
+ */
+bool sharedregion_is_cache_enabled(u16 region_id);
+
+/*
+ * Sets the entry at the specified region id
+ */
+int sharedregion_set_entry(u16 region_id, struct sharedregion_entry *entry);
+
+/*
+ * Whether address translation is enabled
+ */
+bool sharedregion_translate_enabled(void);
+
+#endif /* _SHAREDREGION_H */
diff --git a/arch/arm/plat-omap/include/syslink/sharedregion_ioctl.h b/arch/arm/plat-omap/include/syslink/sharedregion_ioctl.h
new file mode 100644
index 00000000000..adff03f0434
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/sharedregion_ioctl.h
@@ -0,0 +1,189 @@
+/*
+ * sharedregion_ioctl.h
+ *
+ * The sharedregion module is designed to be used in a
+ * multi-processor environment where there are memory regions
+ * that are shared and accessed across different processors
+ *
+ * Copyright (C) 2008-2010 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 _SHAREDREGION_IOCTL_H
+#define _SHAREDREGION_IOCTL_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#include <ipc_ioctl.h>
+#include <sharedregion.h>
+
+enum CMD_SHAREDREGION {
+ SHAREDREGION_GETCONFIG = SHAREDREGION_BASE_CMD,
+ SHAREDREGION_SETUP,
+ SHAREDREGION_DESTROY,
+ SHAREDREGION_START,
+ SHAREDREGION_STOP,
+ SHAREDREGION_ATTACH,
+ SHAREDREGION_DETACH,
+ SHAREDREGION_GETHEAP,
+ SHAREDREGION_CLEARENTRY,
+ SHAREDREGION_SETENTRY,
+ SHAREDREGION_RESERVEMEMORY,
+ SHAREDREGION_CLEARRESERVEDMEMORY,
+ SHAREDREGION_GETREGIONINFO
+};
+
+/*
+ * IOCTL command IDs for sharedregion
+ *
+ */
+
+/*
+ * Command for sharedregion_get_config
+ */
+#define CMD_SHAREDREGION_GETCONFIG _IOWR(IPC_IOC_MAGIC, \
+ SHAREDREGION_GETCONFIG, \
+ struct sharedregion_cmd_args)
+/*
+ * Command for sharedregion_setup
+ */
+#define CMD_SHAREDREGION_SETUP _IOWR(IPC_IOC_MAGIC, \
+ SHAREDREGION_SETUP, \
+ struct sharedregion_cmd_args)
+/*
+ * Command for sharedregion_setup
+ */
+#define CMD_SHAREDREGION_DESTROY _IOWR(IPC_IOC_MAGIC, \
+ SHAREDREGION_DESTROY, \
+ struct sharedregion_cmd_args)
+/*
+ * Command for sharedregion_start
+ */
+#define CMD_SHAREDREGION_START _IOWR(IPC_IOC_MAGIC, \
+ SHAREDREGION_START, \
+ struct sharedregion_cmd_args)
+/*
+ * Command for sharedregion_stop
+ */
+#define CMD_SHAREDREGION_STOP _IOWR(IPC_IOC_MAGIC, \
+ SHAREDREGION_STOP, \
+ struct sharedregion_cmd_args)
+/*
+ * Command for sharedregion_attach
+ */
+#define CMD_SHAREDREGION_ATTACH _IOWR(IPC_IOC_MAGIC, \
+ SHAREDREGION_ATTACH, \
+ struct sharedregion_cmd_args)
+/*
+ * Command for sharedregion_detach
+ */
+#define CMD_SHAREDREGION_DETACH _IOWR(IPC_IOC_MAGIC, \
+ SHAREDREGION_DETACH, \
+ struct sharedregion_cmd_args)
+/*
+ * Command for sharedregion_get_heap
+ */
+#define CMD_SHAREDREGION_GETHEAP _IOWR(IPC_IOC_MAGIC, \
+ SHAREDREGION_GETHEAP, \
+ struct sharedregion_cmd_args)
+/*
+ * Command for sharedregion_clear_entry
+ */
+#define CMD_SHAREDREGION_CLEARENTRY _IOWR(IPC_IOC_MAGIC, \
+ SHAREDREGION_CLEARENTRY, \
+ struct sharedregion_cmd_args)
+/*
+ * Command for sharedregion_set_entry
+ */
+#define CMD_SHAREDREGION_SETENTRY _IOWR(IPC_IOC_MAGIC, \
+ SHAREDREGION_SETENTRY, \
+ struct sharedregion_cmd_args)
+/*
+ * Command for sharedregion_reserve_memory
+ */
+#define CMD_SHAREDREGION_RESERVEMEMORY _IOWR(IPC_IOC_MAGIC, \
+ SHAREDREGION_RESERVEMEMORY, \
+ struct sharedregion_cmd_args)
+/*
+ * Command for sharedregion_clear_reserved_memory
+ */
+#define CMD_SHAREDREGION_CLEARRESERVEDMEMORY \
+ _IOWR(IPC_IOC_MAGIC, \
+ SHAREDREGION_CLEARRESERVEDMEMORY, \
+ struct sharedregion_cmd_args)
+/*
+ * Command for sharedregion_get_region_info
+ */
+#define CMD_SHAREDREGION_GETREGIONINFO _IOWR(IPC_IOC_MAGIC, \
+ SHAREDREGION_GETREGIONINFO, \
+ struct sharedregion_cmd_args)
+
+/*
+ * Command arguments for sharedregion
+ */
+union sharedregion_arg {
+ struct {
+ struct sharedregion_config *config;
+ } get_config;
+
+ struct {
+ struct sharedregion_region *regions;
+ struct sharedregion_config *config;
+ } setup;
+
+ struct {
+ struct sharedregion_region *regions;
+ } get_region_info;
+
+ struct {
+ u16 remote_proc_id;
+ } attach;
+
+ struct {
+ u16 remote_proc_id;
+ } detach;
+
+ struct {
+ u16 id;
+ void *heap_handle;
+ } get_heap;
+
+ struct {
+ u16 id;
+ struct sharedregion_entry entry;
+ } set_entry;
+
+ struct {
+ u16 id;
+ } clear_entry;
+
+ struct {
+ u16 id;
+ u32 size;
+ } reserve_memory;
+};
+
+/*
+ * Command arguments for sharedregion
+ */
+struct sharedregion_cmd_args {
+ union sharedregion_arg args;
+ s32 api_status;
+};
+
+/*
+ * This ioctl interface for sharedregion module
+ */
+int sharedregion_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user);
+
+#endif /* _SHAREDREGION_IOCTL_H */
diff --git a/arch/arm/plat-omap/include/syslink/sysipc_ioctl.h b/arch/arm/plat-omap/include/syslink/sysipc_ioctl.h
new file mode 100644
index 00000000000..d6f4428e716
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/sysipc_ioctl.h
@@ -0,0 +1,118 @@
+/*
+ * sysipc_ioctl.h
+ *
+ * Definitions of sysmgr driver types and structures..
+ *
+ * Copyright (C) 2008-2009 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 _SYSIPC_IOCTL_H_
+#define _SYSIPC_IOCTL_H_
+
+/* Standard headers */
+#include <linux/types.h>
+
+/* Syslink headers */
+#include <ipc_ioctl.h>
+#include <ipc.h>
+
+
+/* =============================================================================
+ * Macros and types
+ * =============================================================================
+ */
+/* ----------------------------------------------------------------------------
+ * IOCTL command IDs for sysmgr
+ * ----------------------------------------------------------------------------
+ */
+/* IOC Magic Number for sysmgr */
+#define SYSIPC_IOC_MAGIC IPC_IOC_MAGIC
+
+/* IOCTL command numbers for ipc/sysipc */
+enum sysipc_drv_cmd {
+ IPC_SETUP = IPC_BASE_CMD,
+ IPC_DESTROY,
+ IPC_CONTROL,
+ IPC_READCONFIG,
+ IPC_WRITECONFIG
+ };
+
+/* Command for ipc_setup */
+#define CMD_IPC_SETUP \
+ _IOWR(SYSIPC_IOC_MAGIC, IPC_SETUP, \
+ struct sysipc_cmd_args)
+
+/* Command for ipc_destroy */
+#define CMD_IPC_DESTROY \
+ _IOWR(SYSIPC_IOC_MAGIC, IPC_DESTROY, \
+ struct sysipc_cmd_args)
+
+/* Command for load callback */
+#define CMD_IPC_CONTROL \
+ _IOWR(SYSIPC_IOC_MAGIC, IPC_CONTROL, \
+ struct sysipc_cmd_args)
+
+/* Command for ipc_read_config */
+#define CMD_IPC_READCONFIG \
+ _IOWR(SYSIPC_IOC_MAGIC, IPC_READCONFIG, \
+ struct sysipc_cmd_args)
+
+/* Command for ipc_write_config */
+#define CMD_IPC_WRITECONFIG \
+ _IOWR(SYSIPC_IOC_MAGIC, IPC_WRITECONFIG, \
+ struct sysipc_cmd_args)
+
+
+/* ----------------------------------------------------------------------------
+ * Command arguments for sysmgr
+ * ----------------------------------------------------------------------------
+ */
+/* Command arguments for sysmgr */
+struct sysipc_cmd_args {
+ union {
+ struct {
+ u16 proc_id;
+ s32 cmd_id;
+ void *arg;
+ } control;
+
+ struct {
+ u16 remote_proc_id;
+ u32 tag;
+ void *cfg;
+ u32 size;
+ } read_config;
+
+ struct {
+ u16 remote_proc_id;
+ u32 tag;
+ void *cfg;
+ u32 size;
+ } write_config;
+
+ struct {
+ struct ipc_config *config;
+ } setup;
+ } args;
+
+ s32 api_status;
+};
+
+/* ----------------------------------------------------------------------------
+ * IOCTL functions for sysmgr module
+ * ----------------------------------------------------------------------------
+ */
+/* ioctl interface function for sysmgr */
+int sysipc_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user);
+
+#endif /* _SYSIPC_IOCTL_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/sysmemmgr.h b/arch/arm/plat-omap/include/syslink/sysmemmgr.h
new file mode 100644
index 00000000000..34c3b418228
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/sysmemmgr.h
@@ -0,0 +1,179 @@
+/*
+ * sysmemmgr.h
+ *
+ * Manager for the Slave system memory. Slave system level memory is allocated
+ * through this module.
+ *
+ * Copyright (C) 2009 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 _SYSTEMMEMORYMANAGER_H_
+#define _SYSTEMMEMORYMANAGER_H_
+
+
+/*!
+ * @def SYSMEMMGR_MODULEID
+ * @brief Module identifier for System memory manager.
+ */
+#define SYSMEMMGR_MODULEID (0xb53d)
+
+/*!
+ * @def SYSMEMMGR_STATUSCODEBASE
+ * @brief Error code base for system memory manager module.
+ */
+#define SYSMEMMGR_STATUSCODEBASE (SYSMEMMGR_MODULEID << 12u)
+
+/*!
+ * @def SYSMEMMGR_MAKE_ERROR
+ * @brief Macro to make error code.
+ */
+#define SYSMEMMGR_MAKE_ERROR(x) ((int)(0x80000000 + \
+ (SYSMEMMGR_STATUSCODEBASE + \
+ (x))))
+
+/*!
+ * @def SYSMEMMGR_MAKE_SUCCESS
+ * @brief Macro to make success code.
+ */
+#define SYSMEMMGR_MAKE_SUCCESS(x) (SYSMEMMGR_STATUSCODEBASE + (x))
+
+/*!
+ * @def SYSMEMMGR_E_CREATEALLOCATOR
+ * @brief Static allocator creation failed.
+ */
+#define SYSMEMMGR_E_CREATEALLOCATOR SYSMEMMGR_MAKE_ERROR(1)
+
+/*!
+ * @def SYSMEMMGR_E_CREATELOCK
+ * @brief Mutex lock creation failed.
+ */
+#define SYSMEMMGR_E_CREATELOCK SYSMEMMGR_MAKE_ERROR(2)
+
+/*!
+ * @def SYSMEMMGR_E_INVALIDSTATE
+ * @brief Module is not initialized.
+ */
+#define SYSMEMMGR_E_INVALIDSTATE SYSMEMMGR_MAKE_ERROR(3)
+
+/*!
+ * @def SYSMEMMGR_E_INVALIDARG
+ * @brief Argument passed to a function is invalid.
+ */
+#define SYSMEMMGR_E_INVALIDARG SYSMEMMGR_MAKE_ERROR(4)
+
+/*!
+ * @def SYSMEMMGR_E_BPAFREE
+ * @brief Freeing to buddy allocator failed.
+ */
+#define SYSMEMMGR_E_BPAFREE SYSMEMMGR_MAKE_ERROR(5)
+
+/*!
+ * @def SYSMEMMGR_E_MEMORY
+ * @brief Memory allocation failed.
+ */
+#define SYSMEMMGR_E_MEMORY SYSMEMMGR_MAKE_ERROR(6)
+
+/*!
+ * @def SYSMEMMGR_SUCCESS
+ * @brief Operation successful.
+ */
+#define SYSMEMMGR_SUCCESS SYSMEMMGR_MAKE_SUCCESS(0)
+
+/*!
+ * @def SYSMEMMGR_S_ALREADYSETUP
+ * @brief Module already initialized.
+ */
+#define SYSMEMMGR_S_ALREADYSETUP SYSMEMMGR_MAKE_SUCCESS(1)
+
+/*!
+ * @def SYSMEMMGR_S_DRVALREADYOPENED
+ * @brief Internal OS Driver is already opened.
+ */
+#define SYSMEMMGR_S_DRVALREADYOPENED SYSMEMMGR_MAKE_SUCCESS(2)
+
+/*!
+ * @brief Configuration data structure of system memory manager.
+ */
+struct sysmemmgr_config {
+ u32 sizeof_valloc;
+ /* Total size for virtual memory allocation */
+ u32 sizeof_palloc;
+ /* Total size for physical memory allocation */
+ u32 static_phys_base_addr;
+ /* Physical address of static memory region */
+ u32 static_virt_base_addr;
+ /* Virtual address of static memory region */
+ u32 static_mem_size;
+ /* size of static memory region */
+ u32 page_size;
+ /* Page size */
+ u32 event_no;
+ /* Event number to be used */
+};
+
+/*!
+ * @brief Flag used for allocating memory blocks.
+ */
+enum sysmemmgr_allocflag {
+ sysmemmgr_allocflag_uncached = 0u,
+ /* Flag used for allocating uncacheable block */
+ sysmemmgr_allocflag_cached = 1u,
+ /* Flag used for allocating cacheable block */
+ sysmemmgr_allocflag_physical = 2u,
+ /* Flag used for allocating physically contiguous block */
+ sysmemmgr_allocflag_virtual = 3u,
+ /* Flag used for allocating virtually contiguous block */
+ sysmemmgr_allocflag_dma = 4u
+ /* Flag used for allocating DMAable (physically contiguous) block */
+};
+
+/*!
+ * @brief Flag used for translating address.
+ */
+enum sysmemmgr_xltflag {
+ sysmemmgr_xltflag_kvirt2phys = 0x0001u,
+ /* Flag used for converting Kernel virtual address to physical
+ * address */
+ sysmemmgr_xltflag_kvirt2uvirt = 0x0002u,
+ /* Flag used for converting Kernel virtual address to user virtual
+ * address */
+ sysmemmgr_xltflag_uvirt2phys = 0x0003u,
+ /* Flag used for converting user virtual address to physical address */
+ sysmemmgr_xltflag_uvirt2kvirt = 0x0004u,
+ /* Flag used for converting user virtual address to Kernel virtual
+ * address */
+ sysmemmgr_xltflag_phys2kvirt = 0x0005u,
+ /* Flag used for converting physical address to user virtual address */
+ sysmemmgr_xltflag_phys2uvirt = 0x0006u
+ /* Flag used for converting physical address to Kernel virtual
+ * address */
+};
+
+
+/* Function prototypes */
+void sysmemmgr_get_config(struct sysmemmgr_config *config);
+
+int sysmemmgr_setup(struct sysmemmgr_config *params);
+
+int sysmemmgr_destroy(void);
+
+int sysmemmgr_attach(u16 slave_id);
+
+void *sysmemmgr_alloc(u32 size, enum sysmemmgr_allocflag flag);
+
+int sysmemmgr_free(void *blk, u32 size, enum sysmemmgr_allocflag flag);
+
+void *sysmemmgr_translate(void *srcAddr, enum sysmemmgr_xltflag flag);
+
+
+#endif /* _SYSTEMMEMORYMANAGER_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/sysmemmgr_ioctl.h b/arch/arm/plat-omap/include/syslink/sysmemmgr_ioctl.h
new file mode 100644
index 00000000000..4b0d9961556
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/sysmemmgr_ioctl.h
@@ -0,0 +1,130 @@
+/*
+ * sysmemmgr_ioctl.h
+ *
+ * Definitions of sysmemmgr driver types and structures..
+ *
+ * Copyright (C) 2008-2009 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 _SYSMEMMGR_IOCTL_H_
+#define _SYSMEMMGR_IOCTL_H_
+
+/* Standard headers */
+#include <linux/types.h>
+
+/* Syslink headers */
+#include <ipc_ioctl.h>
+#include <sysmgr.h>
+
+
+/* =============================================================================
+ * Macros and types
+ * =============================================================================
+ */
+/* ----------------------------------------------------------------------------
+ * IOCTL command IDs for sysmemmgr
+ * ----------------------------------------------------------------------------
+ */
+/* IOC Magic Number for sysmemmgr */
+#define SYSMEMMGR_IOC_MAGIC IPC_IOC_MAGIC
+
+/* IOCTL command numbers for sysmemmgr */
+enum sysmemmgr_drv_cmd {
+ SYSMEMMGR_GETCONFIG = SYSMEMMGR_BASE_CMD,
+ SYSMEMMGR_SETUP,
+ SYSMEMMGR_DESTROY,
+ SYSMEMMGR_ALLOC,
+ SYSMEMMGR_FREE,
+ SYSMEMMGR_TRANSLATE
+};
+
+/* Command for sysmemmgr_getConfig */
+#define CMD_SYSMEMMGR_GETCONFIG \
+ _IOWR(SYSMEMMGR_IOC_MAGIC, SYSMEMMGR_GETCONFIG, \
+ struct sysmemmgr_cmd_args)
+
+/* Command for sysmemmgr_setup */
+#define CMD_SYSMEMMGR_SETUP \
+ _IOWR(SYSMEMMGR_IOC_MAGIC, SYSMEMMGR_SETUP, \
+ struct sysmemmgr_cmd_args)
+
+/* Command for sysmemmgr_destroy */
+#define CMD_SYSMEMMGR_DESTROY \
+ _IOWR(SYSMEMMGR_IOC_MAGIC, SYSMEMMGR_DESTROY, \
+ struct sysmemmgr_cmd_args)
+
+/* Command for sysmemmgr_alloc */
+#define CMD_SYSMEMMGR_ALLOC \
+ _IOWR(SYSMEMMGR_IOC_MAGIC, SYSMEMMGR_ALLOC, \
+ struct sysmemmgr_cmd_args)
+
+/* Command for sysmemmgr_free */
+#define CMD_SYSMEMMGR_FREE \
+ _IOWR(SYSMEMMGR_IOC_MAGIC, SYSMEMMGR_FREE, \
+ struct sysmemmgr_cmd_args)
+
+/* Command for sysmemmgr_translate */
+#define CMD_SYSMEMMGR_TRANSLATE \
+ _IOWR(SYSMEMMGR_IOC_MAGIC, SYSMEMMGR_TRANSLATE, \
+ struct sysmemmgr_cmd_args)
+
+
+/* ----------------------------------------------------------------------------
+ * Command arguments for sysmemmgr
+ * ----------------------------------------------------------------------------
+ */
+/* Command arguments for sysmemmgr */
+struct sysmemmgr_cmd_args {
+ union {
+ struct {
+ struct sysmemmgr_config *config;
+ } get_config;
+
+ struct {
+ struct sysmemmgr_config *config;
+ } setup;
+
+ struct {
+ u32 size;
+ void *buf;
+ void *phys;
+ void *kbuf;
+ enum sysmemmgr_allocflag flags;
+ } alloc;
+
+ struct {
+ u32 size;
+ void *buf;
+ void *phys;
+ void *kbuf;
+ enum sysmemmgr_allocflag flags;
+ } free;
+
+ struct {
+ void *buf;
+ void *ret_ptr;
+ enum sysmemmgr_xltflag flags;
+ } translate;
+ } args;
+
+ s32 api_status;
+};
+
+/* ----------------------------------------------------------------------------
+ * IOCTL functions for sysmemmgr module
+ * ----------------------------------------------------------------------------
+ */
+/* ioctl interface function for sysmemmgr */
+int sysmemmgr_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long args);
+
+#endif /* SYSMEMMGR_DRVDEFS_H_0xF414 */
diff --git a/arch/arm/plat-omap/include/syslink/sysmgr.h b/arch/arm/plat-omap/include/syslink/sysmgr.h
new file mode 100644
index 00000000000..19fab220b2c
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/sysmgr.h
@@ -0,0 +1,182 @@
+/*
+ * sysmgr.h
+ *
+ * Defines for System manager.
+ *
+ * Copyright (C) 2009 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 _SYSMGR_H_
+#define _SYSMGR_H_
+
+
+/* Module headers */
+#include <multiproc.h>
+#include <gatepeterson.h>
+#include <sharedregion.h>
+#include <listmp.h>
+#include <listmp_sharedmemory.h>
+#include <messageq.h>
+#include <messageq_transportshm.h>
+#include <notify.h>
+#include <notify_ducatidriver.h>
+#include <nameserver.h>
+#include <nameserver_remote.h>
+#include <nameserver_remotenotify.h>
+#include <procmgr.h>
+#include <heap.h>
+#include <heapbuf.h>
+#include <sysmemmgr.h>
+
+
+/*!
+ * @def SYSMGR_MODULEID
+ * @brief Unique module ID.
+ */
+#define SYSMGR_MODULEID (0xF086)
+
+
+/* =============================================================================
+ * Module Success and Failure codes
+ * =============================================================================
+ */
+/*!
+ * @def SYSMGR_STATUSCODEBASE
+ * @brief Error code base for System manager.
+ */
+#define SYSMGR_STATUSCODEBASE (SYSMGR_MODULEID << 12u)
+
+/*!
+ * @def SYSMGR_MAKE_FAILURE
+ * @brief Macro to make error code.
+ */
+#define SYSMGR_MAKE_FAILURE(x) ((s32)(0x80000000 + \
+ (SYSMGR_STATUSCODEBASE + \
+ (x))))
+
+/*!
+ * @def SYSMGR_MAKE_SUCCESS
+ * @brief Macro to make success code.
+ */
+#define SYSMGR_MAKE_SUCCESS(x) (SYSMGR_STATUSCODEBASE + (x))
+
+/*!
+ * @def SYSMGR_E_INVALIDARG
+ * @brief Argument passed to a function is invalid.
+ */
+#define SYSMGR_E_INVALIDARG SYSMGR_MAKE_FAILURE(1)
+
+/*!
+ * @def SYSMGR_E_MEMORY
+ * @brief Memory allocation failed.
+ */
+#define SYSMGR_E_MEMORY SYSMGR_MAKE_FAILURE(2)
+
+/*!
+ * @def SYSMGR_E_FAIL
+ * @brief General failure.
+ */
+#define SYSMGR_E_FAIL SYSMGR_MAKE_FAILURE(3)
+
+/*!
+ * @def SYSMGR_E_INVALIDSTATE
+ * @brief Module is in invalid state.
+ */
+#define SYSMGR_E_INVALIDSTATE SYSMGR_MAKE_FAILURE(4)
+
+/*!
+ * @def SYSMGR_E_OSFAILURE
+ * @brief Failure in OS call.
+ */
+#define SYSMGR_E_OSFAILURE SYSMGR_MAKE_FAILURE(5)
+
+/*!
+ * @def SYSMGR_S_ALREADYSETUP
+ * @brief Module is already initialized.
+ */
+#define SYSMGR_S_ALREADYSETUP SYSMGR_MAKE_SUCCESS(1)
+
+/*!
+ * @def SYSMGR_CMD_SCALABILITY
+ * @brief Command ID for scalability info.
+ */
+#define SYSMGR_CMD_SCALABILITY (0x00000000)
+
+/*!
+ * @def SYSMGR_CMD_SHAREDREGION_ENTRY_BASE
+ * @brief Base of command IDs for entries used by Shared region.
+ */
+#define SYSMGR_CMD_SHAREDREGION_ENTRY_START (0x00000001)
+#define SYSMGR_CMD_SHAREDREGION_ENTRY_END (0x00001000)
+
+
+/* =============================================================================
+ * Structures & Enums
+ * =============================================================================
+ */
+/*!
+ * @brief Structure defining config parameters for overall System.
+ */
+struct sysmgr_config {
+ struct sysmemmgr_config sysmemmgr_cfg;
+ /*!< System memory manager config parameter */
+
+ struct multiproc_config multiproc_cfg;
+ /*!< Multiproc config parameter */
+
+ struct gatepeterson_config gatepeterson_cfg;
+ /*!< Gatepeterson config parameter */
+
+ struct sharedregion_config sharedregion_cfg;
+ /*!< SharedRegion config parameter */
+
+ struct messageq_config messageq_cfg;
+ /*!< MessageQ config parameter */
+
+ struct notify_config notify_cfg;
+ /*!< Notify config parameter */
+
+ struct proc_mgr_config proc_mgr_cfg;
+ /*!< Processor manager config parameter */
+
+ struct heapbuf_config heapbuf_cfg;
+ /*!< Heap Buf config parameter */
+
+ struct listmp_config listmp_sharedmemory_cfg;
+ /*!< ListMPSharedMemory config parameter */
+
+ struct messageq_transportshm_config messageq_transportshm_cfg;
+ /*!< MessageQTransportShm config parameter */
+
+ struct notify_ducatidrv_config notify_ducatidrv_cfg;
+ /*!< NotifyDriverShm config parameter */
+
+ struct nameserver_remotenotify_config nameserver_remotenotify_cfg;
+ /*!< NameServerRemoteNotify config parameter */
+};
+
+
+/* =============================================================================
+ * APIs
+ * =============================================================================
+ */
+/* Function to initialize the parameter structure */
+void sysmgr_get_config(struct sysmgr_config *config);
+
+/* Function to initialize sysmgr module */
+s32 sysmgr_setup(const struct sysmgr_config *config);
+
+/* Function to Finalize sysmgr module */
+s32 sysmgr_destroy(void);
+
+
+#endif /* ifndef SYSMGR_H_0xF086 */
diff --git a/arch/arm/plat-omap/include/syslink/transportshm.h b/arch/arm/plat-omap/include/syslink/transportshm.h
new file mode 100644
index 00000000000..02a2b6a80c9
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/transportshm.h
@@ -0,0 +1,220 @@
+/*
+ * transportshm.h
+ *
+ * Shared memory based physical transport for
+ * communication with the remote processor.
+ *
+ * This file contains the declarations of types and APIs as part
+ * of interface of the shared memory transport.
+ *
+ * Copyright (C) 2008-2009 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 _TRANSPORTSHM_H_
+#define _TRANSPORTSHM_H_
+
+/* Standard headers */
+#include <linux/types.h>
+
+/* Utilities headers */
+#include <linux/list.h>
+
+/* =============================================================================
+ * All success and failure codes for the module
+ * =============================================================================
+ */
+/* Unique module ID. */
+#define TRANSPORTSHM_MODULEID (0x0a7a)
+
+/* =============================================================================
+ * All success and failure codes for the module
+ * =============================================================================
+ */
+/* Error code base for TransportShm. */
+#define TRANSPORTSHM_STATUSCODEBASE (TRANSPORTSHM_MODULEID << 12)
+
+/* Macro to make error code. */
+#define TRANSPORTSHM_MAKE_FAILURE(x) ((int) (0x80000000 \
+ + (TRANSPORTSHM_STATUSCODEBASE \
+ + (x))))
+
+/* Macro to make success code. */
+#define TRANSPORTSHM_MAKE_SUCCESS(x) (TRANSPORTSHM_STATUSCODEBASE + (x))
+
+/* Argument passed to a function is invalid. */
+#define TRANSPORTSHM_E_INVALIDARG TRANSPORTSHM_MAKE_FAILURE(1)
+
+/* Invalid shared address size */
+#define TRANSPORTSHM_E_INVALIDSIZE TRANSPORTSHM_MAKE_FAILURE(2)
+
+/* Module is not initialized. */
+#define TRANSPORTSHM_E_INVALIDSTATE TRANSPORTSHM_MAKE_FAILURE(3)
+
+/* Versions don't match */
+#define TRANSPORTSHM_E_BADVERSION TRANSPORTSHM_MAKE_FAILURE(4)
+
+/* General Failure */
+#define TRANSPORTSHM_E_FAIL TRANSPORTSHM_MAKE_FAILURE(5)
+
+/* Memory allocation failed */
+#define TRANSPORTSHM_E_MEMORY TRANSPORTSHM_MAKE_FAILURE(6)
+
+/* Failure in OS call. */
+#define TRANSPORTSHM_E_OSFAILURE TRANSPORTSHM_MAKE_FAILURE(7)
+
+/* Invalid handle specified. */
+#define TRANSPORTSHM_E_HANDLE TRANSPORTSHM_MAKE_FAILURE(8)
+
+/* The specified operation is not supported. */
+#define TRANSPORTSHM_E_NOTSUPPORTED TRANSPORTSHM_MAKE_FAILURE(9)
+
+/* Operation successful. */
+#define TRANSPORTSHM_SUCCESS TRANSPORTSHM_MAKE_SUCCESS(0)
+
+/* The MESSAGETRANSPORTSHM module has already been setup in this process. */
+#define TRANSPORTSHM_S_ALREADYSETUP TRANSPORTSHM_MAKE_SUCCESS(1)
+
+
+/* =============================================================================
+ * Structures & Enums
+ * =============================================================================
+ */
+
+/*
+ * Structure defining the reason for error function being called
+ */
+enum transportshm_reason {
+ TRANSPORTSHM_REASON_FAILEDPUT,
+ /* Failed to send the message. */
+ TRANSPORTSHM_REASON_INTERNALERR,
+ /* An internal error occurred in the transport */
+ TRANSPORTSHM_REASON_PHYSICALERR,
+ /* An error occurred in the physical link in the transport */
+ TRANSPORTSHM_REASON_FAILEDALLOC
+ /* Failed to allocate a message. */
+};
+
+/*
+ * transport error callback function.
+ *
+ * First parameter: Why the error function is being called.
+ *
+ * Second parameter: Handle of transport that had the error. NULL denotes
+ * that it is a system error, not a specific transport.
+ *
+ * Third parameter: Pointer to the message. This is only valid for
+ * #TRANSPORTSHM_REASON_FAILEDPUT.
+ *
+ * Fourth parameter: Transport specific information. Refer to individual
+ * transports for more details.
+ */
+
+/*
+ * Module configuration structure.
+ */
+struct transportshm_config {
+ void (*err_fxn)(enum transportshm_reason reason,
+ void *handle,
+ void *msg,
+ u32 info);
+ /* Asynchronous error function for the transport module */
+};
+
+/*
+ * Structure defining config parameters for the transport
+ * instances.
+ */
+struct transportshm_params {
+ u32 priority;
+ /*< Priority of messages supported by this transport */
+ void *gate;
+ /*< Gate used for critical region management of the shared memory */
+ void *shared_addr;
+ /*< Address of the shared memory. The creator must supply the shared
+ * memory that this will use for maintain shared state information.
+ */
+ u32 notify_event_id;
+ /*< Notify event number to be used by the transport */
+};
+
+/*
+ * Structure defining Transport status values
+ */
+enum transportshm_status {
+ transportshm_status_INIT,
+ /*< Transport Shm instance has not not completed
+ * initialization. */
+ transportshm_status_UP,
+ /*< Transport Shm instance is up and functional. */
+ transportshm_status_DOWN,
+ /*< Transport Shm instance is down and not functional. */
+ transportshm_status_RESETTING
+ /*< Transport Shm instance was up at one point and is in
+ * process of resetting.
+ */
+};
+
+
+/* =============================================================================
+ * APIs called by applications
+ * =============================================================================
+ */
+/* Function to get the default configuration for the TransportShm
+ * module. */
+void transportshm_get_config(struct transportshm_config *cfg);
+
+/* Function to setup the TransportShm module. */
+int transportshm_setup(const struct transportshm_config *cfg);
+
+/* Function to destroy the TransportShm module. */
+int transportshm_destroy(void);
+
+/* Get the default parameters for the NotifyShmDriver. */
+void transportshm_params_init(struct transportshm_params *params);
+
+/* Create an instance of the TransportShm. */
+void *transportshm_create(u16 proc_id,
+ const struct transportshm_params *params);
+
+/* Delete an instance of the TransportShm. */
+int transportshm_delete(void **handle_ptr);
+
+/* Open a created TransportShm instance by address */
+int transportshm_open_by_addr(void *shared_addr, void **handle_ptr);
+
+/* Close an opened instance */
+int transportshm_close(void **handle_ptr);
+
+/* Get the shared memory requirements for the TransportShm. */
+u32 transportshm_shared_mem_req(const struct transportshm_params *params);
+
+/* Set the asynchronous error function for the transport module */
+void transportshm_set_err_fxn(void (*err_fxn)(enum transportshm_reason reason,
+ void *handle,
+ void *msg,
+ u32 info));
+
+
+/* =============================================================================
+ * APIs called internally by TransportShm module.
+ * =============================================================================
+ */
+/* Put msg to remote list */
+int transportshm_put(void *handle, void *msg);
+
+/* Control Function */
+int transportshm_control(void *handle, u32 cmd, u32 *cmd_arg);
+
+/* Get current status of the TransportShm */
+enum transportshm_status transportshm_get_status(void *handle);
+
+#endif /* _TRANSPORTSHM_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/transportshm_setup.h b/arch/arm/plat-omap/include/syslink/transportshm_setup.h
new file mode 100644
index 00000000000..99345773dd8
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/transportshm_setup.h
@@ -0,0 +1,47 @@
+/*
+ * transportshm_setup.h
+ *
+ * Shared Memory Transport setup layer
+ *
+ * This file contains the declarations of types and APIs as part
+ * of interface of the shared memory transport.
+ *
+ * Copyright (C) 2008-2009 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 _TRANSPORTSHM_SETUP_H_
+#define _TRANSPORTSHM_SETUP_H_
+
+/* Standard headers */
+#include <linux/types.h>
+
+/* Utilities headers */
+#include <linux/list.h>
+
+/* =============================================================================
+ * APIs called by applications
+ * =============================================================================
+ */
+
+/* Function that will be called in messageq_attach */
+int transportshm_setup_attach(u16 remote_proc_id, u32 *shared_addr);
+
+/* Function that will be called in messageq_detach */
+int transportshm_setup_detach(u16 remote_proc_id);
+
+/* Function that returns the amount of shared memory required */
+u32 transportshm_setup_shared_mem_req(u32 *shared_addr);
+
+/* Determines if a transport has been registered to a remote processor */
+bool transportshm_setup_is_registered(u16 remote_proc_id);
+
+#endif /* _TRANSPORTSHM_SETUP_H_ */
diff --git a/arch/arm/plat-omap/include/syslink/transportshm_setup_proxy.h b/arch/arm/plat-omap/include/syslink/transportshm_setup_proxy.h
new file mode 100644
index 00000000000..72eaf400a19
--- /dev/null
+++ b/arch/arm/plat-omap/include/syslink/transportshm_setup_proxy.h
@@ -0,0 +1,48 @@
+/*
+ * transportshm_setup_proxy.h
+ *
+ * Shared Memory Transport setup layer
+ *
+ * This file contains the declarations of types and APIs as part
+ * of interface of the shared memory transport.
+ *
+ * Copyright (C) 2008-2009 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 _TRANSPORTSHM_SETUP_PROXY_H_
+#define _TRANSPORTSHM_SETUP_PROXY_H_
+
+/* Module headers */
+#include <transportshm_setup.h>
+
+/* =============================================================================
+ * APIs
+ * =============================================================================
+ */
+/* function that will be called in messageq_attach */
+#define messageq_setup_transport_proxy_attach(remote_proc_id, shared_addr) \
+ transportshm_setup_attach(remote_proc_id, \
+ shared_addr)
+
+/* function that will be called in messageq_detach */
+#define messageq_setup_transport_proxy_detach(remote_proc_id) \
+ transportshm_setup_detach(remote_proc_id)
+
+/* Shared memory req function */
+#define messageq_setup_transport_proxy_shared_mem_req(shared_addr) \
+ transportshm_setup_shared_mem_req(shared_addr)
+
+/* is_registered function */
+#define messageq_setup_transport_proxy_is_registered(remote_proc_id) \
+ transportshm_setup_is_registered(remote_proc_id)
+
+#endif /* _TRANSPORTSHM_SETUP_PROXY_H_ */
diff --git a/arch/arm/plat-omap/iodmm.c b/arch/arm/plat-omap/iodmm.c
new file mode 100644
index 00000000000..25a18812d64
--- /dev/null
+++ b/arch/arm/plat-omap/iodmm.c
@@ -0,0 +1,1145 @@
+/*
+ * OMAP DMM (Dynamic memory mapping) to IOMMU module
+ *
+ * Copyright (C) 2010 Texas Instruments. All rights reserved.
+ *
+ * Authors: Ramesh Gupta <grgupta@ti.com>
+ * Hari Kanigeri <h-kanigeri2@ti.com>
+ *
+ * dma_map API usage in this code is inspired from Ohad Ben-Cohen's
+ * implementation in dspbridge code.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/scatterlist.h>
+#include <linux/platform_device.h>
+#include <linux/pagemap.h>
+#include <linux/kernel.h>
+#include <linux/genalloc.h>
+#include <linux/eventfd.h>
+
+#include <linux/sched.h>
+#include <asm/cacheflush.h>
+#include <asm/mach/map.h>
+#include <linux/dma-mapping.h>
+
+#include <plat/iommu.h>
+#include <plat/dmm_user.h>
+
+#include "iopgtable.h"
+
+#ifndef CONFIG_DMM_DMA_API
+/* Hack hack code to handle MM buffers */
+int temp_user_dma_op(unsigned long start, unsigned long end, int op)
+{
+
+ struct mm_struct *mm = current->active_mm;
+ void (*inner_op)(const void *, const void *);
+ void (*outer_op)(unsigned long, unsigned long);
+
+ switch (op) {
+ case 1:
+ inner_op = dmac_inv_range;
+ outer_op = outer_inv_range;
+ break;
+
+ case 2:
+ inner_op = dmac_clean_range;
+ outer_op = outer_clean_range;
+ break;
+
+ case 3:
+ inner_op = dmac_flush_range;
+ outer_op = outer_flush_range;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (end < start)
+ return -EINVAL;
+
+ down_read(&mm->mmap_sem);
+
+ do {
+ struct vm_area_struct *vma = find_vma(mm, start);
+
+ if (!vma || start < vma->vm_start ||
+ vma->vm_flags & (VM_IO | VM_PFNMAP)) {
+ up_read(&mm->mmap_sem);
+ return -EFAULT;
+ }
+ do {
+ unsigned long e = (start | ~PAGE_MASK) + 1;
+ struct page *page;
+
+ if (e > end)
+ e = end;
+ page = follow_page(vma, start, FOLL_GET);
+ if (IS_ERR(page)) {
+ up_read(&mm->mmap_sem);
+ return PTR_ERR(page);
+ }
+ if (page) {
+ unsigned long phys;
+ /*
+ * This flushes the userspace address - which
+ * is not what this API was intended to do.
+ * Things may go astray as a result.
+ */
+ inner_op((void *)start, (void *)e);
+ /*
+ * Now handle the L2 cache.
+ */
+ phys = page_to_phys(page) +
+ (start & ~PAGE_MASK);
+ outer_op(phys, phys + e - start);
+ put_page(page);
+ }
+ start = e;
+ } while (start < end && start < vma->vm_end);
+ } while (start < end);
+
+ up_read(&mm->mmap_sem);
+
+ return 0;
+}
+#endif
+
+static inline struct gen_pool *get_pool_handle(struct iovmm_device *iovmm_obj,
+ int pool_id)
+{
+ struct iovmm_pool *pool;
+
+ list_for_each_entry(pool, &iovmm_obj->mmap_pool, list) {
+ if (pool->pool_id == pool_id)
+ return pool->genpool;
+ }
+ return NULL;
+}
+
+/*
+ * This function walks through the page tables to convert a userland
+ * virtual address to physical address
+ */
+static u32 __user_va2_pa(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;
+}
+
+/* remember mapping information */
+static struct dmm_map_object *add_mapping_info(struct iodmm_struct *obj,
+ struct gen_pool *gen_pool, u32 va, u32 da, u32 size)
+{
+ struct dmm_map_object *map_obj;
+
+ u32 num_usr_pgs = size / PAGE_SIZE;
+
+ pr_debug("%s: adding map info: va 0x%x virt 0x%x size 0x%x\n",
+ __func__, va,
+ da, size);
+ map_obj = kzalloc(sizeof(struct dmm_map_object), GFP_KERNEL);
+ if (!map_obj) {
+ pr_err("%s: kzalloc failed\n", __func__);
+ return NULL;
+ }
+ INIT_LIST_HEAD(&map_obj->link);
+
+ map_obj->pages = kcalloc(num_usr_pgs, sizeof(struct page *),
+ GFP_KERNEL);
+ if (!map_obj->pages) {
+ pr_err("%s: kzalloc failed\n", __func__);
+ kfree(map_obj);
+ return NULL;
+ }
+
+ map_obj->va = va;
+ map_obj->da = da;
+ map_obj->size = size;
+ map_obj->num_usr_pgs = num_usr_pgs;
+ map_obj->gen_pool = gen_pool;
+ list_add(&map_obj->link, &obj->map_list);
+
+ return map_obj;
+}
+
+static int match_exact_map_obj(struct dmm_map_object *map_obj,
+ u32 da, u32 size)
+{
+ u32 res;
+
+ if (map_obj->da == da && map_obj->size != size)
+ pr_err("%s: addr match (0x%x), size don't (0x%x != 0x%x)\n",
+ __func__, da, map_obj->size, size);
+
+ if (map_obj->da == da && map_obj->size == size)
+ res = 0;
+ else
+ res = -ENODATA;
+ return res;
+}
+
+static void remove_mapping_information(struct iodmm_struct *obj,
+ u32 da, u32 size)
+{
+ struct dmm_map_object *map_obj;
+
+ pr_debug("%s: looking for virt 0x%x size 0x%x\n", __func__,
+ da, size);
+ list_for_each_entry(map_obj, &obj->map_list, link) {
+ pr_debug("%s: candidate: va 0x%x virt 0x%x size 0x%x\n",
+ __func__,
+ map_obj->va,
+ map_obj->da,
+ map_obj->size);
+
+ if (!match_exact_map_obj(map_obj, da, size)) {
+ pr_debug("%s: match, deleting map info\n", __func__);
+ if (map_obj->gen_pool != NULL)
+ gen_pool_free(map_obj->gen_pool, da, size);
+ list_del(&map_obj->link);
+ kfree(map_obj->dma_info.sg);
+ kfree(map_obj->pages);
+ kfree(map_obj);
+ goto out;
+ }
+ pr_debug("%s: candidate didn't match\n", __func__);
+ }
+
+ pr_err("%s: failed to find given map info\n", __func__);
+out:
+ return;
+}
+
+static int match_containing_map_obj(struct dmm_map_object *map_obj,
+ u32 va, u32 da, bool check_va, u32 size)
+{
+ u32 res;
+ u32 map_obj_end;
+
+ if (check_va) {
+ map_obj_end = map_obj->va + map_obj->size;
+ if ((va >= map_obj->va) && (va + size <= map_obj_end))
+ res = 0;
+ else
+ res = -ENODATA;
+ } else {
+ if (da == map_obj->da)
+ res = 0;
+ else
+ res = -ENODATA;
+ }
+ return res;
+}
+
+/**
+ * Find the mapping object based on either MPU virtual address or
+ * Device virtual address. Which option to select to search for the mapping
+ * is specified with check_va flag. check_va is set to TRUE if search is
+ * based on MPU virtual address and FALSE if search is based on Device
+ * virtual address
+ */
+static struct dmm_map_object *find_containing_mapping(
+ struct iodmm_struct *obj,
+ u32 va, u32 da, bool check_va,
+ u32 size)
+{
+ struct dmm_map_object *map_obj, *temp_map;
+ pr_debug("%s: looking for va 0x%x size 0x%x\n", __func__,
+ va, size);
+ list_for_each_entry_safe(map_obj, temp_map, &obj->map_list, link) {
+ pr_debug("%s: candidate: va 0x%x virt 0x%x size 0x%x\n",
+ __func__,
+ map_obj->va,
+ map_obj->da,
+ map_obj->size);
+ if (!match_containing_map_obj(map_obj, va, da, check_va,
+ size)) {
+ pr_debug("%s: match!\n", __func__);
+ goto out;
+ }
+
+ pr_debug("%s: no match!\n", __func__);
+ }
+
+ map_obj = NULL;
+out:
+ return map_obj;
+}
+
+
+static inline struct page *get_mapping_page(struct dmm_map_object *map_obj,
+ int pg_i)
+{
+ pr_debug("%s: looking for pg_i %d, num_usr_pgs: %d\n", __func__,
+ pg_i, map_obj->num_usr_pgs);
+ if (pg_i < 0 || pg_i >= map_obj->num_usr_pgs) {
+ pr_err("%s: requested pg_i %d is out of mapped range\n",
+ __func__, pg_i);
+ return NULL;
+ }
+ return map_obj->pages[pg_i];
+}
+
+#ifdef CONFIG_DMM_DMA_API
+static int find_first_page_in_cache(struct dmm_map_object *map_obj,
+ unsigned long va)
+{
+ u32 mapped_base_page = map_obj->va >> PAGE_SHIFT;
+ u32 requested_base_page = va >> PAGE_SHIFT;
+ int pg_index = requested_base_page - mapped_base_page;
+
+ if (pg_index < 0 || pg_index >= map_obj->num_usr_pgs) {
+ pr_err("%s: failed (got %d)\n", __func__, pg_index);
+ return -1;
+ }
+
+ pr_debug("%s: first page is %d\n", __func__, pg_index);
+ return pg_index;
+}
+
+/* Cache operation against kernel address instead of users */
+static int build_dma_sg(struct dmm_map_object *map_obj, unsigned long start,
+ size_t len)
+{
+ struct page *page;
+ unsigned long offset;
+ ssize_t rest;
+ int ret = 0, i = 0;
+ unsigned long first_data_page = start >> PAGE_SHIFT;
+ unsigned long last_data_page = ((u32)(start + len - 1) >> PAGE_SHIFT);
+ /* calculating the number of pages this area spans */
+ unsigned long num_pages = last_data_page - first_data_page + 1;
+ struct scatterlist *sg;
+ int pg_i;
+
+ sg = kcalloc(num_pages, sizeof(*sg), GFP_KERNEL);
+ if (!sg) {
+ pr_err("%s: kcalloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ sg_init_table(sg, num_pages);
+
+ /* cleanup a previous sg allocation */
+ /* this may happen if application doesn't signal for e/o DMA */
+ kfree(map_obj->dma_info.sg);
+
+ map_obj->dma_info.sg = sg;
+ map_obj->dma_info.num_pages = num_pages;
+
+ pg_i = find_first_page_in_cache(map_obj, start);
+
+ while (len) {
+ page = get_mapping_page(map_obj, pg_i);
+ if (!page) {
+ pr_err("%s: no page for %08lx, pg_i is %x\n", __func__,
+ start, pg_i);
+ ret = -EINVAL;
+ goto out;
+ } else if (IS_ERR(page)) {
+ pr_err("%s: err page for %08lx(%lu)\n", __func__, start,
+ PTR_ERR(page));
+ ret = PTR_ERR(page);
+ goto out;
+ }
+
+ offset = start & ~PAGE_MASK;
+ rest = min_t(ssize_t, PAGE_SIZE - offset, len);
+
+ sg_set_page(&sg[i], page, rest, offset);
+
+ len -= rest;
+ start += rest;
+ pg_i++, i++;
+ }
+
+ if (i != map_obj->dma_info.num_pages) {
+ pr_err("%s: bad number of sg iterations\n", __func__);
+ ret = -EFAULT;
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static int memory_regain_ownership(struct device *dev,
+ struct dmm_map_object *map_obj, unsigned long start,
+ ssize_t len, enum dma_data_direction dir)
+{
+ int ret = 0;
+ unsigned long first_data_page = start >> PAGE_SHIFT;
+ unsigned long last_data_page = ((u32)(start + len - 1) >> PAGE_SHIFT);
+ /* calculating the number of pages this area spans */
+ unsigned long num_pages = last_data_page - first_data_page + 1;
+ struct device_dma_map_info *dma_info = &map_obj->dma_info;
+ long pg_i;
+
+ if (!dma_info->sg)
+ goto out;
+
+ if (num_pages > dma_info->num_pages) {
+ pr_err("%s: dma info params invalid\n", __func__);
+ return -EINVAL;
+ }
+
+ pg_i = find_first_page_in_cache(map_obj, start);
+ if (pg_i == -1) {
+ ret = -EFAULT;
+ goto out;
+ }
+ dma_unmap_sg(dev, (dma_info->sg), num_pages, dir);
+
+ pr_debug("%s: dma_map_sg unmapped\n", __func__);
+
+out:
+ return ret;
+}
+
+/* Cache operation against kernel address instead of users */
+static int memory_give_ownership(struct device *dev,
+ struct dmm_map_object *map_obj, unsigned long start,
+ ssize_t len, enum dma_data_direction dir)
+{
+ int ret, sg_num;
+ struct device_dma_map_info *dma_info = &map_obj->dma_info;
+ unsigned long first_data_page = start >> PAGE_SHIFT;
+ unsigned long last_data_page = ((u32)(start + len - 1) >> PAGE_SHIFT);
+ /* calculating the number of pages this area spans */
+ unsigned long num_pages = last_data_page - first_data_page + 1;
+ long pg_i;
+
+ pg_i = find_first_page_in_cache(map_obj, start);
+ if (pg_i == -1) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ sg_num = dma_map_sg(dev, (dma_info->sg), num_pages, dir);
+ if (sg_num < 1) {
+ pr_err("%s: dma_map_sg failed: %d\n", __func__, sg_num);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ pr_debug("%s: dma_map_sg mapped %d elements\n", __func__, sg_num);
+
+ return 0;
+out:
+ return ret;
+}
+#endif
+
+int proc_begin_dma(struct iodmm_struct *obj, const void __user *args)
+{
+ int status = 0;
+ struct dmm_dma_info dma_info;
+#ifdef CONFIG_DMM_DMA_API
+ struct dmm_map_object *map_obj;
+ struct device *dev;
+
+ if (copy_from_user(&dma_info, (void __user *)args,
+ sizeof(struct dmm_dma_info)))
+ return -EFAULT;
+ dev = obj->iovmm->iommu->dev;
+
+ mutex_lock(&obj->iovmm->dmm_map_lock);
+ pr_debug("%s: addr 0x%x, size 0x%x, type %d\n", __func__,
+ (u32)dma_info.pva,
+ dma_info.ul_size, dma_info.dir);
+ /* find requested memory are in cached mapping information */
+ map_obj = find_containing_mapping(obj, (u32)dma_info.pva, 0, true,
+ dma_info.ul_size);
+ if (!map_obj) {
+ pr_err("%s: find_containing_mapping failed\n", __func__);
+ status = -EFAULT;
+ goto err_out;
+ }
+
+ if (memory_give_ownership(dev, map_obj, (u32)dma_info.pva,
+ dma_info.ul_size, dma_info.dir)) {
+ pr_err("%s: InValid address parameters %x %x\n",
+ __func__, (u32)dma_info.pva, dma_info.ul_size);
+ status = -EFAULT;
+ }
+
+err_out:
+ mutex_unlock(&obj->iovmm->dmm_map_lock);
+#else
+ if (copy_from_user(&dma_info, (void __user *)args,
+ sizeof(struct dmm_dma_info)))
+ return -EFAULT;
+ status = temp_user_dma_op((u32)dma_info.pva,
+ (u32)dma_info.pva + dma_info.ul_size, 3);
+#endif
+ return status;
+}
+
+int proc_end_dma(struct iodmm_struct *obj, const void __user *args)
+{
+ int status = 0;
+ struct dmm_dma_info dma_info;
+#ifdef CONFIG_DMM_DMA_API
+ struct device *dev;
+ struct dmm_map_object *map_obj;
+
+ if (copy_from_user(&dma_info, (void __user *)args,
+ sizeof(struct dmm_dma_info)))
+ return -EFAULT;
+ dev = obj->iovmm->iommu->dev;
+
+ pr_debug("%s: addr 0x%x, size 0x%x, type %d\n", __func__,
+ (u32)dma_info.pva,
+ dma_info.ul_size, dma_info.dir);
+ mutex_lock(&obj->iovmm->dmm_map_lock);
+
+ /* find requested memory are in cached mapping information */
+ map_obj = find_containing_mapping(obj, (u32)dma_info.pva, 0, true,
+ dma_info.ul_size);
+ if (!map_obj) {
+ pr_err("%s: find_containing_mapping failed\n", __func__);
+ status = -EFAULT;
+ goto err_out;
+ }
+
+ if (memory_regain_ownership(dev, map_obj, (u32)dma_info.pva,
+ dma_info.ul_size, dma_info.dir)) {
+ pr_err("%s: InValid address parameters %p %x\n",
+ __func__, dma_info.pva, dma_info.ul_size);
+ status = -EFAULT;
+ goto err_out;
+ }
+
+err_out:
+ mutex_unlock(&obj->iovmm->dmm_map_lock);
+#else
+ if (copy_from_user(&dma_info, (void __user *)args,
+ sizeof(struct dmm_dma_info)))
+ return -EFAULT;
+ status = temp_user_dma_op((u32)dma_info.pva,
+ (u32)dma_info.pva + dma_info.ul_size, 1);
+#endif
+ return status;
+}
+
+/**
+ * user_to_device_unmap() - unmaps Device virtual buffer.
+ * @mmu: Pointer to iommu handle.
+ * @da DSP address
+ *
+ * This function unmaps a user space buffer into DSP virtual address.
+ *
+ */
+static int user_to_device_unmap(struct iommu *mmu, u32 da, unsigned size)
+{
+ unsigned total = size;
+ unsigned start = da;
+
+ while (total > 0) {
+ size_t bytes;
+ bytes = iopgtable_clear_entry(mmu, start);
+ if (bytes == 0)
+ bytes = PAGE_SIZE;
+ else
+ dev_dbg(mmu->dev, "%s: unmap 0x%x 0x%x\n",
+ __func__, start, bytes);
+ BUG_ON(!IS_ALIGNED(bytes, PAGE_SIZE));
+ total -= bytes;
+ start += bytes;
+ }
+ return 0;
+}
+
+static int __user_un_map(struct iodmm_struct *obj, u32 map_addr)
+{
+ int status = 0;
+ u32 va_align;
+ u32 size_align;
+ struct dmm_map_object *map_obj;
+ int i;
+ struct page *pg;
+
+ va_align = round_down(map_addr, PAGE_SIZE);
+
+ mutex_lock(&obj->iovmm->dmm_map_lock);
+ /*
+ * Update DMM structures. Get the size to unmap.
+ * This function returns error if the VA is not mapped
+ */
+ /* find requested memory are in cached mapping information */
+ map_obj = find_containing_mapping(obj, 0, map_addr, false, 0);
+ if (!map_obj)
+ goto err;
+ size_align = map_obj->size;
+ /* Remove mapping from the page tables. */
+ status = user_to_device_unmap(obj->iovmm->iommu, va_align,
+ size_align);
+ if (status)
+ goto err;
+
+ i = size_align/PAGE_SIZE;
+ while (i--) {
+ pg = map_obj->pages[i];
+ if (pg && pfn_valid(page_to_pfn(pg))) {
+ if (page_count(pg) < 1)
+ pr_info("%s UNMAP FAILURE !!!\n", __func__);
+ else {
+ SetPageDirty(pg);
+ page_cache_release(pg);
+ }
+ }
+ }
+ /*
+ * A successful unmap should be followed by removal of map_obj
+ * from dmm_map_list, so that mapped memory resource tracking
+ * remains uptodate
+ */
+ remove_mapping_information(obj, map_obj->da, map_obj->size);
+err:
+ mutex_unlock(&obj->iovmm->dmm_map_lock);
+ return status;
+}
+
+
+/**
+ * user_un_map - Removes User's mapped address
+ * @obj: target dmm object
+ * @args Mapped address that needs to be unmapped
+ *
+ * removes user's dmm buffer mapping
+ **/
+int user_un_map(struct iodmm_struct *obj, const void __user *args)
+{
+ int status = 0;
+ u32 map_addr;
+
+ if (copy_from_user(&map_addr, (void __user *)args, sizeof(u32)))
+ return -EFAULT;
+
+ status = __user_un_map(obj, map_addr);
+ if (status)
+ pr_err("%s:Unmap of buffer 0x%x failedn", __func__, map_addr);
+
+ return status;
+}
+
+/**
+ * user_to_device_map() - maps user to dsp virtual address
+ * @mmu: Pointer to iommu handle.
+ * @uva: Virtual user space address.
+ * @da DSP address
+ * @size Buffer size to map.
+ * @usr_pgs struct page array pointer where the user pages will be stored
+ *
+ * This function maps a user space buffer into DSP virtual address.
+ *
+ */
+static int user_to_device_map(struct iommu *mmu, u32 uva, u32 da, u32 size,
+ struct page **usr_pgs)
+
+{
+ int res = 0;
+ int w = 0;
+ struct vm_area_struct *vma;
+ struct mm_struct *mm = current->mm;
+ u32 pg_num;
+ u32 status;
+ int pg_i;
+ u32 pa;
+ unsigned int pages;
+ struct iotlb_entry tlb_entry;
+ struct page *mapped_page;
+
+ if (!size || !usr_pgs)
+ return -EINVAL;
+
+ pages = size / PAGE_SIZE;
+
+ vma = find_vma(mm, uva);
+ if (!vma) {
+ WARN_ON(1);
+ return -EFAULT;
+ }
+
+ if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE))
+ w = 1;
+
+ for (pg_i = 0; pg_i < pages; pg_i++) {
+ pg_num = get_user_pages(current, mm, uva, 1,
+ w, 1, &mapped_page, NULL);
+ if (pg_num > 0) {
+ if (page_count(mapped_page) < 1) {
+ pr_err("Bad page count after doing"
+ "get_user_pages on"
+ "user buffer\n");
+ break;
+ }
+ pa = page_to_phys(mapped_page);
+ iotlb_init_entry(&tlb_entry, da, pa,
+ MMU_CAM_PGSZ_4K |
+ MMU_RAM_ENDIAN_LITTLE |
+ MMU_RAM_ELSZ_32);
+
+ iopgtable_store_entry(mmu, &tlb_entry);
+ if (usr_pgs)
+ usr_pgs[pg_i] = mapped_page;
+ da += PAGE_SIZE;
+ uva += PAGE_SIZE;
+ } else {
+ pr_err("get_user_pages FAILED,"
+ "MPU addr = 0x%x,"
+ "vma->vm_flags = 0x%lx,"
+ "get_user_pages Err"
+ "Value = %d, Buffer"
+ "size=0x%x\n", uva,
+ vma->vm_flags, pg_num,
+ size);
+ status = -EFAULT;
+ break;
+ }
+ }
+
+ return res;
+}
+
+/**
+ * phys_to_device_map() - maps physical addr
+ * to device virtual address
+ * @mmu: Pointer to iommu handle.
+ * @uva: Virtual user space address.
+ * @da DSP address
+ * @size Buffer size to map.
+ * @usr_pgs struct page array pointer where the user pages will be stored
+ *
+ * This function maps a user space buffer into DSP virtual address.
+ *
+ */
+static int phys_to_device_map(struct iodmm_struct *obj,
+ int pool_id, u32 *mapped_addr,
+ u32 pa, size_t bytes, u32 flags)
+{
+ struct iotlb_entry e;
+ struct dmm_map_object *dmm_obj;
+ int da;
+ u32 all_bits;
+ int err = 0;
+ u32 pg_size[] = {SZ_16M, SZ_1M, SZ_64K, SZ_4K};
+ int size_flag[] = {MMU_CAM_PGSZ_16M, MMU_CAM_PGSZ_1M,
+ MMU_CAM_PGSZ_64K, MMU_CAM_PGSZ_4K};
+ int i;
+ struct gen_pool *gen_pool;
+
+ if (!bytes) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ if (pool_id == -1) {
+ da = round_down(*mapped_addr, PAGE_SIZE);
+ gen_pool = NULL;
+ } else {
+ /* search through the list of available pools to
+ * pool handle
+ */
+ gen_pool = get_pool_handle(obj->iovmm, pool_id);
+ if (gen_pool) {
+ da = gen_pool_alloc(gen_pool, bytes);
+ *mapped_addr = (da | (pa & (PAGE_SIZE - 1)));
+ } else {
+ err = -EFAULT;
+ goto exit;
+ }
+ }
+
+ dmm_obj = add_mapping_info(obj, gen_pool, pa, *mapped_addr, bytes);
+ if (dmm_obj == NULL) {
+ err = -ENODEV;
+ goto err_add_map;
+ }
+
+ while (bytes) {
+ /*
+ * To find the max. page size with which both PA & VA are
+ * aligned
+ */
+ all_bits = pa | da;
+ for (i = 0; i < 4; i++) {
+ if ((bytes >= pg_size[i]) && ((all_bits &
+ (pg_size[i] - 1)) == 0)) {
+ iotlb_init_entry(&e, da, pa,
+ size_flag[i] |
+ MMU_RAM_ENDIAN_LITTLE |
+ MMU_RAM_ELSZ_32);
+ iopgtable_store_entry(obj->iovmm->iommu, &e);
+ bytes -= pg_size[i];
+ da += pg_size[i];
+ pa += pg_size[i];
+ break;
+ }
+ }
+ }
+ return 0;
+
+err_add_map:
+ if (gen_pool)
+ gen_pool_free(gen_pool, da, bytes);
+exit:
+ return err;
+}
+
+/**
+ * dmm_user - Maps user buffer to Device address
+ * @obj: target dmm object
+ * @args: DMM map information
+ *
+ * Maps given user buffer to Device address
+ **/
+int dmm_user(struct iodmm_struct *obj, void __user *args)
+{
+ struct gen_pool *gen_pool;
+ struct dmm_map_object *dmm_obj;
+ struct iovmm_device *iovmm_obj = obj->iovmm;
+ u32 addr_align, da_align, size_align, tmp_addr;
+ int err = 0;
+ int i, num_of_pages;
+ struct page *pg;
+ struct vm_area_struct *vma;
+ struct mm_struct *mm = current->mm;
+ u32 io_addr;
+ struct dmm_map_info map_info;
+ struct iotlb_entry e;
+
+
+ if (copy_from_user(&map_info, (void __user *)args,
+ sizeof(struct dmm_map_info)))
+ return -EFAULT;
+
+ /*
+ * Important Note: va 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);
+
+ /* Calculate the page-aligned PA, VA and size */
+ addr_align = round_down((u32) map_info.mpu_addr, PAGE_SIZE);
+ size_align = round_up(map_info.size + map_info.mpu_addr - addr_align,
+ PAGE_SIZE);
+
+ mutex_lock(&iovmm_obj->dmm_map_lock);
+
+ /*
+ * User passed physical address to map. No DMM pool
+ * specified if pool_id as -1, so the da is interpreted
+ * as the Device Address.
+ */
+ if (map_info.flags == DMM_DA_PHYS) {
+ err = phys_to_device_map(obj, map_info.pool_id, map_info.da,
+ addr_align, size_align, map_info.flags);
+ goto exit;
+ }
+
+ vma = find_vma(mm, map_info.mpu_addr);
+ if (vma) {
+ dev_dbg(iovmm_obj->iommu->dev,
+ "VMAfor UserBuf: ul_mpu_addr=%x, ul_num_bytes=%x, "
+ "vm_start=%lx, vm_end=%lx, vm_flags=%lx\n",
+ map_info.mpu_addr,
+ map_info.size, 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) && (map_info.mpu_addr + map_info.size > vma->vm_end)) {
+ /* jump to the next VMA region */
+ vma = find_vma(mm, vma->vm_end + 1);
+ dev_dbg(iovmm_obj->iommu->dev,
+ "VMA for UserBuf ul_mpu_addr=%x ul_num_bytes=%x, "
+ "vm_start=%lx, vm_end=%lx, vm_flags=%lx\n",
+ map_info.mpu_addr,
+ map_info.size, vma->vm_start, vma->vm_end,
+ vma->vm_flags);
+ }
+ if (!vma) {
+ pr_err("%s: Failed to get VMA region for 0x%x (%d)\n",
+ __func__, map_info.mpu_addr, map_info.size);
+ err = -EINVAL;
+ goto exit;
+ }
+
+ /*
+ * If user provided anonymous address, then don't allocate it from
+ * from genpool
+ */
+ if (map_info.flags == DMM_DA_ANON) {
+ gen_pool = NULL;
+ da_align = round_down((u32)map_info.da, PAGE_SIZE);
+ } else {
+ /* search through the list of available pools to
+ * pool handle
+ */
+ gen_pool = get_pool_handle(iovmm_obj, map_info.pool_id);
+ if (gen_pool)
+ da_align = gen_pool_alloc(gen_pool, size_align);
+ else {
+ err = -EFAULT;
+ goto exit;
+ }
+ }
+
+ /* Mapped address = MSB of VA | LSB of PA */
+ tmp_addr = (da_align | ((u32)map_info.mpu_addr & (PAGE_SIZE - 1)));
+ dmm_obj = add_mapping_info(obj, gen_pool, map_info.mpu_addr, tmp_addr,
+ size_align);
+ if (!dmm_obj)
+ goto exit;
+
+ *map_info.da = tmp_addr;
+
+ /* Mapping the IO buffers */
+ if (vma->vm_flags & VM_IO) {
+ num_of_pages = size_align/PAGE_SIZE;
+ for (i = 0; i < num_of_pages; i++) {
+ io_addr = __user_va2_pa(current->mm, addr_align);
+ pg = phys_to_page(io_addr);
+
+ iotlb_init_entry(&e, da_align, io_addr,
+ MMU_CAM_PGSZ_4K |
+ MMU_RAM_ENDIAN_LITTLE |
+ MMU_RAM_ELSZ_32);
+ iopgtable_store_entry(obj->iovmm->iommu, &e);
+ da_align += PAGE_SIZE;
+ addr_align += PAGE_SIZE;
+ dmm_obj->pages[i] = pg;
+ }
+ err = 0;
+ goto exit;
+ }
+
+ /* Mapping the Userspace buffer */
+ err = user_to_device_map(iovmm_obj->iommu, addr_align,
+ da_align, size_align, dmm_obj->pages);
+ if (err) {
+ /* clean the entries that were mapped */
+ __user_un_map(obj, tmp_addr);
+ goto exit;
+ }
+#ifdef CONFIG_DMM_DMA_API
+ /*
+ * Build the SG list that would be required for dma map and
+ * unmap APIs
+ */
+ err = build_dma_sg(dmm_obj, map_info.mpu_addr, map_info.size);
+ if (!err) {
+ /*
+ * calling dma_map_sg(cache flush) is essential for
+ * dma_unmap_sg to work since the sg->dma_address required
+ * for dma_unmap_sg is built during dma_map_sg call.
+ */
+ err = memory_give_ownership(iovmm_obj->iommu->dev, dmm_obj,
+ map_info.mpu_addr, map_info.size, DMA_BIDIRECTIONAL);
+ }
+#endif
+
+exit:
+ copy_to_user((void __user *)args, &map_info,
+ sizeof(struct dmm_map_info));
+ mutex_unlock(&iovmm_obj->dmm_map_lock);
+ up_read(&mm->mmap_sem);
+ return err;
+}
+
+/**
+ * user_remove_resources - Removes User's dmm resources
+ * @obj: target dmm object
+ *
+ * removes user's dmm resources
+ **/
+void user_remove_resources(struct iodmm_struct *obj)
+{
+
+ struct dmm_map_object *temp_map, *map_obj;
+ int status = 0;
+
+ /* Free DMM mapped memory resources */
+ list_for_each_entry_safe(map_obj, temp_map, &obj->map_list, link) {
+ status = __user_un_map(obj, map_obj->da);
+ if (status) {
+ pr_err("%s: proc_un_map failed!"
+ " status = 0x%x\n", __func__, status);
+ }
+ }
+}
+
+/**
+ * omap_create_dmm_pool - Create DMM pool
+ * @obj: target dmm object
+ * @args pool information
+ **/
+int omap_create_dmm_pool(struct iodmm_struct *obj, const void __user *args)
+{
+ struct iovmm_pool *pool;
+ struct iovmm_device *iovmm = obj->iovmm;
+ struct iovmm_pool_info pool_info;
+
+ if (copy_from_user(&pool_info, args, sizeof(struct iovmm_pool_info)))
+ return -EFAULT;
+
+ pool = kzalloc(sizeof(struct iovmm_pool), GFP_KERNEL);
+ if (!pool)
+ return -EFAULT;
+
+ pool->pool_id = pool_info.pool_id;
+ pool->da_begin = pool_info.da_begin;
+ pool->da_end = pool_info.da_begin + pool_info.size;
+
+ pool->genpool = gen_pool_create(12, -1);
+ if (pool->genpool)
+ gen_pool_add(pool->genpool, pool->da_begin,
+ pool_info.size, -1);
+ else
+ pr_err("%s:gen_pool_create retuned null\n", __func__);
+
+ INIT_LIST_HEAD(&pool->list);
+ list_add_tail(&pool->list, &iovmm->mmap_pool);
+
+ return 0;
+}
+
+/**
+ * omap_delete_dmm_pool - Delete DMM pools
+ * @obj: target dmm object
+ **/
+int omap_delete_dmm_pools(struct iodmm_struct *obj)
+{
+ struct iovmm_pool *pool;
+ struct iovmm_device *iovmm_obj = obj->iovmm;
+ struct list_head *_pool, *_next_pool;
+
+ list_for_each_safe(_pool, _next_pool, &iovmm_obj->mmap_pool) {
+ pool = list_entry(_pool, struct iovmm_pool, list);
+ gen_pool_destroy(pool->genpool);
+ list_del(&pool->list);
+ kfree(pool);
+ }
+
+ return 0;
+}
+
+/**
+ * register_mmufault - Register for MMU fault notification
+ * @obj: target dmm object
+ * @args: Eventfd information
+ *
+ * Registering to MMU fault event notification
+ **/
+int register_mmufault(struct iodmm_struct *obj, const void __user *args)
+{
+ int fd;
+ struct iommu_event_ntfy *fd_reg;
+
+ if (copy_from_user(&fd, args, sizeof(int)))
+ return -EFAULT;
+
+ fd_reg = kzalloc(sizeof(struct iommu_event_ntfy), GFP_KERNEL);
+ fd_reg->fd = fd;
+ fd_reg->evt_ctx = eventfd_ctx_fdget(fd);
+ INIT_LIST_HEAD(&fd_reg->list);
+ spin_lock_irq(&obj->iovmm->iommu->event_lock);
+ list_add_tail(&fd_reg->list, &obj->iovmm->iommu->event_list);
+ spin_unlock_irq(&obj->iovmm->iommu->event_lock);
+
+ return 0;
+}
+
+/**
+ * unregister_mmufault - Unregister for MMU fault notification
+ * @obj: target dmm object
+ * @args: Eventfd information
+ *
+ * Unregister to MMU fault event notification
+ **/
+int unregister_mmufault(struct iodmm_struct *obj, const void __user *args)
+{
+ int fd;
+ struct iommu_event_ntfy *fd_reg, *temp_reg;
+
+ if (copy_from_user(&fd, (void __user *)args, sizeof(int)))
+ return -EFAULT;
+
+ /* remove the mmu fault event notification */
+ spin_lock_irq(&obj->iovmm->iommu->event_lock);
+ list_for_each_entry_safe(fd_reg, temp_reg,
+ &obj->iovmm->iommu->event_list, list) {
+ if (fd_reg->fd == fd) {
+ list_del(&fd_reg->list);
+ kfree(fd_reg);
+ }
+ }
+ spin_unlock_irq(&obj->iovmm->iommu->event_lock);
+
+ return 0;
+}
+
+/**
+ * program_tlb_entry - Program the IOMMU TLB entry
+ * @obj: target dmm object
+ * @args: TLB entry information
+ *
+ * This function loads the TLB entry that the user specifies.
+ * This function should be used only during remote Processor
+ * boot time.
+ **/
+int program_tlb_entry(struct iodmm_struct *obj, const void __user *args)
+{
+ struct iotlb_entry e;
+ int ret;
+
+ if (copy_from_user(&e, args, sizeof(struct iotlb_entry)))
+ return -EFAULT;
+
+ ret = load_iotlb_entry(obj->iovmm->iommu, &e);
+ return ret;
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Userspace DMM to IOMMU");
+MODULE_AUTHOR("Hari Kanigeri");
+MODULE_AUTHOR("Ramesh Gupta");
diff --git a/arch/arm/plat-omap/iommu-debug.c b/arch/arm/plat-omap/iommu-debug.c
index f07cf2f08e0..7a8725fd806 100644
--- a/arch/arm/plat-omap/iommu-debug.c
+++ b/arch/arm/plat-omap/iommu-debug.c
@@ -32,7 +32,8 @@ static struct dentry *iommu_debug_root;
static ssize_t debug_read_ver(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
- u32 ver = iommu_arch_version();
+ struct iommu *obj = file->private_data;
+ u32 ver = iommu_arch_version(obj);
char buf[MAXCOLUMN], *p = buf;
p += sprintf(p, "H/W version: %d.%d\n", (ver >> 4) & 0xf , ver & 0xf);
diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c
index 8a51fd58f65..90818cbd745 100644
--- a/arch/arm/plat-omap/iommu.c
+++ b/arch/arm/plat-omap/iommu.c
@@ -16,8 +16,8 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
-#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/eventfd.h>
#include <asm/cacheflush.h>
@@ -72,9 +72,19 @@ EXPORT_SYMBOL_GPL(uninstall_iommu_arch);
* iommu_save_ctx - Save registers for pm off-mode support
* @obj: target iommu
**/
-void iommu_save_ctx(struct iommu *obj)
+u32 iommu_save_ctx(struct iommu *obj)
{
- arch_iommu->save_ctx(obj);
+ u32 err;
+
+ err = iommu_save_tlb_entries(obj);
+ if (err)
+ goto error;
+
+ arch_iommu->disable(obj);
+
+ return 0;
+error:
+ return err;
}
EXPORT_SYMBOL_GPL(iommu_save_ctx);
@@ -82,18 +92,30 @@ EXPORT_SYMBOL_GPL(iommu_save_ctx);
* iommu_restore_ctx - Restore registers for pm off-mode support
* @obj: target iommu
**/
-void iommu_restore_ctx(struct iommu *obj)
+u32 iommu_restore_ctx(struct iommu *obj)
{
- arch_iommu->restore_ctx(obj);
+ u32 err;
+
+ err = arch_iommu->enable(obj);
+ if (err)
+ goto error;
+
+ err = iommu_restore_tlb_entries(obj);
+ if (err)
+ goto error;
+
+ return 0;
+error:
+ return err;
}
EXPORT_SYMBOL_GPL(iommu_restore_ctx);
/**
* iommu_arch_version - Return running iommu arch version
**/
-u32 iommu_arch_version(void)
+u32 iommu_arch_version(struct iommu *obj)
{
- return arch_iommu->version;
+ return arch_iommu->get_version(obj);
}
EXPORT_SYMBOL_GPL(iommu_arch_version);
@@ -103,15 +125,7 @@ static int iommu_enable(struct iommu *obj)
if (!obj)
return -EINVAL;
-
- if (!arch_iommu)
- return -ENODEV;
-
- clk_enable(obj->clk);
-
err = arch_iommu->enable(obj);
-
- clk_disable(obj->clk);
return err;
}
@@ -119,12 +133,7 @@ static void iommu_disable(struct iommu *obj)
{
if (!obj)
return;
-
- clk_enable(obj->clk);
-
arch_iommu->disable(obj);
-
- clk_disable(obj->clk);
}
/*
@@ -247,8 +256,6 @@ int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e)
if (!obj || !obj->nr_tlb_entries || !e)
return -EINVAL;
- clk_enable(obj->clk);
-
iotlb_lock_get(obj, &l);
if (l.base == obj->nr_tlb_entries) {
dev_warn(obj->dev, "%s: preserve entries full\n", __func__);
@@ -276,10 +283,8 @@ int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e)
}
cr = iotlb_alloc_cr(obj, e);
- if (IS_ERR(cr)) {
- clk_disable(obj->clk);
+ if (IS_ERR(cr))
return PTR_ERR(cr);
- }
iotlb_load_cr(obj, cr);
kfree(cr);
@@ -291,7 +296,6 @@ int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e)
l.vict = l.base;
iotlb_lock_set(obj, &l);
out:
- clk_disable(obj->clk);
return err;
}
EXPORT_SYMBOL_GPL(load_iotlb_entry);
@@ -308,8 +312,6 @@ void flush_iotlb_page(struct iommu *obj, u32 da)
int i;
struct cr_regs cr;
- clk_enable(obj->clk);
-
for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, cr) {
u32 start;
size_t bytes;
@@ -327,8 +329,6 @@ void flush_iotlb_page(struct iommu *obj, u32 da)
iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
}
}
- clk_disable(obj->clk);
-
if (i == obj->nr_tlb_entries)
dev_dbg(obj->dev, "%s: no page for %08x\n", __func__, da);
}
@@ -362,15 +362,10 @@ void flush_iotlb_all(struct iommu *obj)
{
struct iotlb_lock l;
- clk_enable(obj->clk);
-
l.base = 0;
l.vict = 0;
iotlb_lock_set(obj, &l);
-
iommu_write_reg(obj, 1, MMU_GFLUSH);
-
- clk_disable(obj->clk);
}
EXPORT_SYMBOL_GPL(flush_iotlb_all);
@@ -385,12 +380,75 @@ EXPORT_SYMBOL_GPL(flush_iotlb_all);
*/
void iommu_set_twl(struct iommu *obj, bool on)
{
- clk_enable(obj->clk);
arch_iommu->set_twl(obj, on);
- clk_disable(obj->clk);
}
EXPORT_SYMBOL_GPL(iommu_set_twl);
+/**
+ * save_tlb_entries - save a num of locked tlb entries
+ * @obj: target iommu
+ *
+ */
+u32 iommu_save_tlb_entries(struct iommu *obj)
+{
+ int i;
+ struct cr_regs cr_tmp;
+ struct iotlb_entry *e;
+
+ if (!obj || !obj->tlbs_e)
+ goto error;
+
+ e = obj->tlbs_e;
+ for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, cr_tmp) {
+ iotlb_cr_to_e(&cr_tmp, e);
+ dev_dbg(obj->dev, "%s: %08x %08x %d %d %d", __func__, e->da,
+ e->pa, e->pgsz, e->prsvd,
+ e->valid);
+ e++;
+ }
+
+ return 0;
+error:
+ return -EINVAL;
+}
+
+/**
+ * restore_tlb_entries - restor a num of locked tlb entries
+ * @obj: target iommu
+ *
+ * Function used to restore exclusively the valid TLB entries
+ * based on the e->valid value
+ *
+ */
+u32 iommu_restore_tlb_entries(struct iommu *obj)
+{
+ int i;
+ int status;
+ struct iotlb_entry *e;
+
+ if (!obj || !obj->tlbs_e)
+ goto error;
+
+ e = obj->tlbs_e;
+ for (i = 0; i < obj->nr_tlb_entries; i++) {
+ if (!e->prsvd) {
+ e++;
+ continue;
+ }
+ dev_dbg(obj->dev, "%s: %08x %08x %d %d %d", __func__, e->da,
+ e->pa, e->pgsz, e->prsvd,
+ e->valid);
+ status = load_iotlb_entry(obj, e);
+ if (status)
+ goto error;
+ e++;
+ }
+
+ return 0;
+error:
+ return -EINVAL;
+}
+
#if defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE)
ssize_t iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t bytes)
@@ -398,12 +456,7 @@ ssize_t iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t bytes)
if (!obj || !buf)
return -EINVAL;
- clk_enable(obj->clk);
-
bytes = arch_iommu->dump_ctx(obj, buf, bytes);
-
- clk_disable(obj->clk);
-
return bytes;
}
EXPORT_SYMBOL_GPL(iommu_dump_ctx);
@@ -415,9 +468,7 @@ static int __dump_tlb_entries(struct iommu *obj, struct cr_regs *crs, int num)
struct cr_regs tmp;
struct cr_regs *p = crs;
- clk_enable(obj->clk);
iotlb_lock_get(obj, &saved);
-
for_each_iotlb_cr(obj, num, i, tmp) {
if (!iotlb_cr_valid(&tmp))
continue;
@@ -425,8 +476,6 @@ static int __dump_tlb_entries(struct iommu *obj, struct cr_regs *crs, int num)
}
iotlb_lock_set(obj, &saved);
- clk_disable(obj->clk);
-
return p - crs;
}
@@ -471,22 +520,15 @@ EXPORT_SYMBOL_GPL(foreach_iommu_device);
*/
static void flush_iopgd_range(u32 *first, u32 *last)
{
- /* FIXME: L2 cache should be taken care of if it exists */
- do {
- asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pgd"
- : : "r" (first));
- first += L1_CACHE_BYTES / sizeof(*first);
- } while (first <= last);
+ dmac_flush_range(first, last);
+ outer_flush_range(virt_to_phys(first), virt_to_phys(last));
}
+
static void flush_iopte_range(u32 *first, u32 *last)
{
- /* FIXME: L2 cache should be taken care of if it exists */
- do {
- asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pte"
- : : "r" (first));
- first += L1_CACHE_BYTES / sizeof(*first);
- } while (first <= last);
+ dmac_flush_range(first, last);
+ outer_flush_range(virt_to_phys(first), virt_to_phys(last));
}
static void iopte_free(u32 *iopte)
@@ -515,7 +557,7 @@ static u32 *iopte_alloc(struct iommu *obj, u32 *iopgd, u32 da)
return ERR_PTR(-ENOMEM);
*iopgd = virt_to_phys(iopte) | IOPGD_TABLE;
- flush_iopgd_range(iopgd, iopgd);
+ flush_iopgd_range(iopgd, iopgd + 1);
dev_vdbg(obj->dev, "%s: a new pte:%p\n", __func__, iopte);
} else {
@@ -544,7 +586,7 @@ static int iopgd_alloc_section(struct iommu *obj, u32 da, u32 pa, u32 prot)
}
*iopgd = (pa & IOSECTION_MASK) | prot | IOPGD_SECTION;
- flush_iopgd_range(iopgd, iopgd);
+ flush_iopgd_range(iopgd, iopgd + 1);
return 0;
}
@@ -561,7 +603,7 @@ static int iopgd_alloc_super(struct iommu *obj, u32 da, u32 pa, u32 prot)
for (i = 0; i < 16; i++)
*(iopgd + i) = (pa & IOSUPER_MASK) | prot | IOPGD_SUPER;
- flush_iopgd_range(iopgd, iopgd + 15);
+ flush_iopgd_range(iopgd, iopgd + 16);
return 0;
}
@@ -574,7 +616,7 @@ static int iopte_alloc_page(struct iommu *obj, u32 da, u32 pa, u32 prot)
return PTR_ERR(iopte);
*iopte = (pa & IOPAGE_MASK) | prot | IOPTE_SMALL;
- flush_iopte_range(iopte, iopte);
+ flush_iopte_range(iopte, iopte + 1);
dev_vdbg(obj->dev, "%s: da:%08x pa:%08x pte:%p *pte:%08x\n",
__func__, da, pa, iopte, *iopte);
@@ -599,7 +641,7 @@ static int iopte_alloc_large(struct iommu *obj, u32 da, u32 pa, u32 prot)
for (i = 0; i < 16; i++)
*(iopte + i) = (pa & IOLARGE_MASK) | prot | IOPTE_LARGE;
- flush_iopte_range(iopte, iopte + 15);
+ flush_iopte_range(iopte, iopte + 16);
return 0;
}
@@ -750,7 +792,7 @@ size_t iopgtable_clear_entry(struct iommu *obj, u32 da)
}
EXPORT_SYMBOL_GPL(iopgtable_clear_entry);
-static void iopgtable_clear_entry_all(struct iommu *obj)
+void iopgtable_clear_entry_all(struct iommu *obj)
{
int i;
@@ -770,13 +812,43 @@ static void iopgtable_clear_entry_all(struct iommu *obj)
iopte_free(iopte_offset(iopgd, 0));
*iopgd = 0;
- flush_iopgd_range(iopgd, iopgd);
+ flush_iopgd_range(iopgd, iopgd + 1);
}
flush_iotlb_all(obj);
spin_unlock(&obj->page_table_lock);
}
+EXPORT_SYMBOL_GPL(iopgtable_clear_entry_all);
+
+void eventfd_notification(struct iommu *obj)
+{
+ struct iommu_event_ntfy *fd_reg;
+
+ list_for_each_entry(fd_reg, &obj->event_list, list)
+ eventfd_signal(fd_reg->evt_ctx, 1);
+}
+
+int iommu_notify_event(struct iommu *obj, int event, void *data)
+{
+ return raw_notifier_call_chain(&obj->notifier, event, data);
+}
+
+int iommu_register_notifier(struct iommu *obj, struct notifier_block *nb)
+{
+ if (!nb)
+ return -EINVAL;
+ return raw_notifier_chain_register(&obj->notifier, nb);
+}
+EXPORT_SYMBOL_GPL(iommu_register_notifier);
+
+int iommu_unregister_notifier(struct iommu *obj, struct notifier_block *nb)
+{
+ if (!nb)
+ return -EINVAL;
+ return raw_notifier_chain_unregister(&obj->notifier, nb);
+}
+EXPORT_SYMBOL_GPL(iommu_unregister_notifier);
/*
* Device IOMMU generic operations
@@ -790,12 +862,14 @@ static irqreturn_t iommu_fault_handler(int irq, void *data)
if (!obj->refcount)
return IRQ_NONE;
- clk_enable(obj->clk);
- errs = iommu_report_fault(obj, &da);
- clk_disable(obj->clk);
+ eventfd_notification(obj);
+ /* Dynamic loading TLB or PTE */
+ errs = iommu_notify_event(obj, IOMMU_FAULT, data);
- /* Fault callback or TLB/PTE Dynamic loading */
- if (obj->isr && !obj->isr(obj, da, errs, obj->isr_priv))
+ if (errs == NOTIFY_OK)
+ return IRQ_HANDLED;
+ errs = iommu_report_fault(obj, &da);
+ if (!errs)
return IRQ_HANDLED;
iommu_disable(obj);
@@ -858,28 +932,29 @@ struct iommu *iommu_get(const char *name)
int err = -ENOMEM;
struct device *dev;
struct iommu *obj;
-
+ int rev;
dev = driver_find_device(&omap_iommu_driver.driver, NULL, (void *)name,
device_match_by_alias);
if (!dev)
return ERR_PTR(-ENODEV);
-
obj = to_iommu(dev);
mutex_lock(&obj->iommu_lock);
-
if (obj->refcount++ == 0) {
err = iommu_enable(obj);
if (err)
goto err_enable;
+ if (!strcmp(obj->name, "ducati")) {
+ rev = GET_OMAP_REVISION();
+ if (rev == 0x0)
+ iommu_set_twl(obj, false);
+ }
+
flush_iotlb_all(obj);
}
-
if (!try_module_get(obj->owner))
goto err_module;
-
mutex_unlock(&obj->iommu_lock);
-
dev_dbg(obj->dev, "%s: %s\n", __func__, obj->name);
return obj;
@@ -949,62 +1024,39 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
{
int err = -ENODEV;
void *p;
- int irq;
struct iommu *obj;
- struct resource *res;
struct iommu_platform_data *pdata = pdev->dev.platform_data;
- if (pdev->num_resources != 2)
- return -EINVAL;
-
- obj = kzalloc(sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL);
+ obj = kzalloc(sizeof(*obj), GFP_KERNEL);
if (!obj)
return -ENOMEM;
- obj->clk = clk_get(&pdev->dev, pdata->clk_name);
- if (IS_ERR(obj->clk))
- goto err_clk;
-
obj->nr_tlb_entries = pdata->nr_tlb_entries;
obj->name = pdata->name;
obj->dev = &pdev->dev;
- obj->ctx = (void *)obj + sizeof(*obj);
+ obj->pdev = pdev;
obj->da_start = pdata->da_start;
obj->da_end = pdata->da_end;
+ obj->tlbs_e = kzalloc(sizeof(struct iotlb_entry) * obj->nr_tlb_entries,
+ GFP_KERNEL);
+ if (!obj->tlbs_e)
+ goto error;
mutex_init(&obj->iommu_lock);
mutex_init(&obj->mmap_lock);
spin_lock_init(&obj->page_table_lock);
INIT_LIST_HEAD(&obj->mmap);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- err = -ENODEV;
- goto err_mem;
- }
-
- res = request_mem_region(res->start, resource_size(res),
- dev_name(&pdev->dev));
- if (!res) {
- err = -EIO;
- goto err_mem;
- }
+ spin_lock_init(&obj->event_lock);
+ INIT_LIST_HEAD(&obj->event_list);
- obj->regbase = ioremap(res->start, resource_size(res));
- if (!obj->regbase) {
- err = -ENOMEM;
- goto err_ioremap;
- }
+ obj->regbase = pdata->io_base;
+ RAW_INIT_NOTIFIER_HEAD(&obj->notifier);
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- err = -ENODEV;
- goto err_irq;
- }
- err = request_irq(irq, iommu_fault_handler, IRQF_SHARED,
+ err = request_irq(pdata->irq, iommu_fault_handler, IRQF_SHARED,
dev_name(&pdev->dev), obj);
if (err < 0)
- goto err_irq;
+ goto error;
platform_set_drvdata(pdev, obj);
p = (void *)__get_free_pages(GFP_KERNEL, get_order(IOPGD_TABLE_SIZE));
@@ -1022,36 +1074,24 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
return 0;
err_pgd:
- free_irq(irq, obj);
-err_irq:
- iounmap(obj->regbase);
-err_ioremap:
- release_mem_region(res->start, resource_size(res));
-err_mem:
- clk_put(obj->clk);
-err_clk:
+ free_irq(pdata->irq, obj);
+error:
kfree(obj);
return err;
}
static int __devexit omap_iommu_remove(struct platform_device *pdev)
{
- int irq;
- struct resource *res;
struct iommu *obj = platform_get_drvdata(pdev);
+ struct iommu_platform_data *pdata = pdev->dev.platform_data;
+
+ free_irq(pdata->irq, obj);
platform_set_drvdata(pdev, NULL);
iopgtable_clear_entry_all(obj);
free_pages((unsigned long)obj->iopgd, get_order(IOPGD_TABLE_SIZE));
- irq = platform_get_irq(pdev, 0);
- free_irq(irq, obj);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
- iounmap(obj->regbase);
-
- clk_put(obj->clk);
dev_info(&pdev->dev, "%s removed\n", obj->name);
kfree(obj);
return 0;
@@ -1070,6 +1110,7 @@ static void iopte_cachep_ctor(void *iopte)
clean_dcache_area(iopte, IOPTE_TABLE_SIZE);
}
+
static int __init omap_iommu_init(void)
{
struct kmem_cache *p;
diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c
index 51ef43e8def..2a86fe51d7c 100644
--- a/arch/arm/plat-omap/iovmm.c
+++ b/arch/arm/plat-omap/iovmm.c
@@ -57,9 +57,7 @@
*
* '*': not yet, but feasible.
*/
-
static struct kmem_cache *iovm_area_cachep;
-
/* return total bytes of sg buffers */
static size_t sgtable_len(const struct sg_table *sgt)
{
@@ -275,7 +273,6 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da,
if (!obj || !bytes)
return ERR_PTR(-EINVAL);
-
start = da;
alignment = PAGE_SIZE;
@@ -290,11 +287,9 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da,
obj->da_end - start < bytes) {
return ERR_PTR(-EINVAL);
}
-
tmp = NULL;
if (list_empty(&obj->mmap))
goto found;
-
prev_end = 0;
list_for_each_entry(tmp, &obj->mmap, list) {
@@ -459,7 +454,7 @@ static inline void sgtable_drain_kmalloc(struct sg_table *sgt)
static int map_iovm_area(struct iommu *obj, struct iovm_struct *new,
const struct sg_table *sgt, u32 flags)
{
- int err;
+ int err = 0;
unsigned int i, j;
struct scatterlist *sg;
u32 da = new->da_start;
@@ -884,7 +879,6 @@ void iommu_kfree(struct iommu *obj, u32 da)
}
EXPORT_SYMBOL_GPL(iommu_kfree);
-
static int __init iovmm_init(void)
{
const unsigned long flags = SLAB_HWCACHE_ALIGN;
@@ -894,6 +888,7 @@ static int __init iovmm_init(void)
flags, NULL);
if (!p)
return -ENOMEM;
+
iovm_area_cachep = p;
return 0;
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
index 49d3208793e..6412fad5e05 100644
--- a/arch/arm/plat-omap/mailbox.c
+++ b/arch/arm/plat-omap/mailbox.c
@@ -34,6 +34,7 @@
static struct workqueue_struct *mboxd;
static struct omap_mbox **mboxes;
+static DEFINE_MUTEX(mboxes_lock);
static int mbox_configured;
static DEFINE_MUTEX(mbox_configured_lock);
@@ -152,7 +153,7 @@ static void mbox_rx_work(struct work_struct *work)
WARN_ON(len != sizeof(msg));
blocking_notifier_call_chain(&mq->mbox->notifier, len,
- (void *)msg);
+ (void *)msg);
spin_lock_irq(&mq->lock);
if (mq->full) {
mq->full = false;
@@ -167,37 +168,59 @@ static void mbox_rx_work(struct work_struct *work)
*/
static void __mbox_tx_interrupt(struct omap_mbox *mbox)
{
- omap_mbox_disable_irq(mbox, IRQ_TX);
- ack_mbox_irq(mbox, IRQ_TX);
- tasklet_schedule(&mbox->txq->tasklet);
+ struct omap_mbox *mbox_curr;
+ int i =0;
+
+ while (mboxes[i]) {
+ mbox_curr = mboxes[i];
+ if (!mbox_fifo_full(mbox_curr)) {
+ omap_mbox_disable_irq(mbox_curr, IRQ_TX);
+ ack_mbox_irq(mbox_curr, IRQ_TX);
+ tasklet_schedule(&mbox_curr->txq->tasklet);
+ }
+ i++;
+ }
}
static void __mbox_rx_interrupt(struct omap_mbox *mbox)
{
- struct omap_mbox_queue *mq = mbox->rxq;
+ struct omap_mbox_queue *mq;
mbox_msg_t msg;
int len;
-
- while (!mbox_fifo_empty(mbox)) {
- if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) {
- omap_mbox_disable_irq(mbox, IRQ_RX);
- mq->full = true;
- goto nomem;
+ int i = 0;
+ struct omap_mbox *mbox_curr;
+ bool msg_rx;
+
+ while (mboxes[i]) {
+ mbox_curr = mboxes[i];
+ mq = mbox_curr->rxq;
+ msg_rx = false;
+ while (!mbox_fifo_empty(mbox_curr)) {
+ msg_rx = true;
+ if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) {
+ omap_mbox_disable_irq(mbox_curr, IRQ_RX);
+ mq->full = true;
+ goto nomem;
+ }
+
+ msg = mbox_fifo_read(mbox_curr);
+
+ len = kfifo_in(&mq->fifo, (unsigned char *)&msg,
+ sizeof(msg));
+ if (unlikely(len != sizeof(msg)))
+ pr_err("%s: kfifo_in anomaly detected\n",
+ __func__);
+ if (mbox->ops->type == OMAP_MBOX_TYPE1)
+ break;
}
+ /* no more messages in the fifo. clear IRQ source. */
+ if (msg_rx)
+ ack_mbox_irq(mbox_curr, IRQ_RX);
+nomem:
+ queue_work(mboxd, &mbox->rxq->work);
- msg = mbox_fifo_read(mbox);
-
- len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
- WARN_ON(len != sizeof(msg));
-
- if (mbox->ops->type == OMAP_MBOX_TYPE1)
- break;
+ i++;
}
-
- /* no more messages in the fifo. clear IRQ source. */
- ack_mbox_irq(mbox, IRQ_RX);
-nomem:
- queue_work(mboxd, &mbox->rxq->work);
}
static irqreturn_t mbox_interrupt(int irq, void *p)
@@ -291,7 +314,7 @@ fail_alloc_rxq:
fail_alloc_txq:
free_irq(mbox->irq, mbox);
fail_request_irq:
- if (mbox->ops->shutdown)
+ if (likely(mbox->ops->shutdown))
mbox->ops->shutdown(mbox);
mbox->use_count--;
fail_startup:
@@ -335,8 +358,11 @@ struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb)
}
}
- if (!mbox)
+ if (!mbox) {
+ mutex_unlock(&mboxes_lock);
return ERR_PTR(-ENOENT);
+ }
+ mutex_unlock(&mboxes_lock);
ret = omap_mbox_startup(mbox);
if (ret)
@@ -351,7 +377,8 @@ EXPORT_SYMBOL(omap_mbox_get);
void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb)
{
- blocking_notifier_chain_unregister(&mbox->notifier, nb);
+ if (nb)
+ blocking_notifier_chain_unregister(&mbox->notifier, nb);
omap_mbox_fini(mbox);
}
EXPORT_SYMBOL(omap_mbox_put);
@@ -366,6 +393,7 @@ int omap_mbox_register(struct device *parent, struct omap_mbox **list)
mboxes = list;
if (!mboxes)
return -EINVAL;
+ mutex_lock(&mboxes_lock);
for (i = 0; mboxes[i]; i++) {
struct omap_mbox *mbox = mboxes[i];
@@ -378,11 +406,13 @@ int omap_mbox_register(struct device *parent, struct omap_mbox **list)
BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier);
}
+ mutex_unlock(&mboxes_lock);
return 0;
err_out:
while (i--)
device_unregister(mboxes[i]->dev);
+ mutex_unlock(&mboxes_lock);
return ret;
}
EXPORT_SYMBOL(omap_mbox_register);
@@ -394,9 +424,11 @@ int omap_mbox_unregister(void)
if (!mboxes)
return -EINVAL;
+ mutex_lock(&mboxes_lock);
for (i = 0; mboxes[i]; i++)
device_unregister(mboxes[i]->dev);
mboxes = NULL;
+ mutex_unlock(&mboxes_lock);
return 0;
}
EXPORT_SYMBOL(omap_mbox_unregister);
diff --git a/arch/arm/plat-omap/remoteproc.c b/arch/arm/plat-omap/remoteproc.c
new file mode 100644
index 00000000000..6cd2aff8a2b
--- /dev/null
+++ b/arch/arm/plat-omap/remoteproc.c
@@ -0,0 +1,587 @@
+/*
+ * OMAP Remote Processor driver
+ *
+ * Copyright (C) 2010 Texas Instruments Inc.
+ *
+ * Written by Ohad Ben-Cohen <ohad@wizery.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/eventfd.h>
+
+#include <plat/remoteproc.h>
+
+#define OMAP_RPROC_NAME "omap-rproc"
+
+static struct class *omap_rproc_class;
+static dev_t omap_rproc_dev;
+static atomic_t num_of_rprocs;
+
+
+static void rproc_eventfd_ntfy(struct omap_rproc *obj, int event)
+{
+ struct omap_rproc_ntfy *fd_reg;
+
+ spin_lock_irq(&obj->event_lock);
+ list_for_each_entry(fd_reg, &obj->event_list, list)
+ if (fd_reg->event == event)
+ eventfd_signal(fd_reg->evt_ctx, 1);
+ spin_unlock_irq(&obj->event_lock);
+}
+
+int rproc_start(struct omap_rproc *rproc, const void __user *arg)
+{
+ int ret;
+ struct omap_rproc_platform_data *pdata;
+ struct omap_rproc_start_args start_args;
+
+ start_args.start_addr = 0;
+
+ if (!rproc->dev)
+ return -EINVAL;
+
+ pdata = rproc->dev->platform_data;
+ if (!pdata->ops)
+ return -EINVAL;
+
+#if 0
+ if (copy_from_user(&start_args, arg, sizeof(start_args)))
+ return -EFAULT;
+#endif
+ ret = mutex_lock_interruptible(&rproc->lock);
+ if (ret)
+ return ret;
+
+ ret = pdata->ops->start(rproc->dev, start_args.start_addr);
+
+ if (!ret) {
+ omap_rproc_notify_event(rproc, OMAP_RPROC_START, NULL);
+ rproc_eventfd_ntfy(rproc, PROC_START);
+ }
+
+ mutex_unlock(&rproc->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_start);
+
+int rproc_stop(struct omap_rproc *rproc)
+{
+ int ret;
+ struct omap_rproc_platform_data *pdata;
+ if (!rproc->dev)
+ return -EINVAL;
+
+ pdata = rproc->dev->platform_data;
+ if (!pdata->ops)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&rproc->lock);
+ if (ret)
+ return ret;
+
+ ret = pdata->ops->stop(rproc->dev);
+
+ if (!ret) {
+ omap_rproc_notify_event(rproc, OMAP_RPROC_STOP, NULL);
+ rproc_eventfd_ntfy(rproc, PROC_STOP);
+ }
+
+ mutex_unlock(&rproc->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_stop);
+
+int rproc_sleep(struct omap_rproc *rproc)
+{
+ int ret;
+ struct omap_rproc_platform_data *pdata;
+ if (!rproc->dev)
+ return -EINVAL;
+
+ pdata = rproc->dev->platform_data;
+ if (!pdata->ops)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&rproc->lock);
+ if (ret)
+ return ret;
+
+ ret = pdata->ops->sleep(rproc->dev);
+
+ mutex_unlock(&rproc->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_sleep);
+
+int rproc_wakeup(struct omap_rproc *rproc)
+{
+ int ret;
+ struct omap_rproc_platform_data *pdata;
+
+ if (!rproc->dev)
+ return -EINVAL;
+
+ pdata = rproc->dev->platform_data;
+ if (!pdata->ops)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&rproc->lock);
+ if (ret)
+ return ret;
+
+ ret = pdata->ops->wakeup(rproc->dev);
+
+ mutex_unlock(&rproc->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_wakeup);
+
+static inline int rproc_get_state(struct omap_rproc *rproc)
+{
+ struct omap_rproc_platform_data *pdata;
+ if (!rproc->dev)
+ return -EINVAL;
+
+ pdata = rproc->dev->platform_data;
+ if (!pdata->ops)
+ return -EINVAL;
+
+ return pdata->ops->get_state(rproc->dev);
+}
+
+static int rproc_reg_user_event(struct omap_rproc *rproc,
+ const void __user *arg)
+{
+ struct omap_rproc_ntfy *fd_reg;
+ int state;
+ struct omap_rproc_reg_event_args args;
+ int size;
+
+ size = copy_from_user(&args, arg,
+ sizeof(struct omap_rproc_reg_event_args));
+ if (size)
+ return -EINVAL;
+
+ fd_reg = kzalloc(sizeof(struct omap_rproc_ntfy), GFP_KERNEL);
+ if (!fd_reg)
+ return -ENOMEM;
+
+ fd_reg->fd = args.fd;
+ fd_reg->evt_ctx = eventfd_ctx_fdget(args.fd);
+ fd_reg->event = args.event;
+
+ INIT_LIST_HEAD(&fd_reg->list);
+
+ spin_lock_irq(&rproc->event_lock);
+ list_add_tail(&fd_reg->list, &rproc->event_list);
+ spin_unlock_irq(&rproc->event_lock);
+
+ /*
+ * Check the state of remote proc and send the notification
+ * if it is already in the desired state.
+ */
+ state = rproc_get_state(rproc);
+
+ switch (state) {
+ case OMAP_RPROC_RUNNING:
+ case OMAP_RPROC_HIBERNATING:
+ if (args.event == PROC_START)
+ rproc_eventfd_ntfy(rproc, args.event);
+ break;
+ case OMAP_RPROC_STOPPED:
+ if (args.event == PROC_STOP)
+ rproc_eventfd_ntfy(rproc, args.event);
+ break;
+ }
+
+ return 0;
+}
+
+static int rproc_unreg_user_event(struct omap_rproc *rproc,
+ const void __user *arg)
+{
+ struct omap_rproc_ntfy *fd_reg, *temp_reg;
+ struct omap_rproc_reg_event_args args;
+ int size;
+ int ret = -ENOENT;
+
+ size = copy_from_user(&args, arg,
+ sizeof(struct omap_rproc_reg_event_args));
+ if (size)
+ return -EINVAL;
+
+ spin_lock_irq(&rproc->event_lock);
+ list_for_each_entry_safe(fd_reg, temp_reg,
+ &rproc->event_list, list) {
+ if (fd_reg->fd == args.fd) {
+ list_del(&fd_reg->list);
+ kfree(fd_reg);
+ ret = 0;
+ break;
+ }
+ }
+ spin_unlock_irq(&rproc->event_lock);
+ return ret;
+}
+
+int omap_rproc_notify_event(struct omap_rproc *rproc, int event, void *data)
+{
+ return blocking_notifier_call_chain(&rproc->notifier, event, data);
+}
+
+int omap_rproc_register_notifier(struct omap_rproc *rproc,
+ struct notifier_block *nb)
+{
+ if (!nb)
+ return -EINVAL;
+ return blocking_notifier_chain_register(&rproc->notifier, nb);
+}
+EXPORT_SYMBOL_GPL(omap_rproc_register_notifier);
+
+int omap_rproc_unregister_notifier(struct omap_rproc *rproc,
+ struct notifier_block *nb)
+{
+ if (!nb)
+ return -EINVAL;
+ return blocking_notifier_chain_unregister(&rproc->notifier, nb);
+}
+EXPORT_SYMBOL_GPL(omap_rproc_unregister_notifier);
+
+static int omap_rproc_open(struct inode *inode, struct file *filp)
+{
+ unsigned int count, dev_num = iminor(inode);
+ struct omap_rproc *rproc;
+ struct omap_rproc_platform_data *pdata;
+
+ rproc = container_of(inode->i_cdev, struct omap_rproc, cdev);
+ if (!rproc->dev)
+ return -EINVAL;
+
+ pdata = rproc->dev->platform_data;
+
+ count = atomic_inc_return(&rproc->count);
+ dev_info(rproc->dev, "%s: dev num %d, name %s, count %d\n", __func__,
+ dev_num,
+ pdata->name,
+ count);
+ filp->private_data = rproc;
+
+ return 0;
+}
+
+static int omap_rproc_release(struct inode *inode, struct file *filp)
+{
+ unsigned int count;
+ struct omap_rproc_platform_data *pdata;
+ struct omap_rproc *rproc = filp->private_data;
+ if (!rproc || !rproc->dev)
+ return -EINVAL;
+
+ pdata = rproc->dev->platform_data;
+
+ count = atomic_dec_return(&rproc->count);
+ if (!count && (rproc->state != OMAP_RPROC_STOPPED))
+ rproc_stop(rproc);
+
+ return 0;
+}
+
+static long omap_rproc_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+ struct omap_rproc *rproc = filp->private_data;
+
+ if (!rproc)
+ return -EINVAL;
+
+ dev_info(rproc->dev, "%s\n", __func__);
+
+ if (_IOC_TYPE(cmd) != RPROC_IOC_MAGIC)
+ return -ENOTTY;
+ if (_IOC_NR(cmd) > RPROC_IOC_MAXNR)
+ return -ENOTTY;
+
+ switch (cmd) {
+ case RPROC_IOCSTART:
+ /* FIXME: re-visit this check to perform
+ proper permission checks */
+ /* if (!capable(CAP_SYS_ADMIN))
+ return -EPERM; */
+ rc = rproc_start(rproc, (const void __user *) arg);
+ break;
+ case RPROC_IOCSTOP:
+ /* FIXME: re-visit this check to perform
+ proper permission checks */
+ /* if (!capable(CAP_SYS_ADMIN))
+ return -EPERM; */
+ rc = rproc_stop(rproc);
+ break;
+ case RPROC_IOCGETSTATE:
+ rc = rproc_get_state(rproc);
+ break;
+ case RPROC_IOCREGEVENT:
+ rc = rproc_reg_user_event(rproc, (const void __user *) arg);
+ break;
+ case RPROC_IOCUNREGEVENT:
+ rc = rproc_unreg_user_event(rproc, (const void __user *) arg);
+ break;
+ default:
+ return -ENOTTY;
+ }
+
+ /* First element of arg is the status */
+ copy_to_user((void __user *)arg, &rc, sizeof(rc));
+
+ return 0;
+}
+
+static int omap_rproc_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+
+ vma->vm_page_prot = pgprot_dmacoherent(vma->vm_page_prot);
+ vma->vm_flags |= VM_RESERVED;
+
+ if (remap_pfn_range(vma,
+ vma->vm_start,
+ vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+static const struct file_operations omap_rproc_fops = {
+ .open = omap_rproc_open,
+ .release = omap_rproc_release,
+ .unlocked_ioctl = omap_rproc_ioctl,
+ .mmap = omap_rproc_mmap,
+ .owner = THIS_MODULE,
+};
+
+static int omap_rproc_probe(struct platform_device *pdev)
+{
+ int ret = 0, major, minor;
+ struct device *tmpdev;
+ struct device *dev = &pdev->dev;
+ struct omap_rproc_platform_data *pdata = dev->platform_data;
+ struct omap_rproc *rproc;
+
+ if (!pdata || !pdata->name || !pdata->oh_name || !pdata->ops)
+ return -EINVAL;
+
+ dev_info(dev, "%s: adding rproc %s\n", __func__, pdata->name);
+
+ rproc = kzalloc(sizeof(struct omap_rproc), GFP_KERNEL);
+ if (!rproc) {
+ dev_err(dev, "%s: kzalloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ platform_set_drvdata(pdev, rproc);
+ major = MAJOR(omap_rproc_dev);
+ minor = atomic_read(&num_of_rprocs);
+ atomic_inc(&num_of_rprocs);
+
+ rproc->dev = dev;
+ rproc->minor = minor;
+ atomic_set(&rproc->count, 0);
+ rproc->name = pdata->name;
+
+ rproc->timer_clk_id = pdata->timer_clk_id;
+ rproc->timer_hib_id = pdata->timer_hib_id;
+
+ mutex_init(&rproc->lock);
+ BLOCKING_INIT_NOTIFIER_HEAD(&rproc->notifier);
+
+ spin_lock_init(&rproc->event_lock);
+ INIT_LIST_HEAD(&rproc->event_list);
+
+ cdev_init(&rproc->cdev, &omap_rproc_fops);
+ rproc->cdev.owner = THIS_MODULE;
+ ret = cdev_add(&rproc->cdev, MKDEV(major, minor), 1);
+ if (ret) {
+ dev_err(dev, "%s: cdev_add failed: %d\n", __func__, ret);
+ goto free_rproc;
+ }
+
+ tmpdev = device_create(omap_rproc_class, NULL,
+ MKDEV(major, minor),
+ NULL,
+ OMAP_RPROC_NAME "%d", minor);
+ if (IS_ERR(tmpdev)) {
+ ret = PTR_ERR(tmpdev);
+ dev_err(dev, "%s: device_create failed: %d\n", __func__, ret);
+ goto clean_cdev;
+ }
+
+ dev_info(dev, "%s initialized %s, major: %d, base-minor: %d\n",
+ OMAP_RPROC_NAME,
+ pdata->name,
+ MAJOR(omap_rproc_dev),
+ minor);
+ return 0;
+
+clean_cdev:
+ cdev_del(&rproc->cdev);
+free_rproc:
+ kfree(rproc);
+out:
+ return ret;
+}
+
+static int __devexit omap_rproc_remove(struct platform_device *pdev)
+{
+ int major = MAJOR(omap_rproc_dev);
+ struct device *dev = &pdev->dev;
+ struct omap_rproc_platform_data *pdata = dev->platform_data;
+ struct omap_rproc *rproc = platform_get_drvdata(pdev);
+
+ if (!pdata || !rproc)
+ return -EINVAL;
+
+ dev_info(dev, "%s removing %s, major: %d, base-minor: %d\n",
+ OMAP_RPROC_NAME,
+ pdata->name,
+ major,
+ rproc->minor);
+
+ device_destroy(omap_rproc_class, MKDEV(major, rproc->minor));
+ cdev_del(&rproc->cdev);
+
+ return 0;
+}
+
+static struct platform_driver omap_rproc_driver = {
+ .probe = omap_rproc_probe,
+ .remove = __devexit_p(omap_rproc_remove),
+ .driver = {
+ .name = "omap-remoteproc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int device_match_by_alias(struct device *dev, void *data)
+{
+ struct omap_rproc *obj = (struct omap_rproc *)platform_get_drvdata(
+ to_platform_device(dev));
+ const char *name = data;
+
+ pr_debug("%s: %s %s\n", __func__, obj->name, name);
+
+ return strcmp(obj->name, name) == 0;
+}
+
+struct omap_rproc *omap_rproc_get(const char *name)
+{
+ struct device *dev;
+ struct omap_rproc *rproc;
+ dev = driver_find_device(&omap_rproc_driver.driver, NULL, (void *)name,
+ device_match_by_alias);
+ if (!dev)
+ return ERR_PTR(-ENODEV);
+ rproc = (struct omap_rproc *)platform_get_drvdata(
+ to_platform_device(dev));
+
+ dev_dbg(rproc->dev, "%s: %s\n", __func__, rproc->name);
+ return rproc;
+}
+EXPORT_SYMBOL_GPL(omap_rproc_get);
+
+void omap_rproc_put(struct omap_rproc *rproc)
+{
+ if (!rproc || IS_ERR(rproc))
+ return;
+
+ dev_dbg(rproc->dev, "%s: %s\n", __func__, rproc->name);
+}
+EXPORT_SYMBOL_GPL(omap_rproc_put);
+
+static int __init omap_rproc_init(void)
+{
+ int num;
+ int ret;
+
+ if (cpu_is_omap44xx())
+ num = NR_RPROC_OMAP4_DEVICES;
+ else
+ return 0;
+
+ ret = alloc_chrdev_region(&omap_rproc_dev, 0, num, OMAP_RPROC_NAME);
+ if (ret) {
+ pr_err("%s: alloc_chrdev_region failed: %d\n", __func__, ret);
+ goto out;
+ }
+
+ omap_rproc_class = class_create(THIS_MODULE, OMAP_RPROC_NAME);
+ if (IS_ERR(omap_rproc_class)) {
+ ret = PTR_ERR(omap_rproc_class);
+ pr_err("%s: class_create failed: %d\n", __func__, ret);
+ goto unreg_region;
+ }
+
+ atomic_set(&num_of_rprocs, 0);
+
+ ret = platform_driver_register(&omap_rproc_driver);
+ if (ret) {
+ pr_err("%s: platform_driver_register failed: %d\n", __func__,
+ ret);
+ goto out;
+ }
+ return 0;
+
+unreg_region:
+ unregister_chrdev_region(omap_rproc_dev, num);
+out:
+ return ret;
+}
+module_init(omap_rproc_init);
+
+static void __exit omap_rproc_exit(void)
+{
+ int num;
+
+ if (cpu_is_omap44xx())
+ num = NR_RPROC_OMAP4_DEVICES;
+ else
+ return;
+
+ class_destroy(omap_rproc_class);
+ unregister_chrdev_region(omap_rproc_dev, num);
+}
+module_exit(omap_rproc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("OMAP Remote Processor driver");
+MODULE_AUTHOR("Ohad Ben-Cohen <ohad@wizery.com>");
+MODULE_AUTHOR("Hari Kanigeri <h-kanigeri2@ti.com>");
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 177c7d15693..66decb49cea 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -119,4 +119,7 @@ source "drivers/platform/Kconfig"
source "drivers/clk/Kconfig"
source "drivers/hwspinlock/Kconfig"
+
+source "drivers/dsp/syslink/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 3f135b6fb01..f45b9ac9f3c 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -119,3 +119,12 @@ obj-y += ieee802154/
obj-y += clk/
obj-$(CONFIG_HWSPINLOCK) += hwspinlock/
+obj-$(CONFIG_SYSLINK_DUCATI_PM) += dsp/syslink/multicore_ipc/
+obj-$(CONFIG_MPU_SYSLINK_PLATFORM) += dsp/syslink/multicore_ipc/
+obj-$(CONFIG_MPU_SYSLINK_IPC) += dsp/syslink/multicore_ipc/
+obj-$(CONFIG_SYSLINK_PROC) += dsp/syslink/procmgr/
+obj-$(CONFIG_SYSLINK_PROC4430) += dsp/syslink/procmgr/proc4430/
+obj-$(CONFIG_OMAP_DEVICE_HANDLER) += dsp/syslink/devh/
+obj-$(CONFIG_OMAP_DEVICE_HANDLER) += dsp/syslink/devh/44xx/
+obj-$(CONFIG_DMM_OMAP) += media/
+obj-$(CONFIG_TILER_OMAP) += media/
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 02deef42492..8e0de9a0586 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -219,4 +219,14 @@ config BT_ATH3K
Say Y here to compile support for "Atheros firmware download driver"
into the kernel or say M to compile it as module (ath3k).
+config BT_WILINK
+ tristate "Texas Instruments WiLink7 driver"
+ depends on TI_ST
+ help
+ This enables the Bluetooth driver for Texas Instrument's BT/FM/GPS
+ combo devices. This makes use of shared transport line discipline
+ core driver to communicate with the BT core of the combo chip.
+
+ Say Y here to compile support for Texas Instrument's WiLink7 driver
+ into the kernel or say M to compile it as module.
endmenu
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 71bdf13287c..f4460f4f4b7 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o
obj-$(CONFIG_BT_ATH3K) += ath3k.o
obj-$(CONFIG_BT_MRVL) += btmrvl.o
obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o
+obj-$(CONFIG_BT_WILINK) += btwilink.o
btmrvl-y := btmrvl_main.o
btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c
new file mode 100644
index 00000000000..7dc4e17493d
--- /dev/null
+++ b/drivers/bluetooth/btwilink.c
@@ -0,0 +1,395 @@
+/*
+ * Texas Instrument's Bluetooth Driver For Shared Transport.
+ *
+ * Bluetooth Driver acts as interface between HCI core and
+ * TI Shared Transport Layer.
+ *
+ * Copyright (C) 2009-2010 Texas Instruments
+ * Author: Raja Mani <raja_mani@ti.com>
+ * Pavan Savoy <pavan_savoy@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#define DEBUG
+#include <linux/platform_device.h>
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#include <linux/ti_wilink_st.h>
+
+/* Bluetooth Driver Version */
+#define VERSION "1.0"
+#define MAX_BT_CHNL_IDS 3
+
+/* Number of seconds to wait for registration completion
+ * when ST returns PENDING status.
+ */
+#define BT_REGISTER_TIMEOUT 16000 /* 16 sec */
+
+/**
+ * struct ti_st - driver operation structure
+ * @hdev: hci device pointer which binds to bt driver
+ * @reg_status: ST registration callback status
+ * @st_write: write function provided by the ST driver
+ * to be used by the driver during send_frame.
+ * @wait_reg_completion - completion sync between ti_st_open
+ * and st_reg_completion_cb.
+ */
+struct ti_st {
+ struct hci_dev *hdev;
+ char reg_status;
+ long (*st_write) (struct sk_buff *);
+ struct completion wait_reg_completion;
+};
+
+/* Increments HCI counters based on pocket ID (cmd,acl,sco) */
+static inline void ti_st_tx_complete(struct ti_st *hst, int pkt_type)
+{
+ struct hci_dev *hdev = hst->hdev;
+
+ /* Update HCI stat counters */
+ switch (pkt_type) {
+ case HCI_COMMAND_PKT:
+ hdev->stat.cmd_tx++;
+ break;
+
+ case HCI_ACLDATA_PKT:
+ hdev->stat.acl_tx++;
+ break;
+
+ case HCI_SCODATA_PKT:
+ hdev->stat.sco_tx++;
+ break;
+ }
+}
+
+/* ------- Interfaces to Shared Transport ------ */
+
+/* Called by ST layer to indicate protocol registration completion
+ * status.ti_st_open() function will wait for signal from this
+ * API when st_register() function returns ST_PENDING.
+ */
+static void st_reg_completion_cb(void *priv_data, char data)
+{
+ struct ti_st *lhst = priv_data;
+
+ /* Save registration status for use in ti_st_open() */
+ lhst->reg_status = data;
+ /* complete the wait in ti_st_open() */
+ complete(&lhst->wait_reg_completion);
+}
+
+/* Called by Shared Transport layer when receive data is
+ * available */
+static long st_receive(void *priv_data, struct sk_buff *skb)
+{
+ struct ti_st *lhst = priv_data;
+ int err;
+
+ if (!skb)
+ return -EFAULT;
+
+ if (!lhst) {
+ kfree_skb(skb);
+ return -EFAULT;
+ }
+
+ skb->dev = (void *) lhst->hdev;
+
+ /* Forward skb to HCI core layer */
+ err = hci_recv_frame(skb);
+ if (err < 0) {
+ BT_ERR("Unable to push skb to HCI core(%d)", err);
+ return err;
+ }
+
+ lhst->hdev->stat.byte_rx += skb->len;
+
+ return 0;
+}
+
+/* ------- Interfaces to HCI layer ------ */
+/* protocol structure registered with shared transport */
+static struct st_proto_s ti_st_proto[MAX_BT_CHNL_IDS] = {
+ {
+ .chnl_id = HCI_ACLDATA_PKT, /* ACL */
+ .hdr_len = sizeof(struct hci_acl_hdr),
+ .offset_len_in_hdr = offsetof(struct hci_acl_hdr, dlen),
+ .len_size = 2, /* sizeof(dlen) in struct hci_acl_hdr */
+ .reserve = 8,
+ },
+ {
+ .chnl_id = HCI_SCODATA_PKT, /* SCO */
+ .hdr_len = sizeof(struct hci_sco_hdr),
+ .offset_len_in_hdr = offsetof(struct hci_sco_hdr, dlen),
+ .len_size = 1, /* sizeof(dlen) in struct hci_sco_hdr */
+ .reserve = 8,
+ },
+ {
+ .chnl_id = HCI_EVENT_PKT, /* HCI Events */
+ .hdr_len = sizeof(struct hci_event_hdr),
+ .offset_len_in_hdr = offsetof(struct hci_event_hdr, plen),
+ .len_size = 1, /* sizeof(plen) in struct hci_event_hdr */
+ .reserve = 8,
+ },
+};
+
+/* Called from HCI core to initialize the device */
+static int ti_st_open(struct hci_dev *hdev)
+{
+ unsigned long timeleft;
+ struct ti_st *hst;
+ int err, i;
+
+ BT_DBG("%s %p", hdev->name, hdev);
+
+ if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
+ /* provide contexts for callbacks from ST */
+ hst = hdev->driver_data;
+
+ for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
+ ti_st_proto[i].priv_data = hst;
+ ti_st_proto[i].max_frame_size = HCI_MAX_FRAME_SIZE;
+ ti_st_proto[i].recv = st_receive;
+ ti_st_proto[i].reg_complete_cb = st_reg_completion_cb;
+
+ /* Prepare wait-for-completion handler */
+ init_completion(&hst->wait_reg_completion);
+ /* Reset ST registration callback status flag,
+ * this value will be updated in
+ * st_reg_completion_cb()
+ * function whenever it called from ST driver.
+ */
+ hst->reg_status = -EINPROGRESS;
+
+ err = st_register(&ti_st_proto[i]);
+ if (!err)
+ goto done;
+
+ if (err != -EINPROGRESS) {
+ clear_bit(HCI_RUNNING, &hdev->flags);
+ BT_ERR("st_register failed %d", err);
+ return err;
+ }
+
+ /* ST is busy with either protocol
+ * registration or firmware download.
+ */
+ BT_DBG("waiting for registration "
+ "completion signal from ST");
+ timeleft = wait_for_completion_timeout
+ (&hst->wait_reg_completion,
+ msecs_to_jiffies(BT_REGISTER_TIMEOUT));
+ if (!timeleft) {
+ clear_bit(HCI_RUNNING, &hdev->flags);
+ BT_ERR("Timeout(%d sec),didn't get reg "
+ "completion signal from ST",
+ BT_REGISTER_TIMEOUT / 1000);
+ return -ETIMEDOUT;
+ }
+
+ /* Is ST registration callback
+ * called with ERROR status? */
+ if (hst->reg_status != 0) {
+ clear_bit(HCI_RUNNING, &hdev->flags);
+ BT_ERR("ST registration completed with invalid "
+ "status %d", hst->reg_status);
+ return -EAGAIN;
+ }
+
+done:
+ hst->st_write = ti_st_proto[i].write;
+ if (!hst->st_write) {
+ BT_ERR("undefined ST write function");
+ clear_bit(HCI_RUNNING, &hdev->flags);
+ for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
+ /* Undo registration with ST */
+ err = st_unregister(&ti_st_proto[i]);
+ if (err)
+ BT_ERR("st_unregister() failed with "
+ "error %d", err);
+ hst->st_write = NULL;
+ }
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+/* Close device */
+static int ti_st_close(struct hci_dev *hdev)
+{
+ int err, i;
+ struct ti_st *hst = hdev->driver_data;
+
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
+ err = st_unregister(&ti_st_proto[i]);
+ if (err)
+ BT_ERR("st_unregister(%d) failed with error %d",
+ ti_st_proto[i].chnl_id, err);
+ }
+
+ hst->st_write = NULL;
+
+ return err;
+}
+
+static int ti_st_send_frame(struct sk_buff *skb)
+{
+ struct hci_dev *hdev;
+ struct ti_st *hst;
+ long len;
+
+ hdev = (struct hci_dev *)skb->dev;
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
+ hst = hdev->driver_data;
+
+ /* Prepend skb with frame type */
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+
+ BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type,
+ skb->len);
+
+ /* Insert skb to shared transport layer's transmit queue.
+ * Freeing skb memory is taken care in shared transport layer,
+ * so don't free skb memory here.
+ */
+ len = hst->st_write(skb);
+ if (len < 0) {
+ kfree_skb(skb);
+ BT_ERR("ST write failed (%ld)", len);
+ /* Try Again, would only fail if UART has gone bad */
+ return -EAGAIN;
+ }
+
+ /* ST accepted our skb. So, Go ahead and do rest */
+ hdev->stat.byte_tx += len;
+ ti_st_tx_complete(hst, bt_cb(skb)->pkt_type);
+
+ return 0;
+}
+
+static void ti_st_destruct(struct hci_dev *hdev)
+{
+ BT_DBG("%s", hdev->name);
+ /* do nothing here, since platform remove
+ * would free the hdev->driver_data
+ */
+}
+
+static int bt_ti_probe(struct platform_device *pdev)
+{
+ static struct ti_st *hst;
+ struct hci_dev *hdev;
+ int err;
+
+ hst = kzalloc(sizeof(struct ti_st), GFP_KERNEL);
+ if (!hst)
+ return -ENOMEM;
+
+ /* Expose "hciX" device to user space */
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+ kfree(hst);
+ return -ENOMEM;
+ }
+
+ BT_DBG("hdev %p", hdev);
+
+ hst->hdev = hdev;
+ hdev->bus = HCI_UART;
+ hdev->driver_data = hst;
+ hdev->open = ti_st_open;
+ hdev->close = ti_st_close;
+ hdev->flush = NULL;
+ hdev->send = ti_st_send_frame;
+ hdev->destruct = ti_st_destruct;
+ hdev->owner = THIS_MODULE;
+
+ err = hci_register_dev(hdev);
+ if (err < 0) {
+ BT_ERR("Can't register HCI device error %d", err);
+ kfree(hst);
+ hci_free_dev(hdev);
+ return err;
+ }
+
+ BT_DBG("HCI device registered (hdev %p)", hdev);
+
+ dev_set_drvdata(&pdev->dev, hst);
+ return err;
+}
+
+static int bt_ti_remove(struct platform_device *pdev)
+{
+ struct hci_dev *hdev;
+ struct ti_st *hst = dev_get_drvdata(&pdev->dev);
+
+ if (!hst)
+ return -EFAULT;
+
+ BT_DBG("%s", hst->hdev->name);
+
+ hdev = hst->hdev;
+ ti_st_close(hdev);
+ hci_unregister_dev(hdev);
+
+ hci_free_dev(hdev);
+ kfree(hst);
+
+ dev_set_drvdata(&pdev->dev, NULL);
+ return 0;
+}
+
+static struct platform_driver btwilink_driver = {
+ .probe = bt_ti_probe,
+ .remove = bt_ti_remove,
+ .driver = {
+ .name = "btwilink",
+ .owner = THIS_MODULE,
+ },
+};
+
+/* ------- Module Init/Exit interfaces ------ */
+static int __init btwilink_init(void)
+{
+ BT_INFO("Bluetooth Driver for TI WiLink - Version %s", VERSION);
+
+ return platform_driver_register(&btwilink_driver);
+}
+
+static void __exit btwilink_exit(void)
+{
+ platform_driver_unregister(&btwilink_driver);
+}
+
+module_init(btwilink_init);
+module_exit(btwilink_exit);
+
+/* ------ Module Info ------ */
+
+MODULE_AUTHOR("Raja Mani <raja_mani@ti.com>");
+MODULE_DESCRIPTION("Bluetooth Driver for TI Shared Transport" VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/dsp/syslink/Kconfig b/drivers/dsp/syslink/Kconfig
new file mode 100644
index 00000000000..c744be6ddc8
--- /dev/null
+++ b/drivers/dsp/syslink/Kconfig
@@ -0,0 +1,116 @@
+
+
+menuconfig Sys_Link
+ bool "Sys_Link"
+ depends on ARCH_OMAP4
+ default y
+
+if Sys_Link
+
+config SYSLINK_PROC
+ tristate "Syslink ProcMgr"
+ default y
+ help
+ Syslink Proc manager
+
+config SYSLINK_PROC4430
+ tristate "Proc 4430"
+ depends on SYSLINK_PROC
+ default y
+ help
+ Ducati Proc implementation
+
+config DUCATI_BASEIMAGE_PHYS_ADDR
+ hex "Physical Address where the Ducati is loaded"
+ depends on SYSLINK_PROC4430
+ default 0x9CF00000
+ help
+ Specify the physical address where the Ducati image will be
+ loaded.
+
+config SYSLINK_DUCATI_PM
+ bool "IPU Power Management"
+ depends on SYSLINK_PROC
+ default y
+ help
+ Enables the options available for ipu_pm implementation
+
+config SYSLINK_IPU_SELF_HIBERNATION
+ bool "Enable IPU Self hibernation"
+ depends on SYSLINK_DUCATI_PM
+ default n
+ help
+ IPU will hibernate by it self after a configurable time, this
+ controls the self hibernation, IPU will hibernate when a system
+ suspend is executed and wake up when system resumes.
+
+config DUCATI_WATCH_DOG
+ bool "Enable Ducati watch dog timer"
+ depends on SYSLINK_IPU_SELF_HIBERNATION
+ default y
+ help
+ Ducati cores will trigger reset if any of the two M3 cores stop
+ responding after 7 seconds. Requires Hibernation enabled. If
+ hibernation is enabled, M3 cores go to hibernation after 5
+ seconds. Ducati cannot go to hibernation if fault occurs on one
+ of the M3 cores
+
+config SYSLINK_IPU_PM_TRACES
+ bool "IPU PM Debug Traces"
+ depends on SYSLINK_DUCATI_PM
+ default n
+
+config OMAP_DEVICE_HANDLER
+ tristate "Device Handler"
+ depends on OMAP_IOMMU
+ select OMAP_REMOTE_PROC
+ select MPU_SYSLINK_IPC
+ default y
+ help
+ Select this to enable the Device Handler. The Device Handler
+ is a module that handles device-specific events. Events handled
+ include process termination.
+
+config MPU_SYSLINK_PLATFORM
+ tristate "Syslink Platform Module"
+ default y
+ help
+ Syslink Platform Module
+
+config MPU_SYSLINK_IPC
+ tristate "Syslink IPC Module"
+ depends on SYSLINK_PROC4430
+ default y
+ select OMAP_MBOX_FWK
+ select OMAP_REMOTE_PROC
+ help
+ Syslink IPC Module (includes Notify)
+
+config SYSLINK_USE_SYSMGR
+ bool "Enable SYS MGR setup"
+ depends on MPU_SYSLINK_IPC && SYSLINK_PROC
+ default y
+ help
+ This is the experimental option to enable SYS manager setup
+
+config SYSLINK_IOMMU_ENABLE
+ bool
+ select OMAP_IOMMU
+ select OMAP_USER_DMM
+ default y
+
+config SYSLINK_RECOVERY
+ bool "Enable Syslink Fault Recovery"
+ default y
+
+config DMM_DMA_API
+ bool "Enable DMA APIs for flushing"
+ depends on SYSLINK_IOMMU_ENABLE
+ default n
+ help
+ Setting this would enable DMA APIs in Kernel for Mapped buffers
+ cache maintainance. Not setting this option will allow unrestricted
+ cache operations on the userspace buffers. This option would be
+ made default once the code is stabilized
+
+endif
diff --git a/drivers/dsp/syslink/devh/44xx/Kbuild b/drivers/dsp/syslink/devh/44xx/Kbuild
new file mode 100644
index 00000000000..1cc02051301
--- /dev/null
+++ b/drivers/dsp/syslink/devh/44xx/Kbuild
@@ -0,0 +1,7 @@
+
+obj-$(CONFIG_OMAP_DEVICE_HANDLER) += devh44xx.o
+
+ccflags-y += -Wno-strict-prototypes
+
+#Header files
+ccflags-y += -Iarch/arm/plat-omap/include/syslink
diff --git a/drivers/dsp/syslink/devh/44xx/devh44xx.c b/drivers/dsp/syslink/devh/44xx/devh44xx.c
new file mode 100644
index 00000000000..2aa7425ac78
--- /dev/null
+++ b/drivers/dsp/syslink/devh/44xx/devh44xx.c
@@ -0,0 +1,957 @@
+/*
+ * Device Handler machine-specific module for OMAP4
+ *
+ * Copyright (C) 2010 Texas Instruments Inc.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/sched.h>
+#include <linux/eventfd.h>
+#include <mach/irqs.h>
+#include <plat/omap_device.h>
+#include <plat/iommu.h>
+#include <plat/remoteproc.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#if defined(CONFIG_TILER_OMAP)
+#include <mach/tiler.h>
+#endif
+
+#include <syslink/ipc.h>
+
+#include "../devh.h"
+#include "../../ipu_pm/ipu_pm.h"
+
+static struct mutex local_gate;
+
+struct omap_devh_runtime_info {
+ int brd_state;
+ struct iommu *iommu;
+ struct omap_rproc *rproc;
+};
+
+enum {
+ DEVH_BRDST_RUNNING,
+ DEVH_BRDST_STOPPED,
+ DEVH_BRDST_ERROR,
+};
+
+struct deh_event_ntfy {
+ u32 fd;
+ u32 event;
+ struct eventfd_ctx *evt_ctx;
+ struct list_head list;
+};
+
+struct omap_devh *devh_get_obj(int dev_index);
+
+static struct omap_devh_platform_data *devh_get_plat_data_by_name(char *name)
+{
+ int i, j = devh_get_plat_data_size();
+ struct omap_devh_platform_data *pdata = devh_get_plat_data();
+
+ if (name) {
+ for (i = 0; i < j; i++) {
+ if (!(strcmp(name, pdata[i].name)))
+ return &pdata[i];
+ }
+ }
+ return NULL;
+}
+
+static int devh_notify_event(struct omap_devh *devh , u32 event)
+{
+ struct deh_event_ntfy *fd_reg;
+
+ spin_lock_irq(&(devh->event_lock));
+ list_for_each_entry(fd_reg, &(devh->event_list), list)
+ if (fd_reg->event == event)
+ eventfd_signal(fd_reg->evt_ctx, 1);
+ spin_unlock_irq(&(devh->event_lock));
+
+ return 0;
+}
+
+static void devh_notification_handler(u16 proc_id, u16 line_id, u32 event_id,
+ uint *arg, u32 payload)
+{
+ pr_warning("Sys Error occured in Ducati for proc_id = %d\n",
+ proc_id);
+
+ /* schedule the recovery */
+ ipc_recover_schedule();
+
+ devh_notify_event((struct omap_devh *)arg, DEV_SYS_ERROR);
+}
+
+static int devh44xx_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v,
+ struct omap_devh_platform_data *pdata)
+{
+ int err = 0;
+ pid_t my_pid = current->tgid;
+ struct omap_devh_runtime_info *pinfo = NULL;
+ struct omap_devh_platform_data *pdata2 = NULL;
+
+ if (pdata)
+ pinfo = (struct omap_devh_runtime_info *)pdata->private_data;
+ else
+ return -EINVAL;
+
+ if (pinfo->brd_state == DEVH_BRDST_RUNNING) {
+ err = mutex_lock_interruptible(&local_gate);
+ if (err)
+ goto exit;
+ err = ipu_pm_notifications(APP_M3, PM_PID_DEATH,
+ (void *)my_pid);
+ if (err) {
+ pinfo->brd_state = DEVH_BRDST_ERROR;
+ if (!strcmp(pdata->name, "SysM3")) {
+ pdata2 = devh_get_plat_data_by_name("AppM3");
+ if (pdata2) {
+ pinfo =
+ (struct omap_devh_runtime_info *)
+ pdata2->private_data;
+ pinfo->brd_state = DEVH_BRDST_ERROR;
+ }
+ }
+ }
+ mutex_unlock(&local_gate);
+ }
+
+exit:
+ return err;
+}
+
+static int devh44xx_sysm3_iommu_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ struct omap_devh_platform_data *pdata =
+ devh_get_plat_data_by_name("SysM3");
+ struct omap_devh_runtime_info *pinfo = NULL;
+
+ if (!pdata)
+ return 0;
+
+ pinfo = (struct omap_devh_runtime_info *)pdata->private_data;
+
+ switch ((int)val) {
+ case IOMMU_CLOSE:
+ return devh44xx_notifier_call(nb, val, v, pdata);
+ case IOMMU_FAULT:
+ pinfo->brd_state = DEVH_BRDST_ERROR;
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static int devh44xx_appm3_iommu_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ struct omap_devh_platform_data *pdata =
+ devh_get_plat_data_by_name("AppM3");
+ struct omap_devh_runtime_info *pinfo = NULL;
+
+ if (!pdata)
+ return 0;
+
+ pinfo = (struct omap_devh_runtime_info *)pdata->private_data;
+
+ switch ((int)val) {
+ case IOMMU_CLOSE:
+ return devh44xx_notifier_call(nb, val, v, pdata);
+ case IOMMU_FAULT:
+ pinfo->brd_state = DEVH_BRDST_ERROR;
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static int devh44xx_tesla_iommu_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ struct omap_devh_platform_data *pdata =
+ devh_get_plat_data_by_name("Tesla");
+ struct omap_devh_runtime_info *pinfo = NULL;
+
+ if (!pdata)
+ return 0;
+
+ pinfo = (struct omap_devh_runtime_info *)pdata->private_data;
+
+ switch ((int)val) {
+ case IOMMU_CLOSE:
+ return devh44xx_notifier_call(nb, val, v, pdata);
+ case IOMMU_FAULT:
+ pinfo->brd_state = DEVH_BRDST_ERROR;
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static struct notifier_block devh_notify_nb_iommu_tesla = {
+ .notifier_call = devh44xx_tesla_iommu_notifier_call,
+};
+static struct notifier_block devh_notify_nb_iommu_ducati0 = {
+ .notifier_call = devh44xx_sysm3_iommu_notifier_call,
+};
+static struct notifier_block devh_notify_nb_iommu_ducati1 = {
+ .notifier_call = devh44xx_appm3_iommu_notifier_call,
+};
+
+static int devh44xx_wdt_ipc_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ struct omap_devh *obj;
+ int i = devh_get_plat_data_size();
+
+ pr_warning("Ducati Watch Dog fired\n");
+
+ /* schedule the recovery */
+ ipc_recover_schedule();
+
+ while (i--) {
+ obj = devh_get_obj(i);
+ devh_notify_event(obj, DEV_WATCHDOG_ERROR);
+ }
+
+ return 0;
+}
+
+static struct notifier_block devh_notify_nb_ipc_wdt = {
+ .notifier_call = devh44xx_wdt_ipc_notifier_call,
+};
+
+static int devh44xx_sysm3_ipc_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ struct omap_devh_platform_data *pdata =
+ devh_get_plat_data_by_name("SysM3");
+ u16 *proc_id = (u16 *)v;
+ struct omap_devh *obj;
+ int status;
+
+ switch ((int)val) {
+ case IPC_CLOSE:
+ return devh44xx_notifier_call(nb, val, v, pdata);
+ case IPC_START:
+ /*
+ * TODO - hack hack - clean this up to use a define proc id
+ * and use this to get the devh object
+ */
+ if (*proc_id == multiproc_get_id("SysM3")) {
+ obj = devh_get_obj(1);
+ if (WARN_ON(obj == NULL)) {
+ status = -1;
+ pr_err("devh_44xx_notifier_call: cannot grab "
+ "device devh1 instance\n");
+ } else {
+ status = notify_register_event(pdata->proc_id,
+ pdata->line_id,
+ pdata->err_event_id,
+ (notify_fn_notify_cbck) \
+ devh_notification_handler,
+ (void *)obj);
+ }
+ if (status == 0)
+ status = ipu_pm_register_notifier(
+ &devh_notify_nb_ipc_wdt);
+ } else {
+ status = 0;
+ }
+ return status;
+ case IPC_STOP:
+ if (*proc_id == multiproc_get_id("SysM3")) {
+ ipu_pm_unregister_notifier(&devh_notify_nb_ipc_wdt);
+ obj = devh_get_obj(1);
+ if (WARN_ON(obj == NULL)) {
+ status = -1;
+ pr_err("devh_44xx_notifier_call: cannot grab "
+ "device devh1 instance\n");
+ } else {
+ status = notify_unregister_event(pdata->proc_id,
+ pdata->line_id,
+ pdata->err_event_id,
+ (notify_fn_notify_cbck) \
+ devh_notification_handler,
+ (void *)obj);
+ }
+ } else {
+ status = 0;
+ }
+ return status;
+ default:
+ return 0;
+ }
+}
+
+static int devh44xx_appm3_ipc_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ struct omap_devh_platform_data *pdata =
+ devh_get_plat_data_by_name("AppM3");
+ struct omap_devh *obj;
+
+ u16* proc_id = (u16 *)v;
+ int status;
+ switch ((int)val) {
+ case IPC_CLOSE:
+ return devh44xx_notifier_call(nb, val, v, pdata);
+ case IPC_START:
+ /*
+ * TODO - hack hack - clean this up to use a define proc id
+ * and use this to get the devh object
+ */
+ if (*proc_id == multiproc_get_id("AppM3")) {
+ obj = devh_get_obj(2);
+ if (WARN_ON(obj == NULL)) {
+ status = -1;
+ pr_err("devh_44xx_notifier_call: cannot grab "
+ "device devh2 instance\n");
+ } else {
+ status = notify_register_event(pdata->proc_id,
+ pdata->line_id,
+ pdata->err_event_id,
+ (notify_fn_notify_cbck) \
+ devh_notification_handler,
+ (void *)obj);
+ }
+ } else {
+ status = 0;
+ }
+ return status;
+ case IPC_STOP:
+ if (*proc_id == multiproc_get_id("AppM3")) {
+ obj = devh_get_obj(2);
+ if (WARN_ON(obj == NULL)) {
+ status = -1;
+ pr_err("devh_44xx_notifier_call: cannot grab "
+ "device devh2 instance\n");
+ } else {
+ status = notify_unregister_event(pdata->proc_id,
+ pdata->line_id,
+ pdata->err_event_id,
+ (notify_fn_notify_cbck) \
+ devh_notification_handler,
+ (void *)obj);
+ }
+ } else {
+ status = 0;
+ }
+ return status;
+ default:
+ return 0;
+ }
+}
+
+static int devh44xx_tesla_ipc_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ struct omap_devh_platform_data *pdata =
+ devh_get_plat_data_by_name("Tesla");
+
+ switch ((int)val) {
+ case IPC_CLOSE:
+ return devh44xx_notifier_call(nb, val, v, pdata);
+ default:
+ return 0;
+ }
+}
+
+static struct notifier_block devh_notify_nb_ipc_tesla = {
+ .notifier_call = devh44xx_tesla_ipc_notifier_call,
+};
+static struct notifier_block devh_notify_nb_ipc_ducati1 = {
+ .notifier_call = devh44xx_appm3_ipc_notifier_call,
+};
+static struct notifier_block devh_notify_nb_ipc_ducati0 = {
+ .notifier_call = devh44xx_sysm3_ipc_notifier_call,
+};
+
+static int devh44xx_sysm3_rproc_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ struct omap_devh_platform_data *pdata =
+ devh_get_plat_data_by_name("SysM3");
+ struct omap_devh_runtime_info *pinfo = NULL;
+
+ if (pdata)
+ pinfo = (struct omap_devh_runtime_info *)pdata->private_data;
+ else
+ return -EINVAL;
+
+ switch ((int)val) {
+ case OMAP_RPROC_START:
+ pinfo->brd_state = DEVH_BRDST_RUNNING;
+ pinfo->iommu = iommu_get("ducati");
+ if (pinfo->iommu != ERR_PTR(-ENODEV) &&
+ pinfo->iommu != ERR_PTR(-EINVAL))
+ iommu_register_notifier(pinfo->iommu,
+ &devh_notify_nb_iommu_ducati0);
+ else
+ pinfo->iommu = NULL;
+ return 0;
+ case OMAP_RPROC_STOP:
+ pinfo->brd_state = DEVH_BRDST_STOPPED;
+ if (pinfo->iommu != NULL) {
+ iommu_unregister_notifier(pinfo->iommu,
+ &devh_notify_nb_iommu_ducati0);
+ iommu_put(pinfo->iommu);
+ pinfo->iommu = NULL;
+ }
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static int devh44xx_appm3_rproc_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ struct omap_devh_platform_data *pdata =
+ devh_get_plat_data_by_name("AppM3");
+ struct omap_devh_runtime_info *pinfo = NULL;
+
+ if (pdata)
+ pinfo = (struct omap_devh_runtime_info *)pdata->private_data;
+ else
+ return -EINVAL;
+
+ switch ((int)val) {
+ case OMAP_RPROC_START:
+ pinfo->brd_state = DEVH_BRDST_RUNNING;
+ pinfo->iommu = iommu_get("ducati");
+ if (pinfo->iommu != ERR_PTR(-ENODEV) &&
+ pinfo->iommu != ERR_PTR(-EINVAL))
+ iommu_register_notifier(pinfo->iommu,
+ &devh_notify_nb_iommu_ducati1);
+ else
+ pinfo->iommu = NULL;
+ return 0;
+ case OMAP_RPROC_STOP:
+ pinfo->brd_state = DEVH_BRDST_STOPPED;
+ if (pinfo->iommu != NULL) {
+ iommu_unregister_notifier(pinfo->iommu,
+ &devh_notify_nb_iommu_ducati1);
+ iommu_put(pinfo->iommu);
+ pinfo->iommu = NULL;
+ }
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static int devh44xx_tesla_rproc_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ struct omap_devh_platform_data *pdata =
+ devh_get_plat_data_by_name("Tesla");
+ struct omap_devh_runtime_info *pinfo = NULL;
+
+ if (pdata)
+ pinfo = (struct omap_devh_runtime_info *)pdata->private_data;
+ else
+ return -EINVAL;
+
+ switch ((int)val) {
+ case OMAP_RPROC_START:
+ pinfo->brd_state = DEVH_BRDST_RUNNING;
+ pinfo->iommu = iommu_get("tesla");
+ if (pinfo->iommu != ERR_PTR(-ENODEV) &&
+ pinfo->iommu != ERR_PTR(-EINVAL))
+ iommu_register_notifier(pinfo->iommu,
+ &devh_notify_nb_iommu_tesla);
+ else
+ pinfo->iommu = NULL;
+ return 0;
+ case OMAP_RPROC_STOP:
+ pinfo->brd_state = DEVH_BRDST_STOPPED;
+ if (pinfo->iommu != NULL) {
+ iommu_unregister_notifier(pinfo->iommu,
+ &devh_notify_nb_iommu_tesla);
+ iommu_put(pinfo->iommu);
+ pinfo->iommu = NULL;
+ }
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static struct notifier_block devh_notify_nb_rproc_tesla = {
+ .notifier_call = devh44xx_tesla_rproc_notifier_call,
+};
+static struct notifier_block devh_notify_nb_rproc_ducati0 = {
+ .notifier_call = devh44xx_sysm3_rproc_notifier_call,
+};
+static struct notifier_block devh_notify_nb_rproc_ducati1 = {
+ .notifier_call = devh44xx_appm3_rproc_notifier_call,
+};
+
+#if defined(CONFIG_TILER_OMAP)
+static int devh44xx_sysm3_tiler_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ struct omap_devh_platform_data *pdata =
+ devh_get_plat_data_by_name("SysM3");
+
+ switch ((int)val) {
+ case TILER_DEVICE_CLOSE:
+ return devh44xx_notifier_call(nb, val, v, pdata);
+ default:
+ return 0;
+ }
+}
+
+static int devh44xx_appm3_tiler_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ struct omap_devh_platform_data *pdata =
+ devh_get_plat_data_by_name("AppM3");
+
+ switch ((int)val) {
+ case TILER_DEVICE_CLOSE:
+ return devh44xx_notifier_call(nb, val, v, pdata);
+ default:
+ return 0;
+ }
+}
+
+static int devh44xx_tesla_tiler_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ struct omap_devh_platform_data *pdata =
+ devh_get_plat_data_by_name("Tesla");
+
+ switch ((int)val) {
+ case TILER_DEVICE_CLOSE:
+ return devh44xx_notifier_call(nb, val, v, pdata);
+ default:
+ return 0;
+ }
+}
+
+static struct notifier_block devh_notify_nb_tiler_tesla = {
+ .notifier_call = devh44xx_tesla_tiler_notifier_call,
+};
+static struct notifier_block devh_notify_nb_tiler_ducati0 = {
+ .notifier_call = devh44xx_sysm3_tiler_notifier_call,
+};
+static struct notifier_block devh_notify_nb_tiler_ducati1 = {
+ .notifier_call = devh44xx_appm3_tiler_notifier_call,
+};
+#endif
+
+static inline int devh44xx_sysm3_register(struct omap_devh *devh)
+{
+ int retval = 0;
+ struct omap_devh_platform_data *pdata = NULL;
+ struct omap_devh_runtime_info *pinfo = NULL;
+ if (!devh->dev)
+ return -EINVAL;
+
+ pdata = (struct omap_devh_platform_data *)devh->dev->platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+
+ pinfo = (struct omap_devh_runtime_info *)pdata->private_data;
+
+ /* register will kernel modules for event notifications. */
+ ipc_register_notifier(&devh_notify_nb_ipc_ducati0);
+ pinfo->rproc = omap_rproc_get("ducati-proc0");
+ if (pinfo->rproc != ERR_PTR(-ENODEV))
+ omap_rproc_register_notifier(pinfo->rproc,
+ &devh_notify_nb_rproc_ducati0);
+ else
+ pinfo->rproc = NULL;
+#if defined(CONFIG_TILER_OMAP)
+ tiler_reg_notifier(&devh_notify_nb_tiler_ducati0);
+#endif
+
+ return retval;
+}
+
+static inline int devh44xx_appm3_register(struct omap_devh *devh)
+{
+ int retval = 0;
+ struct omap_devh_platform_data *pdata = NULL;
+ struct omap_devh_runtime_info *pinfo = NULL;
+ if (!devh->dev)
+ return -EINVAL;
+
+ pdata = (struct omap_devh_platform_data *)devh->dev->platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+
+ pinfo = (struct omap_devh_runtime_info *)pdata->private_data;
+
+ /* register will kernel modules for event notifications. */
+ ipc_register_notifier(&devh_notify_nb_ipc_ducati1);
+ pinfo->rproc = omap_rproc_get("ducati-proc1");
+ if (pinfo->rproc != ERR_PTR(-ENODEV))
+ omap_rproc_register_notifier(pinfo->rproc,
+ &devh_notify_nb_rproc_ducati1);
+ else
+ pinfo->rproc = NULL;
+#if defined(CONFIG_TILER_OMAP)
+ tiler_reg_notifier(&devh_notify_nb_tiler_ducati1);
+#endif
+
+ return retval;
+}
+
+static inline int devh44xx_tesla_register(struct omap_devh *devh)
+{
+ int retval = 0;
+ struct omap_devh_platform_data *pdata = NULL;
+ struct omap_devh_runtime_info *pinfo = NULL;
+ if (!devh->dev)
+ return -EINVAL;
+
+ pdata = (struct omap_devh_platform_data *)devh->dev->platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+
+ pinfo = (struct omap_devh_runtime_info *)pdata->private_data;
+
+ /* register will kernel modules for event notifications. */
+ ipc_register_notifier(&devh_notify_nb_ipc_tesla);
+ pinfo->rproc = omap_rproc_get("tesla");
+ if (pinfo->rproc != ERR_PTR(-ENODEV))
+ omap_rproc_register_notifier(pinfo->rproc,
+ &devh_notify_nb_rproc_tesla);
+ else
+ pinfo->rproc = NULL;
+#if defined(CONFIG_TILER_OMAP)
+ tiler_reg_notifier(&devh_notify_nb_tiler_tesla);
+#endif
+
+ return retval;
+}
+
+static inline int devh44xx_sysm3_unregister(struct omap_devh *devh)
+{
+ int retval = 0;
+ struct omap_devh_platform_data *pdata = NULL;
+ struct omap_devh_runtime_info *pinfo = NULL;
+
+ if (!devh->dev)
+ return -EINVAL;
+
+ pdata = (struct omap_devh_platform_data *)devh->dev->platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+
+ pinfo = (struct omap_devh_runtime_info *)pdata->private_data;
+
+ /* un-register will kernel modules for event notifications. */
+ ipc_unregister_notifier(&devh_notify_nb_ipc_ducati0);
+ if (pinfo->rproc) {
+ omap_rproc_unregister_notifier(pinfo->rproc,
+ &devh_notify_nb_rproc_ducati0);
+ omap_rproc_put(pinfo->rproc);
+ }
+ if (pinfo->iommu) {
+ iommu_unregister_notifier(pinfo->iommu,
+ &devh_notify_nb_iommu_ducati0);
+ iommu_put(pinfo->iommu);
+ }
+#if defined(CONFIG_TILER_OMAP)
+ tiler_unreg_notifier(&devh_notify_nb_tiler_ducati0);
+#endif
+
+ return retval;
+}
+
+static inline int devh44xx_appm3_unregister(struct omap_devh *devh)
+{
+ int retval = 0;
+ struct omap_devh_platform_data *pdata = NULL;
+ struct omap_devh_runtime_info *pinfo = NULL;
+
+ if (!devh->dev)
+ return -EINVAL;
+
+ pdata = (struct omap_devh_platform_data *)devh->dev->platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+
+ pinfo = (struct omap_devh_runtime_info *)pdata->private_data;
+
+ /* un-register will kernel modules for event notifications. */
+ ipc_unregister_notifier(&devh_notify_nb_ipc_ducati1);
+ if (pinfo->rproc) {
+ omap_rproc_unregister_notifier(pinfo->rproc,
+ &devh_notify_nb_rproc_ducati1);
+ omap_rproc_put(pinfo->rproc);
+ }
+ if (pinfo->iommu) {
+ iommu_unregister_notifier(pinfo->iommu,
+ &devh_notify_nb_iommu_ducati1);
+ iommu_put(pinfo->iommu);
+ }
+#if defined(CONFIG_TILER_OMAP)
+ tiler_unreg_notifier(&devh_notify_nb_tiler_ducati1);
+#endif
+
+ return retval;
+}
+
+static inline int devh44xx_tesla_unregister(struct omap_devh *devh)
+{
+ int retval = 0;
+ struct omap_devh_platform_data *pdata = NULL;
+ struct omap_devh_runtime_info *pinfo = NULL;
+
+ if (!devh->dev)
+ return -EINVAL;
+
+ pdata = (struct omap_devh_platform_data *)devh->dev->platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+
+ pinfo = (struct omap_devh_runtime_info *)pdata->private_data;
+
+ /* un-register will kernel modules for event notifications. */
+ ipc_unregister_notifier(&devh_notify_nb_ipc_tesla);
+ if (pinfo->rproc) {
+ omap_rproc_unregister_notifier(pinfo->rproc,
+ &devh_notify_nb_rproc_tesla);
+ omap_rproc_put(pinfo->rproc);
+ }
+ if (pinfo->iommu) {
+ iommu_unregister_notifier(pinfo->iommu,
+ &devh_notify_nb_iommu_tesla);
+ iommu_put(pinfo->iommu);
+ }
+#if defined(CONFIG_TILER_OMAP)
+ tiler_unreg_notifier(&devh_notify_nb_tiler_tesla);
+#endif
+ return retval;
+}
+
+static struct omap_devh_runtime_info omap4_sysm3_runtime_info = {
+ .brd_state = DEVH_BRDST_STOPPED,
+ .iommu = NULL,
+ .rproc = NULL,
+};
+
+static struct omap_devh_runtime_info omap4_appm3_runtime_info = {
+ .brd_state = DEVH_BRDST_STOPPED,
+ .iommu = NULL,
+ .rproc = NULL,
+};
+
+static struct omap_devh_runtime_info omap4_tesla_runtime_info = {
+ .brd_state = DEVH_BRDST_STOPPED,
+ .iommu = NULL,
+ .rproc = NULL,
+};
+
+static inline int devh44xx_register_event
+ (struct omap_devh *devh, const void __user *args)
+{
+ struct deh_event_ntfy *fd_reg;
+ struct deh_reg_event_args re_args;
+
+ if (copy_from_user(&re_args, args, sizeof(re_args)))
+ return -EFAULT;
+
+ fd_reg = kzalloc(sizeof(struct deh_event_ntfy), GFP_KERNEL);
+ if (!fd_reg) {
+ dev_err(devh->dev, "%s: kzalloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ fd_reg->fd = re_args.fd;
+ fd_reg->event = re_args.event;
+ fd_reg->evt_ctx = eventfd_ctx_fdget(re_args.fd);
+
+ INIT_LIST_HEAD(&fd_reg->list);
+
+ spin_lock_irq(&(devh->event_lock));
+ list_add_tail(&fd_reg->list, &(devh->event_list));
+ spin_unlock_irq(&(devh->event_lock));
+
+ pr_info("Registered user-space process for %s event in %s\n",
+ (re_args.event == 1 ? "DEV_SYS_ERROR" :
+ (re_args.event == 2 ? "DEV_WATCHDOG_ERROR" : "UNKNOWN EVENT")),
+ devh->name);
+ return 0;
+}
+
+static inline int devh44xx_unregister_event(struct omap_devh *devh,
+ const void __user *args)
+{
+ struct deh_event_ntfy *fd_reg, *tmp_reg;
+ struct deh_reg_event_args re_args;
+ if (copy_from_user(&re_args, args, sizeof(re_args)))
+ return -EFAULT;
+
+ spin_lock_irq(&(devh->event_lock));
+ list_for_each_entry_safe(fd_reg, tmp_reg, &(devh->event_list), list)
+ {
+ if (fd_reg->fd == re_args.fd) {
+ list_del(&fd_reg->list);
+ kfree(fd_reg);
+ }
+ }
+ spin_unlock_irq(&(devh->event_lock));
+ return 0;
+}
+
+static struct omap_devh_ops omap4_sysm3_ops = {
+ .register_notifiers = devh44xx_sysm3_register,
+ .unregister_notifiers = devh44xx_sysm3_unregister,
+ .register_event_notification = devh44xx_register_event,
+ .unregister_event_notification = devh44xx_unregister_event,
+};
+
+static struct omap_devh_ops omap4_appm3_ops = {
+ .register_notifiers = devh44xx_appm3_register,
+ .unregister_notifiers = devh44xx_appm3_unregister,
+ .register_event_notification = devh44xx_register_event,
+ .unregister_event_notification = devh44xx_unregister_event,
+};
+
+static struct omap_devh_ops omap4_tesla_ops = {
+ .register_notifiers = devh44xx_tesla_register,
+ .unregister_notifiers = devh44xx_tesla_unregister,
+};
+
+static struct omap_devh_platform_data omap4_devh_data[] = {
+ {
+ .name = "Tesla",
+ .ops = &omap4_tesla_ops,
+ .proc_id = 0,
+ .err_event_id = -1,
+ .line_id = -1,
+ .private_data = &omap4_tesla_runtime_info,
+ },
+ {
+ .name = "SysM3",
+ .ops = &omap4_sysm3_ops,
+ .proc_id = 2,
+ .err_event_id = (4 | (NOTIFY_SYSTEMKEY << 16)),
+ .line_id = 0,
+ .private_data = &omap4_sysm3_runtime_info,
+ },
+ {
+ .name = "AppM3",
+ .ops = &omap4_appm3_ops,
+ .proc_id = 1,
+ .err_event_id = (4 | (NOTIFY_SYSTEMKEY << 16)),
+ .line_id = 0,
+ .private_data = &omap4_appm3_runtime_info,
+ },
+};
+
+int devh_get_plat_data_size(void)
+{
+ return ARRAY_SIZE(omap4_devh_data);
+}
+EXPORT_SYMBOL(devh_get_plat_data_size);
+
+
+#define NR_DEVH_DEVICES ARRAY_SIZE(omap4_devh_data)
+
+static struct platform_device *omap4_devh_pdev[NR_DEVH_DEVICES];
+
+struct omap_devh_platform_data *devh_get_plat_data(void)
+{
+ return omap4_devh_data;
+}
+
+/* returns devh object based on the device index */
+struct omap_devh *devh_get_obj(int dev_index)
+{
+ struct platform_device *pdev;
+ struct omap_devh *obj = NULL;
+ int max_num_devices;
+
+ max_num_devices = devh_get_plat_data_size();
+
+ if (WARN_ON((dev_index > (max_num_devices - 1))))
+ return NULL;
+
+ pdev = omap4_devh_pdev[dev_index];
+
+ if (pdev)
+ obj = (struct omap_devh *)platform_get_drvdata(pdev);
+
+ return obj;
+}
+
+static int __init omap4_devh_init(void)
+{
+ int i, err;
+
+ mutex_init(&local_gate);
+ for (i = 0; i < NR_DEVH_DEVICES; i++) {
+ struct platform_device *pdev;
+
+ pdev = platform_device_alloc("omap-devicehandler", i);
+ if (!pdev) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ err = platform_device_add_data(pdev, &omap4_devh_data[i],
+ sizeof(omap4_devh_data[0]));
+ sema_init(&(omap4_devh_data[i].sem_handle), 0);
+ err = platform_device_add(pdev);
+ if (err)
+ goto err_out;
+ omap4_devh_pdev[i] = pdev;
+ }
+ return 0;
+
+err_out:
+ while (i--)
+ platform_device_put(omap4_devh_pdev[i]);
+ return err;
+}
+module_init(omap4_devh_init);
+
+static void __exit omap4_devh_exit(void)
+{
+ int i;
+
+ for (i = 0; i < NR_DEVH_DEVICES; i++)
+ platform_device_unregister(omap4_devh_pdev[i]);
+}
+module_exit(omap4_devh_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("OMAP4 Device Handler module");
+MODULE_AUTHOR("Angela Stegmaier <angelabaker@ti.com>");
diff --git a/drivers/dsp/syslink/devh/Kbuild b/drivers/dsp/syslink/devh/Kbuild
new file mode 100644
index 00000000000..65184bd3b59
--- /dev/null
+++ b/drivers/dsp/syslink/devh/Kbuild
@@ -0,0 +1,7 @@
+
+obj-$(CONFIG_OMAP_DEVICE_HANDLER) += devh.o
+
+ccflags-y += -Wno-strict-prototypes
+
+#Header files
+ccflags-y += -Iarch/arm/plat-omap/include/syslink
diff --git a/drivers/dsp/syslink/devh/devh.c b/drivers/dsp/syslink/devh/devh.c
new file mode 100644
index 00000000000..609bb312be2
--- /dev/null
+++ b/drivers/dsp/syslink/devh/devh.c
@@ -0,0 +1,273 @@
+/*
+ * OMAP Device Handler driver
+ *
+ * Copyright (C) 2010 Texas Instruments Inc.
+ *
+ * Written by Angela Stegmaier <angelabaker@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include "devh.h"
+
+#define OMAP_DEVH_NAME "omap-devh"
+#define DRV_NAME "omap-devicehandler"
+
+static struct class *omap_devh_class;
+static dev_t omap_devh_dev;
+static atomic_t num_of_devhs;
+static struct platform_driver omap_devh_driver;
+
+static int omap_devh_open(struct inode *inode, struct file *filp)
+{
+ int ret = 0;
+ struct omap_devh *devh;
+
+ devh = container_of(inode->i_cdev, struct omap_devh, cdev);
+ if (!devh->dev)
+ return -EINVAL;
+
+ filp->private_data = devh;
+
+ return ret;
+}
+
+static int omap_devh_release(struct inode *inode, struct file *filp)
+{
+ struct omap_devh *devh = filp->private_data;
+ if (!devh || !devh->dev)
+ return -EINVAL;
+
+ return 0;
+}
+
+static long omap_devh_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc = 0;
+ struct omap_devh *devh = filp->private_data;
+ struct omap_devh_platform_data *pdata =
+ (struct omap_devh_platform_data *)devh->dev->platform_data;
+
+ if (!devh)
+ return -EINVAL;
+
+ if (_IOC_TYPE(cmd) != DEVH_IOC_MAGIC)
+ return -ENOTTY;
+ if (_IOC_NR(cmd) > DEVH_IOC_MAXNR)
+ return -ENOTTY;
+ if (_IOC_DIR(cmd) & _IOC_READ) {
+ if (!access_ok(VERIFY_WRITE, (void __user *)arg,
+ _IOC_SIZE(cmd)))
+ return -EFAULT;
+ } else if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ if (!access_ok(VERIFY_READ, (void __user *)arg,
+ _IOC_SIZE(cmd)))
+ return -EFAULT;
+ }
+
+ switch (cmd) {
+
+ /*
+ * this will be updated to support user registering for event
+ * notifications.
+ */
+ case DEVH_IOCWAITONEVENTS:
+ /*rc = omap_devh_wait_on_events(devh);*/
+ break;
+ case DEVH_IOCEVENTREG:
+ rc = pdata->ops->register_event_notification(devh,
+ (const void __user *)arg);
+ break;
+ case DEVH_IOCEVENTUNREG:
+ rc = pdata->ops->unregister_event_notification(devh,
+ (const void __user *)arg);
+ break;
+ default:
+ return -ENOTTY;
+ }
+
+ return rc;
+}
+
+static const struct file_operations omap_devh_fops = {
+ .open = omap_devh_open,
+ .release = omap_devh_release,
+ .unlocked_ioctl = omap_devh_ioctl,
+ .owner = THIS_MODULE,
+};
+
+static int omap_devh_probe(struct platform_device *pdev)
+{
+ int ret = 0, major, minor;
+ struct device *tmpdev;
+ struct device *dev = &pdev->dev;
+ struct omap_devh_platform_data *pdata = dev->platform_data;
+ struct omap_devh *devh;
+
+ if (!pdata || !pdata->name || !pdata->ops)
+ return -EINVAL;
+
+ dev_info(dev, "%s: adding devh %s\n", __func__, pdata->name);
+
+ devh = kzalloc(sizeof(struct omap_devh), GFP_KERNEL);
+ if (!devh) {
+ dev_err(dev, "%s: kzalloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ platform_set_drvdata(pdev, devh);
+ major = MAJOR(omap_devh_dev);
+ minor = atomic_read(&num_of_devhs);
+ atomic_inc(&num_of_devhs);
+
+ devh->dev = dev;
+ devh->minor = minor;
+ devh->name = pdata->name;
+
+ cdev_init(&devh->cdev, &omap_devh_fops);
+ devh->cdev.owner = THIS_MODULE;
+ ret = cdev_add(&devh->cdev, MKDEV(major, minor), 1);
+ if (ret) {
+ dev_err(dev, "%s: cdev_add failed: %d\n", __func__, ret);
+ goto free_devh;
+ }
+
+ tmpdev = device_create(omap_devh_class, NULL,
+ MKDEV(major, minor),
+ NULL,
+ OMAP_DEVH_NAME "%d", minor);
+ if (IS_ERR(tmpdev)) {
+ ret = PTR_ERR(tmpdev);
+ pr_err("%s: device_create failed: %d\n", __func__, ret);
+ goto clean_cdev;
+ }
+
+ pr_info("%s initialized %s, major: %d, base-minor: %d\n",
+ OMAP_DEVH_NAME,
+ pdata->name,
+ MAJOR(omap_devh_dev),
+ minor);
+
+ INIT_LIST_HEAD(&(devh->event_list));
+ spin_lock_init(&(devh->event_lock));
+ if (pdata->ops->register_notifiers)
+ pdata->ops->register_notifiers(devh);
+
+ return 0;
+
+clean_cdev:
+ cdev_del(&devh->cdev);
+free_devh:
+ kfree(devh);
+out:
+ return ret;
+}
+
+static int omap_devh_remove(struct platform_device *pdev)
+{
+ int major = MAJOR(omap_devh_dev);
+ struct device *dev = &pdev->dev;
+ struct omap_devh_platform_data *pdata = dev->platform_data;
+ struct omap_devh *devh = platform_get_drvdata(pdev);
+
+ if (!pdata || !devh)
+ return -EINVAL;
+
+ if (pdata->ops->unregister_notifiers)
+ pdata->ops->unregister_notifiers(devh);
+
+ dev_info(dev, "%s removing %s, major: %d, base-minor: %d\n",
+ OMAP_DEVH_NAME,
+ pdata->name,
+ major,
+ devh->minor);
+
+ device_destroy(omap_devh_class, MKDEV(major, devh->minor));
+ cdev_del(&devh->cdev);
+ kfree(devh);
+
+ return 0;
+}
+
+static struct platform_driver omap_devh_driver = {
+ .probe = omap_devh_probe,
+ .remove = omap_devh_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init omap_devh_init(void)
+{
+ int num = devh_get_plat_data_size();
+ int ret;
+
+ ret = alloc_chrdev_region(&omap_devh_dev, 0, num, OMAP_DEVH_NAME);
+ if (ret) {
+ pr_err("%s: alloc_chrdev_region failed: %d\n", __func__, ret);
+ goto out;
+ }
+
+ omap_devh_class = class_create(THIS_MODULE, OMAP_DEVH_NAME);
+ if (IS_ERR(omap_devh_class)) {
+ ret = PTR_ERR(omap_devh_class);
+ pr_err("%s: class_create failed: %d\n", __func__, ret);
+ goto unreg_region;
+ }
+
+ atomic_set(&num_of_devhs, 0);
+
+ ret = platform_driver_register(&omap_devh_driver);
+ if (ret) {
+ pr_err("%s: platform_driver_register failed: %d\n",
+ __func__, ret);
+ goto out;
+ }
+ return 0;
+unreg_region:
+ unregister_chrdev_region(omap_devh_dev, num);
+out:
+ return ret;
+}
+module_init(omap_devh_init);
+
+static void __exit omap_devh_exit(void)
+{
+ int num = devh_get_plat_data_size();
+ pr_info("%s\n", __func__);
+ platform_driver_unregister(&omap_devh_driver);
+ class_destroy(omap_devh_class);
+ unregister_chrdev_region(omap_devh_dev, num);
+}
+module_exit(omap_devh_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("OMAP Device Handler driver");
+MODULE_AUTHOR("Angela Stegmaier <angelabaker@ti.com>");
diff --git a/drivers/dsp/syslink/devh/devh.h b/drivers/dsp/syslink/devh/devh.h
new file mode 100644
index 00000000000..a77af52184e
--- /dev/null
+++ b/drivers/dsp/syslink/devh/devh.h
@@ -0,0 +1,87 @@
+/*
+ * OMAP Device Handler driver
+ *
+ * Copyright (C) 2010 Texas Instruments Inc.
+ *
+ * Written by Angela Stegmaier <angelabaker@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef DEVH_H
+#define DEVH_H
+
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/semaphore.h>
+
+#define DEVH_IOC_MAGIC 'E'
+
+#define DEVH_IOCWAITONEVENTS _IO(DEVH_IOC_MAGIC, 0)
+#define DEVH_IOCEVENTREG _IOW(DEVH_IOC_MAGIC, 1, \
+ struct deh_reg_event_args)
+#define DEVH_IOCEVENTUNREG _IOW(DEVH_IOC_MAGIC, 2, \
+ struct deh_reg_event_args)
+
+#define DEVH_IOC_MAXNR (2)
+
+/* Device error types */
+enum {
+ DEV_SYS_ERROR = 1,
+ DEV_WATCHDOG_ERROR,
+};
+
+struct omap_devh;
+
+struct omap_devh_ops {
+ int (*register_notifiers)(struct omap_devh *devh);
+ int (*unregister_notifiers)(struct omap_devh *devh);
+ int (*register_event_notification)(struct omap_devh *devh,
+ const void __user *args);
+ int (*unregister_event_notification)(struct omap_devh *devh,
+ const void __user *args);
+};
+
+struct omap_devh_platform_data {
+ struct omap_devh_ops *ops;
+ char *name;
+ int proc_id;
+ int err_event_id;
+ int line_id;
+ struct semaphore sem_handle;
+ void *private_data;
+};
+
+struct omap_devh {
+ struct device *dev;
+ struct cdev cdev;
+ atomic_t count;
+ int state;
+ int minor;
+ char *name;
+ struct list_head event_list;
+ spinlock_t event_lock;
+};
+
+struct deh_reg_event_args {
+ int fd;
+ u32 event;
+};
+
+extern struct omap_devh_platform_data *devh_get_plat_data(void);
+extern int devh_get_plat_data_size(void);
+
+#endif /* DEVH_H */
diff --git a/drivers/dsp/syslink/ipu_pm/ipu_pm.c b/drivers/dsp/syslink/ipu_pm/ipu_pm.c
new file mode 100644
index 00000000000..ff6ad2041c2
--- /dev/null
+++ b/drivers/dsp/syslink/ipu_pm/ipu_pm.c
@@ -0,0 +1,3165 @@
+#define TMP_AUX_CLK_HACK 1 /* should be removed by Nov 13, 2010 */
+#define SR_WA
+/*
+ * ipu_pm.c
+ *
+ * IPU Power Management support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2009-2010 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 <generated/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/clk.h>
+#include <linux/uaccess.h>
+#include <linux/irq.h>
+
+#include <linux/platform_device.h>
+#include <syslink/notify.h>
+#include <syslink/notify_driver.h>
+#include <syslink/notifydefs.h>
+#include <syslink/notify_driverdefs.h>
+#include <syslink/notify_ducatidriver.h>
+
+/* Power Management headers */
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
+#include <plat/dma.h>
+#include <plat/dmtimer.h>
+#include <plat/clock.h>
+#include <plat/i2c.h>
+#include <plat/io.h>
+#include <plat/iommu.h>
+#include <plat/mailbox.h>
+#include <plat/remoteproc.h>
+#include <plat/omap-pm.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/semaphore.h>
+#include <linux/jiffies.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/i2c/twl.h>
+
+/* Module headers */
+#include <plat/ipu_dev.h>
+#include "../../../../arch/arm/mach-omap2/cm.h"
+#include "ipu_pm.h"
+
+/** ============================================================================
+ * Macros and types
+ * ============================================================================
+ */
+#define HW_AUTO 3
+#define CM_DUCATI_M3_CLKSTCTRL 0x4A008900
+#define SL2_RESOURCE 10
+
+#define proc_supported(proc_id) (proc_id == SYS_M3 || proc_id == APP_M3)
+#define _has_cstrs(r) ((PM_FIRST_RES <= r && r < PM_NUM_RES_W_CSTRS) ? 1 : 0)
+#define _is_res(r) ((PM_FIRST_RES <= r && r < PM_NUM_RES) ? 1 : 0)
+#define _is_event(e) ((PM_FIRST_EVENT <= e && e < PM_LAST_EVENT) ? 1 : 0)
+
+#define LINE_ID 0
+#define NUM_SELF_PROC 2
+#define IPU_KFIFO_SIZE 16
+#define PM_VERSION 0x00020000
+
+/* Flag provided by BIOS */
+#define IDLE_FLAG_PHY_ADDR 0x9E0502D8
+
+#define NUM_IDLE_CORES ((__raw_readl(appm3Idle) << 1) + \
+ (__raw_readl(sysm3Idle)))
+
+/** ============================================================================
+ * Forward declarations of internal functions
+ * ============================================================================
+ */
+
+/* Request a sdma channels on behalf of an IPU client */
+static inline int ipu_pm_get_sdma_chan(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Request a gptimer on behalf of an IPU client */
+static inline int ipu_pm_get_gptimer(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Request an i2c bus on behalf of an IPU client */
+static inline int ipu_pm_get_i2c_bus(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Request a gpio on behalf of an IPU client */
+static inline int ipu_pm_get_gpio(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Request a regulator on behalf of an IPU client */
+static inline int ipu_pm_get_regulator(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Request an Aux clk on behalf of an IPU client */
+static inline int ipu_pm_get_aux_clk(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Request sys m3 on behalf of an IPU client */
+static inline int ipu_pm_get_sys_m3(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Request app m3 on behalf of an IPU client */
+static inline int ipu_pm_get_app_m3(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Request L3 Bus on behalf of an IPU client */
+static inline int ipu_pm_get_l3_bus(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Request IVA HD on behalf of an IPU client */
+static inline int ipu_pm_get_iva_hd(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Request FDIF on behalf of an IPU client */
+static inline int ipu_pm_get_fdif(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Request MPU on behalf of an IPU client */
+static inline int ipu_pm_get_mpu(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Request IPU on behalf of an IPU client */
+static inline int ipu_pm_get_ipu(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Request IVA SEQ0 on behalf of an IPU client */
+static inline int ipu_pm_get_ivaseq0(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Request IVA SEQ1 on behalf of an IPU client */
+static inline int ipu_pm_get_ivaseq1(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Request ISS on behalf of an IPU client */
+static inline int ipu_pm_get_iss(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release a sdma on behalf of an IPU client */
+static inline int ipu_pm_rel_sdma_chan(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release a gptimer on behalf of an IPU client */
+static inline int ipu_pm_rel_gptimer(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release an i2c buses on behalf of an IPU client */
+static inline int ipu_pm_rel_i2c_bus(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release a gpio on behalf of an IPU client */
+static inline int ipu_pm_rel_gpio(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release a regulator on behalf of an IPU client */
+static inline int ipu_pm_rel_regulator(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release an Aux clk on behalf of an IPU client */
+static inline int ipu_pm_rel_aux_clk(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release sys m3 on behalf of an IPU client */
+static inline int ipu_pm_rel_sys_m3(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release app m3 on behalf of an IPU client */
+static inline int ipu_pm_rel_app_m3(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release L3 Bus on behalf of an IPU client */
+static inline int ipu_pm_rel_l3_bus(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release IVA HD on behalf of an IPU client */
+static inline int ipu_pm_rel_iva_hd(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release FDIF on behalf of an IPU client */
+static inline int ipu_pm_rel_fdif(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release MPU on behalf of an IPU client */
+static inline int ipu_pm_rel_mpu(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release IPU on behalf of an IPU client */
+static inline int ipu_pm_rel_ipu(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release IVA SEQ0 on behalf of an IPU client */
+static inline int ipu_pm_rel_ivaseq0(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release IVA SEQ1 on behalf of an IPU client */
+static inline int ipu_pm_rel_ivaseq1(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release ISS on behalf of an IPU client */
+static inline int ipu_pm_rel_iss(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Request a res constraint on behalf of an IPU client */
+static inline int ipu_pm_req_cstr(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Release a res constraint on behalf of an IPU client */
+static inline int ipu_pm_rel_cstr(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params);
+
+/* Hibernate and watch dog timer interrupt */
+static irqreturn_t ipu_pm_timer_interrupt(int irq,
+ void *dev_id);
+
+/* Hibernate and watch dog timer function */
+static int ipu_pm_timer_state(int event);
+
+#ifdef CONFIG_DUCATI_WATCH_DOG
+/* Functions for reporing watch dog reset */
+static int ipu_pm_notify_event(int event, void *data);
+#endif
+
+/** ============================================================================
+ * Globals
+ * ============================================================================
+ */
+
+/* Usage Masks */
+static u32 GPTIMER_USE_MASK = 0xFFFF;
+static u32 I2C_USE_MASK = 0xFFFF;
+static u32 AUX_CLK_USE_MASK = 0xFFFF;
+
+/* Previous voltage value of secondary camera regulator */
+static u32 cam2_prev_volt;
+
+/* Resources and notifications*/
+static struct ipu_pm_object *pm_handle_appm3;
+static struct ipu_pm_object *pm_handle_sysm3;
+struct sms *global_rcb;
+static struct workqueue_struct *ipu_resources;
+
+/* Clean up and recover */
+static struct workqueue_struct *ipu_clean_up;
+struct work_struct clean;
+static DECLARE_COMPLETION(ipu_clean_up_comp);
+static bool recover;
+
+/* Latency cstrs */
+#ifdef CONFIG_OMAP_PM
+static struct pm_qos_request_list *pm_qos_handle;
+static struct pm_qos_request_list *pm_qos_handle_2;
+#endif
+
+/* Save/restore for hibernation */
+static struct omap_rproc *sys_rproc;
+static struct omap_rproc *app_rproc;
+static struct omap_mbox *ducati_mbox;
+static struct iommu *ducati_iommu;
+static bool first_time = 1;
+
+/* BIOS flags states for each core in IPU */
+static void __iomem *sysm3Idle;
+static void __iomem *appm3Idle;
+#ifdef SR_WA
+static void __iomem *issHandle;
+static void __iomem *fdifHandle;
+#endif
+
+/* Ducati Interrupt Capable Gptimers */
+static int ipu_timer_list[NUM_IPU_TIMERS] = {
+ GP_TIMER_9,
+ GP_TIMER_11};
+
+/* I2C spinlock assignment mapping table */
+static int i2c_spinlock_list[I2C_BUS_MAX + 1] = {
+ I2C_SL_INVAL,
+ I2C_1_SL,
+ I2C_2_SL,
+ I2C_3_SL,
+ I2C_4_SL};
+
+/* Camera regulator */
+static char *ipu_regulator_name[REGULATOR_MAX] = {
+ "cam2pwr"};
+
+static struct clk *aux_clk_ptr[NUM_AUX_CLK];
+
+static char *aux_clk_name[NUM_AUX_CLK] = {
+ "auxclk0_ck",
+ "auxclk1_ck",
+ "auxclk2_ck",
+ "auxclk3_ck",
+ "auxclk4_ck",
+ "auxclk5_ck",
+} ;
+
+static char *aux_clk_source_name[] = {
+ "sys_clkin_ck",
+ "dpll_core_m3x2_ck",
+ "dpll_per_m3x2_ck",
+ NULL
+} ;
+
+/* static struct clk *aux_clk_source_clocks[3]; */
+
+static struct ipu_pm_module_object ipu_pm_state = {
+ .def_cfg.reserved = 1,
+ .gate_handle = NULL
+} ;
+
+/* Default params for ipu_pm handle */
+static struct ipu_pm_params pm_params = {
+ .pm_fdif_counter = 0,
+ .pm_ipu_counter = 0,
+ .pm_sys_m3_counter = 0,
+ .pm_app_m3_counter = 0,
+ .pm_iss_counter = 0,
+ .pm_iva_hd_counter = 0,
+ .pm_ivaseq0_counter = 0,
+ .pm_ivaseq1_counter = 0,
+ .pm_sl2if_counter = 0,
+ .pm_l3_bus_counter = 0,
+ .pm_mpu_counter = 0,
+ .pm_sdmachan_counter = 0,
+ .pm_gptimer_counter = 0,
+ .pm_gpio_counter = 0,
+ .pm_i2c_bus_counter = 0,
+ .pm_regulator_counter = 0,
+ .pm_aux_clk_counter = 0,
+ .timeout = 10000,
+ .shared_addr = NULL,
+ .pm_num_events = NUMBER_PM_EVENTS,
+ .pm_resource_event = PM_RESOURCE,
+ .pm_notification_event = PM_NOTIFICATION,
+ .proc_id = A9,
+ .remote_proc_id = -1,
+ .line_id = 0,
+ .hib_timer_state = PM_HIB_TIMER_RESET,
+ .wdt_time = 0
+} ;
+
+/* Functions to request resources */
+static int (*request_fxn[PM_NUM_RES]) (struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params) = {
+ ipu_pm_get_fdif,
+ ipu_pm_get_ipu,
+ ipu_pm_get_sys_m3,
+ ipu_pm_get_app_m3,
+ ipu_pm_get_iss,
+ ipu_pm_get_iva_hd,
+ ipu_pm_get_ivaseq0,
+ ipu_pm_get_ivaseq1,
+ ipu_pm_get_l3_bus,
+ ipu_pm_get_mpu,
+ /* ipu_pm_get_sl2if, */
+ /* ipu_pm_get_dsp, */
+ ipu_pm_get_sdma_chan,
+ ipu_pm_get_gptimer,
+ ipu_pm_get_gpio,
+ ipu_pm_get_i2c_bus,
+ ipu_pm_get_regulator,
+ ipu_pm_get_aux_clk,
+};
+
+/* Functions to release resources */
+static int (*release_fxn[PM_NUM_RES]) (struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params) = {
+ ipu_pm_rel_fdif,
+ ipu_pm_rel_ipu,
+ ipu_pm_rel_sys_m3,
+ ipu_pm_rel_app_m3,
+ ipu_pm_rel_iss,
+ ipu_pm_rel_iva_hd,
+ ipu_pm_rel_ivaseq0,
+ ipu_pm_rel_ivaseq1,
+ ipu_pm_rel_l3_bus,
+ ipu_pm_rel_mpu,
+ /* ipu_pm_rel_sl2if, */
+ /* ipu_pm_rel_dsp, */
+ ipu_pm_rel_sdma_chan,
+ ipu_pm_rel_gptimer,
+ ipu_pm_rel_gpio,
+ ipu_pm_rel_i2c_bus,
+ ipu_pm_rel_regulator,
+ ipu_pm_rel_aux_clk,
+
+};
+
+static struct blocking_notifier_head ipu_pm_notifier;
+
+/*
+ Function to schedule the recover process
+ *
+ */
+static void ipu_pm_recover_schedule(void)
+{
+ struct ipu_pm_object *handle;
+
+ INIT_COMPLETION(ipu_clean_up_comp);
+ recover = true;
+
+ /* get the handle to proper ipu pm object
+ * and flush any pending fifo message
+ */
+ handle = ipu_pm_get_handle(APP_M3);
+ if (handle)
+ kfifo_reset(&handle->fifo);
+ handle = ipu_pm_get_handle(SYS_M3);
+ if (handle)
+ kfifo_reset(&handle->fifo);
+
+ /* schedule clean up work */
+ queue_work(ipu_clean_up, &clean);
+}
+
+/*
+ Function to clean/release all the resources
+ *
+ */
+static void ipu_pm_clean_res(void)
+{
+ /* Check RAT and call each release function
+ * per resource in rcb
+ */
+ unsigned used_res_mask = global_rcb->rat;
+ struct ipu_pm_object *handle;
+ struct ipu_pm_params *params;
+ struct rcb_block *rcb_p;
+ int cur_rcb = 0;
+ u32 mask;
+ int res;
+ int retval = 0;
+
+ /* The reserved RCB's are marked as valid
+ * by the remote proc but are not requesting any
+ * resource so no need to release.
+ * rcb = 0 is invalid.
+ * rcb = 1 is reserved.
+ * Start in 2
+ */
+ used_res_mask &= RESERVED_RCBS;
+ pr_debug("Resources Mask 0x%x\n", used_res_mask);
+
+ if (!used_res_mask)
+ goto complete_exit;
+
+ while (cur_rcb < RCB_MAX && used_res_mask != 0) {
+ cur_rcb++;
+ mask = 1;
+ mask = mask << cur_rcb;
+
+ if (!(mask & used_res_mask))
+ continue;
+
+ rcb_p = (struct rcb_block *)&global_rcb->rcb[cur_rcb];
+ handle = ipu_pm_get_handle(rcb_p->rqst_cpu);
+ if (!handle) {
+ pr_err("Invalid RCB, maybe corrupted!\n");
+ used_res_mask &= ~mask;
+ continue;
+ }
+ params = handle->params;
+ res = rcb_p->sub_type;
+
+ if (_has_cstrs(res)) {
+ pr_debug("Releasing res:%d cstrs\n", res);
+ retval = ipu_pm_rel_cstr(handle, rcb_p, params);
+ if (retval)
+ pr_err("Error releasing res:%d cstrs\n", res);
+ }
+
+ /* The first resource is internally created to manage the
+ * the constrainst of the IPU via SYS and APP and it shouldn't
+ * be released as a resource
+ */
+ if (cur_rcb > 1) {
+ if (_is_res(res)) {
+ pr_debug("Releasing res:%d\n", res);
+ retval = release_fxn[res](handle, rcb_p,
+ params);
+ if (retval)
+ pr_err("Can't release resource: %d\n",
+ res);
+ }
+ }
+
+ /* Clear the RCB from the RAT if success */
+ if (!retval)
+ used_res_mask &= ~mask;
+ pr_debug("Mask 0x%x\n", used_res_mask);
+ }
+
+ global_rcb->rat = used_res_mask;
+ if (!used_res_mask)
+ goto complete_exit;
+
+ pr_warning("%s:Not all resources were released", __func__);
+ return;
+complete_exit:
+ complete_all(&ipu_clean_up_comp);
+ return;
+}
+
+/*
+ Work Function to clean up resources
+ *
+ */
+static void ipu_pm_clean_work(struct work_struct *work)
+{
+ ipu_pm_clean_res();
+}
+
+/*
+ Notifier Function to handle IOMMU events
+ *
+ */
+static int ipu_pm_iommu_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ switch ((int)val) {
+ case IOMMU_CLOSE:
+ /*
+ * restore IOMMU since it is required the IOMMU
+ * is up and running for reclaiming MMU entries
+ */
+ if (ipu_pm_get_state(SYS_M3) & SYS_PROC_DOWN)
+ iommu_restore_ctx(ducati_iommu);
+ return 0;
+ case IOMMU_FAULT:
+ ipu_pm_recover_schedule();
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static struct notifier_block ipu_pm_notify_nb_iommu_ducati = {
+ .notifier_call = ipu_pm_iommu_notifier_call,
+};
+
+/*
+ Work Function to req/rel a resource
+ *
+ */
+static void ipu_pm_work(struct work_struct *work)
+{
+ struct ipu_pm_object *handle =
+ container_of(work, struct ipu_pm_object, work);
+ struct rcb_block *rcb_p;
+ struct ipu_pm_msg im;
+ struct ipu_pm_params *params;
+ union message_slicer pm_msg;
+ int action;
+ int res;
+ int rcb_num;
+ int retval;
+
+ if (WARN_ON(handle == NULL))
+ return;
+
+ params = handle->params;
+ if (WARN_ON(params == NULL))
+ return;
+
+ while (kfifo_len(&handle->fifo) >= sizeof(im)) {
+ /* set retval for each iteration asumming error */
+ retval = PM_UNSUPPORTED;
+ spin_lock_irq(&handle->lock);
+ retval = kfifo_out(&handle->fifo, &im, sizeof(im));
+ spin_unlock_irq(&handle->lock);
+
+ if (retval == 0)
+ break;
+
+ /* Get the payload */
+ pm_msg.whole = im.pm_msg;
+ /* Get the rcb_num */
+ rcb_num = pm_msg.fields.rcb_num;
+ /* Get pointer to the proper RCB */
+ if (WARN_ON((rcb_num < RCB_MIN) || (rcb_num > RCB_MAX)))
+ return;
+ rcb_p = (struct rcb_block *)&handle->rcb_table->rcb[rcb_num];
+
+ /* Get the type of resource and the actions required */
+ action = rcb_p->msg_type;
+ res = rcb_p->sub_type;
+ if (!_is_res(res)) {
+ pr_err("Invalid res number: %d\n", res);
+ /* No need to continue, send error back */
+ goto send_msg;
+ }
+ switch (action) {
+ case PM_REQUEST_RESOURCE:
+ if (request_fxn[res])
+ retval = request_fxn[res](handle, rcb_p,
+ params);
+ break;
+ case PM_RELEASE_RESOURCE:
+ if (release_fxn[res])
+ retval = release_fxn[res](handle, rcb_p,
+ params);
+ break;
+ case PM_REQUEST_CONSTRAINTS:
+ if (_has_cstrs(res))
+ retval = ipu_pm_req_cstr(handle, rcb_p,
+ params);
+ break;
+ case PM_RELEASE_CONSTRAINTS:
+ if (_has_cstrs(res))
+ retval = ipu_pm_rel_cstr(handle, rcb_p,
+ params);
+ break;
+ default:
+ pm_msg.fields.msg_type = PM_FAIL;
+ break;
+ }
+send_msg:
+ if (retval != PM_SUCCESS)
+ pm_msg.fields.msg_type = PM_FAIL;
+ /* Update the payload with the reply msg */
+ pm_msg.fields.reply_flag = true;
+ pm_msg.fields.parm = retval;
+
+ /* Restore the payload and send to caller*/
+ im.pm_msg = pm_msg.whole;
+
+ /* Send the ACK to Remote Proc*/
+ retval = notify_send_event(
+ params->remote_proc_id,
+ params->line_id,
+ params->pm_resource_event | \
+ (NOTIFY_SYSTEMKEY << 16),
+ im.pm_msg,
+ true);
+ if (retval < 0)
+ pr_err("Error sending notify event\n");
+ }
+}
+
+void ipu_pm_callback(u16 proc_id, u16 line_id, u32 event_id,
+ uint *arg, u32 payload)
+{
+ struct ipu_pm_object *handle;
+ struct ipu_pm_msg im;
+
+ /*get the handle to proper ipu pm object */
+ handle = ipu_pm_get_handle(proc_id);
+
+ if (WARN_ON(unlikely(handle == NULL)))
+ return;
+
+ im.proc_id = proc_id;
+ im.pm_msg = payload;
+
+ spin_lock_irq(&handle->lock);
+ if (kfifo_avail(&handle->fifo) >= sizeof(im)) {
+ kfifo_in(&handle->fifo, (unsigned char *)&im, sizeof(im));
+ queue_work(ipu_resources, &handle->work);
+ }
+ spin_unlock_irq(&handle->lock);
+}
+EXPORT_SYMBOL(ipu_pm_callback);
+
+
+/* Function for PM notifications Callback
+ * This functions receives an event coming from
+ * remote proc as an ack.
+ * Post semaphore based in eventType (payload)
+ * If PM_HIBERNATE is received the save_ctx is triggered
+ * in order to put remote proc in reset.
+ */
+void ipu_pm_notify_callback(u16 proc_id, u16 line_id, u32 event_id,
+ uint *arg, u32 payload)
+{
+ struct ipu_pm_object *handle;
+ union message_slicer pm_msg;
+ struct ipu_pm_params *params;
+ enum pm_event_type event;
+ int retval;
+
+ /* get the handle to proper ipu pm object */
+ handle = ipu_pm_get_handle(proc_id);
+ if (WARN_ON(unlikely(handle == NULL)))
+ return;
+ params = handle->params;
+ if (WARN_ON(unlikely(params == NULL)))
+ return;
+
+ pm_msg.whole = payload;
+ /* get the event type sent by remote proc */
+ event = pm_msg.fields.msg_subtype;
+ if (!_is_event(event))
+ goto error;
+ if (event == PM_HIBERNATE) {
+ /* If any resource in use, no hibernation */
+ if (!(handle->rcb_table->state_flag & HIB_REF_MASK)) {
+ /* Remote Proc is ready to hibernate
+ * PM_HIBERNATE is a one way notification
+ * Remote proc to Host proc
+ */
+ pr_debug("Remote Proc is ready to hibernate\n");
+
+ retval = ipu_pm_save_ctx(proc_id);
+ if (retval)
+ pr_err("Unable to stop proc %d\n", proc_id);
+ } else
+ pr_err("Hibernation is not allowed if resource in use");
+ } else if (event == PM_ALIVE) {
+ /* If resources are in use ipu will send an event to make
+ * sure it is in a good state but hibernation won't happen
+ * and the timer will be reloaded to hib_time again.
+ */
+ pr_debug("Unable to stop proc, Resources in use\n");
+ ipu_pm_timer_state(PM_HIB_TIMER_ON);
+ } else {
+ pr_debug("Remote Proc received %d event\n", event);
+ handle->pm_event[event].pm_msg = payload;
+ up(&handle->pm_event[event].sem_handle);
+ }
+
+ return;
+error:
+ pr_err("Unknow event received from remote proc: %d\n", event);
+}
+EXPORT_SYMBOL(ipu_pm_notify_callback);
+
+/* Function for send PM Notifications
+ * Function used by devh and dev_pm
+ * Recieves evenType: Suspend, Resume, Proc_Obit
+ * Send event to Ducati
+ * Pend semaphore based in event_type (payload)
+ * Return ACK to caller
+ */
+int ipu_pm_notifications(int proc_id, enum pm_event_type event, void *data)
+{
+ struct ipu_pm_object *handle;
+ struct ipu_pm_params *params;
+ union message_slicer pm_msg;
+ int retval;
+ int pm_ack = 0;
+
+ handle = ipu_pm_get_handle(proc_id);
+ if (handle == NULL)
+ goto error;
+ params = handle->params;
+ if (params == NULL)
+ goto error;
+
+ /* Prepare the message for remote proc */
+ pm_msg.fields.msg_type = PM_NOTIFICATIONS;
+ pm_msg.fields.msg_subtype = event;
+ pm_msg.fields.parm = PM_SUCCESS;
+
+ /* put general purpose message in share memory
+ * this message is just for devh but it can be use
+ * for sending any message to the remote proc
+ * along with the notification
+ */
+ handle->rcb_table->gp_msg = (unsigned)data;
+
+ /* send the request to IPU*/
+ retval = notify_send_event(params->remote_proc_id,
+ params->line_id,
+ params->pm_notification_event | \
+ (NOTIFY_SYSTEMKEY << 16),
+ (unsigned int)pm_msg.whole,
+ true);
+ if (retval < 0)
+ goto error_send;
+
+ /* wait for remote proc ack (ipu_pm_notify_callback)*/
+ retval = down_timeout(&handle->pm_event[event].sem_handle,
+ msecs_to_jiffies(params->timeout));
+
+ pm_msg.whole = handle->pm_event[event].pm_msg;
+ if (WARN_ON((retval < 0) || (pm_msg.fields.parm != PM_SUCCESS)))
+ goto error;
+ return pm_ack;
+
+error_send:
+ pr_err("Error notify_send event %d to proc %d\n", event, proc_id);
+error:
+ pr_err("Error sending Notification event %d\n", event);
+ return -EBUSY;
+}
+EXPORT_SYMBOL(ipu_pm_notifications);
+
+/*
+ Request a sdma channels on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_get_sdma_chan(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ int pm_sdmachan_num;
+ int pm_sdmachan_dummy;
+ int ch;
+ int ch_aux;
+ int retval;
+
+ /* Get number of channels from RCB */
+ pm_sdmachan_num = rcb_p->num_chan;
+ if (WARN_ON((pm_sdmachan_num <= 0) ||
+ (pm_sdmachan_num > SDMA_CHANNELS_MAX))) {
+ pr_err("%s %d Not able to provide %d channels\n", __func__
+ , __LINE__
+ , pm_sdmachan_num);
+ return PM_INVAL_NUM_CHANNELS;
+ }
+
+ /* Request resource using PRCM API */
+ for (ch = 0; ch < pm_sdmachan_num; ch++) {
+ retval = omap_request_dma(params->proc_id,
+ "ducati-ss",
+ NULL,
+ NULL,
+ &pm_sdmachan_dummy);
+ if (retval == 0) {
+ params->pm_sdmachan_counter++;
+ rcb_p->channels[ch] = (unsigned char)pm_sdmachan_dummy;
+ pr_debug("Providing sdma ch %d\n", pm_sdmachan_dummy);
+ } else {
+ pr_err("%s %d Error providing sdma channel\n", __func__
+ , __LINE__);
+ goto clean_sdma;
+ }
+ }
+ return PM_SUCCESS;
+clean_sdma:
+ /*failure, need to free the channels*/
+ pr_debug("Freeing sdma channel because of failure\n");
+ for (ch_aux = 0; ch_aux < ch; ch_aux++) {
+ pm_sdmachan_dummy = (int)rcb_p->channels[ch_aux];
+ omap_free_dma(pm_sdmachan_dummy);
+ params->pm_sdmachan_counter--;
+ }
+ return PM_INSUFFICIENT_CHANNELS;
+}
+
+/*
+ Request a gptimer on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_get_gptimer(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ struct omap_dm_timer *p_gpt = NULL;
+ int pm_gp_num;
+
+ /* Request resource using PRCM API */
+ for (pm_gp_num = 0; pm_gp_num < NUM_IPU_TIMERS; pm_gp_num++) {
+ if (GPTIMER_USE_MASK & (1 << ipu_timer_list[pm_gp_num])) {
+ p_gpt = omap_dm_timer_request_specific
+ (ipu_timer_list[pm_gp_num]);
+ } else
+ continue;
+ if (p_gpt != NULL) {
+ /* Check the range of the src clk */
+ if (rcb_p->data[0] < OMAP_TIMER_SRC_SYS_CLK ||
+ rcb_p->data[0] > OMAP_TIMER_SRC_32_KHZ) {
+ /* Default src clk is SYS_CLK */
+ pr_debug("Setting Default Clock Source\n");
+ rcb_p->data[0] = OMAP_TIMER_SRC_SYS_CLK;
+ }
+ /* Set the src clk of gpt */
+ omap_dm_timer_set_source(p_gpt, rcb_p->data[0]);
+ /* Clear the bit in the usage mask */
+ GPTIMER_USE_MASK &= ~(1 << ipu_timer_list[pm_gp_num]);
+ break;
+ }
+ }
+ if (p_gpt == NULL) {
+ pr_err("%s %d Error providing gp_timer\n", __func__, __LINE__);
+ return PM_NO_GPTIMER;
+ } else {
+ /* Store the gptimer number and base address */
+ rcb_p->fill9 = ipu_timer_list[pm_gp_num];
+ pr_debug("Providing gp_timer %d\n", rcb_p->fill9);
+ rcb_p->mod_base_addr = (unsigned)p_gpt;
+ params->pm_gptimer_counter++;
+ return PM_SUCCESS;
+ }
+}
+
+/*
+ Request an i2c bus on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_get_i2c_bus(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ struct clk *p_i2c_clk;
+ int i2c_clk_status;
+ char i2c_name[I2C_NAME_SIZE];
+ int pm_i2c_bus_num;
+
+ pm_i2c_bus_num = rcb_p->fill9;
+ if (WARN_ON((pm_i2c_bus_num < I2C_BUS_MIN) ||
+ (pm_i2c_bus_num > I2C_BUS_MAX)))
+ goto error;
+
+ if (I2C_USE_MASK & (1 << pm_i2c_bus_num)) {
+ /* building the name for i2c_clk */
+ sprintf(i2c_name, "i2c%d_fck", pm_i2c_bus_num);
+
+ /* Request resource using PRCM API */
+ p_i2c_clk = omap_clk_get_by_name(i2c_name);
+ if (p_i2c_clk == NULL) {
+ pr_err("%s %d Error providing i2c_%d\n"
+ , __func__, __LINE__
+ , pm_i2c_bus_num);
+ goto error;
+ }
+ i2c_clk_status = clk_enable(p_i2c_clk);
+ if (i2c_clk_status != 0) {
+ pr_err("%s %d Error enabling i2c_%d clock\n"
+ , __func__, __LINE__
+ , pm_i2c_bus_num);
+ goto error;
+ }
+ /* Clear the bit in the usage mask */
+ I2C_USE_MASK &= ~(1 << pm_i2c_bus_num);
+ rcb_p->mod_base_addr = (unsigned)p_i2c_clk;
+ /* Get the HW spinlock and store it in the RCB */
+ rcb_p->data[0] = i2c_spinlock_list[pm_i2c_bus_num];
+ params->pm_i2c_bus_counter++;
+ pr_debug("Providing %s\n", i2c_name);
+
+ return PM_SUCCESS;
+ }
+error:
+ return PM_NO_I2C;
+}
+
+/*
+ Request a gpio on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_get_gpio(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ int pm_gpio_num;
+ int retval;
+
+ pm_gpio_num = rcb_p->fill9;
+ retval = gpio_request(pm_gpio_num , "ducati-ss");
+ if (retval != 0) {
+ pr_err("%s %d Error providing gpio %d\n", __func__, __LINE__
+ , pm_gpio_num);
+ return PM_NO_GPIO;
+ }
+ pr_debug("Providing gpio %d\n", pm_gpio_num);
+ params->pm_gpio_counter++;
+
+ return PM_SUCCESS;
+}
+
+/*
+ Request a regulator on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_get_regulator(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ struct regulator *p_regulator = NULL;
+ char *regulator_name;
+ int pm_regulator_num;
+ int retval = 0;
+
+ pm_regulator_num = rcb_p->fill9;
+ if (WARN_ON((pm_regulator_num < REGULATOR_MIN) ||
+ (pm_regulator_num > REGULATOR_MAX))) {
+ pr_err("%s %d Invalid regulator %d\n", __func__, __LINE__
+ , pm_regulator_num);
+ goto error;
+ }
+
+ /*
+ FIXME:Only providing 1 regulator, if more are provided
+ * this check is not valid.
+ */
+ if (WARN_ON(params->pm_regulator_counter > 0)) {
+ pr_err("%s %d No more regulators\n", __func__, __LINE__);
+ goto error;
+ }
+
+ /* Search the name of regulator based on the id and request it */
+ regulator_name = ipu_regulator_name[pm_regulator_num - 1];
+ p_regulator = regulator_get(NULL, regulator_name);
+ if (p_regulator == NULL) {
+ pr_err("%s %d Error providing regulator %s\n", __func__
+ , __LINE__
+ , regulator_name);
+ goto error;
+ }
+
+ /* Get and store the regulator default voltage */
+ cam2_prev_volt = regulator_get_voltage(p_regulator);
+
+ /* Set the regulator voltage min = data[0]; max = data[1]*/
+ retval = regulator_set_voltage(p_regulator, rcb_p->data[0],
+ rcb_p->data[1]);
+ if (retval) {
+ pr_err("%s %d Error setting %s voltage\n", __func__
+ , __LINE__
+ , regulator_name);
+ goto error;
+ }
+
+ /* Store the regulator handle in the RCB */
+ rcb_p->mod_base_addr = (unsigned)p_regulator;
+ params->pm_regulator_counter++;
+ pr_debug("Providing regulator %s\n", regulator_name);
+
+ return PM_SUCCESS;
+error:
+ return PM_INVAL_REGULATOR;
+}
+
+/*
+ Request an Aux clk on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_get_aux_clk(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ u32 a_clk = 0;
+ int ret;
+ int pm_aux_clk_num;
+
+ pm_aux_clk_num = rcb_p->fill9;
+
+ if (WARN_ON((pm_aux_clk_num < AUX_CLK_MIN) ||
+ (pm_aux_clk_num > AUX_CLK_MAX))) {
+ pr_err("%s %d Invalid aux_clk %d\n", __func__, __LINE__
+ , pm_aux_clk_num);
+ return PM_INVAL_AUX_CLK;
+ }
+
+ if (AUX_CLK_USE_MASK & (1 << pm_aux_clk_num)) {
+ struct clk *aux_clk;
+ struct clk *aux_clk_src_ptr;
+
+ aux_clk = clk_get(NULL, aux_clk_name[pm_aux_clk_num]);
+ if (!aux_clk) {
+ pr_err("%s %d Unable to get %s\n", __func__, __LINE__
+ , aux_clk_name[pm_aux_clk_num]);
+ return PM_NO_AUX_CLK;
+ }
+ if (unlikely(aux_clk->usecount != 0)) {
+ pr_err("%s %d aux_clk%d->usecount = %d, expected to "
+ "be zero as there should be no other users\n",
+ __func__, __LINE__, pm_aux_clk_num,
+ aux_clk->usecount);
+ }
+
+ aux_clk_src_ptr = clk_get(NULL,
+ aux_clk_source_name[PER_DPLL_CLK]);
+ if (!aux_clk_src_ptr) {
+ pr_err("%s %d Unable to get aux_clk source %s\n"
+ , __func__, __LINE__
+ , aux_clk_source_name[PER_DPLL_CLK]);
+ return PM_NO_AUX_CLK;
+ }
+ ret = clk_set_parent(aux_clk, aux_clk_src_ptr);
+ if (ret) {
+ pr_err("%s %d Unable to set clk %s"
+ " as parent of aux_clk %s\n"
+ , __func__, __LINE__
+ , aux_clk_source_name[PER_DPLL_CLK]
+ , aux_clk_name[pm_aux_clk_num]);
+ return PM_NO_AUX_CLK;
+ }
+
+ /* update divisor manually until API available */
+ a_clk = __raw_readl(AUX_CLK_REG(pm_aux_clk_num));
+ MASK_CLEAR_FIELD(a_clk, AUX_CLK_CLKDIV);
+ MASK_SET_FIELD(a_clk, AUX_CLK_CLKDIV, 0xA);
+
+ /* Enable and configure aux clock */
+ __raw_writel(a_clk, AUX_CLK_REG(pm_aux_clk_num));
+
+ ret = clk_enable(aux_clk);
+ if (ret) {
+ pr_err("%s %d Unable to enable aux_clk %s\n"
+ , __func__, __LINE__
+ , aux_clk_name[pm_aux_clk_num]);
+ return PM_NO_AUX_CLK;
+ }
+
+ aux_clk_ptr[pm_aux_clk_num] = aux_clk;
+
+ /* Clear the bit in the usage mask */
+ AUX_CLK_USE_MASK &= ~(1 << pm_aux_clk_num);
+
+ pr_debug("Providing aux_clk_%d [0x%x] [0x%x]\n", pm_aux_clk_num,
+ __raw_readl(AUX_CLK_REG(pm_aux_clk_num)),
+ __raw_readl(AUX_CLK_REG_REQ(pm_aux_clk_num)));
+
+ /* Store the aux clk addres in the RCB */
+ rcb_p->mod_base_addr =
+ (unsigned __force)AUX_CLK_REG(pm_aux_clk_num);
+ params->pm_aux_clk_counter++;
+ } else {
+ pr_err("%s %d Error providing aux_clk %d\n", __func__, __LINE__
+ , pm_aux_clk_num);
+ return PM_NO_AUX_CLK;
+ }
+
+ return PM_SUCCESS;
+}
+
+/*
+ Request sys m3 on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_get_sys_m3(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ if (params->pm_sys_m3_counter) {
+ pr_err("%s %d SYS_M3 already requested\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+
+ params->pm_sys_m3_counter++;
+ pr_debug("Request SYS M3\n");
+
+ return PM_SUCCESS;
+}
+
+/*
+ Request app m3 on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_get_app_m3(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ if (params->pm_app_m3_counter) {
+ pr_err("%s %d APP_M3 already requested\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+
+ params->pm_app_m3_counter++;
+ pr_debug("Request APP M3\n");
+
+ return PM_SUCCESS;
+}
+
+/*
+ Request L3 Bus on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_get_l3_bus(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ if (params->pm_l3_bus_counter) {
+ pr_err("%s %d L3_BUS already requested\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+
+ params->pm_l3_bus_counter++;
+ pr_debug("Request L3 BUS\n");
+
+ return PM_SUCCESS;
+}
+
+/*
+ Request IVA HD on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_get_iva_hd(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ int retval;
+
+ if (params->pm_iva_hd_counter) {
+ pr_err("%s %d IVA_HD already requested\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+
+ retval = ipu_pm_module_start(rcb_p->sub_type);
+ if (retval) {
+ pr_err("%s %d Error requesting IVA_HD\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+ params->pm_iva_hd_counter++;
+ pr_debug("Request IVA_HD\n");
+
+#ifdef CONFIG_OMAP_PM
+ pr_debug("Request MPU wakeup latency\n");
+ retval = omap_pm_set_max_mpu_wakeup_lat(&pm_qos_handle,
+ IPU_PM_MM_MPU_LAT_CONSTRAINT);
+ if (retval) {
+ pr_err("%s %d Error setting MPU cstr\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+#endif
+
+ return PM_SUCCESS;
+}
+
+/*
+ Request FDIF on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_get_fdif(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ int retval;
+
+ if (params->pm_fdif_counter) {
+ pr_err("%s %d FDIF already requested\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+
+ retval = ipu_pm_module_start(rcb_p->sub_type);
+ if (retval) {
+ pr_err("%s %d Error requesting FDIF\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+ params->pm_fdif_counter++;
+ pr_debug("Request FDIF\n");
+
+ return PM_SUCCESS;
+}
+
+/*
+ Request MPU on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_get_mpu(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ if (params->pm_mpu_counter) {
+ pr_err("%s %d MPU already requested\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+
+ params->pm_mpu_counter++;
+ pr_debug("Request MPU\n");
+
+ return PM_SUCCESS;
+}
+
+/*
+ Request IPU on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_get_ipu(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ if (params->pm_ipu_counter) {
+ pr_err("%s %d IPU already requested\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+
+ params->pm_ipu_counter++;
+ pr_debug("Request IPU\n");
+
+ return PM_SUCCESS;
+}
+
+/*
+ Request IVA SEQ0 on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_get_ivaseq0(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ int retval;
+
+ if (params->pm_ivaseq0_counter) {
+ pr_err("%s %d IVASEQ0 already requested\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+
+ retval = ipu_pm_module_start(rcb_p->sub_type);
+ if (retval) {
+ pr_err("%s %d Error requesting IVASEQ0\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+ params->pm_ivaseq0_counter++;
+ pr_debug("Request IVASEQ0\n");
+
+ return PM_SUCCESS;
+}
+
+/*
+ Request IVA SEQ1 on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_get_ivaseq1(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ int retval;
+
+ if (params->pm_ivaseq1_counter) {
+ pr_err("%s %d IVASEQ1 already requested\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+
+ retval = ipu_pm_module_start(rcb_p->sub_type);
+ if (retval) {
+ pr_err("%s %d Error requesting IVASEQ1\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+ params->pm_ivaseq1_counter++;
+ pr_debug("Request IVASEQ1\n");
+
+ /*Requesting SL2*/
+ /* FIXME: sl2if should be moved to a independent function */
+ retval = ipu_pm_module_start(SL2_RESOURCE);
+ if (retval) {
+ pr_err("%s %d Error requesting sl2if\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+ params->pm_sl2if_counter++;
+ pr_debug("Request sl2if\n");
+
+ return PM_SUCCESS;
+}
+
+/*
+ Request ISS on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_get_iss(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ int retval;
+
+ if (params->pm_iss_counter) {
+ pr_err("%s %d ISS already requested\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+
+#if TMP_AUX_CLK_HACK
+ rcb_p->fill9 = AUX_CLK_MIN;
+ ipu_pm_get_aux_clk(handle, rcb_p, params);
+#endif
+
+ retval = ipu_pm_module_start(rcb_p->sub_type);
+ if (retval) {
+ pr_err("%s %d Error requesting ISS\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+
+ /* FIXME:
+ * enable OPTFCLKEN_CTRLCLK for camera sensors
+ * should be moved to a separate function for
+ * independent control this also duplicates the
+ * above call to avoid read modify write locking.
+ */
+ /*cm_write_mod_reg((OPTFCLKEN | CAM_ENABLED),
+ OMAP4430_CM2_CAM_MOD,
+ OMAP4_CM_CAM_ISS_CLKCTRL_OFFSET);*/
+
+#ifdef CONFIG_OMAP_PM
+ pr_debug("Request MPU wakeup latency\n");
+ retval = omap_pm_set_max_mpu_wakeup_lat(&pm_qos_handle,
+ IPU_PM_MM_MPU_LAT_CONSTRAINT);
+ if (retval) {
+ pr_err("%s %d Error setting MPU cstr\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+#endif
+
+ params->pm_iss_counter++;
+ pr_debug("Request ISS\n");
+
+ return PM_SUCCESS;
+}
+
+/*
+ Release a sdma on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_sdma_chan(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ int pm_sdmachan_num;
+ int pm_sdmachan_dummy;
+ int ch;
+
+ /* Release resource using PRCM API */
+ pm_sdmachan_num = rcb_p->num_chan;
+ for (ch = 0; ch < pm_sdmachan_num; ch++) {
+ pm_sdmachan_dummy = (int)rcb_p->channels[ch];
+ omap_free_dma(pm_sdmachan_dummy);
+ params->pm_sdmachan_counter--;
+ pr_debug("Releasing sdma ch %d\n", pm_sdmachan_dummy);
+ }
+ return PM_SUCCESS;
+}
+
+/*
+ Release a gptimer on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_gptimer(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ struct omap_dm_timer *p_gpt;
+ int pm_gptimer_num;
+
+ p_gpt = (struct omap_dm_timer *)rcb_p->mod_base_addr;
+ pm_gptimer_num = rcb_p->fill9;
+
+ /* Check the usage mask */
+ if (GPTIMER_USE_MASK & (1 << pm_gptimer_num)) {
+ pr_err("%s %d Invalid gptimer %d\n", __func__, __LINE__
+ , pm_gptimer_num);
+ return PM_NO_GPTIMER;
+ }
+
+ /* Set the usage mask for reuse */
+ GPTIMER_USE_MASK |= (1 << pm_gptimer_num);
+
+ /* Release resource using PRCM API */
+ if (!p_gpt) {
+ pr_err("%s %d Null gptimer\n", __func__, __LINE__);
+ return PM_NO_GPTIMER;
+ }
+ omap_dm_timer_free(p_gpt);
+ rcb_p->mod_base_addr = 0;
+ params->pm_gptimer_counter--;
+ pr_debug("Releasing gptimer %d\n", pm_gptimer_num);
+ return PM_SUCCESS;
+}
+
+/*
+ Release an i2c buses on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_i2c_bus(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ struct clk *p_i2c_clk;
+ int pm_i2c_bus_num;
+
+ pm_i2c_bus_num = rcb_p->fill9;
+ p_i2c_clk = (struct clk *)rcb_p->mod_base_addr;
+
+ /* Check the usage mask */
+ if (I2C_USE_MASK & (1 << pm_i2c_bus_num)) {
+ pr_err("%s %d Invalid i2c_%d\n", __func__, __LINE__
+ , pm_i2c_bus_num);
+ return PM_NO_I2C;
+ }
+
+ if (!p_i2c_clk) {
+ pr_err("%s %d Null i2c_%d\n", __func__, __LINE__
+ , pm_i2c_bus_num);
+ return PM_NO_I2C;
+ }
+
+ /* Release resource using PRCM API */
+ clk_disable(p_i2c_clk);
+ rcb_p->mod_base_addr = 0;
+
+ /* Set the usage mask for reuse */
+ I2C_USE_MASK |= (1 << pm_i2c_bus_num);
+
+ params->pm_i2c_bus_counter--;
+ pr_debug("Releasing i2c_%d\n", pm_i2c_bus_num);
+
+ return PM_SUCCESS;
+}
+
+/*
+ Release a gpio on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_gpio(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ int pm_gpio_num;
+
+ if (!params->pm_gpio_counter) {
+ pr_err("%s %d No gpio requested\n", __func__, __LINE__);
+ return PM_NO_GPIO;
+ }
+
+ pm_gpio_num = rcb_p->fill9;
+ gpio_free(pm_gpio_num);
+ params->pm_gpio_counter--;
+ pr_debug("Releasing gpio %d\n", pm_gpio_num);
+
+ return PM_SUCCESS;
+}
+
+/*
+ Release a regulator on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_regulator(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ struct regulator *p_regulator = NULL;
+ int retval = 0;
+
+ /* Get the regulator */
+ p_regulator = (struct regulator *)rcb_p->mod_base_addr;
+
+ if (!p_regulator) {
+ pr_err("%s %d Null regulator\n", __func__, __LINE__);
+ return PM_INVAL_REGULATOR;
+ }
+
+ /* Restart the voltage to the default value */
+ retval = regulator_set_voltage(p_regulator, cam2_prev_volt,
+ cam2_prev_volt);
+ if (retval) {
+ pr_err("%s %d Error restoring voltage\n", __func__, __LINE__);
+ return PM_INVAL_REGULATOR;
+ }
+
+ /* Release resource using PRCM API */
+ regulator_put(p_regulator);
+
+ rcb_p->mod_base_addr = 0;
+ params->pm_regulator_counter--;
+ pr_debug("Releasing regulator\n");
+
+ return PM_SUCCESS;
+}
+
+/*
+ Release an Aux clk on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_aux_clk(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ struct clk *aux_clk;
+ int pm_aux_clk_num;
+
+ pm_aux_clk_num = rcb_p->fill9;
+
+ /* Check the usage mask */
+ if (AUX_CLK_USE_MASK & (1 << pm_aux_clk_num)) {
+ pr_err("%s %d Invalid aux_clk_%d\n", __func__, __LINE__
+ , pm_aux_clk_num);
+ return PM_INVAL_AUX_CLK;
+ }
+
+ aux_clk = aux_clk_ptr[pm_aux_clk_num];
+ if (!aux_clk) {
+ pr_err("%s %d Null aux_clk %s\n", __func__, __LINE__
+ , aux_clk_name[pm_aux_clk_num]);
+ return PM_INVAL_AUX_CLK;
+ }
+ clk_disable(aux_clk);
+
+ aux_clk_ptr[pm_aux_clk_num] = 0;
+
+ /* Set the usage mask for reuse */
+ AUX_CLK_USE_MASK |= (1 << pm_aux_clk_num);
+
+ rcb_p->mod_base_addr = 0;
+ params->pm_aux_clk_counter--;
+ pr_debug("Releasing aux_clk_%d\n", pm_aux_clk_num);
+
+ return PM_SUCCESS;
+}
+
+/*
+ Release sys m3 on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_sys_m3(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ if (!params->pm_sys_m3_counter) {
+ pr_err("%s %d SYSM3 not requested\n", __func__, __LINE__);
+ goto error;
+ }
+
+ params->pm_sys_m3_counter--;
+ pr_debug("Release SYS M3\n");
+
+ return PM_SUCCESS;
+error:
+ return PM_UNSUPPORTED;
+}
+
+/*
+ Release app m3 on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_app_m3(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ if (!params->pm_app_m3_counter) {
+ pr_err("%s %d APPM3 not requested\n", __func__, __LINE__);
+ goto error;
+ }
+
+ params->pm_app_m3_counter--;
+ pr_debug("Release APP M3\n");
+
+ return PM_SUCCESS;
+error:
+ return PM_UNSUPPORTED;
+}
+
+/*
+ Release L3 Bus on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_l3_bus(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ if (!params->pm_l3_bus_counter) {
+ pr_err("%s %d L3_BUS not requested\n", __func__, __LINE__);
+ goto error;
+ }
+
+ params->pm_l3_bus_counter--;
+ pr_debug("Release L3 BUS\n");
+
+ return PM_SUCCESS;
+error:
+ return PM_UNSUPPORTED;
+}
+
+/*
+ Release FDIF on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_fdif(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ int retval;
+
+ if (!params->pm_fdif_counter) {
+ pr_err("%s %d FDIF not requested\n", __func__, __LINE__);
+ goto error;
+ }
+
+ retval = ipu_pm_module_stop(rcb_p->sub_type);
+ if (retval)
+ return PM_UNSUPPORTED;
+
+#ifdef SR_WA
+ /* Make sure the clock domain is in idle if not softreset */
+ /*if ((cm_read_mod_reg(OMAP4430_CM2_CAM_MOD,
+ OMAP4_CM_CAM_CLKSTCTRL_OFFSET)) & 0x400) {
+ __raw_writel(__raw_readl(fdifHandle + 0x10) | 0x1,
+ fdifHandle + 0x10);
+ }*/
+#endif
+
+ params->pm_fdif_counter--;
+ pr_debug("Release FDIF\n");
+
+ return PM_SUCCESS;
+error:
+ return PM_UNSUPPORTED;
+}
+
+/*
+ Release MPU on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_mpu(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ if (!params->pm_mpu_counter) {
+ pr_err("%s %d MPU not requested\n", __func__, __LINE__);
+ goto error;
+ }
+
+ params->pm_mpu_counter--;
+ pr_debug("Release MPU\n");
+
+ return PM_SUCCESS;
+error:
+ return PM_UNSUPPORTED;
+}
+
+/*
+ Release IPU on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_ipu(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ if (!params->pm_ipu_counter) {
+ pr_err("%s %d IPU not requested\n", __func__, __LINE__);
+ goto error;
+ }
+
+ params->pm_ipu_counter--;
+ pr_debug("Release IPU\n");
+
+ return PM_SUCCESS;
+error:
+ return PM_UNSUPPORTED;
+}
+
+/*
+ Release IVA HD on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_iva_hd(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ int retval;
+
+ if (!params->pm_iva_hd_counter) {
+ pr_err("%s %d IVA_HD not requested\n", __func__, __LINE__);
+ goto error;
+ }
+
+ /* Releasing SL2 */
+ /* FIXME: sl2if should be moved to a independent function */
+ if (params->pm_sl2if_counter) {
+ retval = ipu_pm_module_stop(SL2_RESOURCE);
+ if (retval) {
+ pr_err("%s %d Error releasing sl2if\n"
+ , __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+ params->pm_sl2if_counter--;
+ pr_debug("Release SL2IF\n");
+ }
+
+ retval = ipu_pm_module_stop(rcb_p->sub_type);
+ if (retval) {
+ pr_err("%s %d Error releasing IVA_HD\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+ params->pm_iva_hd_counter--;
+ pr_debug("Release IVA_HD\n");
+
+#ifdef CONFIG_OMAP_PM
+ if (params->pm_iva_hd_counter == 0 && params->pm_iss_counter == 0) {
+ pr_debug("Release MPU wakeup latency\n");
+ retval = omap_pm_set_max_mpu_wakeup_lat(&pm_qos_handle,
+ IPU_PM_NO_MPU_LAT_CONSTRAINT);
+ if (retval) {
+ pr_err("%s %d Error setting MPU cstr\n"
+ , __func__, __LINE__);
+ goto error;
+ }
+ }
+#endif
+ return PM_SUCCESS;
+error:
+ return PM_UNSUPPORTED;
+}
+
+/*
+ Release IVA SEQ0 on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_ivaseq0(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ int retval;
+
+ if (!params->pm_ivaseq0_counter) {
+ pr_err("%s %d IVASEQ0 not requested\n", __func__, __LINE__);
+ goto error;
+ }
+
+ retval = ipu_pm_module_stop(rcb_p->sub_type);
+ if (retval) {
+ pr_err("%s %d Error releasing IVASEQ0\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+ params->pm_ivaseq0_counter--;
+ pr_debug("Release IVASEQ0\n");
+
+ return PM_SUCCESS;
+error:
+ return PM_UNSUPPORTED;
+}
+
+/*
+ Release IVA SEQ1 on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_ivaseq1(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ int retval;
+
+ if (!params->pm_ivaseq1_counter) {
+ pr_err("%s %d IVASEQ1 not requested\n", __func__, __LINE__);
+ goto error;
+ }
+
+ retval = ipu_pm_module_stop(rcb_p->sub_type);
+ if (retval) {
+ pr_err("%s %d Error releasing IVASEQ1\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+ params->pm_ivaseq1_counter--;
+ pr_debug("Release IVASEQ1\n");
+
+ return PM_SUCCESS;
+error:
+ return PM_UNSUPPORTED;
+}
+
+/*
+ Release ISS on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_iss(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ int retval;
+
+ if (!params->pm_iss_counter) {
+ pr_err("%s %d ISS not requested\n", __func__, __LINE__);
+ goto error;
+ }
+
+#if TMP_AUX_CLK_HACK
+ rcb_p->fill9 = AUX_CLK_MIN;
+ ipu_pm_rel_aux_clk(handle, rcb_p, params);
+#endif
+
+ retval = ipu_pm_module_stop(rcb_p->sub_type);
+ if (retval) {
+ pr_err("%s %d Error releasing ISS\n", __func__, __LINE__);
+ return PM_UNSUPPORTED;
+ }
+
+#ifdef SR_WA
+ /* Make sure the clock domain is in idle if not softreset */
+ /*if ((cm_read_mod_reg(OMAP4430_CM2_CAM_MOD,
+ OMAP4_CM_CAM_CLKSTCTRL_OFFSET)) & 0x100) {
+ __raw_writel(__raw_readl(issHandle + 0x10) | 0x1,
+ issHandle + 0x10);
+ }*/
+#endif
+
+ /* FIXME:
+ * disable OPTFCLKEN_CTRLCLK for camera sensors
+ * should be moved to a separate function for
+ * independent control this also duplicates the
+ * above call to avoid read modify write locking
+ */
+ /*cm_write_mod_reg(CAM_DISABLED,
+ OMAP4430_CM2_CAM_MOD,
+ OMAP4_CM_CAM_ISS_CLKCTRL_OFFSET);*/
+ params->pm_iss_counter--;
+ pr_debug("Release ISS\n");
+
+#ifdef CONFIG_OMAP_PM
+ if (params->pm_iva_hd_counter == 0 && params->pm_iss_counter == 0) {
+ pr_debug("Release MPU wakeup latency\n");
+ retval = omap_pm_set_max_mpu_wakeup_lat(&pm_qos_handle,
+ IPU_PM_NO_MPU_LAT_CONSTRAINT);
+ if (retval) {
+ pr_err("%s %d Error setting MPU cstr\n"
+ , __func__, __LINE__);
+ goto error;
+ }
+ }
+#endif
+ return PM_SUCCESS;
+error:
+ return PM_UNSUPPORTED;
+}
+
+/*
+ Request a FDIF constraint on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_req_cstr(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ int perf;
+ int lat;
+ int bw;
+ int retval;
+ unsigned temp_rsrc;
+ u32 cstr_flags;
+
+ /* Get the configurable constraints */
+ cstr_flags = rcb_p->data[0];
+
+ /* TODO: call the baseport APIs */
+ if (cstr_flags & PM_CSTR_PERF_MASK) {
+ switch (rcb_p->sub_type) {
+ case MPU:
+ temp_rsrc = IPU_PM_MPU;
+ break;
+ case IPU:
+ case ISS:
+ case FDIF:
+ temp_rsrc = IPU_PM_CORE;
+ break;
+ default:
+ temp_rsrc = rcb_p->sub_type;
+ break;
+ }
+ perf = rcb_p->data[1];
+ pr_debug("Request perfomance Cstr %d\n", perf);
+ retval = ipu_pm_module_set_rate(rcb_p->sub_type,
+ temp_rsrc,
+ perf);
+ if (retval)
+ return PM_UNSUPPORTED;
+ }
+
+ if (cstr_flags & PM_CSTR_LAT_MASK) {
+ switch (rcb_p->sub_type) {
+ case MPU:
+ temp_rsrc = IPU_PM_MPU;
+ break;
+ case IPU:
+ case L3_BUS:
+ temp_rsrc = IPU_PM_CORE;
+ break;
+ case ISS:
+ case FDIF:
+ temp_rsrc = IPU_PM_SELF;
+ break;
+ default:
+ temp_rsrc = rcb_p->sub_type;
+ break;
+ }
+ lat = rcb_p->data[2];
+ pr_debug("Request latency Cstr %d\n", lat);
+ retval = ipu_pm_module_set_latency(rcb_p->sub_type,
+ temp_rsrc,
+ lat);
+ if (retval)
+ return PM_UNSUPPORTED;
+ }
+
+ if (cstr_flags & PM_CSTR_BW_MASK) {
+ bw = rcb_p->data[3];
+ pr_debug("Request bandwidth Cstr L3bus:%d\n", bw);
+ retval = ipu_pm_module_set_bandwidth(rcb_p->sub_type,
+ rcb_p->sub_type,
+ bw);
+ if (retval)
+ return PM_UNSUPPORTED;
+ }
+
+ return PM_SUCCESS;
+}
+
+/*
+ Release a constraint on behalf of an IPU client
+ *
+ */
+static inline int ipu_pm_rel_cstr(struct ipu_pm_object *handle,
+ struct rcb_block *rcb_p,
+ struct ipu_pm_params *params)
+{
+ u32 cstr_flags;
+ unsigned temp_rsrc;
+ int retval;
+
+ /* Get the configurable constraints */
+ cstr_flags = rcb_p->data[0];
+
+ /* TODO: call the baseport APIs */
+ if (cstr_flags & PM_CSTR_PERF_MASK) {
+ switch (rcb_p->sub_type) {
+ case MPU:
+ temp_rsrc = IPU_PM_MPU;
+ break;
+ case IPU:
+ case ISS:
+ case FDIF:
+ temp_rsrc = IPU_PM_CORE;
+ break;
+ default:
+ temp_rsrc = rcb_p->sub_type;
+ break;
+ }
+ pr_debug("Release perfomance Cstr\n");
+ retval = ipu_pm_module_set_rate(rcb_p->sub_type,
+ temp_rsrc,
+ NO_FREQ_CONSTRAINT);
+ if (retval)
+ return PM_UNSUPPORTED;
+ }
+
+ if (cstr_flags & PM_CSTR_LAT_MASK) {
+ switch (rcb_p->sub_type) {
+ case MPU:
+ temp_rsrc = IPU_PM_MPU;
+ break;
+ case IPU:
+ case L3_BUS:
+ temp_rsrc = IPU_PM_CORE;
+ break;
+ case ISS:
+ case FDIF:
+ temp_rsrc = IPU_PM_SELF;
+ break;
+ default:
+ temp_rsrc = rcb_p->sub_type;
+ break;
+ }
+ pr_debug("Release latency Cstr\n");
+ retval = ipu_pm_module_set_latency(rcb_p->sub_type,
+ temp_rsrc,
+ NO_LAT_CONSTRAINT);
+ if (retval)
+ return PM_UNSUPPORTED;
+ }
+
+ if (cstr_flags & PM_CSTR_BW_MASK) {
+ pr_debug("Release bandwidth Cstr\n");
+ retval = ipu_pm_module_set_bandwidth(rcb_p->sub_type,
+ rcb_p->sub_type,
+ NO_BW_CONSTRAINT);
+ if (retval)
+ return PM_UNSUPPORTED;
+ }
+
+ return PM_SUCCESS;
+}
+
+/*
+ Function to set init parameters
+ *
+ */
+void ipu_pm_params_init(struct ipu_pm_params *params)
+{
+ int retval = 0;
+
+ if (WARN_ON(unlikely(params == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ memcpy(params, &(pm_params), sizeof(struct ipu_pm_params));
+ return;
+exit:
+ pr_err("ipu_pm_params_init failed status(0x%x)\n", retval);
+}
+EXPORT_SYMBOL(ipu_pm_params_init);
+
+/*
+ Function to calculate ipu_pm mem required
+ *
+ */
+int ipu_pm_mem_req(const struct ipu_pm_params *params)
+{
+ /* Memory required for ipu pm module */
+ /* FIXME: Maybe more than this is needed */
+ return sizeof(struct sms);
+}
+EXPORT_SYMBOL(ipu_pm_mem_req);
+
+/*
+ Function to register events
+ This function will register the events needed for ipu_pm
+ the events reserved for power management are 2 and 3
+ both sysm3 and appm3 will use the same events.
+ */
+int ipu_pm_init_transport(struct ipu_pm_object *handle)
+{
+ int retval = 0;
+ struct ipu_pm_params *params;
+
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto pm_register_fail;
+ }
+
+ params = handle->params;
+ if (WARN_ON(unlikely(params == NULL))) {
+ retval = -EINVAL;
+ goto pm_register_fail;
+ }
+
+ retval = notify_register_event(
+ params->remote_proc_id,
+ params->line_id,
+ params->pm_resource_event | \
+ (NOTIFY_SYSTEMKEY << 16),
+ (notify_fn_notify_cbck)ipu_pm_callback,
+ (void *)NULL);
+ if (retval < 0)
+ goto pm_register_fail;
+
+ retval = notify_register_event(
+ params->remote_proc_id,
+ params->line_id,
+ params->pm_notification_event | \
+ (NOTIFY_SYSTEMKEY << 16),
+ (notify_fn_notify_cbck)ipu_pm_notify_callback,
+ (void *)NULL);
+
+ if (retval < 0) {
+ retval = notify_unregister_event(
+ params->remote_proc_id,
+ params->line_id,
+ params->pm_resource_event | \
+ (NOTIFY_SYSTEMKEY << 16),
+ (notify_fn_notify_cbck)ipu_pm_callback,
+ (void *)NULL);
+ if (retval < 0)
+ pr_err("Error unregistering notify event\n");
+ goto pm_register_fail;
+ }
+ return retval;
+
+pm_register_fail:
+ pr_err("pm register events failed status(0x%x)", retval);
+ return retval;
+}
+
+/*
+ Function to create ipu pm object
+ *
+ */
+struct ipu_pm_object *ipu_pm_create(const struct ipu_pm_params *params)
+{
+ int i;
+ int retval = 0;
+
+ if (WARN_ON(unlikely(params == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (params->remote_proc_id == SYS_M3) {
+ pm_handle_sysm3 = kmalloc(sizeof(struct ipu_pm_object),
+ GFP_ATOMIC);
+
+ if (WARN_ON(unlikely(pm_handle_sysm3 == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ pm_handle_sysm3->rcb_table = (struct sms *)params->shared_addr;
+
+ pm_handle_sysm3->pm_event = kzalloc(sizeof(struct pm_event)
+ * params->pm_num_events, GFP_KERNEL);
+
+ if (WARN_ON(unlikely(pm_handle_sysm3->pm_event == NULL))) {
+ retval = -EINVAL;
+ kfree(pm_handle_sysm3);
+ goto exit;
+ }
+
+ /* Each event has it own sem */
+ for (i = 0; i < params->pm_num_events; i++) {
+ sema_init(&pm_handle_sysm3->pm_event[i].sem_handle, 0);
+ pm_handle_sysm3->pm_event[i].event_type = i;
+ }
+
+ pm_handle_sysm3->params = kzalloc(sizeof(struct ipu_pm_params)
+ , GFP_KERNEL);
+
+ if (WARN_ON(unlikely(pm_handle_sysm3->params == NULL))) {
+ retval = -EINVAL;
+ kfree(pm_handle_sysm3->pm_event);
+ kfree(pm_handle_sysm3);
+ goto exit;
+ }
+
+ memcpy(pm_handle_sysm3->params, params,
+ sizeof(struct ipu_pm_params));
+
+ /* Check the SW version on both sides */
+ if (WARN_ON(pm_handle_sysm3->rcb_table->pm_version !=
+ PM_VERSION))
+ pr_warning("Mismatch in PM version Host:0x%08x "
+ "Remote:0x%08x", PM_VERSION,
+ pm_handle_sysm3->rcb_table->pm_version);
+
+ spin_lock_init(&pm_handle_sysm3->lock);
+ INIT_WORK(&pm_handle_sysm3->work, ipu_pm_work);
+
+ if (!kfifo_alloc(&pm_handle_sysm3->fifo,
+ IPU_KFIFO_SIZE * sizeof(struct ipu_pm_msg),
+ GFP_KERNEL))
+ return pm_handle_sysm3;
+
+ retval = -ENOMEM;
+ kfree(pm_handle_sysm3->params);
+ kfree(pm_handle_sysm3->pm_event);
+ kfree(pm_handle_sysm3);
+ } else if (params->remote_proc_id == APP_M3) {
+ pm_handle_appm3 = kmalloc(sizeof(struct ipu_pm_object),
+ GFP_ATOMIC);
+
+ if (WARN_ON(unlikely(pm_handle_appm3 == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ pm_handle_appm3->rcb_table = (struct sms *)params->shared_addr;
+
+ pm_handle_appm3->pm_event = kzalloc(sizeof(struct pm_event)
+ * params->pm_num_events, GFP_KERNEL);
+
+ if (WARN_ON(unlikely(pm_handle_appm3->pm_event == NULL))) {
+ retval = -EINVAL;
+ kfree(pm_handle_appm3);
+ goto exit;
+ }
+
+ /* Each event has it own sem */
+ for (i = 0; i < params->pm_num_events; i++) {
+ sema_init(&pm_handle_appm3->pm_event[i].sem_handle, 0);
+ pm_handle_appm3->pm_event[i].event_type = i;
+ }
+
+ pm_handle_appm3->params = kzalloc(sizeof(struct ipu_pm_params)
+ , GFP_KERNEL);
+
+ if (WARN_ON(unlikely(pm_handle_appm3->params == NULL))) {
+ retval = -EINVAL;
+ kfree(pm_handle_appm3->pm_event);
+ kfree(pm_handle_appm3);
+ goto exit;
+ }
+
+ memcpy(pm_handle_appm3->params, params,
+ sizeof(struct ipu_pm_params));
+
+ /* Check the SW version on both sides */
+ if (WARN_ON(pm_handle_appm3->rcb_table->pm_version !=
+ PM_VERSION))
+ pr_warning("Mismatch in PM version Host:0x%08x "
+ "Remote:0x%08x", PM_VERSION,
+ pm_handle_appm3->rcb_table->pm_version);
+
+ spin_lock_init(&pm_handle_appm3->lock);
+ INIT_WORK(&pm_handle_appm3->work, ipu_pm_work);
+
+ if (!kfifo_alloc(&pm_handle_appm3->fifo,
+ IPU_KFIFO_SIZE * sizeof(struct ipu_pm_msg),
+ GFP_KERNEL))
+ return pm_handle_appm3;
+
+ retval = -ENOMEM;
+ kfree(pm_handle_appm3->params);
+ kfree(pm_handle_appm3->pm_event);
+ kfree(pm_handle_appm3);
+ } else
+ retval = -EINVAL;
+
+exit:
+ pr_err("ipu_pm_create failed! status = 0x%x\n", retval);
+ return NULL;
+}
+
+/*
+ Function to delete ipu pm object
+ *
+ */
+void ipu_pm_delete(struct ipu_pm_object *handle)
+{
+ int retval = 0;
+ struct ipu_pm_params *params;
+
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ params = handle->params;
+ if (WARN_ON(unlikely(params == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ /* Release the shared RCB */
+ handle->rcb_table = NULL;
+
+ kfree(handle->pm_event);
+ if (params->remote_proc_id == SYS_M3)
+ pm_handle_sysm3 = NULL;
+ else
+ pm_handle_appm3 = NULL;
+ kfree(handle->params);
+ kfree(handle);
+ return;
+exit:
+ pr_err("ipu_pm_delete is already NULL status = 0x%x\n", retval);
+}
+
+/*
+ Function to get the ducati state flag from Share memory
+ *
+ */
+u32 ipu_pm_get_state(int proc_id)
+{
+ struct ipu_pm_object *handle;
+
+ /* get the handle to proper ipu pm object */
+ handle = ipu_pm_get_handle(proc_id);
+ if (WARN_ON(unlikely(handle == NULL)))
+ return -EINVAL;
+
+ return handle->rcb_table->state_flag;
+}
+EXPORT_SYMBOL(ipu_pm_get_state);
+
+/*
+ Function to get ipu pm object
+ *
+ */
+struct ipu_pm_object *ipu_pm_get_handle(int proc_id)
+{
+ if (proc_id == SYS_M3)
+ return pm_handle_sysm3;
+ else if (proc_id == APP_M3)
+ return pm_handle_appm3;
+ else
+ return NULL;
+}
+EXPORT_SYMBOL(ipu_pm_get_handle);
+
+/*
+ Function to save a processor context and send it to hibernate
+ *
+ */
+int ipu_pm_save_ctx(int proc_id)
+{
+ int retval = 0;
+ int flag;
+ int num_loaded_cores = 0;
+ int sys_loaded;
+ int app_loaded;
+ unsigned long timeout;
+ struct ipu_pm_object *handle;
+
+ /* get the handle to proper ipu pm object */
+ handle = ipu_pm_get_handle(proc_id);
+ if (unlikely(handle == NULL))
+ return 0;
+
+ /* get M3's load flag */
+ sys_loaded = (ipu_pm_get_state(proc_id) & SYS_PROC_LOADED) >>
+ PROC_LD_SHIFT;
+ app_loaded = (ipu_pm_get_state(proc_id) & APP_PROC_LOADED) >>
+ PROC_LD_SHIFT;
+
+ /* If already down don't kill it twice */
+ if (ipu_pm_get_state(proc_id) & SYS_PROC_DOWN) {
+ pr_warn("ipu already hibernated, no need to save again");
+ return 0;
+ }
+
+#ifdef CONFIG_OMAP_PM
+ retval = omap_pm_set_max_sdma_lat(&pm_qos_handle_2,
+ IPU_PM_NO_MPU_LAT_CONSTRAINT);
+ if (retval)
+ pr_info("Unable to remove cstr on IPU\n");
+#endif
+
+ /* Because of the current scheme, we need to check
+ * if APPM3 is enable and we need to shut it down too
+ * Sysm3 is the only want sending the hibernate message
+ */
+ mutex_lock(ipu_pm_state.gate_handle);
+ if (proc_id == SYS_M3 || proc_id == APP_M3) {
+ if (!sys_loaded)
+ goto exit;
+
+ num_loaded_cores = app_loaded + sys_loaded;
+
+#ifdef CONFIG_SYSLINK_IPU_SELF_HIBERNATION
+ /* Turn off timer before hibernation */
+ ipu_pm_timer_state(PM_HIB_TIMER_OFF);
+#endif
+
+ flag = 1;
+ timeout = jiffies + msecs_to_jiffies(WAIT_FOR_IDLE_TIMEOUT);
+ /* Wait fot Ducati to hibernate */
+ do {
+ /* Checking if IPU is really in idle */
+ if (NUM_IDLE_CORES == num_loaded_cores) {
+ flag = 0;
+ break;
+ }
+ } while (!time_after(jiffies, timeout));
+ if (flag)
+ goto error;
+
+ /* Check for APPM3, if loaded reset first */
+ if (app_loaded) {
+ pr_info("Sleep APPM3\n");
+ retval = rproc_sleep(app_rproc);
+ /*cm_write_mod_reg(HW_AUTO,
+ OMAP4430_CM2_CORE_MOD,
+ OMAP4_CM_DUCATI_CLKSTCTRL_OFFSET);*/
+ if (retval)
+ goto error;
+ handle->rcb_table->state_flag |= APP_PROC_DOWN;
+ }
+ pr_info("Sleep SYSM3\n");
+ retval = rproc_sleep(sys_rproc);
+ /*cm_write_mod_reg(HW_AUTO,
+ OMAP4430_CM2_CORE_MOD,
+ OMAP4_CM_DUCATI_CLKSTCTRL_OFFSET);*/
+ if (retval)
+ goto error;
+ handle->rcb_table->state_flag |= SYS_PROC_DOWN;
+ if (ducati_mbox)
+ omap_mbox_save_ctx(ducati_mbox);
+ else
+ pr_err("Not able to save mbox");
+ if (ducati_iommu)
+ iommu_save_ctx(ducati_iommu);
+ else
+ pr_err("Not able to save iommu");
+ } else
+ goto error;
+
+
+exit:
+ mutex_unlock(ipu_pm_state.gate_handle);
+ return 0;
+error:
+#ifdef CONFIG_SYSLINK_IPU_SELF_HIBERNATION
+ ipu_pm_timer_state(PM_HIB_TIMER_ON);
+#endif
+ mutex_unlock(ipu_pm_state.gate_handle);
+ pr_debug("Aborting hibernation process\n");
+ return -EINVAL;
+}
+EXPORT_SYMBOL(ipu_pm_save_ctx);
+
+/* Function to check if a processor is shutdown
+ * if shutdown then restore context else return.
+ */
+int ipu_pm_restore_ctx(int proc_id)
+{
+ int retval = 0;
+ int sys_loaded;
+ int app_loaded;
+ struct ipu_pm_object *handle;
+
+ /*If feature not supported by proc, return*/
+ if (!proc_supported(proc_id))
+ return 0;
+
+ /* get the handle to proper ipu pm object */
+ handle = ipu_pm_get_handle(proc_id);
+
+ if (WARN_ON(unlikely(handle == NULL)))
+ return -EINVAL;
+
+ /* FIXME: This needs mor analysis.
+ * Since the sync of IPU and MPU is done this is a safe place
+ * to switch to HW_AUTO to allow transition of clocks to gated
+ * supervised by HW.
+ */
+ if (first_time) {
+ /* Enable/disable ipu hibernation*/
+#ifdef CONFIG_SYSLINK_IPU_SELF_HIBERNATION
+ handle->rcb_table->pm_flags.hibernateAllowed = 1;
+ /* turn on ducati hibernation timer */
+ ipu_pm_timer_state(PM_HIB_TIMER_ON);
+#else
+ handle->rcb_table->pm_flags.hibernateAllowed = 0;
+#endif
+ pr_debug("hibernateAllowed=%d\n",
+ handle->rcb_table->pm_flags.hibernateAllowed);
+ first_time = 0;
+ /*cm_write_mod_reg(HW_AUTO,
+ OMAP4430_CM2_CORE_MOD,
+ OMAP4_CM_DUCATI_CLKSTCTRL_OFFSET);*/
+#ifdef CONFIG_OMAP_PM
+ retval = omap_pm_set_max_sdma_lat(&pm_qos_handle_2,
+ IPU_PM_MM_MPU_LAT_CONSTRAINT);
+ if (retval)
+ pr_info("Unable to set cstr on IPU\n");
+#endif
+ }
+
+ /* Check if the M3 was loaded */
+ sys_loaded = (ipu_pm_get_state(proc_id) & SYS_PROC_LOADED) >>
+ PROC_LD_SHIFT;
+ app_loaded = (ipu_pm_get_state(proc_id) & APP_PROC_LOADED) >>
+ PROC_LD_SHIFT;
+
+ /* Because of the current scheme, we need to check
+ * if APPM3 is enable and we need to enable it too
+ * In both cases we should check if for both cores
+ * and enable them if they were loaded.
+ */
+ mutex_lock(ipu_pm_state.gate_handle);
+ if (proc_id == SYS_M3 || proc_id == APP_M3) {
+ if (!(ipu_pm_get_state(proc_id) & SYS_PROC_DOWN))
+ goto exit;
+
+ if (ducati_mbox)
+ omap_mbox_restore_ctx(ducati_mbox);
+ else
+ pr_err("Not able to restore mbox");
+ if (ducati_iommu)
+ iommu_restore_ctx(ducati_iommu);
+ else
+ pr_err("Not able to restore iommu");
+
+ pr_info("Wakeup SYSM3\n");
+ retval = rproc_wakeup(sys_rproc);
+ /*cm_write_mod_reg(HW_AUTO,
+ OMAP4430_CM2_CORE_MOD,
+ OMAP4_CM_DUCATI_CLKSTCTRL_OFFSET);*/
+ if (retval)
+ goto error;
+ handle->rcb_table->state_flag &= ~SYS_PROC_DOWN;
+ if (ipu_pm_get_state(proc_id) & APP_PROC_LOADED) {
+ pr_info("Wakeup APPM3\n");
+ retval = rproc_wakeup(app_rproc);
+ /*cm_write_mod_reg(HW_AUTO,
+ OMAP4430_CM2_CORE_MOD,
+ OMAP4_CM_DUCATI_CLKSTCTRL_OFFSET);*/
+ if (retval)
+ goto error;
+ handle->rcb_table->state_flag &= ~APP_PROC_DOWN;
+ }
+#ifdef CONFIG_SYSLINK_IPU_SELF_HIBERNATION
+ /* turn on ducati hibernation timer */
+ ipu_pm_timer_state(PM_HIB_TIMER_ON);
+#endif
+#ifdef CONFIG_OMAP_PM
+ retval = omap_pm_set_max_sdma_lat(&pm_qos_handle_2,
+ IPU_PM_MM_MPU_LAT_CONSTRAINT);
+ if (retval)
+ pr_info("Unable to set cstr on IPU\n");
+#endif
+ } else
+ goto error;
+exit:
+ mutex_unlock(ipu_pm_state.gate_handle);
+ return retval;
+error:
+ mutex_unlock(ipu_pm_state.gate_handle);
+ pr_debug("Aborting restoring process\n");
+ return -EINVAL;
+}
+EXPORT_SYMBOL(ipu_pm_restore_ctx);
+
+/* Get the default configuration for the ipu_pm module.
+ * needed in ipu_pm_setup.
+ */
+void ipu_pm_get_config(struct ipu_pm_config *cfg)
+{
+ int retval = 0;
+
+ if (WARN_ON(unlikely(cfg == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (atomic_cmpmask_and_lt(&(ipu_pm_state.ref_count),
+ IPU_PM_MAKE_MAGICSTAMP(0),
+ IPU_PM_MAKE_MAGICSTAMP(1)) == true)
+ memcpy(cfg, &ipu_pm_state.def_cfg,
+ sizeof(struct ipu_pm_config));
+ else
+ memcpy(cfg, &ipu_pm_state.cfg, sizeof(struct ipu_pm_config));
+ return;
+
+exit:
+ if (retval < 0)
+ pr_err("ipu_pm_get_config failed! status = 0x%x", retval);
+ return;
+}
+EXPORT_SYMBOL(ipu_pm_get_config);
+
+/* Function to setup ipu pm object
+ * This function is called in platform_setup()
+ * This function will load the default configuration for ipu_pm
+ * in this function we can decide what is going to be controled
+ * by ipu_pm (DVFS, NOTIFICATIONS, ...) this configuration can
+ * can be changed on run-time.
+ * Also the workqueue is created and the local mutex
+ */
+int ipu_pm_setup(struct ipu_pm_config *cfg)
+{
+ struct ipu_pm_config tmp_cfg;
+ int retval = 0;
+ struct mutex *lock = NULL;
+
+ /* This sets the ref_count variable is not initialized, upper 16 bits is
+ written with module Id to ensure correctness of refCount variable.
+ */
+ atomic_cmpmask_and_set(&ipu_pm_state.ref_count,
+ IPU_PM_MAKE_MAGICSTAMP(0),
+ IPU_PM_MAKE_MAGICSTAMP(0));
+ if (atomic_inc_return(&ipu_pm_state.ref_count)
+ != IPU_PM_MAKE_MAGICSTAMP(1)) {
+ return 1;
+ }
+
+ if (cfg == NULL) {
+ ipu_pm_get_config(&tmp_cfg);
+ cfg = &tmp_cfg;
+ }
+
+ /* Create a default gate handle for local module protection */
+ lock = kmalloc(sizeof(struct mutex), GFP_KERNEL);
+ if (lock == NULL) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+ mutex_init(lock);
+ ipu_pm_state.gate_handle = lock;
+
+ /* Create the wq for req/rel resources */
+ ipu_resources = create_singlethread_workqueue("ipu_resources");
+ ipu_clean_up = create_singlethread_workqueue("ipu_clean_up");
+ INIT_WORK(&clean, ipu_pm_clean_work);
+
+ /* No proc attached yet */
+ global_rcb = NULL;
+ pm_handle_appm3 = NULL;
+ pm_handle_sysm3 = NULL;
+ ducati_iommu = NULL;
+ ducati_mbox = NULL;
+ sys_rproc = NULL;
+ app_rproc = NULL;
+
+ memcpy(&ipu_pm_state.cfg, cfg, sizeof(struct ipu_pm_config));
+ ipu_pm_state.is_setup = true;
+
+ /* BIOS flags to know the state of IPU cores */
+ sysm3Idle = ioremap(IDLE_FLAG_PHY_ADDR, (sizeof(void) * 2));
+ if (!sysm3Idle) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ appm3Idle = (void *)sysm3Idle + sizeof(void *);
+ if (!appm3Idle) {
+ retval = -ENOMEM;
+ iounmap(sysm3Idle);
+ goto exit;
+ }
+#ifdef SR_WA
+ issHandle = ioremap(0x52000000, (sizeof(void) * 1));
+ fdifHandle = ioremap(0x4A10A000, (sizeof(void) * 1));
+#endif
+ BLOCKING_INIT_NOTIFIER_HEAD(&ipu_pm_notifier);
+
+ return retval;
+exit:
+ pr_err("ipu_pm_setup failed! retval = 0x%x", retval);
+ return retval;
+}
+EXPORT_SYMBOL(ipu_pm_setup);
+
+/* Function to attach ipu pm object
+ * This function is called in ipc_attach()
+ * This function will create the object based on the remoteproc id
+ * It is also recieving the shared address pointer to use in rcb
+ */
+int ipu_pm_attach(u16 remote_proc_id, void *shared_addr)
+{
+ struct ipu_pm_params params;
+ struct ipu_pm_object *handle;
+ int retval = 0;
+
+ /* Since currently the share memory used by remote cores
+ * to manage the rcb (resources) is one, a global pointer
+ * can be used to access it.
+ */
+ if (!global_rcb)
+ global_rcb = (struct sms *)shared_addr;
+
+ ipu_pm_params_init(&params);
+ params.remote_proc_id = remote_proc_id;
+ params.shared_addr = (void *)global_rcb;
+ params.line_id = LINE_ID;
+ params.shared_addr_size = ipu_pm_mem_req(NULL);
+
+ handle = ipu_pm_create(&params);
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ retval = ipu_pm_init_transport(handle);
+ if (retval)
+ goto exit;
+
+ /* FIXME the physical address should be calculated */
+ pr_debug("ipu_pm_attach at va0x%x pa0x9cf00400\n",
+ (unsigned int)shared_addr);
+
+ /* Get remote processor handle to save/restore */
+ if (remote_proc_id == SYS_M3 && IS_ERR_OR_NULL(sys_rproc)) {
+ pr_debug("requesting sys_rproc\n");
+ sys_rproc = omap_rproc_get("ducati-proc0");
+ if (sys_rproc == NULL) {
+ retval = PTR_ERR(sys_rproc);
+ sys_rproc = NULL;
+ pr_err("%s %d failed to get sysm3 handle",
+ __func__, __LINE__);
+ goto exit;
+ }
+ handle->dmtimer = NULL;
+ } else if (remote_proc_id == APP_M3 && IS_ERR_OR_NULL(app_rproc)) {
+ pr_debug("requesting app_rproc\n");
+ app_rproc = omap_rproc_get("ducati-proc1");
+ if (IS_ERR_OR_NULL(app_rproc)) {
+ retval = PTR_ERR(app_rproc);
+ app_rproc = NULL;
+ pr_err("%s %d failed to get appm3 handle",
+ __func__, __LINE__);
+ goto exit;
+ }
+ handle->dmtimer = NULL;
+ }
+
+ if (IS_ERR_OR_NULL(ducati_iommu)) {
+ pr_debug("requesting ducati_iommu\n");
+ ducati_iommu = iommu_get("ducati");
+ if (IS_ERR_OR_NULL(ducati_iommu)) {
+ retval = PTR_ERR(ducati_iommu);
+ ducati_iommu = NULL;
+ pr_err("%s %d failed to get iommu handle",
+ __func__, __LINE__);
+ goto exit;
+ }
+ iommu_register_notifier(ducati_iommu,
+ &ipu_pm_notify_nb_iommu_ducati);
+ }
+ /* Get mailbox for save/restore */
+ if (IS_ERR_OR_NULL(ducati_mbox)) {
+ pr_debug("requesting ducati_mbox\n");
+ ducati_mbox = omap_mbox_get("mailbox-2", NULL);
+ if (IS_ERR_OR_NULL(ducati_mbox)) {
+ retval = PTR_ERR(ducati_mbox);
+ ducati_mbox = NULL;
+ pr_err("%s %d failed to get mailbox handle",
+ __func__, __LINE__);
+ goto exit;
+ }
+ }
+
+ return retval;
+exit:
+ pr_err("ipu_pm_attach failed! retval = 0x%x", retval);
+ return retval;
+}
+EXPORT_SYMBOL(ipu_pm_attach);
+
+/* Function to deattach ipu pm object
+ * This function is called in ipc_detach()
+ * This function will delete the object based
+ * on the remoteproc id and unregister the notify
+ * events used by ipu_pm module
+ */
+int ipu_pm_detach(u16 remote_proc_id)
+{
+ struct ipu_pm_object *handle;
+ struct ipu_pm_params *params;
+ int retval = 0;
+
+ /* get the handle to proper ipu pm object */
+ handle = ipu_pm_get_handle(remote_proc_id);
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ params = handle->params;
+ if (WARN_ON(unlikely(params == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+#ifdef CONFIG_SYSLINK_IPU_SELF_HIBERNATION
+ /* reset the ducati hibernation timer */
+ if (remote_proc_id == SYS_M3)
+ ipu_pm_timer_state(PM_HIB_TIMER_RESET);
+#endif
+
+ /* When recovering clean_up was called, so wait for completion.
+ * If not make sure there is no resource pending.
+ */
+ if (recover) {
+ pr_debug("Recovering IPU\n");
+ while (!wait_for_completion_timeout(&ipu_clean_up_comp,
+ msecs_to_jiffies(params->timeout)))
+ pr_warn("%s: handle(s) still opened\n", __func__);
+ /* Get rid of any pending work */
+ flush_workqueue(ipu_resources);
+ } else {
+ ipu_pm_clean_res();
+ }
+
+ /* unregister the events used for ipu_pm */
+ retval = notify_unregister_event(
+ params->remote_proc_id,
+ params->line_id,
+ params->pm_resource_event | (NOTIFY_SYSTEMKEY << 16),
+ (notify_fn_notify_cbck)ipu_pm_callback,
+ (void *)NULL);
+ if (retval < 0) {
+ pr_err("Error unregistering notify event\n");
+ goto exit;
+ }
+ retval = notify_unregister_event(
+ params->remote_proc_id,
+ params->line_id,
+ params->pm_notification_event | (NOTIFY_SYSTEMKEY << 16),
+ (notify_fn_notify_cbck)ipu_pm_notify_callback,
+ (void *)NULL);
+ if (retval < 0) {
+ pr_err("Error unregistering notify event\n");
+ goto exit;
+ }
+
+ /* Put remote processor handle to save/restore */
+ if (remote_proc_id == SYS_M3 && !IS_ERR_OR_NULL(sys_rproc)) {
+ pr_debug("releasing sys_rproc\n");
+ omap_rproc_put(sys_rproc);
+ sys_rproc = NULL;
+ } else if (remote_proc_id == APP_M3 && !IS_ERR_OR_NULL(app_rproc)) {
+ pr_debug("releasing app_rproc\n");
+ omap_rproc_put(app_rproc);
+ app_rproc = NULL;
+ }
+
+ if (IS_ERR_OR_NULL(sys_rproc) && IS_ERR_OR_NULL(app_rproc)) {
+ if (!IS_ERR_OR_NULL(ducati_iommu)) {
+ /*
+ * Restore iommu to allow process's iommu cleanup
+ * after ipu_pm is shutdown
+ */
+ if (ipu_pm_get_state(SYS_M3) & SYS_PROC_DOWN)
+ iommu_restore_ctx(ducati_iommu);
+ iommu_unregister_notifier(ducati_iommu,
+ &ipu_pm_notify_nb_iommu_ducati);
+ pr_debug("releasing ducati_iommu\n");
+ iommu_put(ducati_iommu);
+ ducati_iommu = NULL;
+ }
+ /* Get mailbox for save/restore */
+ if (!IS_ERR_OR_NULL(ducati_mbox)) {
+ pr_debug("releasing ducati_mbox\n");
+ omap_mbox_put(ducati_mbox, NULL);
+ ducati_mbox = NULL;
+ }
+ /* Reset the state_flag */
+ handle->rcb_table->state_flag = 0;
+ if (recover)
+ recover = false;
+ global_rcb = NULL;
+ first_time = 1;
+ }
+
+ /* Deleting the handle based on remote_proc_id */
+ ipu_pm_delete(handle);
+
+ return retval;
+exit:
+ pr_err("ipu_pm_detach failed handle null retval 0x%x", retval);
+ return retval;
+}
+EXPORT_SYMBOL(ipu_pm_detach);
+
+/* Function to destroy ipu_pm module
+ * this function will destroy the structs
+ * created to set the configuration
+ */
+int ipu_pm_destroy(void)
+{
+ int retval = 0;
+ struct mutex *lock = NULL;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &ipu_pm_state.ref_count,
+ IPU_PM_MAKE_MAGICSTAMP(0),
+ IPU_PM_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (!(atomic_dec_return(&ipu_pm_state.ref_count)
+ == IPU_PM_MAKE_MAGICSTAMP(0))) {
+ retval = 1;
+ goto exit;
+ }
+
+ if (WARN_ON(ipu_pm_state.gate_handle == NULL)) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ retval = mutex_lock_interruptible(ipu_pm_state.gate_handle);
+ if (retval)
+ goto exit;
+
+ lock = ipu_pm_state.gate_handle;
+ ipu_pm_state.gate_handle = NULL;
+ mutex_unlock(lock);
+ kfree(lock);
+ /* Delete the wq for req/rel resources */
+ destroy_workqueue(ipu_resources);
+ destroy_workqueue(ipu_clean_up);
+
+ first_time = 1;
+ iounmap(sysm3Idle);
+#ifdef SR_WA
+ iounmap(issHandle);
+ iounmap(fdifHandle);
+ issHandle = NULL;
+ fdifHandle = NULL;
+#endif
+ sysm3Idle = NULL;
+ appm3Idle = NULL;
+ global_rcb = NULL;
+
+ return retval;
+exit:
+ if (retval < 0)
+ pr_err("ipu_pm_destroy failed, retval: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(ipu_pm_destroy);
+
+static irqreturn_t ipu_pm_timer_interrupt(int irq, void *dev_id)
+{
+ struct omap_dm_timer *gpt = (struct omap_dm_timer *)dev_id;
+
+ ipu_pm_timer_state(PM_HIB_TIMER_EXPIRE);
+ omap_dm_timer_write_status(gpt, OMAP_TIMER_INT_OVERFLOW);
+ return IRQ_HANDLED;
+}
+
+/* Function implements hibernation and watch dog timer
+ * The functionality is based on following states
+ * RESET: Timer is disabed
+ * OFF: Timer is OFF
+ * ON: Timer running
+ * HIBERNATE: Waking up for ducati cores to hibernate
+ * WD_RESET: Waiting for Ducati cores to complete hibernation
+ */
+static int ipu_pm_timer_state(int event)
+{
+ int retval = 0;
+ int tick_rate;
+ struct ipu_pm_object *handle;
+ struct ipu_pm_params *params;
+
+ handle = ipu_pm_get_handle(SYS_M3);
+ if (handle == NULL) {
+ pr_err("ipu_pm_timer_state handle ptr NULL\n");
+ retval = PTR_ERR(handle);
+ goto exit;
+ }
+ params = handle->params;
+ if (params == NULL) {
+ pr_err("ipu_pm_timer_state params ptr NULL\n");
+ retval = PTR_ERR(params);
+ goto exit;
+ }
+ if (sys_rproc == NULL)
+ goto exit;
+
+ switch (event) {
+ case PM_HIB_TIMER_EXPIRE:
+ if (params->hib_timer_state == PM_HIB_TIMER_ON) {
+ pr_debug("Starting hibernation, waking up M3 cores");
+ handle->rcb_table->state_flag |= (SYS_PROC_HIB |
+ APP_PROC_HIB | ENABLE_IPU_HIB);
+#ifdef CONFIG_DUCATI_WATCH_DOG
+ if (sys_rproc->dmtimer != NULL)
+ omap_dm_timer_set_load(sys_rproc->dmtimer, 1,
+ params->wdt_time);
+ params->hib_timer_state = PM_HIB_TIMER_WDRESET;
+ } else if (params->hib_timer_state ==
+ PM_HIB_TIMER_WDRESET) {
+ /* notify devh to begin error recovery here */
+ pr_debug("Timer ISR: Trigger WD reset + recovery\n");
+ ipu_pm_recover_schedule();
+ ipu_pm_notify_event(0, NULL);
+ if (sys_rproc->dmtimer != NULL)
+ omap_dm_timer_stop(sys_rproc->dmtimer);
+ params->hib_timer_state = PM_HIB_TIMER_OFF;
+#endif
+ }
+ break;
+ case PM_HIB_TIMER_RESET:
+ /* disable timer and remove irq handler */
+ if (handle->dmtimer) {
+ free_irq(OMAP44XX_IRQ_GPT3, (void *)handle->dmtimer);
+ handle->dmtimer = NULL;
+ params->hib_timer_state = PM_HIB_TIMER_RESET;
+ }
+ break;
+ case PM_HIB_TIMER_OFF: /* disable timer */
+ /* no need to disable timer since it
+ * is done in rproc context */
+ params->hib_timer_state = PM_HIB_TIMER_OFF;
+ break;
+ case PM_HIB_TIMER_ON: /* enable timer */
+ if (params->hib_timer_state == PM_HIB_TIMER_RESET) {
+ tick_rate = clk_get_rate(omap_dm_timer_get_fclk(
+ sys_rproc->dmtimer));
+ handle->rcb_table->hib_time = 0xFFFFFFFF - (
+ (tick_rate/1000) * PM_HIB_DEFAULT_TIME);
+ params->wdt_time = 0xFFFFFFFF - (
+ (tick_rate/1000) * PM_HIB_WDT_TIME);
+ retval = request_irq(OMAP44XX_IRQ_GPT3,
+ ipu_pm_timer_interrupt,
+ IRQF_DISABLED,
+ "HIB_TIMER",
+ (void *)sys_rproc->dmtimer);
+ if (retval < 0)
+ pr_warn("request_irq status: %x\n", retval);
+ /*
+ * store the dmtimer handle locally to use during
+ * free_irq as dev_id token in cases where the remote
+ * proc frees the dmtimer handle first
+ */
+ handle->dmtimer = sys_rproc->dmtimer;
+ }
+ if (sys_rproc->dmtimer != NULL)
+ omap_dm_timer_set_load_start(sys_rproc->dmtimer, 1,
+ handle->rcb_table->hib_time);
+ params->hib_timer_state = PM_HIB_TIMER_ON;
+ break;
+ }
+ return retval;
+exit:
+ if (retval < 0)
+ pr_err("ipu_pm_timer_state failed, retval: %x\n", retval);
+ return retval;
+}
+
+/*
+ * ======== ipu_pm_notify_event ========
+ * IPU event notifications.
+ */
+#ifdef CONFIG_DUCATI_WATCH_DOG
+static int ipu_pm_notify_event(int event, void *data)
+{
+ return blocking_notifier_call_chain(&ipu_pm_notifier, event, data);
+}
+#endif
+
+/*
+ * ======== ipu_pm_register_notifier ========
+ * Register for IPC events.
+ */
+int ipu_pm_register_notifier(struct notifier_block *nb)
+{
+ if (!nb)
+ return -EINVAL;
+ return blocking_notifier_chain_register(&ipu_pm_notifier, nb);
+}
+EXPORT_SYMBOL_GPL(ipu_pm_register_notifier);
+
+/*
+ * ======== ipu_pm_unregister_notifier ========
+ * Un-register for events.
+ */
+int ipu_pm_unregister_notifier(struct notifier_block *nb)
+{
+ if (!nb)
+ return -EINVAL;
+ return blocking_notifier_chain_unregister(&ipu_pm_notifier, nb);
+}
+EXPORT_SYMBOL_GPL(ipu_pm_unregister_notifier);
diff --git a/drivers/dsp/syslink/ipu_pm/ipu_pm.h b/drivers/dsp/syslink/ipu_pm/ipu_pm.h
new file mode 100644
index 00000000000..88a9cb4dbd9
--- /dev/null
+++ b/drivers/dsp/syslink/ipu_pm/ipu_pm.h
@@ -0,0 +1,565 @@
+/*
+* ipu_pm.h
+*
+* Syslink IPU Power Managament support functions for TI OMAP processors.
+*
+* Copyright (C) 2009-2010 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.
+*
+* --------------------------------------------------------------------
+* | rcb_num | | | | |
+* | msg_type | | | | |
+* | sub_type | | | | |
+* | rqst_cpu | 1-|word | | |
+* | extd_mem_flag | | | | |
+* | num_chan | | | | |
+* | fill9 | | | | |
+* |-------------------------------------| ------ 4-words 4-words |
+* | process_id | 1-word | | |
+* |-------------------------------------| ------ | | |
+* | sem_hnd | 1-word | | |
+* |-------------------------------------| ------ | | |
+* | mod_base_addr | 1-word | | |
+* |-------------------------------------| ------ ----- ----- |
+* | channels[0] | data[0] | datax[0] | | | | |
+* | channels[1] | | | 1-word | | RCB_SIZE
+* | channels[2] | | | | | | =
+* | channels[3] | | | | | | 8WORDS
+* |--------------|---------|------------| ------ | | |
+* | channels[4] | data[0] | datax[1] | | | | |
+* | channels[5] | | | 1-word | RCB_SIZE-5 |
+* | channels[6] | | | | | | |
+* | channels[7] | | | | RCB_SIZE-4 | |
+* |--------------|---------|------------| ------ | | |
+* | channels[8] | data[0] | datax[2] | | | | |
+* | channels[9] | | | 1-word | | |
+* | channels[10] | | | | | | |
+* | channels[11] | | | | | | |
+* |--------------|---------|------------| ------ | ----- |
+* | channels[12] | data[0] |extd_mem_hnd| | | | |
+* | channels[13] | | | 1-word | 1-word |
+* | channels[14] | | | | | | |
+* | channels[15] | | | | | | |
+* --------------------------------------------------------------------
+*
+*The Ducati Power Management sub-system uses a structure called RCB_struct or
+*just RCB to share information with the MPU about a particular resource involved
+*in the communication. The information stored in this structure is needed to get
+*attributes and other useful data about the resource.
+*The fisrt fields of the RCB resemble the Rcb message sent across the NotifyDver
+*It retains the rcb_num, msg_type and msg_subtype from the rcb message as its
+*first 3 fields. The rqst_cpu fields indicates which remote processor originates
+*the request/release petition. When a particular resource is requested, some of
+*its parameters should be specify.
+*For devices like Gptimer and GPIO, the most significant attribute its itemID.
+*This value should be placed in the "fill9" field of the Rcb sruct. This field
+*should be fill by the requester if asking for a particular resource or by the
+*receiver if the resource granted is other than the one asked.
+*
+*Other variables related with the resource are:
+*"sem_hnd" which storage the semaphore handle associated in the ducati side.
+*We are pending on this semaphore when asked for the resource and
+*posted when granted.
+*"mod_base_addr". It is the virtual base addres for the resource.
+*"process_id". It is the Task Id where the petition for the resource was called.
+*
+*The last 16 bytes of the structure could be interpreted in 3 different ways
+*according to the context.
+*1) For the case of the Rcb is for SDMA. The last 16 bytes correspond to a array
+* of 16 channels[ ]. Each entry has the number of the SDMA channel granted.
+* As many number of channels indicated in num_chan as many are meaningful
+* in the channels[] array.
+*2) If the extd_mem_flag bit is NOT set the 16 last bytes are used as a data[]
+* array. Each entry is 4bytes long so the maximum number of entries is 4.
+*3) If the extd_mem_flag bit is NOT set the 16 last bytes are used as an array
+* datax[ ] 3 members Each entry 4bytes long and one additional field of
+* "extd_mem_hnd" which is a pointer to the continuation of this datax array
+*/
+
+#ifndef _IPU_PM_H_
+#define _IPU_PM_H_
+
+#include <linux/types.h>
+#include <linux/semaphore.h>
+#include <linux/workqueue.h>
+#include <linux/kfifo.h>
+
+/* Suspend/resume/other... */
+#define NUMBER_PM_EVENTS 4
+
+/* Processors id's */
+#define A9 3
+#define SYS_M3 2
+#define APP_M3 1
+#define TESLA 0
+
+/* If sysm3 or appm3 is requested ipu will be automatically requested
+ * this is beacause the cstrs can only be set to ipu and not individually.
+ * SYSM3 + APPM3 + IPU
+ */
+#define MAX_IPU_COUNT 3
+
+#define PM_CSTR_PERF_MASK 0x00000001
+#define PM_CSTR_LAT_MASK 0x00000002
+#define PM_CSTR_BW_MASK 0x00000004
+
+#define IPU_PM_MM_MPU_LAT_CONSTRAINT 10
+#define IPU_PM_NO_MPU_LAT_CONSTRAINT -1
+#define NO_FREQ_CONSTRAINT 0
+#define NO_LAT_CONSTRAINT -1
+#define NO_BW_CONSTRAINT -1
+
+#define RCB_SIZE 8
+
+#define DATA_MAX (RCB_SIZE - 4)
+#define DATAX_MAX (RCB_SIZE - 5)
+#define SDMA_CHANNELS_MAX 16
+#define I2C_BUS_MIN 1
+#define I2C_BUS_MAX 4
+#define REGULATOR_MIN 1
+#define REGULATOR_MAX 1
+
+#define AUX_CLK_MIN 0
+#define AUX_CLK_MAX 5
+#define NUM_AUX_CLK 6
+
+#define GP_TIMER_3 3
+#define GP_TIMER_4 4
+#define GP_TIMER_9 9
+#define GP_TIMER_11 11
+#define NUM_IPU_TIMERS 2
+
+#define I2C_SL_INVAL -1
+#define I2C_1_SL 0
+#define I2C_2_SL 1
+#define I2C_3_SL 2
+#define I2C_4_SL 3
+
+#define RCB_MIN 1
+#define RCB_MAX 32
+/* In some cases remote proc may need rcb's for internal
+ * use without requesting any resource, those need to be
+ * set as 0 in this mask in order to not release it.
+ * i.e. Ducati is using 0 to 4 (b00000011) rcb's for internal purpose
+ * without requestig any resource.
+ */
+#define RESERVED_RCBS 0xFFFFFFFE
+
+#define PM_RESOURCE 2
+#define PM_NOTIFICATION 3
+#define PM_SUCCESS 0
+#define PM_FAILURE -1
+#define PM_SHM_BASE_ADDR 0x9cff0000
+
+/* Auxiliar Clocks Registers */
+#define SCRM_BASE OMAP2_L4_IO_ADDRESS(0x4a30A000)
+#define SCRM_BASE_AUX_CLK 0x00000310
+#define SCRM_BASE_AUX_CLK_REQ 0x00000210
+#define SCRM_AUX_CLK_OFFSET 0x4
+/* Auxiliar Clocks bit fields */
+#define SCRM_AUX_CLK_POLARITY 0x0
+#define SCRM_AUX_CLK_SRCSELECT 0x1
+#define SCRM_AUX_CLK_ENABLE 0x8
+#define SCRM_AUX_CLK_CLKDIV 0x10
+/* Auxiliar Clocks Masks */
+#define SCRM_AUX_CLK_POLARITY_MASK 0x00000001
+#define SCRM_AUX_CLK_SRCSELECT_MASK 0x00000006
+#define SCRM_AUX_CLK_ENABLE_MASK 0x00000100
+#define SCRM_AUX_CLK_CLKDIV_MASK 0x000F0000
+/* Auxiliar Clocks Request bit fields */
+#define SCRM_AUX_CLK_REQ_POLARITY 0x0
+#define SCRM_AUX_CLK_REQ_ACCURACY 0x1
+#define SCRM_AUX_CLK_REQ_MAPPING 0x2
+/* Auxiliar Clocks Request Masks */
+#define SCRM_AUX_CLK_REQ_POLARITY_MASK 0x00000001
+#define SCRM_AUX_CLK_REQ_ACCURACY_MASK 0x00000002
+#define SCRM_AUX_CLK_REQ_MAPPING_MASK 0x0000001C
+/* Auxiliar Clocks/Req values */
+#define SYSTEM_SRC 0x0
+#define CORE_DPLL_SRC 0x1
+#define PER_DPLL_CLK 0x2
+#define POL_GAT_LOW 0x0
+#define POL_GAT_HIGH 0x1
+#define AUX_CLK_DIS 0x0
+#define AUX_CLK_ENA 0x1
+/* ISS OPT Clocks */
+#define OPTFCLKEN (1 << 8)
+#define CAM_ENABLED 0x2
+#define CAM_DISABLED 0x0
+
+/* Macro to set a val in a bitfield*/
+#define MASK_SET_FIELD(tmp, bitfield, val) { \
+ tmp |= \
+ ((val << SCRM_##bitfield)\
+ & SCRM_##bitfield##_MASK);\
+ }
+
+/* Macro to clear a bitfield*/
+#define MASK_CLEAR_FIELD(tmp, bitfield) { \
+ tmp &= \
+ (~SCRM_##bitfield##_MASK);\
+ }
+
+/* Macro to return the address of the aux clk */
+#define AUX_CLK_REG(clk) (SCRM_BASE + (SCRM_BASE_AUX_CLK + \
+ (SCRM_AUX_CLK_OFFSET * clk)))
+
+/* Macro to return the address of the aux clk req */
+#define AUX_CLK_REG_REQ(clk) (SCRM_BASE + (SCRM_BASE_AUX_CLK_REQ + \
+ (SCRM_AUX_CLK_OFFSET * clk)))
+
+/*
+ * IPU_PM_MODULEID
+ * Unique module ID
+ */
+#define IPU_PM_MODULEID (0x6A6A)
+
+/* A9 state flag 0000 | 0000 Ducati internal use*/
+#define SYS_PROC_DOWN 0x00010000
+#define APP_PROC_DOWN 0x00020000
+#define ENABLE_IPU_HIB 0x00000040
+#define SYS_PROC_HIB 0x00000001
+#define APP_PROC_HIB 0x00000002
+#define HIB_REF_MASK 0x00000F80
+
+#define SYS_PROC_IDLING 0x00000001
+#define APP_PROC_IDLING 0x00000002
+
+#define SYS_PROC_LOADED 0x00000010
+#define APP_PROC_LOADED 0x00000020
+#define IPU_PROC_LOADED 0x00000030
+#define PROC_LD_SHIFT 4u
+
+#define IPU_PROC_IDLING 0x0000c000
+#define IPU_IDLING_SHIFT 14u
+
+#define SYS_IDLING_BIT 14
+#define APP_IDLING_BIT 15
+
+#define SYS_LOADED_BIT 4
+#define APP_LOADED_BIT 5
+
+#define ONLY_APPM3_IDLE 0x2
+#define ONLY_SYSM3_IDLE 0x1
+#define ALL_CORES_IDLE 0x3
+#define WAIT_FOR_IDLE_TIMEOUT 40u
+
+/* Macro to make a correct module magic number with refCount */
+#define IPU_PM_MAKE_MAGICSTAMP(x) ((IPU_PM_MODULEID << 12u) | (x))
+
+enum pm_failure_codes{
+ PM_INSUFFICIENT_CHANNELS = 1,
+ PM_NO_GPTIMER,
+ PM_NO_GPIO,
+ PM_NO_I2C,
+ PM_NO_REGULATOR,
+ PM_REGULATOR_IN_USE,
+ PM_INVAL_RCB_NUM,
+ PM_INVAL_NUM_CHANNELS,
+ PM_INVAL_NUM_I2C,
+ PM_INVAL_REGULATOR,
+ PM_NOT_INSTANTIATED,
+ PM_UNSUPPORTED,
+ PM_NO_AUX_CLK,
+ PM_INVAL_AUX_CLK
+};
+
+enum pm_msgtype_codes{PM_FAIL,
+ PM_NULLMSG,
+ PM_ACKNOWLEDGEMENT,
+ PM_REQUEST_RESOURCE,
+ PM_RELEASE_RESOURCE,
+ PM_NOTIFICATIONS,
+ PM_ENABLE_RESOURCE,
+ PM_WRITE_RESOURCE,
+ PM_READ_RESOURCE,
+ PM_DISABLE_RESOURCE,
+ PM_REQUEST_CONSTRAINTS,
+ PM_RELEASE_CONSTRAINTS,
+ PM_NOTIFY_HIBERNATE
+};
+
+enum pm_regulator_action{PM_SET_VOLTAGE,
+ PM_SET_CURRENT,
+ PM_SET_MODE,
+ PM_GET_MODE,
+ PM_GET_CURRENT,
+ PM_GET_VOLTAGE
+};
+
+/* Resources id should start at zero,
+ * should be always consecutive and should match
+ * IPU side.
+ */
+#define PM_FIRST_RES 0
+
+/* Resources that can handle cstrs should be
+ * consecutive and first in the res_type enum
+ */
+#define PM_NUM_RES_W_CSTRS 10
+
+enum res_type{
+ FDIF = PM_FIRST_RES,
+ IPU,
+ SYSM3,
+ APPM3,
+ ISS,
+ IVA_HD,
+ IVASEQ0,
+ IVASEQ1,
+ L3_BUS,
+ MPU,
+ /* SL2IF, */
+ /* DSP, */
+ SDMA,
+ GP_TIMER,
+ GP_IO,
+ I2C,
+ REGULATOR,
+ AUX_CLK,
+ PM_NUM_RES
+};
+
+/* Events should start at zero and
+ * should be always consecutive
+ */
+#define PM_FIRST_EVENT 0
+
+enum pm_event_type{
+ PM_SUSPEND = PM_FIRST_EVENT,
+ PM_RESUME,
+ PM_PID_DEATH,
+ PM_HIBERNATE,
+ PM_ALIVE,
+ PM_LAST_EVENT
+};
+
+
+enum pm_hib_timer_event{
+ PM_HIB_TIMER_RESET,
+ PM_HIB_TIMER_OFF,
+ PM_HIB_TIMER_ON,
+ PM_HIB_TIMER_WDRESET,
+ PM_HIB_TIMER_EXPIRE
+};
+
+#define PM_HIB_DEFAULT_TIME 5000 /* 5 SEC */
+#define PM_HIB_WDT_TIME 3000 /* 3 SEC */
+
+struct rcb_message {
+ unsigned rcb_flag:1;
+ unsigned rcb_num:6;
+ unsigned reply_flag:1;
+ unsigned msg_type:4;
+ unsigned msg_subtype:4;
+ unsigned parm:16;
+};
+
+union message_slicer {
+ struct rcb_message fields;
+ int whole;
+};
+
+struct ipu_pm_override {
+ unsigned hibernateAllowed:1;
+ unsigned retentionAllowed:1;
+ unsigned inactiveAllowed:1;
+ unsigned cmAutostateAllowed:1;
+ unsigned deepSleepAllowed:1;
+ unsigned wfiAllowed:1;
+ unsigned idleAllowed:1;
+ unsigned reserved:24;
+ unsigned highbit:1;
+};
+
+struct rcb_block {
+ unsigned rcb_num:6;
+ unsigned msg_type:4;
+ unsigned sub_type:4;
+ unsigned rqst_cpu:4;
+ unsigned extd_mem_flag:1;
+ unsigned num_chan:4;
+ unsigned fill9:9;
+
+ unsigned process_id;
+ unsigned *sem_hnd;
+ unsigned mod_base_addr;
+ union {
+ unsigned int data[DATA_MAX];
+ struct {
+ unsigned datax[DATAX_MAX];
+ unsigned extd_mem_hnd;
+ };
+ unsigned char channels[SDMA_CHANNELS_MAX];
+ };
+};
+
+struct sms {
+ unsigned rat;
+ unsigned pm_version;
+ unsigned gp_msg;
+ unsigned state_flag;
+ struct ipu_pm_override pm_flags;
+ unsigned hib_time;
+ struct rcb_block rcb[RCB_MAX];
+};
+
+struct pm_event {
+ enum pm_event_type event_type;
+ struct semaphore sem_handle;
+ int pm_msg;
+};
+
+struct ipu_pm_params {
+ int pm_fdif_counter;
+ int pm_ipu_counter;
+ int pm_sys_m3_counter;
+ int pm_app_m3_counter;
+ int pm_iss_counter;
+ int pm_iva_hd_counter;
+ int pm_ivaseq0_counter;
+ int pm_ivaseq1_counter;
+ int pm_sl2if_counter;
+ int pm_l3_bus_counter;
+ int pm_mpu_counter;
+ int pm_sdmachan_counter;
+ int pm_gptimer_counter;
+ int pm_gpio_counter;
+ int pm_i2c_bus_counter;
+ int pm_regulator_counter;
+ int pm_aux_clk_counter;
+ int timeout;
+ void *shared_addr;
+ int shared_addr_size;
+ int pm_num_events;
+ int pm_resource_event;
+ int pm_notification_event;
+ int proc_id;
+ int remote_proc_id;
+ int line_id;
+ void *gate_mp;
+ int hib_timer_state;
+ int wdt_time;
+};
+
+/* This structure defines attributes for initialization of the ipu_pm module. */
+struct ipu_pm_config {
+ u32 reserved;
+};
+
+/* Defines the ipu_pm state object, which contains all the module
+ * specific information. */
+struct ipu_pm_module_object {
+ atomic_t ref_count;
+ /* Reference count */
+ struct ipu_pm_config cfg;
+ /* ipu_pm configuration structure */
+ struct ipu_pm_config def_cfg;
+ /* Default module configuration */
+ struct mutex *gate_handle;
+ /* Handle of gate to be used for local thread safety */
+ bool is_setup;
+ /* Indicates whether the ipu_pm module is setup. */
+};
+
+/* Store the payload and processor id for the wq */
+struct ipu_pm_msg {
+ u16 proc_id;
+ int pm_msg;
+};
+
+/* ipu_pm handle one for each proc SYSM3/APPM3 */
+struct ipu_pm_object {
+ struct sms *rcb_table;
+ struct pm_event *pm_event;
+ struct ipu_pm_params *params;
+ struct work_struct work;
+ struct kfifo fifo;
+ spinlock_t lock;
+ struct omap_dm_timer *dmtimer;
+};
+
+/* Function for PM resources Callback */
+void ipu_pm_callback(u16 proc_id, u16 line_id, u32 event_id,
+ uint *arg, u32 payload);
+
+/* Function for PM notifications Callback */
+void ipu_pm_notify_callback(u16 proc_id, u16 line_id, u32 event_id,
+ uint *arg, u32 payload);
+
+/* Function for send PM Notifications */
+int ipu_pm_notifications(int proc_id, enum pm_event_type event, void *data);
+
+/* Function to set init parameters */
+void ipu_pm_params_init(struct ipu_pm_params *params);
+
+/* Function to calculate ipu pm mem */
+int ipu_pm_mem_req(const struct ipu_pm_params *params);
+
+/* Function to config ipu_pm module */
+void ipu_pm_get_config(struct ipu_pm_config *cfg);
+
+/* Function to set up ipu_pm module */
+int ipu_pm_setup(struct ipu_pm_config *cfg);
+
+/* Function to create ipu pm object */
+struct ipu_pm_object *ipu_pm_create(const struct ipu_pm_params *params);
+
+/* Function to delete ipu pm object */
+void ipu_pm_delete(struct ipu_pm_object *handle);
+
+/* Function to destroy ipu_pm module */
+int ipu_pm_destroy(void);
+
+/* Function to attach ipu_pm module */
+int ipu_pm_attach(u16 remote_proc_id, void *shared_addr);
+
+/* Function to deattach ipu_pm module */
+int ipu_pm_detach(u16 remote_proc_id);
+
+/* Function to register the ipu_pm events */
+int ipu_pm_init_transport(struct ipu_pm_object *handle);
+
+/* Function to get ipu pm object */
+struct ipu_pm_object *ipu_pm_get_handle(int proc_id);
+
+/* Function to save a processor from hibernation */
+int ipu_pm_save_ctx(int proc_id);
+
+/* Function to restore a processor from hibernation */
+int ipu_pm_restore_ctx(int proc_id);
+
+/* Function to start a module */
+int ipu_pm_module_start(unsigned res_type);
+
+/* Function to stop a module */
+int ipu_pm_module_stop(unsigned res_type);
+
+/* Function to set a module's frequency constraint */
+int ipu_pm_module_set_rate(unsigned rsrc, unsigned target_rsrc, unsigned rate);
+
+/* Function to set a module's latency constraint */
+int ipu_pm_module_set_latency(unsigned rsrc, unsigned target_rsrc, int latency);
+
+/* Function to set a module's bandwidth constraint */
+int ipu_pm_module_set_bandwidth(unsigned rsrc,
+ unsigned target_rsrc,
+ int bandwidth);
+
+/* Function to get ducati state flag from share memory */
+u32 ipu_pm_get_state(int proc_id);
+
+/* Function to register notifier from devh module */
+int ipu_pm_register_notifier(struct notifier_block *nb);
+
+/* Function to unregister notifier from devh module */
+int ipu_pm_unregister_notifier(struct notifier_block *nb);
+
+#endif
diff --git a/drivers/dsp/syslink/multicore_ipc/Kbuild b/drivers/dsp/syslink/multicore_ipc/Kbuild
new file mode 100644
index 00000000000..fc5c28d0102
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/Kbuild
@@ -0,0 +1,35 @@
+libsyslink_ipc = multiproc.o multiproc_ioctl.o nameserver.o \
+nameserver_ioctl.o nameserver_remote.o nameserver_remotenotify.o \
+listmp.o listmp_ioctl.o sharedregion.o sharedregion_ioctl.o \
+gate.o gatepeterson.o gatehwspinlock.o gatemp.o gatemp_ioctl.o \
+heap.o heapmemmp.o heapmemmp_ioctl.o heapbufmp.o heapbufmp_ioctl.o \
+messageq.o messageq_ioctl.o transportshm.o transportshm_setup.o \
+platform.o ipc.o sysipc_ioctl.o ipc_ioctl.o ipc_drv.o \
+../omap_notify/notify_driver.o ../omap_notify/notify.o \
+../omap_notify/drv_notify.o ../omap_notify/plat/omap4_notify_setup.o \
+../notify_ducatidriver/notify_ducati.o ../ipu_pm/ipu_pm.o
+
+libsyslink_platform = platform_mem.o
+
+obj-$(CONFIG_MPU_SYSLINK_IPC) += syslink_ipc.o
+syslink_ipc-objs = $(libservices) $(libsyslink_ipc)
+
+obj-$(CONFIG_MPU_SYSLINK_PLATFORM) += syslink_platform.o
+syslink_platform-objs = $(libservices) $(libsyslink_platform)
+
+ccflags-y += -Wno-strict-prototypes
+
+#Enable ipu_pm debug traces
+ifeq ($(CONFIG_SYSLINK_IPU_PM_TRACES),y)
+CFLAGS_ipu_pm.o := -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 \
+ -DCONFIG_DISABLE_BRIDGE_PM -DDSP_TRACEBUF_DISABLED
+
+#Header files
+ccflags-y += -Iarch/arm/plat-omap/include
+ccflags-y += -Iarch/arm/plat-omap/include/syslink
diff --git a/drivers/dsp/syslink/multicore_ipc/gate.c b/drivers/dsp/syslink/multicore_ipc/gate.c
new file mode 100644
index 00000000000..066ef53a37b
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/gate.c
@@ -0,0 +1,69 @@
+/*
+ * gatemp.c
+ *
+ * Gate wrapper implementation
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+
+/* Standard headers */
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+/* Module level headers */
+#include <igateprovider.h>
+#include <gate.h>
+
+
+/* Structure defining internal object for the Gate Peterson.*/
+struct gate_object {
+ IGATEPROVIDER_SUPEROBJECT; /* For inheritance from IGateProvider */
+};
+
+/* Function to enter a Gate */
+int *gate_enter_system(void)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ return (int *)flags;
+}
+
+/* Function to leave a gate */
+void gate_leave_system(int *key)
+{
+ local_irq_restore((unsigned long) key);
+}
+
+/* Match with IGateProvider */
+static inline int *_gate_enter_system(struct gate_object *obj)
+{
+ (void) obj;
+ return gate_enter_system();
+}
+
+/* Match with IGateProvider */
+static inline void _gate_leave_system(struct gate_object *obj, int *key)
+{
+ (void) obj;
+ gate_leave_system(key);
+}
+
+static struct gate_object gate_system_object = {
+ .enter = (int *(*)(void *))_gate_enter_system,
+ .leave = (void (*)(void *, int *))_gate_leave_system,
+};
+
+struct igateprovider_object *gate_system_handle = \
+ (struct igateprovider_object *)&gate_system_object;
diff --git a/drivers/dsp/syslink/multicore_ipc/gate_remote.c b/drivers/dsp/syslink/multicore_ipc/gate_remote.c
new file mode 100644
index 00000000000..cc519d535bc
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/gate_remote.c
@@ -0,0 +1,39 @@
+/*
+ * gate_remote.c
+ *
+ * This includes the functions to handle remote gates
+ *
+ * Copyright (C) 2008-2009 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 <linux/types.h>
+
+/*
+ * ======== gate_remote_enter ========
+ * Purpose:
+ * This function is used to enter in to a remote gate
+ */
+int gate_remote_enter(void *ghandle)
+{
+ return 0;
+}
+
+/*
+ * ======== gate_remote_leave ========
+ * Purpose:
+ * This function is used to leave from a remote gate
+ */
+int gate_remote_leave(void *ghandle, u32 key)
+{
+ key = 0;
+ return 0;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/gatehwspinlock.c b/drivers/dsp/syslink/multicore_ipc/gatehwspinlock.c
new file mode 100644
index 00000000000..57b53ad050e
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/gatehwspinlock.c
@@ -0,0 +1,563 @@
+/*
+ * gatehwspinlock.c
+ *
+ * Hardware-based spinlock gate for mutual exclusion of shared memory.
+ *
+ * Copyright (C) 2008-2009 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 <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <plat/hwspinlock.h>
+
+#include <syslink/atomic_linux.h>
+#include <multiproc.h>
+#include <sharedregion.h>
+#include <gatemp.h>
+#include <igatempsupport.h>
+#include <igateprovider.h>
+#include <iobject.h>
+#include <gatehwspinlock.h>
+
+
+/* =============================================================================
+ * Macros
+ * =============================================================================
+ */
+
+/* Macro to make a correct module magic number with refCount */
+#define GATEHWSPINLOCK_MAKE_MAGICSTAMP(x) ((GATEHWSPINLOCK_MODULEID << 12u) \
+ | (x))
+/*
+ * structure for gatehwspinlock module state
+ */
+struct gatehwspinlock_module_object {
+ atomic_t ref_count; /* Reference count */
+ struct gatehwspinlock_config cfg;
+ struct gatehwspinlock_config default_cfg;
+ struct gatehwspinlock_params def_inst_params; /* default instance
+ paramters */
+ u32 *base_addr; /* Base address of lock registers */
+ u32 num_locks; /* Maximum number of locks */
+ u32 num_reserved; /* Number of reserved locks */
+ struct hwspinlock **hw_lock_handles;
+ /* Array of hwspinlock handles controlled by gatemp */
+};
+
+/*
+ * Structure defining object for the Gate Spinlock
+ */
+struct gatehwspinlock_object {
+ IGATEPROVIDER_SUPEROBJECT; /* For inheritance from IGateProvider */
+ IOBJECT_SUPEROBJECT; /* For inheritance for IObject */
+ u32 lock_num;
+ u32 nested;
+ void *local_gate;
+ struct hwspinlock *hwhandle;
+};
+
+/*
+ * Variable for holding state of the gatehwspinlock module
+ */
+static struct gatehwspinlock_module_object gatehwspinlock_state = {
+ .default_cfg.default_protection = \
+ gatehwspinlock_LOCALPROTECT_INTERRUPT,
+ .default_cfg.num_locks = 32u,
+ .def_inst_params.shared_addr = NULL,
+ .def_inst_params.resource_id = 0x0,
+ .def_inst_params.region_id = 0x0,
+ .hw_lock_handles = NULL,
+ .num_locks = 32u,
+ .num_reserved = 5
+ /* GateMP controls SpinLocks 5-31. 0-3 are reserved for usage by I2C */
+ /* SpinLock 4 is for ipu_pm module usage */
+};
+
+static struct gatehwspinlock_module_object *gatehwspinlock_module =
+ &gatehwspinlock_state;
+
+/* =============================================================================
+ * Internal functions
+ * =============================================================================
+ */
+
+/* TODO: figure these out */
+#define gate_enter_system() (int *)0
+#define gate_leave_system(key) {}
+
+/* =============================================================================
+ * APIS
+ * =============================================================================
+ */
+/*
+ * ======== gatehwspinlock_get_config ========
+ * Purpose:
+ * This will get the default configuration parameters for gatehwspinlock
+ * module
+ */
+void gatehwspinlock_get_config(struct gatehwspinlock_config *config)
+{
+ int *key = NULL;
+
+ if (WARN_ON(config == NULL))
+ goto exit;
+
+ key = gate_enter_system();
+ if (atomic_cmpmask_and_lt(&(gatehwspinlock_module->ref_count),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(0),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(1)) == true)
+ memcpy(config, &gatehwspinlock_module->default_cfg,
+ sizeof(struct gatehwspinlock_config));
+ else
+ memcpy(config, &gatehwspinlock_module->cfg,
+ sizeof(struct gatehwspinlock_config));
+ gate_leave_system(key);
+
+exit:
+ return;
+}
+EXPORT_SYMBOL(gatehwspinlock_get_config);
+
+/*
+ * ======== gatehwspinlock_setup ========
+ * Purpose:
+ * This will setup the gatehwspinlock module
+ */
+int gatehwspinlock_setup(const struct gatehwspinlock_config *config)
+{
+ struct gatehwspinlock_config tmp_cfg;
+ int *key = NULL;
+ struct hwspinlock *lock_handle;
+ int i;
+ s32 retval;
+
+ key = gate_enter_system();
+
+ /* This sets the ref_count variable not initialized, upper 16 bits is
+ * written with module _id to ensure correctness of ref_count variable
+ */
+ atomic_cmpmask_and_set(&gatehwspinlock_module->ref_count,
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(0),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(0));
+
+ if (atomic_inc_return(&gatehwspinlock_module->ref_count)
+ != GATEHWSPINLOCK_MAKE_MAGICSTAMP(1)) {
+ gate_leave_system(key);
+ return 1;
+ }
+
+ if (config == NULL) {
+ gatehwspinlock_get_config(&tmp_cfg);
+ config = &tmp_cfg;
+ }
+ gate_leave_system(key);
+
+ gatehwspinlock_module->hw_lock_handles = kzalloc(
+ gatehwspinlock_module->num_locks * sizeof(struct hwspinlock *),
+ GFP_KERNEL);
+ if (gatehwspinlock_module->hw_lock_handles == NULL) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ memcpy(&gatehwspinlock_module->cfg, config,
+ sizeof(struct gatehwspinlock_config));
+
+ gatehwspinlock_module->base_addr = (void *)config->base_addr;
+ gatehwspinlock_module->num_locks = config->num_locks;
+ for (i = gatehwspinlock_module->num_reserved;
+ i < gatehwspinlock_module->num_locks; i++) {
+ lock_handle = hwspinlock_request_specific(i);
+ if (lock_handle == NULL) {
+ retval = -EBUSY;
+ pr_err("hwspinlock_request failed for"
+ "id = %d", i);
+ goto spinlock_request_fail;
+ }
+ gatehwspinlock_module->hw_lock_handles[i] = lock_handle;
+ }
+ return 0;
+
+spinlock_request_fail:
+ for (i--; i >= gatehwspinlock_module->num_reserved; i--) {
+ hwspinlock_free(gatehwspinlock_module->hw_lock_handles[i]);
+ gatehwspinlock_module->hw_lock_handles[i] = NULL;
+ }
+exit:
+ kfree(gatehwspinlock_module->hw_lock_handles);
+ atomic_dec_return(&gatehwspinlock_module->ref_count);
+ if (retval < 0)
+ pr_err("gatehwspinlock_setup failed! status = 0x%x", retval);
+ return retval;
+}
+EXPORT_SYMBOL(gatehwspinlock_setup);
+
+/*
+ * ======== gatehwspinlock_destroy ========
+ * Purpose:
+ * This will destroy the gatehwspinlock module
+ */
+int gatehwspinlock_destroy(void)
+{
+ s32 retval = 0;
+ int *key = NULL;
+ struct hwspinlock *lock_handle;
+ int i;
+
+ key = gate_enter_system();
+
+ if (atomic_cmpmask_and_lt(&(gatehwspinlock_module->ref_count),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(0),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (!(atomic_dec_return(&gatehwspinlock_module->ref_count)
+ == GATEHWSPINLOCK_MAKE_MAGICSTAMP(0))) {
+ gate_leave_system(key);
+ retval = 1;
+ goto exit;
+ }
+ gate_leave_system(key);
+
+ for (i = gatehwspinlock_module->num_reserved;
+ i < gatehwspinlock_module->num_locks; i++) {
+ lock_handle = gatehwspinlock_module->hw_lock_handles[i];
+ retval = hwspinlock_free(lock_handle);
+ if (retval < 0)
+ pr_err("hwspinlock_free failed for id = %d", i);
+ gatehwspinlock_module->hw_lock_handles[i] = NULL;
+ }
+ memset(&gatehwspinlock_module->cfg, 0,
+ sizeof(struct gatehwspinlock_config));
+ kfree(gatehwspinlock_module->hw_lock_handles);
+ gatehwspinlock_module->hw_lock_handles = NULL;
+ return 0;
+
+exit:
+ if (retval < 0)
+ pr_err("gatehwspinlock_destroy failed status:%x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(gatehwspinlock_destroy);
+
+/*
+ * ======== gatehwspinlock_get_num_instances ========
+ * Purpose:
+ * Function to return the number of instances configured in the module.
+ */
+u32 gatehwspinlock_get_num_instances(void)
+{
+ return gatehwspinlock_module->num_locks;
+}
+EXPORT_SYMBOL(gatehwspinlock_get_num_instances);
+
+/*
+ * ======== gatehwspinlock_get_num_reserved ========
+ * Purpose:
+ * Function to return the number of instances not under GateMP's control.
+ */
+u32 gatehwspinlock_get_num_reserved(void)
+{
+ return gatehwspinlock_module->num_reserved;
+}
+EXPORT_SYMBOL(gatehwspinlock_get_num_reserved);
+
+/*
+ * ======== gatepeterson_locks_init ========
+ * Purpose:
+ * Function to initialize the locks.
+ */
+void gatehwspinlock_locks_init(void)
+{
+ u32 i;
+
+ for (i = 0; i < gatehwspinlock_module->num_locks; i++)
+ gatehwspinlock_module->base_addr[i] = 0;
+}
+EXPORT_SYMBOL(gatehwspinlock_locks_init);
+
+/*
+ * ======== gatehwspinlock_params_init ========
+ * Purpose:
+ * This will Initialize this config-params structure with
+ * supplier-specified defaults before instance creation
+ */
+void gatehwspinlock_params_init(struct gatehwspinlock_params *params)
+{
+ int *key = NULL;
+
+ key = gate_enter_system();
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(gatehwspinlock_module->ref_count),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(0),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(1)) == true))
+ goto exit;
+ if (WARN_ON(params == NULL))
+ goto exit;
+
+ gate_leave_system(key);
+ memcpy(params, &(gatehwspinlock_module->def_inst_params),
+ sizeof(struct gatehwspinlock_params));
+ return;
+
+exit:
+ gate_leave_system(key);
+ return;
+}
+EXPORT_SYMBOL(gatehwspinlock_params_init);
+
+/*
+ * ======== gatehwspinlock_create ========
+ * Purpose:
+ * This will creates a new instance of gatehwspinlock module
+ */
+void *gatehwspinlock_create(enum igatempsupport_local_protect local_protect,
+ const struct gatehwspinlock_params *params)
+{
+ void *handle = NULL;
+ struct gatehwspinlock_object *obj = NULL;
+ s32 retval = 0;
+
+ if (atomic_cmpmask_and_lt(&(gatehwspinlock_module->ref_count),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(0),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(params == NULL)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(params->shared_addr == NULL)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ obj = kzalloc(sizeof(struct gatehwspinlock_object), GFP_KERNEL);
+ if (obj == NULL) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ IGATEPROVIDER_OBJECTINITIALIZER(obj, gatehwspinlock);
+
+ /* Create the local gate */
+ obj->local_gate =
+ gatemp_create_local((enum gatemp_local_protect)local_protect);
+ if (obj->local_gate == NULL) {
+ retval = GATEHWSPINLOCK_E_FAIL;
+ goto free_obj;
+ }
+
+ obj->lock_num = params->resource_id;
+ obj->nested = 0;
+ obj->hwhandle = \
+ gatehwspinlock_module->hw_lock_handles[params->resource_id];
+ if (obj->hwhandle == NULL) {
+ retval = -EBUSY;
+ pr_err("hwspinlock_request failed for id = %d",
+ params->resource_id);
+ goto free_obj;
+ }
+ handle = obj;
+ return handle;
+
+free_obj:
+ kfree(obj);
+exit:
+ pr_err("gatehwspinlock_create failed status: %x\n", retval);
+ return NULL;
+}
+EXPORT_SYMBOL(gatehwspinlock_create);
+
+/*
+ * ======== gatehwspinlock_delete ========
+ * Purpose:
+ * This will deletes an instance of gatehwspinlock module
+ */
+int gatehwspinlock_delete(void **gphandle)
+
+{
+ struct gatehwspinlock_object *obj = NULL;
+ s32 retval;
+
+ if (atomic_cmpmask_and_lt(&(gatehwspinlock_module->ref_count),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(0),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(gphandle == NULL)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(*gphandle == NULL)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct gatehwspinlock_object *)(*gphandle);
+
+ /* No need to delete the local gate, as it is gatemp module wide
+ * local mutex. */
+ obj->hwhandle = NULL;
+ kfree(obj);
+ *gphandle = NULL;
+
+ return 0;
+
+exit:
+ pr_err("gatehwspinlock_delete failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(gatehwspinlock_delete);
+
+
+/*
+ * ======== gatehwspinlock_enter ========
+ * Purpose:
+ * This will enters the gatehwspinlock instance
+ */
+int *gatehwspinlock_enter(void *gphandle)
+{
+ struct gatehwspinlock_object *obj = NULL;
+ s32 retval = 0;
+ int *key = NULL;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(gatehwspinlock_module->ref_count),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(0),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(gphandle == NULL)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct gatehwspinlock_object *)gphandle;
+
+ /* Enter local gate */
+ if (obj->local_gate != NULL) {
+ retval = mutex_lock_interruptible(
+ (struct mutex *)obj->local_gate);
+ if (retval)
+ goto exit;
+ }
+
+ /* If the gate object has already been entered, return the nested
+ * value */
+ obj->nested++;
+ if (obj->nested > 1)
+ return key;
+
+ /* Enter the spinlock */
+ retval = hwspinlock_lock(obj->hwhandle);
+ if (retval < 0) {
+ obj->nested--;
+ mutex_unlock((struct mutex *)obj->local_gate);
+ }
+
+exit:
+ if (retval < 0)
+ pr_err("gatehwspinlock_enter failed! status = 0x%x", retval);
+ return key;
+}
+EXPORT_SYMBOL(gatehwspinlock_enter);
+
+/*
+ * ======== gatehwspinlock_leave ========
+ * Purpose:
+ * This will leaves the gatehwspinlock instance
+ */
+void gatehwspinlock_leave(void *gphandle, int *key)
+{
+ struct gatehwspinlock_object *obj = NULL;
+ s32 retval = 0;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(gatehwspinlock_module->ref_count),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(0),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(gphandle == NULL)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct gatehwspinlock_object *)gphandle;
+ obj->nested--;
+ /* Leave the spinlock if the leave() is not nested */
+ if (obj->nested == 0) {
+ retval = hwspinlock_unlock(obj->hwhandle);
+ if (retval < 0) {
+ obj->nested++;
+ goto exit;
+ }
+ }
+ /* Leave local gate */
+ mutex_unlock(obj->local_gate);
+
+exit:
+ if (retval < 0)
+ pr_err("gatehwspinlock_leave failed! status = 0x%x", retval);
+ return;
+}
+EXPORT_SYMBOL(gatehwspinlock_leave);
+
+/*
+ * ======== gatehwspinlock_get_resource_id ========
+ */
+static u32 gatehwspinlock_get_resource_id(void *handle)
+{
+ struct gatehwspinlock_object *obj = NULL;
+ s32 retval = 0;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(gatehwspinlock_module->ref_count),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(0),
+ GATEHWSPINLOCK_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(handle == NULL)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct gatehwspinlock_object *)handle;
+
+ return obj->lock_num;
+
+exit:
+ pr_err("gatehwspinlock_get_resource_id failed status: %x\n", retval);
+ return (u32)-1;
+}
+EXPORT_SYMBOL(gatehwspinlock_get_resource_id);
+
+/*
+ * ======== gatehwspinlock_shared_memreq ========
+ * Purpose:
+ * This will give the amount of shared memory required
+ * for creation of each instance
+ */
+u32 gatehwspinlock_shared_mem_req(const struct gatehwspinlock_params *params)
+{
+ return 0;
+}
+EXPORT_SYMBOL(gatehwspinlock_shared_mem_req);
diff --git a/drivers/dsp/syslink/multicore_ipc/gatemp.c b/drivers/dsp/syslink/multicore_ipc/gatemp.c
new file mode 100644
index 00000000000..a9e47eff911
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/gatemp.c
@@ -0,0 +1,1858 @@
+/*
+ * gatemp.c
+ *
+ * Gate wrapper implementation
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+/* Standard headers */
+#include <linux/types.h>
+
+/* Utilities headers */
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/semaphore.h>
+
+/* Syslink utilities headers */
+#include <syslink/atomic_linux.h>
+
+/* Syslink module headers */
+#include <multiproc.h>
+#include <igateprovider.h>
+#include <igatempsupport.h>
+#include <iobject.h>
+#include <gate.h>
+/*#include <memory.h>
+#include <bitops.h>
+#include <ti/syslink/utils/Cache.h>
+*/
+#include <nameserver.h>
+#include <sharedregion.h>
+
+/* Module level headers */
+#include <gatemp.h>
+#include <gatemp.h>
+#include <gatempdefs.h>
+
+
+/* -----------------------------------------------------------------------------
+ * Macros
+ * -----------------------------------------------------------------------------
+ */
+/* VERSION */
+#define GATEMP_VERSION (1)
+
+/* CREATED */
+#define GATEMP_CREATED (0x11202009)
+
+/* PROXYORDER_SYSTEM */
+#define GATEMP_PROXYORDER_SYSTEM (0)
+
+/* PROXYORDER_CUSTOM1 */
+#define GATEMP_PROXYORDER_CUSTOM1 (1)
+
+/* PROXYORDER_CUSTOM2 */
+#define GATEMP_PROXYORDER_CUSTOM2 (2)
+
+/* PROXYORDER_NUM */
+#define GATEMP_PROXYORDER_NUM (3)
+
+/* Macro to make a correct module magic number with refCount */
+#define GATEMP_MAKE_MAGICSTAMP(x) \
+ ((GATEMP_MODULEID << 12u) | (x))
+
+/* Helper macros */
+#define GETREMOTE(mask) ((enum gatemp_remote_protect)(mask >> 8))
+#define GETLOCAL(mask) ((enum gatemp_local_protect)(mask & 0xFF))
+#define SETMASK(remote_protect, local_protect) \
+ ((u32)(remote_protect << 8 | local_protect))
+
+
+/* Name of the reserved NameServer used for GateMP. */
+#define GATEMP_NAMESERVER "GateMP"
+
+#define ROUND_UP(a, b) (((a) + ((b) - 1)) & (~((b) - 1)))
+
+#define Gate_enterSystem() (int *)0
+
+#define Gate_leaveSystem(key) (void)0
+
+/* -----------------------------------------------------------------------------
+ * Structs & Enums
+ * -----------------------------------------------------------------------------
+ */
+/* Attrs */
+struct gatemp_attrs {
+ u16 mask;
+ u16 creator_proc_id;
+ u32 arg;
+ u32 status;
+};
+
+/* Structure defining state of GateMP Module */
+struct gatemp_module_state {
+ void *name_server;
+ int num_remote_system;
+ int num_remote_custom1;
+ int num_remote_custom2;
+ int num_remote_system_reserved;
+ int num_remote_custom1_reserved;
+ int num_remote_custom2_reserved;
+ u8 *remote_system_in_use_alloc;
+ u8 *remote_custom1_in_use_alloc;
+ u8 *remote_custom2_in_use_alloc;
+ void **remote_system_gates_alloc;
+ void **remote_custom1_gates_alloc;
+ void **remote_custom2_gates_alloc;
+ u8 *remote_system_in_use;
+ u8 *remote_custom1_in_use;
+ u8 *remote_custom2_in_use;
+ void **remote_system_gates;
+ void **remote_custom1_gates;
+ void **remote_custom2_gates;
+ struct igateprovider_object *gate_hwi;
+ struct mutex *gate_mutex;
+ struct igateprovider_object *gate_null;
+ struct gatemp_object *default_gate;
+ int proxy_map[GATEMP_PROXYORDER_NUM];
+ atomic_t ref_count;
+ struct gatemp_config cfg;
+ /* Current config values */
+ struct gatemp_config default_cfg;
+ /* default config values */
+ struct gatemp_params def_inst_params;
+ /* default instance paramters */
+ bool is_owner;
+ /* Indicates if this processor is the owner */
+ atomic_t attach_ref_count;
+ /* Attach/detach reference count */
+};
+
+/* Structure defining instance of GateMP Module */
+struct gatemp_object {
+ IGATEPROVIDER_SUPEROBJECT; /* For inheritance from IGateProvider */
+ IOBJECT_SUPEROBJECT; /* For inheritance for IObject */
+ enum gatemp_remote_protect remote_protect;
+ enum gatemp_local_protect local_protect;
+ void *ns_key;
+ int num_opens;
+ u16 creator_proc_id;
+ bool cache_enabled;
+ struct gatemp_attrs *attrs;
+ u16 region_id;
+ uint alloc_size;
+ void *proxy_attrs;
+ u32 resource_id;
+ void *gate_handle;
+ enum ipc_obj_type obj_type; /* from shared region? */
+};
+
+/* Reserved */
+struct gatemp_reserved {
+ u32 version;
+};
+
+/* Localgate */
+struct gatemp_local_gate {
+ struct igateprovider_object *local_gate;
+ int ref_count;
+};
+
+/*!
+ * @brief Structure defining parameters for the GateMP module.
+ */
+struct _gatemp_params {
+ char *name;
+ u32 region_id;
+ void *shared_addr;
+ enum gatemp_local_protect local_protect;
+ enum gatemp_remote_protect remote_protect;
+ u32 resource_id;
+ bool open_flag;
+};
+
+/* -----------------------------------------------------------------------------
+ * Forward declaration
+ * -----------------------------------------------------------------------------
+ */
+static void gatemp_set_region0_reserved(void *shared_addr);
+static void gatemp_clear_region0_reserved(void);
+static void gatemp_open_region0_reserved(void *shared_addr);
+static void gatemp_close_region0_reserved(void *shared_addr);
+static void gatemp_set_default_remote(void *handle);
+static uint gatemp_get_free_resource(u8 *in_use, int num, int start_id);
+static struct gatemp_object *_gatemp_create(
+ const struct _gatemp_params *params);
+
+/* -----------------------------------------------------------------------------
+ * Globals
+ * -----------------------------------------------------------------------------
+ */
+static struct gatemp_module_state gatemp_state = {
+ .default_cfg.num_resources = 32,
+ .default_cfg.max_name_len = 32,
+ .default_cfg.default_protection = GATEMP_LOCALPROTECT_INTERRUPT,
+ .def_inst_params.shared_addr = NULL,
+ .def_inst_params.region_id = 0x0,
+ .default_gate = NULL
+};
+
+static struct gatemp_module_state *gatemp_module = &gatemp_state;
+static struct gatemp_object *gatemp_first_object;
+
+/* -----------------------------------------------------------------------------
+ * APIs
+ * -----------------------------------------------------------------------------
+ */
+
+void gatemp_get_config(struct gatemp_config *cfg)
+{
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(cfg == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (atomic_cmpmask_and_lt(&(gatemp_module->ref_count),
+ GATEMP_MAKE_MAGICSTAMP(0),
+ GATEMP_MAKE_MAGICSTAMP(1)) == true) {
+ /* Setup has not yet been called */
+ memcpy((void *)cfg, &gatemp_module->default_cfg,
+ sizeof(struct gatemp_config));
+ } else {
+ memcpy((void *)cfg, &gatemp_module->cfg,
+ sizeof(struct gatemp_config));
+ }
+
+exit:
+ if (retval < 0)
+ pr_err("gatemp_get_config failed! status = 0x%x", retval);
+ return;
+}
+
+s32 gatemp_setup(const struct gatemp_config *cfg)
+{
+ s32 retval = 0;
+ struct gatemp_config tmp_cfg;
+ int i;
+ struct nameserver_params params;
+
+ /* This sets the ref_count variable is not initialized, upper 16 bits is
+ * written with module Id to ensure correctness of refCount variable.
+ */
+ atomic_cmpmask_and_set(&gatemp_module->ref_count,
+ GATEMP_MAKE_MAGICSTAMP(0),
+ GATEMP_MAKE_MAGICSTAMP(0));
+ if (atomic_inc_return(&gatemp_module->ref_count)
+ != GATEMP_MAKE_MAGICSTAMP(1)) {
+ return 1;
+ }
+
+ if (cfg == NULL) {
+ gatemp_get_config(&tmp_cfg);
+ cfg = &tmp_cfg;
+ }
+
+ gatemp_module->default_gate = NULL;
+ for (i = 0; i < GATEMP_PROXYORDER_NUM; i++)
+ gatemp_module->proxy_map[i] = i;
+
+ if ((void *)gatemp_remote_custom1_proxy_create
+ == (void *)gatemp_remote_system_proxy_create) {
+ gatemp_module->proxy_map[GATEMP_PROXYORDER_CUSTOM1] =
+ gatemp_module->proxy_map[GATEMP_PROXYORDER_SYSTEM];
+ }
+
+ if ((void *) gatemp_remote_system_proxy_create
+ == (void *) gatemp_remote_custom2_proxy_create) {
+ gatemp_module->proxy_map[GATEMP_PROXYORDER_CUSTOM2] =
+ gatemp_module->proxy_map[GATEMP_PROXYORDER_SYSTEM];
+ } else if ((void *) gatemp_remote_custom2_proxy_create
+ == (void *) gatemp_remote_custom1_proxy_create) {
+ gatemp_module->proxy_map[GATEMP_PROXYORDER_CUSTOM2] =
+ gatemp_module->proxy_map[GATEMP_PROXYORDER_CUSTOM1];
+ }
+
+ /* Create MutexPri gate */
+ gatemp_module->gate_mutex = kmalloc(sizeof(struct mutex), GFP_KERNEL);
+ if (gatemp_module->gate_mutex == NULL) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+ mutex_init(gatemp_module->gate_mutex);
+
+ /* create Nameserver */
+ nameserver_params_init(&params);
+ params.max_runtime_entries = cfg->max_runtime_entries;
+ params.max_name_len = cfg->max_name_len;
+ params.max_value_len = 2 * sizeof(u32);
+ gatemp_module->name_server = nameserver_create(GATEMP_NAMESERVER,
+ &params);
+ if (gatemp_module->name_server == NULL) {
+ retval = -1;
+ goto error_nameserver;
+ }
+
+ /* Get the number of configured instances from the plugged in
+ * Proxy gates */
+ gatemp_module->num_remote_system = \
+ gatemp_remote_system_proxy_get_num_instances();
+ gatemp_module->num_remote_custom1 = \
+ gatemp_remote_custom1_proxy_get_num_instances();
+ gatemp_module->num_remote_custom2 = \
+ gatemp_remote_custom2_proxy_get_num_instances();
+ gatemp_module->num_remote_system_reserved = \
+ gatemp_remote_system_proxy_get_num_reserved();
+ gatemp_module->num_remote_custom1_reserved = \
+ gatemp_remote_custom1_proxy_get_num_reserved();
+ gatemp_module->num_remote_custom2_reserved = \
+ gatemp_remote_custom2_proxy_get_num_reserved();
+ gatemp_module->remote_system_in_use_alloc = \
+ kzalloc((sizeof(u8) * cfg->num_resources), GFP_KERNEL);
+ if (gatemp_module->remote_system_in_use_alloc == NULL) {
+ retval = -ENOMEM;
+ goto error_remote_system_fail;
+ }
+ gatemp_module->remote_system_in_use = \
+ gatemp_module->remote_system_in_use_alloc;
+
+ gatemp_module->remote_custom1_in_use_alloc = \
+ kzalloc((sizeof(u8) * cfg->num_resources), GFP_KERNEL);
+ if (gatemp_module->remote_custom1_in_use_alloc == NULL) {
+ retval = -ENOMEM;
+ goto error_remote_custom1_fail;
+ }
+ gatemp_module->remote_custom1_in_use = \
+ gatemp_module->remote_custom1_in_use_alloc;
+
+ gatemp_module->remote_custom2_in_use_alloc = \
+ kzalloc((sizeof(u8) * cfg->num_resources), GFP_KERNEL);
+ if (gatemp_module->remote_custom2_in_use_alloc == NULL) {
+ retval = -ENOMEM;
+ goto error_remote_custom2_fail;
+ }
+ gatemp_module->remote_custom2_in_use = \
+ gatemp_module->remote_custom2_in_use_alloc;
+
+ if (gatemp_module->num_remote_system) {
+ gatemp_module->remote_system_gates_alloc = kzalloc(
+ (sizeof(void *) * gatemp_module->num_remote_system),
+ GFP_KERNEL);
+ if (gatemp_module->remote_system_gates_alloc == NULL) {
+ retval = -ENOMEM;
+ goto error_remote_system_gates_fail;
+ }
+ } else
+ gatemp_module->remote_system_gates_alloc = NULL;
+ gatemp_module->remote_system_gates = \
+ gatemp_module->remote_system_gates_alloc;
+
+ if (gatemp_module->num_remote_custom1) {
+ gatemp_module->remote_custom1_gates_alloc = kzalloc(
+ (sizeof(void *) * gatemp_module->num_remote_custom1),
+ GFP_KERNEL);
+ if (gatemp_module->remote_custom1_gates_alloc == NULL) {
+ retval = -ENOMEM;
+ goto error_remote_custom1_gates_fail;
+ }
+ } else
+ gatemp_module->remote_custom1_gates_alloc = NULL;
+ gatemp_module->remote_custom1_gates = \
+ gatemp_module->remote_custom1_gates_alloc;
+
+ if (gatemp_module->num_remote_custom2) {
+ gatemp_module->remote_custom2_gates_alloc = kzalloc(
+ (sizeof(void *) * gatemp_module->num_remote_custom2),
+ GFP_KERNEL);
+ if (gatemp_module->remote_custom2_gates_alloc == NULL) {
+ retval = -ENOMEM;
+ goto error_remote_custom2_gates_fail;
+ }
+ } else
+ gatemp_module->remote_custom2_gates_alloc = NULL;
+ gatemp_module->remote_custom2_gates = \
+ gatemp_module->remote_custom2_gates_alloc;
+
+ /* Copy the cfg */
+ memcpy((void *) &gatemp_module->cfg, (void *) cfg,
+ sizeof(struct gatemp_config));
+ return 0;
+
+error_remote_custom2_gates_fail:
+ kfree(gatemp_module->remote_custom1_gates_alloc);
+ gatemp_module->remote_custom1_gates_alloc = NULL;
+ gatemp_module->remote_custom1_gates = NULL;
+error_remote_custom1_gates_fail:
+ kfree(gatemp_module->remote_system_gates_alloc);
+ gatemp_module->remote_system_gates_alloc = NULL;
+ gatemp_module->remote_system_gates = NULL;
+error_remote_system_gates_fail:
+ kfree(gatemp_module->remote_custom2_in_use_alloc);
+ gatemp_module->remote_custom2_in_use_alloc = NULL;
+ gatemp_module->remote_custom2_in_use = NULL;
+error_remote_custom2_fail:
+ kfree(gatemp_module->remote_custom1_in_use_alloc);
+ gatemp_module->remote_custom1_in_use_alloc = NULL;
+ gatemp_module->remote_custom1_in_use = NULL;
+error_remote_custom1_fail:
+ kfree(gatemp_module->remote_system_in_use_alloc);
+ gatemp_module->remote_system_in_use_alloc = NULL;
+ gatemp_module->remote_system_in_use = NULL;
+error_remote_system_fail:
+ if (gatemp_module->name_server)
+ nameserver_delete(&gatemp_module->name_server);
+error_nameserver:
+ kfree(gatemp_module->gate_mutex);
+ gatemp_module->gate_mutex = NULL;
+exit:
+ pr_err("gatemp_setup failed! status = 0x%x", retval);
+ return retval;
+}
+
+s32 gatemp_destroy(void)
+{
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(gatemp_module->ref_count),
+ GATEMP_MAKE_MAGICSTAMP(0),
+ GATEMP_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (!(atomic_dec_return(&gatemp_module->ref_count)
+ == GATEMP_MAKE_MAGICSTAMP(0))) {
+ retval = 1;
+ goto exit;
+ }
+
+ kfree(gatemp_module->gate_mutex);
+ gatemp_module->gate_mutex = NULL;
+
+ if (gatemp_module->name_server)
+ nameserver_delete(&gatemp_module->name_server);
+
+ kfree(gatemp_module->remote_system_in_use_alloc);
+ gatemp_module->remote_system_in_use_alloc = NULL;
+ gatemp_module->remote_system_in_use = NULL;
+
+ kfree(gatemp_module->remote_custom1_in_use_alloc);
+ gatemp_module->remote_custom1_in_use_alloc = NULL;
+ gatemp_module->remote_custom1_in_use = NULL;
+
+ kfree(gatemp_module->remote_custom2_in_use_alloc);
+ gatemp_module->remote_custom2_in_use_alloc = NULL;
+ gatemp_module->remote_custom2_in_use = NULL;
+
+ kfree(gatemp_module->remote_system_gates_alloc);
+ gatemp_module->remote_system_gates_alloc = NULL;
+ gatemp_module->remote_system_gates = NULL;
+
+ kfree(gatemp_module->remote_custom1_gates_alloc);
+ gatemp_module->remote_custom1_gates_alloc = NULL;
+ gatemp_module->remote_custom1_gates = NULL;
+
+ kfree(gatemp_module->remote_custom2_gates_alloc);
+ gatemp_module->remote_custom2_gates_alloc = NULL;
+ gatemp_module->remote_custom2_gates = NULL;
+
+ /* Clear cfg area */
+ memset((void *) &gatemp_module->cfg, 0, sizeof(struct gatemp_config));
+ gatemp_module->is_owner = false;
+ return 0;
+
+exit:
+ if (retval < 0)
+ pr_err("gatemp_destroy failed! status = 0x%x", retval);
+ return retval;
+}
+
+static void _gatemp_get_shared_params(struct gatemp_params *sparams,
+ const struct _gatemp_params *params)
+{
+ sparams->name = params->name;
+ sparams->region_id = params->region_id;
+ sparams->shared_addr = params->shared_addr;
+ sparams->local_protect = \
+ (enum gatemp_local_protect) params->local_protect;
+ sparams->remote_protect = \
+ (enum gatemp_remote_protect) params->remote_protect;
+}
+
+void gatemp_params_init(struct gatemp_params *params)
+{
+ params->name = NULL;
+ params->region_id = 0;
+ params->shared_addr = NULL;
+ params->local_protect = GATEMP_LOCALPROTECT_INTERRUPT;
+ params->remote_protect = GATEMP_REMOTEPROTECT_SYSTEM;
+}
+
+static int gatemp_instance_init(struct gatemp_object *obj,
+ const struct _gatemp_params *params)
+{
+ int *key;
+ void *remote_handle;
+ gatemp_remote_system_proxy_params system_params;
+ gatemp_remote_custom1_proxy_params custom1_params;
+ gatemp_remote_custom2_proxy_params custom2_params;
+ u32 min_align;
+ u32 offset;
+ u32 *shared_shm_base;
+ struct gatemp_params sparams;
+ u32 ns_value[2];
+ uint cache_line_size = 0;
+ int retval = 0;
+ void *region_heap;
+
+ /* No parameter check since this function will be called internally */
+
+ /* Initialize resource_id to an invalid value */
+ obj->resource_id = (u32)-1;
+
+ /* Open GateMP instance */
+ if (params->open_flag == true) {
+ /* all open work done here except for remote gate_handle */
+ obj->local_protect = params->local_protect;
+ obj->remote_protect = params->remote_protect;
+ obj->ns_key = NULL;
+ obj->num_opens = 1;
+ obj->creator_proc_id = MULTIPROC_INVALIDID;
+ obj->attrs = (struct gatemp_attrs *)params->shared_addr;
+ obj->region_id = sharedregion_get_id((void *)obj->attrs);
+ obj->cache_enabled = \
+ sharedregion_is_cache_enabled(obj->region_id);
+ obj->obj_type = IPC_OBJTYPE_OPENDYNAMIC;
+
+ /* Assert that the buffer is in a valid shared region */
+ if (obj->region_id == SHAREDREGION_INVALIDREGIONID)
+ retval = 1;
+
+ if (retval == 0) {
+ cache_line_size = sharedregion_get_cache_line_size(
+ obj->region_id);
+
+ obj->alloc_size = 0;
+
+ /*min_align = Memory_getMaxDefaultTypeAlign();*/
+ min_align = 4;
+ if (cache_line_size > min_align)
+ min_align = cache_line_size;
+
+ offset = ROUND_UP(sizeof(struct gatemp_attrs), \
+ min_align);
+ obj->proxy_attrs = (void *)((u32)obj->attrs + offset);
+ }
+ goto proxy_work;
+ }
+
+ /* Create GateMP instance */
+ obj->local_protect = params->local_protect;
+ obj->remote_protect = params->remote_protect;
+ obj->ns_key = NULL;
+ obj->num_opens = 0;
+ obj->creator_proc_id = multiproc_self();
+
+ /* No Remote Protection needed, just create the local protection */
+ if (obj->remote_protect == GATEMP_REMOTEPROTECT_NONE) {
+ /* Creating a local gate (Attrs is in local memory) */
+ /* all work done here and return */
+ obj->gate_handle = gatemp_create_local(obj->local_protect);
+
+ if (params->shared_addr != NULL) {
+ obj->attrs = params->shared_addr;
+ obj->obj_type = IPC_OBJTYPE_CREATEDYNAMIC;
+ /* Need cache settings since attrs is in shared mem */
+ obj->region_id = \
+ sharedregion_get_id((void *)obj->attrs);
+ obj->cache_enabled = \
+ sharedregion_is_cache_enabled(obj->region_id);
+ } else {
+ obj->obj_type = IPC_OBJTYPE_LOCAL;
+ obj->cache_enabled = false; /* local */
+ obj->region_id = SHAREDREGION_INVALIDREGIONID;
+ /* Using default target alignment */
+ obj->attrs = kmalloc(sizeof(struct gatemp_attrs),
+ GFP_KERNEL);
+ if (obj->attrs == NULL)
+ return 2;
+ }
+
+ if (retval == 0) {
+ obj->attrs->arg = (u32)obj;
+ obj->attrs->mask = SETMASK(obj->remote_protect,
+ obj->local_protect);
+ obj->attrs->creator_proc_id = obj->creator_proc_id;
+ obj->attrs->status = GATEMP_CREATED;
+#if 0
+ if (obj->cache_enabled) {
+ /* Need to write back memory if cache is enabled
+ * because cache will be invalidated during
+ * open_by_addr */
+ Cache_wbInv(obj->attrs,
+ sizeof(struct gatemp_attrs),
+ Cache_Type_ALL, true);
+ }
+#endif
+ if (params->name != NULL) {
+ /* Top 16 bits = procId of creator. Bottom 16
+ * bits = '0' if local, '1' otherwise */
+ ns_value[0] = (u32)obj->attrs;
+ ns_value[1] = multiproc_self() << 16;
+ obj->ns_key = nameserver_add(
+ gatemp_module->name_server,
+ params->name, &ns_value,
+ 2 * sizeof(u32));
+ }
+ }
+ goto proxy_work;
+ }
+
+ /* Create remote protection */
+ if (params->shared_addr == NULL) {
+ /* If sharedAddr = NULL we are creating dynamically from the
+ * heap */
+ obj->obj_type = IPC_OBJTYPE_CREATEDYNAMIC_REGION;
+ obj->region_id = params->region_id;
+ _gatemp_get_shared_params(&sparams, params);
+ obj->alloc_size = gatemp_shared_mem_req(&sparams);
+ obj->cache_enabled = sharedregion_is_cache_enabled(
+ obj->region_id);
+
+ /* The region heap will do the alignment */
+ region_heap = sharedregion_get_heap(obj->region_id);
+ WARN_ON(region_heap == NULL);
+ obj->attrs = sl_heap_alloc(region_heap, obj->alloc_size, 0);
+ if (obj->attrs == NULL)
+ retval = 3;
+
+ if (retval == 0) {
+ cache_line_size = sharedregion_get_cache_line_size(
+ obj->region_id);
+ /*min_align = Memory_getMaxDefaultTypeAlign();*/
+ min_align = 4;
+
+ if (cache_line_size > min_align)
+ min_align = cache_line_size;
+
+ offset = ROUND_UP(sizeof(struct gatemp_attrs), \
+ min_align);
+ obj->proxy_attrs = (void *)((u32)obj->attrs + offset);
+ }
+ } else { /* creating using shared_addr */
+ obj->region_id = sharedregion_get_id(params->shared_addr);
+ /* Assert that the buffer is in a valid shared region */
+ if (obj->region_id == SHAREDREGION_INVALIDREGIONID)
+ retval = 4;
+
+ cache_line_size = sharedregion_get_cache_line_size(
+ obj->region_id);
+ /* Assert that shared_addr is cache aligned */
+ if ((retval == 0) && (((u32)params->shared_addr % \
+ cache_line_size) != 0))
+ retval = 5;
+
+ if (retval == 0) {
+ obj->obj_type = IPC_OBJTYPE_CREATEDYNAMIC;
+ obj->attrs = (struct gatemp_attrs *)params->shared_addr;
+ obj->cache_enabled = \
+ sharedregion_is_cache_enabled(obj->region_id);
+
+ /*min_align = Memory_getMaxDefaultTypeAlign();*/
+ min_align = 4;
+ if (cache_line_size > min_align)
+ min_align = cache_line_size;
+ offset = ROUND_UP(sizeof(struct gatemp_attrs), \
+ min_align);
+ obj->proxy_attrs = (void *)((u32)obj->attrs + offset);
+ }
+ }
+
+proxy_work:
+ /* Proxy work for open and create done here */
+ switch (obj->remote_protect) {
+ case GATEMP_REMOTEPROTECT_SYSTEM:
+ if (obj->obj_type != IPC_OBJTYPE_OPENDYNAMIC) {
+ /* Created Instance */
+ obj->resource_id = gatemp_get_free_resource(
+ gatemp_module->remote_system_in_use,
+ gatemp_module->num_remote_system,
+ gatemp_module->num_remote_system_reserved);
+ if (obj->resource_id == -1)
+ retval = 6;
+ } else {
+ /* resource_id set by open call */
+ obj->resource_id = params->resource_id;
+ }
+
+ if (retval == 0) {
+ /* Create the proxy object */
+ gatemp_remote_system_proxy_params_init(&system_params);
+ system_params.resource_id = obj->resource_id;
+ system_params.open_flag = \
+ (obj->obj_type == IPC_OBJTYPE_OPENDYNAMIC);
+ system_params.shared_addr = obj->proxy_attrs;
+ system_params.region_id = obj->region_id;
+ remote_handle = gatemp_remote_system_proxy_create(
+ (enum igatempsupport_local_protect)
+ obj->local_protect,
+ &system_params);
+
+ if (remote_handle == NULL)
+ retval = 7;
+
+ if (retval == 0) {
+ /* Finish filling in the object */
+ obj->gate_handle = remote_handle;
+
+ /* Fill in the local array because it is
+ * cooked */
+ key = Gate_enterSystem();
+ gatemp_module->remote_system_gates[
+ obj->resource_id] = (void *)obj;
+ Gate_leaveSystem(key);
+ }
+ }
+ break;
+
+ case GATEMP_REMOTEPROTECT_CUSTOM1:
+ if (obj->obj_type != IPC_OBJTYPE_OPENDYNAMIC) {
+ /* Created Instance */
+ obj->resource_id = gatemp_get_free_resource(
+ gatemp_module->remote_custom1_in_use,
+ gatemp_module->num_remote_custom1,
+ gatemp_module->num_remote_custom1_reserved);
+ if (obj->resource_id == -1)
+ retval = 6;
+ } else {
+ /* resource_id set by open call */
+ obj->resource_id = params->resource_id;
+ }
+
+ if (retval == 0) {
+ /* Create the proxy object */
+ gatemp_remote_custom1_proxy_params_init(\
+ &custom1_params);
+ custom1_params.resource_id = obj->resource_id;
+ custom1_params.open_flag = \
+ (obj->obj_type == IPC_OBJTYPE_OPENDYNAMIC);
+ custom1_params.shared_addr = obj->proxy_attrs;
+ custom1_params.region_id = obj->region_id;
+ remote_handle = gatemp_remote_custom1_proxy_create(
+ (enum igatempsupport_local_protect)
+ obj->local_protect,
+ &custom1_params);
+ if (remote_handle == NULL)
+ retval = 7;
+
+ if (retval == 0) {
+ /* Finish filling in the object */
+ obj->gate_handle = remote_handle;
+
+ /* Fill in the local array because it is
+ * cooked */
+ key = Gate_enterSystem();
+ gatemp_module->remote_custom1_gates[
+ obj->resource_id] = (void *)obj;
+ Gate_leaveSystem(key);
+ }
+ }
+ break;
+
+ case GATEMP_REMOTEPROTECT_CUSTOM2:
+ if (obj->obj_type != IPC_OBJTYPE_OPENDYNAMIC) {
+ /* Created Instance */
+ obj->resource_id = gatemp_get_free_resource(
+ gatemp_module->remote_custom2_in_use,
+ gatemp_module->num_remote_custom2,
+ gatemp_module->num_remote_custom1_reserved);
+ if (obj->resource_id == -1)
+ retval = 6;
+ } else {
+ /* resource_id set by open call */
+ obj->resource_id = params->resource_id;
+ }
+
+ if (retval == 0) {
+ /* Create the proxy object */
+ gatemp_remote_custom2_proxy_params_init(\
+ &custom2_params);
+ custom2_params.resource_id = obj->resource_id;
+ custom2_params.open_flag = \
+ (obj->obj_type == IPC_OBJTYPE_OPENDYNAMIC);
+ custom2_params.shared_addr = obj->proxy_attrs;
+ custom2_params.region_id = obj->region_id;
+ remote_handle = gatemp_remote_custom2_proxy_create(
+ (enum igatempsupport_local_protect)
+ obj->local_protect,
+ &custom2_params);
+ if (remote_handle == NULL)
+ retval = 7;
+
+ if (retval == 0) {
+ /* Finish filling in the object */
+ obj->gate_handle = remote_handle;
+
+ /* Fill in the local array because it is
+ * cooked */
+ key = Gate_enterSystem();
+ gatemp_module->remote_custom2_gates[
+ obj->resource_id] = (void *)obj;
+ Gate_leaveSystem(key);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* Place Name/Attrs into NameServer table */
+ if ((obj->obj_type != IPC_OBJTYPE_OPENDYNAMIC) && (retval == 0)) {
+ /* Fill in the attrs */
+ obj->attrs->arg = obj->resource_id;
+ obj->attrs->mask = \
+ SETMASK(obj->remote_protect, obj->local_protect);
+ obj->attrs->creator_proc_id = obj->creator_proc_id;
+ obj->attrs->status = GATEMP_CREATED;
+#if 0
+ if (obj->cache_enabled) {
+ Cache_wbInv(obj->attrs, sizeof(struct gatemp_attrs),
+ Cache_Type_ALL, true);
+ }
+#endif
+
+ if (params->name != NULL) {
+ shared_shm_base = sharedregion_get_srptr(obj->attrs,
+ obj->region_id);
+ ns_value[0] = (u32)shared_shm_base;
+ /* Top 16 bits = procId of creator, Bottom 16
+ * bits = '0' if local, '1' otherwise */
+ ns_value[1] = multiproc_self() << 16 | 1;
+ obj->ns_key = nameserver_add(gatemp_module->name_server,
+ params->name, &ns_value,
+ 2 * sizeof(u32));
+ if (obj->ns_key == NULL)
+ retval = 8;
+ }
+ }
+
+ if (retval != 0) {
+ pr_err("gatemp_instance_init failed! status = 0x%x", retval);
+ }
+ return retval;
+}
+
+static void gatemp_instance_finalize(struct gatemp_object *obj, int status)
+{
+ int *system_key = (int *)0;
+ gatemp_remote_system_proxy_handle system_handle;
+ gatemp_remote_custom1_proxy_handle custom1_handle;
+ gatemp_remote_custom2_proxy_handle custom2_handle;
+ int retval = 0;
+ void **remote_handles = NULL;
+ u8 *in_use_array = NULL;
+ u32 num_resources = 0;
+
+ /* No parameter check since this function will be called internally */
+
+ /* Cannot call when numOpen is non-zero. */
+ if (obj->num_opens != 0) {
+ retval = GateMP_E_INVALIDSTATE;
+ goto exit;
+ }
+
+ /* Remove from NameServer */
+ if (obj->ns_key != NULL) {
+ nameserver_remove_entry(gatemp_module->name_server,
+ obj->ns_key);
+ }
+ /* Set the status to 0 */
+ if (obj->obj_type != IPC_OBJTYPE_OPENDYNAMIC) {
+ obj->attrs->status = 0;
+#if 0
+ if (obj->cache_enabled)
+ Cache_wbInv(obj->attrs, sizeof(struct gatemp_attrs),
+ Cache_Type_ALL, true);
+#endif
+ }
+
+ /* If ObjType_LOCAL, memory was allocated from the local system heap.
+ * obj->attrs might be NULL if the Memory_alloc failed in Instance_init
+ */
+ if (obj->remote_protect == GATEMP_REMOTEPROTECT_NONE)
+ kfree(obj->attrs);
+
+ /* Delete if a remote gate */
+ switch (obj->remote_protect) {
+ /* Delete proxy instance... need to downCast */
+ case GATEMP_REMOTEPROTECT_SYSTEM:
+ if (obj->gate_handle) {
+ system_handle = (gatemp_remote_system_proxy_handle)
+ (obj->gate_handle);
+ gatemp_remote_system_proxy_delete(&system_handle);
+ }
+ in_use_array = gatemp_module->remote_system_in_use;
+ remote_handles = gatemp_module->remote_system_gates;
+ num_resources = gatemp_module->num_remote_system;
+ break;
+ case GATEMP_REMOTEPROTECT_CUSTOM1:
+ if (obj->gate_handle) {
+ custom1_handle = (gatemp_remote_custom1_proxy_handle)
+ (obj->gate_handle);
+ gatemp_remote_custom1_proxy_delete(&custom1_handle);
+ }
+ in_use_array = gatemp_module->remote_custom1_in_use;
+ remote_handles = gatemp_module->remote_custom1_gates;
+ num_resources = gatemp_module->num_remote_custom1;
+ break;
+ case GATEMP_REMOTEPROTECT_CUSTOM2:
+ if (obj->gate_handle) {
+ custom2_handle = (gatemp_remote_custom2_proxy_handle)
+ (obj->gate_handle);
+ gatemp_remote_custom2_proxy_delete(&custom2_handle);
+ }
+ in_use_array = gatemp_module->remote_custom2_in_use;
+ remote_handles = gatemp_module->remote_custom2_gates;
+ num_resources = gatemp_module->num_remote_custom2;
+ break;
+ case GATEMP_REMOTEPROTECT_NONE:
+ /* Nothing else to finalize. Any alloc'ed memory has already
+ * been freed */
+ return;
+ default:
+ /* Nothing to do */
+ break;
+ }
+
+ /* Clear the handle array entry in local memory */
+ if (obj->resource_id != (uint)-1)
+ remote_handles[obj->resource_id] = NULL;
+
+ if (obj->obj_type != IPC_OBJTYPE_OPENDYNAMIC &&
+ obj->resource_id != (uint)-1) {
+ /* Only enter default gate if not deleting default gate. */
+ if (obj != gatemp_module->default_gate)
+ system_key = gatemp_enter(gatemp_module->default_gate);
+ /* Clear the resource used flag in shared memory */
+ in_use_array[obj->resource_id] = false;
+#if 0
+ if (obj->cache_enabled) {
+ Cache_wbInv(in_use_array, num_resources, Cache_Type_ALL,
+ true);
+ }
+#endif
+ /* Only leave default gate if not deleting default gate. */
+ if (obj != gatemp_module->default_gate)
+ gatemp_leave(gatemp_module->default_gate, system_key);
+ }
+
+ if (obj->obj_type == IPC_OBJTYPE_CREATEDYNAMIC_REGION) {
+ if (obj->attrs) {
+ /* Free memory allocated from the region heap */
+ sl_heap_free(sharedregion_get_heap(obj->region_id),
+ obj->attrs, obj->alloc_size);
+ }
+ }
+
+exit:
+ if (retval < 0) {
+ pr_err("gatemp_instance_finalize failed! "
+ "status = 0x%x", retval);
+ }
+ return;
+}
+
+int *gatemp_enter(void *obj)
+{
+ int *key;
+ struct gatemp_object *gmp_handle = (struct gatemp_object *)obj;
+
+ key = igateprovider_enter(gmp_handle->gate_handle);
+
+ return key;
+}
+
+void gatemp_leave(void *obj, int *key)
+{
+ struct gatemp_object *gmp_handle = (struct gatemp_object *)obj;
+
+ igateprovider_leave(gmp_handle->gate_handle, key);
+}
+
+int gatemp_open(char *name, void **handle)
+{
+ u32 *shared_shm_base;
+ int retval;
+ u32 len;
+ void *shared_addr;
+ u32 ns_value[2];
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(gatemp_module->ref_count),
+ GATEMP_MAKE_MAGICSTAMP(0),
+ GATEMP_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(name == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ len = sizeof(ns_value);
+ /* Get the Attrs out of the NameServer instance.
+ * Search all processors. */
+ retval = nameserver_get(gatemp_module->name_server, name, &ns_value,
+ &len, NULL);
+ if (retval < 0) {
+ *handle = NULL;
+ return GateMP_E_NOTFOUND;
+ }
+
+ /* The least significant bit of nsValue[1] == 0 means its a
+ * local GateMP, otherwise its a remote GateMP. */
+ if (!(ns_value[1] & 0x1) && ((ns_value[1] >> 16) != multiproc_self())) {
+ *handle = NULL;
+ return -1;
+ }
+
+ if ((ns_value[1] & 0x1) == 0) {
+ /* Opening a local GateMP locally. The GateMP is created
+ * from a local heap so don't do SharedRegion Ptr conversion. */
+ shared_addr = (u32 *)ns_value[0];
+ } else {
+ /* Opening a remote GateMP. Need to do SR ptr conversion. */
+ shared_shm_base = (u32 *)ns_value[0];
+ shared_addr = sharedregion_get_ptr(shared_shm_base);
+ }
+
+ retval = gatemp_open_by_addr(shared_addr, handle);
+
+exit:
+ if (retval < 0)
+ pr_err("gatemp_open failed! status = 0x%x", retval);
+ return retval;
+}
+
+int gatemp_open_by_addr(void *shared_addr, void **handle)
+{
+ int retval = 0;
+ int *key;
+ struct gatemp_object *obj = NULL;
+ struct _gatemp_params params;
+ struct gatemp_attrs *attrs;
+#if 0
+ u16 region_id;
+#endif
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(gatemp_module->ref_count),
+ GATEMP_MAKE_MAGICSTAMP(0),
+ GATEMP_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(shared_addr == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ attrs = (struct gatemp_attrs *)shared_addr;
+
+#if 0
+ /* get the region id and invalidate attrs is needed */
+ region_id = sharedregion_get_id(shared_addr);
+ if (region_id != SHAREDREGION_INVALIDREGIONID) {
+ if (sharedregion_is_cache_enabled(region_id))
+ Cache_inv(attrs, sizeof(struct gatemp_attrs),
+ Cache_Type_ALL, true);
+ }
+#endif
+
+ if (attrs->status != GATEMP_CREATED) {
+ retval = -1;
+ goto exit;
+ }
+
+ /* Local gate */
+ if (GETREMOTE(attrs->mask) == GATEMP_REMOTEPROTECT_NONE) {
+ if (attrs->creator_proc_id != multiproc_self())
+ retval = GateMP_E_LOCALGATE; /* TBD */
+ else {
+ key = Gate_enterSystem();
+ obj = (void *)attrs->arg;
+ *handle = obj;
+ obj->num_opens++;
+ Gate_leaveSystem(key);
+ }
+ } else {
+ /* Remote case */
+ switch (GETREMOTE(attrs->mask)) {
+ case GATEMP_REMOTEPROTECT_SYSTEM:
+ obj = (struct gatemp_object *)
+ gatemp_module->remote_system_gates[attrs->arg];
+ break;
+
+ case GATEMP_REMOTEPROTECT_CUSTOM1:
+ obj = (struct gatemp_object *)
+ gatemp_module->remote_custom1_gates[attrs->arg];
+ break;
+
+ case GATEMP_REMOTEPROTECT_CUSTOM2:
+ obj = (struct gatemp_object *)
+ gatemp_module->remote_custom2_gates[attrs->arg];
+ break;
+
+ default:
+ break;
+ }
+
+ /* If the object is NULL, then it must have been created on a
+ * remote processor. Need to create a local object. This is
+ * accomplished by setting the open_flag to true. */
+ if ((retval == 0) && (obj == NULL)) {
+ /* Create a GateMP object with the open_flag set to
+ * true */
+ params.name = NULL;
+ params.open_flag = true;
+ params.shared_addr = shared_addr;
+ params.resource_id = attrs->arg;
+ params.local_protect = GETLOCAL(attrs->mask);
+ params.remote_protect = GETREMOTE(attrs->mask);
+
+ obj = _gatemp_create(&params);
+ if (obj == NULL)
+ retval = GateMP_E_FAIL;
+ } else {
+ obj->num_opens++;
+ }
+
+ /* Return the "opened" GateMP instance */
+ *handle = obj;
+ }
+
+exit:
+ if (retval < 0)
+ pr_err("gatemp_open_by_addr failed! status = 0x%x", retval);
+ return retval;
+}
+
+int gatemp_close(void **handle)
+{
+ int *key;
+ struct gatemp_object *gate_handle = NULL;
+ int count;
+ int retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(gatemp_module->ref_count),
+ GATEMP_MAKE_MAGICSTAMP(0),
+ GATEMP_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely((handle == NULL) || (*handle == NULL)))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ gate_handle = (struct gatemp_object *)(*handle);
+ /* Cannot call with the num_opens equal to zero. This is either
+ * a created handle or been closed already. */
+ if (unlikely(gate_handle->num_opens == 0)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ key = Gate_enterSystem();
+ count = --gate_handle->num_opens;
+ Gate_leaveSystem(key);
+
+ /* If the gate is remote, call the close function */
+ if (gate_handle->remote_protect != GATEMP_REMOTEPROTECT_NONE) {
+ /* if the count is zero and the gate is opened, then this
+ * object was created in the open (i.e. the create happened
+ * on a remote processor.**/
+ if ((count == 0) && \
+ (gate_handle->obj_type == IPC_OBJTYPE_OPENDYNAMIC))
+ gatemp_delete((void **)&gate_handle);
+ }
+ *handle = NULL;
+ return 0;
+
+exit:
+ pr_err("gatemp_close failed! status = 0x%x", retval);
+ return retval;
+}
+
+u32 *gatemp_get_shared_addr(void *obj)
+{
+ u32 *sr_ptr;
+ struct gatemp_object *object = (struct gatemp_object *) obj;
+
+ sr_ptr = sharedregion_get_srptr(object->attrs, object->region_id);
+
+ return sr_ptr;
+}
+
+bool gatemp_query(int qual)
+{
+ return false;
+}
+
+void *gatemp_get_default_remote(void)
+{
+ return gatemp_module->default_gate;
+}
+
+enum gatemp_local_protect gatemp_get_local_protect(void *obj)
+{
+ struct gatemp_object *gmp_handle = (struct gatemp_object *)obj;
+
+ WARN_ON(obj == NULL);
+
+ return gmp_handle->local_protect;
+}
+
+enum gatemp_remote_protect gatemp_get_remote_protect(void *obj)
+{
+ struct gatemp_object *gmp_handle = (struct gatemp_object *)obj;
+
+ WARN_ON(obj == NULL);
+
+ return gmp_handle->remote_protect;
+}
+
+void *gatemp_create_local(enum gatemp_local_protect local_protect)
+{
+ void *gate_handle = NULL;
+
+ /* Create the local gate. */
+ switch (local_protect) {
+ case GATEMP_LOCALPROTECT_NONE:
+ /* Plug with the GateNull singleton */
+ gate_handle = NULL;
+ break;
+
+ case GATEMP_LOCALPROTECT_INTERRUPT:
+ /* Plug with the GateHwi singleton */
+ gate_handle = gate_system_handle;
+ break;
+
+ case GATEMP_LOCALPROTECT_TASKLET:
+ /* Plug with the GateSwi singleton */
+ gate_handle = gatemp_module->gate_mutex;
+ break;
+
+ case GATEMP_LOCALPROTECT_THREAD:
+ case GATEMP_LOCALPROTECT_PROCESS:
+ /* Plug with the GateMutexPri singleton */
+ gate_handle = gatemp_module->gate_mutex;
+ break;
+
+ default:
+ break;
+ }
+
+ return gate_handle;
+}
+
+uint gatemp_shared_mem_req(const struct gatemp_params *params)
+{
+ uint mem_req, min_align;
+ u16 region_id;
+ gatemp_remote_system_proxy_params system_params;
+ gatemp_remote_custom1_proxy_params custom1_params;
+ gatemp_remote_custom2_proxy_params custom2_params;
+
+ if (params->shared_addr)
+ region_id = sharedregion_get_id(params->shared_addr);
+ else
+ region_id = params->region_id;
+
+ /*min_align = Memory_getMaxDefaultTypeAlign();*/min_align = 4;
+ if (sharedregion_get_cache_line_size(region_id) > min_align)
+ min_align = sharedregion_get_cache_line_size(region_id);
+
+ mem_req = ROUND_UP(sizeof(struct gatemp_attrs), min_align);
+
+ /* add the amount of shared memory required by proxy */
+ if (params->remote_protect == GATEMP_REMOTEPROTECT_SYSTEM) {
+ gatemp_remote_system_proxy_params_init(&system_params);
+ system_params.region_id = region_id;
+ mem_req += gatemp_remote_system_proxy_shared_mem_req(
+ &system_params);
+ } else if (params->remote_protect == GATEMP_REMOTEPROTECT_CUSTOM1) {
+ gatemp_remote_custom1_proxy_params_init(&custom1_params);
+ custom1_params.region_id = region_id;
+ mem_req += gatemp_remote_custom1_proxy_shared_mem_req(
+ &custom1_params);
+ } else if (params->remote_protect == GATEMP_REMOTEPROTECT_CUSTOM2) {
+ gatemp_remote_custom2_proxy_params_init(&custom2_params);
+ custom2_params.region_id = region_id;
+ mem_req += gatemp_remote_custom2_proxy_shared_mem_req(
+ &custom2_params);
+ }
+
+ return mem_req;
+}
+
+uint gatemp_get_region0_reserved_size(void)
+{
+ uint reserved, min_align;
+
+ /*min_align = Memory_getMaxDefaultTypeAlign();*/min_align = 4;
+
+ if (sharedregion_get_cache_line_size(0) > min_align)
+ min_align = sharedregion_get_cache_line_size(0);
+
+ reserved = ROUND_UP(sizeof(struct gatemp_reserved), min_align);
+
+ reserved += ROUND_UP(gatemp_module->num_remote_system, min_align);
+
+ if (gatemp_module->proxy_map[GATEMP_PROXYORDER_CUSTOM1] ==
+ GATEMP_PROXYORDER_CUSTOM1) {
+ reserved += ROUND_UP(gatemp_module->num_remote_custom1,
+ min_align);
+ }
+
+ if (gatemp_module->proxy_map[GATEMP_PROXYORDER_CUSTOM2] ==
+ GATEMP_PROXYORDER_CUSTOM2) {
+ reserved += ROUND_UP(gatemp_module->num_remote_custom2,
+ min_align);
+ }
+
+ return reserved;
+}
+
+static void gatemp_set_region0_reserved(void *shared_addr)
+{
+ struct gatemp_reserved *reserve;
+ u32 min_align, offset;
+
+ /*min_align = Memory_getMaxDefaultTypeAlign();*/min_align = 4;
+ if (sharedregion_get_cache_line_size(0) > min_align)
+ min_align = sharedregion_get_cache_line_size(0);
+
+ /* setup struct gatemp_reserved fields */
+ reserve = (struct gatemp_reserved *)shared_addr;
+ reserve->version = GATEMP_VERSION;
+
+ if (sharedregion_is_cache_enabled(0)) {
+#if 0
+ Cache_wbInv(shared_addr, sizeof(struct gatemp_reserved),
+ Cache_Type_ALL, true);
+#endif
+ }
+
+ /* initialize the in-use array in shared memory for the system gates. */
+ offset = ROUND_UP(sizeof(struct gatemp_reserved), min_align);
+ gatemp_module->remote_system_in_use =
+ (void *)((u32)shared_addr + offset);
+ memset(gatemp_module->remote_system_in_use, 0,
+ gatemp_module->num_remote_system);
+
+ if (sharedregion_is_cache_enabled(0)) {
+#if 0
+ Cache_wbInv(gatemp_module->remote_system_in_use,
+ gatemp_module->num_remote_system,
+ Cache_Type_ALL, true);
+#endif
+ }
+
+ /* initialize the in-use array in shared memory for the custom1 gates.
+ * Need to check if this proxy is the same as system */
+ offset = ROUND_UP(gatemp_module->num_remote_system, min_align);
+ if (gatemp_module->proxy_map[GATEMP_PROXYORDER_CUSTOM1] ==
+ GATEMP_PROXYORDER_CUSTOM1) {
+ if (gatemp_module->num_remote_custom1 != 0) {
+ gatemp_module->remote_custom1_in_use =
+ gatemp_module->remote_system_in_use + offset;
+ }
+
+ memset(gatemp_module->remote_custom1_in_use, 0,
+ gatemp_module->num_remote_custom1);
+
+ if (sharedregion_is_cache_enabled(0)) {
+#if 0
+ Cache_wbInv(gatemp_module->remote_custom1_in_use,
+ gatemp_module->num_remote_custom1,
+ Cache_Type_ALL, true);
+#endif
+ }
+ } else {
+ gatemp_module->remote_custom1_in_use = \
+ gatemp_module->remote_system_in_use;
+ gatemp_module->remote_custom1_gates = \
+ gatemp_module->remote_system_gates;
+ }
+
+ /* initialize the in-use array in shared memory for the custom2 gates.
+ * Need to check if this proxy is the same as system or custom1 */
+ offset = ROUND_UP(gatemp_module->num_remote_custom1, min_align);
+ if (gatemp_module->proxy_map[GATEMP_PROXYORDER_CUSTOM2] ==
+ GATEMP_PROXYORDER_CUSTOM2) {
+ if (gatemp_module->num_remote_custom2 != 0) {
+ gatemp_module->remote_custom2_in_use =
+ gatemp_module->remote_custom1_in_use + offset;
+ }
+ memset(gatemp_module->remote_custom2_in_use, 0,
+ gatemp_module->num_remote_custom2);
+
+ if (sharedregion_is_cache_enabled(0)) {
+#if 0
+ Cache_wbInv(gatemp_module->remote_custom2_in_use,
+ gatemp_module->num_remote_custom2,
+ Cache_Type_ALL, true);
+#endif
+ }
+ } else if (gatemp_module->proxy_map[GATEMP_PROXYORDER_CUSTOM2] ==
+ GATEMP_PROXYORDER_CUSTOM1) {
+ gatemp_module->remote_custom2_in_use =
+ gatemp_module->remote_custom1_in_use;
+ gatemp_module->remote_custom2_gates =
+ gatemp_module->remote_custom1_gates;
+ } else {
+ gatemp_module->remote_custom2_in_use = \
+ gatemp_module->remote_system_in_use;
+ gatemp_module->remote_custom2_gates = \
+ gatemp_module->remote_system_gates;
+ }
+
+ return;
+}
+
+static void gatemp_clear_region0_reserved(void)
+{
+ pr_info("gatemp_clear_region0_reserved: either nothing to do "
+ "or not implemented");
+}
+
+static void gatemp_open_region0_reserved(void *shared_addr)
+{
+ struct gatemp_reserved *reserve;
+ u32 min_align, offset;
+
+ /*min_align = Memory_getMaxDefaultTypeAlign();*/min_align = 4;
+ if (sharedregion_get_cache_line_size(0) > min_align)
+ min_align = sharedregion_get_cache_line_size(0);
+
+
+ /* setup struct gatemp_reserved fields */
+ reserve = (struct gatemp_reserved *)shared_addr;
+
+ if (reserve->version != GATEMP_VERSION) {
+ /* TBD */
+ return;
+ }
+
+ offset = ROUND_UP(sizeof(struct gatemp_reserved), min_align);
+ gatemp_module->remote_system_in_use = \
+ (void *)((u32)shared_addr + offset);
+
+ /* initialize the in-use array in shared memory for the custom1 gates.
+ * Need to check if this proxy is the same as system */
+ offset = ROUND_UP(gatemp_module->num_remote_system, min_align);
+ if (gatemp_module->proxy_map[GATEMP_PROXYORDER_CUSTOM1] ==
+ GATEMP_PROXYORDER_CUSTOM1) {
+ if (gatemp_module->num_remote_custom1 != 0) {
+ gatemp_module->remote_custom1_in_use =
+ gatemp_module->remote_system_in_use + offset;
+ }
+ } else {
+ gatemp_module->remote_custom1_in_use = \
+ gatemp_module->remote_system_in_use;
+ gatemp_module->remote_custom1_gates = \
+ gatemp_module->remote_system_gates;
+ }
+
+ offset = ROUND_UP(gatemp_module->num_remote_custom1, min_align);
+ if (gatemp_module->proxy_map[GATEMP_PROXYORDER_CUSTOM2] ==
+ GATEMP_PROXYORDER_CUSTOM2) {
+ if (gatemp_module->num_remote_custom2 != 0) {
+ gatemp_module->remote_custom2_in_use =
+ gatemp_module->remote_custom1_in_use + offset;
+ }
+ } else if (gatemp_module->proxy_map[GATEMP_PROXYORDER_CUSTOM2] ==
+ GATEMP_PROXYORDER_CUSTOM1) {
+ gatemp_module->remote_custom2_in_use =
+ gatemp_module->remote_custom1_in_use;
+ gatemp_module->remote_custom2_gates =
+ gatemp_module->remote_custom1_gates;
+ } else {
+ gatemp_module->remote_custom2_in_use = \
+ gatemp_module->remote_system_in_use;
+ gatemp_module->remote_custom2_gates = \
+ gatemp_module->remote_system_gates;
+ }
+
+ return;
+}
+
+static void gatemp_close_region0_reserved(void *shared_addr)
+{
+ pr_info("gatemp_close_region0_reserved: either nothing to do "
+ "or not implemented");
+}
+
+static void gatemp_set_default_remote(void *handle)
+{
+ gatemp_module->default_gate = handle;
+}
+
+int gatemp_start(void *shared_addr)
+{
+ struct sharedregion_entry entry;
+ struct gatemp_params gatemp_params;
+ void *default_gate;
+ int retval = 0;
+
+ /* get region 0 information */
+ sharedregion_get_entry(0, &entry);
+
+ /* if entry owner proc is not specified return */
+ if (entry.owner_proc_id != SHAREDREGION_DEFAULTOWNERID) {
+ if (entry.owner_proc_id == multiproc_self()) {
+ /* Intialize the locks if ncessary.*/
+ gatemp_remote_system_proxy_locks_init();
+ gatemp_remote_custom1_proxy_locks_init();
+ gatemp_remote_custom2_proxy_locks_init();
+ }
+
+ /* Init params for default gate */
+ gatemp_params_init(&gatemp_params);
+ gatemp_params.shared_addr = (void *)((u32)shared_addr +
+ gatemp_get_region0_reserved_size());
+ gatemp_params.local_protect = GATEMP_LOCALPROTECT_TASKLET;
+
+ if (multiproc_get_num_processors() > 1) {
+ gatemp_params.remote_protect = \
+ GATEMP_REMOTEPROTECT_SYSTEM;
+ } else {
+ gatemp_params.remote_protect = \
+ GATEMP_REMOTEPROTECT_NONE;
+ }
+
+ if (entry.owner_proc_id == multiproc_self()) {
+ gatemp_module->is_owner = true;
+
+ /* if owner of the SharedRegion */
+ gatemp_set_region0_reserved(shared_addr);
+
+ /* create default GateMP */
+ default_gate = gatemp_create(&gatemp_params);
+
+ if (default_gate != NULL) {
+ /* set the default GateMP for creator */
+ gatemp_set_default_remote(default_gate);
+ } else {
+ retval = -1;
+ }
+ }
+ }
+
+ if (retval < 0)
+ pr_err("gatemp_start failed! status = 0x%x", retval);
+ return retval;
+}
+
+int gatemp_stop(void)
+{
+ int retval = 0;
+
+ /* if entry owner proc is not specified return */
+ if (gatemp_module->is_owner == true) {
+ /* if owner of the SharedRegion */
+ gatemp_clear_region0_reserved();
+
+ gatemp_delete((void **)&gatemp_module->default_gate);
+
+ /* set the default GateMP for creator */
+ gatemp_set_default_remote(NULL);
+ }
+
+ return retval;
+}
+
+
+/*
+ *************************************************************************
+ * Internal functions
+ *************************************************************************
+ */
+static uint gatemp_get_free_resource(u8 *in_use, int num, int start_id)
+{
+ int *key = NULL;
+ bool flag = false;
+ uint resource_id;
+ void *default_gate;
+
+ /* Need to look at shared memory. Enter default gate */
+ default_gate = gatemp_get_default_remote();
+
+ if (default_gate)
+ key = gatemp_enter(default_gate);
+
+#if 0
+ /* Invalidate cache before looking at the in-use flags */
+ if (sharedregion_is_cache_enabled(0))
+ Cache_inv(in_use, num * sizeof(u8), Cache_Type_ALL, true);
+#endif
+
+ /* Find a free resource id. Note: zero is reserved on the
+ * system proxy for the default gate. */
+ for (resource_id = start_id; resource_id < num; resource_id++) {
+ /* If not in-use, set the in_use to true to prevent other
+ * creates from getting this one. */
+ if (in_use[resource_id] == false) {
+ flag = true;
+
+ /* Denote in shared memory that the resource is used */
+ in_use[resource_id] = true;
+ break;
+ }
+ }
+
+#if 0
+ /* Write-back if a in-use flag was changed */
+ if (flag == true && sharedregion_is_cache_enabled(0))
+ Cache_wbInv(in_use, num * sizeof(u8), Cache_Type_ALL, true);
+#endif
+
+ /* Done with the critical section */
+ if (default_gate)
+ gatemp_leave(default_gate, key);
+
+ if (flag == false)
+ resource_id = -1;
+
+ return resource_id;
+}
+
+void *gatemp_create(const struct gatemp_params *params)
+{
+ struct _gatemp_params _params;
+ struct gatemp_object *handle = NULL;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(gatemp_module->ref_count),
+ GATEMP_MAKE_MAGICSTAMP(0),
+ GATEMP_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(params == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(params->shared_addr == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ memset(&_params, 0, sizeof(struct _gatemp_params));
+ memcpy(&_params, params, sizeof(struct gatemp_params));
+
+ handle = _gatemp_create(&_params);
+
+exit:
+ if (retval < 0)
+ pr_err("gatemp_create failed! status = 0x%x", retval);
+ return (void *)handle;
+}
+
+static struct gatemp_object *_gatemp_create(const struct _gatemp_params *params)
+{
+ struct gatemp_object *obj = NULL;
+ s32 retval = 0;
+ int *key;
+
+ /* No parameter checking since internal function */
+
+ obj = kmalloc(sizeof(struct gatemp_object), GFP_KERNEL);
+ if (obj == NULL) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ obj->status = gatemp_instance_init(obj, params);
+ if (obj->status != 0) {
+ retval = -1;
+ goto gatemp_init_fail;
+ }
+
+ key = Gate_enterSystem();
+ if (gatemp_first_object == NULL) {
+ gatemp_first_object = obj;
+ obj->next = NULL;
+ } else {
+ obj->next = gatemp_first_object;
+ gatemp_first_object = obj;
+ }
+ Gate_leaveSystem(key);
+ return (void *)obj;
+
+gatemp_init_fail:
+ kfree(obj);
+ obj = NULL;
+exit:
+ pr_err("_gatemp_create failed! status = 0x%x", retval);
+ return (void *)NULL;
+}
+
+int gatemp_delete(void **handle)
+{
+ int *key;
+ struct gatemp_object *temp;
+ bool found = false;
+ int retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(gatemp_module->ref_count),
+ GATEMP_MAKE_MAGICSTAMP(0),
+ GATEMP_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely((handle == NULL) || (*handle == NULL)))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ key = Gate_enterSystem();
+ if ((struct gatemp_object *)*handle == gatemp_first_object) {
+ gatemp_first_object = ((struct gatemp_object *)(*handle))->next;
+ found = true;
+ } else {
+ temp = gatemp_first_object;
+ while (temp) {
+ if (temp->next == (struct gatemp_object *)(*handle)) {
+ temp->next = ((struct gatemp_object *)
+ (*handle))->next;
+ found = true;
+ break;
+ } else {
+ temp = temp->next;
+ }
+ }
+ }
+ Gate_leaveSystem(key);
+
+ if (found == false) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ gatemp_instance_finalize(*handle, ((struct gatemp_object *)
+ (*handle))->status);
+ kfree((*handle));
+ *handle = NULL;
+ return 0;
+
+exit:
+ pr_err("gatemp_delete failed! status = 0x%x", retval);
+ return retval;
+}
+
+int gatemp_attach(u16 remote_proc_id, void *shared_addr)
+{
+ int retval = 0;
+ void *gatemp_shared_addr;
+ struct sharedregion_entry entry;
+ void *default_gate;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(gatemp_module->ref_count),
+ GATEMP_MAKE_MAGICSTAMP(0),
+ GATEMP_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(shared_addr == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (atomic_inc_return(&gatemp_module->attach_ref_count) != 1)
+ return 1;
+
+ /* get region 0 information */
+ sharedregion_get_entry(0, &entry);
+
+ gatemp_shared_addr = (void *)((u32)shared_addr +
+ gatemp_get_region0_reserved_size());
+
+ if ((entry.owner_proc_id != multiproc_self()) &&
+ (entry.owner_proc_id != SHAREDREGION_DEFAULTOWNERID)) {
+ gatemp_module->is_owner = false;
+
+ /* if not the owner of the SharedRegion */
+ gatemp_open_region0_reserved(shared_addr);
+
+ /* open the gate by address */
+ retval = gatemp_open_by_addr(gatemp_shared_addr, &default_gate);
+ /* set the default GateMP for opener */
+ if (retval >= 0)
+ gatemp_set_default_remote(default_gate);
+ }
+
+exit:
+ if (retval < 0)
+ pr_err("gatemp_attach failed! status = 0x%x", retval);
+ return retval;
+}
+
+int gatemp_detach(u16 remote_proc_id, void *shared_addr)
+{
+ int retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(gatemp_module->ref_count),
+ GATEMP_MAKE_MAGICSTAMP(0),
+ GATEMP_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(shared_addr == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (!(atomic_dec_return(&gatemp_module->attach_ref_count) == 0))
+ return 1;
+
+ /* if entry owner proc is not specified return */
+ if (gatemp_module->is_owner == false) {
+ gatemp_close_region0_reserved(shared_addr);
+
+ retval = gatemp_close((void **)&gatemp_module->default_gate);
+
+ /* set the default GateMP for opener */
+ gatemp_set_default_remote(NULL);
+ }
+
+exit:
+ if (retval < 0)
+ pr_err("gatemp_detach failed! status = 0x%x", retval);
+ return retval;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/gatemp_ioctl.c b/drivers/dsp/syslink/multicore_ipc/gatemp_ioctl.c
new file mode 100644
index 00000000000..68071d92530
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/gatemp_ioctl.c
@@ -0,0 +1,445 @@
+/*
+ * gatemp_ioctl.c
+ *
+ * The Gate Peterson Algorithm for mutual exclusion of shared memory.
+ * Current implementation works for 2 processors.
+ *
+ * Copyright (C) 2008-2009 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 <linux/uaccess.h>
+#include <linux/types.h>
+#include <linux/bug.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <ipc.h>
+#include <gatemp.h>
+#include <gatemp_ioctl.h>
+#include <sharedregion.h>
+
+static struct resource_info *find_gatemp_resource(
+ struct ipc_process_context *pr_ctxt,
+ unsigned int cmd,
+ struct gatemp_cmd_args *cargs)
+{
+ struct resource_info *info = NULL;
+ bool found = false;
+
+ spin_lock(&pr_ctxt->res_lock);
+
+ list_for_each_entry(info, &pr_ctxt->resources, res) {
+ struct gatemp_cmd_args *args =
+ (struct gatemp_cmd_args *)info->data;
+ if (info->cmd == cmd) {
+ switch (cmd) {
+ case CMD_GATEMP_DELETE:
+ {
+ void *handle =
+ args->args.delete_instance.handle;
+ void *temp =
+ cargs->args.delete_instance.handle;
+ if (temp == handle)
+ found = true;
+ break;
+ }
+ case CMD_GATEMP_DESTROY:
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found == true)
+ break;
+ }
+ }
+
+ spin_unlock(&pr_ctxt->res_lock);
+
+ if (found == false)
+ info = NULL;
+
+ return info;
+}
+
+/* ioctl interface to gatemp_get_config function*/
+static int gatemp_ioctl_get_config(struct gatemp_cmd_args *cargs)
+{
+ struct gatemp_config config;
+ s32 status = 0;
+ s32 size;
+
+ gatemp_get_config(&config);
+ size = copy_to_user((void __user *)cargs->args.get_config.config,
+ &config, sizeof(struct gatemp_config));
+ if (size)
+ status = -EFAULT;
+
+ cargs->api_status = 0;
+ return status;
+}
+
+/* ioctl interface to gatemp_setup function */
+static int gatemp_ioctl_setup(struct gatemp_cmd_args *cargs)
+{
+ struct gatemp_config config;
+ s32 status = 0;
+ s32 size;
+
+ size = copy_from_user(&config, (void __user *)cargs->args.setup.config,
+ sizeof(struct gatemp_config));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ cargs->api_status = gatemp_setup(&config);
+
+exit:
+ return status;
+}
+
+/* ioctl interface to gatemp_destroy function */
+static int gatemp_ioctl_destroy(struct gatemp_cmd_args *cargs)
+{
+ cargs->api_status = gatemp_destroy();
+ return 0;
+}
+
+/* ioctl interface to gatemp_params_init function */
+static int gatemp_ioctl_params_init(struct gatemp_cmd_args *cargs)
+{
+ struct gatemp_params params;
+ s32 status = 0;
+ s32 size;
+
+ gatemp_params_init(&params);
+ size = copy_to_user((void __user *)cargs->args.params_init.params,
+ &params, sizeof(struct gatemp_params));
+ if (size)
+ status = -EFAULT;
+
+ cargs->api_status = 0;
+ return status;
+}
+
+/* ioctl interface to gatemp_create function */
+static int gatemp_ioctl_create(struct gatemp_cmd_args *cargs)
+{
+ struct gatemp_params params;
+ s32 status = 0;
+ s32 size;
+
+ cargs->api_status = -1;
+ size = copy_from_user(&params, (void __user *)cargs->args.create.params,
+ sizeof(struct gatemp_params));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ if (cargs->args.create.name_len > 0) {
+ params.name = kmalloc(cargs->args.create.name_len, GFP_KERNEL);
+ if (params.name == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ params.name[cargs->args.create.name_len] = '\0';
+ size = copy_from_user(params.name,
+ (void __user *)cargs->args.create.params->name,
+ cargs->args.create.name_len);
+ if (size) {
+ status = -EFAULT;
+ goto name_from_usr_error;
+ }
+
+ }
+
+ params.shared_addr = sharedregion_get_ptr(
+ (u32 *)cargs->args.create.shared_addr_srptr);
+ cargs->args.create.handle = gatemp_create(&params);
+ if (cargs->args.create.handle != NULL)
+ cargs->api_status = 0;
+
+name_from_usr_error:
+ if (cargs->args.open.name_len > 0)
+ kfree(params.name);
+
+exit:
+ return status;
+}
+
+/* ioctl interface to gatemp_ioctl_delete function */
+static int gatemp_ioctl_delete(struct gatemp_cmd_args *cargs)
+
+{
+ cargs->api_status = gatemp_delete(&cargs->args.delete_instance.handle);
+ return 0;
+}
+
+/* ioctl interface to gatemp_open function */
+static int gatemp_ioctl_open(struct gatemp_cmd_args *cargs)
+{
+ struct gatemp_params params;
+ void *handle = NULL;
+ s32 status = 0;
+ s32 size;
+
+ gatemp_params_init(&params);
+ if (cargs->args.open.name_len > 0) {
+ params.name = kmalloc(cargs->args.open.name_len, GFP_KERNEL);
+ if (params.name == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ params.name[cargs->args.open.name_len] = '\0';
+ size = copy_from_user(params.name,
+ (void __user *)cargs->args.open.name,
+ cargs->args.open.name_len);
+ if (size) {
+ status = -EFAULT;
+ goto name_from_usr_error;
+ }
+ }
+
+ cargs->api_status = gatemp_open(params.name, &handle);
+ cargs->args.open.handle = handle;
+
+name_from_usr_error:
+ if (cargs->args.open.name_len > 0)
+ kfree(params.name);
+
+exit:
+ return status;
+}
+
+/* ioctl interface to gatemp_close function */
+static int gatemp_ioctl_close(struct gatemp_cmd_args *cargs)
+{
+ cargs->api_status = gatemp_close(&cargs->args.close.handle);
+ return 0;
+}
+
+/* ioctl interface to gatemp_enter function */
+static int gatemp_ioctl_enter(struct gatemp_cmd_args *cargs)
+{
+ cargs->args.enter.flags = gatemp_enter(cargs->args.enter.handle);
+ cargs->api_status = 0;
+ return 0;
+}
+
+/* ioctl interface to gatemp_leave function */
+static int gatemp_ioctl_leave(struct gatemp_cmd_args *cargs)
+{
+ gatemp_leave(cargs->args.leave.handle, cargs->args.leave.flags);
+ cargs->api_status = 0;
+ return 0;
+}
+
+/* ioctl interface to gatemp_shared_mem_req function */
+static int gatemp_ioctl_shared_mem_req(struct gatemp_cmd_args *cargs)
+{
+ struct gatemp_params params;
+ s32 status = 0;
+ s32 size;
+
+ size = copy_from_user(&params,
+ (void __user *)cargs->args.shared_mem_req.params,
+ sizeof(struct gatemp_params));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ cargs->args.shared_mem_req.ret_val =
+ gatemp_shared_mem_req(cargs->args.shared_mem_req.params);
+ cargs->api_status = 0;
+
+exit:
+ return status;
+}
+
+/* ioctl interface to gatemp_open_by_addr function */
+static int gatemp_ioctl_open_by_addr(struct gatemp_cmd_args *cargs)
+{
+ void *shared_addr = NULL;
+ void *handle = NULL;
+ s32 status = 0;
+
+ /* For open by name, the shared_add_srptr may be invalid */
+ if (cargs->args.open_by_addr.shared_addr_srptr != \
+ SHAREDREGION_INVALIDSRPTR) {
+ shared_addr = sharedregion_get_ptr((u32 *)cargs->args.
+ open_by_addr.shared_addr_srptr);
+ }
+ cargs->api_status = gatemp_open_by_addr(shared_addr, &handle);
+ cargs->args.open.handle = handle;
+
+ return status;
+}
+
+/* ioctl interface to gatemp_ioctl_get_default_remote function */
+static int gatemp_ioctl_get_default_remote(struct gatemp_cmd_args *cargs)
+{
+ void *handle = NULL;
+
+ handle = gatemp_get_default_remote();
+ cargs->args.get_default_remote.handle = handle;
+ cargs->api_status = 0;
+
+ return 0;
+}
+
+/* ioctl interface for gatemp module */
+int gatemp_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user)
+{
+ s32 status = 0;
+ s32 size = 0;
+ struct gatemp_cmd_args __user *uarg =
+ (struct gatemp_cmd_args __user *)args;
+ struct gatemp_cmd_args cargs;
+ struct ipc_process_context *pr_ctxt =
+ (struct ipc_process_context *)filp->private_data;
+
+
+ if (user == true) {
+#ifdef CONFIG_SYSLINK_RECOVERY
+ if (ipc_recovering()) {
+ status = -EIO;
+ goto exit;
+ }
+#endif
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ status = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ status = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
+
+ if (status) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ /* Copy the full args from user-side */
+ size = copy_from_user(&cargs, uarg,
+ sizeof(struct gatemp_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ } else {
+ if (args != 0)
+ memcpy(&cargs, (void *)args,
+ sizeof(struct gatemp_cmd_args));
+ }
+
+ switch (cmd) {
+ case CMD_GATEMP_GETCONFIG:
+ status = gatemp_ioctl_get_config(&cargs);
+ break;
+
+ case CMD_GATEMP_SETUP:
+ status = gatemp_ioctl_setup(&cargs);
+ if (status >= 0)
+ add_pr_res(pr_ctxt, CMD_GATEMP_DESTROY, NULL);
+ break;
+
+ case CMD_GATEMP_DESTROY:
+ {
+ struct resource_info *info = NULL;
+ info = find_gatemp_resource(pr_ctxt, CMD_GATEMP_DESTROY,
+ &cargs);
+ status = gatemp_ioctl_destroy(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_GATEMP_PARAMS_INIT:
+ status = gatemp_ioctl_params_init(&cargs);
+ break;
+
+ case CMD_GATEMP_CREATE:
+ status = gatemp_ioctl_create(&cargs);
+ if (status >= 0) {
+ struct gatemp_cmd_args *temp = kmalloc(
+ sizeof(struct gatemp_cmd_args),
+ GFP_KERNEL);
+ if (WARN_ON(!temp)) {
+ status = -ENOMEM;
+ goto exit;
+ }
+ temp->args.delete_instance.handle =
+ cargs.args.create.handle;
+ add_pr_res(pr_ctxt, CMD_GATEMP_DELETE, (void *)temp);
+ }
+ break;
+
+ case CMD_GATEMP_DELETE:
+ {
+ struct resource_info *info = NULL;
+ info = find_gatemp_resource(pr_ctxt, CMD_GATEMP_DELETE,
+ &cargs);
+ status = gatemp_ioctl_delete(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_GATEMP_OPEN:
+ status = gatemp_ioctl_open(&cargs);
+ break;
+
+ case CMD_GATEMP_CLOSE:
+ status = gatemp_ioctl_close(&cargs);
+ break;
+
+ case CMD_GATEMP_ENTER:
+ status = gatemp_ioctl_enter(&cargs);
+ break;
+
+ case CMD_GATEMP_LEAVE:
+ status = gatemp_ioctl_leave(&cargs);
+ break;
+
+ case CMD_GATEMP_SHAREDMEMREQ:
+ status = gatemp_ioctl_shared_mem_req(&cargs);
+ break;
+
+ case CMD_GATEMP_OPENBYADDR:
+ status = gatemp_ioctl_open_by_addr(&cargs);
+ break;
+
+ case CMD_GATEMP_GETDEFAULTREMOTE:
+ status = gatemp_ioctl_get_default_remote(&cargs);
+ break;
+
+ default:
+ WARN_ON(cmd);
+ status = -ENOTTY;
+ break;
+ }
+
+ if (user == true) {
+ /* Copy the full args to the user-side. */
+ size = copy_to_user(uarg, &cargs,
+ sizeof(struct gatemp_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ }
+
+exit:
+ return status;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/gatepeterson.c b/drivers/dsp/syslink/multicore_ipc/gatepeterson.c
new file mode 100644
index 00000000000..21a58c20a1b
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/gatepeterson.c
@@ -0,0 +1,1010 @@
+/*
+ * gatepeterson.c
+ *
+ * The Gate Peterson Algorithm for mutual exclusion of shared memory.
+ * Current implementation works for 2 processors.
+ *
+ * Copyright (C) 2008-2009 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 <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <syslink/atomic_linux.h>
+#include <multiproc.h>
+#include <sharedregion.h>
+#include <gatemp.h>
+#include <igatempsupport.h>
+#include <igateprovider.h>
+#include <iobject.h>
+#include <gatepeterson.h>
+
+
+/* IPC stubs */
+
+#define GATEPETERSON_BUSY 1
+#define GATEPETERSON_FREE 0
+#define GATEPETERSON_VERSION 1
+#define GATEPETERSON_CREATED 0x08201997 /* Stamp to indicate GP
+ was created here */
+
+/* Cache line size */
+#define GATEPETERSON_CACHESIZE 128
+
+/* Macro to make a correct module magic number with ref_count */
+#define GATEPETERSON_MAKE_MAGICSTAMP(x) ((GATEPETERSON_MODULEID << 12) | (x))
+
+/*
+ * structure for gatepeterson module state
+ */
+struct gatepeterson_module_object {
+ atomic_t ref_count; /* Reference count */
+ struct list_head obj_list;
+ struct mutex *mod_lock; /* Lock for obj list */
+ struct gatepeterson_config cfg;
+ struct gatepeterson_config default_cfg;
+ struct gatepeterson_params def_inst_params; /* default instance
+ paramters */
+};
+
+/*
+ * Structure defining attribute parameters for the Gate Peterson module
+ */
+struct gatepeterson_attrs {
+ VOLATILE u16 creator_proc_id;
+ VOLATILE u16 opener_proc_id;
+};
+
+/*
+ * Structure defining internal object for the Gate Peterson
+ */
+struct gatepeterson_object {
+ IGATEPROVIDER_SUPEROBJECT; /* For inheritance from IGateProvider */
+ IOBJECT_SUPEROBJECT; /* For inheritance for IObject */
+ struct list_head elem;
+ VOLATILE struct gatepeterson_attrs *attrs; /* Instance attr */
+ VOLATILE u16 *flag[2]; /* Flags for processors */
+ VOLATILE u16 *turn; /* Indicates whoes turn it is now? */
+ u16 self_id; /* Self identifier */
+ u16 other_id; /* Other's identifier */
+ u32 nested; /* Counter to track nesting */
+ void *local_gate; /* Local lock handle */
+ enum igatempsupport_local_protect local_protect; /* Type of local
+ protection to be used */
+ struct gatepeterson_params params;
+ u32 ref_count; /* Local reference count */
+ u32 cache_line_size; /* Cache Line Size */
+ bool cache_enabled; /* Is cache enabled? */
+};
+
+
+/*
+ * Variable for holding state of the gatepeterson module
+ */
+static struct gatepeterson_module_object gatepeterson_state = {
+ .obj_list = LIST_HEAD_INIT(gatepeterson_state.obj_list),
+ .default_cfg.default_protection = GATEPETERSON_PROTECT_INTERRUPT,
+ .default_cfg.num_instances = 16,
+ .def_inst_params.shared_addr = NULL,
+ .def_inst_params.resource_id = 0x0,
+ .def_inst_params.region_id = 0x0
+};
+
+static struct gatepeterson_module_object *gatepeterson_module =
+ &gatepeterson_state;
+
+/* =============================================================================
+ * Internal functions
+ * =============================================================================
+ */
+#if 0
+static void *_gatepeterson_create(enum igatempsupport_local_protect
+ local_protect,
+ const struct gatepeterson_params *params,
+ bool create_flag);
+#endif
+
+static void gatepeterson_post_init(struct gatepeterson_object *obj);
+
+#if 0
+static bool gatepeterson_inc_refcount(const struct gatepeterson_params *params,
+ void **handle);
+#endif
+
+/* TODO: figure these out */
+#define gate_enter_system() (int *)0
+#define gate_leave_system(key) {}
+
+/* =============================================================================
+ * APIS
+ * =============================================================================
+ */
+/*
+ * ======== gatepeterson_get_config ========
+ * Purpose:
+ * This will get the default configuration parameters for gatepeterson
+ * module
+ */
+void gatepeterson_get_config(struct gatepeterson_config *config)
+{
+ if (WARN_ON(config == NULL))
+ goto exit;
+
+ if (atomic_cmpmask_and_lt(&(gatepeterson_module->ref_count),
+ GATEPETERSON_MAKE_MAGICSTAMP(0),
+ GATEPETERSON_MAKE_MAGICSTAMP(1)) == true)
+ memcpy(config, &gatepeterson_module->default_cfg,
+ sizeof(struct gatepeterson_config));
+ else
+ memcpy(config, &gatepeterson_module->cfg,
+ sizeof(struct gatepeterson_config));
+
+exit:
+ return;
+}
+EXPORT_SYMBOL(gatepeterson_get_config);
+
+/*
+ * ======== gatepeterson_setup ========
+ * Purpose:
+ * This will setup the gatepeterson module
+ */
+int gatepeterson_setup(const struct gatepeterson_config *config)
+{
+ struct gatepeterson_config tmp_cfg;
+ int *key = NULL;
+ s32 retval = 0;
+
+ key = gate_enter_system();
+
+ /* This sets the ref_count variable not initialized, upper 16 bits is
+ * written with module _id to ensure correctness of ref_count variable
+ */
+ atomic_cmpmask_and_set(&gatepeterson_module->ref_count,
+ GATEPETERSON_MAKE_MAGICSTAMP(0),
+ GATEPETERSON_MAKE_MAGICSTAMP(0));
+
+ if (atomic_inc_return(&gatepeterson_module->ref_count)
+ != GATEPETERSON_MAKE_MAGICSTAMP(1)) {
+ gate_leave_system(key);
+ return 1;
+ }
+
+ if (config == NULL) {
+ gatepeterson_get_config(&tmp_cfg);
+ config = &tmp_cfg;
+ }
+ gate_leave_system(key);
+
+ memcpy(&gatepeterson_module->cfg, config,
+ sizeof(struct gatepeterson_config));
+
+ gatepeterson_module->mod_lock = kmalloc(sizeof(struct mutex),
+ GFP_KERNEL);
+ if (gatepeterson_module->mod_lock == NULL) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+ mutex_init(gatepeterson_module->mod_lock);
+
+ /* Initialize object list */
+ INIT_LIST_HEAD(&gatepeterson_module->obj_list);
+
+ return 0;
+
+exit:
+ atomic_set(&gatepeterson_module->ref_count,
+ GATEPETERSON_MAKE_MAGICSTAMP(0));
+
+ pr_err("gatepeterson_setup failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(gatepeterson_setup);
+
+/*
+ * ======== gatepeterson_destroy ========
+ * Purpose:
+ * This will destroy the gatepeterson module
+ */
+int gatepeterson_destroy(void)
+{
+ struct gatepeterson_object *obj = NULL, *n;
+ struct mutex *lock = NULL;
+ s32 retval = 0;
+ int *key = NULL;
+
+ key = gate_enter_system();
+
+ if (atomic_cmpmask_and_lt(&(gatepeterson_module->ref_count),
+ GATEPETERSON_MAKE_MAGICSTAMP(0),
+ GATEPETERSON_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (!(atomic_dec_return(&gatepeterson_module->ref_count)
+ == GATEPETERSON_MAKE_MAGICSTAMP(0))) {
+ gate_leave_system(key);
+ retval = 1;
+ goto exit;
+ }
+ atomic_set(&gatepeterson_module->ref_count,
+ GATEPETERSON_MAKE_MAGICSTAMP(1));
+ /* Check if any gatepeterson instances have not been
+ * ideleted/closed so far, if there any, delete or close them
+ */
+ list_for_each_entry_safe(obj, n, &gatepeterson_module->obj_list, elem) {
+ gatepeterson_delete((void **)&obj);
+
+ if (list_empty(&gatepeterson_module->obj_list))
+ break;
+ }
+
+ /* Again reset ref_count. */
+ atomic_set(&gatepeterson_module->ref_count,
+ GATEPETERSON_MAKE_MAGICSTAMP(0));
+ gate_leave_system(key);
+
+ retval = mutex_lock_interruptible(gatepeterson_module->mod_lock);
+ if (retval != 0)
+ goto exit;
+
+ lock = gatepeterson_module->mod_lock;
+ gatepeterson_module->mod_lock = NULL;
+ memset(&gatepeterson_module->cfg, 0,
+ sizeof(struct gatepeterson_config));
+ mutex_unlock(lock);
+ kfree(lock);
+ return 0;
+
+exit:
+ if (retval < 0)
+ pr_err("gatepeterson_destroy failed status:%x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(gatepeterson_destroy);
+
+/*
+ * ======== gatepeterson_get_num_instances ========
+ * Purpose:
+ * Function to return the number of instances configured in the module.
+ */
+u32 gatepeterson_get_num_instances(void)
+{
+ return gatepeterson_module->default_cfg.num_instances;
+}
+EXPORT_SYMBOL(gatepeterson_get_num_instances);
+
+/*
+ * ======== gatepeterson_get_num_reserved ========
+ * Purpose:
+ * Function to return the number of instances not under GateMP's control.
+ */
+u32 gatepeterson_get_num_reserved(void)
+{
+ return 0;
+}
+EXPORT_SYMBOL(gatepeterson_get_num_reserved);
+
+/*
+ * ======== gatepeterson_locks_init ========
+ * Purpose:
+ * Function to initialize the locks.
+ */
+inline void gatepeterson_locks_init(void)
+{
+ /* Do nothing*/
+}
+
+/*
+ * ======== gatepeterson_params_init ========
+ * Purpose:
+ * This will Initialize this config-params structure with
+ * supplier-specified defaults before instance creation
+ */
+void gatepeterson_params_init(struct gatepeterson_params *params)
+{
+ int *key = NULL;
+
+ key = gate_enter_system();
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(gatepeterson_module->ref_count),
+ GATEPETERSON_MAKE_MAGICSTAMP(0),
+ GATEPETERSON_MAKE_MAGICSTAMP(1)) == true))
+ goto exit;
+
+ if (WARN_ON(params == NULL))
+ goto exit;
+
+ memcpy(params, &(gatepeterson_module->def_inst_params),
+ sizeof(struct gatepeterson_params));
+
+exit:
+ gate_leave_system(key);
+ return;
+}
+EXPORT_SYMBOL(gatepeterson_params_init);
+
+
+static int gatepeterson_instance_init(struct gatepeterson_object *obj,
+ enum igatempsupport_local_protect local_protect,
+ const struct gatepeterson_params *params)
+{
+ s32 retval = 0;
+
+ IGATEPROVIDER_OBJECTINITIALIZER(obj, gatepeterson);
+
+ if (params->shared_addr == NULL) {
+ retval = 1;
+ goto exit;
+ }
+
+ /* Create the local gate */
+ obj->local_gate = gatemp_create_local(
+ (enum gatemp_local_protect)local_protect);
+ obj->cache_enabled = sharedregion_is_cache_enabled(params->region_id);
+ obj->cache_line_size =
+ sharedregion_get_cache_line_size(params->region_id);
+
+ /* Settings for both the creator and opener */
+ if (obj->cache_line_size > sizeof(struct gatepeterson_attrs)) {
+ obj->attrs = params->shared_addr;
+ obj->flag[0] = (u16 *)((u32)(obj->attrs) +
+ obj->cache_line_size);
+ obj->flag[1] = (u16 *)((u32)(obj->flag[0]) +
+ obj->cache_line_size);
+ obj->turn = (u16 *)((u32)(obj->flag[1]) +
+ obj->cache_line_size);
+ } else {
+ obj->attrs = params->shared_addr;
+ obj->flag[0] = (u16 *)((u32)(obj->attrs) +
+ sizeof(struct gatepeterson_attrs));
+ obj->flag[1] = (u16 *)((u32)(obj->flag[0]) + sizeof(u16));
+ obj->turn = (u16 *)((u32)(obj->flag[1]) + sizeof(u16));
+ }
+ obj->nested = 0;
+
+ if (!params->open_flag) {
+ /* Creating. */
+ obj->self_id = 0;
+ obj->other_id = 1;
+ gatepeterson_post_init(obj);
+ } else {
+#if 0
+ Cache_inv((Ptr)obj->attrs, sizeof(struct gatepeterson_attrs),
+ Cache_Type_ALL, TRUE);
+#endif
+ if (obj->attrs->creator_proc_id == multiproc_self()) {
+ /* Opening locally */
+ obj->self_id = 0;
+ obj->other_id = 1;
+ } else {
+ /* Trying to open a gate remotely */
+ obj->self_id = 1;
+ obj->other_id = 0;
+ if (obj->attrs->opener_proc_id == MULTIPROC_INVALIDID) {
+ /* Opening remotely for the first time */
+ obj->attrs->opener_proc_id = multiproc_self();
+ } else if (obj->attrs->opener_proc_id !=
+ multiproc_self()) {
+ retval = -EACCES;
+ goto exit;
+ }
+#if 0
+ if (obj->cache_enabled) {
+ Cache_wbInv((Ptr)obj->attrs,
+ sizeof(struct gatepeterson_attrs),
+ Cache_Type_ALL, TRUE);
+ }
+#endif
+ }
+ }
+
+exit:
+ if (retval < 0)
+ pr_err("gatemp_instance_init failed! status = 0x%x", retval);
+ return retval;
+}
+
+static void gatepeterson_instance_finalize(struct gatepeterson_object *obj,
+ int status)
+{
+ switch (status) {
+ /* No break here. Fall through to the next. */
+ case 0:
+ {
+ /* Modify shared memory */
+ obj->attrs->opener_proc_id = MULTIPROC_INVALIDID;
+#if 0
+ Cache_wbInv((Ptr)obj->attrs, sizeof(GatePeterson_Attrs),
+ Cache_Type_ALL, TRUE);
+#endif
+ }
+ /* No break here. Fall through to the next. */
+
+ case 1:
+ {
+ /* Nothing to be done. */
+ }
+ }
+ return;
+}
+
+
+
+#if 0
+/*
+ * ======== gatepeterson_create ========
+ * Purpose:
+ * This will creates a new instance of gatepeterson module
+ */
+void *gatepeterson_create(enum igatempsupport_local_protect local_protect,
+ const struct gatepeterson_params *params)
+{
+ void *handle = NULL;
+ s32 retval = 0;
+
+ BUG_ON(params == NULL);
+ if (atomic_cmpmask_and_lt(&(gatepeterson_module->ref_count),
+ GATEPETERSON_MAKE_MAGICSTAMP(0),
+ GATEPETERSON_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (WARN_ON(params->shared_addr == NULL)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ handle = _gatepeterson_create(local_protect, params, true);
+ return handle;
+
+exit:
+ return NULL;
+}
+EXPORT_SYMBOL(gatepeterson_create);
+
+/*
+ * ======== gatepeterson_delete ========
+ * Purpose:
+ * This will deletes an instance of gatepeterson module
+ */
+int gatepeterson_delete(void **gphandle)
+
+{
+ struct gatepeterson_object *obj = NULL;
+ s32 retval;
+
+ BUG_ON(gphandle == NULL);
+ BUG_ON(*gphandle == NULL);
+ if (atomic_cmpmask_and_lt(&(gatepeterson_module->ref_count),
+ GATEPETERSON_MAKE_MAGICSTAMP(0),
+ GATEPETERSON_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ obj = (struct gatepeterson_object *)(*gphandle);
+ if (unlikely(obj == NULL)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (unlikely(obj->attrs == NULL)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ /* Check if we have created the GP or not */
+ if (WARN_ON(unlikely(obj->attrs->creator_proc_id !=
+ multiproc_get_id(NULL)))) {
+ retval = -EACCES;
+ goto exit;
+ }
+
+ if (obj->ref_count != 0) {
+ retval = -EBUSY;
+ goto exit;
+ }
+
+ retval = mutex_lock_interruptible(gatepeterson_module->mod_lock);
+ if (retval)
+ goto exit;
+
+ list_del(&obj->elem); /* Remove the GP instance from the GP list */
+ mutex_unlock(gatepeterson_module->mod_lock);
+ /* Modify shared memory */
+ obj->attrs->opener_proc_id = MULTIPROC_INVALIDID;
+#if 0
+ Cache_wbInv((Ptr)obj->attrs, sizeof(struct gatepeterson_attrs),
+ Cache_Type_ALL, true);
+#endif
+
+ kfree(obj);
+ *gphandle = NULL;
+ return 0;
+
+exit:
+ pr_err("gatepeterson_delete failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(gatepeterson_delete);
+
+#else
+
+/* Override the IObject interface to define create and delete APIs */
+IOBJECT_CREATE1(gatepeterson, enum igatempsupport_local_protect);
+
+#endif
+
+#if 0
+/*
+ * ======== gatepeterson_open ========
+ * Purpose:
+ * This will opens a created instance of gatepeterson
+ * module by shared addr.
+ */
+int gatepeterson_open_by_addr(enum igatempsupport_local_protect local_protect,
+ void *shared_addr, void **handle_ptr)
+{
+ void *temp = NULL;
+ s32 retval = 0;
+ struct gatepeterson_params params;
+
+ BUG_ON(shared_addr == NULL);
+ BUG_ON(handle_ptr == NULL);
+ if (atomic_cmpmask_and_lt(&(gatepeterson_module->ref_count),
+ GATEPETERSON_MAKE_MAGICSTAMP(0),
+ GATEPETERSON_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (shared_addr == NULL) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (handle_ptr == NULL) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (gatepeterson_inc_refcount(&params, &temp)) {
+ retval = -EBUSY;
+ goto exit; /* It's already opened from local processor */
+ }
+
+ gatepeterson_params_init(&params);
+ params.shared_addr = shared_addr;
+ params.region_id = sharedregion_get_id(shared_addr);
+
+ *handle_ptr = _gatepeterson_create(local_protect, &params, false);
+ return 0;
+
+exit:
+ pr_err("gatepeterson_open failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(gatepeterson_open_by_addr);
+
+/*
+ * ======== gatepeterson_close ========
+ * Purpose:
+ * This will closes previously opened/created instance
+ * of gatepeterson module
+ */
+int gatepeterson_close(void **gphandle)
+{
+ struct gatepeterson_object *obj = NULL;
+ struct gatepeterson_params *params = NULL;
+ s32 retval = 0;
+
+ BUG_ON(gphandle == NULL);
+ if (atomic_cmpmask_and_lt(&(gatepeterson_module->ref_count),
+ GATEPETERSON_MAKE_MAGICSTAMP(0),
+ GATEPETERSON_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (WARN_ON(*gphandle == NULL)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct gatepeterson_object *) (*gphandle);
+ if (unlikely(obj == NULL)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ key = gatemp_enter(obj->local_gate);
+
+ if (obj->ref_count > 1) {
+ obj->ref_count--;
+ gatemp_leave(obj->local_gate, key);
+ goto exit;
+ }
+
+ retval = mutex_lock_interruptible(gatepeterson_module->mod_lock);
+ if (retval)
+ goto error_handle;
+
+ list_del(&obj->elem);
+ mutex_unlock(gatepeterson_module->mod_lock);
+ params = &obj->params;
+
+ gatemp_leave(obj->local_gate, key);
+
+ gatemp_delete(obj->local_gate);
+
+ kfree(obj);
+ *gphandle = NULL;
+ return 0;
+
+error_handle:
+ gatemp_leave(obj->local_gate, key);
+
+exit:
+ pr_err("gatepeterson_close failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(gatepeterson_close);
+#endif
+
+/*
+ * ======== gatepeterson_enter ========
+ * Purpose:
+ * This will enters the gatepeterson instance
+ */
+int *gatepeterson_enter(void *gphandle)
+{
+ struct gatepeterson_object *obj = NULL;
+ s32 retval = 0;
+ int *key = NULL;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(gatepeterson_module->ref_count),
+ GATEPETERSON_MAKE_MAGICSTAMP(0),
+ GATEPETERSON_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(gphandle == NULL)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct gatepeterson_object *) gphandle;
+
+ /* Enter local gate */
+ if (obj->local_gate != NULL) {
+ retval = mutex_lock_interruptible(obj->local_gate);
+ if (retval)
+ goto exit;
+ }
+
+ /* If the gate object has already been entered, return the key */
+ obj->nested++;
+ if (obj->nested > 1)
+ return key;
+
+ /* indicate, needs to use the resource. */
+ *((u32 *)obj->flag[obj->self_id]) = GATEPETERSON_BUSY ;
+#if 0
+ if (obj->cacheEnabled)
+ Cache_wbInv((Ptr)obj->flag[obj->selfId],
+ obj->cacheLineSize, Cache_Type_ALL, true);
+#endif
+ /* Give away the turn. */
+ *((u32 *)(obj->turn)) = obj->other_id;
+#if 0
+ if (obj->cacheEnabled) {
+ Cache_wbInv((Ptr)obj->turn, obj->cacheLineSize,
+ Cache_Type_ALL, true);
+ Cache_inv((Ptr)obj->flag[obj->otherId], obj->cacheLineSize,
+ Cache_Type_ALL, true);
+ }
+#endif
+
+ /* Wait while other processor is using the resource and has
+ * the turn
+ */
+ while ((*((VOLATILE u32 *) obj->flag[obj->other_id])
+ == GATEPETERSON_BUSY) &&
+ (*((VOLATILE u32 *)obj->turn) == obj->other_id)) {
+ /* Empty body loop */
+ /* Except for cache stuff */
+#if 0
+ if (obj->cacheEnabled) {
+ Cache_inv((Ptr)obj->flag[obj->otherId], obj->
+ cacheLineSize, Cache_Type_ALL, true);
+ Cache_inv((Ptr)obj->turn, obj->
+ cacheLineSize, Cache_Type_ALL, true);
+ }
+ udelay(10);
+#endif
+ }
+
+ return key;
+
+exit:
+ return NULL;
+}
+EXPORT_SYMBOL(gatepeterson_enter);
+
+/*
+ * ======== gatepeterson_leave ========
+ * Purpose:
+ * This will leaves the gatepeterson instance
+ */
+void gatepeterson_leave(void *gphandle, int *key)
+{
+ struct gatepeterson_object *obj = NULL;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(gatepeterson_module->ref_count),
+ GATEPETERSON_MAKE_MAGICSTAMP(0),
+ GATEPETERSON_MAKE_MAGICSTAMP(1)) == true))
+ goto exit;
+
+ BUG_ON(gphandle == NULL);
+
+ obj = (struct gatepeterson_object *)gphandle;
+
+ /* Release the resource and leave system gate. */
+ obj->nested--;
+ if (obj->nested == 0) {
+ *((VOLATILE u32 *)obj->flag[obj->self_id]) = GATEPETERSON_FREE;
+#if 0
+ if (obj->cacheEnabled)
+ Cache_wbInv((Ptr)obj->flag[obj->selfId],
+ obj->cacheLineSize, Cache_Type_ALL, true);
+#endif
+ }
+ /* Leave local gate */
+ mutex_unlock(obj->local_gate);
+
+exit:
+ return;
+}
+EXPORT_SYMBOL(gatepeterson_leave);
+
+/*
+ * ======== gatepeterson_shared_mem_req ========
+ * Purpose:
+ * This will give the amount of shared memory required
+ * for creation of each instance
+ */
+u32 gatepeterson_shared_mem_req(const struct gatepeterson_params *params)
+{
+ u32 mem_req = 0;
+
+ if (sharedregion_get_cache_line_size(params->region_id) >=
+ sizeof(struct gatepeterson_attrs))
+ /* 4 Because shared of shared memory usage */
+ mem_req = 4 * sharedregion_get_cache_line_size(params->
+ region_id);
+ else
+ mem_req = sizeof(struct gatepeterson_attrs) +
+ sizeof(u16) * 3;
+
+ return mem_req;
+}
+EXPORT_SYMBOL(gatepeterson_shared_mem_req);
+
+/*
+ *************************************************************************
+ * Internal functions
+ *************************************************************************
+ */
+#if 0
+/*
+ * ======== gatepeterson_create ========
+ * Purpose:
+ * Creates a new instance of gatepeterson module.
+ * This is an internal function because both
+ * gatepeterson_create and gatepeterson_open
+ * call use the same functionality.
+ */
+static void *_gatepeterson_create(enum igatempsupport_local_protect
+ local_protect, const struct gatepeterson_params *params,
+ bool create_flag)
+{
+ int status = 0;
+ struct gatepeterson_object *handle = NULL;
+ struct gatepeterson_obj *obj = NULL;
+
+ handle = kmalloc(sizeof(struct gatepeterson_object), GFP_KERNEL);
+ if (handle == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ obj = kmalloc(sizeof(struct gatepeterson_obj), GFP_KERNEL);
+ if (obj == NULL) {
+ status = -ENOMEM;
+ goto obj_alloc_fail;
+ }
+
+ if (local_protect >= GATEPETERSON_PROTECT_END_VALUE) {
+ status = -EINVAL;
+ goto exit_with_cleanup;
+ }
+
+ handle->obj = obj;
+ handle->enter = &gatepeterson_enter;
+ handle->leave = &gatepeterson_leave;
+
+ /* Create the local gate */
+ obj->local_gate = gatemp_create_local(local_protect);
+ obj->cache_enabled = sharedregion_is_cache_enabled(params->region_id);
+ obj->cache_line_size = sharedregion_get_cache_line_size(params->
+ region_id);
+
+ /* Settings for both the creator and opener */
+ if (obj->cache_line_size > sizeof(struct gatepeterson_attrs)) {
+ obj->attrs = params->shared_addr;
+ obj->flag[0] = (u16 *)((u32)(obj->attrs) + obj->
+ cache_line_size);
+ obj->flag[1] = (u16 *)((u32)(obj->flag[0]) + obj->
+ cache_line_size);
+ obj->turn = (u16 *)((u32)(obj->flag[1]) + obj->
+ cache_line_size);
+ } else {
+ obj->attrs = params->shared_addr;
+ obj->flag[0] = (u16 *)((u32)(obj->attrs) +
+ sizeof(struct gatepeterson_attrs));
+ obj->flag[1] = (u16 *)((u32)(obj->flag[0]) + sizeof(u16));
+ obj->turn = (u16 *)((u32)(obj->flag[1]) + sizeof(u16));
+ }
+ obj->nested = 0;
+
+ if (params->open_flag == false) {
+ /* Creating. */
+ obj->self_id = 0;
+ obj->other_id = 1;
+ obj->ref_count = 0;
+ gatepeterson_post_init(obj);
+ } else {
+#if 0
+ Cache_inv((Ptr)obj->attrs, sizeof(struct gatepeterson_attrs),
+ Cache_Type_ALL, true);
+#endif
+ obj->ref_count = 1;
+ if (obj->attrs->creator_proc_id == multiproc_self()) {
+ /* Opening locally */
+ obj->self_id = 0;
+ obj->other_id = 1;
+ } else {
+ /* Trying to open a gate remotely */
+ obj->self_id = 1;
+ obj->other_id = 0;
+ if (obj->attrs->opener_proc_id == MULTIPROC_INVALIDID)
+ /* Opening remotely for the first time */
+ obj->attrs->opener_proc_id = multiproc_self();
+ else if (obj->attrs->opener_proc_id !=
+ multiproc_self()) {
+ status = -EFAULT;
+ goto exit_with_cleanup;
+ }
+#if 0
+ if (status >= 0) {
+ if (obj->cache_enabled) {
+ Cache_wbInv((Ptr)obj->attrs,
+ sizeof(struct gatepeterson_attrs),
+ Cache_Type_ALL, true);
+ }
+ }
+#endif
+ }
+ }
+
+ status = mutex_lock_interruptible(gatepeterson_module->mod_lock);
+ if (status)
+ goto mod_lock_fail;
+
+ list_add_tail(&obj->elem, &gatepeterson_module->obj_list);
+ mutex_unlock(gatepeterson_module->mod_lock);
+
+ return handle;
+mod_lock_fail:
+exit_with_cleanup:
+ gatemp_delete(&obj->local_gate);
+ kfree(obj);
+
+obj_alloc_fail:
+ kfree(handle);
+ handle = NULL;
+
+exit:
+ if (create_flag == true)
+ pr_err("_gatepeterson_create (create) failed "
+ "status: %x\n", status);
+ else
+ pr_err("_gatepeterson_create (open) failed "
+ "status: %x\n", status);
+
+ return NULL;
+}
+
+#endif
+
+/*
+ * ======== gatepeterson_post_init ========
+ * Purpose:
+ * Function to be called during
+ * 1. module startup to complete the initialization of all static instances
+ * 2. instance_init to complete the initialization of a dynamic instance
+ *
+ * Main purpose is to set up shared memory
+ */
+static void gatepeterson_post_init(struct gatepeterson_object *obj)
+{
+ /* Set up shared memory */
+ *(obj->turn) = 0;
+ *(obj->flag[0]) = 0;
+ *(obj->flag[1]) = 0;
+ obj->attrs->creator_proc_id = multiproc_self();
+ obj->attrs->opener_proc_id = MULTIPROC_INVALIDID;
+#if 0
+ /*
+ * Write everything back to memory. This assumes that obj->attrs is
+ * equal to the shared memory base address
+ */
+ if (obj->cacheEnabled) {
+ Cache_wbInv((Ptr)obj->attrs, sizeof(struct gatepeterson_attrs),
+ Cache_Type_ALL, false);
+ Cache_wbInv((Ptr)(obj->flag[0]), obj->cacheLineSize * 3,
+ Cache_Type_ALL, true);
+ }
+#endif
+}
+
+#if 0
+/*
+ * ======== gatepeterson_inc_refcount ========
+ * Purpose:
+ * This will increment the reference count while opening
+ * a GP instance if it is already opened from local processor
+ */
+static bool gatepeterson_inc_refcount(const struct gatepeterson_params *params,
+ void **handle)
+{
+ struct gatepeterson_object *obj = NULL;
+ s32 retval = 0;
+ bool done = false;
+
+ list_for_each_entry(obj, &gatepeterson_module->obj_list, elem) {
+ if (params->shared_addr != NULL) {
+ if (obj->params.shared_addr == params->shared_addr) {
+ retval = mutex_lock_interruptible(
+ gatepeterson_module->mod_lock);
+ if (retval)
+ break;
+
+ obj->ref_count++;
+ *handle = obj;
+ mutex_unlock(gatepeterson_module->mod_lock);
+ done = true;
+ break;
+ }
+ }
+ }
+
+ return done;
+}
+#endif
diff --git a/drivers/dsp/syslink/multicore_ipc/heap.c b/drivers/dsp/syslink/multicore_ipc/heap.c
new file mode 100644
index 00000000000..479174dab1a
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/heap.c
@@ -0,0 +1,114 @@
+/*
+ * heap.c
+ *
+ * Heap module manages fixed size buffers that can be used
+ * in a multiprocessor system with shared memory
+ *
+ * Copyright (C) 2008-2009 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 <linux/types.h>
+#include <linux/bug.h>
+
+
+#include <heap.h>
+
+
+/*
+ * ======== sl_heap_alloc ========
+ * Purpose:
+ * This will allocate a block of memory of specified
+ * size
+ */
+void *sl_heap_alloc(void *hphandle, u32 size, u32 align)
+{
+ char *block = NULL;
+ struct heap_object *obj = NULL;
+
+ BUG_ON(hphandle == NULL);
+
+ obj = (struct heap_object *)hphandle;
+ BUG_ON(obj->alloc == NULL);
+ block = obj->alloc(hphandle, size, align);
+ return block;
+}
+
+/*
+ * ======== sl_heap_free ========
+ * Purpose:
+ * This will frees a block of memory allocated
+ * rom heap
+ */
+int sl_heap_free(void *hphandle, void *block, u32 size)
+{
+ struct heap_object *obj = NULL;
+ s32 retval = 0;
+
+ BUG_ON(hphandle == NULL);
+
+ obj = (struct heap_object *)hphandle;
+ BUG_ON(obj->free == NULL);
+ retval = obj->free(hphandle, block, size);
+ return retval;
+}
+
+/*
+ * ======== sl_heap_get_stats ========
+ * Purpose:
+ * This will get the heap memory statistics
+ */
+void sl_heap_get_stats(void *hphandle, struct memory_stats *stats)
+{
+ struct heap_object *obj = NULL;
+
+ BUG_ON(hphandle == NULL);
+ BUG_ON(stats == NULL);
+
+ obj = (struct heap_object *)hphandle;
+ BUG_ON(obj->get_stats == NULL);
+ obj->get_stats(hphandle, stats);
+}
+
+/*
+ * ======== sl_heap_get_extended_stats ========
+ * Purpose:
+ * This will get the heap memory extended statistics
+ */
+void sl_heap_get_extended_stats(void *hphandle,
+ struct heap_extended_stats *stats)
+{
+ struct heap_object *obj = NULL;
+
+ BUG_ON(hphandle == NULL);
+ BUG_ON(stats == NULL);
+
+ obj = (struct heap_object *)hphandle;
+ BUG_ON(obj->get_extended_stats == NULL);
+ obj->get_extended_stats(hphandle, stats);
+}
+
+
+/*
+ * ======== sl_heap_is_blocking ========
+ * Purpose:
+ * Indicates whether the heap may block during an alloc or free call
+ */
+bool sl_heap_is_blocking(void *hphandle)
+{
+ struct heap_object *obj = NULL;
+
+ BUG_ON(hphandle == NULL);
+
+ obj = (struct heap_object *)hphandle;
+ BUG_ON(obj->is_blocking == NULL);
+
+ return obj->is_blocking(hphandle);
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/heapbufmp.c b/drivers/dsp/syslink/multicore_ipc/heapbufmp.c
new file mode 100644
index 00000000000..7840c79fe1d
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/heapbufmp.c
@@ -0,0 +1,1555 @@
+/*
+ * heapbufmp.c
+ *
+ * Heap module manages variable size buffers that can be used
+ * in a multiprocessor system with shared memory.
+ *
+ * Copyright(C) 2008-2009 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 <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <atomic_linux.h>
+#include <multiproc.h>
+#include <nameserver.h>
+#include <sharedregion.h>
+#include <gatemp.h>
+#include <heapbufmp.h>
+
+/*
+ * Name of the reserved nameserver used for heapbufmp.
+ */
+#define HEAPBUFMP_NAMESERVER "HeapBufMP"
+/* brief Macro to make a correct module magic number with ref_count */
+#define HEAPBUFMP_MAKE_MAGICSTAMP(x) ((HEAPBUFMP_MODULEID << 12) | (x))
+/* Max heapbufmp name length */
+#define HEAPBUFMP_MAX_NAME_LEN 32
+/* Max number of runtime entries */
+#define HEAPBUFMP_MAX_RUNTIME_ENTRIES 32
+
+#define ROUND_UP(a, b) (((a) + ((b) - 1)) & (~((b) - 1)))
+
+/*
+ * Structure defining attribute parameters for the heapbufmp module
+ */
+struct heapbufmp_attrs {
+ VOLATILE u32 status; /* Module status */
+ VOLATILE u32 *gatemp_addr; /* gatemp shared address(shm safe) */
+ VOLATILE u32 *buf_ptr; /* Memory managed by instance */
+ VOLATILE u32 num_free_blocks; /* Number of free blocks */
+ VOLATILE u32 min_free_blocks; /* Min number of free blocks */
+ VOLATILE u32 block_size; /* True size of each block */
+ VOLATILE u32 align; /* Alignment of each block */
+ VOLATILE u32 num_blocks; /* Number of individual blocks */
+ VOLATILE u16 exact; /* For 'exact' allocation */
+};
+
+/*
+ * Structure defining processor related information for the
+ * heapbufmp module
+ */
+struct heapbufmp_proc_attrs {
+ bool creator; /* Creator or opener */
+ u16 proc_id; /* Processor identifier */
+ u32 open_count; /* open count in a processor */
+};
+
+/*
+ * Structure for heapbufmp module state
+ */
+struct heapbufmp_module_object {
+ atomic_t ref_count; /* Reference count */
+ void *nameserver; /* Nameserver handle */
+ struct list_head obj_list; /* List holding created objects */
+ struct mutex *local_lock; /* lock for protecting obj_list */
+ struct heapbufmp_config cfg; /* Current config values */
+ struct heapbufmp_config default_cfg; /* Default config values */
+ struct heapbufmp_params default_inst_params; /* Default instance
+ creation parameters */
+};
+
+static struct heapbufmp_module_object heapbufmp_state = {
+ .obj_list = LIST_HEAD_INIT(heapbufmp_state.obj_list),
+ .default_cfg.max_name_len = HEAPBUFMP_MAX_NAME_LEN,
+ .default_cfg.max_runtime_entries = HEAPBUFMP_MAX_RUNTIME_ENTRIES,
+ .default_cfg.track_allocs = false,
+ .default_inst_params.gate = NULL,
+ .default_inst_params.exact = false,
+ .default_inst_params.name = NULL,
+ .default_inst_params.align = 1u,
+ .default_inst_params.num_blocks = 0u,
+ .default_inst_params.block_size = 0u,
+ .default_inst_params.region_id = 0,
+ .default_inst_params.shared_addr = NULL,
+};
+
+/* Pointer to module state */
+static struct heapbufmp_module_object *heapbufmp_module = &heapbufmp_state;
+
+/*
+ * Structure for the handle for the heapbufmp
+ */
+struct heapbufmp_obj {
+ struct list_head list_elem; /* Used for creating a linked list */
+ struct heapbufmp_attrs *attrs; /* The shared attributes structure */
+ void *gate; /* Lock used for critical region management */
+ void *ns_key; /* nameserver key required for remove */
+ bool cache_enabled; /* Whether to do cache calls */
+ u16 region_id; /* shared region index */
+ u32 alloc_size; /* Size of allocated shared memory */
+ char *buf; /* Pointer to allocated memory */
+ void *free_list; /* List of free buffers */
+ u32 block_size; /* Adjusted block_size */
+ u32 align; /* Adjusted alignment */
+ u32 num_blocks; /* Number of blocks in buffer */
+ bool exact; /* Exact match flag */
+ struct heapbufmp_proc_attrs owner; /* owner processor info */
+ void *top; /* Pointer to the top object */
+ struct heapbufmp_params params; /* The creation parameter structure */
+};
+
+#define heapbufmp_object heap_object
+
+/* =============================================================================
+ * Forward declarations of internal functions
+ * =============================================================================
+ */
+static int heapbufmp_post_init(struct heapbufmp_object *handle);
+
+/* =============================================================================
+ * APIs called directly by applications
+ * =============================================================================
+ */
+/*
+ * ======== heapbufmp_get_config ========
+ * Purpose:
+ * This will get default configuration for the
+ * heapbufmp module
+ */
+int heapbufmp_get_config(struct heapbufmp_config *cfgparams)
+{
+ s32 retval = 0;
+
+ BUG_ON(cfgparams == NULL);
+
+ if (cfgparams == NULL) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (atomic_cmpmask_and_lt(&(heapbufmp_module->ref_count),
+ HEAPBUFMP_MAKE_MAGICSTAMP(0),
+ HEAPBUFMP_MAKE_MAGICSTAMP(1)) == true)
+ memcpy(cfgparams, &heapbufmp_module->default_cfg,
+ sizeof(struct heapbufmp_config));
+ else
+ memcpy(cfgparams, &heapbufmp_module->cfg,
+ sizeof(struct heapbufmp_config));
+ return 0;
+error:
+ pr_err("heapbufmp_get_config failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(heapbufmp_get_config);
+
+/*
+ * ======== heapbufmp_setup ========
+ * Purpose:
+ * This will setup the heapbufmp module
+ *
+ * This function sets up the heapbufmp module. This function
+ * must be called before any other instance-level APIs can be
+ * invoked.
+ * Module-level configuration needs to be provided to this
+ * function. If the user wishes to change some specific config
+ * parameters, then heapbufmp_getconfig can be called to get
+ * the configuration filled with the default values. After this,
+ * only the required configuration values can be changed. If the
+ * user does not wish to make any change in the default parameters,
+ * the application can simply call heapbufmp_setup with NULL
+ * parameters. The default parameters would get automatically used.
+ */
+int heapbufmp_setup(const struct heapbufmp_config *cfg)
+{
+ struct nameserver_params params;
+ struct heapbufmp_config tmp_cfg;
+ s32 retval = 0;
+
+ /* This sets the ref_count variable not initialized, upper 16 bits is
+ * written with module Id to ensure correctness of ref_count variable
+ */
+ atomic_cmpmask_and_set(&heapbufmp_module->ref_count,
+ HEAPBUFMP_MAKE_MAGICSTAMP(0),
+ HEAPBUFMP_MAKE_MAGICSTAMP(0));
+ if (atomic_inc_return(&heapbufmp_module->ref_count)
+ != HEAPBUFMP_MAKE_MAGICSTAMP(1)) {
+ return 1;
+ }
+
+ if (cfg == NULL) {
+ heapbufmp_get_config(&tmp_cfg);
+ cfg = &tmp_cfg;
+ }
+
+ if (cfg->max_name_len == 0 ||
+ cfg->max_name_len > HEAPBUFMP_MAX_NAME_LEN) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /* Initialize the parameters */
+ nameserver_params_init(&params);
+ params.max_value_len = sizeof(u32);
+ params.max_name_len = cfg->max_name_len;
+ params.max_runtime_entries = cfg->max_runtime_entries;
+
+ /* Create the nameserver for modules */
+ heapbufmp_module->nameserver =
+ nameserver_create(HEAPBUFMP_NAMESERVER, &params);
+ if (heapbufmp_module->nameserver == NULL) {
+ retval = -EFAULT;
+ goto error;
+ }
+
+ /* Construct the list object */
+ INIT_LIST_HEAD(&heapbufmp_module->obj_list);
+ /* Copy config info */
+ memcpy(&heapbufmp_module->cfg, cfg, sizeof(struct heapbufmp_config));
+ /* Create a lock for protecting list object */
+ heapbufmp_module->local_lock = kmalloc(sizeof(struct mutex),
+ GFP_KERNEL);
+ mutex_init(heapbufmp_module->local_lock);
+ if (heapbufmp_module->local_lock == NULL) {
+ retval = -ENOMEM;
+ heapbufmp_destroy();
+ goto error;
+ }
+
+ return 0;
+
+error:
+ pr_err("heapbufmp_setup failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(heapbufmp_setup);
+
+/*
+ * ======== heapbufmp_destroy ========
+ * Purpose:
+ * This will destroy the heapbufmp module
+ */
+int heapbufmp_destroy(void)
+{
+ s32 retval = 0;
+ struct mutex *lock = NULL;
+ struct heapbufmp_obj *obj = NULL;
+
+ if (atomic_cmpmask_and_lt(&(heapbufmp_module->ref_count),
+ HEAPBUFMP_MAKE_MAGICSTAMP(0),
+ HEAPBUFMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (atomic_dec_return(&heapbufmp_module->ref_count)
+ == HEAPBUFMP_MAKE_MAGICSTAMP(0)) {
+ /* Temporarily increment ref_count here. */
+ atomic_set(&heapbufmp_module->ref_count,
+ HEAPBUFMP_MAKE_MAGICSTAMP(1));
+
+ /* Check if any heapbufmp instances have not been
+ * deleted/closed so far. if there any, delete or close them
+ */
+ list_for_each_entry(obj, &heapbufmp_module->obj_list,
+ list_elem) {
+ if (obj->owner.proc_id == multiproc_get_id(NULL))
+ retval = heapbufmp_delete(&obj->top);
+ else
+ retval = heapbufmp_close(obj->top);
+
+ if (list_empty(&heapbufmp_module->obj_list))
+ break;
+
+ if (retval < 0)
+ goto error;
+ }
+
+ /* Again reset ref_count. */
+ atomic_set(&heapbufmp_module->ref_count,
+ HEAPBUFMP_MAKE_MAGICSTAMP(0));
+
+ if (likely(heapbufmp_module->nameserver != NULL)) {
+ retval = nameserver_delete(&heapbufmp_module->
+ nameserver);
+ if (unlikely(retval != 0))
+ goto error;
+ }
+
+ /* Delete the list lock */
+ lock = heapbufmp_module->local_lock;
+ retval = mutex_lock_interruptible(lock);
+ if (retval)
+ goto error;
+
+ heapbufmp_module->local_lock = NULL;
+ mutex_unlock(lock);
+ kfree(lock);
+ memset(&heapbufmp_module->cfg, 0,
+ sizeof(struct heapbufmp_config));
+ }
+
+ return 0;
+
+error:
+ pr_err("heapbufmp_destroy failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(heapbufmp_destroy);
+
+/*
+ * ======== heapbufmp_params_init ========
+ * Purpose:
+ * This will get the intialization prams for a heapbufmp
+ * module instance
+ */
+void heapbufmp_params_init(struct heapbufmp_params *params)
+{
+ s32 retval = 0;
+
+ if (atomic_cmpmask_and_lt(&(heapbufmp_module->ref_count),
+ HEAPBUFMP_MAKE_MAGICSTAMP(0),
+ HEAPBUFMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ BUG_ON(params == NULL);
+
+ memcpy(params, &heapbufmp_module->default_inst_params,
+ sizeof(struct heapbufmp_params));
+
+ return;
+error:
+ pr_err("heapbufmp_params_init failed status: %x\n", retval);
+}
+EXPORT_SYMBOL(heapbufmp_params_init);
+
+/*
+ * ======== _heapbufmp_create ========
+ * Purpose:
+ * This will create a new instance of heapbufmp module
+ * This is an internal function as both heapbufmp_create
+ * and heapbufmp_open use the functionality
+ *
+ * NOTE: The lock to protect the shared memory area
+ * used by heapbufmp is provided by the consumer of
+ * heapbufmp module
+ */
+static int _heapbufmp_create(void **handle_ptr,
+ const struct heapbufmp_params *params,
+ u32 create_flag)
+{
+ s32 retval = 0;
+ struct heapbufmp_obj *obj = NULL;
+ struct heapbufmp_object *handle = NULL;
+ void *gate_handle = NULL;
+ void *local_addr = NULL;
+ u32 *shared_shm_base;
+ u32 min_align;
+
+ if (atomic_cmpmask_and_lt(&(heapbufmp_module->ref_count),
+ HEAPBUFMP_MAKE_MAGICSTAMP(0),
+ HEAPBUFMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ /* No need for parameter checks, since this is an internal function. */
+
+ /* Initialize return parameter. */
+ *handle_ptr = NULL;
+
+ handle = kmalloc(sizeof(struct heapbufmp_object), GFP_KERNEL);
+ if (handle == NULL) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ obj = kmalloc(sizeof(struct heapbufmp_obj), GFP_KERNEL);
+ if (obj == NULL) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ handle->obj = (struct heapbufmp_obj *)obj;
+ handle->alloc = &heapbufmp_alloc;
+ handle->free = &heapbufmp_free;
+ handle->get_stats = &heapbufmp_get_stats;
+ handle->is_blocking = &heapbufmp_isblocking;
+
+ obj->ns_key = NULL;
+ obj->alloc_size = 0;
+
+ /* Put in local ilst */
+ retval = mutex_lock_interruptible(heapbufmp_module->local_lock);
+ if (retval < 0)
+ goto error;
+
+ INIT_LIST_HEAD(&obj->list_elem);
+ list_add(&obj->list_elem, &heapbufmp_module->obj_list);
+ mutex_unlock(heapbufmp_module->local_lock);
+
+ if (create_flag == false) {
+ obj->owner.creator = false;
+ obj->owner.open_count = 0;
+ obj->owner.proc_id = MULTIPROC_INVALIDID;
+ obj->top = handle;
+
+ obj->attrs = (struct heapbufmp_attrs *) params->shared_addr;
+
+ /* No need to Cache_inv- already done in openByAddr() */
+ obj->align = obj->attrs->align;
+ obj->num_blocks = obj->attrs->num_blocks;
+ obj->block_size = obj->attrs->block_size;
+ obj->exact = obj->attrs->exact;
+ obj->buf = sharedregion_get_ptr((u32 *)obj->attrs->
+ buf_ptr);
+ obj->region_id = sharedregion_get_id(obj->buf);
+
+ /* Set min_align */
+ min_align = 4; /* memory_get_max_default_type_align(); */
+ if (sharedregion_get_cache_line_size(obj->region_id) >
+ min_align)
+ min_align = sharedregion_get_cache_line_size(obj->
+ region_id);
+ obj->cache_enabled = sharedregion_is_cache_enabled(obj->
+ region_id);
+
+ local_addr = sharedregion_get_ptr((u32 *)obj->attrs->
+ gatemp_addr);
+ retval = gatemp_open_by_addr(local_addr, &gate_handle);
+
+ if (retval < 0) {
+ retval = -EFAULT;
+ goto error;
+ }
+ obj->gate = gate_handle;
+
+ /* Open the ListMP */
+ local_addr = (void *) ROUND_UP(((u32)obj->attrs
+ + sizeof(struct heapbufmp_attrs)),
+ min_align);
+ retval = listmp_open_by_addr(local_addr, &(obj->free_list));
+
+ if (retval < 0) {
+ retval = -EFAULT;
+ goto error;
+ }
+ } else {
+ obj->owner.creator = true;
+ obj->owner.open_count = 1;
+ obj->owner.proc_id = multiproc_self();
+ obj->top = handle;
+
+ /* Creating the gate */
+ if (params->gate != NULL)
+ obj->gate = params->gate;
+ else {
+ /* If no gate specified, get the default system gate */
+ obj->gate = gatemp_get_default_remote();
+ }
+
+ if (obj->gate == NULL) {
+ retval = -EFAULT;
+ goto error;
+ }
+
+ obj->exact = params->exact;
+ obj->align = params->align;
+ obj->num_blocks = params->num_blocks;
+
+ if (params->shared_addr == NULL) {
+ /* Creating using a shared region ID */
+ /* It is allowed to have NULL name for an anonymous, not
+ * to be opened by name, heap.
+ */
+ /* Will be allocated in post_init */
+ obj->attrs = NULL;
+ obj->region_id = params->region_id;
+ } else {
+ /* Creating using shared_addr */
+ obj->region_id = sharedregion_get_id(
+ params->shared_addr);
+
+ /* Assert that the buffer is in a valid shared
+ * region
+ */
+ if (obj->region_id == SHAREDREGION_INVALIDREGIONID) {
+ retval = -EFAULT;
+ goto error;
+ } else if (((u32) params->shared_addr
+ % sharedregion_get_cache_line_size(obj->
+ region_id) != 0)) {
+ retval = -EFAULT;
+ goto error;
+ }
+ obj->attrs = (struct heapbufmp_attrs *)
+ params->shared_addr;
+ }
+
+ obj->cache_enabled = sharedregion_is_cache_enabled(
+ obj->region_id);
+
+ /* Fix the alignment (alignment may be needed even if
+ * cache is disabled)
+ */
+ obj->align = 4; /* memory_get_max_default_type_align(); */
+ if (sharedregion_get_cache_line_size(obj->region_id) >
+ obj->align)
+ obj->align = sharedregion_get_cache_line_size(
+ obj->region_id);
+
+ /* Round the block_size up by the adjusted alignment */
+ obj->block_size = ROUND_UP(params->block_size, obj->align);
+
+ retval = heapbufmp_post_init(handle);
+ if (retval < 0) {
+ retval = -EFAULT;
+ goto error;
+ }
+
+ /* Populate the params member */
+ memcpy(&obj->params, params, sizeof(struct heapbufmp_params));
+ if (params->name != NULL) {
+ obj->params.name = kmalloc(strlen(params->name) + 1,
+ GFP_KERNEL);
+ if (obj->params.name == NULL) {
+ retval = -ENOMEM;
+ goto error;
+ }
+ strncpy(obj->params.name, params->name,
+ strlen(params->name) + 1);
+ }
+
+ /* We will store a shared pointer in the NameServer */
+ shared_shm_base = sharedregion_get_srptr((void *)obj->attrs,
+ obj->region_id);
+ if (obj->params.name != NULL) {
+ obj->ns_key = nameserver_add_uint32(
+ heapbufmp_module->nameserver,
+ params->name,
+ (u32)shared_shm_base);
+ if (obj->ns_key == NULL) {
+ retval = -EFAULT;
+ goto error;
+ }
+ }
+ }
+
+ *handle_ptr = (void *)handle;
+ return retval;
+
+
+error:
+ *handle_ptr = (void *)handle;
+
+ /* Do whatever cleanup is required*/
+ if (create_flag == true)
+ heapbufmp_delete(handle_ptr);
+ else
+ heapbufmp_close(handle_ptr);
+
+ pr_err("_heapbufmp_create failed status: %x\n", retval);
+ return retval;
+}
+
+/*
+ * ======== heapbufmp_create ========
+ * Purpose:
+ * This will create a new instance of heapbufmp module
+ */
+void *heapbufmp_create(const struct heapbufmp_params *params)
+{
+ s32 retval = 0;
+ struct heapbufmp_object *handle = NULL;
+ struct heapbufmp_params sparams;
+
+ BUG_ON(params == NULL);
+
+ if (atomic_cmpmask_and_lt(&(heapbufmp_module->ref_count),
+ HEAPBUFMP_MAKE_MAGICSTAMP(0),
+ HEAPBUFMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (params == NULL) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (params->block_size == 0) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (params->num_blocks == 0) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ memcpy(&sparams, (void *)params, sizeof(struct heapbufmp_params));
+ retval = _heapbufmp_create((void **)&handle, &sparams, true);
+ if (retval < 0)
+ goto error;
+
+ return (void *)handle;
+
+error:
+ pr_err("heapbufmp_create failed status: %x\n", retval);
+ return (void *)handle;
+}
+EXPORT_SYMBOL(heapbufmp_create);
+
+/*
+ * ======== heapbufmp_delete ========
+ * Purpose:
+ * This will delete an instance of heapbufmp module
+ */
+int heapbufmp_delete(void **handle_ptr)
+{
+ int status = 0;
+ struct heapbufmp_object *handle = NULL;
+ struct heapbufmp_obj *obj = NULL;
+ struct heapbufmp_params *params = NULL;
+ struct heapbufmp_object *region_heap = NULL;
+ s32 retval = 0;
+ int *key;
+
+ if (atomic_cmpmask_and_lt(&(heapbufmp_module->ref_count),
+ HEAPBUFMP_MAKE_MAGICSTAMP(0),
+ HEAPBUFMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(handle_ptr == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ handle = (struct heapbufmp_object *)(*handle_ptr);
+ if (WARN_ON(handle == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ obj = (struct heapbufmp_obj *)handle->obj;
+ if (obj != NULL) {
+ if (obj->owner.proc_id != multiproc_self()) {
+ status = -ENODEV;
+ goto error;
+ }
+
+ /* Take the local lock */
+ key = gatemp_enter(obj->gate);
+
+ if (obj->owner.open_count > 1) {
+ retval = -ENODEV;
+ goto device_busy_error;
+ }
+
+ retval = mutex_lock_interruptible(heapbufmp_module->local_lock);
+ if (retval < 0)
+ goto lock_error;
+
+ /* Remove frmo the local list */
+ list_del(&obj->list_elem);
+
+ mutex_unlock(heapbufmp_module->local_lock);
+
+ params = (struct heapbufmp_params *) &obj->params;
+
+ if (likely(params->name != NULL)) {
+ if (likely(obj->ns_key != NULL)) {
+ nameserver_remove_entry(heapbufmp_module->
+ nameserver, obj->ns_key);
+ obj->ns_key = NULL;
+ }
+ kfree(params->name);
+ }
+
+ /* Set status to 'not created' */
+ if (obj->attrs != NULL) {
+#if 0
+ obj->attrs->status = 0;
+ if (obj->cache_enabled) {
+ cache_wbinv(obj->attrs, sizeof(struct
+ heapbufmp_attrs), CACHE_TYPE_ALL,
+ true);
+ }
+#endif
+ }
+
+ /* Release the shared lock */
+ gatemp_leave(obj->gate, key);
+
+ if (obj->free_list != NULL)
+ /* Free the list */
+ listmp_delete(&obj->free_list);
+
+ /* If necessary, free shared memory if memory is internally
+ * allocated
+ */
+ region_heap = sharedregion_get_heap(obj->region_id);
+
+ if ((region_heap != NULL) &&
+ (obj->params.shared_addr == NULL) &&
+ (obj->attrs != NULL)) {
+ sl_heap_free(region_heap, obj->attrs, obj->alloc_size);
+ }
+
+ kfree(obj);
+ kfree(handle);
+
+ *handle_ptr = NULL;
+ } else { /* obj == NULL */
+ kfree(handle);
+ *handle_ptr = NULL;
+ }
+
+
+ return 0;
+
+lock_error:
+device_busy_error:
+ gatemp_leave(obj->gate, key);
+
+error:
+ pr_err("heapbufmp_delete failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(heapbufmp_delete);
+
+/*
+ * ======== heapbufmp_open ========
+ * Purpose:
+ * This will opens a created instance of heapbufmp
+ * module
+ */
+int heapbufmp_open(char *name, void **handle_ptr)
+{
+ s32 retval = 0;
+ u32 *shared_shm_base = SHAREDREGION_INVALIDSRPTR;
+ u32 *shared_addr = NULL;
+ struct heapbufmp_obj *obj = NULL;
+ bool done_flag = false;
+ struct list_head *elem = NULL;
+
+ BUG_ON(name == NULL);
+ BUG_ON(handle_ptr == NULL);
+
+ if (unlikely(
+ atomic_cmpmask_and_lt(&(heapbufmp_module->ref_count),
+ HEAPBUFMP_MAKE_MAGICSTAMP(0),
+ HEAPBUFMP_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (name == NULL) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (handle_ptr == NULL) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /* First check in the local list */
+ list_for_each(elem, &heapbufmp_module->obj_list) {
+ obj = (struct heapbufmp_obj *)elem;
+ if (obj->params.name != NULL) {
+ if (strcmp(obj->params.name, name) == 0) {
+ retval = mutex_lock_interruptible(
+ heapbufmp_module->local_lock);
+ if (retval < 0)
+ goto error;
+ /* Check if we have created the heapbufmp or
+ * not
+ */
+ if (obj->owner.proc_id == multiproc_self())
+ obj->owner.open_count++;
+
+ *handle_ptr = (void *)obj->top;
+ mutex_unlock(heapbufmp_module->local_lock);
+ done_flag = true;
+ break;
+ }
+ }
+ }
+
+ if (likely(done_flag == false)) {
+ /* Find in name server */
+ retval = nameserver_get_uint32(heapbufmp_module->nameserver,
+ name,
+ &shared_shm_base,
+ NULL);
+ if (unlikely(retval < 0))
+ goto error;
+
+ /*
+ * Convert from shared region pointer to local address
+ */
+ shared_addr = sharedregion_get_ptr(shared_shm_base);
+ if (unlikely(shared_addr == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ retval = heapbufmp_open_by_addr(shared_addr, handle_ptr);
+
+ if (unlikely(retval < 0))
+ goto error;
+ }
+
+ return 0;
+
+error:
+ pr_err("heapbufmp_open failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(heapbufmp_open);
+
+/*
+ * ======== heapbufmp_close ========
+ * Purpose:
+ * This will closes previously opened/created instance
+ * of heapbufmp module
+ */
+int heapbufmp_close(void **handle_ptr)
+{
+ struct heapbufmp_object *handle = NULL;
+ struct heapbufmp_obj *obj = NULL;
+ s32 retval = 0;
+
+ if (atomic_cmpmask_and_lt(&(heapbufmp_module->ref_count),
+ HEAPBUFMP_MAKE_MAGICSTAMP(0),
+ HEAPBUFMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(handle_ptr == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (WARN_ON(*handle_ptr == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ handle = (struct heapbufmp_object *)(*handle_ptr);
+ obj = (struct heapbufmp_obj *)handle->obj;
+
+ if (obj != NULL) {
+ retval = mutex_lock_interruptible(heapbufmp_module->
+ local_lock);
+ if (retval)
+ goto error;
+
+ /* opening an instance created locally */
+ if (obj->owner.proc_id == multiproc_self())
+ obj->owner.open_count--;
+
+ /* Check if HeapMemMP is opened on same processor
+ * and this is the last closure.
+ */
+ if ((obj->owner.creator == false)
+ && (obj->owner.open_count == 0)) {
+ list_del(&obj->list_elem);
+
+ if (obj->free_list != NULL)
+ /* Close the list */
+ listmp_close(&obj->free_list);
+
+ if (obj->gate != NULL)
+ /* Close the instance gate */
+ gatemp_close(&obj->gate);
+
+ /* Now free the handle */
+ kfree(obj);
+ obj = NULL;
+ kfree(handle);
+ *handle_ptr = NULL;
+ }
+
+ mutex_unlock(heapbufmp_module->local_lock);
+ } else {
+ kfree(handle);
+ *handle_ptr = NULL;
+ }
+ return 0;
+
+error:
+ pr_err("heapbufmp_close failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(heapbufmp_close);
+
+/*
+ * ======== heapbufmp_alloc ========
+ * Purpose:
+ * This will allocs a block of memory
+ */
+void *heapbufmp_alloc(void *hphandle, u32 size, u32 align)
+{
+ char *block = NULL;
+ struct heapbufmp_object *handle = NULL;
+ struct heapbufmp_obj *obj = NULL;
+ int *key;
+ s32 retval = 0;
+
+ if (atomic_cmpmask_and_lt(&(heapbufmp_module->ref_count),
+ HEAPBUFMP_MAKE_MAGICSTAMP(0),
+ HEAPBUFMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+ if (WARN_ON(hphandle == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+ if (WARN_ON(size == 0)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ handle = (struct heapbufmp_object *)(hphandle);
+ obj = (struct heapbufmp_obj *)handle->obj;
+ if (WARN_ON(obj == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (WARN_ON(unlikely(size > obj->block_size))) {
+ retval = -EINVAL;
+ goto error;
+ }
+ if (WARN_ON(unlikely((obj->exact == true)
+ && (size != obj->block_size)))) {
+ retval = -EINVAL;
+ goto error;
+ }
+ if (WARN_ON(unlikely(align > obj->align))) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /*key = gatemp_enter(obj->gate); gate protection acquired in listmp */
+ block = listmp_get_head((struct listmp_object *) obj->free_list);
+ if (unlikely(block == NULL)) {
+ retval = -ENOMEM;
+ goto error;
+ }
+ key = gatemp_enter(obj->gate); /*gatemp call moved down */
+ if (unlikely(heapbufmp_module->cfg.track_allocs)) {
+#if 0
+ /* Make sure the attrs are not in cache */
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((Ptr) obj->attrs,
+ sizeof(heapbufmp_attrs),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+
+ obj->attrs->num_free_blocks--;
+
+ if (obj->attrs->num_free_blocks
+ < obj->attrs->min_free_blocks) {
+ /* save the new minimum */
+ obj->attrs->min_free_blocks =
+ obj->attrs->num_free_blocks;
+ }
+#if 0
+ /* Make sure the attrs are written out to memory */
+ if (EXPECT_false(obj->cacheEnabled == true)) {
+ Cache_wbInv((Ptr) obj->attrs,
+ sizeof(heapbufmp_attrs),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+ }
+ gatemp_leave(obj->gate, key);
+
+ if (block == NULL)
+ pr_err("heapbufmp_alloc returned NULL\n");
+
+ return block;
+error:
+ pr_err("heapbufmp_alloc failed status: %x\n", retval);
+ return NULL;
+}
+EXPORT_SYMBOL(heapbufmp_alloc);
+
+/*
+ * ======== heapbufmp_free ========
+ * Purpose:
+ * This will free a block of memory
+ */
+int heapbufmp_free(void *hphandle, void *block, u32 size)
+{
+ struct heapbufmp_object *handle = NULL;
+ s32 retval = 0;
+ struct heapbufmp_obj *obj = NULL;
+ int *key;
+
+ if (atomic_cmpmask_and_lt(&(heapbufmp_module->ref_count),
+ HEAPBUFMP_MAKE_MAGICSTAMP(0),
+ HEAPBUFMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+ if (WARN_ON(hphandle == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+ if (WARN_ON(block == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ handle = (struct heapbufmp_object *)(hphandle);
+ obj = (struct heapbufmp_obj *)handle->obj;
+ if (WARN_ON(obj == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /* key = gatemp_enter(obj->gate); */
+ retval = listmp_put_tail(obj->free_list, block);
+ if (unlikely(retval < 0)) {
+ retval = -EFAULT;
+ goto error;
+ }
+ key = gatemp_enter(obj->gate); /*gatemp call moved down */
+ if (unlikely(heapbufmp_module->cfg.track_allocs)) {
+#if 0
+ /* Make sure the attrs are not in cache */
+ if (EXPECT_false(obj->cacheEnabled == true)) {
+ Cache_inv((Ptr) obj->attrs,
+ sizeof(heapbufmp_attrs),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+
+ obj->attrs->num_free_blocks++;
+#if 0
+ /* Make sure the attrs are written out to memory */
+ if (EXPECT_false(obj->cacheEnabled == true)) {
+ Cache_wbInv((Ptr) obj->attrs,
+ sizeof(heapbufmp_attrs),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+ }
+
+ gatemp_leave(obj->gate, key);
+
+ return 0;
+
+error:
+ pr_err("heapbufmp_free failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(heapbufmp_free);
+
+/*
+ * ======== heapbufmp_get_stats ========
+ * Purpose:
+ * This will get memory statistics
+ */
+void heapbufmp_get_stats(void *hphandle, struct memory_stats *stats)
+{
+ struct heapbufmp_object *object = NULL;
+ struct heapbufmp_obj *obj = NULL;
+ int *key;
+ s32 retval = 0;
+ u32 block_size;
+
+ if (atomic_cmpmask_and_lt(&(heapbufmp_module->ref_count),
+ HEAPBUFMP_MAKE_MAGICSTAMP(0),
+ HEAPBUFMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+ if (WARN_ON(hphandle == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+ if (WARN_ON(stats == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ object = (struct heapbufmp_object *)(hphandle);
+ obj = (struct heapbufmp_obj *)object->obj;
+ if (WARN_ON(obj == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ block_size = obj->attrs->block_size;
+
+ if (unlikely(heapbufmp_module->cfg.track_allocs)) {
+
+ key = gatemp_enter(obj->gate);
+#if 0
+ /* Make sure the attrs are not in cache */
+ if (EXPECT_false(obj->cacheEnabled == true)) {
+ Cache_inv((Ptr) obj->attrs,
+ sizeof(heapbufmp_attrs),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+
+ stats->total_free_size = block_size * obj->attrs->
+ num_free_blocks;
+ stats->largest_free_size = (obj->attrs->num_free_blocks > 0) ?
+ block_size : 0; /* determined later */
+
+ gatemp_leave(obj->gate, key);
+ } else {
+ /* Tracking disabled */
+ stats->total_free_size = 0;
+ stats->largest_free_size = 0;
+ }
+ return;
+
+error:
+ if (retval < 0)
+ pr_err("heapbufmp_get_stats status: [0x%x]\n", retval);
+}
+EXPORT_SYMBOL(heapbufmp_get_stats);
+
+/*
+ * ======== heapbufmp_isblocking ========
+ * Purpose:
+ * Indicate whether the heap may block during an alloc or free call
+ */
+bool heapbufmp_isblocking(void *handle)
+{
+ bool isblocking = false;
+ s32 retval = 0;
+
+ if (WARN_ON(handle == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /* TBD: Figure out how to determine whether the gate is blocking */
+ isblocking = true;
+
+ /* retval true Heap blocks during alloc/free calls */
+ /* retval false Heap does not block during alloc/free calls */
+ return isblocking;
+
+error:
+ pr_err("heapbufmp_isblocking status: %x\n", retval);
+ return isblocking;
+}
+EXPORT_SYMBOL(heapbufmp_isblocking);
+
+/*
+ * ======== heapbufmp_get_extended_stats ========
+ * Purpose:
+ * This will get extended statistics
+ */
+void heapbufmp_get_extended_stats(void *hphandle,
+ struct heapbufmp_extended_stats *stats)
+{
+ s32 retval = 0;
+ struct heapbufmp_object *object = NULL;
+ struct heapbufmp_obj *obj = NULL;
+ int *key;
+
+ if (atomic_cmpmask_and_lt(&(heapbufmp_module->ref_count),
+ HEAPBUFMP_MAKE_MAGICSTAMP(0),
+ HEAPBUFMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+ if (WARN_ON(heapbufmp_module->nameserver == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+ if (WARN_ON(hphandle == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ object = (struct heapbufmp_object *)(hphandle);
+ obj = (struct heapbufmp_obj *)object->obj;
+ if (WARN_ON(obj == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+#if 0
+ /* Make sure the attrs are not in cache */
+ if (EXPECT_false(obj->cacheEnabled == true)) {
+ Cache_inv((Ptr) obj->attrs,
+ sizeof(heapbufmp_attrs),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+ /*
+ * The maximum number of allocations for this HeapBufMP(for any given
+ * instance of time during its liftime) is computed as follows:
+ *
+ * max_allocated_blocks = obj->num_blocks - obj->min_free_blocks
+ *
+ * Note that max_allocated_blocks is *not* the maximum allocation
+ * count, but rather the maximum allocations seen at any snapshot of
+ * time in the HeapBufMP instance.
+ */
+ key = gatemp_enter(obj->gate);
+ /* if nothing has been alloc'ed yet, return 0 */
+ if ((s32)(obj->attrs->min_free_blocks) == -1)
+ stats->max_allocated_blocks = 0;
+ else
+ stats->max_allocated_blocks = obj->attrs->num_blocks
+ - obj->attrs->min_free_blocks;
+
+ /*
+ * current # of alloc'ed blocks is computed
+ * using curr # of free blocks
+ */
+ stats->num_allocated_blocks = obj->attrs->num_blocks
+ - obj->attrs->num_free_blocks;
+
+ gatemp_leave(obj->gate, key);
+
+ return;
+
+error:
+ pr_err("heapbufmp_get_extended_stats status: %x\n", retval);
+}
+EXPORT_SYMBOL(heapbufmp_get_extended_stats);
+
+/*
+ * ======== heapbufmp_shared_mem_req ========
+ * Purpose:
+ * This will get amount of shared memory required for
+ * creation of each instance
+ */
+int heapbufmp_shared_mem_req(const struct heapbufmp_params *params)
+{
+ int mem_req = 0;
+ struct listmp_params listmp_params;
+ u32 buf_align = 0;
+ u32 block_size = 0;
+
+ s32 status = 0;
+ u32 region_id;
+ u32 min_align;
+
+ if (WARN_ON(params == NULL)) {
+ status = -EINVAL;
+ goto error;
+ }
+ if (WARN_ON(params->block_size == 0)) {
+ status = -EINVAL;
+ goto error;
+ }
+ if (WARN_ON(params->num_blocks == 0)) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ if (params->shared_addr == NULL)
+ region_id = params->region_id;
+ else
+ region_id = sharedregion_get_id(params->shared_addr);
+
+ if (region_id == SHAREDREGION_INVALIDREGIONID) {
+ status = -EFAULT;
+ goto error;
+ }
+
+ buf_align = params->align;
+
+ min_align = 4; /* memory_get_default_type_align() */
+ if (sharedregion_get_cache_line_size(region_id) > min_align)
+ min_align = sharedregion_get_cache_line_size(region_id);
+
+ if (buf_align < min_align)
+ buf_align = min_align;
+
+ /* Determine the actual block size */
+ block_size = ROUND_UP(params->block_size, buf_align);
+
+ /* Add size of HeapBufMP Attrs */
+ mem_req = ROUND_UP(sizeof(struct heapbufmp_attrs), min_align);
+
+ /*
+ * Add size of ListMP Attrs. No need to init params since it's
+ * not used to create.
+ */
+ listmp_params_init(&listmp_params);
+ listmp_params.region_id = region_id;
+ mem_req += listmp_shared_mem_req(&listmp_params);
+
+ /* Round by the buffer alignment */
+ mem_req = ROUND_UP(mem_req, buf_align);
+
+ /*
+ * Add the buffer size. No need to subsequently round because the
+ * product should be a multiple of cacheLineSize if cache alignment
+ * is enabled
+ */
+ mem_req += (block_size * params->num_blocks);
+
+ return mem_req;
+error:
+ pr_err("heapbufmp_shared_mem_req status: %x\n", status);
+ return mem_req;
+}
+EXPORT_SYMBOL(heapbufmp_shared_mem_req);
+
+
+/*
+ * ======== heapbufmp_open_by_addr ========
+ * Purpose:
+ * Open existing heapbufmp based on address
+ */
+int
+heapbufmp_open_by_addr(void *shared_addr, void **handle_ptr)
+{
+ s32 retval = 0;
+ bool done_flag = false;
+ struct heapbufmp_attrs *attrs = NULL;
+ u16 id = 0;
+ struct heapbufmp_params params;
+ struct heapbufmp_obj *obj = NULL;
+
+ if (unlikely(atomic_cmpmask_and_lt(&(heapbufmp_module->ref_count),
+ HEAPBUFMP_MAKE_MAGICSTAMP(0),
+ HEAPBUFMP_MAKE_MAGICSTAMP(1))
+ == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+ if (unlikely(handle_ptr == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /* First check in the local list */
+ list_for_each_entry(obj, &heapbufmp_module->obj_list, list_elem) {
+ if (obj->params.shared_addr == shared_addr) {
+ retval = mutex_lock_interruptible(heapbufmp_module->
+ local_lock);
+ if (retval < 0)
+ goto error;
+
+ if (obj->owner.proc_id == multiproc_self())
+ obj->owner.open_count++;
+
+ mutex_unlock(heapbufmp_module->local_lock);
+ *handle_ptr = obj->top;
+ done_flag = true;
+ break;
+ }
+ }
+
+ /* If not already existing locally, create object locally for open. */
+ if (unlikely(done_flag == false)) {
+ heapbufmp_params_init(&params);
+ params.shared_addr = shared_addr;
+ attrs = (struct heapbufmp_attrs *) shared_addr;
+ id = sharedregion_get_id(shared_addr);
+#if 0
+ if (unlikely(sharedregion_is_cache_enabled(id))) {
+ Cache_inv(attrs,
+ sizeof(heapbufmp_attrs),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+ if (unlikely(attrs->status != HEAPBUFMP_CREATED)) {
+ *handle_ptr = NULL;
+ retval = -ENOENT;
+ goto error;
+ }
+
+ retval = _heapbufmp_create(handle_ptr, &params, false);
+
+ if (unlikely(retval < 0))
+ goto error;
+ }
+ return 0;
+
+error:
+ pr_err("heapbufmp_open_by_addr status: %x\n", retval);
+
+ return retval;
+}
+
+
+/* =========================================================================
+ * Internal functions
+ * =========================================================================
+ */
+/*
+ * Shared memory Layout:
+ *
+ * sharedAddr -> ---------------------------
+ * | heapbufmp_attrs |
+ * | (min_align PADDING) |
+ * |-------------------------|
+ * | ListMP shared instance |
+ * | (bufAlign PADDING) |
+ * |-------------------------|
+ * | HeapBufMP BUFFER |
+ * |-------------------------|
+ */
+
+
+/*
+ * ======== heapbufmp_post_init ========
+ * Purpose:
+ * Slice and dice the buffer up into the correct size blocks and
+ * add to the freelist.
+ */
+static int heapbufmp_post_init(struct heapbufmp_object *handle)
+{
+ s32 retval = 0;
+ char *buf = NULL;
+ struct heapbufmp_obj *obj = NULL;
+ struct heapbufmp_object *region_heap = NULL;
+ struct heapbufmp_params params;
+ struct listmp_params listmp_params;
+ u32 min_align;
+ u32 i;
+
+ obj = (struct heapbufmp_obj *)handle->obj;
+ if (WARN_ON(obj == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ min_align = 4; /* memory_get_default_type_align() */
+ if (sharedregion_get_cache_line_size(obj->region_id) > min_align)
+ min_align = sharedregion_get_cache_line_size(obj->region_id);
+
+ if (obj->attrs == NULL) {
+ heapbufmp_params_init(&params);
+ params.region_id = obj->region_id;
+ params.num_blocks = obj->num_blocks;
+ params.align = obj->align;
+ params.block_size = obj->block_size;
+ obj->alloc_size = heapbufmp_shared_mem_req(&params);
+
+ region_heap = sharedregion_get_heap(obj->region_id);
+ if (region_heap == NULL) {
+ retval = -EFAULT;
+ goto error;
+ }
+
+ obj->attrs = sl_heap_alloc(region_heap, obj->alloc_size,
+ min_align);
+ if (obj->attrs == NULL) {
+ retval = -ENOMEM;
+ goto error;
+ }
+ }
+
+ /* Store the GateMP sharedAddr in the HeapBuf Attrs */
+ obj->attrs->gatemp_addr = gatemp_get_shared_addr(obj->gate);
+
+ /* Create the free_list */
+ listmp_params_init(&listmp_params);
+ listmp_params.shared_addr = (void *)ROUND_UP((u32)obj->attrs
+ + sizeof(struct heapbufmp_attrs),
+ min_align);
+ listmp_params.gatemp_handle = obj->gate;
+ obj->free_list = listmp_create(&listmp_params);
+ if (obj->free_list == NULL) {
+ retval = -EFAULT;
+ goto error;
+ }
+
+ /* obj->buf will get alignment-adjusted in postInit */
+ obj->buf = (void *)((u32)listmp_params.shared_addr
+ + listmp_shared_mem_req(&listmp_params));
+ buf = obj->buf = (char *)ROUND_UP((u32)obj->buf, obj->align);
+
+ obj->attrs->num_free_blocks = obj->num_blocks;
+ obj->attrs->min_free_blocks = (32)-1;
+ obj->attrs->block_size = obj->block_size;
+ obj->attrs->align = obj->align;
+ obj->attrs->num_blocks = obj->num_blocks;
+ obj->attrs->exact = obj->exact ? 1 : 0;
+
+ /* Put a SRPtr in attrs */
+ obj->attrs->buf_ptr = sharedregion_get_srptr(obj->buf,
+ obj->region_id);
+ BUG_ON(obj->attrs->buf_ptr == SHAREDREGION_INVALIDSRPTR);
+
+ /*
+ * Split the buffer into blocks that are length "block_size" and
+ * add into the free_list Queue.
+ */
+ for (i = 0; i < obj->num_blocks; i++) {
+ /* Add the block to the free_list */
+ retval = listmp_put_tail(obj->free_list,
+ (struct listmp_elem *)buf);
+ if (retval < 0) {
+ retval = -EFAULT;
+ goto created_free_list_error;
+ }
+
+ buf = (char *)((u32)buf + obj->block_size);
+ }
+
+ /* Last thing, set the status */
+ obj->attrs->status = HEAPBUFMP_CREATED;
+#if 0
+ if (unlikely(obj->cacheEnabled)) {
+ Cache_wbInv((Ptr) obj->attrs,
+ sizeof(heapbufmp_attrs),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+ return 0;
+
+created_free_list_error:
+ listmp_delete(&obj->free_list);
+
+error:
+ pr_err("heapmem_post_init status: %x\n", retval);
+ return retval;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/heapbufmp_ioctl.c b/drivers/dsp/syslink/multicore_ipc/heapbufmp_ioctl.c
new file mode 100644
index 00000000000..dcd8bc01cec
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/heapbufmp_ioctl.c
@@ -0,0 +1,550 @@
+/*
+ * heapbufmp_ioctl.c
+ *
+ * Heap module manages fixed size buffers that can be used
+ * in a multiprocessor system with shared memory.
+ *
+ * Copyright (C) 2008-2009 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 <linux/uaccess.h>
+#include <linux/types.h>
+#include <linux/bug.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <ipc.h>
+#include <sharedregion.h>
+#include <heap.h>
+#include <heapbufmp.h>
+#include <heapbufmp_ioctl.h>
+
+
+static struct resource_info *find_heapbufmp_resource(
+ struct ipc_process_context *pr_ctxt,
+ unsigned int cmd,
+ struct heapbufmp_cmd_args *cargs)
+{
+ struct resource_info *info = NULL;
+ bool found = false;
+
+ spin_lock(&pr_ctxt->res_lock);
+
+ list_for_each_entry(info, &pr_ctxt->resources, res) {
+ struct heapbufmp_cmd_args *args =
+ (struct heapbufmp_cmd_args *)info->data;
+ if (info->cmd == cmd) {
+ switch (cmd) {
+ case CMD_HEAPBUFMP_DELETE:
+ {
+ void *handle =
+ args->args.delete.handle;
+ void *temp =
+ cargs->args.delete.handle;
+ if (temp == handle)
+ found = true;
+ break;
+ }
+ case CMD_HEAPBUFMP_DESTROY:
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found == true)
+ break;
+ }
+ }
+
+ spin_unlock(&pr_ctxt->res_lock);
+
+ if (found == false)
+ info = NULL;
+
+ return info;
+}
+
+/*
+ * ======== heapbufmp_ioctl_alloc ========
+ * Purpose:
+ * This ioctl interface to heapbufmp_alloc function
+ */
+static int heapbufmp_ioctl_alloc(struct heapbufmp_cmd_args *cargs)
+{
+ u32 *block_srptr = SHAREDREGION_INVALIDSRPTR;
+ void *block;
+ s32 index = SHAREDREGION_INVALIDREGIONID;
+ s32 status = 0;
+
+ block = heapbufmp_alloc(cargs->args.alloc.handle,
+ cargs->args.alloc.size,
+ cargs->args.alloc.align);
+ if (block != NULL) {
+ index = sharedregion_get_id(block);
+ block_srptr = sharedregion_get_srptr(block, index);
+ }
+ /* The error on above fn will be a null ptr. We are not
+ checking that condition here. We are passing whatever
+ we are getting from the heapbuf module. So IOCTL will succed,
+ but the actual fn might be failed inside heapbuf
+ */
+ BUG_ON(index == SHAREDREGION_INVALIDREGIONID);
+ cargs->args.alloc.block_srptr = block_srptr;
+ BUG_ON(cargs->args.alloc.block_srptr == SHAREDREGION_INVALIDSRPTR);
+ cargs->api_status = 0;
+ return status;
+}
+
+/*
+ * ======== heapbufmp_ioctl_free ========
+ * Purpose:
+ * This ioctl interface to heapbufmp_free function
+ */
+static int heapbufmp_ioctl_free(struct heapbufmp_cmd_args *cargs)
+{
+ char *block;
+
+ block = sharedregion_get_ptr(cargs->args.free.block_srptr);
+ BUG_ON(block == NULL);
+ cargs->api_status = heapbufmp_free(cargs->args.free.handle, block,
+ cargs->args.free.size);
+ return 0;
+}
+
+/*
+ * ======== heapbufmp_ioctl_params_init ========
+ * Purpose:
+ * This ioctl interface to heapbufmp_params_init function
+ */
+static int heapbufmp_ioctl_params_init(struct heapbufmp_cmd_args *cargs)
+{
+ struct heapbufmp_params params;
+ s32 status = 0;
+ u32 size;
+
+ heapbufmp_params_init(&params);
+ cargs->api_status = 0;
+ size = copy_to_user((void __user *)cargs->args.params_init.params,
+ &params, sizeof(struct heapbufmp_params));
+ if (size)
+ status = -EFAULT;
+
+ return status;
+}
+
+/*
+ * ======== heapbufmp_ioctl_create ========
+ * Purpose:
+ * This ioctl interface to heapbufmp_create function
+ */
+static int heapbufmp_ioctl_create(struct heapbufmp_cmd_args *cargs)
+{
+ struct heapbufmp_params params;
+ s32 status = 0;
+ u32 size;
+ void *handle = NULL;
+
+ size = copy_from_user(&params, (void __user *)cargs->args.create.params,
+ sizeof(struct heapbufmp_params));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ if (cargs->args.create.name_len > 0) {
+ params.name = kmalloc(cargs->args.create.name_len, GFP_KERNEL);
+ if (params.name == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ params.name[cargs->args.create.name_len] = '\0';
+ size = copy_from_user(params.name,
+ (void __user *)cargs->args.create.params->name,
+ cargs->args.create.name_len);
+ if (size) {
+ status = -EFAULT;
+ goto name_from_usr_error;
+ }
+ }
+
+ params.shared_addr = sharedregion_get_ptr((u32 *)
+ cargs->args.create.shared_addr_srptr);
+ params.gate = cargs->args.create.knl_gate;
+ handle = heapbufmp_create(&params);
+ cargs->args.create.handle = handle;
+ cargs->api_status = 0;
+
+name_from_usr_error:
+ if (cargs->args.create.name_len > 0)
+ kfree(params.name);
+
+exit:
+ return status;
+}
+
+
+/*
+ * ======== heapbufmp_ioctl_delete ========
+ * Purpose:
+ * This ioctl interface to heapbufmp_delete function
+ */
+static int heapbufmp_ioctl_delete(struct heapbufmp_cmd_args *cargs)
+{
+ cargs->api_status = heapbufmp_delete(&cargs->args.delete.handle);
+ return 0;
+}
+
+/*
+ * ======== heapbufmp_ioctl_open ========
+ * Purpose:
+ * This ioctl interface to heapbufmp_open function
+ */
+static int heapbufmp_ioctl_open(struct heapbufmp_cmd_args *cargs)
+{
+ s32 status = 0;
+ u32 size = 0;
+ void *handle = NULL;
+ char *name = NULL;
+
+ if (cargs->args.open.name_len > 0) {
+ name = kmalloc(cargs->args.open.name_len, GFP_KERNEL);
+ if (name == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ size = copy_from_user(name,
+ (void __user *)cargs->args.open.name,
+ cargs->args.open.name_len);
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ }
+
+ cargs->api_status = heapbufmp_open(cargs->args.open.name, &handle);
+ cargs->args.open.handle = handle;
+
+ if (cargs->args.open.name_len > 0)
+ kfree(name);
+exit:
+ return status;
+}
+
+/*
+ * ======== heapbufmp_ioctl_open_by_addr ========
+ * Purpose:
+ * This ioctl interface to heapbufmp_open_by_addr function
+ */
+static int heapbufmp_ioctl_open_by_addr(struct heapbufmp_cmd_args *cargs)
+{
+ void *handle = NULL;
+ void *shared_addr;
+
+ shared_addr = sharedregion_get_ptr(cargs->args.
+ open_by_addr.shared_addr_srptr);
+ cargs->api_status = heapbufmp_open_by_addr(
+ shared_addr, &handle);
+ cargs->args.open_by_addr.handle = handle;
+
+ return 0;
+}
+
+
+/*
+ * ======== heapbufmp_ioctl_close ========
+ * Purpose:
+ * This ioctl interface to heapbufmp_close function
+ */
+static int heapbufmp_ioctl_close(struct heapbufmp_cmd_args *cargs)
+{
+ cargs->api_status = heapbufmp_close(&cargs->args.close.handle);
+ return 0;
+}
+
+/*
+ * ======== heapbufmp_ioctl_shared_mem_req ========
+ * Purpose:
+ * This ioctl interface to heapbufmp_shared_mem_req function
+ */
+static int heapbufmp_ioctl_shared_mem_req(struct heapbufmp_cmd_args *cargs)
+{
+ struct heapbufmp_params params;
+ s32 status = 0;
+ ulong size;
+
+ size = copy_from_user(&params,
+ (void __user *)cargs->args.shared_mem_req.params,
+ sizeof(struct heapbufmp_params));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ cargs->args.shared_mem_req.bytes = heapbufmp_shared_mem_req(&params);
+ cargs->api_status = 0;
+
+exit:
+ return status;
+}
+
+
+/*
+ * ======== heapbufmp_ioctl_get_config ========
+ * Purpose:
+ * This ioctl interface to heapbufmp_get_config function
+ */
+static int heapbufmp_ioctl_get_config(struct heapbufmp_cmd_args *cargs)
+{
+ struct heapbufmp_config config;
+ s32 status = 0;
+ ulong size;
+
+ cargs->api_status = heapbufmp_get_config(&config);
+ size = copy_to_user((void __user *)cargs->args.get_config.config,
+ &config, sizeof(struct heapbufmp_config));
+ if (size)
+ status = -EFAULT;
+
+ return status;
+}
+
+/*
+ * ======== heapbufmp_ioctl_setup ========
+ * Purpose:
+ * This ioctl interface to heapbufmp_setup function
+ */
+static int heapbufmp_ioctl_setup(struct heapbufmp_cmd_args *cargs)
+{
+ struct heapbufmp_config config;
+ s32 status = 0;
+ ulong size;
+
+ size = copy_from_user(&config, (void __user *)cargs->args.setup.config,
+ sizeof(struct heapbufmp_config));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ cargs->api_status = heapbufmp_setup(&config);
+
+exit:
+ return status;
+}
+/*
+ * ======== heapbufmp_ioctl_destroy ========
+ * Purpose:
+ * This ioctl interface to heapbufmp_destroy function
+ */
+static int heapbufmp_ioctl_destroy(struct heapbufmp_cmd_args *cargs)
+{
+ cargs->api_status = heapbufmp_destroy();
+ return 0;
+}
+
+
+/*
+ * ======== heapbufmp_ioctl_get_stats ========
+ * Purpose:
+ * This ioctl interface to heapbufmp_get_stats function
+ */
+static int heapbufmp_ioctl_get_stats(struct heapbufmp_cmd_args *cargs)
+{
+ struct memory_stats stats;
+ s32 status = 0;
+ ulong size;
+
+ heapbufmp_get_stats(cargs->args.get_stats.handle, &stats);
+ cargs->api_status = 0;
+
+ size = copy_to_user((void __user *)cargs->args.get_stats.stats, &stats,
+ sizeof(struct memory_stats));
+ if (size)
+ status = -EFAULT;
+
+ return status;
+}
+
+/*
+ * ======== heapbufmp_ioctl_get_extended_stats ========
+ * Purpose:
+ * This ioctl interface to heapbufmp_get_extended_stats function
+ */
+static int heapbufmp_ioctl_get_extended_stats(struct heapbufmp_cmd_args *cargs)
+{
+ struct heapbufmp_extended_stats stats;
+ s32 status = 0;
+ ulong size;
+ heapbufmp_get_extended_stats(cargs->args.get_extended_stats.
+ handle, &stats);
+ cargs->api_status = 0;
+
+ size = copy_to_user((void __user *)cargs->args.get_extended_stats.stats,
+ &stats,
+ sizeof(struct heapbufmp_extended_stats));
+ if (size)
+ status = -EFAULT;
+
+ return status;
+}
+
+/*
+ * ======== heapbufmp_ioctl ========
+ * Purpose:
+ * This ioctl interface for heapbuf module
+ */
+int heapbufmp_ioctl(struct inode *pinode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user)
+{
+ s32 status = 0;
+ s32 size = 0;
+ struct heapbufmp_cmd_args __user *uarg =
+ (struct heapbufmp_cmd_args __user *)args;
+ struct heapbufmp_cmd_args cargs;
+ struct ipc_process_context *pr_ctxt =
+ (struct ipc_process_context *)filp->private_data;
+
+ if (user == true) {
+#ifdef CONFIG_SYSLINK_RECOVERY
+ if (ipc_recovering()) {
+ status = -EIO;
+ goto exit;
+ }
+#endif
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ status = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ status = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
+
+ if (status) {
+ status = -EFAULT;
+ goto exit;
+ }
+ /* Copy the full args from user-side */
+ size = copy_from_user(&cargs, uarg,
+ sizeof(struct heapbufmp_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ } else {
+ if (args != 0)
+ memcpy(&cargs, (void *)args,
+ sizeof(struct heapbufmp_cmd_args));
+ }
+
+ switch (cmd) {
+ case CMD_HEAPBUFMP_ALLOC:
+ status = heapbufmp_ioctl_alloc(&cargs);
+ break;
+
+ case CMD_HEAPBUFMP_FREE:
+ status = heapbufmp_ioctl_free(&cargs);
+ break;
+
+ case CMD_HEAPBUFMP_PARAMS_INIT:
+ status = heapbufmp_ioctl_params_init(&cargs);
+ break;
+
+ case CMD_HEAPBUFMP_CREATE:
+ status = heapbufmp_ioctl_create(&cargs);
+ if (status >= 0) {
+ struct heapbufmp_cmd_args *temp =
+ kmalloc(sizeof(struct heapbufmp_cmd_args),
+ GFP_KERNEL);
+ if (WARN_ON(!temp)) {
+ status = -ENOMEM;
+ goto exit;
+ }
+ temp->args.delete.handle = cargs.args.create.handle;
+ add_pr_res(pr_ctxt, CMD_HEAPBUFMP_DELETE, temp);
+ }
+ break;
+
+ case CMD_HEAPBUFMP_DELETE:
+ {
+ struct resource_info *info = NULL;
+ info = find_heapbufmp_resource(pr_ctxt,
+ CMD_HEAPBUFMP_DELETE,
+ &cargs);
+ status = heapbufmp_ioctl_delete(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_HEAPBUFMP_OPEN:
+ status = heapbufmp_ioctl_open(&cargs);
+ break;
+
+ case CMD_HEAPBUFMP_OPENBYADDR:
+ status = heapbufmp_ioctl_open_by_addr(&cargs);
+ break;
+
+ case CMD_HEAPBUFMP_CLOSE:
+ status = heapbufmp_ioctl_close(&cargs);
+ break;
+
+ case CMD_HEAPBUFMP_SHAREDMEMREQ:
+ status = heapbufmp_ioctl_shared_mem_req(&cargs);
+ break;
+
+ case CMD_HEAPBUFMP_GETCONFIG:
+ status = heapbufmp_ioctl_get_config(&cargs);
+ break;
+
+ case CMD_HEAPBUFMP_SETUP:
+ status = heapbufmp_ioctl_setup(&cargs);
+ if (status >= 0)
+ add_pr_res(pr_ctxt, CMD_HEAPBUFMP_DESTROY, NULL);
+ break;
+
+ case CMD_HEAPBUFMP_DESTROY:
+ {
+ struct resource_info *info = NULL;
+ info = find_heapbufmp_resource(pr_ctxt,
+ CMD_HEAPBUFMP_DESTROY,
+ &cargs);
+ status = heapbufmp_ioctl_destroy(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_HEAPBUFMP_GETSTATS:
+ status = heapbufmp_ioctl_get_stats(&cargs);
+ break;
+
+ case CMD_HEAPBUFMP_GETEXTENDEDSTATS:
+ status = heapbufmp_ioctl_get_extended_stats(&cargs);
+ break;
+
+ default:
+ WARN_ON(cmd);
+ status = -ENOTTY;
+ break;
+ }
+
+ if (user == true) {
+ /* Copy the full args to the user-side. */
+ size = copy_to_user(uarg, &cargs,
+ sizeof(struct heapbufmp_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ }
+
+exit:
+ return status;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/heapmemmp.c b/drivers/dsp/syslink/multicore_ipc/heapmemmp.c
new file mode 100644
index 00000000000..2deae6c7c41
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/heapmemmp.c
@@ -0,0 +1,1666 @@
+/*
+ * heapmemmp.c
+ *
+ * Heap module manages variable size buffers that can be used
+ * in a multiprocessor system with shared memory.
+ *
+ * Copyright (C) 2008-2009 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 <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <atomic_linux.h>
+#include <multiproc.h>
+#include <nameserver.h>
+#include <sharedregion.h>
+#include <gatemp.h>
+#include <heapmemmp.h>
+
+/*
+ * Name of the reserved nameserver used for heapmemmp.
+ */
+#define HEAPMEMMP_NAMESERVER "HeapMemMP"
+#define HEAPMEMMP_MAX_NAME_LEN 32
+#define HEAPMEMMP_MAX_RUNTIME_ENTRIES 32
+#define HEAPMEMMP_CACHESIZE 128
+/* brief Macro to make a correct module magic number with ref_count */
+#define HEAPMEMMP_MAKE_MAGICSTAMP(x) ((HEAPMEMMP_MODULEID << 12) | (x))
+
+#define ROUND_UP(a, b) (((a) + ((b) - 1)) & (~((b) - 1)))
+
+/*
+ * Structure defining processor related information for the
+ * heapmemmp module
+ */
+struct heapmemmp_proc_attrs {
+ bool creator; /* Creator or opener */
+ u16 proc_id; /* Processor identifier */
+ u32 open_count; /* open count in a processor */
+};
+
+/*
+ * heapmemmp header structure
+ */
+struct heapmemmp_header {
+ u32 *next; /* SRPtr to next header */
+ u32 size; /* Size of this segment */
+};
+
+/*
+ * Structure defining attribute parameters for the heapmemmp module
+ */
+struct heapmemmp_attrs {
+ VOLATILE u32 status; /* Module status */
+ VOLATILE u32 *buf_ptr; /* Memory managed by instance */
+ VOLATILE struct heapmemmp_header head; /* header */
+ VOLATILE u32 *gatemp_addr; /* gatemp shared address (shm safe) */
+};
+
+/*
+ * Structure for heapmemmp module state
+ */
+struct heapmemmp_module_object {
+ atomic_t ref_count; /* Reference count */
+ void *nameserver; /* Nameserver handle */
+ struct list_head obj_list; /* List holding created objects */
+ struct mutex *local_lock; /* lock for protecting obj_list */
+ struct heapmemmp_config cfg; /* Current config values */
+ struct heapmemmp_config default_cfg; /* Default config values */
+ struct heapmemmp_params default_inst_params; /* Default instance
+ creation parameters */
+};
+
+static struct heapmemmp_module_object heapmemmp_state = {
+ .obj_list = LIST_HEAD_INIT(heapmemmp_state.obj_list),
+ .default_cfg.max_name_len = HEAPMEMMP_MAX_NAME_LEN,
+ .default_cfg.max_runtime_entries = HEAPMEMMP_MAX_RUNTIME_ENTRIES,
+ .default_inst_params.gate = NULL,
+ .default_inst_params.name = NULL,
+ .default_inst_params.region_id = 0,
+ .default_inst_params.shared_addr = NULL,
+ .default_inst_params.shared_buf_size = 0,
+};
+
+/* Pointer to module state */
+static struct heapmemmp_module_object *heapmemmp_module = &heapmemmp_state;
+
+/*
+ * Structure for the handle for the heapmemmp
+ */
+struct heapmemmp_obj {
+ struct list_head list_elem; /* Used for creating a linked list */
+ struct heapmemmp_attrs *attrs; /* The shared attributes structure */
+ void *gate; /* Lock used for critical region management */
+ void *ns_key; /* nameserver key required for remove */
+ bool cache_enabled; /* Whether to do cache calls */
+ u16 region_id; /* shared region index */
+ u32 alloc_size; /* Size of allocated shared memory */
+ char *buf; /* Pointer to allocated memory */
+ u32 min_align; /* Minimum alignment required */
+ u32 buf_size; /* Buffer Size */
+ struct heapmemmp_proc_attrs owner; /* owner processor info */
+ void *top; /* Pointer to the top object */
+ struct heapmemmp_params params; /* The creation parameter structure */
+};
+
+#define heapmemmp_object heap_object
+
+/* =============================================================================
+ * Forward declarations of internal functions
+ * =============================================================================
+ */
+static int heapmemmp_post_init(struct heapmemmp_object *handle);
+
+/* =============================================================================
+ * APIs called directly by applications
+ * =============================================================================
+ */
+
+/*
+ * This will get default configuration for the
+ * heapmemmp module
+ */
+int heapmemmp_get_config(struct heapmemmp_config *cfgparams)
+{
+ s32 retval = 0;
+
+ BUG_ON(cfgparams == NULL);
+
+ if (cfgparams == NULL) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (atomic_cmpmask_and_lt(&(heapmemmp_module->ref_count),
+ HEAPMEMMP_MAKE_MAGICSTAMP(0),
+ HEAPMEMMP_MAKE_MAGICSTAMP(1)) == true)
+ memcpy(cfgparams, &heapmemmp_module->default_cfg,
+ sizeof(struct heapmemmp_config));
+ else
+ memcpy(cfgparams, &heapmemmp_module->cfg,
+ sizeof(struct heapmemmp_config));
+ return 0;
+error:
+ pr_err("heapmemmp_get_config failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(heapmemmp_get_config);
+
+/*
+ * This will setup the heapmemmp module
+ *
+ * This function sets up the heapmemmp module. This function
+ * must be called before any other instance-level APIs can be
+ * invoked.
+ * Module-level configuration needs to be provided to this
+ * function. If the user wishes to change some specific config
+ * parameters, then heapmemmp_getconfig can be called to get
+ * the configuration filled with the default values. After this,
+ * only the required configuration values can be changed. If the
+ * user does not wish to make any change in the default parameters,
+ * the application can simply call heapmemmp_setup with NULL
+ * parameters. The default parameters would get automatically used.
+ */
+int heapmemmp_setup(const struct heapmemmp_config *cfg)
+{
+ struct nameserver_params params;
+ struct heapmemmp_config tmp_cfg;
+ s32 retval = 0;
+
+ /* This sets the ref_count variable not initialized, upper 16 bits is
+ * written with module Id to ensure correctness of ref_count variable
+ */
+ atomic_cmpmask_and_set(&heapmemmp_module->ref_count,
+ HEAPMEMMP_MAKE_MAGICSTAMP(0),
+ HEAPMEMMP_MAKE_MAGICSTAMP(0));
+ if (atomic_inc_return(&heapmemmp_module->ref_count)
+ != HEAPMEMMP_MAKE_MAGICSTAMP(1)) {
+ return 1;
+ }
+
+ if (cfg == NULL) {
+ heapmemmp_get_config(&tmp_cfg);
+ cfg = &tmp_cfg;
+ }
+
+ if (cfg->max_name_len == 0 ||
+ cfg->max_name_len > HEAPMEMMP_MAX_NAME_LEN) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /* Initialize the parameters */
+ nameserver_params_init(&params);
+ params.max_value_len = sizeof(u32);
+ params.max_name_len = cfg->max_name_len;
+
+ /* Create the nameserver for modules */
+ heapmemmp_module->nameserver =
+ nameserver_create(HEAPMEMMP_NAMESERVER, &params);
+ if (heapmemmp_module->nameserver == NULL) {
+ retval = -EFAULT;
+ goto error;
+ }
+
+ /* Construct the list object */
+ INIT_LIST_HEAD(&heapmemmp_module->obj_list);
+ /* Copy config info */
+ memcpy(&heapmemmp_module->cfg, cfg, sizeof(struct heapmemmp_config));
+ /* Create a lock for protecting list object */
+ heapmemmp_module->local_lock = kmalloc(sizeof(struct mutex),
+ GFP_KERNEL);
+ mutex_init(heapmemmp_module->local_lock);
+ if (heapmemmp_module->local_lock == NULL) {
+ retval = -ENOMEM;
+ heapmemmp_destroy();
+ goto error;
+ }
+
+ return 0;
+
+error:
+ pr_err("heapmemmp_setup failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(heapmemmp_setup);
+
+/*
+ * This will destroy the heapmemmp module
+ */
+int heapmemmp_destroy(void)
+{
+ s32 retval = 0;
+ struct mutex *lock = NULL;
+ struct heapmemmp_obj *obj = NULL;
+
+ if (atomic_cmpmask_and_lt(&(heapmemmp_module->ref_count),
+ HEAPMEMMP_MAKE_MAGICSTAMP(0),
+ HEAPMEMMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (atomic_dec_return(&heapmemmp_module->ref_count)
+ == HEAPMEMMP_MAKE_MAGICSTAMP(0)) {
+ /* Temporarily increment ref_count here. */
+ atomic_set(&heapmemmp_module->ref_count,
+ HEAPMEMMP_MAKE_MAGICSTAMP(1));
+
+ /* Check if any heapmemmp instances have not been
+ * deleted/closed so far. if there any, delete or close them
+ */
+ list_for_each_entry(obj, &heapmemmp_module->obj_list,
+ list_elem) {
+ if (obj->owner.proc_id == multiproc_get_id(NULL))
+ retval = heapmemmp_delete(&obj->top);
+ else
+ retval = heapmemmp_close(obj->top);
+
+ if (list_empty(&heapmemmp_module->obj_list))
+ break;
+
+ if (retval < 0)
+ goto error;
+ }
+
+ /* Again reset ref_count. */
+ atomic_set(&heapmemmp_module->ref_count,
+ HEAPMEMMP_MAKE_MAGICSTAMP(0));
+
+ if (likely(heapmemmp_module->nameserver != NULL)) {
+ retval = nameserver_delete(&heapmemmp_module->
+ nameserver);
+ if (unlikely(retval != 0))
+ goto error;
+ }
+
+ /* Delete the list lock */
+ lock = heapmemmp_module->local_lock;
+ retval = mutex_lock_interruptible(lock);
+ if (retval)
+ goto error;
+
+ heapmemmp_module->local_lock = NULL;
+ mutex_unlock(lock);
+ kfree(lock);
+ memset(&heapmemmp_module->cfg, 0,
+ sizeof(struct heapmemmp_config));
+ }
+
+ return 0;
+
+error:
+ pr_err("heapmemmp_destroy failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(heapmemmp_destroy);
+
+/*
+ * This will get the intialization prams for a heapmemmp
+ * module instance
+ */
+void heapmemmp_params_init(struct heapmemmp_params *params)
+{
+ s32 retval = 0;
+
+ if (atomic_cmpmask_and_lt(&(heapmemmp_module->ref_count),
+ HEAPMEMMP_MAKE_MAGICSTAMP(0),
+ HEAPMEMMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ BUG_ON(params == NULL);
+
+ memcpy(params, &heapmemmp_module->default_inst_params,
+ sizeof(struct heapmemmp_params));
+
+ return;
+error:
+ pr_err("heapmemmp_params_init failed status: %x\n", retval);
+}
+EXPORT_SYMBOL(heapmemmp_params_init);
+
+/*
+ * This will create a new instance of heapmemmp module
+ * This is an internal function as both heapmemmp_create
+ * and heapmemmp_open use the functionality
+ *
+ * NOTE: The lock to protect the shared memory area
+ * used by heapmemmp is provided by the consumer of
+ * heapmemmp module
+ */
+static int _heapmemmp_create(void **handle_ptr,
+ const struct heapmemmp_params *params,
+ u32 create_flag)
+{
+ s32 retval = 0;
+ struct heapmemmp_obj *obj = NULL;
+ struct heapmemmp_object *handle = NULL;
+ void *gate_handle = NULL;
+ void *local_addr = NULL;
+ u32 *shared_shm_base;
+
+ if (atomic_cmpmask_and_lt(&(heapmemmp_module->ref_count),
+ HEAPMEMMP_MAKE_MAGICSTAMP(0),
+ HEAPMEMMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ BUG_ON(handle_ptr == NULL);
+
+ BUG_ON(params == NULL);
+
+ /* No need for parameter checks, since this is an internal function. */
+
+ /* Initialize return parameter. */
+ *handle_ptr = NULL;
+
+ handle = kmalloc(sizeof(struct heapmemmp_object), GFP_KERNEL);
+ if (handle == NULL) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ obj = kmalloc(sizeof(struct heapmemmp_obj), GFP_KERNEL);
+ if (obj == NULL) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ handle->obj = (struct heapmemmp_obj *)obj;
+ handle->alloc = &heapmemmp_alloc;
+ handle->free = &heapmemmp_free;
+ handle->get_stats = &heapmemmp_get_stats;
+ handle->is_blocking = &heapmemmp_isblocking;
+
+ obj->ns_key = NULL;
+ obj->alloc_size = 0;
+
+ /* Put in local ilst */
+ retval = mutex_lock_interruptible(heapmemmp_module->local_lock);
+ if (retval < 0)
+ goto error;
+
+ INIT_LIST_HEAD(&obj->list_elem);
+ list_add(&obj->list_elem, &heapmemmp_module->obj_list);
+ mutex_unlock(heapmemmp_module->local_lock);
+
+ if (create_flag == false) {
+ obj->owner.creator = false;
+ obj->owner.open_count = 0;
+ obj->owner.proc_id = MULTIPROC_INVALIDID;
+ obj->top = handle;
+
+ obj->attrs = (struct heapmemmp_attrs *) params->shared_addr;
+
+ /* No need to Cache_inv- already done in openByAddr() */
+ obj->buf = (char *) sharedregion_get_ptr((u32 *)obj->
+ attrs->buf_ptr);
+ obj->buf_size = obj->attrs->head.size;
+ obj->region_id = sharedregion_get_id(obj->buf);
+ obj->cache_enabled = sharedregion_is_cache_enabled(obj->
+ region_id);
+
+ /* Set min_align */
+ obj->min_align = sizeof(struct heapmemmp_header);
+ if (sharedregion_get_cache_line_size(obj->region_id)
+ > obj->min_align) {
+ obj->min_align = sharedregion_get_cache_line_size(
+ obj->region_id);
+ }
+
+ local_addr = sharedregion_get_ptr((u32 *)obj->attrs->
+ gatemp_addr);
+ retval = gatemp_open_by_addr(local_addr, &gate_handle);
+ if (retval < 0) {
+ retval = -EFAULT;
+ goto error;
+ }
+ obj->gate = gate_handle;
+
+
+ } else {
+ obj->owner.creator = true;
+ obj->owner.open_count = 1;
+ obj->owner.proc_id = multiproc_self();
+ obj->top = handle;
+
+ /* Creating the gate */
+ if (params->gate != NULL)
+ obj->gate = params->gate;
+ else {
+ /* If no gate specified, get the default system gate */
+ obj->gate = gatemp_get_default_remote();
+ }
+
+ if (obj->gate == NULL) {
+ retval = -EFAULT;
+ goto error;
+ }
+
+ obj->buf_size = params->shared_buf_size;
+
+ if (params->shared_addr == NULL) {
+ /* Creating using a shared region ID */
+ /* It is allowed to have NULL name for an anonymous,
+ * not to be opened by name, heap.
+ */
+ /* Will be allocated in post_init */
+ obj->attrs = NULL;
+ obj->region_id = params->region_id;
+ } else {
+ /* Creating using shared_addr */
+ obj->region_id = sharedregion_get_id(params->
+ shared_addr);
+
+ /* Assert that the buffer is in a valid shared
+ * region
+ */
+ if (obj->region_id == SHAREDREGION_INVALIDREGIONID) {
+ retval = -EFAULT;
+ goto error;
+ } else if ((u32) params->shared_addr
+ % sharedregion_get_cache_line_size(obj->
+ region_id) != 0) {
+ retval = -EFAULT;
+ goto error;
+ }
+ /* obj->buf will get alignment-adjusted in
+ * postInit
+ */
+ obj->buf = (char *)((u32)params->shared_addr + \
+ sizeof(struct heapmemmp_attrs));
+ obj->attrs = (struct heapmemmp_attrs *)
+ params->shared_addr;
+ }
+
+ obj->cache_enabled = sharedregion_is_cache_enabled(
+ obj->region_id);
+
+ /* Set min_align */
+ obj->min_align = sizeof(struct heapmemmp_header);
+ if (sharedregion_get_cache_line_size(obj->region_id)
+ > obj->min_align)
+ obj->min_align = sharedregion_get_cache_line_size(
+ obj->region_id);
+ retval = heapmemmp_post_init(handle);
+ if (retval < 0) {
+ retval = -EFAULT;
+ goto error;
+ }
+
+ /* Populate the params member */
+ memcpy(&obj->params, params, sizeof(struct heapmemmp_params));
+ if (params->name != NULL) {
+ obj->params.name = kmalloc(strlen(params->name) + 1,
+ GFP_KERNEL);
+ if (obj->params.name == NULL) {
+ retval = -ENOMEM;
+ goto error;
+ }
+ strncpy(obj->params.name, params->name,
+ strlen(params->name) + 1);
+ }
+
+ /* We will store a shared pointer in the NameServer */
+ shared_shm_base = sharedregion_get_srptr(obj->attrs,
+ obj->region_id);
+ if (obj->params.name != NULL) {
+ obj->ns_key =
+ nameserver_add_uint32(heapmemmp_module->nameserver,
+ params->name,
+ (u32) shared_shm_base);
+ if (obj->ns_key == NULL) {
+ retval = -EFAULT;
+ goto error;
+ }
+ }
+ }
+
+ *handle_ptr = (void *)handle;
+ return retval;
+
+error:
+ handle_ptr = (void *)handle;
+ /* Do whatever cleanup is required*/
+ if (create_flag == true)
+ heapmemmp_delete(handle_ptr);
+ else
+ heapmemmp_close(handle_ptr);
+ pr_err("_heapmemmp_create failed status: %x\n", retval);
+ return retval;
+}
+
+/*
+ * This will create a new instance of heapmemmp module
+ */
+void *heapmemmp_create(const struct heapmemmp_params *params)
+{
+ s32 retval = 0;
+ struct heapmemmp_object *handle = NULL;
+ struct heapmemmp_params sparams;
+
+ BUG_ON(params == NULL);
+
+ if (atomic_cmpmask_and_lt(&(heapmemmp_module->ref_count),
+ HEAPMEMMP_MAKE_MAGICSTAMP(0),
+ HEAPMEMMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (params == NULL) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (params->shared_buf_size == 0) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ memcpy(&sparams, (void *)params, sizeof(struct heapmemmp_params));
+ retval = _heapmemmp_create((void **)&handle, params, true);
+ if (retval < 0)
+ goto error;
+
+ return (void *)handle;
+
+error:
+ pr_err("heapmemmp_create failed status: %x\n", retval);
+ return (void *)handle;
+}
+EXPORT_SYMBOL(heapmemmp_create);
+
+/*
+ * This will delete an instance of heapmemmp module
+ */
+int heapmemmp_delete(void **handle_ptr)
+{
+ int status = 0;
+ struct heapmemmp_object *handle = NULL;
+ struct heapmemmp_obj *obj = NULL;
+ struct heapmemmp_params *params = NULL;
+ struct heapmemmp_object *region_heap = NULL;
+ s32 retval = 0;
+ int *key = NULL;
+
+ if (atomic_cmpmask_and_lt(&(heapmemmp_module->ref_count),
+ HEAPMEMMP_MAKE_MAGICSTAMP(0),
+ HEAPMEMMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(handle_ptr == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ handle = (struct heapmemmp_object *)(*handle_ptr);
+ if (WARN_ON(handle == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ obj = (struct heapmemmp_obj *)handle->obj;
+ if (obj != NULL) {
+ if (obj->owner.proc_id != multiproc_self()) {
+ status = -ENODEV;
+ goto error;
+ }
+
+ /* Take the local lock */
+ key = gatemp_enter(obj->gate);
+
+ if (obj->owner.open_count > 1) {
+ retval = -ENODEV;
+ goto device_busy_error;
+ }
+
+ retval = mutex_lock_interruptible(heapmemmp_module->local_lock);
+ if (retval < 0)
+ goto lock_error;
+
+ /* Remove frmo the local list */
+ list_del(&obj->list_elem);
+
+ mutex_unlock(heapmemmp_module->local_lock);
+
+ params = (struct heapmemmp_params *) &obj->params;
+
+ if (likely(params->name != NULL)) {
+ if (likely(obj->ns_key != NULL)) {
+ nameserver_remove_entry(heapmemmp_module->
+ nameserver, obj->ns_key);
+ obj->ns_key = NULL;
+ }
+ kfree(params->name);
+ }
+
+ /* Set status to 'not created' */
+ if (obj->attrs != NULL) {
+#if 0
+ obj->attrs->status = 0;
+ if (obj->cache_enabled) {
+ cache_wbinv(obj->attrs,
+ sizeof(struct heapmemmp_attrs),
+ CACHE_TYPE_ALL, true);
+ }
+#endif
+ }
+
+ /* Release the shared lock */
+ gatemp_leave(obj->gate, key);
+
+ /* If necessary, free shared memory if memory is internally
+ * allocated
+ */
+ region_heap = sharedregion_get_heap(obj->region_id);
+
+ if ((region_heap != NULL) &&
+ (obj->params.shared_addr == NULL) &&
+ (obj->attrs != NULL)) {
+ sl_heap_free(region_heap, obj->attrs, obj->alloc_size);
+ }
+
+ kfree(obj);
+ kfree(region_heap);
+
+ *handle_ptr = NULL;
+ } else { /* obj == NULL */
+ kfree(handle);
+ *handle_ptr = NULL;
+ }
+
+ return 0;
+
+lock_error:
+device_busy_error:
+ gatemp_leave(obj->gate, key);
+
+error:
+ pr_err("heapmemmp_delete failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(heapmemmp_delete);
+
+/*
+ * This will opens a created instance of heapmemmp
+ * module
+ */
+int heapmemmp_open(char *name, void **handle_ptr)
+{
+ s32 retval = 0;
+ u32 *shared_shm_base = SHAREDREGION_INVALIDSRPTR;
+ void *shared_addr = NULL;
+ struct heapmemmp_obj *obj = NULL;
+ bool done_flag = false;
+ struct list_head *elem = NULL;
+
+ BUG_ON(name == NULL);
+ BUG_ON(handle_ptr == NULL);
+
+ if (unlikely(
+ atomic_cmpmask_and_lt(&(heapmemmp_module->ref_count),
+ HEAPMEMMP_MAKE_MAGICSTAMP(0),
+ HEAPMEMMP_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (name == NULL) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (handle_ptr == NULL) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /* First check in the local list */
+ list_for_each(elem, &heapmemmp_module->obj_list) {
+ obj = (struct heapmemmp_obj *)elem;
+ if (obj->params.name != NULL) {
+ if (strcmp(obj->params.name, name)
+ == 0) {
+ retval = mutex_lock_interruptible(
+ heapmemmp_module->local_lock);
+ if (retval < 0)
+ goto error;
+ /* Check if we have created the heapmemmp */
+ /* or not */
+ if (obj->owner.proc_id == multiproc_self())
+ obj->owner.open_count++;
+
+ *handle_ptr = (void *)obj->top;
+ mutex_unlock(heapmemmp_module->local_lock);
+ done_flag = true;
+ break;
+ }
+ }
+ }
+
+ if (likely(done_flag == false)) {
+ /* Find in name server */
+ retval = nameserver_get_uint32(heapmemmp_module->nameserver,
+ name,
+ &shared_shm_base,
+ NULL);
+ if (unlikely(retval < 0))
+ goto error;
+
+ /*
+ * Convert from shared region pointer to local address
+ */
+ shared_addr = sharedregion_get_ptr(shared_shm_base);
+ if (unlikely(shared_addr == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ retval = heapmemmp_open_by_addr(shared_addr, handle_ptr);
+
+ if (unlikely(retval < 0))
+ goto error;
+ }
+
+ return 0;
+
+error:
+ pr_err("heapmemmp_open failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(heapmemmp_open);
+
+/*
+ * This will closes previously opened/created instance
+ * of heapmemmp module
+ */
+int heapmemmp_close(void **handle_ptr)
+{
+ struct heapmemmp_object *handle = NULL;
+ struct heapmemmp_obj *obj = NULL;
+ s32 retval = 0;
+
+ if (atomic_cmpmask_and_lt(&(heapmemmp_module->ref_count),
+ HEAPMEMMP_MAKE_MAGICSTAMP(0),
+ HEAPMEMMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(handle_ptr == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (WARN_ON(*handle_ptr == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ handle = (struct heapmemmp_object *)(*handle_ptr);
+ obj = (struct heapmemmp_obj *)handle->obj;
+
+ if (obj != NULL) {
+ retval = mutex_lock_interruptible(heapmemmp_module->
+ local_lock);
+ if (retval)
+ goto error;
+
+ /* opening an instance created locally */
+ if (obj->owner.proc_id == multiproc_self())
+ obj->owner.open_count--;
+
+ /* Check if HeapMemMP is opened on same processor and
+ * this is the last closure.
+ */
+ if ((obj->owner.creator == false) &&
+ (obj->owner.open_count == 0)) {
+ list_del(&obj->list_elem);
+
+ if (obj->gate != NULL) {
+ /* Close the instance gate */
+ gatemp_close(&obj->gate);
+ }
+
+ /* Now free the handle */
+ kfree(obj);
+ obj = NULL;
+ kfree(handle);
+ *handle_ptr = NULL;
+ }
+
+ mutex_unlock(heapmemmp_module->local_lock);
+ } else {
+ kfree(handle);
+ *handle_ptr = NULL;
+ }
+ return 0;
+
+error:
+ pr_err("heapmemmp_close failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(heapmemmp_close);
+
+/*
+ * This will allocs a block of memory
+ */
+void *heapmemmp_alloc(void *hphandle, u32 size, u32 align)
+{
+ char *alloc_addr = NULL;
+ struct heapmemmp_object *handle = NULL;
+ struct heapmemmp_obj *obj = NULL;
+ int *key = NULL;
+ struct heapmemmp_header *prev_header;
+ struct heapmemmp_header *new_header;
+ struct heapmemmp_header *cur_header;
+ u32 cur_size;
+ u32 adj_size;
+ u32 remain_size;
+ u32 adj_align;
+ u32 offset;
+ s32 retval = 0;
+
+ if (atomic_cmpmask_and_lt(&(heapmemmp_module->ref_count),
+ HEAPMEMMP_MAKE_MAGICSTAMP(0),
+ HEAPMEMMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+ if (WARN_ON(hphandle == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+ if (WARN_ON(size == 0)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ handle = (struct heapmemmp_object *)(hphandle);
+ obj = (struct heapmemmp_obj *)handle->obj;
+ if (WARN_ON(obj == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ adj_size = size;
+
+ /* Make size requested a multipel of min_align */
+ offset = (adj_size & (obj->min_align - 1));
+ if (offset != 0)
+ adj_size += (obj->min_align - offset);
+
+ /*
+ * Make sure the alignment is at least as large as obj->min_align
+ * Note: adjAlign must be a power of 2 (by function constraint) and
+ * obj->min_align is also a power of 2,
+ */
+ adj_align = align;
+ if (adj_align == 0)
+ adj_align = obj->min_align;
+
+ if (adj_align & (obj->min_align - 1))
+ /* adj_align is less than obj->min_align */
+ adj_align = obj->min_align;
+
+ /* No need to Cache_inv Attrs- 'head' should be constant */
+ prev_header = (struct heapmemmp_header *) &obj->attrs->head;
+
+ key = gatemp_enter(obj->gate);
+ /*
+ * The block will be allocated from cur_header. Maintain a pointer to
+ * prev_header so prev_header->next can be updated after the alloc.
+ */
+#if 0
+ if (unlikely(obj->cache_enabled))
+ Cache_inv(prev_header,
+ sizeof(struct heapmemmp_header),
+ Cache_Type_ALL,
+ true); /* A1 */
+#endif
+ cur_header = (struct heapmemmp_header *)
+ sharedregion_get_ptr(prev_header->next);
+ /* A1 */
+
+ /* Loop over the free list. */
+ while (cur_header != NULL) {
+#if 0
+ /* Invalidate cur_header */
+ if (unlikely(obj->cache_enabled))
+ Cache_inv(cur_header,
+ sizeof(struct heapmemmp_header),
+ Cache_Type_ALL,
+ true); /* A2 */
+#endif
+
+ cur_size = cur_header->size;
+
+ /*
+ * Determine the offset from the beginning to make sure
+ * the alignment request is honored.
+ */
+ offset = (u32)cur_header & (adj_align - 1);
+ if (offset)
+ offset = adj_align - offset;
+
+ /* Internal Assert that offset is a multiple of */
+ /* obj->min_align */
+ if (((offset & (obj->min_align - 1)) != 0)) {
+ retval = -EINVAL;
+ goto error;
+ }
+ /* big enough? */
+
+ /* This is the "else" part of the next if block, but we are */
+ /* moving it here to save indent space */
+ if (cur_size < (adj_size + offset)) {
+ prev_header = cur_header;
+ cur_header = sharedregion_get_ptr(cur_header->next);
+ /* We can quit this iteration of the while loop here */
+ continue;
+ }
+
+ /* if (cur_size >= (adj_size + offset)) */
+
+ /* Set the pointer that will be returned. */
+ /* Alloc from front */
+ alloc_addr = (char *) ((u32) cur_header + offset);
+ /*
+ * Determine the remaining memory after the
+ * allocated block.
+ * Note: this cannot be negative because of above
+ * comparison.
+ */
+ remain_size = cur_size - adj_size - offset;
+
+ /* Internal Assert that remain_size is a multiple of
+ * obj->min_align
+ */
+ if (((remain_size & (obj->min_align - 1)) != 0)) {
+ alloc_addr = NULL;
+ break;
+ }
+ /*
+ * If there is memory at the beginning (due to alignment
+ * requirements), maintain it in the list.
+ *
+ * offset and remain_size must be multiples of sizeof(struct
+ * heapmemmp_header). Therefore the address of the new_header
+ * below must be a multiple of the sizeof(struct
+ * heapmemmp_header), thus maintaining the requirement.
+ */
+ if (offset) {
+ /* Adjust the cur_header size accordingly */
+ cur_header->size = offset; /* B2 */
+ /* Cache wb at end of this if block */
+
+ /*
+ * If there is remaining memory, add into the free
+ * list.
+ * Note: no need to coalesce and we have heapmemmp
+ * locked so it is safe.
+ */
+ if (offset && remain_size) {
+ new_header = (struct heapmemmp_header *)
+ ((u32) alloc_addr + adj_size);
+
+ /* cur_header has been inv at top of 'while' */
+ /* loop */
+ new_header->next = cur_header->next; /* B1 */
+ new_header->size = remain_size; /* B1 */
+#if 0
+ if (unlikely(obj->cache_enabled))
+ /* Writing back cur_header will */
+ /* cache-wait */
+ Cache_wbInv(new_header,
+ sizeof(struct
+ heapmemmp_header),
+ Cache_Type_ALL,
+ false); /* B1 */
+#endif
+
+ cur_header->next = sharedregion_get_srptr
+ (new_header,
+ obj->region_id);
+ BUG_ON(cur_header->next
+ == SHAREDREGION_INVALIDSRPTR);
+ }
+#if 0
+ /* Write back (and invalidate) new_header and */
+ /* cur_header */
+ if (unlikely(obj->cache_enabled))
+ /* B2 */
+ Cache_wbInv(cur_header,
+ sizeof(struct heapmemmp_header),
+ Cache_Type_ALL,
+ true);
+#endif
+ } else if (remain_size) {
+ /*
+ * If there is any remaining, link it in,
+ * else point to the next free block.
+ * Note: no need to coalesce and we have heapmemmp
+ * locked so it is safe.
+ */
+
+ new_header = (struct heapmemmp_header *)
+ ((u32) alloc_addr + adj_size);
+
+ new_header->next = cur_header->next; /* A2, B3 */
+ new_header->size = remain_size; /* B3 */
+
+#if 0
+ if (unlikely(obj->cache_enabled))
+ /* Writing back prev_header will cache-wait */
+ Cache_wbInv(new_header,
+ sizeof(struct heapmemmp_header),
+ Cache_Type_ALL,
+ false); /* B3 */
+#endif
+
+ /* B4 */
+ prev_header->next = sharedregion_get_srptr(new_header,
+ obj->region_id);
+ } else
+ /* cur_header has been inv at top of 'while' loop */
+ prev_header->next = cur_header->next; /* A2, B4 */
+
+#if 0
+ if (unlikely(obj->cache_enabled))
+ /* B4 */
+ Cache_wbInv(prev_header,
+ sizeof(struct heapmemmp_header),
+ Cache_Type_ALL,
+ true);
+#endif
+
+ /* Success, return the allocated memory */
+ break;
+
+ }
+
+ gatemp_leave(obj->gate, key);
+
+ if (alloc_addr == NULL)
+ pr_err("heapmemmp_alloc returned NULL\n");
+ return alloc_addr;
+
+error:
+ pr_err("heapmemmp_alloc failed status: %x\n", retval);
+ return NULL;
+}
+EXPORT_SYMBOL(heapmemmp_alloc);
+
+/*
+ * This will free a block of memory
+ */
+int heapmemmp_free(void *hphandle, void *addr, u32 size)
+{
+ struct heapmemmp_object *handle = NULL;
+ s32 retval = 0;
+ struct heapmemmp_obj *obj = NULL;
+ int *key = NULL;
+ struct heapmemmp_header *next_header;
+ struct heapmemmp_header *new_header;
+ struct heapmemmp_header *cur_header;
+ u32 offset;
+
+ if (atomic_cmpmask_and_lt(&(heapmemmp_module->ref_count),
+ HEAPMEMMP_MAKE_MAGICSTAMP(0),
+ HEAPMEMMP_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto error;
+ }
+ if (WARN_ON(hphandle == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+ if (WARN_ON(addr == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ handle = (struct heapmemmp_object *)(hphandle);
+ obj = (struct heapmemmp_obj *)handle->obj;
+ if (WARN_ON(obj == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * obj->attrs never changes, doesn't need Gate protection
+ * and Cache invalidate
+ */
+ cur_header = (struct heapmemmp_header *) &(obj->attrs->head);
+
+ /* Restore size to actual allocated size */
+ offset = size & (obj->min_align - 1);
+ if (offset != 0)
+ size += obj->min_align - offset;
+
+ key = gatemp_enter(obj->gate);
+
+ new_header = (struct heapmemmp_header *) addr;
+
+#if 0
+ if (unlikely(obj->cacheEnabled)) {
+ /* A1 */
+ Cache_inv(cur_header,
+ sizeof(struct heapmemmp_header),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+ next_header = sharedregion_get_ptr(cur_header->next);
+
+ if (unlikely(!(((u32)new_header >= (u32)obj->buf)
+ && ((u32)new_header + size
+ <= (u32)obj->buf + obj->buf_size)))) {
+ retval = -EFAULT;
+ goto error;
+ }
+ /* Go down freelist and find right place for buf */
+ while ((next_header != NULL) && (next_header < new_header)) {
+#if 0
+ if (unlikely(obj->cacheEnabled))
+ Cache_inv(next_header,
+ sizeof(struct heapmemmp_header),
+ Cache_Type_ALL,
+ true); /* A2 */
+#endif
+
+ /* Make sure the addr is not in this free block */
+ if (unlikely((u32)new_header < \
+ ((u32)next_header + next_header->size))) {
+ /* A2 */
+ retval = -EFAULT;
+ goto error;
+ }
+
+ cur_header = next_header;
+ /* A2 */
+ next_header = sharedregion_get_ptr(next_header->next);
+ }
+
+ new_header->next = sharedregion_get_srptr(next_header,
+ obj->region_id);
+ new_header->size = size;
+
+ /* B1, A1 */
+ cur_header->next = sharedregion_get_srptr(new_header,
+ obj->region_id);
+
+ /* Join contiguous free blocks */
+ if (next_header != NULL) {
+ /*
+ * Verify the free size is not overlapping. Not all cases
+ * are detectable, but it is worth a shot. Note: only do
+ * this assert if next_header is non-NULL.
+ */
+ if (unlikely(((u32)new_header + size) > (u32)next_header)) {
+ /* A2 */
+ retval = -EFAULT;
+ goto error;
+ }
+ /* Join with upper block */
+ if (((u32)new_header + size) == (u32)next_header) {
+#if 0
+ if (unlikely(obj->cacheEnabled))
+ Cache_inv(next_header,
+ sizeof(struct heapmemmp_header),
+ Cache_Type_ALL,
+ true);
+#endif
+ new_header->next = next_header->next; /* A2, B2 */
+ new_header->size += next_header->size; /* A2, B2 */
+ /* Don't Cache_wbInv, this will be done later */
+ }
+ }
+
+ /*
+ * Join with lower block. Make sure to check to see if not the
+ * first block. No need to invalidate attrs since head
+ * shouldn't change.
+ */
+ if ((cur_header != &obj->attrs->head)
+ && (((u32) cur_header + cur_header->size)
+ == (u32) new_header)) {
+ /*
+ * Don't Cache_inv new_header since new_header has
+ * data that hasn't been written back yet (B2)
+ */
+ cur_header->next = new_header->next; /* B1, B2 */
+ cur_header->size += new_header->size; /* B1, B2 */
+ }
+#if 0
+ if (unlikely(obj->cacheEnabled)) {
+ Cache_wbInv(cur_header,
+ sizeof(struct heapmemmp_header),
+ Cache_Type_ALL,
+ false); /* B1 */
+ Cache_wbInv(new_header,
+ sizeof(struct heapmemmp_header),
+ Cache_Type_ALL,
+ true); /* B2 */
+ }
+#endif
+
+ gatemp_leave(obj->gate, key);
+ return 0;
+
+error:
+ pr_err("heapmemmp_free failed status: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(heapmemmp_free);
+
+/*
+ * This will get memory statistics
+ */
+void heapmemmp_get_stats(void *hphandle, struct memory_stats *stats)
+{
+ struct heapmemmp_object *object = NULL;
+ struct heapmemmp_obj *obj = NULL;
+ struct heapmemmp_header *cur_header = NULL;
+ int *key = NULL;
+ s32 status = 0;
+
+ if (atomic_cmpmask_and_lt(&(heapmemmp_module->ref_count),
+ HEAPMEMMP_MAKE_MAGICSTAMP(0),
+ HEAPMEMMP_MAKE_MAGICSTAMP(1)) == true) {
+ status = -ENODEV;
+ goto error;
+ }
+ if (WARN_ON(hphandle == NULL)) {
+ status = -EINVAL;
+ goto error;
+ }
+ if (WARN_ON(stats == NULL)) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ object = (struct heapmemmp_object *)(hphandle);
+ obj = (struct heapmemmp_obj *)object->obj;
+ if (WARN_ON(obj == NULL)) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ stats->total_size = obj->buf_size;
+ stats->total_free_size = 0; /* determined later */
+ stats->largest_free_size = 0; /* determined later */
+
+ key = gatemp_enter(obj->gate);
+ cur_header = sharedregion_get_ptr(obj->attrs->head.next);
+
+ while (cur_header != NULL) {
+#if 0
+ /* Invalidate cur_header */
+ if (unlikely(obj->cacheEnabled)) {
+ Cache_inv(cur_header,
+ sizeof(struct heapmemmp_header),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+ stats->total_free_size += cur_header->size;
+ if (stats->largest_free_size < cur_header->size)
+ stats->largest_free_size = cur_header->size;
+
+ /* This condition is required to avoid assertions during call
+ * to SharedRegion_getPtr because at the end of the
+ * calculation cur_header->next will become
+ * SHAREDREGION_INVALIDSRPTR.
+ */
+ if (cur_header->next != SHAREDREGION_INVALIDSRPTR)
+ cur_header = sharedregion_get_ptr(cur_header->next);
+ else
+ cur_header = NULL;
+ }
+
+ gatemp_leave(obj->gate, key);
+error:
+ if (status < 0)
+ pr_err("heapmemmp_get_stats status: %x\n", status);
+}
+EXPORT_SYMBOL(heapmemmp_get_stats);
+
+/*
+ * Indicate whether the heap may block during an alloc or free call
+ */
+bool heapmemmp_isblocking(void *handle)
+{
+ bool isblocking = false;
+ s32 retval = 0;
+
+ if (WARN_ON(handle == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /* TBD: Figure out how to determine whether the gate is blocking */
+ isblocking = true;
+
+ /* retval true Heap blocks during alloc/free calls */
+ /* retval false Heap does not block during alloc/free calls */
+ return isblocking;
+
+error:
+ pr_err("heapmemmp_isblocking status: %x\n", retval);
+ return isblocking;
+}
+EXPORT_SYMBOL(heapmemmp_isblocking);
+
+/*
+ * This will get extended statistics
+ */
+void heapmemmp_get_extended_stats(void *hphandle,
+ struct heapmemmp_extended_stats *stats)
+{
+ int status = 0;
+ struct heapmemmp_object *object = NULL;
+ struct heapmemmp_obj *obj = NULL;
+
+ if (atomic_cmpmask_and_lt(&(heapmemmp_module->ref_count),
+ HEAPMEMMP_MAKE_MAGICSTAMP(0),
+ HEAPMEMMP_MAKE_MAGICSTAMP(1)) == true) {
+ status = -ENODEV;
+ goto error;
+ }
+ if (WARN_ON(heapmemmp_module->nameserver == NULL)) {
+ status = -EINVAL;
+ goto error;
+ }
+ if (WARN_ON(hphandle == NULL)) {
+ status = -EINVAL;
+ goto error;
+ }
+ if (WARN_ON(stats == NULL)) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ object = (struct heapmemmp_object *)hphandle;
+ obj = (struct heapmemmp_obj *)object->obj;
+ if (WARN_ON(obj == NULL)) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ stats->buf = obj->buf;
+ stats->size = obj->buf_size;
+
+ return;
+
+error:
+ pr_err("heapmemmp_get_extended_stats status: %x\n", status);
+}
+EXPORT_SYMBOL(heapmemmp_get_extended_stats);
+
+/*
+ * This will get amount of shared memory required for
+ * creation of each instance
+ */
+int heapmemmp_shared_mem_req(const struct heapmemmp_params *params)
+{
+ int mem_req = 0;
+ s32 retval = 0;
+ u32 region_id;
+ u32 min_align;
+
+ if (params == NULL) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (params->shared_addr == NULL)
+ region_id = params->region_id;
+ else
+ region_id = sharedregion_get_id(params->shared_addr);
+
+ if (region_id == SHAREDREGION_INVALIDREGIONID) {
+ retval = -EFAULT;
+ goto error;
+ }
+
+ min_align = sizeof(struct heapmemmp_header);
+ if (sharedregion_get_cache_line_size(region_id) > min_align)
+ min_align = sharedregion_get_cache_line_size(region_id);
+
+ /* Add size of heapmemmp Attrs */
+ mem_req = ROUND_UP(sizeof(struct heapmemmp_attrs), min_align);
+
+ /* Add the buffer size */
+ mem_req += params->shared_buf_size;
+
+ /* Make sure the size is a multiple of min_align (round down) */
+ mem_req = (mem_req / min_align) * min_align;
+
+ return mem_req;
+
+error:
+ pr_err("heapmemmp_shared_mem_req retval: %x\n", retval);
+ return mem_req;
+}
+EXPORT_SYMBOL(heapmemmp_shared_mem_req);
+
+
+/*
+ * Open existing heapmemmp based on address
+ */
+int
+heapmemmp_open_by_addr(void *shared_addr, void **handle_ptr)
+{
+ s32 retval = 0;
+ bool done_flag = false;
+ struct heapmemmp_attrs *attrs = NULL;
+ struct list_head *elem = NULL;
+ u16 id = 0;
+ struct heapmemmp_params params;
+ struct heapmemmp_obj *obj = NULL;
+
+ BUG_ON(handle_ptr == NULL);
+ BUG_ON(shared_addr == NULL);
+
+ if (unlikely(atomic_cmpmask_and_lt(&(heapmemmp_module->ref_count),
+ HEAPMEMMP_MAKE_MAGICSTAMP(0),
+ HEAPMEMMP_MAKE_MAGICSTAMP(1))
+ == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (unlikely(handle_ptr == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /* First check in the local list */
+ list_for_each(elem, (struct list_head *)&heapmemmp_module->obj_list) {
+ obj = (struct heapmemmp_obj *)elem;
+ if (obj->params.shared_addr == shared_addr) {
+ retval = mutex_lock_interruptible(heapmemmp_module->
+ local_lock);
+ if (retval < 0)
+ goto error;
+
+ if (obj->owner.proc_id == multiproc_self())
+ obj->owner.open_count++;
+
+ mutex_unlock(heapmemmp_module->local_lock);
+ *handle_ptr = obj->top;
+ done_flag = true;
+ break;
+ }
+ }
+
+ /* If not already existing locally, create object locally for open. */
+ if (unlikely(done_flag == false)) {
+ heapmemmp_params_init(&params);
+ params.shared_addr = shared_addr;
+ attrs = (struct heapmemmp_attrs *) shared_addr;
+ id = sharedregion_get_id(shared_addr);
+#if 0
+ if (unlikely(sharedregion_is_cache_enabled(id))) {
+ Cache_inv(attrs,
+ sizeof(struct heapmemmp_attrs),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+ if (unlikely(attrs->status != HEAPMEMMP_CREATED)) {
+ *handle_ptr = NULL;
+ retval = -ENOENT;
+ goto error;
+ }
+
+ retval = _heapmemmp_create(handle_ptr, &params, false);
+ if (unlikely(retval < 0))
+ goto error;
+ }
+ return 0;
+
+error:
+ pr_err("heapmemmp_open_by_addr status: %x\n", retval);
+ return retval;
+}
+
+
+/* =============================================================================
+ * Internal functions
+ * =============================================================================
+ */
+/*
+ * Slice and dice the buffer up into the correct size blocks and
+ * add to the freelist.
+ */
+static int heapmemmp_post_init(struct heapmemmp_object *handle)
+{
+ s32 retval = 0;
+ struct heapmemmp_obj *obj = NULL;
+ struct heapmemmp_object *region_heap = NULL;
+ struct heapmemmp_params params;
+
+ BUG_ON(handle == NULL);
+
+ obj = (struct heapmemmp_obj *) handle->obj;
+ if (obj->attrs == NULL) {
+ heapmemmp_params_init(&params);
+ params.region_id = obj->region_id;
+ params.shared_buf_size = obj->buf_size;
+ obj->alloc_size = heapmemmp_shared_mem_req(&params);
+ region_heap = sharedregion_get_heap(obj->region_id);
+
+ if (region_heap == NULL) {
+ retval = -EFAULT;
+ goto error;
+ }
+
+ obj->attrs = sl_heap_alloc(region_heap,
+ obj->alloc_size,
+ obj->min_align);
+
+ if (obj->attrs == NULL) {
+ retval = -ENOMEM;
+ goto error;
+ }
+ obj->buf = (void *)((u32)obj->attrs +
+ sizeof(struct heapmemmp_attrs));
+ }
+
+ /* Round obj->buf up by obj->min_align */
+ obj->buf = (void *) ROUND_UP((u32)obj->buf, (obj->min_align));
+
+ if (unlikely(obj->buf_size
+ < sharedregion_get_cache_line_size(obj->region_id))) {
+ retval = -EFAULT;
+ goto error;
+ }
+
+ /* Make sure the size is a multiple of obj->min_align */
+ obj->buf_size = (obj->buf_size / obj->min_align) * obj->min_align;
+
+ obj->attrs->gatemp_addr = gatemp_get_shared_addr(obj->gate);
+ obj->attrs->buf_ptr = sharedregion_get_srptr(obj->buf, obj->region_id);
+
+ /* Store computed obj->buf_size in shared mem */
+ obj->attrs->head.size = obj->buf_size;
+
+ /* Place the initial header */
+ heapmemmp_restore((struct heapmemmp_object *) handle);
+
+ /* Last thing, set the status */
+ obj->attrs->status = HEAPMEMMP_CREATED;
+#if 0
+ if (unlikely(obj->cacheEnabled))
+ Cache_wbInv((Ptr) obj->attrs,
+ sizeof(heapmemmp_Attrs),
+ Cache_Type_ALL,
+ true);
+#endif
+
+ return 0;
+error:
+ pr_err("heapmemmp_post_init status: %x\n", retval);
+ return retval;
+}
+
+
+/*
+ * Restore an instance to it's original created state.
+ */
+void
+heapmemmp_restore(void *handle)
+{
+ struct heapmemmp_header *beg_header = NULL;
+ struct heapmemmp_obj *obj = NULL;
+
+ obj = ((struct heapmemmp_object *) handle)->obj;
+ BUG_ON(obj == NULL);
+
+ /*
+ * Fill in the top of the memory block
+ * next: pointer will be NULL (end of the list)
+ * size: size of this block
+ * NOTE: no need to Cache_inv because obj->attrs->bufPtr
+ * should be const
+ */
+ beg_header = (struct heapmemmp_header *) obj->buf;
+ beg_header->next = (u32 *)SHAREDREGION_INVALIDSRPTR;
+ beg_header->size = obj->buf_size;
+
+ obj->attrs->head.next = (u32 *)obj->attrs->buf_ptr;
+#if 0
+ if (unlikely(obj->cacheEnabled)) {
+ Cache_wbInv((Ptr)&(obj->attrs->head),
+ sizeof(struct heapmemmp_header),
+ Cache_Type_ALL,
+ false);
+ Cache_wbInv(begHeader,
+ sizeof(struct heapmemmp_header),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/heapmemmp_ioctl.c b/drivers/dsp/syslink/multicore_ipc/heapmemmp_ioctl.c
new file mode 100644
index 00000000000..11d73696500
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/heapmemmp_ioctl.c
@@ -0,0 +1,567 @@
+/*
+ * heapmemmp_ioctl.c
+ *
+ * Heap module manages fixed size buffers that can be used
+ * in a multiprocessor system with shared memory.
+ *
+ * Copyright (C) 2008-2009 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 <linux/uaccess.h>
+#include <linux/types.h>
+#include <linux/bug.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <ipc.h>
+#include <heap.h>
+#include <heapmemmp_ioctl.h>
+#include <sharedregion.h>
+
+static struct resource_info *find_heapmemmp_resource(
+ struct ipc_process_context *pr_ctxt,
+ unsigned int cmd,
+ struct heapmemmp_cmd_args *cargs)
+{
+ struct resource_info *info = NULL;
+ bool found = false;
+
+ spin_lock(&pr_ctxt->res_lock);
+
+ list_for_each_entry(info, &pr_ctxt->resources, res) {
+ struct heapmemmp_cmd_args *args =
+ (struct heapmemmp_cmd_args *)info->data;
+ if (info->cmd == cmd) {
+ switch (cmd) {
+ case CMD_HEAPMEMMP_DELETE:
+ {
+ void *handle = args->args.delete.handle;
+ void *temp = cargs->args.delete.handle;
+ if (temp == handle)
+ found = true;
+ break;
+ }
+ case CMD_HEAPMEMMP_DESTROY:
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found == true)
+ break;
+ }
+ }
+
+ spin_unlock(&pr_ctxt->res_lock);
+
+ if (found == false)
+ info = NULL;
+
+ return info;
+}
+
+/*
+ * ======== heapmemmp_ioctl_alloc ========
+ * Purpose:
+ * This ioctl interface to heapmemmp_alloc function
+ */
+static int heapmemmp_ioctl_alloc(struct heapmemmp_cmd_args *cargs)
+{
+ u32 *block_srptr = SHAREDREGION_INVALIDSRPTR;
+ void *block;
+ s32 index = SHAREDREGION_INVALIDREGIONID;
+ s32 status = 0;
+
+ block = heapmemmp_alloc(cargs->args.alloc.handle,
+ cargs->args.alloc.size,
+ cargs->args.alloc.align);
+ if (block != NULL) {
+ index = sharedregion_get_id(block);
+ block_srptr = sharedregion_get_srptr(block, index);
+ }
+ /* The error on above fn will be a null ptr. We are not
+ checking that condition here. We are passing whatever
+ we are getting from the heapmem module. So IOCTL will succed,
+ but the actual fn might be failed inside heapmem
+ */
+ BUG_ON(index == SHAREDREGION_INVALIDREGIONID);
+ cargs->args.alloc.block_srptr = block_srptr;
+ BUG_ON(cargs->args.alloc.block_srptr == SHAREDREGION_INVALIDSRPTR);
+ cargs->api_status = 0;
+ return status;
+}
+
+/*
+ * ======== heapmemmp_ioctl_free ========
+ * Purpose:
+ * This ioctl interface to heapmemmp_free function
+ */
+static int heapmemmp_ioctl_free(struct heapmemmp_cmd_args *cargs)
+{
+ char *block;
+
+ block = sharedregion_get_ptr(cargs->args.free.block_srptr);
+ BUG_ON(block == NULL);
+ cargs->api_status = heapmemmp_free(cargs->args.free.handle, block,
+ cargs->args.free.size);
+ return 0;
+}
+
+/*
+ * ======== heapmemmp_ioctl_params_init ========
+ * Purpose:
+ * This ioctl interface to heapmemmp_params_init function
+ */
+static int heapmemmp_ioctl_params_init(struct heapmemmp_cmd_args *cargs)
+{
+ struct heapmemmp_params params;
+ s32 status = 0;
+ u32 size;
+
+ heapmemmp_params_init(&params);
+ cargs->api_status = 0;
+ size = copy_to_user((void __user *)cargs->args.params_init.params,
+ &params, sizeof(struct heapmemmp_params));
+ if (size)
+ status = -EFAULT;
+
+ return status;
+}
+
+/*
+ * ======== heapmemmp_ioctl_create ========
+ * Purpose:
+ * This ioctl interface to heapmemmp_create function
+ */
+static int heapmemmp_ioctl_create(struct heapmemmp_cmd_args *cargs)
+{
+ struct heapmemmp_params params;
+ s32 status = 0;
+ u32 size;
+ void *handle = NULL;
+
+ size = copy_from_user(&params, (void __user *)cargs->args.create.params,
+ sizeof(struct heapmemmp_params));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ if (cargs->args.create.name_len > 0) {
+ params.name = kmalloc(cargs->args.create.name_len, GFP_KERNEL);
+ if (params.name == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ params.name[cargs->args.create.name_len] = '\0';
+ size = copy_from_user(params.name,
+ (void __user *)cargs->args.create.params->name,
+ cargs->args.create.name_len);
+ if (size) {
+ status = -EFAULT;
+ goto name_from_usr_error;
+ }
+ }
+
+ params.shared_addr = sharedregion_get_ptr((u32 *)
+ cargs->args.create.shared_addr_srptr);
+ params.gate = cargs->args.create.knl_gate;
+ handle = heapmemmp_create(&params);
+ cargs->args.create.handle = handle;
+ cargs->api_status = 0;
+
+name_from_usr_error:
+ if (cargs->args.create.name_len > 0)
+ kfree(params.name);
+
+exit:
+ return status;
+}
+
+
+/*
+ * ======== heapmemmp_ioctl_delete ========
+ * Purpose:
+ * This ioctl interface to heapmemmp_delete function
+ */
+static int heapmemmp_ioctl_delete(struct heapmemmp_cmd_args *cargs)
+{
+ cargs->api_status = heapmemmp_delete(&cargs->args.delete.handle);
+ return 0;
+}
+
+/*
+ * ======== heapmemmp_ioctl_open ========
+ * Purpose:
+ * This ioctl interface to heapmemmp_open function
+ */
+static int heapmemmp_ioctl_open(struct heapmemmp_cmd_args *cargs)
+{
+ s32 status = 0;
+ u32 size = 0;
+ void *handle = NULL;
+ char *name = NULL;
+
+ if (cargs->args.open.name_len > 0) {
+ name = kmalloc(cargs->args.open.name_len, GFP_KERNEL);
+ if (name == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ size = copy_from_user(name,
+ (void __user *)cargs->args.open.name,
+ cargs->args.open.name_len);
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ }
+
+ cargs->api_status = heapmemmp_open(cargs->args.open.name, &handle);
+ cargs->args.open.handle = handle;
+
+ if (cargs->args.open.name_len > 0)
+ kfree(name);
+exit:
+ return status;
+}
+
+/*
+ * ======== heapmemmp_ioctl_open_by_addr ========
+ * Purpose:
+ * This ioctl interface to heapmemmp_open_by_addr function
+ */
+static int heapmemmp_ioctl_open_by_addr(struct heapmemmp_cmd_args *cargs)
+{
+ void *handle = NULL;
+
+ cargs->api_status = heapmemmp_open_by_addr((void *)
+ cargs->args.open_by_addr.shared_addr_srptr,
+ &handle);
+ cargs->args.open_by_addr.handle = handle;
+
+ return 0;
+}
+
+
+/*
+ * ======== heapmemmp_ioctl_close ========
+ * Purpose:
+ * This ioctl interface to heapmemmp_close function
+ */
+static int heapmemmp_ioctl_close(struct heapmemmp_cmd_args *cargs)
+{
+ cargs->api_status = heapmemmp_close(cargs->args.close.handle);
+ return 0;
+}
+
+/*
+ * ======== heapmemmp_ioctl_shared_mem_req ========
+ * Purpose:
+ * This ioctl interface to heapmemmp_shared_mem_req function
+ */
+static int heapmemmp_ioctl_shared_mem_req(struct heapmemmp_cmd_args *cargs)
+{
+ struct heapmemmp_params params;
+ s32 status = 0;
+ ulong size;
+ u32 bytes;
+
+ size = copy_from_user(&params,
+ (void __user *)cargs->args.shared_mem_req.params,
+ sizeof(struct heapmemmp_params));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ if (params.shared_addr != NULL) {
+ params.shared_addr = sharedregion_get_ptr(
+ cargs->args.shared_mem_req.shared_addr_srptr);
+ }
+ bytes = heapmemmp_shared_mem_req(&params);
+ cargs->args.shared_mem_req.bytes = bytes;
+ cargs->api_status = 0;
+
+exit:
+ return status;
+}
+
+
+/*
+ * ======== heapmemmp_ioctl_get_config ========
+ * Purpose:
+ * This ioctl interface to heapmemmp_get_config function
+ */
+static int heapmemmp_ioctl_get_config(struct heapmemmp_cmd_args *cargs)
+{
+ struct heapmemmp_config config;
+ s32 status = 0;
+ ulong size;
+
+ cargs->api_status = heapmemmp_get_config(&config);
+ size = copy_to_user((void __user *)cargs->args.get_config.config,
+ &config, sizeof(struct heapmemmp_config));
+ if (size)
+ status = -EFAULT;
+
+ return status;
+}
+
+/*
+ * ======== heapmemmp_ioctl_setup ========
+ * Purpose:
+ * This ioctl interface to heapmemmp_setup function
+ */
+static int heapmemmp_ioctl_setup(struct heapmemmp_cmd_args *cargs)
+{
+ struct heapmemmp_config config;
+ s32 status = 0;
+ ulong size;
+
+ size = copy_from_user(&config, (void __user *)cargs->args.setup.config,
+ sizeof(struct heapmemmp_config));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ cargs->api_status = heapmemmp_setup(&config);
+
+exit:
+ return status;
+}
+/*
+ * ======== heapmemmp_ioctl_destroy ========
+ * Purpose:
+ * This ioctl interface to heapmemmp_destroy function
+ */
+static int heapmemmp_ioctl_destroy(struct heapmemmp_cmd_args *cargs)
+{
+ cargs->api_status = heapmemmp_destroy();
+ return 0;
+}
+
+
+/*
+ * ======== heapmemmp_ioctl_get_stats ========
+ * Purpose:
+ * This ioctl interface to heapmemmp_get_stats function
+ */
+static int heapmemmp_ioctl_get_stats(struct heapmemmp_cmd_args *cargs)
+{
+ struct memory_stats stats;
+ s32 status = 0;
+ ulong size;
+
+ heapmemmp_get_stats(cargs->args.get_stats.handle, &stats);
+ cargs->api_status = 0;
+
+ size = copy_to_user((void __user *)cargs->args.get_stats.stats, &stats,
+ sizeof(struct memory_stats));
+ if (size)
+ status = -EFAULT;
+
+ return status;
+}
+
+/*
+ * ======== heapmemmp_ioctl_get_extended_stats ========
+ * Purpose:
+ * This ioctl interface to heapmemmp_get_extended_stats function
+ */
+static int heapmemmp_ioctl_get_extended_stats(struct heapmemmp_cmd_args *cargs)
+{
+ struct heapmemmp_extended_stats stats;
+ s32 status = 0;
+ ulong size;
+
+ heapmemmp_get_extended_stats(cargs->args.get_extended_stats.handle,
+ &stats);
+ cargs->api_status = 0;
+
+ size = copy_to_user((void __user *)cargs->args.get_extended_stats.stats,
+ &stats,
+ sizeof(struct heapmemmp_extended_stats));
+ if (size)
+ status = -EFAULT;
+
+ return status;
+}
+
+/*
+ * ======== heapmemmp_ioctl_restore ========
+ * Purpose:
+ * This ioctl interface to heapmemmp_get_extended_stats function
+ */
+static int heapmemmp_ioctl_restore(struct heapmemmp_cmd_args *cargs)
+{
+ heapmemmp_restore(cargs->args.restore.handle);
+ cargs->api_status = 0;
+ return 0;
+}
+
+/*
+ * ======== heapmemmp_ioctl ========
+ * Purpose:
+ * This ioctl interface for heapmem module
+ */
+int heapmemmp_ioctl(struct inode *pinode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user)
+{
+ s32 status = 0;
+ s32 size = 0;
+ struct heapmemmp_cmd_args __user *uarg =
+ (struct heapmemmp_cmd_args __user *)args;
+ struct heapmemmp_cmd_args cargs;
+ struct ipc_process_context *pr_ctxt =
+ (struct ipc_process_context *)filp->private_data;
+
+ if (user == true) {
+#ifdef CONFIG_SYSLINK_RECOVERY
+ if (ipc_recovering()) {
+ status = -EIO;
+ goto exit;
+ }
+#endif
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ status = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ status = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
+
+ if (status) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ /* Copy the full args from user-side */
+ size = copy_from_user(&cargs, uarg,
+ sizeof(struct heapmemmp_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ } else {
+ if (args != 0)
+ memcpy(&cargs, (void *)args,
+ sizeof(struct heapmemmp_cmd_args));
+ }
+
+ switch (cmd) {
+ case CMD_HEAPMEMMP_ALLOC:
+ status = heapmemmp_ioctl_alloc(&cargs);
+ break;
+
+ case CMD_HEAPMEMMP_FREE:
+ status = heapmemmp_ioctl_free(&cargs);
+ break;
+
+ case CMD_HEAPMEMMP_PARAMS_INIT:
+ status = heapmemmp_ioctl_params_init(&cargs);
+ break;
+
+ case CMD_HEAPMEMMP_CREATE:
+ status = heapmemmp_ioctl_create(&cargs);
+ if (status >= 0) {
+ struct heapmemmp_cmd_args *temp = kmalloc(
+ sizeof(struct heapmemmp_cmd_args),
+ GFP_KERNEL);
+ if (WARN_ON(!temp)) {
+ status = -ENOMEM;
+ goto exit;
+ }
+ temp->args.delete.handle = cargs.args.create.handle;
+ add_pr_res(pr_ctxt, CMD_HEAPMEMMP_DELETE, (void *)temp);
+ }
+ break;
+
+ case CMD_HEAPMEMMP_DELETE:
+ {
+ struct resource_info *info = NULL;
+ info = find_heapmemmp_resource(pr_ctxt,
+ CMD_HEAPMEMMP_DELETE,
+ &cargs);
+ status = heapmemmp_ioctl_delete(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_HEAPMEMMP_OPEN:
+ status = heapmemmp_ioctl_open(&cargs);
+ break;
+
+ case CMD_HEAPMEMMP_OPENBYADDR:
+ status = heapmemmp_ioctl_open_by_addr(&cargs);
+ break;
+
+ case CMD_HEAPMEMMP_CLOSE:
+ status = heapmemmp_ioctl_close(&cargs);
+ break;
+
+ case CMD_HEAPMEMMP_SHAREDMEMREQ:
+ status = heapmemmp_ioctl_shared_mem_req(&cargs);
+ break;
+
+ case CMD_HEAPMEMMP_GETCONFIG:
+ status = heapmemmp_ioctl_get_config(&cargs);
+ break;
+
+ case CMD_HEAPMEMMP_SETUP:
+ status = heapmemmp_ioctl_setup(&cargs);
+ if (status >= 0)
+ add_pr_res(pr_ctxt, CMD_HEAPMEMMP_DESTROY, NULL);
+ break;
+
+ case CMD_HEAPMEMMP_DESTROY:
+ {
+ struct resource_info *info = NULL;
+ info = find_heapmemmp_resource(pr_ctxt,
+ CMD_HEAPMEMMP_DESTROY,
+ &cargs);
+ status = heapmemmp_ioctl_destroy(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_HEAPMEMMP_GETSTATS:
+ status = heapmemmp_ioctl_get_stats(&cargs);
+ break;
+
+ case CMD_HEAPMEMMP_GETEXTENDEDSTATS:
+ status = heapmemmp_ioctl_get_extended_stats(&cargs);
+ break;
+
+ case CMD_HEAPMEMMP_RESTORE:
+ status = heapmemmp_ioctl_restore(&cargs);
+ break;
+
+ default:
+ WARN_ON(cmd);
+ status = -ENOTTY;
+ break;
+ }
+
+ if (user == true) {
+ /* Copy the full args to the user-side. */
+ size = copy_to_user(uarg, &cargs,
+ sizeof(struct heapmemmp_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ }
+
+exit:
+ return status;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/ipc.c b/drivers/dsp/syslink/multicore_ipc/ipc.c
new file mode 100644
index 00000000000..323006f0a72
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/ipc.c
@@ -0,0 +1,1513 @@
+/*
+ * ipc.c
+ *
+ * This module is primarily used to configure IPC-wide settings and
+ * initialize IPC at runtime
+ *
+ * Copyright (C) 2009 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.
+ */
+
+
+/* Standard headers */
+#include <linux/types.h>
+#include <linux/module.h>
+
+#include <syslink/atomic_linux.h>
+
+/* Module headers */
+#include <multiproc.h>
+#include <ipc.h>
+#include <platform.h>
+
+#include <gatemp.h>
+#include <sharedregion.h>
+#include <notify.h>
+#include <notify_ducatidriver.h>
+#include <notify_setup_proxy.h>
+
+#include <heap.h>
+#include <heapbufmp.h>
+#include <heapmemmp.h>
+
+#include <messageq.h>
+#include <nameserver.h>
+#include <nameserver_remotenotify.h>
+
+/* Ipu Power Management Header (ipu_pm) */
+#include "../ipu_pm/ipu_pm.h"
+/* =============================================================================
+ * Macros
+ * =============================================================================
+ */
+/* Macro to make a correct module magic number with ref_count */
+#define IPC_MAKE_MAGICSTAMP(x)((IPC_MODULEID << 16u) | (x))
+
+/* flag for starting processor synchronization */
+#define IPC_PROCSYNCSTART 1
+
+/* flag for finishing processor synchronization */
+#define IPC_PROCSYNCFINISH 2
+
+#define ROUND_UP(a, b) (((a) + ((b) - 1)) & (~((b) - 1)))
+
+/* =============================================================================
+ * Enums & Structures
+ * =============================================================================
+ */
+
+/* The structure used for reserving memory in SharedRegion */
+struct ipc_reserved {
+ VOLATILE u32 started_key;
+ u32 *notify_sr_ptr;
+ u32 *nsrn_sr_ptr;
+ u32 *transport_sr_ptr;
+ u32 *config_list_head;
+};
+
+
+/* head of the config list */
+struct ipc_config_head {
+ VOLATILE u32 first;
+ /* Address of first config entry */
+};
+
+
+/*
+ * This structure captures Configuration details of a module/instance
+ * written by a slave to synchornize with a remote slave/HOST
+ */
+struct ipc_config_entry {
+ VOLATILE u32 remote_proc_id;
+ /* Remote processor identifier */
+ VOLATILE u32 local_proc_id;
+ /* Config Entry owner processor identifier */
+ VOLATILE u32 tag;
+ /* Unique tag to distinguish config from other config entries */
+ VOLATILE u32 size;
+ /* Size of the config pointer */
+ VOLATILE u32 next;
+ /* Address of next config entry (In SRPtr format) */
+};
+
+/*
+ * This structure defines the fields that are to be configured
+ * between the executing processor and a remote processor.
+ */
+struct ipc_entry {
+ u16 remote_proc_id; /* the remote processor id */
+ bool setup_notify; /* whether to setup Notify */
+ bool setup_messageq; /* whether to setup messageq */
+ bool setup_ipu_pm; /* whether to setup ipu_pm */
+};
+
+/* Ipc instance structure. */
+struct ipc_proc_entry {
+ void *local_config_list;
+ void *remote_config_list;
+ void *user_obj;
+ bool slave;
+ struct ipc_entry entry;
+ bool is_attached;
+};
+
+
+/* Module state structure */
+struct ipc_module_state {
+ s32 ref_count;
+ atomic_t start_ref_count;
+ void *ipc_shared_addr;
+ void *gatemp_shared_addr;
+ void *ipu_pm_shared_addr;
+ enum ipc_proc_sync proc_sync;
+ struct ipc_config cfg;
+ struct ipc_proc_entry proc_entry[MULTIPROC_MAXPROCESSORS];
+};
+
+
+/* =============================================================================
+ * Forward declaration
+ * =============================================================================
+ */
+/*
+ * ======== ipc_get_master_addr() ========
+ */
+static void *ipc_get_master_addr(u16 remote_proc_id, void *shared_addr);
+
+/*
+ * ======== ipc_get_region0_reserved_size ========
+ * Returns the amount of memory to be reserved for Ipc in SharedRegion 0.
+ *
+ * This is used for synchronizing processors.
+ */
+static u32 ipc_get_region0_reserved_size(void);
+
+/*
+ * ======== ipc_get_slave_addr() ========
+ */
+static void *ipc_get_slave_addr(u16 remote_proc_id, void *shared_addr);
+
+/*
+ * ======== ipc_proc_sync_start ========
+ * Starts the process of synchronizing processors.
+ *
+ * Shared memory in region 0 will be used. The processor which owns
+ * SharedRegion 0 writes its reserve memory address in region 0
+ * to let the other processors know it has started. It then spins
+ * until the other processors start. The other processors write their
+ * reserve memory address in region 0 to let the owner processor
+ * know they've started. The other processors then spin until the
+ * owner processor writes to let them know its finished the process
+ * of synchronization before continuing.
+ */
+static int ipc_proc_sync_start(u16 remote_proc_id, void *shared_addr);
+
+/*
+ * ======== ipc_proc_sync_finish ========
+ * Finishes the process of synchronizing processors.
+ *
+ * Each processor writes its reserve memory address in SharedRegion 0
+ * to let the other processors know its finished the process of
+ * synchronization.
+ */
+static int ipc_proc_sync_finish(u16 remote_proc_id, void *shared_addr);
+
+/*
+ * ======== ipc_reserved_size_per_proc ========
+ * The amount of memory required to be reserved per processor.
+ */
+static u32 ipc_reserved_size_per_proc(void);
+
+/* TODO: figure these out */
+#define gate_enter_system() 0
+#define gate_leave_system(key) {}
+
+/* =============================================================================
+ * Globals
+ * =============================================================================
+ */
+static struct ipc_module_state ipc_module_state = {
+ .proc_sync = IPC_PROCSYNC_ALL,
+ .ref_count = 0,
+};
+static struct ipc_module_state *ipc_module = &ipc_module_state;
+
+/* =============================================================================
+ * APIs
+ * =============================================================================
+ */
+/*
+ * ========== ipc_attach ==========
+ * attaches to a remote processor
+ */
+int ipc_attach(u16 remote_proc_id)
+{
+ int status = 0;
+#if 0
+ u32 reserved_size = ipc_reserved_size_per_proc();
+ bool cache_enabled = sharedregion_is_cache_enabled(0);
+#endif
+ void *notify_shared_addr;
+ void *msgq_shared_addr;
+ void *nsrn_shared_addr;
+ u32 notify_mem_req;
+ VOLATILE struct ipc_reserved *slave;
+ struct ipc_proc_entry *ipc;
+
+ if (remote_proc_id >= MULTIPROC_MAXPROCESSORS) {
+ pr_err("Invalid remote_proc_id passed\n");
+ return IPC_E_FAIL;
+ }
+
+ /* determine if self is master or slave */
+ if (multiproc_self() < remote_proc_id)
+ ipc_module->proc_entry[remote_proc_id].slave = true;
+ else
+ ipc_module->proc_entry[remote_proc_id].slave = false;
+
+ /* determine the slave's slot */
+ slave = ipc_get_slave_addr(remote_proc_id, ipc_module->ipc_shared_addr);
+#if 0
+ if (cache_enabled)
+ Cache_inv((void *)slave, reserved_size, Cache_Type_ALL, true);
+#endif
+ /* get the attach paramters associated with remote_proc_id */
+ ipc = &(ipc_module->proc_entry[remote_proc_id]);
+
+ /* Synchronize the processors. */
+ status = ipc_proc_sync_start(remote_proc_id, ipc_module->
+ ipc_shared_addr);
+
+ if (status < 0)
+ pr_err("ipc_attach : ipc_proc_sync_start "
+ "failed [0x%x]\n", status);
+ else
+ pr_err("ipc_proc_sync_start : status [0x%x]\n", status);
+
+
+ if (status >= 0) {
+ /* must be called before SharedRegion_attach */
+ status = gatemp_attach(remote_proc_id, ipc_module->
+ gatemp_shared_addr);
+ if (status < 0)
+ pr_err("ipc_attach : gatemp_attach "
+ "failed [0x%x]\n", status);
+ else
+ pr_err("gatemp_attach : status [0x%x]\n", status);
+
+ }
+
+ /* retrieves the SharedRegion Heap handles */
+ if (status >= 0) {
+ status = sharedregion_attach(remote_proc_id);
+ if (status < 0)
+ pr_err("ipc_attach : sharedregion_attach "
+ "failed [0x%x]\n", status);
+ else
+ pr_err("sharedregion_attach : status "
+ "[0x%x]\n", status);
+ }
+
+ /* attach Notify if not yet attached and specified to set internal
+ setup */
+ if (status >= 0 && !notify_is_registered(remote_proc_id, 0) &&
+ (ipc->entry.setup_notify)) {
+ /* call notify_attach */
+ if (ipc_module->proc_entry[remote_proc_id].slave) {
+ notify_mem_req = notify_shared_mem_req(remote_proc_id,
+ ipc_module->ipc_shared_addr);
+ notify_shared_addr = sl_heap_alloc(
+ sharedregion_get_heap(0),
+ notify_mem_req,
+ sharedregion_get_cache_line_size(0));
+ memset(notify_shared_addr, 0, notify_mem_req);
+ slave->notify_sr_ptr = sharedregion_get_srptr(
+ notify_shared_addr, 0);
+ if (slave->notify_sr_ptr ==
+ SHAREDREGION_INVALIDSRPTR) {
+ status = IPC_E_FAIL;
+ pr_err("ipc_attach : "
+ "sharedregion_get_srptr "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err(
+ "sharedregion_get_srptr : "
+ "status [0x%x]\n", status);
+ }
+ } else {
+ notify_shared_addr = sharedregion_get_ptr(slave->
+ notify_sr_ptr);
+ if (notify_shared_addr == NULL) {
+ status = IPC_E_FAIL;
+ pr_err("ipc_attach : "
+ "sharedregion_get_ptr "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err(
+ "sharedregion_get_ptr : "
+ "status [0x%x]\n", status);
+ }
+ }
+
+ if (status >= 0) {
+ status = notify_attach(remote_proc_id,
+ notify_shared_addr);
+ if (status < 0)
+ pr_err("ipc_attach : "
+ "notify_attach "
+ "failed [0x%x]\n", status);
+ else
+ pr_err(
+ "notify_attach : "
+ "status [0x%x]\n", status);
+ }
+ }
+
+ /* Must come before Notify because depends on default Notify */
+ if (status >= 0 && ipc->entry.setup_notify && ipc->entry.setup_ipu_pm) {
+ if (status >= 0) {
+ status = ipu_pm_attach(remote_proc_id, ipc_module->
+ ipu_pm_shared_addr);
+ if (status < 0)
+ pr_err("ipc_attach : "
+ "ipu_pm_attach "
+ "failed [0x%x]\n", status);
+ else
+ pr_err(
+ "ipu_pm_attach : "
+ "status [0x%x]\n", status);
+ }
+ }
+
+ /* Must come after gatemp_start because depends on default GateMP */
+ if (status >= 0 && ipc->entry.setup_notify) {
+ if (ipc_module->proc_entry[remote_proc_id].slave) {
+ nsrn_shared_addr = sl_heap_alloc(
+ sharedregion_get_heap(0),
+ nameserver_remotenotify_shared_mem_req(
+ NULL),
+ sharedregion_get_cache_line_size(0));
+
+ slave->nsrn_sr_ptr =
+ sharedregion_get_srptr(nsrn_shared_addr, 0);
+ if (slave->nsrn_sr_ptr == SHAREDREGION_INVALIDSRPTR) {
+ status = IPC_E_FAIL;
+ pr_err("ipc_attach : "
+ "sharedregion_get_srptr "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err(
+ "sharedregion_get_srptr : "
+ "status [0x%x]\n", status);
+ }
+ } else {
+ nsrn_shared_addr =
+ sharedregion_get_ptr(slave->nsrn_sr_ptr);
+ if (nsrn_shared_addr == NULL) {
+ status = IPC_E_FAIL;
+ pr_err("ipc_attach : "
+ "sharedregion_get_ptr "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err(
+ "sharedregion_get_ptr : "
+ "status [0x%x]\n", status);
+ }
+ }
+
+ if (status >= 0) {
+ /* create the nameserver_remotenotify instances */
+ status = nameserver_remotenotify_attach(remote_proc_id,
+ nsrn_shared_addr);
+
+ if (status < 0)
+ pr_err("ipc_attach : "
+ "nameserver_remotenotify_attach "
+ "failed [0x%x]\n", status);
+ else
+ pr_err(
+ "nameserver_remotenotify_attach : "
+ "status [0x%x]\n", status);
+ }
+ }
+
+ /* Must come after gatemp_start because depends on default GateMP */
+ if (status >= 0 && ipc->entry.setup_messageq) {
+ if (ipc_module->proc_entry[remote_proc_id].slave) {
+ msgq_shared_addr = sl_heap_alloc
+ (sharedregion_get_heap(0),
+ messageq_shared_mem_req(ipc_module->
+ ipc_shared_addr),
+ sharedregion_get_cache_line_size(0));
+
+ slave->transport_sr_ptr =
+ sharedregion_get_srptr(msgq_shared_addr, 0);
+ if (slave->transport_sr_ptr ==
+ SHAREDREGION_INVALIDSRPTR) {
+ status = IPC_E_FAIL;
+ pr_err("ipc_attach : "
+ "sharedregion_get_srptr "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err(
+ "sharedregion_get_srptr : "
+ "status [0x%x]\n", status);
+ }
+ } else {
+ msgq_shared_addr = sharedregion_get_ptr(slave->
+ transport_sr_ptr);
+ if (msgq_shared_addr == NULL) {
+ status = IPC_E_FAIL;
+ pr_err("ipc_attach : "
+ "sharedregion_get_ptr "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err(
+ "sharedregion_get_ptr : "
+ "status [0x%x]\n", status);
+ }
+ }
+
+ if (status >= 0) {
+ /* create the messageq Transport instances */
+ status = messageq_attach(remote_proc_id,
+ msgq_shared_addr);
+ if (status < 0)
+ pr_err("ipc_attach : "
+ "messageq_attach "
+ "failed [0x%x]\n", status);
+ else
+ pr_err(
+ "messageq_attach : "
+ "status [0x%x]\n", status);
+ }
+ }
+#if 0
+ if (cache_enabled) {
+ if (ipc_module->proc_entry[remote_proc_id].slave)
+ Cache_wbInv((void *)slave, reserved_size,
+ Cache_Type_ALL, true);
+ }
+#endif
+
+ if (status >= 0) {
+ /* Finish the processor synchronization */
+ status = ipc_proc_sync_finish(remote_proc_id,
+ ipc_module->ipc_shared_addr);
+ if (status < 0)
+ pr_err("ipc_attach : "
+ "ipc_proc_sync_finish "
+ "failed [0x%x]\n", status);
+ else
+ pr_err(
+ "ipc_proc_sync_finish : "
+ "status [0x%x]\n", status);
+ }
+
+ if (status >= 0)
+ ipc->is_attached = true;
+ else
+ pr_err("ipc_attach failed! status = 0x%x\n", status);
+
+ return status;
+}
+
+
+/*
+ * ============= ipc_detach ==============
+ * detaches from a remote processor
+ */
+int ipc_detach(u16 remote_proc_id)
+{
+ int status = 0;
+#if 0
+ u32 reserved_size = ipc_reserved_size_per_proc();
+#endif
+ bool cache_enabled = sharedregion_is_cache_enabled(0);
+ void *notify_shared_addr;
+ void *nsrn_shared_addr;
+ void *msgq_shared_addr;
+ VOLATILE struct ipc_reserved *slave;
+ VOLATILE struct ipc_reserved *master;
+ struct ipc_proc_entry *ipc;
+ u32 nsrn_mem_req = nameserver_remotenotify_shared_mem_req(NULL);
+ /* prefetching into local variable because of
+ later space restrictions */
+
+ /* get the paramters associated with remote_proc_id */
+ ipc = &(ipc_module->proc_entry[remote_proc_id]);
+
+ if (ipc->is_attached == false) {
+ status = IPC_E_INVALIDSTATE;
+ goto exit;
+ }
+
+ /* determine the slave's slot */
+ slave = ipc_get_slave_addr(remote_proc_id, ipc_module->
+ ipc_shared_addr);
+
+ if (slave != NULL) {
+#if 0
+ if (unlikely(cache_enabled))
+ Cache_inv((void *) slave, reserved_size,
+ Cache_Type_ALL, true);
+#endif
+ if (ipc->entry.setup_messageq) {
+ /* call messageq_detach for remote processor */
+ status = messageq_detach(remote_proc_id);
+ if (status < 0)
+ pr_err("ipc_detach : "
+ "messageq_detach "
+ "failed [0x%x]\n", status);
+ else
+ pr_err(
+ "messageq_detach : "
+ "status [0x%x]\n", status);
+
+ /* free the memory if slave processor */
+ if (ipc_module->proc_entry[remote_proc_id].slave) {
+ /* get the pointer to messageq transport
+ instance */
+ msgq_shared_addr = sharedregion_get_ptr(
+ slave->transport_sr_ptr);
+
+ if (msgq_shared_addr != NULL) {
+ /* free the memory back to sharedregion
+ 0 heap */
+ sl_heap_free(sharedregion_get_heap(0),
+ msgq_shared_addr,
+ messageq_shared_mem_req(
+ msgq_shared_addr));
+ }
+
+ /* set the pointer for messageq transport
+ instance back to invalid */
+ slave->transport_sr_ptr =
+ SHAREDREGION_INVALIDSRPTR;
+ }
+ }
+
+ if (ipc->entry.setup_notify) {
+ /* call nameserver_remotenotify_detach for
+ remote processor */
+ status = nameserver_remotenotify_detach(
+ remote_proc_id);
+ if (status < 0)
+ pr_err("ipc_detach : "
+ "nameserver_remotenotify_detach "
+ "failed [0x%x]\n", status);
+ else
+ pr_err(
+ "nameserver_remotenotify_detach : "
+ "status [0x%x]\n", status);
+
+ /* free the memory if slave processor */
+ if (ipc_module->proc_entry[remote_proc_id].slave) {
+ /* get the pointer to NSRN instance */
+ nsrn_shared_addr = sharedregion_get_ptr(
+ slave->nsrn_sr_ptr);
+
+ if (nsrn_shared_addr != NULL)
+ /* free the memory back to
+ SharedRegion 0 heap */
+ sl_heap_free(sharedregion_get_heap(0),
+ nsrn_shared_addr,
+ nsrn_mem_req);
+
+ /* set the pointer for NSRN instance back
+ to invalid */
+ slave->nsrn_sr_ptr =
+ SHAREDREGION_INVALIDSRPTR;
+ }
+ }
+
+ if (ipc->entry.setup_notify && ipc->entry.setup_ipu_pm) {
+ /* call ipu_pm_detach for remote processor */
+ status = ipu_pm_detach(remote_proc_id);
+ if (status < 0)
+ pr_err("ipc_detach : "
+ "ipu_pm_detach "
+ "failed [0x%x]\n", status);
+ else
+ pr_err(
+ "ipu_pm_detach : "
+ "status [0x%x]\n", status);
+ }
+
+ if (ipc->entry.setup_notify) {
+ /* call notify_detach for remote processor */
+ status = notify_detach(remote_proc_id);
+ if (status < 0)
+ pr_err("ipc_detach : "
+ "notify_detach "
+ "failed [0x%x]\n", status);
+ else
+ pr_err(
+ "notify_detach : "
+ "status [0x%x]\n", status);
+
+ /* free the memory if slave processor */
+ if (ipc_module->proc_entry[remote_proc_id].slave) {
+ /* get the pointer to Notify instance */
+ notify_shared_addr = sharedregion_get_ptr(
+ slave->notify_sr_ptr);
+
+ if (notify_shared_addr != NULL) {
+ /* free the memory back to
+ SharedRegion 0 heap */
+ sl_heap_free(sharedregion_get_heap(0),
+ notify_shared_addr,
+ notify_shared_mem_req(
+ remote_proc_id,
+ notify_shared_addr));
+ }
+
+ /* set the pointer for Notify instance
+ back to invalid */
+ slave->notify_sr_ptr =
+ SHAREDREGION_INVALIDSRPTR;
+ }
+ }
+
+ if (unlikely(cache_enabled)) {
+ if (ipc_module->proc_entry[remote_proc_id].slave) {
+ slave->started_key = 0;
+ slave->config_list_head =
+ SHAREDREGION_INVALIDSRPTR;
+#if 0
+ Cache_wbInv((void *)slave, reserved_size,
+ Cache_Type_ALL, true);
+#endif
+ } else {
+ /* determine the master's slot */
+ master = ipc_get_master_addr(remote_proc_id,
+ ipc_module->ipc_shared_addr);
+
+ if (master != NULL) {
+ master->started_key = 0;
+ master->config_list_head =
+ SHAREDREGION_INVALIDSRPTR;
+#if 0
+ Cache_wbInv((void *) master,
+ reserved_size,
+ Cache_Type_ALL,
+ true);
+#endif
+ }
+ }
+ }
+
+ /* Now detach the SharedRegion */
+ status = sharedregion_detach(remote_proc_id);
+ BUG_ON(status < 0);
+
+ /* Now detach the GateMP */
+ status = gatemp_detach(remote_proc_id, ipc_module->
+ gatemp_shared_addr);
+ BUG_ON(status < 0);
+ }
+ ipc->is_attached = false;
+
+exit:
+ if (status < 0)
+ pr_err("ipc_detach failed with status [0x%x]\n", status);
+ return status;
+}
+
+
+/*
+ * ========= ipc_control ==========
+ * Function to destroy an ipc instance for a slave
+ */
+int
+ipc_control(u16 proc_id, u32 cmd_id, void *arg)
+{
+ int status = IPC_S_SUCCESS;
+
+ switch (cmd_id) {
+ case IPC_CONTROLCMD_LOADCALLBACK:
+ {
+#if defined CONFIG_SYSLINK_USE_SYSMGR
+ status = platform_load_callback(proc_id, arg);
+ if (status < 0)
+ pr_err("ipc_control : platform_load_callback "
+ "failed [0x%x]\n", status);
+#endif
+ }
+ break;
+
+ case IPC_CONTROLCMD_STARTCALLBACK:
+ {
+#if defined CONFIG_SYSLINK_USE_SYSMGR
+ status = platform_start_callback(proc_id, arg);
+ if (status < 0)
+ pr_err("ipc_control : platform_start_callback"
+ " failed [0x%x]\n", status);
+#endif
+ }
+ break;
+
+ case IPC_CONTROLCMD_STOPCALLBACK:
+ {
+#if defined CONFIG_SYSLINK_USE_SYSMGR
+ status = platform_stop_callback(proc_id, arg);
+ if (status < 0)
+ pr_err("ipc_control : platform_stop_callback"
+ " failed [0x%x]\n", status);
+#endif
+ }
+ break;
+
+ default:
+ {
+ status = -EINVAL;
+ pr_err("ipc_control : invalid "
+ " command code [0x%x]\n", cmd_id);
+ }
+ break;
+ }
+
+ return status;
+}
+
+
+/*
+ * ======== ipc_get_master_addr ========
+ */
+static void *ipc_get_master_addr(u16 remote_proc_id, void *shared_addr)
+{
+ u32 reserved_size = ipc_reserved_size_per_proc();
+ int slot;
+ u16 master_id;
+ VOLATILE struct ipc_reserved *master;
+
+ /* determine the master's proc_id and slot */
+ if (multiproc_self() < remote_proc_id) {
+ master_id = remote_proc_id;
+ slot = multiproc_self();
+ } else {
+ master_id = multiproc_self();
+ slot = remote_proc_id;
+ }
+
+ /* determine the reserve address for master between self and remote */
+ master = (struct ipc_reserved *)((u32)shared_addr +
+ ((master_id * reserved_size) +
+ (slot * sizeof(struct ipc_reserved))));
+
+ return (void *)master;
+}
+
+/*
+ * ======== ipc_get_region0_reserved_size ========
+ */
+static u32 ipc_get_region0_reserved_size(void)
+{
+ u32 reserved_size = ipc_reserved_size_per_proc();
+
+ /* Calculate the total amount to reserve */
+ reserved_size = reserved_size * multiproc_get_num_processors();
+
+ return reserved_size;
+}
+
+/*
+ * ======== Ipc_getSlaveAddr ========
+ */
+static void *ipc_get_slave_addr(u16 remote_proc_id, void *shared_addr)
+{
+ u32 reserved_size = ipc_reserved_size_per_proc();
+ int slot;
+ u16 slave_id;
+ VOLATILE struct ipc_reserved *slave;
+
+ /* determine the slave's proc_id and slot */
+ if (multiproc_self() < remote_proc_id) {
+ slave_id = multiproc_self();
+ slot = remote_proc_id - 1;
+ } else {
+ slave_id = remote_proc_id;
+ slot = multiproc_self() - 1;
+ }
+
+ /* determine the reserve address for slave between self and remote */
+ slave = (struct ipc_reserved *)((u32)shared_addr +
+ ((slave_id * reserved_size) +
+ (slot * sizeof(struct ipc_reserved))));
+
+ return (void *)slave;
+}
+
+/*
+ * ======== Ipc_proc_syncStart ========
+ * The owner of SharedRegion 0 writes to its reserve memory address
+ * in region 0 to let the other processors know it has started.
+ * It then spins until the other processors start.
+ * The other processors write their reserve memory address in
+ * region 0 to let the owner processor know they've started.
+ * The other processors then spin until the owner processor writes
+ * to let them know that its finished the process of synchronization
+ * before continuing.
+ */
+static int ipc_proc_sync_start(u16 remote_proc_id, void *shared_addr)
+{
+#if 0
+ u32 reserved_size = ipc_reserved_size_per_proc();
+ bool cache_enabled = sharedregion_is_cache_enabled(0);
+#endif
+ int status = 0;
+ VOLATILE struct ipc_reserved *self;
+ VOLATILE struct ipc_reserved *remote;
+ struct ipc_proc_entry *ipc;
+
+ /* don't do any synchronization if proc_sync is NONE */
+ if (ipc_module->proc_sync != IPC_PROCSYNC_NONE) {
+ /* determine self and remote pointers */
+ if (ipc_module->proc_entry[remote_proc_id].slave) {
+ self = ipc_get_slave_addr(remote_proc_id, shared_addr);
+ remote = ipc_get_master_addr(remote_proc_id,
+ shared_addr);
+ } else {
+ self = ipc_get_master_addr(remote_proc_id, shared_addr);
+ remote = ipc_get_slave_addr(remote_proc_id,
+ shared_addr);
+ }
+
+ /* construct the config list */
+ ipc = &(ipc_module->proc_entry[remote_proc_id]);
+
+ ipc->local_config_list = (void *)&self->config_list_head;
+ ipc->remote_config_list = (void *)&remote->config_list_head;
+
+ ((struct ipc_config_head *)ipc->local_config_list)->first =
+ (u32)SHAREDREGION_INVALIDSRPTR;
+#if 0
+ if (cache_enabled) {
+ Cache_wbInv(ipc->local_config_list,
+ reserved_size,
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+
+ if (ipc_module->proc_entry[remote_proc_id].slave) {
+ /* set my processor's reserved key to start */
+ self->started_key = IPC_PROCSYNCSTART;
+#if 0
+ /* write back my processor's reserve key */
+ if (cache_enabled)
+ Cache_wbInv((void *)self, reserved_size,
+ Cache_Type_ALL, true);
+
+ /* wait for remote processor to start */
+ if (cache_enabled)
+ Cache_inv((void *)remote, reserved_size,
+ Cache_Type_ALL, true);
+#endif
+ if (remote->started_key != IPC_PROCSYNCSTART)
+ status = IPC_E_FAIL;
+ goto exit;
+ }
+
+#if 0
+ /* wait for remote processor to start */
+ Cache_inv((void *)remote, reserved_size, Cache_Type_ALL, true);
+#endif
+ if ((self->started_key != IPC_PROCSYNCSTART) &&
+ (remote->started_key != IPC_PROCSYNCSTART)) {
+ status = IPC_E_FAIL;
+ goto exit;
+ }
+
+ if (status >= 0) {
+ /* set my processor's reserved key to start */
+ self->started_key = IPC_PROCSYNCSTART;
+#if 0
+ /* write my processor's reserve key back */
+ if (cache_enabled)
+ Cache_wbInv((void *)self, reserved_size,
+ Cache_Type_ALL, true);
+
+ /* wait for remote processor to finish */
+ Cache_inv((void *)remote, reserved_size,
+ Cache_Type_ALL, true);
+#endif
+ if (remote->started_key != IPC_PROCSYNCFINISH) {
+ status = IPC_E_FAIL;
+ goto exit;
+ }
+ }
+ }
+exit:
+ if (status < 0)
+ pr_err("ipc_proc_sync_start failed: status [0x%x]\n", status);
+ else
+ pr_err("ipc_proc_sync_start done\n");
+
+ return status;
+}
+
+/*
+ * ======== Ipc_proc_syncFinish ========
+ * Each processor writes its reserve memory address in SharedRegion 0
+ * to let the other processors know its finished the process of
+ * synchronization.
+ */
+static int ipc_proc_sync_finish(u16 remote_proc_id, void *shared_addr)
+{
+#if 0
+ u32 reserved_size = ipc_reserved_size_per_proc();
+ bool cache_enabled = sharedregion_is_cache_enabled(0);
+#endif
+ VOLATILE struct ipc_reserved *self;
+ VOLATILE struct ipc_reserved *remote;
+
+ /* don't do any synchronization if proc_sync is NONE */
+ if (ipc_module->proc_sync != IPC_PROCSYNC_NONE) {
+ /* determine self pointer */
+ if (ipc_module->proc_entry[remote_proc_id].slave) {
+ self = ipc_get_slave_addr(remote_proc_id, shared_addr);
+ remote = ipc_get_master_addr(remote_proc_id,
+ shared_addr);
+ } else {
+ self = ipc_get_master_addr(remote_proc_id,
+ shared_addr);
+ remote = ipc_get_slave_addr(remote_proc_id,
+ shared_addr);
+ }
+ /* set my processor's reserved key to finish */
+ self->started_key = IPC_PROCSYNCFINISH;
+#if 0
+ /* write back my processor's reserve key */
+ if (cache_enabled)
+ Cache_wbInv((void *)self, reserved_size,
+ Cache_Type_ALL, true);
+#endif
+ /* if slave processor, wait for remote to finish sync */
+ if (ipc_module->proc_entry[remote_proc_id].slave) {
+ /* wait for remote processor to finish */
+ do {
+#if 0
+ if (cacheEnabled) {
+ Cache_inv((Ptr)remote, reservedSize,
+ Cache_Type_ALL, TRUE);
+ }
+#endif
+ } while (remote->started_key != IPC_PROCSYNCFINISH);
+ }
+ }
+
+ return IPC_S_SUCCESS;
+}
+
+/*
+ * ======== ipc_read_config ========
+ */
+int ipc_read_config(u16 remote_proc_id, u32 tag, void *cfg, u32 size)
+{
+#if 0
+ bool cache_enabled = sharedregion_is_cache_enabled(0);
+#endif
+ int status = IPC_E_FAIL;
+ VOLATILE struct ipc_config_entry *entry;
+
+ if (ipc_module->ref_count == 0) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ if (ipc_module->proc_entry[remote_proc_id].is_attached == false) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+
+#if 0
+ if (cache_enabled) {
+ Cache_inv(ipc_module->proc_entry[remote_proc_id].
+ remote_config_list,
+ sharedregion_get_cache_line_size(0),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+ entry = (struct ipc_config_entry *)((struct ipc_config_head *)
+ ipc_module->proc_entry[remote_proc_id].remote_config_list)->
+ first;
+
+ while ((u32 *)entry != SHAREDREGION_INVALIDSRPTR) {
+ entry = (struct ipc_config_entry *)
+ sharedregion_get_ptr((u32 *)entry);
+ if (entry == NULL) {
+ status = IPC_E_FAIL;
+ goto exit;
+ }
+#if 0
+ /* Traverse the list to find the tag */
+ if (cache_enabled) {
+ Cache_inv((void *)entry,
+ size + sizeof(struct ipc_config_entry),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+
+ if ((entry->remote_proc_id == multiproc_self()) &&
+ (entry->local_proc_id == remote_proc_id) &&
+ (entry->tag == tag)) {
+
+ if (size == entry->size)
+ memcpy(cfg,
+ (void *)((u32)entry + sizeof(struct
+ ipc_config_entry)),
+ entry->size);
+ else
+ status = IPC_E_FAIL;
+ } else {
+ entry = (struct ipc_config_entry *)entry->next;
+ }
+ }
+
+
+exit:
+ if (status < 0)
+ pr_err("ipc_read_config failed: status [0x%x]\n", status);
+
+ return status;
+}
+
+/*
+ * ======== ipc_reserved_size_per_proc ========
+ */
+static u32 ipc_reserved_size_per_proc(void)
+{
+ u32 reserved_size = sizeof(struct ipc_reserved) *
+ multiproc_get_num_processors();
+ u32 cache_line_size = sharedregion_get_cache_line_size(0);
+
+ /* Calculate amount to reserve per processor */
+ if (cache_line_size > reserved_size)
+ /* Use cache_line_size if larger than reserved_size */
+ reserved_size = cache_line_size;
+ else
+ /* Round reserved_size to cache_line_size */
+ reserved_size = ROUND_UP(reserved_size, cache_line_size);
+
+ return reserved_size;
+}
+
+/*!
+ * ======== ipc_write_config ========
+ */
+int ipc_write_config(u16 remote_proc_id, u32 tag, void *cfg, u32 size)
+{
+#if 0
+ bool cache_enabled = sharedregion_is_cache_enabled(0);
+#endif
+ u32 cache_line_size = sharedregion_get_cache_line_size(0);
+ int status = IPC_S_SUCCESS;
+ struct ipc_config_entry *entry;
+
+ if (ipc_module->ref_count == 0) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ if (ipc_module->proc_entry[remote_proc_id].is_attached == false) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ /* Allocate memory from the shared heap (System Heap) */
+ entry = sl_heap_alloc(sharedregion_get_heap(0),
+ size + sizeof(struct ipc_config_entry),
+ cache_line_size);
+
+ if (entry == NULL) {
+ status = IPC_E_FAIL;
+ goto exit;
+ }
+
+ entry->remote_proc_id = remote_proc_id;
+ entry->local_proc_id = multiproc_self();
+ entry->tag = tag;
+ entry->size = size;
+ memcpy((void *)((u32)entry + sizeof(struct ipc_config_entry)),
+ cfg, size);
+
+ /* Create a linked-list of config */
+ if (((struct ipc_config_head *)ipc_module->
+ proc_entry[remote_proc_id].local_config_list)->first
+ == (u32)SHAREDREGION_INVALIDSRPTR) {
+
+ entry->next = (u32)SHAREDREGION_INVALIDSRPTR;
+ ((struct ipc_config_head *)ipc_module->
+ proc_entry[remote_proc_id].local_config_list)->first =
+ (u32)sharedregion_get_srptr(entry, 0);
+
+ if (((struct ipc_config_head *)ipc_module->
+ proc_entry[remote_proc_id].local_config_list)->first
+ == (u32)SHAREDREGION_INVALIDSRPTR)
+ status = IPC_E_FAIL;
+ } else {
+ entry->next = ((struct ipc_config_head *)ipc_module->
+ proc_entry[remote_proc_id].local_config_list)->first;
+
+ ((struct ipc_config_head *)ipc_module->
+ proc_entry[remote_proc_id].local_config_list)->first =
+ (u32)sharedregion_get_srptr(entry, 0);
+ if (((struct ipc_config_head *)ipc_module->
+ proc_entry[remote_proc_id].local_config_list)->first
+ == (u32)SHAREDREGION_INVALIDSRPTR)
+ status = IPC_E_FAIL;
+ }
+#if 0
+ if (cache_enabled) {
+ Cache_wbInv(ipc_module->proc_entry[remote_proc_id].
+ local_config_list,
+ sharedregion_get_cache_line_size(0),
+ Cache_Type_ALL,
+ false);
+
+ Cache_wbInv(entry,
+ size + sizeof(struct ipc_config_entry),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+
+exit:
+ if (status < 0)
+ pr_err("ipc_write_config failed: status [0x%x]\n", status);
+
+ return status;
+}
+
+
+/*
+ * ======== ipc_start ========
+ */
+int ipc_start(void)
+{
+ int status = 0;
+ int i;
+ struct sharedregion_entry entry;
+ void *ipc_shared_addr;
+ void *gatemp_shared_addr;
+ void *ipu_pm_shared_addr;
+ struct gatemp_params gatemp_params;
+ bool line_available;
+
+ /* This sets the ref_count variable is not initialized, upper 16 bits
+ * is written with module Id to ensure correctness of ref_count
+ * variable.
+ */
+ atomic_cmpmask_and_set(&(ipc_module->start_ref_count),
+ IPC_MAKE_MAGICSTAMP(0),
+ IPC_MAKE_MAGICSTAMP(0));
+ if (atomic_inc_return(&(ipc_module->start_ref_count))
+ != IPC_MAKE_MAGICSTAMP(1u)) {
+ status = IPC_S_SUCCESS;
+ goto exit;
+ }
+
+ /* get region 0 information */
+ sharedregion_get_entry(0, &entry);
+
+ /* if entry is not valid then return */
+ if (entry.is_valid == false) {
+ status = IPC_E_FAIL;
+ goto exit;
+ }
+ /*
+ * Need to reserve memory in region 0 for processor synchronization.
+ * This must done before SharedRegion_start().
+ */
+ ipc_shared_addr = sharedregion_reserve_memory(0,
+ ipc_get_region0_reserved_size());
+
+ /* must reserve memory for gatemp before sharedregion_start() */
+ gatemp_shared_addr = sharedregion_reserve_memory(0,
+ gatemp_get_region0_reserved_size());
+
+ /* Init params for default gate(must match those in gatemp_start() */
+ gatemp_params_init(&gatemp_params);
+ gatemp_params.local_protect = GATEMP_LOCALPROTECT_TASKLET;
+
+ if (multiproc_get_num_processors() > 1)
+ gatemp_params.remote_protect = GATEMP_REMOTEPROTECT_SYSTEM;
+ else
+ gatemp_params.remote_protect = GATEMP_REMOTEPROTECT_NONE;
+
+ /* reserve memory for default gate before SharedRegion_start() */
+ sharedregion_reserve_memory(0, gatemp_shared_mem_req(&gatemp_params));
+
+ /* reserve memory for PM region */
+ ipu_pm_shared_addr = sharedregion_reserve_memory(0,
+ ipu_pm_mem_req(NULL));
+
+ /* clear the reserved memory */
+ sharedregion_clear_reserved_memory();
+
+ /* Set shared addresses */
+ ipc_module->ipc_shared_addr = ipc_shared_addr;
+ ipc_module->gatemp_shared_addr = gatemp_shared_addr;
+ ipc_module->ipu_pm_shared_addr = ipu_pm_shared_addr;
+
+ /* create default GateMP, must be called before sharedregion_start */
+ status = gatemp_start(ipc_module->gatemp_shared_addr);
+ if (status < 0) {
+ status = IPC_E_FAIL;
+ goto exit;
+ }
+
+ /* create HeapMemMP in each SharedRegion */
+ status = sharedregion_start();
+ if (status < 0) {
+ status = IPC_E_FAIL;
+ goto exit;
+ }
+
+ /* Call attach for all procs if proc_sync is ALL */
+ if (ipc_module->proc_sync == IPC_PROCSYNC_ALL) {
+ /* Must attach to owner first to get default GateMP and
+ * HeapMemMP */
+ if (multiproc_self() != entry.owner_proc_id) {
+ do {
+ status = ipc_attach(entry.owner_proc_id);
+ } while (status < 0);
+ }
+
+ /* Loop to attach to all other processors */
+ for (i = 0; i < multiproc_get_num_processors(); i++) {
+ if ((i == multiproc_self())
+ || (i == entry.owner_proc_id))
+ continue;
+ line_available =
+ notify_setup_proxy_int_line_available(i);
+ if (!line_available)
+ continue;
+ /* call Ipc_attach for every remote processor */
+ do {
+ status = ipc_attach(i);
+ } while (status < 0);
+ }
+ }
+
+exit:
+ if (status < 0)
+ pr_err("ipc_start failed: status [0x%x]\n", status);
+
+ return status;
+}
+
+
+/*
+ * ======== ipc_stop ========
+ */
+int ipc_stop(void)
+{
+ int status = IPC_S_SUCCESS;
+ int tmp_status = IPC_S_SUCCESS;
+ struct sharedregion_entry entry;
+ struct gatemp_params gatemp_params;
+
+ if (unlikely(atomic_cmpmask_and_lt(&(ipc_module->start_ref_count),
+ IPC_MAKE_MAGICSTAMP(0),
+ IPC_MAKE_MAGICSTAMP(1)) == true)) {
+ status = IPC_E_FAIL;
+ goto exit;
+ }
+
+ if (likely(atomic_dec_return(&ipc_module->start_ref_count)
+ == IPC_MAKE_MAGICSTAMP(0))) {
+ /* get region 0 information */
+ sharedregion_get_entry(0, &entry);
+
+ /* if entry is not valid then return */
+ if (entry.is_valid == false) {
+ status = IPC_E_FAIL;
+ goto exit;
+ }
+
+
+ /*
+ * Need to unreserve memory in region 0 for processor
+ * synchronization. This must done before sharedregion_stop().
+ */
+ sharedregion_unreserve_memory(0,
+ ipc_get_region0_reserved_size());
+
+ /* must unreserve memory for GateMP before
+ sharedregion_stop() */
+ sharedregion_unreserve_memory(0,
+ gatemp_get_region0_reserved_size());
+
+ /* Init params for default gate (must match those
+ in gatemp_stop() */
+ gatemp_params_init(&gatemp_params);
+ gatemp_params.local_protect = GATEMP_LOCALPROTECT_TASKLET;
+
+ if (multiproc_get_num_processors() > 1)
+ gatemp_params.remote_protect =
+ GATEMP_REMOTEPROTECT_SYSTEM;
+ else
+ gatemp_params.remote_protect =
+ GATEMP_REMOTEPROTECT_NONE;
+
+ /* unreserve memory for default gate before
+ sharedregion_stop() */
+ sharedregion_unreserve_memory(0,
+ gatemp_shared_mem_req(&gatemp_params));
+
+ /* must unreserve memory for PM before sharedregion_stop() */
+ sharedregion_unreserve_memory(0, ipu_pm_mem_req(NULL));
+
+ /* Delete heapmemmp in each sharedregion */
+ status = sharedregion_stop();
+ if (status < 0) {
+ status = IPC_E_FAIL;
+ goto exit;
+ }
+
+ /* delete default gatemp, must be called after
+ * sharedregion_stop
+ */
+ tmp_status = gatemp_stop();
+ if ((tmp_status < 0) && (status >= 0)) {
+ status = IPC_E_FAIL;
+ goto exit;
+ }
+
+ ipc_module->ipu_pm_shared_addr = NULL;
+ ipc_module->gatemp_shared_addr = NULL;
+ ipc_module->ipc_shared_addr = NULL;
+ }
+exit:
+ if (status < 0)
+ pr_err("ipc_stop failed: status [0x%x]\n", status);
+
+ return status;
+}
+
+
+/*
+ * ======== ipc_get_config ========
+ */
+void ipc_get_config(struct ipc_config *cfg_params)
+{
+ int key;
+ int status = 0;
+
+ BUG_ON(cfg_params == NULL);
+
+ if (cfg_params == NULL) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+
+ key = gate_enter_system();
+ if (ipc_module->ref_count == 0)
+ cfg_params->proc_sync = IPC_PROCSYNC_ALL;
+ else
+ memcpy((void *) cfg_params, (void *) &ipc_module->cfg,
+ sizeof(struct ipc_config));
+
+ gate_leave_system(key);
+
+exit:
+ if (status < 0)
+ pr_err("ipc_get_config failed: status [0x%x]\n", status);
+}
+
+
+/* Sets up ipc for this processor. */
+int ipc_setup(const struct ipc_config *cfg)
+{
+ int status = IPC_S_SUCCESS;
+ struct ipc_config tmp_cfg;
+ int key;
+ int i;
+
+ key = gate_enter_system();
+ ipc_module->ref_count++;
+
+ /* This sets the ref_count variable is not initialized, upper 16 bits is
+ * written with module Id to ensure correctness of ref_count variable.
+ */
+ if (ipc_module->ref_count > 1) {
+ status = IPC_S_ALREADYSETUP;
+ gate_leave_system(key);
+ goto exit;
+ }
+
+ gate_leave_system(key);
+ if (cfg == NULL) {
+ ipc_get_config(&tmp_cfg);
+ cfg = &tmp_cfg;
+ }
+
+ /* Copy the cfg */
+ memcpy(&ipc_module->cfg, cfg, sizeof(struct ipc_config));
+
+ ipc_module->proc_sync = cfg->proc_sync;
+
+ status = platform_setup();
+ if (status < 0) {
+ key = gate_enter_system();
+ ipc_module->ref_count--;
+ gate_leave_system(key);
+ status = IPC_E_FAIL;
+ goto exit;
+ }
+
+ /* Following can be done regardless of status */
+ for (i = 0; i < multiproc_get_num_processors(); i++)
+ ipc_module->proc_entry[i].is_attached = false;
+
+exit:
+ if (status < 0)
+ pr_err("ipc_setup failed: status [0x%x]\n", status);
+
+ return status;
+}
+
+
+/*
+ * =========== ipc_destroy ==========
+ * Destroys ipc for this processor.
+ */
+int ipc_destroy(void)
+{
+ int status = IPC_S_SUCCESS;
+ int key;
+
+ key = gate_enter_system();
+ ipc_module->ref_count--;
+
+ if (ipc_module->ref_count < 0) {
+ gate_leave_system(key);
+ status = IPC_E_INVALIDSTATE;
+ goto exit;
+ }
+
+ if (ipc_module->ref_count == 0) {
+ gate_leave_system(key);
+ if (unlikely(atomic_cmpmask_and_lt(
+ &(ipc_module->start_ref_count),
+ IPC_MAKE_MAGICSTAMP(0),
+ IPC_MAKE_MAGICSTAMP(1)) == false)) {
+ /*
+ * ipc_start was called, but ipc_stop never happened.
+ * Need to call ipc_stop here.
+ */
+ /* Set the count to 1 so only need to call stop once. */
+ atomic_set(&ipc_module->start_ref_count,
+ IPC_MAKE_MAGICSTAMP(1));
+ ipc_stop();
+ }
+ status = platform_destroy();
+ if (status < 0) {
+ status = IPC_E_FAIL;
+ goto exit;
+ }
+ } else
+ gate_leave_system(key);
+
+exit:
+ if (status < 0)
+ pr_err("ipc_destroy failed: status [0x%x]\n", status);
+
+ return status;
+}
+
+
+/*
+ * ====== ipc_create =======
+ * Creates a IPC.
+ */
+int ipc_create(u16 remote_proc_id, struct ipc_params *params)
+{
+ ipc_module->proc_entry[remote_proc_id].entry.setup_messageq =
+ params->setup_messageq;
+ ipc_module->proc_entry[remote_proc_id].entry.setup_notify =
+ params->setup_notify;
+ ipc_module->proc_entry[remote_proc_id].entry.setup_ipu_pm =
+ params->setup_ipu_pm;
+ ipc_module->proc_entry[remote_proc_id].entry.remote_proc_id =
+ remote_proc_id;
+
+ /* Assert that the proc_sync is same as configured for the module. */
+ BUG_ON(ipc_module->proc_sync != params->proc_sync);
+
+ return IPC_S_SUCCESS;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/ipc_drv.c b/drivers/dsp/syslink/multicore_ipc/ipc_drv.c
new file mode 100644
index 00000000000..d3c5a1b279e
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/ipc_drv.c
@@ -0,0 +1,448 @@
+/*
+ * ipc_drv.c
+ *
+ * IPC driver module.
+ *
+ * Copyright (C) 2008-2009 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 <linux/module.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+#include <linux/fs.h>
+#include <linux/moduleparam.h>
+#include <linux/cdev.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+#include <ipc_ioctl.h>
+#include <ipc.h>
+#include <drv_notify.h>
+#include <notify_ioctl.h>
+#include <nameserver.h>
+#ifdef CONFIG_SYSLINK_RECOVERY
+#include <plat/iommu.h>
+#include <plat/remoteproc.h>
+#endif
+
+#define IPC_NAME "syslink_ipc"
+#define IPC_MAJOR 0
+#define IPC_MINOR 0
+#define IPC_DEVICES 1
+
+#define ipc_release_resource(x, y, z) (ipc_ioc_router(x, y, z, false))
+
+struct ipc_device {
+ struct cdev cdev;
+
+ struct blocking_notifier_head notifier;
+};
+
+static struct ipc_device *ipc_device;
+static struct class *ipc_class;
+
+static s32 ipc_major = IPC_MAJOR;
+static s32 ipc_minor = IPC_MINOR;
+static char *ipc_name = IPC_NAME;
+
+module_param(ipc_name, charp, 0);
+MODULE_PARM_DESC(ipc_name, "Device name, default = syslink_ipc");
+
+module_param(ipc_major, int, 0); /* Driver's major number */
+MODULE_PARM_DESC(ipc_major, "Major device number, default = 0 (auto)");
+
+module_param(ipc_minor, int, 0); /* Driver's minor number */
+MODULE_PARM_DESC(ipc_minor, "Minor device number, default = 0 (auto)");
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_LICENSE("GPL v2");
+
+#ifdef CONFIG_SYSLINK_RECOVERY
+#define REC_TIMEOUT 5000 /* recovery timeout in msecs */
+static atomic_t ipc_cref; /* number of ipc open handles */
+static struct workqueue_struct *ipc_rec_queue;
+static struct work_struct ipc_recovery_work;
+static DECLARE_COMPLETION(ipc_comp);
+static DECLARE_COMPLETION(ipc_open_comp);
+static bool recover;
+static struct iommu *piommu;
+static struct omap_rproc *prproc_sysm3;
+
+static int ipc_ducati_iommu_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v);
+
+static int ipc_sysm3_rproc_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v);
+
+static struct notifier_block ipc_notify_nb_iommu_ducati = {
+ .notifier_call = ipc_ducati_iommu_notifier_call,
+};
+
+static struct notifier_block ipc_notify_nb_rproc_ducati0 = {
+ .notifier_call = ipc_sysm3_rproc_notifier_call,
+};
+
+static void ipc_recover(struct work_struct *work)
+{
+ if (atomic_read(&ipc_cref)) {
+ INIT_COMPLETION(ipc_comp);
+ while (!wait_for_completion_timeout(&ipc_comp,
+ msecs_to_jiffies(REC_TIMEOUT)))
+ pr_info("%s:%d handle(s) still opened\n",
+ __func__, atomic_read(&ipc_cref));
+ }
+ recover = false;
+ complete_all(&ipc_open_comp);
+}
+
+void ipc_recover_schedule(void)
+{
+ INIT_COMPLETION(ipc_open_comp);
+ recover = true;
+ queue_work(ipc_rec_queue, &ipc_recovery_work);
+}
+EXPORT_SYMBOL_GPL(ipc_recover_schedule);
+
+static int ipc_ducati_iommu_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ switch ((int)val) {
+ case IOMMU_FAULT:
+ ipc_recover_schedule();
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static int ipc_sysm3_rproc_notifier_call(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ switch ((int)val) {
+ case OMAP_RPROC_START:
+ piommu = iommu_get("ducati");
+ if (piommu != ERR_PTR(-ENODEV) &&
+ piommu != ERR_PTR(-EINVAL))
+ iommu_register_notifier(piommu,
+ &ipc_notify_nb_iommu_ducati);
+ else
+ piommu = NULL;
+ return 0;
+ case OMAP_RPROC_STOP:
+ if (piommu != NULL) {
+ iommu_unregister_notifier(piommu,
+ &ipc_notify_nb_iommu_ducati);
+ iommu_put(piommu);
+ piommu = NULL;
+ }
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+bool ipc_recovering()
+{
+ return recover;
+}
+#endif
+
+/*
+ * ======== ipc_open ========
+ * This function is invoked when an application
+ * opens handle to the ipc driver
+ */
+static int ipc_open(struct inode *inode, struct file *filp)
+{
+ s32 retval = 0;
+ struct ipc_device *dev;
+ struct ipc_process_context *pr_ctxt = NULL;
+
+#ifdef CONFIG_SYSLINK_RECOVERY
+ if (recover) {
+ if (filp->f_flags & O_NONBLOCK ||
+ wait_for_completion_killable(&ipc_open_comp))
+ return -EBUSY;
+ }
+#endif
+
+ pr_ctxt = kzalloc(sizeof(struct ipc_process_context), GFP_KERNEL);
+ if (!pr_ctxt)
+ retval = -ENOMEM;
+ else {
+ INIT_LIST_HEAD(&pr_ctxt->resources);
+ spin_lock_init(&pr_ctxt->res_lock);
+ dev = container_of(inode->i_cdev, struct ipc_device,
+ cdev);
+ pr_ctxt->dev = dev;
+ filp->private_data = pr_ctxt;
+ }
+
+#ifdef CONFIG_SYSLINK_RECOVERY
+ if (!retval)
+ atomic_inc(&ipc_cref);
+#endif
+
+ return retval;
+}
+
+/*
+ * ======== ipc_release ========
+ * This function is invoked when an application
+ * closes handle to the ipc driver
+ */
+static int ipc_release(struct inode *inode, struct file *filp)
+{
+ s32 retval = 0;
+ struct ipc_process_context *pr_ctxt;
+ struct resource_info *info = NULL, *temp = NULL;
+
+ if (!filp->private_data) {
+ retval = -EIO;
+ goto err;
+ }
+
+ ipc_notify_event(IPC_CLOSE, (void *)NULL);
+
+ pr_ctxt = filp->private_data;
+
+ list_for_each_entry_safe(info, temp, &pr_ctxt->resources, res) {
+ retval = ipc_release_resource(info->cmd, (ulong)info->data,
+ filp);
+ }
+
+ list_del(&pr_ctxt->resources);
+ kfree(pr_ctxt);
+
+ filp->private_data = NULL;
+err:
+#ifdef CONFIG_SYSLINK_RECOVERY
+ if (!atomic_dec_return(&ipc_cref))
+ complete(&ipc_comp);
+#endif
+ return retval;
+}
+
+/*
+ * ======== ipc_ioctl ========
+ * This function provides IO interface to the
+ * ipc driver
+ */
+static long ipc_ioctl(struct file *filp, u32 cmd, ulong arg)
+{
+ s32 retval = 0;
+ void __user *argp = (void __user *)arg;
+
+ /* Verify the memory and ensure that it is not is kernel
+ address space
+ */
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ retval = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ retval = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
+
+ if (retval) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ retval = ipc_ioc_router(cmd, (ulong)argp, filp, true);
+ return retval;
+
+exit:
+ return retval;
+}
+
+static const struct file_operations ipc_fops = {
+ .open = ipc_open,
+ .release = ipc_release,
+ .unlocked_ioctl = ipc_ioctl,
+ .read = notify_drv_read,
+ .mmap = notify_drv_mmap,
+};
+
+/*
+ * ======== ipc_notify_event ========
+ * IPC event notifications.
+ */
+int ipc_notify_event(int event, void *data)
+{
+ return blocking_notifier_call_chain(&ipc_device->notifier, event, data);
+}
+
+/*
+ * ======== ipc_register_notifier ========
+ * Register for IPC events.
+ */
+int ipc_register_notifier(struct notifier_block *nb)
+{
+ if (!nb)
+ return -EINVAL;
+ return blocking_notifier_chain_register(&ipc_device->notifier, nb);
+}
+EXPORT_SYMBOL_GPL(ipc_register_notifier);
+
+/*
+ * ======== ipc_unregister_notifier ========
+ * Un-register for IPC events.
+ */
+int ipc_unregister_notifier(struct notifier_block *nb)
+{
+ if (!nb)
+ return -EINVAL;
+ return blocking_notifier_chain_unregister(&ipc_device->notifier, nb);
+}
+EXPORT_SYMBOL_GPL(ipc_unregister_notifier);
+
+/*
+ * ======== ipc_modules_init ========
+ * IPC Initialization routine. will initialize various
+ * sub components (modules) of IPC.
+ */
+static int ipc_modules_init(void)
+{
+ /* Setup the notify_drv module */
+ _notify_drv_setup();
+
+#ifdef CONFIG_SYSLINK_RECOVERY
+ ipc_rec_queue = create_workqueue("ipc_rec_queue");
+ INIT_WORK(&ipc_recovery_work, ipc_recover);
+ INIT_COMPLETION(ipc_comp);
+
+ prproc_sysm3 = omap_rproc_get("ducati-proc0");
+ if (prproc_sysm3 != ERR_PTR(-ENODEV))
+ omap_rproc_register_notifier(prproc_sysm3,
+ &ipc_notify_nb_rproc_ducati0);
+ else
+ prproc_sysm3 = NULL;
+#endif
+
+ return 0;
+}
+
+/*
+ * ======== ipc_modules_exit ========
+ * IPC cleanup routine. will cleanup of various
+ * sub components (modules) of IPC.
+ */
+static void ipc_modules_exit(void)
+{
+#ifdef CONFIG_SYSLINK_RECOVERY
+ if (prproc_sysm3) {
+ omap_rproc_unregister_notifier(prproc_sysm3,
+ &ipc_notify_nb_rproc_ducati0);
+ omap_rproc_put(prproc_sysm3);
+ }
+ destroy_workqueue(ipc_rec_queue);
+#endif
+ /* Destroy the notify_drv module */
+ _notify_drv_destroy();
+}
+
+/*
+ * ======== ipc_init ========
+ * Initialization routine. Executed when the driver is
+ * loaded (as a kernel module), or when the system
+ * is booted (when included as part of the kernel
+ * image).
+ */
+static int __init ipc_init(void)
+{
+ dev_t dev ;
+ s32 retval = 0;
+
+ retval = alloc_chrdev_region(&dev, ipc_minor, IPC_DEVICES,
+ ipc_name);
+ ipc_major = MAJOR(dev);
+
+ if (retval < 0) {
+ pr_err("ipc_init: can't get major %x\n", ipc_major);
+ goto exit;
+ }
+
+ ipc_device = kmalloc(sizeof(struct ipc_device), GFP_KERNEL);
+ if (!ipc_device) {
+ pr_err("ipc_init: memory allocation failed for ipc_device\n");
+ retval = -ENOMEM;
+ goto unreg_exit;
+ }
+
+ memset(ipc_device, 0, sizeof(struct ipc_device));
+
+ BLOCKING_INIT_NOTIFIER_HEAD(&ipc_device->notifier);
+
+ retval = ipc_modules_init();
+ if (retval) {
+ pr_err("ipc_init: ipc initialization failed\n");
+ goto unreg_exit;
+
+ }
+ ipc_class = class_create(THIS_MODULE, "syslink_ipc");
+ if (IS_ERR(ipc_class)) {
+ pr_err("ipc_init: error creating ipc class\n");
+ retval = PTR_ERR(ipc_class);
+ goto unreg_exit;
+ }
+
+ device_create(ipc_class, NULL, MKDEV(ipc_major, ipc_minor), NULL,
+ ipc_name);
+ cdev_init(&ipc_device->cdev, &ipc_fops);
+ ipc_device->cdev.owner = THIS_MODULE;
+ retval = cdev_add(&ipc_device->cdev, dev, IPC_DEVICES);
+ if (retval) {
+ pr_err("ipc_init: failed to add the ipc device\n");
+ goto class_exit;
+ }
+ return retval;
+
+class_exit:
+ class_destroy(ipc_class);
+
+unreg_exit:
+ unregister_chrdev_region(dev, IPC_DEVICES);
+ kfree(ipc_device);
+
+exit:
+ return retval;
+}
+
+/*
+ * ======== ipc_exit ========
+ * This function is invoked during unlinking of ipc
+ * module from the kernel. ipc resources are
+ * freed in this function.
+ */
+static void __exit ipc_exit(void)
+{
+ dev_t devno;
+
+ ipc_modules_exit();
+ devno = MKDEV(ipc_major, ipc_minor);
+ if (ipc_device) {
+ cdev_del(&ipc_device->cdev);
+ kfree(ipc_device);
+ }
+ unregister_chrdev_region(devno, IPC_DEVICES);
+ if (ipc_class) {
+ /* remove the device from sysfs */
+ device_destroy(ipc_class, MKDEV(ipc_major, ipc_minor));
+ class_destroy(ipc_class);
+ }
+}
+
+/*
+ * ipc driver initialization and de-initialization functions
+ */
+module_init(ipc_init);
+module_exit(ipc_exit);
diff --git a/drivers/dsp/syslink/multicore_ipc/ipc_ioctl.c b/drivers/dsp/syslink/multicore_ipc/ipc_ioctl.c
new file mode 100644
index 00000000000..6aa5841fa46
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/ipc_ioctl.c
@@ -0,0 +1,99 @@
+/*
+ * ipc_ioctl.c
+ *
+ * This is the collection of ioctl functions that will invoke various ipc
+ * module level functions based on user comands
+ *
+ * Copyright (C) 2008-2009 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 <linux/uaccess.h>
+#include <linux/types.h>
+#include <linux/bug.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <ipc_ioctl.h>
+#include <multiproc_ioctl.h>
+#include <nameserver_ioctl.h>
+#include <heapbufmp_ioctl.h>
+#include <sharedregion_ioctl.h>
+#include <gatemp_ioctl.h>
+#include <listmp_ioctl.h>
+#include <messageq_ioctl.h>
+#include <sysipc_ioctl.h>
+/*#include <sysmemmgr_ioctl.h>*/
+#include <heapmemmp_ioctl.h>
+#include <drv_notify.h>
+
+void add_pr_res(struct ipc_process_context *pr_ctxt, unsigned int cmd,
+ void *data)
+{
+ struct resource_info *info = kmalloc(sizeof(struct resource_info),
+ GFP_KERNEL);
+ info->cmd = cmd;
+ info->data = data;
+
+ spin_lock(&pr_ctxt->res_lock);
+ list_add(&info->res, &pr_ctxt->resources);
+ spin_unlock(&pr_ctxt->res_lock);
+}
+
+void remove_pr_res(struct ipc_process_context *pr_ctxt,
+ struct resource_info *info)
+{
+ if (info) {
+ spin_lock(&pr_ctxt->res_lock);
+ list_del(&info->res);
+ kfree(info->data);
+ kfree(info);
+ spin_unlock(&pr_ctxt->res_lock);
+ }
+}
+
+/*
+ * This will route the ioctl commands to proper modules
+ */
+int ipc_ioc_router(u32 cmd, ulong arg, struct file *filp, bool user)
+{
+ s32 retval = 0;
+ u32 ioc_nr = _IOC_NR(cmd);
+
+ if (ioc_nr >= MULTIPROC_BASE_CMD && ioc_nr <= MULTIPROC_END_CMD)
+ retval = multiproc_ioctl(NULL, filp, cmd, arg, user);
+ else if (ioc_nr >= NAMESERVER_BASE_CMD && ioc_nr <= NAMESERVER_END_CMD)
+ retval = nameserver_ioctl(NULL, filp, cmd, arg, user);
+ else if (ioc_nr >= HEAPBUFMP_BASE_CMD && ioc_nr <= HEAPBUFMP_END_CMD)
+ retval = heapbufmp_ioctl(NULL, filp, cmd, arg, user);
+ else if (ioc_nr >= SHAREDREGION_BASE_CMD &&
+ ioc_nr <= SHAREDREGION_END_CMD)
+ retval = sharedregion_ioctl(NULL, filp, cmd, arg, user);
+ else if (ioc_nr >= GATEMP_BASE_CMD && ioc_nr <= GATEMP_END_CMD)
+ retval = gatemp_ioctl(NULL, filp, cmd, arg, user);
+ else if (ioc_nr >= LISTMP_BASE_CMD && ioc_nr <= LISTMP_END_CMD)
+ retval = listmp_ioctl(NULL, filp, cmd, arg, user);
+ else if (ioc_nr >= MESSAGEQ_BASE_CMD && ioc_nr <= MESSAGEQ_END_CMD)
+ retval = messageq_ioctl(NULL, filp, cmd, arg, user);
+ else if (ioc_nr >= IPC_BASE_CMD && ioc_nr <= IPC_END_CMD)
+ retval = sysipc_ioctl(NULL, filp, cmd, arg, user);
+/* else if (ioc_nr >= SYSMEMMGR_BASE_CMD && ioc_nr <= SYSMEMMGR_END_CMD)
+ retval = sysmemmgr_ioctl(NULL, NULL, cmd, arg);*/
+ else if (ioc_nr >= HEAPMEMMP_BASE_CMD && ioc_nr <= HEAPMEMMP_END_CMD)
+ retval = heapmemmp_ioctl(NULL, filp, cmd, arg, user);
+ else if (ioc_nr >= NOTIFY_BASE_CMD && ioc_nr <= NOTIFY_END_CMD)
+ retval = notify_drv_ioctl(NULL, filp, cmd, arg, user);
+ else
+ retval = -ENOTTY;
+
+ return retval;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/listmp.c b/drivers/dsp/syslink/multicore_ipc/listmp.c
new file mode 100644
index 00000000000..db604edd450
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/listmp.c
@@ -0,0 +1,1489 @@
+/*
+ * listmp.c
+ *
+ * The listmp is a linked-list based module designed to be
+ * used in a multi-processor environment. It is designed to
+ * provide a means of communication between different processors.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+/* Standard headers */
+#include <linux/types.h>
+#include <linux/module.h>
+
+/* Utilities headers */
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+/* Syslink headers */
+#include <syslink/atomic_linux.h>
+
+/* Module level headers */
+#include <multiproc.h>
+#include <nameserver.h>
+#include <sharedregion.h>
+#include <gatemp.h>
+#include "_listmp.h"
+#include <listmp.h>
+
+
+/* =============================================================================
+ * Globals
+ * =============================================================================
+ */
+/* Macro to make a correct module magic number with ref_count */
+#define LISTMP_MAKE_MAGICSTAMP(x) ((LISTMP_MODULEID << 12u) | (x))
+
+/* Name of the reserved NameServer used for listmp. */
+#define LISTMP_NAMESERVER "ListMP"
+
+#define ROUND_UP(a, b) (((a) + ((b) - 1)) & (~((b) - 1)))
+
+/* =============================================================================
+ * Structures and Enums
+ * =============================================================================
+ */
+/* structure for listmp module state */
+struct listmp_module_object {
+ atomic_t ref_count;
+ /* Reference count */
+ void *ns_handle;
+ /* Handle to the local NameServer used for storing listmp objects */
+ struct list_head obj_list;
+ /* List holding created listmp objects */
+ struct mutex *local_lock;
+ /* Handle to lock for protecting obj_list */
+ struct listmp_config cfg;
+ /* Current config values */
+ struct listmp_config default_cfg;
+ /* Default config values */
+ struct listmp_params default_inst_params;
+ /* Default instance creation parameters */
+};
+
+/* Structure for the internal Handle for the listmp. */
+struct listmp_object{
+ struct list_head list_elem;
+ /* Used for creating a linked list */
+ VOLATILE struct listmp_attrs *attrs;
+ /* Shared memory attributes */
+ void *ns_key;
+ /* nameserver key required for remove */
+ void *gatemp_handle;
+ /* Gate for critical regions */
+ u32 alloc_size;
+ /* Shared memory allocated */
+ u16 region_id;
+ /* SharedRegion ID */
+ bool cache_enabled;
+ /* Whether to do cache calls */
+ struct listmp_proc_attrs owner;
+ /* Creator's attributes associated with an instance */
+ struct listmp_params params;
+ /* the parameter structure */
+ void *top;
+ /* Pointer to the top Object */
+};
+
+/* =============================================================================
+ * Globals
+ * =============================================================================
+ */
+/* Variable for holding state of the nameserver module. */
+static struct listmp_module_object listmp_state = {
+ .default_cfg.max_runtime_entries = 32,
+ .default_cfg.max_name_len = 32,
+ .default_inst_params.shared_addr = NULL,
+ .default_inst_params.name = NULL,
+ .default_inst_params.gatemp_handle = NULL,
+ .default_inst_params.region_id = 0,
+};
+
+/* Pointer to the listmp module state */
+static struct listmp_module_object *listmp_module = &listmp_state;
+
+/* =============================================================================
+ * Function definitions
+ * =============================================================================
+ */
+/* Creates a new instance of listmp module. This is an internal
+ * function because both listmp_create and
+ * listmp_open call use the same functionality. */
+static int _listmp_create(struct listmp_object **handle_ptr,
+ struct listmp_params *params, u32 create_flag);
+
+
+/* =============================================================================
+ * Function API's
+ * =============================================================================
+ */
+/* Function to get configuration parameters to setup the listmp module. */
+void listmp_get_config(struct listmp_config *cfg_params)
+{
+ int status = 0;
+
+ if (WARN_ON(unlikely(cfg_params == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ if (atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true) {
+ /* If setup has not yet been called) */
+ memcpy(cfg_params, &listmp_module->default_cfg,
+ sizeof(struct listmp_config));
+ } else {
+ memcpy(cfg_params, &listmp_module->cfg,
+ sizeof(struct listmp_config));
+ }
+
+exit:
+ if (status < 0)
+ pr_err("listmp_get_config failed: status = 0x%x\n", status);
+ return;
+}
+
+/* Function to setup the listmp module. */
+int listmp_setup(const struct listmp_config *cfg)
+{
+ int status = 0;
+ int status1 = 0;
+ void *nshandle = NULL;
+ struct nameserver_params params;
+ struct listmp_config tmp_cfg;
+
+ /* This sets the ref_count variable if not initialized, upper 16 bits is
+ * written with module Id to ensure correctness of ref_count variable.
+ */
+ atomic_cmpmask_and_set(&listmp_module->ref_count,
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(0));
+ if (atomic_inc_return(&listmp_module->ref_count)
+ != LISTMP_MAKE_MAGICSTAMP(1)) {
+ return 1;
+ }
+
+ if (cfg == NULL) {
+ listmp_get_config(&tmp_cfg);
+ cfg = &tmp_cfg;
+ }
+
+ if (WARN_ON(cfg->max_name_len == 0)) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* Initialize the parameters */
+ nameserver_params_init(&params);
+ params.max_value_len = 4;
+ params.max_name_len = cfg->max_name_len;
+ /* Create the nameserver for modules */
+ nshandle = nameserver_create(LISTMP_NAMESERVER, &params);
+ if (unlikely(nshandle == NULL)) {
+ status = LISTMP_E_FAIL;
+ goto exit;
+ }
+ listmp_module->ns_handle = nshandle;
+
+ /* Construct the list object */
+ INIT_LIST_HEAD(&listmp_module->obj_list);
+ /* Create a lock for protecting list object */
+ listmp_module->local_lock = kmalloc(sizeof(struct mutex), GFP_KERNEL);
+ if (listmp_module->local_lock == NULL) {
+ status = -ENOMEM;
+ goto clean_nameserver;
+ }
+ mutex_init(listmp_module->local_lock);
+
+ /* Copy the cfg */
+ memcpy(&listmp_module->cfg, cfg, sizeof(struct listmp_config));
+ return 0;
+
+clean_nameserver:
+ status1 = nameserver_delete(&(listmp_module->ns_handle));
+ WARN_ON(status1 < 0);
+ atomic_set(&listmp_module->ref_count, LISTMP_MAKE_MAGICSTAMP(0));
+exit:
+ pr_err("listmp_setup failed! status = 0x%x\n", status);
+ return status;
+}
+
+/* Function to destroy the listmp module. */
+int listmp_destroy(void)
+{
+ int status = 0;
+ int status1 = 0;
+ struct list_head *elem = NULL;
+ struct list_head *head = &listmp_module->obj_list;
+ struct list_head *next;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ if (!(atomic_dec_return(&listmp_module->ref_count) == \
+ LISTMP_MAKE_MAGICSTAMP(0))) {
+ status = 1;
+ goto exit;
+ }
+
+ /* Temporarily increment ref_count here. */
+ atomic_set(&listmp_module->ref_count, LISTMP_MAKE_MAGICSTAMP(1));
+ /* Check if any listmp instances have not been
+ * deleted so far. If not, delete them. */
+ for (elem = (head)->next; elem != (head); elem = next) {
+ /* Retain the next pointer so it doesn't get overwritten */
+ next = elem->next;
+ if (((struct listmp_object *) elem)->owner.proc_id == \
+ multiproc_self()) {
+ status1 = listmp_delete((void **)
+ &(((struct listmp_object *)elem)->top));
+ WARN_ON(status1 < 0);
+ } else {
+ status1 = listmp_close((void **)
+ &(((struct listmp_object *)elem)->top));
+ WARN_ON(status1 < 0);
+ }
+ }
+
+ if (likely(listmp_module->ns_handle != NULL)) {
+ /* Delete the nameserver for modules */
+ status = nameserver_delete(&(listmp_module->ns_handle));
+ WARN_ON(status < 0);
+ }
+
+ /* Destruct the list object */
+ list_del(&listmp_module->obj_list);
+ /* Delete the list lock */
+ kfree(listmp_module->local_lock);
+ listmp_module->local_lock = NULL;
+
+ memset(&listmp_module->cfg, 0, sizeof(struct listmp_config));
+
+ /* Again reset ref_count. */
+ atomic_set(&listmp_module->ref_count, LISTMP_MAKE_MAGICSTAMP(0));
+
+exit:
+ if (status < 0)
+ pr_err("listmp_destroy failed! status = 0x%x\n", status);
+ return status;
+}
+
+/* Function to initialize the config-params structure with supplier-specified
+ * defaults before instance creation. */
+void listmp_params_init(struct listmp_params *params)
+{
+ s32 status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(params == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ memcpy((void *)params, (void *)&listmp_module->default_inst_params,
+ sizeof(struct listmp_params));
+
+exit:
+ if (status < 0)
+ pr_err("listmp_params_init failed! status = 0x%x\n", status);
+ return;
+}
+
+/* Creates a new instance of listmp module. */
+void *listmp_create(const struct listmp_params *params)
+{
+ s32 status = 0;
+ struct listmp_object *obj = NULL;
+ struct listmp_params sparams;
+ u32 key;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(params == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ memcpy(&sparams, params, sizeof(struct listmp_params));
+
+ key = mutex_lock_interruptible(listmp_module->local_lock);
+ if (key)
+ goto exit;
+ status = _listmp_create(&obj, &sparams, (u32) true);
+ mutex_unlock(listmp_module->local_lock);
+
+exit:
+ if (status < 0)
+ pr_err("listmp_create failed! status = 0x%x\n", status);
+ return (void *)obj;
+}
+
+/* Deletes a instance of listmp instance object. */
+int listmp_delete(void **listmp_handleptr)
+{
+ int status = 0;
+ struct listmp_object *obj = NULL;
+ struct listmp_params *params = NULL;
+ u32 key;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(listmp_handleptr == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(*listmp_handleptr == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct listmp_object *)(*listmp_handleptr);
+ params = (struct listmp_params *)&obj->params;
+
+ if (unlikely(obj->owner.proc_id != multiproc_self())) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (unlikely(obj->owner.open_count > 1)) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (unlikely(obj->owner.open_count != 1)) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ /* Remove from the local list */
+ key = mutex_lock_interruptible(listmp_module->local_lock);
+ list_del(&obj->list_elem);
+ mutex_unlock(listmp_module->local_lock);
+
+ if (likely(params->name != NULL)) {
+ /* Free memory for the name */
+ kfree(params->name);
+ /* Remove from the name server */
+ if (obj->ns_key != NULL) {
+ nameserver_remove_entry(listmp_module->ns_handle,
+ obj->ns_key);
+ obj->ns_key = NULL;
+ }
+ }
+
+ /* Now free the obj */
+ kfree(obj);
+ obj = NULL;
+ *listmp_handleptr = NULL;
+
+exit:
+ if (status < 0)
+ pr_err("listmp_delete failed! status = 0x%x\n", status);
+ return status;
+}
+
+/* Function to open a listmp instance */
+int listmp_open(char *name, void **listmp_handleptr)
+{
+ int status = 0;
+ void *shared_addr = NULL;
+ bool done_flag = false;
+ struct list_head *elem;
+ u32 key;
+ u32 shared_shm_base;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(listmp_handleptr == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(name == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* First check in the local list */
+ list_for_each(elem, &listmp_module->obj_list) {
+ if (((struct listmp_object *)elem)->params.name != NULL) {
+ if (strcmp(((struct listmp_object *)elem)->params.name,
+ name) == 0) {
+ key = mutex_lock_interruptible(
+ listmp_module->local_lock);
+ if (((struct listmp_object *)elem)
+ ->owner.proc_id == multiproc_self())
+ ((struct listmp_object *)elem)
+ ->owner.open_count++;
+ mutex_unlock(listmp_module->local_lock);
+ *listmp_handleptr = \
+ (((struct listmp_object *)elem)->top);
+ done_flag = true;
+ break;
+ }
+ }
+ }
+
+ if (likely(done_flag == false)) {
+ /* Find in name server */
+ status = nameserver_get_uint32(listmp_module->ns_handle,
+ name, &shared_shm_base, NULL);
+ if (unlikely(status < 0)) {
+ status = ((status == -ENOENT) ? status : -1);
+ goto exit;
+ }
+ shared_addr = sharedregion_get_ptr((u32 *)shared_shm_base);
+ if (unlikely(shared_addr == NULL)) {
+ status = LISTMP_E_FAIL;
+ goto exit;
+ }
+ status = listmp_open_by_addr(shared_addr, listmp_handleptr);
+ }
+
+#if 0
+ if (status >= 0) {
+ attrs = (struct listmp_attrs *) (params->shared_addr);
+ if (unlikely(attrs->status != (LISTMP_CREATED)))
+ status = LISTMP_E_NOTCREATED;
+ else if (unlikely(attrs->version !=
+ (LISTMP_VERSION)))
+ status = LISTMP_E_VERSION;
+ }
+
+ if (likely(status >= 0))
+ *listmp_handleptr = (listmp_handle)
+ _listmp_create(params, false);
+#endif
+
+exit:
+ if (status < 0)
+ pr_err("listmp_open failed! status = 0x%x\n", status);
+ return status;
+}
+
+/* Function to open a listmp instance by address */
+int listmp_open_by_addr(void *shared_addr, void **listmp_handleptr)
+{
+ int status = 0;
+ bool done_flag = false;
+ struct listmp_params params;
+ struct list_head *elem;
+ u32 key;
+ struct listmp_attrs *attrs;
+ u16 id;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(listmp_handleptr == NULL)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(shared_addr == NULL)) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* First check in the local list */
+ list_for_each(elem, &listmp_module->obj_list) {
+ if (((struct listmp_object *)elem)->params.shared_addr == \
+ shared_addr) {
+ key = mutex_lock_interruptible(
+ listmp_module->local_lock);
+ if (((struct listmp_object *)elem)->owner.proc_id == \
+ multiproc_self())
+ ((struct listmp_object *)elem)
+ ->owner.open_count++;
+ mutex_unlock(listmp_module->local_lock);
+ *listmp_handleptr = \
+ (((struct listmp_object *)elem)->top);
+ done_flag = true;
+ break;
+ }
+ }
+
+ if (likely(done_flag == false)) {
+ listmp_params_init(&params);
+ params.shared_addr = shared_addr;
+
+ attrs = (struct listmp_attrs *)(shared_addr);
+ id = sharedregion_get_id(shared_addr);
+#if 0
+ if (sharedregion_is_cache_enabled(id))
+ Cache_inv(in_use, num * sizeof(u8), Cache_Type_ALL,
+ true);
+#endif
+ if (unlikely(attrs->status != LISTMP_CREATED)) {
+ *listmp_handleptr = NULL;
+ status = -ENOENT;
+ } else {
+ key = mutex_lock_interruptible(
+ listmp_module->local_lock);
+ status = _listmp_create((struct listmp_object **)
+ listmp_handleptr, &params,
+ (u32) false);
+ mutex_unlock(listmp_module->local_lock);
+ }
+ }
+
+exit:
+ if (status < 0)
+ pr_err("listmp_open failed! status = 0x%x\n", status);
+ return status;
+}
+
+/* Function to close a previously opened instance */
+int listmp_close(void **listmp_handleptr)
+{
+ int status = 0;
+ struct listmp_object *obj = NULL;
+ struct listmp_params *params = NULL;
+ u32 key;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(listmp_handleptr == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(*listmp_handleptr == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct listmp_object *)(*listmp_handleptr);
+ params = (struct listmp_params *)&obj->params;
+
+ key = mutex_lock_interruptible(listmp_module->local_lock);
+ if (unlikely(obj->owner.proc_id == multiproc_self()))
+ (obj)->owner.open_count--;
+
+ /* Check if ListMP is opened on same processor*/
+ if (likely((((struct listmp_object *)obj)->owner.creator == false))) {
+ list_del(&obj->list_elem);
+ /* remove from the name server */
+ if (params->name != NULL)
+ /* Free memory for the name */
+ kfree(params->name);
+ gatemp_close(&obj->gatemp_handle);
+
+ kfree(obj);
+ obj = NULL;
+ *listmp_handleptr = NULL;
+ }
+
+ mutex_unlock(listmp_module->local_lock);
+
+exit:
+ if (status < 0)
+ pr_err("listmp_close failed! status = 0x%x\n", status);
+ return status;
+}
+
+/* Function to check if the shared memory list is empty */
+bool listmp_empty(void *listmp_handle)
+{
+ int status = 0;
+ bool is_empty = false;
+ struct listmp_object *obj = NULL;
+ int *key;
+ struct listmp_elem *shared_head;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(listmp_handle == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct listmp_object *)listmp_handle;
+ key = gatemp_enter(obj->gatemp_handle);
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)&(obj->attrs->head),
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+
+ /* true if list is empty */
+ shared_head = (struct listmp_elem *)(sharedregion_get_srptr(
+ (void *)&(obj->attrs->head), obj->region_id));
+ dsb();
+ if (obj->attrs->head.next == shared_head)
+ is_empty = true;
+
+ gatemp_leave(obj->gatemp_handle, key);
+
+exit:
+ return is_empty;
+}
+
+/* Retrieves the gatemp handle associated with the listmp instance. */
+void *listmp_get_gate(void *listmp_handle)
+{
+ struct listmp_object *obj = NULL;
+ void *gatemp_handle = NULL;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(listmp_handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct listmp_object *)listmp_handle;
+ gatemp_handle = obj->gatemp_handle;
+
+exit:
+ if (retval < 0)
+ pr_err("listmp_get_gate failed! status = 0x%x", retval);
+ return gatemp_handle;
+}
+
+/* Function to get head element from a shared memory list */
+void *listmp_get_head(void *listmp_handle)
+{
+ struct listmp_object *obj = NULL;
+ struct listmp_elem *elem = NULL;
+ struct listmp_elem *local_head_next = NULL;
+ struct listmp_elem *local_next = NULL;
+ s32 retval = 0;
+ int *key = NULL;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(listmp_handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct listmp_object *)listmp_handle;
+ key = gatemp_enter(obj->gatemp_handle);
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)&(obj->attrs->head),
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+
+ local_head_next = sharedregion_get_ptr((u32 *)obj->attrs->head.next);
+ WARN_ON(local_head_next == NULL);
+ dsb();
+ /* See if the listmp_object was empty */
+ if (local_head_next != (struct listmp_elem *)&obj->attrs->head) {
+ /* Elem to return */
+ elem = local_head_next;
+ dsb();
+ if (WARN_ON(elem == NULL)) {
+ retval = -EFAULT;
+ goto gate_leave_and_exit;
+ }
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)local_head_next,
+ sizeof(struct listmp_elem), Cache_Type_ALL,
+ true);
+ }
+#endif
+ local_next = sharedregion_get_ptr((u32 *)elem->next);
+ if (WARN_ON(local_next == NULL)) {
+ retval = -EFAULT;
+ goto gate_leave_and_exit;
+ }
+
+ /* Fix the head of the list next pointer */
+ obj->attrs->head.next = elem->next;
+ dsb();
+ /* Fix the prev pointer of the new first elem on the list */
+ local_next->prev = local_head_next->prev;
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)&(obj->attrs->head),
+ sizeof(struct listmp_elem), Cache_Type_ALL,
+ true);
+ Cache_inv((void *)local_next,
+ sizeof(struct listmp_elem), Cache_Type_ALL,
+ true);
+ }
+#endif
+ }
+
+gate_leave_and_exit:
+ gatemp_leave(obj->gatemp_handle, key);
+
+exit:
+ if (retval < 0)
+ pr_err("listmp_get_head failed! status = 0x%x", retval);
+
+ return elem;
+}
+
+/* Function to get tail element from a shared memory list */
+void *listmp_get_tail(void *listmp_handle)
+{
+ struct listmp_object *obj = NULL;
+ struct listmp_elem *elem = NULL;
+ int *key;
+ struct listmp_elem *local_head_prev = NULL;
+ struct listmp_elem *local_prev = NULL;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(listmp_module->ns_handle == NULL)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(listmp_handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct listmp_object *)listmp_handle;
+ key = gatemp_enter(obj->gatemp_handle);
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)&(obj->attrs->head),
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+
+ local_head_prev = sharedregion_get_ptr((u32 *)obj->attrs->head.prev);
+ WARN_ON(local_head_prev == NULL);
+
+ /* See if the listmp_object was empty */
+ if (local_head_prev != (struct listmp_elem *)&obj->attrs->head) {
+ /* Elem to return */
+ elem = local_head_prev;
+ if (WARN_ON(elem == NULL)) {
+ retval = -EFAULT;
+ goto gate_leave_and_exit;
+ }
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)local_head_prev,
+ sizeof(struct listmp_elem), Cache_Type_ALL,
+ true);
+ }
+#endif
+ local_prev = sharedregion_get_ptr((u32 *)elem->prev);
+ if (WARN_ON(local_prev == NULL)) {
+ retval = -EFAULT;
+ goto gate_leave_and_exit;
+ }
+
+ /* Fix the head of the list prev pointer */
+ obj->attrs->head.prev = elem->prev;
+
+ /* Fix the next pointer of the new last elem on the list */
+ local_prev->next = local_head_prev->next;
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)&(obj->attrs->head),
+ sizeof(struct listmp_elem), Cache_Type_ALL,
+ true);
+ Cache_inv((void *)local_prev,
+ sizeof(struct listmp_elem), Cache_Type_ALL,
+ true);
+ }
+#endif
+ }
+
+gate_leave_and_exit:
+ gatemp_leave(obj->gatemp_handle, key);
+
+exit:
+ if (retval < 0)
+ pr_err("listmp_get_tail failed! status = 0x%x", retval);
+
+ return elem;
+}
+
+/* Function to put head element into a shared memory list */
+int listmp_put_head(void *listmp_handle, struct listmp_elem *elem)
+{
+ int status = 0;
+ struct listmp_object *obj = NULL;
+ struct listmp_elem *local_next_elem = NULL;
+ int *key;
+ struct listmp_elem *shared_elem = NULL;
+ u32 index;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(listmp_handle == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(elem == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct listmp_object *)listmp_handle;
+ dsb();
+ index = sharedregion_get_id(elem);
+ shared_elem = (struct listmp_elem *)sharedregion_get_srptr((void *)elem,
+ index);
+ WARN_ON((u32 *)shared_elem == SHAREDREGION_INVALIDSRPTR);
+ dsb();
+
+ key = gatemp_enter(obj->gatemp_handle);
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)&(obj->attrs->head),
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+ /* Add the new elem into the list */
+ elem->next = obj->attrs->head.next;
+ dsb();
+ local_next_elem = sharedregion_get_ptr((u32 *)elem->next);
+ if (WARN_ON(local_next_elem == NULL)) {
+ status = -EFAULT;
+ goto gate_leave_and_exit;
+ }
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)local_next_elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+ elem->prev = local_next_elem->prev;
+ local_next_elem->prev = shared_elem;
+ obj->attrs->head.next = shared_elem;
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ /* Need to do cache operations */
+ Cache_inv((void *)local_next_elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ Cache_inv((void *)&(obj->attrs->head),
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ /* writeback invalidate only the elem structure */
+ Cache_inv((void *)elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+
+gate_leave_and_exit:
+ gatemp_leave(obj->gatemp_handle, key);
+
+exit:
+ if (status < 0)
+ pr_err("listmp_put_head failed! status = 0x%x\n", status);
+ return status;
+}
+
+/* Function to put tail element into a shared memory list */
+int listmp_put_tail(void *listmp_handle, struct listmp_elem *elem)
+{
+ int status = 0;
+ struct listmp_object *obj = NULL;
+ int *key;
+ struct listmp_elem *local_prev_elem = NULL;
+ struct listmp_elem *shared_elem = NULL;
+ u32 index;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(listmp_handle == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(elem == NULL)) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct listmp_object *)listmp_handle;
+ dsb();
+ /* Safe to do outside the gate */
+ index = sharedregion_get_id(elem);
+ shared_elem = (struct listmp_elem *)sharedregion_get_srptr((void *)elem,
+ index);
+ WARN_ON((u32 *)shared_elem == SHAREDREGION_INVALIDSRPTR);
+ dsb();
+
+ key = gatemp_enter(obj->gatemp_handle);
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)&(obj->attrs->head),
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+ if (WARN_ON(obj->attrs == NULL)) {
+ status = -EFAULT;
+ goto gate_leave_and_exit;
+ }
+
+ elem->prev = obj->attrs->head.prev;
+ dsb();
+ local_prev_elem = sharedregion_get_ptr((u32 *)elem->prev);
+ if (WARN_ON(local_prev_elem == NULL)) {
+ status = -EFAULT;
+ goto gate_leave_and_exit;
+ }
+ dsb();
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)local_next_elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+ /* Add the new elem into the list */
+ elem->next = local_prev_elem->next;
+ local_prev_elem->next = shared_elem;
+ obj->attrs->head.prev = shared_elem;
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ /* Need to do cache operations */
+ Cache_inv((void *)local_prev_elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ Cache_inv((void *)&(obj->attrs->head),
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ /* writeback invalidate only the elem structure */
+ Cache_inv((void *)elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+
+gate_leave_and_exit:
+ gatemp_leave(obj->gatemp_handle, key);
+
+exit:
+ if (status < 0)
+ pr_err("listmp_put_tail failed! status = 0x%x\n", status);
+ return status;
+}
+
+/* Function to insert an element into a shared memory list */
+int listmp_insert(void *listmp_handle, struct listmp_elem *new_elem,
+ struct listmp_elem *cur_elem)
+{
+ int status = 0;
+ struct listmp_object *obj = NULL;
+ struct listmp_elem *local_prev_elem = NULL;
+ int *key;
+ struct listmp_elem *shared_new_elem = NULL;
+ struct listmp_elem *shared_cur_elem = NULL;
+ u32 index;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(new_elem == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(cur_elem == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct listmp_object *)listmp_handle;
+ dsb();
+ /* Get SRPtr for new_elem */
+ index = sharedregion_get_id(new_elem);
+ shared_new_elem = (struct listmp_elem *)
+ sharedregion_get_srptr((void *)new_elem, index);
+ WARN_ON((u32 *)shared_new_elem == SHAREDREGION_INVALIDSRPTR);
+ dsb();
+ /* Get SRPtr for cur_elem */
+ index = sharedregion_get_id(cur_elem);
+ shared_cur_elem = (struct listmp_elem *)
+ sharedregion_get_srptr((void *)cur_elem, index);
+ WARN_ON((u32 *)shared_cur_elem == SHAREDREGION_INVALIDSRPTR);
+ dsb();
+
+ key = gatemp_enter(obj->gatemp_handle);
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)cur_elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+ local_prev_elem = sharedregion_get_ptr((u32 *)cur_elem->prev);
+ if (WARN_ON(local_prev_elem == NULL)) {
+ status = -EFAULT;
+ goto gate_leave_and_exit;
+ }
+ dsb();
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)local_prev_elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+ new_elem->next = shared_cur_elem;
+ new_elem->prev = cur_elem->prev;
+ local_prev_elem->next = shared_new_elem;
+ cur_elem->prev = shared_new_elem;
+ dsb();
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ /* Need to do cache operations */
+ Cache_inv((void *)local_prev_elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ Cache_inv((void *)cur_elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ /* writeback invalidate only the elem structure */
+ Cache_inv((void *)new_elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+
+gate_leave_and_exit:
+ gatemp_leave(obj->gatemp_handle, key);
+
+exit:
+ if (status < 0)
+ pr_err("listmp_insert failed! status = 0x%x\n", status);
+ return status;
+}
+
+/* Function to remove a element from a shared memory list */
+int listmp_remove(void *listmp_handle, struct listmp_elem *elem)
+{
+ int status = 0;
+ struct listmp_object *obj = NULL;
+ struct listmp_elem *local_prev_elem = NULL;
+ struct listmp_elem *local_next_elem = NULL;
+ int *key;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(elem == NULL)) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct listmp_object *)listmp_handle;
+
+ key = gatemp_enter(obj->gatemp_handle);
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+ local_prev_elem = sharedregion_get_ptr((u32 *)elem->prev);
+ local_next_elem = sharedregion_get_ptr((u32 *)elem->next);
+ dsb();
+ if (WARN_ON((local_next_elem == NULL) || (local_prev_elem == NULL))) {
+ status = -EFAULT;
+ goto gate_leave_and_exit;
+ }
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ /* Need to do cache operations */
+ Cache_inv((void *)local_prev_elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ Cache_inv((void *)local_next_elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+ local_prev_elem->next = elem->next;
+ local_next_elem->prev = elem->prev;
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ /* Need to do cache operations */
+ Cache_inv((void *)local_prev_elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ Cache_inv((void *)local_next_elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+
+gate_leave_and_exit:
+ gatemp_leave(obj->gatemp_handle, key);
+
+exit:
+ if (status < 0)
+ pr_err("listmp_remove failed! status = 0x%x\n", status);
+ return status;
+}
+
+/* Function to traverse to next element in shared memory list */
+void *listmp_next(void *listmp_handle, struct listmp_elem *elem)
+{
+ int status = 0;
+ struct listmp_object *obj = NULL;
+ struct listmp_elem *ret_elem = NULL;
+ int *key;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ obj = (struct listmp_object *)listmp_handle;
+
+ key = gatemp_enter(obj->gatemp_handle);
+ /* If element is NULL start at head */
+ if (elem == NULL)
+ elem = (struct listmp_elem *)&obj->attrs->head;
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+ ret_elem = sharedregion_get_ptr((u32 *)elem->next);
+ WARN_ON(ret_elem == NULL);
+ /* NULL if list is empty */
+ if (ret_elem == (struct listmp_elem *)&obj->attrs->head)
+ ret_elem = NULL;
+ gatemp_leave(obj->gatemp_handle, key);
+
+exit:
+ if (status < 0)
+ pr_err("listmp_next failed! status = 0x%x\n", status);
+ return ret_elem;
+}
+
+/* Function to traverse to prev element in shared memory list */
+void *listmp_prev(void *listmp_handle, struct listmp_elem *elem)
+{
+ int status = 0;
+ struct listmp_object *obj = NULL;
+ struct listmp_elem *ret_elem = NULL;
+ int *key;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(listmp_module->ref_count),
+ LISTMP_MAKE_MAGICSTAMP(0),
+ LISTMP_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ obj = (struct listmp_object *)listmp_handle;
+
+ key = gatemp_enter(obj->gatemp_handle);
+ /* If element is NULL start at head */
+ if (elem == NULL)
+ elem = (struct listmp_elem *)&obj->attrs->head;
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+ ret_elem = sharedregion_get_ptr((u32 *)elem->prev);
+ WARN_ON(ret_elem == NULL);
+ /* NULL if list is empty */
+ if (ret_elem == (struct listmp_elem *)&obj->attrs->head)
+ ret_elem = NULL;
+ gatemp_leave(obj->gatemp_handle, key);
+
+exit:
+ if (status < 0)
+ pr_err("listmp_prev failed! status = 0x%x\n", status);
+ return ret_elem;
+}
+
+/* Function to return the amount of shared memory required for creation of
+ * each instance. */
+uint listmp_shared_mem_req(const struct listmp_params *params)
+{
+ int retval = 0;
+ uint mem_req = 0;
+ uint min_align;
+ u16 region_id;
+
+ if (WARN_ON(unlikely(params == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (params->shared_addr == NULL)
+ region_id = params->region_id;
+ else
+ region_id = sharedregion_get_id(params->shared_addr);
+ WARN_ON(region_id == SHAREDREGION_INVALIDREGIONID);
+
+ /*min_align = Memory_getMaxDefaultTypeAlign();*/min_align = 4;
+ if (sharedregion_get_cache_line_size(region_id) > min_align)
+ min_align = sharedregion_get_cache_line_size(region_id);
+
+ mem_req = ROUND_UP(sizeof(struct listmp_attrs), min_align);
+
+exit:
+ if (retval < 0) {
+ pr_err("listmp_shared_mem_req failed! status = 0x%x\n",
+ retval);
+ }
+ return mem_req;
+}
+
+/* Clears a listmp element's pointers */
+static void _listmp_elem_clear(struct listmp_elem *elem)
+{
+ u32 *shared_elem;
+ int id;
+
+ WARN_ON(elem == NULL);
+
+ id = sharedregion_get_id(elem);
+ shared_elem = sharedregion_get_srptr(elem, id);
+ elem->next = elem->prev = (struct listmp_elem *)shared_elem;
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)elem,
+ sizeof(struct listmp_elem), Cache_Type_ALL, true);
+ }
+#endif
+}
+
+/* Creates a new instance of listmp module. This is an internal
+ * function because both listmp_create and
+ * listmp_open call use the same functionality. */
+static int _listmp_create(struct listmp_object **handle_ptr,
+ struct listmp_params *params, u32 create_flag)
+{
+ int status = 0;
+ struct listmp_object *obj = NULL;
+ void *local_addr = NULL;
+ u32 *shared_shm_base;
+ struct listmp_params sparams;
+ u16 name_len;
+
+ if (WARN_ON(unlikely(handle_ptr == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(params == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* Allow local lock not being provided. Don't do protection if local
+ * lock is not provided.
+ */
+ /* Create the handle */
+ obj = kzalloc(sizeof(struct listmp_object), GFP_KERNEL);
+ *handle_ptr = obj;
+ if (obj == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ /* Populate the params member */
+ memcpy((void *)&obj->params, (void *)params,
+ sizeof(struct listmp_params));
+
+ if (create_flag == false) {
+ /* Update attrs */
+ obj->attrs = (struct listmp_attrs *)params->shared_addr;
+ obj->region_id = sharedregion_get_id((void *)&obj->attrs->head);
+ obj->cache_enabled = sharedregion_is_cache_enabled(
+ obj->region_id);
+ /* get the local address of the SRPtr */
+ local_addr = sharedregion_get_ptr(obj->attrs->gatemp_addr);
+ status = gatemp_open_by_addr(local_addr, &(obj->gatemp_handle));
+ if (status < 0)
+ goto error;
+ } else {
+ INIT_LIST_HEAD(&obj->list_elem);
+
+ /* init the gate */
+ if (params->gatemp_handle != NULL)
+ obj->gatemp_handle = params->gatemp_handle;
+ else
+ obj->gatemp_handle = gatemp_get_default_remote();
+ if (obj->gatemp_handle == NULL)
+ goto error;
+
+ if (params->shared_addr == NULL) {
+ obj->region_id = params->region_id;
+ obj->cache_enabled = sharedregion_is_cache_enabled(
+ obj->region_id);
+
+ listmp_params_init(&sparams);
+ sparams.region_id = params->region_id;
+ obj->alloc_size = listmp_shared_mem_req(&sparams);
+
+ /* HeapMemMP will do the alignment * */
+ obj->attrs = sl_heap_alloc(
+ sharedregion_get_heap(obj->region_id),
+ obj->alloc_size,
+ 0);
+ if (obj->attrs == NULL) {
+ status = -ENOMEM;
+ goto error;
+ }
+ } else {
+ obj->region_id = sharedregion_get_id(
+ params->shared_addr);
+ if (unlikely(obj->region_id == \
+ SHAREDREGION_INVALIDREGIONID)) {
+ status = -1;
+ goto error;
+ }
+ if (((u32) params->shared_addr % \
+ sharedregion_get_cache_line_size(
+ obj->region_id)) != 0) {
+ status = -EFAULT;
+ goto error;
+ }
+
+ obj->cache_enabled = sharedregion_is_cache_enabled(
+ obj->region_id);
+ obj->attrs = (struct listmp_attrs *)params->shared_addr;
+ }
+
+ _listmp_elem_clear((struct listmp_elem *)&obj->attrs->head);
+ obj->attrs->gatemp_addr = gatemp_get_shared_addr(
+ obj->gatemp_handle);
+#if 0
+ if (unlikely(obj->cache_enabled)) {
+ Cache_inv((void *)obj->attrs,
+ sizeof(struct listmp_attrs), Cache_Type_ALL,
+ true);
+ }
+#endif
+ if (params->name != NULL) {
+ name_len = strlen(params->name) + 1;
+ /* Copy the name */
+ obj->params.name = kmalloc(name_len, GFP_KERNEL);
+ if (obj->params.name == NULL) {
+ /* NULL if Memory allocation failed for
+ name */
+ status = -ENOMEM;
+ goto error;
+ }
+ strncpy(obj->params.name, params->name, name_len);
+ shared_shm_base = sharedregion_get_srptr((void *)
+ obj->attrs, obj->region_id);
+ WARN_ON(shared_shm_base == SHAREDREGION_INVALIDSRPTR);
+
+ /* Add list instance to name server */
+ obj->ns_key = nameserver_add_uint32(
+ listmp_module->ns_handle, params->name,
+ (u32)shared_shm_base);
+ if (unlikely(obj->ns_key == NULL)) {
+ status = -EFAULT;
+ goto error;
+ }
+ }
+ obj->attrs->status = LISTMP_CREATED;
+ }
+
+ /* Update owner and opener details */
+ if (create_flag == true) {
+ obj->owner.creator = true;
+ obj->owner.open_count = 1;
+ obj->owner.proc_id = multiproc_self();
+ } else {
+ obj->owner.creator = false;
+ obj->owner.open_count = 0;
+ obj->owner.proc_id = MULTIPROC_INVALIDID;
+ }
+ obj->top = obj;
+
+ /* Put in the module list */
+ /* Function is called already with mutex acquired. So, no need to lock
+ * here */
+ INIT_LIST_HEAD(&obj->list_elem);
+ list_add_tail((&obj->list_elem), &listmp_module->obj_list);
+ return 0;
+
+error:
+ if (status < 0) {
+ if (create_flag == true) {
+ if (obj->params.name != NULL) {
+ if (obj->ns_key != NULL) {
+ nameserver_remove_entry(
+ listmp_module->ns_handle,
+ obj->ns_key);
+ }
+ kfree(obj->params.name);
+ }
+ if (params->shared_addr == NULL) {
+ if (obj->attrs != NULL) {
+ sl_heap_free(sharedregion_get_heap(
+ obj->region_id),
+ (void *)obj->attrs,
+ obj->alloc_size);
+ }
+ }
+ }
+ kfree(obj);
+ obj = NULL;
+ }
+
+exit:
+ if (status < 0)
+ pr_err("_listmp_create failed! status = 0x%x\n", status);
+ return status;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/listmp_ioctl.c b/drivers/dsp/syslink/multicore_ipc/listmp_ioctl.c
new file mode 100644
index 00000000000..d3d266987af
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/listmp_ioctl.c
@@ -0,0 +1,657 @@
+/*
+ * listmp_ioctl.c
+ *
+ * This file implements all the ioctl operations required on the
+ * listmp module.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+/* Standard headers */
+#include <linux/types.h>
+
+/* Linux headers */
+#include <linux/uaccess.h>
+#include <linux/bug.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+/* Module Headers */
+#include <ipc.h>
+#include <listmp.h>
+#include <_listmp.h>
+#include <listmp_ioctl.h>
+#include <sharedregion.h>
+
+static struct resource_info *find_listmp_resource(
+ struct ipc_process_context *pr_ctxt,
+ unsigned int cmd,
+ struct listmp_cmd_args *cargs)
+{
+ struct resource_info *info = NULL;
+ bool found = false;
+
+ spin_lock(&pr_ctxt->res_lock);
+
+ list_for_each_entry(info, &pr_ctxt->resources, res) {
+ struct listmp_cmd_args *args =
+ (struct listmp_cmd_args *)info->data;
+ void *handle = NULL;
+ void *thandle = NULL;
+ if (cargs != NULL && args != NULL) {
+ handle = args->args.delete_instance.listmp_handle;
+ thandle = cargs->args.delete_instance.listmp_handle;
+ }
+ if (info->cmd == cmd) {
+ switch (cmd) {
+ case CMD_LISTMP_DELETE:
+ {
+ if (thandle == handle)
+ found = true;
+ break;
+ }
+ case CMD_LISTMP_DESTROY:
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found == true)
+ break;
+ }
+ }
+
+ spin_unlock(&pr_ctxt->res_lock);
+
+ if (found == false)
+ info = NULL;
+
+ return info;
+}
+
+/* ioctl interface to listmp_get_config function */
+static inline int listmp_ioctl_get_config(struct listmp_cmd_args *cargs)
+{
+ s32 retval = 0;
+ unsigned long size;
+ struct listmp_config config;
+
+ listmp_get_config(&config);
+ size = copy_to_user((void __user *)cargs->args.get_config.config,
+ &config, sizeof(struct listmp_config));
+ if (size) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ cargs->api_status = 0;
+exit:
+ return retval;
+}
+
+/* ioctl interface to listmp_setup function */
+static inline int listmp_ioctl_setup(struct listmp_cmd_args *cargs)
+{
+ s32 retval = 0;
+ unsigned long size;
+ struct listmp_config config;
+
+ size = copy_from_user(&config, (void __user *)cargs->args.setup.config,
+ sizeof(struct listmp_config));
+ if (size) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ cargs->api_status = listmp_setup(&config);
+
+exit:
+ return retval;
+}
+
+/* ioctl interface to listmp_destroy function */
+static inline int listmp_ioctl_destroy(struct listmp_cmd_args *cargs)
+{
+ cargs->api_status = listmp_destroy();
+ return 0;
+}
+
+/* ioctl interface to listmp_params_init function */
+static inline int listmp_ioctl_params_init(struct listmp_cmd_args *cargs)
+{
+ s32 retval = 0;
+ unsigned long size;
+ struct listmp_params params;
+
+ size = copy_from_user(&params,
+ (void __user *)cargs->args.params_init.params,
+ sizeof(struct listmp_params));
+ if (size) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ listmp_params_init(&params);
+ size = copy_to_user((void __user *)cargs->args.params_init.params,
+ &params, sizeof(struct listmp_params));
+ if (size) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ cargs->api_status = 0;
+
+exit:
+ return retval;
+}
+
+/* ioctl interface to listmp_create function */
+static inline int listmp_ioctl_create(struct listmp_cmd_args *cargs)
+{
+ s32 retval = 0;
+ unsigned long size;
+ struct listmp_params params;
+
+ size = copy_from_user(&params, (void __user *)cargs->args.create.params,
+ sizeof(struct listmp_params));
+ if (size) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ /* Allocate memory for the name */
+ if (cargs->args.create.name_len > 0) {
+ params.name = kmalloc(cargs->args.create.name_len, GFP_KERNEL);
+ if (params.name == NULL) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+ /* Copy the name */
+ size = copy_from_user(params.name,
+ (void __user *)cargs->args.create.params->name,
+ cargs->args.create.name_len);
+ if (size) {
+ retval = -EFAULT;
+ goto free_name;
+ }
+ }
+
+ params.shared_addr = sharedregion_get_ptr(
+ (u32 *)cargs->args.create.shared_addr_srptr);
+
+ /* Update gate in params. */
+ params.gatemp_handle = cargs->args.create.knl_gate;
+ cargs->args.create.listmp_handle = listmp_create(&params);
+
+ size = copy_to_user((void __user *)cargs->args.create.params, &params,
+ sizeof(struct listmp_params));
+ if (!size)
+ goto free_name;
+
+ /* Error copying, so delete the handle */
+ retval = -EFAULT;
+ if (cargs->args.create.listmp_handle)
+ listmp_delete(&cargs->args.create.listmp_handle);
+
+free_name:
+ if (cargs->args.create.name_len > 0)
+ kfree(params.name);
+
+ cargs->api_status = 0;
+exit:
+ return retval;
+}
+
+/* ioctl interface to listmp_delete function */
+static inline int listmp_ioctl_delete(struct listmp_cmd_args *cargs)
+{
+ cargs->api_status = listmp_delete(
+ &(cargs->args.delete_instance.listmp_handle));
+ return 0;
+}
+
+/* ioctl interface to listmp_open function */
+static inline int listmp_ioctl_open(struct listmp_cmd_args *cargs)
+{
+ s32 retval = 0;
+ unsigned long size;
+ char *name = NULL;
+ void *listmp_handle = NULL;
+
+ if (cargs->args.open.name_len > 0) {
+ name = kmalloc(cargs->args.open.name_len, GFP_KERNEL);
+ if (name == NULL) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+ /* Copy the name */
+ size = copy_from_user(name,
+ (void __user *)cargs->args.open.name,
+ cargs->args.open.name_len);
+ if (size) {
+ retval = -EFAULT;
+ goto free_name;
+ }
+ }
+
+ /* Update gate in params. */
+ cargs->api_status = listmp_open(name, &listmp_handle);
+ cargs->args.open.listmp_handle = listmp_handle;
+
+free_name:
+ if (cargs->args.open.name_len > 0)
+ kfree(name);
+exit:
+ return retval;
+}
+
+/* ioctl interface to listmp_open_by_addr function */
+static inline int listmp_ioctl_open_by_addr(struct listmp_cmd_args *cargs)
+{
+ s32 retval = 0;
+ void *listmp_handle = NULL;
+ void *shared_addr = NULL;
+
+ /* For open_by_addr, the shared_add_srptr may be invalid */
+ if (cargs->args.open_by_addr.shared_addr_srptr != \
+ (u32)SHAREDREGION_INVALIDSRPTR) {
+ shared_addr = sharedregion_get_ptr((u32 *)
+ cargs->args.open_by_addr.shared_addr_srptr);
+ }
+
+ /* Update gate in params. */
+ cargs->api_status = listmp_open_by_addr(shared_addr, &listmp_handle);
+ cargs->args.open_by_addr.listmp_handle = listmp_handle;
+
+ return retval;
+}
+
+/* ioctl interface to listmp_close function */
+static inline int listmp_ioctl_close(struct listmp_cmd_args *cargs)
+{
+ cargs->api_status = listmp_close(&cargs->args.close.listmp_handle);
+ return 0;
+}
+
+/* ioctl interface to listmp_empty function */
+static inline int listmp_ioctl_isempty(struct listmp_cmd_args *cargs)
+{
+ cargs->args.is_empty.is_empty = \
+ listmp_empty(cargs->args.is_empty.listmp_handle);
+ cargs->api_status = 0;
+ return 0;
+}
+
+/* ioctl interface to listmp_get_head function */
+static inline int listmp_ioctl_get_head(struct listmp_cmd_args *cargs)
+{
+ struct listmp_elem *elem;
+ u32 *elem_srptr = SHAREDREGION_INVALIDSRPTR;
+ int index;
+
+ cargs->api_status = LISTMP_E_FAIL;
+
+ elem = listmp_get_head(cargs->args.get_head.listmp_handle);
+ if (unlikely(elem == NULL))
+ goto exit;
+
+ index = sharedregion_get_id(elem);
+ if (unlikely(index < 0))
+ goto exit;
+
+ elem_srptr = sharedregion_get_srptr((void *)elem, index);
+ cargs->api_status = 0;
+
+exit:
+ cargs->args.get_head.elem_srptr = elem_srptr;
+ return 0;
+}
+
+/* ioctl interface to listmp_get_tail function */
+static inline int listmp_ioctl_get_tail(struct listmp_cmd_args *cargs)
+{
+ struct listmp_elem *elem;
+ u32 *elem_srptr = SHAREDREGION_INVALIDSRPTR;
+ int index;
+
+ cargs->api_status = LISTMP_E_FAIL;
+
+ elem = listmp_get_tail(cargs->args.get_tail.listmp_handle);
+ if (unlikely(elem == NULL))
+ goto exit;
+
+ index = sharedregion_get_id(elem);
+ if (unlikely(index < 0))
+ goto exit;
+
+ elem_srptr = sharedregion_get_srptr((void *)elem, index);
+ cargs->api_status = 0;
+
+exit:
+ cargs->args.get_tail.elem_srptr = elem_srptr;
+ return 0;
+}
+
+/* ioctl interface to listmp_put_head function */
+static inline int listmp_ioctl_put_head(struct listmp_cmd_args *cargs)
+{
+ struct listmp_elem *elem;
+
+ elem = (struct listmp_elem *) sharedregion_get_ptr(
+ cargs->args.put_head.elem_srptr);
+ cargs->api_status = listmp_put_head(
+ cargs->args.put_head.listmp_handle, elem);
+
+ return 0;
+}
+
+/* ioctl interface to listmp_put_tail function */
+static inline int listmp_ioctl_put_tail(struct listmp_cmd_args *cargs)
+{
+ struct listmp_elem *elem;
+
+ elem = (struct listmp_elem *) sharedregion_get_ptr(
+ cargs->args.put_tail.elem_srptr);
+ cargs->api_status = listmp_put_tail(
+ cargs->args.put_head.listmp_handle, elem);
+
+ return 0;
+}
+
+/* ioctl interface to listmp_insert function */
+static inline int listmp_ioctl_insert(struct listmp_cmd_args *cargs)
+{
+ struct listmp_elem *new_elem;
+ struct listmp_elem *cur_elem;
+ int status = -1;
+
+ new_elem = (struct listmp_elem *) sharedregion_get_ptr(
+ cargs->args.insert.new_elem_srptr);
+ if (unlikely(new_elem == NULL))
+ goto exit;
+
+ cur_elem = (struct listmp_elem *) sharedregion_get_ptr(
+ cargs->args.insert.cur_elem_srptr);
+ if (unlikely(cur_elem == NULL))
+ goto exit;
+
+ status = listmp_insert(cargs->args.insert.listmp_handle, new_elem,
+ cur_elem);
+exit:
+ cargs->api_status = status;
+ return 0;
+}
+
+/* ioctl interface to listmp_remove function */
+static inline int listmp_ioctl_remove(struct listmp_cmd_args *cargs)
+{
+ struct listmp_elem *elem;
+
+ elem = (struct listmp_elem *) sharedregion_get_ptr(
+ cargs->args.remove.elem_srptr);
+ cargs->api_status = listmp_remove(
+ cargs->args.get_head.listmp_handle, elem);
+
+ return 0;
+}
+
+/* ioctl interface to listmp_next function */
+static inline int listmp_ioctl_next(struct listmp_cmd_args *cargs)
+{
+ struct listmp_elem *elem = NULL;
+ struct listmp_elem *ret_elem = NULL;
+ u32 *next_elem_srptr = SHAREDREGION_INVALIDSRPTR;
+ int index;
+
+ if (cargs->args.next.elem_srptr != NULL) {
+ elem = (struct listmp_elem *) sharedregion_get_ptr(
+ cargs->args.next.elem_srptr);
+ }
+ ret_elem = (struct listmp_elem *) listmp_next(
+ cargs->args.next.listmp_handle, elem);
+ if (unlikely(ret_elem == NULL))
+ goto exit;
+
+ index = sharedregion_get_id(ret_elem);
+ if (unlikely(index < 0))
+ goto exit;
+
+ next_elem_srptr = sharedregion_get_srptr((void *)ret_elem, index);
+ cargs->api_status = 0;
+
+exit:
+ cargs->args.next.next_elem_srptr = next_elem_srptr;
+ return 0;
+}
+
+/* ioctl interface to listmp_prev function */
+static inline int listmp_ioctl_prev(struct listmp_cmd_args *cargs)
+{
+ struct listmp_elem *elem = NULL;
+ struct listmp_elem *ret_elem = NULL;
+ u32 *prev_elem_srptr = SHAREDREGION_INVALIDSRPTR;
+ int index;
+
+ if (cargs->args.next.elem_srptr != NULL) {
+ elem = (struct listmp_elem *) sharedregion_get_ptr(
+ cargs->args.prev.elem_srptr);
+ }
+ ret_elem = (struct listmp_elem *) listmp_prev(
+ cargs->args.prev.listmp_handle, elem);
+ if (unlikely(ret_elem == NULL))
+ goto exit;
+
+ index = sharedregion_get_id(ret_elem);
+ if (unlikely(index < 0))
+ goto exit;
+
+ prev_elem_srptr = sharedregion_get_srptr((void *)ret_elem, index);
+ cargs->api_status = 0;
+
+exit:
+ cargs->args.prev.prev_elem_srptr = prev_elem_srptr;
+ return 0;
+
+}
+
+/* ioctl interface to listmp_shared_mem_req function */
+static inline int listmp_ioctl_shared_mem_req(struct listmp_cmd_args *cargs)
+{
+ s32 retval = 0;
+ unsigned long size;
+ struct listmp_params params;
+
+ size = copy_from_user(&params,
+ (void __user *)cargs->args.shared_mem_req.params,
+ sizeof(struct listmp_params));
+ if (size) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ params.shared_addr = sharedregion_get_ptr(
+ cargs->args.shared_mem_req.shared_addr_srptr);
+ cargs->args.shared_mem_req.bytes = listmp_shared_mem_req(&params);
+ cargs->api_status = 0;
+
+exit:
+ return retval;
+}
+
+/* ioctl interface function for listmp module */
+int listmp_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user)
+{
+ int status = 0;
+ struct listmp_cmd_args __user *uarg =
+ (struct listmp_cmd_args __user *)args;
+ struct listmp_cmd_args cargs;
+ unsigned long size;
+ struct ipc_process_context *pr_ctxt =
+ (struct ipc_process_context *)filp->private_data;
+
+ if (user == true) {
+#ifdef CONFIG_SYSLINK_RECOVERY
+ if (ipc_recovering()) {
+ status = -EIO;
+ goto exit;
+ }
+#endif
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ status = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ status = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
+ if (status) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ /* Copy the full args from user-side */
+ size = copy_from_user(&cargs, uarg,
+ sizeof(struct listmp_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ } else {
+ if (args != 0)
+ memcpy(&cargs, (void *)args,
+ sizeof(struct listmp_cmd_args));
+ }
+
+ switch (cmd) {
+ case CMD_LISTMP_GETCONFIG:
+ status = listmp_ioctl_get_config(&cargs);
+ break;
+
+ case CMD_LISTMP_SETUP:
+ status = listmp_ioctl_setup(&cargs);
+ if (status >= 0)
+ add_pr_res(pr_ctxt, CMD_LISTMP_DESTROY, NULL);
+ break;
+
+ case CMD_LISTMP_DESTROY:
+ {
+ struct resource_info *info = NULL;
+ info = find_listmp_resource(pr_ctxt, CMD_LISTMP_DESTROY,
+ &cargs);
+ status = listmp_ioctl_destroy(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_LISTMP_PARAMS_INIT:
+ status = listmp_ioctl_params_init(&cargs);
+ break;
+
+ case CMD_LISTMP_CREATE:
+ status = listmp_ioctl_create(&cargs);
+ if (status >= 0) {
+ struct listmp_cmd_args *temp = kmalloc(
+ sizeof(struct listmp_cmd_args),
+ GFP_KERNEL);
+ if (WARN_ON(!temp)) {
+ status = -ENOMEM;
+ goto exit;
+ }
+ temp->args.delete_instance.listmp_handle =
+ cargs.args.create.listmp_handle;
+ add_pr_res(pr_ctxt, CMD_LISTMP_DELETE, (void *)temp);
+ }
+ break;
+
+ case CMD_LISTMP_DELETE:
+ {
+ struct resource_info *info = NULL;
+ info = find_listmp_resource(pr_ctxt, CMD_LISTMP_DELETE,
+ &cargs);
+ status = listmp_ioctl_delete(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_LISTMP_OPEN:
+ status = listmp_ioctl_open(&cargs);
+ break;
+
+ case CMD_LISTMP_CLOSE:
+ status = listmp_ioctl_close(&cargs);
+ break;
+
+ case CMD_LISTMP_ISEMPTY:
+ status = listmp_ioctl_isempty(&cargs);
+ break;
+
+ case CMD_LISTMP_GETHEAD:
+ status = listmp_ioctl_get_head(&cargs);
+ break;
+
+ case CMD_LISTMP_GETTAIL:
+ status = listmp_ioctl_get_tail(&cargs);
+ break;
+
+ case CMD_LISTMP_PUTHEAD:
+ status = listmp_ioctl_put_head(&cargs);
+ break;
+
+ case CMD_LISTMP_PUTTAIL:
+ status = listmp_ioctl_put_tail(&cargs);
+ break;
+
+ case CMD_LISTMP_INSERT:
+ status = listmp_ioctl_insert(&cargs);
+ break;
+
+ case CMD_LISTMP_REMOVE:
+ status = listmp_ioctl_remove(&cargs);
+ break;
+
+ case CMD_LISTMP_NEXT:
+ status = listmp_ioctl_next(&cargs);
+ break;
+
+ case CMD_LISTMP_PREV:
+ status = listmp_ioctl_prev(&cargs);
+ break;
+
+ case CMD_LISTMP_SHAREDMEMREQ:
+ status = listmp_ioctl_shared_mem_req(&cargs);
+ break;
+
+ case CMD_LISTMP_OPENBYADDR:
+ status = listmp_ioctl_open_by_addr(&cargs);
+ break;
+
+ default:
+ WARN_ON(cmd);
+ status = -ENOTTY;
+ break;
+ }
+ if (status < 0)
+ goto exit;
+
+ if (user == true) {
+ /* Copy the full args to the user-side. */
+ size = copy_to_user(uarg, &cargs,
+ sizeof(struct listmp_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ }
+ return status;
+
+exit:
+ pr_err("listmp_ioctl failed: status = 0x%x\n", status);
+ return status;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/messageq.c b/drivers/dsp/syslink/multicore_ipc/messageq.c
new file mode 100644
index 00000000000..83f3d8e7d8e
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/messageq.c
@@ -0,0 +1,1643 @@
+/*
+ * messageq.c
+ *
+ * The messageQ module supports the structured sending and receiving of
+ * variable length messages. This module can be used for homogeneous or
+ * heterogeneous multi-processor messaging.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+/*!
+ * MessageQ provides more sophisticated messaging than other modules. It is
+ * typically used for complex situations such as multi-processor messaging.
+ *
+ * The following are key features of the MessageQ module:
+ * -Writers and readers can be relocated to another processor with no
+ * runtime code changes.
+ * -Timeouts are allowed when receiving messages.
+ * -Readers can determine the writer and reply back.
+ * -Receiving a message is deterministic when the timeout is zero.
+ * -Messages can reside on any message queue.
+ * -Supports zero-copy transfers.
+ * -Can send and receive from any type of thread.
+ * -Notification mechanism is specified by application.
+ * -Allows QoS (quality of service) on message buffer pools. For example,
+ * using specific buffer pools for specific message queues.
+ *
+ * Messages are sent and received via a message queue. A reader is a thread
+ * that gets (reads) messages from a message queue. A writer is a thread that
+ * puts (writes) a message to a message queue. Each message queue has one
+ * reader and can have many writers. A thread may read from or write to
+ * multiple message queues.
+ *
+ * Conceptually, the reader thread owns a message queue. The reader thread
+ * creates a message queue. Writer threads a created message queues to
+ * get access to them.
+ *
+ * Message queues are identified by a system-wide unique name. Internally,
+ * MessageQ uses the NameServer module for managing
+ * these names. The names are used for opening a message queue. Using
+ * names is not required.
+ *
+ * Messages must be allocated from the MessageQ module. Once a message is
+ * allocated, it can be sent on any message queue. Once a message is sent, the
+ * writer loses ownership of the message and should not attempt to modify the
+ * message. Once the reader receives the message, it owns the message. It
+ * may either free the message or re-use the message.
+ *
+ * Messages in a message queue can be of variable length. The only
+ * requirement is that the first field in the definition of a message must be a
+ * MsgHeader structure. For example:
+ * typedef struct MyMsg {
+ * messageq_MsgHeader header;
+ * ...
+ * } MyMsg;
+ *
+ * The MessageQ API uses the messageq_MsgHeader internally. Your application
+ * should not modify or directly access the fields in the messageq_MsgHeader.
+ *
+ * All messages sent via the MessageQ module must be allocated from a
+ * Heap implementation. The heap can be used for
+ * other memory allocation not related to MessageQ.
+ *
+ * An application can use multiple heaps. The purpose of having multiple
+ * heaps is to allow an application to regulate its message usage. For
+ * example, an application can allocate critical messages from one heap of fast
+ * on-chip memory and non-critical messages from another heap of slower
+ * external memory
+ *
+ * MessageQ does support the usage of messages that allocated via the
+ * alloc function. Please refer to the static_msg_init
+ * function description for more details.
+ *
+ * In a multiple processor system, MessageQ communications to other
+ * processors via MessageQ_transport} instances. There must be one and
+ * only one IMessageQ_transport instance for each processor where communication
+ * is desired.
+ * So on a four processor system, each processor must have three
+ * IMessageQ_transport instance.
+ *
+ * The user only needs to create the IMessageQ_transport instances. The
+ * instances are responsible for registering themselves with MessageQ.
+ * This is accomplished via the register_transport function.
+ */
+
+
+
+/* Standard headers */
+#include <linux/types.h>
+#include <linux/module.h>
+
+/* Utilities headers */
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/semaphore.h>
+
+/* Syslink headers */
+#include <syslink/atomic_linux.h>
+
+/* Module level headers */
+#include <nameserver.h>
+#include <multiproc.h>
+#include <transportshm_setup_proxy.h>
+#include <heap.h>
+#include <messageq.h>
+#include <transportshm.h>
+
+
+/* Macro to make a correct module magic number with refCount */
+#define MESSAGEQ_MAKE_MAGICSTAMP(x) ((MESSAGEQ_MODULEID << 12u) | (x))
+
+/* =============================================================================
+ * Globals
+ * =============================================================================
+ */
+/*!
+ * @brief Name of the reserved NameServer used for MessageQ.
+ */
+#define MESSAGEQ_NAMESERVER "MessageQ"
+
+/*! Mask to extract priority setting */
+#define MESSAGEQ_TRANSPORTPRIORITYMASK 0x1
+
+/* =============================================================================
+ * Structures & Enums
+ * =============================================================================
+ */
+/* structure for MessageQ module state */
+struct messageq_module_object {
+ atomic_t ref_count;
+ /* Reference count */
+ void *ns_handle;
+ /* Handle to the local NameServer used for storing GP objects */
+ struct mutex *gate_handle;
+ /* Handle of gate to be used for local thread safety */
+ struct messageq_config cfg;
+ /* Current config values */
+ struct messageq_config default_cfg;
+ /* Default config values */
+ struct messageq_params default_inst_params;
+ /* Default instance creation parameters */
+ void *transports[MULTIPROC_MAXPROCESSORS][MESSAGEQ_NUM_PRIORITY_QUEUES];
+ /* Transport to be set in messageq_register_transport */
+ void **queues; /*messageq_handle *queues;*/
+ /* Grow option */
+ void **heaps; /*Heap_Handle *heaps; */
+ /* Heap to be set in messageq_registerHeap */
+ u16 num_queues;
+ /* Heap to be set in messageq_registerHeap */
+ u16 num_heaps;
+ /* Number of Heaps */
+ bool can_free_queues;
+ /* Grow option */
+ u16 seq_num;
+ /* sequence number */
+};
+
+/* Structure for the Handle for the MessageQ. */
+struct messageq_object {
+ struct messageq_params params;
+ /*! Instance specific creation parameters */
+ u32 queue;
+ /* Unique id */
+ struct list_head normal_list;
+ /* Embedded List objects */
+ struct list_head high_list;
+ /* Embedded List objects */
+ void *ns_key;
+ /* NameServer key */
+ struct semaphore *synchronizer;
+ /* Semaphore used for synchronizing message events */
+ bool unblocked;
+ /* Whether MessageQ is unblocked */
+};
+
+
+static struct messageq_module_object messageq_state = {
+ .ns_handle = NULL,
+ .gate_handle = NULL,
+ .queues = NULL,
+ .heaps = NULL,
+ .num_queues = 1,
+ .num_heaps = 1,
+ .can_free_queues = false,
+ .default_cfg.trace_flag = false,
+ .default_cfg.num_heaps = 1,
+ .default_cfg.max_runtime_entries = 32,
+ .default_cfg.max_name_len = 32,
+ .default_inst_params.synchronizer = NULL
+};
+
+/* Pointer to the MessageQ module state */
+static struct messageq_module_object *messageq_module = &messageq_state;
+
+/* =============================================================================
+ * Constants
+ * =============================================================================
+ */
+/* Used to denote a message that was initialized
+ * with the messageq_static_msg_init function. */
+#define MESSAGEQ_STATICMSG 0xFFFF
+
+
+/* =============================================================================
+ * Forward declarations of internal functions
+ * =============================================================================
+ */
+/* Grow the MessageQ table */
+static u16 _messageq_grow(struct messageq_object *obj);
+
+/* Initializes a message not obtained from MessageQ_alloc */
+static void messageq_msg_init(messageq_msg msg);
+
+/* =============================================================================
+ * APIS
+ * =============================================================================
+ */
+/*
+ * ======== messageq_get_config ========
+ * Purpose:
+ * Function to get the default configuration for the MessageQ
+ * module.
+ *
+ * This function can be called by the application to get their
+ * configuration parameter to MessageQ_setup filled in by the
+ * MessageQ module with the default parameters. If the user does
+ * not wish to make any change in the default parameters, this API
+ * is not required to be called.
+ * the listmp_sharedmemory module.
+ */
+void messageq_get_config(struct messageq_config *cfg)
+{
+ if (WARN_ON(unlikely(cfg == NULL)))
+ goto exit;
+
+ if (likely(atomic_cmpmask_and_lt(&(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true)) {
+ /* (If setup has not yet been called) */
+ memcpy(cfg, &messageq_module->default_cfg,
+ sizeof(struct messageq_config));
+ } else {
+ memcpy(cfg, &messageq_module->cfg,
+ sizeof(struct messageq_config));
+ }
+ return;
+
+exit:
+ pr_err("messageq_get_config: Argument of type "
+ "(struct messageq_config *) passed is null!\n");
+}
+EXPORT_SYMBOL(messageq_get_config);
+
+/*
+ * ======== messageq_setup ========
+ * Purpose:
+ * Function to setup the MessageQ module.
+ *
+ * This function sets up the MessageQ module. This function must
+ * be called before any other instance-level APIs can be invoked.
+ * Module-level configuration needs to be provided to this
+ * function. If the user wishes to change some specific config
+ * parameters, then MessageQ_getConfig can be called to get the
+ * configuration filled with the default values. After this, only
+ * the required configuration values can be changed. If the user
+ * does not wish to make any change in the default parameters, the
+ * application can simply call MessageQ with NULL parameters.
+ * The default parameters would get automatically used.
+ */
+int messageq_setup(const struct messageq_config *cfg)
+{
+ int status = 0;
+ struct nameserver_params params;
+ struct messageq_config tmpcfg;
+
+ /* This sets the ref_count variable is not initialized, upper 16 bits is
+ * written with module Id to ensure correctness of refCount variable.
+ */
+ atomic_cmpmask_and_set(&messageq_module->ref_count,
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(0));
+ if (unlikely(atomic_inc_return(&messageq_module->ref_count)
+ != MESSAGEQ_MAKE_MAGICSTAMP(1))) {
+ return 1;
+ }
+
+ if (unlikely(cfg == NULL)) {
+ messageq_get_config(&tmpcfg);
+ cfg = &tmpcfg;
+ }
+
+ if (WARN_ON(unlikely(cfg->max_name_len == 0))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(cfg->max_runtime_entries == 0))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* User has not provided any gate handle, so create a default
+ * handle for protecting list object */
+ messageq_module->gate_handle = kmalloc(sizeof(struct mutex),
+ GFP_KERNEL);
+ if (unlikely(messageq_module->gate_handle == NULL)) {
+ /*! @retval MESSAGEQ_E_FAIL Failed to create lock! */
+ status = MESSAGEQ_E_FAIL;
+ pr_err("messageq_setup: Failed to create a mutex.\n");
+ status = -ENOMEM;
+ goto exit;
+ }
+ mutex_init(messageq_module->gate_handle);
+
+ memcpy(&messageq_module->cfg, (void *) cfg,
+ sizeof(struct messageq_config));
+ /* Initialize the parameters */
+ nameserver_params_init(&params);
+ params.max_value_len = sizeof(u32);
+ params.max_name_len = cfg->max_name_len;
+ params.max_runtime_entries = cfg->max_runtime_entries;
+
+ messageq_module->seq_num = 0;
+
+ /* Create the nameserver for modules */
+ messageq_module->ns_handle = nameserver_create(MESSAGEQ_NAMESERVER,
+ &params);
+ if (unlikely(messageq_module->ns_handle == NULL)) {
+ /*! @retval MESSAGEQ_E_FAIL Failed to create the
+ * MessageQ nameserver*/
+ status = MESSAGEQ_E_FAIL;
+ pr_err("messageq_setup: Failed to create the messageq"
+ "nameserver!\n");
+ goto exit;
+ }
+
+ messageq_module->num_heaps = cfg->num_heaps;
+ messageq_module->heaps = kzalloc(sizeof(void *) * \
+ messageq_module->num_heaps, GFP_KERNEL);
+ if (unlikely(messageq_module->heaps == NULL)) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ messageq_module->num_queues = cfg->max_runtime_entries;
+ messageq_module->queues = kzalloc(sizeof(struct messageq_object *) * \
+ messageq_module->num_queues, GFP_KERNEL);
+ if (unlikely(messageq_module->queues == NULL)) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ memset(&(messageq_module->transports), 0, (sizeof(void *) * \
+ MULTIPROC_MAXPROCESSORS * \
+ MESSAGEQ_NUM_PRIORITY_QUEUES));
+ return status;
+
+exit:
+ if (status < 0) {
+ messageq_destroy();
+ pr_err("messageq_setup failed! status = 0x%x\n", status);
+ }
+ return status;
+}
+EXPORT_SYMBOL(messageq_setup);
+
+/* Function to destroy the MessageQ module. */
+int messageq_destroy(void)
+{
+ int status = 0;
+ int tmp_status = 0;
+ u32 i;
+
+ if (unlikely(atomic_cmpmask_and_lt(&(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true)) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ if (!(atomic_dec_return(&messageq_module->ref_count)
+ == MESSAGEQ_MAKE_MAGICSTAMP(0))) {
+ status = 1;
+ goto exit;
+ }
+
+ /* Temporarily increment the refcount */
+ atomic_set(&messageq_module->ref_count, MESSAGEQ_MAKE_MAGICSTAMP(1));
+
+ /* Delete any Message Queues that have not been deleted so far. */
+ for (i = 0; i < messageq_module->num_queues; i++) {
+ if (messageq_module->queues[i] != NULL) {
+ tmp_status = \
+ messageq_delete(&(messageq_module->queues[i]));
+ if (unlikely(tmp_status < 0 && status >= 0)) {
+ status = tmp_status;
+ pr_err("messageq_destroy: "
+ "messageq_delete failed for queue %d",
+ i);
+ }
+ }
+ }
+
+ if (likely(messageq_module->ns_handle != NULL)) {
+ /* Delete the nameserver for modules */
+ tmp_status = nameserver_delete(&messageq_module->ns_handle);
+ if (unlikely(tmp_status < 0 && status >= 0)) {
+ status = tmp_status;
+ pr_err("messageq_destroy: nameserver_delete failed");
+ }
+ }
+
+ /* Delete the gate if created internally */
+ if (likely(messageq_module->gate_handle != NULL)) {
+ kfree(messageq_module->gate_handle);
+ messageq_module->gate_handle = NULL;
+ }
+
+ memset(&(messageq_module->transports), 0, (sizeof(void *) * \
+ MULTIPROC_MAXPROCESSORS * MESSAGEQ_NUM_PRIORITY_QUEUES));
+ if (likely(messageq_module->heaps != NULL)) {
+ kfree(messageq_module->heaps);
+ messageq_module->heaps = NULL;
+ }
+ if (likely(messageq_module->queues != NULL)) {
+ kfree(messageq_module->queues);
+ messageq_module->queues = NULL;
+ }
+
+ memset(&messageq_module->cfg, 0, sizeof(struct messageq_config));
+ messageq_module->num_queues = 0;
+ messageq_module->num_heaps = 1;
+ messageq_module->can_free_queues = true;
+ atomic_set(&messageq_module->ref_count, MESSAGEQ_MAKE_MAGICSTAMP(0));
+
+exit:
+ if (status < 0)
+ pr_err("messageq_destroy failed! status = 0x%x\n", status);
+ return status;
+}
+EXPORT_SYMBOL(messageq_destroy);
+
+/* Initialize this config-params structure with supplier-specified
+ * defaults before instance creation. */
+void messageq_params_init(struct messageq_params *params)
+{
+ if (unlikely(atomic_cmpmask_and_lt(&(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))
+ goto exit;
+ if (WARN_ON(unlikely(params == NULL))) {
+ pr_err("messageq_params_init failed:Argument of "
+ "type(messageq_params *) is NULL!\n");
+ goto exit;
+ }
+
+ memcpy(params, &(messageq_module->default_inst_params),
+ sizeof(struct messageq_params));
+
+exit:
+ return;
+}
+EXPORT_SYMBOL(messageq_params_init);
+
+/* Creates a new instance of MessageQ module. */
+void *messageq_create(char *name, const struct messageq_params *params)
+{
+ int status = 0;
+ struct messageq_object *obj = NULL;
+ bool found = false;
+ u16 count = 0;
+ int i;
+ u16 start;
+ u16 queueIndex = 0;
+
+ if (unlikely(atomic_cmpmask_and_lt(&(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true)) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ /* Create the generic obj */
+ obj = kzalloc(sizeof(struct messageq_object), 0);
+ if (unlikely(obj == NULL)) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status)
+ goto exit;
+ start = 0; /* Statically allocated objects not supported */
+ count = messageq_module->num_queues;
+ /* Search the dynamic array for any holes */
+ for (i = start; i < count ; i++) {
+ if (messageq_module->queues[i] == NULL) {
+ messageq_module->queues[i] = (void *) obj;
+ queueIndex = i;
+ found = true;
+ break;
+ }
+ }
+ /*
+ * If no free slot was found:
+ * - if no growth allowed, raise an error
+ * - if growth is allowed, grow the array
+ */
+ if (unlikely(found == false)) {
+ /* Growth is always allowed */
+ queueIndex = _messageq_grow(obj);
+ if (unlikely(queueIndex == MESSAGEQ_INVALIDMESSAGEQ)) {
+ mutex_unlock(messageq_module->gate_handle);
+ status = MESSAGEQ_E_FAIL;
+ pr_err("messageq_create: Failed to grow the "
+ "queue array!");
+ goto exit;
+ }
+ }
+
+ if (params != NULL) {
+ /* Populate the params member */
+ memcpy((void *) &obj->params, (void *)params,
+ sizeof(struct messageq_params));
+ if (unlikely(params->synchronizer == NULL))
+ obj->synchronizer = \
+ kzalloc(sizeof(struct semaphore), GFP_KERNEL);
+ else
+ obj->synchronizer = params->synchronizer;
+ } else {
+ /*obj->synchronizer = OsalSemaphore_create(
+ OsalSemaphore_Type_Binary
+ | OsalSemaphore_IntType_Interruptible);*/
+ obj->synchronizer = kzalloc(sizeof(struct semaphore),
+ GFP_KERNEL);
+ }
+ if (unlikely(obj->synchronizer == NULL)) {
+ mutex_unlock(messageq_module->gate_handle);
+ status = MESSAGEQ_E_FAIL;
+ pr_err("messageq_create: Failed to create "
+ "synchronizer semaphore!\n");
+ goto exit;
+ } else {
+ sema_init(obj->synchronizer, 0);
+ }
+ mutex_unlock(messageq_module->gate_handle);
+
+ /* Construct the list object */
+ INIT_LIST_HEAD(&obj->normal_list);
+ INIT_LIST_HEAD(&obj->high_list);
+
+ /* Update processor information */
+ obj->queue = ((u32)(multiproc_self()) << 16) | queueIndex;
+ if (likely(name != NULL)) {
+ obj->ns_key = nameserver_add_uint32(messageq_module->ns_handle,
+ name, obj->queue);
+ if (unlikely(obj->ns_key == NULL)) {
+ status = MESSAGEQ_E_FAIL;
+ pr_err("messageq_create: Failed to add "
+ "the messageq name!\n");
+ }
+ }
+
+ /* Whether messageq is blocked */
+ obj->unblocked = false;
+
+exit:
+ if (unlikely(status < 0)) {
+ messageq_delete((void **)&obj);
+ pr_err("messageq_create failed! status = 0x%x\n", status);
+ }
+ return (void *) obj;
+}
+EXPORT_SYMBOL(messageq_create);
+
+/* Deletes a instance of MessageQ module. */
+int messageq_delete(void **msg_handleptr)
+{
+ int status = 0;
+ int tmp_status = 0;
+ struct messageq_object *obj = NULL;
+ messageq_msg temp_msg;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(msg_handleptr == NULL)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(*msg_handleptr == NULL)) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct messageq_object *) (*msg_handleptr);
+
+ /* Take the local lock */
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status)
+ goto exit;
+
+ if (unlikely(obj->ns_key != NULL)) {
+ /* remove from the name serve */
+ status = nameserver_remove_entry(messageq_module->ns_handle,
+ obj->ns_key);
+ if (unlikely(status < 0)) {
+ pr_err("messageq_delete: nameserver_remove_"
+ "entry failed! status = 0x%x", status);
+ }
+ }
+
+ /* Remove all the messages for the message queue's normal_list queue
+ * and free the list */
+ while (true) {
+ if (!list_empty(&obj->normal_list)) {
+ temp_msg = (messageq_msg) (obj->normal_list.next);
+ list_del_init(obj->normal_list.next);
+ } else
+ break;
+ tmp_status = messageq_free(temp_msg);
+ if (unlikely((tmp_status < 0) && (status >= 0))) {
+ status = tmp_status;
+ pr_err("messageq_delete: messageq_free failed"
+ " for normal_list!");
+ }
+ }
+ list_del(&obj->normal_list);
+
+ /* Remove all the messages for the message queue's normal_list queue
+ * and free the list */
+ while (true) {
+ if (!list_empty(&obj->high_list)) {
+ temp_msg = (messageq_msg) (obj->high_list.next);
+ list_del_init(obj->high_list.next);
+ } else
+ break;
+ tmp_status = messageq_free(temp_msg);
+ if (unlikely((tmp_status < 0) && (status >= 0))) {
+ status = tmp_status;
+ pr_err("messageq_delete: messageq_free failed"
+ " for high_list!");
+ }
+ }
+ list_del(&obj->high_list);
+
+ /*if (obj->synchronizer != NULL)
+ status = OsalSemaphore_delete(&obj->synchronizer);*/
+ if (obj->synchronizer != NULL) {
+ kfree(obj->synchronizer);
+ obj->synchronizer = NULL;
+ }
+ /* Clear the MessageQ obj from array. */
+ messageq_module->queues[obj->queue & 0xFFFF] = NULL;
+
+ /* Release the local lock */
+ mutex_unlock(messageq_module->gate_handle);
+
+ /* Now free the obj */
+ kfree(obj);
+ *msg_handleptr = NULL;
+
+exit:
+ if (status < 0)
+ pr_err("messageq_delete failed! status = 0x%x\n", status);
+ return status;
+}
+EXPORT_SYMBOL(messageq_delete);
+
+/* Opens a created instance of MessageQ module. */
+int messageq_open(char *name, u32 *queue_id)
+{
+ int status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(name == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(queue_id == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* Initialize return queue ID to invalid. */
+ *queue_id = MESSAGEQ_INVALIDMESSAGEQ;
+ status = nameserver_get_uint32(messageq_module->ns_handle, name,
+ queue_id, NULL);
+
+exit:
+ if (status < 0)
+ pr_err("messageq_open failed! status = 0x%x\n", status);
+ return status;
+}
+EXPORT_SYMBOL(messageq_open);
+
+/* Closes previously opened/created instance of MessageQ module. */
+int messageq_close(u32 *queue_id)
+{
+ s32 status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(queue_id == NULL))) {
+ pr_err("messageq_close: queue_id passed is NULL!\n");
+ status = -EINVAL;
+ goto exit;
+ }
+
+ *queue_id = MESSAGEQ_INVALIDMESSAGEQ;
+
+exit:
+ if (status < 0)
+ pr_err("messageq_close failed! status = 0x%x\n", status);
+ return status;
+}
+EXPORT_SYMBOL(messageq_close);
+
+/* Retrieve a message */
+int messageq_get(void *messageq_handle, messageq_msg *msg,
+ u32 timeout)
+{
+ int status = 0;
+ struct messageq_object *obj = (struct messageq_object *)messageq_handle;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(msg == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(obj == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* Keep looping while there is no element in the list */
+ /* Take the local lock */
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status)
+ goto exit;
+ if (!list_empty(&obj->high_list)) {
+ *msg = (messageq_msg) (obj->high_list.next);
+ list_del_init(obj->high_list.next);
+ }
+ /* Leave the local lock */
+ mutex_unlock(messageq_module->gate_handle);
+ while (*msg == NULL) {
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status)
+ goto exit;
+ if (!list_empty(&obj->normal_list)) {
+ *msg = (messageq_msg) (obj->normal_list.next);
+ list_del_init(obj->normal_list.next);
+ }
+ mutex_unlock(messageq_module->gate_handle);
+
+ if (*msg == NULL) {
+ /*
+ * Block until notified. If pend times-out, no message
+ * should be returned to the caller
+ */
+ /*! @retval NULL timeout has occurred */
+ if (obj->synchronizer != NULL) {
+ /* TODO: cater to different timeout values */
+ /*status = OsalSemaphore_pend(
+ obj->synchronizer, timeout); */
+ if (timeout == MESSAGEQ_FOREVER) {
+ if (down_interruptible
+ (obj->synchronizer)) {
+ status = -ERESTARTSYS;
+ }
+ } else {
+ status = down_timeout(obj->synchronizer,
+ msecs_to_jiffies(timeout));
+ }
+ if (status < 0) {
+ *msg = NULL;
+ break;
+ }
+ if (obj->unblocked) {
+ *msg = NULL;
+ status = MESSAGEQ_E_UNBLOCKED;
+ obj->unblocked = false;
+ break;
+ }
+ }
+ status = mutex_lock_interruptible(
+ messageq_module->gate_handle);
+ if (status)
+ goto exit;
+ if (!list_empty(&obj->high_list)) {
+ *msg = (messageq_msg) (obj->high_list.next);
+ list_del_init(obj->high_list.next);
+ }
+ mutex_unlock(messageq_module->gate_handle);
+ }
+ }
+
+exit:
+ if (unlikely((messageq_module->cfg.trace_flag == true) && \
+ ((*msg != NULL) && \
+ (((*msg)->flags & MESSAGEQ_TRACEMASK) != 0)))) {
+ pr_info("messageq_get: *msg = 0x%x seq_num = 0x%x "
+ "src_proc = 0x%x obj = 0x%x\n", (uint)(*msg),
+ ((*msg)->seq_num), ((*msg)->src_proc), (uint)(obj));
+ }
+ if (status < 0 && status != -ETIME)
+ pr_err("messageq_get failed! status = 0x%x\n", status);
+ return status;
+}
+EXPORT_SYMBOL(messageq_get);
+
+/* Count the number of messages in the queue */
+int messageq_count(void *messageq_handle)
+{
+ struct messageq_object *obj = (struct messageq_object *)messageq_handle;
+ int count = 0;
+ struct list_head *elem;
+ int key;
+ s32 status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(obj == NULL)) {
+ status = -EINVAL;
+ pr_err("messageq_count: obj passed is NULL!\n");
+ goto exit;
+ }
+
+ key = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (key < 0)
+ return key;
+
+ list_for_each(elem, &obj->high_list) {
+ count++;
+ }
+ list_for_each(elem, &obj->normal_list) {
+ count++;
+ }
+ mutex_unlock(messageq_module->gate_handle);
+
+exit:
+ if (status < 0)
+ pr_err("messageq_count failed! status = 0x%x", status);
+ return count;
+}
+EXPORT_SYMBOL(messageq_count);
+
+/* Initialize a static message */
+void messageq_static_msg_init(messageq_msg msg, u32 size)
+{
+ s32 status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(msg == NULL)) {
+ pr_err("messageq_static_msg_init: msg is invalid!\n");
+ goto exit;
+ }
+
+ /* Fill in the fields of the message */
+ messageq_msg_init(msg);
+ msg->heap_id = MESSAGEQ_STATICMSG;
+ msg->msg_size = size;
+
+ if (unlikely((messageq_module->cfg.trace_flag == true) || \
+ (((*msg).flags & MESSAGEQ_TRACEMASK) != 0))) {
+ pr_info("messageq_static_msg_init: msg = 0x%x "
+ "seq_num = 0x%x src_proc = 0x%x", (uint)(msg),
+ (msg)->seq_num, (msg)->src_proc);
+ }
+
+exit:
+ if (status < 0) {
+ pr_err("messageq_static_msg_init failed! "
+ "status = 0x%x", status);
+ }
+ return;
+}
+EXPORT_SYMBOL(messageq_static_msg_init);
+
+/* Allocate a message and initial the needed fields (note some
+ * of the fields in the header at set via other APIs or in the
+ * messageq_put function. */
+messageq_msg messageq_alloc(u16 heap_id, u32 size)
+{
+ int status = 0;
+ messageq_msg msg = NULL;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(heap_id >= messageq_module->num_heaps))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(messageq_module->heaps[heap_id] == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* Allocate the message. No alignment requested */
+ msg = sl_heap_alloc(messageq_module->heaps[heap_id], size, 0);
+ if (msg == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ /* Fill in the fields of the message */
+ messageq_msg_init(msg);
+ msg->msg_size = size;
+ msg->heap_id = heap_id;
+
+ if (unlikely((messageq_module->cfg.trace_flag == true) || \
+ (((*msg).flags & MESSAGEQ_TRACEMASK) != 0))) {
+ pr_info("messageq_alloc: msg = 0x%x seq_num = 0x%x "
+ "src_proc = 0x%x", (uint)(msg), (msg)->seq_num,
+ (msg)->src_proc);
+ }
+
+exit:
+ if (status < 0)
+ pr_err("messageq_alloc failed! status = 0x%x", status);
+ return msg;
+}
+EXPORT_SYMBOL(messageq_alloc);
+
+/* Frees the message. */
+int messageq_free(messageq_msg msg)
+{
+ u32 status = 0;
+ void *heap = NULL;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(msg == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (unlikely(msg->heap_id == MESSAGEQ_STATICMSG)) {
+ status = MESSAGEQ_E_CANNOTFREESTATICMSG;
+ goto exit;
+ }
+ if (unlikely(msg->heap_id >= messageq_module->num_heaps)) {
+ status = MESSAGEQ_E_INVALIDHEAPID;
+ goto exit;
+ }
+ if (unlikely(messageq_module->heaps[msg->heap_id] == NULL)) {
+ status = MESSAGEQ_E_INVALIDHEAPID;
+ goto exit;
+ }
+
+ if (unlikely((messageq_module->cfg.trace_flag == true) || \
+ (((*msg).flags & MESSAGEQ_TRACEMASK) != 0))) {
+ pr_info("messageq_free: msg = 0x%x seq_num = 0x%x "
+ "src_proc = 0x%x", (uint)(msg), (msg)->seq_num,
+ (msg)->src_proc);
+ }
+ heap = messageq_module->heaps[msg->heap_id];
+ sl_heap_free(heap, msg, msg->msg_size);
+
+exit:
+ if (status < 0)
+ pr_err("messageq_free failed! status = 0x%x\n", status);
+ return status;
+}
+EXPORT_SYMBOL(messageq_free);
+
+/* Put a message in the queue */
+int messageq_put(u32 queue_id, messageq_msg msg)
+{
+ int status = 0;
+ u16 dst_proc_id = (u16)(queue_id >> 16);
+ struct messageq_object *obj = NULL;
+ void *transport = NULL;
+ u32 priority;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(queue_id == MESSAGEQ_INVALIDMESSAGEQ))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(msg == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ msg->dst_id = (u16)(queue_id);
+ msg->dst_proc = (u16)(queue_id >> 16);
+ if (likely(dst_proc_id != multiproc_self())) {
+ if (unlikely(dst_proc_id >= multiproc_get_num_processors())) {
+ /* Invalid destination processor id */
+ status = MESSAGEQ_E_INVALIDPROCID;
+ goto exit;
+ }
+
+ priority = (u32)((msg->flags) & MESSAGEQ_TRANSPORTPRIORITYMASK);
+ /* Call the transport associated with this message queue */
+ transport = messageq_module->transports[dst_proc_id][priority];
+ if (transport == NULL) {
+ /* Try the other transport */
+ priority = !priority;
+ transport =
+ messageq_module->transports[dst_proc_id][priority];
+ }
+
+ if (unlikely(transport == NULL)) {
+ status = -ENODEV;
+ goto exit;
+ }
+ status = transportshm_put(transport, msg);
+ if (unlikely(status < 0))
+ goto exit;
+ } else {
+ /* It is a local MessageQ */
+ obj = (struct messageq_object *)
+ (messageq_module->queues[(u16)(queue_id)]);
+ /* Check for MessageQ Validity. */
+ if (obj == NULL) {
+ status = MESSAGEQ_E_INVALIDMSG;
+ goto exit;
+ }
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status < 0)
+ goto exit;
+ if ((msg->flags & MESSAGEQ_PRIORITYMASK) == \
+ MESSAGEQ_URGENTPRI) {
+ list_add((struct list_head *) msg, &obj->high_list);
+ } else {
+ if ((msg->flags & MESSAGEQ_PRIORITYMASK) == \
+ MESSAGEQ_NORMALPRI) {
+ list_add_tail((struct list_head *) msg,
+ &obj->normal_list);
+ } else {
+ list_add_tail((struct list_head *) msg,
+ &obj->high_list);
+ }
+ }
+ mutex_unlock(messageq_module->gate_handle);
+
+ /* Notify the reader. */
+ if (obj->synchronizer != NULL) {
+ up(obj->synchronizer);
+ /*OsalSemaphore_post(obj->synchronizer);*/
+ }
+ }
+ if (unlikely((messageq_module->cfg.trace_flag == true) || \
+ (((*msg).flags & MESSAGEQ_TRACEMASK) != 0))) {
+ pr_info("messageq_put: msg = 0x%x seq_num = 0x%x "
+ "src_proc = 0x%x dst_proc_id = 0x%x\n", (uint)(msg),
+ (msg)->seq_num, (msg)->src_proc, (msg)->dst_proc);
+ }
+
+exit:
+ if (status < 0)
+ pr_err("messageq_put failed! status = 0x%x\n", status);
+ return status;
+}
+EXPORT_SYMBOL(messageq_put);
+
+/* Register a heap */
+int messageq_register_heap(void *heap_handle, u16 heap_id)
+{
+ int status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(heap_handle == NULL))) {
+ /*! @retval -EINVAL Invalid heap_id */
+ status = -EINVAL;
+ goto exit;
+ }
+ /* Make sure the heap_id is valid */
+ if (WARN_ON(unlikely(heap_id >= messageq_module->num_heaps))) {
+ /*! @retval -EINVAL Invalid heap_id */
+ status = -EINVAL;
+ goto exit;
+ }
+
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status)
+ goto exit;
+ if (messageq_module->heaps[heap_id] == NULL)
+ messageq_module->heaps[heap_id] = heap_handle;
+ else {
+ /*! @retval MESSAGEQ_E_ALREADYEXISTS Specified heap is
+ already registered. */
+ status = MESSAGEQ_E_ALREADYEXISTS;
+ }
+ mutex_unlock(messageq_module->gate_handle);
+
+exit:
+ if (status < 0) {
+ pr_err("messageq_register_heap failed! "
+ "status = 0x%x\n", status);
+ }
+ return status;
+}
+EXPORT_SYMBOL(messageq_register_heap);
+
+/* Unregister a heap */
+int messageq_unregister_heap(u16 heap_id)
+{
+ int status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ /* Make sure the heap_id is valid */
+ if (WARN_ON(unlikely(heap_id >= messageq_module->num_heaps))) {
+ /*! @retval -EINVAL Invalid heap_id */
+ status = -EINVAL;
+ goto exit;
+ }
+
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status)
+ goto exit;
+ if (messageq_module->heaps != NULL)
+ messageq_module->heaps[heap_id] = NULL;
+ mutex_unlock(messageq_module->gate_handle);
+
+exit:
+ if (status < 0) {
+ pr_err("messageq_unregister_heap failed! "
+ "status = 0x%x\n", status);
+ }
+ return status;
+}
+EXPORT_SYMBOL(messageq_unregister_heap);
+
+/* Unblock messageq to prevent waiting forever */
+int messageq_unblock(void *messageq_handle)
+{
+ int status = 0;
+ struct messageq_object *obj = (struct messageq_object *)messageq_handle;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(obj == NULL)) || (WARN_ON(unlikely(
+ obj->synchronizer == NULL)))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ /* Set instance to 'unblocked' state */
+ obj->unblocked = true;
+ up(obj->synchronizer);
+
+exit:
+ if (status < 0) {
+ pr_err("messageq_unblock failed! status = 0x%x\n",
+ status);
+ }
+ return status;
+}
+
+/* Register a transport */
+int messageq_register_transport(void *messageq_transportshm_handle,
+ u16 proc_id, u32 priority)
+{
+ int status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(messageq_transportshm_handle == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(proc_id >= multiproc_get_num_processors()))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status)
+ goto exit;
+ if (messageq_module->transports[proc_id][priority] == NULL) {
+ messageq_module->transports[proc_id][priority] = \
+ messageq_transportshm_handle;
+ } else {
+ /*! @retval MESSAGEQ_E_ALREADYEXISTS Specified transport is
+ already registered. */
+ status = MESSAGEQ_E_ALREADYEXISTS;
+ }
+ mutex_unlock(messageq_module->gate_handle);
+
+exit:
+ if (status < 0) {
+ pr_err("messageq_register_transport failed! "
+ "status = 0x%x\n", status);
+ }
+ return status;
+}
+EXPORT_SYMBOL(messageq_register_transport);
+
+/* Unregister a transport */
+void messageq_unregister_transport(u16 proc_id, u32 priority)
+{
+ int status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(proc_id >= multiproc_get_num_processors())) {
+ /*! @retval MESSAGEQ_E_PROCIDINVALID Invalid proc_id */
+ status = -EINVAL;
+ goto exit;
+ }
+
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status)
+ goto exit;
+ if (messageq_module->transports[proc_id][priority] != NULL)
+ messageq_module->transports[proc_id][priority] = NULL;
+ mutex_unlock(messageq_module->gate_handle);
+
+exit:
+ if (status < 0) {
+ pr_err("messageq_unregister_transport failed! "
+ "status = 0x%x\n", status);
+ }
+ return;
+}
+EXPORT_SYMBOL(messageq_unregister_transport);
+
+/* Set the destination queue of the message. */
+void messageq_set_reply_queue(void *messageq_handle, messageq_msg msg)
+{
+ s32 status = 0;
+
+ struct messageq_object *obj = \
+ (struct messageq_object *) messageq_handle;
+
+ if (WARN_ON(unlikely(messageq_handle == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(msg == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ msg->reply_id = (u16)(obj->queue);
+ msg->reply_proc = (u16)(obj->queue >> 16);
+ return;
+
+exit:
+ pr_err("messageq_set_reply_queue failed: status = 0x%x", status);
+ return;
+}
+EXPORT_SYMBOL(messageq_set_reply_queue);
+
+/* Get the queue _id of the message. */
+u32 messageq_get_queue_id(void *messageq_handle)
+{
+ struct messageq_object *obj = \
+ (struct messageq_object *) messageq_handle;
+ u32 queue_id = MESSAGEQ_INVALIDMESSAGEQ;
+
+ if (WARN_ON(unlikely(obj == NULL))) {
+ pr_err("messageq_get_queue_id: obj passed is NULL!\n");
+ goto exit;
+ }
+
+ queue_id = (obj->queue);
+
+exit:
+ return queue_id;
+}
+EXPORT_SYMBOL(messageq_get_queue_id);
+
+/* Get the proc _id of the message. */
+u16 messageq_get_proc_id(void *messageq_handle)
+{
+ struct messageq_object *obj = \
+ (struct messageq_object *) messageq_handle;
+ u16 proc_id = MULTIPROC_INVALIDID;
+
+ if (WARN_ON(unlikely(obj == NULL))) {
+ pr_err("messageq_get_proc_id: obj passed is NULL!\n");
+ goto exit;
+ }
+
+ proc_id = (u16)(obj->queue >> 16);
+
+exit:
+ return proc_id;
+}
+EXPORT_SYMBOL(messageq_get_proc_id);
+
+/* Get the destination queue of the message. */
+u32 messageq_get_dst_queue(messageq_msg msg)
+{
+ u32 queue_id = MESSAGEQ_INVALIDMESSAGEQ;
+
+ if (WARN_ON(unlikely(msg == NULL))) {
+ pr_err("messageq_get_dst_queue: msg passed is NULL!\n");
+ goto exit;
+ }
+
+ /*construct queue value */
+ if (msg->dst_id != (u32)MESSAGEQ_INVALIDMESSAGEQ)
+ queue_id = ((u32) multiproc_self() << 16) | msg->dst_id;
+
+exit:
+ return queue_id;
+}
+EXPORT_SYMBOL(messageq_get_dst_queue);
+
+/* Get the message id of the message. */
+u16 messageq_get_msg_id(messageq_msg msg)
+{
+ u16 id = MESSAGEQ_INVALIDMSGID;
+
+ if (WARN_ON(unlikely(msg == NULL))) {
+ pr_err("messageq_get_msg_id: msg passed is NULL!\n");
+ goto exit;
+ }
+
+ id = msg->msg_id;
+
+exit:
+ return id;
+}
+EXPORT_SYMBOL(messageq_get_msg_id);
+
+/* Get the message size of the message. */
+u32 messageq_get_msg_size(messageq_msg msg)
+{
+ u32 size = 0;
+
+ if (WARN_ON(unlikely(msg == NULL))) {
+ pr_err("messageq_get_msg_size: msg passed is NULL!\n");
+ goto exit;
+ }
+
+ size = msg->msg_size;
+
+exit:
+ return size;
+}
+EXPORT_SYMBOL(messageq_get_msg_size);
+
+/* Get the message priority of the message. */
+u32 messageq_get_msg_pri(messageq_msg msg)
+{
+ u32 priority = MESSAGEQ_NORMALPRI;
+
+ if (WARN_ON(unlikely(msg == NULL))) {
+ pr_err("messageq_get_msg_pri: msg passed is NULL!\n");
+ goto exit;
+ }
+
+ priority = ((u32)(msg->flags & MESSAGEQ_PRIORITYMASK));
+
+exit:
+ return priority;
+}
+EXPORT_SYMBOL(messageq_get_msg_pri);
+
+/* Get the embedded source message queue out of the message. */
+u32 messageq_get_reply_queue(messageq_msg msg)
+{
+ u32 queue = MESSAGEQ_INVALIDMESSAGEQ;
+
+ if (WARN_ON(unlikely(msg == NULL))) {
+ pr_err("messageq_get_reply_queue: msg passed is NULL!\n");
+ goto exit;
+ }
+
+ if (msg->reply_id != (u16)MESSAGEQ_INVALIDMESSAGEQ)
+ queue = ((u32)(msg->reply_proc) << 16) | msg->reply_id;
+
+exit:
+ return queue;
+}
+EXPORT_SYMBOL(messageq_get_reply_queue);
+
+/* Set the message id of the message. */
+void messageq_set_msg_id(messageq_msg msg, u16 msg_id)
+{
+ if (WARN_ON(unlikely(msg == NULL))) {
+ pr_err("messageq_set_msg_id: msg passed is NULL!\n");
+ goto exit;
+ }
+
+ msg->msg_id = msg_id;
+
+exit:
+ return;
+}
+EXPORT_SYMBOL(messageq_set_msg_id);
+
+/* Set the priority of the message. */
+void messageq_set_msg_pri(messageq_msg msg, u32 priority)
+{
+ if (WARN_ON(unlikely(msg == NULL))) {
+ pr_err("messageq_set_msg_pri: msg passed is NULL!\n");
+ goto exit;
+ }
+
+ msg->flags = priority & MESSAGEQ_PRIORITYMASK;
+
+exit:
+ return;
+}
+EXPORT_SYMBOL(messageq_set_msg_pri);
+
+/* Sets the tracing of a message */
+void messageq_set_msg_trace(messageq_msg msg, bool trace_flag)
+{
+ if (WARN_ON(unlikely(msg == NULL))) {
+ pr_err("messageq_set_msg_trace: msg passed is NULL!\n");
+ goto exit;
+ }
+
+ msg->flags = (msg->flags & ~MESSAGEQ_TRACEMASK) | \
+ (trace_flag << MESSAGEQ_TRACESHIFT);
+
+ pr_info("messageq_set_msg_trace: msg = 0x%x, seq_num = 0x%x"
+ "src_proc = 0x%x trace_flag = 0x%x", (uint)msg,
+ msg->seq_num, msg->src_proc, trace_flag);
+exit:
+ return;
+}
+
+/* Returns the amount of shared memory used by one transport instance.
+ *
+ * The MessageQ module itself does not use any shared memory but the
+ * underlying transport may use some shared memory.
+ */
+uint messageq_shared_mem_req(void *shared_addr)
+{
+ uint mem_req;
+
+ if (likely(multiproc_get_num_processors() > 1)) {
+ /* Determine device-specific shared memory requirements */
+ mem_req = messageq_setup_transport_proxy_shared_mem_req(
+ shared_addr);
+ } else {
+ /* Only 1 processor: no shared memory needed */
+ mem_req = 0;
+ }
+
+ return mem_req;
+}
+EXPORT_SYMBOL(messageq_shared_mem_req);
+
+/* Calls the SetupProxy to setup the MessageQ transports. */
+int messageq_attach(u16 remote_proc_id, void *shared_addr)
+{
+ int status = MESSAGEQ_S_SUCCESS;
+
+ if (likely(multiproc_get_num_processors() > 1)) {
+ /* Use the messageq_setup_transport_proxy to attach
+ * transports */
+ status = messageq_setup_transport_proxy_attach(
+ remote_proc_id, shared_addr);
+ if (status < 0) {
+ pr_err("messageq_attach failed in transport"
+ "setup, status = 0x%x", status);
+ }
+ }
+
+ /*! @retval MESSAGEQ_S_SUCCESS Operation successfully completed! */
+ return status;
+}
+EXPORT_SYMBOL(messageq_attach);
+
+/* Calls the SetupProxy to detach the MessageQ transports. */
+int messageq_detach(u16 remote_proc_id)
+{
+ int status = MESSAGEQ_S_SUCCESS;
+
+ if (likely(multiproc_get_num_processors() > 1)) {
+ /* Use the messageq_setup_transport_proxy to detach
+ * transports */
+ status = messageq_setup_transport_proxy_detach(remote_proc_id);
+ if (unlikely(status < 0)) {
+ pr_err("messageq_detach failed in transport"
+ "detach, status = 0x%x", status);
+ }
+ }
+
+ /*! @retval MESSAGEQ_S_SUCCESS Operation successfully completed! */
+ return status;
+}
+EXPORT_SYMBOL(messageq_detach);
+
+/* =============================================================================
+ * Internal functions
+ * =============================================================================
+ */
+/* Grow the MessageQ table */
+static u16 _messageq_grow(struct messageq_object *obj)
+{
+ u16 queue_index = messageq_module->num_queues;
+ int old_size;
+ void **queues;
+ void **oldqueues;
+
+ /* No parameter validation required since this is an internal func. */
+ old_size = (messageq_module->num_queues) * \
+ sizeof(struct messageq_object *);
+ queues = kmalloc(old_size + sizeof(struct messageq_object *),
+ GFP_KERNEL);
+ if (queues == NULL) {
+ pr_err("_messageq_grow: Growing the messageq failed!\n");
+ goto exit;
+ }
+
+ /* Copy contents into new table */
+ memcpy(queues, messageq_module->queues, old_size);
+ /* Fill in the new entry */
+ queues[queue_index] = (void *)obj;
+ /* Hook-up new table */
+ oldqueues = messageq_module->queues;
+ messageq_module->queues = queues;
+ messageq_module->num_queues++;
+
+ /* Delete old table if not statically defined*/
+ if (messageq_module->can_free_queues == true)
+ kfree(oldqueues);
+ else
+ messageq_module->can_free_queues = true;
+
+exit:
+ return queue_index;
+}
+
+/* This is a helper function to initialize a message. */
+static void messageq_msg_init(messageq_msg msg)
+{
+ s32 status = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(messageq_module->ref_count),
+ MESSAGEQ_MAKE_MAGICSTAMP(0),
+ MESSAGEQ_MAKE_MAGICSTAMP(1)) == true))) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ if (WARN_ON(unlikely(msg == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ msg->reply_id = (u16) MESSAGEQ_INVALIDMESSAGEQ;
+ msg->msg_id = MESSAGEQ_INVALIDMSGID;
+ msg->dst_id = (u16) MESSAGEQ_INVALIDMESSAGEQ;
+ msg->flags = MESSAGEQ_HEADERVERSION | MESSAGEQ_NORMALPRI;
+ msg->src_proc = multiproc_self();
+
+ status = mutex_lock_interruptible(messageq_module->gate_handle);
+ if (status < 0)
+ goto exit;
+ msg->seq_num = messageq_module->seq_num++;
+ mutex_unlock(messageq_module->gate_handle);
+
+exit:
+ if (status < 0)
+ pr_err("messageq_msg_init: Invalid NULL msg specified!\n");
+ return;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/messageq_ioctl.c b/drivers/dsp/syslink/multicore_ipc/messageq_ioctl.c
new file mode 100644
index 00000000000..d9cead76533
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/messageq_ioctl.c
@@ -0,0 +1,745 @@
+/*
+ * messageq_ioctl.c
+ *
+ * This file implements all the ioctl operations required on the messageq
+ * module.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+/* Standard headers */
+#include <linux/types.h>
+
+/* Linux headers */
+#include <linux/uaccess.h>
+#include <linux/bug.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+/* Module Headers */
+#include <ipc.h>
+#include <messageq.h>
+#include <messageq_ioctl.h>
+#include <sharedregion.h>
+
+static struct resource_info *find_messageq_resource(
+ struct ipc_process_context *pr_ctxt,
+ unsigned int cmd,
+ struct messageq_cmd_args *cargs)
+{
+ struct resource_info *info = NULL;
+ bool found = false;
+
+ spin_lock(&pr_ctxt->res_lock);
+
+ list_for_each_entry(info, &pr_ctxt->resources, res) {
+ struct messageq_cmd_args *args =
+ (struct messageq_cmd_args *)info->data;
+ if (info->cmd == cmd) {
+ switch (cmd) {
+ case CMD_MESSAGEQ_DELETE:
+ {
+ void *handle = NULL;
+ void *t_handle = NULL;
+ if (cargs != NULL && args != NULL) {
+ handle = args->args.delete_messageq.
+ messageq_handle;
+ t_handle = cargs->args.delete_messageq.
+ messageq_handle;
+ if (t_handle == handle)
+ found = true;
+ }
+ break;
+ }
+ case CMD_MESSAGEQ_CLOSE:
+ {
+ if (cargs != NULL && args != NULL) {
+ u16 q_id = args->args.close.queue_id;
+ u16 temp = cargs->args.close.queue_id;
+ if (temp == q_id)
+ found = true;
+ }
+ break;
+ }
+ case CMD_MESSAGEQ_DESTROY:
+ {
+ found = true;
+ break;
+ }
+ case CMD_MESSAGEQ_UNREGISTERHEAP:
+ {
+ if (cargs != NULL && args != NULL) {
+ u16 h_id = args->args.unregister_heap.
+ heap_id;
+ u16 temp = cargs->args.unregister_heap.
+ heap_id;
+ if (temp == h_id)
+ found = true;
+ }
+ break;
+ }
+ }
+ if (found == true)
+ break;
+ }
+ }
+
+ spin_unlock(&pr_ctxt->res_lock);
+
+ if (found == false)
+ info = NULL;
+
+ return info;
+}
+
+/*
+ * ======== messageq_ioctl_put ========
+ * Purpose:
+ * This ioctl interface to messageq_put function
+ */
+static inline int messageq_ioctl_put(struct messageq_cmd_args *cargs)
+{
+ int status = 0;
+ messageq_msg msg;
+
+ msg = (messageq_msg) sharedregion_get_ptr(cargs->args.put.msg_srptr);
+ if (unlikely(msg == NULL))
+ goto exit;
+
+ status = messageq_put(cargs->args.put.queue_id, msg);
+
+ cargs->api_status = status;
+exit:
+ return 0;
+}
+
+/*
+ * ======== messageq_ioctl_get ========
+ * Purpose:
+ * This ioctl interface to messageq_get function
+ */
+static inline int messageq_ioctl_get(struct messageq_cmd_args *cargs)
+{
+ messageq_msg msg = NULL;
+ u32 *msg_srptr = SHAREDREGION_INVALIDSRPTR;
+ u16 index;
+
+ cargs->api_status = messageq_get(cargs->args.get.messageq_handle,
+ &msg,
+ cargs->args.get.timeout);
+ if (unlikely(cargs->api_status < 0))
+ goto exit;
+
+ index = sharedregion_get_id(msg);
+ if (unlikely(index < 0)) {
+ cargs->api_status = index;
+ goto exit;
+ }
+
+ msg_srptr = sharedregion_get_srptr(msg, index);
+
+exit:
+ cargs->args.get.msg_srptr = msg_srptr;
+ return 0;
+}
+
+/*
+ * ======== messageq_ioctl_count ========
+ * Purpose:
+ * This ioctl interface to messageq_count function
+ */
+static inline int messageq_ioctl_count(struct messageq_cmd_args *cargs)
+{
+ int result = messageq_count(cargs->args.count.messageq_handle);
+ if (result < 0)
+ cargs->api_status = result;
+ else
+ cargs->args.count.count = result;
+
+ return 0;
+}
+
+/*
+ * ======== messageq_ioctl_alloc ========
+ * Purpose:
+ * This ioctl interface to messageq_alloc function
+ */
+static inline int messageq_ioctl_alloc(struct messageq_cmd_args *cargs)
+{
+ messageq_msg msg;
+ u32 *msg_srptr = SHAREDREGION_INVALIDSRPTR;
+ u16 index;
+
+ msg = messageq_alloc(cargs->args.alloc.heap_id, cargs->args.alloc.size);
+ if (unlikely(msg == NULL))
+ goto exit;
+
+ index = sharedregion_get_id(msg);
+ if (unlikely(index < 0))
+ goto exit;
+
+ msg_srptr = sharedregion_get_srptr(msg, index);
+
+ cargs->api_status = 0;
+exit:
+ cargs->args.alloc.msg_srptr = msg_srptr;
+ return 0;
+}
+
+/*
+ * ======== messageq_ioctl_free ========
+ * Purpose:
+ * This ioctl interface to messageq_free function
+ */
+static inline int messageq_ioctl_free(struct messageq_cmd_args *cargs)
+{
+ int status = 0;
+ messageq_msg msg;
+
+ msg = sharedregion_get_ptr(cargs->args.free.msg_srptr);
+ if (unlikely(msg == NULL))
+ goto exit;
+ status = messageq_free(msg);
+
+ cargs->api_status = status;
+exit:
+ return 0;
+}
+
+/*
+ * ======== messageq_ioctl_params_init ========
+ * Purpose:
+ * This ioctl interface to messageq_params_init function
+ */
+static inline int messageq_ioctl_params_init(struct messageq_cmd_args *cargs)
+{
+ s32 retval = 0;
+ int status = 0;
+ unsigned long size;
+ struct messageq_params params;
+
+ messageq_params_init(&params);
+ size = copy_to_user((void __user *)cargs->args.params_init.params,
+ &params, sizeof(struct messageq_params));
+ if (size) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ cargs->api_status = status;
+exit:
+ return retval;
+}
+
+/*
+ * ======== messageq_ioctl_create ========
+ * Purpose:
+ * This ioctl interface to messageq_create function
+ */
+static inline int messageq_ioctl_create(struct messageq_cmd_args *cargs)
+{
+ s32 retval = 0;
+ int status = 0;
+ unsigned long size;
+ struct messageq_params params;
+ char *name = NULL;
+
+ if (cargs->args.create.params != NULL) {
+ size = copy_from_user(&params,
+ (void __user *)cargs->args.create.params,
+ sizeof(struct messageq_params));
+ if (size) {
+ retval = -EFAULT;
+ goto exit;
+ }
+ }
+
+ /* Allocate memory for the name */
+ if (cargs->args.create.name_len > 0) {
+ name = kmalloc(cargs->args.create.name_len, GFP_KERNEL);
+ if (name == NULL) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+ size = copy_from_user(name,
+ (void __user *)cargs->args.create.name,
+ cargs->args.create.name_len);
+ if (size) {
+ retval = -EFAULT;
+ goto free_name;
+ }
+ }
+
+ if (cargs->args.create.params != NULL) {
+ cargs->args.create.messageq_handle = \
+ messageq_create(name, &params);
+ } else {
+ cargs->args.create.messageq_handle = \
+ messageq_create(name, NULL);
+ }
+
+ if (cargs->args.create.messageq_handle != NULL) {
+ cargs->args.create.queue_id = messageq_get_queue_id(
+ cargs->args.create.messageq_handle);
+ }
+
+free_name:
+ if (cargs->args.create.name_len > 0)
+ kfree(name);
+
+ cargs->api_status = status;
+exit:
+ return retval;
+}
+
+/*
+ * ======== messageq_ioctl_delete ========
+ * Purpose:
+ * This ioctl interface to messageq_delete function
+ */
+static inline int messageq_ioctl_delete(struct messageq_cmd_args *cargs)
+{
+ cargs->api_status =
+ messageq_delete(&(cargs->args.delete_messageq.messageq_handle));
+ return 0;
+}
+
+/*
+ * ======== messageq_ioctl_open ========
+ * Purpose:
+ * This ioctl interface to messageq_open function
+ */
+static inline int messageq_ioctl_open(struct messageq_cmd_args *cargs)
+{
+ s32 retval = 0;
+ int status = 0;
+ unsigned long size;
+ char *name = NULL;
+ u32 queue_id = MESSAGEQ_INVALIDMESSAGEQ;
+
+ /* Allocate memory for the name */
+ if (cargs->args.open.name_len > 0) {
+ name = kmalloc(cargs->args.open.name_len, GFP_KERNEL);
+ if (name == NULL) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+ size = copy_from_user(name,
+ (void __user *)cargs->args.open.name,
+ cargs->args.open.name_len);
+ if (size) {
+ retval = -EFAULT;
+ goto free_name;
+ }
+ }
+
+ status = messageq_open(name, &queue_id);
+ cargs->args.open.queue_id = queue_id;
+
+free_name:
+ if (cargs->args.open.name_len > 0)
+ kfree(name);
+
+ cargs->api_status = status;
+exit:
+ return retval;
+}
+
+/*
+ * ======== messageq_ioctl_close ========
+ * Purpose:
+ * This ioctl interface to messageq_close function
+ */
+static inline int messageq_ioctl_close(struct messageq_cmd_args *cargs)
+{
+ u32 queue_id = cargs->args.close.queue_id;
+ messageq_close(&queue_id);
+ cargs->args.close.queue_id = queue_id;
+
+ cargs->api_status = 0;
+ return 0;
+}
+
+/*
+ * ======== messageq_ioctl_get_config ========
+ * Purpose:
+ * This ioctl interface to messageq_get_config function
+ */
+static inline int messageq_ioctl_get_config(struct messageq_cmd_args *cargs)
+{
+ s32 retval = 0;
+ unsigned long size;
+ struct messageq_config config;
+
+ messageq_get_config(&config);
+ size = copy_to_user((void __user *)cargs->args.get_config.config,
+ &config, sizeof(struct messageq_config));
+ if (size) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ cargs->api_status = 0;
+exit:
+ return retval;
+}
+
+/*
+ * ======== messageq_ioctl_unblock ========
+ * Purpose:
+ * This ioctl interface to messageq_unblock function
+ */
+static inline int messageq_ioctl_unblock(struct messageq_cmd_args *cargs)
+{
+ cargs->api_status = messageq_unblock(cargs->args.unblock.messageq_handle);
+
+ return 0;
+}
+
+/*
+ * ======== messageq_ioctl_setup ========
+ * Purpose:
+ * This ioctl interface to messageq_setup function
+ */
+static inline int messageq_ioctl_setup(struct messageq_cmd_args *cargs)
+{
+ s32 retval = 0;
+ unsigned long size;
+ struct messageq_config config;
+
+ size = copy_from_user(&config, (void __user *)cargs->args.setup.config,
+ sizeof(struct messageq_config));
+ if (size) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ cargs->api_status = messageq_setup(&config);
+
+exit:
+ return retval;
+}
+
+/*
+ * ======== messageq_ioctl_destroy ========
+ * Purpose:
+ * This ioctl interface to messageq_destroy function
+ */
+static inline int messageq_ioctl_destroy(struct messageq_cmd_args *cargs)
+{
+ cargs->api_status = messageq_destroy();
+ return 0;
+}
+
+/*
+ * ======== messageq_ioctl_register_heap ========
+ * Purpose:
+ * This ioctl interface to messageq_register_heap function
+ */
+static inline int messageq_ioctl_register_heap(struct messageq_cmd_args *cargs)
+{
+ cargs->api_status = \
+ messageq_register_heap(cargs->args.register_heap.heap_handle,
+ cargs->args.register_heap.heap_id);
+ return 0;
+}
+
+/*
+ * ======== messageq_ioctl_unregister_heap ========
+ * Purpose:
+ * This ioctl interface to messageq_unregister_heap function
+ */
+static inline int messageq_ioctl_unregister_heap(
+ struct messageq_cmd_args *cargs)
+{
+ cargs->api_status = messageq_unregister_heap(
+ cargs->args.unregister_heap.heap_id);
+ return 0;
+}
+
+/*
+ * ======== messageq_ioctl_attach ========
+ * Purpose:
+ * This ioctl interface to messageq_ioctl_attach function
+ */
+static inline int messageq_ioctl_attach(struct messageq_cmd_args *cargs)
+{
+ void *shared_addr;
+
+ shared_addr = sharedregion_get_ptr(
+ cargs->args.attach.shared_addr_srptr);
+ if (unlikely(shared_addr == NULL)) {
+ cargs->api_status = -1;
+ goto exit;
+ }
+ cargs->api_status = messageq_attach(cargs->args.attach.remote_proc_id,
+ shared_addr);
+
+exit:
+ return 0;
+}
+
+/*
+ * ======== messageq_ioctl_detach ========
+ * Purpose:
+ * This ioctl interface to messageq_ioctl_detach function
+ */
+static inline int messageq_ioctl_detach(struct messageq_cmd_args *cargs)
+{
+ cargs->api_status = messageq_detach(cargs->args.detach.remote_proc_id);
+ return 0;
+}
+
+/*
+ * ======== messageq_ioctl_sharedmem_req ========
+ * Purpose:
+ * This ioctl interface to messageq_ioctl_sharedmem_req function
+ */
+static inline int messageq_ioctl_shared_mem_req(struct messageq_cmd_args *cargs)
+{
+ void *shared_addr;
+
+ shared_addr = sharedregion_get_ptr(
+ cargs->args.shared_mem_req.shared_addr_srptr);
+ if (unlikely(shared_addr == NULL)) {
+ cargs->api_status = -1;
+ goto exit;
+ }
+ cargs->args.shared_mem_req.mem_req = \
+ messageq_shared_mem_req(shared_addr);
+ cargs->api_status = 0;
+
+exit:
+ return 0;
+}
+
+/*
+ * ======== messageq_ioctl ========
+ * Purpose:
+ * ioctl interface function for messageq module
+ */
+int messageq_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user)
+{
+ int status = 0;
+ struct messageq_cmd_args __user *uarg =
+ (struct messageq_cmd_args __user *)args;
+ struct messageq_cmd_args cargs;
+ unsigned long size;
+ struct ipc_process_context *pr_ctxt =
+ (struct ipc_process_context *)filp->private_data;
+
+ if (user == true) {
+#ifdef CONFIG_SYSLINK_RECOVERY
+ if (ipc_recovering() && cmd != CMD_MESSAGEQ_UNBLOCK
+ && cmd != CMD_MESSAGEQ_DELETE
+ && cmd != CMD_MESSAGEQ_CLOSE
+ && cmd != CMD_MESSAGEQ_DESTROY) {
+ status = -EIO;
+ goto exit;
+ }
+#endif
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ status = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ status = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
+ if (status) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ /* Copy the full args from user-side */
+ size = copy_from_user(&cargs, uarg,
+ sizeof(struct messageq_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ } else {
+ if (args != 0)
+ memcpy(&cargs, (void *)args,
+ sizeof(struct messageq_cmd_args));
+ }
+
+ switch (cmd) {
+ case CMD_MESSAGEQ_PUT:
+ status = messageq_ioctl_put(&cargs);
+ break;
+
+ case CMD_MESSAGEQ_GET:
+ status = messageq_ioctl_get(&cargs);
+ break;
+
+ case CMD_MESSAGEQ_COUNT:
+ status = messageq_ioctl_count(&cargs);
+ break;
+
+ case CMD_MESSAGEQ_ALLOC:
+ status = messageq_ioctl_alloc(&cargs);
+ break;
+
+ case CMD_MESSAGEQ_FREE:
+ status = messageq_ioctl_free(&cargs);
+ break;
+
+ case CMD_MESSAGEQ_PARAMS_INIT:
+ status = messageq_ioctl_params_init(&cargs);
+ break;
+
+ case CMD_MESSAGEQ_CREATE:
+ status = messageq_ioctl_create(&cargs);
+ if (status >= 0 && cargs.api_status >= 0) {
+ struct messageq_cmd_args *temp = kmalloc(
+ sizeof(struct messageq_cmd_args),
+ GFP_KERNEL);
+ if (WARN_ON(!temp)) {
+ status = -ENOMEM;
+ goto exit;
+ }
+ temp->args.delete_messageq.messageq_handle =
+ cargs.args.create.messageq_handle;
+ add_pr_res(pr_ctxt, CMD_MESSAGEQ_DELETE, (void *)temp);
+ }
+ break;
+
+ case CMD_MESSAGEQ_DELETE:
+ {
+ struct resource_info *info = NULL;
+ info = find_messageq_resource(pr_ctxt,
+ CMD_MESSAGEQ_DELETE,
+ &cargs);
+ status = messageq_ioctl_delete(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_MESSAGEQ_OPEN:
+ status = messageq_ioctl_open(&cargs);
+ if (status >= 0 && cargs.api_status >= 0) {
+ struct messageq_cmd_args *temp = kmalloc(
+ sizeof(struct messageq_cmd_args),
+ GFP_KERNEL);
+ if (WARN_ON(!temp)) {
+ status = -ENOMEM;
+ goto exit;
+ }
+ temp->args.close.queue_id = cargs.args.open.queue_id;
+ add_pr_res(pr_ctxt, CMD_MESSAGEQ_CLOSE, (void *)temp);
+ }
+ break;
+
+ case CMD_MESSAGEQ_CLOSE:
+ {
+ struct resource_info *info = NULL;
+ info = find_messageq_resource(pr_ctxt,
+ CMD_MESSAGEQ_CLOSE,
+ &cargs);
+ status = messageq_ioctl_close(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_MESSAGEQ_GETCONFIG:
+ status = messageq_ioctl_get_config(&cargs);
+ break;
+
+ case CMD_MESSAGEQ_UNBLOCK:
+ status = messageq_ioctl_unblock(&cargs);
+ break;
+
+ case CMD_MESSAGEQ_SETUP:
+ status = messageq_ioctl_setup(&cargs);
+ if (status >= 0)
+ add_pr_res(pr_ctxt, CMD_MESSAGEQ_DESTROY, NULL);
+ break;
+
+ case CMD_MESSAGEQ_DESTROY:
+ {
+ struct resource_info *info = NULL;
+ info = find_messageq_resource(pr_ctxt,
+ CMD_MESSAGEQ_DESTROY,
+ &cargs);
+ status = messageq_ioctl_destroy(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_MESSAGEQ_REGISTERHEAP:
+ status = messageq_ioctl_register_heap(&cargs);
+ if (cargs.api_status >= 0) {
+ struct messageq_cmd_args *temp = kmalloc(
+ sizeof(struct messageq_cmd_args),
+ GFP_KERNEL);
+ if (WARN_ON(!temp)) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ temp->args.unregister_heap.heap_id =
+ cargs.args.register_heap.heap_id;
+ add_pr_res(pr_ctxt, CMD_MESSAGEQ_UNREGISTERHEAP,
+ (void *)temp);
+ }
+ break;
+
+ case CMD_MESSAGEQ_UNREGISTERHEAP:
+ {
+ struct resource_info *info = NULL;
+ info = find_messageq_resource(pr_ctxt,
+ CMD_MESSAGEQ_UNREGISTERHEAP,
+ &cargs);
+ status = messageq_ioctl_unregister_heap(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_MESSAGEQ_ATTACH:
+ status = messageq_ioctl_attach(&cargs);
+ break;
+
+ case CMD_MESSAGEQ_DETACH:
+ status = messageq_ioctl_detach(&cargs);
+ break;
+
+ case CMD_MESSAGEQ_SHAREDMEMREQ:
+ status = messageq_ioctl_shared_mem_req(&cargs);
+ break;
+
+ default:
+ WARN_ON(cmd);
+ cargs.api_status = -EFAULT;
+ status = -ENOTTY;
+ break;
+ }
+
+ if ((cargs.api_status == -ERESTARTSYS) || (cargs.api_status == -EINTR))
+ status = -ERESTARTSYS;
+
+ if (status < 0)
+ goto exit;
+
+ if (user == true) {
+ /* Copy the full args to the user-side. */
+ size = copy_to_user(uarg, &cargs,
+ sizeof(struct messageq_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ }
+ return status;
+
+exit:
+ pr_err("messageq_ioctl failed: status = 0x%x\n", status);
+ return status;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/multiproc.c b/drivers/dsp/syslink/multicore_ipc/multiproc.c
new file mode 100644
index 00000000000..c5d074e8480
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/multiproc.c
@@ -0,0 +1,315 @@
+/*
+* multiproc.c
+*
+* Many multi-processor modules have the concept of processor id. MultiProc
+* centeralizes the processor id management.
+*
+* Copyright (C) 2008-2009 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.
+*/
+
+/*
+ * ======== multiproc.c ========
+ * Notes:
+ * The processor id start at 0 and ascend without skipping values till maximum_
+ * no_of_processors - 1
+ */
+
+/* Standard headers */
+#include <linux/types.h>
+#include <linux/module.h>
+#include <syslink/atomic_linux.h>
+/* Utilities headers */
+#include <linux/string.h>
+
+/* Module level headers */
+#include <multiproc.h>
+
+/* Macro to make a correct module magic number with ref_count */
+#define MULTIPROC_MAKE_MAGICSTAMP(x) ((MULTIPROC_MODULEID << 12u) | (x))
+
+/*
+ * multiproc module state object
+ */
+struct multiproc_module_object {
+ struct multiproc_config cfg; /* Module configuration structure */
+ struct multiproc_config def_cfg; /* Default module configuration */
+ atomic_t ref_count; /* Reference count */
+ u16 id; /* Local processor ID */
+};
+
+static struct multiproc_module_object multiproc_state = {
+ .def_cfg.num_processors = 4,
+ .def_cfg.name_list[0][0] = 'T',
+ .def_cfg.name_list[0][1] = 'e',
+ .def_cfg.name_list[0][2] = 's',
+ .def_cfg.name_list[0][3] = 'l',
+ .def_cfg.name_list[0][4] = 'a',
+ .def_cfg.name_list[1][0] = 'A',
+ .def_cfg.name_list[1][1] = 'p',
+ .def_cfg.name_list[1][2] = 'p',
+ .def_cfg.name_list[1][3] = 'M',
+ .def_cfg.name_list[1][4] = '3',
+ .def_cfg.name_list[2][0] = 'S',
+ .def_cfg.name_list[2][1] = 'y',
+ .def_cfg.name_list[2][2] = 's',
+ .def_cfg.name_list[2][3] = 'M',
+ .def_cfg.name_list[2][4] = '3',
+ .def_cfg.name_list[3][0] = 'M',
+ .def_cfg.name_list[3][1] = 'P',
+ .def_cfg.name_list[3][2] = 'U',
+ .def_cfg.id = 3,
+ .id = MULTIPROC_INVALIDID
+};
+
+/*
+ * ========= multiproc_module =========
+ * Pointer to the MultiProc module state.
+ */
+static struct multiproc_module_object *multiproc_module = &multiproc_state;
+
+
+/*
+ * ======== multiproc_get_config ========
+ * Purpose:
+ * This will get the default configuration for the multiproc module
+ */
+void multiproc_get_config(struct multiproc_config *cfg)
+{
+ BUG_ON(cfg == NULL);
+ if (atomic_cmpmask_and_lt(
+ &(multiproc_module->ref_count),
+ MULTIPROC_MAKE_MAGICSTAMP(0),
+ MULTIPROC_MAKE_MAGICSTAMP(1)) == true) {
+ /* (If setup has not yet been called) */
+ memcpy(cfg, &multiproc_module->def_cfg,
+ sizeof(struct multiproc_config));
+ } else {
+ memcpy(cfg, &multiproc_module->cfg,
+ sizeof(struct multiproc_config));
+ }
+}
+EXPORT_SYMBOL(multiproc_get_config);
+
+/*
+ * ======== multiproc_setup ========
+ * Purpose:
+ * This function sets up the multiproc module. This function
+ * must be called before any other instance-level APIs can be
+ * invoked
+ */
+s32 multiproc_setup(struct multiproc_config *cfg)
+{
+ s32 status = 0;
+ struct multiproc_config tmp_cfg;
+
+ /* This sets the ref_count variable is not initialized, upper 16 bits is
+ * written with module Id to ensure correctness of ref_count variable.
+ */
+ atomic_cmpmask_and_set(&multiproc_module->ref_count,
+ MULTIPROC_MAKE_MAGICSTAMP(0),
+ MULTIPROC_MAKE_MAGICSTAMP(0));
+
+ if (atomic_inc_return(&multiproc_module->ref_count)
+ != MULTIPROC_MAKE_MAGICSTAMP(1u)) {
+ status = 1;
+ } else {
+ if (cfg == NULL) {
+ multiproc_get_config(&tmp_cfg);
+ cfg = &tmp_cfg;
+ }
+
+ memcpy(&multiproc_module->cfg, cfg,
+ sizeof(struct multiproc_config));
+ multiproc_module->id = cfg->id;
+ }
+
+ return status;
+}
+EXPORT_SYMBOL(multiproc_setup);
+
+/*
+ * ======== multiproc_setup ========
+ * Purpose:
+ * This function destroy the multiproc module.
+ * Once this function is called, other multiproc module APIs,
+ * except for the multiproc_get_config API cannot be called
+ * anymore.
+ */
+s32 multiproc_destroy(void)
+{
+ int status = 0;
+
+ if (atomic_cmpmask_and_lt(
+ &(multiproc_module->ref_count),
+ MULTIPROC_MAKE_MAGICSTAMP(0),
+ MULTIPROC_MAKE_MAGICSTAMP(1)) == true) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ atomic_dec_return(&multiproc_module->ref_count);
+
+exit:
+ return status;
+}
+EXPORT_SYMBOL(multiproc_destroy);
+
+/*
+ * ======== multiProc_set_local_id ========
+ * Purpose:
+ * This will set the processor id of local processor on run time
+ */
+int multiproc_set_local_id(u16 proc_id)
+{
+ int status = 0;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(
+ &(multiproc_module->ref_count),
+ MULTIPROC_MAKE_MAGICSTAMP(0),
+ MULTIPROC_MAKE_MAGICSTAMP(1)) == true)) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ if (WARN_ON(proc_id >= MULTIPROC_MAXPROCESSORS)) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ multiproc_module->cfg.id = proc_id;
+
+exit:
+ return status;
+}
+EXPORT_SYMBOL(multiproc_set_local_id);
+
+/*
+ * ======== multiProc_get_local_id ========
+ * Purpose:
+ * This will get the processor id from proccessor name
+ */
+u16 multiproc_get_id(const char *proc_name)
+{
+ s32 i;
+ u16 proc_id = MULTIPROC_INVALIDID;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(
+ &(multiproc_module->ref_count),
+ MULTIPROC_MAKE_MAGICSTAMP(0),
+ MULTIPROC_MAKE_MAGICSTAMP(1)) == true))
+ goto exit;
+
+ /* If the name is NULL, just return the local id */
+ if (proc_name == NULL)
+ proc_id = multiproc_module->cfg.id;
+ else {
+ for (i = 0; i < multiproc_module->cfg.num_processors ; i++) {
+ if (strcmp(proc_name,
+ &multiproc_module->cfg.name_list[i][0]) == 0) {
+ proc_id = i;
+ break;
+ }
+ }
+ }
+
+exit:
+ return proc_id;
+}
+EXPORT_SYMBOL(multiproc_get_id);
+
+/*
+ * ======== multiProc_set_local_id ========
+ * Purpose:
+ * This will get the processor name from proccessor id
+ */
+char *multiproc_get_name(u16 proc_id)
+{
+ char *proc_name = NULL;
+
+ /* On error condition return NULL pointer, else entry from name list */
+ if (WARN_ON(atomic_cmpmask_and_lt(
+ &(multiproc_module->ref_count),
+ MULTIPROC_MAKE_MAGICSTAMP(0),
+ MULTIPROC_MAKE_MAGICSTAMP(1)) == true))
+ goto exit;
+
+ if (WARN_ON(proc_id >= MULTIPROC_MAXPROCESSORS))
+ goto exit;
+
+ proc_name = multiproc_module->cfg.name_list[proc_id];
+
+exit:
+ return proc_name;
+}
+EXPORT_SYMBOL(multiproc_get_name);
+
+/*
+ * ======== multiproc_get_num_processors ========
+ * Purpose:
+ * This will get the number of processors in the system
+ */
+u16 multiproc_get_num_processors(void)
+{
+ return multiproc_module->cfg.num_processors;
+}
+EXPORT_SYMBOL(multiproc_get_num_processors);
+
+/*
+ * ======== multiproc_self ========
+ * Purpose:
+ * Return Id of current processor
+ */
+u16 multiproc_self(void)
+{
+ return multiproc_module->id;
+}
+EXPORT_SYMBOL(multiproc_self);
+
+/*
+ * ======== multiproc_get_slot ========
+ * Determines the offset for any two processors.
+ */
+u32 multiproc_get_slot(u16 remote_proc_id)
+{
+ u32 slot = 0u;
+ u32 i;
+ u32 j;
+ u32 small_id;
+ u32 large_id;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(
+ &(multiproc_module->ref_count),
+ MULTIPROC_MAKE_MAGICSTAMP(0),
+ MULTIPROC_MAKE_MAGICSTAMP(1)) == true))
+ goto exit;
+
+ if (remote_proc_id > multiproc_self()) {
+ small_id = multiproc_self();
+ large_id = remote_proc_id;
+ } else {
+ large_id = multiproc_self();
+ small_id = remote_proc_id;
+ }
+
+ /* determine what offset to create for the remote Proc Id */
+ for (i = 0; i < multiproc_module->cfg.num_processors; i++) {
+ for (j = i + 1; j < multiproc_module->cfg.num_processors; j++) {
+ if ((small_id == i) && (large_id == j))
+ break;
+ slot++;
+ }
+ }
+
+exit:
+ return slot;
+}
+EXPORT_SYMBOL(multiproc_get_slot);
diff --git a/drivers/dsp/syslink/multicore_ipc/multiproc_ioctl.c b/drivers/dsp/syslink/multicore_ipc/multiproc_ioctl.c
new file mode 100644
index 00000000000..79f6ed77b7d
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/multiproc_ioctl.c
@@ -0,0 +1,229 @@
+/*
+* multiproc_ioctl.c
+*
+* This provides the ioctl interface for multiproc module
+*
+* Copyright (C) 2008-2009 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 <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <ipc.h>
+#include <multiproc.h>
+#include <multiproc_ioctl.h>
+
+static struct resource_info *find_mproc_resource(
+ struct ipc_process_context *pr_ctxt,
+ unsigned int cmd,
+ struct multiproc_cmd_args *cargs)
+{
+ struct resource_info *info = NULL;
+ bool found = false;
+
+ spin_lock(&pr_ctxt->res_lock);
+
+ list_for_each_entry(info, &pr_ctxt->resources, res) {
+ if (info->cmd == cmd) {
+ switch (cmd) {
+ case CMD_MULTIPROC_DESTROY:
+ found = true;
+ break;
+ }
+ }
+ if (found == true)
+ break;
+ }
+
+ spin_unlock(&pr_ctxt->res_lock);
+
+ if (found == false)
+ info = NULL;
+
+ return info;
+}
+
+/*
+ * ======== mproc_ioctl_setup ========
+ * Purpose:
+ * This wrapper function will call the multproc function
+ * to setup the module
+ */
+static int mproc_ioctl_setup(struct multiproc_cmd_args *cargs)
+{
+ struct multiproc_config config;
+ s32 status = 0;
+ ulong size;
+
+ size = copy_from_user(&config,
+ (void __user *)cargs->args.setup.config,
+ sizeof(struct multiproc_config));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ cargs->api_status = multiproc_setup(&config);
+
+exit:
+ return status;
+}
+
+/*
+ * ======== mproc_ioctl_destroy ========
+ * Purpose:
+ * This wrapper function will call the multproc function
+ * to destroy the module
+ */
+static int mproc_ioctl_destroy(struct multiproc_cmd_args *cargs)
+{
+ cargs->api_status = multiproc_destroy();
+ return 0;
+}
+
+/*
+ * ======== mproc_ioctl_get_config ========
+ * Purpose:
+ * This wrapper function will call the multproc function
+ * to get the default configuration the module
+ */
+static int mproc_ioctl_get_config(struct multiproc_cmd_args *cargs)
+{
+ struct multiproc_config config;
+ u32 size;
+
+ multiproc_get_config(&config);
+ size = copy_to_user((void __user *)cargs->args.get_config.config,
+ &config, sizeof(struct multiproc_config));
+ if (size) {
+ cargs->api_status = -EFAULT;
+ return 0;
+ }
+ cargs->api_status = 0;
+ return 0;
+}
+
+/*
+ * ======== mproc_ioctl_setup ========
+ * Purpose:
+ * This wrapper function will call the multproc function
+ * to setup the module
+ */
+static int multiproc_ioctl_set_local_id(struct multiproc_cmd_args *cargs)
+{
+ cargs->api_status = multiproc_set_local_id(cargs->args.set_local_id.id);
+ return 0;
+}
+
+/*
+ * ======== multiproc_ioctl ========
+ * Purpose:
+ * This ioctl interface for multiproc module
+ */
+int multiproc_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user)
+{
+ s32 status = 0;
+ s32 size = 0;
+ struct multiproc_cmd_args __user *uarg =
+ (struct multiproc_cmd_args __user *)args;
+ struct multiproc_cmd_args cargs;
+ struct ipc_process_context *pr_ctxt =
+ (struct ipc_process_context *)filp->private_data;
+
+
+ if (user == true) {
+#ifdef CONFIG_SYSLINK_RECOVERY
+ if (ipc_recovering()) {
+ status = -EIO;
+ goto exit;
+ }
+#endif
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ status = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ status = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
+
+ if (status) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ /* Copy the full args from user-side */
+ size = copy_from_user(&cargs, uarg,
+ sizeof(struct multiproc_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ } else {
+ if (args != 0)
+ memcpy(&cargs, (void *)args,
+ sizeof(struct multiproc_cmd_args));
+ }
+
+ switch (cmd) {
+ case CMD_MULTIPROC_SETUP:
+ status = mproc_ioctl_setup(&cargs);
+ if (status == 0 && cargs.api_status >= 0)
+ add_pr_res(pr_ctxt, CMD_MULTIPROC_DESTROY, NULL);
+ break;
+
+ case CMD_MULTIPROC_DESTROY:
+ {
+ struct resource_info *info = NULL;
+
+ info = find_mproc_resource(pr_ctxt,
+ CMD_MULTIPROC_DESTROY,
+ &cargs);
+ status = mproc_ioctl_destroy(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_MULTIPROC_GETCONFIG:
+ status = mproc_ioctl_get_config(&cargs);
+ break;
+
+ case CMD_MULTIPROC_SETLOCALID:
+ status = multiproc_ioctl_set_local_id(&cargs);
+ break;
+
+ default:
+ WARN_ON(cmd);
+ cargs.api_status = -EFAULT;
+ status = -ENOTTY;
+ break;
+ }
+
+ if ((cargs.api_status == -ERESTARTSYS) || (cargs.api_status == -EINTR))
+ status = -ERESTARTSYS;
+
+ if (status < 0)
+ goto exit;
+
+
+ if (user == true) {
+ /* Copy the full args to the user-side. */
+ size = copy_to_user(uarg, &cargs,
+ sizeof(struct multiproc_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ }
+
+exit:
+ return status;
+
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/nameserver.c b/drivers/dsp/syslink/multicore_ipc/nameserver.c
new file mode 100644
index 00000000000..c164b78630b
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/nameserver.c
@@ -0,0 +1,1530 @@
+/*
+ * nameserver.c
+ *
+ * The nameserver module manages local name/value pairs that
+ * enables an application and other modules to store and retrieve
+ * values based on a name.
+ *
+ * Copyright (C) 2008-2009 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 <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <syslink/atomic_linux.h>
+
+#include <nameserver.h>
+#include <multiproc.h>
+#include <nameserver_remote.h>
+
+#define NS_MAX_NAME_LEN 32
+#define NS_MAX_RUNTIME_ENTRY (~0)
+#define NS_MAX_VALUE_LEN 4
+
+/*
+ * The dynamic name/value table looks like the following. This approach allows
+ * each instance table to have different value and different name lengths.
+ * The names block is allocated on the create. The size of that block is
+ * (max_runtime_entries * max_name_en). That block is sliced and diced up and
+ * given to each table entry.
+ * The same thing is done for the values block.
+ *
+ * names table values
+ * ------------- ------------- -------------
+ * | |<-\ | elem | /----->| |
+ * | | \-------| name | / | |
+ * | | | value |-/ | |
+ * | | | len | | |
+ * | |<-\ |-----------| | |
+ * | | \ | elem | | |
+ * | | \------| name | /------>| |
+ * | | | value |-/ | |
+ * ------------- | len | | |
+ * ------------- | |
+ * | |
+ * | |
+ * -------------
+ *
+ * There is an optimization for small values (e.g. <= sizeof(UInt32).
+ * In this case, there is no values block allocated. Instead the value
+ * field is used directly. This optimization occurs and is managed when
+ * obj->max_value_len <= sizeof(Us3232).
+ *
+ * The static create is a little different. The static entries point directly
+ * to a name string (and value). Since it points directly to static items,
+ * this entries cannot be removed.
+ * If max_runtime_entries is non-zero, a names and values block is created.
+ * Here is an example of a table with 1 static entry and 2 dynamic entries
+ *
+ * ------------
+ * this entries cannot be removed.
+ * If max_runtime_entries is non-zero, a names and values block is created.
+ * Here is an example of a table with 1 static entry and 2 dynamic entries
+ *
+ * ------------
+ * | elem |
+ * "myName" <-----------| name |----------> someValue
+ * | value |
+ * names | len | values
+ * ------------- ------------- -------------
+ * | |<-\ | elem | /----->| |
+ * | | \-------| name | / | |
+ * | | | value |-/ | |
+ * | | | len | | |
+ * | |<-\ |-----------| | |
+ * | | \ | elem | | |
+ * | | \------| name | /------>| |
+ * | | | value |-/ | |
+ * ------------- | len | | |
+ * ------------- | |
+ * | |
+ * | |
+ * -------------
+ *
+ * NameServerD uses a freeList and namelist to maintain the empty
+ * and filled-in entries. So when a name/value pair is added, an entry
+ * is pulled off the freeList, filled-in and placed on the namelist.
+ * The reverse happens on a remove.
+ *
+ * For static adds, the entries are placed on the namelist statically.
+ *
+ * For dynamic creates, the freeList is populated in postInt and there are no
+ * entries placed on the namelist (this happens when the add is called).
+ *
+ */
+
+/* Macro to make a correct module magic number with refCount */
+#define NAMESERVER_MAKE_MAGICSTAMP(x) ((NAMESERVER_MODULEID << 12u) | (x))
+
+/*
+ * A name/value table entry
+ */
+struct nameserver_table_entry {
+ struct list_head elem; /* List element */
+ u32 hash; /* Hash value */
+ char *name; /* Name portion of name/value pair */
+ u32 len; /* Length of the value field. */
+ void *buf; /* Value portion of name/value entry */
+ bool collide; /* Does the hash collides? */
+ struct nameserver_table_entry *next; /* Pointer to the next entry,
+ used incase of collision only */
+};
+
+/*
+ * A nameserver instance object
+ */
+struct nameserver_object {
+ struct list_head elem;
+ char *name; /* Name of the instance */
+ struct list_head name_list; /* Filled entries list */
+ struct mutex *gate_handle; /* Gate for critical regions */
+ struct nameserver_params params; /* The parameter structure */
+ u32 count; /* Counter for entries */
+};
+
+
+/* nameserver module state object */
+struct nameserver_module_object {
+ struct list_head obj_list; /* List holding created objects */
+ struct mutex *mod_gate_handle; /* Handle to module gate */
+ struct nameserver_remote_object **remote_handle_list;
+ /* List of Remote driver handles for processors */
+ atomic_t ref_count; /* Reference count */
+ struct nameserver_params def_inst_params;
+ /* Default instance paramters */
+ struct nameserver_config def_cfg; /* Default module configuration */
+ struct nameserver_config cfg; /* Module configuration */
+
+};
+
+/*
+ * Variable for holding state of the nameserver module.
+ */
+static struct nameserver_module_object nameserver_state = {
+ .def_cfg.reserved = 0x0,
+ .def_inst_params.max_runtime_entries = 0u,
+ .def_inst_params.table_heap = NULL,
+ .def_inst_params.check_existing = true,
+ .def_inst_params.max_value_len = 0u,
+ .def_inst_params.max_name_len = 16u,
+ .mod_gate_handle = NULL,
+ .remote_handle_list = NULL,
+};
+
+/*
+ * Pointer to the SharedRegion module state
+ */
+static struct nameserver_module_object *nameserver_module = &(nameserver_state);
+
+/*
+ * Lookup table for CRC calculation.
+ */
+static const u32 nameserver_crc_table[256u] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+/* Function to calculate hash for a string */
+static u32 _nameserver_string_hash(const char *string);
+
+#if 0
+/* This will return true if the entry is found in the table */
+static bool _nameserver_is_entry_found(const char *name, u32 hash,
+ struct list_head *list,
+ struct nameserver_table_entry **entry);
+#endif
+
+/* This will return true if the hash is found in the table */
+static bool _nameserver_is_hash_found(const char *name, u32 hash,
+ struct list_head *list,
+ struct nameserver_table_entry **entry);
+
+/* This will return true if entry is found in the hash collide list */
+static bool _nameserver_check_for_entry(const char *name,
+ struct nameserver_table_entry **entry);
+
+/* Function to get the default configuration for the NameServer module. */
+void nameserver_get_config(struct nameserver_config *cfg)
+{
+ s32 retval = 0;
+
+ if (WARN_ON(cfg == NULL)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (atomic_cmpmask_and_lt(&(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true) {
+ /* (If setup has not yet been called) */
+ memcpy(cfg, &nameserver_module->def_cfg,
+ sizeof(struct nameserver_config));
+ } else {
+ memcpy(cfg, &nameserver_module->cfg,
+ sizeof(struct nameserver_config));
+ }
+
+exit:
+ if (retval < 0)
+ pr_err("nameserver_get_config failed! retval = 0x%x", retval);
+ return;
+}
+EXPORT_SYMBOL(nameserver_get_config);
+
+/* This will setup the nameserver module */
+int nameserver_setup(void)
+{
+ struct nameserver_remote_object **list = NULL;
+ s32 retval = 0;
+ u16 nr_procs = 0;
+
+ /* This sets the ref_count variable if not initialized, upper 16 bits is
+ * written with module Id to ensure correctness of refCount variable
+ */
+ atomic_cmpmask_and_set(&nameserver_module->ref_count,
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(0));
+
+ if (atomic_inc_return(&nameserver_module->ref_count)
+ != NAMESERVER_MAKE_MAGICSTAMP(1)) {
+ return 1;
+ }
+
+ INIT_LIST_HEAD(&nameserver_state.obj_list),
+
+ nameserver_module->mod_gate_handle = kmalloc(sizeof(struct mutex),
+ GFP_KERNEL);
+ if (nameserver_module->mod_gate_handle == NULL) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+ /* mutex is initialized with state = UNLOCKED */
+ mutex_init(nameserver_module->mod_gate_handle);
+
+ nr_procs = multiproc_get_num_processors();
+ list = kmalloc(nr_procs * sizeof(struct nameserver_remote_object *),
+ GFP_KERNEL);
+ if (list == NULL) {
+ retval = -ENOMEM;
+ goto remote_alloc_fail;
+ }
+ memset(list, 0, nr_procs * sizeof(struct nameserver_remote_object *));
+ nameserver_module->remote_handle_list = list;
+
+ return 0;
+
+remote_alloc_fail:
+ kfree(nameserver_module->mod_gate_handle);
+exit:
+ pr_err("nameserver_setup failed, retval: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(nameserver_setup);
+
+/* This will destroy the nameserver module */
+int nameserver_destroy(void)
+{
+ s32 retval = 0;
+ struct mutex *lock = NULL;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (!(atomic_dec_return(&nameserver_module->ref_count)
+ == NAMESERVER_MAKE_MAGICSTAMP(0))) {
+ retval = 1;
+ goto exit;
+ }
+
+ if (WARN_ON(nameserver_module->mod_gate_handle == NULL)) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ /* If a nameserver instance exist, do not proceed */
+ if (!list_empty(&nameserver_module->obj_list)) {
+ retval = -EBUSY;
+ goto exit;
+ }
+
+ retval = mutex_lock_interruptible(nameserver_module->mod_gate_handle);
+ if (retval)
+ goto exit;
+
+ lock = nameserver_module->mod_gate_handle;
+ nameserver_module->mod_gate_handle = NULL;
+ mutex_unlock(lock);
+ kfree(lock);
+ kfree(nameserver_module->remote_handle_list);
+ nameserver_module->remote_handle_list = NULL;
+ return 0;
+
+exit:
+ if (retval < 0)
+ pr_err("nameserver_destroy failed, retval: %x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(nameserver_destroy);
+
+/* Initialize this config-params structure with supplier-specified
+ * defaults before instance creation. */
+void nameserver_params_init(struct nameserver_params *params)
+{
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(params == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ memcpy(params, &nameserver_module->def_inst_params,
+ sizeof(struct nameserver_params));
+
+exit:
+ if (retval < 0)
+ pr_err("nameserver_params_init failed! status = 0x%x", retval);
+ return;
+}
+EXPORT_SYMBOL(nameserver_params_init);
+
+/* This will create a name server instance */
+void *nameserver_create(const char *name,
+ const struct nameserver_params *params)
+{
+ struct nameserver_object *new_obj = NULL;
+ u32 name_len;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(params == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(name == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ name_len = strlen(name) + 1;
+ if (name_len > params->max_name_len) {
+ retval = -E2BIG;
+ goto exit;
+ }
+
+ retval = mutex_lock_interruptible(nameserver_module->mod_gate_handle);
+ if (retval)
+ goto exit;
+
+ /* check if the name is already registered or not */
+ new_obj = nameserver_get_handle(name);
+ if (new_obj != NULL) {
+ retval = -EEXIST;
+ goto error_handle;
+ }
+
+ new_obj = kmalloc(sizeof(struct nameserver_object), GFP_KERNEL);
+ if (new_obj == NULL) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ new_obj->name = kmalloc(name_len, GFP_ATOMIC);
+ if (new_obj->name == NULL) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ strncpy(new_obj->name, name, name_len);
+ memcpy(&new_obj->params, params, sizeof(struct nameserver_params));
+ if (params->max_value_len < sizeof(u32))
+ new_obj->params.max_value_len = sizeof(u32);
+ else
+ new_obj->params.max_value_len = params->max_value_len;
+
+ new_obj->gate_handle = kmalloc(sizeof(struct mutex), GFP_KERNEL);
+ if (new_obj->gate_handle == NULL) {
+ retval = -ENOMEM;
+ goto error_mutex;
+ }
+
+ mutex_init(new_obj->gate_handle);
+ new_obj->count = 0;
+ /* Put in the nameserver instance to local list */
+ INIT_LIST_HEAD(&new_obj->name_list);
+ INIT_LIST_HEAD(&new_obj->elem);
+ list_add(&new_obj->elem, &nameserver_module->obj_list);
+ mutex_unlock(nameserver_module->mod_gate_handle);
+ return (void *)new_obj;
+
+error_mutex:
+ kfree(new_obj->name);
+error:
+ kfree(new_obj);
+error_handle:
+ mutex_unlock(nameserver_module->mod_gate_handle);
+exit:
+ pr_err("nameserver_create failed retval:%x\n", retval);
+ return NULL;
+}
+EXPORT_SYMBOL(nameserver_create);
+
+/* Function to construct a name server. */
+void nameserver_construct(void *handle, const char *name,
+ const struct nameserver_params *params)
+{
+ struct nameserver_object *obj = NULL;
+ u32 name_len = 0;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(params == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(name == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(params->table_heap == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ /* check if the name is already registered or not */
+ if (nameserver_get_handle(name)) {
+ retval = -EEXIST; /* NameServer_E_ALREADYEXISTS */
+ goto exit;
+ }
+ name_len = strlen(name) + 1;
+ if (name_len > params->max_name_len) {
+ retval = -E2BIG;
+ goto exit;
+ }
+
+ obj = (struct nameserver_object *) handle;
+ /* Allocate memory for the name */
+ obj->name = kmalloc(name_len, GFP_ATOMIC);
+ if (obj->name == NULL) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ /* Copy the name */
+ strncpy(obj->name, name, strlen(name) + 1u);
+ /* Copy the params */
+ memcpy((void *) &obj->params, (void *) params,
+ sizeof(struct nameserver_params));
+
+ if (params->max_value_len < sizeof(u32))
+ obj->params.max_value_len = sizeof(u32);
+ else
+ obj->params.max_value_len = params->max_value_len;
+
+ /* Construct the list */
+ INIT_LIST_HEAD(&obj->name_list);
+
+ obj->gate_handle = kmalloc(sizeof(struct mutex), GFP_KERNEL);
+ if (obj->gate_handle == NULL) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+ mutex_init(obj->gate_handle);
+
+ /* Initialize the count */
+ obj->count = 0u;
+
+ /* Put in the local list */
+ retval = mutex_lock_interruptible(nameserver_module->mod_gate_handle);
+ if (retval)
+ goto exit;
+ INIT_LIST_HEAD(&obj->elem);
+ list_add(&obj->elem, &nameserver_module->obj_list);
+ mutex_unlock(nameserver_module->mod_gate_handle);
+
+exit:
+ if (retval < 0)
+ pr_err("nameserver_construct failed! retval = 0x%x", retval);
+ return;
+}
+
+/* This will delete a name server instance */
+int nameserver_delete(void **handle)
+{
+ struct nameserver_object *temp_obj = NULL;
+ struct mutex *gate_handle = NULL;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(*handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ temp_obj = (struct nameserver_object *) (*handle);
+ if (WARN_ON(unlikely((temp_obj->name == NULL) &&
+ (nameserver_get_handle(temp_obj->name) == NULL)))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ gate_handle = temp_obj->gate_handle;
+ retval = mutex_lock_interruptible(gate_handle);
+ if (retval)
+ goto exit;
+
+ /* Do not proceed if an entry in the in the table */
+ if (temp_obj->count != 0) {
+ retval = -EBUSY;
+ goto error;
+ }
+
+ retval = mutex_lock_interruptible(nameserver_module->mod_gate_handle);
+ if (retval)
+ goto error;
+ list_del(&temp_obj->elem);
+ mutex_unlock(nameserver_module->mod_gate_handle);
+
+ /* free the memory allocated for instance name */
+ kfree(temp_obj->name);
+ temp_obj->name = NULL;
+
+ /* Free the memory used for handle */
+ INIT_LIST_HEAD(&temp_obj->name_list);
+ kfree(temp_obj);
+ *handle = NULL;
+ mutex_unlock(gate_handle);
+ kfree(gate_handle);
+ return 0;
+
+error:
+ mutex_unlock(gate_handle);
+exit:
+ pr_err("nameserver_delete failed retval:%x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(nameserver_delete);
+
+/* Function to destroy a name server. */
+void nameserver_destruct(void *handle)
+{
+ struct nameserver_object *obj = NULL;
+ struct mutex *gate_handle = NULL;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct nameserver_object *) handle;
+ if (nameserver_get_handle(obj->name) == NULL) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ /* enter the critical section */
+ gate_handle = obj->gate_handle;
+ retval = mutex_lock_interruptible(gate_handle);
+ if (retval)
+ goto exit;
+ /* Do not proceed if an entry in the in the table */
+ if (obj->count != 0) {
+ retval = -EBUSY;
+ goto error;
+ }
+
+ retval = mutex_lock_interruptible(nameserver_module->mod_gate_handle);
+ if (retval)
+ goto error;
+ list_del(&obj->elem);
+ mutex_unlock(nameserver_module->mod_gate_handle);
+
+ /* free the memory allocated for the name */
+ kfree(obj->name);
+ obj->name = NULL;
+
+ /* Destruct the list */
+ INIT_LIST_HEAD(&obj->name_list);
+
+ /* Free the memory used for obj */
+ memset(obj, 0, sizeof(struct nameserver_object));
+
+ /* leave the critical section */
+ mutex_unlock(gate_handle);
+ kfree(gate_handle);
+ return;
+
+error:
+ /* leave the critical section */
+ mutex_unlock(obj->gate_handle);
+
+exit:
+ pr_err("nameserver_destruct failed! status = 0x%x", retval);
+ return;
+}
+
+/* This will add an entry into a nameserver instance */
+void *nameserver_add(void *handle, const char *name,
+ void *buf, u32 len)
+{
+ struct nameserver_table_entry *node = NULL;
+ struct nameserver_table_entry *new_node = NULL;
+ struct nameserver_object *temp_obj = NULL;
+ bool found = false;
+ bool exact_entry = false;
+ u32 hash;
+ u32 name_len;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(name == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(buf == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(len == 0))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ temp_obj = (struct nameserver_object *)handle;
+ retval = mutex_lock_interruptible(temp_obj->gate_handle);
+ if (retval)
+ goto exit;
+ if (temp_obj->count >= temp_obj->params.max_runtime_entries) {
+ retval = -ENOSPC;
+ goto error;
+ }
+
+ /* make the null char in to account */
+ name_len = strlen(name) + 1;
+ if (name_len > temp_obj->params.max_name_len) {
+ retval = -E2BIG;
+ goto error;
+ }
+
+ /* TODO : hash and collide ?? */
+ hash = _nameserver_string_hash(name);
+ found = _nameserver_is_hash_found(name, hash,
+ &temp_obj->name_list, &node);
+ if (found == true)
+ exact_entry = _nameserver_check_for_entry(name, &node);
+
+ if (exact_entry == true && temp_obj->params.check_existing == true) {
+ retval = -EEXIST;
+ goto error;
+ }
+
+ new_node = kmalloc(sizeof(struct nameserver_table_entry), GFP_KERNEL);
+ if (new_node == NULL) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ new_node->hash = hash;
+ new_node->collide = found;
+ new_node->len = len;
+ new_node->next = NULL;
+ new_node->name = kmalloc(name_len, GFP_KERNEL);
+ if (new_node->name == NULL) {
+ retval = -ENOMEM;
+ goto error_name;
+ }
+ new_node->buf = kmalloc(len, GFP_KERNEL);
+ if (new_node->buf == NULL) {
+ retval = -ENOMEM;
+ goto error_buf;
+ }
+
+ strncpy(new_node->name, name, name_len);
+ memcpy(new_node->buf, buf, len);
+ if (found == true) {
+ /* If hash is found, need to stitch the list to link the
+ * new node to the existing node with the same hash. */
+ new_node->next = node->next;
+ node->next = new_node;
+ node->collide = found;
+ } else
+ list_add(&new_node->elem, &temp_obj->name_list);
+ temp_obj->count++;
+ mutex_unlock(temp_obj->gate_handle);
+ return new_node;
+
+error_buf:
+ kfree(new_node->name);
+error_name:
+ kfree(new_node);
+error:
+ mutex_unlock(temp_obj->gate_handle);
+exit:
+ pr_err("nameserver_add failed status: %x\n", retval);
+ return NULL;
+}
+EXPORT_SYMBOL(nameserver_add);
+
+/* This will add a Uint32 value into a nameserver instance */
+void *nameserver_add_uint32(void *handle, const char *name,
+ u32 value)
+{
+ s32 retval = 0;
+ struct nameserver_table_entry *new_node = NULL;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(name == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ new_node = nameserver_add(handle, name, &value, sizeof(u32));
+
+exit:
+ if (retval < 0 || new_node == NULL) {
+ pr_err("nameserver_add_uint32 failed! status = 0x%x "
+ "new_node = 0x%x", retval, (u32)new_node);
+ }
+ return new_node;
+}
+EXPORT_SYMBOL(nameserver_add_uint32);
+
+/* This will remove a name/value pair from a name server */
+int nameserver_remove(void *handle, const char *name)
+{
+ struct nameserver_object *temp_obj = NULL;
+ struct nameserver_table_entry *entry = NULL;
+ struct nameserver_table_entry *prev = NULL;
+ bool found = false;
+ u32 hash;
+ u32 name_len;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(name == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ temp_obj = (struct nameserver_object *)handle;
+ name_len = strlen(name) + 1;
+ if (name_len > temp_obj->params.max_name_len) {
+ retval = -E2BIG;
+ goto exit;
+ }
+
+ retval = mutex_lock_interruptible(temp_obj->gate_handle);
+ if (retval)
+ goto exit;
+
+ hash = _nameserver_string_hash(name);
+ found = _nameserver_is_hash_found(name, hash,
+ &temp_obj->name_list, &entry);
+ if (found == false) {
+ retval = -ENOENT;
+ goto error;
+ }
+
+ if (entry->collide == true) {
+ if (strcmp(entry->name, name) == 0u) {
+ kfree(entry->buf);
+ kfree(entry->name);
+ entry->hash = entry->next->hash;
+ entry->name = entry->next->name;
+ entry->len = entry->next->len;
+ entry->buf = entry->next->buf;
+ entry->collide = entry->next->collide;
+ entry->next = entry->next->next;
+ kfree(entry->next);
+ temp_obj->count--;
+ } else {
+ found = false;
+ prev = entry;
+ entry = entry->next;
+ while (entry) {
+ if (strcmp(entry->name, name) == 0u) {
+ kfree(entry->buf);
+ kfree(entry->name);
+ prev->next = entry->next;
+ kfree(entry);
+ temp_obj->count--;
+ found = true;
+ break;
+ }
+ prev = entry;
+ entry = entry->next;
+ }
+ if (found == false) {
+ retval = -ENOENT;
+ goto error;
+ }
+ }
+ } else {
+ kfree(entry->buf);
+ kfree(entry->name);
+ list_del(&entry->elem);
+ kfree(entry);
+ temp_obj->count--;
+ }
+
+ mutex_unlock(temp_obj->gate_handle);
+ return 0;
+
+error:
+ mutex_unlock(temp_obj->gate_handle);
+exit:
+ pr_err("nameserver_remove failed status:%x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(nameserver_remove);
+
+/* This will remove a name/value pair from a name server */
+int nameserver_remove_entry(void *nshandle, void *nsentry)
+{
+ struct nameserver_table_entry *node = NULL;
+ struct nameserver_object *obj = NULL;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(nshandle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(nsentry == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct nameserver_object *)nshandle;
+ node = (struct nameserver_table_entry *)nsentry;
+ retval = mutex_lock_interruptible(obj->gate_handle);
+ if (retval)
+ goto exit;
+
+ kfree(node->buf);
+ kfree(node->name);
+ list_del(&node->elem);
+ kfree(node);
+ obj->count--;
+ mutex_unlock(obj->gate_handle);
+ return 0;
+
+exit:
+ pr_err("nameserver_remove_entry failed status:%x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(nameserver_remove_entry);
+
+
+/* This will retrieve the value portion of a name/value
+ * pair from local table */
+int nameserver_get_local(void *handle, const char *name,
+ void *value, u32 *len)
+{
+ struct nameserver_object *temp_obj = NULL;
+ struct nameserver_table_entry *entry = NULL;
+ bool found = false;
+ u32 hash;
+ u32 length = 0;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(name == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(value == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(len == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(*len == 0))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ length = *len;
+ temp_obj = (struct nameserver_object *)handle;
+ retval = mutex_lock_interruptible(temp_obj->gate_handle);
+ if (retval)
+ goto exit;
+
+ hash = _nameserver_string_hash(name);
+ found = _nameserver_is_hash_found(name, hash,
+ &temp_obj->name_list, &entry);
+ if (found == false) {
+ retval = -ENOENT;
+ goto error;
+ }
+
+ if (entry->collide == true) {
+ found = _nameserver_check_for_entry(name, &entry);
+ if (found == false) {
+ retval = -ENOENT;
+ goto error;
+ }
+ }
+
+ if (entry->len >= length) {
+ memcpy(value, entry->buf, length);
+ *len = length;
+ } else {
+ memcpy(value, entry->buf, entry->len);
+ *len = entry->len;
+ }
+
+error:
+ mutex_unlock(temp_obj->gate_handle);
+
+exit:
+ if (retval < 0)
+ pr_err("nameserver_get_local entry not found!\n");
+ return retval;
+}
+EXPORT_SYMBOL(nameserver_get_local);
+
+/* This will retrieve the value portion of a name/value
+ * pair from local table */
+int nameserver_get(void *handle, const char *name,
+ void *value, u32 *len, u16 proc_id[])
+{
+ struct nameserver_object *temp_obj = NULL;
+ u16 max_proc_id;
+ u16 local_proc_id;
+ s32 retval = -ENOENT;
+ u32 i;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(name == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(value == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(len == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(*len == 0))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ temp_obj = (struct nameserver_object *)handle;
+ max_proc_id = multiproc_get_num_processors();
+ local_proc_id = multiproc_self();
+ if (proc_id == NULL) {
+ retval = nameserver_get_local(temp_obj, name, value, len);
+ if (retval == -ENOENT) {
+ for (i = 0; i < max_proc_id; i++) {
+ /* Skip current processor */
+ if (i == local_proc_id)
+ continue;
+
+ if (nameserver_module->remote_handle_list[i] \
+ == NULL)
+ continue;
+
+ retval = nameserver_remote_get(
+ nameserver_module->
+ remote_handle_list[i],
+ temp_obj->name, name, value,
+ len, NULL);
+ if (retval >= 0 || ((retval < 0) &&
+ (retval != -ENOENT)))
+ break;
+ }
+ }
+ goto exit;
+ }
+
+ for (i = 0; i < max_proc_id; i++) {
+ /* Skip processor with invalid id */
+ if (proc_id[i] == MULTIPROC_INVALIDID)
+ continue;
+
+ if (i == local_proc_id) {
+ retval = nameserver_get_local(temp_obj,
+ name, value, len);
+ } else {
+ retval = nameserver_remote_get(
+ nameserver_module->
+ remote_handle_list[proc_id[i]],
+ temp_obj->name, name, value, len, NULL);
+ }
+ if (retval >= 0 || ((retval < 0) && (retval != -ENOENT)))
+ break;
+ }
+
+exit:
+ if (retval < 0)
+ pr_err("nameserver_get failed: status=%x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(nameserver_get);
+
+/* Gets a 32-bit value by name */
+int nameserver_get_uint32(void *handle, const char *name, void *value,
+ u16 proc_id[])
+{
+ /* Initialize retval to not found */
+ int retval = -ENOENT;
+ u32 len = sizeof(u32);
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(name == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(value == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ retval = nameserver_get(handle, name, value, &len, proc_id);
+
+exit:
+ /* -ENOENT is a valid run-time failure. */
+ if ((retval < 0) && (retval != -ENOENT))
+ pr_err("nameserver_get_uint32 failed! status = 0x%x", retval);
+ return retval;
+}
+EXPORT_SYMBOL(nameserver_get_uint32);
+
+/* Gets a 32-bit value by name from the local table
+ *
+ * If the name is found, the 32-bit value is copied into the value
+ * argument and a success retval is returned.
+ *
+ * If the name is not found, zero is returned in len and the contents
+ * of value are not modified. Not finding a name is not considered
+ * an error.
+ *
+ * This function only searches the local name/value table. */
+int nameserver_get_local_uint32(void *handle, const char *name, void *value)
+{
+ int retval = 0;
+ u32 len = sizeof(u32);
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(name == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(value == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ retval = nameserver_get_local(handle, name, value, &len);
+
+exit:
+ /* -ENOENT is a valid run-time failure. */
+ if ((retval < 0) && (retval != -ENOENT)) {
+ pr_err("nameserver_get_local_uint32 failed! "
+ "status = 0x%x", retval);
+ }
+ return retval;
+}
+EXPORT_SYMBOL(nameserver_get_local_uint32);
+
+/* This will retrieve the value portion of a name/value
+ * pair from local table. Returns the number of characters that
+ * matched with an entry. So if "abc" was an entry and you called
+ * match with "abcd", this function will have the "abc" entry.
+ * The return would be 3 since three characters matched */
+int nameserver_match(void *handle, const char *name, u32 *value)
+{
+ struct nameserver_object *temp_obj = NULL;
+ struct nameserver_table_entry *node = NULL;
+ struct nameserver_table_entry *temp = NULL;
+ u32 len = 0;
+ u32 found_len = 0;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(name == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(value == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ temp_obj = (struct nameserver_object *)handle;
+ retval = mutex_lock_interruptible(temp_obj->gate_handle);
+ if (retval)
+ goto exit;
+ list_for_each_entry(node, &temp_obj->name_list, elem) {
+ temp = node;
+ while (temp) {
+ len = strlen(temp->name);
+ if (len > found_len) {
+ if (strncmp(temp->name, name, len) == 0u) {
+ *value = (u32)temp->buf;
+ found_len = len;
+ }
+ }
+ temp = temp->next;
+ }
+ }
+ mutex_unlock(temp_obj->gate_handle);
+
+exit:
+ if (retval < 0)
+ pr_err("nameserver_match failed status:%x\n", retval);
+ return found_len;
+}
+EXPORT_SYMBOL(nameserver_match);
+
+/* This will get the handle of a nameserver instance from name */
+void *nameserver_get_handle(const char *name)
+{
+ struct nameserver_object *obj = NULL;
+ bool found = false;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(name == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ list_for_each_entry(obj, &nameserver_module->obj_list, elem) {
+ if (strcmp(obj->name, name) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (found == false) {
+ retval = -ENOENT;
+ goto exit;
+ }
+ return (void *)obj;
+
+exit:
+ pr_err("nameserver_get_handle failed! status = 0x%x", retval);
+ return (void *)NULL;
+}
+EXPORT_SYMBOL(nameserver_get_handle);
+
+/* =============================================================================
+ * Internal functions
+ * =============================================================================
+ */
+/* Function to register a remote driver for a processor */
+int nameserver_register_remote_driver(void *handle, u16 proc_id)
+{
+ s32 retval = 0;
+ u16 proc_count;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ proc_count = multiproc_get_num_processors();
+ if (WARN_ON(unlikely(proc_id >= proc_count))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ nameserver_module->remote_handle_list[proc_id] = \
+ (struct nameserver_remote_object *)handle;
+ return 0;
+
+exit:
+ pr_err("nameserver_register_remote_driver failed! "
+ "status:%x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(nameserver_register_remote_driver);
+
+/* Function to unregister a remote driver. */
+int nameserver_unregister_remote_driver(u16 proc_id)
+{
+ s32 retval = 0;
+ u16 proc_count;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ proc_count = multiproc_get_num_processors();
+ if (WARN_ON(proc_id >= proc_count)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ nameserver_module->remote_handle_list[proc_id] = NULL;
+ return 0;
+
+exit:
+ pr_err("nameserver_unregister_remote_driver failed! "
+ "status:%x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(nameserver_unregister_remote_driver);
+
+/* Determines if a remote driver is registered for the specified id. */
+bool nameserver_is_registered(u16 proc_id)
+{
+ bool registered = false;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_module->ref_count),
+ NAMESERVER_MAKE_MAGICSTAMP(0),
+ NAMESERVER_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(proc_id >= multiproc_get_num_processors()))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ registered = (nameserver_module->remote_handle_list[proc_id] != NULL);
+
+exit:
+ if (retval < 0) {
+ pr_err("nameserver_is_registered failed! "
+ "status = 0x%x", retval);
+ }
+ return registered;
+}
+EXPORT_SYMBOL(nameserver_is_registered);
+
+/* Function to calculate hash for a string */
+static u32 _nameserver_string_hash(const char *string)
+{
+ u32 i;
+ u32 hash ;
+ u32 len = strlen(string);
+
+ for (i = 0, hash = len; i < len; i++)
+ hash = (hash >> 8) ^
+ nameserver_crc_table[(hash & 0xff)] ^ string[i];
+
+ return hash;
+}
+
+#if 0
+/* This will return true if the entry is found in the table */
+static bool _nameserver_is_entry_found(const char *name, u32 hash,
+ struct list_head *list,
+ struct nameserver_table_entry **entry)
+{
+ struct nameserver_table_entry *node = NULL;
+ bool hash_match = false;
+ bool name_match = false;
+
+ list_for_each_entry(node, list, elem) {
+ /* Hash not matches, take next node */
+ if (node->hash == hash)
+ hash_match = true;
+ else
+ continue;
+ /* If the name matches, incase hash is duplicate */
+ if (strcmp(node->name, name) == 0)
+ name_match = true;
+
+ if (hash_match && name_match) {
+ if (entry != NULL)
+ *entry = node;
+ return true;
+ }
+
+ hash_match = false;
+ name_match = false;
+ }
+ return false;
+}
+#endif
+
+/* This will return true if the hash is found in the table */
+static bool _nameserver_is_hash_found(const char *name, u32 hash,
+ struct list_head *list,
+ struct nameserver_table_entry **entry)
+{
+ struct nameserver_table_entry *node = NULL;
+
+ /* No parameter checking as function is internal */
+
+ list_for_each_entry(node, list, elem) {
+ /* Hash not matches, take next node */
+ if (node->hash == hash) {
+ *entry = node;
+ return true;
+ }
+ }
+ return false;
+}
+
+/* This will return true if entry is found in the hash collide list */
+static bool _nameserver_check_for_entry(const char *name,
+ struct nameserver_table_entry **entry)
+{
+ struct nameserver_table_entry *temp = NULL;
+ bool found = false;
+
+ /* No parameter checking as function is internal */
+
+ temp = *entry;
+ while (temp) {
+ if (strcmp(((struct nameserver_table_entry *)temp)->name,
+ name) == 0u) {
+ *entry = temp;
+ found = true;
+ break;
+ }
+ temp = temp->next;
+ }
+
+ return found;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/nameserver_ioctl.c b/drivers/dsp/syslink/multicore_ipc/nameserver_ioctl.c
new file mode 100644
index 00000000000..2eaec1308e4
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/nameserver_ioctl.c
@@ -0,0 +1,686 @@
+/*
+* nameserver_ioctl.c
+*
+* This provides the ioctl interface for nameserver module
+*
+* Copyright (C) 2008-2009 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 <linux/uaccess.h>
+#include <linux/types.h>
+#include <linux/bug.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <ipc.h>
+#include <nameserver.h>
+#include <nameserver_ioctl.h>
+
+/*
+ * FUNCTIONS NEED TO BE REVIEWED OPTIMIZED!
+ */
+
+static struct resource_info *find_nameserver_resource(
+ struct ipc_process_context *pr_ctxt,
+ unsigned int cmd,
+ struct nameserver_cmd_args *cargs)
+{
+ struct resource_info *info = NULL;
+ bool found = false;
+
+ spin_lock(&pr_ctxt->res_lock);
+
+ list_for_each_entry(info, &pr_ctxt->resources, res) {
+ struct nameserver_cmd_args *args =
+ (struct nameserver_cmd_args *)info->data;
+ if (info->cmd == cmd) {
+ switch (cmd) {
+ case CMD_NAMESERVER_DELETE:
+ {
+ void *handle =
+ args->args.delete_instance.handle;
+ void *temp =
+ cargs->args.delete_instance.handle;
+ if (temp == handle)
+ found = true;
+ break;
+ }
+ case CMD_NAMESERVER_DESTROY:
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found == true)
+ break;
+ }
+ }
+
+ spin_unlock(&pr_ctxt->res_lock);
+
+ if (found == false)
+ info = NULL;
+
+ return info;
+}
+
+/*
+ * ======== nameserver_ioctl_setup ========
+ * Purpose:
+ * This wrapper function will call the nameserver function to
+ * setup nameserver module
+ */
+static int nameserver_ioctl_setup(
+ struct nameserver_cmd_args *cargs)
+{
+ cargs->api_status = nameserver_setup();
+ return 0;
+}
+
+/*
+ * ======== nameserver_ioctl_destroy ========
+ * Purpose:
+ * This wrapper function will call the nameserver function to
+ * destroy nameserver module
+ */
+static int nameserver_ioctl_destroy(
+ struct nameserver_cmd_args *cargs)
+{
+ cargs->api_status = nameserver_destroy();
+ return 0;
+}
+
+/*
+ * ======== nameserver_ioctl_params_init ========
+ * Purpose:
+ * This wrapper function will call the nameserver function to
+ * get the default configuration of a nameserver instance
+ */
+static int nameserver_ioctl_params_init(struct nameserver_cmd_args *cargs)
+{
+ struct nameserver_params params;
+ s32 status = 0;
+ ulong size;
+
+ nameserver_params_init(&params);
+ size = copy_to_user((void __user *)cargs->args.params_init.params,
+ &params, sizeof(struct nameserver_params));
+ if (size)
+ status = -EFAULT;
+ cargs->api_status = 0;
+ return status;
+}
+
+/*
+ * ======== nameserver_ioctl_get_handle ========
+ * Purpose:
+ * This wrapper function will call the nameserver function to
+ * get the handle of a nameserver instance from name
+ */
+static int nameserver_ioctl_get_handle(struct nameserver_cmd_args *cargs)
+{
+ void *handle = NULL;
+ char *name = NULL;
+ s32 status = 0;
+ ulong size;
+
+ name = kmalloc(cargs->args.get_handle.name_len, GFP_KERNEL);
+ if (name == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ name[cargs->args.get_handle.name_len] = '\0';
+ size = copy_from_user(name, (void __user *)cargs->args.get_handle.name,
+ cargs->args.get_handle.name_len);
+ if (size) {
+ status = -EFAULT;
+ goto name_from_usr_error;
+ }
+
+ handle = nameserver_get_handle(name);
+ cargs->args.get_handle.handle = handle;
+ cargs->api_status = 0;
+
+name_from_usr_error:
+ kfree(name);
+
+exit:
+ return status;
+}
+
+/*
+ * ======== nameserver_ioctl_create ========
+ * Purpose:
+ * This wrapper function will call the nameserver function to
+ * create a name server instance
+ */
+static int nameserver_ioctl_create(struct nameserver_cmd_args *cargs)
+{
+ struct nameserver_params params;
+ void *handle = NULL;
+ char *name = NULL;
+ s32 status = 0;
+ ulong size;
+
+ name = kmalloc(cargs->args.create.name_len, GFP_KERNEL);
+ if (name == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ name[cargs->args.get_handle.name_len] = '\0';
+ size = copy_from_user(name, (void __user *)cargs->args.create.name,
+ cargs->args.create.name_len);
+ if (size) {
+ status = -EFAULT;
+ goto copy_from_usr_error;
+ }
+
+ size = copy_from_user(&params, (void __user *)cargs->args.create.params,
+ sizeof(struct nameserver_params));
+ if (size) {
+ status = -EFAULT;
+ goto copy_from_usr_error;
+ }
+
+ handle = nameserver_create(name, &params);
+ cargs->args.create.handle = handle;
+ cargs->api_status = 0;
+
+copy_from_usr_error:
+ kfree(name);
+
+exit:
+ return status;
+}
+
+
+/*
+ * ======== nameserver_ioctl_delete ========
+ * Purpose:
+ * This wrapper function will call the nameserver function to
+ * delete a name server instance
+ */
+static int nameserver_ioctl_delete(struct nameserver_cmd_args *cargs)
+{
+ cargs->api_status =
+ nameserver_delete(&cargs->args.delete_instance.handle);
+ return 0;
+}
+
+/*
+ * ======== nameserver_ioctl_add ========
+ * Purpose:
+ * This wrapper function will call the nameserver function to
+ * add an entry into a nameserver instance
+ */
+static int nameserver_ioctl_add(struct nameserver_cmd_args *cargs)
+{
+ char *name = NULL;
+ char *buf = NULL;
+ void *entry;
+ s32 status = 0;
+ ulong size;
+
+ name = kmalloc(cargs->args.add.name_len, GFP_KERNEL);
+ if (name == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ name[cargs->args.get_handle.name_len] = '\0';
+ size = copy_from_user(name, (void __user *)cargs->args.add.name,
+ cargs->args.add.name_len);
+ if (size) {
+ status = -EFAULT;
+ goto name_from_usr_error;
+ }
+
+ buf = kmalloc(cargs->args.add.len, GFP_KERNEL);
+ if (buf == NULL) {
+ status = -ENOMEM;
+ goto buf_alloc_error;
+ }
+
+ size = copy_from_user(buf, (void __user *)cargs->args.add.buf,
+ cargs->args.add.len);
+ if (size) {
+ status = -EFAULT;
+ goto buf_from_usr_error;
+ }
+
+ entry = nameserver_add(cargs->args.add.handle, name, buf,
+ cargs->args.add.len);
+ cargs->args.add.entry = entry;
+ cargs->args.add.node = entry;
+ cargs->api_status = 0;
+
+buf_from_usr_error:
+ kfree(buf);
+
+buf_alloc_error: /* Fall through */
+name_from_usr_error:
+ kfree(name);
+
+exit:
+ return status;
+}
+
+
+/*
+ * ======== nameserver_ioctl_add_uint32 ========
+ * Purpose:
+ * This wrapper function will call the nameserver function to
+ * add a Uint32 entry into a nameserver instance
+ */
+static int nameserver_ioctl_add_uint32(struct nameserver_cmd_args *cargs)
+{
+ char *name = NULL;
+ void *entry;
+ s32 status = 0;
+ ulong size;
+
+ name = kmalloc(cargs->args.addu32.name_len, GFP_KERNEL);
+ if (name == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ name[cargs->args.get_handle.name_len] = '\0';
+ size = copy_from_user(name, (void __user *)cargs->args.addu32.name,
+ cargs->args.addu32.name_len);
+ if (size) {
+ status = -EFAULT;
+ goto name_from_usr_error;
+ }
+
+ entry = nameserver_add_uint32(cargs->args.addu32.handle, name,
+ cargs->args.addu32.value);
+ cargs->args.addu32.entry = entry;
+ cargs->api_status = 0;
+
+name_from_usr_error:
+ kfree(name);
+
+exit:
+ return status;
+}
+
+
+/*
+ * ======== nameserver_ioctl_match ========
+ * Purpose:
+ * This wrapper function will call the nameserver function
+ * to retrieve the value portion of a name/value
+ * pair from local table
+ */
+static int nameserver_ioctl_match(struct nameserver_cmd_args *cargs)
+{
+ char *name = NULL;
+ s32 status = 0;
+ ulong size;
+
+ name = kmalloc(cargs->args.match.name_len, GFP_KERNEL);
+ if (name == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ name[cargs->args.get_handle.name_len] = '\0';
+ size = copy_from_user(name, (void __user *)cargs->args.match.name,
+ cargs->args.match.name_len);
+ if (size) {
+ status = -EFAULT;
+ goto name_from_usr_error;
+ }
+
+ cargs->args.match.count = nameserver_match(cargs->args.match.handle,
+ name, &cargs->args.match.value);
+ cargs->api_status = 0;
+
+name_from_usr_error: /* Fall through */
+ kfree(name);
+
+exit:
+ return status;
+}
+
+/*
+ * ======== nameserver_ioctl_remove ========
+ * Purpose:
+ * This wrapper function will call the nameserver function to
+ * remove a name/value pair from a name server
+ */
+static int nameserver_ioctl_remove(struct nameserver_cmd_args *cargs)
+{
+ char *name = NULL;
+ s32 status = 0;
+ ulong size;
+
+ name = kmalloc(cargs->args.remove.name_len, GFP_KERNEL);
+ if (name == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ name[cargs->args.get_handle.name_len] = '\0';
+ size = copy_from_user(name, (void __user *)cargs->args.remove.name,
+ cargs->args.remove.name_len);
+ if (size) {
+ status = -EFAULT;
+ goto name_from_usr_error;
+ }
+
+ cargs->api_status =
+ nameserver_remove(cargs->args.remove.handle, name);
+
+name_from_usr_error:
+ kfree(name);
+
+exit:
+ return status;
+}
+
+
+/*
+ * ======== nameserver_ioctl_remove_entry ========
+ * Purpose:
+ * This wrapper function will call the nameserver function to
+ * remove an entry from a name server
+ */
+static int nameserver_ioctl_remove_entry(struct nameserver_cmd_args *cargs)
+{
+ cargs->api_status = nameserver_remove_entry(
+ cargs->args.remove_entry.handle,
+ cargs->args.remove_entry.entry);
+ return 0;
+}
+
+/*
+ * ======== nameserver_ioctl_get_local ========
+ * Purpose:
+ * This wrapper function will call the nameserver function to
+ * retrieve the value portion of a name/value pair from local table
+ */
+static int nameserver_ioctl_get_local(struct nameserver_cmd_args *cargs)
+{
+ char *name = NULL;
+ char *value = NULL;
+ s32 status = 0;
+ ulong size;
+
+ name = kmalloc(cargs->args.get_local.name_len, GFP_KERNEL);
+ if (name == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ name[cargs->args.get_handle.name_len] = '\0';
+ value = kmalloc(cargs->args.get_local.len, GFP_KERNEL);
+ if (value == NULL) {
+ status = -ENOMEM;
+ goto value_alloc_error;
+ }
+
+ size = copy_from_user(name, (void __user *)cargs->args.get_local.name,
+ cargs->args.get_local.name_len);
+ if (size) {
+ status = -EFAULT;
+ goto name_from_usr_error;
+ }
+
+ cargs->api_status = nameserver_get_local(
+ cargs->args.get_local.handle, name,
+ value, &cargs->args.get_local.len);
+ size = copy_to_user((void __user *)cargs->args.get_local.value, value,
+ cargs->args.get_local.len);
+ if (size)
+ status = -EFAULT;
+
+name_from_usr_error:
+ kfree(value);
+
+value_alloc_error:
+ kfree(name);
+
+exit:
+ return status;
+}
+
+
+/*
+ * ======== nameserver_ioctl_get ========
+ * Purpose:
+ * This wrapper function will call the nameserver function to
+ * retrieve the value portion of a name/value pair from table
+ */
+static int nameserver_ioctl_get(struct nameserver_cmd_args *cargs)
+{
+ char *name = NULL;
+ char *value = NULL;
+ u16 *proc_id = NULL;
+ s32 status = 0;
+ ulong size;
+
+ name = kmalloc(cargs->args.get.name_len, GFP_KERNEL);
+ if (name == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ name[cargs->args.get_handle.name_len] = '\0';
+ value = kmalloc(cargs->args.get.len, GFP_KERNEL);
+ if (value == NULL) {
+ status = -ENOMEM;
+ goto value_alloc_error;
+ }
+
+ if (cargs->args.get.proc_len > 0) {
+ proc_id = kmalloc(cargs->args.get.proc_len, GFP_KERNEL);
+ if (proc_id == NULL) {
+ status = -ENOMEM;
+ goto proc_alloc_error;
+ }
+ }
+
+ size = copy_from_user(name, (void __user *)cargs->args.get.name,
+ cargs->args.get.name_len);
+ if (size) {
+ status = -EFAULT;
+ goto name_from_usr_error;
+ }
+
+ status = copy_from_user(proc_id, (void __user *)cargs->args.get.proc_id,
+ cargs->args.get.proc_len);
+ if (size) {
+ status = -EFAULT;
+ goto proc_from_usr_error;
+ }
+
+ cargs->api_status = nameserver_get(cargs->args.get.handle, name, value,
+ &cargs->args.get.len, proc_id);
+ size = copy_to_user((void __user *)cargs->args.get.value, value,
+ cargs->args.get.len);
+ if (size)
+ status = -EFAULT;
+
+
+proc_from_usr_error: /* Fall through */
+name_from_usr_error:
+ kfree(proc_id);
+
+proc_alloc_error:
+ kfree(value);
+
+value_alloc_error:
+ kfree(name);
+
+exit:
+ return status;
+}
+
+/*
+ * ======== nameserver_ioctl ========
+ * Purpose:
+ * This ioctl interface for nameserver module
+ */
+int nameserver_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user)
+{
+ s32 status = 0;
+ s32 size = 0;
+ struct nameserver_cmd_args __user *uarg =
+ (struct nameserver_cmd_args __user *)args;
+ struct nameserver_cmd_args cargs;
+ struct ipc_process_context *pr_ctxt =
+ (struct ipc_process_context *)filp->private_data;
+
+
+ if (user == true) {
+#ifdef CONFIG_SYSLINK_RECOVERY
+ if (ipc_recovering()) {
+ status = -EIO;
+ goto exit;
+ }
+#endif
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ status = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ status = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
+
+ if (status) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ /* Copy the full args from user-side */
+ size = copy_from_user(&cargs, uarg,
+ sizeof(struct nameserver_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ } else {
+ if (args != 0)
+ memcpy(&cargs, (void *)args,
+ sizeof(struct nameserver_cmd_args));
+ }
+
+ switch (cmd) {
+ case CMD_NAMESERVER_ADD:
+ status = nameserver_ioctl_add(&cargs);
+ break;
+
+ case CMD_NAMESERVER_ADDUINT32:
+ status = nameserver_ioctl_add_uint32(&cargs);
+ break;
+
+ case CMD_NAMESERVER_GET:
+ status = nameserver_ioctl_get(&cargs);
+ break;
+
+ case CMD_NAMESERVER_GETLOCAL:
+ status = nameserver_ioctl_get_local(&cargs);
+ break;
+
+ case CMD_NAMESERVER_MATCH:
+ status = nameserver_ioctl_match(&cargs);
+ break;
+
+ case CMD_NAMESERVER_REMOVE:
+ status = nameserver_ioctl_remove(&cargs);
+ break;
+
+ case CMD_NAMESERVER_REMOVEENTRY:
+ status = nameserver_ioctl_remove_entry(&cargs);
+ break;
+
+ case CMD_NAMESERVER_PARAMS_INIT:
+ status = nameserver_ioctl_params_init(&cargs);
+ break;
+
+ case CMD_NAMESERVER_CREATE:
+ status = nameserver_ioctl_create(&cargs);
+ if (status >= 0) {
+ struct nameserver_cmd_args *temp = kmalloc(
+ sizeof(struct nameserver_cmd_args),
+ GFP_KERNEL);
+ if (WARN_ON(!temp)) {
+ status = -ENOMEM;
+ goto exit;
+ }
+ temp->args.delete_instance.handle =
+ cargs.args.create.handle;
+ add_pr_res(pr_ctxt, CMD_NAMESERVER_DELETE,
+ (void *)temp);
+ }
+ break;
+
+ case CMD_NAMESERVER_DELETE:
+ {
+ struct resource_info *info = NULL;
+ info = find_nameserver_resource(pr_ctxt,
+ CMD_NAMESERVER_DELETE,
+ &cargs);
+ status = nameserver_ioctl_delete(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_NAMESERVER_GETHANDLE:
+ status = nameserver_ioctl_get_handle(&cargs);
+ break;
+
+ case CMD_NAMESERVER_SETUP:
+ status = nameserver_ioctl_setup(&cargs);
+ if (cargs.api_status >= 0)
+ add_pr_res(pr_ctxt, CMD_NAMESERVER_DESTROY, NULL);
+ break;
+
+ case CMD_NAMESERVER_DESTROY:
+ {
+ struct resource_info *info = NULL;
+ info = find_nameserver_resource(pr_ctxt,
+ CMD_NAMESERVER_DESTROY,
+ &cargs);
+ status = nameserver_ioctl_destroy(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ default:
+ WARN_ON(cmd);
+ cargs.api_status = -EFAULT;
+ status = -ENOTTY;
+ break;
+ }
+
+ if ((cargs.api_status == -ERESTARTSYS) || (cargs.api_status == -EINTR))
+ status = -ERESTARTSYS;
+
+ if (status < 0)
+ goto exit;
+
+ if (user == true) {
+ /* Copy the full args to the user-side. */
+ size = copy_to_user(uarg, &cargs,
+ sizeof(struct nameserver_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ }
+
+exit:
+ return status;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/nameserver_remote.c b/drivers/dsp/syslink/multicore_ipc/nameserver_remote.c
new file mode 100644
index 00000000000..b958227d40c
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/nameserver_remote.c
@@ -0,0 +1,46 @@
+/*
+ * nameserver_remote.c
+ *
+ * Copyright (C) 2008-2009 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 <linux/types.h>
+#include <linux/slab.h>
+
+#include <nameserver_remote.h>
+
+/* This will get data from remote name server */
+int nameserver_remote_get(const struct nameserver_remote_object *handle,
+ const char *instance_name, const char *name,
+ void *value, u32 *value_len, void *reserved)
+{
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(handle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (WARN_ON(unlikely(((instance_name == NULL) || (name == NULL)
+ || (value == NULL) || (value_len == NULL))))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ retval = handle->get(handle, instance_name,
+ name, value, value_len, NULL);
+
+exit:
+ if (retval < 0)
+ pr_err("nameserver_remote_get failed! status = 0x%x", retval);
+ return retval;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/nameserver_remotenotify.c b/drivers/dsp/syslink/multicore_ipc/nameserver_remotenotify.c
new file mode 100644
index 00000000000..7584fdbf170
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/nameserver_remotenotify.c
@@ -0,0 +1,824 @@
+/*
+ * nameserver_remotenotify.c
+ *
+ * The nameserver_remotenotify module provides functionality to get name
+ * value pair from a remote nameserver.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+/* Standard headers */
+#include <linux/types.h>
+
+/* Utilities headers */
+#include <linux/string.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/semaphore.h>
+
+/* Syslink headers */
+#include <syslink/atomic_linux.h>
+
+/* Module level headers */
+#include <multiproc.h>
+#include <sharedregion.h>
+#include <gate_remote.h>
+#include <gatemp.h>
+#include <nameserver.h>
+#include <nameserver_remotenotify.h>
+#include <notify.h>
+
+
+/*
+ * Macro to make a correct module magic number with refCount
+ */
+#define NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(x) \
+ ((NAMESERVERREMOTENOTIFY_MODULEID << 12u) | (x))
+
+/*
+ * Cache line length
+ * TODO: Short-term hack. Make parameter or figure out some other way!
+ */
+#define NAMESERVERREMOTENOTIFY_CACHESIZE 128
+
+/*
+ * Maximum length of value buffer that can be stored in the NameServer
+ * managed by this NameServerRemoteNotify instance. Value in 4-byte words
+ */
+#define NAMESERVERREMOTENOTIFY_MAXVALUEBUFLEN 75
+
+/* Defines the nameserver_remotenotify state object, which contains all the
+ * module specific information
+ */
+struct nameserver_remotenotify_module_object {
+ struct nameserver_remotenotify_config cfg;
+ struct nameserver_remotenotify_config def_cfg;
+ struct nameserver_remotenotify_params def_inst_params;
+ bool is_setup;
+ void *gate_handle;
+ atomic_t ref_count;
+ void *nsr_handles[MULTIPROC_MAXPROCESSORS];
+};
+
+/*
+ * NameServer remote transport packet definition
+ */
+struct nameserver_remotenotify_message {
+ u32 request; /* If this is a request set to 1 */
+ u32 response; /* If this is a response set to 1 */
+ u32 request_status; /* If request sucessful set to 1 */
+ u32 value; /* Holds value if len <= 4 */
+ u32 value_len; /* Len of value */
+ u32 instance_name[8]; /* Name of NameServer instance */
+ u32 name[8]; /* Size is 8 to align to 128 cache line boundary */
+ u32 value_buf[NAMESERVERREMOTENOTIFY_MAXVALUEBUFLEN];
+ /* Supports up to 300-byte value */
+};
+
+/*
+ * NameServer remote transport state object definition
+ */
+struct nameserver_remotenotify_obj {
+ struct nameserver_remotenotify_message *msg[2];
+ struct nameserver_remotenotify_params params;
+ u16 region_id;
+ u16 remote_proc_id;
+ bool cache_enable;
+ struct mutex *local_gate;
+ void *gatemp;
+ struct semaphore *sem_handle; /* Binary semaphore */
+ u16 notify_event_id;
+};
+
+/*
+ * NameServer remote transport state object definition
+ */
+struct nameserver_remotenotify_object {
+ int (*get)(void *,
+ const char *instance_name, const char *name,
+ void *value, u32 value_len, void *reserved);
+ void *obj; /* Implementation specific object */
+};
+
+/*
+ * nameserver_remotenotify state object variable
+ */
+static struct nameserver_remotenotify_module_object
+ nameserver_remotenotify_state = {
+ .is_setup = false,
+ .gate_handle = NULL,
+ .def_cfg.notify_event_id = 1u,
+ .def_inst_params.gatemp = NULL,
+ .def_inst_params.shared_addr = NULL,
+};
+
+static void _nameserver_remotenotify_callback(u16 proc_id, u16 line_id,
+ u32 event_id, uint *arg, u32 payload);
+
+/*
+ * This will get the default configuration for the nameserver remote
+ * module. This function can be called by the application to get their
+ * configuration parameter to nameserver_remotenotify_setup filled
+ * in by the nameserver_remotenotify module with the default
+ * parameters. If the user does not wish to make any change in the
+ * default parameters, this API is not required to be called
+ */
+void nameserver_remotenotify_get_config(
+ struct nameserver_remotenotify_config *cfg)
+{
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(cfg == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (nameserver_remotenotify_state.is_setup == false)
+ memcpy(cfg, &(nameserver_remotenotify_state.def_cfg),
+ sizeof(struct nameserver_remotenotify_config));
+ else
+ memcpy(cfg, &(nameserver_remotenotify_state.cfg),
+ sizeof(struct nameserver_remotenotify_config));
+
+exit:
+ if (retval < 0) {
+ pr_err("nameserver_remotenotify_get_config failed!"
+ " retval = 0x%x", retval);
+ }
+ return;
+}
+EXPORT_SYMBOL(nameserver_remotenotify_get_config);
+
+/*
+ * This will setup the nameserver_remotenotify module
+ * This function sets up the nameserver_remotenotify module. This
+ * function must be called before any other instance-level APIs can
+ * be invoked
+ * Module-level configuration needs to be provided to this
+ * function. If the user wishes to change some specific config
+ * parameters, then nameserver_remotenotify_get_config can be called
+ * to get the configuration filled with the default values. After
+ * this, only the required configuration values can be changed. If
+ * the user does not wish to make any change in the default
+ * parameters, the application can simply call
+ * nameserver_remotenotify_setup with NULL parameters. The default
+ * parameters would get automatically used
+ */
+int nameserver_remotenotify_setup(struct nameserver_remotenotify_config *cfg)
+{
+ struct nameserver_remotenotify_config tmp_cfg;
+ s32 retval = 0;
+ struct mutex *lock = NULL;
+
+ /* This sets the ref_count variable is not initialized, upper 16 bits is
+ * written with module Id to ensure correctness of refCount variable.
+ */
+ atomic_cmpmask_and_set(&nameserver_remotenotify_state.ref_count,
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(0),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(0));
+ if (atomic_inc_return(&nameserver_remotenotify_state.ref_count)
+ != NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(1)) {
+ return 1;
+ }
+
+ if (cfg == NULL) {
+ nameserver_remotenotify_get_config(&tmp_cfg);
+ cfg = &tmp_cfg;
+ }
+
+ /* Create a default gate handle for local module protection */
+ lock = kmalloc(sizeof(struct mutex), GFP_KERNEL);
+ if (lock == NULL) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+ mutex_init(lock);
+ nameserver_remotenotify_state.gate_handle = lock;
+
+ memcpy(&nameserver_remotenotify_state.cfg, cfg,
+ sizeof(struct nameserver_remotenotify_config));
+ memset(&nameserver_remotenotify_state.nsr_handles, 0,
+ (sizeof(void *) * MULTIPROC_MAXPROCESSORS));
+ nameserver_remotenotify_state.is_setup = true;
+ return 0;
+
+exit:
+ pr_err("nameserver_remotenotify_setup failed! retval = 0x%x",
+ retval);
+ return retval;
+}
+EXPORT_SYMBOL(nameserver_remotenotify_setup);
+
+/*
+ * This will destroy the nameserver_remotenotify module.
+ * Once this function is called, other nameserver_remotenotify
+ * module APIs, except for the nameserver_remotenotify_get_config
+ * API cannot be called anymore.
+ */
+int nameserver_remotenotify_destroy(void)
+{
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_remotenotify_state.ref_count),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(0),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (!(atomic_dec_return(&nameserver_remotenotify_state.ref_count)
+ == NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(0))) {
+ retval = 1;
+ goto exit;
+ }
+
+ kfree(nameserver_remotenotify_state.gate_handle);
+
+ nameserver_remotenotify_state.is_setup = false;
+ return 0;
+
+exit:
+ pr_err("nameserver_remotenotify_destroy failed! retval = 0x%x",
+ retval);
+ return retval;
+}
+EXPORT_SYMBOL(nameserver_remotenotify_destroy);
+
+/* This will get the current configuration values */
+void nameserver_remotenotify_params_init(
+ struct nameserver_remotenotify_params *params)
+{
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_remotenotify_state.ref_count),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(0),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ pr_err("nameserver_remotenotify_params_init failed: "
+ "Module is not initialized!\n");
+ return;
+ }
+
+ if (WARN_ON(unlikely(params == NULL))) {
+ pr_err("nameserver_remotenotify_params_init failed: "
+ "Argument of type(nameserver_remotenotify_params *) "
+ "is NULL!\n");
+ return;
+ }
+
+ memcpy(params, &(nameserver_remotenotify_state.def_inst_params),
+ sizeof(struct nameserver_remotenotify_params));
+
+}
+EXPORT_SYMBOL(nameserver_remotenotify_params_init);
+
+/* This will be called when a notify event is received */
+static void _nameserver_remotenotify_callback(u16 proc_id, u16 line_id,
+ u32 event_id, uint *arg, u32 payload)
+{
+ struct nameserver_remotenotify_obj *handle = NULL;
+ u16 offset = 0;
+ void *nshandle = NULL;
+ u32 value_len;
+ int *key;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_remotenotify_state.ref_count),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(0),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(arg == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(proc_id >= multiproc_get_num_processors()))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ handle = (struct nameserver_remotenotify_obj *)arg;
+ if ((multiproc_self() > proc_id))
+ offset = 1;
+
+#if 0
+ if (handle->cache_enable) {
+ /* write back shared memory that was modified */
+ Cache_wbInv(handle->msg[0],
+ sizeof(struct nameserver_remotenotify_message) << 1,
+ Cache_Type_ALL, TRUE);
+ }
+#endif
+
+ if (handle->msg[1 - offset]->request != true)
+ goto signal_response;
+
+ /* This is a request */
+ value_len = handle->msg[1 - offset]->value_len;
+ nshandle = nameserver_get_handle((const char *)
+ handle->msg[1 - offset]->instance_name);
+ if (nshandle != NULL) {
+ /* Search for the NameServer entry */
+ if (value_len == sizeof(u32)) {
+ retval = nameserver_get_local_uint32(nshandle,
+ (const char *) handle->msg[1 - offset]->
+ name, &handle->msg[1 - offset]->value);
+ } else {
+ retval = nameserver_get_local(nshandle,
+ (const char *) handle->msg[1 - offset]->
+ name,
+ &handle->msg[1 - offset]->value_buf,
+ &value_len);
+ }
+ }
+ BUG_ON(retval != 0 && retval != -ENOENT);
+
+ key = gatemp_enter(handle->gatemp);
+ if (retval == 0) {
+ handle->msg[1 - offset]->request_status = true;
+ handle->msg[1 - offset]->value_len = value_len;
+ }
+ /* Send a response back */
+ handle->msg[1 - offset]->response = true;
+ handle->msg[1 - offset]->request = false;
+
+#if 0
+ if (handle->cache_enable) {
+ /* write back shared memory that was modified */
+ Cache_wbInv(handle->msg[1 - offset],
+ sizeof(struct nameserver_remotenotify_message),
+ Cache_Type_ALL, TRUE);
+ }
+#endif
+ /* now we can leave the gate */
+ gatemp_leave(handle->gatemp, key);
+
+ /*
+ * The NotifyDriver handle must exists at this point,
+ * otherwise the notify_sendEvent should have failed
+ */
+ retval = notify_send_event(handle->remote_proc_id, 0,
+ (handle->notify_event_id | (NOTIFY_SYSTEMKEY << 16)),
+ 0xCBC7, false);
+
+signal_response:
+ if (handle->msg[offset]->response == true)
+ up(handle->sem_handle);
+
+exit:
+ if (retval < 0) {
+ pr_err("nameserver_remotenotify_callback failed! "
+ "status = 0x%x\n", retval);
+ }
+ return;
+}
+
+/* This will get a remote name value pair */
+int nameserver_remotenotify_get(void *rhandle, const char *instance_name,
+ const char *name, void *value, u32 *value_len,
+ void *reserved)
+{
+ struct nameserver_remotenotify_object *handle = NULL;
+ struct nameserver_remotenotify_obj *obj = NULL;
+ s32 offset = 0;
+ s32 len;
+ int *key;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_remotenotify_state.ref_count),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(0),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(rhandle == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(instance_name == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(name == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(value == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(value_len == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely((*value_len == 0) || \
+ (*value_len > NAMESERVERREMOTENOTIFY_MAXVALUEBUFLEN)))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ handle = (struct nameserver_remotenotify_object *)rhandle;
+ obj = (struct nameserver_remotenotify_obj *)handle->obj;
+ if (multiproc_self() > obj->remote_proc_id)
+ offset = 1;
+
+#if 0
+ if (obj->cache_enable) {
+ /* write back shared memory that was modified */
+ Cache_wbInv(obj->msg[offset],
+ sizeof(struct nameserver_remotenotify_message),
+ Cache_Type_ALL, TRUE);
+ }
+#endif
+ /* Allow only one request to be procesed at a time */
+ retval = mutex_lock_interruptible(obj->local_gate);
+ if (retval)
+ goto exit;
+
+ key = gatemp_enter(obj->gatemp);
+ /* This is a request message */
+ obj->msg[offset]->request = 1;
+ obj->msg[offset]->response = 0;
+ obj->msg[offset]->request_status = 0;
+ obj->msg[offset]->value_len = *value_len;
+ len = strlen(instance_name) + 1; /* Take termination null char */
+ if (len >= 32) {
+ retval = -EINVAL;
+ goto inval_len_error;
+ }
+ strncpy((char *)obj->msg[offset]->instance_name, instance_name, len);
+ len = strlen(name) + 1;
+ if (len >= 32) {
+ retval = -EINVAL;
+ goto inval_len_error;
+ }
+ strncpy((char *)obj->msg[offset]->name, name, len);
+
+ /* Send the notification to remote processor */
+ retval = notify_send_event(obj->remote_proc_id, 0,
+ (obj->notify_event_id | (NOTIFY_SYSTEMKEY << 16)),
+ 0x8307, /* Payload */
+ false); /* Not sending a payload */
+ if (retval < 0) {
+ /* Undo previous operations */
+ obj->msg[offset]->request = 0;
+ obj->msg[offset]->value_len = 0;
+ goto notify_error;
+ }
+ gatemp_leave(obj->gatemp, key);
+
+ /* Pend on the semaphore */
+ retval = down_interruptible(obj->sem_handle);
+ if (retval)
+ goto down_error;
+
+ key = gatemp_enter(obj->gatemp);
+
+ if (obj->cache_enable) {
+#if 0
+ /* write back shared memory that was modified */
+ Cache_wbInv(obj->msg[offset],
+ sizeof(struct nameserver_remotenotify_message),
+ Cache_Type_ALL, TRUE);
+#endif
+ }
+ if (obj->msg[offset]->request_status != true) {
+ retval = -ENOENT;
+ goto request_error;
+ }
+
+ if (obj->msg[offset]->value_len == sizeof(u32))
+ memcpy((void *)value, (void *) &(obj->msg[offset]->value),
+ sizeof(u32));
+ else
+ memcpy((void *)value, (void *)&(obj->msg[offset]->value_buf),
+ obj->msg[offset]->value_len);
+ *value_len = obj->msg[offset]->value_len;
+
+ obj->msg[offset]->request_status = false;
+ retval = 0;
+
+inval_len_error:
+notify_error:
+request_error:
+ obj->msg[offset]->request = 0;
+ obj->msg[offset]->response = 0;
+ gatemp_leave(obj->gatemp, key);
+down_error:
+ /* un-block so that subsequent requests can be honored */
+ mutex_unlock(obj->local_gate);
+exit:
+ if (retval < 0)
+ pr_err("nameserver_remotenotify_get failed! "
+ "status = 0x%x", retval);
+ return retval;
+}
+EXPORT_SYMBOL(nameserver_remotenotify_get);
+
+/* This will setup the nameserver remote module */
+void *nameserver_remotenotify_create(u16 remote_proc_id,
+ const struct nameserver_remotenotify_params *params)
+{
+ struct nameserver_remotenotify_object *handle = NULL;
+ struct nameserver_remotenotify_obj *obj = NULL;
+ u32 offset = 0;
+ s32 retval = 0;
+ s32 retval1 = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_remotenotify_state.ref_count),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(0),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely((remote_proc_id == multiproc_self()) &&
+ (remote_proc_id >= multiproc_get_num_processors())))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(params == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(params->shared_addr == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ obj = kzalloc(sizeof(struct nameserver_remotenotify_obj), GFP_KERNEL);
+ handle = kmalloc(sizeof(struct nameserver_remotenotify_object),
+ GFP_KERNEL);
+ if (obj == NULL || handle == NULL) {
+ retval = -ENOMEM;
+ goto mem_error;
+ }
+
+ handle->get = (void *)&nameserver_remotenotify_get;
+ handle->obj = (void *)obj;
+ obj->local_gate = kmalloc(sizeof(struct mutex), GFP_KERNEL);
+ if (obj->local_gate == NULL) {
+ retval = -ENOMEM;
+ goto mem_error;
+ }
+
+ obj->remote_proc_id = remote_proc_id;
+ if (multiproc_self() > remote_proc_id)
+ offset = 1;
+
+ obj->region_id = sharedregion_get_id(params->shared_addr);
+ if (((u32) params->shared_addr % sharedregion_get_cache_line_size(
+ obj->region_id)) != 0) {
+ retval = -EFAULT;
+ goto notify_error;
+ }
+
+ obj->msg[0] = (struct nameserver_remotenotify_message *)
+ (params->shared_addr);
+ obj->msg[1] = (struct nameserver_remotenotify_message *)
+ ((u32)obj->msg[0] +
+ sizeof(struct nameserver_remotenotify_message));
+ obj->gatemp = params->gatemp;
+ obj->remote_proc_id = remote_proc_id;
+ obj->notify_event_id = \
+ nameserver_remotenotify_state.cfg.notify_event_id;
+ /* Clear out self shared structures */
+ memset(obj->msg[offset], 0,
+ sizeof(struct nameserver_remotenotify_message));
+ memcpy((void *)&obj->params, (void *)params,
+ sizeof(struct nameserver_remotenotify_params));
+
+ /* determine cacheability of the object from the regionId */
+ obj->cache_enable = sharedregion_is_cache_enabled(obj->region_id);
+ if (obj->cache_enable) {
+#if 0
+ /* write back shared memory that was modified */
+ Cache_wbInv(obj->msg[offset],
+ sizeof(struct nameserver_remotenotify_message),
+ Cache_Type_ALL, TRUE);
+#endif
+ }
+
+ retval = notify_register_event_single(remote_proc_id,
+ 0, /* TBD: Interrupt line id */
+ (obj->notify_event_id | \
+ (NOTIFY_SYSTEMKEY << 16)),
+ _nameserver_remotenotify_callback,
+ (void *)obj);
+ if (retval < 0)
+ goto notify_error;
+
+ retval = nameserver_register_remote_driver((void *)handle,
+ remote_proc_id);
+ obj->sem_handle = kzalloc(sizeof(struct semaphore), GFP_KERNEL);
+ if (obj->sem_handle == NULL) {
+ retval = -ENOMEM;
+ goto sem_alloc_error;
+ }
+
+ sema_init(obj->sem_handle, 0);
+ /* its is at the end since its init state = unlocked? */
+ mutex_init(obj->local_gate);
+ return (void *)handle;
+
+sem_alloc_error:
+ nameserver_unregister_remote_driver(remote_proc_id);
+ /* Do we want to check the staus ? */
+ retval1 = notify_unregister_event_single(obj->remote_proc_id, 0,
+ (obj->notify_event_id | (NOTIFY_SYSTEMKEY << 16)));
+
+notify_error:
+ kfree(obj->local_gate);
+
+mem_error:
+ kfree(obj);
+ kfree(handle);
+
+exit:
+ pr_err("nameserver_remotenotify_create failed! "
+ "status = 0x%x\n", retval);
+ return NULL;
+}
+EXPORT_SYMBOL(nameserver_remotenotify_create);
+
+/* This will delete the nameserver remote transport instance */
+int nameserver_remotenotify_delete(void **rhandle)
+{
+ struct nameserver_remotenotify_object *handle = NULL;
+ struct nameserver_remotenotify_obj *obj = NULL;
+ s32 retval = 0;
+ s32 retval1 = 0;
+ struct mutex *gate = NULL;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_remotenotify_state.ref_count),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(0),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely((rhandle == NULL) || (*rhandle == NULL)))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ handle = (struct nameserver_remotenotify_object *)(*rhandle);
+ obj = (struct nameserver_remotenotify_obj *)handle->obj;
+ if (obj == NULL) {
+ retval = -EINVAL;
+ goto free_handle;
+ }
+
+ gate = obj->local_gate;
+ retval = mutex_lock_interruptible(gate);
+ if (retval)
+ goto free_handle;
+
+ kfree(obj->sem_handle);
+ obj->sem_handle = NULL;
+
+ retval1 = nameserver_unregister_remote_driver(obj->remote_proc_id);
+ /* Do we have to bug_on/warn_on oops here intead of exit ?*/
+ if (retval1 < 0 && retval >= 0)
+ retval = retval1;
+
+ /* Unregister the event from Notify */
+ retval1 = notify_unregister_event_single(obj->remote_proc_id, 0,
+ (obj->notify_event_id | (NOTIFY_SYSTEMKEY << 16)));
+ if (retval1 < 0 && retval >= 0)
+ retval = retval1;
+ kfree(obj);
+ mutex_unlock(gate);
+ kfree(gate);
+
+free_handle:
+ kfree(handle);
+ *rhandle = NULL;
+
+exit:
+ if (retval < 0) {
+ pr_err("nameserver_remotenotify_delete failed! "
+ "status = 0x%x\n", retval);
+ }
+ return retval;
+}
+EXPORT_SYMBOL(nameserver_remotenotify_delete);
+
+/* This will give shared memory requirements for the
+ * nameserver remote transport instance */
+uint nameserver_remotenotify_shared_mem_req(const
+ struct nameserver_remotenotify_params *params)
+{
+ uint total_size = 0;
+
+ /* params is not used- to remove warning. */
+ (void)params;
+
+ /* Two Message structs are required. One for sending request and
+ * another one for sending response. */
+ if (multiproc_get_num_processors() > 1)
+ total_size = \
+ (2 * sizeof(struct nameserver_remotenotify_message));
+
+ return total_size;
+}
+EXPORT_SYMBOL(nameserver_remotenotify_shared_mem_req);
+
+int nameserver_remotenotify_attach(u16 remote_proc_id, void *shared_addr)
+{
+ struct nameserver_remotenotify_params nsr_params;
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_remotenotify_state.ref_count),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(0),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(shared_addr == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(gatemp_get_default_remote() == NULL))) {
+ retval = -1;
+ goto exit;
+ }
+
+ /* Use default GateMP */
+ nameserver_remotenotify_params_init(&nsr_params);
+ nsr_params.gatemp = gatemp_get_default_remote();
+ nsr_params.shared_addr = shared_addr;
+
+ /* create only if notify driver has been created to remote proc */
+ if (!notify_is_registered(remote_proc_id, 0)) {
+ retval = -1;
+ goto exit;
+ }
+
+ nameserver_remotenotify_state.nsr_handles[remote_proc_id] =
+ nameserver_remotenotify_create(remote_proc_id, &nsr_params);
+ if (nameserver_remotenotify_state.nsr_handles[remote_proc_id] == NULL) {
+ retval = -1;
+ goto exit;
+ }
+ return 0;
+
+exit:
+ pr_err("nameserver_remotenotify_attach failed! status = 0x%x",
+ retval);
+ return retval;
+}
+
+static void *_nameserver_remotenotify_get_handle(u16 remote_proc_id)
+{
+ void *handle = NULL;
+
+ if (remote_proc_id <= multiproc_get_num_processors()) {
+ handle = \
+ nameserver_remotenotify_state.nsr_handles[remote_proc_id];
+ }
+
+ return handle;
+};
+
+
+int nameserver_remotenotify_detach(u16 remote_proc_id)
+{
+ void *handle = NULL;
+ int retval = 0;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(nameserver_remotenotify_state.ref_count),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(0),
+ NAMESERVERREMOTENOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ handle = _nameserver_remotenotify_get_handle(remote_proc_id);
+ if (handle == NULL) {
+ retval = -1;
+ goto exit;
+ }
+
+ nameserver_remotenotify_delete(&handle);
+ nameserver_remotenotify_state.nsr_handles[remote_proc_id] = NULL;
+ return 0;
+
+exit:
+ pr_err("nameserver_remotenotify_detach failed! status = 0x%x",
+ retval);
+ return retval;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/platform.c b/drivers/dsp/syslink/multicore_ipc/platform.c
new file mode 100644
index 00000000000..5ae0127faa1
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/platform.c
@@ -0,0 +1,1932 @@
+/*
+ * platform.c
+ *
+ * Implementation of platform initialization logic for Syslink IPC.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+
+/* Standard header files */
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+/* SysLink device specific headers */
+#include "../procmgr/proc4430/proc4430.h"
+
+/* Ipu Power Management Header (ipu_pm) */
+#include "../ipu_pm/ipu_pm.h"
+/* Module level headers */
+#include <multiproc.h>
+#include <platform.h>
+#include <gatemp.h>
+#include <gatepeterson.h>
+#include <gatehwspinlock.h>
+#include <sharedregion.h>
+#include <listmp.h>
+#include <_listmp.h>
+#include <heap.h>
+#include <heapbufmp.h>
+#include <heapmemmp.h>
+#include <messageq.h>
+#include <transportshm.h>
+#include <notify.h>
+#include <ipc.h>
+
+#include <notify_ducatidriver.h>
+#include <nameserver.h>
+#include <nameserver_remote.h>
+#include <nameserver_remotenotify.h>
+#include <procmgr.h>
+
+#include <platform_mem.h>
+
+
+/** ============================================================================
+ * Macros.
+ * ============================================================================
+ */
+#define RESETVECTOR_SYMBOL "_Ipc_ResetVector"
+
+/** ============================================================================
+ * Application specific configuration, please change these value according to
+ * your application's need.
+ * ============================================================================
+ */
+/*! @brief Start of IPC shared memory */
+#define SHAREDMEMORY_PHY_BASEADDR CONFIG_DUCATI_BASEIMAGE_PHYS_ADDR
+#define SHAREDMEMORY_PHY_BASESIZE 0x00100000
+
+/*! @brief Start of IPC shared memory for SysM3 */
+#define SHAREDMEMORY_PHY_BASEADDR_SR0 SHAREDMEMORY_PHY_BASEADDR
+#define SHAREDMEMORY_PHY_BASESIZE_SR0 0x00054000
+
+/*! @brief Start of IPC shared memory AppM3 */
+#define SHAREDMEMORY_PHY_BASEADDR_SR1 (SHAREDMEMORY_PHY_BASEADDR + 0x54000)
+#define SHAREDMEMORY_PHY_BASESIZE_SR1 0x000AC000
+
+/*! @brief Start of IPC SHM for SysM3 */
+#define SHAREDMEMORY_SLV_VRT_BASEADDR_SR0 0xA0000000
+#define SHAREDMEMORY_SLV_VRT_DSP_BASEADDR_SR0 0x30000000
+#define SHAREDMEMORY_SLV_VRT_BASESIZE_SR0 0x00054000
+
+/*! @brief Start of IPC SHM for AppM3 */
+#define SHAREDMEMORY_SLV_VRT_BASEADDR_SR1 0xA0054000
+#define SHAREDMEMORY_SLV_VRT_DSP_BASEADDR_SR1 0x30054000
+#define SHAREDMEMORY_SLV_VRT_BASESIZE_SR1 0x000AC000
+
+/*! @brief Start of Code memory for SysM3 */
+#define SHAREDMEMORY_SLV_VRT_CODE0_BASEADDR 0x00000000
+#define SHAREDMEMORY_SLV_VRT_CODE0_BASESIZE 0x00100000
+
+/*! @brief Start of Code section for SysM3 */
+#define SHAREDMEMORY_PHY_CODE0_BASEADDR (SHAREDMEMORY_PHY_BASEADDR + 0x100000)
+#define SHAREDMEMORY_PHY_CODE0_BASESIZE 0x00100000
+
+/*! @brief Start of Code memory for SysM3 */
+#define SHAREDMEMORY_SLV_VRT_CODE1_BASEADDR 0x00100000
+#define SHAREDMEMORY_SLV_VRT_CODE1_BASESIZE 0x00300000
+
+/*! @brief Start of Code section for SysM3 */
+#define SHAREDMEMORY_PHY_CODE1_BASEADDR (SHAREDMEMORY_PHY_CODE0_BASEADDR + \
+ SHAREDMEMORY_SLV_VRT_CODE1_BASEADDR)
+#define SHAREDMEMORY_PHY_CODE1_BASESIZE 0x00300000
+
+/*! @brief Start of Const section for SysM3 */
+#define SHAREDMEMORY_PHY_CONST0_BASEADDR (SHAREDMEMORY_PHY_CODE0_BASEADDR + \
+ 0x1000000)
+#define SHAREDMEMORY_PHY_CONST0_BASESIZE 0x00040000
+
+/*! @brief Start of Const section for SysM3 */
+#define SHAREDMEMORY_SLV_VRT_CONST0_BASEADDR 0x80000000
+#define SHAREDMEMORY_SLV_VRT_CONST0_BASESIZE 0x00040000
+
+/*! @brief Start of Const section for AppM3 */
+#define SHAREDMEMORY_PHY_CONST1_BASEADDR (SHAREDMEMORY_PHY_CONST0_BASEADDR + \
+ 0x100000)
+#define SHAREDMEMORY_PHY_CONST1_BASESIZE 0x00180000
+
+/*! @brief Start of Const section for AppM3 */
+#define SHAREDMEMORY_SLV_VRT_CONST1_BASEADDR 0x80100000
+#define SHAREDMEMORY_SLV_VRT_CONST1_BASESIZE 0x00180000
+
+/*! @brief Start of EXT_RAM section for Tesla */
+#define SHAREDMEMORY_PHY_EXT_RAM_BASEADDR \
+ (CONFIG_DUCATI_BASEIMAGE_PHYS_ADDR - 0x2F00000)
+#define SHAREDMEMORY_PHY_EXT_RAM_BASESIZE 0x02000000
+
+/*! @brief Start of Code memory for Tesla */
+#define SHAREDMEMORY_SLV_VRT_CODE_DSP_BASEADDR 0x20000000
+#define SHAREDMEMORY_SLV_VRT_CODE_DSP_BASESIZE 0x00080000
+
+/*! @brief Start of Code section for Tesla */
+#define SHAREDMEMORY_PHY_CODE_DSP_BASEADDR \
+ (SHAREDMEMORY_PHY_BASEADDR - 0x300000)
+#define SHAREDMEMORY_PHY_CODE_DSP_BASESIZE 0x00080000
+
+/*! @brief Start of Const section for Tesla */
+#define SHAREDMEMORY_SLV_VRT_CONST_DSP_BASEADDR 0x20080000
+#define SHAREDMEMORY_SLV_VRT_CONST_DSP_BASESIZE 0x00080000
+
+/*! @brief Start of Const section for Tesla */
+#define SHAREDMEMORY_PHY_CONST_DSP_BASEADDR \
+ (SHAREDMEMORY_PHY_CODE_DSP_BASEADDR + \
+ SHAREDMEMORY_PHY_CODE_DSP_BASESIZE)
+#define SHAREDMEMORY_PHY_CONST_DSP_BASESIZE 0x00080000
+
+/*! @brief Start of EXT_RAM section for Tesla */
+#define SHAREDMEMORY_SLV_VRT_EXT_RAM_BASEADDR 0x20000000
+#define SHAREDMEMORY_SLV_VRT_EXT_RAM_BASESIZE 0x02000000
+
+#define USE_NEW_PROCMGR 0
+
+/** ============================================================================
+ * Struct & Enums.
+ * ============================================================================
+ */
+
+/* Struct for reading platform specific gate peterson configuration values */
+struct platform_gaterpeterson_params {
+ u32 shared_mem_addr; /* Shared memory address */
+ u32 shared_mem_size; /* Shared memory size */
+ u32 remote_proc_id; /* Remote processor identifier */
+};
+
+struct platform_notify_ducatidrv_params {
+ u32 shared_mem_addr; /* Shared memory address */
+ u32 shared_mem_size; /* Shared memory size */
+ u16 remote_proc_id; /* Remote processor identifier */
+};
+
+struct platform_nameserver_remotenotify_params {
+ u32 shared_mem_addr; /* Shared memory address */
+ u32 shared_mem_size; /* Shared memory size */
+ u32 notify_event_no; /* Notify Event number to used */
+};
+
+struct platform_heapbuf_params {
+ u32 shared_mem_addr; /* Shared memory address */
+ u32 shared_mem_size; /* Shared memory size */
+ u32 shared_buf_addr; /* Shared memory address */
+ u32 shared_buf_size; /* Shared memory size */
+ u32 num_blocks;
+ u32 block_size;
+};
+
+struct platform_transportshm_params {
+ u32 shared_mem_addr; /* Shared memory address */
+ u32 shared_mem_size; /* Shared memory size */
+ u32 notify_event_no; /* Notify Event number */
+};
+
+/** ============================================================================
+ * Application specific configuration, please change these value according to
+ * your application's need.
+ * ============================================================================
+ */
+/*
+ * Structure defining config parameters for overall System.
+ */
+struct platform_config {
+ struct multiproc_config multiproc_config;
+ /* multiproc_config parameter */
+
+ struct gatemp_config gatemp_config;
+ /* gatemp_config parameter */
+
+ struct gatepeterson_config gatepeterson_config;
+ /* gatepeterson_config parameter */
+
+ struct gatehwspinlock_config gatehwspinlock_config;
+ /* gatehwspinlock parameter */
+
+ struct sharedregion_config sharedregion_config;
+ /* sharedregion_config parameter */
+
+ struct messageq_config messageq_config;
+ /* messageq_config parameter */
+
+ struct notify_config notify_config;
+ /* notify config parameter */
+ struct ipu_pm_config ipu_pm_config;
+ /* ipu_pm config parameter */
+
+ struct proc_mgr_config proc_mgr_config;
+ /* processor manager config parameter */
+
+ struct heapbufmp_config heapbufmp_config;
+ /* heapbufmp_config parameter */
+
+ struct heapmemmp_config heapmemmp_config;
+ /* heapmemmp_config parameter */
+#if 0
+
+ struct heapmultibuf_config heapmultibuf_config;
+ /* heapmultibuf_config parameter */
+#endif
+ struct listmp_config listmp_config;
+ /* listmp_config parameter */
+
+ struct transportshm_config transportshm_config;
+ /* transportshm_config parameter */
+#if 0
+ struct ringio_config ringio_config;
+ /* ringio_config parameter */
+
+ struct ringiotransportshm_config ringiotransportshm_config;
+ /* ringiotransportshm_config parameter */
+#endif
+ struct notify_ducatidrv_config notify_ducatidrv_config;
+ /* notify_ducatidrv_config parameter */
+
+ struct nameserver_remotenotify_config nameserver_remotenotify_config;
+ /* nameserver_remotenotify_config parameter */
+#if 0
+ struct clientnotifymgr_config clinotifymgr_config_params;
+ /* clientnotifymgr_config parameter */
+
+ struct frameqbufmgr_config frameqbufmgr_config_params;
+ /* frameqbufmgr_config parameter */
+
+ struct frameq_config frameq_config_params;
+ /* frameq_config parameter */
+#endif
+};
+
+
+/* struct embedded into slave binary */
+struct platform_slave_config {
+ u32 cache_line_size;
+ u32 br_offset;
+ u32 sr0_memory_setup;
+ u32 setup_messageq;
+ u32 setup_notify;
+ u32 setup_ipu_pm;
+ u32 proc_sync;
+ u32 num_srs;
+};
+
+struct platform_proc_config_params {
+ u32 use_notify;
+ u32 use_messageq;
+ u32 use_heapbuf;
+ u32 use_frameq;
+ u32 use_ring_io;
+ u32 use_listmp;
+ u32 use_nameserver;
+};
+
+/* shared region configuration */
+struct platform_slave_sr_config {
+ u32 entry_base;
+ u32 entry_len;
+ u32 owner_proc_id;
+ u32 id;
+ u32 create_heap;
+ u32 cache_line_size;
+};
+
+/* Shared region configuration information for host side. */
+struct platform_host_sr_config {
+ u16 ref_count;
+};
+
+/* structure for platform instance */
+struct platform_object {
+ void *pm_handle;
+ /* handle to the proc_mgr instance used */
+ void *phandle;
+ /* handle to the processor instance used */
+ struct platform_slave_config slave_config;
+ /* slave embedded config */
+ struct platform_slave_sr_config *slave_sr_config;
+ /* shared region details from slave */
+};
+
+
+/* structure for platform instance */
+struct platform_module_state {
+ bool multiproc_init_flag;
+ /* multiproc initialize flag */
+ bool gatemp_init_flag;
+ /* gatemp initialize flag */
+ bool gatepeterson_init_flag;
+ /* gatepeterson initialize flag */
+ bool gatehwspinlock_init_flag;
+ /* gatehwspinlock initialize flag */
+ bool sharedregion_init_flag;
+ /* sharedregion initialize flag */
+ bool listmp_init_flag;
+ /* listmp initialize flag */
+ bool messageq_init_flag;
+ /* messageq initialize flag */
+ bool ringio_init_flag;
+ /* ringio initialize flag */
+ bool notify_init_flag;
+ /* notify initialize flag */
+ bool ipu_pm_init_flag;
+ /* ipu_pm initialize flag */
+ bool proc_mgr_init_flag;
+ /* processor manager initialize flag */
+ bool heapbufmp_init_flag;
+ /* heapbufmp initialize flag */
+ bool heapmemmp_init_flag;
+ /* heapmemmp initialize flag */
+ bool heapmultibuf_init_flag;
+ /* heapbufmp initialize flag */
+ bool nameserver_init_flag;
+ /* nameserver initialize flag */
+ bool transportshm_init_flag;
+ /* transportshm initialize flag */
+ bool ringiotransportshm_init_flag;
+ /* ringiotransportshm initialize flag */
+ bool notify_ducatidrv_init_flag;
+ /* notify_ducatidrv initialize flag */
+ bool nameserver_remotenotify_init_flag;
+ /* nameserverremotenotify initialize flag */
+ bool clientnotifymgr_init_flag;
+ /* clientnotifymgr initialize flag */
+ bool frameqbufmgr_init_flag;
+ /* frameqbufmgr initialize flag */
+ bool frameq_init_flag;
+ /* frameq initialize flag */
+ bool platform_init_flag;
+ /* flag to indicate platform initialization status */
+ bool platform_mem_init_flag;
+ /* Platform memory manager initialize flag */
+};
+
+
+/* =============================================================================
+ * GLOBALS
+ * =============================================================================
+ */
+static struct platform_object platform_objects[MULTIPROC_MAXPROCESSORS];
+static struct platform_module_state platform_module_state;
+static struct platform_module_state *platform_module = &platform_module_state;
+static u16 platform_num_srs_unmapped;
+static struct platform_host_sr_config *platform_host_sr_config;
+
+/* ============================================================================
+ * Forward declarations of internal functions.
+ * ============================================================================
+ */
+static int _platform_setup(void);
+static int _platform_destroy(void);
+
+/* function to read slave memory */
+static int
+_platform_read_slave_memory(u16 proc_id,
+ u32 addr,
+ void *value,
+ u32 *num_bytes);
+
+/* function to write slave memory */
+static int
+_platform_write_slave_memory(u16 proc_id,
+ u32 addr,
+ void *value,
+ u32 *num_bytes);
+
+
+/** ============================================================================
+ * Macros and types
+ * ============================================================================
+ */
+/*!
+ * @brief Number of slave memory entries for OMAP4430.
+ */
+#define NUM_MEM_ENTRIES 6
+#define NUM_MEM_ENTRIES_DSP 4
+
+
+/*!
+ * @brief Position of reset vector memory region in the memEntries array.
+ */
+#define RESET_VECTOR_ENTRY_ID 0
+
+
+/** ============================================================================
+ * Globals
+ * ============================================================================
+ */
+/*!
+ * @brief Array of memory entries for OMAP4430
+ */
+static struct proc4430_mem_entry mem_entries[NUM_MEM_ENTRIES] = {
+ {
+ "DUCATI_CODE_SYSM3", /* NAME : Name of the memory region */
+ SHAREDMEMORY_PHY_CODE0_BASEADDR,
+ /* PHYSADDR : Physical address */
+ SHAREDMEMORY_SLV_VRT_CODE0_BASEADDR,
+ /* SLAVEVIRTADDR : Slave virtual address */
+ (u32) -1u,
+ /* MASTERVIRTADDR : Master virtual address (if known) */
+ SHAREDMEMORY_SLV_VRT_CODE0_BASESIZE,
+ /* SIZE : Size of the memory region */
+ true, /* SHARE : Shared access memory? */
+ },
+ {
+ "DUCATI_CODE_APPM3", /* NAME : Name of the memory region */
+ SHAREDMEMORY_PHY_CODE1_BASEADDR,
+ /* PHYSADDR : Physical address */
+ SHAREDMEMORY_SLV_VRT_CODE1_BASEADDR,
+ /* SLAVEVIRTADDR : Slave virtual address */
+ (u32) -1u,
+ /* MASTERVIRTADDR : Master virtual address (if known) */
+ SHAREDMEMORY_SLV_VRT_CODE1_BASESIZE,
+ /* SIZE : Size of the memory region */
+ true, /* SHARE : Shared access memory? */
+ },
+ {
+ "DUCATI_SHM_SR0", /* NAME : Name of the memory region */
+ SHAREDMEMORY_PHY_BASEADDR_SR0,
+ /* PHYSADDR : Physical address */
+ SHAREDMEMORY_SLV_VRT_BASEADDR_SR0,
+ /* SLAVEVIRTADDR : Slave virtual address */
+ (u32) -1u,
+ /* MASTERVIRTADDR : Master virtual address (if known) */
+ SHAREDMEMORY_SLV_VRT_BASESIZE_SR0,
+ /* SIZE : Size of the memory region */
+ true, /* SHARE : Shared access memory? */
+ },
+ {
+ "DUCATI_SHM_SR1", /* NAME : Name of the memory region */
+ SHAREDMEMORY_PHY_BASEADDR_SR1,
+ /* PHYSADDR : Physical address */
+ SHAREDMEMORY_SLV_VRT_BASEADDR_SR1,
+ /* SLAVEVIRTADDR : Slave virtual address */
+ (u32) -1u,
+ /* MASTERVIRTADDR : Master virtual address (if known) */
+ SHAREDMEMORY_SLV_VRT_BASESIZE_SR1,
+ /* SIZE : Size of the memory region */
+ true, /* SHARE : Shared access memory? */
+ },
+ {
+ "DUCATI_CONST_SYSM3", /* NAME : Name of the memory region */
+ SHAREDMEMORY_PHY_CONST0_BASEADDR,
+ /* PHYSADDR : Physical address */
+ SHAREDMEMORY_SLV_VRT_CONST0_BASEADDR,
+ /* SLAVEVIRTADDR : Slave virtual address */
+ (u32) -1u,
+ /* MASTERVIRTADDR : Master virtual address (if known) */
+ SHAREDMEMORY_SLV_VRT_CONST0_BASESIZE,
+ /* SIZE : Size of the memory region */
+ true, /* SHARE : Shared access memory? */
+ },
+ {
+ "DUCATI_CONST_APPM3", /* NAME : Name of the memory region */
+ SHAREDMEMORY_PHY_CONST1_BASEADDR,
+ /* PHYSADDR : Physical address */
+ SHAREDMEMORY_SLV_VRT_CONST1_BASEADDR,
+ /* SLAVEVIRTADDR : Slave virtual address */
+ (u32) -1u,
+ /* MASTERVIRTADDR : Master virtual address (if known) */
+ SHAREDMEMORY_SLV_VRT_CONST1_BASESIZE,
+ /* SIZE : Size of the memory region */
+ true, /* SHARE : Shared access memory? */
+ },
+};
+
+
+/*!
+ * @brief Array of memory entries for OMAP4430
+ */
+static struct proc4430_mem_entry mem_entries_dsp[NUM_MEM_ENTRIES_DSP] = {
+ {
+ "TESLA_CODE_DSP", /* NAME : Name of the memory region */
+ SHAREDMEMORY_PHY_CODE_DSP_BASEADDR,
+ /* PHYSADDR : Physical address */
+ SHAREDMEMORY_SLV_VRT_CODE_DSP_BASEADDR,
+ /* SLAVEVIRTADDR : Slave virtual address */
+ (u32) -1u,
+ /* MASTERVIRTADDR : Master virtual address (if known) */
+ SHAREDMEMORY_SLV_VRT_CODE_DSP_BASESIZE,
+ /* SIZE : Size of the memory region */
+ true, /* SHARE : Shared access memory? */
+ },
+ {
+ "TESLA_CONST_DSP", /* NAME : Name of the memory region */
+ SHAREDMEMORY_PHY_CONST_DSP_BASEADDR,
+ /* PHYSADDR : Physical address */
+ SHAREDMEMORY_SLV_VRT_CONST_DSP_BASEADDR,
+ /* SLAVEVIRTADDR : Slave virtual address */
+ (u32) -1u,
+ /* MASTERVIRTADDR : Master virtual address (if known) */
+ SHAREDMEMORY_SLV_VRT_CONST_DSP_BASESIZE,
+ /* SIZE : Size of the memory region */
+ true, /* SHARE : Shared access memory? */
+ },
+ {
+ "TESLA_SHM_SR0", /* NAME : Name of the memory region */
+ SHAREDMEMORY_PHY_BASEADDR_SR0,
+ /* PHYSADDR : Physical address */
+ SHAREDMEMORY_SLV_VRT_DSP_BASEADDR_SR0,
+ /* SLAVEVIRTADDR : Slave virtual address */
+ (u32) -1u,
+ /* MASTERVIRTADDR : Master virtual address (if known) */
+ SHAREDMEMORY_SLV_VRT_BASESIZE_SR0,
+ /* SIZE : Size of the memory region */
+ true, /* SHARE : Shared access memory? */
+ },
+ {
+ "TESLA_SHM_SR1", /* NAME : Name of the memory region */
+ SHAREDMEMORY_PHY_BASEADDR_SR1,
+ /* PHYSADDR : Physical address */
+ SHAREDMEMORY_SLV_VRT_DSP_BASEADDR_SR1,
+ /* SLAVEVIRTADDR : Slave virtual address */
+ (u32) -1u,
+ /* MASTERVIRTADDR : Master virtual address (if known) */
+ SHAREDMEMORY_SLV_VRT_BASESIZE_SR1,
+ /* SIZE : Size of the memory region */
+ true, /* SHARE : Shared access memory? */
+ }
+};
+
+
+
+/* =============================================================================
+ * APIS
+ * =============================================================================
+ */
+
+/*
+ * ======== platform_get_config =======
+ * function to get the default values for confiurations.
+ */
+static void
+platform_get_config(struct platform_config *config)
+{
+ int status = PLATFORM_S_SUCCESS;
+
+ BUG_ON(config == NULL);
+ if (config == NULL) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* get the gatepeterson default config */
+ multiproc_get_config(&config->multiproc_config);
+
+ /* get the gatemp default config */
+ gatemp_get_config(&config->gatemp_config);
+
+ /* get the gatepeterson default config */
+ gatepeterson_get_config(&config->gatepeterson_config);
+
+ /* get the gatehwspinlock default config */
+ gatehwspinlock_get_config(&config->gatehwspinlock_config);
+
+ /* get the sharedregion default config */
+ sharedregion_get_config(&config->sharedregion_config);
+
+ /* get the messageq default config */
+ messageq_get_config(&config->messageq_config);
+
+ /* get the notify default config */
+ notify_get_config(&config->notify_config);
+ /* get the ipu_pm default config */
+ ipu_pm_get_config(&config->ipu_pm_config);
+
+ /* get the procmgr default config */
+ proc_mgr_get_config(&config->proc_mgr_config);
+
+ /* get the heapbufmpfault config */
+ heapbufmp_get_config(&config->heapbufmp_config);
+
+ /* get the heapmemmpfault config */
+ heapmemmp_get_config(&config->heapmemmp_config);
+#if 0
+ /* get the heapmultibuf default config */
+ heapmultibuf_get_config(&config->heapmultibuf_config
+#endif
+ /* get the listmp default config */
+ listmp_get_config(&config->listmp_config);
+
+ /* get the transportshm default config */
+ transportshm_get_config(&config->transportshm_config);
+ /* get the notifyshmdriver default config */
+ notify_ducatidrv_get_config(&config->notify_ducatidrv_config);
+
+ /* get the nameserver_remotenotify default config */
+ nameserver_remotenotify_get_config(&config->
+ nameserver_remotenotify_config);
+#if 0
+ /* get the clientnotifymgr default config */
+ clientnotifymgr_get_config(&config->clinotifymgr_config_params);
+
+ /* get the frameqbufmgr default config */
+ frameqbufmgr_get_config(&config->frameqbufmgr_config_params);
+ /* get the frameq default config */
+ frameq_get_config(&config->frameqcfg_params);
+
+ /* get the ringio default config */
+ ringio_get_config(&config->ringio_config);
+
+ /* get the ringiotransportshm default config */
+ ringiotransportshm_get_config(&config->ringiotransportshm_config);
+#endif
+
+exit:
+ if (status < 0)
+ pr_err("platform_get_config failed! status = 0x%x\n", status);
+ return;
+}
+
+
+/*
+ * ======== platform_override_config ======
+ * Function to override the default configuration values.
+ *
+ */
+static int
+platform_override_config(struct platform_config *config)
+{
+ int status = PLATFORM_S_SUCCESS;
+
+ BUG_ON(config == NULL);
+
+ if (config == NULL) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* Override the multiproc_config default config */
+ config->multiproc_config.num_processors = 4;
+ config->multiproc_config.id = 3;
+ strcpy(config->multiproc_config.name_list[0], "Tesla");
+ strcpy(config->multiproc_config.name_list[1], "AppM3");
+ strcpy(config->multiproc_config.name_list[2], "SysM3");
+ strcpy(config->multiproc_config.name_list[3], "MPU");
+
+ /* Override the gate,p default config */
+ config->gatemp_config.num_resources = 32;
+
+ /* Override the Sharedregion default config */
+ config->sharedregion_config.cache_line_size = 128;
+
+ /* Override the LISTMP default config */
+
+ /* Override the MESSAGEQ default config */
+ config->messageq_config.num_heaps = 2;
+
+ /* Override the NOTIFY default config */
+
+ /* Override the PROCMGR default config */
+
+ /* Override the HeapBuf default config */
+ config->heapbufmp_config.track_allocs = true;
+
+ /* Override the LISTMPSHAREDMEMORY default config */
+
+ /* Override the MESSAGEQTRANSPORTSHM default config */
+
+ /* Override the NOTIFYSHMDRIVER default config */
+
+ /* Override the NAMESERVERREMOTENOTIFY default config */
+
+ /* Override the ClientNotifyMgr default config */
+ /* Override the FrameQBufMgr default config */
+
+ /* Override the FrameQ default config */
+
+exit:
+ if (status < 0)
+ pr_err("platform_override_config failed! status "
+ "= 0x%x\n", status);
+ return status;
+}
+
+/*
+ * ======= platform_setup ========
+ * function to setup platform.
+ * TBD: logic would change completely in the final system.
+ */
+int
+platform_setup(void)
+{
+ int status = PLATFORM_S_SUCCESS;
+ struct platform_config _config;
+ struct platform_config *config;
+ struct platform_mem_map_info m_info;
+
+ platform_get_config(&_config);
+ config = &_config;
+
+ /* Initialize PlatformMem */
+ status = platform_mem_setup();
+ if (status < 0) {
+ pr_err("platform_setup : platform_mem_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("platform_mem_setup : status [0x%x]\n" ,
+ status);
+ platform_module->platform_mem_init_flag = true;
+ }
+
+ platform_override_config(config);
+
+ status = multiproc_setup(&(config->multiproc_config));
+ if (status < 0) {
+ pr_err("platform_setup : multiproc_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("platform_setup : status [0x%x]\n", status);
+ platform_module->multiproc_init_flag = true;
+ }
+
+ /* Initialize ProcMgr */
+ if (status >= 0) {
+ status = proc_mgr_setup(&(config->proc_mgr_config));
+ if (status < 0) {
+ pr_err("platform_setup : proc_mgr_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("proc_mgr_setup : status [0x%x]\n", status);
+ platform_module->proc_mgr_init_flag = true;
+ }
+ }
+
+ /* Initialize SharedRegion */
+ if (status >= 0) {
+ status = sharedregion_setup(&config->sharedregion_config);
+ if (status < 0) {
+ pr_err("platform_setup : sharedregion_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("sharedregion_setup : status [0x%x]\n", status);
+ platform_module->sharedregion_init_flag = true;
+ }
+ }
+
+ /* Initialize Notify DucatiDriver */
+ if (status >= 0) {
+ status = notify_ducatidrv_setup(&config->
+ notify_ducatidrv_config);
+ if (status < 0) {
+ pr_err("platform_setup : "
+ "notify_ducatidrv_setup failed [0x%x]\n",
+ status);
+ } else {
+ pr_err("notify_ducatidrv_setup : "
+ "status [0x%x]\n", status);
+ platform_module->notify_ducatidrv_init_flag = true;
+ }
+ }
+
+ /* Initialize Notify */
+ if (status >= 0) {
+ status = notify_setup(&config->notify_config);
+ if (status < 0) {
+ pr_err("platform_setup : notify_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("notify_setup : status [0x%x]\n", status);
+ platform_module->notify_init_flag = true;
+ }
+ }
+
+ /* Initialize ipu_pm */
+ if (status >= 0) {
+ status = ipu_pm_setup(&config->ipu_pm_config);
+ if (status < 0) {
+ pr_err("platform_setup : ipu_pm_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("ipu_pm_setup : status [0x%x]\n", status);
+ platform_module->ipu_pm_init_flag = true;
+ }
+ }
+ /* Initialize NameServer */
+ if (status >= 0) {
+ status = nameserver_setup();
+ if (status < 0) {
+ pr_err("platform_setup : nameserver_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("nameserver_setup : status [0x%x]\n", status);
+ platform_module->nameserver_init_flag = true;
+ }
+ }
+
+ /* Initialize GateMP */
+ if (status >= 0) {
+ status = gatemp_setup(&config->gatemp_config);
+ if (status < 0) {
+ pr_err("platform_setup : gatemp_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("gatemp_setup : status [0x%x]\n", status);
+ platform_module->gatemp_init_flag = true;
+ }
+ }
+
+ /* Initialize GatePeterson */
+ if (status >= 0) {
+ status = gatepeterson_setup(&config->gatepeterson_config);
+ if (status < 0) {
+ pr_err("platform_setup : gatepeterson_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("gatepeterson_setup : status [0x%x]\n", status);
+ platform_module->gatepeterson_init_flag = true;
+ }
+ }
+
+ /* Initialize GateHWSpinlock */
+ if (status >= 0) {
+ m_info.src = 0x4A0F6000;
+ m_info.size = 0x1000;
+ m_info.is_cached = false;
+ status = platform_mem_map(&m_info);
+ if (status < 0) {
+ pr_err("platform_setup : platform_mem_map "
+ "failed [0x%x]\n", status);
+ } else {
+ config->gatehwspinlock_config.num_locks = 32;
+ config->gatehwspinlock_config.base_addr = \
+ m_info.dst + 0x800;
+ status = gatehwspinlock_setup(&config->
+ gatehwspinlock_config);
+ if (status < 0) {
+ pr_err("platform_setup : "
+ "gatehwspinlock_setup failed [0x%x]\n",
+ status);
+ } else
+ platform_module->gatehwspinlock_init_flag =
+ true;
+ }
+ }
+
+ /* Initialize MessageQ */
+ if (status >= 0) {
+ status = messageq_setup(&config->messageq_config);
+ if (status < 0) {
+ pr_err("platform_setup : messageq_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("messageq_setup : status [0x%x]\n", status);
+ platform_module->messageq_init_flag = true;
+ }
+ }
+#if 0
+ /* Initialize RingIO */
+ if (status >= 0) {
+ status = ringio_setup(&config->ringio_config);
+ if (status < 0) {
+ pr_err("platform_setup : ringio_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("ringio_setup : status [0x%x]\n",
+ status);
+ platform_module->ringio_init_flag = true;
+ }
+ }
+
+ /* Initialize RingIOTransportShm */
+ if (status >= 0) {
+ status = ringiotransportshm_setup(&config->
+ ringiotransportshm_config);
+ if (status < 0) {
+ pr_err("platform_setup : "
+ "ringiotransportshm_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("ringiotransportshm_setup : status "
+ "[0x%x]\n", status);
+ platform_module->ringiotransportshm_init_flag = true;
+ }
+ }
+#endif
+ /* Initialize HeapBufMP */
+ if (status >= 0) {
+ status = heapbufmp_setup(&config->heapbufmp_config);
+ if (status < 0) {
+ pr_err("platform_setup : heapbufmp_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("heapbufmp_setup : status [0x%x]\n", status);
+ platform_module->heapbufmp_init_flag = true;
+ }
+ }
+
+ /* Initialize HeapMemMP */
+ if (status >= 0) {
+ status = heapmemmp_setup(&config->heapmemmp_config);
+ if (status < 0) {
+ pr_err("platform_setup : heapmemmp_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("heapmemmp_setup : status [0x%x]\n", status);
+ platform_module->heapmemmp_init_flag = true;
+ }
+ }
+#if 0
+ /* Initialize HeapMultiBuf */
+ if (status >= 0) {
+ status = heapmultibuf_setup(&config->heapmultibuf_config);
+ if (status < 0) {
+ pr_err("platform_setup : heapmultibuf_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("heapmultibuf_setup : status [0x%x]\n",
+ status);
+ platform_module->heapmultibuf_init_flag = true;
+ }
+ }
+#endif
+ /* Initialize ListMP */
+ if (status >= 0) {
+ status = listmp_setup(
+ &config->listmp_config);
+ if (status < 0) {
+ pr_err("platform_setup : "
+ "listmp_setup failed [0x%x]\n",
+ status);
+ } else {
+ pr_err("listmp_setup : "
+ "status [0x%x]\n", status);
+ platform_module->listmp_init_flag = true;
+ }
+ }
+
+ /* Initialize TransportShm */
+ if (status >= 0) {
+ status = transportshm_setup(
+ &config->transportshm_config);
+ if (status < 0) {
+ pr_err("platform_setup : "
+ "transportshm_setup failed [0x%x]\n",
+ status);
+ } else {
+ pr_err("transportshm_setup : status [0x%x]\n", status);
+ platform_module->transportshm_init_flag = true;
+ }
+ }
+
+ /* Initialize NameServerRemoteNotify */
+ if (status >= 0) {
+ status = nameserver_remotenotify_setup(
+ &config->nameserver_remotenotify_config);
+ if (status < 0) {
+ pr_err("platform_setup : "
+ "nameserver_remotenotify_setup failed "
+ "[0x%x]\n", status);
+ } else {
+ pr_err("nameserver_remotenotify_setup : "
+ "status [0x%x]\n", status);
+ platform_module->nameserver_remotenotify_init_flag =
+ true;
+ }
+ }
+#if 0
+ /* Get the ClientNotifyMgr default config */
+ if (status >= 0) {
+ status = ClientNotifyMgr_setup(&config->cliNotifyMgrCfgParams);
+ if (status < 0)
+ GT_setFailureReason(curTrace,
+ GT_4CLASS,
+ "Platform_setup",
+ status,
+ "ClientNotifyMgr_setup failed!");
+ else
+ Platform_module->clientNotifyMgrInitFlag = true;
+ }
+
+ /* Get the FrameQBufMgr default config */
+ if (status >= 0) {
+ status = FrameQBufMgr_setup(&config->frameQBufMgrCfgParams);
+ if (status < 0)
+ GT_setFailureReason(curTrace,
+ GT_4CLASS,
+ "Platform_setup",
+ status,
+ "FrameQBufMgr_setup failed!");
+ else
+ Platform_module->frameQBufMgrInitFlag = true;
+ }
+ /* Get the FrameQ default config */
+ if (status >= 0) {
+ status = FrameQ_setup(&config->frameQCfgParams);
+ if (status < 0)
+ GT_setFailureReason(curTrace,
+ GT_4CLASS,
+ "Platform_setup",
+ status,
+ "FrameQ_setup failed!");
+ else
+ Platform_module->frameQInitFlag = true;
+ }
+#endif
+
+ if (status >= 0) {
+ memset(platform_objects, 0,
+ (sizeof(struct platform_object) * \
+ MULTIPROC_MAXPROCESSORS));
+ }
+
+
+ /* Initialize Platform */
+ if (status >= 0) {
+ status = _platform_setup();
+ if (status < 0) {
+ pr_err("platform_setup : _platform_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("_platform_setup : status [0x%x]\n", status);
+ platform_module->platform_init_flag = true;
+ }
+
+ }
+
+ return status;
+}
+
+
+/*
+ * =========== platform_destroy ==========
+ * Function to destroy the System.
+ */
+int
+platform_destroy(void)
+{
+ int status = PLATFORM_S_SUCCESS;
+ struct platform_mem_unmap_info u_info;
+
+ /* Finalize Platform module*/
+ if (platform_module->platform_init_flag == true) {
+ status = _platform_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : _platform_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ platform_module->platform_init_flag = false;
+ }
+ }
+#if 0
+ /* Finalize Frame module */
+ if (Platform_module->frameQInitFlag == true) {
+ status = FrameQ_destroy();
+ if (status < 0)
+ GT_setFailureReason(curTrace,
+ GT_4CLASS,
+ "Platform_destroy",
+ status,
+ "FrameQ_destroy failed!");
+ else
+ Platform_module->frameQInitFlag = false;
+ }
+
+ /* Finalize FrameQBufMgr module */
+ if (Platform_module->frameQBufMgrInitFlag == true) {
+ status = FrameQBufMgr_destroy();
+ if (status < 0)
+ GT_setFailureReason(curTrace,
+ GT_4CLASS,
+ "Platform_destroy",
+ status,
+ "FrameQBufMgr_destroy failed!");
+ else
+ Platform_module->frameQBufMgrInitFlag = false;
+ }
+
+ /* Finalize ClientNotifyMgr module */
+ if (Platform_module->clientNotifyMgrInitFlag == true) {
+ status = ClientNotifyMgr_destroy();
+ if (status < 0)
+ GT_setFailureReason(curTrace,
+ GT_4CLASS,
+ "Platform_destroy",
+ status,
+ "ClientNotifyMgr_destroy failed!");
+ else
+ Platform_module->clientNotifyMgrInitFlag = false;
+ }
+#endif
+ /* Finalize NameServerRemoteNotify module */
+ if (platform_module->nameserver_remotenotify_init_flag == true) {
+ status = nameserver_remotenotify_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : "
+ "nameserver_remotenotify_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ platform_module->nameserver_remotenotify_init_flag \
+ = false;
+ }
+ }
+
+ /* Finalize TransportShm module */
+ if (platform_module->transportshm_init_flag == true) {
+ status = transportshm_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : "
+ "transportshm_destroy failed "
+ "[0x%x]\n", status);
+ } else {
+ platform_module->transportshm_init_flag = \
+ false;
+ }
+ }
+
+ /* Finalize ListMP module */
+ if (platform_module->listmp_init_flag == true) {
+ status = listmp_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : "
+ "listmp_destroy failed [0x%x]\n",
+ status);
+ } else {
+ platform_module->listmp_init_flag = \
+ false;
+ }
+ }
+#if 0
+ /* Finalize HeapMultiBuf module */
+ if (platform_module->heapmultibuf_init_flag == true) {
+ status = heapmultibuf_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : "
+ "heapmultibuf_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ platform_module->heapmultibuf_init_flag = false;
+ }
+ }
+#endif
+ /* Finalize HeapBufMP module */
+ if (platform_module->heapbufmp_init_flag == true) {
+ status = heapbufmp_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : heapbufmp_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ platform_module->heapbufmp_init_flag = false;
+ }
+ }
+
+ /* Finalize HeapMemMP module */
+ if (platform_module->heapmemmp_init_flag == true) {
+ status = heapmemmp_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : heapmemmp_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ platform_module->heapmemmp_init_flag = false;
+ }
+ }
+
+ /* Finalize MessageQ module */
+ if (platform_module->messageq_init_flag == true) {
+ status = messageq_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : messageq_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ platform_module->messageq_init_flag = false;
+ }
+ }
+#if 0
+ /* Finalize RingIO module */
+ if (platform_module->ringio_init_flag == true) {
+ status = ringio_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : ringio_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ platform_module->ringio_init_flag = false;
+ }
+ }
+
+
+ /* Finalize RingIOTransportShm module */
+ if (platform_module->ringiotransportshm_init_flag == true) {
+ status = ringiotransportshm_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : "
+ "ringiotransportshm_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ platform_module->ringiotransportshm_init_flag = false;
+ }
+ }
+#endif
+ /* Finalize GatePeterson module */
+ if (platform_module->gatepeterson_init_flag == true) {
+ status = gatepeterson_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : "
+ "gatepeterson_destroy failed [0x%x]\n", status);
+ } else {
+ platform_module->gatepeterson_init_flag = false;
+ }
+ }
+
+ /* Finalize GateHWSpinlock module */
+ if (platform_module->gatehwspinlock_init_flag == true) {
+ status = gatehwspinlock_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : "
+ "gatehwspinlock_destroy failed "
+ "[0x%x]\n", status);
+ } else {
+ platform_module->gatehwspinlock_init_flag = false;
+ }
+
+ u_info.addr = 0x4A0F6000;
+ u_info.size = 0x1000;
+ u_info.is_cached = false;
+ status = platform_mem_unmap(&u_info);
+ if (status < 0)
+ pr_err("platform_destroy : platform_mem_unmap"
+ " failed [0x%x]\n", status);
+ }
+
+ /* Finalize GateMP module */
+ if (platform_module->gatemp_init_flag == true) {
+ status = gatemp_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : "
+ "gatemp_destroy failed [0x%x]\n", status);
+ } else {
+ platform_module->gatemp_init_flag = false;
+ }
+ }
+
+ /* Finalize NameServer module */
+ if (platform_module->nameserver_init_flag == true) {
+ status = nameserver_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : nameserver_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ platform_module->nameserver_init_flag = false;
+ }
+ }
+ /* Finalize ipu_pm module */
+ if (platform_module->ipu_pm_init_flag == true) {
+ status = ipu_pm_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : ipu_pm_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ platform_module->ipu_pm_init_flag = false;
+ }
+ }
+
+ /* Finalize Notify Ducati Driver module */
+ if (platform_module->notify_ducatidrv_init_flag == true) {
+ status = notify_ducatidrv_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : "
+ "notify_ducatidrv_destroy failed [0x%x]\n",
+ status);
+ } else {
+ platform_module->notify_ducatidrv_init_flag = false;
+ }
+ }
+
+ /* Finalize Notify module */
+ if (platform_module->notify_init_flag == true) {
+ status = notify_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : notify_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ platform_module->notify_init_flag = false;
+ }
+ }
+
+ /* Finalize SharedRegion module */
+ if (platform_module->sharedregion_init_flag == true) {
+ status = sharedregion_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : "
+ "sharedregion_destroy failed [0x%x]\n", status);
+ } else {
+ platform_module->sharedregion_init_flag = false;
+ }
+ }
+
+ /* Finalize ProcMgr module */
+ if (platform_module->proc_mgr_init_flag == true) {
+ status = proc_mgr_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : proc_mgr_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ platform_module->proc_mgr_init_flag = false;
+ }
+ }
+
+ /* Finalize MultiProc module */
+ if (platform_module->multiproc_init_flag == true) {
+ status = multiproc_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : multiproc_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ platform_module->multiproc_init_flag = false;
+ }
+ }
+
+ /* Finalize PlatformMem module */
+ if (platform_module->platform_mem_init_flag == true) {
+ status = platform_mem_destroy();
+ if (status < 0) {
+ pr_err("platform_destroy : "
+ "platform_mem_destroy failed [0x%x]\n", status);
+ } else {
+ platform_module->platform_mem_init_flag = false;
+ }
+ }
+
+ if (status >= 0)
+ memset(platform_objects,
+ 0,
+ (sizeof(struct platform_object) *
+ MULTIPROC_MAXPROCESSORS));
+
+ return status;
+}
+
+/*
+ * ======== platform_setup ========
+ * Purpose:
+ * TBD: logic would change completely in the final system.
+ */
+static s32 _platform_setup(void)
+{
+
+ s32 status = 0;
+ struct proc4430_config proc_config;
+ struct proc_mgr_params params;
+ struct proc4430_params proc_params;
+ u16 proc_id;
+ struct platform_object *handle;
+ void *proc_mgr_handle;
+ void *proc_mgr_proc_handle;
+
+ /* Create the SysM3 ProcMgr object */
+ proc4430_get_config(&proc_config);
+ status = proc4430_setup(&proc_config);
+ if (status < 0)
+ goto exit;
+
+ /* Get MultiProc ID by name. */
+ proc_id = multiproc_get_id("SysM3");
+ if (proc_id >= MULTIPROC_MAXPROCESSORS) {
+ pr_err("multi proc returned invalid proc id\n");
+ goto multiproc_id_fail;
+ }
+ handle = &platform_objects[proc_id];
+
+ /* Create an instance of the Processor object for OMAP4430 */
+ proc4430_params_init(NULL, &proc_params);
+ /* TODO: SysLink-38 has these in individual Proc Objects */
+ proc_params.num_mem_entries = NUM_MEM_ENTRIES;
+ proc_params.mem_entries = mem_entries;
+ proc_params.reset_vector_mem_entry = RESET_VECTOR_ENTRY_ID;
+ proc_mgr_proc_handle = proc4430_create(proc_id, &proc_params);
+ if (proc_mgr_proc_handle == NULL) {
+ status = PLATFORM_E_FAIL;
+ goto proc_create_fail;
+ }
+
+ /* Initialize parameters */
+ proc_mgr_params_init(NULL, &params);
+ params.proc_handle = proc_mgr_proc_handle;
+ proc_mgr_handle = proc_mgr_create(proc_id, &params);
+ if (proc_mgr_handle == NULL) {
+ status = PLATFORM_E_FAIL;
+ goto proc_mgr_create_fail;
+ }
+
+ /* SysM3 and AppM3 use the same handle */
+ handle->phandle = proc_mgr_proc_handle;
+ handle->pm_handle = proc_mgr_handle;
+
+ proc_mgr_handle = NULL;
+ proc_mgr_proc_handle = NULL;
+
+
+ /* Create the AppM3 ProcMgr object */
+ /* Get MultiProc ID by name. */
+ proc_id = multiproc_get_id("AppM3");
+ if (proc_id >= MULTIPROC_MAXPROCESSORS) {
+ pr_err("multi proc returned invalid proc id\n");
+ goto proc_mgr_create_fail;
+ }
+ handle = &platform_objects[proc_id];
+
+ /* Create an instance of the Processor object for OMAP4430 */
+ proc4430_params_init(NULL, &proc_params);
+ proc_params.num_mem_entries = NUM_MEM_ENTRIES;
+ proc_params.mem_entries = mem_entries;
+ proc_params.reset_vector_mem_entry = RESET_VECTOR_ENTRY_ID;
+ proc_mgr_proc_handle = proc4430_create(proc_id, &proc_params);
+ if (proc_mgr_proc_handle == NULL) {
+ status = PLATFORM_E_FAIL;
+ goto proc_create_fail;
+ }
+
+ /* Initialize parameters */
+ proc_mgr_params_init(NULL, &params);
+ params.proc_handle = proc_mgr_proc_handle;
+ proc_mgr_handle = proc_mgr_create(proc_id, &params);
+ if (proc_mgr_handle == NULL) {
+ status = PLATFORM_E_FAIL;
+ goto proc_mgr_create_fail;
+ }
+
+ handle->phandle = proc_mgr_proc_handle;
+ handle->pm_handle = proc_mgr_handle;
+
+ /* Create the Tesla ProcMgr object */
+ /* Get MultiProc ID by name. */
+ proc_id = multiproc_get_id("Tesla");
+ if (proc_id >= MULTIPROC_MAXPROCESSORS) {
+ pr_err("multi proc returned invalid proc id\n");
+ goto multiproc_id_fail;
+ }
+ handle = &platform_objects[proc_id];
+
+ /* Create an instance of the Processor object for OMAP4430 */
+ proc4430_params_init(NULL, &proc_params);
+ proc_params.num_mem_entries = NUM_MEM_ENTRIES_DSP;
+ proc_params.mem_entries = mem_entries_dsp;
+ proc_params.reset_vector_mem_entry = RESET_VECTOR_ENTRY_ID;
+ proc_mgr_proc_handle = proc4430_create(proc_id, &proc_params);
+ if (proc_mgr_proc_handle == NULL) {
+ status = PLATFORM_E_FAIL;
+ goto proc_create_fail;
+ }
+
+ /* Initialize parameters */
+ proc_mgr_params_init(NULL, &params);
+ params.proc_handle = proc_mgr_proc_handle;
+ proc_mgr_handle = proc_mgr_create(proc_id, &params);
+ if (proc_mgr_handle == NULL) {
+ status = PLATFORM_E_FAIL;
+ goto proc_mgr_create_fail;
+ }
+
+ handle->phandle = proc_mgr_proc_handle;
+ handle->pm_handle = proc_mgr_handle;
+
+ /* TODO: See if we need to do proc_mgr_attach on both SysM3 & AppM3
+ * to set the memory maps before hand. Or fix ProcMgr_open &
+ * ProcMgr_attach from the userspace */
+ return status;
+
+multiproc_id_fail:
+proc_create_fail:
+proc_mgr_create_fail:
+ /* Clean up created objects */
+ _platform_destroy();
+exit:
+ return status;
+}
+
+
+/*
+ * ======== platform_destroy ========
+ * Purpose:
+ * Function to finalize the platform.
+ */
+static s32 _platform_destroy(void)
+{
+ s32 status = 0;
+ struct platform_object *handle;
+ int i;
+
+ for (i = 0; i < MULTIPROC_MAXPROCESSORS; i++) {
+ handle = &platform_objects[i];
+
+ /* Delete the Processor instances */
+ if (handle->phandle != NULL) {
+ status = proc4430_delete(&handle->phandle);
+ WARN_ON(status < 0);
+ }
+
+ if (handle->pm_handle != NULL) {
+ status = proc_mgr_delete(&handle->pm_handle);
+ WARN_ON(status < 0);
+ }
+ }
+
+ status = proc4430_destroy();
+ WARN_ON(status < 0);
+
+ return status;
+}
+
+
+/*
+ * ======== platform_load_callback ========
+ * Purpose:
+ * Function called by proc_mgr when slave is in loaded state.
+ */
+int platform_load_callback(u16 proc_id, void *arg)
+{
+ int status = PLATFORM_S_SUCCESS;
+ struct platform_object *handle;
+ u32 start;
+ u32 num_bytes;
+ struct sharedregion_entry entry;
+ u32 m_addr = 0;
+ /*struct proc_mgr_addr_info ai;*/
+ struct ipc_params ipc_params;
+ int i;
+ void *pm_handle;
+
+ handle = &platform_objects[proc_id];
+ pm_handle = handle->pm_handle;
+
+ /* TODO: hack */
+ start = (u32)arg; /* start address passed in as argument */
+
+ /* Read the slave config */
+ num_bytes = sizeof(struct platform_slave_config);
+ status = _platform_read_slave_memory(proc_id,
+ start,
+ &handle->slave_config,
+ &num_bytes);
+ if (status < 0) {
+ status = PLATFORM_E_FAIL;
+ goto exit;
+ }
+
+ if (platform_host_sr_config == NULL)
+ platform_host_sr_config = kmalloc(sizeof(struct
+ platform_host_sr_config) * handle->
+ slave_config.num_srs, GFP_KERNEL);
+
+ if (platform_host_sr_config == NULL) {
+ status = -ENOMEM;
+ goto alloced_host_sr_config_exit;
+ }
+
+ if (handle->slave_config.num_srs > 0) {
+ num_bytes = handle->slave_config.num_srs * sizeof(struct
+ platform_slave_sr_config);
+ handle->slave_sr_config = kmalloc(num_bytes, GFP_KERNEL);
+ if (handle->slave_sr_config == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ } else {
+ status = _platform_read_slave_memory(
+ proc_id,
+ start + sizeof(struct
+ platform_slave_config),
+ handle->slave_sr_config,
+ &num_bytes);
+ if (status < 0) {
+ status = PLATFORM_E_FAIL;
+ goto alloced_slave_sr_config_exit;
+ }
+ }
+ }
+
+ if (status >= 0) {
+ ipc_params.setup_messageq = handle->slave_config.setup_messageq;
+ ipc_params.setup_notify = handle->slave_config.setup_notify;
+ ipc_params.setup_ipu_pm = handle->slave_config.setup_ipu_pm;
+ ipc_params.proc_sync = handle->slave_config.proc_sync;
+ status = ipc_create(proc_id, &ipc_params);
+ if (status < 0) {
+ status = PLATFORM_E_FAIL;
+ goto alloced_slave_sr_config_exit;
+ }
+ }
+
+ /* Setup the shared memory for region with owner == host */
+ /* TODO: May need to replace proc_mgr_map with platform_mem_map */
+ for (i = 0; i < handle->slave_config.num_srs; i++) {
+ status = sharedregion_get_entry(i, &entry);
+ if (status < 0) {
+ status = PLATFORM_E_FAIL;
+ goto alloced_slave_sr_config_exit;
+ }
+ BUG_ON(!((entry.is_valid == false)
+ || ((entry.is_valid == true)
+ && (entry.len == (handle->
+ slave_sr_config[i].entry_len)))));
+
+ platform_host_sr_config[i].ref_count++;
+
+ /* Add the entry only if previously not added */
+ if (entry.is_valid == false) {
+ /* Translate the slave address to master */
+
+ /* This SharedRegion is already pre-mapped. So, no need
+ * to do a new mapping. Just need to translate to get
+ * the master virtual address */
+ status = proc_mgr_translate_addr(pm_handle,
+ (void **)&m_addr,
+ PROC_MGR_ADDRTYPE_MASTERKNLVIRT,
+ (void *)handle->slave_sr_config[i].entry_base,
+ PROC_MGR_ADDRTYPE_SLAVEVIRT);
+ if (status < 0) {
+ status = PLATFORM_E_FAIL;
+ goto alloced_slave_sr_config_exit;
+ }
+
+ /* TODO: compatibility with new procmgr */
+ /* No need to map this to Slave. Slave is pre-mapped */
+ /*status = proc_mgr_map(pm_handle,
+ handle->slave_sr_config[i].entry_base,
+ handle->slave_sr_config[i].entry_len,
+ &ai.addr[PROC_MGR_ADDRTYPE_MASTERKNLVIRT],
+ &handle->slave_sr_config[i].entry_len,
+ PROC_MGR_MAPTYPE_VIRT);
+ if (status < 0) {
+ status = PLATFORM_E_FAIL;
+ goto alloced_slave_sr_config_exit;
+ }
+
+ memset((u32 *)ai.addr[PROC_MGR_ADDRTYPE_MASTERKNLVIRT],
+ 0, handle->slave_sr_config[i].entry_len); */
+ memset((u32 *)m_addr, 0,
+ handle->slave_sr_config[i].entry_len);
+ memset(&entry, 0, sizeof(struct sharedregion_entry));
+ /*entry.base = (void *)ai.
+ addr[PROC_MGR_ADDRTYPE_MASTERKNLVIRT];*/
+ entry.base = (void *) m_addr;
+ entry.len = handle->slave_sr_config[i].entry_len;
+ entry.owner_proc_id = handle->slave_sr_config[i].
+ owner_proc_id;
+ entry.is_valid = true;
+ entry.cache_line_size = handle->slave_sr_config[i].
+ cache_line_size;
+ entry.create_heap = handle->slave_sr_config[i].
+ create_heap;
+ _sharedregion_set_entry(handle->slave_sr_config[i].id,
+ &entry);
+ }
+ }
+
+ /* Read sr0_memory_setup */
+ num_bytes = sizeof(struct platform_slave_config);
+ handle->slave_config.sr0_memory_setup = 1;
+ status = _platform_write_slave_memory(proc_id,
+ start,
+ &handle->slave_config,
+ &num_bytes);
+ if (status < 0) {
+ status = PLATFORM_E_FAIL;
+ goto alloced_slave_sr_config_exit;
+ }
+
+ status = ipc_start();
+ if (status < 0) {
+ status = PLATFORM_E_FAIL;
+ goto alloced_slave_sr_config_exit;
+ }
+
+ return 0;
+
+alloced_slave_sr_config_exit:
+ kfree(handle->slave_sr_config);
+
+alloced_host_sr_config_exit:
+ kfree(platform_host_sr_config);
+exit:
+ if (status < 0)
+ pr_err("platform_load_callback failed, status [0x%x]\n",
+ status);
+
+ return status;
+}
+EXPORT_SYMBOL(platform_load_callback);
+
+
+/*
+ * ======== platform_start_callback ========
+ * Purpose:
+ * Function called by proc_mgr when slave is in started state.
+ * FIXME: logic would change completely in the final system.
+ */
+int platform_start_callback(u16 proc_id, void *arg)
+{
+ int status = PLATFORM_S_SUCCESS;
+
+ do {
+ status = ipc_attach(proc_id);
+ msleep(1);
+ } while (status < 0);
+
+ if (status < 0)
+ pr_err("platform_load_callback failed, status [0x%x]\n",
+ status);
+
+ ipc_notify_event(IPC_START, &proc_id);
+
+ return status;
+}
+EXPORT_SYMBOL(platform_start_callback);
+/* FIXME: since application has to call this API for now */
+
+
+/*
+ * ======== platform_stop_callback ========
+ * Purpose:
+ * Function called by proc_mgr when slave is in stopped state.
+ * FIXME: logic would change completely in the final system.
+ */
+int platform_stop_callback(u16 proc_id, void *arg)
+{
+ int status = PLATFORM_S_SUCCESS;
+ u32 i;
+ u32 m_addr;
+ struct platform_object *handle;
+ void *pm_handle;
+
+ handle = (struct platform_object *)&platform_objects[proc_id];
+ pm_handle = handle->pm_handle;
+ /* delete the System manager instance here */
+ for (i = 0;
+ ((handle->slave_sr_config != NULL) &&
+ (i < handle->slave_config.num_srs));
+ i++) {
+ platform_host_sr_config[i].ref_count--;
+ if (platform_host_sr_config[i].ref_count == 0) {
+ platform_num_srs_unmapped++;
+ /* Translate the slave address to master */
+ /* TODO: backwards compatibility with old procmgr */
+ status = proc_mgr_translate_addr(pm_handle,
+ (void **)&m_addr,
+ PROC_MGR_ADDRTYPE_MASTERKNLVIRT,
+ (void *)handle->slave_sr_config[i].entry_base,
+ PROC_MGR_ADDRTYPE_SLAVEVIRT);
+ if (status < 0) {
+ status = PLATFORM_E_FAIL;
+ continue;
+ }
+
+ }
+ }
+
+ if (platform_num_srs_unmapped == handle->slave_config.num_srs) {
+ if (handle->slave_sr_config != NULL) {
+ kfree(handle->slave_sr_config);
+ handle->slave_sr_config = NULL;
+ }
+ if (platform_host_sr_config != NULL) {
+ kfree(platform_host_sr_config);
+ platform_host_sr_config = NULL;
+ platform_num_srs_unmapped = 0;
+ }
+ }
+
+ ipc_notify_event(IPC_STOP, &proc_id);
+
+ ipc_detach(proc_id);
+
+ ipc_stop();
+
+ return status;
+}
+EXPORT_SYMBOL(platform_stop_callback);
+
+/* ============================================================================
+ * Internal functions
+ * ============================================================================
+ */
+/* Function to read slave memory */
+static int
+_platform_read_slave_memory(u16 proc_id,
+ u32 addr,
+ void *value,
+ u32 *num_bytes)
+{
+ int status = 0;
+ bool done = false;
+ struct platform_object *handle;
+ u32 m_addr;
+ void *pm_handle;
+
+ handle = (struct platform_object *)&platform_objects[proc_id];
+ BUG_ON(handle == NULL);
+ if (handle == NULL) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ pm_handle = handle->pm_handle;
+ BUG_ON(pm_handle == NULL);
+ if (pm_handle == NULL) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* TODO: backwards compatibility with old procmgr */
+ status = proc_mgr_translate_addr(pm_handle,
+ (void **)&m_addr,
+ PROC_MGR_ADDRTYPE_MASTERKNLVIRT,
+ (void *)addr,
+ PROC_MGR_ADDRTYPE_SLAVEVIRT);
+ if (status >= 0) {
+ memcpy(value, (void *) m_addr, *num_bytes);
+ done = true;
+ pr_err("_platform_read_slave_memory successful! "
+ "status = 0x%x, proc_id = %d, addr = 0x%x, "
+ "m_addr = 0x%x, size = 0x%x", status, proc_id, addr,
+ m_addr, *num_bytes);
+ } else {
+ pr_err("_platform_read_slave_memory failed! "
+ "status = 0x%x, proc_id = %d, addr = 0x%x, "
+ "m_addr = 0x%x, size = 0x%x", status, proc_id, addr,
+ m_addr, *num_bytes);
+ status = PLATFORM_E_FAIL;
+ goto exit;
+ }
+
+ if (done == false) {
+ status = proc_mgr_read(pm_handle,
+ addr,
+ num_bytes,
+ value);
+ if (status < 0) {
+ status = PLATFORM_E_FAIL;
+ goto exit;
+ }
+ }
+
+exit:
+ return status;
+}
+
+
+/* Function to write slave memory */
+static int _platform_write_slave_memory(u16 proc_id, u32 addr, void *value,
+ u32 *num_bytes)
+{
+ int status = 0;
+ bool done = false;
+ struct platform_object *handle;
+ u32 m_addr;
+ void *pm_handle = NULL;
+
+ handle = (struct platform_object *)&platform_objects[proc_id];
+ BUG_ON(handle == NULL);
+ if (handle == NULL) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ pm_handle = handle->pm_handle;
+ BUG_ON(pm_handle == NULL);
+ if (pm_handle == NULL) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* Translate the slave address to master address */
+ /* TODO: backwards compatibility with old procmgr */
+ status = proc_mgr_translate_addr(pm_handle,
+ (void **)&m_addr,
+ PROC_MGR_ADDRTYPE_MASTERKNLVIRT,
+ (void *)addr,
+ PROC_MGR_ADDRTYPE_SLAVEVIRT);
+ if (status >= 0) {
+ memcpy((void *) m_addr, value, *num_bytes);
+ done = true;
+ pr_err("_platform_write_slave_memory successful! "
+ "status = 0x%x, proc_id = %d, addr = 0x%x, "
+ "m_addr = 0x%x, size = 0x%x", status, proc_id, addr,
+ m_addr, *num_bytes);
+ } else {
+ pr_err("_platform_write_slave_memory failed! "
+ "status = 0x%x, proc_id = %d, addr = 0x%x, "
+ "m_addr = 0x%x, size = 0x%x", status, proc_id, addr,
+ m_addr, *num_bytes);
+ status = PLATFORM_E_FAIL;
+ goto exit;
+ }
+
+ if (done == false) {
+ status = proc_mgr_write(pm_handle,
+ addr,
+ num_bytes,
+ value);
+ if (status < 0) {
+ status = PLATFORM_E_FAIL;
+ goto exit;
+ }
+ }
+
+exit:
+ return status;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/platform_mem.c b/drivers/dsp/syslink/multicore_ipc/platform_mem.c
new file mode 100644
index 00000000000..eb6d3905cf9
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/platform_mem.c
@@ -0,0 +1,325 @@
+/*
+ * platform_mem.c
+ *
+ * Target memory management interface implementation.
+ *
+ * This abstracts the Memory management interface in the kernel
+ * code. Allocation, Freeing-up, copy and address translate are
+ * supported for the kernel memory management.
+ *
+ * Copyright (C) 2008-2009 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 specific header files */
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <platform_mem.h>
+#include <atomic_linux.h>
+
+/* Macro to make a correct module magic number with ref_count */
+#define PLATFORM_MEM_MAKE_MAGICSTAMP(x) ((PLATFORM_MEM_MODULEID << 12u) | (x))
+
+/*
+ * Structure for containing
+ */
+struct platform_mem_map_table_info {
+ struct list_head mem_entry; /* Pointer to mem_entry entry */
+ u32 physical_address; /* Actual address */
+ u32 knl_virtual_address; /* Mapped address */
+ u32 size; /* Size of the region mapped */
+ u16 ref_count; /* Reference count of mapped entry */
+ bool is_cached;
+};
+
+/*
+ * Structure defining state object of system memory manager
+ */
+struct platform_mem_module_object {
+ atomic_t ref_count; /* Reference count */
+ struct list_head map_table; /* Head of map table */
+ struct mutex *gate; /* Pointer to lock */
+};
+
+
+/*
+ * Object containing state of the platform mem module
+ */
+static struct platform_mem_module_object platform_mem_state;
+
+/*
+ * ======== platform_mem_setup ========
+ * Purpose:
+ * This will initialize the platform mem module.
+ */
+int platform_mem_setup(void)
+{
+ s32 retval = 0;
+
+ atomic_cmpmask_and_set(&platform_mem_state.ref_count,
+ PLATFORM_MEM_MAKE_MAGICSTAMP(0),
+ PLATFORM_MEM_MAKE_MAGICSTAMP(0));
+ if (atomic_inc_return(&platform_mem_state.ref_count)
+ != PLATFORM_MEM_MAKE_MAGICSTAMP(1)) {
+ return 1;
+ }
+
+ /* Create the Gate handle */
+ platform_mem_state.gate =
+ kmalloc(sizeof(struct mutex), GFP_KERNEL);
+ if (platform_mem_state.gate == NULL) {
+ retval = -ENOMEM;
+ goto gate_create_fail;
+ }
+
+ /* Construct the map table */
+ INIT_LIST_HEAD(&platform_mem_state.map_table);
+ mutex_init(platform_mem_state.gate);
+ goto exit;
+
+gate_create_fail:
+ atomic_set(&platform_mem_state.ref_count,
+ PLATFORM_MEM_MAKE_MAGICSTAMP(0));
+exit:
+ return retval;
+}
+EXPORT_SYMBOL(platform_mem_setup);
+
+/*
+ * ======== platform_mem_destroy ========
+ * Purpose:
+ * This will finalize the platform mem module.
+ */
+int platform_mem_destroy(void)
+{
+ s32 retval = 0;
+ struct platform_mem_map_table_info *info = NULL, *temp = NULL;
+
+ if (atomic_cmpmask_and_lt(&(platform_mem_state.ref_count),
+ PLATFORM_MEM_MAKE_MAGICSTAMP(0),
+ PLATFORM_MEM_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (atomic_dec_return(&platform_mem_state.ref_count)
+ == PLATFORM_MEM_MAKE_MAGICSTAMP(0)) {
+ /* Delete the node in the map table */
+ list_for_each_entry_safe(info, temp,
+ &platform_mem_state.map_table,
+ mem_entry) {
+ iounmap((void __iomem *) info->knl_virtual_address);
+ list_del(&info->mem_entry);
+ kfree(info);
+ }
+ list_del(&platform_mem_state.map_table);
+ /* Delete the gate handle */
+ kfree(platform_mem_state.gate);
+ }
+
+exit:
+ return retval;
+}
+EXPORT_SYMBOL(platform_mem_destroy);
+
+/*
+ * ======== platform_mem_map ========
+ * Purpose:
+ * This will maps a memory area into virtual space.
+ */
+int platform_mem_map(memory_map_info *map_info)
+{
+ int retval = 0;
+ bool exists = false;
+ struct platform_mem_map_table_info *info = NULL;
+ struct list_head *list_info = NULL;
+
+ if (atomic_cmpmask_and_lt(&(platform_mem_state.ref_count),
+ PLATFORM_MEM_MAKE_MAGICSTAMP(0),
+ PLATFORM_MEM_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(map_info == NULL)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (map_info->src == (u32) NULL) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ retval = mutex_lock_interruptible(platform_mem_state.gate);
+ if (retval)
+ goto exit;
+
+ /* First check if the mapping already exists in the map table */
+ list_for_each(list_info, (struct list_head *)
+ &platform_mem_state.map_table) {
+ if ((((struct platform_mem_map_table_info *)
+ list_info)->physical_address == map_info->src) && \
+ (((struct platform_mem_map_table_info *)
+ list_info)->is_cached == map_info->is_cached)) {
+ exists = true;
+ map_info->dst = ((struct platform_mem_map_table_info *)
+ list_info)->knl_virtual_address;
+ /* Increase the refcount. */
+ ((struct platform_mem_map_table_info *)
+ list_info)->ref_count++;
+ break;
+ }
+ }
+ if (exists) {
+ mutex_unlock(platform_mem_state.gate);
+ goto exit;
+ }
+
+ map_info->dst = 0;
+ if (map_info->is_cached == true)
+ map_info->dst = (u32 __force) ioremap((dma_addr_t)
+ (map_info->src), map_info->size);
+ else
+ map_info->dst = (u32 __force) ioremap_nocache((dma_addr_t)
+ (map_info->src), map_info->size);
+ if (map_info->dst == 0) {
+ retval = -EFAULT;
+ goto ioremap_fail;
+ }
+
+ info = kmalloc(sizeof(struct platform_mem_map_table_info), GFP_KERNEL);
+ if (info == NULL) {
+ retval = -ENOMEM;
+ goto ioremap_fail;
+ }
+ /* Populate the info */
+ info->physical_address = map_info->src;
+ info->knl_virtual_address = map_info->dst;
+ info->size = map_info->size;
+ info->ref_count = 1;
+ info->is_cached = map_info->is_cached;
+ /* Put the info into the list */
+ list_add(&info->mem_entry, &platform_mem_state.map_table);
+ mutex_unlock(platform_mem_state.gate);
+ goto exit;
+
+ioremap_fail:
+ mutex_unlock(platform_mem_state.gate);
+exit:
+ return retval;
+}
+EXPORT_SYMBOL(platform_mem_map);
+
+/*
+ * ======== platform_mem_unmap ========
+ * Purpose:
+ * This will unmaps a memory area into virtual space.
+ */
+int platform_mem_unmap(memory_unmap_info *unmap_info)
+{
+ s32 retval = 0;
+ bool found = false;
+ struct platform_mem_map_table_info *info = NULL;
+
+ if (atomic_cmpmask_and_lt(&(platform_mem_state.ref_count),
+ PLATFORM_MEM_MAKE_MAGICSTAMP(0),
+ PLATFORM_MEM_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (unmap_info == NULL) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ if (unmap_info->addr == (u32) NULL) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ retval = mutex_lock_interruptible(platform_mem_state.gate);
+ if (retval)
+ goto exit;
+
+ list_for_each_entry(info,
+ (struct list_head *)&platform_mem_state.map_table, mem_entry) {
+ if ((info->knl_virtual_address == unmap_info->addr) && \
+ (info->is_cached == unmap_info->is_cached)) {
+ info->ref_count--;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ mutex_unlock(platform_mem_state.gate);
+ goto exit;
+ }
+
+ if (info->ref_count == 0) {
+ list_del(&info->mem_entry);
+ kfree(info);
+ iounmap((void __iomem *) unmap_info->addr);
+ }
+ mutex_unlock(platform_mem_state.gate);
+
+exit:
+ return retval;
+}
+EXPORT_SYMBOL(platform_mem_unmap);
+
+/*
+ * ======== platform_mem_translate ========
+ * Purpose:
+ * This will translate an address.
+ */
+void *platform_mem_translate(void *src_addr, enum memory_xlt_flags flags)
+{
+ void *buf = NULL;
+ struct platform_mem_map_table_info *tinfo = NULL;
+ u32 frm_addr;
+ u32 to_addr;
+ s32 retval = 0;
+
+ if (atomic_cmpmask_and_lt(&(platform_mem_state.ref_count),
+ PLATFORM_MEM_MAKE_MAGICSTAMP(0),
+ PLATFORM_MEM_MAKE_MAGICSTAMP(1)) == true) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ retval = mutex_lock_interruptible(platform_mem_state.gate);
+ if (retval)
+ goto exit;
+
+ /* Traverse to the node in the map table */
+ list_for_each_entry(tinfo, &platform_mem_state.map_table, mem_entry) {
+ frm_addr = (flags == PLATFORM_MEM_XLT_FLAGS_VIRT2PHYS) ?
+ tinfo->knl_virtual_address : tinfo->physical_address;
+ to_addr = (flags == PLATFORM_MEM_XLT_FLAGS_VIRT2PHYS) ?
+ tinfo->physical_address : tinfo->knl_virtual_address;
+ if ((((u32) src_addr) >= frm_addr)
+ && (((u32) src_addr) < (frm_addr + tinfo->size))) {
+ buf = (void *) (to_addr + ((u32)src_addr - frm_addr));
+ break;
+ }
+ }
+ mutex_unlock(platform_mem_state.gate);
+
+exit:
+ return buf;
+}
+EXPORT_SYMBOL(platform_mem_translate);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/dsp/syslink/multicore_ipc/sharedregion.c b/drivers/dsp/syslink/multicore_ipc/sharedregion.c
new file mode 100644
index 00000000000..7095f142d97
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/sharedregion.c
@@ -0,0 +1,1589 @@
+/*
+ * sharedregion.c
+ *
+ * The SharedRegion module is designed to be used in a
+ * multi-processor environment where there are memory regions
+ * that are shared and accessed across different processors
+ *
+ * Copyright (C) 2008-2009 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 <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <syslink/atomic_linux.h>
+
+#include <multiproc.h>
+#include <nameserver.h>
+#include <heapmemmp.h>
+#include <sharedregion.h>
+
+/* Macro to make a correct module magic number with refCount */
+#define SHAREDREGION_MAKE_MAGICSTAMP(x) ((SHAREDREGION_MODULEID << 16u) | (x))
+
+#define SHAREDREGION_MAX_REGIONS_DEFAULT 4
+
+#define ROUND_UP(a, b) (((a) + ((b) - 1)) & (~((b) - 1)))
+
+/* Module state object */
+struct sharedregion_module_object {
+ atomic_t ref_count; /* Reference count */
+ struct mutex *local_lock; /* Handle to a gate instance */
+ struct sharedregion_region *regions; /* Pointer to the regions */
+ struct sharedregion_config cfg; /* Current config values */
+ struct sharedregion_config def_cfg; /* Default config values */
+ u32 num_offset_bits;
+ /* no. of bits for the offset for a SRPtr. This value is calculated */
+ u32 offset_mask; /* offset bitmask using for generating a SRPtr */
+};
+
+/* Shared region state object variable with default settings */
+static struct sharedregion_module_object sharedregion_state = {
+ .num_offset_bits = 0,
+ .regions = NULL,
+ .local_lock = NULL,
+ .offset_mask = 0,
+ .def_cfg.num_entries = 4u,
+ .def_cfg.translate = true,
+ .def_cfg.cache_line_size = 128u
+};
+
+/* Pointer to the SharedRegion module state */
+static struct sharedregion_module_object *sharedregion_module = \
+ &sharedregion_state;
+
+/* Checks to make sure overlap does not exists.
+ * Return error if overlap found. */
+static int _sharedregion_check_overlap(void *base, u32 len);
+
+/* Return the number of offsetBits bits */
+static u32 _sharedregion_get_num_offset_bits(void);
+
+/* This will get the sharedregion module configuration */
+int sharedregion_get_config(struct sharedregion_config *config)
+{
+ BUG_ON((config == NULL));
+ if (atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true) {
+ memcpy(config, &sharedregion_module->def_cfg,
+ sizeof(struct sharedregion_config));
+ } else {
+ memcpy(config, &sharedregion_module->cfg,
+ sizeof(struct sharedregion_config));
+ }
+ return 0;
+}
+EXPORT_SYMBOL(sharedregion_get_config);
+
+/* This will get setup the sharedregion module */
+int sharedregion_setup(const struct sharedregion_config *config)
+{
+ struct sharedregion_config tmpcfg;
+ u32 i;
+ s32 retval = 0;
+
+ /* This sets the refCount variable is not initialized, upper 16 bits is
+ * written with module Id to ensure correctness of refCount variable
+ */
+ atomic_cmpmask_and_set(&sharedregion_module->ref_count,
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(0));
+
+ if (atomic_inc_return(&sharedregion_module->ref_count)
+ != SHAREDREGION_MAKE_MAGICSTAMP(1)) {
+ return 1;
+ }
+
+ if (config == NULL) {
+ sharedregion_get_config(&tmpcfg);
+ config = &tmpcfg;
+ }
+
+ if (WARN_ON(config->num_entries == 0)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ memcpy(&sharedregion_module->cfg, config,
+ sizeof(struct sharedregion_config));
+ sharedregion_module->cfg.translate = true;
+
+ sharedregion_module->regions = kmalloc(
+ (sizeof(struct sharedregion_region) * \
+ sharedregion_module->cfg.num_entries),
+ GFP_KERNEL);
+ if (sharedregion_module->regions == NULL) {
+ retval = -ENOMEM;
+ goto error;
+ }
+ for (i = 0; i < sharedregion_module->cfg.num_entries; i++) {
+ sharedregion_module->regions[i].entry.base = NULL;
+ sharedregion_module->regions[i].entry.len = 0;
+ sharedregion_module->regions[i].entry.owner_proc_id = 0;
+ sharedregion_module->regions[i].entry.is_valid = false;
+ sharedregion_module->regions[i].entry.cache_enable = true;
+ sharedregion_module->regions[i].entry.cache_line_size =
+ sharedregion_module->cfg.cache_line_size;
+ sharedregion_module->regions[i].entry.create_heap = false;
+ sharedregion_module->regions[i].reserved_size = 0;
+ sharedregion_module->regions[i].heap = NULL;
+ sharedregion_module->regions[i].entry.name = NULL;
+ }
+
+ /* set the defaults for region 0 */
+ sharedregion_module->regions[0].entry.create_heap = true;
+ sharedregion_module->regions[0].entry.owner_proc_id = multiproc_self();
+
+ sharedregion_module->num_offset_bits = \
+ _sharedregion_get_num_offset_bits();
+ sharedregion_module->offset_mask =
+ (1 << sharedregion_module->num_offset_bits) - 1;
+
+ sharedregion_module->local_lock = kmalloc(sizeof(struct mutex),
+ GFP_KERNEL);
+ if (sharedregion_module->local_lock == NULL) {
+ retval = -ENOMEM;
+ goto gate_create_fail;
+ }
+ mutex_init(sharedregion_module->local_lock);
+
+ return 0;
+
+gate_create_fail:
+ kfree(sharedregion_module->regions);
+
+error:
+ pr_err("sharedregion_setup failed status:%x\n", retval);
+ sharedregion_destroy();
+ return retval;
+}
+EXPORT_SYMBOL(sharedregion_setup);
+
+/* This will get destroy the sharedregion module */
+int sharedregion_destroy(void)
+{
+ s32 retval = 0;
+ void *local_lock = NULL;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (!(atomic_dec_return(&sharedregion_module->ref_count)
+ == SHAREDREGION_MAKE_MAGICSTAMP(0))) {
+ retval = 1;
+ goto error;
+ }
+
+ retval = mutex_lock_interruptible(sharedregion_module->local_lock);
+ if (retval)
+ goto error;
+ kfree(sharedregion_module->regions);
+ memset(&sharedregion_module->cfg, 0,
+ sizeof(struct sharedregion_config));
+ sharedregion_module->num_offset_bits = 0;
+ sharedregion_module->offset_mask = 0;
+ mutex_unlock(sharedregion_module->local_lock);
+
+ kfree(local_lock);
+ return 0;
+
+error:
+ if (retval < 0) {
+ pr_err("sharedregion_destroy failed status:%x\n",
+ retval);
+ }
+ return retval;
+}
+EXPORT_SYMBOL(sharedregion_destroy);
+
+/* Creates a heap by owner of region for each SharedRegion.
+ * Function is called by Ipc_start(). Requires that SharedRegion 0
+ * be valid before calling start(). */
+int sharedregion_start(void)
+{
+ int retval = 0;
+ struct sharedregion_region *region = NULL;
+ void *shared_addr = NULL;
+ struct heapmemmp_object *heap_handle = NULL;
+ struct heapmemmp_params params;
+ int i;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if ((sharedregion_module->cfg.num_entries == 0) ||
+ (sharedregion_module->regions[0].entry.is_valid == false)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ /*
+ * Loop through shared regions. If an owner of a region is specified
+ * and create_heap has been specified for the SharedRegion, then
+ * the owner creates a HeapMemMP and the other processors open it.
+ */
+ for (i = 0; i < sharedregion_module->cfg.num_entries; i++) {
+ region = &(sharedregion_module->regions[i]);
+ if ((region->entry.is_valid)
+ && (region->entry.owner_proc_id == multiproc_self())
+ && (region->entry.create_heap)
+ && (region->heap == NULL)) {
+ /* get the next free address in each region */
+ shared_addr = (void *)((u32) region->entry.base
+ + region->reserved_size);
+
+ /* Create the HeapMemMP in the region. */
+ heapmemmp_params_init(&params);
+ params.shared_addr = shared_addr;
+ params.shared_buf_size =
+ region->entry.len - region->reserved_size;
+
+ /* Adjust to account for the size of HeapMemMP_Attrs */
+ params.shared_buf_size -=
+ ((heapmemmp_shared_mem_req(&params) - \
+ params.shared_buf_size));
+ heap_handle = heapmemmp_create(&params);
+ if (heap_handle == NULL) {
+ retval = -1;
+ break;
+ } else {
+ region->heap = heap_handle;
+ }
+ }
+ }
+
+error:
+ if (retval < 0)
+ pr_err("sharedregion_start failed status:%x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(sharedregion_start);
+
+/* Function to stop the SharedRegion module */
+int sharedregion_stop(void)
+{
+ int retval = 0;
+ int tmp_status = 0;
+ struct sharedregion_region *region = NULL;
+ int i;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON((sharedregion_module->cfg.num_entries == 0)
+ || (sharedregion_module->regions[0].entry.is_valid == false))) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ /*
+ * Loop through shared regions. If an owner of a region is specified
+ * and create_heap has been specified for the SharedRegion, then
+ * the other processors close it and the owner deletes the HeapMemMP.
+ */
+ for (i = 0; i < sharedregion_module->cfg.num_entries; i++) {
+ region = &(sharedregion_module->regions[i]);
+ if ((region->entry.is_valid)
+ && (region->entry.owner_proc_id == multiproc_self())
+ && (region->entry.create_heap)
+ && (region->heap != NULL)) {
+ /* Delete heap */
+ tmp_status = heapmemmp_delete((void **)&(region->heap));
+ if ((tmp_status < 0) && (retval >= 0))
+ retval = -1;
+ }
+ memset(region, 0, sizeof(struct sharedregion_region));
+ }
+
+ /* set the defaults for region 0 */
+ sharedregion_module->regions[0].entry.create_heap = true;
+ sharedregion_module->regions[0].entry.owner_proc_id = multiproc_self();
+
+error:
+ if (retval < 0)
+ pr_err("sharedregion_stop failed status:%x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(sharedregion_stop);
+
+/* Opens a heap, for non-owner processors, for each SharedRegion. */
+int sharedregion_attach(u16 remote_proc_id)
+{
+ int retval = 0;
+ struct sharedregion_region *region = NULL;
+ void *shared_addr = NULL;
+ int i;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON((remote_proc_id > MULTIPROC_MAXPROCESSORS))) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * Loop through the regions and open the heap if not owner
+ */
+ for (i = 0; i < sharedregion_module->cfg.num_entries; i++) {
+ region = &(sharedregion_module->regions[i]);
+ if ((region->entry.is_valid) && \
+ (region->entry.owner_proc_id != multiproc_self()) && \
+ (region->entry.owner_proc_id != \
+ SHAREDREGION_DEFAULTOWNERID) && \
+ (region->entry.create_heap) && (region->heap == NULL)) {
+ /* SharedAddr should match creator's for each region */
+ shared_addr = (void *)((u32) region->entry.base +
+ region->reserved_size);
+
+ /* Heap should already be created so open by address */
+ retval = heapmemmp_open_by_addr(shared_addr,
+ (void **) &(region->heap));
+ if (retval < 0) {
+ retval = -1;
+ break;
+ }
+ }
+ }
+
+error:
+ if (retval < 0)
+ pr_err("sharedregion_attach failed status:%x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(sharedregion_attach);
+
+/* Closes a heap, for non-owner processors, for each SharedRegion. */
+int sharedregion_detach(u16 remote_proc_id)
+{
+ int retval = 0;
+ int tmp_status = 0;
+ struct sharedregion_region *region = NULL;
+ u16 i;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON((remote_proc_id > MULTIPROC_MAXPROCESSORS))) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * Loop through the regions and open the heap if not owner
+ */
+ for (i = 0; i < sharedregion_module->cfg.num_entries; i++) {
+ region = &(sharedregion_module->regions[i]);
+ if ((region->entry.is_valid) && \
+ (region->entry.owner_proc_id != multiproc_self()) && \
+ (region->entry.owner_proc_id != \
+ SHAREDREGION_DEFAULTOWNERID) && \
+ (region->entry.create_heap) && (region->heap != NULL)) {
+ /* Heap should already be created so open by address */
+ tmp_status = heapmemmp_close((void **) &(region->heap));
+ if ((tmp_status < 0) && (retval >= 0)) {
+ retval = -1;
+ pr_err("sharedregion_detach: "
+ "heapmemmp_close failed!");
+ }
+ }
+ }
+
+error:
+ if (retval < 0)
+ pr_err("sharedregion_detach failed status:%x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(sharedregion_detach);
+
+/* This will return the address pointer associated with the
+ * shared region pointer */
+void *sharedregion_get_ptr(u32 *srptr)
+{
+ struct sharedregion_region *region = NULL;
+ void *return_ptr = NULL;
+ u16 region_id;
+ s32 retval = 0;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (srptr == SHAREDREGION_INVALIDSRPTR)
+ goto error;
+
+ if (sharedregion_module->cfg.translate == false)
+ return_ptr = (void *)srptr;
+ else {
+ region_id = \
+ ((u32)(srptr) >> sharedregion_module->num_offset_bits);
+ if (region_id >= sharedregion_module->cfg.num_entries) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ region = &(sharedregion_module->regions[region_id]);
+ return_ptr = (void *)(((u32)srptr & \
+ sharedregion_module->offset_mask) + \
+ (u32) region->entry.base);
+ }
+ return return_ptr;
+
+error:
+ pr_err("sharedregion_get_ptr failed 0x%x\n", retval);
+ return (void *)NULL;
+
+}
+EXPORT_SYMBOL(sharedregion_get_ptr);
+
+/* This will return sharedregion pointer associated with the
+ * an address in a shared region area registered with the
+ * sharedregion module */
+u32 *sharedregion_get_srptr(void *addr, u16 id)
+{
+ struct sharedregion_region *region = NULL;
+ u32 *ret_ptr = SHAREDREGION_INVALIDSRPTR ;
+ s32 retval = 0;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(addr == NULL))
+ goto error;
+
+ if (WARN_ON(id >= sharedregion_module->cfg.num_entries))
+ goto error;
+
+ if (sharedregion_module->cfg.translate == false)
+ ret_ptr = (u32 *)addr;
+ else {
+ region = &(sharedregion_module->regions[id]);
+ /*
+ * Note: The very last byte on the very last id cannot be
+ * mapped because SharedRegion_INVALIDSRPTR which is ~0
+ * denotes an error. Since pointers should be word
+ * aligned, we don't expect this to be a problem.
+ *
+ * ie: numEntries = 4, id = 3, base = 0x00000000,
+ * len = 0x40000000 ==> address 0x3fffffff would be
+ * invalid because the SRPtr for this address is
+ * 0xffffffff
+ */
+ if (((u32) addr >= (u32) region->entry.base) && ((u32) addr < \
+ ((u32) region->entry.base + region->entry.len))) {
+ ret_ptr = (u32 *)
+ ((id << sharedregion_module->num_offset_bits) |
+ ((u32) addr - (u32) region->entry.base));
+ }
+ }
+ return ret_ptr;
+
+error:
+ pr_err("sharedregion_get_srptr failed 0x%x\n", retval);
+ return (u32 *)NULL;
+}
+EXPORT_SYMBOL(sharedregion_get_srptr);
+
+#if 0
+/*
+ * ======== sharedregion_add ========
+ * Purpose:
+ * This will add a memory segment to the lookup table
+ * during runtime by base and length
+ */
+int sharedregion_add(u32 index, void *base, u32 len)
+{
+ struct sharedregion_info *entry = NULL;
+ struct sharedregion_info *table = NULL;
+ s32 retval = 0;
+ u32 i;
+ u16 myproc_id;
+ bool overlap = false;
+ bool same = false;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (index >= sharedregion_module->cfg.num_entries ||
+ sharedregion_module->region_size < len) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ myproc_id = multiproc_get_id(NULL);
+ retval = mutex_lock_interruptible(sharedregion_module->local_lock);
+ if (retval)
+ goto error;
+
+
+ table = sharedregion_module->table;
+ /* Check for overlap */
+ for (i = 0; i < sharedregion_module->cfg.num_entries; i++) {
+ entry = (table
+ + (myproc_id * sharedregion_module->cfg.num_entries)
+ + i);
+ if (entry->is_valid) {
+ /* Handle duplicate entry */
+ if ((base == entry->base) && (len == entry->len)) {
+ same = true;
+ break;
+ }
+
+ if ((base >= entry->base) &&
+ (base < (void *)
+ ((u32)entry->base + entry->len))) {
+ overlap = true;
+ break;
+ }
+
+ if ((base < entry->base) &&
+ (void *)((u32)base + len) >= entry->base) {
+ overlap = true;
+ break;
+ }
+ }
+ }
+
+ if (same) {
+ retval = 1;
+ goto success;
+ }
+
+ if (overlap) {
+ /* FHACK: FIX ME */
+ retval = 1;
+ goto mem_overlap_error;
+ }
+
+ entry = (table
+ + (myproc_id * sharedregion_module->cfg.num_entries)
+ + index);
+ if (entry->is_valid == false) {
+ entry->base = base;
+ entry->len = len;
+ entry->is_valid = true;
+
+ } else {
+ /* FHACK: FIX ME */
+ sharedregion_module->ref_count_table[(myproc_id *
+ sharedregion_module->cfg.num_entries)
+ + index] += 1;
+ retval = 1;
+ goto dup_entry_error;
+ }
+
+success:
+ mutex_unlock(sharedregion_module->local_lock);
+ return 0;
+
+dup_entry_error: /* Fall through */
+mem_overlap_error:
+ pr_warn("sharedregion_add entry exists status: %x\n",
+ retval);
+ mutex_unlock(sharedregion_module->local_lock);
+
+error:
+ if (retval < 0)
+ pr_err("sharedregion_add failed status:%x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(sharedregion_add);
+
+/*
+ * ======== sharedregion_remove ========
+ * Purpose:
+ * This will removes a memory segment to the lookup table
+ * during runtime by base and length
+ */
+int sharedregion_remove(u32 index)
+{
+ struct sharedregion_info *entry = NULL;
+ struct sharedregion_info *table = NULL;
+ u16 myproc_id;
+ s32 retval = 0;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (index >= sharedregion_module->cfg.num_entries) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ retval = mutex_lock_interruptible(sharedregion_module->local_lock);
+ if (retval)
+ goto error;
+
+ myproc_id = multiproc_get_id(NULL);
+ table = sharedregion_module->table;
+ entry = (table
+ + (myproc_id * sharedregion_module->cfg.num_entries)
+ + index);
+
+ if (sharedregion_module->ref_count_table[(myproc_id *
+ sharedregion_module->cfg.num_entries)
+ + index] > 0)
+ sharedregion_module->ref_count_table[(myproc_id *
+ sharedregion_module->cfg.num_entries)
+ + index] -= 1;
+ else {
+ entry->is_valid = false;
+ entry->base = NULL;
+ entry->len = 0;
+ }
+ mutex_unlock(sharedregion_module->local_lock);
+ return 0;
+
+error:
+ pr_err("sharedregion_remove failed status:%x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(sharedregion_remove);
+
+/*
+ * ======== sharedregion_get_table_info ========
+ * Purpose:
+ * This will get the table entry information for the
+ * specified index and id
+ */
+int sharedregion_get_table_info(u32 index, u16 proc_id,
+ struct sharedregion_info *info)
+{
+ struct sharedregion_info *entry = NULL;
+ struct sharedregion_info *table = NULL;
+ u16 proc_count;
+ s32 retval = 0;
+
+ BUG_ON(info == NULL);
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ proc_count = multiproc_get_max_processors();
+ if (index >= sharedregion_module->cfg.num_entries ||
+ proc_id >= proc_count) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ retval = mutex_lock_interruptible(sharedregion_module->local_lock);
+ if (retval)
+ goto error;
+
+ table = sharedregion_module->table;
+ entry = (table
+ + (proc_id * sharedregion_module->cfg.num_entries)
+ + index);
+ memcpy((void *) info, (void *) entry, sizeof(struct sharedregion_info));
+ mutex_unlock(sharedregion_module->local_lock);
+ return 0;
+
+error:
+ pr_err("sharedregion_get_table_info failed status:%x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(sharedregion_get_table_info);
+
+/*
+ * ======== sharedregion_set_table_info ========
+ * Purpose:
+ * This will set the table entry information for the
+ * specified index and id
+ */
+int sharedregion_set_table_info(u32 index, u16 proc_id,
+ struct sharedregion_info *info)
+{
+ struct sharedregion_info *entry = NULL;
+ struct sharedregion_info *table = NULL;
+ u16 proc_count;
+ s32 retval = 0;
+
+ BUG_ON(info == NULL);
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ proc_count = multiproc_get_max_processors();
+ if (index >= sharedregion_module->cfg.num_entries ||
+ proc_id >= proc_count) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ retval = mutex_lock_interruptible(sharedregion_module->local_lock);
+ if (retval)
+ goto error;
+
+ table = sharedregion_module->table;
+ entry = (table
+ + (proc_id * sharedregion_module->cfg.num_entries)
+ + index);
+ memcpy((void *) entry, (void *) info, sizeof(struct sharedregion_info));
+ mutex_unlock(sharedregion_module->local_lock);
+ return 0;
+
+error:
+ pr_err("sharedregion_set_table_info failed status:%x\n", retval);
+ return retval;
+}
+EXPORT_SYMBOL(sharedregion_set_table_info);
+#endif
+
+/* Return the region info */
+void sharedregion_get_region_info(u16 id, struct sharedregion_region *region)
+{
+ struct sharedregion_region *regions = NULL;
+ s32 retval = 0;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(id >= sharedregion_module->cfg.num_entries)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (WARN_ON(region == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ regions = &(sharedregion_module->regions[id]);
+ memcpy((void *) region, (void *) regions,
+ sizeof(struct sharedregion_region));
+
+error:
+ if (retval < 0) {
+ pr_err("sharedregion_get_region_info failed: "
+ "status = 0x%x", retval);
+ }
+ return;
+}
+
+/* Whether address translation is enabled */
+bool sharedregion_translate_enabled(void)
+{
+ return sharedregion_module->cfg.translate;
+}
+
+/* Gets the number of regions */
+u16 sharedregion_get_num_regions(void)
+{
+ return sharedregion_module->cfg.num_entries;
+}
+
+/* Sets the table information entry in the table */
+int sharedregion_set_entry(u16 id, struct sharedregion_entry *entry)
+{
+ int retval = 0;
+ struct sharedregion_region *region = NULL;
+ void *shared_addr = NULL;
+ struct heapmemmp_object *heap_handle = NULL;
+ struct heapmemmp_object **heap_handle_ptr = NULL;
+ struct heapmemmp_params params;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(entry == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (WARN_ON(id >= sharedregion_module->cfg.num_entries)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ region = &(sharedregion_module->regions[id]);
+
+ /* Make sure region does not overlap existing ones */
+ retval = _sharedregion_check_overlap(region->entry.base,
+ region->entry.len);
+ if (retval < 0) {
+ pr_err("sharedregion_set_entry: Entry is overlapping "
+ "existing entry!");
+ goto error;
+ }
+ if (region->entry.is_valid) {
+ /*region entry should be invalid at this point */
+ retval = -EEXIST;
+ pr_err("_sharedregion_setEntry: Entry already exists");
+ goto error;
+ }
+ if ((entry->cache_enable) && (entry->cache_line_size == 0)) {
+ /* if cache enabled, cache line size must != 0 */
+ retval = -1;
+ pr_err("_sharedregion_setEntry: If cache enabled, "
+ "cache line size must != 0");
+ goto error;
+ }
+
+ /* needs to be thread safe */
+ retval = mutex_lock_interruptible(sharedregion_module->local_lock);
+ if (retval)
+ goto error;
+ /* set specified region id to entry values */
+ memcpy((void *)&(region->entry), (void *)entry,
+ sizeof(struct sharedregion_entry));
+ mutex_unlock(sharedregion_module->local_lock);
+
+ if (entry->owner_proc_id == multiproc_self()) {
+ if ((entry->create_heap) && (region->heap == NULL)) {
+ /* get current Ptr (reserve memory with size of 0) */
+ shared_addr = sharedregion_reserve_memory(id, 0);
+ heapmemmp_params_init(&params);
+ params.shared_addr = shared_addr;
+ params.shared_buf_size = region->entry.len - \
+ region->reserved_size;
+
+ /*
+ * Calculate size of HeapMemMP_Attrs and adjust
+ * shared_buf_size. Size of HeapMemMP_Attrs =
+ * HeapMemMP_sharedMemReq(&params) -
+ * params.shared_buf_size
+ */
+ params.shared_buf_size -= \
+ (heapmemmp_shared_mem_req(&params) - \
+ params.shared_buf_size);
+
+ heap_handle = heapmemmp_create(&params);
+ if (heap_handle == NULL) {
+ region->entry.is_valid = false;
+ retval = -ENOMEM;
+ goto error;
+ } else
+ region->heap = heap_handle;
+ }
+ } else {
+ if ((entry->create_heap) && (region->heap == NULL)) {
+ /* shared_addr should match creator's for each region */
+ shared_addr = (void *)((u32) region->entry.base
+ + region->reserved_size);
+
+ /* set the pointer to a heap handle */
+ heap_handle_ptr = \
+ (struct heapmemmp_object **) &(region->heap);
+
+ /* open the heap by address */
+ retval = heapmemmp_open_by_addr(shared_addr, (void **)
+ heap_handle_ptr);
+ if (retval < 0) {
+ region->entry.is_valid = false;
+ retval = -1;
+ goto error;
+ }
+ }
+ }
+ return 0;
+
+error:
+ pr_err("sharedregion_set_entry failed! status = 0x%x", retval);
+ return retval;
+}
+
+/* Clears the region in the table */
+int sharedregion_clear_entry(u16 id)
+{
+ int retval = 0;
+ struct sharedregion_region *region = NULL;
+ struct heapmemmp_object *heapmem_ptr = NULL;
+ u16 my_id;
+ u16 owner_proc_id;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(id >= sharedregion_module->cfg.num_entries)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /* Need to make sure not trying to clear Region 0 */
+ if (WARN_ON(id == 0)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ my_id = multiproc_self();
+
+ /* Needs to be thread safe */
+ retval = mutex_lock_interruptible(sharedregion_module->local_lock);
+ if (retval)
+ goto error;
+ region = &(sharedregion_module->regions[id]);
+
+ /* Store these fields to local variables */
+ owner_proc_id = region->entry.owner_proc_id;
+ heapmem_ptr = region->heap;
+
+ /* Clear region to their defaults */
+ region->entry.is_valid = false;
+ region->entry.base = NULL;
+ region->entry.len = 0u;
+ region->entry.owner_proc_id = SHAREDREGION_DEFAULTOWNERID;
+ region->entry.cache_enable = true;
+ region->entry.cache_line_size = \
+ sharedregion_module->cfg.cache_line_size;
+ region->entry.create_heap = false;
+ region->entry.name = NULL;
+ region->reserved_size = 0u;
+ region->heap = NULL;
+ mutex_unlock(sharedregion_module->local_lock);
+
+ /* Delete or close previous created heap outside the gate */
+ if (heapmem_ptr != NULL) {
+ if (owner_proc_id == my_id) {
+ retval = heapmemmp_delete((void **) &heapmem_ptr);
+ if (retval < 0) {
+ retval = -1;
+ goto error;
+ }
+ } else if (owner_proc_id != (u16) SHAREDREGION_DEFAULTOWNERID) {
+ retval = heapmemmp_close((void **) &heapmem_ptr);
+ if (retval < 0) {
+ retval = -1;
+ goto error;
+ }
+ }
+ }
+ return 0;
+
+error:
+ pr_err("sharedregion_clear_entry failed! status = 0x%x", retval);
+ return retval;
+}
+
+/* Clears the reserve memory for each region in the table */
+void sharedregion_clear_reserved_memory(void)
+{
+ struct sharedregion_region *region = NULL;
+ int i;
+
+ /*
+ * Loop through shared regions. If an owner of a region is specified,
+ * the owner zeros out the reserved memory in each region.
+ */
+ for (i = 0; i < sharedregion_module->cfg.num_entries; i++) {
+ region = &(sharedregion_module->regions[i]);
+ if ((region->entry.is_valid) && \
+ (region->entry.owner_proc_id == multiproc_self())) {
+ /* Clear reserved memory */
+ memset(region->entry.base, 0, region->reserved_size);
+
+ /* Writeback invalidate cache if enabled in region */
+ if (region->entry.cache_enable) {
+ /* TODO: Enable cache */
+ /* Cache_wbInv(region->entry.base,
+ region->reserved_size,
+ Cache_Type_ALL,
+ true); */
+ }
+ }
+ }
+}
+
+/* Initializes the entry fields */
+void sharedregion_entry_init(struct sharedregion_entry *entry)
+{
+ s32 retval = 0;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(entry == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /* init the entry to default values */
+ entry->base = NULL;
+ entry->len = 0;
+ entry->owner_proc_id = SHAREDREGION_DEFAULTOWNERID;
+ entry->cache_enable = false; /*Set to true once cache API is done */
+ entry->cache_line_size = sharedregion_module->cfg.cache_line_size;
+ entry->create_heap = false;
+ entry->name = NULL;
+ entry->is_valid = false;
+
+error:
+ if (retval < 0)
+ pr_err("sharedregion_entry_init failed: status = 0x%x", retval);
+ return;
+}
+
+/* Returns Heap Handle of associated id */
+void *sharedregion_get_heap(u16 id)
+{
+ struct heapmemmp_object *heap = NULL;
+ s32 retval = 0;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(id >= sharedregion_module->cfg.num_entries)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * If translate == true or translate == false
+ * and 'id' is not INVALIDREGIONID, then assert id is valid.
+ * Return the heap associated with the region id.
+ *
+ * If those conditions are not met, the id is from
+ * an addres in local memory so return NULL.
+ */
+ if ((sharedregion_module->cfg.translate) || \
+ ((sharedregion_module->cfg.translate == false) && \
+ (id != SHAREDREGION_INVALIDREGIONID))) {
+ heap = sharedregion_module->regions[id].heap;
+ }
+ return (void *)heap;
+
+error:
+ pr_err("sharedregion_get_heap failed: status = 0x%x", retval);
+ return (void *)NULL;
+}
+
+/* This will return the id for the specified address pointer. */
+u16 sharedregion_get_id(void *addr)
+{
+ struct sharedregion_region *region = NULL;
+ u16 region_id = SHAREDREGION_INVALIDREGIONID;
+ u16 i;
+ s32 retval = -ENOENT;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(addr == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ retval = mutex_lock_interruptible(sharedregion_module->local_lock);
+ if (retval) {
+ retval = -ENODEV;
+ goto error;
+ }
+ for (i = 0; i < sharedregion_module->cfg.num_entries; i++) {
+ region = &(sharedregion_module->regions[i]);
+ if (region->entry.is_valid && (addr >= region->entry.base) &&
+ (addr < (void *)((u32)region->entry.base + \
+ (region->entry.len)))) {
+ region_id = i;
+ retval = 0;
+ break;
+ }
+ }
+ mutex_unlock(sharedregion_module->local_lock);
+
+error:
+ if (retval < 0)
+ pr_err("sharedregion_get_id failed: status = 0x%x", retval);
+ return region_id;
+}
+EXPORT_SYMBOL(sharedregion_get_id);
+
+/* Returns the id of shared region that matches name.
+ * Returns sharedregion_INVALIDREGIONID if no region is found. */
+u16 sharedregion_get_id_by_name(char *name)
+{
+ struct sharedregion_region *region = NULL;
+ u16 region_id = SHAREDREGION_INVALIDREGIONID;
+ u16 i;
+ s32 retval = 0;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(name == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /* Needs to be thread safe */
+ retval = mutex_lock_interruptible(sharedregion_module->local_lock);
+ if (retval)
+ goto error;
+ /* loop through entries to find matching name */
+ for (i = 0; i < sharedregion_module->cfg.num_entries; i++) {
+ region = &(sharedregion_module->regions[i]);
+ if (region->entry.is_valid) {
+ if (strcmp(region->entry.name, name) == 0) {
+ region_id = i;
+ break;
+ }
+ }
+ }
+ mutex_unlock(sharedregion_module->local_lock);
+
+error:
+ if (retval < 0) {
+ pr_err("sharedregion_get_id_by_name failed: "
+ "status = 0x%x", retval);
+ }
+ return region_id;
+}
+
+/* Gets the entry information for the specified region id */
+int sharedregion_get_entry(u16 id, struct sharedregion_entry *entry)
+{
+ int retval = 0;
+ struct sharedregion_region *region = NULL;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(entry == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (WARN_ON(id >= sharedregion_module->cfg.num_entries)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ region = &(sharedregion_module->regions[id]);
+ memcpy((void *) entry, (void *) &(region->entry),
+ sizeof(struct sharedregion_entry));
+ return 0;
+
+error:
+ pr_err("sharedregion_get_entry failed: status = 0x%x", retval);
+ return retval;
+}
+
+/* Get cache line size */
+uint sharedregion_get_cache_line_size(u16 id)
+{
+ uint cache_line_size = sizeof(int);
+ s32 retval = 0;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(id >= sharedregion_module->cfg.num_entries)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * If translate == true or translate == false
+ * and 'id' is not INVALIDREGIONID, then assert id is valid.
+ * Return the heap associated with the region id.
+ *
+ * If those conditions are not met, the id is from
+ * an addres in local memory so return NULL.
+ */
+ if ((sharedregion_module->cfg.translate) || \
+ ((sharedregion_module->cfg.translate == false) && \
+ (id != SHAREDREGION_INVALIDREGIONID))) {
+ cache_line_size =
+ sharedregion_module->regions[id].entry.cache_line_size;
+ }
+ return cache_line_size;
+
+error:
+ pr_err("sharedregion_get_cache_line_size failed: "
+ "status = 0x%x", retval);
+ return cache_line_size;
+}
+
+/* Is cache enabled? */
+bool sharedregion_is_cache_enabled(u16 id)
+{
+ bool cache_enable = false;
+ s32 retval = 0;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(id >= sharedregion_module->cfg.num_entries)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * If translate == true or translate == false
+ * and 'id' is not INVALIDREGIONID, then assert id is valid.
+ * Return the heap associated with the region id.
+ *
+ * If those conditions are not met, the id is from
+ * an address in local memory so return NULL.
+ */
+ if ((sharedregion_module->cfg.translate) || \
+ ((sharedregion_module->cfg.translate == false) && \
+ (id != SHAREDREGION_INVALIDREGIONID))) {
+ cache_enable = \
+ sharedregion_module->regions[id].entry.cache_enable;
+ }
+ return cache_enable;
+
+error:
+ pr_err("sharedregion_is_cache_enabled failed: "
+ "status = 0x%x", retval);
+ return false;
+}
+
+/* Reserves the specified amount of memory from the specified region id. */
+void *sharedregion_reserve_memory(u16 id, uint size)
+{
+ void *ret_ptr = NULL;
+ struct sharedregion_region *region = NULL;
+ u32 min_align;
+ uint new_size;
+ uint cur_size;
+ uint cache_line_size = 0;
+ s32 retval = 0;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(id >= sharedregion_module->cfg.num_entries)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (WARN_ON(sharedregion_module->regions[id].entry.is_valid == false)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /*TODO: min_align = Memory_getMaxDefaultTypeAlign();*/min_align = 4;
+ cache_line_size = sharedregion_get_cache_line_size(id);
+ if (cache_line_size > min_align)
+ min_align = cache_line_size;
+
+ region = &(sharedregion_module->regions[id]);
+
+ /* Set the current size to the reserved_size */
+ cur_size = region->reserved_size;
+
+ /* No need to round here since cur_size is already aligned */
+ ret_ptr = (void *)((u32) region->entry.base + cur_size);
+
+ /* Round the new size to the min alignment since */
+ new_size = ROUND_UP(size, min_align);
+
+ /* Need to make sure (cur_size + new_size) is smaller than region len */
+ if (region->entry.len < (cur_size + new_size)) {
+ retval = -EINVAL;
+ pr_err("sharedregion_reserve_memory: Too large size "
+ "is requested to be reserved!");
+ goto error;
+ }
+
+ /* Add the new size to current size */
+ region->reserved_size = cur_size + new_size;
+ return ret_ptr;
+
+error:
+ pr_err("sharedregion_reserve_memory failed: status = 0x%x", retval);
+ return (void *)NULL;
+}
+
+/* Unreserve the specified amount of memory from the specified region id. */
+void sharedregion_unreserve_memory(u16 id, uint size)
+{
+ struct sharedregion_region *region = NULL;
+ u32 min_align;
+ uint new_size;
+ uint cur_size;
+ uint cache_line_size = 0;
+ s32 retval = 0;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(id >= sharedregion_module->cfg.num_entries)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (WARN_ON(sharedregion_module->regions[id].entry.is_valid == false)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ /*TODO: min_align = Memory_getMaxDefaultTypeAlign();*/min_align = 4;
+ cache_line_size = sharedregion_get_cache_line_size(id);
+ if (cache_line_size > min_align)
+ min_align = cache_line_size;
+
+ region = &(sharedregion_module->regions[id]);
+
+ /* Set the current size to the unreservedSize */
+ cur_size = region->reserved_size;
+
+ /* Round the new size to the min alignment since */
+ new_size = ROUND_UP(size, min_align);
+
+ /* Add the new size to current size */
+ region->reserved_size = cur_size - new_size;
+
+error:
+ if (retval < 0) {
+ pr_err("sharedregion_unreserve_memory failed: "
+ "status = 0x%x", retval);
+ }
+ return;
+}
+
+/* =============================================================================
+ * Internal Functions
+ * =============================================================================
+ */
+/* Checks to make sure overlap does not exists. */
+static int _sharedregion_check_overlap(void *base, u32 len)
+{
+ int retval = 0;
+ struct sharedregion_region *region = NULL;
+ u32 i;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ retval = mutex_lock_interruptible(sharedregion_module->local_lock);
+ if (retval)
+ goto error;
+
+ /* check whether new region overlaps existing ones */
+ for (i = 0; i < sharedregion_module->cfg.num_entries; i++) {
+ region = &(sharedregion_module->regions[i]);
+ if (region->entry.is_valid) {
+ if (base >= region->entry.base) {
+ if (base < (void *)((u32) region->entry.base
+ + region->entry.len)) {
+ retval = -1;
+ pr_err("_sharedregion_check_"
+ "_overlap failed: Specified "
+ "region falls within another "
+ "region!");
+ break;
+ }
+ } else {
+ if ((void *)((u32) base + len) > \
+ region->entry.base) {
+ retval = -1;
+ pr_err("_sharedregion_check_"
+ "_overlap failed: Specified "
+ "region spans across multiple "
+ "regions!");
+ break;
+ }
+ }
+ }
+ }
+
+ mutex_unlock(sharedregion_module->local_lock);
+ return 0;
+
+error:
+ pr_err("_sharedregion_check_overlap failed: status = 0x%x", retval);
+ return retval;
+}
+
+/* Return the number of offset_bits bits */
+static u32 _sharedregion_get_num_offset_bits(void)
+{
+ u32 num_entries = sharedregion_module->cfg.num_entries;
+ u32 index_bits = 0;
+ u32 num_offset_bits = 0;
+ s32 retval = 0;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (num_entries == 0 || num_entries == 1)
+ index_bits = num_entries;
+ else {
+ num_entries = num_entries - 1;
+
+ /* determine the number of bits for the index */
+ while (num_entries) {
+ index_bits++;
+ num_entries = num_entries >> 1;
+ }
+ }
+ num_offset_bits = 32 - index_bits;
+
+error:
+ if (retval < 0) {
+ pr_err("_sharedregion_get_num_offset_bits failed: "
+ "status = 0x%x", retval);
+ }
+ return num_offset_bits;
+}
+
+/* Sets the table information entry in the table (doesn't create heap). */
+int _sharedregion_set_entry(u16 id, struct sharedregion_entry *entry)
+{
+ int retval = 0;
+ struct sharedregion_region *region = NULL;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(sharedregion_module->ref_count),
+ SHAREDREGION_MAKE_MAGICSTAMP(0),
+ SHAREDREGION_MAKE_MAGICSTAMP(1)) == true)) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (WARN_ON(entry == NULL)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ if (WARN_ON(id >= sharedregion_module->cfg.num_entries)) {
+ retval = -EINVAL;
+ goto error;
+ }
+
+ region = &(sharedregion_module->regions[id]);
+
+ /* Make sure region does not overlap existing ones */
+ retval = _sharedregion_check_overlap(region->entry.base,
+ region->entry.len);
+ if (retval < 0) {
+ pr_err("_sharedregion_set_entry: Entry is overlapping "
+ "existing entry!");
+ goto error;
+ }
+ if (region->entry.is_valid) {
+ /*region entry should be invalid at this point */
+ retval = -EEXIST;
+ pr_err("_sharedregion_set_entry: ntry already exists");
+ goto error;
+ }
+ /* Fail if cacheEnabled and cache_line_size equal 0 */
+ if ((entry->cache_enable) && (entry->cache_line_size == 0)) {
+ /* if cache enabled, cache line size must != 0 */
+ retval = -1;
+ pr_err("_sharedregion_set_entry: If cache enabled, "
+ "cache line size must != 0");
+ goto error;
+ }
+
+ /* needs to be thread safe */
+ retval = mutex_lock_interruptible(sharedregion_module->local_lock);
+ if (retval)
+ goto error;
+ /* set specified region id to entry values */
+ memcpy((void *)&(region->entry), (void *)entry,
+ sizeof(struct sharedregion_entry));
+ mutex_unlock(sharedregion_module->local_lock);
+ return 0;
+
+error:
+ pr_err("_sharedregion_set_entry failed! status = 0x%x", retval);
+ return retval;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/sharedregion_ioctl.c b/drivers/dsp/syslink/multicore_ipc/sharedregion_ioctl.c
new file mode 100644
index 00000000000..53d209a256b
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/sharedregion_ioctl.c
@@ -0,0 +1,568 @@
+/*
+ * sharedregion_ioctl.c
+ *
+ * The sharedregion module is designed to be used in a
+ * multi-processor environment where there are memory regions
+ * that are shared and accessed across different processors
+ *
+ * Copyright (C) 2008-2010 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 <linux/uaccess.h>
+#include <linux/types.h>
+#include <linux/bug.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <ipc.h>
+#include <multiproc.h>
+#include <sharedregion.h>
+#include <sharedregion_ioctl.h>
+#include <platform_mem.h>
+
+static struct resource_info *find_sharedregion_resource(
+ struct ipc_process_context *pr_ctxt,
+ unsigned int cmd,
+ struct sharedregion_cmd_args *cargs)
+{
+ struct resource_info *info = NULL;
+ bool found = false;
+
+ spin_lock(&pr_ctxt->res_lock);
+
+ list_for_each_entry(info, &pr_ctxt->resources, res) {
+ struct sharedregion_cmd_args *args =
+ (struct sharedregion_cmd_args *)info->data;
+ if (info->cmd == cmd) {
+ switch (cmd) {
+ case CMD_SHAREDREGION_CLEARENTRY:
+ {
+ u16 id = args->args.clear_entry.id;
+ u16 temp = cargs->args.clear_entry.id;
+ if (temp == id)
+ found = true;
+ break;
+ }
+ case CMD_SHAREDREGION_DESTROY:
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found == true)
+ break;
+ }
+ }
+
+ spin_unlock(&pr_ctxt->res_lock);
+
+ if (found == false)
+ info = NULL;
+
+ return info;
+}
+
+/* This ioctl interface to sharedregion_get_config function */
+static int sharedregion_ioctl_get_config(struct sharedregion_cmd_args *cargs)
+{
+
+ struct sharedregion_config config;
+ s32 status = 0;
+ s32 size;
+
+ sharedregion_get_config(&config);
+ size = copy_to_user((void __user *)cargs->args.get_config.config,
+ &config, sizeof(struct sharedregion_config));
+ if (size)
+ status = -EFAULT;
+
+ cargs->api_status = 0;
+ return status;
+}
+
+
+/* This ioctl interface to sharedregion_setup function */
+static int sharedregion_ioctl_setup(struct sharedregion_cmd_args *cargs)
+{
+ struct sharedregion_config config;
+ struct sharedregion_region region;
+ u16 i;
+ s32 status = 0;
+ s32 size;
+
+ size = copy_from_user(&config, (void __user *)cargs->args.setup.config,
+ sizeof(struct sharedregion_config));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ cargs->api_status = sharedregion_setup(&config);
+ if (cargs->api_status < 0)
+ goto exit;
+
+ for (i = 0; i < config.num_entries; i++) {
+ sharedregion_get_region_info(i, &region);
+ if (region.entry.is_valid == true) {
+ /* Convert kernel virtual address to physical
+ * addresses */
+ /*region.entry.base = MemoryOS_translate(
+ (Ptr) region.entry.base,
+ Memory_XltFlags_Virt2Phys);*/
+ region.entry.base = platform_mem_translate(
+ region.entry.base,
+ PLATFORM_MEM_XLT_FLAGS_VIRT2PHYS);
+ if (region.entry.base == NULL) {
+ pr_err("sharedregion_ioctl_setup: "
+ "failed to translate region virtual "
+ "address.\n");
+ status = -ENOMEM;
+ goto exit;
+ }
+ size = copy_to_user((void __user *)
+ &(cargs->args.setup.regions[i]),
+ &region,
+ sizeof(struct sharedregion_region));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ }
+ }
+
+exit:
+ return status;
+}
+
+/* This ioctl interface to sharedregion_destroy function */
+static int sharedregion_ioctl_destroy(
+ struct sharedregion_cmd_args *cargs)
+{
+ cargs->api_status = sharedregion_destroy();
+ return 0;
+}
+
+/* This ioctl interface to sharedregion_start function */
+static int sharedregion_ioctl_start(struct sharedregion_cmd_args *cargs)
+{
+ cargs->api_status = sharedregion_start();
+ return 0;
+}
+
+/* This ioctl interface to sharedregion_stop function */
+static int sharedregion_ioctl_stop(struct sharedregion_cmd_args *cargs)
+{
+ cargs->api_status = sharedregion_stop();
+ return 0;
+}
+
+/* This ioctl interface to sharedregion_attach function */
+static int sharedregion_ioctl_attach(struct sharedregion_cmd_args *cargs)
+{
+ cargs->api_status = sharedregion_attach(
+ cargs->args.attach.remote_proc_id);
+ return 0;
+}
+
+/* This ioctl interface to sharedregion_detach function */
+static int sharedregion_ioctl_detach(struct sharedregion_cmd_args *cargs)
+{
+ cargs->api_status = sharedregion_detach(
+ cargs->args.detach.remote_proc_id);
+ return 0;
+}
+
+/* This ioctl interface to sharedregion_get_heap function */
+static int sharedregion_ioctl_get_heap(struct sharedregion_cmd_args *cargs)
+{
+ struct heap_object *heap_handle = NULL;
+ s32 status = 0;
+
+ heap_handle = (struct heap_object *) sharedregion_get_heap(
+ cargs->args.get_heap.id);
+ if (heap_handle != NULL)
+ cargs->api_status = 0;
+ else {
+ pr_err("sharedregion_ioctl_get_heap failed: "
+ "heap_handle is NULL!");
+ cargs->api_status = -1;
+ }
+
+ cargs->args.get_heap.heap_handle = heap_handle;
+
+ return status;
+}
+
+/* This ioctl interface to sharedregion_clear_entry function */
+static int sharedregion_ioctl_clear_entry(struct sharedregion_cmd_args *cargs)
+{
+ cargs->api_status = sharedregion_clear_entry(
+ cargs->args.clear_entry.id);
+ return 0;
+}
+
+/* This ioctl interface to sharedregion_set_entry function */
+static int sharedregion_ioctl_set_entry(struct sharedregion_cmd_args *cargs)
+{
+ struct sharedregion_entry entry;
+ s32 status = 0;
+
+ entry = cargs->args.set_entry.entry;
+ /* entry.base = Memory_translate ((Ptr)cargs->args.setEntry.entry.base,
+ Memory_XltFlags_Phys2Virt); */
+ entry.base = platform_mem_translate(
+ (void *)cargs->args.set_entry.entry.base,
+ PLATFORM_MEM_XLT_FLAGS_PHYS2VIRT);
+ if (entry.base == NULL) {
+ pr_err("sharedregion_ioctl_set_entry: failed to"
+ "translate region virtual address.\n");
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ cargs->api_status = sharedregion_set_entry(cargs->args.set_entry.id,
+ &entry);
+
+exit:
+ return status;
+}
+
+/* This ioctl interface to sharedregion_reserve_memory function */
+static int sharedregion_ioctl_reserve_memory
+ (struct sharedregion_cmd_args *cargs)
+{
+ /* Ignore the return value. */
+ sharedregion_reserve_memory(cargs->args.reserve_memory.id,
+ cargs->args.reserve_memory.size);
+ cargs->api_status = 0;
+ return 0;
+}
+
+/* This ioctl interface to sharedregion_clear_reserved_memory function */
+static int sharedregion_ioctl_clear_reserved_memory(
+ struct sharedregion_cmd_args *cargs)
+{
+ /* Ignore the return value. */
+ sharedregion_clear_reserved_memory();
+ cargs->api_status = 0;
+ return 0;
+}
+
+/* This ioctl interface to sharedregion_get_region_info function */
+static int sharedregion_ioctl_get_region_info(
+ struct sharedregion_cmd_args *cargs)
+{
+ struct sharedregion_config config;
+ struct sharedregion_region region;
+ u16 i;
+ s32 status = 0;
+ s32 size;
+
+ sharedregion_get_config(&config);
+ for (i = 0; i < config.num_entries; i++) {
+ sharedregion_get_region_info(i, &region);
+ if (region.entry.is_valid == true) {
+ /* Convert the kernel virtual address to physical
+ * addresses */
+ /*region.entry.base = MemoryOS_translate (
+ (Ptr)region.entry.base,
+ Memory_XltFlags_Virt2Phys);*/
+ region.entry.base = platform_mem_translate(
+ region.entry.base,
+ PLATFORM_MEM_XLT_FLAGS_VIRT2PHYS);
+ if (region.entry.base == NULL) {
+ pr_err(
+ "sharedregion_ioctl_get_region_info: "
+ "failed to translate region virtual "
+ "address.\n");
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ size = copy_to_user(
+ (void __user *)&(cargs->args.setup.regions[i]),
+ &region,
+ sizeof(struct sharedregion_region));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ } else {
+ region.entry.base = NULL;
+ size = copy_to_user(
+ (void __user *)&(cargs->args.setup.regions[i]),
+ &region,
+ sizeof(struct sharedregion_region));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ }
+ }
+ cargs->api_status = 0;
+
+exit:
+ if (status < 0)
+ cargs->api_status = -1;
+ return status;
+}
+
+#if 0
+/*
+ * ======== sharedregion_ioctl_add ========
+ * Purpose:
+ * This ioctl interface to sharedregion_add function
+ */
+static int sharedregion_ioctl_add(struct sharedregion_cmd_args *cargs)
+{
+ u32 base = (u32)platform_mem_translate(cargs->args.add.base,
+ PLATFORM_MEM_XLT_FLAGS_PHYS2VIRT);
+ cargs->api_status = sharedregion_add(cargs->args.add.index,
+ (void *)base, cargs->args.add.len);
+ return 0;
+}
+
+/*
+ * ======== sharedregion_ioctl_get_index ========
+ * Purpose:
+ * This ioctl interface to sharedregion_get_index function
+ */
+static int sharedregion_ioctl_get_index(struct sharedregion_cmd_args *cargs)
+{
+ s32 index = 0;
+
+ index = sharedregion_get_index(cargs->args.get_index.addr);
+ cargs->args.get_index.index = index;
+ cargs->api_status = 0;
+ return 0;
+}
+
+/*
+ * ======== sharedregion_ioctl_get_ptr ========
+ * Purpose:
+ * This ioctl interface to sharedregion_get_ptr function
+ */
+static int sharedregion_ioctl_get_ptr(struct sharedregion_cmd_args *cargs)
+{
+ void *addr = NULL;
+
+ addr = sharedregion_get_ptr(cargs->args.get_ptr.srptr);
+ /* We are not checking the return from the module, its user
+ responsibilty to pass proper value to application
+ */
+ cargs->args.get_ptr.addr = addr;
+ cargs->api_status = 0;
+ return 0;
+}
+
+/*
+ * ======== sharedregion_ioctl_get_srptr ========
+ * Purpose:
+ * This ioctl interface to sharedregion_get_srptr function
+ */
+static int sharedregion_ioctl_get_srptr(struct sharedregion_cmd_args *cargs)
+{
+ u32 *srptr = NULL;
+
+ srptr = sharedregion_get_srptr(cargs->args.get_srptr.addr,
+ cargs->args.get_srptr.index);
+ /* We are not checking the return from the module, its user
+ responsibilty to pass proper value to application
+ */
+ cargs->args.get_srptr.srptr = srptr;
+ cargs->api_status = 0;
+ return 0;
+}
+
+/*
+ * ======== sharedregion_ioctl_remove ========
+ * Purpose:
+ * This ioctl interface to sharedregion_remove function
+ */
+static int sharedregion_ioctl_remove(struct sharedregion_cmd_args *cargs)
+{
+ cargs->api_status = sharedregion_remove(cargs->args.remove.index);
+ return 0;
+}
+
+/*
+ * ======== sharedregion_ioctl_set_table_info ========
+ * Purpose:
+ * This ioctl interface to sharedregion_set_table_info function
+ */
+static int sharedregion_ioctl_set_table_info(
+ struct sharedregion_cmd_args *cargs)
+{
+ struct sharedregion_info info;
+ s32 status = 0;
+ s32 size;
+
+ size = copy_from_user(&info, cargs->args.set_table_info.info,
+ sizeof(struct sharedregion_info));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ cargs->api_status = sharedregion_set_table_info(
+ cargs->args.set_table_info.index,
+ cargs->args.set_table_info.proc_id, &info);
+
+exit:
+ return status;
+}
+#endif
+
+/* This ioctl interface for sharedregion module */
+int sharedregion_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user)
+{
+ s32 status = 0;
+ s32 size = 0;
+ struct sharedregion_cmd_args __user *uarg =
+ (struct sharedregion_cmd_args __user *)args;
+ struct sharedregion_cmd_args cargs;
+ struct ipc_process_context *pr_ctxt =
+ (struct ipc_process_context *)filp->private_data;
+
+ if (user == true) {
+#ifdef CONFIG_SYSLINK_RECOVERY
+ if (ipc_recovering()) {
+ status = -EIO;
+ goto exit;
+ }
+#endif
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ status = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ status = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
+
+ if (status) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ /* Copy the full args from user-side */
+ size = copy_from_user(&cargs, uarg,
+ sizeof(struct sharedregion_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ } else {
+ if (args != 0)
+ memcpy(&cargs, (void *)args,
+ sizeof(struct sharedregion_cmd_args));
+ }
+
+ switch (cmd) {
+ case CMD_SHAREDREGION_GETCONFIG:
+ status = sharedregion_ioctl_get_config(&cargs);
+ break;
+
+ case CMD_SHAREDREGION_SETUP:
+ status = sharedregion_ioctl_setup(&cargs);
+ if (status >= 0)
+ add_pr_res(pr_ctxt, CMD_SHAREDREGION_DESTROY, NULL);
+ break;
+
+ case CMD_SHAREDREGION_DESTROY:
+ {
+ struct resource_info *info = NULL;
+ info = find_sharedregion_resource(pr_ctxt,
+ CMD_SHAREDREGION_DESTROY,
+ &cargs);
+ status = sharedregion_ioctl_destroy(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_SHAREDREGION_START:
+ status = sharedregion_ioctl_start(&cargs);
+ break;
+
+ case CMD_SHAREDREGION_STOP:
+ status = sharedregion_ioctl_stop(&cargs);
+ break;
+
+ case CMD_SHAREDREGION_ATTACH:
+ status = sharedregion_ioctl_attach(&cargs);
+ break;
+
+ case CMD_SHAREDREGION_DETACH:
+ status = sharedregion_ioctl_detach(&cargs);
+ break;
+
+ case CMD_SHAREDREGION_GETHEAP:
+ status = sharedregion_ioctl_get_heap(&cargs);
+ break;
+
+ case CMD_SHAREDREGION_CLEARENTRY:
+ {
+ struct resource_info *info = NULL;
+ info = find_sharedregion_resource(pr_ctxt,
+ CMD_SHAREDREGION_CLEARENTRY,
+ &cargs);
+ status = sharedregion_ioctl_clear_entry(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_SHAREDREGION_SETENTRY:
+ status = sharedregion_ioctl_set_entry(&cargs);
+ if (status >= 0) {
+ struct sharedregion_cmd_args *temp =
+ kmalloc(sizeof(struct sharedregion_cmd_args),
+ GFP_KERNEL);
+ if (WARN_ON(!temp)) {
+ status = -ENOMEM;
+ goto exit;
+ }
+ temp->args.clear_entry.id = cargs.args.set_entry.id;
+ add_pr_res(pr_ctxt, CMD_SHAREDREGION_CLEARENTRY, temp);
+ }
+ break;
+
+ case CMD_SHAREDREGION_RESERVEMEMORY:
+ status = sharedregion_ioctl_reserve_memory(&cargs);
+ break;
+
+ case CMD_SHAREDREGION_CLEARRESERVEDMEMORY:
+ status = sharedregion_ioctl_clear_reserved_memory(&cargs);
+ break;
+
+ case CMD_SHAREDREGION_GETREGIONINFO:
+ status = sharedregion_ioctl_get_region_info(&cargs);
+ break;
+
+ default:
+ WARN_ON(cmd);
+ status = -ENOTTY;
+ break;
+ }
+
+ if (user == true) {
+ /* Copy the full args to the user-side. */
+ size = copy_to_user(uarg, &cargs,
+ sizeof(struct sharedregion_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ }
+
+exit:
+ if (status < 0)
+ pr_err("sharedregion_ioctl failed! status = 0x%x", status);
+ return status;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/sysipc_ioctl.c b/drivers/dsp/syslink/multicore_ipc/sysipc_ioctl.c
new file mode 100644
index 00000000000..4ee64a19b70
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/sysipc_ioctl.c
@@ -0,0 +1,305 @@
+/*
+ * sysipc_ioctl.c
+ *
+ * This file implements all the ioctl operations required on the sysmgr
+ * module.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+/* Standard headers */
+#include <linux/types.h>
+
+/* Linux headers */
+#include <linux/uaccess.h>
+#include <linux/bug.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+/* Module Headers */
+#include <ipc.h>
+#include <sysipc_ioctl.h>
+/*#include <platform.h>*/
+
+
+static struct resource_info *find_sysipc_resource(
+ struct ipc_process_context *pr_ctxt,
+ unsigned int cmd,
+ struct sysipc_cmd_args *cargs)
+{
+ struct resource_info *info = NULL;
+ bool found = false;
+
+ spin_lock(&pr_ctxt->res_lock);
+
+ list_for_each_entry(info, &pr_ctxt->resources, res) {
+ struct sysipc_cmd_args *args =
+ (struct sysipc_cmd_args *)info->data;
+ if (info->cmd == cmd) {
+ switch (cmd) {
+ case CMD_IPC_CONTROL:
+ {
+ s32 cmd_id = args->args.control.cmd_id;
+ s32 t_cmd_id = cargs->args.control.cmd_id;
+ u16 proc_id = args->args.control.proc_id;
+ u16 t_proc_id = cargs->args.control.proc_id;
+ if (cmd_id == t_cmd_id && proc_id == t_proc_id)
+ found = true;
+ break;
+ }
+ case CMD_IPC_DESTROY:
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found == true)
+ break;
+ }
+ }
+
+ spin_unlock(&pr_ctxt->res_lock);
+
+ if (found == false)
+ info = NULL;
+
+ return info;
+}
+
+/*
+ * ioctl interface to ipc_setup function
+ */
+static inline int sysipc_ioctl_setup(struct sysipc_cmd_args *cargs)
+{
+ s32 retval = 0;
+ unsigned long size;
+ struct ipc_config config;
+
+ size = copy_from_user(&config, (void __user *)cargs->args.setup.config,
+ sizeof(struct ipc_config));
+ if (size) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ cargs->api_status = ipc_setup(&config);
+
+exit:
+ return retval;
+}
+
+/*
+ * ioctl interface to ipc_control function
+ */
+static inline int sysipc_ioctl_control(struct sysipc_cmd_args *cargs)
+{
+ cargs->api_status = ipc_control(cargs->args.control.proc_id,
+ cargs->args.control.cmd_id,
+ cargs->args.control.arg);
+ return 0;
+}
+
+/*
+ * ioctl interface to ipc_read_config function
+ */
+static inline int sysipc_ioctl_read_config(struct sysipc_cmd_args *cargs)
+{
+ s32 retval = 0;
+ unsigned long size;
+ void *cfg = NULL;
+
+ cfg = kzalloc(cargs->args.read_config.size, GFP_KERNEL);
+ if (cfg == NULL) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ cargs->api_status = ipc_read_config(
+ cargs->args.read_config.remote_proc_id,
+ cargs->args.read_config.tag, cfg,
+ cargs->args.read_config.size);
+
+ size = copy_to_user((void __user *)cargs->args.read_config.cfg, cfg,
+ cargs->args.read_config.size);
+ if (size)
+ retval = -EFAULT;
+
+ kfree(cfg);
+
+exit:
+ return retval;
+}
+
+/*
+ * ioctl interface to ipc_write_config function
+ */
+static inline int sysipc_ioctl_write_config(struct sysipc_cmd_args *cargs)
+{
+ s32 retval = 0;
+ unsigned long size;
+ void *cfg = NULL;
+
+ cfg = kzalloc(cargs->args.write_config.size, GFP_KERNEL);
+ if (cfg == NULL) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ size = copy_from_user(cfg, (void __user *)cargs->args.write_config.cfg,
+ cargs->args.write_config.size);
+ if (size) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ cargs->api_status = ipc_write_config(
+ cargs->args.write_config.remote_proc_id,
+ cargs->args.write_config.tag, cfg,
+ cargs->args.write_config.size);
+
+ kfree(cfg);
+
+exit:
+ return retval;
+}
+
+/*
+ * ioctl interface to sysmgr_destroy function
+ */
+static inline int sysipc_ioctl_destroy(struct sysipc_cmd_args *cargs)
+{
+ cargs->api_status = ipc_destroy();
+ return 0;
+}
+
+/*
+ * ioctl interface function for sysmgr module
+ */
+int sysipc_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long args, bool user)
+{
+ int status = 0;
+ struct sysipc_cmd_args __user *uarg =
+ (struct sysipc_cmd_args __user *)args;
+ struct sysipc_cmd_args cargs;
+ unsigned long size;
+ struct ipc_process_context *pr_ctxt =
+ (struct ipc_process_context *)filp->private_data;
+
+ if (user == true) {
+#ifdef CONFIG_SYSLINK_RECOVERY
+ if (ipc_recovering()) {
+ status = -EIO;
+ goto exit;
+ }
+#endif
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ status = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ status = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
+ if (status) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ /* Copy the full args from user-side */
+ size = copy_from_user(&cargs, uarg,
+ sizeof(struct sysipc_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ } else {
+ if (args != 0)
+ memcpy(&cargs, (void *)args,
+ sizeof(struct sysipc_cmd_args));
+ }
+
+ switch (cmd) {
+ case CMD_IPC_SETUP:
+ status = sysipc_ioctl_setup(&cargs);
+ if (status >= 0)
+ add_pr_res(pr_ctxt, CMD_IPC_DESTROY, NULL);
+ break;
+
+ case CMD_IPC_DESTROY:
+ {
+ struct resource_info *info = NULL;
+ info = find_sysipc_resource(pr_ctxt, CMD_IPC_DESTROY,
+ &cargs);
+ status = sysipc_ioctl_destroy(&cargs);
+ remove_pr_res(pr_ctxt, info);
+ break;
+ }
+
+ case CMD_IPC_CONTROL:
+ {
+ u32 id = cargs.args.control.proc_id;
+ u32 ctrl_cmd = cargs.args.control.cmd_id;
+ struct resource_info *info = NULL;
+
+ info = find_sysipc_resource(pr_ctxt, CMD_IPC_CONTROL,
+ &cargs);
+
+ status = sysipc_ioctl_control(&cargs);
+ if (ctrl_cmd == IPC_CONTROLCMD_STARTCALLBACK) {
+ if (status >= 0) {
+ struct sysipc_cmd_args *temp = kmalloc(
+ sizeof(struct sysipc_cmd_args),
+ GFP_KERNEL);
+ if (WARN_ON(!temp)) {
+ status = -ENOMEM;
+ goto exit;
+ }
+ temp->args.control.cmd_id =
+ IPC_CONTROLCMD_STOPCALLBACK;
+ temp->args.control.proc_id = id;
+ temp->args.control.arg = NULL;
+ add_pr_res(pr_ctxt, CMD_IPC_CONTROL,
+ (void *)temp);
+ }
+ } else if (ctrl_cmd == IPC_CONTROLCMD_STOPCALLBACK) {
+ remove_pr_res(pr_ctxt, info);
+ }
+ break;
+ }
+
+ case CMD_IPC_READCONFIG:
+ status = sysipc_ioctl_read_config(&cargs);
+ break;
+
+ case CMD_IPC_WRITECONFIG:
+ status = sysipc_ioctl_write_config(&cargs);
+ break;
+
+ default:
+ WARN_ON(cmd);
+ status = -ENOTTY;
+ break;
+ }
+ if (status < 0)
+ goto exit;
+
+ if (user == true) {
+ /* Copy the full args to the user-side. */
+ size = copy_to_user(uarg, &cargs,
+ sizeof(struct sysipc_cmd_args));
+ if (size) {
+ status = -EFAULT;
+ goto exit;
+ }
+ }
+
+exit:
+ return status;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/sysmemmgr.c b/drivers/dsp/syslink/multicore_ipc/sysmemmgr.c
new file mode 100644
index 00000000000..ef09bdfc4e7
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/sysmemmgr.c
@@ -0,0 +1,458 @@
+/*
+ * sysmemmgr.c
+ *
+ * Manager for the Slave system memory. Slave system level memory is allocated
+ * through this modules.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+
+/* Standard headers */
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+/* Utils headers */
+#include <linux/vmalloc.h>
+#include <syslink/atomic_linux.h>
+#include <syslink/platform_mem.h>
+/*#include <GateMutex.h>
+#include <Memory.h>
+#include <Trace.h>*/
+
+
+/* Module level headers */
+#include <sysmemmgr.h>
+/*#include <BuddyPageAllocator.h>*/
+
+
+/* =============================================================================
+ * Macros
+ * =============================================================================
+ */
+/*! @brief Event reserved for System memory manager */
+#define SYSMEMMGR_EVENTNO 12
+
+/* Macro to make a correct module magic number with ref_count */
+#define SYSMEMMGR_MAKE_MAGICSTAMP(x) ((SYSMEMMGR_MODULEID << 12) | (x))
+
+/* =============================================================================
+ * Structs & Enums
+ * =============================================================================
+ */
+/*! @brief Structure containing list of buffers. The list is kept sorted by
+ * address. */
+struct sysmemmgr_static_mem_struct {
+ struct sysmemmgr_static_mem_struct *next;
+ /*!< Pointer to next entry */
+ u32 address;
+ /*!< Address of this entry */
+ u32 size;
+ /*!< Size of this entry */
+};
+
+
+/*! @brief Static memory manager object. */
+struct sysmemmgr_static_mem_mgr_obj {
+ struct sysmemmgr_static_mem_struct head;
+ /*!< Pointer to head entry */
+ struct sysmemmgr_static_mem_struct tail;
+ /*!< Pointer to tail entry */
+};
+
+/*!
+ * @brief Structure defining state object of system memory manager.
+ */
+struct sysmemmgr_module_object {
+ atomic_t ref_count;
+ /*!< Reference count */
+ struct sysmemmgr_static_mem_mgr_obj static_mem_obj;
+ /*!< Static memory manager object */
+ struct mutex *gate_handle;
+ /*!< Pointer to lock */
+ struct sysmemmgr_config cfg;
+ /*!< Current configuration values */
+ struct sysmemmgr_config default_cfg;
+ /*!< Default configuration values */
+};
+
+
+/*!
+ * @brief Object containing state of the system memory manager.
+ */
+static struct sysmemmgr_module_object sysmemmgr_state = {
+ .default_cfg.sizeof_valloc = 0x100000,
+ .default_cfg.sizeof_palloc = 0x100000,
+ .default_cfg.page_size = 0x1000,
+ .default_cfg.event_no = SYSMEMMGR_EVENTNO,
+};
+
+
+/* =============================================================================
+ * APIS
+ * =============================================================================
+ */
+/*
+ * ======== sysmemmgr_get_config ========
+ * Purpose:
+ * Function to get the default values for configuration.
+ */
+void sysmemmgr_get_config(struct sysmemmgr_config *config)
+{
+ if (WARN_ON(config == NULL))
+ goto err_exit;
+
+ if (atomic_cmpmask_and_lt(&(sysmemmgr_state.ref_count),
+ SYSMEMMGR_MAKE_MAGICSTAMP(0),
+ SYSMEMMGR_MAKE_MAGICSTAMP(1)) == true)
+ memcpy((void *) config, (void *)(&sysmemmgr_state.default_cfg),
+ sizeof(struct sysmemmgr_config));
+ else
+ memcpy((void *) config, (void *)(&sysmemmgr_state.cfg),
+ sizeof(struct sysmemmgr_config));
+
+ return;
+
+err_exit:
+ pr_err("sysmemmgr_get_config: Argument of type "
+ "(struct sysmemmgr_config *) passed is NULL\n");
+ return;
+}
+
+
+/*
+ * ======== sysmemmgr_setup ========
+ * Purpose:
+ * Function to get the default values for configuration.
+ */
+int sysmemmgr_setup(struct sysmemmgr_config *config)
+{
+ int status = 0;
+ struct sysmemmgr_static_mem_mgr_obj *smmObj = NULL;
+
+ /* This sets the ref_count variable is not initialized, upper 16 bits is
+ * written with module Id to ensure correctness of ref_count variable.
+ */
+ atomic_cmpmask_and_set(&sysmemmgr_state.ref_count,
+ SYSMEMMGR_MAKE_MAGICSTAMP(0), SYSMEMMGR_MAKE_MAGICSTAMP(0));
+
+ if (atomic_inc_return(&sysmemmgr_state.ref_count) != \
+ SYSMEMMGR_MAKE_MAGICSTAMP(1)) {
+ status = SYSMEMMGR_S_ALREADYSETUP;
+ goto exit;
+ }
+
+ if (WARN_ON(config == NULL)) {
+ /* Config parameters are not provided */
+ status = -EINVAL;
+ goto err_config;
+ }
+ if (WARN_ON((config->static_virt_base_addr == (u32) NULL)
+ && (config->static_mem_size != 0))) {
+ /* Virtual Base address of static memory region is NULL */
+ status = -EINVAL;
+ goto err_virt_addr;
+ }
+ if (WARN_ON((config->static_phys_base_addr == (u32) NULL)
+ && (config->static_mem_size != 0))) {
+ /*Physical Base address of static memory region is NULL */
+ status = -EINVAL;
+ goto err_phys_addr;
+ }
+
+ /* Copy the config parameters to the module state */
+ memcpy((void *)(&sysmemmgr_state.cfg), (void *) config,
+ sizeof(struct sysmemmgr_config));
+
+ /* Create the static memory allocator */
+ if (config->static_mem_size != 0) {
+ smmObj = &sysmemmgr_state.static_mem_obj;
+ smmObj->head.address = config->static_virt_base_addr;
+ smmObj->head.size = 0;
+ smmObj->tail.address = (config->static_virt_base_addr + \
+ config->static_mem_size);
+ smmObj->tail.size = 0;
+ smmObj->head.next = &smmObj->tail;
+ smmObj->tail.next = NULL;
+ }
+
+ /* Create the lock */
+ sysmemmgr_state.gate_handle = kzalloc(sizeof(struct mutex), GFP_KERNEL);
+ if (sysmemmgr_state.gate_handle == NULL) {
+ /* Failed to create gate handle */
+ status = -ENOMEM;
+ goto err_mem_gate;
+ }
+ return 0;
+
+err_mem_gate:
+ pr_err("sysmemmgr_setup: Failed to create gate handle\n");
+ goto exit;
+
+err_phys_addr:
+ pr_err("sysmemmgr_setup: Physical Base address of static "
+ "memory region is NULL\n");
+ goto exit;
+
+err_virt_addr:
+ pr_err("sysmemmgr_setup: Virtual Base address of static "
+ "memory region is NULL\n");
+ goto exit;
+
+err_config:
+ pr_err("sysmemmgr_setup: Argument of type "
+ "(struct sysmemmgr_config *) passed is NULL\n");
+ goto exit;
+
+exit:
+ if (status < 0) {
+ atomic_set(&sysmemmgr_state.ref_count,
+ SYSMEMMGR_MAKE_MAGICSTAMP(0));
+ }
+ return status;
+}
+
+
+/*
+ * ======== sysmemmgr_destroy ========
+ * Purpose:
+ * Function to finalize the system memory manager module.
+ */
+int sysmemmgr_destroy(void)
+{
+ int status = 0;
+
+ if (atomic_cmpmask_and_lt(&(sysmemmgr_state.ref_count),
+ SYSMEMMGR_MAKE_MAGICSTAMP(0), SYSMEMMGR_MAKE_MAGICSTAMP(1)) == \
+ true) {
+ /*! @retval SYSMEMMGR_E_INVALIDSTATE Module was not
+ * initialized */
+ status = SYSMEMMGR_E_INVALIDSTATE;
+ goto err_exit;
+ }
+
+ if (atomic_dec_return(&sysmemmgr_state.ref_count) == \
+ SYSMEMMGR_MAKE_MAGICSTAMP(0)) {
+ /* Delete the lock */
+ kfree(sysmemmgr_state.gate_handle);
+ }
+ return 0;
+
+err_exit:
+ pr_err("sysmemgr_destroy: Module was not initialized\n");
+ return status;
+}
+
+
+/*
+ * ======== sysmemmgr_alloc ========
+ * Purpose:
+ * Function to allocate a memory block.
+ */
+void *sysmemmgr_alloc(u32 size, enum sysmemmgr_allocflag flag)
+{
+ int status = 0;
+ struct sysmemmgr_static_mem_mgr_obj *smObj = NULL;
+ struct sysmemmgr_static_mem_struct *ptr = NULL;
+ struct sysmemmgr_static_mem_struct *newptr = NULL;
+ void *ret_ptr = NULL;
+
+ if (atomic_cmpmask_and_lt(&(sysmemmgr_state.ref_count),
+ SYSMEMMGR_MAKE_MAGICSTAMP(0), SYSMEMMGR_MAKE_MAGICSTAMP(1)) == \
+ true) {
+ /*! @retval SYSMEMMGR_E_INVALIDSTATE Module was not
+ * initialized */
+ status = SYSMEMMGR_E_INVALIDSTATE;
+ goto err_exit;
+ }
+
+ if ((flag & sysmemmgr_allocflag_physical) && \
+ !(flag & sysmemmgr_allocflag_dma)) {
+ /* TBD: works with DMM
+ ret_ptr = platform_mem_alloc (size, 0,
+ MemoryOS_MemTypeFlags_Physical); */
+ if (ret_ptr == NULL) {
+ if (sysmemmgr_state.cfg.static_mem_size == 0) {
+ /* Memory pool is not configured. */
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ smObj = &sysmemmgr_state.static_mem_obj;
+ ptr = &smObj->head;
+ while (ptr && ptr->next) {
+ if (((ptr->next->address - \
+ (ptr->address + ptr->size)) >= size))
+ break;
+ ptr = ptr->next;
+ }
+
+ if (ptr->next == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ newptr = vmalloc(
+ sizeof(struct sysmemmgr_static_mem_struct));
+ if (newptr != NULL) {
+ newptr->address = ptr->address + ptr->size;
+ newptr->size = size;
+ newptr->next = ptr->next;
+ ptr->next = newptr;
+ ret_ptr = (void *) newptr->address;
+ } else {
+ status = -ENOMEM;
+ }
+ }
+ goto exit;
+ }
+
+ if (flag & sysmemmgr_allocflag_physical) {
+ ret_ptr = kmalloc(size, GFP_KERNEL);
+ if (ret_ptr == NULL)
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ if (flag & sysmemmgr_allocflag_dma) {
+ ret_ptr = kmalloc(size, GFP_KERNEL | GFP_DMA);
+ if (ret_ptr == NULL)
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ ret_ptr = vmalloc(size);
+ if (ret_ptr == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+
+err_exit:
+ pr_err("sysmemgr_alloc: Module was not initialized\n");
+exit:
+ if (WARN_ON(ret_ptr == NULL))
+ pr_err("sysmemmgr_alloc: Allocation failed\n");
+ return ret_ptr;
+}
+
+
+/*
+ * ======== sysmemmgr_free ========
+ * Purpose:
+ * Function to de-allocate a previous allocated memory block.
+ */
+int sysmemmgr_free(void *blk, u32 size, enum sysmemmgr_allocflag flag)
+{
+ int status = 0;
+ struct sysmemmgr_static_mem_mgr_obj *smObj = NULL;
+ struct sysmemmgr_static_mem_struct *ptr = NULL;
+ struct sysmemmgr_static_mem_struct *prev = NULL;
+
+ if (atomic_cmpmask_and_lt(&(sysmemmgr_state.ref_count),
+ SYSMEMMGR_MAKE_MAGICSTAMP(0), SYSMEMMGR_MAKE_MAGICSTAMP(1)) == \
+ true) {
+ /*! @retval SYSMEMMGR_E_INVALIDSTATE Module was not
+ * initialized */
+ status = SYSMEMMGR_E_INVALIDSTATE;
+ goto err_exit;
+ }
+
+ if ((flag & sysmemmgr_allocflag_physical) && \
+ !(flag & sysmemmgr_allocflag_dma)) {
+ if (((u32) blk >= sysmemmgr_state.cfg.static_virt_base_addr)
+ && ((u32) blk < \
+ (sysmemmgr_state.cfg.static_virt_base_addr + \
+ sysmemmgr_state.cfg.static_mem_size))) {
+ smObj = &sysmemmgr_state.static_mem_obj;
+ ptr = &smObj->head;
+ while (ptr && ptr->next) {
+ if (ptr->next->address == (u32) blk)
+ break;
+ ptr = ptr->next;
+ }
+ prev = ptr;
+ ptr = ptr->next;
+ prev->next = ptr->next;
+
+ /* Free the node */
+ vfree(ptr);
+ } else {
+ kfree(blk);
+ }
+ } else if (flag & sysmemmgr_allocflag_physical) {
+ kfree(blk);
+ } else if (flag & sysmemmgr_allocflag_dma) {
+ kfree(blk);
+ } else {
+ vfree(blk);
+ }
+ return 0;
+
+err_exit:
+ pr_err("sysmemgr_free: Module was not initialized\n");
+ return status;
+}
+
+
+/*
+ * ======== sysmemmgr_setup ========
+ * Purpose:
+ * Function to translate an address among different address spaces.
+ */
+void *sysmemmgr_translate(void *src_addr, enum sysmemmgr_xltflag flags)
+{
+ void *ret_ptr = NULL;
+
+ switch (flags) {
+ case sysmemmgr_xltflag_kvirt2phys:
+ {
+ if (((u32) src_addr >= \
+ sysmemmgr_state.cfg.static_virt_base_addr) && \
+ ((u32) src_addr < \
+ (sysmemmgr_state.cfg.static_virt_base_addr + \
+ sysmemmgr_state.cfg.static_mem_size))) {
+ ret_ptr = (void *)(((u32) src_addr - \
+ sysmemmgr_state.cfg.static_virt_base_addr) + \
+ (sysmemmgr_state.cfg.static_phys_base_addr));
+ } else {
+ ret_ptr = platform_mem_translate(src_addr,
+ PLATFORM_MEM_XLT_FLAGS_VIRT2PHYS);
+ }
+ }
+ break;
+
+ case sysmemmgr_xltflag_phys2kvirt:
+ {
+ if (((u32) src_addr >= \
+ sysmemmgr_state.cfg.static_phys_base_addr) && \
+ ((u32) src_addr < \
+ (sysmemmgr_state.cfg.static_phys_base_addr + \
+ sysmemmgr_state.cfg.static_mem_size))) {
+ ret_ptr = (void *)(((u32) src_addr - \
+ sysmemmgr_state.cfg.static_phys_base_addr) + \
+ (sysmemmgr_state.cfg.static_virt_base_addr));
+ } else {
+ ret_ptr = platform_mem_translate(src_addr,
+ PLATFORM_MEM_XLT_FLAGS_PHYS2VIRT);
+ }
+ }
+ break;
+
+ default:
+ {
+ pr_err("sysmemmgr_translate: Unhandled translation flag\n");
+ }
+ break;
+ }
+
+ return ret_ptr;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/sysmemmgr_ioctl.c b/drivers/dsp/syslink/multicore_ipc/sysmemmgr_ioctl.c
new file mode 100644
index 00000000000..591e0484987
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/sysmemmgr_ioctl.c
@@ -0,0 +1,227 @@
+/*
+ * sysmemmgr_ioctl.c
+ *
+ * This file implements all the ioctl operations required on the sysmemmgr
+ * module.
+ *
+ * Copyright (C) 2008-2009 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.
+ */
+
+/* Standard headers */
+#include <linux/types.h>
+
+/* Linux headers */
+#include <linux/uaccess.h>
+#include <linux/bug.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+
+/* Module Headers */
+#include <sysmemmgr.h>
+#include <sysmemmgr_ioctl.h>
+
+
+/*
+ * ======== sysmemmgr_ioctl_get_config ========
+ * Purpose:
+ * This ioctl interface to sysmemmgr_get_config function
+ */
+static inline int sysmemmgr_ioctl_get_config(struct sysmemmgr_cmd_args *cargs)
+{
+ s32 retval = 0;
+ unsigned long size;
+ struct sysmemmgr_config config;
+
+ sysmemmgr_get_config(&config);
+ size = copy_to_user(cargs->args.get_config.config, &config,
+ sizeof(struct sysmemmgr_config));
+ if (size) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ cargs->api_status = 0;
+exit:
+ return retval;
+}
+
+/*
+ * ======== sysmemmgr_ioctl_setup ========
+ * Purpose:
+ * This ioctl interface to sysmemmgr_setup function
+ */
+static inline int sysmemmgr_ioctl_setup(struct sysmemmgr_cmd_args *cargs)
+{
+ s32 retval = 0;
+ unsigned long size;
+ struct sysmemmgr_config config;
+
+ if (cargs->args.setup.config == NULL) {
+ cargs->api_status = sysmemmgr_setup(NULL);
+ goto exit;
+ }
+
+ size = copy_from_user(&config, cargs->args.setup.config,
+ sizeof(struct sysmemmgr_config));
+ if (size) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ cargs->api_status = sysmemmgr_setup(&config);
+
+exit:
+ return retval;
+}
+
+/*
+ * ======== sysmemmgr_ioctl_destroy ========
+ * Purpose:
+ * This ioctl interface to sysmemmgr_destroy function
+ */
+static inline int sysmemmgr_ioctl_destroy(struct sysmemmgr_cmd_args *cargs)
+{
+ cargs->api_status = sysmemmgr_destroy();
+ return 0;
+}
+
+/*
+ * ======== sysmemmgr_ioctl_alloc ========
+ * Purpose:
+ * This ioctl interface to sysmemmgr_alloc function
+ */
+static inline int sysmemmgr_ioctl_alloc(struct sysmemmgr_cmd_args *cargs)
+{
+ void *kbuf = NULL;
+ void *phys = NULL;
+
+ kbuf = sysmemmgr_alloc(cargs->args.alloc.size,
+ cargs->args.alloc.flags);
+ if (unlikely(kbuf == NULL))
+ goto exit;
+
+ /* If the flag is not virtually contiguous */
+ if (cargs->args.alloc.flags != sysmemmgr_allocflag_virtual)
+ phys = sysmemmgr_translate(kbuf, sysmemmgr_xltflag_kvirt2phys);
+ cargs->api_status = 0;
+
+exit:
+ cargs->args.alloc.kbuf = kbuf;
+ cargs->args.alloc.kbuf = phys;
+ return 0;
+}
+
+/*
+ * ======== sysmemmgr_ioctl_free ========
+ * Purpose:
+ * This ioctl interface to sysmemmgr_free function
+ */
+static inline int sysmemmgr_ioctl_free(struct sysmemmgr_cmd_args *cargs)
+{
+ cargs->api_status = sysmemmgr_free(cargs->args.free.kbuf,
+ cargs->args.free.size,
+ cargs->args.alloc.flags);
+ return 0;
+}
+
+/*
+ * ======== sysmemmgr_ioctl_translate ========
+ * Purpose:
+ * This ioctl interface to sysmemmgr_translate function
+ */
+static inline int sysmemmgr_ioctl_translate(struct sysmemmgr_cmd_args *cargs)
+{
+ cargs->args.translate.ret_ptr = sysmemmgr_translate(
+ cargs->args.translate.buf,
+ cargs->args.translate.flags);
+ WARN_ON(cargs->args.translate.ret_ptr == NULL);
+ cargs->api_status = 0;
+ return 0;
+}
+
+/*
+ * ======== sysmemmgr_ioctl ========
+ * Purpose:
+ * ioctl interface function for sysmemmgr module
+ */
+int sysmemmgr_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long args)
+{
+ int os_status = 0;
+ struct sysmemmgr_cmd_args __user *uarg =
+ (struct sysmemmgr_cmd_args __user *)args;
+ struct sysmemmgr_cmd_args cargs;
+ unsigned long size;
+
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ os_status = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ os_status = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
+ if (os_status) {
+ os_status = -EFAULT;
+ goto exit;
+ }
+
+ /* Copy the full args from user-side */
+ size = copy_from_user(&cargs, uarg, sizeof(struct sysmemmgr_cmd_args));
+ if (size) {
+ os_status = -EFAULT;
+ goto exit;
+ }
+
+ switch (cmd) {
+ case CMD_SYSMEMMGR_GETCONFIG:
+ os_status = sysmemmgr_ioctl_get_config(&cargs);
+ break;
+
+ case CMD_SYSMEMMGR_SETUP:
+ os_status = sysmemmgr_ioctl_setup(&cargs);
+ break;
+
+ case CMD_SYSMEMMGR_DESTROY:
+ os_status = sysmemmgr_ioctl_destroy(&cargs);
+ break;
+
+ case CMD_SYSMEMMGR_ALLOC:
+ os_status = sysmemmgr_ioctl_alloc(&cargs);
+ break;
+
+ case CMD_SYSMEMMGR_FREE:
+ os_status = sysmemmgr_ioctl_free(&cargs);
+ break;
+
+ case CMD_SYSMEMMGR_TRANSLATE:
+ os_status = sysmemmgr_ioctl_translate(&cargs);
+ break;
+
+ default:
+ WARN_ON(cmd);
+ os_status = -ENOTTY;
+ break;
+ }
+
+ if ((cargs.api_status == -ERESTARTSYS) || (cargs.api_status == -EINTR))
+ os_status = -ERESTARTSYS;
+
+ if (os_status < 0)
+ goto exit;
+
+ /* Copy the full args to the user-side. */
+ size = copy_to_user(uarg, &cargs, sizeof(struct sysmemmgr_cmd_args));
+ if (size) {
+ os_status = -EFAULT;
+ goto exit;
+ }
+
+exit:
+ return os_status;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/sysmgr.c b/drivers/dsp/syslink/multicore_ipc/sysmgr.c
new file mode 100644
index 00000000000..13bcce110ba
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/sysmgr.c
@@ -0,0 +1,846 @@
+/*
+ * sysmgr.c
+ *
+ * Implementation of System manager.
+ *
+ * Copyright (C) 2009 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.
+ */
+
+
+/* Standard headers */
+#include <linux/types.h>
+#include <linux/module.h>
+
+#include <syslink/atomic_linux.h>
+
+/* Module headers */
+#include <multiproc.h>
+#include <sysmemmgr.h>
+#include <sysmgr.h>
+#include <_sysmgr.h>
+#include <platform.h>
+#include <platform_mem.h>
+
+#include <gatepeterson.h>
+#include <sharedregion.h>
+#include <listmp.h>
+#include <messageq.h>
+#include <messageq_transportshm.h>
+#include <notify.h>
+/*#include <notify_driver.h>*/
+#include <notify_ducatidriver.h>
+
+#include <nameserver.h>
+#include <nameserver_remote.h>
+#include <nameserver_remotenotify.h>
+#include <procmgr.h>
+#include <heap.h>
+#include <heapbuf.h>
+
+/* =============================================================================
+ * Macros
+ * =============================================================================
+ */
+/*!
+ * @def BOOTLOADPAGESIZE
+ * @brief Error code base for System manager.
+ */
+#define BOOTLOADPAGESIZE (0x1000) /* 4K page size */
+
+/*!
+ * @def SYSMGR_ENTRYVALIDITYSTAMP
+ * @brief Validity stamp for boot load page entries.
+ */
+#define SYSMGR_ENTRYVALIDITYSTAMP (0xBABAC0C0)
+
+/*!
+ * @def SYSMGR_ENTRYVALIDSTAMP
+ * @brief Validity stamp for boot load page entries.
+ */
+#define SYSMGR_ENTRYVALIDSTAMP (0xBABAC0C0)
+
+/*!
+ * @def SYSMGR_SCALABILITYHANDSHAKESTAMP
+ * @brief scalability configuration handshake value.
+ */
+#define SYSMGR_SCALABILITYHANDSHAKESTAMP (0xBEEF0000)
+
+/*!
+ * @def SYSMGR_SETUPHANDSHAKESTAMP
+ * @brief Platform configured handshake value.
+ */
+#define SYSMGR_SETUPHANDSHAKESTAMP (0xBEEF0001)
+
+/*!
+ * @def SYSMGR_DESTROYHANDSHAKESTAMP
+ * @brief Destroy handshake value.
+ */
+#define SYSMGR_DESTROYHANDSHAKESTAMP (0xBEEF0002)
+
+/*!
+ * @def SYSMGR_BOOTLOADPAGESIZE
+ * @brief Boot load page size.
+ */
+#define SYSMGR_BOOTLOADPAGESIZE (0x00001000)
+
+/* Macro to make a correct module magic number with ref_count */
+#define SYSMGR_MAKE_MAGICSTAMP(x) ((SYSMGR_MODULEID << 12) | (x))
+
+
+/* =============================================================================
+ * Structures & Enums
+ * =============================================================================
+ */
+/*! @brief structure for System manager boot load page entry */
+struct sysmgr_bootload_page_entry {
+ VOLATILE u32 offset;
+ /* Offset of next entry (-1 if not present) */
+ VOLATILE u32 valid;
+ /* Validity of the entry */
+ VOLATILE u32 size;
+ /* Size of the entry data */
+ VOLATILE u32 cmd_id;
+ /* Command ID */
+};
+
+/*! @brief structure containg system manager state object */
+struct sysmgr_boot_load_page {
+ VOLATILE struct sysmgr_bootload_page_entry host_config;
+ /* First entry, host specific configuration in the boot load page */
+ u8 padding1[(BOOTLOADPAGESIZE/2) - \
+ sizeof(struct sysmgr_bootload_page_entry)];
+ /* Padding1 */
+ VOLATILE u32 handshake;
+ /* Handshake variable, wrote by slave to indicate configuration done. */
+ VOLATILE struct sysmgr_bootload_page_entry slave_config;
+ /* First entry, slave specific configuration in the boot load page */
+ u8 padding2[(BOOTLOADPAGESIZE/2) - \
+ sizeof(struct sysmgr_bootload_page_entry) - \
+ sizeof(u32)];
+ /* Padding2 */
+};
+
+/*! @brief structure for System manager module state */
+struct sysmgr_module_object {
+ atomic_t ref_count;
+ /* Reference count */
+ struct sysmgr_config config;
+ /* Overall system configuration */
+ struct sysmgr_boot_load_page *boot_load_page[MULTIPROC_MAXPROCESSORS];
+ /* Boot load page of the slaves */
+ bool platform_mem_init_flag;
+ /* Platform memory manager initialize flag */
+ bool multiproc_init_flag;
+ /* Multiproc Initialize flag */
+ bool gatepeterson_init_flag;
+ /* Gatepeterson Initialize flag */
+ bool sharedregion_init_flag;
+ /* Sharedregion Initialize flag */
+ bool listmp_init_flag;
+ /* Listmp Initialize flag */
+ bool messageq_init_flag;
+ /* Messageq Initialize flag */
+ bool notify_init_flag;
+ /* Notify Initialize flag */
+ bool proc_mgr_init_flag;
+ /* Processor manager Initialize flag */
+ bool heapbuf_init_flag;
+ /* Heapbuf Initialize flag */
+ bool nameserver_init_flag;
+ /* Nameserver_remotenotify Initialize flag */
+ bool listmp_sharedmemory_init_flag;
+ /* Listmp_sharedmemory Initialize flag */
+ bool messageq_transportshm_init_flag;
+ /* Messageq_transportshm Initialize flag */
+ bool notify_ducatidrv_init_flag;
+ /* notify_ducatidrv Initialize flag */
+ bool nameserver_remotenotify_init_flag;
+ /* nameserver_remotenotify Initialize flag */
+ bool platform_init_flag;
+ /* Flag to indicate platform initialization status */
+};
+
+
+/* =============================================================================
+ * Globals
+ * =============================================================================
+ */
+/*!
+ * @var sysmgr_state
+ *
+ * @brief Variable holding state of system manager.
+ */
+static struct sysmgr_module_object sysmgr_state;
+
+
+/* =============================================================================
+ * APIS
+ * =============================================================================
+ */
+/*
+ * ======== sysmgr_get_config ========
+ * Purpose:
+ * Function to get the default values for configuration.
+ */
+void sysmgr_get_config(struct sysmgr_config *config)
+{
+ s32 status = 0;
+
+ if (WARN_ON(config == NULL)) {
+ status = -EINVAL;
+ pr_err("sysmgr_get_config [0x%x] : Argument of type"
+ " (sysmgr_get_config *) passed is null!",
+ status);
+ return;
+ }
+
+ /* Get the gatepeterson default config */
+ multiproc_get_config(&config->multiproc_cfg);
+
+ /* Get the gatepeterson default config */
+ gatepeterson_get_config(&config->gatepeterson_cfg);
+
+ /* Get the sharedregion default config */
+ sharedregion_get_config(&config->sharedregion_cfg);
+
+ /* Get the messageq default config */
+ messageq_get_config(&config->messageq_cfg);
+
+ /* Get the notify default config */
+ notify_get_config(&config->notify_cfg);
+
+ /* Get the proc_mgr default config */
+ proc_mgr_get_config(&config->proc_mgr_cfg);
+
+ /* Get the heapbuf default config */
+ heapbuf_get_config(&config->heapbuf_cfg);
+
+ /* Get the listmp_sharedmemory default config */
+ listmp_sharedmemory_get_config(&config->listmp_sharedmemory_cfg);
+
+ /* Get the messageq_transportshm default config */
+ messageq_transportshm_get_config(&config->messageq_transportshm_cfg);
+
+ /* Get the notify_ducati driver default config */
+ notify_ducatidrv_getconfig(&config->notify_ducatidrv_cfg);
+
+ /* Get the nameserver_remotenotify default config */
+ nameserver_remotenotify_get_config(
+ &config->nameserver_remotenotify_cfg);
+}
+EXPORT_SYMBOL(sysmgr_get_config);
+
+/*
+ * ======== sysmgr_get_object_config ========
+ * Purpose:
+ * Function to get the SysMgr Object configuration from Slave.
+ */
+u32 sysmgr_get_object_config(u16 proc_id, void *config, u32 cmd_id, u32 size)
+{
+ struct sysmgr_bootload_page_entry *entry = NULL;
+ u32 offset = 0;
+ u32 ret = 0;
+ struct sysmgr_boot_load_page *blp = NULL;
+
+ if ((proc_id < 0) || (proc_id >= MULTIPROC_MAXPROCESSORS)) {
+ ret = 0;
+ goto exit;
+ }
+
+ blp = (struct sysmgr_boot_load_page *)
+ sysmgr_state.boot_load_page[proc_id];
+
+ entry = (struct sysmgr_bootload_page_entry *) &blp->slave_config;
+ while (entry->valid == SYSMGR_ENTRYVALIDSTAMP) {
+ if (entry->cmd_id == cmd_id) {
+ if (size == entry->size) {
+ memcpy(config, (void *)((u32)entry + \
+ sizeof(struct sysmgr_bootload_page_entry)),
+ size);
+ ret = size;
+ break;
+ }
+ }
+ if (entry->offset != -1) {
+ offset += entry->offset;
+ entry = (struct sysmgr_bootload_page_entry *)
+ ((u32) &blp->slave_config + entry->offset);
+ } else {
+ break;
+ }
+ }
+
+exit:
+ /* return number of bytes wrote to the boot load page */
+ return ret;
+}
+
+
+/*
+ * ======== sysmgr_put_object_config ========
+ * Purpose:
+ * Function to put the SysMgr Object configuration to Slave.
+ */
+u32 sysmgr_put_object_config(u16 proc_id, void *config, u32 cmd_id, u32 size)
+{
+ struct sysmgr_bootload_page_entry *entry = NULL;
+ struct sysmgr_bootload_page_entry *prev = NULL;
+ u32 offset = 0;
+ struct sysmgr_boot_load_page *blp = NULL;
+
+ if ((proc_id < 0) || (proc_id >= MULTIPROC_MAXPROCESSORS)) {
+ size = 0;
+ goto exit;
+ }
+
+ /* Get the boot load page pointer */
+ blp = sysmgr_state.boot_load_page[proc_id];
+
+ /* Put the entry at the end of list */
+ entry = (struct sysmgr_bootload_page_entry *) &blp->host_config;
+ while (entry->valid == SYSMGR_ENTRYVALIDSTAMP) {
+ prev = entry;
+ if (entry->offset != -1) {
+ offset += entry->offset;
+ entry = (struct sysmgr_bootload_page_entry *)
+ ((u32) &blp->host_config + entry->offset);
+ } else {
+ break;
+ }
+ }
+
+ /* First entry has prev set to NULL */
+ if (prev == NULL) {
+ entry->offset = -1;
+ entry->cmd_id = cmd_id;
+ entry->size = size;
+ memcpy((void *)((u32)entry + \
+ sizeof(struct sysmgr_bootload_page_entry)),
+ config, size);
+ entry->valid = SYSMGR_ENTRYVALIDSTAMP;
+ } else {
+ entry = (struct sysmgr_bootload_page_entry *)((u32)entry + \
+ sizeof(struct sysmgr_bootload_page_entry) + \
+ entry->size);
+ entry->offset = -1;
+ entry->cmd_id = cmd_id;
+ entry->size = size;
+ memcpy((void *)((u32)entry + \
+ sizeof(struct sysmgr_bootload_page_entry)),
+ config, size);
+ entry->valid = SYSMGR_ENTRYVALIDSTAMP;
+
+ /* Attach the new created entry */
+ prev->offset = ((u32) entry - (u32) &blp->host_config);
+ }
+
+exit:
+ /* return number of bytes wrote to the boot load page */
+ return size;
+}
+
+
+/*
+ * ======== sysmgr_setup ========
+ * Purpose:
+ * Function to setup the System.
+ */
+s32 sysmgr_setup(const struct sysmgr_config *cfg)
+{
+ s32 status = 0;
+ struct sysmgr_config *config = NULL;
+
+ /* This sets the ref_count variable is not initialized, upper 16 bits is
+ * written with module Id to ensure correctness of ref_count variable.
+ */
+ atomic_cmpmask_and_set(&sysmgr_state.ref_count,
+ SYSMGR_MAKE_MAGICSTAMP(0),
+ SYSMGR_MAKE_MAGICSTAMP(0));
+
+ if (atomic_inc_return(&sysmgr_state.ref_count)
+ != SYSMGR_MAKE_MAGICSTAMP(1)) {
+ status = 1;
+ goto exit;
+ }
+
+ if (cfg == NULL) {
+ sysmgr_get_config(&sysmgr_state.config);
+ config = &sysmgr_state.config;
+ } else {
+ memcpy((void *) (&sysmgr_state.config), (void *) cfg,
+ sizeof(struct sysmgr_config));
+ config = (struct sysmgr_config *) cfg;
+ }
+
+ /* Initialize PlatformMem */
+ status = platform_mem_setup();
+ if (status < 0) {
+ pr_err("sysmgr_setup : platform_mem_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("platform_mem_setup : status [0x%x]\n" ,
+ status);
+ sysmgr_state.platform_mem_init_flag = true;
+ }
+
+ /* Override the platform specific configuration */
+ platform_override_config(config);
+
+ status = multiproc_setup(&(config->multiproc_cfg));
+ if (status < 0) {
+ pr_err("sysmgr_setup : multiproc_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("sysmgr_setup : status [0x%x]\n" , status);
+ sysmgr_state.multiproc_init_flag = true;
+ }
+
+ /* Initialize ProcMgr */
+ if (status >= 0) {
+ status = proc_mgr_setup(&(config->proc_mgr_cfg));
+ if (status < 0) {
+ pr_err("sysmgr_setup : proc_mgr_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("proc_mgr_setup : status [0x%x]\n" ,
+ status);
+ sysmgr_state.proc_mgr_init_flag = true;
+ }
+ }
+
+ /* Initialize SharedRegion */
+ if (status >= 0) {
+ status = sharedregion_setup(&config->sharedregion_cfg);
+ if (status < 0) {
+ pr_err("sysmgr_setup : sharedregion_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("sharedregion_setup : status [0x%x]\n" ,
+ status);
+ sysmgr_state.sharedregion_init_flag = true;
+ }
+ }
+
+ /* Initialize Notify */
+ if (status >= 0) {
+ status = notify_setup(&config->notify_cfg);
+ if (status < 0) {
+ pr_err("sysmgr_setup : notify_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("notify_setup : status [0x%x]\n" ,
+ status);
+ sysmgr_state.notify_init_flag = true;
+ }
+ }
+
+ /* Initialize NameServer */
+ if (status >= 0) {
+ status = nameserver_setup();
+ if (status < 0) {
+ pr_err("sysmgr_setup : nameserver_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("nameserver_setup : status [0x%x]\n" ,
+ status);
+ sysmgr_state.nameserver_init_flag = true;
+ }
+ }
+
+ /* Initialize GatePeterson */
+ if (status >= 0) {
+ status = gatepeterson_setup(&config->gatepeterson_cfg);
+ if (status < 0) {
+ pr_err("sysmgr_setup : gatepeterson_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("gatepeterson_setup : status [0x%x]\n" ,
+ status);
+ sysmgr_state.gatepeterson_init_flag = true;
+ }
+ }
+
+ /* Intialize MessageQ */
+ if (status >= 0) {
+ status = messageq_setup(&config->messageq_cfg);
+ if (status < 0) {
+ pr_err("sysmgr_setup : messageq_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("messageq_setup : status [0x%x]\n" ,
+ status);
+ sysmgr_state.messageq_init_flag = true;
+ }
+ }
+
+ /* Intialize HeapBuf */
+ if (status >= 0) {
+ status = heapbuf_setup(&config->heapbuf_cfg);
+ if (status < 0) {
+ pr_err("sysmgr_setup : heapbuf_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("heapbuf_setup : status [0x%x]\n" ,
+ status);
+ sysmgr_state.heapbuf_init_flag = true;
+ }
+ }
+
+ /* Initialize ListMPSharedMemory */
+ if (status >= 0) {
+ status = listmp_sharedmemory_setup(
+ &config->listmp_sharedmemory_cfg);
+ if (status < 0) {
+ pr_err("sysmgr_setup : "
+ "listmp_sharedmemory_setup failed [0x%x]\n",
+ status);
+ } else {
+ pr_err("listmp_sharedmemory_setup : "
+ "status [0x%x]\n" , status);
+ sysmgr_state.listmp_sharedmemory_init_flag = true;
+ }
+ }
+
+ /* Initialize MessageQTransportShm */
+ if (status >= 0) {
+ status = messageq_transportshm_setup(
+ &config->messageq_transportshm_cfg);
+ if (status < 0) {
+ pr_err("sysmgr_setup : "
+ "messageq_transportshm_setup failed [0x%x]\n",
+ status);
+ } else {
+ pr_err("messageq_transportshm_setup : "
+ "status [0x%x]\n", status);
+ sysmgr_state.messageq_transportshm_init_flag = true;
+ }
+ }
+
+ /* Initialize Notify DucatiDriver */
+ if (status >= 0) {
+ status = notify_ducatidrv_setup(&config->notify_ducatidrv_cfg);
+ if (status < 0) {
+ pr_err("sysmgr_setup : "
+ "notify_ducatidrv_setup failed [0x%x]\n",
+ status);
+ } else {
+ pr_err("notify_ducatidrv_setup : "
+ "status [0x%x]\n" , status);
+ sysmgr_state.notify_ducatidrv_init_flag = true;
+ }
+ }
+
+ /* Initialize NameServerRemoteNotify */
+ if (status >= 0) {
+ status = nameserver_remotenotify_setup(
+ &config->nameserver_remotenotify_cfg);
+ if (status < 0) {
+ pr_err("sysmgr_setup : "
+ "nameserver_remotenotify_setup failed [0x%x]\n",
+ status);
+ } else {
+ pr_err("nameserver_remotenotify_setup : "
+ "status [0x%x]\n" , status);
+ sysmgr_state.nameserver_remotenotify_init_flag = true;
+ }
+ }
+
+ if (status >= 0) {
+ /* Call platform setup function */
+ status = platform_setup(config);
+ if (status < 0) {
+ pr_err("sysmgr_setup : platform_setup "
+ "failed [0x%x]\n", status);
+ } else {
+ pr_err("platform_setup : status [0x%x]\n" ,
+ status);
+ sysmgr_state.platform_init_flag = true;
+ }
+ }
+
+exit:
+ if (status < 0)
+ atomic_set(&sysmgr_state.ref_count, SYSMGR_MAKE_MAGICSTAMP(0));
+
+ return status;
+}
+EXPORT_SYMBOL(sysmgr_setup);
+
+/*
+ * ======== sysmgr_setup ========
+ * Purpose:
+ * Function to finalize the System.
+ */
+s32 sysmgr_destroy(void)
+{
+ s32 status = 0;
+
+ if (atomic_cmpmask_and_lt(&(sysmgr_state.ref_count),
+ SYSMGR_MAKE_MAGICSTAMP(0),
+ SYSMGR_MAKE_MAGICSTAMP(1)) != false) {
+ /*! @retval SYSMGR_E_INVALIDSTATE Module was not initialized */
+ status = SYSMGR_E_INVALIDSTATE;
+ goto exit;
+ }
+
+ if (atomic_dec_return(&sysmgr_state.ref_count)
+ != SYSMGR_MAKE_MAGICSTAMP(0)) {
+ status = 1;
+ goto exit;
+ }
+
+ /* Finalize Platform module*/
+ if (sysmgr_state.platform_init_flag == true) {
+ status = platform_destroy();
+ if (status < 0) {
+ pr_err("sysmgr_destroy : platform_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ sysmgr_state.platform_init_flag = false;
+ }
+ }
+
+ /* Finalize NameServerRemoteNotify module */
+ if (sysmgr_state.nameserver_remotenotify_init_flag == true) {
+ status = nameserver_remotenotify_destroy();
+ if (status < 0) {
+ pr_err("sysmgr_destroy : "
+ "nameserver_remotenotify_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ sysmgr_state.nameserver_remotenotify_init_flag \
+ = false;
+ }
+ }
+
+ /* Finalize Notify Ducati Driver module */
+ if (sysmgr_state.notify_ducatidrv_init_flag == true) {
+ status = notify_ducatidrv_destroy();
+ if (status < 0) {
+ pr_err("sysmgr_destroy : "
+ "notify_ducatidrv_destroy failed [0x%x]\n",
+ status);
+ } else {
+ sysmgr_state.notify_ducatidrv_init_flag = false;
+ }
+ }
+
+ /* Finalize MessageQTransportShm module */
+ if (sysmgr_state.messageq_transportshm_init_flag == true) {
+ status = messageq_transportshm_destroy();
+ if (status < 0) {
+ pr_err("sysmgr_destroy : "
+ "messageq_transportshm_destroy failed [0x%x]\n",
+ status);
+ } else {
+ sysmgr_state.messageq_transportshm_init_flag = \
+ false;
+ }
+ }
+
+ /* Finalize ListMPSharedMemory module */
+ if (sysmgr_state.listmp_sharedmemory_init_flag == true) {
+ status = listmp_sharedmemory_destroy();
+ if (status < 0) {
+ pr_err("sysmgr_destroy : "
+ "listmp_sharedmemory_destroy failed [0x%x]\n",
+ status);
+ } else {
+ sysmgr_state.listmp_sharedmemory_init_flag = \
+ false;
+ }
+ }
+
+ /* Finalize HeapBuf module */
+ if (sysmgr_state.heapbuf_init_flag == true) {
+ status = heapbuf_destroy();
+ if (status < 0) {
+ pr_err("sysmgr_destroy : heapbuf_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ sysmgr_state.heapbuf_init_flag = false;
+ }
+ }
+
+ /* Finalize MessageQ module */
+ if (sysmgr_state.messageq_init_flag == true) {
+ status = messageq_destroy();
+ if (status < 0) {
+ pr_err("sysmgr_destroy : messageq_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ sysmgr_state.messageq_init_flag = false;
+ }
+ }
+
+ /* Finalize GatePeterson module */
+ if (sysmgr_state.gatepeterson_init_flag == true) {
+ status = gatepeterson_destroy();
+ if (status < 0) {
+ pr_err("sysmgr_destroy : "
+ "gatepeterson_destroy failed [0x%x]\n", status);
+ } else {
+ sysmgr_state.gatepeterson_init_flag = false;
+ }
+ }
+
+ /* Finalize NameServer module */
+ if (sysmgr_state.nameserver_init_flag == true) {
+ status = nameserver_destroy();
+ if (status < 0) {
+ pr_err("sysmgr_destroy : nameserver_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ sysmgr_state.nameserver_init_flag = false;
+ }
+ }
+
+ /* Finalize Notify module */
+ if (sysmgr_state.notify_init_flag == true) {
+ status = notify_destroy();
+ if (status < 0) {
+ pr_err("sysmgr_destroy : sysmgr_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ sysmgr_state.notify_init_flag = false;
+ }
+ }
+
+ /* Finalize SharedRegion module */
+ if (sysmgr_state.sharedregion_init_flag == true) {
+ status = sharedregion_destroy();
+ if (status < 0) {
+ pr_err("sysmgr_destroy : "
+ "sharedregion_destroy failed [0x%x]\n", status);
+ } else {
+ sysmgr_state.sharedregion_init_flag = false;
+ }
+ }
+
+ /* Finalize ProcMgr module */
+ if (sysmgr_state.proc_mgr_init_flag == true) {
+ status = proc_mgr_destroy();
+ if (status < 0) {
+ pr_err("sysmgr_destroy : proc_mgr_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ sysmgr_state.proc_mgr_init_flag = false;
+ }
+ }
+
+ /* Finalize MultiProc module */
+ if (sysmgr_state.multiproc_init_flag == true) {
+ status = multiproc_destroy();
+ if (status < 0) {
+ pr_err("sysmgr_destroy : multiproc_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ sysmgr_state.proc_mgr_init_flag = false;
+ }
+ }
+
+ /* Finalize PlatformMem module */
+ if (sysmgr_state.platform_mem_init_flag == true) {
+ status = platform_mem_destroy();
+ if (status < 0) {
+ pr_err("sysmgr_destroy : platform_mem_destroy "
+ "failed [0x%x]\n", status);
+ } else {
+ sysmgr_state.platform_mem_init_flag = false;
+ }
+ }
+
+ atomic_set(&sysmgr_state.ref_count, SYSMGR_MAKE_MAGICSTAMP(0));
+
+exit:
+ if (status < 0) {
+ pr_err("sysmgr_destroy : failed with "
+ "status = [0x%x]\n", status);
+ }
+ return status;
+}
+EXPORT_SYMBOL(sysmgr_destroy);
+
+/*
+ * ======== sysmgr_set_boot_load_page ========
+ * Purpose:
+ * Function to set the boot load page address for a slave.
+ */
+void sysmgr_set_boot_load_page(u16 proc_id, u32 boot_load_page)
+{
+ struct sysmgr_boot_load_page *temp = \
+ (struct sysmgr_boot_load_page *) boot_load_page;
+
+ if ((proc_id < 0) || (proc_id >= MULTIPROC_MAXPROCESSORS)) {
+ pr_err(
+ "sysmgr_set_boot_load_page failed: Invalid proc_id passed\n");
+ return;
+ }
+
+ /* Initialize the host config area */
+ sysmgr_state.boot_load_page[proc_id] = temp;
+ temp->host_config.offset = -1;
+ temp->host_config.valid = 0;
+ temp->handshake = 0;
+}
+
+
+/*
+ * ======== sysmgr_wait_for_scalability_info ========
+ * Purpose:
+ * Function to wait for scalability handshake value.
+ */
+void sysmgr_wait_for_scalability_info(u16 proc_id)
+{
+ VOLATILE struct sysmgr_boot_load_page *temp = NULL;
+
+ if ((proc_id < 0) || (proc_id >= MULTIPROC_MAXPROCESSORS)) {
+ pr_err("sysmgr_wait_for_scalability_info failed: "
+ "Invalid proc_id passed\n");
+ return;
+ }
+ temp = sysmgr_state.boot_load_page[proc_id];
+
+ pr_err("sysmgr_wait_for_scalability_info: BF while temp->handshake:%x\n",
+ temp->handshake);
+ while (temp->handshake != SYSMGR_SCALABILITYHANDSHAKESTAMP)
+ ;
+ pr_err("sysmgr_wait_for_scalability_info:AF while temp->handshake:%x\n",
+ temp->handshake);
+
+ /* Reset the handshake value for reverse synchronization */
+ temp->handshake = 0;
+}
+
+
+/*
+ * ======== sysmgr_wait_for_slave_setup ========
+ * Purpose:
+ * Function to wait for slave to complete setup.
+ */
+void sysmgr_wait_for_slave_setup(u16 proc_id)
+{
+ VOLATILE struct sysmgr_boot_load_page *temp = NULL;
+
+ if ((proc_id < 0) || (proc_id >= MULTIPROC_MAXPROCESSORS)) {
+ pr_err("sysmgr_wait_for_slave_setup failed: "
+ "Invalid proc_id passed\n");
+ return;
+ }
+ temp = sysmgr_state.boot_load_page[proc_id];
+
+ while (temp->handshake != SYSMGR_SETUPHANDSHAKESTAMP)
+ ;
+
+ /* Reset the handshake value for reverse synchronization */
+ temp->handshake = 0;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/transportshm.c b/drivers/dsp/syslink/multicore_ipc/transportshm.c
new file mode 100644
index 00000000000..621bcaf4a59
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/transportshm.c
@@ -0,0 +1,1146 @@
+/*
+ * transportshm.c
+ *
+ * Shared Memory Transport module
+ *
+ * Copyright (C) 2009 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.
+ */
+
+/* Standard headers */
+#include <linux/types.h>
+
+/* Utilities headers */
+#include <linux/string.h>
+#include <linux/slab.h>
+
+/* Syslink headers */
+#include <syslink/atomic_linux.h>
+/* Module level headers */
+#include <multiproc.h>
+#include <sharedregion.h>
+#include <nameserver.h>
+#include <gatepeterson.h>
+#include <notify.h>
+#include <messageq.h>
+#include <listmp.h>
+#include <gatemp.h>
+#include <transportshm.h>
+
+/* =============================================================================
+ * Globals
+ * =============================================================================
+ */
+
+/* Indicates that the transport is up. */
+#define TRANSPORTSHM_UP 0xBADC0FFE
+
+/* transportshm Version. */
+#define TRANSPORTSHM_VERSION 1
+
+/*!
+ * @brief Macro to make a correct module magic number with refCount
+ */
+#define TRANSPORTSHM_MAKE_MAGICSTAMP(x) \
+ ((TRANSPORTSHM_MODULEID << 12u) | (x))
+
+#define ROUND_UP(a, b) (((a) + ((b) - 1)) & (~((b) - 1)))
+
+typedef void (*transportshm_err_fxn)(enum transportshm_reason reason,
+ void *handle,
+ void *msg,
+ u32 info);
+
+/* =============================================================================
+ * Structures & Enums
+ * =============================================================================
+ */
+/*
+ * Defines the transportshm state object, which contains all the
+ * module specific information.
+ */
+struct transportshm_module_object {
+ atomic_t ref_count;
+ /* Flag to indicate initialization state of transportshr */
+ struct transportshm_config cfg;
+ /* transportshm configuration structure */
+ struct transportshm_config def_cfg;
+ /* Default module configuration */
+ struct transportshm_params def_inst_params;
+ /* Default instance parameters */
+ void *gate_handle;
+ /* Handle to the gate for local thread safety */
+ void *transports
+ [MULTIPROC_MAXPROCESSORS][MESSAGEQ_NUM_PRIORITY_QUEUES];
+ /* Transport to be set in messageq_register_transport */
+ transportshm_err_fxn err_fxn;
+ /* Error function */
+
+};
+
+/*
+ * Structure of attributes in shared memory
+ */
+struct transportshm_attrs {
+ VOLATILE u32 flag; /* flag */
+ VOLATILE u32 creator_proc_id; /* Creator processor ID */
+ VOLATILE u32 notify_event_id; /* Notify event number */
+ VOLATILE u16 priority; /* priority */
+ VOLATILE u32 *gatemp_addr; /* gatemp shared memory srptr */
+};
+
+/*
+ * Structure defining config parameters for the MessageQ transport
+ * instances.
+ */
+struct transportshm_object {
+ VOLATILE struct transportshm_attrs *self;
+ /* Attributes for local processor in shared memory */
+ VOLATILE struct transportshm_attrs *other;
+ /* Attributes for remote processor in shared memory */
+ void *local_list;
+ /* List for this processor */
+ void *remote_list;
+ /* List for remote processor */
+ VOLATILE int status;
+ /* Current status */
+ u32 alloc_size;
+ /* Shared memory allocated */
+ bool cache_enabled;
+ /* Whether to cache calls */
+ int notify_event_id;
+ /* Notify event to be used */
+ u16 region_id;
+ /* The shared region id */
+ u16 remote_proc_id;
+ /* dst proc id */
+ u32 priority;
+ /* Priority of messages supported by this transport */
+ void *gate;
+ /* Gate for critical regions */
+ struct transportshm_params params;
+ /* Instance specific parameters */
+};
+
+/* =============================================================================
+ * Globals
+ * =============================================================================
+ */
+/*
+ * @var transportshm_state
+ *
+ * transportshm state object variable
+ */
+static struct transportshm_module_object transportshm_state = {
+ .gate_handle = NULL,
+ .def_cfg.err_fxn = NULL,
+ .def_inst_params.gate = NULL,
+ .def_inst_params.shared_addr = NULL,
+ .def_inst_params.notify_event_id = (u32)(-1),
+ .def_inst_params.priority = MESSAGEQ_NORMALPRI
+};
+
+/* Pointer to module state */
+static struct transportshm_module_object *transportshm_module =
+ &transportshm_state;
+
+/* =============================================================================
+ * Forward declarations of internal functions
+ * =============================================================================
+ */
+/* Callback function registered with the Notify module. */
+static void _transportshm_notify_fxn(u16 proc_id,
+ u16 line_id,
+ u32 event_id,
+ uint *arg,
+ u32 payload);
+
+/* Function to create/open the handle. */
+static int _transportshm_create(struct transportshm_object **handle_ptr,
+ u16 proc_id,
+ const struct transportshm_params *params,
+ bool create_flag);
+
+/* =============================================================================
+ * APIs called directly by applications
+ * =============================================================================
+ */
+/*
+ * ======== transportshm_get_config ========
+ * Purpose:
+ * Get the default configuration for the transportshm
+ * module.
+ *
+ * This function can be called by the application to get their
+ * configuration parameter to transportshm_setup filled in
+ * by the transportshm module with the default parameters.
+ * If the user does not wish to make any change in the default
+ * parameters, this API is not required to be called.
+ */
+void transportshm_get_config(struct transportshm_config *cfg)
+{
+ if (WARN_ON(cfg == NULL))
+ goto exit;
+
+ if (atomic_cmpmask_and_lt(&(transportshm_module->ref_count),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(0),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(1)) == true) {
+ memcpy(cfg, &(transportshm_module->def_cfg),
+ sizeof(struct transportshm_config));
+ } else {
+ memcpy(cfg, &(transportshm_module->cfg),
+ sizeof(struct transportshm_config));
+ }
+ return;
+
+exit:
+ pr_err("transportshm_get_config: Argument of type"
+ "(struct transportshm_config *) passed is null!\n");
+}
+
+
+/*
+ * ======== transportshm_setup ========
+ * Purpose:
+ * Setup the transportshm module.
+ *
+ * This function sets up the transportshm module. This
+ * function must be called before any other instance-level APIs can
+ * be invoked.
+ * Module-level configuration needs to be provided to this
+ * function. If the user wishes to change some specific config
+ * parameters, then transportshm_getconfig can be called
+ * to get the configuration filled with the default values. After
+ * this, only the required configuration values can be changed. If
+ * the user does not wish to make any change in the default
+ * parameters, the application can simply call
+ * transportshm_setup with NULL parameters. The default
+ * parameters would get automatically used.
+ */
+int transportshm_setup(const struct transportshm_config *cfg)
+{
+ int status = TRANSPORTSHM_SUCCESS;
+ struct transportshm_config tmpCfg;
+
+ /* This sets the refCount variable is not initialized, upper 16 bits is
+ * written with module Id to ensure correctness of refCount variable.
+ */
+ atomic_cmpmask_and_set(&transportshm_module->ref_count,
+ TRANSPORTSHM_MAKE_MAGICSTAMP(0),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(0));
+
+ if (atomic_inc_return(&transportshm_module->ref_count)
+ != TRANSPORTSHM_MAKE_MAGICSTAMP(1u)) {
+ return 1;
+ }
+
+ if (cfg == NULL) {
+ transportshm_get_config(&tmpCfg);
+ cfg = &tmpCfg;
+ }
+
+ transportshm_module->gate_handle = \
+ kmalloc(sizeof(struct mutex), GFP_KERNEL);
+ if (transportshm_module->gate_handle == NULL) {
+ /* @retval TRANSPORTSHM_E_FAIL Failed to create
+ GateMutex! */
+ status = TRANSPORTSHM_E_FAIL;
+ pr_err("transportshm_setup: Failed to create mutex!\n");
+ atomic_set(&transportshm_module->ref_count,
+ TRANSPORTSHM_MAKE_MAGICSTAMP(0));
+ goto exit;
+ }
+ mutex_init(transportshm_module->gate_handle);
+
+ /* Copy the user provided values into the state object. */
+ memcpy(&transportshm_module->cfg, cfg,
+ sizeof(struct transportshm_config));
+ memset(&(transportshm_module->transports), 0, (sizeof(void *) * \
+ MULTIPROC_MAXPROCESSORS * MESSAGEQ_NUM_PRIORITY_QUEUES));
+ return status;
+
+exit:
+ pr_err("transportshm_setup failed: status = 0x%x", status);
+ return status;
+}
+
+
+/*
+ * ======== transportshm_destroy ========
+ * Purpose:
+ * Destroy the transportshm module.
+ *
+ * Once this function is called, other transportshm module
+ * APIs, except for the transportshm_getConfig API cannot
+ * be called anymore.
+ */
+int transportshm_destroy(void)
+{
+ struct transportshm_object *obj = NULL;
+ int status = 0;
+ u16 i;
+ u16 j;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(
+ &(transportshm_module->ref_count),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(0),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(1)) == true)) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ if (!(atomic_dec_return(&transportshm_module->ref_count)
+ == TRANSPORTSHM_MAKE_MAGICSTAMP(0))) {
+ status = 1;
+ goto exit;
+ }
+
+ /* Temporarily increment ref_count here. */
+ atomic_set(&transportshm_module->ref_count,
+ TRANSPORTSHM_MAKE_MAGICSTAMP(1));
+
+ /* Delete any Transports that have not been deleted so far. */
+ for (i = 0; i < MULTIPROC_MAXPROCESSORS; i++) {
+ for (j = 0 ; j < MESSAGEQ_NUM_PRIORITY_QUEUES; j++) {
+ if (transportshm_module->transports[i][j] != \
+ NULL) {
+ obj = (struct transportshm_object *)
+ transportshm_module->transports[i][j];
+ if (obj->self != NULL) {
+ if (obj->self->creator_proc_id
+ == multiproc_self())
+ transportshm_delete(
+ &(transportshm_module->
+ transports[i][j]));
+ else
+ transportshm_close(
+ &(transportshm_module->
+ transports[i][j]));
+ }
+ }
+ }
+ }
+
+ /* Decrease the ref_count */
+ atomic_set(&transportshm_module->ref_count,
+ TRANSPORTSHM_MAKE_MAGICSTAMP(0));
+
+ if (transportshm_module->gate_handle != NULL) {
+ kfree(transportshm_module->gate_handle);
+ transportshm_module->gate_handle = NULL;
+ }
+ return 0;
+
+exit:
+ if (status < 0)
+ pr_err("transportshm_destroy failed: status = 0x%x\n", status);
+ return status;
+}
+
+
+/*
+ * ======== transportshm_params_init ========
+ * Purpose:
+ * Get Instance parameters
+ */
+void transportshm_params_init(struct transportshm_params *params)
+{
+ if (WARN_ON(atomic_cmpmask_and_lt(
+ &(transportshm_module->ref_count),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(0),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(1)) == true)) {
+ pr_err("transportshm_params_init: Module was "
+ " not initialized\n");
+ goto exit;
+ }
+
+ if (WARN_ON(params == NULL)) {
+ pr_err("transportshm_params_init: Argument of"
+ " type (struct transportshm_params *) "
+ "is NULL!");
+ goto exit;
+ }
+
+ memcpy(params, &(transportshm_module->def_inst_params),
+ sizeof(struct transportshm_params));
+
+exit:
+ return;
+}
+
+/*
+ * ======== transportshm_create ========
+ * Purpose:
+ * Create a transport instance. This function waits for the remote
+ * processor to complete its transport creation. Hence it must be
+ * called only after the remote processor is running.
+ */
+void *transportshm_create(u16 proc_id,
+ const struct transportshm_params *params)
+{
+ struct transportshm_object *handle = NULL;
+ int status = 0;
+
+ BUG_ON(params == NULL);
+ BUG_ON(!(proc_id < multiproc_get_num_processors()));
+ if (WARN_ON(atomic_cmpmask_and_lt(
+ &(transportshm_module->ref_count),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(0),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(1)) == true)) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ if (WARN_ON(params == NULL)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (transportshm_module->transports[proc_id][params->priority] \
+ != NULL) {
+ /* Specified transport is already registered. */
+ status = MESSAGEQ_E_ALREADYEXISTS;
+ goto exit;
+ }
+
+ status = _transportshm_create(&handle, proc_id, params, true);
+
+ if (status < 0) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ return handle;
+
+exit:
+ pr_err("transportshm_create failed: status = 0x%x\n", status);
+ return handle;
+}
+
+
+/*
+ * ======== transportshm_delete ========
+ * Purpose:
+ * Delete instance
+ */
+int transportshm_delete(void **handle_ptr)
+{
+ int status = 0;
+ int tmp_status = 0;
+ struct transportshm_object *handle;
+ u16 proc_id;
+ u32 key;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(
+ &(transportshm_module->ref_count),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(0),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(1)) == true)) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(handle_ptr == NULL)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(*handle_ptr == NULL)) {
+ status = -EINVAL;
+ pr_warn("transportshm_delete: Invalid NULL"
+ " mqtshm_handle specified! status = 0x%x\n", status);
+ goto exit;
+ }
+
+ key = mutex_lock_interruptible(transportshm_state.gate_handle);
+ if (key < 0)
+ goto exit;
+
+ handle = (struct transportshm_object *) (*handle_ptr);
+ if (handle != NULL) {
+ if (handle->self != NULL) {
+ proc_id = handle->self->creator_proc_id;
+ /* Clear handle in the local array */
+ transportshm_module->
+ transports[proc_id][handle->priority] = NULL;
+ /* clear the self flag */
+ handle->self->flag = 0;
+#if 0
+ if (EXPECT_FALSE(handle->cache_enabled)) {
+ Cache_wbinv((Ptr)&(handle->self->flag),
+ sharedregion_get_cache_line_size(
+ handle->region_id),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+ }
+
+ if (handle->local_list != NULL) {
+ status = listmp_delete(&handle->local_list);
+ if (status < 0)
+ pr_warn("transportshm_delete: "
+ "Failed to delete local listmp "
+ "instance!\n");
+ }
+
+ if (handle->remote_list != NULL) {
+ tmp_status = listmp_close(&handle->remote_list);
+ if ((tmp_status < 0) && (status >= 0)) {
+ status = tmp_status;
+ pr_warn("transportshm_delete: "
+ "Failed to close remote listmp "
+ "instance!\n");
+ }
+ }
+
+ messageq_unregister_transport(handle->
+ remote_proc_id, handle->params.priority);
+
+ tmp_status = notify_unregister_event_single(handle->
+ remote_proc_id,
+ 0,
+ handle->notify_event_id);
+ if (tmp_status < 0) {
+ status = tmp_status;
+ pr_warn("transportshm_delete: Failed to "
+ "unregister notify event!\n");
+ }
+
+ kfree(handle);
+ *handle_ptr = NULL;
+ }
+ mutex_unlock(transportshm_state.gate_handle);
+ return status;
+
+exit:
+ if (status < 0)
+ pr_err("transportshm_delete failed: "
+ "status = 0x%x\n", status);
+ return status;
+}
+
+/*
+ * ========== transportshm_open_by_addr ===========
+ * Open a transport instance
+ */
+int
+transportshm_open_by_addr(void *shared_addr, void **handle_ptr)
+{
+ int status = 0;
+ struct transportshm_attrs *attrs = NULL;
+ struct transportshm_params params;
+ u16 id;
+
+ BUG_ON(shared_addr == NULL);
+ BUG_ON(handle_ptr == NULL);
+
+ if (WARN_ON(atomic_cmpmask_and_lt(
+ &(transportshm_module->ref_count),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(0),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(1)) == true)) {
+ status = -ENODEV;
+ goto exit;
+ }
+
+ if (shared_addr == NULL) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ if (handle_ptr == NULL) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ attrs = (struct transportshm_attrs *) shared_addr;
+ id = sharedregion_get_id(shared_addr);
+
+ if (id == SHAREDREGION_INVALIDREGIONID) {
+ status = -EFAULT;
+ goto exit;
+ }
+ if (((u32) shared_addr % sharedregion_get_cache_line_size(id) != 0)) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+#if 0
+ /* invalidate the attrs before using it */
+ if (EXPECT_FALSE(SharedRegion_isCacheEnabled(id))) {
+ Cache_inv((Ptr) attrs,
+ sizeof(struct transportshm_attrs),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+ transportshm_params_init(&params);
+ /* set params field */
+ params.shared_addr = shared_addr;
+ params.notify_event_id = attrs->notify_event_id | \
+ (NOTIFY_SYSTEMKEY << 16);
+ params.priority = attrs->priority;
+
+ if (unlikely(attrs->flag != TRANSPORTSHM_UP)) {
+ status = -EFAULT;
+ *handle_ptr = NULL;
+ goto exit;
+ }
+
+ /* Create the object */
+ status = _transportshm_create((struct transportshm_object **)
+ handle_ptr,
+ attrs->creator_proc_id, &params, false);
+ if (status < 0)
+ goto exit;
+
+ return status;
+
+exit:
+ pr_err("transportshm_open_by_addr failed: status = 0x%x\n", status);
+ return status;
+}
+
+/*
+ * ========== transportshm_close ===========
+ * Close an opened transport instance
+ */
+int
+transportshm_close(void **handle_ptr)
+{
+ int status = 0;
+ int tmp_status = 0;
+ struct transportshm_object *obj;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(
+ &(transportshm_module->ref_count),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(0),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(1)) == true)) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(handle_ptr == NULL)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(*handle_ptr == NULL)) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct transportshm_object *)(*handle_ptr);
+ transportshm_module->transports[obj->remote_proc_id]
+ [obj->params.priority] = NULL;
+
+ if (obj->other != NULL) {
+ /* other flag was set by remote proc */
+ obj->other->flag = 0;
+#if 0
+ if (EXPECT_FALSE(obj->cache_enabled)) {
+ Cache_wbInv(&(obj->other->flag),
+ sharedregion_get_cache_line_size
+ (obj->region_id),
+ Cache_Type_ALL,
+ TRUE);
+ }
+#endif
+ }
+
+ if (obj->gate != NULL) {
+ status = gatemp_close(&obj->gate);
+ if (status < 0) {
+ status = TRANSPORTSHM_E_FAIL;
+ pr_err("transportshm_close: "
+ "gatemp_close failed, status [0x%x]\n",
+ status);
+ }
+ }
+
+ if (obj->local_list != NULL) {
+ tmp_status = listmp_close(&obj->local_list);
+ if ((tmp_status < 0) && (status >= 0)) {
+ status = TRANSPORTSHM_E_FAIL;
+ pr_err("transportshm_close: "
+ "listmp_close(local_list) failed, "
+ "status [0x%x]\n", status);
+ }
+ }
+
+ if (obj->remote_list != NULL) {
+ tmp_status = listmp_close(&obj->remote_list);
+ if ((tmp_status < 0) && (status >= 0)) {
+ status = TRANSPORTSHM_E_FAIL;
+ pr_err("transportshm_close: "
+ "listmp_close(remote_list) failed, "
+ "status [0x%x]\n", status);
+ }
+ }
+
+ messageq_unregister_transport(obj->remote_proc_id,
+ obj->params.priority);
+
+ tmp_status = notify_unregister_event_single(obj->remote_proc_id, 0,
+ (obj->notify_event_id | (NOTIFY_SYSTEMKEY << 16)));
+ if ((tmp_status < 0) && (status >= 0))
+ status = TRANSPORTSHM_E_FAIL;
+
+ kfree(obj);
+ *handle_ptr = NULL;
+exit:
+ if (status < 0)
+ pr_err("transportshm_close failed: status = 0x%x\n", status);
+ return status;
+}
+
+
+/*
+ * ======== transportshm_put ========
+ * Purpose:
+ * Put msg to remote list
+*/
+int transportshm_put(void *handle, void *msg)
+{
+ int status = 0;
+ struct transportshm_object *obj = NULL;
+ /*int *key;*/
+
+ if (WARN_ON(atomic_cmpmask_and_lt(
+ &(transportshm_module->ref_count),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(0),
+ TRANSPORTSHM_MAKE_MAGICSTAMP(1)) == true)) {
+ status = -ENODEV;
+ goto exit;
+ }
+ if (WARN_ON(handle == NULL)) {
+ status = -EINVAL;
+ goto exit;
+ }
+ if (WARN_ON(msg == NULL)) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ obj = (struct transportshm_object *)handle;
+#if 0
+ /* writeback invalidate the message */
+ if (EXPECT_FALSE(obj->cache_enabled)) {
+ Cache_wbinv((Ptr) msg,
+ ((MessageQ_Msg)(msg))->msgSize,
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+ /* make sure ListMP_put and sendEvent are done before remote executes */
+ /*key = gatemp_enter(obj->gate);*/
+ status = listmp_put_tail(obj->remote_list, (struct listmp_elem *) msg);
+ if (status < 0) {
+ pr_err("transportshm_put: Failed to put "
+ "message in the shared list! status = 0x%x\n", status);
+ goto exit_with_gate;
+ }
+
+ status = notify_send_event(obj->remote_proc_id, 0,
+ obj->notify_event_id, 0, false);
+ if (status < 0)
+ goto notify_send_fail;
+ else
+ goto exit_with_gate;
+
+
+notify_send_fail:
+ pr_err("transportshm_put: Notification to remote "
+ "processor failed, status = 0x%x\n", status);
+ /* If sending the event failed, then remove the element from the */
+ /* list. Ignore the status of remove. */
+ listmp_remove(obj->remote_list, (struct listmp_elem *) msg);
+
+exit_with_gate:
+ /*gatemp_leave(obj->gate, key);*/
+exit:
+ if (status < 0)
+ pr_err("transportshm_put failed: status = 0x%x\n", status);
+ return status;
+}
+
+/*
+ * ======== transportshm_control ========
+ * Purpose:
+ * Control Function
+*/
+int transportshm_control(void *handle, u32 cmd, u32 *cmd_arg)
+{
+ BUG_ON(handle == NULL);
+
+ pr_err("transportshm_control not supported!\n");
+ return TRANSPORTSHM_E_NOTSUPPORTED;
+}
+
+/*
+ * ======== transportshm_get_status ========
+ * Purpose:
+ * Get status
+ */
+enum transportshm_status transportshm_get_status(void *handle)
+{
+ struct transportshm_object *obj = \
+ (struct transportshm_object *) handle;
+
+ BUG_ON(obj == NULL);
+
+ return obj->status;
+}
+
+/*
+ * ======== transportshm_put ========
+ * Purpose:
+ * Get shared memory requirements.
+ */
+u32 transportshm_shared_mem_req(const struct transportshm_params *params)
+{
+ u32 mem_req = 0;
+ s32 min_align;
+ u16 region_id;
+ struct listmp_params list_params;
+ s32 status = 0;
+
+ if (params == NULL) {
+ status = -EINVAL;
+ goto exit;
+ }
+ region_id = sharedregion_get_id(params->shared_addr);
+
+ if (region_id == SHAREDREGION_INVALIDREGIONID) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ min_align = 4; /*memory_get_max_default_type_align(); */
+ if (sharedregion_get_cache_line_size(region_id) > min_align)
+ min_align = sharedregion_get_cache_line_size(region_id);
+
+ /* for the Attrs structure */
+ mem_req = ROUND_UP(sizeof(struct transportshm_attrs), min_align);
+
+ /* for the second Attrs structure */
+ mem_req += ROUND_UP(sizeof(struct transportshm_attrs), min_align);
+
+ listmp_params_init(&list_params);
+ list_params.region_id = region_id;
+ /* for local listMP */
+ mem_req += listmp_shared_mem_req(&list_params);
+
+ /* for remote listMP */
+ mem_req += listmp_shared_mem_req(&list_params);
+
+exit:
+ if (status < 0)
+ pr_err("transportshm_shared_mem_req failed: "
+ "status = 0x%x\n", status);
+
+ return mem_req;
+}
+
+
+/* =============================================================================
+ * internal functions
+ * =============================================================================
+ */
+/*
+ * ======== _transportshm_notify_fxn ========
+ * Purpose:
+ * Callback function registered with the Notify module.
+ */
+static void _transportshm_notify_fxn(u16 proc_id, u16 line_id, u32 event_no,
+ uint *arg, u32 payload)
+{
+ struct transportshm_object *obj = NULL;
+ messageq_msg msg = NULL;
+ u32 queue_id;
+ u32 key;
+
+ key = mutex_lock_interruptible(transportshm_state.gate_handle);
+
+ if (key < 0)
+ goto mutex_fail;
+
+ if (WARN_ON(arg == NULL))
+ goto exit;
+
+ obj = (struct transportshm_object *)arg;
+ /* While there is are messages, get them out and send them to
+ * their final destination. */
+ if (obj->local_list)
+ msg = (messageq_msg) listmp_get_head(obj->local_list);
+ else
+ goto exit;
+ while (msg != NULL) {
+ /* Get the destination message queue Id */
+ queue_id = messageq_get_dst_queue(msg);
+
+ /* put the message to the destination queue */
+ messageq_put(queue_id, msg);
+ if (obj->local_list)
+ msg = (messageq_msg)
+ listmp_get_head(obj->local_list);
+ else
+ msg = NULL;
+ }
+ mutex_unlock(transportshm_state.gate_handle);
+ return;
+
+exit:
+ mutex_unlock(transportshm_state.gate_handle);
+mutex_fail:
+ pr_err("transportshm_notify_fxn: argument passed is NULL!\n");
+ return;
+}
+
+
+/*
+ * ======== transportshm_delete ========
+ * Purpose:
+ * This will set the asynchronous error function for the transport module
+ */
+void transportshm_set_err_fxn( void (*err_fxn)(
+ enum transportshm_reason reason,
+ void *handle,
+ void *msg,
+ u32 info))
+{
+ int key;
+
+ key = mutex_lock_interruptible(transportshm_module->gate_handle);
+ if (key < 0)
+ goto exit;
+
+ transportshm_module->cfg.err_fxn = err_fxn;
+ mutex_unlock(transportshm_module->gate_handle);
+
+exit:
+ return;
+}
+
+
+/*
+ * ========= _transportshm_create =========
+ * Purpose:
+ * Internal function for create()/open()
+ */
+static int _transportshm_create(struct transportshm_object **handle_ptr,
+ u16 proc_id, const struct transportshm_params *params,
+ bool create_flag)
+{
+ int status = 0;
+ struct transportshm_object *handle = NULL;
+ void *local_addr = NULL;
+ int local_index;
+ int remote_index;
+ u32 min_align;
+ struct listmp_params listmp_params[2];
+
+ BUG_ON(handle_ptr == NULL);
+ BUG_ON(params == NULL);
+ BUG_ON(proc_id >= multiproc_get_num_processors());
+
+ /*
+ * Determine who gets the '0' slot and who gets the '1' slot
+ * The '0' slot is given to the lower multiproc id.
+ */
+ if (multiproc_self() < proc_id) {
+ local_index = 0;
+ remote_index = 1;
+ } else {
+ local_index = 1;
+ remote_index = 0;
+ }
+
+ handle = kzalloc(sizeof(struct transportshm_object), GFP_KERNEL);
+ if (handle == NULL) {
+ status = -ENOMEM;
+ goto exit;
+ }
+ *handle_ptr = handle;
+
+ if (create_flag == false) {
+ /* Open by shared addr */
+ handle->self = (struct transportshm_attrs *)
+ params->shared_addr;
+ handle->region_id = sharedregion_get_id(params->shared_addr);
+ BUG_ON(handle->region_id == SHAREDREGION_INVALIDREGIONID);
+
+ handle->cache_enabled = sharedregion_is_cache_enabled(handle->
+ region_id);
+
+ local_addr = sharedregion_get_ptr((u32 *)handle->self->
+ gatemp_addr);
+ BUG_ON(local_addr == NULL);
+
+ status = gatemp_open_by_addr(local_addr, &handle->gate);
+ if (status < 0) {
+ status = -EFAULT;
+ goto exit;
+ }
+ } else {
+ /* Init the gate for ListMP create below */
+ if (params->gate != NULL)
+ handle->gate = params->gate;
+ else
+ handle->gate = gatemp_get_default_remote();
+
+ if (handle->gate == NULL) {
+ status = -EFAULT;
+ goto exit;
+ }
+ memcpy(&(handle->params), params,
+ sizeof(struct transportshm_params));
+ handle->region_id = sharedregion_get_id(params->shared_addr);
+
+ /* Assert that the buffer is in a valid shared
+ * region
+ */
+ if (handle->region_id == SHAREDREGION_INVALIDREGIONID) {
+ status = -EFAULT;
+ goto exit;
+ }
+ if (((u32)params->shared_addr
+ % sharedregion_get_cache_line_size(handle->region_id)
+ != 0)) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ /* set handle's cache_enabled, type, attrs */
+ handle->cache_enabled = sharedregion_is_cache_enabled(
+ handle->region_id);
+ handle->self = (struct transportshm_attrs *)
+ params->shared_addr;
+ }
+
+ /* Determine the minimum alignment to align to */
+ min_align = 4; /*memory_get_max_default_type_align(); */
+ if (sharedregion_get_cache_line_size(handle->region_id) > min_align)
+ min_align = sharedregion_get_cache_line_size(handle->
+ region_id);
+ /*
+ * Carve up the shared memory.
+ * If cache is enabled, these need to be on separate cache
+ * lines. This is done with min_align and ROUND_UP function.
+ */
+
+ handle->other = (struct transportshm_attrs *)(((u32)handle->self) +
+ (ROUND_UP(sizeof(struct transportshm_attrs), min_align)));
+
+
+ listmp_params_init(&(listmp_params[0]));
+ listmp_params[0].gatemp_handle = handle->gate;
+ listmp_params[0].shared_addr = (void *)(((u32)handle->other)
+ + (ROUND_UP(sizeof(struct transportshm_attrs), min_align)));
+
+ listmp_params_init(&listmp_params[1]);
+ listmp_params[1].gatemp_handle = handle->gate;
+ listmp_params[1].shared_addr = (void *)
+ (((u32)listmp_params[0].shared_addr)
+ + listmp_shared_mem_req(&listmp_params[0]));
+
+ handle->notify_event_id = params->notify_event_id;
+ handle->priority = params->priority;
+ handle->remote_proc_id = proc_id;
+
+ if (create_flag == true) {
+ handle->local_list =
+ listmp_create(&(listmp_params[local_index]));
+ if (handle->local_list == NULL) {
+ status = -EFAULT;
+ goto exit;
+ }
+ handle->remote_list = listmp_create(
+ &(listmp_params[remote_index]));
+ if (handle->remote_list == NULL) {
+ status = -EFAULT;
+ goto exit;
+ }
+ } else {
+ /* Open the local ListMP instance */
+ status = listmp_open_by_addr(
+ listmp_params[local_index].shared_addr,
+ &(handle->local_list));
+ if (status < 0) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ status = listmp_open_by_addr(
+ listmp_params[remote_index].shared_addr,
+ &(handle->remote_list));
+ if (status < 0) {
+ status = -EFAULT;
+ goto exit;
+ }
+ }
+
+ status = notify_register_event_single(proc_id,
+ 0, /* lineId */
+ params->notify_event_id,
+ _transportshm_notify_fxn,
+ handle);
+ if (status < 0) {
+ status = -EFAULT;
+ goto exit;
+ }
+
+ if (create_flag == true) {
+ handle->self->creator_proc_id = multiproc_self();
+ handle->self->notify_event_id = handle->notify_event_id;
+ handle->self->priority = handle->priority;
+
+ /* Store the GateMP shared_addr in the Attrs */
+ handle->self->gatemp_addr =
+ gatemp_get_shared_addr(handle->gate);
+ handle->self->flag = TRANSPORTSHM_UP;
+#if 0
+ if (EXPECT_FALSE(handle->cache_enabled)) {
+ Cache_wbinv((Ptr) handle->self,
+ sizeof(struct transportshm_attrs),
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+ } else {
+ handle->other->flag = TRANSPORTSHM_UP;
+#if 0
+ if (EXPECT_FALSE(handle->cache_enabled)) {
+ Cache_wb((Ptr)&(handle->other->flag),
+ min_align,
+ Cache_Type_ALL,
+ true);
+ }
+#endif
+ }
+
+ /* Register the transport with MessageQ */
+ status = messageq_register_transport(handle, proc_id,
+ params->priority);
+ if (status < 0) {
+ status = -EFAULT;
+ goto exit;
+ }
+ handle->status = TRANSPORTSHM_UP;
+ /* Set handle in the local array. */
+ transportshm_module->transports[handle->remote_proc_id]
+ [handle->params.priority] = handle;
+
+ return status;
+
+exit:
+ /* Cleanup in case of error. */
+ if (create_flag == true)
+ transportshm_delete((void **)handle_ptr);
+ else
+ transportshm_close((void **)handle_ptr);
+
+ return status;
+}
diff --git a/drivers/dsp/syslink/multicore_ipc/transportshm_setup.c b/drivers/dsp/syslink/multicore_ipc/transportshm_setup.c
new file mode 100644
index 00000000000..a348c03f6b0
--- /dev/null
+++ b/drivers/dsp/syslink/multicore_ipc/transportshm_setup.c
@@ -0,0 +1,206 @@
+/*
+ * transportshm_setup.c
+ *
+ * Shared Memory Transport setup module
+ *
+ * Copyright (C) 2009 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.
+ */
+
+/* Standard headers */
+#include <linux/types.h>
+
+/* Utilities headers */
+#include <linux/string.h>
+#include <linux/slab.h>
+
+/* Syslink headers */
+#include <syslink/atomic_linux.h>
+/* Module level headers */
+#include <multiproc.h>
+#include <sharedregion.h>
+#include <nameserver.h>
+#include <gatepeterson.h>
+#include <notify.h>
+#include <messageq.h>
+#include <listmp.h>
+#include <gatemp.h>
+#include <transportshm.h>
+#include <transportshm_setup.h>
+
+/* =============================================================================
+ * Structures & Enums
+ * =============================================================================
+ */
+/* structure for transportshm_setup module state */
+struct transportshm_setup_module_object {
+ void *handles[MULTIPROC_MAXPROCESSORS];
+ /* Store a handle per remote proc */
+};
+
+
+/* =============================================================================
+ * Globals
+ * =============================================================================
+ */
+static struct transportshm_setup_module_object transportshm_setup_state = {
+ .handles[0] = NULL
+};
+
+/* Pointer to the transportshm_setup module state */
+static struct transportshm_setup_module_object *transportshm_setup_module =
+ &transportshm_setup_state;
+
+
+/* =============================================================================
+ * Functions
+ * =============================================================================
+ */
+/*
+ * =========== transportshm_setup_attach ===========
+ * Function that will be called in messageq_attach. Creates a
+ * transportshm object for a given processor
+ */
+int transportshm_setup_attach(u16 remote_proc_id, u32 *shared_addr)
+{
+ s32 status = 0;
+ struct transportshm_params params;
+ void *handle;
+
+ BUG_ON(remote_proc_id >= MULTIPROC_MAXPROCESSORS);
+
+ if (WARN_ON(unlikely(shared_addr == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ /* Init the transport parameters */
+ transportshm_params_init(&params);
+ params.gate = gatemp_get_default_remote();
+ params.shared_addr = shared_addr;
+
+ /* Make sure notify driver has been created */
+ if (unlikely(notify_is_registered(remote_proc_id, 0) == false)) {
+ status = TRANSPORTSHM_E_FAIL;
+ goto exit;
+ }
+
+ if (multiproc_self() < remote_proc_id) {
+ handle = transportshm_create(remote_proc_id, &params);
+ if (unlikely(handle == NULL)) {
+ status = TRANSPORTSHM_E_FAIL;
+ goto exit;
+ }
+
+ transportshm_setup_module->handles[remote_proc_id] = handle;
+ } else {
+ status = transportshm_open_by_addr(params.shared_addr, &handle);
+ if (status < 0)
+ goto exit;
+
+ transportshm_setup_module->handles[remote_proc_id] = handle;
+ }
+
+exit:
+ if (status < 0)
+ pr_err("transportshm_setup_attach failed! status "
+ "= 0x%x", status);
+ return status;
+}
+
+/*
+ * =========== transportshm_setup_detach ===========
+ * Function that will be called in messageq_detach. Deletes a
+ * transportshm object created by transportshm_setup_attach.
+ */
+int transportshm_setup_detach(u16 remote_proc_id)
+{
+ int status = 0;
+ void *handle = NULL;
+
+ if (WARN_ON(remote_proc_id >= MULTIPROC_MAXPROCESSORS)) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ handle = transportshm_setup_module->handles[remote_proc_id];
+ if (WARN_ON(unlikely(handle == NULL))) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ if (multiproc_self() < remote_proc_id) {
+ /* Delete the transport */
+ status = transportshm_delete(&handle);
+ if (unlikely(status < 0)) {
+ status = TRANSPORTSHM_E_FAIL;
+ goto exit;
+ }
+ transportshm_setup_module->handles[remote_proc_id] = NULL;
+ } else {
+ status = transportshm_close(&handle);
+ if (unlikely(status < 0)) {
+ status = TRANSPORTSHM_E_FAIL;
+ goto exit;
+ }
+ transportshm_setup_module->handles[remote_proc_id] = NULL;
+ }
+
+exit:
+ if (status < 0)
+ pr_err("transportshm_setup_detach failed! status "
+ "= 0x%x", status);
+ return status;
+}
+
+
+/*
+ * =========== transportshm_setup_shared_mem_req ===========
+ * Function that returns the amount of shared memory required
+ */
+u32 transportshm_setup_shared_mem_req(u32 *shared_addr)
+{
+ u32 mem_req = 0x0;
+ int status = 0;
+ struct transportshm_params params;
+
+ /* Don't do anything if only 1 processor in system */
+ if (likely(multiproc_get_num_processors() != 1)) {
+ BUG_ON(shared_addr == NULL);
+
+ if (unlikely(shared_addr == NULL)) {
+ status = -EINVAL;
+ goto exit;
+ }
+
+ transportshm_params_init(&params);
+ params.shared_addr = shared_addr;
+
+ mem_req += transportshm_shared_mem_req(&params);
+ }
+
+exit:
+ if (status < 0)
+ pr_err("transportshm_setup_shared_mem_req failed! "
+ "status = 0x%x", status);
+ return mem_req;
+}
+
+/* Determines if a transport has been registered to a remote processor */
+bool transportshm_setup_is_registered(u16 remote_proc_id)
+{
+ bool registered;
+
+ registered = (transportshm_setup_module->handles[remote_proc_id] !=
+ NULL);
+
+ return registered;
+}
diff --git a/drivers/dsp/syslink/notify_ducatidriver/notify_ducati.c b/drivers/dsp/syslink/notify_ducatidriver/notify_ducati.c
new file mode 100644
index 00000000000..5ffc0991ee3
--- /dev/null
+++ b/drivers/dsp/syslink/notify_ducatidriver/notify_ducati.c
@@ -0,0 +1,1370 @@
+/*
+ * notify_ducati.c
+ *
+ * Syslink driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2008-2009 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 <linux/spinlock.h>
+#include <linux/semaphore.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <plat/mailbox.h>
+
+#include <syslink/multiproc.h>
+#include <syslink/atomic_linux.h>
+#include <syslink/sharedregion.h>
+#include <syslink/notify_driver.h>
+#include <syslink/notifydefs.h>
+#include <syslink/notify_driverdefs.h>
+#include <syslink/notify_ducatidriver.h>
+
+
+
+#define NOTIFYDUCATIDRIVER_MEM_ALIGN 0
+
+#define NOTIFYDUCATIDRIVER_MAX_EVENTS 32
+
+#define NOTIFYNONSHMDRV_MAX_EVENTS 1
+
+#define NOTIFYNONSHMDRV_RESERVED_EVENTS 1
+
+#define NOTIFYDRV_DUCATI_RECV_MBX 2
+
+#define NOTIFYDRV_DUCATI_SEND_MBX 3
+
+/* Get address of event entry. */
+#define EVENTENTRY(event_chart, align, event_id) \
+ ((struct notify_ducatidrv_event_entry *) \
+ ((u32)event_chart + (align * event_id)));
+
+/* Stamp indicating that the Notify Shared Memory driver on the
+ * processor has been initialized. */
+#define NOTIFYDUCATIDRIVER_INIT_STAMP 0xA9C8B7D6
+
+/* Flag indicating event is set. */
+#define NOTIFYDUCATIDRIVER_UP 1
+
+/* Flag indicating event is not set. */
+#define NOTIFYDUCATIDRIVER_DOWN 0
+
+/*FIX ME: Make use of Multi Proc module */
+#define SELF_ID 0
+
+#define OTHER_ID 1
+
+#define PROC_TESLA 0
+#define PROC_DUCATI 1
+#define PROC_GPP 2
+#define PROCSYSM3 2
+#define PROCAPPM3 3
+#define MAX_SUBPROC_EVENTS 15
+
+/* Macro to make a correct module magic number with refCount */
+#define NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(x) \
+ ((NOTIFY_DUCATIDRIVER_MODULEID << 12u) | (x))
+
+#define ROUND_UP(a, b) (((a) + ((b) - 1)) & (~((b) - 1)))
+
+static struct omap_mbox *ducati_mbox;
+static struct omap_mbox *tesla_mbox;
+static int notify_shmdrv_isr(struct notifier_block *, unsigned long, void *);
+static bool notify_shmdrv_isr_callback(void *ref_data, void* ntfy_msg);
+
+
+/* Defines the notify_ducatidrv state object, which contains all
+ * the module specific information. */
+struct notify_ducatidrv_module {
+ atomic_t ref_count;
+ /* Reference count */
+ struct notify_ducatidrv_config cfg;
+ /* NotifyDriverShm configuration structure */
+ struct notify_ducatidrv_config def_cfg;
+ /* Default module configuration */
+ struct notify_ducatidrv_params def_inst_params;
+ /* Default instance parameters */
+ struct mutex *gate_handle;
+ /* Handle to the gate for local thread safety */
+ struct notify_ducatidrv_object *driver_handles
+ [MULTIPROC_MAXPROCESSORS][NOTIFY_MAX_INTLINES];
+ /* Loader handle array. */
+ atomic_t mbox2_ref_count;
+ /* Reference count for enabling/disabling ducati mailbox interrupt */
+ atomic_t mbox1_ref_count;
+ /* Reference count for enabling/disabling tesla mailbox interrupt */
+};
+
+/* Notify ducati driver instance object. */
+struct notify_ducatidrv_object {
+ struct notify_ducatidrv_params params;
+ /* Instance parameters (configuration values) */
+ VOLATILE struct notify_ducatidrv_proc_ctrl *self_proc_ctrl;
+ /* Pointer to control structure in shared memory for self processor. */
+ VOLATILE struct notify_ducatidrv_proc_ctrl *other_proc_ctrl;
+ /* Pointer to control structure in shared memory for remote processor.*/
+ VOLATILE struct notify_ducatidrv_event_entry *self_event_chart;
+ /* Pointer to event chart for local processor */
+ VOLATILE struct notify_ducatidrv_event_entry *other_event_chart;
+ /* Pointer to event chart for remote processor */
+ u32 reg_chart[NOTIFY_MAXEVENTS];
+ /* Local event registration chart for tracking registered events. */
+ u16 self_id;
+ /* Self ID used for identification of local control region */
+ u16 other_id;
+ /* Other ID used for identification of remote control region */
+ u16 remote_proc_id;
+ /* Processor ID of the remote processor which which this driver instance
+ communicates. */
+ struct notify_driver_object *drv_handle;
+ /* Common NotifyDriver handle */
+ u32 nesting;
+ /* For disable/restore nesting */
+ u32 cache_enabled;
+ /* Whether to perform cache calls */
+ u32 event_entry_size;
+ /* Spacing between event entries */
+ u32 num_events;
+ /* Number of events configured */
+};
+
+
+static struct notify_ducatidrv_module notify_ducatidriver_state = {
+ .gate_handle = NULL,
+ .def_inst_params.shared_addr = NULL,
+ .def_inst_params.cache_enabled = false,
+ .def_inst_params.cache_line_size = 128u,
+ .def_inst_params.remote_proc_id = MULTIPROC_INVALIDID,
+ .def_inst_params.line_id = 0,
+ .def_inst_params.local_int_id = (u32) -1,
+ .def_inst_params.remote_int_id = (u32) -1
+};
+
+static struct notifier_block ducati_notify_nb = {
+ .notifier_call = notify_shmdrv_isr,
+};
+
+/* Get the default configuration for the notify_ducatidrv module. */
+void notify_ducatidrv_get_config(struct notify_ducatidrv_config *cfg)
+{
+ int status = NOTIFY_S_SUCCESS;
+
+ if (WARN_ON(unlikely(cfg == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ if (atomic_cmpmask_and_lt(&(notify_ducatidriver_state.ref_count),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1))
+ == true)
+ memcpy(cfg, &(notify_ducatidriver_state.def_cfg),
+ sizeof(struct notify_ducatidrv_config));
+ else
+ memcpy(cfg, &(notify_ducatidriver_state.cfg),
+ sizeof(struct notify_ducatidrv_config));
+
+exit:
+ if (status < 0) {
+ pr_err("notify_ducatidrv_get_config failed! "
+ "status = 0x%x", status);
+ }
+ return;
+}
+EXPORT_SYMBOL(notify_ducatidrv_get_config);
+
+/* Setup the notify_ducatidrv module. */
+int notify_ducatidrv_setup(struct notify_ducatidrv_config *cfg)
+{
+ int status = 0;
+ struct notify_ducatidrv_config tmp_cfg;
+ u16 i;
+ u16 j;
+
+ /* Init the ref_count to 0 */
+ atomic_cmpmask_and_set(&(notify_ducatidriver_state.ref_count),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0));
+ if (atomic_inc_return(&(notify_ducatidriver_state.ref_count)) !=
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1u)) {
+ return NOTIFY_S_ALREADYSETUP;
+ }
+ atomic_set(&(notify_ducatidriver_state.mbox2_ref_count), 0);
+ atomic_set(&(notify_ducatidriver_state.mbox1_ref_count), 0);
+
+ if (cfg == NULL) {
+ notify_ducatidrv_get_config(&tmp_cfg);
+ cfg = &tmp_cfg;
+ }
+
+ /* Create a default gate handle here */
+ notify_ducatidriver_state.gate_handle =
+ kmalloc(sizeof(struct mutex), GFP_KERNEL);
+ if (notify_ducatidriver_state.gate_handle == NULL) {
+ status = NOTIFY_E_MEMORY;
+ goto error_exit;
+ }
+ mutex_init(notify_ducatidriver_state.gate_handle);
+
+ for (i = 0 ; i < MULTIPROC_MAXPROCESSORS; i++)
+ for (j = 0 ; j < NOTIFY_MAX_INTLINES; j++)
+ notify_ducatidriver_state.driver_handles[i][j] = NULL;
+
+ memcpy(&notify_ducatidriver_state.cfg, cfg,
+ sizeof(struct notify_ducatidrv_config));
+
+ /* Initialize the maibox module for Ducati */
+ if (ducati_mbox == NULL) {
+ ducati_mbox = omap_mbox_get("mailbox-2", &ducati_notify_nb);
+ if (ducati_mbox == NULL) {
+ pr_err("Failed in omap_mbox_get(ducati)\n");
+ status = NOTIFY_E_INVALIDSTATE;
+ goto error_mailbox_get_failed;
+ }
+ }
+
+ /* Initialize the maibox module for Tesla */
+ if (!tesla_mbox) {
+ tesla_mbox = omap_mbox_get("mailbox-1", &ducati_notify_nb);
+ if (!tesla_mbox) {
+ pr_err("Failed in omap_mbox_get(tesla)\n");
+ status = NOTIFY_E_INVALIDSTATE;
+ goto error_mailbox_get_failed;
+ }
+ }
+ return 0;
+
+error_mailbox_get_failed:
+ kfree(notify_ducatidriver_state.gate_handle);
+error_exit:
+ atomic_set(&(notify_ducatidriver_state.ref_count),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0));
+ pr_err("notify_ducatidrv_setup failed! status = 0x%x", status);
+ return status;
+}
+EXPORT_SYMBOL(notify_ducatidrv_setup);
+
+/* Destroy the notify_ducatidrv module. */
+int notify_ducatidrv_destroy(void)
+{
+ int status = NOTIFY_S_SUCCESS;
+ u16 i;
+ u16 j;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(notify_ducatidriver_state.ref_count),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (!(atomic_dec_return(&notify_ducatidriver_state.ref_count) == \
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0)))
+ return NOTIFY_S_ALREADYSETUP;
+
+ /* Temporarily increment the refcount */
+ atomic_set(&(notify_ducatidriver_state.ref_count),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1));
+
+ for (i = 0 ; i < MULTIPROC_MAXPROCESSORS; i++) {
+ for (j = 0 ; j < NOTIFY_MAX_INTLINES; j++) {
+ if (notify_ducatidriver_state.driver_handles[i][j] != \
+ NULL) {
+ notify_ducatidrv_delete(
+ &notify_ducatidriver_state.\
+ driver_handles[i][j]);
+ }
+ }
+ }
+
+ if (notify_ducatidriver_state.gate_handle != NULL)
+ kfree(notify_ducatidriver_state.gate_handle);
+
+ atomic_set(&(notify_ducatidriver_state.ref_count),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0));
+
+ /* Finalize the maibox module for Ducati */
+ omap_mbox_put(ducati_mbox, &ducati_notify_nb);
+ ducati_mbox = NULL;
+
+ /* Finalize the maibox module for Tesla */
+ omap_mbox_put(tesla_mbox, &ducati_notify_nb);
+ tesla_mbox = NULL;
+
+exit:
+ if (status < 0) {
+ pr_err("notify_ducatidrv_destroy failed! "
+ "status = 0x%x", status);
+ }
+ return status;
+}
+EXPORT_SYMBOL(notify_ducatidrv_destroy);
+
+/* Function to initialize the parameters for this notify_ducatidrv instance. */
+void notify_ducatidrv_params_init(struct notify_ducatidrv_params *params)
+{
+ int status = NOTIFY_S_SUCCESS;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(notify_ducatidriver_state.ref_count),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(params == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ /*Return updated notify_ducatidrv instance specific parameters*/
+ memcpy(params, &(notify_ducatidriver_state.def_inst_params),
+ sizeof(struct notify_ducatidrv_params));
+
+exit:
+ if (status < 0) {
+ pr_err("notify_ducatidrv_params_init failed! "
+ "status = 0x%x", status);
+ }
+ return;
+}
+EXPORT_SYMBOL(notify_ducatidrv_params_init);
+
+/* Function to create an instance of this Notify ducati driver. */
+struct notify_ducatidrv_object *notify_ducatidrv_create(
+ const struct notify_ducatidrv_params *params)
+{
+ int status = NOTIFY_S_SUCCESS;
+ struct notify_ducatidrv_object *obj = NULL;
+ struct notify_driver_object *drv_handle = NULL;
+ struct notify_driver_fxn_table fxn_table;
+ struct omap_mbox *mbox;
+ atomic_t *mbx_cnt;
+ u32 i;
+ u16 region_id;
+ uint region_cache_size;
+ uint min_align;
+ struct notify_ducatidrv_event_entry *event_entry;
+ u32 proc_ctrl_size;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(notify_ducatidriver_state.ref_count),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(params == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely((params->remote_proc_id == MULTIPROC_INVALIDID)
+ || (params->remote_proc_id == multiproc_self())))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(params->line_id >= NOTIFY_MAX_INTLINES))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(((u32)params->shared_addr % \
+ (u32) params->cache_line_size)) != 0)) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ if (params->remote_proc_id) {
+ mbox = ducati_mbox;
+ mbx_cnt = &notify_ducatidriver_state.mbox2_ref_count;
+ } else {
+ mbox = tesla_mbox;
+ mbx_cnt = &notify_ducatidriver_state.mbox1_ref_count;
+ }
+
+ status = mutex_lock_interruptible(
+ notify_ducatidriver_state.gate_handle);
+ if (status)
+ goto exit;
+
+ /* Check if driver already exists. */
+ drv_handle = notify_get_driver_handle(params->remote_proc_id,
+ params->line_id);
+ if (drv_handle != NULL) {
+ status = NOTIFY_E_ALREADYEXISTS;
+ goto error_unlock_and_return;
+ }
+
+ /* Function table information */
+ fxn_table.register_event = (void *)&notify_ducatidrv_register_event;
+ fxn_table.unregister_event = (void *)&notify_ducatidrv_unregister_event;
+ fxn_table.send_event = (void *)&notify_ducatidrv_send_event;
+ fxn_table.disable = (void *)&notify_ducatidrv_disable;
+ fxn_table.enable = (void *)&notify_ducatidrv_enable;
+ fxn_table.disable_event = (void *)&notify_ducatidrv_disable_event;
+ fxn_table.enable_event = (void *)&notify_ducatidrv_enable_event;
+
+ /* Register driver with the Notify module. */
+ status = notify_register_driver(params->remote_proc_id,
+ params->line_id, &fxn_table,
+ &drv_handle);
+ if (status < 0) {
+ status = NOTIFY_E_FAIL;
+ goto error_clean_and_exit;
+ }
+
+ /* Allocate memory for the notify_ducatidrv_object object. */
+ obj = kzalloc(sizeof(struct notify_ducatidrv_object), GFP_ATOMIC);
+ if (obj == NULL) {
+ status = NOTIFY_E_MEMORY;
+ goto error_clean_and_exit;
+ }
+ memcpy(&(obj->params), (void *) params,
+ sizeof(struct notify_ducatidrv_params));
+ obj->num_events = notify_state.cfg.num_events;
+ /* Set the handle in the driverHandles array. */
+ notify_ducatidriver_state.driver_handles
+ [params->remote_proc_id][params->line_id] = obj;
+ /* Point to the generic drvHandle object from this specific
+ * NotifyDriverShm object. */
+ obj->drv_handle = drv_handle;
+
+ /* Determine obj->cacheEnabled using params->cacheEnabled and
+ * SharedRegion cache flag setting, if applicable. */
+ obj->cache_enabled = params->cache_enabled;
+ min_align = params->cache_line_size;
+ region_id = sharedregion_get_id((void *)params->shared_addr);
+ if (region_id != SHAREDREGION_INVALIDREGIONID) {
+ /* Override the user cacheEnabled setting if the region
+ * cacheEnabled is FALSE. */
+ if (!sharedregion_is_cache_enabled(region_id))
+ obj->cache_enabled = false;
+
+ region_cache_size = sharedregion_get_cache_line_size(region_id);
+
+ /* Override the user cache line size setting if the region
+ * cache line size is smaller. */
+ if (region_cache_size < min_align)
+ min_align = region_cache_size;
+ }
+
+ if ((u32)params->shared_addr % min_align != 0) {
+ status = NOTIFY_E_FAIL;
+ goto error_clean_and_exit;
+ }
+ obj->remote_proc_id = params->remote_proc_id;
+ obj->nesting = 0;
+ if (params->remote_proc_id > multiproc_self()) {
+ obj->self_id = SELF_ID;
+ obj->other_id = OTHER_ID;
+ } else {
+ obj->self_id = OTHER_ID;
+ obj->other_id = SELF_ID;
+ }
+
+ proc_ctrl_size = ROUND_UP(sizeof(struct notify_ducatidrv_proc_ctrl),
+ min_align);
+
+ /* Save the eventEntrySize in obj since we will need it at runtime to
+ * index the event charts */
+
+ obj->event_entry_size = ROUND_UP(
+ sizeof(struct notify_ducatidrv_event_entry),
+ min_align);
+ obj->self_proc_ctrl = (struct notify_ducatidrv_proc_ctrl *)
+ ((u32) params->shared_addr + \
+ (obj->self_id * proc_ctrl_size));
+ obj->other_proc_ctrl = (struct notify_ducatidrv_proc_ctrl *)
+ ((u32) params->shared_addr + \
+ (obj->other_id * proc_ctrl_size));
+ obj->self_event_chart = (struct notify_ducatidrv_event_entry *)
+ ((u32) params->shared_addr + \
+ (2 * proc_ctrl_size) + \
+ (obj->event_entry_size * \
+ obj->num_events * obj->self_id));
+ obj->other_event_chart = (struct notify_ducatidrv_event_entry *)
+ ((u32) params->shared_addr + \
+ (2 * proc_ctrl_size) + \
+ (obj->event_entry_size * \
+ obj->num_events * obj->other_id));
+
+ for (i = 0; i < obj->num_events; i++)
+ obj->reg_chart[i] = (u32)-1;
+
+ /* All events initially unflagged */
+ for (i = 0; i < obj->num_events; i++) {
+ event_entry = EVENTENTRY(obj->self_event_chart,
+ obj->event_entry_size, i);
+ event_entry->flag = 0;
+ }
+
+ /* All events initially not registered */
+ obj->self_proc_ctrl->event_reg_mask = 0x0;
+
+ /* Enable all events initially.*/
+ obj->self_proc_ctrl->event_enable_mask = 0xFFFFFFFF;
+
+
+ /*Set up the ISR on the MPU-Ducati FIFO */
+ if (atomic_inc_return(mbx_cnt) == 1)
+ omap_mbox_enable_irq(mbox, IRQ_RX);
+ obj->self_proc_ctrl->recv_init_status = NOTIFYDUCATIDRIVER_INIT_STAMP;
+ obj->self_proc_ctrl->send_init_status = NOTIFYDUCATIDRIVER_INIT_STAMP;
+
+#if 0
+ /* Write back our own ProcCtrl */
+ if (obj->cache_enabled) {
+ Cache_wbInv((void *) obj->self_proc_ctrl,
+ sizeof(struct notify_ducatidrv_proc_ctrl),
+ Cache_Type_ALL, true);
+ }
+#endif
+
+ drv_handle->is_init = NOTIFY_DRIVERINITSTATUS_DONE;
+ mutex_unlock(notify_ducatidriver_state.gate_handle);
+ return obj;
+
+error_clean_and_exit:
+ if (obj != NULL) {
+ if (obj->self_proc_ctrl != NULL) {
+ /* Clear initialization status in shared memory. */
+ obj->self_proc_ctrl->recv_init_status = 0x0;
+ obj->self_proc_ctrl->recv_init_status = 0x0;
+ obj->self_proc_ctrl = NULL;
+#if 0
+ /* Write back our own ProcCtrl */
+ if (obj->cache_enabled) {
+ Cache_wbInv((void *) obj->self_proc_ctrl,
+ sizeof(struct notify_ducatidrv_proc_ctrl),
+ Cache_Type_ALL, true);
+ }
+#endif
+ kfree(obj);
+ obj = NULL;
+ }
+ }
+ if (drv_handle != NULL) {
+ /* Unregister driver from the Notify module*/
+ notify_unregister_driver(drv_handle);
+ notify_ducatidriver_state.driver_handles
+ [params->remote_proc_id][params->line_id] = NULL;
+ drv_handle = NULL;
+ }
+error_unlock_and_return:
+ /* Leave critical section protection. */
+ mutex_unlock(notify_ducatidriver_state.gate_handle);
+exit:
+ pr_err("notify_ducatidrv_create failed! status = 0x%x", status);
+ return NULL;
+}
+EXPORT_SYMBOL(notify_ducatidrv_create);
+
+/* Function to delete the instance of shared memory driver */
+int notify_ducatidrv_delete(struct notify_ducatidrv_object **handle_ptr)
+{
+ int status = NOTIFY_S_SUCCESS;
+ int tmp_status = NOTIFY_S_SUCCESS;
+ struct notify_ducatidrv_object *obj = NULL;
+ struct omap_mbox *mbox;
+ atomic_t *mbx_cnt;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(notify_ducatidriver_state.ref_count),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+
+ if (WARN_ON(unlikely(handle_ptr == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(*handle_ptr == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ obj = (struct notify_ducatidrv_object *)(*handle_ptr);
+ if (obj != NULL) {
+ if (obj->remote_proc_id) {
+ mbox = ducati_mbox;
+ mbx_cnt = &notify_ducatidriver_state.mbox2_ref_count;
+ } else {
+ mbox = tesla_mbox;
+ mbx_cnt = &notify_ducatidriver_state.mbox1_ref_count;
+ }
+ /* Uninstall the ISRs & Disable the Mailbox interrupt.*/
+ if (atomic_dec_and_test(mbx_cnt))
+ omap_mbox_disable_irq(mbox, IRQ_RX);
+
+ if (obj->self_proc_ctrl != NULL) {
+ /* Clear initialization status in shared memory. */
+ obj->self_proc_ctrl->recv_init_status = 0x0;
+ obj->self_proc_ctrl->recv_init_status = 0x0;
+ obj->self_proc_ctrl = NULL;
+#if 0
+ /* Write back our own ProcCtrl */
+ if (obj->cache_enabled) {
+ Cache_wbInv((void *) obj->self_proc_ctrl,
+ sizeof(struct notify_ducatidrv_proc_ctrl),
+ Cache_Type_ALL, true);
+ }
+#endif
+ }
+
+ tmp_status = notify_unregister_driver(obj->drv_handle);
+ if (status >= 0 && tmp_status < 0)
+ status = tmp_status;
+
+ notify_ducatidriver_state.driver_handles
+ [obj->params.remote_proc_id][obj->params.line_id] = \
+ NULL;
+
+ kfree(obj);
+ obj = NULL;
+ }
+
+exit:
+ if (status < 0)
+ pr_err("notify_ducatidrv_delete failed! status = 0x%x", status);
+ return status;
+}
+EXPORT_SYMBOL(notify_ducatidrv_delete);
+
+/* Register a callback for an event with the Notify driver. */
+int notify_ducatidrv_register_event(struct notify_driver_object *handle,
+ u32 event_id)
+{
+ int status = NOTIFY_S_SUCCESS;
+ struct notify_ducatidrv_object *obj;
+ VOLATILE struct notify_ducatidrv_event_entry *event_entry;
+ int i;
+ int j;
+
+ if (WARN_ON(unlikely(handle == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->is_init != \
+ NOTIFY_DRIVERINITSTATUS_DONE))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
+ status = NOTIFY_E_DRIVERNOTREGISTERED;
+ goto exit;
+ }
+
+ obj = (struct notify_ducatidrv_object *)
+ handle->notify_handle->driver_handle;
+ if (WARN_ON(unlikely(obj->reg_chart == NULL))) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ /* This function is only called for the first register, i.e. when the
+ * first callback is being registered. */
+ /* Add an entry for the registered event into the Event Registration
+ * Chart, in ascending order of event numbers (and decreasing
+ * priorities). There is no need to make this atomic since
+ * Notify_exec cannot preempt: shared memory hasn't been modified yet.
+ */
+ for (i = 0 ; i < obj->num_events; i++) {
+ /* Find the correct slot in the registration array. */
+ if (obj->reg_chart[i] == (u32) -1) {
+ for (j = (i - 1); j >= 0; j--) {
+ if (event_id < obj->reg_chart[j]) {
+ obj->reg_chart[j + 1] = \
+ obj->reg_chart[j];
+ i = j;
+ } else {
+ /* End the loop, slot found. */
+ j = -1;
+ }
+ }
+ obj->reg_chart[i] = event_id;
+ break;
+ }
+ }
+
+ /* Clear any pending unserviced event as there are no listeners
+ * for the pending event */
+ event_entry = EVENTENTRY(obj->self_event_chart, obj->event_entry_size,
+ event_id);
+ event_entry->flag = NOTIFYDUCATIDRIVER_DOWN;
+
+ /* Set the registered bit in shared memory and write back */
+ set_bit(event_id, (unsigned long *)
+ &(obj->self_proc_ctrl->event_reg_mask));
+
+#if 0
+ /* Write back both the flag and the reg mask */
+ if (obj->cache_enabled) {
+ /* Writeback eventRegMask */
+ Cache_wbInv((void *) obj->self_proc_ctrl,
+ sizeof(struct notify_ducatidrv_proc_ctrl),
+ Cache_Type_ALL, true);
+ /* Writeback event entry */
+ Cache_wbInv((void *) event_entry,
+ sizeof(struct notify_ducatidrv_event_entry),
+ Cache_Type_ALL, true);
+ }
+#endif
+
+exit:
+ if (status < 0) {
+ pr_err("notify_ducatidrv_register_event failed! "
+ "status = 0x%x", status);
+ }
+ return status;
+}
+
+/* Unregister a callback for an event with the Notify driver. */
+int notify_ducatidrv_unregister_event(struct notify_driver_object *handle,
+ u32 event_id)
+{
+ int status = NOTIFY_S_SUCCESS;
+ struct notify_ducatidrv_object *obj;
+ VOLATILE struct notify_ducatidrv_event_entry *event_entry;
+ int i;
+ int j;
+
+ if (WARN_ON(unlikely(handle == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->is_init != \
+ NOTIFY_DRIVERINITSTATUS_DONE))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
+ status = NOTIFY_E_DRIVERNOTREGISTERED;
+ goto exit;
+ }
+
+ obj = (struct notify_ducatidrv_object *)
+ handle->notify_handle->driver_handle;
+ if (WARN_ON(unlikely(obj->reg_chart == NULL))) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ /* This function is only called for the last unregister, i.e. when the
+ * final remaining callback is being unregistered.
+ * Unset the registered bit in shared memory */
+ clear_bit(event_id, (unsigned long *)
+ &(obj->self_proc_ctrl->event_reg_mask));
+
+ /* Clear any pending unserviced event as there are no listeners
+ * for the pending event. This should be done only after the event
+ * is unregistered from shared memory so the other processor doesn't
+ * successfully send an event our way immediately after unflagging this
+ * event. */
+ event_entry = EVENTENTRY(obj->self_event_chart, obj->event_entry_size,
+ event_id);
+ event_entry->flag = NOTIFYDUCATIDRIVER_DOWN;
+
+#if 0
+ /* Write back both the flag and the reg mask */
+ if (obj->cache_enabled) {
+ /* Writeback event entry */
+ Cache_wbInv((void *) event_entry,
+ sizeof(struct notify_ducatidrv_event_entry),
+ Cache_Type_ALL, true);
+ /* Writeback eventRegMask */
+ Cache_wbInv((void *) obj->self_proc_ctrl,
+ sizeof(struct notify_ducatidrv_proc_ctrl),
+ Cache_Type_ALL, true);
+ }
+#endif
+
+ /* Re-arrange eventIds in the Event Registration Chart so there is
+ * no gap caused by the removal of this eventId
+ *
+ * There is no need to make this atomic since Notify_exec cannot
+ * preempt: the event has already been disabled in shared memory
+ * (see above) */
+ for (i = 0 ; i < obj->num_events; i++) {
+ /* Find the correct slot in the registration array. */
+ if (event_id == obj->reg_chart[i]) {
+ obj->reg_chart[i] = (u32) -1;
+ for (j = (i + 1); (j != obj->num_events) && \
+ (obj->reg_chart[j] != (u32)-1); j++) {
+ obj->reg_chart[j - 1] = obj->reg_chart[j];
+ obj->reg_chart[j] = (u32)-1;
+ }
+ break;
+ }
+ }
+
+exit:
+ if (status < 0) {
+ pr_err("notify_ducatidrv_unregister_event failed! "
+ "status = 0x%x", status);
+ }
+ return status;
+}
+
+/* Send a notification event to the registered users for this
+ * notification on the specified processor. */
+int notify_ducatidrv_send_event(struct notify_driver_object *handle,
+ u32 event_id, u32 payload, bool wait_clear)
+{
+ int status = NOTIFY_S_SUCCESS;
+ struct notify_ducatidrv_object *obj;
+ struct omap_mbox *mbox;
+ VOLATILE struct notify_ducatidrv_event_entry *event_entry;
+ int max_poll_count;
+ int i = 0;
+ mbox_msg_t msg;
+
+ if (WARN_ON(unlikely(handle == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->is_init != \
+ NOTIFY_DRIVERINITSTATUS_DONE))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
+ status = NOTIFY_E_DRIVERNOTREGISTERED;
+ goto exit;
+ }
+
+ obj = (struct notify_ducatidrv_object *)
+ handle->notify_handle->driver_handle;
+
+ mbox = (obj->remote_proc_id) ? ducati_mbox : tesla_mbox;
+ if (WARN_ON(unlikely(obj->reg_chart == NULL))) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ dsb();
+ event_entry = EVENTENTRY(obj->other_event_chart, obj->event_entry_size,
+ event_id);
+#if 0
+ /* Invalidate cache for the other processor's procCtrl. */
+ if (obj->cache_enabled) {
+ Cache_wbInv((void *) obj->other_proc_ctrl,
+ sizeof(struct notify_ducatidrv_proc_ctrl),
+ Cache_Type_ALL, true);
+ }
+#endif
+ max_poll_count = notify_state.cfg.send_event_poll_count;
+
+ /* Check whether driver on other processor is initialized */
+ if (obj->other_proc_ctrl->recv_init_status != \
+ NOTIFYDUCATIDRIVER_INIT_STAMP) {
+ /* This may be used for polling till other-side driver is ready,
+ * so do not set failure reason. */
+ status = NOTIFY_E_NOTINITIALIZED;
+ goto exit;
+ }
+ /* Check if other side has registered to receive this event. */
+ if (!test_bit(event_id, (unsigned long *)
+ &obj->other_proc_ctrl->event_reg_mask)) {
+ status = NOTIFY_E_EVTNOTREGISTERED;
+ /* This may be used for polling till other-side is ready, so
+ * do not set failure reason. */
+ goto exit;
+ }
+ if (!test_bit(event_id, (unsigned long *)
+ &obj->other_proc_ctrl->event_enable_mask)) {
+ status = NOTIFY_E_EVTDISABLED;
+ /* This may be used for polling till other-side is ready, so
+ * do not set failure reason. */
+ goto exit;
+ }
+#if 0
+ if (obj->cache_enabled) {
+ Cache_inv((void *)event_entry,
+ sizeof(struct notify_ducatidrv_event_entry),
+ Cache_Type_ALL, TRUE);
+ }
+#endif
+ dsb();
+ status = mutex_lock_interruptible(
+ notify_ducatidriver_state.gate_handle);
+ if (status)
+ goto exit;
+
+ if (wait_clear == true) {
+ /*Wait for completion of prev
+ event from other side*/
+ while ((event_entry->flag != NOTIFYDUCATIDRIVER_DOWN) && \
+ (status >= 0)) {
+ /* Leave critical section protection. Create a window
+ * of opportunity for other interrupts to be handled.*/
+ mutex_unlock(notify_ducatidriver_state.gate_handle);
+ i++;
+ if ((max_poll_count != (u32)-1) && \
+ (i == max_poll_count)) {
+ status = NOTIFY_E_TIMEOUT;
+ break;
+ }
+
+#if 0
+ if (obj->cache_enabled) {
+ Cache_inv((void *)event_entry,
+ sizeof(struct notify_ducatidrv_event_entry),
+ Cache_Type_ALL, TRUE);
+ }
+#endif
+ dsb();
+
+ /* Enter critical section protection. */
+ status = mutex_lock_interruptible(
+ notify_ducatidriver_state.gate_handle);
+ }
+ }
+
+ if (status >= 0) {
+ /* Set the event bit field and payload. */
+ event_entry->payload = payload;
+ event_entry->flag = NOTIFYDUCATIDRIVER_UP;
+
+#if 0
+ if (obj->cache_enabled) {
+ Cache_inv((void *)event_entry,
+ sizeof(struct notify_ducatidrv_event_entry),
+ Cache_Type_ALL, TRUE);
+ }
+#endif
+ dsb();
+
+ /* Send an interrupt with the event information to the
+ * remote processor */
+ msg = ((obj->remote_proc_id << 16) | event_id);
+ status = omap_mbox_msg_send(mbox, msg);
+
+ /* Leave critical section protection. */
+ mutex_unlock(notify_ducatidriver_state.gate_handle);
+ }
+
+exit:
+ if (status < 0) {
+ pr_err("notify_ducatidrv_sendevent failed! "
+ "status = 0x%x", status);
+ }
+ return status;
+}
+
+/* Disable all events for this Notify driver.*/
+int notify_ducatidrv_disable(struct notify_driver_object *handle)
+{
+ int status = NOTIFY_S_SUCCESS;
+ struct notify_ducatidrv_object *obj;
+ struct omap_mbox *mbox;
+
+ /* All the below parameter checking is unnecessary, but added to
+ * make sure the driver object is initialized properly */
+ if (WARN_ON(unlikely(handle == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->is_init != \
+ NOTIFY_DRIVERINITSTATUS_DONE))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
+ status = NOTIFY_E_DRIVERNOTREGISTERED;
+ goto exit;
+ }
+
+ obj = (struct notify_ducatidrv_object *)
+ handle->notify_handle->driver_handle;
+
+ mbox = (obj->remote_proc_id) ? ducati_mbox : tesla_mbox;
+ if (WARN_ON(unlikely(obj->reg_chart == NULL))) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ /* Disable the mailbox interrupt associated with ducati mailbox */
+ omap_mbox_disable_irq(mbox, IRQ_RX);
+
+exit:
+ if (status < 0) {
+ pr_err("notify_ducatidrv_disable failed! "
+ "status = 0x%x", status);
+ }
+ /*No flags to be returned. */
+ return 0;
+}
+
+/* Restore the notify_ducatidrv to the state before the last disable was
+ * called. */
+void notify_ducatidrv_enable(struct notify_driver_object *handle)
+{
+ int status = NOTIFY_S_SUCCESS;
+ struct notify_ducatidrv_object *obj;
+ struct omap_mbox *mbox;
+
+ /* All the below parameter checking is unnecessary, but added to
+ * make sure the driver object is initialized properly */
+ if (WARN_ON(unlikely(handle == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->is_init != \
+ NOTIFY_DRIVERINITSTATUS_DONE))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
+ status = NOTIFY_E_DRIVERNOTREGISTERED;
+ goto exit;
+ }
+
+ obj = (struct notify_ducatidrv_object *)
+ handle->notify_handle->driver_handle;
+
+ mbox = (obj->remote_proc_id) ? ducati_mbox : tesla_mbox;
+ if (WARN_ON(unlikely(obj->reg_chart == NULL))) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ /*Enable the receive interrupt for ducati */
+ omap_mbox_enable_irq(mbox, IRQ_RX);
+
+exit:
+ if (status < 0) {
+ pr_err("notify_ducatidrv_enable failed! "
+ "status = 0x%x", status);
+ }
+ return;
+}
+
+/* Disable a specific event for this Notify ducati driver */
+void notify_ducatidrv_disable_event(struct notify_driver_object *handle,
+ u32 event_id)
+{
+ int status = NOTIFY_S_SUCCESS;
+ struct notify_ducatidrv_object *obj;
+ VOLATILE struct notify_ducatidrv_event_entry *event_entry;
+
+ if (WARN_ON(unlikely(handle == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->is_init != \
+ NOTIFY_DRIVERINITSTATUS_DONE))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
+ status = NOTIFY_E_DRIVERNOTREGISTERED;
+ goto exit;
+ }
+
+ obj = (struct notify_ducatidrv_object *)
+ handle->notify_handle->driver_handle;
+ if (event_id > obj->num_events) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ /* Enter critical section protection. */
+ status = mutex_lock_interruptible(
+ notify_ducatidriver_state.gate_handle);
+ if (status)
+ goto exit;
+ clear_bit(event_id, (unsigned long *)
+ &(obj->self_proc_ctrl->event_enable_mask));
+ /* Leave critical section protection. */
+ mutex_unlock(notify_ducatidriver_state.gate_handle);
+#if 0
+ if (obj->cache_enabled) {
+ /* Writeback event_enable_mask */
+ Cache_wbInv((void *) obj->self_proc_ctrl,
+ sizeof(struct notify_ducatidrv_proc_ctrl),
+ Cache_Type_ALL, true);
+ }
+#endif
+
+ event_entry = EVENTENTRY(obj->self_event_chart, obj->event_entry_size,
+ event_id)
+#if 0
+ if (obj->cache_enabled) {
+ /* Writeback event entry */
+ Cache_wbInv((void *) event_entry,
+ sizeof(struct notify_ducatidrv_event_entry),
+ Cache_Type_ALL, true);
+ }
+#endif
+
+ /* Disable incoming Notify interrupts. This is done to ensure that the
+ * eventEntry->flag is read atomically with any write back to shared
+ * memory */
+ notify_ducatidrv_disable(handle);
+
+ /* Is the local notify_ducatidrv_disable_event happening between the
+ * following two notify_ducatidrv_send_event operations on the remote
+ * processor?
+ * 1. Writing notify_ducatidrv_UP to shared memory
+ * 2. Sending the interrupt across
+ * If so, we should handle this event so the other core isn't left
+ * spinning until the event is re-enabled and the next
+ * notify_ducatidrv_isr executes This race condition is very rare but we
+ * need to account for it: */
+ if (event_entry->flag == NOTIFYDUCATIDRIVER_UP) {
+ /* Acknowledge the event. No need to store the payload. The
+ * other side will not send this event again even though flag is
+ * down, because the event is now disabled. So the payload
+ * within the eventChart will not get overwritten. */
+ event_entry->flag = NOTIFYDUCATIDRIVER_DOWN;
+#if 0
+ /* Write back acknowledgement */
+ if (obj->cache_enabled) {
+ Cache_wbInv(event_entry,
+ sizeof(struct notify_ducatidrv_event_entry),
+ Cache_Type_ALL, TRUE);
+ }
+#endif
+ /* Execute the callback function. This will execute in a Task
+ * or Swi context (not Hwi!) */
+ notify_exec(obj->drv_handle->notify_handle, event_id,
+ event_entry->payload);
+ }
+
+ /* Re-enable incoming Notify interrupts */
+ notify_ducatidrv_enable(handle);
+
+exit:
+ if (status < 0) {
+ pr_err("notify_ducatidrv_disable_event failed! "
+ "status = 0x%x", status);
+ }
+ return;
+}
+
+/* Enable a specific event for this Notify ducati driver */
+void notify_ducatidrv_enable_event(struct notify_driver_object *handle,
+ u32 event_id)
+{
+ int status = 0;
+ struct notify_ducatidrv_object *obj;
+
+ if (WARN_ON(unlikely(handle == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->is_init != \
+ NOTIFY_DRIVERINITSTATUS_DONE))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
+ status = NOTIFY_E_DRIVERNOTREGISTERED;
+ goto exit;
+ }
+
+ obj = (struct notify_ducatidrv_object *)
+ handle->notify_handle->driver_handle;
+ if (event_id > obj->num_events) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ /* Enter critical section protection. */
+ status = mutex_lock_interruptible(
+ notify_ducatidriver_state.gate_handle);
+ if (status)
+ goto exit;
+ set_bit(event_id, (unsigned long *)
+ &(obj->self_proc_ctrl->event_enable_mask));
+ /* Leave critical section protection. */
+ mutex_unlock(notify_ducatidriver_state.gate_handle);
+#if 0
+ if (obj->cache_enabled) {
+ /* Writeback event_enable_mask */
+ Cache_wbInv((void *) obj->self_proc_ctrl,
+ sizeof(struct notify_ducatidrv_proc_ctrl),
+ Cache_Type_ALL, true);
+ }
+#endif
+
+exit:
+ if (status < 0) {
+ pr_err("notify_ducatidrv_enable_event failed! "
+ "status = 0x%x", status);
+ }
+ return;
+}
+
+/* Get the shared memory requirements for the notify_ducatidrv. */
+uint notify_ducatidrv_shared_mem_req(
+ const struct notify_ducatidrv_params *params)
+{
+ uint mem_req = 0;
+ u16 region_id;
+ uint region_cache_size;
+ uint min_align;
+ s32 status = NOTIFY_S_SUCCESS;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
+ &(notify_ducatidriver_state.ref_count),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0),
+ NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(params == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ /* Determine obj->cache_enabled using params->cache_enabled and
+ * sharedregion cache flag setting, if applicable. */
+ min_align = params->cache_line_size;
+ region_id = sharedregion_get_id((void *) params->shared_addr);
+ if (region_id != SHAREDREGION_INVALIDREGIONID) {
+ region_cache_size = sharedregion_get_cache_line_size(region_id);
+
+ /* Override the user cache line size setting if the region
+ * cache line size is smaller. */
+ if (region_cache_size < min_align)
+ min_align = region_cache_size;
+ }
+
+ /* Determine obj->eventEntrySize which will be used to ROUND_UP
+ * addresses */
+ mem_req = ((ROUND_UP(sizeof(struct notify_ducatidrv_proc_ctrl),
+ min_align)) * 2) + \
+ ((ROUND_UP(sizeof(struct notify_ducatidrv_event_entry),
+ min_align) * 2 * notify_state.cfg.num_events));
+
+exit:
+ if (status < 0) {
+ pr_err("notify_ducatidrv_shared_mem_req failed!"
+ " status = 0x%x", status);
+ }
+ return mem_req;
+}
+
+/* This function implements the interrupt service routine for the interrupt
+ * received from the Ducati processor. */
+static int notify_shmdrv_isr(struct notifier_block *nb, unsigned long val,
+ void *ntfy_msg)
+{
+ /* Decode the msg to identify the processor that has sent the message */
+ u32 proc_id = (u32)ntfy_msg;
+
+ /* Call the corresponding prpc_id callback */
+ notify_shmdrv_isr_callback(notify_ducatidriver_state.driver_handles
+ [proc_id][0], ntfy_msg);
+
+ return 0;
+}
+EXPORT_SYMBOL(notify_shmdrv_isr);
+
+static bool notify_shmdrv_isr_callback(void *ref_data, void *notify_msg)
+{
+ u32 payload = 0;
+ u32 i = 0;
+ VOLATILE struct notify_ducatidrv_event_entry *event_entry;
+ struct notify_ducatidrv_object *obj;
+ u32 event_id;
+
+ obj = (struct notify_ducatidrv_object *) ref_data;
+
+ dsb();
+ /* Execute the loop till no asserted event is found for one complete
+ * loop through all registered events */
+ do {
+ /* Check if the entry is a valid registered event.*/
+ event_id = obj->reg_chart[i];
+ if (event_id == (u32) -1)
+ break;
+
+ event_entry = EVENTENTRY(obj->self_event_chart,
+ obj->event_entry_size, event_id);
+#if 0
+ if (obj->cache_enabled) {
+ Cache_inv((void *)event_entry,
+ sizeof(struct notify_ducatidrv_event_entry),
+ Cache_Type_ALL, TRUE);
+ }
+#endif
+ dsb();
+
+ /* Determine the current high priority event.*/
+ /* Check if the event is set and enabled.*/
+ if (event_entry->flag == NOTIFYDUCATIDRIVER_UP &&
+ test_bit(event_id, (unsigned long *)
+ &obj->self_proc_ctrl->event_enable_mask)) {
+ payload = event_entry->payload;
+
+ /* Acknowledge the event. */
+ event_entry->flag = NOTIFYDUCATIDRIVER_DOWN;
+
+ /* Write back acknowledgement */
+#if 0
+ if (obj->cache_enabled) {
+ Cache_inv((void *)event_entry,
+ sizeof(struct notify_ducatidrv_event_entry),
+ Cache_Type_ALL, TRUE);
+ }
+#endif
+ dsb();
+
+ /* Execute the callback function */
+ notify_exec(obj->drv_handle->notify_handle, event_id,
+ payload);
+ /* reinitialize the event check counter. */
+ i = 0;
+ } else {
+ /* check for next event. */
+ i++;
+ }
+ } while ((event_id != (u32) -1) && (i < obj->num_events));
+
+ return true;
+}
diff --git a/drivers/dsp/syslink/omap_notify/drv_notify.c b/drivers/dsp/syslink/omap_notify/drv_notify.c
new file mode 100644
index 00000000000..aafe34667e7
--- /dev/null
+++ b/drivers/dsp/syslink/omap_notify/drv_notify.c
@@ -0,0 +1,1005 @@
+/*
+ * drv_notify.c
+ *
+ * Syslink support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2008-2009 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 <generated/autoconf.h>
+#include <linux/spinlock.h>
+#include <linux/semaphore.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <asm/pgtable.h>
+#include <linux/types.h>
+#include <linux/cdev.h>
+
+#include <syslink/platform_mem.h>
+#include <syslink/ipc_ioctl.h>
+#include <syslink/ipc.h>
+#include <syslink/drv_notify.h>
+#include <syslink/notify_driver.h>
+#include <syslink/notify.h>
+#include <syslink/notify_ioctl.h>
+
+
+/** ============================================================================
+ * Macros and types
+ * ============================================================================
+ */
+/* Maximum number of user supported. */
+#define MAX_PROCESSES 32
+
+/*Structure of Event callback argument passed to register fucntion*/
+struct notify_drv_event_cbck {
+ struct list_head element; /* List element header */
+ u16 proc_id; /* Processor identifier */
+ u16 line_id; /* line identifier */
+ u32 event_id; /* Event identifier */
+ notify_fn_notify_cbck func; /* Callback function for the event. */
+ void *param; /* User callback argument. */
+ u32 pid; /* Process Identifier for user process. */
+};
+
+/* Keeps the information related to Event.*/
+struct notify_drv_event_state {
+ struct list_head buf_list;
+ /* Head of received event list. */
+ u32 pid;
+ /* User process ID. */
+ u32 ref_count;
+ /*Reference count, used when multiple Notify_registerEvent are called
+ from same process space(multi threads/processes). */
+ struct semaphore *semhandle;
+ /* Semaphore for waiting on event. */
+ struct semaphore *tersemhandle;
+ /* Termination synchronization semaphore. */
+};
+
+/* NotifyDrv module state object */
+struct notify_drv_module_object {
+ bool is_setup;
+ /* Indicates whether the module has been already setup */
+ bool open_ref_count;
+ /* Open reference count. */
+ struct mutex *gate_handle;
+ /* Handle of gate to be used for local thread safety */
+ struct list_head event_cbck_list;
+ /* List containg callback arguments for all registered handlers from
+ * user mode. */
+ struct list_head single_event_cbck_list;
+ /* List containg callback arguments for all registered handlers from
+ user mode for 'single' registrations. */
+ struct notify_drv_event_state event_state[MAX_PROCESSES];
+ /* List for all user processes registered. */
+};
+
+static struct notify_drv_module_object notifydrv_state = {
+ .is_setup = false,
+ .open_ref_count = 0,
+ .gate_handle = NULL
+ /*.event_cbck_list = NULL,
+ .single_event_cbck_list = NULL*/
+};
+
+
+/* Attach a process to notify user support framework. */
+static int notify_drv_attach(u32 pid);
+
+/* Detach a process from notify user support framework. */
+static int notify_drv_detach(u32 pid, bool force);
+
+/* This function implements the callback registered with IPS. Here to pass
+ * event no. back to user function (so that it can do another level of
+ * demultiplexing of callbacks) */
+static void _notify_drv_callback(u16 proc_id, u16 line_id, u32 event_id,
+ uint *arg, u32 payload);
+
+/* This function adds a data to a registered process. */
+static int _notify_drv_add_buf_by_pid(u16 proc_id, u16 line_id, u32 pid,
+ u32 event_id, u32 data, notify_fn_notify_cbck cb_fxn,
+ void *param);
+
+
+static struct resource_info *find_notify_drv_resource(
+ struct ipc_process_context *pr_ctxt,
+ unsigned int cmd,
+ void *args)
+{
+ struct resource_info *info = NULL;
+ bool found = false;
+
+ spin_lock(&pr_ctxt->res_lock);
+
+ list_for_each_entry(info, &pr_ctxt->resources, res) {
+ if (info->cmd == cmd) {
+ switch (cmd) {
+ case CMD_NOTIFY_DESTROY:
+ found = true;
+ break;
+ case CMD_NOTIFY_THREADDETACH:
+ if ((u32)args == *(u32 *)info->data)
+ found = true;
+ break;
+ }
+ }
+ if (found == true)
+ break;
+ }
+
+ spin_unlock(&pr_ctxt->res_lock);
+
+ if (found == false)
+ info = NULL;
+
+ return info;
+}
+
+/*
+ * read data from the driver
+ */
+int notify_drv_read(struct file *filp, char __user *dst, size_t size,
+ loff_t *offset)
+{
+
+ bool flag = false;
+ struct notify_drv_event_packet *u_buf = NULL;
+ int ret_val = 0;
+ u32 i;
+ struct list_head *elem;
+ struct notify_drv_event_packet t_buf;
+
+ if (WARN_ON(notifydrv_state.is_setup == false)) {
+ ret_val = -EFAULT;
+ goto func_end;
+ }
+
+ ret_val = copy_from_user((void *)&t_buf,
+ (void __user *)dst,
+ sizeof(struct notify_drv_event_packet));
+ if (WARN_ON(ret_val != 0))
+ ret_val = -EFAULT;
+
+ for (i = 0; i < MAX_PROCESSES; i++) {
+ if (notifydrv_state.event_state[i].pid == t_buf.pid) {
+ flag = true;
+ break;
+ }
+ }
+ if (flag == false) {
+ ret_val = -EFAULT;
+ goto func_end;
+ }
+
+ /* Wait for the event */
+ ret_val = down_interruptible(notifydrv_state.event_state[i].semhandle);
+ if (ret_val < 0) {
+ ret_val = -ERESTARTSYS;
+ goto func_end;
+ }
+ WARN_ON(mutex_lock_interruptible(notifydrv_state.gate_handle));
+ elem = ((struct list_head *)
+ &(notifydrv_state.event_state[i].buf_list))->next;
+ u_buf = container_of(elem, struct notify_drv_event_packet, element);
+ list_del(elem);
+ mutex_unlock(notifydrv_state.gate_handle);
+ if (u_buf == NULL) {
+ ret_val = -EFAULT;
+ goto func_end;
+ }
+ ret_val = copy_to_user((void __user *)dst, u_buf,
+ sizeof(struct notify_drv_event_packet));
+ if (WARN_ON(ret_val != 0))
+ ret_val = -EFAULT;
+ ret_val = sizeof(struct notify_drv_event_packet);
+
+ if (u_buf->is_exit == true)
+ up(notifydrv_state.event_state[i].tersemhandle);
+
+ kfree(u_buf);
+ u_buf = NULL;
+
+func_end:
+ return ret_val;
+}
+
+int notify_drv_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ vma->vm_page_prot = pgprot_dmacoherent(vma->vm_page_prot);
+
+ if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot))
+ return -EAGAIN;
+ return 0;
+}
+
+/* ioctl function for of Linux Notify driver. */
+int notify_drv_ioctl(struct inode *inode, struct file *filp, u32 cmd,
+ unsigned long args, bool user)
+{
+ int status = NOTIFY_S_SUCCESS;
+ int os_status = 0;
+ unsigned long size;
+ struct notify_cmd_args *cmd_args = (struct notify_cmd_args *)args;
+ struct notify_cmd_args common_args;
+ struct ipc_process_context *pr_ctxt =
+ (struct ipc_process_context *)filp->private_data;
+
+#ifdef CONFIG_SYSLINK_RECOVERY
+ if (ipc_recovering() && user && cmd != CMD_NOTIFY_THREADDETACH)
+ return -EIO;
+#endif
+
+ switch (cmd) {
+ case CMD_NOTIFY_GETCONFIG:
+ {
+ struct notify_cmd_args_get_config *src_args =
+ (struct notify_cmd_args_get_config *)args;
+ struct notify_config cfg;
+
+ notify_get_config(&cfg);
+ size = copy_to_user((void __user *) (src_args->cfg),
+ (const void *) &cfg, sizeof(struct notify_config));
+ if (WARN_ON(size != 0))
+ os_status = -EFAULT;
+ }
+ break;
+
+ case CMD_NOTIFY_SETUP:
+ {
+ struct notify_cmd_args_setup *src_args =
+ (struct notify_cmd_args_setup *) args;
+ struct notify_config cfg;
+
+ size = copy_from_user((void *) &cfg,
+ (const void __user *) (src_args->cfg),
+ sizeof(struct notify_config));
+ if (WARN_ON(size != 0)) {
+ os_status = -EFAULT;
+ goto func_end;
+ }
+ status = notify_setup(&cfg);
+ if (status >= 0)
+ add_pr_res(pr_ctxt, CMD_NOTIFY_DESTROY, NULL);
+ }
+ break;
+
+ case CMD_NOTIFY_DESTROY:
+ {
+ struct resource_info *info = NULL;
+ /* copy_from_user is not needed for Notify_getConfig, since the
+ * user's config is not used.
+ */
+ info = find_notify_drv_resource(pr_ctxt,
+ CMD_NOTIFY_DESTROY,
+ NULL);
+ status = notify_destroy();
+ remove_pr_res(pr_ctxt, info);
+ }
+ break;
+
+ case CMD_NOTIFY_REGISTEREVENTSINGLE:
+ {
+ struct notify_cmd_args_register_event src_args;
+ struct notify_drv_event_cbck *cbck = NULL;
+
+ /* Copy the full args from user-side. */
+ size = copy_from_user((void *) &src_args,
+ (const void __user *) (args),
+ sizeof(struct notify_cmd_args_register_event));
+ if (WARN_ON(size != 0)) {
+ os_status = -EFAULT;
+ goto func_end;
+ }
+
+ cbck = kmalloc(sizeof(struct notify_drv_event_cbck),
+ GFP_ATOMIC);
+ WARN_ON(cbck == NULL);
+ cbck->proc_id = src_args.proc_id;
+ cbck->line_id = src_args.line_id;
+ cbck->event_id = src_args.event_id;
+ cbck->pid = src_args.pid;
+ cbck->func = src_args.fn_notify_cbck;
+ cbck->param = src_args.cbck_arg;
+ status = notify_register_event_single(src_args.proc_id,
+ src_args.line_id, src_args.event_id,
+ _notify_drv_callback, (void *)cbck);
+ if (status < 0) {
+ /* This does not impact return status of this function,
+ * so retval comment is not used. */
+ kfree(cbck);
+ } else {
+ WARN_ON(mutex_lock_interruptible
+ (notifydrv_state.gate_handle));
+ INIT_LIST_HEAD((struct list_head *)&(cbck->element));
+ list_add_tail(&(cbck->element),
+ &(notifydrv_state.single_event_cbck_list));
+ mutex_unlock(notifydrv_state.gate_handle);
+ }
+ }
+ break;
+
+ case CMD_NOTIFY_REGISTEREVENT:
+ {
+ struct notify_cmd_args_register_event src_args;
+ struct notify_drv_event_cbck *cbck = NULL;
+
+ /* Copy the full args from user-side. */
+ size = copy_from_user((void *) &src_args,
+ (const void __user *) (args),
+ sizeof(struct notify_cmd_args_register_event));
+ if (WARN_ON(size != 0)) {
+ os_status = -EFAULT;
+ goto func_end;
+ }
+
+ cbck = kmalloc(sizeof(struct notify_drv_event_cbck),
+ GFP_ATOMIC);
+ WARN_ON(cbck == NULL);
+ cbck->proc_id = src_args.proc_id;
+ cbck->line_id = src_args.line_id;
+ cbck->event_id = src_args.event_id;
+ cbck->func = src_args.fn_notify_cbck;
+ cbck->param = src_args.cbck_arg;
+ cbck->pid = src_args.pid;
+ status = notify_register_event(src_args.proc_id,
+ src_args.line_id, src_args.event_id,
+ _notify_drv_callback, (void *)cbck);
+ if (status < 0) {
+ /* This does not impact return status of this function,
+ * so retval comment is not used. */
+ kfree(cbck);
+ } else {
+ WARN_ON(mutex_lock_interruptible
+ (notifydrv_state.gate_handle));
+ INIT_LIST_HEAD((struct list_head *)&(cbck->element));
+ list_add_tail(&(cbck->element),
+ &(notifydrv_state.event_cbck_list));
+ mutex_unlock(notifydrv_state.gate_handle);
+ }
+ }
+ break;
+
+ case CMD_NOTIFY_UNREGISTEREVENTSINGLE:
+ {
+ bool found = false;
+ u32 pid;
+ struct notify_drv_event_cbck *cbck = NULL;
+ struct list_head *entry = NULL;
+ struct notify_cmd_args_unregister_event src_args;
+
+ /* Copy the full args from user-side. */
+ size = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct notify_cmd_args_unregister_event));
+ if (WARN_ON(size != 0)) {
+ os_status = -EFAULT;
+ goto func_end;
+ }
+
+ WARN_ON(mutex_lock_interruptible(notifydrv_state.gate_handle));
+ pid = src_args.pid;
+ list_for_each(entry, (struct list_head *)
+ &(notifydrv_state.single_event_cbck_list)) {
+ cbck = (struct notify_drv_event_cbck *)(entry);
+ if ((cbck->proc_id == src_args.proc_id) &&
+ (cbck->line_id == src_args.line_id) &&
+ (cbck->event_id == src_args.event_id) &&
+ (cbck->pid == pid)) {
+ found = true;
+ break;
+ }
+ }
+ mutex_unlock(notifydrv_state.gate_handle);
+ if (found == false) {
+ status = NOTIFY_E_NOTFOUND;
+ goto func_end;
+ }
+ status = notify_unregister_event_single(src_args.proc_id,
+ src_args.line_id, src_args.event_id);
+ /* This check is needed at run-time also to propagate the
+ * status to user-side. This must not be optimized out. */
+ if (status >= 0) {
+ WARN_ON(mutex_lock_interruptible
+ (notifydrv_state.gate_handle));
+ list_del((struct list_head *)cbck);
+ mutex_unlock(notifydrv_state.gate_handle);
+ kfree(cbck);
+ }
+ }
+ break;
+
+ case CMD_NOTIFY_UNREGISTEREVENT:
+ {
+ bool found = false;
+ u32 pid;
+ struct notify_drv_event_cbck *cbck = NULL;
+ struct list_head *entry = NULL;
+ struct notify_cmd_args_unregister_event src_args;
+
+ /* Copy the full args from user-side. */
+ size = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct notify_cmd_args_unregister_event));
+ if (WARN_ON(size != 0)) {
+ os_status = -EFAULT;
+ goto func_end;
+ }
+
+ WARN_ON(mutex_lock_interruptible(notifydrv_state.gate_handle));
+ pid = src_args.pid;
+ list_for_each(entry, (struct list_head *)
+ &(notifydrv_state.event_cbck_list)) {
+ cbck = (struct notify_drv_event_cbck *)(entry);
+ if ((cbck->func == src_args.fn_notify_cbck) &&
+ (cbck->param == src_args.cbck_arg) &&
+ (cbck->proc_id == src_args.proc_id) &&
+ (cbck->line_id == src_args.line_id) &&
+ (cbck->event_id == src_args.event_id) &&
+ (cbck->pid == pid)) {
+ found = true;
+ break;
+ }
+ }
+ mutex_unlock(notifydrv_state.gate_handle);
+ if (found == false) {
+ status = NOTIFY_E_NOTFOUND;
+ goto func_end;
+ }
+ status = notify_unregister_event(src_args.proc_id,
+ src_args.line_id, src_args.event_id,
+ _notify_drv_callback, (void *) cbck);
+ /* This check is needed at run-time also to propagate the
+ * status to user-side. This must not be optimized out. */
+ if (status >= 0) {
+ WARN_ON(mutex_lock_interruptible
+ (notifydrv_state.gate_handle));
+ list_del((struct list_head *)cbck);
+ mutex_unlock(notifydrv_state.gate_handle);
+ kfree(cbck);
+ }
+ }
+ break;
+
+ case CMD_NOTIFY_SENDEVENT:
+ {
+ struct notify_cmd_args_send_event src_args;
+
+ /* Copy the full args from user-side. */
+ size = copy_from_user((void *) &src_args,
+ (const void __user *) (args),
+ sizeof(struct notify_cmd_args_send_event));
+ if (WARN_ON(size != 0)) {
+ os_status = -EFAULT;
+ goto func_end;
+ }
+ status = notify_send_event(src_args.proc_id, src_args.line_id,
+ src_args.event_id, src_args.payload,
+ src_args.wait_clear);
+ }
+ break;
+
+ case CMD_NOTIFY_DISABLE:
+ {
+ struct notify_cmd_args_disable src_args;
+
+ /* Copy the full args from user-side. */
+ size = copy_from_user((void *) &src_args,
+ (const void __user *) (args),
+ sizeof(struct notify_cmd_args_disable));
+ if (WARN_ON(size != 0)) {
+ os_status = -EFAULT;
+ goto func_end;
+ }
+ src_args.flags = notify_disable(src_args.proc_id,
+ src_args.line_id);
+
+ /* Copy the full args to user-side */
+ size = copy_to_user((void __user *) (args),
+ (const void *) &src_args,
+ sizeof(struct notify_cmd_args_disable));
+ /* This check is needed at run-time also since it depends on
+ * run environment. It must not be optimized out. */
+ if (WARN_ON(size != 0))
+ os_status = -EFAULT;
+ }
+ break;
+
+ case CMD_NOTIFY_RESTORE:
+ {
+ struct notify_cmd_args_restore src_args;
+
+ /* Copy the full args from user-side. */
+ size = copy_from_user((void *) &src_args,
+ (const void __user *)(args),
+ sizeof(struct notify_cmd_args_restore));
+ if (WARN_ON(size != 0)) {
+ os_status = -EFAULT;
+ goto func_end;
+ }
+ notify_restore(src_args.proc_id, src_args.line_id,
+ src_args.key);
+ }
+ break;
+
+ case CMD_NOTIFY_DISABLEEVENT:
+ {
+ struct notify_cmd_args_disable_event src_args;
+
+ /* Copy the full args from user-side. */
+ size = copy_from_user((void *) &src_args,
+ (const void __user *)(args),
+ sizeof(struct notify_cmd_args_disable_event));
+ if (WARN_ON(size != 0)) {
+ os_status = -EFAULT;
+ goto func_end;
+ }
+ notify_disable_event(src_args.proc_id, src_args.line_id,
+ src_args.event_id);
+ }
+ break;
+
+ case CMD_NOTIFY_ENABLEEVENT:
+ {
+ struct notify_cmd_args_enable_event src_args;
+
+ /* Copy the full args from user-side. */
+ size = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct notify_cmd_args_enable_event));
+ if (WARN_ON(size != 0)) {
+ os_status = -EFAULT;
+ goto func_end;
+ }
+ notify_enable_event(src_args.proc_id, src_args.line_id,
+ src_args.event_id);
+ }
+ break;
+
+ case CMD_NOTIFY_THREADATTACH:
+ {
+ u32 pid = *((u32 *)args);
+ status = notify_drv_attach(pid);
+ if (status < 0)
+ pr_err("NOTIFY_ATTACH FAILED\n");
+ else {
+ u32 *data = kmalloc(sizeof(u32), GFP_KERNEL);
+ if (WARN_ON(!data)) {
+ notify_drv_detach(pid, true);
+ os_status = -ENOMEM;
+ goto func_end;
+ }
+ *data = pid;
+ add_pr_res(pr_ctxt, CMD_NOTIFY_THREADDETACH,
+ (void *)data);
+ }
+ }
+ break;
+
+ case CMD_NOTIFY_THREADDETACH:
+ {
+ struct resource_info *info = NULL;
+ u32 pid = *((u32 *)args);
+ info = find_notify_drv_resource(pr_ctxt,
+ CMD_NOTIFY_THREADDETACH,
+ (void *)pid);
+ if (user == true)
+ status = notify_drv_detach(pid, false);
+ else
+ status = notify_drv_detach(pid, true);
+ if (status < 0)
+ pr_err("NOTIFY_DETACH FAILED\n");
+ else
+ remove_pr_res(pr_ctxt, info);
+ }
+ break;
+
+ case CMD_NOTIFY_ATTACH:
+ {
+ struct notify_cmd_args_attach src_args;
+ void *knl_shared_addr;
+
+ size = copy_from_user((void *) &src_args,
+ (const void __user *)(args),
+ sizeof(struct notify_cmd_args_attach));
+ if (size != 0) {
+ os_status = -EFAULT;
+ goto func_end;
+ }
+
+ /* knl_shared_addr = Memory_translate(src_args.shared_addr,
+ Memory_XltFlags_Phys2Virt); */
+ knl_shared_addr = platform_mem_translate(
+ (void *)src_args.shared_addr,
+ PLATFORM_MEM_XLT_FLAGS_PHYS2VIRT);
+ status = notify_attach(src_args.proc_id, knl_shared_addr);
+ }
+ break;
+
+ case CMD_NOTIFY_DETACH:
+ {
+ struct notify_cmd_args_detach src_args;
+
+ size = copy_from_user((void *) &src_args,
+ (const void __user *)(args),
+ sizeof(struct notify_cmd_args_detach));
+ if (size != 0) {
+ os_status = -EFAULT;
+ goto func_end;
+ }
+
+ status = notify_detach(src_args.proc_id);
+ }
+ break;
+
+ case CMD_NOTIFY_SHAREDMEMREQ:
+ {
+ struct notify_cmd_args_shared_mem_req src_args;
+ void *knl_shared_addr;
+
+ size = copy_from_user((void *) &src_args,
+ (const void __user *)(args),
+ sizeof(struct notify_cmd_args_shared_mem_req));
+ if (size != 0) {
+ os_status = -EFAULT;
+ goto func_end;
+ }
+
+ /* knl_shared_addr = Memory_translate(src_args.shared_addr,
+ Memory_XltFlags_Phys2Virt); */
+ knl_shared_addr = platform_mem_translate(
+ (void *)src_args.shared_addr,
+ PLATFORM_MEM_XLT_FLAGS_PHYS2VIRT);
+ status = notify_shared_mem_req(src_args.proc_id,
+ knl_shared_addr);
+ }
+ break;
+
+ case CMD_NOTIFY_ISREGISTERED:
+ {
+ struct notify_cmd_args_is_registered src_args;
+
+ size = copy_from_user((void *) &src_args,
+ (const void __user *)(args),
+ sizeof(struct notify_cmd_args_is_registered));
+ if (size != 0) {
+ os_status = -EFAULT;
+ goto func_end;
+ }
+
+ src_args.is_registered = notify_is_registered(src_args.proc_id,
+ src_args.line_id);
+ size = copy_to_user((void __user *) (args),
+ (const void *)&src_args,
+ sizeof(struct notify_cmd_args_is_registered));
+ if (size != 0) {
+ os_status = -EFAULT;
+ goto func_end;
+ }
+ }
+ break;
+
+ default:
+ {
+ /* This does not impact return status of this function,so retval
+ * comment is not used. */
+ status = NOTIFY_E_INVALIDARG;
+ pr_err("not valid command\n");
+ }
+ break;
+ }
+
+func_end:
+ /* Set the status and copy the common args to user-side. */
+ common_args.api_status = status;
+ if (user == true) {
+ size = copy_to_user((void __user *) cmd_args,
+ (const void *) &common_args,
+ sizeof(struct notify_cmd_args));
+ if (size)
+ os_status = -EFAULT;
+ }
+ return os_status;
+}
+
+/* This function implements the callback registered with IPS. Here
+ * to pass event no. back to user function(so that it can do another
+ * level of demultiplexing of callbacks) */
+static void _notify_drv_callback(u16 proc_id, u16 line_id, u32 event_id,
+ uint *arg, u32 payload)
+{
+ struct notify_drv_event_cbck *cbck;
+ int status = 0;
+
+ if (WARN_ON(notifydrv_state.is_setup == false)) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ if (WARN_ON(arg == NULL)) {
+ status = -EINVAL;
+ goto func_end;
+ }
+
+ cbck = (struct notify_drv_event_cbck *)arg;
+ status = _notify_drv_add_buf_by_pid(proc_id, line_id, cbck->pid,
+ event_id, payload, cbck->func, cbck->param);
+
+func_end:
+ if (status < 0)
+ pr_err("_notify_drv_callback failed! status = 0x%x", status);
+ return;
+}
+
+/* This function adds a data to a registered process. */
+static int _notify_drv_add_buf_by_pid(u16 proc_id, u16 line_id, u32 pid,
+ u32 event_id, u32 data,
+ notify_fn_notify_cbck cb_fxn,
+ void *param)
+{
+ s32 status = 0;
+ bool flag = false;
+ bool is_exit = false;
+ struct notify_drv_event_packet *u_buf = NULL;
+ u32 i;
+
+ WARN_ON(mutex_lock_interruptible(notifydrv_state.gate_handle));
+ for (i = 0; (i < MAX_PROCESSES) && (flag != true); i++) {
+ if (notifydrv_state.event_state[i].pid == pid) {
+ flag = true;
+ break;
+ }
+ }
+ mutex_unlock(notifydrv_state.gate_handle);
+
+ if (WARN_ON(flag == false)) {
+ status = -EFAULT;
+ goto func_end;
+ }
+
+ u_buf = kmalloc(sizeof(struct notify_drv_event_packet), GFP_ATOMIC);
+ if (u_buf == NULL) {
+ status = -ENOMEM;
+ goto func_end;
+ }
+
+ INIT_LIST_HEAD((struct list_head *)&u_buf->element);
+ u_buf->proc_id = proc_id;
+ u_buf->line_id = line_id;
+ u_buf->data = data;
+ u_buf->event_id = event_id;
+ u_buf->func = cb_fxn;
+ u_buf->param = param;
+ u_buf->is_exit = false;
+ if (u_buf->event_id == (u32) -1) {
+ u_buf->is_exit = true;
+ is_exit = true;
+ }
+ WARN_ON(mutex_lock_interruptible(notifydrv_state.gate_handle));
+ list_add_tail((struct list_head *)&(u_buf->element),
+ (struct list_head *)&(notifydrv_state.event_state[i].buf_list));
+ mutex_unlock(notifydrv_state.gate_handle);
+ up(notifydrv_state.event_state[i].semhandle);
+
+ /* Termination packet */
+ if (is_exit == true) {
+ if (down_interruptible(
+ notifydrv_state.event_state[i].tersemhandle))
+ status = NOTIFY_E_OSFAILURE;
+ }
+
+func_end:
+ if (status < 0) {
+ pr_err("_notify_drv_add_buf_by_pid failed! "
+ "status = 0x%x", status);
+ }
+ return status;
+}
+
+/* Module setup function.*/
+void _notify_drv_setup(void)
+{
+ int i;
+
+ INIT_LIST_HEAD((struct list_head *)&(notifydrv_state.event_cbck_list));
+ INIT_LIST_HEAD(
+ (struct list_head *)&(notifydrv_state.single_event_cbck_list));
+ notifydrv_state.gate_handle = kmalloc(sizeof(struct mutex), GFP_KERNEL);
+ mutex_init(notifydrv_state.gate_handle);
+ for (i = 0; i < MAX_PROCESSES; i++) {
+ notifydrv_state.event_state[i].pid = -1;
+ notifydrv_state.event_state[i].ref_count = 0;
+ INIT_LIST_HEAD((struct list_head *)
+ &(notifydrv_state.event_state[i].buf_list));
+ }
+ notifydrv_state.is_setup = true;
+}
+
+/* Module destroy function.*/
+void _notify_drv_destroy(void)
+{
+ int i;
+ struct notify_drv_event_packet *packet;
+ struct list_head *entry, *n;
+ struct notify_drv_event_cbck *cbck;
+
+ for (i = 0; i < MAX_PROCESSES; i++) {
+ notifydrv_state.event_state[i].pid = -1;
+ notifydrv_state.event_state[i].ref_count = 0;
+ /* Free event packets for any received but unprocessed events.*/
+ list_for_each_safe(entry, n, (struct list_head *)
+ &(notifydrv_state.event_state[i].buf_list)) {
+ packet = (struct notify_drv_event_packet *)entry;
+ kfree(packet);
+ }
+ INIT_LIST_HEAD(&notifydrv_state.event_state[i].buf_list);
+ }
+
+ /* Clear any event registrations that were not unregistered. */
+ list_for_each_safe(entry, n, (struct list_head *)
+ &(notifydrv_state.event_cbck_list)) {
+ cbck = (struct notify_drv_event_cbck *)(entry);
+ kfree(cbck);
+ }
+ INIT_LIST_HEAD(&notifydrv_state.event_cbck_list);
+
+ /* Clear any event registrations that were not unregistered from single
+ * list. */
+ list_for_each_safe(entry, n,
+ (struct list_head *)&(notifydrv_state.single_event_cbck_list)) {
+ cbck = (struct notify_drv_event_cbck *)(entry);
+ kfree(cbck);
+ }
+ INIT_LIST_HEAD(&notifydrv_state.single_event_cbck_list);
+
+ mutex_destroy(notifydrv_state.gate_handle);
+ kfree(notifydrv_state.gate_handle);
+ notifydrv_state.is_setup = false;
+ return;
+}
+
+/* Attach a process to notify user support framework. */
+static int notify_drv_attach(u32 pid)
+{
+ bool flag = false;
+ bool is_init = false;
+ u32 i;
+ struct semaphore *sem_handle = NULL;
+ struct semaphore *ter_sem_handle = NULL;
+ int ret_val = 0;
+
+ if (WARN_ON(notifydrv_state.is_setup == false)) {
+ ret_val = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ WARN_ON(mutex_lock_interruptible(notifydrv_state.gate_handle));
+ for (i = 0; (i < MAX_PROCESSES); i++) {
+ if (notifydrv_state.event_state[i].pid == pid) {
+ notifydrv_state.event_state[i].ref_count++;
+ is_init = true;
+ break;
+ }
+ }
+ if (is_init == true) {
+ mutex_unlock(notifydrv_state.gate_handle);
+ return 0;
+ }
+
+ sem_handle = kmalloc(sizeof(struct semaphore), GFP_ATOMIC);
+ ter_sem_handle = kmalloc(sizeof(struct semaphore), GFP_ATOMIC);
+ if (sem_handle == NULL || ter_sem_handle == NULL) {
+ ret_val = -ENOMEM;
+ goto sem_fail;
+ }
+ sema_init(sem_handle, 0);
+ /* Create the termination semaphore */
+ sema_init(ter_sem_handle, 0);
+
+ /* Search for an available slot for user process. */
+ for (i = 0; i < MAX_PROCESSES; i++) {
+ if (notifydrv_state.event_state[i].pid == -1) {
+ notifydrv_state.event_state[i].semhandle = \
+ sem_handle;
+ notifydrv_state.event_state[i].tersemhandle = \
+ ter_sem_handle;
+ notifydrv_state.event_state[i].pid = pid;
+ notifydrv_state.event_state[i].ref_count = 1;
+ INIT_LIST_HEAD(&(notifydrv_state.event_state[i].
+ buf_list));
+ flag = true;
+ break;
+ }
+ }
+ mutex_unlock(notifydrv_state.gate_handle);
+
+ if (WARN_ON(flag != true)) {
+ /* Max users have registered. No more clients
+ * can be supported */
+ ret_val = NOTIFY_E_RESOURCE;
+ goto sem_fail;
+ }
+
+ return 0;
+
+sem_fail:
+ kfree(ter_sem_handle);
+ kfree(sem_handle);
+exit:
+ return ret_val;
+}
+
+
+/* Detach a process from notify user support framework. */
+static int notify_drv_detach(u32 pid, bool force)
+{
+ s32 status = NOTIFY_S_SUCCESS;
+ bool flag = false;
+ u32 i;
+ struct semaphore *sem_handle = NULL;
+ struct semaphore *ter_sem_handle = NULL;
+
+ if (WARN_ON(notifydrv_state.is_setup == false)) {
+ status = NOTIFY_E_FAIL;
+ goto func_end;
+ }
+
+ /* Send termination packet only if this is not a forced detach */
+ if (force == false) {
+ /* Send the termination packet to notify thread */
+ status = _notify_drv_add_buf_by_pid(0, 0, pid, (u32)-1, (u32)0,
+ NULL, NULL);
+ }
+
+ WARN_ON(mutex_lock_interruptible(notifydrv_state.gate_handle));
+ for (i = 0; i < MAX_PROCESSES; i++) {
+ if (notifydrv_state.event_state[i].pid == pid) {
+ if (notifydrv_state.event_state[i].ref_count == 1) {
+ /* Last client being unregistered for this
+ * process*/
+ notifydrv_state.event_state[i].pid = -1;
+ notifydrv_state.event_state[i].ref_count = 0;
+ sem_handle =
+ notifydrv_state.event_state[i].semhandle;
+ ter_sem_handle =
+ notifydrv_state.event_state[i].tersemhandle;
+ INIT_LIST_HEAD((struct list_head *)
+ &(notifydrv_state.event_state[i].buf_list));
+ notifydrv_state.event_state[i].semhandle =
+ NULL;
+ notifydrv_state.event_state[i].tersemhandle =
+ NULL;
+ flag = true;
+ break;
+ } else
+ notifydrv_state.event_state[i].ref_count--;
+ }
+ }
+ mutex_unlock(notifydrv_state.gate_handle);
+
+ if ((flag == false) && (i == MAX_PROCESSES)) {
+ /* The specified user process was not found registered with
+ * Notify Driver module. */
+ status = NOTIFY_E_NOTFOUND;
+ } else {
+ kfree(sem_handle);
+ kfree(ter_sem_handle);
+ }
+
+func_end:
+ return status;
+}
diff --git a/drivers/dsp/syslink/omap_notify/notify.c b/drivers/dsp/syslink/omap_notify/notify.c
new file mode 100644
index 00000000000..6d4614ccad2
--- /dev/null
+++ b/drivers/dsp/syslink/omap_notify/notify.c
@@ -0,0 +1,1094 @@
+/*
+ * notify.c
+ *
+ * Syslink driver support for OMAP Processors.
+ *
+ * Copyright (C) 2008-2009 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 <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <asm/pgtable.h>
+
+#include "../ipu_pm/ipu_pm.h"
+
+#include <syslink/atomic_linux.h>
+#include <syslink/multiproc.h>
+#include <syslink/notify.h>
+#include <syslink/_notify.h>
+#include <syslink/notifydefs.h>
+#include <syslink/notify_driver.h>
+#include <syslink/notify_setup_proxy.h>
+
+struct notify_event_listener {
+ struct list_head element;
+ struct notify_event_callback callback;
+};
+
+/* Function registered with notify_exec when multiple registrations are present
+ * for the events. */
+static void _notify_exec_many(u16 proc_id, u16 line_id, u32 event_id, uint *arg,
+ u32 payload);
+
+struct notify_module_object notify_state = {
+ .def_cfg.num_events = 32u,
+ .def_cfg.send_event_poll_count = -1u,
+ .def_cfg.num_lines = 1u,
+ .def_cfg.reserved_events = 5u,
+ .gate_handle = NULL,
+ .local_notify_handle = NULL
+};
+
+/* Get the default configuration for the Notify module. */
+void notify_get_config(struct notify_config *cfg)
+{
+ s32 retval = 0;
+
+ if (WARN_ON(unlikely(cfg == NULL))) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true)
+ memcpy(cfg, &notify_state.def_cfg,
+ sizeof(struct notify_config));
+ else
+ memcpy(cfg, &notify_state.cfg, sizeof(struct notify_config));
+
+exit:
+ if (retval < 0)
+ pr_err("notify_get_config failed! status = 0x%x", retval);
+ return;
+}
+EXPORT_SYMBOL(notify_get_config);
+
+/* This function sets up the Notify module. This function must be called
+ * before any other instance-level APIs can be invoked. */
+int notify_setup(struct notify_config *cfg)
+{
+ int status = NOTIFY_S_SUCCESS;
+ struct notify_config tmp_cfg;
+
+ atomic_cmpmask_and_set(&notify_state.ref_count,
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(0));
+ if (atomic_inc_return(&notify_state.ref_count)
+ != NOTIFY_MAKE_MAGICSTAMP(1u)) {
+ return NOTIFY_S_ALREADYSETUP;
+ }
+
+ if (cfg == NULL) {
+ notify_get_config(&tmp_cfg);
+ cfg = &tmp_cfg;
+ }
+
+ if (cfg->num_events > NOTIFY_MAXEVENTS) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (cfg->num_lines > NOTIFY_MAX_INTLINES) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (cfg->reserved_events > cfg->num_events) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ notify_state.gate_handle = kmalloc(sizeof(struct mutex), GFP_ATOMIC);
+ if (notify_state.gate_handle == NULL) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+ /*User has not provided any gate handle,
+ so create a default handle.*/
+ mutex_init(notify_state.gate_handle);
+
+ memcpy(&notify_state.cfg, cfg, sizeof(struct notify_config));
+ notify_state.local_enable_mask = -1u;
+ notify_state.start_complete = false;
+ memset(&notify_state.drivers, 0, (sizeof(struct notify_driver_object) *
+ NOTIFY_MAX_DRIVERS * NOTIFY_MAX_INTLINES));
+
+ /* tbd: Should return Notify_Handle */
+ notify_state.local_notify_handle = notify_create(NULL, multiproc_self(),
+ 0, NULL);
+ if (notify_state.local_notify_handle == NULL) {
+ status = NOTIFY_E_FAIL;
+ goto local_notify_fail;
+ }
+ return 0;
+
+local_notify_fail:
+ kfree(notify_state.gate_handle);
+exit:
+ atomic_set(&notify_state.ref_count, NOTIFY_MAKE_MAGICSTAMP(0));
+ pr_err("notify_setup failed! status = 0x%x", status);
+ return status;
+}
+EXPORT_SYMBOL(notify_setup);
+
+/* Once this function is called, other Notify module APIs,
+ * except for the Notify_getConfig API cannot be called anymore. */
+int notify_destroy(void)
+{
+ int i;
+ int j;
+ int status = NOTIFY_S_SUCCESS;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (!(atomic_dec_return(&notify_state.ref_count)
+ == NOTIFY_MAKE_MAGICSTAMP(0)))
+ return NOTIFY_S_ALREADYSETUP;
+
+ /* Temporarily increment refCount here. */
+ atomic_set(&notify_state.ref_count, NOTIFY_MAKE_MAGICSTAMP(1));
+ if (notify_state.local_notify_handle != NULL)
+ status = notify_delete(&notify_state.local_notify_handle);
+ atomic_set(&notify_state.ref_count, NOTIFY_MAKE_MAGICSTAMP(0));
+
+ /* Check if any Notify driver instances have
+ * not been deleted so far. If not, assert. */
+ for (i = 0; i < NOTIFY_MAX_DRIVERS; i++)
+ for (j = 0; j < NOTIFY_MAX_INTLINES; j++)
+ WARN_ON(notify_state.drivers[i][j].is_init != false);
+
+ kfree(notify_state.gate_handle);
+
+exit:
+ if (status < 0)
+ pr_err("notify_destroy failed! status = 0x%x", status);
+ return status;
+}
+EXPORT_SYMBOL(notify_destroy);
+
+/* Function to create an instance of Notify driver */
+struct notify_object *notify_create(void *driver_handle, u16 remote_proc_id,
+ u16 line_id, const struct notify_params *params)
+{
+ int status = NOTIFY_S_SUCCESS;
+ struct notify_object *obj = NULL;
+ uint i;
+
+ /* driver_handle can be NULL for local create */
+ /* params can be NULL */
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(remote_proc_id >= \
+ multiproc_get_num_processors()))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(line_id >= NOTIFY_MAX_INTLINES))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ /* Allocate memory for the Notify object. */
+ obj = kzalloc(sizeof(struct notify_object), GFP_KERNEL);
+ if (obj == NULL) {
+ status = NOTIFY_E_MEMORY;
+ goto exit;
+ }
+
+ obj->remote_proc_id = remote_proc_id;
+ obj->line_id = line_id;
+ obj->nesting = 0;
+ mutex_init(&obj->lock);
+
+ for (i = 0; i < notify_state.cfg.num_events; i++)
+ INIT_LIST_HEAD(&obj->event_list[i]);
+
+ /* Used solely for remote driver
+ * (NULL if remote_proc_id == self) */
+ obj->driver_handle = driver_handle;
+ /* Send this handle to the NotifyDriver */
+ status = notify_set_driver_handle(remote_proc_id, line_id, obj);
+ if (status < 0)
+ goto notify_handle_fail;
+
+ /* For local notify */
+ if (driver_handle == NULL)
+ /* Set driver status to indicate that it is done. */
+ notify_state.drivers[multiproc_self()][line_id].is_init =
+ NOTIFY_DRIVERINITSTATUS_DONE;
+ return obj;
+
+notify_handle_fail:
+ notify_set_driver_handle(remote_proc_id, line_id, NULL);
+ kfree(obj);
+ obj = NULL;
+exit:
+ if (status < 0)
+ pr_err("notify_create failed! status = 0x%x", status);
+ return obj;
+}
+
+
+/* Function to delete an instance of Notify driver */
+int notify_delete(struct notify_object **handle_ptr)
+{
+ int status = NOTIFY_S_SUCCESS;
+ struct notify_object *obj;
+ u16 i;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(unlikely((handle_ptr == NULL) || (*handle_ptr == NULL)))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ obj = (struct notify_object *)(*handle_ptr);
+
+ if (obj->remote_proc_id == multiproc_self()) {
+ if (WARN_ON(obj->line_id >= NOTIFY_MAX_INTLINES ||
+ multiproc_self() >= MULTIPROC_MAXPROCESSORS)) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ notify_state.drivers[multiproc_self()][obj->line_id].is_init =
+ NOTIFY_DRIVERINITSTATUS_NOTDONE;
+ }
+ notify_set_driver_handle(obj->remote_proc_id, obj->line_id, NULL);
+ for (i = 0; i < notify_state.cfg.num_events; i++)
+ INIT_LIST_HEAD(&obj->event_list[i]);
+
+ kfree(obj);
+ obj = NULL;
+ *handle_ptr = NULL;
+
+exit:
+ if (status < 0)
+ pr_err("notify_delete failed! status = 0x%x", status);
+ return status;
+}
+
+/* This function registers a callback for a specific event with the
+ * Notify module. */
+int notify_register_event(u16 proc_id, u16 line_id, u32 event_id,
+ notify_fn_notify_cbck notify_callback_fxn, void *cbck_arg)
+{
+ int status = NOTIFY_S_SUCCESS;
+ u32 stripped_event_id = (event_id & NOTIFY_EVENT_MASK);
+ struct notify_driver_object *driver_handle;
+ struct list_head *event_list;
+ struct notify_event_listener *listener;
+ bool list_was_empty;
+ struct notify_object *obj;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(proc_id >= multiproc_get_num_processors()))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(line_id >= NOTIFY_MAX_INTLINES))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(notify_callback_fxn == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely((stripped_event_id >= \
+ notify_state.cfg.num_events)))) {
+ status = NOTIFY_E_EVTNOTREGISTERED;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(!ISRESERVED(event_id,
+ notify_state.cfg.reserved_events)))) {
+ status = NOTIFY_E_EVTRESERVED;
+ goto exit;
+ }
+
+ driver_handle = notify_get_driver_handle(proc_id, line_id);
+ if (WARN_ON(driver_handle == NULL)) {
+ status = NOTIFY_E_DRIVERNOTREGISTERED;
+ goto exit;
+ }
+ if (WARN_ON(driver_handle->is_init != NOTIFY_DRIVERINITSTATUS_DONE)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ obj = (struct notify_object *)driver_handle->notify_handle;
+ if (WARN_ON(obj == NULL)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ listener = kmalloc(sizeof(struct notify_event_listener), GFP_KERNEL);
+ if (listener == NULL) {
+ status = NOTIFY_E_MEMORY;
+ goto exit;
+ }
+ listener->callback.fn_notify_cbck = notify_callback_fxn;
+ listener->callback.cbck_arg = cbck_arg;
+
+ event_list = &(obj->event_list[stripped_event_id]);
+ list_was_empty = list_empty(event_list);
+ mutex_lock_killable(&obj->lock);
+ list_add_tail((struct list_head *) listener, event_list);
+ mutex_unlock(&obj->lock);
+ if (list_was_empty) {
+ /* Registering this event for the first time. Need to
+ * register the callback function.
+ */
+ status = notify_register_event_single(proc_id, line_id,
+ event_id, _notify_exec_many,
+ (uint *) obj);
+ }
+
+exit:
+ if (status < 0)
+ pr_err("notify_register_event failed! status = 0x%x", status);
+ return status;
+}
+EXPORT_SYMBOL(notify_register_event);
+
+/* This function registers a single callback for a specific event with the
+ * Notify module. */
+int notify_register_event_single(u16 proc_id, u16 line_id, u32 event_id,
+ notify_fn_notify_cbck notify_callback_fxn, void *cbck_arg)
+{
+ int status = NOTIFY_S_SUCCESS;
+ u32 stripped_event_id = (event_id & NOTIFY_EVENT_MASK);
+ struct notify_driver_object *driver_handle;
+ struct notify_object *obj;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(proc_id >= multiproc_get_num_processors()))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(line_id >= NOTIFY_MAX_INTLINES))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(notify_callback_fxn == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely((stripped_event_id >= \
+ notify_state.cfg.num_events)))) {
+ status = NOTIFY_E_EVTNOTREGISTERED;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(!ISRESERVED(event_id,
+ notify_state.cfg.reserved_events)))) {
+ status = NOTIFY_E_EVTRESERVED;
+ goto exit;
+ }
+
+ driver_handle = notify_get_driver_handle(proc_id, line_id);
+ if (WARN_ON(driver_handle == NULL)) {
+ status = NOTIFY_E_DRIVERNOTREGISTERED;
+ goto exit;
+ }
+ if (WARN_ON(driver_handle->is_init != NOTIFY_DRIVERINITSTATUS_DONE)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ obj = (struct notify_object *)driver_handle->notify_handle;
+ if (WARN_ON(obj == NULL)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ if (obj->callbacks[stripped_event_id].fn_notify_cbck != NULL) {
+ status = NOTIFY_E_ALREADYEXISTS;
+ goto exit;
+ }
+
+ obj->callbacks[stripped_event_id].fn_notify_cbck = notify_callback_fxn;
+ obj->callbacks[stripped_event_id].cbck_arg = cbck_arg;
+
+ if (proc_id != multiproc_self()) {
+ status = driver_handle->fxn_table.register_event(driver_handle,
+ stripped_event_id);
+ }
+exit:
+ if (status < 0) {
+ pr_err("notify_register_event_single failed! "
+ "status = 0x%x", status);
+ }
+ return status;
+}
+EXPORT_SYMBOL(notify_register_event_single);
+
+/* This function un-registers the callback for the specific event with
+ * the Notify module. */
+int notify_unregister_event(u16 proc_id, u16 line_id, u32 event_id,
+ notify_fn_notify_cbck notify_callback_fxn, void *cbck_arg)
+{
+ int status = NOTIFY_S_SUCCESS;
+ u32 stripped_event_id = (event_id & NOTIFY_EVENT_MASK);
+ struct notify_event_listener *listener;
+ bool found = false;
+ struct notify_driver_object *driver_handle;
+ struct list_head *event_list;
+ struct notify_object *obj;
+ /*int *sys_key;*/
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(proc_id >= multiproc_get_num_processors()))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(line_id >= NOTIFY_MAX_INTLINES))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(notify_callback_fxn == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely((stripped_event_id >= \
+ notify_state.cfg.num_events)))) {
+ status = NOTIFY_E_EVTNOTREGISTERED;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(!ISRESERVED(event_id,
+ notify_state.cfg.reserved_events)))) {
+ status = NOTIFY_E_EVTRESERVED;
+ goto exit;
+ }
+
+ driver_handle = notify_get_driver_handle(proc_id, line_id);
+ if (WARN_ON(driver_handle == NULL)) {
+ status = NOTIFY_E_DRIVERNOTREGISTERED;
+ goto exit;
+ }
+ if (WARN_ON(driver_handle->is_init != NOTIFY_DRIVERINITSTATUS_DONE)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ obj = (struct notify_object *)driver_handle->notify_handle;
+ if (WARN_ON(obj == NULL)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ event_list = &(obj->event_list[stripped_event_id]);
+ if (list_empty(event_list)) {
+ status = NOTIFY_E_NOTFOUND;
+ goto exit;
+ }
+
+ mutex_lock_killable(&obj->lock);
+ list_for_each_entry(listener, event_list, element) {
+ /* Hash not matches, take next node */
+ if ((listener->callback.fn_notify_cbck == notify_callback_fxn)
+ && (listener->callback.cbck_arg == cbck_arg)) {
+ list_del((struct list_head *)listener);
+ found = true;
+ break;
+ }
+ }
+ if (found == false) {
+ status = NOTIFY_E_NOTFOUND;
+ mutex_unlock(&obj->lock);
+ goto exit;
+ }
+
+ if (list_empty(event_list)) {
+ status = notify_unregister_event_single(proc_id, line_id,
+ event_id);
+ }
+ mutex_unlock(&obj->lock);
+ kfree(listener);
+exit:
+ if (status < 0) {
+ pr_err("notify_unregister_event failed! "
+ "status = 0x%x", status);
+ }
+ return status;
+}
+EXPORT_SYMBOL(notify_unregister_event);
+
+/* This function un-registers a single callback for the specific event with
+ * the Notify module. */
+int notify_unregister_event_single(u16 proc_id, u16 line_id, u32 event_id)
+{
+ int status = NOTIFY_S_SUCCESS;
+ u32 stripped_event_id = (event_id & NOTIFY_EVENT_MASK);
+ struct notify_driver_object *driver_handle;
+ struct notify_object *obj;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(proc_id >= multiproc_get_num_processors()))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(line_id >= NOTIFY_MAX_INTLINES))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely((stripped_event_id >= \
+ notify_state.cfg.num_events)))) {
+ status = NOTIFY_E_EVTNOTREGISTERED;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(!ISRESERVED(event_id,
+ notify_state.cfg.reserved_events)))) {
+ status = NOTIFY_E_EVTRESERVED;
+ goto exit;
+ }
+
+ driver_handle = notify_get_driver_handle(proc_id, line_id);
+ if (WARN_ON(driver_handle == NULL)) {
+ status = NOTIFY_E_DRIVERNOTREGISTERED;
+ goto exit;
+ }
+ if (WARN_ON(driver_handle->is_init != NOTIFY_DRIVERINITSTATUS_DONE)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ obj = (struct notify_object *)driver_handle->notify_handle;
+ if (WARN_ON(obj == NULL)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ if (obj->callbacks[stripped_event_id].fn_notify_cbck == NULL) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ obj->callbacks[stripped_event_id].fn_notify_cbck = NULL;
+ obj->callbacks[stripped_event_id].cbck_arg = NULL;
+ if (proc_id != multiproc_self()) {
+ status = driver_handle->fxn_table.unregister_event(
+ driver_handle, stripped_event_id);
+ }
+exit:
+ if (status < 0) {
+ pr_err("notify_unregister_event_single failed! "
+ "status = 0x%x", status);
+ }
+ return status;
+}
+EXPORT_SYMBOL(notify_unregister_event_single);
+
+/* This function sends a notification to the specified event. */
+int notify_send_event(u16 proc_id, u16 line_id, u32 event_id, u32 payload,
+ bool wait_clear)
+{
+ int status = NOTIFY_S_SUCCESS;
+ u32 stripped_event_id = (event_id & NOTIFY_EVENT_MASK);
+ struct notify_driver_object *driver_handle;
+ struct notify_object *obj;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(proc_id >= multiproc_get_num_processors()))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(line_id >= NOTIFY_MAX_INTLINES))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely((stripped_event_id >= \
+ notify_state.cfg.num_events)))) {
+ status = NOTIFY_E_EVTNOTREGISTERED;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(!ISRESERVED(event_id,
+ notify_state.cfg.reserved_events)))) {
+ status = NOTIFY_E_EVTRESERVED;
+ goto exit;
+ }
+
+ driver_handle = notify_get_driver_handle(proc_id, line_id);
+ if (WARN_ON(driver_handle == NULL)) {
+ status = NOTIFY_E_DRIVERNOTREGISTERED;
+ goto exit;
+ }
+ if (WARN_ON(driver_handle->is_init != NOTIFY_DRIVERINITSTATUS_DONE)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ obj = (struct notify_object *)driver_handle->notify_handle;
+ if (WARN_ON(obj == NULL)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ /* Maybe the proc is shutdown this functions will check and
+ * restore if needed.
+ * Currently only used to enable Idle and set HW_AUTO as
+ * the ducati_clkstctrl mode*/
+ status = ipu_pm_restore_ctx(proc_id);
+ if (status)
+ goto exit;
+
+ if (proc_id != multiproc_self()) {
+ status = driver_handle->fxn_table.send_event(driver_handle,
+ stripped_event_id, payload, wait_clear);
+ } else {
+ /* If nesting == 0 (the driver is enabled) and the event is
+ * enabled, send the event */
+ if (obj->callbacks[stripped_event_id].fn_notify_cbck == NULL) {
+ /* No callbacks are registered locally for the event. */
+ status = NOTIFY_E_EVTNOTREGISTERED;
+ } else if (obj->nesting != 0) {
+ /* Driver is disabled */
+ status = NOTIFY_E_FAIL;
+ } else if (!test_bit(stripped_event_id, (unsigned long *)
+ &notify_state.local_enable_mask)) {
+ /* Event is disabled */
+ status = NOTIFY_E_EVTDISABLED;
+ } else {
+ /* Execute the callback function registered to the
+ * event */
+ notify_exec(obj, event_id, payload);
+ }
+ }
+exit:
+ if (status < 0)
+ pr_err("notify_send_event failed! status = 0x%x", status);
+ return status;
+}
+EXPORT_SYMBOL(notify_send_event);
+
+/* This function disables all events. This is equivalent to global
+ * interrupt disable, however restricted within interrupts handled by
+ * the Notify module. All callbacks registered for all events are
+ * disabled with this API. It is not possible to disable a specific
+ * callback. */
+u32 notify_disable(u16 proc_id, u16 line_id)
+{
+ uint key = 0;
+ int status = NOTIFY_S_SUCCESS;
+ struct notify_driver_object *driver_handle;
+ struct notify_object *obj;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(proc_id >= multiproc_get_num_processors()))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(line_id >= NOTIFY_MAX_INTLINES))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ driver_handle = notify_get_driver_handle(proc_id, line_id);
+ if (WARN_ON(driver_handle == NULL)) {
+ status = NOTIFY_E_DRIVERNOTREGISTERED;
+ goto exit;
+ }
+ if (WARN_ON(driver_handle->is_init != NOTIFY_DRIVERINITSTATUS_DONE)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ obj = (struct notify_object *)driver_handle->notify_handle;
+ if (WARN_ON(obj == NULL)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ mutex_lock_killable(&obj->lock);
+ obj->nesting++;
+ if (obj->nesting == 1) {
+ /* Disable receiving all events */
+ if (proc_id != multiproc_self())
+ driver_handle->fxn_table.disable(driver_handle);
+ }
+ key = obj->nesting;
+ mutex_unlock(&obj->lock);
+exit:
+ if (status < 0)
+ pr_err("notify_disable failed! status = 0x%x", status);
+ return key;
+}
+EXPORT_SYMBOL(notify_disable);
+
+/* This function restores the Notify module to the state before the
+ * last notify_disable() was called. This is equivalent to global
+ * interrupt restore, however restricted within interrupts handled by
+ * the Notify module. All callbacks registered for all events as
+ * specified in the flags are enabled with this API. It is not possible
+ * to enable a specific callback. */
+void notify_restore(u16 proc_id, u16 line_id, u32 key)
+{
+ int status = NOTIFY_S_SUCCESS;
+ struct notify_driver_object *driver_handle;
+ struct notify_object *obj;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(proc_id >= multiproc_get_num_processors()))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(line_id >= NOTIFY_MAX_INTLINES))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ driver_handle = notify_get_driver_handle(proc_id, line_id);
+ if (WARN_ON(driver_handle == NULL)) {
+ status = NOTIFY_E_DRIVERNOTREGISTERED;
+ goto exit;
+ }
+ if (WARN_ON(driver_handle->is_init != NOTIFY_DRIVERINITSTATUS_DONE)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ obj = (struct notify_object *)driver_handle->notify_handle;
+ if (WARN_ON(obj == NULL)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ if (key != obj->nesting) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+
+ mutex_lock_killable(&obj->lock);
+ obj->nesting--;
+ if (obj->nesting == 0) {
+ /* Enable receiving events */
+ if (proc_id != multiproc_self())
+ driver_handle->fxn_table.enable(driver_handle);
+ }
+ mutex_unlock(&obj->lock);
+exit:
+ if (status < 0)
+ pr_err("notify_restore failed! status = 0x%x", status);
+ return;
+}
+EXPORT_SYMBOL(notify_restore);
+
+/* This function disables a specific event. All callbacks registered
+ * for the specific event are disabled with this API. It is not
+ * possible to disable a specific callback. */
+void notify_disable_event(u16 proc_id, u16 line_id, u32 event_id)
+{
+ int status = 0;
+ u32 stripped_event_id = (event_id & NOTIFY_EVENT_MASK);
+ struct notify_driver_object *driver_handle;
+ struct notify_object *obj;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(proc_id >= multiproc_get_num_processors()))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(line_id >= NOTIFY_MAX_INTLINES))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely((stripped_event_id >= \
+ notify_state.cfg.num_events)))) {
+ status = NOTIFY_E_EVTNOTREGISTERED;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(!ISRESERVED(event_id,
+ notify_state.cfg.reserved_events)))) {
+ status = NOTIFY_E_EVTRESERVED;
+ goto exit;
+ }
+
+ driver_handle = notify_get_driver_handle(proc_id, line_id);
+ if (WARN_ON(driver_handle == NULL)) {
+ status = NOTIFY_E_DRIVERNOTREGISTERED;
+ goto exit;
+ }
+ if (WARN_ON(driver_handle->is_init != NOTIFY_DRIVERINITSTATUS_DONE)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ obj = (struct notify_object *)driver_handle->notify_handle;
+ if (WARN_ON(obj == NULL)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ if (proc_id != multiproc_self()) {
+ driver_handle->fxn_table.disable_event(driver_handle,
+ stripped_event_id);
+ } else {
+ clear_bit(stripped_event_id,
+ (unsigned long *) &notify_state.local_enable_mask);
+ }
+exit:
+ if (status < 0)
+ pr_err("notify_disable_event failed! status = 0x%x", status);
+ return;
+}
+EXPORT_SYMBOL(notify_disable_event);
+
+/* This function enables a specific event. All callbacks registered for
+ * this specific event are enabled with this API. It is not possible to
+ * enable a specific callback. */
+void notify_enable_event(u16 proc_id, u16 line_id, u32 event_id)
+{
+ int status = 0;
+ u32 stripped_event_id = (event_id & NOTIFY_EVENT_MASK);
+ struct notify_driver_object *driver_handle;
+ struct notify_object *obj;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(proc_id >= multiproc_get_num_processors()))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(line_id >= NOTIFY_MAX_INTLINES))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely((stripped_event_id >= \
+ notify_state.cfg.num_events)))) {
+ status = NOTIFY_E_EVTNOTREGISTERED;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(!ISRESERVED(event_id,
+ notify_state.cfg.reserved_events)))) {
+ status = NOTIFY_E_EVTRESERVED;
+ goto exit;
+ }
+
+ driver_handle = notify_get_driver_handle(proc_id, line_id);
+ if (WARN_ON(driver_handle == NULL)) {
+ status = NOTIFY_E_DRIVERNOTREGISTERED;
+ goto exit;
+ }
+ if (WARN_ON(driver_handle->is_init != NOTIFY_DRIVERINITSTATUS_DONE)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ obj = (struct notify_object *)driver_handle->notify_handle;
+ if (WARN_ON(obj == NULL)) {
+ status = NOTIFY_E_FAIL;
+ goto exit;
+ }
+
+ if (proc_id != multiproc_self()) {
+ driver_handle->fxn_table.enable_event(driver_handle,
+ stripped_event_id);
+ } else {
+ set_bit(stripped_event_id,
+ (unsigned long *)&notify_state.local_enable_mask);
+ }
+exit:
+ if (status < 0)
+ pr_err("notify_enable_event failed! status = 0x%x", status);
+ return;
+}
+EXPORT_SYMBOL(notify_enable_event);
+
+/* Whether notification via interrupt line has been registered. */
+bool notify_is_registered(u16 proc_id, u16 line_id)
+{
+ int status = NOTIFY_S_SUCCESS;
+ bool is_registered = false;
+ struct notify_driver_object *driver_handle;
+
+ if (WARN_ON(unlikely(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true))) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(proc_id >= multiproc_get_num_processors()))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(line_id >= NOTIFY_MAX_INTLINES))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ driver_handle = notify_get_driver_handle(proc_id, line_id);
+ if ((driver_handle != NULL) && (driver_handle->notify_handle != NULL))
+ is_registered = true;
+
+exit:
+ if (status < 0)
+ pr_err("notify_is_registered failed! status = 0x%x", status);
+ return is_registered;
+}
+EXPORT_SYMBOL(notify_is_registered);
+
+/* Creates notify drivers and registers them with Notify */
+int notify_attach(u16 proc_id, void *shared_addr)
+{
+ int status = NOTIFY_S_SUCCESS;
+
+ /* Use the NotifySetup proxy to setup drivers */
+ status = notify_setup_proxy_attach(proc_id, shared_addr);
+
+ notify_state.start_complete = true;
+
+ return status;
+}
+EXPORT_SYMBOL(notify_attach);
+
+/* Creates notify drivers and registers them with Notify */
+int notify_detach(u16 proc_id)
+{
+ int status = 0;
+
+ /* Use the NotifySetup proxy to destroy drivers */
+ status = notify_setup_proxy_detach(proc_id);
+
+ notify_state.start_complete = false;
+
+ return status;
+}
+EXPORT_SYMBOL(notify_detach);
+
+/* Returns the total amount of shared memory used by the Notify module
+ * and all instances after notify_start has been called. */
+uint notify_shared_mem_req(u16 proc_id, void *shared_addr)
+{
+ uint mem_req = 0x0;
+
+ if (multiproc_get_num_processors() > 1)
+ /* Determine device-specific shared memory requirements */
+ mem_req = notify_setup_proxy_shared_mem_req(proc_id,\
+ shared_addr);
+ else
+ /* Only 1 processor: no shared memory needed */
+ mem_req = 0;
+
+ return mem_req;
+}
+
+/* Indicates whether notify_start is completed. */
+inline bool _notify_start_complete(void)
+{
+ return notify_state.start_complete;
+}
+
+/* Function registered as callback with the Notify driver */
+void notify_exec(struct notify_object *obj, u32 event_id, u32 payload)
+{
+ struct notify_event_callback *callback;
+
+ WARN_ON(obj == NULL);
+ if (WARN_ON((event_id >= notify_state.cfg.num_events) ||
+ (event_id >= NOTIFY_MAXEVENTS))) {
+ pr_err("Invalid event_id %d\n", event_id);
+ } else {
+ callback = &(obj->callbacks[event_id]);
+ WARN_ON(callback->fn_notify_cbck == NULL);
+
+ /* Execute the callback function with its argument
+ and the payload */
+ callback->fn_notify_cbck(obj->remote_proc_id, obj->line_id,
+ event_id, callback->cbck_arg, payload);
+ }
+}
+
+
+/* Function registered with notify_exec when multiple registrations are present
+ * for the events. */
+static void _notify_exec_many(u16 proc_id, u16 line_id, u32 event_id, uint *arg,
+ u32 payload)
+{
+ struct notify_object *obj = (struct notify_object *)arg;
+ struct list_head *event_list;
+ struct notify_event_listener *listener;
+
+ WARN_ON(proc_id >= multiproc_get_num_processors());
+ WARN_ON(obj == NULL);
+ WARN_ON(line_id >= NOTIFY_MAX_INTLINES);
+ WARN_ON(event_id >= notify_state.cfg.num_events);
+
+ /* Both loopback and the the event itself are enabled */
+ event_list = &(obj->event_list[event_id]);
+
+ /* Enter critical section protection. */
+ mutex_lock_killable(&obj->lock);
+ /* Use "NULL" to get the first EventListener on the list */
+ list_for_each_entry(listener, event_list, element) {
+ listener->callback.fn_notify_cbck(proc_id, line_id, event_id,
+ listener->callback.cbck_arg, payload);
+ }
+ /* Leave critical section protection. */
+ mutex_unlock(&obj->lock);
+}
diff --git a/drivers/dsp/syslink/omap_notify/notify_driver.c b/drivers/dsp/syslink/omap_notify/notify_driver.c
new file mode 100644
index 00000000000..c6c399605dd
--- /dev/null
+++ b/drivers/dsp/syslink/omap_notify/notify_driver.c
@@ -0,0 +1,186 @@
+/*
+ * notify_driver.c
+ *
+ * Syslink driver support for OMAP Processors.
+ *
+ * Copyright (C) 2008-2009 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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <asm/pgtable.h>
+
+#include <syslink/gt.h>
+#include <syslink/notify.h>
+#include <syslink/notify_driver.h>
+#include <syslink/notifydefs.h>
+#include <syslink/atomic_linux.h>
+
+
+/* Function to register driver with the Notify module. */
+int notify_register_driver(u16 remote_proc_id,
+ u16 line_id,
+ struct notify_driver_fxn_table *fxn_table,
+ struct notify_driver_object **driver_handle)
+{
+ int status = NOTIFY_S_SUCCESS;
+ struct notify_driver_object *drv_handle = NULL;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true)) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(fxn_table == NULL)) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(remote_proc_id >= multiproc_get_num_processors())) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(line_id >= NOTIFY_MAX_INTLINES)) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(driver_handle == NULL)) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ *driver_handle = NULL;
+ if (mutex_lock_interruptible(notify_state.gate_handle) != 0)
+ WARN_ON(1);
+ drv_handle = &(notify_state.drivers[remote_proc_id][line_id]);
+ if (drv_handle->is_init == NOTIFY_DRIVERINITSTATUS_DONE) {
+ status = NOTIFY_E_ALREADYEXISTS;
+ mutex_unlock(notify_state.gate_handle);
+ goto exit;
+ }
+ mutex_unlock(notify_state.gate_handle);
+ WARN_ON(status < 0);
+
+ /*Complete registration of the driver. */
+ memcpy(&(drv_handle->fxn_table), fxn_table,
+ sizeof(struct notify_driver_fxn_table));
+ drv_handle->notify_handle = NULL; /* Initialize to NULL. */
+ drv_handle->is_init = NOTIFY_DRIVERINITSTATUS_DONE;
+ *driver_handle = drv_handle;
+
+exit:
+ return status;
+}
+EXPORT_SYMBOL(notify_register_driver);
+
+/* Function to unregister driver with the Notify module. */
+int notify_unregister_driver(struct notify_driver_object *drv_handle)
+{
+ int status = NOTIFY_E_FAIL;
+ s32 key;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true)) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(drv_handle == NULL)) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ key = mutex_lock_interruptible(notify_state.gate_handle);
+ if (key)
+ goto exit;
+
+ /* Unregister the driver. */
+ drv_handle->is_init = NOTIFY_DRIVERINITSTATUS_NOTDONE;
+ mutex_unlock(notify_state.gate_handle);
+ status = NOTIFY_S_SUCCESS;
+
+exit:
+ return status;
+}
+EXPORT_SYMBOL(notify_unregister_driver);
+
+/* Function to set the Notify object handle maintained within the
+ * Notify module. */
+int notify_set_driver_handle(u16 remote_proc_id, u16 line_id,
+ struct notify_object *handle)
+{
+ s32 status = NOTIFY_S_SUCCESS;
+
+ /* Handle can be set to NULL */
+ if (WARN_ON(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true)) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(remote_proc_id >= multiproc_get_num_processors())) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(line_id >= NOTIFY_MAX_INTLINES)) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ notify_state.drivers[remote_proc_id][line_id].notify_handle = handle;
+
+exit:
+ return status;
+}
+EXPORT_SYMBOL(notify_set_driver_handle);
+
+
+/* Function to find and return the driver handle maintained within
+ * the Notify module. */
+struct notify_driver_object *notify_get_driver_handle(u16 remote_proc_id,
+ u16 line_id)
+{
+ struct notify_driver_object *handle = NULL;
+ s32 status = NOTIFY_S_SUCCESS;
+
+ if (WARN_ON(atomic_cmpmask_and_lt(&(notify_state.ref_count),
+ NOTIFY_MAKE_MAGICSTAMP(0),
+ NOTIFY_MAKE_MAGICSTAMP(1)) == true)) {
+ status = NOTIFY_E_INVALIDSTATE;
+ goto exit;
+ }
+ if (WARN_ON(remote_proc_id >= multiproc_get_num_processors())) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(line_id >= NOTIFY_MAX_INTLINES)) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ handle = &(notify_state.drivers[remote_proc_id][line_id]);
+ /* Check whether the driver handle slot is occupied. */
+ if (handle->is_init == NOTIFY_DRIVERINITSTATUS_NOTDONE)
+ handle = NULL;
+
+exit:
+ if (status < 0) {
+ pr_err("notify_get_driver_handle failed! "
+ "status = 0x%x\n", status);
+ }
+ return handle;
+}
+EXPORT_SYMBOL(notify_get_driver_handle);
diff --git a/drivers/dsp/syslink/omap_notify/plat/omap4_notify_setup.c b/drivers/dsp/syslink/omap_notify/plat/omap4_notify_setup.c
new file mode 100644
index 00000000000..f62d0ad5884
--- /dev/null
+++ b/drivers/dsp/syslink/omap_notify/plat/omap4_notify_setup.c
@@ -0,0 +1,165 @@
+/*
+ * omap4_notify_setup.c
+ *
+ * OMAP4 device-specific functions to setup the Notify module.
+ *
+ * Copyright (C) 2008-2009 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 headers */
+#include <linux/spinlock.h>
+/*#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <asm/pgtable.h>*/
+
+/* Module headers */
+#include <syslink/multiproc.h>
+
+#include <syslink/notify.h>
+#include <syslink/notify_setup_proxy.h>
+#include <syslink/notify_ducatidriver.h>
+#include <syslink/notify_driver.h>
+#include <syslink/notifydefs.h>
+
+
+/* Handle to the NotifyDriver for line 0 */
+static struct notify_ducatidrv_object *notify_setup_driver_handles[
+ MULTIPROC_MAXPROCESSORS];
+
+/* Handle to the Notify objects */
+static
+struct notify_object *notify_setup_notify_handles[MULTIPROC_MAXPROCESSORS];
+
+
+/* Function to perform device specific setup for Notify module.
+ * This function creates the Notify drivers. */
+int notify_setup_omap4_attach(u16 proc_id, void *shared_addr)
+{
+ s32 status = NOTIFY_S_SUCCESS;
+ struct notify_ducatidrv_params notify_shm_params;
+
+ if (WARN_ON(unlikely(shared_addr == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+ if (WARN_ON(unlikely(proc_id == multiproc_self()))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ notify_ducatidrv_params_init(&notify_shm_params);
+
+ /* Currently not supporting caching on host side. */
+ notify_shm_params.cache_enabled = false;
+ notify_shm_params.line_id = 0;
+ notify_shm_params.local_int_id = 77u; /* TBD: Ipc_getConfig */
+ notify_shm_params.remote_int_id = 0u; /* TBD: Ipc_getConfig */
+ notify_shm_params.remote_proc_id = proc_id;
+ notify_shm_params.shared_addr = shared_addr;
+
+ notify_setup_driver_handles[proc_id] = notify_ducatidrv_create(
+ &notify_shm_params);
+ if (notify_setup_driver_handles[proc_id] == NULL) {
+ status = NOTIFY_E_FAIL;
+ pr_err("notify_setup_omap4_attach: "
+ "notify_ducatidrv_create failed! status = 0x%x",
+ status);
+ goto exit;
+ }
+
+ notify_setup_notify_handles[proc_id] = \
+ notify_create(notify_setup_driver_handles[proc_id],
+ proc_id, 0u, NULL);
+ if (notify_setup_notify_handles[proc_id] == NULL) {
+ status = NOTIFY_E_FAIL;
+ pr_err("notify_setup_omap4_attach: notify_create "
+ "failed!");
+ goto exit;
+ }
+
+exit:
+ if (status < 0) {
+ pr_err("notify_setup_omap4_attach failed! "
+ "status = 0x%x", status);
+ }
+ return status;
+}
+
+
+/* Function to perform device specific destroy for Notify module.
+ * This function deletes the Notify drivers. */
+int notify_setup_omap4_detach(u16 proc_id)
+{
+ s32 status = NOTIFY_S_SUCCESS;
+ s32 tmp_status = NOTIFY_S_SUCCESS;
+
+ if (WARN_ON(unlikely(proc_id == multiproc_self()))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ /* Delete the notify driver to the M3 (Line 0) */
+ status = notify_delete(&(notify_setup_notify_handles[proc_id]));
+ if (status < 0) {
+ pr_err("notify_setup_omap4_detach: notify_delete "
+ "failed for line 0!");
+ }
+
+ tmp_status = notify_ducatidrv_delete(
+ &(notify_setup_driver_handles[proc_id]));
+ if ((tmp_status < 0) && (status >= 0)) {
+ status = tmp_status;
+ pr_err("notify_setup_omap4_detach: "
+ "notify_ducatidrv_delete failed for line 0!");
+ }
+
+exit:
+ if (status < 0) {
+ pr_err("notify_setup_omap4_detach failed! "
+ "status = 0x%x", status);
+ }
+ return status;
+}
+
+
+/* Return the amount of shared memory required */
+uint notify_setup_omap4_shared_mem_req(u16 remote_proc_id, void *shared_addr)
+{
+ int status = NOTIFY_S_SUCCESS;
+ uint mem_req = 0x0;
+ struct notify_ducatidrv_params params;
+
+ if (WARN_ON(unlikely(shared_addr == NULL))) {
+ status = NOTIFY_E_INVALIDARG;
+ goto exit;
+ }
+
+ notify_ducatidrv_params_init(&params);
+ params.shared_addr = shared_addr;
+
+ mem_req = notify_ducatidrv_shared_mem_req(&params);
+
+exit:
+ if (status < 0) {
+ pr_err("notify_setup_omap4_shared_mem_req failed!"
+ " status = 0x%x", status);
+ }
+ return mem_req;
+}
+
+bool notify_setup_omap4_int_line_available(u16 remote_proc_id)
+{
+ return true;
+}
diff --git a/drivers/dsp/syslink/procmgr/Kbuild b/drivers/dsp/syslink/procmgr/Kbuild
new file mode 100644
index 00000000000..33622e8425b
--- /dev/null
+++ b/drivers/dsp/syslink/procmgr/Kbuild
@@ -0,0 +1,9 @@
+libomap_syslink_proc = processor.o procmgr.o procmgr_drv.o
+
+obj-$(CONFIG_SYSLINK_PROC) += syslink_proc.o
+syslink_proc-objs = $(libomap_syslink_proc)
+
+ccflags-y += -Wno-strict-prototypes
+
+#Header files
+ccflags-y += -Iarch/arm/plat-omap/include/syslink
diff --git a/drivers/dsp/syslink/procmgr/proc4430/Kbuild b/drivers/dsp/syslink/procmgr/proc4430/Kbuild
new file mode 100644
index 00000000000..3dee46d956d
--- /dev/null
+++ b/drivers/dsp/syslink/procmgr/proc4430/Kbuild
@@ -0,0 +1,9 @@
+libomap_proc4430 = proc4430.o proc4430_drv.o
+
+obj-$(CONFIG_SYSLINK_PROC) += syslink_proc4430.o
+syslink_proc4430-objs = $(libomap_proc4430)
+
+ccflags-y += -Wno-strict-prototypes -DUSE_LEVEL_1_MACROS
+
+#Header files
+ccflags-y += -Iarch/arm/plat-omap/include/syslink
diff --git a/drivers/dsp/syslink/procmgr/proc4430/proc4430.c b/drivers/dsp/syslink/procmgr/proc4430/proc4430.c
new file mode 100644
index 00000000000..7530ba8df5b
--- /dev/null
+++ b/drivers/dsp/syslink/procmgr/proc4430/proc4430.c
@@ -0,0 +1,825 @@
+/*
+ * proc4430.c
+ *
+ * Syslink driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2009-2010 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 <linux/types.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+/* Module level headers */
+#include "../procdefs.h"
+#include "../processor.h"
+#include <procmgr.h>
+#include "../procmgr_drvdefs.h"
+#include "proc4430.h"
+#include "../../ipu_pm/ipu_pm.h"
+#include <syslink/multiproc.h>
+#include <syslink/platform_mem.h>
+#include <syslink/atomic_linux.h>
+
+
+#define OMAP4430PROC_MODULEID (u16) 0xbbec
+
+/* Macro to make a correct module magic number with refCount */
+#define OMAP4430PROC_MAKE_MAGICSTAMP(x) ((OMAP4430PROC_MODULEID << 12u) | (x))
+
+#define PG_MASK(pg_size) (~((pg_size)-1))
+#define PG_ALIGN_LOW(addr, pg_size) ((addr) & PG_MASK(pg_size))
+
+/*OMAP4430 Module state object */
+struct proc4430_module_object {
+ u32 config_size;
+ /* Size of configuration structure */
+ struct proc4430_config cfg;
+ /* OMAP4430 configuration structure */
+ struct proc4430_config def_cfg;
+ /* Default module configuration */
+ struct proc4430_params def_inst_params;
+ /* Default parameters for the OMAP4430 instances */
+ void *proc_handles[MULTIPROC_MAXPROCESSORS];
+ /* Processor handle array. */
+ struct mutex *gate_handle;
+ /* void * of gate to be used for local thread safety */
+ atomic_t ref_count;
+};
+
+/*
+ OMAP4430 instance object.
+ */
+struct proc4430_object {
+ struct proc4430_params params;
+ /* Instance parameters (configuration values) */
+ atomic_t attach_count;
+ /* attach reference count */
+};
+
+
+/* =================================
+ * Globals
+ * =================================
+ */
+/*
+ OMAP4430 state object variable
+ */
+
+static struct proc4430_module_object proc4430_state = {
+ .config_size = sizeof(struct proc4430_config),
+ .gate_handle = NULL,
+ .def_inst_params.num_mem_entries = 0u,
+ .def_inst_params.mem_entries = NULL,
+ .def_inst_params.reset_vector_mem_entry = 0
+};
+
+
+/* =================================
+ * APIs directly called by applications
+ * =================================
+ */
+/*
+ * Function to get the default configuration for the OMAP4430
+ * module.
+ *
+ * This function can be called by the application to get their
+ * configuration parameter to proc4430_setup filled in by the
+ * OMAP4430 module with the default parameters. If the user
+ * does not wish to make any change in the default parameters, this
+ * API is not required to be called.
+ */
+void proc4430_get_config(struct proc4430_config *cfg)
+{
+ BUG_ON(cfg == NULL);
+ memcpy(cfg, &(proc4430_state.def_cfg),
+ sizeof(struct proc4430_config));
+}
+EXPORT_SYMBOL(proc4430_get_config);
+
+/*
+ * Function to setup the OMAP4430 module.
+ *
+ * This function sets up the OMAP4430 module. This function
+ * must be called before any other instance-level APIs can be
+ * invoked.
+ * Module-level configuration needs to be provided to this
+ * function. If the user wishes to change some specific config
+ * parameters, then proc4430_get_config can be called to get the
+ * configuration filled with the default values. After this, only
+ * the required configuration values can be changed. If the user
+ * does not wish to make any change in the default parameters, the
+ * application can simply call proc4430_setup with NULL
+ * parameters. The default parameters would get automatically used.
+ */
+int proc4430_setup(struct proc4430_config *cfg)
+{
+ int retval = 0;
+ struct proc4430_config tmp_cfg;
+ atomic_cmpmask_and_set(&proc4430_state.ref_count,
+ OMAP4430PROC_MAKE_MAGICSTAMP(0),
+ OMAP4430PROC_MAKE_MAGICSTAMP(0));
+
+ if (atomic_inc_return(&proc4430_state.ref_count) !=
+ OMAP4430PROC_MAKE_MAGICSTAMP(1)) {
+ return 1;
+ }
+
+ if (cfg == NULL) {
+ proc4430_get_config(&tmp_cfg);
+ cfg = &tmp_cfg;
+ }
+
+ /* Create a default gate handle for local module protection. */
+ proc4430_state.gate_handle =
+ kmalloc(sizeof(struct mutex), GFP_KERNEL);
+ if (proc4430_state.gate_handle == NULL) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ mutex_init(proc4430_state.gate_handle);
+
+ /* Initialize the name to handles mapping array. */
+ memset(&proc4430_state.proc_handles, 0,
+ (sizeof(void *) * MULTIPROC_MAXPROCESSORS));
+
+ /* Copy the user provided values into the state object. */
+ memcpy(&proc4430_state.cfg, cfg,
+ sizeof(struct proc4430_config));
+
+ return 0;
+
+error:
+ atomic_dec_return(&proc4430_state.ref_count);
+
+ return retval;
+}
+EXPORT_SYMBOL(proc4430_setup);
+
+/*
+ * Function to destroy the OMAP4430 module.
+ *
+ * Once this function is called, other OMAP4430 module APIs,
+ * except for the proc4430_get_config API cannot be called
+ * anymore.
+ */
+int proc4430_destroy(void)
+{
+ int retval = 0;
+ u16 i;
+
+ if (atomic_cmpmask_and_lt(&proc4430_state.ref_count,
+ OMAP4430PROC_MAKE_MAGICSTAMP(0),
+ OMAP4430PROC_MAKE_MAGICSTAMP(1))
+ == true) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (!(atomic_dec_return(&proc4430_state.ref_count)
+ == OMAP4430PROC_MAKE_MAGICSTAMP(0))) {
+
+ retval = 1;
+ goto exit;
+ }
+
+ /* Check if any OMAP4430 instances have not been
+ * deleted so far. If not,delete them.
+ */
+
+ for (i = 0; i < MULTIPROC_MAXPROCESSORS; i++) {
+ if (proc4430_state.proc_handles[i] == NULL)
+ continue;
+ proc4430_delete(&(proc4430_state.proc_handles[i]));
+ }
+
+ /* Check if the gate_handle was created internally. */
+ if (proc4430_state.gate_handle != NULL) {
+ mutex_destroy(proc4430_state.gate_handle);
+ kfree(proc4430_state.gate_handle);
+ }
+
+exit:
+ return retval;
+}
+EXPORT_SYMBOL(proc4430_destroy);
+
+/*=================================================
+ * Function to initialize the parameters for this Processor
+ * instance.
+ */
+void proc4430_params_init(void *handle, struct proc4430_params *params)
+{
+ struct proc4430_object *proc_object = (struct proc4430_object *)handle;
+
+ if (atomic_cmpmask_and_lt(&proc4430_state.ref_count,
+ OMAP4430PROC_MAKE_MAGICSTAMP(0),
+ OMAP4430PROC_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc4430_params_init failed - Module not initialized");
+ return;
+ }
+
+ if (WARN_ON(params == NULL)) {
+ pr_err("proc4430_params_init failed "
+ "Argument of type proc4430_params * "
+ "is NULL");
+ return;
+ }
+
+ if (handle == NULL)
+ memcpy(params, &(proc4430_state.def_inst_params),
+ sizeof(struct proc4430_params));
+ else
+ memcpy(params, &(proc_object->params),
+ sizeof(struct proc4430_params));
+}
+EXPORT_SYMBOL(proc4430_params_init);
+
+/*===================================================
+ *Function to create an instance of this Processor.
+ *
+ */
+void *proc4430_create(u16 proc_id, const struct proc4430_params *params)
+{
+ struct processor_object *handle = NULL;
+ struct proc4430_object *object = NULL;
+
+ BUG_ON(!IS_VALID_PROCID(proc_id));
+ BUG_ON(params == NULL);
+
+ if (atomic_cmpmask_and_lt(&proc4430_state.ref_count,
+ OMAP4430PROC_MAKE_MAGICSTAMP(0),
+ OMAP4430PROC_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc4430_create failed - Module not initialized");
+ goto error;
+ }
+
+ /* Enter critical section protection. */
+ WARN_ON(mutex_lock_interruptible(proc4430_state.gate_handle));
+ if (proc4430_state.proc_handles[proc_id] != NULL) {
+ handle = proc4430_state.proc_handles[proc_id];
+ goto func_end;
+ } else {
+ handle = (struct processor_object *)
+ vmalloc(sizeof(struct processor_object));
+ if (WARN_ON(handle == NULL))
+ goto func_end;
+
+ handle->proc_fxn_table.attach = &proc4430_attach;
+ handle->proc_fxn_table.detach = &proc4430_detach;
+ handle->proc_fxn_table.read = &proc4430_read;
+ handle->proc_fxn_table.write = &proc4430_write;
+ handle->proc_fxn_table.control = &proc4430_control;
+ handle->proc_fxn_table.translateAddr =
+ &proc4430_translate_addr;
+ handle->proc_fxn_table.procinfo = &proc4430_proc_info;
+ handle->proc_fxn_table.virt_to_phys = &proc4430_virt_to_phys;
+ handle->state = PROC_MGR_STATE_UNKNOWN;
+ handle->object = vmalloc(sizeof(struct proc4430_object));
+ handle->proc_id = proc_id;
+ object = (struct proc4430_object *)handle->object;
+ if (params != NULL) {
+ /* Copy params into instance object. */
+ memcpy(&(object->params), (void *)params,
+ sizeof(struct proc4430_params));
+ }
+ if ((params != NULL) && (params->mem_entries != NULL)
+ && (params->num_mem_entries > 0)) {
+ /* Allocate memory for, and copy mem_entries table*/
+ object->params.mem_entries = vmalloc(sizeof(struct
+ proc4430_mem_entry) *
+ params->num_mem_entries);
+ memcpy(object->params.mem_entries,
+ params->mem_entries,
+ (sizeof(struct proc4430_mem_entry) *
+ params->num_mem_entries));
+ }
+ handle->boot_mode = PROC_MGR_BOOTMODE_NOLOAD;
+ /* Set the handle in the state object. */
+ proc4430_state.proc_handles[proc_id] = handle;
+ }
+
+func_end:
+ mutex_unlock(proc4430_state.gate_handle);
+error:
+ return (void *)handle;
+}
+EXPORT_SYMBOL(proc4430_create);
+
+/*=================================================
+ * Function to delete an instance of this Processor.
+ *
+ * The user provided pointer to the handle is reset after
+ * successful completion of this function.
+ *
+ */
+int proc4430_delete(void **handle_ptr)
+{
+ int retval = 0;
+ struct proc4430_object *object = NULL;
+ struct processor_object *handle;
+
+ BUG_ON(handle_ptr == NULL);
+ BUG_ON(*handle_ptr == NULL);
+
+ if (atomic_cmpmask_and_lt(&proc4430_state.ref_count,
+ OMAP4430PROC_MAKE_MAGICSTAMP(0),
+ OMAP4430PROC_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc4430_delete failed Module not initialized");
+ return -ENODEV;
+ }
+
+ handle = (struct processor_object *)(*handle_ptr);
+ BUG_ON(!IS_VALID_PROCID(handle->proc_id));
+ /* Enter critical section protection. */
+ WARN_ON(mutex_lock_interruptible(proc4430_state.gate_handle));
+ /* Reset handle in PwrMgr handle array. */
+ proc4430_state.proc_handles[handle->proc_id] = NULL;
+ /* Free memory used for the OMAP4430 object. */
+ if (handle->object != NULL) {
+ object = (struct proc4430_object *)handle->object;
+ if (object->params.mem_entries != NULL) {
+ vfree(object->params.mem_entries);
+ object->params.mem_entries = NULL;
+ }
+ vfree(handle->object);
+ handle->object = NULL;
+ }
+ /* Free memory used for the Processor object. */
+ vfree(handle);
+ *handle_ptr = NULL;
+ /* Leave critical section protection. */
+ mutex_unlock(proc4430_state.gate_handle);
+ return retval;
+}
+EXPORT_SYMBOL(proc4430_delete);
+
+/*===================================================
+ * Function to open a handle to an instance of this Processor. This
+ * function is called when access to the Processor is required from
+ * a different process.
+ */
+int proc4430_open(void **handle_ptr, u16 proc_id)
+{
+ int retval = 0;
+
+ BUG_ON(handle_ptr == NULL);
+ BUG_ON(!IS_VALID_PROCID(proc_id));
+
+ if (atomic_cmpmask_and_lt(&proc4430_state.ref_count,
+ OMAP4430PROC_MAKE_MAGICSTAMP(0),
+ OMAP4430PROC_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc4430_open failed Module not initialized");
+ return -ENODEV;
+ }
+
+ /* Initialize return parameter handle. */
+ *handle_ptr = NULL;
+
+ /* Check if the PwrMgr exists and return the handle if found. */
+ if (proc4430_state.proc_handles[proc_id] == NULL) {
+ retval = -ENODEV;
+ goto func_exit;
+ } else
+ *handle_ptr = proc4430_state.proc_handles[proc_id];
+func_exit:
+ return retval;
+}
+EXPORT_SYMBOL(proc4430_open);
+
+/*===============================================
+ * Function to close a handle to an instance of this Processor.
+ *
+ */
+int proc4430_close(void *handle)
+{
+ int retval = 0;
+
+ BUG_ON(handle == NULL);
+
+ if (atomic_cmpmask_and_lt(&proc4430_state.ref_count,
+ OMAP4430PROC_MAKE_MAGICSTAMP(0),
+ OMAP4430PROC_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc4430_close failed Module not initialized");
+ return -ENODEV;
+ }
+
+ /* nothing to be done for now */
+ return retval;
+}
+EXPORT_SYMBOL(proc4430_close);
+
+/* =================================
+ * APIs called by Processor module (part of function table interface)
+ * =================================
+ */
+/*================================
+ * Function to initialize the slave processor
+ *
+ */
+int proc4430_attach(void *handle, struct processor_attach_params *params)
+{
+ int retval = 0;
+
+ struct processor_object *proc_handle = NULL;
+ struct proc4430_object *object = NULL;
+ u32 map_count = 0;
+ u32 i;
+ memory_map_info map_info;
+
+ if (atomic_cmpmask_and_lt(&proc4430_state.ref_count,
+ OMAP4430PROC_MAKE_MAGICSTAMP(0),
+ OMAP4430PROC_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc4430_attach failed Module not initialized");
+ return -ENODEV;
+ }
+
+ if (WARN_ON(handle == NULL)) {
+ pr_err("proc4430_attach failed Driver handle is NULL");
+ return -EINVAL;
+ }
+
+ if (WARN_ON(params == NULL)) {
+ pr_err("proc4430_attach failed"
+ "Argument processor_attach_params * is NULL");
+ return -EINVAL;
+ }
+
+ proc_handle = (struct processor_object *)handle;
+
+ object = (struct proc4430_object *)proc_handle->object;
+
+ atomic_cmpmask_and_set(&object->attach_count,
+ OMAP4430PROC_MAKE_MAGICSTAMP(0),
+ OMAP4430PROC_MAKE_MAGICSTAMP(0));
+ atomic_inc_return(&object->attach_count);
+
+ pr_err("proc4430_attach num_mem_entries = %d",
+ object->params.num_mem_entries);
+ /* Return memory information in params. */
+ for (i = 0; (i < object->params.num_mem_entries); i++) {
+ /* If the configured master virtual address is invalid, get the
+ * actual address by mapping the physical address into master
+ * kernel memory space.
+ */
+ if ((object->params.mem_entries[i].master_virt_addr == (u32)-1)
+ && (object->params.mem_entries[i].shared == true)) {
+ map_info.src = object->params.mem_entries[i].phys_addr;
+ map_info.size = object->params.mem_entries[i].size;
+ map_info.is_cached = false;
+ retval = platform_mem_map(&map_info);
+ if (retval != 0) {
+ pr_err("proc4430_attach failed\n");
+ return -EFAULT;
+ }
+ map_count++;
+ object->params.mem_entries[i].master_virt_addr =
+ map_info.dst;
+ params->mem_entries[i].addr
+ [PROC_MGR_ADDRTYPE_MASTERKNLVIRT] =
+ map_info.dst;
+ params->mem_entries[i].addr
+ [PROC_MGR_ADDRTYPE_SLAVEVIRT] =
+ (object->params.mem_entries[i].slave_virt_addr);
+ /* User virtual will be filled by user side. For now,
+ fill in the physical address so that it can be used
+ by mmap to remap this region into user-space */
+ params->mem_entries[i].addr
+ [PROC_MGR_ADDRTYPE_MASTERUSRVIRT] = \
+ object->params.mem_entries[i].phys_addr;
+ params->mem_entries[i].size =
+ object->params.mem_entries[i].size;
+ }
+ }
+ params->num_mem_entries = map_count;
+ return retval;
+}
+
+
+/*==========================================
+ * Function to detach from the Processor.
+ *
+ */
+int proc4430_detach(void *handle)
+{
+ struct processor_object *proc_handle = NULL;
+ struct proc4430_object *object = NULL;
+ u32 i;
+ memory_unmap_info unmap_info;
+
+ if (atomic_cmpmask_and_lt(&proc4430_state.ref_count,
+ OMAP4430PROC_MAKE_MAGICSTAMP(0),
+ OMAP4430PROC_MAKE_MAGICSTAMP(1))
+ == true) {
+
+ pr_err("proc4430_detach failed Module not initialized");
+ return -ENODEV;
+ }
+ if (WARN_ON(handle == NULL)) {
+ pr_err("proc4430_detach failed "
+ "Argument Driverhandle is NULL");
+ return -EINVAL;
+ }
+
+ proc_handle = (struct processor_object *)handle;
+ object = (struct proc4430_object *)proc_handle->object;
+
+ if (!(atomic_dec_return(&object->attach_count) == \
+ OMAP4430PROC_MAKE_MAGICSTAMP(0)))
+ return 1;
+
+ for (i = 0; (i < object->params.num_mem_entries); i++) {
+ if ((object->params.mem_entries[i].master_virt_addr > 0)
+ && (object->params.mem_entries[i].shared == true)) {
+ unmap_info.addr =
+ object->params.mem_entries[i].master_virt_addr;
+ unmap_info.size = object->params.mem_entries[i].size;
+ platform_mem_unmap(&unmap_info);
+ object->params.mem_entries[i].master_virt_addr =
+ (u32)-1;
+ }
+ }
+ return 0;
+}
+
+
+/*==============================================
+ * Function to read from the slave processor's memory.
+ *
+ * Read from the slave processor's memory and copy into the
+ * provided buffer.
+ */
+int proc4430_read(void *handle, u32 proc_addr, u32 *num_bytes,
+ void *buffer)
+{
+ int retval = 0;
+ if (atomic_cmpmask_and_lt(&proc4430_state.ref_count,
+ OMAP4430PROC_MAKE_MAGICSTAMP(0),
+ OMAP4430PROC_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc4430_read failed Module not initialized");
+ return -ENODEV;
+ }
+
+ buffer = memcpy(buffer, (void *)proc_addr, *num_bytes);
+
+ return retval;
+}
+
+
+/*==============================================
+ * Function to write into the slave processor's memory.
+ *
+ * Read from the provided buffer and copy into the slave
+ * processor's memory.
+ *
+ */
+int proc4430_write(void *handle, u32 proc_addr, u32 *num_bytes,
+ void *buffer)
+{
+ int retval = 0;
+
+ if (atomic_cmpmask_and_lt(&proc4430_state.ref_count,
+ OMAP4430PROC_MAKE_MAGICSTAMP(0),
+ OMAP4430PROC_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc4430_write failed Module not initialized");
+ return -ENODEV;
+ }
+
+ proc_addr = (u32)memcpy((void *)proc_addr, buffer, *num_bytes);
+
+ return retval;
+}
+
+
+/*=========================================================
+ * Function to perform device-dependent operations.
+ *
+ * Performs device-dependent control operations as exposed by this
+ * implementation of the Processor module.
+ */
+int proc4430_control(void *handle, int cmd, void *arg)
+{
+ int retval = 0;
+
+ /*FIXME: Remove handle,etc if not used */
+
+#ifdef CONFIG_SYSLINK_DUCATI_PM
+ /* Just for testing purpose */
+ switch (cmd) {
+ case PM_SUSPEND:
+ retval = ipu_pm_notifications(APP_M3, cmd, NULL);
+ retval = ipu_pm_notifications(SYS_M3, cmd, NULL);
+ ipu_pm_save_ctx(SYS_M3);
+ break;
+ case PM_RESUME:
+ retval = ipu_pm_notifications(APP_M3, cmd, NULL);
+ retval = ipu_pm_notifications(SYS_M3, cmd, NULL);
+ break;
+ default:
+ pr_err("Invalid notification\n");
+ }
+ if (retval != PM_SUCCESS)
+ pr_err("Error in notifications\n");
+#endif
+
+ if (atomic_cmpmask_and_lt(&proc4430_state.ref_count,
+ OMAP4430PROC_MAKE_MAGICSTAMP(0),
+ OMAP4430PROC_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc4430_control failed Module not initialized");
+ return -ENODEV;
+ }
+
+ return retval;
+}
+
+
+/*=====================================================
+ * Function to translate between two types of address spaces.
+ *
+ * Translate between the specified address spaces.
+ */
+int proc4430_translate_addr(void *handle,
+ void **dst_addr, enum proc_mgr_addr_type dst_addr_type,
+ void *src_addr, enum proc_mgr_addr_type src_addr_type)
+{
+ int retval = 0;
+ struct processor_object *proc_handle = NULL;
+ struct proc4430_object *object = NULL;
+ struct proc4430_mem_entry *entry = NULL;
+ bool found = false;
+ u32 fm_addr_base = (u32)NULL;
+ u32 to_addr_base = (u32)NULL;
+ u32 i;
+
+ if (atomic_cmpmask_and_lt(&proc4430_state.ref_count,
+ OMAP4430PROC_MAKE_MAGICSTAMP(0),
+ OMAP4430PROC_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc4430_translate_addr failed Module not initialized");
+ retval = -ENODEV;
+ goto error_exit;
+ }
+
+ if (WARN_ON(handle == NULL)) {
+ retval = -EINVAL;
+ goto error_exit;
+ }
+ if (WARN_ON(dst_addr == NULL)) {
+ retval = -EINVAL;
+ goto error_exit;
+ }
+ if (WARN_ON(dst_addr_type > PROC_MGR_ADDRTYPE_ENDVALUE)) {
+ retval = -EINVAL;
+ goto error_exit;
+ }
+ if (WARN_ON(src_addr == NULL)) {
+ retval = -EINVAL;
+ goto error_exit;
+ }
+ if (WARN_ON(src_addr_type > PROC_MGR_ADDRTYPE_ENDVALUE)) {
+ retval = -EINVAL;
+ goto error_exit;
+ }
+
+ proc_handle = (struct processor_object *)handle;
+ object = (struct proc4430_object *)proc_handle->object;
+ *dst_addr = NULL;
+ for (i = 0 ; i < object->params.num_mem_entries ; i++) {
+ entry = &(object->params.mem_entries[i]);
+ fm_addr_base =
+ (src_addr_type == PROC_MGR_ADDRTYPE_MASTERKNLVIRT) ?
+ entry->master_virt_addr : entry->slave_virt_addr;
+ to_addr_base =
+ (dst_addr_type == PROC_MGR_ADDRTYPE_MASTERKNLVIRT) ?
+ entry->master_virt_addr : entry->slave_virt_addr;
+ /* Determine whether which way to convert */
+ if (((u32)src_addr < (fm_addr_base + entry->size)) &&
+ ((u32)src_addr >= fm_addr_base)) {
+ found = true;
+ *dst_addr = (void *)(((u32)src_addr - fm_addr_base)
+ + to_addr_base);
+ break;
+ }
+ }
+
+ /* This check must not be removed even with build optimize. */
+ if (WARN_ON(found == false)) {
+ /*Failed to translate address. */
+ retval = -ENXIO;
+ goto error_exit;
+ }
+ return 0;
+
+error_exit:
+ return retval;
+}
+
+
+/*=================================================
+ * Function to return list of translated mem entries
+ *
+ * This function takes the remote processor address as
+ * an input and returns the mapped Page entries in the
+ * buffer passed
+ */
+int proc4430_virt_to_phys(void *handle, u32 da, u32 *mapped_entries,
+ u32 num_of_entries)
+{
+ int da_align;
+ int i;
+ int ret_val = 0;
+
+ if (atomic_cmpmask_and_lt(&proc4430_state.ref_count,
+ OMAP4430PROC_MAKE_MAGICSTAMP(0),
+ OMAP4430PROC_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc4430_virt_to_phys failed Module not initialized");
+ ret_val = -EFAULT;
+ goto error_exit;
+ }
+
+ if (handle == NULL || mapped_entries == NULL || num_of_entries == 0) {
+ ret_val = -EFAULT;
+ goto error_exit;
+ }
+ da_align = PG_ALIGN_LOW((u32)da, PAGE_SIZE);
+ for (i = 0; i < num_of_entries; i++) {
+ mapped_entries[i] = da_align;
+ da_align += PAGE_SIZE;
+ }
+ return 0;
+
+error_exit:
+ pr_warn("proc4430_virtToPhys failed !!!!\n");
+ return ret_val;
+}
+
+
+/*=================================================
+ * Function to return PROC4430 mem_entries info
+ *
+ */
+int proc4430_proc_info(void *handle, struct proc_mgr_proc_info *procinfo)
+{
+ struct processor_object *proc_handle = NULL;
+ struct proc4430_object *object = NULL;
+ struct proc4430_mem_entry *entry = NULL;
+ int i;
+
+ if (atomic_cmpmask_and_lt(&proc4430_state.ref_count,
+ OMAP4430PROC_MAKE_MAGICSTAMP(0),
+ OMAP4430PROC_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc4430_proc_info failed Module not initialized");
+ goto error_exit;
+ }
+
+ if (WARN_ON(handle == NULL))
+ goto error_exit;
+ if (WARN_ON(procinfo == NULL))
+ goto error_exit;
+
+ proc_handle = (struct processor_object *)handle;
+
+ object = (struct proc4430_object *)proc_handle->object;
+
+ for (i = 0 ; i < object->params.num_mem_entries ; i++) {
+ entry = &(object->params.mem_entries[i]);
+ procinfo->mem_entries[i].addr[PROC_MGR_ADDRTYPE_MASTERKNLVIRT]
+ = entry->master_virt_addr;
+ procinfo->mem_entries[i].addr[PROC_MGR_ADDRTYPE_SLAVEVIRT]
+ = entry->slave_virt_addr;
+ procinfo->mem_entries[i].size = entry->size;
+ }
+ procinfo->num_mem_entries = object->params.num_mem_entries;
+ procinfo->boot_mode = proc_handle->boot_mode;
+ return 0;
+
+error_exit:
+ pr_warn("proc4430_proc_info failed !!!!\n");
+ return -EFAULT;
+}
diff --git a/drivers/dsp/syslink/procmgr/proc4430/proc4430.h b/drivers/dsp/syslink/procmgr/proc4430/proc4430.h
new file mode 100644
index 00000000000..e264f473aa0
--- /dev/null
+++ b/drivers/dsp/syslink/procmgr/proc4430/proc4430.h
@@ -0,0 +1,133 @@
+/*
+ * proc4430.h
+ *
+ * Syslink driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2009-2010 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 _SYSLINK_PROC_4430_H_
+#define _SYSLINK_PROC_4430_H_
+
+
+/* Module headers */
+#include <procmgr.h>
+#include "../procdefs.h"
+#include <linux/types.h>
+
+/*
+ Module configuration structure.
+ */
+struct proc4430_config {
+ struct mutex *gate_handle;
+ /* void * of gate to be used for local thread safety */
+};
+
+/*
+ Memory entry for slave memory map configuration
+ */
+struct proc4430_mem_entry {
+ char name[PROCMGR_MAX_STRLEN];
+ /* Name identifying the memory region. */
+ u32 phys_addr;
+ /* Physical address of the memory region. */
+ u32 slave_virt_addr;
+ /* Slave virtual address of the memory region. */
+ u32 master_virt_addr;
+ /* Master virtual address of the memory region. If specified as -1,
+ * the master virtual address is assumed to be invalid, and shall be
+ * set internally within the Processor module. */
+ u32 size;
+ /* Size (in bytes) of the memory region. */
+ bool shared;
+ /* Flag indicating whether the memory region is shared between master
+ * and slave. */
+};
+
+/*
+ Configuration parameters specific to this processor.
+ */
+struct proc4430_params {
+ int num_mem_entries;
+ /* Number of memory regions to be configured. */
+ struct proc4430_mem_entry *mem_entries;
+ /* Array of information structures for memory regions
+ * to be configured. */
+ u32 reset_vector_mem_entry;
+ /* Index of the memory entry within the mem_entries array,
+ * which is the resetVector memory region. */
+};
+
+
+/* Function to initialize the slave processor */
+int proc4430_attach(void *handle, struct processor_attach_params *params);
+
+/* Function to finalize the slave processor */
+int proc4430_detach(void *handle);
+
+
+/* Function to read from the slave processor's memory. */
+int proc4430_read(void *handle, u32 proc_addr, u32 *num_bytes,
+ void *buffer);
+
+/* Function to write into the slave processor's memory. */
+int proc4430_write(void *handle, u32 proc_addr, u32 *num_bytes,
+ void *buffer);
+
+/* Function to perform device-dependent operations. */
+int proc4430_control(void *handle, int cmd, void *arg);
+
+/* Function to translate between two types of address spaces. */
+int proc4430_translate_addr(void *handle, void **dst_addr,
+ enum proc_mgr_addr_type dst_addr_type,
+ void *src_addr, enum proc_mgr_addr_type src_addr_type);
+
+/* Function to retrive physical address translations */
+int proc4430_virt_to_phys(void *handle, u32 da, u32 *mapped_entries,
+ u32 num_of_entries);
+
+/* =================================================
+ * APIs
+ * =================================================
+ */
+
+/* Function to get the default configuration for the OMAP4430PROC module */
+void proc4430_get_config(struct proc4430_config *cfg);
+
+/* Function to setup the OMAP4430PROC module. */
+int proc4430_setup(struct proc4430_config *cfg);
+
+/* Function to destroy the OMAP4430PROC module. */
+int proc4430_destroy(void);
+
+/* Function to initialize the parameters for this processor instance. */
+void proc4430_params_init(void *handle,
+ struct proc4430_params *params);
+
+/* Function to create an instance of this processor. */
+void *proc4430_create(u16 proc_id, const struct proc4430_params *params);
+
+/* Function to delete an instance of this processor. */
+int proc4430_delete(void **handle_ptr);
+
+/* Function to open an instance of this processor. */
+int proc4430_open(void **handle_ptr, u16 proc_id);
+
+/* Function to close an instance of this processor. */
+int proc4430_close(void *handle);
+
+/* Function to get the proc info */
+int proc4430_proc_info(void *handle, struct proc_mgr_proc_info *procinfo);
+
+#endif
diff --git a/drivers/dsp/syslink/procmgr/proc4430/proc4430_drv.c b/drivers/dsp/syslink/procmgr/proc4430/proc4430_drv.c
new file mode 100644
index 00000000000..9a334b372a3
--- /dev/null
+++ b/drivers/dsp/syslink/procmgr/proc4430/proc4430_drv.c
@@ -0,0 +1,433 @@
+/*
+ * proc4430_drv.c
+ *
+ * Syslink driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2009-2010 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 <generated/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+
+
+/* Module headers */
+#include "proc4430.h"
+#include "proc4430_drvdefs.h"
+
+
+
+/** ============================================================================
+ * Macros and types
+ * ============================================================================
+ */
+#define PROC4430_NAME "syslink-proc4430"
+
+static char *driver_name = PROC4430_NAME;
+
+static s32 driver_major;
+
+static s32 driver_minor;
+
+struct proc_4430_dev {
+ struct cdev cdev;
+};
+
+static struct proc_4430_dev *proc_4430_device;
+
+static struct class *proc_4430_class;
+
+
+
+/** ============================================================================
+ * Forward declarations of internal functions
+ * ============================================================================
+ */
+/* Linux driver function to open the driver object. */
+static int proc4430_drv_open(struct inode *inode, struct file *filp);
+
+/* Linux driver function to close the driver object. */
+static int proc4430_drv_release(struct inode *inode, struct file *filp);
+
+/* Linux driver function to invoke the APIs through ioctl. */
+static long proc4430_drv_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long args);
+
+/* Linux driver function to map memory regions to user space. */
+static int proc4430_drv_mmap(struct file *filp,
+ struct vm_area_struct *vma);
+
+/* Module initialization function for Linux driver. */
+static int __init proc4430_drv_initializeModule(void);
+
+/* Module finalization function for Linux driver. */
+static void __exit proc4430_drv_finalizeModule(void);
+
+
+/* Process Context */
+struct proc4430_process_context {
+ u32 setup_count;
+};
+
+/** ============================================================================
+ * Globals
+ * ============================================================================
+ */
+
+/*
+ File operations table for PROC4430.
+ */
+static const struct file_operations proc_4430_fops = {
+ .open = proc4430_drv_open,
+ .release = proc4430_drv_release,
+ .unlocked_ioctl = proc4430_drv_ioctl,
+ .mmap = proc4430_drv_mmap,
+};
+
+static int proc4430_drv_open(struct inode *inode, struct file *filp)
+{
+ s32 retval = 0;
+ struct proc4430_process_context *pr_ctxt = NULL;
+
+ pr_ctxt = kzalloc(sizeof(struct proc4430_process_context), GFP_KERNEL);
+ if (!pr_ctxt)
+ retval = -ENOMEM;
+
+ filp->private_data = pr_ctxt;
+ return retval;
+}
+
+static int proc4430_drv_release(struct inode *inode, struct file *filp)
+{
+ s32 retval = 0;
+ struct proc4430_process_context *pr_ctxt;
+
+ if (!filp->private_data) {
+ retval = -EIO;
+ goto err;
+ }
+
+ pr_ctxt = filp->private_data;
+ while (pr_ctxt->setup_count-- > 0) {
+ /* Destroy has not been called. Call destroy now. */
+ proc4430_destroy();
+ }
+ kfree(pr_ctxt);
+
+ filp->private_data = NULL;
+err:
+ return retval;
+}
+
+
+/*
+ Linux driver function to invoke the APIs through ioctl.
+ *
+ */
+static long proc4430_drv_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long args)
+{
+ int retval = 0;
+ struct proc_mgr_cmd_args *cmd_args = (struct proc_mgr_cmd_args *)args;
+ struct proc_mgr_cmd_args command_args;
+ struct proc4430_process_context *pr_ctxt =
+ (struct proc4430_process_context *)filp->private_data;
+
+ switch (cmd) {
+ case CMD_PROC4430_GETCONFIG:
+ {
+ struct proc4430_cmd_args_get_config *src_args =
+ (struct proc4430_cmd_args_get_config *)args;
+ struct proc4430_config cfg;
+
+ /* copy_from_useris not needed for
+ * proc4430_get_config, since the
+ * user's config is not used.
+ */
+ proc4430_get_config(&cfg);
+
+ retval = copy_to_user((void __user *)(src_args->cfg),
+ (const void *)&cfg,
+ sizeof(struct proc4430_config));
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ }
+ break;
+
+ case CMD_PROC4430_SETUP:
+ {
+ struct proc4430_cmd_args_setup *src_args =
+ (struct proc4430_cmd_args_setup *)args;
+ struct proc4430_config cfg;
+
+ retval = copy_from_user((void *)&cfg,
+ (const void __user *)(src_args->cfg),
+ sizeof(struct proc4430_config));
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ proc4430_setup(&cfg);
+ pr_ctxt->setup_count++;
+ }
+ break;
+
+ case CMD_PROC4430_DESTROY:
+ {
+ proc4430_destroy();
+ pr_ctxt->setup_count--;
+ }
+ break;
+
+ case CMD_PROC4430_PARAMS_INIT:
+ {
+ struct proc4430_cmd_args_params_init src_args;
+ struct proc4430_params params;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc4430_cmd_args_params_init));
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ proc4430_params_init(src_args.handle, &params);
+ retval = copy_to_user((void __user *)(src_args.params),
+ (const void *) &params,
+ sizeof(struct proc4430_params));
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ }
+ break;
+
+ case CMD_PROC4430_CREATE:
+ {
+ struct proc4430_cmd_args_create src_args;
+ struct proc4430_params params;
+ struct proc4430_mem_entry *entries = NULL;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc4430_cmd_args_create));
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ retval = copy_from_user((void *) &params,
+ (const void __user *)(src_args.params),
+ sizeof(struct proc4430_params));
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ /* Copy the contents of mem_entries from user-side */
+ if (params.num_mem_entries) {
+ entries = vmalloc(params.num_mem_entries * \
+ sizeof(struct proc4430_mem_entry));
+ if (WARN_ON(!entries))
+ goto func_exit;
+ retval = copy_from_user((void *) (entries),
+ (const void __user *)(params.mem_entries),
+ params.num_mem_entries * \
+ sizeof(struct proc4430_mem_entry));
+ if (WARN_ON(retval < 0)) {
+ vfree(entries);
+ goto func_exit;
+ }
+ params.mem_entries = entries;
+ }
+ src_args.handle = proc4430_create(src_args.proc_id,
+ &params);
+ if (WARN_ON(src_args.handle == NULL))
+ goto func_exit;
+ retval = copy_to_user((void __user *)(args),
+ (const void *)&src_args,
+ sizeof(struct proc4430_cmd_args_create));
+ /* Free the memory created */
+ if (params.num_mem_entries)
+ vfree(entries);
+ }
+ break;
+
+ case CMD_PROC4430_DELETE:
+ {
+ struct proc4430_cmd_args_delete src_args;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc4430_cmd_args_delete));
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ retval = proc4430_delete(&(src_args.handle));
+ WARN_ON(retval < 0);
+ }
+ break;
+
+ case CMD_PROC4430_OPEN:
+ {
+ struct proc4430_cmd_args_open src_args;
+
+ /*Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc4430_cmd_args_open));
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ retval = proc4430_open(&(src_args.handle),
+ src_args.proc_id);
+ retval = copy_to_user((void __user *)(args),
+ (const void *)&src_args,
+ sizeof(struct proc4430_cmd_args_open));
+ WARN_ON(retval < 0);
+ }
+ break;
+
+ case CMD_PROC4430_CLOSE:
+ {
+ struct proc4430_cmd_args_close src_args;
+
+ /*Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc4430_cmd_args_close));
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ retval = proc4430_close(src_args.handle);
+ WARN_ON(retval < 0);
+ }
+ break;
+
+ default:
+ {
+ pr_err("unsupported ioctl\n");
+ }
+ break;
+ }
+func_exit:
+ /* Set the status and copy the common args to user-side. */
+ command_args.api_status = retval;
+ retval = copy_to_user((void __user *) cmd_args,
+ (const void *) &command_args,
+ sizeof(struct proc_mgr_cmd_args));
+ WARN_ON(retval < 0);
+ return retval;
+}
+
+
+/*
+ Linux driver function to map memory regions to user space.
+ *
+ */
+static int proc4430_drv_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ vma->vm_page_prot = pgprot_dmacoherent(vma->vm_page_prot);
+
+ if (remap_pfn_range(vma,
+ vma->vm_start,
+ vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+
+/** ==================================================================
+ * Functions required for multiple .ko modules configuration
+ * ==================================================================
+ */
+/*
+ Module initialization function for Linux driver.
+ */
+static int __init proc4430_drv_initializeModule(void)
+{
+ dev_t dev = 0 ;
+ int retval;
+
+ /* Display the version info and created date/time */
+ pr_info("proc4430_drv_initializeModule\n");
+
+ if (driver_major) {
+ dev = MKDEV(driver_major, driver_minor);
+ retval = register_chrdev_region(dev, 1, driver_name);
+ } else {
+ retval = alloc_chrdev_region(&dev, driver_minor, 1,
+ driver_name);
+ driver_major = MAJOR(dev);
+ }
+
+ proc_4430_device = kmalloc(sizeof(struct proc_4430_dev), GFP_KERNEL);
+ if (!proc_4430_device) {
+ retval = -ENOMEM;
+ unregister_chrdev_region(dev, 1);
+ goto exit;
+ }
+ memset(proc_4430_device, 0, sizeof(struct proc_4430_dev));
+ cdev_init(&proc_4430_device->cdev, &proc_4430_fops);
+ proc_4430_device->cdev.owner = THIS_MODULE;
+ proc_4430_device->cdev.ops = &proc_4430_fops;
+
+ retval = cdev_add(&proc_4430_device->cdev, dev, 1);
+
+ if (retval) {
+ pr_err("Failed to add the syslink proc_4430 device\n");
+ goto exit;
+ }
+
+ /* udev support */
+ proc_4430_class = class_create(THIS_MODULE, "syslink-proc4430");
+
+ if (IS_ERR(proc_4430_class)) {
+ pr_err("Error creating bridge class\n");
+ goto exit;
+ }
+ device_create(proc_4430_class, NULL, MKDEV(driver_major, driver_minor),
+ NULL, PROC4430_NAME);
+exit:
+ return 0;
+}
+
+/*
+ function to finalize the driver module.
+ */
+static void __exit proc4430_drv_finalizeModule(void)
+{
+ dev_t devno = 0;
+
+ /* FIX ME: THIS MIGHT NOT BE THE RIGHT PLACE TO CALL THE SETUP */
+ proc4430_destroy();
+
+ devno = MKDEV(driver_major, driver_minor);
+ if (proc_4430_device) {
+ cdev_del(&proc_4430_device->cdev);
+ kfree(proc_4430_device);
+ }
+ unregister_chrdev_region(devno, 1);
+ if (proc_4430_class) {
+ /* remove the device from sysfs */
+ device_destroy(proc_4430_class, MKDEV(driver_major,
+ driver_minor));
+ class_destroy(proc_4430_class);
+ }
+ return;
+}
+
+/*
+ Macro calls that indicate initialization and finalization functions
+ * to the kernel.
+ */
+MODULE_LICENSE("GPL v2");
+module_init(proc4430_drv_initializeModule);
+module_exit(proc4430_drv_finalizeModule);
diff --git a/drivers/dsp/syslink/procmgr/proc4430/proc4430_drvdefs.h b/drivers/dsp/syslink/procmgr/proc4430/proc4430_drvdefs.h
new file mode 100644
index 00000000000..4176d731f1d
--- /dev/null
+++ b/drivers/dsp/syslink/procmgr/proc4430/proc4430_drvdefs.h
@@ -0,0 +1,169 @@
+/*
+ * proc4430_drvdefs.h
+ *
+ * Syslink driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2009-2010 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 _SYSLINK_PROC4430_H
+#define _SYSLINK_PROC4430_H
+
+
+/* Module headers */
+#include "../procmgr_drvdefs.h"
+#include "proc4430.h"
+
+
+/* ----------------------------------------------------------------------------
+ * IOCTL command IDs for OMAP4430PROC
+ * ----------------------------------------------------------------------------
+ */
+/*
+ * Base command ID for OMAP4430PROC
+ */
+#define PROC4430_BASE_CMD 0x200
+
+/*
+ * Command for PROC4430_getConfig
+ */
+#define CMD_PROC4430_GETCONFIG (PROC4430_BASE_CMD + 1)
+
+/*
+ * Command for PROC4430_setup
+ */
+#define CMD_PROC4430_SETUP (PROC4430_BASE_CMD + 2)
+
+/*
+ * Command for PROC4430_setup
+ */
+#define CMD_PROC4430_DESTROY (PROC4430_BASE_CMD + 3)
+
+/*
+ * Command for PROC4430_destroy
+ */
+#define CMD_PROC4430_PARAMS_INIT (PROC4430_BASE_CMD + 4)
+
+/*
+ * Command for PROC4430_create
+ */
+#define CMD_PROC4430_CREATE (PROC4430_BASE_CMD + 5)
+
+/*
+ * Command for PROC4430_delete
+ */
+#define CMD_PROC4430_DELETE (PROC4430_BASE_CMD + 6)
+
+/*
+ * Command for PROC4430_open
+ */
+#define CMD_PROC4430_OPEN (PROC4430_BASE_CMD + 7)
+
+/*
+ * Command for PROC4430_close
+ */
+#define CMD_PROC4430_CLOSE (PROC4430_BASE_CMD + 8)
+
+
+/* ---------------------------------------------------
+ * Command arguments for OMAP4430PROC
+ * ---------------------------------------------------
+ */
+/*
+ * Command arguments for PROC4430_getConfig
+ */
+struct proc4430_cmd_args_get_config {
+ struct proc_mgr_cmd_args command_args;
+ /* Common command args */
+ struct proc4430_config *cfg;
+ /* Pointer to the OMAP4430PROC module configuration structure
+ * in which the default config is to be returned. */
+};
+
+/*
+ * Command arguments for PROC4430_setup
+ */
+struct proc4430_cmd_args_setup {
+ struct proc_mgr_cmd_args command_args;
+ /* Common command args */
+ struct proc4430_config *cfg;
+ /* Optional OMAP4430PROC module configuration. If provided as NULL,
+ * default configuration is used. */
+};
+
+/*
+ * Command arguments for PROC4430_destroy
+ */
+struct proc4430_cmd_args_destroy {
+ struct proc_mgr_cmd_args command_args;
+ /* Common command args */
+};
+
+/*
+ * Command arguments for struct struct proc4430_params_init
+ */
+struct proc4430_cmd_args_params_init {
+ struct proc_mgr_cmd_args command_args;
+ /* Common command args */
+ void *handle;
+ /* void * to the processor instance. */
+ struct proc4430_params *params;
+ /* Configuration parameters. */
+};
+
+/*
+ * Command arguments for PROC4430_create
+ */
+struct proc4430_cmd_args_create {
+ struct proc_mgr_cmd_args command_args;
+ /* Common command args */
+ u16 proc_id;
+ /* Processor ID for which this processor instance is required. */
+ struct proc4430_params *params;
+ /*Configuration parameters. */
+ void *handle;
+ /* void * to the created processor instance. */
+};
+
+/*
+ * Command arguments for PROC4430_delete
+ */
+struct proc4430_cmd_args_delete {
+ struct proc_mgr_cmd_args command_args;
+ /* Common command args */
+ void *handle;
+ /* Pointer to handle to the processor instance */
+};
+
+/*
+ * Command arguments for PROC4430_open
+ */
+struct proc4430_cmd_args_open {
+ struct proc_mgr_cmd_args command_args;
+ /* Common command args */
+ u16 proc_id;
+ /* Processor ID addressed by this OMAP4430PROC instance. */
+ void *handle;
+ /* Return parameter: void * to the processor instance */
+};
+
+/*
+ * Command arguments for PROC4430_close
+ */
+struct proc4430_cmd_args_close {
+ struct proc_mgr_cmd_args command_args;
+ /* Common command args */
+ void *handle;
+ /* void * to the processor instance */
+};
+
+#endif
diff --git a/drivers/dsp/syslink/procmgr/procdefs.h b/drivers/dsp/syslink/procmgr/procdefs.h
new file mode 100644
index 00000000000..d28025835aa
--- /dev/null
+++ b/drivers/dsp/syslink/procmgr/procdefs.h
@@ -0,0 +1,155 @@
+/*
+ * procdefs.h
+ *
+ * Syslink driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2009-2010 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 SYSLINK_PROCDEFS_H
+#define SYSLINK_PROCDEFS_H
+
+#include <linux/types.h>
+
+/* Module level headers */
+#include <procmgr.h>
+
+
+/* =============================
+ * Macros and types
+ * =============================
+ */
+/*
+ * Enumerates the types of Endianism of slave processor.
+ */
+enum processor_endian{
+ PROCESSOR_ENDIAN_DEFAULT = 0,
+ /* Default endianism (no conversion required) */
+ PROCESSOR_ENDIAN_BIG = 1,
+ /* Big endian */
+ PROCESSOR_ENDIAN_LITTLE = 2,
+ /* Little endian */
+ PROCESSOR_ENDIAN_ENDVALUE = 3
+ /* End delimiter indicating start of invalid values for this enum */
+};
+
+
+/*
+ * Configuration parameters for attaching to the slave Processor
+ */
+struct processor_attach_params {
+ struct proc_mgr_attach_params *params;
+ /* Common attach parameters for ProcMgr */
+ u16 num_mem_entries;
+ /* Number of valid memory entries */
+ struct proc_mgr_addr_info mem_entries[PROCMGR_MAX_MEMORY_REGIONS];
+ /* Configuration of memory regions */
+};
+
+/*
+ * Function pointer type for the function to attach to the processor.
+ */
+typedef int (*processor_attach_fxn) (void *handle,
+ struct processor_attach_params *params);
+
+/*
+ * Function pointer type for the function to detach from the
+ * procssor
+ */
+typedef int (*processor_detach_fxn) (void *handle);
+
+/*
+ * Function pointer type for the function to read from the slave
+ * processor's memory.
+ */
+typedef int (*processor_read_fxn) (void *handle, u32 proc_addr,
+ u32 *num_bytes, void *buffer);
+
+/*
+ *Function pointer type for the function to write into the slave
+ *processor's memory.
+ */
+typedef int (*processor_write_fxn) (void *handle, u32 proc_addr,
+ u32 *num_bytes, void *buffer);
+
+/*
+ *Function pointer type for the function to perform device-dependent
+ * operations.
+ */
+typedef int (*processor_control_fxn) (void *handle, int cmd, void *arg);
+
+/*
+ *Function pointer type for the function to translate between
+ * two types of address spaces.
+ */
+typedef int (*processor_translate_addr_fxn) (void *handle, void **dst_addr,
+ enum proc_mgr_addr_type dstAddrType, void *srcAddr,
+ enum proc_mgr_addr_type srcAddrType);
+
+/*
+ *Function pointer type for the function that returns proc info
+ */
+typedef int (*processor_proc_info) (void *handle,
+ struct proc_mgr_proc_info *proc_info);
+
+/*
+ *Function pointer type for the function that returns proc info
+ */
+typedef int (*processor_virt_to_phys_fxn) (void *handle, u32 da,
+ u32 *mapped_entries, u32 num_of_entries);
+
+
+/* =============================
+ * Function table interface
+ * =============================
+ */
+/*
+ *Function table interface for Processor.
+ */
+struct processor_fxn_table {
+ processor_attach_fxn attach;
+ /* Function to attach to the slave processor */
+ processor_detach_fxn detach;
+ /* Function to detach from the slave processor */
+ processor_read_fxn read;
+ /* Function to read from the slave processor's memory */
+ processor_write_fxn write;
+ /* Function to write into the slave processor's memory */
+ processor_control_fxn control;
+ /* Function to perform device-dependent control function */
+ processor_translate_addr_fxn translateAddr;
+ /* Function to translate between address ranges */
+ processor_proc_info procinfo;
+ /* Function to convert Virtual to Physical pages */
+ processor_virt_to_phys_fxn virt_to_phys;
+};
+
+/* =============================
+ * Processor structure
+ * =============================
+ */
+/*
+ * Generic Processor object. This object defines the handle type for all
+ * Processor operations.
+ */
+struct processor_object {
+ struct processor_fxn_table proc_fxn_table;
+ /* interface function table to plug into the generic Processor. */
+ enum proc_mgr_state state;
+ /* State of the slave processor */
+ enum proc_mgr_boot_mode boot_mode;
+ /* Boot mode for the slave processor. */
+ void *object;
+ /* Pointer to Processor-specific object. */
+ u16 proc_id;
+ /* Processor ID addressed by this Processor instance. */
+};
+#endif
diff --git a/drivers/dsp/syslink/procmgr/processor.c b/drivers/dsp/syslink/procmgr/processor.c
new file mode 100644
index 00000000000..34a2d252b3f
--- /dev/null
+++ b/drivers/dsp/syslink/procmgr/processor.c
@@ -0,0 +1,293 @@
+/*
+ * processor.c
+ *
+ * Syslink driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2009-2010 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 <linux/types.h>
+#include <linux/module.h>
+
+/* Module level headers */
+#include "procdefs.h"
+#include "processor.h"
+
+
+
+/* =========================================
+ * Functions called by ProcMgr
+ * =========================================
+ */
+/*
+ * Function to attach to the Processor.
+ *
+ * This function calls into the specific Processor implementation
+ * to attach to it.
+ * This function is called from the ProcMgr attach function, and
+ * hence is used to perform any activities that may be required
+ * once the slave is powered up.
+ * Depending on the type of Processor, this function may or may not
+ * perform any activities.
+ */
+inline int processor_attach(void *handle,
+ struct processor_attach_params *params)
+{
+ int retval = 0;
+ struct processor_object *proc_handle =
+ (struct processor_object *)handle;
+
+ BUG_ON(handle == NULL);
+ BUG_ON(params == NULL);
+ BUG_ON(proc_handle->proc_fxn_table.attach == NULL);
+
+ proc_handle->boot_mode = params->params->boot_mode;
+ retval = proc_handle->proc_fxn_table.attach(handle, params);
+
+ if (proc_handle->boot_mode == PROC_MGR_BOOTMODE_BOOT)
+ proc_handle->state = PROC_MGR_STATE_POWERED;
+ else if (proc_handle->boot_mode == PROC_MGR_BOOTMODE_NOLOAD)
+ proc_handle->state = PROC_MGR_STATE_LOADED;
+ else if (proc_handle->boot_mode == PROC_MGR_BOOTMODE_NOBOOT)
+ proc_handle->state = PROC_MGR_STATE_RUNNNING;
+ return retval;
+}
+
+
+/*
+ * Function to detach from the Processor.
+ *
+ * This function calls into the specific Processor implementation
+ * to detach from it.
+ * This function is called from the ProcMgr detach function, and
+ * hence is useful to perform any activities that may be required
+ * before the slave is powered down.
+ * Depending on the type of Processor, this function may or may not
+ * perform any activities.
+ */
+inline int processor_detach(void *handle)
+{
+ int retval = 0;
+ struct processor_object *proc_handle =
+ (struct processor_object *)handle;
+
+ BUG_ON(handle == NULL);
+ BUG_ON(proc_handle->proc_fxn_table.detach == NULL);
+
+ retval = proc_handle->proc_fxn_table.detach(handle);
+ /* For all boot modes, at the end of detach, the Processor is in
+ * unknown state.
+ */
+ proc_handle->state = PROC_MGR_STATE_UNKNOWN;
+ return retval;
+}
+
+
+/*
+ * Function to read from the slave processor's memory.
+ *
+ * This function calls into the specific Processor implementation
+ * to read from the slave processor's memory. It reads from the
+ * specified address in the processor's address space and copies
+ * the required number of bytes into the specified buffer.
+ * It returns the number of bytes actually read in the num_bytes
+ * parameter.
+ * Depending on the processor implementation, it may result in
+ * reading from shared memory or across a peripheral physical
+ * connectivity.
+ * The handle specifies the specific Processor instance to be used.
+ */
+inline int processor_read(void *handle, u32 proc_addr,
+ u32 *num_bytes, void *buffer)
+{
+ int retval = 0;
+ struct processor_object *proc_handle =
+ (struct processor_object *)handle;
+
+ BUG_ON(handle == NULL);
+ BUG_ON(proc_addr == 0);
+ BUG_ON(num_bytes == 0);
+ BUG_ON(buffer == NULL);
+ BUG_ON(proc_handle->proc_fxn_table.read == NULL);
+
+ retval = proc_handle->proc_fxn_table.read(handle, proc_addr,
+ num_bytes, buffer);
+ return retval;
+}
+
+
+/*
+ * Function to write into the slave processor's memory.
+ *
+ * This function calls into the specific Processor implementation
+ * to write into the slave processor's memory. It writes into the
+ * specified address in the processor's address space and copies
+ * the required number of bytes from the specified buffer.
+ * It returns the number of bytes actually written in the num_bytes
+ * parameter.
+ * Depending on the processor implementation, it may result in
+ * writing into shared memory or across a peripheral physical
+ * connectivity.
+ * The handle specifies the specific Processor instance to be used.
+ */
+inline int processor_write(void *handle, u32 proc_addr, u32 *num_bytes,
+ void *buffer)
+{
+ int retval = 0;
+ struct processor_object *proc_handle =
+ (struct processor_object *)handle;
+ BUG_ON(handle == NULL);
+ BUG_ON(proc_addr == 0);
+ BUG_ON(num_bytes == 0);
+ BUG_ON(buffer == NULL);
+ BUG_ON(proc_handle->proc_fxn_table.write == NULL);
+
+ retval = proc_handle->proc_fxn_table.write(handle, proc_addr,
+ num_bytes, buffer);
+ return retval;
+}
+
+
+/*
+ * Function to get the current state of the slave Processor.
+ *
+ * This function gets the state of the slave processor as
+ * maintained on the master Processor state machine. It does not
+ * go to the slave processor to get its actual state at the time
+ * when this API is called.
+ */
+enum proc_mgr_state processor_get_state(void *handle)
+{
+ struct processor_object *proc_handle =
+ (struct processor_object *)handle;
+
+ BUG_ON(handle == NULL);
+
+ return proc_handle->state;
+}
+
+
+/*
+ * Function to set the current state of the slave Processor
+ * to specified value.
+ *
+ * This function is used to set the state of the processor to the
+ * value as specified. This function may be used by external
+ * entities that affect the state of the slave processor, such as
+ * PwrMgr, error handler, or ProcMgr.
+ */
+void processor_set_state(void *handle, enum proc_mgr_state state)
+{
+ struct processor_object *proc_handle =
+ (struct processor_object *)handle;
+
+ BUG_ON(handle == NULL);
+ proc_handle->state = state;
+}
+
+
+/*
+ * Function to perform device-dependent operations.
+ *
+ * This function calls into the specific Processor implementation
+ * to perform device dependent control operations. The control
+ * operations supported by the device are exposed directly by the
+ * specific implementation of the Processor interface. These
+ * commands and their specific argument types are used with this
+ * function.
+ */
+inline int processor_control(void *handle, int cmd, void *arg)
+{
+ int retval = 0;
+ struct processor_object *proc_handle =
+ (struct processor_object *)handle;
+
+ BUG_ON(handle == NULL);
+ BUG_ON(proc_handle->proc_fxn_table.control == NULL);
+
+ retval = proc_handle->proc_fxn_table.control(handle, cmd, arg);
+ return retval;
+}
+
+
+/*
+ * Function to translate between two types of address spaces.
+ *
+ * This function translates addresses between two types of address
+ * spaces. The destination and source address types are indicated
+ * through parameters specified in this function.
+ */
+inline int processor_translate_addr(void *handle, void **dst_addr,
+ enum proc_mgr_addr_type dst_addr_type, void *src_addr,
+ enum proc_mgr_addr_type src_addr_type)
+{
+ int retval = 0;
+ struct processor_object *proc_handle =
+ (struct processor_object *)handle;
+
+ BUG_ON(handle == NULL);
+ BUG_ON(dst_addr == NULL);
+ BUG_ON(src_addr == NULL);
+ BUG_ON(dst_addr_type >= PROC_MGR_ADDRTYPE_ENDVALUE);
+ BUG_ON(src_addr_type >= PROC_MGR_ADDRTYPE_ENDVALUE);
+ BUG_ON(proc_handle->proc_fxn_table.translateAddr == NULL);
+
+ retval = proc_handle->proc_fxn_table.translateAddr(handle,
+ dst_addr, dst_addr_type, src_addr, src_addr_type);
+ return retval;
+}
+
+
+/*
+ * Function that registers for notification when the slave
+ * processor transitions to any of the states specified.
+ *
+ * This function allows the user application to register for
+ * changes in processor state and take actions accordingly.
+
+ */
+inline int processor_register_notify(void *handle, proc_mgr_callback_fxn fxn,
+ void *args, enum proc_mgr_state state[])
+{
+ int retval = 0;
+
+ BUG_ON(handle == NULL);
+ BUG_ON(fxn == NULL);
+
+ /* TODO: TBD: To be implemented. */
+ return retval;
+}
+
+/*
+ * Function that returns the proc instance mem info
+ */
+int processor_get_proc_info(void *handle, struct proc_mgr_proc_info *procinfo)
+{
+ struct processor_object *proc_handle =
+ (struct processor_object *)handle;
+ int retval;
+ retval = proc_handle->proc_fxn_table.procinfo(proc_handle, procinfo);
+ return retval;
+}
+
+/*
+ * Function that returns the address translations
+ */
+int processor_virt_to_phys(void *handle, u32 da, u32 *mapped_entries,
+ u32 num_of_entries)
+{
+ struct processor_object *proc_handle =
+ (struct processor_object *)handle;
+ int retval;
+ retval = proc_handle->proc_fxn_table.virt_to_phys(handle, da,
+ mapped_entries, num_of_entries);
+ return retval;
+}
diff --git a/drivers/dsp/syslink/procmgr/processor.h b/drivers/dsp/syslink/procmgr/processor.h
new file mode 100644
index 00000000000..13942e91e84
--- /dev/null
+++ b/drivers/dsp/syslink/procmgr/processor.h
@@ -0,0 +1,70 @@
+/*
+ * processor.h
+ *
+ * Syslink driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2009-2010 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 SYSLINK_PROCESSOR_H_
+#define SYSLINK_PROCESSOR_H_
+
+#include <linux/types.h>
+
+/* Module level headers */
+#include "procdefs.h"
+
+/* ===================================
+ * APIs
+ * ===================================
+ */
+/* Function to attach to the Processor. */
+int processor_attach(void *handle, struct processor_attach_params *params);
+
+/* Function to detach from the Processor. */
+int processor_detach(void *handle);
+
+/* Function to read from the slave processor's memory. */
+int processor_read(void *handle, u32 proc_addr, u32 *num_bytes, void *buffer);
+
+/* Function to read write into the slave processor's memory. */
+int processor_write(void *handle, u32 proc_addr, u32 *num_bytes, void *buffer);
+
+/* Function to get the current state of the slave Processor as maintained on
+ * the master Processor state machine.
+ */
+enum proc_mgr_state processor_get_state(void *handle);
+
+/* Function to set the current state of the slave Processor to specified value.
+ */
+void processor_set_state(void *handle, enum proc_mgr_state state);
+
+/* Function to perform device-dependent operations. */
+int processor_control(void *handle, int cmd, void *arg);
+
+/* Function to translate between two types of address spaces. */
+int processor_translate_addr(void *handle, void **dst_addr,
+ enum proc_mgr_addr_type dst_addr_type, void *src_addr,
+ enum proc_mgr_addr_type src_addr_type);
+
+/* Function that registers for notification when the slave processor
+ * transitions to any of the states specified.
+ */
+int processor_register_notify(void *handle, proc_mgr_callback_fxn fxn,
+ void *args, enum proc_mgr_state state[]);
+
+/* Function that returns the return value of specific processor info
+ */
+int processor_get_proc_info(void *handle, struct proc_mgr_proc_info *procinfo);
+
+int processor_virt_to_phys(void *handle, u32 da, u32 *mapped_entries,
+ u32 num_of_entries);
+#endif
diff --git a/drivers/dsp/syslink/procmgr/procmgr.c b/drivers/dsp/syslink/procmgr/procmgr.c
new file mode 100644
index 00000000000..187f100b4a4
--- /dev/null
+++ b/drivers/dsp/syslink/procmgr/procmgr.c
@@ -0,0 +1,784 @@
+/*
+ * procmgr.c
+ *
+ * Syslink driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2009-2010 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 <linux/types.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <asm/atomic.h>
+
+/* Module level headers */
+#include <procmgr.h>
+#include "procdefs.h"
+#include "processor.h"
+#include <syslink/atomic_linux.h>
+
+/* ================================
+ * Macros and types
+ * ================================
+ */
+/*! @brief Macro to make a correct module magic number with refCount */
+#define PROCMGR_MAKE_MAGICSTAMP(x) ((PROCMGR_MODULEID << 12u) | (x))
+
+/*
+ * ProcMgr Module state object
+ */
+struct proc_mgr_module_object {
+ atomic_t ref_count;
+ u32 config_size;
+ /* Size of configuration structure */
+ struct proc_mgr_config cfg;
+ /* ProcMgr configuration structure */
+ struct proc_mgr_config def_cfg;
+ /* Default module configuration */
+ struct proc_mgr_params def_inst_params;
+ /* Default parameters for the ProcMgr instances */
+ struct proc_mgr_attach_params def_attach_params;
+ /* Default parameters for the ProcMgr attach function */
+ struct mutex *gate_handle;
+ /* handle of gate to be used for local thread safety */
+ void *proc_handles[MULTIPROC_MAXPROCESSORS];
+ /* Array of handles of ProcMgr instances */
+};
+
+/*
+ * ProcMgr instance object
+ */
+struct proc_mgr_object {
+ u16 proc_id;
+ /* Processor ID associated with this ProcMgr. */
+ struct processor_object *proc_handle;
+ /* Processor ID of the processor being represented by this instance. */
+ void *loader_handle;
+ /*!< Handle to the Loader object associated with this ProcMgr. */
+ void *pwr_handle;
+ /*!< Handle to the PwrMgr object associated with this ProcMgr. */
+ /*!< Processor ID of the processor being represented by this instance */
+ struct proc_mgr_params params;
+ /* ProcMgr instance params structure */
+ struct proc_mgr_attach_params attach_params;
+ /* ProcMgr attach params structure */
+ u32 file_id;
+ /*!< File ID of the loaded static executable */
+ u16 num_mem_entries;
+ /* Number of valid memory entries */
+ struct proc_mgr_addr_info mem_entries[PROCMGR_MAX_MEMORY_REGIONS];
+ /* Configuration of memory regions */
+};
+
+static struct proc_mgr_module_object proc_mgr_obj_state = {
+ .config_size = sizeof(struct proc_mgr_config),
+ .def_cfg.gate_handle = NULL,
+ .gate_handle = NULL,
+ .def_inst_params.proc_handle = NULL,
+ .def_attach_params.boot_mode = PROC_MGR_BOOTMODE_BOOT,
+};
+
+
+/*======================================
+ * Function to get the default configuration for the ProcMgr
+ * module.
+ *
+* This function can be called by the application to get their
+* configuration parameter to ProcMgr_setup filled in by the
+* ProcMgr module with the default parameters. If the user does
+* not wish to make any change in the default parameters, this API
+* is not required to be called.
+ */
+void proc_mgr_get_config(struct proc_mgr_config *cfg)
+{
+ BUG_ON(cfg == NULL);
+ memcpy(cfg, &proc_mgr_obj_state.def_cfg,
+ sizeof(struct proc_mgr_config));
+ return;
+}
+EXPORT_SYMBOL(proc_mgr_get_config);
+
+/*
+ * Function to setup the ProcMgr module.
+ *
+ *This function sets up the ProcMgr module. This function must
+ *be called before any other instance-level APIs can be invoked.
+ *Module-level configuration needs to be provided to this
+ *function. If the user wishes to change some specific config
+ *parameters, then ProcMgr_getConfig can be called to get the
+ *configuration filled with the default values. After this, only
+ *the required configuration values can be changed. If the user
+ *does not wish to make any change in the default parameters, the
+ *application can simply call ProcMgr_setup with NULL parameters.
+ *The default parameters would get automatically used.
+ */
+int proc_mgr_setup(struct proc_mgr_config *cfg)
+{
+ int retval = 0;
+ struct proc_mgr_config tmp_cfg;
+
+ /* This sets the refCount variable is not initialized, upper 16 bits is
+ * written with module Id to ensure correctness of refCount variable.
+ */
+ atomic_cmpmask_and_set(&proc_mgr_obj_state.ref_count,
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(0));
+
+ if (atomic_inc_return(&proc_mgr_obj_state.ref_count)
+ != PROCMGR_MAKE_MAGICSTAMP(1u))
+ return 0;
+ if (cfg == NULL) {
+ proc_mgr_get_config(&tmp_cfg);
+ cfg = &tmp_cfg;
+ }
+ if (cfg->gate_handle != NULL) {
+ proc_mgr_obj_state.gate_handle = cfg->gate_handle;
+ } else {
+ /* User has not provided any gate handle, so create a
+ *default handle.
+ */
+ proc_mgr_obj_state.gate_handle = kmalloc(sizeof(struct mutex),
+ GFP_KERNEL);
+ mutex_init(proc_mgr_obj_state.gate_handle);
+ }
+ memcpy(&proc_mgr_obj_state.cfg, cfg, sizeof(struct proc_mgr_config));
+ /* Initialize the procHandles array. */
+ memset(&proc_mgr_obj_state.proc_handles, 0,
+ (sizeof(void *) * MULTIPROC_MAXPROCESSORS));
+ return retval;
+}
+EXPORT_SYMBOL(proc_mgr_setup);
+
+/*==================================
+ * Function to destroy the ProcMgr module.
+ *
+ * Once this function is called, other ProcMgr module APIs, except
+ * for the proc_mgr_get_config API cannot be called anymore.
+ */
+int proc_mgr_destroy(void)
+{
+ int retval = 0;
+ int i;
+
+ if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count),
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc_mgr_destroy: Error - module not initialized\n");
+ return -EFAULT;
+ }
+ if (atomic_dec_return(&proc_mgr_obj_state.ref_count)
+ == PROCMGR_MAKE_MAGICSTAMP(0)) {
+
+ /* Check if any ProcMgr instances have not been deleted so far
+ *. If not,delete them
+ */
+ for (i = 0 ; i < MULTIPROC_MAXPROCESSORS; i++) {
+ if (proc_mgr_obj_state.proc_handles[i] != NULL)
+ proc_mgr_delete
+ (&(proc_mgr_obj_state.proc_handles[i]));
+ }
+
+ mutex_destroy(proc_mgr_obj_state.gate_handle);
+ kfree(proc_mgr_obj_state.gate_handle);
+ /* Decrease the refCount */
+ atomic_set(&proc_mgr_obj_state.ref_count,
+ PROCMGR_MAKE_MAGICSTAMP(0));
+ }
+ return retval;;
+}
+EXPORT_SYMBOL(proc_mgr_destroy);
+
+/*=====================================
+ * Function to initialize the parameters for the ProcMgr instance.
+ *
+ * This function can be called by the application to get their
+ * configuration parameter to ProcMgr_create filled in by the
+ * ProcMgr module with the default parameters.
+ */
+void proc_mgr_params_init(void *handle, struct proc_mgr_params *params)
+{
+ struct proc_mgr_object *proc_handle = (struct proc_mgr_object *)handle;
+
+ if (WARN_ON(params == NULL))
+ goto exit;
+ if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count),
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc_mgr_params_init: Error - module not initialized\n");
+ }
+ if (handle == NULL) {
+ memcpy(params, &(proc_mgr_obj_state.def_inst_params),
+ sizeof(struct proc_mgr_params));
+ } else {
+ /* Return updated ProcMgr instance specific parameters. */
+ memcpy(params, &(proc_handle->params),
+ sizeof(struct proc_mgr_params));
+ }
+exit:
+ return;
+}
+EXPORT_SYMBOL(proc_mgr_params_init);
+
+/*=====================================
+ * Function to create a ProcMgr object for a specific slave
+ * processor.
+ *
+ * This function creates an instance of the ProcMgr module and
+ * returns an instance handle, which is used to access the
+ * specified slave processor. The processor ID specified here is
+ * the ID of the slave processor as configured with the MultiProc
+ * module.
+ * Instance-level configuration needs to be provided to this
+ * function. If the user wishes to change some specific config
+ * parameters, then struct proc_mgr_params_init can be called to get the
+ * configuration filled with the default values. After this, only
+ * the required configuration values can be changed. For this
+ * API, the params argument is not optional, since the user needs
+ * to provide some essential values such as loader, PwrMgr and
+ * Processor instances to be used with this ProcMgr instance.
+ */
+void *proc_mgr_create(u16 proc_id, const struct proc_mgr_params *params)
+{
+ struct proc_mgr_object *handle = NULL;
+
+ BUG_ON(!IS_VALID_PROCID(proc_id));
+ BUG_ON(params == NULL);
+ BUG_ON(params->proc_handle == NULL);
+ if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count),
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc_mgr_create: Error - module not initialized\n");
+ return NULL;
+ }
+ if (proc_mgr_obj_state.proc_handles[proc_id] != NULL) {
+ handle = proc_mgr_obj_state.proc_handles[proc_id];
+ pr_warn("proc_mgr_create:"
+ "Processor already exists for specified"
+ "%d proc_id, handle = 0x%x\n", proc_id, (u32)handle);
+ return handle;
+ }
+ WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle));
+ handle = (struct proc_mgr_object *)
+ vmalloc(sizeof(struct proc_mgr_object));
+ BUG_ON(handle == NULL);
+ memset(handle, 0, sizeof(struct proc_mgr_object));
+ memcpy(&(handle->params), params, sizeof(struct proc_mgr_params));
+ handle->proc_id = proc_id;
+ handle->proc_handle = params->proc_handle;
+ handle->loader_handle = params->loader_handle;
+ handle->pwr_handle = params->pwr_handle;
+ proc_mgr_obj_state.proc_handles[proc_id] = handle;
+ mutex_unlock(proc_mgr_obj_state.gate_handle);
+ return handle;
+}
+EXPORT_SYMBOL(proc_mgr_create);
+
+/*===================================
+ * Function to delete a ProcMgr object for a specific slave
+ * processor.
+ *
+ * Once this function is called, other ProcMgr instance level APIs
+ * that require the instance handle cannot be called.
+ *
+ */
+int
+proc_mgr_delete(void **handle_ptr)
+{
+ int retval = 0;
+ struct proc_mgr_object *handle;
+
+ BUG_ON(handle_ptr == NULL);
+ if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count),
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc_mgr_delete: Error - module not initialized\n");
+ return -EFAULT;
+ }
+
+ handle = (struct proc_mgr_object *)(*handle_ptr);
+ WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle));
+ proc_mgr_obj_state.proc_handles[handle->proc_id] = NULL;
+ vfree(handle);
+ *handle_ptr = NULL;
+ mutex_unlock(proc_mgr_obj_state.gate_handle);
+ return retval;
+}
+EXPORT_SYMBOL(proc_mgr_delete);
+
+/*======================================
+ * Function to open a handle to an existing ProcMgr object handling
+ * the proc_id.
+ *
+ * This function returns a handle to an existing ProcMgr instance
+ * created for this proc_id. It enables other entities to access
+ * and use this ProcMgr instance.
+ */
+int proc_mgr_open(void **handle_ptr, u16 proc_id)
+{
+ int retval = 0;
+
+ BUG_ON(handle_ptr == NULL);
+ BUG_ON(!IS_VALID_PROCID(proc_id));
+ if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count),
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc_mgr_open: Error - module not initialized\n");
+ return -EFAULT;
+ }
+
+ WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle));
+ *handle_ptr = proc_mgr_obj_state.proc_handles[proc_id];
+ mutex_unlock(proc_mgr_obj_state.gate_handle);
+ return retval;
+}
+EXPORT_SYMBOL(proc_mgr_open);
+
+/*=====================================
+ * Function to close this handle to the ProcMgr instance.
+ *
+ * This function closes the handle to the ProcMgr instance
+ * obtained through proc_mgr_open call made earlier.
+ */
+int proc_mgr_close(void *handle)
+{
+ int retval = 0;
+
+ BUG_ON(handle == NULL);
+ if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count),
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc_mgr_close: Error - module not initialized\n");
+ return -EFAULT;
+ }
+ /* Nothing to be done for closing the handle. */
+ return retval;
+}
+EXPORT_SYMBOL(proc_mgr_close);
+
+/*========================================
+ * Function to initialize the parameters for the ProcMgr attach
+ * function.
+ *
+ * This function can be called by the application to get their
+ * configuration parameter to proc_mgr_attach filled in by the
+ * ProcMgr module with the default parameters. If the user does
+ * not wish to make any change in the default parameters, this API
+ * is not required to be called.
+ */
+void proc_mgr_get_attach_params(void *handle,
+ struct proc_mgr_attach_params *params)
+{
+ struct proc_mgr_object *proc_mgr_handle =
+ (struct proc_mgr_object *)handle;
+ BUG_ON(params == NULL);
+ if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count),
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc_mgr_get_attach_params:"
+ "Error - module not initialized\n");
+ }
+ if (handle == NULL) {
+ memcpy(params, &(proc_mgr_obj_state.def_attach_params),
+ sizeof(struct proc_mgr_attach_params));
+ } else {
+ /* Return updated ProcMgr instance specific parameters. */
+ memcpy(params, &(proc_mgr_handle->attach_params),
+ sizeof(struct proc_mgr_attach_params));
+ }
+ return;
+}
+EXPORT_SYMBOL(proc_mgr_get_attach_params);
+
+/*
+ * Function to attach the client to the specified slave and also
+ * initialize the slave (if required).
+ *
+ * This function attaches to an instance of the ProcMgr module and
+ * performs any hardware initialization required to power up the
+ * slave device. This function also performs the required state
+ * transitions for this ProcMgr instance to ensure that the local
+ * object representing the slave device correctly indicates the
+ * state of the slave device. Depending on the slave boot mode
+ * being used, the slave may be powered up, in reset, or even
+ * running state.
+ * Configuration parameters need to be provided to this
+ * function. If the user wishes to change some specific config
+ * parameters, then proc_mgr_get_attach_params can be called to get
+ * the configuration filled with the default values. After this,
+ * only the required configuration values can be changed. If the
+ * user does not wish to make any change in the default parameters,
+ * the application can simply call proc_mgr_attach with NULL
+ * parameters.
+ * The default parameters would get automatically used.
+ */
+int proc_mgr_attach(void *handle, struct proc_mgr_attach_params *params)
+{
+ int retval = 0;
+ struct proc_mgr_object *proc_mgr_handle =
+ (struct proc_mgr_object *)handle;
+ struct proc_mgr_attach_params tmp_params;
+ struct processor_attach_params proc_attach_params;
+
+ if (params == NULL) {
+ proc_mgr_get_attach_params(handle, &tmp_params);
+ params = &tmp_params;
+ }
+ if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count),
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc_mgr_attach: Error - module not initialized\n");
+ return -EFAULT;
+ }
+ if (WARN_ON(handle == NULL)) {
+ retval = -EFAULT;
+ goto exit;
+ }
+ if (WARN_ON(params->boot_mode == PROC_MGR_BOOTMODE_ENDVALUE)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle));
+ /* Copy the user provided values into the instance object. */
+ memcpy(&(proc_mgr_handle->attach_params), params,
+ sizeof(struct proc_mgr_attach_params));
+ proc_attach_params.params = params;
+ proc_attach_params.num_mem_entries = 0;
+ /* Attach to the specified Processor instance. */
+ retval = processor_attach(proc_mgr_handle->proc_handle,
+ &proc_attach_params);
+ proc_mgr_handle->num_mem_entries = proc_attach_params.num_mem_entries;
+ pr_info("proc_mgr_attach:proc_mgr_handle->num_mem_entries = %d\n",
+ proc_mgr_handle->num_mem_entries);
+ /* Store memory information in local object.*/
+ memcpy(&(proc_mgr_handle->mem_entries),
+ &(proc_attach_params.mem_entries),
+ sizeof(proc_mgr_handle->mem_entries));
+ mutex_unlock(proc_mgr_obj_state.gate_handle);
+exit:
+ return retval;
+}
+EXPORT_SYMBOL(proc_mgr_attach);
+
+/*===================================
+ * Function to detach the client from the specified slave and also
+ * finalze the slave (if required).
+ *
+ * This function detaches from an instance of the ProcMgr module
+ * and performs any hardware finalization required to power down
+ * the slave device. This function also performs the required state
+ * transitions for this ProcMgr instance to ensure that the local
+ * object representing the slave device correctly indicates the
+ * state of the slave device. Depending on the slave boot mode
+ * being used, the slave may be powered down, in reset, or left in
+ * its original state.
+*/
+int proc_mgr_detach(void *handle)
+{
+ int retval = 0;
+ struct proc_mgr_object *proc_mgr_handle =
+ (struct proc_mgr_object *)handle;
+ if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count),
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc_mgr_detach: Error - module not initialized\n");
+ return -EFAULT;
+ }
+ BUG_ON(handle == NULL);
+ WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle));
+ /* Detach from the Processor. */
+ retval = processor_detach(proc_mgr_handle->proc_handle);
+ mutex_unlock(proc_mgr_obj_state.gate_handle);
+ return retval;
+}
+EXPORT_SYMBOL(proc_mgr_detach);
+
+/*===================================
+ * Function to get the current state of the slave Processor.
+ *
+ * This function gets the state of the slave processor as
+ * maintained on the master Processor state machine. It does not
+ * go to the slave processor to get its actual state at the time
+ * when this API is called.
+ *
+ */
+enum proc_mgr_state proc_mgr_get_state(void *handle)
+{
+ struct proc_mgr_object *proc_mgr_handle =
+ (struct proc_mgr_object *)handle;
+ enum proc_mgr_state state = PROC_MGR_STATE_UNKNOWN;
+ if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count),
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc_mgr_get_state: Error - module not initialized\n");
+ return -EFAULT;
+ }
+ BUG_ON(handle == NULL);
+
+ WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle));
+ state = processor_get_state(proc_mgr_handle->proc_handle);
+ mutex_unlock(proc_mgr_obj_state.gate_handle);
+ return state;
+}
+EXPORT_SYMBOL(proc_mgr_get_state);
+
+/*==================================================
+ * Function to read from the slave processor's memory.
+ *
+ * This function reads from the specified address in the
+ * processor's address space and copies the required number of
+ * bytes into the specified buffer.
+ * It returns the number of bytes actually read in thenum_bytes
+ * parameter.
+ */
+int proc_mgr_read(void *handle, u32 proc_addr, u32 *num_bytes, void *buffer)
+{
+ int retval = 0;
+ struct proc_mgr_object *proc_mgr_handle =
+ (struct proc_mgr_object *)handle;
+ void *addr;
+
+ if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count),
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc_mgr_read: Error - module not initialized\n");
+ return -EFAULT;
+ }
+ BUG_ON(handle == NULL);
+ BUG_ON(proc_addr == 0);
+ BUG_ON(num_bytes == NULL);
+ BUG_ON(buffer == NULL);
+
+ /* Check if the address is already mapped */
+ retval = proc_mgr_translate_addr(handle,
+ (void **) &addr,
+ PROC_MGR_ADDRTYPE_MASTERKNLVIRT,
+ (void *) proc_addr,
+ PROC_MGR_ADDRTYPE_SLAVEVIRT);
+
+
+ if (retval >= 0) {
+ /* Enter critical section protection. */
+ WARN_ON(mutex_lock_interruptible(
+ proc_mgr_obj_state.gate_handle));
+
+ retval = processor_read(proc_mgr_handle->proc_handle, (u32)addr,
+ num_bytes, buffer);
+
+ /* Leave critical section protection. */
+ mutex_unlock(proc_mgr_obj_state.gate_handle);
+ }
+
+ WARN_ON(retval < 0);
+ return retval;
+}
+EXPORT_SYMBOL(proc_mgr_read);
+
+/*
+ * Function to write into the slave processor's memory.
+ *
+ * This function writes into the specified address in the
+ * processor's address space and copies the required number of
+ * bytes from the specified buffer.
+ * It returns the number of bytes actually written in thenum_bytes
+ * parameter.
+ */
+int proc_mgr_write(void *handle, u32 proc_addr, u32 *num_bytes, void *buffer)
+{
+ int retval = 0;
+ struct proc_mgr_object *proc_mgr_handle =
+ (struct proc_mgr_object *)handle;
+ if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count),
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc_mgr_write: Error - module not initialized\n");
+ return -EFAULT;
+ }
+ BUG_ON(proc_addr == 0);
+ BUG_ON(num_bytes == NULL);
+ BUG_ON(buffer == NULL);
+
+ WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle));
+ retval = processor_write(proc_mgr_handle->proc_handle, proc_addr,
+ num_bytes, buffer);
+ WARN_ON(retval < 0);
+ mutex_unlock(proc_mgr_obj_state.gate_handle);
+ return retval;;
+}
+EXPORT_SYMBOL(proc_mgr_write);
+
+
+/*===================================
+ * Function to perform device-dependent operations.
+ *
+ * This function performs control operations supported by the
+ * as exposed directly by the specific implementation of the
+ * Processor interface. These commands and their specific argument
+ * types are used with this function.
+ */
+int proc_mgr_control(void *handle, int cmd, void *arg)
+{
+ int retval = 0;
+ struct proc_mgr_object *proc_mgr_handle
+ = (struct proc_mgr_object *)handle;
+ if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count),
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc_mgr_control: Error - module not initialized\n");
+ return -EFAULT;
+ }
+ BUG_ON(handle == NULL);
+ WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle));
+ /* Perform device-dependent control operation. */
+ retval = processor_control(proc_mgr_handle->proc_handle, cmd, arg);
+ WARN_ON(retval < 0);
+ mutex_unlock(proc_mgr_obj_state.gate_handle);
+ return retval;;
+}
+EXPORT_SYMBOL(proc_mgr_control);
+
+/*========================================
+ * Function to translate between two types of address spaces.
+ *
+ * This function translates addresses between two types of address
+ * spaces. The destination and source address types are indicated
+ * through parameters specified in this function.
+ */
+int proc_mgr_translate_addr(void *handle, void **dst_addr,
+ enum proc_mgr_addr_type dst_addr_type, void *src_addr,
+ enum proc_mgr_addr_type src_addr_type)
+{
+ int retval = 0;
+ struct proc_mgr_object *proc_mgr_handle =
+ (struct proc_mgr_object *)handle;
+
+ if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count),
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc_mgr_translate_addr:"
+ "Error - module not initialized\n");
+ return -EFAULT;
+ }
+ BUG_ON(dst_addr == NULL);
+ BUG_ON(handle == NULL);
+ BUG_ON(dst_addr_type > PROC_MGR_ADDRTYPE_ENDVALUE);
+ BUG_ON(src_addr == NULL);
+ BUG_ON(src_addr_type > PROC_MGR_ADDRTYPE_ENDVALUE);
+
+ WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle));
+ /* Translate the address. */
+ retval = processor_translate_addr(proc_mgr_handle->proc_handle,
+ dst_addr, dst_addr_type, src_addr, src_addr_type);
+ WARN_ON(retval < 0);
+ mutex_unlock(proc_mgr_obj_state.gate_handle);
+ return retval;;
+}
+EXPORT_SYMBOL(proc_mgr_translate_addr);
+
+/*=================================
+ * Function that registers for notification when the slave
+ * processor transitions to any of the states specified.
+ *
+ * This function allows the user application to register for
+ * changes in processor state and take actions accordingly.
+ *
+ */
+int proc_mgr_register_notify(void *handle, proc_mgr_callback_fxn fxn,
+ void *args, enum proc_mgr_state state[])
+{
+ int retval = 0;
+ struct proc_mgr_object *proc_mgr_handle
+ = (struct proc_mgr_object *)handle;
+ if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count),
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc_mgr_register_notify:"
+ "Error - module not initialized\n");
+ return -EFAULT;
+ }
+ BUG_ON(handle == NULL);
+ BUG_ON(fxn == NULL);
+ WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle));
+ retval = processor_register_notify(proc_mgr_handle->proc_handle, fxn,
+ args, state);
+ WARN_ON(retval < 0);
+ mutex_unlock(proc_mgr_obj_state.gate_handle);
+ return retval;
+}
+EXPORT_SYMBOL(proc_mgr_register_notify);
+
+/*
+ * Function that returns information about the characteristics of
+ * the slave processor.
+ */
+int proc_mgr_get_proc_info(void *handle, struct proc_mgr_proc_info *proc_info)
+{
+ struct proc_mgr_object *proc_mgr_handle =
+ (struct proc_mgr_object *)handle;
+ struct processor_object *proc_handle;
+
+ struct proc_mgr_proc_info proc_info_test;
+
+ if (atomic_cmpmask_and_lt(&(proc_mgr_obj_state.ref_count),
+ PROCMGR_MAKE_MAGICSTAMP(0), PROCMGR_MAKE_MAGICSTAMP(1))
+ == true) {
+ pr_err("proc_mgr_get_proc_info:"
+ "Error - module not initialized\n");
+ return -EFAULT;
+ }
+ if (WARN_ON(handle == NULL))
+ goto error_exit;
+ if (WARN_ON(proc_info == NULL))
+ goto error_exit;
+ proc_handle = proc_mgr_handle->proc_handle;
+ if (WARN_ON(proc_handle == NULL))
+ goto error_exit;
+
+ WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle));
+
+ processor_get_proc_info(proc_handle, &proc_info_test);
+ /* Return bootMode information. */
+ proc_info->boot_mode = proc_mgr_handle->attach_params.boot_mode;
+ /* Return memory information. */
+ proc_info->num_mem_entries = proc_mgr_handle->num_mem_entries;
+ memcpy(&(proc_info->mem_entries),
+ &(proc_mgr_handle->mem_entries),
+ sizeof(proc_mgr_handle->mem_entries));
+ mutex_unlock(proc_mgr_obj_state.gate_handle);
+ return 0;
+error_exit:
+ return -EFAULT;
+}
+EXPORT_SYMBOL(proc_mgr_get_proc_info);
+
+/*============================================
+ * Function to get virtual to physical address translations
+ *
+ * This function retrieves physical entries
+ *
+ */
+int proc_mgr_virt_to_phys(void *handle, u32 da, u32 *mapped_entries,
+ u32 num_of_entries)
+{
+ int retval = 0;
+ struct proc_mgr_object *proc_mgr_handle =
+ (struct proc_mgr_object *)handle;
+
+ WARN_ON(mutex_lock_interruptible(proc_mgr_obj_state.gate_handle));
+
+ /* Map to host address space. */
+ retval = processor_virt_to_phys(proc_mgr_handle->proc_handle, da,
+ mapped_entries, num_of_entries);
+ WARN_ON(retval < 0);
+ mutex_unlock(proc_mgr_obj_state.gate_handle);
+ return retval;;
+}
+EXPORT_SYMBOL(proc_mgr_virt_to_phys);
diff --git a/drivers/dsp/syslink/procmgr/procmgr_drv.c b/drivers/dsp/syslink/procmgr/procmgr_drv.c
new file mode 100644
index 00000000000..dfcafcda6a6
--- /dev/null
+++ b/drivers/dsp/syslink/procmgr/procmgr_drv.c
@@ -0,0 +1,730 @@
+/*
+ * procmgr_drv.c
+ *
+ * Syslink driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2009-2010 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 <generated/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+
+#include <plat/cpu.h>
+
+/* Module headers */
+#include <procmgr.h>
+#include "procmgr_drvdefs.h"
+
+#define PROCMGR_NAME "syslink-procmgr"
+
+static char *driver_name = PROCMGR_NAME;
+
+static s32 driver_major;
+
+static s32 driver_minor;
+
+struct procmgr_dev {
+ struct cdev cdev;
+};
+
+static struct platform_device *omap_proc_dev;
+static struct platform_device *procmgr_pdev;
+static struct procmgr_dev *procmgr_device;
+
+static struct class *proc_mgr_class;
+
+
+/** ====================================
+ * Forward declarations of internal functions
+ * ====================================
+ */
+/* Linux driver function to open the driver object. */
+static int proc_mgr_drv_open(struct inode *inode, struct file *filp);
+
+/* Linux driver function to close the driver object. */
+static int proc_mgr_drv_release(struct inode *inode, struct file *filp);
+
+/* Linux driver function to invoke the APIs through ioctl. */
+static long proc_mgr_drv_ioctl(struct file *filp,
+ unsigned int cmd,
+ unsigned long args);
+
+/* Linux driver function to map memory regions to user space. */
+static int proc_mgr_drv_mmap(struct file *filp, struct vm_area_struct *vma);
+
+/* Module initialization function for Linux driver. */
+static int __init proc_mgr_drv_initialize_module(void);
+
+/* Module finalization function for Linux driver. */
+static void __exit proc_mgr_drv_finalize_module(void);
+
+/* Platform driver probe function */
+static int __devinit proc_mgr_probe(struct platform_device *pdev);
+
+/* Platform driver remove function */
+static int __devexit proc_mgr_remove(struct platform_device *pdev);
+
+/*
+ * name DriverOps
+ *
+ * desc Function to invoke the APIs through ioctl
+ *
+ */
+static const struct file_operations procmgr_fops = {
+ .open = proc_mgr_drv_open,
+ .unlocked_ioctl = proc_mgr_drv_ioctl,
+ .release = proc_mgr_drv_release,
+ .mmap = proc_mgr_drv_mmap,
+} ;
+
+/* Imtiaz changed places */
+static struct platform_driver procmgr_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = PROCMGR_NAME,
+ },
+ .probe = proc_mgr_probe,
+ .remove = __devexit_p(proc_mgr_remove),
+ .shutdown = NULL,
+ .suspend = NULL,
+ .resume = NULL,
+};
+
+/* Process Context */
+struct procmgr_process_context {
+ u32 setup_count;
+};
+
+/*
+* brief Linux specific function to open the driver.
+ */
+static int proc_mgr_drv_open(struct inode *inode, struct file *filp)
+{
+ s32 retval = 0;
+ struct procmgr_process_context *pr_ctxt = NULL;
+
+ pr_ctxt = kzalloc(sizeof(struct procmgr_process_context), GFP_KERNEL);
+ if (!pr_ctxt)
+ retval = -ENOMEM;
+
+ filp->private_data = pr_ctxt;
+ return retval;
+}
+
+/*
+* brief Linux driver function to close the driver object.
+ */
+static int proc_mgr_drv_release(struct inode *inode, struct file *filp)
+{
+ s32 retval = 0;
+ struct procmgr_process_context *pr_ctxt;
+
+ if (!filp->private_data) {
+ retval = -EIO;
+ goto err;
+ }
+
+ pr_ctxt = filp->private_data;
+ while (pr_ctxt->setup_count-- > 0) {
+ /* Destroy has not been called. Call destroy now. */
+ pr_err("proc_mgr_drv_release: "
+ "proc_mgr_destroy %d\n", pr_ctxt->setup_count);
+ proc_mgr_destroy();
+ }
+ kfree(pr_ctxt);
+
+ filp->private_data = NULL;
+err:
+ return retval;
+}
+
+/*
+* Linux driver function to invoke the APIs through ioctl.
+ */
+static long proc_mgr_drv_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long args)
+{
+ int retval = 0;
+ struct proc_mgr_cmd_args *cmd_args = (struct proc_mgr_cmd_args *)args;
+ struct proc_mgr_cmd_args command_args;
+ struct procmgr_process_context *pr_ctxt =
+ (struct procmgr_process_context *)filp->private_data;
+
+ switch (cmd) {
+ case CMD_PROCMGR_GETCONFIG:
+ {
+ struct proc_mgr_cmd_args_get_config *src_args =
+ (struct proc_mgr_cmd_args_get_config *)args;
+ struct proc_mgr_config cfg;
+
+ /* copy_from_user is not needed for proc_mgr_get_config,
+ * since the user's config is not used.
+ */
+ proc_mgr_get_config(&cfg);
+
+ retval = copy_to_user((void __user *)(src_args->cfg),
+ (const void *)&cfg,
+ sizeof(struct proc_mgr_config));
+
+ WARN_ON(retval < 0);
+ }
+ break;
+
+ case CMD_PROCMGR_SETUP:
+ {
+ struct proc_mgr_cmd_args_setup *src_args =
+ (struct proc_mgr_cmd_args_setup *)args;
+ struct proc_mgr_config cfg;
+
+ retval = copy_from_user((void *)&cfg,
+ (const void __user *)(src_args->cfg),
+ sizeof(struct proc_mgr_config));
+
+ /* This check is needed at run-time also since it
+ * depends on run environment.
+ * It must not be optimized out.
+ */
+ if (WARN_ON(retval != 0))
+ goto func_exit;
+
+ retval = proc_mgr_setup(&cfg);
+ if (retval >= 0)
+ pr_ctxt->setup_count++;
+ }
+ break;
+
+ case CMD_PROCMGR_DESTROY:
+ {
+ retval = proc_mgr_destroy();
+ pr_ctxt->setup_count--;
+ WARN_ON(retval < 0);
+ }
+ break;
+
+ case CMD_PROCMGR_PARAMS_INIT:
+ {
+ struct proc_mgr_cmd_args_params_init src_args;
+ struct proc_mgr_params params;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc_mgr_cmd_args_params_init));
+
+ if (WARN_ON(retval != 0))
+ goto func_exit;
+
+ proc_mgr_params_init(src_args.handle, &params);
+
+ /* Copy only the params to user-side */
+ retval = copy_to_user((void __user *)(src_args.params),
+ (const void *)&params,
+ sizeof(struct proc_mgr_params));
+ WARN_ON(retval < 0);
+ }
+ break;
+
+ case CMD_PROCMGR_CREATE:
+ {
+ struct proc_mgr_cmd_args_create src_args;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc_mgr_cmd_args_create));
+
+ src_args.handle = proc_mgr_create(src_args.proc_id,
+ &(src_args.params));
+ if (src_args.handle == NULL) {
+ retval = -EFAULT;
+ goto func_exit;
+ }
+ retval = copy_to_user((void __user *)(args),
+ (const void *)&src_args,
+ sizeof(struct proc_mgr_cmd_args_create));
+ WARN_ON(retval < 0);
+ }
+ break;
+
+ case CMD_PROCMGR_DELETE:
+ {
+ struct proc_mgr_cmd_args_delete src_args;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc_mgr_cmd_args_delete));
+ if (WARN_ON(retval != 0))
+ goto func_exit;
+
+ retval = proc_mgr_delete(&(src_args.handle));
+ }
+ break;
+
+ case CMD_PROCMGR_OPEN:
+ {
+ struct proc_mgr_cmd_args_open src_args;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc_mgr_cmd_args_open));
+
+ if (WARN_ON(retval != 0))
+ goto func_exit;
+ retval = proc_mgr_open(&(src_args.handle),
+ src_args.proc_id);
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ retval = proc_mgr_get_proc_info(src_args.handle,
+ &(src_args.proc_info));
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ retval = copy_to_user((void __user *)(args),
+ (const void *)&src_args,
+ sizeof(struct proc_mgr_cmd_args_open));
+ WARN_ON(retval);
+ }
+ break;
+
+ case CMD_PROCMGR_CLOSE:
+ {
+ struct proc_mgr_cmd_args_close src_args;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc_mgr_cmd_args_close));
+ if (WARN_ON(retval != 0))
+ goto func_exit;
+ retval = proc_mgr_close(&(src_args.handle));
+ }
+ break;
+
+ case CMD_PROCMGR_GETATTACHPARAMS:
+ {
+ struct proc_mgr_cmd_args_get_attach_params src_args;
+ struct proc_mgr_attach_params params;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc_mgr_cmd_args_get_attach_params));
+ if (WARN_ON(retval != 0))
+ goto func_exit;
+ proc_mgr_get_attach_params(src_args.handle, &params);
+ retval = copy_to_user((void __user *)(src_args.params),
+ (const void *)&params,
+ sizeof(struct proc_mgr_attach_params));
+ WARN_ON(retval);
+ }
+ break;
+
+ case CMD_PROCMGR_ATTACH:
+ {
+ struct proc_mgr_cmd_args_attach src_args;
+ struct proc_mgr_attach_params params;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc_mgr_cmd_args_attach));
+ if (WARN_ON(retval != 0))
+ goto func_exit;
+ /* Copy params from user-side. */
+ retval = copy_from_user((void *)&params,
+ (const void __user *)(src_args.params),
+ sizeof(struct proc_mgr_attach_params));
+ retval = proc_mgr_attach(src_args.handle, &params);
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ /* Get memory information. */
+ retval = proc_mgr_get_proc_info(src_args.handle,
+ &(src_args.proc_info));
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ retval = copy_to_user((void __user *)(args),
+ (const void *)&src_args,
+ sizeof(struct proc_mgr_cmd_args_attach));
+ }
+ break;
+
+ case CMD_PROCMGR_DETACH:
+ {
+ struct proc_mgr_cmd_args_detach src_args;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc_mgr_cmd_args_detach));
+ if (WARN_ON(retval != 0))
+ goto func_exit;
+ retval = proc_mgr_detach(src_args.handle);
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ }
+ break;
+
+ case CMD_PROCMGR_GETSTATE:
+ {
+ struct proc_mgr_cmd_args_get_state src_args;
+ enum proc_mgr_state procmgrstate;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const __user void *)(args),
+ sizeof(struct proc_mgr_cmd_args_get_state));
+ if (WARN_ON(retval != 0))
+ goto func_exit;
+ procmgrstate = proc_mgr_get_state(src_args.handle);
+ src_args.proc_mgr_state = procmgrstate;
+ retval = copy_to_user((void __user *)(args),
+ (const void *)&src_args,
+ sizeof(struct proc_mgr_cmd_args_get_state));
+ WARN_ON(retval < 0);
+ }
+ break;
+
+ case CMD_PROCMGR_READ:
+ {
+ struct proc_mgr_cmd_args_read src_args;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc_mgr_cmd_args_read));
+ if (WARN_ON(retval != 0))
+ goto func_exit;
+ retval = proc_mgr_read(src_args.handle,
+ src_args.proc_addr, &(src_args.num_bytes),
+ src_args.buffer);
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ retval = copy_to_user((void __user *)(args),
+ (const void *)&src_args,
+ sizeof(struct proc_mgr_cmd_args_read));
+ WARN_ON(retval < 0);
+ }
+ break;
+
+ case CMD_PROCMGR_WRITE:
+ {
+ struct proc_mgr_cmd_args_write src_args;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc_mgr_cmd_args_write));
+ if (WARN_ON(retval != 0))
+ goto func_exit;
+ retval = proc_mgr_write(src_args.handle,
+ src_args.proc_addr, &(src_args.num_bytes),
+ src_args.buffer);
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ retval = copy_to_user((void __user *)(args),
+ (const void *)&src_args,
+ sizeof(struct proc_mgr_cmd_args_write));
+ WARN_ON(retval < 0);
+ }
+ break;
+
+ case CMD_PROCMGR_CONTROL:
+ {
+ struct proc_mgr_cmd_args_control src_args;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc_mgr_cmd_args_control));
+ if (WARN_ON(retval != 0))
+ goto func_exit;
+ retval = proc_mgr_control(src_args.handle,
+ src_args.cmd, src_args.arg);
+ WARN_ON(retval < 0);
+ }
+ break;
+
+ case CMD_PROCMGR_TRANSLATEADDR:
+ {
+ struct proc_mgr_cmd_args_translate_addr src_args;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc_mgr_cmd_args_translate_addr));
+ if (WARN_ON(retval != 0))
+ goto func_exit;
+ retval = proc_mgr_translate_addr(src_args.handle,
+ &(src_args.dst_addr), src_args.dst_addr_type,
+ src_args.src_addr, src_args.src_addr_type);
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ retval = copy_to_user((void __user *)(args),
+ (const void *)&src_args, sizeof
+ (struct proc_mgr_cmd_args_translate_addr));
+ WARN_ON(retval < 0);
+ }
+ break;
+
+ case CMD_PROCMGR_REGISTERNOTIFY:
+ {
+ struct proc_mgr_cmd_args_register_notify src_args;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc_mgr_cmd_args_register_notify));
+ if (WARN_ON(retval != 0))
+ goto func_exit;
+ retval = proc_mgr_register_notify(src_args.handle,
+ src_args.callback_fxn,
+ src_args.args, src_args.state);
+ WARN_ON(retval < 0);
+ }
+ break;
+
+ case CMD_PROCMGR_GETPROCINFO:
+ {
+ struct proc_mgr_cmd_args_get_proc_info src_args;
+ struct proc_mgr_proc_info *proc_info;
+
+ /* Copy the full args from user-side. */
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc_mgr_cmd_args_get_proc_info));
+ if (WARN_ON(retval != 0))
+ goto func_exit;
+
+ proc_info = kzalloc(sizeof(struct proc_mgr_proc_info),
+ GFP_KERNEL);
+ retval = proc_mgr_get_proc_info
+ (src_args.handle, proc_info);
+ if (WARN_ON(retval < 0)) {
+ kfree(proc_info);
+ goto func_exit;
+ }
+ retval = copy_to_user((void __user *)(src_args.proc_info),
+ (const void *) proc_info,
+ sizeof(struct proc_mgr_proc_info));
+ WARN_ON(retval < 0);
+ kfree(proc_info);
+ }
+ break;
+
+ case CMD_PROCMGR_GETVIRTTOPHYS:
+ {
+ struct proc_mgr_cmd_args_get_virt_to_phys src_args;
+
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc_mgr_cmd_args_get_virt_to_phys));
+ retval = proc_mgr_virt_to_phys(src_args.handle,
+ src_args.da, (src_args.mem_entries),
+ src_args.num_of_entries);
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ retval = copy_to_user((void __user *)(args),
+ (const void *)&src_args,
+ sizeof(struct proc_mgr_cmd_args_get_virt_to_phys));
+ WARN_ON(retval < 0);
+ }
+ break;
+
+ /*
+ * This is added to provide the information whether to enable
+ * lock all entries in TLB or not. ES1.0 requires all the entries
+ * to be locked, so the loader in userspace makes the decision on
+ * how the entries should be programmed based on ES revision. This
+ * case is meant for temporary purpose and can be removed once ES1.0
+ * boards are phased out
+ */
+ case CMD_PROCMGR_GETBOARDREV:
+ {
+ int rev;
+ struct proc_mgr_cmd_args_cpurev src_args;
+ retval = copy_from_user((void *)&src_args,
+ (const void __user *)(args),
+ sizeof(struct proc_mgr_cmd_args_cpurev));
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+
+ rev = GET_OMAP_REVISION();
+ *(src_args.cpu_rev) = rev;
+ retval = copy_to_user((void __user *)(args),
+ (const void *)&src_args,
+ sizeof(struct proc_mgr_cmd_args_cpurev));
+ if (WARN_ON(retval < 0))
+ goto func_exit;
+ }
+ break;
+ default:
+ pr_err("PROC_MGR_DRV: WRONG IOCTL !!!!\n");
+ BUG_ON(1);
+ break;
+ }
+func_exit:
+ /* Set the retval and copy the common args to user-side. */
+ command_args.api_status = retval;
+ retval = copy_to_user((void __user *)cmd_args,
+ (const void *)&command_args, sizeof(struct proc_mgr_cmd_args));
+
+ WARN_ON(retval < 0);
+ return retval;
+}
+
+
+/*
+ Driver function to map memory regions to user space.
+ */
+static int proc_mgr_drv_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ vma->vm_page_prot = pgprot_dmacoherent(vma->vm_page_prot);
+ vma->vm_flags |= VM_RESERVED;
+
+ if (remap_pfn_range(vma,
+ vma->vm_start,
+ vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+static int __devinit proc_mgr_probe(struct platform_device *pdev)
+{
+ dev_t dev = 0 ;
+ int retval = -ENOMEM;
+
+ /* Display the version info and created date/time */
+ dev_dbg(&omap_proc_dev->dev, "Entering %s function\n\n", __func__);
+
+ if (driver_major) {
+ dev = MKDEV(driver_major, driver_minor);
+ retval = register_chrdev_region(dev, 1, driver_name);
+ } else {
+ retval = alloc_chrdev_region(&dev, driver_minor, 1,
+ driver_name);
+ driver_major = MAJOR(dev);
+ }
+
+ procmgr_device = kmalloc(sizeof(struct procmgr_dev), GFP_KERNEL);
+ if (!procmgr_device) {
+ retval = -ENOMEM;
+ unregister_chrdev_region(dev, 1);
+ goto exit;
+ }
+ memset(procmgr_device, 0, sizeof(struct procmgr_dev));
+ cdev_init(&procmgr_device->cdev, &procmgr_fops);
+ procmgr_device->cdev.owner = THIS_MODULE;
+ procmgr_device->cdev.ops = &procmgr_fops;
+
+ retval = cdev_add(&procmgr_device->cdev, dev, 1);
+
+ if (retval) {
+ pr_err("Failed to add the syslink procmgr device\n");
+ goto exit;
+ }
+
+ /* udev support */
+ proc_mgr_class = class_create(THIS_MODULE, "syslink-procmgr");
+
+ if (IS_ERR(proc_mgr_class)) {
+ pr_err("Error creating bridge class\n");
+ goto exit;
+ }
+ device_create(proc_mgr_class, NULL, MKDEV(driver_major, driver_minor),
+ NULL, PROCMGR_NAME);
+
+exit:
+ dev_dbg(&omap_proc_dev->dev, "Leaving %s function\n\n", __func__);
+ return retval;
+}
+
+
+static int __devexit proc_mgr_remove(struct platform_device *pdev)
+{
+ dev_t devno = 0;
+
+ dev_dbg(&omap_proc_dev->dev, "Entering %s function\n", __func__);
+ devno = MKDEV(driver_major, driver_minor);
+ if (procmgr_device) {
+ cdev_del(&procmgr_device->cdev);
+ kfree(procmgr_device);
+ }
+ unregister_chrdev_region(devno, 1);
+ if (proc_mgr_class) {
+ /* remove the device from sysfs */
+ device_destroy(proc_mgr_class, MKDEV(driver_major,
+ driver_minor));
+ class_destroy(proc_mgr_class);
+ }
+ dev_dbg(&omap_proc_dev->dev, "Entering %s function\n", __func__);
+ return 0;
+}
+
+/*
+* Module initialization function for Linux driver.
+ */
+static int __init proc_mgr_drv_initialize_module(void)
+{
+ int retval = -ENOMEM;
+
+ procmgr_pdev = platform_device_alloc(PROCMGR_NAME, -1);
+ if (!procmgr_pdev) {
+ pr_err("%s:device allocation failed\n", __func__);
+ return -ENOMEM;
+ }
+ retval = platform_device_add(procmgr_pdev);
+ if (retval)
+ goto err_out;
+
+ /*Saving the context for future use*/
+ omap_proc_dev = procmgr_pdev;
+
+ retval = platform_driver_register(&procmgr_driver);
+ if (!retval)
+ return retval;
+err_out:
+ platform_device_put(procmgr_pdev);
+ return retval;
+}
+
+/*
+* driver function to finalize the driver module.
+ */
+static void __exit proc_mgr_drv_finalize_module(void)
+{
+
+ dev_dbg(&omap_proc_dev->dev, "Entering %s function\n", __func__);
+ platform_device_unregister(procmgr_pdev);
+ platform_driver_unregister(&procmgr_driver);
+ dev_dbg(&omap_proc_dev->dev, "Leaving %s function\n", __func__);
+}
+
+/*
+* brief Macro calls that indicate initialization and finalization functions
+ * to the kernel.
+ */
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Mugdha Kamoolkar");
+module_init(proc_mgr_drv_initialize_module);
+module_exit(proc_mgr_drv_finalize_module);
diff --git a/drivers/dsp/syslink/procmgr/procmgr_drvdefs.h b/drivers/dsp/syslink/procmgr/procmgr_drvdefs.h
new file mode 100644
index 00000000000..fc0015d5882
--- /dev/null
+++ b/drivers/dsp/syslink/procmgr/procmgr_drvdefs.h
@@ -0,0 +1,491 @@
+/*
+ * procmgr_drvdefs.h
+ *
+ * Syslink driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2009-2010 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 SYSLINK_PROCMGR_DRVDEFS_H
+#define SYSLINK_PROCMGR_DRVDEFS_H
+
+#include <linux/types.h>
+
+/* Module headers */
+#include <procmgr.h>
+
+
+/* =================================
+ * Macros and types
+ * =================================
+ */
+/*
+ * Base structure for ProcMgr command args. This needs to be the first
+ * field in all command args structures.
+ */
+struct proc_mgr_cmd_args {
+ int api_status;
+ /*Status of the API being called. */
+};
+
+/* --------------------------------------
+ * IOCTL command IDs for ProcMgr
+ * ---------------------------------------
+ */
+/*
+ * Base command ID for ProcMgr
+ */
+#define PROCMGR_BASE_CMD 0x100
+
+/*
+ * Command for ProcMgr_getConfig
+ */
+#define CMD_PROCMGR_GETCONFIG (PROCMGR_BASE_CMD + 1)
+
+/*
+ * Command for ProcMgr_setup
+ */
+#define CMD_PROCMGR_SETUP (PROCMGR_BASE_CMD + 2)
+
+/*
+ * Command for ProcMgr_setup
+ */
+#define CMD_PROCMGR_DESTROY (PROCMGR_BASE_CMD + 3)
+
+/*
+ * Command for ProcMgr_destroy
+ */
+#define CMD_PROCMGR_PARAMS_INIT (PROCMGR_BASE_CMD + 4)
+
+/*
+ * Command for ProcMgr_create
+ */
+#define CMD_PROCMGR_CREATE (PROCMGR_BASE_CMD + 5)
+
+/*
+ * Command for ProcMgr_delete
+ */
+#define CMD_PROCMGR_DELETE (PROCMGR_BASE_CMD + 6)
+
+/*
+ * Command for ProcMgr_open
+ */
+#define CMD_PROCMGR_OPEN (PROCMGR_BASE_CMD + 7)
+
+/*
+ * Command for ProcMgr_close
+ */
+#define CMD_PROCMGR_CLOSE (PROCMGR_BASE_CMD + 8)
+
+/*
+ * Command for ProcMgr_getAttachParams
+ */
+#define CMD_PROCMGR_GETATTACHPARAMS (PROCMGR_BASE_CMD + 9)
+
+/*
+ * Command for ProcMgr_attach
+ */
+#define CMD_PROCMGR_ATTACH (PROCMGR_BASE_CMD + 10)
+
+/*
+ * Command for ProcMgr_detach
+ */
+#define CMD_PROCMGR_DETACH (PROCMGR_BASE_CMD + 11)
+
+/*
+ * Command for ProcMgr_load
+ */
+#define CMD_PROCMGR_LOAD (PROCMGR_BASE_CMD + 12)
+
+/*
+ * Command for ProcMgr_unload
+ */
+#define CMD_PROCMGR_UNLOAD (PROCMGR_BASE_CMD + 13)
+
+/*
+ * Command for ProcMgr_getStartParams
+ */
+#define CMD_PROCMGR_GETSTARTPARAMS (PROCMGR_BASE_CMD + 14)
+
+/*
+ * Command for ProcMgr_start
+ */
+#define CMD_PROCMGR_START (PROCMGR_BASE_CMD + 15)
+
+/*
+ * Command for ProcMgr_stop
+ */
+#define CMD_PROCMGR_STOP (PROCMGR_BASE_CMD + 16)
+
+/*
+ * Command for ProcMgr_getState
+ */
+#define CMD_PROCMGR_GETSTATE (PROCMGR_BASE_CMD + 17)
+
+/*
+ * Command for ProcMgr_read
+ */
+#define CMD_PROCMGR_READ (PROCMGR_BASE_CMD + 18)
+
+/*
+ * Command for ProcMgr_write
+ */
+#define CMD_PROCMGR_WRITE (PROCMGR_BASE_CMD + 19)
+
+/*
+ * Command for ProcMgr_control
+ */
+#define CMD_PROCMGR_CONTROL (PROCMGR_BASE_CMD + 20)
+
+/*
+ * Command for ProcMgr_translateAddr
+ */
+#define CMD_PROCMGR_TRANSLATEADDR (PROCMGR_BASE_CMD + 22)
+
+/*
+ * Command for ProcMgr_getSymbolAddress
+ */
+#define CMD_PROCMGR_GETSYMBOLADDRESS (PROCMGR_BASE_CMD + 23)
+
+/*
+ * Command for ProcMgr_map
+ */
+#define CMD_PROCMGR_MAP (PROCMGR_BASE_CMD + 24)
+
+/*
+ * Command for ProcMgr_registerNotify
+ */
+#define CMD_PROCMGR_REGISTERNOTIFY (PROCMGR_BASE_CMD + 25)
+
+/*
+ * Command for ProcMgr_getProcInfo
+ */
+#define CMD_PROCMGR_GETPROCINFO (PROCMGR_BASE_CMD + 26)
+
+/*
+ * Command for ProcMgr_unmap
+ */
+#define CMD_PROCMGR_UNMAP (PROCMGR_BASE_CMD + 27)
+
+/*
+ * Command for ProcMgr_getVirtToPhysPages
+ */
+#define CMD_PROCMGR_GETVIRTTOPHYS (PROCMGR_BASE_CMD + 28)
+
+
+/*
+ * Command to get Board revision
+ */
+#define CMD_PROCMGR_GETBOARDREV (PROCMGR_BASE_CMD + 31)
+
+
+
+/* ----------------------------------------------------------------------------
+ * Command arguments for ProcMgr
+ * ----------------------------------------------------------------------------
+ */
+/*
+ * Command arguments for ProcMgr_getConfig
+ */
+struct proc_mgr_cmd_args_get_config {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ struct proc_mgr_config *cfg;
+ /*Pointer to the ProcMgr module configuration structure in which the
+ default config is to be returned. */
+};
+
+/*
+ * Command arguments for ProcMgr_setup
+ */
+struct proc_mgr_cmd_args_setup {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ struct proc_mgr_config *cfg;
+ /*Optional ProcMgr module configuration. If provided as NULL, default
+ configuration is used. */
+};
+
+/*
+ * Command arguments for ProcMgr_destroy
+ */
+struct proc_mgr_cmd_args_destroy {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+};
+
+/*
+ * Command arguments for ProcMgr_Params_init
+ */
+struct proc_mgr_cmd_args_params_init {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ void *handle;
+ /*Handle to the ProcMgr object. */
+ struct proc_mgr_params *params;
+ /*Pointer to the ProcMgr instance params structure in which the default
+ params is to be returned. */
+};
+
+/*
+ * Command arguments for ProcMgr_create
+ */
+struct proc_mgr_cmd_args_create {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ u16 proc_id;
+ /*Processor ID represented by this ProcMgr instance */
+ struct proc_mgr_params params;
+ /*ProcMgr instance configuration parameters. */
+ void *handle;
+ /*Handle to the created ProcMgr object */
+};
+
+/*
+ * Command arguments for ProcMgr_delete
+ */
+struct proc_mgr_cmd_args_delete{
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ void *handle;
+ /*Pointer to Handle to the ProcMgr object */
+};
+
+/*
+ * Command arguments for ProcMgr_open
+ */
+struct proc_mgr_cmd_args_open {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ u16 proc_id;
+ /*Processor ID represented by this ProcMgr instance */
+ void *handle;
+ /*Handle to the opened ProcMgr object. */
+ struct proc_mgr_proc_info proc_info;
+ /*Processor information. */
+};
+
+/*
+ * Command arguments for ProcMgr_close
+ */
+struct proc_mgr_cmd_args_close{
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ void *handle;
+ /*Handle to the ProcMgr object */
+ struct proc_mgr_proc_info proc_info;
+ /*Processor information. */
+};
+
+/*
+ * Command arguments for ProcMgr_getAttachParams
+ */
+struct proc_mgr_cmd_args_get_attach_params{
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ void *handle;
+ /*Handle to the ProcMgr object. */
+ struct proc_mgr_attach_params *params;
+ /*Pointer to the ProcMgr attach params structure in which the default
+ params is to be returned. */
+};
+
+/*
+ * Command arguments for ProcMgr_attach
+ */
+struct proc_mgr_cmd_args_attach {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ void *handle;
+ /*Handle to the ProcMgr object. */
+ struct proc_mgr_attach_params *params;
+ /*Optional ProcMgr attach parameters. */
+ struct proc_mgr_proc_info proc_info;
+ /*Processor information. */
+};
+
+/*
+ * Command arguments for ProcMgr_detach
+ */
+struct proc_mgr_cmd_args_detach {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ void *handle;
+ /*Handle to the ProcMgr object */
+ struct proc_mgr_proc_info proc_info;
+ /*Processor information. */
+};
+
+
+/*
+ * Command arguments for ProcMgr_getStartParams
+ */
+struct proc_mgr_cmd_args_get_start_params {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ void *handle;
+ /*Entry point for the image*/
+ u32 entry_point;
+ /*Handle to the ProcMgr object */
+ struct proc_mgr_start_params *params;
+ /*Pointer to the ProcMgr start params structure in which the default
+ params is to be returned. */
+};
+
+/*
+ * Command arguments for ProcMgr_getState
+ */
+struct proc_mgr_cmd_args_get_state {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ void *handle;
+ /* Handle to the ProcMgr object */
+ enum proc_mgr_state proc_mgr_state;
+ /*Current state of the ProcMgr object. */
+};
+
+/*
+ * Command arguments for ProcMgr_read
+ */
+struct proc_mgr_cmd_args_read {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ void *handle;
+ /*Handle to the ProcMgr object */
+ u32 proc_addr;
+ /*Address in space processor's address space of the memory region to
+ read from. */
+ u32 num_bytes;
+ /*IN/OUT parameter. As an IN-parameter, it takes in the number of bytes
+ to be read. When the function returns, this parameter contains the
+ number of bytes actually read. */
+ void *buffer;
+ /*User-provided buffer in which the slave processor's memory contents
+ are to be copied. */
+};
+
+/*
+ * Command arguments for ProcMgr_write
+ */
+struct proc_mgr_cmd_args_write {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ void *handle;
+ /*Handle to the ProcMgr object */
+ u32 proc_addr;
+ /*Address in space processor's address space of the memory region to
+ write into. */
+ u32 num_bytes;
+ /*IN/OUT parameter. As an IN-parameter, it takes in the number of bytes
+ to be written. When the function returns, this parameter contains the
+ number of bytes actually written. */
+ void *buffer;
+ /*User-provided buffer from which the data is to be written into the
+ slave processor's memory. */
+};
+
+/*
+ * Command arguments for ProcMgr_control
+ */
+struct proc_mgr_cmd_args_control {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ void *handle;
+ /*Handle to the ProcMgr object */
+ int cmd;
+ /*Device specific processor command */
+ void *arg;
+ /*Arguments specific to the type of command. */
+};
+
+/*
+ * Command arguments for ProcMgr_translateAddr
+ */
+struct proc_mgr_cmd_args_translate_addr {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ void *handle;
+ /*Handle to the ProcMgr object */
+ void *dst_addr;
+ /*Return parameter: Pointer to receive the translated address. */
+ enum proc_mgr_addr_type dst_addr_type;
+ /*Destination address type requested */
+ void *src_addr;
+ /*Source address in the source address space */
+ enum proc_mgr_addr_type src_addr_type;
+ /*Source address type */
+};
+
+/*
+ * Command arguments for ProcMgr_getSymbolAddress
+ */
+struct proc_mgr_cmd_args_get_symbol_address {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ void *handle;
+ /*Handle to the ProcMgr object */
+ u32 file_id;
+ /*ID of the file received from the load function */
+ char *symbol_name;
+ /*Name of the symbol */
+ u32 sym_value;
+ /*Return parameter: Symbol address */
+};
+
+/*
+ * Command arguments for ProcMgr_registerNotify
+ */
+struct proc_mgr_cmd_args_register_notify {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ void *handle;
+ /*Handle to the ProcMgr object */
+ int (*callback_fxn)(u16 proc_id, void *handle,
+ enum proc_mgr_state from_state, enum proc_mgr_state to_state);
+ /*Handling function to be registered. */
+ void *args;
+ /*Optional arguments associated with the handler fxn. */
+ enum proc_mgr_state state[];
+ /*Array of target states for which registration is required. */
+};
+
+/*
+ * Command arguments for ProcMgr_getProcInfo
+ */
+struct proc_mgr_cmd_args_get_proc_info {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ void *handle;
+ /*Handle to the ProcMgr object */
+ struct proc_mgr_proc_info *proc_info;
+ /*Pointer to the ProcInfo object to be populated. */
+};
+
+/*
+ * Command arguments for ProcMgr_virtToPhys
+ */
+struct proc_mgr_cmd_args_get_virt_to_phys {
+ struct proc_mgr_cmd_args commond_args;
+ /*Common command args */
+ void *handle;
+ u32 da;
+ /* mem entries buffer */
+ u32 *mem_entries;
+ /* number of entries */
+ u32 num_of_entries;
+};
+
+struct proc_mgr_cmd_args_cpurev {
+ struct proc_mgr_cmd_args commond_args;
+ u32 *cpu_rev;
+};
+#endif
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 271835a7157..7301d5e7fda 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -262,15 +262,12 @@ EXPORT_SYMBOL(drm_init);
void drm_exit(struct drm_driver *driver)
{
- struct drm_device *dev, *tmp;
DRM_DEBUG("\n");
- if (driver->driver_features & DRIVER_MODESET) {
- pci_unregister_driver(&driver->pci_driver);
- } else {
- list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
- drm_put_dev(dev);
- }
+ if (driver->driver_features & DRIVER_USE_PLATFORM_DEVICE)
+ drm_platform_exit(driver);
+ else
+ drm_pci_exit(driver);
DRM_INFO("Module unloaded\n");
}
diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c
index be9a9c07d15..73bf49360c9 100644
--- a/drivers/gpu/drm/drm_info.c
+++ b/drivers/gpu/drm/drm_info.c
@@ -54,11 +54,11 @@ int drm_name_info(struct seq_file *m, void *data)
if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) {
if (master->unique) {
seq_printf(m, "%s %s %s\n",
- dev->driver->platform_device->name,
+ dev->platformdev->name,
dev_name(dev->dev), master->unique);
} else {
seq_printf(m, "%s\n",
- dev->driver->platform_device->name);
+ dev->platformdev->name);
}
} else {
if (master->unique) {
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index f5bd9e590c8..6f7e41b5816 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -263,6 +263,19 @@ int drm_pci_init(struct drm_driver *driver)
return 0;
}
+void drm_pci_exit(struct drm_driver *driver)
+{
+ struct drm_device *dev, *tmp;
+
+ if (driver->driver_features & DRIVER_MODESET) {
+ pci_unregister_driver(&driver->pci_driver);
+ } else {
+ list_for_each_entry_safe(dev, tmp, &driver->device_list,
+ driver_item)
+ drm_put_dev(dev);
+ }
+}
+
#else
int drm_pci_init(struct drm_driver *driver)
@@ -270,5 +283,9 @@ int drm_pci_init(struct drm_driver *driver)
return -1;
}
+void drm_pci_exit(struct drm_driver *driver)
+{
+}
+
#endif
/*@}*/
diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c
index 92d1d0fb7b7..8f68a5431db 100644
--- a/drivers/gpu/drm/drm_platform.c
+++ b/drivers/gpu/drm/drm_platform.c
@@ -123,5 +123,10 @@ EXPORT_SYMBOL(drm_get_platform_dev);
int drm_platform_init(struct drm_driver *driver)
{
- return drm_get_platform_dev(driver->platform_device, driver);
+ return platform_driver_register(&driver->platform_driver);
+}
+
+void drm_platform_exit(struct drm_driver *driver)
+{
+ platform_driver_unregister(&driver->platform_driver);
}
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
index 45bd0977d00..4d48b96bb75 100644
--- a/drivers/input/keyboard/omap4-keypad.c
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -29,6 +29,7 @@
#include <linux/io.h>
#include <linux/input.h>
#include <linux/slab.h>
+#include <linux/pm_runtime.h>
#include <plat/omap4-keypad.h>
@@ -239,6 +240,9 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
input_dev->keycode, input_dev->keybit);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
omap4_keypad_config(keypad_data);
error = request_irq(keypad_data->irq, omap4_keypad_interrupt,
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 61834ae282e..e65616cfef2 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -681,6 +681,17 @@ config TOUCHSCREEN_STMPE
To compile this driver as a module, choose M here: the
module will be called stmpe-ts.
+config TOUCHSCREEN_SYNTM12XX
+ tristate "Synaptic TM12xx touchscreen"
+ help
+ Say Y here to enable support for Synaptic TM12xx
+ series touchscreen controller.
+
+ If unsure, say N.
+
+ To compile this driver as module, choose M here: the
+ module will be called syntm12xx
+
config TOUCHSCREEN_TPS6507X
tristate "TPS6507x based touchscreens"
depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 718bcc81495..e24e083a84e 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -56,4 +56,5 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
+obj-$(CONFIG_TOUCHSCREEN_SYNTM12XX) += syntm12xx.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
diff --git a/drivers/input/touchscreen/syntm12xx.c b/drivers/input/touchscreen/syntm12xx.c
new file mode 100644
index 00000000000..c0ab7f7933a
--- /dev/null
+++ b/drivers/input/touchscreen/syntm12xx.c
@@ -0,0 +1,3545 @@
+/*
+ * syntm12xx.c
+ * Synaptic TM12XX touchscreen driver
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Mika Kuoppala <mika.kuoppala@nokia.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+
+#include <plat/syntm12xx.h>
+
+#define DRIVER_DESC "Synaptic TM12xx Touchscreen Driver"
+#define DRIVER_NAME "tm12xx_ts"
+
+/* Do validation of firmware image on device */
+#define FIRMWARE_VERIFY
+
+/* Number of touch points and input devices supported */
+#define MAX_TOUCH_POINTS 6
+
+#define REG_PDT_PROPERTIES 0xef
+#define REG_PAGE_SELECT 0xff
+
+#define FUNC_DEVICE_CONTROL 0x01
+#define FUNC_BIST 0x08
+#define FUNC_2D 0x11
+#define FUNC_BUTTONS 0x19
+#define FUNC_TIMER 0x32
+#define FUNC_FLASH 0x34
+#define FUNC_PROXIMITY 0x40
+
+#define MAX_FUNC_DESCS 7
+
+/* Device Control Functionality */
+#define DEVICE_CONTROL_DATA_STATUS 0x00
+#define DEVICE_CONTROL_DATA_INTR_STATUS 0x01
+
+#define DEVICE_CONTROL_STATUS_SCODE_MASK 0x0f
+#define STATUS_CODE_NO_ERROR 0x00
+#define STATUS_CODE_RESET 0x01
+#define STATUS_CODE_INVALID_CONF 0x02
+#define STATUS_CODE_DEVICE_FAILURE 0x03
+
+#define DEVICE_CONTROL_CTRL 0
+#define DEVICE_CONTROL_CONFIGURED (1 << 7)
+#define DEVICE_CONTROL_SLEEP_NORMAL 0x00
+#define DEVICE_CONTROL_SLEEP_SENSOR 0x01
+#define DEVICE_CONTROL_INTR_ENABLE 1
+#define INTR_FLASH (1 << 0)
+#define INTR_STATUS (1 << 1)
+#define INTR_BIST (1 << 2)
+#define INTR_2D (1 << 3)
+#define INTR_BUTTON (1 << 4)
+#define INTR_UADC (1 << 5)
+#define INTR_ALL 0x3f
+
+#define DEVICE_CONTROL_STATUS_FLASH_PROG (1 << 6)
+#define DEVICE_CONTROL_STATUS_UNCONFIGURED (1 << 7)
+
+#define DEVICE_CONTROL_COMMAND 0x00
+#define DEVICE_COMMAND_RESET (1 << 0)
+#define DEVICE_COMMAND_SHUTDOWN (1 << 1)
+
+#define DEVICE_CONTROL_QUERY_MANID 0
+#define DEVICE_CONTROL_QUERY_PROD_PROPERTIES 1
+#define DEVICE_CONTROL_QUERY_PROD_FAMILY 2
+#define DEVICE_CONTROL_QUERY_FW_VER 3
+#define DEVICE_CONTROL_QUERY_PROD_ID 11
+#define DEVICE_CONTROL_QUERY_PROD_ID_LAST 20
+#define PRODUCT_ID_LEN (DEVICE_CONTROL_QUERY_PROD_ID_LAST - \
+ DEVICE_CONTROL_QUERY_PROD_ID + 1)
+
+
+/* Capasitive Buttons */
+
+#define MAX_BUTTONS 31
+
+#define BUTTON_QUERY_QUERY0 0
+#define BUTTON_QUERY_BUTTON_COUNT 1
+#define BUTTON_QUERY_BUTTON_MASK 0x1f
+
+#define BUTTON_CONFIGURABLE (1 << 0)
+
+/* 2D Functionality */
+
+#define TOUCH_QUERY_NUM_SENSORS 0 /* Zero based */
+#define TOUCH_QUERY_LEN 6
+
+#define TOUCH_CONTROL_REPORT_MODE 0
+#define TOUCH_CONTROL_SENSOR_MAX_X 6
+#define TOUCH_CONTROL_SENSOR_MAX_Y 8
+#define TOUCH_CONTROL_SENSOR_MAPPING 10
+
+/* This is for now fixed for 2 touch points */
+#define TOUCH_DATA_LEN (1 + (MAX_TOUCH_POINTS * 5))
+
+#define FINGER_STATE_NOT_PRESENT 0
+#define FINGER_STATE_ACCURATE 1
+#define FINGER_STATE_INACCURATE 2
+#define FINGER_STATE_RESERVED 3
+
+/* Flashing */
+#define FLASH_MAX_SIZE (16*1024)
+#define FW_MAX_NAME_SIZE 31
+
+#define FLASH_QUERY_BOOTLOADER_ID_0 0
+#define FLASH_QUERY_BOOTLOADER_ID_1 1
+#define FLASH_QUERY_PROPERTIES 2
+#define FLASH_QUERY_BLOCK_SIZE_0 3
+#define FLASH_QUERY_BLOCK_SIZE_1 4
+#define FLASH_QUERY_FW_BLOCK_COUNT_0 5
+#define FLASH_QUERY_FW_BLOCK_COUNT_1 6
+#define FLASH_QUERY_CONF_BLOCK_COUNT_0 7
+#define FLASH_QUERY_CONF_BLOCK_COUNT_1 8
+
+/* Flash Properties */
+#define FLASH_PROPERTY_REGMAP_VERSION (1 << 0)
+
+/* Commands for FLASH_DATA_COMMAND */
+#define FLASH_CMD_IDLE 0x00
+#define FLASH_CMD_FW_CRC_BLOCK 0x01
+#define FLASH_CMD_FW_WRITE_BLOCK 0x02
+#define FLASH_CMD_ERASE_ALL 0x03
+#define FLASH_CMD_CONF_READ_BLOCK 0x05
+#define FLASH_CMD_CONF_WRITE_BLOCK 0x06
+#define FLASH_CMD_CONF_ERASE_BLOCK 0x07
+#define FLASH_CMD_PROGRAM_ENABLE 0x0f
+
+#define FLASH_ERROR_SUCCESS 0
+#define FLASH_ERROR_RESERVED 1
+#define FLASH_ERROR_NOT_ENABLED 2
+#define FLASH_ERROR_INVALID_BLOCK 3
+#define FLASH_ERROR_BLOCK_NOT_ERASED 4
+#define FLASH_ERROR_ERASE_KEY 5
+#define FLASH_ERROR_UNKNOWN 6
+#define FLASH_ERROR_RESET 7
+#define FLASH_ERROR_COUNT 8
+
+#define DEVICE_STATUS_NO_ERROR 0
+#define DEVICE_STATUS_RESET_OCCURRED 1
+#define DEVICE_STATUS_INVALID_CONFIG 2
+#define DEVICE_STATUS_DEVICE_FAILURE 3
+#define DEVICE_STATUS_CFG_CRC_FAILURE 4
+#define DEVICE_STATUS_FW_CRC_FAILURE 5
+#define DEVICE_STATUS_CRC_IN_PROGRESS 6
+#define DEVICE_STATUS_UNKNOWN 7
+#define DEVICE_STATUS_COUNT 8
+
+/* Selftest */
+#define BIST_QUERY_LIMIT_REG_COUNT 0
+#define BIST_DATA_TEST_NUMBER_CTRL 0
+#define BIST_DATA_OVERALL_RESULT 1
+#define BIST_DATA_TEST_RESULT 2
+#define BIST_CONTROL_COMMAND 0
+
+static const char *const device_status_str[DEVICE_STATUS_COUNT] = {
+ "no error",
+ "reset occurred",
+ "invalid configuration",
+ "device failure",
+ "configuration crc failure",
+ "firmware crc failure",
+ "crc in progress",
+ "unknown",
+};
+
+static const char *const flash_error_str[FLASH_ERROR_COUNT] = {
+ "success",
+ "reserved",
+ "programming not enabled",
+ "invalid block number",
+ "block not erased",
+ "erase key incorrect",
+ "unknown",
+ "device reset",
+};
+
+/* Offsets within firmware image */
+#define FW_FILE_CHECKSUM 0x0000
+#define FW_VERSION 0x0007
+#define FW_FW_SIZE 0x0008
+#define FW_CONFIG_SIZE 0x000C
+#define FW_PRODUCT_ID 0x0010
+#define FW_PRODUCT_INFO_0 0x001E
+#define FW_PRODUCT_INFO_1 0x001F
+#define FW_FW_DATA 0x0100
+
+/* How many times we try to re-initialize chip in row */
+#define MAX_FAILED_INITS 4
+
+/* How much data we can put into single write block */
+#define MAX_I2C_WRITE_BLOCK_SIZE 32
+
+#define DFLAG_VERBOSE (1 << 0)
+#define DFLAG_I2C_DUMP (1 << 1)
+
+struct syn;
+
+struct func_desc {
+ void (*intr_handler)(struct syn *sd, u8 bits);
+ u8 num;
+ u8 version;
+ u8 query;
+ u8 command;
+ u8 control;
+ u8 data;
+ u8 exists;
+
+ u8 intr_start_bit;
+ u8 intr_sources;
+};
+
+struct touch_sensor_caps {
+ unsigned is_configurable:1;
+ unsigned has_gestures:1;
+ unsigned has_abs_mode:1;
+ unsigned has_rel_mode:1;
+ unsigned finger_count:4;
+ unsigned x_electrodes:5;
+ unsigned y_electrodes:5;
+ unsigned max_electrodes:5;
+ unsigned abs_data_size:2;
+
+ /* XXX These are not yet in use
+ unsigned has_pinch:1;
+ unsigned has_press:1;
+ unsigned has_flick:1;
+ unsigned has_early_tap:1;
+ unsigned has_double_tap:1;
+ unsigned had_tap_and_hold:1;
+ unsigned has_single_tap:1;
+ unsigned has_anchored_finger:1;
+ unsigned has_palm_detect:1;
+ */
+
+ u16 max_x;
+ u16 max_y;
+};
+
+struct button_caps {
+ u8 button_count;
+};
+
+struct flash_caps {
+ u16 bootloader_id;
+ u16 block_size;
+ u16 fw_block_count;
+ u16 conf_block_count;
+ u8 properties;
+};
+
+struct fw_image {
+ u32 file_checksum;
+ u8 version;
+ u8 product_id[PRODUCT_ID_LEN + 1];
+ u8 product_info_0;
+ u8 product_info_1;
+ const u8 *fw_data;
+ u32 fw_size;
+ const u8 *config_data;
+ u32 config_size;
+ u32 config_checksum;
+};
+
+struct touch_data {
+ u16 x;
+ u16 y;
+ u8 wx;
+ u8 wy;
+ u8 z;
+ u8 finger_state;
+};
+
+struct touch_point {
+ struct input_dev *idev;
+ struct touch_data cur_td;
+ struct touch_data prev_td;
+ int num;
+};
+
+struct bist_test_result {
+ u8 failed; /* == 0, if all passed */
+ u8 result; /* specific error for failed test */
+};
+
+struct syn {
+ struct mutex lock;
+ struct i2c_client *client;
+ struct workqueue_struct *wq;
+ struct work_struct isr_work;
+
+ struct func_desc *control;
+ u8 device_control_ctrl; /* saved state */
+
+ struct func_desc *touch;
+ struct touch_point tp[MAX_TOUCH_POINTS];
+ struct touch_sensor_caps touch_caps;
+
+ struct func_desc *buttons;
+ struct button_caps button_caps;
+ u32 button_state;
+
+ struct func_desc func_desc[MAX_FUNC_DESCS];
+ unsigned func_desc_num;
+ unsigned interrupt_sources;
+
+ struct func_desc *flash;
+ struct flash_caps flash_caps;
+ struct fw_image fw_image;
+ const struct firmware *fw_entry;
+
+ struct func_desc *bist;
+ struct func_desc *timer;
+ struct func_desc *prox;
+
+ int gpio_intr;
+ int func_descs_valid;
+
+ int failed_inits;
+ u32 debug_flag;
+
+ unsigned long ts_intr;
+ unsigned long ts_work;
+ unsigned long ts_done;
+
+ unsigned long t_wakeup_min;
+ unsigned long t_wakeup_max;
+ unsigned long t_wakeup_c;
+
+ unsigned long t_work_min;
+ unsigned long t_work_max;
+ unsigned long t_work_c;
+
+ unsigned long t_wakeup;
+ unsigned long t_work;
+
+ unsigned long t_count;
+ unsigned long f_measure;
+
+ int virtualized;
+};
+
+static int syn_initialize(struct syn *sd);
+static int syn_reset_device(struct syn *sd);
+static int syn_read_func_descs(struct syn *sd);
+
+static int syn_write_block(struct syn *sd, int reg, const u8 *data, int len)
+{
+ unsigned char wb[MAX_I2C_WRITE_BLOCK_SIZE + 1];
+ struct i2c_msg msg;
+ int r;
+ int i;
+
+ if (len < 1 ||
+ len > MAX_I2C_WRITE_BLOCK_SIZE) {
+ dev_info(&sd->client->dev, "too long syn_write_block len %d\n",
+ len);
+ return -EIO;
+ }
+
+ wb[0] = reg & 0xff;
+
+ for (i = 0; i < len; i++)
+ wb[i + 1] = data[i];
+
+ msg.addr = sd->client->addr;
+ msg.flags = 0;
+ msg.len = len + 1;
+ msg.buf = wb;
+
+ r = i2c_transfer(sd->client->adapter, &msg, 1);
+
+ if (sd->debug_flag & DFLAG_I2C_DUMP) {
+ if (r == 1) {
+ for (i = 0; i < len; i++)
+ dev_info(&sd->client->dev,
+ "bw 0x%02x[%d]: 0x%02x\n",
+ reg + i, i, data[i]);
+ }
+ }
+
+ if (r == 1)
+ return 0;
+
+ return r;
+}
+
+static int syn_read_block(struct syn *sd, int reg, u8 *data, int len)
+{
+ unsigned char wb[1];
+ struct i2c_msg msg[2];
+ int r;
+
+ wb[0] = reg & 0xff;
+
+ msg[0].addr = sd->client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = wb;
+
+ msg[1].addr = msg[0].addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = len;
+ msg[1].buf = data;
+
+ r = i2c_transfer(sd->client->adapter, msg, 2);
+
+ if (sd->debug_flag & DFLAG_I2C_DUMP) {
+ if (r == 2) {
+ int i;
+
+ for (i = 0; i < len; i++)
+ dev_info(&sd->client->dev,
+ "br 0x%02x[%d]: 0x%02x\n",
+ reg + i, i, data[i]);
+ }
+ }
+
+ if (r == 2)
+ return len;
+
+ return r;
+}
+
+static int syn_read_u8(struct syn *sd, int reg)
+{
+ unsigned char b[1];
+ int r;
+
+ r = syn_read_block(sd, reg, b, 1);
+ if (r == 1)
+ return (int)b[0];
+
+ return r;
+}
+
+static int syn_write_u8(struct syn *sd, u8 reg, u8 value)
+{
+ return syn_write_block(sd, reg, &value, 1);
+}
+
+static int syn_read_u16(struct syn *sd, int reg)
+{
+ int r;
+ u8 data[2];
+
+ r = syn_read_block(sd, reg, data, 2);
+ if (r < 0)
+ return r;
+
+ return (int)data[0] | ((int)(data[1]) << 8);
+}
+
+static int syn_write_u16(struct syn *sd, int reg, u16 value)
+{
+ u8 data[2];
+
+ data[1] = (value & 0xFF00) >> 8;
+ data[0] = value & 0x00FF;
+
+ return syn_write_block(sd, reg, data, 2);
+}
+
+static int syn_control_query_read(struct syn *sd, int reg)
+{
+ return syn_read_u8(sd, sd->control->query + reg);
+}
+
+static int syn_control_data_read(struct syn *sd, int reg)
+{
+ return syn_read_u8(sd, sd->control->data + reg);
+}
+
+static const char *syn_device_status_str(u8 dev_status)
+{
+ if (dev_status >= DEVICE_STATUS_COUNT)
+ return device_status_str[DEVICE_STATUS_UNKNOWN];
+
+ return device_status_str[dev_status];
+}
+
+static int syn_get_nosleep(struct syn *sd)
+{
+ int r;
+
+ r = syn_read_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL);
+ if (r < 0)
+ return r;
+
+ return (r & 0x04) >> 2;
+}
+
+static int syn_set_nosleep(struct syn *sd, int val)
+{
+ int r;
+
+ r = syn_read_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL);
+ if (r < 0)
+ return r;
+
+ val = (r & (~0x04)) | ((!!val) << 2);
+
+ r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL,
+ val);
+
+ return r;
+}
+
+static int syn_get_proximity_state(struct syn *sd)
+{
+ int r;
+
+ if (!sd->prox)
+ return -ENODEV;
+
+ r = syn_read_u8(sd, sd->prox->control);
+ if (r < 0)
+ return r;
+
+ return (r & (1 << 7)) == 0;
+}
+
+static int syn_set_proximity_state(struct syn *sd, int val)
+{
+ int r;
+
+ if (!sd->prox)
+ return -ENODEV;
+
+ r = syn_read_u8(sd, sd->prox->control);
+ if (r < 0)
+ return r;
+
+ /* It is called 'inhibit proximity' in register */
+ val = (r & (~0x80)) | ((!val) << 7);
+
+ r = syn_write_u8(sd, sd->prox->control,
+ val);
+ if (r < 0)
+ return r;
+
+ return r;
+}
+
+static void syn_report_device_status(struct syn *sd, u8 dev_status)
+{
+ struct device *dev = &sd->client->dev;
+
+ if (dev_status & (1 << 7))
+ dev_info(dev, "device is unconfigured\n");
+
+ if (dev_status & (1 << 6))
+ dev_info(dev, "device is in flashing mode\n");
+
+ dev_info(dev, "device status: 0x%x, %s\n", dev_status,
+ syn_device_status_str(dev_status & 0x0f));
+}
+
+static void syn_device_change_state(struct syn *sd, u8 dev_status)
+{
+ int r;
+
+ /* Unconfigured or reset, we initialize*/
+ if ((dev_status & (1 << 7)) ||
+ (dev_status & 0x0f) == DEVICE_STATUS_RESET_OCCURRED) {
+ r = syn_initialize(sd);
+ if (r)
+ dev_err(&sd->client->dev,
+ "error %d in syn_initialize\n", r);
+ }
+}
+
+static void syn_recalculate_latency_data(struct syn *sd)
+{
+ if (sd->ts_intr <= sd->ts_work && sd->ts_work < sd->ts_done) {
+ sd->t_wakeup = sd->ts_work - sd->ts_intr;
+ do_div(sd->t_wakeup, 1000);
+ sd->t_work = sd->ts_done - sd->ts_work;
+ do_div(sd->t_work, 1000);
+
+ if (sd->t_wakeup > sd->t_wakeup_max)
+ sd->t_wakeup_max = sd->t_wakeup;
+
+ if (sd->t_wakeup < sd->t_wakeup_min)
+ sd->t_wakeup_min = sd->t_wakeup;
+
+ if (sd->t_work > sd->t_work_max)
+ sd->t_work_max = sd->t_work;
+
+ if (sd->t_work < sd->t_work_min)
+ sd->t_work_min = sd->t_work;
+
+ if ((sd->t_work_c + sd->t_work) < sd->t_work_c ||
+ (sd->t_wakeup_c + sd->t_wakeup) < sd->t_wakeup_c) {
+
+ /* Wrap */
+ sd->t_work_c = sd->t_work;
+ sd->t_wakeup_c = sd->t_wakeup;
+ sd->t_count = 0;
+ } else {
+ sd->t_work_c += sd->t_work;
+ sd->t_wakeup_c += sd->t_wakeup;
+ sd->t_count++;
+ }
+ } else {
+ /* Time wrap or something else, discard */
+ }
+}
+
+static void syn_isr_device_control(struct syn *sd, u8 bits)
+{
+ int dev_status;
+
+ dev_status = syn_control_data_read(sd, DEVICE_CONTROL_DATA_STATUS);
+ if (dev_status < 0) {
+ dev_err(&sd->client->dev, "error %d reading device status\n",
+ dev_status);
+ }
+
+ syn_report_device_status(sd, dev_status);
+
+ syn_device_change_state(sd, dev_status);
+}
+
+static void syn_isr_flash(struct syn *sd, u8 bits)
+{
+ int dev_status;
+
+ dev_info(&sd->client->dev, "flash interrupt\n");
+
+ if (!sd->flash) {
+ dev_warn(&sd->client->dev,
+ "flash interrupt without registered functionality\n");
+ return;
+ }
+
+ dev_status = syn_control_data_read(sd, DEVICE_CONTROL_DATA_STATUS);
+ syn_report_device_status(sd, dev_status);
+
+ syn_device_change_state(sd, dev_status);
+}
+
+static void syn_isr_timer(struct syn *sd, u8 bits)
+{
+ if (!sd->timer) {
+ dev_warn(&sd->client->dev,
+ "flash interrupt without registered functionality\n");
+ return;
+ }
+}
+
+static void syn_isr_bist(struct syn *sd, u8 bits)
+{
+ if (!sd->bist) {
+ dev_warn(&sd->client->dev,
+ "bist interrupt without registered functionality\n");
+ return;
+ }
+}
+
+static void syn_isr_proximity(struct syn *sd, u8 bits)
+{
+ unsigned char data[6];
+ struct input_dev *idev;
+ int r;
+
+ idev = sd->tp[0].idev;
+
+ if (!sd->prox) {
+ dev_warn(&sd->client->dev,
+ "spurious proximity interrupty\n");
+ return;
+ }
+
+ r = syn_read_block(sd, sd->prox->data, data, 6);
+ if (r < 0) {
+ dev_warn(&sd->client->dev,
+ "error %d reading proximity data\n", r);
+ return;
+ }
+
+ if (data[0] & 0x01) {
+ input_report_abs(idev, ABS_RZ, data[1]);
+ input_report_abs(idev, ABS_HAT0X, data[2]); /* BH */
+ input_report_abs(idev, ABS_HAT0Y, data[4]); /* LH */
+ input_report_abs(idev, ABS_HAT1X, data[3]); /* TH */
+ input_report_abs(idev, ABS_HAT1Y, data[5]); /* RH */
+ } else
+ input_report_abs(idev, ABS_RZ, 0);
+
+ input_sync(idev);
+}
+
+static void syn_touch_parse_one_touch_data(struct syn *sd, struct touch_data *p,
+ u8 finger_state, const u8 *d)
+{
+ p->finger_state = finger_state;
+ p->x = (u16)(d[2] & 0x0f) | (u16)(d[0] << 4);
+ p->y = ((u16)(d[2] & 0xf0) >> 4) | (u16)(d[1] << 4);
+ p->wx = d[3] & 0x0f;
+ p->wy = (d[3] & 0xf0) >> 4;
+ p->z = d[4];
+}
+
+static void syn_touch_parse_touch_data(struct syn *sd, const u8 *d)
+{
+ unsigned i;
+ u8 fc;
+ u8 fs;
+ struct touch_data *p;
+
+ fc = sd->touch_caps.finger_count;
+
+ if (fc > MAX_TOUCH_POINTS)
+ dev_err(&sd->client->dev, "error in finger count %d\n", fc);
+
+ for (i = 0; i < fc; i++) {
+ p = &sd->tp[i].cur_td;
+
+ fs = (d[(i >> 2)] >> ((i % 4) << 1)) & 0x03;
+
+ /* dev_warn(&sd->client->dev, "fs[%d] = %d\n", i, fs); */
+
+ syn_touch_parse_one_touch_data(sd, p, fs,
+ d + ((fc >> 2) + 1) +
+ i * 5);
+
+ }
+}
+
+static int syn_touch_get_data(struct syn *sd)
+{
+ int r;
+ u8 data[TOUCH_DATA_LEN];
+
+ r = syn_read_block(sd, sd->touch->data, data, TOUCH_DATA_LEN);
+ if (r < 0)
+ return r;
+
+ if (r != TOUCH_DATA_LEN)
+ return -EIO;
+
+ syn_touch_parse_touch_data(sd, data);
+
+ return 0;
+}
+
+static void syn_touch_report_data(struct syn *sd, int dev_number)
+{
+ struct tm12xx_ts_platform_data *pdata = sd->client->dev.platform_data;
+ struct input_dev *idev;
+ struct touch_data *d;
+ struct touch_data *p;
+
+ idev = sd->tp[dev_number].idev;
+ d = &sd->tp[dev_number].cur_td;
+ p = &sd->tp[dev_number].prev_td;
+
+ if (memcmp(p, d, sizeof(struct touch_data)) == 0)
+ return;
+
+ memcpy(p, d, sizeof(struct touch_data));
+
+ switch (d->finger_state) {
+
+ case FINGER_STATE_ACCURATE:
+ input_report_key(idev, BTN_TOUCH, 1);
+ input_report_key(idev, BTN_MODE, 0);
+ break;
+
+ case FINGER_STATE_INACCURATE:
+ input_report_key(idev, BTN_TOUCH, 1);
+ input_report_key(idev, BTN_MODE, 1);
+ break;
+
+ case FINGER_STATE_RESERVED:
+ /* Intentional fall thru */
+
+ case FINGER_STATE_NOT_PRESENT:
+ input_report_key(idev, BTN_MODE, 0);
+ input_report_key(idev, BTN_TOUCH, 0);
+ goto out;
+
+ default:
+ dev_err(&sd->client->dev, "unknown finger state 0x%x\n",
+ d->finger_state);
+ goto out;
+ }
+
+ if (sd->virtualized && pdata->swap_xy &&
+ dev_name(&sd->client->dev)[0] != '2')
+ d->x = sd->touch_caps.max_x + d->x;
+
+ if (pdata->swap_xy) {
+ input_report_abs(idev, ABS_X, d->y);
+ input_report_abs(idev, ABS_Y, d->x);
+ input_report_abs(idev, ABS_TOOL_WIDTH, d->wy);
+ } else {
+ input_report_abs(idev, ABS_X, d->x);
+ input_report_abs(idev, ABS_Y, d->y);
+ input_report_abs(idev, ABS_TOOL_WIDTH, d->wx);
+ }
+
+ input_report_abs(idev, ABS_Z, d->z);
+ input_report_abs(idev, ABS_VOLUME, d->wx * d->wy);
+
+out:
+ input_sync(idev);
+}
+
+static void syn_isr_2d(struct syn *sd, u8 bits)
+{
+ int r;
+ int i;
+
+ if (!sd->touch) {
+ dev_warn(&sd->client->dev,
+ "2d interrupt without registered functionality\n");
+ return;
+ }
+
+ r = syn_touch_get_data(sd);
+ if (r) {
+ dev_err(&sd->client->dev, "error getting touch data\n");
+ return;
+ }
+
+ if (sd->debug_flag & DFLAG_VERBOSE) {
+ dev_info(&sd->client->dev,
+ "1: state=0x%x, x=%d, y=%d, z=%d, wx=%d, wy=%d\n",
+ sd->tp[0].cur_td.finger_state,
+ sd->tp[0].cur_td.x, sd->tp[0].cur_td.y,
+ sd->tp[0].cur_td.z, sd->tp[0].cur_td.wx,
+ sd->tp[0].cur_td.wy);
+ dev_info(&sd->client->dev,
+ "2: state=0x%x, x=%d, y=%d, z=%d, wx=%d, wy=%d\n",
+ sd->tp[1].cur_td.finger_state,
+ sd->tp[1].cur_td.x, sd->tp[1].cur_td.y,
+ sd->tp[1].cur_td.z, sd->tp[1].cur_td.wx,
+ sd->tp[1].cur_td.wy);
+ }
+
+ for (i = 0; i < sd->touch_caps.finger_count; i++)
+ syn_touch_report_data(sd, i);
+}
+
+static int syn_button_report(struct syn *sd, unsigned button_nr, const int val)
+{
+ struct tm12xx_ts_platform_data *pdata = sd->client->dev.platform_data;
+ unsigned max_buttons;
+
+ max_buttons = pdata->num_buttons;
+
+ if (button_nr >= max_buttons)
+ return -EINVAL;
+
+ input_report_key(sd->tp[0].idev, pdata->button_map[button_nr], val);
+ input_sync(sd->tp[0].idev);
+
+ return 0;
+}
+
+static void syn_isr_buttons(struct syn *sd, u8 bits)
+{
+ int data_reg_count = (sd->button_caps.button_count + 7) / 8;
+ int i = 0;
+ int r;
+ u32 state = 0;
+ u32 last_state;
+
+ if (!sd->buttons) {
+ dev_warn(&sd->client->dev,
+ "button interrupt without registered functionality\n");
+ return;
+ }
+
+ if (data_reg_count > MAX_BUTTONS/8 + 1)
+ data_reg_count = MAX_BUTTONS/8 + 1;
+
+ while (i < data_reg_count) {
+ r = syn_read_u8(sd, sd->buttons->data + i);
+ if (r < 0) {
+ dev_err(&sd->client->dev,
+ "error reading button state\n");
+ return;
+ }
+
+ state |= (u32)r << (i * 8);
+ i++;
+ }
+
+ last_state = sd->button_state;
+
+ for (i = 0; i < sd->button_caps.button_count; i++) {
+ const u32 mask = (1 << i);
+ if ((state & mask) ^ (last_state & mask)) {
+ r = syn_button_report(sd, i, state & mask ? 1 : 0);
+ if (r) {
+ dev_warn(&sd->client->dev,
+ "error reporting button "
+ "(no mapping for %d ?)\n", i);
+ }
+ }
+ }
+
+ sd->button_state = state;
+}
+
+static u8 syn_get_status_bits(u8 *int_status, int start, int bits)
+{
+ const u16 mask = ((1 << bits) - 1) << start;
+ u8 val;
+
+ val = (*int_status & mask) >> start;
+
+ *int_status &= ~mask;
+
+ return val;
+}
+
+static void syn_isr_call_handlers(struct syn *sd, u8 int_status)
+{
+ int i;
+ u8 bits;
+
+ for (i = 0; i < sd->func_desc_num; i++) {
+ struct func_desc * const f = &sd->func_desc[i];
+
+ if (!int_status)
+ return;
+
+ bits = syn_get_status_bits(&int_status, f->intr_start_bit,
+ f->intr_sources);
+
+ if (likely(bits)) {
+ if (likely(f->intr_handler))
+ f->intr_handler(sd, bits);
+ else {
+ if (printk_ratelimit())
+ dev_warn(&sd->client->dev,
+ "no intr handler for %d\n", i);
+ }
+ }
+ }
+
+ if (unlikely(int_status))
+ dev_warn(&sd->client->dev,
+ "unhandled attentions: 0x%x\n", int_status);
+}
+
+static void syn_clear_device_state(struct syn *sd)
+{
+ int i;
+
+ sd->control = NULL;
+
+ sd->touch = NULL;
+ /*
+ * We don't clear previous exported devices.
+ * If after firmware upgrade there would be different
+ * amount of touchpoints rmmod/insmod cycle is needed.
+ */
+ memset(&sd->touch_caps, 0, sizeof(struct touch_sensor_caps));
+
+ sd->buttons = NULL;
+ memset(&sd->button_caps, 0, sizeof(struct button_caps));
+ sd->button_state = 0;
+
+ for (i = 0; i < MAX_FUNC_DESCS; i++)
+ memset(&sd->func_desc[i], 0, sizeof(struct func_desc));
+
+ sd->func_desc_num = 0;
+ sd->interrupt_sources = 0;
+
+ sd->flash = NULL;
+ memset(&sd->flash_caps, 0, sizeof(struct flash_caps));
+ memset(&sd->fw_image, 0, sizeof(struct fw_image));
+
+ sd->bist = NULL;
+}
+
+static void syn_isr_work(struct work_struct *work)
+{
+ int is;
+ int r;
+ struct syn *sd = container_of(work, struct syn, isr_work);
+
+ mutex_lock(&sd->lock);
+
+ if (sd->f_measure) {
+ sd->ts_work = cpu_clock(get_cpu());
+ put_cpu();
+ }
+
+ if (sd->func_descs_valid == 0) {
+ if (sd->failed_inits < MAX_FAILED_INITS) {
+ r = syn_initialize(sd);
+ if (r) {
+ dev_err(&sd->client->dev,
+ "error initializing\n");
+ goto out;
+ }
+ }
+ }
+
+ is = syn_control_data_read(sd, DEVICE_CONTROL_DATA_INTR_STATUS);
+
+ if (unlikely(is < 0)) {
+ dev_err(&sd->client->dev,
+ "unable to read intr status\n");
+ syn_reset_device(sd);
+ goto out;
+ }
+
+ if (likely(is))
+ syn_isr_call_handlers(sd, is);
+
+out:
+ if (sd->f_measure) {
+ sd->ts_done = cpu_clock(get_cpu());
+ put_cpu();
+ syn_recalculate_latency_data(sd);
+ sd->f_measure = 0;
+ }
+ enable_irq(gpio_to_irq(sd->gpio_intr));
+ mutex_unlock(&sd->lock);
+}
+
+static irqreturn_t syn_isr(int irq, void *data)
+{
+ struct syn *sd = data;
+
+ if (sd->wq != NULL) {
+ int r;
+ r = queue_work(sd->wq, &sd->isr_work);
+ if (r) {
+ if (sd->f_measure == 0) {
+ sd->ts_intr = cpu_clock(get_cpu());
+ put_cpu();
+ sd->f_measure = 1;
+ }
+ disable_irq_nosync(gpio_to_irq(sd->gpio_intr));
+ }
+
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int syn_set_input_dev_params(struct syn *sd, int dev_number)
+{
+ struct input_dev *dev;
+ struct tm12xx_ts_platform_data *pdata;
+ int i;
+
+ if (!sd || dev_number < 0 || dev_number >= MAX_TOUCH_POINTS)
+ return -EINVAL;
+
+ dev = sd->tp[dev_number].idev;
+ if (!dev)
+ return -ENODEV;
+
+ pdata = sd->client->dev.platform_data;
+
+ set_bit(EV_KEY, dev->evbit);
+ set_bit(EV_ABS, dev->evbit);
+
+ set_bit(BTN_TOUCH, dev->keybit);
+ set_bit(BTN_MODE, dev->keybit);
+
+ set_bit(ABS_X, dev->absbit);
+ set_bit(ABS_Y, dev->absbit);
+ set_bit(ABS_Z, dev->absbit);
+ set_bit(ABS_VOLUME, dev->absbit);
+ set_bit(ABS_TOOL_WIDTH, dev->absbit);
+
+ if (dev_number == 0) {
+ set_bit(ABS_RZ, dev->absbit);
+ set_bit(ABS_HAT0X, dev->absbit);
+ set_bit(ABS_HAT0Y, dev->absbit);
+ set_bit(ABS_HAT1X, dev->absbit);
+ set_bit(ABS_HAT1Y, dev->absbit);
+ }
+
+ if (pdata->repeat)
+ set_bit(EV_REP, dev->evbit);
+
+ for (i = 0; i < pdata->num_buttons; i++)
+ set_bit(pdata->button_map[i], dev->keybit);
+
+ if (pdata->swap_xy) {
+ input_set_abs_params(dev, ABS_X, 0, sd->touch_caps.max_y, 0, 0);
+ input_set_abs_params(dev, ABS_Y, 0, sd->touch_caps.max_x, 0, 0);
+ } else {
+ input_set_abs_params(dev, ABS_X, 0, sd->touch_caps.max_x, 0, 0);
+ input_set_abs_params(dev, ABS_Y, 0, sd->touch_caps.max_y, 0, 0);
+ }
+
+ input_set_abs_params(dev, ABS_Z, 0, 255, 0, 0);
+ input_set_abs_params(dev, ABS_VOLUME, 0, 225, 0, 0);
+ input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
+
+ if (dev_number == 0) {
+ input_set_abs_params(dev, ABS_RZ, 0, 255, 0, 0);
+ input_set_abs_params(dev, ABS_HAT0X, 0, 255, 0, 0);
+ input_set_abs_params(dev, ABS_HAT0Y, 0, 255, 0, 0);
+ input_set_abs_params(dev, ABS_HAT1X, 0, 255, 0, 0);
+ input_set_abs_params(dev, ABS_HAT1Y, 0, 255, 0, 0);
+ }
+
+ dev->dev.parent = &sd->client->dev;
+
+ return 0;
+}
+
+static int syn_register_input_devices(struct syn *sd, int num_devices)
+{
+ struct tm12xx_ts_platform_data *pdata;
+ int r;
+ int i;
+ int j;
+
+ if (!sd || num_devices < 0 || num_devices > MAX_TOUCH_POINTS)
+ return -EINVAL;
+
+ pdata = sd->client->dev.platform_data;
+
+ /* After firmware upgrade no need to reregister */
+ if (sd->tp[0].idev != NULL) {
+ if (sd->debug_flag & DFLAG_VERBOSE)
+ dev_info(&sd->client->dev,
+ "input device already existing\n");
+ return 0;
+ }
+
+ for (i = 0; i < num_devices; i++) {
+ sd->tp[i].idev = input_allocate_device();
+ if (!sd->tp[i].idev) {
+ dev_err(&sd->client->dev,
+ "not enough memory for input device %d\n", i);
+ r = -ENOMEM;
+ goto err_alloc;
+ }
+ }
+
+ for (i = 0; i < num_devices; i++) {
+ r = syn_set_input_dev_params(sd, i);
+ if (r != 0)
+ goto err_alloc;
+
+ if (pdata->idev_name[i])
+ sd->tp[i].idev->name = pdata->idev_name[i];
+ else {
+ dev_err(&sd->client->dev,
+ "no input device name. check platform data\n");
+ goto err_alloc;
+ }
+ }
+
+ /* We use j in the err_alloc to unregister */
+ for (j = 0; j < num_devices; j++) {
+ r = input_register_device(sd->tp[j].idev);
+ if (r) {
+ dev_err(&sd->client->dev,
+ "failed to register input device %d\n", j);
+ goto err_register;
+ }
+ }
+
+ return 0;
+
+err_register:
+ for (i = 0; i < j; i++)
+ input_unregister_device(sd->tp[i].idev);
+err_alloc:
+ for (i = 0; i < num_devices; i++) {
+ if (sd->tp[i].idev) {
+ input_free_device(sd->tp[i].idev);
+ sd->tp[i].idev = NULL;
+ }
+ }
+
+ return r;
+}
+
+static struct func_desc *syn_get_func_desc(struct syn *sd, int func)
+{
+ int i;
+
+ for (i = 0; i < sd->func_desc_num; i++) {
+ struct func_desc * const f = &sd->func_desc[i];
+
+ if (f->num == func)
+ return f;
+ }
+
+ return NULL;
+}
+
+static int syn_register_intr_handler(struct syn *sd, int func,
+ void (*h)(struct syn *sd, u8 bits))
+{
+ struct func_desc * const f = syn_get_func_desc(sd, func);
+
+ if (!f)
+ return -EINVAL;
+
+ if (f->intr_handler == NULL) {
+ f->intr_handler = h;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * Flashing support
+ */
+static int syn_flash_query_caps(struct syn *sd)
+{
+ int r;
+
+ r = syn_read_u16(sd, sd->flash->query + FLASH_QUERY_BOOTLOADER_ID_0);
+ if (r < 0)
+ return r;
+
+ sd->flash_caps.bootloader_id = r;
+
+ r = syn_read_u8(sd, sd->flash->query + FLASH_QUERY_PROPERTIES);
+ if (r < 0)
+ return r;
+
+ sd->flash_caps.properties = r;
+
+ r = syn_read_u16(sd, sd->flash->query + FLASH_QUERY_BLOCK_SIZE_0);
+ if (r < 0)
+ return r;
+
+ sd->flash_caps.block_size = r;
+
+ r = syn_read_u16(sd, sd->flash->query + FLASH_QUERY_FW_BLOCK_COUNT_0);
+ if (r < 0)
+ return r;
+
+ sd->flash_caps.fw_block_count = r;
+
+ r = syn_read_u16(sd, sd->flash->query + FLASH_QUERY_CONF_BLOCK_COUNT_0);
+ if (r < 0)
+ return r;
+
+ sd->flash_caps.conf_block_count = r;
+
+ return 0;
+}
+
+static u32 syn_crc_fletcher32(const u16 *data, unsigned int len)
+{
+ u32 sum1 = 0xffff;
+ u32 sum2 = 0xffff;
+
+ while (len--) {
+ sum1 += *data++;
+ sum2 += sum1;
+
+ sum1 = (sum1 & 0xffff) + (sum1 >> 16);
+ sum2 = (sum2 & 0xffff) + (sum2 >> 16);
+ }
+
+ return sum1 | (sum2 << 16);
+}
+
+static int syn_fw_read_bytes(struct syn *sd, u8 *b, int offset, int len)
+{
+ if (offset + len > sd->fw_entry->size) {
+ dev_err(&sd->client->dev,
+ "fw_read_bytes overflow on offset %d\n", offset);
+ return -EINVAL;
+ }
+
+ memcpy(b, sd->fw_entry->data + offset, len);
+
+ return len;
+}
+
+static int syn_fw_read_u32(struct syn *sd, u32 *d, int offset)
+{
+ const u8 *l;
+
+ if (offset + 4 > sd->fw_entry->size) {
+ dev_err(&sd->client->dev,
+ "fw_read_u32 overflow on offset %d\n", offset);
+
+ return -EINVAL;
+ }
+
+ l = sd->fw_entry->data + offset;
+
+ *d = l[0] | (l[1] << 8) | (l[2] << 16) | (l[3] << 24);
+
+ return 4;
+}
+
+static int syn_request_firmware(struct syn *sd, const char *filename)
+{
+ int r;
+
+ r = request_firmware(&sd->fw_entry, filename, &sd->client->dev);
+
+ return r;
+}
+
+static int syn_check_firmware(struct syn *sd)
+{
+ u32 calc_file_crc;
+ u32 calc_config_crc;
+ struct fw_image *d = &sd->fw_image;
+ int r;
+
+ /*
+ * Restrict sizes.
+ * Absolute minimum is zero sized fw data and config
+ * areas.
+ */
+
+ if (sd->fw_entry->size > FLASH_MAX_SIZE ||
+ sd->fw_entry->size < FW_FW_DATA + 4) {
+ dev_err(&sd->client->dev, "illegal firmware size\n");
+ return -EINVAL;
+ }
+
+ r = syn_fw_read_u32(sd, &d->file_checksum, FW_FILE_CHECKSUM);
+ if (r < 0)
+ return r;
+
+ r = syn_fw_read_bytes(sd, &d->version, FW_VERSION, 1);
+ if (r < 0)
+ return r;
+
+ r = syn_fw_read_u32(sd, &d->fw_size, FW_FW_SIZE);
+ if (r < 0)
+ return r;
+
+ r = syn_fw_read_u32(sd, &d->config_size, FW_CONFIG_SIZE);
+ if (r < 0)
+ return r;
+
+ if ((d->fw_size + d->config_size + FW_FW_DATA) > sd->fw_entry->size) {
+ dev_err(&sd->client->dev, "fw size mismatch\n");
+ return -EINVAL;
+ }
+
+ /* These have to be u32 aligned */
+ if ((d->fw_size & 0x0f) || (d->config_size & 0x0f)) {
+ dev_err(&sd->client->dev, "fw areas not aligned to 4 bytes\n");
+ return -EINVAL;
+ }
+
+ r = syn_fw_read_bytes(sd, d->product_id, FW_PRODUCT_ID,
+ PRODUCT_ID_LEN);
+ if (r < 10)
+ return r;
+
+ r = syn_fw_read_bytes(sd, &d->product_info_0,
+ FW_PRODUCT_INFO_0, 1);
+ if (r < 0)
+ return r;
+
+ r = syn_fw_read_bytes(sd, &d->product_info_1,
+ FW_PRODUCT_INFO_1, 1);
+ if (r < 0)
+ return r;
+
+ r = syn_fw_read_u32(sd, &d->config_checksum,
+ d->fw_size + FW_FW_DATA + d->config_size - 4);
+ if (r < 0)
+ return r;
+
+ d->fw_data = sd->fw_entry->data + FW_FW_DATA;
+ d->config_data = sd->fw_entry->data + FW_FW_DATA + d->fw_size;
+
+ calc_file_crc = syn_crc_fletcher32((u16 *)(sd->fw_entry->data + 4),
+ (sd->fw_entry->size - 4) >> 1);
+
+ calc_config_crc = syn_crc_fletcher32((u16 *)(d->config_data),
+ (d->config_size - 4) >> 1);
+
+ if (calc_file_crc != d->file_checksum) {
+ dev_err(&sd->client->dev, "fw file crc failed\n");
+ return -EINVAL;
+ }
+
+ if (calc_config_crc != d->config_checksum) {
+ dev_err(&sd->client->dev, "fw config area crc failed\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const char *syn_flash_error_str(u8 flash_error)
+{
+ if (flash_error >= FLASH_ERROR_COUNT)
+ return flash_error_str[FLASH_ERROR_UNKNOWN];
+
+ return flash_error_str[flash_error];
+}
+
+static u8 syn_flash_error(int flash_status)
+{
+ return ((u8)(flash_status) >> 4) & 0x07;
+}
+
+/*
+ * There are two different ways the flash register are organized
+ */
+static u8 syn_flash_data_command_offset(struct syn *sd)
+{
+ if (sd->flash_caps.properties & FLASH_PROPERTY_REGMAP_VERSION)
+ return 2 + sd->flash_caps.block_size;
+ else
+ return 0;
+}
+
+static u8 syn_flash_block_data_offset(struct syn *sd)
+{
+ if (sd->flash_caps.properties & FLASH_PROPERTY_REGMAP_VERSION)
+ return 2;
+ else
+ return 3;
+}
+
+static u8 syn_flash_block_num_offset(struct syn *sd)
+{
+ if (sd->flash_caps.properties & FLASH_PROPERTY_REGMAP_VERSION)
+ return 0;
+ else
+ return 1;
+}
+
+static int syn_flash_status(struct syn *sd)
+{
+ return syn_read_u8(sd, sd->flash->data +
+ syn_flash_data_command_offset(sd));
+}
+
+static int syn_wait_for_attn(struct syn *sd, unsigned long timeout_usecs,
+ int state)
+{
+ const unsigned long one_wait = 20;
+ unsigned long waited = 0;
+ int r;
+
+ do {
+ r = gpio_get_value(sd->gpio_intr);
+ if (r == state)
+ break;
+
+ udelay(one_wait);
+ waited += one_wait;
+ } while (waited < timeout_usecs);
+
+ if (waited > 500000 ||
+ waited >= timeout_usecs ||
+ (sd->debug_flag & DFLAG_VERBOSE))
+ dev_info(&sd->client->dev, "waited %lu usecs for attn\n",
+ waited);
+
+ return r == state ? 0 : -1;
+}
+
+static int syn_flash_command(struct syn *sd, u8 flash_command)
+{
+ int r;
+ int s;
+
+ if (flash_command & 0xf0)
+ return -EINVAL;
+
+ r = syn_wait_for_attn(sd, 200 * 1000, 1);
+ if (r) {
+ dev_err(&sd->client->dev,
+ "timeout: attn didn't clear for 200 ms\n");
+ return r;
+ }
+
+ r = syn_write_u8(sd,
+ sd->flash->data + syn_flash_data_command_offset(sd),
+ flash_command);
+
+ if (r) {
+ dev_err(&sd->client->dev, "flash command error %d\n", r);
+ return r;
+ }
+
+ r = syn_wait_for_attn(sd, 700 * 1000, 0);
+ if (r) {
+ dev_err(&sd->client->dev,
+ "timeout attn didn't assert for 700 ms\n");
+ }
+
+ s = syn_control_data_read(sd, DEVICE_CONTROL_DATA_INTR_STATUS);
+ if (s < 0)
+ dev_err(&sd->client->dev, "error reading int status\n");
+
+ if (sd->debug_flag & DFLAG_VERBOSE) {
+ if (s != 0x01)
+ dev_info(&sd->client->dev,
+ "wait for attn intr status 0x%x\n", s);
+ }
+
+ return r == 0 ? 0 : -1;
+}
+
+static int syn_flash_enable(struct syn *sd)
+{
+ int r;
+
+ r = syn_control_data_read(sd, DEVICE_CONTROL_DATA_STATUS);
+ if (r < 0)
+ return r;
+
+ if (r & (1 << 6)) {
+ dev_err(&sd->client->dev, "flashing mode already enabled\n");
+ return 0;
+ }
+
+ r = syn_write_u16(sd, sd->flash->data + syn_flash_block_data_offset(sd),
+ sd->flash_caps.bootloader_id);
+ if (r < 0)
+ return r;
+
+ r = syn_flash_command(sd, FLASH_CMD_PROGRAM_ENABLE);
+ if (r < 0)
+ return r;
+
+ r = syn_read_func_descs(sd);
+ if (r < 0)
+ return r;
+
+ r = syn_flash_status(sd);
+ if (r < 0) {
+ dev_info(&sd->client->dev, "flash error in enable %s\n",
+ syn_flash_error_str(syn_flash_error(r)));
+ return r;
+ }
+
+ if (syn_flash_error(r) != FLASH_ERROR_SUCCESS &&
+ syn_flash_error(r) != FLASH_ERROR_RESET) {
+ dev_err(&sd->client->dev, "flash error: %s\n",
+ syn_flash_error_str(syn_flash_error(r)));
+
+ return -EINVAL;
+ }
+
+ if (!(r & 0x80)) {
+ dev_err(&sd->client->dev, "flashing not enabled 0x%02x\n", r);
+ return -EINVAL;
+ }
+
+ return r;
+}
+
+static int syn_flash_write_block_cmd_old(struct syn *sd, const u8 *data,
+ int blocks, u8 flash_command)
+{
+ int block;
+ int r;
+ const u8 block_num_offset = syn_flash_block_num_offset(sd);
+ const u8 block_data_offset = syn_flash_block_data_offset(sd);
+
+ for (block = 0; block < blocks; block++) {
+ if (!(block % 10))
+ dev_info(&sd->client->dev, "0x%x writing block %d\n",
+ flash_command, block);
+
+ r = syn_write_u16(sd, sd->flash->data + block_num_offset,
+ block);
+ if (r < 0)
+ return r;
+
+ r = syn_write_block(sd, sd->flash->data + block_data_offset,
+ data + (block * sd->flash_caps.block_size),
+ sd->flash_caps.block_size);
+ if (r < 0)
+ return r;
+
+ r = syn_flash_command(sd, flash_command);
+ if (r < 0)
+ return r;
+
+ r = syn_flash_status(sd);
+ if (r < 0)
+ return r;
+
+ if (r != 0x80) {
+ dev_err(&sd->client->dev,
+ "flash_write error : %s\n",
+ syn_flash_error_str(syn_flash_error(r)));
+ return syn_flash_error(r);
+ }
+ }
+
+ return 0;
+}
+
+static int syn_flash_write_block_cmd_fast(struct syn *sd, const u8 *data,
+ int blocks, u8 flash_command)
+{
+ const u16 block_size = sd->flash_caps.block_size;
+ u8 *d;
+ u16 block;
+ int r;
+
+ d = kmalloc(block_size + 3, GFP_KERNEL);
+ if (d == NULL)
+ return -ENOMEM;
+
+ for (block = 0; block < blocks; block++) {
+ if (!(block % 10))
+ dev_info(&sd->client->dev,
+ "0x%x fast writing block %d\n",
+ flash_command, block);
+ d[0] = block & 0xff;
+ d[1] = (block & 0xff00) >> 8;
+ memcpy(&d[2], data + (block * block_size), block_size);
+ d[2 + block_size] = flash_command;
+
+ r = syn_wait_for_attn(sd, 200 * 1000, 1);
+ if (r) {
+ dev_err(&sd->client->dev,
+ "timeout: attn didn't clear for 200 ms\n");
+ goto out;
+ }
+
+ r = syn_write_block(sd, sd->flash->data,
+ d, block_size + 3);
+
+
+ r = syn_wait_for_attn(sd, 700 * 1000, 0);
+ if (r) {
+ dev_err(&sd->client->dev,
+ "timeout attn didn't assert for 700 ms\n");
+ goto out;
+ }
+
+ /* We need to do this read to release ATTN */
+ syn_control_data_read(sd, DEVICE_CONTROL_DATA_INTR_STATUS);
+ }
+out:
+ kfree(d);
+
+ return r;
+}
+
+static int syn_flash_write_block_cmd(struct syn *sd, const u8 *data,
+ int blocks, u8 flash_command)
+{
+ if (sd->flash_caps.properties & FLASH_PROPERTY_REGMAP_VERSION)
+ return syn_flash_write_block_cmd_fast(sd, data,
+ blocks, flash_command);
+ else
+ return syn_flash_write_block_cmd_old(sd, data,
+ blocks, flash_command);
+}
+
+static int syn_flash_read_config(struct syn *sd, u8 *d)
+{
+ const u8 flash_command = FLASH_CMD_CONF_READ_BLOCK;
+ const u8 block_num_offset = syn_flash_block_num_offset(sd);
+ const u8 block_data_offset = syn_flash_block_data_offset(sd);
+ const int blocks = sd->fw_image.config_size / sd->flash_caps.block_size;
+ int i;
+ int r;
+
+ for (i = 0; i < blocks; i++) {
+ if (!(i % 10))
+ dev_info(&sd->client->dev,
+ "0x%x reading conf block %d\n",
+ flash_command, i);
+
+ r = syn_write_u16(sd, sd->flash->data + block_num_offset, i);
+ if (r < 0)
+ return r;
+
+ r = syn_flash_command(sd, flash_command);
+ if (r < 0)
+ return r;
+
+ r = syn_flash_status(sd);
+ if (r < 0)
+ return r;
+
+ if (r != 0x80) {
+ dev_err(&sd->client->dev,
+ "flash_read error : %s\n",
+ syn_flash_error_str(syn_flash_error(r)));
+ return syn_flash_error(r);
+ }
+
+ r = syn_read_block(sd, sd->flash->data + block_data_offset, d,
+ sd->flash_caps.block_size);
+ if (r < 0)
+ return r;
+
+ d += sd->flash_caps.block_size;
+ }
+
+ return 0;
+}
+
+static int syn_flash_write_config(struct syn *sd)
+{
+ int r;
+ const int config_size = sd->fw_image.config_size;
+ const int blocks = config_size / sd->flash_caps.block_size;
+
+ r = syn_flash_write_block_cmd(sd, sd->fw_image.config_data, blocks,
+ FLASH_CMD_CONF_WRITE_BLOCK);
+ if (r < 0)
+ return r;
+
+ if (r) {
+ dev_err(&sd->client->dev,
+ "flash write fw error : %s\n",
+ syn_flash_error_str(r));
+ return -EIO;
+ }
+
+ return 0;
+}
+
+#ifdef FIRMWARE_VERIFY
+static int syn_flash_validate(struct syn *sd)
+{
+ int r;
+ const int fw_size = sd->fw_image.fw_size;
+ const int blocks = fw_size / sd->flash_caps.block_size;
+
+ if (sd->flash_caps.fw_block_count !=
+ (fw_size / sd->flash_caps.block_size) ||
+ (fw_size % sd->flash_caps.block_size)) {
+ dev_err(&sd->client->dev,
+ "fw size not aligned to block count\n");
+ return -EINVAL;
+ }
+
+ r = syn_flash_write_block_cmd(sd, sd->fw_image.fw_data, blocks,
+ FLASH_CMD_FW_CRC_BLOCK);
+ if (r < 0)
+ return r;
+
+ if (r) {
+ dev_err(&sd->client->dev,
+ "flash validate error : %s\n",
+ syn_flash_error_str(r));
+ return -EIO;
+ }
+
+ r = syn_read_u8(sd, sd->flash->data + syn_flash_block_data_offset(sd));
+ if (r < 0)
+ return r;
+
+ if (r == 0x00) {
+ dev_info(&sd->client->dev, "flash_validate: image is valid\n");
+ return 0;
+ } else if (r == 0xff)
+ dev_info(&sd->client->dev,
+ "flash_validate: image is invalid\n");
+ else
+ dev_info(&sd->client->dev,
+ "flash_validate: image status unknown: 0x%02x\n", r);
+
+ return -1;
+}
+
+static int syn_flash_compare_config(struct syn *sd)
+{
+ u32 cfg_crc_c;
+ u32 cfg_crc;
+ u32 cfg_crc_r;
+ u8 *cfg_data_r;
+ int r;
+
+ cfg_data_r = kmalloc(sd->fw_image.config_size, GFP_KERNEL);
+ if (cfg_data_r == NULL)
+ return -ENOMEM;
+
+ r = syn_flash_read_config(sd, cfg_data_r);
+ if (r < 0) {
+ kfree(cfg_data_r);
+ return r;
+ }
+
+ dev_info(&sd->client->dev, "Flash read config done\n");
+
+ cfg_crc = sd->fw_image.config_checksum;
+ cfg_crc_c = syn_crc_fletcher32((u16 *)(sd->fw_image.config_data),
+ (sd->fw_image.config_size - 4) >> 1);
+ cfg_crc_r = syn_crc_fletcher32((u16 *)(cfg_data_r),
+ (sd->fw_image.config_size - 4) >> 1);
+
+ kfree(cfg_data_r);
+ cfg_data_r = NULL;
+
+ dev_info(&sd->client->dev, "calculated fw image crc 0x%x\n", cfg_crc_c);
+ dev_info(&sd->client->dev, "read fw image crc 0x%x\n", cfg_crc);
+ dev_info(&sd->client->dev, "calculated cfg read crc 0x%x\n", cfg_crc_r);
+
+ if (cfg_crc != cfg_crc_c) {
+ dev_err(&sd->client->dev,
+ "fw crc differs from calculated\n");
+ return -EINVAL;
+ }
+
+ if (cfg_crc != cfg_crc_r) {
+ dev_err(&sd->client->dev,
+ "fw crc differs from read from device\n");
+ return -EINVAL;
+ }
+
+ if (cfg_crc_c != cfg_crc_r) {
+ dev_err(&sd->client->dev,
+ "fw calculated crc differs from read from device\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#else /* FIRMWARE_VERIFY */
+static int syn_flash_compare_config(struct syn *sd)
+{
+ return 0;
+}
+
+static int syn_flash_validate(struct syn *sd)
+{
+ return 0;
+}
+#endif
+
+static int syn_flash_erase_all(struct syn *sd)
+{
+ int r;
+
+ r = syn_write_u16(sd, sd->flash->data + syn_flash_block_data_offset(sd),
+ sd->flash_caps.bootloader_id);
+
+ r = syn_flash_command(sd, FLASH_CMD_ERASE_ALL);
+ if (r < 0)
+ return r;
+
+ r = syn_flash_status(sd);
+ if (r < 0)
+ return r;
+
+ if (r != 0x80) {
+ dev_err(&sd->client->dev,
+ "flash erase_all error : %d %s\n", syn_flash_error(r),
+ syn_flash_error_str(syn_flash_error(r)));
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int syn_flash_write_fw(struct syn *sd)
+{
+ int r;
+ const int fw_size = sd->fw_image.fw_size;
+ const int blocks = fw_size / sd->flash_caps.block_size;
+
+ r = syn_flash_write_block_cmd(sd, sd->fw_image.fw_data, blocks,
+ FLASH_CMD_FW_WRITE_BLOCK);
+ if (r < 0)
+ return r;
+
+ r = syn_flash_status(sd);
+ if (r < 0)
+ return r;
+
+ if (r != 0x80) {
+ dev_err(&sd->client->dev,
+ "flash write fw : %d %s\n", syn_flash_error(r),
+ syn_flash_error_str(syn_flash_error(r)));
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int syn_flash_firmware(struct syn *sd)
+{
+ int r;
+ int flash_status;
+
+ /* Restrict interrupts during flashing */
+ r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_INTR_ENABLE,
+ INTR_FLASH | INTR_STATUS);
+
+ r = syn_flash_enable(sd);
+ if (r < 0)
+ goto flash_out;
+
+ r = syn_flash_validate(sd);
+ if (r < 0)
+ goto flash_out;
+
+ r = syn_flash_erase_all(sd);
+ if (r < 0)
+ goto flash_out;
+
+ r = syn_flash_write_fw(sd);
+ if (r < 0)
+ goto flash_out;
+
+ r = syn_flash_write_config(sd);
+ if (r < 0)
+ goto flash_out;
+
+ r = syn_flash_compare_config(sd);
+ if (r < 0)
+ goto flash_out;
+
+flash_out:
+ flash_status = syn_flash_status(sd);
+ dev_info(&sd->client->dev,
+ "flash status: %x %s\n", flash_status,
+ syn_flash_error_str(syn_flash_error(flash_status)));
+
+ /*
+ * We reset and interrupt handler should notice that
+ * everything has changed and reread the page descriptor table.
+ */
+ syn_reset_device(sd);
+
+ return syn_flash_error(flash_status) == FLASH_ERROR_SUCCESS ? 0 : -1;
+}
+
+static ssize_t syn_show_attr_flash(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ const ssize_t size = PAGE_SIZE;
+ ssize_t l = 0;
+ int r;
+
+ if (!sd->flash) {
+ l += snprintf(buf + l, size - l, "N/A\n");
+ return l;
+ }
+
+ mutex_lock(&sd->lock);
+
+ r = syn_control_data_read(sd, DEVICE_CONTROL_DATA_STATUS);
+
+ mutex_unlock(&sd->lock);
+
+ if (r < 0)
+ dev_err(&sd->client->dev, "read error %d\n", r);
+ else
+ l += snprintf(buf + l, size - l, "%d\n",
+ (r & (1 << 6)) ? 1 : 0);
+
+ return l;
+}
+
+static ssize_t syn_store_attr_flash(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ const struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ int r;
+ char name[FW_MAX_NAME_SIZE + 1];
+
+ if (count > FW_MAX_NAME_SIZE || count == 0) {
+ dev_err(&sd->client->dev, "firmware name check failure\n");
+ return 0;
+ }
+
+ memcpy(name, buf, count);
+ name[count] = 0;
+
+ mutex_lock(&sd->lock);
+
+ if (name[count - 1] == '\n')
+ name[count - 1] = 0;
+
+ if (sd->fw_entry) {
+ dev_err(&sd->client->dev, "firmware already in memory\n");
+ goto firmware_out;
+ }
+
+ r = syn_request_firmware(sd, name);
+ if (r < 0) {
+ dev_err(&sd->client->dev, "firmware not found\n");
+ goto store_out;
+ }
+
+ memset(&sd->fw_image, 0, sizeof(struct fw_image));
+
+ r = syn_check_firmware(sd);
+ if (r != 0) {
+ dev_err(&sd->client->dev,
+ "consistency check of firmware failed\n");
+ goto firmware_out;
+ }
+
+ dev_info(&sd->client->dev, "firmware consistency check ok\n");
+
+ r = syn_flash_firmware(sd);
+ if (r != 0) {
+ dev_err(&sd->client->dev,
+ "flashing of firmware failed\n");
+ goto firmware_out;
+ }
+
+ dev_info(&sd->client->dev, "flashing done with success\n");
+
+firmware_out:
+ memset(&sd->fw_image, 0, sizeof(struct fw_image));
+ release_firmware(sd->fw_entry);
+ sd->fw_entry = NULL;
+
+store_out:
+ mutex_unlock(&sd->lock);
+
+ return count;
+}
+
+static ssize_t syn_show_attr_product_id(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ const ssize_t size = PAGE_SIZE;
+ u8 product_id[PRODUCT_ID_LEN + 1];
+ ssize_t l = 0;
+ int r;
+
+ if (!sd->flash) {
+ l += snprintf(buf + l, size - l, "N/A\n");
+ return l;
+ }
+
+ mutex_lock(&sd->lock);
+
+ r = syn_read_block(sd, sd->control->query +
+ DEVICE_CONTROL_QUERY_PROD_ID,
+ product_id, PRODUCT_ID_LEN);
+
+ mutex_unlock(&sd->lock);
+
+ product_id[PRODUCT_ID_LEN] = 0;
+
+ if (r < 0)
+ dev_warn(&sd->client->dev,
+ "error %d reading product id\n", r);
+ else
+ l += snprintf(buf + l, size - l, "%s\n",
+ product_id);
+
+ return l;
+}
+
+static ssize_t syn_show_attr_product_family(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ const ssize_t size = PAGE_SIZE;
+ ssize_t l = 0;
+ int r;
+
+ if (!sd->flash) {
+ l += snprintf(buf + l, size - l, "N/A\n");
+ return l;
+ }
+
+ mutex_lock(&sd->lock);
+
+ r = syn_control_query_read(sd,
+ DEVICE_CONTROL_QUERY_PROD_FAMILY);
+
+ mutex_unlock(&sd->lock);
+
+ if (r < 0)
+ dev_warn(&sd->client->dev,
+ "error %d reading product family\n", r);
+ else
+ l += snprintf(buf + l, size - l, "%d\n",
+ r);
+
+ return l;
+}
+
+static ssize_t syn_show_attr_firmware_version(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ const ssize_t size = PAGE_SIZE;
+ ssize_t l = 0;
+ int r;
+
+ if (!sd->flash) {
+ l += snprintf(buf + l, size - l, "N/A\n");
+ return l;
+ }
+
+ mutex_lock(&sd->lock);
+
+ r = syn_control_query_read(sd,
+ DEVICE_CONTROL_QUERY_FW_VER);
+
+ mutex_unlock(&sd->lock);
+
+ if (r < 0)
+ dev_warn(&sd->client->dev,
+ "error %d reading fw version\n", r);
+ else
+ l += snprintf(buf + l, size - l, "%d\n",
+ r);
+
+ return l;
+}
+
+/*
+ * BIST (selftest) support
+ */
+
+static int syn_bist_run_test(struct syn *sd, struct bist_test_result *tr,
+ u8 test)
+{
+ int r;
+ u8 intr_mask = INTR_ALL;
+
+ if (!sd || !tr || !sd->bist)
+ return -EINVAL;
+
+ mutex_lock(&sd->lock);
+
+ r = syn_read_u8(sd, sd->control->control +
+ DEVICE_CONTROL_INTR_ENABLE);
+ if (r < 0)
+ goto out;
+
+ intr_mask = r & 0xFF;
+
+ /* Restrict interrupt sources*/
+ r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_INTR_ENABLE,
+ INTR_BIST | INTR_STATUS);
+
+ r = syn_write_u8(sd, sd->bist->data + BIST_DATA_TEST_NUMBER_CTRL,
+ test);
+ if (r < 0)
+ goto out;
+
+ r = syn_write_u8(sd, sd->bist->command + BIST_CONTROL_COMMAND,
+ 0x01);
+ if (r < 0)
+ goto out;
+
+ r = syn_wait_for_attn(sd, 5 * 1000 * 1000, 0);
+ if (r < 0) {
+ dev_err(&sd->client->dev, "timeout running bist test\n");
+ goto out;
+ }
+
+ r = syn_control_data_read(sd, DEVICE_CONTROL_DATA_INTR_STATUS);
+ if (r < 0)
+ dev_err(&sd->client->dev, "error reading int status\n");
+
+ r = syn_read_u8(sd, sd->bist->command + BIST_CONTROL_COMMAND);
+ if (r < 0)
+ goto out;
+
+ if (r & (1 << 0)) {
+ r = -EBUSY;
+ goto out;
+ }
+
+ r = syn_read_u8(sd, sd->bist->data + BIST_DATA_OVERALL_RESULT);
+ if (r < 0)
+ goto out;
+
+ tr->failed = r;
+
+ r = syn_read_u8(sd, sd->bist->data + BIST_DATA_TEST_RESULT);
+ if (r < 0)
+ goto out;
+
+ tr->result = r;
+
+out:
+ r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_INTR_ENABLE,
+ intr_mask);
+ mutex_unlock(&sd->lock);
+
+ return r;
+}
+
+static int syn_test_i2c_wr(struct syn *sd, const u8 value)
+{
+ int r;
+
+ r = syn_write_u8(sd, sd->bist->data + BIST_DATA_TEST_NUMBER_CTRL,
+ value);
+ if (r < 0)
+ goto out;
+
+ r = syn_read_u8(sd, sd->bist->data + BIST_DATA_TEST_NUMBER_CTRL);
+ if (r < 0)
+ goto out;
+
+ if (r != value) {
+ dev_err(&sd->client->dev,
+ "write verify error: wrote 0x%x got 0x%x\n",
+ value, r);
+ r = -EINVAL;
+ goto out;
+ }
+
+ r = 0;
+out:
+
+ return r;
+}
+
+static int syn_test_i2c(struct syn *sd)
+{
+ int r;
+ int i;
+
+ mutex_lock(&sd->lock);
+
+ for (i = 0; i < 8; i++) {
+ r = syn_test_i2c_wr(sd, 1 << i);
+ if (r < 0)
+ goto out;
+ }
+
+ for (i = 0; i < 256; i++) {
+ r = syn_test_i2c_wr(sd, i);
+ if (r < 0)
+ goto out;
+ }
+
+out:
+ mutex_unlock(&sd->lock);
+
+ return r;
+}
+
+static int syn_bist_selftest(struct syn *sd, struct bist_test_result *tr)
+{
+ int r;
+
+ r = syn_test_i2c(sd);
+ if (r != 0)
+ return r;
+
+ r = syn_bist_run_test(sd, tr, 0x00);
+
+ return r;
+}
+
+static ssize_t syn_show_attr_selftest(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ const ssize_t size = PAGE_SIZE;
+ ssize_t l = 0;
+ struct bist_test_result tr = { 0, };
+ int r;
+
+ if (!sd->bist) {
+ l += snprintf(buf + l, size - l, "Not available\n");
+ return l;
+ }
+
+ r = syn_bist_selftest(sd, &tr);
+ if (r != 0)
+ l += snprintf(buf + l, size - l,
+ "FAIL (io error %d)\n", r);
+ else {
+ if (tr.failed == 0)
+ l += snprintf(buf + l, size - l,
+ "PASS\n");
+ else
+ l += snprintf(buf + l, size - l,
+ "FAIL (test %d, result %d)\n",
+ tr.failed, tr.result);
+ }
+
+ return l;
+}
+
+static ssize_t syn_store_attr_reset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+
+ mutex_lock(&sd->lock);
+
+ syn_reset_device(sd);
+
+ mutex_unlock(&sd->lock);
+
+ return count;
+}
+
+static ssize_t syn_show_attr_doze(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ const ssize_t size = PAGE_SIZE;
+ ssize_t l = 0;
+ int r;
+
+ mutex_lock(&sd->lock);
+ r = syn_get_nosleep(sd);
+ mutex_unlock(&sd->lock);
+
+ if (r < 0)
+ goto out;
+
+ l += snprintf(buf + l, size - l, "%d\n", !r);
+out:
+ return l;
+}
+
+static ssize_t syn_store_attr_doze(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ int val;
+
+ if (sscanf(buf, "%i", &val) != 1) {
+ dev_info(&sd->client->dev,
+ "error parsing debug\n");
+ return count;
+ }
+
+ if (val & (~0x01))
+ return count;
+
+ mutex_lock(&sd->lock);
+ syn_set_nosleep(sd, !val);
+ mutex_unlock(&sd->lock);
+
+ return count;
+}
+
+static ssize_t syn_show_attr_sleepmode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ const ssize_t size = PAGE_SIZE;
+ ssize_t l = 0;
+ int r;
+
+ mutex_lock(&sd->lock);
+
+ r = syn_read_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL);
+ if (r < 0)
+ goto out;
+
+ l += snprintf(buf + l, size - l, "%d\n", (r & 0x03));
+out:
+ mutex_unlock(&sd->lock);
+ return l;
+}
+
+static ssize_t syn_store_attr_sleepmode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ int val;
+ int r;
+
+ if (sscanf(buf, "%i", &val) != 1) {
+ dev_info(&sd->client->dev,
+ "error parsing debug\n");
+ return count;
+ }
+
+ if (val & (~0x03))
+ return count;
+
+ mutex_lock(&sd->lock);
+
+ r = syn_read_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL);
+ if (r < 0)
+ goto out;
+
+ val = (r & (~0x03)) | (val & 0x03);
+
+ r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL,
+ val);
+
+out:
+ mutex_unlock(&sd->lock);
+
+ return count;
+}
+
+static ssize_t syn_show_attr_proximity(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ const ssize_t size = PAGE_SIZE;
+ ssize_t l = 0;
+ int r;
+
+ mutex_lock(&sd->lock);
+ r = syn_get_proximity_state(sd);
+ mutex_unlock(&sd->lock);
+
+ if (r < 0)
+ r = 0;
+
+ l += snprintf(buf + l, size - l, "%d\n", r);
+
+ return l;
+}
+
+static ssize_t syn_store_attr_proximity(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ int val;
+
+ if (sscanf(buf, "%i", &val) != 1) {
+ dev_info(&sd->client->dev,
+ "error parsing debug\n");
+ return count;
+ }
+
+ if (val & (~0x01))
+ return count;
+
+ mutex_lock(&sd->lock);
+ syn_set_proximity_state(sd, !!val);
+ mutex_unlock(&sd->lock);
+
+ return count;
+}
+
+static ssize_t syn_show_attr_sensitivity(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ const ssize_t size = PAGE_SIZE;
+ ssize_t l = 0;
+ int i;
+ u8 addr;
+ int r;
+
+ if (!sd->touch) {
+ l += snprintf(buf + l, size - l, "Not available\n");
+ return l;
+ }
+
+ addr = sd->touch->control + TOUCH_CONTROL_SENSOR_MAPPING +
+ sd->touch_caps.max_electrodes;
+
+ if (sd->touch_caps.has_gestures)
+ addr += 2;
+
+ mutex_lock(&sd->lock);
+
+ for (i = 0; i < sd->touch_caps.max_electrodes; i++) {
+ r = syn_read_u8(sd, addr + i);
+ if (r < 0) {
+ l += snprintf(buf + l, size - l, "Read error %d\n", r);
+ goto out;
+ } else
+ l += snprintf(buf + l, size - l, "0x%x ", r);
+ }
+
+ l += snprintf(buf + l, size - l, "\n");
+
+out:
+ mutex_unlock(&sd->lock);
+
+ return l;
+}
+
+static ssize_t syn_store_attr_sensitivity(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ int r;
+ int addr;
+ int base;
+ int value;
+
+ if (!sd->touch)
+ return count;
+
+ if (sscanf(buf, "%d %i", &addr, &value) != 2) {
+ dev_info(&sd->client->dev,
+ "error parsing sensitivity info <addr> <value>\n");
+ return count;
+ }
+
+ if (addr >= sd->touch_caps.max_electrodes) {
+ dev_info(&sd->client->dev,
+ "electorode number out of bounds %d > %d\n", addr,
+ sd->touch_caps.max_electrodes);
+ return count;
+ }
+
+ base = sd->touch->control + TOUCH_CONTROL_SENSOR_MAPPING +
+ sd->touch_caps.max_electrodes;
+
+ if (sd->touch_caps.has_gestures)
+ base += 2;
+
+ mutex_lock(&sd->lock);
+
+ r = syn_write_u8(sd, base + addr, value);
+ if (r < 0) {
+ dev_err(&sd->client->dev, "write failed with %d\n", r);
+ goto out;
+ }
+
+ r = syn_read_u8(sd, base + addr);
+ if (r < 0) {
+ dev_err(&sd->client->dev, "read failed with %d\n", r);
+ goto out;
+ }
+
+ if (r != value) {
+ dev_warn(&sd->client->dev,
+ "value verify error 0x%x != 0x%x\n", r, value);
+ }
+out:
+ mutex_unlock(&sd->lock);
+
+ return count;
+}
+
+static ssize_t syn_show_attr_sensormap(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ const ssize_t size = PAGE_SIZE;
+ ssize_t l = 0;
+ int i;
+ u8 addr;
+ int r;
+
+ if (!sd->touch) {
+ l += snprintf(buf + l, size - l, "Not available\n");
+ return l;
+ }
+
+ addr = sd->touch->control + TOUCH_CONTROL_SENSOR_MAPPING;
+
+ if (sd->touch_caps.has_gestures)
+ addr += 2;
+
+ mutex_lock(&sd->lock);
+
+ for (i = 0; i < sd->touch_caps.max_electrodes; i++) {
+ r = syn_read_u8(sd, addr + i);
+ if (r < 0) {
+ l += snprintf(buf + l, size - l, "Read error %d\n", r);
+ goto out;
+ } else
+ l += snprintf(buf + l, size - l, "%s: %d\n",
+ r & 0x80 ? "Y" : "X", r & 0x1F);
+ }
+
+ l += snprintf(buf + l, size - l, "\n");
+
+out:
+ mutex_unlock(&sd->lock);
+
+ return l;
+}
+
+static ssize_t syn_show_attr_reg_dump(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ const ssize_t size = PAGE_SIZE;
+ ssize_t l = 0;
+ int i;
+ int r;
+
+ if (!sd->touch) {
+ l += snprintf(buf + l, size - l, "Not available\n");
+ return l;
+ }
+
+ mutex_lock(&sd->lock);
+
+ for (i = 0; i < 0xff; i++) {
+ r = syn_read_u8(sd, i);
+ if (r < 0) {
+ l += snprintf(buf + l, size - l,
+ "Read error at 0x%x %d\n", i, r);
+ goto out;
+ } else
+ l += snprintf(buf + l, size - l,
+ "0x%02x: 0x%02x (%d)\n", i, r, r);
+ }
+
+ l += snprintf(buf + l, size - l, "\n");
+
+out:
+ mutex_unlock(&sd->lock);
+ return l;
+}
+
+static ssize_t syn_store_attr_reg_dump(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ int addr;
+ int value;
+
+ if (!sd->touch)
+ return count;
+
+ if (sscanf(buf, "%i", &addr) != 1) {
+ dev_info(&sd->client->dev,
+ "error parsing addr\n");
+ return count;
+ }
+
+ if (addr < 0 || addr > 0xff) {
+ dev_info(&sd->client->dev,
+ "error 0x%x out of bounds\n", addr);
+ return count;
+ }
+
+ mutex_lock(&sd->lock);
+
+ value = syn_read_u8(sd, addr);
+ if (value < 0) {
+ dev_info(&sd->client->dev,
+ "error %d reading from 0x%x\n", value, addr);
+ goto out;
+ }
+
+ dev_info(&sd->client->dev, "0x%x: 0x%x\n", addr, value);
+
+out:
+ mutex_unlock(&sd->lock);
+
+ return count;
+}
+
+static ssize_t syn_show_attr_debug(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ const ssize_t size = PAGE_SIZE;
+ ssize_t l = 0;
+
+ mutex_lock(&sd->lock);
+
+ l += snprintf(buf + l, size - l, "0x%02x\n", sd->debug_flag);
+
+ mutex_unlock(&sd->lock);
+
+ return l;
+}
+
+static ssize_t syn_store_attr_debug(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ int flag = 0;
+
+ if (sscanf(buf, "%i", &flag) != 1) {
+ dev_info(&sd->client->dev,
+ "error parsing debug\n");
+ return count;
+ }
+
+ mutex_lock(&sd->lock);
+
+ sd->debug_flag = flag;
+
+ mutex_unlock(&sd->lock);
+
+ return count;
+}
+
+static ssize_t syn_store_attr_latency(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+
+ mutex_lock(&sd->lock);
+
+ sd->t_work_min = ULONG_MAX;
+ sd->t_work_max = 0;
+ sd->t_work = 0;
+ sd->t_work_c = 0;
+
+ sd->t_wakeup_min = ULONG_MAX;
+ sd->t_wakeup_max = 0;
+ sd->t_wakeup = 0;
+ sd->t_wakeup_c = 0;
+
+ sd->t_count = 0;
+
+ mutex_unlock(&sd->lock);
+
+ return count;
+}
+
+static ssize_t syn_show_attr_latency(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ const ssize_t size = PAGE_SIZE;
+ ssize_t l = 0;
+
+ mutex_lock(&sd->lock);
+
+ l += snprintf(buf + l, size - l,
+ "count %lu: wakeup %lu (%lu, %lu, %lu), "
+ "work %lu (%lu, %lu, %lu)\n",
+ sd->t_count,
+ sd->t_wakeup, sd->t_wakeup_min, sd->t_wakeup_max,
+ sd->t_count ? (sd->t_wakeup_c / sd->t_count) : 0,
+ sd->t_work, sd->t_work_min, sd->t_work_max,
+ sd->t_count ? (sd->t_work_c / sd->t_count) : 0);
+
+ mutex_unlock(&sd->lock);
+
+ return l;
+}
+
+static ssize_t syn_show_attr_virtualized(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ const ssize_t size = PAGE_SIZE;
+ ssize_t l = 0;
+
+ mutex_lock(&sd->lock);
+
+ l += snprintf(buf + l, size - l, "%d\n", sd->virtualized);
+
+ mutex_unlock(&sd->lock);
+
+ return l;
+}
+
+static ssize_t syn_store_attr_virtualized(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct syn *sd = platform_get_drvdata(pdev);
+ int val;
+
+ if (sscanf(buf, "%i", &val) != 1) {
+ dev_info(&sd->client->dev,
+ "error parsing virtualized\n");
+ return count;
+ }
+
+ if (val & (~0x01))
+ return count;
+
+ mutex_lock(&sd->lock);
+ sd->virtualized = val;
+ mutex_unlock(&sd->lock);
+
+ return count;
+}
+
+
+
+static DEVICE_ATTR(flash, S_IWUSR | S_IRUGO,
+ syn_show_attr_flash, syn_store_attr_flash);
+
+static DEVICE_ATTR(product_id, S_IRUGO,
+ syn_show_attr_product_id, NULL);
+
+static DEVICE_ATTR(product_family, S_IRUGO,
+ syn_show_attr_product_family, NULL);
+
+static DEVICE_ATTR(firmware_version, S_IRUGO,
+ syn_show_attr_firmware_version, NULL);
+
+static DEVICE_ATTR(selftest, S_IRUGO,
+ syn_show_attr_selftest, NULL);
+
+static DEVICE_ATTR(reset, S_IWUSR, NULL, syn_store_attr_reset);
+
+static DEVICE_ATTR(doze, S_IRUGO | S_IWUSR,
+ syn_show_attr_doze, syn_store_attr_doze);
+
+static DEVICE_ATTR(sleepmode, S_IRUGO | S_IWUSR,
+ syn_show_attr_sleepmode, syn_store_attr_sleepmode);
+
+static DEVICE_ATTR(proximity, S_IRUGO | S_IWUSR,
+ syn_show_attr_proximity, syn_store_attr_proximity);
+
+static DEVICE_ATTR(sensitivity, S_IRUGO | S_IWUSR,
+ syn_show_attr_sensitivity, syn_store_attr_sensitivity);
+
+static DEVICE_ATTR(sensormap, S_IRUGO,
+ syn_show_attr_sensormap, NULL);
+
+static DEVICE_ATTR(dump, S_IRUGO | S_IWUSR,
+ syn_show_attr_reg_dump, syn_store_attr_reg_dump);
+
+static DEVICE_ATTR(debug, S_IRUGO | S_IWUSR,
+ syn_show_attr_debug, syn_store_attr_debug);
+
+static DEVICE_ATTR(latency, S_IRUGO | S_IWUSR,
+ syn_show_attr_latency, syn_store_attr_latency);
+
+static DEVICE_ATTR(virtualized, S_IRUGO | S_IWUSR,
+ syn_show_attr_virtualized, syn_store_attr_virtualized);
+
+static struct attribute *syn_attrs[] = {
+ &dev_attr_flash.attr,
+ &dev_attr_product_id.attr,
+ &dev_attr_product_family.attr,
+ &dev_attr_firmware_version.attr,
+ &dev_attr_selftest.attr,
+ &dev_attr_reset.attr,
+ &dev_attr_doze.attr,
+ &dev_attr_sleepmode.attr,
+ &dev_attr_proximity.attr,
+ &dev_attr_sensitivity.attr,
+ &dev_attr_sensormap.attr,
+ &dev_attr_dump.attr,
+ &dev_attr_debug.attr,
+ &dev_attr_latency.attr,
+ &dev_attr_virtualized.attr,
+ NULL,
+};
+
+static struct attribute_group syn_attr_group = {
+ .attrs = syn_attrs,
+};
+
+static void syn_create_sysfs(struct syn *sd)
+{
+ int r;
+
+ r = sysfs_create_group(&sd->client->dev.kobj, &syn_attr_group);
+ if (r) {
+ dev_err(&sd->client->dev,
+ "failed to create flash sysfs files\n");
+ }
+}
+
+static void syn_remove_sysfs(struct syn *sd)
+{
+ sysfs_remove_group(&sd->client->dev.kobj, &syn_attr_group);
+}
+
+static int syn_read_func_descs(struct syn *sd)
+{
+ int properties;
+ int fun;
+ int r;
+ int addr = REG_PDT_PROPERTIES;
+
+ sd->func_descs_valid = 0;
+ sd->interrupt_sources = 0;
+
+ properties = syn_read_u8(sd, addr--);
+ if (properties < 0)
+ return properties;
+
+ /* We don't support non standard page select register addr */
+ if (properties != 0x00) {
+ dev_err(&sd->client->dev, "unsupported pdt\n");
+ return -ENODEV;
+ }
+
+ sd->func_desc_num = 0;
+
+ while (sd->func_desc_num < MAX_FUNC_DESCS) {
+ struct func_desc * const f = &sd->func_desc[sd->func_desc_num];
+ u8 regs[5];
+
+ fun = syn_read_u8(sd, addr);
+ if (fun < 0)
+ return fun;
+
+ if (fun == 0x00)
+ goto out;
+
+ if (sd->debug_flag & DFLAG_VERBOSE)
+ dev_info(&sd->client->dev,
+ "found function 0x%x\n", fun);
+
+ f->num = fun;
+ addr -= 5;
+ r = syn_read_block(sd, addr, regs, 5);
+ if (r != 5) {
+ dev_err(&sd->client->dev, "error reading pdt\n");
+ return -ENODEV;
+ }
+
+ f->query = regs[0];
+ f->command = regs[1];
+ f->control = regs[2];
+ f->data = regs[3];
+ f->intr_sources = regs[4] & 0x07;
+ f->version = (regs[4] >> 5) & 0x3;
+
+ if (f->intr_sources) {
+ f->intr_start_bit = sd->interrupt_sources;
+ sd->interrupt_sources += f->intr_sources;
+ }
+
+ sd->func_desc_num++;
+ addr--;
+ }
+
+out:
+ /* Put shortcuts in place */
+ sd->control = syn_get_func_desc(sd, FUNC_DEVICE_CONTROL);
+ sd->flash = syn_get_func_desc(sd, FUNC_FLASH);
+ sd->touch = syn_get_func_desc(sd, FUNC_2D);
+ sd->buttons = syn_get_func_desc(sd, FUNC_BUTTONS);
+ sd->bist = syn_get_func_desc(sd, FUNC_BIST);
+ sd->prox = syn_get_func_desc(sd, FUNC_PROXIMITY);
+
+ if (sd->touch == NULL)
+ dev_warn(&sd->client->dev,
+ "no 2d functionality found! (in flash mode ?)\n");
+
+ if (sd->flash) {
+ r = syn_flash_query_caps(sd);
+ if (r)
+ return r;
+ } else
+ dev_warn(&sd->client->dev, "no flash functionality found!\n");
+
+ if (sd->control) {
+ sd->func_descs_valid = 1;
+ return 0;
+ }
+
+ return -1;
+}
+
+static int syn_register_handlers(struct syn *sd)
+{
+ int r;
+
+ r = syn_register_intr_handler(sd, FUNC_DEVICE_CONTROL,
+ syn_isr_device_control);
+ if (r < 0) {
+ dev_err(&sd->client->dev,
+ "no device control, cant continue\n");
+ return r;
+ }
+
+ /*
+ * Don't care about return values here.
+ * Install interrupt handlers for every function
+ * (even if they dont exist)
+ */
+
+ syn_register_intr_handler(sd, FUNC_BIST, syn_isr_bist);
+ syn_register_intr_handler(sd, FUNC_BUTTONS, syn_isr_buttons);
+ syn_register_intr_handler(sd, FUNC_TIMER, syn_isr_timer);
+ syn_register_intr_handler(sd, FUNC_2D, syn_isr_2d);
+ syn_register_intr_handler(sd, FUNC_FLASH, syn_isr_flash);
+ syn_register_intr_handler(sd, FUNC_PROXIMITY, syn_isr_proximity);
+
+ return 0;
+}
+
+static int syn_touch_get_max_pos(struct syn *sd, u8 reg)
+{
+ int data;
+
+ data = syn_read_u16(sd, sd->touch->control + reg);
+ if (data < 0)
+ return data;
+
+ return data & 0x00000fff;
+}
+
+static int syn_touch_get_max_x_pos(struct syn *sd)
+{
+ return syn_touch_get_max_pos(sd, TOUCH_CONTROL_SENSOR_MAX_X);
+}
+
+static int syn_touch_get_max_y_pos(struct syn *sd)
+{
+ return syn_touch_get_max_pos(sd, TOUCH_CONTROL_SENSOR_MAX_Y);
+}
+
+static int syn_button_query_caps(struct syn *sd)
+{
+ int r;
+
+ r = syn_read_u8(sd, sd->buttons->query + BUTTON_QUERY_BUTTON_COUNT);
+ if (r < 0)
+ return r;
+
+ if (r > MAX_BUTTONS)
+ return -EINVAL;
+
+ sd->button_caps.button_count = r & BUTTON_QUERY_BUTTON_MASK;
+
+ return 0;
+}
+
+static int syn_touch_query_caps(struct syn *sd)
+{
+ int r;
+ u8 data[TOUCH_QUERY_LEN];
+
+ if (sd->touch == NULL)
+ return -ENODEV;
+
+ r = syn_read_block(sd, sd->touch->query + TOUCH_QUERY_NUM_SENSORS,
+ data, TOUCH_QUERY_LEN);
+ if (r < 0)
+ return r;
+
+ if (data[0] != 0) {
+ dev_err(&sd->client->dev, "no support for multiple sensors\n");
+ return -ENODEV;
+ }
+
+ sd->touch_caps.is_configurable = (data[1] & (1 << 7)) ? 1 : 0;
+ sd->touch_caps.has_gestures = (data[1] & (1 << 5)) ? 1 : 0;
+ sd->touch_caps.has_abs_mode = (data[1] & (1 << 4)) ? 1 : 0;
+ sd->touch_caps.has_rel_mode = (data[1] & (1 << 3)) ? 1 : 0;
+ sd->touch_caps.finger_count = (data[1] & 0x07) + 1;
+ sd->touch_caps.x_electrodes = (data[2] & 0x1f);
+ sd->touch_caps.y_electrodes = (data[3] & 0x1f);
+ sd->touch_caps.max_electrodes = (data[4] & 0x1f);
+ sd->touch_caps.abs_data_size = (data[5] & 0x03);
+
+ if (sd->touch_caps.finger_count > MAX_TOUCH_POINTS ||
+ sd->touch_caps.has_rel_mode ||
+ /* sd->touch_caps.has_gestures || */
+ sd->touch_caps.abs_data_size) {
+ dev_err(&sd->client->dev, "no support for this sensor\n");
+ return -ENODEV;
+ }
+
+ r = syn_touch_get_max_x_pos(sd);
+ if (r < 0)
+ return r;
+
+ sd->touch_caps.max_x = r;
+
+ r = syn_touch_get_max_y_pos(sd);
+ if (r < 0)
+ return r;
+
+ sd->touch_caps.max_y = r;
+
+ return 0;
+}
+
+static int syn_reset_device(struct syn *sd)
+{
+ int r;
+
+ /*
+ * We get called from various contexts, for example after firmware
+ * change. Resetting with state registermap would be disastrous
+ * so we reread everything in order to be sure to write
+ * to correct register.
+ */
+ r = syn_read_func_descs(sd);
+
+ if (!sd->control) {
+ dev_err(&sd->client->dev, "no control. can't reset!\n");
+ return -1;
+ }
+
+ dev_info(&sd->client->dev, "resetting device (reg 0x%x)\n",
+ sd->control->command + DEVICE_CONTROL_COMMAND);
+
+ r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_INTR_ENABLE,
+ 0);
+
+ r = syn_control_data_read(sd, DEVICE_CONTROL_DATA_INTR_STATUS);
+
+ sd->func_descs_valid = 0;
+
+ r = syn_write_u8(sd, sd->control->command +
+ DEVICE_CONTROL_COMMAND, DEVICE_COMMAND_RESET);
+
+ r = syn_wait_for_attn(sd, 100 * 1000, 0);
+ r = syn_wait_for_attn(sd, 100 * 1000, 1);
+ r = syn_wait_for_attn(sd, 500 * 1000, 0);
+
+ return 0;
+}
+
+static int syn_initialize(struct syn *sd)
+{
+ int r;
+ char prod_id[PRODUCT_ID_LEN + 1];
+ int prod_family;
+ int prod_fw_version;
+
+ syn_clear_device_state(sd);
+
+ r = syn_read_u8(sd, REG_PAGE_SELECT);
+ if (r < 0) {
+ dev_err(&sd->client->dev, "error reading page select\n");
+ goto err_out;
+ }
+
+ if (r != 0x00) {
+ dev_err(&sd->client->dev, "page select non zero\n");
+ r = -ENODEV;
+ goto err_out;
+ }
+
+ r = syn_read_func_descs(sd);
+ if (r < 0) {
+ dev_err(&sd->client->dev, "error reading func descs\n");
+ goto err_out;
+ }
+
+ if (!sd->control) {
+ dev_err(&sd->client->dev, "no control functions found\n");
+ r = -ENODEV;
+ goto err_out;
+ }
+
+ /* Clear the Unconfigured bit */
+ r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL,
+ DEVICE_CONTROL_CONFIGURED);
+
+ if (!sd->bist)
+ dev_warn(&sd->client->dev, "no bist capabilities found\n");
+
+ if (sd->touch) {
+ r = syn_touch_query_caps(sd);
+ if (r < 0) {
+ dev_err(&sd->client->dev,
+ "error reading touch capabilities\n");
+ sd->touch = NULL;
+ }
+ } else {
+ dev_err(&sd->client->dev, "no touch capabilities found\n");
+ }
+
+ if (sd->buttons) {
+ r = syn_button_query_caps(sd);
+ if (r < 0) {
+ dev_err(&sd->client->dev,
+ "error reading button capabilities\n");
+ sd->buttons = NULL;
+ }
+ } else {
+ dev_err(&sd->client->dev, "no button capabilities found\n");
+ }
+
+ r = syn_read_block(sd, sd->control->query +
+ DEVICE_CONTROL_QUERY_PROD_ID,
+ prod_id, PRODUCT_ID_LEN);
+
+ if (r != PRODUCT_ID_LEN) {
+ dev_err(&sd->client->dev, "unable to read product id\n");
+ r = -ENODEV;
+ goto err_out;
+ }
+ prod_id[r] = 0;
+
+ prod_family = syn_control_query_read(sd,
+ DEVICE_CONTROL_QUERY_PROD_FAMILY);
+ if (prod_family < 0) {
+ dev_err(&sd->client->dev, "unable to read product family\n");
+ goto err_out;
+ }
+
+ prod_fw_version = syn_control_query_read(sd,
+ DEVICE_CONTROL_QUERY_FW_VER);
+ if (prod_fw_version < 0) {
+ dev_err(&sd->client->dev, "unable to read product family\n");
+ goto err_out;
+ }
+
+ printk(KERN_INFO DRIVER_NAME ": product ID: %s family:%d fw:%d\n",
+ prod_id, prod_family, prod_fw_version);
+
+ r = syn_register_handlers(sd);
+ if (r) {
+ dev_err(&sd->client->dev, "failed to register_handlers\n");
+ r = -ENODEV;
+ goto err_out;
+ }
+
+ if (sd->touch) {
+ r = syn_register_input_devices(sd, sd->touch_caps.finger_count);
+ if (r) {
+ dev_err(&sd->client->dev,
+ "failed to register input devices\n");
+ r = -ENODEV;
+ goto err_out;
+ }
+ }
+
+ if (sd->prox) {
+ /* By default disable it */
+ syn_set_proximity_state(sd, 0);
+ }
+
+ r = syn_control_data_read(sd, DEVICE_CONTROL_DATA_STATUS);
+ if (r < 0) {
+ dev_err(&sd->client->dev, "error %d reading device status\n",
+ r);
+ }
+
+ /*
+ * If we get reset during initialization, unconfigured should be on
+ */
+ if (r & (1 << 7)) {
+ dev_warn(&sd->client->dev, "lost config during initialize\n");
+ sd->failed_inits++;
+ syn_reset_device(sd);
+ goto err_out;
+ }
+
+ sd->failed_inits = 0;
+ return 0;
+
+err_out:
+ return r;
+}
+
+static int syn_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct syn *sd;
+ struct tm12xx_ts_platform_data *pdata;
+ int r;
+ int man_id;
+
+ sd = kzalloc(sizeof(struct syn), GFP_KERNEL);
+ if (sd == NULL)
+ return -ENOMEM;
+
+ INIT_WORK(&sd->isr_work, syn_isr_work);
+ i2c_set_clientdata(client, sd);
+ sd->client = client;
+
+ mutex_init(&sd->lock);
+
+ sd->t_work_min = ULONG_MAX;
+ sd->t_wakeup_min = ULONG_MAX;
+
+ sd->wq = create_singlethread_workqueue("tm12xx_wq");
+ if (!sd->wq) {
+ r = -ENOMEM;
+ goto err_free_dev;
+ }
+
+ pdata = sd->client->dev.platform_data;
+ if (!pdata) {
+ dev_err(&client->dev, "no platform data found\n");
+ r = -ENODEV;
+ goto err_free_dev;
+ }
+
+ sd->gpio_intr = pdata->gpio_intr;
+
+ r = syn_read_func_descs(sd);
+ if (r < 0) {
+ dev_err(&client->dev, "error reading func descs\n");
+ goto err_free_dev;
+ }
+
+ r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_INTR_ENABLE,
+ 0);
+ if (r < 0)
+ goto err_free_dev;
+
+ r = syn_control_data_read(sd, DEVICE_CONTROL_DATA_INTR_STATUS);
+ if (r < 0)
+ goto err_free_dev;
+
+ man_id = syn_control_query_read(sd, DEVICE_CONTROL_QUERY_MANID);
+ if (man_id < 0) {
+ dev_dbg(&client->dev, "unable to get manufacturer id\n");
+ r = -ENODEV;
+ goto err_free_dev;
+ }
+
+ printk(KERN_INFO DRIVER_NAME ": " DRIVER_DESC
+ " found man id %x (%d)\n", man_id, man_id);
+
+ r = gpio_request(sd->gpio_intr, "Synaptic TM12XX Interrupt");
+ if (r < 0) {
+ dev_dbg(&client->dev, "unable to get INT GPIO\n");
+ r = -ENODEV;
+ goto err_free_dev;
+ }
+
+ gpio_direction_input(sd->gpio_intr);
+
+ r = syn_register_intr_handler(sd, FUNC_DEVICE_CONTROL,
+ syn_isr_device_control);
+ if (r < 0) {
+ dev_err(&sd->client->dev,
+ "no device control, can't continue\n");
+ r = -ENODEV;
+ goto err_free_int_gpio;
+ }
+
+ mutex_lock(&sd->lock);
+
+ r = request_irq(gpio_to_irq(sd->gpio_intr), syn_isr,
+ IRQF_DISABLED | IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING,
+ DRIVER_NAME, sd);
+ if (r) {
+ dev_dbg(&client->dev, "can't get IRQ %d (%d), err %d\n",
+ gpio_to_irq(sd->gpio_intr), sd->gpio_intr, r);
+ goto err_release_mutex;
+ }
+
+ syn_create_sysfs(sd);
+
+ /* Initialize thru reset */
+ r = syn_reset_device(sd);
+ if (r < 0) {
+ dev_err(&client->dev, "error in reset device\n");
+ goto err_free_irq;
+ }
+
+ mutex_unlock(&sd->lock);
+
+ return 0;
+
+err_free_irq:
+ free_irq(gpio_to_irq(sd->gpio_intr), sd);
+
+err_release_mutex:
+ mutex_unlock(&sd->lock);
+
+err_free_int_gpio:
+ gpio_free(sd->gpio_intr);
+
+err_free_dev:
+ kfree(sd);
+ sd = NULL;
+ return r;
+}
+
+static int __exit syn_remove(struct i2c_client *client)
+{
+ struct syn *sd = i2c_get_clientdata(client);
+ int i;
+
+ mutex_lock(&sd->lock);
+
+ if (sd->control)
+ syn_write_u8(sd,
+ sd->control->control + DEVICE_CONTROL_INTR_ENABLE,
+ 0);
+
+ free_irq(gpio_to_irq(sd->gpio_intr), sd);
+
+ mutex_unlock(&sd->lock);
+
+ destroy_workqueue(sd->wq);
+ sd->wq = NULL;
+
+ syn_remove_sysfs(sd);
+
+ for (i = 0; i < MAX_TOUCH_POINTS; i++) {
+ if (sd->tp[i].idev) {
+ input_unregister_device(sd->tp[i].idev);
+ input_free_device(sd->tp[i].idev);
+ sd->tp[i].idev = NULL;
+ }
+ }
+
+ gpio_free(sd->gpio_intr);
+
+ kfree(sd);
+ i2c_set_clientdata(client, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int syn_suspend(struct i2c_client *client, pm_message_t msg)
+{
+ struct syn *sd = i2c_get_clientdata(client);
+ int r;
+
+ mutex_lock(&sd->lock);
+
+ r = syn_read_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL);
+ /* If we fail to get previous finetuned power mode, we don't care */
+ if (r < 0)
+ goto out;
+
+ sd->device_control_ctrl = r & 0xff;
+
+ r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL,
+ DEVICE_CONTROL_SLEEP_SENSOR);
+out:
+ mutex_unlock(&sd->lock);
+
+ return 0;
+}
+
+static int syn_resume(struct i2c_client *client)
+{
+ struct syn *sd = i2c_get_clientdata(client);
+ int r;
+
+ mutex_lock(&sd->lock);
+ r = syn_write_u8(sd, sd->control->control + DEVICE_CONTROL_CTRL,
+ sd->device_control_ctrl);
+ if (r < 0)
+ dev_err(&sd->client->dev, "error %d restoring device state\n",
+ r);
+ mutex_unlock(&sd->lock);
+
+ return 0;
+}
+
+#endif
+
+
+static const struct i2c_device_id syn_id[] = {
+ { "tm12xx_ts_primary", 0 },
+ { "tm12xx_ts_secondary", 1},
+ { }
+};
+
+static struct i2c_driver syn_i2c_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .probe = syn_probe,
+ .remove = __exit_p(syn_remove),
+ .id_table = syn_id,
+
+#ifdef CONFIG_PM
+ .suspend = syn_suspend,
+ .resume = syn_resume,
+#endif
+};
+
+static int __init syn_init(void)
+{
+ int r;
+
+ r = i2c_add_driver(&syn_i2c_driver);
+ if (r < 0) {
+ printk(KERN_WARNING DRIVER_NAME
+ " driver registration failed\n");
+ return r;
+ }
+
+ return 0;
+}
+
+static void __exit syn_exit(void)
+{
+ i2c_del_driver(&syn_i2c_driver);
+}
+
+module_init(syn_init);
+module_exit(syn_exit);
+
+MODULE_AUTHOR("Mika Kuoppala <mika.kuoppala@nokia.com>");
+MODULE_DESCRIPTION("Synaptic TM12xx Touch controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 81b3ba83cc6..c33d3effb26 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -93,3 +93,7 @@ source "drivers/media/radio/Kconfig"
source "drivers/media/dvb/Kconfig"
endif # MEDIA_SUPPORT
+
+if MEDIA_SUPPORT || FB
+ source "drivers/media/video/tiler/Kconfig"
+endif
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index c0902465bdf..299994c3aa7 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -455,4 +455,7 @@ config RADIO_WL1273
To compile this driver as a module, choose M here: the
module will be called radio-wl1273.
+# TI's ST based wl128x FM radio
+source "drivers/media/radio/wl128x/Kconfig"
+
endif # RADIO_ADAPTERS
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index 717656d2f74..2faa3337198 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -26,5 +26,6 @@ obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o
obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o
obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o
+obj-$(CONFIG_RADIO_WL128X) += wl128x/
EXTRA_CFLAGS += -Isound
diff --git a/drivers/media/radio/wl128x/Kconfig b/drivers/media/radio/wl128x/Kconfig
new file mode 100644
index 00000000000..749f67b192e
--- /dev/null
+++ b/drivers/media/radio/wl128x/Kconfig
@@ -0,0 +1,17 @@
+#
+# TI's wl128x FM driver based on TI's ST driver.
+#
+menu "Texas Instruments WL128x FM driver (ST based)"
+config RADIO_WL128X
+ tristate "Texas Instruments WL128x FM Radio"
+ depends on VIDEO_V4L2 && RFKILL
+ select TI_ST
+ help
+ Choose Y here if you have this FM radio chip.
+
+ In order to control your radio card, you will need to use programs
+ that are compatible with the Video For Linux 2 API. Information on
+ this API and pointers to "v4l2" programs may be found at
+ <file:Documentation/video4linux/API.html>.
+
+endmenu
diff --git a/drivers/media/radio/wl128x/Makefile b/drivers/media/radio/wl128x/Makefile
new file mode 100644
index 00000000000..32a0ead0984
--- /dev/null
+++ b/drivers/media/radio/wl128x/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for TI's shared transport driver based wl128x
+# FM radio.
+#
+obj-$(CONFIG_RADIO_WL128X) += fm_drv.o
+fm_drv-objs := fmdrv_common.o fmdrv_rx.o fmdrv_tx.o fmdrv_v4l2.o
diff --git a/drivers/media/radio/wl128x/fmdrv.h b/drivers/media/radio/wl128x/fmdrv.h
new file mode 100644
index 00000000000..5db6fd14cf3
--- /dev/null
+++ b/drivers/media/radio/wl128x/fmdrv.h
@@ -0,0 +1,244 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ *
+ * Common header for all FM driver sub-modules.
+ *
+ * Copyright (C) 2011 Texas Instruments
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _FM_DRV_H
+#define _FM_DRV_H
+
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <linux/timer.h>
+#include <linux/version.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+
+#define FM_DRV_VERSION "0.10"
+/* Should match with FM_DRV_VERSION */
+#define FM_DRV_RADIO_VERSION KERNEL_VERSION(0, 0, 1)
+#define FM_DRV_NAME "ti_fmdrv"
+#define FM_DRV_CARD_SHORT_NAME "TI FM Radio"
+#define FM_DRV_CARD_LONG_NAME "Texas Instruments FM Radio"
+
+/* Flag info */
+#define FM_INTTASK_RUNNING 0
+#define FM_INTTASK_SCHEDULE_PENDING 1
+#define FM_FW_DW_INPROGRESS 2
+#define FM_CORE_READY 3
+#define FM_CORE_TRANSPORT_READY 4
+#define FM_AF_SWITCH_INPROGRESS 5
+#define FM_CORE_TX_XMITING 6
+
+#define FM_TUNE_COMPLETE 0x1
+#define FM_BAND_LIMIT 0x2
+
+#define FM_DRV_TX_TIMEOUT (5*HZ) /* 5 seconds */
+#define FM_DRV_RX_SEEK_TIMEOUT (20*HZ) /* 20 seconds */
+
+#define NO_OF_ENTRIES_IN_ARRAY(array) (sizeof(array) / sizeof(array[0]))
+
+#define fmerr(format, ...) \
+ printk(KERN_ERR "fmdrv: " format, ## __VA_ARGS__)
+#define fmwarn(format, ...) \
+ printk(KERN_WARNING "fmdrv: " format, ##__VA_ARGS__)
+#ifdef DEBUG
+#define fmdbg(format, ...) \
+ printk(KERN_DEBUG "fmdrv: " format, ## __VA_ARGS__)
+#else /* DEBUG */
+#define fmdbg(format, ...)
+#endif
+enum {
+ FM_MODE_OFF,
+ FM_MODE_TX,
+ FM_MODE_RX,
+ FM_MODE_ENTRY_MAX
+};
+
+#define FM_RX_RDS_INFO_FIELD_MAX 8 /* 4 Group * 2 Bytes */
+
+/* RX RDS data format */
+struct fm_rdsdata_format {
+ union {
+ struct {
+ u8 buff[FM_RX_RDS_INFO_FIELD_MAX];
+ } groupdatabuff;
+ struct {
+ u16 pidata;
+ u8 blk_b[2];
+ u8 blk_c[2];
+ u8 blk_d[2];
+ } groupgeneral;
+ struct {
+ u16 pidata;
+ u8 blk_b[2];
+ u8 af[2];
+ u8 ps[2];
+ } group0A;
+ struct {
+ u16 pi[2];
+ u8 blk_b[2];
+ u8 ps[2];
+ } group0B;
+ } data;
+};
+
+/* FM region (Europe/US, Japan) info */
+struct region_info {
+ u32 chanl_space;
+ u32 bot_freq;
+ u32 top_freq;
+ u8 fm_band;
+};
+struct fmdev;
+typedef void (*int_handler_prototype) (struct fmdev *);
+
+/* FM Interrupt processing related info */
+struct fm_irq {
+ u8 stage;
+ u16 flag; /* FM interrupt flag */
+ u16 mask; /* FM interrupt mask */
+ /* Interrupt process timeout handler */
+ struct timer_list timer;
+ u8 retry;
+ int_handler_prototype *handlers;
+};
+
+/* RDS info */
+struct fm_rds {
+ u8 flag; /* RX RDS on/off status */
+ u8 last_blk_idx; /* Last received RDS block */
+
+ /* RDS buffer */
+ wait_queue_head_t read_queue;
+ u32 buf_size; /* Size is always multiple of 3 */
+ u32 wr_idx;
+ u32 rd_idx;
+ u8 *buff;
+};
+
+#define FM_RDS_MAX_AF_LIST 25
+
+/*
+ * Current RX channel Alternate Frequency cache.
+ * This info is used to switch to other freq (AF)
+ * when current channel signal strengh is below RSSI threshold.
+ */
+struct tuned_station_info {
+ u16 picode;
+ u32 af_cache[FM_RDS_MAX_AF_LIST];
+ u8 afcache_size;
+ u8 af_list_max;
+};
+
+/* FM RX mode info */
+struct fm_rx {
+ struct region_info region; /* Current selected band */
+ u32 freq; /* Current RX frquency */
+ u8 mute_mode; /* Current mute mode */
+ u8 deemphasis_mode; /* Current deemphasis mode */
+ /* RF dependent soft mute mode */
+ u8 rf_depend_mute;
+ u16 volume; /* Current volume level */
+ u16 rssi_threshold; /* Current RSSI threshold level */
+ /* Holds the index of the current AF jump */
+ u8 afjump_idx;
+ /* Will hold the frequency before the jump */
+ u32 freq_before_jump;
+ u8 rds_mode; /* RDS operation mode (RDS/RDBS) */
+ u8 af_mode; /* Alternate frequency on/off */
+ struct tuned_station_info stat_info;
+ struct fm_rds rds;
+};
+
+#define FMTX_RDS_TXT_STR_SIZE 25
+/*
+ * FM TX RDS data
+ *
+ * @ text_type: is the text following PS or RT
+ * @ text: radio text string which could either be PS or RT
+ * @ af_freq: alternate frequency for Tx
+ * TODO: to be declared in application
+ */
+struct tx_rds {
+ u8 text_type;
+ u8 text[FMTX_RDS_TXT_STR_SIZE];
+ u8 flag;
+ u32 af_freq;
+};
+/*
+ * FM TX global data
+ *
+ * @ pwr_lvl: Power Level of the Transmission from mixer control
+ * @ xmit_state: Transmission state = Updated locally upon Start/Stop
+ * @ audio_io: i2S/Analog
+ * @ tx_frq: Transmission frequency
+ */
+struct fmtx_data {
+ u8 pwr_lvl;
+ u8 xmit_state;
+ u8 audio_io;
+ u8 region;
+ u16 aud_mode;
+ u32 preemph;
+ u32 tx_frq;
+ struct tx_rds rds;
+};
+
+/* FM driver operation structure */
+struct fmdev {
+ struct video_device *radio_dev; /* V4L2 video device pointer */
+ struct snd_card *card; /* Card which holds FM mixer controls */
+ u16 asci_id;
+ spinlock_t rds_buff_lock; /* To protect access to RDS buffer */
+ spinlock_t resp_skb_lock; /* To protect access to received SKB */
+
+ long flag; /* FM driver state machine info */
+ u8 streg_cbdata; /* status of ST registration */
+
+ struct sk_buff_head rx_q; /* RX queue */
+ struct tasklet_struct rx_task; /* RX Tasklet */
+
+ struct sk_buff_head tx_q; /* TX queue */
+ struct tasklet_struct tx_task; /* TX Tasklet */
+ unsigned long last_tx_jiffies; /* Timestamp of last pkt sent */
+ atomic_t tx_cnt; /* Number of packets can send at a time */
+
+ struct sk_buff *resp_skb; /* Response from the chip */
+ /* Main task completion handler */
+ struct completion maintask_comp;
+ /* Opcode of last command sent to the chip */
+ u8 pre_op;
+ /* Handler used for wakeup when response packet is received */
+ struct completion *resp_comp;
+ struct fm_irq irq_info;
+ u8 curr_fmmode; /* Current FM chip mode (TX, RX, OFF) */
+ struct fm_rx rx; /* FM receiver info */
+ struct fmtx_data tx_data;
+
+ /* V4L2 ctrl framwork handler*/
+ struct v4l2_ctrl_handler ctrl_handler;
+
+ /* For core assisted locking */
+ struct mutex mutex;
+};
+#endif
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
new file mode 100644
index 00000000000..319f32506ff
--- /dev/null
+++ b/drivers/media/radio/wl128x/fmdrv_common.c
@@ -0,0 +1,1688 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ *
+ * This sub-module of FM driver is common for FM RX and TX
+ * functionality. This module is responsible for:
+ * 1) Forming group of Channel-8 commands to perform particular
+ * functionality (eg., frequency set require more than
+ * one Channel-8 command to be sent to the chip).
+ * 2) Sending each Channel-8 command to the chip and reading
+ * response back over Shared Transport.
+ * 3) Managing TX and RX Queues and Tasklets.
+ * 4) Handling FM Interrupt packet and taking appropriate action.
+ * 5) Loading FM firmware to the chip (common, FM TX, and FM RX
+ * firmware files based on mode selection)
+ *
+ * Copyright (C) 2011 Texas Instruments
+ * Author: Raja Mani <raja_mani@ti.com>
+ * Author: Manjunatha Halli <manjunatha_halli@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include "fmdrv.h"
+#include "fmdrv_v4l2.h"
+#include "fmdrv_common.h"
+#include <linux/ti_wilink_st.h>
+#include "fmdrv_rx.h"
+#include "fmdrv_tx.h"
+
+/* Region info */
+static struct region_info region_configs[] = {
+ /* Europe/US */
+ {
+ .chanl_space = FM_CHANNEL_SPACING_200KHZ * FM_FREQ_MUL,
+ .bot_freq = 87500, /* 87.5 MHz */
+ .top_freq = 108000, /* 108 MHz */
+ .fm_band = 0,
+ },
+ /* Japan */
+ {
+ .chanl_space = FM_CHANNEL_SPACING_200KHZ * FM_FREQ_MUL,
+ .bot_freq = 76000, /* 76 MHz */
+ .top_freq = 90000, /* 90 MHz */
+ .fm_band = 1,
+ },
+};
+
+/* Band selection */
+static u8 default_radio_region; /* Europe/US */
+module_param(default_radio_region, byte, 0);
+MODULE_PARM_DESC(default_radio_region, "Region: 0=Europe/US, 1=Japan");
+
+/* RDS buffer blocks */
+static u32 default_rds_buf = 300;
+module_param(default_rds_buf, uint, 0444);
+MODULE_PARM_DESC(rds_buf, "RDS buffer entries");
+
+/* Radio Nr */
+static u32 radio_nr = -1;
+module_param(radio_nr, int, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio Nr");
+
+/* FM irq handlers forward declaration */
+static void fm_irq_send_flag_getcmd(struct fmdev *);
+static void fm_irq_handle_flag_getcmd_resp(struct fmdev *);
+static void fm_irq_handle_hw_malfunction(struct fmdev *);
+static void fm_irq_handle_rds_start(struct fmdev *);
+static void fm_irq_send_rdsdata_getcmd(struct fmdev *);
+static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *);
+static void fm_irq_handle_rds_finish(struct fmdev *);
+static void fm_irq_handle_tune_op_ended(struct fmdev *);
+static void fm_irq_handle_power_enb(struct fmdev *);
+static void fm_irq_handle_low_rssi_start(struct fmdev *);
+static void fm_irq_afjump_set_pi(struct fmdev *);
+static void fm_irq_handle_set_pi_resp(struct fmdev *);
+static void fm_irq_afjump_set_pimask(struct fmdev *);
+static void fm_irq_handle_set_pimask_resp(struct fmdev *);
+static void fm_irq_afjump_setfreq(struct fmdev *);
+static void fm_irq_handle_setfreq_resp(struct fmdev *);
+static void fm_irq_afjump_enableint(struct fmdev *);
+static void fm_irq_afjump_enableint_resp(struct fmdev *);
+static void fm_irq_start_afjump(struct fmdev *);
+static void fm_irq_handle_start_afjump_resp(struct fmdev *);
+static void fm_irq_afjump_rd_freq(struct fmdev *);
+static void fm_irq_afjump_rd_freq_resp(struct fmdev *);
+static void fm_irq_handle_low_rssi_finish(struct fmdev *);
+static void fm_irq_send_intmsk_cmd(struct fmdev *);
+static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *);
+
+/*
+ * When FM common module receives interrupt packet, following handlers
+ * will be executed one after another to service the interrupt(s)
+ */
+enum fmc_irq_handler_index {
+ FM_SEND_FLAG_GETCMD_IDX,
+ FM_HANDLE_FLAG_GETCMD_RESP_IDX,
+
+ /* HW malfunction irq handler */
+ FM_HW_MAL_FUNC_IDX,
+
+ /* RDS threshold reached irq handler */
+ FM_RDS_START_IDX,
+ FM_RDS_SEND_RDS_GETCMD_IDX,
+ FM_RDS_HANDLE_RDS_GETCMD_RESP_IDX,
+ FM_RDS_FINISH_IDX,
+
+ /* Tune operation ended irq handler */
+ FM_HW_TUNE_OP_ENDED_IDX,
+
+ /* TX power enable irq handler */
+ FM_HW_POWER_ENB_IDX,
+
+ /* Low RSSI irq handler */
+ FM_LOW_RSSI_START_IDX,
+ FM_AF_JUMP_SETPI_IDX,
+ FM_AF_JUMP_HANDLE_SETPI_RESP_IDX,
+ FM_AF_JUMP_SETPI_MASK_IDX,
+ FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_IDX,
+ FM_AF_JUMP_SET_AF_FREQ_IDX,
+ FM_AF_JUMP_HANDLE_SET_AFFREQ_RESP_IDX,
+ FM_AF_JUMP_ENABLE_INT_IDX,
+ FM_AF_JUMP_ENABLE_INT_RESP_IDX,
+ FM_AF_JUMP_START_AFJUMP_IDX,
+ FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_IDX,
+ FM_AF_JUMP_RD_FREQ_IDX,
+ FM_AF_JUMP_RD_FREQ_RESP_IDX,
+ FM_LOW_RSSI_FINISH_IDX,
+
+ /* Interrupt process post action */
+ FM_SEND_INTMSK_CMD_IDX,
+ FM_HANDLE_INTMSK_CMD_RESP_IDX,
+};
+
+/* FM interrupt handler table */
+static int_handler_prototype int_handler_table[] = {
+ fm_irq_send_flag_getcmd,
+ fm_irq_handle_flag_getcmd_resp,
+ fm_irq_handle_hw_malfunction,
+ fm_irq_handle_rds_start, /* RDS threshold reached irq handler */
+ fm_irq_send_rdsdata_getcmd,
+ fm_irq_handle_rdsdata_getcmd_resp,
+ fm_irq_handle_rds_finish,
+ fm_irq_handle_tune_op_ended,
+ fm_irq_handle_power_enb, /* TX power enable irq handler */
+ fm_irq_handle_low_rssi_start,
+ fm_irq_afjump_set_pi,
+ fm_irq_handle_set_pi_resp,
+ fm_irq_afjump_set_pimask,
+ fm_irq_handle_set_pimask_resp,
+ fm_irq_afjump_setfreq,
+ fm_irq_handle_setfreq_resp,
+ fm_irq_afjump_enableint,
+ fm_irq_afjump_enableint_resp,
+ fm_irq_start_afjump,
+ fm_irq_handle_start_afjump_resp,
+ fm_irq_afjump_rd_freq,
+ fm_irq_afjump_rd_freq_resp,
+ fm_irq_handle_low_rssi_finish,
+ fm_irq_send_intmsk_cmd, /* Interrupt process post action */
+ fm_irq_handle_intmsk_cmd_resp
+};
+
+long (*g_st_write) (struct sk_buff *skb);
+static struct completion wait_for_fmdrv_reg_comp;
+
+static inline void fm_irq_call(struct fmdev *fmdev)
+{
+ fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev);
+}
+
+/* Continue next function in interrupt handler table */
+static inline void fm_irq_call_stage(struct fmdev *fmdev, u8 stage)
+{
+ fmdev->irq_info.stage = stage;
+ fm_irq_call(fmdev);
+}
+
+static inline void fm_irq_timeout_stage(struct fmdev *fmdev, u8 stage)
+{
+ fmdev->irq_info.stage = stage;
+ mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT);
+}
+
+#ifdef FM_DUMP_TXRX_PKT
+ /* To dump outgoing FM Channel-8 packets */
+inline void dump_tx_skb_data(struct sk_buff *skb)
+{
+ int len, len_org;
+ u8 index;
+ struct fm_cmd_msg_hdr *cmd_hdr;
+
+ cmd_hdr = (struct fm_cmd_msg_hdr *)skb->data;
+ printk(KERN_INFO "<<%shdr:%02x len:%02x opcode:%02x type:%s dlen:%02x",
+ fm_cb(skb)->completion ? " " : "*", cmd_hdr->hdr,
+ cmd_hdr->len, cmd_hdr->op,
+ cmd_hdr->rd_wr ? "RD" : "WR", cmd_hdr->dlen);
+
+ len_org = skb->len - FM_CMD_MSG_HDR_SIZE;
+ if (len_org > 0) {
+ printk("\n data(%d): ", cmd_hdr->dlen);
+ len = min(len_org, 14);
+ for (index = 0; index < len; index++)
+ printk("%x ",
+ skb->data[FM_CMD_MSG_HDR_SIZE + index]);
+ printk("%s", (len_org > 14) ? ".." : "");
+ }
+ printk("\n");
+}
+
+ /* To dump incoming FM Channel-8 packets */
+inline void dump_rx_skb_data(struct sk_buff *skb)
+{
+ int len, len_org;
+ u8 index;
+ struct fm_event_msg_hdr *evt_hdr;
+
+ evt_hdr = (struct fm_event_msg_hdr *)skb->data;
+ printk(KERN_INFO ">> hdr:%02x len:%02x sts:%02x numhci:%02x "
+ "opcode:%02x type:%s dlen:%02x", evt_hdr->hdr, evt_hdr->len,
+ evt_hdr->status, evt_hdr->num_fm_hci_cmds, evt_hdr->op,
+ (evt_hdr->rd_wr) ? "RD" : "WR", evt_hdr->dlen);
+
+ len_org = skb->len - FM_EVT_MSG_HDR_SIZE;
+ if (len_org > 0) {
+ printk("\n data(%d): ", evt_hdr->dlen);
+ len = min(len_org, 14);
+ for (index = 0; index < len; index++)
+ printk("%x ",
+ skb->data[FM_EVT_MSG_HDR_SIZE + index]);
+ printk("%s", (len_org > 14) ? ".." : "");
+ }
+ printk("\n");
+}
+#endif
+
+void fmc_update_region_info(struct fmdev *fmdev, u8 region_to_set)
+{
+ fmdev->rx.region = region_configs[region_to_set];
+}
+
+/*
+ * FM common sub-module will schedule this tasklet whenever it receives
+ * FM packet from ST driver.
+ */
+static void recv_tasklet(unsigned long arg)
+{
+ struct fmdev *fmdev;
+ struct fm_irq *irq_info;
+ struct fm_event_msg_hdr *evt_hdr;
+ struct sk_buff *skb;
+ u8 num_fm_hci_cmds;
+ unsigned long flags;
+
+ fmdev = (struct fmdev *)arg;
+ irq_info = &fmdev->irq_info;
+ /* Process all packets in the RX queue */
+ while ((skb = skb_dequeue(&fmdev->rx_q))) {
+ if (skb->len < sizeof(struct fm_event_msg_hdr)) {
+ fmerr("skb(%p) has only %d bytes"
+ "atleast need %d bytes to decode\n", skb,
+ skb->len, sizeof(struct fm_event_msg_hdr));
+ kfree_skb(skb);
+ continue;
+ }
+
+ evt_hdr = (void *)skb->data;
+ num_fm_hci_cmds = evt_hdr->num_fm_hci_cmds;
+
+ /* FM interrupt packet? */
+ if (evt_hdr->op == FM_INTERRUPT) {
+ /* FM interrupt handler started already? */
+ if (!test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) {
+ set_bit(FM_INTTASK_RUNNING, &fmdev->flag);
+ if (irq_info->stage != 0) {
+ fmerr("Inval stage resetting to zero\n");
+ irq_info->stage = 0;
+ }
+
+ /*
+ * Execute first function in interrupt handler
+ * table.
+ */
+ irq_info->handlers[irq_info->stage](fmdev);
+ } else {
+ set_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag);
+ }
+ kfree_skb(skb);
+ }
+ /* Anyone waiting for this with completion handler? */
+ else if (evt_hdr->op == fmdev->pre_op && fmdev->resp_comp != NULL) {
+
+ spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
+ fmdev->resp_skb = skb;
+ spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
+ complete(fmdev->resp_comp);
+
+ fmdev->resp_comp = NULL;
+ atomic_set(&fmdev->tx_cnt, 1);
+ }
+ /* Is this for interrupt handler? */
+ else if (evt_hdr->op == fmdev->pre_op && fmdev->resp_comp == NULL) {
+ if (fmdev->resp_skb != NULL)
+ fmerr("Response SKB ptr not NULL\n");
+
+ spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
+ fmdev->resp_skb = skb;
+ spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
+
+ /* Execute interrupt handler where state index points */
+ irq_info->handlers[irq_info->stage](fmdev);
+
+ kfree_skb(skb);
+ atomic_set(&fmdev->tx_cnt, 1);
+ } else {
+ fmerr("Nobody claimed SKB(%p),purging\n", skb);
+ }
+
+ /*
+ * Check flow control field. If Num_FM_HCI_Commands field is
+ * not zero, schedule FM TX tasklet.
+ */
+ if (num_fm_hci_cmds && atomic_read(&fmdev->tx_cnt))
+ if (!skb_queue_empty(&fmdev->tx_q))
+ tasklet_schedule(&fmdev->tx_task);
+ }
+}
+
+/* FM send tasklet: is scheduled when FM packet has to be sent to chip */
+static void send_tasklet(unsigned long arg)
+{
+ struct fmdev *fmdev;
+ struct sk_buff *skb;
+ int len;
+
+ fmdev = (struct fmdev *)arg;
+
+ if (!atomic_read(&fmdev->tx_cnt))
+ return;
+
+ /* Check, is there any timeout happenned to last transmitted packet */
+ if ((jiffies - fmdev->last_tx_jiffies) > FM_DRV_TX_TIMEOUT) {
+ fmdbg("TX timeout occurred\n");
+ atomic_set(&fmdev->tx_cnt, 1);
+ }
+
+ /* Send queued FM TX packets */
+ skb = skb_dequeue(&fmdev->tx_q);
+ if (!skb)
+ return;
+
+ atomic_dec(&fmdev->tx_cnt);
+ fmdev->pre_op = fm_cb(skb)->fm_op;
+
+ if (fmdev->resp_comp != NULL)
+ fmerr("Response completion handler is not NULL\n");
+
+ fmdev->resp_comp = fm_cb(skb)->completion;
+
+ /* Write FM packet to ST driver */
+ len = g_st_write(skb);
+ if (len < 0) {
+ kfree_skb(skb);
+ fmdev->resp_comp = NULL;
+ fmerr("TX tasklet failed to send skb(%p)\n", skb);
+ atomic_set(&fmdev->tx_cnt, 1);
+ } else {
+ fmdev->last_tx_jiffies = jiffies;
+ }
+}
+
+/*
+ * Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for
+ * transmission
+ */
+static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
+ int payload_len, struct completion *wait_completion)
+{
+ struct sk_buff *skb;
+ struct fm_cmd_msg_hdr *hdr;
+ int size;
+
+ if (fm_op >= FM_INTERRUPT) {
+ fmerr("Invalid fm opcode - %d\n", fm_op);
+ return -EINVAL;
+ }
+ if (test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) && payload == NULL) {
+ fmerr("Payload data is NULL during fw download\n");
+ return -EINVAL;
+ }
+ if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag))
+ size =
+ FM_CMD_MSG_HDR_SIZE + ((payload == NULL) ? 0 : payload_len);
+ else
+ size = payload_len;
+
+ skb = alloc_skb(size, GFP_ATOMIC);
+ if (!skb) {
+ fmerr("No memory to create new SKB\n");
+ return -ENOMEM;
+ }
+ /*
+ * Don't fill FM header info for the commands which come from
+ * FM firmware file.
+ */
+ if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) ||
+ test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) {
+ /* Fill command header info */
+ hdr = (struct fm_cmd_msg_hdr *)skb_put(skb, FM_CMD_MSG_HDR_SIZE);
+ hdr->hdr = FM_PKT_LOGICAL_CHAN_NUMBER; /* 0x08 */
+
+ /* 3 (fm_opcode,rd_wr,dlen) + payload len) */
+ hdr->len = ((payload == NULL) ? 0 : payload_len) + 3;
+
+ /* FM opcode */
+ hdr->op = fm_op;
+
+ /* read/write type */
+ hdr->rd_wr = type;
+ hdr->dlen = payload_len;
+ fm_cb(skb)->fm_op = fm_op;
+
+ /*
+ * If firmware download has finished and the command is
+ * not a read command then payload is != NULL - a write
+ * command with u16 payload - convert to be16
+ */
+ if (payload != NULL)
+ *(u16 *)payload = cpu_to_be16(*(u16 *)payload);
+
+ } else if (payload != NULL) {
+ fm_cb(skb)->fm_op = *((u8 *)payload + 2);
+ }
+ if (payload != NULL)
+ memcpy(skb_put(skb, payload_len), payload, payload_len);
+
+ fm_cb(skb)->completion = wait_completion;
+ skb_queue_tail(&fmdev->tx_q, skb);
+ tasklet_schedule(&fmdev->tx_task);
+
+ return 0;
+}
+
+/* Sends FM Channel-8 command to the chip and waits for the response */
+u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
+ unsigned int payload_len, void *response, int *response_len)
+{
+ struct sk_buff *skb;
+ struct fm_event_msg_hdr *evt_hdr;
+ unsigned long flags;
+ u32 ret;
+
+ init_completion(&fmdev->maintask_comp);
+ ret = fm_send_cmd(fmdev, fm_op, type, payload, payload_len,
+ &fmdev->maintask_comp);
+ if (ret)
+ return ret;
+
+ ret = wait_for_completion_timeout(&fmdev->maintask_comp, FM_DRV_TX_TIMEOUT);
+ if (!ret) {
+ fmerr("Timeout(%d sec),didn't get reg"
+ "completion signal from RX tasklet\n",
+ jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
+ return -ETIMEDOUT;
+ }
+ if (!fmdev->resp_skb) {
+ fmerr("Reponse SKB is missing\n");
+ return -EFAULT;
+ }
+ spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
+ skb = fmdev->resp_skb;
+ fmdev->resp_skb = NULL;
+ spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
+
+ evt_hdr = (void *)skb->data;
+ if (evt_hdr->status != 0) {
+ fmerr("Received event pkt status(%d) is not zero\n",
+ evt_hdr->status);
+ kfree_skb(skb);
+ return -EIO;
+ }
+ /* Send response data to caller */
+ if (response != NULL && response_len != NULL && evt_hdr->dlen) {
+ /* Skip header info and copy only response data */
+ skb_pull(skb, sizeof(struct fm_event_msg_hdr));
+ memcpy(response, skb->data, evt_hdr->dlen);
+ *response_len = evt_hdr->dlen;
+ } else if (response_len != NULL && evt_hdr->dlen == 0) {
+ *response_len = 0;
+ }
+ kfree_skb(skb);
+
+ return 0;
+}
+
+/* --- Helper functions used in FM interrupt handlers ---*/
+static inline u32 check_cmdresp_status(struct fmdev *fmdev,
+ struct sk_buff **skb)
+{
+ struct fm_event_msg_hdr *fm_evt_hdr;
+ unsigned long flags;
+
+ del_timer(&fmdev->irq_info.timer);
+
+ spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
+ *skb = fmdev->resp_skb;
+ fmdev->resp_skb = NULL;
+ spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
+
+ fm_evt_hdr = (void *)(*skb)->data;
+ if (fm_evt_hdr->status != 0) {
+ fmerr("irq: opcode %x response status is not zero "
+ "Initiating irq recovery process\n",
+ fm_evt_hdr->op);
+
+ mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT);
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline void fm_irq_common_cmd_resp_helper(struct fmdev *fmdev, u8 stage)
+{
+ struct sk_buff *skb;
+
+ if (!check_cmdresp_status(fmdev, &skb))
+ fm_irq_call_stage(fmdev, stage);
+}
+
+/*
+ * Interrupt process timeout handler.
+ * One of the irq handler did not get proper response from the chip. So take
+ * recovery action here. FM interrupts are disabled in the beginning of
+ * interrupt process. Therefore reset stage index to re-enable default
+ * interrupts. So that next interrupt will be processed as usual.
+ */
+static void int_timeout_handler(unsigned long data)
+{
+ struct fmdev *fmdev;
+ struct fm_irq *fmirq;
+
+ fmdbg("irq: timeout,trying to re-enable fm interrupts\n");
+ fmdev = (struct fmdev *)data;
+ fmirq = &fmdev->irq_info;
+ fmirq->retry++;
+
+ if (fmirq->retry > FM_IRQ_TIMEOUT_RETRY_MAX) {
+ /* Stop recovery action (interrupt reenable process) and
+ * reset stage index & retry count values */
+ fmirq->stage = 0;
+ fmirq->retry = 0;
+ fmerr("Recovery action failed during"
+ "irq processing, max retry reached\n");
+ return;
+ }
+ fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX);
+}
+
+/* --------- FM interrupt handlers ------------*/
+static void fm_irq_send_flag_getcmd(struct fmdev *fmdev)
+{
+ u16 flag;
+
+ /* Send FLAG_GET command , to know the source of interrupt */
+ if (!fm_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, sizeof(flag), NULL))
+ fm_irq_timeout_stage(fmdev, FM_HANDLE_FLAG_GETCMD_RESP_IDX);
+}
+
+static void fm_irq_handle_flag_getcmd_resp(struct fmdev *fmdev)
+{
+ struct sk_buff *skb;
+ struct fm_event_msg_hdr *fm_evt_hdr;
+
+ if (check_cmdresp_status(fmdev, &skb))
+ return;
+
+ fm_evt_hdr = (void *)skb->data;
+
+ /* Skip header info and copy only response data */
+ skb_pull(skb, sizeof(struct fm_event_msg_hdr));
+ memcpy(&fmdev->irq_info.flag, skb->data, fm_evt_hdr->dlen);
+
+ fmdev->irq_info.flag = be16_to_cpu(fmdev->irq_info.flag);
+ fmdbg("irq: flag register(0x%x)\n", fmdev->irq_info.flag);
+
+ /* Continue next function in interrupt handler table */
+ fm_irq_call_stage(fmdev, FM_HW_MAL_FUNC_IDX);
+}
+
+static void fm_irq_handle_hw_malfunction(struct fmdev *fmdev)
+{
+ if (fmdev->irq_info.flag & FM_MAL_EVENT & fmdev->irq_info.mask)
+ fmerr("irq: HW MAL int received - do nothing\n");
+
+ /* Continue next function in interrupt handler table */
+ fm_irq_call_stage(fmdev, FM_RDS_START_IDX);
+}
+
+static void fm_irq_handle_rds_start(struct fmdev *fmdev)
+{
+ if (fmdev->irq_info.flag & FM_RDS_EVENT & fmdev->irq_info.mask) {
+ fmdbg("irq: rds threshold reached\n");
+ fmdev->irq_info.stage = FM_RDS_SEND_RDS_GETCMD_IDX;
+ } else {
+ /* Continue next function in interrupt handler table */
+ fmdev->irq_info.stage = FM_HW_TUNE_OP_ENDED_IDX;
+ }
+
+ fm_irq_call(fmdev);
+}
+
+static void fm_irq_send_rdsdata_getcmd(struct fmdev *fmdev)
+{
+ /* Send the command to read RDS data from the chip */
+ if (!fm_send_cmd(fmdev, RDS_DATA_GET, REG_RD, NULL,
+ (FM_RX_RDS_FIFO_THRESHOLD * 3), NULL))
+ fm_irq_timeout_stage(fmdev, FM_RDS_HANDLE_RDS_GETCMD_RESP_IDX);
+}
+
+/* Keeps track of current RX channel AF (Alternate Frequency) */
+static void fm_rx_update_af_cache(struct fmdev *fmdev, u8 af)
+{
+ struct tuned_station_info *stat_info = &fmdev->rx.stat_info;
+ u8 reg_idx = fmdev->rx.region.fm_band;
+ u8 index;
+ u32 freq;
+
+ /* First AF indicates the number of AF follows. Reset the list */
+ if ((af >= FM_RDS_1_AF_FOLLOWS) && (af <= FM_RDS_25_AF_FOLLOWS)) {
+ fmdev->rx.stat_info.af_list_max = (af - FM_RDS_1_AF_FOLLOWS + 1);
+ fmdev->rx.stat_info.afcache_size = 0;
+ fmdbg("No of expected AF : %d\n", fmdev->rx.stat_info.af_list_max);
+ return;
+ }
+
+ if (af < FM_RDS_MIN_AF)
+ return;
+ if (reg_idx == FM_BAND_EUROPE_US && af > FM_RDS_MAX_AF)
+ return;
+ if (reg_idx == FM_BAND_JAPAN && af > FM_RDS_MAX_AF_JAPAN)
+ return;
+
+ freq = fmdev->rx.region.bot_freq + (af * 100);
+ if (freq == fmdev->rx.freq) {
+ fmdbg("Current freq(%d) is matching with received AF(%d)\n",
+ fmdev->rx.freq, freq);
+ return;
+ }
+ /* Do check in AF cache */
+ for (index = 0; index < stat_info->afcache_size; index++) {
+ if (stat_info->af_cache[index] == freq)
+ break;
+ }
+ /* Reached the limit of the list - ignore the next AF */
+ if (index == stat_info->af_list_max) {
+ fmdbg("AF cache is full\n");
+ return;
+ }
+ /*
+ * If we reached the end of the list then this AF is not
+ * in the list - add it.
+ */
+ if (index == stat_info->afcache_size) {
+ fmdbg("Storing AF %d to cache index %d\n", freq, index);
+ stat_info->af_cache[index] = freq;
+ stat_info->afcache_size++;
+ }
+}
+
+/*
+ * Converts RDS buffer data from big endian format
+ * to little endian format.
+ */
+static void fm_rdsparse_swapbytes(struct fmdev *fmdev,
+ struct fm_rdsdata_format *rds_format)
+{
+ u8 byte1;
+ u8 index = 0;
+ u8 *rds_buff;
+
+ /*
+ * Since in Orca the 2 RDS Data bytes are in little endian and
+ * in Dolphin they are in big endian, the parsing of the RDS data
+ * is chip dependent
+ */
+ if (fmdev->asci_id != 0x6350) {
+ rds_buff = &rds_format->data.groupdatabuff.buff[0];
+ while (index + 1 < FM_RX_RDS_INFO_FIELD_MAX) {
+ byte1 = rds_buff[index];
+ rds_buff[index] = rds_buff[index + 1];
+ rds_buff[index + 1] = byte1;
+ index += 2;
+ }
+ }
+}
+
+static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev)
+{
+ struct sk_buff *skb;
+ struct fm_rdsdata_format rds_fmt;
+ struct fm_rds *rds = &fmdev->rx.rds;
+ unsigned long group_idx, flags;
+ u8 *rds_data, meta_data, tmpbuf[3];
+ u8 type, blk_idx;
+ u16 cur_picode;
+ u32 rds_len;
+
+ if (check_cmdresp_status(fmdev, &skb))
+ return;
+
+ /* Skip header info */
+ skb_pull(skb, sizeof(struct fm_event_msg_hdr));
+ rds_data = skb->data;
+ rds_len = skb->len;
+
+ /* Parse the RDS data */
+ while (rds_len >= FM_RDS_BLK_SIZE) {
+ meta_data = rds_data[2];
+ /* Get the type: 0=A, 1=B, 2=C, 3=C', 4=D, 5=E */
+ type = (meta_data & 0x07);
+
+ /* Transform the blk type into index sequence (0, 1, 2, 3, 4) */
+ blk_idx = (type <= FM_RDS_BLOCK_C ? type : (type - 1));
+ fmdbg("Block index:%d(%s)\n", blk_idx,
+ (meta_data & FM_RDS_STATUS_ERR_MASK) ? "Bad" : "Ok");
+
+ if ((meta_data & FM_RDS_STATUS_ERR_MASK) != 0)
+ break;
+
+ if (blk_idx < FM_RDS_BLK_IDX_A || blk_idx > FM_RDS_BLK_IDX_D) {
+ fmdbg("Block sequence mismatch\n");
+ rds->last_blk_idx = -1;
+ break;
+ }
+
+ /* Skip checkword (control) byte and copy only data byte */
+ memcpy(&rds_fmt.data.groupdatabuff.
+ buff[blk_idx * (FM_RDS_BLK_SIZE - 1)],
+ rds_data, (FM_RDS_BLK_SIZE - 1));
+
+ rds->last_blk_idx = blk_idx;
+
+ /* If completed a whole group then handle it */
+ if (blk_idx == FM_RDS_BLK_IDX_D) {
+ fmdbg("Good block received\n");
+ fm_rdsparse_swapbytes(fmdev, &rds_fmt);
+
+ /*
+ * Extract PI code and store in local cache.
+ * We need this during AF switch processing.
+ */
+ cur_picode = be16_to_cpu(rds_fmt.data.groupgeneral.pidata);
+ if (fmdev->rx.stat_info.picode != cur_picode)
+ fmdev->rx.stat_info.picode = cur_picode;
+
+ fmdbg("picode:%d\n", cur_picode);
+
+ group_idx = (rds_fmt.data.groupgeneral.blk_b[0] >> 3);
+ fmdbg("(fmdrv):Group:%ld%s\n", group_idx/2,
+ (group_idx % 2) ? "B" : "A");
+
+ group_idx = 1 << (rds_fmt.data.groupgeneral.blk_b[0] >> 3);
+ if (group_idx == FM_RDS_GROUP_TYPE_MASK_0A) {
+ fm_rx_update_af_cache(fmdev, rds_fmt.data.group0A.af[0]);
+ fm_rx_update_af_cache(fmdev, rds_fmt.data.group0A.af[1]);
+ }
+ }
+ rds_len -= FM_RDS_BLK_SIZE;
+ rds_data += FM_RDS_BLK_SIZE;
+ }
+
+ /* Copy raw rds data to internal rds buffer */
+ rds_data = skb->data;
+ rds_len = skb->len;
+
+ spin_lock_irqsave(&fmdev->rds_buff_lock, flags);
+ while (rds_len > 0) {
+ /*
+ * Fill RDS buffer as per V4L2 specification.
+ * Store control byte
+ */
+ type = (rds_data[2] & 0x07);
+ blk_idx = (type <= FM_RDS_BLOCK_C ? type : (type - 1));
+ tmpbuf[2] = blk_idx; /* Offset name */
+ tmpbuf[2] |= blk_idx << 3; /* Received offset */
+
+ /* Store data byte */
+ tmpbuf[0] = rds_data[0];
+ tmpbuf[1] = rds_data[1];
+
+ memcpy(&rds->buff[rds->wr_idx], &tmpbuf, FM_RDS_BLK_SIZE);
+ rds->wr_idx = (rds->wr_idx + FM_RDS_BLK_SIZE) % rds->buf_size;
+
+ /* Check for overflow & start over */
+ if (rds->wr_idx == rds->rd_idx) {
+ fmdbg("RDS buffer overflow\n");
+ rds->wr_idx = 0;
+ rds->rd_idx = 0;
+ break;
+ }
+ rds_len -= FM_RDS_BLK_SIZE;
+ rds_data += FM_RDS_BLK_SIZE;
+ }
+ spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags);
+
+ /* Wakeup read queue */
+ if (rds->wr_idx != rds->rd_idx)
+ wake_up_interruptible(&rds->read_queue);
+
+ fm_irq_call_stage(fmdev, FM_RDS_FINISH_IDX);
+}
+
+static void fm_irq_handle_rds_finish(struct fmdev *fmdev)
+{
+ fm_irq_call_stage(fmdev, FM_HW_TUNE_OP_ENDED_IDX);
+}
+
+static void fm_irq_handle_tune_op_ended(struct fmdev *fmdev)
+{
+ if (fmdev->irq_info.flag & (FM_FR_EVENT | FM_BL_EVENT) & fmdev->
+ irq_info.mask) {
+ fmdbg("irq: tune ended/bandlimit reached\n");
+ if (test_and_clear_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag)) {
+ fmdev->irq_info.stage = FM_AF_JUMP_RD_FREQ_IDX;
+ } else {
+ complete(&fmdev->maintask_comp);
+ fmdev->irq_info.stage = FM_HW_POWER_ENB_IDX;
+ }
+ } else
+ fmdev->irq_info.stage = FM_HW_POWER_ENB_IDX;
+
+ fm_irq_call(fmdev);
+}
+
+static void fm_irq_handle_power_enb(struct fmdev *fmdev)
+{
+ if (fmdev->irq_info.flag & FM_POW_ENB_EVENT) {
+ fmdbg("irq: Power Enabled/Disabled\n");
+ complete(&fmdev->maintask_comp);
+ }
+
+ fm_irq_call_stage(fmdev, FM_LOW_RSSI_START_IDX);
+}
+
+static void fm_irq_handle_low_rssi_start(struct fmdev *fmdev)
+{
+ if ((fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) &&
+ (fmdev->irq_info.flag & FM_LEV_EVENT & fmdev->irq_info.mask) &&
+ (fmdev->rx.freq != FM_UNDEFINED_FREQ) &&
+ (fmdev->rx.stat_info.afcache_size != 0)) {
+ fmdbg("irq: rssi level has fallen below threshold level\n");
+
+ /* Disable further low RSSI interrupts */
+ fmdev->irq_info.mask &= ~FM_LEV_EVENT;
+
+ fmdev->rx.afjump_idx = 0;
+ fmdev->rx.freq_before_jump = fmdev->rx.freq;
+ fmdev->irq_info.stage = FM_AF_JUMP_SETPI_IDX;
+ } else {
+ /* Continue next function in interrupt handler table */
+ fmdev->irq_info.stage = FM_SEND_INTMSK_CMD_IDX;
+ }
+
+ fm_irq_call(fmdev);
+}
+
+static void fm_irq_afjump_set_pi(struct fmdev *fmdev)
+{
+ u16 payload;
+
+ /* Set PI code - must be updated if the AF list is not empty */
+ payload = fmdev->rx.stat_info.picode;
+ if (!fm_send_cmd(fmdev, RDS_PI_SET, REG_WR, &payload, sizeof(payload), NULL))
+ fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SETPI_RESP_IDX);
+}
+
+static void fm_irq_handle_set_pi_resp(struct fmdev *fmdev)
+{
+ fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_SETPI_MASK_IDX);
+}
+
+/*
+ * Set PI mask.
+ * 0xFFFF = Enable PI code matching
+ * 0x0000 = Disable PI code matching
+ */
+static void fm_irq_afjump_set_pimask(struct fmdev *fmdev)
+{
+ u16 payload;
+
+ payload = 0x0000;
+ if (!fm_send_cmd(fmdev, RDS_PI_MASK_SET, REG_WR, &payload, sizeof(payload), NULL))
+ fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_IDX);
+}
+
+static void fm_irq_handle_set_pimask_resp(struct fmdev *fmdev)
+{
+ fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_SET_AF_FREQ_IDX);
+}
+
+static void fm_irq_afjump_setfreq(struct fmdev *fmdev)
+{
+ u16 frq_index;
+ u16 payload;
+
+ fmdbg("Swtich to %d KHz\n", fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx]);
+ frq_index = (fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx] -
+ fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
+
+ payload = frq_index;
+ if (!fm_send_cmd(fmdev, AF_FREQ_SET, REG_WR, &payload, sizeof(payload), NULL))
+ fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SET_AFFREQ_RESP_IDX);
+}
+
+static void fm_irq_handle_setfreq_resp(struct fmdev *fmdev)
+{
+ fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_ENABLE_INT_IDX);
+}
+
+static void fm_irq_afjump_enableint(struct fmdev *fmdev)
+{
+ u16 payload;
+
+ /* Enable FR (tuning operation ended) interrupt */
+ payload = FM_FR_EVENT;
+ if (!fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, sizeof(payload), NULL))
+ fm_irq_timeout_stage(fmdev, FM_AF_JUMP_ENABLE_INT_RESP_IDX);
+}
+
+static void fm_irq_afjump_enableint_resp(struct fmdev *fmdev)
+{
+ fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_START_AFJUMP_IDX);
+}
+
+static void fm_irq_start_afjump(struct fmdev *fmdev)
+{
+ u16 payload;
+
+ payload = FM_TUNER_AF_JUMP_MODE;
+ if (!fm_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload,
+ sizeof(payload), NULL))
+ fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_IDX);
+}
+
+static void fm_irq_handle_start_afjump_resp(struct fmdev *fmdev)
+{
+ struct sk_buff *skb;
+
+ if (check_cmdresp_status(fmdev, &skb))
+ return;
+
+ fmdev->irq_info.stage = FM_SEND_FLAG_GETCMD_IDX;
+ set_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag);
+ clear_bit(FM_INTTASK_RUNNING, &fmdev->flag);
+}
+
+static void fm_irq_afjump_rd_freq(struct fmdev *fmdev)
+{
+ u16 payload;
+
+ if (!fm_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, sizeof(payload), NULL))
+ fm_irq_timeout_stage(fmdev, FM_AF_JUMP_RD_FREQ_RESP_IDX);
+}
+
+static void fm_irq_afjump_rd_freq_resp(struct fmdev *fmdev)
+{
+ struct sk_buff *skb;
+ u16 read_freq;
+ u32 curr_freq, jumped_freq;
+
+ if (check_cmdresp_status(fmdev, &skb))
+ return;
+
+ /* Skip header info and copy only response data */
+ skb_pull(skb, sizeof(struct fm_event_msg_hdr));
+ memcpy(&read_freq, skb->data, sizeof(read_freq));
+ read_freq = be16_to_cpu(read_freq);
+ curr_freq = fmdev->rx.region.bot_freq + ((u32)read_freq * FM_FREQ_MUL);
+
+ jumped_freq = fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx];
+
+ /* If the frequency was changed the jump succeeded */
+ if ((curr_freq != fmdev->rx.freq_before_jump) && (curr_freq == jumped_freq)) {
+ fmdbg("Successfully switched to alternate freq %d\n", curr_freq);
+ fmdev->rx.freq = curr_freq;
+ fm_rx_reset_rds_cache(fmdev);
+
+ /* AF feature is on, enable low level RSSI interrupt */
+ if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
+ fmdev->irq_info.mask |= FM_LEV_EVENT;
+
+ fmdev->irq_info.stage = FM_LOW_RSSI_FINISH_IDX;
+ } else { /* jump to the next freq in the AF list */
+ fmdev->rx.afjump_idx++;
+
+ /* If we reached the end of the list - stop searching */
+ if (fmdev->rx.afjump_idx >= fmdev->rx.stat_info.afcache_size) {
+ fmdbg("AF switch processing failed\n");
+ fmdev->irq_info.stage = FM_LOW_RSSI_FINISH_IDX;
+ } else { /* AF List is not over - try next one */
+
+ fmdbg("Trying next freq in AF cache\n");
+ fmdev->irq_info.stage = FM_AF_JUMP_SETPI_IDX;
+ }
+ }
+ fm_irq_call(fmdev);
+}
+
+static void fm_irq_handle_low_rssi_finish(struct fmdev *fmdev)
+{
+ fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX);
+}
+
+static void fm_irq_send_intmsk_cmd(struct fmdev *fmdev)
+{
+ u16 payload;
+
+ /* Re-enable FM interrupts */
+ payload = fmdev->irq_info.mask;
+
+ if (!fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL))
+ fm_irq_timeout_stage(fmdev, FM_HANDLE_INTMSK_CMD_RESP_IDX);
+}
+
+static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *fmdev)
+{
+ struct sk_buff *skb;
+
+ if (check_cmdresp_status(fmdev, &skb))
+ return;
+ /*
+ * This is last function in interrupt table to be executed.
+ * So, reset stage index to 0.
+ */
+ fmdev->irq_info.stage = FM_SEND_FLAG_GETCMD_IDX;
+
+ /* Start processing any pending interrupt */
+ if (test_and_clear_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag))
+ fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev);
+ else
+ clear_bit(FM_INTTASK_RUNNING, &fmdev->flag);
+}
+
+/* Returns availability of RDS data in internel buffer */
+u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file,
+ struct poll_table_struct *pts)
+{
+ poll_wait(file, &fmdev->rx.rds.read_queue, pts);
+ if (fmdev->rx.rds.rd_idx != fmdev->rx.rds.wr_idx)
+ return 0;
+
+ return -EAGAIN;
+}
+
+/* Copies RDS data from internal buffer to user buffer */
+u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file,
+ u8 __user *buf, size_t count)
+{
+ u32 block_count;
+ unsigned long flags;
+ int ret;
+
+ if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+
+ ret = wait_event_interruptible(fmdev->rx.rds.read_queue,
+ (fmdev->rx.rds.wr_idx != fmdev->rx.rds.rd_idx));
+ if (ret)
+ return -EINTR;
+ }
+
+ /* Calculate block count from byte count */
+ count /= 3;
+ block_count = 0;
+ ret = 0;
+
+ spin_lock_irqsave(&fmdev->rds_buff_lock, flags);
+
+ while (block_count < count) {
+ if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx)
+ break;
+
+ if (copy_to_user(buf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx],
+ FM_RDS_BLK_SIZE))
+ break;
+
+ fmdev->rx.rds.rd_idx += FM_RDS_BLK_SIZE;
+ if (fmdev->rx.rds.rd_idx >= fmdev->rx.rds.buf_size)
+ fmdev->rx.rds.rd_idx = 0;
+
+ block_count++;
+ buf += FM_RDS_BLK_SIZE;
+ ret += FM_RDS_BLK_SIZE;
+ }
+ spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags);
+ return ret;
+}
+
+u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set)
+{
+ switch (fmdev->curr_fmmode) {
+ case FM_MODE_RX:
+ return fm_rx_set_freq(fmdev, freq_to_set);
+
+ case FM_MODE_TX:
+ return fm_tx_set_freq(fmdev, freq_to_set);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq)
+{
+ if (fmdev->rx.freq == FM_UNDEFINED_FREQ) {
+ fmerr("RX frequency is not set\n");
+ return -EPERM;
+ }
+ if (cur_tuned_frq == NULL) {
+ fmerr("Invalid memory\n");
+ return -ENOMEM;
+ }
+
+ switch (fmdev->curr_fmmode) {
+ case FM_MODE_RX:
+ *cur_tuned_frq = fmdev->rx.freq;
+ return 0;
+
+ case FM_MODE_TX:
+ *cur_tuned_frq = 0; /* TODO : Change this later */
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+
+}
+
+u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set)
+{
+ switch (fmdev->curr_fmmode) {
+ case FM_MODE_RX:
+ return fm_rx_set_region(fmdev, region_to_set);
+
+ case FM_MODE_TX:
+ return fm_tx_set_region(fmdev, region_to_set);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
+{
+ switch (fmdev->curr_fmmode) {
+ case FM_MODE_RX:
+ return fm_rx_set_mute_mode(fmdev, mute_mode_toset);
+
+ case FM_MODE_TX:
+ return fm_tx_set_mute_mode(fmdev, mute_mode_toset);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode)
+{
+ switch (fmdev->curr_fmmode) {
+ case FM_MODE_RX:
+ return fm_rx_set_stereo_mono(fmdev, mode);
+
+ case FM_MODE_TX:
+ return fm_tx_set_stereo_mono(fmdev, mode);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
+{
+ switch (fmdev->curr_fmmode) {
+ case FM_MODE_RX:
+ return fm_rx_set_rds_mode(fmdev, rds_en_dis);
+
+ case FM_MODE_TX:
+ return fm_tx_set_rds_mode(fmdev, rds_en_dis);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+/* Sends power off command to the chip */
+static u32 fm_power_down(struct fmdev *fmdev)
+{
+ u16 payload;
+ u32 ret;
+
+ if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+ fmerr("FM core is not ready\n");
+ return -EPERM;
+ }
+ if (fmdev->curr_fmmode == FM_MODE_OFF) {
+ fmdbg("FM chip is already in OFF state\n");
+ return 0;
+ }
+
+ payload = 0x0;
+ ret = fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ return fmc_release(fmdev);
+}
+
+/* Reads init command from FM firmware file and loads to the chip */
+static u32 fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name)
+{
+ const struct firmware *fw_entry;
+ struct bts_header *fw_header;
+ struct bts_action *action;
+ struct bts_action_delay *delay;
+ u8 *fw_data;
+ int ret, fw_len, cmd_cnt;
+
+ cmd_cnt = 0;
+ set_bit(FM_FW_DW_INPROGRESS, &fmdev->flag);
+
+ ret = request_firmware(&fw_entry, fw_name,
+ &fmdev->radio_dev->dev);
+ if (ret < 0) {
+ fmerr("Unable to read firmware(%s) content\n", fw_name);
+ return ret;
+ }
+ fmdbg("Firmware(%s) length : %d bytes\n", fw_name, fw_entry->size);
+
+ fw_data = (void *)fw_entry->data;
+ fw_len = fw_entry->size;
+
+ fw_header = (struct bts_header *)fw_data;
+ if (fw_header->magic != FM_FW_FILE_HEADER_MAGIC) {
+ fmerr("%s not a legal TI firmware file\n", fw_name);
+ ret = -EINVAL;
+ goto rel_fw;
+ }
+ fmdbg("FW(%s) magic number : 0x%x\n", fw_name, fw_header->magic);
+
+ /* Skip file header info , we already verified it */
+ fw_data += sizeof(struct bts_header);
+ fw_len -= sizeof(struct bts_header);
+
+ while (fw_data && fw_len > 0) {
+ action = (struct bts_action *)fw_data;
+
+ switch (action->type) {
+ case ACTION_SEND_COMMAND: /* Send */
+ if (fmc_send_cmd(fmdev, 0, 0, action->data,
+ action->size, NULL, NULL))
+ goto rel_fw;
+
+ cmd_cnt++;
+ break;
+
+ case ACTION_DELAY: /* Delay */
+ delay = (struct bts_action_delay *)action->data;
+ mdelay(delay->msec);
+ break;
+ }
+
+ fw_data += (sizeof(struct bts_action) + (action->size));
+ fw_len -= (sizeof(struct bts_action) + (action->size));
+ }
+ fmdbg("Firmware commands(%d) loaded to chip\n", cmd_cnt);
+rel_fw:
+ release_firmware(fw_entry);
+ clear_bit(FM_FW_DW_INPROGRESS, &fmdev->flag);
+
+ return ret;
+}
+
+/* Loads default RX configuration to the chip */
+static u32 load_default_rx_configuration(struct fmdev *fmdev)
+{
+ int ret;
+
+ ret = fm_rx_set_volume(fmdev, FM_DEFAULT_RX_VOLUME);
+ if (ret < 0)
+ return ret;
+
+ return fm_rx_set_rssi_threshold(fmdev, FM_DEFAULT_RSSI_THRESHOLD);
+}
+
+/* Does FM power on sequence */
+static u32 fm_power_up(struct fmdev *fmdev, u8 mode)
+{
+ u16 payload, asic_id, asic_ver;
+ int resp_len, ret;
+ u8 fw_name[50];
+
+ if (mode >= FM_MODE_ENTRY_MAX) {
+ fmerr("Invalid firmware download option\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Initialize FM common module. FM GPIO toggling is
+ * taken care in Shared Transport driver.
+ */
+ ret = fmc_prepare(fmdev);
+ if (ret < 0) {
+ fmerr("Unable to prepare FM Common\n");
+ return ret;
+ }
+
+ payload = FM_ENABLE;
+ if (fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload,
+ sizeof(payload), NULL, NULL))
+ goto rel;
+
+ /* Allow the chip to settle down in Channel-8 mode */
+ msleep(20);
+
+ if (fmc_send_cmd(fmdev, ASIC_ID_GET, REG_RD, NULL,
+ sizeof(asic_id), &asic_id, &resp_len))
+ goto rel;
+
+ if (fmc_send_cmd(fmdev, ASIC_VER_GET, REG_RD, NULL,
+ sizeof(asic_ver), &asic_ver, &resp_len))
+ goto rel;
+
+ fmdbg("ASIC ID: 0x%x , ASIC Version: %d\n",
+ be16_to_cpu(asic_id), be16_to_cpu(asic_ver));
+
+ sprintf(fw_name, "%s_%x.%d.bts", FM_FMC_FW_FILE_START,
+ be16_to_cpu(asic_id), be16_to_cpu(asic_ver));
+
+ ret = fm_download_firmware(fmdev, fw_name);
+ if (ret < 0) {
+ fmdbg("Failed to download firmware file %s\n", fw_name);
+ goto rel;
+ }
+ sprintf(fw_name, "%s_%x.%d.bts", (mode == FM_MODE_RX) ?
+ FM_RX_FW_FILE_START : FM_TX_FW_FILE_START,
+ be16_to_cpu(asic_id), be16_to_cpu(asic_ver));
+
+ ret = fm_download_firmware(fmdev, fw_name);
+ if (ret < 0) {
+ fmdbg("Failed to download firmware file %s\n", fw_name);
+ goto rel;
+ } else
+ return ret;
+rel:
+ return fmc_release(fmdev);
+}
+
+/* Set FM Modes(TX, RX, OFF) */
+u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode)
+{
+ int ret = 0;
+
+ if (fm_mode >= FM_MODE_ENTRY_MAX) {
+ fmerr("Invalid FM mode\n");
+ return -EINVAL;
+ }
+ if (fmdev->curr_fmmode == fm_mode) {
+ fmdbg("Already fm is in mode(%d)\n", fm_mode);
+ return ret;
+ }
+
+ switch (fm_mode) {
+ case FM_MODE_OFF: /* OFF Mode */
+ ret = fm_power_down(fmdev);
+ if (ret < 0) {
+ fmerr("Failed to set OFF mode\n");
+ return ret;
+ }
+ break;
+
+ case FM_MODE_TX: /* TX Mode */
+ case FM_MODE_RX: /* RX Mode */
+ /* Power down before switching to TX or RX mode */
+ if (fmdev->curr_fmmode != FM_MODE_OFF) {
+ ret = fm_power_down(fmdev);
+ if (ret < 0) {
+ fmerr("Failed to set OFF mode\n");
+ return ret;
+ }
+ msleep(30);
+ }
+ ret = fm_power_up(fmdev, fm_mode);
+ if (ret < 0) {
+ fmerr("Failed to load firmware\n");
+ return ret;
+ }
+ }
+ fmdev->curr_fmmode = fm_mode;
+
+ /* Set default configuration */
+ if (fmdev->curr_fmmode == FM_MODE_RX) {
+ fmdbg("Loading default rx configuration..\n");
+ ret = load_default_rx_configuration(fmdev);
+ if (ret < 0)
+ fmerr("Failed to load default values\n");
+ }
+
+ return ret;
+}
+
+/* Returns current FM mode (TX, RX, OFF) */
+u32 fmc_get_mode(struct fmdev *fmdev, u8 *fmmode)
+{
+ if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+ fmerr("FM core is not ready\n");
+ return -EPERM;
+ }
+ if (fmmode == NULL) {
+ fmerr("Invalid memory\n");
+ return -ENOMEM;
+ }
+
+ *fmmode = fmdev->curr_fmmode;
+ return 0;
+}
+
+/* Called by ST layer when FM packet is available */
+static long fm_st_receive(void *arg, struct sk_buff *skb)
+{
+ struct fmdev *fmdev;
+
+ fmdev = (struct fmdev *)arg;
+
+ if (skb == NULL) {
+ fmerr("Invalid SKB received from ST\n");
+ return -EFAULT;
+ }
+
+ if (skb->cb[0] != FM_PKT_LOGICAL_CHAN_NUMBER) {
+ fmerr("Received SKB (%p) is not FM Channel 8 pkt\n", skb);
+ return -EINVAL;
+ }
+
+ memcpy(skb_push(skb, 1), &skb->cb[0], 1);
+ skb_queue_tail(&fmdev->rx_q, skb);
+ tasklet_schedule(&fmdev->rx_task);
+
+ return 0;
+}
+
+/*
+ * Called by ST layer to indicate protocol registration completion
+ * status.
+ */
+static void fm_st_reg_comp_cb(void *arg, char data)
+{
+ struct fmdev *fmdev;
+
+ fmdev = (struct fmdev *)arg;
+ fmdev->streg_cbdata = data;
+ complete(&wait_for_fmdrv_reg_comp);
+}
+
+/*
+ * This function will be called from FM V4L2 open function.
+ * Register with ST driver and initialize driver data.
+ */
+u32 fmc_prepare(struct fmdev *fmdev)
+{
+ static struct st_proto_s fm_st_proto;
+ u32 ret;
+
+ if (test_bit(FM_CORE_READY, &fmdev->flag)) {
+ fmdbg("FM Core is already up\n");
+ return 0;
+ }
+
+ memset(&fm_st_proto, 0, sizeof(fm_st_proto));
+ fm_st_proto.type = ST_FM;
+ fm_st_proto.recv = fm_st_receive;
+ fm_st_proto.match_packet = NULL;
+ fm_st_proto.reg_complete_cb = fm_st_reg_comp_cb;
+ fm_st_proto.write = NULL; /* TI ST driver will fill write pointer */
+ fm_st_proto.priv_data = fmdev;
+ fm_st_proto.chnl_id = 0x08;
+ fm_st_proto.max_frame_size = 0xff;
+ fm_st_proto.hdr_len = 1;
+ fm_st_proto.offset_len_in_hdr = 0;
+ fm_st_proto.len_size = 1;
+ fm_st_proto.reserve = 1;
+
+ ret = st_register(&fm_st_proto);
+ if (ret == -EINPROGRESS) {
+ init_completion(&wait_for_fmdrv_reg_comp);
+ fmdev->streg_cbdata = -EINPROGRESS;
+ fmdbg("%s waiting for ST reg completion signal\n", __func__);
+
+ ret = wait_for_completion_timeout(&wait_for_fmdrv_reg_comp,
+ FM_ST_REG_TIMEOUT);
+
+ if (!ret) {
+ fmerr("Timeout(%d sec), didn't get reg "
+ "completion signal from ST\n",
+ jiffies_to_msecs(FM_ST_REG_TIMEOUT) / 1000);
+ return -ETIMEDOUT;
+ }
+ if (fmdev->streg_cbdata != 0) {
+ fmerr("ST reg comp CB called with error "
+ "status %d\n", fmdev->streg_cbdata);
+ return -EAGAIN;
+ }
+
+ ret = 0;
+ } else if (ret == -1) {
+ fmerr("st_register failed %d\n", ret);
+ return -EAGAIN;
+ }
+
+ if (fm_st_proto.write != NULL) {
+ g_st_write = fm_st_proto.write;
+ } else {
+ fmerr("Failed to get ST write func pointer\n");
+ ret = st_unregister(&fm_st_proto);
+ if (ret < 0)
+ fmerr("st_unregister failed %d\n", ret);
+ return -EAGAIN;
+ }
+
+ spin_lock_init(&fmdev->rds_buff_lock);
+ spin_lock_init(&fmdev->resp_skb_lock);
+
+ /* Initialize TX queue and TX tasklet */
+ skb_queue_head_init(&fmdev->tx_q);
+ tasklet_init(&fmdev->tx_task, send_tasklet, (unsigned long)fmdev);
+
+ /* Initialize RX Queue and RX tasklet */
+ skb_queue_head_init(&fmdev->rx_q);
+ tasklet_init(&fmdev->rx_task, recv_tasklet, (unsigned long)fmdev);
+
+ fmdev->irq_info.stage = 0;
+ atomic_set(&fmdev->tx_cnt, 1);
+ fmdev->resp_comp = NULL;
+
+ init_timer(&fmdev->irq_info.timer);
+ fmdev->irq_info.timer.function = &int_timeout_handler;
+ fmdev->irq_info.timer.data = (unsigned long)fmdev;
+ /*TODO: add FM_STIC_EVENT later */
+ fmdev->irq_info.mask = FM_MAL_EVENT;
+
+ /* Region info */
+ memcpy(&fmdev->rx.region, &region_configs[default_radio_region],
+ sizeof(struct region_info));
+
+ fmdev->rx.mute_mode = FM_MUTE_OFF;
+ fmdev->rx.rf_depend_mute = FM_RX_RF_DEPENDENT_MUTE_OFF;
+ fmdev->rx.rds.flag = FM_RDS_DISABLE;
+ fmdev->rx.freq = FM_UNDEFINED_FREQ;
+ fmdev->rx.rds_mode = FM_RDS_SYSTEM_RDS;
+ fmdev->rx.af_mode = FM_RX_RDS_AF_SWITCH_MODE_OFF;
+ fmdev->irq_info.retry = 0;
+
+ fm_rx_reset_rds_cache(fmdev);
+ init_waitqueue_head(&fmdev->rx.rds.read_queue);
+
+ fm_rx_reset_station_info(fmdev);
+ set_bit(FM_CORE_READY, &fmdev->flag);
+
+ return ret;
+}
+
+/*
+ * This function will be called from FM V4L2 release function.
+ * Unregister from ST driver.
+ */
+u32 fmc_release(struct fmdev *fmdev)
+{
+ static struct st_proto_s fm_st_proto;
+ u32 ret;
+
+ if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+ fmdbg("FM Core is already down\n");
+ return 0;
+ }
+ /* Sevice pending read */
+ wake_up_interruptible(&fmdev->rx.rds.read_queue);
+
+ tasklet_kill(&fmdev->tx_task);
+ tasklet_kill(&fmdev->rx_task);
+
+ skb_queue_purge(&fmdev->tx_q);
+ skb_queue_purge(&fmdev->rx_q);
+
+ fmdev->resp_comp = NULL;
+ fmdev->rx.freq = 0;
+
+ memset(&fm_st_proto, 0, sizeof(fm_st_proto));
+ fm_st_proto.chnl_id = 0x08;
+
+ ret = st_unregister(&fm_st_proto);
+
+ if (ret < 0)
+ fmerr("Failed to de-register FM from ST %d\n", ret);
+ else
+ fmdbg("Successfully unregistered from ST\n");
+
+ clear_bit(FM_CORE_READY, &fmdev->flag);
+ return ret;
+}
+
+/*
+ * Module init function. Ask FM V4L module to register video device.
+ * Allocate memory for FM driver context and RX RDS buffer.
+ */
+static int __init fm_drv_init(void)
+{
+ struct fmdev *fmdev = NULL;
+ u32 ret = -ENOMEM;
+
+ fmdbg("FM driver version %s\n", FM_DRV_VERSION);
+
+ fmdev = kzalloc(sizeof(struct fmdev), GFP_KERNEL);
+ if (NULL == fmdev) {
+ fmerr("Can't allocate operation structure memory\n");
+ return ret;
+ }
+ fmdev->rx.rds.buf_size = default_rds_buf * FM_RDS_BLK_SIZE;
+ fmdev->rx.rds.buff = kzalloc(fmdev->rx.rds.buf_size, GFP_KERNEL);
+ if (NULL == fmdev->rx.rds.buff) {
+ fmerr("Can't allocate rds ring buffer\n");
+ goto rel_dev;
+ }
+
+ ret = fm_v4l2_init_video_device(fmdev, radio_nr);
+ if (ret < 0)
+ goto rel_rdsbuf;
+
+ fmdev->irq_info.handlers = int_handler_table;
+ fmdev->curr_fmmode = FM_MODE_OFF;
+ fmdev->tx_data.pwr_lvl = FM_PWR_LVL_DEF;
+ fmdev->tx_data.preemph = FM_TX_PREEMPH_50US;
+ return ret;
+
+rel_rdsbuf:
+ kfree(fmdev->rx.rds.buff);
+rel_dev:
+ kfree(fmdev);
+
+ return ret;
+}
+
+/* Module exit function. Ask FM V4L module to unregister video device */
+static void __exit fm_drv_exit(void)
+{
+ struct fmdev *fmdev = NULL;
+
+ fmdev = fm_v4l2_deinit_video_device();
+ if (fmdev != NULL) {
+ kfree(fmdev->rx.rds.buff);
+ kfree(fmdev);
+ }
+}
+
+module_init(fm_drv_init);
+module_exit(fm_drv_exit);
+
+/* ------------- Module Info ------------- */
+MODULE_AUTHOR("Manjunatha Halli <manjunatha_halli@ti.com>");
+MODULE_DESCRIPTION("FM Driver for TI's Connectivity chip. " FM_DRV_VERSION);
+MODULE_VERSION(FM_DRV_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/radio/wl128x/fmdrv_common.h b/drivers/media/radio/wl128x/fmdrv_common.h
new file mode 100644
index 00000000000..725af7e66e1
--- /dev/null
+++ b/drivers/media/radio/wl128x/fmdrv_common.h
@@ -0,0 +1,402 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ * FM Common module header file
+ *
+ * Copyright (C) 2011 Texas Instruments
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _FMDRV_COMMON_H
+#define _FMDRV_COMMON_H
+
+#define FM_ST_REG_TIMEOUT msecs_to_jiffies(16000) /* 16 sec */
+#define FM_PKT_LOGICAL_CHAN_NUMBER 0x08 /* Logical channel 8 */
+
+#define REG_RD 0x1
+#define REG_WR 0x0
+
+struct fm_reg_table {
+ u8 opcode;
+ u8 type;
+ u8 *name;
+};
+
+#define STEREO_GET 0
+#define RSSI_LVL_GET 1
+#define IF_COUNT_GET 2
+#define FLAG_GET 3
+#define RDS_SYNC_GET 4
+#define RDS_DATA_GET 5
+#define FREQ_SET 10
+#define AF_FREQ_SET 11
+#define MOST_MODE_SET 12
+#define MOST_BLEND_SET 13
+#define DEMPH_MODE_SET 14
+#define SEARCH_LVL_SET 15
+#define BAND_SET 16
+#define MUTE_STATUS_SET 17
+#define RDS_PAUSE_LVL_SET 18
+#define RDS_PAUSE_DUR_SET 19
+#define RDS_MEM_SET 20
+#define RDS_BLK_B_SET 21
+#define RDS_MSK_B_SET 22
+#define RDS_PI_MASK_SET 23
+#define RDS_PI_SET 24
+#define RDS_SYSTEM_SET 25
+#define INT_MASK_SET 26
+#define SEARCH_DIR_SET 27
+#define VOLUME_SET 28
+#define AUDIO_ENABLE_SET 29
+#define PCM_MODE_SET 30
+#define I2S_MODE_CONFIG_SET 31
+#define POWER_SET 32
+#define INTX_CONFIG_SET 33
+#define PULL_EN_SET 34
+#define HILO_SET 35
+#define SWITCH2FREF 36
+#define FREQ_DRIFT_REPORT 37
+
+#define PCE_GET 40
+#define FIRM_VER_GET 41
+#define ASIC_VER_GET 42
+#define ASIC_ID_GET 43
+#define MAN_ID_GET 44
+#define TUNER_MODE_SET 45
+#define STOP_SEARCH 46
+#define RDS_CNTRL_SET 47
+
+#define WRITE_HARDWARE_REG 100
+#define CODE_DOWNLOAD 101
+#define RESET 102
+
+#define FM_POWER_MODE 254
+#define FM_INTERRUPT 255
+
+/* Transmitter API */
+
+#define CHANL_SET 55
+#define CHANL_BW_SET 56
+#define REF_SET 57
+#define POWER_ENB_SET 90
+#define POWER_ATT_SET 58
+#define POWER_LEV_SET 59
+#define AUDIO_DEV_SET 60
+#define PILOT_DEV_SET 61
+#define RDS_DEV_SET 62
+#define TX_BAND_SET 65
+#define PUPD_SET 91
+#define AUDIO_IO_SET 63
+#define PREMPH_SET 64
+#define MONO_SET 66
+#define MUTE 92
+#define MPX_LMT_ENABLE 67
+#define PI_SET 93
+#define ECC_SET 69
+#define PTY 70
+#define AF 71
+#define DISPLAY_MODE 74
+#define RDS_REP_SET 77
+#define RDS_CONFIG_DATA_SET 98
+#define RDS_DATA_SET 99
+#define RDS_DATA_ENB 94
+#define TA_SET 78
+#define TP_SET 79
+#define DI_SET 80
+#define MS_SET 81
+#define PS_SCROLL_SPEED 82
+#define TX_AUDIO_LEVEL_TEST 96
+#define TX_AUDIO_LEVEL_TEST_THRESHOLD 73
+#define TX_AUDIO_INPUT_LEVEL_RANGE_SET 54
+#define RX_ANTENNA_SELECT 87
+#define I2C_DEV_ADDR_SET 86
+#define REF_ERR_CALIB_PARAM_SET 88
+#define REF_ERR_CALIB_PERIODICITY_SET 89
+#define SOC_INT_TRIGGER 52
+#define SOC_AUDIO_PATH_SET 83
+#define SOC_PCMI_OVERRIDE 84
+#define SOC_I2S_OVERRIDE 85
+#define RSSI_BLOCK_SCAN_FREQ_SET 95
+#define RSSI_BLOCK_SCAN_START 97
+#define RSSI_BLOCK_SCAN_DATA_GET 5
+#define READ_FMANT_TUNE_VALUE 104
+
+/* SKB helpers */
+struct fm_skb_cb {
+ __u8 fm_op;
+ struct completion *completion;
+};
+
+#define fm_cb(skb) ((struct fm_skb_cb *)(skb->cb))
+
+/* FM Channel-8 command message format */
+struct fm_cmd_msg_hdr {
+ __u8 hdr; /* Logical Channel-8 */
+ __u8 len; /* Number of bytes follows */
+ __u8 op; /* FM Opcode */
+ __u8 rd_wr; /* Read/Write command */
+ __u8 dlen; /* Length of payload */
+} __attribute__ ((packed));
+
+#define FM_CMD_MSG_HDR_SIZE 5 /* sizeof(struct fm_cmd_msg_hdr) */
+
+/* FM Channel-8 event messgage format */
+struct fm_event_msg_hdr {
+ __u8 header; /* Logical Channel-8 */
+ __u8 len; /* Number of bytes follows */
+ __u8 status; /* Event status */
+ __u8 num_fm_hci_cmds; /* Number of pkts the host allowed to send */
+ __u8 op; /* FM Opcode */
+ __u8 rd_wr; /* Read/Write command */
+ __u8 dlen; /* Length of payload */
+} __attribute__ ((packed));
+
+#define FM_EVT_MSG_HDR_SIZE 7 /* sizeof(struct fm_event_msg_hdr) */
+
+/* TI's magic number in firmware file */
+#define FM_FW_FILE_HEADER_MAGIC 0x42535442
+
+#define FM_ENABLE 1
+#define FM_DISABLE 0
+
+/* FLAG_GET register bits */
+#define FM_FR_EVENT (1 << 0)
+#define FM_BL_EVENT (1 << 1)
+#define FM_RDS_EVENT (1 << 2)
+#define FM_BBLK_EVENT (1 << 3)
+#define FM_LSYNC_EVENT (1 << 4)
+#define FM_LEV_EVENT (1 << 5)
+#define FM_IFFR_EVENT (1 << 6)
+#define FM_PI_EVENT (1 << 7)
+#define FM_PD_EVENT (1 << 8)
+#define FM_STIC_EVENT (1 << 9)
+#define FM_MAL_EVENT (1 << 10)
+#define FM_POW_ENB_EVENT (1 << 11)
+
+/*
+ * Firmware files of FM. ASIC ID and ASIC version will be appened to this,
+ * later.
+ */
+#define FM_FMC_FW_FILE_START ("fmc_ch8")
+#define FM_RX_FW_FILE_START ("fm_rx_ch8")
+#define FM_TX_FW_FILE_START ("fm_tx_ch8")
+
+#define FM_UNDEFINED_FREQ 0xFFFFFFFF
+
+/* Band types */
+#define FM_BAND_EUROPE_US 0
+#define FM_BAND_JAPAN 1
+
+/* Seek directions */
+#define FM_SEARCH_DIRECTION_DOWN 0
+#define FM_SEARCH_DIRECTION_UP 1
+
+/* Tunner modes */
+#define FM_TUNER_STOP_SEARCH_MODE 0
+#define FM_TUNER_PRESET_MODE 1
+#define FM_TUNER_AUTONOMOUS_SEARCH_MODE 2
+#define FM_TUNER_AF_JUMP_MODE 3
+
+/* Min and Max volume */
+#define FM_RX_VOLUME_MIN 0
+#define FM_RX_VOLUME_MAX 70
+
+/* Volume gain step */
+#define FM_RX_VOLUME_GAIN_STEP 0x370
+
+/* Mute modes */
+#define FM_MUTE_ON 0
+#define FM_MUTE_OFF 1
+#define FM_MUTE_ATTENUATE 2
+
+#define FM_RX_UNMUTE_MODE 0x00
+#define FM_RX_RF_DEP_MODE 0x01
+#define FM_RX_AC_MUTE_MODE 0x02
+#define FM_RX_HARD_MUTE_LEFT_MODE 0x04
+#define FM_RX_HARD_MUTE_RIGHT_MODE 0x08
+#define FM_RX_SOFT_MUTE_FORCE_MODE 0x10
+
+/* RF dependent mute mode */
+#define FM_RX_RF_DEPENDENT_MUTE_ON 1
+#define FM_RX_RF_DEPENDENT_MUTE_OFF 0
+
+/* RSSI threshold min and max */
+#define FM_RX_RSSI_THRESHOLD_MIN -128
+#define FM_RX_RSSI_THRESHOLD_MAX 127
+
+/* Stereo/Mono mode */
+#define FM_STEREO_MODE 0
+#define FM_MONO_MODE 1
+#define FM_STEREO_SOFT_BLEND 1
+
+/* FM RX De-emphasis filter modes */
+#define FM_RX_EMPHASIS_FILTER_50_USEC 0
+#define FM_RX_EMPHASIS_FILTER_75_USEC 1
+
+/* FM RDS modes */
+#define FM_RDS_DISABLE 0
+#define FM_RDS_ENABLE 1
+
+#define FM_NO_PI_CODE 0
+
+/* FM and RX RDS block enable/disable */
+#define FM_RX_PWR_SET_FM_ON_RDS_OFF 0x1
+#define FM_RX_PWR_SET_FM_AND_RDS_BLK_ON 0x3
+#define FM_RX_PWR_SET_FM_AND_RDS_BLK_OFF 0x0
+
+/* RX RDS */
+#define FM_RX_RDS_FLUSH_FIFO 0x1
+#define FM_RX_RDS_FIFO_THRESHOLD 64 /* tuples */
+#define FM_RDS_BLK_SIZE 3 /* 3 bytes */
+
+/* RDS block types */
+#define FM_RDS_BLOCK_A 0
+#define FM_RDS_BLOCK_B 1
+#define FM_RDS_BLOCK_C 2
+#define FM_RDS_BLOCK_Ctag 3
+#define FM_RDS_BLOCK_D 4
+#define FM_RDS_BLOCK_E 5
+
+#define FM_RDS_BLK_IDX_A 0
+#define FM_RDS_BLK_IDX_B 1
+#define FM_RDS_BLK_IDX_C 2
+#define FM_RDS_BLK_IDX_D 3
+#define FM_RDS_BLK_IDX_UNKNOWN 0xF0
+
+#define FM_RDS_STATUS_ERR_MASK 0x18
+
+/*
+ * Represents an RDS group type & version.
+ * There are 15 groups, each group has 2 versions: A and B.
+ */
+#define FM_RDS_GROUP_TYPE_MASK_0A ((unsigned long)1<<0)
+#define FM_RDS_GROUP_TYPE_MASK_0B ((unsigned long)1<<1)
+#define FM_RDS_GROUP_TYPE_MASK_1A ((unsigned long)1<<2)
+#define FM_RDS_GROUP_TYPE_MASK_1B ((unsigned long)1<<3)
+#define FM_RDS_GROUP_TYPE_MASK_2A ((unsigned long)1<<4)
+#define FM_RDS_GROUP_TYPE_MASK_2B ((unsigned long)1<<5)
+#define FM_RDS_GROUP_TYPE_MASK_3A ((unsigned long)1<<6)
+#define FM_RDS_GROUP_TYPE_MASK_3B ((unsigned long)1<<7)
+#define FM_RDS_GROUP_TYPE_MASK_4A ((unsigned long)1<<8)
+#define FM_RDS_GROUP_TYPE_MASK_4B ((unsigned long)1<<9)
+#define FM_RDS_GROUP_TYPE_MASK_5A ((unsigned long)1<<10)
+#define FM_RDS_GROUP_TYPE_MASK_5B ((unsigned long)1<<11)
+#define FM_RDS_GROUP_TYPE_MASK_6A ((unsigned long)1<<12)
+#define FM_RDS_GROUP_TYPE_MASK_6B ((unsigned long)1<<13)
+#define FM_RDS_GROUP_TYPE_MASK_7A ((unsigned long)1<<14)
+#define FM_RDS_GROUP_TYPE_MASK_7B ((unsigned long)1<<15)
+#define FM_RDS_GROUP_TYPE_MASK_8A ((unsigned long)1<<16)
+#define FM_RDS_GROUP_TYPE_MASK_8B ((unsigned long)1<<17)
+#define FM_RDS_GROUP_TYPE_MASK_9A ((unsigned long)1<<18)
+#define FM_RDS_GROUP_TYPE_MASK_9B ((unsigned long)1<<19)
+#define FM_RDS_GROUP_TYPE_MASK_10A ((unsigned long)1<<20)
+#define FM_RDS_GROUP_TYPE_MASK_10B ((unsigned long)1<<21)
+#define FM_RDS_GROUP_TYPE_MASK_11A ((unsigned long)1<<22)
+#define FM_RDS_GROUP_TYPE_MASK_11B ((unsigned long)1<<23)
+#define FM_RDS_GROUP_TYPE_MASK_12A ((unsigned long)1<<24)
+#define FM_RDS_GROUP_TYPE_MASK_12B ((unsigned long)1<<25)
+#define FM_RDS_GROUP_TYPE_MASK_13A ((unsigned long)1<<26)
+#define FM_RDS_GROUP_TYPE_MASK_13B ((unsigned long)1<<27)
+#define FM_RDS_GROUP_TYPE_MASK_14A ((unsigned long)1<<28)
+#define FM_RDS_GROUP_TYPE_MASK_14B ((unsigned long)1<<29)
+#define FM_RDS_GROUP_TYPE_MASK_15A ((unsigned long)1<<30)
+#define FM_RDS_GROUP_TYPE_MASK_15B ((unsigned long)1<<31)
+
+/* RX Alternate Frequency info */
+#define FM_RDS_MIN_AF 1
+#define FM_RDS_MAX_AF 204
+#define FM_RDS_MAX_AF_JAPAN 140
+#define FM_RDS_1_AF_FOLLOWS 225
+#define FM_RDS_25_AF_FOLLOWS 249
+
+/* RDS system type (RDS/RBDS) */
+#define FM_RDS_SYSTEM_RDS 0
+#define FM_RDS_SYSTEM_RBDS 1
+
+/* AF on/off */
+#define FM_RX_RDS_AF_SWITCH_MODE_ON 1
+#define FM_RX_RDS_AF_SWITCH_MODE_OFF 0
+
+/* Retry count when interrupt process goes wrong */
+#define FM_IRQ_TIMEOUT_RETRY_MAX 5 /* 5 times */
+
+/* Audio IO set values */
+#define FM_RX_AUDIO_ENABLE_I2S 0x01
+#define FM_RX_AUDIO_ENABLE_ANALOG 0x02
+#define FM_RX_AUDIO_ENABLE_I2S_AND_ANALOG 0x03
+#define FM_RX_AUDIO_ENABLE_DISABLE 0x00
+
+/* HI/LO set values */
+#define FM_RX_IFFREQ_TO_HI_SIDE 0x0
+#define FM_RX_IFFREQ_TO_LO_SIDE 0x1
+#define FM_RX_IFFREQ_HILO_AUTOMATIC 0x2
+
+/*
+ * Default RX mode configuration. Chip will be configured
+ * with this default values after loading RX firmware.
+ */
+#define FM_DEFAULT_RX_VOLUME 10
+#define FM_DEFAULT_RSSI_THRESHOLD 3
+
+/* Range for TX power level in units for dB/uV */
+#define FM_PWR_LVL_LOW 91
+#define FM_PWR_LVL_HIGH 122
+
+/* Chip specific default TX power level value */
+#define FM_PWR_LVL_DEF 4
+
+/* FM TX Pre-emphasis filter values */
+#define FM_TX_PREEMPH_OFF 1
+#define FM_TX_PREEMPH_50US 0
+#define FM_TX_PREEMPH_75US 2
+
+/* FM TX antenna impedence values */
+#define FM_TX_ANT_IMP_50 0
+#define FM_TX_ANT_IMP_200 1
+#define FM_TX_ANT_IMP_500 2
+
+/* Functions exported by FM common sub-module */
+u32 fmc_prepare(struct fmdev *);
+u32 fmc_release(struct fmdev *);
+
+void fmc_update_region_info(struct fmdev *, u8);
+u32 fmc_send_cmd(struct fmdev *, u8, u16,
+ void *, unsigned int, void *, int *);
+u32 fmc_is_rds_data_available(struct fmdev *, struct file *,
+ struct poll_table_struct *);
+u32 fmc_transfer_rds_from_internal_buff(struct fmdev *, struct file *,
+ u8 __user *, size_t);
+
+u32 fmc_set_freq(struct fmdev *, u32);
+u32 fmc_set_mode(struct fmdev *, u8);
+u32 fmc_set_region(struct fmdev *, u8);
+u32 fmc_set_mute_mode(struct fmdev *, u8);
+u32 fmc_set_stereo_mono(struct fmdev *, u16);
+u32 fmc_set_rds_mode(struct fmdev *, u8);
+
+u32 fmc_get_freq(struct fmdev *, u32 *);
+u32 fmc_get_region(struct fmdev *, u8 *);
+u32 fmc_get_mode(struct fmdev *, u8 *);
+
+/*
+ * channel spacing
+ */
+#define FM_CHANNEL_SPACING_50KHZ 1
+#define FM_CHANNEL_SPACING_100KHZ 2
+#define FM_CHANNEL_SPACING_200KHZ 4
+#define FM_FREQ_MUL 50
+
+#endif
+
diff --git a/drivers/media/radio/wl128x/fmdrv_rx.c b/drivers/media/radio/wl128x/fmdrv_rx.c
new file mode 100644
index 00000000000..ec529b55b04
--- /dev/null
+++ b/drivers/media/radio/wl128x/fmdrv_rx.c
@@ -0,0 +1,847 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ * This sub-module of FM driver implements FM RX functionality.
+ *
+ * Copyright (C) 2011 Texas Instruments
+ * Author: Raja Mani <raja_mani@ti.com>
+ * Author: Manjunatha Halli <manjunatha_halli@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "fmdrv.h"
+#include "fmdrv_common.h"
+#include "fmdrv_rx.h"
+
+void fm_rx_reset_rds_cache(struct fmdev *fmdev)
+{
+ fmdev->rx.rds.flag = FM_RDS_DISABLE;
+ fmdev->rx.rds.last_blk_idx = 0;
+ fmdev->rx.rds.wr_idx = 0;
+ fmdev->rx.rds.rd_idx = 0;
+
+ if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
+ fmdev->irq_info.mask |= FM_LEV_EVENT;
+}
+
+void fm_rx_reset_station_info(struct fmdev *fmdev)
+{
+ fmdev->rx.stat_info.picode = FM_NO_PI_CODE;
+ fmdev->rx.stat_info.afcache_size = 0;
+ fmdev->rx.stat_info.af_list_max = 0;
+}
+
+u32 fm_rx_set_freq(struct fmdev *fmdev, u32 freq)
+{
+ unsigned long timeleft;
+ u16 payload, curr_frq, intr_flag;
+ u32 curr_frq_in_khz;
+ u32 ret, resp_len;
+
+ if (freq < fmdev->rx.region.bot_freq || freq > fmdev->rx.region.top_freq) {
+ fmerr("Invalid frequency %d\n", freq);
+ return -EINVAL;
+ }
+
+ /* Set audio enable */
+ payload = FM_RX_AUDIO_ENABLE_I2S_AND_ANALOG;
+
+ ret = fmc_send_cmd(fmdev, AUDIO_ENABLE_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Set hilo to automatic selection */
+ payload = FM_RX_IFFREQ_HILO_AUTOMATIC;
+ ret = fmc_send_cmd(fmdev, HILO_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Calculate frequency index and set*/
+ payload = (freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
+
+ ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Read flags - just to clear any pending interrupts if we had */
+ ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Enable FR, BL interrupts */
+ intr_flag = fmdev->irq_info.mask;
+ fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT);
+ payload = fmdev->irq_info.mask;
+ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Start tune */
+ payload = FM_TUNER_PRESET_MODE;
+ ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ goto exit;
+
+ /* Wait for tune ended interrupt */
+ init_completion(&fmdev->maintask_comp);
+ timeleft = wait_for_completion_timeout(&fmdev->maintask_comp,
+ FM_DRV_TX_TIMEOUT);
+ if (!timeleft) {
+ fmerr("Timeout(%d sec),didn't get tune ended int\n",
+ jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
+ ret = -ETIMEDOUT;
+ goto exit;
+ }
+
+ /* Read freq back to confirm */
+ ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2, &curr_frq, &resp_len);
+ if (ret < 0)
+ goto exit;
+
+ curr_frq = be16_to_cpu(curr_frq);
+ curr_frq_in_khz = (fmdev->rx.region.bot_freq + ((u32)curr_frq * FM_FREQ_MUL));
+
+ if (curr_frq_in_khz != freq) {
+ pr_info("Frequency is set to (%d) but "
+ "requested freq is (%d)\n", curr_frq_in_khz, freq);
+ }
+
+ /* Update local cache */
+ fmdev->rx.freq = curr_frq_in_khz;
+exit:
+ /* Re-enable default FM interrupts */
+ fmdev->irq_info.mask = intr_flag;
+ payload = fmdev->irq_info.mask;
+ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Reset RDS cache and current station pointers */
+ fm_rx_reset_rds_cache(fmdev);
+ fm_rx_reset_station_info(fmdev);
+
+ return ret;
+}
+
+static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing)
+{
+ u16 payload;
+ u32 ret;
+
+ if (spacing > 0 && spacing <= 50000)
+ spacing = FM_CHANNEL_SPACING_50KHZ;
+ else if (spacing > 50000 && spacing <= 100000)
+ spacing = FM_CHANNEL_SPACING_100KHZ;
+ else
+ spacing = FM_CHANNEL_SPACING_200KHZ;
+
+ /* set channel spacing */
+ payload = spacing;
+ ret = fmc_send_cmd(fmdev, CHANL_BW_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ fmdev->rx.region.chanl_space = spacing * FM_FREQ_MUL;
+
+ return ret;
+}
+
+u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward,
+ u32 wrap_around, u32 spacing)
+{
+ u32 resp_len;
+ u16 curr_frq, next_frq, last_frq;
+ u16 payload, int_reason, intr_flag;
+ u16 offset, space_idx;
+ unsigned long timeleft;
+ u32 ret;
+
+ /* Set channel spacing */
+ ret = fm_rx_set_channel_spacing(fmdev, spacing);
+ if (ret < 0) {
+ fmerr("Failed to set channel spacing\n");
+ return ret;
+ }
+
+ /* Read the current frequency from chip */
+ ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL,
+ sizeof(curr_frq), &curr_frq, &resp_len);
+ if (ret < 0)
+ return ret;
+
+ curr_frq = be16_to_cpu(curr_frq);
+ last_frq = (fmdev->rx.region.top_freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
+
+ /* Check the offset in order to be aligned to the channel spacing*/
+ space_idx = fmdev->rx.region.chanl_space / FM_FREQ_MUL;
+ offset = curr_frq % space_idx;
+
+ next_frq = seek_upward ? curr_frq + space_idx /* Seek Up */ :
+ curr_frq - space_idx /* Seek Down */ ;
+
+ /*
+ * Add or subtract offset in order to stay aligned to the channel
+ * spacing.
+ */
+ if ((short)next_frq < 0)
+ next_frq = last_frq - offset;
+ else if (next_frq > last_frq)
+ next_frq = 0 + offset;
+
+again:
+ /* Set calculated next frequency to perform seek */
+ payload = next_frq;
+ ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Set search direction (0:Seek Down, 1:Seek Up) */
+ payload = (seek_upward ? FM_SEARCH_DIRECTION_UP : FM_SEARCH_DIRECTION_DOWN);
+ ret = fmc_send_cmd(fmdev, SEARCH_DIR_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Read flags - just to clear any pending interrupts if we had */
+ ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Enable FR, BL interrupts */
+ intr_flag = fmdev->irq_info.mask;
+ fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT);
+ payload = fmdev->irq_info.mask;
+ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Start seek */
+ payload = FM_TUNER_AUTONOMOUS_SEARCH_MODE;
+ ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Wait for tune ended/band limit reached interrupt */
+ init_completion(&fmdev->maintask_comp);
+ timeleft = wait_for_completion_timeout(&fmdev->maintask_comp,
+ FM_DRV_RX_SEEK_TIMEOUT);
+ if (!timeleft) {
+ fmerr("Timeout(%d sec),didn't get tune ended int\n",
+ jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000);
+ return -ETIMEDOUT;
+ }
+
+ int_reason = fmdev->irq_info.flag & (FM_TUNE_COMPLETE | FM_BAND_LIMIT);
+
+ /* Re-enable default FM interrupts */
+ fmdev->irq_info.mask = intr_flag;
+ payload = fmdev->irq_info.mask;
+ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ if (int_reason & FM_BL_EVENT) {
+ if (wrap_around == 0) {
+ fmdev->rx.freq = seek_upward ?
+ fmdev->rx.region.top_freq :
+ fmdev->rx.region.bot_freq;
+ } else {
+ fmdev->rx.freq = seek_upward ?
+ fmdev->rx.region.bot_freq :
+ fmdev->rx.region.top_freq;
+ /* Calculate frequency index to write */
+ next_frq = (fmdev->rx.freq -
+ fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
+ goto again;
+ }
+ } else {
+ /* Read freq to know where operation tune operation stopped */
+ ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2,
+ &curr_frq, &resp_len);
+ if (ret < 0)
+ return ret;
+
+ curr_frq = be16_to_cpu(curr_frq);
+ fmdev->rx.freq = (fmdev->rx.region.bot_freq +
+ ((u32)curr_frq * FM_FREQ_MUL));
+
+ }
+ /* Reset RDS cache and current station pointers */
+ fm_rx_reset_rds_cache(fmdev);
+ fm_rx_reset_station_info(fmdev);
+
+ return ret;
+}
+
+u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set)
+{
+ u16 payload;
+ u32 ret;
+
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
+
+ if (vol_to_set < FM_RX_VOLUME_MIN || vol_to_set > FM_RX_VOLUME_MAX) {
+ fmerr("Volume is not within(%d-%d) range\n",
+ FM_RX_VOLUME_MIN, FM_RX_VOLUME_MAX);
+ return -EINVAL;
+ }
+ vol_to_set *= FM_RX_VOLUME_GAIN_STEP;
+
+ payload = vol_to_set;
+ ret = fmc_send_cmd(fmdev, VOLUME_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ fmdev->rx.volume = vol_to_set;
+ return ret;
+}
+
+/* Get volume */
+u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol)
+{
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
+
+ if (curr_vol == NULL) {
+ fmerr("Invalid memory\n");
+ return -ENOMEM;
+ }
+
+ *curr_vol = fmdev->rx.volume / FM_RX_VOLUME_GAIN_STEP;
+
+ return 0;
+}
+
+/* To get current band's bottom and top frequency */
+u32 fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq)
+{
+ if (bot_freq != NULL)
+ *bot_freq = fmdev->rx.region.bot_freq;
+
+ if (top_freq != NULL)
+ *top_freq = fmdev->rx.region.top_freq;
+
+ return 0;
+}
+
+/* Returns current band index (0-Europe/US; 1-Japan) */
+void fm_rx_get_region(struct fmdev *fmdev, u8 *region)
+{
+ *region = fmdev->rx.region.fm_band;
+}
+
+/* Sets band (0-Europe/US; 1-Japan) */
+u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set)
+{
+ u16 payload;
+ u32 new_frq = 0;
+ u32 ret;
+
+ if (region_to_set != FM_BAND_EUROPE_US &&
+ region_to_set != FM_BAND_JAPAN) {
+ fmerr("Invalid band\n");
+ return -EINVAL;
+ }
+
+ if (fmdev->rx.region.fm_band == region_to_set) {
+ fmerr("Requested band is already configured\n");
+ return 0;
+ }
+
+ /* Send cmd to set the band */
+ payload = (u16)region_to_set;
+ ret = fmc_send_cmd(fmdev, BAND_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ fmc_update_region_info(fmdev, region_to_set);
+
+ /* Check whether current RX frequency is within band boundary */
+ if (fmdev->rx.freq < fmdev->rx.region.bot_freq)
+ new_frq = fmdev->rx.region.bot_freq;
+ else if (fmdev->rx.freq > fmdev->rx.region.top_freq)
+ new_frq = fmdev->rx.region.top_freq;
+
+ if (new_frq) {
+ fmdbg("Current freq is not within band limit boundary,"
+ "switching to %d KHz\n", new_frq);
+ /* Current RX frequency is not in range. So, update it */
+ ret = fm_rx_set_freq(fmdev, new_frq);
+ }
+
+ return ret;
+}
+
+/* Reads current mute mode (Mute Off/On/Attenuate)*/
+u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode)
+{
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
+
+ if (curr_mute_mode == NULL) {
+ fmerr("Invalid memory\n");
+ return -ENOMEM;
+ }
+
+ *curr_mute_mode = fmdev->rx.mute_mode;
+
+ return 0;
+}
+
+static u32 fm_config_rx_mute_reg(struct fmdev *fmdev)
+{
+ u16 payload, muteval;
+ u32 ret;
+
+ muteval = 0;
+ switch (fmdev->rx.mute_mode) {
+ case FM_MUTE_ON:
+ muteval = FM_RX_AC_MUTE_MODE;
+ break;
+
+ case FM_MUTE_OFF:
+ muteval = FM_RX_UNMUTE_MODE;
+ break;
+
+ case FM_MUTE_ATTENUATE:
+ muteval = FM_RX_SOFT_MUTE_FORCE_MODE;
+ break;
+ }
+ if (fmdev->rx.rf_depend_mute == FM_RX_RF_DEPENDENT_MUTE_ON)
+ muteval |= FM_RX_RF_DEP_MODE;
+ else
+ muteval &= ~FM_RX_RF_DEP_MODE;
+
+ payload = muteval;
+ ret = fmc_send_cmd(fmdev, MUTE_STATUS_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/* Configures mute mode (Mute Off/On/Attenuate) */
+u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
+{
+ u8 org_state;
+ u32 ret;
+
+ if (fmdev->rx.mute_mode == mute_mode_toset)
+ return 0;
+
+ org_state = fmdev->rx.mute_mode;
+ fmdev->rx.mute_mode = mute_mode_toset;
+
+ ret = fm_config_rx_mute_reg(fmdev);
+ if (ret < 0) {
+ fmdev->rx.mute_mode = org_state;
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Gets RF dependent soft mute mode enable/disable status */
+u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode)
+{
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
+
+ if (curr_mute_mode == NULL) {
+ fmerr("Invalid memory\n");
+ return -ENOMEM;
+ }
+
+ *curr_mute_mode = fmdev->rx.rf_depend_mute;
+
+ return 0;
+}
+
+/* Sets RF dependent soft mute mode */
+u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute)
+{
+ u8 org_state;
+ u32 ret;
+
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
+
+ if (rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_ON &&
+ rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_OFF) {
+ fmerr("Invalid RF dependent soft mute\n");
+ return -EINVAL;
+ }
+ if (fmdev->rx.rf_depend_mute == rfdepend_mute)
+ return 0;
+
+ org_state = fmdev->rx.rf_depend_mute;
+ fmdev->rx.rf_depend_mute = rfdepend_mute;
+
+ ret = fm_config_rx_mute_reg(fmdev);
+ if (ret < 0) {
+ fmdev->rx.rf_depend_mute = org_state;
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Returns the signal strength level of current channel */
+u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl)
+{
+ u16 curr_rssi_lel;
+ u32 resp_len;
+ u32 ret;
+
+ if (rssilvl == NULL) {
+ fmerr("Invalid memory\n");
+ return -ENOMEM;
+ }
+ /* Read current RSSI level */
+ ret = fmc_send_cmd(fmdev, RSSI_LVL_GET, REG_RD, NULL, 2,
+ &curr_rssi_lel, &resp_len);
+ if (ret < 0)
+ return ret;
+
+ *rssilvl = be16_to_cpu(curr_rssi_lel);
+
+ return 0;
+}
+
+/*
+ * Sets the signal strength level that once reached
+ * will stop the auto search process
+ */
+u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset)
+{
+ u16 payload;
+ u32 ret;
+
+ if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN ||
+ rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) {
+ fmerr("Invalid RSSI threshold level\n");
+ return -EINVAL;
+ }
+ payload = (u16)rssi_lvl_toset;
+ ret = fmc_send_cmd(fmdev, SEARCH_LVL_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ fmdev->rx.rssi_threshold = rssi_lvl_toset;
+
+ return 0;
+}
+
+/* Returns current RX RSSI threshold value */
+u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl)
+{
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
+
+ if (curr_rssi_lvl == NULL) {
+ fmerr("Invalid memory\n");
+ return -ENOMEM;
+ }
+
+ *curr_rssi_lvl = fmdev->rx.rssi_threshold;
+
+ return 0;
+}
+
+/* Sets RX stereo/mono modes */
+u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
+{
+ u16 payload;
+ u32 ret;
+
+ if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) {
+ fmerr("Invalid mode\n");
+ return -EINVAL;
+ }
+
+ /* Set stereo/mono mode */
+ payload = (u16)mode;
+ ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Set stereo blending mode */
+ payload = FM_STEREO_SOFT_BLEND;
+ ret = fmc_send_cmd(fmdev, MOST_BLEND_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/* Gets current RX stereo/mono mode */
+u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode)
+{
+ u16 curr_mode;
+ u32 ret, resp_len;
+
+ if (mode == NULL) {
+ fmerr("Invalid memory\n");
+ return -ENOMEM;
+ }
+
+ ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_RD, NULL, 2,
+ &curr_mode, &resp_len);
+ if (ret < 0)
+ return ret;
+
+ *mode = be16_to_cpu(curr_mode);
+
+ return 0;
+}
+
+/* Choose RX de-emphasis filter mode (50us/75us) */
+u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode)
+{
+ u16 payload;
+ u32 ret;
+
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
+
+ if (mode != FM_RX_EMPHASIS_FILTER_50_USEC &&
+ mode != FM_RX_EMPHASIS_FILTER_75_USEC) {
+ fmerr("Invalid rx de-emphasis mode (%d)\n", mode);
+ return -EINVAL;
+ }
+
+ payload = mode;
+ ret = fmc_send_cmd(fmdev, DEMPH_MODE_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ fmdev->rx.deemphasis_mode = mode;
+
+ return 0;
+}
+
+/* Gets current RX de-emphasis filter mode */
+u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode)
+{
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
+
+ if (curr_deemphasis_mode == NULL) {
+ fmerr("Invalid memory\n");
+ return -ENOMEM;
+ }
+
+ *curr_deemphasis_mode = fmdev->rx.deemphasis_mode;
+
+ return 0;
+}
+
+/* Enable/Disable RX RDS */
+u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
+{
+ u16 payload;
+ u32 ret;
+
+ if (rds_en_dis != FM_RDS_ENABLE && rds_en_dis != FM_RDS_DISABLE) {
+ fmerr("Invalid rds option\n");
+ return -EINVAL;
+ }
+
+ if (rds_en_dis == FM_RDS_ENABLE
+ && fmdev->rx.rds.flag == FM_RDS_DISABLE) {
+ /* Turn on RX RDS and RDS circuit */
+ payload = FM_RX_PWR_SET_FM_AND_RDS_BLK_ON;
+ ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Clear and reset RDS FIFO */
+ payload = FM_RX_RDS_FLUSH_FIFO;
+ ret = fmc_send_cmd(fmdev, RDS_CNTRL_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Read flags - just to clear any pending interrupts. */
+ ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2,
+ NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Set RDS FIFO threshold value */
+ payload = FM_RX_RDS_FIFO_THRESHOLD;
+ ret = fmc_send_cmd(fmdev, RDS_MEM_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Enable RDS interrupt */
+ fmdev->irq_info.mask |= FM_RDS_EVENT;
+ payload = fmdev->irq_info.mask;
+ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0) {
+ fmdev->irq_info.mask &= ~FM_RDS_EVENT;
+ return ret;
+ }
+
+ /* Update our local flag */
+ fmdev->rx.rds.flag = FM_RDS_ENABLE;
+ } else if (rds_en_dis == FM_RDS_DISABLE
+ && fmdev->rx.rds.flag == FM_RDS_ENABLE) {
+ /* Turn off RX RDS */
+ payload = FM_RX_PWR_SET_FM_ON_RDS_OFF;
+ ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Reset RDS pointers */
+ fmdev->rx.rds.last_blk_idx = 0;
+ fmdev->rx.rds.wr_idx = 0;
+ fmdev->rx.rds.rd_idx = 0;
+ fm_rx_reset_station_info(fmdev);
+
+ /* Update RDS local cache */
+ fmdev->irq_info.mask &= ~(FM_RDS_EVENT);
+ fmdev->rx.rds.flag = FM_RDS_DISABLE;
+ }
+
+ return 0;
+}
+
+/* Returns current RX RDS enable/disable status */
+u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis)
+{
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
+
+ if (curr_rds_en_dis == NULL) {
+ fmerr("Invalid memory\n");
+ return -ENOMEM;
+ }
+
+ *curr_rds_en_dis = fmdev->rx.rds.flag;
+
+ return 0;
+}
+
+/* Sets RDS operation mode (RDS/RDBS) */
+u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode)
+{
+ u16 payload;
+ u32 ret;
+
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
+
+ if (rds_mode != FM_RDS_SYSTEM_RDS && rds_mode != FM_RDS_SYSTEM_RBDS) {
+ fmerr("Invalid rds mode\n");
+ return -EINVAL;
+ }
+ /* Set RDS operation mode */
+ payload = (u16)rds_mode;
+ ret = fmc_send_cmd(fmdev, RDS_SYSTEM_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ fmdev->rx.rds_mode = rds_mode;
+
+ return 0;
+}
+
+/* Returns current RDS operation mode */
+u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode)
+{
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
+
+ if (rds_mode == NULL) {
+ fmerr("Invalid memory\n");
+ return -ENOMEM;
+ }
+
+ *rds_mode = fmdev->rx.rds_mode;
+
+ return 0;
+}
+
+/* Configures Alternate Frequency switch mode */
+u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode)
+{
+ u16 payload;
+ u32 ret;
+
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
+
+ if (af_mode != FM_RX_RDS_AF_SWITCH_MODE_ON &&
+ af_mode != FM_RX_RDS_AF_SWITCH_MODE_OFF) {
+ fmerr("Invalid af mode\n");
+ return -EINVAL;
+ }
+ /* Enable/disable low RSSI interrupt based on af_mode */
+ if (af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
+ fmdev->irq_info.mask |= FM_LEV_EVENT;
+ else
+ fmdev->irq_info.mask &= ~FM_LEV_EVENT;
+
+ payload = fmdev->irq_info.mask;
+ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ fmdev->rx.af_mode = af_mode;
+
+ return 0;
+}
+
+/* Returns Alternate Frequency switch status */
+u32 fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode)
+{
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
+
+ if (af_mode == NULL) {
+ fmerr("Invalid memory\n");
+ return -ENOMEM;
+ }
+
+ *af_mode = fmdev->rx.af_mode;
+
+ return 0;
+}
diff --git a/drivers/media/radio/wl128x/fmdrv_rx.h b/drivers/media/radio/wl128x/fmdrv_rx.h
new file mode 100644
index 00000000000..329e62f6be7
--- /dev/null
+++ b/drivers/media/radio/wl128x/fmdrv_rx.h
@@ -0,0 +1,59 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ * FM RX module header.
+ *
+ * Copyright (C) 2011 Texas Instruments
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _FMDRV_RX_H
+#define _FMDRV_RX_H
+
+u32 fm_rx_set_freq(struct fmdev *, u32);
+u32 fm_rx_set_mute_mode(struct fmdev *, u8);
+u32 fm_rx_set_stereo_mono(struct fmdev *, u16);
+u32 fm_rx_set_rds_mode(struct fmdev *, u8);
+u32 fm_rx_set_rds_system(struct fmdev *, u8);
+u32 fm_rx_set_volume(struct fmdev *, u16);
+u32 fm_rx_set_rssi_threshold(struct fmdev *, short);
+u32 fm_rx_set_region(struct fmdev *, u8);
+u32 fm_rx_set_rfdepend_softmute(struct fmdev *, u8);
+u32 fm_rx_set_deemphasis_mode(struct fmdev *, u16);
+u32 fm_rx_set_af_switch(struct fmdev *, u8);
+
+void fm_rx_reset_rds_cache(struct fmdev *);
+void fm_rx_reset_station_info(struct fmdev *);
+
+u32 fm_rx_seek(struct fmdev *, u32, u32, u32);
+
+u32 fm_rx_get_rds_mode(struct fmdev *, u8 *);
+u32 fm_rx_get_rds_system(struct fmdev *, u8 *);
+u32 fm_rx_get_mute_mode(struct fmdev *, u8 *);
+u32 fm_rx_get_volume(struct fmdev *, u16 *);
+u32 fm_rx_get_band_freq_range(struct fmdev *,
+ u32 *, u32 *);
+u32 fm_rx_get_stereo_mono(struct fmdev *, u16 *);
+u32 fm_rx_get_rssi_level(struct fmdev *, u16 *);
+u32 fm_rx_get_rssi_threshold(struct fmdev *, short *);
+u32 fm_rx_get_rfdepend_softmute(struct fmdev *, u8 *);
+u32 fm_rx_get_deemph_mode(struct fmdev *, u16 *);
+u32 fm_rx_get_af_switch(struct fmdev *, u8 *);
+void fm_rx_get_region(struct fmdev *, u8 *);
+
+u32 fm_rx_set_chanl_spacing(struct fmdev *, u8);
+u32 fm_rx_get_chanl_spacing(struct fmdev *, u8 *);
+#endif
+
diff --git a/drivers/media/radio/wl128x/fmdrv_tx.c b/drivers/media/radio/wl128x/fmdrv_tx.c
new file mode 100644
index 00000000000..be54068b56a
--- /dev/null
+++ b/drivers/media/radio/wl128x/fmdrv_tx.c
@@ -0,0 +1,425 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ * This sub-module of FM driver implements FM TX functionality.
+ *
+ * Copyright (C) 2011 Texas Instruments
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/delay.h>
+#include "fmdrv.h"
+#include "fmdrv_common.h"
+#include "fmdrv_tx.h"
+
+u32 fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
+{
+ u16 payload;
+ u32 ret;
+
+ if (fmdev->tx_data.aud_mode == mode)
+ return 0;
+
+ fmdbg("stereo mode: %d\n", mode);
+
+ /* Set Stereo/Mono mode */
+ payload = (1 - mode);
+ ret = fmc_send_cmd(fmdev, MONO_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ fmdev->tx_data.aud_mode = mode;
+
+ return ret;
+}
+
+static u32 set_rds_text(struct fmdev *fmdev, u8 *rds_text)
+{
+ u16 payload;
+ u32 ret;
+
+ ret = fmc_send_cmd(fmdev, RDS_DATA_SET, REG_WR, rds_text,
+ strlen(rds_text), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Scroll mode */
+ payload = (u16)0x1;
+ ret = fmc_send_cmd(fmdev, DISPLAY_MODE, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static u32 set_rds_data_mode(struct fmdev *fmdev, u8 mode)
+{
+ u16 payload;
+ u32 ret;
+
+ /* Setting unique PI TODO: how unique? */
+ payload = (u16)0xcafe;
+ ret = fmc_send_cmd(fmdev, PI_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Set decoder id */
+ payload = (u16)0xa;
+ ret = fmc_send_cmd(fmdev, DI_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* TODO: RDS_MODE_GET? */
+ return 0;
+}
+
+static u32 set_rds_len(struct fmdev *fmdev, u8 type, u16 len)
+{
+ u16 payload;
+ u32 ret;
+
+ len |= type << 8;
+ payload = len;
+ ret = fmc_send_cmd(fmdev, RDS_CONFIG_DATA_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* TODO: LENGTH_GET? */
+ return 0;
+}
+
+u32 fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
+{
+ u16 payload;
+ u32 ret;
+ u8 rds_text[] = "Zoom2\n";
+
+ fmdbg("rds_en_dis:%d(E:%d, D:%d)\n", rds_en_dis,
+ FM_RDS_ENABLE, FM_RDS_DISABLE);
+
+ if (rds_en_dis == FM_RDS_ENABLE) {
+ /* Set RDS length */
+ set_rds_len(fmdev, 0, strlen(rds_text));
+
+ /* Set RDS text */
+ set_rds_text(fmdev, rds_text);
+
+ /* Set RDS mode */
+ set_rds_data_mode(fmdev, 0x0);
+ }
+
+ /* Send command to enable RDS */
+ if (rds_en_dis == FM_RDS_ENABLE)
+ payload = 0x01;
+ else
+ payload = 0x00;
+
+ ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ if (rds_en_dis == FM_RDS_ENABLE) {
+ /* Set RDS length */
+ set_rds_len(fmdev, 0, strlen(rds_text));
+
+ /* Set RDS text */
+ set_rds_text(fmdev, rds_text);
+ }
+ fmdev->tx_data.rds.flag = rds_en_dis;
+
+ return 0;
+}
+
+u32 fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type)
+{
+ u16 payload;
+ u32 ret;
+
+ if (fmdev->curr_fmmode != FM_MODE_TX)
+ return -EPERM;
+
+ fm_tx_set_rds_mode(fmdev, 0);
+
+ /* Set RDS length */
+ set_rds_len(fmdev, rds_type, strlen(rds_text));
+
+ /* Set RDS text */
+ set_rds_text(fmdev, rds_text);
+
+ /* Set RDS mode */
+ set_rds_data_mode(fmdev, 0x0);
+
+ payload = 1;
+ ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+u32 fm_tx_set_af(struct fmdev *fmdev, u32 af)
+{
+ u16 payload;
+ u32 ret;
+
+ if (fmdev->curr_fmmode != FM_MODE_TX)
+ return -EPERM;
+
+ fmdbg("AF: %d\n", af);
+
+ af = (af - 87500) / 100;
+ payload = (u16)af;
+ ret = fmc_send_cmd(fmdev, TA_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+u32 fm_tx_set_region(struct fmdev *fmdev, u8 region)
+{
+ u16 payload;
+ u32 ret;
+
+ if (region != FM_BAND_EUROPE_US && region != FM_BAND_JAPAN) {
+ fmerr("Invalid band\n");
+ return -EINVAL;
+ }
+
+ /* Send command to set the band */
+ payload = (u16)region;
+ ret = fmc_send_cmd(fmdev, TX_BAND_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+u32 fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
+{
+ u16 payload;
+ u32 ret;
+
+ fmdbg("tx: mute mode %d\n", mute_mode_toset);
+
+ payload = mute_mode_toset;
+ ret = fmc_send_cmd(fmdev, MUTE, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/* Set TX Audio I/O */
+static u32 set_audio_io(struct fmdev *fmdev)
+{
+ struct fmtx_data *tx = &fmdev->tx_data;
+ u16 payload;
+ u32 ret;
+
+ /* Set Audio I/O Enable */
+ payload = tx->audio_io;
+ ret = fmc_send_cmd(fmdev, AUDIO_IO_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* TODO: is audio set? */
+ return 0;
+}
+
+/* Start TX Transmission */
+static u32 enable_xmit(struct fmdev *fmdev, u8 new_xmit_state)
+{
+ struct fmtx_data *tx = &fmdev->tx_data;
+ unsigned long timeleft;
+ u16 payload;
+ u32 ret;
+
+ /* Enable POWER_ENB interrupts */
+ payload = FM_POW_ENB_EVENT;
+ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Set Power Enable */
+ payload = new_xmit_state;
+ ret = fmc_send_cmd(fmdev, POWER_ENB_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* Wait for Power Enabled */
+ init_completion(&fmdev->maintask_comp);
+ timeleft = wait_for_completion_timeout(&fmdev->maintask_comp,
+ FM_DRV_TX_TIMEOUT);
+ if (!timeleft) {
+ fmerr("Timeout(%d sec),didn't get tune ended interrupt\n",
+ jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
+ return -ETIMEDOUT;
+ }
+
+ set_bit(FM_CORE_TX_XMITING, &fmdev->flag);
+ tx->xmit_state = new_xmit_state;
+
+ return 0;
+}
+
+/* Set TX power level */
+u32 fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl)
+{
+ u16 payload;
+ struct fmtx_data *tx = &fmdev->tx_data;
+ u32 ret;
+
+ if (fmdev->curr_fmmode != FM_MODE_TX)
+ return -EPERM;
+ fmdbg("tx: pwr_level_to_set %ld\n", (long int)new_pwr_lvl);
+
+ /* If the core isn't ready update global variable */
+ if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+ tx->pwr_lvl = new_pwr_lvl;
+ return 0;
+ }
+
+ /* Set power level: Application will specify power level value in
+ * units of dB/uV, whereas range and step are specific to FM chip.
+ * For TI's WL chips, convert application specified power level value
+ * to chip specific value by subtracting 122 from it. Refer to TI FM
+ * data sheet for details.
+ * */
+
+ payload = (FM_PWR_LVL_HIGH - new_pwr_lvl);
+ ret = fmc_send_cmd(fmdev, POWER_LEV_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ /* TODO: is the power level set? */
+ tx->pwr_lvl = new_pwr_lvl;
+
+ return 0;
+}
+
+/*
+ * Sets FM TX pre-emphasis filter value (OFF, 50us, or 75us)
+ * Convert V4L2 specified filter values to chip specific filter values.
+ */
+u32 fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis)
+{
+ struct fmtx_data *tx = &fmdev->tx_data;
+ u16 payload;
+ u32 ret;
+
+ if (fmdev->curr_fmmode != FM_MODE_TX)
+ return -EPERM;
+
+ switch (preemphasis) {
+ case V4L2_PREEMPHASIS_DISABLED:
+ payload = FM_TX_PREEMPH_OFF;
+ break;
+ case V4L2_PREEMPHASIS_50_uS:
+ payload = FM_TX_PREEMPH_50US;
+ break;
+ case V4L2_PREEMPHASIS_75_uS:
+ payload = FM_TX_PREEMPH_75US;
+ break;
+ }
+
+ ret = fmc_send_cmd(fmdev, PREMPH_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ tx->preemph = payload;
+
+ return ret;
+}
+
+/* Get the TX tuning capacitor value.*/
+u32 fm_tx_get_tune_cap_val(struct fmdev *fmdev)
+{
+ u16 curr_val;
+ u32 ret, resp_len;
+
+ if (fmdev->curr_fmmode != FM_MODE_TX)
+ return -EPERM;
+
+ ret = fmc_send_cmd(fmdev, READ_FMANT_TUNE_VALUE, REG_RD,
+ NULL, sizeof(curr_val), &curr_val, &resp_len);
+ if (ret < 0)
+ return ret;
+
+ curr_val = be16_to_cpu(curr_val);
+
+ return curr_val;
+}
+
+/* Set TX Frequency */
+u32 fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set)
+{
+ struct fmtx_data *tx = &fmdev->tx_data;
+ u16 payload, chanl_index;
+ u32 ret;
+
+ if (test_bit(FM_CORE_TX_XMITING, &fmdev->flag)) {
+ enable_xmit(fmdev, 0);
+ clear_bit(FM_CORE_TX_XMITING, &fmdev->flag);
+ }
+
+ /* Enable FR, BL interrupts */
+ payload = (FM_FR_EVENT | FM_BL_EVENT);
+ ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ tx->tx_frq = (unsigned long)freq_to_set;
+ fmdbg("tx: freq_to_set %ld\n", (long int)tx->tx_frq);
+
+ chanl_index = freq_to_set / 10;
+
+ /* Set current tuner channel */
+ payload = chanl_index;
+ ret = fmc_send_cmd(fmdev, CHANL_SET, REG_WR, &payload,
+ sizeof(payload), NULL, NULL);
+ if (ret < 0)
+ return ret;
+
+ fm_tx_set_pwr_lvl(fmdev, tx->pwr_lvl);
+ fm_tx_set_preemph_filter(fmdev, tx->preemph);
+
+ tx->audio_io = 0x01; /* I2S */
+ set_audio_io(fmdev);
+
+ enable_xmit(fmdev, 0x01); /* Enable transmission */
+
+ tx->aud_mode = FM_STEREO_MODE;
+ tx->rds.flag = FM_RDS_DISABLE;
+
+ return 0;
+}
+
diff --git a/drivers/media/radio/wl128x/fmdrv_tx.h b/drivers/media/radio/wl128x/fmdrv_tx.h
new file mode 100644
index 00000000000..e393a2bdd49
--- /dev/null
+++ b/drivers/media/radio/wl128x/fmdrv_tx.h
@@ -0,0 +1,37 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ * FM TX module header.
+ *
+ * Copyright (C) 2011 Texas Instruments
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _FMDRV_TX_H
+#define _FMDRV_TX_H
+
+u32 fm_tx_set_freq(struct fmdev *, u32);
+u32 fm_tx_set_pwr_lvl(struct fmdev *, u8);
+u32 fm_tx_set_region(struct fmdev *, u8);
+u32 fm_tx_set_mute_mode(struct fmdev *, u8);
+u32 fm_tx_set_stereo_mono(struct fmdev *, u16);
+u32 fm_tx_set_rds_mode(struct fmdev *, u8);
+u32 fm_tx_set_radio_text(struct fmdev *, u8 *, u8);
+u32 fm_tx_set_af(struct fmdev *, u32);
+u32 fm_tx_set_preemph_filter(struct fmdev *, u32);
+u32 fm_tx_get_tune_cap_val(struct fmdev *);
+
+#endif
+
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
new file mode 100644
index 00000000000..d50e5ac75ab
--- /dev/null
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -0,0 +1,580 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ * This file provides interfaces to V4L2 subsystem.
+ *
+ * This module registers with V4L2 subsystem as Radio
+ * data system interface (/dev/radio). During the registration,
+ * it will expose two set of function pointers.
+ *
+ * 1) File operation related API (open, close, read, write, poll...etc).
+ * 2) Set of V4L2 IOCTL complaint API.
+ *
+ * Copyright (C) 2011 Texas Instruments
+ * Author: Raja Mani <raja_mani@ti.com>
+ * Author: Manjunatha Halli <manjunatha_halli@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "fmdrv.h"
+#include "fmdrv_v4l2.h"
+#include "fmdrv_common.h"
+#include "fmdrv_rx.h"
+#include "fmdrv_tx.h"
+
+static struct video_device *gradio_dev;
+static u8 radio_disconnected;
+
+/* -- V4L2 RADIO (/dev/radioX) device file operation interfaces --- */
+
+/* Read RX RDS data */
+static ssize_t fm_v4l2_fops_read(struct file *file, char __user * buf,
+ size_t count, loff_t *ppos)
+{
+ u8 rds_mode;
+ int ret;
+ struct fmdev *fmdev;
+
+ fmdev = video_drvdata(file);
+
+ if (!radio_disconnected) {
+ fmerr("FM device is already disconnected\n");
+ return -EIO;
+ }
+
+ /* Turn on RDS mode , if it is disabled */
+ ret = fm_rx_get_rds_mode(fmdev, &rds_mode);
+ if (ret < 0) {
+ fmerr("Unable to read current rds mode\n");
+ return ret;
+ }
+
+ if (rds_mode == FM_RDS_DISABLE) {
+ ret = fmc_set_rds_mode(fmdev, FM_RDS_ENABLE);
+ if (ret < 0) {
+ fmerr("Failed to enable rds mode\n");
+ return ret;
+ }
+ }
+
+ /* Copy RDS data from internal buffer to user buffer */
+ return fmc_transfer_rds_from_internal_buff(fmdev, file, buf, count);
+}
+
+/* Write TX RDS data */
+static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf,
+ size_t count, loff_t *ppos)
+{
+ struct tx_rds rds;
+ int ret;
+ struct fmdev *fmdev;
+
+ ret = copy_from_user(&rds, buf, sizeof(rds));
+ fmdbg("(%d)type: %d, text %s, af %d\n",
+ ret, rds.text_type, rds.text, rds.af_freq);
+
+ fmdev = video_drvdata(file);
+ fm_tx_set_radio_text(fmdev, rds.text, rds.text_type);
+ fm_tx_set_af(fmdev, rds.af_freq);
+
+ return 0;
+}
+
+static u32 fm_v4l2_fops_poll(struct file *file, struct poll_table_struct *pts)
+{
+ int ret;
+ struct fmdev *fmdev;
+
+ fmdev = video_drvdata(file);
+ ret = fmc_is_rds_data_available(fmdev, file, pts);
+ if (ret < 0)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+/*
+ * Handle open request for "/dev/radioX" device.
+ * Start with FM RX mode as default.
+ */
+static int fm_v4l2_fops_open(struct file *file)
+{
+ int ret;
+ struct fmdev *fmdev = NULL;
+
+ /* Don't allow multiple open */
+ if (radio_disconnected) {
+ fmerr("FM device is already opened\n");
+ return -EBUSY;
+ }
+
+ fmdev = video_drvdata(file);
+
+ ret = fmc_prepare(fmdev);
+ if (ret < 0) {
+ fmerr("Unable to prepare FM CORE\n");
+ return ret;
+ }
+
+ fmdbg("Load FM RX firmware..\n");
+
+ ret = fmc_set_mode(fmdev, FM_MODE_RX);
+ if (ret < 0) {
+ fmerr("Unable to load FM RX firmware\n");
+ return ret;
+ }
+ radio_disconnected = 1;
+
+ return ret;
+}
+
+static int fm_v4l2_fops_release(struct file *file)
+{
+ int ret;
+ struct fmdev *fmdev;
+
+ fmdev = video_drvdata(file);
+ if (!radio_disconnected) {
+ fmdbg("FM device is already closed\n");
+ return 0;
+ }
+
+ ret = fmc_set_mode(fmdev, FM_MODE_OFF);
+ if (ret < 0) {
+ fmerr("Unable to turn off the chip\n");
+ return ret;
+ }
+
+ ret = fmc_release(fmdev);
+ if (ret < 0) {
+ fmerr("FM CORE release failed\n");
+ return ret;
+ }
+ radio_disconnected = 0;
+
+ return ret;
+}
+
+/* V4L2 RADIO (/dev/radioX) device IOCTL interfaces */
+static int fm_v4l2_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *capability)
+{
+ strlcpy(capability->driver, FM_DRV_NAME, sizeof(capability->driver));
+ strlcpy(capability->card, FM_DRV_CARD_SHORT_NAME,
+ sizeof(capability->card));
+ sprintf(capability->bus_info, "UART");
+ capability->version = FM_DRV_RADIO_VERSION;
+ capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER |
+ V4L2_CAP_RADIO | V4L2_CAP_MODULATOR |
+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE |
+ V4L2_CAP_RDS_CAPTURE;
+
+ return 0;
+}
+
+static int fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct fmdev *fmdev = container_of(ctrl->handler,
+ struct fmdev, ctrl_handler);
+
+ switch (ctrl->id) {
+ case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+ ctrl->val = fm_tx_get_tune_cap_val(fmdev);
+ break;
+ default:
+ fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id);
+ break;
+ }
+
+ return 0;
+}
+
+static int fm_v4l2_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct fmdev *fmdev = container_of(ctrl->handler,
+ struct fmdev, ctrl_handler);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_VOLUME: /* set volume */
+ return fm_rx_set_volume(fmdev, (u16)ctrl->val);
+
+ case V4L2_CID_AUDIO_MUTE: /* set mute */
+ return fmc_set_mute_mode(fmdev, (u8)ctrl->val);
+
+ case V4L2_CID_TUNE_POWER_LEVEL:
+ /* set TX power level - ext control */
+ return fm_tx_set_pwr_lvl(fmdev, (u8)ctrl->val);
+
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ return fm_tx_set_preemph_filter(fmdev, (u8) ctrl->val);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int fm_v4l2_vidioc_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *audio)
+{
+ memset(audio, 0, sizeof(*audio));
+ strcpy(audio->name, "Radio");
+ audio->capability = V4L2_AUDCAP_STEREO;
+
+ return 0;
+}
+
+static int fm_v4l2_vidioc_s_audio(struct file *file, void *priv,
+ struct v4l2_audio *audio)
+{
+ if (audio->index != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* Get tuner attributes. If current mode is NOT RX, return error */
+static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *tuner)
+{
+ struct fmdev *fmdev = video_drvdata(file);
+ u32 bottom_freq;
+ u32 top_freq;
+ u16 stereo_mono_mode;
+ u16 rssilvl;
+ int ret;
+
+ if (tuner->index != 0)
+ return -EINVAL;
+
+ if (fmdev->curr_fmmode != FM_MODE_RX)
+ return -EPERM;
+
+ ret = fm_rx_get_band_freq_range(fmdev, &bottom_freq, &top_freq);
+ if (ret != 0)
+ return ret;
+
+ ret = fm_rx_get_stereo_mono(fmdev, &stereo_mono_mode);
+ if (ret != 0)
+ return ret;
+
+ ret = fm_rx_get_rssi_level(fmdev, &rssilvl);
+ if (ret != 0)
+ return ret;
+
+ strcpy(tuner->name, "FM");
+ tuner->type = V4L2_TUNER_RADIO;
+ /* Store rangelow and rangehigh freq in unit of 62.5 Hz */
+ tuner->rangelow = bottom_freq * 16;
+ tuner->rangehigh = top_freq * 16;
+ tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO |
+ ((fmdev->rx.rds.flag == FM_RDS_ENABLE) ? V4L2_TUNER_SUB_RDS : 0);
+ tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
+ V4L2_TUNER_CAP_LOW;
+ tuner->audmode = (stereo_mono_mode ?
+ V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO);
+
+ /*
+ * Actual rssi value lies in between -128 to +127.
+ * Convert this range from 0 to 255 by adding +128
+ */
+ rssilvl += 128;
+
+ /*
+ * Return signal strength value should be within 0 to 65535.
+ * Find out correct signal radio by multiplying (65535/255) = 257
+ */
+ tuner->signal = rssilvl * 257;
+ tuner->afc = 0;
+
+ return ret;
+}
+
+/*
+ * Set tuner attributes. If current mode is NOT RX, set to RX.
+ * Currently, we set only audio mode (mono/stereo) and RDS state (on/off).
+ * Should we set other tuner attributes, too?
+ */
+static int fm_v4l2_vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *tuner)
+{
+ struct fmdev *fmdev = video_drvdata(file);
+ u16 aud_mode;
+ u8 rds_mode;
+ int ret;
+
+ if (tuner->index != 0)
+ return -EINVAL;
+
+ aud_mode = (tuner->audmode == V4L2_TUNER_MODE_STEREO) ?
+ FM_STEREO_MODE : FM_MONO_MODE;
+ rds_mode = (tuner->rxsubchans & V4L2_TUNER_SUB_RDS) ?
+ FM_RDS_ENABLE : FM_RDS_DISABLE;
+
+ if (fmdev->curr_fmmode != FM_MODE_RX) {
+ ret = fmc_set_mode(fmdev, FM_MODE_RX);
+ if (ret < 0) {
+ fmerr("Failed to set RX mode\n");
+ return ret;
+ }
+ }
+
+ ret = fmc_set_stereo_mono(fmdev, aud_mode);
+ if (ret < 0) {
+ fmerr("Failed to set RX stereo/mono mode\n");
+ return ret;
+ }
+
+ ret = fmc_set_rds_mode(fmdev, rds_mode);
+ if (ret < 0)
+ fmerr("Failed to set RX RDS mode\n");
+
+ return ret;
+}
+
+/* Get tuner or modulator radio frequency */
+static int fm_v4l2_vidioc_g_freq(struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct fmdev *fmdev = video_drvdata(file);
+ int ret;
+
+ ret = fmc_get_freq(fmdev, &freq->frequency);
+ if (ret < 0) {
+ fmerr("Failed to get frequency\n");
+ return ret;
+ }
+
+ /* Frequency unit of 62.5 Hz*/
+ freq->frequency = (u32) freq->frequency * 16;
+
+ return 0;
+}
+
+/* Set tuner or modulator radio frequency */
+static int fm_v4l2_vidioc_s_freq(struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct fmdev *fmdev = video_drvdata(file);
+
+ /*
+ * As V4L2_TUNER_CAP_LOW is set 1 user sends the frequency
+ * in units of 62.5 Hz.
+ */
+ freq->frequency = (u32)(freq->frequency / 16);
+
+ return fmc_set_freq(fmdev, freq->frequency);
+}
+
+/* Set hardware frequency seek. If current mode is NOT RX, set it RX. */
+static int fm_v4l2_vidioc_s_hw_freq_seek(struct file *file, void *priv,
+ struct v4l2_hw_freq_seek *seek)
+{
+ struct fmdev *fmdev = video_drvdata(file);
+ int ret;
+
+ if (fmdev->curr_fmmode != FM_MODE_RX) {
+ ret = fmc_set_mode(fmdev, FM_MODE_RX);
+ if (ret != 0) {
+ fmerr("Failed to set RX mode\n");
+ return ret;
+ }
+ }
+
+ ret = fm_rx_seek(fmdev, seek->seek_upward, seek->wrap_around,
+ seek->spacing);
+ if (ret < 0)
+ fmerr("RX seek failed - %d\n", ret);
+
+ return ret;
+}
+/* Get modulator attributes. If mode is not TX, return no attributes. */
+static int fm_v4l2_vidioc_g_modulator(struct file *file, void *priv,
+ struct v4l2_modulator *mod)
+{
+ struct fmdev *fmdev = video_drvdata(file);;
+
+ if (mod->index != 0)
+ return -EINVAL;
+
+ if (fmdev->curr_fmmode != FM_MODE_TX)
+ return -EPERM;
+
+ mod->txsubchans = ((fmdev->tx_data.aud_mode == FM_STEREO_MODE) ?
+ V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO) |
+ ((fmdev->tx_data.rds.flag == FM_RDS_ENABLE) ?
+ V4L2_TUNER_SUB_RDS : 0);
+
+ mod->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
+ V4L2_TUNER_CAP_LOW;
+
+ return 0;
+}
+
+/* Set modulator attributes. If mode is not TX, set to TX. */
+static int fm_v4l2_vidioc_s_modulator(struct file *file, void *priv,
+ struct v4l2_modulator *mod)
+{
+ struct fmdev *fmdev = video_drvdata(file);
+ u8 rds_mode;
+ u16 aud_mode;
+ int ret;
+
+ if (mod->index != 0)
+ return -EINVAL;
+
+ if (fmdev->curr_fmmode != FM_MODE_TX) {
+ ret = fmc_set_mode(fmdev, FM_MODE_TX);
+ if (ret != 0) {
+ fmerr("Failed to set TX mode\n");
+ return ret;
+ }
+ }
+
+ aud_mode = (mod->txsubchans & V4L2_TUNER_SUB_STEREO) ?
+ FM_STEREO_MODE : FM_MONO_MODE;
+ rds_mode = (mod->txsubchans & V4L2_TUNER_SUB_RDS) ?
+ FM_RDS_ENABLE : FM_RDS_DISABLE;
+ ret = fm_tx_set_stereo_mono(fmdev, aud_mode);
+ if (ret < 0) {
+ fmerr("Failed to set mono/stereo mode for TX\n");
+ return ret;
+ }
+ ret = fm_tx_set_rds_mode(fmdev, rds_mode);
+ if (ret < 0)
+ fmerr("Failed to set rds mode for TX\n");
+
+ return ret;
+}
+
+static const struct v4l2_file_operations fm_drv_fops = {
+ .owner = THIS_MODULE,
+ .read = fm_v4l2_fops_read,
+ .write = fm_v4l2_fops_write,
+ .poll = fm_v4l2_fops_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .open = fm_v4l2_fops_open,
+ .release = fm_v4l2_fops_release,
+};
+
+static const struct v4l2_ctrl_ops fm_ctrl_ops = {
+ .s_ctrl = fm_v4l2_s_ctrl,
+ .g_volatile_ctrl = fm_g_volatile_ctrl,
+};
+static const struct v4l2_ioctl_ops fm_drv_ioctl_ops = {
+ .vidioc_querycap = fm_v4l2_vidioc_querycap,
+ .vidioc_g_audio = fm_v4l2_vidioc_g_audio,
+ .vidioc_s_audio = fm_v4l2_vidioc_s_audio,
+ .vidioc_g_tuner = fm_v4l2_vidioc_g_tuner,
+ .vidioc_s_tuner = fm_v4l2_vidioc_s_tuner,
+ .vidioc_g_frequency = fm_v4l2_vidioc_g_freq,
+ .vidioc_s_frequency = fm_v4l2_vidioc_s_freq,
+ .vidioc_s_hw_freq_seek = fm_v4l2_vidioc_s_hw_freq_seek,
+ .vidioc_g_modulator = fm_v4l2_vidioc_g_modulator,
+ .vidioc_s_modulator = fm_v4l2_vidioc_s_modulator
+};
+
+/* V4L2 RADIO device parent structure */
+static struct video_device fm_viddev_template = {
+ .fops = &fm_drv_fops,
+ .ioctl_ops = &fm_drv_ioctl_ops,
+ .name = FM_DRV_NAME,
+ .release = video_device_release,
+};
+
+int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
+{
+ struct v4l2_ctrl *ctrl;
+ int ret;
+
+ /* Init mutex for core locking */
+ mutex_init(&fmdev->mutex);
+
+ /* Allocate new video device */
+ gradio_dev = video_device_alloc();
+ if (NULL == gradio_dev) {
+ fmerr("Can't allocate video device\n");
+ return -ENOMEM;
+ }
+
+ /* Setup FM driver's V4L2 properties */
+ memcpy(gradio_dev, &fm_viddev_template, sizeof(fm_viddev_template));
+
+ video_set_drvdata(gradio_dev, fmdev);
+
+ gradio_dev->lock = &fmdev->mutex;
+
+ /* Register with V4L2 subsystem as RADIO device */
+ if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) {
+ video_device_release(gradio_dev);
+ fmerr("Could not register video device\n");
+ return -ENOMEM;
+ }
+
+ fmdev->radio_dev = gradio_dev;
+
+ /* Register to v4l2 ctrl handler framework */
+ fmdev->radio_dev->ctrl_handler = &fmdev->ctrl_handler;
+
+ ret = v4l2_ctrl_handler_init(&fmdev->ctrl_handler, 5);
+ if (ret < 0) {
+ fmerr("(fmdev): Can't init ctrl handler\n");
+ v4l2_ctrl_handler_free(&fmdev->ctrl_handler);
+ return -EBUSY;
+ }
+
+ /*
+ * Following controls are handled by V4L2 control framework.
+ * Added in ascending ID order.
+ */
+ v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, FM_RX_VOLUME_MIN,
+ FM_RX_VOLUME_MAX, 1, FM_RX_VOLUME_MAX);
+
+ v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+
+ v4l2_ctrl_new_std_menu(&fmdev->ctrl_handler, &fm_ctrl_ops,
+ V4L2_CID_TUNE_PREEMPHASIS, V4L2_PREEMPHASIS_75_uS,
+ 0, V4L2_PREEMPHASIS_75_uS);
+
+ v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops,
+ V4L2_CID_TUNE_POWER_LEVEL, FM_PWR_LVL_LOW,
+ FM_PWR_LVL_HIGH, 1, FM_PWR_LVL_HIGH);
+
+ ctrl = v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops,
+ V4L2_CID_TUNE_ANTENNA_CAPACITOR, 0,
+ 255, 1, 255);
+
+ if (ctrl)
+ ctrl->is_volatile = 1;
+
+ return 0;
+}
+
+void *fm_v4l2_deinit_video_device(void)
+{
+ struct fmdev *fmdev;
+
+
+ fmdev = video_get_drvdata(gradio_dev);
+
+ /* Unregister to v4l2 ctrl handler framework*/
+ v4l2_ctrl_handler_free(&fmdev->ctrl_handler);
+
+ /* Unregister RADIO device from V4L2 subsystem */
+ video_unregister_device(gradio_dev);
+
+ return fmdev;
+}
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.h b/drivers/media/radio/wl128x/fmdrv_v4l2.h
new file mode 100644
index 00000000000..0ba79d745e2
--- /dev/null
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.h
@@ -0,0 +1,33 @@
+/*
+ * FM Driver for Connectivity chip of Texas Instruments.
+ *
+ * FM V4L2 module header.
+ *
+ * Copyright (C) 2011 Texas Instruments
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _FMDRV_V4L2_H
+#define _FMDRV_V4L2_H
+
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+
+int fm_v4l2_init_video_device(struct fmdev *, int);
+void *fm_v4l2_deinit_video_device(void);
+
+#endif
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index a509d317e25..10bf2f26004 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -168,6 +168,7 @@ obj-$(CONFIG_VIDEO_SAA7164) += saa7164/
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-y += davinci/
+obj-$(CONFIG_TI_TILER) += tiler/
obj-$(CONFIG_ARCH_OMAP) += omap/
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
index 029a4babfd6..de08878f73c 100644
--- a/drivers/media/video/omap/omap_vout.c
+++ b/drivers/media/video/omap/omap_vout.c
@@ -125,8 +125,8 @@ module_param(vid2_static_vrfb_alloc, bool, S_IRUGO);
MODULE_PARM_DESC(vid2_static_vrfb_alloc,
"Static allocation of the VRFB buffer for video2 device");
-module_param(debug, bool, S_IRUGO);
-MODULE_PARM_DESC(debug, "Debug level (0-1)");
+module_param(debug, int, S_IRUGO);
+MODULE_PARM_DESC(debug, "Debug level");
/* list of image formats supported by OMAP2 video pipelines */
const static struct v4l2_fmtdesc omap_formats[] = {
@@ -2235,6 +2235,8 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
mutex_init(&vout->lock);
vfd->minor = -1;
+ vfd->debug = debug;
+
return 0;
}
diff --git a/drivers/media/video/tiler/Kconfig b/drivers/media/video/tiler/Kconfig
new file mode 100644
index 00000000000..00461eb5b5a
--- /dev/null
+++ b/drivers/media/video/tiler/Kconfig
@@ -0,0 +1,126 @@
+config HAVE_TI_TILER
+ bool
+ default y
+ depends on ARCH_OMAP4
+
+menuconfig TI_TILER
+ tristate "TI TILER support"
+ default y
+ depends on HAVE_TI_TILER
+ help
+ TILER and TILER-DMM driver for TI chips. The TI TILER device
+ enables video rotation on certain TI chips such as OMAP4 or
+ Netra. Video rotation will be limited without TILER support.
+
+config TILER_GRANULARITY
+ int "Allocation granularity (2^n)"
+ range 1 4096
+ default 128
+ depends on TI_TILER
+ help
+ This option sets the default TILER allocation granularity. It can
+ be overriden by the tiler.grain boot argument.
+
+ The allocation granularity is the smallest TILER block size (in
+ bytes) managed distinctly by the TILER driver. TILER blocks of any
+ size are managed in chunks of at least this size.
+
+ Must be a 2^n in the range of 1 to 4096; however, the TILER driver
+ may use a larger supported granularity.
+
+ Supported values are: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
+ 2048, 4096.
+
+config TILER_ALIGNMENT
+ int "Allocation alignment (2^n)"
+ range 1 4096
+ default 4096
+ depends on TI_TILER
+ help
+ This option sets the default TILER allocation alignment. It can
+ be overriden by the tiler.align boot argument.
+
+ Must be a 2^n in the range of 1 to 4096; however, it is naturally
+ aligned to the TILER granularity.
+
+ Supported values are: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
+ 2048, 4096.
+
+config TILER_CACHE_LIMIT
+ int "Memory limit to cache free pages in MBytes"
+ range 0 128
+ default 40
+ depends on TI_TILER
+ help
+ This option sets the minimum memory that TILER retains even if
+ there is less TILER allocated memory is use. The unused memory is
+ instead stored in a cache to speed up allocation and freeing of
+ physical pages.
+
+ This option can be overriden by the tiler.cache boot argument.
+
+ While initially TILER will use less memory than this limit (0), it
+ will not release any memory used until it reaches this limit.
+ Thereafter, TILER will release any unused memory immediately as
+ long as there it is above this threshold.
+
+config TILER_SECURITY
+ int "Process security"
+ range 0 1
+ default 1
+ depends on TI_TILER
+ help
+ This option sets the default TILER process security. It can be
+ overriden by the tiler.secure boot argument.
+
+ If process security is enabled (1), the TILER driver uses a separate
+ TILER buffer address spaces (for mmap purposes) for each process.
+ This means that one process cannot simply map another process's
+ TILER buffer into its memory, even for sharing. However, it can
+ recreate the buffer by knowing the id-s and secret keys for the
+ TILER blocks involved. This is the preferred configuration.
+
+ Disabling security (0) allows sharing buffers simply by sharing the
+ mmap offset and size. However, because buffers can potentially be
+ shared between processes, it delays resource cleanup while any
+ process has an open TILER device.
+
+config TILER_SSPTR_ID
+ int "Use SSPtr for id"
+ range 0 1
+ default 1
+ depends on TI_TILER
+ help
+ This option sets the default behavior for TILER block ids. It can
+ be overriden by the tiler.ssptr_id boot argument.
+
+ If true, TILER driver uses the system-space (physical) address
+ (SSPtr) of a TILER block as its unique id. This may help sharing
+ TILER blocks between co-processors if using a constant key for each
+ block.
+
+ Note that the SSPtr is unique for each TILER block.
+
+config TILER_SECURE
+ bool "Secure TILER build"
+ default n
+ depends on TI_TILER
+ help
+ This option forces TILER security features that bypasses module
+ parameters.
+
+ If set, process security will be hardwired and ssptr and offset
+ lookup APIs are removed.
+
+config TILER_EXPOSE_SSPTR
+ bool "Expose SSPtr to userspace"
+ default y
+ depends on TI_TILER
+ help
+ This option sets whether SSPtr-s for blocks are exposed
+ during TILIOC_GBLK ioctls (MemMgr_Alloc APIs). In a secure
+ TILER build, this may be the only way for the userspace code
+ to learn the system-space addresses of TILER blocks.
+
+ You can use this flag to see if the userspace is relying on
+ having access to the SSPtr.
diff --git a/drivers/media/video/tiler/Makefile b/drivers/media/video/tiler/Makefile
new file mode 100644
index 00000000000..b3276440304
--- /dev/null
+++ b/drivers/media/video/tiler/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_TI_TILER) += tcm/
+
+obj-$(CONFIG_TI_TILER) += tiler.o
+tiler-objs = tiler-geom.o tiler-main.o tiler-iface.o tiler-reserve.o tmm-pat.o
+
+obj-$(CONFIG_TI_TILER) += tiler_dmm.o
+tiler_dmm-objs = dmm.o
+
diff --git a/drivers/media/video/tiler/_tiler.h b/drivers/media/video/tiler/_tiler.h
new file mode 100644
index 00000000000..aeec9f6de6e
--- /dev/null
+++ b/drivers/media/video/tiler/_tiler.h
@@ -0,0 +1,148 @@
+/*
+ * _tiler.h
+ *
+ * TI TILER driver internal shared definitions.
+ *
+ * Author: Lajos Molnar <molnar@ti.com>
+ *
+ * Copyright (C) 2009-2010 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 _TILER_H
+#define _TILER_H
+
+#include <linux/kernel.h>
+#include <mach/tiler.h>
+#include "tcm.h"
+
+#define TILER_FORMATS (TILFMT_MAX - TILFMT_MIN + 1)
+
+/* per process (thread group) info */
+struct process_info {
+ struct list_head list; /* other processes */
+ struct list_head groups; /* my groups */
+ struct list_head bufs; /* my registered buffers */
+ pid_t pid; /* really: thread group ID */
+ u32 refs; /* open tiler devices, 0 for processes
+ tracked via kernel APIs */
+ bool kernel; /* tracking kernel objects */
+};
+
+/* per group info (within a process) */
+struct gid_info {
+ struct list_head by_pid; /* other groups */
+ struct list_head areas; /* all areas in this pid/gid */
+ struct list_head reserved; /* areas pre-reserved */
+ struct list_head onedim; /* all 1D areas in this pid/gid */
+ u32 gid; /* group ID */
+ int refs; /* instances directly using this ptr */
+ struct process_info *pi; /* parent */
+};
+
+/* info for an area reserved from a container */
+struct area_info {
+ struct list_head by_gid; /* areas in this pid/gid */
+ struct list_head blocks; /* blocks in this area */
+ u32 nblocks; /* # of blocks in this area */
+
+ struct tcm_area area; /* area details */
+ struct gid_info *gi; /* link to parent, if still alive */
+};
+
+/* info for a block */
+struct mem_info {
+ struct list_head global; /* reserved / global blocks */
+ struct tiler_block_t blk; /* block info */
+ u32 num_pg; /* number of pages in page-list */
+ u32 usr; /* user space address */
+ u32 *pg_ptr; /* list of mapped struct page ptrs */
+ struct tcm_area area;
+ u32 *mem; /* list of alloced phys addresses */
+ int refs; /* number of times referenced */
+ bool alloced; /* still alloced */
+
+ struct list_head by_area; /* blocks in the same area / 1D */
+ void *parent; /* area info for 2D, else group info */
+};
+
+/* tiler geometry information */
+struct tiler_geom {
+ u32 x_shft; /* unused X-bits (as part of bpp) */
+ u32 y_shft; /* unused Y-bits (as part of bpp) */
+ u32 bpp; /* bytes per pixel */
+ u32 slot_w; /* width of each slot (in pixels) */
+ u32 slot_h; /* height of each slot (in pixels) */
+ u32 bpp_m; /* modified bytes per pixel (=1 for page mode) */
+};
+
+/* methods and variables shared between source files */
+struct tiler_ops {
+ /* block operations */
+ s32 (*alloc) (enum tiler_fmt fmt, u32 width, u32 height,
+ u32 align, u32 offs, u32 key,
+ u32 gid, struct process_info *pi,
+ struct mem_info **info);
+ s32 (*map) (enum tiler_fmt fmt, u32 width, u32 height,
+ u32 key, u32 gid, struct process_info *pi,
+ struct mem_info **info, u32 usr_addr);
+ void (*reserve_nv12) (u32 n, u32 width, u32 height, u32 align, u32 offs,
+ u32 gid, struct process_info *pi);
+ void (*reserve) (u32 n, enum tiler_fmt fmt, u32 width, u32 height,
+ u32 align, u32 offs, u32 gid, struct process_info *pi);
+ void (*unreserve) (u32 gid, struct process_info *pi);
+
+ /* block access operations */
+ struct mem_info * (*lock) (u32 key, u32 id, struct gid_info *gi);
+ struct mem_info * (*lock_by_ssptr) (u32 sys_addr);
+ void (*describe) (struct mem_info *i, struct tiler_block_info *blk);
+ void (*unlock_free) (struct mem_info *mi, bool free);
+
+ s32 (*lay_2d) (enum tiler_fmt fmt, u16 n, u16 w, u16 h, u16 band,
+ u16 align, u16 offs, struct gid_info *gi,
+ struct list_head *pos);
+ s32 (*lay_nv12) (int n, u16 w, u16 w1, u16 h, struct gid_info *gi,
+ u8 *p);
+ /* group operations */
+ struct gid_info * (*get_gi) (struct process_info *pi, u32 gid);
+ void (*release_gi) (struct gid_info *gi);
+ void (*destroy_group) (struct gid_info *pi);
+
+ /* group access operations */
+ void (*add_reserved) (struct list_head *reserved, struct gid_info *gi);
+ void (*release) (struct list_head *reserved);
+
+ /* area operations */
+ s32 (*analize) (enum tiler_fmt fmt, u32 width, u32 height,
+ u16 *x_area, u16 *y_area, u16 *band,
+ u16 *align, u16 *offs, u16 *in_offs);
+
+ /* process operations */
+ void (*cleanup) (void);
+
+ /* geometry operations */
+ void (*xy) (u32 ssptr, u32 *x, u32 *y);
+ u32 (*addr) (enum tiler_fmt fmt, u32 x, u32 y);
+ const struct tiler_geom * (*geom) (enum tiler_fmt fmt);
+
+ /* additional info */
+ const struct file_operations *fops;
+
+ bool nv12_packed; /* whether NV12 is packed into same container */
+ u32 page; /* page size */
+ u32 width; /* container width */
+ u32 height; /* container height */
+};
+
+void tiler_iface_init(struct tiler_ops *tiler);
+void tiler_geom_init(struct tiler_ops *tiler);
+void tiler_reserve_init(struct tiler_ops *tiler);
+
+#endif
diff --git a/drivers/media/video/tiler/dmm.c b/drivers/media/video/tiler/dmm.c
new file mode 100644
index 00000000000..5ca5e7d5fa3
--- /dev/null
+++ b/drivers/media/video/tiler/dmm.c
@@ -0,0 +1,231 @@
+/*
+ * dmm.c
+ *
+ * DMM driver support functions for TI OMAP processors.
+ *
+ * Authors: David Sin <davidsin@ti.com>
+ * Lajos Molnar <molnar@ti.com>
+ *
+ * Copyright (C) 2009-2010 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h> /* platform_device() */
+#include <linux/io.h> /* ioremap() */
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <mach/dmm.h>
+
+#undef __DEBUG__
+
+#define MASK(msb, lsb) (((1 << ((msb) + 1 - (lsb))) - 1) << (lsb))
+#define SET_FLD(reg, msb, lsb, val) \
+(((reg) & ~MASK((msb), (lsb))) | (((val) << (lsb)) & MASK((msb), (lsb))))
+
+#ifdef __DEBUG__
+#define DEBUG(x, y) printk(KERN_NOTICE "%s()::%d:%s=(0x%08x)\n", \
+ __func__, __LINE__, x, (s32)y);
+#else
+#define DEBUG(x, y)
+#endif
+
+static struct platform_driver dmm_driver_ldm = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "dmm",
+ },
+ .probe = NULL,
+ .shutdown = NULL,
+ .remove = NULL,
+};
+
+s32 dmm_pat_refill(struct dmm *dmm, struct pat *pd, enum pat_mode mode)
+{
+ void __iomem *r;
+ u32 v;
+
+ /* Only manual refill supported */
+ if (mode != MANUAL)
+ return -EFAULT;
+
+ /* Check that the DMM_PAT_STATUS register has not reported an error */
+ r = dmm->base + DMM_PAT_STATUS__0;
+ v = __raw_readl(r);
+ if ((v & 0xFC00) != 0) {
+ while (1)
+ printk(KERN_ERR "dmm_pat_refill() error.\n");
+ }
+
+ /* Set "next" register to NULL */
+ r = dmm->base + DMM_PAT_DESCR__0;
+ v = __raw_readl(r);
+ v = SET_FLD(v, 31, 4, (u32) NULL);
+ __raw_writel(v, r);
+
+ /* Set area to be refilled */
+ r = dmm->base + DMM_PAT_AREA__0;
+ v = __raw_readl(r);
+ v = SET_FLD(v, 30, 24, pd->area.y1);
+ v = SET_FLD(v, 23, 16, pd->area.x1);
+ v = SET_FLD(v, 14, 8, pd->area.y0);
+ v = SET_FLD(v, 7, 0, pd->area.x0);
+ __raw_writel(v, r);
+ wmb();
+
+#ifdef __DEBUG__
+ printk(KERN_NOTICE "\nx0=(%d),y0=(%d),x1=(%d),y1=(%d)\n",
+ (char)pd->area.x0,
+ (char)pd->area.y0,
+ (char)pd->area.x1,
+ (char)pd->area.y1);
+#endif
+
+ /* First, clear the DMM_PAT_IRQSTATUS register */
+ r = dmm->base + DMM_PAT_IRQSTATUS;
+ __raw_writel(0xFFFFFFFF, r);
+ wmb();
+
+ r = dmm->base + DMM_PAT_IRQSTATUS_RAW;
+ do {
+ v = __raw_readl(r);
+ DEBUG("DMM_PAT_IRQSTATUS_RAW", v);
+ } while (v != 0x0);
+
+ /* Fill data register */
+ r = dmm->base + DMM_PAT_DATA__0;
+ v = __raw_readl(r);
+
+ /* pd->data must be 16 aligned */
+ BUG_ON(pd->data & 15);
+ v = SET_FLD(v, 31, 4, pd->data >> 4);
+ __raw_writel(v, r);
+ wmb();
+
+ /* Read back PAT_DATA__0 to see if write was successful */
+ do {
+ v = __raw_readl(r);
+ DEBUG("DMM_PAT_DATA__0", v);
+ } while (v != pd->data);
+
+ r = dmm->base + DMM_PAT_CTRL__0;
+ v = __raw_readl(r);
+ v = SET_FLD(v, 31, 28, pd->ctrl.ini);
+ v = SET_FLD(v, 16, 16, pd->ctrl.sync);
+ v = SET_FLD(v, 9, 8, pd->ctrl.lut_id);
+ v = SET_FLD(v, 6, 4, pd->ctrl.dir);
+ v = SET_FLD(v, 0, 0, pd->ctrl.start);
+ __raw_writel(v, r);
+ wmb();
+
+ /* Check if PAT_IRQSTATUS_RAW is set after the PAT has been refilled */
+ r = dmm->base + DMM_PAT_IRQSTATUS_RAW;
+ do {
+ v = __raw_readl(r);
+ DEBUG("DMM_PAT_IRQSTATUS_RAW", v);
+ } while ((v & 0x3) != 0x3);
+
+ /* Again, clear the DMM_PAT_IRQSTATUS register */
+ r = dmm->base + DMM_PAT_IRQSTATUS;
+ __raw_writel(0xFFFFFFFF, r);
+ wmb();
+
+ r = dmm->base + DMM_PAT_IRQSTATUS_RAW;
+ do {
+ v = __raw_readl(r);
+ DEBUG("DMM_PAT_IRQSTATUS_RAW", v);
+ } while (v != 0x0);
+
+ /* Again, set "next" register to NULL to clear any PAT STATUS errors */
+ r = dmm->base + DMM_PAT_DESCR__0;
+ v = __raw_readl(r);
+ v = SET_FLD(v, 31, 4, (u32) NULL);
+ __raw_writel(v, r);
+
+ /*
+ * Now, check that the DMM_PAT_STATUS register
+ * has not reported an error before exiting.
+ */
+ r = dmm->base + DMM_PAT_STATUS__0;
+ v = __raw_readl(r);
+ if ((v & 0xFC00) != 0) {
+ while (1)
+ printk(KERN_ERR "dmm_pat_refill() error.\n");
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(dmm_pat_refill);
+
+struct dmm *dmm_pat_init(u32 id)
+{
+ u32 base;
+ struct dmm *dmm;
+ switch (id) {
+ case 0:
+ /* only support id 0 for now */
+ base = DMM_BASE;
+ break;
+ default:
+ return NULL;
+ }
+
+ dmm = kmalloc(sizeof(*dmm), GFP_KERNEL);
+ if (!dmm)
+ return NULL;
+
+ dmm->base = ioremap(base, DMM_SIZE);
+ if (!dmm->base) {
+ kfree(dmm);
+ return NULL;
+ }
+
+ __raw_writel(0x88888888, dmm->base + DMM_PAT_VIEW__0);
+ __raw_writel(0x88888888, dmm->base + DMM_PAT_VIEW__1);
+ __raw_writel(0x80808080, dmm->base + DMM_PAT_VIEW_MAP__0);
+ __raw_writel(0x80000000, dmm->base + DMM_PAT_VIEW_MAP_BASE);
+ __raw_writel(0x88888888, dmm->base + DMM_TILER_OR__0);
+ __raw_writel(0x88888888, dmm->base + DMM_TILER_OR__1);
+
+ return dmm;
+}
+EXPORT_SYMBOL(dmm_pat_init);
+
+/**
+ * Clean up the physical address translator.
+ * @param dmm Device data
+ * @return an error status.
+ */
+void dmm_pat_release(struct dmm *dmm)
+{
+ if (dmm) {
+ iounmap(dmm->base);
+ kfree(dmm);
+ }
+}
+EXPORT_SYMBOL(dmm_pat_release);
+
+static s32 __init dmm_init(void)
+{
+ return platform_driver_register(&dmm_driver_ldm);
+}
+
+static void __exit dmm_exit(void)
+{
+ platform_driver_unregister(&dmm_driver_ldm);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("davidsin@ti.com");
+MODULE_AUTHOR("molnar@ti.com");
+module_init(dmm_init);
+module_exit(dmm_exit);
diff --git a/drivers/media/video/tiler/tcm.h b/drivers/media/video/tiler/tcm.h
new file mode 100644
index 00000000000..68b0d684dd5
--- /dev/null
+++ b/drivers/media/video/tiler/tcm.h
@@ -0,0 +1,309 @@
+/*
+ * tcm.h
+ *
+ * TILER container manager specification and support functions for TI
+ * TILER driver.
+ *
+ * Author: Lajos Molnar <molnar@ti.com>
+ *
+ * Copyright (C) 2009-2010 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 TCM_H
+#define TCM_H
+
+struct tcm;
+
+/* point */
+struct tcm_pt {
+ u16 x;
+ u16 y;
+};
+
+/* 1d or 2d area */
+struct tcm_area {
+ bool is2d; /* whether are is 1d or 2d */
+ struct tcm *tcm; /* parent */
+ struct tcm_pt p0;
+ struct tcm_pt p1;
+};
+
+struct tcm {
+ u16 width, height; /* container dimensions */
+
+ /* 'pvt' structure shall contain any tcm details (attr) along with
+ linked list of allocated areas and mutex for mutually exclusive access
+ to the list. It may also contain copies of width and height to notice
+ any changes to the publicly available width and height fields. */
+ void *pvt;
+
+ /* function table */
+ s32 (*reserve_2d)(struct tcm *tcm, u16 height, u16 width, u8 align,
+ struct tcm_area *area);
+ s32 (*reserve_1d)(struct tcm *tcm, u32 slots, struct tcm_area *area);
+ s32 (*free) (struct tcm *tcm, struct tcm_area *area);
+ void (*deinit) (struct tcm *tcm);
+};
+
+/*=============================================================================
+ BASIC TILER CONTAINER MANAGER INTERFACE
+=============================================================================*/
+
+/*
+ * NOTE:
+ *
+ * Since some basic parameter checking is done outside the TCM algorithms,
+ * TCM implementation do NOT have to check the following:
+ *
+ * area pointer is NULL
+ * width and height fits within container
+ * number of pages is more than the size of the container
+ *
+ */
+
+/**
+ * Template for <ALGO_NAME>_tcm_init method. Define as:
+ * TCM_INIT(<ALGO_NAME>_tcm_init)
+ *
+ * Allocates and initializes a tiler container manager.
+ *
+ * @param width Width of container
+ * @param height Height of container
+ * @param attr Container manager specific configuration
+ * arguments. Please describe these in
+ * your header file.
+ *
+ * @return Pointer to the allocated and initialized container
+ * manager. NULL on failure. DO NOT leak any memory on
+ * failure!
+ */
+#define TCM_INIT(name, attr_t) \
+struct tcm *name(u16 width, u16 height, typeof(attr_t) *attr);
+
+/**
+ * Deinitialize tiler container manager.
+ *
+ * @param tcm Pointer to container manager.
+ *
+ * @return 0 on success, non-0 error value on error. The call
+ * should free as much memory as possible and meaningful
+ * even on failure. Some error codes: -ENODEV: invalid
+ * manager.
+ */
+static inline void tcm_deinit(struct tcm *tcm)
+{
+ if (tcm)
+ tcm->deinit(tcm);
+}
+
+/**
+ * Reserves a 2D area in the container.
+ *
+ * @param tcm Pointer to container manager.
+ * @param height Height(in pages) of area to be reserved.
+ * @param width Width(in pages) of area to be reserved.
+ * @param align Alignment requirement for top-left corner of area. Not
+ * all values may be supported by the container manager,
+ * but it must support 0 (1), 32 and 64.
+ * 0 value is equivalent to 1.
+ * @param area Pointer to where the reserved area should be stored.
+ *
+ * @return 0 on success. Non-0 error code on failure. Also,
+ * the tcm field of the area will be set to NULL on
+ * failure. Some error codes: -ENODEV: invalid manager,
+ * -EINVAL: invalid area, -ENOMEM: not enough space for
+ * allocation.
+ */
+static inline s32 tcm_reserve_2d(struct tcm *tcm, u16 width, u16 height,
+ u16 align, struct tcm_area *area)
+{
+ /* perform rudimentary error checking */
+ s32 res = tcm == NULL ? -ENODEV :
+ (area == NULL || width == 0 || height == 0 ||
+ /* align must be a 2 power */
+ align & (align - 1)) ? -EINVAL :
+ (height > tcm->height || width > tcm->width) ? -ENOMEM : 0;
+
+ if (!res) {
+ area->is2d = true;
+ res = tcm->reserve_2d(tcm, height, width, align, area);
+ area->tcm = res ? NULL : tcm;
+ }
+
+ return res;
+}
+
+/**
+ * Reserves a 1D area in the container.
+ *
+ * @param tcm Pointer to container manager.
+ * @param slots Number of (contiguous) slots to reserve.
+ * @param area Pointer to where the reserved area should be stored.
+ *
+ * @return 0 on success. Non-0 error code on failure. Also,
+ * the tcm field of the area will be set to NULL on
+ * failure. Some error codes: -ENODEV: invalid manager,
+ * -EINVAL: invalid area, -ENOMEM: not enough space for
+ * allocation.
+ */
+static inline s32 tcm_reserve_1d(struct tcm *tcm, u32 slots,
+ struct tcm_area *area)
+{
+ /* perform rudimentary error checking */
+ s32 res = tcm == NULL ? -ENODEV :
+ (area == NULL || slots == 0) ? -EINVAL :
+ slots > (tcm->width * (u32) tcm->height) ? -ENOMEM : 0;
+
+ if (!res) {
+ area->is2d = false;
+ res = tcm->reserve_1d(tcm, slots, area);
+ area->tcm = res ? NULL : tcm;
+ }
+
+ return res;
+}
+
+/**
+ * Free a previously reserved area from the container.
+ *
+ * @param area Pointer to area reserved by a prior call to
+ * tcm_reserve_1d or tcm_reserve_2d call, whether
+ * it was successful or not. (Note: all fields of
+ * the structure must match.)
+ *
+ * @return 0 on success. Non-0 error code on failure. Also, the tcm
+ * field of the area is set to NULL on success to avoid subsequent
+ * freeing. This call will succeed even if supplying
+ * the area from a failed reserved call.
+ */
+static inline s32 tcm_free(struct tcm_area *area)
+{
+ s32 res = 0; /* free succeeds by default */
+
+ if (area && area->tcm) {
+ res = area->tcm->free(area->tcm, area);
+ if (res == 0)
+ area->tcm = NULL;
+ }
+
+ return res;
+}
+
+/*=============================================================================
+ HELPER FUNCTION FOR ANY TILER CONTAINER MANAGER
+=============================================================================*/
+
+/**
+ * This method slices off the topmost 2D slice from the parent area, and stores
+ * it in the 'slice' parameter. The 'parent' parameter will get modified to
+ * contain the remaining portion of the area. If the whole parent area can
+ * fit in a 2D slice, its tcm pointer is set to NULL to mark that it is no
+ * longer a valid area.
+ *
+ * @param parent Pointer to a VALID parent area that will get modified
+ * @param slice Pointer to the slice area that will get modified
+ */
+static inline void tcm_slice(struct tcm_area *parent, struct tcm_area *slice)
+{
+ *slice = *parent;
+
+ /* check if we need to slice */
+ if (slice->tcm && !slice->is2d &&
+ slice->p0.y != slice->p1.y &&
+ (slice->p0.x || (slice->p1.x != slice->tcm->width - 1))) {
+ /* set end point of slice (start always remains) */
+ slice->p1.x = slice->tcm->width - 1;
+ slice->p1.y = (slice->p0.x) ? slice->p0.y : slice->p1.y - 1;
+ /* adjust remaining area */
+ parent->p0.x = 0;
+ parent->p0.y = slice->p1.y + 1;
+ } else {
+ /* mark this as the last slice */
+ parent->tcm = NULL;
+ }
+}
+
+/* Verify if a tcm area is logically valid */
+static inline bool tcm_area_is_valid(struct tcm_area *area)
+{
+ return area && area->tcm &&
+ /* coordinate bounds */
+ area->p1.x < area->tcm->width &&
+ area->p1.y < area->tcm->height &&
+ area->p0.y <= area->p1.y &&
+ /* 1D coordinate relationship + p0.x check */
+ ((!area->is2d &&
+ area->p0.x < area->tcm->width &&
+ area->p0.x + area->p0.y * area->tcm->width <=
+ area->p1.x + area->p1.y * area->tcm->width) ||
+ /* 2D coordinate relationship */
+ (area->is2d &&
+ area->p0.x <= area->p1.x));
+}
+
+/* see if a coordinate is within an area */
+static inline bool __tcm_is_in(struct tcm_pt *p, struct tcm_area *a)
+{
+ u16 i;
+
+ if (a->is2d) {
+ return p->x >= a->p0.x && p->x <= a->p1.x &&
+ p->y >= a->p0.y && p->y <= a->p1.y;
+ } else {
+ i = p->x + p->y * a->tcm->width;
+ return i >= a->p0.x + a->p0.y * a->tcm->width &&
+ i <= a->p1.x + a->p1.y * a->tcm->width;
+ }
+}
+
+/* calculate area width */
+static inline u16 __tcm_area_width(struct tcm_area *area)
+{
+ return area->p1.x - area->p0.x + 1;
+}
+
+/* calculate area height */
+static inline u16 __tcm_area_height(struct tcm_area *area)
+{
+ return area->p1.y - area->p0.y + 1;
+}
+
+/* calculate number of slots in an area */
+static inline u16 __tcm_sizeof(struct tcm_area *area)
+{
+ return area->is2d ?
+ __tcm_area_width(area) * __tcm_area_height(area) :
+ (area->p1.x - area->p0.x + 1) + (area->p1.y - area->p0.y) *
+ area->tcm->width;
+}
+#define tcm_sizeof(area) __tcm_sizeof(&(area))
+#define tcm_awidth(area) __tcm_area_width(&(area))
+#define tcm_aheight(area) __tcm_area_height(&(area))
+#define tcm_is_in(pt, area) __tcm_is_in(&(pt), &(area))
+
+/**
+ * Iterate through 2D slices of a valid area. Behaves
+ * syntactically as a for(;;) statement.
+ *
+ * @param var Name of a local variable of type 'struct
+ * tcm_area *' that will get modified to
+ * contain each slice.
+ * @param area Pointer to the VALID parent area. This
+ * structure will not get modified
+ * throughout the loop.
+ *
+ */
+#define tcm_for_each_slice(var, area, safe) \
+ for (safe = area, \
+ tcm_slice(&safe, &var); \
+ var.tcm; tcm_slice(&safe, &var))
+
+#endif
diff --git a/drivers/media/video/tiler/tcm/Makefile b/drivers/media/video/tiler/tcm/Makefile
new file mode 100644
index 00000000000..efd62d77847
--- /dev/null
+++ b/drivers/media/video/tiler/tcm/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_TI_TILER) += tcm-sita.o
+
diff --git a/drivers/media/video/tiler/tcm/_tcm-sita.h b/drivers/media/video/tiler/tcm/_tcm-sita.h
new file mode 100644
index 00000000000..a300b923ef0
--- /dev/null
+++ b/drivers/media/video/tiler/tcm/_tcm-sita.h
@@ -0,0 +1,65 @@
+/*
+ * _tcm_sita.h
+ *
+ * SImple Tiler Allocator (SiTA) private structures.
+ *
+ * Author: Ravi Ramachandra <r.ramachandra@ti.com>
+ *
+ * Copyright (C) 2009-2010 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 _TCM_SITA_H
+#define _TCM_SITA_H
+
+#include "../tcm.h"
+
+/* length between two coordinates */
+#define LEN(a, b) ((a) > (b) ? (a) - (b) + 1 : (b) - (a) + 1)
+
+enum criteria {
+ CR_MAX_NEIGHS = 0x01,
+ CR_FIRST_FOUND = 0x10,
+ CR_BIAS_HORIZONTAL = 0x20,
+ CR_BIAS_VERTICAL = 0x40,
+ CR_DIAGONAL_BALANCE = 0x80
+};
+
+/* nearness to the beginning of the search field from 0 to 1000 */
+struct nearness_factor {
+ s32 x;
+ s32 y;
+};
+
+/*
+ * Statistics on immediately neighboring slots. Edge is the number of
+ * border segments that are also border segments of the scan field. Busy
+ * refers to the number of neighbors that are occupied.
+ */
+struct neighbor_stats {
+ u16 edge;
+ u16 busy;
+};
+
+/* structure to keep the score of a potential allocation */
+struct score {
+ struct nearness_factor f;
+ struct neighbor_stats n;
+ struct tcm_area a;
+ u16 neighs; /* number of busy neighbors */
+};
+
+struct sita_pvt {
+ struct mutex mtx;
+ struct tcm_pt div_pt; /* divider point splitting container */
+ struct tcm_area ***map; /* pointers to the parent area for each slot */
+};
+
+#endif
diff --git a/drivers/media/video/tiler/tcm/tcm-sita.c b/drivers/media/video/tiler/tcm/tcm-sita.c
new file mode 100644
index 00000000000..71b921308bb
--- /dev/null
+++ b/drivers/media/video/tiler/tcm/tcm-sita.c
@@ -0,0 +1,934 @@
+/*
+ * tcm-sita.c
+ *
+ * SImple Tiler Allocator (SiTA): 2D and 1D allocation(reservation) algorithm
+ *
+ * Authors: Ravi Ramachandra <r.ramachandra@ti.com>,
+ * Lajos Molnar <molnar@ti.com>
+ *
+ * Copyright (C) 2009-2010 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 <linux/slab.h>
+
+#include "_tcm-sita.h"
+#include "tcm-sita.h"
+
+#define TCM_ALG_NAME "tcm_sita"
+#include "tcm-utils.h"
+
+#define X_SCAN_LIMITER 1
+#define Y_SCAN_LIMITER 1
+
+#define ALIGN_DOWN(value, align) ((value) & ~((align) - 1))
+
+/* Individual selection criteria for different scan areas */
+static s32 CR_L2R_T2B = CR_BIAS_HORIZONTAL;
+static s32 CR_R2L_T2B = CR_DIAGONAL_BALANCE;
+#ifdef SCAN_BOTTOM_UP
+static s32 CR_R2L_B2T = CR_FIRST_FOUND;
+static s32 CR_L2R_B2T = CR_DIAGONAL_BALANCE;
+#endif
+
+/*********************************************
+ * TCM API - Sita Implementation
+ *********************************************/
+static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u8 align,
+ struct tcm_area *area);
+static s32 sita_reserve_1d(struct tcm *tcm, u32 slots, struct tcm_area *area);
+static s32 sita_free(struct tcm *tcm, struct tcm_area *area);
+static void sita_deinit(struct tcm *tcm);
+
+/*********************************************
+ * Main Scanner functions
+ *********************************************/
+static s32 scan_areas_and_find_fit(struct tcm *tcm, u16 w, u16 h, u16 align,
+ struct tcm_area *area);
+
+static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
+ struct tcm_area *field, struct tcm_area *area);
+
+static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
+ struct tcm_area *field, struct tcm_area *area);
+
+#ifdef SCAN_BOTTOM_UP
+static s32 scan_l2r_b2t(struct tcm *tcm, u16 w, u16 h, u16 align,
+ struct tcm_area *field, struct tcm_area *area);
+
+static s32 scan_r2l_b2t(struct tcm *tcm, u16 w, u16 h, u16 align,
+ struct tcm_area *field, struct tcm_area *area);
+#endif
+static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_slots,
+ struct tcm_area *field, struct tcm_area *area);
+
+/*********************************************
+ * Support Infrastructure Methods
+ *********************************************/
+static s32 is_area_free(struct tcm_area ***map, u16 x0, u16 y0, u16 w, u16 h);
+
+static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h,
+ struct tcm_area *field, s32 criteria,
+ struct score *best);
+
+static void get_nearness_factor(struct tcm_area *field,
+ struct tcm_area *candidate,
+ struct nearness_factor *nf);
+
+static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area,
+ struct neighbor_stats *stat);
+
+static void fill_area(struct tcm *tcm,
+ struct tcm_area *area, struct tcm_area *parent);
+
+/*********************************************/
+
+/*********************************************
+ * Utility Methods
+ *********************************************/
+struct tcm *sita_init(u16 width, u16 height, struct tcm_pt *attr)
+{
+ struct tcm *tcm;
+ struct sita_pvt *pvt;
+ struct tcm_area area = {0};
+ s32 i;
+
+ if (width == 0 || height == 0)
+ return NULL;
+
+ tcm = kmalloc(sizeof(*tcm), GFP_KERNEL);
+ pvt = kmalloc(sizeof(*pvt), GFP_KERNEL);
+ if (!tcm || !pvt)
+ goto error;
+
+ memset(tcm, 0, sizeof(*tcm));
+ memset(pvt, 0, sizeof(*pvt));
+
+ /* Updating the pointers to SiTA implementation APIs */
+ tcm->height = height;
+ tcm->width = width;
+ tcm->reserve_2d = sita_reserve_2d;
+ tcm->reserve_1d = sita_reserve_1d;
+ tcm->free = sita_free;
+ tcm->deinit = sita_deinit;
+ tcm->pvt = (void *)pvt;
+
+ mutex_init(&(pvt->mtx));
+
+ /* Creating tam map */
+ pvt->map = kmalloc(sizeof(*pvt->map) * tcm->width, GFP_KERNEL);
+ if (!pvt->map)
+ goto error;
+
+ for (i = 0; i < tcm->width; i++) {
+ pvt->map[i] =
+ kmalloc(sizeof(**pvt->map) * tcm->height,
+ GFP_KERNEL);
+ if (pvt->map[i] == NULL) {
+ while (i--)
+ kfree(pvt->map[i]);
+ kfree(pvt->map);
+ goto error;
+ }
+ }
+
+ if (attr && attr->x <= tcm->width && attr->y <= tcm->height) {
+ pvt->div_pt.x = attr->x;
+ pvt->div_pt.y = attr->y;
+
+ } else {
+ /* Defaulting to 3:1 ratio on width for 2D area split */
+ /* Defaulting to 3:1 ratio on height for 2D and 1D split */
+ pvt->div_pt.x = (tcm->width * 3) / 4;
+ pvt->div_pt.y = (tcm->height * 3) / 4;
+ }
+
+ mutex_lock(&(pvt->mtx));
+ assign(&area, 0, 0, width - 1, height - 1);
+ fill_area(tcm, &area, NULL);
+ mutex_unlock(&(pvt->mtx));
+ return tcm;
+
+error:
+ kfree(tcm);
+ kfree(pvt);
+ return NULL;
+}
+
+static void sita_deinit(struct tcm *tcm)
+{
+ struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+ struct tcm_area area = {0};
+ s32 i;
+
+ area.p1.x = tcm->width - 1;
+ area.p1.y = tcm->height - 1;
+
+ mutex_lock(&(pvt->mtx));
+ fill_area(tcm, &area, NULL);
+ mutex_unlock(&(pvt->mtx));
+
+ mutex_destroy(&(pvt->mtx));
+
+ for (i = 0; i < tcm->height; i++)
+ kfree(pvt->map[i]);
+ kfree(pvt->map);
+ kfree(pvt);
+}
+
+/**
+ * Reserve a 1D area in the container
+ *
+ * @param num_slots size of 1D area
+ * @param area pointer to the area that will be populated with the
+ * reserved area
+ *
+ * @return 0 on success, non-0 error value on failure.
+ */
+static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots,
+ struct tcm_area *area)
+{
+ s32 ret;
+ struct tcm_area field = {0};
+ struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+
+ mutex_lock(&(pvt->mtx));
+#ifdef RESTRICT_1D
+ /* scan within predefined 1D boundary */
+ assign(&field, tcm->width - 1, tcm->height - 1, 0, pvt->div_pt.y);
+#else
+ /* Scanning entire container */
+ assign(&field, tcm->width - 1, tcm->height - 1, 0, 0);
+#endif
+ ret = scan_r2l_b2t_one_dim(tcm, num_slots, &field, area);
+ if (!ret)
+ /* update map */
+ fill_area(tcm, area, area);
+
+ mutex_unlock(&(pvt->mtx));
+ return ret;
+}
+
+/**
+ * Reserve a 2D area in the container
+ *
+ * @param w width
+ * @param h height
+ * @param area pointer to the area that will be populated with the reesrved
+ * area
+ *
+ * @return 0 on success, non-0 error value on failure.
+ */
+static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u8 align,
+ struct tcm_area *area)
+{
+ s32 ret;
+ struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+
+ /* not supporting more than 64 as alignment */
+ if (align > 64)
+ return -EINVAL;
+
+ /* we prefer 1, 32 and 64 as alignment */
+ align = align <= 1 ? 1 : align <= 32 ? 32 : 64;
+
+ mutex_lock(&(pvt->mtx));
+ ret = scan_areas_and_find_fit(tcm, w, h, align, area);
+ if (!ret)
+ /* update map */
+ fill_area(tcm, area, area);
+
+ mutex_unlock(&(pvt->mtx));
+ return ret;
+}
+
+/**
+ * Unreserve a previously allocated 2D or 1D area
+ * @param area area to be freed
+ * @return 0 - success
+ */
+static s32 sita_free(struct tcm *tcm, struct tcm_area *area)
+{
+ struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+
+ mutex_lock(&(pvt->mtx));
+
+ /* check that this is in fact an existing area */
+ WARN_ON(pvt->map[area->p0.x][area->p0.y] != area ||
+ pvt->map[area->p1.x][area->p1.y] != area);
+
+ /* Clear the contents of the associated tiles in the map */
+ fill_area(tcm, area, NULL);
+
+ mutex_unlock(&(pvt->mtx));
+
+ return 0;
+}
+
+/**
+ * Note: In general the cordinates in the scan field area relevant to the can
+ * sweep directions. The scan origin (e.g. top-left corner) will always be
+ * the p0 member of the field. Therfore, for a scan from top-left p0.x <= p1.x
+ * and p0.y <= p1.y; whereas, for a scan from bottom-right p1.x <= p0.x and p1.y
+ * <= p0.y
+ */
+
+/**
+ * Raster scan horizontally right to left from top to bottom to find a place for
+ * a 2D area of given size inside a scan field.
+ *
+ * @param w width of desired area
+ * @param h height of desired area
+ * @param align desired area alignment
+ * @param area pointer to the area that will be set to the best position
+ * @param field area to scan (inclusive)
+ *
+ * @return 0 on success, non-0 error value on failure.
+ */
+static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
+ struct tcm_area *field, struct tcm_area *area)
+{
+ s32 x, y;
+ s16 start_x, end_x, start_y, end_y, found_x = -1;
+ struct tcm_area ***map = ((struct sita_pvt *)tcm->pvt)->map;
+ struct score best = {{0}, {0}, {0}, 0};
+
+ PA(2, "scan_r2l_t2b:", field);
+
+ start_x = field->p0.x;
+ end_x = field->p1.x;
+ start_y = field->p0.y;
+ end_y = field->p1.y;
+
+ /* check scan area co-ordinates */
+ if (field->p0.x < field->p1.x ||
+ field->p1.y < field->p0.y)
+ return -EINVAL;
+
+ /* check if allocation would fit in scan area */
+ if (w > LEN(start_x, end_x) || h > LEN(end_y, start_y))
+ return -ENOSPC;
+
+ /* adjust start_x and end_y, as allocation would not fit beyond */
+ start_x = ALIGN_DOWN(start_x - w + 1, align); /* - 1 to be inclusive */
+ end_y = end_y - h + 1;
+
+ /* check if allocation would still fit in scan area */
+ if (start_x < end_x)
+ return -ENOSPC;
+
+ P2("ali=%d x=%d..%d y=%d..%d", align, start_x, end_x, start_y, end_y);
+
+ /* scan field top-to-bottom, right-to-left */
+ for (y = start_y; y <= end_y; y++) {
+ for (x = start_x; x >= end_x; x -= align) {
+ if (is_area_free(map, x, y, w, h)) {
+ P3("found shoulder: %d,%d", x, y);
+ found_x = x;
+
+ /* update best candidate */
+ if (update_candidate(tcm, x, y, w, h, field,
+ CR_R2L_T2B, &best))
+ goto done;
+
+#ifdef X_SCAN_LIMITER
+ /* change upper x bound */
+ end_x = x + 1;
+#endif
+ break;
+ } else if (map[x][y] && map[x][y]->is2d) {
+ /* step over 2D areas */
+ x = ALIGN(map[x][y]->p0.x - w + 1, align);
+ P3("moving to: %d,%d", x, y);
+ }
+ }
+#ifdef Y_SCAN_LIMITER
+ /* break if you find a free area shouldering the scan field */
+ if (found_x == start_x)
+ break;
+#endif
+ }
+
+ if (!best.a.tcm)
+ return -ENOSPC;
+done:
+ assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y);
+ return 0;
+}
+
+#ifdef SCAN_BOTTOM_UP
+/**
+ * Raster scan horizontally right to left from bottom to top to find a place
+ * for a 2D area of given size inside a scan field.
+ *
+ * @param w width of desired area
+ * @param h height of desired area
+ * @param align desired area alignment
+ * @param area pointer to the area that will be set to the best position
+ * @param field area to scan (inclusive)
+ *
+ * @return 0 on success, non-0 error value on failure.
+ */
+static s32 scan_r2l_b2t(struct tcm *tcm, u16 w, u16 h, u16 align,
+ struct tcm_area *field, struct tcm_area *area)
+{
+ /* TODO: Should I check scan area?
+ * Might have to take it as input during initialization
+ */
+ s32 x, y;
+ s16 start_x, end_x, start_y, end_y, found_x = -1;
+ struct tcm_area ***map = ((struct sita_pvt *)tcm->pvt)->map;
+ struct score best = {{0}, {0}, {0}, 0};
+
+ PA(2, "scan_r2l_b2t:", field);
+
+ start_x = field->p0.x;
+ end_x = field->p1.x;
+ start_y = field->p0.y;
+ end_y = field->p1.y;
+
+ /* check scan area co-ordinates */
+ if (field->p1.x < field->p0.x ||
+ field->p1.y < field->p0.y)
+ return -EINVAL;
+
+ /* check if allocation would fit in scan area */
+ if (w > LEN(start_x, end_x) || h > LEN(start_y, end_y))
+ return -ENOSPC;
+
+ /* adjust start_x and start_y, as allocation would not fit beyond */
+ start_x = ALIGN_DOWN(start_x - w + 1, align); /* + 1 to be inclusive */
+ start_y = start_y - h + 1;
+
+ /* check if allocation would still fit in scan area */
+ if (start_x < end_x)
+ return -ENOSPC;
+
+ P2("ali=%d x=%d..%d y=%d..%d", align, start_x, end_x, start_y, end_y);
+
+ /* scan field bottom-to-top, right-to-left */
+ for (y = start_y; y >= end_y; y--) {
+ for (x = start_x; x >= end_x; x -= align) {
+ if (is_area_free(map, x, y, w, h)) {
+ P3("found shoulder: %d,%d", x, y);
+ found_x = x;
+
+ /* update best candidate */
+ if (update_candidate(tcm, x, y, w, h, field,
+ CR_R2L_B2T, &best))
+ goto done;
+#ifdef X_SCAN_LIMITER
+ /* change upper x bound */
+ end_x = x + 1;
+#endif
+ break;
+ } else if (map[x][y] && map[x][y]->is2d) {
+ /* step over 2D areas */
+ x = ALIGN(map[x][y]->p0.x - w + 1, align);
+ P3("moving to: %d,%d", x, y);
+ }
+ }
+#ifdef Y_SCAN_LIMITER
+ /* break if you find a free area shouldering the scan field */
+ if (found_x == start_x)
+ break;
+#endif
+ }
+
+ if (!best.a.tcm)
+ return -ENOSPC;
+done:
+ assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y);
+ return 0;
+}
+#endif
+
+/**
+ * Raster scan horizontally left to right from top to bottom to find a place for
+ * a 2D area of given size inside a scan field.
+ *
+ * @param w width of desired area
+ * @param h height of desired area
+ * @param align desired area alignment
+ * @param area pointer to the area that will be set to the best position
+ * @param field area to scan (inclusive)
+ *
+ * @return 0 on success, non-0 error value on failure.
+ */
+static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
+ struct tcm_area *field, struct tcm_area *area)
+{
+ s32 x, y;
+ s16 start_x, end_x, start_y, end_y, found_x = -1;
+ struct tcm_area ***map = ((struct sita_pvt *)tcm->pvt)->map;
+ struct score best = {{0}, {0}, {0}, 0};
+
+ PA(2, "scan_l2r_t2b:", field);
+
+ start_x = field->p0.x;
+ end_x = field->p1.x;
+ start_y = field->p0.y;
+ end_y = field->p1.y;
+
+ /* check scan area co-ordinates */
+ if (field->p1.x < field->p0.x ||
+ field->p1.y < field->p0.y)
+ return -EINVAL;
+
+ /* check if allocation would fit in scan area */
+ if (w > LEN(end_x, start_x) || h > LEN(end_y, start_y))
+ return -ENOSPC;
+
+ start_x = ALIGN(start_x, align);
+
+ /* check if allocation would still fit in scan area */
+ if (w > LEN(end_x, start_x))
+ return -ENOSPC;
+
+ /* adjust end_x and end_y, as allocation would not fit beyond */
+ end_x = end_x - w + 1; /* + 1 to be inclusive */
+ end_y = end_y - h + 1;
+
+ P2("ali=%d x=%d..%d y=%d..%d", align, start_x, end_x, start_y, end_y);
+
+ /* scan field top-to-bottom, left-to-right */
+ for (y = start_y; y <= end_y; y++) {
+ for (x = start_x; x <= end_x; x += align) {
+ if (is_area_free(map, x, y, w, h)) {
+ P3("found shoulder: %d,%d", x, y);
+ found_x = x;
+
+ /* update best candidate */
+ if (update_candidate(tcm, x, y, w, h, field,
+ CR_L2R_T2B, &best))
+ goto done;
+#ifdef X_SCAN_LIMITER
+ /* change upper x bound */
+ end_x = x - 1;
+#endif
+ break;
+ } else if (map[x][y] && map[x][y]->is2d) {
+ /* step over 2D areas */
+ x = ALIGN_DOWN(map[x][y]->p1.x, align);
+ P3("moving to: %d,%d", x, y);
+ }
+ }
+#ifdef Y_SCAN_LIMITER
+ /* break if you find a free area shouldering the scan field */
+ if (found_x == start_x)
+ break;
+#endif
+ }
+
+ if (!best.a.tcm)
+ return -ENOSPC;
+done:
+ assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y);
+ return 0;
+}
+
+#ifdef SCAN_BOTTOM_UP
+/**
+ * Raster scan horizontally left to right from bottom to top to find a
+ * place for a 2D area of given size inside a scan field.
+ *
+ * @param w width of desired area
+ * @param h height of desired area
+ * @param align desired area alignment
+ * @param area pointer to the area that will be set to the best position
+ * @param field area to scan (inclusive)
+ *
+ * @return 0 on success, non-0 error value on failure.
+ */
+static s32 scan_l2r_b2t(struct tcm *tcm, u16 w, u16 h, u16 align,
+ struct tcm_area *field, struct tcm_area *area)
+{
+ s32 x, y;
+ s16 start_x, end_x, start_y, end_y, found_x = -1;
+ struct tcm_area ***map = ((struct sita_pvt *)tcm->pvt)->map;
+ struct score best = {{0}, {0}, {0}, 0};
+
+ PA(2, "scan_l2r_b2t:", field);
+
+ start_x = field->p0.x;
+ end_x = field->p1.x;
+ start_y = field->p0.y;
+ end_y = field->p1.y;
+
+ /* check scan area co-ordinates */
+ if (field->p1.x < field->p0.x ||
+ field->p0.y < field->p1.y)
+ return -EINVAL;
+
+ /* check if allocation would fit in scan area */
+ if (w > LEN(end_x, start_x) || h > LEN(start_y, end_y))
+ return -ENOSPC;
+
+ start_x = ALIGN(start_x, align);
+
+ /* check if allocation would still fit in scan area */
+ if (w > LEN(end_x, start_x))
+ return -ENOSPC;
+
+ /* adjust end_x and start_y, as allocation would not fit beyond */
+ end_x = end_x - w + 1; /* + 1 to be inclusive */
+ start_y = start_y - h + 1;
+
+ P2("ali=%d x=%d..%d y=%d..%d", align, start_x, end_x, start_y, end_y);
+
+ /* scan field bottom-to-top, left-to-right */
+ for (y = start_y; y >= end_y; y--) {
+ for (x = start_x; x <= end_x; x += align) {
+ if (is_area_free(map, x, y, w, h)) {
+ P3("found shoulder: %d,%d", x, y);
+ found_x = x;
+
+ /* update best candidate */
+ if (update_candidate(tcm, x, y, w, h, field,
+ CR_L2R_B2T, &best))
+ goto done;
+#ifdef X_SCAN_LIMITER
+ /* change upper x bound */
+ end_x = x - 1;
+#endif
+ break;
+ } else if (map[x][y] && map[x][y]->is2d) {
+ /* step over 2D areas */
+ x = ALIGN_DOWN(map[x][y]->p1.x, align);
+ P3("moving to: %d,%d", x, y);
+ }
+ }
+
+#ifdef Y_SCAN_LIMITER
+ /* break if you find a free area shouldering the scan field */
+ if (found_x == start_x)
+ break;
+#endif
+ }
+
+ if (!best.a.tcm)
+ return -ENOSPC;
+done:
+ assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y);
+ return 0;
+}
+#endif
+
+/**
+ * Raster scan horizontally right to left from bottom to top to find a place
+ * for a 1D area of given size inside a scan field.
+ *
+ * @param num_slots size of desired area
+ * @param align desired area alignment
+ * @param area pointer to the area that will be set to the best
+ * position
+ * @param field area to scan (inclusive)
+ *
+ * @return 0 on success, non-0 error value on failure.
+ */
+static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_slots,
+ struct tcm_area *field, struct tcm_area *area)
+{
+ s32 found = 0;
+ s16 x, y;
+ struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+ struct tcm_area *p;
+
+ /* check scan area co-ordinates */
+ if (field->p0.y < field->p1.y)
+ return -EINVAL;
+
+ PA(2, "scan_r2l_b2t_one_dim:", field);
+
+ /**
+ * Currently we only support full width 1D scan field, which makes sense
+ * since 1D slot-ordering spans the full container width.
+ */
+ if (tcm->width != field->p0.x - field->p1.x + 1)
+ return -EINVAL;
+
+ /* check if allocation would fit in scan area */
+ if (num_slots > tcm->width * LEN(field->p0.y, field->p1.y))
+ return -ENOSPC;
+
+ x = field->p0.x;
+ y = field->p0.y;
+
+ /* find num_slots consecutive free slots to the left */
+ while (found < num_slots) {
+ if (y < 0)
+ return -ENOSPC;
+
+ /* remember bottom-right corner */
+ if (found == 0) {
+ area->p1.x = x;
+ area->p1.y = y;
+ }
+
+ /* skip busy regions */
+ p = pvt->map[x][y];
+ if (p) {
+ /* move to left of 2D areas, top left of 1D */
+ x = p->p0.x;
+ if (!p->is2d)
+ y = p->p0.y;
+
+ /* start over */
+ found = 0;
+ } else {
+ /* count consecutive free slots */
+ found++;
+ }
+
+ /* move to the left */
+ if (x == 0)
+ y--;
+ x = (x ? : tcm->width) - 1;
+
+ }
+
+ /* set top-left corner */
+ area->p0.x = x;
+ area->p0.y = y;
+ return 0;
+}
+
+/**
+ * Find a place for a 2D area of given size inside a scan field based on its
+ * alignment needs.
+ *
+ * @param w width of desired area
+ * @param h height of desired area
+ * @param align desired area alignment
+ * @param area pointer to the area that will be set to the best position
+ *
+ * @return 0 on success, non-0 error value on failure.
+ */
+static s32 scan_areas_and_find_fit(struct tcm *tcm, u16 w, u16 h, u16 align,
+ struct tcm_area *area)
+{
+ s32 ret = 0;
+ struct tcm_area field = {0};
+ u16 boundary_x, boundary_y;
+ struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+
+ if (align > 1) {
+ /* prefer top-left corner */
+ boundary_x = pvt->div_pt.x - 1;
+ boundary_y = pvt->div_pt.y - 1;
+
+ /* expand width and height if needed */
+ if (w > pvt->div_pt.x)
+ boundary_x = tcm->width - 1;
+ if (h > pvt->div_pt.y)
+ boundary_y = tcm->height - 1;
+
+ assign(&field, 0, 0, boundary_x, boundary_y);
+ ret = scan_l2r_t2b(tcm, w, h, align, &field, area);
+
+ /* scan whole container if failed, but do not scan 2x */
+ if (ret != 0 && (boundary_x != tcm->width - 1 ||
+ boundary_y != tcm->height - 1)) {
+ /* scan the entire container if nothing found */
+ assign(&field, 0, 0, tcm->width - 1, tcm->height - 1);
+ ret = scan_l2r_t2b(tcm, w, h, align, &field, area);
+ }
+ } else if (align == 1) {
+ /* prefer top-right corner */
+ boundary_x = pvt->div_pt.x;
+ boundary_y = pvt->div_pt.y - 1;
+
+ /* expand width and height if needed */
+ if (w > (tcm->width - pvt->div_pt.x))
+ boundary_x = 0;
+ if (h > pvt->div_pt.y)
+ boundary_y = tcm->height - 1;
+
+ assign(&field, tcm->width - 1, 0, boundary_x, boundary_y);
+ ret = scan_r2l_t2b(tcm, w, h, align, &field, area);
+
+ /* scan whole container if failed, but do not scan 2x */
+ if (ret != 0 && (boundary_x != 0 ||
+ boundary_y != tcm->height - 1)) {
+ /* scan the entire container if nothing found */
+ assign(&field, tcm->width - 1, 0, 0, tcm->height - 1);
+ ret = scan_r2l_t2b(tcm, w, h, align, &field,
+ area);
+ }
+ }
+
+ return ret;
+}
+
+/* check if an entire area is free */
+static s32 is_area_free(struct tcm_area ***map, u16 x0, u16 y0, u16 w, u16 h)
+{
+ u16 x = 0, y = 0;
+ for (y = y0; y < y0 + h; y++) {
+ for (x = x0; x < x0 + w; x++) {
+ if (map[x][y])
+ return false;
+ }
+ }
+ return true;
+}
+
+/* fills an area with a parent tcm_area */
+static void fill_area(struct tcm *tcm, struct tcm_area *area,
+ struct tcm_area *parent)
+{
+ s32 x, y;
+ struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+ struct tcm_area a, a_;
+
+ /* set area's tcm; otherwise, enumerator considers it invalid */
+ area->tcm = tcm;
+
+ tcm_for_each_slice(a, *area, a_) {
+ PA(2, "fill 2d area", &a);
+ for (x = a.p0.x; x <= a.p1.x; ++x)
+ for (y = a.p0.y; y <= a.p1.y; ++y)
+ pvt->map[x][y] = parent;
+
+ }
+}
+
+/**
+ * Compares a candidate area to the current best area, and if it is a better
+ * fit, it updates the best to this one.
+ *
+ * @param x0, y0, w, h top, left, width, height of candidate area
+ * @param field scan field
+ * @param criteria scan criteria
+ * @param best best candidate and its scores
+ *
+ * @return 1 (true) if the candidate area is known to be the final best, so no
+ * more searching should be performed
+ */
+static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h,
+ struct tcm_area *field, s32 criteria,
+ struct score *best)
+{
+ struct score me; /* score for area */
+
+ /*
+ * If first found is enabled then we stop looking
+ * NOTE: For horizontal bias we always give the first found, because our
+ * scan is horizontal-raster-based and the first candidate will always
+ * have the horizontal bias.
+ */
+ bool first = criteria & (CR_FIRST_FOUND | CR_BIAS_HORIZONTAL);
+
+ assign(&me.a, x0, y0, x0 + w - 1, y0 + h - 1);
+
+ /* calculate score for current candidate */
+ if (!first) {
+ get_neighbor_stats(tcm, &me.a, &me.n);
+ me.neighs = me.n.edge + me.n.busy;
+ get_nearness_factor(field, &me.a, &me.f);
+ }
+
+ /* the 1st candidate is always the best */
+ if (!best->a.tcm)
+ goto better;
+
+ BUG_ON(first);
+
+ /* see if this are is better than the best so far */
+
+ /* neighbor check */
+ if ((criteria & CR_MAX_NEIGHS) &&
+ me.neighs > best->neighs)
+ goto better;
+
+ /* vertical bias check */
+ if ((criteria & CR_BIAS_VERTICAL) &&
+ /*
+ * NOTE: not checking if lengths are same, because that does not
+ * find new shoulders on the same row after a fit
+ */
+ LEN(me.a.p0.y, field->p0.y) >
+ LEN(best->a.p0.y, field->p0.y))
+ goto better;
+
+ /* diagonal balance check */
+ if ((criteria & CR_DIAGONAL_BALANCE) &&
+ best->neighs <= me.neighs &&
+ (best->neighs < me.neighs ||
+ /* this implies that neighs and occupied match */
+ best->n.busy < me.n.busy ||
+ (best->n.busy == me.n.busy &&
+ /* check the nearness factor */
+ best->f.x + best->f.y > me.f.x + me.f.y)))
+ goto better;
+
+ /* not better, keep going */
+ return 0;
+
+better:
+ /* save current area as best */
+ memcpy(best, &me, sizeof(me));
+ best->a.tcm = tcm;
+ return first;
+}
+
+/**
+ * Calculate the nearness factor of an area in a search field. The nearness
+ * factor is smaller if the area is closer to the search origin.
+ */
+static void get_nearness_factor(struct tcm_area *field, struct tcm_area *area,
+ struct nearness_factor *nf)
+{
+ /**
+ * Using signed math as field coordinates may be reversed if
+ * search direction is right-to-left or bottom-to-top.
+ */
+ nf->x = (s32)(area->p0.x - field->p0.x) * 1000 /
+ (field->p1.x - field->p0.x);
+ nf->y = (s32)(area->p0.y - field->p0.y) * 1000 /
+ (field->p1.y - field->p0.y);
+}
+
+/* get neighbor statistics */
+static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area,
+ struct neighbor_stats *stat)
+{
+ s16 x = 0, y = 0;
+ struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+
+ /* Clearing any exisiting values */
+ memset(stat, 0, sizeof(*stat));
+
+ /* process top & bottom edges */
+ for (x = area->p0.x; x <= area->p1.x; x++) {
+ if (area->p0.y == 0)
+ stat->edge++;
+ else if (pvt->map[x][area->p0.y - 1])
+ stat->busy++;
+
+ if (area->p1.y == tcm->height - 1)
+ stat->edge++;
+ else if (pvt->map[x][area->p1.y + 1])
+ stat->busy++;
+ }
+
+ /* process left & right edges */
+ for (y = area->p0.y; y <= area->p1.y; ++y) {
+ if (area->p0.x == 0)
+ stat->edge++;
+ else if (pvt->map[area->p0.x - 1][y])
+ stat->busy++;
+
+ if (area->p1.x == tcm->width - 1)
+ stat->edge++;
+ else if (pvt->map[area->p1.x + 1][y])
+ stat->busy++;
+ }
+}
diff --git a/drivers/media/video/tiler/tcm/tcm-sita.h b/drivers/media/video/tiler/tcm/tcm-sita.h
new file mode 100644
index 00000000000..6098ea00fb2
--- /dev/null
+++ b/drivers/media/video/tiler/tcm/tcm-sita.h
@@ -0,0 +1,39 @@
+/*
+ * tcm_sita.h
+ *
+ * SImple Tiler Allocator (SiTA) interface.
+ *
+ * Author: Ravi Ramachandra <r.ramachandra@ti.com>
+ *
+ * Copyright (C) 2009-2010 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 TCM_SITA_H
+#define TCM_SITA_H
+
+#include "../tcm.h"
+
+/**
+ * Create a SiTA tiler container manager.
+ *
+ * @param width Container width
+ * @param height Container height
+ * @param attr preferred division point between 64-aligned
+ * allocation (top left), 32-aligned allocations
+ * (top right), and page mode allocations (bottom)
+ *
+ * @return TCM instance
+ */
+struct tcm *sita_init(u16 width, u16 height, struct tcm_pt *attr);
+
+TCM_INIT(sita_init, struct tcm_pt);
+
+#endif /* TCM_SITA_H_ */
diff --git a/drivers/media/video/tiler/tcm/tcm-utils.h b/drivers/media/video/tiler/tcm/tcm-utils.h
new file mode 100644
index 00000000000..0d1260af197
--- /dev/null
+++ b/drivers/media/video/tiler/tcm/tcm-utils.h
@@ -0,0 +1,54 @@
+/*
+ * tcm_utils.h
+ *
+ * Utility functions for implementing TILER container managers.
+ *
+ * Author: Lajos Molnar <molnar@ti.com>
+ *
+ * Copyright (C) 2009-2010 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 TCM_UTILS_H
+#define TCM_UTILS_H
+
+#include "../tcm.h"
+
+/* TCM_ALG_NAME must be defined to use the debug methods */
+
+#ifdef DEBUG
+#define IFDEBUG(x) x
+#else
+/* compile-check debug statements even if not DEBUG */
+#define IFDEBUG(x) do { if (0) x; } while (0)
+#endif
+
+#define P(level, fmt, ...) \
+ IFDEBUG(printk(level TCM_ALG_NAME ":%d:%s()" fmt "\n", \
+ __LINE__, __func__, ##__VA_ARGS__))
+
+#define P1(fmt, ...) P(KERN_NOTICE, fmt, ##__VA_ARGS__)
+#define P2(fmt, ...) P(KERN_INFO, fmt, ##__VA_ARGS__)
+#define P3(fmt, ...) P(KERN_DEBUG, fmt, ##__VA_ARGS__)
+
+#define PA(level, msg, p_area) P##level(msg " (%03d %03d)-(%03d %03d)\n", \
+ (p_area)->p0.x, (p_area)->p0.y, (p_area)->p1.x, (p_area)->p1.y)
+
+/* assign coordinates to area */
+static inline
+void assign(struct tcm_area *a, u16 x0, u16 y0, u16 x1, u16 y1)
+{
+ a->p0.x = x0;
+ a->p0.y = y0;
+ a->p1.x = x1;
+ a->p1.y = y1;
+}
+
+#endif
diff --git a/drivers/media/video/tiler/tiler-geom.c b/drivers/media/video/tiler/tiler-geom.c
new file mode 100644
index 00000000000..f95ae5c9ef9
--- /dev/null
+++ b/drivers/media/video/tiler/tiler-geom.c
@@ -0,0 +1,372 @@
+/*
+ * tiler-geom.c
+ *
+ * TILER geometry functions for TI TILER hardware block.
+ *
+ * Author: Lajos Molnar <molnar@ti.com>
+ *
+ * Copyright (C) 2009-2010 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 <linux/module.h>
+#include "_tiler.h"
+
+/* bits representing the same slot in DMM-TILER hw-block */
+#define SLOT_WIDTH_BITS 6
+#define SLOT_HEIGHT_BITS 6
+
+/* bits reserved to describe coordinates in DMM-TILER hw-block */
+#define CONT_WIDTH_BITS 14
+#define CONT_HEIGHT_BITS 13
+
+static struct tiler_geom geom[TILER_FORMATS] = {
+ {
+ .x_shft = 0,
+ .y_shft = 0,
+ },
+ {
+ .x_shft = 0,
+ .y_shft = 1,
+ },
+ {
+ .x_shft = 1,
+ .y_shft = 1,
+ },
+ {
+ .x_shft = SLOT_WIDTH_BITS,
+ .y_shft = SLOT_HEIGHT_BITS,
+ },
+};
+
+/* tiler space addressing bitfields */
+#define MASK_XY_FLIP (1 << 31)
+#define MASK_Y_INVERT (1 << 30)
+#define MASK_X_INVERT (1 << 29)
+#define SHIFT_ACC_MODE 27
+#define MASK_ACC_MODE 3
+
+/* calculated constants */
+#define TILER_PAGE (1 << (SLOT_WIDTH_BITS + SLOT_HEIGHT_BITS))
+#define TILER_WIDTH (1 << (CONT_WIDTH_BITS - SLOT_WIDTH_BITS))
+#define TILER_HEIGHT (1 << (CONT_HEIGHT_BITS - SLOT_HEIGHT_BITS))
+
+#define VIEW_SIZE (1u << (CONT_WIDTH_BITS + CONT_HEIGHT_BITS))
+#define VIEW_MASK (VIEW_SIZE - 1u)
+
+#define MASK(bits) ((1 << (bits)) - 1)
+
+#define TILER_FMT(x) ((enum tiler_fmt) \
+ ((x >> SHIFT_ACC_MODE) & MASK_ACC_MODE))
+
+#define MASK_VIEW (MASK_X_INVERT | MASK_Y_INVERT | MASK_XY_FLIP)
+
+/* location of the various tiler views in physical address space */
+#define TILVIEW_8BIT 0x60000000u
+#define TILVIEW_16BIT (TILVIEW_8BIT + VIEW_SIZE)
+#define TILVIEW_32BIT (TILVIEW_16BIT + VIEW_SIZE)
+#define TILVIEW_PAGE (TILVIEW_32BIT + VIEW_SIZE)
+#define TILVIEW_END (TILVIEW_PAGE + VIEW_SIZE)
+
+/* create tsptr by adding view orientation and access mode */
+#define TIL_ADDR(x, orient, a)\
+ ((u32) (x) | (orient) | ((a) << SHIFT_ACC_MODE))
+
+bool is_tiler_addr(u32 phys)
+{
+ return phys >= TILVIEW_8BIT && phys < TILVIEW_END;
+}
+EXPORT_SYMBOL(is_tiler_addr);
+
+u32 tiler_bpp(const struct tiler_block_t *b)
+{
+ enum tiler_fmt fmt = tiler_fmt(b->phys);
+ BUG_ON(fmt == TILFMT_INVALID);
+
+ return geom[fmt].bpp_m;
+}
+EXPORT_SYMBOL(tiler_bpp);
+
+/* return the stride of a tiler-block in tiler space */
+static inline s32 tiler_stride(u32 tsptr)
+{
+ enum tiler_fmt fmt = TILER_FMT(tsptr);
+
+ if (fmt == TILFMT_PAGE)
+ return 0;
+ else if (tsptr & MASK_XY_FLIP)
+ return 1 << (CONT_HEIGHT_BITS + geom[fmt].x_shft);
+ else
+ return 1 << (CONT_WIDTH_BITS + geom[fmt].y_shft);
+}
+
+u32 tiler_pstride(const struct tiler_block_t *b)
+{
+ enum tiler_fmt fmt = tiler_fmt(b->phys);
+ BUG_ON(fmt == TILFMT_INVALID);
+
+ /* return the virtual stride for page mode */
+ if (fmt == TILFMT_PAGE)
+ return tiler_vstride(b);
+
+ return tiler_stride(b->phys & ~MASK_VIEW);
+}
+EXPORT_SYMBOL(tiler_pstride);
+
+enum tiler_fmt tiler_fmt(u32 phys)
+{
+ if (!is_tiler_addr(phys))
+ return TILFMT_INVALID;
+
+ return TILER_FMT(phys);
+}
+EXPORT_SYMBOL(tiler_fmt);
+
+/* returns the tiler geometry information for a format */
+static const struct tiler_geom *get_geom(enum tiler_fmt fmt)
+{
+ if (fmt >= TILFMT_MIN && fmt <= TILFMT_MAX)
+ return geom + fmt;
+ return NULL;
+}
+
+/**
+ * Returns the natural x and y coordinates for a pixel in tiler space address.
+ * That is, the coordinates for the same pixel in the natural (non-rotated,
+ * non-mirrored) view. This allows to uniquely identify a tiler pixel in any
+ * view orientation.
+ */
+static void tiler_get_natural_xy(u32 tsptr, u32 *x, u32 *y)
+{
+ u32 x_bits, y_bits, offset;
+ enum tiler_fmt fmt;
+
+ fmt = TILER_FMT(tsptr);
+
+ x_bits = CONT_WIDTH_BITS - geom[fmt].x_shft;
+ y_bits = CONT_HEIGHT_BITS - geom[fmt].y_shft;
+ offset = (tsptr & VIEW_MASK) >> (geom[fmt].x_shft + geom[fmt].y_shft);
+
+ /* separate coordinate bitfields based on view orientation */
+ if (tsptr & MASK_XY_FLIP) {
+ *x = offset >> y_bits;
+ *y = offset & MASK(y_bits);
+ } else {
+ *x = offset & MASK(x_bits);
+ *y = offset >> x_bits;
+ }
+
+ /* account for mirroring */
+ if (tsptr & MASK_X_INVERT)
+ *x ^= MASK(x_bits);
+ if (tsptr & MASK_Y_INVERT)
+ *y ^= MASK(y_bits);
+}
+
+/* calculate the tiler space address of a pixel in a view orientation */
+static u32 tiler_get_address(u32 orient, enum tiler_fmt fmt, u32 x, u32 y)
+{
+ u32 x_bits, y_bits, tmp, x_mask, y_mask, alignment;
+
+ x_bits = CONT_WIDTH_BITS - geom[fmt].x_shft;
+ y_bits = CONT_HEIGHT_BITS - geom[fmt].y_shft;
+ alignment = geom[fmt].x_shft + geom[fmt].y_shft;
+
+ /* validate coordinate */
+ x_mask = MASK(x_bits);
+ y_mask = MASK(y_bits);
+ if (x < 0 || x > x_mask || y < 0 || y > y_mask)
+ return 0;
+
+ /* account for mirroring */
+ if (orient & MASK_X_INVERT)
+ x ^= x_mask;
+ if (orient & MASK_Y_INVERT)
+ y ^= y_mask;
+
+ /* get coordinate address */
+ if (orient & MASK_XY_FLIP)
+ tmp = ((x << y_bits) + y);
+ else
+ tmp = ((y << x_bits) + x);
+
+ return TIL_ADDR((tmp << alignment), orient, fmt);
+}
+
+void tilview_create(struct tiler_view_t *view, u32 phys, u32 width, u32 height)
+{
+ BUG_ON(!is_tiler_addr(phys));
+
+ view->tsptr = phys & ~MASK_VIEW;
+ view->bpp = geom[TILER_FMT(phys)].bpp_m;
+ view->width = width;
+ view->height = height;
+ view->h_inc = view->bpp;
+ view->v_inc = tiler_stride(view->tsptr);
+}
+EXPORT_SYMBOL(tilview_create);
+
+void tilview_get(struct tiler_view_t *view, struct tiler_block_t *blk)
+{
+ view->tsptr = blk->phys & ~MASK_VIEW;
+ view->bpp = tiler_bpp(blk);
+ view->width = blk->width;
+ view->height = blk->height;
+ view->h_inc = view->bpp;
+ view->v_inc = tiler_stride(view->tsptr);
+}
+EXPORT_SYMBOL(tilview_get);
+
+s32 tilview_crop(struct tiler_view_t *view, u32 left, u32 top, u32 width,
+ u32 height)
+{
+ /* check for valid crop */
+ if (left + width < left || left + width > view->width ||
+ top + height < top || top + height > view->height)
+ return -EINVAL;
+
+ view->tsptr += left * view->h_inc + top * view->v_inc;
+ view->width = width;
+ view->height = height;
+ return 0;
+}
+EXPORT_SYMBOL(tilview_crop);
+
+/* calculate tilerspace address and stride after view orientation change */
+static void reorient(struct tiler_view_t *view, u32 orient)
+{
+ u32 x, y;
+
+ tiler_get_natural_xy(view->tsptr, &x, &y);
+ view->tsptr = tiler_get_address(orient,
+ TILER_FMT(view->tsptr), x, y);
+ view->v_inc = tiler_stride(view->tsptr);
+}
+
+s32 tilview_rotate(struct tiler_view_t *view, s32 rotation)
+{
+ u32 orient;
+
+ if (rotation % 90)
+ return -EINVAL;
+
+ /* normalize rotation to quarters */
+ rotation = (rotation / 90) & 3;
+ if (!rotation)
+ return 0; /* nothing to do */
+
+ /* PAGE mode view cannot be rotated */
+ if (TILER_FMT(view->tsptr) == TILFMT_PAGE)
+ return -EPERM;
+
+ /*
+ * first adjust top-left corner. NOTE: it rotates counter-clockwise:
+ * 0 < 3
+ * v ^
+ * 1 > 2
+ */
+ if (rotation < 3)
+ view->tsptr += (view->height - 1) * view->v_inc;
+ if (rotation > 1)
+ view->tsptr += (view->width - 1) * view->h_inc;
+
+ /* then rotate view itself */
+ orient = view->tsptr & MASK_VIEW;
+
+ /* rotate first 2 quarters */
+ if (rotation & 2) {
+ orient ^= MASK_X_INVERT;
+ orient ^= MASK_Y_INVERT;
+ }
+
+ /* rotate last quarter */
+ if (rotation & 1) {
+ orient ^= (orient & MASK_XY_FLIP) ?
+ MASK_X_INVERT : MASK_Y_INVERT;
+
+ /* swap x & y */
+ orient ^= MASK_XY_FLIP;
+ swap(view->height, view->width);
+ }
+
+ /* finally reorient view */
+ reorient(view, orient);
+ return 0;
+}
+EXPORT_SYMBOL(tilview_rotate);
+
+s32 tilview_flip(struct tiler_view_t *view, bool flip_x, bool flip_y)
+{
+ u32 orient;
+ orient = view->tsptr & MASK_VIEW;
+
+ if (!flip_x && !flip_y)
+ return 0; /* nothing to do */
+
+ /* PAGE mode view cannot be flipped */
+ if (TILER_FMT(view->tsptr) == TILFMT_PAGE)
+ return -EPERM;
+
+ /* adjust top-left corner */
+ if (flip_x)
+ view->tsptr += (view->width - 1) * view->h_inc;
+ if (flip_y)
+ view->tsptr += (view->height - 1) * view->v_inc;
+
+ /* flip view orientation */
+ if (orient & MASK_XY_FLIP)
+ swap(flip_x, flip_y);
+
+ if (flip_x)
+ orient ^= MASK_X_INVERT;
+ if (flip_y)
+ orient ^= MASK_Y_INVERT;
+
+ /* finally reorient view */
+ reorient(view, orient);
+ return 0;
+}
+EXPORT_SYMBOL(tilview_flip);
+
+/* return the alias address for a coordinate */
+static inline u32 alias_address(enum tiler_fmt fmt, u32 x, u32 y)
+{
+ return tiler_get_address(0, fmt, x, y) + TILVIEW_8BIT;
+}
+
+/* get the coordinates for an alias address */
+static inline void alias_xy(u32 ssptr, u32 *x, u32 *y)
+{
+ tiler_get_natural_xy(ssptr & ~MASK_VIEW, x, y);
+}
+
+/* initialize shared geometric data */
+void tiler_geom_init(struct tiler_ops *tiler)
+{
+ struct tiler_geom *g;
+
+ tiler->xy = alias_xy;
+ tiler->addr = alias_address;
+ tiler->geom = get_geom;
+
+ tiler->page = TILER_PAGE;
+ tiler->width = TILER_WIDTH;
+ tiler->height = TILER_HEIGHT;
+
+ /* calculate geometry */
+ for (g = geom; g < geom + TILER_FORMATS; g++) {
+ g->bpp_m = g->bpp = 1 << (g->x_shft + g->y_shft);
+ g->slot_w = 1 << (SLOT_WIDTH_BITS - g->x_shft);
+ g->slot_h = 1 << (SLOT_HEIGHT_BITS - g->y_shft);
+ }
+
+ /* set bpp_m = 1 for page mode as most applications deal in byte data */
+ geom[TILFMT_PAGE].bpp_m = 1;
+}
diff --git a/drivers/media/video/tiler/tiler-iface.c b/drivers/media/video/tiler/tiler-iface.c
new file mode 100644
index 00000000000..9a967bcffd0
--- /dev/null
+++ b/drivers/media/video/tiler/tiler-iface.c
@@ -0,0 +1,827 @@
+/*
+ * tiler-iface.c
+ *
+ * TILER driver interace functions for TI TILER hardware block.
+ *
+ * Authors: Lajos Molnar <molnar@ti.com>
+ * David Sin <davidsin@ti.com>
+ *
+ * Copyright (C) 2009-2010 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 <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/fs.h> /* fops */
+#include <linux/uaccess.h> /* copy_to_user */
+#include <linux/slab.h> /* kmalloc */
+#include <linux/sched.h> /* current */
+#include <linux/mm.h>
+#include <linux/mm_types.h>
+#include <asm/mach/map.h> /* for ioremap_page */
+
+#include "_tiler.h"
+
+static bool security = CONFIG_TILER_SECURITY;
+static bool ssptr_lookup = true;
+static bool offset_lookup = true;
+
+module_param(security, bool, 0644);
+MODULE_PARM_DESC(security,
+ "Separate allocations by different processes into different pages");
+module_param(ssptr_lookup, bool, 0644);
+MODULE_PARM_DESC(ssptr_lookup,
+ "Allow looking up a block by ssptr - This is a security risk");
+module_param(offset_lookup, bool, 0644);
+MODULE_PARM_DESC(offset_lookup,
+ "Allow looking up a buffer by offset - This is a security risk");
+
+static struct mutex mtx;
+static struct list_head procs; /* list of process info structs */
+static struct tiler_ops *ops; /* shared methods and variables */
+static struct blocking_notifier_head notifier; /* notifier for events */
+
+/*
+ * Event notification methods
+ * ==========================================================================
+ */
+
+static s32 tiler_notify_event(int event, void *data)
+{
+ return blocking_notifier_call_chain(&notifier, event, data);
+}
+
+/*
+ * Buffer handling methods
+ * ==========================================================================
+ */
+
+struct __buf_info {
+ struct list_head by_pid; /* list of buffers per pid */
+ struct tiler_buf_info buf_info;
+ struct mem_info *mi[TILER_MAX_NUM_BLOCKS]; /* blocks */
+};
+
+/* check if an offset is used */
+static bool _m_offs_in_use(u32 offs, u32 length, struct process_info *pi)
+{
+ struct __buf_info *_b;
+ /* have mutex */
+ list_for_each_entry(_b, &pi->bufs, by_pid)
+ if (_b->buf_info.offset < offs + length &&
+ _b->buf_info.offset + _b->buf_info.length > offs)
+ return 1;
+ return 0;
+}
+
+/* get an offset */
+static u32 _m_get_offs(struct process_info *pi, u32 length)
+{
+ static u32 offs = 0xda7a;
+
+ /* ensure no-one is using this offset */
+ while ((offs << PAGE_SHIFT) + length < length ||
+ _m_offs_in_use(offs << PAGE_SHIFT, length, pi)) {
+ /* use a pseudo-random generator to get a new offset to try */
+
+ /* Galois LSF: 20, 17 */
+ offs = (offs >> 1) ^ (u32)((0 - (offs & 1u)) & 0x90000);
+ }
+
+ return offs << PAGE_SHIFT;
+}
+
+/* find and lock a block. process_info is optional */
+static struct mem_info *
+_m_lock_block(u32 key, u32 id, struct process_info *pi) {
+ struct gid_info *gi;
+ struct mem_info *mi;
+
+ /* if process_info is given, look there first */
+ if (pi) {
+ /* have mutex */
+
+ /* find block in process list and free it */
+ list_for_each_entry(gi, &pi->groups, by_pid) {
+ mi = ops->lock(key, id, gi);
+ if (mi)
+ return mi;
+ }
+ }
+
+ /* if not found or no process_info given, find block in global list */
+ return ops->lock(key, id, NULL);
+}
+
+/* register a buffer */
+static s32 _m_register_buf(struct __buf_info *_b, struct process_info *pi)
+{
+ struct mem_info *mi;
+ struct tiler_buf_info *b = &_b->buf_info;
+ u32 i, num = b->num_blocks, offs;
+
+ /* check validity */
+ if (num > TILER_MAX_NUM_BLOCKS || num == 0)
+ return -EINVAL;
+
+ /* find each block */
+ b->length = 0;
+ for (i = 0; i < num; i++) {
+ mi = _m_lock_block(b->blocks[i].key, b->blocks[i].id, pi);
+ if (!mi) {
+ /* unlock any blocks already found */
+ while (i--)
+ ops->unlock_free(_b->mi[i], false);
+ return -EACCES;
+ }
+ _b->mi[i] = mi;
+
+ /* we don't keep track of ptr and 1D stride so clear them */
+ b->blocks[i].ptr = NULL;
+ b->blocks[i].stride = 0;
+
+ ops->describe(mi, b->blocks + i);
+ b->length += tiler_size(&mi->blk);
+ }
+
+ /* if found all, register buffer */
+ offs = _b->mi[0]->blk.phys & ~PAGE_MASK;
+ b->offset = _m_get_offs(pi, b->length) + offs;
+ b->length -= offs;
+
+ /* have mutex */
+ list_add(&_b->by_pid, &pi->bufs);
+
+ return 0;
+}
+
+/* unregister a buffer */
+static void _m_unregister_buf(struct __buf_info *_b)
+{
+ u32 i;
+
+ /* unregister */
+ list_del(&_b->by_pid);
+
+ /* no longer using the blocks */
+ for (i = 0; i < _b->buf_info.num_blocks; i++)
+ ops->unlock_free(_b->mi[i], false);
+
+ kfree(_b);
+}
+
+/*
+ * process_info handling methods
+ * ==========================================================================
+ */
+
+/* get process info, and increment refs for device tracking */
+static struct process_info *__get_pi(pid_t pid, bool kernel)
+{
+ struct process_info *pi;
+
+ /*
+ * treat all processes as the same, kernel processes are still treated
+ * differently so not to free kernel allocated areas when a user process
+ * closes the tiler driver
+ */
+ if (!security)
+ pid = 0;
+
+ /* find process context */
+ mutex_lock(&mtx);
+ list_for_each_entry(pi, &procs, list) {
+ if (pi->pid == pid && pi->kernel == kernel)
+ goto done;
+ }
+
+ /* create process context */
+ pi = kmalloc(sizeof(*pi), GFP_KERNEL);
+ if (!pi)
+ goto done;
+ memset(pi, 0, sizeof(*pi));
+
+ pi->pid = pid;
+ pi->kernel = kernel;
+ INIT_LIST_HEAD(&pi->groups);
+ INIT_LIST_HEAD(&pi->bufs);
+ list_add(&pi->list, &procs);
+done:
+ /* increment reference count */
+ if (pi && !kernel)
+ pi->refs++;
+ mutex_unlock(&mtx);
+ return pi;
+}
+
+/**
+ * Free all info kept by a process: all registered buffers, allocated blocks,
+ * and unreferenced blocks. Any blocks/areas still referenced will move to the
+ * orphaned lists to avoid issues if a new process is created with the same pid.
+ */
+static void _m_free_process_info(struct process_info *pi)
+{
+ struct gid_info *gi, *gi_;
+ struct __buf_info *_b = NULL, *_b_ = NULL;
+
+ /* have mutex */
+
+ if (!list_empty(&pi->bufs))
+ tiler_notify_event(TILER_DEVICE_CLOSE, NULL);
+
+ /* unregister all buffers */
+ list_for_each_entry_safe(_b, _b_, &pi->bufs, by_pid)
+ _m_unregister_buf(_b);
+
+ BUG_ON(!list_empty(&pi->bufs));
+
+ /* free all allocated blocks, and remove unreferenced ones */
+ list_for_each_entry_safe(gi, gi_, &pi->groups, by_pid)
+ ops->destroy_group(gi);
+
+ BUG_ON(!list_empty(&pi->groups));
+ list_del(&pi->list);
+ kfree(pi);
+}
+
+/* Free all info kept by all processes. Called on cleanup. */
+static void destroy_processes(void)
+{
+ struct process_info *pi, *pi_;
+
+ mutex_lock(&mtx);
+
+ list_for_each_entry_safe(pi, pi_, &procs, list)
+ _m_free_process_info(pi);
+ BUG_ON(!list_empty(&procs));
+
+ mutex_unlock(&mtx);
+}
+
+/*
+ * File operations (mmap, ioctl, open, close)
+ * ==========================================================================
+ */
+
+/* mmap tiler buffer into user's virtual space */
+static s32 tiler_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct __buf_info *_b;
+ struct tiler_buf_info *b = NULL;
+ u32 i, map_offs, map_size, blk_offs, blk_size, mapped_size;
+ struct process_info *pi = filp->private_data;
+ u32 offs = vma->vm_pgoff << PAGE_SHIFT;
+ u32 size = vma->vm_end - vma->vm_start;
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ /* find tiler buffer to mmap */
+ mutex_lock(&mtx);
+ list_for_each_entry(_b, &pi->bufs, by_pid) {
+ /* we support partial mmaping of a whole tiler buffer */
+ if (offs >= (_b->buf_info.offset & PAGE_MASK) &&
+ offs + size <= PAGE_ALIGN(_b->buf_info.offset +
+ _b->buf_info.length)) {
+ b = &_b->buf_info;
+ break;
+ }
+ }
+ mutex_unlock(&mtx);
+
+ /* we use b to detect if we found the bufffer */
+ if (!b)
+ return -ENXIO;
+
+ /* mmap relevant blocks */
+ blk_offs = _b->buf_info.offset;
+
+ /* start at the beginning of the region */
+ mapped_size = 0;
+ for (i = 0; i < b->num_blocks; i++, blk_offs += blk_size) {
+ blk_size = tiler_size(&_b->mi[i]->blk);
+ /* see if tiler block is inside the requested region */
+ if (offs >= blk_offs + blk_size || offs + size < blk_offs)
+ continue;
+ /* get the offset and map size for this particular block */
+ map_offs = max(offs, blk_offs) - blk_offs;
+ map_size = min(size - mapped_size, blk_size);
+
+ /* mmap block */
+ if (tiler_mmap_blk(&_b->mi[i]->blk, map_offs, map_size, vma,
+ mapped_size))
+ return -EAGAIN;
+
+ /* update mmap region pointer */
+ mapped_size += map_size;
+ }
+ return 0;
+}
+
+/* ioctl handler */
+static long tiler_ioctl(struct file *filp, u32 cmd, unsigned long arg)
+{
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+ s32 r;
+ void __user *data = (void __user *)arg;
+ struct process_info *pi = filp->private_data;
+ struct __buf_info *_b;
+ struct tiler_buf_info buf_info = {0};
+ struct tiler_block_info block_info = {0};
+ struct mem_info *mi;
+
+ switch (cmd) {
+ /* allocate block */
+ case TILIOC_GBLK:
+ if (copy_from_user(&block_info, data, sizeof(block_info)))
+ return -EFAULT;
+
+ switch (block_info.fmt) {
+ case TILFMT_PAGE:
+ r = ops->alloc(block_info.fmt, block_info.dim.len, 1,
+ block_info.align, block_info.offs,
+ block_info.key, block_info.group_id,
+ pi, &mi);
+ break;
+ case TILFMT_8BIT:
+ case TILFMT_16BIT:
+ case TILFMT_32BIT:
+ r = ops->alloc(block_info.fmt,
+ block_info.dim.area.width,
+ block_info.dim.area.height,
+ block_info.align, block_info.offs,
+ block_info.key, block_info.group_id,
+ pi, &mi);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (r)
+ return r;
+
+ /* fill out block info */
+ if (mi) {
+ block_info.ptr = NULL;
+ ops->describe(mi, &block_info);
+ }
+
+ if (copy_to_user(data, &block_info, sizeof(block_info)))
+ return -EFAULT;
+ break;
+ /* free/unmap block */
+ case TILIOC_FBLK:
+ case TILIOC_UMBLK:
+ if (copy_from_user(&block_info, data, sizeof(block_info)))
+ return -EFAULT;
+
+ /* search current process first, then all processes */
+ mutex_lock(&mtx);
+ mi = _m_lock_block(block_info.key, block_info.id, pi);
+ mutex_unlock(&mtx);
+ if (mi)
+ ops->unlock_free(mi, true);
+
+ /* free always succeeds */
+ break;
+ /* get physical address */
+ case TILIOC_GSSP:
+ pgd = pgd_offset(current->mm, arg);
+ if (!(pgd_none(*pgd) || pgd_bad(*pgd))) {
+ pmd = pmd_offset(pgd, arg);
+ if (!(pmd_none(*pmd) || pmd_bad(*pmd))) {
+ ptep = pte_offset_map(pmd, arg);
+ if (ptep) {
+ pte = *ptep;
+ if (pte_present(pte))
+ return (pte & PAGE_MASK) |
+ (~PAGE_MASK & arg);
+ }
+ }
+ }
+ /* va not in page table, return NULL */
+ return (s32) NULL;
+ break;
+ /* map block */
+ case TILIOC_MBLK:
+ if (copy_from_user(&block_info, data, sizeof(block_info)))
+ return -EFAULT;
+
+ if (!block_info.ptr)
+ return -EFAULT;
+
+ r = ops->map(block_info.fmt, block_info.dim.len, 1,
+ block_info.key, block_info.group_id, pi,
+ &mi, (u32)block_info.ptr);
+ if (r)
+ return r;
+
+ /* fill out block info */
+ if (mi)
+ ops->describe(mi, &block_info);
+
+ if (copy_to_user(data, &block_info, sizeof(block_info)))
+ return -EFAULT;
+ break;
+#ifndef CONFIG_TILER_SECURE
+ /* query buffer information by offset */
+ case TILIOC_QBUF:
+ if (!offset_lookup)
+ return -EPERM;
+
+ if (copy_from_user(&buf_info, data, sizeof(buf_info)))
+ return -EFAULT;
+
+ /* find buffer */
+ mutex_lock(&mtx);
+ r = -ENOENT;
+ /* buffer registration is per process */
+ list_for_each_entry(_b, &pi->bufs, by_pid) {
+ if (buf_info.offset == _b->buf_info.offset) {
+ memcpy(&buf_info, &_b->buf_info,
+ sizeof(buf_info));
+ r = 0;
+ break;
+ }
+ }
+ mutex_unlock(&mtx);
+
+ if (r)
+ return r;
+
+ if (copy_to_user(data, &_b->buf_info, sizeof(_b->buf_info)))
+ return -EFAULT;
+ break;
+#endif
+ /* register buffer */
+ case TILIOC_RBUF:
+ /* save buffer information */
+ _b = kmalloc(sizeof(*_b), GFP_KERNEL);
+ if (!_b)
+ return -ENOMEM;
+ memset(_b, 0, sizeof(*_b));
+
+ if (copy_from_user(&_b->buf_info, data, sizeof(_b->buf_info))) {
+ kfree(_b);
+ return -EFAULT;
+ }
+
+ mutex_lock(&mtx);
+ r = _m_register_buf(_b, pi);
+ mutex_unlock(&mtx);
+
+ if (r) {
+ kfree(_b);
+ return -EACCES;
+ }
+
+ /* undo registration on failure */
+ if (copy_to_user(data, &_b->buf_info, sizeof(_b->buf_info))) {
+ mutex_lock(&mtx);
+ _m_unregister_buf(_b);
+ mutex_unlock(&mtx);
+ return -EFAULT;
+ }
+ break;
+ /* unregister a buffer */
+ case TILIOC_URBUF:
+ if (copy_from_user(&buf_info, data, sizeof(buf_info)))
+ return -EFAULT;
+
+ /* find buffer */
+ r = -EFAULT;
+ mutex_lock(&mtx);
+ /* buffer registration is per process */
+ list_for_each_entry(_b, &pi->bufs, by_pid) {
+ if (buf_info.offset == _b->buf_info.offset) {
+ _m_unregister_buf(_b);
+ /* only retrieve buffer length */
+ buf_info.length = _b->buf_info.length;
+ r = 0;
+ break;
+ }
+ }
+ mutex_unlock(&mtx);
+
+ if (r)
+ return r;
+
+ if (copy_to_user(data, &buf_info, sizeof(buf_info)))
+ return -EFAULT;
+ break;
+ /* prereserv blocks */
+ case TILIOC_PRBLK:
+ if (copy_from_user(&block_info, data, sizeof(block_info)))
+ return -EFAULT;
+
+ if (block_info.fmt == TILFMT_8AND16)
+ ops->reserve_nv12(block_info.key,
+ block_info.dim.area.width,
+ block_info.dim.area.height,
+ block_info.align,
+ block_info.offs,
+ block_info.group_id, pi);
+ else
+ ops->reserve(block_info.key,
+ block_info.fmt,
+ block_info.dim.area.width,
+ block_info.dim.area.height,
+ block_info.align,
+ block_info.offs,
+ block_info.group_id, pi);
+ break;
+ /* unreserve blocks */
+ case TILIOC_URBLK:
+ ops->unreserve(arg, pi);
+ break;
+ /* query a tiler block */
+ case TILIOC_QBLK:
+ if (copy_from_user(&block_info, data, sizeof(block_info)))
+ return -EFAULT;
+
+ if (block_info.id) {
+ /* look up by id if specified */
+ mutex_lock(&mtx);
+ mi = _m_lock_block(block_info.key, block_info.id, pi);
+ mutex_unlock(&mtx);
+ } else
+#ifndef CONFIG_TILER_SECURE
+ if (ssptr_lookup) {
+ /* otherwise, look up by ssptr if allowed */
+ mi = ops->lock_by_ssptr(block_info.ssptr);
+ } else
+#endif
+ return -EPERM;
+
+ if (!mi)
+ return -EFAULT;
+
+ /* we don't keep track of ptr and 1D stride so clear them */
+ block_info.ptr = NULL;
+ block_info.stride = 0;
+
+ ops->describe(mi, &block_info);
+ ops->unlock_free(mi, false);
+
+ if (copy_to_user(data, &block_info, sizeof(block_info)))
+ return -EFAULT;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* open tiler driver */
+static s32 tiler_open(struct inode *ip, struct file *filp)
+{
+ struct process_info *pi = __get_pi(current->tgid, false);
+ if (!pi)
+ return -ENOMEM;
+
+ filp->private_data = pi;
+ return 0;
+}
+
+/* close tiler driver */
+static s32 tiler_release(struct inode *ip, struct file *filp)
+{
+ struct process_info *pi = filp->private_data;
+
+ mutex_lock(&mtx);
+ /* free resources if last device in this process */
+ if (0 == --pi->refs)
+ _m_free_process_info(pi);
+
+ mutex_unlock(&mtx);
+
+ return 0;
+}
+
+/* tiler driver file operations */
+static const struct file_operations tiler_fops = {
+ .open = tiler_open,
+ .unlocked_ioctl = tiler_ioctl,
+ .release = tiler_release,
+ .mmap = tiler_mmap,
+};
+
+/* initialize tiler interface */
+void tiler_iface_init(struct tiler_ops *tiler)
+{
+ ops = tiler;
+ ops->cleanup = destroy_processes;
+ ops->fops = &tiler_fops;
+
+#ifdef CONFIG_TILER_SECURE
+ security = true;
+ offset_lookup = ssptr_lookup = false;
+#endif
+
+ mutex_init(&mtx);
+ INIT_LIST_HEAD(&procs);
+ BLOCKING_INIT_NOTIFIER_HEAD(&notifier);
+}
+
+/*
+ * Kernel APIs
+ * ==========================================================================
+ */
+
+s32 tiler_reg_notifier(struct notifier_block *nb)
+{
+ if (!nb)
+ return -EINVAL;
+ return blocking_notifier_chain_register(&notifier, nb);
+}
+EXPORT_SYMBOL(tiler_reg_notifier);
+
+s32 tiler_unreg_notifier(struct notifier_block *nb)
+{
+ if (!nb)
+ return -EINVAL;
+ return blocking_notifier_chain_unregister(&notifier, nb);
+}
+EXPORT_SYMBOL(tiler_unreg_notifier);
+
+void tiler_reservex(u32 n, enum tiler_fmt fmt, u32 width, u32 height,
+ u32 align, u32 offs, u32 gid, pid_t pid)
+{
+ struct process_info *pi = __get_pi(pid, true);
+
+ if (pi)
+ ops->reserve(n, fmt, width, height, align, offs, gid, pi);
+}
+EXPORT_SYMBOL(tiler_reservex);
+
+void tiler_reserve(u32 n, enum tiler_fmt fmt, u32 width, u32 height,
+ u32 align, u32 offs)
+{
+ tiler_reservex(n, fmt, width, height, align, offs, 0, current->tgid);
+}
+EXPORT_SYMBOL(tiler_reserve);
+
+void tiler_reservex_nv12(u32 n, u32 width, u32 height, u32 align, u32 offs,
+ u32 gid, pid_t pid)
+{
+ struct process_info *pi = __get_pi(pid, true);
+
+ if (pi)
+ ops->reserve_nv12(n, width, height, align, offs, gid, pi);
+}
+EXPORT_SYMBOL(tiler_reservex_nv12);
+
+void tiler_reserve_nv12(u32 n, u32 width, u32 height, u32 align, u32 offs)
+{
+ tiler_reservex_nv12(n, width, height, align, offs, 0, current->tgid);
+}
+EXPORT_SYMBOL(tiler_reserve_nv12);
+
+s32 tiler_allocx(struct tiler_block_t *blk, enum tiler_fmt fmt,
+ u32 align, u32 offs, u32 gid, pid_t pid)
+{
+ struct mem_info *mi;
+ struct process_info *pi;
+ s32 res;
+
+ BUG_ON(!blk || blk->phys);
+
+ pi = __get_pi(pid, true);
+ if (!pi)
+ return -ENOMEM;
+
+ res = ops->alloc(fmt, blk->width, blk->height, align, offs, blk->key,
+ gid, pi, &mi);
+ if (mi) {
+ blk->phys = mi->blk.phys;
+ blk->id = mi->blk.id;
+ }
+ return res;
+}
+EXPORT_SYMBOL(tiler_allocx);
+
+s32 tiler_alloc(struct tiler_block_t *blk, enum tiler_fmt fmt,
+ u32 align, u32 offs)
+{
+ return tiler_allocx(blk, fmt, align, offs, 0, current->tgid);
+}
+EXPORT_SYMBOL(tiler_alloc);
+
+s32 tiler_mapx(struct tiler_block_t *blk, enum tiler_fmt fmt, u32 gid,
+ pid_t pid, u32 usr_addr)
+{
+ struct mem_info *mi;
+ struct process_info *pi;
+ s32 res;
+
+ BUG_ON(!blk || blk->phys);
+
+ pi = __get_pi(pid, true);
+ if (!pi)
+ return -ENOMEM;
+
+ res = ops->map(fmt, blk->width, blk->height, blk->key, gid, pi, &mi,
+ usr_addr);
+ if (mi) {
+ blk->phys = mi->blk.phys;
+ blk->id = mi->blk.id;
+ }
+ return res;
+
+}
+EXPORT_SYMBOL(tiler_mapx);
+
+s32 tiler_map(struct tiler_block_t *blk, enum tiler_fmt fmt, u32 usr_addr)
+{
+ return tiler_mapx(blk, fmt, 0, current->tgid, usr_addr);
+}
+EXPORT_SYMBOL(tiler_map);
+
+s32 tiler_mmap_blk(struct tiler_block_t *blk, u32 offs, u32 size,
+ struct vm_area_struct *vma, u32 voffs)
+{
+ u32 v, p, len;
+
+ /* mapping must fit into vma */
+ BUG_ON(vma->vm_start > vma->vm_start + voffs ||
+ vma->vm_start + voffs > vma->vm_start + voffs + size ||
+ vma->vm_start + voffs + size > vma->vm_end);
+
+ /* mapping must fit into block */
+ BUG_ON(offs > offs + size || offs + size > tiler_size(blk));
+
+ v = tiler_vstride(blk);
+ p = tiler_pstride(blk);
+
+ /* remap block portion */
+ len = v - (offs % v); /* initial area to map */
+ while (size) {
+ /* restrict to size still needs mapping */
+ if (len > size)
+ len = size;
+
+ vma->vm_pgoff = (blk->phys + offs) >> PAGE_SHIFT;
+ if (remap_pfn_range(vma, vma->vm_start + voffs, vma->vm_pgoff,
+ len, vma->vm_page_prot))
+ return -EAGAIN;
+ voffs += len;
+ offs += len + p - v;
+ size -= len;
+ len = v; /* subsequent area to map */
+ }
+ return 0;
+}
+EXPORT_SYMBOL(tiler_mmap_blk);
+
+s32 tiler_ioremap_blk(struct tiler_block_t *blk, u32 offs, u32 size,
+ u32 addr, u32 mtype)
+{
+ u32 v, p;
+ u32 len; /* area to map */
+ const struct mem_type *type = get_mem_type(mtype);
+
+ /* mapping must fit into address space */
+ BUG_ON(addr > addr + size);
+
+ /* mapping must fit into block */
+ BUG_ON(offs > offs + size || offs + size > tiler_size(blk));
+
+ v = tiler_vstride(blk);
+ p = tiler_pstride(blk);
+
+ /* move offset and address to end */
+ offs += blk->phys + size;
+ addr += size;
+
+ len = v - (offs % v); /* initial area to map */
+ while (size) {
+ while (len && size) {
+ if (ioremap_page(addr - size, offs - size, type))
+ return -EAGAIN;
+ len -= PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ offs += p - v;
+ len = v; /* subsequent area to map */
+ }
+ return 0;
+}
+EXPORT_SYMBOL(tiler_ioremap_blk);
+
+void tiler_free(struct tiler_block_t *blk)
+{
+ /* find block */
+ struct mem_info *mi = ops->lock(blk->key, blk->id, NULL);
+ if (mi)
+ ops->unlock_free(mi, true);
+ blk->phys = blk->id = 0;
+}
+EXPORT_SYMBOL(tiler_free);
diff --git a/drivers/media/video/tiler/tiler-main.c b/drivers/media/video/tiler/tiler-main.c
new file mode 100644
index 00000000000..4d33d09fc73
--- /dev/null
+++ b/drivers/media/video/tiler/tiler-main.c
@@ -0,0 +1,1270 @@
+/*
+ * tiler-main.c
+ *
+ * TILER driver main support functions for TI TILER hardware block.
+ *
+ * Authors: Lajos Molnar <molnar@ti.com>
+ * David Sin <davidsin@ti.com>
+ *
+ * Copyright (C) 2009-2010 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/cdev.h> /* struct cdev */
+#include <linux/kdev_t.h> /* MKDEV() */
+#include <linux/fs.h> /* register_chrdev_region() */
+#include <linux/device.h> /* struct class */
+#include <linux/platform_device.h> /* platform_device() */
+#include <linux/err.h> /* IS_ERR() */
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/dma-mapping.h> /* dma_alloc_coherent */
+#include <linux/pagemap.h> /* page_cache_release() */
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#include <mach/dmm.h>
+#include "tmm.h"
+#include "_tiler.h"
+#include "tcm/tcm-sita.h" /* TCM algorithm */
+
+static bool ssptr_id = CONFIG_TILER_SSPTR_ID;
+static uint default_align = CONFIG_TILER_ALIGNMENT;
+static uint granularity = CONFIG_TILER_GRANULARITY;
+
+/*
+ * We can only change ssptr_id if there are no blocks allocated, so that
+ * pseudo-random ids and ssptrs do not potentially clash. For now make it
+ * read-only.
+ */
+module_param(ssptr_id, bool, 0444);
+MODULE_PARM_DESC(ssptr_id, "Use ssptr as block ID");
+module_param_named(align, default_align, uint, 0644);
+MODULE_PARM_DESC(align, "Default block ssptr alignment");
+module_param_named(grain, granularity, uint, 0644);
+MODULE_PARM_DESC(grain, "Granularity (bytes)");
+
+struct tiler_dev {
+ struct cdev cdev;
+};
+
+struct platform_driver tiler_driver_ldm = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tiler",
+ },
+ .probe = NULL,
+ .shutdown = NULL,
+ .remove = NULL,
+};
+
+static struct tiler_ops tiler; /* shared methods and variables */
+
+static struct list_head blocks; /* all tiler blocks */
+static struct list_head orphan_areas; /* orphaned 2D areas */
+static struct list_head orphan_onedim; /* orphaned 1D areas */
+
+static s32 tiler_major;
+static s32 tiler_minor;
+static struct tiler_dev *tiler_device;
+static struct class *tilerdev_class;
+static struct mutex mtx;
+static struct tcm *tcm[TILER_FORMATS];
+static struct tmm *tmm[TILER_FORMATS];
+static u32 *dmac_va;
+static dma_addr_t dmac_pa;
+
+/*
+ * TMM connectors
+ * ==========================================================================
+ */
+/* wrapper around tmm_map */
+static s32 refill_pat(struct tmm *tmm, struct tcm_area *area, u32 *ptr)
+{
+ s32 res = 0;
+ struct pat_area p_area = {0};
+ struct tcm_area slice, area_s;
+
+ tcm_for_each_slice(slice, *area, area_s) {
+ p_area.x0 = slice.p0.x;
+ p_area.y0 = slice.p0.y;
+ p_area.x1 = slice.p1.x;
+ p_area.y1 = slice.p1.y;
+
+ memcpy(dmac_va, ptr, sizeof(*ptr) * tcm_sizeof(slice));
+ ptr += tcm_sizeof(slice);
+
+ if (tmm_map(tmm, p_area, dmac_pa)) {
+ res = -EFAULT;
+ break;
+ }
+ }
+
+ return res;
+}
+
+/* wrapper around tmm_clear */
+static void clear_pat(struct tmm *tmm, struct tcm_area *area)
+{
+ struct pat_area p_area = {0};
+ struct tcm_area slice, area_s;
+
+ tcm_for_each_slice(slice, *area, area_s) {
+ p_area.x0 = slice.p0.x;
+ p_area.y0 = slice.p0.y;
+ p_area.x1 = slice.p1.x;
+ p_area.y1 = slice.p1.y;
+
+ tmm_clear(tmm, p_area);
+ }
+}
+
+/*
+ * ID handling methods
+ * ==========================================================================
+ */
+
+/* check if an id is used */
+static bool _m_id_in_use(u32 id)
+{
+ struct mem_info *mi;
+ list_for_each_entry(mi, &blocks, global)
+ if (mi->blk.id == id)
+ return 1;
+ return 0;
+}
+
+/* get an id */
+static u32 _m_get_id(void)
+{
+ static u32 id = 0x2d7ae;
+
+ /* ensure noone is using this id */
+ while (_m_id_in_use(id)) {
+ /* generate a new pseudo-random ID */
+
+ /* Galois LSFR: 32, 22, 2, 1 */
+ id = (id >> 1) ^ (u32)((0 - (id & 1u)) & 0x80200003u);
+ }
+
+ return id;
+}
+
+/*
+ * gid_info handling methods
+ * ==========================================================================
+ */
+
+/* get or create new gid_info object */
+static struct gid_info *_m_get_gi(struct process_info *pi, u32 gid)
+{
+ struct gid_info *gi;
+
+ /* have mutex */
+
+ /* see if group already exist */
+ list_for_each_entry(gi, &pi->groups, by_pid) {
+ if (gi->gid == gid)
+ goto done;
+ }
+
+ /* create new group */
+ gi = kmalloc(sizeof(*gi), GFP_KERNEL);
+ if (!gi)
+ return gi;
+
+ memset(gi, 0, sizeof(*gi));
+ INIT_LIST_HEAD(&gi->areas);
+ INIT_LIST_HEAD(&gi->onedim);
+ INIT_LIST_HEAD(&gi->reserved);
+ gi->pi = pi;
+ gi->gid = gid;
+ list_add(&gi->by_pid, &pi->groups);
+done:
+ /*
+ * Once area is allocated, the group info's ref count will be
+ * decremented as the reference is no longer needed.
+ */
+ gi->refs++;
+ return gi;
+}
+
+/* free gid_info object if empty */
+static void _m_try_free_group(struct gid_info *gi)
+{
+ /* have mutex */
+ if (gi && list_empty(&gi->areas) && list_empty(&gi->onedim) &&
+ /* also ensure noone is still using this group */
+ !gi->refs) {
+ BUG_ON(!list_empty(&gi->reserved));
+ list_del(&gi->by_pid);
+
+ /* if group is tracking kernel objects, we may free even
+ the process info */
+ if (gi->pi->kernel && list_empty(&gi->pi->groups)) {
+ list_del(&gi->pi->list);
+ kfree(gi->pi);
+ }
+
+ kfree(gi);
+ }
+}
+
+/* --- external versions --- */
+
+static struct gid_info *get_gi(struct process_info *pi, u32 gid)
+{
+ struct gid_info *gi;
+ mutex_lock(&mtx);
+ gi = _m_get_gi(pi, gid);
+ mutex_unlock(&mtx);
+ return gi;
+}
+
+static void release_gi(struct gid_info *gi)
+{
+ mutex_lock(&mtx);
+ gi->refs--;
+ _m_try_free_group(gi);
+ mutex_unlock(&mtx);
+}
+
+/*
+ * Area handling methods
+ * ==========================================================================
+ */
+
+/* allocate an reserved area of size, alignment and link it to gi */
+/* leaves mutex locked to be able to add block to area */
+static struct area_info *area_new_m(u16 width, u16 height, u16 align,
+ struct tcm *tcm, struct gid_info *gi)
+{
+ struct area_info *ai = kmalloc(sizeof(*ai), GFP_KERNEL);
+ if (!ai)
+ return NULL;
+
+ /* set up empty area info */
+ memset(ai, 0x0, sizeof(*ai));
+ INIT_LIST_HEAD(&ai->blocks);
+
+ /* reserve an allocation area */
+ if (tcm_reserve_2d(tcm, width, height, align, &ai->area)) {
+ kfree(ai);
+ return NULL;
+ }
+
+ ai->gi = gi;
+ mutex_lock(&mtx);
+ list_add_tail(&ai->by_gid, &gi->areas);
+ return ai;
+}
+
+/* (must have mutex) free an area */
+static inline void _m_area_free(struct area_info *ai)
+{
+ if (ai) {
+ list_del(&ai->by_gid);
+ kfree(ai);
+ }
+}
+
+static s32 __analize_area(enum tiler_fmt fmt, u32 width, u32 height,
+ u16 *x_area, u16 *y_area, u16 *band,
+ u16 *align, u16 *offs, u16 *in_offs)
+{
+ /* input: width, height is in pixels, align, offs in bytes */
+ /* output: x_area, y_area, band, align, offs in slots */
+
+ /* slot width, height, and row size */
+ u32 slot_row, min_align;
+ const struct tiler_geom *g;
+
+ /* width and height must be positive */
+ if (!width || !height)
+ return -EINVAL;
+
+ /* align must be 2 power */
+ if (*align & (*align - 1))
+ return -EINVAL;
+
+ if (fmt == TILFMT_PAGE) {
+ /* adjust size to accomodate offset, only do page alignment */
+ *align = PAGE_SIZE;
+ *in_offs = *offs & ~PAGE_MASK;
+ width += *in_offs;
+
+ /* for 1D area keep the height (1), width is in tiler slots */
+ *x_area = DIV_ROUND_UP(width, tiler.page);
+ *y_area = *band = 1;
+
+ if (*x_area * *y_area > tiler.width * tiler.height)
+ return -ENOMEM;
+ return 0;
+ }
+
+ /* format must be valid */
+ g = tiler.geom(fmt);
+ if (!g)
+ return -EINVAL;
+
+ /* get the # of bytes per row in 1 slot */
+ slot_row = g->slot_w * g->bpp;
+
+ /* how many slots are can be accessed via one physical page */
+ *band = PAGE_SIZE / slot_row;
+
+ /* minimum alignment is at least 1 slot. Use default if needed */
+ min_align = max(slot_row, granularity);
+ *align = ALIGN(*align ? : default_align, min_align);
+
+ /* align must still be 2 power (in case default_align is wrong) */
+ if (*align & (*align - 1))
+ return -EAGAIN;
+
+ /* offset must be multiple of bpp */
+ if (*offs & (g->bpp - 1) || *offs >= *align)
+ return -EINVAL;
+
+ /* round down the offset to the nearest slot size, and increase width
+ to allow space for having the correct offset */
+ width += (*offs & (min_align - 1)) / g->bpp;
+ if (in_offs)
+ *in_offs = *offs & (min_align - 1);
+ *offs &= ~(min_align - 1);
+
+ /* expand width to block size */
+ width = ALIGN(width, min_align / g->bpp);
+
+ /* adjust to slots */
+ *x_area = DIV_ROUND_UP(width, g->slot_w);
+ *y_area = DIV_ROUND_UP(height, g->slot_h);
+ *align /= slot_row;
+ *offs /= slot_row;
+
+ if (*x_area > tiler.width || *y_area > tiler.height)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * Find a place where a 2D block would fit into a 2D area of the
+ * same height.
+ *
+ * @author a0194118 (3/19/2010)
+ *
+ * @param w Width of the block.
+ * @param align Alignment of the block.
+ * @param offs Offset of the block (within alignment)
+ * @param ai Pointer to area info
+ * @param next Pointer to the variable where the next block
+ * will be stored. The block should be inserted
+ * before this block.
+ *
+ * @return the end coordinate (x1 + 1) where a block would fit,
+ * or 0 if it does not fit.
+ *
+ * (must have mutex)
+ */
+static u16 _m_blk_find_fit(u16 w, u16 align, u16 offs,
+ struct area_info *ai, struct list_head **before)
+{
+ int x = ai->area.p0.x + w + offs;
+ struct mem_info *mi;
+
+ /* area blocks are sorted by x */
+ list_for_each_entry(mi, &ai->blocks, by_area) {
+ /* check if buffer would fit before this area */
+ if (x <= mi->area.p0.x) {
+ *before = &mi->by_area;
+ return x;
+ }
+ x = ALIGN(mi->area.p1.x + 1 - offs, align) + w + offs;
+ }
+ *before = &ai->blocks;
+
+ /* check if buffer would fit after last area */
+ return (x <= ai->area.p1.x + 1) ? x : 0;
+}
+
+/* (must have mutex) adds a block to an area with certain x coordinates */
+static inline
+struct mem_info *_m_add2area(struct mem_info *mi, struct area_info *ai,
+ u16 x0, u16 w, struct list_head *before)
+{
+ mi->parent = ai;
+ mi->area = ai->area;
+ mi->area.p0.x = x0;
+ mi->area.p1.x = x0 + w - 1;
+ list_add_tail(&mi->by_area, before);
+ ai->nblocks++;
+ return mi;
+}
+
+static struct mem_info *get_2d_area(u16 w, u16 h, u16 align, u16 offs, u16 band,
+ struct gid_info *gi, struct tcm *tcm)
+{
+ struct area_info *ai = NULL;
+ struct mem_info *mi = NULL;
+ struct list_head *before = NULL;
+ u16 x = 0; /* this holds the end of a potential area */
+
+ /* allocate map info */
+
+ /* see if there is available prereserved space */
+ mutex_lock(&mtx);
+ list_for_each_entry(mi, &gi->reserved, global) {
+ if (mi->area.tcm == tcm &&
+ tcm_aheight(mi->area) == h &&
+ tcm_awidth(mi->area) == w &&
+ (mi->area.p0.x & (align - 1)) == offs) {
+ /* this area is already set up */
+
+ /* remove from reserved list */
+ list_del(&mi->global);
+ goto done;
+ }
+ }
+ mutex_unlock(&mtx);
+
+ /* if not, reserve a block struct */
+ mi = kmalloc(sizeof(*mi), GFP_KERNEL);
+ if (!mi)
+ return mi;
+ memset(mi, 0, sizeof(*mi));
+
+ /* see if allocation fits in one of the existing areas */
+ /* this sets x, ai and before */
+ mutex_lock(&mtx);
+ list_for_each_entry(ai, &gi->areas, by_gid) {
+ if (ai->area.tcm == tcm &&
+ tcm_aheight(ai->area) == h) {
+ x = _m_blk_find_fit(w, align, offs, ai, &before);
+ if (x) {
+ _m_add2area(mi, ai, x - w, w, before);
+ goto done;
+ }
+ }
+ }
+ mutex_unlock(&mtx);
+
+ /* if no area fit, reserve a new one */
+ ai = area_new_m(ALIGN(w + offs, max(band, align)), h,
+ max(band, align), tcm, gi);
+ if (ai) {
+ _m_add2area(mi, ai, ai->area.p0.x + offs, w, &ai->blocks);
+ } else {
+ /* clean up */
+ kfree(mi);
+ return NULL;
+ }
+
+done:
+ mutex_unlock(&mtx);
+ return mi;
+}
+
+/* layout reserved 2d blocks in a larger area */
+/* NOTE: band, w, h, a(lign), o(ffs) is in slots */
+static s32 lay_2d(enum tiler_fmt fmt, u16 n, u16 w, u16 h, u16 band,
+ u16 align, u16 offs, struct gid_info *gi,
+ struct list_head *pos)
+{
+ u16 x, x0, e = ALIGN(w, align), w_res = (n - 1) * e + w;
+ struct mem_info *mi = NULL;
+ struct area_info *ai = NULL;
+
+ printk(KERN_INFO "packing %u %u buffers into %u width\n",
+ n, w, w_res);
+
+ /* calculate dimensions, band, offs and alignment in slots */
+ /* reserve an area */
+ ai = area_new_m(ALIGN(w_res + offs, max(band, align)), h,
+ max(band, align), tcm[fmt], gi);
+ if (!ai)
+ return -ENOMEM;
+
+ /* lay out blocks in the reserved area */
+ for (n = 0, x = offs; x < w_res; x += e, n++) {
+ /* reserve a block struct */
+ mi = kmalloc(sizeof(*mi), GFP_KERNEL);
+ if (!mi)
+ break;
+
+ memset(mi, 0, sizeof(*mi));
+ x0 = ai->area.p0.x + x;
+ _m_add2area(mi, ai, x0, w, &ai->blocks);
+ list_add(&mi->global, pos);
+ }
+
+ mutex_unlock(&mtx);
+ return n;
+}
+
+/* layout reserved nv12 blocks in a larger area */
+/* NOTE: area w(idth), w1 (8-bit block width), h(eight) are in slots */
+/* p is a pointer to a packing description, which is a list of offsets in
+ the area for consecutive 8-bit and 16-bit blocks */
+static s32 lay_nv12(int n, u16 w, u16 w1, u16 h, struct gid_info *gi, u8 *p)
+{
+ u16 wh = (w1 + 1) >> 1, width, x0;
+ int m;
+ int a = PAGE_SIZE / tiler.geom(TILFMT_8BIT)->slot_w;
+
+ struct mem_info *mi = NULL;
+ struct area_info *ai = NULL;
+ struct list_head *pos;
+
+ /* reserve area */
+ ai = area_new_m(w, h, a, TILFMT_8BIT, gi);
+ if (!ai)
+ return -ENOMEM;
+
+ /* lay out blocks in the reserved area */
+ for (m = 0; m < 2 * n; m++) {
+ width = (m & 1) ? wh : w1;
+ x0 = ai->area.p0.x + *p++;
+
+ /* get insertion head */
+ list_for_each(pos, &ai->blocks) {
+ mi = list_entry(pos, struct mem_info, by_area);
+ if (mi->area.p0.x > x0)
+ break;
+ }
+
+ /* reserve a block struct */
+ mi = kmalloc(sizeof(*mi), GFP_KERNEL);
+ if (!mi)
+ break;
+
+ memset(mi, 0, sizeof(*mi));
+
+ _m_add2area(mi, ai, x0, width, pos);
+ list_add(&mi->global, &gi->reserved);
+ }
+
+ mutex_unlock(&mtx);
+ return n;
+}
+
+/* (must have mutex) free block and any freed areas */
+static s32 _m_free(struct mem_info *mi)
+{
+ struct area_info *ai = NULL;
+ struct page *page = NULL;
+ s32 res = 0;
+ u32 i;
+
+ /* release memory */
+ if (mi->pg_ptr) {
+ for (i = 0; i < mi->num_pg; i++) {
+ page = (struct page *)mi->pg_ptr[i];
+ if (page) {
+ if (!PageReserved(page))
+ SetPageDirty(page);
+ page_cache_release(page);
+ }
+ }
+ kfree(mi->pg_ptr);
+ } else if (mi->mem) {
+ tmm_free(tmm[tiler_fmt(mi->blk.phys)], mi->mem);
+ }
+ clear_pat(tmm[tiler_fmt(mi->blk.phys)], &mi->area);
+
+ /* safe deletion as list may not have been assigned */
+ if (mi->global.next)
+ list_del(&mi->global);
+ if (mi->by_area.next)
+ list_del(&mi->by_area);
+
+ /* remove block from area first if 2D */
+ if (mi->area.is2d) {
+ ai = mi->parent;
+
+ /* check to see if area needs removing also */
+ if (ai && !--ai->nblocks) {
+ res = tcm_free(&ai->area);
+ list_del(&ai->by_gid);
+ /* try to remove parent if it became empty */
+ _m_try_free_group(ai->gi);
+ kfree(ai);
+ ai = NULL;
+ }
+ } else {
+ /* remove 1D area */
+ res = tcm_free(&mi->area);
+ /* try to remove parent if it became empty */
+ _m_try_free_group(mi->parent);
+ }
+
+ kfree(mi);
+ return res;
+}
+
+/* (must have mutex) returns true if block was freed */
+static bool _m_chk_ref(struct mem_info *mi)
+{
+ /* check references */
+ if (mi->refs)
+ return 0;
+
+ if (_m_free(mi))
+ printk(KERN_ERR "error while removing tiler block\n");
+
+ return 1;
+}
+
+/* (must have mutex) */
+static inline bool _m_dec_ref(struct mem_info *mi)
+{
+ if (mi->refs-- <= 1)
+ return _m_chk_ref(mi);
+
+ return 0;
+}
+
+/* (must have mutex) */
+static inline void _m_inc_ref(struct mem_info *mi)
+{
+ mi->refs++;
+}
+
+/* (must have mutex) returns true if block was freed */
+static inline bool _m_try_free(struct mem_info *mi)
+{
+ if (mi->alloced) {
+ mi->refs--;
+ mi->alloced = false;
+ }
+ return _m_chk_ref(mi);
+}
+
+/* --- external methods --- */
+
+/* find a block by key/id and lock it */
+static struct mem_info *
+find_n_lock(u32 key, u32 id, struct gid_info *gi) {
+ struct area_info *ai = NULL;
+ struct mem_info *mi = NULL;
+
+ mutex_lock(&mtx);
+
+ /* if group is not given, look globally */
+ if (!gi) {
+ list_for_each_entry(mi, &blocks, global) {
+ if (mi->blk.key == key && mi->blk.id == id)
+ goto done;
+ }
+ } else {
+ /* is id is ssptr, we know if block is 1D or 2D by the address,
+ so we optimize lookup */
+ if (!ssptr_id ||
+ tiler_fmt(id) == TILFMT_PAGE) {
+ list_for_each_entry(mi, &gi->onedim, by_area) {
+ if (mi->blk.key == key && mi->blk.id == id)
+ goto done;
+ }
+ }
+
+ if (!ssptr_id ||
+ tiler_fmt(id) != TILFMT_PAGE) {
+ list_for_each_entry(ai, &gi->areas, by_gid) {
+ list_for_each_entry(mi, &ai->blocks, by_area) {
+ if (mi->blk.key == key &&
+ mi->blk.id == id)
+ goto done;
+ }
+ }
+ }
+ }
+
+ mi = NULL;
+done:
+ /* lock block by increasing its ref count */
+ if (mi)
+ mi->refs++;
+
+ mutex_unlock(&mtx);
+
+ return mi;
+}
+
+/* unlock a block, and optionally free it */
+static void unlock_n_free(struct mem_info *mi, bool free)
+{
+ mutex_lock(&mtx);
+
+ _m_dec_ref(mi);
+ if (free)
+ _m_try_free(mi);
+
+ mutex_unlock(&mtx);
+}
+
+/**
+ * Free all blocks in a group:
+ *
+ * allocated blocks, and unreferenced blocks. Any blocks/areas still referenced
+ * will move to the orphaned lists to avoid issues if a new process is created
+ * with the same pid.
+ *
+ * (must have mutex)
+ */
+static void destroy_group(struct gid_info *gi)
+{
+ struct area_info *ai, *ai_;
+ struct mem_info *mi, *mi_;
+ bool ai_autofreed, need2free;
+
+ mutex_lock(&mtx);
+
+ /* free all allocated blocks, and remove unreferenced ones */
+
+ /*
+ * Group info structs when they become empty on an _m_try_free.
+ * However, if the group info is already empty, we need to
+ * remove it manually
+ */
+ need2free = list_empty(&gi->areas) && list_empty(&gi->onedim);
+ list_for_each_entry_safe(ai, ai_, &gi->areas, by_gid) {
+ ai_autofreed = true;
+ list_for_each_entry_safe(mi, mi_, &ai->blocks, by_area)
+ ai_autofreed &= _m_try_free(mi);
+
+ /* save orphaned areas for later removal */
+ if (!ai_autofreed) {
+ need2free = true;
+ ai->gi = NULL;
+ list_move(&ai->by_gid, &orphan_areas);
+ }
+ }
+
+ list_for_each_entry_safe(mi, mi_, &gi->onedim, by_area) {
+ if (!_m_try_free(mi)) {
+ need2free = true;
+ /* save orphaned 1D blocks */
+ mi->parent = NULL;
+ list_move(&mi->by_area, &orphan_onedim);
+ }
+ }
+
+ /* if group is still alive reserved list should have been
+ emptied as there should be no reference on those blocks */
+ if (need2free) {
+ BUG_ON(!list_empty(&gi->onedim));
+ BUG_ON(!list_empty(&gi->areas));
+ _m_try_free_group(gi);
+ }
+
+ mutex_unlock(&mtx);
+}
+
+/* release (reserved) blocks */
+static void release_blocks(struct list_head *reserved)
+{
+ struct mem_info *mi, *mi_;
+
+ mutex_lock(&mtx);
+
+ /* find block in global list and free it */
+ list_for_each_entry_safe(mi, mi_, reserved, global) {
+ BUG_ON(mi->refs || mi->alloced);
+ _m_free(mi);
+ }
+ mutex_unlock(&mtx);
+}
+
+/* add reserved blocks to a group */
+static void add_reserved_blocks(struct list_head *reserved, struct gid_info *gi)
+{
+ mutex_lock(&mtx);
+ list_splice_init(reserved, &gi->reserved);
+ mutex_unlock(&mtx);
+}
+
+/* find a block by ssptr */
+static struct mem_info *find_block_by_ssptr(u32 sys_addr)
+{
+ struct mem_info *i;
+ struct tcm_pt pt;
+ u32 x, y;
+ enum tiler_fmt fmt;
+ const struct tiler_geom *g;
+
+ fmt = tiler_fmt(sys_addr);
+ if (fmt == TILFMT_INVALID)
+ return NULL;
+
+ g = tiler.geom(fmt);
+
+ /* convert x & y pixel coordinates to slot coordinates */
+ tiler.xy(sys_addr, &x, &y);
+ pt.x = x / g->slot_w;
+ pt.y = y / g->slot_h;
+
+ mutex_lock(&mtx);
+ list_for_each_entry(i, &blocks, global) {
+ if (tiler_fmt(i->blk.phys) == tiler_fmt(sys_addr) &&
+ tcm_is_in(pt, i->area)) {
+ i->refs++;
+ goto found;
+ }
+ }
+ i = NULL;
+
+found:
+ mutex_unlock(&mtx);
+ return i;
+}
+
+/* find a block by ssptr */
+static void fill_block_info(struct mem_info *i, struct tiler_block_info *blk)
+{
+ blk->fmt = tiler_fmt(i->blk.phys);
+#ifdef CONFIG_TILER_EXPOSE_SSPTR
+ blk->ssptr = i->blk.phys;
+#endif
+ if (blk->fmt == TILFMT_PAGE) {
+ blk->dim.len = i->blk.width;
+ blk->group_id = ((struct gid_info *) i->parent)->gid;
+ } else {
+ blk->stride = tiler_vstride(&i->blk);
+ blk->dim.area.width = i->blk.width;
+ blk->dim.area.height = i->blk.height;
+ blk->group_id = ((struct area_info *) i->parent)->gi->gid;
+ }
+ blk->id = i->blk.id;
+ blk->key = i->blk.key;
+ blk->offs = i->blk.phys & ~PAGE_MASK;
+ blk->align = PAGE_SIZE;
+}
+
+/*
+ * Block operations
+ * ==========================================================================
+ */
+
+static struct mem_info *__get_area(enum tiler_fmt fmt, u32 width, u32 height,
+ u16 align, u16 offs, struct gid_info *gi)
+{
+ u16 x, y, band, in_offs = 0;
+ struct mem_info *mi = NULL;
+ const struct tiler_geom *g = tiler.geom(fmt);
+
+ /* calculate dimensions, band, offs and alignment in slots */
+ if (__analize_area(fmt, width, height, &x, &y, &band, &align, &offs,
+ &in_offs))
+ return NULL;
+
+ if (fmt == TILFMT_PAGE) {
+ /* 1D areas don't pack */
+ mi = kmalloc(sizeof(*mi), GFP_KERNEL);
+ if (!mi)
+ return NULL;
+ memset(mi, 0x0, sizeof(*mi));
+
+ if (tcm_reserve_1d(tcm[fmt], x * y, &mi->area)) {
+ kfree(mi);
+ return NULL;
+ }
+
+ mutex_lock(&mtx);
+ mi->parent = gi;
+ list_add(&mi->by_area, &gi->onedim);
+ } else {
+ mi = get_2d_area(x, y, align, offs, band, gi, tcm[fmt]);
+ if (!mi)
+ return NULL;
+
+ mutex_lock(&mtx);
+ }
+
+ list_add(&mi->global, &blocks);
+ mi->alloced = true;
+ mi->refs++;
+ gi->refs--;
+ mutex_unlock(&mtx);
+
+ mi->blk.phys = tiler.addr(fmt,
+ mi->area.p0.x * g->slot_w, mi->area.p0.y * g->slot_h)
+ + in_offs;
+ return mi;
+}
+
+static s32 alloc_block(enum tiler_fmt fmt, u32 width, u32 height,
+ u32 align, u32 offs, u32 key, u32 gid, struct process_info *pi,
+ struct mem_info **info)
+{
+ struct mem_info *mi = NULL;
+ struct gid_info *gi = NULL;
+
+ *info = NULL;
+
+ /* only support up to page alignment */
+ if (align > PAGE_SIZE || offs >= (align ? : default_align) || !pi)
+ return -EINVAL;
+
+ /* get group context */
+ mutex_lock(&mtx);
+ gi = _m_get_gi(pi, gid);
+ mutex_unlock(&mtx);
+
+ if (!gi)
+ return -ENOMEM;
+
+ /* reserve area in tiler container */
+ mi = __get_area(fmt, width, height, align, offs, gi);
+ if (!mi) {
+ mutex_lock(&mtx);
+ gi->refs--;
+ _m_try_free_group(gi);
+ mutex_unlock(&mtx);
+ return -ENOMEM;
+ }
+
+ mi->blk.width = width;
+ mi->blk.height = height;
+ mi->blk.key = key;
+ if (ssptr_id) {
+ mi->blk.id = mi->blk.phys;
+ } else {
+ mutex_lock(&mtx);
+ mi->blk.id = _m_get_id();
+ mutex_unlock(&mtx);
+ }
+
+ /* allocate and map if mapping is supported */
+ if (tmm_can_map(tmm[fmt])) {
+ mi->num_pg = tcm_sizeof(mi->area);
+
+ mi->mem = tmm_get(tmm[fmt], mi->num_pg);
+ if (!mi->mem)
+ goto cleanup;
+
+ /* Ensure the data reaches to main memory before PAT refill */
+ wmb();
+
+ /* program PAT */
+ if (refill_pat(tmm[fmt], &mi->area, mi->mem))
+ goto cleanup;
+ }
+ *info = mi;
+ return 0;
+
+cleanup:
+ mutex_lock(&mtx);
+ _m_free(mi);
+ mutex_unlock(&mtx);
+ return -ENOMEM;
+
+}
+
+static s32 map_block(enum tiler_fmt fmt, u32 width, u32 height,
+ u32 key, u32 gid, struct process_info *pi,
+ struct mem_info **info, u32 usr_addr)
+{
+ u32 i = 0, tmp = -1, *mem = NULL;
+ u8 write = 0;
+ s32 res = -ENOMEM;
+ struct mem_info *mi = NULL;
+ struct page *page = NULL;
+ struct task_struct *curr_task = current;
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma = NULL;
+ struct gid_info *gi = NULL;
+
+ *info = NULL;
+
+ /* we only support mapping a user buffer in page mode */
+ if (fmt != TILFMT_PAGE)
+ return -EPERM;
+
+ /* check if mapping is supported by tmm */
+ if (!tmm_can_map(tmm[fmt]))
+ return -EPERM;
+
+ /* get group context */
+ mutex_lock(&mtx);
+ gi = _m_get_gi(pi, gid);
+ mutex_unlock(&mtx);
+
+ if (!gi)
+ return -ENOMEM;
+
+ /* reserve area in tiler container */
+ mi = __get_area(fmt, width, height, 0, 0, gi);
+ if (!mi) {
+ mutex_lock(&mtx);
+ gi->refs--;
+ _m_try_free_group(gi);
+ mutex_unlock(&mtx);
+ return -ENOMEM;
+ }
+
+ mi->blk.width = width;
+ mi->blk.height = height;
+ mi->blk.key = key;
+ if (ssptr_id) {
+ mi->blk.id = mi->blk.phys;
+ } else {
+ mutex_lock(&mtx);
+ mi->blk.id = _m_get_id();
+ mutex_unlock(&mtx);
+ }
+
+ mi->usr = usr_addr;
+
+ /* allocate pages */
+ mi->num_pg = tcm_sizeof(mi->area);
+
+ mem = kmalloc(mi->num_pg * sizeof(*mem), GFP_KERNEL);
+ if (!mem)
+ goto done;
+ memset(mem, 0x0, sizeof(*mem) * mi->num_pg);
+
+ mi->pg_ptr = kmalloc(mi->num_pg * sizeof(*mi->pg_ptr), GFP_KERNEL);
+ if (!mi->pg_ptr)
+ goto done;
+ memset(mi->pg_ptr, 0x0, sizeof(*mi->pg_ptr) * mi->num_pg);
+
+ /*
+ * Important Note: usr_addr 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, mi->usr);
+ res = -EFAULT;
+
+ /*
+ * 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) && (mi->usr + width > vma->vm_end)) {
+ /* jump to the next VMA region */
+ vma = find_vma(mm, vma->vm_end + 1);
+ }
+ if (!vma) {
+ printk(KERN_ERR "Failed to get the vma region for "
+ "user buffer.\n");
+ goto fault;
+ }
+
+ if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE))
+ write = 1;
+
+ tmp = mi->usr;
+ for (i = 0; i < mi->num_pg; i++) {
+ if (get_user_pages(curr_task, mm, tmp, 1, write, 1, &page,
+ NULL)) {
+ if (page_count(page) < 1) {
+ printk(KERN_ERR "Bad page count from"
+ "get_user_pages()\n");
+ }
+ mi->pg_ptr[i] = (u32)page;
+ mem[i] = page_to_phys(page);
+ tmp += PAGE_SIZE;
+ } else {
+ printk(KERN_ERR "get_user_pages() failed\n");
+ goto fault;
+ }
+ }
+ up_read(&mm->mmap_sem);
+
+ /* Ensure the data reaches to main memory before PAT refill */
+ wmb();
+
+ if (refill_pat(tmm[fmt], &mi->area, mem))
+ goto fault;
+
+ res = 0;
+ *info = mi;
+ goto done;
+fault:
+ up_read(&mm->mmap_sem);
+done:
+ if (res) {
+ mutex_lock(&mtx);
+ _m_free(mi);
+ mutex_unlock(&mtx);
+ }
+ kfree(mem);
+ return res;
+}
+
+/*
+ * Driver code
+ * ==========================================================================
+ */
+
+static s32 __init tiler_init(void)
+{
+ dev_t dev = 0;
+ s32 r = -1;
+ struct device *device = NULL;
+ struct tcm_pt div_pt;
+ struct tcm *sita = NULL;
+ struct tmm *tmm_pat = NULL;
+
+ tiler.alloc = alloc_block;
+ tiler.map = map_block;
+ tiler.lock = find_n_lock;
+ tiler.unlock_free = unlock_n_free;
+ tiler.lay_2d = lay_2d;
+ tiler.lay_nv12 = lay_nv12;
+ tiler.destroy_group = destroy_group;
+ tiler.lock_by_ssptr = find_block_by_ssptr;
+ tiler.describe = fill_block_info;
+ tiler.get_gi = get_gi;
+ tiler.release_gi = release_gi;
+ tiler.release = release_blocks;
+ tiler.add_reserved = add_reserved_blocks;
+ tiler.analize = __analize_area;
+ tiler_geom_init(&tiler);
+ tiler_reserve_init(&tiler);
+ tiler_iface_init(&tiler);
+
+ /* check module parameters for correctness */
+ if (default_align > PAGE_SIZE ||
+ default_align & (default_align - 1) ||
+ granularity < 1 || granularity > PAGE_SIZE ||
+ granularity & (granularity - 1))
+ return -EINVAL;
+
+ /*
+ * Array of physical pages for PAT programming, which must be a 16-byte
+ * aligned physical address.
+ */
+ dmac_va = dma_alloc_coherent(NULL, tiler.width * tiler.height *
+ sizeof(*dmac_va), &dmac_pa, GFP_ATOMIC);
+ if (!dmac_va)
+ return -ENOMEM;
+
+ /* Allocate tiler container manager (we share 1 on OMAP4) */
+ div_pt.x = tiler.width; /* hardcoded default */
+ div_pt.y = (3 * tiler.height) / 4;
+ sita = sita_init(tiler.width, tiler.height, (void *)&div_pt);
+
+ tcm[TILFMT_8BIT] = sita;
+ tcm[TILFMT_16BIT] = sita;
+ tcm[TILFMT_32BIT] = sita;
+ tcm[TILFMT_PAGE] = sita;
+
+ /* Allocate tiler memory manager (must have 1 unique TMM per TCM ) */
+ tmm_pat = tmm_pat_init(0);
+ tmm[TILFMT_8BIT] = tmm_pat;
+ tmm[TILFMT_16BIT] = tmm_pat;
+ tmm[TILFMT_32BIT] = tmm_pat;
+ tmm[TILFMT_PAGE] = tmm_pat;
+
+ tiler.nv12_packed = tcm[TILFMT_8BIT] == tcm[TILFMT_16BIT];
+
+ tiler_device = kmalloc(sizeof(*tiler_device), GFP_KERNEL);
+ if (!tiler_device || !sita || !tmm_pat) {
+ r = -ENOMEM;
+ goto error;
+ }
+
+ memset(tiler_device, 0x0, sizeof(*tiler_device));
+ if (tiler_major) {
+ dev = MKDEV(tiler_major, tiler_minor);
+ r = register_chrdev_region(dev, 1, "tiler");
+ } else {
+ r = alloc_chrdev_region(&dev, tiler_minor, 1, "tiler");
+ tiler_major = MAJOR(dev);
+ }
+
+ cdev_init(&tiler_device->cdev, tiler.fops);
+ tiler_device->cdev.owner = THIS_MODULE;
+ tiler_device->cdev.ops = tiler.fops;
+
+ r = cdev_add(&tiler_device->cdev, dev, 1);
+ if (r)
+ printk(KERN_ERR "cdev_add():failed\n");
+
+ tilerdev_class = class_create(THIS_MODULE, "tiler");
+
+ if (IS_ERR(tilerdev_class)) {
+ printk(KERN_ERR "class_create():failed\n");
+ goto error;
+ }
+
+ device = device_create(tilerdev_class, NULL, dev, NULL, "tiler");
+ if (device == NULL)
+ printk(KERN_ERR "device_create() fail\n");
+
+ r = platform_driver_register(&tiler_driver_ldm);
+
+ mutex_init(&mtx);
+ INIT_LIST_HEAD(&blocks);
+ INIT_LIST_HEAD(&orphan_areas);
+ INIT_LIST_HEAD(&orphan_onedim);
+
+error:
+ /* TODO: error handling for device registration */
+ if (r) {
+ kfree(tiler_device);
+ tcm_deinit(sita);
+ tmm_deinit(tmm_pat);
+ dma_free_coherent(NULL, tiler.width * tiler.height *
+ sizeof(*dmac_va), dmac_va, dmac_pa);
+ }
+
+ return r;
+}
+
+static void __exit tiler_exit(void)
+{
+ int i, j;
+
+ mutex_lock(&mtx);
+
+ /* free all process data */
+ tiler.cleanup();
+
+ /* all lists should have cleared */
+ BUG_ON(!list_empty(&blocks));
+ BUG_ON(!list_empty(&orphan_onedim));
+ BUG_ON(!list_empty(&orphan_areas));
+
+ mutex_unlock(&mtx);
+
+ dma_free_coherent(NULL, tiler.width * tiler.height * sizeof(*dmac_va),
+ dmac_va, dmac_pa);
+
+ /* close containers only once */
+ for (i = TILFMT_MIN; i <= TILFMT_MAX; i++) {
+ /* remove identical containers (tmm is unique per tcm) */
+ for (j = i + 1; j <= TILFMT_MAX; j++)
+ if (tcm[i] == tcm[j]) {
+ tcm[j] = NULL;
+ tmm[j] = NULL;
+ }
+
+ tcm_deinit(tcm[i]);
+ tmm_deinit(tmm[i]);
+ }
+
+ mutex_destroy(&mtx);
+ platform_driver_unregister(&tiler_driver_ldm);
+ cdev_del(&tiler_device->cdev);
+ kfree(tiler_device);
+ device_destroy(tilerdev_class, MKDEV(tiler_major, tiler_minor));
+ class_destroy(tilerdev_class);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Lajos Molnar <molnar@ti.com>");
+MODULE_AUTHOR("David Sin <davidsin@ti.com>");
+module_init(tiler_init);
+module_exit(tiler_exit);
diff --git a/drivers/media/video/tiler/tiler-reserve.c b/drivers/media/video/tiler/tiler-reserve.c
new file mode 100644
index 00000000000..6715d3ddd6a
--- /dev/null
+++ b/drivers/media/video/tiler/tiler-reserve.c
@@ -0,0 +1,550 @@
+/*
+ * tiler-reserve.c
+ *
+ * TILER driver area reservation functions for TI TILER hardware block.
+ *
+ * Author: Lajos Molnar <molnar@ti.com>
+ *
+ * Copyright (C) 2009-2010 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 "_tiler.h"
+
+static struct tiler_ops *ops; /* shared methods and variables */
+static int band_8; /* size of 8-bit band in slots */
+static int band_16; /* size of 16-bit band in slots */
+
+/**
+ * Calculate the maximum number buffers that can be packed next to each other,
+ * and the area they occupy. This method is used for both 2D and NV12 packing.
+ *
+ * @author a0194118 (7/16/2010)
+ *
+ * @param o desired offset
+ * @param w width of one block (>0)
+ * @param a desired alignment
+ * @param b band width (each block must occupy the same number of bands)
+ * @param n pointer to the desired number of blocks to pack. It will be
+ * updated with the maximum number of blocks that can be packed.
+ * @param _area pointer to store total area needed
+ *
+ * @return packing efficiency (0-1024)
+ */
+static u32 tiler_best2pack(u16 o, u16 a, u16 b, u16 w, u16 *n, u16 *_area)
+{
+ u16 m = 0, max_n = *n; /* m is mostly n - 1 */
+ u16 e = ALIGN(w, a); /* effective width of one block */
+ u32 eff, best_eff = 0; /* best values */
+ u16 stride = ALIGN(o + w, b); /* block stride */
+ u16 area = stride; /* area needed (for m + 1 blocks) */
+
+ /* NOTE: block #m+1 occupies the range (o + m * e, o + m * e + w) */
+
+ /* see how many blocks we can pack */
+ while (m < max_n &&
+ /* blocks must fit in tiler container */
+ o + m * e + w <= ops->width &&
+ /* block stride must be correct */
+ stride == ALIGN(area - o - m * e, b)) {
+
+ m++;
+ eff = m * w * 1024 / area;
+ if (eff > best_eff) {
+ /* store packing for best efficiency & smallest area */
+ best_eff = eff;
+ *n = m;
+ if (_area)
+ *_area = area;
+ }
+ /* update area */
+ area = ALIGN(o + m * e + w, b);
+ }
+
+ return best_eff;
+}
+
+/*
+ * NV12 Reservation Functions
+ *
+ * TILER is designed so that a (w * h) * 8bit area is twice as wide as a
+ * (w/2 * h/2) * 16bit area. Since having pairs of such 8-bit and 16-bit
+ * blocks is a common usecase for TILER, we optimize packing these into a
+ * TILER area.
+ *
+ * During reservation we want to find the most effective packing (most used area
+ * in the smallest overall area)
+ *
+ * We have two algorithms for packing nv12 blocks: either pack 8- and 16-bit
+ * blocks into separate container areas, or pack them together into same area.
+ */
+
+/**
+ * Calculate effectiveness of packing. We weight total area much higher than
+ * packing efficiency to get the smallest overall container use.
+ *
+ * @param w width of one (8-bit) block
+ * @param n buffers in a packing
+ * @param area width of packing area
+ * @param n_total total number of buffers to be packed
+ * @return effectiveness, the higher the better
+ */
+static inline u32 nv12_eff(u16 w, u16 n, u16 area, u16 n_total)
+{
+ return 0x10000000 -
+ /* weigh against total area needed (for all buffers) */
+ /* 64-slots = -2048 */
+ DIV_ROUND_UP(n_total, n) * area * 32 +
+ /* packing efficiency (0 - 1024) */
+ 1024 * n * ((w * 3 + 1) >> 1) / area;
+}
+
+/**
+ * Fallback nv12 packing algorithm: pack 8 and 16 bit block into separate
+ * areas.
+ *
+ * @author a0194118 (7/16/2010)
+ *
+ * @param o desired offset (<a)
+ * @param a desired alignment (>=2)
+ * @param w block width (>0)
+ * @param n number of blocks desired
+ * @param area pointer to store total area needed
+ *
+ * @return number of blocks that can be allocated
+ */
+static u16 nv12_separate(u16 o, u16 a, u16 w, u16 n, u16 *area)
+{
+ tiler_best2pack(o, a, band_8, w, &n, area);
+ tiler_best2pack(o >> 1, a >> 1, band_16, (w + 1) >> 1, &n, area);
+ *area *= 3;
+ return n;
+}
+
+/*
+ * Specialized NV12 Reservation Algorithms
+ *
+ * We use 4 packing methods that pack nv12 blocks into the same area. Together
+ * these 4 methods give the optimal result for most possible input parameters.
+ *
+ * For now we pack into a 64-slot area, so that we don't have to worry about
+ * stride issues (all blocks get 4K stride). For some of the algorithms this
+ * could be true even if the area was 128.
+ */
+
+/**
+ * Packing types are marked using a letter sequence, capital letters denoting
+ * 8-bit blocks, lower case letters denoting corresponding 16-bit blocks.
+ *
+ * All methods have the following parameters. They also define the maximum
+ * number of coordinates that could potentially be packed.
+ *
+ * @param o, a, w, n offset, alignment, width, # of blocks as usual
+ * @param area pointer to store area needed for packing
+ * @param p pointer to store packing coordinates
+ * @return number of blocks that can be packed
+ */
+
+/* Method A: progressive packing: AAAAaaaaBBbbCc into 64-slot area */
+#define MAX_A 21
+static int nv12_A(u16 o, u16 a, u16 w, u16 n, u16 *area, u8 *p)
+{
+ u16 x = o, u, l, m = 0;
+ *area = band_8;
+
+ while (x + w < *area && m < n) {
+ /* current 8bit upper bound (a) is next 8bit lower bound (B) */
+ l = u = (*area + x) >> 1;
+
+ /* pack until upper bound */
+ while (x + w <= u && m < n) {
+ /* save packing */
+ BUG_ON(m + 1 >= MAX_A);
+ *p++ = x;
+ *p++ = l;
+ l = (*area + x + w + 1) >> 1;
+ x = ALIGN(x + w - o, a) + o;
+ m++;
+ }
+ x = ALIGN(l - o, a) + o; /* set new lower bound */
+ }
+ return m;
+}
+
+/* Method -A: regressive packing: cCbbBBaaaaAAAA into 64-slot area */
+static int nv12_revA(u16 o, u16 a, u16 w, u16 n, u16 *area, u8 *p)
+{
+ u16 m;
+
+ /* this is a mirrored packing of method A */
+ n = nv12_A((a - (o + w) % a) % a, a, w, n, area, p);
+
+ /* reverse packing */
+ for (m = 0; m < n; m++) {
+ *p = *area - *p - w;
+ p++;
+ *p = *area - *p - ((w + 1) >> 1);
+ p++;
+ }
+ return n;
+}
+
+/* Method B: simple layout: aAbcBdeCfgDhEFGH */
+#define MAX_B 8
+static int nv12_B(u16 o, u16 a, u16 w, u16 n, u16 *area, u8 *p)
+{
+ u16 e = (o + w) % a; /* end offset */
+ u16 o1 = (o >> 1) % a; /* half offset */
+ u16 e1 = ((o + w + 1) >> 1) % a; /* half end offset */
+ u16 o2 = o1 + (a >> 2); /* 2nd half offset */
+ u16 e2 = e1 + (a >> 2); /* 2nd half end offset */
+ u16 m = 0;
+ *area = band_8;
+
+ /* ensure 16-bit blocks don't overlap 8-bit blocks */
+
+ /* width cannot wrap around alignment, half block must be before block,
+ 2nd half can be before or after */
+ if (w < a && o < e && e1 <= o && (e2 <= o || o2 >= e))
+ while (o + w <= *area && m < n) {
+ BUG_ON(m + 1 >= MAX_B);
+ *p++ = o;
+ *p++ = o >> 1;
+ m++;
+ o += a;
+ }
+ return m;
+}
+
+/* Method C: butterfly layout: AAbbaaBB */
+#define MAX_C 20
+static int nv12_C(u16 o, u16 a, u16 w, u16 n, u16 *area, u8 *p)
+{
+ int m = 0;
+ u16 o2, e = ALIGN(w, a), i = 0, j = 0;
+ *area = band_8;
+ o2 = *area - (a - (o + w) % a) % a; /* end of last possible block */
+
+ m = (min(o2 - 2 * o, 2 * o2 - o - *area) / 3 - w) / e + 1;
+ for (i = j = 0; i < m && j < n; i++, j++) {
+ BUG_ON(j + 1 >= MAX_C);
+ *p++ = o + i * e;
+ *p++ = (o + i * e + *area) >> 1;
+ if (++j < n) {
+ *p++ = o2 - i * e - w;
+ *p++ = (o2 - i * e - w) >> 1;
+ }
+ }
+ return j;
+}
+
+/* Method D: for large allocation: aA or Aa */
+#define MAX_D 1
+static int nv12_D(u16 o, u16 a, u16 w, u16 n, u16 *area, u8 *p)
+{
+ u16 o1, w1 = (w + 1) >> 1, d;
+ *area = ALIGN(o + w, band_8);
+
+ for (d = 0; n > 0 && d + o + w <= *area; d += a) {
+ /* try to fit 16-bit before 8-bit */
+ o1 = ((o + d) % band_8) >> 1;
+ if (o1 + w1 <= o + d) {
+ *p++ = o + d;
+ *p++ = o1;
+ return 1;
+ }
+
+ /* try to fit 16-bit after 8-bit */
+ o1 += ALIGN(d + o + w - o1, band_16);
+ if (o1 + w1 <= *area) {
+ *p++ = o;
+ *p++ = o1;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Umbrella nv12 packing method. This selects the best packings from the above
+ * methods. It also contains hardcoded packings for parameter combinations
+ * that have more efficient packings. This method provides is guaranteed to
+ * provide the optimal packing if 2 <= a <= 64 and w <= 64 and n is large.
+ */
+#define MAX_ANY 21 /* must be MAX(method-MAX-s, hardcoded n-s) */
+static u16 nv12_together(u16 o, u16 a, u16 w, u16 n, u16 *area, u8 *packing)
+{
+ u16 n_best, a_best, n2, a_, o_, w_;
+
+ /* algo results (packings) */
+ u8 pack_A[MAX_A * 2], pack_rA[MAX_A * 2];
+ u8 pack_B[MAX_B * 2], pack_C[MAX_C * 2];
+ u8 pack_D[MAX_D * 2];
+
+ /*
+ * Hardcoded packings. They are sorted by increasing area, and then by
+ * decreasing n. We may not get the best efficiency if less than n
+ * blocks are needed as packings are not necessarily sorted in
+ * increasing order. However, for those n-s one of the other 4 methods
+ * may return the optimal packing.
+ */
+ u8 packings[] = {
+ /* n=9, o=2, w=4, a=4, area=64 */
+ 9, 2, 4, 4, 64,
+ /* 8-bit, 16-bit block coordinate pairs */
+ 2, 33, 6, 35, 10, 37, 14, 39, 18, 41,
+ 46, 23, 50, 25, 54, 27, 58, 29,
+ /* o=0, w=12, a=4, n=3 */
+ 3, 0, 12, 4, 64,
+ 0, 32, 12, 38, 48, 24,
+ /* end */
+ 0
+ }, *p = packings, *p_best = NULL, *p_end;
+ p_end = packings + sizeof(packings) - 1;
+
+ /* see which method gives the best packing */
+
+ /* start with smallest area algorithms A, B & C, stop if we can
+ pack all buffers */
+ n_best = nv12_A(o, a, w, n, area, pack_A);
+ p_best = pack_A;
+ if (n_best < n) {
+ n2 = nv12_revA(o, a, w, n, &a_best, pack_rA);
+ if (n2 > n_best) {
+ n_best = n2;
+ p_best = pack_rA;
+ *area = a_best;
+ }
+ }
+ if (n_best < n) {
+ n2 = nv12_B(o, a, w, n, &a_best, pack_B);
+ if (n2 > n_best) {
+ n_best = n2;
+ p_best = pack_B;
+ *area = a_best;
+ }
+ }
+ if (n_best < n) {
+ n2 = nv12_C(o, a, w, n, &a_best, pack_C);
+ if (n2 > n_best) {
+ n_best = n2;
+ p_best = pack_C;
+ *area = a_best;
+ }
+ }
+
+ /* traverse any special packings */
+ while (*p) {
+ n2 = *p++;
+ o_ = *p++;
+ w_ = *p++;
+ a_ = *p++;
+ /* stop if we already have a better packing */
+ if (n2 < n_best)
+ break;
+
+ /* check if this packing is satisfactory */
+ if (a_ >= a && o + w + ALIGN(o_ - o, a) <= o_ + w_) {
+ *area = *p++;
+ n_best = min(n2, n);
+ p_best = p;
+ break;
+ }
+
+ /* skip to next packing */
+ p += 1 + n2 * 2;
+ }
+
+ /*
+ * If so far unsuccessful, check whether 8 and 16 bit blocks can be
+ * co-packed. This will actually be done in the end by the normal
+ * allocation, but we need to reserve a big-enough area.
+ */
+ if (!n_best) {
+ n_best = nv12_D(o, a, w, n, area, pack_D);
+ p_best = NULL;
+ }
+
+ /* store best packing */
+ if (p_best && n_best) {
+ BUG_ON(n_best > MAX_ANY);
+ memcpy(packing, p_best, n_best * 2 * sizeof(*pack_A));
+ }
+
+ return n_best;
+}
+
+/* reserve nv12 blocks */
+static void reserve_nv12(u32 n, u32 width, u32 height, u32 align, u32 offs,
+ u32 gid, struct process_info *pi)
+{
+ u16 w, h, band, a = align, o = offs;
+ struct gid_info *gi;
+ int res = 0, res2, i;
+ u16 n_t, n_s, area_t, area_s;
+ u8 packing[2 * MAX_ANY];
+ struct list_head reserved = LIST_HEAD_INIT(reserved);
+
+ /* adjust alignment to the largest slot width (128 bytes) */
+ a = max_t(u16, PAGE_SIZE / min(band_8, band_16), a);
+
+ /* Check input parameters for correctness, and support */
+ if (!width || !height || !n ||
+ offs >= align || offs & 1 ||
+ align >= PAGE_SIZE ||
+ n > ops->width * ops->height / 2)
+ return;
+
+ /* calculate dimensions, band, offs and alignment in slots */
+ if (ops->analize(TILFMT_8BIT, width, height, &w, &h, &band, &a, &o,
+ NULL))
+ return;
+
+ /* get group context */
+ gi = ops->get_gi(pi, gid);
+ if (!gi)
+ return;
+
+ /* reserve in groups until failed or all is reserved */
+ for (i = 0; i < n && res >= 0; i += res) {
+ /* check packing separately vs together */
+ n_s = nv12_separate(o, a, w, n - i, &area_s);
+ if (ops->nv12_packed)
+ n_t = nv12_together(o, a, w, n - i, &area_t, packing);
+ else
+ n_t = 0;
+
+ /* pack based on better efficiency */
+ res = -1;
+ if (!ops->nv12_packed ||
+ nv12_eff(w, n_s, area_s, n - i) >
+ nv12_eff(w, n_t, area_t, n - i)) {
+
+ /*
+ * Reserve blocks separately into a temporary list, so
+ * that we can free them if unsuccessful. We need to be
+ * able to reserve both 8- and 16-bit blocks as the
+ * offsets of them must match.
+ */
+ res = ops->lay_2d(TILFMT_8BIT, n_s, w, h, band_8, a, o,
+ gi, &reserved);
+ res2 = ops->lay_2d(TILFMT_16BIT, n_s, (w + 1) >> 1, h,
+ band_16, a >> 1, o >> 1, gi, &reserved);
+
+ if (res2 < 0 || res < 0 || res != res2) {
+ /* clean up */
+ ops->release(&reserved);
+ res = -1;
+ } else {
+ /* add list to reserved */
+ ops->add_reserved(&reserved, gi);
+ }
+ }
+
+ /* if separate packing failed, still try to pack together */
+ if (res < 0 && ops->nv12_packed && n_t) {
+ /* pack together */
+ res = ops->lay_nv12(n_t, area_t, w, h, gi, packing);
+ }
+ }
+
+ ops->release_gi(gi);
+}
+
+/**
+ * We also optimize packing regular 2D areas as the auto-packing may result in
+ * sub-optimal efficiency. This is most pronounced if the area is wider than
+ * half a PAGE_SIZE (e.g. 2048 in 8-bit mode, or 1024 in 16-bit mode).
+ */
+
+/* reserve 2d blocks */
+static void reserve_blocks(u32 n, enum tiler_fmt fmt, u32 width, u32 height,
+ u32 align, u32 offs, u32 gid,
+ struct process_info *pi)
+{
+ u32 bpt, res = 0, i;
+ u16 o = offs, a = align, band, w, h, n_try;
+ struct gid_info *gi;
+ const struct tiler_geom *g;
+
+ /* Check input parameters for correctness, and support */
+ if (!width || !height || !n ||
+ align > PAGE_SIZE || offs >= align ||
+ fmt < TILFMT_8BIT || fmt > TILFMT_32BIT)
+ return;
+
+ /* tiler slot in bytes */
+ g = ops->geom(fmt);
+ bpt = g->slot_w * g->bpp;
+
+ /*
+ * For blocks narrower than half PAGE_SIZE the default allocation is
+ * sufficient. Also check for basic area info.
+ */
+ if (width * g->bpp * 2 <= PAGE_SIZE ||
+ ops->analize(fmt, width, height, &w, &h, &band, &a, &o, NULL))
+ return;
+
+ /* get group id */
+ gi = ops->get_gi(pi, gid);
+ if (!gi)
+ return;
+
+ /* reserve in groups until failed or all is reserved */
+ for (i = 0; i < n && res >= 0; i += res + 1) {
+ /* blocks to allocate in one area */
+ n_try = min(n - i, ops->width);
+ tiler_best2pack(offs, a, band, w, &n_try, NULL);
+
+ res = -1;
+ while (n_try > 1) {
+ /* adjust res so we fail on 0 return value */
+ res = ops->lay_2d(fmt, n_try, w, h, band, a, o,
+ gi, &gi->reserved) - 1;
+ if (res >= 0)
+ break;
+
+ /* reduce n if failed to allocate area */
+ n_try--;
+ }
+ }
+ /* keep reserved blocks even if failed to reserve all */
+
+ ops->release_gi(gi);
+}
+
+/* unreserve blocks for a group id */
+static void unreserve_blocks(u32 gid, struct process_info *pi)
+{
+ struct gid_info *gi;
+
+ gi = ops->get_gi(pi, gid);
+ if (!gi)
+ return;
+
+ ops->release(&gi->reserved);
+
+ ops->release_gi(gi);
+}
+
+/* initialize shared method pointers and global static variables */
+void tiler_reserve_init(struct tiler_ops *tiler)
+{
+ ops = tiler;
+
+ ops->reserve_nv12 = reserve_nv12;
+ ops->reserve = reserve_blocks;
+ ops->unreserve = unreserve_blocks;
+
+ band_8 = PAGE_SIZE / ops->geom(TILFMT_8BIT)->slot_w
+ / ops->geom(TILFMT_8BIT)->bpp;
+ band_16 = PAGE_SIZE / ops->geom(TILFMT_16BIT)->slot_w
+ / ops->geom(TILFMT_16BIT)->bpp;
+}
diff --git a/drivers/media/video/tiler/tmm-pat.c b/drivers/media/video/tiler/tmm-pat.c
new file mode 100644
index 00000000000..bc28ae4f6ec
--- /dev/null
+++ b/drivers/media/video/tiler/tmm-pat.c
@@ -0,0 +1,300 @@
+/*
+ * tmm-pat.c
+ *
+ * DMM driver support functions for TI TILER hardware block.
+ *
+ * Author: Lajos Molnar <molnar@ti.com>, David Sin <dsin@ti.com>
+ *
+ * Copyright (C) 2009-2010 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <asm/cacheflush.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#include "tmm.h"
+
+static int param_set_mem(const char *val, struct kernel_param *kp);
+
+/* Memory limit to cache free pages. TILER will eventually use this much */
+static u32 cache_limit = CONFIG_TILER_CACHE_LIMIT << 20;
+
+param_check_uint(cache, &cache_limit);
+module_param_call(cache, param_set_mem, param_get_uint, &cache_limit, 0644);
+__MODULE_PARM_TYPE(cache, "uint");
+MODULE_PARM_DESC(cache, "Cache free pages if total memory is under this limit");
+
+/* global state - statically initialized */
+static LIST_HEAD(free_list); /* page cache: list of free pages */
+static u32 total_mem; /* total memory allocated (free & used) */
+static u32 refs; /* number of tmm_pat instances */
+static DEFINE_MUTEX(mtx); /* global mutex */
+
+/* The page struct pointer and physical address of each page.*/
+struct mem {
+ struct list_head list;
+ struct page *pg; /* page struct */
+ u32 pa; /* physical address */
+};
+
+/* Used to keep track of mem per tmm_pat_get_pages call */
+struct fast {
+ struct list_head list;
+ struct mem **mem; /* array of page info */
+ u32 *pa; /* array of physical addresses */
+ u32 num; /* number of pages */
+};
+
+/* TMM PAT private structure */
+struct dmm_mem {
+ struct list_head fast_list;
+ struct dmm *dmm;
+};
+
+/* read mem values for a param */
+static int param_set_mem(const char *val, struct kernel_param *kp)
+{
+ u32 a;
+ char *p;
+
+ /* must specify memory */
+ if (!val)
+ return -EINVAL;
+
+ /* parse value */
+ a = memparse(val, &p);
+ if (p == val || *p)
+ return -EINVAL;
+
+ /* store parsed value */
+ *(uint *)kp->arg = a;
+ return 0;
+}
+
+/**
+ * Frees pages in a fast structure. Moves pages to the free list if there
+ * are less pages used than max_to_keep. Otherwise, it frees the pages
+ */
+static void free_fast(struct fast *f)
+{
+ s32 i = 0;
+
+ /* mutex is locked */
+ for (i = 0; i < f->num; i++) {
+ if (total_mem < cache_limit) {
+ /* cache free page if under the limit */
+ list_add(&f->mem[i]->list, &free_list);
+ } else {
+ /* otherwise, free */
+ total_mem -= PAGE_SIZE;
+ __free_page(f->mem[i]->pg);
+ }
+ }
+ kfree(f->pa);
+ kfree(f->mem);
+ /* remove only if element was added */
+ if (f->list.next)
+ list_del(&f->list);
+ kfree(f);
+}
+
+/* allocate and flush a page */
+static struct mem *alloc_mem(void)
+{
+ struct mem *m = kmalloc(sizeof(*m), GFP_KERNEL);
+ if (!m)
+ return NULL;
+ memset(m, 0, sizeof(*m));
+
+ m->pg = alloc_page(GFP_KERNEL | GFP_DMA);
+ if (!m->pg) {
+ kfree(m);
+ return NULL;
+ }
+
+ m->pa = page_to_phys(m->pg);
+
+ /* flush the cache entry for each page we allocate. */
+ dmac_flush_range(page_address(m->pg),
+ page_address(m->pg) + PAGE_SIZE);
+ outer_flush_range(m->pa, m->pa + PAGE_SIZE);
+
+ return m;
+}
+
+static void free_page_cache(void)
+{
+ struct mem *m, *m_;
+
+ /* mutex is locked */
+ list_for_each_entry_safe(m, m_, &free_list, list) {
+ __free_page(m->pg);
+ total_mem -= PAGE_SIZE;
+ list_del(&m->list);
+ kfree(m);
+ }
+}
+
+static void tmm_pat_deinit(struct tmm *tmm)
+{
+ struct fast *f, *f_;
+ struct dmm_mem *pvt = (struct dmm_mem *) tmm->pvt;
+
+ mutex_lock(&mtx);
+
+ /* free all outstanding used memory */
+ list_for_each_entry_safe(f, f_, &pvt->fast_list, list)
+ free_fast(f);
+
+ /* if this is the last tmm_pat, free all memory */
+ if (--refs == 0)
+ free_page_cache();
+
+ mutex_unlock(&mtx);
+}
+
+static u32 *tmm_pat_get_pages(struct tmm *tmm, u32 n)
+{
+ struct mem *m;
+ struct fast *f;
+ struct dmm_mem *pvt = (struct dmm_mem *) tmm->pvt;
+
+ f = kmalloc(sizeof(*f), GFP_KERNEL);
+ if (!f)
+ return NULL;
+ memset(f, 0, sizeof(*f));
+
+ /* array of mem struct pointers */
+ f->mem = kmalloc(n * sizeof(*f->mem), GFP_KERNEL);
+
+ /* array of physical addresses */
+ f->pa = kmalloc(n * sizeof(*f->pa), GFP_KERNEL);
+
+ /* no pages have been allocated yet (needed for cleanup) */
+ f->num = 0;
+
+ if (!f->mem || !f->pa)
+ goto cleanup;
+
+ memset(f->mem, 0, n * sizeof(*f->mem));
+ memset(f->pa, 0, n * sizeof(*f->pa));
+
+ /* fill out fast struct mem array with free pages */
+ mutex_lock(&mtx);
+ while (f->num < n) {
+ /* if there is a free cached page use it */
+ if (!list_empty(&free_list)) {
+ /* unbind first element from list */
+ m = list_first_entry(&free_list, typeof(*m), list);
+ list_del(&m->list);
+ } else {
+ mutex_unlock(&mtx);
+
+ /**
+ * Unlock mutex during allocation and cache flushing.
+ */
+ m = alloc_mem();
+ if (!m)
+ goto cleanup;
+
+ mutex_lock(&mtx);
+ total_mem += PAGE_SIZE;
+ }
+
+ f->mem[f->num] = m;
+ f->pa[f->num++] = m->pa;
+ }
+
+ list_add(&f->list, &pvt->fast_list);
+ mutex_unlock(&mtx);
+ return f->pa;
+
+cleanup:
+ free_fast(f);
+ return NULL;
+}
+
+static void tmm_pat_free_pages(struct tmm *tmm, u32 *page_list)
+{
+ struct dmm_mem *pvt = (struct dmm_mem *) tmm->pvt;
+ struct fast *f, *f_;
+
+ mutex_lock(&mtx);
+ /* find fast struct based on 1st page */
+ list_for_each_entry_safe(f, f_, &pvt->fast_list, list) {
+ if (f->pa[0] == page_list[0]) {
+ free_fast(f);
+ break;
+ }
+ }
+ mutex_unlock(&mtx);
+}
+
+static s32 tmm_pat_map(struct tmm *tmm, struct pat_area area, u32 page_pa)
+{
+ struct dmm_mem *pvt = (struct dmm_mem *) tmm->pvt;
+ struct pat pat_desc = {0};
+
+ /* send pat descriptor to dmm driver */
+ pat_desc.ctrl.dir = 0;
+ pat_desc.ctrl.ini = 0;
+ pat_desc.ctrl.lut_id = 0;
+ pat_desc.ctrl.start = 1;
+ pat_desc.ctrl.sync = 0;
+ pat_desc.area = area;
+ pat_desc.next = NULL;
+
+ /* must be a 16-byte aligned physical address */
+ pat_desc.data = page_pa;
+ return dmm_pat_refill(pvt->dmm, &pat_desc, MANUAL);
+}
+
+struct tmm *tmm_pat_init(u32 pat_id)
+{
+ struct tmm *tmm = NULL;
+ struct dmm_mem *pvt = NULL;
+
+ struct dmm *dmm = dmm_pat_init(pat_id);
+ if (dmm)
+ tmm = kmalloc(sizeof(*tmm), GFP_KERNEL);
+ if (tmm)
+ pvt = kmalloc(sizeof(*pvt), GFP_KERNEL);
+ if (pvt) {
+ /* private data */
+ pvt->dmm = dmm;
+ INIT_LIST_HEAD(&pvt->fast_list);
+
+ /* increate tmm_pat references */
+ mutex_lock(&mtx);
+ refs++;
+ mutex_unlock(&mtx);
+
+ /* public data */
+ tmm->pvt = pvt;
+ tmm->deinit = tmm_pat_deinit;
+ tmm->get = tmm_pat_get_pages;
+ tmm->free = tmm_pat_free_pages;
+ tmm->map = tmm_pat_map;
+ tmm->clear = NULL; /* not yet supported */
+
+ return tmm;
+ }
+
+ kfree(pvt);
+ kfree(tmm);
+ dmm_pat_release(dmm);
+ return NULL;
+}
+EXPORT_SYMBOL(tmm_pat_init);
diff --git a/drivers/media/video/tiler/tmm.h b/drivers/media/video/tiler/tmm.h
new file mode 100644
index 00000000000..fbdc1e23d0e
--- /dev/null
+++ b/drivers/media/video/tiler/tmm.h
@@ -0,0 +1,109 @@
+/*
+ * tmm.h
+ *
+ * TMM interface definition for TI TILER driver.
+ *
+ * Author: Lajos Molnar <molnar@ti.com>
+ *
+ * Copyright (C) 2009-2010 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 TMM_H
+#define TMM_H
+
+#include <mach/dmm.h>
+/**
+ * TMM interface
+ */
+struct tmm {
+ void *pvt;
+
+ /* function table */
+ u32 *(*get) (struct tmm *tmm, u32 num_pages);
+ void (*free) (struct tmm *tmm, u32 *pages);
+ s32 (*map) (struct tmm *tmm, struct pat_area area, u32 page_pa);
+ void (*clear) (struct tmm *tmm, struct pat_area area);
+ void (*deinit) (struct tmm *tmm);
+};
+
+/**
+ * Request a set of pages from the DMM free page stack.
+ * @return a pointer to a list of physical page addresses.
+ */
+static inline
+u32 *tmm_get(struct tmm *tmm, u32 num_pages)
+{
+ if (tmm && tmm->pvt)
+ return tmm->get(tmm, num_pages);
+ return NULL;
+}
+
+/**
+ * Return a set of used pages to the DMM free page stack.
+ * @param list a pointer to a list of physical page addresses.
+ */
+static inline
+void tmm_free(struct tmm *tmm, u32 *pages)
+{
+ if (tmm && tmm->pvt)
+ tmm->free(tmm, pages);
+}
+
+/**
+ * Program the physical address translator.
+ * @param area PAT area
+ * @param list of pages
+ */
+static inline
+s32 tmm_map(struct tmm *tmm, struct pat_area area, u32 page_pa)
+{
+ if (tmm && tmm->map && tmm->pvt)
+ return tmm->map(tmm, area, page_pa);
+ return -ENODEV;
+}
+
+/**
+ * Clears the physical address translator.
+ * @param area PAT area
+ */
+static inline
+void tmm_clear(struct tmm *tmm, struct pat_area area)
+{
+ if (tmm && tmm->clear && tmm->pvt)
+ tmm->clear(tmm, area);
+}
+
+/**
+ * Checks whether tiler memory manager supports mapping
+ */
+static inline
+bool tmm_can_map(struct tmm *tmm)
+{
+ return tmm && tmm->map;
+}
+
+/**
+ * Deinitialize tiler memory manager
+ */
+static inline
+void tmm_deinit(struct tmm *tmm)
+{
+ if (tmm && tmm->pvt)
+ tmm->deinit(tmm);
+}
+
+/**
+ * TMM implementation for PAT support.
+ *
+ * Initialize TMM for PAT with given id.
+ */
+struct tmm *tmm_pat_init(u32 pat_id);
+
+#endif
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 8d7d098f7a0..204058e720a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -227,6 +227,12 @@ config TWL6030_PWM
Say yes here if you want support for TWL6030 PWM.
This is used to control charging LED brightness.
+config TWL6040_CODEC
+ bool
+ depends on TWL4030_CORE
+ select MFD_CORE
+ default n
+
config MFD_STMPE
bool "Support STMicroelectronics STMPE"
depends on I2C=y && GENERIC_HARDIRQS
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 47f5709f382..d646a41dc50 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o
obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o
+obj-$(CONFIG_TWL6040_CODEC) += twl6040-codec.o twl6040-irq.o
obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 960b5bed7f5..b4a8d914035 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -217,6 +217,7 @@
#define HIGH_PERF_SQ (1 << 3)
#define CK32K_LOWPWR_EN (1 << 7)
+#define CLK32KG_CFG_STATE 0xBE
/* chip-specific feature flags, for i2c_device_id.driver_data */
#define TWL4030_VAUX2 BIT(0) /* pre-5030 voltage ranges */
@@ -746,7 +747,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
/* Phoenix codec driver is probed directly atm */
if (twl_has_codec() && pdata->codec && twl_class_is_6030()) {
sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
- child = add_child(sub_chip_id, "twl6040-codec",
+ child = add_child(sub_chip_id, "twl6040-audio",
pdata->codec, sizeof(*pdata->codec),
false, 0, 0);
if (IS_ERR(child))
@@ -1093,6 +1094,9 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
}
+ if (twl_class_is_6030())
+ twl_i2c_write_u8(TWL6030_MODULE_ID0, 0xE1, CLK32KG_CFG_STATE);
+
status = add_children(pdata, id->driver_data);
fail:
if (status < 0)
diff --git a/drivers/mfd/twl6040-codec.c b/drivers/mfd/twl6040-codec.c
new file mode 100644
index 00000000000..0a262242f2e
--- /dev/null
+++ b/drivers/mfd/twl6040-codec.c
@@ -0,0 +1,707 @@
+/*
+ * MFD driver for twl6040 codec submodule
+ *
+ * Authors: Jorge Eduardo Candelaria <jorge.candelaria@ti.com>
+ * Misael Lopez Cruz <misael.lopez@ti.com>
+ *
+ * Copyright: (C) 20010 Texas Instruments, Inc.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/i2c/twl.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/twl6040-codec.h>
+
+static struct platform_device *twl6040_dev;
+
+int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg)
+{
+ int ret;
+ u8 val;
+
+ mutex_lock(&twl6040->io_mutex);
+ ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &val, reg);
+ if (ret < 0) {
+ mutex_unlock(&twl6040->io_mutex);
+ return ret;
+ }
+ mutex_unlock(&twl6040->io_mutex);
+
+ return val;
+}
+EXPORT_SYMBOL(twl6040_reg_read);
+
+int twl6040_reg_write(struct twl6040 *twl6040, unsigned int reg, u8 val)
+{
+ int ret;
+
+ mutex_lock(&twl6040->io_mutex);
+ ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, val, reg);
+ mutex_unlock(&twl6040->io_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(twl6040_reg_write);
+
+int twl6040_set_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask)
+{
+ int ret;
+ u8 val;
+
+ mutex_lock(&twl6040->io_mutex);
+ ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &val, reg);
+ if (ret)
+ goto out;
+
+ val |= mask;
+ ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, val, reg);
+out:
+ mutex_unlock(&twl6040->io_mutex);
+ return ret;
+}
+EXPORT_SYMBOL(twl6040_set_bits);
+
+int twl6040_clear_bits(struct twl6040 *twl6040, unsigned int reg, u8 mask)
+{
+ int ret;
+ u8 val;
+
+ mutex_lock(&twl6040->io_mutex);
+ ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &val, reg);
+ if (ret)
+ goto out;
+
+ val &= ~mask;
+ ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, val, reg);
+out:
+ mutex_unlock(&twl6040->io_mutex);
+ return ret;
+}
+EXPORT_SYMBOL(twl6040_clear_bits);
+
+/* twl6040 codec manual power-up sequence */
+static int twl6040_power_up(struct twl6040 *twl6040)
+{
+ u8 ncpctl, ldoctl, lppllctl, accctl;
+ int ret;
+
+ ncpctl = twl6040_reg_read(twl6040, TWL6040_REG_NCPCTL);
+ ldoctl = twl6040_reg_read(twl6040, TWL6040_REG_LDOCTL);
+ lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL);
+ accctl = twl6040_reg_read(twl6040, TWL6040_REG_ACCCTL);
+
+ /* enable reference system */
+ ldoctl |= TWL6040_REFENA;
+ ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ if (ret)
+ return ret;
+ msleep(10);
+
+ /* enable internal oscillator */
+ ldoctl |= TWL6040_OSCENA;
+ ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ if (ret)
+ goto osc_err;
+ udelay(10);
+
+ /* enable high-side ldo */
+ ldoctl |= TWL6040_HSLDOENA;
+ ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ if (ret)
+ goto hsldo_err;
+ udelay(244);
+
+ /* enable negative charge pump */
+ ncpctl |= TWL6040_NCPENA | TWL6040_NCPOPEN;
+ ret = twl6040_reg_write(twl6040, TWL6040_REG_NCPCTL, ncpctl);
+ if (ret)
+ goto ncp_err;
+ udelay(488);
+
+ /* enable low-side ldo */
+ ldoctl |= TWL6040_LSLDOENA;
+ ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ if (ret)
+ goto lsldo_err;
+ udelay(244);
+
+ /* enable low-power pll */
+ lppllctl |= TWL6040_LPLLENA;
+ ret = twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+ if (ret)
+ goto lppll_err;
+
+ /* reset state machine */
+ accctl |= TWL6040_RESETSPLIT;
+ ret = twl6040_reg_write(twl6040, TWL6040_REG_ACCCTL, accctl);
+ if (ret)
+ goto rst_err;
+ mdelay(5);
+ accctl &= ~TWL6040_RESETSPLIT;
+ ret = twl6040_reg_write(twl6040, TWL6040_REG_ACCCTL, accctl);
+ if (ret)
+ goto rst_err;
+
+ /* disable internal oscillator */
+ ldoctl &= ~TWL6040_OSCENA;
+ ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ if (ret)
+ goto rst_err;
+
+ return 0;
+
+rst_err:
+ lppllctl &= ~TWL6040_LPLLENA;
+ twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+lppll_err:
+ ldoctl &= ~TWL6040_LSLDOENA;
+ twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ udelay(244);
+lsldo_err:
+ ncpctl &= ~(TWL6040_NCPENA | TWL6040_NCPOPEN);
+ twl6040_reg_write(twl6040, TWL6040_REG_NCPCTL, ncpctl);
+ udelay(488);
+ncp_err:
+ ldoctl &= ~TWL6040_HSLDOENA;
+ twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ udelay(244);
+hsldo_err:
+ ldoctl &= ~TWL6040_OSCENA;
+ twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+osc_err:
+ ldoctl &= ~TWL6040_REFENA;
+ twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ msleep(10);
+
+ return ret;
+}
+
+/* twl6040 codec manual power-down sequence */
+static int twl6040_power_down(struct twl6040 *twl6040)
+{
+ u8 ncpctl, ldoctl, lppllctl, accctl;
+ int ret;
+
+ ncpctl = twl6040_reg_read(twl6040, TWL6040_REG_NCPCTL);
+ ldoctl = twl6040_reg_read(twl6040, TWL6040_REG_LDOCTL);
+ lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL);
+ accctl = twl6040_reg_read(twl6040, TWL6040_REG_ACCCTL);
+
+ /* enable internal oscillator */
+ ldoctl |= TWL6040_OSCENA;
+ ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ if (ret)
+ return ret;
+ udelay(10);
+
+ /* disable low-power pll */
+ lppllctl &= ~TWL6040_LPLLENA;
+ ret = twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+ if (ret)
+ goto lppll_err;
+
+ /* disable low-side ldo */
+ ldoctl &= ~TWL6040_LSLDOENA;
+ ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ if (ret)
+ goto lsldo_err;
+ udelay(244);
+
+ /* disable negative charge pump */
+ ncpctl &= ~(TWL6040_NCPENA | TWL6040_NCPOPEN);
+ ret = twl6040_reg_write(twl6040, TWL6040_REG_NCPCTL, ncpctl);
+ if (ret)
+ goto ncp_err;
+ udelay(488);
+
+ /* disable high-side ldo */
+ ldoctl &= ~TWL6040_HSLDOENA;
+ ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ if (ret)
+ goto hsldo_err;
+ udelay(244);
+
+ /* disable internal oscillator */
+ ldoctl &= ~TWL6040_OSCENA;
+ ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ if (ret)
+ goto osc_err;
+
+ /* disable reference system */
+ ldoctl &= ~TWL6040_REFENA;
+ ret = twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ if (ret)
+ goto ref_err;
+ msleep(10);
+
+ return 0;
+
+ref_err:
+ ldoctl |= TWL6040_OSCENA;
+ twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ udelay(10);
+osc_err:
+ ldoctl |= TWL6040_HSLDOENA;
+ twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ udelay(244);
+hsldo_err:
+ ncpctl |= TWL6040_NCPENA | TWL6040_NCPOPEN;
+ twl6040_reg_write(twl6040, TWL6040_REG_NCPCTL, ncpctl);
+ udelay(488);
+ncp_err:
+ ldoctl |= TWL6040_LSLDOENA;
+ twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ udelay(244);
+lsldo_err:
+ lppllctl |= TWL6040_LPLLENA;
+ twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+lppll_err:
+ lppllctl |= TWL6040_LPLLENA;
+ twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+ accctl |= TWL6040_RESETSPLIT;
+ twl6040_reg_write(twl6040, TWL6040_REG_ACCCTL, accctl);
+ mdelay(5);
+ accctl &= ~TWL6040_RESETSPLIT;
+ twl6040_reg_write(twl6040, TWL6040_REG_ACCCTL, accctl);
+ ldoctl &= ~TWL6040_OSCENA;
+ twl6040_reg_write(twl6040, TWL6040_REG_LDOCTL, ldoctl);
+ msleep(10);
+
+ return ret;
+}
+
+static irqreturn_t twl6040_naudint_handler(int irq, void *data)
+{
+ struct twl6040 *twl6040 = data;
+ u8 intid;
+
+ intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
+
+ if (intid & TWL6040_READYINT)
+ complete(&twl6040->ready);
+
+ return IRQ_HANDLED;
+}
+
+static int twl6040_power_up_completion(struct twl6040 *twl6040,
+ int naudint)
+{
+ int time_left;
+ u8 intid;
+
+ time_left = wait_for_completion_timeout(&twl6040->ready,
+ msecs_to_jiffies(144));
+ if (!time_left) {
+ intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
+ if (!(intid & TWL6040_READYINT)) {
+ dev_err(&twl6040_dev->dev,
+ "timeout waiting for READYINT\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static int twl6040_power(struct twl6040 *twl6040, int enable)
+{
+ int audpwron = twl6040->audpwron;
+ int naudint = twl6040->irq;
+ int ret = 0;
+
+ if (enable) {
+ if (gpio_is_valid(audpwron)) {
+ /* use AUDPWRON line */
+ gpio_set_value(audpwron, 1);
+ /* wait for power-up completion */
+ ret = twl6040_power_up_completion(twl6040, naudint);
+ if (ret) {
+ dev_err(&twl6040_dev->dev,
+ "automatic power-down failed\n");
+ return ret;
+ }
+ } else {
+ /* use manual power-up sequence */
+ ret = twl6040_power_up(twl6040);
+ if (ret) {
+ dev_err(&twl6040_dev->dev,
+ "manual power-up failed\n");
+ return ret;
+ }
+ }
+ twl6040->pll = TWL6040_LPPLL_ID;
+ twl6040->sysclk = 19200000;
+ } else {
+ if (gpio_is_valid(audpwron)) {
+ /* use AUDPWRON line */
+ gpio_set_value(audpwron, 0);
+
+ /* power-down sequence latency */
+ udelay(500);
+ } else {
+ /* use manual power-down sequence */
+ ret = twl6040_power_down(twl6040);
+ if (ret) {
+ dev_err(&twl6040_dev->dev,
+ "manual power-down failed\n");
+ return ret;
+ }
+ }
+ twl6040->pll = TWL6040_NOPLL_ID;
+ twl6040->sysclk = 0;
+ }
+
+ twl6040->powered = enable;
+
+ return ret;
+}
+
+int twl6040_enable(struct twl6040 *twl6040)
+{
+ int ret = 0;
+
+ mutex_lock(&twl6040->mutex);
+ if (!twl6040->power_count++)
+ ret = twl6040_power(twl6040, 1);
+ mutex_unlock(&twl6040->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(twl6040_enable);
+
+int twl6040_disable(struct twl6040 *twl6040)
+{
+ int ret = 0;
+
+ mutex_lock(&twl6040->mutex);
+ if (!--twl6040->power_count)
+ ret = twl6040_power(twl6040, 0);
+ mutex_unlock(&twl6040->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(twl6040_disable);
+
+int twl6040_is_enabled(struct twl6040 *twl6040)
+{
+ return twl6040->power_count;
+}
+EXPORT_SYMBOL(twl6040_is_enabled);
+
+int twl6040_set_pll(struct twl6040 *twl6040, enum twl6040_pll_id id,
+ unsigned int freq_in, unsigned int freq_out)
+{
+ u8 hppllctl, lppllctl;
+ int ret = 0;
+
+ mutex_lock(&twl6040->mutex);
+
+ hppllctl = twl6040_reg_read(twl6040, TWL6040_REG_HPPLLCTL);
+ lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL);
+
+ switch (id) {
+ case TWL6040_LPPLL_ID:
+ /* lppll divider */
+ switch (freq_out) {
+ case 17640000:
+ lppllctl |= TWL6040_LPLLFIN;
+ break;
+ case 19200000:
+ lppllctl &= ~TWL6040_LPLLFIN;
+ break;
+ default:
+ dev_err(&twl6040_dev->dev,
+ "freq_out %d not supported\n", freq_out);
+ ret = -EINVAL;
+ goto pll_out;
+ }
+ twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+
+ switch (freq_in) {
+ case 32768:
+ lppllctl |= TWL6040_LPLLENA;
+ twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
+ lppllctl);
+ mdelay(5);
+ lppllctl &= ~TWL6040_HPLLSEL;
+ twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
+ lppllctl);
+ hppllctl &= ~TWL6040_HPLLENA;
+ twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL,
+ hppllctl);
+ break;
+ default:
+ dev_err(&twl6040_dev->dev,
+ "freq_in %d not supported\n", freq_in);
+ ret = -EINVAL;
+ goto pll_out;
+ }
+
+ twl6040->pll = TWL6040_LPPLL_ID;
+ break;
+ case TWL6040_HPPLL_ID:
+ /* high-performance pll can provide only 19.2 MHz */
+ if (freq_out != 19200000) {
+ dev_err(&twl6040_dev->dev,
+ "freq_out %d not supported\n", freq_out);
+ ret = -EINVAL;
+ goto pll_out;
+ }
+
+ hppllctl &= ~TWL6040_MCLK_MSK;
+
+ switch (freq_in) {
+ case 12000000:
+ /* mclk input, pll enabled */
+ hppllctl |= TWL6040_MCLK_12000KHZ |
+ TWL6040_HPLLSQRBP |
+ TWL6040_HPLLENA;
+ break;
+ case 19200000:
+ /* mclk input, pll disabled */
+ hppllctl |= TWL6040_MCLK_19200KHZ |
+ TWL6040_HPLLSQRENA |
+ TWL6040_HPLLBP;
+ break;
+ case 26000000:
+ /* mclk input, pll enabled */
+ hppllctl |= TWL6040_MCLK_26000KHZ |
+ TWL6040_HPLLSQRBP |
+ TWL6040_HPLLENA;
+ break;
+ case 38400000:
+ /* clk slicer, pll disabled */
+ hppllctl |= TWL6040_MCLK_38400KHZ |
+ TWL6040_HPLLSQRENA |
+ TWL6040_HPLLBP;
+ break;
+ default:
+ dev_err(&twl6040_dev->dev,
+ "freq_in %d not supported\n", freq_in);
+ ret = -EINVAL;
+ goto pll_out;
+ }
+
+ twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL, hppllctl);
+ udelay(500);
+ lppllctl |= TWL6040_HPLLSEL;
+ twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+ lppllctl &= ~TWL6040_LPLLENA;
+ twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+
+ twl6040->pll = TWL6040_HPPLL_ID;
+ break;
+ default:
+ dev_err(&twl6040_dev->dev, "unknown pll id %d\n", id);
+ ret = -EINVAL;
+ goto pll_out;
+ }
+
+ twl6040->sysclk = freq_out;
+
+pll_out:
+ mutex_unlock(&twl6040->mutex);
+ return ret;
+}
+EXPORT_SYMBOL(twl6040_set_pll);
+
+enum twl6040_pll_id twl6040_get_pll(struct twl6040 *twl6040)
+{
+ return twl6040->pll;
+}
+EXPORT_SYMBOL(twl6040_get_pll);
+
+unsigned int twl6040_get_sysclk(struct twl6040 *twl6040)
+{
+ return twl6040->sysclk;
+}
+EXPORT_SYMBOL(twl6040_get_sysclk);
+
+static int __devinit twl6040_probe(struct platform_device *pdev)
+{
+ struct twl4030_codec_data *pdata = pdev->dev.platform_data;
+ struct twl6040 *twl6040;
+ struct mfd_cell *cell = NULL;
+ unsigned int naudint;
+ int audpwron;
+ int ret, children = 0;
+ u8 icrev = 0, accctl;
+
+ if(!pdata) {
+ dev_err(&pdev->dev, "Platform data is missing\n");
+ return -EINVAL;
+ }
+
+ twl6040 = kzalloc(sizeof(struct twl6040), GFP_KERNEL);
+ if (!twl6040)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, twl6040);
+
+ twl6040_dev = pdev;
+ twl6040->dev = &pdev->dev;
+ mutex_init(&twl6040->mutex);
+ mutex_init(&twl6040->io_mutex);
+
+ icrev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV);
+
+ if (pdata && (icrev > 0))
+ audpwron = pdata->audpwron_gpio;
+ else
+ audpwron = -EINVAL;
+
+ if (pdata)
+ naudint = pdata->naudint_irq;
+ else
+ naudint = 0;
+
+ twl6040->audpwron = audpwron;
+ twl6040->powered = 0;
+ twl6040->irq = naudint;
+ twl6040->irq_base = pdata->irq_base;
+ init_completion(&twl6040->ready);
+
+ if (gpio_is_valid(audpwron)) {
+ ret = gpio_request(audpwron, "audpwron");
+ if (ret)
+ goto gpio1_err;
+
+ ret = gpio_direction_output(audpwron, 0);
+ if (ret)
+ goto gpio2_err;
+ }
+
+ if (naudint) {
+ /* codec interrupt */
+ ret = twl6040_irq_init(twl6040);
+ if (ret)
+ goto gpio2_err;
+
+ ret = twl6040_request_irq(twl6040, TWL6040_IRQ_READY,
+ twl6040_naudint_handler, "twl6040_irq_ready",
+ twl6040);
+ if (ret) {
+ dev_err(twl6040->dev, "READY IRQ request failed: %d\n",
+ ret);
+ goto irq_err;
+ }
+ }
+
+ /* dual-access registers controlled by I2C only */
+ accctl = twl6040_reg_read(twl6040, TWL6040_REG_ACCCTL);
+ twl6040_reg_write(twl6040, TWL6040_REG_ACCCTL, accctl | TWL6040_I2CSEL);
+
+ if (pdata->audio) {
+ cell = &twl6040->cells[children];
+ cell->name = "twl6040-codec";
+ cell->mfd_data = pdata->audio;
+ children++;
+ }
+
+ if (pdata->vibra) {
+ cell = &twl6040->cells[children];
+ cell->name = "twl6040-vibra";
+ cell->mfd_data = pdata->vibra;
+ children++;
+ }
+
+ if (children) {
+ ret = mfd_add_devices(&pdev->dev, pdev->id, twl6040->cells,
+ children, NULL, 0);
+ if (ret)
+ goto mfd_err;
+ } else {
+ dev_err(&pdev->dev, "No platform data found for children\n");
+ ret = -ENODEV;
+ goto mfd_err;
+ }
+
+ return 0;
+
+mfd_err:
+ if (naudint)
+ twl6040_free_irq(twl6040, TWL6040_IRQ_READY, twl6040);
+irq_err:
+ if (naudint)
+ twl6040_irq_exit(twl6040);
+gpio2_err:
+ if (gpio_is_valid(audpwron))
+ gpio_free(audpwron);
+gpio1_err:
+ platform_set_drvdata(pdev, NULL);
+ kfree(twl6040);
+ twl6040_dev = NULL;
+ return ret;
+}
+
+static int __devexit twl6040_remove(struct platform_device *pdev)
+{
+ struct twl6040 *twl6040 = platform_get_drvdata(pdev);
+ int audpwron = twl6040->audpwron;
+ int naudint = twl6040->irq;
+
+ twl6040_disable(twl6040);
+
+ twl6040_free_irq(twl6040, TWL6040_IRQ_READY, twl6040);
+
+ if (gpio_is_valid(audpwron))
+ gpio_free(audpwron);
+
+ if (naudint)
+ twl6040_irq_exit(twl6040);
+
+ mfd_remove_devices(&pdev->dev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(twl6040);
+ twl6040_dev = NULL;
+
+ return 0;
+}
+
+static struct platform_driver twl6040_driver = {
+ .probe = twl6040_probe,
+ .remove = __devexit_p(twl6040_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "twl6040-audio",
+ },
+};
+
+static int __devinit twl6040_init(void)
+{
+ return platform_driver_register(&twl6040_driver);
+}
+module_init(twl6040_init);
+
+static void __devexit twl6040_exit(void)
+{
+ platform_driver_unregister(&twl6040_driver);
+}
+
+module_exit(twl6040_exit);
+
+MODULE_DESCRIPTION("TWL6040 MFD");
+MODULE_AUTHOR("Jorge Eduardo Candelaria <jorge.candelaria@ti.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:twl6040-audio");
diff --git a/drivers/mfd/twl6040-irq.c b/drivers/mfd/twl6040-irq.c
new file mode 100644
index 00000000000..c607ed65511
--- /dev/null
+++ b/drivers/mfd/twl6040-irq.c
@@ -0,0 +1,196 @@
+/*
+ * twl6040-irq.c -- Interrupt controller support for TWL6040
+ *
+ * Copyright 2010 Texas Instruments Inc.
+ *
+ * Author: Misael Lopez Cruz <misael.lopez@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/twl6040-codec.h>
+
+struct twl6040_irq_data {
+ int mask;
+ int status;
+};
+
+static struct twl6040_irq_data twl6040_irqs[] = {
+ {
+ .mask = TWL6040_THMSK,
+ .status = TWL6040_THINT,
+ },
+ {
+ .mask = TWL6040_PLUGMSK,
+ .status = TWL6040_PLUGINT | TWL6040_UNPLUGINT,
+ },
+ {
+ .mask = TWL6040_HOOKMSK,
+ .status = TWL6040_HOOKINT,
+ },
+ {
+ .mask = TWL6040_HFMSK,
+ .status = TWL6040_HFINT,
+ },
+ {
+ .mask = TWL6040_VIBMSK,
+ .status = TWL6040_VIBINT,
+ },
+ {
+ .mask = TWL6040_READYMSK,
+ .status = TWL6040_READYINT,
+ },
+};
+
+static inline struct twl6040_irq_data *irq_to_twl6040_irq(struct twl6040 *twl6040,
+ int irq)
+{
+ return &twl6040_irqs[irq - twl6040->irq_base];
+}
+
+static void twl6040_irq_lock(unsigned int irq)
+{
+ struct twl6040 *twl6040 = get_irq_chip_data(irq);
+
+ mutex_lock(&twl6040->irq_mutex);
+}
+
+static void twl6040_irq_sync_unlock(unsigned int irq)
+{
+ struct twl6040 *twl6040 = get_irq_chip_data(irq);
+
+ /* write back to hardware any change in irq mask */
+ if (twl6040->irq_masks_cur != twl6040->irq_masks_cache) {
+ twl6040->irq_masks_cache = twl6040->irq_masks_cur;
+ twl6040_reg_write(twl6040, TWL6040_REG_INTMR,
+ twl6040->irq_masks_cur);
+ }
+
+ mutex_unlock(&twl6040->irq_mutex);
+}
+
+static void twl6040_irq_unmask(unsigned int irq)
+{
+ struct twl6040 *twl6040 = get_irq_chip_data(irq);
+ struct twl6040_irq_data *irq_data = irq_to_twl6040_irq(twl6040, irq);
+
+ twl6040->irq_masks_cur &= ~irq_data->mask;
+}
+
+static void twl6040_irq_mask(unsigned int irq)
+{
+ struct twl6040 *twl6040 = get_irq_chip_data(irq);
+ struct twl6040_irq_data *irq_data = irq_to_twl6040_irq(twl6040, irq);
+
+ twl6040->irq_masks_cur |= irq_data->mask;
+}
+
+static struct irq_chip twl6040_irq_chip = {
+ .name = "twl6040",
+ .bus_lock = twl6040_irq_lock,
+ .bus_sync_unlock = twl6040_irq_sync_unlock,
+ .mask = twl6040_irq_mask,
+ .unmask = twl6040_irq_unmask,
+};
+
+static irqreturn_t twl6040_irq_thread(int irq, void *data)
+{
+ struct twl6040 *twl6040 = data;
+ u8 intid;
+ int i;
+
+ intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
+
+ /* apply masking and report (backwards to handle READYINT first) */
+ for (i = ARRAY_SIZE(twl6040_irqs) - 1; i >= 0; i--) {
+ if (twl6040->irq_masks_cur & twl6040_irqs[i].mask)
+ intid &= ~twl6040_irqs[i].status;
+ if (intid & twl6040_irqs[i].status)
+ handle_nested_irq(twl6040->irq_base + i);
+ }
+
+ /* ack unmasked irqs */
+ twl6040_reg_write(twl6040, TWL6040_REG_INTID, intid);
+
+ return IRQ_HANDLED;
+}
+
+int twl6040_irq_init(struct twl6040 *twl6040)
+{
+ int cur_irq, ret;
+ u8 val;
+
+ mutex_init(&twl6040->irq_mutex);
+
+ /* mask the individual interrupt sources */
+ twl6040->irq_masks_cur = TWL6040_ALLINT_MSK;
+ twl6040->irq_masks_cache = TWL6040_ALLINT_MSK;
+ twl6040_reg_write(twl6040, TWL6040_REG_INTMR, TWL6040_ALLINT_MSK);
+
+ if (!twl6040->irq) {
+ dev_warn(twl6040->dev,
+ "no interrupt specified, no interrupts\n");
+ twl6040->irq_base = 0;
+ return 0;
+ }
+
+ if (!twl6040->irq_base) {
+ dev_err(twl6040->dev,
+ "no interrupt base specified, no interrupts\n");
+ return 0;
+ }
+
+ /* Register them with genirq */
+ for (cur_irq = twl6040->irq_base;
+ cur_irq < twl6040->irq_base + ARRAY_SIZE(twl6040_irqs);
+ cur_irq++) {
+ set_irq_chip_data(cur_irq, twl6040);
+ set_irq_chip_and_handler(cur_irq, &twl6040_irq_chip,
+ handle_level_irq);
+ set_irq_nested_thread(cur_irq, 1);
+
+ /* ARM needs us to explicitly flag the IRQ as valid
+ * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+ set_irq_flags(cur_irq, IRQF_VALID);
+#else
+ set_irq_noprobe(cur_irq);
+#endif
+ }
+
+ ret = request_threaded_irq(twl6040->irq, NULL, twl6040_irq_thread,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "twl6040", twl6040);
+ if (ret) {
+ dev_err(twl6040->dev, "failed to request IRQ %d: %d\n",
+ twl6040->irq, ret);
+ return ret;
+ }
+
+ /* reset interrupts */
+ val = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
+
+ /* interrupts cleared on write */
+ val = twl6040_reg_read(twl6040, TWL6040_REG_ACCCTL)
+ & ~TWL6040_INTCLRMODE;
+ twl6040_reg_write(twl6040, TWL6040_REG_ACCCTL, val);
+
+ return 0;
+}
+EXPORT_SYMBOL(twl6040_irq_init);
+
+void twl6040_irq_exit(struct twl6040 *twl6040)
+{
+ if (twl6040->irq)
+ free_irq(twl6040->irq, twl6040);
+}
+EXPORT_SYMBOL(twl6040_irq_exit);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index cc8e49db45f..c6806ebc381 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -371,6 +371,12 @@ config HMC6352
This driver provides support for the Honeywell HMC6352 compass,
providing configuration and heading data via sysfs.
+config TWL6040_VIB
+ bool "TWL6040 Vibrator"
+ depends on TWL4030_CORE && ANDROID_TIMED_OUTPUT
+ select TWL6040_CODEC
+ default n
+
config EP93XX_PWM
tristate "EP93xx PWM support"
depends on ARCH_EP93XX
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 98009cc20cb..d5fea762410 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -42,3 +42,4 @@ obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o
obj-$(CONFIG_PCH_PHUB) += pch_phub.o
obj-y += ti-st/
obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o
+obj-$(CONFIG_TWL6040_VIB) += twl6040-vib.o
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index f9aad06d1ae..1847c477c0c 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -25,10 +25,9 @@
#include <linux/init.h>
#include <linux/tty.h>
-/* understand BT, FM and GPS for now */
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/hci.h>
+#include <linux/seq_file.h>
+#include <linux/skbuff.h>
+
#include <linux/ti_wilink_st.h>
/* function pointer pointing to either,
@@ -38,21 +37,38 @@
void (*st_recv) (void*, const unsigned char*, long);
/********************************************************************/
-#if 0
-/* internal misc functions */
-bool is_protocol_list_empty(void)
+static void add_channel_to_table(struct st_data_s *st_gdata,
+ struct st_proto_s *new_proto)
{
- unsigned char i = 0;
- pr_debug(" %s ", __func__);
- for (i = 0; i < ST_MAX; i++) {
- if (st_gdata->list[i] != NULL)
- return ST_NOTEMPTY;
- /* not empty */
+ pr_info("%s: id %d\n", __func__, new_proto->chnl_id);
+ /* list now has the channel id as index itself */
+ st_gdata->list[new_proto->chnl_id] = new_proto;
+}
+
+static void remove_channel_from_table(struct st_data_s *st_gdata,
+ struct st_proto_s *proto)
+{
+ pr_info("%s: id %d\n", __func__, proto->chnl_id);
+ st_gdata->list[proto->chnl_id] = NULL;
+}
+
+/*
+ * called from KIM during firmware download.
+ *
+ * This is a wrapper function to tty->ops->write_room.
+ * It returns number of free space available in
+ * uart tx buffer.
+ */
+int st_get_uart_wr_room(struct st_data_s *st_gdata)
+{
+ struct tty_struct *tty;
+ if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) {
+ pr_err("tty unavailable to perform write");
+ return -1;
}
- /* list empty */
- return ST_EMPTY;
+ tty = st_gdata->tty;
+ return tty->ops->write_room(tty);
}
-#endif
/* can be called in from
* -- KIM (during fw download)
@@ -67,7 +83,7 @@ int st_int_write(struct st_data_s *st_gdata,
struct tty_struct *tty;
if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) {
pr_err("tty unavailable to perform write");
- return -1;
+ return -EINVAL;
}
tty = st_gdata->tty;
#ifdef VERBOSE
@@ -82,15 +98,15 @@ int st_int_write(struct st_data_s *st_gdata,
* push the skb received to relevant
* protocol stacks
*/
-void st_send_frame(enum proto_type protoid, struct st_data_s *st_gdata)
+void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
{
- pr_info(" %s(prot:%d) ", __func__, protoid);
+ pr_debug(" %s(prot:%d) ", __func__, chnl_id);
if (unlikely
(st_gdata == NULL || st_gdata->rx_skb == NULL
- || st_gdata->list[protoid] == NULL)) {
- pr_err("protocol %d not registered, no data to send?",
- protoid);
+ || st_gdata->list[chnl_id] == NULL)) {
+ pr_err("chnl_id %d not registered, no data to send?",
+ chnl_id);
kfree_skb(st_gdata->rx_skb);
return;
}
@@ -99,17 +115,17 @@ void st_send_frame(enum proto_type protoid, struct st_data_s *st_gdata)
* - should be just skb_queue_tail for the
* protocol stack driver
*/
- if (likely(st_gdata->list[protoid]->recv != NULL)) {
+ if (likely(st_gdata->list[chnl_id]->recv != NULL)) {
if (unlikely
- (st_gdata->list[protoid]->recv
- (st_gdata->list[protoid]->priv_data, st_gdata->rx_skb)
+ (st_gdata->list[chnl_id]->recv
+ (st_gdata->list[chnl_id]->priv_data, st_gdata->rx_skb)
!= 0)) {
- pr_err(" proto stack %d's ->recv failed", protoid);
+ pr_err(" proto stack %d's ->recv failed", chnl_id);
kfree_skb(st_gdata->rx_skb);
return;
}
} else {
- pr_err(" proto stack %d's ->recv null", protoid);
+ pr_err(" proto stack %d's ->recv null", chnl_id);
kfree_skb(st_gdata->rx_skb);
}
return;
@@ -124,16 +140,22 @@ void st_reg_complete(struct st_data_s *st_gdata, char err)
{
unsigned char i = 0;
pr_info(" %s ", __func__);
- for (i = 0; i < ST_MAX; i++) {
+ for (i = 0; i < ST_MAX_CHANNELS; i++) {
if (likely(st_gdata != NULL && st_gdata->list[i] != NULL &&
- st_gdata->list[i]->reg_complete_cb != NULL))
+ st_gdata->list[i]->reg_complete_cb != NULL)) {
st_gdata->list[i]->reg_complete_cb
(st_gdata->list[i]->priv_data, err);
+ pr_info("protocol %d's cb sent %d\n", i, err);
+ if (err) { /* cleanup registered protocol */
+ st_gdata->protos_registered--;
+ st_gdata->list[i] = NULL;
+ }
+ }
}
}
static inline int st_check_data_len(struct st_data_s *st_gdata,
- int protoid, int len)
+ unsigned char chnl_id, int len)
{
int room = skb_tailroom(st_gdata->rx_skb);
@@ -144,7 +166,7 @@ static inline int st_check_data_len(struct st_data_s *st_gdata,
* has zero length payload. So, ask ST CORE to
* forward the packet to protocol driver (BT/FM/GPS)
*/
- st_send_frame(protoid, st_gdata);
+ st_send_frame(chnl_id, st_gdata);
} else if (len > room) {
/* Received packet's payload length is larger.
@@ -157,7 +179,7 @@ static inline int st_check_data_len(struct st_data_s *st_gdata,
/* Packet header has non-zero payload length and
* we have enough space in created skb. Lets read
* payload data */
- st_gdata->rx_state = ST_BT_W4_DATA;
+ st_gdata->rx_state = ST_W4_DATA;
st_gdata->rx_count = len;
return len;
}
@@ -167,6 +189,7 @@ static inline int st_check_data_len(struct st_data_s *st_gdata,
st_gdata->rx_state = ST_W4_PACKET_TYPE;
st_gdata->rx_skb = NULL;
st_gdata->rx_count = 0;
+ st_gdata->rx_chnl = 0;
return 0;
}
@@ -208,14 +231,12 @@ void st_int_recv(void *disc_data,
const unsigned char *data, long count)
{
char *ptr;
- struct hci_event_hdr *eh;
- struct hci_acl_hdr *ah;
- struct hci_sco_hdr *sh;
- struct fm_event_hdr *fm;
- struct gps_event_hdr *gps;
- int len = 0, type = 0, dlen = 0;
- static enum proto_type protoid = ST_MAX;
+ struct st_proto_s *proto;
+ unsigned short payload_len = 0;
+ int len = 0, type = 0;
+ unsigned char *plen;
struct st_data_s *st_gdata = (struct st_data_s *)disc_data;
+ unsigned long flags;
ptr = (char *)data;
/* tty_receive sent null ? */
@@ -224,10 +245,11 @@ void st_int_recv(void *disc_data,
return;
}
- pr_info("count %ld rx_state %ld"
+ pr_debug("count %ld rx_state %ld"
"rx_count %ld", count, st_gdata->rx_state,
st_gdata->rx_count);
+ spin_lock_irqsave(&st_gdata->lock, flags);
/* Decode received bytes here */
while (count) {
if (st_gdata->rx_count) {
@@ -242,64 +264,36 @@ void st_int_recv(void *disc_data,
/* Check ST RX state machine , where are we? */
switch (st_gdata->rx_state) {
-
- /* Waiting for complete packet ? */
- case ST_BT_W4_DATA:
+ /* Waiting for complete packet ? */
+ case ST_W4_DATA:
pr_debug("Complete pkt received");
-
/* Ask ST CORE to forward
* the packet to protocol driver */
- st_send_frame(protoid, st_gdata);
+ st_send_frame(st_gdata->rx_chnl, st_gdata);
st_gdata->rx_state = ST_W4_PACKET_TYPE;
st_gdata->rx_skb = NULL;
- protoid = ST_MAX; /* is this required ? */
- continue;
-
- /* Waiting for Bluetooth event header ? */
- case ST_BT_W4_EVENT_HDR:
- eh = (struct hci_event_hdr *)st_gdata->rx_skb->
- data;
-
- pr_debug("Event header: evt 0x%2.2x"
- "plen %d", eh->evt, eh->plen);
-
- st_check_data_len(st_gdata, protoid, eh->plen);
- continue;
-
- /* Waiting for Bluetooth acl header ? */
- case ST_BT_W4_ACL_HDR:
- ah = (struct hci_acl_hdr *)st_gdata->rx_skb->
- data;
- dlen = __le16_to_cpu(ah->dlen);
-
- pr_info("ACL header: dlen %d", dlen);
-
- st_check_data_len(st_gdata, protoid, dlen);
- continue;
-
- /* Waiting for Bluetooth sco header ? */
- case ST_BT_W4_SCO_HDR:
- sh = (struct hci_sco_hdr *)st_gdata->rx_skb->
- data;
-
- pr_info("SCO header: dlen %d", sh->dlen);
-
- st_check_data_len(st_gdata, protoid, sh->dlen);
- continue;
- case ST_FM_W4_EVENT_HDR:
- fm = (struct fm_event_hdr *)st_gdata->rx_skb->
- data;
- pr_info("FM Header: ");
- st_check_data_len(st_gdata, ST_FM, fm->plen);
continue;
- /* TODO : Add GPS packet machine logic here */
- case ST_GPS_W4_EVENT_HDR:
- /* [0x09 pkt hdr][R/W byte][2 byte len] */
- gps = (struct gps_event_hdr *)st_gdata->rx_skb->
- data;
- pr_info("GPS Header: ");
- st_check_data_len(st_gdata, ST_GPS, gps->plen);
+ /* parse the header to know details */
+ case ST_W4_HEADER:
+ proto = st_gdata->list[st_gdata->rx_chnl];
+ plen =
+ &st_gdata->rx_skb->data
+ [proto->offset_len_in_hdr];
+ pr_debug("plen pointing to %x\n", *plen);
+ if (proto->len_size == 1)/* 1 byte len field */
+ payload_len = *(unsigned char *)plen;
+ else if (proto->len_size == 2)
+ payload_len =
+ __le16_to_cpu(*(unsigned short *)plen);
+ else
+ pr_info("%s: invalid length "
+ "for id %d\n",
+ __func__, proto->chnl_id);
+ st_check_data_len(st_gdata, proto->chnl_id,
+ payload_len);
+ pr_debug("off %d, pay len %d\n",
+ proto->offset_len_in_hdr, payload_len);
continue;
} /* end of switch rx_state */
}
@@ -308,123 +302,56 @@ void st_int_recv(void *disc_data,
/* Check first byte of packet and identify module
* owner (BT/FM/GPS) */
switch (*ptr) {
-
- /* Bluetooth event packet? */
- case HCI_EVENT_PKT:
- pr_info("Event packet");
- st_gdata->rx_state = ST_BT_W4_EVENT_HDR;
- st_gdata->rx_count = HCI_EVENT_HDR_SIZE;
- type = HCI_EVENT_PKT;
- protoid = ST_BT;
- break;
-
- /* Bluetooth acl packet? */
- case HCI_ACLDATA_PKT:
- pr_info("ACL packet");
- st_gdata->rx_state = ST_BT_W4_ACL_HDR;
- st_gdata->rx_count = HCI_ACL_HDR_SIZE;
- type = HCI_ACLDATA_PKT;
- protoid = ST_BT;
- break;
-
- /* Bluetooth sco packet? */
- case HCI_SCODATA_PKT:
- pr_info("SCO packet");
- st_gdata->rx_state = ST_BT_W4_SCO_HDR;
- st_gdata->rx_count = HCI_SCO_HDR_SIZE;
- type = HCI_SCODATA_PKT;
- protoid = ST_BT;
- break;
-
- /* Channel 8(FM) packet? */
- case ST_FM_CH8_PKT:
- pr_info("FM CH8 packet");
- type = ST_FM_CH8_PKT;
- st_gdata->rx_state = ST_FM_W4_EVENT_HDR;
- st_gdata->rx_count = FM_EVENT_HDR_SIZE;
- protoid = ST_FM;
- break;
-
- /* Channel 9(GPS) packet? */
- case 0x9: /*ST_LL_GPS_CH9_PKT */
- pr_info("GPS CH9 packet");
- type = 0x9; /* ST_LL_GPS_CH9_PKT; */
- protoid = ST_GPS;
- st_gdata->rx_state = ST_GPS_W4_EVENT_HDR;
- st_gdata->rx_count = 3; /* GPS_EVENT_HDR_SIZE -1*/
- break;
case LL_SLEEP_IND:
case LL_SLEEP_ACK:
case LL_WAKE_UP_IND:
- pr_info("PM packet");
+ pr_debug("PM packet");
/* this takes appropriate action based on
* sleep state received --
*/
st_ll_sleep_state(st_gdata, *ptr);
+ /* if WAKEUP_IND collides copy from waitq to txq
+ * and assume chip awake
+ */
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
+ if (st_ll_getstate(st_gdata) == ST_LL_AWAKE)
+ st_wakeup_ack(st_gdata, LL_WAKE_UP_ACK);
+ spin_lock_irqsave(&st_gdata->lock, flags);
+
ptr++;
count--;
continue;
case LL_WAKE_UP_ACK:
- pr_info("PM packet");
+ pr_debug("PM packet");
+
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
/* wake up ack received */
st_wakeup_ack(st_gdata, *ptr);
+ spin_lock_irqsave(&st_gdata->lock, flags);
+
ptr++;
count--;
continue;
/* Unknow packet? */
default:
- pr_err("Unknown packet type %2.2x", (__u8) *ptr);
- ptr++;
- count--;
- continue;
+ type = *ptr;
+ st_gdata->rx_skb = alloc_skb(
+ st_gdata->list[type]->max_frame_size,
+ GFP_ATOMIC);
+ skb_reserve(st_gdata->rx_skb,
+ st_gdata->list[type]->reserve);
+ /* next 2 required for BT only */
+ st_gdata->rx_skb->cb[0] = type; /*pkt_type*/
+ st_gdata->rx_skb->cb[1] = 0; /*incoming*/
+ st_gdata->rx_chnl = *ptr;
+ st_gdata->rx_state = ST_W4_HEADER;
+ st_gdata->rx_count = st_gdata->list[type]->hdr_len;
+ pr_debug("rx_count %ld\n", st_gdata->rx_count);
};
ptr++;
count--;
-
- switch (protoid) {
- case ST_BT:
- /* Allocate new packet to hold received data */
- st_gdata->rx_skb =
- bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
- if (!st_gdata->rx_skb) {
- pr_err("Can't allocate mem for new packet");
- st_gdata->rx_state = ST_W4_PACKET_TYPE;
- st_gdata->rx_count = 0;
- return;
- }
- bt_cb(st_gdata->rx_skb)->pkt_type = type;
- break;
- case ST_FM: /* for FM */
- st_gdata->rx_skb =
- alloc_skb(FM_MAX_FRAME_SIZE, GFP_ATOMIC);
- if (!st_gdata->rx_skb) {
- pr_err("Can't allocate mem for new packet");
- st_gdata->rx_state = ST_W4_PACKET_TYPE;
- st_gdata->rx_count = 0;
- return;
- }
- /* place holder 0x08 */
- skb_reserve(st_gdata->rx_skb, 1);
- st_gdata->rx_skb->cb[0] = ST_FM_CH8_PKT;
- break;
- case ST_GPS:
- /* for GPS */
- st_gdata->rx_skb =
- alloc_skb(100 /*GPS_MAX_FRAME_SIZE */ , GFP_ATOMIC);
- if (!st_gdata->rx_skb) {
- pr_err("Can't allocate mem for new packet");
- st_gdata->rx_state = ST_W4_PACKET_TYPE;
- st_gdata->rx_count = 0;
- return;
- }
- /* place holder 0x09 */
- skb_reserve(st_gdata->rx_skb, 1);
- st_gdata->rx_skb->cb[0] = 0x09; /*ST_GPS_CH9_PKT; */
- break;
- case ST_MAX:
- break;
- }
}
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
pr_debug("done %s", __func__);
return;
}
@@ -466,7 +393,7 @@ void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb)
switch (st_ll_getstate(st_gdata)) {
case ST_LL_AWAKE:
- pr_info("ST LL is AWAKE, sending normally");
+ pr_debug("ST LL is AWAKE, sending normally");
skb_queue_tail(&st_gdata->txq, skb);
break;
case ST_LL_ASLEEP_TO_AWAKE:
@@ -506,7 +433,7 @@ void st_tx_wakeup(struct st_data_s *st_data)
pr_debug("%s", __func__);
/* check for sending & set flag sending here */
if (test_and_set_bit(ST_TX_SENDING, &st_data->tx_state)) {
- pr_info("ST already sending");
+ pr_debug("ST already sending");
/* keep sending */
set_bit(ST_TX_WAKEUP, &st_data->tx_state);
return;
@@ -565,20 +492,20 @@ long st_register(struct st_proto_s *new_proto)
unsigned long flags = 0;
st_kim_ref(&st_gdata, 0);
- pr_info("%s(%d) ", __func__, new_proto->type);
+ pr_info("%s(%d) ", __func__, new_proto->chnl_id);
if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL
|| new_proto->reg_complete_cb == NULL) {
pr_err("gdata/new_proto/recv or reg_complete_cb not ready");
- return -1;
+ return -EINVAL;
}
- if (new_proto->type < ST_BT || new_proto->type >= ST_MAX) {
- pr_err("protocol %d not supported", new_proto->type);
+ if (new_proto->chnl_id >= ST_MAX_CHANNELS) {
+ pr_err("chnl_id %d not supported", new_proto->chnl_id);
return -EPROTONOSUPPORT;
}
- if (st_gdata->list[new_proto->type] != NULL) {
- pr_err("protocol %d already registered", new_proto->type);
+ if (st_gdata->list[new_proto->chnl_id] != NULL) {
+ pr_err("chnl_id %d already registered", new_proto->chnl_id);
return -EALREADY;
}
@@ -586,11 +513,10 @@ long st_register(struct st_proto_s *new_proto)
spin_lock_irqsave(&st_gdata->lock, flags);
if (test_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state)) {
- pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->type);
+ pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->chnl_id);
/* fw download in progress */
- st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
- st_gdata->list[new_proto->type] = new_proto;
+ add_channel_to_table(st_gdata, new_proto);
st_gdata->protos_registered++;
new_proto->write = st_write;
@@ -598,7 +524,7 @@ long st_register(struct st_proto_s *new_proto)
spin_unlock_irqrestore(&st_gdata->lock, flags);
return -EINPROGRESS;
} else if (st_gdata->protos_registered == ST_EMPTY) {
- pr_info(" protocol list empty :%d ", new_proto->type);
+ pr_info(" chnl_id list empty :%d ", new_proto->chnl_id);
set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
st_recv = st_kim_recv;
@@ -616,16 +542,11 @@ long st_register(struct st_proto_s *new_proto)
if ((st_gdata->protos_registered != ST_EMPTY) &&
(test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
pr_err(" KIM failure complete callback ");
- st_reg_complete(st_gdata, -1);
+ st_reg_complete(st_gdata, err);
}
-
- return -1;
+ return -EINVAL;
}
- /* the protocol might require other gpios to be toggled
- */
- st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
-
clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
st_recv = st_int_recv;
@@ -642,14 +563,14 @@ long st_register(struct st_proto_s *new_proto)
/* check for already registered once more,
* since the above check is old
*/
- if (st_gdata->list[new_proto->type] != NULL) {
+ if (st_gdata->list[new_proto->chnl_id] != NULL) {
pr_err(" proto %d already registered ",
- new_proto->type);
+ new_proto->chnl_id);
return -EALREADY;
}
spin_lock_irqsave(&st_gdata->lock, flags);
- st_gdata->list[new_proto->type] = new_proto;
+ add_channel_to_table(st_gdata, new_proto);
st_gdata->protos_registered++;
new_proto->write = st_write;
spin_unlock_irqrestore(&st_gdata->lock, flags);
@@ -657,22 +578,7 @@ long st_register(struct st_proto_s *new_proto)
}
/* if fw is already downloaded & new stack registers protocol */
else {
- switch (new_proto->type) {
- case ST_BT:
- /* do nothing */
- break;
- case ST_FM:
- case ST_GPS:
- st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
- break;
- case ST_MAX:
- default:
- pr_err("%d protocol not supported",
- new_proto->type);
- spin_unlock_irqrestore(&st_gdata->lock, flags);
- return -EPROTONOSUPPORT;
- }
- st_gdata->list[new_proto->type] = new_proto;
+ add_channel_to_table(st_gdata, new_proto);
st_gdata->protos_registered++;
new_proto->write = st_write;
@@ -680,48 +586,42 @@ long st_register(struct st_proto_s *new_proto)
spin_unlock_irqrestore(&st_gdata->lock, flags);
return err;
}
- pr_debug("done %s(%d) ", __func__, new_proto->type);
+ pr_debug("done %s(%d) ", __func__, new_proto->chnl_id);
}
EXPORT_SYMBOL_GPL(st_register);
/* to unregister a protocol -
* to be called from protocol stack driver
*/
-long st_unregister(enum proto_type type)
+long st_unregister(struct st_proto_s *proto)
{
long err = 0;
unsigned long flags = 0;
struct st_data_s *st_gdata;
- pr_debug("%s: %d ", __func__, type);
+ pr_debug("%s: %d ", __func__, proto->chnl_id);
st_kim_ref(&st_gdata, 0);
- if (type < ST_BT || type >= ST_MAX) {
- pr_err(" protocol %d not supported", type);
+ if (proto->chnl_id >= ST_MAX_CHANNELS) {
+ pr_err(" chnl_id %d not supported", proto->chnl_id);
return -EPROTONOSUPPORT;
}
spin_lock_irqsave(&st_gdata->lock, flags);
- if (st_gdata->list[type] == NULL) {
- pr_err(" protocol %d not registered", type);
+ if (st_gdata->list[proto->chnl_id] == NULL) {
+ pr_err(" chnl_id %d not registered", proto->chnl_id);
spin_unlock_irqrestore(&st_gdata->lock, flags);
return -EPROTONOSUPPORT;
}
st_gdata->protos_registered--;
- st_gdata->list[type] = NULL;
-
- /* kim ignores BT in the below function
- * and handles the rest, BT is toggled
- * only in kim_start and kim_stop
- */
- st_kim_chip_toggle(type, KIM_GPIO_INACTIVE);
+ remove_channel_from_table(st_gdata, proto);
spin_unlock_irqrestore(&st_gdata->lock, flags);
if ((st_gdata->protos_registered == ST_EMPTY) &&
(!test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
- pr_info(" all protocols unregistered ");
+ pr_info(" all chnl_ids unregistered ");
/* stop traffic on tty */
if (st_gdata->tty) {
@@ -729,7 +629,7 @@ long st_unregister(enum proto_type type)
stop_tty(st_gdata->tty);
}
- /* all protocols now unregistered */
+ /* all chnl_ids now unregistered */
st_kim_stop(st_gdata->kim_data);
/* disable ST LL */
st_ll_disable(st_gdata);
@@ -745,7 +645,7 @@ long st_write(struct sk_buff *skb)
{
struct st_data_s *st_gdata;
#ifdef DEBUG
- enum proto_type protoid = ST_MAX;
+ unsigned char chnl_id = ST_MAX_CHANNELS;
#endif
long len;
@@ -753,26 +653,14 @@ long st_write(struct sk_buff *skb)
if (unlikely(skb == NULL || st_gdata == NULL
|| st_gdata->tty == NULL)) {
pr_err("data/tty unavailable to perform write");
- return -1;
+ return -EINVAL;
}
#ifdef DEBUG /* open-up skb to read the 1st byte */
- switch (skb->data[0]) {
- case HCI_COMMAND_PKT:
- case HCI_ACLDATA_PKT:
- case HCI_SCODATA_PKT:
- protoid = ST_BT;
- break;
- case ST_FM_CH8_PKT:
- protoid = ST_FM;
- break;
- case 0x09:
- protoid = ST_GPS;
- break;
- }
- if (unlikely(st_gdata->list[protoid] == NULL)) {
- pr_err(" protocol %d not registered, and writing? ",
- protoid);
- return -1;
+ chnl_id = skb->data[0];
+ if (unlikely(st_gdata->list[chnl_id] == NULL)) {
+ pr_err(" chnl_id %d not registered, and writing? ",
+ chnl_id);
+ return -EINVAL;
}
#endif
pr_debug("%d to be written", skb->len);
@@ -824,7 +712,7 @@ static int st_tty_open(struct tty_struct *tty)
static void st_tty_close(struct tty_struct *tty)
{
- unsigned char i = ST_MAX;
+ unsigned char i = ST_MAX_CHANNELS;
unsigned long flags = 0;
struct st_data_s *st_gdata = tty->disc_data;
@@ -835,7 +723,7 @@ static void st_tty_close(struct tty_struct *tty)
* un-installed for some reason - what should be done ?
*/
spin_lock_irqsave(&st_gdata->lock, flags);
- for (i = ST_BT; i < ST_MAX; i++) {
+ for (i = ST_BT; i < ST_MAX_CHANNELS; i++) {
if (st_gdata->list[i] != NULL)
pr_err("%d not un-registered", i);
st_gdata->list[i] = NULL;
@@ -869,7 +757,6 @@ static void st_tty_close(struct tty_struct *tty)
static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
char *tty_flags, int count)
{
-
#ifdef VERBOSE
print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE,
16, 1, data, count, 0);
@@ -960,7 +847,7 @@ int st_core_init(struct st_data_s **core_data)
err = tty_unregister_ldisc(N_TI_WL);
if (err)
pr_err("unable to un-register ldisc");
- return -1;
+ return err;
}
*core_data = st_gdata;
return 0;
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c
index 73b6c8b0e86..9ee4c788aa6 100644
--- a/drivers/misc/ti-st/st_kim.c
+++ b/drivers/misc/ti-st/st_kim.c
@@ -30,50 +30,12 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/sched.h>
-#include <linux/rfkill.h>
-
-/* understand BT events for fw response */
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/hci.h>
+#include <linux/tty.h>
+#include <linux/skbuff.h>
#include <linux/ti_wilink_st.h>
-static int kim_probe(struct platform_device *pdev);
-static int kim_remove(struct platform_device *pdev);
-
-/* KIM platform device driver structure */
-static struct platform_driver kim_platform_driver = {
- .probe = kim_probe,
- .remove = kim_remove,
- /* TODO: ST driver power management during suspend/resume ?
- */
-#if 0
- .suspend = kim_suspend,
- .resume = kim_resume,
-#endif
- .driver = {
- .name = "kim",
- .owner = THIS_MODULE,
- },
-};
-
-static int kim_toggle_radio(void*, bool);
-static const struct rfkill_ops kim_rfkill_ops = {
- .set_block = kim_toggle_radio,
-};
-
-/* strings to be used for rfkill entries and by
- * ST Core to be used for sysfs debug entry
- */
-#define PROTO_ENTRY(type, name) name
-const unsigned char *protocol_names[] = {
- PROTO_ENTRY(ST_BT, "Bluetooth"),
- PROTO_ENTRY(ST_FM, "FM"),
- PROTO_ENTRY(ST_GPS, "GPS"),
-};
-
#define MAX_ST_DEVICES 3 /* Imagine 1 on each UART for now */
static struct platform_device *st_kim_devices[MAX_ST_DEVICES];
@@ -134,7 +96,7 @@ static inline int kim_check_data_len(struct kim_data_s *kim_gdata, int len)
/* Packet header has non-zero payload length and
* we have enough space in created skb. Lets read
* payload data */
- kim_gdata->rx_state = ST_BT_W4_DATA;
+ kim_gdata->rx_state = ST_W4_DATA;
kim_gdata->rx_count = len;
return len;
}
@@ -158,8 +120,8 @@ void kim_int_recv(struct kim_data_s *kim_gdata,
const unsigned char *data, long count)
{
const unsigned char *ptr;
- struct hci_event_hdr *eh;
int len = 0, type = 0;
+ unsigned char *plen;
pr_debug("%s", __func__);
/* Decode received bytes here */
@@ -183,29 +145,27 @@ void kim_int_recv(struct kim_data_s *kim_gdata,
/* Check ST RX state machine , where are we? */
switch (kim_gdata->rx_state) {
/* Waiting for complete packet ? */
- case ST_BT_W4_DATA:
+ case ST_W4_DATA:
pr_debug("Complete pkt received");
validate_firmware_response(kim_gdata);
kim_gdata->rx_state = ST_W4_PACKET_TYPE;
kim_gdata->rx_skb = NULL;
continue;
/* Waiting for Bluetooth event header ? */
- case ST_BT_W4_EVENT_HDR:
- eh = (struct hci_event_hdr *)kim_gdata->
- rx_skb->data;
- pr_debug("Event header: evt 0x%2.2x"
- "plen %d", eh->evt, eh->plen);
- kim_check_data_len(kim_gdata, eh->plen);
+ case ST_W4_HEADER:
+ plen =
+ (unsigned char *)&kim_gdata->rx_skb->data[1];
+ pr_debug("event hdr: plen 0x%02x\n", *plen);
+ kim_check_data_len(kim_gdata, *plen);
continue;
} /* end of switch */
} /* end of if rx_state */
switch (*ptr) {
/* Bluetooth event packet? */
- case HCI_EVENT_PKT:
- pr_info("Event packet");
- kim_gdata->rx_state = ST_BT_W4_EVENT_HDR;
- kim_gdata->rx_count = HCI_EVENT_HDR_SIZE;
- type = HCI_EVENT_PKT;
+ case 0x04:
+ kim_gdata->rx_state = ST_W4_HEADER;
+ kim_gdata->rx_count = 2;
+ type = *ptr;
break;
default:
pr_info("unknown packet");
@@ -216,16 +176,18 @@ void kim_int_recv(struct kim_data_s *kim_gdata,
ptr++;
count--;
kim_gdata->rx_skb =
- bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ alloc_skb(1024+8, GFP_ATOMIC);
if (!kim_gdata->rx_skb) {
pr_err("can't allocate mem for new packet");
kim_gdata->rx_state = ST_W4_PACKET_TYPE;
kim_gdata->rx_count = 0;
return;
}
- bt_cb(kim_gdata->rx_skb)->pkt_type = type;
+ skb_reserve(kim_gdata->rx_skb, 8);
+ kim_gdata->rx_skb->cb[0] = 4;
+ kim_gdata->rx_skb->cb[1] = 0;
+
}
- pr_info("done %s", __func__);
return;
}
@@ -239,13 +201,13 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name)
INIT_COMPLETION(kim_gdata->kim_rcvd);
if (4 != st_int_write(kim_gdata->core_data, read_ver_cmd, 4)) {
pr_err("kim: couldn't write 4 bytes");
- return -1;
+ return -EIO;
}
if (!wait_for_completion_timeout
(&kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) {
pr_err(" waiting for ver info- timed out ");
- return -1;
+ return -ETIMEDOUT;
}
version =
@@ -270,6 +232,26 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name)
return 0;
}
+void skip_change_remote_baud(unsigned char **ptr, long *len)
+{
+ unsigned char *nxt_action, *cur_action;
+ cur_action = *ptr;
+
+ nxt_action = cur_action + sizeof(struct bts_action) +
+ ((struct bts_action *) cur_action)->size;
+
+ if (((struct bts_action *) nxt_action)->type != ACTION_WAIT_EVENT) {
+ pr_err("invalid action after change remote baud command");
+ } else {
+ *ptr = *ptr + sizeof(struct bts_action) +
+ ((struct bts_action *)nxt_action)->size;
+ *len = *len - (sizeof(struct bts_action) +
+ ((struct bts_action *)nxt_action)->size);
+ /* warn user on not commenting these in firmware */
+ pr_warn("skipping the wait event of change remote baud");
+ }
+}
+
/**
* download_firmware -
* internal function which parses through the .bts firmware
@@ -282,6 +264,9 @@ static long download_firmware(struct kim_data_s *kim_gdata)
unsigned char *ptr = NULL;
unsigned char *action_ptr = NULL;
unsigned char bts_scr_name[30] = { 0 }; /* 30 char long bts scr name? */
+ int wr_room_space;
+ int cmd_size;
+ unsigned long timeout;
err = read_local_version(kim_gdata, bts_scr_name);
if (err != 0) {
@@ -295,7 +280,7 @@ static long download_firmware(struct kim_data_s *kim_gdata)
(kim_gdata->fw_entry->size == 0))) {
pr_err(" request_firmware failed(errno %ld) for %s", err,
bts_scr_name);
- return -1;
+ return -EINVAL;
}
ptr = (void *)kim_gdata->fw_entry->data;
len = kim_gdata->fw_entry->size;
@@ -318,29 +303,72 @@ static long download_firmware(struct kim_data_s *kim_gdata)
0xFF36)) {
/* ignore remote change
* baud rate HCI VS command */
- pr_err
- (" change remote baud"
+ pr_warn("change remote baud"
" rate command in firmware");
+ skip_change_remote_baud(&ptr, &len);
break;
}
+ /*
+ * Make sure we have enough free space in uart
+ * tx buffer to write current firmware command
+ */
+ cmd_size = ((struct bts_action *)ptr)->size;
+ timeout = jiffies + msecs_to_jiffies(CMD_WR_TIME);
+ do {
+ wr_room_space =
+ st_get_uart_wr_room(kim_gdata->core_data);
+ if (wr_room_space < 0) {
+ pr_err("Unable to get free "
+ "space info from uart tx buffer");
+ release_firmware(kim_gdata->fw_entry);
+ return wr_room_space;
+ }
+ mdelay(1); /* wait 1ms before checking room */
+ } while ((wr_room_space < cmd_size) &&
+ time_before(jiffies, timeout));
+
+ /* Timeout happened ? */
+ if (time_after_eq(jiffies, timeout)) {
+ pr_err("Timeout while waiting for free "
+ "free space in uart tx buffer");
+ release_firmware(kim_gdata->fw_entry);
+ return -ETIMEDOUT;
+ }
- INIT_COMPLETION(kim_gdata->kim_rcvd);
+ /*
+ * Free space found in uart buffer, call st_int_write
+ * to send current firmware command to the uart tx
+ * buffer.
+ */
err = st_int_write(kim_gdata->core_data,
((struct bts_action_send *)action_ptr)->data,
((struct bts_action *)ptr)->size);
if (unlikely(err < 0)) {
release_firmware(kim_gdata->fw_entry);
- return -1;
+ return err;
}
+ /*
+ * Check number of bytes written to the uart tx buffer
+ * and requested command write size
+ */
+ if (err != cmd_size) {
+ pr_err("Number of bytes written to uart "
+ "tx buffer are not matching with "
+ "requested cmd write size");
+ release_firmware(kim_gdata->fw_entry);
+ return -EIO;
+ }
+ break;
+ case ACTION_WAIT_EVENT: /* wait */
if (!wait_for_completion_timeout
- (&kim_gdata->kim_rcvd,
- msecs_to_jiffies(CMD_RESP_TIME))) {
- pr_err
- (" response timeout during fw download ");
+ (&kim_gdata->kim_rcvd,
+ msecs_to_jiffies(CMD_RESP_TIME))) {
+ pr_err("response timeout during fw download ");
/* timed out */
release_firmware(kim_gdata->fw_entry);
- return -1;
+ return -ETIMEDOUT;
}
+ INIT_COMPLETION(kim_gdata->kim_rcvd);
break;
case ACTION_DELAY: /* sleep */
pr_info("sleep command in scr");
@@ -362,50 +390,6 @@ static long download_firmware(struct kim_data_s *kim_gdata)
/**********************************************************************/
/* functions called from ST core */
-/* function to toggle the GPIO
- * needs to know whether the GPIO is active high or active low
- */
-void st_kim_chip_toggle(enum proto_type type, enum kim_gpio_state state)
-{
- struct platform_device *kim_pdev;
- struct kim_data_s *kim_gdata;
- pr_info(" %s ", __func__);
-
- kim_pdev = st_get_plat_device(0);
- kim_gdata = dev_get_drvdata(&kim_pdev->dev);
-
- if (kim_gdata->gpios[type] == -1) {
- pr_info(" gpio not requested for protocol %s",
- protocol_names[type]);
- return;
- }
- switch (type) {
- case ST_BT:
- /*Do Nothing */
- break;
-
- case ST_FM:
- if (state == KIM_GPIO_ACTIVE)
- gpio_set_value(kim_gdata->gpios[ST_FM], GPIO_LOW);
- else
- gpio_set_value(kim_gdata->gpios[ST_FM], GPIO_HIGH);
- break;
-
- case ST_GPS:
- if (state == KIM_GPIO_ACTIVE)
- gpio_set_value(kim_gdata->gpios[ST_GPS], GPIO_HIGH);
- else
- gpio_set_value(kim_gdata->gpios[ST_GPS], GPIO_LOW);
- break;
-
- case ST_MAX:
- default:
- break;
- }
-
- return;
-}
-
/* called from ST Core, when REG_IN_PROGRESS (registration in progress)
* can be because of
* 1. response to read local version
@@ -416,7 +400,6 @@ void st_kim_recv(void *disc_data, const unsigned char *data, long count)
struct st_data_s *st_gdata = (struct st_data_s *)disc_data;
struct kim_data_s *kim_gdata = st_gdata->kim_data;
- pr_info(" %s ", __func__);
/* copy to local buffer */
if (unlikely(data[4] == 0x01 && data[5] == 0x10 && data[0] == 0x04)) {
/* must be the read_ver_cmd */
@@ -455,35 +438,28 @@ long st_kim_start(void *kim_data)
pr_info(" %s", __func__);
do {
- /* TODO: this is only because rfkill sub-system
- * doesn't send events to user-space if the state
- * isn't changed
- */
- rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 1);
/* Configure BT nShutdown to HIGH state */
- gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW);
+ gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
mdelay(5); /* FIXME: a proper toggle */
- gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_HIGH);
+ gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH);
mdelay(100);
/* re-initialize the completion */
INIT_COMPLETION(kim_gdata->ldisc_installed);
-#if 0 /* older way of signalling user-space UIM */
- /* send signal to UIM */
- err = kill_pid(find_get_pid(kim_gdata->uim_pid), SIGUSR2, 0);
- if (err != 0) {
- pr_info(" sending SIGUSR2 to uim failed %ld", err);
- err = -1;
- continue;
- }
-#endif
- /* unblock and send event to UIM via /dev/rfkill */
- rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 0);
+ /* send notification to UIM */
+ kim_gdata->ldisc_install = 1;
+ pr_info("ldisc_install = 1");
+ sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
+ NULL, "install");
/* wait for ldisc to be installed */
err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
msecs_to_jiffies(LDISC_TIME));
if (!err) { /* timeout */
pr_err("line disc installation timed out ");
- err = -1;
+ kim_gdata->ldisc_install = 0;
+ pr_info("ldisc_install = 0");
+ sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
+ NULL, "install");
+ err = -ETIMEDOUT;
continue;
} else {
/* ldisc installed now */
@@ -491,6 +467,10 @@ long st_kim_start(void *kim_data)
err = download_firmware(kim_gdata);
if (err != 0) {
pr_err("download firmware failed");
+ kim_gdata->ldisc_install = 0;
+ pr_info("ldisc_install = 0");
+ sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
+ NULL, "install");
continue;
} else { /* on success don't retry */
break;
@@ -510,31 +490,30 @@ long st_kim_stop(void *kim_data)
struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data;
INIT_COMPLETION(kim_gdata->ldisc_installed);
-#if 0 /* older way of signalling user-space UIM */
- /* send signal to UIM */
- err = kill_pid(find_get_pid(kim_gdata->uim_pid), SIGUSR2, 1);
- if (err != 0) {
- pr_err("sending SIGUSR2 to uim failed %ld", err);
- return -1;
- }
-#endif
- /* set BT rfkill to be blocked */
- err = rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 1);
+
+ /* Flush any pending characters in the driver and discipline. */
+ tty_ldisc_flush(kim_gdata->core_data->tty);
+ tty_driver_flush_buffer(kim_gdata->core_data->tty);
+
+ /* send uninstall notification to UIM */
+ pr_info("ldisc_install = 0");
+ kim_gdata->ldisc_install = 0;
+ sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, NULL, "install");
/* wait for ldisc to be un-installed */
err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
msecs_to_jiffies(LDISC_TIME));
if (!err) { /* timeout */
pr_err(" timed out waiting for ldisc to be un-installed");
- return -1;
+ return -ETIMEDOUT;
}
/* By default configure BT nShutdown to LOW state */
- gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW);
+ gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
mdelay(1);
- gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_HIGH);
+ gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH);
mdelay(1);
- gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW);
+ gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
return err;
}
@@ -558,33 +537,59 @@ static int show_list(struct seq_file *s, void *unused)
return 0;
}
-/* function called from rfkill subsystem, when someone from
- * user space would write 0/1 on the sysfs entry
- * /sys/class/rfkill/rfkill0,1,3/state
- */
-static int kim_toggle_radio(void *data, bool blocked)
+static ssize_t show_install(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- enum proto_type type = *((enum proto_type *)data);
- pr_debug(" %s: %d ", __func__, type);
-
- switch (type) {
- case ST_BT:
- /* do nothing */
- break;
- case ST_FM:
- case ST_GPS:
- if (blocked)
- st_kim_chip_toggle(type, KIM_GPIO_INACTIVE);
- else
- st_kim_chip_toggle(type, KIM_GPIO_ACTIVE);
- break;
- case ST_MAX:
- pr_err(" wrong proto type ");
- break;
- }
- return 0;
+ struct kim_data_s *kim_data = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", kim_data->ldisc_install);
}
+static ssize_t show_dev_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kim_data_s *kim_data = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", kim_data->dev_name);
+}
+
+static ssize_t show_baud_rate(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kim_data_s *kim_data = dev_get_drvdata(dev);
+ return sprintf(buf, "%ld\n", kim_data->baud_rate);
+}
+
+static ssize_t show_flow_cntrl(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kim_data_s *kim_data = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", kim_data->flow_cntrl);
+}
+
+/* structures specific for sysfs entries */
+static struct kobj_attribute ldisc_install =
+__ATTR(install, 0444, (void *)show_install, NULL);
+
+static struct kobj_attribute uart_dev_name =
+__ATTR(dev_name, 0444, (void *)show_dev_name, NULL);
+
+static struct kobj_attribute uart_baud_rate =
+__ATTR(baud_rate, 0444, (void *)show_baud_rate, NULL);
+
+static struct kobj_attribute uart_flow_cntrl =
+__ATTR(flow_cntrl, 0444, (void *)show_flow_cntrl, NULL);
+
+static struct attribute *uim_attrs[] = {
+ &ldisc_install.attr,
+ &uart_dev_name.attr,
+ &uart_baud_rate.attr,
+ &uart_flow_cntrl.attr,
+ NULL,
+};
+
+static struct attribute_group uim_attr_grp = {
+ .attrs = uim_attrs,
+};
+
/**
* st_kim_ref - reference the core's data
* This references the per-ST platform device in the arch/xx/
@@ -637,9 +642,8 @@ struct dentry *kim_debugfs_dir;
static int kim_probe(struct platform_device *pdev)
{
long status;
- long proto;
- long *gpios = pdev->dev.platform_data;
struct kim_data_s *kim_gdata;
+ struct ti_st_plat_data *pdata = pdev->dev.platform_data;
if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) {
/* multiple devices could exist */
@@ -659,44 +663,24 @@ static int kim_probe(struct platform_device *pdev)
status = st_core_init(&kim_gdata->core_data);
if (status != 0) {
pr_err(" ST core init failed");
- return -1;
+ return -EIO;
}
/* refer to itself */
kim_gdata->core_data->kim_data = kim_gdata;
- for (proto = 0; proto < ST_MAX; proto++) {
- kim_gdata->gpios[proto] = gpios[proto];
- pr_info(" %ld gpio to be requested", gpios[proto]);
+ /* Claim the chip enable nShutdown gpio from the system */
+ kim_gdata->nshutdown = pdata->nshutdown_gpio;
+ status = gpio_request(kim_gdata->nshutdown, "kim");
+ if (unlikely(status)) {
+ pr_err(" gpio %ld request failed ", kim_gdata->nshutdown);
+ return status;
}
- for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
- /* Claim the Bluetooth/FM/GPIO
- * nShutdown gpio from the system
- */
- status = gpio_request(gpios[proto], "kim");
- if (unlikely(status)) {
- pr_err(" gpio %ld request failed ", gpios[proto]);
- proto -= 1;
- while (proto >= 0) {
- if (gpios[proto] != -1)
- gpio_free(gpios[proto]);
- }
- return status;
- }
-
- /* Configure nShutdown GPIO as output=0 */
- status =
- gpio_direction_output(gpios[proto], 0);
- if (unlikely(status)) {
- pr_err(" unable to configure gpio %ld",
- gpios[proto]);
- proto -= 1;
- while (proto >= 0) {
- if (gpios[proto] != -1)
- gpio_free(gpios[proto]);
- }
- return status;
- }
+ /* Configure nShutdown GPIO as output=0 */
+ status = gpio_direction_output(kim_gdata->nshutdown, 0);
+ if (unlikely(status)) {
+ pr_err(" unable to configure gpio %ld", kim_gdata->nshutdown);
+ return status;
}
/* get reference of pdev for request_firmware
*/
@@ -704,34 +688,23 @@ static int kim_probe(struct platform_device *pdev)
init_completion(&kim_gdata->kim_rcvd);
init_completion(&kim_gdata->ldisc_installed);
- for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
- /* TODO: should all types be rfkill_type_bt ? */
- kim_gdata->rf_protos[proto] = proto;
- kim_gdata->rfkill[proto] = rfkill_alloc(protocol_names[proto],
- &pdev->dev, RFKILL_TYPE_BLUETOOTH,
- &kim_rfkill_ops, &kim_gdata->rf_protos[proto]);
- if (kim_gdata->rfkill[proto] == NULL) {
- pr_err("cannot create rfkill entry for gpio %ld",
- gpios[proto]);
- continue;
- }
- /* block upon creation */
- rfkill_init_sw_state(kim_gdata->rfkill[proto], 1);
- status = rfkill_register(kim_gdata->rfkill[proto]);
- if (unlikely(status)) {
- pr_err("rfkill registration failed for gpio %ld",
- gpios[proto]);
- rfkill_unregister(kim_gdata->rfkill[proto]);
- continue;
- }
- pr_info("rfkill entry created for %ld", gpios[proto]);
+ status = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp);
+ if (status) {
+ pr_err("failed to create sysfs entries");
+ return status;
}
+ /* copying platform data */
+ strncpy(kim_gdata->dev_name, pdata->dev_name, UART_DEV_NAME_LEN);
+ kim_gdata->flow_cntrl = pdata->flow_cntrl;
+ kim_gdata->baud_rate = pdata->baud_rate;
+ pr_info("sysfs entries created\n");
+
kim_debugfs_dir = debugfs_create_dir("ti-st", NULL);
if (IS_ERR(kim_debugfs_dir)) {
pr_err(" debugfs entries creation failed ");
kim_debugfs_dir = NULL;
- return -1;
+ return -EIO;
}
debugfs_create_file("version", S_IRUGO, kim_debugfs_dir,
@@ -744,25 +717,22 @@ static int kim_probe(struct platform_device *pdev)
static int kim_remove(struct platform_device *pdev)
{
- /* free the GPIOs requested
- */
- long *gpios = pdev->dev.platform_data;
- long proto;
+ /* free the GPIOs requested */
+ struct ti_st_plat_data *pdata = pdev->dev.platform_data;
struct kim_data_s *kim_gdata;
kim_gdata = dev_get_drvdata(&pdev->dev);
- for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
- /* Claim the Bluetooth/FM/GPIO
- * nShutdown gpio from the system
- */
- gpio_free(gpios[proto]);
- rfkill_unregister(kim_gdata->rfkill[proto]);
- rfkill_destroy(kim_gdata->rfkill[proto]);
- kim_gdata->rfkill[proto] = NULL;
- }
- pr_info("kim: GPIO Freed");
+ /* Free the Bluetooth/FM/GPIO
+ * nShutdown gpio from the system
+ */
+ gpio_free(pdata->nshutdown_gpio);
+ pr_info("nshutdown GPIO Freed");
+
debugfs_remove_recursive(kim_debugfs_dir);
+ sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp);
+ pr_info("sysfs entries removed");
+
kim_gdata->kim_pdev = NULL;
st_core_exit(kim_gdata->core_data);
@@ -771,23 +741,46 @@ static int kim_remove(struct platform_device *pdev)
return 0;
}
+int kim_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct ti_st_plat_data *pdata = pdev->dev.platform_data;
+
+ if (pdata->suspend)
+ return pdata->suspend(pdev, state);
+
+ return -EOPNOTSUPP;
+}
+
+int kim_resume(struct platform_device *pdev)
+{
+ struct ti_st_plat_data *pdata = pdev->dev.platform_data;
+
+ if (pdata->resume)
+ return pdata->resume(pdev);
+
+ return -EOPNOTSUPP;
+}
+
/**********************************************************************/
/* entry point for ST KIM module, called in from ST Core */
+static struct platform_driver kim_platform_driver = {
+ .probe = kim_probe,
+ .remove = kim_remove,
+ .suspend = kim_suspend,
+ .resume = kim_resume,
+ .driver = {
+ .name = "kim",
+ .owner = THIS_MODULE,
+ },
+};
static int __init st_kim_init(void)
{
- long ret = 0;
- ret = platform_driver_register(&kim_platform_driver);
- if (ret != 0) {
- pr_err("platform drv registration failed");
- return -1;
- }
- return 0;
+ return platform_driver_register(&kim_platform_driver);
}
static void __exit st_kim_deinit(void)
{
- /* the following returns void */
platform_driver_unregister(&kim_platform_driver);
}
diff --git a/drivers/misc/ti-st/st_ll.c b/drivers/misc/ti-st/st_ll.c
index 2bda8dea15b..3f249513885 100644
--- a/drivers/misc/ti-st/st_ll.c
+++ b/drivers/misc/ti-st/st_ll.c
@@ -30,7 +30,7 @@ static void send_ll_cmd(struct st_data_s *st_data,
unsigned char cmd)
{
- pr_info("%s: writing %x", __func__, cmd);
+ pr_debug("%s: writing %x", __func__, cmd);
st_int_write(st_data, &cmd, 1);
return;
}
@@ -114,23 +114,23 @@ unsigned long st_ll_sleep_state(struct st_data_s *st_data,
{
switch (cmd) {
case LL_SLEEP_IND: /* sleep ind */
- pr_info("sleep indication recvd");
+ pr_debug("sleep indication recvd");
ll_device_want_to_sleep(st_data);
break;
case LL_SLEEP_ACK: /* sleep ack */
pr_err("sleep ack rcvd: host shouldn't");
break;
case LL_WAKE_UP_IND: /* wake ind */
- pr_info("wake indication recvd");
+ pr_debug("wake indication recvd");
ll_device_want_to_wakeup(st_data);
break;
case LL_WAKE_UP_ACK: /* wake ack */
- pr_info("wake ack rcvd");
+ pr_debug("wake ack rcvd");
st_data->ll_state = ST_LL_AWAKE;
break;
default:
pr_err(" unknown input/state ");
- return -1;
+ return -EINVAL;
}
return 0;
}
diff --git a/drivers/misc/twl6040-vib.c b/drivers/misc/twl6040-vib.c
new file mode 100644
index 00000000000..fbb664adfd1
--- /dev/null
+++ b/drivers/misc/twl6040-vib.c
@@ -0,0 +1,255 @@
+/* drivers/misc/twl6040-vib.c
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Dan Murphy <dmurphy@ti.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Derived from: vib-gpio.c
+ * Additional derivation from: twl6040-vibra.c
+ */
+
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/twl6040-vib.h>
+#include <linux/i2c/twl.h>
+#include <linux/mfd/twl6040-codec.h>
+#include "../staging/android/timed_output.h"
+
+struct vib_data {
+ struct timed_output_dev dev;
+ struct work_struct vib_work;
+ struct hrtimer timer;
+ spinlock_t lock;
+
+ struct twl4030_codec_vibra_data *pdata;
+ struct twl6040 *twl6040;
+
+ int vib_power_state;
+ int vib_state;
+};
+
+struct vib_data *misc_data;
+
+static void vib_set(int on)
+{
+ struct twl6040 *twl6040 = misc_data->twl6040;
+ u8 mask = TWL6040_VIBENAL | TWL6040_VIBCTRLLP;
+
+ if (on) {
+ twl6040_set_bits(twl6040, TWL6040_REG_VIBCTLL, mask);
+ twl6040_set_bits(twl6040, TWL6040_REG_VIBCTLR, mask);
+ } else {
+ twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL, mask);
+ twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR, mask);
+ }
+}
+
+static void vib_update(struct work_struct *work)
+{
+ vib_set(misc_data->vib_state);
+}
+
+static enum hrtimer_restart vib_timer_func(struct hrtimer *timer)
+{
+ struct vib_data *data =
+ container_of(timer, struct vib_data, timer);
+ data->vib_state = 0;
+ schedule_work(&data->vib_work);
+ return HRTIMER_NORESTART;
+}
+
+static int vib_get_time(struct timed_output_dev *dev)
+{
+ struct vib_data *data =
+ container_of(dev, struct vib_data, dev);
+
+ if (hrtimer_active(&data->timer)) {
+ ktime_t r = hrtimer_get_remaining(&data->timer);
+ struct timeval t = ktime_to_timeval(r);
+ return t.tv_sec * 1000 + t.tv_usec / 1000;
+ } else
+ return 0;
+}
+
+static void vib_enable(struct timed_output_dev *dev, int value)
+{
+ struct vib_data *data = container_of(dev, struct vib_data, dev);
+ unsigned long flags;
+
+ if (value < 0) {
+ pr_err("%s: Invalid vibrator timer value\n", __func__);
+ return;
+ }
+
+ twl6040_reg_write(data->twl6040, TWL6040_REG_VIBDATL, 0x32);
+ twl6040_reg_write(data->twl6040, TWL6040_REG_VIBDATR, 0x32);
+
+ spin_lock_irqsave(&data->lock, flags);
+ hrtimer_cancel(&data->timer);
+
+ if (value == 0)
+ data->vib_state = 0;
+ else {
+ value = (value > data->pdata->max_timeout ?
+ data->pdata->max_timeout : value);
+ data->vib_state = 1;
+ hrtimer_start(&data->timer,
+ ktime_set(value / 1000, (value % 1000) * 1000000),
+ HRTIMER_MODE_REL);
+ }
+
+ spin_unlock_irqrestore(&data->lock, flags);
+
+ schedule_work(&data->vib_work);
+}
+
+/*
+ * This is a temporary solution until a more global haptics soltion is
+ * available for haptics that need to occur in any application
+ */
+void vibrator_haptic_fire(int value)
+{
+ vib_enable(&misc_data->dev, value);
+}
+
+#if CONFIG_PM
+static int vib_suspend(struct device *dev)
+{
+ struct vib_data *data = dev_get_drvdata(dev);
+
+ twl6040_disable(data->twl6040);
+
+ return 0;
+}
+
+static int vib_resume(struct device *dev)
+{
+ struct vib_data *data = dev_get_drvdata(dev);
+
+ twl6040_enable(data->twl6040);
+
+ return 0;
+}
+#else
+#define vib_suspend NULL
+#define vib_resume NULL
+#endif
+
+static const struct dev_pm_ops vib_pm_ops = {
+ .suspend = vib_suspend,
+ .resume = vib_resume,
+};
+
+static int vib_probe(struct platform_device *pdev)
+{
+ struct twl4030_codec_vibra_data *pdata = pdev->dev.platform_data;
+ struct vib_data *data;
+ int ret = 0;
+
+ if (!pdata) {
+ ret = -EBUSY;
+ goto err0;
+ }
+
+ data = kzalloc(sizeof(struct vib_data), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ data->pdata = pdata;
+ data->twl6040 = dev_get_drvdata(pdev->dev.parent);
+
+ INIT_WORK(&data->vib_work, vib_update);
+
+ hrtimer_init(&data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+
+ data->timer.function = vib_timer_func;
+ spin_lock_init(&data->lock);
+
+ data->dev.name = "vibrator";
+ data->dev.get_time = vib_get_time;
+ data->dev.enable = vib_enable;
+ ret = timed_output_dev_register(&data->dev);
+ if (ret < 0)
+ goto err1;
+
+ if (data->pdata->init)
+ ret = data->pdata->init();
+ if (ret < 0)
+ goto err2;
+
+ misc_data = data;
+ platform_set_drvdata(pdev, data);
+
+ twl6040_enable(data->twl6040);
+ vib_enable(&data->dev, data->pdata->initial_vibrate);
+
+ return 0;
+
+err2:
+ timed_output_dev_unregister(&data->dev);
+err1:
+ kfree(data->pdata);
+ kfree(data);
+err0:
+ return ret;
+}
+
+static int vib_remove(struct platform_device *pdev)
+{
+ struct vib_data *data = platform_get_drvdata(pdev);
+
+ if (data->pdata->exit)
+ data->pdata->exit();
+
+ twl6040_disable(data->twl6040);
+
+ timed_output_dev_unregister(&data->dev);
+ kfree(data->pdata);
+ kfree(data);
+
+ return 0;
+}
+
+/* TO DO: Need to make this drivers own platform data entries */
+static struct platform_driver twl6040_vib_driver = {
+ .probe = vib_probe,
+ .remove = vib_remove,
+ .driver = {
+ .name = VIB_NAME,
+ .owner = THIS_MODULE,
+ .pm = &vib_pm_ops,
+ },
+};
+
+static int __init twl6040_vib_init(void)
+{
+ return platform_driver_register(&twl6040_vib_driver);
+}
+
+static void __exit twl6040_vib_exit(void)
+{
+ platform_driver_unregister(&twl6040_vib_driver);
+}
+
+module_init(twl6040_vib_init);
+module_exit(twl6040_vib_exit);
+
+MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
+MODULE_DESCRIPTION("TWL6040 Vibrator Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 727874d9deb..2f88eb0e2cf 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -46,6 +46,7 @@
#define SMSC95XX_INTERNAL_PHY_ID (1)
#define SMSC95XX_TX_OVERHEAD (8)
#define SMSC95XX_TX_OVERHEAD_CSUM (12)
+#define MAC_ADDR_LEN (6)
struct smsc95xx_priv {
u32 mac_cr;
@@ -65,6 +66,10 @@ static int turbo_mode = true;
module_param(turbo_mode, bool, 0644);
MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
+static char *macaddr = ":";
+module_param(macaddr, charp, 0);
+MODULE_PARM_DESC(macaddr, "MAC address");
+
static int smsc95xx_read_reg(struct usbnet *dev, u32 index, u32 *data)
{
u32 *buf = kmalloc(4, GFP_KERNEL);
@@ -640,8 +645,59 @@ static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
}
+/* Check the macaddr module parameter for a MAC address */
+static int smsc95xx_is_macaddr_param(struct usbnet *dev, u8 *dev_mac)
+{
+ int i, j, got_num, num;
+ u8 mtbl[MAC_ADDR_LEN];
+
+ if (macaddr[0] == ':')
+ return 0;
+
+ i = 0;
+ j = 0;
+ num = 0;
+ got_num = 0;
+ while (j < MAC_ADDR_LEN) {
+ if (macaddr[i] && macaddr[i] != ':') {
+ got_num++;
+ if ('0' <= macaddr[i] && macaddr[i] <= '9')
+ num = num * 16 + macaddr[i] - '0';
+ else if ('A' <= macaddr[i] && macaddr[i] <= 'F')
+ num = num * 16 + 10 + macaddr[i] - 'A';
+ else if ('a' <= macaddr[i] && macaddr[i] <= 'f')
+ num = num * 16 + 10 + macaddr[i] - 'a';
+ else
+ break;
+ i++;
+ } else if (got_num == 2) {
+ mtbl[j++] = (u8) num;
+ num = 0;
+ got_num = 0;
+ i++;
+ } else {
+ break;
+ }
+ }
+
+ if (j == MAC_ADDR_LEN) {
+ netif_dbg(dev, ifup, dev->net, "Overriding MAC address with: "
+ "%02x:%02x:%02x:%02x:%02x:%02x\n", mtbl[0], mtbl[1], mtbl[2],
+ mtbl[3], mtbl[4], mtbl[5]);
+ for (i = 0; i < MAC_ADDR_LEN; i++)
+ dev_mac[i] = mtbl[i];
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
static void smsc95xx_init_mac_address(struct usbnet *dev)
{
+ /* Check module parameters */
+ if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr))
+ return;
+
/* try reading mac address from EEPROM */
if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
dev->net->dev_addr) == 0) {
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index 93cbb8d5aba..8c0eb433a35 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -28,6 +28,7 @@
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
#include <linux/gpio.h>
#include <linux/wl12xx.h>
#include <linux/pm_runtime.h>
@@ -163,6 +164,11 @@ static int wl1271_sdio_power_on(struct wl1271 *wl)
struct sdio_func *func = wl_to_func(wl);
int ret;
+ /*
+ * defeat the runtime_idle OFF state
+ */
+ mmc_power_restore_host(func->card->host);
+
/* Power up the card */
ret = pm_runtime_get_sync(&func->dev);
if (ret < 0)
@@ -302,9 +308,23 @@ static int wl1271_resume(struct device *dev)
return 0;
}
+/*
+ * SDIO bus runtime idle gets precedence over this, but that just calls
+ * the generic version. The generic version will call our version if
+ * it exists, so we still get called. We need to allow it to power us
+ * off.
+ */
+static int wl1271_runtime_idle(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+
+ return mmc_power_save_host(func->card->host);
+}
+
static const struct dev_pm_ops wl1271_sdio_pm_ops = {
.suspend = wl1271_suspend,
.resume = wl1271_resume,
+ .runtime_idle = wl1271_runtime_idle,
};
static struct sdio_driver wl1271_sdio_driver = {
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 9050dd9b62d..8ceb6a0d53e 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -112,8 +112,8 @@ extern u32 wl12xx_debug_level;
CFG_RX_CTL_EN | CFG_RX_BCN_EN | \
CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
-#define WL1271_FW_NAME "wl1271-fw.bin"
-#define WL1271_NVS_NAME "wl1271-nvs.bin"
+#define WL1271_FW_NAME "ti-connectivity/wl1271-fw.bin"
+#define WL1271_NVS_NAME "ti-connectivity/wl1271-nvs.bin"
#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 5c8fcfc42c3..b6cb9db128c 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -141,8 +141,6 @@ source "drivers/staging/crystalhd/Kconfig"
source "drivers/staging/cxt1e1/Kconfig"
-source "drivers/staging/ti-st/Kconfig"
-
source "drivers/staging/xgifb/Kconfig"
source "drivers/staging/msm/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index d5388631782..ad8209e6ca9 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -53,7 +53,6 @@ obj-$(CONFIG_FB_SM7XX) += sm7xx/
obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/
obj-$(CONFIG_CRYSTALHD) += crystalhd/
obj-$(CONFIG_CXT1E1) += cxt1e1/
-obj-$(CONFIG_TI_ST) += ti-st/
obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_MSM_STAGING) += msm/
obj-$(CONFIG_EASYCAP) += easycap/
diff --git a/drivers/staging/ti-st/Kconfig b/drivers/staging/ti-st/Kconfig
deleted file mode 100644
index 074b8e89e91..00000000000
--- a/drivers/staging/ti-st/Kconfig
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# TI's shared transport line discipline and the protocol
-# drivers (BT, FM and GPS)
-#
-menu "Texas Instruments shared transport line discipline"
-config ST_BT
- tristate "BlueZ bluetooth driver for ST"
- depends on BT && RFKILL
- select TI_ST
- help
- This enables the Bluetooth driver for TI BT/FM/GPS combo devices.
- This makes use of shared transport line discipline core driver to
- communicate with the BT core of the combo chip.
-endmenu
diff --git a/drivers/staging/ti-st/Makefile b/drivers/staging/ti-st/Makefile
deleted file mode 100644
index 5f11b82c016..00000000000
--- a/drivers/staging/ti-st/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for TI's shared transport line discipline
-# and its protocol drivers (BT, FM, GPS)
-#
-obj-$(CONFIG_ST_BT) += bt_drv.o
diff --git a/drivers/staging/ti-st/TODO b/drivers/staging/ti-st/TODO
deleted file mode 100644
index ebfd6bb6017..00000000000
--- a/drivers/staging/ti-st/TODO
+++ /dev/null
@@ -1,8 +0,0 @@
-TODO:
-
-1. Step up and maintain this driver to ensure that it continues
-to work. Having the hardware for this is pretty much a
-requirement. If this does not happen, the will be removed in
-the 2.6.35 kernel release.
-
-Please send patches to Greg Kroah-Hartman <greg@kroah.com>.
diff --git a/drivers/staging/ti-st/bt_drv.c b/drivers/staging/ti-st/bt_drv.c
deleted file mode 100644
index 75065bf39e5..00000000000
--- a/drivers/staging/ti-st/bt_drv.c
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
- * Texas Instrument's Bluetooth Driver For Shared Transport.
- *
- * Bluetooth Driver acts as interface between HCI CORE and
- * TI Shared Transport Layer.
- *
- * Copyright (C) 2009 Texas Instruments
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-
-#include <linux/ti_wilink_st.h>
-#include "bt_drv.h"
-
-/* Define this macro to get debug msg */
-#undef DEBUG
-
-#ifdef DEBUG
-#define BT_DRV_DBG(fmt, arg...) printk(KERN_INFO "(btdrv):"fmt"\n" , ## arg)
-#define BTDRV_API_START() printk(KERN_INFO "(btdrv): %s Start\n", \
- __func__)
-#define BTDRV_API_EXIT(errno) printk(KERN_INFO "(btdrv): %s Exit(%d)\n", \
- __func__, errno)
-#else
-#define BT_DRV_DBG(fmt, arg...)
-#define BTDRV_API_START()
-#define BTDRV_API_EXIT(errno)
-#endif
-
-#define BT_DRV_ERR(fmt, arg...) printk(KERN_ERR "(btdrv):"fmt"\n" , ## arg)
-
-static int reset;
-static struct hci_st *hst;
-
-/* Increments HCI counters based on pocket ID (cmd,acl,sco) */
-static inline void hci_st_tx_complete(struct hci_st *hst, int pkt_type)
-{
- struct hci_dev *hdev;
-
- BTDRV_API_START();
-
- hdev = hst->hdev;
-
- /* Update HCI stat counters */
- switch (pkt_type) {
- case HCI_COMMAND_PKT:
- hdev->stat.cmd_tx++;
- break;
-
- case HCI_ACLDATA_PKT:
- hdev->stat.acl_tx++;
- break;
-
- case HCI_SCODATA_PKT:
- hdev->stat.cmd_tx++;
- break;
- }
-
- BTDRV_API_EXIT(0);
-}
-
-/* ------- Interfaces to Shared Transport ------ */
-
-/* Called by ST layer to indicate protocol registration completion
- * status.hci_st_open() function will wait for signal from this
- * API when st_register() function returns ST_PENDING.
- */
-static void hci_st_registration_completion_cb(void *priv_data, char data)
-{
- struct hci_st *lhst = (struct hci_st *)priv_data;
- BTDRV_API_START();
-
- /* hci_st_open() function needs value of 'data' to know
- * the registration status(success/fail),So have a back
- * up of it.
- */
- lhst->streg_cbdata = data;
-
- /* Got a feedback from ST for BT driver registration
- * request.Wackup hci_st_open() function to continue
- * it's open operation.
- */
- complete(&lhst->wait_for_btdrv_reg_completion);
-
- BTDRV_API_EXIT(0);
-}
-
-/* Called by Shared Transport layer when receive data is
- * available */
-static long hci_st_receive(void *priv_data, struct sk_buff *skb)
-{
- int err;
- int len;
- struct hci_st *lhst = (struct hci_st *)priv_data;
-
- BTDRV_API_START();
-
- err = 0;
- len = 0;
-
- if (skb == NULL) {
- BT_DRV_ERR("Invalid SKB received from ST");
- BTDRV_API_EXIT(-EFAULT);
- return -EFAULT;
- }
- if (!lhst) {
- kfree_skb(skb);
- BT_DRV_ERR("Invalid hci_st memory,freeing SKB");
- BTDRV_API_EXIT(-EFAULT);
- return -EFAULT;
- }
- if (!test_bit(BT_DRV_RUNNING, &lhst->flags)) {
- kfree_skb(skb);
- BT_DRV_ERR("Device is not running,freeing SKB");
- BTDRV_API_EXIT(-EINVAL);
- return -EINVAL;
- }
-
- len = skb->len;
- skb->dev = (struct net_device *)lhst->hdev;
-
- /* Forward skb to HCI CORE layer */
- err = hci_recv_frame(skb);
- if (err) {
- kfree_skb(skb);
- BT_DRV_ERR("Unable to push skb to HCI CORE(%d),freeing SKB",
- err);
- BTDRV_API_EXIT(err);
- return err;
- }
- lhst->hdev->stat.byte_rx += len;
-
- BTDRV_API_EXIT(0);
- return 0;
-}
-
-/* ------- Interfaces to HCI layer ------ */
-
-/* Called from HCI core to initialize the device */
-static int hci_st_open(struct hci_dev *hdev)
-{
- static struct st_proto_s hci_st_proto;
- unsigned long timeleft;
- int err;
-
- BTDRV_API_START();
-
- err = 0;
-
- BT_DRV_DBG("%s %p", hdev->name, hdev);
-
- /* Already registered with ST ? */
- if (test_bit(BT_ST_REGISTERED, &hst->flags)) {
- BT_DRV_ERR("Registered with ST already,open called again?");
- BTDRV_API_EXIT(0);
- return 0;
- }
-
- /* Populate BT driver info required by ST */
- memset(&hci_st_proto, 0, sizeof(hci_st_proto));
-
- /* BT driver ID */
- hci_st_proto.type = ST_BT;
-
- /* Receive function which called from ST */
- hci_st_proto.recv = hci_st_receive;
-
- /* Packet match function may used in future */
- hci_st_proto.match_packet = NULL;
-
- /* Callback to be called when registration is pending */
- hci_st_proto.reg_complete_cb = hci_st_registration_completion_cb;
-
- /* This is write function pointer of ST. BT driver will make use of this
- * for sending any packets to chip. ST will assign and give to us, so
- * make it as NULL */
- hci_st_proto.write = NULL;
-
- /* send in the hst to be received at registration complete callback
- * and during st's receive
- */
- hci_st_proto.priv_data = hst;
-
- /* Register with ST layer */
- err = st_register(&hci_st_proto);
- if (err == -EINPROGRESS) {
- /* Prepare wait-for-completion handler data structures.
- * Needed to syncronize this and st_registration_completion_cb()
- * functions.
- */
- init_completion(&hst->wait_for_btdrv_reg_completion);
-
- /* Reset ST registration callback status flag , this value
- * will be updated in hci_st_registration_completion_cb()
- * function whenever it called from ST driver.
- */
- hst->streg_cbdata = -EINPROGRESS;
-
- /* ST is busy with other protocol registration(may be busy with
- * firmware download).So,Wait till the registration callback
- * (passed as a argument to st_register() function) getting
- * called from ST.
- */
- BT_DRV_DBG(" %s waiting for reg completion signal from ST",
- __func__);
-
- timeleft =
- wait_for_completion_timeout
- (&hst->wait_for_btdrv_reg_completion,
- msecs_to_jiffies(BT_REGISTER_TIMEOUT));
- if (!timeleft) {
- BT_DRV_ERR("Timeout(%ld sec),didn't get reg"
- "completion signal from ST",
- BT_REGISTER_TIMEOUT / 1000);
- BTDRV_API_EXIT(-ETIMEDOUT);
- return -ETIMEDOUT;
- }
-
- /* Is ST registration callback called with ERROR value? */
- if (hst->streg_cbdata != 0) {
- BT_DRV_ERR("ST reg completion CB called with invalid"
- "status %d", hst->streg_cbdata);
- BTDRV_API_EXIT(-EAGAIN);
- return -EAGAIN;
- }
- err = 0;
- } else if (err == -1) {
- BT_DRV_ERR("st_register failed %d", err);
- BTDRV_API_EXIT(-EAGAIN);
- return -EAGAIN;
- }
-
- /* Do we have proper ST write function? */
- if (hci_st_proto.write != NULL) {
- /* We need this pointer for sending any Bluetooth pkts */
- hst->st_write = hci_st_proto.write;
- } else {
- BT_DRV_ERR("failed to get ST write func pointer");
-
- /* Undo registration with ST */
- err = st_unregister(ST_BT);
- if (err < 0)
- BT_DRV_ERR("st_unregister failed %d", err);
-
- hst->st_write = NULL;
- BTDRV_API_EXIT(-EAGAIN);
- return -EAGAIN;
- }
-
- /* Registration with ST layer is completed successfully,
- * now chip is ready to accept commands from HCI CORE.
- * Mark HCI Device flag as RUNNING
- */
- set_bit(HCI_RUNNING, &hdev->flags);
-
- /* Registration with ST successful */
- set_bit(BT_ST_REGISTERED, &hst->flags);
-
- BTDRV_API_EXIT(err);
- return err;
-}
-
-/* Close device */
-static int hci_st_close(struct hci_dev *hdev)
-{
- int err;
-
- BTDRV_API_START();
-
- err = 0;
-
- /* Unregister from ST layer */
- if (test_and_clear_bit(BT_ST_REGISTERED, &hst->flags)) {
- err = st_unregister(ST_BT);
- if (err != 0) {
- BT_DRV_ERR("st_unregister failed %d", err);
- BTDRV_API_EXIT(-EBUSY);
- return -EBUSY;
- }
- }
-
- hst->st_write = NULL;
-
- /* ST layer would have moved chip to inactive state.
- * So,clear HCI device RUNNING flag.
- */
- if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) {
- BTDRV_API_EXIT(0);
- return 0;
- }
-
- BTDRV_API_EXIT(err);
- return err;
-}
-
-/* Called from HCI CORE , Sends frames to Shared Transport */
-static int hci_st_send_frame(struct sk_buff *skb)
-{
- struct hci_dev *hdev;
- struct hci_st *hst;
- long len;
-
- BTDRV_API_START();
-
- if (skb == NULL) {
- BT_DRV_ERR("Invalid skb received from HCI CORE");
- BTDRV_API_EXIT(-ENOMEM);
- return -ENOMEM;
- }
- hdev = (struct hci_dev *)skb->dev;
- if (!hdev) {
- BT_DRV_ERR("SKB received for invalid HCI Device (hdev=NULL)");
- BTDRV_API_EXIT(-ENODEV);
- return -ENODEV;
- }
- if (!test_bit(HCI_RUNNING, &hdev->flags)) {
- BT_DRV_ERR("Device is not running");
- BTDRV_API_EXIT(-EBUSY);
- return -EBUSY;
- }
-
- hst = (struct hci_st *)hdev->driver_data;
-
- /* Prepend skb with frame type */
- memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
-
- BT_DRV_DBG(" %s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type,
- skb->len);
-
- /* Insert skb to shared transport layer's transmit queue.
- * Freeing skb memory is taken care in shared transport layer,
- * so don't free skb memory here.
- */
- if (!hst->st_write) {
- kfree_skb(skb);
- BT_DRV_ERR(" Can't write to ST, st_write null?");
- BTDRV_API_EXIT(-EAGAIN);
- return -EAGAIN;
- }
- len = hst->st_write(skb);
- if (len < 0) {
- /* Something went wrong in st write , free skb memory */
- kfree_skb(skb);
- BT_DRV_ERR(" ST write failed (%ld)", len);
- BTDRV_API_EXIT(-EAGAIN);
- return -EAGAIN;
- }
-
- /* ST accepted our skb. So, Go ahead and do rest */
- hdev->stat.byte_tx += len;
- hci_st_tx_complete(hst, bt_cb(skb)->pkt_type);
-
- BTDRV_API_EXIT(0);
- return 0;
-}
-
-static void hci_st_destruct(struct hci_dev *hdev)
-{
- BTDRV_API_START();
-
- if (!hdev) {
- BT_DRV_ERR("Destruct called with invalid HCI Device"
- "(hdev=NULL)");
- BTDRV_API_EXIT(0);
- return;
- }
-
- BT_DRV_DBG("%s", hdev->name);
-
- /* free hci_st memory */
- if (hdev->driver_data != NULL)
- kfree(hdev->driver_data);
-
- BTDRV_API_EXIT(0);
- return;
-}
-
-/* Creates new HCI device */
-static int hci_st_register_dev(struct hci_st *hst)
-{
- struct hci_dev *hdev;
-
- BTDRV_API_START();
-
- /* Initialize and register HCI device */
- hdev = hci_alloc_dev();
- if (!hdev) {
- BT_DRV_ERR("Can't allocate HCI device");
- BTDRV_API_EXIT(-ENOMEM);
- return -ENOMEM;
- }
- BT_DRV_DBG(" HCI device allocated. hdev= %p", hdev);
-
- hst->hdev = hdev;
- hdev->bus = HCI_UART;
- hdev->driver_data = hst;
- hdev->open = hci_st_open;
- hdev->close = hci_st_close;
- hdev->flush = NULL;
- hdev->send = hci_st_send_frame;
- hdev->destruct = hci_st_destruct;
- hdev->owner = THIS_MODULE;
-
- if (reset)
- set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
-
- if (hci_register_dev(hdev) < 0) {
- BT_DRV_ERR("Can't register HCI device");
- hci_free_dev(hdev);
- BTDRV_API_EXIT(-ENODEV);
- return -ENODEV;
- }
-
- BT_DRV_DBG(" HCI device registered. hdev= %p", hdev);
- BTDRV_API_EXIT(0);
- return 0;
-}
-
-/* ------- Module Init interface ------ */
-
-static int __init bt_drv_init(void)
-{
- int err;
-
- BTDRV_API_START();
-
- err = 0;
-
- BT_DRV_DBG(" Bluetooth Driver Version %s", VERSION);
-
- /* Allocate local resource memory */
- hst = kzalloc(sizeof(struct hci_st), GFP_KERNEL);
- if (!hst) {
- BT_DRV_ERR("Can't allocate control structure");
- BTDRV_API_EXIT(-ENFILE);
- return -ENFILE;
- }
-
- /* Expose "hciX" device to user space */
- err = hci_st_register_dev(hst);
- if (err) {
- /* Release local resource memory */
- kfree(hst);
-
- BT_DRV_ERR("Unable to expose hci0 device(%d)", err);
- BTDRV_API_EXIT(err);
- return err;
- }
- set_bit(BT_DRV_RUNNING, &hst->flags);
-
- BTDRV_API_EXIT(err);
- return err;
-}
-
-/* ------- Module Exit interface ------ */
-
-static void __exit bt_drv_exit(void)
-{
- BTDRV_API_START();
-
- /* Deallocate local resource's memory */
- if (hst) {
- struct hci_dev *hdev = hst->hdev;
-
- if (hdev == NULL) {
- BT_DRV_ERR("Invalid hdev memory");
- kfree(hst);
- } else {
- hci_st_close(hdev);
- if (test_and_clear_bit(BT_DRV_RUNNING, &hst->flags)) {
- /* Remove HCI device (hciX) created
- * in module init.
- */
- hci_unregister_dev(hdev);
-
- /* Free HCI device memory */
- hci_free_dev(hdev);
- }
- }
- }
- BTDRV_API_EXIT(0);
-}
-
-module_init(bt_drv_init);
-module_exit(bt_drv_exit);
-
-/* ------ Module Info ------ */
-
-module_param(reset, bool, 0644);
-MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");
-MODULE_AUTHOR("Raja Mani <raja_mani@ti.com>");
-MODULE_DESCRIPTION("Bluetooth Driver for TI Shared Transport" VERSION);
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/ti-st/bt_drv.h b/drivers/staging/ti-st/bt_drv.h
deleted file mode 100644
index a0beebec846..00000000000
--- a/drivers/staging/ti-st/bt_drv.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Texas Instrument's Bluetooth Driver For Shared Transport.
- *
- * Bluetooth Driver acts as interface between HCI CORE and
- * TI Shared Transport Layer.
- *
- * Copyright (C) 2009 Texas Instruments
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#ifndef _BT_DRV_H
-#define _BT_DRV_H
-
-/* Bluetooth Driver Version */
-#define VERSION "1.0"
-
-/* Defines number of seconds to wait for reg completion
- * callback getting called from ST (in case,registration
- * with ST returns PENDING status)
- */
-#define BT_REGISTER_TIMEOUT msecs_to_jiffies(6000) /* 6 sec */
-
-/* BT driver's local status */
-#define BT_DRV_RUNNING 0
-#define BT_ST_REGISTERED 1
-
-/* BT driver operation structure */
-struct hci_st {
-
- /* hci device pointer which binds to bt driver */
- struct hci_dev *hdev;
-
- /* used locally,to maintain various BT driver status */
- unsigned long flags;
-
- /* to hold ST registration callback status */
- char streg_cbdata;
-
- /* write function pointer of ST driver */
- long (*st_write) (struct sk_buff *);
-
- /* Wait on comepletion handler needed to synchronize
- * hci_st_open() and hci_st_registration_completion_cb()
- * functions.*/
- struct completion wait_for_btdrv_reg_completion;
-};
-
-#endif
diff --git a/drivers/staging/ti-st/sysfs-uim b/drivers/staging/ti-st/sysfs-uim
deleted file mode 100644
index 626bda51ee8..00000000000
--- a/drivers/staging/ti-st/sysfs-uim
+++ /dev/null
@@ -1,28 +0,0 @@
-What: /sys/class/rfkill/rfkill%d/
-Date: March 22
-Contact: Pavan Savoy <pavan_savoy@ti.com>
-Description:
- Creates the rfkill entries for Radio apps like
- BT app, FM app or GPS app to toggle corresponding
- cores of the chip
-
-What: /dev/rfkill
-Date: March 22
-Contact: Pavan Savoy <pavan_savoy@ti.com>
-Description:
- A daemon which maintains the ldisc installation and
- uninstallation would be ppolling on this device and listening
- on events which would suggest either to install or un-install
- line discipline
-
-What: /sys/kernel/debug/ti-st/version
-Contact: Pavan Savoy <pavan_savoy@ti.com>
-Description:
- WiLink chip's ROM version exposed to user-space for some
- proprietary protocol stacks to make use of.
-
-What: /sys/kernel/debug/ti-st/protocols
-Contact: Pavan Savoy <pavan_savoy@ti.com>
-Description:
- The reason for chip being ON, the list of protocols registered.
-
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index a6d3f2ffe81..c2915133291 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -555,7 +555,6 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
musb->ep0_stage = MUSB_EP0_START;
musb->xceiv->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
- musb_platform_set_vbus(musb, 1);
handled = IRQ_HANDLED;
}
@@ -848,12 +847,16 @@ b_host:
DBG(1, "HNP: in %s, %d msec timeout\n",
otg_state_string(musb),
TA_WAIT_BCON(musb));
+#ifdef CONFIG_USB_MUSB_OTG
mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies(TA_WAIT_BCON(musb)));
+#endif
break;
case OTG_STATE_A_PERIPHERAL:
musb->ignore_disconnect = 0;
+#ifdef CONFIG_USB_MUSB_OTG
del_timer(&musb->otg_timer);
+#endif
musb_g_reset(musb);
break;
case OTG_STATE_B_WAIT_ACON:
@@ -1729,6 +1732,8 @@ musb_mode_store(struct device *dev, struct device_attribute *attr,
unsigned long flags;
int status;
+ pm_runtime_get_sync(musb->controller);
+
spin_lock_irqsave(&musb->lock, flags);
if (sysfs_streq(buf, "host"))
status = musb_platform_set_mode(musb, MUSB_HOST);
@@ -1740,6 +1745,8 @@ musb_mode_store(struct device *dev, struct device_attribute *attr,
status = -EINVAL;
spin_unlock_irqrestore(&musb->lock, flags);
+ pm_runtime_put_sync(musb->controller);
+
return (status == 0) ? n : status;
}
static DEVICE_ATTR(mode, 0644, musb_mode_show, musb_mode_store);
@@ -1837,6 +1844,9 @@ static void musb_irq_work(struct work_struct *data)
struct musb *musb = container_of(data, struct musb, irq_work);
static int old_state;
+ if(musb->xceiv->state = OTG_STATE_A_IDLE)
+ musb_platform_set_vbus(musb, 1);
+
if (musb->xceiv->state != old_state) {
old_state = musb->xceiv->state;
sysfs_notify(&musb->controller->kobj, NULL, "mode");
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 25cb8b0003b..50d2694409d 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -259,8 +259,10 @@ static int musb_otg_notifications(struct notifier_block *nb,
case USB_EVENT_VBUS:
DBG(4, "VBUS Connect\n");
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
if (musb->gadget_driver)
pm_runtime_get_sync(musb->controller);
+#endif
otg_init(musb->xceiv);
break;
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
index bfc5da0e970..5c299d5552c 100644
--- a/drivers/video/omap2/dss/Kconfig
+++ b/drivers/video/omap2/dss/Kconfig
@@ -56,6 +56,7 @@ config OMAP2_DSS_RFBI
config OMAP2_DSS_VENC
bool "VENC support"
+ depends on BROKEN
default y
help
OMAP Video Encoder support for S-Video and composite TV-out.
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 1aa2ed1e786..19075085f96 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -491,6 +491,9 @@ int omap_dss_register_device(struct omap_dss_device *dssdev)
dssdev->dev.parent = &dss_bus;
dssdev->dev.release = omap_dss_dev_release;
dev_set_name(&dssdev->dev, "display%d", dev_num++);
+
+ BLOCKING_INIT_NOTIFIER_HEAD(&dssdev->notifier);
+
return device_register(&dssdev->dev);
}
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 7804779c9da..abfe4b0bbdb 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -128,6 +128,16 @@ struct dispc_reg { u16 idx; };
#define DISPC_VID_PRELOAD(n) DISPC_REG(0x230 + (n)*0x04)
+/*
+ * The OMAP4 DISPC_DIVISOR1 is backward compatible to OMAP3xxx DISPC_DIVISOR.
+ * However DISPC_DIVISOR is also provided in OMAP4, to control DISPC_CORE_CLK.
+ * This allows DISPC_CORE_CLK to be independent of logical clock dividers (lcd)
+ * of LCD1 (primary) and LCD2 (secondary) displays.
+ *
+ * To derive pixel clocks for Primary and Secondary LCD channels, configure the
+ * lcd and pcd in DISPC_DIVISOR1 and DISPC_DIVISOR2 respectively, using the
+ * DISPC_DIVISORo(ch).
+ */
#define DISPC_DIVISOR DISPC_REG(0x0804)
#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index a85a6f38b40..fa9df604387 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <plat/display.h>
#include "dss.h"
@@ -614,3 +615,51 @@ void omap_dss_stop_device(struct omap_dss_device *dssdev)
}
EXPORT_SYMBOL(omap_dss_stop_device);
+/* since omap_dss_update_size can be called in irq context, schedule work from
+ * work-queue to deliver notification to client..
+ */
+struct notify_work {
+ struct work_struct work;
+ struct omap_dss_device *dssdev;
+ enum omap_dss_event evt;
+};
+
+static void notify_worker(struct work_struct *work)
+{
+ struct notify_work *nw =
+ container_of(work, struct notify_work, work);
+ struct omap_dss_device *dssdev = nw->dssdev;
+ blocking_notifier_call_chain(&dssdev->notifier, nw->evt, dssdev);
+ kfree(work);
+}
+
+/**
+ * Called by lower level driver to notify about a change in resolution, etc.
+ */
+void omap_dss_notify(struct omap_dss_device *dssdev, enum omap_dss_event evt)
+{
+ struct notify_work *nw =
+ kmalloc(sizeof(struct notify_work), GFP_KERNEL);
+ if (nw) {
+ INIT_WORK(&nw->work, notify_worker);
+ nw->dssdev = dssdev;
+ nw->evt = evt;
+ schedule_work(&nw->work);
+ }
+}
+EXPORT_SYMBOL(omap_dss_notify);
+
+void omap_dss_add_notify(struct omap_dss_device *dssdev,
+ struct notifier_block *nb)
+{
+ blocking_notifier_chain_register(&dssdev->notifier, nb);
+}
+EXPORT_SYMBOL(omap_dss_add_notify);
+
+void omap_dss_remove_notify(struct omap_dss_device *dssdev,
+ struct notifier_block *nb)
+{
+ blocking_notifier_chain_unregister(&dssdev->notifier, nb);
+}
+EXPORT_SYMBOL(omap_dss_remove_notify);
+
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index e9b734ccb1a..0b943f68979 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -190,11 +190,19 @@ typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
#define DSI_MAX_NR_ISRS 2
struct dsi_isr_data {
- omap_dsi_isr_t isr;
- void *arg;
- u32 mask;
+ omap_dsi_isr_t isr;
+ void *arg;
+ u32 mask;
};
+#define FINT_MAX 2100000
+#define FINT_MIN 750000
+#define REGN_MAX (1 << 7)
+#define REGM_MAX ((1 << 11) - 1)
+#define REGM_DISPC_MAX (1 << 4)
+#define REGM_DSI_MAX (1 << 4)
+#define LP_DIV_MAX ((1 << 13) - 1)
+
enum fifo_size {
DSI_FIFO_SIZE_0 = 0,
DSI_FIFO_SIZE_32 = 1,
@@ -249,10 +257,8 @@ static struct
unsigned pll_locked;
- spinlock_t irq_lock;
- struct dsi_isr_tables isr_tables;
- /* space for a copy used by the interrupt handler */
- struct dsi_isr_tables isr_tables_copy;
+ struct completion bta_completion;
+ void (*bta_callback)(void);
int update_channel;
struct dsi_update_region update_region;
@@ -287,11 +293,6 @@ static struct
spinlock_t irq_stats_lock;
struct dsi_irq_stats irq_stats;
#endif
- /* DSI PLL Parameter Ranges */
- unsigned long regm_max, regn_max;
- unsigned long regm_dispc_max, regm_dsi_max;
- unsigned long fint_min, fint_max;
- unsigned long lpdiv_max;
} dsi;
#ifdef DEBUG
@@ -335,11 +336,6 @@ static bool dsi_bus_is_locked(void)
return dsi.bus_lock.count == 0;
}
-static void dsi_completion_handler(void *data, u32 mask)
-{
- complete((struct completion *)data);
-}
-
static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
int value)
{
@@ -409,9 +405,6 @@ static void dsi_perf_show(const char *name)
static void print_irq_status(u32 status)
{
- if (status == 0)
- return;
-
#ifndef VERBOSE_IRQ
if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0)
return;
@@ -447,9 +440,6 @@ static void print_irq_status(u32 status)
static void print_irq_status_vc(int channel, u32 status)
{
- if (status == 0)
- return;
-
#ifndef VERBOSE_IRQ
if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
return;
@@ -509,33 +499,26 @@ static void print_irq_status_cio(u32 status)
printk("\n");
}
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-static void dsi_collect_irq_stats(u32 irqstatus, u32 *vcstatus, u32 ciostatus)
+static int debug_irq;
+
+/* called from dss */
+static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
{
+ u32 irqstatus, vcstatus, ciostatus;
int i;
- spin_lock(&dsi.irq_stats_lock);
+ irqstatus = dsi_read_reg(DSI_IRQSTATUS);
+
+ /* IRQ is not for us */
+ if (!irqstatus)
+ return IRQ_NONE;
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
+ spin_lock(&dsi.irq_stats_lock);
dsi.irq_stats.irq_count++;
dss_collect_irq_stats(irqstatus, dsi.irq_stats.dsi_irqs);
-
- for (i = 0; i < 4; ++i)
- dss_collect_irq_stats(vcstatus[i], dsi.irq_stats.vc_irqs[i]);
-
- dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs);
-
- spin_unlock(&dsi.irq_stats_lock);
-}
-#else
-#define dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus)
#endif
-static int debug_irq;
-
-static void dsi_handle_irq_errors(u32 irqstatus, u32 *vcstatus, u32 ciostatus)
-{
- int i;
-
if (irqstatus & DSI_IRQ_ERROR_MASK) {
DSSERR("DSI error, irqstatus %x\n", irqstatus);
print_irq_status(irqstatus);
@@ -546,88 +529,37 @@ static void dsi_handle_irq_errors(u32 irqstatus, u32 *vcstatus, u32 ciostatus)
print_irq_status(irqstatus);
}
- for (i = 0; i < 4; ++i) {
- if (vcstatus[i] & DSI_VC_IRQ_ERROR_MASK) {
- DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
- i, vcstatus[i]);
- print_irq_status_vc(i, vcstatus[i]);
- } else if (debug_irq) {
- print_irq_status_vc(i, vcstatus[i]);
- }
- }
-
- if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
- DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
- print_irq_status_cio(ciostatus);
- } else if (debug_irq) {
- print_irq_status_cio(ciostatus);
- }
-}
-
-static void dsi_call_isrs(struct dsi_isr_data *isr_array,
- unsigned isr_array_size, u32 irqstatus)
-{
- struct dsi_isr_data *isr_data;
- int i;
-
- for (i = 0; i < isr_array_size; i++) {
- isr_data = &isr_array[i];
- if (isr_data->isr && isr_data->mask & irqstatus)
- isr_data->isr(isr_data->arg, irqstatus);
- }
-}
-
-static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables,
- u32 irqstatus, u32 *vcstatus, u32 ciostatus)
-{
- int i;
-
- dsi_call_isrs(isr_tables->isr_table,
- ARRAY_SIZE(isr_tables->isr_table),
- irqstatus);
+#ifdef DSI_CATCH_MISSING_TE
+ if (irqstatus & DSI_IRQ_TE_TRIGGER)
+ del_timer(&dsi.te_timer);
+#endif
for (i = 0; i < 4; ++i) {
- if (vcstatus[i] == 0)
+ if ((irqstatus & (1<<i)) == 0)
continue;
- dsi_call_isrs(isr_tables->isr_table_vc[i],
- ARRAY_SIZE(isr_tables->isr_table_vc[i]),
- vcstatus[i]);
- }
- if (ciostatus != 0)
- dsi_call_isrs(isr_tables->isr_table_cio,
- ARRAY_SIZE(isr_tables->isr_table_cio),
- ciostatus);
-}
+ vcstatus = dsi_read_reg(DSI_VC_IRQSTATUS(i));
-static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
-{
- u32 irqstatus, vcstatus[4], ciostatus;
- int i;
-
- spin_lock(&dsi.irq_lock);
-
- irqstatus = dsi_read_reg(DSI_IRQSTATUS);
-
- /* IRQ is not for us */
- if (!irqstatus) {
- spin_unlock(&dsi.irq_lock);
- return IRQ_NONE;
- }
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
+ dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]);
+#endif
- dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
- /* flush posted write */
- dsi_read_reg(DSI_IRQSTATUS);
+ if (vcstatus & DSI_VC_IRQ_BTA) {
+ complete(&dsi.bta_completion);
- for (i = 0; i < 4; ++i) {
- if ((irqstatus & (1 << i)) == 0) {
- vcstatus[i] = 0;
- continue;
+ if (dsi.bta_callback)
+ dsi.bta_callback();
}
- vcstatus[i] = dsi_read_reg(DSI_VC_IRQSTATUS(i));
+ if (vcstatus & DSI_VC_IRQ_ERROR_MASK) {
+ DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
+ i, vcstatus);
+ print_irq_status_vc(i, vcstatus);
+ } else if (debug_irq) {
+ print_irq_status_vc(i, vcstatus);
+ }
- dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus[i]);
+ dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus);
/* flush posted write */
dsi_read_reg(DSI_VC_IRQSTATUS(i));
}
@@ -635,289 +567,99 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
+ dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs);
+#endif
+
dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
/* flush posted write */
dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
- } else {
- ciostatus = 0;
- }
-
-#ifdef DSI_CATCH_MISSING_TE
- if (irqstatus & DSI_IRQ_TE_TRIGGER)
- del_timer(&dsi.te_timer);
-#endif
-
- /* make a copy and unlock, so that isrs can unregister
- * themselves */
- memcpy(&dsi.isr_tables_copy, &dsi.isr_tables, sizeof(dsi.isr_tables));
-
- spin_unlock(&dsi.irq_lock);
- dsi_handle_isrs(&dsi.isr_tables_copy, irqstatus, vcstatus, ciostatus);
-
- dsi_handle_irq_errors(irqstatus, vcstatus, ciostatus);
-
- dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus);
-
- return IRQ_HANDLED;
-}
-
-/* dsi.irq_lock has to be locked by the caller */
-static void _omap_dsi_configure_irqs(struct dsi_isr_data *isr_array,
- unsigned isr_array_size, u32 default_mask,
- const struct dsi_reg enable_reg,
- const struct dsi_reg status_reg)
-{
- struct dsi_isr_data *isr_data;
- u32 mask;
- u32 old_mask;
- int i;
-
- mask = default_mask;
-
- for (i = 0; i < isr_array_size; i++) {
- isr_data = &isr_array[i];
-
- if (isr_data->isr == NULL)
- continue;
-
- mask |= isr_data->mask;
+ if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
+ DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
+ print_irq_status_cio(ciostatus);
+ } else if (debug_irq) {
+ print_irq_status_cio(ciostatus);
+ }
}
- old_mask = dsi_read_reg(enable_reg);
- /* clear the irqstatus for newly enabled irqs */
- dsi_write_reg(status_reg, (mask ^ old_mask) & mask);
- dsi_write_reg(enable_reg, mask);
-
- /* flush posted writes */
- dsi_read_reg(enable_reg);
- dsi_read_reg(status_reg);
-}
+ dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
+ /* flush posted write */
+ dsi_read_reg(DSI_IRQSTATUS);
-/* dsi.irq_lock has to be locked by the caller */
-static void _omap_dsi_set_irqs(void)
-{
- u32 mask = DSI_IRQ_ERROR_MASK;
-#ifdef DSI_CATCH_MISSING_TE
- mask |= DSI_IRQ_TE_TRIGGER;
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
+ spin_unlock(&dsi.irq_stats_lock);
#endif
- _omap_dsi_configure_irqs(dsi.isr_tables.isr_table,
- ARRAY_SIZE(dsi.isr_tables.isr_table), mask,
- DSI_IRQENABLE, DSI_IRQSTATUS);
-}
-
-/* dsi.irq_lock has to be locked by the caller */
-static void _omap_dsi_set_irqs_vc(int vc)
-{
- _omap_dsi_configure_irqs(dsi.isr_tables.isr_table_vc[vc],
- ARRAY_SIZE(dsi.isr_tables.isr_table_vc[vc]),
- DSI_VC_IRQ_ERROR_MASK,
- DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc));
-}
-
-/* dsi.irq_lock has to be locked by the caller */
-static void _omap_dsi_set_irqs_cio(void)
-{
- _omap_dsi_configure_irqs(dsi.isr_tables.isr_table_cio,
- ARRAY_SIZE(dsi.isr_tables.isr_table_cio),
- DSI_CIO_IRQ_ERROR_MASK,
- DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS);
+ return IRQ_HANDLED;
}
static void _dsi_initialize_irq(void)
{
- unsigned long flags;
- int vc;
-
- spin_lock_irqsave(&dsi.irq_lock, flags);
-
- memset(&dsi.isr_tables, 0, sizeof(dsi.isr_tables));
-
- _omap_dsi_set_irqs();
- for (vc = 0; vc < 4; ++vc)
- _omap_dsi_set_irqs_vc(vc);
- _omap_dsi_set_irqs_cio();
-
- spin_unlock_irqrestore(&dsi.irq_lock, flags);
-}
-
-static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
- struct dsi_isr_data *isr_array, unsigned isr_array_size)
-{
- struct dsi_isr_data *isr_data;
- int free_idx;
- int i;
-
- BUG_ON(isr == NULL);
-
- /* check for duplicate entry and find a free slot */
- free_idx = -1;
- for (i = 0; i < isr_array_size; i++) {
- isr_data = &isr_array[i];
-
- if (isr_data->isr == isr && isr_data->arg == arg &&
- isr_data->mask == mask) {
- return -EINVAL;
- }
-
- if (isr_data->isr == NULL && free_idx == -1)
- free_idx = i;
- }
-
- if (free_idx == -1)
- return -EBUSY;
-
- isr_data = &isr_array[free_idx];
- isr_data->isr = isr;
- isr_data->arg = arg;
- isr_data->mask = mask;
-
- return 0;
-}
-
-static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
- struct dsi_isr_data *isr_array, unsigned isr_array_size)
-{
- struct dsi_isr_data *isr_data;
+ u32 l;
int i;
- for (i = 0; i < isr_array_size; i++) {
- isr_data = &isr_array[i];
- if (isr_data->isr != isr || isr_data->arg != arg ||
- isr_data->mask != mask)
- continue;
+ /* disable all interrupts */
+ dsi_write_reg(DSI_IRQENABLE, 0);
+ for (i = 0; i < 4; ++i)
+ dsi_write_reg(DSI_VC_IRQENABLE(i), 0);
+ dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, 0);
- isr_data->isr = NULL;
- isr_data->arg = NULL;
- isr_data->mask = 0;
+ /* clear interrupt status */
+ l = dsi_read_reg(DSI_IRQSTATUS);
+ dsi_write_reg(DSI_IRQSTATUS, l & ~DSI_IRQ_CHANNEL_MASK);
- return 0;
+ for (i = 0; i < 4; ++i) {
+ l = dsi_read_reg(DSI_VC_IRQSTATUS(i));
+ dsi_write_reg(DSI_VC_IRQSTATUS(i), l);
}
- return -EINVAL;
-}
-
-static int dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask)
-{
- unsigned long flags;
- int r;
-
- spin_lock_irqsave(&dsi.irq_lock, flags);
-
- r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table,
- ARRAY_SIZE(dsi.isr_tables.isr_table));
-
- if (r == 0)
- _omap_dsi_set_irqs();
-
- spin_unlock_irqrestore(&dsi.irq_lock, flags);
+ l = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
+ dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, l);
- return r;
-}
-
-static int dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask)
-{
- unsigned long flags;
- int r;
-
- spin_lock_irqsave(&dsi.irq_lock, flags);
-
- r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table,
- ARRAY_SIZE(dsi.isr_tables.isr_table));
-
- if (r == 0)
- _omap_dsi_set_irqs();
-
- spin_unlock_irqrestore(&dsi.irq_lock, flags);
-
- return r;
-}
-
-static int dsi_register_isr_vc(int channel, omap_dsi_isr_t isr, void *arg,
- u32 mask)
-{
- unsigned long flags;
- int r;
-
- spin_lock_irqsave(&dsi.irq_lock, flags);
-
- r = _dsi_register_isr(isr, arg, mask,
- dsi.isr_tables.isr_table_vc[channel],
- ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel]));
-
- if (r == 0)
- _omap_dsi_set_irqs_vc(channel);
+ /* enable error irqs */
+ l = DSI_IRQ_ERROR_MASK;
+#ifdef DSI_CATCH_MISSING_TE
+ l |= DSI_IRQ_TE_TRIGGER;
+#endif
+ dsi_write_reg(DSI_IRQENABLE, l);
- spin_unlock_irqrestore(&dsi.irq_lock, flags);
+ l = DSI_VC_IRQ_ERROR_MASK;
+ for (i = 0; i < 4; ++i)
+ dsi_write_reg(DSI_VC_IRQENABLE(i), l);
- return r;
+ l = DSI_CIO_IRQ_ERROR_MASK;
+ dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, l);
}
-static int dsi_unregister_isr_vc(int channel, omap_dsi_isr_t isr, void *arg,
- u32 mask)
+static u32 dsi_get_errors(void)
{
unsigned long flags;
- int r;
-
- spin_lock_irqsave(&dsi.irq_lock, flags);
-
- r = _dsi_unregister_isr(isr, arg, mask,
- dsi.isr_tables.isr_table_vc[channel],
- ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel]));
-
- if (r == 0)
- _omap_dsi_set_irqs_vc(channel);
-
- spin_unlock_irqrestore(&dsi.irq_lock, flags);
-
- return r;
+ u32 e;
+ spin_lock_irqsave(&dsi.errors_lock, flags);
+ e = dsi.errors;
+ dsi.errors = 0;
+ spin_unlock_irqrestore(&dsi.errors_lock, flags);
+ return e;
}
-static int dsi_register_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask)
+static void dsi_vc_enable_bta_irq(int channel)
{
- unsigned long flags;
- int r;
-
- spin_lock_irqsave(&dsi.irq_lock, flags);
-
- r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio,
- ARRAY_SIZE(dsi.isr_tables.isr_table_cio));
-
- if (r == 0)
- _omap_dsi_set_irqs_cio();
+ u32 l;
- spin_unlock_irqrestore(&dsi.irq_lock, flags);
+ dsi_write_reg(DSI_VC_IRQSTATUS(channel), DSI_VC_IRQ_BTA);
- return r;
+ l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
+ l |= DSI_VC_IRQ_BTA;
+ dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
}
-static int dsi_unregister_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask)
+static void dsi_vc_disable_bta_irq(int channel)
{
- unsigned long flags;
- int r;
-
- spin_lock_irqsave(&dsi.irq_lock, flags);
-
- r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio,
- ARRAY_SIZE(dsi.isr_tables.isr_table_cio));
-
- if (r == 0)
- _omap_dsi_set_irqs_cio();
-
- spin_unlock_irqrestore(&dsi.irq_lock, flags);
-
- return r;
-}
+ u32 l;
-static u32 dsi_get_errors(void)
-{
- unsigned long flags;
- u32 e;
- spin_lock_irqsave(&dsi.errors_lock, flags);
- e = dsi.errors;
- dsi.errors = 0;
- spin_unlock_irqrestore(&dsi.errors_lock, flags);
- return e;
+ l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
+ l &= ~DSI_VC_IRQ_BTA;
+ dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
}
/* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */
@@ -1028,7 +770,7 @@ static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
lp_clk_div = dssdev->phy.dsi.div.lp_clk_div;
- if (lp_clk_div == 0 || lp_clk_div > dsi.lpdiv_max)
+ if (lp_clk_div == 0 || lp_clk_div > LP_DIV_MAX)
return -EINVAL;
dsi_fclk = dsi_fclk_rate();
@@ -1078,16 +820,16 @@ static int dsi_pll_power(enum dsi_pll_power_state state)
static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
struct dsi_clock_info *cinfo)
{
- if (cinfo->regn == 0 || cinfo->regn > dsi.regn_max)
+ if (cinfo->regn == 0 || cinfo->regn > REGN_MAX)
return -EINVAL;
- if (cinfo->regm == 0 || cinfo->regm > dsi.regm_max)
+ if (cinfo->regm == 0 || cinfo->regm > REGM_MAX)
return -EINVAL;
- if (cinfo->regm_dispc > dsi.regm_dispc_max)
+ if (cinfo->regm_dispc > REGM_DISPC_MAX)
return -EINVAL;
- if (cinfo->regm_dsi > dsi.regm_dsi_max)
+ if (cinfo->regm_dsi > REGM_DSI_MAX)
return -EINVAL;
if (cinfo->use_sys_clk) {
@@ -1106,7 +848,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1));
- if (cinfo->fint > dsi.fint_max || cinfo->fint < dsi.fint_min)
+ if (cinfo->fint > FINT_MAX || cinfo->fint < FINT_MIN)
return -EINVAL;
cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint;
@@ -1141,7 +883,7 @@ int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
dss_sys_clk = dss_clk_get_rate(DSS_CLK_SYSCK);
- max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
+ max_dss_fck = dss_feat_get_max_dss_fck();
if (req_pck == dsi.cache_req_pck &&
dsi.cache_cinfo.clkin == dss_sys_clk) {
@@ -1176,17 +918,17 @@ retry:
/* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */
/* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */
/* To reduce PLL lock time, keep Fint high (around 2 MHz) */
- for (cur.regn = 1; cur.regn < dsi.regn_max; ++cur.regn) {
+ for (cur.regn = 1; cur.regn < REGN_MAX; ++cur.regn) {
if (cur.highfreq == 0)
cur.fint = cur.clkin / cur.regn;
else
cur.fint = cur.clkin / (2 * cur.regn);
- if (cur.fint > dsi.fint_max || cur.fint < dsi.fint_min)
+ if (cur.fint > FINT_MAX || cur.fint < FINT_MIN)
continue;
/* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */
- for (cur.regm = 1; cur.regm < dsi.regm_max; ++cur.regm) {
+ for (cur.regm = 1; cur.regm < REGM_MAX; ++cur.regm) {
unsigned long a, b;
a = 2 * cur.regm * (cur.clkin/1000);
@@ -1198,7 +940,7 @@ retry:
/* dsi_pll_hsdiv_dispc_clk(MHz) =
* DSIPHY(MHz) / regm_dispc < 173MHz/186Mhz */
- for (cur.regm_dispc = 1; cur.regm_dispc < dsi.regm_dispc_max;
+ for (cur.regm_dispc = 1; cur.regm_dispc < REGM_DISPC_MAX;
++cur.regm_dispc) {
struct dispc_clock_info cur_dispc;
cur.dsi_pll_hsdiv_dispc_clk =
@@ -1270,9 +1012,7 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
{
int r = 0;
u32 l;
- int f = 0;
- u8 regn_start, regn_end, regm_start, regm_end;
- u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end;
+ int f;
DSSDBGF();
@@ -1317,43 +1057,32 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
cinfo->dsi_pll_hsdiv_dsi_clk);
- dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGN, &regn_start, &regn_end);
- dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM, &regm_start, &regm_end);
- dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DISPC, &regm_dispc_start,
- &regm_dispc_end);
- dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DSI, &regm_dsi_start,
- &regm_dsi_end);
-
REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */
l = dsi_read_reg(DSI_PLL_CONFIGURATION1);
l = FLD_MOD(l, 1, 0, 0); /* DSI_PLL_STOPMODE */
- /* DSI_PLL_REGN */
- l = FLD_MOD(l, cinfo->regn - 1, regn_start, regn_end);
- /* DSI_PLL_REGM */
- l = FLD_MOD(l, cinfo->regm, regm_start, regm_end);
- /* DSI_CLOCK_DIV */
+ l = FLD_MOD(l, cinfo->regn - 1, 7, 1); /* DSI_PLL_REGN */
+ l = FLD_MOD(l, cinfo->regm, 18, 8); /* DSI_PLL_REGM */
l = FLD_MOD(l, cinfo->regm_dispc > 0 ? cinfo->regm_dispc - 1 : 0,
- regm_dispc_start, regm_dispc_end);
- /* DSIPROTO_CLOCK_DIV */
+ 22, 19); /* DSI_CLOCK_DIV */
l = FLD_MOD(l, cinfo->regm_dsi > 0 ? cinfo->regm_dsi - 1 : 0,
- regm_dsi_start, regm_dsi_end);
+ 26, 23); /* DSIPROTO_CLOCK_DIV */
dsi_write_reg(DSI_PLL_CONFIGURATION1, l);
- BUG_ON(cinfo->fint < dsi.fint_min || cinfo->fint > dsi.fint_max);
-
- if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) {
- f = cinfo->fint < 1000000 ? 0x3 :
- cinfo->fint < 1250000 ? 0x4 :
- cinfo->fint < 1500000 ? 0x5 :
- cinfo->fint < 1750000 ? 0x6 :
- 0x7;
- }
+ BUG_ON(cinfo->fint < 750000 || cinfo->fint > 2100000);
+ if (cinfo->fint < 1000000)
+ f = 0x3;
+ else if (cinfo->fint < 1250000)
+ f = 0x4;
+ else if (cinfo->fint < 1500000)
+ f = 0x5;
+ else if (cinfo->fint < 1750000)
+ f = 0x6;
+ else
+ f = 0x7;
l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
-
- if (dss_has_feature(FEAT_DSI_PLL_FREQSEL))
- l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */
+ l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */
l = FLD_MOD(l, cinfo->use_sys_clk ? 0 : 1,
11, 11); /* DSI_PLL_CLKSEL */
l = FLD_MOD(l, cinfo->highfreq,
@@ -1873,6 +1602,9 @@ static int dsi_complexio_init(struct omap_dss_device *dssdev)
DSSDBG("dsi_complexio_init\n");
+ /* CIO_CLK_ICG, enable L3 clk to CIO */
+ REG_FLD_MOD(DSI_CLK_CTRL, 1, 14, 14);
+
/* A dummy read using the SCP interface to any DSIPHY register is
* required after DSIPHY reset to complete the reset of the DSI complex
* I/O. */
@@ -1897,12 +1629,10 @@ static int dsi_complexio_init(struct omap_dss_device *dssdev)
goto err;
}
- if (dss_has_feature(FEAT_DSI_LDO_STATUS)) {
- if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 21, 1) != 1) {
- DSSERR("ComplexIO LDO power down.\n");
- r = -ENODEV;
- goto err;
- }
+ if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 21, 1) != 1) {
+ DSSERR("ComplexIO LDO power down.\n");
+ r = -ENODEV;
+ goto err;
}
dsi_complexio_timings();
@@ -2069,8 +1799,6 @@ static void dsi_vc_initial_config(int channel)
r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */
- if (dss_has_feature(FEAT_DSI_VC_OCP_WIDTH))
- r = FLD_MOD(r, 3, 11, 10); /* OCP_WIDTH = 32 bit */
r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
@@ -2095,10 +1823,6 @@ static int dsi_vc_config_l4(int channel)
REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */
- /* DCS_CMD_ENABLE */
- if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC))
- REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 30, 30);
-
dsi_vc_enable(channel, 1);
dsi.vc[channel].mode = DSI_VC_MODE_L4;
@@ -2123,10 +1847,6 @@ static int dsi_vc_config_vp(int channel)
REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 1, 1); /* SOURCE, 1 = video port */
- /* DCS_CMD_ENABLE */
- if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC))
- REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 30, 30);
-
dsi_vc_enable(channel, 1);
dsi.vc[channel].mode = DSI_VC_MODE_VP;
@@ -2251,44 +1971,33 @@ static int dsi_vc_send_bta(int channel)
int dsi_vc_send_bta_sync(int channel)
{
- DECLARE_COMPLETION_ONSTACK(completion);
int r = 0;
u32 err;
- r = dsi_register_isr_vc(channel, dsi_completion_handler,
- &completion, DSI_VC_IRQ_BTA);
- if (r)
- goto err0;
+ INIT_COMPLETION(dsi.bta_completion);
- r = dsi_register_isr(dsi_completion_handler, &completion,
- DSI_IRQ_ERROR_MASK);
- if (r)
- goto err1;
+ dsi_vc_enable_bta_irq(channel);
r = dsi_vc_send_bta(channel);
if (r)
- goto err2;
+ goto err;
- if (wait_for_completion_timeout(&completion,
+ if (wait_for_completion_timeout(&dsi.bta_completion,
msecs_to_jiffies(500)) == 0) {
DSSERR("Failed to receive BTA\n");
r = -EIO;
- goto err2;
+ goto err;
}
err = dsi_get_errors();
if (err) {
DSSERR("Error while sending BTA: %x\n", err);
r = -EIO;
- goto err2;
+ goto err;
}
-err2:
- dsi_unregister_isr(dsi_completion_handler, &completion,
- DSI_IRQ_ERROR_MASK);
-err1:
- dsi_unregister_isr_vc(channel, dsi_completion_handler,
- &completion, DSI_VC_IRQ_BTA);
-err0:
+err:
+ dsi_vc_disable_bta_irq(channel);
+
return r;
}
EXPORT_SYMBOL(dsi_vc_send_bta_sync);
@@ -2782,11 +2491,8 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
r = FLD_MOD(r, 2, 13, 12); /* LINE_BUFFER, 2 lines */
r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */
r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */
- if (!dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) {
- r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */
- /* DCS_CMD_CODE, 1=start, 0=continue */
- r = FLD_MOD(r, 0, 25, 25);
- }
+ r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */
+ r = FLD_MOD(r, 0, 25, 25); /* DCS_CMD_CODE, 1=start, 0=continue */
dsi_write_reg(DSI_CTRL, r);
@@ -3105,20 +2811,19 @@ static void dsi_te_timeout(unsigned long arg)
}
#endif
-static void dsi_framedone_bta_callback(void *data, u32 mask);
-
static void dsi_handle_framedone(int error)
{
const int channel = dsi.update_channel;
- dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback,
- NULL, DSI_VC_IRQ_BTA);
-
cancel_delayed_work(&dsi.framedone_timeout_work);
+ dsi_vc_disable_bta_irq(channel);
+
/* SIDLEMODE back to smart-idle */
dispc_enable_sidle();
+ dsi.bta_callback = NULL;
+
if (dsi.te_enabled) {
/* enable LP_RX_TO again after the TE */
REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
@@ -3152,7 +2857,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work)
dsi_handle_framedone(-ETIMEDOUT);
}
-static void dsi_framedone_bta_callback(void *data, u32 mask)
+static void dsi_framedone_bta_callback(void)
{
dsi_handle_framedone(0);
@@ -3192,19 +2897,15 @@ static void dsi_framedone_irq_callback(void *data, u32 mask)
* asynchronously.
* */
- r = dsi_register_isr_vc(channel, dsi_framedone_bta_callback,
- NULL, DSI_VC_IRQ_BTA);
- if (r) {
- DSSERR("Failed to register BTA ISR\n");
- dsi_handle_framedone(-EIO);
- return;
- }
+ dsi.bta_callback = dsi_framedone_bta_callback;
+
+ barrier();
+
+ dsi_vc_enable_bta_irq(channel);
r = dsi_vc_send_bta(channel);
if (r) {
DSSERR("BTA after framedone failed\n");
- dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback,
- NULL, DSI_VC_IRQ_BTA);
dsi_handle_framedone(-EIO);
}
}
@@ -3383,10 +3084,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
{
int r;
- /* The SCPClk is required for both PLL and CIO registers on OMAP4 */
- /* CIO_CLK_ICG, enable L3 clk to CIO */
- REG_FLD_MOD(DSI_CLK_CTRL, 1, 14, 14);
-
_dsi_print_reset_status();
r = dsi_pll_init(dssdev, true, true);
@@ -3399,8 +3096,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
dss_select_dispc_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC);
dss_select_dsi_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI);
- dss_select_lcd_clk_source(dssdev->manager->id,
- DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC);
DSSDBG("PLL OK\n");
@@ -3657,24 +3352,12 @@ void dsi_wait_pll_hsdiv_dsi_active(void)
dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI));
}
-static void dsi_calc_clock_param_ranges(void)
-{
- dsi.regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN);
- dsi.regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM);
- dsi.regm_dispc_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC);
- dsi.regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI);
- dsi.fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT);
- dsi.fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT);
- dsi.lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
-}
-
static int dsi_init(struct platform_device *pdev)
{
u32 rev;
int r, i;
struct resource *dsi_mem;
- spin_lock_init(&dsi.irq_lock);
spin_lock_init(&dsi.errors_lock);
dsi.errors = 0;
@@ -3683,6 +3366,8 @@ static int dsi_init(struct platform_device *pdev)
dsi.irq_stats.last_reset = jiffies;
#endif
+ init_completion(&dsi.bta_completion);
+
mutex_init(&dsi.lock);
sema_init(&dsi.bus_lock, 1);
@@ -3731,8 +3416,6 @@ static int dsi_init(struct platform_device *pdev)
dsi.vc[i].vc_id = 0;
}
- dsi_calc_clock_param_ranges();
-
enable_clocks(1);
rev = dsi_read_reg(DSI_REVISION);
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 3f1fee63c67..7f846996dc3 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -82,10 +82,10 @@ static struct {
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
} dss;
-static const char * const dss_generic_clk_source_names[] = {
- [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC",
- [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI",
- [DSS_CLK_SRC_FCK] = "DSS_FCK",
+static const struct dss_clk_source_name dss_generic_clk_source_names[] = {
+ { DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, "DSI_PLL_HSDIV_DISPC" },
+ { DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, "DSI_PLL_HSDIV_DSI" },
+ { DSS_CLK_SRC_FCK, "DSS_FCK" },
};
static void dss_clk_enable_all_no_ctx(void);
@@ -232,47 +232,37 @@ void dss_sdi_disable(void)
const char *dss_get_generic_clk_source_name(enum dss_clk_source clk_src)
{
- return dss_generic_clk_source_names[clk_src];
+ return dss_generic_clk_source_names[clk_src].clksrc_name;
}
void dss_dump_clocks(struct seq_file *s)
{
unsigned long dpll4_ck_rate;
unsigned long dpll4_m4_ck_rate;
- const char *fclk_name, *fclk_real_name;
- unsigned long fclk_rate;
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
- seq_printf(s, "- DSS -\n");
-
- fclk_name = dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK);
- fclk_real_name = dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK);
- fclk_rate = dss_clk_get_rate(DSS_CLK_FCK);
+ dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
+ dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck);
- if (dss.dpll4_m4_ck) {
- dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
- dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck);
+ seq_printf(s, "- DSS -\n");
- seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
+ seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
- if (cpu_is_omap3630() || cpu_is_omap44xx())
- seq_printf(s, "%s (%s) = %lu / %lu = %lu\n",
- fclk_name, fclk_real_name,
- dpll4_ck_rate,
- dpll4_ck_rate / dpll4_m4_ck_rate,
- fclk_rate);
- else
- seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n",
- fclk_name, fclk_real_name,
- dpll4_ck_rate,
- dpll4_ck_rate / dpll4_m4_ck_rate,
- fclk_rate);
- } else {
- seq_printf(s, "%s (%s) = %lu\n",
- fclk_name, fclk_real_name,
- fclk_rate);
- }
+ if (cpu_is_omap3630() || cpu_is_omap44xx())
+ seq_printf(s, "%s (%s) = %lu / %lu = %lu\n",
+ dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK),
+ dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK),
+ dpll4_ck_rate,
+ dpll4_ck_rate / dpll4_m4_ck_rate,
+ dss_clk_get_rate(DSS_CLK_FCK));
+ else
+ seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n",
+ dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK),
+ dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK),
+ dpll4_ck_rate,
+ dpll4_ck_rate / dpll4_m4_ck_rate,
+ dss_clk_get_rate(DSS_CLK_FCK));
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
}
@@ -392,43 +382,34 @@ enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
/* calculate clock rates using dividers in cinfo */
int dss_calc_clock_rates(struct dss_clock_info *cinfo)
{
- if (dss.dpll4_m4_ck) {
- unsigned long prate;
- u16 fck_div_max = 16;
+ unsigned long prate;
+ u16 fck_div_max = 16;
- if (cpu_is_omap3630() || cpu_is_omap44xx())
- fck_div_max = 32;
+ if (cpu_is_omap3630() || cpu_is_omap44xx())
+ fck_div_max = 32;
- if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0)
- return -EINVAL;
+ if ((cinfo->fck_div > fck_div_max) || cinfo->fck_div == 0)
+ return -EINVAL;
- prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
+ prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
- cinfo->fck = prate / cinfo->fck_div;
- } else {
- if (cinfo->fck_div != 0)
- return -EINVAL;
- cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK);
- }
+ cinfo->fck = prate / cinfo->fck_div;
return 0;
}
int dss_set_clock_div(struct dss_clock_info *cinfo)
{
- if (dss.dpll4_m4_ck) {
- unsigned long prate;
- int r;
+ unsigned long prate;
+ int r;
+ if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
DSSDBG("dpll4_m4 = %ld\n", prate);
r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div);
if (r)
return r;
- } else {
- if (cinfo->fck_div != 0)
- return -EINVAL;
}
DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
@@ -440,11 +421,9 @@ int dss_get_clock_div(struct dss_clock_info *cinfo)
{
cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK);
- if (dss.dpll4_m4_ck) {
+ if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
unsigned long prate;
-
prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
-
if (cpu_is_omap3630() || cpu_is_omap44xx())
cinfo->fck_div = prate / (cinfo->fck);
else
@@ -458,7 +437,7 @@ int dss_get_clock_div(struct dss_clock_info *cinfo)
unsigned long dss_get_dpll4_rate(void)
{
- if (dss.dpll4_m4_ck)
+ if (cpu_is_omap34xx() || cpu_is_omap44xx())
return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
else
return 0;
@@ -481,7 +460,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
prate = dss_get_dpll4_rate();
- max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
+ max_dss_fck = dss_feat_get_max_dss_fck();
fck = dss_clk_get_rate(DSS_CLK_FCK);
if (req_pck == dss.cache_req_pck &&
@@ -507,7 +486,7 @@ retry:
memset(&best_dss, 0, sizeof(best_dss));
memset(&best_dispc, 0, sizeof(best_dispc));
- if (dss.dpll4_m4_ck == NULL) {
+ if (cpu_is_omap24xx()) {
struct dispc_clock_info cur_dispc;
/* XXX can we change the clock on omap2? */
fck = dss_clk_get_rate(DSS_CLK_FCK);
@@ -522,7 +501,8 @@ retry:
best_dispc = cur_dispc;
goto found;
- } else {
+ } else if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
+
if (cpu_is_omap3630() || cpu_is_omap44xx())
fck_div_max = 32;
@@ -557,6 +537,8 @@ retry:
goto found;
}
}
+ } else {
+ BUG();
}
found:
@@ -639,7 +621,6 @@ static int dss_init(void)
int r;
u32 rev;
struct resource *dss_mem;
- struct clk *dpll4_m4_ck;
dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
if (!dss_mem) {
@@ -680,26 +661,23 @@ static int dss_init(void)
REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
#endif
+
if (cpu_is_omap34xx()) {
- dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
- if (IS_ERR(dpll4_m4_ck)) {
+ dss.dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
+ if (IS_ERR(dss.dpll4_m4_ck)) {
DSSERR("Failed to get dpll4_m4_ck\n");
- r = PTR_ERR(dpll4_m4_ck);
+ r = PTR_ERR(dss.dpll4_m4_ck);
goto fail1;
}
} else if (cpu_is_omap44xx()) {
- dpll4_m4_ck = clk_get(NULL, "dpll_per_m5x2_ck");
- if (IS_ERR(dpll4_m4_ck)) {
+ dss.dpll4_m4_ck = clk_get(NULL, "dpll_per_m5x2_ck");
+ if (IS_ERR(dss.dpll4_m4_ck)) {
DSSERR("Failed to get dpll4_m4_ck\n");
- r = PTR_ERR(dpll4_m4_ck);
+ r = PTR_ERR(dss.dpll4_m4_ck);
goto fail1;
}
- } else { /* omap24xx */
- dpll4_m4_ck = NULL;
}
- dss.dpll4_m4_ck = dpll4_m4_ck;
-
dss.dsi_clk_source = DSS_CLK_SRC_FCK;
dss.dispc_clk_source = DSS_CLK_SRC_FCK;
dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK;
@@ -721,7 +699,7 @@ fail0:
static void dss_exit(void)
{
- if (dss.dpll4_m4_ck)
+ if (cpu_is_omap34xx() || cpu_is_omap44xx())
clk_put(dss.dpll4_m4_ck);
iounmap(dss.base);
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index c2f582bb19c..05ccd005e26 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -126,6 +126,12 @@ enum dss_clk_source {
* OMAP4: DSS_FCLK */
};
+/* Correlates clock source name and dss_clk_source member */
+struct dss_clk_source_name {
+ enum dss_clk_source clksrc;
+ const char *clksrc_name;
+};
+
enum dss_hdmi_venc_clk_source_select {
DSS_VENC_TV_CLK = 0,
DSS_HDMI_M_PCLK = 1,
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index 179a7a4f63b..86dc848fae2 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -30,13 +30,10 @@
/* Defines a generic omap register field */
struct dss_reg_field {
+ enum dss_feat_reg_field id;
u8 start, end;
};
-struct dss_param_range {
- int min, max;
-};
-
struct omap_dss_features {
const struct dss_reg_field *reg_fields;
const int num_reg_fields;
@@ -45,58 +42,46 @@ struct omap_dss_features {
const int num_mgrs;
const int num_ovls;
+ const unsigned long max_dss_fck;
const enum omap_display_type *supported_displays;
const enum omap_color_mode *supported_color_modes;
- const char * const *clksrc_names;
- const struct dss_param_range *dss_params;
+ const struct dss_clk_source_name *clksrc_names;
};
/* This struct is assigned to one of the below during initialization */
static struct omap_dss_features *omap_current_dss_features;
static const struct dss_reg_field omap2_dss_reg_fields[] = {
- [FEAT_REG_FIRHINC] = { 11, 0 },
- [FEAT_REG_FIRVINC] = { 27, 16 },
- [FEAT_REG_FIFOLOWTHRESHOLD] = { 8, 0 },
- [FEAT_REG_FIFOHIGHTHRESHOLD] = { 24, 16 },
- [FEAT_REG_FIFOSIZE] = { 8, 0 },
- [FEAT_REG_HORIZONTALACCU] = { 9, 0 },
- [FEAT_REG_VERTICALACCU] = { 25, 16 },
- [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
- [FEAT_REG_DSIPLL_REGN] = { 0, 0 },
- [FEAT_REG_DSIPLL_REGM] = { 0, 0 },
- [FEAT_REG_DSIPLL_REGM_DISPC] = { 0, 0 },
- [FEAT_REG_DSIPLL_REGM_DSI] = { 0, 0 },
+ { FEAT_REG_FIRHINC, 11, 0 },
+ { FEAT_REG_FIRVINC, 27, 16 },
+ { FEAT_REG_FIFOLOWTHRESHOLD, 8, 0 },
+ { FEAT_REG_FIFOHIGHTHRESHOLD, 24, 16 },
+ { FEAT_REG_FIFOSIZE, 8, 0 },
+ { FEAT_REG_HORIZONTALACCU, 9, 0 },
+ { FEAT_REG_VERTICALACCU, 25, 16 },
+ { FEAT_REG_DISPC_CLK_SWITCH, 0, 0 },
};
static const struct dss_reg_field omap3_dss_reg_fields[] = {
- [FEAT_REG_FIRHINC] = { 12, 0 },
- [FEAT_REG_FIRVINC] = { 28, 16 },
- [FEAT_REG_FIFOLOWTHRESHOLD] = { 11, 0 },
- [FEAT_REG_FIFOHIGHTHRESHOLD] = { 27, 16 },
- [FEAT_REG_FIFOSIZE] = { 10, 0 },
- [FEAT_REG_HORIZONTALACCU] = { 9, 0 },
- [FEAT_REG_VERTICALACCU] = { 25, 16 },
- [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
- [FEAT_REG_DSIPLL_REGN] = { 7, 1 },
- [FEAT_REG_DSIPLL_REGM] = { 18, 8 },
- [FEAT_REG_DSIPLL_REGM_DISPC] = { 22, 19 },
- [FEAT_REG_DSIPLL_REGM_DSI] = { 26, 23 },
+ { FEAT_REG_FIRHINC, 12, 0 },
+ { FEAT_REG_FIRVINC, 28, 16 },
+ { FEAT_REG_FIFOLOWTHRESHOLD, 11, 0 },
+ { FEAT_REG_FIFOHIGHTHRESHOLD, 27, 16 },
+ { FEAT_REG_FIFOSIZE, 10, 0 },
+ { FEAT_REG_HORIZONTALACCU, 9, 0 },
+ { FEAT_REG_VERTICALACCU, 25, 16 },
+ { FEAT_REG_DISPC_CLK_SWITCH, 0, 0 },
};
static const struct dss_reg_field omap4_dss_reg_fields[] = {
- [FEAT_REG_FIRHINC] = { 12, 0 },
- [FEAT_REG_FIRVINC] = { 28, 16 },
- [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 },
- [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 },
- [FEAT_REG_FIFOSIZE] = { 15, 0 },
- [FEAT_REG_HORIZONTALACCU] = { 10, 0 },
- [FEAT_REG_VERTICALACCU] = { 26, 16 },
- [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 8 },
- [FEAT_REG_DSIPLL_REGN] = { 8, 1 },
- [FEAT_REG_DSIPLL_REGM] = { 20, 9 },
- [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 },
- [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
+ { FEAT_REG_FIRHINC, 12, 0 },
+ { FEAT_REG_FIRVINC, 28, 16 },
+ { FEAT_REG_FIFOLOWTHRESHOLD, 15, 0 },
+ { FEAT_REG_FIFOHIGHTHRESHOLD, 31, 16 },
+ { FEAT_REG_FIFOSIZE, 15, 0 },
+ { FEAT_REG_HORIZONTALACCU, 10, 0 },
+ { FEAT_REG_VERTICALACCU, 26, 16 },
+ { FEAT_REG_DISPC_CLK_SWITCH, 9, 8 },
};
static const enum omap_display_type omap2_dss_supported_displays[] = {
@@ -177,52 +162,22 @@ static const enum omap_color_mode omap3_dss_supported_color_modes[] = {
OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
};
-static const char * const omap2_dss_clk_source_names[] = {
- [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "N/A",
- [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "N/A",
- [DSS_CLK_SRC_FCK] = "DSS_FCLK1",
-};
-
-static const char * const omap3_dss_clk_source_names[] = {
- [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI1_PLL_FCLK",
- [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI2_PLL_FCLK",
- [DSS_CLK_SRC_FCK] = "DSS1_ALWON_FCLK",
-};
-
-static const char * const omap4_dss_clk_source_names[] = {
- [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "PLL1_CLK1",
- [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "PLL1_CLK2",
- [DSS_CLK_SRC_FCK] = "DSS_FCLK",
+static const struct dss_clk_source_name omap2_dss_clk_source_names[] = {
+ { DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, "N/A" },
+ { DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, "N/A" },
+ { DSS_CLK_SRC_FCK, "DSS_FCLK1" },
};
-static const struct dss_param_range omap2_dss_param_range[] = {
- [FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
- [FEAT_PARAM_DSIPLL_REGN] = { 0, 0 },
- [FEAT_PARAM_DSIPLL_REGM] = { 0, 0 },
- [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, 0 },
- [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, 0 },
- [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 },
- [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 },
+static const struct dss_clk_source_name omap3_dss_clk_source_names[] = {
+ { DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, "DSI1_PLL_FCLK" },
+ { DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, "DSI2_PLL_FCLK" },
+ { DSS_CLK_SRC_FCK, "DSS1_ALWON_FCLK" },
};
-static const struct dss_param_range omap3_dss_param_range[] = {
- [FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
- [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 7) - 1 },
- [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 11) - 1 },
- [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 4) - 1 },
- [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 },
- [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 },
- [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1},
-};
-
-static const struct dss_param_range omap4_dss_param_range[] = {
- [FEAT_PARAM_DSS_FCK] = { 0, 186000000 },
- [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 },
- [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 },
- [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 },
- [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
- [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 },
- [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
+static const struct dss_clk_source_name omap4_dss_clk_source_names[] = {
+ { DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, "PLL1_CLK1" },
+ { DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, "PLL1_CLK2" },
+ { DSS_CLK_SRC_FCK, "DSS_FCLK" },
};
/* OMAP2 DSS Features */
@@ -237,10 +192,10 @@ static struct omap_dss_features omap2_dss_features = {
.num_mgrs = 2,
.num_ovls = 3,
+ .max_dss_fck = 173000000,
.supported_displays = omap2_dss_supported_displays,
.supported_color_modes = omap2_dss_supported_color_modes,
.clksrc_names = omap2_dss_clk_source_names,
- .dss_params = omap2_dss_param_range,
};
/* OMAP3 DSS Features */
@@ -252,15 +207,14 @@ static struct omap_dss_features omap3430_dss_features = {
FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
FEAT_FUNCGATED | FEAT_ROWREPEATENABLE |
- FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF |
- FEAT_DSI_PLL_FREQSEL | FEAT_DSI_LDO_STATUS,
+ FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF,
.num_mgrs = 2,
.num_ovls = 3,
+ .max_dss_fck = 173000000,
.supported_displays = omap3430_dss_supported_displays,
.supported_color_modes = omap3_dss_supported_color_modes,
.clksrc_names = omap3_dss_clk_source_names,
- .dss_params = omap3_dss_param_range,
};
static struct omap_dss_features omap3630_dss_features = {
@@ -272,15 +226,14 @@ static struct omap_dss_features omap3630_dss_features = {
FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED |
FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
- FEAT_RESIZECONF | FEAT_DSI_PLL_FREQSEL |
- FEAT_DSI_LDO_STATUS,
+ FEAT_RESIZECONF,
.num_mgrs = 2,
.num_ovls = 3,
+ .max_dss_fck = 173000000,
.supported_displays = omap3630_dss_supported_displays,
.supported_color_modes = omap3_dss_supported_color_modes,
.clksrc_names = omap3_dss_clk_source_names,
- .dss_params = omap3_dss_param_range,
};
/* OMAP4 DSS Features */
@@ -291,15 +244,14 @@ static struct omap_dss_features omap4_dss_features = {
.has_feature =
FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA |
FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 |
- FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
- FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH,
+ FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC,
.num_mgrs = 3,
.num_ovls = 3,
+ .max_dss_fck = 186000000,
.supported_displays = omap4_dss_supported_displays,
.supported_color_modes = omap3_dss_supported_color_modes,
.clksrc_names = omap4_dss_clk_source_names,
- .dss_params = omap4_dss_param_range,
};
/* Functions returning values related to a DSS feature */
@@ -313,14 +265,10 @@ int dss_feat_get_num_ovls(void)
return omap_current_dss_features->num_ovls;
}
-unsigned long dss_feat_get_param_min(enum dss_range_param param)
-{
- return omap_current_dss_features->dss_params[param].min;
-}
-
-unsigned long dss_feat_get_param_max(enum dss_range_param param)
+/* Max supported DSS FCK in Hz */
+unsigned long dss_feat_get_max_dss_fck(void)
{
- return omap_current_dss_features->dss_params[param].max;
+ return omap_current_dss_features->max_dss_fck;
}
enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel)
@@ -342,7 +290,7 @@ bool dss_feat_color_mode_supported(enum omap_plane plane,
const char *dss_feat_get_clk_source_name(enum dss_clk_source id)
{
- return omap_current_dss_features->clksrc_names[id];
+ return omap_current_dss_features->clksrc_names[id].clksrc_name;
}
/* DSS has_feature check */
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
index c5c0b4001ab..2601626519c 100644
--- a/drivers/video/omap2/dss/dss_features.h
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -77,6 +77,8 @@ int dss_feat_get_num_mgrs(void);
int dss_feat_get_num_ovls(void);
unsigned long dss_feat_get_param_min(enum dss_range_param param);
unsigned long dss_feat_get_param_max(enum dss_range_param param);
+/* HDMI from Seb comapat */
+unsigned long dss_feat_get_max_dss_fck(void);
enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane);
bool dss_feat_color_mode_supported(enum omap_plane plane,
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 0d44f070ef3..aa5b3dc5f44 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -30,6 +30,11 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <plat/display.h>
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#endif
#include "dss.h"
#include "hdmi.h"
@@ -1104,6 +1109,7 @@ static void hdmi_enable_clocks(int enable)
static int hdmi_power_on(struct omap_dss_device *dssdev)
{
int r, code = 0;
+ int dirty = true;
struct hdmi_pll_info pll_data;
struct omap_video_timings *p;
int clkin, n, phy;
@@ -1119,8 +1125,10 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
dssdev->panel.timings.y_res);
if (!hdmi.custom_set) {
+ code = get_timings_index();
DSSDBG("Read EDID as no EDID is not set on poweron\n");
hdmi_read_edid(p);
+ dirty = get_timings_index() != code;
}
code = get_timings_index();
dssdev->panel.timings = cea_vesa_timings[code].timings;
@@ -1134,7 +1142,11 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
hdmi_wp_video_start(0);
- /* config the PLL and PHY first */
+ if (dirty) {
+ omap_dss_notify(dssdev, OMAP_DSS_SIZE_CHANGE);
+ }
+
+ /* config the PLL and PHY first */
r = hdmi_pll_program(&pll_data);
if (r) {
DSSDBG("Failed to lock PLL\n");
@@ -1275,11 +1287,392 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
mutex_unlock(&hdmi.lock);
}
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+static void hdmi_wp_audio_config_format(
+ struct hdmi_audio_format *aud_fmt)
+{
+ u32 r;
+
+ DSSDBG("Enter hdmi_wp_audio_config_format\n");
+
+ r = hdmi_read_reg(HDMI_WP_AUDIO_CFG);
+ r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
+ r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
+ r = FLD_MOD(r, aud_fmt->sig_blk_strt_end, 5, 5);
+ r = FLD_MOD(r, aud_fmt->type, 4, 4);
+ r = FLD_MOD(r, aud_fmt->justif, 3, 3);
+ r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);
+ r = FLD_MOD(r, aud_fmt->samples_p_word, 1, 1);
+ r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);
+ hdmi_write_reg(HDMI_WP_AUDIO_CFG, r);
+}
+
+static void hdmi_wp_audio_config_dma(struct hdmi_audio_dma *aud_dma)
+{
+ u32 r;
+
+ DSSDBG("Enter hdmi_wp_audio_config_dma\n");
+
+ r = hdmi_read_reg(HDMI_WP_AUDIO_CFG2);
+ r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);
+ r = FLD_MOD(r, aud_dma->block_size, 7, 0);
+ hdmi_write_reg(HDMI_WP_AUDIO_CFG2, r);
+
+ r = hdmi_read_reg(HDMI_WP_AUDIO_CTRL);
+ r = FLD_MOD(r, aud_dma->mode, 9, 9);
+ r = FLD_MOD(r, aud_dma->threshold, 8, 0);
+ hdmi_write_reg(HDMI_WP_AUDIO_CTRL, r);
+}
+
+static void hdmi_core_audio_config(struct hdmi_core_audio_config *cfg)
+{
+ u32 r;
+
+ /* audio clock recovery parameters */
+ r = hdmi_read_reg(HDMI_CORE_AV_ACR_CTRL);
+ r = FLD_MOD(r, cfg->use_mclk, 2, 2);
+ r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1);
+ r = FLD_MOD(r, cfg->cts_mode, 0, 0);
+ hdmi_write_reg(HDMI_CORE_AV_ACR_CTRL, r);
+
+ REG_FLD_MOD(HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0);
+ REG_FLD_MOD(HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0);
+ REG_FLD_MOD(HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0);
+ REG_FLD_MOD(HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0);
+ REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL1, cfg->cts, 7, 0);
+ REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL2, cfg->cts >> 8, 7, 0);
+ REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0);
+
+ REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_1, cfg->aud_par_busclk, 7, 0);
+ REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_2,
+ (cfg->aud_par_busclk >> 8), 7, 0);
+ REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_3,
+ (cfg->aud_par_busclk >> 16), 7, 0);
+ REG_FLD_MOD(HDMI_CORE_AV_SPDIF_CTRL, cfg->fs_override, 1, 1);
+
+ /* I2S parameters */
+ REG_FLD_MOD(HDMI_CORE_AV_I2S_CHST4, cfg->freq_sample, 3, 0);
+
+ r = FLD_MOD(r, cfg->i2s_cfg.en_high_br_aud, 7, 7);
+ r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6);
+ r = FLD_MOD(r, cfg->i2s_cfg.cbit_order, 5, 5);
+ r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4);
+ r = FLD_MOD(r, cfg->i2s_cfg.ws_polarity, 3, 3);
+ r = FLD_MOD(r, cfg->i2s_cfg.justif, 2, 2);
+ r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1);
+ r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0);
+ hdmi_write_reg(HDMI_CORE_AV_I2S_IN_CTRL, r);
+
+ r = hdmi_read_reg(HDMI_CORE_AV_I2S_CHST5);
+ r = FLD_MOD(r, cfg->freq_sample, 7, 4);
+ r = FLD_MOD(r, cfg->i2s_cfg.word_length, 3, 1);
+ r = FLD_MOD(r, cfg->i2s_cfg.word_max_length, 0, 0);
+ hdmi_write_reg(HDMI_CORE_AV_I2S_CHST5, r);
+
+ REG_FLD_MOD(HDMI_CORE_AV_I2S_IN_LEN, cfg->i2s_cfg.in_length_bits, 3, 0);
+
+ /* audio channels and mode parameters */
+ REG_FLD_MOD(HDMI_CORE_AV_HDMI_CTRL, cfg->layout, 2, 1);
+ r = hdmi_read_reg(HDMI_CORE_AV_AUD_MODE);
+ r = FLD_MOD(r, 0, 7, 7);
+ r = FLD_MOD(r, 0, 6, 6);
+ r = FLD_MOD(r, 0, 5, 5);
+ r = FLD_MOD(r, 1, 4, 4);
+ r = FLD_MOD(r, cfg->en_direct_strm_dig_aud, 3, 3);
+ r = FLD_MOD(r, cfg->en_parallel_aud, 2, 2);
+ r = FLD_MOD(r, cfg->en_spdif, 1, 1);
+ hdmi_write_reg(HDMI_CORE_AV_AUD_MODE, r);
+}
+
+static void hdmi_core_audio_infoframe_config(
+ struct hdmi_core_infoframe_audio *info_aud)
+{
+ u8 val;
+ u8 sum = 0, checksum = 0;
+
+ sum += 0x84 + 0x001 + 0x00a;
+ hdmi_write_reg(HDMI_CORE_AV_AUDIO_TYPE, 0x84);
+ hdmi_write_reg(HDMI_CORE_AV_AUDIO_VERS, 0x01);
+ hdmi_write_reg(HDMI_CORE_AV_AUDIO_LEN, 0x0a);
+
+ val = (info_aud->db1_coding_type << 4)
+ | (info_aud->db1_channel_count - 1);
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(0), val);
+ sum += val;
+
+ val = (info_aud->db2_sample_freq << 2) | info_aud->db2_sample_size;
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(1), val);
+ sum += val;
+
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(2), 0x00);
+
+ val = info_aud->db4_channel_alloc;
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(3), val);
+ sum += val;
+
+ val = (info_aud->db5_downmix_inh << 7) | (info_aud->db5_lsv << 3);
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(4), val);
+ sum += val;
+
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(5), 0x00);
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(6), 0x00);
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(7), 0x00);
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(8), 0x00);
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(9), 0x00);
+
+ checksum = 0x100 - sum;
+ hdmi_write_reg(HDMI_CORE_AV_AUDIO_CHSUM, checksum);
+
+ /*
+ * TODO: Add MPEG and SPD enable and repeat cfg when EDID parsing
+ * is available.
+ */
+}
+
+static int hdmi_config_audio_acr(u32 sample_freq, u32 *n, u32 *cts)
+{
+ u32 r;
+ u32 deep_color = 0;
+ u32 pclk = hdmi.cfg.timings.timings.pixel_clock;
+
+ if (n == NULL || cts == NULL)
+ return -EINVAL;
+ if (omap_rev() == OMAP4430_REV_ES1_0)
+ deep_color = 100;
+ else {
+ r = hdmi_read_reg(HDMI_WP_VIDEO_CFG);
+ switch (r & 0x03) {
+ case 1:
+ deep_color = 100;
+ break;
+ case 2:
+ deep_color = 125;
+ break;
+ case 3:
+ deep_color = 150;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ switch (sample_freq) {
+ case 32000:
+ if ((deep_color == 125) && ((pclk == 54054)
+ || (pclk == 74250)))
+ *n = 8192;
+ else
+ *n = 4096;
+ break;
+ case 44100:
+ *n = 6272;
+ break;
+ case 48000:
+ if ((deep_color == 125) && ((pclk == 54054)
+ || (pclk == 74250)))
+ *n = 8192;
+ else
+ *n = 6144;
+ break;
+ default:
+ *n = 0;
+ return -EINVAL;
+ }
+
+ /* calculate CTS */
+ *cts = pclk*(*n/128)*deep_color / (sample_freq/10);
+
+ return 0;
+}
+
+static int hdmi_audio_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct hdmi_audio_format audio_format;
+ struct hdmi_audio_dma audio_dma;
+ struct hdmi_core_audio_config core_cfg;
+ struct hdmi_core_infoframe_audio aud_if_cfg;
+ int err, n, cts;
+ enum hdmi_core_audio_sample_freq sample_freq;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ core_cfg.i2s_cfg.word_max_length =
+ HDMI_AUDIO_I2S_MAX_WORD_20BITS;
+ core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_16_BITS;
+ core_cfg.i2s_cfg.in_length_bits =
+ HDMI_AUDIO_I2S_INPUT_LENGTH_16;
+ core_cfg.i2s_cfg.justif = HDMI_AUDIO_JUSTIFY_LEFT;
+ audio_format.samples_p_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES;
+ audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS;
+ audio_format.justif = HDMI_AUDIO_JUSTIFY_LEFT;
+ audio_dma.transfer_size = 0x10;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ core_cfg.i2s_cfg.word_max_length =
+ HDMI_AUDIO_I2S_MAX_WORD_24BITS;
+ core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_24_BITS;
+ core_cfg.i2s_cfg.in_length_bits =
+ HDMI_AUDIO_I2S_INPUT_LENGTH_24;
+ audio_format.samples_p_word = HDMI_AUDIO_ONEWORD_ONESAMPLE;
+ audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS;
+ audio_format.justif = HDMI_AUDIO_JUSTIFY_RIGHT;
+ core_cfg.i2s_cfg.justif = HDMI_AUDIO_JUSTIFY_RIGHT;
+ audio_dma.transfer_size = 0x20;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (params_rate(params)) {
+ case 32000:
+ sample_freq = HDMI_AUDIO_FS_32000;
+ break;
+ case 44100:
+ sample_freq = HDMI_AUDIO_FS_44100;
+ break;
+ case 48000:
+ sample_freq = HDMI_AUDIO_FS_48000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = hdmi_config_audio_acr(params_rate(params), &n, &cts);
+ if (err < 0)
+ return err;
+
+ /* audio wrapper config */
+ audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL;
+ audio_format.active_chnnls_msk = 0x03;
+ audio_format.type = HDMI_AUDIO_TYPE_LPCM;
+ audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
+ audio_format.sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON;
+
+ audio_dma.block_size = 0xC0;
+ audio_dma.mode = HDMI_AUDIO_TRANSF_DMA;
+ audio_dma.threshold = 0x20;
+
+ hdmi_wp_audio_config_dma(&audio_dma);
+ hdmi_wp_audio_config_format(&audio_format);
+
+ /* I2S config */
+ core_cfg.i2s_cfg.en_high_br_aud = false;
+ core_cfg.i2s_cfg.sck_edge_mode =
+ HDMI_AUDIO_I2S_SCK_SAMPLE_EDGE_RISING;
+ core_cfg.i2s_cfg.cbit_order = false;
+ core_cfg.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_PCM;
+ core_cfg.i2s_cfg.ws_polarity = HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT;
+ core_cfg.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST;
+ core_cfg.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT;
+
+ /* core audio config */
+ core_cfg.freq_sample = sample_freq;
+ core_cfg.n = n;
+ core_cfg.cts = cts;
+ if (omap_rev() == OMAP4430_REV_ES1_0) {
+ core_cfg.aud_par_busclk = (((128 * 31) - 1) << 8);
+ core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_HW;
+ } else {
+ core_cfg.aud_par_busclk = 0;
+ core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_SW;
+ }
+ core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH;
+ core_cfg.use_mclk = false;
+ core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS;
+ core_cfg.fs_override = true;
+ core_cfg.en_acr_pkt = true;
+ core_cfg.en_direct_strm_dig_aud = false;
+ core_cfg.en_parallel_aud = true;
+ core_cfg.en_spdif = false;
+
+ hdmi_core_audio_config(&core_cfg);
+
+ /*
+ * configure packet
+ * info frame audio see doc CEA861-D page 74
+ */
+ aud_if_cfg.db1_coding_type = HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM;
+ aud_if_cfg.db1_channel_count = 2;
+ aud_if_cfg.db2_sample_freq = HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM;
+ aud_if_cfg.db2_sample_size = HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM;
+ aud_if_cfg.db4_channel_alloc = 0x00;
+ aud_if_cfg.db5_downmix_inh = false;
+ aud_if_cfg.db5_lsv = 0;
+
+ hdmi_core_audio_infoframe_config(&aud_if_cfg);
+ return 0;
+}
+
+static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ int err = 0;
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 1, 0, 0);
+ REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 31, 31);
+ REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 30, 30);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 0, 0, 0);
+ REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 30, 30);
+ REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 31, 31);
+ break;
+ default:
+ err = -EINVAL;
+ }
+ return err;
+}
+
+static struct snd_soc_codec_driver hdmi_audio_codec_drv = {
+};
+
+static struct snd_soc_dai_ops hdmi_audio_codec_ops = {
+ .hw_params = hdmi_audio_hw_params,
+ .trigger = hdmi_audio_trigger,
+};
+
+static struct snd_soc_dai_driver hdmi_codec_dai_drv = {
+ .name = "omap4-hdmi-audio-codec",
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ },
+ .ops = &hdmi_audio_codec_ops,
+};
+#endif
+
+
/* HDMI HW IP initialisation */
static int omapdss_hdmihw_probe(struct platform_device *pdev)
{
struct resource *hdmi_mem;
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+ int ret;
+
+ /* Register ASoC codec DAI */
+ ret = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv,
+ &hdmi_codec_dai_drv, 1);
+ if (ret) {
+ DSSERR("can't register ASoC HDMI audio codec\n");
+ return ret;
+ }
+#endif
+
hdmi.pdata = pdev->dev.platform_data;
hdmi.pdev = pdev;
@@ -1307,6 +1700,11 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev)
{
hdmi_panel_exit();
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+ snd_soc_unregister_codec(&pdev->dev);
+#endif
+
iounmap(hdmi.base_wp);
return 0;
diff --git a/drivers/video/omap2/dss/hdmi.h b/drivers/video/omap2/dss/hdmi.h
index 9887ab96da3..6c79a57500b 100644
--- a/drivers/video/omap2/dss/hdmi.h
+++ b/drivers/video/omap2/dss/hdmi.h
@@ -48,6 +48,10 @@ struct hdmi_reg { u16 idx; };
#define HDMI_WP_VIDEO_TIMING_H HDMI_WP_REG(0x68)
#define HDMI_WP_VIDEO_TIMING_V HDMI_WP_REG(0x6C)
#define HDMI_WP_WP_CLK HDMI_WP_REG(0x70)
+#define HDMI_WP_AUDIO_CFG HDMI_WP_REG(0x80)
+#define HDMI_WP_AUDIO_CFG2 HDMI_WP_REG(0x84)
+#define HDMI_WP_AUDIO_CTRL HDMI_WP_REG(0x88)
+#define HDMI_WP_AUDIO_DATA HDMI_WP_REG(0x8C)
/* HDMI IP Core System */
#define HDMI_CORE_SYS_REG(idx) HDMI_REG(HDMI_CORE_SYS + idx)
@@ -105,6 +109,8 @@ struct hdmi_reg { u16 idx; };
#define HDMI_CORE_AV_AVI_DBYTE_NELEMS HDMI_CORE_AV_REG(15)
#define HDMI_CORE_AV_SPD_DBYTE HDMI_CORE_AV_REG(0x190)
#define HDMI_CORE_AV_SPD_DBYTE_NELEMS HDMI_CORE_AV_REG(27)
+#define HDMI_CORE_AV_AUD_DBYTE(n) HDMI_CORE_AV_REG(n * 4 + 0x210)
+#define HDMI_CORE_AV_AUD_DBYTE_NELEMS HDMI_CORE_AV_REG(10)
#define HDMI_CORE_AV_MPEG_DBYTE HDMI_CORE_AV_REG(0x290)
#define HDMI_CORE_AV_MPEG_DBYTE_NELEMS HDMI_CORE_AV_REG(27)
#define HDMI_CORE_AV_GEN_DBYTE HDMI_CORE_AV_REG(0x300)
@@ -153,6 +159,10 @@ struct hdmi_reg { u16 idx; };
#define HDMI_CORE_AV_SPD_VERS HDMI_CORE_AV_REG(0x184)
#define HDMI_CORE_AV_SPD_LEN HDMI_CORE_AV_REG(0x188)
#define HDMI_CORE_AV_SPD_CHSUM HDMI_CORE_AV_REG(0x18C)
+#define HDMI_CORE_AV_AUDIO_TYPE HDMI_CORE_AV_REG(0x200)
+#define HDMI_CORE_AV_AUDIO_VERS HDMI_CORE_AV_REG(0x204)
+#define HDMI_CORE_AV_AUDIO_LEN HDMI_CORE_AV_REG(0x208)
+#define HDMI_CORE_AV_AUDIO_CHSUM HDMI_CORE_AV_REG(0x20C)
#define HDMI_CORE_AV_MPEG_TYPE HDMI_CORE_AV_REG(0x280)
#define HDMI_CORE_AV_MPEG_VERS HDMI_CORE_AV_REG(0x284)
#define HDMI_CORE_AV_MPEG_LEN HDMI_CORE_AV_REG(0x288)
@@ -272,7 +282,7 @@ enum hdmi_core_packet_ctrl {
HDMI_PACKETREPEATOFF = 0
};
-/* INFOFRAME_AVI_ definitions */
+/* INFOFRAME_AVI_ and INFOFRAME_AUDIO_ definitions */
enum hdmi_core_infoframe {
HDMI_INFOFRAME_AVI_DB1Y_RGB = 0,
HDMI_INFOFRAME_AVI_DB1Y_YUV422 = 1,
@@ -317,7 +327,36 @@ enum hdmi_core_infoframe {
HDMI_INFOFRAME_AVI_DB5PR_7 = 6,
HDMI_INFOFRAME_AVI_DB5PR_8 = 7,
HDMI_INFOFRAME_AVI_DB5PR_9 = 8,
- HDMI_INFOFRAME_AVI_DB5PR_10 = 9
+ HDMI_INFOFRAME_AVI_DB5PR_10 = 9,
+ HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM = 0,
+ HDMI_INFOFRAME_AUDIO_DB1CT_IEC60958 = 1,
+ HDMI_INFOFRAME_AUDIO_DB1CT_AC3 = 2,
+ HDMI_INFOFRAME_AUDIO_DB1CT_MPEG1 = 3,
+ HDMI_INFOFRAME_AUDIO_DB1CT_MP3 = 4,
+ HDMI_INFOFRAME_AUDIO_DB1CT_MPEG2_MULTICH = 5,
+ HDMI_INFOFRAME_AUDIO_DB1CT_AAC = 6,
+ HDMI_INFOFRAME_AUDIO_DB1CT_DTS = 7,
+ HDMI_INFOFRAME_AUDIO_DB1CT_ATRAC = 8,
+ HDMI_INFOFRAME_AUDIO_DB1CT_ONEBIT = 9,
+ HDMI_INFOFRAME_AUDIO_DB1CT_DOLBY_DIGITAL_PLUS = 10,
+ HDMI_INFOFRAME_AUDIO_DB1CT_DTS_HD = 11,
+ HDMI_INFOFRAME_AUDIO_DB1CT_MAT = 12,
+ HDMI_INFOFRAME_AUDIO_DB1CT_DST = 13,
+ HDMI_INFOFRAME_AUDIO_DB1CT_WMA_PRO = 14,
+ HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM = 0,
+ HDMI_INFOFRAME_AUDIO_DB2SF_32000 = 1,
+ HDMI_INFOFRAME_AUDIO_DB2SF_44100 = 2,
+ HDMI_INFOFRAME_AUDIO_DB2SF_48000 = 3,
+ HDMI_INFOFRAME_AUDIO_DB2SF_88200 = 4,
+ HDMI_INFOFRAME_AUDIO_DB2SF_96000 = 5,
+ HDMI_INFOFRAME_AUDIO_DB2SF_176400 = 6,
+ HDMI_INFOFRAME_AUDIO_DB2SF_192000 = 7,
+ HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM = 0,
+ HDMI_INFOFRAME_AUDIO_DB2SS_16BIT = 1,
+ HDMI_INFOFRAME_AUDIO_DB2SS_20BIT = 2,
+ HDMI_INFOFRAME_AUDIO_DB2SS_24BIT = 3,
+ HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PERMITTED = 0,
+ HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PROHIBITED = 1
};
enum hdmi_packing_mode {
@@ -327,6 +366,117 @@ enum hdmi_packing_mode {
HDMI_PACK_ALREADYPACKED = 7
};
+enum hdmi_core_audio_sample_freq {
+ HDMI_AUDIO_FS_32000 = 0x3,
+ HDMI_AUDIO_FS_44100 = 0x0,
+ HDMI_AUDIO_FS_48000 = 0x2,
+ HDMI_AUDIO_FS_88200 = 0x8,
+ HDMI_AUDIO_FS_96000 = 0xA,
+ HDMI_AUDIO_FS_176400 = 0xC,
+ HDMI_AUDIO_FS_192000 = 0xE,
+ HDMI_AUDIO_FS_NOT_INDICATED = 0x1
+};
+
+enum hdmi_core_audio_layout {
+ HDMI_AUDIO_LAYOUT_2CH = 0,
+ HDMI_AUDIO_LAYOUT_8CH = 1
+};
+
+enum hdmi_core_cts_mode {
+ HDMI_AUDIO_CTS_MODE_HW = 0,
+ HDMI_AUDIO_CTS_MODE_SW = 1
+};
+
+enum hdmi_stereo_channels {
+ HDMI_AUDIO_STEREO_NOCHANNELS = 0,
+ HDMI_AUDIO_STEREO_ONECHANNEL = 1,
+ HDMI_AUDIO_STEREO_TWOCHANNELS = 2,
+ HDMI_AUDIO_STEREO_THREECHANNELS = 3,
+ HDMI_AUDIO_STEREO_FOURCHANNELS = 4
+};
+
+enum hdmi_audio_type {
+ HDMI_AUDIO_TYPE_LPCM = 0,
+ HDMI_AUDIO_TYPE_IEC = 1
+};
+
+enum hdmi_audio_justif {
+ HDMI_AUDIO_JUSTIFY_LEFT = 0,
+ HDMI_AUDIO_JUSTIFY_RIGHT = 1
+};
+
+enum hdmi_audio_sample_order {
+ HDMI_AUDIO_SAMPLE_RIGHT_FIRST = 0,
+ HDMI_AUDIO_SAMPLE_LEFT_FIRST = 1
+};
+
+enum hdmi_audio_samples_perword {
+ HDMI_AUDIO_ONEWORD_ONESAMPLE = 0,
+ HDMI_AUDIO_ONEWORD_TWOSAMPLES = 1
+};
+
+enum hdmi_audio_sample_size {
+ HDMI_AUDIO_SAMPLE_16BITS = 0,
+ HDMI_AUDIO_SAMPLE_24BITS = 1
+};
+
+enum hdmi_audio_transf_mode {
+ HDMI_AUDIO_TRANSF_DMA = 0,
+ HDMI_AUDIO_TRANSF_IRQ = 1
+};
+
+enum hdmi_audio_blk_strt_end_sig {
+ HDMI_AUDIO_BLOCK_SIG_STARTEND_ON = 0,
+ HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF = 1
+};
+
+enum hdmi_audio_i2s_config {
+ HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT = 0,
+ HDMI_AUDIO_I2S_WS_POLARIT_YLOW_IS_RIGHT = 1,
+ HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0,
+ HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1,
+ HDMI_AUDIO_I2S_MAX_WORD_20BITS = 0,
+ HDMI_AUDIO_I2S_MAX_WORD_24BITS = 1,
+ HDMI_AUDIO_I2S_CHST_WORD_NOT_SPECIFIED = 0,
+ HDMI_AUDIO_I2S_CHST_WORD_16_BITS = 1,
+ HDMI_AUDIO_I2S_CHST_WORD_17_BITS = 6,
+ HDMI_AUDIO_I2S_CHST_WORD_18_BITS = 2,
+ HDMI_AUDIO_I2S_CHST_WORD_19_BITS = 4,
+ HDMI_AUDIO_I2S_CHST_WORD_20_BITS_20MAX = 5,
+ HDMI_AUDIO_I2S_CHST_WORD_20_BITS_24MAX = 1,
+ HDMI_AUDIO_I2S_CHST_WORD_21_BITS = 6,
+ HDMI_AUDIO_I2S_CHST_WORD_22_BITS = 2,
+ HDMI_AUDIO_I2S_CHST_WORD_23_BITS = 4,
+ HDMI_AUDIO_I2S_CHST_WORD_24_BITS = 5,
+ HDMI_AUDIO_I2S_SCK_SAMPLE_EDGE_FALLING = 0,
+ HDMI_AUDIO_I2S_SCK_SAMPLE_EDGE_RISING = 1,
+ HDMI_AUDIO_I2S_VBIT_PCM = 0,
+ HDMI_AUDIO_I2S_VBIT_COMPRESSED = 1,
+ HDMI_AUDIO_I2S_INPUT_LENGTH_NA = 0,
+ HDMI_AUDIO_I2S_INPUT_LENGTH_16 = 2,
+ HDMI_AUDIO_I2S_INPUT_LENGTH_17 = 12,
+ HDMI_AUDIO_I2S_INPUT_LENGTH_18 = 4,
+ HDMI_AUDIO_I2S_INPUT_LENGTH_19 = 8,
+ HDMI_AUDIO_I2S_INPUT_LENGTH_20 = 10,
+ HDMI_AUDIO_I2S_INPUT_LENGTH_21 = 13,
+ HDMI_AUDIO_I2S_INPUT_LENGTH_22 = 5,
+ HDMI_AUDIO_I2S_INPUT_LENGTH_23 = 9,
+ HDMI_AUDIO_I2S_INPUT_LENGTH_24 = 11,
+ HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0,
+ HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1
+};
+
+enum hdmi_audio_mclk_mode {
+ HDMI_AUDIO_MCLK_128FS = 0,
+ HDMI_AUDIO_MCLK_256FS = 1,
+ HDMI_AUDIO_MCLK_384FS = 2,
+ HDMI_AUDIO_MCLK_512FS = 3,
+ HDMI_AUDIO_MCLK_768FS = 4,
+ HDMI_AUDIO_MCLK_1024FS = 5,
+ HDMI_AUDIO_MCLK_1152FS = 6,
+ HDMI_AUDIO_MCLK_192FS = 7
+};
+
struct hdmi_core_video_config {
enum hdmi_core_inputbus_width ip_bus_width;
enum hdmi_core_dither_trunc op_dither_truc;
@@ -376,6 +526,26 @@ struct hdmi_core_infoframe_avi {
u16 db12_13_pixel_sofright;
/* Pixel number start of right bar */
};
+/*
+ * Refer to section 8.2 in HDMI 1.3 specification for
+ * details about infoframe databytes
+ */
+struct hdmi_core_infoframe_audio {
+ u8 db1_coding_type;
+ /* Audio coding type */
+ u8 db1_channel_count;
+ /* Number of channels */
+ u8 db2_sample_freq;
+ /* Sample frequency */
+ u8 db2_sample_size;
+ /* Sample size */
+ u8 db4_channel_alloc;
+ /* Channel allocation code */
+ bool db5_downmix_inh;
+ /* Downmix inhibit flag */
+ u8 db5_lsv;
+ /* Level shift values for downmix */
+};
struct hdmi_core_packet_enable_repeat {
u32 audio_pkt;
@@ -412,4 +582,52 @@ struct hdmi_config {
struct hdmi_cm cm;
};
+struct hdmi_audio_format {
+ enum hdmi_stereo_channels stereo_channels;
+ u8 active_chnnls_msk;
+ enum hdmi_audio_type type;
+ enum hdmi_audio_justif justif;
+ enum hdmi_audio_sample_order sample_order;
+ enum hdmi_audio_samples_perword samples_p_word;
+ enum hdmi_audio_sample_size sample_size;
+ enum hdmi_audio_blk_strt_end_sig sig_blk_strt_end;
+};
+
+struct hdmi_audio_dma {
+ u8 transfer_size;
+ u8 block_size;
+ enum hdmi_audio_transf_mode mode;
+ u16 threshold;
+};
+
+struct hdmi_core_audio_i2s_config {
+ u8 word_max_length;
+ u8 word_length;
+ u8 in_length_bits;
+ u8 justif;
+ u8 en_high_br_aud;
+ u8 sck_edge_mode;
+ u8 cbit_order;
+ u8 vbit;
+ u8 ws_polarity;
+ u8 direction;
+ u8 shift;
+};
+
+struct hdmi_core_audio_config {
+ struct hdmi_core_audio_i2s_config i2s_cfg;
+ enum hdmi_core_audio_sample_freq freq_sample;
+ bool fs_override;
+ u32 n;
+ u32 cts;
+ u32 aud_par_busclk;
+ enum hdmi_core_audio_layout layout;
+ enum hdmi_core_cts_mode cts_mode;
+ bool use_mclk;
+ enum hdmi_audio_mclk_mode mclk_mode;
+ bool en_acr_pkt;
+ bool en_direct_strm_dig_aud;
+ bool en_parallel_aud;
+ bool en_spdif;
+};
#endif
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 8e35a5bae42..43009e57cd3 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -769,16 +769,10 @@ static struct platform_driver omap_venchw_driver = {
int venc_init_platform_driver(void)
{
- if (cpu_is_omap44xx())
- return 0;
-
return platform_driver_register(&omap_venchw_driver);
}
void venc_uninit_platform_driver(void)
{
- if (cpu_is_omap44xx())
- return;
-
return platform_driver_unregister(&omap_venchw_driver);
}
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 505ec667204..2bd90ca93d6 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -29,6 +29,7 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/omapfb.h>
+#include <linux/console.h>
#include <plat/display.h>
#include <plat/vram.h>
@@ -1902,6 +1903,94 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev)
kfree(fbdev);
}
+static void size_notify(struct fb_info *fbi, int w, int h)
+{
+ struct omapfb_info *ofbi = FB2OFB(fbi);
+ struct fb_var_screeninfo var = fbi->var;
+ struct fb_var_screeninfo saved_var = fbi->var;
+ int orig_flags;
+ int new_size = (w * var.bits_per_pixel >> 3) * h;
+
+ DBG("size_notify: %dx%d\n", w, h);
+
+ var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_ALL | FB_ACTIVATE_NOW;
+ var.xres = w;
+ var.yres = h;
+ var.xres_virtual = w;
+ var.yres_virtual = h;
+
+ console_lock();
+
+ /* Try to increase memory allocated for FB, if needed */
+ if (new_size > ofbi->region->size) {
+ DBG("re-allocating FB - old size: %ld - new size: %d\n", ofbi->region->size, new_size);
+ omapfb_get_mem_region(ofbi->region);
+ omapfb_realloc_fbmem(fbi, new_size, 0);
+ omapfb_put_mem_region(ofbi->region);
+ }
+
+ /* this ensures fbdev clients, like the console driver, get notified about
+ * the change:
+ */
+ orig_flags = fbi->flags;
+ fbi->flags |= FBINFO_MISC_USEREVENT;
+ fb_set_var(fbi, &var);
+ fbi->flags &= ~FBINFO_MISC_USEREVENT;
+
+ /* now delete old mode:
+ */
+ saved_var.activate |= FB_ACTIVATE_INV_MODE;
+ fbi->flags |= FBINFO_MISC_USEREVENT;
+ fb_set_var(fbi, &saved_var);
+ fbi->flags = orig_flags;
+
+ console_unlock();
+}
+
+struct omapfb_notifier_block {
+ struct notifier_block notifier;
+ struct omapfb2_device *fbdev;
+};
+
+static int omapfb_notifier(struct notifier_block *nb,
+ unsigned long evt, void *arg)
+{
+ struct omapfb_notifier_block *notifier =
+ container_of(nb, struct omapfb_notifier_block, notifier);
+ struct omap_dss_device *dssdev = arg;
+ struct omapfb2_device *fbdev = notifier->fbdev;
+ int keep = false;
+ int i;
+
+ /* figure out if this event pertains to this omapfb device:
+ */
+ for (i = 0; i < fbdev->num_managers; i++) {
+ if (fbdev->managers[i]->device == dssdev) {
+ keep = true;
+ break;
+ }
+ }
+
+ if (!keep)
+ return NOTIFY_DONE;
+
+ /* the event pertains to us.. see if we care:
+ */
+ switch (evt) {
+ case OMAP_DSS_SIZE_CHANGE: {
+ u16 w, h;
+ dssdev->driver->get_resolution(dssdev, &w, &h);
+ for (i = 0; i < fbdev->num_fbs; i++)
+ size_notify(fbdev->fbs[i], w, h);
+ break;
+ }
+ default: /* don't care about other events for now */
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
{
int r, i;
@@ -2227,6 +2316,7 @@ static int omapfb_probe(struct platform_device *pdev)
fbdev->num_displays = 0;
dssdev = NULL;
for_each_dss_dev(dssdev) {
+ struct omapfb_notifier_block *notifier;
omap_dss_get_device(dssdev);
if (!dssdev->driver) {
@@ -2235,7 +2325,12 @@ static int omapfb_probe(struct platform_device *pdev)
}
fbdev->displays[fbdev->num_displays++] = dssdev;
- }
+
+ notifier = kzalloc(sizeof(struct omapfb_notifier_block), GFP_KERNEL);
+ notifier->notifier.notifier_call = omapfb_notifier;
+ notifier->fbdev = fbdev;
+ omap_dss_add_notify(dssdev, &notifier->notifier);
+ }
if (r)
goto cleanup;
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 348843b8015..5edb34458d7 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -896,7 +896,7 @@ struct drm_driver {
int num_ioctls;
struct file_operations fops;
struct pci_driver pci_driver;
- struct platform_device *platform_device;
+ struct platform_driver platform_driver;
/* List of devices hanging off this driver */
struct list_head device_list;
};
@@ -1656,6 +1656,8 @@ static inline void *drm_get_device(struct drm_device *dev)
extern int drm_platform_init(struct drm_driver *driver);
extern int drm_pci_init(struct drm_driver *driver);
+extern void drm_platform_exit(struct drm_driver *driver);
+extern void drm_pci_exit(struct drm_driver *driver);
extern int drm_fill_in_dev(struct drm_device *dev,
const struct pci_device_id *ent,
struct drm_driver *driver);
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index 0c0d1ae7998..edf6edeee51 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -645,11 +645,21 @@ struct twl4030_codec_audio_data {
unsigned int check_defaults:1;
unsigned int reset_registers:1;
unsigned int hs_extmute:1;
+ u16 left_step_hs;
+ u16 right_step_hs;
+ u16 left_step_hf;
+ u16 right_step_hf;
void (*set_hs_extmute)(int mute);
};
struct twl4030_codec_vibra_data {
unsigned int coexist;
+
+ /* timed-output based implementations */
+ int max_timeout;
+ int initial_vibrate;
+ int (*init)(void);
+ void (*exit)(void);
};
struct twl4030_codec_data {
@@ -660,6 +670,7 @@ struct twl4030_codec_data {
/* twl6040 */
int audpwron_gpio; /* audio power-on gpio */
int naudint_irq; /* audio interrupt */
+ unsigned int irq_base;
};
struct twl4030_platform_data {
diff --git a/include/linux/mfd/twl6040-codec.h b/include/linux/mfd/twl6040-codec.h
new file mode 100644
index 00000000000..5d0fb100072
--- /dev/null
+++ b/include/linux/mfd/twl6040-codec.h
@@ -0,0 +1,243 @@
+/*
+ * MFD driver for twl6040 codec submodule
+ *
+ * Authors: Jorge Eduardo Candelaria <jorge.candelaria@ti.com>
+ * Misael Lopez Cruz <misael.lopez@ti.com>
+ *
+ * Copyright: (C) 2011 Texas Instruments, Inc.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TWL6040_CODEC_H__
+#define __TWL6040_CODEC_H__
+
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+
+#define TWL6040_REG_ASICID 0x01
+#define TWL6040_REG_ASICREV 0x02
+#define TWL6040_REG_INTID 0x03
+#define TWL6040_REG_INTMR 0x04
+#define TWL6040_REG_NCPCTL 0x05
+#define TWL6040_REG_LDOCTL 0x06
+#define TWL6040_REG_HPPLLCTL 0x07
+#define TWL6040_REG_LPPLLCTL 0x08
+#define TWL6040_REG_LPPLLDIV 0x09
+#define TWL6040_REG_AMICBCTL 0x0A
+#define TWL6040_REG_DMICBCTL 0x0B
+#define TWL6040_REG_MICLCTL 0x0C
+#define TWL6040_REG_MICRCTL 0x0D
+#define TWL6040_REG_MICGAIN 0x0E
+#define TWL6040_REG_LINEGAIN 0x0F
+#define TWL6040_REG_HSLCTL 0x10
+#define TWL6040_REG_HSRCTL 0x11
+#define TWL6040_REG_HSGAIN 0x12
+#define TWL6040_REG_EARCTL 0x13
+#define TWL6040_REG_HFLCTL 0x14
+#define TWL6040_REG_HFLGAIN 0x15
+#define TWL6040_REG_HFRCTL 0x16
+#define TWL6040_REG_HFRGAIN 0x17
+#define TWL6040_REG_VIBCTLL 0x18
+#define TWL6040_REG_VIBDATL 0x19
+#define TWL6040_REG_VIBCTLR 0x1A
+#define TWL6040_REG_VIBDATR 0x1B
+#define TWL6040_REG_HKCTL1 0x1C
+#define TWL6040_REG_HKCTL2 0x1D
+#define TWL6040_REG_GPOCTL 0x1E
+#define TWL6040_REG_ALB 0x1F
+#define TWL6040_REG_DLB 0x20
+#define TWL6040_REG_TRIM1 0x28
+#define TWL6040_REG_TRIM2 0x29
+#define TWL6040_REG_TRIM3 0x2A
+#define TWL6040_REG_HSOTRIM 0x2B
+#define TWL6040_REG_HFOTRIM 0x2C
+#define TWL6040_REG_ACCCTL 0x2D
+#define TWL6040_REG_STATUS 0x2E
+
+#define TWL6040_CACHEREGNUM (TWL6040_REG_STATUS + 1)
+
+#define TWL6040_VIOREGNUM 18
+#define TWL6040_VDDREGNUM 21
+
+/* INTID (0x03) fields */
+
+#define TWL6040_THINT 0x01
+#define TWL6040_PLUGINT 0x02
+#define TWL6040_UNPLUGINT 0x04
+#define TWL6040_HOOKINT 0x08
+#define TWL6040_HFINT 0x10
+#define TWL6040_VIBINT 0x20
+#define TWL6040_READYINT 0x40
+
+/* INTMR (0x04) fields */
+
+#define TWL6040_THMSK 0x01
+#define TWL6040_PLUGMSK 0x02
+#define TWL6040_HOOKMSK 0x08
+#define TWL6040_HFMSK 0x10
+#define TWL6040_VIBMSK 0x20
+#define TWL6040_READYMSK 0x40
+#define TWL6040_ALLINT_MSK 0x7B
+
+/* NCPCTL (0x05) fields */
+
+#define TWL6040_NCPENA 0x01
+#define TWL6040_NCPOPEN 0x40
+
+/* LDOCTL (0x06) fields */
+
+#define TWL6040_LSLDOENA 0x01
+#define TWL6040_HSLDOENA 0x04
+#define TWL6040_REFENA 0x40
+#define TWL6040_OSCENA 0x80
+
+/* HPPLLCTL (0x07) fields */
+
+#define TWL6040_HPLLENA 0x01
+#define TWL6040_HPLLRST 0x02
+#define TWL6040_HPLLBP 0x04
+#define TWL6040_HPLLSQRENA 0x08
+#define TWL6040_HPLLSQRBP 0x10
+#define TWL6040_MCLK_12000KHZ (0 << 5)
+#define TWL6040_MCLK_19200KHZ (1 << 5)
+#define TWL6040_MCLK_26000KHZ (2 << 5)
+#define TWL6040_MCLK_38400KHZ (3 << 5)
+#define TWL6040_MCLK_MSK 0x60
+
+/* LPPLLCTL (0x08) fields */
+
+#define TWL6040_LPLLENA 0x01
+#define TWL6040_LPLLRST 0x02
+#define TWL6040_LPLLSEL 0x04
+#define TWL6040_LPLLFIN 0x08
+#define TWL6040_HPLLSEL 0x10
+
+/* HSLCTL (0x10) fields */
+
+#define TWL6040_HSDACMODEL 0x02
+#define TWL6040_HSDRVMODEL 0x08
+
+/* HSRCTL (0x11) fields */
+
+#define TWL6040_HSDACMODER 0x02
+#define TWL6040_HSDRVMODER 0x08
+
+/* VIBCTLL (0x18) fields */
+
+#define TWL6040_VIBCTRLLN 0x10
+#define TWL6040_VIBCTRLLP 0x04
+#define TWL6040_VIBENAL 0x01
+
+/* VIBCTLL (0x19) fields */
+
+#define TWL6040_VIBCTRLRN 0x10
+#define TWL6040_VIBCTRLRP 0x04
+#define TWL6040_VIBENAR 0x01
+
+/* GPOCTL (0x1E) fields */
+
+#define TWL6040_GPO1 0x01
+#define TWL6040_GPO2 0x02
+#define TWL6040_GPO3 0x03
+
+/* ACCCTL (0x2D) fields */
+
+#define TWL6040_I2CSEL 0x01
+#define TWL6040_RESETSPLIT 0x04
+#define TWL6040_INTCLRMODE 0x08
+
+#define TWL6040_SYSCLK_SEL_LPPLL 1
+#define TWL6040_SYSCLK_SEL_HPPLL 2
+
+/* STATUS (0x2E) fields */
+
+#define TWL6040_PLUGCOMP 0x02
+
+#define TWL6040_CELLS 2
+
+#define TWL6040_IRQ_TH 0
+#define TWL6040_IRQ_PLUG 1
+#define TWL6040_IRQ_HOOK 2
+#define TWL6040_IRQ_HF 3
+#define TWL6040_IRQ_VIB 4
+#define TWL6040_IRQ_READY 5
+
+enum twl6040_pll_id {
+ TWL6040_NOPLL_ID,
+ TWL6040_LPPLL_ID,
+ TWL6040_HPPLL_ID,
+};
+
+struct twl6040 {
+ struct device *dev;
+ struct mutex mutex;
+ struct mutex io_mutex;
+ struct mutex irq_mutex;
+ struct mfd_cell cells[TWL6040_CELLS];
+ struct completion ready;
+
+ int audpwron;
+ int powered;
+ int power_count;
+
+ enum twl6040_pll_id pll;
+ unsigned int sysclk;
+
+ unsigned int irq;
+ unsigned int irq_base;
+ u8 irq_masks_cur;
+ u8 irq_masks_cache;
+};
+
+static inline int twl6040_request_irq(struct twl6040 *twl6040, int irq,
+ irq_handler_t handler, const char *name,
+ void *data)
+{
+ if (!twl6040->irq_base)
+ return -EINVAL;
+
+ return request_threaded_irq(twl6040->irq_base + irq, NULL, handler,
+ 0, name, data);
+}
+
+static inline void twl6040_free_irq(struct twl6040 *twl6040, int irq,
+ void *data)
+{
+ if (!twl6040->irq_base)
+ return;
+
+ free_irq(twl6040->irq_base + irq, data);
+}
+
+int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg);
+int twl6040_reg_write(struct twl6040 *twl6040, unsigned int reg,
+ u8 val);
+int twl6040_set_bits(struct twl6040 *twl6040, unsigned int reg,
+ u8 mask);
+int twl6040_clear_bits(struct twl6040 *twl6040, unsigned int reg,
+ u8 mask);
+int twl6040_enable(struct twl6040 *twl6040);
+int twl6040_disable(struct twl6040 *twl6040);
+int twl6040_is_enabled(struct twl6040 *twl6040);
+int twl6040_set_pll(struct twl6040 *twl6040, enum twl6040_pll_id id,
+ unsigned int freq_in, unsigned int freq_out);
+enum twl6040_pll_id twl6040_get_pll(struct twl6040 *twl6040);
+unsigned int twl6040_get_sysclk(struct twl6040 *twl6040);
+int twl6040_irq_init(struct twl6040 *twl6040);
+void twl6040_irq_exit(struct twl6040 *twl6040);
+
+#endif /* End of __TWL6040_CODEC_H__ */
diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h
index 4c7be226301..36310070a85 100644
--- a/include/linux/ti_wilink_st.h
+++ b/include/linux/ti_wilink_st.h
@@ -26,15 +26,6 @@
#define TI_WILINK_ST_H
/**
- * enum kim_gpio_state - Few protocols such as FM have ACTIVE LOW
- * gpio states for their chip/core enable gpios
- */
-enum kim_gpio_state {
- KIM_GPIO_INACTIVE,
- KIM_GPIO_ACTIVE,
-};
-
-/**
* enum proto-type - The protocol on WiLink chips which share a
* common physical interface like UART.
*/
@@ -42,7 +33,7 @@ enum proto_type {
ST_BT,
ST_FM,
ST_GPS,
- ST_MAX,
+ ST_MAX_CHANNELS = 16,
};
/**
@@ -62,6 +53,17 @@ enum proto_type {
* @priv_data: privdate data holder for the protocol drivers, sent
* from the protocol drivers during registration, and sent back on
* reg_complete_cb and recv.
+ * @chnl_id: channel id the protocol driver is interested in, the channel
+ * id is nothing but the 1st byte of the packet in UART frame.
+ * @max_frame_size: size of the largest frame the protocol can receive.
+ * @hdr_len: length of the header structure of the protocol.
+ * @offset_len_in_hdr: this provides the offset of the length field in the
+ * header structure of the protocol header, to assist ST to know
+ * how much to receive, if the data is split across UART frames.
+ * @len_size: whether the length field inside the header is 2 bytes
+ * or 1 byte.
+ * @reserve: the number of bytes ST needs to reserve in the skb being
+ * prepared for the protocol driver.
*/
struct st_proto_s {
enum proto_type type;
@@ -70,10 +72,17 @@ struct st_proto_s {
void (*reg_complete_cb) (void *, char data);
long (*write) (struct sk_buff *skb);
void *priv_data;
+
+ unsigned char chnl_id;
+ unsigned short max_frame_size;
+ unsigned char hdr_len;
+ unsigned char offset_len_in_hdr;
+ unsigned char len_size;
+ unsigned char reserve;
};
extern long st_register(struct st_proto_s *);
-extern long st_unregister(enum proto_type);
+extern long st_unregister(struct st_proto_s *);
/*
@@ -114,6 +123,7 @@ extern long st_unregister(enum proto_type);
* @rx_skb: the skb where all data for a protocol gets accumulated,
* since tty might not call receive when a complete event packet
* is received, the states, count and the skb needs to be maintained.
+ * @rx_chnl: the channel ID for which the data is getting accumalated for.
* @txq: the list of skbs which needs to be sent onto the TTY.
* @tx_waitq: if the chip is not in AWAKE state, the skbs needs to be queued
* up in here, PM(WAKEUP_IND) data needs to be sent and then the skbs
@@ -135,10 +145,11 @@ struct st_data_s {
#define ST_TX_SENDING 1
#define ST_TX_WAKEUP 2
unsigned long tx_state;
- struct st_proto_s *list[ST_MAX];
+ struct st_proto_s *list[ST_MAX_CHANNELS];
unsigned long rx_state;
unsigned long rx_count;
struct sk_buff *rx_skb;
+ unsigned char rx_chnl;
struct sk_buff_head txq, tx_waitq;
spinlock_t lock;
unsigned char protos_registered;
@@ -146,6 +157,11 @@ struct st_data_s {
void *kim_data;
};
+/*
+ * wrapper around tty->ops->write_room to check
+ * availability during firmware download
+ */
+int st_get_uart_wr_room(struct st_data_s *st_gdata);
/**
* st_int_write -
* point this to tty->driver->write or tty->ops->write
@@ -186,8 +202,9 @@ void gps_chrdrv_stub_init(void);
/* time in msec to wait for
* line discipline to be installed
*/
-#define LDISC_TIME 500
-#define CMD_RESP_TIME 500
+#define LDISC_TIME 1000
+#define CMD_RESP_TIME 800
+#define CMD_WR_TIME 5000
#define MAKEWORD(a, b) ((unsigned short)(((unsigned char)(a)) \
| ((unsigned short)((unsigned char)(b))) << 8))
@@ -198,7 +215,7 @@ void gps_chrdrv_stub_init(void);
* to download firmware onto chip more than once
* since the self-test for chip takes a while
*/
-#define POR_RETRY_COUNT 5
+#define POR_RETRY_COUNT 10
/**
* struct chip_version - save the chip version
@@ -210,6 +227,7 @@ struct chip_version {
unsigned short maj_ver;
};
+#define UART_DEV_NAME_LEN 32
/**
* struct kim_data_s - the KIM internal data, embedded as the
* platform's drv data. One for each ST device in the system.
@@ -225,14 +243,11 @@ struct chip_version {
* the ldisc was properly installed.
* @resp_buffer: data buffer for the .bts fw file name.
* @fw_entry: firmware class struct to request/release the fw.
- * @gpios: the list of core/chip enable gpios for BT, FM and GPS cores.
* @rx_state: the rx state for kim's receive func during fw download.
* @rx_count: the rx count for the kim's receive func during fw download.
* @rx_skb: all of fw data might not come at once, and hence data storage for
* whole of the fw response, only HCI_EVENTs and hence diff from ST's
* response.
- * @rfkill: rfkill data for each of the cores to be registered with rfkill.
- * @rf_protos: proto types of the data registered with rfkill sub-system.
* @core_data: ST core's data, which mainly is the tty's disc_data
* @version: chip version available via a sysfs entry.
*
@@ -243,14 +258,16 @@ struct kim_data_s {
struct completion kim_rcvd, ldisc_installed;
char resp_buffer[30];
const struct firmware *fw_entry;
- long gpios[ST_MAX];
+ long nshutdown;
unsigned long rx_state;
unsigned long rx_count;
struct sk_buff *rx_skb;
- struct rfkill *rfkill[ST_MAX];
- enum proto_type rf_protos[ST_MAX];
struct st_data_s *core_data;
struct chip_version version;
+ unsigned char ldisc_install;
+ unsigned char dev_name[UART_DEV_NAME_LEN];
+ unsigned char flow_cntrl;
+ unsigned long baud_rate;
};
/**
@@ -262,7 +279,6 @@ long st_kim_start(void *);
long st_kim_stop(void *);
void st_kim_recv(void *, const unsigned char *, long count);
-void st_kim_chip_toggle(enum proto_type, enum kim_gpio_state);
void st_kim_complete(void *);
void kim_st_list_protocols(struct st_data_s *, void *);
@@ -338,12 +354,8 @@ struct hci_command {
/* ST LL receiver states */
#define ST_W4_PACKET_TYPE 0
-#define ST_BT_W4_EVENT_HDR 1
-#define ST_BT_W4_ACL_HDR 2
-#define ST_BT_W4_SCO_HDR 3
-#define ST_BT_W4_DATA 4
-#define ST_FM_W4_EVENT_HDR 5
-#define ST_GPS_W4_EVENT_HDR 6
+#define ST_W4_HEADER 1
+#define ST_W4_DATA 2
/* ST LL state machines */
#define ST_LL_ASLEEP 0
@@ -397,4 +409,14 @@ struct gps_event_hdr {
u16 plen;
} __attribute__ ((packed));
+/* platform data */
+struct ti_st_plat_data {
+ long nshutdown_gpio;
+ unsigned char dev_name[UART_DEV_NAME_LEN]; /* uart name */
+ unsigned char flow_cntrl; /* flow control flag */
+ unsigned long baud_rate;
+ int (*suspend)(struct platform_device *, pm_message_t);
+ int (*resume)(struct platform_device *);
+};
+
#endif /* TI_WILINK_ST_H */
diff --git a/include/linux/twl6040-vib.h b/include/linux/twl6040-vib.h
new file mode 100644
index 00000000000..0a85a67afe2
--- /dev/null
+++ b/include/linux/twl6040-vib.h
@@ -0,0 +1,30 @@
+/* drivers/misc/twl6040-vib.h
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Dan Murphy <dmurphy@ti.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Derived from: vib-gpio.h
+ */
+
+#ifndef _LINUX_TWL6040_VIB_H
+#define _LINUX_TWL6040_VIB_H
+
+#ifdef __KERNEL__
+
+#define VIB_NAME "vib-twl6040"
+
+#endif /* __KERNEL__ */
+
+void vibrator_haptic_fire(int value);
+
+#endif /* _LINUX_TWL6040_VIB_H */
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 29a7a8ca043..c4f4c42d120 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -76,6 +76,7 @@ enum {
HCI_INQUIRY,
HCI_RAW,
+ HCI_RESET,
};
/* HCI ioctl defines */
diff --git a/include/sound/omap-abe-dsp.h b/include/sound/omap-abe-dsp.h
new file mode 100644
index 00000000000..04dae9b3e7c
--- /dev/null
+++ b/include/sound/omap-abe-dsp.h
@@ -0,0 +1,19 @@
+/*
+ * omap-aess -- OMAP4 ABE DSP
+ *
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ */
+
+#ifndef _OMAP4_ABE_DSP_H
+#define _OMAP4_ABE_DSP_H
+
+struct omap4_abe_dsp_pdata {
+ /* Return context loss count due to PM states changing */
+ int (*get_context_loss_count)(struct device *dev);
+};
+
+#endif
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index ec2678131e1..5c544bdb9e1 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -412,6 +412,7 @@ struct snd_pcm_substream {
#endif
/* misc flags */
unsigned int hw_opened: 1;
+ unsigned int hw_no_buffer: 1; /* substream may not have a buffer */
};
#define SUBSTREAM_BUSY(substream) ((substream)->ref_count > 0)
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 1bafe95dcf4..af9a5519e33 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -277,4 +277,53 @@ static inline void *snd_soc_dai_get_drvdata(struct snd_soc_dai *dai)
return dev_get_drvdata(dai->dev);
}
+/* Backend DAI PCM ops */
+static inline int snd_soc_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ if (dai->driver->ops->startup)
+ return dai->driver->ops->startup(substream, dai);
+ return 0;
+}
+
+static inline void snd_soc_dai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ if (dai->driver->ops->shutdown)
+ dai->driver->ops->shutdown(substream, dai);
+}
+
+static inline int snd_soc_dai_hw_params(struct snd_pcm_substream * substream,
+ struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai)
+{
+ if (dai->driver->ops->hw_params)
+ return dai->driver->ops->hw_params(substream, hw_params, dai);
+ return 0;
+}
+
+static inline int snd_soc_dai_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ if (dai->driver->ops->hw_free)
+ return dai->driver->ops->hw_free(substream, dai);
+ return 0;
+}
+
+static inline int snd_soc_dai_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ if (dai->driver->ops->prepare)
+ return dai->driver->ops->prepare(substream, dai);
+ return 0;
+}
+
+static inline int snd_soc_dai_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ if (dai->driver->ops->trigger)
+ return dai->driver->ops->trigger(substream, cmd, dai);
+ return 0;
+}
+
+
#endif
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 60f94fbd3a1..b45ca9bfca4 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -254,6 +254,12 @@
.get = snd_soc_dapm_get_enum_virt, \
.put = snd_soc_dapm_put_enum_virt, \
.private_value = (unsigned long)&xenum }
+#define SOC_DAPM_ENUM_EXT(xname, xenum, xget, xput) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_enum_double, \
+ .get = xget, \
+ .put = xput, \
+ .private_value = (unsigned long)&xenum }
#define SOC_DAPM_VALUE_ENUM(xname, xenum) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_enum_double, \
@@ -336,12 +342,23 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm);
void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num);
+int snd_soc_scenario_set_path(struct snd_soc_dapm_context *dapm,
+ const char *source_name, const char *sink_name, int stream);
+const char *snd_soc_dapm_get_aif(struct snd_soc_dapm_context *dapm,
+ const char *stream_name, enum snd_soc_dapm_type type);
/* dapm events */
int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
- const char *stream, int event);
+ int dir, const char *stream, int event);
void snd_soc_dapm_shutdown(struct snd_soc_card *card);
+/* external DAPM widget events */
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+ struct snd_kcontrol *kcontrol, int connect);
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+ struct snd_kcontrol *kcontrol, int change,
+ int mux, struct soc_enum *e);
+
/* dapm sys fs - used by the core */
int snd_soc_dapm_sys_add(struct device *dev);
void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm);
@@ -416,6 +433,7 @@ struct snd_soc_dapm_path {
/* status */
u32 connect:1; /* source and sink widgets are connected */
u32 walked:1; /* path has been walked */
+ u32 length:6; /* path length - used by route mapper */
int (*connected)(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink);
@@ -431,6 +449,7 @@ struct snd_soc_dapm_widget {
char *name; /* widget name */
char *sname; /* stream name */
struct snd_soc_codec *codec;
+ struct snd_soc_platform *platform;
struct list_head list;
struct snd_soc_dapm_context *dapm;
@@ -439,6 +458,8 @@ struct snd_soc_dapm_widget {
unsigned char shift; /* bits to shift */
unsigned int saved_value; /* widget saved value */
unsigned int value; /* widget current value */
+ unsigned int path_idx;
+ unsigned int hops;
unsigned int mask; /* non-shifted mask */
unsigned int on_val; /* on state value */
unsigned int off_val; /* off state value */
@@ -480,6 +501,7 @@ struct snd_soc_dapm_update {
/* DAPM context */
struct snd_soc_dapm_context {
int n_widgets; /* number of widgets in this context */
+ int num_valid_paths;
enum snd_soc_bias_level bias_level;
enum snd_soc_bias_level suspend_bias_level;
struct delayed_work delayed_work;
@@ -489,6 +511,8 @@ struct snd_soc_dapm_context {
struct device *dev; /* from parent - for debug */
struct snd_soc_codec *codec; /* parent codec */
+ struct snd_soc_platform *platform; /*parent platform */
+ int (*stream_event)(struct snd_soc_dapm_context *dapm);
struct snd_soc_card *card; /* parent card */
/* used during DAPM updates */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 74921f20a1d..41b931a0c52 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -235,6 +235,7 @@ struct snd_soc_codec_driver;
struct soc_enum;
struct snd_soc_jack;
struct snd_soc_jack_pin;
+struct snd_soc_dapm_context;
struct snd_soc_cache_ops;
#include <sound/soc-dapm.h>
@@ -257,6 +258,12 @@ enum snd_soc_compress_type {
SND_SOC_LZO_COMPRESSION,
SND_SOC_RBTREE_COMPRESSION
};
+/* Max number of Backend DAIs */
+#define SND_SOC_MAX_BE 8
+
+/* DAI Link Host Mode Support */
+#define SND_SOC_DAI_LINK_NO_HOST 0x1
+#define SND_SOC_DAI_LINK_OPT_HOST 0x2
int snd_soc_register_platform(struct device *dev,
struct snd_soc_platform_driver *platform_drv);
@@ -277,6 +284,24 @@ int snd_soc_cache_write(struct snd_soc_codec *codec,
int snd_soc_cache_read(struct snd_soc_codec *codec,
unsigned int reg, unsigned int *value);
+/* pcm <-> DAI connect */
+void snd_soc_free_pcms(struct snd_soc_codec *codec);
+int snd_soc_new_pcms(struct snd_soc_codec *codec, int idx, const char *xid);
+
+/* DAI operations - for backend DAIs */
+int snd_soc_pcm_open(struct snd_pcm_substream *substream);
+int snd_soc_pcm_close(struct snd_pcm_substream *substream);
+int snd_soc_pcm_prepare(struct snd_pcm_substream *substream);
+int snd_soc_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params);
+int snd_soc_pcm_hw_free(struct snd_pcm_substream *substream);
+int snd_soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
+snd_pcm_uframes_t snd_soc_pcm_pointer(struct snd_pcm_substream *substream);
+struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
+ const char *dai_link, int stream);
+struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
+ const char *dai_link);
+
/* Utility functions to get clock rates from various things */
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
@@ -324,6 +349,8 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
void *data, char *long_name);
int snd_soc_add_controls(struct snd_soc_codec *codec,
const struct snd_kcontrol_new *controls, int num_controls);
+int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
+ const struct snd_kcontrol_new *controls, int num_controls);
int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
@@ -519,6 +546,8 @@ struct snd_soc_codec_driver {
/* codec bias level */
int (*set_bias_level)(struct snd_soc_codec *,
enum snd_soc_bias_level level);
+ /* codec stream completion event */
+ int (*stream_event)(struct snd_soc_dapm_context *dapm);
};
/* SoC platform interface */
@@ -530,8 +559,7 @@ struct snd_soc_platform_driver {
int (*resume)(struct snd_soc_dai *dai);
/* pcm creation and destruction */
- int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
- struct snd_pcm *);
+ int (*pcm_new)(struct snd_soc_pcm_runtime *);
void (*pcm_free)(struct snd_pcm *);
/*
@@ -543,6 +571,13 @@ struct snd_soc_platform_driver {
/* platform stream ops */
struct snd_pcm_ops *ops;
+
+ /* platform DAPM IO TODO: refactor this */
+ unsigned int (*read)(struct snd_soc_platform *, unsigned int);
+ int (*write)(struct snd_soc_platform *, unsigned int, unsigned int);
+
+ /* platform stream completion event */
+ int (*stream_event)(struct snd_soc_dapm_context *dapm);
};
struct snd_soc_platform {
@@ -557,6 +592,10 @@ struct snd_soc_platform {
struct snd_soc_card *card;
struct list_head list;
struct list_head card_list;
+ int num_dai;
+
+ /* dapm */
+ struct snd_soc_dapm_context dapm;
};
struct snd_soc_dai_link {
@@ -568,15 +607,36 @@ struct snd_soc_dai_link {
const char *cpu_dai_name;
const char *codec_dai_name;
+ /* supported BE */
+ const char **supported_be;
+ int num_be;
+ int fe_playback_channels;
+ int fe_capture_channels;
+
+
/* Keep DAI active over suspend */
unsigned int ignore_suspend:1;
/* Symmetry requirements */
unsigned int symmetric_rates:1;
+ /* No PCM created for this DAI link */
+ unsigned int no_pcm:1;
+ /* This DAI link can change CODEC and platform at runtime*/
+ unsigned int dynamic:1;
+ /* This DAI link has no codec side driver*/
+ unsigned int no_codec:1;
+ /* This DAI has a Backend ID */
+ unsigned int be_id;
+ /* This DAI can support no host IO (no pcm data is copied to from host) */
+ unsigned int no_host_mode:2;
/* codec/machine specific init - e.g. add machine controls */
int (*init)(struct snd_soc_pcm_runtime *rtd);
+ /* hw_params re-writing for BE and FE sync */
+ int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params);
+
/* machine stream operations */
struct snd_soc_ops *ops;
};
@@ -608,12 +668,14 @@ struct snd_soc_aux_dev {
/* SoC card */
struct snd_soc_card {
const char *name;
+ const char *long_name;
struct device *dev;
struct snd_card *snd_card;
struct module *owner;
struct list_head list;
struct mutex mutex;
+ struct mutex dapm_mutex;
bool instantiated;
@@ -677,10 +739,18 @@ struct snd_soc_pcm_runtime {
struct device dev;
struct snd_soc_card *card;
struct snd_soc_dai_link *dai_link;
+ struct mutex pcm_mutex;
+ struct snd_pcm_ops ops;
unsigned int complete:1;
unsigned int dev_registered:1;
+ /* BE runtime data */
+ unsigned int fe_clients;
+ unsigned int num_be[2];
+ unsigned int be_active;
+ struct snd_soc_pcm_runtime *be_rtd[SND_SOC_MAX_BE][2];
+
/* Symmetry data - only valid if symmetry is being enforced */
unsigned int rate;
long pmdown_time;
@@ -691,6 +761,7 @@ struct snd_soc_pcm_runtime {
struct snd_soc_platform *platform;
struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai;
+ int current_fe;
struct delayed_work delayed_work;
};
@@ -718,6 +789,18 @@ struct soc_enum {
unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
unsigned int snd_soc_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int val);
+/* platform DAPM IO - refactor */
+static inline unsigned int snd_soc_platform_read(struct snd_soc_platform *platform,
+ unsigned int reg)
+{
+ return platform->driver->read(platform, reg);
+}
+
+static inline unsigned int snd_soc_platform_write(struct snd_soc_platform *platform,
+ unsigned int reg, unsigned int val)
+{
+ return platform->driver->write(platform, reg, val);
+}
/* device driver data */
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9c4541bc488..181de200959 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -184,6 +184,7 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
BT_DBG("%s %ld", hdev->name, opt);
/* Reset device */
+ set_bit(HCI_RESET, &hdev->flags);
hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
}
@@ -210,8 +211,10 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
/* Mandatory initialization */
/* Reset */
- if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks))
+ if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
+ set_bit(HCI_RESET, &hdev->flags);
hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
+ }
/* Read Local Supported Features */
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
@@ -1753,6 +1756,7 @@ static void hci_cmd_task(unsigned long arg)
if (!atomic_read(&hdev->cmd_cnt) && time_after(jiffies, hdev->cmd_last_tx + HZ)) {
BT_ERR("%s command tx timeout", hdev->name);
atomic_set(&hdev->cmd_cnt, 1);
+ clear_bit(HCI_RESET, &hdev->flags);
}
/* Send queued commands */
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index a290854fdaa..a63bcf039ee 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -183,6 +183,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%x", hdev->name, status);
+ clear_bit(HCI_RESET, &hdev->flags);
+
hci_req_complete(hdev, HCI_OP_RESET, status);
}
@@ -1464,7 +1466,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
break;
}
- if (ev->ncmd) {
+ if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q))
tasklet_schedule(&hdev->cmd_task);
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 64449cb8f87..c80d36ffd6b 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1933,6 +1933,9 @@ static int pcm_sanity_check(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime;
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
+ /* TODO: consider and -EINVAL here */
+ if (substream->hw_no_buffer)
+ snd_printd("%s: warning this PCM is host less\n", __func__);
runtime = substream->runtime;
if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area))
return -EINVAL;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 6848dd9c70a..c5a97a8958d 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -842,6 +842,7 @@ static int snd_pcm_pre_start(struct snd_pcm_substream *substream, int state)
if (runtime->status->state != SNDRV_PCM_STATE_PREPARED)
return -EBADFD;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+ !substream->hw_no_buffer &&
!snd_pcm_playback_data(substream))
return -EPIPE;
runtime->trigger_master = substream;
@@ -2028,6 +2029,12 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
goto error;
}
+ if (substream->ops == NULL) {
+ snd_printd("cannot open back end PCMs directly\n");
+ err = -ENODEV;
+ goto error;
+ }
+
if ((err = substream->ops->open(substream)) < 0)
goto error;
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
index d0e75323ec1..912558cf732 100644
--- a/sound/soc/atmel/atmel-pcm.c
+++ b/sound/soc/atmel/atmel-pcm.c
@@ -364,9 +364,10 @@ static struct snd_pcm_ops atmel_pcm_ops = {
\*--------------------------------------------------------------------------*/
static u64 atmel_pcm_dmamask = 0xffffffff;
-static int atmel_pcm_new(struct snd_card *card,
- struct snd_soc_dai *dai, struct snd_pcm *pcm)
+static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
int ret = 0;
if (!card->dev->dma_mask)
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index 10fdd2854e5..c675ac8bbcc 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -319,10 +319,10 @@ static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm *pcm)
snd_pcm_lib_preallocate_free_for_all(pcm);
}
-static int au1xpsc_pcm_new(struct snd_card *card,
- struct snd_soc_dai *dai,
- struct snd_pcm *pcm)
+static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1);
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index c48b23c1d4f..7a8e90d4c53 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -203,6 +203,7 @@ config SND_SOC_TWL4030
tristate
config SND_SOC_TWL6040
+ select TWL6040_CODEC
tristate
config SND_SOC_UDA134X
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 4bbf1b15a49..34fcfd46295 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -29,6 +29,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/i2c/twl.h>
+#include <linux/mfd/twl6040-codec.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -77,14 +78,18 @@ struct twl6040_jack_data {
/* codec private data */
struct twl6040_data {
- int audpwron;
- int naudint;
int codec_powered;
int pll;
int non_lp;
+ int power_mode_forced;
+ int headset_mode;
+ unsigned int clk_in;
unsigned int sysclk;
+ u16 left_step_hs;
+ u16 right_step_hs;
+ u16 left_step_hf;
+ u16 right_step_hf;
struct snd_pcm_hw_constraint_list *sysclk_constraints;
- struct completion ready;
struct twl6040_jack_data hs_jack;
struct snd_soc_codec *codec;
struct workqueue_struct *workqueue;
@@ -239,12 +244,13 @@ static inline void twl6040_write_reg_cache(struct snd_soc_codec *codec,
static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
unsigned int reg)
{
+ struct twl6040 *twl6040 = codec->control_data;
u8 value;
if (reg >= TWL6040_CACHEREGNUM)
return -EIO;
- twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &value, reg);
+ value = twl6040_reg_read(twl6040, reg);
twl6040_write_reg_cache(codec, reg, value);
return value;
@@ -256,11 +262,13 @@ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
static int twl6040_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
+ struct twl6040 *twl6040 = codec->control_data;
+
if (reg >= TWL6040_CACHEREGNUM)
return -EIO;
twl6040_write_reg_cache(codec, reg, value);
- return twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, value, reg);
+ return twl6040_reg_write(twl6040, reg, value);
}
static void twl6040_init_vio_regs(struct snd_soc_codec *codec)
@@ -268,15 +276,21 @@ static void twl6040_init_vio_regs(struct snd_soc_codec *codec)
u8 *cache = codec->reg_cache;
int reg, i;
- /* allow registers to be accessed by i2c */
- twl6040_write(codec, TWL6040_REG_ACCCTL, cache[TWL6040_REG_ACCCTL]);
-
for (i = 0; i < TWL6040_VIOREGNUM; i++) {
reg = twl6040_vio_reg[i];
- /* skip read-only registers (ASICID, ASICREV, STATUS) */
+ /*
+ * skip read-only registers (ASICID, ASICREV, STATUS)
+ * and registers shared among MFD children
+ */
switch (reg) {
case TWL6040_REG_ASICID:
case TWL6040_REG_ASICREV:
+ case TWL6040_REG_INTID:
+ case TWL6040_REG_INTMR:
+ case TWL6040_REG_NCPCTL:
+ case TWL6040_REG_LDOCTL:
+ case TWL6040_REG_GPOCTL:
+ case TWL6040_REG_ACCCTL:
case TWL6040_REG_STATUS:
continue;
default:
@@ -293,6 +307,19 @@ static void twl6040_init_vdd_regs(struct snd_soc_codec *codec)
for (i = 0; i < TWL6040_VDDREGNUM; i++) {
reg = twl6040_vdd_reg[i];
+ /* skip vibra and pll registers */
+ switch (reg) {
+ case TWL6040_REG_VIBCTLL:
+ case TWL6040_REG_VIBDATL:
+ case TWL6040_REG_VIBCTLR:
+ case TWL6040_REG_VIBDATR:
+ case TWL6040_REG_HPPLLCTL:
+ case TWL6040_REG_LPPLLCTL:
+ case TWL6040_REG_LPPLLDIV:
+ continue;
+ default:
+ break;
+ }
twl6040_write(codec, reg, cache[reg]);
}
}
@@ -317,7 +344,11 @@ static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
if (headset->ramp == TWL6040_RAMP_UP) {
/* ramp step up */
if (val < headset->left_vol) {
- val += left_step;
+ if (val + left_step > headset->left_vol)
+ val = headset->left_vol;
+ else
+ val += left_step;
+
reg &= ~TWL6040_HSL_VOL_MASK;
twl6040_write(codec, TWL6040_REG_HSGAIN,
(reg | (~val & TWL6040_HSL_VOL_MASK)));
@@ -327,7 +358,11 @@ static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
} else if (headset->ramp == TWL6040_RAMP_DOWN) {
/* ramp step down */
if (val > 0x0) {
- val -= left_step;
+ if ((int)val - (int)left_step < 0)
+ val = 0;
+ else
+ val -= left_step;
+
reg &= ~TWL6040_HSL_VOL_MASK;
twl6040_write(codec, TWL6040_REG_HSGAIN, reg |
(~val & TWL6040_HSL_VOL_MASK));
@@ -344,7 +379,11 @@ static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
if (headset->ramp == TWL6040_RAMP_UP) {
/* ramp step up */
if (val < headset->right_vol) {
- val += right_step;
+ if (val + right_step > headset->right_vol)
+ val = headset->right_vol;
+ else
+ val += right_step;
+
reg &= ~TWL6040_HSR_VOL_MASK;
twl6040_write(codec, TWL6040_REG_HSGAIN,
(reg | (~val << TWL6040_HSR_VOL_SHIFT)));
@@ -354,7 +393,11 @@ static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
} else if (headset->ramp == TWL6040_RAMP_DOWN) {
/* ramp step down */
if (val > 0x0) {
- val -= right_step;
+ if ((int)val - (int)right_step < 0)
+ val = 0;
+ else
+ val -= right_step;
+
reg &= ~TWL6040_HSR_VOL_MASK;
twl6040_write(codec, TWL6040_REG_HSGAIN,
reg | (~val << TWL6040_HSR_VOL_SHIFT));
@@ -385,7 +428,11 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
if (handsfree->ramp == TWL6040_RAMP_UP) {
/* ramp step up */
if (val < handsfree->left_vol) {
- val += left_step;
+ if (val + left_step > handsfree->left_vol)
+ val = handsfree->left_vol;
+ else
+ val += left_step;
+
reg &= ~TWL6040_HF_VOL_MASK;
twl6040_write(codec, TWL6040_REG_HFLGAIN,
reg | (0x1D - val));
@@ -395,7 +442,11 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
} else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
/* ramp step down */
if (val > 0) {
- val -= left_step;
+ if ((int)val - (int)left_step < 0)
+ val = 0;
+ else
+ val -= left_step;
+
reg &= ~TWL6040_HF_VOL_MASK;
twl6040_write(codec, TWL6040_REG_HFLGAIN,
reg | (0x1D - val));
@@ -412,7 +463,11 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
if (handsfree->ramp == TWL6040_RAMP_UP) {
/* ramp step up */
if (val < handsfree->right_vol) {
- val += right_step;
+ if (val + right_step > handsfree->right_vol)
+ val = handsfree->right_vol;
+ else
+ val += right_step;
+
reg &= ~TWL6040_HF_VOL_MASK;
twl6040_write(codec, TWL6040_REG_HFRGAIN,
reg | (0x1D - val));
@@ -422,7 +477,11 @@ static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
} else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
/* ramp step down */
if (val > 0) {
- val -= right_step;
+ if ((int)val - (int)right_step < 0)
+ val = 0;
+ else
+ val -= right_step;
+
reg &= ~TWL6040_HF_VOL_MASK;
twl6040_write(codec, TWL6040_REG_HFRGAIN,
reg | (0x1D - val));
@@ -451,11 +510,9 @@ static void twl6040_pga_hs_work(struct work_struct *work)
/* HS PGA volumes have 4 bits of resolution to ramp */
for (i = 0; i <= 16; i++) {
- headset_complete = 1;
- if (headset->ramp != TWL6040_RAMP_NONE)
- headset_complete = twl6040_hs_ramp_step(codec,
- headset->left_step,
- headset->right_step);
+ headset_complete = twl6040_hs_ramp_step(codec,
+ headset->left_step,
+ headset->right_step);
/* ramp finished ? */
if (headset_complete)
@@ -496,11 +553,9 @@ static void twl6040_pga_hf_work(struct work_struct *work)
/* HF PGA volumes have 5 bits of resolution to ramp */
for (i = 0; i <= 32; i++) {
- handsfree_complete = 1;
- if (handsfree->ramp != TWL6040_RAMP_NONE)
- handsfree_complete = twl6040_hf_ramp_step(codec,
- handsfree->left_step,
- handsfree->right_step);
+ handsfree_complete = twl6040_hf_ramp_step(codec,
+ handsfree->left_step,
+ handsfree->right_step);
/* ramp finished ? */
if (handsfree_complete)
@@ -541,12 +596,16 @@ static int pga_event(struct snd_soc_dapm_widget *w,
out = &priv->headset;
work = &priv->hs_delayed_work;
queue = priv->hs_workqueue;
+ out->left_step = priv->left_step_hs;
+ out->right_step = priv->right_step_hs;
out->step_delay = 5; /* 5 ms between volume ramp steps */
break;
case 4:
out = &priv->handsfree;
work = &priv->hf_delayed_work;
queue = priv->hf_workqueue;
+ out->left_step = priv->left_step_hf;
+ out->right_step = priv->right_step_hf;
out->step_delay = 5; /* 5 ms between volume ramp steps */
if (SND_SOC_DAPM_EVENT_ON(event))
priv->non_lp++;
@@ -579,8 +638,6 @@ static int pga_event(struct snd_soc_dapm_widget *w,
if (!delayed_work_pending(work)) {
/* use volume ramp for power-down */
- out->left_step = 1;
- out->right_step = 1;
out->ramp = TWL6040_RAMP_DOWN;
INIT_COMPLETION(out->ramp_done);
@@ -596,88 +653,6 @@ static int pga_event(struct snd_soc_dapm_widget *w,
return 0;
}
-/* twl6040 codec manual power-up sequence */
-static void twl6040_power_up(struct snd_soc_codec *codec)
-{
- u8 ncpctl, ldoctl, lppllctl, accctl;
-
- ncpctl = twl6040_read_reg_cache(codec, TWL6040_REG_NCPCTL);
- ldoctl = twl6040_read_reg_cache(codec, TWL6040_REG_LDOCTL);
- lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
- accctl = twl6040_read_reg_cache(codec, TWL6040_REG_ACCCTL);
-
- /* enable reference system */
- ldoctl |= TWL6040_REFENA;
- twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
- msleep(10);
- /* enable internal oscillator */
- ldoctl |= TWL6040_OSCENA;
- twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
- udelay(10);
- /* enable high-side ldo */
- ldoctl |= TWL6040_HSLDOENA;
- twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
- udelay(244);
- /* enable negative charge pump */
- ncpctl |= TWL6040_NCPENA | TWL6040_NCPOPEN;
- twl6040_write(codec, TWL6040_REG_NCPCTL, ncpctl);
- udelay(488);
- /* enable low-side ldo */
- ldoctl |= TWL6040_LSLDOENA;
- twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
- udelay(244);
- /* enable low-power pll */
- lppllctl |= TWL6040_LPLLENA;
- twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
- /* reset state machine */
- accctl |= TWL6040_RESETSPLIT;
- twl6040_write(codec, TWL6040_REG_ACCCTL, accctl);
- mdelay(5);
- accctl &= ~TWL6040_RESETSPLIT;
- twl6040_write(codec, TWL6040_REG_ACCCTL, accctl);
- /* disable internal oscillator */
- ldoctl &= ~TWL6040_OSCENA;
- twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
-}
-
-/* twl6040 codec manual power-down sequence */
-static void twl6040_power_down(struct snd_soc_codec *codec)
-{
- u8 ncpctl, ldoctl, lppllctl, accctl;
-
- ncpctl = twl6040_read_reg_cache(codec, TWL6040_REG_NCPCTL);
- ldoctl = twl6040_read_reg_cache(codec, TWL6040_REG_LDOCTL);
- lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
- accctl = twl6040_read_reg_cache(codec, TWL6040_REG_ACCCTL);
-
- /* enable internal oscillator */
- ldoctl |= TWL6040_OSCENA;
- twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
- udelay(10);
- /* disable low-power pll */
- lppllctl &= ~TWL6040_LPLLENA;
- twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
- /* disable low-side ldo */
- ldoctl &= ~TWL6040_LSLDOENA;
- twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
- udelay(244);
- /* disable negative charge pump */
- ncpctl &= ~(TWL6040_NCPENA | TWL6040_NCPOPEN);
- twl6040_write(codec, TWL6040_REG_NCPCTL, ncpctl);
- udelay(488);
- /* disable high-side ldo */
- ldoctl &= ~TWL6040_HSLDOENA;
- twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
- udelay(244);
- /* disable internal oscillator */
- ldoctl &= ~TWL6040_OSCENA;
- twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
- /* disable reference system */
- ldoctl &= ~TWL6040_REFENA;
- twl6040_write(codec, TWL6040_REG_LDOCTL, ldoctl);
- msleep(10);
-}
-
/* set headset dac and driver power mode */
static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
{
@@ -713,15 +688,26 @@ static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_codec *codec = w->codec;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
- if (SND_SOC_DAPM_EVENT_ON(event))
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
priv->non_lp++;
- else
+ if (!strcmp(w->name, "Earphone Driver")) {
+ /* Earphone doesn't support low power mode */
+ priv->power_mode_forced = 1;
+ ret = headset_power_mode(codec, 1);
+ }
+ } else {
priv->non_lp--;
+ if (!strcmp(w->name, "Earphone Driver")) {
+ priv->power_mode_forced = 0;
+ ret = headset_power_mode(codec, priv->headset_mode);
+ }
+ }
msleep(1);
- return 0;
+ return ret;
}
void twl6040_hs_jack_report(struct snd_soc_codec *codec,
@@ -766,32 +752,18 @@ static void twl6040_accessory_work(struct work_struct *work)
}
/* audio interrupt handler */
-static irqreturn_t twl6040_naudint_handler(int irq, void *data)
+static irqreturn_t twl6040_audio_handler(int irq, void *data)
{
struct snd_soc_codec *codec = data;
+ struct twl6040 *twl6040 = codec->control_data;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
u8 intid;
- twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &intid, TWL6040_REG_INTID);
-
- if (intid & TWL6040_THINT)
- dev_alert(codec->dev, "die temp over-limit detection\n");
+ intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
if ((intid & TWL6040_PLUGINT) || (intid & TWL6040_UNPLUGINT))
queue_delayed_work(priv->workqueue, &priv->delayed_work,
- msecs_to_jiffies(200));
-
- if (intid & TWL6040_HOOKINT)
- dev_info(codec->dev, "hook detection\n");
-
- if (intid & TWL6040_HFINT)
- dev_alert(codec->dev, "hf drivers over current detection\n");
-
- if (intid & TWL6040_VIBINT)
- dev_alert(codec->dev, "vib drivers over current detection\n");
-
- if (intid & TWL6040_READYINT)
- complete(&priv->ready);
+ msecs_to_jiffies(200));
return IRQ_HANDLED;
}
@@ -960,9 +932,9 @@ static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -600, 600, 0);
/*
* AFMGAIN volume control:
- * from 18 to 24 dB in 6 dB steps
+ * from -18 to 24 dB in 6 dB steps
*/
-static DECLARE_TLV_DB_SCALE(afm_amp_tlv, 1800, 600, 0);
+static DECLARE_TLV_DB_SCALE(afm_amp_tlv, -1800, 600, 0);
/*
* HSGAIN volume control:
@@ -1040,6 +1012,58 @@ static const struct snd_kcontrol_new hfr_mux_controls =
static const struct snd_kcontrol_new ep_driver_switch_controls =
SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0);
+/* AVADC clock priority */
+static const char *twl6040_dmic_volt_texts[] = {
+ "1.80V", "1.85V"
+};
+
+static const struct soc_enum twl6040_dmic_volt_enum[] = {
+ SOC_ENUM_SINGLE(TWL6040_REG_DMICBCTL, 2,
+ ARRAY_SIZE(twl6040_dmic_volt_texts),
+ twl6040_dmic_volt_texts),
+ SOC_ENUM_SINGLE(TWL6040_REG_DMICBCTL, 6,
+ ARRAY_SIZE(twl6040_dmic_volt_texts),
+ twl6040_dmic_volt_texts),
+};
+
+/* Headset power mode */
+static const char *twl6040_headset_power_texts[] = {
+ "Low-Power", "High-Perfomance",
+};
+
+static const struct soc_enum twl6040_headset_power_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl6040_headset_power_texts),
+ twl6040_headset_power_texts);
+
+static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.enumerated.item[0] = priv->headset_mode;
+
+ return 0;
+}
+
+static int twl6040_headset_power_put_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+ int high_perf = ucontrol->value.enumerated.item[0];
+ int ret;
+
+ if (priv->power_mode_forced)
+ return -EPERM;
+
+ ret = headset_power_mode(codec, high_perf);
+ if (!ret)
+ priv->headset_mode = high_perf;
+
+ return ret;
+}
+
static const struct snd_kcontrol_new twl6040_snd_controls[] = {
/* Capture gains */
SOC_DOUBLE_TLV("Capture Preamplifier Volume",
@@ -1049,7 +1073,7 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = {
/* AFM gains */
SOC_DOUBLE_TLV("Aux FM Volume",
- TWL6040_REG_LINEGAIN, 0, 4, 0xF, 0, afm_amp_tlv),
+ TWL6040_REG_LINEGAIN, 0, 3, 7, 0, afm_amp_tlv),
/* Playback gains */
SOC_TWL6040_DOUBLE_TLV("Headset Playback Volume",
@@ -1058,6 +1082,13 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = {
TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv),
SOC_SINGLE_TLV("Earphone Playback Volume",
TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv),
+
+ SOC_ENUM("Digital Mic Bias 1 Voltage", twl6040_dmic_volt_enum[0]),
+ SOC_ENUM("Digital Mic Bias 2 Voltage", twl6040_dmic_volt_enum[1]),
+
+ SOC_ENUM_EXT("Headset Power Mode", twl6040_headset_power_enum,
+ twl6040_headset_power_get_enum,
+ twl6040_headset_power_put_enum),
};
static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
@@ -1231,37 +1262,11 @@ static int twl6040_add_widgets(struct snd_soc_codec *codec)
return 0;
}
-static int twl6040_power_up_completion(struct snd_soc_codec *codec,
- int naudint)
-{
- struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
- int time_left;
- u8 intid;
-
- time_left = wait_for_completion_timeout(&priv->ready,
- msecs_to_jiffies(144));
-
- if (!time_left) {
- twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &intid,
- TWL6040_REG_INTID);
- if (!(intid & TWL6040_READYINT)) {
- dev_err(codec->dev, "timeout waiting for READYINT\n");
- return -ETIMEDOUT;
- }
- }
-
- priv->codec_powered = 1;
-
- return 0;
-}
-
static int twl6040_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct twl6040 *twl6040 = codec->control_data;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
- int audpwron = priv->audpwron;
- int naudint = priv->naudint;
- int ret;
switch (level) {
case SND_SOC_BIAS_ON:
@@ -1272,24 +1277,8 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
if (priv->codec_powered)
break;
- if (gpio_is_valid(audpwron)) {
- /* use AUDPWRON line */
- gpio_set_value(audpwron, 1);
-
- /* wait for power-up completion */
- ret = twl6040_power_up_completion(codec, naudint);
- if (ret)
- return ret;
-
- /* sync registers updated during power-up sequence */
- twl6040_read_reg_volatile(codec, TWL6040_REG_NCPCTL);
- twl6040_read_reg_volatile(codec, TWL6040_REG_LDOCTL);
- twl6040_read_reg_volatile(codec, TWL6040_REG_LPPLLCTL);
- } else {
- /* use manual power-up sequence */
- twl6040_power_up(codec);
- priv->codec_powered = 1;
- }
+ twl6040_enable(twl6040);
+ priv->codec_powered = 1;
/* initialize vdd/vss registers with reg_cache */
twl6040_init_vdd_regs(codec);
@@ -1307,28 +1296,15 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
if (!priv->codec_powered)
break;
- if (gpio_is_valid(audpwron)) {
- /* use AUDPWRON line */
- gpio_set_value(audpwron, 0);
-
- /* power-down sequence latency */
- udelay(500);
-
- /* sync registers updated during power-down sequence */
- twl6040_read_reg_volatile(codec, TWL6040_REG_NCPCTL);
- twl6040_read_reg_volatile(codec, TWL6040_REG_LDOCTL);
- twl6040_write_reg_cache(codec, TWL6040_REG_LPPLLCTL,
- 0x00);
- } else {
- /* use manual power-down sequence */
- twl6040_power_down(codec);
- }
-
+ twl6040_disable(twl6040);
priv->codec_powered = 0;
break;
}
codec->dapm.bias_level = level;
+ /* get pll and sysclk after power transition */
+ priv->pll = twl6040_get_pll(twl6040);
+ priv->sysclk = twl6040_get_sysclk(twl6040);
return 0;
}
@@ -1357,13 +1333,17 @@ static struct snd_pcm_hw_constraint_list hp_constraints = {
static int twl6040_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ /* TODO: Add constraint for backends */
+#if 0
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
+
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
priv->sysclk_constraints);
+#endif
return 0;
}
@@ -1374,39 +1354,40 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
+ struct twl6040 *twl6040 = codec->control_data;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
- u8 lppllctl;
- int rate;
+ unsigned int sysclk;
+ int rate, ret;
/* nothing to do for high-perf pll, it supports only 48 kHz */
if (priv->pll == TWL6040_HPPLL_ID)
return 0;
- lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
-
rate = params_rate(params);
switch (rate) {
case 11250:
case 22500:
case 44100:
case 88200:
- lppllctl |= TWL6040_LPLLFIN;
- priv->sysclk = 17640000;
+ sysclk = 17640000;
break;
case 8000:
case 16000:
case 32000:
case 48000:
case 96000:
- lppllctl &= ~TWL6040_LPLLFIN;
- priv->sysclk = 19200000;
+ sysclk = 19200000;
break;
default:
dev_err(codec->dev, "unsupported rate %d\n", rate);
return -EINVAL;
}
- twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
+ ret = twl6040_set_pll(twl6040, TWL6040_LPPLL_ID, priv->clk_in, sysclk);
+ if (ret)
+ return ret;
+
+ priv->sysclk = twl6040_get_sysclk(twl6040);
return 0;
}
@@ -1449,99 +1430,25 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
+ struct twl6040 *twl6040 = codec->control_data;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
- u8 hppllctl, lppllctl;
-
- hppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_HPPLLCTL);
- lppllctl = twl6040_read_reg_cache(codec, TWL6040_REG_LPPLLCTL);
+ int ret;
switch (clk_id) {
case TWL6040_SYSCLK_SEL_LPPLL:
- switch (freq) {
- case 32768:
- /* headset dac and driver must be in low-power mode */
- headset_power_mode(codec, 0);
-
- /* clk32k input requires low-power pll */
- lppllctl |= TWL6040_LPLLENA;
- twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
- mdelay(5);
- lppllctl &= ~TWL6040_HPLLSEL;
- twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
- hppllctl &= ~TWL6040_HPLLENA;
- twl6040_write(codec, TWL6040_REG_HPPLLCTL, hppllctl);
- break;
- default:
- dev_err(codec->dev, "unknown mclk freq %d\n", freq);
- return -EINVAL;
- }
-
- /* lppll divider */
- switch (priv->sysclk) {
- case 17640000:
- lppllctl |= TWL6040_LPLLFIN;
- break;
- case 19200000:
- lppllctl &= ~TWL6040_LPLLFIN;
- break;
- default:
- /* sysclk not yet configured */
- lppllctl &= ~TWL6040_LPLLFIN;
- priv->sysclk = 19200000;
- break;
- }
-
- twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
+ ret = twl6040_set_pll(twl6040, TWL6040_LPPLL_ID,
+ freq, priv->sysclk);
+ if (ret)
+ return ret;
- priv->pll = TWL6040_LPPLL_ID;
priv->sysclk_constraints = &lp_constraints;
break;
case TWL6040_SYSCLK_SEL_HPPLL:
- hppllctl &= ~TWL6040_MCLK_MSK;
-
- switch (freq) {
- case 12000000:
- /* mclk input, pll enabled */
- hppllctl |= TWL6040_MCLK_12000KHZ |
- TWL6040_HPLLSQRBP |
- TWL6040_HPLLENA;
- break;
- case 19200000:
- /* mclk input, pll disabled */
- hppllctl |= TWL6040_MCLK_19200KHZ |
- TWL6040_HPLLSQRENA |
- TWL6040_HPLLBP;
- break;
- case 26000000:
- /* mclk input, pll enabled */
- hppllctl |= TWL6040_MCLK_26000KHZ |
- TWL6040_HPLLSQRBP |
- TWL6040_HPLLENA;
- break;
- case 38400000:
- /* clk slicer, pll disabled */
- hppllctl |= TWL6040_MCLK_38400KHZ |
- TWL6040_HPLLSQRENA |
- TWL6040_HPLLBP;
- break;
- default:
- dev_err(codec->dev, "unknown mclk freq %d\n", freq);
- return -EINVAL;
- }
-
- /* headset dac and driver must be in high-performance mode */
- headset_power_mode(codec, 1);
-
- twl6040_write(codec, TWL6040_REG_HPPLLCTL, hppllctl);
- udelay(500);
- lppllctl |= TWL6040_HPLLSEL;
- twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
- lppllctl &= ~TWL6040_LPLLENA;
- twl6040_write(codec, TWL6040_REG_LPPLLCTL, lppllctl);
+ ret = twl6040_set_pll(twl6040, TWL6040_HPPLL_ID, freq,
+ priv->sysclk);
+ if (ret)
+ return ret;
- /* high-performance pll can provide only 19.2 MHz */
- priv->pll = TWL6040_HPPLL_ID;
- priv->sysclk = 19200000;
priv->sysclk_constraints = &hp_constraints;
break;
default:
@@ -1549,6 +1456,10 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
return -EINVAL;
}
+ priv->pll = twl6040_get_pll(twl6040);
+ priv->clk_in = freq;
+ priv->sysclk = twl6040_get_sysclk(twl6040);
+
return 0;
}
@@ -1559,23 +1470,51 @@ static struct snd_soc_dai_ops twl6040_dai_ops = {
.set_sysclk = twl6040_set_dai_sysclk,
};
-static struct snd_soc_dai_driver twl6040_dai = {
- .name = "twl6040-hifi",
+static struct snd_soc_dai_driver twl6040_dai[] = {
+{
+ .name = "twl6040-ul",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = TWL6040_RATES,
+ .formats = TWL6040_FORMATS,
+ },
+ .ops = &twl6040_dai_ops,
+},
+{
+ .name = "twl6040-dl1",
.playback = {
- .stream_name = "Playback",
+ .stream_name = "Headset Playback",
.channels_min = 1,
- .channels_max = 4,
+ .channels_max = 2,
.rates = TWL6040_RATES,
.formats = TWL6040_FORMATS,
},
- .capture = {
- .stream_name = "Capture",
+ .ops = &twl6040_dai_ops,
+},
+{
+ .name = "twl6040-dl2",
+ .playback = {
+ .stream_name = "Handsfree Playback",
.channels_min = 1,
.channels_max = 2,
.rates = TWL6040_RATES,
.formats = TWL6040_FORMATS,
},
.ops = &twl6040_dai_ops,
+},
+{
+ .name = "twl6040-vib",
+ .playback = {
+ .stream_name = "Vibra Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .formats = TWL6040_FORMATS,
+ },
+ .ops = &twl6040_dai_ops,
+},
};
#ifdef CONFIG_PM
@@ -1600,11 +1539,9 @@ static int twl6040_resume(struct snd_soc_codec *codec)
static int twl6040_probe(struct snd_soc_codec *codec)
{
- struct twl4030_codec_data *twl_codec = codec->dev->platform_data;
struct twl6040_data *priv;
- int audpwron, naudint;
+ struct twl4030_codec_audio_data *pdata = dev_get_platdata(codec->dev);
int ret = 0;
- u8 icrev, intmr = TWL6040_ALLINT_MSK;
priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL);
if (priv == NULL)
@@ -1612,23 +1549,28 @@ static int twl6040_probe(struct snd_soc_codec *codec)
snd_soc_codec_set_drvdata(codec, priv);
priv->codec = codec;
+ codec->control_data = dev_get_drvdata(codec->dev->parent);
- twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &icrev, TWL6040_REG_ASICREV);
-
- if (twl_codec && (icrev > 0))
- audpwron = twl_codec->audpwron_gpio;
- else
- audpwron = -EINVAL;
+ if (pdata && pdata->left_step_hs && pdata->right_step_hs) {
+ priv->left_step_hs = pdata->left_step_hs;
+ priv->right_step_hs = pdata->right_step_hs;
+ } else {
+ priv->left_step_hs = 1;
+ priv->right_step_hs = 1;
+ }
- if (twl_codec)
- naudint = twl_codec->naudint_irq;
- else
- naudint = 0;
+ if (pdata && pdata->left_step_hf && pdata->right_step_hf) {
+ priv->left_step_hf = pdata->left_step_hf;
+ priv->right_step_hf = pdata->right_step_hf;
+ } else {
+ priv->left_step_hf = 1;
+ priv->right_step_hf = 1;
+ }
- priv->audpwron = audpwron;
- priv->naudint = naudint;
+ /* default is high-performance mode */
+ priv->headset_mode = 1;
+ priv->sysclk_constraints = &lp_constraints;
priv->workqueue = create_singlethread_workqueue("twl6040-codec");
-
if (!priv->workqueue)
goto work_err;
@@ -1636,56 +1578,34 @@ static int twl6040_probe(struct snd_soc_codec *codec)
mutex_init(&priv->mutex);
- init_completion(&priv->ready);
init_completion(&priv->headset.ramp_done);
init_completion(&priv->handsfree.ramp_done);
- if (gpio_is_valid(audpwron)) {
- ret = gpio_request(audpwron, "audpwron");
- if (ret)
- goto gpio1_err;
-
- ret = gpio_direction_output(audpwron, 0);
- if (ret)
- goto gpio2_err;
-
- priv->codec_powered = 0;
-
- /* enable only codec ready interrupt */
- intmr &= ~(TWL6040_READYMSK | TWL6040_PLUGMSK);
-
- /* reset interrupt status to allow correct power up sequence */
- twl6040_read_reg_volatile(codec, TWL6040_REG_INTID);
- }
- twl6040_write(codec, TWL6040_REG_INTMR, intmr);
-
- if (naudint) {
- /* audio interrupt */
- ret = request_threaded_irq(naudint, NULL,
- twl6040_naudint_handler,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- "twl6040_codec", codec);
- if (ret)
- goto gpio2_err;
- }
-
- /* init vio registers */
- twl6040_init_vio_regs(codec);
-
priv->hf_workqueue = create_singlethread_workqueue("twl6040-hf");
if (priv->hf_workqueue == NULL) {
ret = -ENOMEM;
- goto irq_err;
+ goto hfwork_err;
}
priv->hs_workqueue = create_singlethread_workqueue("twl6040-hs");
if (priv->hs_workqueue == NULL) {
ret = -ENOMEM;
- goto wq_err;
+ goto hswork_err;
}
INIT_DELAYED_WORK(&priv->hs_delayed_work, twl6040_pga_hs_work);
INIT_DELAYED_WORK(&priv->hf_delayed_work, twl6040_pga_hf_work);
+ ret = twl6040_request_irq(codec->control_data, TWL6040_IRQ_PLUG,
+ twl6040_audio_handler, "twl6040_irq_plug",
+ codec);
+ if (ret) {
+ dev_err(codec->dev, "PLUG IRQ request failed: %d\n", ret);
+ goto irq_err;
+ }
+
+ /* init vio registers */
+ twl6040_init_vio_regs(codec);
+
/* power on device */
ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
if (ret)
@@ -1698,16 +1618,12 @@ static int twl6040_probe(struct snd_soc_codec *codec)
return 0;
bias_err:
+ twl6040_free_irq(codec->control_data, TWL6040_IRQ_PLUG, codec);
+irq_err:
destroy_workqueue(priv->hs_workqueue);
-wq_err:
+hswork_err:
destroy_workqueue(priv->hf_workqueue);
-irq_err:
- if (naudint)
- free_irq(naudint, codec);
-gpio2_err:
- if (gpio_is_valid(audpwron))
- gpio_free(audpwron);
-gpio1_err:
+hfwork_err:
destroy_workqueue(priv->workqueue);
work_err:
kfree(priv);
@@ -1717,17 +1633,9 @@ work_err:
static int twl6040_remove(struct snd_soc_codec *codec)
{
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
- int audpwron = priv->audpwron;
- int naudint = priv->naudint;
twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- if (gpio_is_valid(audpwron))
- gpio_free(audpwron);
-
- if (naudint)
- free_irq(naudint, codec);
-
+ twl6040_free_irq(codec->control_data, TWL6040_IRQ_PLUG, codec);
destroy_workqueue(priv->workqueue);
destroy_workqueue(priv->hf_workqueue);
destroy_workqueue(priv->hs_workqueue);
@@ -1752,7 +1660,8 @@ static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
static int __devinit twl6040_codec_probe(struct platform_device *pdev)
{
return snd_soc_register_codec(&pdev->dev,
- &soc_codec_dev_twl6040, &twl6040_dai, 1);
+ &soc_codec_dev_twl6040, twl6040_dai,
+ ARRAY_SIZE(twl6040_dai));
}
static int __devexit twl6040_codec_remove(struct platform_device *pdev)
diff --git a/sound/soc/codecs/twl6040.h b/sound/soc/codecs/twl6040.h
index 23aeed0963e..105a6fde5f9 100644
--- a/sound/soc/codecs/twl6040.h
+++ b/sound/soc/codecs/twl6040.h
@@ -22,123 +22,7 @@
#ifndef __TWL6040_H__
#define __TWL6040_H__
-#define TWL6040_REG_ASICID 0x01
-#define TWL6040_REG_ASICREV 0x02
-#define TWL6040_REG_INTID 0x03
-#define TWL6040_REG_INTMR 0x04
-#define TWL6040_REG_NCPCTL 0x05
-#define TWL6040_REG_LDOCTL 0x06
-#define TWL6040_REG_HPPLLCTL 0x07
-#define TWL6040_REG_LPPLLCTL 0x08
-#define TWL6040_REG_LPPLLDIV 0x09
-#define TWL6040_REG_AMICBCTL 0x0A
-#define TWL6040_REG_DMICBCTL 0x0B
-#define TWL6040_REG_MICLCTL 0x0C
-#define TWL6040_REG_MICRCTL 0x0D
-#define TWL6040_REG_MICGAIN 0x0E
-#define TWL6040_REG_LINEGAIN 0x0F
-#define TWL6040_REG_HSLCTL 0x10
-#define TWL6040_REG_HSRCTL 0x11
-#define TWL6040_REG_HSGAIN 0x12
-#define TWL6040_REG_EARCTL 0x13
-#define TWL6040_REG_HFLCTL 0x14
-#define TWL6040_REG_HFLGAIN 0x15
-#define TWL6040_REG_HFRCTL 0x16
-#define TWL6040_REG_HFRGAIN 0x17
-#define TWL6040_REG_VIBCTLL 0x18
-#define TWL6040_REG_VIBDATL 0x19
-#define TWL6040_REG_VIBCTLR 0x1A
-#define TWL6040_REG_VIBDATR 0x1B
-#define TWL6040_REG_HKCTL1 0x1C
-#define TWL6040_REG_HKCTL2 0x1D
-#define TWL6040_REG_GPOCTL 0x1E
-#define TWL6040_REG_ALB 0x1F
-#define TWL6040_REG_DLB 0x20
-#define TWL6040_REG_TRIM1 0x28
-#define TWL6040_REG_TRIM2 0x29
-#define TWL6040_REG_TRIM3 0x2A
-#define TWL6040_REG_HSOTRIM 0x2B
-#define TWL6040_REG_HFOTRIM 0x2C
-#define TWL6040_REG_ACCCTL 0x2D
-#define TWL6040_REG_STATUS 0x2E
-
-#define TWL6040_CACHEREGNUM (TWL6040_REG_STATUS + 1)
-
-#define TWL6040_VIOREGNUM 18
-#define TWL6040_VDDREGNUM 21
-
-/* INTID (0x03) fields */
-
-#define TWL6040_THINT 0x01
-#define TWL6040_PLUGINT 0x02
-#define TWL6040_UNPLUGINT 0x04
-#define TWL6040_HOOKINT 0x08
-#define TWL6040_HFINT 0x10
-#define TWL6040_VIBINT 0x20
-#define TWL6040_READYINT 0x40
-
-/* INTMR (0x04) fields */
-
-#define TWL6040_PLUGMSK 0x02
-#define TWL6040_READYMSK 0x40
-#define TWL6040_ALLINT_MSK 0x7B
-
-/* NCPCTL (0x05) fields */
-
-#define TWL6040_NCPENA 0x01
-#define TWL6040_NCPOPEN 0x40
-
-/* LDOCTL (0x06) fields */
-
-#define TWL6040_LSLDOENA 0x01
-#define TWL6040_HSLDOENA 0x04
-#define TWL6040_REFENA 0x40
-#define TWL6040_OSCENA 0x80
-
-/* HPPLLCTL (0x07) fields */
-
-#define TWL6040_HPLLENA 0x01
-#define TWL6040_HPLLRST 0x02
-#define TWL6040_HPLLBP 0x04
-#define TWL6040_HPLLSQRENA 0x08
-#define TWL6040_HPLLSQRBP 0x10
-#define TWL6040_MCLK_12000KHZ (0 << 5)
-#define TWL6040_MCLK_19200KHZ (1 << 5)
-#define TWL6040_MCLK_26000KHZ (2 << 5)
-#define TWL6040_MCLK_38400KHZ (3 << 5)
-#define TWL6040_MCLK_MSK 0x60
-
-/* LPPLLCTL (0x08) fields */
-
-#define TWL6040_LPLLENA 0x01
-#define TWL6040_LPLLRST 0x02
-#define TWL6040_LPLLSEL 0x04
-#define TWL6040_LPLLFIN 0x08
-#define TWL6040_HPLLSEL 0x10
-
-/* HSLCTL (0x10) fields */
-
-#define TWL6040_HSDACMODEL 0x02
-#define TWL6040_HSDRVMODEL 0x08
-
-/* HSRCTL (0x11) fields */
-
-#define TWL6040_HSDACMODER 0x02
-#define TWL6040_HSDRVMODER 0x08
-
-/* ACCCTL (0x2D) fields */
-
-#define TWL6040_RESETSPLIT 0x04
-
-#define TWL6040_SYSCLK_SEL_LPPLL 1
-#define TWL6040_SYSCLK_SEL_HPPLL 2
-
-#define TWL6040_HPPLL_ID 1
-#define TWL6040_LPPLL_ID 2
-
-/* STATUS (0x2E) fields */
-
-#define TWL6040_PLUGCOMP 0x02
+#include <linux/mfd/twl6040-codec.h>
void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
struct snd_soc_jack *jack, int report);
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index 9d35b8c1a62..7d889d45cb4 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -811,9 +811,10 @@ static void davinci_pcm_free(struct snd_pcm *pcm)
static u64 davinci_pcm_dmamask = 0xffffffff;
-static int davinci_pcm_new(struct snd_card *card,
- struct snd_soc_dai *dai, struct snd_pcm *pcm)
+static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
int ret;
if (!card->dev->dma_mask)
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c
index 06670776f64..210e4a72b07 100644
--- a/sound/soc/ep93xx/ep93xx-pcm.c
+++ b/sound/soc/ep93xx/ep93xx-pcm.c
@@ -266,9 +266,10 @@ static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
static u64 ep93xx_pcm_dmamask = 0xffffffff;
-static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
- struct snd_pcm *pcm)
+static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
int ret = 0;
if (!card->dev->dma_mask)
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c
index 413b78da248..58a4c227459 100644
--- a/sound/soc/imx/imx-pcm-fiq.c
+++ b/sound/soc/imx/imx-pcm-fiq.c
@@ -238,12 +238,13 @@ static struct snd_pcm_ops imx_pcm_ops = {
static int ssi_irq = 0;
-static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
- struct snd_pcm *pcm)
+static int imx_pcm_fiq_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
int ret;
- ret = imx_pcm_new(card, dai, pcm);
+ ret = imx_pcm_new(rtd);
if (ret)
return ret;
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index 30894ea7f33..e74c84cfc88 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -388,10 +388,10 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
static u64 imx_pcm_dmamask = DMA_BIT_MASK(32);
-int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
- struct snd_pcm *pcm)
+int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
-
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
int ret = 0;
if (!card->dev->dma_mask)
diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h
index dc8a87530e3..0a84cec3599 100644
--- a/sound/soc/imx/imx-ssi.h
+++ b/sound/soc/imx/imx-ssi.h
@@ -225,8 +225,7 @@ struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev,
struct imx_ssi *ssi);
int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma);
-int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
- struct snd_pcm *pcm);
+int imx_pcm_new(struct snd_soc_pcm_runtime *rtd);
void imx_pcm_free(struct snd_pcm *pcm);
/*
diff --git a/sound/soc/jz4740/jz4740-pcm.c b/sound/soc/jz4740/jz4740-pcm.c
index fb1483f7c96..6d0a9361773 100644
--- a/sound/soc/jz4740/jz4740-pcm.c
+++ b/sound/soc/jz4740/jz4740-pcm.c
@@ -299,9 +299,10 @@ static void jz4740_pcm_free(struct snd_pcm *pcm)
static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32);
-int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
- struct snd_pcm *pcm)
+int jz4740_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
int ret = 0;
if (!card->dev->dma_mask)
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index a088db6d509..771da39fa9f 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -2,6 +2,9 @@ config SND_OMAP_SOC
tristate "SoC Audio for the Texas Instruments OMAP chips"
depends on ARCH_OMAP
+config SND_OMAP_SOC_ABE_DSP
+ tristate
+
config SND_OMAP_SOC_MCBSP
tristate
select OMAP_MCBSP
@@ -9,6 +12,13 @@ config SND_OMAP_SOC_MCBSP
config SND_OMAP_SOC_MCPDM
tristate
+config SND_OMAP_SOC_ABE
+ select SND_DYNAMIC_MINORS
+ tristate
+
+config SND_OMAP_SOC_DMIC
+ tristate
+
config SND_OMAP_SOC_N810
tristate "SoC Audio support for Nokia N810"
depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C
@@ -99,13 +109,28 @@ config SND_OMAP_SOC_SDP3430
SDP3430.
config SND_OMAP_SOC_SDP4430
- tristate "SoC Audio support for Texas Instruments SDP4430"
- depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_4430SDP
+ tristate "SoC Audio support for Texas Instruments SDP4430 or PandaBoard"
+ depends on (MACH_OMAP_4430SDP || MACH_OMAP4_PANDA)
+ depends on TWL4030_CORE && SND_OMAP_SOC
+ select SND_OMAP_SOC_ABE
select SND_OMAP_SOC_MCPDM
select SND_SOC_TWL6040
+ select SND_OMAP_SOC_MCBSP
+ select SND_SOC_DMIC
+ select SND_OMAP_SOC_DMIC
+ select SND_OMAP_SOC_ABE_DSP
help
Say Y if you want to add support for SoC audio on Texas Instruments
- SDP4430.
+ SDP4430 or PandaBoard.
+
+config SND_OMAP_SOC_OMAP4_HDMI
+ tristate "SoC Audio support for Texas Instruments SDP4430 or Panda HDMI port"
+ depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS
+ depends on (MACH_OMAP_4430SDP || MACH_OMAP4_PANDA)
+ select SND_OMAP_SOC_HDMI
+ help
+ Say Y if you want to add support for SoC HDMI audio on Texas Instruments
+ SDP4430 or Panda
config SND_OMAP_SOC_OMAP3_PANDORA
tristate "SoC Audio support for OMAP3 Pandora"
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index ba9fc650db2..0267ec9e43a 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -1,11 +1,17 @@
# OMAP Platform Support
+snd-soc-omap-abe-objs := omap-abe.o
snd-soc-omap-objs := omap-pcm.o
+snd-soc-omap-dmic-objs := omap-dmic.o
snd-soc-omap-mcbsp-objs := omap-mcbsp.o
-snd-soc-omap-mcpdm-objs := omap-mcpdm.o mcpdm.o
+snd-soc-omap-mcpdm-objs := omap-mcpdm.o
+snd-soc-omap-abe-dsp-objs := omap-abe-dsp.o
+obj-$(CONFIG_SND_OMAP_SOC_ABE) += snd-soc-omap-abe.o
obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o
+obj-$(CONFIG_SND_OMAP_SOC_DMIC) += snd-soc-omap-dmic.o
obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o
+obj-$(CONFIG_SND_OMAP_SOC_ABE_DSP) += snd-soc-omap-abe-dsp.o abe/
# OMAP Machine Support
snd-soc-n810-objs := n810.o
@@ -22,6 +28,7 @@ snd-soc-omap3pandora-objs := omap3pandora.o
snd-soc-omap3beagle-objs := omap3beagle.o
snd-soc-zoom2-objs := zoom2.o
snd-soc-igep0020-objs := igep0020.o
+snd-soc-omap4-hdmi-objs := omap-hdmi.o omap4-hdmi-card.o
obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
@@ -37,3 +44,4 @@ obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o
obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o
+obj-$(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) += snd-soc-omap4-hdmi.o
diff --git a/sound/soc/omap/abe/Makefile b/sound/soc/omap/abe/Makefile
new file mode 100644
index 00000000000..33005870479
--- /dev/null
+++ b/sound/soc/omap/abe/Makefile
@@ -0,0 +1,11 @@
+snd-soc-abe-hal-objs += abe_api.o \
+ abe_dbg.o \
+ abe_dat.o \
+ abe_ext.o \
+ abe_ini.o \
+ abe_irq.o \
+ abe_lib.o \
+ abe_mem.o \
+ abe_seq.o \
+
+obj-$(CONFIG_SND_OMAP_SOC_ABE_DSP) += snd-soc-abe-hal.o
diff --git a/sound/soc/omap/abe/abe_api.c b/sound/soc/omap/abe/abe_api.c
new file mode 100644
index 00000000000..a09ca1e1add
--- /dev/null
+++ b/sound/soc/omap/abe/abe_api.c
@@ -0,0 +1,2040 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include "abe_main.h"
+#include "abe_typedef.h"
+#include "abe_initxxx_labels.h"
+#include "abe_dbg.h"
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+u32 warm_boot = 0;
+
+/**
+ * abe_reset_hal - reset the ABE/HAL
+ * @rdev: regulator source
+ * @constraints: constraints to apply
+ *
+ * Operations : reset the HAL by reloading the static variables and
+ * default AESS registers.
+ * Called after a PRCM cold-start reset of ABE
+ */
+abehal_status abe_reset_hal(void)
+{
+ u32 i;
+ _log(id_reset_hal, 0, 0, 0);
+ abe_dbg_output = TERMINAL_OUTPUT;
+ abe_dbg_activity_log_write_pointer = 0;
+ /* IRQ & DBG circular read pointer in DMEM */
+ abe_irq_dbg_read_ptr = 0;
+ /* PDM_DL enable/disable collisions */
+ pdm_dl1_status = 0;
+ pdm_dl2_status = 0;
+ pdm_vib_status = 0;
+ /* default = disable the mixer's adaptive gain control */
+ abe_use_compensated_gain(0);
+ /* reset the default gain values */
+ for (i = 0; i < MAX_NBGAIN_CMEM; i++) {
+ abe_muted_gains_indicator[i] = 0;
+ abe_desired_gains_decibel[i] = (u32) GAIN_MUTE;
+ abe_desired_gains_linear[i] = 0;
+ abe_desired_ramp_delay_ms[i] = 0;
+ abe_muted_gains_decibel[i] = (u32) GAIN_TOOLOW;
+ }
+ /* set debug mask to "enable all traces" */
+ abe_dbg_mask = (abe_dbg_t) (0);
+ abe_hw_configuration();
+ return 0;
+}
+EXPORT_SYMBOL(abe_reset_hal);
+/**
+ * abe_load_fw_param - Load ABE Firmware memories
+ * @PMEM: Pointer of Program memory data
+ * @PMEM_SIZE: Size of PMEM data
+ * @CMEM: Pointer of Coeffients memory data
+ * @CMEM_SIZE: Size of CMEM data
+ * @SMEM: Pointer of Sample memory data
+ * @SMEM_SIZE: Size of SMEM data
+ * @DMEM: Pointer of Data memory data
+ * @DMEM_SIZE: Size of DMEM data
+ *
+ * loads the Audio Engine firmware, generate a single pulse on the Event
+ * generator to let execution start, read the version number returned from
+ * this execution.
+ */
+abehal_status abe_load_fw_param(u32 *ABE_FW)
+{
+ u32 event_gen;
+ u32 pmem_size, dmem_size, smem_size, cmem_size;
+ u32 *pmem_ptr, *dmem_ptr, *smem_ptr, *cmem_ptr, *fw_ptr;
+ _log(id_load_fw_param, 0, 0, 0);
+#if PC_SIMULATION
+ /* the code is loaded from the Checkers */
+#else
+#define ABE_FW_OFFSET 5
+ fw_ptr = ABE_FW;
+ abe_firmware_version_number = *fw_ptr++;
+ pmem_size = *fw_ptr++;
+ cmem_size = *fw_ptr++;
+ dmem_size = *fw_ptr++;
+ smem_size = *fw_ptr++;
+ pmem_ptr = fw_ptr;
+ cmem_ptr = pmem_ptr + (pmem_size >> 2);
+ dmem_ptr = cmem_ptr + (cmem_size >> 2);
+ smem_ptr = dmem_ptr + (dmem_size >> 2);
+ /* do not load PMEM */
+ if (warm_boot) {
+ /* Stop the event Generator */
+ event_gen = 0;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_ATC,
+ EVENT_GENERATOR_START, &event_gen, 4);
+ /* Now we are sure the firmware is stalled */
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_CMEM, 0, cmem_ptr,
+ cmem_size);
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_SMEM, 0, smem_ptr,
+ smem_size);
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, 0, dmem_ptr,
+ dmem_size);
+ /* Restore the event Generator status */
+ event_gen = 1;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_ATC,
+ EVENT_GENERATOR_START, &event_gen, 4);
+ } else {
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_PMEM, 0, pmem_ptr,
+ pmem_size);
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_CMEM, 0, cmem_ptr,
+ cmem_size);
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_SMEM, 0, smem_ptr,
+ smem_size);
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, 0, dmem_ptr,
+ dmem_size);
+ }
+ warm_boot = 1;
+#endif
+ return 0;
+}
+EXPORT_SYMBOL(abe_load_fw_param);
+/**
+ * abe_load_fw - Load ABE Firmware and initialize memories
+ *
+ * loads the Audio Engine firmware, generate a single pulse on the Event
+ * generator to let execution start, read the version number returned from
+ * this execution.
+ */
+abehal_status abe_load_fw(void)
+{
+ _log(id_load_fw, 0, 0, 0);
+ abe_load_fw_param((u32 *) abe_firmware_array);
+ abe_reset_all_ports();
+ abe_build_scheduler_table();
+ abe_reset_all_sequence();
+ abe_select_main_port(PDM_DL_PORT);
+ return 0;
+}
+EXPORT_SYMBOL(abe_load_fw);
+/**
+ * abe_reload_fw - Reload ABE Firmware after OFF mode
+ *
+ * loads the Audio Engine firmware, generate a single pulse on the Event
+ * generator to let execution start, read the version number returned from
+ * this execution.
+ */
+abehal_status abe_reload_fw(void)
+{
+ warm_boot = 0;
+ abe_load_fw_param((u32 *) abe_firmware_array);
+ abe_build_scheduler_table();
+
+ /* IRQ & DBG circular read pointer in DMEM */
+ abe_dbg_activity_log_write_pointer = 0;
+ abe_irq_dbg_read_ptr = 0;
+
+ /* Restore Gains not managed by the drivers */
+ abe_write_gain(GAINS_SPLIT, GAIN_0dB, RAMP_100MS, GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_SPLIT, GAIN_0dB, RAMP_100MS, GAIN_RIGHT_OFFSET);
+ abe_write_gain(GAINS_DL1, GAIN_0dB, RAMP_100MS, GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_DL1, GAIN_0dB, RAMP_100MS, GAIN_RIGHT_OFFSET);
+ abe_write_gain(GAINS_DL2, GAIN_0dB, RAMP_100MS, GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_DL2, GAIN_0dB, RAMP_100MS, GAIN_RIGHT_OFFSET);
+
+ return 0;
+}
+EXPORT_SYMBOL(abe_reload_fw);
+/**
+ * abe_read_hardware_configuration - Return default HW periferals configuration
+ * @u: use-case description list (pointer)
+ * @o: opp mode (pointer)
+ * @hw: pointer to the output HW structure
+ *
+ * Parameter :
+ * U : use-case description list (pointer)
+ * H : pointer to the output structure
+ *
+ * Operations :
+ * return a structure with the HW thresholds compatible with the HAL/FW/AESS_ATC
+ * will be upgraded in FW06
+ * return a structure with the HW thresholds compatible with the HAL/FW/AESS_ATC
+ */
+abehal_status abe_read_hardware_configuration(u32 *u, u32 *o,
+ abe_hw_config_init_t *hw)
+{
+ _log(id_read_hardware_configuration, (u32) u,
+ (u32) u >> 8, (u32) u >> 16);
+ abe_read_use_case_opp(u, o);
+ /* 0: 96kHz 1:192kHz */
+ hw->MCPDM_CTRL__DIV_SEL = 0;
+ /* 0: no command in the FIFO, 1: 6 data on each lines (with commands) */
+ hw->MCPDM_CTRL__CMD_INT = 1;
+ /* 0:MSB aligned 1:LSB aligned */
+ hw->MCPDM_CTRL__PDMOUTFORMAT = 0;
+ hw->MCPDM_CTRL__PDM_DN5_EN = 1;
+ hw->MCPDM_CTRL__PDM_DN4_EN = 1;
+ hw->MCPDM_CTRL__PDM_DN3_EN = 1;
+ hw->MCPDM_CTRL__PDM_DN2_EN = 1;
+ hw->MCPDM_CTRL__PDM_DN1_EN = 1;
+ hw->MCPDM_CTRL__PDM_UP3_EN = 0;
+ hw->MCPDM_CTRL__PDM_UP2_EN = 1;
+ hw->MCPDM_CTRL__PDM_UP1_EN = 1;
+ /* All the McPDM_DL FIFOs are enabled simultaneously */
+ hw->MCPDM_FIFO_CTRL_DN__DN_TRESH = MCPDM_DL_ITER / 6;
+ /* number of ATC access upon AMIC DMArequests, 2 the FIFOs channels
+ are enabled */
+ hw->MCPDM_FIFO_CTRL_UP__UP_TRESH = MCPDM_UL_ITER / 2;
+ /* 0:2.4MHz 1:3.84MHz */
+ hw->DMIC_CTRL__DMIC_CLK_DIV = 0;
+ /* 0:MSB aligned 1:LSB aligned */
+ hw->DMIC_CTRL__DMICOUTFORMAT = 0;
+ hw->DMIC_CTRL__DMIC_UP3_EN = 1;
+ hw->DMIC_CTRL__DMIC_UP2_EN = 1;
+ hw->DMIC_CTRL__DMIC_UP1_EN = 1;
+ /* 1*(DMIC_UP1_EN+ 2+ 3)*2 OCP read access every 96/88.1 KHz. */
+ hw->DMIC_FIFO_CTRL__DMIC_TRESH = DMIC_ITER / 6;
+ /* MCBSP SPECIFICATION
+ RJUST = 00 Right justify data and zero fill MSBs in DRR[1,2]
+ RJUST = 01 Right justify data and sign extend it into the MSBs
+ in DRR[1,2]
+ RJUST = 10 Left justify data and zero fill LSBs in DRR[1,2]
+ MCBSPLP_RJUST_MODE_RIGHT_ZERO = 0x0,
+ MCBSPLP_RJUST_MODE_RIGHT_SIGN = 0x1,
+ MCBSPLP_RJUST_MODE_LEFT_ZERO = 0x2,
+ MCBSPLP_RJUST_MODE_MAX = MCBSPLP_RJUST_MODE_LEFT_ZERO
+ */
+ hw->MCBSP_SPCR1_REG__RJUST = 2;
+ /* 1=MONO, 2=STEREO, 3=TDM_3_CHANNELS, 4=TDM_4_CHANNELS, .... */
+ hw->MCBSP_THRSH2_REG_REG__XTHRESHOLD = 1;
+ /* 1=MONO, 2=STEREO, 3=TDM_3_CHANNELS, 4=TDM_4_CHANNELS, .... */
+ hw->MCBSP_THRSH1_REG_REG__RTHRESHOLD = 1;
+ /* Slimbus IP FIFO thresholds */
+ hw->SLIMBUS_DCT_FIFO_SETUP_REG__SB_THRESHOLD = 1;
+ /* 2050 gives about 96kHz */
+ hw->AESS_EVENT_GENERATOR_COUNTER__COUNTER_VALUE =
+ EVENT_GENERATOR_COUNTER_DEFAULT;
+ /* 0: DMAreq, 1:Counter */
+ hw->AESS_EVENT_SOURCE_SELECTION__SELECTION = 1;
+ /* 5bits DMAreq selection */
+ hw->AESS_AUDIO_ENGINE_SCHEDULER__DMA_REQ_SELECTION =
+ ABE_ATC_MCPDMDL_DMA_REQ;
+ /* THE famous EVENT timer ! */
+ hw->HAL_EVENT_SELECTION = EVENT_TIMER;
+ return 0;
+}
+EXPORT_SYMBOL(abe_read_hardware_configuration);
+/**
+ * abe_irq_processing - Process ABE interrupt
+ *
+ * This subroutine is call upon reception of "MA_IRQ_99 ABE_MPU_IRQ" Audio
+ * back-end interrupt. This subroutine will check the ATC Hrdware, the
+ * IRQ_FIFO from the AE and act accordingly. Some IRQ source are originated
+ * for the delivery of "end of time sequenced tasks" notifications, some are
+ * originated from the Ping-Pong protocols, some are generated from
+ * the embedded debugger when the firmware stops on programmable break-points,
+ * etc
+ */
+abehal_status abe_irq_processing(void)
+{
+ u32 abe_irq_dbg_write_ptr, i, cmem_src, sm_cm;
+ abe_irq_data_t IRQ_data;
+#define IrqFiFoMask ((D_McuIrqFifo_sizeof >> 2) -1)
+ _log(id_irq_processing, 0, 0, 0);
+ /* extract the write pointer index from CMEM memory (INITPTR format) */
+ /* CMEM address of the write pointer in bytes */
+ cmem_src = MCU_IRQ_FIFO_ptr_labelID << 2;
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_CMEM, cmem_src,
+ &sm_cm, sizeof(abe_irq_dbg_write_ptr));
+ /* AESS left-pointer index located on MSBs */
+ abe_irq_dbg_write_ptr = sm_cm >> 16;
+ abe_irq_dbg_write_ptr &= 0xFF;
+ /* loop on the IRQ FIFO content */
+ for (i = 0; i < D_McuIrqFifo_sizeof; i++) {
+ /* stop when the FIFO is empty */
+ if (abe_irq_dbg_write_ptr == abe_irq_dbg_read_ptr)
+ break;
+ /* read the IRQ/DBG FIFO */
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ (D_McuIrqFifo_ADDR +
+ (abe_irq_dbg_read_ptr << 2)),
+ (u32 *) &IRQ_data, sizeof(IRQ_data));
+ abe_irq_dbg_read_ptr = (abe_irq_dbg_read_ptr + 1) &IrqFiFoMask;
+ /* select the source of the interrupt */
+ switch (IRQ_data.tag) {
+ case IRQtag_APS:
+ _log(id_irq_processing, IRQ_data.data, 0, 1);
+ abe_irq_aps(IRQ_data.data);
+ break;
+ case IRQtag_PP:
+ _log(id_irq_processing, 0, 0, 2);
+ abe_irq_ping_pong();
+ break;
+ case IRQtag_COUNT:
+ _log(id_irq_processing, IRQ_data.data, 0, 3);
+ abe_irq_check_for_sequences(IRQ_data.data);
+ break;
+ default:
+ break;
+ }
+ }
+ abe_monitoring();
+ return 0;
+}
+EXPORT_SYMBOL(abe_irq_processing);
+/**
+ * abe_clear_irq - clear ABE interrupt
+ *
+ * This subroutine is call to clear MCU Irq
+ */
+abehal_status abe_clear_irq(void)
+{
+ u32 clear_abe_irq = 1;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_ATC, ABE_MCU_IRQSTATUS,
+ &clear_abe_irq, 4);
+
+ return 0;
+}
+EXPORT_SYMBOL(abe_clear_irq);
+/**
+ * abe_select_main_port - Select stynchronization port for Event generator.
+ * @id: audio port name
+ *
+ * tells the FW which is the reference stream for adjusting
+ * the processing on 23/24/25 slots
+ */
+abehal_status abe_select_main_port(u32 id)
+{
+ u32 selection;
+ _log(id_select_main_port, id, 0, 0);
+ /* flow control */
+ selection = D_IOdescr_ADDR + id * sizeof(ABE_SIODescriptor) +
+ flow_counter_;
+ /* when the main port is a sink port from AESS point of view
+ the sign the firmware task analysis must be changed */
+ selection &= 0xFFFFL;
+ if (abe_port[id].protocol.direction == ABE_ATC_DIRECTION_IN)
+ selection |= 0x80000;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, D_Slot23_ctrl_ADDR,
+ &selection, 4);
+ return 0;
+}
+/**
+ * abe_write_event_generator - Select event generator source
+ * @e: Event Generation Counter, McPDM, DMIC or default.
+ *
+ * load the AESS event generator hardware source. Loads the firmware parameters
+ * accordingly. Indicates to the FW which data stream is the most important to preserve
+ * in case all the streams are asynchronous. If the parameter is "default", let the HAL
+ * decide which Event source is the best appropriate based on the opened ports.
+ *
+ * When neither the DMIC and the McPDM are activated the AE will have its EVENT generator programmed
+ * with the EVENT_COUNTER. The event counter will be tuned in order to deliver a pulse frequency higher
+ * than 96 kHz. The DPLL output at 100% OPP is MCLK = (32768kHz x6000) = 196.608kHz
+ * The ratio is (MCLK/96000)+(1<<1) = 2050
+ * (1<<1) in order to have the same speed at 50% and 100% OPP (only 15 MSB bits are used at OPP50%)
+ */
+abehal_status abe_write_event_generator(u32 e)
+{
+ u32 event, selection, counter, start;
+ _log(id_write_event_generator, e, 0, 0);
+ counter = EVENT_GENERATOR_COUNTER_DEFAULT;
+ start = EVENT_GENERATOR_ON;
+ abe_current_event_id = e;
+ switch (e) {
+ case EVENT_TIMER:
+ selection = EVENT_SOURCE_COUNTER;
+ event = 0;
+ break;
+ case EVENT_44100:
+ selection = EVENT_SOURCE_COUNTER;
+ event = 0;
+ counter = EVENT_GENERATOR_COUNTER_44100;
+ break;
+ default:
+ abe_dbg_param |= ERR_API;
+ abe_dbg_error_log(ABE_BLOCK_COPY_ERR);
+ }
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_ATC,
+ EVENT_GENERATOR_COUNTER, &counter, 4);
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_ATC,
+ EVENT_SOURCE_SELECTION, &selection, 4);
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_ATC,
+ EVENT_GENERATOR_START, &start, 4);
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_ATC,
+ AUDIO_ENGINE_SCHEDULER, &event, 4);
+ return 0;
+}
+EXPORT_SYMBOL(abe_write_event_generator);
+/**
+ * abe_stop_event_generator - Stop event generator source
+ *
+ * Stop the event genrator of AESS. No more event will be send to AESS engine.
+ * Upper layer needs to wait 1/96kHz to be sure that engine reach IDLE instruction
+ */
+abehal_status abe_stop_event_generator(void)
+{
+ u32 event_gen;
+ /* Stop the event Generator */
+ event_gen = 0;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_ATC,
+ EVENT_GENERATOR_START, &event_gen, 4);
+ return 0;
+}
+EXPORT_SYMBOL(abe_stop_event_generator);
+/**
+ * abe_read_use_case_opp() - description for void abe_read_use_case_opp().
+ *
+ * returns the expected min OPP for a given use_case list
+ */
+abehal_status abe_read_use_case_opp(u32 *u, u32 *o)
+{
+ u32 opp, i;
+ u32 *ptr = u;
+#define MAX_READ_USE_CASE_OPP 10
+#define OPP_25 1
+#define OPP_50 2
+#define OPP_100 4
+ _log(id_read_use_case_opp, (u32) u, (u32) u >> 8, (u32) u >> 16);
+ opp = i = 0;
+ do {
+ /* check for pointer errors */
+ if (i > MAX_READ_USE_CASE_OPP) {
+ abe_dbg_param |= ERR_API;
+ abe_dbg_error_log(ABE_READ_USE_CASE_OPP_ERR);
+ break;
+ }
+ /* check for end_of_list */
+ if (*ptr <= 0)
+ break;
+ /* OPP selection based on current firmware implementation */
+ switch (*ptr) {
+ case ABE_AUDIO_PLAYER_ON_HEADSET_OR_EARPHONE:
+ opp |= OPP_25;
+ break;
+ case ABE_DRIFT_MANAGEMENT_FOR_AUDIO_PLAYER:
+ opp |= OPP_100;
+ break;
+ case ABE_DRIFT_MANAGEMENT_FOR_VOICE_CALL:
+ opp |= OPP_100;
+ break;
+ case ABE_VOICE_CALL_ON_HEADSET_OR_EARPHONE_OR_BT:
+ opp |= OPP_50;
+ break;
+ case ABE_MULTIMEDIA_AUDIO_RECORDER:
+ opp |= OPP_50;
+ break;
+ case ABE_VIBRATOR_OR_HAPTICS:
+ opp |= OPP_100;
+ break;
+ case ABE_VOICE_CALL_ON_HANDS_FREE_SPEAKER:
+ opp |= OPP_100;
+ break;
+ case ABE_RINGER_TONES:
+ opp |= OPP_100;
+ break;
+ case ABE_VOICE_CALL_WITH_EARPHONE_ACTIVE_NOISE_CANCELLER:
+ opp |= OPP_100;
+ break;
+ default:
+ break;
+ }
+ i++;
+ ptr++;
+ } while (*ptr != 0);
+ if (opp & OPP_100)
+ *o = ABE_OPP100;
+ else if (opp & OPP_50)
+ *o = ABE_OPP50;
+ else
+ *o = ABE_OPP25;
+ return 0;
+}
+EXPORT_SYMBOL(abe_read_use_case_opp);
+/**
+ * abe_set_opp_processing - Set OPP mode for ABE Firmware
+ * @opp: OOPP mode
+ *
+ * New processing network and OPP:
+ * 0: Ultra Lowest power consumption audio player (no post-processing, no mixer)
+ * 1: OPP 25% (simple multimedia features, including low-power player)
+ * 2: OPP 50% (multimedia and voice calls)
+ * 3: OPP100% ( multimedia complex use-cases)
+ *
+ * Rearranges the FW task network to the corresponding OPP list of features.
+ * The corresponding AE ports are supposed to be set/reset accordingly before
+ * this switch.
+ *
+ */
+abehal_status abe_set_opp_processing(u32 opp)
+{
+ u32 dOppMode32, sio_desc_address;
+ _lock_enter;
+ _log(id_set_opp_processing, opp, 0, 0);
+ switch (opp) {
+ case ABE_OPP25:
+ /* OPP25% */
+ dOppMode32 = DOPPMODE32_OPP25;
+ break;
+ case ABE_OPP50:
+ /* OPP50% */
+ dOppMode32 = DOPPMODE32_OPP50;
+ break;
+ default:
+ abe_dbg_param |= ERR_API;
+ abe_dbg_error_log(ABE_BLOCK_COPY_ERR);
+ case ABE_OPP100:
+ /* OPP100% */
+ dOppMode32 = DOPPMODE32_OPP100;
+ break;
+ }
+ /* Write Multiframe inside DMEM */
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ D_maxTaskBytesInSlot_ADDR, &dOppMode32, sizeof(u32));
+ sio_desc_address = dmem_port_descriptors + (MM_EXT_IN_PORT *
+ sizeof(ABE_SIODescriptor));
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM, sio_desc_address,
+ (u32 *) &sio_desc, sizeof(sio_desc));
+ if (dOppMode32 == DOPPMODE32_OPP100) {
+ /* ASRC input buffer, size 40 */
+ sio_desc.smem_addr1 = smem_mm_ext_in_opp100;
+ /* Init MM_EXT_IN ASRC and enable its adaptation */
+ abe_init_asrc_mm_ext_in(250);
+ } else
+ /* at OPP 50 or without ASRC */
+ sio_desc.smem_addr1 = smem_mm_ext_in_opp50;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, sio_desc_address,
+ (u32 *) &sio_desc, sizeof(sio_desc));
+ sio_desc_address = dmem_port_descriptors + (BT_VX_UL_PORT *
+ sizeof(ABE_SIODescriptor));
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM, sio_desc_address,
+ (u32 *) &sio_desc, sizeof(sio_desc));
+ if (dOppMode32 == DOPPMODE32_OPP100) {
+ /* ASRC input buffer, size 40 */
+ sio_desc.smem_addr1 = smem_bt_vx_ul_opp100;
+ /* Init MM_EXT_IN ASRC and enable its adaptation */
+ abe_init_asrc_bt_ul(250);
+ } else
+ /* at OPP 50 or without ASRC */
+ sio_desc.smem_addr1 = smem_bt_vx_ul_opp50;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, sio_desc_address,
+ (u32 *) &sio_desc, sizeof(sio_desc));
+ sio_desc_address = dmem_port_descriptors + (BT_VX_DL_PORT *
+ sizeof(ABE_SIODescriptor));
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM, sio_desc_address,
+ (u32 *) &sio_desc, sizeof(sio_desc));
+ if (dOppMode32 == DOPPMODE32_OPP100) {
+ /* ASRC input buffer, size 40 */
+ sio_desc.smem_addr1 = smem_bt_vx_dl_opp100;
+ /* Init MM_EXT_IN ASRC and enable its adaptation */
+ abe_init_asrc_bt_dl(250);
+ } else
+ /* at OPP 50 or without ASRC */
+ sio_desc.smem_addr1 = smem_bt_vx_dl_opp50;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, sio_desc_address,
+ (u32 *) &sio_desc, sizeof(sio_desc));
+ return 0;
+}
+EXPORT_SYMBOL(abe_set_opp_processing);
+/**
+ * abe_set_ping_pong_buffer
+ * @port: ABE port ID
+ * @n_bytes: Size of Ping/Pong buffer
+ *
+ * Updates the next ping-pong buffer with "size" bytes copied from the
+ * host processor. This API notifies the FW that the data transfer is done.
+ */
+abehal_status abe_set_ping_pong_buffer(u32 port, u32 n_bytes)
+{
+ u32 sio_pp_desc_address, struct_offset, n_samples, datasize,
+ base_and_size, *src;
+ _log(id_set_ping_pong_buffer, port, n_bytes, n_bytes >> 8);
+ /* ping_pong is only supported on MM_DL */
+ if (port != MM_DL_PORT) {
+ abe_dbg_param |= ERR_API;
+ abe_dbg_error_log(ABE_PARAMETER_ERROR);
+ }
+ /* translates the number of bytes in samples */
+ /* data size in DMEM words */
+ datasize = abe_dma_port_iter_factor(&((abe_port[port]).format));
+ /* data size in bytes */
+ datasize = datasize << 2;
+ n_samples = n_bytes / datasize;
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM, D_PingPongDesc_ADDR,
+ (u32 *) &desc_pp, sizeof(desc_pp));
+ /*
+ * read the port SIO descriptor and extract the current pointer
+ * address after reading the counter
+ */
+ if ((desc_pp.counter & 0x1) == 0) {
+ struct_offset = (u32) &(desc_pp.nextbuff0_BaseAddr) -
+ (u32) &(desc_pp);
+ base_and_size = desc_pp.nextbuff0_BaseAddr;
+ } else {
+ struct_offset = (u32) &(desc_pp.nextbuff1_BaseAddr) -
+ (u32) &(desc_pp);
+ base_and_size = desc_pp.nextbuff1_BaseAddr;
+ }
+ base_and_size = (base_and_size & 0xFFFFL) + (n_samples << 16);
+ sio_pp_desc_address = D_PingPongDesc_ADDR + struct_offset;
+ src = &base_and_size;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, sio_pp_desc_address,
+ (u32 *) &base_and_size, sizeof(u32));
+ return 0;
+}
+EXPORT_SYMBOL(abe_set_ping_pong_buffer);
+/**
+ * abe_read_next_ping_pong_buffer
+ * @port: ABE portID
+ * @p: Next buffer address (pointer)
+ * @n: Next buffer size (pointer)
+ *
+ * Tell the next base address of the next ping_pong Buffer and its size
+ */
+abehal_status abe_read_next_ping_pong_buffer(u32 port, u32 *p, u32 *n)
+{
+ u32 sio_pp_desc_address;
+ _log(id_read_next_ping_pong_buffer, port, 0, 0);
+ /* ping_pong is only supported on MM_DL */
+ if (port != MM_DL_PORT) {
+ abe_dbg_param |= ERR_API;
+ abe_dbg_error_log(ABE_PARAMETER_ERROR);
+ }
+ /* read the port SIO descriptor and extract the current pointer
+ address after reading the counter */
+ sio_pp_desc_address = D_PingPongDesc_ADDR;
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM, sio_pp_desc_address,
+ (u32 *) &desc_pp, sizeof(ABE_SPingPongDescriptor));
+ if ((desc_pp.counter & 0x1) == 0) {
+ _log(id_read_next_ping_pong_buffer, port, 0, 0);
+ *p = desc_pp.nextbuff0_BaseAddr;
+ } else {
+ _log(id_read_next_ping_pong_buffer, port, 1, 0);
+ *p = desc_pp.nextbuff1_BaseAddr;
+ }
+ /* translates the number of samples in bytes */
+ *n = abe_size_pingpong;
+ return 0;
+}
+EXPORT_SYMBOL(abe_read_next_ping_pong_buffer);
+/**
+ * abe_init_ping_pong_buffer
+ * @id: ABE port ID
+ * @size_bytes:size of the ping pong
+ * @n_buffers:number of buffers (2 = ping/pong)
+ * @p:returned address of the ping-pong list of base address (byte offset
+ from DMEM start)
+ *
+ * Computes the base address of the ping_pong buffers
+ */
+abehal_status abe_init_ping_pong_buffer(u32 id, u32 size_bytes, u32 n_buffers,
+ u32 *p)
+{
+ u32 i, dmem_addr;
+ _log(id_init_ping_pong_buffer, id, size_bytes, n_buffers);
+ /* ping_pong is supported in 2 buffers configuration right now but FW
+ is ready for ping/pong/pung/pang... */
+ if (id != MM_DL_PORT || n_buffers > MAX_PINGPONG_BUFFERS) {
+ abe_dbg_param |= ERR_API;
+ abe_dbg_error_log(ABE_PARAMETER_ERROR);
+ }
+ for (i = 0; i < n_buffers; i++) {
+ dmem_addr = dmem_ping_pong_buffer + (i * size_bytes);
+ /* base addresses of the ping pong buffers in U8 unit */
+ abe_base_address_pingpong[i] = dmem_addr;
+ }
+ /* global data */
+ abe_size_pingpong = size_bytes;
+ *p = (u32) dmem_ping_pong_buffer;
+ return 0;
+}
+EXPORT_SYMBOL(abe_init_ping_pong_buffer);
+/**
+ * abe_read_offset_from_ping_buffer
+ * @id: ABE port ID
+ * @n: returned address of the offset from the ping buffer start address expressed in samples
+ *
+ * Computes the current firmware ping pong read pointer location, expressed in samples,
+ * as the offset from the start address of ping buffer.
+ */
+abehal_status abe_read_offset_from_ping_buffer(u32 id, u32 *n)
+{
+ u32 sio_pp_desc_address;
+ /* ping_pong is only supported on MM_DL */
+ if (MM_DL_PORT != id) {
+ abe_dbg_param |= ERR_API;
+ abe_dbg_error_log(ABE_PARAMETER_ERROR);
+ } else {
+ /* read the port SIO ping pong descriptor */
+ sio_pp_desc_address = D_PingPongDesc_ADDR;
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ sio_pp_desc_address, (u32 *) &desc_pp,
+ sizeof(ABE_SPingPongDescriptor));
+ /* extract the current ping pong buffer read pointer based on
+ the value of the counter */
+ if ((desc_pp.counter & 0x1) == 0) {
+ /* the next is buffer0, hence the current is buffer1 */
+ if (abe_port[MM_DL_PORT].format.samp_format &
+ (MONO_MSB | MONO_RSHIFTED_16 | STEREO_16_16)) {
+ *n = abe_size_pingpong / 4 +
+ desc_pp.nextbuff1_Samples -
+ desc_pp.workbuff_Samples;
+ } else if (abe_port[MM_DL_PORT].format.samp_format &
+ (STEREO_MSB | STEREO_RSHIFTED_16)) {
+ *n = abe_size_pingpong / 8 +
+ desc_pp.nextbuff1_Samples -
+ desc_pp.workbuff_Samples;
+ } else {
+ abe_dbg_param |= ERR_API;
+ abe_dbg_error_log(ABE_PARAMETER_ERROR);
+ }
+ } else {
+ /* the next is buffer1, hence the current is buffer0 */
+ *n = desc_pp.nextbuff0_Samples -
+ desc_pp.workbuff_Samples;
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL(abe_read_offset_from_ping_buffer);
+/**
+ * abe_plug_subroutine
+ * @id: returned sequence index after plugging a new subroutine
+ * @f: subroutine address to be inserted
+ * @n: number of parameters of this subroutine
+ * @params: pointer on parameters
+ *
+ * register a list of subroutines for call-back purpose
+ */
+abehal_status abe_plug_subroutine(u32 *id, abe_subroutine2 f, u32 n,
+ u32 *params)
+{
+ _log(id_plug_subroutine, (u32) (*id), (u32) f, n);
+ abe_add_subroutine(id, (abe_subroutine2) f, n, (u32 *) params);
+ return 0;
+}
+EXPORT_SYMBOL(abe_plug_subroutine);
+/**
+ * abe_set_sequence_time_accuracy
+ * @fast: fast counter
+ * @slow: slow counter
+ *
+ */
+abehal_status abe_set_sequence_time_accuracy(u32 fast, u32 slow)
+{
+ u32 data;
+ _log(id_set_sequence_time_accuracy, fast, slow, 0);
+ data = minimum(MAX_UINT16, fast / FW_SCHED_LOOP_FREQ_DIV1000);
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, D_fastCounter_ADDR,
+ &data, sizeof(data));
+ data = minimum(MAX_UINT16, slow / FW_SCHED_LOOP_FREQ_DIV1000);
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, D_slowCounter_ADDR,
+ &data, sizeof(data));
+ return 0;
+}
+EXPORT_SYMBOL(abe_set_sequence_time_accuracy);
+/**
+ * abe_reset_port
+ * @id: ABE port ID
+ *
+ * stop the port activity and reload default parameters on the associated
+ * processing features.
+ * Clears the internal AE buffers.
+ */
+abehal_status abe_reset_port(u32 id)
+{
+ _log(id_reset_port, id, 0, 0);
+ abe_port[id] = ((abe_port_t *) abe_port_init)[id];
+ return 0;
+}
+EXPORT_SYMBOL(abe_reset_port);
+/**
+ * abe_read_remaining_data
+ * @id: ABE port_ID
+ * @n: size pointer to the remaining number of 32bits words
+ *
+ * computes the remaining amount of data in the buffer.
+ */
+abehal_status abe_read_remaining_data(u32 port, u32 *n)
+{
+ u32 sio_pp_desc_address;
+ _log(id_read_remaining_data, port, 0, 0);
+ /*
+ * read the port SIO descriptor and extract the
+ * current pointer address after reading the counter
+ */
+ sio_pp_desc_address = D_PingPongDesc_ADDR;
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM, sio_pp_desc_address,
+ (u32 *) &desc_pp, sizeof(ABE_SPingPongDescriptor));
+ *n = desc_pp.workbuff_Samples;
+ return 0;
+}
+EXPORT_SYMBOL(abe_read_remaining_data);
+/**
+ * abe_disable_data_transfer
+ * @id: ABE port id
+ *
+ * disables the ATC descriptor and stop IO/port activities
+ * disable the IO task (@f = 0)
+ * clear ATC DMEM buffer, ATC enabled
+ */
+abehal_status abe_disable_data_transfer(u32 id)
+{
+ abe_port_protocol_t *protocol;
+ _log(id_disable_data_transfer, id, 0, 0);
+ /* there is only one PDM_DL physical port shared
+ with DL1/DL2/VIB. Here is a check for the need to stop
+ PDM_DL if some activity is already on */
+ if (id == PDM_DL1_PORT) {
+ pdm_dl1_status = 0;
+ if (pdm_dl2_status || pdm_vib_status)
+ return 0;
+ else
+ id = PDM_DL_PORT;
+ }
+ if (id == PDM_DL2_PORT) {
+ pdm_dl2_status = 0;
+ if (pdm_dl1_status || pdm_vib_status)
+ return 0;
+ else
+ id = PDM_DL_PORT;
+ }
+ if (id == PDM_VIB_PORT) {
+ pdm_vib_status = 0;
+ if (pdm_dl1_status || pdm_dl2_status)
+ return 0;
+ else
+ id = PDM_DL_PORT;
+ }
+ /* MM_DL managed in ping-pong */
+ if (id == MM_DL_PORT) {
+ protocol = &(abe_port[MM_DL_PORT].protocol);
+ if (protocol->protocol_switch == PINGPONG_PORT_PROT) {
+ abe_disable_pp_io_task(MM_DL_PORT);
+ }
+ }
+ /* local host variable status= "port is running" */
+ abe_port[id].status = OMAP_ABE_PORT_ACTIVITY_IDLE;
+ /* disable DMA requests */
+ abe_disable_dma_request(id);
+ /* disable ATC transfers */
+ abe_init_atc(id);
+ abe_clean_temporary_buffers(id);
+ /* select the main port based on the desactivation of this port */
+ abe_decide_main_port();
+ return 0;
+}
+EXPORT_SYMBOL(abe_disable_data_transfer);
+/**
+ * abe_enable_data_transfer
+ * @ip: ABE port id
+ *
+ * enables the ATC descriptor
+ * reset ATC pointers
+ * enable the IO task (@f <> 0)
+ */
+abehal_status abe_enable_data_transfer(u32 id)
+{
+ abe_port_protocol_t *protocol;
+ abe_data_format_t format;
+ _log(id_enable_data_transfer, id, 0, 0);
+ /* there is only one PDM_DL physical port shared
+ with DL1/DL2/VIB. Here is a check for the need to enable
+ PDM_DL when some activity is already on */
+ if (id == PDM_DL1_PORT) {
+ id = PDM_DL_PORT;
+ if (pdm_dl1_status == 1)
+ return 0;
+ else
+ pdm_dl1_status = 1;
+ }
+ if (id == PDM_DL2_PORT) {
+ id = PDM_DL_PORT;
+ if (pdm_dl2_status == 1)
+ return 0;
+ else
+ pdm_dl2_status = 1;
+ }
+ if (id == PDM_VIB_PORT) {
+ id = PDM_DL_PORT;
+ if (pdm_vib_status == 1)
+ return 0;
+ else
+ pdm_vib_status = 1;
+ }
+ abe_clean_temporary_buffers(id);
+ if (id == PDM_UL_PORT) {
+ /* initializes the ABE ATC descriptors in DMEM - MCPDM_UL */
+ protocol = &(abe_port[PDM_UL_PORT].protocol);
+ format = abe_port[PDM_UL_PORT].format;
+ abe_init_atc(PDM_UL_PORT);
+ abe_init_io_tasks(PDM_UL_PORT, &format, protocol);
+ }
+ if (id == PDM_DL_PORT) {
+ /* initializes the ABE ATC descriptors in DMEM - MCPDM_DL */
+ protocol = &(abe_port[PDM_DL_PORT].protocol);
+ format = abe_port[PDM_DL_PORT].format;
+ abe_init_atc(PDM_DL_PORT);
+ abe_init_io_tasks(PDM_DL_PORT, &format, protocol);
+ }
+ /* MM_DL managed in ping-pong */
+ if (id == MM_DL_PORT) {
+ protocol = &(abe_port[MM_DL_PORT].protocol);
+ if (protocol->protocol_switch == PINGPONG_PORT_PROT) {
+ abe_enable_pp_io_task(MM_DL_PORT);
+ }
+ }
+ if (id == DMIC_PORT) {
+ /* one DMIC port enabled = all DMICs enabled,
+ * since there is a single DMIC path for all DMICs */
+ protocol = &(abe_port[DMIC_PORT].protocol);
+ format = abe_port[DMIC_PORT].format;
+ abe_init_atc(DMIC_PORT);
+ abe_init_io_tasks(DMIC_PORT, &format, protocol);
+ }
+ if (id == VX_UL_PORT) {
+ /* Init VX_UL ASRC and enable its adaptation */
+ abe_init_asrc_vx_ul(250);
+ }
+ if (id == VX_DL_PORT) {
+ /* Init VX_DL ASRC and enable its adaptation */
+ abe_init_asrc_vx_dl(250);
+ }
+ /* local host variable status= "port is running" */
+ abe_port[id].status = OMAP_ABE_PORT_ACTIVITY_RUNNING;
+ /* enable DMA requests */
+ abe_enable_dma_request(id);
+ /* select the main port based on the activation of this new port */
+ abe_decide_main_port();
+ return 0;
+}
+EXPORT_SYMBOL(abe_enable_data_transfer);
+/**
+ * abe_connect_cbpr_dmareq_port
+ * @id: port name
+ * @f: desired data format
+ * @d: desired dma_request line (0..7)
+ * @a: returned pointer to the base address of the CBPr register and number of
+ * samples to exchange during a DMA_request.
+ *
+ * enables the data echange between a DMA and the ABE through the
+ * CBPr registers of AESS.
+ */
+abehal_status abe_connect_cbpr_dmareq_port(u32 id, abe_data_format_t *f, u32 d,
+ abe_dma_t *returned_dma_t)
+{
+ _log(id_connect_cbpr_dmareq_port, id, f->f, f->samp_format);
+ abe_port[id] = ((abe_port_t *) abe_port_init)[id];
+ (abe_port[id]).format = (*f);
+ abe_port[id].protocol.protocol_switch = DMAREQ_PORT_PROT;
+ abe_port[id].protocol.p.prot_dmareq.iter = abe_dma_port_iteration(f);
+ abe_port[id].protocol.p.prot_dmareq.dma_addr = ABE_DMASTATUS_RAW;
+ abe_port[id].protocol.p.prot_dmareq.dma_data = (1 << d);
+ abe_port[id].status = OMAP_ABE_PORT_INITIALIZED;
+ /* load the micro-task parameters */
+ abe_init_io_tasks(id, &((abe_port[id]).format),
+ &((abe_port[id]).protocol));
+ /* load the dma_t with physical information from AE memory mapping */
+ abe_init_dma_t(id, &((abe_port[id]).protocol));
+ /* load the ATC descriptors - disabled */
+ abe_init_atc(id);
+ /* return the dma pointer address */
+ abe_read_port_address(id, returned_dma_t);
+ return 0;
+}
+EXPORT_SYMBOL(abe_connect_cbpr_dmareq_port);
+/**
+ * abe_connect_dmareq_ping_pong_port
+ * @id: port name
+ * @f: desired data format
+ * @d: desired dma_request line (0..7)
+ * @s: half-buffer (ping) size
+ * @a: returned pointer to the base address of the ping-pong buffer and number
+ * of samples to exchange during a DMA_request.
+ *
+ * enables the data echanges between a DMA and a direct access to
+ * the DMEM memory of ABE. On each dma_request activation the DMA will exchange
+ * "s" bytes and switch to the "pong" buffer for a new buffer exchange.
+ */
+abehal_status abe_connect_dmareq_ping_pong_port(u32 id, abe_data_format_t *f,
+ u32 d, u32 s,
+ abe_dma_t *returned_dma_t)
+{
+ abe_dma_t dma1;
+ _log(id_connect_dmareq_ping_pong_port, id, f->f, f->samp_format);
+ /* ping_pong is only supported on MM_DL */
+ if (id != MM_DL_PORT) {
+ abe_dbg_param |= ERR_API;
+ abe_dbg_error_log(ABE_PARAMETER_ERROR);
+ }
+ /* declare PP buffer and prepare the returned dma_t */
+ abe_init_ping_pong_buffer(MM_DL_PORT, s, 2,
+ (u32 *) &(returned_dma_t->data));
+ abe_port[id] = ((abe_port_t *) abe_port_init)[id];
+ (abe_port[id]).format = (*f);
+ (abe_port[id]).protocol.protocol_switch = PINGPONG_PORT_PROT;
+ (abe_port[id]).protocol.p.prot_pingpong.buf_addr =
+ dmem_ping_pong_buffer;
+ (abe_port[id]).protocol.p.prot_pingpong.buf_size = s;
+ (abe_port[id]).protocol.p.prot_pingpong.irq_addr = ABE_DMASTATUS_RAW;
+ (abe_port[id]).protocol.p.prot_pingpong.irq_data = (1 << d);
+ abe_port[id].status = OMAP_ABE_PORT_INITIALIZED;
+ /* load the micro-task parameters DESC_IO_PP */
+ abe_init_io_tasks(id, &((abe_port[id]).format),
+ &((abe_port[id]).protocol));
+ /* load the dma_t with physical information from AE memory mapping */
+ abe_init_dma_t(id, &((abe_port[id]).protocol));
+ dma1.data = (u32 *) (abe_port[id].dma.data + ABE_DMEM_BASE_ADDRESS_L3);
+ dma1.iter = abe_port[id].dma.iter;
+ *returned_dma_t = dma1;
+ return 0;
+}
+EXPORT_SYMBOL(abe_connect_dmareq_ping_pong_port);
+/**
+ * abe_connect_irq_ping_pong_port
+ * @id: port name
+ * @f: desired data format
+ * @I: index of the call-back subroutine to call
+ * @s: half-buffer (ping) size
+ * @p: returned base address of the first (ping) buffer)
+ *
+ * enables the data echanges between a direct access to the DMEM
+ * memory of ABE using cache flush. On each IRQ activation a subroutine
+ * registered with "abe_plug_subroutine" will be called. This subroutine
+ * will generate an amount of samples, send them to DMEM memory and call
+ * "abe_set_ping_pong_buffer" to notify the new amount of samples in the
+ * pong buffer.
+ */
+abehal_status abe_connect_irq_ping_pong_port(u32 id, abe_data_format_t *f,
+ u32 subroutine_id, u32 size,
+ u32 *sink, u32 dsp_mcu_flag)
+{
+ _log(id_connect_irq_ping_pong_port, id, f->f, f->samp_format);
+ /* ping_pong is only supported on MM_DL */
+ if (id != MM_DL_PORT) {
+ abe_dbg_param |= ERR_API;
+ abe_dbg_error_log(ABE_PARAMETER_ERROR);
+ }
+ abe_port[id] = ((abe_port_t *) abe_port_init)[id];
+ (abe_port[id]).format = (*f);
+ (abe_port[id]).protocol.protocol_switch = PINGPONG_PORT_PROT;
+ (abe_port[id]).protocol.p.prot_pingpong.buf_addr =
+ dmem_ping_pong_buffer;
+ (abe_port[id]).protocol.p.prot_pingpong.buf_size = size;
+ (abe_port[id]).protocol.p.prot_pingpong.irq_data = (1);
+ abe_init_ping_pong_buffer(MM_DL_PORT, size, 2, sink);
+ if (dsp_mcu_flag == PING_PONG_WITH_MCU_IRQ)
+ (abe_port[id]).protocol.p.prot_pingpong.irq_addr =
+ ABE_MCU_IRQSTATUS_RAW;
+ if (dsp_mcu_flag == PING_PONG_WITH_DSP_IRQ)
+ (abe_port[id]).protocol.p.prot_pingpong.irq_addr =
+ ABE_DSP_IRQSTATUS_RAW;
+ abe_port[id].status = OMAP_ABE_PORT_INITIALIZED;
+ /* load the micro-task parameters */
+ abe_init_io_tasks(id, &((abe_port[id]).format),
+ &((abe_port[id]).protocol));
+ /* load the ATC descriptors - disabled */
+ abe_init_atc(id);
+ *sink = (abe_port[id]).protocol.p.prot_pingpong.buf_addr;
+ return 0;
+}
+EXPORT_SYMBOL(abe_connect_irq_ping_pong_port);
+/**
+ * abe_connect_serial_port()
+ * @id: port name
+ * @f: data format
+ * @i: peripheral ID (McBSP #1, #2, #3)
+ *
+ * Operations : enables the data echanges between a McBSP and an ATC buffer in
+ * DMEM. This API is used connect 48kHz McBSP streams to MM_DL and 8/16kHz
+ * voice streams to VX_UL, VX_DL, BT_VX_UL, BT_VX_DL. It abstracts the
+ * abe_write_port API.
+ */
+abehal_status abe_connect_serial_port(u32 id, abe_data_format_t *f,
+ u32 mcbsp_id)
+{
+ u32 UC_NULL[] = { 0 };
+ u32 OPP;
+ abe_hw_config_init_t CONFIG;
+ _log(id_connect_serial_port, id, f->samp_format, mcbsp_id);
+ abe_port[id] = ((abe_port_t *) abe_port_init)[id];
+ (abe_port[id]).format = (*f);
+ (abe_port[id]).protocol.protocol_switch = SERIAL_PORT_PROT;
+ /* McBSP peripheral connected to ATC */
+ (abe_port[id]).protocol.p.prot_serial.desc_addr = mcbsp_id*ATC_SIZE;
+ /* check the iteration of ATC */
+ abe_read_hardware_configuration(UC_NULL, &OPP, &CONFIG);
+ (abe_port[id]).protocol.p.prot_serial.iter =
+ abe_dma_port_iter_factor(f);
+ abe_port[id].status = OMAP_ABE_PORT_INITIALIZED;
+ /* load the micro-task parameters */
+ abe_init_io_tasks(id, &((abe_port[id]).format),
+ &((abe_port[id]).protocol));
+ /* load the ATC descriptors - disabled */
+ abe_init_atc(id);
+ return 0;
+}
+EXPORT_SYMBOL(abe_connect_serial_port);
+/**
+ * abe_connect_slimbus_port
+ * @id: port name
+ * @f: data format
+ * @i: peripheral ID (McBSP #1, #2, #3)
+ * @j: peripheral ID (McBSP #1, #2, #3)
+ *
+ * enables the data echanges between 1/2 SB and an ATC buffers in
+ * DMEM.
+ */
+abehal_status abe_connect_slimbus_port(u32 id, abe_data_format_t *f,
+ u32 sb_port1, u32 sb_port2)
+{
+ u32 UC_NULL[] = {
+ 0
+ };
+ u32 OPP;
+ abe_hw_config_init_t CONFIG;
+ u32 iter;
+ _log(id_connect_slimbus_port, id, f->samp_format, sb_port2);
+ abe_port[id] = ((abe_port_t *) abe_port_init)[id];
+ (abe_port[id]).format = (*f);
+ (abe_port[id]).protocol.protocol_switch = SLIMBUS_PORT_PROT;
+ /* SB1 peripheral connected to ATC */
+ (abe_port[id]).protocol.p.prot_slimbus.desc_addr1 = sb_port1*ATC_SIZE;
+ /* SB2 peripheral connected to ATC */
+ (abe_port[id]).protocol.p.prot_slimbus.desc_addr2 = sb_port2*ATC_SIZE;
+ /* check the iteration of ATC */
+ abe_read_hardware_configuration(UC_NULL, &OPP, &CONFIG);
+ iter = CONFIG.SLIMBUS_DCT_FIFO_SETUP_REG__SB_THRESHOLD;
+ /* SLIMBUS iter should be 1 */
+ (abe_port[id]).protocol.p.prot_serial.iter = iter;
+ abe_port[id].status = OMAP_ABE_PORT_INITIALIZED;
+ /* load the micro-task parameters */
+ abe_init_io_tasks(id, &((abe_port[id]).format),
+ &((abe_port[id]).protocol));
+ /* load the ATC descriptors - disabled */
+ abe_init_atc(id);
+ return 0;
+}
+EXPORT_SYMBOL(abe_connect_slimbus_port);
+/**
+ * abe_connect_tdm_port
+ * @id: port name
+ * @f: data format
+ * @i: peripheral ID (McBSP #1, #2, #3)
+ * @j: peripheral ID (McBSP #1, #2, #3)
+ *
+ * enables the data echanges between TDM McBSP ATC buffers in
+ * DMEM and 1/2 SMEM buffers
+ */
+abehal_status abe_connect_tdm_port(u32 id, abe_data_format_t *f, u32 mcbsp_id)
+{
+ u32 UC_NULL[] = { 0 };
+ u32 OPP;
+ abe_hw_config_init_t CONFIG;
+ u32 iter;
+ _log(id_connect_tdm_port, id, f->samp_format, mcbsp_id);
+ abe_port[id] = ((abe_port_t *) abe_port_init)[id];
+ (abe_port[id]).format = (*f);
+ (abe_port[id]).protocol.protocol_switch = TDM_SERIAL_PORT_PROT;
+ /* McBSP peripheral connected to ATC */
+ (abe_port[id]).protocol.p.prot_serial.desc_addr = mcbsp_id*ATC_SIZE;
+ /* check the iteration of ATC */
+ abe_read_hardware_configuration(UC_NULL, &OPP, &CONFIG);
+ if (abe_port[id].protocol.direction == ABE_ATC_DIRECTION_IN)
+ iter = CONFIG.MCBSP_THRSH1_REG_REG__RTHRESHOLD;
+ else
+ iter = CONFIG.MCBSP_THRSH2_REG_REG__XTHRESHOLD;
+ /* McBSP iter should be 1 */
+ (abe_port[id]).protocol.p.prot_serial.iter = iter;
+ abe_port[id].status = OMAP_ABE_PORT_INITIALIZED;
+ /* load the micro-task parameters */
+ abe_init_io_tasks(id, &((abe_port[id]).format),
+ &((abe_port[id]).protocol));
+ /* load the ATC descriptors - disabled */
+ abe_init_atc(id);
+ return 0;
+}
+EXPORT_SYMBOL(abe_connect_tdm_port);
+/**
+ * abe_read_port_address
+ * @dma: output pointer to the DMA iteration and data destination pointer
+ *
+ * This API returns the address of the DMA register used on this audio port.
+ * Depending on the protocol being used, adds the base address offset L3
+ * (DMA) or MPU (ARM)
+ */
+abehal_status abe_read_port_address(u32 port, abe_dma_t *dma2)
+{
+ abe_dma_t_offset dma1;
+ u32 protocol_switch;
+ _log(id_read_port_address, port, 0, 0);
+ dma1 = (abe_port[port]).dma;
+ protocol_switch = abe_port[port].protocol.protocol_switch;
+ switch (protocol_switch) {
+ case PINGPONG_PORT_PROT:
+ /* return the base address of the buffer in L3 and L4 spaces */
+ (*dma2).data = (void *)(dma1.data + ABE_DMEM_BASE_ADDRESS_L3);
+ (*dma2).l3_dmem =
+ (void *)(dma1.data + ABE_DMEM_BASE_ADDRESS_L3);
+ (*dma2).l4_dmem =
+ (void *)(dma1.data + ABE_DMEM_BASE_ADDRESS_L4);
+ break;
+ case DMAREQ_PORT_PROT:
+ /* return the CBPr(L3), DMEM(L3), DMEM(L4) address */
+ (*dma2).data = (void *)(dma1.data + ABE_ATC_BASE_ADDRESS_L3);
+ (*dma2).l3_dmem =
+ (void *)((abe_port[port]).protocol.p.prot_dmareq.
+ buf_addr + ABE_DMEM_BASE_ADDRESS_L3);
+ (*dma2).l4_dmem =
+ (void *)((abe_port[port]).protocol.p.prot_dmareq.
+ buf_addr + ABE_DMEM_BASE_ADDRESS_L4);
+ break;
+ default:
+ break;
+ }
+ (*dma2).iter = (dma1.iter);
+ return 0;
+}
+EXPORT_SYMBOL(abe_read_port_address);
+/*
+ * ABE_SELECT_DATA_SOURCE
+ *
+ * Parameter :
+ * port id where data are exchanged
+ * data_cource_id among:
+ * SRC_DL1_MIXER_OUTPUT (DL1_M_labelID)
+ * SRC_SDT_MIXER_OUTPUT (SDT_M_labelID)
+ * SRC_DL1_GAIN_OUTPUT (DL1_GAIN_out_labelID)
+ * SRC_DL1_EQ_OUTPUT (DL1_EQ_labelID)
+ * SRC_DL2_GAIN_OUTPUT (DL2_GAIN_out_labelID)
+ * SRC_DL2_EQ_OUTPUT (DL2_EQ_labelID)
+ * SRC_MM_DL (MM_DL_labelID)
+ * SRC_TONES_DL (Tones_labelID)
+ * SRC_VX_DL (VX_DL_labelID)
+ * SRC_VX_UL (VX_UL_labelID)
+ * SRC_MM_UL2 (MM_UL2_labelID)
+ * SRC_MM_UL (MM_UL_labelID)
+ *
+ * Operations :
+ *
+ * Return value :
+ * None.
+ */
+abehal_status abe_select_data_source(u32 port_id, u32 smem_source)
+{
+ u32 sio_desc_address;
+ sio_desc_address = dmem_port_descriptors +
+ (port_id * sizeof(ABE_SIODescriptor));
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ sio_desc_address, (u32 *) &sio_desc, sizeof(sio_desc));
+ sio_desc.smem_addr1 = (u16) smem_source;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ sio_desc_address, (u32 *) &sio_desc, sizeof(sio_desc));
+ return 0;
+}
+EXPORT_SYMBOL(abe_select_data_source);
+/**
+ * abe_write_equalizer
+ * @id: name of the equalizer
+ * @param : equalizer coefficients
+ *
+ * Load the coefficients in CMEM.
+ */
+abehal_status abe_write_equalizer(u32 id, abe_equ_t *param)
+{
+ u32 eq_offset, length, *src, eq_mem, eq_mem_len;
+ _log(id_write_equalizer, id, 0, 0);
+ switch (id) {
+ default:
+ case EQ1:
+ eq_offset = C_DL1_Coefs_ADDR;
+ eq_mem = S_DL1_M_EQ_data_ADDR;
+ eq_mem_len = S_DL1_M_EQ_data_sizeof;
+ break;
+ case EQ2L:
+ eq_offset = C_DL2_L_Coefs_ADDR;
+ eq_mem = S_DL2_M_LR_EQ_data_ADDR;
+ eq_mem_len = S_DL2_M_LR_EQ_data_sizeof;
+ break;
+ case EQ2R:
+ eq_offset = C_DL2_R_Coefs_ADDR;
+ eq_mem = S_DL2_M_LR_EQ_data_ADDR;
+ eq_mem_len = S_DL2_M_LR_EQ_data_sizeof;
+ break;
+ case EQSDT:
+ eq_offset = C_SDT_Coefs_ADDR;
+ eq_mem = S_SDT_F_data_ADDR;
+ eq_mem_len = S_SDT_F_data_sizeof;
+ break;
+ case EQAMIC:
+ eq_offset = C_96_48_AMIC_Coefs_ADDR;
+ eq_mem = S_AMIC_96_48_data_ADDR;
+ eq_mem_len = S_AMIC_96_48_data_sizeof;
+ break;
+ case EQDMIC:
+ eq_offset = C_96_48_DMIC_Coefs_ADDR;
+ eq_mem = S_DMIC0_96_48_data_ADDR;
+ eq_mem_len = S_DMIC0_96_48_data_sizeof;
+ /* three DMIC are clear at the same time DMIC0 DMIC1 DMIC2 */
+ eq_mem_len *= 3;
+ break;
+ case APS1:
+ eq_offset = C_APS_DL1_coeffs1_ADDR;
+ eq_mem = S_APS_IIRmem1_ADDR;
+ eq_mem_len = S_APS_IIRmem1_sizeof;
+ break;
+ case APS2L:
+ eq_offset = C_APS_DL2_L_coeffs1_ADDR;
+ eq_mem = S_APS_M_IIRmem2_ADDR;
+ eq_mem_len = S_APS_M_IIRmem2_sizeof;
+ break;
+ case APS2R:
+ eq_offset = C_APS_DL2_R_coeffs1_ADDR;
+ eq_mem = S_APS_M_IIRmem2_ADDR;
+ eq_mem_len = S_APS_M_IIRmem2_sizeof;
+ break;
+ }
+ length = param->equ_length;
+ src = (u32 *) ((param->coef).type1);
+ /* translate in bytes */
+ eq_offset <<= 2;
+ /* reset SMEM buffers before the coefficients are loaded */
+ abe_reset_mem(ABE_SMEM, eq_mem << 3, eq_mem_len << 3);
+ /* translate in bytes */
+ length <<= 2;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_CMEM, eq_offset, src, length);
+ /* reset SMEM buffers after the coefficients are loaded */
+ abe_reset_mem(ABE_SMEM, eq_mem << 3, eq_mem_len << 3);
+ return 0;
+}
+EXPORT_SYMBOL(abe_write_equalizer);
+/**
+ * abe_write_asrc
+ * @id: name of the port
+ * @param: drift value to compensate [ppm]
+ *
+ * Load the drift variables to the FW memory. This API can be called only
+ * when the corresponding port has been already opened and the ASRC has
+ * been correctly initialized with API abe_init_asrc_... If this API is
+ * used such that the drift has been changed from positive to negative drift
+ * or vice versa, there will be click in the output signal. Loading the drift
+ * value with zero disables the feature.
+ */
+abehal_status abe_write_asrc(u32 port, s32 dppm)
+{
+ s32 dtempvalue, adppm, drift_sign, drift_sign_addr, alpha_params_addr;
+ s32 alpha_params[3];
+ _log(id_write_asrc, port, dppm, dppm >> 8);
+ /*
+ * x = ppm
+ *
+ * - 1000000/x must be multiple of 16
+ * - deltaalpha = round(2^20*x*16/1000000)=round(2^18/5^6*x) on 22 bits.
+ * then shifted by 2bits
+ * - minusdeltaalpha
+ * - oneminusepsilon = 1-deltaalpha/2.
+ *
+ * ppm = 250
+ * - 1000000/250=4000
+ * - deltaalpha = 4194.3 ~ 4195 => 0x00418c
+ */
+ /* examples for -6250 ppm */
+ /* atempvalue32[1] = -1; d_driftsign */
+ /* atempvalue32[3] = 0x00066668; d_deltaalpha */
+ /* atempvalue32[4] = 0xfff99998; d_minusdeltaalpha */
+ /* atempvalue32[5] = 0x003ccccc; d_oneminusepsilon */
+ /* example for 100 ppm */
+ /* atempvalue32[1] = 1;* d_driftsign */
+ /* atempvalue32[3] = 0x00001a38; d_deltaalpha */
+ /* atempvalue32[4] = 0xffffe5c8; d_minusdeltaalpha */
+ /* atempvalue32[5] = 0x003ccccc; d_oneminusepsilon */
+ /* compute new value for the ppm */
+ if (dppm >= 0) {
+ /* d_driftsign */
+ drift_sign = 1;
+ adppm = dppm;
+ } else {
+ /* d_driftsign */
+ drift_sign = -1;
+ adppm = (-1 * dppm);
+ }
+ if (dppm == 0) {
+ /* delta_alpha */
+ alpha_params[0] = 0;
+ /* minusdelta_alpha */
+ alpha_params[1] = 0;
+ /* one_minusepsilon */
+ alpha_params[2] = 0x003ffff0;
+ } else {
+ dtempvalue = (adppm << 4) + adppm - ((adppm * 3481L) / 15625L);
+ /* delta_alpha */
+ alpha_params[0] = dtempvalue << 2;
+ /* minusdelta_alpha */
+ alpha_params[1] = (-dtempvalue) << 2;
+ /* one_minusepsilon */
+ alpha_params[2] = (0x00100000 - (dtempvalue / 2)) << 2;
+ }
+ switch (port) {
+ /* asynchronous sample-rate-converter for the uplink voice path */
+ case VX_DL_PORT:
+ drift_sign_addr = D_AsrcVars_DL_VX_ADDR + (1 * sizeof(s32));
+ alpha_params_addr = D_AsrcVars_DL_VX_ADDR + (3 * sizeof(s32));
+ break;
+ /* asynchronous sample-rate-converter for the downlink voice path */
+ case VX_UL_PORT:
+ drift_sign_addr = D_AsrcVars_UL_VX_ADDR + (1 * sizeof(s32));
+ alpha_params_addr = D_AsrcVars_UL_VX_ADDR + (3 * sizeof(s32));
+ break;
+ /* asynchronous sample-rate-converter for the BT_UL path */
+ case BT_VX_UL_PORT:
+ drift_sign_addr = D_AsrcVars_BT_UL_ADDR + (1 * sizeof(s32));
+ alpha_params_addr = D_AsrcVars_BT_UL_ADDR + (3 * sizeof(s32));
+ break;
+ /* asynchronous sample-rate-converter for the BT_DL path */
+ case BT_VX_DL_PORT:
+ drift_sign_addr = D_AsrcVars_BT_DL_ADDR + (1 * sizeof(s32));
+ alpha_params_addr = D_AsrcVars_BT_DL_ADDR + (3 * sizeof(s32));
+ break;
+ default:
+ /* asynchronous sample-rate-converter for the MM_EXT_IN path */
+ case MM_EXT_IN_PORT:
+ drift_sign_addr = D_AsrcVars_MM_EXT_IN_ADDR + (1 * sizeof(s32));
+ alpha_params_addr =
+ D_AsrcVars_MM_EXT_IN_ADDR + (3 * sizeof(s32));
+ break;
+ }
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, drift_sign_addr,
+ (u32 *) &drift_sign, 4);
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, alpha_params_addr,
+ (u32 *) &alpha_params[0], 12);
+ return 0;
+}
+EXPORT_SYMBOL(abe_write_asrc);
+/**
+ * abe_write_aps
+ * @id: name of the aps filter
+ * @param: table of filter coefficients
+ *
+ * Load the filters and thresholds coefficients in FW memory. This AP
+ * can be called when the corresponding APS is not activated. After
+ * reloading the firmware the default coefficients corresponds to "no APS
+ * activated".
+ * Loading all the coefficients value with zero disables the feature.
+ */
+abehal_status abe_write_aps(u32 id, abe_aps_t *param)
+{
+ _log(id_write_aps, id, 0, 0);
+ return 0;
+}
+EXPORT_SYMBOL(abe_write_aps);
+/**
+ * abe_use_compensated_gain
+ * @on_off:
+ *
+ * Selects the automatic Mixer's gain management
+ * on_off = 1 allows the "abe_write_gain" to adjust the overall
+ * gains of the mixer to be tuned not to create saturation
+ */
+abehal_status abe_use_compensated_gain(u32 on_off)
+{
+ abe_compensated_mixer_gain = on_off;
+ return 0;
+}
+EXPORT_SYMBOL(abe_use_compensated_gain);
+/**
+ * abe_disable_gain
+ * Parameters:
+ * mixer id
+ * sub-port id
+ *
+ */
+abehal_status abe_disable_gain(u32 id, u32 p)
+{
+ u32 mixer_offset, f_g, ramp;
+ abe_gain_offset(id, &mixer_offset);
+ /* save the input parameters for mute/unmute */
+ ramp = abe_desired_ramp_delay_ms[mixer_offset + p];
+ f_g = GAIN_MUTE;
+ if (!(abe_muted_gains_indicator[mixer_offset + p] & 0x02)) {
+ /* Check if we are in mute */
+ if (!(abe_muted_gains_indicator[mixer_offset + p] & 0x01)) {
+ abe_muted_gains_decibel[mixer_offset + p] =
+ abe_desired_gains_decibel[mixer_offset + p];
+ /* mute the gain */
+ abe_write_gain(id, f_g, ramp, p);
+ }
+ abe_muted_gains_indicator[mixer_offset + p] |= 0x02;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(abe_disable_gain);
+/**
+ * abe_enable_gain
+ * Parameters:
+ * mixer id
+ * sub-port id
+ *
+ */
+abehal_status abe_enable_gain(u32 id, u32 p)
+{
+ u32 mixer_offset, f_g, ramp;
+ abe_gain_offset(id, &mixer_offset);
+ if ((abe_muted_gains_indicator[mixer_offset + p] & 0x02)) {
+ /* restore the input parameters for mute/unmute */
+ f_g = abe_muted_gains_decibel[mixer_offset + p];
+ ramp = abe_desired_ramp_delay_ms[mixer_offset + p];
+ abe_muted_gains_indicator[mixer_offset + p] &= ~0x02;
+ /* unmute the gain */
+ abe_write_gain(id, f_g, ramp, p);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(abe_enable_gain);
+/**
+ * abe_mute_gain
+ * Parameters:
+ * mixer id
+ * sub-port id
+ *
+ */
+abehal_status abe_mute_gain(u32 id, u32 p)
+{
+ u32 mixer_offset, f_g, ramp;
+ abe_gain_offset(id, &mixer_offset);
+ /* save the input parameters for mute/unmute */
+ ramp = abe_desired_ramp_delay_ms[mixer_offset + p];
+ f_g = GAIN_MUTE;
+ if (!abe_muted_gains_indicator[mixer_offset + p]) {
+ abe_muted_gains_decibel[mixer_offset + p] =
+ abe_desired_gains_decibel[mixer_offset + p];
+ /* mute the gain */
+ abe_write_gain(id, f_g, ramp, p);
+ }
+ abe_muted_gains_indicator[mixer_offset + p] |= 0x01;
+ return 0;
+}
+EXPORT_SYMBOL(abe_mute_gain);
+/**
+ * abe_unmute_gain
+ * Parameters:
+ * mixer id
+ * sub-port id
+ *
+ */
+abehal_status abe_unmute_gain(u32 id, u32 p)
+{
+ u32 mixer_offset, f_g, ramp;
+ abe_gain_offset(id, &mixer_offset);
+ if ((abe_muted_gains_indicator[mixer_offset + p] & 0x01)) {
+ /* restore the input parameters for mute/unmute */
+ f_g = abe_muted_gains_decibel[mixer_offset + p];
+ ramp = abe_desired_ramp_delay_ms[mixer_offset + p];
+ abe_muted_gains_indicator[mixer_offset + p] &= ~0x01;
+ /* unmute the gain */
+ abe_write_gain(id, f_g, ramp, p);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(abe_unmute_gain);
+/**
+ * abe_write_mixer
+ * @id: name of the mixer
+ * @param: list of input gains of the mixer
+ * @p: list of port corresponding to the above gains
+ *
+ * Load the gain coefficients in FW memory. This API can be called when
+ * the corresponding MIXER is not activated. After reloading the firmware
+ * the default coefficients corresponds to "all input and output mixer's gain
+ * in mute state". A mixer is disabled with a network reconfiguration
+ * corresponding to an OPP value.
+ */
+abehal_status abe_write_gain(u32 id, s32 f_g, u32 ramp, u32 p)
+{
+ u32 lin_g, sum_g, mixer_target, mixer_offset, i, mean_gain, mean_exp;
+ u32 new_gain_linear[4];
+ s32 gain_index;
+ u32 alpha, beta;
+ u32 ramp_index;
+ _log(id_write_gain, id, f_g, p);
+ gain_index = ((f_g - min_mdb) / 100);
+ gain_index = maximum(gain_index, 0);
+ gain_index = minimum(gain_index, sizeof_db2lin_table);
+ lin_g = abe_db2lin_table[gain_index];
+ abe_gain_offset(id, &mixer_offset);
+ /* save the input parameters for mute/unmute */
+ abe_desired_gains_linear[mixer_offset + p] = lin_g;
+ abe_desired_gains_decibel[mixer_offset + p] = f_g;
+ abe_desired_ramp_delay_ms[mixer_offset + p] = ramp;
+ /* SMEM word32 address */
+ mixer_target = (S_GTarget1_ADDR << 1);
+ mixer_target += mixer_offset;
+ mixer_target += p;
+ /* translate coef address in Bytes */
+ mixer_target <<= 2;
+ if (abe_compensated_mixer_gain) {
+ switch (id) {
+ case MIXDL1:
+ case MIXDL2:
+ case MIXVXREC:
+ case MIXAUDUL:
+ /* compute the sum of the gain of the mixer */
+ for (sum_g = i = 0; i < 4; i++)
+ sum_g += abe_desired_gains_linear[mixer_offset +
+ i];
+ /* lets avoid a division by 0 */
+ if (sum_g == 0)
+ break;
+ /* if the sum is OK with less than 1, then
+ do not weight the gains */
+ if (sum_g < 0x00040000) { /* REMOVE HARD CONST */
+ /* recompute all gains from original
+ desired values */
+ sum_g = 0x00040000;
+ }
+ /* translate it in Q16 format for the later division */
+ abe_int_2_float16(sum_g, &mean_gain, &mean_exp);
+ mean_exp = 10 - mean_exp;
+ for (i = 0; i < 4; i++) {
+ /* new gain = desired gain divided by sum of gains */
+ new_gain_linear[i] =
+ (abe_desired_gains_linear
+ [mixer_offset + i]
+ << 8) / mean_gain;
+ new_gain_linear[i] = (mean_exp > 0) ?
+ new_gain_linear[i] << mean_exp :
+ new_gain_linear[i] >> mean_exp;
+ }
+ /* load the whole adpated S_G_Target SMEM MIXER table */
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_SMEM,
+ mixer_target - (p << 2),
+ new_gain_linear, (4 * sizeof(lin_g)));
+ break;
+ default:
+ /* load the S_G_Target SMEM table */
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_SMEM,
+ mixer_target,
+ (u32 *) &lin_g, sizeof(lin_g));
+ break;
+ }
+ } else {
+ if (!abe_muted_gains_indicator[mixer_offset + p])
+ /* load the S_G_Target SMEM table */
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_SMEM,
+ mixer_target, (u32 *) &lin_g,
+ sizeof(lin_g));
+ else
+ /* update muted gain with new value */
+ abe_muted_gains_decibel[mixer_offset + p] = f_g;
+ }
+ ramp = maximum(minimum(RAMP_MAXLENGTH, ramp), RAMP_MINLENGTH);
+ /* ramp data should be interpolated in the table instead */
+ ramp_index = 8;
+ if ((RAMP_5MS <= ramp) && (ramp < RAMP_50MS))
+ ramp_index = 24;
+ if ((RAMP_50MS <= ramp) && (ramp < RAMP_500MS))
+ ramp_index = 36;
+ if (ramp > RAMP_500MS)
+ ramp_index = 48;
+ beta = abe_alpha_iir[ramp_index];
+ alpha = abe_1_alpha_iir[ramp_index];
+ /* CMEM word32 address */
+ mixer_target = C_1_Alpha_ADDR;
+ /* a pair of gains is updated once in the firmware */
+ mixer_target += (p + mixer_offset) >> 1;
+ /* translate coef address in Bytes */
+ mixer_target <<= 2;
+ /* load the ramp delay data */
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_CMEM, mixer_target,
+ (u32 *) &alpha, sizeof(alpha));
+ /* CMEM word32 address */
+ mixer_target = C_Alpha_ADDR;
+ /* a pair of gains is updated once in the firmware */
+ mixer_target += (p + mixer_offset) >> 1;
+ /* translate coef address in Bytes */
+ mixer_target <<= 2;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_CMEM, mixer_target,
+ (u32 *) &beta, sizeof(beta));
+ return 0;
+}
+EXPORT_SYMBOL(abe_write_gain);
+/**
+ * abe_write_mixer
+ * @id: name of the mixer
+ * @param: input gains and delay ramp of the mixer
+ * @p: port corresponding to the above gains
+ *
+ * Load the gain coefficients in FW memory. This API can be called when
+ * the corresponding MIXER is not activated. After reloading the firmware
+ * the default coefficients corresponds to "all input and output mixer's
+ * gain in mute state". A mixer is disabled with a network reconfiguration
+ * corresponding to an OPP value.
+ */
+abehal_status abe_write_mixer(u32 id, s32 f_g, u32 f_ramp, u32 p)
+{
+ _log(id_write_mixer, id, f_ramp, p);
+ abe_write_gain(id, f_g, f_ramp, p);
+ return 0;
+}
+EXPORT_SYMBOL(abe_write_mixer);
+/**
+ * abe_read_gain
+ * @id: name of the mixer
+ * @param: list of input gains of the mixer
+ * @p: list of port corresponding to the above gains
+ *
+ */
+abehal_status abe_read_gain(u32 id, u32 *f_g, u32 p)
+{
+ u32 mixer_target, mixer_offset, i;
+ _log(id_read_gain, id, (u32) f_g, p);
+ abe_gain_offset(id, &mixer_offset);
+ /* SMEM word32 address */
+ mixer_target = (S_GTarget1_ADDR << 1);
+ mixer_target += mixer_offset;
+ mixer_target += p;
+ /* translate coef address in Bytes */
+ mixer_target <<= 2;
+
+ if (!abe_muted_gains_indicator[mixer_offset + p]) {
+ /* load the S_G_Target SMEM table */
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_SMEM, mixer_target,
+ (u32 *) f_g, sizeof(*f_g));
+ for (i = 0; i < sizeof_db2lin_table; i++) {
+ if (abe_db2lin_table[i] == *f_g)
+ goto found;
+ }
+ *f_g = 0;
+ return -1;
+ found:
+ *f_g = (i * 100) + min_mdb;
+ } else {
+ /* update muted gain with new value */
+ *f_g = abe_muted_gains_decibel[mixer_offset + p];
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(abe_read_gain);
+/**
+ * abe_read_mixer
+ * @id: name of the mixer
+ * @param: gains of the mixer
+ * @p: port corresponding to the above gains
+ *
+ * Load the gain coefficients in FW memory. This API can be called when
+ * the corresponding MIXER is not activated. After reloading the firmware
+ * the default coefficients corresponds to "all input and output mixer's
+ * gain in mute state". A mixer is disabled with a network reconfiguration
+ * corresponding to an OPP value.
+ */
+abehal_status abe_read_mixer(u32 id, u32 *f_g, u32 p)
+{
+ _log(id_read_mixer, id, 0, p);
+ abe_read_gain(id, f_g, p);
+ return 0;
+}
+EXPORT_SYMBOL(abe_read_mixer);
+/**
+ * abe_set_router_configuration
+ * @Id: name of the router
+ * @Conf: id of the configuration
+ * @param: list of output index of the route
+ *
+ * The uplink router takes its input from DMIC (6 samples), AMIC (2 samples)
+ * and PORT1/2 (2 stereo ports). Each sample will be individually stored in
+ * an intermediate table of 10 elements.
+ *
+ * Example of router table parameter for voice uplink with phoenix microphones
+ *
+ * indexes 0 .. 9 = MM_UL description (digital MICs and MMEXTIN)
+ * DMIC1_L_labelID, DMIC1_R_labelID, DMIC2_L_labelID, DMIC2_R_labelID,
+ * MM_EXT_IN_L_labelID, MM_EXT_IN_R_labelID, ZERO_labelID, ZERO_labelID,
+ * ZERO_labelID, ZERO_labelID,
+ * indexes 10 .. 11 = MM_UL2 description (recording on DMIC3)
+ * DMIC3_L_labelID, DMIC3_R_labelID,
+ * indexes 12 .. 13 = VX_UL description (VXUL based on PDMUL data)
+ * AMIC_L_labelID, AMIC_R_labelID,
+ * indexes 14 .. 15 = RESERVED (NULL)
+ * ZERO_labelID, ZERO_labelID,
+ */
+abehal_status abe_set_router_configuration(u32 id, u32 k, u32 *param)
+{
+ _log(id_set_router_configuration, id, (u32) param, (u32) param >> 8);
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ D_aUplinkRouting_ADDR, param, D_aUplinkRouting_sizeof);
+ return 0;
+}
+EXPORT_SYMBOL(abe_set_router_configuration);
+/**
+ * ABE_READ_DEBUG_TRACE
+ *
+ * Parameter :
+ * data destination pointer
+ * max number of data read
+ *
+ * Operations :
+ * reads the AE circular data pointer holding pairs of debug data+
+ * timestamps, and store the pairs in linear addressing to the parameter
+ * pointer. Stops the copy when the max parameter is reached or when the
+ * FIFO is empty.
+ *
+ * Return value :
+ * None.
+ */
+abehal_status abe_read_debug_trace(u32 *data, u32 *n)
+{
+ _log(id_select_data_source, 0, 0, 0);
+ return 0;
+}
+EXPORT_SYMBOL(abe_read_debug_trace);
+/**
+ * abe_connect_debug_trace
+ * @dma2:pointer to the DMEM trace buffer
+ *
+ * returns the address and size of the real-time debug trace buffer,
+ * the content of which will vary from one firmware release to an other
+ */
+abehal_status abe_connect_debug_trace(abe_dma_t *dma2)
+{
+ _log(id_connect_debug_trace, 0, 0, 0);
+ /* return the base address of the ping buffer in L3 and L4 spaces */
+ (*dma2).data = (void *)(D_DEBUG_FIFO_ADDR + ABE_DMEM_BASE_ADDRESS_L3);
+ (*dma2).l3_dmem =
+ (void *)(D_DEBUG_FIFO_ADDR + ABE_DMEM_BASE_ADDRESS_L3);
+ (*dma2).l4_dmem =
+ (void *)(D_DEBUG_FIFO_ADDR + ABE_DMEM_BASE_ADDRESS_L4);
+ (*dma2).iter = D_DEBUG_FIFO_sizeof;
+ return 0;
+}
+EXPORT_SYMBOL(abe_connect_debug_trace);
+/**
+ * abe_set_debug_trace
+ * @debug: debug ID from a list to be defined
+ *
+ * load a mask which filters the debug trace to dedicated types of data
+ */
+abehal_status abe_set_debug_trace(abe_dbg_t debug)
+{
+ _log(id_set_debug_trace, 0, 0, 0);
+ abe_dbg_mask = debug;
+ return 0;
+}
+EXPORT_SYMBOL(abe_set_debug_trace);
+/**
+ * abe_remote_debugger_interface
+ *
+ * interpretation of the UART stream from the remote debugger commands.
+ * The commands consist in setting break points, loading parameter
+ */
+abehal_status abe_remote_debugger_interface(u32 n, u8 *p)
+{
+ _log(id_remote_debugger_interface, n, 0, 0);
+ return 0;
+}
+EXPORT_SYMBOL(abe_remote_debugger_interface);
+/**
+ * abe_enable_test_pattern
+ *
+ */
+abehal_status abe_enable_test_pattern(u32 smem_id, u32 on_off)
+{
+ u16 dbg_on, dbg_off, idx_patch, task_patch, addr_patch;
+ u32 patch, task32;
+ _log(id_enable_test_pattern, on_off, smem_id, smem_id >> 8);
+ switch (smem_id) {
+ case DBG_PATCH_AMIC:
+ dbg_on = DBG_48K_PATTERN_labelID;
+ dbg_off = AMIC_labelID;
+ task_patch = C_ABE_FW_TASK_AMIC_SPLIT;
+ idx_patch = 1;
+ break;
+ case DBG_PATCH_DMIC1:
+ dbg_on = DBG_48K_PATTERN_labelID;
+ dbg_off = DMIC1_labelID;
+ task_patch = C_ABE_FW_TASK_DMIC1_SPLIT;
+ idx_patch = 1;
+ break;
+ case DBG_PATCH_DMIC2:
+ dbg_on = DBG_48K_PATTERN_labelID;
+ dbg_off = DMIC2_labelID;
+ task_patch = C_ABE_FW_TASK_DMIC2_SPLIT;
+ idx_patch = 1;
+ break;
+ case DBG_PATCH_DMIC3:
+ dbg_on = DBG_48K_PATTERN_labelID;
+ dbg_off = DMIC3_labelID;
+ task_patch = C_ABE_FW_TASK_DMIC3_SPLIT;
+ idx_patch = 1;
+ break;
+ case DBG_PATCH_VX_REC:
+ dbg_on = DBG_48K_PATTERN_labelID;
+ dbg_off = VX_REC_labelID;
+ task_patch = C_ABE_FW_TASK_VXREC_SPLIT;
+ idx_patch = 1;
+ break;
+ case DBG_PATCH_BT_UL:
+ dbg_on = DBG_48K_PATTERN_labelID;
+ dbg_off = BT_UL_labelID;
+ task_patch = C_ABE_FW_TASK_BT_UL_SPLIT;
+ idx_patch = 1;
+ break;
+ case DBG_PATCH_MM_DL:
+ dbg_on = DBG_48K_PATTERN_labelID;
+ dbg_off = MM_DL_labelID;
+ task_patch = C_ABE_FW_TASK_MM_SPLIT;
+ idx_patch = 1;
+ break;
+ case DBG_PATCH_DL2_EQ:
+ dbg_on = DBG_48K_PATTERN_labelID;
+ dbg_off = DL2_EQ_labelID;
+ task_patch = C_ABE_FW_TASK_DL2_APS_SPLIT;
+ idx_patch = 1;
+ break;
+ case DBG_PATCH_VIBRA:
+ dbg_on = DBG_48K_PATTERN_labelID;
+ dbg_off = VIBRA_labelID;
+ task_patch = C_ABE_FW_TASK_VIBRA_SPLIT;
+ idx_patch = 1;
+ break;
+ case DBG_PATCH_MM_EXT_IN:
+ dbg_on = DBG_48K_PATTERN_labelID;
+ dbg_off = MM_EXT_IN_labelID;
+ task_patch = C_ABE_FW_TASK_MM_EXT_IN_SPLIT;
+ idx_patch = 1;
+ break;
+ case DBG_PATCH_MIC4:
+ dbg_on = DBG_48K_PATTERN_labelID;
+ dbg_off = MIC4_labelID;
+ task_patch = C_ABE_FW_TASK_MIC4_SPLIT;
+ idx_patch = 1;
+ break;
+ case DBG_PATCH_MM_DL_MIXDL1:
+ dbg_on = DBG_48K_PATTERN_labelID;
+ dbg_off = AMIC_labelID;
+ task_patch = C_ABE_FW_TASK_DL1Mixer;
+ idx_patch = 1;
+ break;
+ case DBG_PATCH_MM_DL_MIXDL2:
+ dbg_on = DBG_48K_PATTERN_labelID;
+ dbg_off = AMIC_labelID;
+ task_patch = C_ABE_FW_TASK_DL2Mixer;
+ idx_patch = 1;
+ break;
+ default:
+ return 0;
+ }
+ patch = (on_off != 0) ? dbg_on : dbg_off;
+ /* address is on 16bits boundary */
+ addr_patch = D_tasksList_ADDR + (16 * task_patch) + (2 * idx_patch);
+ /* read on 32bits words' boundary */
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM, addr_patch & (~0x03),
+ &task32, 4);
+ if (addr_patch & 0x03)
+ task32 = (0x0000FFFFL & task32) | (patch << 16);
+ else
+ task32 = (0xFFFF0000L & task32) | (0x0000FFFF & patch);
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, addr_patch & (~0x03),
+ &task32, 4);
+ return 0;
+}
+EXPORT_SYMBOL(abe_enable_test_pattern);
+/**
+ * abe_wakeup - Wakeup ABE
+ *
+ * Wakeup ABE in case of retention
+ */
+abehal_status abe_wakeup(void)
+{
+ /* Restart event generator */
+ abe_write_event_generator(EVENT_TIMER);
+ /* reconfigure DMA Req and MCU Irq visibility */
+ abe_hw_configuration();
+ return 0;
+}
+EXPORT_SYMBOL(abe_wakeup);
+/**
+ * abe_disable_irq - disable MCU/DSP ABE interrupt
+ *
+ * This subroutine is disabling ABE MCU/DSP Irq
+ */
+abehal_status abe_disable_irq(void)
+{
+ u32 atc_reg;
+ /* disables the DMAreq from AESS AESS_DMAENABLE_CLR = 127
+ * DMA_Req7 will still be enabled as it is used for ABE trace */
+ atc_reg = 0x7F;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_ATC, 0x64, &atc_reg, 4);
+ /* disables the MCU IRQ from AESS to Cortex A9 */
+ atc_reg = 0x01;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_ATC, 0x40, &atc_reg, 4);
+ return 0;
+}
+EXPORT_SYMBOL(abe_disable_irq);
+/**
+ * abe_check_activity - Check if some ABE activity.
+ *
+ * Check if any ABE ports are running.
+ * return 1: still activity on ABE
+ * return 0: no more activity on ABE. Event generator can be stopped
+ *
+ */
+u32 abe_check_activity(void)
+{
+ u32 i;
+ u32 ret;
+ ret = 0;
+ for (i = 0; i < (LAST_PORT_ID - 1); i++) {
+ if (abe_port[abe_port_priority[i]].status ==
+ OMAP_ABE_PORT_ACTIVITY_RUNNING)
+ break;
+ }
+ if (i < (LAST_PORT_ID - 1))
+ ret = 1;
+ return ret;
+}
+EXPORT_SYMBOL(abe_check_activity);
+/**
+ * abe_init_mem - Allocate Kernel space memory map for ABE
+ *
+ * Memory map of ABE memory space for PMEM/DMEM/SMEM/DMEM
+ */
+void abe_init_mem(void __iomem *_io_base)
+{
+ io_base = _io_base;
+}
+EXPORT_SYMBOL(abe_init_mem);
diff --git a/sound/soc/omap/abe/abe_api.h b/sound/soc/omap/abe/abe_api.h
new file mode 100644
index 00000000000..df3d34a29aa
--- /dev/null
+++ b/sound/soc/omap/abe/abe_api.h
@@ -0,0 +1,516 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#ifndef _ABE_API_H_
+#define _ABE_API_H_
+/**
+ * abe_reset_hal - reset the ABE/HAL
+ * @rdev: regulator source
+ * @constraints: constraints to apply
+ *
+ * Operations : reset the HAL by reloading the static variables and
+ * default AESS registers.
+ * Called after a PRCM cold-start reset of ABE
+ */
+abehal_status abe_reset_hal(void);
+/**
+ * abe_load_fw_param - Load ABE Firmware memories
+ * @PMEM: Pointer of Program memory data
+ * @PMEM_SIZE: Size of PMEM data
+ * @CMEM: Pointer of Coeffients memory data
+ * @CMEM_SIZE: Size of CMEM data
+ * @SMEM: Pointer of Sample memory data
+ * @SMEM_SIZE: Size of SMEM data
+ * @DMEM: Pointer of Data memory data
+ * @DMEM_SIZE: Size of DMEM data
+ *
+ * loads the Audio Engine firmware, generate a single pulse on the Event
+ * generator to let execution start, read the version number returned from
+ * this execution.
+ */
+abehal_status abe_load_fw_param(u32 *FW);
+/**
+ * abe_load_fw - Load ABE Firmware and initialize memories
+ *
+ * loads the Audio Engine firmware, generate a single pulse on the Event
+ * generator to let execution start, read the version number returned from
+ * this execution.
+ */
+abehal_status abe_load_fw(void);
+/**
+ * abe_reload_fw - Reload ABE Firmware after OFF mode
+ *
+ * loads the Audio Engine firmware, generate a single pulse on the Event
+ * generator to let execution start, read the version number returned from
+ * this execution.
+ */
+abehal_status abe_reload_fw(void);
+/**
+ * abe_read_hardware_configuration - Return default HW periferals configuration
+ * @u: use-case description list (pointer)
+ * @o: opp mode (pointer)
+ * @hw: pointer to the output HW structure
+ *
+ * Parameter :
+ * U : use-case description list (pointer)
+ * H : pointer to the output structure
+ *
+ * Operations :
+ * return a structure with the HW thresholds compatible with the HAL/FW/AESS_ATC
+ * will be upgraded in FW06
+ * return a structure with the HW thresholds compatible with the HAL/FW/AESS_ATC
+ */
+abehal_status abe_read_hardware_configuration(u32 *u, u32 *o,
+ abe_hw_config_init_t *hw);
+/**
+ * abe_irq_processing - Process ABE interrupt
+ *
+ * This subroutine is call upon reception of "MA_IRQ_99 ABE_MPU_IRQ" Audio
+ * back-end interrupt. This subroutine will check the ATC Hrdware, the
+ * IRQ_FIFO from the AE and act accordingly. Some IRQ source are originated
+ * for the delivery of "end of time sequenced tasks" notifications, some are
+ * originated from the Ping-Pong protocols, some are generated from
+ * the embedded debugger when the firmware stops on programmable break-points,
+ * etc ...
+ */
+abehal_status abe_irq_processing(void);
+/**
+ * abe_clear_irq - clear ABE interrupt
+ *
+ * This subroutine is call to clear MCU Irq
+ */
+abehal_status abe_clear_irq(void);
+/**
+ * abe_disable_irq - disable MCU/DSP ABE interrupt
+ *
+ * This subroutine is disabling ABE MCU/DSP Irq
+ */
+abehal_status abe_disable_irq(void);
+/*
+ * abe_check_activity - check all ports are closed
+ */
+u32 abe_check_activity(void);
+/**
+ * abe_wakeup - Wakeup ABE
+ *
+ * Wakeup ABE in case of retention
+ */
+abehal_status abe_wakeup(void);
+/**
+ * abe_stop_event_generator - Stop event generator source
+ *
+ * Stop the event genrator of AESS. No more event will be send to AESS engine.
+ * Upper layer needs to wait 1/96kHz to be sure that engine reach IDLE instruction
+ */
+abehal_status abe_stop_event_generator(void);
+/**
+ * abe_select_main_port - Select stynchronization port for Event generator.
+ * @id: audio port name
+ *
+ * tells the FW which is the reference stream for adjusting
+ * the processing on 23/24/25 slots
+ */
+abehal_status abe_select_main_port(u32 id);
+/**
+ * abe_write_event_generator - Select event generator source
+ * @e: Event Generation Counter, McPDM, DMIC or default.
+ *
+ * load the AESS event generator hardware source. Loads the firmware parameters
+ * accordingly. Indicates to the FW which data stream is the most important to preserve
+ * in case all the streams are asynchronous. If the parameter is "default", let the HAL
+ * decide which Event source is the best appropriate based on the opened ports.
+ *
+ * When neither the DMIC and the McPDM are activated the AE will have its EVENT generator programmed
+ * with the EVENT_COUNTER. The event counter will be tuned in order to deliver a pulse frequency higher
+ * than 96 kHz. The DPLL output at 100% OPP is MCLK = (32768kHz x6000) = 196.608kHz
+ * The ratio is (MCLK/96000)+(1<<1) = 2050
+ * (1<<1) in order to have the same speed at 50% and 100% OPP (only 15 MSB bits are used at OPP50%)
+ */
+abehal_status abe_write_event_generator(u32 e);
+/**
+ * abe_read_use_case_opp() - description for void abe_read_use_case_opp().
+ *
+ * returns the expected min OPP for a given use_case list
+ */
+abehal_status abe_read_use_case_opp(u32 *u, u32 *o);
+/**
+ * abe_set_opp_processing - Set OPP mode for ABE Firmware
+ * @opp: OOPP mode
+ *
+ * New processing network and OPP:
+ * 0: Ultra Lowest power consumption audio player (no post-processing, no mixer)
+ * 1: OPP 25% (simple multimedia features, including low-power player)
+ * 2: OPP 50% (multimedia and voice calls)
+ * 3: OPP100% (EANC, multimedia complex use-cases)
+ *
+ * Rearranges the FW task network to the corresponding OPP list of features.
+ * The corresponding AE ports are supposed to be set/reset accordingly before
+ * this switch.
+ *
+ */
+abehal_status abe_set_opp_processing(u32 opp);
+/**
+ * abe_set_ping_pong_buffer
+ * @port: ABE port ID
+ * @n_bytes: Size of Ping/Pong buffer
+ *
+ * Updates the next ping-pong buffer with "size" bytes copied from the
+ * host processor. This API notifies the FW that the data transfer is done.
+ */
+abehal_status abe_set_ping_pong_buffer(u32 port, u32 n_bytes);
+/**
+ * abe_read_next_ping_pong_buffer
+ * @port: ABE portID
+ * @p: Next buffer address (pointer)
+ * @n: Next buffer size (pointer)
+ *
+ * Tell the next base address of the next ping_pong Buffer and its size
+ */
+abehal_status abe_read_next_ping_pong_buffer(u32 port, u32 *p, u32 *n);
+/**
+ * abe_init_ping_pong_buffer
+ * @id: ABE port ID
+ * @size_bytes:size of the ping pong
+ * @n_buffers:number of buffers (2 = ping/pong)
+ * @p:returned address of the ping-pong list of base address (byte offset
+ from DMEM start)
+ *
+ * Computes the base address of the ping_pong buffers
+ */
+abehal_status abe_init_ping_pong_buffer(u32 id, u32 size_bytes, u32 n_buffers,
+ u32 *p);
+/**
+ * abe_read_offset_from_ping_buffer
+ * @id: ABE port ID
+ * @n: returned address of the offset from the ping buffer start address expressed in samples
+ *
+ * Computes the current firmware ping pong read pointer location, expressed in samples,
+ * as the offset from the start address of ping buffer.
+ */
+abehal_status abe_read_offset_from_ping_buffer(u32 id, u32 *n);
+/**
+ * abe_plug_subroutine
+ * @id: returned sequence index after plugging a new subroutine
+ * @f: subroutine address to be inserted
+ * @n: number of parameters of this subroutine
+ * @params: pointer on parameters
+ *
+ * register a list of subroutines for call-back purpose
+ */
+abehal_status abe_plug_subroutine(u32 *id, abe_subroutine2 f, u32 n,
+ u32 *params);
+/**
+ * abe_set_sequence_time_accuracy
+ * @fast: fast counter
+ * @slow: slow counter
+ *
+ */
+abehal_status abe_set_sequence_time_accuracy(u32 fast, u32 slow);
+/**
+ * abe_reset_port
+ * @id: ABE port ID
+ *
+ * stop the port activity and reload default parameters on the associated
+ * processing features.
+ * Clears the internal AE buffers.
+ */
+abehal_status abe_reset_port(u32 id);
+/**
+ * abe_read_remaining_data
+ * @id: ABE port_ID
+ * @n: size pointer to the remaining number of 32bits words
+ *
+ * computes the remaining amount of data in the buffer.
+ */
+abehal_status abe_read_remaining_data(u32 port, u32 *n);
+/**
+ * abe_disable_data_transfer
+ * @id: ABE port id
+ *
+ * disables the ATC descriptor and stop IO/port activities
+ * disable the IO task (@f = 0)
+ * clear ATC DMEM buffer, ATC enabled
+ */
+abehal_status abe_disable_data_transfer(u32 id);
+/**
+ * abe_enable_data_transfer
+ * @ip: ABE port id
+ *
+ * enables the ATC descriptor
+ * reset ATC pointers
+ * enable the IO task (@f <> 0)
+ */
+abehal_status abe_enable_data_transfer(u32 id);
+/**
+ * abe_set_dmic_filter
+ * @d: DMIC decimation ratio : 16/25/32/40
+ *
+ * Loads in CMEM a specific list of coefficients depending on the DMIC sampling
+ * frequency (2.4MHz or 3.84MHz). This table compensates the DMIC decimator
+ * roll-off at 20kHz.
+ * The default table is loaded with the DMIC 2.4MHz recommended configuration.
+ */
+abehal_status abe_set_dmic_filter(u32 d);
+/**
+ * abe_connect_cbpr_dmareq_port
+ * @id: port name
+ * @f: desired data format
+ * @d: desired dma_request line (0..7)
+ * @a: returned pointer to the base address of the CBPr register and number of
+ * samples to exchange during a DMA_request.
+ *
+ * enables the data echange between a DMA and the ABE through the
+ * CBPr registers of AESS.
+ */
+abehal_status abe_connect_cbpr_dmareq_port(u32 id, abe_data_format_t *f, u32 d,
+ abe_dma_t *returned_dma_t);
+/**
+ * abe_connect_dmareq_ping_pong_port
+ * @id: port name
+ * @f: desired data format
+ * @d: desired dma_request line (0..7)
+ * @s: half-buffer (ping) size
+ * @a: returned pointer to the base address of the ping-pong buffer and number
+ * of samples to exchange during a DMA_request.
+ *
+ * enables the data echanges between a DMA and a direct access to
+ * the DMEM memory of ABE. On each dma_request activation the DMA will exchange
+ * "s" bytes and switch to the "pong" buffer for a new buffer exchange.
+ */
+abehal_status abe_connect_dmareq_ping_pong_port(u32 id, abe_data_format_t *f,
+ u32 d, u32 s,
+ abe_dma_t *returned_dma_t);
+/**
+ * abe_connect_irq_ping_pong_port
+ * @id: port name
+ * @f: desired data format
+ * @I: index of the call-back subroutine to call
+ * @s: half-buffer (ping) size
+ * @p: returned base address of the first (ping) buffer)
+ *
+ * enables the data echanges between a direct access to the DMEM
+ * memory of ABE using cache flush. On each IRQ activation a subroutine
+ * registered with "abe_plug_subroutine" will be called. This subroutine
+ * will generate an amount of samples, send them to DMEM memory and call
+ * "abe_set_ping_pong_buffer" to notify the new amount of samples in the
+ * pong buffer.
+ */
+abehal_status abe_connect_irq_ping_pong_port(u32 id, abe_data_format_t *f,
+ u32 subroutine_id, u32 size,
+ u32 *sink, u32 dsp_mcu_flag);
+/**
+ * abe_connect_serial_port()
+ * @id: port name
+ * @f: data format
+ * @i: peripheral ID (McBSP #1, #2, #3)
+ *
+ * Operations : enables the data echanges between a McBSP and an ATC buffer in
+ * DMEM. This API is used connect 48kHz McBSP streams to MM_DL and 8/16kHz
+ * voice streams to VX_UL, VX_DL, BT_VX_UL, BT_VX_DL. It abstracts the
+ * abe_write_port API.
+ */
+abehal_status abe_connect_serial_port(u32 id, abe_data_format_t *f,
+ u32 mcbsp_id);
+/**
+ * abe_connect_slimbus_port
+ * @id: port name
+ * @f: data format
+ * @i: peripheral ID (McBSP #1, #2, #3)
+ * @j: peripheral ID (McBSP #1, #2, #3)
+ *
+ * enables the data echanges between 1/2 SB and an ATC buffers in
+ * DMEM.
+ */
+abehal_status abe_connect_slimbus_port(u32 id, abe_data_format_t *f,
+ u32 sb_port1, u32 sb_port2);
+/**
+ * abe_connect_tdm_port
+ * @id: port name
+ * @f: data format
+ * @i: peripheral ID (McBSP #1, #2, #3)
+ * @j: peripheral ID (McBSP #1, #2, #3)
+ *
+ * enables the data echanges between TDM McBSP ATC buffers in
+ * DMEM and 1/2 SMEM buffers
+ */
+abehal_status abe_connect_tdm_port(u32 id, abe_data_format_t *f, u32 mcbsp_id);
+/**
+ * abe_read_port_address
+ * @dma: output pointer to the DMA iteration and data destination pointer
+ *
+ * This API returns the address of the DMA register used on this audio port.
+ * Depending on the protocol being used, adds the base address offset L3
+ * (DMA) or MPU (ARM)
+ */
+abehal_status abe_read_port_address(u32 port, abe_dma_t *dma2);
+/**
+ * abe_write_equalizer
+ * @id: name of the equalizer
+ * @param : equalizer coefficients
+ *
+ * Load the coefficients in CMEM.
+ */
+abehal_status abe_write_equalizer(u32 id, abe_equ_t *param);
+/**
+ * abe_write_asrc
+ * @id: name of the port
+ * @param: drift value to compensate [ppm]
+ *
+ * Load the drift variables to the FW memory. This API can be called only
+ * when the corresponding port has been already opened and the ASRC has
+ * been correctly initialized with API abe_init_asrc_... If this API is
+ * used such that the drift has been changed from positive to negative drift
+ * or vice versa, there will be click in the output signal. Loading the drift
+ * value with zero disables the feature.
+ */
+abehal_status abe_write_asrc(u32 port, s32 dppm);
+/**
+ * abe_write_aps
+ * @id: name of the aps filter
+ * @param: table of filter coefficients
+ *
+ * Load the filters and thresholds coefficients in FW memory. This AP
+ * can be called when the corresponding APS is not activated. After
+ * reloading the firmware the default coefficients corresponds to "no APS
+ * activated".
+ * Loading all the coefficients value with zero disables the feature.
+ */
+abehal_status abe_write_aps(u32 id, abe_aps_t *param);
+/**
+ * abe_write_mixer
+ * @id: name of the mixer
+ * @param: list of input gains of the mixer
+ * @p: list of port corresponding to the above gains
+ *
+ * Load the gain coefficients in FW memory. This API can be called when
+ * the corresponding MIXER is not activated. After reloading the firmware
+ * the default coefficients corresponds to "all input and output mixer's gain
+ * in mute state". A mixer is disabled with a network reconfiguration
+ * corresponding to an OPP value.
+ */
+abehal_status abe_write_gain(u32 id, s32 f_g, u32 ramp, u32 p);
+abehal_status abe_use_compensated_gain(u32 on_off);
+abehal_status abe_enable_gain(u32 id, u32 p);
+abehal_status abe_disable_gain(u32 id, u32 p);
+abehal_status abe_mute_gain(u32 id, u32 p);
+abehal_status abe_unmute_gain(u32 id, u32 p);
+/**
+ * abe_write_mixer
+ * @id: name of the mixer
+ * @param: input gains and delay ramp of the mixer
+ * @p: port corresponding to the above gains
+ *
+ * Load the gain coefficients in FW memory. This API can be called when
+ * the corresponding MIXER is not activated. After reloading the firmware
+ * the default coefficients corresponds to "all input and output mixer's
+ * gain in mute state". A mixer is disabled with a network reconfiguration
+ * corresponding to an OPP value.
+ */
+abehal_status abe_write_mixer(u32 id, s32 f_g, u32 f_ramp, u32 p);
+/**
+ * abe_read_gain
+ * @id: name of the mixer
+ * @param: list of input gains of the mixer
+ * @p: list of port corresponding to the above gains
+ *
+ */
+abehal_status abe_read_gain(u32 id, u32 *f_g, u32 p);
+/**
+ * abe_read_mixer
+ * @id: name of the mixer
+ * @param: gains of the mixer
+ * @p: port corresponding to the above gains
+ *
+ * Load the gain coefficients in FW memory. This API can be called when
+ * the corresponding MIXER is not activated. After reloading the firmware
+ * the default coefficients corresponds to "all input and output mixer's
+ * gain in mute state". A mixer is disabled with a network reconfiguration
+ * corresponding to an OPP value.
+ */
+abehal_status abe_read_mixer(u32 id, u32 *f_g, u32 p);
+/**
+ * abe_set_router_configuration
+ * @Id: name of the router
+ * @Conf: id of the configuration
+ * @param: list of output index of the route
+ *
+ * The uplink router takes its input from DMIC (6 samples), AMIC (2 samples)
+ * and PORT1/2 (2 stereo ports). Each sample will be individually stored in
+ * an intermediate table of 10 elements. The intermediate table is used to
+ * route the samples to three directions : REC1 mixer, 2 EANC DMIC source of
+ * filtering and MM recording audio path.
+ */
+abehal_status abe_set_router_configuration(u32 id, u32 k, u32 *param);
+/**
+ * abe_select_data_source
+ * @@@
+ */
+abehal_status abe_select_data_source(u32 port_id, u32 smem_source);
+/**
+ * ABE_READ_DEBUG_TRACE
+ *
+ * Parameter :
+ * data destination pointer
+ * max number of data read
+ *
+ * Operations :
+ * reads the AE circular data pointer holding pairs of debug data+
+ * timestamps, and store the pairs in linear addressing to the parameter
+ * pointer. Stops the copy when the max parameter is reached or when the
+ * FIFO is empty.
+ *
+ * Return value :
+ * None.
+ */
+abehal_status abe_read_debug_trace(u32 *data, u32 *n);
+/**
+ * abe_connect_debug_trace
+ * @dma2:pointer to the DMEM trace buffer
+ *
+ * returns the address and size of the real-time debug trace buffer,
+ * the content of which will vary from one firmware release to an other
+ */
+abehal_status abe_connect_debug_trace(abe_dma_t *dma2);
+/**
+ * abe_set_debug_trace
+ * @debug: debug ID from a list to be defined
+ *
+ * load a mask which filters the debug trace to dedicated types of data
+ */
+abehal_status abe_set_debug_trace(abe_dbg_t debug);
+/**
+ * abe_remote_debugger_interface
+ *
+ * interpretation of the UART stream from the remote debugger commands.
+ * The commands consist in setting break points, loading parameter
+ */
+abehal_status abe_remote_debugger_interface(u32 n, u8 *p);
+/**
+ * abe_enable_test_pattern
+ *
+ */
+abehal_status abe_enable_test_pattern(u32 smem_id, u32 on_off);
+/**
+ * abe_init_mem - Allocate Kernel space memory map for ABE
+ *
+ * Memory map of ABE memory space for PMEM/DMEM/SMEM/DMEM
+ */
+void abe_init_mem(void __iomem *_io_base);
+#endif/* _ABE_API_H_ */
diff --git a/sound/soc/omap/abe/abe_cm_addr.h b/sound/soc/omap/abe/abe_cm_addr.h
new file mode 100644
index 00000000000..070c961c6ed
--- /dev/null
+++ b/sound/soc/omap/abe/abe_cm_addr.h
@@ -0,0 +1,284 @@
+/*
+ * ALSA SoC OMAP ABE driver
+*
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef _ABE_CM_ADDR_H_
+#define _ABE_CM_ADDR_H_
+#define init_CM_ADDR 0
+#define init_CM_ADDR_END 309
+#define init_CM_sizeof 310
+#define C_Data_LSB_2_ADDR 310
+#define C_Data_LSB_2_ADDR_END 310
+#define C_Data_LSB_2_sizeof 1
+#define C_1_Alpha_ADDR 311
+#define C_1_Alpha_ADDR_END 328
+#define C_1_Alpha_sizeof 18
+#define C_Alpha_ADDR 329
+#define C_Alpha_ADDR_END 346
+#define C_Alpha_sizeof 18
+#define C_GainsWRamp_ADDR 347
+#define C_GainsWRamp_ADDR_END 360
+#define C_GainsWRamp_sizeof 14
+#define C_Gains_DL1M_ADDR 361
+#define C_Gains_DL1M_ADDR_END 364
+#define C_Gains_DL1M_sizeof 4
+#define C_Gains_DL2M_ADDR 365
+#define C_Gains_DL2M_ADDR_END 368
+#define C_Gains_DL2M_sizeof 4
+#define C_Gains_EchoM_ADDR 369
+#define C_Gains_EchoM_ADDR_END 370
+#define C_Gains_EchoM_sizeof 2
+#define C_Gains_SDTM_ADDR 371
+#define C_Gains_SDTM_ADDR_END 372
+#define C_Gains_SDTM_sizeof 2
+#define C_Gains_VxRecM_ADDR 373
+#define C_Gains_VxRecM_ADDR_END 376
+#define C_Gains_VxRecM_sizeof 4
+#define C_Gains_ULM_ADDR 377
+#define C_Gains_ULM_ADDR_END 380
+#define C_Gains_ULM_sizeof 4
+#define C_Gains_unused_ADDR 381
+#define C_Gains_unused_ADDR_END 382
+#define C_Gains_unused_sizeof 2
+#define C_SDT_Coefs_ADDR 383
+#define C_SDT_Coefs_ADDR_END 391
+#define C_SDT_Coefs_sizeof 9
+#define C_CoefASRC1_VX_ADDR 392
+#define C_CoefASRC1_VX_ADDR_END 410
+#define C_CoefASRC1_VX_sizeof 19
+#define C_CoefASRC2_VX_ADDR 411
+#define C_CoefASRC2_VX_ADDR_END 429
+#define C_CoefASRC2_VX_sizeof 19
+#define C_CoefASRC3_VX_ADDR 430
+#define C_CoefASRC3_VX_ADDR_END 448
+#define C_CoefASRC3_VX_sizeof 19
+#define C_CoefASRC4_VX_ADDR 449
+#define C_CoefASRC4_VX_ADDR_END 467
+#define C_CoefASRC4_VX_sizeof 19
+#define C_CoefASRC5_VX_ADDR 468
+#define C_CoefASRC5_VX_ADDR_END 486
+#define C_CoefASRC5_VX_sizeof 19
+#define C_CoefASRC6_VX_ADDR 487
+#define C_CoefASRC6_VX_ADDR_END 505
+#define C_CoefASRC6_VX_sizeof 19
+#define C_CoefASRC7_VX_ADDR 506
+#define C_CoefASRC7_VX_ADDR_END 524
+#define C_CoefASRC7_VX_sizeof 19
+#define C_CoefASRC8_VX_ADDR 525
+#define C_CoefASRC8_VX_ADDR_END 543
+#define C_CoefASRC8_VX_sizeof 19
+#define C_CoefASRC9_VX_ADDR 544
+#define C_CoefASRC9_VX_ADDR_END 562
+#define C_CoefASRC9_VX_sizeof 19
+#define C_CoefASRC10_VX_ADDR 563
+#define C_CoefASRC10_VX_ADDR_END 581
+#define C_CoefASRC10_VX_sizeof 19
+#define C_CoefASRC11_VX_ADDR 582
+#define C_CoefASRC11_VX_ADDR_END 600
+#define C_CoefASRC11_VX_sizeof 19
+#define C_CoefASRC12_VX_ADDR 601
+#define C_CoefASRC12_VX_ADDR_END 619
+#define C_CoefASRC12_VX_sizeof 19
+#define C_CoefASRC13_VX_ADDR 620
+#define C_CoefASRC13_VX_ADDR_END 638
+#define C_CoefASRC13_VX_sizeof 19
+#define C_CoefASRC14_VX_ADDR 639
+#define C_CoefASRC14_VX_ADDR_END 657
+#define C_CoefASRC14_VX_sizeof 19
+#define C_CoefASRC15_VX_ADDR 658
+#define C_CoefASRC15_VX_ADDR_END 676
+#define C_CoefASRC15_VX_sizeof 19
+#define C_CoefASRC16_VX_ADDR 677
+#define C_CoefASRC16_VX_ADDR_END 695
+#define C_CoefASRC16_VX_sizeof 19
+#define C_AlphaCurrent_UL_VX_ADDR 696
+#define C_AlphaCurrent_UL_VX_ADDR_END 696
+#define C_AlphaCurrent_UL_VX_sizeof 1
+#define C_BetaCurrent_UL_VX_ADDR 697
+#define C_BetaCurrent_UL_VX_ADDR_END 697
+#define C_BetaCurrent_UL_VX_sizeof 1
+#define C_AlphaCurrent_DL_VX_ADDR 698
+#define C_AlphaCurrent_DL_VX_ADDR_END 698
+#define C_AlphaCurrent_DL_VX_sizeof 1
+#define C_BetaCurrent_DL_VX_ADDR 699
+#define C_BetaCurrent_DL_VX_ADDR_END 699
+#define C_BetaCurrent_DL_VX_sizeof 1
+#define C_CoefASRC1_MM_ADDR 700
+#define C_CoefASRC1_MM_ADDR_END 717
+#define C_CoefASRC1_MM_sizeof 18
+#define C_CoefASRC2_MM_ADDR 718
+#define C_CoefASRC2_MM_ADDR_END 735
+#define C_CoefASRC2_MM_sizeof 18
+#define C_CoefASRC3_MM_ADDR 736
+#define C_CoefASRC3_MM_ADDR_END 753
+#define C_CoefASRC3_MM_sizeof 18
+#define C_CoefASRC4_MM_ADDR 754
+#define C_CoefASRC4_MM_ADDR_END 771
+#define C_CoefASRC4_MM_sizeof 18
+#define C_CoefASRC5_MM_ADDR 772
+#define C_CoefASRC5_MM_ADDR_END 789
+#define C_CoefASRC5_MM_sizeof 18
+#define C_CoefASRC6_MM_ADDR 790
+#define C_CoefASRC6_MM_ADDR_END 807
+#define C_CoefASRC6_MM_sizeof 18
+#define C_CoefASRC7_MM_ADDR 808
+#define C_CoefASRC7_MM_ADDR_END 825
+#define C_CoefASRC7_MM_sizeof 18
+#define C_CoefASRC8_MM_ADDR 826
+#define C_CoefASRC8_MM_ADDR_END 843
+#define C_CoefASRC8_MM_sizeof 18
+#define C_CoefASRC9_MM_ADDR 844
+#define C_CoefASRC9_MM_ADDR_END 861
+#define C_CoefASRC9_MM_sizeof 18
+#define C_CoefASRC10_MM_ADDR 862
+#define C_CoefASRC10_MM_ADDR_END 879
+#define C_CoefASRC10_MM_sizeof 18
+#define C_CoefASRC11_MM_ADDR 880
+#define C_CoefASRC11_MM_ADDR_END 897
+#define C_CoefASRC11_MM_sizeof 18
+#define C_CoefASRC12_MM_ADDR 898
+#define C_CoefASRC12_MM_ADDR_END 915
+#define C_CoefASRC12_MM_sizeof 18
+#define C_CoefASRC13_MM_ADDR 916
+#define C_CoefASRC13_MM_ADDR_END 933
+#define C_CoefASRC13_MM_sizeof 18
+#define C_CoefASRC14_MM_ADDR 934
+#define C_CoefASRC14_MM_ADDR_END 951
+#define C_CoefASRC14_MM_sizeof 18
+#define C_CoefASRC15_MM_ADDR 952
+#define C_CoefASRC15_MM_ADDR_END 969
+#define C_CoefASRC15_MM_sizeof 18
+#define C_CoefASRC16_MM_ADDR 970
+#define C_CoefASRC16_MM_ADDR_END 987
+#define C_CoefASRC16_MM_sizeof 18
+#define C_AlphaCurrent_MM_EXT_IN_ADDR 988
+#define C_AlphaCurrent_MM_EXT_IN_ADDR_END 988
+#define C_AlphaCurrent_MM_EXT_IN_sizeof 1
+#define C_BetaCurrent_MM_EXT_IN_ADDR 989
+#define C_BetaCurrent_MM_EXT_IN_ADDR_END 989
+#define C_BetaCurrent_MM_EXT_IN_sizeof 1
+#define C_DL2_L_Coefs_ADDR 990
+#define C_DL2_L_Coefs_ADDR_END 1014
+#define C_DL2_L_Coefs_sizeof 25
+#define C_DL2_R_Coefs_ADDR 1015
+#define C_DL2_R_Coefs_ADDR_END 1039
+#define C_DL2_R_Coefs_sizeof 25
+#define C_DL1_Coefs_ADDR 1040
+#define C_DL1_Coefs_ADDR_END 1064
+#define C_DL1_Coefs_sizeof 25
+#define C_SRC_3_LP_Coefs_ADDR 1065
+#define C_SRC_3_LP_Coefs_ADDR_END 1075
+#define C_SRC_3_LP_Coefs_sizeof 11
+#define C_SRC_3_LP_GAIN_Coefs_ADDR 1076
+#define C_SRC_3_LP_GAIN_Coefs_ADDR_END 1086
+#define C_SRC_3_LP_GAIN_Coefs_sizeof 11
+#define C_SRC_3_HP_Coefs_ADDR 1087
+#define C_SRC_3_HP_Coefs_ADDR_END 1091
+#define C_SRC_3_HP_Coefs_sizeof 5
+#define C_SRC_6_LP_Coefs_ADDR 1092
+#define C_SRC_6_LP_Coefs_ADDR_END 1102
+#define C_SRC_6_LP_Coefs_sizeof 11
+#define C_SRC_6_LP_GAIN_Coefs_ADDR 1103
+#define C_SRC_6_LP_GAIN_Coefs_ADDR_END 1113
+#define C_SRC_6_LP_GAIN_Coefs_sizeof 11
+#define C_SRC_6_HP_Coefs_ADDR 1114
+#define C_SRC_6_HP_Coefs_ADDR_END 1120
+#define C_SRC_6_HP_Coefs_sizeof 7
+#define C_APS_DL1_coeffs1_ADDR 1121
+#define C_APS_DL1_coeffs1_ADDR_END 1129
+#define C_APS_DL1_coeffs1_sizeof 9
+#define C_APS_DL1_M_coeffs2_ADDR 1130
+#define C_APS_DL1_M_coeffs2_ADDR_END 1132
+#define C_APS_DL1_M_coeffs2_sizeof 3
+#define C_APS_DL1_C_coeffs2_ADDR 1133
+#define C_APS_DL1_C_coeffs2_ADDR_END 1135
+#define C_APS_DL1_C_coeffs2_sizeof 3
+#define C_APS_DL2_L_coeffs1_ADDR 1136
+#define C_APS_DL2_L_coeffs1_ADDR_END 1144
+#define C_APS_DL2_L_coeffs1_sizeof 9
+#define C_APS_DL2_R_coeffs1_ADDR 1145
+#define C_APS_DL2_R_coeffs1_ADDR_END 1153
+#define C_APS_DL2_R_coeffs1_sizeof 9
+#define C_APS_DL2_L_M_coeffs2_ADDR 1154
+#define C_APS_DL2_L_M_coeffs2_ADDR_END 1156
+#define C_APS_DL2_L_M_coeffs2_sizeof 3
+#define C_APS_DL2_R_M_coeffs2_ADDR 1157
+#define C_APS_DL2_R_M_coeffs2_ADDR_END 1159
+#define C_APS_DL2_R_M_coeffs2_sizeof 3
+#define C_APS_DL2_L_C_coeffs2_ADDR 1160
+#define C_APS_DL2_L_C_coeffs2_ADDR_END 1162
+#define C_APS_DL2_L_C_coeffs2_sizeof 3
+#define C_APS_DL2_R_C_coeffs2_ADDR 1163
+#define C_APS_DL2_R_C_coeffs2_ADDR_END 1165
+#define C_APS_DL2_R_C_coeffs2_sizeof 3
+#define C_AlphaCurrent_ECHO_REF_ADDR 1166
+#define C_AlphaCurrent_ECHO_REF_ADDR_END 1166
+#define C_AlphaCurrent_ECHO_REF_sizeof 1
+#define C_BetaCurrent_ECHO_REF_ADDR 1167
+#define C_BetaCurrent_ECHO_REF_ADDR_END 1167
+#define C_BetaCurrent_ECHO_REF_sizeof 1
+#define C_APS_DL1_EQ_ADDR 1168
+#define C_APS_DL1_EQ_ADDR_END 1176
+#define C_APS_DL1_EQ_sizeof 9
+#define C_APS_DL2_L_EQ_ADDR 1177
+#define C_APS_DL2_L_EQ_ADDR_END 1185
+#define C_APS_DL2_L_EQ_sizeof 9
+#define C_APS_DL2_R_EQ_ADDR 1186
+#define C_APS_DL2_R_EQ_ADDR_END 1194
+#define C_APS_DL2_R_EQ_sizeof 9
+#define C_Vibra2_consts_ADDR 1195
+#define C_Vibra2_consts_ADDR_END 1198
+#define C_Vibra2_consts_sizeof 4
+#define C_Vibra1_coeffs_ADDR 1199
+#define C_Vibra1_coeffs_ADDR_END 1209
+#define C_Vibra1_coeffs_sizeof 11
+#define C_48_96_LP_Coefs_ADDR 1210
+#define C_48_96_LP_Coefs_ADDR_END 1224
+#define C_48_96_LP_Coefs_sizeof 15
+#define C_96_48_AMIC_Coefs_ADDR 1225
+#define C_96_48_AMIC_Coefs_ADDR_END 1243
+#define C_96_48_AMIC_Coefs_sizeof 19
+#define C_96_48_DMIC_Coefs_ADDR 1244
+#define C_96_48_DMIC_Coefs_ADDR_END 1262
+#define C_96_48_DMIC_Coefs_sizeof 19
+#define C_INPUT_SCALE_ADDR 1263
+#define C_INPUT_SCALE_ADDR_END 1263
+#define C_INPUT_SCALE_sizeof 1
+#define C_OUTPUT_SCALE_ADDR 1264
+#define C_OUTPUT_SCALE_ADDR_END 1264
+#define C_OUTPUT_SCALE_sizeof 1
+#define C_MUTE_SCALING_ADDR 1265
+#define C_MUTE_SCALING_ADDR_END 1265
+#define C_MUTE_SCALING_sizeof 1
+#define C_GAINS_0DB_ADDR 1266
+#define C_GAINS_0DB_ADDR_END 1267
+#define C_GAINS_0DB_sizeof 2
+#define C_AlphaCurrent_BT_UL_ADDR 1268
+#define C_AlphaCurrent_BT_UL_ADDR_END 1268
+#define C_AlphaCurrent_BT_UL_sizeof 1
+#define C_BetaCurrent_BT_UL_ADDR 1269
+#define C_BetaCurrent_BT_UL_ADDR_END 1269
+#define C_BetaCurrent_BT_UL_sizeof 1
+#define C_AlphaCurrent_BT_DL_ADDR 1270
+#define C_AlphaCurrent_BT_DL_ADDR_END 1270
+#define C_AlphaCurrent_BT_DL_sizeof 1
+#define C_BetaCurrent_BT_DL_ADDR 1271
+#define C_BetaCurrent_BT_DL_ADDR_END 1271
+#define C_BetaCurrent_BT_DL_sizeof 1
+#endif/* _ABECM_ADDR_H_ */
diff --git a/sound/soc/omap/abe/abe_dat.c b/sound/soc/omap/abe/abe_dat.c
new file mode 100644
index 00000000000..82129921fcd
--- /dev/null
+++ b/sound/soc/omap/abe/abe_dat.c
@@ -0,0 +1,862 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <linux/module.h>
+#include "abe_main.h"
+#ifndef abe_dat_c
+#define abe_dat_c
+const u32 abe_firmware_array[ABE_FIRMWARE_MAX_SIZE] = {
+#include "abe_firmware.c"
+};
+u32 abe_firmware_version_number;
+/*
+ * Kernel base
+ */
+void __iomem *io_base;
+/*
+ * global variable : saves stack area
+ */
+u16 MultiFrame[PROCESSING_SLOTS][TASKS_IN_SLOT];
+ABE_SIODescriptor sio_desc;
+ABE_SPingPongDescriptor desc_pp;
+abe_satcdescriptor_aess atc_desc;
+/*
+ * automatic gain control of input mixer's gains
+ */
+u32 abe_compensated_mixer_gain;
+u8 abe_muted_gains_indicator[MAX_NBGAIN_CMEM];
+u32 abe_desired_gains_decibel[MAX_NBGAIN_CMEM];
+u32 abe_muted_gains_decibel[MAX_NBGAIN_CMEM];
+u32 abe_desired_gains_linear[MAX_NBGAIN_CMEM];
+u32 abe_desired_ramp_delay_ms[MAX_NBGAIN_CMEM];
+/*
+ * HAL/FW ports status / format / sampling / protocol(call_back) / features
+ * / gain / name
+ */
+u32 pdm_dl1_status;
+u32 pdm_dl2_status;
+u32 pdm_vib_status;
+/*
+ * HAL/FW ports status / format / sampling / protocol(call_back) / features
+ * / gain / name
+ */
+abe_port_t abe_port[LAST_PORT_ID]; /* list of ABE ports */
+const abe_port_t abe_port_init[LAST_PORT_ID] = {
+ /* Status Data Format Drift Call-Back Protocol+selector desc_addr;
+ buf_addr; buf_size; iter; irq_addr irq_data DMA_T $Features
+ reseted at start Port Name for the debug trace */
+ /* DMIC */ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {96000, SIX_MSB},
+ NODRIFT, NOCALLBACK, 0, (DMIC_ITER / 6),
+ {
+ SNK_P, DMIC_PORT_PROT,
+ {{dmem_dmic, dmem_dmic_size, DMIC_ITER} }
+ },
+ {0, 0},
+ {EQDMIC, 0}, "DMIC"},
+ /* PDM_UL */ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {96000, STEREO_MSB},
+ NODRIFT, NOCALLBACK, smem_amic, (MCPDM_UL_ITER / 2),
+ {
+ SNK_P, MCPDMUL_PORT_PROT,
+ {{dmem_amic, dmem_amic_size, MCPDM_UL_ITER} }
+ },
+ {0, 0},
+ {EQAMIC, 0}, "PDM_UL"},
+ /* BT_VX_UL */ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {8000, STEREO_MSB},
+ NODRIFT, NOCALLBACK, smem_bt_vx_ul_opp50, 1,
+ {
+ SNK_P, SERIAL_PORT_PROT, {{
+ (MCBSP1_DMA_TX*ATC_SIZE),
+ dmem_bt_vx_ul,
+ dmem_bt_vx_ul_size,
+ (1*SCHED_LOOP_8kHz)
+ } }
+ },
+ {0, 0}, {0}, "BT_VX_UL"},
+ /* MM_UL */ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, STEREO_MSB},
+ NODRIFT, NOCALLBACK, smem_mm_ul, 1,
+ {
+ SRC_P, DMAREQ_PORT_PROT, {{
+ (CBPr_DMA_RTX3*ATC_SIZE),
+ dmem_mm_ul, dmem_mm_ul_size,
+ (10*SCHED_LOOP_48kHz),
+ ABE_DMASTATUS_RAW, (1 << 3)
+ } }
+ },
+ {CIRCULAR_BUFFER_PERIPHERAL_R__3, 120},
+ {UPROUTE, 0}, "MM_UL"},
+ /* MM_UL2 */ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, STEREO_MSB},
+ NODRIFT, NOCALLBACK, smem_mm_ul2, 1,
+ {
+ SRC_P, DMAREQ_PORT_PROT, {{
+ (CBPr_DMA_RTX4*ATC_SIZE),
+ dmem_mm_ul2, dmem_mm_ul2_size,
+ (2*SCHED_LOOP_48kHz),
+ ABE_DMASTATUS_RAW, (1 << 4)
+ } }
+ },
+ {CIRCULAR_BUFFER_PERIPHERAL_R__4, 24},
+ {UPROUTE, 0}, "MM_UL2"},
+ /* VX_UL */ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {8000, MONO_MSB},
+ NODRIFT, NOCALLBACK, smem_vx_ul, 1,
+ {
+ SRC_P, DMAREQ_PORT_PROT, {{
+ (CBPr_DMA_RTX2*ATC_SIZE),
+ dmem_vx_ul, dmem_vx_ul_size,
+ (1*SCHED_LOOP_8kHz),
+ ABE_DMASTATUS_RAW, (1 << 2)
+ } }
+ }, {
+ CIRCULAR_BUFFER_PERIPHERAL_R__2, 2},
+ {ASRC2, 0}, "VX_UL"},
+ /* MM_DL */ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, STEREO_MSB},
+ NODRIFT, NOCALLBACK, smem_mm_dl, 1,
+ {
+ SNK_P, PINGPONG_PORT_PROT, {{
+ (CBPr_DMA_RTX0*ATC_SIZE),
+ dmem_mm_dl, dmem_mm_dl_size,
+ (2*SCHED_LOOP_48kHz),
+ ABE_DMASTATUS_RAW, (1 << 0)
+ } }
+ },
+ {CIRCULAR_BUFFER_PERIPHERAL_R__0, 24},
+ {ASRC3, 0}, "MM_DL"},
+ /* VX_DL */ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {8000, MONO_MSB},
+ NODRIFT, NOCALLBACK, smem_vx_dl, 1,
+ {
+ SNK_P, DMAREQ_PORT_PROT, {{
+ (CBPr_DMA_RTX1*ATC_SIZE),
+ dmem_vx_dl, dmem_vx_dl_size,
+ (1*SCHED_LOOP_8kHz),
+ ABE_DMASTATUS_RAW, (1 << 1)
+ } }
+ },
+ {CIRCULAR_BUFFER_PERIPHERAL_R__1, 2},
+ {ASRC1, 0}, "VX_DL"},
+ /* TONES_DL */ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, STEREO_MSB},
+ NODRIFT, NOCALLBACK, smem_tones_dl, 1,
+ {
+ SNK_P, DMAREQ_PORT_PROT, {{
+ (CBPr_DMA_RTX5*ATC_SIZE),
+ dmem_tones_dl,
+ dmem_tones_dl_size,
+ (2*SCHED_LOOP_48kHz),
+ ABE_DMASTATUS_RAW, (1 << 5)
+ } }
+ },
+ {CIRCULAR_BUFFER_PERIPHERAL_R__5, 24},
+ {0}, "TONES_DL"},
+ /* VIB_DL */ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {24000, STEREO_MSB},
+ NODRIFT, NOCALLBACK, smem_vib, 1,
+ {
+ SNK_P, DMAREQ_PORT_PROT, {{
+ (CBPr_DMA_RTX6*ATC_SIZE),
+ dmem_vib_dl, dmem_vib_dl_size,
+ (2*SCHED_LOOP_24kHz),
+ ABE_DMASTATUS_RAW, (1 << 6)
+ } }
+ },
+ {CIRCULAR_BUFFER_PERIPHERAL_R__6, 12},
+ {0}, "VIB_DL"},
+ /* BT_VX_DL */ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {8000, MONO_MSB},
+ NODRIFT, NOCALLBACK, smem_bt_vx_dl_opp50, 1,
+ {
+ SRC_P, SERIAL_PORT_PROT, {{
+ (MCBSP1_DMA_RX*ATC_SIZE),
+ dmem_bt_vx_dl,
+ dmem_bt_vx_dl_size,
+ (1*SCHED_LOOP_8kHz),
+ } }
+ },
+ {0, 0}, {0}, "BT_VX_DL"},
+ /* PDM_DL */ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {96000, SIX_MSB},
+ NODRIFT, NOCALLBACK, 0, (MCPDM_DL_ITER / 6),
+ {SRC_P, MCPDMDL_PORT_PROT,
+ {{dmem_mcpdm, dmem_mcpdm_size} } },
+ {0, 0},
+ {MIXDL1, EQ1, APS1, MIXDL2, EQ2L, EQ2R, APS2L, APS2R, 0},
+ "PDM_DL"},
+ /* MM_EXT_OUT */
+ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, STEREO_MSB},
+ NODRIFT, NOCALLBACK, smem_mm_ext_out, 1,
+ {
+ SRC_P, SERIAL_PORT_PROT, {{
+ (MCBSP1_DMA_TX*ATC_SIZE),
+ dmem_mm_ext_out, dmem_mm_ext_out_size,
+ (2*SCHED_LOOP_48kHz)
+ } }
+ }, {0, 0}, {0}, "MM_EXT_OUT"},
+ /* MM_EXT_IN */
+ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, STEREO_MSB},
+ NODRIFT, NOCALLBACK, smem_mm_ext_in_opp100, 1,
+ {
+ SNK_P, SERIAL_PORT_PROT, {{
+ (MCBSP1_DMA_RX*ATC_SIZE),
+ dmem_mm_ext_in, dmem_mm_ext_in_size,
+ (2*SCHED_LOOP_48kHz)
+ } }
+ },
+ {0, 0}, {0}, "MM_EXT_IN"},
+ /* PCM3_TX */ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, STEREO_MSB},
+ NODRIFT, NOCALLBACK, 0, 1,
+ {
+ SRC_P, TDM_SERIAL_PORT_PROT, {{
+ (MCBSP3_DMA_TX *
+ ATC_SIZE),
+ dmem_mm_ext_out,
+ dmem_mm_ext_out_size,
+ (2*SCHED_LOOP_48kHz)
+ } }
+ },
+ {0, 0}, {0}, "TDM_OUT"},
+ /* PCM3_RX */ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, STEREO_MSB},
+ NODRIFT, NOCALLBACK, 0, 1,
+ {
+ SRC_P, TDM_SERIAL_PORT_PROT, {{
+ (MCBSP3_DMA_RX *
+ ATC_SIZE),
+ dmem_mm_ext_in,
+ dmem_mm_ext_in_size,
+ (2*SCHED_LOOP_48kHz)
+ } }
+ },
+ {0, 0}, {0}, "TDM_IN"},
+ /* SCHD_DBG_PORT */ {
+ OMAP_ABE_PORT_ACTIVITY_IDLE, {48000, MONO_MSB},
+ NODRIFT, NOCALLBACK, 0, 1,
+ {
+ SRC_P, DMAREQ_PORT_PROT, {{
+ (CBPr_DMA_RTX7 *
+ ATC_SIZE),
+ dmem_mm_trace,
+ dmem_mm_trace_size,
+ (2*SCHED_LOOP_48kHz),
+ ABE_DMASTATUS_RAW,
+ (1 << 4)
+ } }
+ }, {CIRCULAR_BUFFER_PERIPHERAL_R__7, 24},
+ {FEAT_SEQ, FEAT_CTL, FEAT_GAINS, 0}, "SCHD_DBG"},
+};
+/* abe_port_init : smem content for DMIC/PDM must be 0 or Dummy_AM_labelID */
+/*
+ * Firmware features
+ */
+abe_feature_t all_feature[MAXNBFEATURE];
+const abe_feature_t all_feature_init[] = {
+ /* ON_reset OFF READ WRITE STATUS INPUT OUTPUT SLOT/S OPP NAME */
+ /* equalizer downlink path headset + earphone */
+ /* EQ1 */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq1,
+ c_write_eq1, 0, 0x1000, 0x1010, 2, 0, ABE_OPP25, " DLEQ1"},
+ /* equalizer downlink path integrated handsfree LEFT */
+ /* EQ2L */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq2,
+ c_write_eq2, 0, 0x1000, 0x1010, 2, 0, ABE_OPP100, " DLEQ2L"},
+ /* equalizer downlink path integrated handsfree RIGHT */
+ /* EQ2R */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP100, " DLEQ2R"},
+ /* equalizer downlink path side-tone */
+ /* EQSDT */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP50, " EQSDT"},
+ /* SRC+equalizer uplink DMIC 1st pair */
+ /* EQDMIC1 */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP50, " EQDMIC1"},
+ /* SRC+equalizer uplink DMIC 2nd pair */
+ /* EQDMIC2 */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP50, " EQDMIC2"},
+ /* SRC+equalizer uplink DMIC 3rd pair */
+ /* EQDMIC3 */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP50, " EQDMIC3"},
+ /* SRC+equalizer uplink AMIC */
+ /* EQAMIC */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP50, " EQAMIC"},
+ /* Acoustic protection for headset */
+ /* APS1 */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP25, " APS1"},
+ /* acoustic protection high-pass filter for handsfree "Left" */
+ /* APS2 */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP100, " APS2"},
+ /* acoustic protection high-pass filter for handsfree "Right" */
+ /* APS3 */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP100, " APS3"},
+ /* asynchronous sample-rate-converter for the downlink voice path */
+ /* ASRC1 */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP50, " ASRC_VXDL"},
+ /* asynchronous sample-rate-converter for the uplink voice path */
+ /* ASRC2 */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP50, " ASRC_VXUL"},
+ /* asynchronous sample-rate-converter for the multimedia player */
+ /* ASRC3 */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP100, " ASRC_MMDL"},
+ /* asynchronous sample-rate-converter for the echo reference */
+ /* ASRC4 */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP50, " ASRC_ECHO"},
+ /* mixer of the headset and earphone path */
+ /* MXDL1 */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP25, " MIX_DL1"},
+ /* mixer of the hands-free path */
+ /* MXDL2 */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP100, " MIX_DL2"},
+ /* mixer for uplink tone mixer */
+ /* MXAUDUL */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP50, " MXSAUDUL"},
+ /* mixer for voice recording */
+ /* MXVXREC */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP50, " MXVXREC"},
+ /* mixer for side-tone */
+ /* MXSDT */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP50, " MIX_SDT"},
+ /* mixer for echo reference */
+ /* MXECHO */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP50, " MIX_ECHO"},
+ /* router of the uplink path */
+ /* UPROUTE */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP50, " DLEQ3"},
+ /* all gains */
+ /* GAINS */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP25, " DLEQ3"},
+ /* active noise canceller */
+ /* EANC */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP100, " DLEQ3"},
+ /* sequencing queue of micro tasks */
+ /* SEQ */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP25, " DLEQ3"},
+ /* Phoenix control queue through McPDM */
+ /* CTL */
+ {
+ c_feat_init_eq, c_feat_init_eq, c_feat_read_eq3, c_write_eq3,
+ 0, 0x1000, 0x1010, 2, 0, ABE_OPP25, " DLEQ3"},
+};
+/*
+ * MEMORY MAPPING OF THE DMEM FIFOs
+ */
+/* DMEM port map */
+u32 abe_map_dmem[LAST_PORT_ID];
+u32 abe_map_dmem_secondary[LAST_PORT_ID];
+/* DMEM port buffer sizes */
+u32 abe_map_dmem_size[LAST_PORT_ID];
+/*
+ * AESS/ATC destination and source address translation (except McASPs)
+ * from the original 64bits words address
+ */
+const u32 abe_atc_dstid[ABE_ATC_DESC_SIZE >> 3] = {
+ /* DMA_0 DMIC PDM_DL PDM_UL McB1TX McB1RX McB2TX McB2RX 0 .. 7 */
+ 0, 0, 12, 0, 1, 0, 2, 0,
+ /* McB3TX McB3RX SLIMT0 SLIMT1 SLIMT2 SLIMT3 SLIMT4 SLIMT5 8 .. 15 */
+ 3, 0, 4, 5, 6, 7, 8, 9,
+ /* SLIMT6 SLIMT7 SLIMR0 SLIMR1 SLIMR2 SLIMR3 SLIMR4 SLIMR5 16 .. 23 */
+ 10, 11, 0, 0, 0, 0, 0, 0,
+ /* SLIMR6 SLIMR7 McASP1X ----- ----- McASP1R ----- ----- 24 .. 31 */
+ 0, 0, 14, 0, 0, 0, 0, 0,
+ /* CBPrT0 CBPrT1 CBPrT2 CBPrT3 CBPrT4 CBPrT5 CBPrT6 CBPrT7 32 .. 39 */
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ /* CBP_T0 CBP_T1 CBP_T2 CBP_T3 CBP_T4 CBP_T5 CBP_T6 CBP_T7 40 .. 47 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* CBP_T8 CBP_T9 CBP_T10 CBP_T11 CBP_T12 CBP_T13 CBP_T14
+ CBP_T15 48 .. 63 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+const u32 abe_atc_srcid[ABE_ATC_DESC_SIZE >> 3] = {
+ /* DMA_0 DMIC PDM_DL PDM_UL McB1TX McB1RX McB2TX McB2RX 0 .. 7 */
+ 0, 12, 0, 13, 0, 1, 0, 2,
+ /* McB3TX McB3RX SLIMT0 SLIMT1 SLIMT2 SLIMT3 SLIMT4 SLIMT5 8 .. 15 */
+ 0, 3, 0, 0, 0, 0, 0, 0,
+ /* SLIMT6 SLIMT7 SLIMR0 SLIMR1 SLIMR2 SLIMR3 SLIMR4 SLIMR5 16 .. 23 */
+ 0, 0, 4, 5, 6, 7, 8, 9,
+ /* SLIMR6 SLIMR7 McASP1X ----- ----- McASP1R ----- ----- 24 .. 31 */
+ 10, 11, 0, 0, 0, 14, 0, 0,
+ /* CBPrT0 CBPrT1 CBPrT2 CBPrT3 CBPrT4 CBPrT5 CBPrT6 CBPrT7 32 .. 39 */
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ /* CBP_T0 CBP_T1 CBP_T2 CBP_T3 CBP_T4 CBP_T5 CBP_T6 CBP_T7 40 .. 47 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* CBP_T8 CBP_T9 CBP_T10 CBP_T11 CBP_T12 CBP_T13 CBP_T14
+ CBP_T15 48 .. 63 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+/*
+ * preset default routing configurations
+ * This is given as implementation EXAMPLES
+ * the programmer uses "abe_set_router_configuration" with its own tables
+ */
+const abe_router_t abe_router_ul_table_preset[NBROUTE_CONFIG][NBROUTE_UL] = {
+ /* VOICE UPLINK WITH PHOENIX MICROPHONES - UPROUTE_CONFIG_AMIC */
+ {
+ /* 0 .. 9 = MM_UL */
+ DMIC1_L_labelID, DMIC1_R_labelID, DMIC2_L_labelID, DMIC2_R_labelID,
+ MM_EXT_IN_L_labelID, MM_EXT_IN_R_labelID, AMIC_L_labelID,
+ AMIC_L_labelID,
+ ZERO_labelID, ZERO_labelID,
+ /* 10 .. 11 = MM_UL2 */
+ AMIC_L_labelID, AMIC_L_labelID,
+ /* 12 .. 13 = VX_UL */
+ AMIC_L_labelID, AMIC_R_labelID,
+ /* 14 .. 15 = RESERVED */
+ ZERO_labelID, ZERO_labelID,
+ },
+ /* VOICE UPLINK WITH THE FIRST DMIC PAIR - UPROUTE_CONFIG_DMIC1 */
+ {
+ /* 0 .. 9 = MM_UL */
+ DMIC2_L_labelID, DMIC2_R_labelID, DMIC3_L_labelID, DMIC3_R_labelID,
+ DMIC1_L_labelID, DMIC1_R_labelID, ZERO_labelID, ZERO_labelID,
+ ZERO_labelID, ZERO_labelID,
+ /* 10 .. 11 = MM_UL2 */
+ DMIC1_L_labelID, DMIC1_R_labelID,
+ /* 12 .. 13 = VX_UL */
+ DMIC1_L_labelID, DMIC1_R_labelID,
+ /* 14 .. 15 = RESERVED */
+ ZERO_labelID, ZERO_labelID,
+ },
+ /* VOICE UPLINK WITH THE SECOND DMIC PAIR - UPROUTE_CONFIG_DMIC2 */
+ {
+ /* 0 .. 9 = MM_UL */
+ DMIC3_L_labelID, DMIC3_R_labelID, DMIC1_L_labelID, DMIC1_R_labelID,
+ DMIC2_L_labelID, DMIC2_R_labelID, ZERO_labelID, ZERO_labelID,
+ ZERO_labelID, ZERO_labelID,
+ /* 10 .. 11 = MM_UL2 */
+ DMIC2_L_labelID, DMIC2_R_labelID,
+ /* 12 .. 13 = VX_UL */
+ DMIC2_L_labelID, DMIC2_R_labelID,
+ /* 14 .. 15 = RESERVED */
+ ZERO_labelID, ZERO_labelID,
+ },
+ /* VOICE UPLINK WITH THE LAST DMIC PAIR - UPROUTE_CONFIG_DMIC3 */
+ {
+ /* 0 .. 9 = MM_UL */
+ AMIC_L_labelID, AMIC_R_labelID, DMIC2_L_labelID, DMIC2_R_labelID,
+ DMIC3_L_labelID, DMIC3_R_labelID, ZERO_labelID, ZERO_labelID,
+ ZERO_labelID, ZERO_labelID,
+ /* 10 .. 11 = MM_UL2 */
+ DMIC3_L_labelID, DMIC3_R_labelID,
+ /* 12 .. 13 = VX_UL */
+ DMIC3_L_labelID, DMIC3_R_labelID,
+ /* 14 .. 15 = RESERVED */
+ ZERO_labelID, ZERO_labelID,
+ },
+ /* VOICE UPLINK WITH THE BT - UPROUTE_CONFIG_BT */
+ {
+ /* 0 .. 9 = MM_UL */
+ BT_UL_L_labelID, BT_UL_R_labelID, DMIC2_L_labelID, DMIC2_R_labelID,
+ DMIC3_L_labelID, DMIC3_R_labelID, DMIC1_L_labelID, DMIC1_R_labelID,
+ ZERO_labelID, ZERO_labelID,
+ /* 10 .. 11 = MM_UL2 */
+ AMIC_L_labelID, AMIC_R_labelID,
+ /* 12 .. 13 = VX_UL */
+ BT_UL_L_labelID, BT_UL_R_labelID,
+ /* 14 .. 15 = RESERVED */
+ ZERO_labelID, ZERO_labelID,
+ },
+ /* VOICE UPLINK WITH THE BT - UPROUTE_ECHO_MMUL2 */
+ {
+ /* 0 .. 9 = MM_UL */
+ MM_EXT_IN_L_labelID, MM_EXT_IN_R_labelID, BT_UL_L_labelID,
+ BT_UL_R_labelID, AMIC_L_labelID, AMIC_R_labelID,
+ ZERO_labelID, ZERO_labelID, ZERO_labelID, ZERO_labelID,
+ /* 10 .. 11 = MM_UL2 */
+ EchoRef_L_labelID, EchoRef_R_labelID,
+ /* 12 .. 13 = VX_UL */
+ AMIC_L_labelID, AMIC_L_labelID,
+ /* 14 .. 15 = RESERVED */
+ ZERO_labelID, ZERO_labelID,
+ },
+};
+/* all default routing configurations */
+abe_router_t abe_router_ul_table[NBROUTE_CONFIG_MAX][NBROUTE_UL];
+/*
+ * ABE SUBROUTINES AND SEQUENCES
+ */
+/*
+const abe_seq_t abe_seq_array [MAXNBSEQUENCE] [MAXSEQUENCESTEPS] =
+ {{0, 0, 0, 0}, {-1, 0, 0, 0} },
+ {{0, 0, 0, 0}, {-1, 0, 0, 0} },
+const seq_t setup_hw_sequence2 [ ] = { 0, C_AE_FUNC1, 0, 0, 0, 0,
+ -1, C_CALLBACK1, 0, 0, 0, 0 };
+const abe_subroutine2 abe_sub_array [MAXNBSUBROUTINE] =
+ abe_init_atc, 0, 0,
+ abe_init_atc, 0, 0,
+ typedef double (*PtrFun) (double);
+PtrFun pFun;
+pFun = sin;
+ y = (* pFun) (x);
+*//* mask, { time id param tag1} */
+const abe_sequence_t seq_null = {
+ NOMASK, {CL_M1, 0, {0, 0, 0, 0}, 0}, {CL_M1, 0, {0, 0, 0, 0}, 0}
+};
+/* table of new subroutines called in the sequence */
+abe_subroutine2 abe_all_subsubroutine[MAXNBSUBROUTINE];
+/* number of parameters per calls */
+u32 abe_all_subsubroutine_nparam[MAXNBSUBROUTINE];
+/* index of the subroutine */
+u32 abe_subroutine_id[MAXNBSUBROUTINE];
+/* paramters of the subroutine (if any) */
+u32 *abe_all_subroutine_params[MAXNBSUBROUTINE];
+u32 abe_subroutine_write_pointer;
+/* table of all sequences */
+abe_sequence_t abe_all_sequence[MAXNBSEQUENCE];
+u32 abe_sequence_write_pointer;
+/* current number of pending sequences (avoids to look in the table) */
+u32 abe_nb_pending_sequences;
+/* pending sequences due to ressource collision */
+u32 abe_pending_sequences[MAXNBSEQUENCE];
+/* mask of unsharable ressources among other sequences */
+u32 abe_global_sequence_mask;
+/* table of active sequences */
+abe_seq_t abe_active_sequence[MAXACTIVESEQUENCE][MAXSEQUENCESTEPS];
+/* index of the plugged subroutine doing ping-pong cache-flush DMEM accesses */
+u32 abe_irq_pingpong_player_id;
+EXPORT_SYMBOL_GPL(abe_irq_pingpong_player_id);
+
+/* index of the plugged subroutine doing acoustics protection adaptation */
+u32 abe_irq_aps_adaptation_id;
+/* base addresses of the ping pong buffers in bytes addresses */
+u32 abe_base_address_pingpong[MAX_PINGPONG_BUFFERS];
+/* size of each ping/pong buffers */
+u32 abe_size_pingpong;
+/* number of ping/pong buffer being used */
+u32 abe_nb_pingpong;
+/* current EVENT */
+u32 abe_current_event_id;
+/*
+ * ABE CONST AREA FOR PARAMETERS TRANSLATION
+ */
+const u32 abe_db2lin_table[sizeof_db2lin_table] = {
+ 0x00000000, /* SMEM coding of -120 dB */
+ 0x00000000, /* SMEM coding of -119 dB */
+ 0x00000000, /* SMEM coding of -118 dB */
+ 0x00000000, /* SMEM coding of -117 dB */
+ 0x00000000, /* SMEM coding of -116 dB */
+ 0x00000000, /* SMEM coding of -115 dB */
+ 0x00000000, /* SMEM coding of -114 dB */
+ 0x00000000, /* SMEM coding of -113 dB */
+ 0x00000000, /* SMEM coding of -112 dB */
+ 0x00000000, /* SMEM coding of -111 dB */
+ 0x00000000, /* SMEM coding of -110 dB */
+ 0x00000000, /* SMEM coding of -109 dB */
+ 0x00000001, /* SMEM coding of -108 dB */
+ 0x00000001, /* SMEM coding of -107 dB */
+ 0x00000001, /* SMEM coding of -106 dB */
+ 0x00000001, /* SMEM coding of -105 dB */
+ 0x00000001, /* SMEM coding of -104 dB */
+ 0x00000001, /* SMEM coding of -103 dB */
+ 0x00000002, /* SMEM coding of -102 dB */
+ 0x00000002, /* SMEM coding of -101 dB */
+ 0x00000002, /* SMEM coding of -100 dB */
+ 0x00000002, /* SMEM coding of -99 dB */
+ 0x00000003, /* SMEM coding of -98 dB */
+ 0x00000003, /* SMEM coding of -97 dB */
+ 0x00000004, /* SMEM coding of -96 dB */
+ 0x00000004, /* SMEM coding of -95 dB */
+ 0x00000005, /* SMEM coding of -94 dB */
+ 0x00000005, /* SMEM coding of -93 dB */
+ 0x00000006, /* SMEM coding of -92 dB */
+ 0x00000007, /* SMEM coding of -91 dB */
+ 0x00000008, /* SMEM coding of -90 dB */
+ 0x00000009, /* SMEM coding of -89 dB */
+ 0x0000000A, /* SMEM coding of -88 dB */
+ 0x0000000B, /* SMEM coding of -87 dB */
+ 0x0000000D, /* SMEM coding of -86 dB */
+ 0x0000000E, /* SMEM coding of -85 dB */
+ 0x00000010, /* SMEM coding of -84 dB */
+ 0x00000012, /* SMEM coding of -83 dB */
+ 0x00000014, /* SMEM coding of -82 dB */
+ 0x00000017, /* SMEM coding of -81 dB */
+ 0x0000001A, /* SMEM coding of -80 dB */
+ 0x0000001D, /* SMEM coding of -79 dB */
+ 0x00000021, /* SMEM coding of -78 dB */
+ 0x00000025, /* SMEM coding of -77 dB */
+ 0x00000029, /* SMEM coding of -76 dB */
+ 0x0000002E, /* SMEM coding of -75 dB */
+ 0x00000034, /* SMEM coding of -74 dB */
+ 0x0000003A, /* SMEM coding of -73 dB */
+ 0x00000041, /* SMEM coding of -72 dB */
+ 0x00000049, /* SMEM coding of -71 dB */
+ 0x00000052, /* SMEM coding of -70 dB */
+ 0x0000005D, /* SMEM coding of -69 dB */
+ 0x00000068, /* SMEM coding of -68 dB */
+ 0x00000075, /* SMEM coding of -67 dB */
+ 0x00000083, /* SMEM coding of -66 dB */
+ 0x00000093, /* SMEM coding of -65 dB */
+ 0x000000A5, /* SMEM coding of -64 dB */
+ 0x000000B9, /* SMEM coding of -63 dB */
+ 0x000000D0, /* SMEM coding of -62 dB */
+ 0x000000E9, /* SMEM coding of -61 dB */
+ 0x00000106, /* SMEM coding of -60 dB */
+ 0x00000126, /* SMEM coding of -59 dB */
+ 0x0000014A, /* SMEM coding of -58 dB */
+ 0x00000172, /* SMEM coding of -57 dB */
+ 0x0000019F, /* SMEM coding of -56 dB */
+ 0x000001D2, /* SMEM coding of -55 dB */
+ 0x0000020B, /* SMEM coding of -54 dB */
+ 0x0000024A, /* SMEM coding of -53 dB */
+ 0x00000292, /* SMEM coding of -52 dB */
+ 0x000002E2, /* SMEM coding of -51 dB */
+ 0x0000033C, /* SMEM coding of -50 dB */
+ 0x000003A2, /* SMEM coding of -49 dB */
+ 0x00000413, /* SMEM coding of -48 dB */
+ 0x00000492, /* SMEM coding of -47 dB */
+ 0x00000521, /* SMEM coding of -46 dB */
+ 0x000005C2, /* SMEM coding of -45 dB */
+ 0x00000676, /* SMEM coding of -44 dB */
+ 0x0000073F, /* SMEM coding of -43 dB */
+ 0x00000822, /* SMEM coding of -42 dB */
+ 0x00000920, /* SMEM coding of -41 dB */
+ 0x00000A3D, /* SMEM coding of -40 dB */
+ 0x00000B7D, /* SMEM coding of -39 dB */
+ 0x00000CE4, /* SMEM coding of -38 dB */
+ 0x00000E76, /* SMEM coding of -37 dB */
+ 0x0000103A, /* SMEM coding of -36 dB */
+ 0x00001235, /* SMEM coding of -35 dB */
+ 0x0000146E, /* SMEM coding of -34 dB */
+ 0x000016EC, /* SMEM coding of -33 dB */
+ 0x000019B8, /* SMEM coding of -32 dB */
+ 0x00001CDC, /* SMEM coding of -31 dB */
+ 0x00002061, /* SMEM coding of -30 dB */
+ 0x00002455, /* SMEM coding of -29 dB */
+ 0x000028C4, /* SMEM coding of -28 dB */
+ 0x00002DBD, /* SMEM coding of -27 dB */
+ 0x00003352, /* SMEM coding of -26 dB */
+ 0x00003995, /* SMEM coding of -25 dB */
+ 0x0000409C, /* SMEM coding of -24 dB */
+ 0x0000487E, /* SMEM coding of -23 dB */
+ 0x00005156, /* SMEM coding of -22 dB */
+ 0x00005B43, /* SMEM coding of -21 dB */
+ 0x00006666, /* SMEM coding of -20 dB */
+ 0x000072E5, /* SMEM coding of -19 dB */
+ 0x000080E9, /* SMEM coding of -18 dB */
+ 0x000090A4, /* SMEM coding of -17 dB */
+ 0x0000A24B, /* SMEM coding of -16 dB */
+ 0x0000B618, /* SMEM coding of -15 dB */
+ 0x0000CC50, /* SMEM coding of -14 dB */
+ 0x0000E53E, /* SMEM coding of -13 dB */
+ 0x00010137, /* SMEM coding of -12 dB */
+ 0x0001209A, /* SMEM coding of -11 dB */
+ 0x000143D1, /* SMEM coding of -10 dB */
+ 0x00016B54, /* SMEM coding of -9 dB */
+ 0x000197A9, /* SMEM coding of -8 dB */
+ 0x0001C967, /* SMEM coding of -7 dB */
+ 0x00020137, /* SMEM coding of -6 dB */
+ 0x00023FD6, /* SMEM coding of -5 dB */
+ 0x00028619, /* SMEM coding of -4 dB */
+ 0x0002D4EF, /* SMEM coding of -3 dB */
+ 0x00032D64, /* SMEM coding of -2 dB */
+ 0x000390A4, /* SMEM coding of -1 dB */
+ 0x00040000, /* SMEM coding of 0 dB */
+ 0x00047CF2, /* SMEM coding of 1 dB */
+ 0x00050923, /* SMEM coding of 2 dB */
+ 0x0005A670, /* SMEM coding of 3 dB */
+ 0x000656EE, /* SMEM coding of 4 dB */
+ 0x00071CF5, /* SMEM coding of 5 dB */
+ 0x0007FB26, /* SMEM coding of 6 dB */
+ 0x0008F473, /* SMEM coding of 7 dB */
+ 0x000A0C2B, /* SMEM coding of 8 dB */
+ 0x000B4606, /* SMEM coding of 9 dB */
+ 0x000CA62C, /* SMEM coding of 10 dB */
+ 0x000E314A, /* SMEM coding of 11 dB */
+ 0x000FEC9E, /* SMEM coding of 12 dB */
+ 0x0011DE0A, /* SMEM coding of 13 dB */
+ 0x00140C28, /* SMEM coding of 14 dB */
+ 0x00167E60, /* SMEM coding of 15 dB */
+ 0x00193D00, /* SMEM coding of 16 dB */
+ 0x001C515D, /* SMEM coding of 17 dB */
+ 0x001FC5EB, /* SMEM coding of 18 dB */
+ 0x0023A668, /* SMEM coding of 19 dB */
+ 0x00280000, /* SMEM coding of 20 dB */
+ 0x002CE178, /* SMEM coding of 21 dB */
+ 0x00325B65, /* SMEM coding of 22 dB */
+ 0x00388062, /* SMEM coding of 23 dB */
+ 0x003F654E, /* SMEM coding of 24 dB */
+ 0x00472194, /* SMEM coding of 25 dB */
+ 0x004FCF7C, /* SMEM coding of 26 dB */
+ 0x00598C81, /* SMEM coding of 27 dB */
+ 0x006479B7, /* SMEM coding of 28 dB */
+ 0x0070BC3D, /* SMEM coding of 29 dB */
+ 0x007E7DB9, /* SMEM coding of 30 dB */
+};
+const u32 abe_1_alpha_iir[64] = {
+ 0x040002, 0x040002, 0x040002, 0x040002, /* 0 */
+ 0x50E955, 0x48CA65, 0x40E321, 0x72BE78, /* 1 [ms] */
+ 0x64BA68, 0x57DF14, 0x4C3D60, 0x41D690, /* 2 */
+ 0x38A084, 0x308974, 0x297B00, 0x235C7C, /* 4 */
+ 0x1E14B0, 0x198AF0, 0x15A800, 0x125660, /* 8 */
+ 0x0F82A0, 0x0D1B5C, 0x0B113C, 0x0956CC, /* 16 */
+ 0x07E054, 0x06A3B8, 0x059844, 0x04B680, /* 32 */
+ 0x03F80C, 0x035774, 0x02D018, 0x025E0C, /* 64 */
+ 0x7F8057, 0x6B482F, 0x5A4297, 0x4BEECB, /* 128 */
+ 0x3FE00B, 0x35BAA7, 0x2D3143, 0x2602AF, /* 256 */
+ 0x1FF803, 0x1AE2FB, 0x169C9F, 0x13042B, /* 512 */
+ 0x0FFE03, 0x0D72E7, 0x0B4F4F, 0x0982CB, /* 1.024 [s] */
+ 0x07FF83, 0x06B9CF, 0x05A7E7, 0x04C193, /* 2.048 */
+ 0x03FFE3, 0x035CFF, 0x02D403, 0x0260D7, /* 4.096 */
+ 0x01FFFB, 0x01AE87, 0x016A07, 0x01306F, /* 8.192 */
+ 0x00FFFF, 0x00D743, 0x00B503, 0x009837,
+};
+const u32 abe_alpha_iir[64] = {
+ 0x000000, 0x000000, 0x000000, 0x000000, /* 0 */
+ 0x5E2D58, 0x6E6B3C, 0x7E39C0, 0x46A0C5, /* 1 [ms] */
+ 0x4DA2CD, 0x541079, 0x59E151, 0x5F14B9, /* 2 */
+ 0x63AFC1, 0x67BB45, 0x6B4281, 0x6E51C1, /* 4 */
+ 0x70F5A9, 0x733A89, 0x752C01, 0x76D4D1, /* 8 */
+ 0x783EB1, 0x797251, 0x7A7761, 0x7B549D, /* 16 */
+ 0x7C0FD5, 0x7CAE25, 0x7D33DD, 0x7DA4C1, /* 32 */
+ 0x7E03FD, 0x7E5449, 0x7E97F5, 0x7ED0F9, /* 64 */
+ 0x7F0101, 0x7F2971, 0x7F4B7D, 0x7F6825, /* 128 */
+ 0x7F8041, 0x7F948D, 0x7FA59D, 0x7FB3FD, /* 256 */
+ 0x7FC011, 0x7FCA3D, 0x7FD2C9, 0x7FD9F9, /* 512 */
+ 0x7FE005, 0x7FE51D, 0x7FE961, 0x7FECFD, /* 1.024 [s] */
+ 0x7FF001, 0x7FF28D, 0x7FF4B1, 0x7FF67D, /* 2.048 */
+ 0x7FF801, 0x7FF949, 0x7FFA59, 0x7FFB41, /* 4.096 */
+ 0x7FFC01, 0x7FFCA5, 0x7FFD2D, 0x7FFDA1, /* 8.192 */
+ 0x7FFE01, 0x7FFE51, 0x7FFE95, 0x7FFED1,
+};
+/*
+ * ABE_DEBUG DATA
+ */
+/*
+ * IRQ and trace pointer in DMEM:
+ * FW updates a write pointer at "MCU_IRQ_FIFO_ptr_labelID", the read pointer is in HAL
+ */
+u32 abe_irq_dbg_read_ptr;
+/*
+ * General circular buffer used to trace APIs calls and AE activity.
+ */
+u32 abe_dbg_activity_log[D_DEBUG_HAL_TASK_sizeof];
+u32 abe_dbg_activity_log_write_pointer;
+u32 abe_dbg_mask;
+/*
+ * Global variable holding parameter errors
+ */
+u32 abe_dbg_param;
+/*
+ * Output of messages selector
+ */
+u32 abe_dbg_output;
+/*
+ * last parameters
+ */
+#define SIZE_PARAM 10
+u32 param1[SIZE_PARAM];
+u32 param2[SIZE_PARAM];
+u32 param3[SIZE_PARAM];
+u32 param4[SIZE_PARAM];
+u32 param5[SIZE_PARAM];
+/*
+ * MAIN PORT SELECTION
+ */
+const u32 abe_port_priority[LAST_PORT_ID - 1] = {
+ PDM_DL_PORT,
+ PDM_UL_PORT,
+ MM_EXT_OUT_PORT,
+ MM_EXT_IN_PORT,
+ TDM_DL_PORT,
+ TDM_UL_PORT,
+ DMIC_PORT,
+ MM_UL_PORT,
+ MM_UL2_PORT,
+ MM_DL_PORT,
+ TONES_DL_PORT,
+ VX_UL_PORT,
+ VX_DL_PORT,
+ BT_VX_DL_PORT,
+ BT_VX_UL_PORT,
+ VIB_DL_PORT,
+};
+/*
+ * ABE CONST AREA FOR DMIC DECIMATION FILTERS
+ */
+/* const s32 abe_dmic_40 [C_98_48_LP_Coefs_sizeof] = {
+ -4119413, -192384, -341428, -348088, -151380, 151380, 348088,
+ 341428, 192384, 4119415, 1938156, -6935719, 775202, -1801934,
+ 2997698, -3692214, 3406822, -2280190, 1042982 };
+const s32 abe_dmic_32 [C_98_48_LP_Coefs_sizeof] = {
+ -4119413, -192384, -341428, -348088, -151380, 151380, 348088,
+ 341428, 192384, 4119415, 1938156, -6935719, 775202, -1801934,
+ 2997698, -3692214, 3406822, -2280190, 1042982 };
+const s32 abe_dmic_25 [C_98_48_LP_Coefs_sizeof] = {
+ -4119413, -192384, -341428, -348088, -151380, 151380, 348088,
+ 341428, 192384, 4119415, 1938156, -6935719, 775202, -1801934,
+ 2997698, -3692214, 3406822, -2280190, 1042982 };
+const s32 abe_dmic_16 [C_98_48_LP_Coefs_sizeof] = {
+ -4119413, -192384, -341428, -348088, -151380, 151380, 348088,
+ 341428, 192384, 4119415, 1938156, -6935719, 775202, -1801934,
+ 2997698, -3692214, 3406822, -2280190, 1042982 };
+*/
+#endif/* abe_dat_c */
diff --git a/sound/soc/omap/abe/abe_dbg.c b/sound/soc/omap/abe/abe_dbg.c
new file mode 100644
index 00000000000..1c4435d66f0
--- /dev/null
+++ b/sound/soc/omap/abe/abe_dbg.c
@@ -0,0 +1,197 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include "abe_main.h"
+/**
+ * abe_dbg_log - Log ABE trace inside circular buffer
+ * @x: data to be logged
+ * @y: data to be logged
+ * @z: data to be logged
+ * @t: data to be logged
+ * Parameter :
+ *
+ * abe_dbg_activity_log : global circular buffer holding the data
+ * abe_dbg_activity_log_write_pointer : circular write pointer
+ *
+ * saves data in the log file
+ */
+void abe_dbg_log(u32 x, u32 y, u32 z, u32 t)
+{
+ u32 time_stamp, data;
+ if (abe_dbg_activity_log_write_pointer >= (D_DEBUG_HAL_TASK_sizeof - 2))
+ abe_dbg_activity_log_write_pointer = 0;
+ /* copy in DMEM trace buffer and CortexA9 local buffer and a small 7
+ words circular buffer of the DMA trace ending with 0x55555555
+ (tag for last word) */
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM, D_loopCounter_ADDR,
+ (u32 *) &time_stamp, sizeof(time_stamp));
+ abe_dbg_activity_log[abe_dbg_activity_log_write_pointer] = time_stamp;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, D_DEBUG_HAL_TASK_ADDR +
+ (abe_dbg_activity_log_write_pointer << 2),
+ (u32 *) &time_stamp, sizeof(time_stamp));
+ abe_dbg_activity_log_write_pointer++;
+ data = ((x & MAX_UINT8) << 24) | ((y & MAX_UINT8) << 16) |
+ ((z & MAX_UINT8) << 8)
+ | (t & MAX_UINT8);
+ abe_dbg_activity_log[abe_dbg_activity_log_write_pointer] = data;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, D_DEBUG_HAL_TASK_ADDR +
+ (abe_dbg_activity_log_write_pointer << 2),
+ (u32 *) &data, sizeof(data));
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ D_DEBUG_FIFO_HAL_ADDR +
+ ((abe_dbg_activity_log_write_pointer << 2) &
+ (D_DEBUG_FIFO_HAL_sizeof - 1)), (u32 *) &data,
+ sizeof(data));
+ data = ABE_DBG_MAGIC_NUMBER;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, D_DEBUG_FIFO_HAL_ADDR +
+ (((abe_dbg_activity_log_write_pointer +
+ 1) << 2) &(D_DEBUG_FIFO_HAL_sizeof - 1)),
+ (u32 *) &data, sizeof(data));
+ abe_dbg_activity_log_write_pointer++;
+ if (abe_dbg_activity_log_write_pointer >= D_DEBUG_HAL_TASK_sizeof)
+ abe_dbg_activity_log_write_pointer = 0;
+}
+/**
+ * abe_debug_output_pins
+ * @x: d
+ *
+ * set the debug output pins of AESS
+ */
+void abe_debug_output_pins(u32 x)
+{
+}
+/**
+ * abe_dbg_error_log - Log ABE error
+ * @x: error to log
+ *
+ * log the error codes
+ */
+void abe_dbg_error_log(u32 x)
+{
+ abe_dbg_log(x, MAX_UINT8, MAX_UINT8, MAX_UINT8);
+}
+/**
+ * abe_debugger
+ * @x: error to log
+ *
+ * log error for debugger
+ */
+void abe_debugger(u32 x)
+{
+}
+/**
+ * abe_load_embeddded_patterns
+ *
+ * load test patterns
+ *
+ * S = power (2, 31) * 0.25;
+ * N = 4; B = 2; F=[1/N 1/N]; gen_and_save('dbg_8k_2.txt', B, F, N, S);
+ * N = 8; B = 2; F=[1/N 2/N]; gen_and_save('dbg_16k_2.txt', B, F, N, S);
+ * N = 12; B = 2; F=[1/N 2/N]; gen_and_save('dbg_48k_2.txt', B, F, N, S);
+ * N = 60; B = 2; F=[4/N 8/N]; gen_and_save('dbg_amic.txt', B, F, N, S);
+ * N = 10; B = 6; F=[1/N 2/N 3/N 1/N 2/N 3/N]; gen_and_save('dbg_dmic.txt', B, F, N, S);
+*/
+void abe_load_embeddded_patterns(void)
+{
+ u32 i;
+#define patterns_96k_len 48
+ const long patterns_96k[patterns_96k_len] = {
+ 1620480, 1452800,
+ 1452800, 838656,
+ 1186304, 0,
+ 838656, -838912,
+ 434176, -1453056,
+ 0, -1677824,
+ -434432, -1453056,
+ -838912, -838912,
+ -1186560, -256,
+ -1453056, 838656,
+ -1620736, 1452800,
+ -1677824, 1677568,
+ -1620736, 1452800,
+ -1453056, 838656,
+ -1186560, 0,
+ -838912, -838912,
+ -434432, -1453056,
+ -256, -1677824,
+ 434176, -1453056,
+ 838656, -838912,
+ 1186304, -256,
+ 1452800, 838656,
+ 1620480, 1452800,
+ 1677568, 1677568,
+ };
+#define patterns_48k_len 24
+ const long patterns_48k[patterns_48k_len] = {
+ 1452800, 838656,
+ 838656, -838912,
+ 0, -1677824,
+ -838912, -838912,
+ -1453056, 838656,
+ -1677824, 1677568,
+ -1453056, 838656,
+ -838912, -838912,
+ -256, -1677824,
+ 838656, -838912,
+ 1452800, 838656,
+ 1677568, 1677568,
+ };
+#define patterns_24k_len 12
+ const long patterns_24k[patterns_24k_len] = {
+ 838656, -838912,
+ -838912, -838912,
+ -1677824, 1677568,
+ -838912, -838912,
+ 838656, -838912,
+ 1677568, 1677568,
+ };
+#define patterns_16k_len 8
+ const long patterns_16k[patterns_16k_len] = {
+ 0, 0,
+ -1677824, -1677824,
+ -256, -256,
+ 1677568, 1677568,
+ };
+#define patterns_8k_len 4
+ const long patterns_8k[patterns_8k_len] = {
+ 1677568, -1677824,
+ 1677568, 1677568,
+ };
+ for (i = 0; i < patterns_8k_len; i++)
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_SMEM,
+ (S_DBG_8K_PATTERN_ADDR * 8) + (i * 4),
+ (u32 *) (&(patterns_8k[i])), 4);
+ for (i = 0; i < patterns_16k_len; i++)
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_SMEM,
+ (S_DBG_16K_PATTERN_ADDR * 8) + (i * 4),
+ (u32 *) (&(patterns_16k[i])), 4);
+ for (i = 0; i < patterns_24k_len; i++)
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_SMEM,
+ (S_DBG_24K_PATTERN_ADDR * 8) + (i * 4),
+ (u32 *) (&(patterns_24k[i])), 4);
+ for (i = 0; i < patterns_48k_len; i++)
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_SMEM,
+ (S_DBG_48K_PATTERN_ADDR * 8) + (i * 4),
+ (u32 *) (&(patterns_48k[i])), 4);
+ for (i = 0; i < patterns_96k_len; i++)
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_SMEM,
+ (S_DBG_96K_PATTERN_ADDR * 8) + (i * 4),
+ (u32 *) (&(patterns_96k[i])), 4);
+}
diff --git a/sound/soc/omap/abe/abe_dbg.h b/sound/soc/omap/abe/abe_dbg.h
new file mode 100644
index 00000000000..038f29c8a2f
--- /dev/null
+++ b/sound/soc/omap/abe/abe_dbg.h
@@ -0,0 +1,149 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include "abe_main.h"
+/*
+ * DEFINE
+ */
+#define NO_OUTPUT 0
+#define TERMINAL_OUTPUT 1
+#define LINE_OUTPUT 2
+#define DEBUG_TRACE_OUTPUT 3
+/*
+ * Debug trace format
+ * TIME 2 bytes from ABE : 4kHz period of the FW scheduler
+ * SUBID 1 byte : HAL API index
+ * From 0 to 16 bytes : parameters of the subroutine
+ * on every 32 dumps a tag is pushed on the debug trace : 0x55555555
+ */
+#define dbg_bitfield_offset 8
+#define dbg_api_calls 0
+#define dbg_mapi (1L << (dbg_api_calls + dbg_bitfield_offset))
+#define dbg_external_data_access 1
+#define dbg_mdata (1L << (dbg_external_data_access + dbg_bitfield_offset))
+#define dbg_err_codes 2
+#define dbg_merr (1L << (dbg_api_calls + dbg_bitfield_offset))
+#define ABE_DBG_MAGIC_NUMBER 0x55555555
+/*
+ * IDs used for traces
+ */
+#define id_reset_hal (1 + dbg_mapi)
+#define id_load_fw (2 + dbg_mapi)
+#define id_default_configuration (3 + dbg_mapi)
+#define id_irq_processing (4 + dbg_mapi)
+#define id_event_generator_switch (5 + dbg_mapi)
+#define id_read_hardware_configuration (6 + dbg_mapi)
+#define id_read_lowest_opp (7 + dbg_mapi)
+#define id_write_gain (8 + dbg_mapi)
+#define id_set_asrc_drift_control (9 + dbg_mapi)
+#define id_plug_subroutine (10 + dbg_mapi)
+#define id_unplug_subroutine (11 + dbg_mapi)
+#define id_plug_sequence (12 + dbg_mapi)
+#define id_launch_sequence (13 + dbg_mapi)
+#define id_launch_sequence_param (14 + dbg_mapi)
+#define id_connect_irq_ping_pong_port (15 + dbg_mapi)
+#define id_read_analog_gain_dl (16 + dbg_mapi)
+#define id_read_analog_gain_ul (17 + dbg_mapi)
+#define id_enable_dyn_ul_gain (18 + dbg_mapi)
+#define id_disable_dyn_ul_gain (19 + dbg_mapi)
+#define id_enable_dyn_extension (20 + dbg_mapi)
+#define id_disable_dyn_extension (21 + dbg_mapi)
+#define id_notify_analog_gain_changed (22 + dbg_mapi)
+#define id_reset_port (23 + dbg_mapi)
+#define id_read_remaining_data (24 + dbg_mapi)
+#define id_disable_data_transfer (25 + dbg_mapi)
+#define id_enable_data_transfer (26 + dbg_mapi)
+#define id_read_global_counter (27 + dbg_mapi)
+#define id_set_dmic_filter (28 + dbg_mapi)
+#define id_set_opp_processing (29 + dbg_mapi)
+#define id_set_ping_pong_buffer (30 + dbg_mapi)
+#define id_read_port_address (31 + dbg_mapi)
+#define id_load_fw_param (32 + dbg_mapi)
+#define id_write_headset_offset (33 + dbg_mapi)
+#define id_read_gain_ranges (34 + dbg_mapi)
+#define id_write_equalizer (35 + dbg_mapi)
+#define id_write_asrc (36 + dbg_mapi)
+#define id_write_aps (37 + dbg_mapi)
+#define id_write_mixer (38 + dbg_mapi)
+#define id_write_eanc (39 + dbg_mapi)
+#define id_write_router (40 + dbg_mapi)
+#define id_read_port_gain (41 + dbg_mapi)
+#define id_read_asrc (42 + dbg_mapi)
+#define id_read_aps (43 + dbg_mapi)
+#define id_read_aps_energy (44 + dbg_mapi)
+#define id_read_mixer (45 + dbg_mapi)
+#define id_read_eanc (46 + dbg_mapi)
+#define id_read_router (47 + dbg_mapi)
+#define id_read_debug_trace (48 + dbg_mapi)
+#define id_set_sequence_time_accuracy (49 + dbg_mapi)
+#define id_set_debug_pins (50 + dbg_mapi)
+#define id_select_main_port (51 + dbg_mapi)
+#define id_write_event_generator (52 + dbg_mapi)
+#define id_read_use_case_opp (53 + dbg_mapi)
+#define id_select_data_source (54 + dbg_mapi)
+#define id_read_next_ping_pong_buffer (55 + dbg_mapi)
+#define id_init_ping_pong_buffer (56 + dbg_mapi)
+#define id_connect_cbpr_dmareq_port (57 + dbg_mapi)
+#define id_connect_dmareq_port (58 + dbg_mapi)
+#define id_connect_dmareq_ping_pong_port (59 + dbg_mapi)
+#define id_connect_serial_port (60 + dbg_mapi)
+#define id_connect_slimbus_port (61 + dbg_mapi)
+#define id_read_gain (62 + dbg_mapi)
+#define id_set_router_configuration (63 + dbg_mapi)
+#define id_connect_debug_trace (64 + dbg_mapi)
+#define id_set_debug_trace (65 + dbg_mapi)
+#define id_remote_debugger_interface (66 + dbg_mapi)
+#define id_enable_test_pattern (67 + dbg_mapi)
+#define id_connect_tdm_port (68 + dbg_mapi)
+/*
+ * IDs used for error codes
+ */
+#define NOERR 0
+#define ABE_SET_MEMORY_CONFIG_ERR (1 + dbg_merr)
+#define ABE_BLOCK_COPY_ERR (2 + dbg_merr)
+#define ABE_SEQTOOLONG (3 + dbg_merr)
+#define ABE_BADSAMPFORMAT (4 + dbg_merr)
+#define ABE_SET_ATC_MEMORY_CONFIG_ERR (5 + dbg_merr)
+#define ABE_PROTOCOL_ERROR (6 + dbg_merr)
+#define ABE_PARAMETER_ERROR (7 + dbg_merr)
+/* port programmed while still running */
+#define ABE_PORT_REPROGRAMMING (8 + dbg_merr)
+#define ABE_READ_USE_CASE_OPP_ERR (9 + dbg_merr)
+#define ABE_PARAMETER_OVERFLOW (10 + dbg_merr)
+#define ABE_FW_FIFO_WRITE_PTR_ERR (11 + dbg_merr)
+/*
+ * IDs used for error codes
+ */
+/* error in the LIB.C file */
+#define ERR_LIB (1 << 1)
+/* error in the API.C file */
+#define ERR_API (1 << 2)
+/* error in the INI.C file */
+#define ERR_INI (1 << 3)
+/* error in the SEQ.C file */
+#define ERR_SEQ (1 << 4)
+/* error in the DBG.C file */
+#define ERR_DBG (1 << 5)
+/* error in the DBG.C file */
+#define ERR_EXT (1 << 6)
+/*
+ * MACROS
+ */
+#define _log(x, y, z, t) {if (x & abe_dbg_mask) abe_dbg_log(x, y, z, t); }
diff --git a/sound/soc/omap/abe/abe_def.h b/sound/soc/omap/abe/abe_def.h
new file mode 100644
index 00000000000..af2cbc689f9
--- /dev/null
+++ b/sound/soc/omap/abe/abe_def.h
@@ -0,0 +1,274 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#ifndef _ABE_DEF_H_
+#define _ABE_DEF_H_
+/*
+ * HARDWARE AND PERIPHERAL DEFINITIONS
+ */
+/* MM_DL */
+#define ABE_CBPR0_IDX 0
+/* VX_DL */
+#define ABE_CBPR1_IDX 1
+/* VX_UL */
+#define ABE_CBPR2_IDX 2
+/* MM_UL */
+#define ABE_CBPR3_IDX 3
+/* MM_UL2 */
+#define ABE_CBPR4_IDX 4
+/* TONES */
+#define ABE_CBPR5_IDX 5
+/* VIB */
+#define ABE_CBPR6_IDX 6
+/* DEBUG/CTL */
+#define ABE_CBPR7_IDX 7
+#define CIRCULAR_BUFFER_PERIPHERAL_R__0 (0x100 + ABE_CBPR0_IDX*4)
+#define CIRCULAR_BUFFER_PERIPHERAL_R__1 (0x100 + ABE_CBPR1_IDX*4)
+#define CIRCULAR_BUFFER_PERIPHERAL_R__2 (0x100 + ABE_CBPR2_IDX*4)
+#define CIRCULAR_BUFFER_PERIPHERAL_R__3 (0x100 + ABE_CBPR3_IDX*4)
+#define CIRCULAR_BUFFER_PERIPHERAL_R__4 (0x100 + ABE_CBPR4_IDX*4)
+#define CIRCULAR_BUFFER_PERIPHERAL_R__5 (0x100 + ABE_CBPR5_IDX*4)
+#define CIRCULAR_BUFFER_PERIPHERAL_R__6 (0x100 + ABE_CBPR6_IDX*4)
+#define CIRCULAR_BUFFER_PERIPHERAL_R__7 (0x100 + ABE_CBPR7_IDX*4)
+#define PING_PONG_WITH_MCU_IRQ 1
+#define PING_PONG_WITH_DSP_IRQ 2
+/* ID used for LIB memory copy subroutines */
+#define COPY_FROM_ABE_TO_HOST 1
+#define COPY_FROM_HOST_TO_ABE 2
+/*
+ * INTERNAL DEFINITIONS
+ */
+#define ABE_FIRMWARE_MAX_SIZE 26629
+/* 24 Q6.26 coefficients */
+#define NBEQ1 25
+/* 2x12 Q6.26 coefficients */
+#define NBEQ2 13
+/* TBD APS first set of parameters */
+#define NBAPS1 10
+/* TBD APS second set of parameters */
+#define NBAPS2 10
+/* Mixer used for sending tones to the uplink voice path */
+#define NBMIX_AUDIO_UL 2
+/* Main downlink mixer */
+#define NBMIX_DL1 4
+/* Handsfree downlink mixer */
+#define NBMIX_DL2 4
+/* Side-tone mixer */
+#define NBMIX_SDT 2
+/* Echo reference mixer */
+#define NBMIX_ECHO 2
+/* Voice record mixer */
+#define NBMIX_VXREC 4
+/* unsigned version of (-1) */
+#define CC_M1 0xFF
+#define CS_M1 0xFFFF
+#define CL_M1 0xFFFFFFFFL
+/*
+ Mixer ID Input port ID Comments
+ DL1_MIXER 0 MMDL path
+ 1 MMUL2 path
+ 2 VXDL path
+ 3 TONES path
+ SDT_MIXER 0 Uplink path
+ 1 Downlink path
+ ECHO_MIXER 0 DL1_MIXER path
+ 1 DL2_MIXER path
+ AUDUL_MIXER 0 TONES_DL path
+ 1 Uplink path
+ 2 MM_DL path
+ VXREC_MIXER 0 TONES_DL path
+ 1 VX_DL path
+ 2 MM_DL path
+ 3 VX_UL path
+*/
+#define MIX_VXUL_INPUT_MM_DL 0
+#define MIX_VXUL_INPUT_TONES 1
+#define MIX_VXUL_INPUT_VX_UL 2
+#define MIX_VXUL_INPUT_VX_DL 3
+#define MIX_DL1_INPUT_MM_DL 0
+#define MIX_DL1_INPUT_MM_UL2 1
+#define MIX_DL1_INPUT_VX_DL 2
+#define MIX_DL1_INPUT_TONES 3
+#define MIX_DL2_INPUT_MM_DL 0
+#define MIX_DL2_INPUT_MM_UL2 1
+#define MIX_DL2_INPUT_VX_DL 2
+#define MIX_DL2_INPUT_TONES 3
+#define MIX_SDT_INPUT_UP_MIXER 0
+#define MIX_SDT_INPUT_DL1_MIXER 1
+#define MIX_AUDUL_INPUT_MM_DL 0
+#define MIX_AUDUL_INPUT_TONES 1
+#define MIX_AUDUL_INPUT_UPLINK 2
+#define MIX_AUDUL_INPUT_VX_DL 3
+#define MIX_VXREC_INPUT_MM_DL 0
+#define MIX_VXREC_INPUT_TONES 1
+#define MIX_VXREC_INPUT_VX_UL 2
+#define MIX_VXREC_INPUT_VX_DL 3
+#define MIX_ECHO_DL1 0
+#define MIX_ECHO_DL2 1
+/* nb of samples to route */
+#define NBROUTE_UL 16
+/* 10 routing tables max */
+#define NBROUTE_CONFIG_MAX 10
+/* 5 pre-computed routing tables */
+#define NBROUTE_CONFIG 6
+/* AMIC on VX_UL */
+#define UPROUTE_CONFIG_AMIC 0
+/* DMIC first pair on VX_UL */
+#define UPROUTE_CONFIG_DMIC1 1
+/* DMIC second pair on VX_UL */
+#define UPROUTE_CONFIG_DMIC2 2
+/* DMIC last pair on VX_UL */
+#define UPROUTE_CONFIG_DMIC3 3
+/* BT_UL on VX_UL */
+#define UPROUTE_CONFIG_BT 4
+/* ECHO_REF on MM_UL2 */
+#define UPROUTE_ECHO_MMUL2 5
+/* call-back indexes */
+#define MAXCALLBACK 100
+/* subroutines */
+#define MAXNBSUBROUTINE 100
+/* time controlled sequenced */
+#define MAXNBSEQUENCE 20
+/* maximum simultaneous active sequences */
+#define MAXACTIVESEQUENCE 20
+/* max number of steps in the sequences */
+#define MAXSEQUENCESTEPS 2
+/* max number of feature associated to a port */
+#define MAXFEATUREPORT 12
+#define SUB_0_PARAM 0
+/* number of parameters per sequence calls */
+#define SUB_1_PARAM 1
+#define SUB_2_PARAM 2
+#define SUB_3_PARAM 3
+#define SUB_4_PARAM 4
+/* active sequence mask = 0 means the line is free */
+#define FREE_LINE 0
+/* no ask for collision protection */
+#define NOMASK (1 << 0)
+/* do not allow a PDM OFF during the execution of this sequence */
+#define MASK_PDM_OFF (1 << 1)
+/* do not allow a PDM ON during the execution of this sequence */
+#define MASK_PDM_ON (1 << 2)
+/* explicit name of the feature */
+#define NBCHARFEATURENAME 16
+/* explicit name of the port */
+#define NBCHARPORTNAME 16
+/* sink / input port from Host point of view (or AESS for DMIC/McPDM/.. */
+#define SNK_P ABE_ATC_DIRECTION_IN
+/* source / ouptut port */
+#define SRC_P ABE_ATC_DIRECTION_OUT
+/* no ASRC applied */
+#define NODRIFT 0
+/* for abe_set_asrc_drift_control */
+#define FORCED_DRIFT_CONTROL 1
+/* for abe_set_asrc_drift_control */
+#define ADPATIVE_DRIFT_CONTROL 2
+/* number of task/slot depending on the OPP value */
+#define DOPPMODE32_OPP100 (0x00000010)
+#define DOPPMODE32_OPP50 (0x0000000C)
+#define DOPPMODE32_OPP25 (0x0000004)
+/*
+ * ABE CONST AREA FOR PARAMETERS TRANSLATION
+ */
+#define min_mdb (-12000)
+#define max_mdb ( 3000)
+#define sizeof_db2lin_table (1 + ((max_mdb - min_mdb)/100))
+#define sizeof_alpha_iir_table 61
+#define sizeof_beta_iir_table 61
+#define GAIN_MAXIMUM 3000L
+#define GAIN_24dB 2400L
+#define GAIN_18dB 1800L
+#define GAIN_12dB 1200L
+#define GAIN_6dB 600L
+/* default gain = 1 */
+#define GAIN_0dB 0L
+#define GAIN_M6dB -600L
+#define GAIN_M12dB -1200L
+#define GAIN_M18dB -1800L
+#define GAIN_M24dB -2400L
+#define GAIN_M30dB -3000L
+#define GAIN_M40dB -4000L
+#define GAIN_M50dB -5000L
+/* muted gain = -120 decibels */
+#define MUTE_GAIN -12000L
+#define GAIN_TOOLOW -13000L
+#define GAIN_MUTE MUTE_GAIN
+#define RAMP_MINLENGTH 3L
+/* ramp_t is in milli- seconds */
+#define RAMP_0MS 0L
+#define RAMP_1MS 1L
+#define RAMP_2MS 2L
+#define RAMP_5MS 5L
+#define RAMP_10MS 10L
+#define RAMP_20MS 20L
+#define RAMP_50MS 50L
+#define RAMP_100MS 100L
+#define RAMP_200MS 200L
+#define RAMP_500MS 500L
+#define RAMP_1000MS 1000L
+#define RAMP_MAXLENGTH 10000L
+/* for abe_translate_gain_format */
+#define LINABE_TO_DECIBELS 1
+#define DECIBELS_TO_LINABE 2
+/* for abe_translate_ramp_format */
+#define IIRABE_TO_MICROS 1
+#define MICROS_TO_IIABE 2
+/*
+ * ABE CONST AREA FOR PERIPHERAL TUNING
+ */
+/* port idled IDLE_P */
+#define OMAP_ABE_PORT_ACTIVITY_IDLE 1
+/* port initialized, ready to be activated */
+#define OMAP_ABE_PORT_INITIALIZED 3
+/* port activated RUN_P */
+#define OMAP_ABE_PORT_ACTIVITY_RUNNING 2
+#define NOCALLBACK 0
+#define NOPARAMETER 0
+/* number of ATC access upon AMIC DMArequests, all the FIFOs are enabled */
+#define MCPDM_UL_ITER 4
+/* All the McPDM FIFOs are enabled simultaneously */
+#define MCPDM_DL_ITER 24
+/* All the DMIC FIFOs are enabled simultaneously */
+#define DMIC_ITER 12
+/* TBD later if needed */
+#define MAX_PINGPONG_BUFFERS 2
+/*
+ * Indexes to the subroutines
+ */
+#define SUB_WRITE_MIXER 1
+#define SUB_WRITE_PORT_GAIN 2
+/* OLD WAY */
+#define c_feat_init_eq 1
+#define c_feat_read_eq1 2
+#define c_write_eq1 3
+#define c_feat_read_eq2 4
+#define c_write_eq2 5
+#define c_feat_read_eq3 6
+#define c_write_eq3 7
+/* max number of gain to be controlled by HAL */
+#define MAX_NBGAIN_CMEM 34
+/*
+ * MACROS
+ */
+#define maximum(a,b) (((a)<(b))?(b):(a))
+#define minimum(a,b) (((a)>(b))?(b):(a))
+#define absolute(a) (((a)>0)?(a):((-1)*(a)))
+#define HAL_VERSIONS 9
+#endif/* _ABE_DEF_H_ */
diff --git a/sound/soc/omap/abe/abe_define.h b/sound/soc/omap/abe/abe_define.h
new file mode 100644
index 00000000000..ff54cc3490b
--- /dev/null
+++ b/sound/soc/omap/abe/abe_define.h
@@ -0,0 +1,65 @@
+/*
+ * ALSA SoC OMAP ABE driver
+*
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef _ABE_DEFINE_H_
+#define _ABE_DEFINE_H_
+#define ATC_DESCRIPTOR_NUMBER 64
+#define PROCESSING_SLOTS 25
+#define TASK_POOL_LENGTH 128
+#define MCU_IRQ 0x24
+#define MCU_IRQ_SHIFT2 0x90
+#define DMA_REQ_SHIFT2 0x210
+#define DSP_IRQ 0x4c
+#define IRQtag_APS 0x000a
+#define IRQtag_COUNT 0x000c
+#define IRQtag_PP 0x000d
+#define DMAreq_7 0x0080
+#define IRQ_FIFO_LENGTH 16
+#define SDT_EQ_ORDER 4
+#define DL_EQ_ORDER 12
+#define MIC_FILTER_ORDER 4
+#define GAINS_WITH_RAMP1 14
+#define GAINS_WITH_RAMP2 22
+#define GAINS_WITH_RAMP_TOTAL 36
+#define ASRC_MEMLENGTH 40
+#define ASRC_UL_VX_FIR_L 19
+#define ASRC_DL_VX_FIR_L 19
+#define ASRC_MM_EXT_IN_FIR_L 18
+#define ASRC_margin 2
+#define ASRC_N_8k 2
+#define ASRC_N_16k 4
+#define ASRC_N_48k 12
+#define VIBRA_N 5
+#define VIBRA1_IIR_MEMSIZE 11
+#define SAMP_LOOP_96K 24
+#define SAMP_LOOP_48K 12
+#define SAMP_LOOP_16K 4
+#define SAMP_LOOP_8K 2
+#define INPUT_SCALE_SHIFTM2 5052
+#define OUTPUT_SCALE_SHIFTM2 5056
+#define MUTE_SCALING 5060
+#define ABE_PMEM 1
+#define ABE_CMEM 2
+#define ABE_SMEM 3
+#define ABE_DMEM 4
+#define ABE_ATC 5
+#define ASRC_BT_UL_FIR_L 19
+#define ASRC_BT_DL_FIR_L 19
+#endif/* _ABE_DEFINE_H_ */
diff --git a/sound/soc/omap/abe/abe_dm_addr.h b/sound/soc/omap/abe/abe_dm_addr.h
new file mode 100644
index 00000000000..a6a6c3df045
--- /dev/null
+++ b/sound/soc/omap/abe/abe_dm_addr.h
@@ -0,0 +1,326 @@
+/*
+ * ALSA SoC OMAP ABE driver
+*
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef _ABE_DM_ADDR_H_
+#define _ABE_DM_ADDR_H_
+#define D_atcDescriptors_ADDR 0
+#define D_atcDescriptors_ADDR_END 511
+#define D_atcDescriptors_sizeof 512
+#define stack_ADDR 512
+#define stack_ADDR_END 623
+#define stack_sizeof 112
+#define D_version_ADDR 624
+#define D_version_ADDR_END 627
+#define D_version_sizeof 4
+#define D_BT_DL_FIFO_ADDR 1024
+#define D_BT_DL_FIFO_ADDR_END 1503
+#define D_BT_DL_FIFO_sizeof 480
+#define D_BT_UL_FIFO_ADDR 1536
+#define D_BT_UL_FIFO_ADDR_END 2015
+#define D_BT_UL_FIFO_sizeof 480
+#define D_MM_EXT_OUT_FIFO_ADDR 2048
+#define D_MM_EXT_OUT_FIFO_ADDR_END 2527
+#define D_MM_EXT_OUT_FIFO_sizeof 480
+#define D_MM_EXT_IN_FIFO_ADDR 2560
+#define D_MM_EXT_IN_FIFO_ADDR_END 3039
+#define D_MM_EXT_IN_FIFO_sizeof 480
+#define D_MM_UL2_FIFO_ADDR 3072
+#define D_MM_UL2_FIFO_ADDR_END 3551
+#define D_MM_UL2_FIFO_sizeof 480
+#define D_VX_UL_FIFO_ADDR 3584
+#define D_VX_UL_FIFO_ADDR_END 4063
+#define D_VX_UL_FIFO_sizeof 480
+#define D_VX_DL_FIFO_ADDR 4096
+#define D_VX_DL_FIFO_ADDR_END 4575
+#define D_VX_DL_FIFO_sizeof 480
+#define D_DMIC_UL_FIFO_ADDR 4608
+#define D_DMIC_UL_FIFO_ADDR_END 5087
+#define D_DMIC_UL_FIFO_sizeof 480
+#define D_MM_UL_FIFO_ADDR 5120
+#define D_MM_UL_FIFO_ADDR_END 5599
+#define D_MM_UL_FIFO_sizeof 480
+#define D_MM_DL_FIFO_ADDR 5632
+#define D_MM_DL_FIFO_ADDR_END 6111
+#define D_MM_DL_FIFO_sizeof 480
+#define D_TONES_DL_FIFO_ADDR 6144
+#define D_TONES_DL_FIFO_ADDR_END 6623
+#define D_TONES_DL_FIFO_sizeof 480
+#define D_VIB_DL_FIFO_ADDR 6656
+#define D_VIB_DL_FIFO_ADDR_END 7135
+#define D_VIB_DL_FIFO_sizeof 480
+#define D_McPDM_DL_FIFO_ADDR 7168
+#define D_McPDM_DL_FIFO_ADDR_END 7647
+#define D_McPDM_DL_FIFO_sizeof 480
+#define D_McPDM_UL_FIFO_ADDR 7680
+#define D_McPDM_UL_FIFO_ADDR_END 8159
+#define D_McPDM_UL_FIFO_sizeof 480
+#define D_DEBUG_FIFO_ADDR 8160
+#define D_DEBUG_FIFO_ADDR_END 8255
+#define D_DEBUG_FIFO_sizeof 96
+#define D_DEBUG_FIFO_HAL_ADDR 8256
+#define D_DEBUG_FIFO_HAL_ADDR_END 8287
+#define D_DEBUG_FIFO_HAL_sizeof 32
+#define D_IOdescr_ADDR 8288
+#define D_IOdescr_ADDR_END 8927
+#define D_IOdescr_sizeof 640
+#define d_zero_ADDR 8928
+#define d_zero_ADDR_END 8931
+#define d_zero_sizeof 4
+#define dbg_trace1_ADDR 8932
+#define dbg_trace1_ADDR_END 8932
+#define dbg_trace1_sizeof 1
+#define dbg_trace2_ADDR 8933
+#define dbg_trace2_ADDR_END 8933
+#define dbg_trace2_sizeof 1
+#define dbg_trace3_ADDR 8934
+#define dbg_trace3_ADDR_END 8934
+#define dbg_trace3_sizeof 1
+#define D_multiFrame_ADDR 8936
+#define D_multiFrame_ADDR_END 9335
+#define D_multiFrame_sizeof 400
+#define D_tasksList_ADDR 9336
+#define D_tasksList_ADDR_END 11383
+#define D_tasksList_sizeof 2048
+#define D_idleTask_ADDR 11384
+#define D_idleTask_ADDR_END 11385
+#define D_idleTask_sizeof 2
+#define D_typeLengthCheck_ADDR 11386
+#define D_typeLengthCheck_ADDR_END 11387
+#define D_typeLengthCheck_sizeof 2
+#define D_maxTaskBytesInSlot_ADDR 11388
+#define D_maxTaskBytesInSlot_ADDR_END 11389
+#define D_maxTaskBytesInSlot_sizeof 2
+#define D_rewindTaskBytes_ADDR 11390
+#define D_rewindTaskBytes_ADDR_END 11391
+#define D_rewindTaskBytes_sizeof 2
+#define D_pCurrentTask_ADDR 11392
+#define D_pCurrentTask_ADDR_END 11393
+#define D_pCurrentTask_sizeof 2
+#define D_pFastLoopBack_ADDR 11394
+#define D_pFastLoopBack_ADDR_END 11395
+#define D_pFastLoopBack_sizeof 2
+#define D_pNextFastLoopBack_ADDR 11396
+#define D_pNextFastLoopBack_ADDR_END 11399
+#define D_pNextFastLoopBack_sizeof 4
+#define D_ppCurrentTask_ADDR 11400
+#define D_ppCurrentTask_ADDR_END 11401
+#define D_ppCurrentTask_sizeof 2
+#define D_slotCounter_ADDR 11404
+#define D_slotCounter_ADDR_END 11405
+#define D_slotCounter_sizeof 2
+#define D_loopCounter_ADDR 11408
+#define D_loopCounter_ADDR_END 11411
+#define D_loopCounter_sizeof 4
+#define D_RewindFlag_ADDR 11412
+#define D_RewindFlag_ADDR_END 11413
+#define D_RewindFlag_sizeof 2
+#define D_Slot23_ctrl_ADDR 11416
+#define D_Slot23_ctrl_ADDR_END 11419
+#define D_Slot23_ctrl_sizeof 4
+#define D_McuIrqFifo_ADDR 11420
+#define D_McuIrqFifo_ADDR_END 11483
+#define D_McuIrqFifo_sizeof 64
+#define D_PingPongDesc_ADDR 11484
+#define D_PingPongDesc_ADDR_END 11507
+#define D_PingPongDesc_sizeof 24
+#define D_PP_MCU_IRQ_ADDR 11508
+#define D_PP_MCU_IRQ_ADDR_END 11509
+#define D_PP_MCU_IRQ_sizeof 2
+#define D_ctrlPortFifo_ADDR 11520
+#define D_ctrlPortFifo_ADDR_END 11535
+#define D_ctrlPortFifo_sizeof 16
+#define D_Idle_State_ADDR 11536
+#define D_Idle_State_ADDR_END 11539
+#define D_Idle_State_sizeof 4
+#define D_Stop_Request_ADDR 11540
+#define D_Stop_Request_ADDR_END 11543
+#define D_Stop_Request_sizeof 4
+#define D_Ref0_ADDR 11544
+#define D_Ref0_ADDR_END 11545
+#define D_Ref0_sizeof 2
+#define D_DebugRegister_ADDR 11548
+#define D_DebugRegister_ADDR_END 11687
+#define D_DebugRegister_sizeof 140
+#define D_Gcount_ADDR 11688
+#define D_Gcount_ADDR_END 11689
+#define D_Gcount_sizeof 2
+#define D_DCcounter_ADDR 11692
+#define D_DCcounter_ADDR_END 11695
+#define D_DCcounter_sizeof 4
+#define D_DCsum_ADDR 11696
+#define D_DCsum_ADDR_END 11703
+#define D_DCsum_sizeof 8
+#define D_fastCounter_ADDR 11704
+#define D_fastCounter_ADDR_END 11707
+#define D_fastCounter_sizeof 4
+#define D_slowCounter_ADDR 11708
+#define D_slowCounter_ADDR_END 11711
+#define D_slowCounter_sizeof 4
+#define D_aUplinkRouting_ADDR 11712
+#define D_aUplinkRouting_ADDR_END 11743
+#define D_aUplinkRouting_sizeof 32
+#define D_VirtAudioLoop_ADDR 11744
+#define D_VirtAudioLoop_ADDR_END 11747
+#define D_VirtAudioLoop_sizeof 4
+#define D_AsrcVars_DL_VX_ADDR 11748
+#define D_AsrcVars_DL_VX_ADDR_END 11779
+#define D_AsrcVars_DL_VX_sizeof 32
+#define D_AsrcVars_UL_VX_ADDR 11780
+#define D_AsrcVars_UL_VX_ADDR_END 11811
+#define D_AsrcVars_UL_VX_sizeof 32
+#define D_CoefAddresses_VX_ADDR 11812
+#define D_CoefAddresses_VX_ADDR_END 11843
+#define D_CoefAddresses_VX_sizeof 32
+#define D_AsrcVars_MM_EXT_IN_ADDR 11844
+#define D_AsrcVars_MM_EXT_IN_ADDR_END 11875
+#define D_AsrcVars_MM_EXT_IN_sizeof 32
+#define D_CoefAddresses_MM_ADDR 11876
+#define D_CoefAddresses_MM_ADDR_END 11907
+#define D_CoefAddresses_MM_sizeof 32
+#define D_APS_DL1_M_thresholds_ADDR 11908
+#define D_APS_DL1_M_thresholds_ADDR_END 11915
+#define D_APS_DL1_M_thresholds_sizeof 8
+#define D_APS_DL1_M_IRQ_ADDR 11916
+#define D_APS_DL1_M_IRQ_ADDR_END 11917
+#define D_APS_DL1_M_IRQ_sizeof 2
+#define D_APS_DL1_C_IRQ_ADDR 11918
+#define D_APS_DL1_C_IRQ_ADDR_END 11919
+#define D_APS_DL1_C_IRQ_sizeof 2
+#define D_TraceBufAdr_ADDR 11920
+#define D_TraceBufAdr_ADDR_END 11921
+#define D_TraceBufAdr_sizeof 2
+#define D_TraceBufOffset_ADDR 11922
+#define D_TraceBufOffset_ADDR_END 11923
+#define D_TraceBufOffset_sizeof 2
+#define D_TraceBufLength_ADDR 11924
+#define D_TraceBufLength_ADDR_END 11925
+#define D_TraceBufLength_sizeof 2
+#define D_AsrcVars_ECHO_REF_ADDR 11928
+#define D_AsrcVars_ECHO_REF_ADDR_END 11959
+#define D_AsrcVars_ECHO_REF_sizeof 32
+#define D_Pempty_ADDR 11960
+#define D_Pempty_ADDR_END 11963
+#define D_Pempty_sizeof 4
+#define D_APS_DL2_L_M_IRQ_ADDR 11964
+#define D_APS_DL2_L_M_IRQ_ADDR_END 11965
+#define D_APS_DL2_L_M_IRQ_sizeof 2
+#define D_APS_DL2_L_C_IRQ_ADDR 11966
+#define D_APS_DL2_L_C_IRQ_ADDR_END 11967
+#define D_APS_DL2_L_C_IRQ_sizeof 2
+#define D_APS_DL2_R_M_IRQ_ADDR 11968
+#define D_APS_DL2_R_M_IRQ_ADDR_END 11969
+#define D_APS_DL2_R_M_IRQ_sizeof 2
+#define D_APS_DL2_R_C_IRQ_ADDR 11970
+#define D_APS_DL2_R_C_IRQ_ADDR_END 11971
+#define D_APS_DL2_R_C_IRQ_sizeof 2
+#define D_APS_DL1_C_thresholds_ADDR 11972
+#define D_APS_DL1_C_thresholds_ADDR_END 11979
+#define D_APS_DL1_C_thresholds_sizeof 8
+#define D_APS_DL2_L_M_thresholds_ADDR 11980
+#define D_APS_DL2_L_M_thresholds_ADDR_END 11987
+#define D_APS_DL2_L_M_thresholds_sizeof 8
+#define D_APS_DL2_L_C_thresholds_ADDR 11988
+#define D_APS_DL2_L_C_thresholds_ADDR_END 11995
+#define D_APS_DL2_L_C_thresholds_sizeof 8
+#define D_APS_DL2_R_M_thresholds_ADDR 11996
+#define D_APS_DL2_R_M_thresholds_ADDR_END 12003
+#define D_APS_DL2_R_M_thresholds_sizeof 8
+#define D_APS_DL2_R_C_thresholds_ADDR 12004
+#define D_APS_DL2_R_C_thresholds_ADDR_END 12011
+#define D_APS_DL2_R_C_thresholds_sizeof 8
+#define D_ECHO_REF_48_16_WRAP_ADDR 12012
+#define D_ECHO_REF_48_16_WRAP_ADDR_END 12019
+#define D_ECHO_REF_48_16_WRAP_sizeof 8
+#define D_ECHO_REF_48_8_WRAP_ADDR 12020
+#define D_ECHO_REF_48_8_WRAP_ADDR_END 12027
+#define D_ECHO_REF_48_8_WRAP_sizeof 8
+#define D_BT_UL_16_48_WRAP_ADDR 12028
+#define D_BT_UL_16_48_WRAP_ADDR_END 12035
+#define D_BT_UL_16_48_WRAP_sizeof 8
+#define D_BT_UL_8_48_WRAP_ADDR 12036
+#define D_BT_UL_8_48_WRAP_ADDR_END 12043
+#define D_BT_UL_8_48_WRAP_sizeof 8
+#define D_BT_DL_48_16_WRAP_ADDR 12044
+#define D_BT_DL_48_16_WRAP_ADDR_END 12051
+#define D_BT_DL_48_16_WRAP_sizeof 8
+#define D_BT_DL_48_8_WRAP_ADDR 12052
+#define D_BT_DL_48_8_WRAP_ADDR_END 12059
+#define D_BT_DL_48_8_WRAP_sizeof 8
+#define D_VX_DL_16_48_WRAP_ADDR 12060
+#define D_VX_DL_16_48_WRAP_ADDR_END 12067
+#define D_VX_DL_16_48_WRAP_sizeof 8
+#define D_VX_DL_8_48_WRAP_ADDR 12068
+#define D_VX_DL_8_48_WRAP_ADDR_END 12075
+#define D_VX_DL_8_48_WRAP_sizeof 8
+#define D_VX_UL_48_16_WRAP_ADDR 12076
+#define D_VX_UL_48_16_WRAP_ADDR_END 12083
+#define D_VX_UL_48_16_WRAP_sizeof 8
+#define D_VX_UL_48_8_WRAP_ADDR 12084
+#define D_VX_UL_48_8_WRAP_ADDR_END 12091
+#define D_VX_UL_48_8_WRAP_sizeof 8
+#define D_APS_DL1_IRQs_WRAP_ADDR 12092
+#define D_APS_DL1_IRQs_WRAP_ADDR_END 12099
+#define D_APS_DL1_IRQs_WRAP_sizeof 8
+#define D_APS_DL2_L_IRQs_WRAP_ADDR 12100
+#define D_APS_DL2_L_IRQs_WRAP_ADDR_END 12107
+#define D_APS_DL2_L_IRQs_WRAP_sizeof 8
+#define D_APS_DL2_R_IRQs_WRAP_ADDR 12108
+#define D_APS_DL2_R_IRQs_WRAP_ADDR_END 12115
+#define D_APS_DL2_R_IRQs_WRAP_sizeof 8
+#define D_nextMultiFrame_ADDR 12116
+#define D_nextMultiFrame_ADDR_END 12123
+#define D_nextMultiFrame_sizeof 8
+#define D_HW_TEST_ADDR 12124
+#define D_HW_TEST_ADDR_END 12131
+#define D_HW_TEST_sizeof 8
+#define D_TraceBufAdr_HAL_ADDR 12132
+#define D_TraceBufAdr_HAL_ADDR_END 12135
+#define D_TraceBufAdr_HAL_sizeof 4
+#define D_DEBUG_HAL_TASK_ADDR 12288
+#define D_DEBUG_HAL_TASK_ADDR_END 14335
+#define D_DEBUG_HAL_TASK_sizeof 2048
+#define D_DEBUG_FW_TASK_ADDR 14336
+#define D_DEBUG_FW_TASK_ADDR_END 14591
+#define D_DEBUG_FW_TASK_sizeof 256
+#define D_FwMemInit_ADDR 14592
+#define D_FwMemInit_ADDR_END 15551
+#define D_FwMemInit_sizeof 960
+#define D_FwMemInitDescr_ADDR 15552
+#define D_FwMemInitDescr_ADDR_END 15567
+#define D_FwMemInitDescr_sizeof 16
+#define D_AsrcVars_BT_UL_ADDR 15568
+#define D_AsrcVars_BT_UL_ADDR_END 15599
+#define D_AsrcVars_BT_UL_sizeof 32
+#define D_AsrcVars_BT_DL_ADDR 15600
+#define D_AsrcVars_BT_DL_ADDR_END 15631
+#define D_AsrcVars_BT_DL_sizeof 32
+#define D_BT_DL_48_8_OPP100_WRAP_ADDR 15632
+#define D_BT_DL_48_8_OPP100_WRAP_ADDR_END 15639
+#define D_BT_DL_48_8_OPP100_WRAP_sizeof 8
+#define D_BT_DL_48_16_OPP100_WRAP_ADDR 15640
+#define D_BT_DL_48_16_OPP100_WRAP_ADDR_END 15647
+#define D_BT_DL_48_16_OPP100_WRAP_sizeof 8
+#define D_PING_ADDR 16384
+#define D_PING_ADDR_END 40959
+#define D_PING_sizeof 24576
+#define D_PONG_ADDR 40960
+#define D_PONG_ADDR_END 65535
+#define D_PONG_sizeof 24576
+#endif/* _ABEDM_ADDR_H_ */
diff --git a/sound/soc/omap/abe/abe_ext.c b/sound/soc/omap/abe/abe_ext.c
new file mode 100644
index 00000000000..21f05d6c4fa
--- /dev/null
+++ b/sound/soc/omap/abe/abe_ext.c
@@ -0,0 +1,228 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include "abe_main.h"
+#define ENABLE_DEFAULT_PLAYERS 0
+/**
+ * abe_default_irq_pingpong_player
+ *
+ * generates data for the cache-flush buffer MODE 16+16
+ */
+void abe_default_irq_pingpong_player(void)
+{
+#if ENABLE_DEFAULT_PLAYERS
+#define N_SAMPLES_MAX ((int)(1024)) /* ping-pong access to MM_DL at 48kHz Mono with 20ms packet sizes */
+ static s32 idx;
+ u32 i, dst, n_samples, n_bytes;
+ s32 temp[N_SAMPLES_MAX], audio_sample;
+#define DATA_SIZE 20 /* t = [0:N-1]/N; x = round(16383*sin(2*pi*t)) */
+ const s32 audio_pattern[DATA_SIZE] = {
+ 0, 5063, 9630, 13254, 15581, 16383, 15581, 13254, 9630,
+ 5063, 0, -5063, -9630, -13254, -15581, -16383, -15581,
+ -13254, -9630, -5063
+ };
+#if 0
+#define DATA_SIZE 8
+ const s32 audio_pattern[DATA_SIZE] = {
+ 0, 11585, 16384, 11585, 0, -11586, -16384, -11586
+ };
+#define DATA_SIZE 12
+ const s32 audio_pattern[DATA_SIZE] = {
+ 0, 8191, 14188, 16383, 14188, 8191, 0,
+ -8192, -14188, -16383, -14188, -8192
+ };
+ const s32 audio_pattern[8] = {
+ 16383, 16383, 16383, 16383, -16384, -16384, -16384, -16384
+ };
+#endif
+ /* read the address of the Pong buffer */
+ abe_read_next_ping_pong_buffer(MM_DL_PORT, &dst, &n_bytes);
+ /* each stereo sample weights 4 bytes (format 16|16) */
+ n_samples = n_bytes / 4;
+ /* generate a test pattern */
+ for (i = 0; i < n_samples; i++) {
+ audio_sample = audio_pattern[idx];
+ idx = (idx >= (DATA_SIZE - 1)) ? 0 : (idx + 1);
+ /* format 16|16 */
+ temp[i] = ((audio_sample << 16) + audio_sample);
+ }
+ /* copy the pattern (flush it) to DMEM pointer update
+ * not necessary here because the buffer size do not
+ * change from one ping to the other pong
+ */
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, dst,
+ (u32 *) &(temp[0]), n_bytes);
+ abe_set_ping_pong_buffer(MM_DL_PORT, n_bytes);
+#endif
+}
+/**
+ * abe_default_irq_pingpong_player_32bits
+ *
+ * generates data for the cache-flush buffer MODE 32 BITS
+ * Return value:
+ * None.
+ */
+void abe_default_irq_pingpong_player_32bits(void)
+{
+#if ENABLE_DEFAULT_PLAYERS
+ /* ping-pong access to MM_DL at 48kHz Mono with 20ms packet sizes */
+ static s32 idx;
+ u32 i, dst, n_samples, n_bytes;
+ s32 temp[N_SAMPLES_MAX], audio_sample;
+#define DATA_SIZE 20 /* t = [0:N-1]/N; x = round(16383*sin(2*pi*t)) */
+ const s32 audio_pattern[DATA_SIZE] = {
+ 0, 5063, 9630, 13254, 15581, 16383, 15581, 13254,
+ 9630, 5063, 0, -5063, -9630, -13254, -15581, -16383,
+ -15581, -13254, -9630, -5063
+ };
+ /* read the address of the Pong buffer */
+ abe_read_next_ping_pong_buffer(MM_DL_PORT, &dst, &n_bytes);
+ /* each stereo sample weights 8 bytes (format 32|32) */
+ n_samples = n_bytes / 8;
+ /* generate a test pattern */
+ for (i = 0; i < n_samples; i++) {
+ /* circular addressing */
+ audio_sample = audio_pattern[idx];
+ idx = (idx >= (DATA_SIZE - 1)) ? 0 : (idx + 1);
+ temp[i * 2 + 0] = (audio_sample << 16);
+ temp[i * 2 + 1] = (audio_sample << 16);
+ }
+ abe_set_ping_pong_buffer(MM_DL_PORT, 0);
+ /* copy the pattern (flush it) to DMEM pointer update
+ * not necessary here because the buffer size do not
+ * change from one ping to the other pong
+ */
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, dst,
+ (u32 *) &(temp[0]), n_bytes);
+ abe_set_ping_pong_buffer(MM_DL_PORT, n_bytes);
+#endif
+}
+/**
+ * abe_rshifted16_irq_pingpong_player_32bits
+ *
+ * generates data for the cache-flush buffer MODE 32 BITS
+ * Return value:
+ * None.
+ */
+void abe_rshifted16_irq_pingpong_player_32bits(void)
+{
+#if ENABLE_DEFAULT_PLAYERS
+ /* ping-pong access to MM_DL at 48kHz Mono with 20ms packet sizes */
+ static s32 idx;
+ u32 i, dst, n_samples, n_bytes;
+ s32 temp[N_SAMPLES_MAX], audio_sample;
+#define DATA_SIZE 20 /* t = [0:N-1]/N; x = round(16383*sin(2*pi*t)) */
+ const s32 audio_pattern[DATA_SIZE] = {
+ 0, 5063, 9630, 13254, 15581, 16383, 15581, 13254,
+ 9630, 5063, 0, -5063, -9630, -13254, -15581, -16383,
+ -15581, -13254, -9630, -5063
+ };
+ /* read the address of the Pong buffer */
+ abe_read_next_ping_pong_buffer(MM_DL_PORT, &dst, &n_bytes);
+ /* each stereo sample weights 8 bytes (format 32|32) */
+ n_samples = n_bytes / 8;
+ /* generate a test pattern */
+ for (i = 0; i < n_samples; i++) {
+ /* circular addressing */
+ audio_sample = audio_pattern[idx];
+ idx = (idx >= (DATA_SIZE - 1)) ? 0 : (idx + 1);
+ temp[i * 2 + 0] = audio_sample;
+ temp[i * 2 + 1] = audio_sample;
+ }
+ abe_set_ping_pong_buffer(MM_DL_PORT, 0);
+ /* copy the pattern (flush it) to DMEM pointer update
+ * not necessary here because the buffer size do not
+ * change from one ping to the other pong
+ */
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, dst,
+ (u32 *) &(temp[0]), n_bytes);
+ abe_set_ping_pong_buffer(MM_DL_PORT, n_bytes);
+#endif
+}
+/**
+ * abe_1616_irq_pingpong_player_1616bits
+ *
+ * generates data for the cache-flush buffer MODE 16+16 BITS
+ * Return value:
+ * None.
+ */
+void abe_1616_irq_pingpong_player_1616bits(void)
+{
+#if ENABLE_DEFAULT_PLAYERS
+ /* ping-pong access to MM_DL at 48kHz Mono with 20ms packet sizes */
+ static s32 idx;
+ u32 i, dst, n_samples, n_bytes;
+ s32 temp[N_SAMPLES_MAX], audio_sample;
+#define DATA_SIZE 20 /* t = [0:N-1]/N; x = round(16383*sin(2*pi*t)) */
+ const s32 audio_pattern[DATA_SIZE] = {
+ 0, 5063, 9630, 13254, 15581, 16383, 15581, 13254,
+ 9630, 5063, 0, -5063, -9630, -13254, -15581, -16383,
+ -15581, -13254, -9630, -5063
+ };
+ /* read the address of the Pong buffer */
+ abe_read_next_ping_pong_buffer(MM_DL_PORT, &dst, &n_bytes);
+ /* each stereo sample weights 4 bytes (format 16+16) */
+ n_samples = n_bytes / 4;
+ /* generate a test pattern */
+ for (i = 0; i < n_samples; i++) {
+ /* circular addressing */
+ audio_sample = audio_pattern[idx];
+ idx = (idx >= (DATA_SIZE - 1)) ? 0 : (idx + 1);
+ temp[i] = (audio_sample << 16) | (audio_sample & 0x0000FFFF);
+ }
+ abe_set_ping_pong_buffer(MM_DL_PORT, 0);
+ /* copy the pattern (flush it) to DMEM pointer update
+ * not necessary here because the buffer size do not
+ * change from one ping to the other pong
+ */
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, dst,
+ (u32 *) &(temp[0]), n_bytes);
+ abe_set_ping_pong_buffer(MM_DL_PORT, n_bytes);
+#endif
+}
+/**
+ * abe_default_irq_aps_adaptation
+ *
+ * updates the APS filter and gain
+ */
+void abe_default_irq_aps_adaptation(void)
+{
+}
+/**
+ * abe_read_sys_clock
+ * @time: pointer to the system clock
+ *
+ * returns the current time indication for the LOG
+ */
+void abe_read_sys_clock(u32 *time)
+{
+ static u32 clock;
+ *time = clock;
+ clock++;
+}
+/**
+ * abe_aps_tuning
+ *
+ * Tune APS parameters
+ *
+ */
+void abe_aps_tuning(void)
+{
+}
diff --git a/sound/soc/omap/abe/abe_ext.h b/sound/soc/omap/abe/abe_ext.h
new file mode 100644
index 00000000000..eed6395a9e2
--- /dev/null
+++ b/sound/soc/omap/abe/abe_ext.h
@@ -0,0 +1,222 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#ifndef _ABE_EXT_H_
+#define _ABE_EXT_H_
+/* Tuning is done on PC ? */
+#define PC_SIMULATION 0
+/*
+ * OS DEPENDENT MMU CONFIGURATION
+ */
+#define _lock_enter
+#define _lock_exit
+#define ABE_PMEM_BASE_OFFSET_MPU 0xe0000
+#define ABE_CMEM_BASE_OFFSET_MPU 0xa0000
+#define ABE_SMEM_BASE_OFFSET_MPU 0xc0000
+#define ABE_DMEM_BASE_OFFSET_MPU 0x80000
+#define ABE_ATC_BASE_OFFSET_MPU 0xf1000
+/* default base address for io_base */
+#define ABE_DEFAULT_BASE_ADDRESS_L3 0x49000000L
+/* base address used for L3/DMA access */
+#define ABE_ATC_BASE_ADDRESS_L3 0x490F1000L
+/* base address used for L4/MCU access */
+#define ABE_ATC_BASE_ADDRESS_L4 0x401F1000L
+/* 64kB as seen from DMA access */
+#define ABE_DMEM_BASE_ADDRESS_L3 0x49080000L
+/* 64kB as seen from MCU access */
+#define ABE_DMEM_BASE_ADDRESS_L4 0x40180000L
+/* 8kB as seen from MPU access */
+#define ABE_PMEM_BASE_ADDRESS_MPU 0x490E0000L
+/* 8kB */
+#define ABE_CMEM_BASE_ADDRESS_MPU 0x490A0000L
+/* 24kB */
+#define ABE_SMEM_BASE_ADDRESS_MPU 0x490C0000L
+/* 64kB */
+#define ABE_DMEM_BASE_ADDRESS_MPU 0x49080000L
+#define ABE_ATC_BASE_ADDRESS_MPU 0x490F1000L
+/*
+ * HARDWARE AND PERIPHERAL DEFINITIONS
+ */
+/* PMEM SIZE in bytes (1024 words of 64 bits: : #32bits words x 4)*/
+#define ABE_PMEM_SIZE 8192
+/* CMEM SIZE in bytes (2048 coeff : #32bits words x 4)*/
+#define ABE_CMEM_SIZE 8192
+/* SMEM SIZE in bytes (3072 stereo samples : #32bits words x 4)*/
+#define ABE_SMEM_SIZE 24576
+/* DMEM SIZE in bytes */
+#define ABE_DMEM_SIZE 65536L
+/* ATC REGISTERS SIZE in bytes */
+#define ABE_ATC_DESC_SIZE 512
+/* holds the MCU Irq signal */
+#define ABE_MCU_IRQSTATUS_RAW 0x24
+/* status : clear the IRQ */
+#define ABE_MCU_IRQSTATUS 0x28
+/* holds the DSP Irq signal */
+#define ABE_DSP_IRQSTATUS_RAW 0x4C
+/* holds the DMA req lines to the sDMA */
+#define ABE_DMASTATUS_RAW 0x84
+#define EVENT_GENERATOR_COUNTER 0x68
+/* PLL output/desired sampling rate = (32768 * 6000)/96000 */
+#define EVENT_GENERATOR_COUNTER_DEFAULT 2048
+/* PLL output/desired sampling rate = (32768 * 6000)/88200 */
+#define EVENT_GENERATOR_COUNTER_44100 2228
+/* start / stop the EVENT generator */
+#define EVENT_GENERATOR_START 0x6C
+#define EVENT_GENERATOR_ON 1
+#define EVENT_GENERATOR_OFF 0
+/* selection of the EVENT generator source */
+#define EVENT_SOURCE_SELECTION 0x70
+#define EVENT_SOURCE_DMA 0
+#define EVENT_SOURCE_COUNTER 1
+/* selection of the ABE DMA req line from ATC */
+#define AUDIO_ENGINE_SCHEDULER 0x74
+#define ABE_ATC_DMIC_DMA_REQ 1
+#define ABE_ATC_MCPDMDL_DMA_REQ 2
+#define ABE_ATC_MCPDMUL_DMA_REQ 3
+/* Direction=0 means input from ABE point of view */
+#define ABE_ATC_DIRECTION_IN 0
+/* Direction=1 means output from ABE point of view */
+#define ABE_ATC_DIRECTION_OUT 1
+/*
+ * DMA requests
+ */
+/*Internal connection doesn't connect at ABE boundary */
+#define External_DMA_0 0
+/*Transmit request digital microphone */
+#define DMIC_DMA_REQ 1
+/*Multichannel PDM downlink */
+#define McPDM_DMA_DL 2
+/*Multichannel PDM uplink */
+#define McPDM_DMA_UP 3
+/*MCBSP module 1 - transmit request */
+#define MCBSP1_DMA_TX 4
+/*MCBSP module 1 - receive request */
+#define MCBSP1_DMA_RX 5
+/*MCBSP module 2 - transmit request */
+#define MCBSP2_DMA_TX 6
+/*MCBSP module 2 - receive request */
+#define MCBSP2_DMA_RX 7
+/*MCBSP module 3 - transmit request */
+#define MCBSP3_DMA_TX 8
+/*MCBSP module 3 - receive request */
+#define MCBSP3_DMA_RX 9
+/*SLIMBUS module 1 - transmit request channel 0 */
+#define SLIMBUS1_DMA_TX0 10
+/*SLIMBUS module 1 - transmit request channel 1 */
+#define SLIMBUS1_DMA_TX1 11
+/*SLIMBUS module 1 - transmit request channel 2 */
+#define SLIMBUS1_DMA_TX2 12
+/*SLIMBUS module 1 - transmit request channel 3 */
+#define SLIMBUS1_DMA_TX3 13
+/*SLIMBUS module 1 - transmit request channel 4 */
+#define SLIMBUS1_DMA_TX4 14
+/*SLIMBUS module 1 - transmit request channel 5 */
+#define SLIMBUS1_DMA_TX5 15
+/*SLIMBUS module 1 - transmit request channel 6 */
+#define SLIMBUS1_DMA_TX6 16
+/*SLIMBUS module 1 - transmit request channel 7 */
+#define SLIMBUS1_DMA_TX7 17
+/*SLIMBUS module 1 - receive request channel 0 */
+#define SLIMBUS1_DMA_RX0 18
+/*SLIMBUS module 1 - receive request channel 1 */
+#define SLIMBUS1_DMA_RX1 19
+/*SLIMBUS module 1 - receive request channel 2 */
+#define SLIMBUS1_DMA_RX2 20
+/*SLIMBUS module 1 - receive request channel 3 */
+#define SLIMBUS1_DMA_RX3 21
+/*SLIMBUS module 1 - receive request channel 4 */
+#define SLIMBUS1_DMA_RX4 22
+/*SLIMBUS module 1 - receive request channel 5 */
+#define SLIMBUS1_DMA_RX5 23
+/*SLIMBUS module 1 - receive request channel 6 */
+#define SLIMBUS1_DMA_RX6 24
+/*SLIMBUS module 1 - receive request channel 7 */
+#define SLIMBUS1_DMA_RX7 25
+/*McASP - Data transmit DMA request line */
+#define McASP1_AXEVT 26
+/*McASP - Data receive DMA request line */
+#define McASP1_AREVT 29
+/*DUMMY FIFO @@@ */
+#define _DUMMY_FIFO_ 30
+/*DMA of the Circular buffer peripheral 0 */
+#define CBPr_DMA_RTX0 32
+/*DMA of the Circular buffer peripheral 1 */
+#define CBPr_DMA_RTX1 33
+/*DMA of the Circular buffer peripheral 2 */
+#define CBPr_DMA_RTX2 34
+/*DMA of the Circular buffer peripheral 3 */
+#define CBPr_DMA_RTX3 35
+/*DMA of the Circular buffer peripheral 4 */
+#define CBPr_DMA_RTX4 36
+/*DMA of the Circular buffer peripheral 5 */
+#define CBPr_DMA_RTX5 37
+/*DMA of the Circular buffer peripheral 6 */
+#define CBPr_DMA_RTX6 38
+/*DMA of the Circular buffer peripheral 7 */
+#define CBPr_DMA_RTX7 39
+/*
+ * ATC DESCRIPTORS - DESTINATIONS
+ */
+#define DEST_DMEM_access 0x00
+#define DEST_MCBSP1_ TX 0x01
+#define DEST_MCBSP2_ TX 0x02
+#define DEST_MCBSP3_TX 0x03
+#define DEST_SLIMBUS1_TX0 0x04
+#define DEST_SLIMBUS1_TX1 0x05
+#define DEST_SLIMBUS1_TX2 0x06
+#define DEST_SLIMBUS1_TX3 0x07
+#define DEST_SLIMBUS1_TX4 0x08
+#define DEST_SLIMBUS1_TX5 0x09
+#define DEST_SLIMBUS1_TX6 0x0A
+#define DEST_SLIMBUS1_TX7 0x0B
+#define DEST_MCPDM_DL 0x0C
+#define DEST_MCASP_TX0 0x0D
+#define DEST_MCASP_TX1 0x0E
+#define DEST_MCASP_TX2 0x0F
+#define DEST_MCASP_TX3 0x10
+#define DEST_EXTPORT0 0x11
+#define DEST_EXTPORT1 0x12
+#define DEST_EXTPORT2 0x13
+#define DEST_EXTPORT3 0x14
+#define DEST_MCPDM_ON 0x15
+#define DEST_CBP_CBPr 0x3F
+/*
+ * ATC DESCRIPTORS - SOURCES
+ */
+#define SRC_DMEM_access 0x0
+#define SRC_MCBSP1_ RX 0x01
+#define SRC_MCBSP2_RX 0x02
+#define SRC_MCBSP3_RX 0x03
+#define SRC_SLIMBUS1_RX0 0x04
+#define SRC_SLIMBUS1_RX1 0x05
+#define SRC_SLIMBUS1_RX2 0x06
+#define SRC_SLIMBUS1_RX3 0x07
+#define SRC_SLIMBUS1_RX4 0x08
+#define SRC_SLIMBUS1_RX5 0x09
+#define SRC_SLIMBUS1_RX6 0x0A
+#define SRC_SLIMBUS1_RX7 0x0B
+#define SRC_DMIC_UP 0x0C
+#define SRC_MCPDM_UP 0x0D
+#define SRC_MCASP_RX0 0x0E
+#define SRC_MCASP_RX1 0x0F
+#define SRC_MCASP_RX2 0x10
+#define SRC_MCASP_RX3 0x11
+#define SRC_CBP_CBPr 0x3F
+#endif/* _ABE_EXT_H_ */
diff --git a/sound/soc/omap/abe/abe_firmware.c b/sound/soc/omap/abe/abe_firmware.c
new file mode 100644
index 00000000000..061afac3605
--- /dev/null
+++ b/sound/soc/omap/abe/abe_firmware.c
@@ -0,0 +1,24119 @@
+0x00009060, /* VERSION NUMBER */
+0x00002000, /* PMEM LENGTH IN BYTES */
+0x000013E0, /* CMEM LENGTH IN BYTES */
+0x00010000, /* DMEM LENGTH IN BYTES */
+0x000044E8, /* SMEM LENGTH IN BYTES */
+0x1600200f,
+0x0a000670,
+0x08200000,
+0x08200000,
+0x07800000,
+0x1602d1ce,
+0x014000e0,
+0x014000e1,
+0x014000e2,
+0x014000e3,
+0x014000e4,
+0x014000e5,
+0x014000e6,
+0x014000e7,
+0x014000e8,
+0x014000e9,
+0x014000ea,
+0x014000eb,
+0x014000ec,
+0x014000ed,
+0x014000ef,
+0x014000ef,
+0x144000e4,
+0x9e000000,
+0x0a200c40,
+0x9e000040,
+0x0a200c40,
+0x9e000080,
+0x0a200c40,
+0x9e0000c0,
+0x0a200c40,
+0x9e080000,
+0x0a200c40,
+0x9e080100,
+0x0a200c40,
+0x9e080200,
+0x0a200c40,
+0x9e080300,
+0x0a200c40,
+0x9e080400,
+0x0a200c40,
+0x9e080500,
+0x0a200c40,
+0x9e080600,
+0x0a200c40,
+0x9e080700,
+0x0a200c40,
+0x9c050800,
+0x0a200c40,
+0x16000010,
+0x16000001,
+0x17000102,
+0x01400042,
+0x17800103,
+0x01400043,
+0x98020000,
+0x9d0c8118,
+0x07800000,
+0x9f16001a,
+0x9f12021a,
+0x9f12031a,
+0x9f12051a,
+0x98800380,
+0x9d0c8118,
+0x08200000,
+0x9d0c8118,
+0x07800000,
+0x9f15001a,
+0x9f11041a,
+0x98800410,
+0x9d0c8118,
+0x08200000,
+0x400002c0,
+0x048002ff,
+0x000000c5,
+0x000004c6,
+0x9c028000,
+0x400006c7,
+0x12000155,
+0x013ffefe,
+0xc00008c4,
+0x1e080000,
+0x020005de,
+0x00000ac3,
+0xdc02b160,
+0x04c3ff2d,
+0xdc01ba70,
+0x128002dd,
+0xdc02a440,
+0x048fffdd,
+0x9c061830,
+0x0b200000,
+0x003ffefe,
+0x000002c4,
+0x400004c5,
+0x048ffeff,
+0x000006c6,
+0x000008c7,
+0x9d02a040,
+0x9d02a950,
+0x9d01b260,
+0x9d02bc70,
+0x08200000,
+0x1602c7c6,
+0x00000068,
+0x16003fc5,
+0x01000058,
+0x1602c88a,
+0x000000a9,
+0x16003fc6,
+0x00000068,
+0x0400089b,
+0x4000009c,
+0x1602c80e,
+0x410000ec,
+0x0600000c,
+0x1600274d,
+0x0a800870,
+0x1602e903,
+0x00000030,
+0x00000231,
+0x00000435,
+0x04800211,
+0x04400511,
+0x1602c944,
+0x0000004e,
+0x0300010e,
+0x04800211,
+0x04400511,
+0x0300010c,
+0x04800211,
+0x04400511,
+0x03000109,
+0x01000231,
+0x0a200480,
+0x04800299,
+0x410000a9,
+0x05c00b90,
+0x4ac00700,
+0x04a01085,
+0x1602c8c4,
+0x40000047,
+0x1602c94e,
+0x04200599,
+0x400000e1,
+0x04800177,
+0x010000a9,
+0x41000047,
+0x04a00111,
+0x410000e1,
+0x06000001,
+0x4aa00a50,
+0x1602c90d,
+0x400000d6,
+0x16022e89,
+0x400002d7,
+0x04800166,
+0x410000a9,
+0x04900077,
+0x010000d6,
+0x010002d7,
+0x1602c7c6,
+0x00000068,
+0x16003fc5,
+0x01000058,
+0x1600c005,
+0x1602d141,
+0x16000002,
+0x40000011,
+0x1602d100,
+0x9e0e0550,
+0xdd140530,
+0x160ffff4,
+0x41000002,
+0x06000001,
+0x08400000,
+0x01000004,
+0x9d140550,
+0x0a8006b0,
+0x0a000a50,
+0x048006ff,
+0x013ffafb,
+0x013ffcfc,
+0x413ffefe,
+0x04a0020b,
+0x004002bc,
+0x0600000c,
+0x1600274d,
+0x0a800bf0,
+0x0a200480,
+0x0a000b90,
+0x003ffefe,
+0x003ffcfc,
+0x003ffafb,
+0x048ffaff,
+0x08200000,
+0x07800000,
+0x01400040,
+0x01400041,
+0x01400042,
+0x01400043,
+0x08200000,
+0x16000494,
+0x160004a5,
+0x160004b6,
+0x16000007,
+0x9c032040,
+0x9c032950,
+0x9c033260,
+0x9e0f0070,
+0x9e0f0170,
+0x9e0f0270,
+0x9d032040,
+0x9d032950,
+0x9d033260,
+0x08200000,
+0x9f158048,
+0x07800000,
+0x07800000,
+0x9d088118,
+0x98800d80,
+0x08200000,
+0x9f158048,
+0x9f040040,
+0x07800000,
+0x9f03fc10,
+0x07800000,
+0x07800000,
+0x07800000,
+0x9d188148,
+0x98800de0,
+0x08200000,
+0x9f158048,
+0x07800000,
+0x07800000,
+0x9d188148,
+0x9d188108,
+0x98800e80,
+0x08200000,
+0x9f158048,
+0x07800000,
+0x07800000,
+0x9d0e0040,
+0x07800000,
+0x07800000,
+0x9d1e8148,
+0x9d1e8108,
+0x98800ef0,
+0x08200000,
+0x9f158018,
+0x9f040010,
+0x07800000,
+0x9f03fc10,
+0x07800000,
+0x07800000,
+0x07800000,
+0x9d0e0010,
+0x07800000,
+0x07800000,
+0x9d1e8108,
+0x98800f90,
+0x08200000,
+0x9c080048,
+0x9f1d0010,
+0x07800000,
+0x07800000,
+0x9d0c8118,
+0x98801060,
+0x08200000,
+0x9c180028,
+0x9f1d0010,
+0x07800000,
+0x07800000,
+0x9d0c8108,
+0x988010d0,
+0x08200000,
+0x9c180068,
+0x9c180028,
+0x9f1d0010,
+0x07800000,
+0x07800000,
+0x9d0c8148,
+0x98801140,
+0x08200000,
+0x9c1e0048,
+0x9c1e0008,
+0x9f1d0010,
+0x07800000,
+0x07800000,
+0x9d0c8148,
+0x988011c0,
+0x08200000,
+0x9c1e0008,
+0x9f1d0010,
+0x07800000,
+0x07800000,
+0x9d0c8108,
+0x98801240,
+0x08200000,
+0x16000494,
+0x160004a5,
+0x160004b6,
+0x160000bd,
+0x9c032340,
+0x9c032c50,
+0x9c033560,
+0x9c180028,
+0x9c180068,
+0x9f1d0010,
+0x9c1800a8,
+0x9c1800e8,
+0x9f1d00b0,
+0x07800000,
+0x9d0c8318,
+0x9d0c84b8,
+0x9c180028,
+0x9c180068,
+0x9f1d0010,
+0x07800000,
+0x07800000,
+0x9d0c8518,
+0x98801320,
+0x9d032340,
+0x9d032c50,
+0x9d033560,
+0x08200000,
+0x160004f4,
+0x16000505,
+0x16000516,
+0x9c03a440,
+0x9c03ad50,
+0x9c03b660,
+0x160000bd,
+0x9f158418,
+0x9f1585b8,
+0x07800000,
+0x9d188108,
+0x9d188148,
+0x9d188188,
+0x9c0c0618,
+0x07800000,
+0x9d1881c8,
+0x9d188108,
+0x9d188148,
+0x988014d0,
+0x9d032440,
+0x9d032d50,
+0x9d033660,
+0x08200000,
+0x1600000d,
+0x9e0f00d0,
+0x00800e0d,
+0x9f158038,
+0x07800000,
+0x04a002dd,
+0x9d188108,
+0x9f158038,
+0x07800000,
+0x98801630,
+0x9d188108,
+0x08200000,
+0x9e088100,
+0x07800000,
+0x07800000,
+0x12800277,
+0x04c0ff77,
+0x04a00174,
+0x12800266,
+0x04c0ff66,
+0x04000645,
+0x060ffff4,
+0x17000454,
+0x12000244,
+0x9e0f0140,
+0x07800000,
+0x07800000,
+0x9c0c0118,
+0x07800000,
+0x07800000,
+0x9d0c8118,
+0x988017b0,
+0x08200000,
+0x08200000,
+0x08200000,
+0x08200000,
+0x9c038600,
+0x07800000,
+0x07800000,
+0x9c180770,
+0xdc100348,
+0x160fff05,
+0x9f000810,
+0x9f118412,
+0x9f001010,
+0x9f002810,
+0x9c0c00b8,
+0x160ffd80,
+0x9d0c8410,
+0x9f1d8012,
+0x9f001810,
+0x9f0400d0,
+0x9c0c0210,
+0x16000204,
+0xdd0e00b0,
+0x16000005,
+0x9f1d80b2,
+0x9f0000b0,
+0x9f0020b0,
+0x9f0400d0,
+0x05800560,
+0x0a8019d0,
+0x9c0c0510,
+0x0a0019e0,
+0x9c0c0618,
+0x16000014,
+0x9d0c81e8,
+0x9d0c8148,
+0x0a801a50,
+0x9c0c05b0,
+0x9c0c0510,
+0x0a001a70,
+0x9c0c06b8,
+0x9c0c0618,
+0x07800000,
+0x9d0c81e8,
+0x9d0c8148,
+0x98801850,
+0x9d180750,
+0x08200000,
+0x9d019220,
+0x048002ff,
+0x14400004,
+0x413ffefe,
+0x16000040,
+0x9c010910,
+0x0a202e80,
+0x14400040,
+0x9c030810,
+0x16000171,
+0x9c009f30,
+0x9c019220,
+0x0a202980,
+0x9c009830,
+0x003ffefe,
+0x048ffeff,
+0x08200000,
+0x40000024,
+0x048002ff,
+0x41000224,
+0x16000005,
+0x413ffefe,
+0x04000400,
+0x9e0f0150,
+0x01000025,
+0x0a201d80,
+0x403ffefe,
+0x16000007,
+0x9e0f0170,
+0x048ffeff,
+0x08200000,
+0x048002ff,
+0x413ffefe,
+0x16000005,
+0x01000025,
+0x0a201d80,
+0x40000024,
+0x16000005,
+0x403ffefe,
+0x04200454,
+0x41000224,
+0x048ffeff,
+0x08200000,
+0x048008ff,
+0x413ff8f8,
+0x1440000d,
+0x9c038e10,
+0x413ffaf9,
+0x04a001dd,
+0x413ffcfa,
+0x16000001,
+0x413ffefb,
+0x160000f0,
+0x9c100400,
+0x9c100480,
+0x9c1d06c4,
+0x9f085030,
+0x9c180674,
+0x9c180650,
+0x058001a0,
+0x0aa02280,
+0x04800144,
+0x04400044,
+0x05800040,
+0x0aa01fc0,
+0x05800160,
+0x0ac01f60,
+0x9e090000,
+0x07800000,
+0x07800000,
+0x9e0d0500,
+0x9d040508,
+0x0a002150,
+0x9d040008,
+0x9e090000,
+0x07800000,
+0x9d040008,
+0x9e0d0500,
+0x0a002150,
+0x9d040008,
+0x9e090000,
+0x07800000,
+0x07800000,
+0x9e0d0500,
+0x1280010a,
+0x048001a9,
+0x05800940,
+0x0aa02150,
+0x05800160,
+0x40000628,
+0x160ffff9,
+0x0ac020e0,
+0x05800180,
+0x0ae02150,
+0x160ffff6,
+0x160ffff7,
+0x0a002120,
+0x05800810,
+0x0ae02150,
+0x16000016,
+0x16000007,
+0x9d044690,
+0x04a00144,
+0x9d180674,
+0x05800160,
+0x9d180654,
+0x0ac021c0,
+0x0420040a,
+0x04a001ab,
+0x4a0021f0,
+0x044000bb,
+0x0480014b,
+0x044000bb,
+0x1440004a,
+0x120001aa,
+0x42000a38,
+0x120001bb,
+0x42000b39,
+0x12000288,
+0x12000299,
+0x9e0e8280,
+0xca002390,
+0x1e0e8390,
+0xdd040604,
+0x05800160,
+0x0ac02330,
+0x9d040008,
+0x9e090000,
+0x07800000,
+0x05800040,
+0x9e0d0500,
+0x0aa02390,
+0x9d040508,
+0x0a002390,
+0x9e090000,
+0x05800040,
+0x9d040008,
+0x9e0d0500,
+0x0a802390,
+0x9d040508,
+0x9c1d06c4,
+0xdc1d0644,
+0x1f0400b0,
+0x9c100700,
+0xdc1d06c4,
+0x1f040010,
+0x9d108480,
+0x9f0940b0,
+0x9d108700,
+0x00000cc9,
+0x06000008,
+0x0aa02590,
+0xdc1d0684,
+0x14400005,
+0xdc1d0604,
+0x160fff8a,
+0x04a00255,
+0xdd108480,
+0x16000017,
+0xdd108700,
+0x160ffff8,
+0x05800540,
+0x0aa02550,
+0x05800160,
+0x0ac02540,
+0x01000027,
+0x0a002550,
+0x01000028,
+0x9e088000,
+0xa0054dba,
+0xa005c81a,
+0x0a002620,
+0x9e088000,
+0xa0054dba,
+0xa005c81a,
+0x160fffaa,
+0x9f1f80b0,
+0x9f1e0010,
+0x9f040020,
+0x9f040070,
+0x9f020810,
+0x9d0446a0,
+0x9e0f0070,
+0x9d0c8118,
+0x98801e20,
+0x003ffefb,
+0x003ffcfa,
+0x003ffaf9,
+0x003ff8f8,
+0x048ff8ff,
+0x08200000,
+0x9c0c0018,
+0x9f0b0010,
+0x04a001dd,
+0x07800000,
+0x9d0c8318,
+0x07800000,
+0xa00602ba,
+0x9c0c0018,
+0x9f0b0010,
+0x9d0c82b8,
+0x07800000,
+0x9d0c8318,
+0x98802720,
+0x07800000,
+0xa00602ba,
+0x9c0c0118,
+0x16000015,
+0x9d0c81b8,
+0x9d0c82b8,
+0x9f092010,
+0x9f0920b0,
+0x9c1d05c0,
+0x9f0930c0,
+0x9c1d0548,
+0x9f093860,
+0x06000006,
+0x0aa028a0,
+0x06000017,
+0x0aa028a0,
+0x07800000,
+0x9c0c0118,
+0x9c0c01b0,
+0x9f082010,
+0x9f0820b0,
+0x9c1d05c0,
+0x9f0830c0,
+0x9c1d0548,
+0x9f083860,
+0x06000006,
+0x0aa02970,
+0x06000017,
+0x0aa02970,
+0x07800000,
+0x08200000,
+0x9c0c0018,
+0x1440001d,
+0x04a001dd,
+0x9d0c8318,
+0x07800000,
+0x9c0c0018,
+0xa00602ba,
+0x07800000,
+0x9d0c8318,
+0x9d0c81b8,
+0x9d0c02b8,
+0x988029d0,
+0x07800000,
+0xa00602ba,
+0x07800000,
+0x07800000,
+0x9d0c81b8,
+0x9d0c82b8,
+0x08200000,
+0x9c0c0018,
+0x160000ad,
+0x07800000,
+0x9d0c8318,
+0x07800000,
+0x9c0c0018,
+0xa00602ba,
+0x07800000,
+0x9d0c8318,
+0x9d0c81b8,
+0x9d0c02b8,
+0x07800000,
+0x9c0c0018,
+0xa00602ba,
+0x07800000,
+0x9d0c8318,
+0x9d0c02b8,
+0x98802b00,
+0x9c0c0018,
+0xa00602ba,
+0x07800000,
+0x9d0c8318,
+0x9d0c81b8,
+0x9d0c02b8,
+0x07800000,
+0xa00602ba,
+0x07800000,
+0x07800000,
+0x9d0c02b8,
+0x08200000,
+0x9c0c0038,
+0x1440001d,
+0x04a001dd,
+0x9d0c8338,
+0x07800000,
+0xa00602ba,
+0xa006821a,
+0x9c0c0038,
+0x07800000,
+0x9d0c8298,
+0x9d0c8338,
+0x9d0c8198,
+0x98802ce0,
+0x07800000,
+0xa00602ba,
+0xa006821a,
+0x07800000,
+0x07800000,
+0x9d0c8298,
+0x9d0c8198,
+0x08200000,
+0xdc0c0018,
+0x04a00201,
+0x04a001dd,
+0xdd040008,
+0x06000001,
+0x04a00111,
+0x0aa02e00,
+0x9d0c8118,
+0x98802de0,
+0x08200000,
+0x9c0c02b0,
+0x9c0c0018,
+0x04a00205,
+0x07800000,
+0x9d0c8118,
+0xdd0c81b8,
+0x06000005,
+0x04a00155,
+0x0aa02ed0,
+0x98802e90,
+0x08200000,
+0x9c0c0018,
+0x9e0e0620,
+0x1600004d,
+0x9d0c8318,
+0x07800000,
+0x9c0c0610,
+0xa00602ba,
+0x07800000,
+0x9d0c8318,
+0x9d0c81b8,
+0x9d0c02b8,
+0x07800000,
+0x9c0c0018,
+0xa00602ba,
+0x07800000,
+0x9d0c8318,
+0x9d0c81b8,
+0x9d0c02b8,
+0x98802f80,
+0x9c0c0610,
+0xa00602ba,
+0x07800000,
+0x9d0c8318,
+0x9d0c81b8,
+0x9d0c02b8,
+0x07800000,
+0xa00602ba,
+0x07800000,
+0x07800000,
+0x9d0c81b8,
+0x9d0c82b8,
+0x08200000,
+0x9f160028,
+0x9f168298,
+0x04a001dd,
+0x07800000,
+0x9d0c8128,
+0x07800000,
+0x9f160028,
+0x9f168298,
+0x98803170,
+0x9d0c8128,
+0x08200000,
+0x9f160020,
+0x9f168098,
+0x07800000,
+0x9d0c8108,
+0x9d0c8258,
+0x988031e0,
+0x08200000,
+0x9f160010,
+0x9f168068,
+0x07800000,
+0x07800000,
+0x9d0c8128,
+0x98803250,
+0x08200000,
+0x9d008810,
+0x1280020d,
+0x07800000,
+0x9c038810,
+0x9e0e0620,
+0x04a001dd,
+0x9f16801a,
+0x9f12011a,
+0x9f039810,
+0x9f026810,
+0x9f118610,
+0x9f1680ba,
+0x9f1201ba,
+0x9f0398b0,
+0x9f0268b0,
+0x9f1186b0,
+0x9d0c8718,
+0x9d108248,
+0x9d108208,
+0x9d0c87b8,
+0x9d1082c8,
+0x9d108288,
+0x98803320,
+0x08200000,
+0x00000003,
+0x00000205,
+0x1440001d,
+0x9c039830,
+0x9c03aa50,
+0x07800000,
+0x9c0c0018,
+0x9c0c02b8,
+0x07800000,
+0x07800000,
+0x9d0c8128,
+0x988034a0,
+0x08200000,
+0x010002fe,
+0x00801605,
+0x16002a63,
+0x12000155,
+0x0200035e,
+0x0b200000,
+0x00800405,
+0x16002a63,
+0x12000155,
+0x0200035e,
+0x0b200000,
+0x00801705,
+0x16002a63,
+0x12000155,
+0x0200035e,
+0x0b200000,
+0x000002fe,
+0x07800000,
+0x08200000,
+0x16000181,
+0x04000101,
+0x00800b03,
+0x00000212,
+0x00000017,
+0x9e0e0420,
+0x00000416,
+0xdc180404,
+0x06000003,
+0x9c180480,
+0x0aa03a10,
+0x9c052b20,
+0x9c042820,
+0x9c023970,
+0x07800000,
+0x07800000,
+0x9d01b060,
+0x16000005,
+0x160fffd6,
+0x00800e04,
+0x00800503,
+0x05800420,
+0x0ae03900,
+0x160fffe6,
+0x04000344,
+0x05800420,
+0x0ae039f0,
+0x160ffff6,
+0x04000344,
+0x05800420,
+0x0ae039f0,
+0x16000006,
+0x04000344,
+0x05800420,
+0x0ae039f0,
+0x16000016,
+0x04000344,
+0x05800420,
+0x0ae039f0,
+0x16000026,
+0x04000344,
+0x05800420,
+0x0ae039f0,
+0x16000036,
+0x010000f6,
+0x12000132,
+0x04000233,
+0x9e088300,
+0x40800e02,
+0x16000005,
+0x04000233,
+0x12000233,
+0x04200377,
+0x05800570,
+0x16001e02,
+0x17800523,
+0x04000377,
+0x9e0f0070,
+0x000000f6,
+0x01000606,
+0x0a003e10,
+0x9c042b20,
+0x9c052920,
+0x9c023870,
+0x07800000,
+0x07800000,
+0x9d00b360,
+0x16000004,
+0x16000005,
+0x160fffb6,
+0x00800503,
+0x05800420,
+0x0ae03d20,
+0x160fffc6,
+0x04000344,
+0x05800420,
+0x0ae03e00,
+0x160fffd6,
+0x04000344,
+0x05800420,
+0x0ae03e00,
+0x160fffe6,
+0x04000344,
+0x05800420,
+0x0ae03e00,
+0x160ffff6,
+0x04000344,
+0x05800420,
+0x0ae03e00,
+0x16000006,
+0x04000344,
+0x05800420,
+0x0ae03e00,
+0x16000016,
+0x04000344,
+0x05800420,
+0x0ae03e00,
+0x16000026,
+0x04000344,
+0x05800420,
+0x0ae03e00,
+0x16000036,
+0x04000344,
+0x05800420,
+0x0ae03e00,
+0x16000046,
+0x04000344,
+0x05800420,
+0x0ae03e00,
+0x16000056,
+0x010000f6,
+0x12000232,
+0x04000233,
+0x9e088300,
+0x16000005,
+0x12000233,
+0x04000377,
+0x04a1e077,
+0x05800570,
+0x16001e02,
+0x17800523,
+0x04000377,
+0x9e0f0170,
+0x000000f6,
+0x01000606,
+0x00800715,
+0x16002a66,
+0x410004fe,
+0x12000155,
+0x00000202,
+0x00800d04,
+0x0200056e,
+0x16013bc6,
+0x16013c07,
+0x0400042d,
+0x04a001dd,
+0x9e0e0260,
+0x9e0e0370,
+0x0b200000,
+0x00000806,
+0x000004fe,
+0x0000021d,
+0x9e0e0560,
+0x00800b05,
+0x408007d7,
+0x06000005,
+0x40800f02,
+0x04c07f77,
+0x4a804040,
+0x04500273,
+0x00800a02,
+0x9e088100,
+0x00000011,
+0x418007d3,
+0x16000003,
+0x12800277,
+0x018003d7,
+0x9d140530,
+0x9d038810,
+0x08200000,
+0x00800a02,
+0x9e088000,
+0x00000011,
+0x418007d3,
+0x16000003,
+0x12800277,
+0x018000d7,
+0x9d140530,
+0x9d038910,
+0x08200000,
+0x00001807,
+0x00801e02,
+0x16000003,
+0x9c01b970,
+0x06000082,
+0x17000233,
+0x9e088100,
+0x07800000,
+0x12000c33,
+0x04c3ff66,
+0x04500366,
+0x07800000,
+0x16000003,
+0x9e0c8100,
+0x1602dc06,
+0x00000064,
+0x1600003d,
+0x04a00122,
+0x9c03a040,
+0x04800266,
+0x9e0f0130,
+0x04800433,
+0x06000002,
+0x9c0c0038,
+0x9c0c0078,
+0x9c0c00b8,
+0x9d0c810c,
+0x9d0c815c,
+0x9d0c81ac,
+0x98804250,
+0x0aa041d0,
+0x9e0f0120,
+0x08200000,
+0x4080070d,
+0x048002ff,
+0x00800203,
+0x00800905,
+0x40000e04,
+0x040003dd,
+0x413ffefe,
+0x06000004,
+0x9c03a950,
+0x4aa043f0,
+0x144000d2,
+0x0a2046b0,
+0x40000e04,
+0x1440002d,
+0x06000004,
+0x0a804530,
+0x05800d40,
+0x0ae04430,
+0x0a204560,
+0x0a0044e0,
+0x042004d2,
+0x1440004d,
+0x0a204560,
+0x0a2046b0,
+0x06000002,
+0x0a8044e0,
+0x1440002d,
+0x00000e04,
+0x05800d40,
+0x0ac04530,
+0x0a204560,
+0x003ffefe,
+0x40800905,
+0x048ffeff,
+0x9d03a950,
+0x08200000,
+0x04a0012d,
+0x0a201690,
+0x0a0044e0,
+0x16013bc6,
+0x40800605,
+0x048002ff,
+0x413ffefe,
+0x144000d3,
+0x16002a6e,
+0x9e0e0260,
+0x12000155,
+0x420005ee,
+0x04a001dd,
+0x0b200000,
+0x9e088000,
+0x403ffefe,
+0x16000006,
+0x40000e05,
+0x048ffeff,
+0x9e0e8040,
+0x9e0f0060,
+0x04200355,
+0x01000e05,
+0x08200000,
+0x40800b0d,
+0x16000246,
+0x40000403,
+0x04c001d7,
+0x06000007,
+0x4a8047a0,
+0x16000017,
+0x00001604,
+0x06000004,
+0x0a8048c0,
+0x40001405,
+0x048001dd,
+0x01000e04,
+0x01000c05,
+0x0a004810,
+0x00001204,
+0x06000004,
+0x0a8048c0,
+0x40001005,
+0x048001dd,
+0x01000e04,
+0x01000c05,
+0x9e0e8050,
+0x41800b0d,
+0x16000005,
+0x40800a04,
+0x05c00630,
+0x0a8048b0,
+0x12000233,
+0x9e0e0530,
+0x9d140550,
+0x0a0048c0,
+0x01800017,
+0x08200000,
+0x048008ff,
+0x413ff8f8,
+0x1440001d,
+0x013ffaf9,
+0x413ffcfa,
+0x1602c909,
+0x413ffefb,
+0x1601fe02,
+0x00000095,
+0x00000296,
+0x9c018201,
+0x01000025,
+0x41400226,
+0x16020603,
+0x04800122,
+0x9e088200,
+0x9e090300,
+0x07800000,
+0x12800277,
+0x128002bb,
+0x01c00127,
+0x01c0012b,
+0x9c018201,
+0x988049c0,
+0x04800633,
+0x1440001d,
+0x00000034,
+0x04802833,
+0x01c00124,
+0x98804a70,
+0x1602e8ca,
+0x16002102,
+0x408000a4,
+0x1602ebcd,
+0x408001a5,
+0x16000007,
+0x9e0e0220,
+0x408002a8,
+0x16000806,
+0x408003a9,
+0x12000155,
+0x410000a7,
+0x04500544,
+0x9d140270,
+0x408000d5,
+0x12000288,
+0x410002a7,
+0x04500844,
+0x408001d8,
+0x12000399,
+0x408002d6,
+0x04500944,
+0x410000d7,
+0x1602ec0a,
+0x408003d9,
+0x12000455,
+0x410002d7,
+0x04500544,
+0x408000a5,
+0x12000588,
+0x408001a2,
+0x04500844,
+0x408002a8,
+0x12000666,
+0x410000a7,
+0x04500644,
+0x408003a6,
+0x12000799,
+0x410002a7,
+0x04500944,
+0x12000855,
+0x04500544,
+0x1602db8a,
+0x1602dbcb,
+0x12000922,
+0x04500244,
+0x12000a88,
+0x04500844,
+0x400000a8,
+0x12000b66,
+0x400000b9,
+0x04500644,
+0x04a00188,
+0x04a00199,
+0x16000005,
+0x16000006,
+0x06000008,
+0x0aa04e70,
+0x16000015,
+0x000002a8,
+0x06000009,
+0x0aa04eb0,
+0x16000016,
+0x000002b9,
+0x1602cf42,
+0x410000a8,
+0x12000166,
+0x410000b9,
+0x04500655,
+0x40800021,
+0x1602c90d,
+0x41800027,
+0x06000004,
+0x0aa04fa0,
+0x06000005,
+0x0aa05020,
+0x06000001,
+0x0aa050b0,
+0x0a0051a0,
+0x160000a8,
+0x400000d6,
+0x12000c88,
+0x04500487,
+0x07800000,
+0x06000005,
+0x9d180078,
+0x0a805090,
+0x160000c8,
+0x400000d6,
+0x12000c88,
+0x04500587,
+0x07800000,
+0x07800000,
+0x9d180078,
+0x06000001,
+0x0a805120,
+0x160000d8,
+0x400000d6,
+0x12000c88,
+0x04500187,
+0x07800000,
+0x07800000,
+0x9d180078,
+0x16000903,
+0x16000f99,
+0x16000016,
+0x9e0e0530,
+0x16000007,
+0x9d03c890,
+0x07800000,
+0x9d140570,
+0x1602c988,
+0x16000013,
+0x00000084,
+0x00000280,
+0x1602c942,
+0x06000000,
+0x00000049,
+0x16000005,
+0x0a805240,
+0x04200959,
+0x160ffff6,
+0x05800590,
+0x01000045,
+0x17000353,
+0x17800363,
+0x04800233,
+0x01000023,
+0x1601fe02,
+0x01004a23,
+0x003ffefb,
+0x003ffcfa,
+0x003ffaf9,
+0x003ff8f8,
+0x048ff8ff,
+0x16002202,
+0x9e0e0220,
+0x16000806,
+0x07800000,
+0x07800000,
+0x9d140270,
+0x08200000,
+0x048008ff,
+0x413ff8f8,
+0x1601fe02,
+0x013ffaf9,
+0x013ffcfa,
+0x413ffefb,
+0x04803322,
+0x1602e045,
+0x16000ded,
+0x00000454,
+0x00000856,
+0x9c0768d0,
+0x01c00124,
+0x01c00126,
+0x40000087,
+0x16002b89,
+0x0000028d,
+0x40000c54,
+0x12000299,
+0x00000e56,
+0x01c00127,
+0x0180012d,
+0x9e0e0490,
+0x41400224,
+0x16002b98,
+0x41400226,
+0x12000288,
+0x9c100480,
+0x9f03e0b0,
+0x9e0e0580,
+0x9e010080,
+0xdc1005c0,
+0x160005fd,
+0x9f03e0b0,
+0x01400229,
+0x9e0080c0,
+0x0140022a,
+0x9c01ead0,
+0x01400225,
+0x41400226,
+0x16000623,
+0x9e090200,
+0x04800122,
+0x9c029c30,
+0x128002bb,
+0x01c0012b,
+0x160005ad,
+0x9e088400,
+0x07800000,
+0x9c01ead0,
+0x12800277,
+0x01c00127,
+0x9e090200,
+0x16000023,
+0x1600005d,
+0x128002bb,
+0x9c029c30,
+0x01c0012b,
+0x04800122,
+0x9e088400,
+0x9c01ead0,
+0x07800000,
+0x12800277,
+0x9e090200,
+0x07800000,
+0x01c00127,
+0x128002bb,
+0x01c0012b,
+0x04800222,
+0x1602de45,
+0x16000e0d,
+0x00000454,
+0x00000856,
+0x9c0768d0,
+0x01c00124,
+0x01c00126,
+0x40000087,
+0x16002ba9,
+0x0000028d,
+0x40000c54,
+0x12000299,
+0x00000e56,
+0x01c00127,
+0x0180012d,
+0x9e0e0490,
+0x41400224,
+0x16002bb8,
+0x41400226,
+0x12000288,
+0x9c100480,
+0x9f03e0b0,
+0x9e0e0580,
+0x9e010080,
+0xdc1005c0,
+0x1600009d,
+0x9f03e0b0,
+0x01400229,
+0x9e0080c0,
+0x0140022a,
+0x9c01ead0,
+0x01400225,
+0x16000553,
+0x01400226,
+0x9e090200,
+0x9c029c30,
+0x07800000,
+0x128002bb,
+0x9e088400,
+0x01c0022b,
+0x07800000,
+0x12800277,
+0x01c00227,
+0x003ffefb,
+0x003ffcfa,
+0x003ffaf9,
+0x003ff8f8,
+0x048ff8ff,
+0x08200000,
+0x00000004,
+0x00000405,
+0x00000806,
+0x00000c07,
+0x05c00540,
+0x0b800000,
+0x9e0e8040,
+0x9c180034,
+0x07800000,
+0x07800000,
+0x06000033,
+0x9e0e8220,
+0x0aa05c10,
+0x9c1d0004,
+0x9c1d0044,
+0x07800000,
+0x9d0c0210,
+0x0a005cc0,
+0x06000023,
+0x0aa05c70,
+0x9c1d0004,
+0x9d040004,
+0x9d100200,
+0x0a005cc0,
+0x06000043,
+0x0aa05cc0,
+0x9c180024,
+0x9d040004,
+0x9d180200,
+0x04800c44,
+0x05c00740,
+0x17800644,
+0x01000004,
+0x0a005b30,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x07800000,
+0x07800000,
+0x07800000,
+0x08400000,
+0x0a000000,
+0x00000000,
+0x00000000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00151000,
+0x00201000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001001,
+0x00000000,
+0x00001011,
+0x00001011,
+0x00021031,
+0x00041051,
+0x00061071,
+0x00081091,
+0x000a10b1,
+0x000c10d1,
+0x00001001,
+0x00001001,
+0x00001000,
+0x00001000,
+0x00001001,
+0x00001001,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001001,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001041,
+0x00001000,
+0x00000000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001001,
+0x00001001,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001001,
+0x00001001,
+0x00001000,
+0x00001001,
+0x00001001,
+0x00001001,
+0x00001001,
+0x00001000,
+0x00001001,
+0x00001001,
+0x00001001,
+0x00001001,
+0x00001001,
+0x00001001,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00000000,
+0x00000000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00001000,
+0x00001001,
+0x00000001,
+0x00001000,
+0x00002e24,
+0x00001000,
+0x00001001,
+0x00000001,
+0x00001000,
+0x00002e24,
+0x00151000,
+0x00002e24,
+0x00002e24,
+0x00151000,
+0x00001000,
+0x00001001,
+0x00000001,
+0x00001000,
+0x00002e64,
+0x00001000,
+0x00001001,
+0x00001000,
+0x00001000,
+0x00001001,
+0x00001001,
+0x000010c1,
+0x00001000,
+0x000010c1,
+0x00001001,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001051,
+0x00001031,
+0x00001051,
+0x00001021,
+0x00001051,
+0x00001031,
+0x00001051,
+0x00001021,
+0x00001051,
+0x00001031,
+0x00001051,
+0x00001021,
+0x00001051,
+0x00001031,
+0x00001051,
+0x00001021,
+0x00001051,
+0x00001031,
+0x00001051,
+0x00001021,
+0x00151000,
+0x00001000,
+0x00001000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00001071,
+0x00000000,
+0x00001071,
+0x00000000,
+0x00001041,
+0x00001001,
+0x00000000,
+0x00001000,
+0x00001011,
+0x00001001,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00001000,
+0x00001011,
+0x00001001,
+0x00000000,
+0x00001041,
+0x00001041,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001011,
+0x00001001,
+0x00001000,
+0x00001011,
+0x00001001,
+0x00001000,
+0x00001011,
+0x00001001,
+0x00000000,
+0x00001000,
+0x00001011,
+0x00001001,
+0x00000000,
+0x00001000,
+0x00001001,
+0x00001001,
+0x00001041,
+0x00001000,
+0x00001041,
+0x00001001,
+0x00001001,
+0x00001000,
+0x00001051,
+0x00001000,
+0x00001001,
+0x00001051,
+0x00001001,
+0x000000c5,
+0x00001000,
+0x00001001,
+0x00001001,
+0x00001001,
+0x00001001,
+0x0000fff9,
+0x00001000,
+0x00001000,
+0x00000000,
+0x00001000,
+0x00001091,
+0x00001000,
+0x00001000,
+0x00000000,
+0x00000000,
+0x00001091,
+0x00001091,
+0x00001091,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00001000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001001,
+0x00001001,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00001000,
+0x00001001,
+0x00000000,
+0x00011001,
+0x00001000,
+0x00151000,
+0x00001001,
+0x00000001,
+0x00001000,
+0x00002e24,
+0x00002e24,
+0x00001000,
+0x00151000,
+0x00151000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001000,
+0x00001001,
+0x00000001,
+0x00001000,
+0x00002e24,
+0x00002e24,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000008,
+0x00700001,
+0x00700001,
+0x00700001,
+0x00700001,
+0x00700001,
+0x00700001,
+0x00700001,
+0x00700001,
+0x00700001,
+0x00700001,
+0x00700001,
+0x00700001,
+0x00700001,
+0x00700001,
+0x00700001,
+0x00700001,
+0x00700001,
+0x00700001,
+0x00100001,
+0x00100001,
+0x00100001,
+0x00100001,
+0x00100001,
+0x00100001,
+0x00100001,
+0x00100001,
+0x00100001,
+0x00100001,
+0x00100001,
+0x00100001,
+0x00100001,
+0x00100001,
+0x00100001,
+0x00100001,
+0x00100001,
+0x00100001,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00040002,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00fc4793,
+0x000a8b43,
+0x00e7110b,
+0x003411d3,
+0x009d1cfb,
+0x0002b6a8,
+0x00fb8ca8,
+0x0006dac8,
+0x00f610e8,
+0x000d8628,
+0x00eed498,
+0x0013f0e8,
+0x00eb9d08,
+0x000f02e8,
+0x00056260,
+0x00bf42f0,
+0x006a9a5d,
+0x005ed280,
+0x00023c94,
+0x00fb2e83,
+0x000c8ac3,
+0x00e408e3,
+0x0037ceab,
+0x0099fe5b,
+0x0002b430,
+0x00fbb618,
+0x000661c0,
+0x00f71850,
+0x000b9710,
+0x00f220d0,
+0x000eb9d8,
+0x00f37700,
+0x0003c304,
+0x00142c90,
+0x00b09170,
+0x0066c791,
+0x006d23e0,
+0x000208b8,
+0x00fa9443,
+0x000d8413,
+0x00e2e293,
+0x00386703,
+0x009badeb,
+0x000296d8,
+0x00fc0144,
+0x0005c418,
+0x00f83d98,
+0x0009a2c0,
+0x00f53c30,
+0x000a1678,
+0x00fa10a0,
+0x00fadbf0,
+0x001ef5c0,
+0x00a7ab80,
+0x0061b101,
+0x00782010,
+0x000464a8,
+0x00fa1fab,
+0x000e2353,
+0x00e28193,
+0x003770b3,
+0x00a04a0b,
+0x000264f0,
+0x00fc6e8c,
+0x0004f108,
+0x00f9b218,
+0x00073f50,
+0x00f8ea80,
+0x0004be58,
+0x005c1863,
+0x00f141c8,
+0x002a0528,
+0x009fa4a8,
+0x005b6439,
+0x0042ccf5,
+0x0005d8f0,
+0x00f9f08b,
+0x000e2e23,
+0x00e33ce3,
+0x00348833,
+0x00a80de3,
+0x00022008,
+0x00fcf654,
+0x0003fc0c,
+0x00fb4d68,
+0x0004b6b0,
+0x00fcaf74,
+0x00dcf75b,
+0x000875d0,
+0x00e88c00,
+0x00334af8,
+0x009a9170,
+0x0053f3c9,
+0x00498425,
+0x0007d850,
+0x00fa0193,
+0x000db28b,
+0x00e4f083,
+0x0030005b,
+0x00b24bfb,
+0x007356ab,
+0x00fd8f38,
+0x0002f50c,
+0x00fcf624,
+0x00022f7c,
+0x0014e623,
+0x00fa8240,
+0x000ec210,
+0x00e12888,
+0x003a6068,
+0x00989408,
+0x004b98d9,
+0x004fdc61,
+0x000aadb0,
+0x00fa47fb,
+0x000cc843,
+0x00e76cb3,
+0x002a3303,
+0x00be6543,
+0x005c437b,
+0x008ca913,
+0x007977d3,
+0x00a7922b,
+0x00ef1dc3,
+0x0003bf5c,
+0x00f604a8,
+0x00143b08,
+0x00db27e8,
+0x003f50c0,
+0x009968b8,
+0x00427b21,
+0x0055cb8d,
+0x000e5198,
+0x00faba2b,
+0x000b83a3,
+0x00ea894b,
+0x00236a23,
+0x00cbda13,
+0x004398b3,
+0x00b6e5bb,
+0x003575db,
+0x000eee5b,
+0x00fd6ac0,
+0x0006e2f8,
+0x00f20c30,
+0x0018d298,
+0x00d68e40,
+0x00423000,
+0x009cd148,
+0x00716ee8,
+0x005b537d,
+0x0012b270,
+0x00fb4feb,
+0x0009f65b,
+0x00ee2313,
+0x001be763,
+0x00da372b,
+0x002a1533,
+0x00e15813,
+0x00f2fbd3,
+0x007127a3,
+0x00fb4778,
+0x0009ae08,
+0x00eeab88,
+0x001c7728,
+0x00d365f8,
+0x004306e0,
+0x00a2a0d0,
+0x005cd070,
+0x00606a75,
+0x0017d078,
+0x00fc00bb,
+0x0008330b,
+0x00f2141b,
+0x0013f29b,
+0x00e8fcc3,
+0x00108f73,
+0x000aabc3,
+0x00b409ab,
+0x00032d94,
+0x00f961f0,
+0x000c0d48,
+0x00ebf900,
+0x001f1310,
+0x00d1bd70,
+0x0041db98,
+0x00aaa7f0,
+0x004768e0,
+0x0064f695,
+0x001db640,
+0x00fcc40b,
+0x00064cab,
+0x00f635fb,
+0x000bd423,
+0x00f7ab83,
+0x00f7da9b,
+0x00319613,
+0x00fdea24,
+0x00046be0,
+0x00f7c838,
+0x000def88,
+0x00ea0778,
+0x002095b8,
+0x00d19bf0,
+0x003ebd10,
+0x00b4aec0,
+0x00318e40,
+0x0068d739,
+0x002477b8,
+0x00fd9103,
+0x000456bb,
+0x00fa6163,
+0x0003d51b,
+0x0005c47b,
+0x00e0c55b,
+0x0054da23,
+0x00fd2110,
+0x000575e0,
+0x00f68680,
+0x000f46d0,
+0x00e8e4e8,
+0x0020f5c0,
+0x00d2fe70,
+0x0039c7a8,
+0x00c06ee8,
+0x001ba3e0,
+0x006be82d,
+0x002c29d8,
+0x00fe5ef3,
+0x000264b3,
+0x00fe6f83,
+0x00fc3c73,
+0x0012cf0b,
+0x00cc0f3b,
+0x00735b43,
+0x00fc7b10,
+0x00064398,
+0x00f5a608,
+0x001009d8,
+0x00e89830,
+0x002033b8,
+0x00d5d488,
+0x003327e0,
+0x00cd9208,
+0x000617a0,
+0x006e0619,
+0x0034dcb8,
+0x00ff2633,
+0x0000878b,
+0x00023efb,
+0x00f54613,
+0x001e683b,
+0x00ba501b,
+0x00023104,
+0x00fbfc98,
+0x0006cfe8,
+0x00f52c00,
+0x001034f8,
+0x00e92088,
+0x001e5960,
+0x00da0390,
+0x002b1358,
+0x00dbbf58,
+0x00f14c40,
+0x006f129d,
+0x003ea030,
+0x00ffdfeb,
+0x00feceb3,
+0x0005b193,
+0x00ef271b,
+0x00283a63,
+0x00ac06cb,
+0x00027b84,
+0x00fba8d8,
+0x00071778,
+0x00f51a98,
+0x000fc900,
+0x00ea7720,
+0x001b7880,
+0x00df6710,
+0x0021ca50,
+0x00ea95d0,
+0x00dda780,
+0x006ef2a5,
+0x00497dd8,
+0x00000003,
+0x00fd4a6b,
+0x0008a803,
+0x00ea151b,
+0x002ff333,
+0x00a1a463,
+0x0002aad0,
+0x00fb81d8,
+0x00071978,
+0x00f56fc8,
+0x000ecde0,
+0x00ec89f0,
+0x0017b2e0,
+0x00e5c408,
+0x0017aaa0,
+0x00f99118,
+0x00cbaf78,
+0x006d93e5,
+0x005561e0,
+0x00000020,
+0x003fffe0,
+0x00000020,
+0x003fffe0,
+0x00069cf3,
+0x00eda3d3,
+0x00284343,
+0x00b2821b,
+0x000228bc,
+0x00fc4508,
+0x0006a660,
+0x00f19bc0,
+0x007f26c5,
+0x00107398,
+0x00f8cbc0,
+0x0003fef8,
+0x00fdafb8,
+0x00539323,
+0x00d40cc3,
+0x0014740b,
+0x00f855f3,
+0x0001b16b,
+0x000c0373,
+0x00ddec9b,
+0x004b880b,
+0x00fdb6d0,
+0x00041728,
+0x00f8ede8,
+0x000c8b38,
+0x00e57730,
+0x007ca649,
+0x0022b568,
+0x00f146b8,
+0x00081d20,
+0x00fb4da0,
+0x0002a8ac,
+0x00a5ff43,
+0x002a4a93,
+0x00efdbfb,
+0x0003c6eb,
+0x00101e33,
+0x00d13c0b,
+0x0068d11b,
+0x00fcce9c,
+0x0005bc08,
+0x00f61488,
+0x001185c8,
+0x00dbb070,
+0x00788dfd,
+0x00367598,
+0x00e9b5b8,
+0x000c31f8,
+0x00f8f1a0,
+0x00040178,
+0x00fdde98,
+0x0040ab93,
+0x00e6e21b,
+0x0006309b,
+0x0012ea3b,
+0x00c7c91b,
+0x007f746f,
+0x00fc1754,
+0x00070c10,
+0x00f3cc50,
+0x00157878,
+0x00d45408,
+0x0072f70d,
+0x004b56d0,
+0x00e26390,
+0x001012a8,
+0x00f6b500,
+0x00054a20,
+0x00fd2bf0,
+0x0056a233,
+0x00ddc993,
+0x0008d62b,
+0x00147503,
+0x00c1a1c3,
+0x00023c70,
+0x00fb9490,
+0x0007fff0,
+0x00f221f8,
+0x00185148,
+0x00cf5d50,
+0x006c0395,
+0x0060f058,
+0x00db9f08,
+0x00139340,
+0x00f4b188,
+0x00067398,
+0x00fc8844,
+0x006b2573,
+0x00d501e3,
+0x000b96fb,
+0x0014d9d3,
+0x00beae3b,
+0x00025f04,
+0x00fb4790,
+0x00089470,
+0x00f11b68,
+0x001a0988,
+0x00ccb738,
+0x0063ddc5,
+0x0076d0d4,
+0x00d5b880,
+0x001688a8,
+0x00f30060,
+0x00076f18,
+0x00fbfbf8,
+0x007d228f,
+0x00cd04b3,
+0x000e4b13,
+0x00143ecb,
+0x00beb5b3,
+0x000266a0,
+0x00fb2f48,
+0x0008ca48,
+0x00f0b7e8,
+0x001aa578,
+0x00cc3da8,
+0x005ab67d,
+0x004640a1,
+0x00d0ff50,
+0x0018ca30,
+0x00f1b920,
+0x00082ea8,
+0x00fb8f00,
+0x00022e24,
+0x00c650c3,
+0x0010c49b,
+0x0012d1ab,
+0x00c1642b,
+0x0002555c,
+0x00fb48b0,
+0x0008a5d0,
+0x00f0f0a0,
+0x001a3350,
+0x00cdbf38,
+0x0050c415,
+0x0050c415,
+0x00cdbf38,
+0x001a3350,
+0x00f0f0a0,
+0x0008a5d0,
+0x00fb48b0,
+0x0002555c,
+0x00c1642b,
+0x0012d1ab,
+0x0010c49b,
+0x00c650c3,
+0x00022e24,
+0x00fb8f00,
+0x00082ea8,
+0x00f1b920,
+0x0018ca30,
+0x00d0ff50,
+0x004640a1,
+0x005ab67d,
+0x00cc3da8,
+0x001aa578,
+0x00f0b7e8,
+0x0008ca48,
+0x00fb2f48,
+0x000266a0,
+0x00beb5b3,
+0x00143ecb,
+0x000e4b13,
+0x00cd04b3,
+0x007d228f,
+0x00fbfbf8,
+0x00076f18,
+0x00f30060,
+0x001688a8,
+0x00d5b880,
+0x0076d0d4,
+0x0063ddc5,
+0x00ccb738,
+0x001a0988,
+0x00f11b68,
+0x00089470,
+0x00fb4790,
+0x00025f04,
+0x00beae3b,
+0x0014d9d3,
+0x000b96fb,
+0x00d501e3,
+0x006b2573,
+0x00fc8844,
+0x00067398,
+0x00f4b188,
+0x00139340,
+0x00db9f08,
+0x0060f058,
+0x006c0395,
+0x00cf5d50,
+0x00185148,
+0x00f221f8,
+0x0007fff0,
+0x00fb9490,
+0x00023c70,
+0x00c1a1c3,
+0x00147503,
+0x0008d62b,
+0x00ddc993,
+0x0056a233,
+0x00fd2bf0,
+0x00054a20,
+0x00f6b500,
+0x001012a8,
+0x00e26390,
+0x004b56d0,
+0x0072f70d,
+0x00d45408,
+0x00157878,
+0x00f3cc50,
+0x00070c10,
+0x00fc1754,
+0x007f746f,
+0x00c7c91b,
+0x0012ea3b,
+0x0006309b,
+0x00e6e21b,
+0x0040ab93,
+0x00fdde98,
+0x00040178,
+0x00f8f1a0,
+0x000c31f8,
+0x00e9b5b8,
+0x00367598,
+0x00788dfd,
+0x00dbb070,
+0x001185c8,
+0x00f61488,
+0x0005bc08,
+0x00fcce9c,
+0x0068d11b,
+0x00d13c0b,
+0x00101e33,
+0x0003c6eb,
+0x00efdbfb,
+0x002a4a93,
+0x00a5ff43,
+0x0002a8ac,
+0x00fb4da0,
+0x00081d20,
+0x00f146b8,
+0x0022b568,
+0x007ca649,
+0x00e57730,
+0x000c8b38,
+0x00f8ede8,
+0x00041728,
+0x00fdb6d0,
+0x004b880b,
+0x00ddec9b,
+0x000c0373,
+0x0001b16b,
+0x00f855f3,
+0x0014740b,
+0x00d40cc3,
+0x00539323,
+0x00fdafb8,
+0x0003fef8,
+0x00f8cbc0,
+0x00107398,
+0x007f26c5,
+0x00f19bc0,
+0x0006a660,
+0x00fc4508,
+0x000228bc,
+0x00b2821b,
+0x00284343,
+0x00eda3d3,
+0x00069cf3,
+0x00000003,
+0x00000003,
+0x00000003,
+0x00000003,
+0x00000003,
+0x00000003,
+0x00000003,
+0x00000003,
+0x00000003,
+0x00040002,
+0x00000003,
+0x00000003,
+0x00000003,
+0x00000003,
+0x00000003,
+0x00000003,
+0x00000003,
+0x00000003,
+0x00000020,
+0x003fffe0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00040002,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00040002,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00040002,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x000695c4,
+0x007cdb3b,
+0x000870d8,
+0x000870d8,
+0x007cdb3b,
+0x000695c4,
+0x004470ec,
+0x00fa825a,
+0x000c7322,
+0x00f02316,
+0x000b4d9e,
+0x0013c14c,
+0x0005da48,
+0x00195288,
+0x00195288,
+0x0005da48,
+0x0013c14c,
+0x004470ec,
+0x00fa825a,
+0x000c7322,
+0x00f02316,
+0x000b4d9e,
+0x007de295,
+0x00f821da,
+0x007de295,
+0x008431e5,
+0x0007dde2,
+0x000271f8,
+0x00fb6e08,
+0x0002d334,
+0x0002d334,
+0x00fb6e08,
+0x000271f8,
+0x00421c2d,
+0x00f4e40e,
+0x00188dd6,
+0x00e410d6,
+0x001066c6,
+0x000eabd0,
+0x00e49430,
+0x0010f338,
+0x0010f338,
+0x00e49430,
+0x000eabd0,
+0x00421c2d,
+0x00f4e40e,
+0x00188dd6,
+0x00e410d6,
+0x001066c6,
+0x008e3ba9,
+0x000aaa6a,
+0x00f5559a,
+0x0071c459,
+0x00651dd9,
+0x00f5c6b6,
+0x000b0ede,
+0x00000003,
+0x00000003,
+0x0002c197,
+0x0005832b,
+0x0002c197,
+0x00000003,
+0x00000003,
+0x0084a705,
+0x0007da1a,
+0x00000003,
+0x000430ab,
+0x007ff7a1,
+0x00000003,
+0x000430ab,
+0x007ff7a1,
+0x00000003,
+0x00000003,
+0x0002c197,
+0x0005832b,
+0x0002c197,
+0x00000003,
+0x00000003,
+0x0084a705,
+0x0007da1a,
+0x00000003,
+0x00000003,
+0x0002c197,
+0x0005832b,
+0x0002c197,
+0x00000003,
+0x00000003,
+0x0084a705,
+0x0007da1a,
+0x00000003,
+0x000430ab,
+0x007ff7a1,
+0x00000003,
+0x000430ab,
+0x007ff7a1,
+0x00000003,
+0x000430ab,
+0x007ff7a1,
+0x00000003,
+0x000430ab,
+0x007ff7a1,
+0x00000020,
+0x003fffe0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00040002,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00040002,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00040002,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00269ec3,
+0x000d0ff4,
+0x00051eba,
+0x00640001,
+0x0002f290,
+0x00fdd340,
+0x0002a810,
+0x0002a810,
+0x00fdd340,
+0x0002f290,
+0x0045a895,
+0x00f4a186,
+0x0018a312,
+0x00e445b2,
+0x0010419e,
+0x000b68e0,
+0x0021f7f0,
+0x0044471c,
+0x005c5e48,
+0x005c5e48,
+0x0044471c,
+0x0021f7f0,
+0x000b68e0,
+0x0020ff38,
+0x00b24b3d,
+0x00062d86,
+0x00f4f6ea,
+0x000d3f5a,
+0x00f2ea1a,
+0x00075f92,
+0x00c1248b,
+0x00fd1080,
+0x00faca4c,
+0x00fab048,
+0x00fdb0ac,
+0x00024f54,
+0x00054fb8,
+0x000535b4,
+0x0002ef80,
+0x003edb7b,
+0x001d92ec,
+0x00962b59,
+0x000bd422,
+0x00e48132,
+0x002dbdc2,
+0x00c7a94a,
+0x0033fbe6,
+0x00dd3502,
+0x000fea26,
+0x00c1248b,
+0x00fd1080,
+0x00faca4c,
+0x00fab048,
+0x00fdb0ac,
+0x00024f54,
+0x00054fb8,
+0x000535b4,
+0x0002ef80,
+0x003edb7b,
+0x001d92ec,
+0x00962b59,
+0x000bd422,
+0x00e48132,
+0x002dbdc2,
+0x00c7a94a,
+0x0033fbe6,
+0x00dd3502,
+0x000fea26,
+0x003c0001,
+0x00080002,
+0x007f0001,
+0x00040002,
+0x00040002,
+0x00000020,
+0x003fffe0,
+0x00000020,
+0x003fffe0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00009060,
+0x03130298,
+0x02DE031E,
+0x004302E8,
+0x0325003A,
+0x032C0344,
+0x042F02C9,
+0x048D0351,
+0x018100CA,
+0x026C01AD,
+0x00B402AB,
+0x01BE01CC,
+0x053905AF,
+0x000202F3,
+0x00DE00D8,
+0x00EF00E8,
+0x010600F9,
+0x0124010D,
+0x0114011C,
+0x0146012B,
+0x0003015D,
+0x017F017E,
+0x040E0180,
+0x01690364,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00B80011,
+0x009D009C,
+0x009F009E,
+0x00000000,
+0x002E0011,
+0x00A300A2,
+0x00A500A4,
+0x00000000,
+0x00B90011,
+0x00AB00AA,
+0x00A000AC,
+0x00000000,
+0x00B90011,
+0x00B100B0,
+0x00B300B2,
+0x00000000,
+0x00BA0011,
+0x00AE00AD,
+0x00A100AF,
+0x00000000,
+0x00BA0011,
+0x00B500B4,
+0x00B700B6,
+0x00000000,
+0x00550014,
+0x00560003,
+0x00590057,
+0x00000013,
+0x00550014,
+0x00560006,
+0x00600057,
+0x00000013,
+0x00630014,
+0x0064010B,
+0x00670065,
+0x00000012,
+0x005A0015,
+0x005B0002,
+0x005E005C,
+0x00000013,
+0x005A0015,
+0x005B0005,
+0x0061005C,
+0x00000013,
+0x01030003,
+0x0001008D,
+0x008F0001,
+0x00000000,
+0x01040003,
+0x0001008E,
+0x00900001,
+0x00000000,
+0x01050003,
+0x0001012A,
+0x008F0001,
+0x00000000,
+0x01050003,
+0x0001012B,
+0x00900001,
+0x00000000,
+0x004C0003,
+0x0001008D,
+0x008F0001,
+0x00000000,
+0x004C0003,
+0x0001008E,
+0x00900001,
+0x00000000,
+0x0031000A,
+0x0070002F,
+0x004D0071,
+0x00000000,
+0x00B90000,
+0x00A600B9,
+0x009B00A8,
+0x00000000,
+0x00BA0000,
+0x00A700BA,
+0x009B00A9,
+0x00000000,
+0x002F000A,
+0x00BD002F,
+0x009B00BE,
+0x00000000,
+0x00010013,
+0x00010001,
+0x010E0001,
+0x00000000,
+0x00010013,
+0x00010001,
+0x010F0001,
+0x00000000,
+0x000D0009,
+0x000F000E,
+0x00110010,
+0x00000000,
+0x00270000,
+0x002A0029,
+0x002C002B,
+0x00000000,
+0x00230000,
+0x00780023,
+0x00910073,
+0x00000000,
+0x00030000,
+0x00790003,
+0x00920074,
+0x00000000,
+0x00230000,
+0x007A0023,
+0x00930076,
+0x00000000,
+0x00060000,
+0x007B0006,
+0x00940077,
+0x00000000,
+0x00280000,
+0x007C0103,
+0x00910072,
+0x00000000,
+0x008D0000,
+0x007D005F,
+0x00920074,
+0x00000000,
+0x00280000,
+0x007E0104,
+0x00930075,
+0x00000000,
+0x008E0000,
+0x007F0062,
+0x00940077,
+0x00000000,
+0x01060000,
+0x00800106,
+0x00910073,
+0x00000000,
+0x01090000,
+0x00810109,
+0x00920074,
+0x00000000,
+0x01060000,
+0x00820106,
+0x00930076,
+0x00000000,
+0x010A0000,
+0x0083010A,
+0x00940077,
+0x00000000,
+0x00300000,
+0x00840105,
+0x00910072,
+0x00000000,
+0x012A0000,
+0x00850107,
+0x00920074,
+0x00000000,
+0x00300000,
+0x00860105,
+0x00930075,
+0x00000000,
+0x012B0000,
+0x00870108,
+0x00940077,
+0x00000000,
+0x00260000,
+0x008A004C,
+0x00910072,
+0x00000000,
+0x008D0000,
+0x008B008C,
+0x00920074,
+0x00000000,
+0x00260000,
+0x0088004C,
+0x00930075,
+0x00000000,
+0x008E0000,
+0x0089008C,
+0x00940077,
+0x00000000,
+0x00300000,
+0x006E002E,
+0x004D006F,
+0x00000000,
+0x002E0000,
+0x009900B8,
+0x009B009A,
+0x00000000,
+0x002E0000,
+0x00BB002E,
+0x009B00BC,
+0x00000000,
+0x002F0018,
+0x00970050,
+0x009600D0,
+0x00000000,
+0x002E0018,
+0x0095004F,
+0x009600D0,
+0x00000000,
+0x002D0007,
+0x00010030,
+0x00000017,
+0x00000000,
+0x00210007,
+0x00010031,
+0x00000018,
+0x00000000,
+0x00CE000B,
+0x00010001,
+0x00CF0001,
+0x00000000,
+0x0001000C,
+0x00010001,
+0x00D90001,
+0x00000000,
+0x0001000C,
+0x00010001,
+0x00DA0001,
+0x00000000,
+0x0001000C,
+0x00010001,
+0x00DB0001,
+0x00000000,
+0x0001000C,
+0x00010001,
+0x00DC0001,
+0x00000000,
+0x0001000C,
+0x00010001,
+0x00DD0001,
+0x00000000,
+0x0001000C,
+0x00010001,
+0x00DE0001,
+0x00000000,
+0x0001000C,
+0x00010001,
+0x00DF0001,
+0x00000000,
+0x0001000C,
+0x00010001,
+0x00E00001,
+0x00000000,
+0x0001000C,
+0x00010001,
+0x00E10001,
+0x00000000,
+0x0001000C,
+0x00010001,
+0x00E20001,
+0x00000000,
+0x0001000C,
+0x00010001,
+0x00E30001,
+0x00000000,
+0x0001000C,
+0x00010001,
+0x00E40001,
+0x00000000,
+0x0001000C,
+0x00010001,
+0x00E50001,
+0x00000000,
+0x0001000C,
+0x00010001,
+0x00E60001,
+0x00000000,
+0x0001000C,
+0x00010001,
+0x00E70001,
+0x00000000,
+0x0001000C,
+0x00010001,
+0x00E80001,
+0x00000000,
+0x00F9000D,
+0x00010001,
+0x00FA0001,
+0x00000000,
+0x002E0005,
+0x001C0026,
+0x0000002F,
+0x00000000,
+0x00290005,
+0x001D002D,
+0x00000020,
+0x00000000,
+0x00080006,
+0x00250020,
+0x0000001A,
+0x00000000,
+0x00080006,
+0x00250021,
+0x0000001B,
+0x00000000,
+0x00080006,
+0x00690068,
+0x0000001E,
+0x00000000,
+0x00080006,
+0x00690028,
+0x0000001F,
+0x00000000,
+0x00C00001,
+0x00C80051,
+0x0000011F,
+0x00000000,
+0x00030004,
+0x000C0023,
+0x008F0001,
+0x00000000,
+0x00060004,
+0x000C0023,
+0x00900001,
+0x00000000,
+0x01090004,
+0x000C0106,
+0x008F0001,
+0x00000000,
+0x010A0004,
+0x000C0106,
+0x00900001,
+0x00000000,
+0x002F0004,
+0x00FC0050,
+0x00FB0001,
+0x00000000,
+0x002E0004,
+0x00FC004F,
+0x00FB0001,
+0x00000000,
+0x00400002,
+0x00420041,
+0x00000016,
+0x00000000,
+0x00320002,
+0x00340033,
+0x00000013,
+0x00000000,
+0x00350002,
+0x00370036,
+0x00000014,
+0x00000000,
+0x00380002,
+0x003A0039,
+0x00000015,
+0x00000000,
+0x00680002,
+0x006B006A,
+0x00000019,
+0x00000000,
+0x01060002,
+0x003F003E,
+0x00000019,
+0x00000000,
+0x00080002,
+0x00460045,
+0x00000019,
+0x00000000,
+0x002F0002,
+0x00BA00B9,
+0x00000019,
+0x00000000,
+0x00CD0002,
+0x00C700BF,
+0x00000019,
+0x00000000,
+0x010B0002,
+0x010D010C,
+0x00000019,
+0x00000000,
+0x00260002,
+0x00440043,
+0x00000019,
+0x00000000,
+0x003B0002,
+0x003D003C,
+0x00000019,
+0x00000000,
+0x00010008,
+0x00010027,
+0x00520001,
+0x00000000,
+0x00010008,
+0x00010022,
+0x00530001,
+0x00000000,
+0x00BF0010,
+0x00C100C0,
+0x00C600C2,
+0x00000000,
+0x00C7000F,
+0x00C900C8,
+0x00CC00CA,
+0x00000000,
+0x00010013,
+0x00010001,
+0x01100001,
+0x00000000,
+0x00010013,
+0x00010001,
+0x01110001,
+0x00000000,
+0x00010013,
+0x00010001,
+0x01120001,
+0x00000000,
+0x00010013,
+0x00010001,
+0x01130001,
+0x00000000,
+0x00010013,
+0x00010001,
+0x01140001,
+0x00000000,
+0x00010013,
+0x00010001,
+0x01150001,
+0x00000000,
+0x00010013,
+0x00010001,
+0x01160001,
+0x00000000,
+0x00010013,
+0x00010001,
+0x01170001,
+0x00000000,
+0x0001000E,
+0x00010001,
+0x00010001,
+0x00000000,
+0x00010013,
+0x00010001,
+0x01180001,
+0x00000000,
+0x00010013,
+0x00010001,
+0x01190001,
+0x00000000,
+0x00010013,
+0x00010001,
+0x011A0001,
+0x00000000,
+0x00480012,
+0x00D10040,
+0x00D400D2,
+0x00000000,
+0x00490012,
+0x00D60032,
+0x00D500D3,
+0x00000000,
+0x004A0012,
+0x00D70035,
+0x00D500D3,
+0x00000000,
+0x004B0012,
+0x00D80038,
+0x00D500D3,
+0x00000000,
+0x011C0016,
+0x011D0001,
+0x011E0001,
+0x00000000,
+0x00010017,
+0x00010001,
+0x00000001,
+0x00000000,
+0x01200014,
+0x01220109,
+0x01250123,
+0x00000013,
+0x01200014,
+0x0122010A,
+0x01260123,
+0x00000013,
+0x01270015,
+0x012E012C,
+0x0131012F,
+0x00000013,
+0x01270015,
+0x012E012D,
+0x0132012F,
+0x00000013,
+0x012A0000,
+0x00850128,
+0x00920074,
+0x00000000,
+0x012B0000,
+0x00870129,
+0x00940077,
+0x00000000,
+0x00010013,
+0x00010001,
+0x01330001,
+0x00000000,
+0x00010013,
+0x00010001,
+0x01340001,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000010,
+0x00000000,
+0x00000000,
+0x000022E8,
+0x00000000,
+0x00000000,
+0x00000018,
+0x000022E0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x0000000A,
+0x00000000,
+0x00000000,
+0x00000000,
+0x7FFF7FFF,
+0x7FFF7FFF,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000004,
+0x00000001,
+0x00000000,
+0x00000000,
+0x00000000,
+0x003FFFF0,
+0x00000000,
+0x00400000,
+0x00000004,
+0x00000001,
+0x00000000,
+0x00000000,
+0x00000000,
+0x003FFFF0,
+0x00000000,
+0x00400000,
+0x019B0188,
+0x01C101AE,
+0x01E701D4,
+0x020D01FA,
+0x02330220,
+0x02590246,
+0x027F026C,
+0x02A50292,
+0x00000004,
+0x00000001,
+0x00000000,
+0x00000000,
+0x00000000,
+0x003FFFF0,
+0x00000000,
+0x00400000,
+0x02CE02BC,
+0x02F202E0,
+0x03160304,
+0x033A0328,
+0x035E034C,
+0x03820370,
+0x03A60394,
+0x03CA03B8,
+0x00008363,
+0x00000428,
+0x00000000,
+0x00003800,
+0x000000FF,
+0x00000004,
+0x00000001,
+0x00000000,
+0x00000000,
+0x00000000,
+0x003FFFF0,
+0x00000000,
+0x00400000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x000CE13D,
+0x00006845,
+0x00008363,
+0x00000428,
+0x000CE13D,
+0x00006845,
+0x00008363,
+0x00000428,
+0x000CE13D,
+0x00006845,
+0x25782728,
+0x00002738,
+0x25682708,
+0x00002718,
+0x297826B8,
+0x000026A8,
+0x29682698,
+0x00002688,
+0x255826E8,
+0x000026F8,
+0x254826C8,
+0x000026D8,
+0x29582638,
+0x00002628,
+0x29482618,
+0x00002608,
+0x25382668,
+0x00002678,
+0x25282648,
+0x00002658,
+0x27582488,
+0x00002478,
+0x259824A8,
+0x00002498,
+0x25A824C8,
+0x000024B8,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00003000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00003900,
+0x00003900,
+0x00003900,
+0x00003CBF,
+0x00000004,
+0x00000001,
+0x00000000,
+0x00000000,
+0x00000000,
+0x003FFFF0,
+0x00000000,
+0x00400000,
+0x00000004,
+0x00000001,
+0x00000000,
+0x00000000,
+0x00000000,
+0x003FFFF0,
+0x00000000,
+0x00400000,
+0x254826C8,
+0x00002C08,
+0x255826E8,
+0x00002C18,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00041503,
+0x00000000,
+0x00041802,
+0x00000000,
+0x00066903,
+0x00000000,
+0x00046205,
+0x00000000,
+0x00046704,
+0x00000000,
+0x00066405,
+0x00000000,
+0x0001820C,
+0x00000000,
+0x00046B28,
+0x00000000,
+0x0004BB28,
+0x00000000,
+0x0006F106,
+0x00000000,
+0x00022918,
+0x00000000,
+0x00013912,
+0x00000000,
+0x00014B12,
+0x00013600,
+0x00015B24,
+0x00013712,
+0x00014912,
+0x00120024,
+0x00057400,
+0x00015B0E,
+0x00015B0E,
+0x00015B0E,
+0x00015B0E,
+0x00015B0E,
+0x00015B0E,
+0x00015B0E,
+0x00015B0E,
+0x00015B0E,
+0x00015B0E,
+0x00015B0E,
+0x00015B0E,
+0x00015B0E,
+0x00015B0E,
+0x00015B0E,
+0x00015B0E,
+0x00015E0C,
+0x00016904,
+0x00015E0C,
+0x00016D04,
+0x00000000,
+0x00017102,
+0x00000000,
+0x00017302,
+0x00016A0C,
+0x00017504,
+0x00016A0C,
+0x00017904,
+0x00000000,
+0x00018E0C,
+0x00000000,
+0x00019A0C,
+0x00000000,
+0x0001760C,
+0x00000000,
+0x00016A0C,
+0x00000000,
+0x00015E0C,
+0x00016A0C,
+0x0001760C,
+0x00000000,
+0x0001A60C,
+0x00000000,
+0x0001BE0C,
+0x00000000,
+0x0001CA0C,
+0x00000000,
+0x0001FC0C,
+0x00020809,
+0x00020809,
+0x00000000,
+0x00017F09,
+0x000B0009,
+0x00000000,
+0x00000000,
+0x0001B20C,
+0x00000000,
+0x00066C0C,
+0x00000000,
+0x0006780C,
+0x00000000,
+0x0006840C,
+0x00000000,
+0x0006900C,
+0x00000000,
+0x0002410C,
+0x00022918,
+0x0002710C,
+0x00022918,
+0x00027D0C,
+0x00000000,
+0x00024D0C,
+0x00022900,
+0x0002890C,
+0x00022900,
+0x0002950C,
+0x00000000,
+0x0002590C,
+0x00022918,
+0x0002A10C,
+0x00022918,
+0x0002AD0C,
+0x00000000,
+0x0008220C,
+0x00022918,
+0x00082E0C,
+0x00022918,
+0x00083A0C,
+0x00022918,
+0x0002B90C,
+0x00022918,
+0x0002C50C,
+0x00000000,
+0x0002650C,
+0x00022918,
+0x0002D10C,
+0x00022918,
+0x0002DD0C,
+0x00022918,
+0x0002E90C,
+0x00022918,
+0x0002F50C,
+0x00022918,
+0x0003010C,
+0x00022918,
+0x00030D0C,
+0x00000000,
+0x00031978,
+0x00000000,
+0x00039118,
+0x00000000,
+0x0003A918,
+0x00000000,
+0x0003C118,
+0x00000000,
+0x0003D918,
+0x00000000,
+0x0004090C,
+0x000B0019,
+0x00000000,
+0x000B0009,
+0x00000000,
+0x00000000,
+0x00041A18,
+0x00000000,
+0x00043218,
+0x00000000,
+0x00044A18,
+0x000B2DD8,
+0x00000000,
+0x000B2DD4,
+0x00000000,
+0x000B2DC0,
+0x00000000,
+0x00000000,
+0x00046B28,
+0x00029213,
+0x0002A513,
+0x00046B28,
+0x0002BA00,
+0x0002BB00,
+0x000B7900,
+0x00580002,
+0x00217800,
+0x00000000,
+0x00049328,
+0x00029213,
+0x0002A513,
+0x00049328,
+0x0002B800,
+0x0002B900,
+0x000B8100,
+0x005D0002,
+0x00212800,
+0x00000000,
+0x00049328,
+0x00580004,
+0x00217800,
+0x005D0004,
+0x00212800,
+0x00000000,
+0x00049328,
+0x00000000,
+0x0004BB28,
+0x0003B812,
+0x0003CA12,
+0x0004BB28,
+0x0003DC00,
+0x0003DD00,
+0x000B9100,
+0x0066000C,
+0x00226800,
+0x00000000,
+0x0004E30C,
+0x0001BE0C,
+0x00015E0C,
+0x00000000,
+0x0004EF0C,
+0x00000000,
+0x0004FB0C,
+0x00022918,
+0x0005070C,
+0x00022918,
+0x0005130C,
+0x00053819,
+0x00053819,
+0x00000000,
+0x00041019,
+0x00051F19,
+0x00051F19,
+0x0003F719,
+0x0003DE19,
+0x00000000,
+0x0004440B,
+0x00000000,
+0x00044F0B,
+0x00000000,
+0x00045A07,
+0x00000000,
+0x0004290B,
+0x00000000,
+0x0004340B,
+0x00000000,
+0x00043F05,
+0x0005750B,
+0x0005750B,
+0x00058007,
+0x00058007,
+0x0005870B,
+0x0005870B,
+0x00059205,
+0x00059205,
+0x0005970B,
+0x0005970B,
+0x0005A207,
+0x0005A207,
+0x0005A90B,
+0x0005A90B,
+0x0005B405,
+0x0005B405,
+0x0005BB0B,
+0x0005BB0B,
+0x0005C607,
+0x0005C607,
+0x0005CD0B,
+0x0005CD0B,
+0x0005D805,
+0x0005D805,
+0x0005DD0B,
+0x0005DD0B,
+0x0005E807,
+0x0005E807,
+0x0005EF0B,
+0x0005EF0B,
+0x0005FA05,
+0x0005FA05,
+0x0006110B,
+0x0006110B,
+0x00061C07,
+0x00061C07,
+0x0005FF0B,
+0x0005FF0B,
+0x00060A05,
+0x00060A05,
+0x00000000,
+0x00063C28,
+0x00000000,
+0x00056F02,
+0x00000000,
+0x00057104,
+0x00000006,
+0x00000000,
+0x00000003,
+0x00000000,
+0x000B000B,
+0x00000000,
+0x00010007,
+0x00000000,
+0x000B000B,
+0x00000000,
+0x00030005,
+0x00000000,
+0x0005510F,
+0x0005510F,
+0x000B000F,
+0x0008A400,
+0x0005600F,
+0x0005600F,
+0x00030007,
+0x00000000,
+0x00062109,
+0x00062109,
+0x00046109,
+0x00046109,
+0x000B0009,
+0x00000000,
+0x00000000,
+0x00063002,
+0x00062A03,
+0x00062A03,
+0x000BA102,
+0x00046A03,
+0x00000003,
+0x002E8C00,
+0x00000003,
+0x002EBC00,
+0x00000003,
+0x002EC000,
+0x00000000,
+0x00063202,
+0x00062D03,
+0x00062D03,
+0x000BB102,
+0x00046D03,
+0x00000003,
+0x002E8E00,
+0x00069C09,
+0x00069C09,
+0x0006A509,
+0x0006A509,
+0x00000000,
+0x00047009,
+0x00000000,
+0x00047909,
+0x00000000,
+0x00063402,
+0x0006AE03,
+0x0006AE03,
+0x000BB302,
+0x00048203,
+0x00000000,
+0x00063802,
+0x0006B103,
+0x0006B103,
+0x000BB702,
+0x00048503,
+0x00000000,
+0x00063602,
+0x0006B403,
+0x0006B403,
+0x000BB502,
+0x00048803,
+0x00000003,
+0x002EBE00,
+0x00000000,
+0x00063A02,
+0x0006B703,
+0x0006B703,
+0x000BB902,
+0x00048B03,
+0x00000003,
+0x002EC200,
+0x00000000,
+0x0006BA0C,
+0x00022918,
+0x0006C60C,
+0x00022918,
+0x0006D20C,
+0x0006DE09,
+0x0006DE09,
+0x00000000,
+0x00049009,
+0x0006E709,
+0x0006E709,
+0x0004A209,
+0x00049909,
+0x00000000,
+0x00072906,
+0x00022900,
+0x00074718,
+0x00075F0B,
+0x00075F0B,
+0x00000000,
+0x0004AF0B,
+0x00013600,
+0x00072F18,
+0x00075F0B,
+0x00075F0B,
+0x00074718,
+0x00072906,
+0x00C3000B,
+0x0000C400,
+0x00000000,
+0x0006F706,
+0x00022918,
+0x0006FE18,
+0x0004AB04,
+0x0006FD00,
+0x00013600,
+0x00071600,
+0x000BAE00,
+0x00071712,
+0x00EA00CB,
+0x000026FF,
+0x00000000,
+0x0006F106,
+0x00000000,
+0x00100020,
+0x00F42CDC,
+0x0000002C,
+0x00000000,
+0x0004BA0F,
+0x00078213,
+0x00078213,
+0x00000000,
+0x0004C913,
+0x00000000,
+0x0004DC13,
+0x00170013,
+0x00000000,
+0x00170013,
+0x00000000,
+0x00079513,
+0x00079513,
+0x0007A813,
+0x0007A813,
+0x0007BB13,
+0x0007BB13,
+0x00002060,
+0x00000000,
+0x00002088,
+0x00000000,
+0x000020B0,
+0x00000000,
+0x000020D8,
+0x00000000,
+0x00002100,
+0x00000000,
+0x00002128,
+0x00000000,
+0x00002150,
+0x00000000,
+0x00002178,
+0x00000000,
+0x000021A0,
+0x00000000,
+0x000021C8,
+0x00000000,
+0x000021F0,
+0x00000000,
+0x00002218,
+0x00000000,
+0x00002240,
+0x00000000,
+0x00002268,
+0x00000000,
+0x00002290,
+0x00000000,
+0x000022B8,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x000B2710,
+0x000F00E9,
+0x00000000,
+0x00000002,
+0x00000000,
+0x00000000,
+0x00013600,
+0x00000000,
+0x0001400C,
+0x00000000,
+0x0007CE02,
+0x00000000,
+0x0007D004,
+0x00000000,
+0x0007D406,
+0x00000000,
+0x0007DA0C,
+0x00000000,
+0x0007E648,
+0x00000000,
+0x0003F10C,
+0x00000000,
+0x0003FD0C,
+0x00000000,
+0x0001D60C,
+0x00000000,
+0x0001E20C,
+0x00000000,
+0x0001EE02,
+0x00000000,
+0x0001F104,
+0x00000000,
+0x0001F602,
+0x00000000,
+0x0001F804,
+0x00000000,
+0x0007FE0C,
+0x00022918,
+0x00080A0C,
+0x00022918,
+0x0008160C,
+0x00002EEC,
+0x00000000,
+0x00002EF4,
+0x00000000,
+0x00002EFC,
+0x00000000,
+0x00002F04,
+0x00000000,
+0x00002F0C,
+0x00000000,
+0x00002F14,
+0x00000000,
+0x00002F1C,
+0x00000000,
+0x00002F24,
+0x00000000,
+0x00002F2C,
+0x00000000,
+0x00002F34,
+0x00000000,
+0x00002F3C,
+0x00000000,
+0x00002F44,
+0x00000000,
+0x00002F4C,
+0x00000000,
+0x00000000,
+0x0008B800,
+0x00000000,
+0x000E4000,
+0x0008B800,
+0x00013600,
+0x00003CC0,
+0x00000000,
+0x0004F200,
+0x0004F201,
+0x00000000,
+0x00084728,
+0x00000000,
+0x00084728,
+0x00029213,
+0x0002A513,
+0x00084728,
+0x0004F400,
+0x0004F500,
+0x000F3400,
+0x00240002,
+0x0020B001,
+0x00240004,
+0x0020B001,
+0x00000000,
+0x00086F28,
+0x00000000,
+0x00086F28,
+0x00000000,
+0x00086F28,
+0x00000000,
+0x00089702,
+0x00000000,
+0x00089904,
+0x00000000,
+0x0001EE03,
+0x00000000,
+0x0001F105,
+0x00029213,
+0x0002A513,
+0x00086F28,
+0x0004F600,
+0x0004F700,
+0x000F3C00,
+0x00300002,
+0x0021F001,
+0x00300004,
+0x0021F001,
+0x00003D10,
+0x00000000,
+0x00003D18,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00040000,
+0x00040000,
+0x00000001,
+0x00000010,
+0x00000001,
+0x00000010,
+0x00000001,
+0x00000010,
+0x00000001,
+0x00000010,
+0x00000001,
+0x00000010,
+0x00000001,
+0x00000010,
+0x00000001,
+0x00000010,
+0x00000001,
+0x00000010,
+0x00000001,
+0x00000010,
+0x00000001,
+0x00000010,
+0x00000001,
+0x00000010,
+0x00000001,
+0x00000010,
+0x00000001,
+0x00000010,
+0x00000001,
+0x00000010,
+0x00000001,
+0x00000010,
+0x00000001,
+0x00000010,
+0x00000001,
+0x00000010,
+0x00000000,
+0x00000000,
+0x00400000,
+0x00400000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x0000001B,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000003,
+0x00000000,
+0x00000003,
+0x00000000,
+0x00000003,
+0x00000000,
+0x00000006,
+0x00000000,
+0x00000006,
+0x00000000,
+0x00000006,
+0x00000000,
+0x00000009,
+0x00000000,
+0x00000009,
+0x00000000,
+0x00000009,
+0x00000000,
+0x00000005,
+0x00000000,
+0x00000005,
+0x00000000,
+0x00000005,
+0x00000000,
+0x00000007,
+0x00000000,
+0x00000007,
+0x00000000,
+0x00000007,
+0x00000000,
+0x00000008,
+0x00000000,
+0x00000008,
+0x00000000,
+0x00000008,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00E66666,
+0x00199999,
+0x00199999,
+0x00199999,
+0x00000000,
+0x00000000,
+0x00E66666,
+0x00E66666,
+0x00FFFFFF,
+0x00FFFFFF,
+0x00199999,
+0x00199999,
+0x00F33333,
+0x000CCCCC,
+0x00F33333,
+0x00F33333,
+0x00199999,
+0x00E66666,
+0x00F33333,
+0x00F33333,
+0x00F33333,
+0x000CCCCC,
+0x00199999,
+0x00199999,
+0x000CCCCC,
+0x00162B95,
+0x00F33333,
+0x000CCCCC,
+0x00E66666,
+0x00000000,
+0x00F33333,
+0x00F33333,
+0x000CCCCC,
+0x00E9D46A,
+0x00199999,
+0x00E66666,
+0x000CCCCC,
+0x00E9D46A,
+0x00F33333,
+0x00F33333,
+0x00E66666,
+0x00FFFFFF,
+0x00F33333,
+0x000CCCCC,
+0x000CCCCC,
+0x00162B95,
+0x00199999,
+0x00199999,
+0x00162B95,
+0x0018BA4A,
+0x000CCCCC,
+0x00162B95,
+0x00000000,
+0x00121A18,
+0x00F33333,
+0x000CCCCC,
+0x00E9D46A,
+0x0006A032,
+0x00E66666,
+0x00000000,
+0x00E9D46A,
+0x00F95FCD,
+0x00F33333,
+0x00F33333,
+0x00FFFFFF,
+0x00EDE5E7,
+0x000CCCCC,
+0x00E9D46A,
+0x00162B95,
+0x00E745B5,
+0x00199999,
+0x00E66666,
+0x00162B95,
+0x00E745B5,
+0x000CCCCC,
+0x00E9D46A,
+0x00000000,
+0x00EDE5E7,
+0x00F33333,
+0x00F33333,
+0x00E9D46A,
+0x00F95FCF,
+0x00E66666,
+0x00FFFFFF,
+0x00E9D46A,
+0x0006A032,
+0x00F33333,
+0x000CCCCC,
+0x00FFFFFF,
+0x00121A18,
+0x000CCCCC,
+0x00162B95,
+0x00162B95,
+0x0018BA4A,
+0x00199999,
+0x00199999,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00010000,
+0x00010000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000000,
diff --git a/sound/soc/omap/abe/abe_functionsid.h b/sound/soc/omap/abe/abe_functionsid.h
new file mode 100644
index 00000000000..9320afe249d
--- /dev/null
+++ b/sound/soc/omap/abe/abe_functionsid.h
@@ -0,0 +1,75 @@
+/*
+ * ALSA SoC OMAP ABE driver
+*
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef _ABE_FUNCTIONSID_H_
+#define _ABE_FUNCTIONSID_H_
+/*
+ * TASK function ID definitions
+ */
+#define C_ABE_FW_FUNCTION_IIR 0
+#define C_ABE_FW_FUNCTION_monoToStereoPack 1
+#define C_ABE_FW_FUNCTION_stereoToMonoSplit 2
+#define C_ABE_FW_FUNCTION_decimator 3
+#define C_ABE_FW_FUNCTION_OS0Fill 4
+#define C_ABE_FW_FUNCTION_mixer2 5
+#define C_ABE_FW_FUNCTION_mixer4 6
+#define C_ABE_FW_FUNCTION_inplaceGain 7
+#define C_ABE_FW_FUNCTION_StreamRouting 8
+#define C_ABE_FW_FUNCTION_gainConverge 9
+#define C_ABE_FW_FUNCTION_dualIir 10
+#define C_ABE_FW_FUNCTION_IO_DL_pp 11
+#define C_ABE_FW_FUNCTION_IO_generic 12
+#define C_ABE_FW_FUNCTION_irq_fifo_debug 13
+#define C_ABE_FW_FUNCTION_synchronize_pointers 14
+#define C_ABE_FW_FUNCTION_VIBRA2 15
+#define C_ABE_FW_FUNCTION_VIBRA1 16
+#define C_ABE_FW_FUNCTION_APS_core 17
+#define C_ABE_FW_FUNCTION_IIR_SRC_MIC 18
+#define C_ABE_FW_FUNCTION_wrappers 19
+#define C_ABE_FW_FUNCTION_ASRC_DL_wrapper 20
+#define C_ABE_FW_FUNCTION_ASRC_UL_wrapper 21
+#define C_ABE_FW_FUNCTION_mem_init 22
+#define C_ABE_FW_FUNCTION_debug_vx_asrc 23
+#define C_ABE_FW_FUNCTION_IIR_SRC2 24
+/*
+ * COPY function ID definitions
+ */
+#define NULL_COPY_CFPID 0
+#define S2D_STEREO_16_16_CFPID 1
+#define S2D_MONO_MSB_CFPID 2
+#define S2D_STEREO_MSB_CFPID 3
+#define S2D_STEREO_RSHIFTED_16_CFPID 4
+#define S2D_MONO_RSHIFTED_16_CFPID 5
+#define D2S_STEREO_16_16_CFPID 6
+#define D2S_MONO_MSB_CFPID 7
+#define D2S_MONO_RSHIFTED_16_CFPID 8
+#define D2S_STEREO_RSHIFTED_16_CFPID 9
+#define D2S_STEREO_MSB_CFPID 10
+#define COPY_DMIC_CFPID 11
+#define COPY_MCPDM_DL_CFPID 12
+#define COPY_MM_UL_CFPID 13
+#define SPLIT_SMEM_CFPID 14
+#define MERGE_SMEM_CFPID 15
+#define SPLIT_TDM_CFPID 16
+#define MERGE_TDM_CFPID 17
+#define ROUTE_MM_UL_CFPID 18
+#define IO_IP_CFPID 19
+#define COPY_UNDERFLOW_CFPID 20
+#endif/* _ABE_FUNCTIONSID_H_ */
diff --git a/sound/soc/omap/abe/abe_fw.h b/sound/soc/omap/abe/abe_fw.h
new file mode 100644
index 00000000000..5691e4e0996
--- /dev/null
+++ b/sound/soc/omap/abe/abe_fw.h
@@ -0,0 +1,379 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software`
+ * 02110-1301 USA
+ */
+#ifndef _ABE_FW_H_
+#define _ABE_FW_H_
+#include "abe_cm_addr.h"
+#include "abe_sm_addr.h"
+#include "abe_dm_addr.h"
+#include "abe_typedef.h"
+/*
+ * GLOBAL DEFINITION
+ */
+/* one scheduler loop = 4kHz = 12 samples at 48kHz */
+#define FW_SCHED_LOOP_FREQ 4000
+/* one scheduler loop = 4kHz = 12 samples at 48kHz */
+#define FW_SCHED_LOOP_FREQ_DIV1000 (FW_SCHED_LOOP_FREQ/1000)
+#define EVENT_FREQUENCY 96000
+#define SLOTS_IN_SCHED_LOOP (96000/FW_SCHED_LOOP_FREQ)
+#define SCHED_LOOP_8kHz ( 8000/FW_SCHED_LOOP_FREQ)
+#define SCHED_LOOP_16kHz (16000/FW_SCHED_LOOP_FREQ)
+#define SCHED_LOOP_24kHz (24000/FW_SCHED_LOOP_FREQ)
+#define SCHED_LOOP_48kHz (48000/FW_SCHED_LOOP_FREQ)
+#define TASKS_IN_SLOT 8
+/*
+ * DMEM AREA - SCHEDULER
+ */
+#define dmem_mm_trace D_DEBUG_FIFO_ADDR
+#define dmem_mm_trace_size ((D_DEBUG_FIFO_ADDR_END-D_DEBUG_FIFO_ADDR+1)/4)
+#define ATC_SIZE 8 /* 8 bytes per descriptors */
+typedef struct {
+ unsigned rdpt:7; /* first 32bits word of the descriptor */
+ unsigned reserved0:1;
+ unsigned cbsize:7;
+ unsigned irqdest:1;
+ unsigned cberr:1;
+ unsigned reserved1:5;
+ unsigned cbdir:1;
+ unsigned nw:1;
+ unsigned wrpt:7;
+ unsigned reserved2:1;
+ unsigned badd:12; /* second 32bits word of the descriptor */
+ unsigned iter:7; /* iteration field overlaps the 16 bits boundary */
+ unsigned srcid:6;
+ unsigned destid:6;
+ unsigned desen:1;
+} abe_satcdescriptor_aess;
+/*
+ * table of scheduler tasks :
+ * char scheduler_table[24 x 4] : four bytes used at OPP100%
+ */
+#define dmem_scheduler_table D_multiFrame_ADDR
+#define dmem_eanc_task_pointer D_pFastLoopBack_ADDR
+/*
+ * OPP value :
+ * pointer increment steps in the scheduler table
+ */
+#define dmem_scheduler_table_step D_taskStep_ADDR
+/*
+ * table of scheduler tasks (max 64) :
+ * char task_descriptors[64 x 8] : eight bytes per task
+ * TASK INDEX, INITPTR 1,2,3, INITREG, Loop Counter, Reserved 1,2
+ */
+#define dmem_task_descriptor D_tasksList_ADDR
+/*
+ * I/O DESCRIPTORS
+ */
+#define dmem_port_descriptors D_IOdescr_ADDR
+/* ping_pong_t descriptors table
+ * structure of 8 bytes:
+ * uint16 base_address1
+ * uint16 size1 (16bits address format)
+ * uint16 base_address2
+ * uint16 size2
+ * } ping_pong_t
+ * ping_pong_t dmem_ping_pong_t [8]
+ */
+/* U8 address */
+#define dmem_ping_pong_buffer D_PING_ADDR
+/*
+ * IRQ mask used with ports with IRQ (DMA or host)
+ * uint32 dmem_irq_masks [8]
+ */
+#define dmem_irq_masks D_IRQMask_ADDR
+/*
+ * tables of to the 8 FIFO sequences (delayed commands) holding 12bytes tasks
+ * in the format
+ * structure {
+ * 1) Down counter delay on 16bits, decremented on each scheduler period
+ * 2) Code on 8 bits for the type of operation to execute : call or data move.
+ * 3) Three 16bits parameters (for data move example example : source/
+ * destination/counter)
+ * 4) Three bytes reserved
+ * } seq_fw_task_t
+ *
+ * structure {
+ * uint32 : base address(MSB) + read pointer(LSB)
+ * uint32 : max address (MSB) + write pointer (LSB)
+ * } FIFO_generic;
+ * seq_fw_task_t FIFO_CONTENT [8]; 96 bytes
+ *
+ * FIFO_SEQ dmem_fifo_sequences [8]; all FIFO sequences
+ */
+#define dmem_fifo_sequences D_DCFifo_ADDR
+#define dmem_fifo_sequences_descriptors D_DCFifoDesc_ADDR
+/*
+ * IRQ FIFOs
+ *
+ * structure {
+ * uint32 : base address(MSB) + read pointer(LSB)
+ * uint32 : max address (MSB) + write pointer (LSB)
+ * uint32 IRQ_CODES [6];
+ * } dmem_fifo_irq_mcu; 32 bytes
+ * } dmem_fifo_irq_dsp; 32 bytes
+ */
+#define dmem_fifo_irq_mcu_descriptor D_McuIrqFifoDesc_ADDR
+#define dmem_fifo_irq_dsp_descriptor D_DspIrqFifoDesc_ADDR
+#define dmem_fifo_irq_mcu D_McuIrqFifo_ADDR
+#define dmem_fifo_irq_dsp D_DspIrqFifo_ADDR
+/*
+ * remote debugger exchange buffer
+ * uint32 dmem_debug_ae2hal [32]
+ * uint32 dmem_debug_hal2ae [32]
+ */
+#define dmem_debug_ae2hal D_DebugAbe2hal_ADDR
+#define dmem_debug_hal2ae D_Debug_hal2abe_ADDR
+/*
+ * DMEM address of the ASRC ppm drift parameter for ASRCs (voice and multimedia
+ * paths)
+ * uint32 smem_asrc(x)_drift
+ */
+#define dmem_asrc1_drift D_ASRC1drift_ADDR
+#define dmem_asrc2_drift D_ASRC2drift_ADDR
+/*
+ * DMEM indexes of the router uplink paths
+ * uint8 dmem_router_index [8]
+ */
+// OC: TBD ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//#define dmem_router_index
+/*
+ * analog control circular buffer commands to Phoenix
+ * structure {
+ * uint32 : base address(MSB) + read pointer(LSB)
+ * uint32 : max address (MSB) + write pointer (LSB)
+ * uint32 FIFO_CONTENT [6];
+ * } dmem_commands_to_phoenix; 32 bytes
+ */
+#define dmem_commands_to_phoenix D_Cmd2PhenixFifo_ADDR
+#define dmem_commands_to_phoenix_descriptor D_Cmd2PhenixFifoDesc_ADDR
+/*
+ * analog control circular buffer commands from Phoenix (status line)
+ * structure {
+ * uint32 : base address(MSB) + read pointer(LSB)
+ * uint32 : max address (MSB) + write pointer (LSB)
+ * uint32 FIFO_CONTENT [6];
+ * } dmem_commands_to_phoenix; 32 bytes
+ */
+#define dmem_commands_from_phoenix D_StatusFromPhenixFifo_ADDR
+#define dmem_commands_from_phoenix_descriptor D_StatusFromPhenixFifoDesc_ADDR
+/*
+ * DEBUG mask
+ * uint16 dmem_debug_trace_mask
+ * each bit of this word enables a type a trace in the debug circular buffer
+ */
+// OC: TBD ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//#define dmem_debug_trace_mask
+/*
+ * DEBUG circular buffer
+ * structure {
+ * uint32 : base address(MSB) + read pointer(LSB)
+ * uint32 : max address (MSB) + write pointer (LSB)
+ * uint32 FIFO_CONTENT [14]; = TIMESTAMP + CODE
+ * } dmem_debug_trace_buffer; 64 bytes
+ * should be much larger (depends on the DMEM mapping...)
+ */
+#define dmem_debug_trace_buffer
+#define dmem_debug_trace_fifo D_debugFifo_ADDR
+#define dmem_debug_trace_descriptor D_debugFifoDesc_ADDR
+/*
+ * Infinite counter incremented on each sheduler periods (~250 us)
+ * uint16 dmem_debug_time_stamp
+ */
+#define dmem_debug_time_stamp D_loopCounter_ADDR
+/*
+ * ATC BUFFERS + IO TASKS SMEM buffers
+ */
+#define dmem_dmic D_DMIC_UL_FIFO_ADDR
+#define dmem_dmic_size (D_DMIC_UL_FIFO_sizeof/4)
+#define dmem_amic D_McPDM_UL_FIFO_ADDR
+#define dmem_amic_size (D_McPDM_UL_FIFO_sizeof/4)
+#define smem_amic AMIC_96_labelID
+#define dmem_mcpdm D_McPDM_DL_FIFO_ADDR
+#define dmem_mcpdm_size (D_McPDM_DL_FIFO_sizeof/4)
+#define dmem_mm_ul D_MM_UL_FIFO_ADDR
+#define dmem_mm_ul_size (D_MM_UL_FIFO_sizeof/4)
+/* managed directly by the router */
+#define smem_mm_ul MM_UL_labelID
+#define dmem_mm_ul2 D_MM_UL2_FIFO_ADDR
+#define dmem_mm_ul2_size (D_MM_UL2_FIFO_sizeof/4)
+/* managed directly by the router */
+#define smem_mm_ul2 MM_UL2_labelID
+#define dmem_mm_dl D_MM_DL_FIFO_ADDR
+#define dmem_mm_dl_size (D_MM_DL_FIFO_sizeof/4)
+#define smem_mm_dl MM_DL_labelID
+#define dmem_vx_dl D_VX_DL_FIFO_ADDR
+#define dmem_vx_dl_size (D_VX_DL_FIFO_sizeof/4)
+#define smem_vx_dl IO_VX_DL_ASRC_labelID /* Voice_16k_DL_labelID */
+#define dmem_vx_ul D_VX_UL_FIFO_ADDR
+#define dmem_vx_ul_size (D_VX_UL_FIFO_sizeof/4)
+#define smem_vx_ul Voice_8k_UL_labelID
+#define dmem_tones_dl D_TONES_DL_FIFO_ADDR
+#define dmem_tones_dl_size (D_TONES_DL_FIFO_sizeof/4)
+#define smem_tones_dl Tones_labelID
+#define dmem_vib_dl D_VIB_DL_FIFO_ADDR
+#define dmem_vib_dl_size (D_VIB_DL_FIFO_sizeof/4)
+#define smem_vib IO_VIBRA_DL_labelID
+#define dmem_mm_ext_out D_MM_EXT_OUT_FIFO_ADDR
+#define dmem_mm_ext_out_size (D_MM_EXT_OUT_FIFO_sizeof/4)
+#define smem_mm_ext_out DL1_GAIN_out_labelID
+#define dmem_mm_ext_in D_MM_EXT_IN_FIFO_ADDR
+#define dmem_mm_ext_in_size (D_MM_EXT_IN_FIFO_sizeof/4)
+/*IO_MM_EXT_IN_ASRC_labelID ASRC input buffer, size 40 */
+#define smem_mm_ext_in_opp100 IO_MM_EXT_IN_ASRC_labelID
+/* at OPP 50 without ASRC */
+#define smem_mm_ext_in_opp50 MM_EXT_IN_labelID
+#define dmem_bt_vx_dl D_BT_DL_FIFO_ADDR
+#define dmem_bt_vx_dl_size (D_BT_DL_FIFO_sizeof/4)
+#define smem_bt_vx_dl_opp50 BT_DL_8k_labelID
+/*BT_DL_8k_opp100_labelID ASRC output buffer, size 40 */
+#define smem_bt_vx_dl_opp100 BT_DL_8k_opp100_labelID
+#define dmem_bt_vx_ul D_BT_UL_FIFO_ADDR
+#define dmem_bt_vx_ul_size (D_BT_UL_FIFO_sizeof/4)
+#define smem_bt_vx_ul_opp50 BT_UL_8k_labelID
+/*IO_BT_UL_ASRC_labelID ASRC input buffer, size 40 */
+#define smem_bt_vx_ul_opp100 IO_BT_UL_ASRC_labelID
+/*
+ * INITPTR / INITREG AREA
+ */
+/*
+ * POINTER - used for the port descriptor programming
+ * corresponds to 8bits addresses to the INITPTR area
+ *
+ * List from ABE_INITxxx_labels.h
+ */
+#define ptr_ul_rec
+#define ptr_vx_dl
+#define ptr_mm_dl
+#define ptr_mm_ext
+#define ptr_tones
+#define ptr_vibra2
+/*
+ * SMEM AREA
+ */
+/*
+ * PHOENIX OFFSET in SMEM
+ * used to subtract a DC offset on the headset path (power consumption optimization)
+ */
+/* OC: exact usage to be detailled */
+#define smem_phoenix_offset S_PhoenixOffset_ADDR
+/*
+ * EQUALIZERS Z AREA
+ * used to reset the filter memory - IIR-8 (max)
+ * int24 stereo smem_equ(x) [8x2 + 1]
+ */
+#define smem_equ1 S_EQU1_data_ADDR
+#define smem_equ2 S_EQU2_data_ADDR
+#define smem_equ3 S_EQU3_data_ADDR
+#define smem_equ4 S_EQU4_data_ADDR
+#define smem_sdt S_SDT_data_ADDR
+/*
+ * GAIN SMEM on PORT
+ * int32 smem_G0 [18] : desired gain on the ports
+ * format of G0 = 6 bits left shifted desired gain in linear 24bits format
+ * int24 stereo G0 [18] = G0
+ * int24 stereo GI [18] current value of the gain in the same format of G0
+ * List of smoothed gains :
+ * 6 DMIC 0 1 2 3 4 5
+ * 2 AMIC L R
+ * 4 PORT1/2_RX L R
+ * 2 MM_EXT L R
+ * 2 MM_VX_DL L R
+ * 2 IHF L R
+ * ---------------
+ * 18 = TOTAL
+ */
+#if 0
+#define smem_g0 S_GTarget_ADDR // [9] 2 gains in 1 SM address
+#define smem_g1 S_GCurrent_ADDR // [9] 2 gains in 1 SM address
+#endif
+/*
+ * COEFFICIENTS AREA
+ */
+/*
+ * delay coefficients used in the IIR-1 filters
+ * int24 cmem_gain_delay_iir1[9 x 2] (a, (1-a))
+ *
+ * 3 for 6 DMIC 0 1 2 3 4 5
+ * 1 for 2 AMIC L R
+ * 2 for 4 PORT1/2_RX L R
+ * 1 for 2 MM_EXT L R
+ * 1 for 2 MM_VX_DL L R
+ * 1 for 2 IHF L R
+ */
+#define cmem_gain_alpha C_Alpha_ADDR
+#define cmem_gain_1_alpha C_1_Alpha_ADDR
+/*
+ * gain controls
+ */
+#define GAIN_LEFT_OFFSET 0
+#define GAIN_RIGHT_OFFSET 1
+/* stereo gains */
+#define dmic1_gains_offset 0
+#define dmic2_gains_offset 2
+#define dmic3_gains_offset 4
+#define amic_gains_offset 6
+#define dl1_gains_offset 8
+#define dl2_gains_offset 10
+#define splitters_gains_offset 12
+#define mixer_dl1_offset 14
+#define mixer_dl2_offset 18
+#define mixer_echo_offset 22
+#define mixer_sdt_offset 24
+#define mixer_vxrec_offset 26
+#define mixer_audul_offset 30
+#define gain_unused_offset 34
+/*
+ * DMIC SRC 96->48
+ * the filter is changed depending on the decimatio ratio used (16/25/32/40)
+ * int32 cmem_src2_dmic [6] IIR with 2 coefs in the recursive part and 4 coefs
+ * in the direct part
+ */
+#define cmem_src2_dmic
+/*
+ * EANC coefficients
+ * structure of :
+ * 20 Q6.26 coef for the FIR
+ * 16 Q6.26 coef for the IIR
+ * 1 Q6.26 coef for Lambda
+ */
+#define cmem_eanc_coef_fir
+#define cmem_eanc_coef_iir
+#define cmem_eanc_coef_lambda
+/*
+ * EQUALIZERS - SDT - COEF AREA
+ * int24 cmem_equ(x) [8x2+1]
+ */
+#define cmem_equ1 C_EQU1_data_ADDR
+#define cmem_equ2 C_EQU2_data_ADDR
+#define cmem_equ3 C_EQU3_data_ADDR
+#define cmem_equ4 C_EQU4_data_ADDR
+#define cmem_sdt C_SDT_data_ADDR
+/*
+ * APS - COEF AREA
+ * int24 cmem_aps(x) [16]
+ */
+#define cmem_aps1
+#define cmem_aps2
+#define cmem_aps3
+/*
+ * DITHER - COEF AREA
+ * int24 cmem_dither(x) [4]
+ */
+#define cmem_dither
+#endif /* _ABE_FW_H_ */
diff --git a/sound/soc/omap/abe/abe_ini.c b/sound/soc/omap/abe/abe_ini.c
new file mode 100644
index 00000000000..c193393568b
--- /dev/null
+++ b/sound/soc/omap/abe/abe_ini.c
@@ -0,0 +1,2279 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include "abe_main.h"
+#include "abe_dm_addr.h"
+/*
+ * initialize the default values for call-backs to subroutines
+ * - FIFO IRQ call-backs for sequenced tasks
+ * - FIFO IRQ call-backs for audio player/recorders (ping-pong protocols)
+ * - Remote debugger interface
+ * - Error monitoring
+ * - Activity Tracing
+ */
+/**
+ * abe_hw_configuration
+ *
+ */
+void abe_hw_configuration()
+{
+ u32 atc_reg;
+ /* enables the DMAreq from AESS AESS_DMAENABLE_SET = 255 */
+ atc_reg = 0xFF;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_ATC, 0x60, &atc_reg, 4);
+ /* enables the MCU IRQ from AESS to Cortex A9 */
+ atc_reg = 0x01;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_ATC, 0x3C, &atc_reg, 4);
+}
+/**
+ * abe_build_scheduler_table
+ *
+ */
+void abe_build_scheduler_table()
+{
+ u16 i, n;
+ u8 *ptr;
+ char aUplinkMuxing[16];
+#define ABE_TASK_ID(ID) (D_tasksList_ADDR + sizeof(ABE_STask)*(ID))
+ /* LOAD OF THE TASKS' MULTIFRAME */
+ /* WARNING ON THE LOCATION OF IO_MM_DL WHICH IS PATCHED
+ IN "abe_init_io_tasks" */
+ for (ptr = (u8 *) &(MultiFrame[0][0]), i = 0;
+ i < sizeof(MultiFrame); i++)
+ *ptr++ = 0;
+ /* MultiFrame[0][0] = 0; */
+ /* MultiFrame[0][1] = 0; */
+ MultiFrame[0][2] = ABE_TASK_ID(C_ABE_FW_TASK_IO_VX_DL);
+ /* MultiFrame[0][3] = 0; */
+ /* MultiFrame[0][4] = 0; */
+ /* MultiFrame[0][5] = 0; */
+ /* MultiFrame[0][6] = 0; */
+ /* MultiFrame[0][7] = 0; */
+ /* MultiFrame[1][0] = 0; */
+ /* MultiFrame[1][1] = 0; */
+#define TASK_ASRC_VX_DL_SLT 1
+#define TASK_ASRC_VX_DL_IDX 2
+ MultiFrame[1][2] = ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_DL_8);
+#define TASK_VX_DL_SLT 1
+#define TASK_VX_DL_IDX 3
+ MultiFrame[1][3] = ABE_TASK_ID(C_ABE_FW_TASK_VX_DL_8_48);
+ /* MultiFrame[1][4] = 0; */
+ /* MultiFrame[1][5] = 0; */
+ MultiFrame[1][6] = ABE_TASK_ID(C_ABE_FW_TASK_DL2Mixer);
+ MultiFrame[1][7] = ABE_TASK_ID(C_ABE_FW_TASK_IO_VIB_DL);
+ MultiFrame[2][0] = ABE_TASK_ID(C_ABE_FW_TASK_DL1Mixer);
+ MultiFrame[2][1] = ABE_TASK_ID(C_ABE_FW_TASK_SDTMixer);
+ /* MultiFrame[2][2] = 0; */
+ /* MultiFrame[2][3] = 0; */
+ /* MultiFrame[2][4] = 0; */
+ MultiFrame[2][5] = ABE_TASK_ID(C_ABE_FW_TASK_IO_DMIC);
+ /* MultiFrame[2][6] = 0; */
+ /* MultiFrame[2][7] = 0; */
+ MultiFrame[3][0] = ABE_TASK_ID(C_ABE_FW_TASK_DL1_GAIN);
+ /* MultiFrame[3][1] = 0; */
+ /* MultiFrame[3][2] = 0; */
+ /* MultiFrame[3][3] = 0; */
+ /* MultiFrame[3][4] = 0; */
+ /* MultiFrame[3][5] = 0; */
+ MultiFrame[3][6] = ABE_TASK_ID(C_ABE_FW_TASK_DL2_GAIN);
+ MultiFrame[3][7] = ABE_TASK_ID(C_ABE_FW_TASK_DL2_EQ);
+ MultiFrame[4][0] = ABE_TASK_ID(C_ABE_FW_TASK_DL1_EQ);
+ /* MultiFrame[4][1] = 0; */
+ MultiFrame[4][2] = ABE_TASK_ID(C_ABE_FW_TASK_VXRECMixer);
+ MultiFrame[4][3] = ABE_TASK_ID(C_ABE_FW_TASK_VXREC_SPLIT);
+ /* MultiFrame[4][4] = 0; */
+ /* MultiFrame[4][5] = 0; */
+ MultiFrame[4][6] = ABE_TASK_ID(C_ABE_FW_TASK_VIBRA1);
+ MultiFrame[4][7] = ABE_TASK_ID(C_ABE_FW_TASK_VIBRA2);
+ MultiFrame[5][0] = 0;
+ MultiFrame[5][1] = ABE_TASK_ID(C_ABE_FW_TASK_EARP_48_96_LP);
+ MultiFrame[5][2] = ABE_TASK_ID(C_ABE_FW_TASK_IO_PDM_UL);
+ /* MultiFrame[5][3] = 0; */
+ /* MultiFrame[5][4] = 0; */
+ /* MultiFrame[5][5] = 0; */
+ /* MultiFrame[5][6] = 0; */
+ MultiFrame[5][7] = ABE_TASK_ID(C_ABE_FW_TASK_VIBRA_SPLIT);
+ MultiFrame[6][0] = ABE_TASK_ID(C_ABE_FW_TASK_EARP_48_96_LP);
+ /* MultiFrame[6][1] = 0; */
+ /* MultiFrame[6][2] = 0; */
+ /* MultiFrame[6][3] = 0; */
+ /* MultiFrame[6][4] = 0; */
+ MultiFrame[6][5] = ABE_TASK_ID(C_ABE_FW_TASK_EchoMixer);
+ /* MultiFrame[6][6] = 0; */
+ /* MultiFrame[6][7] = 0; */
+ MultiFrame[7][0] = ABE_TASK_ID(C_ABE_FW_TASK_IO_PDM_DL);
+ /* MultiFrame[7][1] = 0; */
+ MultiFrame[7][2] = ABE_TASK_ID(C_ABE_FW_TASK_BT_UL_SPLIT);
+ MultiFrame[7][3] = ABE_TASK_ID(C_ABE_FW_TASK_DBG_SYNC);
+ /* MultiFrame[7][4] = 0; */
+ MultiFrame[7][5] = ABE_TASK_ID(C_ABE_FW_TASK_ECHO_REF_SPLIT);
+ /* MultiFrame[7][6] = 0; */
+ /* MultiFrame[7][7] = 0; */
+ /* MultiFrame[8][0] = 0; */
+ /* MultiFrame[8][1] = 0; */
+ MultiFrame[8][2] = ABE_TASK_ID(C_ABE_FW_TASK_DMIC1_96_48_LP);
+ /* MultiFrame[8][3] = 0; */
+ MultiFrame[8][4] = ABE_TASK_ID(C_ABE_FW_TASK_DMIC1_SPLIT);
+ /* MultiFrame[8][5] = 0; */
+ /* MultiFrame[8][6] = 0; */
+ /* MultiFrame[8][7] = 0; */
+ /* MultiFrame[9][0] = 0; */
+ /* MultiFrame[9][1] = 0; */
+ MultiFrame[9][2] = ABE_TASK_ID(C_ABE_FW_TASK_DMIC2_96_48_LP);
+ /* MultiFrame[9][3] = 0; */
+ MultiFrame[9][4] = ABE_TASK_ID(C_ABE_FW_TASK_DMIC2_SPLIT);
+ /* MultiFrame[9][5] = 0; */
+ MultiFrame[9][6] = 0;
+ MultiFrame[9][7] = ABE_TASK_ID(C_ABE_FW_TASK_IHF_48_96_LP);
+ /* MultiFrame[10][0] = 0; */
+ /* MultiFrame[10][1] = 0; */
+ MultiFrame[10][2] = ABE_TASK_ID(C_ABE_FW_TASK_DMIC3_96_48_LP);
+ /* MultiFrame[10][3] = 0; */
+ MultiFrame[10][4] = ABE_TASK_ID(C_ABE_FW_TASK_DMIC3_SPLIT);
+ /* MultiFrame[10][5] = 0; */
+ /* MultiFrame[10][6] = 0; */
+ MultiFrame[10][7] = ABE_TASK_ID(C_ABE_FW_TASK_IHF_48_96_LP);
+ /* MultiFrame[11][0] = 0; */
+ /* MultiFrame[11][1] = 0; */
+ MultiFrame[11][2] = ABE_TASK_ID(C_ABE_FW_TASK_AMIC_96_48_LP);
+ /* MultiFrame[11][3] = 0; */
+ MultiFrame[11][4] = ABE_TASK_ID(C_ABE_FW_TASK_AMIC_SPLIT);
+ /* MultiFrame[11][5] = 0; */
+ /* MultiFrame[11][6] = 0; */
+ MultiFrame[11][7] = ABE_TASK_ID(C_ABE_FW_TASK_VIBRA_PACK);
+ /* MultiFrame[12][0] = 0; */
+ /* MultiFrame[12][1] = 0; */
+ /* MultiFrame[12][2] = 0; */
+ MultiFrame[12][3] = ABE_TASK_ID(C_ABE_FW_TASK_VX_UL_ROUTING);
+ MultiFrame[12][4] = ABE_TASK_ID(C_ABE_FW_TASK_ULMixer);
+#define TASK_VX_UL_SLT 12
+#define TASK_VX_UL_IDX 5
+ MultiFrame[12][5] = ABE_TASK_ID(C_ABE_FW_TASK_VX_UL_48_8);
+ /* MultiFrame[12][6] = 0; */
+ /* MultiFrame[12][7] = 0; */
+ /* MultiFrame[13][0] = 0; */
+ /* MultiFrame[13][1] = 0; */
+ MultiFrame[13][2] = ABE_TASK_ID(C_ABE_FW_TASK_MM_UL2_ROUTING);
+ MultiFrame[13][3] = ABE_TASK_ID(C_ABE_FW_TASK_SideTone);
+ /* MultiFrame[13][4] = 0; */
+ MultiFrame[13][5] = ABE_TASK_ID(C_ABE_FW_TASK_IO_BT_VX_DL);
+ /* MultiFrame[13][6] = 0; */
+ /* MultiFrame[13][7] = 0; */
+ /* MultiFrame[14][0] = 0; */
+ /* MultiFrame[14][1] = 0; */
+ /* MultiFrame[14][2] = 0; */
+ MultiFrame[14][3] = ABE_TASK_ID(C_ABE_FW_TASK_IO_DMIC);
+#define TASK_BT_DL_48_8_SLT 14
+#define TASK_BT_DL_48_8_IDX 4
+ MultiFrame[14][4] = ABE_TASK_ID(C_ABE_FW_TASK_BT_DL_48_8);
+ /* MultiFrame[14][5] = 0; */
+ /* MultiFrame[14][6] = 0; */
+ /* MultiFrame[14][7] = 0; */
+#define TASK_ASRC_BT_UL_SLT 15
+#define TASK_ASRC_BT_UL_IDX 6
+ MultiFrame[15][0] = ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_EXT_OUT);
+ /* MultiFrame[15][1] = 0; */
+ /* MultiFrame[15][2] = 0; */
+ MultiFrame[15][3] = ABE_TASK_ID(C_ABE_FW_TASK_IO_BT_VX_UL);
+ /* MultiFrame[15][4] = 0; */
+ /* MultiFrame[15][5] = 0; */
+ MultiFrame[15][6] = ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_UL_8);
+ /* MultiFrame[15][7] = 0; */
+ /* MultiFrame[16][0] = 0; */
+ /* MultiFrame[16][1] = 0; */
+#define TASK_ASRC_VX_UL_SLT 16
+#define TASK_ASRC_VX_UL_IDX 2
+ MultiFrame[16][2] = ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_UL_8);
+ MultiFrame[16][3] = ABE_TASK_ID(C_ABE_FW_TASK_IO_VX_UL);
+ /* MultiFrame[16][4] = 0; */
+ /* MultiFrame[16][5] = 0; */
+ /* MultiFrame[16][6] = 0; */
+ /* MultiFrame[16][7] = 0; */
+ /* MultiFrame[17][0] = 0; */
+ /* MultiFrame[17][1] = 0; */
+#define TASK_BT_UL_8_48_SLT 17
+#define TASK_BT_UL_8_48_IDX 2
+ MultiFrame[17][2] = ABE_TASK_ID(C_ABE_FW_TASK_BT_UL_8_48);
+ MultiFrame[17][3] = ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_UL2);
+ /* MultiFrame[17][4] = 0; */
+ /* MultiFrame[17][5] = 0; */
+ /* MultiFrame[17][6] = 0; */
+ /* MultiFrame[17][7] = 0; */
+#define TASK_IO_MM_DL_SLT 18
+#define TASK_IO_MM_DL_IDX 0
+ MultiFrame[18][0] = ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_DL);
+ /* MultiFrame[18][1] = 0; */
+ /* MultiFrame[18][2] = 0; */
+ /* MultiFrame[18][3] = 0; */
+ /* MultiFrame[18][4] = 0; */
+ /* MultiFrame[18][5] = 0; */
+#define TASK_ASRC_BT_DL_SLT 18
+#define TASK_ASRC_BT_DL_IDX 6
+ MultiFrame[18][6] = ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_DL_8);
+ /* MultiFrame[18][7] = 0; */
+ MultiFrame[19][0] = ABE_TASK_ID(C_ABE_FW_TASK_IO_PDM_DL);
+ /* MultiFrame[19][1] = 0 */
+ /* MultiFrame[19][2] = 0; */
+ /* MultiFrame[19][3] = 0; */
+ /* MultiFrame[19][4] = 0; */
+ /* MultiFrame[19][5] = 0; */
+ /* MM_UL is moved to OPP 100% */
+ MultiFrame[19][6] = ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_UL);
+ /* MultiFrame[19][7] = 0; */
+ MultiFrame[20][0] = ABE_TASK_ID(C_ABE_FW_TASK_IO_TONES_DL);
+ /* MultiFrame[20][1] = 0; */
+ /* MultiFrame[20][2] = 0; */
+ /* MultiFrame[20][3] = 0; */
+ /* MultiFrame[20][4] = 0; */
+ /* MultiFrame[20][5] = 0; */
+ MultiFrame[20][6] = ABE_TASK_ID(C_ABE_FW_TASK_ASRC_MM_EXT_IN);
+ /* MultiFrame[20][7] = 0; */
+ /* MultiFrame[21][0] = 0; */
+ MultiFrame[21][1] = ABE_TASK_ID(C_ABE_FW_TASK_DEBUGTRACE_VX_ASRCs);
+ /* MultiFrame[21][2] = 0; */
+ MultiFrame[21][3] = ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_EXT_IN);
+ /* MultiFrame[21][4] = 0; */
+ /* MultiFrame[21][5] = 0; */
+ /* MultiFrame[21][6] = 0; */
+ /* MultiFrame[21][7] = 0; */
+ /* MUST STAY ON SLOT 22 */
+ MultiFrame[22][0] = ABE_TASK_ID(C_ABE_FW_TASK_DEBUG_IRQFIFO);
+ MultiFrame[22][1] = ABE_TASK_ID(C_ABE_FW_TASK_INIT_FW_MEMORY);
+ MultiFrame[22][2] = 0;
+ /* MultiFrame[22][3] = 0; */
+ /* MM_EXT_IN_SPLIT task must be after IO_MM_EXT_IN and before
+ ASRC_MM_EXT_IN in order to manage OPP50 <-> transitions */
+ MultiFrame[22][4] = ABE_TASK_ID(C_ABE_FW_TASK_MM_EXT_IN_SPLIT);
+ /* MultiFrame[22][5] = 0; */
+ /* MultiFrame[22][6] = 0; */
+ /* MultiFrame[22][7] = 0; */
+ MultiFrame[23][0] = ABE_TASK_ID(C_ABE_FW_TASK_GAIN_UPDATE);
+ /* MultiFrame[23][1] = 0; */
+ /* MultiFrame[23][2] = 0; */
+ /* MultiFrame[23][3] = 0; */
+ /* MultiFrame[23][4] = 0; */
+ /* MultiFrame[23][5] = 0; */
+ /* MultiFrame[23][6] = 0; */
+ /* MultiFrame[23][7] = 0; */
+ /* MultiFrame[24][0] = 0; */
+ /* MultiFrame[24][1] = 0; */
+ /* MultiFrame[24][2] = 0; */
+ /* MultiFrame[24][3] = 0; */
+ /* MultiFrame[24][4] = 0; */
+ /* MultiFrame[24][5] = 0; */
+ /* MultiFrame[24][6] = 0; */
+ /* MultiFrame[24][7] = 0; */
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, D_multiFrame_ADDR,
+ (u32 *) MultiFrame, sizeof(MultiFrame));
+ /* reset the uplink router */
+ n = (D_aUplinkRouting_sizeof) >> 1;
+ for (i = 0; i < n; i++)
+ aUplinkMuxing[i] = ZERO_labelID;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, D_aUplinkRouting_ADDR,
+ (u32 *) aUplinkMuxing, sizeof(aUplinkMuxing));
+}
+/**
+ * abe_init_atc
+ * @id: ABE port ID
+ *
+ * load the DMEM ATC/AESS descriptors
+ */
+void abe_init_atc(u32 id)
+{
+ u8 iter;
+ s32 datasize;
+#define JITTER_MARGIN 4
+ /* load default values of the descriptor */
+ atc_desc.rdpt = atc_desc.wrpt = atc_desc.irqdest = atc_desc.cberr = 0;
+ atc_desc.desen = atc_desc.nw = 0;
+ atc_desc.reserved0 = atc_desc.reserved1 = atc_desc.reserved2 = 0;
+ atc_desc.srcid = atc_desc.destid = atc_desc.badd = atc_desc.iter =
+ atc_desc.cbsize = 0;
+ datasize = abe_dma_port_iter_factor(&((abe_port[id]).format));
+ iter = (u8) abe_dma_port_iteration(&((abe_port[id]).format));
+ /* if the ATC FIFO is too small there will be two ABE firmware
+ utasks to do the copy this happems on DMIC and MCPDMDL */
+ /* VXDL_8kMono = 4 = 2 + 2x1 */
+ /* VXDL_16kstereo = 12 = 8 + 2x2 */
+ /* MM_DL_1616 = 14 = 12 + 2x1 */
+ /* DMIC = 84 = 72 + 2x6 */
+ /* VXUL_8kMono = 2 */
+ /* VXUL_16kstereo = 4 */
+ /* MM_UL2_Stereo = 4 */
+ /* PDMDL = 12 */
+ /* IN from AESS point of view */
+ if (abe_port[id].protocol.direction == ABE_ATC_DIRECTION_IN)
+ if (iter + 2 * datasize > 126)
+ atc_desc.wrpt =
+ (iter >> 1) + ((JITTER_MARGIN - 1) * datasize);
+ else
+ atc_desc.wrpt = iter + ((JITTER_MARGIN - 1) * datasize);
+ else
+ atc_desc.wrpt = 0 + ((JITTER_MARGIN + 1) * datasize);
+ switch ((abe_port[id]).protocol.protocol_switch) {
+ case SLIMBUS_PORT_PROT:
+ atc_desc.cbdir = (abe_port[id]).protocol.direction;
+ atc_desc.cbsize =
+ (abe_port[id]).protocol.p.prot_slimbus.buf_size;
+ atc_desc.badd =
+ ((abe_port[id]).protocol.p.prot_slimbus.buf_addr1) >> 4;
+ atc_desc.iter = (abe_port[id]).protocol.p.prot_slimbus.iter;
+ atc_desc.srcid =
+ abe_atc_srcid[(abe_port[id]).protocol.p.prot_slimbus.
+ desc_addr1 >> 3];
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ (abe_port[id]).protocol.p.prot_slimbus.
+ desc_addr1, (u32 *) &atc_desc,
+ sizeof(atc_desc));
+ atc_desc.badd =
+ (abe_port[id]).protocol.p.prot_slimbus.buf_addr2;
+ atc_desc.srcid =
+ abe_atc_srcid[(abe_port[id]).protocol.p.prot_slimbus.
+ desc_addr2 >> 3];
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ (abe_port[id]).protocol.p.prot_slimbus.
+ desc_addr2, (u32 *) &atc_desc,
+ sizeof(atc_desc));
+ break;
+ case SERIAL_PORT_PROT:
+ atc_desc.cbdir = (abe_port[id]).protocol.direction;
+ atc_desc.cbsize =
+ (abe_port[id]).protocol.p.prot_serial.buf_size;
+ atc_desc.badd =
+ ((abe_port[id]).protocol.p.prot_serial.buf_addr) >> 4;
+ atc_desc.iter = (abe_port[id]).protocol.p.prot_serial.iter;
+ atc_desc.srcid =
+ abe_atc_srcid[(abe_port[id]).protocol.p.prot_serial.
+ desc_addr >> 3];
+ atc_desc.destid =
+ abe_atc_dstid[(abe_port[id]).protocol.p.prot_serial.
+ desc_addr >> 3];
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ (abe_port[id]).protocol.p.prot_serial.desc_addr,
+ (u32 *) &atc_desc, sizeof(atc_desc));
+ break;
+ case DMIC_PORT_PROT:
+ atc_desc.cbdir = ABE_ATC_DIRECTION_IN;
+ atc_desc.cbsize = (abe_port[id]).protocol.p.prot_dmic.buf_size;
+ atc_desc.badd =
+ ((abe_port[id]).protocol.p.prot_dmic.buf_addr) >> 4;
+ atc_desc.iter = DMIC_ITER;
+ atc_desc.srcid = abe_atc_srcid[ABE_ATC_DMIC_DMA_REQ];
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ (ABE_ATC_DMIC_DMA_REQ*ATC_SIZE),
+ (u32 *) &atc_desc, sizeof(atc_desc));
+ break;
+ case MCPDMDL_PORT_PROT:
+ atc_desc.cbdir = ABE_ATC_DIRECTION_OUT;
+ atc_desc.cbsize =
+ (abe_port[id]).protocol.p.prot_mcpdmdl.buf_size;
+ atc_desc.badd =
+ ((abe_port[id]).protocol.p.prot_mcpdmdl.buf_addr) >> 4;
+ atc_desc.iter = MCPDM_DL_ITER;
+ atc_desc.destid = abe_atc_dstid[ABE_ATC_MCPDMDL_DMA_REQ];
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ (ABE_ATC_MCPDMDL_DMA_REQ*ATC_SIZE),
+ (u32 *) &atc_desc, sizeof(atc_desc));
+ break;
+ case MCPDMUL_PORT_PROT:
+ atc_desc.cbdir = ABE_ATC_DIRECTION_IN;
+ atc_desc.cbsize =
+ (abe_port[id]).protocol.p.prot_mcpdmul.buf_size;
+ atc_desc.badd =
+ ((abe_port[id]).protocol.p.prot_mcpdmul.buf_addr) >> 4;
+ atc_desc.iter = MCPDM_UL_ITER;
+ atc_desc.srcid = abe_atc_srcid[ABE_ATC_MCPDMUL_DMA_REQ];
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ (ABE_ATC_MCPDMUL_DMA_REQ*ATC_SIZE),
+ (u32 *) &atc_desc, sizeof(atc_desc));
+ break;
+ case PINGPONG_PORT_PROT:
+ /* software protocol, nothing to do on ATC */
+ break;
+ case DMAREQ_PORT_PROT:
+ atc_desc.cbdir = (abe_port[id]).protocol.direction;
+ atc_desc.cbsize =
+ (abe_port[id]).protocol.p.prot_dmareq.buf_size;
+ atc_desc.badd =
+ ((abe_port[id]).protocol.p.prot_dmareq.buf_addr) >> 4;
+ /* CBPr needs ITER=1. this is the eDMA job to do the iterations */
+ atc_desc.iter = 1;
+ /* input from ABE point of view */
+ if (abe_port[id].protocol.direction == ABE_ATC_DIRECTION_IN) {
+ /* atc_atc_desc.rdpt = 127; */
+ /* atc_atc_desc.wrpt = 0; */
+ atc_desc.srcid = abe_atc_srcid
+ [(abe_port[id]).protocol.p.prot_dmareq.
+ desc_addr >> 3];
+ } else {
+ /* atc_atc_desc.rdpt = 0; */
+ /* atc_atc_desc.wrpt = 127; */
+ atc_desc.destid = abe_atc_dstid
+ [(abe_port[id]).protocol.p.prot_dmareq.
+ desc_addr >> 3];
+ }
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ (abe_port[id]).protocol.p.prot_dmareq.desc_addr,
+ (u32 *) &atc_desc, sizeof(atc_desc));
+ break;
+ }
+}
+/**
+ * abe_init_dma_t
+ * @ id: ABE port ID
+ * @ prot: protocol being used
+ *
+ * load the dma_t with physical information from AE memory mapping
+ */
+void abe_init_dma_t(u32 id, abe_port_protocol_t *prot)
+{
+ abe_dma_t_offset dma;
+ u32 idx;
+ /* default dma_t points to address 0000... */
+ dma.data = 0;
+ dma.iter = 0;
+ switch (prot->protocol_switch) {
+ case PINGPONG_PORT_PROT:
+ for (idx = 0; idx < 32; idx++) {
+ if (((prot->p).prot_pingpong.irq_data) ==
+ (u32) (1 << idx))
+ break;
+ }
+ (prot->p).prot_dmareq.desc_addr =
+ ((CBPr_DMA_RTX0 + idx)*ATC_SIZE);
+ /* translate byte address/size in DMEM words */
+ dma.data = (prot->p).prot_pingpong.buf_addr >> 2;
+ dma.iter = (prot->p).prot_pingpong.buf_size >> 2;
+ break;
+ case DMAREQ_PORT_PROT:
+ for (idx = 0; idx < 32; idx++) {
+ if (((prot->p).prot_dmareq.dma_data) ==
+ (u32) (1 << idx))
+ break;
+ }
+ dma.data = (CIRCULAR_BUFFER_PERIPHERAL_R__0 + (idx << 2));
+ dma.iter = (prot->p).prot_dmareq.iter;
+ (prot->p).prot_dmareq.desc_addr =
+ ((CBPr_DMA_RTX0 + idx)*ATC_SIZE);
+ break;
+ case SLIMBUS_PORT_PROT:
+ case SERIAL_PORT_PROT:
+ case DMIC_PORT_PROT:
+ case MCPDMDL_PORT_PROT:
+ case MCPDMUL_PORT_PROT:
+ default:
+ break;
+ }
+ /* upload the dma type */
+ abe_port[id].dma = dma;
+}
+/**
+ * abe_disenable_dma_request
+ * Parameter:
+ * Operations:
+ * Return value:
+ */
+void abe_disable_enable_dma_request(u32 id, u32 on_off)
+{
+ u8 desc_third_word[4], irq_dmareq_field;
+ u32 sio_desc_address;
+ u32 struct_offset;
+ if (abe_port[id].protocol.protocol_switch == PINGPONG_PORT_PROT) {
+ irq_dmareq_field =
+ (u8) (on_off *
+ abe_port[id].protocol.p.prot_pingpong.irq_data);
+ sio_desc_address = D_PingPongDesc_ADDR;
+ struct_offset = (u32) &(desc_pp.data_size) - (u32) &(desc_pp);
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ sio_desc_address + struct_offset,
+ (u32 *) desc_third_word, 4);
+ desc_third_word[2] = irq_dmareq_field;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ sio_desc_address + struct_offset,
+ (u32 *) desc_third_word, 4);
+ } else {
+ /* serial interface: sync ATC with Firmware activity */
+ sio_desc_address =
+ dmem_port_descriptors +
+ (id * sizeof(ABE_SIODescriptor));
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ sio_desc_address, (u32 *) &sio_desc,
+ sizeof(sio_desc));
+ if (on_off) {
+ sio_desc.atc_irq_data =
+ (u8) abe_port[id].protocol.p.prot_dmareq.
+ dma_data;
+ sio_desc.on_off = 0x80;
+ } else {
+ sio_desc.atc_irq_data = 0;
+ sio_desc.on_off = 0;
+ }
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ sio_desc_address, (u32 *) &sio_desc,
+ sizeof(sio_desc));
+ }
+}
+void abe_enable_dma_request(u32 id)
+{
+ abe_disable_enable_dma_request(id, 1);
+}
+/**
+ * abe_disable_dma_request
+ *
+ * Parameter:
+ * Operations:
+ * Return value:
+ *
+ */
+void abe_disable_dma_request(u32 id)
+{
+ abe_disable_enable_dma_request(id, 0);
+}
+/**
+ * abe_enable_atc
+ * Parameter:
+ * Operations:
+ * Return value:
+ */
+void abe_enable_atc(u32 id)
+{
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ (abe_port[id]).protocol.p.prot_dmareq.desc_addr,
+ (u32 *) &atc_desc, sizeof(atc_desc));
+ atc_desc.desen = 1;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ (abe_port[id]).protocol.p.prot_dmareq.desc_addr,
+ (u32 *) &atc_desc, sizeof(atc_desc));
+}
+/**
+ * abe_disable_atc
+ * Parameter:
+ * Operations:
+ * Return value:
+ */
+void abe_disable_atc(u32 id)
+{
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ (abe_port[id]).protocol.p.prot_dmareq.desc_addr,
+ (u32 *) &atc_desc, sizeof(atc_desc));
+ atc_desc.desen = 0;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ (abe_port[id]).protocol.p.prot_dmareq.desc_addr,
+ (u32 *) &atc_desc, sizeof(atc_desc));
+}
+/**
+ * abe_init_io_tasks
+ * @prot : protocol being used
+ *
+ * load the micro-task parameters doing to DMEM <==> SMEM data moves
+ *
+ * I/O descriptors input parameters :
+ * For Read from DMEM usually THR1/THR2 = X+1/X-1
+ * For Write to DMEM usually THR1/THR2 = 2/0
+ * UP_1/2 =X+1/X-1
+ */
+void abe_init_io_tasks(u32 id, abe_data_format_t *format,
+ abe_port_protocol_t *prot)
+{
+ u32 x_io, direction, iter_samples, smem1, smem2, smem3, io_sub_id,
+ io_flag;
+ u32 copy_func_index, before_func_index, after_func_index;
+ u32 dmareq_addr, dmareq_field;
+ u32 sio_desc_address, datasize, iter, nsamp, datasize2, dOppMode32;
+ u32 atc_ptr_saved, atc_ptr_saved2, copy_func_index1;
+ u32 copy_func_index2, atc_desc_address1, atc_desc_address2;
+ if (prot->protocol_switch == PINGPONG_PORT_PROT) {
+ /* ping_pong is only supported on MM_DL */
+ if (MM_DL_PORT != id) {
+ abe_dbg_param |= ERR_API;
+ abe_dbg_error_log(ABE_PARAMETER_ERROR);
+ }
+ smem1 = smem_mm_dl;
+ copy_func_index = (u8) abe_dma_port_copy_subroutine_id(id);
+ dmareq_addr = abe_port[id].protocol.p.prot_pingpong.irq_addr;
+ dmareq_field = abe_port[id].protocol.p.prot_pingpong.irq_data;
+ datasize = abe_dma_port_iter_factor(format);
+ /* number of "samples" either mono or stereo */
+ iter = abe_dma_port_iteration(format);
+ iter_samples = (iter / datasize);
+ /* load the IO descriptor */
+ /* no drift */
+ desc_pp.drift_ASRC = 0;
+ /* no drift */
+ desc_pp.drift_io = 0;
+ desc_pp.hw_ctrl_addr = (u16) dmareq_addr;
+ desc_pp.copy_func_index = (u8) copy_func_index;
+ desc_pp.smem_addr = (u8) smem1;
+ /* DMA req 0 is used for CBPr0 */
+ desc_pp.atc_irq_data = (u8) dmareq_field;
+ /* size of block transfer */
+ desc_pp.x_io = (u8) iter_samples;
+ desc_pp.data_size = (u8) datasize;
+ /* address comunicated in Bytes */
+ desc_pp.workbuff_BaseAddr =
+ (u16) (abe_base_address_pingpong[1]);
+ /* size comunicated in XIO sample */
+ desc_pp.workbuff_Samples = 0;
+ desc_pp.nextbuff0_BaseAddr =
+ (u16) (abe_base_address_pingpong[0]);
+ desc_pp.nextbuff1_BaseAddr =
+ (u16) (abe_base_address_pingpong[1]);
+ if (dmareq_addr == ABE_DMASTATUS_RAW) {
+ desc_pp.nextbuff0_Samples =
+ (u16) ((abe_size_pingpong >> 2) / datasize);
+ desc_pp.nextbuff1_Samples =
+ (u16) ((abe_size_pingpong >> 2) / datasize);
+ } else {
+ desc_pp.nextbuff0_Samples = 0;
+ desc_pp.nextbuff1_Samples = 0;
+ }
+ /* next buffer to send is B1, first IRQ fills B0 */
+ desc_pp.counter = 0;
+ /* send a DMA req to fill B0 with N samples
+ abe_block_copy (COPY_FROM_HOST_TO_ABE, ABE_ATC, ABE_DMASTATUS_RAW,
+ &(abe_port[id].protocol.p.prot_pingpong.irq_data), 4); */
+ sio_desc_address = D_PingPongDesc_ADDR;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ sio_desc_address, (u32 *) &desc_pp,
+ sizeof(desc_pp));
+ } else {
+ io_sub_id = dmareq_addr = ABE_DMASTATUS_RAW;
+ dmareq_field = 0;
+ atc_desc_address1 = atc_desc_address2 = 0;
+ /* default: repeat of the last downlink samples in case of
+ DMA errors, (disable=0x00) */
+ io_flag = 0xFF;
+ datasize2 = datasize = abe_dma_port_iter_factor(format);
+ x_io = (u8) abe_dma_port_iteration(format);
+ nsamp = (x_io / datasize);
+ atc_ptr_saved2 = atc_ptr_saved = DMIC_ATC_PTR_labelID + id;
+ smem1 = abe_port[id].smem_buffer1;
+ smem3 = smem2 = abe_port[id].smem_buffer2;
+ copy_func_index1 = (u8) abe_dma_port_copy_subroutine_id(id);
+ before_func_index = after_func_index =
+ copy_func_index2 = NULL_COPY_CFPID;
+ switch (prot->protocol_switch) {
+ case DMIC_PORT_PROT:
+ /* DMIC port is read in two steps */
+ x_io = x_io >> 1;
+ nsamp = nsamp >> 1;
+ atc_desc_address1 = (ABE_ATC_DMIC_DMA_REQ*ATC_SIZE);
+ io_sub_id = IO_IP_CFPID;
+ break;
+ case MCPDMDL_PORT_PROT:
+ /* PDMDL port is written to in two steps */
+ x_io = x_io >> 1;
+ atc_desc_address1 =
+ (ABE_ATC_MCPDMDL_DMA_REQ*ATC_SIZE);
+ io_sub_id = IO_IP_CFPID;
+ break;
+ case MCPDMUL_PORT_PROT:
+ atc_desc_address1 =
+ (ABE_ATC_MCPDMUL_DMA_REQ*ATC_SIZE);
+ io_sub_id = IO_IP_CFPID;
+ break;
+ case SLIMBUS_PORT_PROT:
+ atc_desc_address1 =
+ abe_port[id].protocol.p.prot_slimbus.desc_addr1;
+ atc_desc_address2 =
+ abe_port[id].protocol.p.prot_slimbus.desc_addr2;
+ copy_func_index2 = NULL_COPY_CFPID;
+ /* @@@@@@
+ #define SPLIT_SMEM_CFPID 9
+ #define MERGE_SMEM_CFPID 10
+ #define SPLIT_TDM_12_CFPID 11
+ #define MERGE_TDM_12_CFPID 12
+ */
+ io_sub_id = IO_IP_CFPID;
+ break;
+ case SERIAL_PORT_PROT: /* McBSP/McASP */
+ atc_desc_address1 =
+ (s16) abe_port[id].protocol.p.prot_serial.
+ desc_addr;
+ io_sub_id = IO_IP_CFPID;
+ break;
+ case DMAREQ_PORT_PROT: /* DMA w/wo CBPr */
+ dmareq_addr =
+ abe_port[id].protocol.p.prot_dmareq.dma_addr;
+ dmareq_field = 0;
+ atc_desc_address1 =
+ abe_port[id].protocol.p.prot_dmareq.desc_addr;
+ io_sub_id = IO_IP_CFPID;
+ break;
+ }
+ /* special situation of the PING_PONG protocol which has its own SIO descriptor format */
+ /*
+ Sequence of operations on ping-pong buffers B0/B1
+ ----------------------------------------------------------------- time --------------------------------------------->>>>
+ Host Application is ready to send data from DDR to B0
+ SDMA is initialized from "abe_connect_irq_ping_pong_port" to B0
+ FIRMWARE starts with #12 B1 data, sends IRQ/DMAreq sens #pong B1 data sends IRQ/DMAreq sends #ping B0 v sends B1 samples
+ ARM / SDMA | fills B0 | fills B1 ... | fills B0 ...
+ Counter 0 1 2 3
+ */
+ if (MM_UL_PORT == id) {
+ copy_func_index1 = COPY_MM_UL_CFPID;
+ before_func_index = ROUTE_MM_UL_CFPID;
+ }
+ /* check for 8kHz/16kHz */
+ if (VX_DL_PORT == id) {
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ D_multiFrame_ADDR, (u32 *) MultiFrame,
+ sizeof(MultiFrame));
+ if (abe_port[id].format.f == 8000) {
+ MultiFrame[TASK_ASRC_VX_DL_SLT]
+ [TASK_ASRC_VX_DL_IDX] =
+ ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_DL_8);
+ MultiFrame[TASK_VX_DL_SLT][TASK_VX_DL_IDX] =
+ ABE_TASK_ID(C_ABE_FW_TASK_VX_DL_8_48);
+ /*Voice_8k_DL_labelID */
+ smem1 = IO_VX_DL_ASRC_labelID;
+ } else {
+ MultiFrame[TASK_ASRC_VX_DL_SLT]
+ [TASK_ASRC_VX_DL_IDX] =
+ ABE_TASK_ID
+ (C_ABE_FW_TASK_ASRC_VX_DL_16);
+ MultiFrame[TASK_VX_DL_SLT][TASK_VX_DL_IDX] =
+ ABE_TASK_ID(C_ABE_FW_TASK_VX_DL_16_48);
+ /* Voice_16k_DL_labelID */
+ smem1 = IO_VX_DL_ASRC_labelID;
+ }
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ D_multiFrame_ADDR, (u32 *) MultiFrame,
+ sizeof(MultiFrame));
+ }
+ /* check for 8kHz/16kHz */
+ if (VX_UL_PORT == id) {
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ D_multiFrame_ADDR, (u32 *) MultiFrame,
+ sizeof(MultiFrame));
+ if (abe_port[id].format.f == 8000) {
+ MultiFrame[TASK_ASRC_VX_UL_SLT]
+ [TASK_ASRC_VX_UL_IDX] =
+ ABE_TASK_ID(C_ABE_FW_TASK_ASRC_VX_UL_8);
+ MultiFrame[TASK_VX_UL_SLT][TASK_VX_UL_IDX] =
+ ABE_TASK_ID(C_ABE_FW_TASK_VX_UL_48_8);
+ /* MultiFrame[TASK_ECHO_SLT][TASK_ECHO_IDX] =
+ ABE_TASK_ID(C_ABE_FW_TASK_ECHO_REF_48_8); */
+ smem1 = Voice_8k_UL_labelID;
+ } else {
+ MultiFrame[TASK_ASRC_VX_UL_SLT]
+ [TASK_ASRC_VX_UL_IDX] =
+ ABE_TASK_ID
+ (C_ABE_FW_TASK_ASRC_VX_UL_16);
+ MultiFrame[TASK_VX_UL_SLT][TASK_VX_UL_IDX] =
+ ABE_TASK_ID(C_ABE_FW_TASK_VX_UL_48_16);
+ /* MultiFrame[TASK_ECHO_SLT][TASK_ECHO_IDX] =
+ ABE_TASK_ID(C_ABE_FW_TASK_ECHO_REF_48_16); */
+ smem1 = Voice_16k_UL_labelID;
+ }
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ D_multiFrame_ADDR, (u32 *) MultiFrame,
+ sizeof(MultiFrame));
+ }
+ /* check for 8kHz/16kHz */
+ if (BT_VX_DL_PORT == id) {
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ D_multiFrame_ADDR, (u32 *) MultiFrame,
+ sizeof(MultiFrame));
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ D_maxTaskBytesInSlot_ADDR, &dOppMode32,
+ sizeof(u32));
+ if (abe_port[id].format.f == 8000) {
+ MultiFrame[TASK_ASRC_BT_DL_SLT]
+ [TASK_ASRC_BT_DL_IDX] =
+ ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_DL_8);
+ if (dOppMode32 == DOPPMODE32_OPP100) {
+ MultiFrame[TASK_BT_DL_48_8_SLT]
+ [TASK_BT_DL_48_8_IDX] =
+ ABE_TASK_ID
+ (C_ABE_FW_TASK_BT_DL_48_8_OPP100);
+ smem1 = BT_DL_8k_opp100_labelID;
+ } else {
+ MultiFrame[TASK_BT_DL_48_8_SLT]
+ [TASK_BT_DL_48_8_IDX] =
+ ABE_TASK_ID
+ (C_ABE_FW_TASK_BT_DL_48_8);
+ smem1 = BT_DL_8k_labelID;
+ }
+ } else {
+ MultiFrame[TASK_ASRC_BT_DL_SLT]
+ [TASK_ASRC_BT_DL_IDX] =
+ ABE_TASK_ID
+ (C_ABE_FW_TASK_ASRC_BT_DL_16);
+ if (dOppMode32 == DOPPMODE32_OPP100) {
+ MultiFrame[TASK_BT_DL_48_8_SLT]
+ [TASK_BT_DL_48_8_IDX] =
+ ABE_TASK_ID
+ (C_ABE_FW_TASK_BT_DL_48_16_OPP100);
+ smem1 = BT_DL_16k_opp100_labelID;
+ } else {
+ MultiFrame[TASK_BT_DL_48_8_SLT]
+ [TASK_BT_DL_48_8_IDX] =
+ ABE_TASK_ID
+ (C_ABE_FW_TASK_BT_DL_48_16);
+ smem1 = BT_DL_16k_labelID;
+ }
+ }
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ D_multiFrame_ADDR, (u32 *) MultiFrame,
+ sizeof(MultiFrame));
+ }
+ /* check for 8kHz/16kHz */
+ if (BT_VX_UL_PORT == id) {
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ D_multiFrame_ADDR, (u32 *) MultiFrame,
+ sizeof(MultiFrame));
+ /* set the SMEM buffer -- programming sequence */
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ D_maxTaskBytesInSlot_ADDR, &dOppMode32,
+ sizeof(u32));
+ if (abe_port[id].format.f == 8000) {
+ MultiFrame[TASK_ASRC_BT_UL_SLT]
+ [TASK_ASRC_BT_UL_IDX] =
+ ABE_TASK_ID(C_ABE_FW_TASK_ASRC_BT_UL_8);
+ MultiFrame[TASK_BT_UL_8_48_SLT]
+ [TASK_BT_UL_8_48_IDX] =
+ ABE_TASK_ID(C_ABE_FW_TASK_BT_UL_8_48);
+ if (dOppMode32 == DOPPMODE32_OPP100)
+ /* ASRC input buffer, size 40 */
+ smem1 = smem_bt_vx_ul_opp100;
+ else
+ /* at OPP 50 without ASRC */
+ smem1 = BT_UL_8k_labelID;
+ } else {
+ MultiFrame[TASK_ASRC_BT_UL_SLT]
+ [TASK_ASRC_BT_UL_IDX] =
+ ABE_TASK_ID
+ (C_ABE_FW_TASK_ASRC_BT_UL_16);
+ MultiFrame[TASK_BT_UL_8_48_SLT]
+ [TASK_BT_UL_8_48_IDX] =
+ ABE_TASK_ID(C_ABE_FW_TASK_BT_UL_16_48);
+ if (dOppMode32 == DOPPMODE32_OPP100)
+ /* ASRC input buffer, size 40 */
+ smem1 = smem_bt_vx_ul_opp100;
+ else
+ /* at OPP 50 without ASRC */
+ smem1 = BT_UL_16k_labelID;
+ }
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ D_multiFrame_ADDR, (u32 *) MultiFrame,
+ sizeof(MultiFrame));
+ }
+ if (MM_DL_PORT == id) {
+ /* check for CBPr / serial_port / Ping-pong access */
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ D_multiFrame_ADDR, (u32 *) MultiFrame,
+ sizeof(MultiFrame));
+ MultiFrame[TASK_IO_MM_DL_SLT][TASK_IO_MM_DL_IDX] =
+ ABE_TASK_ID(C_ABE_FW_TASK_IO_MM_DL);
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ D_multiFrame_ADDR, (u32 *) MultiFrame,
+ sizeof(MultiFrame));
+ smem1 = smem_mm_dl;
+ }
+ if (MM_EXT_IN_PORT == id) {
+ /* set the SMEM buffer -- programming sequence */
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ D_maxTaskBytesInSlot_ADDR, &dOppMode32,
+ sizeof(u32));
+ if (dOppMode32 == DOPPMODE32_OPP100)
+ /* ASRC input buffer, size 40 */
+ smem1 = smem_mm_ext_in_opp100;
+ else
+ /* at OPP 50 without ASRC */
+ smem1 = smem_mm_ext_in_opp50;
+ }
+ if (abe_port[id].protocol.direction == ABE_ATC_DIRECTION_IN)
+ direction = 0;
+ else
+ /* offset of the write pointer in the ATC descriptor */
+ direction = 3;
+ sio_desc.drift_ASRC = 0;
+ sio_desc.drift_io = 0;
+ sio_desc.io_type_idx = (u8) io_sub_id;
+ sio_desc.samp_size = (u8) datasize;
+ sio_desc.hw_ctrl_addr = (u16) (dmareq_addr << 2);
+ sio_desc.atc_irq_data = (u8) dmareq_field;
+ sio_desc.flow_counter = (u16) 0;
+ sio_desc.direction_rw = (u8) direction;
+ sio_desc.repeat_last_samp = (u8) io_flag;
+ sio_desc.nsamp = (u8) nsamp;
+ sio_desc.x_io = (u8) x_io;
+ /* set ATC ON */
+ sio_desc.on_off = 0x80;
+ sio_desc.split_addr1 = (u16) smem1;
+ sio_desc.split_addr2 = (u16) smem2;
+ sio_desc.split_addr3 = (u16) smem3;
+ sio_desc.before_f_index = (u8) before_func_index;
+ sio_desc.after_f_index = (u8) after_func_index;
+ sio_desc.smem_addr1 = (u16) smem1;
+ sio_desc.atc_address1 = (u16) atc_desc_address1;
+ sio_desc.atc_pointer_saved1 = (u16) atc_ptr_saved;
+ sio_desc.data_size1 = (u8) datasize;
+ sio_desc.copy_f_index1 = (u8) copy_func_index1;
+ sio_desc.smem_addr2 = (u16) smem2;
+ sio_desc.atc_address2 = (u16) atc_desc_address2;
+ sio_desc.atc_pointer_saved2 = (u16) atc_ptr_saved2;
+ sio_desc.data_size2 = (u8) datasize2;
+ sio_desc.copy_f_index2 = (u8) copy_func_index2;
+ sio_desc_address = dmem_port_descriptors + (id *
+ sizeof
+ (ABE_SIODescriptor));
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ sio_desc_address, (u32 *) &sio_desc,
+ sizeof(sio_desc));
+ }
+}
+/**
+ * abe_enable_pp_io_task
+ * @id: port_id
+ *
+ *
+ */
+void abe_enable_pp_io_task(u32 id)
+{
+ /* MM_DL managed in ping-pong */
+ if (MM_DL_PORT == id) {
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ D_multiFrame_ADDR, (u32 *) MultiFrame,
+ sizeof(MultiFrame));
+ MultiFrame[TASK_IO_MM_DL_SLT][TASK_IO_MM_DL_IDX] =
+ ABE_TASK_ID(C_ABE_FW_TASK_IO_PING_PONG);
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ D_multiFrame_ADDR, (u32 *) MultiFrame,
+ sizeof(MultiFrame));
+ }
+ /* ping_pong is only supported on MM_DL */
+ else {
+ abe_dbg_param |= ERR_API;
+ abe_dbg_error_log(ABE_PARAMETER_ERROR);
+ }
+}
+/**
+ * abe_disable_pp_io_task
+ * @id: port_id
+ *
+ *
+ */
+void abe_disable_pp_io_task(u32 id)
+{
+ /* MM_DL managed in ping-pong */
+ if (MM_DL_PORT == id) {
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM,
+ D_multiFrame_ADDR, (u32 *) MultiFrame,
+ sizeof(MultiFrame));
+ MultiFrame[TASK_IO_MM_DL_SLT][TASK_IO_MM_DL_IDX] = 0;
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ D_multiFrame_ADDR, (u32 *) MultiFrame,
+ sizeof(MultiFrame));
+ }
+ /* ping_pong is only supported on MM_DL */
+ else {
+ abe_dbg_param |= ERR_API;
+ abe_dbg_error_log(ABE_PARAMETER_ERROR);
+ }
+}
+/**
+ * abe_init_dmic
+ * @x: d
+ *
+ *
+ */
+void abe_init_dmic(u32 x)
+{
+}
+/**
+ * abe_init_mcpdm
+ * @x: d
+ *
+ */
+void abe_init_mcpdm(u32 x)
+{
+}
+/**
+ * abe_reset_feature
+ * @x: index of the feature to be initialized
+ *
+ * reload the configuration
+ */
+void abe_reset_one_feature(u32 x)
+{
+ all_feature[x] = all_feature_init[x]; /* load default fields */
+ /* abe_call_subroutine ((all_feature[x]).disable_feature, NOPARAMETER,
+ NOPARAMETER, NOPARAMETER, NOPARAMETER); */
+}
+/**
+ * abe_reset_all_feature
+ *
+ * load default configuration for all features
+ * struct {
+ * uint16 load_default_data;
+ * uint16 read_parameter;
+ * uint16 write_parameter;
+ * uint16 running_status;
+ * uint16 fw_input_buffer_address;
+ * uint16 fw_output_buffer_address;
+ * uint16 fw_scheduler_slot_position;
+ * uint16 fw_scheduler_subslot_position;
+ * uint16 min_opp;
+ * char name[NBCHARFEATURENAME];
+ * } abe_feature_t;
+ */
+void abe_reset_all_features(void)
+{
+ u16 i;
+ for (i = 0; i < MAXNBFEATURE; i++)
+ abe_reset_one_feature(i);
+}
+/**
+ * abe_reset_all_ports
+ *
+ * load default configuration for all features
+ */
+void abe_reset_all_ports(void)
+{
+ u16 i;
+ for (i = 0; i < LAST_PORT_ID; i++)
+ abe_reset_port(i);
+ /* mixers' configuration */
+ abe_write_mixer(MIXDL1, MUTE_GAIN, RAMP_100MS, MIX_DL1_INPUT_MM_DL);
+ abe_write_mixer(MIXDL1, MUTE_GAIN, RAMP_100MS, MIX_DL1_INPUT_MM_UL2);
+ abe_write_mixer(MIXDL1, MUTE_GAIN, RAMP_100MS, MIX_DL1_INPUT_VX_DL);
+ abe_write_mixer(MIXDL1, MUTE_GAIN, RAMP_100MS, MIX_DL1_INPUT_TONES);
+ abe_write_mixer(MIXDL2, MUTE_GAIN, RAMP_100MS, MIX_DL2_INPUT_TONES);
+ abe_write_mixer(MIXDL2, MUTE_GAIN, RAMP_100MS, MIX_DL2_INPUT_VX_DL);
+ abe_write_mixer(MIXDL2, MUTE_GAIN, RAMP_100MS, MIX_DL2_INPUT_MM_DL);
+ abe_write_mixer(MIXDL2, MUTE_GAIN, RAMP_100MS, MIX_DL2_INPUT_MM_UL2);
+ abe_write_mixer(MIXSDT, MUTE_GAIN, RAMP_100MS, MIX_SDT_INPUT_UP_MIXER);
+ abe_write_mixer(MIXSDT, GAIN_0dB, RAMP_100MS, MIX_SDT_INPUT_DL1_MIXER);
+ abe_write_mixer(MIXECHO, MUTE_GAIN, RAMP_100MS, MIX_ECHO_DL1);
+ abe_write_mixer(MIXECHO, MUTE_GAIN, RAMP_100MS, MIX_ECHO_DL2);
+ abe_write_mixer(MIXAUDUL, MUTE_GAIN, RAMP_100MS, MIX_AUDUL_INPUT_MM_DL);
+ abe_write_mixer(MIXAUDUL, MUTE_GAIN, RAMP_100MS, MIX_AUDUL_INPUT_TONES);
+ abe_write_mixer(MIXAUDUL, GAIN_0dB, RAMP_100MS, MIX_AUDUL_INPUT_UPLINK);
+ abe_write_mixer(MIXAUDUL, MUTE_GAIN, RAMP_100MS, MIX_AUDUL_INPUT_VX_DL);
+ abe_write_mixer(MIXVXREC, MUTE_GAIN, RAMP_100MS, MIX_VXREC_INPUT_TONES);
+ abe_write_mixer(MIXVXREC, MUTE_GAIN, RAMP_100MS, MIX_VXREC_INPUT_VX_DL);
+ abe_write_mixer(MIXVXREC, MUTE_GAIN, RAMP_100MS, MIX_VXREC_INPUT_MM_DL);
+ abe_write_mixer(MIXVXREC, MUTE_GAIN, RAMP_100MS, MIX_VXREC_INPUT_VX_UL);
+ abe_write_gain(GAINS_DMIC1, GAIN_0dB, RAMP_100MS, GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_DMIC1, GAIN_0dB, RAMP_100MS, GAIN_RIGHT_OFFSET);
+ abe_write_gain(GAINS_DMIC2, GAIN_0dB, RAMP_100MS, GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_DMIC2, GAIN_0dB, RAMP_100MS, GAIN_RIGHT_OFFSET);
+ abe_write_gain(GAINS_DMIC3, GAIN_0dB, RAMP_100MS, GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_DMIC3, GAIN_0dB, RAMP_100MS, GAIN_RIGHT_OFFSET);
+ abe_write_gain(GAINS_AMIC, GAIN_0dB, RAMP_100MS, GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_AMIC, GAIN_0dB, RAMP_100MS, GAIN_RIGHT_OFFSET);
+ abe_write_gain(GAINS_SPLIT, GAIN_0dB, RAMP_100MS, GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_SPLIT, GAIN_0dB, RAMP_100MS, GAIN_RIGHT_OFFSET);
+ abe_write_gain(GAINS_DL1, GAIN_0dB, RAMP_100MS, GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_DL1, GAIN_0dB, RAMP_100MS, GAIN_RIGHT_OFFSET);
+ abe_write_gain(GAINS_DL2, GAIN_0dB, RAMP_100MS, GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_DL2, GAIN_0dB, RAMP_100MS, GAIN_RIGHT_OFFSET);
+}
+/**
+ * abe_clean_temporay buffers
+ *
+ * clear temporary buffers
+ */
+void abe_clean_temporary_buffers(u32 id)
+{
+ switch (id) {
+ case DMIC_PORT:
+ abe_reset_mem(ABE_DMEM, D_DMIC_UL_FIFO_ADDR,
+ D_DMIC_UL_FIFO_sizeof);
+ abe_reset_mem(ABE_SMEM, S_DMIC0_96_48_data_ADDR << 3,
+ S_DMIC0_96_48_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_DMIC1_96_48_data_ADDR << 3,
+ S_DMIC1_96_48_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_DMIC2_96_48_data_ADDR << 3,
+ S_DMIC1_96_48_data_sizeof << 3);
+ abe_reset_mem(ABE_CMEM, (C_GainsWRamp_ADDR + dmic1_gains_offset) << 2, 6 << 2); /* reset current gains */
+ abe_reset_mem(ABE_SMEM,
+ (S_GCurrent_ADDR + dmic1_gains_offset) << 3,
+ 6 << 3);
+ abe_reset_gain_mixer(GAINS_DMIC1, 0);
+ abe_reset_gain_mixer(GAINS_DMIC2, 0);
+ abe_reset_gain_mixer(GAINS_DMIC3, 0);
+ break;
+ case PDM_UL_PORT:
+ abe_reset_mem(ABE_DMEM, D_McPDM_UL_FIFO_ADDR,
+ D_McPDM_UL_FIFO_sizeof);
+ abe_reset_mem(ABE_SMEM, S_BT_UL_ADDR << 3, S_BT_UL_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_AMIC_96_48_data_ADDR << 3,
+ S_AMIC_96_48_data_sizeof << 3);
+ abe_reset_mem(ABE_CMEM, (C_GainsWRamp_ADDR + amic_gains_offset) << 2, 2 << 2); /* reset current gains */
+ abe_reset_mem(ABE_SMEM,
+ (S_GCurrent_ADDR + amic_gains_offset) << 3,
+ 6 << 3);
+ abe_reset_gain_mixer(GAINS_AMIC, 0);
+ break;
+ case BT_VX_UL_PORT:
+ abe_reset_mem(ABE_DMEM, D_BT_UL_FIFO_ADDR, D_BT_UL_FIFO_sizeof);
+ abe_reset_mem(ABE_SMEM, S_BT_UL_ADDR << 3, S_BT_UL_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_BT_UL_ADDR << 3, S_BT_UL_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_BT_UL_8_48_HP_data_ADDR << 3,
+ S_BT_UL_8_48_HP_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_BT_UL_8_48_LP_data_ADDR << 3,
+ S_BT_UL_8_48_LP_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_BT_UL_16_48_HP_data_ADDR << 3,
+ S_BT_UL_16_48_HP_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_BT_UL_16_48_LP_data_ADDR << 3,
+ S_BT_UL_16_48_LP_data_sizeof << 3);
+ break;
+ case MM_UL_PORT:
+ abe_reset_mem(ABE_DMEM, D_MM_UL_FIFO_ADDR, D_MM_UL_FIFO_sizeof);
+ abe_reset_mem(ABE_SMEM, S_MM_UL_ADDR << 3, S_MM_UL_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_MM_UL2_ADDR << 3,
+ D_MM_UL2_FIFO_sizeof << 3);
+ break;
+ case MM_UL2_PORT:
+ abe_reset_mem(ABE_DMEM, D_MM_UL2_FIFO_ADDR,
+ D_MM_UL2_FIFO_sizeof);
+ abe_reset_mem(ABE_SMEM, S_MM_UL2_ADDR << 3,
+ S_MM_UL2_sizeof << 3);
+ break;
+ case VX_UL_PORT:
+ abe_reset_mem(ABE_DMEM, D_VX_UL_FIFO_ADDR, D_VX_UL_FIFO_sizeof);
+ abe_reset_mem(ABE_SMEM, S_VX_UL_ADDR << 3, S_VX_UL_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_VX_UL_48_8_HP_data_ADDR << 3,
+ S_VX_UL_48_8_HP_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_VX_UL_48_8_LP_data_ADDR << 3,
+ S_VX_UL_48_8_LP_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_VX_UL_48_16_HP_data_ADDR << 3,
+ S_VX_UL_48_16_HP_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_VX_UL_48_16_LP_data_ADDR << 3,
+ S_VX_UL_48_16_LP_data_sizeof << 3);
+ abe_reset_gain_mixer(MIXAUDUL, MIX_AUDUL_INPUT_UPLINK);
+ break;
+ case MM_DL_PORT:
+ abe_reset_mem(ABE_DMEM, D_MM_DL_FIFO_ADDR, D_MM_DL_FIFO_sizeof);
+ abe_reset_mem(ABE_SMEM, S_MM_DL_ADDR << 3, S_MM_DL_sizeof << 3);
+ abe_reset_gain_mixer(MIXDL1, MIX_DL1_INPUT_MM_DL);
+ abe_reset_gain_mixer(MIXDL2, MIX_DL2_INPUT_MM_DL);
+ break;
+ case VX_DL_PORT:
+ abe_reset_mem(ABE_DMEM, D_VX_DL_FIFO_ADDR, D_VX_DL_FIFO_sizeof);
+ abe_reset_mem(ABE_SMEM, S_VX_DL_ADDR << 3, S_VX_DL_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_VX_DL_8_48_HP_data_ADDR << 3,
+ S_VX_DL_8_48_HP_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_VX_DL_8_48_LP_data_ADDR << 3,
+ S_VX_DL_8_48_LP_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_VX_DL_16_48_HP_data_ADDR << 3,
+ S_VX_DL_16_48_HP_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_VX_DL_16_48_LP_data_ADDR << 3,
+ S_VX_DL_16_48_LP_data_sizeof << 3);
+ abe_reset_gain_mixer(MIXDL1, MIX_DL1_INPUT_VX_DL);
+ abe_reset_gain_mixer(MIXDL2, MIX_DL2_INPUT_VX_DL);
+ break;
+ case TONES_DL_PORT:
+ abe_reset_mem(ABE_DMEM, D_TONES_DL_FIFO_ADDR,
+ D_TONES_DL_FIFO_sizeof);
+ abe_reset_mem(ABE_SMEM, S_Tones_ADDR << 3, S_Tones_sizeof << 3);
+ abe_reset_gain_mixer(MIXDL1, MIX_DL1_INPUT_TONES);
+ abe_reset_gain_mixer(MIXDL2, MIX_DL2_INPUT_TONES);
+ break;
+ case VIB_DL_PORT:
+ abe_reset_mem(ABE_DMEM, D_VIB_DL_FIFO_ADDR,
+ D_VIB_DL_FIFO_sizeof);
+ abe_reset_mem(ABE_SMEM, S_VIBRA_ADDR << 3, S_VIBRA_sizeof << 3);
+ break;
+ case BT_VX_DL_PORT:
+ abe_reset_mem(ABE_DMEM, D_BT_DL_FIFO_ADDR, D_BT_DL_FIFO_sizeof);
+ abe_reset_mem(ABE_SMEM, S_BT_DL_ADDR << 3, S_BT_DL_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_BT_DL_48_8_HP_data_ADDR << 3,
+ S_BT_DL_48_8_HP_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_BT_DL_48_8_LP_data_ADDR << 3,
+ S_BT_DL_48_8_LP_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_BT_DL_48_16_HP_data_ADDR << 3,
+ S_BT_DL_48_16_HP_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_BT_DL_48_16_LP_data_ADDR << 3,
+ S_BT_DL_48_16_LP_data_sizeof << 3);
+ break;
+ case PDM_DL_PORT:
+ abe_reset_mem(ABE_DMEM, D_McPDM_DL_FIFO_ADDR,
+ D_McPDM_DL_FIFO_sizeof);
+ abe_reset_mem(ABE_SMEM, S_DL2_M_LR_EQ_data_ADDR << 3,
+ S_DL2_M_LR_EQ_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_DL1_M_EQ_data_ADDR << 3,
+ S_DL1_M_EQ_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_EARP_48_96_LP_data_ADDR << 3,
+ S_EARP_48_96_LP_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_IHF_48_96_LP_data_ADDR << 3,
+ S_IHF_48_96_LP_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_APS_DL1_EQ_data_ADDR << 3,
+ S_APS_DL1_EQ_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_APS_DL2_EQ_data_ADDR << 3,
+ S_APS_DL2_EQ_data_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_APS_DL2_L_IIRmem1_ADDR << 3,
+ S_APS_DL2_L_IIRmem1_sizeof << 3);
+ abe_reset_mem(ABE_SMEM, S_APS_DL2_R_IIRmem1_ADDR << 3,
+ S_APS_DL2_R_IIRmem1_sizeof << 3);
+ abe_reset_gain_mixer(GAINS_DL1, GAIN_LEFT_OFFSET);
+ abe_reset_gain_mixer(GAINS_DL1, GAIN_RIGHT_OFFSET);
+ abe_reset_gain_mixer(GAINS_DL2, GAIN_LEFT_OFFSET);
+ abe_reset_gain_mixer(GAINS_DL2, GAIN_RIGHT_OFFSET);
+ abe_reset_gain_mixer(MIXSDT, MIX_SDT_INPUT_UP_MIXER);
+ abe_reset_gain_mixer(MIXSDT, MIX_SDT_INPUT_DL1_MIXER);
+ break;
+ case MM_EXT_OUT_PORT:
+ abe_reset_mem(ABE_DMEM, D_MM_EXT_OUT_FIFO_ADDR,
+ D_MM_EXT_OUT_FIFO_sizeof);
+ break;
+ case MM_EXT_IN_PORT:
+ abe_reset_mem(ABE_DMEM, D_MM_EXT_IN_FIFO_ADDR,
+ D_MM_EXT_IN_FIFO_sizeof);
+ break;
+ }
+}
+/**
+ * abe_clear_current_gain_mixer
+ * @id: name of the mixer
+ * @param: list of input gains of the mixer
+ * @p: list of port corresponding to the above gains
+ *
+ * restart the working gain value of the mixers when a port is enabled
+ */
+void abe_reset_gain_mixer(u32 id, u32 p)
+{
+ u32 lin_g, mixer_target, mixer_offset;
+ switch (id) {
+ default:
+ case GAINS_DMIC1:
+ mixer_offset = dmic1_gains_offset;
+ break;
+ case GAINS_DMIC2:
+ mixer_offset = dmic2_gains_offset;
+ break;
+ case GAINS_DMIC3:
+ mixer_offset = dmic3_gains_offset;
+ break;
+ case GAINS_AMIC:
+ mixer_offset = amic_gains_offset;
+ break;
+ case GAINS_DL1:
+ mixer_offset = dl1_gains_offset;
+ break;
+ case GAINS_DL2:
+ mixer_offset = dl2_gains_offset;
+ break;
+ case GAINS_SPLIT:
+ mixer_offset = splitters_gains_offset;
+ break;
+ case MIXDL1:
+ mixer_offset = mixer_dl1_offset;
+ break;
+ case MIXDL2:
+ mixer_offset = mixer_dl2_offset;
+ break;
+ case MIXECHO:
+ mixer_offset = mixer_echo_offset;
+ break;
+ case MIXSDT:
+ mixer_offset = mixer_sdt_offset;
+ break;
+ case MIXVXREC:
+ mixer_offset = mixer_vxrec_offset;
+ break;
+ case MIXAUDUL:
+ mixer_offset = mixer_audul_offset;
+ break;
+ }
+ /* SMEM word32 address for the CURRENT gain values */
+ mixer_target = (S_GCurrent_ADDR << 1);
+ mixer_target += mixer_offset;
+ mixer_target += p;
+ /* translate coef address in Bytes */
+ mixer_target <<= 2;
+ lin_g = 0;
+ /* load the S_G_Target SMEM table */
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_SMEM, mixer_target,
+ (u32 *) &lin_g, sizeof(lin_g));
+}
+/**
+ * abe_init_asrc_vx_dl
+ *
+ * Initialize the following ASRC VX_DL parameters :
+ * 1. DriftSign = D_AsrcVars[1] = 1 or -1
+ * 2. Subblock = D_AsrcVars[2] = 0
+ * 3. DeltaAlpha = D_AsrcVars[3] = (round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2
+ * 4. MinusDeltaAlpha = D_AsrcVars[4] = (-round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2
+ * 5. OneMinusEpsilon = D_AsrcVars[5] = 1 - DeltaAlpha/2
+ * 6. AlphaCurrent = 0x000020 (CMEM), initial value of Alpha parameter
+ * 7. BetaCurrent = 0x3fffe0 (CMEM), initial value of Beta parameter
+ * AlphaCurrent + BetaCurrent = 1 (=0x400000 in CMEM = 2^20 << 2)
+ * 8. drift_ASRC = 0 & drift_io = 0
+ * 9. SMEM for ASRC_DL_VX_Coefs pointer
+ * 10. CMEM for ASRC_DL_VX_Coefs pointer
+ * ASRC_DL_VX_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/
+ * C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1
+ * 11. SMEM for XinASRC_DL_VX pointer
+ * 12. CMEM for XinASRC_DL_VX pointer
+ * XinASRC_DL_VX = S_XinASRC_DL_VX_ADDR/S_XinASRC_DL_VX_sizeof/0/1/0/0/0/0
+ * 13. SMEM for IO_VX_DL_ASRC pointer
+ * 14. CMEM for IO_VX_DL_ASRC pointer
+ * IO_VX_DL_ASRC = S_XinASRC_DL_VX_ADDR/S_XinASRC_DL_VX_sizeof/ASRC_DL_VX_FIR_L+ASRC_margin/1/0/0/0/0
+ */
+void abe_init_asrc_vx_dl(s32 dppm)
+{
+ s32 el[45];
+ s32 temp0, temp1, adppm, dtemp, mem_tag, mem_addr;
+ u32 i = 0;
+ temp0 = 0;
+ temp1 = 1;
+ /* 1. DriftSign = D_AsrcVars[1] = 1 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_DL_VX_ADDR + (1 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm >= 0) {
+ el[i + 1] = 1;
+ adppm = dppm;
+ } else {
+ el[i + 1] = -1;
+ adppm = (-1 * dppm);
+ }
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ dtemp = (adppm << 4) + adppm - ((adppm * 3481L) / 15625L);
+ /* 2. Subblock = D_AsrcVars[2] = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_DL_VX_ADDR + (2 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ el[i + 1] = temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 3. DeltaAlpha = D_AsrcVars[3] = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_DL_VX_ADDR + (3 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm == 0) {
+ el[i + 1] = 0;
+ } else {
+ el[i + 1] = dtemp << 2;
+ }
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 4. MinusDeltaAlpha = D_AsrcVars[4] = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_DL_VX_ADDR + (4 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm == 0) {
+ el[i + 1] = 0;
+ } else {
+ el[i + 1] = (-dtemp) << 2;
+ }
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /*5. OneMinusEpsilon = D_AsrcVars[5] = 0x00400000 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_DL_VX_ADDR + (5 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm == 0) {
+ el[i + 1] = 0x00400000;
+ } else {
+ el[i + 1] = (0x00100000 - (dtemp / 2)) << 2;
+ }
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 6. AlphaCurrent = 0x000020 (CMEM) */
+ mem_tag = ABE_CMEM;
+ mem_addr = C_AlphaCurrent_DL_VX_ADDR;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = 0x00000020;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 7. BetaCurrent = 0x3fffe0 (CMEM) */
+ mem_tag = ABE_CMEM;
+ mem_addr = C_BetaCurrent_DL_VX_ADDR;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = 0x003fffe0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 8. drift_ASRC = 0 & drift_io = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_IOdescr_ADDR + (VX_DL_PORT * sizeof(ABE_SIODescriptor))
+ + drift_asrc_;
+ el[i] = (mem_tag << 16) + mem_addr;
+ el[i + 1] = temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 9. SMEM for ASRC_DL_VX_Coefs pointer */
+ /* ASRC_DL_VX_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0
+ /1/C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 */
+ mem_tag = ABE_SMEM;
+ mem_addr = ASRC_DL_VX_Coefs_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = C_CoefASRC16_VX_ADDR;
+ el[i + 1] = (el[i + 1] << 8) + C_CoefASRC16_VX_sizeof;
+ el[i + 2] = C_CoefASRC15_VX_ADDR;
+ el[i + 2] = (el[i + 2] << 8) + C_CoefASRC15_VX_sizeof;
+ i = i + 3;
+ /* 10. CMEM for ASRC_DL_VX_Coefs pointer */
+ /* ASRC_DL_VX_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/
+ 1/C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 */
+ mem_tag = ABE_CMEM;
+ mem_addr = ASRC_DL_VX_Coefs_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp1;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 11. SMEM for XinASRC_DL_VX pointer */
+ /* XinASRC_DL_VX = S_XinASRC_DL_VX_ADDR/S_XinASRC_DL_VX_sizeof/0/1/0/0/0/0 */
+ mem_tag = ABE_SMEM;
+ mem_addr = XinASRC_DL_VX_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = S_XinASRC_DL_VX_ADDR;
+ el[i + 1] = (el[i + 1] << 8) + S_XinASRC_DL_VX_sizeof;
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 12. CMEM for XinASRC_DL_VX pointer */
+ /* XinASRC_DL_VX = S_XinASRC_DL_VX_ADDR/S_XinASRC_DL_VX_sizeof/0/1/0/0/0/0 */
+ mem_tag = ABE_CMEM;
+ mem_addr = XinASRC_DL_VX_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 13. SMEM for IO_VX_DL_ASRC pointer */
+ /* IO_VX_DL_ASRC = S_XinASRC_DL_VX_ADDR/S_XinASRC_DL_VX_sizeof/
+ ASRC_DL_VX_FIR_L+ASRC_margin/1/0/0/0/0 */
+ mem_tag = ABE_SMEM;
+ mem_addr = IO_VX_DL_ASRC_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = S_XinASRC_DL_VX_ADDR;
+ el[i + 1] = (el[i + 1] << 8) + S_XinASRC_DL_VX_sizeof;
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 14. CMEM for IO_VX_DL_ASRC pointer */
+ /* IO_VX_DL_ASRC = S_XinASRC_DL_VX_ADDR/S_XinASRC_DL_VX_sizeof/
+ ASRC_DL_VX_FIR_L+ASRC_margin/1/0/0/0/0 */
+ mem_tag = ABE_CMEM;
+ mem_addr = IO_VX_DL_ASRC_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = ((ASRC_DL_VX_FIR_L + ASRC_margin) << 16) + (temp1 << 12)
+ + (temp0 << 4) + temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ abe_write_fifo(ABE_DMEM, D_FwMemInitDescr_ADDR, (u32 *) &el[0], 42);
+}
+/**
+ * abe_init_asrc_vx_ul
+ *
+ * Initialize the following ASRC VX_UL parameters :
+ * 1. DriftSign = D_AsrcVars[1] = 1 or -1
+ * 2. Subblock = D_AsrcVars[2] = 0
+ * 3. DeltaAlpha = D_AsrcVars[3] = (round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2
+ * 4. MinusDeltaAlpha = D_AsrcVars[4] = (-round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2
+ * 5. OneMinusEpsilon = D_AsrcVars[5] = 1 - DeltaAlpha/2
+ * 6. AlphaCurrent = 0x000020 (CMEM), initial value of Alpha parameter
+ * 7. BetaCurrent = 0x3fffe0 (CMEM), initial value of Beta parameter
+ * AlphaCurrent + BetaCurrent = 1 (=0x400000 in CMEM = 2^20 << 2)
+ * 8. drift_ASRC = 0 & drift_io = 0
+ * 9. SMEM for ASRC_UL_VX_Coefs pointer
+ * 10. CMEM for ASRC_UL_VX_Coefs pointer
+ * ASRC_UL_VX_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof
+ * /0/1/C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1
+ * 11. SMEM for XinASRC_UL_VX pointer
+ * 12. CMEM for XinASRC_UL_VX pointer
+ * XinASRC_UL_VX = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/0/1/0/0/0/0
+ * 13. SMEM for UL_48_8_DEC pointer
+ * 14. CMEM for UL_48_8_DEC pointer
+ * UL_48_8_DEC = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/
+ * ASRC_UL_VX_FIR_L+ASRC_margin/1/0/0/0/0
+ * 15. SMEM for UL_48_16_DEC pointer
+ * 16. CMEM for UL_48_16_DEC pointer
+ * UL_48_16_DEC = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/
+ * ASRC_UL_VX_FIR_L+ASRC_margin/1/0/0/0/0
+ */
+void abe_init_asrc_vx_ul(s32 dppm)
+{
+ s32 el[51];
+ s32 temp0, temp1, adppm, dtemp, mem_tag, mem_addr;
+ u32 i = 0;
+ temp0 = 0;
+ temp1 = 1;
+ /* 1. DriftSign = D_AsrcVars[1] = 1 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_UL_VX_ADDR + (1 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm >= 0) {
+ el[i + 1] = 1;
+ adppm = dppm;
+ } else {
+ el[i + 1] = -1;
+ adppm = (-1 * dppm);
+ }
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ dtemp = (adppm << 4) + adppm - ((adppm * 3481L) / 15625L);
+ /* 2. Subblock = D_AsrcVars[2] = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_UL_VX_ADDR + (2 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ el[i + 1] = temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 3. DeltaAlpha = D_AsrcVars[3] = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_UL_VX_ADDR + (3 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm == 0) {
+ el[i + 1] = 0;
+ } else {
+ el[i + 1] = dtemp << 2;
+ }
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 4. MinusDeltaAlpha = D_AsrcVars[4] = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_UL_VX_ADDR + (4 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm == 0) {
+ el[i + 1] = 0;
+ } else {
+ el[i + 1] = (-dtemp) << 2;
+ }
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 5. OneMinusEpsilon = D_AsrcVars[5] = 0x00400000 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_UL_VX_ADDR + (5 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm == 0) {
+ el[i + 1] = 0x00400000;
+ } else {
+ el[i + 1] = (0x00100000 - (dtemp / 2)) << 2;
+ }
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 6. AlphaCurrent = 0x000020 (CMEM) */
+ mem_tag = ABE_CMEM;
+ mem_addr = C_AlphaCurrent_UL_VX_ADDR;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = 0x00000020;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 7. BetaCurrent = 0x3fffe0 (CMEM) */
+ mem_tag = ABE_CMEM;
+ mem_addr = C_BetaCurrent_UL_VX_ADDR;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = 0x003fffe0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 8. drift_ASRC = 0 & drift_io = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_IOdescr_ADDR + (VX_UL_PORT * sizeof(ABE_SIODescriptor))
+ + drift_asrc_;
+ el[i] = (mem_tag << 16) + mem_addr;
+ el[i + 1] = temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 9. SMEM for ASRC_UL_VX_Coefs pointer */
+ /* ASRC_UL_VX_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/
+ C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 */
+ mem_tag = ABE_SMEM;
+ mem_addr = ASRC_UL_VX_Coefs_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = C_CoefASRC16_VX_ADDR;
+ el[i + 1] = (el[i + 1] << 8) + C_CoefASRC16_VX_sizeof;
+ el[i + 2] = C_CoefASRC15_VX_ADDR;
+ el[i + 2] = (el[i + 2] << 8) + C_CoefASRC15_VX_sizeof;
+ i = i + 3;
+ /* 10. CMEM for ASRC_UL_VX_Coefs pointer */
+ /* ASRC_UL_VX_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/
+ C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 */
+ mem_tag = ABE_CMEM;
+ mem_addr = ASRC_UL_VX_Coefs_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp1;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 11. SMEM for XinASRC_UL_VX pointer */
+ /* XinASRC_UL_VX = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/0/1/0/0/0/0 */
+ mem_tag = ABE_SMEM;
+ mem_addr = XinASRC_UL_VX_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = S_XinASRC_UL_VX_ADDR;
+ el[i + 1] = (el[i + 1] << 8) + S_XinASRC_UL_VX_sizeof;
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 12. CMEM for XinASRC_UL_VX pointer */
+ /* XinASRC_UL_VX = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/0/1/0/0/0/0 */
+ mem_tag = ABE_CMEM;
+ mem_addr = XinASRC_UL_VX_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 13. SMEM for UL_48_8_DEC pointer */
+ /* UL_48_8_DEC = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/
+ ASRC_UL_VX_FIR_L+ASRC_margin/1/0/0/0/0 */
+ mem_tag = ABE_SMEM;
+ mem_addr = UL_48_8_DEC_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = S_XinASRC_UL_VX_ADDR;
+ el[i + 1] = (el[i + 1] << 8) + S_XinASRC_UL_VX_sizeof;
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 14. CMEM for UL_48_8_DEC pointer */
+ /* UL_48_8_DEC = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/
+ ASRC_UL_VX_FIR_L+ASRC_margin/1/0/0/0/0 */
+ mem_tag = ABE_CMEM;
+ mem_addr = UL_48_8_DEC_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = ((ASRC_UL_VX_FIR_L + ASRC_margin) << 16) + (temp1 << 12)
+ + (temp0 << 4) + temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 15. SMEM for UL_48_16_DEC pointer */
+ /* UL_48_16_DEC = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/
+ ASRC_UL_VX_FIR_L+ASRC_margin/1/0/0/0/0 */
+ mem_tag = ABE_SMEM;
+ mem_addr = UL_48_16_DEC_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = S_XinASRC_UL_VX_ADDR;
+ el[i + 1] = (el[i + 1] << 8) + S_XinASRC_UL_VX_sizeof;
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 16. CMEM for UL_48_16_DEC pointer */
+ /* UL_48_16_DEC = S_XinASRC_UL_VX_ADDR/S_XinASRC_UL_VX_sizeof/
+ ASRC_UL_VX_FIR_L+ASRC_margin/1/0/0/0/0 */
+ mem_tag = ABE_CMEM;
+ mem_addr = UL_48_16_DEC_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = ((ASRC_UL_VX_FIR_L + ASRC_margin) << 16) + (temp1 << 12)
+ + (temp0 << 4) + temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ abe_write_fifo(ABE_DMEM, D_FwMemInitDescr_ADDR, (u32 *) &el[0], 48);
+}
+/**
+ * abe_init_asrc_mm_ext_in
+ *
+ * Initialize the following ASRC MM_EXT_IN parameters :
+ * 1. DriftSign = D_AsrcVars[1] = 1 or -1
+ * 2. Subblock = D_AsrcVars[2] = 0
+ * 3. DeltaAlpha = D_AsrcVars[3] = (round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2
+ * 4. MinusDeltaAlpha = D_AsrcVars[4] = (-round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2
+ * 5. OneMinusEpsilon = D_AsrcVars[5] = 1 - DeltaAlpha/2
+ * 6. AlphaCurrent = 0x000020 (CMEM), initial value of Alpha parameter
+ * 7. BetaCurrent = 0x3fffe0 (CMEM), initial value of Beta parameter
+ * AlphaCurrent + BetaCurrent = 1 (=0x400000 in CMEM = 2^20 << 2)
+ * 8. drift_ASRC = 0 & drift_io = 0
+ * 9. SMEM for ASRC_MM_EXT_IN_Coefs pointer
+ * 10. CMEM for ASRC_MM_EXT_IN_Coefs pointer
+ * ASRC_MM_EXT_IN_Coefs = C_CoefASRC16_MM_ADDR/C_CoefASRC16_MM_sizeof/
+ * 0/1/C_CoefASRC15_MM_ADDR/C_CoefASRC15_MM_sizeof/0/1
+ * 11. SMEM for XinASRC_MM_EXT_IN pointer
+ * 12. CMEM for XinASRC_MM_EXT_IN pointer
+ * XinASRC_MM_EXT_IN = S_XinASRC_MM_EXT_IN_ADDR/S_XinASRC_MM_EXT_IN_sizeof/0/1/0/0/0/0
+ * 13. SMEM for IO_MM_EXT_IN_ASRC pointer
+ * 14. CMEM for IO_MM_EXT_IN_ASRC pointer
+ * IO_MM_EXT_IN_ASRC = S_XinASRC_MM_EXT_IN_ADDR/S_XinASRC_MM_EXT_IN_sizeof/
+ * ASRC_MM_EXT_IN_FIR_L+ASRC_margin+ASRC_N_48k/1/0/0/0/0
+ */
+void abe_init_asrc_mm_ext_in(s32 dppm)
+{
+ s32 el[45];
+ s32 temp0, temp1, adppm, dtemp, mem_tag, mem_addr;
+ u32 i = 0;
+ temp0 = 0;
+ temp1 = 1;
+ /* 1. DriftSign = D_AsrcVars[1] = 1 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_MM_EXT_IN_ADDR + (1 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm >= 0) {
+ el[i + 1] = 1;
+ adppm = dppm;
+ } else {
+ el[i + 1] = -1;
+ adppm = (-1 * dppm);
+ }
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ dtemp = (adppm << 4) + adppm - ((adppm * 3481L) / 15625L);
+ /* 2. Subblock = D_AsrcVars[2] = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_MM_EXT_IN_ADDR + (2 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ el[i + 1] = temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 3. DeltaAlpha = D_AsrcVars[3] = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_MM_EXT_IN_ADDR + (3 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm == 0) {
+ el[i + 1] = 0;
+ } else {
+ el[i + 1] = dtemp << 2;
+ }
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 4. MinusDeltaAlpha = D_AsrcVars[4] = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_MM_EXT_IN_ADDR + (4 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm == 0) {
+ el[i + 1] = 0;
+ } else {
+ el[i + 1] = (-dtemp) << 2;
+ }
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 5. OneMinusEpsilon = D_AsrcVars[5] = 0x00400000 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_MM_EXT_IN_ADDR + (5 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm == 0) {
+ el[i + 1] = 0x00400000;
+ } else {
+ el[i + 1] = (0x00100000 - (dtemp / 2)) << 2;
+ }
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 6. AlphaCurrent = 0x000020 (CMEM) */
+ mem_tag = ABE_CMEM;
+ mem_addr = C_AlphaCurrent_MM_EXT_IN_ADDR;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = 0x00000020;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 7. BetaCurrent = 0x3fffe0 (CMEM) */
+ mem_tag = ABE_CMEM;
+ mem_addr = C_BetaCurrent_MM_EXT_IN_ADDR;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = 0x003fffe0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 8. drift_ASRC = 0 & drift_io = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_IOdescr_ADDR + (MM_EXT_IN_PORT * sizeof(ABE_SIODescriptor))
+ + drift_asrc_;
+ el[i] = (mem_tag << 16) + mem_addr;
+ el[i + 1] = temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 9. SMEM for ASRC_MM_EXT_IN_Coefs pointer */
+ /* ASRC_MM_EXT_IN_Coefs = C_CoefASRC16_MM_ADDR/C_CoefASRC16_MM_sizeof
+ /0/1/C_CoefASRC15_MM_ADDR/C_CoefASRC15_MM_sizeof/0/1 */
+ mem_tag = ABE_SMEM;
+ mem_addr = ASRC_MM_EXT_IN_Coefs_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = C_CoefASRC16_MM_ADDR;
+ el[i + 1] = (el[i + 1] << 8) + C_CoefASRC16_MM_sizeof;
+ el[i + 2] = C_CoefASRC15_MM_ADDR;
+ el[i + 2] = (el[i + 2] << 8) + C_CoefASRC15_MM_sizeof;
+ i = i + 3;
+ /*10. CMEM for ASRC_MM_EXT_IN_Coefs pointer */
+ /* ASRC_MM_EXT_IN_Coefs = C_CoefASRC16_MM_ADDR/C_CoefASRC16_MM_sizeof
+ /0/1/C_CoefASRC15_MM_ADDR/C_CoefASRC15_MM_sizeof/0/1 */
+ mem_tag = ABE_CMEM;
+ mem_addr = ASRC_MM_EXT_IN_Coefs_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp1;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 11. SMEM for XinASRC_MM_EXT_IN pointer */
+ /* XinASRC_MM_EXT_IN = S_XinASRC_MM_EXT_IN_ADDR/S_XinASRC_MM_EXT_IN_sizeof/0/1/0/0/0/0 */
+ mem_tag = ABE_SMEM;
+ mem_addr = XinASRC_MM_EXT_IN_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = S_XinASRC_MM_EXT_IN_ADDR;
+ el[i + 1] = (el[i + 1] << 8) + S_XinASRC_MM_EXT_IN_sizeof;
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 12. CMEM for XinASRC_MM_EXT_IN pointer */
+ /* XinASRC_MM_EXT_IN = S_XinASRC_MM_EXT_IN_ADDR/S_XinASRC_MM_EXT_IN_sizeof/0/1/0/0/0/0 */
+ mem_tag = ABE_CMEM;
+ mem_addr = XinASRC_MM_EXT_IN_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 13. SMEM for IO_MM_EXT_IN_ASRC pointer */
+ /* IO_MM_EXT_IN_ASRC = S_XinASRC_MM_EXT_IN_ADDR/S_XinASRC_MM_EXT_IN_sizeof/
+ ASRC_MM_EXT_IN_FIR_L+ASRC_margin+ASRC_N_48k/1/0/0/0/0 */
+ mem_tag = ABE_SMEM;
+ mem_addr = IO_MM_EXT_IN_ASRC_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = S_XinASRC_MM_EXT_IN_ADDR;
+ el[i + 1] = (el[i + 1] << 8) + S_XinASRC_MM_EXT_IN_sizeof;
+ el[i + 2] = temp0;
+ i = i + 3;
+ /* 14. CMEM for IO_MM_EXT_IN_ASRC pointer */
+ /* IO_MM_EXT_IN_ASRC = S_XinASRC_MM_EXT_IN_ADDR/S_XinASRC_MM_EXT_IN_sizeof/
+ ASRC_MM_EXT_IN_FIR_L+ASRC_margin+ASRC_N_48k/1/0/0/0/0 */
+ mem_tag = ABE_CMEM;
+ mem_addr = IO_MM_EXT_IN_ASRC_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = ((ASRC_MM_EXT_IN_FIR_L + ASRC_margin + ASRC_N_48k) << 16) +
+ (temp1 << 12) + (temp0 << 4) + temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ abe_write_fifo(ABE_DMEM, D_FwMemInitDescr_ADDR, (u32 *) &el[0], 42);
+}
+/**
+ * abe_init_asrc_bt_ul
+ *
+ * Initialize the following ASRC BT_UL parameters :
+ * 1. DriftSign = D_AsrcVars[1] = 1 or -1
+ * 2. Subblock = D_AsrcVars[2] = 0
+ * 3. DeltaAlpha = D_AsrcVars[3] = (round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2
+ * 4. MinusDeltaAlpha = D_AsrcVars[4] = (-round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2
+ * 5. OneMinusEpsilon = D_AsrcVars[5] = 1 - DeltaAlpha/2
+ * 6. AlphaCurrent = 0x000020 (CMEM), initial value of Alpha parameter
+ * 7. BetaCurrent = 0x3fffe0 (CMEM), initial value of Beta parameter
+ * AlphaCurrent + BetaCurrent = 1 (=0x400000 in CMEM = 2^20 << 2)
+ * 8. drift_ASRC = 0 & drift_io = 0
+ * 9. SMEM for ASRC_BT_UL_Coefs pointer
+ * 10. CMEM for ASRC_BT_UL_Coefs pointer
+ * ASRC_BT_UL_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/
+ * C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1
+ * 11. SMEM for XinASRC_BT_UL pointer
+ * 12. CMEM for XinASRC_BT_UL pointer
+ * XinASRC_BT_UL = S_XinASRC_BT_UL_ADDR/S_XinASRC_BT_UL_sizeof/0/1/0/0/0/0
+ * 13. SMEM for IO_BT_UL_ASRC pointer
+ * 14. CMEM for IO_BT_UL_ASRC pointer
+ * IO_BT_UL_ASRC = S_XinASRC_BT_UL_ADDR/S_XinASRC_BT_UL_sizeof/ASRC_BT_UL_FIR_L+ASRC_margin/1/0/0/0/0
+ */
+void abe_init_asrc_bt_ul(s32 dppm)
+{
+ s32 el[45];
+ s32 temp0, temp1, adppm, dtemp, mem_tag, mem_addr;
+ u32 i = 0;
+ temp0 = 0;
+ temp1 = 1;
+
+ /* 1. DriftSign = D_AsrcVars[1] = 1 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_BT_UL_ADDR + (1 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm >= 0) {
+ el[i + 1] = 1;
+ adppm = dppm;
+ } else {
+ el[i + 1] = -1;
+ adppm = (-1 * dppm);
+ }
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ dtemp = (adppm << 4) + adppm - ((adppm * 3481L) / 15625L);
+
+ /* 2. Subblock = D_AsrcVars[2] = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_BT_UL_ADDR + (2 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ el[i + 1] = temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 3. DeltaAlpha = D_AsrcVars[3] = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_BT_UL_ADDR + (3 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm == 0)
+ el[i + 1] = 0;
+ else
+ el[i + 1] = dtemp << 2;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 4. MinusDeltaAlpha = D_AsrcVars[4] = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_BT_UL_ADDR + (4 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm == 0)
+ el[i + 1] = 0;
+ else
+ el[i + 1] = (-dtemp) << 2;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /*5. OneMinusEpsilon = D_AsrcVars[5] = 0x00400000 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_BT_UL_ADDR + (5 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm == 0)
+ el[i + 1] = 0x00400000;
+ else
+ el[i + 1] = (0x00100000 - (dtemp / 2)) << 2;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 6. AlphaCurrent = 0x000020 (CMEM) */
+ mem_tag = ABE_CMEM;
+ mem_addr = C_AlphaCurrent_BT_UL_ADDR;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = 0x00000020;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 7. BetaCurrent = 0x3fffe0 (CMEM) */
+ mem_tag = ABE_CMEM;
+ mem_addr = C_BetaCurrent_BT_UL_ADDR;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = 0x003fffe0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 8. drift_ASRC = 0 & drift_io = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_IOdescr_ADDR + (BT_VX_UL_PORT * sizeof(ABE_SIODescriptor))
+ + drift_asrc_;
+ el[i] = (mem_tag << 16) + mem_addr;
+ el[i + 1] = temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 9. SMEM for ASRC_BT_UL_Coefs pointer */
+ /* ASRC_BT_UL_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0
+ /1/C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 */
+ mem_tag = ABE_SMEM;
+ mem_addr = ASRC_BT_UL_Coefs_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = C_CoefASRC16_VX_ADDR;
+ el[i + 1] = (el[i + 1] << 8) + C_CoefASRC16_VX_sizeof;
+ el[i + 2] = C_CoefASRC15_VX_ADDR;
+ el[i + 2] = (el[i + 2] << 8) + C_CoefASRC15_VX_sizeof;
+ i = i + 3;
+
+ /* 10. CMEM for ASRC_BT_UL_Coefs pointer */
+ /* ASRC_BT_UL_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/
+ 1/C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 */
+ mem_tag = ABE_CMEM;
+ mem_addr = ASRC_BT_UL_Coefs_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp1;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 11. SMEM for XinASRC_BT_UL pointer */
+ /* XinASRC_BT_UL = S_XinASRC_BT_UL_ADDR/S_XinASRC_BT_UL_sizeof/0/1/0/0/0/0 */
+ mem_tag = ABE_SMEM;
+ mem_addr = XinASRC_BT_UL_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = S_XinASRC_BT_UL_ADDR;
+ el[i + 1] = (el[i + 1] << 8) + S_XinASRC_BT_UL_sizeof;
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 12. CMEM for XinASRC_BT_UL pointer */
+ /* XinASRC_BT_UL = S_XinASRC_BT_UL_ADDR/S_XinASRC_BT_UL_sizeof/0/1/0/0/0/0 */
+ mem_tag = ABE_CMEM;
+ mem_addr = XinASRC_BT_UL_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 13. SMEM for IO_BT_UL_ASRC pointer */
+ /* IO_BT_UL_ASRC = S_XinASRC_BT_UL_ADDR/S_XinASRC_BT_UL_sizeof/
+ ASRC_BT_UL_FIR_L+ASRC_margin/1/0/0/0/0 */
+ mem_tag = ABE_SMEM;
+ mem_addr = IO_BT_UL_ASRC_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = S_XinASRC_BT_UL_ADDR;
+ el[i + 1] = (el[i + 1] << 8) + S_XinASRC_BT_UL_sizeof;
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 14. CMEM for IO_BT_UL_ASRC pointer */
+ /* IO_BT_UL_ASRC = S_XinASRC_BT_UL_ADDR/S_XinASRC_BT_UL_sizeof/
+ ASRC_BT_UL_FIR_L+ASRC_margin/1/0/0/0/0 */
+ mem_tag = ABE_CMEM;
+ mem_addr = IO_BT_UL_ASRC_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = ((ASRC_BT_UL_FIR_L + ASRC_margin) << 16) + (temp1 << 12)
+ + (temp0 << 4) + temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ abe_write_fifo(ABE_DMEM, D_FwMemInitDescr_ADDR, (u32 *) &el[0], 42);
+}
+/**
+ * abe_init_asrc_bt_dl
+ *
+ * Initialize the following ASRC BT_DL parameters :
+ * 1. DriftSign = D_AsrcVars[1] = 1 or -1
+ * 2. Subblock = D_AsrcVars[2] = 0
+ * 3. DeltaAlpha = D_AsrcVars[3] = (round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2
+ * 4. MinusDeltaAlpha = D_AsrcVars[4] = (-round(nb_phases * drift[ppm] * 10^-6 * 2^20)) << 2
+ * 5. OneMinusEpsilon = D_AsrcVars[5] = 1 - DeltaAlpha/2
+ * 6. AlphaCurrent = 0x000020 (CMEM), initial value of Alpha parameter
+ * 7. BetaCurrent = 0x3fffe0 (CMEM), initial value of Beta parameter
+ * AlphaCurrent + BetaCurrent = 1 (=0x400000 in CMEM = 2^20 << 2)
+ * 8. drift_ASRC = 0 & drift_io = 0
+ * 9. SMEM for ASRC_BT_DL_Coefs pointer
+ * 10. CMEM for ASRC_BT_DL_Coefs pointer
+ * ASRC_BT_DL_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof
+ * /0/1/C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1
+ * 11. SMEM for XinASRC_BT_DL pointer
+ * 12. CMEM for XinASRC_BT_DL pointer
+ * XinASRC_BT_DL = S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/0/1/0/0/0/0
+ * 13. SMEM for DL_48_8_DEC pointer
+ * 14. CMEM for DL_48_8_DEC pointer
+ * DL_48_8_DEC = S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/
+ * ASRC_BT_DL_FIR_L+ASRC_margin/1/0/0/0/0
+ * 15. SMEM for DL_48_16_DEC pointer
+ * 16. CMEM for DL_48_16_DEC pointer
+ * DL_48_16_DEC = S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/
+ * ASRC_BT_DL_FIR_L+ASRC_margin/1/0/0/0/0
+ */
+void abe_init_asrc_bt_dl(s32 dppm)
+{
+ s32 el[51];
+ s32 temp0, temp1, adppm, dtemp, mem_tag, mem_addr;
+ u32 i = 0;
+ temp0 = 0;
+ temp1 = 1;
+
+ /* 1. DriftSign = D_AsrcVars[1] = 1 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_BT_DL_ADDR + (1 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm >= 0) {
+ el[i + 1] = 1;
+ adppm = dppm;
+ } else {
+ el[i + 1] = -1;
+ adppm = (-1 * dppm);
+ }
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+ dtemp = (adppm << 4) + adppm - ((adppm * 3481L) / 15625L);
+
+ /* 2. Subblock = D_AsrcVars[2] = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_BT_DL_ADDR + (2 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ el[i + 1] = temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 3. DeltaAlpha = D_AsrcVars[3] = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_BT_DL_ADDR + (3 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm == 0)
+ el[i + 1] = 0;
+ else
+ el[i + 1] = dtemp << 2;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 4. MinusDeltaAlpha = D_AsrcVars[4] = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_BT_DL_ADDR + (4 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm == 0)
+ el[i + 1] = 0;
+ else
+ el[i + 1] = (-dtemp) << 2;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 5. OneMinusEpsilon = D_AsrcVars[5] = 0x00400000 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_AsrcVars_BT_DL_ADDR + (5 * sizeof(s32));
+ el[i] = (mem_tag << 16) + mem_addr;
+ if (dppm == 0)
+ el[i + 1] = 0x00400000;
+ else
+ el[i + 1] = (0x00100000 - (dtemp / 2)) << 2;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 6. AlphaCurrent = 0x000020 (CMEM) */
+ mem_tag = ABE_CMEM;
+ mem_addr = C_AlphaCurrent_BT_DL_ADDR;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = 0x00000020;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 7. BetaCurrent = 0x3fffe0 (CMEM) */
+ mem_tag = ABE_CMEM;
+ mem_addr = C_BetaCurrent_BT_DL_ADDR;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = 0x003fffe0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 8. drift_ASRC = 0 & drift_io = 0 */
+ mem_tag = ABE_DMEM;
+ mem_addr = D_IOdescr_ADDR + (BT_VX_DL_PORT * sizeof(ABE_SIODescriptor))
+ + drift_asrc_;
+ el[i] = (mem_tag << 16) + mem_addr;
+ el[i + 1] = temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 9. SMEM for ASRC_BT_DL_Coefs pointer */
+ /* ASRC_BT_DL_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/
+ C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 */
+ mem_tag = ABE_SMEM;
+ mem_addr = ASRC_BT_DL_Coefs_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = (C_CoefASRC16_VX_ADDR << 8) + C_CoefASRC16_VX_sizeof;
+ el[i + 2] = (C_CoefASRC15_VX_ADDR << 8) + C_CoefASRC15_VX_sizeof;
+ i = i + 3;
+
+ /* 10. CMEM for ASRC_BT_DL_Coefs pointer */
+ /* ASRC_BT_DL_Coefs = C_CoefASRC16_VX_ADDR/C_CoefASRC16_VX_sizeof/0/1/
+ C_CoefASRC15_VX_ADDR/C_CoefASRC15_VX_sizeof/0/1 */
+ mem_tag = ABE_CMEM;
+ mem_addr = ASRC_BT_DL_Coefs_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp1;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 11. SMEM for XinASRC_BT_DL pointer */
+ /* XinASRC_BT_DL = S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/0/1/0/0/0/0 */
+ mem_tag = ABE_SMEM;
+ mem_addr = XinASRC_BT_DL_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = (S_XinASRC_BT_DL_ADDR << 8) + S_XinASRC_BT_DL_sizeof;
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 12. CMEM for XinASRC_BT_DL pointer */
+ /* XinASRC_BT_DL = S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/0/1/0/0/0/0 */
+ mem_tag = ABE_CMEM;
+ mem_addr = XinASRC_BT_DL_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = (temp0 << 16) + (temp1 << 12) + (temp0 << 4) + temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 13. SMEM for DL_48_8_DEC pointer */
+ /* DL_48_8_DEC = S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/
+ ASRC_BT_DL_FIR_L+ASRC_margin/1/0/0/0/0 */
+ mem_tag = ABE_SMEM;
+ mem_addr = DL_48_8_DEC_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = (S_XinASRC_BT_DL_ADDR << 8) + S_XinASRC_BT_DL_sizeof;
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 14. CMEM for DL_48_8_DEC pointer */
+ /* DL_48_8_DEC = S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/
+ ASRC_BT_DL_FIR_L+ASRC_margin/1/0/0/0/0 */
+ mem_tag = ABE_CMEM;
+ mem_addr = DL_48_8_DEC_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = ((ASRC_BT_DL_FIR_L + ASRC_margin) << 16) + (temp1 << 12)
+ + (temp0 << 4) + temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 15. SMEM for DL_48_16_DEC pointer */
+ /* DL_48_16_DEC = S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/
+ ASRC_BT_DL_FIR_L+ASRC_margin/1/0/0/0/0 */
+ mem_tag = ABE_SMEM;
+ mem_addr = DL_48_16_DEC_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ el[i + 1] = (S_XinASRC_BT_DL_ADDR << 8) + S_XinASRC_BT_DL_sizeof;
+ el[i + 2] = temp0;
+ i = i + 3;
+
+ /* 16. CMEM for DL_48_16_DEC pointer */
+ /* DL_48_16_DEC = S_XinASRC_BT_DL_ADDR/S_XinASRC_BT_DL_sizeof/
+ ASRC_BT_DL_FIR_L+ASRC_margin/1/0/0/0/0 */
+ mem_tag = ABE_CMEM;
+ mem_addr = DL_48_16_DEC_labelID;
+ el[i] = (mem_tag << 16) + (mem_addr << 2);
+ /* el[i+1] = iam1<<16 + inc1<<12 + iam2<<4 + inc2 */
+ el[i + 1] = ((ASRC_BT_DL_FIR_L + ASRC_margin) << 16) + (temp1 << 12)
+ + (temp0 << 4) + temp0;
+ /* dummy field */
+ el[i + 2] = temp0;
+ abe_write_fifo(ABE_DMEM, D_FwMemInitDescr_ADDR, (u32 *) &el[0], 48);
+}
diff --git a/sound/soc/omap/abe/abe_initxxx_labels.h b/sound/soc/omap/abe/abe_initxxx_labels.h
new file mode 100644
index 00000000000..5120c000dfa
--- /dev/null
+++ b/sound/soc/omap/abe/abe_initxxx_labels.h
@@ -0,0 +1,332 @@
+/*
+ * ALSA SoC OMAP ABE driver
+*
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef _ABE_INITXXX_LABELS_H_
+#define _ABE_INITXXX_LABELS_H_
+#define Dummy_Regs_labelID 0
+#define Dummy_AM_labelID 1
+#define Voice_8k_UL_labelID 2
+#define Voice_8k_DL_labelID 3
+#define ECHO_REF_8K_labelID 4
+#define Voice_16k_UL_labelID 5
+#define Voice_16k_DL_labelID 6
+#define ECHO_REF_16K_labelID 7
+#define MM_DL_labelID 8
+#define IO_VX_DL_ASRC_labelID 9
+#define IO_MM_EXT_IN_ASRC_labelID 10
+#define IO_VIBRA_DL_labelID 11
+#define ZERO_labelID 12
+#define GTarget_labelID 13
+#define GCurrent_labelID 14
+#define Gr_1_labelID 15
+#define Gr_2_labelID 16
+#define Gr_Regs_labelID 17
+#define DMIC0_Gain_labelID 18
+#define DMIC1_Gain_labelID 19
+#define DMIC2_Gain_labelID 20
+#define DMIC3_Gain_labelID 21
+#define AMIC_Gain_labelID 22
+#define MIXDL1_Gain_labelID 23
+#define MIXDL2_Gain_labelID 24
+#define DEFAULT_Gain_labelID 25
+#define DL1_M_G_Tones_labelID 26
+#define DL2_M_G_Tones_labelID 27
+#define Echo_M_G_labelID 28
+#define SDT_M_G_labelID 29
+#define VXREC_M_G_VX_DL_labelID 30
+#define UL_M_G_VX_DL_labelID 31
+#define DL1_M_labelID 32
+#define DL2_M_labelID 33
+#define MM_UL2_labelID 34
+#define VX_DL_labelID 35
+#define Tones_labelID 36
+#define DL_M_MM_UL2_VX_DL_labelID 37
+#define Echo_M_labelID 38
+#define VX_UL_labelID 39
+#define VX_UL_M_labelID 40
+#define SDT_F_labelID 41
+#define SDT_F_data_labelID 42
+#define SDT_Coef_labelID 43
+#define SDT_Regs_labelID 44
+#define SDT_M_labelID 45
+#define DL1_EQ_labelID 46
+#define DL2_EQ_labelID 47
+#define DL1_GAIN_out_labelID 48
+#define DL2_GAIN_out_labelID 49
+#define DMIC1_labelID 50
+#define DMIC1_L_labelID 51
+#define DMIC1_R_labelID 52
+#define DMIC2_labelID 53
+#define DMIC2_L_labelID 54
+#define DMIC2_R_labelID 55
+#define DMIC3_labelID 56
+#define DMIC3_L_labelID 57
+#define DMIC3_R_labelID 58
+#define MIC4_labelID 59
+#define MIC4_L_labelID 60
+#define MIC4_R_labelID 61
+#define BT_UL_L_labelID 62
+#define BT_UL_R_labelID 63
+#define AMIC_labelID 64
+#define AMIC_L_labelID 65
+#define AMIC_R_labelID 66
+#define EchoRef_L_labelID 67
+#define EchoRef_R_labelID 68
+#define MM_DL_L_labelID 69
+#define MM_DL_R_labelID 70
+#define MM_UL_labelID 71
+#define AMIC_96_labelID 72
+#define DMIC0_96_labelID 73
+#define DMIC1_96_labelID 74
+#define DMIC2_96_labelID 75
+#define UL_MIC_48K_labelID 76
+#define EQ_DL_48K_labelID 77
+#define EQ_48K_labelID 78
+#define McPDM_Out1_labelID 79
+#define McPDM_Out2_labelID 80
+#define McPDM_Out3_labelID 81
+#define VX_UL_MUX_labelID 82
+#define MM_UL2_MUX_labelID 83
+#define MM_UL_MUX_labelID 84
+#define XinASRC_DL_VX_labelID 85
+#define ASRC_DL_VX_Coefs_labelID 86
+#define ASRC_DL_VX_Alpha_labelID 87
+#define ASRC_DL_VX_VarsBeta_labelID 88
+#define ASRC_DL_VX_8k_Regs_labelID 89
+#define XinASRC_UL_VX_labelID 90
+#define ASRC_UL_VX_Coefs_labelID 91
+#define ASRC_UL_VX_Alpha_labelID 92
+#define ASRC_UL_VX_VarsBeta_labelID 93
+#define ASRC_UL_VX_8k_Regs_labelID 94
+#define UL_48_8_DEC_labelID 95
+#define ASRC_DL_VX_16k_Regs_labelID 96
+#define ASRC_UL_VX_16k_Regs_labelID 97
+#define UL_48_16_DEC_labelID 98
+#define XinASRC_MM_EXT_IN_labelID 99
+#define ASRC_MM_EXT_IN_Coefs_labelID 100
+#define ASRC_MM_EXT_IN_Alpha_labelID 101
+#define ASRC_MM_EXT_IN_VarsBeta_labelID 102
+#define ASRC_MM_EXT_IN_Regs_labelID 103
+#define VX_REC_labelID 104
+#define VXREC_UL_M_Tones_VX_UL_labelID 105
+#define VX_REC_L_labelID 106
+#define VX_REC_R_labelID 107
+#define DL2_M_L_labelID 108
+#define DL2_M_R_labelID 109
+#define DL1_M_data_labelID 110
+#define DL1_M_Coefs_labelID 111
+#define DL2_M_LR_data_labelID 112
+#define DL2_M_LR_Coefs_labelID 113
+#define SRC_6_LP_COEFS_labelID 114
+#define SRC_6_LP_GAIN_COEFS_labelID 115
+#define SRC_6_HP_COEFS_labelID 116
+#define SRC_3_LP_COEFS_labelID 117
+#define SRC_3_LP_GAIN_COEFS_labelID 118
+#define SRC_3_HP_COEFS_labelID 119
+#define VX_DL_8_48_LP_DATA_labelID 120
+#define VX_DL_8_48_HP_DATA_labelID 121
+#define VX_DL_16_48_LP_DATA_labelID 122
+#define VX_DL_16_48_HP_DATA_labelID 123
+#define VX_UL_48_8_LP_DATA_labelID 124
+#define VX_UL_48_8_HP_DATA_labelID 125
+#define VX_UL_48_16_LP_DATA_labelID 126
+#define VX_UL_48_16_HP_DATA_labelID 127
+#define BT_UL_8_48_LP_DATA_labelID 128
+#define BT_UL_8_48_HP_DATA_labelID 129
+#define BT_UL_16_48_LP_DATA_labelID 130
+#define BT_UL_16_48_HP_DATA_labelID 131
+#define BT_DL_48_8_LP_DATA_labelID 132
+#define BT_DL_48_8_HP_DATA_labelID 133
+#define BT_DL_48_16_LP_DATA_labelID 134
+#define BT_DL_48_16_HP_DATA_labelID 135
+#define ECHO_REF_48_16_LP_DATA_labelID 136
+#define ECHO_REF_48_16_HP_DATA_labelID 137
+#define ECHO_REF_48_8_LP_DATA_labelID 138
+#define ECHO_REF_48_8_HP_DATA_labelID 139
+#define ECHO_REF_DEC_labelID 140
+#define VX_UL_8_TEMP_labelID 141
+#define VX_UL_16_TEMP_labelID 142
+#define UP_DOWN_8_48_labelID 143
+#define UP_DOWN_16_48_labelID 144
+#define SRC_6_LP_48k_labelID 145
+#define SRC_6_HP_labelID 146
+#define SRC_3_LP_48k_labelID 147
+#define SRC_3_HP_labelID 148
+#define EARP_48_96_LP_DATA_labelID 149
+#define SRC_48_96_LP_labelID 150
+#define IHF_48_96_LP_DATA_labelID 151
+#define EQ_VX_UL_16K_labelID 152
+#define pAPS_iir1_p23_labelID 153
+#define pAPS_iir1_p45_labelID 154
+#define APS_IIR_Regs_labelID 155
+#define pAPS_core_DL1_p1_labelID 156
+#define pAPS_core_DL1_p23_labelID 157
+#define pAPS_core_DL1_p45_labelID 158
+#define pAPS_core_DL1_r_labelID 159
+#define pAPS_DL2L_core_r_labelID 160
+#define pAPS_DL2R_core_r_labelID 161
+#define pAPS_COIL_core_DL1_p1_labelID 162
+#define pAPS_COIL_core_DL1_p23_labelID 163
+#define pAPS_COIL_core_DL1_p45_labelID 164
+#define pAPS_COIL_core_DL1_r_labelID 165
+#define DL2_L_APS_IIR_p23_labelID 166
+#define DL2_R_APS_IIR_p23_labelID 167
+#define DL2_L_APS_IIR_p45_labelID 168
+#define DL2_R_APS_IIR_p45_labelID 169
+#define DL2_L_APS_CORE_p1_labelID 170
+#define DL2_L_APS_CORE_p23_labelID 171
+#define DL2_L_APS_CORE_p45_labelID 172
+#define DL2_R_APS_CORE_p1_labelID 173
+#define DL2_R_APS_CORE_p23_labelID 174
+#define DL2_R_APS_CORE_p45_labelID 175
+#define DL2_L_APS_COIL_CORE_p1_labelID 176
+#define DL2_L_APS_COIL_CORE_p23_labelID 177
+#define DL2_L_APS_COIL_CORE_p45_labelID 178
+#define pAPS_COIL_DL2L_core_r_labelID 179
+#define DL2_R_APS_COIL_CORE_p1_labelID 180
+#define DL2_R_APS_COIL_CORE_p23_labelID 181
+#define DL2_R_APS_COIL_CORE_p45_labelID 182
+#define pAPS_COIL_DL2R_core_r_labelID 183
+#define DL1_APS_labelID 184
+#define DL2_L_APS_labelID 185
+#define DL2_R_APS_labelID 186
+#define DL1_APS_EQ_p23_labelID 187
+#define DL1_APS_EQ_p45_labelID 188
+#define DL2_APS_EQ_p23_labelID 189
+#define DL2_APS_EQ_p45_labelID 190
+#define pVIBRA1_p0_labelID 191
+#define pVIBRA1_p1_labelID 192
+#define pVIBRA1_p23_labelID 193
+#define pVIBRA1_p45_labelID 194
+#define pVibra1_pR1_labelID 195
+#define pVibra1_pR2_labelID 196
+#define pVibra1_pR3_labelID 197
+#define pVIBRA1_r_labelID 198
+#define pVIBRA2_p0_labelID 199
+#define pVIBRA2_p1_labelID 200
+#define pVIBRA2_p23_labelID 201
+#define pVIBRA2_p45_labelID 202
+#define pCtrl_p67_labelID 203
+#define pVIBRA2_r_labelID 204
+#define VIBRA_labelID 205
+#define PING_labelID 206
+#define PING_Regs_labelID 207
+#define UP_48_96_LP_COEFS_labelID 208
+#define AMIC_96_48_data_labelID 209
+#define DOWN_96_48_AMIC_Coefs_labelID 210
+#define DOWN_96_48_DMIC_Coefs_labelID 211
+#define DOWN_96_48_AMIC_Regs_labelID 212
+#define DOWN_96_48_DMIC_Regs_labelID 213
+#define DMIC0_96_48_data_labelID 214
+#define DMIC1_96_48_data_labelID 215
+#define DMIC2_96_48_data_labelID 216
+#define SIO_DMIC_labelID 217
+#define SIO_PDM_UL_labelID 218
+#define SIO_BT_VX_UL_labelID 219
+#define SIO_MM_UL_labelID 220
+#define SIO_MM_UL2_labelID 221
+#define SIO_VX_UL_labelID 222
+#define SIO_MM_DL_labelID 223
+#define SIO_VX_DL_labelID 224
+#define SIO_TONES_DL_labelID 225
+#define SIO_VIB_DL_labelID 226
+#define SIO_BT_VX_DL_labelID 227
+#define SIO_PDM_DL_labelID 228
+#define SIO_MM_EXT_OUT_labelID 229
+#define SIO_MM_EXT_IN_labelID 230
+#define SIO_TDM_OUT_labelID 231
+#define SIO_TDM_IN_labelID 232
+#define DMIC_ATC_PTR_labelID 233
+#define MCPDM_UL_ATC_PTR_labelID 234
+#define BT_VX_UL_ATC_PTR_labelID 235
+#define MM_UL_ATC_PTR_labelID 236
+#define MM_UL2_ATC_PTR_labelID 237
+#define VX_UL_ATC_PTR_labelID 238
+#define MM_DL_ATC_PTR_labelID 239
+#define VX_DL_ATC_PTR_labelID 240
+#define TONES_DL_ATC_PTR_labelID 241
+#define VIB_DL_ATC_PTR_labelID 242
+#define BT_VX_DL_ATC_PTR_labelID 243
+#define PDM_DL_ATC_PTR_labelID 244
+#define MM_EXT_OUT_ATC_PTR_labelID 245
+#define MM_EXT_IN_ATC_PTR_labelID 246
+#define TDM_OUT_ATC_PTR_labelID 247
+#define TDM_IN_ATC_PTR_labelID 248
+#define MCU_IRQ_FIFO_ptr_labelID 249
+#define DEBUG_IRQ_FIFO_reg_labelID 250
+#define UP_DOWN_48_96_labelID 251
+#define OSR96_2_labelID 252
+#define DEBUG_GAINS_labelID 253
+#define DBG_8K_PATTERN_labelID 254
+#define DBG_16K_PATTERN_labelID 255
+#define DBG_24K_PATTERN_labelID 256
+#define DBG_48K_PATTERN_labelID 257
+#define DBG_96K_PATTERN_labelID 258
+#define UL_VX_UL_48_8K_labelID 259
+#define UL_VX_UL_48_16K_labelID 260
+#define BT_DL_labelID 261
+#define BT_UL_labelID 262
+#define BT_DL_8k_labelID 263
+#define BT_DL_16k_labelID 264
+#define BT_UL_8k_labelID 265
+#define BT_UL_16k_labelID 266
+#define MM_EXT_IN_labelID 267
+#define MM_EXT_IN_L_labelID 268
+#define MM_EXT_IN_R_labelID 269
+#define ECHO_REF_48_16_WRAP_labelID 270
+#define ECHO_REF_48_8_WRAP_labelID 271
+#define BT_UL_16_48_WRAP_labelID 272
+#define BT_UL_8_48_WRAP_labelID 273
+#define BT_DL_48_16_WRAP_labelID 274
+#define BT_DL_48_8_WRAP_labelID 275
+#define VX_DL_16_48_WRAP_labelID 276
+#define VX_DL_8_48_WRAP_labelID 277
+#define VX_UL_48_16_WRAP_labelID 278
+#define VX_UL_48_8_WRAP_labelID 279
+#define APS_DL1_IRQs_WRAP_labelID 280
+#define APS_DL2_L_IRQs_WRAP_labelID 281
+#define APS_DL2_R_IRQs_WRAP_labelID 282
+#define ATC_NULL_BUFFER_labelID 283
+#define MEM_INIT_hal_mem_labelID 284
+#define MEM_INIT_write_mem_labelID 285
+#define MEM_INIT_regs_labelID 286
+#define GAIN_0DB_labelID 287
+#define XinASRC_BT_UL_labelID 288
+#define IO_BT_UL_ASRC_labelID 289
+#define ASRC_BT_UL_Coefs_labelID 290
+#define ASRC_BT_UL_Alpha_labelID 291
+#define ASRC_BT_UL_VarsBeta_labelID 292
+#define ASRC_BT_UL_8k_Regs_labelID 293
+#define ASRC_BT_UL_16k_Regs_labelID 294
+#define XinASRC_BT_DL_labelID 295
+#define DL_48_8_DEC_labelID 296
+#define DL_48_16_DEC_labelID 297
+#define BT_DL_8k_TEMP_labelID 298
+#define BT_DL_16k_TEMP_labelID 299
+#define BT_DL_8k_opp100_labelID 300
+#define BT_DL_16k_opp100_labelID 301
+#define ASRC_BT_DL_Coefs_labelID 302
+#define ASRC_BT_DL_Alpha_labelID 303
+#define ASRC_BT_DL_VarsBeta_labelID 304
+#define ASRC_BT_DL_8k_Regs_labelID 305
+#define ASRC_BT_DL_16k_Regs_labelID 306
+#define BT_DL_48_8_OPP100_WRAP_labelID 307
+#define BT_DL_48_16_OPP100_WRAP_labelID 308
+#endif/* _ABE_INITXXXX_LABELS_H_ */
diff --git a/sound/soc/omap/abe/abe_irq.c b/sound/soc/omap/abe/abe_irq.c
new file mode 100644
index 00000000000..cfed1c2cb5a
--- /dev/null
+++ b/sound/soc/omap/abe/abe_irq.c
@@ -0,0 +1,62 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include "abe_main.h"
+/*
+ * initialize the default values for call-backs to subroutines
+ * - FIFO IRQ call-backs for sequenced tasks
+ * - FIFO IRQ call-backs for audio player/recorders (ping-pong protocols)
+ * - Remote debugger interface
+ * - Error monitoring
+ * - Activity Tracing
+ */
+/**
+ * abe_irq_ping_pong
+ *
+ * Call the respective subroutine depending on the IRQ FIFO content:
+ * APS interrupts : IRQtag_APS to [31:28], APS_IRQs to [27:16], loopCounter to [15:0]
+ * SEQ interrupts : IRQtag_COUNT to [31:28], Count_IRQs to [27:16], loopCounter to [15:0]
+ * Ping-Pong Interrupts : IRQtag_PP to [31:28], PP_MCU_IRQ to [27:16], loopCounter to [15:0]
+ */
+void abe_irq_ping_pong(void)
+{
+ abe_call_subroutine(abe_irq_pingpong_player_id, NOPARAMETER,
+ NOPARAMETER, NOPARAMETER, NOPARAMETER);
+}
+/**
+ * abe_irq_check_for_sequences
+* @i: sequence ID
+ *
+ * check the active sequence list
+ *
+ */
+void abe_irq_check_for_sequences(u32 i)
+{
+}
+/**
+ * abe_irq_aps
+ *
+ * call the application subroutines that updates the acoustics protection filters
+ */
+void abe_irq_aps(u32 aps_info)
+{
+ abe_call_subroutine(abe_irq_aps_adaptation_id, NOPARAMETER, NOPARAMETER,
+ NOPARAMETER, NOPARAMETER);
+}
diff --git a/sound/soc/omap/abe/abe_lib.c b/sound/soc/omap/abe/abe_lib.c
new file mode 100644
index 00000000000..d95afe74343
--- /dev/null
+++ b/sound/soc/omap/abe/abe_lib.c
@@ -0,0 +1,394 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include "abe_main.h"
+/**
+* abe_fprintf
+* @line: character line to be printed
+*
+* Print ABE debug messages.
+*/
+/**
+ * abe_read_feature_from_port
+ * @x: d
+ *
+ * TBD
+ *
+ */
+void abe_read_feature_from_port(u32 x)
+{
+}
+/**
+ * abe_write_feature_to_port
+ * @x: d
+ *
+ * TBD
+ *
+ */
+void abe_write_feature_to_port(u32 x)
+{
+}
+/**
+ * abe_read_fifo
+ * @x: d
+ *
+ * TBD
+ */
+void abe_read_fifo(u32 x)
+{
+}
+/**
+ * abe_write_fifo
+ * @mem_bank: currently only ABE_DMEM supported
+ * @addr: FIFO descriptor address ( descriptor fields : READ ptr, WRITE ptr,
+ * FIFO START_ADDR, FIFO END_ADDR)
+ * @data: data to write to FIFO
+ * @number: number of 32-bit words to write to DMEM FIFO
+ *
+ * write DMEM FIFO and update FIFO descriptor, it is assumed that FIFO descriptor
+ * is located in DMEM
+ */
+void abe_write_fifo(u32 memory_bank, u32 descr_addr, u32 *data, u32 nb_data32)
+{
+ u32 fifo_addr[4];
+ u32 i;
+ /* read FIFO descriptor from DMEM */
+ abe_block_copy(COPY_FROM_ABE_TO_HOST, ABE_DMEM, descr_addr,
+ &fifo_addr[0], 4 * sizeof(u32));
+ /* WRITE ptr < FIFO start address */
+ if (fifo_addr[1] < fifo_addr[2])
+ abe_dbg_error_log(ABE_FW_FIFO_WRITE_PTR_ERR);
+ /* WRITE ptr > FIFO end address */
+ if (fifo_addr[1] > fifo_addr[3])
+ abe_dbg_error_log(ABE_FW_FIFO_WRITE_PTR_ERR);
+ switch (memory_bank) {
+ case ABE_DMEM:
+ for (i = 0; i < nb_data32; i++) {
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM,
+ (s32) fifo_addr[1], (u32 *) (data + i),
+ 4);
+ /* increment WRITE pointer */
+ fifo_addr[1] = fifo_addr[1] + 4;
+ if (fifo_addr[1] > fifo_addr[3])
+ fifo_addr[1] = fifo_addr[2];
+ if (fifo_addr[1] == fifo_addr[0])
+ abe_dbg_error_log(ABE_FW_FIFO_WRITE_PTR_ERR);
+ }
+ /* update WRITE pointer in DMEM */
+ abe_block_copy(COPY_FROM_HOST_TO_ABE, ABE_DMEM, descr_addr +
+ sizeof(u32), &fifo_addr[1], 4);
+ break;
+ default:
+ /* printf("currently only DMEM FIFO write supported ERROR\n"); */
+ break;
+ }
+}
+/**
+ * abe_monitoring
+ *
+ * checks the internal status of ABE and HAL
+ */
+void abe_monitoring(void)
+{
+ abe_dbg_param = 0;
+}
+/**
+ * abe_format_switch
+ * @f: port format
+ * @iter: port iteration
+ * @mulfac: multiplication factor
+ *
+ * translates the sampling and data length to ITER number for the DMA
+ * and the multiplier factor to apply during data move with DMEM
+ *
+ */
+void abe_format_switch(abe_data_format_t *f, u32 *iter, u32 *mulfac)
+{
+ u32 n_freq;
+#if FW_SCHED_LOOP_FREQ==4000
+ switch (f->f) {
+ /* nb of samples processed by scheduling loop */
+ case 8000:
+ n_freq = 2;
+ break;
+ case 16000:
+ n_freq = 4;
+ break;
+ case 24000:
+ n_freq = 6;
+ break;
+ case 44100:
+ n_freq = 12;
+ break;
+ case 96000:
+ n_freq = 24;
+ break;
+ default/*case 48000 */ :
+ n_freq = 12;
+ break;
+ }
+#else
+ /* erroneous cases */
+ n_freq = 0;
+#endif
+ switch (f->samp_format) {
+ case MONO_MSB:
+ case MONO_RSHIFTED_16:
+ case STEREO_16_16:
+ *mulfac = 1;
+ break;
+ case STEREO_MSB:
+ case STEREO_RSHIFTED_16:
+ *mulfac = 2;
+ break;
+ case THREE_MSB:
+ *mulfac = 3;
+ break;
+ case FOUR_MSB:
+ *mulfac = 4;
+ break;
+ case FIVE_MSB:
+ *mulfac = 5;
+ break;
+ case SIX_MSB:
+ *mulfac = 6;
+ break;
+ case SEVEN_MSB:
+ *mulfac = 7;
+ break;
+ case EIGHT_MSB:
+ *mulfac = 8;
+ break;
+ case NINE_MSB:
+ *mulfac = 9;
+ break;
+ default:
+ *mulfac = 1;
+ break;
+ }
+ *iter = (n_freq * (*mulfac));
+}
+/**
+ * abe_dma_port_iteration
+ * @f: port format
+ *
+ * translates the sampling and data length to ITER number for the DMA
+ */
+u32 abe_dma_port_iteration(abe_data_format_t *f)
+{
+ u32 iter, mulfac;
+ abe_format_switch(f, &iter, &mulfac);
+ return iter;
+}
+/**
+ * abe_dma_port_iter_factor
+ * @f: port format
+ *
+ * returns the multiplier factor to apply during data move with DMEM
+ */
+u32 abe_dma_port_iter_factor(abe_data_format_t *f)
+{
+ u32 iter, mulfac;
+ abe_format_switch(f, &iter, &mulfac);
+ return mulfac;
+}
+/**
+ * abe_dma_port_copy_subroutine_id
+ *
+ * @port_id: ABE port ID
+ *
+ * returns the index of the function doing the copy in I/O tasks
+ */
+u32 abe_dma_port_copy_subroutine_id(u32 port_id)
+{
+ u32 sub_id;
+ if (abe_port[port_id].protocol.direction == ABE_ATC_DIRECTION_IN) {
+ switch (abe_port[port_id].format.samp_format) {
+ case MONO_MSB:
+ sub_id = D2S_MONO_MSB_CFPID;
+ break;
+ case MONO_RSHIFTED_16:
+ sub_id = D2S_MONO_RSHIFTED_16_CFPID;
+ break;
+ case STEREO_RSHIFTED_16:
+ sub_id = D2S_STEREO_RSHIFTED_16_CFPID;
+ break;
+ case STEREO_16_16:
+ sub_id = D2S_STEREO_16_16_CFPID;
+ break;
+ case STEREO_MSB:
+ sub_id = D2S_STEREO_MSB_CFPID;
+ break;
+ case SIX_MSB:
+ if (port_id == DMIC_PORT) {
+ sub_id = COPY_DMIC_CFPID;
+ break;
+ }
+ default:
+ sub_id = NULL_COPY_CFPID;
+ break;
+ }
+ } else {
+ switch (abe_port[port_id].format.samp_format) {
+ case MONO_MSB:
+ sub_id = S2D_MONO_MSB_CFPID;
+ break;
+ case MONO_RSHIFTED_16:
+ sub_id = S2D_MONO_RSHIFTED_16_CFPID;
+ break;
+ case STEREO_RSHIFTED_16:
+ sub_id = S2D_STEREO_RSHIFTED_16_CFPID;
+ break;
+ case STEREO_16_16:
+ sub_id = S2D_STEREO_16_16_CFPID;
+ break;
+ case STEREO_MSB:
+ sub_id = S2D_STEREO_MSB_CFPID;
+ break;
+ case SIX_MSB:
+ if (port_id == PDM_DL_PORT) {
+ sub_id = COPY_MCPDM_DL_CFPID;
+ break;
+ }
+ if (port_id == MM_UL_PORT) {
+ sub_id = COPY_MM_UL_CFPID;
+ break;
+ }
+ case THREE_MSB:
+ case FOUR_MSB:
+ case FIVE_MSB:
+ case SEVEN_MSB:
+ case EIGHT_MSB:
+ case NINE_MSB:
+ sub_id = COPY_MM_UL_CFPID;
+ break;
+ default:
+ sub_id = NULL_COPY_CFPID;
+ break;
+ }
+ }
+ return sub_id;
+}
+/**
+ * abe_int_2_float
+ * returns a mantissa on 16 bits and the exponent
+ * 0x4000.0000 leads to M=0x4000 X=15
+ * 0x0004.0000 leads to M=0x4000 X=4
+ * 0x0000.0001 leads to M=0x4000 X=-14
+ *
+ */
+void abe_int_2_float16(u32 data, u32 *mantissa, u32 *exp)
+{
+ u32 i;
+ *exp = 0;
+ *mantissa = 0;
+ for (i = 0; i < 32; i++) {
+ if ((1 << i) > data)
+ break;
+ }
+ *exp = i - 15;
+ *mantissa = (*exp > 0) ? data >> (*exp) : data << (*exp);
+}
+/**
+ * abe_gain_offset
+ * returns the offset to firmware data structures
+ *
+ */
+void abe_gain_offset(u32 id, u32 *mixer_offset)
+{
+ switch (id) {
+ default:
+ case GAINS_DMIC1:
+ *mixer_offset = dmic1_gains_offset;
+ break;
+ case GAINS_DMIC2:
+ *mixer_offset = dmic2_gains_offset;
+ break;
+ case GAINS_DMIC3:
+ *mixer_offset = dmic3_gains_offset;
+ break;
+ case GAINS_AMIC:
+ *mixer_offset = amic_gains_offset;
+ break;
+ case GAINS_DL1:
+ *mixer_offset = dl1_gains_offset;
+ break;
+ case GAINS_DL2:
+ *mixer_offset = dl2_gains_offset;
+ break;
+ case GAINS_SPLIT:
+ *mixer_offset = splitters_gains_offset;
+ break;
+ case MIXDL1:
+ *mixer_offset = mixer_dl1_offset;
+ break;
+ case MIXDL2:
+ *mixer_offset = mixer_dl2_offset;
+ break;
+ case MIXECHO:
+ *mixer_offset = mixer_echo_offset;
+ break;
+ case MIXSDT:
+ *mixer_offset = mixer_sdt_offset;
+ break;
+ case MIXVXREC:
+ *mixer_offset = mixer_vxrec_offset;
+ break;
+ case MIXAUDUL:
+ *mixer_offset = mixer_audul_offset;
+ break;
+ }
+}
+/**
+ * abe_decide_main_port - Select stynchronization port for Event generator.
+ * @id: audio port name
+ *
+ * tells the FW which is the reference stream for adjusting
+ * the processing on 23/24/25 slots
+ *
+ * takes the first port in a list which is slave on the data interface
+ */
+u32 abe_valid_port_for_synchro(u32 id)
+{
+ if ((abe_port[id].protocol.protocol_switch ==
+ DMAREQ_PORT_PROT) ||
+ (abe_port[id].protocol.protocol_switch ==
+ PINGPONG_PORT_PROT) ||
+ (abe_port[id].status != OMAP_ABE_PORT_ACTIVITY_RUNNING))
+ return 0;
+ else
+ return 1;
+}
+void abe_decide_main_port(void)
+{
+ u32 id, id_not_found;
+ id_not_found = 1;
+ for (id = 0; id < LAST_PORT_ID - 1; id++) {
+ if (abe_valid_port_for_synchro(abe_port_priority[id])) {
+ id_not_found = 0;
+ break;
+ }
+ }
+ /* if no port is currently activated, the default one is PDM_DL */
+ if (id_not_found)
+ abe_select_main_port(PDM_DL_PORT);
+ else
+ abe_select_main_port(abe_port_priority[id]);
+}
diff --git a/sound/soc/omap/abe/abe_lib.h b/sound/soc/omap/abe/abe_lib.h
new file mode 100644
index 00000000000..647a941482d
--- /dev/null
+++ b/sound/soc/omap/abe/abe_lib.h
@@ -0,0 +1,122 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+/**
+ * abe_fprintf
+ *
+ * Parameter :
+ * character line to be printed
+ *
+ * Operations :
+ *
+ * Return value :
+ * None.
+ */
+void abe_fprintf(char *line);
+/*
+ * ABE_READ_FEATURE_FROM_PORT
+ *
+ * Parameter :
+ * x : d
+ *
+ * Operations :
+ *
+ *
+ * Return value :
+ *
+ */
+void abe_read_feature_from_port(u32 x);
+/*
+ * ABE_WRITE_FEATURE_TO_PORT
+ *
+ * Parameter :
+ * x : d
+ *
+ * Operations :
+ *
+ *
+ * Return value :
+ *
+ */
+void abe_write_feature_to_port(u32 x);
+/*
+ * ABE_READ_FIFO
+ *
+ * Parameter :
+ * x : d
+ *
+ * Operations :
+ *
+ *
+ * Return value :
+ *
+ */
+void abe_read_fifo(u32 x);
+/*
+ * ABE_WRITE_FIFO
+ *
+ * Parameter :
+ * mem_bank : currently only ABE_DMEM supported
+ * addr : FIFO descriptor address ( descriptor fields : READ ptr,
+ * WRITE ptr, FIFO START_ADDR, FIFO END_ADDR)
+ * data to write to FIFO
+ * number of 32-bit words to write to DMEM FIFO
+ *
+ * Operations :
+ * write DMEM FIFO and update FIFO descriptor, it is assumed that FIFO
+ * descriptor is located in DMEM
+ *
+ * Return value :
+ * none
+ */
+void abe_write_fifo(u32 mem_bank, u32 addr, u32 *data, u32 nb_data32);
+/*
+ * ABE_BLOCK_COPY
+ *
+ * Parameter :
+ * direction of the data move (Read/Write)
+ * memory bank among PMEM, DMEM, CMEM, SMEM, ATC/IO
+ * address of the memory copy (byte addressing)
+ * long pointer to the data
+ * number of data to move
+ *
+ * Operations :
+ * block data move
+ *
+ * Return value :
+ * none
+ */
+void abe_block_copy(u32 direction, u32 memory_bank, u32 address, u32 *data,
+ u32 nb);
+/*
+ * ABE_RESET_MEM
+ *
+ * Parameter :
+ * memory bank among DMEM, SMEM
+ * address of the memory copy (byte addressing)
+ * number of data to move
+ *
+ * Operations :
+ * reset memory
+ *
+ * Return value :
+ * none
+ */
+void abe_reset_mem(u32 memory_bank, u32 address, u32 nb_bytes);
diff --git a/sound/soc/omap/abe/abe_main.h b/sound/soc/omap/abe/abe_main.h
new file mode 100644
index 00000000000..4d60c088a80
--- /dev/null
+++ b/sound/soc/omap/abe/abe_main.h
@@ -0,0 +1,48 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#ifndef _ABE_MAIN_H_
+#define _ABE_MAIN_H_
+#include <linux/io.h>
+#include "abe_dm_addr.h"
+#include "abe_sm_addr.h"
+#include "abe_cm_addr.h"
+#include "abe_define.h"
+#include "abe_fw.h"
+#include "abe_def.h"
+#include "abe_typ.h"
+#include "abe_ext.h"
+#include "abe_dbg.h"
+#include "abe_lib.h"
+#include "abe_ref.h"
+#include "abe_api.h"
+#include "abe_typedef.h"
+#include "abe_functionsid.h"
+#include "abe_taskid.h"
+#include "abe_initxxx_labels.h"
+#include "abe_fw.h"
+/* pipe connection to the TARGET simulator */
+#define ABE_DEBUG_CHECKERS 0
+/* simulator data extracted from a text-file */
+#define ABE_DEBUG_HWFILE 0
+/* low-level log files */
+#define ABE_DEBUG_LL_LOG 0
+#define ABE_DEBUG (ABE_DEBUG_CHECKERS | ABE_DEBUG_HWFILE | ABE_DEBUG_LL_LOG)
+#endif /* _ABE_MAIN_H_ */
diff --git a/sound/soc/omap/abe/abe_mem.c b/sound/soc/omap/abe/abe_mem.c
new file mode 100644
index 00000000000..cbd0afb8d82
--- /dev/null
+++ b/sound/soc/omap/abe/abe_mem.c
@@ -0,0 +1,100 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include "abe_main.h"
+
+/**
+ * abe_block_copy
+ * @direction: direction of the data move (Read/Write)
+ * @memory_bamk:memory bank among PMEM, DMEM, CMEM, SMEM, ATC/IO
+ * @address: address of the memory copy (byte addressing)
+ * @data: pointer to the data to transfer
+ * @nb_bytes: number of data to move
+ *
+ * Memory transfer to/from ABE to MPU
+ */
+void abe_block_copy(u32 direction, u32 memory_bank, u32 address,
+ u32 *data, u32 nb_bytes)
+{
+ u32 i;
+ u32 base_address = 0, *src_ptr, *dst_ptr, n;
+ switch (memory_bank) {
+ case ABE_PMEM:
+ base_address = (u32) io_base + ABE_PMEM_BASE_OFFSET_MPU;
+ break;
+ case ABE_CMEM:
+ base_address = (u32) io_base + ABE_CMEM_BASE_OFFSET_MPU;
+ break;
+ case ABE_SMEM:
+ base_address = (u32) io_base + ABE_SMEM_BASE_OFFSET_MPU;
+ break;
+ case ABE_DMEM:
+ base_address = (u32) io_base + ABE_DMEM_BASE_OFFSET_MPU;
+ break;
+ case ABE_ATC:
+ base_address = (u32) io_base + ABE_ATC_BASE_OFFSET_MPU;
+ break;
+ default:
+ base_address = (u32) io_base + ABE_SMEM_BASE_OFFSET_MPU;
+ abe_dbg_param |= ERR_LIB;
+ abe_dbg_error_log(ABE_BLOCK_COPY_ERR);
+ break;
+ }
+ if (direction == COPY_FROM_HOST_TO_ABE) {
+ dst_ptr = (u32 *) (base_address + address);
+ src_ptr = (u32 *) data;
+ } else {
+ dst_ptr = (u32 *) data;
+ src_ptr = (u32 *) (base_address + address);
+ }
+ n = (nb_bytes / 4);
+ for (i = 0; i < n; i++)
+ *dst_ptr++ = *src_ptr++;
+}
+/**
+ * abe_reset_mem
+ *
+ * @memory_bank: memory bank among DMEM, SMEM
+ * @address: address of the memory copy (byte addressing)
+ * @nb_bytes: number of data to move
+ *
+ * Reset ABE memory
+ */
+void abe_reset_mem(u32 memory_bank, u32 address, u32 nb_bytes)
+{
+ u32 i;
+ u32 *dst_ptr, n;
+ u32 base_address = 0;
+ switch (memory_bank) {
+ case ABE_SMEM:
+ base_address = (u32) io_base + ABE_SMEM_BASE_OFFSET_MPU;
+ break;
+ case ABE_DMEM:
+ base_address = (u32) io_base + ABE_DMEM_BASE_OFFSET_MPU;
+ break;
+ case ABE_CMEM:
+ base_address = (u32) io_base + ABE_CMEM_BASE_OFFSET_MPU;
+ break;
+ }
+ dst_ptr = (u32 *) (base_address + address);
+ n = (nb_bytes / 4);
+ for (i = 0; i < n; i++)
+ *dst_ptr++ = 0;
+}
diff --git a/sound/soc/omap/abe/abe_ref.h b/sound/soc/omap/abe/abe_ref.h
new file mode 100644
index 00000000000..91f8e472dc0
--- /dev/null
+++ b/sound/soc/omap/abe/abe_ref.h
@@ -0,0 +1,158 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#ifndef _ABE_REF_H_
+#define _ABE_REF_H_
+/*
+ * 'ABE_PRO.H' all non-API prototypes for INI, IRQ, SEQ ...
+ */
+/*
+ * HAL EXTERNAL AP
+ */
+/*
+ * HAL INTERNAL AP
+ */
+void abe_decide_main_port(void);
+void abe_gain_offset(u32 id, u32 *mixer_offset);
+void abe_int_2_float16(u32 data, u32 *mantissa, u32 *exp);
+void abe_reset_gain_mixer(u32 id, u32 p);
+void abe_load_embeddded_patterns(void);
+void abe_build_scheduler_table(void);
+void abe_reset_one_feature(u32 x);
+void abe_reset_all_features(void);
+void abe_reset_all_ports(void);
+void abe_reset_all_fifo(void);
+void abe_reset_all_sequence(void);
+u32 abe_dma_port_iteration(abe_data_format_t *format);
+void abe_read_sys_clock(u32 *time);
+void abe_enable_dma_request(u32 id);
+void abe_disable_dma_request(u32 id);
+void abe_enable_atc(u32 id);
+void abe_disable_atc(u32 id);
+void abe_init_atc(u32 id);
+void abe_init_io_tasks(u32 id, abe_data_format_t *format,
+ abe_port_protocol_t *prot);
+void abe_enable_pp_io_task(u32 id);
+void abe_disable_pp_io_task(u32 id);
+void abe_init_dma_t(u32 id, abe_port_protocol_t *prot);
+u32 abe_dma_port_iter_factor(abe_data_format_t *f);
+u32 abe_dma_port_copy_subroutine_id(u32 i);
+void abe_call_subroutine(u32 idx, u32 p1, u32 p2, u32 p3, u32 p4);
+void abe_monitoring(void);
+void abe_lock_execution(void);
+void abe_unlock_execution(void);
+void abe_hw_configuration(void);
+void abe_add_subroutine(u32 *id, abe_subroutine2 f, u32 nparam, u32 *params);
+abehal_status abe_read_next_ping_pong_buffer(u32 port, u32 *p, u32 *n);
+void abe_irq_ping_pong(void);
+void abe_irq_check_for_sequences(u32 seq_info);
+void abe_default_irq_pingpong_player(void);
+void abe_default_irq_pingpong_player_32bits(void);
+void abe_rshifted16_irq_pingpong_player_32bits(void);
+void abe_1616_irq_pingpong_player_1616bits(void);
+void abe_default_irq_aps_adaptation(void);
+void abe_irq_aps(u32 aps_info);
+void abe_clean_temporary_buffers(u32 id);
+void abe_dbg_log(u32 x, u32 y, u32 z, u32 t);
+void abe_dbg_error_log(u32 x);
+void abe_init_asrc_vx_dl(s32 dppm);
+void abe_init_asrc_vx_ul(s32 dppm);
+void abe_init_asrc_mm_ext_in(s32 dppm);
+void abe_init_asrc_bt_ul(s32 dppm);
+void abe_init_asrc_bt_dl(s32 dppm);
+//u8 *memmove(u8 *dst, u8 *src, u32 n);
+//u32 __get_unaligned_memmove32(void *p);
+//void __put_unaligned_memmove32(u32 val, void *p);
+/*
+ * HAL INTERNAL DATA
+ */
+extern void __iomem *io_base;
+extern u16 MultiFrame[PROCESSING_SLOTS][TASKS_IN_SLOT];
+extern ABE_SIODescriptor sio_desc;
+extern ABE_SPingPongDescriptor desc_pp;
+extern abe_satcdescriptor_aess atc_desc;
+extern const u32 abe_port_priority[LAST_PORT_ID - 1];
+extern u32 abe_compensated_mixer_gain;
+extern u8 abe_muted_gains_indicator[MAX_NBGAIN_CMEM];
+extern u32 abe_desired_gains_decibel[MAX_NBGAIN_CMEM];
+extern u32 abe_muted_gains_decibel[MAX_NBGAIN_CMEM];
+extern u32 abe_desired_gains_linear[MAX_NBGAIN_CMEM];
+extern u32 abe_desired_ramp_delay_ms[MAX_NBGAIN_CMEM];
+extern u32 pdm_dl1_status;
+extern u32 pdm_dl2_status;
+extern u32 pdm_vib_status;
+extern const u32 abe_firmware_array[ABE_FIRMWARE_MAX_SIZE];
+extern u32 abe_firmware_version_number;
+extern const u32 abe_atc_srcid[];
+extern const u32 abe_atc_dstid[];
+extern abe_port_t abe_port[];
+extern abe_feature_t feature[];
+extern const abe_port_t abe_port_init[];
+extern abe_feature_t all_feature[];
+extern const abe_feature_t all_feature_init[];
+extern abe_seq_t all_sequence[];
+extern const abe_seq_t all_sequence_init[];
+extern const abe_router_t abe_router_ul_table_preset
+ [NBROUTE_CONFIG][NBROUTE_UL];
+extern abe_router_t abe_router_ul_table[NBROUTE_CONFIG_MAX][NBROUTE_UL];
+extern u32 abe_dbg_output;
+extern u32 abe_dbg_mask;
+extern u32 abe_dbg_activity_log[D_DEBUG_HAL_TASK_sizeof];
+extern u32 abe_dbg_activity_log_write_pointer;
+extern u32 abe_dbg_param;
+extern u32 abe_current_event_id;
+extern const abe_sequence_t seq_null;
+/* table of new subroutines called in the sequence */
+extern abe_subroutine2 abe_all_subsubroutine[MAXNBSUBROUTINE];
+/* number of parameters per calls */
+extern u32 abe_all_subsubroutine_nparam[MAXNBSUBROUTINE];
+extern u32 abe_subroutine_id[MAXNBSUBROUTINE];
+extern u32 *abe_all_subroutine_params[MAXNBSUBROUTINE];
+extern u32 abe_subroutine_write_pointer;
+extern abe_sequence_t abe_all_sequence[MAXNBSEQUENCE];
+extern u32 abe_sequence_write_pointer;
+/* current number of pending sequences (avoids to look in the table) */
+extern u32 abe_nb_pending_sequences;
+/* pending sequences due to ressource collision */
+extern u32 abe_pending_sequences[MAXNBSEQUENCE];
+/* mask of unsharable ressources among other sequences */
+extern u32 abe_global_sequence_mask;
+/* table of active sequences */
+extern abe_seq_t abe_active_sequence[MAXACTIVESEQUENCE][MAXSEQUENCESTEPS];
+/* index of the plugged subroutine doing ping-pong cache-flush
+ DMEM accesses */
+extern u32 abe_irq_pingpong_player_id;
+extern u32 abe_irq_aps_adaptation_id;
+/* base addresses of the ping pong buffers */
+extern u32 abe_base_address_pingpong[MAX_PINGPONG_BUFFERS];
+/* size of each ping/pong buffers */
+extern u32 abe_size_pingpong;
+/* number of ping/pong buffer being used */
+extern u32 abe_nb_pingpong;
+/* circular read pointer to IRQ/DBG DMEM buffer */
+extern u32 abe_irq_dbg_read_ptr;
+/* extern const s32 abe_dmic_40 [C_98_48_LP_Coefs_sizeof];
+extern const s32 abe_dmic_32 [C_98_48_LP_Coefs_sizeof];
+extern const s32 abe_dmic_25 [C_98_48_LP_Coefs_sizeof];
+extern const s32 abe_dmic_16 [C_98_48_LP_Coefs_sizeof]; */
+extern const u32 abe_db2lin_table[];
+extern const u32 abe_alpha_iir[64];
+extern const u32 abe_1_alpha_iir[64];
+#endif/* _ABE_REF_H_ */
diff --git a/sound/soc/omap/abe/abe_seq.c b/sound/soc/omap/abe/abe_seq.c
new file mode 100644
index 00000000000..797fef3bd78
--- /dev/null
+++ b/sound/soc/omap/abe/abe_seq.c
@@ -0,0 +1,248 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <linux/module.h>
+#include "abe_main.h"
+/**
+ * abe_null_subroutine
+ *
+ */
+void abe_null_subroutine_0(void)
+{
+}
+void abe_null_subroutine_2(u32 a, u32 b)
+{
+}
+void abe_null_subroutine_4(u32 a, u32 b, u32 c, u32 d)
+{
+}
+/**
+ * abe_init_subroutine_table - initializes the default table of pointers
+ * to subroutines
+ *
+ * initializes the default table of pointers to subroutines
+ *
+ */
+void abe_init_subroutine_table(void)
+{
+ u32 id;
+ /* reset the table's pointers */
+ abe_subroutine_write_pointer = 0;
+ /* the first index is the NULL task */
+ abe_add_subroutine(&id, (abe_subroutine2) abe_null_subroutine_2,
+ SUB_0_PARAM, (u32 *) 0);
+ /* write mixer has 4 parameters */
+ abe_add_subroutine(&(abe_subroutine_id[SUB_WRITE_MIXER]),
+ (abe_subroutine2) abe_write_mixer, SUB_4_PARAM,
+ (u32 *) 0);
+ /* ping-pong player IRQ */
+ abe_add_subroutine(&abe_irq_pingpong_player_id,
+ (abe_subroutine2) abe_null_subroutine_0, SUB_0_PARAM,
+ (u32 *) 0);
+ abe_add_subroutine(&abe_irq_aps_adaptation_id,
+ (abe_subroutine2) abe_default_irq_aps_adaptation,
+ SUB_0_PARAM, (u32 *) 0);
+}
+/**
+ * abe_add_subroutine
+ * @id: ABE port id
+ * @f: pointer to the subroutines
+ * @nparam: number of parameters
+ * @params: pointer to the psrameters
+ *
+ * add one function pointer more and returns the index to it
+ */
+void abe_add_subroutine(u32 *id, abe_subroutine2 f, u32 nparam, u32 *params)
+{
+ u32 i, i_found;
+ if ((abe_subroutine_write_pointer >= MAXNBSUBROUTINE) || ((u32) f == 0)) {
+ abe_dbg_param |= ERR_SEQ;
+ abe_dbg_error_log(ABE_PARAMETER_OVERFLOW);
+ } else {
+ /* search if this subroutine address was not already
+ * declared, then return the previous index
+ */
+ for (i_found = abe_subroutine_write_pointer, i = 0;
+ i < abe_subroutine_write_pointer; i++) {
+ if (f == abe_all_subsubroutine[i])
+ i_found = i;
+ }
+ if (i_found == abe_subroutine_write_pointer) {
+ *id = abe_subroutine_write_pointer;
+ abe_all_subsubroutine
+ [abe_subroutine_write_pointer] = (f);
+ abe_all_subroutine_params
+ [abe_subroutine_write_pointer] = params;
+ abe_all_subsubroutine_nparam
+ [abe_subroutine_write_pointer] = nparam;
+ abe_subroutine_write_pointer++;
+ } else {
+ abe_all_subroutine_params[i_found] = params;
+ *id = i_found;
+ }
+ }
+}
+
+EXPORT_SYMBOL_GPL(abe_add_subroutine);
+
+/**
+ * abe_add_sequence
+ * @id: returned sequence index after pluging a new sequence (index in the tables)
+ * @s: sequence to be inserted
+ *
+ * Load a time-sequenced operations.
+ */
+void abe_add_sequence(u32 *id, abe_sequence_t *s)
+{
+ abe_seq_t *seq_src, *seq_dst;
+ u32 i, no_end_of_sequence_found;
+ seq_src = &(s->seq1);
+ seq_dst = &((abe_all_sequence[abe_sequence_write_pointer]).seq1);
+ if ((abe_sequence_write_pointer >= MAXNBSEQUENCE) || ((u32) s == 0)) {
+ abe_dbg_param |= ERR_SEQ;
+ abe_dbg_error_log(ABE_PARAMETER_OVERFLOW);
+ } else {
+ *id = abe_subroutine_write_pointer;
+ /* copy the mask */
+ (abe_all_sequence[abe_sequence_write_pointer]).mask = s->mask;
+ for (no_end_of_sequence_found = 1, i = 0; i < MAXSEQUENCESTEPS;
+ i++, seq_src++, seq_dst++) {
+ /* sequence copied line by line */
+ (*seq_dst) = (*seq_src);
+ /* stop when the line start with time=(-1) */
+ if ((*(s32 *) seq_src) == (-1)) {
+ /* stop when the line start with time=(-1) */
+ no_end_of_sequence_found = 0;
+ break;
+ }
+ }
+ abe_subroutine_write_pointer++;
+ if (no_end_of_sequence_found)
+ abe_dbg_error_log(ABE_SEQTOOLONG);
+ }
+}
+/**
+ * abe_reset_one_sequence
+ * @id: sequence ID
+ *
+ * load default configuration for that sequence
+ * kill running activities
+ */
+void abe_reset_one_sequence(u32 id)
+{
+}
+/**
+ * abe_reset_all_sequence
+ *
+ * load default configuration for all sequences
+ * kill any running activities
+ */
+void abe_reset_all_sequence(void)
+{
+ u32 i;
+ abe_init_subroutine_table();
+ /* arrange to have the first sequence index=0 to the NULL operation
+ sequence */
+ abe_add_sequence(&i, (abe_sequence_t *) &seq_null);
+ /* reset the the collision protection mask */
+ abe_global_sequence_mask = 0;
+ /* reset the pending sequences list */
+ for (abe_nb_pending_sequences = i = 0; i < MAXNBSEQUENCE; i++)
+ abe_pending_sequences[i] = 0;
+}
+/**
+ * abe_call_subroutine
+ * @idx: index to the table of all registered Call-backs and subroutines
+ *
+ * run and log a subroutine
+ */
+void abe_call_subroutine(u32 idx, u32 p1, u32 p2, u32 p3, u32 p4)
+{
+ abe_subroutine0 f0;
+ abe_subroutine1 f1;
+ abe_subroutine2 f2;
+ abe_subroutine3 f3;
+ abe_subroutine4 f4;
+ u32 *params;
+ if (idx >= MAXNBSUBROUTINE)
+ return;
+ switch (idx) {
+ /* call the subroutines defined at compilation time
+ (const .. sequences) */
+#if 0
+ case SUB_WRITE_MIXER_DL1:
+ abe_write_mixer_dl1(p1, p2, p3)
+ abe_fprintf("write_mixer");
+ break;
+#endif
+ /* call the subroutines defined at execution time
+ (dynamic sequences) */
+ default:
+ switch (abe_all_subsubroutine_nparam[idx]) {
+ case SUB_0_PARAM:
+ f0 = (abe_subroutine0) abe_all_subsubroutine[idx];
+ (*f0) ();
+ break;
+ case SUB_1_PARAM:
+ f1 = (abe_subroutine1) abe_all_subsubroutine[idx];
+ params = abe_all_subroutine_params
+ [abe_irq_pingpong_player_id];
+ if (params != (u32 *) 0)
+ p1 = params[0];
+ (*f1) (p1);
+ break;
+ case SUB_2_PARAM:
+ f2 = abe_all_subsubroutine[idx];
+ params = abe_all_subroutine_params
+ [abe_irq_pingpong_player_id];
+ if (params != (u32 *) 0) {
+ p1 = params[0];
+ p2 = params[1];
+ }
+ (*f2) (p1, p2);
+ break;
+ case SUB_3_PARAM:
+ f3 = (abe_subroutine3) abe_all_subsubroutine[idx];
+ params = abe_all_subroutine_params
+ [abe_irq_pingpong_player_id];
+ if (params != (u32 *) 0) {
+ p1 = params[0];
+ p2 = params[1];
+ p3 = params[2];
+ }
+ (*f3) (p1, p2, p3);
+ break;
+ case SUB_4_PARAM:
+ f4 = (abe_subroutine4) abe_all_subsubroutine[idx];
+ params = abe_all_subroutine_params
+ [abe_irq_pingpong_player_id];
+ if (params != (u32 *) 0) {
+ p1 = params[0];
+ p2 = params[1];
+ p3 = params[2];
+ p4 = params[3];
+ }
+ (*f4) (p1, p2, p3, p4);
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/sound/soc/omap/abe/abe_sm_addr.h b/sound/soc/omap/abe/abe_sm_addr.h
new file mode 100644
index 00000000000..53447b64ec3
--- /dev/null
+++ b/sound/soc/omap/abe/abe_sm_addr.h
@@ -0,0 +1,503 @@
+/*
+ * ALSA SoC OMAP ABE driver
+*
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef _ABE_SM_ADDR_H_
+#define _ABE_SM_ADDR_H_
+#define init_SM_ADDR 0
+#define init_SM_ADDR_END 309
+#define init_SM_sizeof 310
+#define S_Data0_ADDR 310
+#define S_Data0_ADDR_END 310
+#define S_Data0_sizeof 1
+#define S_Temp_ADDR 311
+#define S_Temp_ADDR_END 311
+#define S_Temp_sizeof 1
+#define S_PhoenixOffset_ADDR 312
+#define S_PhoenixOffset_ADDR_END 312
+#define S_PhoenixOffset_sizeof 1
+#define S_GTarget1_ADDR 313
+#define S_GTarget1_ADDR_END 319
+#define S_GTarget1_sizeof 7
+#define S_Gtarget_DL1_ADDR 320
+#define S_Gtarget_DL1_ADDR_END 321
+#define S_Gtarget_DL1_sizeof 2
+#define S_Gtarget_DL2_ADDR 322
+#define S_Gtarget_DL2_ADDR_END 323
+#define S_Gtarget_DL2_sizeof 2
+#define S_Gtarget_Echo_ADDR 324
+#define S_Gtarget_Echo_ADDR_END 324
+#define S_Gtarget_Echo_sizeof 1
+#define S_Gtarget_SDT_ADDR 325
+#define S_Gtarget_SDT_ADDR_END 325
+#define S_Gtarget_SDT_sizeof 1
+#define S_Gtarget_VxRec_ADDR 326
+#define S_Gtarget_VxRec_ADDR_END 327
+#define S_Gtarget_VxRec_sizeof 2
+#define S_Gtarget_UL_ADDR 328
+#define S_Gtarget_UL_ADDR_END 329
+#define S_Gtarget_UL_sizeof 2
+#define S_Gtarget_unused_ADDR 330
+#define S_Gtarget_unused_ADDR_END 330
+#define S_Gtarget_unused_sizeof 1
+#define S_GCurrent_ADDR 331
+#define S_GCurrent_ADDR_END 348
+#define S_GCurrent_sizeof 18
+#define S_GAIN_ONE_ADDR 349
+#define S_GAIN_ONE_ADDR_END 349
+#define S_GAIN_ONE_sizeof 1
+#define S_Tones_ADDR 350
+#define S_Tones_ADDR_END 361
+#define S_Tones_sizeof 12
+#define S_VX_DL_ADDR 362
+#define S_VX_DL_ADDR_END 373
+#define S_VX_DL_sizeof 12
+#define S_MM_UL2_ADDR 374
+#define S_MM_UL2_ADDR_END 385
+#define S_MM_UL2_sizeof 12
+#define S_MM_DL_ADDR 386
+#define S_MM_DL_ADDR_END 397
+#define S_MM_DL_sizeof 12
+#define S_DL1_M_Out_ADDR 398
+#define S_DL1_M_Out_ADDR_END 409
+#define S_DL1_M_Out_sizeof 12
+#define S_DL2_M_Out_ADDR 410
+#define S_DL2_M_Out_ADDR_END 421
+#define S_DL2_M_Out_sizeof 12
+#define S_Echo_M_Out_ADDR 422
+#define S_Echo_M_Out_ADDR_END 433
+#define S_Echo_M_Out_sizeof 12
+#define S_SDT_M_Out_ADDR 434
+#define S_SDT_M_Out_ADDR_END 445
+#define S_SDT_M_Out_sizeof 12
+#define S_VX_UL_ADDR 446
+#define S_VX_UL_ADDR_END 457
+#define S_VX_UL_sizeof 12
+#define S_VX_UL_M_ADDR 458
+#define S_VX_UL_M_ADDR_END 469
+#define S_VX_UL_M_sizeof 12
+#define S_BT_DL_ADDR 470
+#define S_BT_DL_ADDR_END 481
+#define S_BT_DL_sizeof 12
+#define S_BT_UL_ADDR 482
+#define S_BT_UL_ADDR_END 493
+#define S_BT_UL_sizeof 12
+#define S_BT_DL_8k_ADDR 494
+#define S_BT_DL_8k_ADDR_END 496
+#define S_BT_DL_8k_sizeof 3
+#define S_BT_DL_16k_ADDR 497
+#define S_BT_DL_16k_ADDR_END 501
+#define S_BT_DL_16k_sizeof 5
+#define S_BT_UL_8k_ADDR 502
+#define S_BT_UL_8k_ADDR_END 503
+#define S_BT_UL_8k_sizeof 2
+#define S_BT_UL_16k_ADDR 504
+#define S_BT_UL_16k_ADDR_END 507
+#define S_BT_UL_16k_sizeof 4
+#define S_SDT_F_ADDR 508
+#define S_SDT_F_ADDR_END 519
+#define S_SDT_F_sizeof 12
+#define S_SDT_F_data_ADDR 520
+#define S_SDT_F_data_ADDR_END 528
+#define S_SDT_F_data_sizeof 9
+#define S_MM_DL_OSR_ADDR 529
+#define S_MM_DL_OSR_ADDR_END 552
+#define S_MM_DL_OSR_sizeof 24
+#define S_24_zeros_ADDR 553
+#define S_24_zeros_ADDR_END 576
+#define S_24_zeros_sizeof 24
+#define S_DMIC1_ADDR 577
+#define S_DMIC1_ADDR_END 588
+#define S_DMIC1_sizeof 12
+#define S_DMIC2_ADDR 589
+#define S_DMIC2_ADDR_END 600
+#define S_DMIC2_sizeof 12
+#define S_DMIC3_ADDR 601
+#define S_DMIC3_ADDR_END 612
+#define S_DMIC3_sizeof 12
+#define S_AMIC_ADDR 613
+#define S_AMIC_ADDR_END 624
+#define S_AMIC_sizeof 12
+#define S_DMIC1_L_ADDR 625
+#define S_DMIC1_L_ADDR_END 636
+#define S_DMIC1_L_sizeof 12
+#define S_DMIC1_R_ADDR 637
+#define S_DMIC1_R_ADDR_END 648
+#define S_DMIC1_R_sizeof 12
+#define S_DMIC2_L_ADDR 649
+#define S_DMIC2_L_ADDR_END 660
+#define S_DMIC2_L_sizeof 12
+#define S_DMIC2_R_ADDR 661
+#define S_DMIC2_R_ADDR_END 672
+#define S_DMIC2_R_sizeof 12
+#define S_DMIC3_L_ADDR 673
+#define S_DMIC3_L_ADDR_END 684
+#define S_DMIC3_L_sizeof 12
+#define S_DMIC3_R_ADDR 685
+#define S_DMIC3_R_ADDR_END 696
+#define S_DMIC3_R_sizeof 12
+#define S_BT_UL_L_ADDR 697
+#define S_BT_UL_L_ADDR_END 708
+#define S_BT_UL_L_sizeof 12
+#define S_BT_UL_R_ADDR 709
+#define S_BT_UL_R_ADDR_END 720
+#define S_BT_UL_R_sizeof 12
+#define S_AMIC_L_ADDR 721
+#define S_AMIC_L_ADDR_END 732
+#define S_AMIC_L_sizeof 12
+#define S_AMIC_R_ADDR 733
+#define S_AMIC_R_ADDR_END 744
+#define S_AMIC_R_sizeof 12
+#define S_EchoRef_L_ADDR 745
+#define S_EchoRef_L_ADDR_END 756
+#define S_EchoRef_L_sizeof 12
+#define S_EchoRef_R_ADDR 757
+#define S_EchoRef_R_ADDR_END 768
+#define S_EchoRef_R_sizeof 12
+#define S_MM_DL_L_ADDR 769
+#define S_MM_DL_L_ADDR_END 780
+#define S_MM_DL_L_sizeof 12
+#define S_MM_DL_R_ADDR 781
+#define S_MM_DL_R_ADDR_END 792
+#define S_MM_DL_R_sizeof 12
+#define S_MM_UL_ADDR 793
+#define S_MM_UL_ADDR_END 912
+#define S_MM_UL_sizeof 120
+#define S_AMIC_96k_ADDR 913
+#define S_AMIC_96k_ADDR_END 936
+#define S_AMIC_96k_sizeof 24
+#define S_DMIC0_96k_ADDR 937
+#define S_DMIC0_96k_ADDR_END 960
+#define S_DMIC0_96k_sizeof 24
+#define S_DMIC1_96k_ADDR 961
+#define S_DMIC1_96k_ADDR_END 984
+#define S_DMIC1_96k_sizeof 24
+#define S_DMIC2_96k_ADDR 985
+#define S_DMIC2_96k_ADDR_END 1008
+#define S_DMIC2_96k_sizeof 24
+#define S_UL_VX_UL_48_8K_ADDR 1009
+#define S_UL_VX_UL_48_8K_ADDR_END 1020
+#define S_UL_VX_UL_48_8K_sizeof 12
+#define S_UL_VX_UL_48_16K_ADDR 1021
+#define S_UL_VX_UL_48_16K_ADDR_END 1032
+#define S_UL_VX_UL_48_16K_sizeof 12
+#define S_UL_MIC_48K_ADDR 1033
+#define S_UL_MIC_48K_ADDR_END 1044
+#define S_UL_MIC_48K_sizeof 12
+#define S_Voice_8k_UL_ADDR 1045
+#define S_Voice_8k_UL_ADDR_END 1047
+#define S_Voice_8k_UL_sizeof 3
+#define S_Voice_8k_DL_ADDR 1048
+#define S_Voice_8k_DL_ADDR_END 1049
+#define S_Voice_8k_DL_sizeof 2
+#define S_McPDM_Out1_ADDR 1050
+#define S_McPDM_Out1_ADDR_END 1073
+#define S_McPDM_Out1_sizeof 24
+#define S_McPDM_Out2_ADDR 1074
+#define S_McPDM_Out2_ADDR_END 1097
+#define S_McPDM_Out2_sizeof 24
+#define S_McPDM_Out3_ADDR 1098
+#define S_McPDM_Out3_ADDR_END 1121
+#define S_McPDM_Out3_sizeof 24
+#define S_Voice_16k_UL_ADDR 1122
+#define S_Voice_16k_UL_ADDR_END 1126
+#define S_Voice_16k_UL_sizeof 5
+#define S_Voice_16k_DL_ADDR 1127
+#define S_Voice_16k_DL_ADDR_END 1130
+#define S_Voice_16k_DL_sizeof 4
+#define S_XinASRC_DL_VX_ADDR 1131
+#define S_XinASRC_DL_VX_ADDR_END 1170
+#define S_XinASRC_DL_VX_sizeof 40
+#define S_XinASRC_UL_VX_ADDR 1171
+#define S_XinASRC_UL_VX_ADDR_END 1210
+#define S_XinASRC_UL_VX_sizeof 40
+#define S_XinASRC_MM_EXT_IN_ADDR 1211
+#define S_XinASRC_MM_EXT_IN_ADDR_END 1250
+#define S_XinASRC_MM_EXT_IN_sizeof 40
+#define S_VX_REC_ADDR 1251
+#define S_VX_REC_ADDR_END 1262
+#define S_VX_REC_sizeof 12
+#define S_VX_REC_L_ADDR 1263
+#define S_VX_REC_L_ADDR_END 1274
+#define S_VX_REC_L_sizeof 12
+#define S_VX_REC_R_ADDR 1275
+#define S_VX_REC_R_ADDR_END 1286
+#define S_VX_REC_R_sizeof 12
+#define S_DL2_M_L_ADDR 1287
+#define S_DL2_M_L_ADDR_END 1298
+#define S_DL2_M_L_sizeof 12
+#define S_DL2_M_R_ADDR 1299
+#define S_DL2_M_R_ADDR_END 1310
+#define S_DL2_M_R_sizeof 12
+#define S_DL2_M_LR_EQ_data_ADDR 1311
+#define S_DL2_M_LR_EQ_data_ADDR_END 1335
+#define S_DL2_M_LR_EQ_data_sizeof 25
+#define S_DL1_M_EQ_data_ADDR 1336
+#define S_DL1_M_EQ_data_ADDR_END 1360
+#define S_DL1_M_EQ_data_sizeof 25
+#define S_EARP_48_96_LP_data_ADDR 1361
+#define S_EARP_48_96_LP_data_ADDR_END 1375
+#define S_EARP_48_96_LP_data_sizeof 15
+#define S_IHF_48_96_LP_data_ADDR 1376
+#define S_IHF_48_96_LP_data_ADDR_END 1390
+#define S_IHF_48_96_LP_data_sizeof 15
+#define S_VX_UL_8_TEMP_ADDR 1391
+#define S_VX_UL_8_TEMP_ADDR_END 1392
+#define S_VX_UL_8_TEMP_sizeof 2
+#define S_VX_UL_16_TEMP_ADDR 1393
+#define S_VX_UL_16_TEMP_ADDR_END 1396
+#define S_VX_UL_16_TEMP_sizeof 4
+#define S_VX_DL_8_48_LP_data_ADDR 1397
+#define S_VX_DL_8_48_LP_data_ADDR_END 1407
+#define S_VX_DL_8_48_LP_data_sizeof 11
+#define S_VX_DL_8_48_HP_data_ADDR 1408
+#define S_VX_DL_8_48_HP_data_ADDR_END 1414
+#define S_VX_DL_8_48_HP_data_sizeof 7
+#define S_VX_DL_16_48_LP_data_ADDR 1415
+#define S_VX_DL_16_48_LP_data_ADDR_END 1425
+#define S_VX_DL_16_48_LP_data_sizeof 11
+#define S_VX_DL_16_48_HP_data_ADDR 1426
+#define S_VX_DL_16_48_HP_data_ADDR_END 1430
+#define S_VX_DL_16_48_HP_data_sizeof 5
+#define S_VX_UL_48_8_LP_data_ADDR 1431
+#define S_VX_UL_48_8_LP_data_ADDR_END 1441
+#define S_VX_UL_48_8_LP_data_sizeof 11
+#define S_VX_UL_48_8_HP_data_ADDR 1442
+#define S_VX_UL_48_8_HP_data_ADDR_END 1448
+#define S_VX_UL_48_8_HP_data_sizeof 7
+#define S_VX_UL_48_16_LP_data_ADDR 1449
+#define S_VX_UL_48_16_LP_data_ADDR_END 1459
+#define S_VX_UL_48_16_LP_data_sizeof 11
+#define S_VX_UL_48_16_HP_data_ADDR 1460
+#define S_VX_UL_48_16_HP_data_ADDR_END 1466
+#define S_VX_UL_48_16_HP_data_sizeof 7
+#define S_BT_UL_8_48_LP_data_ADDR 1467
+#define S_BT_UL_8_48_LP_data_ADDR_END 1477
+#define S_BT_UL_8_48_LP_data_sizeof 11
+#define S_BT_UL_8_48_HP_data_ADDR 1478
+#define S_BT_UL_8_48_HP_data_ADDR_END 1484
+#define S_BT_UL_8_48_HP_data_sizeof 7
+#define S_BT_UL_16_48_LP_data_ADDR 1485
+#define S_BT_UL_16_48_LP_data_ADDR_END 1495
+#define S_BT_UL_16_48_LP_data_sizeof 11
+#define S_BT_UL_16_48_HP_data_ADDR 1496
+#define S_BT_UL_16_48_HP_data_ADDR_END 1500
+#define S_BT_UL_16_48_HP_data_sizeof 5
+#define S_BT_DL_48_8_LP_data_ADDR 1501
+#define S_BT_DL_48_8_LP_data_ADDR_END 1511
+#define S_BT_DL_48_8_LP_data_sizeof 11
+#define S_BT_DL_48_8_HP_data_ADDR 1512
+#define S_BT_DL_48_8_HP_data_ADDR_END 1518
+#define S_BT_DL_48_8_HP_data_sizeof 7
+#define S_BT_DL_48_16_LP_data_ADDR 1519
+#define S_BT_DL_48_16_LP_data_ADDR_END 1529
+#define S_BT_DL_48_16_LP_data_sizeof 11
+#define S_BT_DL_48_16_HP_data_ADDR 1530
+#define S_BT_DL_48_16_HP_data_ADDR_END 1534
+#define S_BT_DL_48_16_HP_data_sizeof 5
+#define S_ECHO_REF_48_8_LP_data_ADDR 1535
+#define S_ECHO_REF_48_8_LP_data_ADDR_END 1545
+#define S_ECHO_REF_48_8_LP_data_sizeof 11
+#define S_ECHO_REF_48_8_HP_data_ADDR 1546
+#define S_ECHO_REF_48_8_HP_data_ADDR_END 1552
+#define S_ECHO_REF_48_8_HP_data_sizeof 7
+#define S_ECHO_REF_48_16_LP_data_ADDR 1553
+#define S_ECHO_REF_48_16_LP_data_ADDR_END 1563
+#define S_ECHO_REF_48_16_LP_data_sizeof 11
+#define S_ECHO_REF_48_16_HP_data_ADDR 1564
+#define S_ECHO_REF_48_16_HP_data_ADDR_END 1568
+#define S_ECHO_REF_48_16_HP_data_sizeof 5
+#define S_APS_IIRmem1_ADDR 1569
+#define S_APS_IIRmem1_ADDR_END 1577
+#define S_APS_IIRmem1_sizeof 9
+#define S_APS_M_IIRmem2_ADDR 1578
+#define S_APS_M_IIRmem2_ADDR_END 1580
+#define S_APS_M_IIRmem2_sizeof 3
+#define S_APS_C_IIRmem2_ADDR 1581
+#define S_APS_C_IIRmem2_ADDR_END 1583
+#define S_APS_C_IIRmem2_sizeof 3
+#define S_APS_DL1_OutSamples_ADDR 1584
+#define S_APS_DL1_OutSamples_ADDR_END 1585
+#define S_APS_DL1_OutSamples_sizeof 2
+#define S_APS_DL1_COIL_OutSamples_ADDR 1586
+#define S_APS_DL1_COIL_OutSamples_ADDR_END 1587
+#define S_APS_DL1_COIL_OutSamples_sizeof 2
+#define S_APS_DL2_L_OutSamples_ADDR 1588
+#define S_APS_DL2_L_OutSamples_ADDR_END 1589
+#define S_APS_DL2_L_OutSamples_sizeof 2
+#define S_APS_DL2_L_COIL_OutSamples_ADDR 1590
+#define S_APS_DL2_L_COIL_OutSamples_ADDR_END 1591
+#define S_APS_DL2_L_COIL_OutSamples_sizeof 2
+#define S_APS_DL2_R_OutSamples_ADDR 1592
+#define S_APS_DL2_R_OutSamples_ADDR_END 1593
+#define S_APS_DL2_R_OutSamples_sizeof 2
+#define S_APS_DL2_R_COIL_OutSamples_ADDR 1594
+#define S_APS_DL2_R_COIL_OutSamples_ADDR_END 1595
+#define S_APS_DL2_R_COIL_OutSamples_sizeof 2
+#define S_XinASRC_ECHO_REF_ADDR 1596
+#define S_XinASRC_ECHO_REF_ADDR_END 1635
+#define S_XinASRC_ECHO_REF_sizeof 40
+#define S_ECHO_REF_16K_ADDR 1636
+#define S_ECHO_REF_16K_ADDR_END 1640
+#define S_ECHO_REF_16K_sizeof 5
+#define S_ECHO_REF_8K_ADDR 1641
+#define S_ECHO_REF_8K_ADDR_END 1643
+#define S_ECHO_REF_8K_sizeof 3
+#define S_DL1_EQ_ADDR 1644
+#define S_DL1_EQ_ADDR_END 1655
+#define S_DL1_EQ_sizeof 12
+#define S_DL2_EQ_ADDR 1656
+#define S_DL2_EQ_ADDR_END 1667
+#define S_DL2_EQ_sizeof 12
+#define S_DL1_GAIN_out_ADDR 1668
+#define S_DL1_GAIN_out_ADDR_END 1679
+#define S_DL1_GAIN_out_sizeof 12
+#define S_DL2_GAIN_out_ADDR 1680
+#define S_DL2_GAIN_out_ADDR_END 1691
+#define S_DL2_GAIN_out_sizeof 12
+#define S_APS_DL2_L_IIRmem1_ADDR 1692
+#define S_APS_DL2_L_IIRmem1_ADDR_END 1700
+#define S_APS_DL2_L_IIRmem1_sizeof 9
+#define S_APS_DL2_R_IIRmem1_ADDR 1701
+#define S_APS_DL2_R_IIRmem1_ADDR_END 1709
+#define S_APS_DL2_R_IIRmem1_sizeof 9
+#define S_APS_DL2_L_M_IIRmem2_ADDR 1710
+#define S_APS_DL2_L_M_IIRmem2_ADDR_END 1712
+#define S_APS_DL2_L_M_IIRmem2_sizeof 3
+#define S_APS_DL2_R_M_IIRmem2_ADDR 1713
+#define S_APS_DL2_R_M_IIRmem2_ADDR_END 1715
+#define S_APS_DL2_R_M_IIRmem2_sizeof 3
+#define S_APS_DL2_L_C_IIRmem2_ADDR 1716
+#define S_APS_DL2_L_C_IIRmem2_ADDR_END 1718
+#define S_APS_DL2_L_C_IIRmem2_sizeof 3
+#define S_APS_DL2_R_C_IIRmem2_ADDR 1719
+#define S_APS_DL2_R_C_IIRmem2_ADDR_END 1721
+#define S_APS_DL2_R_C_IIRmem2_sizeof 3
+#define S_DL1_APS_ADDR 1722
+#define S_DL1_APS_ADDR_END 1733
+#define S_DL1_APS_sizeof 12
+#define S_DL2_L_APS_ADDR 1734
+#define S_DL2_L_APS_ADDR_END 1745
+#define S_DL2_L_APS_sizeof 12
+#define S_DL2_R_APS_ADDR 1746
+#define S_DL2_R_APS_ADDR_END 1757
+#define S_DL2_R_APS_sizeof 12
+#define S_APS_DL1_EQ_data_ADDR 1758
+#define S_APS_DL1_EQ_data_ADDR_END 1766
+#define S_APS_DL1_EQ_data_sizeof 9
+#define S_APS_DL2_EQ_data_ADDR 1767
+#define S_APS_DL2_EQ_data_ADDR_END 1775
+#define S_APS_DL2_EQ_data_sizeof 9
+#define S_DC_DCvalue_ADDR 1776
+#define S_DC_DCvalue_ADDR_END 1776
+#define S_DC_DCvalue_sizeof 1
+#define S_VIBRA_ADDR 1777
+#define S_VIBRA_ADDR_END 1782
+#define S_VIBRA_sizeof 6
+#define S_Vibra2_in_ADDR 1783
+#define S_Vibra2_in_ADDR_END 1788
+#define S_Vibra2_in_sizeof 6
+#define S_Vibra2_addr_ADDR 1789
+#define S_Vibra2_addr_ADDR_END 1789
+#define S_Vibra2_addr_sizeof 1
+#define S_VibraCtrl_forRightSM_ADDR 1790
+#define S_VibraCtrl_forRightSM_ADDR_END 1813
+#define S_VibraCtrl_forRightSM_sizeof 24
+#define S_Rnoise_mem_ADDR 1814
+#define S_Rnoise_mem_ADDR_END 1814
+#define S_Rnoise_mem_sizeof 1
+#define S_Ctrl_ADDR 1815
+#define S_Ctrl_ADDR_END 1832
+#define S_Ctrl_sizeof 18
+#define S_Vibra1_in_ADDR 1833
+#define S_Vibra1_in_ADDR_END 1838
+#define S_Vibra1_in_sizeof 6
+#define S_Vibra1_temp_ADDR 1839
+#define S_Vibra1_temp_ADDR_END 1862
+#define S_Vibra1_temp_sizeof 24
+#define S_VibraCtrl_forLeftSM_ADDR 1863
+#define S_VibraCtrl_forLeftSM_ADDR_END 1886
+#define S_VibraCtrl_forLeftSM_sizeof 24
+#define S_Vibra1_mem_ADDR 1887
+#define S_Vibra1_mem_ADDR_END 1897
+#define S_Vibra1_mem_sizeof 11
+#define S_VibraCtrl_Stereo_ADDR 1898
+#define S_VibraCtrl_Stereo_ADDR_END 1921
+#define S_VibraCtrl_Stereo_sizeof 24
+#define S_AMIC_96_48_data_ADDR 1922
+#define S_AMIC_96_48_data_ADDR_END 1940
+#define S_AMIC_96_48_data_sizeof 19
+#define S_DMIC0_96_48_data_ADDR 1941
+#define S_DMIC0_96_48_data_ADDR_END 1959
+#define S_DMIC0_96_48_data_sizeof 19
+#define S_DMIC1_96_48_data_ADDR 1960
+#define S_DMIC1_96_48_data_ADDR_END 1978
+#define S_DMIC1_96_48_data_sizeof 19
+#define S_DMIC2_96_48_data_ADDR 1979
+#define S_DMIC2_96_48_data_ADDR_END 1997
+#define S_DMIC2_96_48_data_sizeof 19
+#define S_DBG_8K_PATTERN_ADDR 1998
+#define S_DBG_8K_PATTERN_ADDR_END 1999
+#define S_DBG_8K_PATTERN_sizeof 2
+#define S_DBG_16K_PATTERN_ADDR 2000
+#define S_DBG_16K_PATTERN_ADDR_END 2003
+#define S_DBG_16K_PATTERN_sizeof 4
+#define S_DBG_24K_PATTERN_ADDR 2004
+#define S_DBG_24K_PATTERN_ADDR_END 2009
+#define S_DBG_24K_PATTERN_sizeof 6
+#define S_DBG_48K_PATTERN_ADDR 2010
+#define S_DBG_48K_PATTERN_ADDR_END 2021
+#define S_DBG_48K_PATTERN_sizeof 12
+#define S_DBG_96K_PATTERN_ADDR 2022
+#define S_DBG_96K_PATTERN_ADDR_END 2045
+#define S_DBG_96K_PATTERN_sizeof 24
+#define S_MM_EXT_IN_ADDR 2046
+#define S_MM_EXT_IN_ADDR_END 2057
+#define S_MM_EXT_IN_sizeof 12
+#define S_MM_EXT_IN_L_ADDR 2058
+#define S_MM_EXT_IN_L_ADDR_END 2069
+#define S_MM_EXT_IN_L_sizeof 12
+#define S_MM_EXT_IN_R_ADDR 2070
+#define S_MM_EXT_IN_R_ADDR_END 2081
+#define S_MM_EXT_IN_R_sizeof 12
+#define S_MIC4_ADDR 2082
+#define S_MIC4_ADDR_END 2093
+#define S_MIC4_sizeof 12
+#define S_MIC4_L_ADDR 2094
+#define S_MIC4_L_ADDR_END 2105
+#define S_MIC4_L_sizeof 12
+#define S_MIC4_R_ADDR 2106
+#define S_MIC4_R_ADDR_END 2117
+#define S_MIC4_R_sizeof 12
+#define S_HW_TEST_ADDR 2118
+#define S_HW_TEST_ADDR_END 2118
+#define S_HW_TEST_sizeof 1
+#define S_XinASRC_BT_UL_ADDR 2119
+#define S_XinASRC_BT_UL_ADDR_END 2158
+#define S_XinASRC_BT_UL_sizeof 40
+#define S_XinASRC_BT_DL_ADDR 2159
+#define S_XinASRC_BT_DL_ADDR_END 2198
+#define S_XinASRC_BT_DL_sizeof 40
+#define S_BT_DL_8k_TEMP_ADDR 2199
+#define S_BT_DL_8k_TEMP_ADDR_END 2200
+#define S_BT_DL_8k_TEMP_sizeof 2
+#define S_BT_DL_16k_TEMP_ADDR 2201
+#define S_BT_DL_16k_TEMP_ADDR_END 2204
+#define S_BT_DL_16k_TEMP_sizeof 4
+#endif/* _ABESM_ADDR_H_ */
diff --git a/sound/soc/omap/abe/abe_taskid.h b/sound/soc/omap/abe/abe_taskid.h
new file mode 100644
index 00000000000..a384e1ab70b
--- /dev/null
+++ b/sound/soc/omap/abe/abe_taskid.h
@@ -0,0 +1,148 @@
+/*
+ * ALSA SoC OMAP ABE driver
+*
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#ifndef _ABE_TASKID_H_
+#define _ABE_TASKID_H_
+#define C_ABE_FW_TASK_DL1_APS_CORE 0
+#define C_ABE_FW_TASK_DL1_APS_COIL_CORE 1
+#define C_ABE_FW_TASK_DL2_L_APS_CORE 2
+#define C_ABE_FW_TASK_DL2_L_APS_COIL_CORE 3
+#define C_ABE_FW_TASK_DL2_R_APS_CORE 4
+#define C_ABE_FW_TASK_DL2_R_APS_COIL_CORE 5
+#define C_ABE_FW_TASK_ASRC_VX_DL_8 6
+#define C_ABE_FW_TASK_ASRC_VX_DL_16 7
+#define C_ABE_FW_TASK_ASRC_MM_EXT_IN 8
+#define C_ABE_FW_TASK_ASRC_VX_UL_8 9
+#define C_ABE_FW_TASK_ASRC_VX_UL_16 10
+#define C_ABE_FW_TASK_VX_UL_48_8_DEC 11
+#define C_ABE_FW_TASK_VX_UL_48_16_DEC 12
+#define C_ABE_FW_TASK_BT_DL_48_8_DEC 13
+#define C_ABE_FW_TASK_BT_DL_48_16_DEC 14
+#define C_ABE_FW_TASK_ECHO_REF_48_8_DEC 15
+#define C_ABE_FW_TASK_ECHO_REF_48_16_DEC 16
+#define C_ABE_FW_TASK_DL2_EQ 17
+#define C_ABE_FW_TASK_DL2_L_APS_IIR 18
+#define C_ABE_FW_TASK_DL2_R_APS_IIR 19
+#define C_ABE_FW_TASK_DL2_APS_EQ 20
+#define C_ABE_FW_TASK_ECHO_REF_48_16 21
+#define C_ABE_FW_TASK_ECHO_REF_48_8 22
+#define C_ABE_FW_TASK_GAIN_UPDATE 23
+#define C_ABE_FW_TASK_SideTone 24
+#define C_ABE_FW_TASK_VX_DL_8_48_LP 25
+#define C_ABE_FW_TASK_VX_DL_8_48_HP 26
+#define C_ABE_FW_TASK_VX_DL_16_48_LP 27
+#define C_ABE_FW_TASK_VX_DL_16_48_HP 28
+#define C_ABE_FW_TASK_VX_UL_48_8_LP 29
+#define C_ABE_FW_TASK_VX_UL_48_8_HP 30
+#define C_ABE_FW_TASK_VX_UL_48_16_LP 31
+#define C_ABE_FW_TASK_VX_UL_48_16_HP 32
+#define C_ABE_FW_TASK_BT_UL_8_48_LP 33
+#define C_ABE_FW_TASK_BT_UL_8_48_HP 34
+#define C_ABE_FW_TASK_BT_UL_16_48_LP 35
+#define C_ABE_FW_TASK_BT_UL_16_48_HP 36
+#define C_ABE_FW_TASK_BT_DL_48_8_LP 37
+#define C_ABE_FW_TASK_BT_DL_48_8_HP 38
+#define C_ABE_FW_TASK_BT_DL_48_16_LP 39
+#define C_ABE_FW_TASK_BT_DL_48_16_HP 40
+#define C_ABE_FW_TASK_ECHO_REF_48_8_LP 41
+#define C_ABE_FW_TASK_ECHO_REF_48_8_HP 42
+#define C_ABE_FW_TASK_ECHO_REF_48_16_LP 43
+#define C_ABE_FW_TASK_ECHO_REF_48_16_HP 44
+#define C_ABE_FW_TASK_DL1_EQ 45
+#define C_ABE_FW_TASK_DL1_APS_IIR 46
+#define C_ABE_FW_TASK_DL1_APS_EQ 47
+#define C_ABE_FW_TASK_IHF_48_96_LP 48
+#define C_ABE_FW_TASK_EARP_48_96_LP 49
+#define C_ABE_FW_TASK_DL1_GAIN 50
+#define C_ABE_FW_TASK_DL2_GAIN 51
+#define C_ABE_FW_TASK_IO_PING_PONG 52
+#define C_ABE_FW_TASK_IO_DMIC 53
+#define C_ABE_FW_TASK_IO_PDM_UL 54
+#define C_ABE_FW_TASK_IO_BT_VX_UL 55
+#define C_ABE_FW_TASK_IO_MM_UL 56
+#define C_ABE_FW_TASK_IO_MM_UL2 57
+#define C_ABE_FW_TASK_IO_VX_UL 58
+#define C_ABE_FW_TASK_IO_MM_DL 59
+#define C_ABE_FW_TASK_IO_VX_DL 60
+#define C_ABE_FW_TASK_IO_TONES_DL 61
+#define C_ABE_FW_TASK_IO_VIB_DL 62
+#define C_ABE_FW_TASK_IO_BT_VX_DL 63
+#define C_ABE_FW_TASK_IO_PDM_DL 64
+#define C_ABE_FW_TASK_IO_MM_EXT_OUT 65
+#define C_ABE_FW_TASK_IO_MM_EXT_IN 66
+#define C_ABE_FW_TASK_IO_TDM_OUT 67
+#define C_ABE_FW_TASK_IO_TDM_IN 68
+#define C_ABE_FW_TASK_DEBUG_IRQFIFO 69
+#define C_ABE_FW_TASK_EchoMixer 70
+#define C_ABE_FW_TASK_SDTMixer 71
+#define C_ABE_FW_TASK_DL1Mixer 72
+#define C_ABE_FW_TASK_DL2Mixer 73
+#define C_ABE_FW_TASK_VXRECMixer 74
+#define C_ABE_FW_TASK_ULMixer 75
+#define C_ABE_FW_TASK_VIBRA_PACK 76
+#define C_ABE_FW_TASK_VX_DL_8_48_0SR 77
+#define C_ABE_FW_TASK_VX_DL_16_48_0SR 78
+#define C_ABE_FW_TASK_BT_UL_8_48_0SR 79
+#define C_ABE_FW_TASK_BT_UL_16_48_0SR 80
+#define C_ABE_FW_TASK_IHF_48_96_0SR 81
+#define C_ABE_FW_TASK_EARP_48_96_0SR 82
+#define C_ABE_FW_TASK_AMIC_SPLIT 83
+#define C_ABE_FW_TASK_DMIC1_SPLIT 84
+#define C_ABE_FW_TASK_DMIC2_SPLIT 85
+#define C_ABE_FW_TASK_DMIC3_SPLIT 86
+#define C_ABE_FW_TASK_VXREC_SPLIT 87
+#define C_ABE_FW_TASK_BT_UL_SPLIT 88
+#define C_ABE_FW_TASK_MM_SPLIT 89
+#define C_ABE_FW_TASK_DL2_APS_SPLIT 90
+#define C_ABE_FW_TASK_VIBRA_SPLIT 91
+#define C_ABE_FW_TASK_MM_EXT_IN_SPLIT 92
+#define C_ABE_FW_TASK_ECHO_REF_SPLIT 93
+#define C_ABE_FW_TASK_MIC4_SPLIT 94
+#define C_ABE_FW_TASK_VX_UL_ROUTING 95
+#define C_ABE_FW_TASK_MM_UL2_ROUTING 96
+#define C_ABE_FW_TASK_VIBRA1 97
+#define C_ABE_FW_TASK_VIBRA2 98
+#define C_ABE_FW_TASK_BT_UL_16_48 99
+#define C_ABE_FW_TASK_BT_UL_8_48 100
+#define C_ABE_FW_TASK_BT_DL_48_16 101
+#define C_ABE_FW_TASK_BT_DL_48_8 102
+#define C_ABE_FW_TASK_VX_DL_16_48 103
+#define C_ABE_FW_TASK_VX_DL_8_48 104
+#define C_ABE_FW_TASK_VX_UL_48_16 105
+#define C_ABE_FW_TASK_VX_UL_48_8 106
+#define C_ABE_FW_TASK_DBG_SYNC 107
+#define C_ABE_FW_TASK_APS_DL1_IRQs 108
+#define C_ABE_FW_TASK_APS_DL2_L_IRQs 109
+#define C_ABE_FW_TASK_APS_DL2_R_IRQs 110
+#define C_ABE_FW_TASK_AMIC_96_48_LP 111
+#define C_ABE_FW_TASK_DMIC1_96_48_LP 112
+#define C_ABE_FW_TASK_DMIC2_96_48_LP 113
+#define C_ABE_FW_TASK_DMIC3_96_48_LP 114
+#define C_ABE_FW_TASK_INIT_FW_MEMORY 115
+#define C_ABE_FW_TASK_DEBUGTRACE_VX_ASRCs 116
+#define C_ABE_FW_TASK_ASRC_BT_UL_8 117
+#define C_ABE_FW_TASK_ASRC_BT_UL_16 118
+#define C_ABE_FW_TASK_ASRC_BT_DL_8 119
+#define C_ABE_FW_TASK_ASRC_BT_DL_16 120
+#define C_ABE_FW_TASK_BT_DL_48_8_HP_OPP100 121
+#define C_ABE_FW_TASK_BT_DL_48_16_HP_OPP100 122
+#define C_ABE_FW_TASK_BT_DL_48_8_OPP100 123
+#define C_ABE_FW_TASK_BT_DL_48_16_OPP100 124
+#endif/* _ABE_TASKID_H_ */
diff --git a/sound/soc/omap/abe/abe_typ.h b/sound/soc/omap/abe/abe_typ.h
new file mode 100644
index 00000000000..801b0423857
--- /dev/null
+++ b/sound/soc/omap/abe/abe_typ.h
@@ -0,0 +1,679 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include "abe_def.h"
+#include "abe_initxxx_labels.h"
+#ifndef ABETYP
+#define ABETYP
+/*
+ * BASIC TYPES
+ */
+#define MAX_UINT8 ((((1L << 7) -1)<<1) +1)
+#define MAX_UINT16 ((((1L << 15) -1)<<1) +1)
+#define MAX_UINT32 ((((1L << 31) -1)<<1) +1)
+#define s8 char
+#define u8 unsigned char
+#define s16 short
+#define u16 unsigned short
+#define s32 int
+#define u32 unsigned int
+/* returned status from HAL APIs */
+#define abehal_status u32
+/* 4 bytes Bit field indicating the type of informations to be traced */
+typedef u32 abe_dbg_mask_t;
+/* scheduling task loops (250us / 272us with respectively 48kHz /
+ 44.1kHz on Phoenix). */
+typedef u32 abe_dbg_t;
+/* Index to the table of sequences */
+typedef u32 abe_seq_code_t;
+/* Index to the table of subroutines called in the sequence */
+typedef u32 abe_sub_code_t;
+/* subroutine with no parameter */
+typedef void (*abe_subroutine0) (void);
+/* subroutine with one parameter */
+typedef void (*abe_subroutine1) (u32);
+typedef void (*abe_subroutine2) (u32, u32);
+typedef void (*abe_subroutine3) (u32, u32, u32);
+typedef void (*abe_subroutine4) (u32, u32, u32, u32);
+/*
+ * CODE PORTABILITY - FUTURE PATCHES
+ *
+ * 32bits field for having the code compatible with future revisions of
+ * the hardware (audio integration) or evolution of the software
+ * partitionning. Used for the highest level APIs (launch_sequences)
+ */
+typedef u32 abe_patch_rev;
+/*
+ * ENUMS
+ */
+/*
+ * MEMORY CONFIG TYPE
+ *
+ * 0: Ultra Lowest power consumption audio player
+ * 1: OPP 25% (simple multimedia features)
+ * 2: OPP 50% (multimedia and voice calls)
+ * 3: OPP100% (multimedia complex use-cases)
+ */
+#define ABE_AUDIO_PLAYER_ON_HEADSET_OR_EARPHONE 1
+#define ABE_DRIFT_MANAGEMENT_FOR_AUDIO_PLAYER 2
+#define ABE_DRIFT_MANAGEMENT_FOR_VOICE_CALL 3
+#define ABE_VOICE_CALL_ON_HEADSET_OR_EARPHONE_OR_BT 4
+#define ABE_MULTIMEDIA_AUDIO_RECORDER 5
+#define ABE_VIBRATOR_OR_HAPTICS 6
+#define ABE_VOICE_CALL_ON_HANDS_FREE_SPEAKER 7
+#define ABE_RINGER_TONES 8
+#define ABE_VOICE_CALL_WITH_EARPHONE_ACTIVE_NOISE_CANCELLER 9
+#define ABE_LAST_USE_CASE 10
+/*
+ * OPP TYPE
+ *
+ * 0: Ultra Lowest power consumption audio player
+ * 1: OPP 25% (simple multimedia features)
+ * 2: OPP 50% (multimedia and voice calls)
+ * 3: OPP100% (multimedia complex use-cases)
+ */
+#define ABE_OPP0 0
+#define ABE_OPP25 1
+#define ABE_OPP50 2
+#define ABE_OPP100 3
+/*
+ * DMIC DECIMATION RATIO
+ *
+ */
+#define ABE_DEC16 16
+#define ABE_DEC25 25
+#define ABE_DEC32 32
+#define ABE_DEC40 40
+/*
+ * SAMPLES TYPE
+ *
+ * mono 16bits sample LSB aligned, 16 MSB bits are unused
+ * mono right shifted to 16bits LSBs on a 32bits DMEM FIFO for McBSP
+ * TX purpose.
+ * mono sample MSB aligned (16/24/32bits)
+ * two successive mono samples in one 32bits container
+ * Two L/R 16bits samples in a 32bits container,
+ * Two channels defined with two MSB aligned samples
+ * Three channels defined with three MSB aligned samples (MIC)
+ * Four channels defined with four MSB aligned samples (MIC)
+ . . .
+ * Eight channels defined with eight MSB aligned samples (MIC)
+ */
+#define MONO_MSB 1
+#define MONO_RSHIFTED_16 2
+#define STEREO_RSHIFTED_16 3
+#define STEREO_16_16 4
+#define STEREO_MSB 5
+#define THREE_MSB 6
+#define FOUR_MSB 7
+#define FIVE_MSB 8
+#define SIX_MSB 9
+#define SEVEN_MSB 10
+#define EIGHT_MSB 11
+#define NINE_MSB 12
+#define TEN_MSB 13
+/*
+ * PORT PROTOCOL TYPE - abe_port_protocol_switch_id
+ */
+#define SLIMBUS_PORT_PROT 1
+#define SERIAL_PORT_PROT 2
+#define TDM_SERIAL_PORT_PROT 3
+#define DMIC_PORT_PROT 4
+#define MCPDMDL_PORT_PROT 5
+#define MCPDMUL_PORT_PROT 6
+#define PINGPONG_PORT_PROT 7
+#define DMAREQ_PORT_PROT 8
+/*
+ * PORT IDs, this list is aligned with the FW data mapping
+ */
+#define DMIC_PORT 0
+#define PDM_UL_PORT 1
+#define BT_VX_UL_PORT 2
+#define MM_UL_PORT 3
+#define MM_UL2_PORT 4
+#define VX_UL_PORT 5
+#define MM_DL_PORT 6
+#define VX_DL_PORT 7
+#define TONES_DL_PORT 8
+#define VIB_DL_PORT 9
+#define BT_VX_DL_PORT 10
+#define PDM_DL_PORT 11
+#define MM_EXT_OUT_PORT 12
+#define MM_EXT_IN_PORT 13
+#define TDM_DL_PORT 14
+#define TDM_UL_PORT 15
+#define DEBUG_PORT 16
+#define LAST_PORT_ID 17
+/* definitions for the compatibility with HAL05xx */
+#define PDM_DL1_PORT 18
+#define PDM_DL2_PORT 19
+#define PDM_VIB_PORT 20
+/* There is only one DMIC port, always used with 6 samples
+ per 96kHz periods */
+#define DMIC_PORT1 DMIC_PORT
+#define DMIC_PORT2 DMIC_PORT
+#define DMIC_PORT3 DMIC_PORT
+/*
+ * ABE_DL_SRC_ID source of samples
+ */
+#define SRC_DL1_MIXER_OUTPUT DL1_M_labelID
+#define SRC_SDT_MIXER_OUTPUT SDT_M_labelID
+#define SRC_DL1_GAIN_OUTPUT DL1_GAIN_out_labelID
+#define SRC_DL1_EQ_OUTPUT DL1_EQ_labelID
+#define SRC_DL2_GAIN_OUTPUT DL2_GAIN_out_labelID
+#define SRC_DL2_EQ_OUTPUT DL2_EQ_labelID
+#define SRC_MM_DL MM_DL_labelID
+#define SRC_TONES_DL Tones_labelID
+#define SRC_VX_DL VX_DL_labelID
+#define SRC_VX_UL VX_UL_labelID
+#define SRC_MM_UL2 MM_UL2_labelID
+#define SRC_MM_UL MM_UL_labelID
+/*
+ * abe_patched_pattern_id selection of the audio engine signal to
+ * replace by a precomputed pattern
+ */
+#define DBG_PATCH_AMIC 1
+#define DBG_PATCH_DMIC1 2
+#define DBG_PATCH_DMIC2 3
+#define DBG_PATCH_DMIC3 4
+#define DBG_PATCH_VX_REC 5
+#define DBG_PATCH_BT_UL 6
+#define DBG_PATCH_MM_DL 7
+#define DBG_PATCH_DL2_EQ 8
+#define DBG_PATCH_VIBRA 9
+#define DBG_PATCH_MM_EXT_IN 10
+#define DBG_PATCH_EANC_FBK_Out 11
+#define DBG_PATCH_MIC4 12
+#define DBG_PATCH_MM_DL_MIXDL1 13
+#define DBG_PATCH_MM_DL_MIXDL2 14
+/*
+ * Signal processing module names - EQ APS MIX ROUT
+ */
+/* equalizer downlink path headset + earphone */
+#define FEAT_EQ1 1
+/* equalizer downlink path integrated handsfree LEFT */
+#define FEAT_EQ2L (FEAT_EQ1+1)
+/* equalizer downlink path integrated handsfree RIGHT */
+#define FEAT_EQ2R (FEAT_EQ2L+1)
+/* equalizer downlink path side-tone */
+#define FEAT_EQSDT (FEAT_EQ2R+1)
+/* equalizer uplink path AMIC */
+#define FEAT_EQAMIC (FEAT_EQSDT+1)
+/* equalizer uplink path DMIC */
+#define FEAT_EQDMIC (FEAT_EQAMIC+1)
+/* Acoustic protection for headset */
+#define FEAT_APS1 (FEAT_EQDMIC+1)
+/* acoustic protection high-pass filter for handsfree "Left" */
+#define FEAT_APS2 (FEAT_APS1+1)
+/* acoustic protection high-pass filter for handsfree "Right" */
+#define FEAT_APS3 (FEAT_APS2+1)
+/* asynchronous sample-rate-converter for the downlink voice path */
+#define FEAT_ASRC1 (FEAT_APS3+1)
+/* asynchronous sample-rate-converter for the uplink voice path */
+#define FEAT_ASRC2 (FEAT_ASRC1+1)
+/* asynchronous sample-rate-converter for the multimedia player */
+#define FEAT_ASRC3 (FEAT_ASRC2+1)
+/* asynchronous sample-rate-converter for the echo reference */
+#define FEAT_ASRC4 (FEAT_ASRC3+1)
+/* mixer of the headset and earphone path */
+#define FEAT_MIXDL1 (FEAT_ASRC4+1)
+/* mixer of the hands-free path */
+#define FEAT_MIXDL2 (FEAT_MIXDL1+1)
+/* mixer for audio being sent on the voice_ul path */
+#define FEAT_MIXAUDUL (FEAT_MIXDL2+1)
+/* mixer for voice communication recording */
+#define FEAT_MIXVXREC (FEAT_MIXAUDUL+1)
+/* mixer for side-tone */
+#define FEAT_MIXSDT (FEAT_MIXVXREC+1)
+/* mixer for echo reference */
+#define FEAT_MIXECHO (FEAT_MIXSDT+1)
+/* router of the uplink path */
+#define FEAT_UPROUTE (FEAT_MIXECHO+1)
+/* all gains */
+#define FEAT_GAINS (FEAT_UPROUTE+1)
+#define FEAT_GAINS_DMIC1 (FEAT_GAINS+1)
+#define FEAT_GAINS_DMIC2 (FEAT_GAINS_DMIC1+1)
+#define FEAT_GAINS_DMIC3 (FEAT_GAINS_DMIC2+1)
+#define FEAT_GAINS_AMIC (FEAT_GAINS_DMIC3+1)
+#define FEAT_GAINS_SPLIT (FEAT_GAINS_AMIC+1)
+#define FEAT_GAINS_DL1 (FEAT_GAINS_SPLIT+1)
+#define FEAT_GAINS_DL2 (FEAT_GAINS_DL1+1)
+#define FEAT_GAIN_EANC (FEAT_GAINS_DL2+1)
+/* sequencing queue of micro tasks */
+#define FEAT_SEQ (FEAT_GAIN_EANC+1)
+/* Phoenix control queue through McPDM */
+#define FEAT_CTL (FEAT_SEQ+1)
+/* list of features of the firmware -------------------------------*/
+#define MAXNBFEATURE FEAT_CTL
+/* abe_equ_id */
+/* equalizer downlink path headset + earphone */
+#define EQ1 FEAT_EQ1
+/* equalizer downlink path integrated handsfree LEFT */
+#define EQ2L FEAT_EQ2L
+#define EQ2R FEAT_EQ2R
+/* equalizer downlink path side-tone */
+#define EQSDT FEAT_EQSDT
+#define EQAMIC FEAT_EQAMIC
+#define EQDMIC FEAT_EQDMIC
+/* abe_aps_id */
+/* Acoustic protection for headset */
+#define APS1 FEAT_APS1
+#define APS2L FEAT_APS2
+#define APS2R FEAT_APS3
+/* abe_asrc_id */
+/* asynchronous sample-rate-converter for the downlink voice path */
+#define ASRC1 FEAT_ASRC1
+/* asynchronous sample-rate-converter for the uplink voice path */
+#define ASRC2 FEAT_ASRC2
+/* asynchronous sample-rate-converter for the multimedia player */
+#define ASRC3 FEAT_ASRC3
+/* asynchronous sample-rate-converter for the voice uplink echo_reference */
+#define ASRC4 FEAT_ASRC4
+/* abe_mixer_id */
+#define MIXDL1 FEAT_MIXDL1
+#define MIXDL2 FEAT_MIXDL2
+#define MIXSDT FEAT_MIXSDT
+#define MIXECHO FEAT_MIXECHO
+#define MIXEANC FEAT_GAIN_EANC
+#define MIXAUDUL FEAT_MIXAUDUL
+#define MIXVXREC FEAT_MIXVXREC
+/* abe_router_id */
+/* there is only one router up to now */
+#define UPROUTE FEAT_UPROUTE
+/*
+ * GAIN IDs
+ */
+#define GAINS_DMIC1 FEAT_GAINS_DMIC1
+#define GAINS_DMIC2 FEAT_GAINS_DMIC2
+#define GAINS_DMIC3 FEAT_GAINS_DMIC3
+#define GAINS_AMIC FEAT_GAINS_AMIC
+#define GAINS_SPLIT FEAT_GAINS_SPLIT
+#define GAINS_DL1 FEAT_GAINS_DL1
+#define GAINS_DL2 FEAT_GAINS_DL2
+#define GAINS_EANC FEAT_GAIN_EANC
+/*
+ * EVENT GENERATORS - abe_event_id
+ */
+#define EVENT_TIMER 0
+#define EVENT_44100 1
+/*
+ * SERIAL PORTS IDs - abe_mcbsp_id
+ */
+#define MCBSP1_TX MCBSP1_DMA_TX
+#define MCBSP1_RX MCBSP1_DMA_RX
+#define MCBSP2_TX MCBSP2_DMA_TX
+#define MCBSP2_RX MCBSP2_DMA_RX
+#define MCBSP3_TX MCBSP3_DMA_TX
+#define MCBSP3_RX MCBSP3_DMA_RX
+/*
+ * SERIAL PORTS IDs - abe_slimbus_id;
+ */
+#define SLIMBUS1_TX0 SLIMBUS1_DMA_TX0
+#define SLIMBUS1_TX1 SLIMBUS1_DMA_TX1
+#define SLIMBUS1_TX2 SLIMBUS1_DMA_TX2
+#define SLIMBUS1_TX3 SLIMBUS1_DMA_TX3
+#define SLIMBUS1_TX4 SLIMBUS1_DMA_TX4
+#define SLIMBUS1_TX5 SLIMBUS1_DMA_TX5
+#define SLIMBUS1_TX6 SLIMBUS1_DMA_TX6
+#define SLIMBUS1_TX7 SLIMBUS1_DMA_TX7
+#define SLIMBUS1_RX0 SLIMBUS1_DMA_RX0
+#define SLIMBUS1_RX1 SLIMBUS1_DMA_RX1
+#define SLIMBUS1_RX2 SLIMBUS1_DMA_RX2
+#define SLIMBUS1_RX3 SLIMBUS1_DMA_RX3
+#define SLIMBUS1_RX4 SLIMBUS1_DMA_RX4
+#define SLIMBUS1_RX5 SLIMBUS1_DMA_RX5
+#define SLIMBUS1_RX6 SLIMBUS1_DMA_RX6
+#define SLIMBUS1_RX7 SLIMBUS1_DMA_RX7
+#define SLIMBUS_UNUSED _DUMMY_FIFO_
+/*
+ * --------------------------------- TYPES USED FOR APIS ---------------
+ */
+/*
+ * HARDWARE CONFIG TYPE
+ */
+typedef struct {
+ /* EVENT_GENERATOR_COUNTER_DEFAULT gives about 96kHz */
+ u32 AESS_EVENT_GENERATOR_COUNTER__COUNTER_VALUE;
+ /* 0: DMAreq, 1:Counter */
+ u32 AESS_EVENT_SOURCE_SELECTION__SELECTION;
+ /* 5bits DMAreq selection */
+ u32 AESS_AUDIO_ENGINE_SCHEDULER__DMA_REQ_SELECTION;
+ u32 HAL_EVENT_SELECTION;
+ /* 0: 96kHz 1:192kHz */
+ u32 MCPDM_CTRL__DIV_SEL;
+ /* 0: no command in the FIFO, 1: 6 data on each lines (with commands) */
+ u32 MCPDM_CTRL__CMD_INT;
+ /* 0:MSB aligned 1:LSB aligned */
+ u32 MCPDM_CTRL__PDMOUTFORMAT;
+ u32 MCPDM_CTRL__PDM_DN5_EN;
+ u32 MCPDM_CTRL__PDM_DN4_EN;
+ u32 MCPDM_CTRL__PDM_DN3_EN;
+ u32 MCPDM_CTRL__PDM_DN2_EN;
+ u32 MCPDM_CTRL__PDM_DN1_EN;
+ u32 MCPDM_CTRL__PDM_UP3_EN;
+ u32 MCPDM_CTRL__PDM_UP2_EN;
+ u32 MCPDM_CTRL__PDM_UP1_EN;
+ u32 MCPDM_FIFO_CTRL_DN__DN_TRESH;
+ u32 MCPDM_FIFO_CTRL_UP__UP_TRESH;
+ /* 0:2.4MHz 1:3.84MHz */
+ u32 DMIC_CTRL__DMIC_CLK_DIV;
+ /* 0:MSB aligned 1:LSB aligned */
+ u32 DMIC_CTRL__DMICOUTFORMAT;
+ u32 DMIC_CTRL__DMIC_UP3_EN;
+ u32 DMIC_CTRL__DMIC_UP2_EN;
+ u32 DMIC_CTRL__DMIC_UP1_EN;
+ /* 1*(DMIC_UP1_EN+ 2+ 3)*2 OCP read access every 96/88.1 KHz. */
+ u32 DMIC_FIFO_CTRL__DMIC_TRESH;
+ /* 1:MSB 2:LSB aligned */
+ u32 MCBSP_SPCR1_REG__RJUST;
+ /* 1=MONO, 2=STEREO, 3=TDM_3_CHANNELS, 4=TDM_4_CHANNELS, .... */
+ u32 MCBSP_THRSH2_REG_REG__XTHRESHOLD;
+ /* 1=MONO, 2=STEREO, 3=TDM_3_CHANNELS, 4=TDM_4_CHANNELS, .... */
+ u32 MCBSP_THRSH1_REG_REG__RTHRESHOLD;
+ u32 SLIMBUS_DCT_FIFO_SETUP_REG__SB_THRESHOLD;
+} abe_hw_config_init_t;
+/*
+ * EQU_T
+ *
+ * coefficients of the equalizer
+ */
+typedef struct {
+ /* type of filter */
+ u32 equ_type;
+ /* filter length */
+ u32 equ_length;
+ union {
+ /* parameters are the direct and recursive coefficients in */
+ /* Q6.26 integer fixed-point format. */
+ s32 type1[NBEQ1];
+ struct {
+ /* center frequency of the band [Hz] */
+ s32 freq[NBEQ2];
+ /* gain of each band. [dB] */
+ s32 gain[NBEQ2];
+ /* Q factor of this band [dB] */
+ s32 q[NBEQ2];
+ } type2;
+ } coef;
+ s32 equ_param3;
+} abe_equ_t;
+/*
+ * APS_T
+ *
+ * coefficients of the Acoustics Protection and Safety
+ */
+typedef struct {
+ s32 coef1[NBAPS1];
+ s32 coef2[NBAPS2];
+} abe_aps_t;
+typedef struct {
+ /* structure of two energy_t estimation for coil and membrane */
+ u32 e1;
+ u32 e2;
+} abe_aps_energy_t;
+/*
+ * ROUTER_T
+ *
+ * table of indexes in unsigned bytes
+ */
+typedef u16 abe_router_t;
+/*
+ * DATA_FORMAT_T
+ *
+ * used in port declaration
+ */
+typedef struct {
+ /* Sampling frequency of the stream */
+ u32 f;
+ /* Sample format type */
+ u32 samp_format;
+} abe_data_format_t;
+/*
+ * PORT_PROTOCOL_T
+ *
+ * port declaration
+ */
+typedef struct {
+ /* Direction=0 means input from AESS point of view */
+ u32 direction;
+ /* Protocol type (switch) during the data transfers */
+ u32 protocol_switch;
+ union {
+ /* Slimbus peripheral connected to ATC */
+ struct {
+ /* Address of ATC Slimbus descriptor's index */
+ u32 desc_addr1;
+ /* DMEM address 1 in bytes */
+ u32 buf_addr1;
+ /* DMEM buffer size size in bytes */
+ u32 buf_size;
+ /* ITERation on each DMAreq signals */
+ u32 iter;
+ /* Second ATC index for SlimBus reception (or NULL) */
+ u32 desc_addr2;
+ /* DMEM address 2 in bytes */
+ u32 buf_addr2;
+ } prot_slimbus;
+ /* McBSP/McASP peripheral connected to ATC */
+ struct {
+ u32 desc_addr;
+ /* Address of ATC McBSP/McASP descriptor's in bytes */
+ u32 buf_addr;
+ /* DMEM address in bytes */
+ u32 buf_size;
+ /* ITERation on each DMAreq signals */
+ u32 iter;
+ } prot_serial;
+ /* DMIC peripheral connected to ATC */
+ struct {
+ /* DMEM address in bytes */
+ u32 buf_addr;
+ /* DMEM buffer size in bytes */
+ u32 buf_size;
+ /* Number of activated DMIC */
+ u32 nbchan;
+ } prot_dmic;
+ /* McPDMDL peripheral connected to ATC */
+ struct {
+ /* DMEM address in bytes */
+ u32 buf_addr;
+ /* DMEM size in bytes */
+ u32 buf_size;
+ /* Control allowed on McPDM DL */
+ u32 control;
+ } prot_mcpdmdl;
+ /* McPDMUL peripheral connected to ATC */
+ struct {
+ /* DMEM address size in bytes */
+ u32 buf_addr;
+ /* DMEM buffer size size in bytes */
+ u32 buf_size;
+ } prot_mcpdmul;
+ /* Ping-Pong interface to the Host using cache-flush */
+ struct {
+ /* Address of ATC descriptor's */
+ u32 desc_addr;
+ /* DMEM buffer base address in bytes */
+ u32 buf_addr;
+ /* DMEM size in bytes for each ping and pong buffers */
+ u32 buf_size;
+ /* IRQ address (either DMA (0) MCU (1) or DSP(2)) */
+ u32 irq_addr;
+ /* IRQ data content loaded in the AESS IRQ register */
+ u32 irq_data;
+ /* Call-back function upon IRQ reception */
+ u32 callback;
+ } prot_pingpong;
+ /* DMAreq line to CBPr */
+ struct {
+ /* Address of ATC descriptor's */
+ u32 desc_addr;
+ /* DMEM buffer address in bytes */
+ u32 buf_addr;
+ /* DMEM buffer size size in bytes */
+ u32 buf_size;
+ /* ITERation on each DMAreq signals */
+ u32 iter;
+ /* DMAreq address */
+ u32 dma_addr;
+ /* DMA/AESS = 1 << #DMA */
+ u32 dma_data;
+ } prot_dmareq;
+ /* Circular buffer - direct addressing to DMEM */
+ struct {
+ /* DMEM buffer base address in bytes */
+ u32 buf_addr;
+ /* DMEM buffer size in bytes */
+ u32 buf_size;
+ /* DMAreq address */
+ u32 dma_addr;
+ /* DMA/AESS = 1 << #DMA */
+ u32 dma_data;
+ } prot_circular_buffer;
+ } p;
+} abe_port_protocol_t;
+/*
+ * DMA_T
+ *
+ * dma structure for easing programming
+ */
+typedef struct {
+ /* OCP L3 pointer to the first address of the */
+ void *data;
+ /* destination buffer (either DMA or Ping-Pong read/write pointers). */
+ /* address L3 when addressing the DMEM buffer instead of CBPr */
+ void *l3_dmem;
+ /* address L3 translated to L4 the ARM memory space */
+ void *l4_dmem;
+ /* number of iterations for the DMA data moves. */
+ u32 iter;
+} abe_dma_t;
+typedef struct {
+ /* Offset to the first address of the */
+ u32 data;
+ /* number of iterations for the DMA data moves. */
+ u32 iter;
+} abe_dma_t_offset;
+/*
+ * SEQ_T
+ *
+ * struct {
+ * micros_t time; Waiting time before executing next line
+ * seq_code_t code Subroutine index interpreted in the HAL and
+ * translated to
+ * FW subroutine codes in case of ABE tasks
+ * int32 param[2] Two parameters
+ * } seq_t
+ *
+ */
+typedef struct {
+ u32 delta_time;
+ u32 code;
+ u32 param[4];
+ u8 tag;
+} abe_seq_t;
+typedef struct {
+ u32 mask;
+ abe_seq_t seq1;
+ abe_seq_t seq2;
+} abe_sequence_t;
+/*
+ * DRIFT_T abe_drift_t = s32
+ *
+ * ASRC drift parameter in [ppm] value
+ */
+/*
+ * --------------------------------- INTERNAL DATA TYPES ---------------------
+ */
+/*
+ * ABE_IRQ_DATA_T
+ *
+ * IRQ FIFO content declaration
+ * APS interrupts : IRQtag_APS to [31:28], APS_IRQs to [27:16],
+ * loopCounter to [15:0]
+ * SEQ interrupts : IRQtag_COUNT to [31:28], Count_IRQs to [27:16],
+ * loopCounter to [15:0]
+ * Ping-Pong Interrupts : IRQtag_PP to [31:28], PP_MCU_IRQ to [27:16],
+ * loopCounter to [15:0]
+ */
+typedef struct {
+ unsigned int counter:16;
+ unsigned int data:12;
+ unsigned int tag:4;
+} abe_irq_data_t;
+/*
+ * ABE_PORT_T status / format / sampling / protocol(call_back) / features /
+ * gain / name ..
+ *
+ */
+typedef struct {
+ /* running / idled */
+ u16 status;
+ /* Sample format type */
+ abe_data_format_t format;
+ /* API : for ASRC */
+ s32 drift;
+ /* optionnal call-back index for errors and ack */
+ u16 callback;
+ /* IO tasks buffers */
+ u16 smem_buffer1;
+ u16 smem_buffer2;
+ abe_port_protocol_t protocol;
+ /* pointer and iteration counter of the xDMA */
+ abe_dma_t_offset dma;
+ /* list of features associated to a port (EQ, APS, ... , ends with 0) */
+ u16 feature_index[MAXFEATUREPORT];
+ char name[NBCHARPORTNAME];
+} abe_port_t;
+/*
+ * ABE_SUBROUTINE_T
+ *
+ */
+typedef struct {
+ u32 sub_id;
+ s32 param[4];
+} abe_subroutine_t;
+/*
+ * ABE_PORT_INFO_T OPP, subroutines to call on reset
+ *
+ */
+typedef struct {
+ u32 min_opp;
+ abe_subroutine_t sub1;
+ abe_subroutine_t sub2;
+} abe_port_info_t;
+/*
+ * ABE_FEATURE_T
+ *
+ */
+typedef struct {
+ u16 enable_with_default_data;
+ u16 disable_feature;
+ u16 read_parameter;
+ u16 write_parameter;
+ u16 running_status;
+ u16 fw_input_buffer_address;
+ u16 fw_output_buffer_address;
+ u16 fw_scheduler_slot_position;
+ u16 fw_scheduler_subslot_position;
+ u32 min_opp;
+ char name[NBCHARFEATURENAME];
+} abe_feature_t;
+#endif/* ifndef ABETYP */
diff --git a/sound/soc/omap/abe/abe_typedef.h b/sound/soc/omap/abe/abe_typedef.h
new file mode 100644
index 00000000000..37c1146fdf1
--- /dev/null
+++ b/sound/soc/omap/abe/abe_typedef.h
@@ -0,0 +1,199 @@
+/*
+ * ALSA SoC OMAP ABE driver
+ *
+ * Author: Laurent Le Faucheur <l-le-faucheur@ti.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#ifndef _ABE_TYPEDEF_H_
+#define _ABE_TYPEDEF_H_
+#include "abe_define.h"
+/*
+ * Basic types definition
+ */
+typedef unsigned char ABE_uchar;
+typedef char ABE_char;
+typedef unsigned short ABE_uint16;
+typedef short ABE_int16;
+typedef long ABE_int32;
+typedef unsigned long ABE_uint32;
+typedef ABE_uchar *pABE_uchar;
+typedef ABE_char *pABE_char;
+typedef ABE_uint16 *pABE_uint16;
+typedef ABE_int16 *pABE_int16;
+typedef ABE_int32 *pABE_int32;
+typedef ABE_uint32 *pABE_uint32;
+/*
+ * Commonly used structures
+ */
+typedef struct abetaskTag {
+ /* 0 ... Index of called function */
+ ABE_uint16 iF;
+ /* 2 ... for INITPTR of A0 */
+ ABE_uint16 A0;
+ /* 4 ... for INITPTR of A1 */
+ ABE_uint16 A1;
+ /* 6 ... for INITPTR of A2 & A3 */
+ ABE_uint16 A2_3;
+ /* 8 ... for INITPTR of A4 & A5 */
+ ABE_uint16 A4_5;
+ /* 10 ... for INITREG of R0, R1, R2, R3 */
+ ABE_uint16 R;
+ /* 12 */
+ ABE_uint16 misc0;
+ /* 14 */
+ ABE_uint16 misc1;
+} ABE_STask;
+typedef ABE_STask *pABE_STask;
+typedef ABE_STask **ppABE_STask;
+typedef struct {
+ /* 0 */
+ ABE_uint16 drift_ASRC;
+ /* 2 */
+ ABE_uint16 drift_io;
+ /* 4 "Function index" of XLS sheet "Functions" */
+ ABE_uchar io_type_idx;
+ /* 5 1 = MONO or Stereo1616, 2= STEREO, ... */
+ ABE_uchar samp_size;
+ /* 6 drift "issues" for ASRC */
+ ABE_int16 flow_counter;
+ /* 8 address for IRQ or DMArequests */
+ ABE_uint16 hw_ctrl_addr;
+ /* 10 DMA request bit-field or IRQ (DSP/MCU) */
+ ABE_uchar atc_irq_data;
+ /* 11 0 = Read, 3 = Write */
+ ABE_uchar direction_rw;
+ /* 12 */
+ ABE_uchar repeat_last_samp;
+ /* 13 12 at 48kHz, ... */
+ ABE_uchar nsamp;
+ /* 14 nsamp x samp_size */
+ ABE_uchar x_io;
+ /* 15 ON = 0x80, OFF = 0x00 */
+ ABE_uchar on_off;
+ /* 16 For Slimbus and TDM purpose */
+ ABE_uint16 split_addr1;
+ /* 18 */
+ ABE_uint16 split_addr2;
+ /* 20 */
+ ABE_uint16 split_addr3;
+ /* 22 */
+ ABE_uchar before_f_index;
+ /* 23 */
+ ABE_uchar after_f_index;
+ /* 24 SM/CM INITPTR field */
+ ABE_uint16 smem_addr1;
+ /* 26 in bytes */
+ ABE_uint16 atc_address1;
+ /* 28 DMIC_ATC_PTR, MCPDM_UL_ATC_PTR, ... */
+ ABE_uint16 atc_pointer_saved1;
+ /* 30 samp_size (except in TDM or Slimbus) */
+ ABE_uchar data_size1;
+ /* 31 "Function index" of XLS sheet "Functions" */
+ ABE_uchar copy_f_index1;
+ /* 32 For Slimbus and TDM purpose */
+ ABE_uint16 smem_addr2;
+ /* 34 */
+ ABE_uint16 atc_address2;
+ /* 36 */
+ ABE_uint16 atc_pointer_saved2;
+ /* 38 */
+ ABE_uchar data_size2;
+ /* 39 */
+ ABE_uchar copy_f_index2;
+} ABE_SIODescriptor;
+/* [w] asrc output used for the next asrc call (+/- 1 / 0) */
+#define drift_asrc_ 0
+/* [w] asrc output used for controlling the number of samples to be
+ exchanged (+/- 1 / 0) */
+#define drift_io_ 2
+/* address of the IO subroutine */
+#define io_type_idx_ 4
+#define samp_size_ 5
+/* flow error counter */
+#define flow_counter_ 6
+/* dmareq address or host irq buffer address (atc address) */
+#define hw_ctrl_addr_ 8
+/* data content to be loaded to "hw_ctrl_addr" */
+#define atc_irq_data_ 10
+/* read dmem =0, write dmem =3 (atc offset of the access pointer) */
+#define direction_rw_ 11
+/* flag set to allow repeating the last sample on downlink paths */
+#define repeat_last_samp_ 12
+/* number of samples (either mono stereo...) */
+#define nsamp_ 13
+/* x number of raw DMEM data moved */
+#define x_io_ 14
+#define on_off_ 15
+/* internal smem buffer initptr pointer index */
+#define split_addr1_ 16
+/* internal smem buffer initptr pointer index */
+#define split_addr2_ 18
+/* internal smem buffer initptr pointer index */
+#define split_addr3_ 20
+/* index of the copy subroutine */
+#define before_f_index_ 22
+/* index of the copy subroutine */
+#define after_f_index_ 23
+#define minidesc1_ 24
+/* internal smem buffer initptr pointer index */
+#define rel_smem_ 0
+/* atc descriptor address (byte address x4) */
+#define rel_atc_ 2
+/* location of the saved ATC pointer (+debug info) */
+#define rel_atc_saved 4
+/* size of each sample (1:mono/1616 2:stereo ... ) */
+#define rel_size_ 6
+/* index of the copy subroutine */
+#define rel_f_ 7
+#define s_mem_mm_ul 24
+#define s_mm_ul_size 30
+#define minidesc2_ 32
+#define Struct_Size 40
+typedef struct {
+ /* 0: [W] asrc output used for the next ASRC call (+/- 1 / 0) */
+ ABE_uint16 drift_ASRC;
+ /* 2: [W] asrc output used for controlling the number of
+ samples to be exchanged (+/- 1 / 0) */
+ ABE_uint16 drift_io;
+ /* 4: DMAReq address or HOST IRQ buffer address (ATC ADDRESS) */
+ ABE_uint16 hw_ctrl_addr;
+ /* 6: index of the copy subroutine */
+ ABE_uchar copy_func_index;
+ /* 7: X number of SMEM samples to move */
+ ABE_uchar x_io;
+ /* 8: 0 for mono data, 1 for stereo data */
+ ABE_uchar data_size;
+ /* 9: internal SMEM buffer INITPTR pointer index */
+ ABE_uchar smem_addr;
+ /* 10: data content to be loaded to "hw_ctrl_addr" */
+ ABE_uchar atc_irq_data;
+ /* 11: ping/pong buffer flag */
+ ABE_uchar counter;
+ /* 12: current Base address of the working buffer */
+ ABE_uint16 workbuff_BaseAddr;
+ /* 14: samples left in the working buffer */
+ ABE_uint16 workbuff_Samples;
+ /* 16: Base address of the ping/pong buffer 0 */
+ ABE_uint16 nextbuff0_BaseAddr;
+ /* 18: samples available in the ping/pong buffer 0 */
+ ABE_uint16 nextbuff0_Samples;
+ /* 20: Base address of the ping/pong buffer 1 */
+ ABE_uint16 nextbuff1_BaseAddr;
+ /* 22: samples available in the ping/pong buffer 1 */
+ ABE_uint16 nextbuff1_Samples;
+} ABE_SPingPongDescriptor;
+#endif/* _ABE_TYPEDEF_H_ */
diff --git a/sound/soc/omap/mcpdm.c b/sound/soc/omap/mcpdm.c
deleted file mode 100644
index 928f0370745..00000000000
--- a/sound/soc/omap/mcpdm.c
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * mcpdm.c -- McPDM interface driver
- *
- * Author: Jorge Eduardo Candelaria <x0107209@ti.com>
- * Copyright (C) 2009 - Texas Instruments, Inc.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-
-#include "mcpdm.h"
-
-static struct omap_mcpdm *mcpdm;
-
-static inline void omap_mcpdm_write(u16 reg, u32 val)
-{
- __raw_writel(val, mcpdm->io_base + reg);
-}
-
-static inline int omap_mcpdm_read(u16 reg)
-{
- return __raw_readl(mcpdm->io_base + reg);
-}
-
-static void omap_mcpdm_reg_dump(void)
-{
- dev_dbg(mcpdm->dev, "***********************\n");
- dev_dbg(mcpdm->dev, "IRQSTATUS_RAW: 0x%04x\n",
- omap_mcpdm_read(MCPDM_IRQSTATUS_RAW));
- dev_dbg(mcpdm->dev, "IRQSTATUS: 0x%04x\n",
- omap_mcpdm_read(MCPDM_IRQSTATUS));
- dev_dbg(mcpdm->dev, "IRQENABLE_SET: 0x%04x\n",
- omap_mcpdm_read(MCPDM_IRQENABLE_SET));
- dev_dbg(mcpdm->dev, "IRQENABLE_CLR: 0x%04x\n",
- omap_mcpdm_read(MCPDM_IRQENABLE_CLR));
- dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n",
- omap_mcpdm_read(MCPDM_IRQWAKE_EN));
- dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n",
- omap_mcpdm_read(MCPDM_DMAENABLE_SET));
- dev_dbg(mcpdm->dev, "DMAENABLE_CLR: 0x%04x\n",
- omap_mcpdm_read(MCPDM_DMAENABLE_CLR));
- dev_dbg(mcpdm->dev, "DMAWAKEEN: 0x%04x\n",
- omap_mcpdm_read(MCPDM_DMAWAKEEN));
- dev_dbg(mcpdm->dev, "CTRL: 0x%04x\n",
- omap_mcpdm_read(MCPDM_CTRL));
- dev_dbg(mcpdm->dev, "DN_DATA: 0x%04x\n",
- omap_mcpdm_read(MCPDM_DN_DATA));
- dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n",
- omap_mcpdm_read(MCPDM_UP_DATA));
- dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n",
- omap_mcpdm_read(MCPDM_FIFO_CTRL_DN));
- dev_dbg(mcpdm->dev, "FIFO_CTRL_UP: 0x%04x\n",
- omap_mcpdm_read(MCPDM_FIFO_CTRL_UP));
- dev_dbg(mcpdm->dev, "DN_OFFSET: 0x%04x\n",
- omap_mcpdm_read(MCPDM_DN_OFFSET));
- dev_dbg(mcpdm->dev, "***********************\n");
-}
-
-/*
- * Takes the McPDM module in and out of reset state.
- * Uplink and downlink can be reset individually.
- */
-static void omap_mcpdm_reset_capture(int reset)
-{
- int ctrl = omap_mcpdm_read(MCPDM_CTRL);
-
- if (reset)
- ctrl |= SW_UP_RST;
- else
- ctrl &= ~SW_UP_RST;
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-}
-
-static void omap_mcpdm_reset_playback(int reset)
-{
- int ctrl = omap_mcpdm_read(MCPDM_CTRL);
-
- if (reset)
- ctrl |= SW_DN_RST;
- else
- ctrl &= ~SW_DN_RST;
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-}
-
-/*
- * Enables the transfer through the PDM interface to/from the Phoenix
- * codec by enabling the corresponding UP or DN channels.
- */
-void omap_mcpdm_start(int stream)
-{
- int ctrl = omap_mcpdm_read(MCPDM_CTRL);
-
- if (stream)
- ctrl |= mcpdm->up_channels;
- else
- ctrl |= mcpdm->dn_channels;
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-}
-
-/*
- * Disables the transfer through the PDM interface to/from the Phoenix
- * codec by disabling the corresponding UP or DN channels.
- */
-void omap_mcpdm_stop(int stream)
-{
- int ctrl = omap_mcpdm_read(MCPDM_CTRL);
-
- if (stream)
- ctrl &= ~mcpdm->up_channels;
- else
- ctrl &= ~mcpdm->dn_channels;
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-}
-
-/*
- * Configures McPDM uplink for audio recording.
- * This function should be called before omap_mcpdm_start.
- */
-int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink)
-{
- int irq_mask = 0;
- int ctrl;
-
- if (!uplink)
- return -EINVAL;
-
- mcpdm->uplink = uplink;
-
- /* Enable irq request generation */
- irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK;
- omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask);
-
- /* Configure uplink threshold */
- if (uplink->threshold > UP_THRES_MAX)
- uplink->threshold = UP_THRES_MAX;
-
- omap_mcpdm_write(MCPDM_FIFO_CTRL_UP, uplink->threshold);
-
- /* Configure DMA controller */
- omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_UP_ENABLE);
-
- /* Set pdm out format */
- ctrl = omap_mcpdm_read(MCPDM_CTRL);
- ctrl &= ~PDMOUTFORMAT;
- ctrl |= uplink->format & PDMOUTFORMAT;
-
- /* Uplink channels */
- mcpdm->up_channels = uplink->channels & (PDM_UP_MASK | PDM_STATUS_MASK);
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-
- return 0;
-}
-
-/*
- * Configures McPDM downlink for audio playback.
- * This function should be called before omap_mcpdm_start.
- */
-int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink)
-{
- int irq_mask = 0;
- int ctrl;
-
- if (!downlink)
- return -EINVAL;
-
- mcpdm->downlink = downlink;
-
- /* Enable irq request generation */
- irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK;
- omap_mcpdm_write(MCPDM_IRQENABLE_SET, irq_mask);
-
- /* Configure uplink threshold */
- if (downlink->threshold > DN_THRES_MAX)
- downlink->threshold = DN_THRES_MAX;
-
- omap_mcpdm_write(MCPDM_FIFO_CTRL_DN, downlink->threshold);
-
- /* Enable DMA request generation */
- omap_mcpdm_write(MCPDM_DMAENABLE_SET, DMA_DN_ENABLE);
-
- /* Set pdm out format */
- ctrl = omap_mcpdm_read(MCPDM_CTRL);
- ctrl &= ~PDMOUTFORMAT;
- ctrl |= downlink->format & PDMOUTFORMAT;
-
- /* Downlink channels */
- mcpdm->dn_channels = downlink->channels & (PDM_DN_MASK | PDM_CMD_MASK);
-
- omap_mcpdm_write(MCPDM_CTRL, ctrl);
-
- return 0;
-}
-
-/*
- * Cleans McPDM uplink configuration.
- * This function should be called when the stream is closed.
- */
-int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink)
-{
- int irq_mask = 0;
-
- if (!uplink)
- return -EINVAL;
-
- /* Disable irq request generation */
- irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK;
- omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask);
-
- /* Disable DMA request generation */
- omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_UP_ENABLE);
-
- /* Clear Downlink channels */
- mcpdm->up_channels = 0;
-
- mcpdm->uplink = NULL;
-
- return 0;
-}
-
-/*
- * Cleans McPDM downlink configuration.
- * This function should be called when the stream is closed.
- */
-int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink)
-{
- int irq_mask = 0;
-
- if (!downlink)
- return -EINVAL;
-
- /* Disable irq request generation */
- irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK;
- omap_mcpdm_write(MCPDM_IRQENABLE_CLR, irq_mask);
-
- /* Disable DMA request generation */
- omap_mcpdm_write(MCPDM_DMAENABLE_CLR, DMA_DN_ENABLE);
-
- /* clear Downlink channels */
- mcpdm->dn_channels = 0;
-
- mcpdm->downlink = NULL;
-
- return 0;
-}
-
-static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id)
-{
- struct omap_mcpdm *mcpdm_irq = dev_id;
- int irq_status;
-
- irq_status = omap_mcpdm_read(MCPDM_IRQSTATUS);
-
- /* Acknowledge irq event */
- omap_mcpdm_write(MCPDM_IRQSTATUS, irq_status);
-
- if (irq & MCPDM_DN_IRQ_FULL) {
- dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status);
- omap_mcpdm_reset_playback(1);
- omap_mcpdm_playback_open(mcpdm_irq->downlink);
- omap_mcpdm_reset_playback(0);
- }
-
- if (irq & MCPDM_DN_IRQ_EMPTY) {
- dev_err(mcpdm_irq->dev, "DN FIFO error %x\n", irq_status);
- omap_mcpdm_reset_playback(1);
- omap_mcpdm_playback_open(mcpdm_irq->downlink);
- omap_mcpdm_reset_playback(0);
- }
-
- if (irq & MCPDM_DN_IRQ) {
- dev_dbg(mcpdm_irq->dev, "DN write request\n");
- }
-
- if (irq & MCPDM_UP_IRQ_FULL) {
- dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status);
- omap_mcpdm_reset_capture(1);
- omap_mcpdm_capture_open(mcpdm_irq->uplink);
- omap_mcpdm_reset_capture(0);
- }
-
- if (irq & MCPDM_UP_IRQ_EMPTY) {
- dev_err(mcpdm_irq->dev, "UP FIFO error %x\n", irq_status);
- omap_mcpdm_reset_capture(1);
- omap_mcpdm_capture_open(mcpdm_irq->uplink);
- omap_mcpdm_reset_capture(0);
- }
-
- if (irq & MCPDM_UP_IRQ) {
- dev_dbg(mcpdm_irq->dev, "UP write request\n");
- }
-
- return IRQ_HANDLED;
-}
-
-int omap_mcpdm_request(void)
-{
- int ret;
-
- clk_enable(mcpdm->clk);
-
- spin_lock(&mcpdm->lock);
-
- if (!mcpdm->free) {
- dev_err(mcpdm->dev, "McPDM interface is in use\n");
- spin_unlock(&mcpdm->lock);
- ret = -EBUSY;
- goto err;
- }
- mcpdm->free = 0;
-
- spin_unlock(&mcpdm->lock);
-
- /* Disable lines while request is ongoing */
- omap_mcpdm_write(MCPDM_CTRL, 0x00);
-
- ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler,
- 0, "McPDM", (void *)mcpdm);
- if (ret) {
- dev_err(mcpdm->dev, "Request for McPDM IRQ failed\n");
- goto err;
- }
-
- return 0;
-
-err:
- clk_disable(mcpdm->clk);
- return ret;
-}
-
-void omap_mcpdm_free(void)
-{
- spin_lock(&mcpdm->lock);
- if (mcpdm->free) {
- dev_err(mcpdm->dev, "McPDM interface is already free\n");
- spin_unlock(&mcpdm->lock);
- return;
- }
- mcpdm->free = 1;
- spin_unlock(&mcpdm->lock);
-
- clk_disable(mcpdm->clk);
-
- free_irq(mcpdm->irq, (void *)mcpdm);
-}
-
-/* Enable/disable DC offset cancelation for the analog
- * headset path (PDM channels 1 and 2).
- */
-int omap_mcpdm_set_offset(int offset1, int offset2)
-{
- int offset;
-
- if ((offset1 > DN_OFST_MAX) || (offset2 > DN_OFST_MAX))
- return -EINVAL;
-
- offset = (offset1 << DN_OFST_RX1) | (offset2 << DN_OFST_RX2);
-
- /* offset cancellation for channel 1 */
- if (offset1)
- offset |= DN_OFST_RX1_EN;
- else
- offset &= ~DN_OFST_RX1_EN;
-
- /* offset cancellation for channel 2 */
- if (offset2)
- offset |= DN_OFST_RX2_EN;
- else
- offset &= ~DN_OFST_RX2_EN;
-
- omap_mcpdm_write(MCPDM_DN_OFFSET, offset);
-
- return 0;
-}
-
-int __devinit omap_mcpdm_probe(struct platform_device *pdev)
-{
- struct resource *res;
- int ret = 0;
-
- mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL);
- if (!mcpdm) {
- ret = -ENOMEM;
- goto exit;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "no resource\n");
- goto err_resource;
- }
-
- spin_lock_init(&mcpdm->lock);
- mcpdm->free = 1;
- mcpdm->io_base = ioremap(res->start, resource_size(res));
- if (!mcpdm->io_base) {
- ret = -ENOMEM;
- goto err_resource;
- }
-
- mcpdm->irq = platform_get_irq(pdev, 0);
-
- mcpdm->clk = clk_get(&pdev->dev, "pdm_ck");
- if (IS_ERR(mcpdm->clk)) {
- ret = PTR_ERR(mcpdm->clk);
- dev_err(&pdev->dev, "unable to get pdm_ck: %d\n", ret);
- goto err_clk;
- }
-
- mcpdm->dev = &pdev->dev;
- platform_set_drvdata(pdev, mcpdm);
-
- return 0;
-
-err_clk:
- iounmap(mcpdm->io_base);
-err_resource:
- kfree(mcpdm);
-exit:
- return ret;
-}
-
-int __devexit omap_mcpdm_remove(struct platform_device *pdev)
-{
- struct omap_mcpdm *mcpdm_ptr = platform_get_drvdata(pdev);
-
- platform_set_drvdata(pdev, NULL);
-
- clk_put(mcpdm_ptr->clk);
-
- iounmap(mcpdm_ptr->io_base);
-
- mcpdm_ptr->clk = NULL;
- mcpdm_ptr->free = 0;
- mcpdm_ptr->dev = NULL;
-
- kfree(mcpdm_ptr);
-
- return 0;
-}
-
diff --git a/sound/soc/omap/mcpdm.h b/sound/soc/omap/mcpdm.h
deleted file mode 100644
index df3e16fb51f..00000000000
--- a/sound/soc/omap/mcpdm.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * mcpdm.h -- Defines for McPDM driver
- *
- * Author: Jorge Eduardo Candelaria <x0107209@ti.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-/* McPDM registers */
-
-#define MCPDM_REVISION 0x00
-#define MCPDM_SYSCONFIG 0x10
-#define MCPDM_IRQSTATUS_RAW 0x24
-#define MCPDM_IRQSTATUS 0x28
-#define MCPDM_IRQENABLE_SET 0x2C
-#define MCPDM_IRQENABLE_CLR 0x30
-#define MCPDM_IRQWAKE_EN 0x34
-#define MCPDM_DMAENABLE_SET 0x38
-#define MCPDM_DMAENABLE_CLR 0x3C
-#define MCPDM_DMAWAKEEN 0x40
-#define MCPDM_CTRL 0x44
-#define MCPDM_DN_DATA 0x48
-#define MCPDM_UP_DATA 0x4C
-#define MCPDM_FIFO_CTRL_DN 0x50
-#define MCPDM_FIFO_CTRL_UP 0x54
-#define MCPDM_DN_OFFSET 0x58
-
-/*
- * MCPDM_IRQ bit fields
- * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR
- */
-
-#define MCPDM_DN_IRQ (1 << 0)
-#define MCPDM_DN_IRQ_EMPTY (1 << 1)
-#define MCPDM_DN_IRQ_ALMST_EMPTY (1 << 2)
-#define MCPDM_DN_IRQ_FULL (1 << 3)
-
-#define MCPDM_UP_IRQ (1 << 8)
-#define MCPDM_UP_IRQ_EMPTY (1 << 9)
-#define MCPDM_UP_IRQ_ALMST_FULL (1 << 10)
-#define MCPDM_UP_IRQ_FULL (1 << 11)
-
-#define MCPDM_DOWNLINK_IRQ_MASK 0x00F
-#define MCPDM_UPLINK_IRQ_MASK 0xF00
-
-/*
- * MCPDM_DMAENABLE bit fields
- */
-
-#define DMA_DN_ENABLE 0x1
-#define DMA_UP_ENABLE 0x2
-
-/*
- * MCPDM_CTRL bit fields
- */
-
-#define PDM_UP1_EN 0x0001
-#define PDM_UP2_EN 0x0002
-#define PDM_UP3_EN 0x0004
-#define PDM_DN1_EN 0x0008
-#define PDM_DN2_EN 0x0010
-#define PDM_DN3_EN 0x0020
-#define PDM_DN4_EN 0x0040
-#define PDM_DN5_EN 0x0080
-#define PDMOUTFORMAT 0x0100
-#define CMD_INT 0x0200
-#define STATUS_INT 0x0400
-#define SW_UP_RST 0x0800
-#define SW_DN_RST 0x1000
-#define PDM_UP_MASK 0x007
-#define PDM_DN_MASK 0x0F8
-#define PDM_CMD_MASK 0x200
-#define PDM_STATUS_MASK 0x400
-
-
-#define PDMOUTFORMAT_LJUST (0 << 8)
-#define PDMOUTFORMAT_RJUST (1 << 8)
-
-/*
- * MCPDM_FIFO_CTRL bit fields
- */
-
-#define UP_THRES_MAX 0xF
-#define DN_THRES_MAX 0xF
-
-/*
- * MCPDM_DN_OFFSET bit fields
- */
-
-#define DN_OFST_RX1_EN 0x0001
-#define DN_OFST_RX2_EN 0x0100
-
-#define DN_OFST_RX1 1
-#define DN_OFST_RX2 9
-#define DN_OFST_MAX 0x1F
-
-#define MCPDM_UPLINK 1
-#define MCPDM_DOWNLINK 2
-
-struct omap_mcpdm_link {
- int irq_mask;
- int threshold;
- int format;
- int channels;
-};
-
-struct omap_mcpdm_platform_data {
- unsigned long phys_base;
- u16 irq;
-};
-
-struct omap_mcpdm {
- struct device *dev;
- unsigned long phys_base;
- void __iomem *io_base;
- u8 free;
- int irq;
-
- spinlock_t lock;
- struct omap_mcpdm_platform_data *pdata;
- struct clk *clk;
- struct omap_mcpdm_link *downlink;
- struct omap_mcpdm_link *uplink;
- struct completion irq_completion;
-
- int dn_channels;
- int up_channels;
-};
-
-extern void omap_mcpdm_start(int stream);
-extern void omap_mcpdm_stop(int stream);
-extern int omap_mcpdm_capture_open(struct omap_mcpdm_link *uplink);
-extern int omap_mcpdm_playback_open(struct omap_mcpdm_link *downlink);
-extern int omap_mcpdm_capture_close(struct omap_mcpdm_link *uplink);
-extern int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink);
-extern int omap_mcpdm_request(void);
-extern void omap_mcpdm_free(void);
-extern int omap_mcpdm_set_offset(int offset1, int offset2);
-int __devinit omap_mcpdm_probe(struct platform_device *pdev);
-int __devexit omap_mcpdm_remove(struct platform_device *pdev);
diff --git a/sound/soc/omap/omap-abe-coef.h b/sound/soc/omap/omap-abe-coef.h
new file mode 100644
index 00000000000..6a169805b2e
--- /dev/null
+++ b/sound/soc/omap/omap-abe-coef.h
@@ -0,0 +1,200 @@
+/*
+ * omap-abe-coef.h
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * Contact: Ricardo Neri <ricardo.neri@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_ABE_COEFFICIENTS_H__
+#define __OMAP_ABE_COEFFICIENTS_H__
+
+/*
+ * ABE CONST AREA FOR EQUALIZER COEFFICIENTS
+ *
+ * TODO: These coefficents are for demonstration purposes. Set of
+ * coefficients can be computed for specific needs.
+ */
+
+#define NBDL1EQ_PROFILES 4 /* Number of supported DL1EQ profiles */
+#define NBDL1COEFFS 25 /* Number of coefficients for DL1EQ profiles */
+#define NBDL20EQ_PROFILES 4 /* Number of supported DL2EQ_L profiles */
+#define NBDL21EQ_PROFILES 4 /* Number of supported DL2EQ_R profiles */
+#define NBDL2COEFFS 25 /* Number of coefficients of DL2EQ profiles */
+#define NBAMICEQ_PROFILES 3 /* Number of supported AMICEQ profiles */
+#define NBAMICCOEFFS 19 /* Number of coefficients of AMICEQ profiles */
+#define NBSDTEQ_PROFILES 4 /* Number of supported SDTEQ profiles */
+#define NBSDTCOEFFS 9 /* Number of coefficients for SDTEQ profiles */
+#define NBDMICEQ_PROFILES 3 /* Number of supported DMICEQ profiles */
+#define NBDMICCOEFFS 19 /* Number of coefficients of DMICEQ profiles */
+
+/*
+ * Coefficients for DL1EQ
+ */
+const s32 dl1_equ_coeffs[NBDL1EQ_PROFILES][NBDL1COEFFS] = {
+/* Flat response with Gain = 0dB */
+ {0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0x040002, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0},
+
+/* 800Hz cut-off frequency and Gain = 0dB */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, -7554223,
+ 708210, -708206, 7554225, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 6802833, -682266, 731554},
+
+/* 800Hz cut-off frequency and Gain = -12dB */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, -3777112,
+ 5665669, -5665667, 3777112, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 6802833, -682266, 731554},
+
+/* 800Hz cut-off frequency and Gain = -20dB */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, -1510844,
+ 4532536, -4532536, 1510844, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 6802833, -682266, 731554},
+};
+
+/*
+ * Coefficients for DL2EQ_L
+ */
+const s32 dl20_equ_coeffs[NBDL20EQ_PROFILES][NBDL2COEFFS] = {
+/* Flat response with Gain = 0dB */
+ {0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0x040002, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0},
+
+/* 800Hz cut-off frequency and Gain = 0dB */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, -7554223,
+ 708210, -708206, 7554225, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 6802833, -682266, 731554},
+
+/* 800Hz cut-off frequency and Gain = -12dB */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, -3777112,
+ 5665669, -5665667, 3777112, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 6802833, -682266, 731554},
+
+/* 800Hz cut-off frequency and Gain = -20dB */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, -1510844,
+ 4532536, -4532536, 1510844, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 6802833, -682266, 731554},
+};
+
+/*
+ * Coefficients for DL2_EQ_R
+ */
+const s32 dl21_equ_coeffs[NBDL20EQ_PROFILES][NBDL2COEFFS] = {
+/* Flat response with Gain = 0dB */
+ {0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0x040002, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0},
+
+/* 800Hz cut-off frequency and Gain = 0dB */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, -7554223,
+ 708210, -708206, 7554225, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 6802833, -682266, 731554},
+
+/*800Hz cut-off frequency and Gain = -12dB */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, -3777112,
+ 5665669, -5665667, 3777112, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 6802833, -682266, 731554},
+
+/* 800Hz cut-off frequency and Gain = -20dB */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, -1510844,
+ 4532536, -4532536, 1510844, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 6802833, -682266, 731554},
+};
+
+/*
+ * Coefficients for DMICEQ
+ */
+const u32 dmic_equ_coeffs[NBDMICEQ_PROFILES][NBDMICCOEFFS] = {
+/* 20kHz cut-off frequency and Gain = 0dB */
+ {-4119413, -192384, -341428, -348088,
+ -151380, 151380, 348088, 341428, 192384,
+ 4119419, 1938156, -6935719, 775202,
+ -1801934, 2997698, -3692214, 3406822,
+ -2280190, 1042982},
+
+/* 20kHz cut-off frequency and Gain = -12dB */
+ {-1029873, -3078121, -5462817, -5569389,
+ -2422069, 2422071, 5569391, 5462819,
+ 3078123, 1029875, 1938188, -6935811,
+ 775210, -1801950, 2997722, -3692238,
+ 3406838, -2280198, 1042982},
+
+/* 20kHz cut-off frequency and Gain = -18dB */
+ {-514937, -1539061, -2731409, -2784693,
+ -1211033, 1211035, 2784695, 2731411,
+ 1539063, 514939, 1938188, -6935811,
+ 775210, -1801950, 2997722, -3692238,
+ 3406838, -2280198, 1042982},
+};
+
+/*
+ * Coefficients for AMICEQ
+ */
+const u32 amic_equ_coeffs[NBAMICEQ_PROFILES][NBAMICCOEFFS] = {
+/* 20kHz cut-off frequency and Gain = 0dB */
+ {-4119413, -192384, -341428, -348088,
+ -151380, 151380, 348088, 341428, 192384,
+ 4119419, 1938156, -6935719, 775202,
+ -1801934, 2997698, -3692214, 3406822,
+ -2280190, 1042982},
+
+/* 20kHz cut-off frequency and Gain = -12dB */
+ {-1029873, -3078121, -5462817, -5569389,
+ -2422069, 2422071, 5569391, 5462819,
+ 3078123, 1029875, 1938188, -6935811,
+ 775210, -1801950, 2997722, -3692238,
+ 3406838, -2280198, 1042982},
+
+/* 20kHz cut-off frequency and Gain = -18dB */
+ {-514937, -1539061, -2731409, -2784693,
+ -1211033, 1211035, 2784695, 2731411,
+ 1539063, 514939, 1938188, -6935811,
+ 775210, -1801950, 2997722, -3692238,
+ 3406838, -2280198, 1042982},
+};
+
+
+/*
+ * Coefficients for SDTEQ
+ */
+const u32 sdt_equ_coeffs[NBSDTEQ_PROFILES][NBSDTCOEFFS] = {
+/* Flat response with Gain = 0dB */
+ {0, 0, 0, 0, 0x040002, 0, 0, 0, 0},
+
+/* 800Hz cut-off frequency and Gain = 0dB */
+ {0, -7554223, 708210, -708206, 7554225,
+ 0, 6802833, -682266, 731554},
+
+/* 800Hz cut-off frequency and Gain = -12dB */
+ {0, -3777112, 5665669, -5665667, 3777112,
+ 0, 6802833, -682266, 731554},
+
+/* 800Hz cut-off frequency and Gain = -20dB */
+ {0, -1510844, 4532536, -4532536, 1510844,
+ 0, 6802833, -682266, 731554}
+};
+
+#endif /* End of __OMAP_ABE_COEFFICIENTS_H__ */
diff --git a/sound/soc/omap/omap-abe-dsp.c b/sound/soc/omap/omap-abe-dsp.c
new file mode 100644
index 00000000000..8ebc71f6fa3
--- /dev/null
+++ b/sound/soc/omap/omap-abe-dsp.c
@@ -0,0 +1,2163 @@
+/*
+ * omap-abe-dsp.c
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Copyright (C) 2010 Texas Instruments Inc.
+ *
+ * Author : Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/i2c/twl.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/dma-mapping.h>
+
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
+#include <plat/dma.h>
+#include <plat/omap-pm.h>
+#include <plat/prcm.h>
+#include "../../../arch/arm/mach-omap2/powerdomain.h"
+#include "../../../arch/arm/mach-omap2/pm.h"
+
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/omap-abe-dsp.h>
+
+#include "omap-abe-dsp.h"
+#include "omap-abe-coef.h"
+#include "omap-abe.h"
+#include "abe/abe_main.h"
+
+// TODO: change to S16 and use ARM SIMD to re-format to S32
+#define ABE_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
+
+// TODO: make all these into virtual registers or similar - split out by type */
+#define ABE_NUM_MIXERS 22
+#define ABE_NUM_MUXES 12
+#define ABE_NUM_WIDGETS 46 /* TODO - refine this val */
+#define ABE_NUM_DAPM_REG \
+ (ABE_NUM_MIXERS + ABE_NUM_MUXES + ABE_NUM_WIDGETS)
+#define ABE_WIDGET_START (ABE_NUM_MIXERS + ABE_NUM_MUXES)
+#define ABE_WIDGET_END (ABE_WIDGET_START + ABE_NUM_WIDGETS)
+#define ABE_BE_START (ABE_WIDGET_START + 7)
+#define ABE_BE_END (ABE_BE_START + 10)
+#define ABE_MUX_BASE ABE_NUM_MIXERS
+
+/* Uplink MUX path identifiers from ROUTE_UL */
+#define ABE_MM_UL1(x) (x + ABE_NUM_MIXERS)
+#define ABE_MM_UL2(x) (x + ABE_NUM_MIXERS + 8)
+#define ABE_VX_UL(x) (x + ABE_NUM_MIXERS + 10)
+#define ABE_WIDGET(x) (x + ABE_NUM_MIXERS + ABE_NUM_MUXES)
+//#define ABE_BE_WIDGET(x) (x + ABE_NUM_MIXERS + ABE_NUM_MUXES)
+
+#define VIRT_SWITCH 0
+
+// TODO: OPP bitmask - Use HAL version after update
+#define ABE_OPP_25 0
+#define ABE_OPP_50 1
+#define ABE_OPP_100 2
+
+#define ABE_ROUTES_UL 14
+
+/* TODO: fine tune for ping pong - buffer is 2 periods of 12k each*/
+static const struct snd_pcm_hardware omap_abe_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .period_bytes_min = 4 * 1024,
+ .period_bytes_max = 24 * 1024,
+ .periods_min = 2,
+ .periods_max = 2,
+ .buffer_bytes_max = 24 * 1024 * 2,
+};
+
+/*
+ * ABE driver
+ *
+ * TODO: tasks 1,2,3,4,5,6,7,8 below
+ *
+ * This driver is responsible for :-
+ * 1) ABE init - including loading ABE firmware
+ * 2) ABE coefficient mgmt - inc user space re-calcs
+ * 8) Process ABE platform data
+ *
+ */
+
+/* ABE private data */
+struct abe_data {
+ struct omap4_abe_dsp_pdata *abe_pdata;
+ struct platform_device *pdev;
+ struct snd_soc_platform *platform;
+
+ struct delayed_work delayed_work;
+ struct mutex mutex;
+ struct mutex opp_mutex;
+
+ struct clk *clk;
+
+ void __iomem *io_base;
+ int irq;
+ int opp;
+
+ int fe_id;
+
+ unsigned int dl1_equ_profile;
+ unsigned int dl20_equ_profile;
+ unsigned int dl21_equ_profile;
+ unsigned int sdt_equ_profile;
+ unsigned int amic_equ_profile;
+ unsigned int dmic_equ_profile;
+
+ int active;
+
+ /* DAPM mixer config - TODO: some of this can be replaced with HAL update */
+ u32 dapm[ABE_NUM_DAPM_REG];
+
+ u16 router[16];
+
+ int loss_count;
+
+ int first_irq;
+
+ struct snd_pcm_substream *psubs;
+
+};
+
+static struct abe_data *abe;
+
+static struct powerdomain *abe_pwrdm;
+
+// TODO: map to the new version of HAL
+static unsigned int abe_dsp_read(struct snd_soc_platform *platform,
+ unsigned int reg)
+{
+ struct abe_data *priv = snd_soc_platform_get_drvdata(platform);
+ return priv->dapm[reg];
+}
+
+static int abe_dsp_write(struct snd_soc_platform *platform, unsigned int reg,
+ unsigned int val)
+{
+ struct abe_data *priv = snd_soc_platform_get_drvdata(platform);
+ priv->dapm[reg] = val;
+
+ //dev_dbg(platform->dev, "fe: %d widget %d %s\n", abe->fe_id,
+ // reg - ABE_WIDGET_START, val ? "on" : "off");
+ return 0;
+}
+
+static void abe_irq_pingpong_subroutine(void)
+{
+ u32 dst, n_bytes;
+
+ abe_read_next_ping_pong_buffer(MM_DL_PORT, &dst, &n_bytes);
+ abe_set_ping_pong_buffer(MM_DL_PORT, n_bytes);
+
+ /* Do not call ALSA function for first IRQ */
+ if (abe->first_irq) {
+ abe->first_irq = 0;
+ } else {
+ if (abe->psubs)
+ snd_pcm_period_elapsed(abe->psubs);
+ }
+}
+
+static irqreturn_t abe_irq_handler(int irq, void *dev_id)
+{
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ /* TODO: handle underruns/overruns/errors */
+ pm_runtime_get_sync(&pdev->dev);
+ abe_clear_irq();
+ abe_irq_processing();
+ pm_runtime_put_sync(&pdev->dev);
+
+ return IRQ_HANDLED;
+}
+
+static int abe_init_engine(struct snd_soc_platform *platform)
+{
+ struct abe_data *priv = snd_soc_platform_get_drvdata(platform);
+#ifndef CONFIG_PM_RUNTIME
+ struct omap4_abe_dsp_pdata *pdata = priv->abe_pdata;
+#endif
+ struct platform_device *pdev = priv->pdev;
+ abe_equ_t dl2_eq;
+ int ret = 0;
+
+ abe_init_mem(abe->io_base);
+
+ /* aess_clk has to be enabled to access hal register.
+ * Disable the clk after it has been used.
+ */
+ pm_runtime_get_sync(&pdev->dev);
+
+ ret = request_threaded_irq(abe->irq, NULL, abe_irq_handler,
+ IRQF_ONESHOT, "ABE", (void *)abe);
+ if (ret) {
+ dev_err(platform->dev, "request for ABE IRQ %d failed %d\n",
+ abe->irq, ret);
+ return ret;
+ }
+
+ abe_reset_hal();
+
+ abe_load_fw(); // TODO: use fw API here
+
+ /* Config OPP 100 for now */
+ mutex_lock(&abe->opp_mutex);
+ abe_set_opp_processing(ABE_OPP100);
+ abe->opp = 100;
+ mutex_unlock(&abe->opp_mutex);
+
+ /* "tick" of the audio engine */
+ abe_write_event_generator(EVENT_TIMER);
+
+ dl2_eq.equ_length = NBDL2COEFFS;
+
+ /* build the coefficient parameter for the equalizer api */
+ memcpy(dl2_eq.coef.type1, dl20_equ_coeffs[1],
+ sizeof(dl20_equ_coeffs[1]));
+
+ /* load the high-pass coefficient of IHF-Right */
+ abe_write_equalizer(EQ2L, &dl2_eq);
+ abe->dl20_equ_profile = 1;
+
+ /* build the coefficient parameter for the equalizer api */
+ memcpy(dl2_eq.coef.type1, dl21_equ_coeffs[1],
+ sizeof(dl21_equ_coeffs[1]));
+
+ /* load the high-pass coefficient of IHF-Left */
+ abe_write_equalizer(EQ2R, &dl2_eq);
+ abe->dl21_equ_profile = 1;
+
+ pm_runtime_put_sync(&pdev->dev);
+
+ /* set initial state to all-pass with gain=1 coefficients */
+ abe->amic_equ_profile = 0;
+ abe->dmic_equ_profile = 0;
+ abe->dl1_equ_profile = 0;
+ abe->sdt_equ_profile = 0;
+
+
+ return ret;
+}
+
+void abe_dsp_pm_get(void)
+{
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ pm_runtime_get_sync(&pdev->dev);
+}
+
+void abe_dsp_pm_put(void)
+{
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ pm_runtime_put_sync(&pdev->dev);
+}
+
+void abe_dsp_shutdown(void)
+{
+ if (!abe->active && !abe_check_activity()) {
+ abe_set_opp_processing(ABE_OPP25);
+ abe->opp = 25;
+ abe_stop_event_generator();
+ udelay(250);
+ /* FIXME: Dependency on PM framework */
+ //omap_device_set_rate(&pdev->dev, &pdev->dev, 0);
+ }
+}
+
+void abe_dsp_mcpdm_shutdown(void)
+{
+ mutex_lock(&abe->mutex);
+
+ abe_dsp_shutdown();
+
+ mutex_unlock(&abe->mutex);
+
+ return;
+}
+
+/*
+ * These TLV settings will need fine tuned for each individual control
+ */
+
+/* Media DL1 volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(mm_dl1_tlv, -12000, 100, 3000);
+
+/* Media DL1 volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(tones_dl1_tlv, -12000, 100, 3000);
+
+/* Media DL1 volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(voice_dl1_tlv, -12000, 100, 3000);
+
+/* Media DL1 volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(capture_dl1_tlv, -12000, 100, 3000);
+
+/* Media DL2 volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(mm_dl2_tlv, -12000, 100, 3000);
+
+/* Media DL2 volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(tones_dl2_tlv, -12000, 100, 3000);
+
+/* Media DL2 volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(voice_dl2_tlv, -12000, 100, 3000);
+
+/* Media DL2 volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(capture_dl2_tlv, -12000, 100, 3000);
+
+/* SDT volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(sdt_ul_tlv, -12000, 100, 3000);
+
+/* SDT volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(sdt_dl_tlv, -12000, 100, 3000);
+
+/* AUDUL volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(audul_mm_tlv, -12000, 100, 3000);
+
+/* AUDUL volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(audul_tones_tlv, -12000, 100, 3000);
+
+/* AUDUL volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(audul_vx_ul_tlv, -12000, 100, 3000);
+
+/* AUDUL volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(audul_vx_dl_tlv, -12000, 100, 3000);
+
+/* VXREC volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(vxrec_mm_dl_tlv, -12000, 100, 3000);
+
+/* VXREC volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(vxrec_tones_tlv, -12000, 100, 3000);
+
+/* VXREC volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(vxrec_vx_dl_tlv, -12000, 100, 3000);
+
+/* VXREC volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(vxrec_vx_ul_tlv, -12000, 100, 3000);
+
+/* DMIC volume control from -120 to 30 dB in 1 dB steps */
+static DECLARE_TLV_DB_SCALE(dmic_tlv, -12000, 100, 3000);
+
+//TODO: we have to use the shift value atm to represent register id due to current HAL
+static int dl1_put_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ if (ucontrol->value.integer.value[0]) {
+ abe->dapm[mc->shift] = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
+ abe_enable_gain(MIXDL1, mc->reg);
+ } else {
+ abe->dapm[mc->shift] = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
+ abe_disable_gain(MIXDL1, mc->reg);
+ }
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 1;
+}
+
+static int dl2_put_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ if (ucontrol->value.integer.value[0]) {
+ abe->dapm[mc->shift] = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
+ abe_enable_gain(MIXDL2, mc->reg);
+ } else {
+ abe->dapm[mc->shift] = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
+ abe_disable_gain(MIXDL2, mc->reg);
+ }
+
+ pm_runtime_put_sync(&pdev->dev);
+ return 1;
+}
+
+static int audio_ul_put_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ if (ucontrol->value.integer.value[0]) {
+ abe->dapm[mc->shift] = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
+ abe_enable_gain(MIXAUDUL, mc->reg);
+ } else {
+ abe->dapm[mc->shift] = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
+ abe_disable_gain(MIXAUDUL, mc->reg);
+ }
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 1;
+}
+
+static int vxrec_put_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ if (ucontrol->value.integer.value[0]) {
+ abe->dapm[mc->shift] = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
+ abe_enable_gain(MIXVXREC, mc->reg);
+ } else {
+ abe->dapm[mc->shift] = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
+ abe_disable_gain(MIXVXREC, mc->reg);
+ }
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 1;
+}
+
+static int sdt_put_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ if (ucontrol->value.integer.value[0]) {
+ abe->dapm[mc->shift] = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
+ abe_enable_gain(MIXSDT, mc->reg);
+ } else {
+ abe->dapm[mc->shift] = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
+ abe_disable_gain(MIXSDT, mc->reg);
+ }
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 1;
+}
+
+static int abe_get_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ ucontrol->value.integer.value[0] = abe->dapm[mc->shift];
+
+ return 0;
+}
+
+/* router IDs that match our mixer strings */
+static const abe_router_t router[] = {
+ ZERO_labelID, /* strangely this is not 0 */
+ DMIC1_L_labelID, DMIC1_R_labelID,
+ DMIC2_L_labelID, DMIC2_R_labelID,
+ DMIC3_L_labelID, DMIC3_R_labelID,
+ BT_UL_L_labelID, BT_UL_R_labelID,
+ AMIC_L_labelID, AMIC_R_labelID,
+ VX_REC_L_labelID, VX_REC_R_labelID,
+};
+
+static int ul_mux_put_route(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ int mux = ucontrol->value.enumerated.item[0];
+ int reg = e->reg - ABE_MUX_BASE, i;
+
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ if (mux >= ABE_ROUTES_UL)
+ return 0;
+
+ if (reg < 8) {
+ /* 0 .. 9 = MM_UL */
+ abe->router[reg] = router[mux];
+ } else if (reg < 12) {
+ /* 10 .. 11 = MM_UL2 */
+ /* 12 .. 13 = VX_UL */
+ abe->router[reg + 2] = router[mux];
+ }
+
+ /* there is a 2 slot gap in the table, making it ABE_ROUTES_UL + 2 in size */
+ for (i = 0; i < ABE_ROUTES_UL + 2; i++)
+ dev_dbg(widget->dapm->dev, "router table [%d] = %d\n", i, abe->router[i]);
+
+ /* 2nd arg here is unused */
+ abe_set_router_configuration(UPROUTE, 0, (u32 *)abe->router);
+
+ abe->dapm[e->reg] = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mux_update_power(widget, kcontrol, abe->dapm[e->reg], mux, e);
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 1;
+}
+
+static int ul_mux_get_route(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_enum *e =
+ (struct soc_enum *)kcontrol->private_value;
+
+ // TODO: get mux via HAL
+
+ ucontrol->value.integer.value[0] = abe->dapm[e->reg];
+ return 0;
+}
+
+
+static int abe_put_switch(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ if (ucontrol->value.integer.value[0]) {
+ abe->dapm[mc->shift] = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
+ } else {
+ abe->dapm[mc->shift] = ucontrol->value.integer.value[0];
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
+ }
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 1;
+}
+
+
+static int volume_put_sdt_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ abe_write_mixer(MIXSDT, -12000 + (ucontrol->value.integer.value[0] * 100),
+ RAMP_0MS, mc->reg);
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 1;
+}
+
+static int volume_put_audul_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ pm_runtime_get_sync(&pdev->dev);
+ abe_write_mixer(MIXAUDUL, -12000 + (ucontrol->value.integer.value[0] * 100),
+ RAMP_0MS, mc->reg);
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 1;
+}
+
+static int volume_put_vxrec_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ pm_runtime_get_sync(&pdev->dev);
+ abe_write_mixer(MIXVXREC, -12000 + (ucontrol->value.integer.value[0] * 100),
+ RAMP_0MS, mc->reg);
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 1;
+}
+
+static int volume_put_dl1_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ pm_runtime_get_sync(&pdev->dev);
+ abe_write_mixer(MIXDL1, -12000 + (ucontrol->value.integer.value[0] * 100),
+ RAMP_0MS, mc->reg);
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 1;
+}
+
+static int volume_put_dl2_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ pm_runtime_get_sync(&pdev->dev);
+ abe_write_mixer(MIXDL2, -12000 + (ucontrol->value.integer.value[0] * 100),
+ RAMP_0MS, mc->reg);
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 1;
+}
+
+static int volume_put_dmic(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ pm_runtime_get_sync(&pdev->dev);
+ abe_write_gain(mc->reg,
+ -12000 + (ucontrol->value.integer.value[0] * 100),
+ RAMP_20MS, mc->shift);
+ abe_write_gain(mc->reg,
+ -12000 + (ucontrol->value.integer.value[1] * 100),
+ RAMP_20MS, mc->rshift);
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 1;
+}
+
+static int volume_get_dl1_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ u32 val;
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ pm_runtime_get_sync(&pdev->dev);
+ abe_read_mixer(MIXDL1, &val, mc->reg);
+ ucontrol->value.integer.value[0] = (val + 12000) / 100;
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 0;
+}
+
+static int volume_get_dl2_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+ u32 val;
+
+ pm_runtime_get_sync(&pdev->dev);
+ abe_read_mixer(MIXDL2, &val, mc->reg);
+ ucontrol->value.integer.value[0] = (val + 12000) / 100;
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 0;
+}
+
+static int volume_get_audul_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+ u32 val;
+
+ pm_runtime_get_sync(&pdev->dev);
+ abe_read_mixer(MIXAUDUL, &val, mc->reg);
+ ucontrol->value.integer.value[0] = (val + 12000) / 100;
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 0;
+}
+
+static int volume_get_vxrec_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+ u32 val;
+
+ pm_runtime_get_sync(&pdev->dev);
+ abe_read_mixer(MIXVXREC, &val, mc->reg);
+ ucontrol->value.integer.value[0] = (val + 12000) / 100;
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 0;
+}
+
+static int volume_get_sdt_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+ u32 val;
+
+ pm_runtime_get_sync(&pdev->dev);
+ abe_read_mixer(MIXSDT, &val, mc->reg);
+ ucontrol->value.integer.value[0] = (val + 12000) / 100;
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 0;
+}
+
+static int volume_get_dmic(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+ u32 val;
+
+ pm_runtime_get_sync(&pdev->dev);
+ abe_read_gain(mc->reg, &val, mc->shift);
+ ucontrol->value.integer.value[0] = (val + 12000) / 100;
+ abe_read_gain(mc->reg, &val, mc->rshift);
+ ucontrol->value.integer.value[1] = (val + 12000) / 100;
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 0;
+}
+
+static int abe_get_equalizer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_enum *eqc = (struct soc_enum *)kcontrol->private_value;
+ switch (eqc->reg) {
+ case EQ1:
+ ucontrol->value.integer.value[0] = abe->dl1_equ_profile;
+ break;
+ case EQ2L:
+ ucontrol->value.integer.value[0] = abe->dl20_equ_profile;
+ break;
+ case EQ2R:
+ ucontrol->value.integer.value[0] = abe->dl21_equ_profile;
+ break;
+ case EQAMIC:
+ ucontrol->value.integer.value[0] = abe->amic_equ_profile;
+ break;
+ case EQDMIC:
+ ucontrol->value.integer.value[0] = abe->dmic_equ_profile;
+ break;
+ case EQSDT:
+ ucontrol->value.integer.value[0] = abe->sdt_equ_profile;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void abe_dsp_set_equalizer(unsigned int id, unsigned int profile)
+{
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+ abe_equ_t equ_params;
+
+ switch (id) {
+ case EQ1:
+ equ_params.equ_length = NBDL1COEFFS;
+ memcpy(equ_params.coef.type1, dl1_equ_coeffs[profile],
+ sizeof(dl1_equ_coeffs[profile]));
+ abe->dl1_equ_profile = profile;
+ break;
+ case EQ2L:
+ equ_params.equ_length = NBDL2COEFFS;
+ memcpy(equ_params.coef.type1, dl20_equ_coeffs[profile],
+ sizeof(dl20_equ_coeffs[profile]));
+ abe->dl20_equ_profile = profile;
+ break;
+ case EQ2R:
+ equ_params.equ_length = NBDL2COEFFS;
+ memcpy(equ_params.coef.type1, dl21_equ_coeffs[profile],
+ sizeof(dl21_equ_coeffs[profile]));
+ abe->dl21_equ_profile = profile;
+ break;
+ case EQAMIC:
+ equ_params.equ_length = NBAMICCOEFFS;
+ memcpy(equ_params.coef.type1, amic_equ_coeffs[profile],
+ sizeof(amic_equ_coeffs[profile]));
+ abe->amic_equ_profile = profile;
+ break;
+ case EQDMIC:
+ equ_params.equ_length = NBDMICCOEFFS;
+ memcpy(equ_params.coef.type1, dmic_equ_coeffs[profile],
+ sizeof(dmic_equ_coeffs[profile]));
+ abe->dmic_equ_profile = profile;
+ break;
+ case EQSDT:
+ equ_params.equ_length = NBSDTCOEFFS;
+ memcpy(equ_params.coef.type1, sdt_equ_coeffs[profile],
+ sizeof(sdt_equ_coeffs[profile]));
+ abe->sdt_equ_profile = profile;
+ break;
+ default:
+ return;
+ }
+
+ pm_runtime_get_sync(&pdev->dev);
+ abe_write_equalizer(id, &equ_params);
+ pm_runtime_put_sync(&pdev->dev);
+}
+
+static int abe_put_equalizer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_enum *eqc = (struct soc_enum *)kcontrol->private_value;
+ u16 val = ucontrol->value.enumerated.item[0];
+
+ abe_dsp_set_equalizer(eqc->reg, val);
+
+ return 1;
+}
+
+static const char *dl1_equ_texts[] = {
+ "Flat response",
+ "High-pass 0dB",
+ "High-pass -12dB",
+ "High-pass -20dB",
+};
+
+static const char *dl20_equ_texts[] = {
+ "Flat response",
+ "High-pass 0dB",
+ "High-pass -12dB",
+ "High-pass -20dB",
+};
+
+static const char *dl21_equ_texts[] = {
+ "Flat response",
+ "High-pass 0dB",
+ "High-pass -12dB",
+ "High-pass -20dB",
+};
+
+static const char *amic_equ_texts[] = {
+ "High-pass 0dB",
+ "High-pass -12dB",
+ "High-pass -18dB",
+};
+
+static const char *dmic_equ_texts[] = {
+ "High-pass 0dB",
+ "High-pass -12dB",
+ "High-pass -18dB",
+};
+
+static const char *sdt_equ_texts[] = {
+ "Flat response",
+ "High-pass 0dB",
+ "High-pass -12dB",
+ "High-pass -20dB",
+};
+
+static const struct soc_enum dl1_equalizer_enum =
+ SOC_ENUM_SINGLE(EQ1, 0, NBDL1EQ_PROFILES, dl1_equ_texts);
+
+static const struct soc_enum dl20_equalizer_enum =
+ SOC_ENUM_SINGLE(EQ2L, 0, NBDL20EQ_PROFILES, dl20_equ_texts);
+
+static const struct soc_enum dl21_equalizer_enum =
+ SOC_ENUM_SINGLE(EQ2R, 0, NBDL21EQ_PROFILES, dl21_equ_texts);
+
+static const struct soc_enum amic_equalizer_enum =
+ SOC_ENUM_SINGLE(EQAMIC, 0, NBAMICEQ_PROFILES, amic_equ_texts);
+
+static const struct soc_enum dmic_equalizer_enum =
+ SOC_ENUM_SINGLE(EQDMIC, 0, NBDMICEQ_PROFILES, dmic_equ_texts);
+
+static const struct soc_enum sdt_equalizer_enum =
+ SOC_ENUM_SINGLE(EQSDT, 0, NBSDTEQ_PROFILES, sdt_equ_texts);
+
+static const char *route_ul_texts[] =
+ {"None", "DMic0L", "DMic0R", "DMic1L", "DMic1R", "DMic2L", "DMic2R",
+ "BT Left", "BT Right", "AMic0", "AMic1", "VX Left", "VX Right"};
+
+/* ROUTE_UL Mux table */
+static const struct soc_enum abe_enum[] = {
+ SOC_ENUM_SINGLE(ABE_MM_UL1(0), 0, 13, route_ul_texts),
+ SOC_ENUM_SINGLE(ABE_MM_UL1(1), 0, 13, route_ul_texts),
+ SOC_ENUM_SINGLE(ABE_MM_UL1(2), 0, 13, route_ul_texts),
+ SOC_ENUM_SINGLE(ABE_MM_UL1(3), 0, 13, route_ul_texts),
+ SOC_ENUM_SINGLE(ABE_MM_UL1(4), 0, 13, route_ul_texts),
+ SOC_ENUM_SINGLE(ABE_MM_UL1(5), 0, 13, route_ul_texts),
+ SOC_ENUM_SINGLE(ABE_MM_UL1(6), 0, 13, route_ul_texts),
+ SOC_ENUM_SINGLE(ABE_MM_UL1(7), 0, 13, route_ul_texts),
+ SOC_ENUM_SINGLE(ABE_MM_UL2(0), 0, 13, route_ul_texts),
+ SOC_ENUM_SINGLE(ABE_MM_UL2(1), 0, 13, route_ul_texts),
+ SOC_ENUM_SINGLE(ABE_VX_UL(0), 0, 13, route_ul_texts),
+ SOC_ENUM_SINGLE(ABE_VX_UL(1), 0, 13, route_ul_texts),
+};
+
+static const struct snd_kcontrol_new mm_ul00_control =
+ SOC_DAPM_ENUM_EXT("Route", abe_enum[0],
+ ul_mux_get_route, ul_mux_put_route);
+
+static const struct snd_kcontrol_new mm_ul01_control =
+ SOC_DAPM_ENUM_EXT("Route", abe_enum[1],
+ ul_mux_get_route, ul_mux_put_route);
+
+static const struct snd_kcontrol_new mm_ul02_control =
+ SOC_DAPM_ENUM_EXT("Route", abe_enum[2],
+ ul_mux_get_route, ul_mux_put_route);
+
+static const struct snd_kcontrol_new mm_ul03_control =
+ SOC_DAPM_ENUM_EXT("Route", abe_enum[3],
+ ul_mux_get_route, ul_mux_put_route);
+
+static const struct snd_kcontrol_new mm_ul04_control =
+ SOC_DAPM_ENUM_EXT("Route", abe_enum[4],
+ ul_mux_get_route, ul_mux_put_route);
+
+static const struct snd_kcontrol_new mm_ul05_control =
+ SOC_DAPM_ENUM_EXT("Route", abe_enum[5],
+ ul_mux_get_route, ul_mux_put_route);
+
+static const struct snd_kcontrol_new mm_ul06_control =
+ SOC_DAPM_ENUM_EXT("Route", abe_enum[6],
+ ul_mux_get_route, ul_mux_put_route);
+
+static const struct snd_kcontrol_new mm_ul07_control =
+ SOC_DAPM_ENUM_EXT("Route", abe_enum[7],
+ ul_mux_get_route, ul_mux_put_route);
+
+static const struct snd_kcontrol_new mm_ul10_control =
+ SOC_DAPM_ENUM_EXT("Route", abe_enum[8],
+ ul_mux_get_route, ul_mux_put_route);
+
+static const struct snd_kcontrol_new mm_ul11_control =
+ SOC_DAPM_ENUM_EXT("Route", abe_enum[9],
+ ul_mux_get_route, ul_mux_put_route);
+
+static const struct snd_kcontrol_new mm_vx0_control =
+ SOC_DAPM_ENUM_EXT("Route", abe_enum[10],
+ ul_mux_get_route, ul_mux_put_route);
+
+static const struct snd_kcontrol_new mm_vx1_control =
+ SOC_DAPM_ENUM_EXT("Route", abe_enum[11],
+ ul_mux_get_route, ul_mux_put_route);
+
+/* DL1 mixer paths */
+static const struct snd_kcontrol_new dl1_mixer_controls[] = {
+ SOC_SINGLE_EXT("Tones", MIX_DL1_INPUT_TONES, 0, 1, 0,
+ abe_get_mixer, dl1_put_mixer),
+ SOC_SINGLE_EXT("Voice", MIX_DL1_INPUT_VX_DL, 1, 1, 0,
+ abe_get_mixer, dl1_put_mixer),
+ SOC_SINGLE_EXT("Capture", MIX_DL1_INPUT_MM_UL2, 2, 1, 0,
+ abe_get_mixer, dl1_put_mixer),
+ SOC_SINGLE_EXT("Multimedia", MIX_DL1_INPUT_MM_DL, 3, 1, 0,
+ abe_get_mixer, dl1_put_mixer),
+};
+
+/* DL2 mixer paths */
+static const struct snd_kcontrol_new dl2_mixer_controls[] = {
+ SOC_SINGLE_EXT("Tones", MIX_DL2_INPUT_TONES, 4, 1, 0,
+ abe_get_mixer, dl2_put_mixer),
+ SOC_SINGLE_EXT("Voice", MIX_DL2_INPUT_VX_DL, 5, 1, 0,
+ abe_get_mixer, dl2_put_mixer),
+ SOC_SINGLE_EXT("Capture", MIX_DL2_INPUT_MM_UL2, 6, 1, 0,
+ abe_get_mixer, dl2_put_mixer),
+ SOC_SINGLE_EXT("Multimedia", MIX_DL2_INPUT_MM_DL, 7, 1, 0,
+ abe_get_mixer, dl2_put_mixer),
+};
+
+/* AUDUL ("Voice Capture Mixer") mixer paths */
+static const struct snd_kcontrol_new audio_ul_mixer_controls[] = {
+ SOC_SINGLE_EXT("Tones Playback", MIX_AUDUL_INPUT_TONES, 8, 1, 0,
+ abe_get_mixer, audio_ul_put_mixer),
+ SOC_SINGLE_EXT("Media Playback", MIX_AUDUL_INPUT_MM_DL, 9, 1, 0,
+ abe_get_mixer, audio_ul_put_mixer),
+ SOC_SINGLE_EXT("Capture", MIX_AUDUL_INPUT_UPLINK, 10, 1, 0,
+ abe_get_mixer, audio_ul_put_mixer),
+};
+
+/* VXREC ("Capture Mixer") mixer paths */
+static const struct snd_kcontrol_new vx_rec_mixer_controls[] = {
+ SOC_SINGLE_EXT("Tones", MIX_VXREC_INPUT_TONES, 11, 1, 0,
+ abe_get_mixer, vxrec_put_mixer),
+ SOC_SINGLE_EXT("Voice Playback", MIX_VXREC_INPUT_VX_DL, 12, 1, 0,
+ abe_get_mixer, vxrec_put_mixer),
+ SOC_SINGLE_EXT("Voice Capture", MIX_VXREC_INPUT_VX_UL, 13, 1, 0,
+ abe_get_mixer, vxrec_put_mixer),
+ SOC_SINGLE_EXT("Media Playback", MIX_VXREC_INPUT_MM_DL, 14, 1, 0,
+ abe_get_mixer, vxrec_put_mixer),
+};
+
+/* SDT ("Sidetone Mixer") mixer paths */
+static const struct snd_kcontrol_new sdt_mixer_controls[] = {
+ SOC_SINGLE_EXT("Capture", MIX_SDT_INPUT_UP_MIXER, 15, 1, 0,
+ abe_get_mixer, sdt_put_mixer),
+ SOC_SINGLE_EXT("Playback", MIX_SDT_INPUT_DL1_MIXER, 16, 1, 0,
+ abe_get_mixer, sdt_put_mixer),
+};
+
+/* Virtual PDM_DL Switch */
+static const struct snd_kcontrol_new pdm_dl1_switch_controls =
+ SOC_SINGLE_EXT("Switch", VIRT_SWITCH, 17, 1, 0,
+ abe_get_mixer, abe_put_switch);
+
+/* Virtual BT_VX_DL Switch */
+static const struct snd_kcontrol_new bt_vx_dl_switch_controls =
+ SOC_SINGLE_EXT("Switch", VIRT_SWITCH, 18, 1, 0,
+ abe_get_mixer, abe_put_switch);
+
+/* Virtual MM_EXT_DL Switch */
+static const struct snd_kcontrol_new mm_ext_dl_switch_controls =
+ SOC_SINGLE_EXT("Switch", VIRT_SWITCH, 19, 1, 0,
+ abe_get_mixer, abe_put_switch);
+
+/* Virtual MM_EXT_UL Switch */
+static const struct snd_kcontrol_new mm_ext_ul_switch_controls =
+ SOC_SINGLE_EXT("Switch", VIRT_SWITCH, 20, 1, 0,
+ abe_get_mixer, abe_put_switch);
+
+/* Virtual PDM_UL Switch */
+static const struct snd_kcontrol_new pdm_ul1_switch_controls =
+ SOC_SINGLE_EXT("Switch", VIRT_SWITCH, 21, 1, 0,
+ abe_get_mixer, abe_put_switch);
+
+static const struct snd_kcontrol_new abe_controls[] = {
+ /* DL1 mixer gains */
+ SOC_SINGLE_EXT_TLV("DL1 Media Playback Volume",
+ MIX_DL1_INPUT_MM_DL, 0, 149, 0,
+ volume_get_dl1_mixer, volume_put_dl1_mixer, mm_dl1_tlv),
+ SOC_SINGLE_EXT_TLV("DL1 Tones Playback Volume",
+ MIX_DL1_INPUT_TONES, 0, 149, 0,
+ volume_get_dl1_mixer, volume_put_dl1_mixer, tones_dl1_tlv),
+ SOC_SINGLE_EXT_TLV("DL1 Voice Playback Volume",
+ MIX_DL1_INPUT_VX_DL, 0, 149, 0,
+ volume_get_dl1_mixer, volume_put_dl1_mixer, voice_dl1_tlv),
+ SOC_SINGLE_EXT_TLV("DL1 Capture Playback Volume",
+ MIX_DL1_INPUT_MM_UL2, 0, 149, 0,
+ volume_get_dl1_mixer, volume_put_dl1_mixer, capture_dl1_tlv),
+
+ /* DL2 mixer gains */
+ SOC_SINGLE_EXT_TLV("DL2 Media Playback Volume",
+ MIX_DL2_INPUT_MM_DL, 0, 149, 0,
+ volume_get_dl2_mixer, volume_put_dl2_mixer, mm_dl2_tlv),
+ SOC_SINGLE_EXT_TLV("DL2 Tones Playback Volume",
+ MIX_DL2_INPUT_TONES, 0, 149, 0,
+ volume_get_dl2_mixer, volume_put_dl2_mixer, tones_dl2_tlv),
+ SOC_SINGLE_EXT_TLV("DL2 Voice Playback Volume",
+ MIX_DL2_INPUT_VX_DL, 0, 149, 0,
+ volume_get_dl2_mixer, volume_put_dl2_mixer, voice_dl2_tlv),
+ SOC_SINGLE_EXT_TLV("DL2 Capture Playback Volume",
+ MIX_DL2_INPUT_MM_UL2, 0, 149, 0,
+ volume_get_dl2_mixer, volume_put_dl2_mixer, capture_dl2_tlv),
+
+ /* VXREC mixer gains */
+ SOC_SINGLE_EXT_TLV("VXREC Media Volume",
+ MIX_VXREC_INPUT_MM_DL, 0, 149, 0,
+ volume_get_vxrec_mixer, volume_put_vxrec_mixer, vxrec_mm_dl_tlv),
+ SOC_SINGLE_EXT_TLV("VXREC Tones Volume",
+ MIX_VXREC_INPUT_TONES, 0, 149, 0,
+ volume_get_vxrec_mixer, volume_put_vxrec_mixer, vxrec_tones_tlv),
+ SOC_SINGLE_EXT_TLV("VXREC Voice DL Volume",
+ MIX_VXREC_INPUT_VX_UL, 0, 149, 0,
+ volume_get_vxrec_mixer, volume_put_vxrec_mixer, vxrec_vx_dl_tlv),
+ SOC_SINGLE_EXT_TLV("VXREC Voice UL Volume",
+ MIX_VXREC_INPUT_VX_DL, 0, 149, 0,
+ volume_get_vxrec_mixer, volume_put_vxrec_mixer, vxrec_vx_ul_tlv),
+
+ /* AUDUL mixer gains */
+ SOC_SINGLE_EXT_TLV("AUDUL Media Volume",
+ MIX_AUDUL_INPUT_MM_DL, 0, 149, 0,
+ volume_get_audul_mixer, volume_put_audul_mixer, audul_mm_tlv),
+ SOC_SINGLE_EXT_TLV("AUDUL Tones Volume",
+ MIX_AUDUL_INPUT_TONES, 0, 149, 0,
+ volume_get_audul_mixer, volume_put_audul_mixer, audul_tones_tlv),
+ SOC_SINGLE_EXT_TLV("AUDUL Voice UL Volume",
+ MIX_AUDUL_INPUT_UPLINK, 0, 149, 0,
+ volume_get_audul_mixer, volume_put_audul_mixer, audul_vx_ul_tlv),
+ SOC_SINGLE_EXT_TLV("AUDUL Voice DL Volume",
+ MIX_AUDUL_INPUT_VX_DL, 0, 149, 0,
+ volume_get_audul_mixer, volume_put_audul_mixer, audul_vx_dl_tlv),
+
+ /* SDT mixer gains */
+ SOC_SINGLE_EXT_TLV("SDT UL Volume",
+ MIX_SDT_INPUT_UP_MIXER, 0, 149, 0,
+ volume_get_sdt_mixer, volume_put_sdt_mixer, sdt_ul_tlv),
+ SOC_SINGLE_EXT_TLV("SDT DL Volume",
+ MIX_SDT_INPUT_DL1_MIXER, 0, 149, 0,
+ volume_get_sdt_mixer, volume_put_sdt_mixer, sdt_dl_tlv),
+
+ /* DMIC gains */
+ SOC_DOUBLE_EXT_TLV("DMIC1 UL Volume",
+ GAINS_DMIC1, GAIN_LEFT_OFFSET, GAIN_RIGHT_OFFSET, 149, 0,
+ volume_get_dmic, volume_put_dmic, dmic_tlv),
+
+ SOC_DOUBLE_EXT_TLV("DMIC2 UL Volume",
+ GAINS_DMIC2, GAIN_LEFT_OFFSET, GAIN_RIGHT_OFFSET, 149, 0,
+ volume_get_dmic, volume_put_dmic, dmic_tlv),
+
+ SOC_DOUBLE_EXT_TLV("DMIC3 UL Volume",
+ GAINS_DMIC3, GAIN_LEFT_OFFSET, GAIN_RIGHT_OFFSET, 149, 0,
+ volume_get_dmic, volume_put_dmic, dmic_tlv),
+
+ SOC_ENUM_EXT("DL1 Equalizer",
+ dl1_equalizer_enum ,
+ abe_get_equalizer, abe_put_equalizer),
+
+ SOC_ENUM_EXT("DL2 Left Equalizer",
+ dl20_equalizer_enum ,
+ abe_get_equalizer, abe_put_equalizer),
+
+ SOC_ENUM_EXT("DL2 Right Equalizer",
+ dl21_equalizer_enum ,
+ abe_get_equalizer, abe_put_equalizer),
+
+ SOC_ENUM_EXT("AMIC Equalizer",
+ amic_equalizer_enum ,
+ abe_get_equalizer, abe_put_equalizer),
+
+ SOC_ENUM_EXT("DMIC Equalizer",
+ dmic_equalizer_enum ,
+ abe_get_equalizer, abe_put_equalizer),
+
+ SOC_ENUM_EXT("Sidetone Equalizer",
+ sdt_equalizer_enum ,
+ abe_get_equalizer, abe_put_equalizer),
+};
+
+static const struct snd_soc_dapm_widget abe_dapm_widgets[] = {
+
+ /* Frontend AIFs */
+ SND_SOC_DAPM_AIF_IN("TONES_DL", "Tones Playback", 0,
+ ABE_WIDGET(0), ABE_OPP_25, 0),
+ SND_SOC_DAPM_AIF_IN("VX_DL", "Voice Playback", 0,
+ ABE_WIDGET(1), ABE_OPP_50, 0),
+ SND_SOC_DAPM_AIF_OUT("VX_UL", "Voice Capture", 0,
+ ABE_WIDGET(2), ABE_OPP_50, 0),
+ /* the MM_UL mapping is intentional */
+ SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0,
+ ABE_WIDGET(3), ABE_OPP_100, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0,
+ ABE_WIDGET(4), ABE_OPP_50, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL", " MultiMedia1 Playback", 0,
+ ABE_WIDGET(5), ABE_OPP_25, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL_LP", " MultiMedia1 LP Playback", 0,
+ ABE_WIDGET(5), ABE_OPP_25, 0),
+ SND_SOC_DAPM_AIF_IN("VIB_DL", "Vibra Playback", 0,
+ ABE_WIDGET(6), ABE_OPP_100, 0),
+ SND_SOC_DAPM_AIF_IN("MODEM_DL", "MODEM Playback", 0,
+ ABE_WIDGET(7), ABE_OPP_50, 0),
+ SND_SOC_DAPM_AIF_OUT("MODEM_UL", "MODEM Capture", 0,
+ ABE_WIDGET(8), ABE_OPP_50, 0),
+
+ /* Backend DAIs */
+ // FIXME: must match BE order in abe_dai.h
+ SND_SOC_DAPM_AIF_IN("PDM_UL1", "Analog Capture", 0,
+ ABE_WIDGET(9), ABE_OPP_50, 0),
+ SND_SOC_DAPM_AIF_OUT("PDM_DL1", "HS Playback", 0,
+ ABE_WIDGET(10), ABE_OPP_25, 0),
+ SND_SOC_DAPM_AIF_OUT("PDM_DL2", "HF Playback", 0,
+ ABE_WIDGET(11), ABE_OPP_100, 0),
+ SND_SOC_DAPM_AIF_OUT("PDM_VIB", "Vibra Playback", 0,
+ ABE_WIDGET(12), ABE_OPP_100, 0),
+ SND_SOC_DAPM_AIF_IN("BT_VX_UL", "BT Capture", 0,
+ ABE_WIDGET(13), ABE_OPP_50, 0),
+ SND_SOC_DAPM_AIF_OUT("BT_VX_DL", "BT Playback", 0,
+ ABE_WIDGET(14), ABE_OPP_50, 0),
+ SND_SOC_DAPM_AIF_IN("MM_EXT_UL", "FM Capture", 0,
+ ABE_WIDGET(15), ABE_OPP_50, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_EXT_DL", "FM Playback", 0,
+ ABE_WIDGET(16), ABE_OPP_25, 0),
+ SND_SOC_DAPM_AIF_IN("DMIC0", "DMIC0 Capture", 0,
+ ABE_WIDGET(17), ABE_OPP_50, 0),
+ SND_SOC_DAPM_AIF_IN("DMIC1", "DMIC1 Capture", 0,
+ ABE_WIDGET(18), ABE_OPP_50, 0),
+ SND_SOC_DAPM_AIF_IN("DMIC2", "DMIC2 Capture", 0,
+ ABE_WIDGET(19), ABE_OPP_50, 0),
+
+ /* ROUTE_UL Capture Muxes */
+ SND_SOC_DAPM_MUX("MUX_UL00",
+ ABE_WIDGET(20), ABE_OPP_50, 0, &mm_ul00_control),
+ SND_SOC_DAPM_MUX("MUX_UL01",
+ ABE_WIDGET(21), ABE_OPP_50, 0, &mm_ul01_control),
+ SND_SOC_DAPM_MUX("MUX_UL02",
+ ABE_WIDGET(22), ABE_OPP_50, 0, &mm_ul02_control),
+ SND_SOC_DAPM_MUX("MUX_UL03",
+ ABE_WIDGET(23), ABE_OPP_50, 0, &mm_ul03_control),
+ SND_SOC_DAPM_MUX("MUX_UL04",
+ ABE_WIDGET(24), ABE_OPP_50, 0, &mm_ul04_control),
+ SND_SOC_DAPM_MUX("MUX_UL05",
+ ABE_WIDGET(25), ABE_OPP_50, 0, &mm_ul05_control),
+ SND_SOC_DAPM_MUX("MUX_UL06",
+ ABE_WIDGET(26), ABE_OPP_50, 0, &mm_ul06_control),
+ SND_SOC_DAPM_MUX("MUX_UL07",
+ ABE_WIDGET(27), ABE_OPP_50, 0, &mm_ul07_control),
+ SND_SOC_DAPM_MUX("MUX_UL10",
+ ABE_WIDGET(28), ABE_OPP_50, 0, &mm_ul10_control),
+ SND_SOC_DAPM_MUX("MUX_UL11",
+ ABE_WIDGET(29), ABE_OPP_50, 0, &mm_ul11_control),
+ SND_SOC_DAPM_MUX("MUX_VX0",
+ ABE_WIDGET(30), ABE_OPP_50, 0, &mm_vx0_control),
+ SND_SOC_DAPM_MUX("MUX_VX1",
+ ABE_WIDGET(31), ABE_OPP_50, 0, &mm_vx1_control),
+
+ /* DL1 & DL2 Playback Mixers */
+ SND_SOC_DAPM_MIXER("DL1 Mixer",
+ ABE_WIDGET(32), ABE_OPP_25, 0, dl1_mixer_controls,
+ ARRAY_SIZE(dl1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("DL2 Mixer",
+ ABE_WIDGET(33), ABE_OPP_100, 0, dl2_mixer_controls,
+ ARRAY_SIZE(dl2_mixer_controls)),
+
+ /* DL1 Mixer Input volumes ?????*/
+ SND_SOC_DAPM_PGA("DL1 Media Volume",
+ ABE_WIDGET(34), 0, 0, NULL, 0),
+
+ /* AUDIO_UL_MIXER */
+ SND_SOC_DAPM_MIXER("Voice Capture Mixer",
+ ABE_WIDGET(35), ABE_OPP_50, 0, audio_ul_mixer_controls,
+ ARRAY_SIZE(audio_ul_mixer_controls)),
+
+ /* VX_REC_MIXER */
+ SND_SOC_DAPM_MIXER("Capture Mixer",
+ ABE_WIDGET(36), ABE_OPP_50, 0, vx_rec_mixer_controls,
+ ARRAY_SIZE(vx_rec_mixer_controls)),
+
+ /* SDT_MIXER */
+ SND_SOC_DAPM_MIXER("Sidetone Mixer",
+ ABE_WIDGET(37), ABE_OPP_25, 0, sdt_mixer_controls,
+ ARRAY_SIZE(sdt_mixer_controls)),
+
+ /*
+ * The Following three are virtual switches to select the output port
+ * after DL1 Gain - HAL V0.6x
+ */
+
+ /* Virtual PDM_DL1 Switch */
+ SND_SOC_DAPM_MIXER("DL1 PDM",
+ ABE_WIDGET(38), ABE_OPP_25, 0, &pdm_dl1_switch_controls, 1),
+
+ /* Virtual BT_VX_DL Switch */
+ SND_SOC_DAPM_MIXER("DL1 BT_VX",
+ ABE_WIDGET(39), ABE_OPP_50, 0, &bt_vx_dl_switch_controls, 1),
+
+ /* Virtual MM_EXT_DL Switch TODO: confrm OPP level here */
+ SND_SOC_DAPM_MIXER("DL1 MM_EXT",
+ ABE_WIDGET(40), ABE_OPP_50, 0, &mm_ext_dl_switch_controls, 1),
+
+ /*
+ * The Following three are virtual switches to select the input port
+ * before AMIC_UL enters ROUTE_UL - HAL V0.6x
+ */
+
+ /* Virtual MM_EXT_UL Switch */
+ SND_SOC_DAPM_MIXER("AMIC_UL MM_EXT",
+ ABE_WIDGET(41), ABE_OPP_50, 0, &mm_ext_ul_switch_controls, 1),
+
+ /* Virtual PDM_UL1 Switch */
+ SND_SOC_DAPM_MIXER("AMIC_UL PDM",
+ ABE_WIDGET(42), ABE_OPP_50, 0, &pdm_ul1_switch_controls, 1),
+
+ /* Virtual to join MM_EXT and PDM+UL1 switches */
+ SND_SOC_DAPM_MIXER("AMIC_UL", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Virtuals to join our capture sources */
+ SND_SOC_DAPM_MIXER("Sidetone Capture VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Voice Capture VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("DL1 Capture VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("DL2 Capture VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Join our MM_DL and MM_DL_LP playback */
+ SND_SOC_DAPM_MIXER("MM_DL VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Virtual MODEM and VX_UL mixer */
+ SND_SOC_DAPM_MIXER("VX UL VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("VX DL VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Virtual Pins to force backends ON atm */
+ SND_SOC_DAPM_OUTPUT("BE_OUT"),
+ SND_SOC_DAPM_INPUT("BE_IN"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+
+ /* MUX_UL00 - ROUTE_UL - Chan 0 */
+ {"MUX_UL00", "DMic0L", "DMIC0"},
+ {"MUX_UL00", "DMic0R", "DMIC0"},
+ {"MUX_UL00", "DMic1L", "DMIC1"},
+ {"MUX_UL00", "DMic1R", "DMIC1"},
+ {"MUX_UL00", "DMic2L", "DMIC2"},
+ {"MUX_UL00", "DMic2R", "DMIC2"},
+ {"MUX_UL00", "BT Left", "BT_VX_UL"},
+ {"MUX_UL00", "BT Right", "BT_VX_UL"},
+ {"MUX_UL00", "AMic0", "AMIC_UL"},
+ {"MUX_UL00", "AMic1", "AMIC_UL"},
+ {"MUX_UL00", "VX Left", "Capture Mixer"},
+ {"MUX_UL00", "VX Right", "Capture Mixer"},
+ {"MM_UL1", NULL, "MUX_UL00"},
+
+ /* MUX_UL01 - ROUTE_UL - Chan 1 */
+ {"MUX_UL01", "DMic0L", "DMIC0"},
+ {"MUX_UL01", "DMic0R", "DMIC0"},
+ {"MUX_UL01", "DMic1L", "DMIC1"},
+ {"MUX_UL01", "DMic1R", "DMIC1"},
+ {"MUX_UL01", "DMic2L", "DMIC2"},
+ {"MUX_UL01", "DMic2R", "DMIC2"},
+ {"MUX_UL01", "BT Left", "BT_VX_UL"},
+ {"MUX_UL01", "BT Right", "BT_VX_UL"},
+ {"MUX_UL01", "AMic0", "AMIC_UL"},
+ {"MUX_UL01", "AMic1", "AMIC_UL"},
+ {"MUX_UL01", "VX Left", "Capture Mixer"},
+ {"MUX_UL01", "VX Right", "Capture Mixer"},
+ {"MM_UL1", NULL, "MUX_UL01"},
+
+ /* MUX_UL02 - ROUTE_UL - Chan 2 */
+ {"MUX_UL02", "DMic0L", "DMIC0"},
+ {"MUX_UL02", "DMic0R", "DMIC0"},
+ {"MUX_UL02", "DMic1L", "DMIC1"},
+ {"MUX_UL02", "DMic1R", "DMIC1"},
+ {"MUX_UL02", "DMic2L", "DMIC2"},
+ {"MUX_UL02", "DMic2R", "DMIC2"},
+ {"MUX_UL02", "BT Left", "BT_VX_UL"},
+ {"MUX_UL02", "BT Right", "BT_VX_UL"},
+ {"MUX_UL02", "AMic0", "AMIC_UL"},
+ {"MUX_UL02", "AMic1", "AMIC_UL"},
+ {"MUX_UL02", "VX Left", "Capture Mixer"},
+ {"MUX_UL02", "VX Right", "Capture Mixer"},
+ {"MM_UL1", NULL, "MUX_UL02"},
+
+ /* MUX_UL03 - ROUTE_UL - Chan 3 */
+ {"MUX_UL03", "DMic0L", "DMIC0"},
+ {"MUX_UL03", "DMic0R", "DMIC0"},
+ {"MUX_UL03", "DMic1L", "DMIC1"},
+ {"MUX_UL03", "DMic1R", "DMIC1"},
+ {"MUX_UL03", "DMic2L", "DMIC2"},
+ {"MUX_UL03", "DMic2R", "DMIC2"},
+ {"MUX_UL03", "BT Left", "BT_VX_UL"},
+ {"MUX_UL03", "BT Right", "BT_VX_UL"},
+ {"MUX_UL03", "AMic0", "AMIC_UL"},
+ {"MUX_UL03", "AMic1", "AMIC_UL"},
+ {"MUX_UL03", "VX Left", "Capture Mixer"},
+ {"MUX_UL03", "VX Right", "Capture Mixer"},
+ {"MM_UL1", NULL, "MUX_UL03"},
+
+ /* MUX_UL04 - ROUTE_UL - Chan 4 */
+ {"MUX_UL04", "DMic0L", "DMIC0"},
+ {"MUX_UL04", "DMic0R", "DMIC0"},
+ {"MUX_UL04", "DMic1L", "DMIC1"},
+ {"MUX_UL04", "DMic1R", "DMIC1"},
+ {"MUX_UL04", "DMic2L", "DMIC2"},
+ {"MUX_UL04", "DMic2R", "DMIC2"},
+ {"MUX_UL04", "BT Left", "BT_VX_UL"},
+ {"MUX_UL04", "BT Right", "BT_VX_UL"},
+ {"MUX_UL04", "AMic0", "AMIC_UL"},
+ {"MUX_UL04", "AMic1", "AMIC_UL"},
+ {"MUX_UL04", "VX Left", "Capture Mixer"},
+ {"MUX_UL04", "VX Right", "Capture Mixer"},
+ {"MM_UL1", NULL, "MUX_UL04"},
+
+ /* MUX_UL05 - ROUTE_UL - Chan 5 */
+ {"MUX_UL05", "DMic0L", "DMIC0"},
+ {"MUX_UL05", "DMic0R", "DMIC0"},
+ {"MUX_UL05", "DMic1L", "DMIC1"},
+ {"MUX_UL05", "DMic1R", "DMIC1"},
+ {"MUX_UL05", "DMic2L", "DMIC2"},
+ {"MUX_UL05", "DMic2R", "DMIC2"},
+ {"MUX_UL05", "BT Left", "BT_VX_UL"},
+ {"MUX_UL05", "BT Right", "BT_VX_UL"},
+ {"MUX_UL05", "AMic0", "AMIC_UL"},
+ {"MUX_UL05", "AMic1", "AMIC_UL"},
+ {"MUX_UL05", "VX Left", "Capture Mixer"},
+ {"MUX_UL05", "VX Right", "Capture Mixer"},
+ {"MM_UL1", NULL, "MUX_UL05"},
+
+ /* MUX_UL06 - ROUTE_UL - Chan 6 */
+ {"MUX_UL06", "DMic0L", "DMIC0"},
+ {"MUX_UL06", "DMic0R", "DMIC0"},
+ {"MUX_UL06", "DMic1L", "DMIC1"},
+ {"MUX_UL06", "DMic1R", "DMIC1"},
+ {"MUX_UL06", "DMic2L", "DMIC2"},
+ {"MUX_UL06", "DMic2R", "DMIC2"},
+ {"MUX_UL06", "BT Left", "BT_VX_UL"},
+ {"MUX_UL06", "BT Right", "BT_VX_UL"},
+ {"MUX_UL06", "AMic0", "AMIC_UL"},
+ {"MUX_UL06", "AMic1", "AMIC_UL"},
+ {"MUX_UL06", "VX Left", "Capture Mixer"},
+ {"MUX_UL06", "VX Right", "Capture Mixer"},
+ {"MM_UL1", NULL, "MUX_UL06"},
+
+ /* MUX_UL07 - ROUTE_UL - Chan 7 */
+ {"MUX_UL07", "DMic0L", "DMIC0"},
+ {"MUX_UL07", "DMic0R", "DMIC0"},
+ {"MUX_UL07", "DMic1L", "DMIC1"},
+ {"MUX_UL07", "DMic1R", "DMIC1"},
+ {"MUX_UL07", "DMic2L", "DMIC2"},
+ {"MUX_UL07", "DMic2R", "DMIC2"},
+ {"MUX_UL07", "BT Left", "BT_VX_UL"},
+ {"MUX_UL07", "BT Right", "BT_VX_UL"},
+ {"MUX_UL07", "AMic0", "AMIC_UL"},
+ {"MUX_UL07", "AMic1", "AMIC_UL"},
+ {"MUX_UL07", "VX Left", "Capture Mixer"},
+ {"MUX_UL07", "VX Right", "Capture Mixer"},
+ {"MM_UL1", NULL, "MUX_UL07"},
+
+ /* MUX_UL10 - ROUTE_UL - Chan 10 */
+ {"MUX_UL10", "DMic0L", "DMIC0"},
+ {"MUX_UL10", "DMic0R", "DMIC0"},
+ {"MUX_UL10", "DMic1L", "DMIC1"},
+ {"MUX_UL10", "DMic1R", "DMIC1"},
+ {"MUX_UL10", "DMic2L", "DMIC2"},
+ {"MUX_UL10", "DMic2R", "DMIC2"},
+ {"MUX_UL10", "BT Left", "BT_VX_UL"},
+ {"MUX_UL10", "BT Right", "BT_VX_UL"},
+ {"MUX_UL10", "AMic0", "AMIC_UL"},
+ {"MUX_UL10", "AMic1", "AMIC_UL"},
+ {"MUX_UL10", "VX Left", "Capture Mixer"},
+ {"MUX_UL10", "VX Right", "Capture Mixer"},
+ {"MM_UL2", NULL, "MUX_UL10"},
+
+ /* MUX_UL11 - ROUTE_UL - Chan 11 */
+ {"MUX_UL11", "DMic0L", "DMIC0"},
+ {"MUX_UL11", "DMic0R", "DMIC0"},
+ {"MUX_UL11", "DMic1L", "DMIC1"},
+ {"MUX_UL11", "DMic1R", "DMIC1"},
+ {"MUX_UL11", "DMic2L", "DMIC2"},
+ {"MUX_UL11", "DMic2R", "DMIC2"},
+ {"MUX_UL11", "BT Left", "BT_VX_UL"},
+ {"MUX_UL11", "BT Right", "BT_VX_UL"},
+ {"MUX_UL11", "AMic0", "AMIC_UL"},
+ {"MUX_UL11", "AMic1", "AMIC_UL"},
+ {"MUX_UL11", "VX Left", "Capture Mixer"},
+ {"MUX_UL11", "VX Right", "Capture Mixer"},
+ {"MM_UL2", NULL, "MUX_UL11"},
+
+ /* MUX_VX0 - ROUTE_UL - Chan 20 */
+ {"MUX_VX0", "DMic0L", "DMIC0"},
+ {"MUX_VX0", "DMic0R", "DMIC0"},
+ {"MUX_VX0", "DMic1L", "DMIC1"},
+ {"MUX_VX0", "DMic1R", "DMIC1"},
+ {"MUX_VX0", "DMic2L", "DMIC2"},
+ {"MUX_VX0", "DMic2R", "DMIC2"},
+ {"MUX_VX0", "BT Left", "BT_VX_UL"},
+ {"MUX_VX0", "BT Right", "BT_VX_UL"},
+ {"MUX_VX0", "AMic0", "AMIC_UL"},
+ {"MUX_VX0", "AMic1", "AMIC_UL"},
+ {"MUX_VX0", "VX Left", "Capture Mixer"},
+ {"MUX_VX0", "VX Right", "Capture Mixer"},
+
+ /* MUX_VX1 - ROUTE_UL - Chan 20 */
+ {"MUX_VX1", "DMic0L", "DMIC0"},
+ {"MUX_VX1", "DMic0R", "DMIC0"},
+ {"MUX_VX1", "DMic1L", "DMIC1"},
+ {"MUX_VX1", "DMic1R", "DMIC1"},
+ {"MUX_VX1", "DMic2L", "DMIC2"},
+ {"MUX_VX1", "DMic2R", "DMIC2"},
+ {"MUX_VX1", "BT Left", "BT_VX_UL"},
+ {"MUX_VX1", "BT Right", "BT_VX_UL"},
+ {"MUX_VX1", "AMic0", "AMIC_UL"},
+ {"MUX_VX1", "AMic1", "AMIC_UL"},
+ {"MUX_VX1", "VX Left", "Capture Mixer"},
+ {"MUX_VX1", "VX Right", "Capture Mixer"},
+
+ /* Capture Input Selection for AMIC_UL */
+ {"AMIC_UL MM_EXT", "Switch", "MM_EXT_UL"},
+ {"AMIC_UL PDM", "Switch", "PDM_UL1"},
+ {"AMIC_UL", NULL, "AMIC_UL MM_EXT"},
+ {"AMIC_UL", NULL, "AMIC_UL PDM"},
+
+ /* Headset (DL1) playback path */
+ {"DL1 Mixer", "Tones", "TONES_DL"},
+ {"DL1 Mixer", "Voice", "VX DL VMixer"},
+ {"DL1 Mixer", "Capture", "DL1 Capture VMixer"},
+ {"DL1 Capture VMixer", NULL, "MUX_UL10"},
+ {"DL1 Capture VMixer", NULL, "MUX_UL11"},
+ {"DL1 Mixer", "Multimedia", "MM_DL VMixer"},
+ {"MM_DL VMixer", NULL, "MM_DL"},
+ {"MM_DL VMixer", NULL, "MM_DL_LP"},
+
+ /* Sidetone Mixer */
+ {"Sidetone Mixer", "Playback", "DL1 Mixer"},
+ {"Sidetone Mixer", "Capture", "Sidetone Capture VMixer"},
+ {"Sidetone Capture VMixer", NULL, "MUX_VX0"},
+ {"Sidetone Capture VMixer", NULL, "MUX_VX1"},
+
+ /* Playback Output selection after DL1 Gain */
+ {"DL1 BT_VX", "Switch", "Sidetone Mixer"},
+ {"DL1 MM_EXT", "Switch", "Sidetone Mixer"},
+ {"DL1 PDM", "Switch", "Sidetone Mixer"},
+ {"PDM_DL1", NULL, "DL1 PDM"},
+ {"BT_VX_DL", NULL, "DL1 BT_VX"},
+ {"MM_EXT_DL", NULL, "DL1 MM_EXT"},
+
+ /* Handsfree (DL2) playback path */
+ {"DL2 Mixer", "Tones", "TONES_DL"},
+ {"DL2 Mixer", "Voice", "VX DL VMixer"},
+ {"DL2 Mixer", "Capture", "DL2 Capture VMixer"},
+ {"DL2 Capture VMixer", NULL, "MUX_UL10"},
+ {"DL2 Capture VMixer", NULL, "MUX_UL11"},
+ {"DL2 Mixer", "Multimedia", "MM_DL VMixer"},
+ {"MM_DL VMixer", NULL, "MM_DL"},
+ {"MM_DL VMixer", NULL, "MM_DL_LP"},
+ {"PDM_DL2", NULL, "DL2 Mixer"},
+
+ /* VxREC Mixer */
+ {"Capture Mixer", "Tones", "TONES_DL"},
+ {"Capture Mixer", "Voice Playback", "VX DL VMixer"},
+ {"Capture Mixer", "Voice Capture", "VX UL VMixer"},
+ {"Capture Mixer", "Media Playback", "MM_DL VMixer"},
+ {"MM_DL VMixer", NULL, "MM_DL"},
+ {"MM_DL VMixer", NULL, "MM_DL_LP"},
+
+ /* Audio UL mixer */
+ {"Voice Capture Mixer", "Tones Playback", "TONES_DL"},
+ {"Voice Capture Mixer", "Media Playback", "MM_DL VMixer"},
+ {"MM_DL VMixer", NULL, "MM_DL"},
+ {"MM_DL VMixer", NULL, "MM_DL_LP"},
+ {"Voice Capture Mixer", "Capture", "Voice Capture VMixer"},
+ {"Voice Capture VMixer", NULL, "MUX_VX0"},
+ {"Voice Capture VMixer", NULL, "MUX_VX1"},
+
+ /* BT */
+ {"VX UL VMixer", NULL, "Voice Capture Mixer"},
+
+ /* Vibra */
+ {"PDM_VIB", NULL, "VIB_DL"},
+
+ /* VX and MODEM */
+ {"VX_UL", NULL, "VX UL VMixer"},
+ {"MODEM_UL", NULL, "VX UL VMixer"},
+ {"VX DL VMixer", NULL, "VX_DL"},
+ {"VX DL VMixer", NULL, "MODEM_DL"},
+
+ /* Backend Enablement - TODO: maybe re-work*/
+ {"BE_OUT", NULL, "PDM_DL1"},
+ {"BE_OUT", NULL, "PDM_DL2"},
+ {"BE_OUT", NULL, "PDM_VIB"},
+ {"BE_OUT", NULL, "MM_EXT_DL"},
+ {"BE_OUT", NULL, "BT_VX_DL"},
+ {"PDM_UL1", NULL, "BE_IN"},
+ {"BT_VX_UL", NULL, "BE_IN"},
+ {"MM_EXT_UL", NULL, "BE_IN"},
+ {"DMIC0", NULL, "BE_IN"},
+ {"DMIC1", NULL, "BE_IN"},
+ {"DMIC2", NULL, "BE_IN"},
+};
+
+static int abe_add_widgets(struct snd_soc_platform *platform)
+{
+ snd_soc_add_platform_controls(platform, abe_controls,
+ ARRAY_SIZE(abe_controls));
+
+ snd_soc_dapm_new_controls(&platform->dapm, abe_dapm_widgets,
+ ARRAY_SIZE(abe_dapm_widgets));
+
+ snd_soc_dapm_add_routes(&platform->dapm, intercon, ARRAY_SIZE(intercon));
+
+ snd_soc_dapm_new_widgets(&platform->dapm);
+
+ return 0;
+}
+
+static int aess_set_opp_mode(void)
+{
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+ int i, opp = 0;
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ mutex_lock(&abe->opp_mutex);
+
+ /* now calculate OPP level based upon DAPM widget status */
+ for (i = ABE_WIDGET_START; i < ABE_WIDGET_END; i++)
+ opp |= abe->dapm[i];
+
+ opp = (1 << (fls(opp) - 1)) * 25;
+
+ if (abe->opp > opp) {
+ /* Decrease OPP mode - no need of OPP100% */
+ switch (opp) {
+ case 25:
+ abe_set_opp_processing(ABE_OPP25);
+ udelay(250);
+ /* FIXME: Dependency on PM framework */
+ //omap_device_set_rate(&pdev->dev, &pdev->dev, 98000000);
+ break;
+ case 50:
+ default:
+ abe_set_opp_processing(ABE_OPP50);
+ udelay(250);
+ /* FIXME: Dependency on PM framework */
+ //omap_device_set_rate(&pdev->dev, &pdev->dev, 98000000);
+ break;
+ }
+ } else if (abe->opp < opp) {
+ /* Increase OPP mode */
+ switch (opp) {
+ case 25:
+ /* FIXME: Dependency on PM framework */
+ //omap_device_set_rate(&pdev->dev, &pdev->dev, 98000000);
+ abe_set_opp_processing(ABE_OPP25);
+ break;
+ case 50:
+ /* FIXME: Dependency on PM framework */
+ //omap_device_set_rate(&pdev->dev, &pdev->dev, 98000000);
+ abe_set_opp_processing(ABE_OPP50);
+ break;
+ case 100:
+ default:
+ /* FIXME: Dependency on PM framework */
+ //omap_device_set_rate(&pdev->dev, &pdev->dev, 196000000);
+ abe_set_opp_processing(ABE_OPP100);
+ break;
+ }
+ }
+ abe->opp = opp;
+
+ mutex_unlock(&abe->opp_mutex);
+
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 0;
+}
+
+static int abe_probe(struct snd_soc_platform *platform)
+{
+ abe_init_engine(platform);
+ abe_add_widgets(platform);
+ abe->platform = platform;
+ return 0;
+}
+
+static int abe_remove(struct snd_soc_platform *platform)
+{
+ return 0;
+}
+
+static int aess_save_context(struct abe_data *abe)
+{
+ struct platform_device *pdev = abe->pdev;
+ struct omap4_abe_dsp_pdata *pdata = pdev->dev.platform_data;
+
+ /* TODO: Find a better way to save/retore gains after OFF mode */
+ abe_mute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER);
+ abe_mute_gain(MIXSDT, MIX_SDT_INPUT_DL1_MIXER);
+ abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_MM_DL);
+ abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_TONES);
+ abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_UPLINK);
+ abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_VX_DL);
+ abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_TONES);
+ abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_DL);
+ abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_MM_DL);
+ abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_UL);
+ abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL);
+ abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_UL2);
+ abe_mute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL);
+ abe_mute_gain(MIXDL1, MIX_DL1_INPUT_TONES);
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_TONES);
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL);
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL);
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_UL2);
+ abe_mute_gain(MIXECHO, MIX_ECHO_DL1);
+ abe_mute_gain(MIXECHO, MIX_ECHO_DL2);
+ abe_mute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET);
+ abe_mute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET);
+ abe_mute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET);
+ abe_mute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET);
+
+ if (pdata->get_context_loss_count)
+ abe->loss_count = pdata->get_context_loss_count(&pdev->dev);
+
+ return 0;
+}
+
+static int aess_restore_context(struct abe_data *abe)
+{
+ struct platform_device *pdev = abe->pdev;
+ struct omap4_abe_dsp_pdata *pdata = pdev->dev.platform_data;
+ int loss_count = 0;
+/* FIXME: Dependency on PM framework */
+// omap_device_set_rate(&pdev->dev, &pdev->dev, 98000000);
+
+ if (pdata->get_context_loss_count)
+ loss_count = pdata->get_context_loss_count(&pdev->dev);
+
+ if (loss_count != abe->loss_count)
+ abe_reload_fw();
+
+ /* TODO: Find a better way to save/retore gains after dor OFF mode */
+ abe_unmute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER);
+ abe_unmute_gain(MIXSDT, MIX_SDT_INPUT_DL1_MIXER);
+ abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_MM_DL);
+ abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_TONES);
+ abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_UPLINK);
+ abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_VX_DL);
+ abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_TONES);
+ abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_DL);
+ abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_MM_DL);
+ abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_UL);
+ abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL);
+ abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_MM_UL2);
+ abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL);
+ abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_TONES);
+ abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_TONES);
+ abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL);
+ abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL);
+ abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_MM_UL2);
+ abe_unmute_gain(MIXECHO, MIX_ECHO_DL1);
+ abe_unmute_gain(MIXECHO, MIX_ECHO_DL2);
+ abe_unmute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET);
+ abe_unmute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET);
+ abe_unmute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET);
+ abe_unmute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET);
+
+ abe_dsp_set_equalizer(EQ1, abe->dl1_equ_profile);
+ abe_dsp_set_equalizer(EQ2L, abe->dl20_equ_profile);
+ abe_dsp_set_equalizer(EQ2R, abe->dl21_equ_profile);
+ abe_dsp_set_equalizer(EQAMIC, abe->amic_equ_profile);
+ abe_dsp_set_equalizer(EQDMIC, abe->dmic_equ_profile);
+ abe_dsp_set_equalizer(EQSDT, abe->sdt_equ_profile);
+
+ abe_set_router_configuration(UPROUTE, 0, (u32 *)abe->router);
+
+ return 0;
+}
+
+static int aess_open(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *dai = rtd->cpu_dai;
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+ int ret = 0;
+
+ mutex_lock(&abe->mutex);
+
+ abe->fe_id = dai->id;
+ dev_dbg(&rtd->dev, "%s ID %d\n", __func__, dai->id);
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ if (!abe->active++) {
+ abe->opp = 0;
+ aess_restore_context(abe);
+ aess_set_opp_mode();
+ abe_wakeup();
+ }
+
+ switch (dai->id) {
+ case ABE_FRONTEND_DAI_MODEM:
+ break;
+ case ABE_FRONTEND_DAI_LP_MEDIA:
+ snd_soc_set_runtime_hwparams(substream, &omap_abe_hardware);
+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 1024);
+ break;
+ default:
+ break;
+ }
+
+ mutex_unlock(&abe->mutex);
+ return ret;
+}
+
+static int abe_ping_pong_init(struct snd_pcm_hw_params *params,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ abe_data_format_t format;
+ size_t period_size;
+ u32 dst;
+
+ /*Storing substream pointer for irq*/
+ abe->psubs = substream;
+
+ format.f = params_rate(params);
+ format.samp_format = STEREO_16_16;
+
+ if (format.f == 44100)
+ abe_write_event_generator(EVENT_44100);
+
+ period_size = params_period_bytes(params);
+
+ /* Adding ping pong buffer subroutine */
+ abe_plug_subroutine(&abe_irq_pingpong_player_id,
+ (abe_subroutine2) abe_irq_pingpong_subroutine,
+ SUB_0_PARAM, (u32 *)0);
+
+ /* Connect a Ping-Pong cache-flush protocol to MM_DL port */
+ abe_connect_irq_ping_pong_port(MM_DL_PORT, &format,
+ abe_irq_pingpong_player_id,
+ period_size, &dst,
+ PING_PONG_WITH_MCU_IRQ);
+
+ /* Memory mapping for hw params */
+ runtime->dma_area = abe->io_base + ABE_DMEM_BASE_OFFSET_MPU + dst;
+ runtime->dma_addr = 0;
+ runtime->dma_bytes = period_size * 2;
+
+ /* Need to set the first buffer in order to get interrupt */
+ abe_set_ping_pong_buffer(MM_DL_PORT, period_size);
+ abe->first_irq = 1;
+
+ return 0;
+}
+
+static int aess_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *dai = rtd->cpu_dai;
+ int ret = 0;
+
+ dev_dbg(&rtd->dev, "%s ID %d\n", __func__, dai->id);
+
+ switch (dai->id) {
+ case ABE_FRONTEND_DAI_MODEM:
+ break;
+ case ABE_FRONTEND_DAI_LP_MEDIA:
+ ret = abe_ping_pong_init(params, substream);
+ if (ret < 0)
+ return ret;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int aess_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+
+ mutex_lock(&abe->mutex);
+
+ dev_dbg(&rtd->dev, "%s ID %d\n", __func__, rtd->cpu_dai->id);
+
+ aess_set_opp_mode();
+
+ mutex_unlock(&abe->mutex);
+ return 0;
+}
+
+static int aess_close(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *dai = rtd->cpu_dai;
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ mutex_lock(&abe->mutex);
+
+ abe->fe_id = dai->id;
+ dev_dbg(&rtd->dev, "%s ID %d\n", __func__, dai->id);
+
+ if (!--abe->active) {
+ abe_disable_irq();
+ aess_save_context(abe);
+ abe_dsp_shutdown();
+ }
+ pm_runtime_put_sync(&pdev->dev);
+
+ mutex_unlock(&abe->mutex);
+ return 0;
+}
+
+static int aess_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ int offset, size, err;
+
+ /* TODO: we may need to check for underrun. */
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ size = vma->vm_end - vma->vm_start;
+ offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ err = io_remap_pfn_range(vma, vma->vm_start,
+ (ABE_DMEM_BASE_ADDRESS_MPU +
+ ABE_DMEM_BASE_OFFSET_PING_PONG + offset) >> PAGE_SHIFT,
+ size, vma->vm_page_prot);
+
+ if (err)
+ return -EAGAIN;
+
+ return 0;
+}
+
+static snd_pcm_uframes_t aess_pointer(struct snd_pcm_substream *substream)
+{
+ snd_pcm_uframes_t offset;
+ u32 pingpong;
+
+ abe_read_offset_from_ping_buffer(MM_DL_PORT, &pingpong);
+ offset = (snd_pcm_uframes_t)pingpong;
+/*
+ if (offset >= runtime->buffer_size)
+ offset = 0;
+*/
+ return offset;
+}
+
+
+static struct snd_pcm_ops omap_aess_pcm_ops = {
+ .open = aess_open,
+ .hw_params = aess_hw_params,
+ .prepare = aess_prepare,
+ .close = aess_close,
+ .pointer = aess_pointer,
+ .mmap = aess_mmap,
+};
+
+static int aess_stream_event(struct snd_soc_dapm_context *dapm)
+{
+ /* TODO: do not use abe global structure to assign pdev */
+ struct platform_device *pdev = abe->pdev;
+
+ if (abe->active) {
+ pm_runtime_get_sync(&pdev->dev);
+ aess_set_opp_mode();
+ pm_runtime_put_sync(&pdev->dev);
+ }
+
+ return 0;
+}
+
+static struct snd_soc_platform_driver omap_aess_platform = {
+ .ops = &omap_aess_pcm_ops,
+ .probe = abe_probe,
+ .remove = abe_remove,
+ .read = abe_dsp_read,
+ .write = abe_dsp_write,
+ .stream_event = aess_stream_event,
+};
+
+/* FIXME: Dependency on PM framework */
+#if 0//
+defined(CONFIG_PM)
+static int omap_pm_abe_get_dev_context_loss_count(struct device *dev)
+{
+
+ int ret;
+
+ ret = prm_read_mod_reg(abe_pwrdm->prcm_offs,
+ abe_pwrdm->context_offset);
+
+ if ((ret & 0x0001) == 0x0001) {
+ prm_write_mod_reg(0x0001, abe_pwrdm->prcm_offs,
+ abe_pwrdm->context_offset);
+ ret &= ~0x0001;
+ }
+
+ if ((ret & 0x0100) == 0x0100)
+ prm_write_mod_reg(0x0100, abe_pwrdm->prcm_offs,
+ abe_pwrdm->context_offset);
+
+ return ret;
+}
+
+#else
+#define omap_pm_abe_get_dev_context_loss_count NULL
+#endif
+
+static int __devinit abe_engine_probe(struct platform_device *pdev)
+{
+ struct omap4_abe_dsp_pdata *pdata = pdev->dev.platform_data;
+ struct resource *res;
+ int ret = -EINVAL, i;
+
+ abe = kzalloc(sizeof(struct abe_data), GFP_KERNEL);
+ if (abe == NULL)
+ return -ENOMEM;
+ dev_set_drvdata(&pdev->dev, abe);
+
+ /* ZERO_labelID should really be 0 */
+ for (i = 0; i < ABE_ROUTES_UL + 2; i++)
+ abe->router[i] = ZERO_labelID;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no resource\n");
+ goto err;
+ }
+
+ abe->io_base = ioremap(res->start, resource_size(res));
+ if (!abe->io_base) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ abe->irq = platform_get_irq(pdev, 0);
+ if (abe->irq < 0) {
+ ret = abe->irq;
+ goto err_irq;
+ }
+
+#if defined(CONFIG_PM)
+ abe_pwrdm = pwrdm_lookup("abe_pwrdm");
+ if (!abe_pwrdm)
+ return -ENODEV;
+
+ pdata->get_context_loss_count = omap_pm_abe_get_dev_context_loss_count;
+#endif
+
+ pm_runtime_enable(&pdev->dev);
+
+ abe->abe_pdata = pdata;
+ abe->pdev = pdev;
+
+ mutex_init(&abe->mutex);
+ mutex_init(&abe->opp_mutex);
+
+ ret = snd_soc_register_platform(&pdev->dev,
+ &omap_aess_platform);
+ if (ret == 0)
+ return 0;
+
+err_irq:
+ iounmap(abe->io_base);
+err:
+ kfree(abe);
+ return ret;
+}
+
+static int __devexit abe_engine_remove(struct platform_device *pdev)
+{
+ struct abe_data *priv = dev_get_drvdata(&pdev->dev);
+
+ snd_soc_unregister_platform(&pdev->dev);
+ iounmap(priv->io_base);
+ kfree(priv);
+ return 0;
+}
+
+static struct platform_driver omap_aess_driver = {
+ .driver = {
+ .name = "omap-aess-audio",
+ .owner = THIS_MODULE,
+ },
+ .probe = abe_engine_probe,
+ .remove = __devexit_p(abe_engine_remove),
+};
+
+static int __init abe_engine_init(void)
+{
+ return platform_driver_register(&omap_aess_driver);
+}
+module_init(abe_engine_init);
+
+static void __exit abe_engine_exit(void)
+{
+ platform_driver_unregister(&omap_aess_driver);
+}
+module_exit(abe_engine_exit);
+
+MODULE_DESCRIPTION("ASoC OMAP4 ABE");
+MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-abe-dsp.h b/sound/soc/omap/omap-abe-dsp.h
new file mode 100644
index 00000000000..212ef3bf30f
--- /dev/null
+++ b/sound/soc/omap/omap-abe-dsp.h
@@ -0,0 +1,34 @@
+/*
+ * omap-abe-dsp.h
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * Contact: Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_ABE_DSP_H__
+#define __OMAP_ABE_DSP_H__
+
+/* Ping pong buffer DMEM offset */
+#define ABE_DMEM_BASE_OFFSET_PING_PONG 0x4000
+
+void abe_dsp_mcpdm_shutdown(void);
+void abe_dsp_pm_get(void);
+void abe_dsp_pm_put(void);
+
+#endif /* End of __OMAP_ABE_DSP_H__ */
diff --git a/sound/soc/omap/omap-abe.c b/sound/soc/omap/omap-abe.c
new file mode 100644
index 00000000000..ded9194efd8
--- /dev/null
+++ b/sound/soc/omap/omap-abe.c
@@ -0,0 +1,1669 @@
+/*
+ * omap-abe.c -- OMAP ALSA SoC DAI driver using Audio Backend
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * Contact: Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/control.h>
+
+#include <plat/dma-44xx.h>
+#include <plat/dma.h>
+#include "omap-mcpdm.h"
+#include "omap-pcm.h"
+#include "omap-abe.h"
+#include "omap-abe-dsp.h"
+#include "abe/abe_main.h"
+
+#define OMAP_ABE_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
+
+/*
+ * This is the AESS frontend driver. i.e. the part that Tx and Rx PCM
+ * data via the OMAP sDMA and ALSA userspace PCMs.
+ *
+ * TODO:
+ *
+ * 1) Get DAI params from HAL and pass onto DAI drivers ?
+ * (are params static ??, i.e. can I just use a table)
+ */
+
+#define NUM_ABE_FRONTENDS 7
+#define NUM_ABE_BACKENDS 11
+
+/* logical -> physical DAI status */
+enum dai_status {
+ DAI_STOPPED = 0,
+ DAI_STARTED,
+};
+
+struct omap_abe_data {
+ int be_active[NUM_ABE_BACKENDS][2];
+
+ struct clk *clk;
+ struct workqueue_struct *workqueue;
+
+ /* hwmod platform device */
+ struct platform_device *pdev;
+
+ /* MODEM FE*/
+ struct snd_pcm_substream *modem_substream[2];
+ struct snd_soc_dai *modem_dai;
+
+ /* reference counting and port status - HAL should really do this */
+ enum dai_status dmic_status[3];
+ enum dai_status pdm_dl_status[3];
+ enum dai_status pdm_ul_status;
+
+};
+
+static struct omap_abe_data abe_data;
+static void capture_trigger(struct snd_pcm_substream *substream, int cmd);
+static void playback_trigger(struct snd_pcm_substream *substream, int cmd);
+
+/* frontend mutex */
+static DEFINE_MUTEX(fe_mutex);
+
+/*
+ * Stream DMA parameters
+ */
+static struct omap_pcm_dma_data omap_abe_dai_dma_params[7][2] = {
+{
+ {
+ .name = "Media Playback",
+ .dma_req = OMAP44XX_DMA_ABE_REQ_0,
+ .data_type = OMAP_DMA_DATA_TYPE_S32,
+ .sync_mode = OMAP_DMA_SYNC_PACKET,
+ },
+ {
+ .name = "Media Capture1",
+ .dma_req = OMAP44XX_DMA_ABE_REQ_3,
+ .data_type = OMAP_DMA_DATA_TYPE_S32,
+ .sync_mode = OMAP_DMA_SYNC_PACKET,
+ },
+},
+{
+ {},
+ {
+ .name = "Media Capture2",
+ .dma_req = OMAP44XX_DMA_ABE_REQ_4,
+ .data_type = OMAP_DMA_DATA_TYPE_S32,
+ .sync_mode = OMAP_DMA_SYNC_PACKET,
+ },
+},
+{
+ {
+ .name = "Voice Playback",
+ .dma_req = OMAP44XX_DMA_ABE_REQ_1,
+ .data_type = OMAP_DMA_DATA_TYPE_S32,
+ .sync_mode = OMAP_DMA_SYNC_PACKET,
+ },
+ {
+ .name = "Voice Capture",
+ .dma_req = OMAP44XX_DMA_ABE_REQ_2,
+ .data_type = OMAP_DMA_DATA_TYPE_S32,
+ .sync_mode = OMAP_DMA_SYNC_PACKET,
+ },
+},
+{
+ {
+ .name = "Tones Playback",
+ .dma_req = OMAP44XX_DMA_ABE_REQ_5,
+ .data_type = OMAP_DMA_DATA_TYPE_S32,
+ .sync_mode = OMAP_DMA_SYNC_PACKET,
+ },{},
+},
+{
+ {
+ .name = "Vibra Playback",
+ .dma_req = OMAP44XX_DMA_ABE_REQ_6,
+ .data_type = OMAP_DMA_DATA_TYPE_S32,
+ .sync_mode = OMAP_DMA_SYNC_PACKET,
+ },{},
+},
+{
+ {
+ .name = "MODEM Playback",
+ .dma_req = OMAP44XX_DMA_ABE_REQ_1,
+ .data_type = OMAP_DMA_DATA_TYPE_S32,
+ .sync_mode = OMAP_DMA_SYNC_PACKET,
+ },
+ {
+ .name = "MODEM Capture",
+ .dma_req = OMAP44XX_DMA_ABE_REQ_2,
+ .data_type = OMAP_DMA_DATA_TYPE_S32,
+ .sync_mode = OMAP_DMA_SYNC_PACKET,
+ },
+},
+{
+ {
+ .name = "Low Power Playback",
+ .dma_req = OMAP44XX_DMA_ABE_REQ_0,
+ .data_type = OMAP_DMA_DATA_TYPE_S32,
+ .sync_mode = OMAP_DMA_SYNC_PACKET,
+ },{},
+},};
+
+/*
+ * Caller holds lock for be_active calls.
+ */
+static inline int be_get_active(struct snd_soc_pcm_runtime *be_rtd, int stream)
+{
+ return abe_data.be_active[be_rtd->dai_link->be_id][stream];
+}
+
+static inline void be_inc_active(struct snd_soc_pcm_runtime *be_rtd, int stream)
+{
+ abe_data.be_active[be_rtd->dai_link->be_id][stream]++;
+}
+
+static inline void be_dec_active(struct snd_soc_pcm_runtime *be_rtd, int stream)
+{
+ abe_data.be_active[be_rtd->dai_link->be_id][stream]--;
+}
+
+/* iff the BE has one user can we start and stop the port */
+static inline int be_is_pending(struct snd_soc_pcm_runtime *be_rtd, int stream)
+{
+ return abe_data.be_active[be_rtd->dai_link->be_id][stream] == 1 ? 1 : 0;
+}
+
+/*
+ * consolidate our 3 PDM and DMICs.
+ */
+static inline int pdm_ready(struct omap_abe_data *abe)
+{
+ int i;
+
+ /* check the 3 DL DAIs */
+ for (i = 0; i < 3; i++) {
+ if (abe->pdm_dl_status[i] == DAI_STARTED)
+ return 0;
+ }
+
+ return 1;
+}
+
+static inline int dmic_ready(struct omap_abe_data *abe)
+{
+ int i;
+
+ /* check the 3 DMIC DAIs */
+ for (i = 0; i < 3; i++) {
+ if (abe->dmic_status[i] == DAI_STARTED)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int modem_get_dai(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *modem_rtd;
+
+ abe_data.modem_substream[substream->stream] =
+ snd_soc_get_dai_substream(rtd->card,
+ OMAP_ABE_BE_MM_EXT1, substream->stream);
+ if (abe_data.modem_substream[substream->stream] == NULL)
+ return -ENODEV;
+
+ modem_rtd = abe_data.modem_substream[substream->stream]->private_data;
+ abe_data.modem_dai = modem_rtd->cpu_dai;
+ return 0;
+}
+
+/* Frontend PCM Operations */
+
+static int abe_fe_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int ret = 0;
+
+ /* TODO: complete HW pcm for backends */
+#if 0
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ priv->sysclk_constraints);
+#endif
+
+ if (dai->id == ABE_FRONTEND_DAI_MODEM) {
+
+ ret = modem_get_dai(substream);
+ if (ret < 0) {
+ dev_err(dai->dev, "failed to get MODEM DAI\n");
+ return ret;
+ }
+ dev_dbg(abe_data.modem_dai->dev, "%s: MODEM stream %d\n",
+ __func__, substream->stream);
+
+ ret = snd_soc_dai_startup(abe_data.modem_substream[substream->stream],
+ abe_data.modem_dai);
+ if (ret < 0) {
+ dev_err(abe_data.modem_dai->dev, "failed to open DAI %d\n", ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int abe_fe_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ abe_data_format_t format;
+ abe_dma_t dma_sink;
+ abe_dma_t dma_params;
+ int ret;
+
+ switch (params_channels(params)) {
+ case 1:
+ if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)
+ format.samp_format = MONO_RSHIFTED_16;
+ else
+ format.samp_format = MONO_MSB;
+ break;
+ case 2:
+ if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)
+ format.samp_format = STEREO_16_16;
+ else
+ format.samp_format = STEREO_MSB;
+ break;
+ case 3:
+ format.samp_format = THREE_MSB;
+ break;
+ case 4:
+ format.samp_format = FOUR_MSB;
+ break;
+ case 5:
+ format.samp_format = FIVE_MSB;
+ break;
+ case 6 :
+ format.samp_format = SIX_MSB;
+ break;
+ case 7 :
+ format.samp_format = SEVEN_MSB;
+ break;
+ case 8:
+ format.samp_format = EIGHT_MSB;
+ break;
+ default:
+ dev_err(dai->dev, "%d channels not supported",
+ params_channels(params));
+ return -EINVAL;
+ }
+
+ format.f = params_rate(params);
+
+ switch (dai->id) {
+ case ABE_FRONTEND_DAI_MEDIA:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ abe_connect_cbpr_dmareq_port(MM_DL_PORT, &format, ABE_CBPR0_IDX,
+ &dma_sink);
+ abe_read_port_address(MM_DL_PORT, &dma_params);
+ } else {
+ abe_connect_cbpr_dmareq_port(MM_UL_PORT, &format, ABE_CBPR3_IDX,
+ &dma_sink);
+ abe_read_port_address(MM_UL_PORT, &dma_params);
+ }
+ break;
+ case ABE_FRONTEND_DAI_LP_MEDIA:
+ return 0;
+ break;
+ case ABE_FRONTEND_DAI_MEDIA_CAPTURE:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return -EINVAL;
+ else {
+ abe_connect_cbpr_dmareq_port(MM_UL2_PORT, &format, ABE_CBPR4_IDX,
+ &dma_sink);
+ abe_read_port_address(MM_UL2_PORT, &dma_params);
+ }
+ break;
+ case ABE_FRONTEND_DAI_VOICE:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ abe_connect_cbpr_dmareq_port(VX_DL_PORT, &format, ABE_CBPR1_IDX,
+ &dma_sink);
+ abe_read_port_address(VX_DL_PORT, &dma_params);
+ } else {
+ abe_connect_cbpr_dmareq_port(VX_UL_PORT, &format, ABE_CBPR2_IDX,
+ &dma_sink);
+ abe_read_port_address(VX_UL_PORT, &dma_params);
+ }
+ break;
+ case ABE_FRONTEND_DAI_TONES:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ abe_connect_cbpr_dmareq_port(TONES_DL_PORT, &format, ABE_CBPR5_IDX,
+ &dma_sink);
+ abe_read_port_address(TONES_DL_PORT, &dma_params);
+ } else
+ return -EINVAL;
+ break;
+ case ABE_FRONTEND_DAI_VIBRA:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ abe_connect_cbpr_dmareq_port(VIB_DL_PORT, &format, ABE_CBPR6_IDX,
+ &dma_sink);
+ abe_read_port_address(VIB_DL_PORT, &dma_params);
+ } else
+ return -EINVAL;
+ break;
+ case ABE_FRONTEND_DAI_MODEM:
+ /* MODEM is special case where data IO is performed by McBSP2
+ * directly onto VX_DL and VX_UL (instead of SDMA).
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /* Vx_DL connection to McBSP 2 ports */
+ format.samp_format = STEREO_RSHIFTED_16;
+ abe_connect_serial_port(VX_DL_PORT, &format, MCBSP2_RX);
+ abe_read_port_address(VX_DL_PORT, &dma_params);
+ } else {
+ /* Vx_UL connection to McBSP 2 ports */
+ format.samp_format = STEREO_RSHIFTED_16;
+ abe_connect_serial_port(VX_UL_PORT, &format, MCBSP2_TX);
+ abe_read_port_address(VX_UL_PORT, &dma_params);
+ }
+ break;
+ }
+
+ /* configure frontend SDMA data */
+ omap_abe_dai_dma_params[dai->id][substream->stream].port_addr =
+ (unsigned long)dma_params.data;
+ omap_abe_dai_dma_params[dai->id][substream->stream].packet_size =
+ dma_params.iter;
+
+ if (dai->id == ABE_FRONTEND_DAI_MODEM) {
+ /* call hw_params on McBSP with correct DMA data */
+ snd_soc_dai_set_dma_data(abe_data.modem_dai, substream,
+ &omap_abe_dai_dma_params[dai->id][substream->stream]);
+
+ dev_dbg(abe_data.modem_dai->dev, "%s: MODEM stream %d\n",
+ __func__, substream->stream);
+
+ ret = snd_soc_dai_hw_params(abe_data.modem_substream[substream->stream],
+ params, abe_data.modem_dai);
+ if (ret < 0)
+ dev_err(abe_data.modem_dai->dev, "MODEM hw_params failed\n");
+ return ret;
+ }
+
+ snd_soc_dai_set_dma_data(dai, substream,
+ &omap_abe_dai_dma_params[dai->id][substream->stream]);
+
+ return 0;
+}
+
+static int abe_fe_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int ret = 0;
+
+ if (dai->id == ABE_FRONTEND_DAI_MODEM) {
+ ret = snd_soc_dai_prepare(abe_data.modem_substream[substream->stream],
+ abe_data.modem_dai);
+
+ dev_dbg(abe_data.modem_dai->dev, "%s: MODEM stream %d\n",
+ __func__, substream->stream);
+
+ if (ret < 0) {
+ dev_err(abe_data.modem_dai->dev, "MODEM prepare failed\n");
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static int abe_fe_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ int ret = 0;
+
+ if (dai->id == ABE_FRONTEND_DAI_MODEM) {
+
+ dev_dbg(abe_data.modem_dai->dev, "%s: MODEM stream %d cmd %d\n",
+ __func__, substream->stream, cmd);
+
+ ret = snd_soc_dai_trigger(abe_data.modem_substream[substream->stream],
+ cmd, abe_data.modem_dai);
+ if (ret < 0) {
+ dev_err(abe_data.modem_dai->dev, "MODEM trigger failed\n");
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static int abe_fe_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int ret = 0;
+
+ if (dai->id == ABE_FRONTEND_DAI_MODEM) {
+
+ dev_dbg(abe_data.modem_dai->dev, "%s: MODEM stream %d\n",
+ __func__, substream->stream);
+
+ ret = snd_soc_dai_hw_free(abe_data.modem_substream[substream->stream],
+ abe_data.modem_dai);
+ if (ret < 0) {
+ dev_err(abe_data.modem_dai->dev, "MODEM hw_free failed\n");
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static void abe_fe_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+
+ if (dai->id == ABE_FRONTEND_DAI_MODEM) {
+ dev_dbg(abe_data.modem_dai->dev, "%s: MODEM stream %d\n",
+ __func__, substream->stream);
+
+ snd_soc_dai_shutdown(abe_data.modem_substream[substream->stream],
+ abe_data.modem_dai);
+ }
+ //TODO: Do we need to do reset this stuff i.e. :-
+ //abe_connect_cbpr_dmareq_port(VIB_DL_PORT, &format, ABE_CBPR6_IDX,
+ // &dma_sink);
+}
+
+static void abe_be_dapm(struct snd_soc_pcm_runtime *rtd,
+ int id, int stream, int cmd)
+{
+ dev_dbg(&rtd->dev, "%s: id %d stream %d cmd %d\n",
+ __func__, id, stream, cmd);
+
+ switch (id) {
+ case ABE_FRONTEND_DAI_MEDIA:
+ case ABE_FRONTEND_DAI_LP_MEDIA:
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_dapm_stream_event(rtd, stream, "Multimedia Playback",cmd);
+ else
+ snd_soc_dapm_stream_event(rtd, stream, "Multimedia Capture1",cmd);
+ break;
+ case ABE_FRONTEND_DAI_MEDIA_CAPTURE:
+ snd_soc_dapm_stream_event(rtd, stream, "Multimedia Capture2",cmd);
+ break;
+ case ABE_FRONTEND_DAI_VOICE:
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_dapm_stream_event(rtd, stream, "Voice Playback",cmd);
+ else
+ snd_soc_dapm_stream_event(rtd, stream, "Voice Capture",cmd);
+ break;
+ case ABE_FRONTEND_DAI_TONES:
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_dapm_stream_event(rtd, stream, "Tones Playback",cmd);
+ break;
+ case ABE_FRONTEND_DAI_VIBRA:
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_dapm_stream_event(rtd, stream, "Vibra Playback",cmd);
+ break;
+ case ABE_FRONTEND_DAI_MODEM:
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_dapm_stream_event(rtd, stream, "MODEM Playback",cmd);
+ else
+ snd_soc_dapm_stream_event(rtd, stream, "MODEM Capture",cmd);
+ break;
+ }
+}
+
+/* Frontend --> Backend ALSA PCM OPS */
+
+static int omap_abe_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int stream = substream->stream, ret = 0, i;
+
+ dev_dbg(dai->dev, "%s: frontend %s %d\n", __func__,
+ rtd->dai_link->name, dai->id);
+
+ /* ABE needs a step of 24 * 4 data bytes */
+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 96);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&fe_mutex);
+
+ /* only startup BE DAIs that are either sinks or sources to this FE DAI */
+ for (i = 0; i < rtd->num_be[stream]; i++) {
+ struct snd_soc_pcm_runtime *be_rtd = rtd->be_rtd[i][stream];
+ struct snd_pcm_substream *be_substream =
+ be_rtd->pcm->streams[stream].substream;
+
+ if (be_substream == NULL)
+ continue;
+
+ /* update BE ref counts */
+ be_inc_active(rtd->be_rtd[i][stream], stream);
+
+ if (be_is_pending(rtd->be_rtd[i][stream], stream)) {
+ be_rtd->current_fe = dai->id;
+ ret = snd_soc_pcm_open(be_substream);
+ if (ret < 0)
+ goto unwind;
+ dev_dbg(&rtd->dev, "%s: open %s:%d at %d act %d\n", __func__,
+ rtd->be_rtd[i][stream]->dai_link->name,
+ rtd->be_rtd[i][stream]->dai_link->be_id, i,
+ abe_data.be_active[rtd->be_rtd[i][stream]->dai_link->be_id][stream]);
+ }
+ }
+
+ /* start the ABE frontend */
+ ret = abe_fe_startup(substream, dai);
+ if (ret < 0) {
+ dev_err(dai->dev,"%s: failed to start FE %d\n", __func__, ret);
+ goto unwind;
+ }
+
+ dev_dbg(dai->dev,"%s: frontend finished %s %d\n", __func__,
+ rtd->dai_link->name, dai->id);
+ mutex_unlock(&fe_mutex);
+ return 0;
+
+unwind:
+ /* disable any enabled and non active backends */
+ for (--i; i >= 0; i--) {
+ struct snd_soc_pcm_runtime *be_rtd = rtd->be_rtd[i][stream];
+ struct snd_pcm_substream *be_substream =
+ be_rtd->pcm->streams[stream].substream;
+
+ if (be_substream == NULL)
+ continue;
+
+ if (be_is_pending(rtd->be_rtd[i][stream], stream)) {
+ be_rtd->current_fe = dai->id;
+ snd_soc_pcm_close(be_substream);
+
+ dev_dbg(&rtd->dev, "%s: open-err-close %s:%d at %d act %d\n", __func__,
+ rtd->be_rtd[i][stream]->dai_link->name,
+ rtd->be_rtd[i][stream]->dai_link->be_id, i,
+ abe_data.be_active[rtd->be_rtd[i][stream]->dai_link->be_id][stream]);
+ }
+
+ be_dec_active(rtd->be_rtd[i][stream], stream);
+ }
+
+ mutex_unlock(&fe_mutex);
+ return ret;
+}
+
+static void omap_abe_dai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int stream = substream->stream, i;
+
+ dev_dbg(dai->dev,"%s: frontend %s \n", __func__, rtd->dai_link->name);
+ /* only shutdown backends that are either sinks or sources to this frontend DAI */
+
+ mutex_lock(&fe_mutex);
+
+ for (i = 0; i < rtd->num_be[stream]; i++) {
+ struct snd_soc_pcm_runtime *be_rtd = rtd->be_rtd[i][stream];
+ struct snd_pcm_substream *be_substream =
+ be_rtd->pcm->streams[stream].substream;
+
+ if (be_substream == NULL)
+ continue;
+
+ /* close backend stream if inactive */
+ if (be_is_pending(rtd->be_rtd[i][stream], stream)) {
+ be_rtd->current_fe = dai->id;
+ snd_soc_pcm_close(be_substream);
+
+ dev_dbg(&rtd->dev,"%s: close %s:%d at %d act %d\n", __func__,
+ rtd->be_rtd[i][stream]->dai_link->name,
+ rtd->be_rtd[i][stream]->dai_link->be_id, i,
+ abe_data.be_active[rtd->be_rtd[i][stream]->dai_link->be_id][stream]);
+ }
+
+ be_dec_active(rtd->be_rtd[i][stream], stream);
+ }
+
+ /* now shutdown the frontend */
+ abe_fe_shutdown(substream, dai);
+
+ abe_be_dapm(rtd, dai->id, stream, SND_SOC_DAPM_STREAM_STOP);
+ dev_dbg(dai->dev,"%s: frontend %s completed !\n", __func__, rtd->dai_link->name);
+ mutex_unlock(&fe_mutex);
+}
+
+static int omap_abe_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int stream = substream->stream, i, ret = 0;
+ struct snd_pcm_hw_params *params_fe;
+
+ params_fe = kzalloc(sizeof(struct snd_pcm_hw_params), GFP_KERNEL);
+ dev_dbg(dai->dev,"%s: frontend %s \n", __func__, rtd->dai_link->name);
+
+ memcpy(params_fe, params, sizeof(struct snd_pcm_hw_params));
+
+ mutex_lock(&fe_mutex);
+
+ for (i = 0; i < rtd->num_be[stream]; i++) {
+ struct snd_soc_pcm_runtime *be_rtd = rtd->be_rtd[i][stream];
+ struct snd_pcm_substream *be_substream =
+ be_rtd->pcm->streams[stream].substream;
+
+ if (be_substream == NULL)
+ continue;
+
+ if (be_is_pending(rtd->be_rtd[i][stream], stream)) {
+ be_rtd->current_fe = dai->id;
+ if (be_rtd->dai_link->be_hw_params_fixup)
+ ret = be_rtd->dai_link->be_hw_params_fixup(be_rtd, params);
+ if (ret < 0) {
+ dev_err(&rtd->dev, "%s: backend hw_params fixup failed %d\n",
+ __func__, ret);
+ goto out;
+ }
+
+ ret = snd_soc_pcm_hw_params(be_substream, params);
+ if (ret < 0) {
+ dev_err(&rtd->dev, "%s: backend hw_params failed %d\n",
+ __func__, ret);
+ goto out;
+ }
+ }
+ }
+
+ /* call hw_params on the frontend */
+ memcpy(params, params_fe, sizeof(struct snd_pcm_hw_params));
+ ret = abe_fe_hw_params(substream, params, dai);
+ if (ret < 0)
+ dev_err(dai->dev,"%s: frontend hw_params failed\n", __func__);
+
+out:
+ mutex_unlock(&fe_mutex);
+ kfree(params_fe);
+ return ret;
+}
+
+static int omap_abe_dai_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int ret;
+
+ dev_dbg(dai->dev,"%s: frontend %s \n", __func__, rtd->dai_link->name);
+
+ /* call prepare on the frontend. TODO: do we handle MODEM as sequence */
+ ret = abe_fe_trigger(substream, cmd, dai);
+ if (ret < 0) {
+ dev_err(dai->dev,"%s: frontend trigger failed\n", __func__);
+ return ret;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ playback_trigger(substream, cmd);
+ else
+ capture_trigger(substream, cmd);
+
+ return 0;
+}
+
+static int omap_abe_dai_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int stream = substream->stream, ret = 0, i;
+
+ dev_dbg(dai->dev,"%s: frontend %s \n", __func__, rtd->dai_link->name);
+ /* only prepare backends that are either sinks or sources to
+ * this frontend DAI */
+
+ mutex_lock(&fe_mutex);
+
+ for (i = 0; i < rtd->num_be[stream]; i++) {
+ struct snd_soc_pcm_runtime *be_rtd = rtd->be_rtd[i][stream];
+ struct snd_pcm_substream *be_substream =
+ be_rtd->pcm->streams[stream].substream;
+
+ if (be_substream == NULL)
+ continue;
+
+ /* prepare backend stream */
+ if (be_is_pending(rtd->be_rtd[i][stream], stream)) {
+ be_rtd->current_fe = dai->id;
+ snd_soc_pcm_prepare(be_substream);
+ }
+ }
+
+ /* call prepare on the frontend */
+ ret = abe_fe_prepare(substream, dai);
+ if (ret < 0)
+ dev_err(dai->dev,"%s: frontend prepare failed\n", __func__);
+
+ abe_be_dapm(rtd, dai->id, stream, SND_SOC_DAPM_STREAM_START);
+
+ mutex_unlock(&fe_mutex);
+ return ret;
+}
+
+static int omap_abe_dai_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int stream = substream->stream, ret = 0, i;
+
+ dev_dbg(dai->dev,"%s: frontend %s \n", __func__, rtd->dai_link->name);
+
+ mutex_lock(&fe_mutex);
+
+ /* call hw_free on the frontend */
+ ret = abe_fe_hw_free(substream, dai);
+ if (ret < 0)
+ dev_err(dai->dev,"%s: frontend hw_free failed\n", __func__);
+
+ /* only hw_params backends that are either sinks or sources
+ * to this frontend DAI */
+ for (i = 0; i < rtd->num_be[stream]; i++) {
+ struct snd_soc_pcm_runtime *be_rtd = rtd->be_rtd[i][stream];
+ struct snd_pcm_substream *be_substream =
+ be_rtd->pcm->streams[stream].substream;
+
+ if (be_substream == NULL)
+ continue;
+
+ if (be_is_pending(rtd->be_rtd[i][stream], stream)) {
+ be_rtd->current_fe = dai->id;
+ snd_soc_pcm_hw_free(be_substream);
+ }
+ }
+
+ mutex_unlock(&fe_mutex);
+ return ret;
+}
+
+/* ABE Frontend PCM OPS */
+static struct snd_soc_dai_ops omap_abe_dai_ops = {
+ .startup = omap_abe_dai_startup,
+ .shutdown = omap_abe_dai_shutdown,
+ .hw_params = omap_abe_dai_hw_params,
+ .prepare = omap_abe_dai_prepare,
+ .hw_free = omap_abe_dai_hw_free,
+ .trigger = omap_abe_dai_trigger,
+};
+
+// TODO: finish this
+static void mute_be_capture(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *be_rtd;
+ int i;
+
+ for (i = 0; i < rtd->num_be[SNDRV_PCM_STREAM_CAPTURE]; i++) {
+ be_rtd = rtd->be_rtd[i][SNDRV_PCM_STREAM_CAPTURE];
+
+ dev_dbg(&rtd->dev, "%s: be ID=%d\n", __func__, be_rtd->dai_link->be_id);
+
+ switch (be_rtd->dai_link->be_id) {
+ case OMAP_ABE_DAI_PDM_UL:
+ abe_mute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET);
+ break;
+ case OMAP_ABE_DAI_BT_VX:
+ case OMAP_ABE_DAI_MM_FM:
+ case OMAP_ABE_DAI_MODEM:
+ break;
+ case OMAP_ABE_DAI_DMIC0:
+ abe_mute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET);
+ break;
+ case OMAP_ABE_DAI_DMIC1:
+ abe_mute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET);
+ break;
+ case OMAP_ABE_DAI_DMIC2:
+ abe_mute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET);
+ break;
+ }
+ }
+}
+
+// TODO: finish this and restore correct volume levels
+static void unmute_be_capture(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *be_rtd;
+ int i;
+
+ for (i = 0; i < rtd->num_be[SNDRV_PCM_STREAM_CAPTURE]; i++) {
+ be_rtd = rtd->be_rtd[i][SNDRV_PCM_STREAM_CAPTURE];
+
+ dev_dbg(&rtd->dev, "%s: be ID=%d\n", __func__, be_rtd->dai_link->be_id);
+
+ switch (be_rtd->dai_link->be_id) {
+ case OMAP_ABE_DAI_PDM_UL:
+ abe_unmute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET);
+ break;
+ case OMAP_ABE_DAI_BT_VX:
+ case OMAP_ABE_DAI_MM_FM:
+ case OMAP_ABE_DAI_MODEM:
+ break;
+ case OMAP_ABE_DAI_DMIC0:
+ abe_unmute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET);
+ break;
+ case OMAP_ABE_DAI_DMIC1:
+ abe_unmute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET);
+ break;
+ case OMAP_ABE_DAI_DMIC2:
+ abe_unmute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET);
+ break;
+ }
+ }
+}
+#if 0
+static void mute_fe_playback(struct abe_frontend_dai *fe,
+ struct snd_soc_pcm_runtime *be_rtd, int mixer, int *volume)
+{
+ struct snd_soc_pcm_runtime *rtd = fe->substream->private_data;
+
+ switch (rtd->cpu_dai->id) {
+ case ABE_FRONTEND_DAI_MEDIA:
+ case ABE_FRONTEND_DAI_LP_MEDIA:
+ if (be_is_pending(be_rtd, SNDRV_PCM_STREAM_PLAYBACK)) {
+ abe_read_mixer(mixer, volume, MIX_DL1_INPUT_MM_DL);
+ abe_write_mixer(mixer, MUTE_GAIN, RAMP_0MS,
+ MIX_DL1_INPUT_MM_DL);
+ }
+ break;
+ case ABE_FRONTEND_DAI_MODEM:
+ case ABE_FRONTEND_DAI_VOICE:
+ if (be_is_pending(be_rtd, SNDRV_PCM_STREAM_PLAYBACK)) {
+ abe_read_mixer(mixer, volume, MIX_DL1_INPUT_VX_DL);
+ abe_write_mixer(mixer, MUTE_GAIN, RAMP_0MS,
+ MIX_DL1_INPUT_VX_DL);
+ }
+ break;
+ case ABE_FRONTEND_DAI_TONES:
+ if (be_is_pending(be_rtd, SNDRV_PCM_STREAM_PLAYBACK)) {
+ abe_read_mixer(mixer, volume, MIX_DL1_INPUT_TONES);
+ abe_write_mixer(mixer, MUTE_GAIN, RAMP_0MS,
+ MIX_DL1_INPUT_TONES);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void unmute_fe_playback(struct abe_frontend_dai *fe,
+ struct snd_soc_pcm_runtime *be_rtd, int mixer, int volume)
+{
+ struct snd_soc_pcm_runtime *rtd = fe->substream->private_data;
+
+ switch (rtd->cpu_dai->id) {
+ case ABE_FRONTEND_DAI_MEDIA:
+ case ABE_FRONTEND_DAI_LP_MEDIA:
+ if (be_is_pending(be_rtd, SNDRV_PCM_STREAM_PLAYBACK)) {
+ abe_write_mixer(mixer, volume, RAMP_5MS,
+ MIX_DL1_INPUT_MM_DL);
+ }
+ break;
+ case ABE_FRONTEND_DAI_MODEM:
+ case ABE_FRONTEND_DAI_VOICE:
+ if (be_is_pending(be_rtd, SNDRV_PCM_STREAM_PLAYBACK)) {
+ abe_write_mixer(mixer, volume, RAMP_5MS,
+ MIX_DL1_INPUT_VX_DL);
+ }
+ break;
+ case ABE_FRONTEND_DAI_TONES:
+ if (be_is_pending(be_rtd, SNDRV_PCM_STREAM_PLAYBACK)) {
+ abe_write_mixer(mixer, volume, RAMP_5MS,
+ MIX_DL1_INPUT_TONES);
+ }
+ break;
+ default:
+ break;
+ }
+}
+#endif
+static void mute_be_playback(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *be_rtd;
+ int i;
+
+ for (i = 0; i < rtd->num_be[SNDRV_PCM_STREAM_PLAYBACK]; i++) {
+ be_rtd = rtd->be_rtd[i][SNDRV_PCM_STREAM_PLAYBACK];
+
+ dev_dbg(&rtd->dev, "%s: be ID=%d\n", __func__, be_rtd->dai_link->be_id);
+
+ switch (be_rtd->dai_link->be_id) {
+ case OMAP_ABE_DAI_PDM_DL1:
+ abe_write_gain(GAINS_DL1, MUTE_GAIN, RAMP_5MS,
+ GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_DL1, MUTE_GAIN, RAMP_5MS,
+ GAIN_RIGHT_OFFSET);
+ break;
+ case OMAP_ABE_DAI_PDM_DL2:
+ abe_write_gain(GAINS_DL2, MUTE_GAIN, RAMP_5MS,
+ GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_DL2, MUTE_GAIN, RAMP_5MS,
+ GAIN_RIGHT_OFFSET);
+ break;
+ case OMAP_ABE_DAI_PDM_VIB:
+ case OMAP_ABE_DAI_BT_VX:
+ case OMAP_ABE_DAI_MM_FM:
+ case OMAP_ABE_DAI_MODEM:
+ break;
+ }
+ }
+}
+
+static void unmute_be_playback(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *be_rtd;
+ int i;
+
+ for (i = 0; i < rtd->num_be[SNDRV_PCM_STREAM_PLAYBACK]; i++) {
+ be_rtd = rtd->be_rtd[i][SNDRV_PCM_STREAM_PLAYBACK];
+
+ dev_dbg(&rtd->dev, "%s: be ID=%d\n", __func__, be_rtd->dai_link->be_id);
+
+ switch (be_rtd->dai_link->be_id) {
+ case OMAP_ABE_DAI_PDM_DL1:
+ abe_write_gain(GAINS_DL1, GAIN_0dB, RAMP_5MS,
+ GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_DL1, GAIN_0dB, RAMP_5MS,
+ GAIN_RIGHT_OFFSET);
+ break;
+ case OMAP_ABE_DAI_PDM_DL2:
+ abe_write_gain(GAINS_DL2, GAIN_0dB, RAMP_5MS,
+ GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_DL2, GAIN_0dB, RAMP_5MS,
+ GAIN_RIGHT_OFFSET);
+ break;
+ case OMAP_ABE_DAI_PDM_VIB:
+ case OMAP_ABE_DAI_BT_VX:
+ case OMAP_ABE_DAI_MM_FM:
+ case OMAP_ABE_DAI_MODEM:
+ break;
+ }
+ }
+}
+
+static inline void abe_dai_enable_data_transfer(int port)
+{
+ pr_debug("%s : port %d\n", __func__, port);
+ if (port != PDM_DL_PORT)
+ abe_enable_data_transfer(port);
+}
+
+static void enable_be_ports(struct snd_pcm_substream *substream, int stream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *be_rtd;
+ abe_data_format_t format;
+ int i;
+
+ for (i = 0; i < rtd->num_be[stream]; i++) {
+ be_rtd = rtd->be_rtd[i][stream];
+
+ dev_dbg(&rtd->dev, "%s: be ID=%d stream %d active %d\n",
+ __func__, be_rtd->dai_link->be_id, stream,
+ be_get_active(be_rtd, stream));
+
+ switch (be_rtd->dai_link->be_id) {
+ case OMAP_ABE_DAI_PDM_DL1:
+ if (be_is_pending(be_rtd, stream) && pdm_ready(&abe_data))
+ abe_dai_enable_data_transfer(PDM_DL_PORT);
+ abe_data.pdm_dl_status[0] = DAI_STARTED;
+ break;
+ case OMAP_ABE_DAI_PDM_DL2:
+ if (be_is_pending(be_rtd, stream) && pdm_ready(&abe_data))
+ abe_dai_enable_data_transfer(PDM_DL_PORT);
+ abe_data.pdm_dl_status[1] = DAI_STARTED;
+ break;
+ case OMAP_ABE_DAI_PDM_VIB:
+ if (be_is_pending(be_rtd, stream) && pdm_ready(&abe_data))
+ abe_dai_enable_data_transfer(PDM_DL_PORT);
+ abe_data.pdm_dl_status[2] = DAI_STARTED;
+ break;
+ case OMAP_ABE_DAI_PDM_UL:
+ if (be_is_pending(be_rtd, stream)) {
+ abe_dai_enable_data_transfer(PDM_UL_PORT);
+ }
+ abe_data.pdm_ul_status = DAI_STARTED;
+ break;
+ case OMAP_ABE_DAI_BT_VX:
+ if (be_is_pending(be_rtd, stream)) {
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /* BT_DL connection to McBSP 1 ports */
+ format.f = 8000;
+ format.samp_format = MONO_RSHIFTED_16;
+ abe_connect_serial_port(BT_VX_DL_PORT,
+ &format, MCBSP1_TX);
+ abe_dai_enable_data_transfer(BT_VX_DL_PORT);
+ } else {
+ /* BT_UL connection to McBSP 1 ports */
+ format.f = 8000;
+ format.samp_format = MONO_RSHIFTED_16;
+ abe_connect_serial_port(BT_VX_UL_PORT,
+ &format, MCBSP1_RX);
+ abe_dai_enable_data_transfer(BT_VX_UL_PORT);
+ }
+ }
+ break;
+ case OMAP_ABE_DAI_MM_FM:
+ if (be_is_pending(be_rtd, stream)) {
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /* MM_EXT connection to McBSP 2 ports */
+ format.f = 48000;
+ format.samp_format = STEREO_RSHIFTED_16;
+ abe_connect_serial_port(MM_EXT_OUT_PORT,
+ &format, MCBSP2_TX);
+ abe_dai_enable_data_transfer(MM_EXT_OUT_PORT);
+ } else {
+ /* MM_EXT connection to McBSP 2 ports */
+ format.f = 48000;
+ format.samp_format = STEREO_RSHIFTED_16;
+ abe_connect_serial_port(MM_EXT_IN_PORT,
+ &format, MCBSP2_RX);
+ abe_dai_enable_data_transfer(MM_EXT_IN_PORT);
+ }
+ }
+ break;
+ case OMAP_ABE_DAI_DMIC0:
+ if (be_is_pending(be_rtd, stream) && dmic_ready(&abe_data))
+ abe_dai_enable_data_transfer(DMIC_PORT);
+ abe_data.dmic_status[0] = DAI_STARTED;
+ break;
+ case OMAP_ABE_DAI_DMIC1:
+ if (be_is_pending(be_rtd, stream) && dmic_ready(&abe_data))
+ abe_dai_enable_data_transfer(DMIC_PORT1);
+ abe_data.dmic_status[1] = DAI_STARTED;
+ break;
+ case OMAP_ABE_DAI_DMIC2:
+ if (be_is_pending(be_rtd, stream) && dmic_ready(&abe_data))
+ abe_dai_enable_data_transfer(DMIC_PORT2);
+ abe_data.dmic_status[2] = DAI_STARTED;
+ break;
+ }
+ }
+}
+
+static void enable_fe_ports(struct snd_pcm_substream *substream, int stream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ dev_dbg(&rtd->dev, "%s: fe ID=%d stream %d\n",
+ __func__, rtd->cpu_dai->id, stream);
+
+ switch(rtd->cpu_dai->id) {
+ case ABE_FRONTEND_DAI_MEDIA:
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ abe_enable_data_transfer(MM_DL_PORT);
+ else
+ abe_enable_data_transfer(MM_UL_PORT);
+ break;
+ case ABE_FRONTEND_DAI_LP_MEDIA:
+ abe_enable_data_transfer(MM_DL_PORT);
+ break;
+ case ABE_FRONTEND_DAI_MEDIA_CAPTURE:
+ if (stream == SNDRV_PCM_STREAM_CAPTURE)
+ abe_enable_data_transfer(MM_UL2_PORT);
+ break;
+ case ABE_FRONTEND_DAI_MODEM:
+ case ABE_FRONTEND_DAI_VOICE:
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ abe_enable_data_transfer(VX_DL_PORT);
+ else
+ abe_enable_data_transfer(VX_UL_PORT);
+ break;
+ case ABE_FRONTEND_DAI_TONES:
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ abe_enable_data_transfer(TONES_DL_PORT);
+ break;
+ case ABE_FRONTEND_DAI_VIBRA:
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ abe_enable_data_transfer(VIB_DL_PORT);
+ break;
+ }
+}
+
+static inline void abe_dai_disable_data_transfer(int port)
+{
+ pr_debug("%s : port %d\n", __func__, port);
+ if (port != PDM_DL_PORT)
+ abe_disable_data_transfer(port);
+}
+
+static void disable_be_ports(struct snd_pcm_substream *substream, int stream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *be_rtd;
+ int i;
+
+ for (i = 0; i < rtd->num_be[stream]; i++) {
+
+ be_rtd = rtd->be_rtd[i][stream];
+
+ dev_dbg(&rtd->dev, "%s: be ID=%d stream %d active %d\n",
+ __func__, be_rtd->dai_link->be_id, stream,
+ be_get_active(be_rtd, stream));
+
+ // TODO: main port active logic will be moved into HAL
+ switch (be_rtd->dai_link->be_id) {
+ case OMAP_ABE_DAI_PDM_DL1:
+ abe_data.pdm_dl_status[0] = DAI_STOPPED;
+ if (be_is_pending(be_rtd, stream) && pdm_ready(&abe_data)) {
+ abe_dai_disable_data_transfer(PDM_DL_PORT);
+ }
+ break;
+ case OMAP_ABE_DAI_PDM_DL2:
+ abe_data.pdm_dl_status[1] = DAI_STOPPED;
+ if (be_is_pending(be_rtd, stream) && pdm_ready(&abe_data)) {
+ abe_dai_disable_data_transfer(PDM_DL_PORT);
+ }
+ break;
+ case OMAP_ABE_DAI_PDM_VIB:
+ abe_data.pdm_dl_status[2] = DAI_STOPPED;
+ if (be_is_pending(be_rtd, stream) && pdm_ready(&abe_data))
+ abe_dai_disable_data_transfer(PDM_VIB_PORT);
+ break;
+ case OMAP_ABE_DAI_PDM_UL:
+ abe_data.pdm_ul_status = DAI_STOPPED;
+ if (be_is_pending(be_rtd, stream)) {
+ abe_dai_disable_data_transfer(PDM_UL_PORT);
+ }
+ break;
+ case OMAP_ABE_DAI_BT_VX:
+ if (be_is_pending(be_rtd, stream)) {
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ abe_dai_disable_data_transfer(BT_VX_DL_PORT);
+ else
+ abe_dai_disable_data_transfer(BT_VX_UL_PORT);
+ }
+ break;
+ case OMAP_ABE_DAI_MM_FM:
+ case OMAP_ABE_DAI_MODEM:
+ if (be_is_pending(be_rtd, stream)) {
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ abe_dai_disable_data_transfer(MM_EXT_OUT_PORT);
+ else
+ abe_dai_disable_data_transfer(MM_EXT_IN_PORT);
+ }
+ case OMAP_ABE_DAI_DMIC0:
+ abe_data.dmic_status[0] = DAI_STOPPED;
+ if (be_is_pending(be_rtd, stream) && dmic_ready(&abe_data))
+ abe_dai_disable_data_transfer(DMIC_PORT);
+ break;
+ case OMAP_ABE_DAI_DMIC1:
+ abe_data.dmic_status[1] = DAI_STOPPED;
+ if (be_is_pending(be_rtd, stream) && dmic_ready(&abe_data))
+ abe_dai_disable_data_transfer(DMIC_PORT1);
+ break;
+ case OMAP_ABE_DAI_DMIC2:
+ abe_data.dmic_status[2] = DAI_STOPPED;
+ if (be_is_pending(be_rtd, stream) && dmic_ready(&abe_data))
+ abe_dai_disable_data_transfer(DMIC_PORT2);
+ break;
+ }
+ }
+}
+
+static void disable_fe_ports(struct snd_pcm_substream *substream, int stream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ dev_dbg(&rtd->dev, "%s: fe ID=%d stream %d\n",
+ __func__, rtd->cpu_dai->id, stream);
+
+ switch(rtd->cpu_dai->id) {
+ case ABE_FRONTEND_DAI_MEDIA:
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ abe_disable_data_transfer(MM_DL_PORT);
+ else
+ abe_disable_data_transfer(MM_UL_PORT);
+ break;
+ case ABE_FRONTEND_DAI_LP_MEDIA:
+ abe_disable_data_transfer(MM_DL_PORT);
+ break;
+ case ABE_FRONTEND_DAI_MEDIA_CAPTURE:
+ if (stream == SNDRV_PCM_STREAM_CAPTURE)
+ abe_disable_data_transfer(MM_UL2_PORT);
+ break;
+ case ABE_FRONTEND_DAI_MODEM:
+ case ABE_FRONTEND_DAI_VOICE:
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ abe_disable_data_transfer(VX_DL_PORT);
+ else
+ abe_disable_data_transfer(VX_UL_PORT);
+ break;
+ case ABE_FRONTEND_DAI_TONES:
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ abe_disable_data_transfer(TONES_DL_PORT);
+ break;
+ case ABE_FRONTEND_DAI_VIBRA:
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ abe_disable_data_transfer(VIB_DL_PORT);
+ break;
+ }
+}
+
+/* TODO: finish this */
+static void mute_fe_port(struct snd_pcm_substream *substream, int stream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ dev_dbg(&rtd->dev, "%s: fe ID=%d stream %d\n",
+ __func__, rtd->cpu_dai->id, stream);
+
+ switch(rtd->cpu_dai->id) {
+ case ABE_FRONTEND_DAI_MEDIA:
+ case ABE_FRONTEND_DAI_LP_MEDIA:
+ if (abe_data.be_active[OMAP_ABE_DAI_PDM_DL2][SNDRV_PCM_STREAM_PLAYBACK]) {
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL);
+ }
+ if (abe_data.be_active[OMAP_ABE_DAI_PDM_DL1][SNDRV_PCM_STREAM_PLAYBACK]) {
+ abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL);
+ }
+ break;
+ case ABE_FRONTEND_DAI_MEDIA_CAPTURE:
+ break;
+ case ABE_FRONTEND_DAI_VOICE:
+ if (abe_data.be_active[OMAP_ABE_DAI_PDM_DL2][SNDRV_PCM_STREAM_PLAYBACK]) {
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL);
+ }
+ if (abe_data.be_active[OMAP_ABE_DAI_PDM_DL1][SNDRV_PCM_STREAM_PLAYBACK]) {
+ abe_mute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL);
+ }
+ break;
+ case ABE_FRONTEND_DAI_TONES:
+ if (abe_data.be_active[OMAP_ABE_DAI_PDM_DL2][SNDRV_PCM_STREAM_PLAYBACK]) {
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_TONES);
+ }
+ if (abe_data.be_active[OMAP_ABE_DAI_PDM_DL1][SNDRV_PCM_STREAM_PLAYBACK]) {
+ abe_mute_gain(MIXDL1, MIX_DL1_INPUT_TONES);
+ }
+ break;
+ case ABE_FRONTEND_DAI_VIBRA:
+
+ break;
+ }
+}
+
+/* TODO: finish this */
+static void unmute_fe_port(struct snd_pcm_substream *substream, int stream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ dev_dbg(&rtd->dev, "%s: fe ID=%d stream %d\n",
+ __func__, rtd->cpu_dai->id, stream);
+
+ switch(rtd->cpu_dai->id) {
+ case ABE_FRONTEND_DAI_MEDIA:
+ case ABE_FRONTEND_DAI_LP_MEDIA:
+ if (abe_data.be_active[OMAP_ABE_DAI_PDM_DL2][SNDRV_PCM_STREAM_PLAYBACK]) {
+ abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL);
+ }
+ if (abe_data.be_active[OMAP_ABE_DAI_PDM_DL1][SNDRV_PCM_STREAM_PLAYBACK]) {
+ abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL);
+ }
+ break;
+ case ABE_FRONTEND_DAI_MEDIA_CAPTURE:
+ break;
+ case ABE_FRONTEND_DAI_VOICE:
+ if (abe_data.be_active[OMAP_ABE_DAI_PDM_DL2][SNDRV_PCM_STREAM_PLAYBACK]) {
+ abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL);
+ }
+ if (abe_data.be_active[OMAP_ABE_DAI_PDM_DL1][SNDRV_PCM_STREAM_PLAYBACK]) {
+ abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL);
+ }
+ break;
+ case ABE_FRONTEND_DAI_TONES:
+ if (abe_data.be_active[OMAP_ABE_DAI_PDM_DL2][SNDRV_PCM_STREAM_PLAYBACK]) {
+ abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_TONES);
+ }
+ if (abe_data.be_active[OMAP_ABE_DAI_PDM_DL1][SNDRV_PCM_STREAM_PLAYBACK]) {
+ abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_TONES);
+ }
+ break;
+ case ABE_FRONTEND_DAI_VIBRA:
+
+ break;
+ }
+}
+
+static void trigger_be_ports(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_pcm_runtime *be_rtd;
+ int i, stream = substream->stream;
+
+ for (i = 0; i < rtd->num_be[stream]; i++) {
+ be_rtd = rtd->be_rtd[i][stream];
+
+ dev_dbg(&rtd->dev, "%s: be ID=%d cmd %d act %d\n",
+ __func__, be_rtd->dai_link->be_id, cmd,
+ abe_data.be_active[be_rtd->dai_link->be_id][stream]);
+
+ if (be_is_pending(be_rtd, stream))
+ snd_soc_dai_trigger(substream, cmd, be_rtd->cpu_dai);
+ }
+}
+
+static void capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ dev_dbg(&rtd->dev, "%s-start: fe ID=%d stream %d\n",
+ __func__, rtd->cpu_dai->id, substream->stream);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* ALL BE GAINS set to mute */
+ mute_be_capture(substream);
+
+ /* Enable ALL ABE BE ports */
+ enable_be_ports(substream, SNDRV_PCM_STREAM_CAPTURE);
+
+ /* DAI work must be started/stopped at least 250us after ABE */
+ udelay(250);
+
+ /* trigger ALL BE ports */
+ trigger_be_ports(substream, cmd);
+
+ /* Enable Frontend sDMA */
+ enable_fe_ports(substream, SNDRV_PCM_STREAM_CAPTURE);
+
+ /* Restore ABE GAINS AMIC */
+ unmute_be_capture(substream);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ /* Enable sDMA / Enable ABE MM_UL2 */
+ enable_fe_ports(substream, SNDRV_PCM_STREAM_CAPTURE);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ /* Disable sDMA / Enable ABE MM_UL2 */
+ disable_fe_ports(substream, SNDRV_PCM_STREAM_CAPTURE);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ /* Disable sDMA */
+ disable_fe_ports(substream, SNDRV_PCM_STREAM_CAPTURE);
+
+ disable_be_ports(substream, SNDRV_PCM_STREAM_CAPTURE);
+
+ /* DAI work must be started/stopped at least 250us after ABE */
+ udelay(250);
+
+ /* trigger ALL BE ports */
+ trigger_be_ports(substream, cmd);
+ break;
+ default:
+ break;
+ }
+
+ dev_dbg(&rtd->dev, "%s - finish: fe ID=%d stream %d\n",
+ __func__, rtd->cpu_dai->id, substream->stream);
+}
+
+static void playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ dev_dbg(&rtd->dev, "%s-start: fe ID=%d stream %d\n",
+ __func__, rtd->cpu_dai->id, substream->stream);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* mute splayback */
+ mute_be_playback(substream);
+
+ /* enabled BE ports */
+ enable_be_ports(substream, SNDRV_PCM_STREAM_PLAYBACK);
+
+ /* DAI work must be started/stopped at least 250us after ABE */
+ udelay(250);
+
+ /* trigger ALL BE ports */
+ trigger_be_ports(substream, cmd);
+
+ /* TODO: unmute DL1 */
+ unmute_be_playback(substream);
+
+ /* Enable Frontend sDMA */
+ enable_fe_ports(substream, SNDRV_PCM_STREAM_PLAYBACK);
+
+ /* unmute ABE_MM_DL */
+ unmute_fe_port(substream, SNDRV_PCM_STREAM_PLAYBACK);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ /* Enable Frontend sDMA */
+ enable_fe_ports(substream, SNDRV_PCM_STREAM_PLAYBACK);
+
+ /* unmute ABE_MM_DL */
+ unmute_fe_port(substream, SNDRV_PCM_STREAM_PLAYBACK);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ /* Enable Frontend sDMA */
+ disable_fe_ports(substream, SNDRV_PCM_STREAM_PLAYBACK);
+
+ /* mute ABE_MM_DL */
+ mute_fe_port(substream, SNDRV_PCM_STREAM_PLAYBACK);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ /* disable the transfer */
+ disable_fe_ports(substream, SNDRV_PCM_STREAM_PLAYBACK);
+
+ /* mute ABE_MM_DL */
+ mute_fe_port(substream, SNDRV_PCM_STREAM_PLAYBACK);
+
+ /* TODO :mute Phoenix */
+
+ /* disable our backends */
+ disable_be_ports(substream, SNDRV_PCM_STREAM_PLAYBACK);
+
+ /* DAI work must be started/stopped at least 250us after ABE */
+ udelay(250);
+
+ /* trigger ALL BE ports */
+ trigger_be_ports(substream, cmd);
+ break;
+ default:
+ break;
+ }
+
+ dev_dbg(&rtd->dev, "%s - finish: fe ID=%d stream %d\n",
+ __func__, rtd->cpu_dai->id, substream->stream);
+}
+
+static int omap_abe_dai_probe(struct snd_soc_dai *dai)
+{
+ snd_soc_dai_set_drvdata(dai, &abe_data);
+
+ abe_data.workqueue = create_singlethread_workqueue("omap-abe");
+ if (abe_data.workqueue == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static int omap_abe_dai_remove(struct snd_soc_dai *dai)
+{
+ destroy_workqueue(abe_data.workqueue);
+ return 0;
+}
+
+static struct snd_soc_dai_driver omap_abe_dai[] = {
+ { /* Multimedia Playback and Capture */
+ .name = "MultiMedia1",
+ .probe = omap_abe_dai_probe,
+ .remove = omap_abe_dai_remove,
+ .playback = {
+ .stream_name = "MultiMedia1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = OMAP_ABE_FORMATS,
+ },
+ .capture = {
+ .stream_name = "MultiMedia1 Capture",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = OMAP_ABE_FORMATS,
+ },
+ .ops = &omap_abe_dai_ops,
+ },
+ { /* Multimedia Capture */
+ .name = "MultiMedia2",
+ .capture = {
+ .stream_name = "MultiMedia2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = OMAP_ABE_FORMATS,
+ },
+ .ops = &omap_abe_dai_ops,
+ },
+ { /* Voice Playback and Capture */
+ .name = "Voice",
+ .playback = {
+ .stream_name = "Voice Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = OMAP_ABE_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Voice Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = OMAP_ABE_FORMATS,
+ },
+ .ops = &omap_abe_dai_ops,
+ },
+ { /* Tones Playback */
+ .name = "Tones",
+ .playback = {
+ .stream_name = "Tones Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = OMAP_ABE_FORMATS,
+ },
+ .ops = &omap_abe_dai_ops,
+ },
+ { /* Vibra */
+ .name = "Vibra",
+ .playback = {
+ .stream_name = "Vibra Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .formats = OMAP_ABE_FORMATS,
+ },
+ .ops = &omap_abe_dai_ops,
+ },
+ { /* MODEM Voice Playback and Capture */
+ .name = "MODEM",
+ .playback = {
+ .stream_name = "Voice Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = OMAP_ABE_FORMATS | SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "Voice Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = OMAP_ABE_FORMATS | SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &omap_abe_dai_ops,
+ },
+ { /* Low Power HiFi Playback */
+ .name = "MultiMedia1 LP",
+ .playback = {
+ .stream_name = "MultiMedia1 LP Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+ .formats = OMAP_ABE_FORMATS | SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &omap_abe_dai_ops,
+ },
+};
+
+static int __devinit omap_abe_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dais(&pdev->dev, omap_abe_dai,
+ ARRAY_SIZE(omap_abe_dai));
+}
+
+static int __devexit omap_abe_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(omap_abe_dai));
+ return 0;
+}
+
+static struct platform_driver omap_abe_driver = {
+ .driver = {
+ .name = "omap-abe-dai",
+ .owner = THIS_MODULE,
+ },
+ .probe = omap_abe_probe,
+ .remove = __devexit_p(omap_abe_remove),
+};
+
+static int __init omap_abe_init(void)
+{
+ return platform_driver_register(&omap_abe_driver);
+}
+module_init(omap_abe_init);
+
+static void __exit omap_abe_exit(void)
+{
+ platform_driver_unregister(&omap_abe_driver);
+}
+module_exit(omap_abe_exit);
+
+MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
+MODULE_DESCRIPTION("OMAP ABE SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-abe.h b/sound/soc/omap/omap-abe.h
new file mode 100644
index 00000000000..bc33ad18818
--- /dev/null
+++ b/sound/soc/omap/omap-abe.h
@@ -0,0 +1,59 @@
+/*
+ * omap-abe.h
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * Contact: Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_ABE_H__
+#define __OMAP_ABE_H__
+
+#define ABE_FRONTEND_DAI_MEDIA 0
+#define ABE_FRONTEND_DAI_MEDIA_CAPTURE 1
+#define ABE_FRONTEND_DAI_VOICE 2
+#define ABE_FRONTEND_DAI_TONES 3
+#define ABE_FRONTEND_DAI_VIBRA 4
+#define ABE_FRONTEND_DAI_MODEM 5
+#define ABE_FRONTEND_DAI_LP_MEDIA 6
+
+/* This must currently match the BE order in DSP */
+#define OMAP_ABE_DAI_PDM_UL 0
+#define OMAP_ABE_DAI_PDM_DL1 1
+#define OMAP_ABE_DAI_PDM_DL2 2
+#define OMAP_ABE_DAI_PDM_VIB 3
+#define OMAP_ABE_DAI_BT_VX 4
+#define OMAP_ABE_DAI_MM_FM 5
+#define OMAP_ABE_DAI_MODEM 6
+#define OMAP_ABE_DAI_DMIC0 7
+#define OMAP_ABE_DAI_DMIC1 8
+#define OMAP_ABE_DAI_DMIC2 9
+
+#define OMAP_ABE_BE_PDM_DL1 "(Backend) PDM-DL1"
+#define OMAP_ABE_BE_PDM_UL1 "(Backend) PDM-UL1"
+#define OMAP_ABE_BE_PDM_DL2 "(Backend) PDM-DL2"
+#define OMAP_ABE_BE_PDM_VIB "(Backend) PDM-VIB"
+#define OMAP_ABE_BE_BT_VX "(Backend) BT-VX"
+#define OMAP_ABE_BE_MM_EXT0 "(Backend) FM-EXT"
+#define OMAP_ABE_BE_MM_EXT1 "(Backend) MODEM-EXT"
+#define OMAP_ABE_BE_DMIC0 "(Backend) DMIC0"
+#define OMAP_ABE_BE_DMIC1 "(Backend) DMIC1"
+#define OMAP_ABE_BE_DMIC2 "(Backend) DMIC2"
+
+
+#endif /* End of __OMAP_MCPDM_H__ */
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c
new file mode 100644
index 00000000000..886ca9bfb29
--- /dev/null
+++ b/sound/soc/omap/omap-dmic.c
@@ -0,0 +1,668 @@
+/*
+ * omap-dmic.c -- OMAP ASoC DMIC DAI driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ * David Lambert <dlambert@ti.com>
+ * Misael Lopez Cruz <misael.lopez@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+
+#include <plat/dma.h>
+#include <plat/omap_hwmod.h>
+
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "omap-dmic.h"
+#include "omap-pcm.h"
+
+#define OMAP_DMIC_RATES (SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define OMAP_DMIC_FORMATS SNDRV_PCM_FMTBIT_S32_LE
+
+struct omap_dmic {
+ struct device *dev;
+ void __iomem *io_base;
+ int irq;
+ int clk_freq;
+ int sysclk;
+ int active;
+ spinlock_t lock;
+ struct omap_dmic_link *link;
+};
+
+static struct omap_dmic_link omap_dmic_link = {
+ .irq_mask = DMIC_IRQ_EMPTY | DMIC_IRQ_FULL,
+ .threshold = 2,
+ .format = DMICOUTFORMAT_LJUST,
+ .polar = DMIC_POLAR1 | DMIC_POLAR2 | DMIC_POLAR3,
+};
+
+/*
+ * Stream DMA parameters
+ */
+static struct omap_pcm_dma_data omap_dmic_dai_dma_params = {
+ .name = "DMIC capture",
+ .data_type = OMAP_DMA_DATA_TYPE_S32,
+ .sync_mode = OMAP_DMA_SYNC_PACKET,
+ .packet_size = 2,
+ .port_addr = OMAP44XX_DMIC_L3_BASE + DMIC_DATA,
+};
+
+
+static inline void omap_dmic_write(struct omap_dmic *dmic,
+ u16 reg, u32 val)
+{
+ __raw_writel(val, dmic->io_base + reg);
+}
+
+static inline int omap_dmic_read(struct omap_dmic *dmic, u16 reg)
+{
+ return __raw_readl(dmic->io_base + reg);
+}
+
+#ifdef DEBUG
+static void omap_dmic_reg_dump(struct omap_dmic *dmic)
+{
+ dev_dbg(dmic->dev, "***********************\n");
+ dev_dbg(dmic->dev, "DMIC_IRQSTATUS_RAW: 0x%04x\n",
+ omap_dmic_read(dmic, DMIC_IRQSTATUS_RAW));
+ dev_dbg(dmic->dev, "DMIC_IRQSTATUS: 0x%04x\n",
+ omap_dmic_read(dmic, DMIC_IRQSTATUS));
+ dev_dbg(dmic->dev, "DMIC_IRQENABLE_SET: 0x%04x\n",
+ omap_dmic_read(dmic, DMIC_IRQENABLE_SET));
+ dev_dbg(dmic->dev, "DMIC_IRQENABLE_CLR: 0x%04x\n",
+ omap_dmic_read(dmic, DMIC_IRQENABLE_CLR));
+ dev_dbg(dmic->dev, "DMIC_IRQWAKE_EN: 0x%04x\n",
+ omap_dmic_read(dmic, DMIC_IRQWAKE_EN));
+ dev_dbg(dmic->dev, "DMIC_DMAENABLE_SET: 0x%04x\n",
+ omap_dmic_read(dmic, DMIC_DMAENABLE_SET));
+ dev_dbg(dmic->dev, "DMIC_DMAENABLE_CLR: 0x%04x\n",
+ omap_dmic_read(dmic, DMIC_DMAENABLE_CLR));
+ dev_dbg(dmic->dev, "DMIC_DMAWAKEEN: 0x%04x\n",
+ omap_dmic_read(dmic, DMIC_DMAWAKEEN));
+ dev_dbg(dmic->dev, "DMIC_CTRL: 0x%04x\n",
+ omap_dmic_read(dmic, DMIC_CTRL));
+ dev_dbg(dmic->dev, "DMIC_DATA: 0x%04x\n",
+ omap_dmic_read(dmic, DMIC_DATA));
+ dev_dbg(dmic->dev, "DMIC_FIFO_CTRL: 0x%04x\n",
+ omap_dmic_read(dmic, DMIC_FIFO_CTRL));
+ dev_dbg(dmic->dev, "DMIC_FIFO_DMIC1R_DATA: 0x%08x\n",
+ omap_dmic_read(dmic, DMIC_FIFO_DMIC1R_DATA));
+ dev_dbg(dmic->dev, "DMIC_FIFO_DMIC1L_DATA: 0x%08x\n",
+ omap_dmic_read(dmic, DMIC_FIFO_DMIC1L_DATA));
+ dev_dbg(dmic->dev, "DMIC_FIFO_DMIC2R_DATA: 0x%08x\n",
+ omap_dmic_read(dmic, DMIC_FIFO_DMIC2R_DATA));
+ dev_dbg(dmic->dev, "DMIC_FIFO_DMIC2L_DATA: 0x%08x\n",
+ omap_dmic_read(dmic, DMIC_FIFO_DMIC2L_DATA));
+ dev_dbg(dmic->dev, "DMIC_FIFO_DMIC3R_DATA: 0x%08x\n",
+ omap_dmic_read(dmic, DMIC_FIFO_DMIC3R_DATA));
+ dev_dbg(dmic->dev, "DMIC_FIFO_DMIC3L_DATA: 0x%08x\n",
+ omap_dmic_read(dmic, DMIC_FIFO_DMIC3L_DATA));
+ dev_dbg(dmic->dev, "***********************\n");
+}
+#else
+static void omap_dmic_reg_dump(struct omap_dmic *dmic) {}
+#endif
+
+/*
+ * Enables the transfer through the DMIC interface
+ */
+static void omap_dmic_start(struct omap_dmic *dmic, int channels)
+{
+ int ctrl = omap_dmic_read(dmic, DMIC_CTRL);
+ omap_dmic_write(dmic, DMIC_CTRL, ctrl | channels);
+}
+
+/*
+ * Disables the transfer through the DMIC interface
+ */
+static void omap_dmic_stop(struct omap_dmic *dmic, int channels)
+{
+ int ctrl = omap_dmic_read(dmic, DMIC_CTRL);
+ omap_dmic_write(dmic, DMIC_CTRL, ctrl & ~channels);
+}
+
+/*
+ * Configures DMIC for audio recording.
+ * This function should be called before omap_dmic_start.
+ */
+static int omap_dmic_open(struct omap_dmic *dmic)
+{
+ struct omap_dmic_link *link = dmic->link;
+ int ctrl;
+
+ /* Enable irq request generation */
+ omap_dmic_write(dmic, DMIC_IRQENABLE_SET,
+ link->irq_mask & DMIC_IRQ_MASK);
+
+ /* Configure uplink threshold */
+ if (link->threshold > DMIC_THRES_MAX)
+ link->threshold = DMIC_THRES_MAX;
+
+ omap_dmic_write(dmic, DMIC_FIFO_CTRL, link->threshold);
+
+ /* Configure DMA controller */
+ omap_dmic_write(dmic, DMIC_DMAENABLE_SET, DMIC_DMA_ENABLE);
+
+ /* Set dmic out format */
+ ctrl = omap_dmic_read(dmic, DMIC_CTRL)
+ & ~(DMIC_FORMAT | DMIC_POLAR_MASK);
+ omap_dmic_write(dmic, DMIC_CTRL,
+ ctrl | link->format | link->polar);
+
+ return 0;
+}
+
+/*
+ * Cleans DMIC uplink configuration.
+ * This function should be called when the stream is closed.
+ */
+static int omap_dmic_close(struct omap_dmic *dmic)
+{
+ struct omap_dmic_link *link = dmic->link;
+
+ /* Disable irq request generation */
+ omap_dmic_write(dmic, DMIC_IRQENABLE_CLR,
+ link->irq_mask & DMIC_IRQ_MASK);
+
+ /* Disable DMA request generation */
+ omap_dmic_write(dmic, DMIC_DMAENABLE_CLR, DMIC_DMA_ENABLE);
+
+ return 0;
+}
+
+static irqreturn_t omap_dmic_irq_handler(int irq, void *dev_id)
+{
+ struct omap_dmic *dmic = dev_id;
+ int irq_status;
+
+ irq_status = omap_dmic_read(dmic, DMIC_IRQSTATUS);
+
+ /* Acknowledge irq event */
+ omap_dmic_write(dmic, DMIC_IRQSTATUS, irq_status);
+ if (irq_status & DMIC_IRQ_FULL)
+ dev_dbg(dmic->dev, "DMIC FIFO error %x\n", irq_status);
+
+ if (irq_status & DMIC_IRQ_EMPTY)
+ dev_dbg(dmic->dev, "DMIC FIFO error %x\n", irq_status);
+
+ if (irq_status & DMIC_IRQ)
+ dev_dbg(dmic->dev, "DMIC write request\n");
+
+ return IRQ_HANDLED;
+}
+
+static int omap_dmic_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+
+ if (!dmic->active++)
+ pm_runtime_get_sync(dmic->dev);
+
+ return 0;
+}
+
+static void omap_dmic_dai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+
+ if (!--dmic->active)
+ pm_runtime_put_sync(dmic->dev);
+}
+
+static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+ struct omap_dmic_link *link = dmic->link;
+ int channels;
+ int ret = 0;
+
+ channels = params_channels(params);
+ switch (channels) {
+ case 1:
+ case 2:
+ link->channels = 2;
+ break;
+ default:
+ dev_err(dmic->dev, "invalid number of channels\n");
+ return -EINVAL;
+ }
+
+ omap_dmic_dai_dma_params.packet_size = link->threshold * link->channels;
+ snd_soc_dai_set_dma_data(dai, substream, &omap_dmic_dai_dma_params);
+
+ if (dmic->active == 1)
+ ret = omap_dmic_open(dmic);
+
+ return ret;
+}
+
+static int omap_dmic_dai_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+ struct omap_dmic_link *link = dmic->link;
+ int ret = 0;
+
+ if (dmic->active == 1) {
+ ret = omap_dmic_close(dmic);
+ link->channels = 0;
+ }
+
+ return ret;
+}
+
+static int omap_dmic_dai_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+ int dmic_id = 1 << dai->id;
+
+ omap_dmic_reg_dump(dmic);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ omap_dmic_start(dmic, dmic_id);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ omap_dmic_stop(dmic, dmic_id);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int omap_dmic_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq,
+ int dir)
+{
+ struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+ struct clk *dmic_clk, *parent_clk;
+ int ret = 0;
+
+ dmic_clk = clk_get(NULL, "dmic_fck");
+ if (IS_ERR(dmic_clk))
+ return -ENODEV;
+
+ switch (clk_id) {
+ case OMAP_DMIC_SYSCLK_PAD_CLKS:
+ parent_clk = clk_get(NULL, "pad_clks_ck");
+ if (IS_ERR(parent_clk)) {
+ ret = -ENODEV;
+ goto err_par;
+ }
+ break;
+ case OMAP_DMIC_SYSCLK_SLIMBLUS_CLKS:
+ parent_clk = clk_get(NULL, "slimbus_clk");
+ if (IS_ERR(parent_clk)) {
+ ret = -ENODEV;
+ goto err_par;
+ }
+ break;
+ case OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS:
+ parent_clk = clk_get(NULL, "dmic_sync_mux_ck");
+ if (IS_ERR(parent_clk)) {
+ ret = -ENODEV;
+ goto err_par;
+ }
+ break;
+ default:
+ dev_err(dai->dev, "clk_id not supported %d\n", clk_id);
+ ret = -EINVAL;
+ goto err_par;
+ }
+
+ switch (freq) {
+ case 19200000:
+ case 24000000:
+ case 24576000:
+ case 12000000:
+ dmic->clk_freq = freq;
+ break;
+ default:
+ dev_err(dai->dev, "clk freq not supported %d\n", freq);
+ ret = -EINVAL;
+ goto err_freq;
+ }
+
+ if (dmic->sysclk != clk_id) {
+ /* reparent not allowed if a stream is ongoing */
+ if (dmic->active > 1)
+ return -EBUSY;
+
+ /* disable clock while reparenting */
+ if (dmic->active == 1)
+ pm_runtime_put_sync(dmic->dev);
+
+ ret = clk_set_parent(dmic_clk, parent_clk);
+
+ if (dmic->active == 1)
+ pm_runtime_get_sync(dmic->dev);
+
+ dmic->sysclk = clk_id;
+ }
+
+err_freq:
+ clk_put(parent_clk);
+err_par:
+ clk_put(dmic_clk);
+
+ return ret;
+}
+
+static int omap_dmic_set_clkdiv(struct snd_soc_dai *dai,
+ int div_id, int div)
+{
+ struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+ int ctrl, div_sel = -EINVAL;
+
+ if (div_id != OMAP_DMIC_CLKDIV)
+ return -ENODEV;
+
+ switch (dmic->clk_freq) {
+ case 19200000:
+ if (div == 5)
+ div_sel = 0x1;
+ else if (div == 8)
+ div_sel = 0x0;
+ break;
+ case 24000000:
+ if (div == 10)
+ div_sel = 0x2;
+ break;
+ case 24576000:
+ if (div == 8)
+ div_sel = 0x3;
+ else if (div == 16)
+ div_sel = 0x4;
+ break;
+ case 12000000:
+ if (div == 5)
+ div_sel = 0x5;
+ break;
+ default:
+ dev_err(dai->dev, "invalid freq %d\n", dmic->clk_freq);
+ return -EINVAL;
+ }
+
+ if (div_sel < 0) {
+ dev_err(dai->dev, "divider not supported %d\n", div);
+ return -EINVAL;
+ }
+
+ ctrl = omap_dmic_read(dmic, DMIC_CTRL) & ~DMIC_CLK_DIV_MASK;
+ omap_dmic_write(dmic, DMIC_CTRL,
+ ctrl | (div_sel << DMIC_CLK_DIV_SHIFT));
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops omap_dmic_dai_ops = {
+ .startup = omap_dmic_dai_startup,
+ .shutdown = omap_dmic_dai_shutdown,
+ .hw_params = omap_dmic_dai_hw_params,
+ .trigger = omap_dmic_dai_trigger,
+ .hw_free = omap_dmic_dai_hw_free,
+ .set_sysclk = omap_dmic_set_dai_sysclk,
+ .set_clkdiv = omap_dmic_set_clkdiv,
+};
+
+#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP) || \
+ defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE)
+static int omap_dmic_abe_dai_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+ int dmic_id = DMIC_UP1_ENABLE | DMIC_UP2_ENABLE | DMIC_UP3_ENABLE;
+
+ omap_dmic_reg_dump(dmic);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ if (dmic->active == 1)
+ omap_dmic_start(dmic, dmic_id);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ if (dmic->active == 1)
+ omap_dmic_stop(dmic, dmic_id);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops omap_dmic_abe_dai_ops = {
+ .startup = omap_dmic_dai_startup,
+ .shutdown = omap_dmic_dai_shutdown,
+ .hw_params = omap_dmic_dai_hw_params,
+ .trigger = omap_dmic_abe_dai_trigger,
+ .hw_free = omap_dmic_dai_hw_free,
+ .set_sysclk = omap_dmic_set_dai_sysclk,
+ .set_clkdiv = omap_dmic_set_clkdiv,
+};
+#endif
+
+static struct snd_soc_dai_driver omap_dmic_dai[] = {
+{
+ .name = "omap-dmic-dai-0",
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = OMAP_DMIC_RATES,
+ .formats = OMAP_DMIC_FORMATS,
+ },
+ .ops = &omap_dmic_dai_ops,
+},
+{
+ .name = "omap-dmic-dai-1",
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = OMAP_DMIC_RATES,
+ .formats = OMAP_DMIC_FORMATS,
+ },
+ .ops = &omap_dmic_abe_dai_ops,
+},
+{
+ .name = "omap-dmic-dai-2",
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = OMAP_DMIC_RATES,
+ .formats = OMAP_DMIC_FORMATS,
+ },
+ .ops = &omap_dmic_abe_dai_ops,
+},
+#if defined(CONFIG_SND_OMAP_SOC_ABE_DSP) || \
+ defined(CONFIG_SND_OMAP_SOC_ABE_DSP_MODULE)
+{
+ .name = "omap-dmic-abe-dai-0",
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = OMAP_DMIC_RATES,
+ .formats = OMAP_DMIC_FORMATS,
+ },
+ .ops = &omap_dmic_abe_dai_ops,
+},
+{
+ .name = "omap-dmic-abe-dai-1",
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = OMAP_DMIC_RATES,
+ .formats = OMAP_DMIC_FORMATS,
+ },
+ .ops = &omap_dmic_abe_dai_ops,
+},
+{
+ .name = "omap-dmic-abe-dai-2",
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = OMAP_DMIC_RATES,
+ .formats = OMAP_DMIC_FORMATS,
+ },
+ .ops = &omap_dmic_abe_dai_ops,
+},
+#endif
+};
+
+static __devinit int asoc_dmic_probe(struct platform_device *pdev)
+{
+ struct omap_dmic *dmic;
+ struct resource *res;
+ int ret;
+
+ dmic = kzalloc(sizeof(struct omap_dmic), GFP_KERNEL);
+ if (!dmic)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, dmic);
+ dmic->dev = &pdev->dev;
+ dmic->link = &omap_dmic_link;
+
+ spin_lock_init(&dmic->lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dmic->dev, "invalid memory resource\n");
+ ret = -ENODEV;
+ goto err_res;
+ }
+
+ dmic->io_base = ioremap(res->start, resource_size(res));
+ if (!dmic->io_base) {
+ ret = -ENOMEM;
+ goto err_res;
+ }
+
+ dmic->irq = platform_get_irq(pdev, 0);
+ if (dmic->irq < 0) {
+ ret = dmic->irq;
+ goto err_irq;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res) {
+ dev_err(dmic->dev, "invalid dma resource\n");
+ ret = -ENODEV;
+ goto err_irq;
+ }
+ omap_dmic_dai_dma_params.dma_req = res->start;
+
+ pm_runtime_enable(dmic->dev);
+
+ /* Disable lines while request is ongoing */
+ omap_dmic_write(dmic, DMIC_CTRL, 0x00);
+
+ ret = request_threaded_irq(dmic->irq, NULL, omap_dmic_irq_handler,
+ IRQF_ONESHOT, "DMIC", (void *)dmic);
+ if (ret) {
+ dev_err(dmic->dev, "irq request failed\n");
+ goto err_irq;
+ }
+
+ ret = snd_soc_register_dais(&pdev->dev, omap_dmic_dai,
+ ARRAY_SIZE(omap_dmic_dai));
+ if (ret)
+ goto err_dai;
+
+ return 0;
+
+err_dai:
+ free_irq(dmic->irq, (void *)dmic);
+err_irq:
+ iounmap(dmic->io_base);
+err_res:
+ kfree(dmic);
+ return ret;
+}
+
+static int __devexit asoc_dmic_remove(struct platform_device *pdev)
+{
+ struct omap_dmic *dmic = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_dai(&pdev->dev);
+ iounmap(dmic->io_base);
+ free_irq(dmic->irq, (void *)dmic);
+ kfree(dmic);
+
+ return 0;
+}
+
+static struct platform_driver asoc_dmic_driver = {
+ .driver = {
+ .name = "omap-dmic-dai",
+ .owner = THIS_MODULE,
+ },
+ .probe = asoc_dmic_probe,
+ .remove = __devexit_p(asoc_dmic_remove),
+};
+
+static int __init snd_omap_dmic_init(void)
+{
+ return platform_driver_register(&asoc_dmic_driver);
+}
+module_init(snd_omap_dmic_init);
+
+static void __exit snd_omap_dmic_exit(void)
+{
+ platform_driver_unregister(&asoc_dmic_driver);
+}
+module_exit(snd_omap_dmic_exit);
+
+MODULE_AUTHOR("David Lambert <dlambert@ti.com>");
+MODULE_DESCRIPTION("OMAP DMIC SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-dmic.h b/sound/soc/omap/omap-dmic.h
new file mode 100644
index 00000000000..4f86371f80f
--- /dev/null
+++ b/sound/soc/omap/omap-dmic.h
@@ -0,0 +1,103 @@
+/*
+ * omap-dmic.h -- OMAP Digital Microphone Controller
+ *
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ * David Lambert <dlambert@ti.com>
+ * Misael Lopez Cruz <misael.lopez@ti.com>
+ *
+ * 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.
+ */
+
+#ifndef _OMAP_DMIC_H
+#define _OMAP_DMIC_H
+
+#include <sound/soc.h>
+
+#define OMAP44XX_DMIC_L3_BASE 0x4902e000
+
+#define DMIC_REVISION 0x00
+#define DMIC_SYSCONFIG 0x10
+#define DMIC_IRQSTATUS_RAW 0x24
+#define DMIC_IRQSTATUS 0x28
+#define DMIC_IRQENABLE_SET 0x2C
+#define DMIC_IRQENABLE_CLR 0x30
+#define DMIC_IRQWAKE_EN 0x34
+#define DMIC_DMAENABLE_SET 0x38
+#define DMIC_DMAENABLE_CLR 0x3C
+#define DMIC_DMAWAKEEN 0x40
+#define DMIC_CTRL 0x44
+#define DMIC_DATA 0x48
+#define DMIC_FIFO_CTRL 0x4C
+#define DMIC_FIFO_DMIC1R_DATA 0x50
+#define DMIC_FIFO_DMIC1L_DATA 0x54
+#define DMIC_FIFO_DMIC2R_DATA 0x58
+#define DMIC_FIFO_DMIC2L_DATA 0x5C
+#define DMIC_FIFO_DMIC3R_DATA 0x60
+#define DMIC_FIFO_DMIC3L_DATA 0x64
+
+/*
+ * DMIC_IRQ bit fields
+ * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR
+ */
+
+#define DMIC_IRQ (1 << 0)
+#define DMIC_IRQ_FULL (1 << 1)
+#define DMIC_IRQ_ALMST_EMPTY (1 << 2)
+#define DMIC_IRQ_EMPTY (1 << 3)
+#define DMIC_IRQ_MASK 0x07
+
+/*
+ * DMIC_DMAENABLE bit fields
+ */
+
+#define DMIC_DMA_ENABLE 0x1
+
+/*
+ * DMIC_CTRL bit fields
+ */
+
+#define DMIC_UP1_ENABLE 0x0001
+#define DMIC_UP2_ENABLE 0x0002
+#define DMIC_UP3_ENABLE 0x0004
+#define DMIC_FORMAT 0x0008
+#define DMIC_POLAR1 0x0010
+#define DMIC_POLAR2 0x0020
+#define DMIC_POLAR3 0x0040
+#define DMIC_POLAR_MASK 0x0070
+#define DMIC_CLK_DIV_SHIFT 7
+#define DMIC_CLK_DIV_MASK 0x0380
+#define DMIC_RESET 0x0400
+
+#define DMIC_ENABLE_MASK 0x007
+
+#define DMICOUTFORMAT_LJUST (0 << 3)
+#define DMICOUTFORMAT_RJUST (1 << 3)
+
+/*
+ * DMIC_FIFO_CTRL bit fields
+ */
+
+#define DMIC_THRES_MAX 0xF
+
+enum omap_dmic_clk {
+ OMAP_DMIC_SYSCLK_PAD_CLKS, /* PAD_CLKS */
+ OMAP_DMIC_SYSCLK_SLIMBLUS_CLKS, /* SLIMBUS_CLK */
+ OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS, /* DMIC_SYNC_MUX_CLK */
+};
+
+/* DMIC dividers */
+enum omap_dmic_div {
+ OMAP_DMIC_CLKDIV,
+};
+
+struct omap_dmic_link {
+ int irq_mask;
+ int threshold;
+ int format;
+ int channels;
+ int polar;
+};
+
+#endif
diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c
new file mode 100644
index 00000000000..e19f062788c
--- /dev/null
+++ b/sound/soc/omap/omap-hdmi.c
@@ -0,0 +1,150 @@
+/*
+ * omap-hdmi.c
+ *
+ * OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors.
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Authors: Jorge Candelaria <jorge.candelaria@gmail.com>
+ * Ricardo Neri <ricardo.neri@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <plat/dma.h>
+#include <plat/display.h>
+#include <plat/omap44xx.h>
+#include "omap-pcm.h"
+#include "omap-hdmi.h"
+
+static struct omap_pcm_dma_data omap_hdmi_dai_dma_params = {
+ .name = "HDMI playback",
+ .dma_req = OMAP44XX_DMA_DSS_HDMI_REQ,
+ .port_addr = OMAP44XX_DSS_HDMI_L3_BASE + OMAP44XX_HDMI_AUDIO_DMA_PORT,
+ .sync_mode = OMAP_DMA_SYNC_PACKET,
+};
+
+static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int err = 0, i;
+ struct omap_overlay *ovl = NULL;
+
+ /*
+ * Make sure that the period bytes are multiple of the DMA packet size.
+ * Largest packet size we use is 32 32-bit words = 128 bytes
+ */
+ err = snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
+ if (err < 0)
+ return err;
+
+ /* find DSS HDMI device */
+ for (i = 0; i < omap_dss_get_num_overlays(); i++) {
+ ovl = omap_dss_get_overlay(i);
+ if (strcmp(ovl->manager->device->name, "hdmi") == 0)
+ break;
+ }
+ if (ovl->manager->device->state != OMAP_DSS_DISPLAY_ACTIVE) {
+ printk(KERN_ERR "HDMI display is not active!");
+ return -EIO;
+ }
+ return err;
+}
+
+static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ int err = 0;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ omap_hdmi_dai_dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
+ omap_hdmi_dai_dma_params.packet_size = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ omap_hdmi_dai_dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
+ omap_hdmi_dai_dma_params.packet_size = 32;
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ snd_soc_dai_set_dma_data(dai, substream,
+ &omap_hdmi_dai_dma_params);
+
+ return err;
+}
+
+static struct snd_soc_dai_ops omap_hdmi_dai_ops = {
+ .startup = omap_hdmi_dai_startup,
+ .hw_params = omap_hdmi_dai_hw_params,
+};
+
+static struct snd_soc_dai_driver omap_hdmi_dai = {
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = OMAP_HDMI_RATES,
+ .formats = OMAP_HDMI_FORMATS,
+ },
+ .ops = &omap_hdmi_dai_ops,
+};
+
+static __devinit int omap_hdmi_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai);
+}
+
+static int __devexit omap_hdmi_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver hdmi_dai_driver = {
+ .driver = {
+ .name = "hdmi-audio-dai",
+ .owner = THIS_MODULE,
+ },
+ .probe = omap_hdmi_probe,
+ .remove = __devexit_p(omap_hdmi_remove),
+};
+
+static int __init hdmi_dai_init(void)
+{
+ return platform_driver_register(&hdmi_dai_driver);
+}
+module_init(hdmi_dai_init);
+
+static void __exit hdmi_dai_exit(void)
+{
+ platform_driver_unregister(&hdmi_dai_driver);
+}
+module_exit(hdmi_dai_exit);
+
+MODULE_AUTHOR("Jorge Candelaria <jorge.candelaria@gmail.com>");
+MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
+MODULE_DESCRIPTION("OMAP HDMI SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-hdmi.h b/sound/soc/omap/omap-hdmi.h
new file mode 100644
index 00000000000..77bc7851f37
--- /dev/null
+++ b/sound/soc/omap/omap-hdmi.h
@@ -0,0 +1,36 @@
+/*
+ * omap-hdmi.h
+ *
+ * Definitions for OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors.
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Autors: Jorge Candelaria <jorge.candelaria@gmail.com>
+ * Ricardo Neri <ricardo.neri@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_HDMI_H__
+#define __OMAP_HDMI_H__
+
+#define OMAP44XX_HDMI_AUDIO_DMA_PORT 0x8c
+
+#define OMAP_HDMI_RATES (SNDRV_PCM_RATE_32000 | \
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define OMAP_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+#endif
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 2175f09e57b..a7f6ece85eb 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -102,6 +102,7 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, words);
}
+#if 0
static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
@@ -120,6 +121,7 @@ static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
frames.integer = 1;
return snd_interval_refine(buffer_size, &frames);
}
+#endif
static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
@@ -151,6 +153,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
* Rule for the buffer size. We should not allow
* smaller buffer than the FIFO size to avoid underruns
*/
+#if 0 // FIXME: All BE must support hw_rules and constraints */
snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS,
omap_mcbsp_hwrule_min_buffersize,
@@ -160,6 +163,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
/* Make sure, that the period size is always even */
snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
+#endif
}
return err;
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index bed09c27e44..a68546d228a 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -25,7 +25,17 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/workqueue.h>
+
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -33,35 +43,62 @@
#include <sound/soc.h>
#include <plat/dma.h>
+#include <plat/mcpdm.h>
#include <plat/mcbsp.h>
-#include "mcpdm.h"
+#include <plat/omap_hwmod.h>
+#include "omap-mcpdm.h"
#include "omap-pcm.h"
+#ifdef CONFIG_SND_OMAP_SOC_ABE_DSP
+#include "omap-abe-dsp.h"
+#include "abe/abe_main.h"
+#endif
struct omap_mcpdm_data {
struct omap_mcpdm_link *links;
- int active;
+};
+
+struct omap_mcpdm {
+ struct device *dev;
+ unsigned long phys_base;
+ void __iomem *io_base;
+ u8 free;
+ int irq;
+ struct delayed_work delayed_work;
+#ifdef CONFIG_SND_OMAP_SOC_ABE_DSP
+ struct delayed_work delayed_abe_work;
+#endif
+
+ struct mutex mutex;
+ struct omap_mcpdm_platform_data *pdata;
+ struct omap_mcpdm_link *downlink;
+ struct omap_mcpdm_link *uplink;
+ struct completion irq_completion;
+
+ int dn_channels;
+ int up_channels;
+ int dl_active;
+ int ul_active;
+
+ /* DC offset */
+ int dl1_offset;
+ int dl2_offset;
};
static struct omap_mcpdm_link omap_mcpdm_links[] = {
/* downlink */
{
.irq_mask = MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL,
- .threshold = 1,
+ .threshold = 2,
.format = PDMOUTFORMAT_LJUST,
},
/* uplink */
{
.irq_mask = MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL,
- .threshold = 1,
+ .threshold = 2,
.format = PDMOUTFORMAT_LJUST,
},
};
-static struct omap_mcpdm_data mcpdm_data = {
- .links = omap_mcpdm_links,
- .active = 0,
-};
-
/*
* Stream DMA parameters
*/
@@ -84,13 +121,413 @@ static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
},
};
+static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm,
+ u16 reg, u32 val)
+{
+ __raw_writel(val, mcpdm->io_base + reg);
+}
+
+static inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg)
+{
+ return __raw_readl(mcpdm->io_base + reg);
+}
+
+#ifdef DEBUG
+static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm)
+{
+ dev_dbg(mcpdm->dev, "***********************\n");
+ dev_dbg(mcpdm->dev, "IRQSTATUS_RAW: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_IRQSTATUS_RAW));
+ dev_dbg(mcpdm->dev, "IRQSTATUS: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_IRQSTATUS));
+ dev_dbg(mcpdm->dev, "IRQENABLE_SET: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_IRQENABLE_SET));
+ dev_dbg(mcpdm->dev, "IRQENABLE_CLR: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_IRQENABLE_CLR));
+ dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_IRQWAKE_EN));
+ dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_DMAENABLE_SET));
+ dev_dbg(mcpdm->dev, "DMAENABLE_CLR: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_DMAENABLE_CLR));
+ dev_dbg(mcpdm->dev, "DMAWAKEEN: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_DMAWAKEEN));
+ dev_dbg(mcpdm->dev, "CTRL: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_CTRL));
+ dev_dbg(mcpdm->dev, "DN_DATA: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_DN_DATA));
+ dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_UP_DATA));
+ dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_FIFO_CTRL_DN));
+ dev_dbg(mcpdm->dev, "FIFO_CTRL_UP: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_FIFO_CTRL_UP));
+ dev_dbg(mcpdm->dev, "DN_OFFSET: 0x%04x\n",
+ omap_mcpdm_read(mcpdm, MCPDM_DN_OFFSET));
+ dev_dbg(mcpdm->dev, "***********************\n");
+}
+#else
+static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {}
+#endif
+
+/*
+ * Takes the McPDM module in and out of reset state.
+ * Uplink and downlink can be reset individually.
+ */
+static void omap_mcpdm_reset_capture(struct omap_mcpdm * mcpdm,
+ int reset)
+{
+ int ctrl = omap_mcpdm_read(mcpdm, MCPDM_CTRL);
+
+ if (reset)
+ ctrl |= SW_UP_RST;
+ else
+ ctrl &= ~SW_UP_RST;
+
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+}
+
+static void omap_mcpdm_reset_playback(struct omap_mcpdm * mcpdm,
+ int reset)
+{
+ int ctrl = omap_mcpdm_read(mcpdm, MCPDM_CTRL);
+
+ if (reset)
+ ctrl |= SW_DN_RST;
+ else
+ ctrl &= ~SW_DN_RST;
+
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+}
+
+/*
+ * Enables the transfer through the PDM interface to/from the Phoenix
+ * codec by enabling the corresponding UP or DN channels.
+ */
+static void omap_mcpdm_start(struct omap_mcpdm *mcpdm, int stream)
+{
+ int ctrl = omap_mcpdm_read(mcpdm, MCPDM_CTRL);
+
+ if (stream) {
+ ctrl |= SW_UP_RST;
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+ ctrl |= mcpdm->up_channels;
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+ ctrl &= ~SW_UP_RST;
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+ } else {
+ ctrl |= SW_DN_RST;
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+ ctrl |= mcpdm->dn_channels;
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+ ctrl &= ~SW_DN_RST;
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+ }
+}
+
+/*
+ * Disables the transfer through the PDM interface to/from the Phoenix
+ * codec by disabling the corresponding UP or DN channels.
+ */
+static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm, int stream)
+{
+ int ctrl = omap_mcpdm_read(mcpdm, MCPDM_CTRL);
+
+ if (stream) {
+ ctrl |= SW_UP_RST;
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+ ctrl &= ~mcpdm->up_channels;
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+ ctrl &= ~SW_UP_RST;
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+ } else {
+ ctrl |= SW_DN_RST;
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+ ctrl &= ~mcpdm->dn_channels;
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+ ctrl &= ~SW_DN_RST;
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+ }
+}
+
+/*
+ * Configures McPDM uplink for audio recording.
+ * This function should be called before omap_mcpdm_start.
+ */
+static int omap_mcpdm_capture_open(struct omap_mcpdm *mcpdm,
+ struct omap_mcpdm_link *uplink)
+{
+ int irq_mask = 0;
+ int ctrl;
+
+ /* Enable irq request generation */
+ irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK;
+ omap_mcpdm_write(mcpdm, MCPDM_IRQENABLE_SET, irq_mask);
+
+ /* Configure uplink threshold */
+ if (uplink->threshold > UP_THRES_MAX)
+ uplink->threshold = UP_THRES_MAX;
+
+ omap_mcpdm_write(mcpdm, MCPDM_FIFO_CTRL_UP, uplink->threshold);
+
+ /* Configure DMA controller */
+ omap_mcpdm_write(mcpdm, MCPDM_DMAENABLE_SET, DMA_UP_ENABLE);
+
+ /* Set pdm out format */
+ ctrl = omap_mcpdm_read(mcpdm, MCPDM_CTRL);
+ ctrl &= ~PDMOUTFORMAT;
+ ctrl |= uplink->format & PDMOUTFORMAT;
+
+ /* Uplink channels */
+ mcpdm->up_channels = uplink->channels & (PDM_UP_MASK | PDM_STATUS_MASK);
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+
+ return 0;
+}
+
+/*
+ * Configures McPDM downlink for audio playback.
+ * This function should be called before omap_mcpdm_start.
+ */
+static int omap_mcpdm_playback_open(struct omap_mcpdm *mcpdm,
+ struct omap_mcpdm_link *downlink)
+{
+ int irq_mask = 0;
+ int ctrl;
+
+ /* Enable irq request generation */
+ irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK;
+ omap_mcpdm_write(mcpdm, MCPDM_IRQENABLE_SET, irq_mask);
+
+ /* Configure uplink threshold */
+ if (downlink->threshold > DN_THRES_MAX)
+ downlink->threshold = DN_THRES_MAX;
+
+ omap_mcpdm_write(mcpdm, MCPDM_FIFO_CTRL_DN, downlink->threshold);
+
+ /* Enable DMA request generation */
+ omap_mcpdm_write(mcpdm, MCPDM_DMAENABLE_SET, DMA_DN_ENABLE);
+
+ /* Set pdm out format */
+ ctrl = omap_mcpdm_read(mcpdm, MCPDM_CTRL);
+ ctrl &= ~PDMOUTFORMAT;
+ ctrl |= downlink->format & PDMOUTFORMAT;
+
+ /* Downlink channels */
+ mcpdm->dn_channels = downlink->channels & (PDM_DN_MASK | PDM_CMD_MASK);
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+
+ return 0;
+}
+
+/*
+ * Cleans McPDM uplink configuration.
+ * This function should be called when the stream is closed.
+ */
+static int omap_mcpdm_capture_close(struct omap_mcpdm *mcpdm,
+ struct omap_mcpdm_link *uplink)
+{
+ int irq_mask = 0;
+
+ /* Disable irq request generation */
+ irq_mask |= uplink->irq_mask & MCPDM_UPLINK_IRQ_MASK;
+ omap_mcpdm_write(mcpdm, MCPDM_IRQENABLE_CLR, irq_mask);
+
+ /* Disable DMA request generation */
+ omap_mcpdm_write(mcpdm, MCPDM_DMAENABLE_CLR, DMA_UP_ENABLE);
+
+ /* Clear Downlink channels */
+ mcpdm->up_channels = 0;
+
+ return 0;
+}
+
+/*
+ * Cleans McPDM downlink configuration.
+ * This function should be called when the stream is closed.
+ */
+static int omap_mcpdm_playback_close(struct omap_mcpdm *mcpdm,
+ struct omap_mcpdm_link *downlink)
+{
+ int irq_mask = 0;
+
+ /* Disable irq request generation */
+ irq_mask |= downlink->irq_mask & MCPDM_DOWNLINK_IRQ_MASK;
+ omap_mcpdm_write(mcpdm, MCPDM_IRQENABLE_CLR, irq_mask);
+
+ /* Disable DMA request generation */
+ omap_mcpdm_write(mcpdm, MCPDM_DMAENABLE_CLR, DMA_DN_ENABLE);
+
+ /* clear Downlink channels */
+ mcpdm->dn_channels = 0;
+
+ return 0;
+}
+
+static irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id)
+{
+ struct omap_mcpdm *mcpdm = dev_id;
+ int irq_status;
+
+ irq_status = omap_mcpdm_read(mcpdm, MCPDM_IRQSTATUS);
+
+ /* Acknowledge irq event */
+ omap_mcpdm_write(mcpdm, MCPDM_IRQSTATUS, irq_status);
+
+ if (irq & MCPDM_DN_IRQ_FULL) {
+ dev_err(mcpdm->dev, "DN FIFO error %x\n", irq_status);
+ omap_mcpdm_reset_playback(mcpdm, 1);
+ omap_mcpdm_playback_open(mcpdm, mcpdm->downlink);
+ omap_mcpdm_reset_playback(mcpdm, 0);
+ }
+
+ if (irq & MCPDM_DN_IRQ_EMPTY) {
+ dev_err(mcpdm->dev, "DN FIFO error %x\n", irq_status);
+ omap_mcpdm_reset_playback(mcpdm, 1);
+ omap_mcpdm_playback_open(mcpdm, mcpdm->downlink);
+ omap_mcpdm_reset_playback(mcpdm, 0);
+ }
+
+ if (irq & MCPDM_DN_IRQ) {
+ dev_dbg(mcpdm->dev, "DN write request\n");
+ }
+
+ if (irq & MCPDM_UP_IRQ_FULL) {
+ dev_err(mcpdm->dev, "UP FIFO error %x\n", irq_status);
+ omap_mcpdm_reset_capture(mcpdm, 1);
+ omap_mcpdm_capture_open(mcpdm, mcpdm->uplink);
+ omap_mcpdm_reset_capture(mcpdm, 0);
+ }
+
+ if (irq & MCPDM_UP_IRQ_EMPTY) {
+ dev_err(mcpdm->dev, "UP FIFO error %x\n", irq_status);
+ omap_mcpdm_reset_capture(mcpdm, 1);
+ omap_mcpdm_capture_open(mcpdm, mcpdm->uplink);
+ omap_mcpdm_reset_capture(mcpdm, 0);
+ }
+
+ if (irq & MCPDM_UP_IRQ) {
+ dev_dbg(mcpdm->dev, "UP write request\n");
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int omap_mcpdm_request(struct omap_mcpdm *mcpdm)
+{
+ struct platform_device *pdev;
+ struct omap_mcpdm_platform_data *pdata;
+ int ctrl;
+ int attemps = 0;
+
+ pdev = to_platform_device(mcpdm->dev);
+ pdata = pdev->dev.platform_data;
+
+ if (!mcpdm->free) {
+ dev_err(mcpdm->dev, "McPDM interface is in use\n");
+ return -EBUSY;
+ }
+ mcpdm->free = 0;
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ /* Perform SW RESET of McPDM IP */
+ ctrl = omap_mcpdm_read(mcpdm, MCPDM_SYSCONFIG);
+ ctrl |= MCPDM_SOFTRESET;
+ omap_mcpdm_write(mcpdm, MCPDM_SYSCONFIG, ctrl);
+ /* Wait completion of SW RESET */
+ while ((omap_mcpdm_read(mcpdm, MCPDM_SYSCONFIG) & MCPDM_SOFTRESET)) {
+ if (attemps++ > 10000) {
+ udelay(10);
+ dev_err(mcpdm->dev, "Could not RESET McPDM\n");
+ }
+ }
+
+ /* Disable lines while request is ongoing */
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, 0x00);
+
+ if (omap_rev() != OMAP4430_REV_ES1_0) {
+ /* Enable McPDM watch dog for ES above ES 1.0 to avoid saturation */
+ ctrl = omap_mcpdm_read(mcpdm, MCPDM_CTRL);
+ ctrl |= WD_EN;
+ omap_mcpdm_write(mcpdm, MCPDM_CTRL, ctrl);
+ }
+
+ return 0;
+}
+
+static void omap_mcpdm_free(struct omap_mcpdm *mcpdm)
+{
+ struct platform_device *pdev;
+ struct omap_mcpdm_platform_data *pdata;
+
+ pdev = to_platform_device(mcpdm->dev);
+ pdata = pdev->dev.platform_data;
+
+ if (mcpdm->free) {
+ dev_err(mcpdm->dev, "McPDM interface is already free\n");
+ return;
+ }
+ mcpdm->free = 1;
+
+ pm_runtime_put_sync(&pdev->dev);
+}
+
+/* Enable/disable DC offset cancelation for the analog
+ * headset path (PDM channels 1 and 2).
+ */
+static int omap_mcpdm_set_offset(struct omap_mcpdm *mcpdm)
+{
+ int offset;
+
+ if ((mcpdm->dl1_offset > DN_OFST_MAX) ||
+ (mcpdm->dl2_offset > DN_OFST_MAX))
+ return -EINVAL;
+
+ offset = (mcpdm->dl1_offset << DN_OFST_RX1) |
+ (mcpdm->dl2_offset << DN_OFST_RX2);
+
+ /* offset cancellation for channel 1 */
+ if (mcpdm->dl1_offset)
+ offset |= DN_OFST_RX1_EN;
+ else
+ offset &= ~DN_OFST_RX1_EN;
+
+ /* offset cancellation for channel 2 */
+ if (mcpdm->dl2_offset)
+ offset |= DN_OFST_RX2_EN;
+ else
+ offset &= ~DN_OFST_RX2_EN;
+
+ omap_mcpdm_write(mcpdm, MCPDM_DN_OFFSET, offset);
+
+ return 0;
+}
+
static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
int err = 0;
- if (!dai->active)
- err = omap_mcpdm_request();
+ dev_dbg(dai->dev, "%s: active %d\n", __func__, dai->active);
+
+ mutex_lock(&mcpdm->mutex);
+
+ /* make sure we stop any pre-existing shutdown */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ cancel_delayed_work(&mcpdm->delayed_work);
+
+ if (!dai->active && mcpdm->free) {
+ err = omap_mcpdm_request(mcpdm);
+ if (err) {
+ mutex_unlock(&mcpdm->mutex);
+ return err;
+ }
+ omap_mcpdm_set_offset(mcpdm);
+ }
+
+ mutex_unlock(&mcpdm->mutex);
return err;
}
@@ -98,44 +535,45 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- if (!dai->active)
- omap_mcpdm_free();
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+
+ dev_dbg(dai->dev, "%s: active %d\n", __func__, dai->active);
+
+ mutex_lock(&mcpdm->mutex);
+
+ if (!dai->active) {
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ omap_mcpdm_capture_close(mcpdm, mcpdm->uplink);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ schedule_delayed_work(&mcpdm->delayed_work,
+ msecs_to_jiffies(1000)); /* TODO: pdata ? */
+ }
+
+ mutex_unlock(&mcpdm->mutex);
}
-static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
+/* work to delay McPDM shutdown */
+static void playback_work(struct work_struct *work)
{
- struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
- int stream = substream->stream;
- int err = 0;
+ struct omap_mcpdm *mcpdm =
+ container_of(work, struct omap_mcpdm, delayed_work.work);
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (!mcpdm_priv->active++)
- omap_mcpdm_start(stream);
- break;
+ mutex_lock(&mcpdm->mutex);
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- if (!--mcpdm_priv->active)
- omap_mcpdm_stop(stream);
- break;
- default:
- err = -EINVAL;
- }
+ if (!mcpdm->dl_active)
+ omap_mcpdm_playback_close(mcpdm, mcpdm->downlink);
- return err;
+ if (!mcpdm->free && !mcpdm->dl_active && !mcpdm->ul_active)
+ omap_mcpdm_free(mcpdm);
+
+ mutex_unlock(&mcpdm->mutex);
}
static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
- struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
int stream = substream->stream;
int channels, err, link_mask = 0;
@@ -165,57 +603,250 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
}
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- mcpdm_links[stream].channels = link_mask << 3;
- err = omap_mcpdm_playback_open(&mcpdm_links[stream]);
+ mcpdm->downlink->channels = link_mask << 3;
+ err = omap_mcpdm_playback_open(mcpdm, &omap_mcpdm_links[0]);
} else {
- mcpdm_links[stream].channels = link_mask << 0;
- err = omap_mcpdm_capture_open(&mcpdm_links[stream]);
+ mcpdm->uplink->channels = link_mask << 0;
+ err = omap_mcpdm_capture_open(mcpdm, &omap_mcpdm_links[1]);
}
return err;
}
-static int omap_mcpdm_dai_hw_free(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
{
- struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
- struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
int stream = substream->stream;
- int err;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- err = omap_mcpdm_playback_close(&mcpdm_links[stream]);
- else
- err = omap_mcpdm_capture_close(&mcpdm_links[stream]);
+ dev_dbg(dai->dev, "cmd %d\n", cmd);
+ omap_mcpdm_reg_dump(mcpdm);
- return err;
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ omap_mcpdm_start(mcpdm, stream);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ omap_mcpdm_stop(mcpdm, stream);
+ break;
+ default:
+ break;
+ }
+ return 0;
}
static struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
.startup = omap_mcpdm_dai_startup,
.shutdown = omap_mcpdm_dai_shutdown,
- .trigger = omap_mcpdm_dai_trigger,
.hw_params = omap_mcpdm_dai_hw_params,
- .hw_free = omap_mcpdm_dai_hw_free,
+ .trigger = omap_mcpdm_dai_trigger,
};
-#define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
-#define OMAP_MCPDM_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
+#ifdef CONFIG_SND_OMAP_SOC_ABE_DSP
+static int omap_mcpdm_abe_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+ int ret = 0;
+
+ mutex_lock(&mcpdm->mutex);
+
+ /* make sure we stop any pre-existing shutdown */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ cancel_delayed_work(&mcpdm->delayed_abe_work);
+ }
+
+ if (!dai->active && mcpdm->free) {
+ ret = omap_mcpdm_request(mcpdm);
+ if (ret) {
+ mutex_unlock(&mcpdm->mutex);
+ return ret;
+ }
+ omap_mcpdm_set_offset(mcpdm);
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ mcpdm->dl_active++;
+ else
+ mcpdm->ul_active++;
+
+ mutex_unlock(&mcpdm->mutex);
+
+ return ret;
+}
+
+static void omap_mcpdm_abe_dai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+
+ dev_dbg(dai->dev, "%s: active %d\n", __func__, dai->active);
+
+ mutex_lock(&mcpdm->mutex);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ mcpdm->dl_active--;
+ else
+ mcpdm->ul_active--;
+
+ if (!dai->active) {
+ if (!mcpdm->ul_active && substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ omap_mcpdm_capture_close(mcpdm, mcpdm->uplink);
+ if (!mcpdm->free && !mcpdm->dn_channels &&
+ !mcpdm->dl_active)
+ omap_mcpdm_free(mcpdm);
+ }
+ if (!mcpdm->dl_active && substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ schedule_delayed_work(&mcpdm->delayed_abe_work,
+ msecs_to_jiffies(1000)); /* TODO: pdata ? */
+ }
+
+ mutex_unlock(&mcpdm->mutex);
+
+}
+
+/* work to delay McPDM shutdown */
+static void playback_abe_work(struct work_struct *work)
+{
+ struct omap_mcpdm *mcpdm =
+ container_of(work, struct omap_mcpdm, delayed_abe_work.work);
+
+ mutex_lock(&mcpdm->mutex);
+ if (!mcpdm->dl_active && mcpdm->dn_channels) {
+ abe_disable_data_transfer(PDM_DL_PORT);
+ udelay(250);
+ omap_mcpdm_stop(mcpdm, SNDRV_PCM_STREAM_PLAYBACK);
+ omap_mcpdm_playback_close(mcpdm, mcpdm->downlink);
+ abe_dsp_mcpdm_shutdown();
+ abe_dsp_pm_put();
+ }
+ mutex_unlock(&mcpdm->mutex);
+
+ if (!mcpdm->free && !mcpdm->ul_active && !mcpdm->dl_active)
+ omap_mcpdm_free(mcpdm);
-static int omap_mcpdm_dai_probe(struct snd_soc_dai *dai)
+}
+
+static int omap_mcpdm_abe_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
{
- snd_soc_dai_set_drvdata(dai, &mcpdm_data);
+ struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
+ int stream = substream->stream;
+ int ret = 0;
+
+ snd_soc_dai_set_dma_data(dai, substream,
+ &omap_mcpdm_dai_dma_params[stream]);
+
+ mutex_lock(&mcpdm->mutex);
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /* Check if McPDM is already started */
+ if (!mcpdm->dn_channels) {
+ abe_dsp_pm_get();
+ /* start ATC before McPDM IP */
+ abe_enable_data_transfer(PDM_DL_PORT);
+ udelay(250);
+ mcpdm->downlink->channels = (PDM_DN_MASK | PDM_CMD_MASK);
+ ret = omap_mcpdm_playback_open(mcpdm, &omap_mcpdm_links[0]);
+ if (ret < 0) {
+ mutex_unlock(&mcpdm->mutex);
+ return ret;
+ }
+
+ omap_mcpdm_start(mcpdm, stream);
+ }
+ } else {
+ mcpdm->uplink->channels = PDM_UP1_EN | PDM_UP2_EN;
+ ret = omap_mcpdm_capture_open(mcpdm, &omap_mcpdm_links[1]);
+ }
+
+ mutex_unlock(&mcpdm->mutex);
+
+ return ret;
+}
+
+
+static int omap_mcpdm_abe_dai_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ omap_mcpdm_dai_trigger(substream, cmd, dai);
+ }
+
return 0;
}
-static struct snd_soc_dai_driver omap_mcpdm_dai = {
- .probe = omap_mcpdm_dai_probe,
+static struct snd_soc_dai_ops omap_mcpdm_abe_dai_ops = {
+ .startup = omap_mcpdm_abe_dai_startup,
+ .shutdown = omap_mcpdm_abe_dai_shutdown,
+ .hw_params = omap_mcpdm_abe_dai_hw_params,
+ .trigger = omap_mcpdm_abe_dai_trigger,
+};
+#endif
+
+#define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+#define OMAP_MCPDM_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver omap_mcpdm_dai[] = {
+#ifdef CONFIG_SND_OMAP_SOC_ABE_DSP
+{
+ .name = "mcpdm-dl1",
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = OMAP_MCPDM_RATES,
+ .formats = OMAP_MCPDM_FORMATS,
+ },
+ .ops = &omap_mcpdm_abe_dai_ops,
+},
+{
+ .name = "mcpdm-dl2",
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = OMAP_MCPDM_RATES,
+ .formats = OMAP_MCPDM_FORMATS,
+ },
+ .ops = &omap_mcpdm_abe_dai_ops,
+},
+{
+ .name = "mcpdm-vib",
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = OMAP_MCPDM_RATES,
+ .formats = OMAP_MCPDM_FORMATS,
+ },
+ .ops = &omap_mcpdm_abe_dai_ops,
+},
+{
+ .name = "mcpdm-ul1",
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = OMAP_MCPDM_RATES,
+ .formats = OMAP_MCPDM_FORMATS,
+ },
+ .ops = &omap_mcpdm_abe_dai_ops,
+},
+#endif
+{
+ .name = "mcpdm-dl",
.playback = {
.channels_min = 1,
.channels_max = 4,
.rates = OMAP_MCPDM_RATES,
.formats = OMAP_MCPDM_FORMATS,
},
+ .ops = &omap_mcpdm_dai_ops,
+},
+{
+ .name = "mcpdm-ul",
.capture = {
.channels_min = 1,
.channels_max = 2,
@@ -223,25 +854,88 @@ static struct snd_soc_dai_driver omap_mcpdm_dai = {
.formats = OMAP_MCPDM_FORMATS,
},
.ops = &omap_mcpdm_dai_ops,
-};
+}, };
static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
{
- int ret;
+ struct omap_mcpdm *mcpdm;
+ struct resource *res;
+ int ret = 0;
+
+ mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL);
+ if (!mcpdm)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, mcpdm);
+ mcpdm->downlink = &omap_mcpdm_links[0];
+ mcpdm->uplink = &omap_mcpdm_links[1];
+
+ mutex_init(&mcpdm->mutex);
+ mcpdm->free = 1;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no resource\n");
+ ret = -EINVAL;
+ goto err;
+ }
- ret = omap_mcpdm_probe(pdev);
- if (ret < 0)
- return ret;
- ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
+ mcpdm->io_base = ioremap(res->start, resource_size(res));
+ if (!mcpdm->io_base) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ mcpdm->irq = platform_get_irq(pdev, 0);
+ if (mcpdm->irq < 0) {
+ ret = mcpdm->irq;
+ goto err_irq;
+ }
+
+ ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler,
+ 0, "McPDM", mcpdm);
+ if (ret) {
+ dev_err(mcpdm->dev, "Request for McPDM IRQ failed: %d\n", ret);
+ goto err_irq;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ mcpdm->dev = &pdev->dev;
+
+ /* TODO: values will be different per device, read from FS */
+ mcpdm->dl1_offset = 0x1F;
+ mcpdm->dl2_offset = 0x1F;
+
+ INIT_DELAYED_WORK(&mcpdm->delayed_work, playback_work);
+#ifdef CONFIG_SND_OMAP_SOC_ABE_DSP
+ INIT_DELAYED_WORK(&mcpdm->delayed_abe_work, playback_abe_work);
+#endif
+
+ ret = snd_soc_register_dais(&pdev->dev, omap_mcpdm_dai,
+ ARRAY_SIZE(omap_mcpdm_dai));
if (ret < 0)
- omap_mcpdm_remove(pdev);
+ goto err_dai;
+
+ return 0;
+
+err_dai:
+ free_irq(mcpdm->irq, mcpdm);
+err_irq:
+ iounmap(mcpdm->io_base);
+err:
+ kfree(mcpdm);
return ret;
}
static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&pdev->dev);
- omap_mcpdm_remove(pdev);
+ struct omap_mcpdm *mcpdm = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(omap_mcpdm_dai));
+ iounmap(mcpdm->io_base);
+ free_irq(mcpdm->irq, mcpdm);
+ kfree(mcpdm);
return 0;
}
diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/omap/omap-mcpdm.h
new file mode 100644
index 00000000000..2c69956e99e
--- /dev/null
+++ b/sound/soc/omap/omap-mcpdm.h
@@ -0,0 +1,131 @@
+/*
+ * omap-mcpdm.h
+ *
+ * Copyright (C) 2009 Texas Instruments
+ *
+ * Contact: Misael Lopez Cruz <x0052729@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_MCPDM_H__
+#define __OMAP_MCPDM_H__
+
+#include <linux/platform_device.h>
+
+#define MCPDM_REVISION 0x00
+#define MCPDM_SYSCONFIG 0x10
+#define MCPDM_IRQSTATUS_RAW 0x24
+#define MCPDM_IRQSTATUS 0x28
+#define MCPDM_IRQENABLE_SET 0x2C
+#define MCPDM_IRQENABLE_CLR 0x30
+#define MCPDM_IRQWAKE_EN 0x34
+#define MCPDM_DMAENABLE_SET 0x38
+#define MCPDM_DMAENABLE_CLR 0x3C
+#define MCPDM_DMAWAKEEN 0x40
+#define MCPDM_CTRL 0x44
+#define MCPDM_DN_DATA 0x48
+#define MCPDM_UP_DATA 0x4C
+#define MCPDM_FIFO_CTRL_DN 0x50
+#define MCPDM_FIFO_CTRL_UP 0x54
+#define MCPDM_DN_OFFSET 0x58
+
+/*
+ * MCPDM_IRQ bit fields
+ * IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR
+ */
+
+#define MCPDM_DN_IRQ (1 << 0)
+#define MCPDM_DN_IRQ_EMPTY (1 << 1)
+#define MCPDM_DN_IRQ_ALMST_EMPTY (1 << 2)
+#define MCPDM_DN_IRQ_FULL (1 << 3)
+
+#define MCPDM_UP_IRQ (1 << 8)
+#define MCPDM_UP_IRQ_EMPTY (1 << 9)
+#define MCPDM_UP_IRQ_ALMST_FULL (1 << 10)
+#define MCPDM_UP_IRQ_FULL (1 << 11)
+
+#define MCPDM_DOWNLINK_IRQ_MASK 0x00F
+#define MCPDM_UPLINK_IRQ_MASK 0xF00
+
+/*
+ * MCPDM_DMAENABLE bit fields
+ */
+
+#define DMA_DN_ENABLE 0x1
+#define DMA_UP_ENABLE 0x2
+
+/*
+ * MCPDM_SYSCONFIG bit fields
+ */
+#define MCPDM_SOFTRESET 0x1
+
+/*
+ * MCPDM_CTRL bit fields
+ */
+
+#define PDM_UP1_EN 0x0001
+#define PDM_UP2_EN 0x0002
+#define PDM_UP3_EN 0x0004
+#define PDM_DN1_EN 0x0008
+#define PDM_DN2_EN 0x0010
+#define PDM_DN3_EN 0x0020
+#define PDM_DN4_EN 0x0040
+#define PDM_DN5_EN 0x0080
+#define PDMOUTFORMAT 0x0100
+#define CMD_INT 0x0200
+#define STATUS_INT 0x0400
+#define SW_UP_RST 0x0800
+#define SW_DN_RST 0x1000
+#define WD_EN 0x4000
+#define PDM_UP_MASK 0x007
+#define PDM_DN_MASK 0x0F8
+#define PDM_CMD_MASK 0x200
+#define PDM_STATUS_MASK 0x400
+
+
+#define PDMOUTFORMAT_LJUST (0 << 8)
+#define PDMOUTFORMAT_RJUST (1 << 8)
+
+/*
+ * MCPDM_FIFO_CTRL bit fields
+ */
+
+#define UP_THRES_MAX 0xF
+#define DN_THRES_MAX 0xF
+
+/*
+ * MCPDM_DN_OFFSET bit fields
+ */
+
+#define DN_OFST_RX1_EN 0x0001
+#define DN_OFST_RX2_EN 0x0100
+
+#define DN_OFST_RX1 1
+#define DN_OFST_RX2 9
+#define DN_OFST_MAX 0x1F
+
+#define MCPDM_UPLINK 1
+#define MCPDM_DOWNLINK 2
+
+struct omap_mcpdm_link {
+ int irq_mask;
+ int threshold;
+ int format;
+ int channels;
+};
+
+#endif /* End of __OMAP_MCPDM_H__ */
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 8caeb8d305c..6ca5d611224 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -280,6 +280,16 @@ static int omap_pcm_open(struct snd_pcm_substream *substream)
if (ret < 0)
goto out;
+ if (cpu_is_omap44xx()) {
+ /* ABE needs a step of 24 * 4 data bits, and HDMI 32 * 4
+ * Ensure buffer size satisfies both constraints.
+ */
+ ret = snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 384);
+ if (ret < 0)
+ goto out;
+ }
+
prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
if (prtd == NULL) {
ret = -ENOMEM;
@@ -365,9 +375,10 @@ static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm)
}
}
-static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
- struct snd_pcm *pcm)
+static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
int ret = 0;
if (!card->dev->dma_mask)
@@ -375,14 +386,14 @@ static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(64);
- if (dai->driver->playback.channels_min) {
+ if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = omap_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto out;
}
- if (dai->driver->capture.channels_min) {
+ if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
ret = omap_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
diff --git a/sound/soc/omap/omap4-hdmi-card.c b/sound/soc/omap/omap4-hdmi-card.c
new file mode 100644
index 00000000000..28644e1a37f
--- /dev/null
+++ b/sound/soc/omap/omap4-hdmi-card.c
@@ -0,0 +1,89 @@
+/*
+ * sdp4430-hdmi.c
+ *
+ * OMAP ALSA SoC machine driver for TI OMAP4 HDMI
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Ricardo Neri <ricardo.neri@ti.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <asm/mach-types.h>
+
+#define OMAP4_HDMI_SND_DEV_ID 1
+
+static struct snd_soc_dai_link omap4_hdmi_dai = {
+ .name = "HDMI",
+ .stream_name = "HDMI",
+ .cpu_dai_name = "hdmi-audio-dai",
+ .platform_name = "omap-pcm-audio",
+ .codec_name = "omapdss_hdmi",
+ .codec_dai_name = "omap4-hdmi-audio-codec"
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_omap4_hdmi = {
+ .name = "SDP4430HDMI",
+ .long_name = "TI OMAP4 HDMI Board",
+ .dai_link = &omap4_hdmi_dai,
+ .num_links = 1,
+};
+
+static struct platform_device *omap4_hdmi_snd_device;
+
+static int __init omap4_hdmi_soc_init(void)
+{
+ int ret;
+
+ if (!(machine_is_omap_4430sdp() || machine_is_omap4_panda()))
+ return -ENODEV;
+ printk(KERN_INFO "OMAP4 HDMI audio SoC init\n");
+
+ if (machine_is_omap4_panda())
+ snd_soc_omap4_hdmi.name = "PandaHDMI";
+
+ omap4_hdmi_snd_device = platform_device_alloc("soc-audio",
+ OMAP4_HDMI_SND_DEV_ID);
+ if (!omap4_hdmi_snd_device) {
+ printk(KERN_ERR "Platform device allocation failed\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(omap4_hdmi_snd_device, &snd_soc_omap4_hdmi);
+
+ ret = platform_device_add(omap4_hdmi_snd_device);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ printk(KERN_ERR "Unable to add platform device\n");
+ platform_device_put(omap4_hdmi_snd_device);
+ return ret;
+}
+module_init(omap4_hdmi_soc_init);
+
+static void __exit omap4_hdmi_soc_exit(void)
+{
+ platform_device_unregister(omap4_hdmi_snd_device);
+}
+module_exit(omap4_hdmi_soc_exit);
+
+MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
+MODULE_DESCRIPTION("ALSA SoC OMAP4 HDMI AUDIO");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/sdp4430.c b/sound/soc/omap/sdp4430.c
index 189e0390063..d9a43867f7a 100644
--- a/sound/soc/omap/sdp4430.c
+++ b/sound/soc/omap/sdp4430.c
@@ -22,7 +22,9 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <sound/core.h>
+#include <linux/i2c.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>
@@ -30,19 +32,92 @@
#include <plat/hardware.h>
#include <plat/mux.h>
-#include "mcpdm.h"
+#include "omap-mcpdm.h"
+#include "omap-abe.h"
#include "omap-pcm.h"
+#include "omap-mcbsp.h"
+#include "omap-dmic.h"
#include "../codecs/twl6040.h"
+#define SDP4430_SND_DEV_ID 0
+
+#ifdef CONFIG_SND_OMAP_SOC_HDMI
+#include "omap-hdmi.h"
+#endif
+
static int twl6040_power_mode;
+static int mcbsp_cfg;
+
+static struct i2c_client *tps6130x_client;
+static struct i2c_board_info tps6130x_hwmon_info = {
+ I2C_BOARD_INFO("tps6130x", 0x33),
+};
+
+/* configure the TPS6130x Handsfree Boost Converter */
+static int sdp4430_tps6130x_configure(void)
+{
+ u8 data[2];
+
+ data[0] = 0x01;
+ data[1] = 0x60;
+ if (i2c_master_send(tps6130x_client, data, 2) != 2)
+ printk(KERN_ERR "I2C write to TPS6130x failed\n");
-static int sdp4430_hw_params(struct snd_pcm_substream *substream,
+ data[0] = 0x02;
+ if (i2c_master_send(tps6130x_client, data, 2) != 2)
+ printk(KERN_ERR "I2C write to TPS6130x failed\n");
+
+ return 0;
+}
+
+static int sdp4430_modem_mcbsp_configure(struct snd_pcm_substream *substream,
+ int flag)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_pcm_substream *modem_substream;
+ struct snd_soc_pcm_runtime *modem_rtd;
+ int ret = 0;
+
+ /* already configured, nothing to do */
+ if (mcbsp_cfg == flag)
+ return ret;
+
+ if (flag) {
+ modem_substream = snd_soc_get_dai_substream(rtd->card,
+ OMAP_ABE_BE_MM_EXT1,
+ substream->stream);
+ if (unlikely(modem_substream == NULL)) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ modem_rtd = modem_substream->private_data;
+
+ /* Set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(modem_rtd->cpu_dai,
+ SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (unlikely(ret < 0)) {
+ printk(KERN_ERR "can't set Modem cpu DAI configuration\n");
+ goto exit;
+ }
+ mcbsp_cfg = 1;
+ } else {
+ mcbsp_cfg = 0;
+ }
+
+exit:
+ return ret;
+}
+
+static int sdp4430_mcpdm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int clk_id, freq;
- int ret;
+ int ret = 0;
if (twl6040_power_mode) {
clk_id = TWL6040_SYSCLK_SEL_HPPLL;
@@ -59,13 +134,155 @@ static int sdp4430_hw_params(struct snd_pcm_substream *substream,
printk(KERN_ERR "can't set codec system clock\n");
return ret;
}
+
+ if (rtd->current_fe == ABE_FRONTEND_DAI_MODEM) {
+ /* set Modem McBSP configuration */
+ ret = sdp4430_modem_mcbsp_configure(substream, 1);
+ }
+
return ret;
}
-static struct snd_soc_ops sdp4430_ops = {
- .hw_params = sdp4430_hw_params,
+static int sdp4430_mcpdm_hw_free(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ if (rtd->current_fe == ABE_FRONTEND_DAI_MODEM) {
+ /* freed Modem McBSP configuration */
+ ret = sdp4430_modem_mcbsp_configure(substream, 0);
+ }
+
+ return ret;
+}
+
+static struct snd_soc_ops sdp4430_mcpdm_ops = {
+ .hw_params = sdp4430_mcpdm_hw_params,
+ .hw_free = sdp4430_mcpdm_hw_free,
};
+static int sdp4430_mcbsp_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int be_id;
+
+ be_id = rtd->dai_link->be_id;
+
+ if (be_id == OMAP_ABE_DAI_MM_FM) {
+ /* Set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ } else if (be_id == OMAP_ABE_DAI_BT_VX) {
+ ret = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_DSP_B |
+ SND_SOC_DAIFMT_NB_IF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ }
+
+ if (ret < 0) {
+ printk(KERN_ERR "can't set cpu DAI configuration\n");
+ return ret;
+ }
+
+ /*
+ * TODO: where does this clock come from (external source??) -
+ * do we need to enable it.
+ */
+ /* Set McBSP clock to external */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_FCLK,
+ 64 * params_rate(params),
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set cpu system clock\n");
+ return ret;
+ }
+ return 0;
+}
+
+static struct snd_soc_ops sdp4430_mcbsp_ops = {
+ .hw_params = sdp4430_mcbsp_hw_params,
+};
+
+static int sdp4430_dmic_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_SYSCLK_PAD_CLKS,
+ 19200000, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set DMIC cpu system clock\n");
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_DMIC_CLKDIV, 8);
+ if (ret < 0) {
+ printk(KERN_ERR "can't set DMIC cpu clock divider\n");
+ return ret;
+ }
+
+ if (rtd->current_fe == ABE_FRONTEND_DAI_MODEM) {
+ /* set Modem McBSP configuration */
+ ret = sdp4430_modem_mcbsp_configure(substream, 1);
+ }
+
+ return ret;
+}
+
+static int sdp4430_dmic_hw_free(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ if (rtd->current_fe == ABE_FRONTEND_DAI_MODEM) {
+ /* freed Modem McBSP configuration */
+ ret = sdp4430_modem_mcbsp_configure(substream, 0);
+ }
+
+ return ret;
+}
+
+static struct snd_soc_ops sdp4430_dmic_ops = {
+ .hw_params = sdp4430_dmic_hw_params,
+ .hw_free = sdp4430_dmic_hw_free,
+};
+
+static int mcbsp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ unsigned int be_id;
+
+ be_id = rtd->dai_link->be_id;
+
+ if (be_id == OMAP_ABE_DAI_MM_FM)
+ channels->min = 2;
+ else if (be_id == OMAP_ABE_DAI_BT_VX)
+ channels->min = 1;
+
+ snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
+ SNDRV_PCM_HW_PARAM_FIRST_MASK],
+ SNDRV_PCM_FORMAT_S16_LE);
+ return 0;
+}
+
+static int dmic_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
+ SNDRV_PCM_HW_PARAM_FIRST_MASK],
+ SNDRV_PCM_FORMAT_S32_LE);
+ return 0;
+}
+
/* Headset jack */
static struct snd_soc_jack hs_jack;
@@ -113,6 +330,9 @@ static const struct snd_kcontrol_new sdp4430_controls[] = {
/* SDP4430 machine DAPM */
static const struct snd_soc_dapm_widget sdp4430_twl6040_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Ext Mic", NULL),
+ SND_SOC_DAPM_MIC("Ext DMic0", NULL),
+ SND_SOC_DAPM_MIC("Ext DMic1", NULL),
+ SND_SOC_DAPM_MIC("Ext DMic2", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_HP("Headset Stereophone", NULL),
@@ -121,11 +341,20 @@ static const struct snd_soc_dapm_widget sdp4430_twl6040_dapm_widgets[] = {
};
static const struct snd_soc_dapm_route audio_map[] = {
- /* External Mics: MAINMIC, SUBMIC with bias*/
+ /* External Mics: MAINMIC, SUBMIC and DMICs with bias */
{"MAINMIC", NULL, "Main Mic Bias"},
{"SUBMIC", NULL, "Main Mic Bias"},
{"Main Mic Bias", NULL, "Ext Mic"},
+ {"DMIC0", NULL, "Digital Mic1 Bias"},
+ {"Digital Mic1 Bias", NULL, "Ext DMic0"},
+
+ {"DMIC1", NULL, "Digital Mic1 Bias"},
+ {"Digital Mic1 Bias", NULL, "Ext DMic1"},
+
+ {"DMIC2", NULL, "Digital Mic1 Bias"},
+ {"Digital Mic1 Bias", NULL, "Ext DMic2"},
+
/* External Speakers: HFL, HFR */
{"Ext Spk", NULL, "HFL"},
{"Ext Spk", NULL, "HFR"},
@@ -146,7 +375,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"AFMR", NULL, "Aux/FM Stereo In"},
};
-static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
+static int sdp4430_twl6040_init_hs(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
@@ -169,11 +398,25 @@ static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
/* SDP4430 connected pins */
snd_soc_dapm_enable_pin(dapm, "Ext Mic");
+ snd_soc_dapm_enable_pin(dapm, "Ext DMic0");
+ snd_soc_dapm_enable_pin(dapm, "Ext DMic1");
+ snd_soc_dapm_enable_pin(dapm, "Ext DMic2");
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
snd_soc_dapm_enable_pin(dapm, "AFML");
snd_soc_dapm_enable_pin(dapm, "AFMR");
- snd_soc_dapm_enable_pin(dapm, "Headset Mic");
- snd_soc_dapm_enable_pin(dapm, "Headset Stereophone");
+ snd_soc_dapm_disable_pin(dapm, "Headset Mic");
+ snd_soc_dapm_disable_pin(dapm, "Headset Stereophone");
+
+ /* allow modem audio paths to run during suspend */
+ snd_soc_dapm_ignore_suspend(dapm, "Ext Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Ext DMic0");
+ snd_soc_dapm_ignore_suspend(dapm, "Ext DMic1");
+ snd_soc_dapm_ignore_suspend(dapm, "Ext DMic2");
+ snd_soc_dapm_ignore_suspend(dapm, "Ext Spk");
+ snd_soc_dapm_ignore_suspend(dapm, "AFML");
+ snd_soc_dapm_ignore_suspend(dapm, "AFMR");
+ snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Headset Stereophone");
ret = snd_soc_dapm_sync(dapm);
if (ret)
@@ -193,52 +436,517 @@ static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
else
snd_soc_jack_report(&hs_jack, SND_JACK_HEADSET, SND_JACK_HEADSET);
+ /* wait 500 ms before switching of HS power */
+ rtd->pmdown_time = 500;
+
return ret;
}
+static int sdp4430_twl6040_init_hf(struct snd_soc_pcm_runtime *rtd)
+{
+ /* wait 500 ms before switching of HS power */
+ rtd->pmdown_time = 500;
+ return 0;
+}
+
+/* TODO: make this a separate BT CODEC driver or DUMMY */
+static struct snd_soc_dai_driver dai[] = {
+{
+ .name = "Bluetooth",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+},
+/* TODO: make this a separate FM CODEC driver or DUMMY */
+{
+ .name = "FM Digital",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+},
+{
+ .name = "HDMI",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ },
+},
+};
+
+static const char *mm1_be[] = {
+ OMAP_ABE_BE_PDM_DL1,
+ OMAP_ABE_BE_PDM_UL1,
+ OMAP_ABE_BE_PDM_DL2,
+ OMAP_ABE_BE_BT_VX,
+ OMAP_ABE_BE_MM_EXT0,
+ OMAP_ABE_BE_DMIC0,
+ OMAP_ABE_BE_DMIC1,
+ OMAP_ABE_BE_DMIC2,
+};
+
+static const char *mm2_be[] = {
+ OMAP_ABE_BE_PDM_UL1,
+ OMAP_ABE_BE_BT_VX,
+ OMAP_ABE_BE_MM_EXT0,
+ OMAP_ABE_BE_DMIC0,
+ OMAP_ABE_BE_DMIC1,
+ OMAP_ABE_BE_DMIC2,
+};
+
+static const char *tones_be[] = {
+ OMAP_ABE_BE_PDM_DL1,
+ OMAP_ABE_BE_PDM_DL2,
+ OMAP_ABE_BE_BT_VX,
+ OMAP_ABE_BE_MM_EXT0,
+};
+
+static const char *vib_be[] = {
+ OMAP_ABE_BE_PDM_VIB,
+};
+
+static const char *modem_be[] = {
+ OMAP_ABE_BE_PDM_DL1,
+ OMAP_ABE_BE_PDM_UL1,
+ OMAP_ABE_BE_PDM_DL2,
+ OMAP_ABE_BE_BT_VX,
+ OMAP_ABE_BE_DMIC0,
+ OMAP_ABE_BE_DMIC1,
+ OMAP_ABE_BE_DMIC2,
+};
+
+static const char *mm_lp_be[] = {
+ OMAP_ABE_BE_PDM_DL1,
+ OMAP_ABE_BE_PDM_DL2,
+ OMAP_ABE_BE_BT_VX,
+ OMAP_ABE_BE_MM_EXT0,
+};
+
/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link sdp4430_dai = {
- .name = "TWL6040",
- .stream_name = "TWL6040",
- .cpu_dai_name ="omap-mcpdm-dai",
- .codec_dai_name = "twl6040-hifi",
- .platform_name = "omap-pcm-audio",
- .codec_name = "twl6040-codec",
- .init = sdp4430_twl6040_init,
- .ops = &sdp4430_ops,
+static struct snd_soc_dai_link sdp4430_dai[] = {
+
+/*
+ * Frontend DAIs - i.e. userspace visible interfaces (ALSA PCMs)
+ */
+
+ {
+ .name = "SDP4430 Media",
+ .stream_name = "Multimedia",
+
+ /* ABE components - MM-UL & MM_DL */
+ .cpu_dai_name = "MultiMedia1",
+ .platform_name = "omap-pcm-audio",
+
+ .dynamic = 1, /* BE is dynamic */
+ .supported_be = mm1_be,
+ .num_be = ARRAY_SIZE(mm1_be),
+ .fe_playback_channels = 2,
+ .fe_capture_channels = 8,
+ .no_host_mode = SND_SOC_DAI_LINK_OPT_HOST,
+ },
+ {
+ .name = "SDP4430 Media Capture",
+ .stream_name = "Multimedia Capture",
+
+ /* ABE components - MM-UL2 */
+ .cpu_dai_name = "MultiMedia2",
+ .platform_name = "omap-pcm-audio",
+
+ .dynamic = 1, /* BE is dynamic */
+ .supported_be = mm2_be,
+ .num_be = ARRAY_SIZE(mm2_be),
+ .fe_capture_channels = 2,
+ },
+ {
+ .name = "SDP4430 Voice",
+ .stream_name = "Voice",
+
+ /* ABE components - VX-UL & VX-DL */
+ .cpu_dai_name = "Voice",
+ .platform_name = "omap-pcm-audio",
+
+ .dynamic = 1, /* BE is dynamic */
+ .supported_be = mm1_be,
+ .num_be = ARRAY_SIZE(mm1_be),
+ .fe_playback_channels = 2,
+ .fe_capture_channels = 2,
+ .no_host_mode = SND_SOC_DAI_LINK_OPT_HOST,
+ },
+ {
+ .name = "SDP4430 Tones Playback",
+ .stream_name = "Tone Playback",
+
+ /* ABE components - TONES_DL */
+ .cpu_dai_name = "Tones",
+ .platform_name = "omap-pcm-audio",
+
+ .dynamic = 1, /* BE is dynamic */
+ .supported_be = tones_be,
+ .num_be = ARRAY_SIZE(tones_be),
+ .fe_playback_channels = 2,
+ },
+ {
+ .name = "SDP4430 Vibra Playback",
+ .stream_name = "VIB-DL",
+
+ .cpu_dai_name = "Vibra",
+ .platform_name = "omap-pcm-audio",
+
+ .dynamic = 1, /* BE is dynamic */
+ .supported_be = vib_be,
+ .num_be = ARRAY_SIZE(vib_be),
+ .fe_playback_channels = 2,
+ },
+ {
+ .name = "SDP4430 MODEM",
+ .stream_name = "MODEM",
+
+ /* ABE components - MODEM <-> McBSP2 */
+ .cpu_dai_name = "MODEM",
+ .platform_name = "omap-aess-audio",
+
+ .dynamic = 1, /* BE is dynamic */
+ .supported_be = modem_be,
+ .num_be = ARRAY_SIZE(modem_be),
+ .fe_playback_channels = 2,
+ .fe_capture_channels = 2,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = "SDP4430 Media LP",
+ .stream_name = "Multimedia",
+
+ /* ABE components - MM-DL (mmap) */
+ .cpu_dai_name = "MultiMedia1 LP",
+ .platform_name = "omap-aess-audio",
+
+ .dynamic = 1, /* BE is dynamic */
+ .supported_be = mm_lp_be,
+ .num_be = ARRAY_SIZE(mm_lp_be),
+ .fe_playback_channels = 2,
+ .no_host_mode = SND_SOC_DAI_LINK_OPT_HOST,
+ },
+#ifdef CONFIG_SND_OMAP_SOC_HDMI
+ {
+ .name = "hdmi",
+ .stream_name = "HDMI",
+
+ .cpu_dai_name = "hdmi-dai",
+ .platform_name = "omap-pcm-audio",
+
+ /* HDMI*/
+ .codec_dai_name = "HDMI",
+
+ .no_codec = 1,
+ },
+#endif
+ {
+ .name = "Legacy McBSP",
+ .stream_name = "Multimedia",
+
+ /* ABE components - MCBSP2 - MM-EXT */
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .platform_name = "omap-pcm-audio",
+
+ /* FM */
+ .codec_dai_name = "FM Digital",
+
+ .no_codec = 1, /* TODO: have a dummy CODEC */
+ .ops = &sdp4430_mcbsp_ops,
+ },
+ {
+ .name = "Legacy McPDM",
+ .stream_name = "Headset Playback",
+
+ /* ABE components - DL1 */
+ .cpu_dai_name = "mcpdm-dl",
+ .platform_name = "omap-pcm-audio",
+
+ /* Phoenix - DL1 DAC */
+ .codec_dai_name = "twl6040-dl1",
+ .codec_name = "twl6040-codec",
+
+ .ops = &sdp4430_mcpdm_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = "Legacy DMIC",
+ .stream_name = "DMIC Capture",
+
+ /* ABE components - DMIC0 */
+ .cpu_dai_name = "omap-dmic-dai-0",
+ .platform_name = "omap-pcm-audio",
+
+ /* DMIC codec */
+ .codec_dai_name = "dmic-hifi",
+ .codec_name = "dmic-codec.0",
+
+ .ops = &sdp4430_dmic_ops,
+ .ignore_suspend = 1,
+ },
+
+/*
+ * Backend DAIs - i.e. dynamically matched interfaces, invisible to userspace.
+ * Matched to above interfaces at runtime, based upon use case.
+ */
+
+ {
+ .name = OMAP_ABE_BE_PDM_DL1,
+ .stream_name = "HS Playback",
+
+ /* ABE components - DL1 */
+ .cpu_dai_name = "mcpdm-dl1",
+ .platform_name = "omap-aess-audio",
+
+ /* Phoenix - DL1 DAC */
+ .codec_dai_name = "twl6040-dl1",
+ .codec_name = "twl6040-codec",
+
+ .no_pcm = 1, /* don't create ALSA pcm for this */
+ .init = sdp4430_twl6040_init_hs,
+ .ops = &sdp4430_mcpdm_ops,
+ .be_id = OMAP_ABE_DAI_PDM_DL1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = OMAP_ABE_BE_PDM_UL1,
+ .stream_name = "Analog Capture",
+
+ /* ABE components - UL1 */
+ .cpu_dai_name = "mcpdm-ul1",
+ .platform_name = "omap-aess-audio",
+
+ /* Phoenix - UL ADC */
+ .codec_dai_name = "twl6040-ul",
+ .codec_name = "twl6040-codec",
+
+ .no_pcm = 1, /* don't create ALSA pcm for this */
+ .ops = &sdp4430_mcpdm_ops,
+ .be_id = OMAP_ABE_DAI_PDM_UL,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = OMAP_ABE_BE_PDM_DL2,
+ .stream_name = "HF Playback",
+
+ /* ABE components - DL2 */
+ .cpu_dai_name = "mcpdm-dl2",
+ .platform_name = "omap-aess-audio",
+
+ /* Phoenix - DL2 DAC */
+ .codec_dai_name = "twl6040-dl2",
+ .codec_name = "twl6040-codec",
+
+ .no_pcm = 1, /* don't create ALSA pcm for this */
+ .init = sdp4430_twl6040_init_hf,
+ .ops = &sdp4430_mcpdm_ops,
+ .be_id = OMAP_ABE_DAI_PDM_DL2,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = OMAP_ABE_BE_PDM_VIB,
+ .stream_name = "Vibra",
+
+ /* ABE components - VIB1 DL */
+ .cpu_dai_name = "mcpdm-vib",
+ .platform_name = "omap-aess-audio",
+
+ /* Phoenix - PDM to PWM */
+ .codec_dai_name = "twl6040-vib",
+ .codec_name = "twl6040-codec",
+
+ .no_pcm = 1, /* don't create ALSA pcm for this */
+ .ops = &sdp4430_mcpdm_ops,
+ .be_id = OMAP_ABE_DAI_PDM_VIB,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = OMAP_ABE_BE_BT_VX,
+ .stream_name = "BT",
+
+ /* ABE components - MCBSP1 - BT-VX */
+ .cpu_dai_name = "omap-mcbsp-dai.0",
+ .platform_name = "omap-aess-audio",
+
+ /* Bluetooth */
+ .codec_dai_name = "Bluetooth",
+
+ .no_pcm = 1, /* don't create ALSA pcm for this */
+ .no_codec = 1, /* TODO: have a dummy CODEC */
+ .be_hw_params_fixup = mcbsp_be_hw_params_fixup,
+ .ops = &sdp4430_mcbsp_ops,
+ .be_id = OMAP_ABE_DAI_BT_VX,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = OMAP_ABE_BE_MM_EXT0,
+ .stream_name = "FM",
+
+ /* ABE components - MCBSP2 - MM-EXT */
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .platform_name = "omap-aess-audio",
+
+ /* FM */
+ .codec_dai_name = "FM Digital",
+
+ .no_pcm = 1, /* don't create ALSA pcm for this */
+ .no_codec = 1, /* TODO: have a dummy CODEC */
+ .be_hw_params_fixup = mcbsp_be_hw_params_fixup,
+ .ops = &sdp4430_mcbsp_ops,
+ .be_id = OMAP_ABE_DAI_MM_FM,
+ },
+ {
+ .name = OMAP_ABE_BE_MM_EXT1,
+ .stream_name = "MODEM",
+
+ /* ABE components - MCBSP2 - MM-EXT */
+ .cpu_dai_name = "omap-mcbsp-dai.1",
+ .platform_name = "omap-aess-audio",
+
+ /* MODEM */
+ .codec_dai_name = "MODEM",
+
+ .no_pcm = 1, /* don't create ALSA pcm for this */
+ .no_codec = 1, /* TODO: have a dummy CODEC */
+ .be_hw_params_fixup = mcbsp_be_hw_params_fixup,
+ .ops = &sdp4430_mcbsp_ops,
+ .be_id = OMAP_ABE_DAI_MODEM,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = OMAP_ABE_BE_DMIC0,
+ .stream_name = "DMIC0",
+
+ /* ABE components - DMIC UL 1 */
+ .cpu_dai_name = "omap-dmic-abe-dai-0",
+ .platform_name = "omap-aess-audio",
+
+ /* DMIC 0 */
+ .codec_dai_name = "dmic-hifi",
+ .codec_name = "dmic-codec.0",
+ .ops = &sdp4430_dmic_ops,
+
+ .no_pcm = 1, /* don't create ALSA pcm for this */
+ .be_hw_params_fixup = dmic_be_hw_params_fixup,
+ .be_id = OMAP_ABE_DAI_DMIC0,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = OMAP_ABE_BE_DMIC1,
+ .stream_name = "DMIC1",
+
+ /* ABE components - DMIC UL 1 */
+ .cpu_dai_name = "omap-dmic-abe-dai-1",
+ .platform_name = "omap-aess-audio",
+
+ /* DMIC 1 */
+ .codec_dai_name = "dmic-hifi",
+ .codec_name = "dmic-codec.1",
+ .ops = &sdp4430_dmic_ops,
+
+ .no_pcm = 1, /* don't create ALSA pcm for this */
+ .be_hw_params_fixup = dmic_be_hw_params_fixup,
+ .be_id = OMAP_ABE_DAI_DMIC1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = OMAP_ABE_BE_DMIC2,
+ .stream_name = "DMIC2",
+
+ /* ABE components - DMIC UL 2 */
+ .cpu_dai_name = "omap-dmic-abe-dai-2",
+ .platform_name = "omap-aess-audio",
+
+ /* DMIC 2 */
+ .codec_dai_name = "dmic-hifi",
+ .codec_name = "dmic-codec.2",
+ .ops = &sdp4430_dmic_ops,
+
+ .no_pcm = 1, /* don't create ALSA pcm for this */
+ .be_hw_params_fixup = dmic_be_hw_params_fixup,
+ .be_id = OMAP_ABE_DAI_DMIC2,
+ .ignore_suspend = 1,
+ },
};
/* Audio machine driver */
static struct snd_soc_card snd_soc_sdp4430 = {
.name = "SDP4430",
- .dai_link = &sdp4430_dai,
- .num_links = 1,
+ .long_name = "TI OMAP4 SDP4430 Board",
+ .dai_link = sdp4430_dai,
+ .num_links = ARRAY_SIZE(sdp4430_dai),
};
static struct platform_device *sdp4430_snd_device;
static int __init sdp4430_soc_init(void)
{
+ struct i2c_adapter *adapter;
int ret;
- if (!machine_is_omap_4430sdp())
+ if (!machine_is_omap_4430sdp() && !machine_is_omap4_panda()) {
+ pr_debug("Not SDP4430 or PandaBoard!\n");
return -ENODEV;
+ }
printk(KERN_INFO "SDP4430 SoC init\n");
- sdp4430_snd_device = platform_device_alloc("soc-audio", -1);
+ sdp4430_snd_device = platform_device_alloc("soc-audio",
+ SDP4430_SND_DEV_ID);
if (!sdp4430_snd_device) {
printk(KERN_ERR "Platform device allocation failed\n");
return -ENOMEM;
}
+ snd_soc_register_dais(&sdp4430_snd_device->dev, dai, ARRAY_SIZE(dai));
+
platform_set_drvdata(sdp4430_snd_device, &snd_soc_sdp4430);
ret = platform_device_add(sdp4430_snd_device);
if (ret)
goto err;
- /* Codec starts in HP mode */
- twl6040_power_mode = 1;
+ adapter = i2c_get_adapter(1);
+ if (!adapter) {
+ printk(KERN_ERR "can't get i2c adapter\n");
+ return -ENODEV;
+ }
+
+ tps6130x_client = i2c_new_device(adapter, &tps6130x_hwmon_info);
+ if (!tps6130x_client) {
+ printk(KERN_ERR "can't add i2c device\n");
+ return -ENODEV;
+ }
+
+ /* Only configure the TPS6130x on SDP4430 */
+ if (machine_is_omap_4430sdp())
+ sdp4430_tps6130x_configure();
return 0;
@@ -252,6 +960,7 @@ module_init(sdp4430_soc_init);
static void __exit sdp4430_soc_exit(void)
{
platform_device_unregister(sdp4430_snd_device);
+ i2c_unregister_device(tps6130x_client);
}
module_exit(sdp4430_soc_exit);
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index 02fb66416dd..7c13674110c 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -84,9 +84,10 @@ static struct snd_pcm_ops pxa2xx_pcm_ops = {
static u64 pxa2xx_pcm_dmamask = DMA_BIT_MASK(32);
-static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
- struct snd_pcm *pcm)
+static int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
int ret = 0;
if (!card->dev->dma_mask)
diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c
index ab3ccaec72d..dc6c641ddd4 100644
--- a/sound/soc/s6000/s6000-pcm.c
+++ b/sound/soc/s6000/s6000-pcm.c
@@ -443,9 +443,10 @@ static void s6000_pcm_free(struct snd_pcm *pcm)
static u64 s6000_pcm_dmamask = DMA_BIT_MASK(32);
-static int s6000_pcm_new(struct snd_card *card,
- struct snd_soc_dai *dai, struct snd_pcm *pcm)
+static int s6000_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
struct snd_soc_pcm_runtime *runtime = pcm->private_data;
struct s6000_pcm_dma_params *params;
int res;
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
index c326d29992f..f26d238d40e 100644
--- a/sound/soc/sh/dma-sh7760.c
+++ b/sound/soc/sh/dma-sh7760.c
@@ -327,10 +327,11 @@ static void camelot_pcm_free(struct snd_pcm *pcm)
snd_pcm_lib_preallocate_free_for_all(pcm);
}
-static int camelot_pcm_new(struct snd_card *card,
- struct snd_soc_dai *dai,
- struct snd_pcm *pcm)
+static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
+
/* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
* in MMAP mode (i.e. aplay -M)
*/
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 2b06402801e..c3362d9d3c6 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -1060,10 +1060,10 @@ static void fsi_pcm_free(struct snd_pcm *pcm)
snd_pcm_lib_preallocate_free_for_all(pcm);
}
-static int fsi_pcm_new(struct snd_card *card,
- struct snd_soc_dai *dai,
- struct snd_pcm *pcm)
+static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
/*
* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
* in MMAP mode (i.e. aplay -M)
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
index a423babcf14..5a428dab2d5 100644
--- a/sound/soc/sh/siu_pcm.c
+++ b/sound/soc/sh/siu_pcm.c
@@ -527,9 +527,10 @@ static snd_pcm_uframes_t siu_pcm_pointer_dma(struct snd_pcm_substream *ss)
return bytes_to_frames(ss->runtime, ptr);
}
-static int siu_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
- struct snd_pcm *pcm)
+static int siu_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
/* card->dev == socdev->dev, see snd_soc_new_pcms() */
struct siu_info *info = siu_i2s_data;
struct platform_device *pdev = to_platform_device(card->dev);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index c3f6f1e7279..0224b0cda3a 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -44,7 +44,6 @@
#define NAME_SIZE 32
-static DEFINE_MUTEX(pcm_mutex);
static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
#ifdef CONFIG_DEBUG_FS
@@ -70,6 +69,24 @@ static int pmdown_time = 5000;
module_param(pmdown_time, int, 0);
MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");
+/* ASoC no host IO hardware.
+ * TODO: fine tune these values for all host less transfers.
+ */
+static const struct snd_pcm_hardware no_host_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .period_bytes_min = PAGE_SIZE >> 2,
+ .period_bytes_max = PAGE_SIZE >> 1,
+ .periods_min = 2,
+ .periods_max = 4,
+ .buffer_bytes_max = PAGE_SIZE,
+};
+
/* codec register dump */
static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
{
@@ -454,12 +471,116 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream)
return 0;
}
+static int is_be_supported(struct snd_soc_pcm_runtime *rtd, const char *link)
+{
+ int i;
+
+ for (i= 0; i < rtd->dai_link->num_be; i++) {
+ if(!strcmp(rtd->dai_link->supported_be[i], link))
+ return 1;
+ }
+ return 0;
+}
+
+int snd_soc_get_backend_dais(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_card *card = rtd->card;
+ int i, num;
+ const char *fe_aif = NULL, *be_aif;
+ enum snd_soc_dapm_type fe_type, be_type;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ fe_type = snd_soc_dapm_aif_in;
+ be_type = snd_soc_dapm_aif_out;
+ } else {
+ fe_type = snd_soc_dapm_aif_out;
+ be_type = snd_soc_dapm_aif_in;
+ }
+
+ /* search card for valid frontend steams */
+ for (i = 0; i < card->num_links; i++) {
+
+ /* check for frontend */
+ if (card->rtd[i].dai_link->dynamic)
+ continue;
+
+ fe_aif = snd_soc_dapm_get_aif(&card->rtd[i].platform->dapm,
+ cpu_dai->driver->name, fe_type);
+ }
+
+ if (fe_aif == NULL) {
+ dev_err(&rtd->dev, "no frontend widgets for stream %s\n",
+ cpu_dai->driver->name);
+ return 0;
+ } else
+ dev_dbg(&rtd->dev, "got fe %s\n", fe_aif);
+
+ /* search card for valid backends */
+ for (i = 0; i < card->num_links; i++) {
+
+ /* check for frontend */
+ if (card->rtd[i].dai_link->dynamic)
+ continue;
+
+ /* backends must belong to this frontend */
+ if (card->rtd[i].dai_link->no_pcm) {
+
+ if (!is_be_supported(rtd, card->rtd[i].dai_link->name))
+ continue;
+
+ be_aif = snd_soc_dapm_get_aif(&card->rtd[i].platform->dapm,
+ card->rtd[i].dai_link->stream_name, be_type);
+ if (be_aif == NULL) {
+ dev_dbg(&rtd->dev, "no backend widget for stream %s\n",
+ card->rtd[i].dai_link->stream_name);
+ continue;
+ }
+ dev_dbg(&rtd->dev, "got be %s for stream %s\n", be_aif,
+ card->rtd[i].dai_link->stream_name);
+
+ /* check for valid path */
+ num = snd_soc_scenario_set_path(&card->rtd[i].platform->dapm,
+ fe_aif, be_aif, substream->stream);
+
+ /* add backend if we have space */
+ if (num > 0) {
+ if (rtd->num_be[substream->stream] == SND_SOC_MAX_BE)
+ dev_dbg(&rtd->dev, "no more backends permitted\n");
+ else {
+ dev_dbg(&rtd->dev, "** active path for %s to %s\n", fe_aif, be_aif);
+ rtd->be_rtd[rtd->num_be[substream->stream]++][substream->stream] = &card->rtd[i];
+ card->rtd[i].fe_clients++;
+ }
+ }
+ }
+ }
+
+ return rtd->num_be[substream->stream] ? rtd->num_be[substream->stream] : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_backend_dais);
+
+void snd_soc_put_backend_dais(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int i;
+
+ for (i = 0; i < rtd->num_be[substream->stream]; i++) {
+ rtd->be_rtd[i][substream->stream]->fe_clients--;
+ rtd->be_rtd[i][substream->stream] = NULL;
+ }
+ rtd->num_be[substream->stream] = 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_backend_dais);
+
/*
* Called by ALSA when a PCM substream is opened, the runtime->hw record is
* then initialized and any private data can be allocated. This also calls
* startup for the cpu DAI, platform, machine and codec DAI.
*/
-static int soc_pcm_open(struct snd_pcm_substream *substream)
+
+int snd_soc_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -470,7 +591,33 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver;
int ret = 0;
- mutex_lock(&pcm_mutex);
+ mutex_lock(&rtd->pcm_mutex);
+
+ /* Work out backend DAI's if we are a frontend */
+ if (rtd->dai_link->dynamic) {
+ ret = snd_soc_get_backend_dais(substream);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: no valid backend routes for PCM: %s\n",
+ dev_name(&rtd->dev));
+ goto out;
+ }
+ }
+
+ /* Are we the backend and already enabled */
+ if (rtd->dai_link->no_pcm) {
+
+ if (rtd->fe_clients == 0) {
+ dev_err(&rtd->dev, "operations not permitted on backend DAI\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (rtd->be_active++)
+ goto no_pcm;
+ }
+
+ if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST)
+ snd_soc_set_runtime_hwparams(substream, &no_host_hardware);
/* startup the audio subsystem */
if (cpu_dai->driver->ops->startup) {
@@ -507,6 +654,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
}
}
+ if (rtd->dai_link->no_pcm)
+ goto no_pcm;
+
/* Check that the codec and cpu DAIs are compatible */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
runtime->hw.rate_min =
@@ -587,7 +737,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
runtime->hw.channels_max);
pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min,
runtime->hw.rate_max);
-
+no_pcm:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
cpu_dai->playback_active++;
codec_dai->playback_active++;
@@ -598,7 +748,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
cpu_dai->active++;
codec_dai->active++;
rtd->codec->active++;
- mutex_unlock(&pcm_mutex);
+
+ mutex_unlock(&rtd->pcm_mutex);
+
return 0;
config_err:
@@ -617,9 +769,14 @@ platform_err:
if (cpu_dai->driver->ops->shutdown)
cpu_dai->driver->ops->shutdown(substream, cpu_dai);
out:
- mutex_unlock(&pcm_mutex);
+ if (rtd->dai_link->dynamic)
+ snd_soc_put_backend_dais(substream);
+
+ mutex_unlock(&rtd->pcm_mutex);
+
return ret;
}
+EXPORT_SYMBOL_GPL(snd_soc_pcm_open);
/*
* Power down the audio subsystem pmdown_time msecs after close is called.
@@ -631,8 +788,9 @@ static void close_delayed_work(struct work_struct *work)
struct snd_soc_pcm_runtime *rtd =
container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- mutex_lock(&pcm_mutex);
+ mutex_lock(&rtd->pcm_mutex);
pr_debug("pop wq checking: %s status: %s waiting: %s\n",
codec_dai->driver->playback.stream_name,
@@ -642,12 +800,17 @@ static void close_delayed_work(struct work_struct *work)
/* are we waiting on this codec DAI stream */
if (codec_dai->pop_wait == 1) {
codec_dai->pop_wait = 0;
- snd_soc_dapm_stream_event(rtd,
- codec_dai->driver->playback.stream_name,
- SND_SOC_DAPM_STREAM_STOP);
+ if (rtd->dai_link->dynamic)
+ snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
+ cpu_dai->driver->playback.stream_name,
+ SND_SOC_DAPM_STREAM_STOP);
+ else
+ snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
+ codec_dai->driver->playback.stream_name,
+ SND_SOC_DAPM_STREAM_STOP);
}
- mutex_unlock(&pcm_mutex);
+ mutex_unlock(&rtd->pcm_mutex);
}
/*
@@ -655,7 +818,7 @@ static void close_delayed_work(struct work_struct *work)
* freed here. The cpu DAI, codec DAI, machine and platform are also
* shutdown.
*/
-static int soc_codec_close(struct snd_pcm_substream *substream)
+int snd_soc_pcm_close(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_platform *platform = rtd->platform;
@@ -663,7 +826,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_codec *codec = rtd->codec;
- mutex_lock(&pcm_mutex);
+ mutex_lock(&rtd->pcm_mutex);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
cpu_dai->playback_active--;
@@ -677,6 +840,9 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
codec_dai->active--;
codec->active--;
+ if (rtd->dai_link->no_pcm)
+ rtd->be_active--;
+
/* Muting the DAC suppresses artifacts caused during digital
* shutdown, for example from stopping clocks.
*/
@@ -703,21 +869,30 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
msecs_to_jiffies(rtd->pmdown_time));
} else {
/* capture streams can be powered down now */
- snd_soc_dapm_stream_event(rtd,
- codec_dai->driver->capture.stream_name,
- SND_SOC_DAPM_STREAM_STOP);
+ if (rtd->dai_link->dynamic)
+ snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
+ cpu_dai->driver->capture.stream_name,
+ SND_SOC_DAPM_STREAM_STOP);
+ else
+ snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
+ codec_dai->driver->capture.stream_name,
+ SND_SOC_DAPM_STREAM_STOP);
}
- mutex_unlock(&pcm_mutex);
+ if (rtd->dai_link->dynamic)
+ snd_soc_put_backend_dais(substream);
+
+ mutex_unlock(&rtd->pcm_mutex);
return 0;
}
+EXPORT_SYMBOL_GPL(snd_soc_pcm_close);
/*
* Called by ALSA when the PCM substream is prepared, can set format, sample
* rate, etc. This function is non atomic and can be called multiple times,
* it can refer to the runtime info.
*/
-static int soc_pcm_prepare(struct snd_pcm_substream *substream)
+int snd_soc_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_platform *platform = rtd->platform;
@@ -725,7 +900,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret = 0;
- mutex_lock(&pcm_mutex);
+ mutex_lock(&rtd->pcm_mutex);
if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) {
ret = rtd->dai_link->ops->prepare(substream);
@@ -766,28 +941,39 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
cancel_delayed_work(&rtd->delayed_work);
}
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- snd_soc_dapm_stream_event(rtd,
+ if (rtd->dai_link->dynamic) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
+ cpu_dai->driver->playback.stream_name,
+ SND_SOC_DAPM_STREAM_START);
+ else
+ snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
+ cpu_dai->driver->capture.stream_name,
+ SND_SOC_DAPM_STREAM_START);
+ } else {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
codec_dai->driver->playback.stream_name,
SND_SOC_DAPM_STREAM_START);
- else
- snd_soc_dapm_stream_event(rtd,
+ else
+ snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
codec_dai->driver->capture.stream_name,
SND_SOC_DAPM_STREAM_START);
-
+ }
snd_soc_dai_digital_mute(codec_dai, 0);
out:
- mutex_unlock(&pcm_mutex);
+ mutex_unlock(&rtd->pcm_mutex);
return ret;
}
+EXPORT_SYMBOL_GPL(snd_soc_pcm_prepare);
/*
* Called by ALSA when the hardware params are set by application. This
* function can also be called multiple times and can allocate buffers
* (using snd_pcm_lib_* ). It's non-atomic.
*/
-static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
+int snd_soc_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -796,7 +982,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret = 0;
- mutex_lock(&pcm_mutex);
+ mutex_lock(&rtd->pcm_mutex);
if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
ret = rtd->dai_link->ops->hw_params(substream, params);
@@ -835,8 +1021,21 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
rtd->rate = params_rate(params);
+ /* malloc a page for hostless IO.
+ * FIXME: rework with alsa-lib changes so that this malloc is not required.
+ */
+ if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST) {
+ substream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV;
+ substream->dma_buffer.dev.dev = &rtd->dev;
+ substream->dma_buffer.private_data = NULL;
+
+ ret = snd_pcm_lib_malloc_pages(substream, PAGE_SIZE);
+ if (ret < 0)
+ goto platform_err;
+ }
+
out:
- mutex_unlock(&pcm_mutex);
+ mutex_unlock(&rtd->pcm_mutex);
return ret;
platform_err:
@@ -851,14 +1050,15 @@ codec_err:
if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
rtd->dai_link->ops->hw_free(substream);
- mutex_unlock(&pcm_mutex);
+ mutex_unlock(&rtd->pcm_mutex);;
return ret;
}
+EXPORT_SYMBOL_GPL(snd_soc_pcm_hw_params);
/*
* Frees resources allocated by hw_params, can be called multiple times
*/
-static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
+int snd_soc_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_platform *platform = rtd->platform;
@@ -866,7 +1066,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_codec *codec = rtd->codec;
- mutex_lock(&pcm_mutex);
+ mutex_lock(&rtd->pcm_mutex);
/* apply codec digital mute */
if (!codec->active)
@@ -887,11 +1087,15 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
if (cpu_dai->driver->ops->hw_free)
cpu_dai->driver->ops->hw_free(substream, cpu_dai);
- mutex_unlock(&pcm_mutex);
+ if (rtd->dai_link->no_host_mode == SND_SOC_DAI_LINK_NO_HOST)
+ snd_pcm_lib_free_pages(substream);
+
+ mutex_unlock(&rtd->pcm_mutex);
return 0;
}
+EXPORT_SYMBOL_GPL(snd_soc_pcm_hw_free);
-static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+int snd_soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_platform *platform = rtd->platform;
@@ -918,13 +1122,14 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
}
return 0;
}
+EXPORT_SYMBOL_GPL(snd_soc_pcm_trigger);
/*
* soc level wrapper for pointer callback
* If cpu_dai, codec_dai, platform driver has the delay callback, than
* the runtime->delay will be updated accordingly.
*/
-static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
+snd_pcm_uframes_t snd_soc_pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_platform *platform = rtd->platform;
@@ -950,17 +1155,48 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
return offset;
}
+EXPORT_SYMBOL_GPL(snd_soc_pcm_pointer);
-/* ASoC PCM operations */
-static struct snd_pcm_ops soc_pcm_ops = {
- .open = soc_pcm_open,
- .close = soc_codec_close,
- .hw_params = soc_pcm_hw_params,
- .hw_free = soc_pcm_hw_free,
- .prepare = soc_pcm_prepare,
- .trigger = soc_pcm_trigger,
- .pointer = soc_pcm_pointer,
-};
+
+int snd_soc_pcm_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_platform *platform = rtd->platform;
+
+ if (platform->driver->ops->ioctl)
+ return platform->driver->ops->ioctl(substream, cmd, arg);
+ return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+
+struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
+ const char *dai_link, int stream)
+{
+ int i;
+
+ for (i = 0; i < card->num_links; i++) {
+ if (card->rtd[i].dai_link->no_pcm &&
+ !strcmp(card->rtd[i].dai_link->name, dai_link))
+ return card->rtd[i].pcm->streams[stream].substream;
+ }
+ dev_dbg(card->dev, "failed to find dai link %s\n", dai_link);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream);
+
+struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
+ const char *dai_link)
+{
+ int i;
+
+ for (i = 0; i < card->num_links; i++) {
+ if (!strcmp(card->rtd[i].dai_link->name, dai_link))
+ return &card->rtd[i];
+ }
+ dev_dbg(card->dev, "failed to find rtd %s\n", dai_link);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime);
#ifdef CONFIG_PM
/* powers down audio subsystem for suspend */
@@ -1038,12 +1274,12 @@ static int soc_suspend(struct device *dev)
continue;
if (driver->playback.stream_name != NULL)
- snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
- SND_SOC_DAPM_STREAM_SUSPEND);
+ snd_soc_dapm_stream_event(&card->rtd[i], SNDRV_PCM_STREAM_PLAYBACK,
+ driver->playback.stream_name, SND_SOC_DAPM_STREAM_SUSPEND);
if (driver->capture.stream_name != NULL)
- snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
- SND_SOC_DAPM_STREAM_SUSPEND);
+ snd_soc_dapm_stream_event(&card->rtd[i], SNDRV_PCM_STREAM_CAPTURE,
+ driver->capture.stream_name, SND_SOC_DAPM_STREAM_SUSPEND);
}
/* suspend all CODECs */
@@ -1140,12 +1376,12 @@ static void soc_resume_deferred(struct work_struct *work)
continue;
if (driver->playback.stream_name != NULL)
- snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
- SND_SOC_DAPM_STREAM_RESUME);
+ snd_soc_dapm_stream_event(&card->rtd[i], SNDRV_PCM_STREAM_PLAYBACK,
+ driver->playback.stream_name, SND_SOC_DAPM_STREAM_RESUME);
if (driver->capture.stream_name != NULL)
- snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
- SND_SOC_DAPM_STREAM_RESUME);
+ snd_soc_dapm_stream_event(&card->rtd[i], SNDRV_PCM_STREAM_CAPTURE,
+ driver->capture.stream_name, SND_SOC_DAPM_STREAM_RESUME);
}
/* unmute any active DACs */
@@ -1201,12 +1437,12 @@ static int soc_resume(struct device *dev)
if (cpu_dai->driver->ac97_control) {
dev_dbg(dev, "Resuming AC97 immediately\n");
soc_resume_deferred(&card->deferred_resume_work);
- } else {
- dev_dbg(dev, "Scheduling resume work\n");
- if (!schedule_work(&card->deferred_resume_work))
- dev_err(dev, "resume work item may be lost\n");
+ return 0;
}
}
+ dev_dbg(dev, "Scheduling resume work\n");
+ if (!schedule_work(&card->deferred_resume_work))
+ dev_err(dev, "resume work item may be lost\n");
return 0;
}
@@ -1215,9 +1451,32 @@ static int soc_resume(struct device *dev)
#define soc_resume NULL
#endif
+#define NULL_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 |\
+ SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 |\
+ SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32)
+
static struct snd_soc_dai_ops null_dai_ops = {
};
+static struct snd_soc_dai_driver null_codec_dai_drv = {
+ .name = "null-codec-dai",
+ .ops = &null_dai_ops,
+ .capture = {
+ .channels_min = 1 ,
+ .channels_max = 16,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .formats = NULL_FORMATS,
+ },
+ .playback = {
+ .channels_min = 1 ,
+ .channels_max = 16,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .formats = NULL_FORMATS,
+ },
+};
+static struct snd_soc_codec_driver null_codec_drv = {};
+
static int soc_bind_dai_link(struct snd_soc_card *card, int num)
{
struct snd_soc_dai_link *dai_link = &card->dai_link[num];
@@ -1261,7 +1520,7 @@ find_codec:
/* CODEC found, so find CODEC DAI from registered DAIs from this CODEC*/
list_for_each_entry(codec_dai, &dai_list, list) {
- if (codec->dev == codec_dai->dev &&
+ if ((codec->dev == codec_dai->dev || codec->driver == &null_codec_drv) &&
!strcmp(codec_dai->name, dai_link->codec_dai_name)) {
rtd->codec_dai = codec_dai;
goto find_platform;
@@ -1357,6 +1616,10 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num)
if (err < 0)
printk(KERN_ERR "asoc: failed to remove %s\n", platform->name);
}
+
+ /* Make sure all DAPM widgets are freed */
+ snd_soc_dapm_free(&platform->dapm);
+
platform->probed = 0;
list_del(&platform->card_list);
module_put(platform->dev->driver->owner);
@@ -1512,9 +1775,14 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
/* config components */
codec_dai->codec = codec;
+ platform->card = card;
cpu_dai->platform = platform;
codec_dai->card = card;
cpu_dai->card = card;
+ codec->card = card;
+ platform->dapm.card = card;
+ rtd->card = card;
+ rtd->dev.parent = card->dev;
/* set default power off timeout */
rtd->pmdown_time = pmdown_time;
@@ -1529,6 +1797,9 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
return ret;
}
}
+ /* Make sure all DAPM widgets are instantiated */
+ snd_soc_dapm_new_widgets(&platform->dapm);
+
cpu_dai->probed = 1;
/* mark cpu_dai as probed and add to card cpu_dai list */
list_add(&cpu_dai->card_list, &card->dai_dev_list);
@@ -1558,6 +1829,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
platform->probed = 1;
list_add(&platform->card_list, &card->platform_dev_list);
+ INIT_LIST_HEAD(&platform->dapm.list);
}
/* probe the CODEC DAI */
@@ -1578,6 +1850,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
/* DAPM dai link stream work */
INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
+ mutex_init(&rtd->pcm_mutex);
ret = soc_post_component_init(card, codec, num, 0);
if (ret)
@@ -1811,8 +2084,10 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
}
snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
- "%s", card->name);
+ "%s", card->name);
snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
+ "%s", card->long_name);
+ snprintf(card->snd_card->driver, sizeof(card->snd_card->driver),
"%s", card->name);
ret = snd_card_register(card->snd_card);
@@ -1972,6 +2247,7 @@ static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_pcm_substream *substream[2];
struct snd_pcm *pcm;
char new_name[64];
int ret = 0, playback = 0, capture = 0;
@@ -1980,10 +2256,17 @@ static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
snprintf(new_name, sizeof(new_name), "%s %s-%d",
rtd->dai_link->stream_name, codec_dai->name, num);
- if (codec_dai->driver->playback.channels_min)
- playback = 1;
- if (codec_dai->driver->capture.channels_min)
- capture = 1;
+ if (rtd->dai_link->dynamic) {
+ if (rtd->dai_link->fe_playback_channels)
+ playback = 1;
+ if (rtd->dai_link->fe_capture_channels)
+ capture = 1;
+ } else {
+ if (codec_dai->driver->playback.channels_min)
+ playback = 1;
+ if (codec_dai->driver->capture.channels_min)
+ capture = 1;
+ }
dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name);
ret = snd_pcm_new(rtd->card->snd_card, new_name,
@@ -1995,26 +2278,64 @@ static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
rtd->pcm = pcm;
pcm->private_data = rtd;
- soc_pcm_ops.mmap = platform->driver->ops->mmap;
- soc_pcm_ops.pointer = platform->driver->ops->pointer;
- soc_pcm_ops.ioctl = platform->driver->ops->ioctl;
- soc_pcm_ops.copy = platform->driver->ops->copy;
- soc_pcm_ops.silence = platform->driver->ops->silence;
- soc_pcm_ops.ack = platform->driver->ops->ack;
- soc_pcm_ops.page = platform->driver->ops->page;
+ substream[SNDRV_PCM_STREAM_PLAYBACK] =
+ pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ substream[SNDRV_PCM_STREAM_CAPTURE] =
+ pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+
+ if (rtd->dai_link->no_pcm) {
+ if (playback)
+ substream[SNDRV_PCM_STREAM_PLAYBACK]->private_data = rtd;
+ if (capture)
+ substream[SNDRV_PCM_STREAM_CAPTURE]->private_data = rtd;
+ goto out;
+ }
+
+ /* setup any hostless PCMs - i.e. no host IO is performed */
+ if (rtd->dai_link->no_host_mode) {
+ if (substream[SNDRV_PCM_STREAM_PLAYBACK]) {
+ substream[SNDRV_PCM_STREAM_PLAYBACK]->hw_no_buffer = 1;
+ snd_soc_set_runtime_hwparams(substream[SNDRV_PCM_STREAM_PLAYBACK],
+ &no_host_hardware);
+ }
+ if (substream[SNDRV_PCM_STREAM_CAPTURE]) {
+ substream[SNDRV_PCM_STREAM_CAPTURE]->hw_no_buffer = 1;
+ snd_soc_set_runtime_hwparams(substream[SNDRV_PCM_STREAM_CAPTURE],
+ &no_host_hardware);
+ }
+ }
+
+ /* ASoC PCM operations */
+ rtd->ops.open = snd_soc_pcm_open;
+ rtd->ops.hw_params = snd_soc_pcm_hw_params;
+ rtd->ops.prepare = snd_soc_pcm_prepare;
+ rtd->ops.trigger = snd_soc_pcm_trigger;
+ rtd->ops.hw_free = snd_soc_pcm_hw_free;
+ rtd->ops.close = snd_soc_pcm_close;
+ rtd->ops.pointer = snd_soc_pcm_pointer;
+ rtd->ops.ioctl = snd_soc_pcm_ioctl;
+ rtd->ops.ack = platform->driver->ops->ack;
+ rtd->ops.copy = platform->driver->ops->copy;
+ rtd->ops.silence = platform->driver->ops->silence;
+ rtd->ops.page = platform->driver->ops->page;
+ rtd->ops.mmap = platform->driver->ops->mmap;
if (playback)
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
if (capture)
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
- ret = platform->driver->pcm_new(rtd->card->snd_card, codec_dai, pcm);
+ if (!platform->driver->pcm_new)
+ goto out;
+ ret = platform->driver->pcm_new(rtd);
if (ret < 0) {
printk(KERN_ERR "asoc: platform pcm constructor failed\n");
return ret;
}
+out:
+
pcm->private_free = platform->driver->pcm_free;
printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
cpu_dai->name);
@@ -2209,6 +2530,10 @@ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
const struct snd_pcm_hardware *hw)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+
+ if (!runtime)
+ return 0;
+
runtime->hw.info = hw->info;
runtime->hw.formats = hw->formats;
runtime->hw.period_bytes_min = hw->period_bytes_min;
@@ -2285,6 +2610,35 @@ int snd_soc_add_controls(struct snd_soc_codec *codec,
EXPORT_SYMBOL_GPL(snd_soc_add_controls);
/**
+ * snd_soc_add_platform_controls - add an array of controls to a platform.
+ * Convienience function to add a list of controls.
+ *
+ * @platform: platform to add controls to
+ * @controls: array of controls to add
+ * @num_controls: number of elements in the array
+ *
+ * Return 0 for success, else error.
+ */
+int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
+ const struct snd_kcontrol_new *controls, int num_controls)
+{
+ struct snd_card *card = platform->card->snd_card;
+ int err, i;
+
+ for (i = 0; i < num_controls; i++) {
+ const struct snd_kcontrol_new *control = &controls[i];
+ err = snd_ctl_add(card, snd_soc_cnew(control, platform, NULL));
+ if (err < 0) {
+ dev_err(platform->dev, "Failed to add %s %d\n", control->name, err);
+ return err;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_add_platform_controls);
+
+/**
* snd_soc_info_enum_double - enumerated double mixer info callback
* @kcontrol: mixer control
* @uinfo: control element information
@@ -3107,7 +3461,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
*/
static int snd_soc_register_card(struct snd_soc_card *card)
{
- int i;
+ int i, ret = 0;
if (!card->name || !card->dev)
return -EINVAL;
@@ -3119,12 +3473,41 @@ static int snd_soc_register_card(struct snd_soc_card *card)
return -ENOMEM;
card->rtd_aux = &card->rtd[card->num_links];
- for (i = 0; i < card->num_links; i++)
+ for (i = 0; i < card->num_links; i++) {
+ /* create virtual CODEC for dynamic links */
+ dev_dbg(card->dev, "DAI create runtime %s\n", card->dai_link[i].name);
card->rtd[i].dai_link = &card->dai_link[i];
+ if (card->rtd[i].dai_link->dynamic) {
+
+ card->rtd[i].dai_link->codec_name = "null-codec";
+ card->rtd[i].dai_link->codec_dai_name = "null-codec-dai";
+ ret = snd_soc_register_codec(card->dev, &null_codec_drv,
+ &null_codec_dai_drv, 1);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: failed to register dynamic DAI link %d\n",
+ __func__, ret);
+ goto out;
+ }
+ continue;
+ }
+ if (card->rtd[i].dai_link->no_codec) {
+ card->rtd[i].dai_link->codec_name = "null-codec";
+
+ ret = snd_soc_register_codec(card->dev, &null_codec_drv,
+ &null_codec_dai_drv, 1);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: failed to register dynamic DAI link %d\n",
+ __func__, ret);
+ goto out;
+ }
+ continue;
+ }
+ }
INIT_LIST_HEAD(&card->list);
card->instantiated = 0;
mutex_init(&card->mutex);
+ mutex_init(&card->dapm_mutex);
mutex_lock(&client_mutex);
list_add(&card->list, &card_list);
@@ -3132,8 +3515,8 @@ static int snd_soc_register_card(struct snd_soc_card *card)
mutex_unlock(&client_mutex);
dev_dbg(card->dev, "Registered card '%s'\n", card->name);
-
- return 0;
+out:
+ return ret;
}
/**
@@ -3376,6 +3759,10 @@ int snd_soc_register_platform(struct device *dev,
return -ENOMEM;
}
+ platform->dapm.bias_level = SND_SOC_BIAS_OFF;
+ platform->dapm.dev = dev;
+ platform->dapm.platform = platform;
+ platform->dapm.stream_event = platform_drv->stream_event;
platform->dev = dev;
platform->driver = platform_drv;
@@ -3470,7 +3857,11 @@ int snd_soc_register_codec(struct device *dev,
return -ENOMEM;
/* create CODEC component name */
- codec->name = fmt_single_name(dev, &codec->id);
+ if (codec_drv == &null_codec_drv)
+ codec->name = kstrdup("null-codec", GFP_KERNEL);
+ else
+ codec->name = fmt_single_name(dev, &codec->id);
+
if (codec->name == NULL) {
kfree(codec);
return -ENOMEM;
@@ -3489,6 +3880,7 @@ int snd_soc_register_codec(struct device *dev,
codec->dev = dev;
codec->driver = codec_drv;
codec->num_dai = num_dai;
+ codec->dapm.stream_event = codec_drv->stream_event;
mutex_init(&codec->mutex);
/* allocate CODEC register cache */
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 1790f83ee66..4f69ef40f07 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -47,6 +47,8 @@
#include <trace/events/asoc.h>
+static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm);
+
/* dapm power sequences - make this per codec in the future */
static int dapm_up_seq[] = {
[snd_soc_dapm_pre] = 0,
@@ -123,6 +125,243 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
}
+static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg)
+{
+ if (w->codec)
+ return snd_soc_read(w->codec, reg);
+ else if (w->platform)
+ return snd_soc_platform_read(w->platform, reg);
+ return 0;
+}
+
+static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val)
+{
+ if (w->codec)
+ return snd_soc_write(w->codec, reg, val);
+ else if (w->platform)
+ return snd_soc_platform_write(w->platform, reg, val);
+ return 0;
+}
+
+int soc_widget_update_bits(struct snd_soc_dapm_widget *w, unsigned short reg,
+ unsigned int mask, unsigned int value)
+{
+ int change;
+ unsigned int old, new;
+
+ old = soc_widget_read(w, reg);
+ new = (old & ~mask) | value;
+ change = old != new;
+// if (change)
+ soc_widget_write(w, reg, new);
+
+ return change;
+}
+
+int soc_widget_test_bits(struct snd_soc_dapm_widget *w, unsigned short reg,
+ unsigned int mask, unsigned int value)
+{
+ int change;
+ unsigned int old, new;
+
+ old = soc_widget_read(w, reg);
+ new = (old & ~mask) | value;
+ change = old != new;
+
+ return change;
+}
+
+#define MAX_HOPS 16
+
+static void scenario_clear_paths(struct snd_soc_dapm_context *dapm)
+{
+ struct snd_soc_dapm_path *p;
+ struct snd_soc_dapm_widget *w;
+ struct list_head *l;
+
+ list_for_each(l, &dapm->card->paths) {
+ p = list_entry(l, struct snd_soc_dapm_path, list);
+ p->length = 0;
+ }
+ list_for_each(l, &dapm->card->widgets) {
+ w = list_entry(l, struct snd_soc_dapm_widget, list);
+ w->hops = 0;
+ }
+ dapm_clear_walk(dapm);
+}
+
+/*
+ * find all the paths between source and sink
+ */
+static int scenario_find_playback_paths(struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
+ int hops)
+{
+ struct list_head *lp;
+ struct snd_soc_dapm_path *path;
+ int dist = 0;
+
+ if (hops > MAX_HOPS)
+ return 0;
+
+ if (source == sink) {
+ dev_dbg(dapm->dev,"** found route with length %d\n", hops);
+ dapm->num_valid_paths++;
+ return 1;
+ }
+
+ if (source->hops && source->hops <= hops)
+ return 0;
+ source->hops = hops;
+
+ /*
+ * check all the output paths on this source widget
+ * by walking from source to sink
+ */
+ list_for_each(lp, &source->sinks) {
+ path = list_entry(lp, struct snd_soc_dapm_path, list_source);
+
+ dev_dbg(dapm->dev,"%d:try source %s path %s to %s len %d connect %d\n",
+ hops, source->name, path->name, path->sink->name,
+ path->length, path->connect);
+
+ /* been here before ? */
+ if (path->length && path->length <= hops)
+ continue;
+
+ /* check down the next path if connected */
+ if (path->sink && path->connect &&
+ scenario_find_playback_paths(dapm, path->sink, sink, hops + 1)) {
+ path->length = hops;
+ if (!dist || dist > path->length)
+ dist = path->length;
+ }
+ }
+
+ return dist;
+}
+
+static int scenario_find_capture_paths (struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
+ int hops)
+{
+ struct list_head *lp;
+ struct snd_soc_dapm_path *path;
+ int dist = 0;
+
+ if (hops > MAX_HOPS)
+ return 0;
+
+ if (source == sink) {
+ dev_dbg(dapm->dev,"** found route with length %d\n", hops);
+ dapm->num_valid_paths++;
+ return 1;
+ }
+
+ if (sink->hops && sink->hops <= hops)
+ return 0;
+ sink->hops = hops;
+
+ /*
+ * check all the output paths on this source widget
+ * by walking from sink to source
+ */
+ list_for_each(lp, &sink->sources) {
+ path = list_entry(lp, struct snd_soc_dapm_path, list_sink);
+
+ dev_dbg(dapm->dev,"%d:try sink %s path %s to %s len %d connect %d\n",
+ hops, sink->name, path->name, path->source->name,
+ path->length, path->connect);
+
+ /* been here before ? */
+ if (path->length && path->length <= hops)
+ continue;
+
+ /* check down the next path if connected */
+ if (path->source && path->connect &&
+ scenario_find_capture_paths(dapm, source, path->source, hops + 1)) {
+ path->length = hops;
+ if (!dist || dist > path->length)
+ dist = path->length;
+ }
+ }
+
+ return dist;
+}
+
+/*
+ * traverse the tree from sink to source via the shortest path
+ */
+static int scenario_get_playback_paths(struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink)
+{
+ dapm->num_valid_paths = 0;
+
+ dev_dbg(dapm->dev, "check playback path from %s to %s\n",
+ source->name, sink->name);
+ scenario_find_playback_paths(dapm, source, sink, 1);
+ return dapm->num_valid_paths;
+}
+
+static int scenario_get_capture_paths(struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink)
+{
+ dapm->num_valid_paths = 0;
+ dev_dbg(dapm->dev, "check capture path to %s from %s\n",
+ source->name, sink->name);
+ scenario_find_capture_paths(dapm, sink, source, 1);
+ return dapm->num_valid_paths;
+}
+
+/**
+ * snd_soc_scenario_set_path - set new scenario path
+ * @codec: the soc codec
+ * @scenario: the sceanrio path
+ *
+ * Sets up a new audio path within the audio susbsytem.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_scenario_set_path(struct snd_soc_dapm_context *dapm,
+ const char *source_name, const char *sink_name, int stream)
+{
+ struct snd_soc_dapm_widget *sink = NULL, *source = NULL;
+ struct list_head *l = NULL;
+ int routes;
+
+ /* find source */
+ list_for_each(l, &dapm->card->widgets) {
+ struct snd_soc_dapm_widget *w;
+ w = list_entry(l, struct snd_soc_dapm_widget, list);
+
+ if(!source && !strncmp(w->name, source_name, 16)) {
+ source = w;
+ continue;
+ }
+ if(!sink && !strncmp(w->name, sink_name, 16)) {
+ sink = w;
+ }
+ }
+
+ if(!source) {
+ printk(KERN_ERR "soc: invalid scenario source %s\n", source_name);
+ return -EINVAL;
+ }
+ if(!sink) {
+ printk(KERN_ERR "soc: invalid scenario sink %s\n", sink_name);
+ return -EINVAL;
+ }
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ routes = scenario_get_playback_paths(dapm, source, sink);
+ else
+ routes = scenario_get_capture_paths(dapm, source, sink);
+ scenario_clear_paths(dapm);
+
+ return routes;
+}
+EXPORT_SYMBOL_GPL(snd_soc_scenario_set_path);
+
/**
* snd_soc_dapm_set_bias_level - set the bias level for the system
* @card: audio device
@@ -193,7 +432,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
- val = snd_soc_read(w->codec, reg);
+ val = soc_widget_read(w, reg);
val = (val >> shift) & mask;
if ((invert && !val) || (!invert && val))
@@ -208,7 +447,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
;
- val = snd_soc_read(w->codec, e->reg);
+ val = soc_widget_read(w, e->reg);
item = (val >> e->shift_l) & (bitmask - 1);
p->connect = 0;
@@ -237,7 +476,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
w->kcontrols[i].private_value;
int val, item;
- val = snd_soc_read(w->codec, e->reg);
+ val = soc_widget_read(w, e->reg);
val = (val >> e->shift_l) & e->mask;
for (item = 0; item < e->max; item++) {
if (val == e->values[item])
@@ -326,7 +565,6 @@ static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
{
int change, power;
unsigned int old, new;
- struct snd_soc_codec *codec = widget->codec;
struct snd_soc_dapm_context *dapm = widget->dapm;
struct snd_soc_card *card = dapm->card;
@@ -343,7 +581,7 @@ static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
if (widget->invert)
power = (power ? 0:1);
- old = snd_soc_read(codec, widget->reg);
+ old = soc_widget_read(widget, widget->reg);
new = (old & ~(0x1 << widget->shift)) | (power << widget->shift);
change = old != new;
@@ -353,7 +591,7 @@ static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
widget->name, widget->power ? "on" : "off",
card->pop_time);
pop_wait(card->pop_time);
- snd_soc_write(codec, widget->reg, new);
+ soc_widget_write(widget, widget->reg, new);
}
dev_dbg(dapm->dev, "reg %x old %x new %x change %d\n", widget->reg,
old, new, change);
@@ -367,7 +605,14 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
int i, ret = 0;
size_t name_len;
struct snd_soc_dapm_path *path;
- struct snd_card *card = dapm->codec->card->snd_card;
+ struct snd_card *card;
+
+ if (dapm->codec)
+ card = dapm->codec->card->snd_card;
+ if (dapm->platform)
+ card = dapm->platform->card->snd_card;
+ if (!card)
+ return -ENODEV;
/* add kcontrol */
for (i = 0; i < w->num_kcontrols; i++) {
@@ -429,9 +674,16 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm,
{
struct snd_soc_dapm_path *path = NULL;
struct snd_kcontrol *kcontrol;
- struct snd_card *card = dapm->codec->card->snd_card;
+ struct snd_card *card;
int ret = 0;
+ if (dapm->codec)
+ card = dapm->codec->card->snd_card;
+ if (dapm->platform)
+ card = dapm->platform->card->snd_card;
+ if (!card)
+ return -ENODEV;
+
if (!w->num_kcontrols) {
dev_err(dapm->dev, "asoc: mux %s has no controls\n", w->name);
return -EINVAL;
@@ -479,7 +731,17 @@ static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm)
*/
static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
{
- int level = snd_power_get_state(widget->dapm->codec->card->snd_card);
+ struct snd_card *card;
+ int level;
+
+ if (widget->codec)
+ card = widget->codec->card->snd_card;
+ else if (widget->platform)
+ card = widget->platform->card->snd_card;
+ else
+ return 0;
+
+ level = snd_power_get_state(card);
switch (level) {
case SNDRV_CTL_POWER_D3hot:
@@ -601,7 +863,7 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
else
val = w->off_val;
- snd_soc_update_bits(w->codec, -(w->reg + 1),
+ soc_widget_update_bits(w, -(w->reg + 1),
w->mask << w->shift, val << w->shift);
return 0;
@@ -811,7 +1073,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
struct list_head *pending)
{
struct snd_soc_card *card = dapm->card;
- struct snd_soc_dapm_widget *w;
+ struct snd_soc_dapm_widget *w, *wf;
int reg, power;
unsigned int value = 0;
unsigned int mask = 0;
@@ -819,6 +1081,8 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
reg = list_first_entry(pending, struct snd_soc_dapm_widget,
power_list)->reg;
+ wf = list_first_entry(pending, struct snd_soc_dapm_widget,
+ power_list);
list_for_each_entry(w, pending, power_list) {
cur_mask = 1 << w->shift;
@@ -847,7 +1111,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
"pop test : Applying 0x%x/0x%x to %x in %dms\n",
value, mask, reg, card->pop_time);
pop_wait(card->pop_time);
- snd_soc_update_bits(dapm->codec, reg, mask, value);
+ soc_widget_update_bits(wf, reg, mask, value);
}
list_for_each_entry(w, pending, power_list) {
@@ -990,7 +1254,7 @@ static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
*/
static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
{
- struct snd_soc_card *card = dapm->codec->card;
+ struct snd_soc_card *card = NULL;
struct snd_soc_dapm_widget *w;
struct snd_soc_dapm_context *d;
LIST_HEAD(up_list);
@@ -998,6 +1262,13 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
int ret = 0;
int power;
+ if (dapm->codec)
+ card = dapm->codec->card;
+ if (dapm->platform)
+ card = dapm->platform->card;
+ if (!card)
+ return -ENODEV;
+
trace_snd_soc_dapm_start(card);
list_for_each_entry(d, &card->dapm_list, list)
@@ -1007,6 +1278,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
/* Check which widgets we need to power and store them in
* lists indicating if they should be powered up or down.
*/
+ mutex_lock(&card->dapm_mutex);
list_for_each_entry(w, &card->widgets, list) {
switch (w->id) {
case snd_soc_dapm_pre:
@@ -1041,6 +1313,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
break;
}
}
+ mutex_unlock(&card->dapm_mutex);
/* If there are no DAPM widgets then try to figure out power from the
* event type.
@@ -1244,7 +1517,7 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm)
#endif
/* test and update the power status of a mux widget */
-static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
struct snd_kcontrol *kcontrol, int change,
int mux, struct soc_enum *e)
{
@@ -1280,10 +1553,11 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
return 0;
}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
/* test and update the power status of a mixer or switch widget */
-static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
- struct snd_kcontrol *kcontrol, int connect)
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+ struct snd_kcontrol *kcontrol, int connect)
{
struct snd_soc_dapm_path *path;
int found = 0;
@@ -1309,6 +1583,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
return 0;
}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
/* show dapm widget status in sys fs */
static ssize_t dapm_widget_show(struct device *dev,
@@ -1464,7 +1739,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
char prefixed_source[80];
int ret = 0;
- if (dapm->codec->name_prefix) {
+ if (dapm->codec && dapm->codec->name_prefix) {
snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
dapm->codec->name_prefix, route->sink);
sink = prefixed_sink;
@@ -1686,7 +1961,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
}
/* Read the initial power state from the device */
- if (w->reg >= 0) {
+ if (w->reg >= 0 && w->codec) {
val = snd_soc_read(w->codec, w->reg);
val &= 1 << w->shift;
if (w->invert)
@@ -1704,6 +1979,23 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
+const char *snd_soc_dapm_get_aif(struct snd_soc_dapm_context *dapm,
+ const char *stream_name, enum snd_soc_dapm_type type)
+{
+ struct snd_soc_dapm_widget *w;
+
+ list_for_each_entry(w, &dapm->card->widgets, list) {
+
+ if (!w->sname)
+ continue;
+
+ if (w->id == type && strstr(w->sname, stream_name))
+ return w->name;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_aif);
+
/**
* snd_soc_dapm_get_volsw - dapm mixer get callback
* @kcontrol: mixer control
@@ -1727,10 +2019,10 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
unsigned int mask = (1 << fls(max)) - 1;
ucontrol->value.integer.value[0] =
- (snd_soc_read(widget->codec, reg) >> shift) & mask;
+ (soc_widget_read(widget, reg) >> shift) & mask;
if (shift != rshift)
ucontrol->value.integer.value[1] =
- (snd_soc_read(widget->codec, reg) >> rshift) & mask;
+ (soc_widget_read(widget, reg) >> rshift) & mask;
if (invert) {
ucontrol->value.integer.value[0] =
max - ucontrol->value.integer.value[0];
@@ -1777,7 +2069,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
mutex_lock(&widget->codec->mutex);
widget->value = val;
- change = snd_soc_test_bits(widget->codec, reg, mask, val);
+ change = soc_widget_test_bits(widget, reg, mask, val);
if (change) {
if (val)
/* new connection */
@@ -1793,7 +2085,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
update.val = val;
widget->dapm->update = &update;
- dapm_mixer_update_power(widget, kcontrol, connect);
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, connect);
widget->dapm->update = NULL;
}
@@ -1821,7 +2113,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
;
- val = snd_soc_read(widget->codec, e->reg);
+ val = soc_widget_read(widget, e->reg);
ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
if (e->shift_l != e->shift_r)
ucontrol->value.enumerated.item[1] =
@@ -1865,7 +2157,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
mutex_lock(&widget->codec->mutex);
widget->value = val;
- change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
+ change = soc_widget_test_bits(widget, e->reg, mask, val);
update.kcontrol = kcontrol;
update.widget = widget;
@@ -1874,7 +2166,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
update.val = val;
widget->dapm->update = &update;
- dapm_mux_update_power(widget, kcontrol, change, mux, e);
+ snd_soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
widget->dapm->update = NULL;
@@ -1924,7 +2216,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
change = widget->value != ucontrol->value.enumerated.item[0];
widget->value = ucontrol->value.enumerated.item[0];
- dapm_mux_update_power(widget, kcontrol, change, widget->value, e);
+ snd_soc_dapm_mux_update_power(widget, kcontrol, change, widget->value, e);
mutex_unlock(&widget->codec->mutex);
return ret;
@@ -1951,7 +2243,7 @@ int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int reg_val, val, mux;
- reg_val = snd_soc_read(widget->codec, e->reg);
+ reg_val = soc_widget_read(widget, e->reg);
val = (reg_val >> e->shift_l) & e->mask;
for (mux = 0; mux < e->max; mux++) {
if (val == e->values[mux])
@@ -2007,7 +2299,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
mutex_lock(&widget->codec->mutex);
widget->value = val;
- change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
+ change = soc_widget_test_bits(widget, e->reg, mask, val);
update.kcontrol = kcontrol;
update.widget = widget;
@@ -2016,7 +2308,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
update.val = val;
widget->dapm->update = &update;
- dapm_mux_update_power(widget, kcontrol, change, mux, e);
+ snd_soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
widget->dapm->update = NULL;
@@ -2114,14 +2406,14 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
return -ENOMEM;
name_len = strlen(widget->name) + 1;
- if (dapm->codec->name_prefix)
+ if (dapm->codec && dapm->codec->name_prefix)
name_len += 1 + strlen(dapm->codec->name_prefix);
w->name = kmalloc(name_len, GFP_KERNEL);
if (w->name == NULL) {
kfree(w);
return -ENOMEM;
}
- if (dapm->codec->name_prefix)
+ if (dapm->codec && dapm->codec->name_prefix)
snprintf(w->name, name_len, "%s %s",
dapm->codec->name_prefix, widget->name);
else
@@ -2130,6 +2422,7 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
dapm->n_widgets++;
w->dapm = dapm;
w->codec = dapm->codec;
+ w->platform = dapm->platform;
INIT_LIST_HEAD(&w->sources);
INIT_LIST_HEAD(&w->sinks);
INIT_LIST_HEAD(&w->list);
@@ -2200,6 +2493,10 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
}
dapm_power_widgets(dapm, event);
+
+ /* do we need to notify any clients that DAPM stream is complete */
+ if (dapm->stream_event)
+ dapm->stream_event(dapm);
}
/**
@@ -2214,16 +2511,27 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
* Returns 0 for success else error.
*/
int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
- const char *stream, int event)
+ int dir, const char *stream, int event)
{
- struct snd_soc_codec *codec = rtd->codec;
+ int i;
if (stream == NULL)
return 0;
- mutex_lock(&codec->mutex);
- soc_dapm_stream_event(&codec->dapm, stream, event);
- mutex_unlock(&codec->mutex);
+ if (rtd->dai_link->dynamic) {
+ for (i = 0; i < rtd->num_be[dir]; i++) {
+ struct snd_soc_platform *platform = rtd->be_rtd[i][dir]->platform;
+
+ soc_dapm_stream_event(&platform->dapm, stream, event);
+ }
+ } else {
+ struct snd_soc_codec *codec = rtd->codec;
+
+ mutex_lock(&codec->mutex);
+ soc_dapm_stream_event(&(codec->dapm), stream, event);
+ mutex_unlock(&codec->mutex);
+ }
+
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
index f4aa4e03c88..53ec40b356d 100644
--- a/sound/soc/txx9/txx9aclc.c
+++ b/sound/soc/txx9/txx9aclc.c
@@ -288,9 +288,10 @@ static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm)
snd_pcm_lib_preallocate_free_for_all(pcm);
}
-static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
- struct snd_pcm *pcm)
+static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
struct platform_device *pdev = to_platform_device(dai->platform->dev);
struct txx9aclc_soc_device *dev;
struct resource *r;