Skip to content

Commit

Permalink
(wip) clk: bcm-kona: implement full CCU initialization sequence
Browse files Browse the repository at this point in the history
*Still* doesn't fix the clock issues, actually, now it prints a message about
being unable to start the policy engine...

Signed-off-by: Artur Weber <aweber@dithernet.org>
  • Loading branch information
refractionware committed Jan 7, 2023
1 parent c8445f6 commit bf88ab3
Show file tree
Hide file tree
Showing 3 changed files with 270 additions and 0 deletions.
85 changes: 85 additions & 0 deletions drivers/clk/bcm/clk-bcm21664.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,33 @@ static struct ccu_data aon_ccu_data = {
.policy = {
.enable = CCU_LVM_EN(0x0034, 0),
.control = CCU_POLICY_CTL(0x000c, 0, 1, 2),
.mask = CCU_POLICY_MASK(0x0010, 0),
},
.voltage = {
CCU_VOLTAGE_OFFSET(0x0040, 0x0044),
.voltage_table = {
CCU_VOLTAGE_ECO,
CCU_VOLTAGE_ECO,
CCU_VOLTAGE_ECO,
CCU_VOLTAGE_ECO,
CCU_VOLTAGE_ECO,
},
.voltage_table_len = 5,
},
.peri_volt = {
.offset = 0x0030,
.peri_volt_table = {
CCU_PERI_VOLT_NORMAL,
CCU_PERI_VOLT_HIGH,
},
.peri_volt_table_len = 2,
},
.freq_policy = {
.offset = 0x0008,
.freq_policy_table = {
1, 1, 2, 2 /* ECO, ECO, NORMAL, NORMAL */
},
.freq_policy_table_len = 4,
},
.kona_clks = {
[BCM21664_AON_CCU_HUB_TIMER] =
Expand Down Expand Up @@ -140,6 +167,36 @@ static struct ccu_data master_ccu_data = {
.policy = {
.enable = CCU_LVM_EN(0x0034, 0),
.control = CCU_POLICY_CTL(0x000c, 0, 1, 2),
.mask = CCU_POLICY_MASK(0x0010, 0),
},
.voltage = {
CCU_VOLTAGE_OFFSET(0x0040, 0x0044),
.voltage_table = {
CCU_VOLTAGE_ECO,
CCU_VOLTAGE_ECO,
CCU_VOLTAGE_ECO,
CCU_VOLTAGE_ECO,
CCU_VOLTAGE_ECO,
CCU_VOLTAGE_ECO,
CCU_VOLTAGE_ECO,
CCU_VOLTAGE_ECO,
},
.voltage_table_len = 8,
},
.peri_volt = {
.offset = 0x0030,
.peri_volt_table = {
CCU_PERI_VOLT_NORMAL,
CCU_PERI_VOLT_HIGH,
},
.peri_volt_table_len = 2,
},
.freq_policy = {
.offset = 0x0008,
.freq_policy_table = {
2, 2, 3, 3 /* ECO, ECO, NORMAL, NORMAL */
},
.freq_policy_table_len = 4,
},
.kona_clks = {
[BCM21664_MASTER_CCU_SDIO1] =
Expand Down Expand Up @@ -243,6 +300,34 @@ static struct ccu_data slave_ccu_data = {
.policy = {
.enable = CCU_LVM_EN(0x0034, 0),
.control = CCU_POLICY_CTL(0x000c, 0, 1, 2),
.mask = CCU_POLICY_MASK(0x0010, 0),
},
.voltage = {
CCU_VOLTAGE_OFFSET(0x0040, 0x0044),
.voltage_table = {
CCU_VOLTAGE_ECO,
CCU_VOLTAGE_ECO,
CCU_VOLTAGE_ECO,
CCU_VOLTAGE_ECO,
CCU_VOLTAGE_ECO,
CCU_VOLTAGE_ECO,
},
.voltage_table_len = 6,
},
.peri_volt = {
.offset = 0x0030,
.peri_volt_table = {
CCU_PERI_VOLT_NORMAL,
CCU_PERI_VOLT_HIGH,
},
.peri_volt_table_len = 2,
},
.freq_policy = {
.offset = 0x0008,
.freq_policy_table = {
1, 1, 3, 3 /* ECO, ECO, NORMAL, NORMAL */
},
.freq_policy_table_len = 4,
},
.kona_clks = {
[BCM21664_SLAVE_CCU_UARTB] =
Expand Down
110 changes: 110 additions & 0 deletions drivers/clk/bcm/clk-kona.c
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,75 @@ static int selector_write(struct ccu_data *ccu, struct bcm_clk_gate *gate,
return ret;
}

/* CCU operations */

static void kona_ccu_set_voltage(struct ccu_data *ccu, int voltage_reg_num,
u8 voltage_policy_id)
{
unsigned long flags;
u32 offset;
u32 value;
u8 shift;

flags = ccu_lock(ccu);

if (voltage_reg_num <= 3) {
shift = voltage_reg_num << 3;
offset = ccu->voltage.offset1;
} else if ((voltage_reg_num <= 7) && ccu->voltage.offset2) {
shift = (voltage_reg_num - 4) << 3;
offset = ccu->voltage.offset2;
} else {
BUG();
}

value = __ccu_read(ccu, offset);
value = (value & ~(0xF << shift)) |
((voltage_policy_id & 0xF) << shift);

__ccu_write(ccu, offset, value);

ccu_unlock(ccu, flags);
}

static void kona_ccu_set_peri_voltage(struct ccu_data *ccu, u8 peri_volt_reg_num,
u8 peri_volt_policy_id)
{
unsigned long flags;
u32 value;
u8 shift;

flags = ccu_lock(ccu);

shift = peri_volt_reg_num << 3;
value = __ccu_read(ccu, ccu->peri_volt.offset);
value = (value & ~(0xF << shift)) |
((peri_volt_policy_id & 0xF) << shift);

__ccu_write(ccu, ccu->peri_volt.offset, value);

ccu_unlock(ccu, flags);
}

static void kona_ccu_set_freq_policy(struct ccu_data *ccu, u8 freq_policy_reg_num,
u8 freq_policy_policy_id)
{
unsigned long flags;
u32 value;
u8 shift;

flags = ccu_lock(ccu);

shift = freq_policy_reg_num << 3;
value = __ccu_read(ccu, ccu->freq_policy.offset);
value = (value & ~(0x7 << shift)) |
(freq_policy_policy_id << shift);

__ccu_write(ccu, ccu->freq_policy.offset, value);

ccu_unlock(ccu, flags);
}

/* Clock operations */

static int kona_peri_clk_enable(struct clk_hw *hw)
Expand Down Expand Up @@ -1254,7 +1323,48 @@ bool __init kona_ccu_init(struct ccu_data *ccu)

flags = ccu_lock(ccu);
__ccu_write_enable(ccu);
if (!__ccu_policy_engine_stop(ccu))
pr_err("Could not stop policy engine");

/* Enable all policies */

This comment has been minimized.

Copy link
@knuxify

knuxify Feb 8, 2023

even downstream says this is a hack of dubious utility; i think how this works is somewhat similar to the .policy member of peripheral clocks, so this is better implemented there...? unless this is required, since it goes over all CCU policies, not just the first one. what does mainline do there anyways? investigate

if (ccu_policy_exists(&ccu->policy)) {
for (which = 0; which < CCU_POLICY_MAX; which++) {
if (ccu->policy.mask.mask1_offset != 0)
__ccu_write(ccu, ccu->policy.mask.mask1_offset + (4 * which),
CCU_POLICY_ENABLE_ALL);

if (ccu->policy.mask.mask2_offset != 0)
__ccu_write(ccu, ccu->policy.mask.mask2_offset + (4 * which),
CCU_POLICY_ENABLE_ALL);
}
}

/* Set voltage from voltage tables */
if (ccu_voltage_exists(&ccu->voltage)) {
for (which = 0; which < ccu->voltage.voltage_table_len; which++) {
kona_ccu_set_voltage(ccu, which, ccu->voltage.voltage_table[which]);
}
}

/* Set peripheral voltage from voltage tables */
if (ccu_peri_volt_exists(&ccu->peri_volt)) {
for (which = 0; which < ccu->peri_volt.peri_volt_table_len; which++) {
kona_ccu_set_peri_voltage(ccu, which,
ccu->peri_volt.peri_volt_table[which]);
}
}

/* Set peripheral voltage from voltage tables */
if (ccu_freq_policy_exists(&ccu->freq_policy)) {
for (which = 0; which < ccu->freq_policy.freq_policy_table_len; which++) {
kona_ccu_set_freq_policy(ccu, which,
ccu->freq_policy.freq_policy_table[which]);
}
}

__ccu_policy_engine_start(ccu, true);

/* Initialize clocks */
for (which = 0; which < ccu->clk_num; which++) {
struct kona_clk *bcm_clk = &kona_clks[which];

Expand Down
75 changes: 75 additions & 0 deletions drivers/clk/bcm/clk-kona.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
/* CCU field state tests */

#define ccu_policy_exists(ccu_policy) ((ccu_policy)->enable.offset != 0)
#define ccu_voltage_exists(ccu_voltage) ((ccu_voltage)->offset1 != 0)
#define ccu_peri_volt_exists(ccu_peri_volt) ((ccu_peri_volt)->offset != 0)
#define ccu_freq_policy_exists(ccu_freq_policy) ((ccu_freq_policy)->offset != 0)

/* Clock field state tests */

Expand Down Expand Up @@ -453,9 +456,78 @@ struct bcm_policy_ctl {
.atl_bit = (_atl_bit), \
}


/* CCU policy masks */
enum {
CCU_POLICY_0,
CCU_POLICY_1,
CCU_POLICY_2,
CCU_POLICY_3,
CCU_POLICY_MAX,
};

#define CCU_POLICY_ENABLE_ALL 0x7FFFFFFF

struct bcm_policy_mask {
u32 mask1_offset;
u32 mask2_offset;
};

/* Policy mask initialization macro */
#define CCU_POLICY_MASK(_mask1_offset, _mask2_offset) \
{ \
.mask1_offset = (_mask1_offset), \
.mask2_offset = (_mask2_offset), \
}


struct ccu_policy {
struct bcm_lvm_en enable;
struct bcm_policy_ctl control;
struct bcm_policy_mask mask;
};

/* CCU voltage policy IDs */
#define CCU_VOLATGE_OFF 0x0
#define CCU_VOLTAGE_RETN 0x1
#define CCU_VOLTAGE_WAKEUP 0x2

#define CCU_VOLTAGE_ECO 0x9
#define CCU_VOLTAGE_NORMAL 0xB
#define CCU_VOLTAGE_TURBO 0xD
#define CCU_VOLTAGE_SUPER_TURBO 0xF

#define CCU_VOLTAGE_A9_ECO 0x8
#define CCU_VOLTAGE_A9_NORMAL 0xA
#define CCU_VOLTAGE_A9_TURBO 0xC
#define CCU_VOLTAGE_A9_SUPER_TURBO 0xE

#define CCU_VOLTAGE_OFFSET(_offset1, _offset2) \
.offset1 = _offset1, \
.offset2 = _offset2

struct ccu_voltage {
u32 offset1; /* 0-3 */
u32 offset2; /* 4-7 */
u32 voltage_table[8]; /* Array of voltage IDs */
size_t voltage_table_len;
};

/* CCU peripheral voltage policy IDs */
#define CCU_PERI_VOLT_NORMAL 0
#define CCU_PERI_VOLT_HIGH 0

struct ccu_peri_volt {
u32 offset;
u32 peri_volt_table[2];
size_t peri_volt_table_len;
};

/* CCU frequency policy data */
struct ccu_freq_policy {
u32 offset;
u32 freq_policy_table[4];
size_t freq_policy_table_len;
};

/*
Expand All @@ -472,6 +544,9 @@ struct ccu_data {
spinlock_t lock; /* serialization lock */
bool write_enabled; /* write access is currently enabled */
struct ccu_policy policy;
struct ccu_voltage voltage;
struct ccu_peri_volt peri_volt;
struct ccu_freq_policy freq_policy;
struct device_node *node;
size_t clk_num;
const char *name;
Expand Down

0 comments on commit bf88ab3

Please sign in to comment.