Sunday, July 22, 2018

Linux Clock - clk_hw_register_mux_table

note for myself:

For mux, I still dont understand most of its.
The frame:
/**
 * struct clk_mux - multiplexer clock
 *
 * @hw:  handle between common and hardware-specific interfaces
 * @reg: register controlling multiplexer
 * @table: array of register values corresponding to the parent index
 * @shift: shift to multiplexer bit field
 * @mask: mask of mutliplexer bit field
 * @flags: hardware-specific flags
 * @lock: register lock
 *
 * Clock with multiple selectable parents.  Implements .get_parent, .set_parent
 * and .recalc_rate
 *
 * Flags:
 * CLK_MUX_INDEX_ONE - register index starts at 1, not 0
 * CLK_MUX_INDEX_BIT - register index is a single bit (power of two)
 * CLK_MUX_HIWORD_MASK - The mux settings are only in lower 16-bit of this
 * register, and mask of mux bits are in higher 16-bit of this register.
 * While setting the mux bits, higher 16-bit should also be updated to
 * indicate changing mux bits.
 * CLK_MUX_ROUND_CLOSEST - Use the parent rate that is closest to the desired
 * frequency.
 */
struct clk_mux {
 struct clk_hw hw;
 void __iomem *reg;
 u32  *table;
 u32  mask;
 u8  shift;
 u8  flags;
 spinlock_t *lock;
};

#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw)

#define CLK_MUX_INDEX_ONE  BIT(0)
#define CLK_MUX_INDEX_BIT  BIT(1)
#define CLK_MUX_HIWORD_MASK  BIT(2)
#define CLK_MUX_READ_ONLY  BIT(3) /* mux can't be changed */
#define CLK_MUX_ROUND_CLOSEST  BIT(4)

extern const struct clk_ops clk_mux_ops;
extern const struct clk_ops clk_mux_ro_ops;

struct clk *clk_register_mux(struct device *dev, const char *name,
  const char * const *parent_names, u8 num_parents,
  unsigned long flags,
  void __iomem *reg, u8 shift, u8 width,
  u8 clk_mux_flags, spinlock_t *lock);
struct clk_hw *clk_hw_register_mux(struct device *dev, const char *name,
  const char * const *parent_names, u8 num_parents,
  unsigned long flags,
  void __iomem *reg, u8 shift, u8 width,
  u8 clk_mux_flags, spinlock_t *lock);

struct clk *clk_register_mux_table(struct device *dev, const char *name,
  const char * const *parent_names, u8 num_parents,
  unsigned long flags,
  void __iomem *reg, u8 shift, u32 mask,
  u8 clk_mux_flags, u32 *table, spinlock_t *lock);
struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name,
  const char * const *parent_names, u8 num_parents,
  unsigned long flags,
  void __iomem *reg, u8 shift, u32 mask,
  u8 clk_mux_flags, u32 *table, spinlock_t *lock);

int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags,
    unsigned int val);
unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index);

void clk_unregister_mux(struct clk *clk);
void clk_hw_unregister_mux(struct clk_hw *hw);

And from "drivers/clk/clk-mux.c"
clk_register_mux -> clk_register_mux_table -> clk_hw_register_mux_table
clk_hw_register_mux ->  clk_hw_register_mux_table

Let see the differences:
struct clk *clk_register_mux_table(struct device *dev, const char *name,
  const char * const *parent_names, u8 num_parents,
  unsigned long flags,
  void __iomem *reg, u8 shift, u32 mask,
  u8 clk_mux_flags, u32 *table, spinlock_t *lock)
{
 struct clk_hw *hw;

 hw = clk_hw_register_mux_table(dev, name, parent_names, num_parents,
           flags, reg, shift, mask, clk_mux_flags,
           table, lock);
 if (IS_ERR(hw))
  return ERR_CAST(hw);
 return hw->clk;
}
EXPORT_SYMBOL_GPL(clk_register_mux_table);

struct clk *clk_register_mux(struct device *dev, const char *name,
  const char * const *parent_names, u8 num_parents,
  unsigned long flags,
  void __iomem *reg, u8 shift, u8 width,
  u8 clk_mux_flags, spinlock_t *lock)
{
 u32 mask = BIT(width) - 1;

 return clk_register_mux_table(dev, name, parent_names, num_parents,
          flags, reg, shift, mask, clk_mux_flags,
          NULL, lock);
}
EXPORT_SYMBOL_GPL(clk_register_mux);

struct clk_hw *clk_hw_register_mux(struct device *dev, const char *name,
  const char * const *parent_names, u8 num_parents,
  unsigned long flags,
  void __iomem *reg, u8 shift, u8 width,
  u8 clk_mux_flags, spinlock_t *lock)
{
 u32 mask = BIT(width) - 1;

 return clk_hw_register_mux_table(dev, name, parent_names, num_parents,
          flags, reg, shift, mask, clk_mux_flags,
          NULL, lock);
}
EXPORT_SYMBOL_GPL(clk_hw_register_mux);

clk_register_mux  and clk_hw_register_mux:
do "u32 mask = BIT(width) - 1;"
and passing NULL to xxx_register_mux_table

clk_register_mux_table and clk_hw_register_mux_table:
almost the same, but clk_register_mux_table do error checking.

I should study "clk_hw_register_mux_table" is the function doing all the work
struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name,
  const char * const *parent_names, u8 num_parents,
  unsigned long flags,
  void __iomem *reg, u8 shift, u32 mask,
  u8 clk_mux_flags, u32 *table, spinlock_t *lock)
{
 struct clk_mux *mux;
 struct clk_hw *hw;
 struct clk_init_data init;
 u8 width = 0;
 int ret;

 if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
  width = fls(mask) - ffs(mask) + 1;
  if (width + shift > 16) {
   pr_err("mux value exceeds LOWORD field\n");
   return ERR_PTR(-EINVAL);
  }
 }

 /* allocate the mux */
 mux = kzalloc(sizeof(*mux), GFP_KERNEL);
 if (!mux)
  return ERR_PTR(-ENOMEM);

 init.name = name;
 if (clk_mux_flags & CLK_MUX_READ_ONLY)
  init.ops = &clk_mux_ro_ops;
 else
  init.ops = &clk_mux_ops;
 init.flags = flags | CLK_IS_BASIC;
 init.parent_names = parent_names;
 init.num_parents = num_parents;

 /* struct clk_mux assignments */
 mux->reg = reg;
 mux->shift = shift;
 mux->mask = mask;
 mux->flags = clk_mux_flags;
 mux->lock = lock;
 mux->table = table;
 mux->hw.init = &init;

 hw = &mux->hw;
 ret = clk_hw_register(dev, hw);
 if (ret) {
  kfree(mux);
  hw = ERR_PTR(ret);
 }

 return hw;
}
EXPORT_SYMBOL_GPL(clk_hw_register_mux_table);
Copy everything here for better viewing.
there are two ops, this code is self-explainable.
if (clk_mux_flags & CLK_MUX_READ_ONLY)
init.ops = &clk_mux_ro_ops;
else
init.ops = &clk_mux_ops;


const struct clk_ops clk_mux_ops = {
 .get_parent = clk_mux_get_parent,
 .set_parent = clk_mux_set_parent,
 .determine_rate = clk_mux_determine_rate,
};
EXPORT_SYMBOL_GPL(clk_mux_ops);

const struct clk_ops clk_mux_ro_ops = {
 .get_parent = clk_mux_get_parent,
};
EXPORT_SYMBOL_GPL(clk_mux_ro_ops);

clk_mux_set_parent:
static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
{
 struct clk_mux *mux = to_clk_mux(hw);
 u32 val = clk_mux_index_to_val(mux->table, mux->flags, index);
 unsigned long flags = 0;
 u32 reg;

 if (mux->lock)
  spin_lock_irqsave(mux->lock, flags);
 else
  __acquire(mux->lock);

 if (mux->flags & CLK_MUX_HIWORD_MASK) {
  reg = mux->mask << (mux->shift + 16);
 } else {
  reg = clk_readl(mux->reg);
  reg &= ~(mux->mask << mux->shift);
 }
 val = val << mux->shift;
 reg |= val;
 clk_writel(reg, mux->reg);

 if (mux->lock)
  spin_unlock_irqrestore(mux->lock, flags);
 else
  __release(mux->lock);

 return 0;
}

clk_mux_index_to_val:

unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index)
{
 unsigned int val = index;

 if (table) {
  val = table[index];
 } else {
  if (flags & CLK_MUX_INDEX_BIT)
   val = 1 << index;

  if (flags & CLK_MUX_INDEX_ONE)
   val++;
 }

 return val;
}
EXPORT_SYMBOL_GPL(clk_mux_index_to_val);
4 ways to obtain the val:
1. from predefined table val = table[index];
2. one bit mask is corresponding to one source
3. value + 1 corresponded to one clock source
4. value directly read out from register

After the val is obtained, it is normal write to particular register.
val = val << mux->shift;
reg |= val;
clk_writel(reg, mux->reg);

clk_mux_get_parent:
now is how to get the parent clock.

static u8 clk_mux_get_parent(struct clk_hw *hw)
{
 struct clk_mux *mux = to_clk_mux(hw);
 u32 val;

 val = clk_readl(mux->reg) >> mux->shift;
 val &= mux->mask;

 return clk_mux_val_to_index(hw, mux->table, mux->flags, val);
}

// all information is at clk_mux_val_to_index

int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags,
    unsigned int val)
{
 int num_parents = clk_hw_get_num_parents(hw);

 if (table) {
  int i;

  for (i = 0; i < num_parents; i++)
   if (table[i] == val)
    return i;
  return -EINVAL;
 }

 if (val && (flags & CLK_MUX_INDEX_BIT))
  val = ffs(val) - 1;

 if (val && (flags & CLK_MUX_INDEX_ONE))
  val--;

 if (val >= num_parents)
  return -EINVAL;

 return val;
}
EXPORT_SYMBOL_GPL(clk_mux_val_to_index);
still 3 ways to do the mapping:
1. get the val from table - easiest to understand
2. return the least significant index bit value, for example, bit4 is passed to ffs, ffs will return 5. "val = ffs(val) - 1" = 4.
3. register index starts at 1, not 0.
4. register index starts at 0.

I need to read reference code to understand how to use this mux register.

Linux Clock - clk_hw_register_custom_function

note for myself:

Driver clk-stm32h7.c is creating own clock function - clk_register_ready_gate
static struct clk_hw *clk_register_ready_gate(struct device *dev,
  const char *name, const char *parent_name,
  void __iomem *reg, u8 bit_idx, u8 bit_rdy,
  unsigned long flags, spinlock_t *lock)
{
 struct stm32_ready_gate *rgate;
 struct clk_init_data init = { NULL };
 struct clk_hw *hw;
 int ret;

 rgate = kzalloc(sizeof(*rgate), GFP_KERNEL);
 if (!rgate)
  return ERR_PTR(-ENOMEM);

 init.name = name;
 init.ops = &ready_gate_clk_ops;
 init.flags = flags;
 init.parent_names = &parent_name;
 init.num_parents = 1;

 rgate->bit_rdy = bit_rdy;
 rgate->gate.lock = lock;
 rgate->gate.reg = reg;
 rgate->gate.bit_idx = bit_idx;
 rgate->gate.hw.init = &init;

 hw = &rgate->gate.hw;
 ret = clk_hw_register(dev, hw);
 if (ret) {
  kfree(rgate);
  hw = ERR_PTR(ret);
 }

 return hw;
}

clk_hw_register is the common function to register clock.

what functions needed to create your own clock function.
static const struct clk_ops
static const struct clk_ops ready_gate_clk_ops = {
 .enable  = ready_gate_clk_enable,
 .disable = ready_gate_clk_disable,
 .is_enabled = clk_gate_is_enabled,
};
enable, disable, is_enabled are needed.

Look at ready_gate_clk_enable
static int ready_gate_clk_enable(struct clk_hw *hw)
{
 struct clk_gate *gate = to_clk_gate(hw);
 struct stm32_ready_gate *rgate = to_ready_gate_clk(gate);
 int bit_status;
 unsigned int timeout = RGATE_TIMEOUT;

 if (clk_gate_ops.is_enabled(hw))
  return 0;

 clk_gate_ops.enable(hw);

 /* We can't use readl_poll_timeout() because we can blocked if
  * someone enables this clock before clocksource changes.
  * Only jiffies counter is available. Jiffies are incremented by
  * interruptions and enable op does not allow to be interrupted.
  */
 do {
  bit_status = !(readl(gate->reg) & BIT(rgate->bit_rdy));

  if (bit_status)
   udelay(100);

 } while (bit_status && --timeout);

 return bit_status;
}

it is checking
1. whether the clock is enabled or not,
2. enable the clock
3. check the register for particular bit, whether the particular bit is ready.

Same goes to ready_gate_clk_disable:
static void ready_gate_clk_disable(struct clk_hw *hw)
{
 struct clk_gate *gate = to_clk_gate(hw);
 struct stm32_ready_gate *rgate = to_ready_gate_clk(gate);
 int bit_status;
 unsigned int timeout = RGATE_TIMEOUT;

 if (!clk_gate_ops.is_enabled(hw))
  return;

 clk_gate_ops.disable(hw);

 do {
  bit_status = !!(readl(gate->reg) & BIT(rgate->bit_rdy));

  if (bit_status)
   udelay(100);

 } while (bit_status && --timeout);
}

Almost he same
1. whether the clock is disable or not,
2. disable the clock
3. check the register for particular bit, whether the particular bit is ready.

one thing to take note, in
ready_gate_clk_enable,
ready_gate_clk_disable,
it is using existing "clk_gate_ops.disable(hw);" and "clk_gate_ops.enable(hw);" to disable and enable clock.
However it is adding a layer of checking to check whether the clock is ready or not.

Erm, now, where does "clk_register_ready_gate" is used.

 hws[HSE_CK] = clk_register_ready_gate(NULL,
    "hse_ck",
    hse_clk,
    RCC_CR + base,
    16, 17,
    0,
    &stm32rcc_lock);

 hws[LSE_CK] = clk_register_ready_gate(NULL,
    "lse_ck",
    lse_clk,
    RCC_BDCR + base,
    0, 1,
    0,
    &stm32rcc_lock);

Go read databook for RCC_CR and RCC_BDCR.
RCC_CR:
Bit 17 HSERDY: HSE clock ready flag
0: HSE clock is not ready (default after reset)
1: HSE clock is ready
Bit 16 HSEON: HSE clock enable
0: HSE is OFF (default after reset)
1: HSE is ON

RCC_BDCR:
Bit 1 LSERDY: LSE oscillator ready
0: LSE oscillator not ready (default after backup domain reset)
1: LSE oscillator ready
Bit 0 LSEON: LSE oscillator enabled
0: LSE oscillator OFF (default after backup domain reset)
1: LSE oscillator ON

From here, we know that this function "clk_register_ready_gate" still performing normal clock gating using default gate-clock framework, but it is adding a wait function to allow the clock to stabilize. After the clock is stabilized, it is indicated by ready_bit.

ah.., I couldnt understand the code without databook.
Most drivers at linux mainline doesnt provide databook to public.
So I am thankful to have MCU manufacturer to open out the databook.
STM is the one to thank in this case. Thank you.

Linux Clock - clk_hw_register_gate

Note for myself:
clk_hw_register_gate 

Always start with source code:
/**
 * clk_hw_register_gate - register a gate clock with the clock framework
 * @dev: device that is registering this clock
 * @name: name of this clock
 * @parent_name: name of this clock's parent
 * @flags: framework-specific flags for this clock
 * @reg: register address to control gating of this clock
 * @bit_idx: which bit in the register controls gating of this clock
 * @clk_gate_flags: gate-specific flags for this clock
 * @lock: shared register lock for this clock
 */
struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name,
  const char *parent_name, unsigned long flags,
  void __iomem *reg, u8 bit_idx,
  u8 clk_gate_flags, spinlock_t *lock)
{
 struct clk_gate *gate;
 struct clk_hw *hw;
 struct clk_init_data init;
 int ret;

 if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
  if (bit_idx > 15) {
   pr_err("gate bit exceeds LOWORD field\n");
   return ERR_PTR(-EINVAL);
  }
 }

 /* allocate the gate */
 gate = kzalloc(sizeof(*gate), GFP_KERNEL);
 if (!gate)
  return ERR_PTR(-ENOMEM);

 init.name = name;
 init.ops = &clk_gate_ops;
 init.flags = flags | CLK_IS_BASIC;
 init.parent_names = parent_name ? &parent_name : NULL;
 init.num_parents = parent_name ? 1 : 0;

 /* struct clk_gate assignments */
 gate->reg = reg;
 gate->bit_idx = bit_idx;
 gate->flags = clk_gate_flags;
 gate->lock = lock;
 gate->hw.init = &init;

 hw = &gate->hw;
 ret = clk_hw_register(dev, hw);
 if (ret) {
  kfree(gate);
  hw = ERR_PTR(ret);
 }

 return hw;
}
EXPORT_SYMBOL_GPL(clk_hw_register_gate);

What does it meant by CLK_IS_BASIC, the definition is all come from clk-provider.h

/*
 * flags used across common struct clk.  these flags should only affect the
 * top-level framework.  custom flags for dealing with hardware specifics
 * belong in struct clk_foo
 *
 * Please update clk_flags[] in drivers/clk/clk.c when making changes here!
 */
#define CLK_SET_RATE_GATE BIT(0) /* must be gated across rate change */
#define CLK_SET_PARENT_GATE BIT(1) /* must be gated across re-parent */
#define CLK_SET_RATE_PARENT BIT(2) /* propagate rate change up one level */
#define CLK_IGNORE_UNUSED BIT(3) /* do not gate even if unused */
    /* unused */
#define CLK_IS_BASIC  BIT(5) /* Basic clk, can't do a to_clk_foo() */
#define CLK_GET_RATE_NOCACHE BIT(6) /* do not use the cached clk rate */
#define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
#define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
#define CLK_RECALC_NEW_RATES BIT(9) /* recalc rates after notifications */
#define CLK_SET_RATE_UNGATE BIT(10) /* clock needs to run to set rate */
#define CLK_IS_CRITICAL  BIT(11) /* do not gate, ever */
/* parents need enable during gate/ungate, set rate and re-parent */
#define CLK_OPS_PARENT_ENABLE BIT(12)
all these flags are used in difference driver files, seem like the common clock framework had cater for most cases, also it is making the framework getting complicated. Where is details documentation and reference code. Guess more to code readings and tracking.

This line init.ops = &clk_gate_ops; linked to following code

const struct clk_ops clk_gate_ops = {
 .enable = clk_gate_enable,
 .disable = clk_gate_disable,
 .is_enabled = clk_gate_is_enabled,
};
EXPORT_SYMBOL_GPL(clk_gate_ops);

tracing a bit: clk_gate_enable -> clk_gate_endisable(hw, 1);

/*
 * It works on following logic:
 *
 * For enabling clock, enable = 1
 * set2dis = 1 -> clear bit -> set = 0
 * set2dis = 0 -> set bit -> set = 1
 *
 * For disabling clock, enable = 0
 * set2dis = 1 -> set bit -> set = 1
 * set2dis = 0 -> clear bit -> set = 0
 *
 * So, result is always: enable xor set2dis.
 */
static void clk_gate_endisable(struct clk_hw *hw, int enable)
{
 struct clk_gate *gate = to_clk_gate(hw);
 int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
 unsigned long uninitialized_var(flags);
 u32 reg;

 set ^= enable;

 if (gate->lock)
  spin_lock_irqsave(gate->lock, flags);
 else
  __acquire(gate->lock);

 if (gate->flags & CLK_GATE_HIWORD_MASK) {
  reg = BIT(gate->bit_idx + 16);
  if (set)
   reg |= BIT(gate->bit_idx);
 } else {
  reg = clk_readl(gate->reg);

  if (set)
   reg |= BIT(gate->bit_idx);
  else
   reg &= ~BIT(gate->bit_idx);
 }

 clk_writel(reg, gate->reg);

 if (gate->lock)
  spin_unlock_irqrestore(gate->lock, flags);
 else
  __release(gate->lock);
}
Above is the framework working behind on how to do clock gating.

Below is the usage this function in driver clock "clk-stm32h7.c":

/* PERIF CLOCKS */
struct pclk_t {
 u32 gate_offset;
 u8 bit_idx;
 const char *name;
 const char *parent;
 u32 flags;
};

#define PER_CLK(_gate_offset, _bit_idx, _name, _parent)\
 PER_CLKF(_gate_offset, _bit_idx, _name, _parent, 0)

static const struct pclk_t pclk[] = {
 PER_CLK(RCC_AHB3ENR, 31, "d1sram1", "hclk"),
 PER_CLK(RCC_AHB3ENR, 30, "itcm", "hclk"),
 PER_CLK(RCC_AHB3ENR, 29, "dtcm2", "hclk"),
 PER_CLK(RCC_AHB3ENR, 28, "dtcm1", "hclk"),
 PER_CLK(RCC_AHB3ENR, 8, "flitf", "hclk"),
 PER_CLK(RCC_AHB3ENR, 5, "jpgdec", "hclk"),
 PER_CLK(RCC_AHB3ENR, 4, "dma2d", "hclk"),
 PER_CLK(RCC_AHB3ENR, 0, "mdma", "hclk"),
all the clocks information is passed to this struct pclk[];
_gate_offset = RCC_AHB3ENR = 0xD4
_bit_idx = 31
_name = d1sram1
_parent = hclk

I looked back "RM0433: STM32H743/753 and STM32H750 advanced ARM®-based 32-bit MCUs", page 428.
Strangely, I cannot match back the register.
Bits 31:17 Reserved
And Bits 11:6 also Reserved

only bit 0, 4 and 5 able to be matched.
Bit 5 JPGDECEN: JPGDEC Peripheral Clock Enable
Bit 4 DMA2DEN: DMA2D Peripheral Clock Enable
Bit 0 MDMAEN: MDMA Peripheral Clock Enable
and it is matching the description name.

oh, well. As long as something matched.

Back to driver code again:

 /* Peripheral clocks */
 for (n = 0; n < ARRAY_SIZE(pclk); n++)
  hws[PERIF_BANK + n] = clk_hw_register_gate(NULL, pclk[n].name,
    pclk[n].parent,
    pclk[n].flags, base + pclk[n].gate_offset,
    pclk[n].bit_idx, pclk[n].flags, &stm32rcc_lock);

This is where the struct pclk[] is registered to clock framework.


The more I read, the more I need to read.

Saturday, July 21, 2018

Linux Clock - clk_register_fractional_divider

note for myself (all the clock description is at clk-provider.h):

/**
 * struct clk_fractional_divider - adjustable fractional divider clock
 *
 * @hw:  handle between common and hardware-specific interfaces
 * @reg: register containing the divider
 * @mshift: shift to the numerator bit field
 * @mwidth: width of the numerator bit field
 * @nshift: shift to the denominator bit field
 * @nwidth: width of the denominator bit field
 * @lock: register lock
 *
 * Clock with adjustable fractional divider affecting its output frequency.
 */
struct clk_fractional_divider {
 struct clk_hw hw;
 void __iomem *reg;
 u8  mshift;
 u8  mwidth;
 u32  mmask;
 u8  nshift;
 u8  nwidth;
 u32  nmask;
 u8  flags;
 void  (*approximation)(struct clk_hw *hw,
    unsigned long rate, unsigned long *parent_rate,
    unsigned long *m, unsigned long *n);
 spinlock_t *lock;
};

#define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw)

extern const struct clk_ops clk_fractional_divider_ops;
struct clk *clk_register_fractional_divider(struct device *dev,
  const char *name, const char *parent_name, unsigned long flags,
  void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
  u8 clk_divider_flags, spinlock_t *lock);
struct clk_hw *clk_hw_register_fractional_divider(struct device *dev,
  const char *name, const char *parent_name, unsigned long flags,
  void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
  u8 clk_divider_flags, spinlock_t *lock);
void clk_hw_unregister_fractional_divider(struct clk_hw *hw);

No reference code is using this function "clk_register_fractional_divider" at the time of writing.

Go for code reading:
struct clk_hw *clk_hw_register_fractional_divider(struct device *dev,
  const char *name, const char *parent_name, unsigned long flags,
  void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
  u8 clk_divider_flags, spinlock_t *lock)
{
 struct clk_fractional_divider *fd;
 struct clk_init_data init;
 struct clk_hw *hw;
 int ret;

 fd = kzalloc(sizeof(*fd), GFP_KERNEL);
 if (!fd)
  return ERR_PTR(-ENOMEM);

 init.name = name;
 init.ops = &clk_fractional_divider_ops;
 init.flags = flags | CLK_IS_BASIC;
 init.parent_names = parent_name ? &parent_name : NULL;
 init.num_parents = parent_name ? 1 : 0;

 fd->reg = reg;
 fd->mshift = mshift;
 fd->mwidth = mwidth;
 fd->mmask = GENMASK(mwidth - 1, 0) << mshift;
 fd->nshift = nshift;
 fd->nwidth = nwidth;
 fd->nmask = GENMASK(nwidth - 1, 0) << nshift;
 fd->flags = clk_divider_flags;
 fd->lock = lock;
 fd->hw.init = &init;

 hw = &fd->hw;
 ret = clk_hw_register(dev, hw);
 if (ret) {
  kfree(fd);
  hw = ERR_PTR(ret);
 }

 return hw;
}
EXPORT_SYMBOL_GPL(clk_hw_register_fractional_divider);

Identified 3 items:
&clk_fractional_divider_ops - functions
mshift, mwidth - numerator
nshift, nwidth - denumerator

We need found out how the mshift, mwidth, nshift, nwidth are used through "clk_fractional_divider_ops".
const struct clk_ops clk_fractional_divider_ops = {
 .recalc_rate = clk_fd_recalc_rate,
 .round_rate = clk_fd_round_rate,
 .set_rate = clk_fd_set_rate,
};
EXPORT_SYMBOL_GPL(clk_fractional_divider_ops);

Let take this "clk_fd_set_rate" for study

static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
      unsigned long parent_rate)
{
 struct clk_fractional_divider *fd = to_clk_fd(hw);
 unsigned long flags = 0;
 unsigned long m, n;
 u32 val;

 rational_best_approximation(rate, parent_rate,
   GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
   &m, &n);

 if (fd->lock)
  spin_lock_irqsave(fd->lock, flags);
 else
  __acquire(fd->lock);

 val = clk_readl(fd->reg);
 val &= ~(fd->mmask | fd->nmask);
 val |= (m << fd->mshift) | (n << fd->nshift);
 clk_writel(val, fd->reg);

 if (fd->lock)
  spin_unlock_irqrestore(fd->lock, flags);
 else
  __release(fd->lock);

 return 0;
}

The highlighted in green is the main function that help to calculate best numerator and denominator to get the best approximate rate.

/*
 * calculate best rational approximation for a given fraction
 * taking into account restricted register size, e.g. to find
 * appropriate values for a pll with 5 bit denominator and
 * 8 bit numerator register fields, trying to set up with a
 * frequency ratio of 3.1415, one would say:
 *
 * rational_best_approximation(31415, 10000,
 *  (1 << 8) - 1, (1 << 5) - 1, &n, &d);
 *
 * you may look at given_numerator as a fixed point number,
 * with the fractional part size described in given_denominator.
 *
 * for theoretical background, see:
 * http://en.wikipedia.org/wiki/Continued_fraction
 */

void rational_best_approximation(
 unsigned long given_numerator, unsigned long given_denominator,
 unsigned long max_numerator, unsigned long max_denominator,
 unsigned long *best_numerator, unsigned long *best_denominator)

while, below perform the task to set register to get correct value.
  val = clk_readl(fd->reg);
 val &= ~(fd->mmask | fd->nmask);
 val |= (m << fd->mshift) | (n << fd->nshift);
 clk_writel(val, fd->reg);

One thing that I am still in doubt, is where the clock rate is defined. Need to study more.

Friday, July 20, 2018

Linux Clock - clk_hw_register_fixed_factor

Studying note:
struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
  const char *name, const char *parent_name, unsigned long flags,
  unsigned int mult, unsigned int div)

Look at this driver file "clk-stm32h7.c".
 /* D1 DOMAIN */
 /* * CPU Systick */
 hws[CPU_SYSTICK] = clk_hw_register_fixed_factor(NULL, "systick",
   "d1cpre", 0, 1, 8);

name: "systiclk"
parent_name: "d1cpre"
flags: 0
mult: 1
div: 8

Doesnt understand anything at all, so referring reference manual DM00314099.pdf, page 331.

The clock value depends on the parent clock, so CPU Systick clock is D1CPRE(1) / 8.

Let look another example:

 hws[CSI_KER_DIV122 + n] = clk_hw_register_fixed_factor(NULL,
   "csi_ker_div122", "csi_ker", 0, 1, 122);

Referring to same databook, page 344.

parent clock is "csi_ker", then it is divided with 122, and the new clock source "csi_ker_div122".

Wednesday, July 18, 2018

VIM pretty theme and CTAGS setup in Raspberry PI

In Linux terminal, VIM is a widely used editor, come in default, support a lot of features, long history (stable). Since I am  using it everyday, so I was thinking to make the editor nice to view.

First is finding a suitable themes, after trying a few, I found this:
My favorite:


Steps:
1. Create directory. If you cannot see the folder ".vim/colors", create using "mkdir -p .vim/colors"
pi@raspberrypi:~/.vim/colors $ ls
atom-dark-256.vim  atom-dark.vim  codedark.vim  dracula.vim - should be empty for your case
3. Find and copy "codedark.vim" to .vim/colors
4. Create if not found. "vi ~/.vimrc". Add below details, then save it.
"set background=dark
set number
set t_Co=256
set t_ut=
colorscheme codedark
syntax on
5. done. You can have pretty source code viewer now.


Ok, now I have pretty view. I want to have simple source code navigator in VIM. So, I decided to install & setup CTAGS.


Steps:
1. sudo apt-get install exuberant-ctags
2. cd ~/.vim/
3. wget https://www.vim.org/scripts/download_script.php?src_id=19574 -O taglist_46.zip
4. unzip taglist_46.zip
5. vim ~/.vimrc
Add following line:
filetype plugin on
nnoremap <F12> :TlistToggle
6. Done. You have pretty vim with simple source code navigator.

Now, my final .vimrc file look like following:

Sunday, May 6, 2018

beaglebone - Making a simple remote host system by accessing gpio through c code + simple tui

With the advancing and mass production of single board computer, the hardware getting cheap and the software getting stable, the community getting stronger, there are a lot of things do not seem out of reach now.

I want a simple remote host system which allowed me to do simple on / off and serial console terminal software to remote slave system.

Power control:
[MY PC] --> [Remote Host System] --> [Relay] --> [Remote Slave System Power Supply]

Communication:
[MY PC] --> [Remote Host System] --> [Serial Console Terminal] --> [Remote Slave System]

Power Control
For power control, I only need to control GPIO. Looking at the beaglebone pinout, I choose GPIO_66 and GPIO_67.


I am using the newest Beaglebone Black image
"
debian@beaglebone:~$ uname -a
Linux beaglebone 4.9.78-ti-r94 #1 SMP PREEMPT Fri Jan 26 21:26:24 UTC 2018 armv7l GNU/Linux
"
where all sysfs for gpios are exported. Good for me. I highlighted gpio66 and gpio67.

I want to control everything through c code.
I found the library written by derekmolloy/beaglebone.
https://github.com/derekmolloy/beaglebone
SimpleGPIO.cpp
SimpleGPIO.h

The library is intuitive and minor modification to get the thing working, at least for my case.

Along that, I can some simple user interface. This is where termbox come along.
I want a simple mouse click to turn on and turn off the relay.
This is the interface I created and use the led for indication.
Red square is the indication of the led is on, while blank indicate the led is off.

This is the actual wiring diagram.


Communication:
For serial console terminal in Linux, after trying two minicom and picocom, I decided to go with picocom. Ok, I lied. I only tried picocom and it is working. Didnt bother to go and try another one.
Source: https://github.com/npat-efault/picocom
Command used: picocom -b 115200 -r -l /dev/ttyS0

debian@beaglebone:~/software/picocom-master$ ./picocom -b 115200 -r -l /dev/ttyUSB0
picocom v3.2a

port is        : /dev/ttyUSB0
flowcontrol    : none
baudrate is    : 115200
parity is      : none
databits are   : 8
stopbits are   : 1
escape is      : C-a
local echo is  : no
noinit is      : no
noreset is     : yes
hangup is      : no
nolock is      : yes
send_cmd is    : sz -vv
receive_cmd is : rz -vv -E
imap is        :
omap is        :
emap is        : crcrlf,delbs,
logfile is     : none
initstring     : none
exit_after is  : not set
exit is        : no

Type [C-a] [C-h] to see available commands
Terminal ready

I felt the interface not bad. Here are the hot keys
*** Picocom commands (all prefixed by [C-a])

*** [C-x] : Exit picocom
*** [C-q] : Exit without reseting serial port
*** [C-b] : Set baudrate
*** [C-u] : Increase baudrate (baud-up)
*** [C-d] : Decrease baudrate (baud-down)
*** [C-i] : Change number of databits
*** [C-j] : Change number of stopbits
*** [C-f] : Change flow-control mode
*** [C-y] : Change parity mode
*** [C-p] : Pulse DTR
*** [C-t] : Toggle DTR
*** [C-g] : Toggle RTS
*** [C-|] : Send break
*** [C-c] : Toggle local echo
*** [C-w] : Write hex
*** [C-s] : Send file
*** [C-r] : Receive file
*** [C-v] : Show port settings
*** [C-h] : Show this message

I would say neat after you explore further.

For current moment, it is suffice for my usage.

Two basic proof of concept are done, now it is time to do it on actual platform.
Still pending for my relay. Till next time then.