Please note as of Wednesday, August 15th, 2018 this wiki has been set to read only. If you are a TI Employee and require Edit ability please contact x0211426 from the company directory.

TI811X PSP PM CLOCK FRAMEWORK User Guide

From Texas Instruments Wiki
Jump to: navigation, search
TIBanner.png
TI81XX PSP PM Clock framework User Guide
Linux PSP
IMPORTANT

TI81XX refers to TI816X, TI814X and TI813X.

About this manual

This document gives an overview as well as implementation details of Clock framework in linux psp on TI81XX devices.

Introduction

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

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
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;
       ...................................
};

NOTE: Refer to <linux_kernel>/arch/arm/plat-omap/include/plat/clock.h for description of each field.

Usage

  • For all of the following operations include clk.h,
#include <linux/clk.h>

Enabling And Disabling Clock

Acquire/Get clock Pointer

  • Use clk_get() to get a pointer to the clock structure
struct clk *clkp;
clkp = clk_get(dev_id,clk_name);
if(!clkp)
     pr_err("clk_get failed\n");
  • 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
struct clk *clkp;

clkp = clk_get(NULL,"gem_fck");
if(!clkp)
     pr_err("clk_get failed for gem_fck\n");

Release/Put clock Pointer

  • To free the pointer to the clock structure, use the clock pointer(clkp) acquired through clk_get(),
clk_put(clkp);

Enable Clock

  • 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(),
clk_enable(clkp);

Disable Clock

  • 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(),
clk_disable(clkp);

Change Clock Rate

Get clock current rate

  • To get the current frequency/rate of the clock, use the clock pointer(clkp) acquired through clk_get(),
unsigned long clk_rate;
clk_rate = clk_get_rate(clkp);

Change clock rate

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,.
 
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);
  • Below is an example code showing how to change rate of gem_ick
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);

  • 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

  • Get the clock pointer to the clock and the new parent and call clk_set_parent()
ret = clk_set_parent(clkp, new_parent);
  • below is an example, showing how to change clock parent
clk = clk_get(NULL, "mcasp1_fck");

new_parent = clk_get(NULL, "sysclk21_ck");

ret = clk_set_parent(clk, new_parent);

Browsing DebugFs for Clock configuration

Clock tree from debugfs

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

  • To find a clock, ex: "gem_ick"
root@ti8168-evm:/sys/kernel/debug/clock# ls -lR | grep gem_ick

Using Script to dump details

The shell script given below can be used to browse the clock tree for debugging purposes.

#!/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"

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

FAQ

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.