Context: Linux PSP 2.01.01.07, VIDEO_OMAP3_ISP, DMAI 1.20.00.06, Codec Engine 2.23.01, XDCtools 3.10.03, CodeGen 6.1.8, building for OMAP3530
Configuration: In the kernel config (make menuconfig), in Device Drivers --> Multimedia devices -->, set Video For Linux to 'M'. Then enable "Video capture adapters --->" (press 'Y' to change it to "[*]"). Then enter "Video capture adapters --->", and change both "OMAP ISP Previewer" and "OMAP ISP Resizer" to 'M'. Now if you search (by pressing '/') for VIDEO_OMAP3_ISP, it will have the value 'm' (it will be built as a module).
And it will almost work...
Boot the kernel and type "modprobe isp-mod". Loading the module will fail as follows (the large hex numbers will vary; underlines have been added for emphasis):
Unable to handle kernel NULL pointer dereference at virtual address 0000002c
pgd = c2030000
[0000002c] *pgd=82370031, *pte=00000000, *ppte=00000000
Internal error: Oops: 17 [#1]
Modules linked in: isp_mod(+) videobuf_dma_sg videobuf_core
CPU: 0 Not tainted (2.6.28-rc8-omap1 #6)
PC is at isp_reg_writel+0x18/0x28 [isp_mod]
LR is at ispmmu_init+0x24/0x3bc [isp_mod]
pc : [<bf00d040>] lr : [<bf0361c0>] psr: 60000013
sp : c4865da8 ip : c4865db8 fp : c4865db4
r10: 00000000 r9 : c4864000 r8 : bf036000
r7 : 00000000 r6 : 4013b000 r5 : 00000000 r4 : bf02e40c
r3 : 00000024 r2 : 00000010 r1 : 00000009 r0 : 00000002
...
Segmentation fault
ispmmu_init() is failing right away (at isp_reg_writel(2, OMAP3_ISP_IOMEM_MMU, ISPMMU_SYSCONFIG);). It expects three things to have happened before it is called (listed in expected chronological order):
- arch/arm/mach-omap2/devices.c:omap2_init_devices() must have called omap_init_isp(), which must have called platform_device_register() to identify the memory windows needed to access ISP registers.
- drivers/media/video/isp/isp.c:isp_init() must have called platform_driver_register() using the same name as in step 1.
- As long as both steps 1 and 2 have been performed, the kernel will call drivers/media/video/isp/isp.c:isp_probe() (chronologically, as step 2 is completed) which then opens up memory windows by repeatedly calling ioremap_uncache() (using values from arch/arm/mach-omap2/devices.c). If either step 1 or step 2 has not been performed, then the kernel will not bind the driver to the device, so isp_probe() will not be called, and memory windows will not be opened.
The specific coding issue is that arch/arm/mach-omap2/devices.c (as written) enables omap_init_isp() only if CONFIG_VIDEO_OMAP3_ISP is defined. If this is configured as a module (as described above), then instead CONFIG_VIDEO_OMAP3_ISP_MODULE is defined, so this function gets quietly stubbed out to do nothing. Thus step 1 is not satisfied, so the memory windows to the ISP registers are not open, so ispmmu_init() crashes when it tries to access an ISP register.
The fix is to edit arch/arm/mach-omap2/devices.c and change the line
#if defined (CONFIG_VIDEO_OMAP3_ISP)
to
#if defined(CONFIG_VIDEO_OMAP3_ISP) || defined(CONFIG_VIDEO_OMAP3_ISP_MODULE)
(which then matches the pattern of the other "#if defined" sequences in the file).
Now ISP support can be built-in ('y') or a module ('m').
Alternatively, if you want to remove the option to build ISP support as a kernel-loadable module (i.e., require it to be either built-in or disabled), then edit drivers/media/video/isp/Kconfig, go to the VIDEO_OMAP3_ISP section, and change "tristate" (y/n/m) to "bool" (y/n).