2009年12月29日 星期二
2009年12月28日 星期一
2009年11月16日 星期一
H.264 RTP Streaming
根據RFC3984以RTP 封裝H.264 raw data來作video streaming.
1.H.264 raw data
以00 00 01 或 00 00 00 01作為開頭(Start Code),接著是8 bit NALU
NALU的format
1.H.264 raw data
以00 00 01 或 00 00 00 01作為開頭(Start Code),接著是8 bit NALU
NALU的format
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
F : forbidden zero bit, 一定為0
NRI : nal_ref_idc, 表示資料的重要性, 00為最不重要.
Type :nal_unit_type, H.264只定義1~23的範圍
一個H.264 raw data看起來像這樣
00 00 00 01 09 30 ......
2.RTP header
因為一個H.264 video frame資料的大小往往會在數k bytes到數十K bytes,
在傳送封包時就會將資料切割分別封裝,也因此需要加入一些額外的參數讓
接收端可以正確組合被分割的video frame.這也是RFC3984最主要的目的.
RTP header 中有三個參數要注意
timestamp : 以90KHz作為基準,以30 fps為例,timestamp遞增 90000 / 30.
實務上是以payload實際間隔時間作計算.同一個video frame的
分割資料timestamp是相同的
sequence : 每個RTP封包sequence number都遞增.
mark bit : RTP封包封裝的是最後一個分割的video frame時mark bit 為 1.
2.Payload format
1~23 : Single NAL unit packet.
RFC3984使用了H.264 NALU中未定義的type 24~29 (相當於增加H.264 nal_unit_type定義)
24 : STAP-A 單一時間組合
25 : STAP-B 單一時間組合
26 : MTAP16 多個時間組合
27 : MTAP32 多個時間組合
28 : FU-A 分割資料
29 : FU-B 分割資料
比較常見的是28,29.
3.Single NAL unit packet
當資料少於MTU的大小就用此方式封裝.
H.264 raw data foramt 為 [Start code][NALU][Raw Data]
封裝時去掉Start Code即可.Format 如下
[RTP Header][NALU][Raw Date]
4.FU-A (Fragmentation unit)
當資料大於MTU以此方式分割
H.264 raw data foramt 為 [Start code][NALU][Raw Data]
去掉[Start code],[NALU],以不超過MTU大小分割[Raw Data]
以NALU產生FU indicator, FU Header.
RFC 3984
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FU indicator | FU header | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| |
| FU payload |
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| :...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 14. RTP payload format for FU-A
The FU indicator octet has the following format:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
The FU header has the following format:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R| Type |
+---------------+
[FU indicator] = (NALU & 0x60) | 28;
[FU Header] = (start << 7) | (end << 6) | (NALU & 0x1f);
format如下
[RTP Header][FU indicator][FU header][Raw Data Part 0]
[RTP Header][FU indicator][FU header][Raw Data Part 1]
[RTP Header][FU indicator][FU header][Raw Data Part 2]
...
5.FU-B (Fragmentation unit)
RFC 3984
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FU indicator | FU header | DON |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
| |
| FU payload |
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| :...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 15. RTP payload format for FU-B
format如下
[RTP Header][FU indicator][FU header][DON][Raw Data Part 0]
[RTP Header][FU indicator][FU header][DON][Raw Data Part 1]
[RTP Header][FU indicator][FU header][DON][Raw Data Part 2]
...
6.Encoding sample code with TI DSP
/* Write the encoded frame to the network */
if (Buffer_getNumBytesUsed(hOutBuf)) {
struct iovec data[3];
rtp_hdr_t rtp;
rtp.version = 2;
rtp.p = 0;
rtp.x = 0;
rtp.cc = 0;
rtp.m = 0;
rtp.pt = 96;
rtp.seq = htons( sequence );
rtp.ts = htonl( timestamp );
rtp.ssrc = 10;
data[0].iov_base = &rtp;
data[0].iov_len = sizeof(rtp_hdr_t);
unsigned char *ptr = (unsigned char *)Buffer_getUserPtr(hOutBuf);
size_t len = Buffer_getNumBytesUsed(hOutBuf);
size_t mtu = DEFAULT_MTU;
/* Skip NAL Start Code 00 00 00 01 */
unsigned char nalType = ptr[4] & 0x1f;
//printf("Processing Buffer with NAL TYPE=%d\n", nalType);
if(len < (mtu - sizeof(rtp_hdr_t))) {
/* Remove NAL Start Code 00 00 00 01 */
data[1].iov_base = (void *)ptr + 4;
data[1].iov_len = len - 4;
//printf("NAL Unit fit in one packet size=%d\n", len);
/* only set the marker bit on packets containing access units */
if (IS_ACCESS_UNIT (nalType))
rtp.m = 1;
writev(sfd, data, 2);
sequence++;
} else {
int start = 1, end = 0;
/* We keep 2 bytes for FU indicator and FU Header */
unsigned payload_len = mtu - sizeof(rtp_hdr_t) - 2;
unsigned char nalHeader = ptr[4];
/* Remove NAL Start Code 00 00 00 01 and NAL Type*/
ptr += 5;
len -= 5;
//printf("Using FU-A fragmentation for data size=%d\n", len);
while(end == 0) {
unsigned char fu[2];
payload_len = len < payload_len ? len : payload_len;
if (payload_len == len)
end = 1;
if (IS_ACCESS_UNIT (nalType))
rtp.m = end;
/* FU indicator */
fu[0] = (nalHeader & 0x60) | 28;
/* FU Header */
fu[1] = (start << 7) | (end << 6) | (nalHeader & 0x1f);
rtp.seq = htons( sequence );
data[1].iov_base = fu;
data[1].iov_len = 2;
data[2].iov_base = (void *)ptr;
data[2].iov_len = payload_len;
writev(sfd, data, 3);
start = 0;
ptr += payload_len;
len -= payload_len;
sequence++;
}
}
if (Time_delta(hTimestamp, &time) < 0) {
printf("Failed to get timer delta\n");
goto cleanup;
}
//printf("Read time: %uus\n", (Uns)time);
timestamp += (unsigned int)(0.09 * time); /*15 fps : 90000 / 15*/
}
2009年11月3日 星期二
OMAP3530 DSP Howto ( Really works by DSPLINK)
搞了一段很長的時間終於把DSP功能弄起來了,該是回頭紀錄一下"眉角"了.
1.Before touch anything
目前有兩種方式可以控制DSP,一個是TI DVSDK提供的DSPLINK,另一個則是DSPBRIDGE.
以我從google搜尋之後的了解DSPBRIDGE目前是沒有繼續maintain.
DSPLINK是TI比較建議的方式.
所搭配的media library為
DSPLINK + gstreamer
DSPBRIDGE + openmax + gstreamer
http://felipec.wordpress.com/2009/10/13/new-project-gst-dsp-with-beagleboard-demo-image/
http://felipec.wordpress.com/2008/12/12/gst-openmax-demo-on-the-beagleboard/
這邊我選擇DSPLINK控制DSP
2.Software
dvsdk_3_00_02_44
gst-ti-plugin-full-1.00.02
gst-omapfb
Build and install to target root file system (過程就省略了)
可參考以下作法
http://ossie.wireless.vt.edu/trac/wiki/BeagleBoard_CodecEngine
安裝目錄
DVSDK : /opt/dvsdk
gstreamer : /opt
3.Setup
DSPLINK透過share memory的方式跟DSP交換資料所以有另一個driver叫cmemk.ko負責建立memory pool. 但這塊memory必須脫離kernel的掌控因此必須要空出一塊memory讓cmemk.ko使用.至於大小要看實際memory size跟DSP所需要的size來決定.
http://pixhawk.ethz.ch/wiki/tutorials/omap/dsplink/memorymap
依照以上說明修改以下檔案
dsplink_1_61_03/packages/dsplink/config/all/CFG_OMAP3530_SHMEM.c
dsplink_1_61_03/packages/dsplink/dsp/inc/DspBios/5.XX/OMAP3530/dsplink-omap3530-base.tci
dsplink_1_61_03/packages/dsplink/config/all/CFG_OMAP3530_SHMEM.c
我的target board有256MB DDR,因此記憶體配置如下
# 0x40200000 60 KB CMEM (internal memory, see comment below)
# 0x80000000 200 MB Linux
# 0x8C900000 16 MB CMEM (external memory)
# 0x8D900000 2 MB DSPLINK (MEM)
# 0x8DB00000 unused
kernel boot command 加上 mem=200M
For kernel 2.6.27
optargs=init=/init omapfb.video_mode=1280x1024MR-16@60 vram=12M omapfb.vram=4M,4M,4M omapfb.debug=1 omap-dss.def_disp=lcd omap-dss.debug=1 mem=200M
For kernel 2.6.29
setenv optargs 'init=/init omapdss.def_disp=dvi omapfb.mode=dvi:1280x1024MR-16@60 vram=12M omapfb.vram=0:4M,1:4M,2:4M mem=200M'
memory pool配置如下
insmod cmemk.ko phys_start=0x8C900000 phys_end=0x8D900000 pools=20x4096,10x131072,2x1048576,1x5250000,4x829440,2x691200
gstreamer需要設定target上的環境變數好讓系統找的到執行檔及plug-in
export PATH=$PATH:/opt/gstreamer/bin
export GST_PLUGIN_PATH=/opt/gstreamer/lib/gstreamer-0.10
export LD_LIBRARY_PATH=/opt/gstreamer/lib
3.Get DSP work
載入drivers
#cd /opt/dvsdk
#./loadmodules.sh
CMEMK module: built on Oct 30 2009 at 20:23:52
Reference Linux version 2.6.28
File /home/gigijoe/OMAP3530/dvsdk_3_00_02_44/linuxutils_2_24_02/packages/ti/sdo/linuxutils/cmem/src/module/cmemk.c
ioremap_nocache(0x8c900000, 16777216)=0xcf000000
allocated heap buffer 0xcf000000 of size 0x32c000
cmem initialized 6 pools between 0x8c900000 and 0x8d900000
DSPLINK Module (1.61.03) created on Date: Oct 30 2009 Time: 20:20:31
# lsmod
lpm_omap3530 8276 0 - Live 0xbf02c000
dsplinkk 114052 1 lpm_omap3530, Live 0xbf00b000
cmemk 24428 0 - Live 0xbf000000
測試omapfb, 應該會在畫面上看到彩色條紋.
gst-launch videotestsrc num-buffers=1000 ! omapfbsink
播放TI h.264 raw data sample
gst-launch --gst-debug-level=1 filesrc location="/media/dcim/100andro/ntsc.264" ! typefind ! TIViddec2 ! omapfbsink
Play avi file
gst-launch --gst-debug-no-color --gst-debug=TI*:2 filesrc location=/media/dcim/100andro/aris.mpeg ! typefind ! qtdemux name=demux demux.audio_00 ! queue max-size-buffers=8000 max-size-time=0 max-size-bytes=0 ! typefind ! TIAuddec1 ! audioconvert ! osssink demux.video_00 ! typefind ! TIViddec2 ! omapfbsink
Play mpeg4 file
gst-launch --gst-debug-no-color --gst-debug=TI*:2 filesrc location=/media/dcim/100andro/KenBlock-TopGear.mp4 ! typefind ! qtdemux name=demux demux.audio_00 ! queue max-size-buffers=8000 max-size-time=0 max-size-bytes=0 ! typefind ! TIAuddec1 ! audioconvert ! osssink demux.video_00 ! typefind ! TIViddec2 ! omapfbsink
Play H.264 mpeg4 file without mp3 audio
gst-launch filesrc location=/media/dcim/100andro/sany0014.mp4 ! typefind ! qtdemux name=demux demux.video_00 ! typefind ! TIViddec2 ! omapfbsink
4.Debug
http://tiexpressdsp.com/wiki/index.php?title=Debugging_DSPLink_using_SET_FAILURE_REASON_prints
http://tiexpressdsp.com/index.php/Enabling_trace_in_DSPLink
一開始有一段時間kernel-2.6.29 DSP_init總是失敗
# ./messagegpp ./message.out 1000
========== Sample Application : Failure [0x8000800b] in [0x401] at line 522
MESSAGE ==========
Entered MESSFailure [0x8000802d] in [0x401] at line 544
AGE_Create ()
Failure [0x8000802d] in [0x401] at line 544
Failure [0x8000802d] in [0x401] at line 544
ISR_Install:445
request_irq 28
request_irq failed with error: -16
Failure [0x80008008] in [0x502] at line 459
Failure [0x80008008] in [0x80a] at line 824
Failure [0x80008008] in [0x80a] at line 1061
Failure [0x80008008] in [0x801] at line 597
Failure [0x80008008] in [0x701] at line 370
DSP_init status [0x80008008]
Assertion failed ((isrObj!= NULL) && (ISR_InstalledIsrs [isrObj->dspId][isrObj->irq] == isrObj)). File : /home/gigijoe/OMAP3530/dvsdk_3_00_02_44/dsplink_1_61_03/packages/dsplink/gp
p/src/../../gpp/src/osal/Linux/2.6.18/isr.c Line : 507
Failure [0x80008000] in [0x502] at line 515
Failure [0x80008008] in [0x300] at line 476
Failure [0x80008008] in [0x300] at line 563
PROC_attach () failed. Status = [0x80008008]
PROC_setup () failed. Status = [0x80008008]
Leaving MESSAGE_Create ()
Entered MESSAGE_Delete ()
Assertion failed (IS_VALID_MSGQ (msgqQueue)). File : msgq.c Line : 484
MSGQ_release () failed. Status = [0x8000800b]
Assertion failed (IS_VALID_MSGQ (msgqQueue)). File : msgq.c Line : 335
Leaving MESSAGE_Delete ()
====================================================
Trace DSPLINK driver發現request_irq 28 居然失敗了.很明顯IRQ被佔據了.
看看到底是誰
cat /proc/interrupts
CPU0
11: 0 INTC prcm
12: 1 INTC DMA
18: 0 INTC sr1
19: 0 INTC sr2
24: 0 INTC omap-iommu.1, Omap 3 Camera ISP
25: 1 INTC OMAP DSS
28: 0 INTC omap-iommu.2
56: 347 INTC i2c_omap
61: 0 INTC i2c_omap
72: 1 INTC serial idle
73: 1 INTC serial idle
74: 94 INTC serial idle, serial
77: 0 INTC ehci_hcd:usb2
83: 0 INTC mmc0
86: 14 INTC mmc1
92: 0 INTC musb_hdrc
93: 0 INTC musb_hdrc
95: 641 INTC gp timer
160: 0 GPIO mmc1
167: 0 GPIO user
181: 8 GPIO eth0
378: 0 twl4030 twl4030_usb
379: 0 twl4030 rtc0
384: 0 twl4030 mmc0
原來是iommu啊,OK,調整一下kernel config
Disable
Device Drivers->Multimedia Devices->Video Capture Adapters->OMAP 3 Camera Support
System Type->TI OMAP Implemenation->IOMMU Support
這樣就OK囉
其實還有一些疑慮沒有解決.
IOMMU 以 Shared IRQ 方式 request_irq而DSPLINK Driver request_irq 並不是.
因此造成問題,DSPLINK Driver是否應該以Shared IRQ方式request_irq呢?
Problem :
# gst-launch --gst-debug=TI*:2 v4l2src always_copy=FALSE num-buffers=100 ! video
/x-raw-yuv,width=320,height=240 ! ffmpegcolorspace ! TIVidenc1 codecName=h264enc
engineName=codecServer contiguousInputFrame=FALSE genTimeStamps=FALSE ! filesin
k location=/tmp/enc.264
(gst-launch-0.10:636): GLib-WARNING **: getpwuid_r(): failed due to unknown user id (0)
Setting pipeline to PAUSED ...
Pipeline is live and does not need PREROLL ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
0:00:01.011901868 636 0x9ebb0 WARN TIVidenc1 gsttividenc1.c:1432:gst_tividenc1_codec_start: error: failed to open codec engine "codecServer"
ERROR: from element /GstPipeline:pipeline0/GstTIVidenc1:tividenc10: failed to open codec engine "codecServer"
Additional debug info:
gsttividenc1.c(1432): gst_tividenc1_codec_start (): /GstPipeline:pipeline0/GstTIVidenc1:tividenc10
Execution ended after 382354731 ns.
Setting pipeline to PAUSED ...
Setting pipeline to READY ...
0:00:01.016387951 636 0x9ebb0 WARN TIVidenc1 gsttividenc1.c:1601:gst_tividenc1_encode_thread: error: failed to start codec
gst-launch-0.10: BufTab.c:440: BufTab_getNumBufs: Assertion `hBufTab' failed.
Aborted
重新compile ti-gstreamer就好了...
Problem:
ERROR: from element /GstPipeline:pipeline0/GstTIViddec2:tividdec20: Failed to determine target board
這個問題是因為所使用的OMAP3530 board不是TI support的.
自己修改來support吧
Get board name first
# cat /proc/cpuinfo
Processor : ARMv7 Processor rev 3 (v7l)
BogoMIPS : 499.92
Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x1
CPU part : 0xc08
CPU revision : 3
Hardware : OMAP3 Thunder Board
Revision : 0020
Serial : 0000000000000000
So, the board name is OMAP3 Thunder Board
Edit dmai_2_05_00_04/packages/ti/sdo/dmai/linux/Cpu.c
...
}
else if ((strcmp(valBuf,"OMAP3EVM Board") == 0) ||
(strcmp(valBuf, "OMAP3 EVM") == 0) ||
(strcmp(valBuf, "OMAP3 Beagle Board") == 0) ||
(strcmp(valBuf, "OMAP3 Thunder Board") == 0)) { <<-- Add here
*device = Cpu_Device_OMAP3530;
}
else {
Dmai_err0("Unknown Cpu Type!\n");
return Dmai_EFAIL;
}
return Dmai_EOK;
}
...
Then rebuild again ...
1.Before touch anything
目前有兩種方式可以控制DSP,一個是TI DVSDK提供的DSPLINK,另一個則是DSPBRIDGE.
以我從google搜尋之後的了解DSPBRIDGE目前是沒有繼續maintain.
DSPLINK是TI比較建議的方式.
所搭配的media library為
DSPLINK + gstreamer
DSPBRIDGE + openmax + gstreamer
http://felipec.wordpress.com/2009/10/13/new-project-gst-dsp-with-beagleboard-demo-image/
http://felipec.wordpress.com/2008/12/12/gst-openmax-demo-on-the-beagleboard/
這邊我選擇DSPLINK控制DSP
2.Software
dvsdk_3_00_02_44
gst-ti-plugin-full-1.00.02
gst-omapfb
Build and install to target root file system (過程就省略了)
可參考以下作法
http://ossie.wireless.vt.edu/trac/wiki/BeagleBoard_CodecEngine
安裝目錄
DVSDK : /opt/dvsdk
gstreamer : /opt
3.Setup
DSPLINK透過share memory的方式跟DSP交換資料所以有另一個driver叫cmemk.ko負責建立memory pool. 但這塊memory必須脫離kernel的掌控因此必須要空出一塊memory讓cmemk.ko使用.至於大小要看實際memory size跟DSP所需要的size來決定.
http://pixhawk.ethz.ch/wiki/tutorials/omap/dsplink/memorymap
依照以上說明修改以下檔案
dsplink_1_61_03/packages/dsplink/config/all/CFG_OMAP3530_SHMEM.c
dsplink_1_61_03/packages/dsplink/dsp/inc/DspBios/5.XX/OMAP3530/dsplink-omap3530-base.tci
dsplink_1_61_03/packages/dsplink/config/all/CFG_OMAP3530_SHMEM.c
我的target board有256MB DDR,因此記憶體配置如下
# 0x40200000 60 KB CMEM (internal memory, see comment below)
# 0x80000000 200 MB Linux
# 0x8C900000 16 MB CMEM (external memory)
# 0x8D900000 2 MB DSPLINK (MEM)
# 0x8DB00000 unused
kernel boot command 加上 mem=200M
For kernel 2.6.27
optargs=init=/init omapfb.video_mode=1280x1024MR-16@60 vram=12M omapfb.vram=4M,4M,4M omapfb.debug=1 omap-dss.def_disp=lcd omap-dss.debug=1 mem=200M
For kernel 2.6.29
setenv optargs 'init=/init omapdss.def_disp=dvi omapfb.mode=dvi:1280x1024MR-16@60 vram=12M omapfb.vram=0:4M,1:4M,2:4M mem=200M'
memory pool配置如下
insmod cmemk.ko phys_start=0x8C900000 phys_end=0x8D900000 pools=20x4096,10x131072,2x1048576,1x5250000,4x829440,2x691200
gstreamer需要設定target上的環境變數好讓系統找的到執行檔及plug-in
export PATH=$PATH:/opt/gstreamer/bin
export GST_PLUGIN_PATH=/opt/gstreamer/lib/gstreamer-0.10
export LD_LIBRARY_PATH=/opt/gstreamer/lib
3.Get DSP work
載入drivers
#cd /opt/dvsdk
#./loadmodules.sh
CMEMK module: built on Oct 30 2009 at 20:23:52
Reference Linux version 2.6.28
File /home/gigijoe/OMAP3530/dvsdk_3_00_02_44/linuxutils_2_24_02/packages/ti/sdo/linuxutils/cmem/src/module/cmemk.c
ioremap_nocache(0x8c900000, 16777216)=0xcf000000
allocated heap buffer 0xcf000000 of size 0x32c000
cmem initialized 6 pools between 0x8c900000 and 0x8d900000
DSPLINK Module (1.61.03) created on Date: Oct 30 2009 Time: 20:20:31
# lsmod
lpm_omap3530 8276 0 - Live 0xbf02c000
dsplinkk 114052 1 lpm_omap3530, Live 0xbf00b000
cmemk 24428 0 - Live 0xbf000000
測試omapfb, 應該會在畫面上看到彩色條紋.
gst-launch videotestsrc num-buffers=1000 ! omapfbsink
播放TI h.264 raw data sample
gst-launch --gst-debug-level=1 filesrc location="/media/dcim/100andro/ntsc.264" ! typefind ! TIViddec2 ! omapfbsink
Play avi file
gst-launch --gst-debug-no-color --gst-debug=TI*:2 filesrc location=/media/dcim/100andro/aris.mpeg ! typefind ! qtdemux name=demux demux.audio_00 ! queue max-size-buffers=8000 max-size-time=0 max-size-bytes=0 ! typefind ! TIAuddec1 ! audioconvert ! osssink demux.video_00 ! typefind ! TIViddec2 ! omapfbsink
Play mpeg4 file
gst-launch --gst-debug-no-color --gst-debug=TI*:2 filesrc location=/media/dcim/100andro/KenBlock-TopGear.mp4 ! typefind ! qtdemux name=demux demux.audio_00 ! queue max-size-buffers=8000 max-size-time=0 max-size-bytes=0 ! typefind ! TIAuddec1 ! audioconvert ! osssink demux.video_00 ! typefind ! TIViddec2 ! omapfbsink
Play H.264 mpeg4 file without mp3 audio
gst-launch filesrc location=/media/dcim/100andro/sany0014.mp4 ! typefind ! qtdemux name=demux demux.video_00 ! typefind ! TIViddec2 ! omapfbsink
4.Debug
http://tiexpressdsp.com/wiki/index.php?title=Debugging_DSPLink_using_SET_FAILURE_REASON_prints
http://tiexpressdsp.com/index.php/Enabling_trace_in_DSPLink
一開始有一段時間kernel-2.6.29 DSP_init總是失敗
# ./messagegpp ./message.out 1000
========== Sample Application : Failure [0x8000800b] in [0x401] at line 522
MESSAGE ==========
Entered MESSFailure [0x8000802d] in [0x401] at line 544
AGE_Create ()
Failure [0x8000802d] in [0x401] at line 544
Failure [0x8000802d] in [0x401] at line 544
ISR_Install:445
request_irq 28
request_irq failed with error: -16
Failure [0x80008008] in [0x502] at line 459
Failure [0x80008008] in [0x80a] at line 824
Failure [0x80008008] in [0x80a] at line 1061
Failure [0x80008008] in [0x801] at line 597
Failure [0x80008008] in [0x701] at line 370
DSP_init status [0x80008008]
Assertion failed ((isrObj!= NULL) && (ISR_InstalledIsrs [isrObj->dspId][isrObj->irq] == isrObj)). File : /home/gigijoe/OMAP3530/dvsdk_3_00_02_44/dsplink_1_61_03/packages/dsplink/gp
p/src/../../gpp/src/osal/Linux/2.6.18/isr.c Line : 507
Failure [0x80008000] in [0x502] at line 515
Failure [0x80008008] in [0x300] at line 476
Failure [0x80008008] in [0x300] at line 563
PROC_attach () failed. Status = [0x80008008]
PROC_setup () failed. Status = [0x80008008]
Leaving MESSAGE_Create ()
Entered MESSAGE_Delete ()
Assertion failed (IS_VALID_MSGQ (msgqQueue)). File : msgq.c Line : 484
MSGQ_release () failed. Status = [0x8000800b]
Assertion failed (IS_VALID_MSGQ (msgqQueue)). File : msgq.c Line : 335
Leaving MESSAGE_Delete ()
====================================================
Trace DSPLINK driver發現request_irq 28 居然失敗了.很明顯IRQ被佔據了.
看看到底是誰
cat /proc/interrupts
CPU0
11: 0 INTC prcm
12: 1 INTC DMA
18: 0 INTC sr1
19: 0 INTC sr2
24: 0 INTC omap-iommu.1, Omap 3 Camera ISP
25: 1 INTC OMAP DSS
28: 0 INTC omap-iommu.2
56: 347 INTC i2c_omap
61: 0 INTC i2c_omap
72: 1 INTC serial idle
73: 1 INTC serial idle
74: 94 INTC serial idle, serial
77: 0 INTC ehci_hcd:usb2
83: 0 INTC mmc0
86: 14 INTC mmc1
92: 0 INTC musb_hdrc
93: 0 INTC musb_hdrc
95: 641 INTC gp timer
160: 0 GPIO mmc1
167: 0 GPIO user
181: 8 GPIO eth0
378: 0 twl4030 twl4030_usb
379: 0 twl4030 rtc0
384: 0 twl4030 mmc0
原來是iommu啊,OK,調整一下kernel config
Disable
Device Drivers->Multimedia Devices->Video Capture Adapters->OMAP 3 Camera Support
System Type->TI OMAP Implemenation->IOMMU Support
這樣就OK囉
其實還有一些疑慮沒有解決.
IOMMU 以 Shared IRQ 方式 request_irq而DSPLINK Driver request_irq 並不是.
因此造成問題,DSPLINK Driver是否應該以Shared IRQ方式request_irq呢?
Problem :
# gst-launch --gst-debug=TI*:2 v4l2src always_copy=FALSE num-buffers=100 ! video
/x-raw-yuv,width=320,height=240 ! ffmpegcolorspace ! TIVidenc1 codecName=h264enc
engineName=codecServer contiguousInputFrame=FALSE genTimeStamps=FALSE ! filesin
k location=/tmp/enc.264
(gst-launch-0.10:636): GLib-WARNING **: getpwuid_r(): failed due to unknown user id (0)
Setting pipeline to PAUSED ...
Pipeline is live and does not need PREROLL ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
0:00:01.011901868 636 0x9ebb0 WARN TIVidenc1 gsttividenc1.c:1432:gst_tividenc1_codec_start: error: failed to open codec engine "codecServer"
ERROR: from element /GstPipeline:pipeline0/GstTIVidenc1:tividenc10: failed to open codec engine "codecServer"
Additional debug info:
gsttividenc1.c(1432): gst_tividenc1_codec_start (): /GstPipeline:pipeline0/GstTIVidenc1:tividenc10
Execution ended after 382354731 ns.
Setting pipeline to PAUSED ...
Setting pipeline to READY ...
0:00:01.016387951 636 0x9ebb0 WARN TIVidenc1 gsttividenc1.c:1601:gst_tividenc1_encode_thread: error: failed to start codec
gst-launch-0.10: BufTab.c:440: BufTab_getNumBufs: Assertion `hBufTab' failed.
Aborted
重新compile ti-gstreamer就好了...
Problem:
ERROR: from element /GstPipeline:pipeline0/GstTIViddec2:tividdec20: Failed to determine target board
這個問題是因為所使用的OMAP3530 board不是TI support的.
自己修改來support吧
Get board name first
# cat /proc/cpuinfo
Processor : ARMv7 Processor rev 3 (v7l)
BogoMIPS : 499.92
Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x1
CPU part : 0xc08
CPU revision : 3
Hardware : OMAP3 Thunder Board
Revision : 0020
Serial : 0000000000000000
So, the board name is OMAP3 Thunder Board
Edit dmai_2_05_00_04/packages/ti/sdo/dmai/linux/Cpu.c
...
}
else if ((strcmp(valBuf,"OMAP3EVM Board") == 0) ||
(strcmp(valBuf, "OMAP3 EVM") == 0) ||
(strcmp(valBuf, "OMAP3 Beagle Board") == 0) ||
(strcmp(valBuf, "OMAP3 Thunder Board") == 0)) { <<-- Add here
*device = Cpu_Device_OMAP3530;
}
else {
Dmai_err0("Unknown Cpu Type!\n");
return Dmai_EFAIL;
}
return Dmai_EOK;
}
...
Then rebuild again ...
2009年9月24日 星期四
OMAP3530 DSP Howto
沿襲TI一貫的傳統,Software package & document一堆但都缺乏最基本的Step-by-Step.
在網路上搜尋到一些resource先記下來
GSG: OMAP35x DVEVM Software Setup
BeagleBoard/DSP Howto
BeagleBoard/gst-openmax
http://groups.google.com/group/beagleboard/browse_thread/thread/05557a0d149fb225
gst-openmax demo on the beagleboard
1.Install TI dspbridge libraries
cd ${HOME}/OMAP3530
git clone git://gitorious.org/ti-dspbridge/userspace.git ti_dspbridge
cd ti_dspbridge
cp -a binaries/lib/lib* ../beagle-cupcake/out/target/product/beagleboard/root/lib
cp source/samples/utils/uninstall_bridge ../beagle-cupcake/out/target/product/beagleboard/root/dspbridge/
mkdir ../beagle-cupcake/out/target/product/beagleboard/root/dspbridge
cp source/samples/utils/install_bridge ../beagle-cupcake/out/target/product/beagleboard/root/dspbridge/
cd ..
2.Install TI OpenMAX IL
Download tiopenmax-0.4.1
cd tiopenmax-0.4.1
Append below to Makefile
export OMXROOT=$(shell /bin/pwd)
export CROSS=arm-none-linux-gnueabi-
export PKGDIR=$(shell /bin/pwd)
export PREFIX=$(shell /bin/pwd)
#export TARGETDIR=${PREFIX}/rootfs
export TARGETDIR=${HOME}/OMAP3530/beagle-cupcake/out/target/product/beagleboard/root
export BRIDGEINCLUDEDIR=${HOME}/OMAP3530/ti_dspbridge/source/mpu_api/inc
export BRIDGELIBDIR=${TARGETDIR}/lib
mkdir ../beagle-cupcake/out/target/product/beagleboard/root/omx
make avplay.clobber avplay
cp bin/cexec.out ../beagle-cupcake/out/target/product/beagleboard/root/dspbridge
mkdir ../beagle-cupcake/out/target/product/beagleboard/root/share
cp -a share/* ../beagle-cupcake/out/target/product/beagleboard/root/share/
3.Install DSP Binary
Download Android_DSP_Binaries-1.2-Linux-x86-Install.tar.gz
/**********/
Install DSP Binaries to ${HOME}/OMAP3530/beagle-cupcake/out/target/product/beagleboard/root/lib/dsp
gigijoe@gigijoe-laptop:~/OMAP3530/beagle-cupcake/out/target/product/beagleboard/root/lib/dsp$ ls
baseimage.dof h264vdec_sn.dll64P m4venc_sn.dll64P postprocessor.dll64P usn.dll64P
conversions.dll64P jpegdec_sn.dll64P mp4vdec_sn.dll64P postprocessor_dualout.dll64P vpp_sn.dll64P
dctn_dyn.dll64P jpegenc_sn.dll64P mpeg4aacdec_sn.dll64P ringio.dll64P
/**********/
在網路上搜尋到一些resource先記下來
GSG: OMAP35x DVEVM Software Setup
BeagleBoard/DSP Howto
BeagleBoard/gst-openmax
http://groups.google.com/group/beagleboard/browse_thread/thread/05557a0d149fb225
gst-openmax demo on the beagleboard
1.Install TI dspbridge libraries
cd ${HOME}/OMAP3530
git clone git://gitorious.org/ti-dspbridge/userspace.git ti_dspbridge
cd ti_dspbridge
cp -a binaries/lib/lib* ../beagle-cupcake/out/target/product/beagleboard/root/lib
cp source/samples/utils/uninstall_bridge ../beagle-cupcake/out/target/product/beagleboard/root/dspbridge/
mkdir ../beagle-cupcake/out/target/product/beagleboard/root/dspbridge
cp source/samples/utils/install_bridge ../beagle-cupcake/out/target/product/beagleboard/root/dspbridge/
cd ..
2.Install TI OpenMAX IL
Download tiopenmax-0.4.1
cd tiopenmax-0.4.1
Append below to Makefile
export OMXROOT=$(shell /bin/pwd)
export CROSS=arm-none-linux-gnueabi-
export PKGDIR=$(shell /bin/pwd)
export PREFIX=$(shell /bin/pwd)
#export TARGETDIR=${PREFIX}/rootfs
export TARGETDIR=${HOME}/OMAP3530/beagle-cupcake/out/target/product/beagleboard/root
export BRIDGEINCLUDEDIR=${HOME}/OMAP3530/ti_dspbridge/source/mpu_api/inc
export BRIDGELIBDIR=${TARGETDIR}/lib
mkdir ../beagle-cupcake/out/target/product/beagleboard/root/omx
make avplay.clobber avplay
cp bin/cexec.out ../beagle-cupcake/out/target/product/beagleboard/root/dspbridge
mkdir ../beagle-cupcake/out/target/product/beagleboard/root/share
cp -a share/* ../beagle-cupcake/out/target/product/beagleboard/root/share/
3.Install DSP Binary
Download Android_DSP_Binaries-1.2-Linux-x86-Install.tar.gz
/**********/
Install DSP Binaries to ${HOME}/OMAP3530/beagle-cupcake/out/target/product/beagleboard/root/lib/dsp
gigijoe@gigijoe-laptop:~/OMAP3530/beagle-cupcake/out/target/product/beagleboard/root/lib/dsp$ ls
baseimage.dof h264vdec_sn.dll64P m4venc_sn.dll64P postprocessor.dll64P usn.dll64P
conversions.dll64P jpegdec_sn.dll64P mp4vdec_sn.dll64P postprocessor_dualout.dll64P vpp_sn.dll64P
dctn_dyn.dll64P jpegenc_sn.dll64P mpeg4aacdec_sn.dll64P ringio.dll64P
/**********/
2009年9月23日 星期三
OMAP3530 MINI V3 + 0xdroid
ICETEK OMAP3530 MINI V3號稱硬體跟beagle board相容.
由於mini board有512MB nand flash & DM9000 ethernet所以捨棄了beagle board.
但風險就是萬一硬體有不相容的地方就得自己搞了
http://code.google.com/p/beagleboard/wiki/BeagleSoftCompile
1.OMAP3530 boot
Boot對Embedded System是一件大事,就像生命的起源一般.
OMAP3530可以從nand flash or SD card boot,由x-loader開始.
x-loader負責初始化CUP,包含memory & nand flash,之後會載入並執行u-boot.
預設供電後由nand flash載入x-loader.
按住user button + reset button就會由SD card載入x-loader.
2.Compile x-loader
修改xloader/include/configs/omap3530Mini.h
/* NAND is partitioned:
* 0x00000000 - 0x0007FFFF Booting Image
* 0x00080000 - 0x0025FFFF U-Boot Image
* 0x00260000 - 0x0027FFFF U-Boot Env Data (X-loader doesn't care)
* 0x00280000 - 0x0067FFFF Kernel Image
* 0x00680000 - 0x08000000 depends on application
*/
#define NAND_UBOOT_START 0x0080000 /* Leaving first 4 blocks for x-load */
#define NAND_UBOOT_END 0x0260000 /* Giving a space of 2 blocks = 256KB */
#define NAND_BLOCK_SIZE 0x20000
make
./signGP x-load.bin
mv x-load.bin.ift MLO
Build x-loader for nand boot
http://elinux.org/BeagleBoardNAND
Modify include/configs/omap3530mini.h
Disable CONFIG_MMC
//#define CONFIG_MMC 1
make
./signGP x-load.bin
Copy x-load.bin.ift to nand
3.Format SD Card
http://elinux.org/BeagleBoardBeginners
有一些細節要注意,就不再贅述
將MLO copy 到SD card FAT partition (FAT partition一定要是乾淨的)
將x-load.bin.ift copy到 FAT partition
4.Install pre-built 0xdroid images
複製uImage / 0xkernel-beagle.bin / android-beagle.ubi 到SD card FAT parition
退出SD card
Boot from SD card
進入u-boot command
由SD card更新nand flash上的檔案
Refresh x-load.bin.ift
OMAP3 MiniBoard # mmcinit
OMAP3 MiniBoard # fatload mmc 0 ${loadaddr} x-load.bin.ift
reading x-load.bin.ift
11332 bytes read
OMAP3 MiniBoard # nand unlock
Usage:
nand - NAND sub-system
OMAP3 MiniBoard # nand erase 0 40000
NAND erase: device 0 offset 0x0, size 0x40000
Erasing at 0x20000 -- 100% complete.
OK
OMAP3 MiniBoard # nandecc hw
HW ECC selected
OMAP3 MiniBoard # nand write ${loadaddr} 0 40000
NAND write: device 0 offset 0x0, size 0x40000
262144 bytes written: OK
OMAP3 MiniBoard # nand lock
Usage:
nand - NAND sub-system
Refresh u-boot
OMAP3 MiniBoard # mmcinit
OMAP3 MiniBoard # fatload mmc 0 ${loadaddr} u-boot.bin
reading u-boot.bin
275904 bytes read
OMAP3 MiniBoard # nand erase 80000 1e0000
NAND erase: device 0 offset 0x80000, size 0x1e0000
Erasing at 0x140000 -- 100% complete.
OK
OMAP3 MiniBoard # nand write ${loadaddr} 80000 1e0000
NAND write: device 0 offset 0x80000, size 0x1e0000
917504 bytes written: OK
OMAP3 MiniBoard #
Refresh uImage.bin
OMAP3 Miniboard # mmcinit
OMAP3 Miniboard # fatload mmc 0 ${loadaddr} uImage-beagle.bin
reading uImage-beagle.bin
2140524 bytes read
OMAP3 Miniboard # nand erase 280000 400000
NAND erase: device 0 offset 0x280000, size 0x400000
Erasing at 0x660000 -- 100% complete.
OK
OMAP3 Miniboard # nand write ${loadaddr} 280000 400000
NAND write: device 0 offset 0x280000, size 0x400000
4194304 bytes written: OK
5.取出SD card, reboot to install 0xdroid automaticlly.
完成後reboot
6.u-boot environment variable
setenv ubifsargs 'setenv bootargs console=${console} init=/init omapdss.def_disp=dvi omapfb.mode=dvi:1280x1024MR-24@60 root=ubi0:rootfs ubi.mtd=4 rw rootfstype=ubifs'
setenv nandboot 'echo Booting from nand ...; run ubifsargs; nand read ${loadaddr} 280000 400000; bootm ${loadaddr}'
7.0xdroid works
Texas Instruments X-Loader 1.4.2 (Sep 24 2009 - 17:05:57)
MiniBoard V2.0: Run Xloader from SD card
Loading u-boot.bin from nand
U-Boot 2009.08-00217-g30d7aae-dirty ( 9月 24 2009 - 20:23:31)
OMAP3530-GP ES2.1, CPU-OPP2 L3-165MHz
OMAP3 Beagle board + LPDDR/NAND
DRAM: 256 MB
NAND: 512 MiB
In: serial
Out: serial
Err: serial
Beagle Board rev C
Die ID #4b9a00020000000004031c1307010007
Hit any key to stop autoboot: 0
Unknown command 'mmcinit' - try 'help'
Booting from nand ...
NAND read: device 0 offset 0x280000, size 0x400000
4194304 bytes read: OK
## Booting kernel from Legacy Image at 80200000 ...
Image Name: Linux-2.6.29-omap1-g327a826
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 2165760 Bytes = 2.1 MB
Load Address: 80008000
Entry Point: 80008000
Verifying Checksum ... OK
Loading Kernel Image ... OK
OK
Starting kernel ...
由於mini board有512MB nand flash & DM9000 ethernet所以捨棄了beagle board.
但風險就是萬一硬體有不相容的地方就得自己搞了
http://code.google.com/p/beagleboard/wiki/BeagleSoftCompile
1.OMAP3530 boot
Boot對Embedded System是一件大事,就像生命的起源一般.
OMAP3530可以從nand flash or SD card boot,由x-loader開始.
x-loader負責初始化CUP,包含memory & nand flash,之後會載入並執行u-boot.
預設供電後由nand flash載入x-loader.
按住user button + reset button就會由SD card載入x-loader.
2.Compile x-loader
修改xloader/include/configs/omap3530Mini.h
/* NAND is partitioned:
* 0x00000000 - 0x0007FFFF Booting Image
* 0x00080000 - 0x0025FFFF U-Boot Image
* 0x00260000 - 0x0027FFFF U-Boot Env Data (X-loader doesn't care)
* 0x00280000 - 0x0067FFFF Kernel Image
* 0x00680000 - 0x08000000 depends on application
*/
#define NAND_UBOOT_START 0x0080000 /* Leaving first 4 blocks for x-load */
#define NAND_UBOOT_END 0x0260000 /* Giving a space of 2 blocks = 256KB */
#define NAND_BLOCK_SIZE 0x20000
make
./signGP x-load.bin
mv x-load.bin.ift MLO
Build x-loader for nand boot
http://elinux.org/BeagleBoardNAND
Modify include/configs/omap3530mini.h
Disable CONFIG_MMC
//#define CONFIG_MMC 1
make
./signGP x-load.bin
Copy x-load.bin.ift to nand
3.Format SD Card
http://elinux.org/BeagleBoardBeginners
有一些細節要注意,就不再贅述
將MLO copy 到SD card FAT partition (FAT partition一定要是乾淨的)
將x-load.bin.ift copy到 FAT partition
4.Install pre-built 0xdroid images
複製uImage / 0xkernel-beagle.bin / android-beagle.ubi 到SD card FAT parition
退出SD card
Boot from SD card
進入u-boot command
由SD card更新nand flash上的檔案
Refresh x-load.bin.ift
OMAP3 MiniBoard # mmcinit
OMAP3 MiniBoard # fatload mmc 0 ${loadaddr} x-load.bin.ift
reading x-load.bin.ift
11332 bytes read
OMAP3 MiniBoard # nand unlock
Usage:
nand - NAND sub-system
OMAP3 MiniBoard # nand erase 0 40000
NAND erase: device 0 offset 0x0, size 0x40000
Erasing at 0x20000 -- 100% complete.
OK
OMAP3 MiniBoard # nandecc hw
HW ECC selected
OMAP3 MiniBoard # nand write ${loadaddr} 0 40000
NAND write: device 0 offset 0x0, size 0x40000
262144 bytes written: OK
OMAP3 MiniBoard # nand lock
Usage:
nand - NAND sub-system
Refresh u-boot
OMAP3 MiniBoard # mmcinit
OMAP3 MiniBoard # fatload mmc 0 ${loadaddr} u-boot.bin
reading u-boot.bin
275904 bytes read
OMAP3 MiniBoard # nand erase 80000 1e0000
NAND erase: device 0 offset 0x80000, size 0x1e0000
Erasing at 0x140000 -- 100% complete.
OK
OMAP3 MiniBoard # nand write ${loadaddr} 80000 1e0000
NAND write: device 0 offset 0x80000, size 0x1e0000
917504 bytes written: OK
OMAP3 MiniBoard #
Refresh uImage.bin
OMAP3 Miniboard # mmcinit
OMAP3 Miniboard # fatload mmc 0 ${loadaddr} uImage-beagle.bin
reading uImage-beagle.bin
2140524 bytes read
OMAP3 Miniboard # nand erase 280000 400000
NAND erase: device 0 offset 0x280000, size 0x400000
Erasing at 0x660000 -- 100% complete.
OK
OMAP3 Miniboard # nand write ${loadaddr} 280000 400000
NAND write: device 0 offset 0x280000, size 0x400000
4194304 bytes written: OK
5.取出SD card, reboot to install 0xdroid automaticlly.
完成後reboot
6.u-boot environment variable
setenv ubifsargs 'setenv bootargs console=${console} init=/init omapdss.def_disp=dvi omapfb.mode=dvi:1280x1024MR-24@60 root=ubi0:rootfs ubi.mtd=4 rw rootfstype=ubifs'
setenv nandboot 'echo Booting from nand ...; run ubifsargs; nand read ${loadaddr} 280000 400000; bootm ${loadaddr}'
7.0xdroid works
Texas Instruments X-Loader 1.4.2 (Sep 24 2009 - 17:05:57)
MiniBoard V2.0: Run Xloader from SD card
Loading u-boot.bin from nand
U-Boot 2009.08-00217-g30d7aae-dirty ( 9月 24 2009 - 20:23:31)
OMAP3530-GP ES2.1, CPU-OPP2 L3-165MHz
OMAP3 Beagle board + LPDDR/NAND
DRAM: 256 MB
NAND: 512 MiB
In: serial
Out: serial
Err: serial
Beagle Board rev C
Die ID #4b9a00020000000004031c1307010007
Hit any key to stop autoboot: 0
Unknown command 'mmcinit' - try 'help'
Booting from nand ...
NAND read: device 0 offset 0x280000, size 0x400000
4194304 bytes read: OK
## Booting kernel from Legacy Image at 80200000 ...
Image Name: Linux-2.6.29-omap1-g327a826
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 2165760 Bytes = 2.1 MB
Load Address: 80008000
Entry Point: 80008000
Verifying Checksum ... OK
Loading Kernel Image ... OK
OK
Starting kernel ...
2009年9月15日 星期二
GIT : Remote Repository
0.環境描述
git config --global user.name "Steve Chang"
git config --global user.email stevegigijoe@yahoo.com.tw
gigijoe@user-desktop:~/myandroid$ git config -l
color.ui=auto
user.name=Steve Chang
user.email=stevegigijoe@yahoo.com.tw
sdaemon2專案原始碼在Client端.
建立Client端GIT專案sdaemon2
設定GIT遠端伺服器並建立GIT專案 sdaemon2.
將sdaemon2提交伺服器端
1.伺服器端設定
adduser git
su git
mkdir sdaemon2.git
cd sdaemon2.git
git --bare init
之後會看到以下訊息
Initialized empty Git repository in /home/git/sdaemon2.git
2.Client端GIT專案
cd sdaemon2
git add .
git commit
git log
commit 86c36413882cc8e364c7764e47c025b4c8930437
Author: Steve Chang
Date: Tue Sep 15 16:03:15 2009 +0800
Initial version of sdaemon2
git remote add origin git@[server]:sdaemon2.git
git push origin master
The authenticity of host 'localhost (127.0.0.1)' can't be established.
RSA key fingerprint is 22:f6:c8:69:bb:36:d2:fb:99:5a:f9:62:32:68:75:c3.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (RSA) to the list of known hosts.
git@localhost's password:
Counting objects: 34, done.
Compressing objects: 100% (34/34), done.
Writing objects: 100% (34/34), 43.87 KiB, done.
Total 34 (delta 0), reused 0 (delta 0)
To git@localhost:sdaemon2.git
* [new branch] master -> master
git config -l
color.ui=auto
user.name=Steve Chang
user.email=stevegigijoe@yahoo.com.tw
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
remote.origin.url=git@localhost:sdaemon2.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
3.其他的Client取得GIT專案
git clone git@[server]:sdaemon2.git
Initialized empty Git repository in /home/gigijoe/VT300/sdaemon2/.git/
git@localhost's password:
remote: Counting objects: 34, done.
remote: Compressing objects: 100% (34/34), done.
remote: Total 34 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (34/34), 43.87 KiB, done.
這時會在目前位置複製一份sdaemon2目錄及原始碼
4.提交更動(commit)
git commit -a
Created commit 9c91092: Add debug message on state machine
1 files changed, 10 insertions(+), 10 deletions(-)
git push origin master
git@localhost's password:
Counting objects: 5, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 421 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)
To git@localhost:sdaemon2.git
86c3641..9c91092 master -> master
5.提取更新
git pull
git@localhost's password:
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From git@localhost:sdaemon2
86c3641..9c91092 master -> origin/master
Updating 86c3641..9c91092
Fast forward
networking.c | 20 ++++++++++----------
1 files changed, 10 insertions(+), 10 deletions(-)
6.差異比較
與前一版的差異
git diff HEAD^
or
git show HEAD
與前兩版的差異
git diff HEAD^^
or
git show HEAD^
與前前前前一版的差異
git diff HEAD~4
or
git show HEAD~3
Referance
http://www.wretch.cc/blog/michaeloil/22286355
http://plog.longwin.com.tw/my_note-unix/2009/05/19/git-learn-initial-command-2009
http://www.qweruiop.org/nchcrails/posts/49
git config --global user.name "Steve Chang"
git config --global user.email stevegigijoe@yahoo.com.tw
gigijoe@user-desktop:~/myandroid$ git config -l
color.ui=auto
user.name=Steve Chang
user.email=stevegigijoe@yahoo.com.tw
sdaemon2專案原始碼在Client端.
建立Client端GIT專案sdaemon2
設定GIT遠端伺服器並建立GIT專案 sdaemon2.
將sdaemon2提交伺服器端
1.伺服器端設定
adduser git
su git
mkdir sdaemon2.git
cd sdaemon2.git
git --bare init
之後會看到以下訊息
Initialized empty Git repository in /home/git/sdaemon2.git
2.Client端GIT專案
cd sdaemon2
git add .
git commit
git log
commit 86c36413882cc8e364c7764e47c025b4c8930437
Author: Steve Chang
Date: Tue Sep 15 16:03:15 2009 +0800
Initial version of sdaemon2
git remote add origin git@[server]:sdaemon2.git
git push origin master
The authenticity of host 'localhost (127.0.0.1)' can't be established.
RSA key fingerprint is 22:f6:c8:69:bb:36:d2:fb:99:5a:f9:62:32:68:75:c3.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (RSA) to the list of known hosts.
git@localhost's password:
Counting objects: 34, done.
Compressing objects: 100% (34/34), done.
Writing objects: 100% (34/34), 43.87 KiB, done.
Total 34 (delta 0), reused 0 (delta 0)
To git@localhost:sdaemon2.git
* [new branch] master -> master
git config -l
color.ui=auto
user.name=Steve Chang
user.email=stevegigijoe@yahoo.com.tw
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
remote.origin.url=git@localhost:sdaemon2.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
3.其他的Client取得GIT專案
git clone git@[server]:sdaemon2.git
Initialized empty Git repository in /home/gigijoe/VT300/sdaemon2/.git/
git@localhost's password:
remote: Counting objects: 34, done.
remote: Compressing objects: 100% (34/34), done.
remote: Total 34 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (34/34), 43.87 KiB, done.
這時會在目前位置複製一份sdaemon2目錄及原始碼
4.提交更動(commit)
git commit -a
Created commit 9c91092: Add debug message on state machine
1 files changed, 10 insertions(+), 10 deletions(-)
git push origin master
git@localhost's password:
Counting objects: 5, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 421 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)
To git@localhost:sdaemon2.git
86c3641..9c91092 master -> master
5.提取更新
git pull
git@localhost's password:
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From git@localhost:sdaemon2
86c3641..9c91092 master -> origin/master
Updating 86c3641..9c91092
Fast forward
networking.c | 20 ++++++++++----------
1 files changed, 10 insertions(+), 10 deletions(-)
6.差異比較
與前一版的差異
git diff HEAD^
or
git show HEAD
與前兩版的差異
git diff HEAD^^
or
git show HEAD^
與前前前前一版的差異
git diff HEAD~4
or
git show HEAD~3
Referance
http://www.wretch.cc/blog/michaeloil/22286355
http://plog.longwin.com.tw/my_note-unix/2009/05/19/git-learn-initial-command-2009
http://www.qweruiop.org/nchcrails/posts/49
2009年9月14日 星期一
UBIFS - Next generation of the JFFS2 file-system
UBIFS 是由NOKIA Engineers開發用於Flash memory的檔案系統.
UBIFS可以視為下一代的Jffs2 file system.
與Jffs2一樣,UBIFS建構於MTD device之上而與一般的block device是不相容的.
1.Jffs2的架構與限制
Jffs2在mount時會scan整個flash所有的資料,再將檔案系統目錄儲存在system memory.
這種作法帶來的缺點是mount動作會消耗很多時間.
而當flash size越大所需的時間及system memory都將成線性倍數成長
Jffs2沒有write-back機制.(write-back : 先cache寫入的資料到一定的量再一次作write動作)
當Application寫入資料,Jffs2幾乎是同步將資料寫入實體flash.
會說幾乎是因為Jffs2的確有一塊NAND page size大小的buffer用來紀錄最後寫入的資料.
沒有write-back機制的缺點是對flash I/O的動作頻繁
Jffs2檔案存取所需要的時間跟檔案大小呈線性倍數成長
Jffs2如果歷經許多檔案小部份修改寫入動作,Jffs2的運作效率會逐漸變差.
2.UBIFS帶來的改進
UBIFS有個子系統UBI用以處理與MTD device之間的動作.
UBIFS檔案系統目錄儲存在flash上.這代表UBIFS mount時不需要scan整個flash的資料來重新建立檔案目錄.
因此mount所需時間約為幾百個ms而且不隨著flash size增加.
UBIFS support write-back.
寫入的資料會被cache住直到有必要寫入時才寫到flash.
這樣的作法降低分散小區塊數量及I/O效率.
但write-back非同步的寫入行為使得Application在寫入檔案時要謹慎處理同步問題.
重要的檔案使用fsync強迫UBIFS將資料寫入flash.
UBIFS supports on-the-flight compression.
UBIFS可壓縮檔案資料而且可選擇性壓縮部份檔案.
UBIFS具有日誌紀錄(journal)以減少檔案目錄更新的頻率
Referance
http://www.linux-mtd.infradead.org/doc/ubifs.html
UBIFS可以視為下一代的Jffs2 file system.
與Jffs2一樣,UBIFS建構於MTD device之上而與一般的block device是不相容的.
1.Jffs2的架構與限制
Jffs2在mount時會scan整個flash所有的資料,再將檔案系統目錄儲存在system memory.
這種作法帶來的缺點是mount動作會消耗很多時間.
而當flash size越大所需的時間及system memory都將成線性倍數成長
Jffs2沒有write-back機制.(write-back : 先cache寫入的資料到一定的量再一次作write動作)
當Application寫入資料,Jffs2幾乎是同步將資料寫入實體flash.
會說幾乎是因為Jffs2的確有一塊NAND page size大小的buffer用來紀錄最後寫入的資料.
沒有write-back機制的缺點是對flash I/O的動作頻繁
Jffs2檔案存取所需要的時間跟檔案大小呈線性倍數成長
Jffs2如果歷經許多檔案小部份修改寫入動作,Jffs2的運作效率會逐漸變差.
2.UBIFS帶來的改進
UBIFS有個子系統UBI用以處理與MTD device之間的動作.
UBIFS檔案系統目錄儲存在flash上.這代表UBIFS mount時不需要scan整個flash的資料來重新建立檔案目錄.
因此mount所需時間約為幾百個ms而且不隨著flash size增加.
UBIFS support write-back.
寫入的資料會被cache住直到有必要寫入時才寫到flash.
這樣的作法降低分散小區塊數量及I/O效率.
但write-back非同步的寫入行為使得Application在寫入檔案時要謹慎處理同步問題.
重要的檔案使用fsync強迫UBIFS將資料寫入flash.
UBIFS supports on-the-flight compression.
UBIFS可壓縮檔案資料而且可選擇性壓縮部份檔案.
UBIFS具有日誌紀錄(journal)以減少檔案目錄更新的頻率
Referance
http://www.linux-mtd.infradead.org/doc/ubifs.html
2009年9月9日 星期三
Linux system time and time zone
Linux上設定time zone的方式有
1.設定環境變數TZ
TZ=GMT-8
2.編輯/etc/TZ
echo GMT-8 > /etc/TZ
http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html
以台灣為例,GMT或UTC時區為+8:00(超前8小時)
但TZ環境變數中的超前為負號,故要設為GMT-8, UTC-8 or GMT-8:00也可以
(其實任意XXX-8都可以)
http://linux.vbird.org/linux_server/0440ntp.php
GMT : Greenwich Mean Time (格林威治時間)
UTC : Coordinated Universal Time (協和標準時間)
CST : China Standard Time
epoch : The Unix epoch is the time 00:00:00 UTC on January 1 1970
系統時間可以透過NTP來校正.
而所得到的時間為再透過time zone設定就是local time了
1.設定環境變數TZ
TZ=GMT-8
2.編輯/etc/TZ
echo GMT-8 > /etc/TZ
http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html
以台灣為例,GMT或UTC時區為+8:00(超前8小時)
但TZ環境變數中的超前為負號,故要設為GMT-8, UTC-8 or GMT-8:00也可以
(其實任意XXX-8都可以)
http://linux.vbird.org/linux_server/0440ntp.php
GMT : Greenwich Mean Time (格林威治時間)
UTC : Coordinated Universal Time (協和標準時間)
CST : China Standard Time
epoch : The Unix epoch is the time 00:00:00 UTC on January 1 1970
系統時間可以透過NTP來校正.
而所得到的時間為再透過time zone設定就是local time了
2009年9月4日 星期五
Process handle tips
一些處理行程的技巧
1.防止zombie process產生
http://home.educities.edu.tw/shirock/comp/Anti_zombie_process.htm
linux上的正解
int child_stat;
1.防止zombie process產生
http://home.educities.edu.tw/shirock/comp/Anti_zombie_process.htm
linux上的正解
int child_stat;
void reapchild() {
while( wait(&child_stat) <= 0 )
/*NOTHING or your code*/;
}
. . .
struct sigaction act;
act.sa_handler = reapchild;
act.sa_flags = SA_NOCLDSTOP; /* Do not signal while process paused */
sigaction( SIGCHLD, &act, NULL);
這個方式不適合在寫library時用
只要用library的人去重設signal就完了
2.system(const char *string)的傳回值
system這個function的return value傳回的是fork process的return value
並不是所執行的程式傳回值.
要拿到執行的程式傳回值要用以下方式
#include
int r;
r = system("ifconfig eth0");
if(WEXITSTATUS(r) == 1) /*Fail*/
return;
2.Fork
pid_t pid;
if((pid = vfork()) == 0) { /*Child*/
execl("/bin/ping", "ping", "-c", "3", ip, (char *)0);
_exit(127);
} else if(pid < 0)
perror("fork");
else /*Parent*/
dev->ping->pid = pid;
.......
.......
int status;
pid_t pid = waitpid(dev->ping->pid, &status, WNOHANG);
if(pid > 0)
if(WIFEXITED(status)) {
dev->ping->pid = 0;
if(WEXITSTATUS(status) != 0) { /*ping without response*/
SxNetDev_Fail(dev, "Ping fail");
return;
} else {
SxNetDev_Connect(dev);
SxNetDev_Ping(dev, config->pppoe.ping);
}
}
2009年8月11日 星期二
2009年7月30日 星期四
2009年7月15日 星期三
Linux Networking Security
網路攻擊簡介
http://www.iii.org.tw/adc/papers/thesis/00B02.htm
鳥哥的私房菜
Linux 防火牆與 NAT 主機
Linux CLDP文件,說明各種受到攻擊時的對策
http://www.linux.org.tw/CLDP/OLD/Adv-Routing-HOWTO-16.html
目前linux kernel對大部分的攻擊應該都已經有防禦能力.
以下是linux的一些防禦對策.
1.TCP Sync Attack
Enable kernel feature - TCP Syncookies
echo "1" > /proc/sys/net/ipv4/tcp_syncookies
2.Smurf
不回應broadcast ICMP封包
echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
3.防止惡意竄改的封包
echo "1" > /proc/sys/net/ipv4/rp_filter
4.用iptables建立一些基礎防禦
阻擋異樣ICMP封包
iptables -A INPUT -p icmp --icmp-type echo-request -j REJECT
或是
iptables -I INPUT -p icmp --icmp-type echo-request -m limit --limit 6/min --limit-burst 4 -j ACCEPT
阻擋port scan
iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL ALL -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL NONE -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
http://www.iii.org.tw/adc/papers/thesis/00B02.htm
鳥哥的私房菜
Linux 防火牆與 NAT 主機
Linux CLDP文件,說明各種受到攻擊時的對策
http://www.linux.org.tw/CLDP/OLD/Adv-Routing-HOWTO-16.html
目前linux kernel對大部分的攻擊應該都已經有防禦能力.
以下是linux的一些防禦對策.
1.TCP Sync Attack
Enable kernel feature - TCP Syncookies
echo "1" > /proc/sys/net/ipv4/tcp_syncookies
2.Smurf
不回應broadcast ICMP封包
echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
3.防止惡意竄改的封包
echo "1" > /proc/sys/net/ipv4/rp_filter
4.用iptables建立一些基礎防禦
阻擋異樣ICMP封包
iptables -A INPUT -p icmp --icmp-type echo-request -j REJECT
或是
iptables -I INPUT -p icmp --icmp-type echo-request -m limit --limit 6/min --limit-burst 4 -j ACCEPT
阻擋port scan
iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL ALL -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags ALL NONE -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
iptables -A INPUT -i eth0 -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
2009年7月3日 星期五
Patch for dillo cross compile friendly
--- VT300/dillo2/configure.in 2009-07-03 21:08:27.000000000 +0800
+++ S3C2440/dillo2/configure.in 2009-07-03 20:53:30.000000000 +0800
@@ -95,10 +95,10 @@
dnl (this is somewhat a religious problem)
dnl --------------------------------------
dnl
-if test "`$CPP -v < /dev/null 2>&1 | grep '/usr/local/include' 2>&1`" = ""; then
- CPPFLAGS="$CPPFLAGS -I/usr/local/include"
- LDFLAGS="$LDFLAGS -L/usr/local/lib"
-fi
+dnl if test "`$CPP -v < /dev/null 2>&1 | grep '/usr/local/include' 2>&1`" = ""; then
+dnl CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+dnl LDFLAGS="$LDFLAGS -L/usr/local/lib"
+dnl fi
dnl ------------------------------------
dnl Check for socket libs (AIX, Solaris)
@@ -145,12 +145,18 @@
dnl ----------------------
dnl
dnl For debugging and to be user friendly
+
+dnl Check if the user hasn't set the variable $FLTK2_CONFIG
+ if test -z "$FLTK2_CONFIG"; then
+ PNG_CONFIG=`which fltk2-config`
+ fi
+
AC_MSG_CHECKING([FLTK2])
if sh -c "fltk2-config --version" >/dev/null 2>&1
then AC_MSG_RESULT(yes)
- LIBFLTK_CXXFLAGS=`fltk2-config --cxxflags`
- LIBFLTK_CFLAGS=`fltk2-config --cflags`
- LIBFLTK_LIBS=`fltk2-config --use-images --ldflags`
+ LIBFLTK_CXXFLAGS=`$FLTK2_CONFIG --cxxflags`
+ LIBFLTK_CFLAGS=`$FLTK2_CONFIG --cflags`
+ LIBFLTK_LIBS=`$FLTK2_CONFIG --use-images --ldflags`
else AC_MSG_RESULT(no)
AC_ERROR(FLTK2 must be installed!)
fi
+++ S3C2440/dillo2/configure.in 2009-07-03 20:53:30.000000000 +0800
@@ -95,10 +95,10 @@
dnl (this is somewhat a religious problem)
dnl --------------------------------------
dnl
-if test "`$CPP -v < /dev/null 2>&1 | grep '/usr/local/include' 2>&1`" = ""; then
- CPPFLAGS="$CPPFLAGS -I/usr/local/include"
- LDFLAGS="$LDFLAGS -L/usr/local/lib"
-fi
+dnl if test "`$CPP -v < /dev/null 2>&1 | grep '/usr/local/include' 2>&1`" = ""; then
+dnl CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+dnl LDFLAGS="$LDFLAGS -L/usr/local/lib"
+dnl fi
dnl ------------------------------------
dnl Check for socket libs (AIX, Solaris)
@@ -145,12 +145,18 @@
dnl ----------------------
dnl
dnl For debugging and to be user friendly
+
+dnl Check if the user hasn't set the variable $FLTK2_CONFIG
+ if test -z "$FLTK2_CONFIG"; then
+ PNG_CONFIG=`which fltk2-config`
+ fi
+
AC_MSG_CHECKING([FLTK2])
if sh -c "fltk2-config --version" >/dev/null 2>&1
then AC_MSG_RESULT(yes)
- LIBFLTK_CXXFLAGS=`fltk2-config --cxxflags`
- LIBFLTK_CFLAGS=`fltk2-config --cflags`
- LIBFLTK_LIBS=`fltk2-config --use-images --ldflags`
+ LIBFLTK_CXXFLAGS=`$FLTK2_CONFIG --cxxflags`
+ LIBFLTK_CFLAGS=`$FLTK2_CONFIG --cflags`
+ LIBFLTK_LIBS=`$FLTK2_CONFIG --use-images --ldflags`
else AC_MSG_RESULT(no)
AC_ERROR(FLTK2 must be installed!)
fi
2009年7月1日 星期三
2009年6月30日 星期二
S3C2440 Camera interface V4L2 driver for linux-2.6.29
/*s3c2440_ov9650.c*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/semaphore.h>
#include <mach/regs-gpio.h>
#include "sccb.h"
#include "s3c2440camif.h"
#define OV9650_SCCB_ADDR 0x60
#define OV9650_MANUFACT_ID 0x7FA2
#define OV9650_PRODUCT_ID 0x9650
/*
09032004
OV9650
VGA YUV
15fps when 24MHz input clock
Device Address(Hex)/Register(Hex)/Value(Hex)
*/
static struct ov9650_reg
{
u8 subaddr;
u8 value;
}regs[] = {
{0x12, 0x80},
{0x11, 0x81},
{0x6b, 0x0a},
{0x6a, 0x3e},
{0x3b, 0x09},
{0x13, 0xe0},
{0x01, 0x80},
{0x02, 0x80},
{0x00, 0x00},
{0x10, 0x00},
{0x13, 0xe5},
/*{0x39, 0x50},*/ /*30 fps*/
{0x39, 0x43}, /*15fps*/
/*{0x38, 0x92},*/ /*30fps*/
{0x38, 0x12}, /*15fps*/
{0x37, 0x00},
/*{0x35, 0x81},*/ /*30 fps*/
{0x35, 0x91}, /*15 fps*/
{0x0e, 0x20},
{0x1e, 0x04},
{0xa8, 0x80},
{0x12, 0x40},
{0x04, 0x00},
{0x0c, 0x04},
{0x0d, 0x80},
{0x18, 0xc6},
{0x17, 0x26},
{0x32, 0xad},
{0x03, 0x00},
{0x1a, 0x3d},
{0x19, 0x01},
{0x3f, 0xa6},
{0x14, 0x2e},
{0x15, 0x02},
{0x41, 0x02},
{0x42, 0x08},
{0x1b, 0x00},
{0x16, 0x06},
{0x33, 0xe2}, /*c0 for internal regulator*/
{0x34, 0xbf},
{0x96, 0x04},
{0x3a, 0x00},
{0x8e, 0x00},
{0x3c, 0x77},
{0x8B, 0x06},
{0x94, 0x88},
{0x95, 0x88},
{0x40, 0xc1},
{0x29, 0x3f}, /*2f for internal regulator*/
{0x0f, 0x42},
{0x3d, 0x92},
{0x69, 0x40},
{0x5c, 0xb9},
{0x5d, 0x96},
{0x5e, 0x10},
{0x59, 0xc0},
{0x5a, 0xaf},
{0x5b, 0x55},
{0x43, 0xf0},
{0x44, 0x10},
{0x45, 0x68},
{0x46, 0x96},
{0x47, 0x60},
{0x48, 0x80},
{0x5f, 0xe0},
{0x60, 0x8c}, /*0c for advanced AWB (related to lens)*/
{0x61, 0x20},
{0xa5, 0xd9},
{0xa4, 0x74},
{0x8d, 0x02},
{0x13, 0xe7},
{0x4f, 0x3a},
{0x50, 0x3d},
{0x51, 0x03},
{0x52, 0x12},
{0x53, 0x26},
{0x54, 0x38},
{0x55, 0x40},
{0x56, 0x40},
{0x57, 0x40},
{0x58, 0x0d},
{0x8C, 0x23},
{0x3e, 0x02},
{0xa9, 0xb8},
{0xaa, 0x92},
{0xab, 0x0a},
{0x8f, 0xdf},
{0x90, 0x00},
{0x91, 0x00},
{0x9f, 0x00},
{0xa0, 0x00},
{0x3a, 0x0d}, /*UYVY, Digital BLC enable*/
{0x24, 0x70},
{0x25, 0x64},
{0x26, 0xc3},
{0x2a, 0x00}, /*10 for 50Hz*/
{0x2b, 0x00}, /*40 for 50Hz*/
{0x6c, 0x40},
{0x6d, 0x30},
{0x6e, 0x4b},
{0x6f, 0x60},
{0x70, 0x70},
{0x71, 0x70},
{0x72, 0x70},
{0x73, 0x70},
{0x74, 0x60},
{0x75, 0x60},
{0x76, 0x50},
{0x77, 0x48},
{0x78, 0x3a},
{0x79, 0x2e},
{0x7a, 0x28},
{0x7b, 0x22},
{0x7c, 0x04},
{0x7d, 0x07},
{0x7e, 0x10},
{0x7f, 0x28},
{0x80, 0x36},
{0x81, 0x44},
{0x82, 0x52},
{0x83, 0x60},
{0x84, 0x6c},
{0x85, 0x78},
{0x86, 0x8c},
{0x87, 0x9e},
{0x88, 0xbb},
{0x89, 0xd2},
{0x8a, 0xe6}
};
#if 0
static struct ov9650_reg
{
u8 subaddr;
u8 value;
}regs[] = {
/* OV9650 intialization parameter table for SXGA application */
{0x12, 0x80}, {0x39, 0x43}, {0x38, 0x12}, {0x37, 0x00}, {0x0e, 0x20},
{0x1e, 0x0c}, {0x01, 0x80}, {0x02, 0x80}, {0x00, 0x00}, {0x10, 0xf0},
{0x04, 0x00}, {0x0c, 0x00}, {0x0d, 0x00}, {0x11, 0x80}, {0x12, 0x40},
{0x14, 0x2e}, {0x15, 0x00}, {0x18, 0xbd}, {0x17, 0x1d}, {0x32, 0xbf},
{0x03, 0x12}, {0x1a, 0x81}, {0x19, 0x01}, {0x3f, 0xa6}, {0x41, 0x02},
{0x42, 0x08}, {0x1b, 0x00}, {0x16, 0x06}, {0x33, 0xc0}, {0x34, 0xbf},
{0xa8, 0x80}, {0x96, 0x04}, {0x3a, 0x00}, {0x8e, 0x00}, {0x3c, 0x77},
{0x8b, 0x06}, {0x35, 0x91}, {0x94, 0x88}, {0x95, 0x88}, {0x40, 0xc1},
{0x29, 0x3f}, {0x0f, 0x42}, {0x13, 0xe5}, {0x3d, 0x92}, {0x69, 0x80},
{0x5c, 0x96}, {0x5d, 0x96}, {0x5e, 0x10}, {0x59, 0xeb}, {0x5a, 0x9c},
{0x5b, 0x55}, {0x43, 0xf0}, {0x44, 0x10}, {0x45, 0x55}, {0x46, 0x86},
{0x47, 0x64}, {0x48, 0x86}, {0x5f, 0xe0}, {0x60, 0x8c}, {0x61, 0x20},
{0xa5, 0xd9}, {0xa4, 0x74}, {0x8d, 0x02}, {0x13, 0xe7}, {0x4f, 0x3a},
{0x50, 0x3d}, {0x51, 0x03}, {0x52, 0x12}, {0x53, 0x26}, {0x54, 0x38},
{0x55, 0x40}, {0x56, 0x40}, {0x57, 0x40}, {0x58, 0x0d}, {0x8c, 0x23},
{0x3e, 0x02}, {0xa9, 0xb8}, {0xaa, 0x92}, {0xab, 0x0a}, {0x8f, 0xdf},
{0x90, 0x00}, {0x91, 0x00}, {0x9f, 0x00}, {0x3a, 0x0c}, {0x24, 0x70},
{0x25, 0x64}, {0x26, 0xc3}, {0x2a, 0x12}, {0x2b, 0x46}, {0x3b, 0x19},
{0x6c, 0x40}, {0x6d, 0x30}, {0x6e, 0x4b}, {0x6f, 0x60},
{0x70, 0x70}, {0x71, 0x70}, {0x72, 0x70}, {0x73, 0x70},
{0x74, 0x60}, {0x75, 0x60}, {0x76, 0x50}, {0x77, 0x48},
{0x78, 0x3a}, {0x79, 0x2e}, {0x7a, 0x28}, {0x7b, 0x22},
{0x7c, 0x04}, {0x7d, 0x07}, {0x7e, 0x10}, {0x7f, 0x28},
{0x80, 0x36}, {0x81, 0x44}, {0x82, 0x52}, {0x83, 0x60},
{0x84, 0x6c}, {0x85, 0x78}, {0x86, 0x8c}, {0x87, 0x9e},
{0x88, 0xbb}, {0x89, 0xd2}, {0x8a, 0xe6},
{0x6a, 0x41}, {0x66, 0x00},
{0x3e, 0x00}, {0x3f, 0xa4}
};
#endif
DECLARE_MUTEX(regs_mutex);
static void __inline__ ov9650_poweron(void)
{
s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_OUTP);
s3c2410_gpio_setpin(S3C2410_GPG12, 0);
mdelay(20);
}
static void __inline__ ov9650_poweroff(void)
{
s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_OUTP);
s3c2410_gpio_setpin(S3C2410_GPG12, 1);
mdelay(20);
}
static int __inline__ ov9650_check(void)
{
u32 mid;
mid = sccb_read(OV9650_SCCB_ADDR, 0x1c)<<8;
mid |= sccb_read(OV9650_SCCB_ADDR, 0x1d);
printk("SCCB address 0x%02X, manufacture ID 0x%04X, expect 0x%04X\n", OV9650_SCCB_ADDR, mid, OV9650_MANUFACT_ID);
return (mid==OV9650_MANUFACT_ID)?1:0;
}
static u32 __inline__ show_ov9650_product_id(void)
{
u32 pid;
pid = sccb_read(OV9650_SCCB_ADDR, 0x0a)<<8;
pid |= sccb_read(OV9650_SCCB_ADDR, 0x0b);
printk("SCCB address 0x%02X, product ID 0x%04X, expect 0x%04X\n", OV9650_SCCB_ADDR, pid, OV9650_PRODUCT_ID);
return pid;
}
static void ov9650_init_regs(void)
{
int i;
down(®s_mutex);
for (i=0; i<ARRAY_SIZE(regs); i++)
{
if (regs[i].subaddr == 0xff)
{
mdelay(regs[i].value);
continue;
}
sccb_write(OV9650_SCCB_ADDR, regs[i].subaddr, regs[i].value);
}
up(®s_mutex);
}
int s3c2440_ov9650_init(void)
{
printk(KERN_ALERT"Loading OV9650 driver.........\n");
/* power on. */
ov9650_poweron();
mdelay(100);
/* check device. */
if (ov9650_check() == 0 && ov9650_check() == 0)
{
printk(KERN_ERR"No OV9650 found!!!\n");
return -ENODEV;
}
show_ov9650_product_id();
ov9650_init_regs();
printk("ov9650 init done!\n");
return 0;
}
#if 0
module_init(ov9650_init);
module_exit(ov9650_cleanup);
MODULE_LICENSE("GPL");
#endif
/*s3c2440camif.h*/
#ifndef __S3C2440CAMIF_H__
#define __S3C2440CAMIF_H__
#define MIN_C_WIDTH 32
#define MAX_C_WIDTH 320
#define MIN_C_HEIGHT 48
#define MAX_C_HEIGHT 240
#define MIN_P_WIDTH 32
#define MAX_P_WIDTH 640
#define MIN_P_HEIGHT 48
#define MAX_P_HEIGHT 480
enum
{
CAMIF_BUFF_INVALID = 0,
CAMIF_BUFF_RGB565 = 1,
CAMIF_BUFF_RGB24 = 2,
CAMIF_BUFF_YCbCr420 = 3,
CAMIF_BUFF_YCbCr422 = 4
};
/* image buffer for s3c2440 camif. */
struct s3c2440camif_buffer
{
int state;
ssize_t img_size;
struct device *dev;
unsigned int order;
unsigned long virt_base;
unsigned long phy_base;
unsigned long offset;
};
/* for s3c2440camif_dev->state field. */
enum
{
CAMIF_STATE_FREE = 0, // not openned
CAMIF_STATE_READY = 1, // openned, but standby
CAMIF_STATE_PREVIEWING = 2, // in previewing
CAMIF_STATE_CODECING = 3 // in capturing
};
/* for s3c2440camif_dev->cmdcode field. */
enum
{
CAMIF_CMD_NONE = 0,
CAMIF_CMD_SFMT = 1<<0, // source image format changed.
CAMIF_CMD_WND = 1<<1, // window offset changed.
CAMIF_CMD_ZOOM = 1<<2, // zoom picture in/out
CAMIF_CMD_TFMT = 1<<3, // target image format changed.
CAMIF_CMD_P2C = 1<<4, // need camif switches from p-path to c-path
CAMIF_CMD_C2P = 1<<5, // neet camif switches from c-path to p-path
CAMIF_CMD_REGS = 1<<6, // Update regs
CAMIF_CMD_START = 1<<15, // stop capture
CAMIF_CMD_STOP = 1<<16 // stop capture
};
enum
{
CAMIF_PATH_NONE = 0,
CAMIF_PATH_PREVIEW = 1<<0,
CAMIF_PATH_CODEC = 1<<1
};
/* main s3c2440 camif structure. */
struct s3c2440camif_dev
{
/* hardware clock. */
struct clk * clk;
/* source(input) image size. */
int srcHsize;
int srcVsize;
/* windowed image size. */
int wndHsize;
int wndVsize;
/* codec-path target(output) image size. */
int coTargetHsize;
int coTargetVsize;
/* preview-path target(preview) image size. */
int preTargetHsize;
int preTargetVsize;
/* the camera interface state. */
int state; // CMAIF_STATE_FREE, CAMIF_STATE_PREVIEWING, CAMIF_STATE_CAPTURING.
/* for executing camif commands. */
int cmdcode; // command code, CAMIF_CMD_START, CAMIF_CMD_CFG, etc.
wait_queue_head_t wait; // wait queue for waiting untile command completed (if in preview or in capturing).
/* For V4L2 data */
__u32 pixelformat;
int path; /*output path*/
spinlock_t lock;
int open_count;
int frame; /*frame index*/
int rdy;
};
#if 0
/* opened file handle.*/
struct s3c2440camif_fh
{
/* the camif */
struct s3c2440camif_dev * dev;
/* master flag, only master openner could execute 'set' ioctls. */
int master;
};
#endif
struct s3c2440camif_res
{
int width;
int height;
};
#define S3C244X_CAMIFREG(x) ((x) + camif_base_addr)
/* CAMIF control registers */
#define S3C244X_CISRCFMT S3C244X_CAMIFREG(0x00)
#define S3C244X_CIWDOFST S3C244X_CAMIFREG(0x04)
#define S3C244X_CIGCTRL S3C244X_CAMIFREG(0x08)
#define S3C244X_CICOYSA1 S3C244X_CAMIFREG(0x18)
#define S3C244X_CICOYSA2 S3C244X_CAMIFREG(0x1C)
#define S3C244X_CICOYSA3 S3C244X_CAMIFREG(0x20)
#define S3C244X_CICOYSA4 S3C244X_CAMIFREG(0x24)
#define S3C244X_CICOCBSA1 S3C244X_CAMIFREG(0x28)
#define S3C244X_CICOCBSA2 S3C244X_CAMIFREG(0x2C)
#define S3C244X_CICOCBSA3 S3C244X_CAMIFREG(0x30)
#define S3C244X_CICOCBSA4 S3C244X_CAMIFREG(0x34)
#define S3C244X_CICOCRSA1 S3C244X_CAMIFREG(0x38)
#define S3C244X_CICOCRSA2 S3C244X_CAMIFREG(0x3C)
#define S3C244X_CICOCRSA3 S3C244X_CAMIFREG(0x40)
#define S3C244X_CICOCRSA4 S3C244X_CAMIFREG(0x44)
#define S3C244X_CICOTRGFMT S3C244X_CAMIFREG(0x48)
#define S3C244X_CICOCTRL S3C244X_CAMIFREG(0x4C)
#define S3C244X_CICOSCPRERATIO S3C244X_CAMIFREG(0x50)
#define S3C244X_CICOSCPREDST S3C244X_CAMIFREG(0x54)
#define S3C244X_CICOSCCTRL S3C244X_CAMIFREG(0x58)
#define S3C244X_CICOTAREA S3C244X_CAMIFREG(0x5C)
#define S3C244X_CICOSTATUS S3C244X_CAMIFREG(0x64)
#define S3C244X_CIPRCLRSA1 S3C244X_CAMIFREG(0x6C)
#define S3C244X_CIPRCLRSA2 S3C244X_CAMIFREG(0x70)
#define S3C244X_CIPRCLRSA3 S3C244X_CAMIFREG(0x74)
#define S3C244X_CIPRCLRSA4 S3C244X_CAMIFREG(0x78)
#define S3C244X_CIPRTRGFMT S3C244X_CAMIFREG(0x7C)
#define S3C244X_CIPRCTRL S3C244X_CAMIFREG(0x80)
#define S3C244X_CIPRSCPRERATIO S3C244X_CAMIFREG(0x84)
#define S3C244X_CIPRSCPREDST S3C244X_CAMIFREG(0x88)
#define S3C244X_CIPRSCCTRL S3C244X_CAMIFREG(0x8C)
#define S3C244X_CIPRTAREA S3C244X_CAMIFREG(0x90)
#define S3C244X_CIPRSTATUS S3C244X_CAMIFREG(0x98)
#define S3C244X_CIIMGCPT S3C244X_CAMIFREG(0xA0)
#define S3C244X_CICOSTAY(i) S3C244X_CAMIFREG((0x18+(i)*4))
#define S3C244X_CICOSTACb(i) S3C244X_CAMIFREG((0x28+(i)*4))
#define S3C244X_CICOSTACr(i) S3C244X_CAMIFREG((0x38+(i)*4))
#define S3C244X_CIPRSTARGB(i) S3C244X_CAMIFREG((0x6C+(i)*4))
#endif
/*s3c2440camif.c*/
/*
* Video for Linux 2 - Camera interface on S3C2440
*
* Copyright (C) 2009
*
* 2009/06/19 :
* ported by Steve Chang
*
* 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef CONFIG_VIDEO_V4L1_COMPAT
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "s3c2440camif.h"
/* debug print macro. */
/* hardware & driver name, version etc. */
#define CARD_NAME "camera"
static unsigned has_ov9650;
unsigned long camif_base_addr;
#if 1
int __init sccb_init(void);
void __exit sccb_cleanup(void);
int __init s3c2440_ov9650_init(void);
void __exit s3c2440_ov9650_cleanup(void);
#endif
/* camera device(s) */
static struct s3c2440camif_dev camera;
/* image buffer for previewing. */
struct s3c2440camif_buffer img_buff[] =
{
{
.state = CAMIF_BUFF_INVALID,
.img_size = 0,
.order = 0,
.virt_base = (unsigned long)NULL,
.phy_base = (unsigned long)NULL,
.offset = 0
},
{
.state = CAMIF_BUFF_INVALID,
.img_size = 0,
.order = 0,
.virt_base = (unsigned long)NULL,
.phy_base = (unsigned long)NULL,
.offset = 0
},
{
.state = CAMIF_BUFF_INVALID,
.img_size = 0,
.order = 0,
.virt_base = (unsigned long)NULL,
.phy_base = (unsigned long)NULL,
.offset = 0
},
{
.state = CAMIF_BUFF_INVALID,
.img_size = 0,
.order = 0,
.virt_base = (unsigned long)NULL,
.phy_base = (unsigned long)NULL,
.offset = 0
}
};
/* software reset camera interface. */
static void __inline__ soft_reset_camif(void)
{
u32 cigctrl;
u32 cisrcfmt;
cisrcfmt = ioread32(S3C244X_CISRCFMT);
cisrcfmt |= (1<<31); // ITU-R BT.601 YCbCr 8-bit mode
iowrite32(cisrcfmt, S3C244X_CISRCFMT); /*Recommand by datasheet p.532*/
cigctrl = (1<<31)|(1<<29);
iowrite32(cigctrl, S3C244X_CIGCTRL);
mdelay(10);
cigctrl = (1<<29);
iowrite32(cigctrl, S3C244X_CIGCTRL);
mdelay(10);
}
/* software reset camera interface. */
static void __inline__ hw_reset_camif(void)
{
u32 cigctrl;
cigctrl = (1<<30)|(1<<29);
iowrite32(cigctrl, S3C244X_CIGCTRL);
mdelay(10);
cigctrl = (1<<29);
iowrite32(cigctrl, S3C244X_CIGCTRL);
mdelay(10);
}
/* switch camif from codec path to preview path. */
static void __inline__ camif_c2p(struct s3c2440camif_dev * pdev)
{
/* 1. stop codec. */
{
u32 cicoscctrl;
cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
cicoscctrl &= ~(1<<15); // stop codec scaler.
iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);
}
/* 2. soft-reset camif. */
soft_reset_camif();
/* 3. clear all overflow. */
{
u32 ciwdofst;
ciwdofst = ioread32(S3C244X_CIWDOFST);
ciwdofst |= (1<<30)|(1<<15)|(1<<14)|(1<<13)|(1<<12);
iowrite32(ciwdofst, S3C244X_CIWDOFST);
ciwdofst &= ~((1<<30)|(1<<15)|(1<<14)|(1<<13)|(1<<12));
iowrite32(ciwdofst, S3C244X_CIWDOFST);
}
pdev->path = CAMIF_PATH_PREVIEW;
}
/* switch camif from codec path to preview path. */
static void __inline__ camif_p2c(struct s3c2440camif_dev * pdev)
{
/* 1. stop preview. */
{
u32 ciprscctrl;
ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
ciprscctrl &= ~(1<<15); // stop preview scaler.
iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL);
}
/* 2. soft-reset camif. */
soft_reset_camif();
/* 3. clear all overflow. */
{
u32 ciwdofst;
ciwdofst = ioread32(S3C244X_CIWDOFST);
ciwdofst |= (1<<30)|(1<<15)|(1<<14)|(1<<13)|(1<<12);
iowrite32(ciwdofst, S3C244X_CIWDOFST);
ciwdofst &= ~((1<<30)|(1<<15)|(1<<14)|(1<<13)|(1<<12));
iowrite32(ciwdofst, S3C244X_CIWDOFST);
}
pdev->path = CAMIF_PATH_CODEC;
}
/* calculate main burst size and remained burst size. */
static void __inline__ calc_burst_size(u32 pixperword,u32 hSize, u32 *mainBurstSize, u32 *remainedBurstSize)
{
u32 tmp;
tmp = (hSize/pixperword)%16;
switch(tmp)
{
case 0:
*mainBurstSize = 16;
*remainedBurstSize = 16;
break;
case 4:
*mainBurstSize = 16;
*remainedBurstSize = 4;
break;
case 8:
*mainBurstSize=16;
*remainedBurstSize = 8;
break;
default:
tmp=(hSize/pixperword)%8;
switch(tmp)
{
case 0:
*mainBurstSize = 8;
*remainedBurstSize = 8;
break;
case 4:
*mainBurstSize = 8;
*remainedBurstSize = 4;
default:
*mainBurstSize = 4;
tmp = (hSize/pixperword)%4;
*remainedBurstSize = (tmp)?tmp:4;
break;
}
break;
}
}
/* calculate prescaler ratio and shift. */
static void __inline__ calc_prescaler_ratio_shift(u32 SrcSize, u32 DstSize, u32 *ratio, u32 *shift)
{
if(SrcSize>=32*DstSize)
{
*ratio=32;
*shift=5;
}
else if(SrcSize>=16*DstSize)
{
*ratio=16;
*shift=4;
}
else if(SrcSize>=8*DstSize)
{
*ratio=8;
*shift=3;
}
else if(SrcSize>=4*DstSize)
{
*ratio=4;
*shift=2;
}
else if(SrcSize>=2*DstSize)
{
*ratio=2;
*shift=1;
}
else
{
*ratio=1;
*shift=0;
}
}
/* update CISRCFMT only. */
static void __inline__ update_source_fmt_regs(struct s3c2440camif_dev *pdev)
{
u32 cisrcfmt;
cisrcfmt = (1<<31) // ITU-R BT.601 YCbCr 8-bit mode
|(0<<30) // CB,Cr value offset cntrol for YCbCr
|(pdev->srcHsize<<16) // source image width
// |(0<<14) // input order is YCbYCr
// |(1<<14) // input order is YCrYCb
|(2<<14) // input order is CbYCrY
// |(3<<14) // input order is CrYCbY
|(pdev->srcVsize<<0); // source image height
iowrite32(cisrcfmt, S3C244X_CISRCFMT);
}
/* update registers:
* PREVIEW path:
* CIPRCLRSA1 ~ CIPRCLRSA4
* CIPRTRGFMT
* CIPRCTRL
* CIPRSCCTRL
* CIPRTAREA
* CODEC path:
* CICOYSA1 ~ CICOYSA4
* CICOCBSA1 ~ CICOCBSA4
* CICOCRSA1 ~ CICOCRSA4
* CICOTRGFMT
* CICOCTRL
* CICOTAREA
*/
static void __inline__ update_target_fmt_regs(struct s3c2440camif_dev * pdev)
{
u32 ciprtrgfmt, cicotrgfmt = 0;
u32 ciprctrl, cicoctrl;
u32 ciprscctrl, cicoscctrl;
u32 mainBurstSize, remainedBurstSize;
switch(pdev->path) {
case CAMIF_PATH_PREVIEW:
/* CIPRCLRSA1 ~ CIPRCLRSA4. */
iowrite32(img_buff[0].phy_base, S3C244X_CIPRCLRSA1);
iowrite32(img_buff[1].phy_base, S3C244X_CIPRCLRSA2);
iowrite32(img_buff[2].phy_base, S3C244X_CIPRCLRSA3);
iowrite32(img_buff[3].phy_base, S3C244X_CIPRCLRSA4);
/* CIPRTRGFMT. */
ciprtrgfmt = (pdev->preTargetHsize<<16) // horizontal pixel number of target image
|(0<<14) // don't mirror or rotation.
|(pdev->preTargetVsize<<0); // vertical pixel number of target image
iowrite32(ciprtrgfmt, S3C244X_CIPRTRGFMT);
/* CIPRCTRL. */
calc_burst_size(2, pdev->preTargetHsize, &mainBurstSize, &remainedBurstSize);
ciprctrl = (mainBurstSize<<19)|(remainedBurstSize<<14);
iowrite32(ciprctrl, S3C244X_CIPRCTRL);
/* CIPRSCCTRL. */
ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
ciprscctrl &= 1<<15; // clear all other info except 'preview scaler start'.
ciprscctrl |= 0<<30; // 16-bits RGB
iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL); // 16-bit RGB
/* CIPRTAREA. */
iowrite32(pdev->preTargetHsize * pdev->preTargetVsize, S3C244X_CIPRTAREA);
break;
case CAMIF_PATH_CODEC:
/* CICOYSA1 ~ CICOYSA4. */
iowrite32(img_buff[0].phy_base, S3C244X_CICOYSA1);
iowrite32(img_buff[1].phy_base, S3C244X_CICOYSA2);
iowrite32(img_buff[2].phy_base, S3C244X_CICOYSA3);
iowrite32(img_buff[3].phy_base, S3C244X_CICOYSA4);
/* CICOCBSA1 ~ CICOCBSA4. */
iowrite32(img_buff[0].phy_base + (pdev->coTargetHsize * pdev->coTargetVsize), S3C244X_CICOCBSA1);
iowrite32(img_buff[1].phy_base + (pdev->coTargetHsize * pdev->coTargetVsize), S3C244X_CICOCBSA2);
iowrite32(img_buff[2].phy_base + (pdev->coTargetHsize * pdev->coTargetVsize), S3C244X_CICOCBSA3);
iowrite32(img_buff[3].phy_base + (pdev->coTargetHsize * pdev->coTargetVsize), S3C244X_CICOCBSA4);
switch(pdev->pixelformat) {
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YUV422P:
/* CICOCRSA1 ~ CICOCRSA4. */
iowrite32(img_buff[0].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 3 / 2), S3C244X_CICOCRSA1);
iowrite32(img_buff[1].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 3 / 2), S3C244X_CICOCRSA2);
iowrite32(img_buff[2].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 3 / 2), S3C244X_CICOCRSA3);
iowrite32(img_buff[3].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 3 / 2), S3C244X_CICOCRSA4);
cicotrgfmt = (1<<31)|(1<<30); /**/
break;
case V4L2_PIX_FMT_YUV420:
/* CICOCRSA1 ~ CICOCRSA4. */
iowrite32(img_buff[0].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 5 / 4), S3C244X_CICOCRSA1);
iowrite32(img_buff[1].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 5 / 4), S3C244X_CICOCRSA2);
iowrite32(img_buff[2].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 5 / 4), S3C244X_CICOCRSA3);
iowrite32(img_buff[3].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 5 / 4), S3C244X_CICOCRSA4);
cicotrgfmt = (1<<31); /**/
break;
}
/* CICOTRGFMT. */
cicotrgfmt |= (pdev->coTargetHsize<<16) // horizontal pixel number of target image
|(0<<14) // don't mirror or rotation.
|(pdev->coTargetVsize<<0); // vertical pixel number of target image
iowrite32(cicotrgfmt, S3C244X_CICOTRGFMT);
/* CICOCTRL. */
calc_burst_size(1, pdev->coTargetHsize, &mainBurstSize, &remainedBurstSize); /*y frame*/
cicoctrl = (mainBurstSize<<19)|(remainedBurstSize<<14);
calc_burst_size(1, (pdev->coTargetHsize / 2), &mainBurstSize, &remainedBurstSize); /*CbCr frame*/
cicoctrl |= (mainBurstSize<<9)|(remainedBurstSize<<4);
iowrite32(cicoctrl, S3C244X_CICOCTRL);
/* CICOSCCTRL. */
cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
cicoscctrl &= 1<<15; // clear all other info except 'codec scaler start'.
iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);
/* CICOTAREA. */
iowrite32(pdev->coTargetHsize * pdev->coTargetVsize, S3C244X_CICOTAREA);
break;
}
}
/* update CIWDOFST only. */
static void __inline__ update_target_wnd_regs(struct s3c2440camif_dev * pdev)
{
u32 ciwdofst;
u32 winHorOfst, winVerOfst;
winHorOfst = (pdev->srcHsize - pdev->wndHsize)>>1;
winVerOfst = (pdev->srcVsize - pdev->wndVsize)>>1;
winHorOfst &= 0xFFFFFFF8;
winVerOfst &= 0xFFFFFFF8;
if ((winHorOfst == 0)&&(winVerOfst == 0))
{
ciwdofst = 0; // disable windows offset.
}
else
{
ciwdofst = (1<<31) // window offset enable
|(1<<30) // clear the overflow ind flag of input CODEC FIFO Y
|(winHorOfst<<16) // windows horizontal offset
|(1<<15) // clear the overflow ind flag of input CODEC FIFO Cb
|(1<<14) // clear the overflow ind flag of input CODEC FIFO Cr
|(1<<13) // clear the overflow ind flag of input PREVIEW FIFO Cb
|(1<<12) // clear the overflow ind flag of input PREVIEW FIFO Cr
|(winVerOfst<<0); // window vertical offset
}
iowrite32(ciwdofst, S3C244X_CIWDOFST);
}
/* update registers:
* PREVIEW path:
* CIPRSCPRERATIO
* CIPRSCPREDST
* CIPRSCCTRL
* CODEC path:
* CICOSCPRERATIO
* CICOSCPREDST
* CICOSCCTRL
*/
static void __inline__ update_target_zoom_regs(struct s3c2440camif_dev *pdev)
{
u32 preHratio, preVratio;
u32 coHratio, coVratio;
u32 Hshift, Vshift;
u32 shfactor;
u32 preDstWidth, preDstHeight;
u32 Hscale, Vscale;
u32 mainHratio, mainVratio;
u32 ciprscpreratio, cicoscpreratio;
u32 ciprscpredst, cicoscpredst;
u32 ciprscctrl, cicoscctrl;
switch(pdev->path) {
case CAMIF_PATH_PREVIEW:
/* CIPRSCPRERATIO. */
calc_prescaler_ratio_shift(pdev->srcHsize, pdev->preTargetHsize,
&preHratio, &Hshift);
calc_prescaler_ratio_shift(pdev->srcVsize, pdev->preTargetVsize,
&preVratio, &Vshift);
shfactor = 10 - (Hshift + Vshift);
ciprscpreratio = (shfactor<<28) // shift factor for preview pre-scaler
|(preHratio<<16) // horizontal ratio of preview pre-scaler
|(preVratio<<0); // vertical ratio of preview pre-scaler
iowrite32(ciprscpreratio, S3C244X_CIPRSCPRERATIO);
/* CIPRSCPREDST. */
preDstWidth = pdev->srcHsize / preHratio;
preDstHeight = pdev->srcVsize / preVratio;
ciprscpredst = (preDstWidth<<16) // destination width for preview pre-scaler
|(preDstHeight<<0); // destination height for preview pre-scaler
iowrite32(ciprscpredst, S3C244X_CIPRSCPREDST);
/* CIPRSCCTRL. */
Hscale = (pdev->srcHsize >= pdev->preTargetHsize)?0:1;
Vscale = (pdev->srcVsize >= pdev->preTargetVsize)?0:1;
mainHratio = (pdev->srcHsize<<8)/(pdev->preTargetHsize<
mainVratio = (pdev->srcVsize<<8)/(pdev->preTargetVsize<
ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
ciprscctrl &= ~(1<<30); //keep preview image format RGB565
// ciprscctrl &= (1<<15); //preview scaler start.
ciprscctrl |= (1<<31) // this bit should be always 1.
|(Hscale<<29) // ???, horizontal scale up/down.
|(Vscale<<28) // ???, vertical scale up/down.
|(mainHratio<<16) // horizontal scale ratio for preview main-scaler
|(mainVratio<<0); // vertical scale ratio for preview main-scaler
iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL);
break;
case CAMIF_PATH_CODEC:
/* CICOSCPRERATIO. */
calc_prescaler_ratio_shift(pdev->srcHsize, pdev->coTargetHsize,
&coHratio, &Hshift);
calc_prescaler_ratio_shift(pdev->srcVsize, pdev->coTargetVsize,
&coVratio, &Vshift);
shfactor = 10 - (Hshift + Vshift);
cicoscpreratio = (shfactor<<28) // shift factor for preview pre-scaler
|(coHratio<<16) // horizontal ratio of preview pre-scaler
|(coVratio<<0); // vertical ratio of preview pre-scaler
iowrite32(cicoscpreratio, S3C244X_CICOSCPRERATIO);
/* CICOSCPREDST. */
preDstWidth = pdev->srcHsize / coHratio;
preDstHeight = pdev->srcVsize / coVratio;
cicoscpredst = (preDstWidth<<16) // destination width for preview pre-scaler
|(preDstHeight<<0); // destination height for preview pre-scaler
iowrite32(cicoscpredst, S3C244X_CICOSCPREDST);
/* CICOSCCTRL. */
Hscale = (pdev->srcHsize >= pdev->coTargetHsize)?0:1;
Vscale = (pdev->srcVsize >= pdev->coTargetVsize)?0:1;
mainHratio = (pdev->srcHsize<<8)/(pdev->coTargetHsize<
mainVratio = (pdev->srcVsize<<8)/(pdev->coTargetVsize<
cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
// cicoscctrl &= (1<<15); //codec scaler start.
cicoscctrl |=
(Hscale<<30) // ???, horizontal scale up/down.
|(Vscale<<29) // ???, vertical scale up/down.
|(mainHratio<<16) // horizontal scale ratio for preview main-scaler
|(mainVratio<<0); // vertical scale ratio for preview main-scaler
iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);
break;
}
}
/* update camif registers, called only when camif ready, or ISR. */
static void __inline__ update_camif_regs(struct s3c2440camif_dev * pdev)
{
if (!in_irq())
{
while(1) // wait until VSYNC is 'L'
{
barrier();
if ((ioread32(S3C244X_CICOSTATUS)&(1<<28)) == 0)
break;
}
}
/* WARNING: don't change the statement sort below!!! */
update_source_fmt_regs(pdev);
update_target_wnd_regs(pdev);
update_target_fmt_regs(pdev);
update_target_zoom_regs(pdev);
}
/* start image capture.
*
* param 'stream' means capture pictures streamly or capture only one picture.
*/
static int start_capture(struct s3c2440camif_dev * pdev)
{
int ret;
u32 ciwdofst;
u32 ciprscctrl, cicoscctrl;
u32 ciimgcpt;
if(pdev->path == CAMIF_PATH_NONE)
return 0;
ciwdofst = ioread32(S3C244X_CIWDOFST);
ciwdofst |= (1<<30) // Clear the overflow indication flag of input CODEC FIFO Y
|(1<<15) // Clear the overflow indication flag of input CODEC FIFO Cb
|(1<<14) // Clear the overflow indication flag of input CODEC FIFO Cr
|(1<<13) // Clear the overflow indication flag of input PREVIEW FIFO Cb
|(1<<12); // Clear the overflow indication flag of input PREVIEW FIFO Cr
iowrite32(ciwdofst, S3C244X_CIWDOFST);
switch(pdev->path) {
case CAMIF_PATH_PREVIEW:
//printk("Preview Start...\n");
ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
ciprscctrl |= 1<<15; // preview scaler start
iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL);
ciimgcpt = (1<<31) // camera interface global capture enable
|(1<<29); // capture enable for preview scaler.
iowrite32(ciimgcpt, S3C244X_CIIMGCPT);
pdev->state = CAMIF_STATE_PREVIEWING;
break;
case CAMIF_PATH_CODEC:
//printk("Codec Start...\n");
cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
cicoscctrl |= (1<<15); // codec scaler start
iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);
ciimgcpt = (1<<31) // camera interface global capture enable
|(1<<30); // capture enable for codec scaler.
iowrite32(ciimgcpt, S3C244X_CIIMGCPT);
pdev->state = CAMIF_STATE_CODECING;
break;
}
ret = 0;
#if 0
if (stream == 0)
{
pdev->cmdcode = CAMIF_CMD_STOP;
ret = wait_event_interruptible(pdev->wait, pdev->cmdcode == CAMIF_CMD_NONE);
}
#endif
return ret;
}
/* stop image capture, always called in ISR.
* P-path regs:
* CIPRSCCTRL
* CIPRCTRL
* C-path regs:
* CICOSCCTRL.
* CICOCTRL
* Global regs:
* CIIMGCPT
*/
static void stop_capture(struct s3c2440camif_dev * pdev)
{
u32 ciprscctrl, cicoscctrl;
u32 ciprctrl, cicoctrl;
switch(pdev->state)
{
case CAMIF_STATE_PREVIEWING:
/* CIPRCTRL. */
ciprctrl = ioread32(S3C244X_CIPRCTRL);
ciprctrl |= 1<<2; // enable last IRQ at the end of frame capture.
iowrite32(ciprctrl, S3C244X_CIPRCTRL);
/* CIPRSCCTRL. */
ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
ciprscctrl &= ~(1<<15); // clear preview scaler start bit.
iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL);
break;
case CAMIF_STATE_CODECING:
/* CICOCTRL. */
cicoctrl = ioread32(S3C244X_CICOCTRL);
cicoctrl |= 1<<2; // enable last IRQ at the end of frame capture.
iowrite32(cicoctrl, S3C244X_CICOCTRL);
/* CICOSCCTRL. */
cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
cicoscctrl &= ~(1<<15); // clear codec scaler start bit.
iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);
break;
}
/* CIIMGCPT. */
iowrite32(0, S3C244X_CIIMGCPT);
pdev->state = CAMIF_STATE_READY;
}
/* update camera interface with the new config. */
static void update_camif_config (struct s3c2440camif_dev *pdev, u32 cmdcode)
{
switch(pdev->state)
{
case CAMIF_STATE_READY:
if(cmdcode == CAMIF_CMD_REGS)
{
update_camif_regs(pdev); // config the regs directly.
break;
}
#if 0
/* source image format. */
if (cmdcode & CAMIF_CMD_SFMT)
{
// ignore it, nothing to do now.
}
/* target image format. */
if (cmdcode & CAMIF_CMD_TFMT)
{
/* change target image format only. */
}
/* target image window offset. */
if (cmdcode & CAMIF_CMD_WND)
{
}
/* target image zoomi & zoomout. */
if (cmdcode & CAMIF_CMD_ZOOM)
{
}
#endif
if (cmdcode == CAMIF_CMD_P2C)
{
camif_p2c(pdev);
break;
}
if (cmdcode == CAMIF_CMD_C2P)
{
camif_c2p(pdev);
break;
}
if (cmdcode == CAMIF_CMD_START)
{
start_capture(pdev);
}
break;
case CAMIF_STATE_PREVIEWING:
/* camif is previewing image. */
disable_irq(IRQ_S3C2440_CAM_P); // disable cam-preview irq.
/* stop previewing. */
if (cmdcode & CAMIF_CMD_STOP)
{
pdev->cmdcode |= CAMIF_CMD_STOP;
}
enable_irq(IRQ_S3C2440_CAM_P); // enable cam-preview irq.
wait_event(pdev->wait, (pdev->cmdcode==CAMIF_CMD_NONE)); // wait until the ISR completes command.
break;
case CAMIF_STATE_CODECING:
/* camif is previewing image. */
disable_irq(IRQ_S3C2440_CAM_C); // disable cam-codec irq.
/* stop previewing. */
if (cmdcode & CAMIF_CMD_STOP)
{
pdev->cmdcode |= CAMIF_CMD_STOP;
}
enable_irq(IRQ_S3C2440_CAM_C); // enable cam-codec irq.
wait_event(pdev->wait, (pdev->cmdcode==CAMIF_CMD_NONE)); // wait until the ISR completes command.
break;
default:
break;
}
}
static void __inline__ invalid_image_buffer(void)
{
img_buff[0].state = CAMIF_BUFF_INVALID;
img_buff[1].state = CAMIF_BUFF_INVALID;
img_buff[2].state = CAMIF_BUFF_INVALID;
img_buff[3].state = CAMIF_BUFF_INVALID;
}
/* init image buffer (only when the camif is first open). */
static int __inline__ init_image_buffer(struct s3c2440camif_dev *pdev)
{
int size1, size2;
unsigned long size = 0;
unsigned int order = 0;
/* size1 is the max image size of codec path. */
size1 = MAX_C_WIDTH * MAX_C_HEIGHT * 2;
/* size2 is the max image size of preview path. */
size2 = MAX_P_WIDTH * MAX_P_HEIGHT * 2;
size = (size1 > size2) ? size1 : size2;
printk("dma_alloc_coherent <0> size : 0x%08x\n", size);
order = get_order(size);
img_buff[0].order = order;
img_buff[0].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[0].order);
if (img_buff[0].virt_base == (unsigned long)NULL)
{
goto error0;
}
img_buff[0].img_size = size;
img_buff[0].phy_base = img_buff[0].virt_base - PAGE_OFFSET + PHYS_OFFSET; // the DMA address.
img_buff[0].offset = 0;
printk("dma_alloc_coherent <1> size : 0x%08x\n", size);
img_buff[1].order = order;
img_buff[1].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[1].order);
if (img_buff[1].virt_base == (unsigned long)NULL)
{
goto error1;
}
img_buff[1].img_size = size;
img_buff[1].phy_base = img_buff[1].virt_base - PAGE_OFFSET + PHYS_OFFSET; // the DMA address.
img_buff[1].offset = PAGE_SIZE << order;
printk("dma_alloc_coherent <2> size : 0x%08x\n", size);
img_buff[2].order = order;
img_buff[2].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[2].order);
if (img_buff[2].virt_base == (unsigned long)NULL)
{
goto error2;
}
img_buff[2].img_size = size;
img_buff[2].phy_base = img_buff[2].virt_base - PAGE_OFFSET + PHYS_OFFSET; // the DMA address.
img_buff[2].offset = (PAGE_SIZE << order) * 2;
printk("dma_alloc_coherent <3> size : 0x%08x\n", size);
img_buff[3].order = order;
img_buff[3].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[3].order);
if (img_buff[3].virt_base == (unsigned long)NULL)
{
goto error3;
}
img_buff[3].img_size = size;
img_buff[3].phy_base = img_buff[3].virt_base - PAGE_OFFSET + PHYS_OFFSET; // the DMA address.
img_buff[3].offset = (PAGE_SIZE << order) * 3;
invalid_image_buffer();
return 0;
error3:
free_pages(img_buff[2].virt_base, order);
img_buff[2].phy_base = (unsigned long)NULL;
error2:
free_pages(img_buff[1].virt_base, order);
img_buff[1].phy_base = (unsigned long)NULL;
error1:
free_pages(img_buff[0].virt_base, order);
img_buff[0].phy_base = (unsigned long)NULL;
error0:
return -ENOMEM;
}
/* free image buffers (only when the camif is latest close). */
static void __inline__ free_image_buffer(struct s3c2440camif_dev *pdev)
{
free_pages(img_buff[0].virt_base, img_buff[0].order);
free_pages(img_buff[1].virt_base, img_buff[1].order);
free_pages(img_buff[2].virt_base, img_buff[2].order);
free_pages(img_buff[3].virt_base, img_buff[3].order);
img_buff[0].order = 0;
img_buff[0].virt_base = (unsigned long)NULL;
img_buff[0].phy_base = (unsigned long)NULL;
img_buff[0].offset = 0;
img_buff[1].order = 0;
img_buff[1].virt_base = (unsigned long)NULL;
img_buff[1].phy_base = (unsigned long)NULL;
img_buff[1].offset = 0;
img_buff[2].order = 0;
img_buff[2].virt_base = (unsigned long)NULL;
img_buff[2].phy_base = (unsigned long)NULL;
img_buff[2].offset = 0;
img_buff[3].order = 0;
img_buff[3].virt_base = (unsigned long)NULL;
img_buff[3].phy_base = (unsigned long)NULL;
img_buff[3].offset = 0;
}
static void __inline__ update_image_buffer(struct s3c2440camif_dev *pdev)
{
unsigned long size = 0;
switch(pdev->pixelformat) {
case V4L2_PIX_FMT_RGB565:
size = pdev->preTargetHsize * pdev->preTargetVsize * 2;
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/semaphore.h>
#include <mach/regs-gpio.h>
#include "sccb.h"
#include "s3c2440camif.h"
#define OV9650_SCCB_ADDR 0x60
#define OV9650_MANUFACT_ID 0x7FA2
#define OV9650_PRODUCT_ID 0x9650
/*
09032004
OV9650
VGA YUV
15fps when 24MHz input clock
Device Address(Hex)/Register(Hex)/Value(Hex)
*/
static struct ov9650_reg
{
u8 subaddr;
u8 value;
}regs[] = {
{0x12, 0x80},
{0x11, 0x81},
{0x6b, 0x0a},
{0x6a, 0x3e},
{0x3b, 0x09},
{0x13, 0xe0},
{0x01, 0x80},
{0x02, 0x80},
{0x00, 0x00},
{0x10, 0x00},
{0x13, 0xe5},
/*{0x39, 0x50},*/ /*30 fps*/
{0x39, 0x43}, /*15fps*/
/*{0x38, 0x92},*/ /*30fps*/
{0x38, 0x12}, /*15fps*/
{0x37, 0x00},
/*{0x35, 0x81},*/ /*30 fps*/
{0x35, 0x91}, /*15 fps*/
{0x0e, 0x20},
{0x1e, 0x04},
{0xa8, 0x80},
{0x12, 0x40},
{0x04, 0x00},
{0x0c, 0x04},
{0x0d, 0x80},
{0x18, 0xc6},
{0x17, 0x26},
{0x32, 0xad},
{0x03, 0x00},
{0x1a, 0x3d},
{0x19, 0x01},
{0x3f, 0xa6},
{0x14, 0x2e},
{0x15, 0x02},
{0x41, 0x02},
{0x42, 0x08},
{0x1b, 0x00},
{0x16, 0x06},
{0x33, 0xe2}, /*c0 for internal regulator*/
{0x34, 0xbf},
{0x96, 0x04},
{0x3a, 0x00},
{0x8e, 0x00},
{0x3c, 0x77},
{0x8B, 0x06},
{0x94, 0x88},
{0x95, 0x88},
{0x40, 0xc1},
{0x29, 0x3f}, /*2f for internal regulator*/
{0x0f, 0x42},
{0x3d, 0x92},
{0x69, 0x40},
{0x5c, 0xb9},
{0x5d, 0x96},
{0x5e, 0x10},
{0x59, 0xc0},
{0x5a, 0xaf},
{0x5b, 0x55},
{0x43, 0xf0},
{0x44, 0x10},
{0x45, 0x68},
{0x46, 0x96},
{0x47, 0x60},
{0x48, 0x80},
{0x5f, 0xe0},
{0x60, 0x8c}, /*0c for advanced AWB (related to lens)*/
{0x61, 0x20},
{0xa5, 0xd9},
{0xa4, 0x74},
{0x8d, 0x02},
{0x13, 0xe7},
{0x4f, 0x3a},
{0x50, 0x3d},
{0x51, 0x03},
{0x52, 0x12},
{0x53, 0x26},
{0x54, 0x38},
{0x55, 0x40},
{0x56, 0x40},
{0x57, 0x40},
{0x58, 0x0d},
{0x8C, 0x23},
{0x3e, 0x02},
{0xa9, 0xb8},
{0xaa, 0x92},
{0xab, 0x0a},
{0x8f, 0xdf},
{0x90, 0x00},
{0x91, 0x00},
{0x9f, 0x00},
{0xa0, 0x00},
{0x3a, 0x0d}, /*UYVY, Digital BLC enable*/
{0x24, 0x70},
{0x25, 0x64},
{0x26, 0xc3},
{0x2a, 0x00}, /*10 for 50Hz*/
{0x2b, 0x00}, /*40 for 50Hz*/
{0x6c, 0x40},
{0x6d, 0x30},
{0x6e, 0x4b},
{0x6f, 0x60},
{0x70, 0x70},
{0x71, 0x70},
{0x72, 0x70},
{0x73, 0x70},
{0x74, 0x60},
{0x75, 0x60},
{0x76, 0x50},
{0x77, 0x48},
{0x78, 0x3a},
{0x79, 0x2e},
{0x7a, 0x28},
{0x7b, 0x22},
{0x7c, 0x04},
{0x7d, 0x07},
{0x7e, 0x10},
{0x7f, 0x28},
{0x80, 0x36},
{0x81, 0x44},
{0x82, 0x52},
{0x83, 0x60},
{0x84, 0x6c},
{0x85, 0x78},
{0x86, 0x8c},
{0x87, 0x9e},
{0x88, 0xbb},
{0x89, 0xd2},
{0x8a, 0xe6}
};
#if 0
static struct ov9650_reg
{
u8 subaddr;
u8 value;
}regs[] = {
/* OV9650 intialization parameter table for SXGA application */
{0x12, 0x80}, {0x39, 0x43}, {0x38, 0x12}, {0x37, 0x00}, {0x0e, 0x20},
{0x1e, 0x0c}, {0x01, 0x80}, {0x02, 0x80}, {0x00, 0x00}, {0x10, 0xf0},
{0x04, 0x00}, {0x0c, 0x00}, {0x0d, 0x00}, {0x11, 0x80}, {0x12, 0x40},
{0x14, 0x2e}, {0x15, 0x00}, {0x18, 0xbd}, {0x17, 0x1d}, {0x32, 0xbf},
{0x03, 0x12}, {0x1a, 0x81}, {0x19, 0x01}, {0x3f, 0xa6}, {0x41, 0x02},
{0x42, 0x08}, {0x1b, 0x00}, {0x16, 0x06}, {0x33, 0xc0}, {0x34, 0xbf},
{0xa8, 0x80}, {0x96, 0x04}, {0x3a, 0x00}, {0x8e, 0x00}, {0x3c, 0x77},
{0x8b, 0x06}, {0x35, 0x91}, {0x94, 0x88}, {0x95, 0x88}, {0x40, 0xc1},
{0x29, 0x3f}, {0x0f, 0x42}, {0x13, 0xe5}, {0x3d, 0x92}, {0x69, 0x80},
{0x5c, 0x96}, {0x5d, 0x96}, {0x5e, 0x10}, {0x59, 0xeb}, {0x5a, 0x9c},
{0x5b, 0x55}, {0x43, 0xf0}, {0x44, 0x10}, {0x45, 0x55}, {0x46, 0x86},
{0x47, 0x64}, {0x48, 0x86}, {0x5f, 0xe0}, {0x60, 0x8c}, {0x61, 0x20},
{0xa5, 0xd9}, {0xa4, 0x74}, {0x8d, 0x02}, {0x13, 0xe7}, {0x4f, 0x3a},
{0x50, 0x3d}, {0x51, 0x03}, {0x52, 0x12}, {0x53, 0x26}, {0x54, 0x38},
{0x55, 0x40}, {0x56, 0x40}, {0x57, 0x40}, {0x58, 0x0d}, {0x8c, 0x23},
{0x3e, 0x02}, {0xa9, 0xb8}, {0xaa, 0x92}, {0xab, 0x0a}, {0x8f, 0xdf},
{0x90, 0x00}, {0x91, 0x00}, {0x9f, 0x00}, {0x3a, 0x0c}, {0x24, 0x70},
{0x25, 0x64}, {0x26, 0xc3}, {0x2a, 0x12}, {0x2b, 0x46}, {0x3b, 0x19},
{0x6c, 0x40}, {0x6d, 0x30}, {0x6e, 0x4b}, {0x6f, 0x60},
{0x70, 0x70}, {0x71, 0x70}, {0x72, 0x70}, {0x73, 0x70},
{0x74, 0x60}, {0x75, 0x60}, {0x76, 0x50}, {0x77, 0x48},
{0x78, 0x3a}, {0x79, 0x2e}, {0x7a, 0x28}, {0x7b, 0x22},
{0x7c, 0x04}, {0x7d, 0x07}, {0x7e, 0x10}, {0x7f, 0x28},
{0x80, 0x36}, {0x81, 0x44}, {0x82, 0x52}, {0x83, 0x60},
{0x84, 0x6c}, {0x85, 0x78}, {0x86, 0x8c}, {0x87, 0x9e},
{0x88, 0xbb}, {0x89, 0xd2}, {0x8a, 0xe6},
{0x6a, 0x41}, {0x66, 0x00},
{0x3e, 0x00}, {0x3f, 0xa4}
};
#endif
DECLARE_MUTEX(regs_mutex);
static void __inline__ ov9650_poweron(void)
{
s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_OUTP);
s3c2410_gpio_setpin(S3C2410_GPG12, 0);
mdelay(20);
}
static void __inline__ ov9650_poweroff(void)
{
s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_OUTP);
s3c2410_gpio_setpin(S3C2410_GPG12, 1);
mdelay(20);
}
static int __inline__ ov9650_check(void)
{
u32 mid;
mid = sccb_read(OV9650_SCCB_ADDR, 0x1c)<<8;
mid |= sccb_read(OV9650_SCCB_ADDR, 0x1d);
printk("SCCB address 0x%02X, manufacture ID 0x%04X, expect 0x%04X\n", OV9650_SCCB_ADDR, mid, OV9650_MANUFACT_ID);
return (mid==OV9650_MANUFACT_ID)?1:0;
}
static u32 __inline__ show_ov9650_product_id(void)
{
u32 pid;
pid = sccb_read(OV9650_SCCB_ADDR, 0x0a)<<8;
pid |= sccb_read(OV9650_SCCB_ADDR, 0x0b);
printk("SCCB address 0x%02X, product ID 0x%04X, expect 0x%04X\n", OV9650_SCCB_ADDR, pid, OV9650_PRODUCT_ID);
return pid;
}
static void ov9650_init_regs(void)
{
int i;
down(®s_mutex);
for (i=0; i<ARRAY_SIZE(regs); i++)
{
if (regs[i].subaddr == 0xff)
{
mdelay(regs[i].value);
continue;
}
sccb_write(OV9650_SCCB_ADDR, regs[i].subaddr, regs[i].value);
}
up(®s_mutex);
}
int s3c2440_ov9650_init(void)
{
printk(KERN_ALERT"Loading OV9650 driver.........\n");
/* power on. */
ov9650_poweron();
mdelay(100);
/* check device. */
if (ov9650_check() == 0 && ov9650_check() == 0)
{
printk(KERN_ERR"No OV9650 found!!!\n");
return -ENODEV;
}
show_ov9650_product_id();
ov9650_init_regs();
printk("ov9650 init done!\n");
return 0;
}
#if 0
module_init(ov9650_init);
module_exit(ov9650_cleanup);
MODULE_LICENSE("GPL");
#endif
/*s3c2440camif.h*/
#ifndef __S3C2440CAMIF_H__
#define __S3C2440CAMIF_H__
#define MIN_C_WIDTH 32
#define MAX_C_WIDTH 320
#define MIN_C_HEIGHT 48
#define MAX_C_HEIGHT 240
#define MIN_P_WIDTH 32
#define MAX_P_WIDTH 640
#define MIN_P_HEIGHT 48
#define MAX_P_HEIGHT 480
enum
{
CAMIF_BUFF_INVALID = 0,
CAMIF_BUFF_RGB565 = 1,
CAMIF_BUFF_RGB24 = 2,
CAMIF_BUFF_YCbCr420 = 3,
CAMIF_BUFF_YCbCr422 = 4
};
/* image buffer for s3c2440 camif. */
struct s3c2440camif_buffer
{
int state;
ssize_t img_size;
struct device *dev;
unsigned int order;
unsigned long virt_base;
unsigned long phy_base;
unsigned long offset;
};
/* for s3c2440camif_dev->state field. */
enum
{
CAMIF_STATE_FREE = 0, // not openned
CAMIF_STATE_READY = 1, // openned, but standby
CAMIF_STATE_PREVIEWING = 2, // in previewing
CAMIF_STATE_CODECING = 3 // in capturing
};
/* for s3c2440camif_dev->cmdcode field. */
enum
{
CAMIF_CMD_NONE = 0,
CAMIF_CMD_SFMT = 1<<0, // source image format changed.
CAMIF_CMD_WND = 1<<1, // window offset changed.
CAMIF_CMD_ZOOM = 1<<2, // zoom picture in/out
CAMIF_CMD_TFMT = 1<<3, // target image format changed.
CAMIF_CMD_P2C = 1<<4, // need camif switches from p-path to c-path
CAMIF_CMD_C2P = 1<<5, // neet camif switches from c-path to p-path
CAMIF_CMD_REGS = 1<<6, // Update regs
CAMIF_CMD_START = 1<<15, // stop capture
CAMIF_CMD_STOP = 1<<16 // stop capture
};
enum
{
CAMIF_PATH_NONE = 0,
CAMIF_PATH_PREVIEW = 1<<0,
CAMIF_PATH_CODEC = 1<<1
};
/* main s3c2440 camif structure. */
struct s3c2440camif_dev
{
/* hardware clock. */
struct clk * clk;
/* source(input) image size. */
int srcHsize;
int srcVsize;
/* windowed image size. */
int wndHsize;
int wndVsize;
/* codec-path target(output) image size. */
int coTargetHsize;
int coTargetVsize;
/* preview-path target(preview) image size. */
int preTargetHsize;
int preTargetVsize;
/* the camera interface state. */
int state; // CMAIF_STATE_FREE, CAMIF_STATE_PREVIEWING, CAMIF_STATE_CAPTURING.
/* for executing camif commands. */
int cmdcode; // command code, CAMIF_CMD_START, CAMIF_CMD_CFG, etc.
wait_queue_head_t wait; // wait queue for waiting untile command completed (if in preview or in capturing).
/* For V4L2 data */
__u32 pixelformat;
int path; /*output path*/
spinlock_t lock;
int open_count;
int frame; /*frame index*/
int rdy;
};
#if 0
/* opened file handle.*/
struct s3c2440camif_fh
{
/* the camif */
struct s3c2440camif_dev * dev;
/* master flag, only master openner could execute 'set' ioctls. */
int master;
};
#endif
struct s3c2440camif_res
{
int width;
int height;
};
#define S3C244X_CAMIFREG(x) ((x) + camif_base_addr)
/* CAMIF control registers */
#define S3C244X_CISRCFMT S3C244X_CAMIFREG(0x00)
#define S3C244X_CIWDOFST S3C244X_CAMIFREG(0x04)
#define S3C244X_CIGCTRL S3C244X_CAMIFREG(0x08)
#define S3C244X_CICOYSA1 S3C244X_CAMIFREG(0x18)
#define S3C244X_CICOYSA2 S3C244X_CAMIFREG(0x1C)
#define S3C244X_CICOYSA3 S3C244X_CAMIFREG(0x20)
#define S3C244X_CICOYSA4 S3C244X_CAMIFREG(0x24)
#define S3C244X_CICOCBSA1 S3C244X_CAMIFREG(0x28)
#define S3C244X_CICOCBSA2 S3C244X_CAMIFREG(0x2C)
#define S3C244X_CICOCBSA3 S3C244X_CAMIFREG(0x30)
#define S3C244X_CICOCBSA4 S3C244X_CAMIFREG(0x34)
#define S3C244X_CICOCRSA1 S3C244X_CAMIFREG(0x38)
#define S3C244X_CICOCRSA2 S3C244X_CAMIFREG(0x3C)
#define S3C244X_CICOCRSA3 S3C244X_CAMIFREG(0x40)
#define S3C244X_CICOCRSA4 S3C244X_CAMIFREG(0x44)
#define S3C244X_CICOTRGFMT S3C244X_CAMIFREG(0x48)
#define S3C244X_CICOCTRL S3C244X_CAMIFREG(0x4C)
#define S3C244X_CICOSCPRERATIO S3C244X_CAMIFREG(0x50)
#define S3C244X_CICOSCPREDST S3C244X_CAMIFREG(0x54)
#define S3C244X_CICOSCCTRL S3C244X_CAMIFREG(0x58)
#define S3C244X_CICOTAREA S3C244X_CAMIFREG(0x5C)
#define S3C244X_CICOSTATUS S3C244X_CAMIFREG(0x64)
#define S3C244X_CIPRCLRSA1 S3C244X_CAMIFREG(0x6C)
#define S3C244X_CIPRCLRSA2 S3C244X_CAMIFREG(0x70)
#define S3C244X_CIPRCLRSA3 S3C244X_CAMIFREG(0x74)
#define S3C244X_CIPRCLRSA4 S3C244X_CAMIFREG(0x78)
#define S3C244X_CIPRTRGFMT S3C244X_CAMIFREG(0x7C)
#define S3C244X_CIPRCTRL S3C244X_CAMIFREG(0x80)
#define S3C244X_CIPRSCPRERATIO S3C244X_CAMIFREG(0x84)
#define S3C244X_CIPRSCPREDST S3C244X_CAMIFREG(0x88)
#define S3C244X_CIPRSCCTRL S3C244X_CAMIFREG(0x8C)
#define S3C244X_CIPRTAREA S3C244X_CAMIFREG(0x90)
#define S3C244X_CIPRSTATUS S3C244X_CAMIFREG(0x98)
#define S3C244X_CIIMGCPT S3C244X_CAMIFREG(0xA0)
#define S3C244X_CICOSTAY(i) S3C244X_CAMIFREG((0x18+(i)*4))
#define S3C244X_CICOSTACb(i) S3C244X_CAMIFREG((0x28+(i)*4))
#define S3C244X_CICOSTACr(i) S3C244X_CAMIFREG((0x38+(i)*4))
#define S3C244X_CIPRSTARGB(i) S3C244X_CAMIFREG((0x6C+(i)*4))
#endif
/*s3c2440camif.c*/
/*
* Video for Linux 2 - Camera interface on S3C2440
*
* Copyright (C) 2009
*
* 2009/06/19 :
* ported by Steve Chang
*
* 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef CONFIG_VIDEO_V4L1_COMPAT
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "s3c2440camif.h"
/* debug print macro. */
/* hardware & driver name, version etc. */
#define CARD_NAME "camera"
static unsigned has_ov9650;
unsigned long camif_base_addr;
#if 1
int __init sccb_init(void);
void __exit sccb_cleanup(void);
int __init s3c2440_ov9650_init(void);
void __exit s3c2440_ov9650_cleanup(void);
#endif
/* camera device(s) */
static struct s3c2440camif_dev camera;
/* image buffer for previewing. */
struct s3c2440camif_buffer img_buff[] =
{
{
.state = CAMIF_BUFF_INVALID,
.img_size = 0,
.order = 0,
.virt_base = (unsigned long)NULL,
.phy_base = (unsigned long)NULL,
.offset = 0
},
{
.state = CAMIF_BUFF_INVALID,
.img_size = 0,
.order = 0,
.virt_base = (unsigned long)NULL,
.phy_base = (unsigned long)NULL,
.offset = 0
},
{
.state = CAMIF_BUFF_INVALID,
.img_size = 0,
.order = 0,
.virt_base = (unsigned long)NULL,
.phy_base = (unsigned long)NULL,
.offset = 0
},
{
.state = CAMIF_BUFF_INVALID,
.img_size = 0,
.order = 0,
.virt_base = (unsigned long)NULL,
.phy_base = (unsigned long)NULL,
.offset = 0
}
};
/* software reset camera interface. */
static void __inline__ soft_reset_camif(void)
{
u32 cigctrl;
u32 cisrcfmt;
cisrcfmt = ioread32(S3C244X_CISRCFMT);
cisrcfmt |= (1<<31); // ITU-R BT.601 YCbCr 8-bit mode
iowrite32(cisrcfmt, S3C244X_CISRCFMT); /*Recommand by datasheet p.532*/
cigctrl = (1<<31)|(1<<29);
iowrite32(cigctrl, S3C244X_CIGCTRL);
mdelay(10);
cigctrl = (1<<29);
iowrite32(cigctrl, S3C244X_CIGCTRL);
mdelay(10);
}
/* software reset camera interface. */
static void __inline__ hw_reset_camif(void)
{
u32 cigctrl;
cigctrl = (1<<30)|(1<<29);
iowrite32(cigctrl, S3C244X_CIGCTRL);
mdelay(10);
cigctrl = (1<<29);
iowrite32(cigctrl, S3C244X_CIGCTRL);
mdelay(10);
}
/* switch camif from codec path to preview path. */
static void __inline__ camif_c2p(struct s3c2440camif_dev * pdev)
{
/* 1. stop codec. */
{
u32 cicoscctrl;
cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
cicoscctrl &= ~(1<<15); // stop codec scaler.
iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);
}
/* 2. soft-reset camif. */
soft_reset_camif();
/* 3. clear all overflow. */
{
u32 ciwdofst;
ciwdofst = ioread32(S3C244X_CIWDOFST);
ciwdofst |= (1<<30)|(1<<15)|(1<<14)|(1<<13)|(1<<12);
iowrite32(ciwdofst, S3C244X_CIWDOFST);
ciwdofst &= ~((1<<30)|(1<<15)|(1<<14)|(1<<13)|(1<<12));
iowrite32(ciwdofst, S3C244X_CIWDOFST);
}
pdev->path = CAMIF_PATH_PREVIEW;
}
/* switch camif from codec path to preview path. */
static void __inline__ camif_p2c(struct s3c2440camif_dev * pdev)
{
/* 1. stop preview. */
{
u32 ciprscctrl;
ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
ciprscctrl &= ~(1<<15); // stop preview scaler.
iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL);
}
/* 2. soft-reset camif. */
soft_reset_camif();
/* 3. clear all overflow. */
{
u32 ciwdofst;
ciwdofst = ioread32(S3C244X_CIWDOFST);
ciwdofst |= (1<<30)|(1<<15)|(1<<14)|(1<<13)|(1<<12);
iowrite32(ciwdofst, S3C244X_CIWDOFST);
ciwdofst &= ~((1<<30)|(1<<15)|(1<<14)|(1<<13)|(1<<12));
iowrite32(ciwdofst, S3C244X_CIWDOFST);
}
pdev->path = CAMIF_PATH_CODEC;
}
/* calculate main burst size and remained burst size. */
static void __inline__ calc_burst_size(u32 pixperword,u32 hSize, u32 *mainBurstSize, u32 *remainedBurstSize)
{
u32 tmp;
tmp = (hSize/pixperword)%16;
switch(tmp)
{
case 0:
*mainBurstSize = 16;
*remainedBurstSize = 16;
break;
case 4:
*mainBurstSize = 16;
*remainedBurstSize = 4;
break;
case 8:
*mainBurstSize=16;
*remainedBurstSize = 8;
break;
default:
tmp=(hSize/pixperword)%8;
switch(tmp)
{
case 0:
*mainBurstSize = 8;
*remainedBurstSize = 8;
break;
case 4:
*mainBurstSize = 8;
*remainedBurstSize = 4;
default:
*mainBurstSize = 4;
tmp = (hSize/pixperword)%4;
*remainedBurstSize = (tmp)?tmp:4;
break;
}
break;
}
}
/* calculate prescaler ratio and shift. */
static void __inline__ calc_prescaler_ratio_shift(u32 SrcSize, u32 DstSize, u32 *ratio, u32 *shift)
{
if(SrcSize>=32*DstSize)
{
*ratio=32;
*shift=5;
}
else if(SrcSize>=16*DstSize)
{
*ratio=16;
*shift=4;
}
else if(SrcSize>=8*DstSize)
{
*ratio=8;
*shift=3;
}
else if(SrcSize>=4*DstSize)
{
*ratio=4;
*shift=2;
}
else if(SrcSize>=2*DstSize)
{
*ratio=2;
*shift=1;
}
else
{
*ratio=1;
*shift=0;
}
}
/* update CISRCFMT only. */
static void __inline__ update_source_fmt_regs(struct s3c2440camif_dev *pdev)
{
u32 cisrcfmt;
cisrcfmt = (1<<31) // ITU-R BT.601 YCbCr 8-bit mode
|(0<<30) // CB,Cr value offset cntrol for YCbCr
|(pdev->srcHsize<<16) // source image width
// |(0<<14) // input order is YCbYCr
// |(1<<14) // input order is YCrYCb
|(2<<14) // input order is CbYCrY
// |(3<<14) // input order is CrYCbY
|(pdev->srcVsize<<0); // source image height
iowrite32(cisrcfmt, S3C244X_CISRCFMT);
}
/* update registers:
* PREVIEW path:
* CIPRCLRSA1 ~ CIPRCLRSA4
* CIPRTRGFMT
* CIPRCTRL
* CIPRSCCTRL
* CIPRTAREA
* CODEC path:
* CICOYSA1 ~ CICOYSA4
* CICOCBSA1 ~ CICOCBSA4
* CICOCRSA1 ~ CICOCRSA4
* CICOTRGFMT
* CICOCTRL
* CICOTAREA
*/
static void __inline__ update_target_fmt_regs(struct s3c2440camif_dev * pdev)
{
u32 ciprtrgfmt, cicotrgfmt = 0;
u32 ciprctrl, cicoctrl;
u32 ciprscctrl, cicoscctrl;
u32 mainBurstSize, remainedBurstSize;
switch(pdev->path) {
case CAMIF_PATH_PREVIEW:
/* CIPRCLRSA1 ~ CIPRCLRSA4. */
iowrite32(img_buff[0].phy_base, S3C244X_CIPRCLRSA1);
iowrite32(img_buff[1].phy_base, S3C244X_CIPRCLRSA2);
iowrite32(img_buff[2].phy_base, S3C244X_CIPRCLRSA3);
iowrite32(img_buff[3].phy_base, S3C244X_CIPRCLRSA4);
/* CIPRTRGFMT. */
ciprtrgfmt = (pdev->preTargetHsize<<16) // horizontal pixel number of target image
|(0<<14) // don't mirror or rotation.
|(pdev->preTargetVsize<<0); // vertical pixel number of target image
iowrite32(ciprtrgfmt, S3C244X_CIPRTRGFMT);
/* CIPRCTRL. */
calc_burst_size(2, pdev->preTargetHsize, &mainBurstSize, &remainedBurstSize);
ciprctrl = (mainBurstSize<<19)|(remainedBurstSize<<14);
iowrite32(ciprctrl, S3C244X_CIPRCTRL);
/* CIPRSCCTRL. */
ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
ciprscctrl &= 1<<15; // clear all other info except 'preview scaler start'.
ciprscctrl |= 0<<30; // 16-bits RGB
iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL); // 16-bit RGB
/* CIPRTAREA. */
iowrite32(pdev->preTargetHsize * pdev->preTargetVsize, S3C244X_CIPRTAREA);
break;
case CAMIF_PATH_CODEC:
/* CICOYSA1 ~ CICOYSA4. */
iowrite32(img_buff[0].phy_base, S3C244X_CICOYSA1);
iowrite32(img_buff[1].phy_base, S3C244X_CICOYSA2);
iowrite32(img_buff[2].phy_base, S3C244X_CICOYSA3);
iowrite32(img_buff[3].phy_base, S3C244X_CICOYSA4);
/* CICOCBSA1 ~ CICOCBSA4. */
iowrite32(img_buff[0].phy_base + (pdev->coTargetHsize * pdev->coTargetVsize), S3C244X_CICOCBSA1);
iowrite32(img_buff[1].phy_base + (pdev->coTargetHsize * pdev->coTargetVsize), S3C244X_CICOCBSA2);
iowrite32(img_buff[2].phy_base + (pdev->coTargetHsize * pdev->coTargetVsize), S3C244X_CICOCBSA3);
iowrite32(img_buff[3].phy_base + (pdev->coTargetHsize * pdev->coTargetVsize), S3C244X_CICOCBSA4);
switch(pdev->pixelformat) {
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YUV422P:
/* CICOCRSA1 ~ CICOCRSA4. */
iowrite32(img_buff[0].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 3 / 2), S3C244X_CICOCRSA1);
iowrite32(img_buff[1].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 3 / 2), S3C244X_CICOCRSA2);
iowrite32(img_buff[2].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 3 / 2), S3C244X_CICOCRSA3);
iowrite32(img_buff[3].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 3 / 2), S3C244X_CICOCRSA4);
cicotrgfmt = (1<<31)|(1<<30); /**/
break;
case V4L2_PIX_FMT_YUV420:
/* CICOCRSA1 ~ CICOCRSA4. */
iowrite32(img_buff[0].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 5 / 4), S3C244X_CICOCRSA1);
iowrite32(img_buff[1].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 5 / 4), S3C244X_CICOCRSA2);
iowrite32(img_buff[2].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 5 / 4), S3C244X_CICOCRSA3);
iowrite32(img_buff[3].phy_base + ((pdev->coTargetHsize * pdev->coTargetVsize) * 5 / 4), S3C244X_CICOCRSA4);
cicotrgfmt = (1<<31); /**/
break;
}
/* CICOTRGFMT. */
cicotrgfmt |= (pdev->coTargetHsize<<16) // horizontal pixel number of target image
|(0<<14) // don't mirror or rotation.
|(pdev->coTargetVsize<<0); // vertical pixel number of target image
iowrite32(cicotrgfmt, S3C244X_CICOTRGFMT);
/* CICOCTRL. */
calc_burst_size(1, pdev->coTargetHsize, &mainBurstSize, &remainedBurstSize); /*y frame*/
cicoctrl = (mainBurstSize<<19)|(remainedBurstSize<<14);
calc_burst_size(1, (pdev->coTargetHsize / 2), &mainBurstSize, &remainedBurstSize); /*CbCr frame*/
cicoctrl |= (mainBurstSize<<9)|(remainedBurstSize<<4);
iowrite32(cicoctrl, S3C244X_CICOCTRL);
/* CICOSCCTRL. */
cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
cicoscctrl &= 1<<15; // clear all other info except 'codec scaler start'.
iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);
/* CICOTAREA. */
iowrite32(pdev->coTargetHsize * pdev->coTargetVsize, S3C244X_CICOTAREA);
break;
}
}
/* update CIWDOFST only. */
static void __inline__ update_target_wnd_regs(struct s3c2440camif_dev * pdev)
{
u32 ciwdofst;
u32 winHorOfst, winVerOfst;
winHorOfst = (pdev->srcHsize - pdev->wndHsize)>>1;
winVerOfst = (pdev->srcVsize - pdev->wndVsize)>>1;
winHorOfst &= 0xFFFFFFF8;
winVerOfst &= 0xFFFFFFF8;
if ((winHorOfst == 0)&&(winVerOfst == 0))
{
ciwdofst = 0; // disable windows offset.
}
else
{
ciwdofst = (1<<31) // window offset enable
|(1<<30) // clear the overflow ind flag of input CODEC FIFO Y
|(winHorOfst<<16) // windows horizontal offset
|(1<<15) // clear the overflow ind flag of input CODEC FIFO Cb
|(1<<14) // clear the overflow ind flag of input CODEC FIFO Cr
|(1<<13) // clear the overflow ind flag of input PREVIEW FIFO Cb
|(1<<12) // clear the overflow ind flag of input PREVIEW FIFO Cr
|(winVerOfst<<0); // window vertical offset
}
iowrite32(ciwdofst, S3C244X_CIWDOFST);
}
/* update registers:
* PREVIEW path:
* CIPRSCPRERATIO
* CIPRSCPREDST
* CIPRSCCTRL
* CODEC path:
* CICOSCPRERATIO
* CICOSCPREDST
* CICOSCCTRL
*/
static void __inline__ update_target_zoom_regs(struct s3c2440camif_dev *pdev)
{
u32 preHratio, preVratio;
u32 coHratio, coVratio;
u32 Hshift, Vshift;
u32 shfactor;
u32 preDstWidth, preDstHeight;
u32 Hscale, Vscale;
u32 mainHratio, mainVratio;
u32 ciprscpreratio, cicoscpreratio;
u32 ciprscpredst, cicoscpredst;
u32 ciprscctrl, cicoscctrl;
switch(pdev->path) {
case CAMIF_PATH_PREVIEW:
/* CIPRSCPRERATIO. */
calc_prescaler_ratio_shift(pdev->srcHsize, pdev->preTargetHsize,
&preHratio, &Hshift);
calc_prescaler_ratio_shift(pdev->srcVsize, pdev->preTargetVsize,
&preVratio, &Vshift);
shfactor = 10 - (Hshift + Vshift);
ciprscpreratio = (shfactor<<28) // shift factor for preview pre-scaler
|(preHratio<<16) // horizontal ratio of preview pre-scaler
|(preVratio<<0); // vertical ratio of preview pre-scaler
iowrite32(ciprscpreratio, S3C244X_CIPRSCPRERATIO);
/* CIPRSCPREDST. */
preDstWidth = pdev->srcHsize / preHratio;
preDstHeight = pdev->srcVsize / preVratio;
ciprscpredst = (preDstWidth<<16) // destination width for preview pre-scaler
|(preDstHeight<<0); // destination height for preview pre-scaler
iowrite32(ciprscpredst, S3C244X_CIPRSCPREDST);
/* CIPRSCCTRL. */
Hscale = (pdev->srcHsize >= pdev->preTargetHsize)?0:1;
Vscale = (pdev->srcVsize >= pdev->preTargetVsize)?0:1;
mainHratio = (pdev->srcHsize<<8)/(pdev->preTargetHsize<
mainVratio = (pdev->srcVsize<<8)/(pdev->preTargetVsize<
ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
ciprscctrl &= ~(1<<30); //keep preview image format RGB565
// ciprscctrl &= (1<<15); //preview scaler start.
ciprscctrl |= (1<<31) // this bit should be always 1.
|(Hscale<<29) // ???, horizontal scale up/down.
|(Vscale<<28) // ???, vertical scale up/down.
|(mainHratio<<16) // horizontal scale ratio for preview main-scaler
|(mainVratio<<0); // vertical scale ratio for preview main-scaler
iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL);
break;
case CAMIF_PATH_CODEC:
/* CICOSCPRERATIO. */
calc_prescaler_ratio_shift(pdev->srcHsize, pdev->coTargetHsize,
&coHratio, &Hshift);
calc_prescaler_ratio_shift(pdev->srcVsize, pdev->coTargetVsize,
&coVratio, &Vshift);
shfactor = 10 - (Hshift + Vshift);
cicoscpreratio = (shfactor<<28) // shift factor for preview pre-scaler
|(coHratio<<16) // horizontal ratio of preview pre-scaler
|(coVratio<<0); // vertical ratio of preview pre-scaler
iowrite32(cicoscpreratio, S3C244X_CICOSCPRERATIO);
/* CICOSCPREDST. */
preDstWidth = pdev->srcHsize / coHratio;
preDstHeight = pdev->srcVsize / coVratio;
cicoscpredst = (preDstWidth<<16) // destination width for preview pre-scaler
|(preDstHeight<<0); // destination height for preview pre-scaler
iowrite32(cicoscpredst, S3C244X_CICOSCPREDST);
/* CICOSCCTRL. */
Hscale = (pdev->srcHsize >= pdev->coTargetHsize)?0:1;
Vscale = (pdev->srcVsize >= pdev->coTargetVsize)?0:1;
mainHratio = (pdev->srcHsize<<8)/(pdev->coTargetHsize<
mainVratio = (pdev->srcVsize<<8)/(pdev->coTargetVsize<
cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
// cicoscctrl &= (1<<15); //codec scaler start.
cicoscctrl |=
(Hscale<<30) // ???, horizontal scale up/down.
|(Vscale<<29) // ???, vertical scale up/down.
|(mainHratio<<16) // horizontal scale ratio for preview main-scaler
|(mainVratio<<0); // vertical scale ratio for preview main-scaler
iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);
break;
}
}
/* update camif registers, called only when camif ready, or ISR. */
static void __inline__ update_camif_regs(struct s3c2440camif_dev * pdev)
{
if (!in_irq())
{
while(1) // wait until VSYNC is 'L'
{
barrier();
if ((ioread32(S3C244X_CICOSTATUS)&(1<<28)) == 0)
break;
}
}
/* WARNING: don't change the statement sort below!!! */
update_source_fmt_regs(pdev);
update_target_wnd_regs(pdev);
update_target_fmt_regs(pdev);
update_target_zoom_regs(pdev);
}
/* start image capture.
*
* param 'stream' means capture pictures streamly or capture only one picture.
*/
static int start_capture(struct s3c2440camif_dev * pdev)
{
int ret;
u32 ciwdofst;
u32 ciprscctrl, cicoscctrl;
u32 ciimgcpt;
if(pdev->path == CAMIF_PATH_NONE)
return 0;
ciwdofst = ioread32(S3C244X_CIWDOFST);
ciwdofst |= (1<<30) // Clear the overflow indication flag of input CODEC FIFO Y
|(1<<15) // Clear the overflow indication flag of input CODEC FIFO Cb
|(1<<14) // Clear the overflow indication flag of input CODEC FIFO Cr
|(1<<13) // Clear the overflow indication flag of input PREVIEW FIFO Cb
|(1<<12); // Clear the overflow indication flag of input PREVIEW FIFO Cr
iowrite32(ciwdofst, S3C244X_CIWDOFST);
switch(pdev->path) {
case CAMIF_PATH_PREVIEW:
//printk("Preview Start...\n");
ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
ciprscctrl |= 1<<15; // preview scaler start
iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL);
ciimgcpt = (1<<31) // camera interface global capture enable
|(1<<29); // capture enable for preview scaler.
iowrite32(ciimgcpt, S3C244X_CIIMGCPT);
pdev->state = CAMIF_STATE_PREVIEWING;
break;
case CAMIF_PATH_CODEC:
//printk("Codec Start...\n");
cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
cicoscctrl |= (1<<15); // codec scaler start
iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);
ciimgcpt = (1<<31) // camera interface global capture enable
|(1<<30); // capture enable for codec scaler.
iowrite32(ciimgcpt, S3C244X_CIIMGCPT);
pdev->state = CAMIF_STATE_CODECING;
break;
}
ret = 0;
#if 0
if (stream == 0)
{
pdev->cmdcode = CAMIF_CMD_STOP;
ret = wait_event_interruptible(pdev->wait, pdev->cmdcode == CAMIF_CMD_NONE);
}
#endif
return ret;
}
/* stop image capture, always called in ISR.
* P-path regs:
* CIPRSCCTRL
* CIPRCTRL
* C-path regs:
* CICOSCCTRL.
* CICOCTRL
* Global regs:
* CIIMGCPT
*/
static void stop_capture(struct s3c2440camif_dev * pdev)
{
u32 ciprscctrl, cicoscctrl;
u32 ciprctrl, cicoctrl;
switch(pdev->state)
{
case CAMIF_STATE_PREVIEWING:
/* CIPRCTRL. */
ciprctrl = ioread32(S3C244X_CIPRCTRL);
ciprctrl |= 1<<2; // enable last IRQ at the end of frame capture.
iowrite32(ciprctrl, S3C244X_CIPRCTRL);
/* CIPRSCCTRL. */
ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
ciprscctrl &= ~(1<<15); // clear preview scaler start bit.
iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL);
break;
case CAMIF_STATE_CODECING:
/* CICOCTRL. */
cicoctrl = ioread32(S3C244X_CICOCTRL);
cicoctrl |= 1<<2; // enable last IRQ at the end of frame capture.
iowrite32(cicoctrl, S3C244X_CICOCTRL);
/* CICOSCCTRL. */
cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
cicoscctrl &= ~(1<<15); // clear codec scaler start bit.
iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);
break;
}
/* CIIMGCPT. */
iowrite32(0, S3C244X_CIIMGCPT);
pdev->state = CAMIF_STATE_READY;
}
/* update camera interface with the new config. */
static void update_camif_config (struct s3c2440camif_dev *pdev, u32 cmdcode)
{
switch(pdev->state)
{
case CAMIF_STATE_READY:
if(cmdcode == CAMIF_CMD_REGS)
{
update_camif_regs(pdev); // config the regs directly.
break;
}
#if 0
/* source image format. */
if (cmdcode & CAMIF_CMD_SFMT)
{
// ignore it, nothing to do now.
}
/* target image format. */
if (cmdcode & CAMIF_CMD_TFMT)
{
/* change target image format only. */
}
/* target image window offset. */
if (cmdcode & CAMIF_CMD_WND)
{
}
/* target image zoomi & zoomout. */
if (cmdcode & CAMIF_CMD_ZOOM)
{
}
#endif
if (cmdcode == CAMIF_CMD_P2C)
{
camif_p2c(pdev);
break;
}
if (cmdcode == CAMIF_CMD_C2P)
{
camif_c2p(pdev);
break;
}
if (cmdcode == CAMIF_CMD_START)
{
start_capture(pdev);
}
break;
case CAMIF_STATE_PREVIEWING:
/* camif is previewing image. */
disable_irq(IRQ_S3C2440_CAM_P); // disable cam-preview irq.
/* stop previewing. */
if (cmdcode & CAMIF_CMD_STOP)
{
pdev->cmdcode |= CAMIF_CMD_STOP;
}
enable_irq(IRQ_S3C2440_CAM_P); // enable cam-preview irq.
wait_event(pdev->wait, (pdev->cmdcode==CAMIF_CMD_NONE)); // wait until the ISR completes command.
break;
case CAMIF_STATE_CODECING:
/* camif is previewing image. */
disable_irq(IRQ_S3C2440_CAM_C); // disable cam-codec irq.
/* stop previewing. */
if (cmdcode & CAMIF_CMD_STOP)
{
pdev->cmdcode |= CAMIF_CMD_STOP;
}
enable_irq(IRQ_S3C2440_CAM_C); // enable cam-codec irq.
wait_event(pdev->wait, (pdev->cmdcode==CAMIF_CMD_NONE)); // wait until the ISR completes command.
break;
default:
break;
}
}
static void __inline__ invalid_image_buffer(void)
{
img_buff[0].state = CAMIF_BUFF_INVALID;
img_buff[1].state = CAMIF_BUFF_INVALID;
img_buff[2].state = CAMIF_BUFF_INVALID;
img_buff[3].state = CAMIF_BUFF_INVALID;
}
/* init image buffer (only when the camif is first open). */
static int __inline__ init_image_buffer(struct s3c2440camif_dev *pdev)
{
int size1, size2;
unsigned long size = 0;
unsigned int order = 0;
/* size1 is the max image size of codec path. */
size1 = MAX_C_WIDTH * MAX_C_HEIGHT * 2;
/* size2 is the max image size of preview path. */
size2 = MAX_P_WIDTH * MAX_P_HEIGHT * 2;
size = (size1 > size2) ? size1 : size2;
printk("dma_alloc_coherent <0> size : 0x%08x\n", size);
order = get_order(size);
img_buff[0].order = order;
img_buff[0].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[0].order);
if (img_buff[0].virt_base == (unsigned long)NULL)
{
goto error0;
}
img_buff[0].img_size = size;
img_buff[0].phy_base = img_buff[0].virt_base - PAGE_OFFSET + PHYS_OFFSET; // the DMA address.
img_buff[0].offset = 0;
printk("dma_alloc_coherent <1> size : 0x%08x\n", size);
img_buff[1].order = order;
img_buff[1].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[1].order);
if (img_buff[1].virt_base == (unsigned long)NULL)
{
goto error1;
}
img_buff[1].img_size = size;
img_buff[1].phy_base = img_buff[1].virt_base - PAGE_OFFSET + PHYS_OFFSET; // the DMA address.
img_buff[1].offset = PAGE_SIZE << order;
printk("dma_alloc_coherent <2> size : 0x%08x\n", size);
img_buff[2].order = order;
img_buff[2].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[2].order);
if (img_buff[2].virt_base == (unsigned long)NULL)
{
goto error2;
}
img_buff[2].img_size = size;
img_buff[2].phy_base = img_buff[2].virt_base - PAGE_OFFSET + PHYS_OFFSET; // the DMA address.
img_buff[2].offset = (PAGE_SIZE << order) * 2;
printk("dma_alloc_coherent <3> size : 0x%08x\n", size);
img_buff[3].order = order;
img_buff[3].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[3].order);
if (img_buff[3].virt_base == (unsigned long)NULL)
{
goto error3;
}
img_buff[3].img_size = size;
img_buff[3].phy_base = img_buff[3].virt_base - PAGE_OFFSET + PHYS_OFFSET; // the DMA address.
img_buff[3].offset = (PAGE_SIZE << order) * 3;
invalid_image_buffer();
return 0;
error3:
free_pages(img_buff[2].virt_base, order);
img_buff[2].phy_base = (unsigned long)NULL;
error2:
free_pages(img_buff[1].virt_base, order);
img_buff[1].phy_base = (unsigned long)NULL;
error1:
free_pages(img_buff[0].virt_base, order);
img_buff[0].phy_base = (unsigned long)NULL;
error0:
return -ENOMEM;
}
/* free image buffers (only when the camif is latest close). */
static void __inline__ free_image_buffer(struct s3c2440camif_dev *pdev)
{
free_pages(img_buff[0].virt_base, img_buff[0].order);
free_pages(img_buff[1].virt_base, img_buff[1].order);
free_pages(img_buff[2].virt_base, img_buff[2].order);
free_pages(img_buff[3].virt_base, img_buff[3].order);
img_buff[0].order = 0;
img_buff[0].virt_base = (unsigned long)NULL;
img_buff[0].phy_base = (unsigned long)NULL;
img_buff[0].offset = 0;
img_buff[1].order = 0;
img_buff[1].virt_base = (unsigned long)NULL;
img_buff[1].phy_base = (unsigned long)NULL;
img_buff[1].offset = 0;
img_buff[2].order = 0;
img_buff[2].virt_base = (unsigned long)NULL;
img_buff[2].phy_base = (unsigned long)NULL;
img_buff[2].offset = 0;
img_buff[3].order = 0;
img_buff[3].virt_base = (unsigned long)NULL;
img_buff[3].phy_base = (unsigned long)NULL;
img_buff[3].offset = 0;
}
static void __inline__ update_image_buffer(struct s3c2440camif_dev *pdev)
{
unsigned long size = 0;
switch(pdev->pixelformat) {
case V4L2_PIX_FMT_RGB565:
size = pdev->preTargetHsize * pdev->preTargetVsize * 2;
訂閱:
文章 (Atom)