This is just a place where I scribble my exciting experience of Linux kernel with naughty hardwares
Tuesday, December 28, 2010
Android kernel additions
Here is a good link which talks about the difference between android kernel and mainline kernel.
How to participate in linux Community
Here is a good document written by Jonathan corbet in linux foundation. The document explains pretty well how the community works. Its a must read for those who are interested in sending patches upstream.
Monday, December 27, 2010
OLED Organic Light Emiting Diodes
Organic in OLED means Organic material. Carbon is the basis of all organic material.
Advantages:
Fast response time.
Wide view angle due to the thin layers used.
Low power consumption.
Outstanding contrast levels.
For more info, OLED diplay.net
How stuff works
Friday, December 24, 2010
Regulator frame work in linux
Version : 2.6.35
You can read a presentation from Liam at free electrons.
Good documentation is there in Linux kernel DOCUMENTATION folder also. (Documentation/power/regulator/)
Problem:
Before enabling the regulator driver in linux kernel, I m able to get the sendend interrupts. But after enabling the regulator driver, not getting the interrupts.
Reason:
There is a call in my board file like,
regulator_has_full_constraints();
Here is the explanation given in drivers/regulators/core.c
/**
* regulator_has_full_constraints - the system has fully specified constraints
*
* Calling this function will cause the regulator API to disable all
* regulators which have a zero use count and don't have an always_on
* constraint in a late_initcall.
*
* The intention is that this will become the default behaviour in a
* future kernel release so users are encouraged to use this facility
* now.
*/
So this was switching off one LDO down which is used by a comparator to detect the send end interrupts. So commented out that function from the board file till power management becomes important. :-)
Monday, December 13, 2010
Trace 32
Trace 32 is an amazing tool for run time intrusive debugging. It has a good support for Linux also. To see the register dumps, where 0xFA50_0000 is the physical register address.
d.dump 0xFA500000
The above access is through processor. For that you need to stop the processor. If you want to access the registers while processor running, you have to access through DAP(Debug Acces Port). Here is the command,
d.dump EDAP:0xFA500000
To save contents to a file,
For eg save data in RAM from 0x96000000 to 0x96004000,
data.save.binary c:\D_drive\file.bin 0x96000000--0x96004000
or to save 1MB from 0x96900000,
data.save.binary c:\D_drive\ptms\notwrapped.bin 0x96900000++0x100000
similarly, to save using EDAP,
data.save.binary c:\D_drive\ptms\notwrapped.bin EDAP:0x96900000++0x100000
You must be thinking now why am I reading through EDAP. what's the difference. Consider the following scenario.
1. memset RAM address from 0x96000000(This will create cache entries for this region)
2. Now this memory is over written by a hardware eg:dma
3. Now if you try to access the RAM through processor, there is a high probabilty that you will see the old value in RAM(the one which you write with memset) and not the updated value written by hardware(eg dma). This is because of cache. When JTAG access through processor if there is a cache hit, it give the value in the cache.
So in these scenarios we have to access through DAP.
To draw the image at frame buffer ram address 0x4f80_0000 with RGB888 format
d.IMAGE a:0x4f800000 480. 992. /RGBX888
Type sys, you will get the window for attach option. Saving page layout, Windows->Store windows to. This will store the windows open as .cmm file. Next time when you want this windows, run the saved cmm file. To add the source, View-> Symbols->Source search path->Add dir To get online help, Type the command on the command line, leave a space blank and press F1. To take Register Dumps us the following scripts,
=======================
printer.filetype ascii
printer.open dump.txt
wp.d a:0xe0100000--a:0xe010700c /WIDTH 4
printer.close
=========================
For loading vmlinux:
data.load.elf Z:\projects\mobcom_andrwks_ext8\users\arunks\common-android\kernel\hawaii\3.4.5\vmlinux /nocode /noclear
NoClear: Existing symbols are not deleted. This option is necessary if more programs
must be loaded (Tasks, Overlays, Banking).
NoCODE: Suppress the code download. Only loads symbolic information.
More info
For loading a binary,
data.load.binary filename A:RamStart--A:RamEnd /noclear
For typcasting any memory:
For eg task_struct,
var.view (struct task_struct*)0xc094d8f0
To view stack frame:
var.frame /core 0
To disassemble a location,
data.list
STRIPPART
===========
Sometimes T32 might complain saying cannot find the path to file, when you try to map to source code.
Lets say for example,
"Z:\projects\mobcom\users\arunks\eos\br-eos-4.4-2b\android\kernel\init\main.c cannot find"
Our source is at location Y:\br-eos-4.4-2b\android\kernel\init\main.c
So our source path is different till br-eos-4.4-2b, so we need to strip till there,
ie 6 elements. so the command is
d.load.elf Y:\br-eos-4.4-2b\vmlinux /nocode /StripPART 6 /PATH Y:\br-eos-4.4-2b
Use command "symbol.list.source" to easily find out how many patch to strip. Before this command you have to load elf without any /Strippart argument.
Sometimes vmlinux might get compiled in different folder, another way of doing it is copy the vmlinux to the kernel source folder. Then load from there and strip using /strippart
CO-Processor registers
=================
http://www2.lauterbach.com/pdf/debugger_arm.pdf
page 32
For all Lauterbach T32 Manual, vist here.
d.dump 0xFA500000
The above access is through processor. For that you need to stop the processor. If you want to access the registers while processor running, you have to access through DAP(Debug Acces Port). Here is the command,
d.dump EDAP:0xFA500000
To save contents to a file,
For eg save data in RAM from 0x96000000 to 0x96004000,
data.save.binary c:\D_drive\file.bin 0x96000000--0x96004000
or to save 1MB from 0x96900000,
data.save.binary c:\D_drive\ptms\notwrapped.bin 0x96900000++0x100000
similarly, to save using EDAP,
data.save.binary c:\D_drive\ptms\notwrapped.bin EDAP:0x96900000++0x100000
You must be thinking now why am I reading through EDAP. what's the difference. Consider the following scenario.
1. memset RAM address from 0x96000000(This will create cache entries for this region)
2. Now this memory is over written by a hardware eg:dma
3. Now if you try to access the RAM through processor, there is a high probabilty that you will see the old value in RAM(the one which you write with memset) and not the updated value written by hardware(eg dma). This is because of cache. When JTAG access through processor if there is a cache hit, it give the value in the cache.
So in these scenarios we have to access through DAP.
To draw the image at frame buffer ram address 0x4f80_0000 with RGB888 format
d.IMAGE a:0x4f800000 480. 992. /RGBX888
Type sys, you will get the window for attach option. Saving page layout, Windows->Store windows to. This will store the windows open as .cmm file. Next time when you want this windows, run the saved cmm file. To add the source, View-> Symbols->Source search path->Add dir To get online help, Type the command on the command line, leave a space blank and press F1. To take Register Dumps us the following scripts,
=======================
printer.filetype ascii
printer.open dump.txt
wp.d a:0xe0100000--a:0xe010700c /WIDTH 4
printer.close
=========================
For loading vmlinux:
data.load.elf Z:\projects\mobcom_andrwks_ext8\users\arunks\common-android\kernel\hawaii\3.4.5\vmlinux /nocode /noclear
NoClear: Existing symbols are not deleted. This option is necessary if more programs
must be loaded (Tasks, Overlays, Banking).
NoCODE: Suppress the code download. Only loads symbolic information.
More info
For loading a binary,
data.load.binary filename A:RamStart--A:RamEnd /noclear
For typcasting any memory:
For eg task_struct,
var.view (struct task_struct*)0xc094d8f0
To view stack frame:
var.frame /core 0
To disassemble a location,
data.list
STRIPPART
===========
Sometimes T32 might complain saying cannot find the path to file, when you try to map to source code.
Lets say for example,
"Z:\projects\mobcom\users\arunks\eos\br-eos-4.4-2b\android\kernel\init\main.c cannot find"
Our source is at location Y:\br-eos-4.4-2b\android\kernel\init\main.c
So our source path is different till br-eos-4.4-2b, so we need to strip till there,
ie 6 elements. so the command is
d.load.elf Y:\br-eos-4.4-2b\vmlinux /nocode /StripPART 6 /PATH Y:\br-eos-4.4-2b
Use command "symbol.list.source" to easily find out how many patch to strip. Before this command you have to load elf without any /Strippart argument.
Sometimes vmlinux might get compiled in different folder, another way of doing it is copy the vmlinux to the kernel source folder. Then load from there and strip using /strippart
Data.LOAD.elf
Z:\autotrees\LA.HB.1.1.5_RB1.07.00.00.310.033\kernel\msm-4.4\vmlinux /stripPart
"/local/mnt/workspace/autotrees/LA.HB.1.1.5_RB1.07.00.00.310.033/kernel/msm-4.4"
/nocode /gnu
CO-Processor registers
=================
http://www2.lauterbach.com/pdf/debugger_arm.pdf
page 32
For all Lauterbach T32 Manual, vist here.
Thursday, December 9, 2010
MIPI display pannel
When I was introduced to the project the display was not at all working. We were doing the porting of Froyo kernel(2.6.32) for garnett phone.
Let me first describe how a MIPI pannel driver works. Mobile Industry Processor Interface(MIPI) alliance is about setting up a standard for interfacing the processor with different peripherals. Our concern in this context is about Display Interface. The Display Serial Interface defines protocol between processor and peripheral device using a D-PHY physical interface. It is build by adopting pixel format and command set specified in DPI-2(Display Parallel Interface) and DCS standards. DSI serializes all pixel data, command and events. The legacy interfaces convey the data and control to and from from the peripheral on a parallel bus. The unavoidable consequence of this transformation is the increased latency. But the D-PHY solution brings out the very low power consumption.
The practical data rate per lane is <1Gb/s.
Min no of pins per direction 4.
So that's it about the DSI interface.
Now on the Garnet phone, which uses the Sam-sung Humming bird processor(C110) has 3-D accelerator. There is a separate driver for this hardware accelerator. In our display driver we will allocate the memory for the frame buffer and pass it to the hardware accelerator driver. It will decode the frames and place it in the frame buffer memory. From Frame buffer memory, the DSIM(Display serial interface Module) implements the DSI protocol for sending data to the lcd panel. The lcd panel used was an AMOLED.
The LCD panel interrupts the processor whenever it is ready to receive a new frame. So initially this gpio pin was not configured properly. After fixing this display started working after booting up. But boot animation was not showing.
The code base for Garnett is taken from the galaxy S phone. Later we found out from some status register that the DSIM controller is going in to ULPS(Ultra Low Power State). On Samsung galaxy, usb OTG uses a LDO3 for USB_V1.1 voltage supply. But on Garnett, this LDO is shared between USV_V1.1 and MIPI_PowerEN. Unluckily usb code was disabling the LDO3 during boot-up.
But still display didn't leave me. The problem becomes like this now. Some times boot animation is not coming. Hmm... What to do... Have to continue hunting... I dumped all the registers of the C110 processor(clock, DSIM, video controllor registers) using JTAG. Everything seems fine. Then checked the gpio mux settings. No issues there also. Cannot find direction to move ahead. At the end, problem was due to frame buffer probe is called before the regulator framework is initialized. During the regulator initialization he reset the chip and enables all the voltage again. So sometimes the LCD panel is going into invalid state.
So good lesson learned. Even if the boot loader initialize the regulators or not, we have to bring regulator up and stabilize all the voltages before initializing any of the peripherals. Dammn it!!!!. Thought of doing this first but didn't contemplate on this much.
Let me first describe how a MIPI pannel driver works. Mobile Industry Processor Interface(MIPI) alliance is about setting up a standard for interfacing the processor with different peripherals. Our concern in this context is about Display Interface. The Display Serial Interface defines protocol between processor and peripheral device using a D-PHY physical interface. It is build by adopting pixel format and command set specified in DPI-2(Display Parallel Interface) and DCS standards. DSI serializes all pixel data, command and events. The legacy interfaces convey the data and control to and from from the peripheral on a parallel bus. The unavoidable consequence of this transformation is the increased latency. But the D-PHY solution brings out the very low power consumption.
The practical data rate per lane is <1Gb/s.
Min no of pins per direction 4.
So that's it about the DSI interface.
Now on the Garnet phone, which uses the Sam-sung Humming bird processor(C110) has 3-D accelerator. There is a separate driver for this hardware accelerator. In our display driver we will allocate the memory for the frame buffer and pass it to the hardware accelerator driver. It will decode the frames and place it in the frame buffer memory. From Frame buffer memory, the DSIM(Display serial interface Module) implements the DSI protocol for sending data to the lcd panel. The lcd panel used was an AMOLED.
The LCD panel interrupts the processor whenever it is ready to receive a new frame. So initially this gpio pin was not configured properly. After fixing this display started working after booting up. But boot animation was not showing.
The code base for Garnett is taken from the galaxy S phone. Later we found out from some status register that the DSIM controller is going in to ULPS(Ultra Low Power State). On Samsung galaxy, usb OTG uses a LDO3 for USB_V1.1 voltage supply. But on Garnett, this LDO is shared between USV_V1.1 and MIPI_PowerEN. Unluckily usb code was disabling the LDO3 during boot-up.
But still display didn't leave me. The problem becomes like this now. Some times boot animation is not coming. Hmm... What to do... Have to continue hunting... I dumped all the registers of the C110 processor(clock, DSIM, video controllor registers) using JTAG. Everything seems fine. Then checked the gpio mux settings. No issues there also. Cannot find direction to move ahead. At the end, problem was due to frame buffer probe is called before the regulator framework is initialized. During the regulator initialization he reset the chip and enables all the voltage again. So sometimes the LCD panel is going into invalid state.
So good lesson learned. Even if the boot loader initialize the regulators or not, we have to bring regulator up and stabilize all the voltages before initializing any of the peripherals. Dammn it!!!!. Thought of doing this first but didn't contemplate on this much.
Wednesday, December 8, 2010
Some Common Questions?
1) What is unaligned memory access?
Definition:
Definition:
Unaligned memory accesses occur when you try to read N bytes of
data starting from an address that is not evenly divisible by N
(i.e. addr % N != 0). For example, reading 4 bytes of data
from address 0x10004 is fine, but reading 4 bytes of data from
address 0x10005 would be an unaligned memory access.
Fortunately things are not too complex, as in most cases, the
compiler ensures that things will work for you.
For more reading,
http://lwn.net/Articles/260456/
Thursday, December 2, 2010
A moment of pride
This is really a moment of pride for me. My driver is going upstream mainline Linux kernel.
Here it goes, the mail from Takashi Iwai to Linus Torvalds requesting to pull the driver,
One of my dreams comes true... Aha.....
I love Linux kernel. The way it works... During initial days of my career I used to ask many questions in the mailing list. I was amazed with the support and patience they posses. So I decided one day I will give something back to the community.
Contributions
Arun
Here it goes, the mail from Takashi Iwai to Linus Torvalds requesting to pull the driver,
One of my dreams comes true... Aha.....
I love Linux kernel. The way it works... During initial days of my career I used to ask many questions in the mailing list. I was amazed with the support and patience they posses. So I decided one day I will give something back to the community.
Contributions
Arun
Thursday, November 18, 2010
Minimal git commands
Initialize a repository by,
git init
Add files to the repo by,
git add .
git add file
removal,
git rm file
rename,
git mv old new
This will add all the file under the directory recursively.
Now do a base commit,
git commit -a
This will commit all the files to the repository .
To create a new branch for editing,
git checkout -b devel
Commit only required changes
If you have many changes, for example in folders like drivers/video and drivers/sound. And you only want to commit the changes to drivers/video, then git add those files and type git commit without using -a option.
git add drivers/video/
git commit
If your master has grown beyond the point when you took the devel branch, you can update the master and you can rebase the devel branch to master,
git rebase -i master
Have a look here for more doubts about merging issues.
http://stackoverflow.com/questions/449541/how-do-you-merge-selective-files-with-git-merge
configuring the .gitconfig file,
My .gitconfig file looks like this
cat ~/.gitconfig
[user]
name = "Arun Sudhilal"
email = "arun.sudhilal@lntinfotech.com"
[core]
editor = vim
[color]
ui = auto
[merge]
tool = vimdiff
Creating patches,
git format-patch HEAD~1
HEAD^^ == HEAD~2
---
git show
git show --stat
git show --name-status HEAD~3
git show HEAD:file
contents.....
git log
git log HEAD~10..
git log --author=arun
git log --committer=arun
git log --grep="commit.*message.*text"
For expample if i want to grep "frame", then
git log --grep="grame"
git log -S "some code change"
git log file
git grep -e "pattern" -- some/file
git branch name commit
git checkout name
git checkout -b name commit
git checkout -m name
merge outstanding diff onto branch "name", can result in conflict.
git tag -a -m "got somewhere" good
git rebase
moves new work to a new base line
git fetch
Just update the remote, but doesn't update work space
git fetch + git merge = git pull
to apply a patch in you local tree,
git am -3
Pushing to the repositories,
* git push origin will push changes from all local branches to matching branches the origin remote
* git push origin master will push changes from the local master branch to the remote master branch
* git push origin master:staginwill push changes from the local master branch to the remote staging branch if it exists
Recovering lost commits,Sometime by mistake you might have done git reset --hard HEAD^. Then you realise that you need that commit. Dont worry, git has a way to recover your lost commit.
git reflog
Git tracks almost everything you does. If you feels that you have screwed up you repo by rebase, merge or even by reset, you can dig reflog and get it back.
git reflog output may be something like this,
6d2a85e HEAD@{0}: merge 6d2a85e: Fast-forward
28eb495 HEAD@{1}: 28eb49561313ce479f228acea6d25a2bf20166a8: updating HEAD
6d2a85e HEAD@{2}: pull : Fast-forward
6744afe HEAD@{3}: 6744afe5afa033763cdb4e698eea1a5febabae8e: updating HEAD
once you get this you can check with git show which commit you want. For here you can cherry-pic, merge or checkout.
.gitconfig
And this is how my .gitconfig looks like,
Renaming current branch,
git branch -m linux-linaro-tracking
Checkout with the same name as remote,
git co -t remotes/origin/linux-linaro
Suwon, S Korea
git init
Add files to the repo by,
git add .
git add file
removal,
git rm file
rename,
git mv old new
This will add all the file under the directory recursively.
Now do a base commit,
git commit -a
This will commit all the files to the repository .
To create a new branch for editing,
git checkout -b devel
Commit only required changes
If you have many changes, for example in folders like drivers/video and drivers/sound. And you only want to commit the changes to drivers/video, then git add those files and type git commit without using -a option.
git add drivers/video/
git commit
If your master has grown beyond the point when you took the devel branch, you can update the master and you can rebase the devel branch to master,
git rebase -i master
Have a look here for more doubts about merging issues.
http://stackoverflow.com/questions/449541/how-do-you-merge-selective-files-with-git-merge
My .gitconfig file looks like this
cat ~/.gitconfig
[user]
name = "Arun Sudhilal"
email = "arun.sudhilal@lntinfotech.com"
[core]
editor = vim
[color]
ui = auto
[merge]
tool = vimdiff
Creating patches,
git format-patch HEAD~1
HEAD^^ == HEAD~2
---
git show
git show --stat
git show --name-status HEAD~3
git show HEAD:file
contents.....
git log
git log HEAD~10..
git log --author=arun
git log --committer=arun
git log --grep="commit.*message.*text"
For expample if i want to grep "frame", then
git log --grep="grame"
git log -S "some code change"
git log file
git grep -e "pattern" -- some/file
git branch name commit
git checkout name
git checkout -b name commit
git checkout -m name
merge outstanding diff onto branch "name", can result in conflict.
git tag -a -m "got somewhere" good
git rebase
moves new work to a new base line
git fetch
Just update the remote, but doesn't update work space
git fetch + git merge = git pull
to apply a patch in you local tree,
git am -3
Pushing to the repositories,
* git push origin will push changes from all local branches to matching branches the origin remote
* git push origin master will push changes from the local master branch to the remote master branch
* git push origin master:staginwill push changes from the local master branch to the remote staging branch if it exists
Recovering lost commits,Sometime by mistake you might have done git reset --hard HEAD^. Then you realise that you need that commit. Dont worry, git has a way to recover your lost commit.
git reflog
Git tracks almost everything you does. If you feels that you have screwed up you repo by rebase, merge or even by reset, you can dig reflog and get it back.
git reflog output may be something like this,
6d2a85e HEAD@{0}: merge 6d2a85e: Fast-forward
28eb495 HEAD@{1}: 28eb49561313ce479f228acea6d25a2bf20166a8: updating HEAD
6d2a85e HEAD@{2}: pull : Fast-forward
6744afe HEAD@{3}: 6744afe5afa033763cdb4e698eea1a5febabae8e: updating HEAD
once you get this you can check with git show which commit you want. For here you can cherry-pic, merge or checkout.
Suwon, S Korea
Monday, November 8, 2010
Touch doesnt work in lock screen after resuming from sleep
In file drivers/i2c/busses/i2c-s3c2410.c, function,
static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
{
unsigned long iicstat;
int timeout = 400;
while (timeout-- > 0) {
iicstat = readl(i2c->regs + S3C2410_IICSTAT);
if (!(iicstat & S3C2410_IICSTAT_BUSBUSY))
return 0;
msleep(1);
}
return -ETIMEDOUT;
}
Some how the bus is busy even after 400 iterations. The i2c adaptor may be going to some invalid state. Added,
writel(iicstat & ~S3C2410_IICSTAT_TXRXEN, i2c->regs + S3C2410_IICSTAT);
after the msleep(1). This will disable the Rx/Tx of the i2c adapter, which is later enabled. So basically its a reset of the register
I2C-bus data output enable/ disable bit.
0 = Disables Rx/Tx,
1 = Enables Rx/Tx
This blog looks interesting about the i2c drive in linux-2.6.32
http://www.embedded-bits.co.uk/?p=174
static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
{
unsigned long iicstat;
int timeout = 400;
while (timeout-- > 0) {
iicstat = readl(i2c->regs + S3C2410_IICSTAT);
if (!(iicstat & S3C2410_IICSTAT_BUSBUSY))
return 0;
msleep(1);
}
return -ETIMEDOUT;
}
Some how the bus is busy even after 400 iterations. The i2c adaptor may be going to some invalid state. Added,
writel(iicstat & ~S3C2410_IICSTAT_TXRXEN, i2c->regs + S3C2410_IICSTAT);
after the msleep(1). This will disable the Rx/Tx of the i2c adapter, which is later enabled. So basically its a reset of the register
I2C-bus data output enable/ disable bit.
0 = Disables Rx/Tx,
1 = Enables Rx/Tx
This blog looks interesting about the i2c drive in linux-2.6.32
http://www.embedded-bits.co.uk/?p=174
Saturday, November 6, 2010
wakeup from suspend to Ram
echo mem > /sys/power/state should suspend to ram and
echo on > /sys/power/state should wake up the device from suspend.
Former was not working on Atlas phone. It was because the read from /sys/power/state was not implemented properly. When you try to read it should print all the valid power states. But it was only giving mem as the output. In file kernel/power/main.c, function state_show calls valid_states which in turn calls a architecture implemented function pointer. The function is called by passing mem, on or standby as the argument. It will return true if it architecture support the argument state. So state_show will give out put accordingly.
Previously it was giving true only for mem. Modified the .valid function pointer in the architecutre file (arch/arm/plat-samsung/pm.c) to give true for mem, on and standby. This fixed the wakeup issue.
Got some help from,
Linux Symposium
echo on > /sys/power/state should wake up the device from suspend.
Former was not working on Atlas phone. It was because the read from /sys/power/state was not implemented properly. When you try to read it should print all the valid power states. But it was only giving mem as the output. In file kernel/power/main.c, function state_show calls valid_states which in turn calls a architecture implemented function pointer. The function is called by passing mem, on or standby as the argument. It will return true if it architecture support the argument state. So state_show will give out put accordingly.
Previously it was giving true only for mem. Modified the .valid function pointer in the architecutre file (arch/arm/plat-samsung/pm.c) to give true for mem, on and standby. This fixed the wakeup issue.
Got some help from,
Linux Symposium
Monday, October 18, 2010
Adding send end key as a wake-up source
On MSM chip there are three Interrupt controllers. One for ARM11, one for ARM9 and one dedicated Interrupt controller(Simple Interrupt Controller(SIC), this is always on) to work when both processors sleep. So before ARM11 sleeps we have to send the wake-up irqs to CP. So that MPP IC will monitors only those wake-up interrupts send by AP. This is achieved by using the kernel function enalbe_irq_wake(irq no). This will add the flag IRQ_WAKE to that descriptor of that particular irq. So whenever AP go to sleep it will send this irq number also to the CP as a wake-up soruce.
Tuesday, September 14, 2010
Problem with udelay
I was working on a mobile device, reducing lcd wake up time once powerkey is pressed. In LCD driver there were many msleeps() used in the kernel. There is some structure like this.
Struct lcd_startup_sequence {
U16 cmd;
U16 timeout;/*in ms*/
}
lcd_startup_sequence[10] = {
{0x34, 100},
{0x23, 0},
{0x14, 0},
{0x11, 50},
};
What i did first is this,
if(lcd_starup_sequence.delay)
msleep(lcd_startup_swquence.delay);
So this will avoids the calls from msleep(0); Because even if msleep is called with 0 as the argument, the current thread will be kept on the wait queue from the running queue.
But from this I haven't got much improvement. So I thought of changing msleep() to mdelay(). So it takes the correct time, because it is busy waiting than sleeping. But you should be very careful in using mdelay() because you are just eating up the processor time. So if not necessary use msleep() instead. This give me good improvement.
The funny part is that in another place also I changed from msleep(100) to mdelay(100). Surprisingly here mdelay is taking around 200 ms and msleep is taking 110 ms. What the heck?
Then I digged in the kernel and found plenty of information about kernel time keeping. The following link explaing how the delay is generated in linux kernel:
http://kerneltrap.org/node/6857
But the reason for mdelay behavior is explained below:
udelay() can be incorrect on SMP machines that scale their CPU frequencies independently of one another he delay loop can either be too fast or too slow depending on which CPU the loops_per_jiffy counter is calibrated on and which CPU the delay loop is running on. udelay() can also be incorrect if the CPU frequency switches during the __delay() loop, causing the loop
to either terminate too early, or too late.
For more informations:
http://www.spinics.net/lists/linux-arm-msm/msg00208.html
http://groups.google.co.kr/group/linux.kernel/browse_thread/thread/0a5c1395e82eabc2?pli=1
Struct lcd_startup_sequence {
U16 cmd;
U16 timeout;/*in ms*/
}
lcd_startup_sequence[10] = {
{0x34, 100},
{0x23, 0},
{0x14, 0},
{0x11, 50},
};
What i did first is this,
if(lcd_starup_sequence.delay)
msleep(lcd_startup_swquence.delay);
So this will avoids the calls from msleep(0); Because even if msleep is called with 0 as the argument, the current thread will be kept on the wait queue from the running queue.
But from this I haven't got much improvement. So I thought of changing msleep() to mdelay(). So it takes the correct time, because it is busy waiting than sleeping. But you should be very careful in using mdelay() because you are just eating up the processor time. So if not necessary use msleep() instead. This give me good improvement.
The funny part is that in another place also I changed from msleep(100) to mdelay(100). Surprisingly here mdelay is taking around 200 ms and msleep is taking 110 ms. What the heck?
Then I digged in the kernel and found plenty of information about kernel time keeping. The following link explaing how the delay is generated in linux kernel:
http://kerneltrap.org/node/6857
But the reason for mdelay behavior is explained below:
udelay() can be incorrect on SMP machines that scale their CPU frequencies independently of one another he delay loop can either be too fast or too slow depending on which CPU the loops_per_jiffy counter is calibrated on and which CPU the delay loop is running on. udelay() can also be incorrect if the CPU frequency switches during the __delay() loop, causing the loop
to either terminate too early, or too late.
For more informations:
http://www.spinics.net/lists/linux-arm-msm/msg00208.html
http://groups.google.co.kr/group/linux.kernel/browse_thread/thread/0a5c1395e82eabc2?pli=1
Monday, August 23, 2010
Samsung work
1) Headset and send-end key driver.
The mobile runs on Qualcomm MSM7627. This is a having two ARM core, two DSP core. There is one ARM11 which is called as Application Processor(AP) on which linux runs. And there is ARM9 which is called Modem Processor(some times called Communication Processor CP) on which REX OS is running. Here CP is the master. Both communicates through Shared memory driver IPC. Whoever want to communicate will place the corresponding COMMAND and data and interrupt the other processor. Send end key is the the switch on the headset to send the key-press events to the application to for disconnecting the call or going to next track in music player. This is implemented as an input device. The driver mechanism is like this.
Headset detection is done on Modem. There is a IPC callback mechanism registered in RIL layer(on AP side) in application space for getting the status change of the headset. So once headset is inserted or remove, modem will pass this information through IPC. The callback in the mode side will write 1 or 0 for headset inserted and headset removed respectively to a sysfs entry(/sys/class/switch/h2w/headset) exported by the headset driver in the AP side. So once the headset is detected we will enable the send-end key interrupt which is done on the AP side. This is implemented on a gpio. Since due to noise created during the headset insertion, lot of spurious interrupts(send end key) where coming. So we enable the send-end key only after 100ms after the headset insertion. This is implemented by using delayed work-queue.
2) Firmware up-gradation on Touch screen.
The touch screen driver is from Melfas. The I2C is implemented using the i2c-gpio driver. This is a kernel driver which manipulates the gpio to implement the I2C protocol. We have to pass the gpios for sda and scl during the initialization of the driver.
some notes about this driver
=======================
This is a very simple bitbanging i2c bus driver utilizing the new
arch-neutral GPIO API. Useful for chips that don't have a built-in
i2c controller, additional i2c busses, or testing purposes.
To use, include something similar to the following in the
board-specific setup code:
#include
static struct i2c_gpio_platform_data i2c_gpio_data = {
.sda_pin = GPIO_PIN_FOO,
.scl_pin = GPIO_PIN_BAR,
};
static struct platform_device i2c_gpio_device = {
.name = "i2c-gpio",
.id = 0,
.dev = {
.platform_data = &i2c_gpio_data,
},
};
Register this platform_device, set up the i2c pins as GPIO if required and you're ready to go. This will use default values for udelay and timeout, and will work with GPIO hardware that does not support open drain mode, but allows changing the direction of the SDA i2c_gpio_device.id is the I2C adapter number i2c_gpio_platform_data has more members to define the pin is
struct i2c_gpio_platform_data {
unsigned int sda_pin;
unsigned int scl_pin;
/*signal toggle delay. SCL frequency is (500 / udelay) kHz*/
int udelay;
/*timeout: clock stretching timeout in jiffies. If the slave keeps
SCL low for longer than this, the transfer will time out.*/
int timeout;
unsigned int sda_is_open_drain:1;
unsigned int scl_is_open_drain:1;
unsigned int scl_is_output_only:1;
}
=============================
3) RamDump Issues
RamDump is a mechanism used by the samsung to catch the cause of any kernel crash and dump it in the RAM. Later they use one software to extract to the machine and can be analyzed. I will explain on RamDump here,
A kernel crash was happening like, freeing the VMA in interrupt context. The kernel back trace is showing starting from work_pending to a place where vumap().
In vunmap() function a BUG(in_interrupt()) is there. It is an assertion to tell that vma should not be freed in interrupt context.
Its takes some time to fix. But I feel little proud of myself after fixing that.
There was one call to lib/genalloc.c gen_pool_destroy(). In that function
write_unlock() is called without the write_lock(). This function basically decrements
and increments the preemt_count to disable the preemption. And everything was going wrong from here. So it was a kernel bug in 2.6.29 kernel.
4) changed msleep() to mdelay()
Not a good thing to do. But in this scenario it is the only solution. The scenario is when user press the , the device should wake up. But the lcd is taking around 900ms to wake up. I saw few msleep(), changed it to mdelay(). This got a reduction of 350ms The only problem is that, the processor will just spin and waist the processor cycles. But here when the device wakes up from sleep it wont be having other things to do. Moreover, mdelay() is not locking anything, it just uses its full time slot. Once its time-slot is over, scheduler will schedules it out.
Another option- One structure they are giving delay after each command. But most of the delay are zero. But in the kernel code they are using like this
msleep(table->wait).
I modified to
if(table->wait)
msleep(table->wait);
The reason is that even msleep(0) will take more than 10ms.
The mobile runs on Qualcomm MSM7627. This is a having two ARM core, two DSP core. There is one ARM11 which is called as Application Processor(AP) on which linux runs. And there is ARM9 which is called Modem Processor(some times called Communication Processor CP) on which REX OS is running. Here CP is the master. Both communicates through Shared memory driver IPC. Whoever want to communicate will place the corresponding COMMAND and data and interrupt the other processor. Send end key is the the switch on the headset to send the key-press events to the application to for disconnecting the call or going to next track in music player. This is implemented as an input device. The driver mechanism is like this.
Headset detection is done on Modem. There is a IPC callback mechanism registered in RIL layer(on AP side) in application space for getting the status change of the headset. So once headset is inserted or remove, modem will pass this information through IPC. The callback in the mode side will write 1 or 0 for headset inserted and headset removed respectively to a sysfs entry(/sys/class/switch/h2w/headset) exported by the headset driver in the AP side. So once the headset is detected we will enable the send-end key interrupt which is done on the AP side. This is implemented on a gpio. Since due to noise created during the headset insertion, lot of spurious interrupts(send end key) where coming. So we enable the send-end key only after 100ms after the headset insertion. This is implemented by using delayed work-queue.
2) Firmware up-gradation on Touch screen.
The touch screen driver is from Melfas. The I2C is implemented using the i2c-gpio driver. This is a kernel driver which manipulates the gpio to implement the I2C protocol. We have to pass the gpios for sda and scl during the initialization of the driver.
some notes about this driver
=======================
This is a very simple bitbanging i2c bus driver utilizing the new
arch-neutral GPIO API. Useful for chips that don't have a built-in
i2c controller, additional i2c busses, or testing purposes.
To use, include something similar to the following in the
board-specific setup code:
#include
static struct i2c_gpio_platform_data i2c_gpio_data = {
.sda_pin = GPIO_PIN_FOO,
.scl_pin = GPIO_PIN_BAR,
};
static struct platform_device i2c_gpio_device = {
.name = "i2c-gpio",
.id = 0,
.dev = {
.platform_data = &i2c_gpio_data,
},
};
Register this platform_device, set up the i2c pins as GPIO if required and you're ready to go. This will use default values for udelay and timeout, and will work with GPIO hardware that does not support open drain mode, but allows changing the direction of the SDA i2c_gpio_device.id is the I2C adapter number i2c_gpio_platform_data has more members to define the pin is
struct i2c_gpio_platform_data {
unsigned int sda_pin;
unsigned int scl_pin;
/*signal toggle delay. SCL frequency is (500 / udelay) kHz*/
int udelay;
/*timeout: clock stretching timeout in jiffies. If the slave keeps
SCL low for longer than this, the transfer will time out.*/
int timeout;
unsigned int sda_is_open_drain:1;
unsigned int scl_is_open_drain:1;
unsigned int scl_is_output_only:1;
}
=============================
3) RamDump Issues
RamDump is a mechanism used by the samsung to catch the cause of any kernel crash and dump it in the RAM. Later they use one software to extract to the machine and can be analyzed. I will explain on RamDump here,
A kernel crash was happening like, freeing the VMA in interrupt context. The kernel back trace is showing starting from work_pending to a place where vumap().
In vunmap() function a BUG(in_interrupt()) is there. It is an assertion to tell that vma should not be freed in interrupt context.
Its takes some time to fix. But I feel little proud of myself after fixing that.
There was one call to lib/genalloc.c gen_pool_destroy(). In that function
write_unlock() is called without the write_lock(). This function basically decrements
and increments the preemt_count to disable the preemption. And everything was going wrong from here. So it was a kernel bug in 2.6.29 kernel.
4) changed msleep() to mdelay()
Not a good thing to do. But in this scenario it is the only solution. The scenario is when user press the , the device should wake up. But the lcd is taking around 900ms to wake up. I saw few msleep(), changed it to mdelay(). This got a reduction of 350ms The only problem is that, the processor will just spin and waist the processor cycles. But here when the device wakes up from sleep it wont be having other things to do. Moreover, mdelay() is not locking anything, it just uses its full time slot. Once its time-slot is over, scheduler will schedules it out.
Another option- One structure they are giving delay after each command. But most of the delay are zero. But in the kernel code they are using like this
msleep(table->wait).
I modified to
if(table->wait)
msleep(table->wait);
The reason is that even msleep(0) will take more than 10ms.
Subscribe to:
Posts (Atom)