MFC r304796, r308233 (jmcneill)
r304796: Switch parent clock when setting frequency if a new parent is a better candidate for the target rate. Reviewed by: andrew, manu r308233: The DTS may report fewer than 4 parents for a module clock. Avoid setting the module clock parent to an out-of-range index in these cases.
This commit is contained in:
parent
9add8f3256
commit
2dd6565094
@ -53,7 +53,6 @@ __FBSDID("$FreeBSD$");
|
||||
#define SCLK_GATING (1 << 31)
|
||||
#define CLK_SRC_SEL (0x3 << 24)
|
||||
#define CLK_SRC_SEL_SHIFT 24
|
||||
#define CLK_SRC_SEL_MAX 0x3
|
||||
#define CLK_RATIO_N (0x3 << 16)
|
||||
#define CLK_RATIO_N_SHIFT 16
|
||||
#define CLK_RATIO_N_MAX 0x3
|
||||
@ -69,6 +68,7 @@ static struct ofw_compat_data compat_data[] = {
|
||||
struct aw_modclk_sc {
|
||||
device_t clkdev;
|
||||
bus_addr_t reg;
|
||||
u_int parent_cnt;
|
||||
};
|
||||
|
||||
#define MODCLK_READ(sc, val) CLKDEV_READ_4((sc)->clkdev, (sc)->reg, (val))
|
||||
@ -102,7 +102,7 @@ aw_modclk_set_mux(struct clknode *clk, int index)
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
|
||||
if (index < 0 || index > CLK_SRC_SEL_MAX)
|
||||
if (index < 0 || index >= sc->parent_cnt)
|
||||
return (ERANGE);
|
||||
|
||||
DEVICE_LOCK(sc);
|
||||
@ -160,28 +160,47 @@ aw_modclk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
|
||||
int flags, int *stop)
|
||||
{
|
||||
struct aw_modclk_sc *sc;
|
||||
uint32_t val, m, n, best_m, best_n;
|
||||
uint32_t val, m, n, src, best_m, best_n, best_src;
|
||||
uint64_t cur_freq;
|
||||
int64_t best_diff, cur_diff;
|
||||
int error;
|
||||
|
||||
sc = clknode_get_softc(clk);
|
||||
best_n = best_m = 0;
|
||||
best_diff = (int64_t)*fout;
|
||||
best_src = 0;
|
||||
|
||||
for (n = 0; n <= CLK_RATIO_N_MAX; n++)
|
||||
for (m = 0; m <= CLK_RATIO_M_MAX; m++) {
|
||||
cur_freq = fin / (1 << n) / (m + 1);
|
||||
cur_diff = (int64_t)*fout - cur_freq;
|
||||
if (cur_diff >= 0 && cur_diff < best_diff) {
|
||||
best_diff = cur_diff;
|
||||
best_m = m;
|
||||
best_n = n;
|
||||
for (src = 0; src < sc->parent_cnt; src++) {
|
||||
error = clknode_set_parent_by_idx(clk, src);
|
||||
if (error != 0)
|
||||
continue;
|
||||
error = clknode_get_freq(clknode_get_parent(clk), &fin);
|
||||
if (error != 0)
|
||||
continue;
|
||||
|
||||
for (n = 0; n <= CLK_RATIO_N_MAX; n++)
|
||||
for (m = 0; m <= CLK_RATIO_M_MAX; m++) {
|
||||
cur_freq = fin / (1 << n) / (m + 1);
|
||||
cur_diff = (int64_t)*fout - cur_freq;
|
||||
if (cur_diff >= 0 && cur_diff < best_diff) {
|
||||
best_src = src;
|
||||
best_diff = cur_diff;
|
||||
best_m = m;
|
||||
best_n = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best_diff == (int64_t)*fout)
|
||||
return (ERANGE);
|
||||
|
||||
error = clknode_set_parent_by_idx(clk, best_src);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
error = clknode_get_freq(clknode_get_parent(clk), &fin);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
DEVICE_LOCK(sc);
|
||||
MODCLK_READ(sc, &val);
|
||||
val &= ~(CLK_RATIO_N | CLK_RATIO_M);
|
||||
@ -280,6 +299,7 @@ aw_modclk_attach(device_t dev)
|
||||
sc = clknode_get_softc(clk);
|
||||
sc->reg = paddr;
|
||||
sc->clkdev = device_get_parent(dev);
|
||||
sc->parent_cnt = def.parent_cnt;
|
||||
|
||||
clknode_register(clkdom, clk);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user