NOTICE: The Processors Wiki will End-of-Life on January 15, 2021. It is recommended to download any files or other content you may need that are hosted on processors.wiki.ti.com. The site is now set to read only.
TI81XX PSP PM CLOCK FRAMEWORK User Guide
TI81XX refers to TI816X, TI814X and TI813X.
Contents
About this manual[edit]
This document gives an overview as well as implementation details of Clock framework in linux psp on TI81XX devices.
Introduction[edit]
This document provides details about clock generation and distribution in hardware, Clock tree implementation in software, Enabling, disabling and changing rate of a clock.
Software Implementation[edit]
Hardware connections are mimicked in software to create complete network of clocks called the Clock Tree.
Parent clock: The clock which provides source
Child clock: A clock to which source is provided
Sibling clock: Clocks drawing source from same parent clock
- Clock data structure
<syntaxhighlight lang="c"> struct clk {
struct list_head node; const struct clkops *ops; const char *name; struct clk *parent; struct list_head children; struct list_head sibling; /* node for children */ ......... Many fields are omitted here...... unsigned long rate; unsigned long (*recalc)(struct clk *); int (*set_rate)(struct clk *, unsigned long); long (*round_rate)(struct clk *, unsigned long); ................................... s8 usecount; ...................................
}; </syntaxhighlight> NOTE: Refer to <linux_kernel>/arch/arm/plat-omap/include/plat/clock.h for description of each field.
Usage[edit]
- For all of the following operations include clk.h,
<syntaxhighlight lang="c">#include <linux/clk.h></syntaxhighlight>
Enabling And Disabling Clock[edit]
Acquire/Get clock Pointer[edit]
- To get a pointer the the clock structure
<syntaxhighlight lang="c"> struct clk *clkp; clkp = clk_get(dev_id,clk_name); if(!clkp)
pr_err("clk_get failed\n");
</syntaxhighlight>
- dev_id of some clocks may be NULL in that case pass NULL in place of dev_id
NOTE: Refer to <kernel_installation>/arch/arm/mach-omap2/clock814x_data.c or <kernel_installation>/arch/arm/mach-omap2/clock816x_data.c to find whether the device id of a clock is NULL or valid string.You can find this info in ti814x_clks[] array, where in the first field is dev_id and second field is clock name. clkp = clk_get(NULL,clk_name);
- Example
<syntaxhighlight lang="c"> struct clk *clkp;
clkp = clk_get(NULL,"gem_fck"); if(!clkp)
pr_err("clk_get failed for gem_fck\n");
</syntaxhighlight>
Release/Put clock Pointer[edit]
- To free the pointer to the clock structure, use the clock pointer(clkp) acquired through clk_get(),
<syntaxhighlight lang="c"> clk_put(clkp); </syntaxhighlight>
Enable Clock[edit]
- A clock must be enabled before using it as a source of clock to any module,to enable the clock, use the clock pointer(clkp) acquired through clk_get(),
<syntaxhighlight lang="c"> clk_enable(clkp); </syntaxhighlight>
Disable Clock[edit]
- A clock can be disabled when the clock is no longer required by any modules or its children clocks,to disable the clock, use the clock pointer(clkp) acquired through clk_get(),
<syntaxhighlight lang="c"> clk_disable(clkp); </syntaxhighlight>
Change Clock Rate[edit]
Get clock current rate[edit]
- To get the current frequency/rate of the clock, use the clock pointer(clkp) acquired through clk_get(),
<syntaxhighlight lang="c"> unsigned long clk_rate; clk_rate = clk_get_rate(clkp); </syntaxhighlight>
Change clock rate[edit]
Note: A clock must be acquired and enabled before changing the rate, enabling the clock will increment the use-count and avoid conflicts such as multiple users setting the rate.
Call to set_rate will return with failure if either the use-count is zero or greater than one thus preventing users from changing rate of the clocks that could affect other users.
- To see if the rate you are targetting is possible for the clock or not, use clk_round_rate() with the clock pointer(clkp) acquired through clk_get(), pass target rate in Hz,.
<syntaxhighlight lang="c">
rounded_rate = clk_round_rate(clkp, target_rate);
Now call set_rate, remember set_rate takes clock frequency in Hz only;
ret = clk_set_rate(clkp, rounded_rate); </syntaxhighlight>
- Below is an example code showing how to change rate of gem_ick
<syntaxhighlight lang="c"> struct clk *clk; unsigned long rate; int ret;
clk = clk_get(NULL, "gem_ick"); if(!IS_ERR(clk))
ret = clk_enable(clk);
else {
pr_err("unable to get clock\n"); return (-1);
} rate = clk_get_rate(clk);
rounded_rate = clk_round_rate(clk, 600000000);
ret = clk_set_rate(clk, rounded_rate);
</syntaxhighlight>
- Changing clock rate may be un-successful in following cases:
- Clock is drawing source from a fixed rate clock source(e.g. OSC0,OSC1,XREF etc) - Clock is in use by more than one modules/children, usecount > 1 - Clock source is in use by more than one children.
Change clock Parent[edit]
- Get the clock pointer to the clock and the new parent and call clk_set_parent()
<syntaxhighlight lang="c"> ret = clk_set_parent(clkp, new_parent); </syntaxhighlight>
- below is an example, showing how to change clock parent
<syntaxhighlight lang="c"> clk = clk_get(NULL, "mcasp1_fck");
new_parent = clk_get(NULL, "sysclk21_ck");
ret = clk_set_parent(clk, new_parent);
</syntaxhighlight>
Browsing DebugFs for Clock configuration[edit]
Clock tree from debugfs[edit]
Details of clocks such as rate,usecount and flags can be viewed through debugfs entries of the clocks. To access these details one has to mount the debugfs root directory first,follow the steps below to mount debugfs and view clock details:
1. Create a directory to mount the debugfs root or use /sys/kernel/debug
$ mount -t debugfs debugfs /sys/kernel/debug
2. Change to clock directory under debugfs,clock entries arranged exactly same as clock tree, ie. root clock -> child clock & sibling clocks, to see the details,
$ cd /sys/kernel/debug/clock root@ti8168-evm:/sys/kernel/debug/clock# ls
ex:
root@ti8168-evm:~# cd /sys/kernel/debug/clock/ root@ti8168-evm:/sys/kernel/debug/clock# ls osc0_clkin_ck/dsp_dpll_ck/gem_fck/ flags rate usecount root@ti8168-evm:/sys/kernel/debug/clock# cd osc0_clkin_ck/dsp_dpll_ck/gem_fck/ root@ti8168-evm:/sys/kernel/debug/clock/osc0_clkin_ck/dsp_dpll_ck/gem_fck# cat rate 500000000
Finding a clock[edit]
- To find a clock, ex: "gem_ick"
root@ti8168-evm:/sys/kernel/debug/clock# ls -lR | grep gem_ick
Using Script to dump details[edit]
The shell script given below can be used to browse the clock tree for debugging purposes. <syntaxhighlight lang="c">
- !/bin/sh
- Clock tree browser
- Version: 1.0
- Copyright (C) {2011} Texas Instruments Incorporated - http://www.ti.com/
- USAGE
- $ browser [attribute] [clock]
- attribute - can be either rate; flags or usecount
- clock - clock source to browse; optional parameter; if not specified
- displays the specified attribute for all the clocks in system
- EXAMPLES
- $browser rate dpll1_fck # Display rate for dpll1_fck
- $browser rate dpll1 # Display rate for all clocks associated with dpll1
- ASSUMPTIONS
- Assumes debug filesystem is available and mounted at /sys/kernel/debug
cd /sys/kernel/debug/clock/
if [ "$2" != "" ]
then find ./ -type f -name $1 | grep $2 > /var/myfile;
else find ./ -type f -name $1 > /var/myfile;
fi
while read line
do
echo "$line ==> `cat $line`";
done < "/var/myfile"
</syntaxhighlight>
Copy the above script to a file, say "browser", copy this file to your file system(nfs/ramdisk) and chmod to execution,
Mount the debugfs as explianed above then execute:
1. To lis current rate of all colcks
$./browser rate
2. To list rate of a particular clock
$./browser rate gem_ick
3. similarly you can list the usecount.
Future Work[edit]
FAQ[edit]
Q: Why am i not able to change rate of a clock using clk_set_rate()?
A:Check if the clock is sourced from a PLL or a fixed clock. Only Clocks, whose root source is from a pll can be changed to run at different rates.