Skip to content

Commit

Permalink
debugcc: Rework clock muxes into a chain structure
Browse files Browse the repository at this point in the history
Enforcing a primary+leaf configuration does not walk for all the cases.
Some clocks (msm8996 CPU) have more muxes to be powered on. Other (MCCC)
do not require GCC at all. Make clock measurement more versatile by
reworking GCC + optional leaf into a chain of muxes.

Signed-off-by: Dmitry Baryshkov <[email protected]>
  • Loading branch information
lumag committed Nov 6, 2023
1 parent 132a037 commit cf5664f
Show file tree
Hide file tree
Showing 18 changed files with 3,983 additions and 3,749 deletions.
127 changes: 50 additions & 77 deletions debugcc.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <fcntl.h>
#include <getopt.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
Expand All @@ -42,33 +43,23 @@

#include "debugcc.h"

static uint32_t readl(void *ptr)
{
return *((volatile uint32_t*)ptr);
}

static void writel(uint32_t val, void *ptr)
{
*((volatile uint32_t*)ptr) = val;
}

static unsigned int measure_ticks(struct debug_mux *gcc, unsigned int ticks)
static unsigned int measure_ticks(struct gcc_mux *gcc, unsigned int ticks)
{
uint32_t val;

writel(ticks, gcc->base + gcc->debug_ctl_reg);
writel(ticks, gcc->mux.base + gcc->debug_ctl_reg);
do {
val = readl(gcc->base + gcc->debug_status_reg);
val = readl(gcc->mux.base + gcc->debug_status_reg);
} while (val & BIT(25));

writel(ticks | BIT(20), gcc->base + gcc->debug_ctl_reg);
writel(ticks | BIT(20), gcc->mux.base + gcc->debug_ctl_reg);
do {
val = readl(gcc->base + gcc->debug_status_reg);
val = readl(gcc->mux.base + gcc->debug_status_reg);
} while (!(val & BIT(25)));

val &= 0x1ffffff;

writel(ticks, gcc->base + gcc->debug_ctl_reg);
writel(ticks, gcc->mux.base + gcc->debug_ctl_reg);

return val;
}
Expand All @@ -92,6 +83,9 @@ static void mux_prepare_enable(struct debug_mux *mux, int selector)
}

mux_enable(mux);

if (mux->parent)
mux_prepare_enable(mux->parent, mux->parent_mux_val);
}

void mux_enable(struct debug_mux *mux)
Expand All @@ -103,17 +97,14 @@ void mux_enable(struct debug_mux *mux)
val |= mux->enable_mask;
writel(val, mux->base + mux->enable_reg);
}

if (mux->premeasure)
mux->premeasure(mux);
}

void mux_disable(struct debug_mux *mux)
{
uint32_t val;

if (mux->postmeasure)
mux->postmeasure(mux);
if (mux->parent)
mux_disable(mux->parent);

if (mux->enable_mask) {
val = readl(mux->base + mux->enable_reg);
Expand All @@ -122,35 +113,21 @@ void mux_disable(struct debug_mux *mux)
}
}

static bool leaf_enabled(struct debug_mux *mux, struct debug_mux *leaf)
{
uint32_t val;

/* If no AHB clock is specified, we assume it's clocked */
if (!leaf || !leaf->ahb_mask)
return true;

val = readl(mux->base + leaf->ahb_reg);
val &= leaf->ahb_mask;

/* CLK_OFF will be set if block is not clocked, so inverse */
return !val;
}

static unsigned long measure_default(const struct measure_clk *clk)
unsigned long measure_gcc(const struct measure_clk *clk,
const struct debug_mux *mux)
{
unsigned long raw_count_short;
unsigned long raw_count_full;
struct debug_mux *gcc = clk->primary;
struct gcc_mux *gcc = container_of(mux, struct gcc_mux, mux);
unsigned long xo_div4;

xo_div4 = readl(gcc->base + gcc->xo_div4_reg);
writel(xo_div4 | 1, gcc->base + gcc->xo_div4_reg);
xo_div4 = readl(mux->base + gcc->xo_div4_reg);
writel(xo_div4 | 1, mux->base + gcc->xo_div4_reg);

raw_count_short = measure_ticks(gcc, 0x1000);
raw_count_full = measure_ticks(gcc, 0x10000);

writel(xo_div4, gcc->base + gcc->xo_div4_reg);
writel(xo_div4, mux->base + gcc->xo_div4_reg);

if (raw_count_full == raw_count_short) {
return 0;
Expand All @@ -159,49 +136,49 @@ static unsigned long measure_default(const struct measure_clk *clk)
raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
raw_count_full = raw_count_full / ((0x10000 * 10) + 35);

if (clk->leaf && clk->leaf->div_val)
raw_count_full *= clk->leaf->div_val;
if (mux->div_val)
raw_count_full *= mux->div_val;

if (clk->primary->div_val)
raw_count_full *= clk->primary->div_val;
return raw_count_full;
}

if (clk->fixed_div)
raw_count_full *= clk->fixed_div;
unsigned long measure_leaf(const struct measure_clk *clk,
const struct debug_mux *mux)
{
unsigned long count;

if (!mux->parent) {
printf("No parent in measure_leaf, mux '%s'\n", mux->block_name ? : "gcc");
return 0;
}

count = mux->parent->measure(clk, mux->parent);

return raw_count_full;
if (mux->div_val)
count *= mux->div_val;

return count;
}

unsigned long measure_mccc(const struct measure_clk *clk)
unsigned long measure_mccc(const struct measure_clk *clk,
const struct debug_mux *mux)
{
/* MCCC is always on, just read the rate and return. */
return 1000000000000ULL / readl(clk->leaf->base + clk->leaf_mux);
return 1000000000000ULL / readl(clk->clk_mux->base + clk->mux);
}

static void measure(const struct measure_clk *clk)
{
unsigned long clk_rate;
struct debug_mux *gcc = clk->primary;

if (!leaf_enabled(gcc, clk->leaf)) {
printf("%50s: skipping\n", clk->name);
return;
}

if (clk->leaf)
mux_prepare_enable(clk->leaf, clk->leaf_mux);
mux_prepare_enable(clk->clk_mux, clk->mux);

mux_prepare_enable(clk->primary, clk->mux);
clk_rate = clk->clk_mux->measure(clk, clk->clk_mux);

if (clk->leaf && clk->leaf->measure)
clk_rate = clk->leaf->measure(clk);
else
clk_rate = measure_default(clk);

mux_disable(clk->primary);
if (clk->fixed_div)
clk_rate *= clk->fixed_div;

if (clk->leaf)
mux_disable(clk->leaf);
mux_disable(clk->clk_mux);

if (clk_rate == 0) {
printf("%50s: off\n", clk->name);
Expand Down Expand Up @@ -265,8 +242,8 @@ static const struct measure_clk *find_clock(const struct debugcc_platform *platf
static bool clock_from_block(const struct measure_clk *clk, const char *block_name)
{
return !block_name ||
(!clk->leaf && !strcmp(block_name, CORE_CC_BLOCK)) ||
(clk->leaf && clk->leaf->block_name && !strcmp(block_name, clk->leaf->block_name));
(!clk->clk_mux && !strcmp(block_name, CORE_CC_BLOCK)) ||
(clk->clk_mux && clk->clk_mux->block_name && !strcmp(block_name, clk->clk_mux->block_name));
}

static void list_clocks_block(const struct debugcc_platform *platform, const char *block_name)
Expand All @@ -277,8 +254,8 @@ static void list_clocks_block(const struct debugcc_platform *platform, const cha
if (!clock_from_block(clk, block_name))
continue;

if (clk->leaf && clk->leaf->block_name)
printf("%-40s %s\n", clk->name, clk->leaf->block_name);
if (clk->clk_mux && clk->clk_mux->block_name)
printf("%-40s %s\n", clk->name, clk->clk_mux->block_name);
else
printf("%s\n", clk->name);
}
Expand All @@ -296,7 +273,7 @@ int mmap_mux(int devmem, struct debug_mux *mux)
return -1;
}

return 0;
return mmap_mux(devmem, mux->parent);
}

/**
Expand All @@ -312,11 +289,7 @@ static int mmap_hardware(int devmem, const struct debugcc_platform *platform)
int ret;

for (clk = platform->clocks; clk->name; clk++) {
ret = mmap_mux(devmem, clk->primary);
if (ret < 0)
return ret;

ret = mmap_mux(devmem, clk->leaf);
ret = mmap_mux(devmem, clk->clk_mux);
if (ret < 0)
return ret;
}
Expand Down
45 changes: 32 additions & 13 deletions debugcc.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ struct debug_mux {
const char *block_name;
size_t size;

struct debug_mux *parent;
unsigned long parent_mux_val;

unsigned int enable_reg;
unsigned int enable_mask;

Expand All @@ -55,25 +58,22 @@ struct debug_mux {
unsigned int div_mask;
unsigned int div_val;

unsigned long (*measure)(const struct measure_clk *clk,
const struct debug_mux *mux);
};

struct gcc_mux {
struct debug_mux mux;

unsigned int xo_div4_reg;
unsigned int debug_ctl_reg;
unsigned int debug_status_reg;

unsigned int ahb_reg;
unsigned int ahb_mask;

void (*premeasure)(struct debug_mux *mux);
unsigned long (*measure)(const struct measure_clk *clk);
void (*postmeasure)(struct debug_mux *mux);
};

struct measure_clk {
char *name;
struct debug_mux *primary;
int mux;

struct debug_mux *leaf;
int leaf_mux;
struct debug_mux *clk_mux;
unsigned long mux;

unsigned int fixed_div;
};
Expand All @@ -84,10 +84,29 @@ struct debugcc_platform {
int (*premap)(int devmem);
};

#define container_of(ptr, type, member) \
((type *) ((char *)(ptr) - offsetof(type, member)))

static inline uint32_t readl(void *ptr)
{
return *((volatile uint32_t*)ptr);
}

static inline void writel(uint32_t val, void *ptr)
{
*((volatile uint32_t*)ptr) = val;
}

int mmap_mux(int devmem, struct debug_mux *mux);
void mux_enable(struct debug_mux *mux);
void mux_disable(struct debug_mux *mux);
unsigned long measure_mccc(const struct measure_clk *clk);

unsigned long measure_gcc(const struct measure_clk *clk,
const struct debug_mux *mux);
unsigned long measure_leaf(const struct measure_clk *clk,
const struct debug_mux *mux);
unsigned long measure_mccc(const struct measure_clk *clk,
const struct debug_mux *mux);

extern const struct debugcc_platform *platforms[];

Expand Down
Loading

0 comments on commit cf5664f

Please sign in to comment.