Index: sys/arm/allwinner/clk/aw_debeclk.c =================================================================== --- sys/arm/allwinner/clk/aw_debeclk.c +++ sys/arm/allwinner/clk/aw_debeclk.c @@ -209,6 +209,12 @@ m = howmany(fin, *fout) - 1; + *fout = fin / (m + 1); + *stop = 1; + + if ((flags & CLK_SET_DRYRUN) != 0) + return (0); + DEVICE_LOCK(sc); DEBECLK_READ(sc, &val); val &= ~CLK_RATIO_M; @@ -216,9 +222,6 @@ DEBECLK_WRITE(sc, val); DEVICE_UNLOCK(sc); - *fout = fin / (m + 1); - *stop = 1; - return (0); } Index: sys/arm/allwinner/clk/aw_hdmiclk.c =================================================================== --- sys/arm/allwinner/clk/aw_hdmiclk.c +++ sys/arm/allwinner/clk/aw_hdmiclk.c @@ -188,6 +188,12 @@ if (best_diff == (int64_t)*fout) return (ERANGE); + *fout = fin / (1 << best_n) / (best_m + 1); + *stop = 1; + + if ((flags & CLK_SET_DRYRUN) != 0) + return (0); + DEVICE_LOCK(sc); HDMICLK_READ(sc, &val); val &= ~(CLK_RATIO_N | CLK_RATIO_M); @@ -196,9 +202,6 @@ HDMICLK_WRITE(sc, val); DEVICE_UNLOCK(sc); - *fout = fin / (1 << best_n) / (best_m + 1); - *stop = 1; - return (0); } Index: sys/arm/allwinner/clk/aw_lcdclk.c =================================================================== --- sys/arm/allwinner/clk/aw_lcdclk.c +++ sys/arm/allwinner/clk/aw_lcdclk.c @@ -389,56 +389,69 @@ int flags, int *stop) { struct aw_lcdclk_softc *sc; + struct clknode *parent_clk; + const char **parent_names; uint64_t pll_freq; uint32_t val, src_sel; int error, tcon_pll_div; sc = clknode_get_softc(clk); - switch (sc->type) { - case AW_LCD_CH0: + if (sc->type == AW_LCD_CH0) { *stop = 0; - break; - case AW_LCD_CH1: - if (sc->id != CLK_IDX_CH1_SCLK2) - return (ENXIO); + return (0); + } - src_sel = calc_tcon_pll(fin, *fout, &pll_freq, &tcon_pll_div); + if (sc->id != CLK_IDX_CH1_SCLK2) + return (ENXIO); - /* Switch parent clock if necessary */ - if (src_sel != clknode_get_parent_idx(clk)) { - error = clknode_set_parent_by_idx(clk, src_sel); - if (error != 0) - return (error); - } + src_sel = calc_tcon_pll(fin, *fout, &pll_freq, &tcon_pll_div); - error = clknode_set_freq(clknode_get_parent(clk), pll_freq, - 0, 0); - if (error != 0) - return (error); + parent_names = clknode_get_parent_names(clk); + parent_clk = clknode_find_by_name(parent_names[src_sel]); - error = clknode_enable(clknode_get_parent(clk)); - if (error != 0) - return (error); + if (parent_clk == NULL) + return (ERANGE); - /* Fetch new input frequency */ - error = clknode_get_freq(clknode_get_parent(clk), &pll_freq); - if (error != 0) - return (error); + /* Fetch input frequency */ + error = clknode_get_freq(parent_clk, &pll_freq); + if (error != 0) + return (error); - /* Set LCD divisor */ - DEVICE_LOCK(sc); - LCDCLK_READ(sc, &val); - val &= ~CH1_CLK_DIV_RATIO_M; - val |= ((tcon_pll_div - 1) << CH1_CLK_DIV_RATIO_M_SHIFT); - LCDCLK_WRITE(sc, val); - DEVICE_UNLOCK(sc); + *fout = pll_freq / tcon_pll_div; + *stop = 1; - *fout = pll_freq / tcon_pll_div; - *stop = 1; + if ((flags & CLK_SET_DRYRUN) != 0) + return (0); - break; - } + /* Switch parent clock if necessary */ + error = clknode_set_parent_by_idx(clk, src_sel); + if (error != 0) + return (error); + + error = clknode_set_freq(parent_clk, pll_freq, + 0, 0); + if (error != 0) + return (error); + + /* Fetch new input frequency */ + error = clknode_get_freq(parent_clk, &pll_freq); + if (error != 0) + return (error); + + *fout = pll_freq / tcon_pll_div; + + error = clknode_enable(parent_clk); + if (error != 0) + return (error); + + /* Set LCD divisor */ + DEVICE_LOCK(sc); + LCDCLK_READ(sc, &val); + val &= ~CH1_CLK_DIV_RATIO_M; + val |= ((tcon_pll_div - 1) << CH1_CLK_DIV_RATIO_M_SHIFT); + LCDCLK_WRITE(sc, val); + DEVICE_UNLOCK(sc); return (0); } Index: sys/arm/allwinner/clk/aw_mmcclk.c =================================================================== --- sys/arm/allwinner/clk/aw_mmcclk.c +++ sys/arm/allwinner/clk/aw_mmcclk.c @@ -77,6 +77,20 @@ bus_addr_t reg; }; +struct phase_clk { + uint64_t freq; + int parent_idx; + uint32_t ophase; + uint32_t phase; + uint32_t n; +}; + +static struct phase_clk aw_mmcclk_phase[] = { + {400000, CLK_SRC_SEL_OSC24M, 0, 0, 2}, + {25000000, CLK_SRC_SEL_PLL6, 0, 5, 2}, + {52000000, CLK_SRC_SEL_PLL6, 3, 5, 0}, +}; + #define MODCLK_READ(sc, val) CLKDEV_READ_4((sc)->clkdev, (sc)->reg, (val)) #define MODCLK_WRITE(sc, val) CLKDEV_WRITE_4((sc)->clkdev, (sc)->reg, (val)) #define DEVICE_LOCK(sc) CLKDEV_DEVICE_LOCK((sc)->clkdev) @@ -166,8 +180,10 @@ int flags, int *stop) { struct aw_mmcclk_sc *sc; - uint32_t val, m, n, phase, ophase; - int parent_idx, error; + struct clknode *parent_clk; + const char **parent_names; + uint32_t val, m; + int parent_idx, error, phase; sc = clknode_get_softc(clk); @@ -175,52 +191,49 @@ * The ophase/phase values should be set by the MMC driver, but * there is currently no way to do this with the clk API */ - if (*fout <= 400000) { - parent_idx = CLK_SRC_SEL_OSC24M; - ophase = 0; - phase = 0; - n = 2; - } else if (*fout <= 25000000) { - parent_idx = CLK_SRC_SEL_PLL6; - ophase = 0; - phase = 5; - n = 2; - } else if (*fout <= 52000000) { - parent_idx = CLK_SRC_SEL_PLL6; - ophase = 3; - phase = 5; - n = 0; - } else + for (phase = 0; phase < nitems(aw_mmcclk_phase); phase++) { + if (*fout <= aw_mmcclk_phase[phase].freq) + break; + } + + if (phase == nitems(aw_mmcclk_phase)) return (ERANGE); - /* Switch parent clock, if necessary */ - if (parent_idx != clknode_get_parent_idx(clk)) { - error = clknode_set_parent_by_idx(clk, parent_idx); - if (error != 0) - return (error); + parent_names = clknode_get_parent_names(clk); + parent_idx = aw_mmcclk_phase[phase].parent_idx; + parent_clk = clknode_find_by_name(parent_names[parent_idx]); - /* Fetch new input frequency */ - error = clknode_get_freq(clknode_get_parent(clk), &fin); - if (error != 0) - return (error); - } + if (parent_clk == NULL) + return (ERANGE); - m = ((fin / (1 << n)) / *fout) - 1; + error = clknode_get_freq(parent_clk, &fin); + if (error != 0) + return (error); + + m = ((fin / (1 << aw_mmcclk_phase[phase].n)) / *fout) - 1; + + *fout = fin / (1 << aw_mmcclk_phase[phase].n) / (m + 1); + *stop = 1; + + if ((flags & CLK_SET_DRYRUN) != 0) + return (0); + + /* Switch to the correct parent if needed */ + error = clknode_set_parent_by_idx(clk, parent_idx); + if (error != 0) + return (error); DEVICE_LOCK(sc); MODCLK_READ(sc, &val); val &= ~(CLK_RATIO_N | CLK_RATIO_M | CLK_PHASE_CTR | OUTPUT_CLK_PHASE_CTR); - val |= (n << CLK_RATIO_N_SHIFT); + val |= (aw_mmcclk_phase[phase].n << CLK_RATIO_N_SHIFT); val |= (m << CLK_RATIO_M_SHIFT); - val |= (phase << CLK_PHASE_CTR_SHIFT); - val |= (ophase << OUTPUT_CLK_PHASE_CTR_SHIFT); + val |= (aw_mmcclk_phase[phase].phase << CLK_PHASE_CTR_SHIFT); + val |= (aw_mmcclk_phase[phase].ophase << OUTPUT_CLK_PHASE_CTR_SHIFT); MODCLK_WRITE(sc, val); DEVICE_UNLOCK(sc); - *fout = fin / (1 << n) / (m + 1); - *stop = 1; - return (0); } Index: sys/arm/allwinner/clk/aw_modclk.c =================================================================== --- sys/arm/allwinner/clk/aw_modclk.c +++ sys/arm/allwinner/clk/aw_modclk.c @@ -68,7 +68,6 @@ 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 +101,7 @@ sc = clknode_get_softc(clk); - if (index < 0 || index >= sc->parent_cnt) + if (index < 0 || index >= clknode_get_parents_num(clk)) return (ERANGE); DEVICE_LOCK(sc); @@ -160,6 +159,8 @@ int flags, int *stop) { struct aw_modclk_sc *sc; + struct clknode *parent_clk, *best_parent; + const char **parent_names; uint32_t val, m, n, src, best_m, best_n, best_src; uint64_t cur_freq; int64_t best_diff, cur_diff; @@ -170,11 +171,12 @@ best_diff = (int64_t)*fout; best_src = 0; - for (src = 0; src < sc->parent_cnt; src++) { - error = clknode_set_parent_by_idx(clk, src); - if (error != 0) + parent_names = clknode_get_parent_names(clk); + for (src = 0; src < clknode_get_parents_num(clk); src++) { + parent_clk = clknode_find_by_name(parent_names[src]); + if (parent_clk == NULL) continue; - error = clknode_get_freq(clknode_get_parent(clk), &fin); + error = clknode_get_freq(parent_clk, &fin); if (error != 0) continue; @@ -184,6 +186,7 @@ cur_diff = (int64_t)*fout - cur_freq; if (cur_diff >= 0 && cur_diff < best_diff) { best_src = src; + best_parent = parent_clk; best_diff = cur_diff; best_m = m; best_n = n; @@ -194,10 +197,17 @@ if (best_diff == (int64_t)*fout) return (ERANGE); - error = clknode_set_parent_by_idx(clk, best_src); + error = clknode_get_freq(best_parent, &fin); if (error != 0) return (error); - error = clknode_get_freq(clknode_get_parent(clk), &fin); + + *fout = fin / (1 << best_n) / (best_m + 1); + *stop = 1; + + if ((flags & CLK_SET_DRYRUN) != 0) + return (0); + + error = clknode_set_parent_by_idx(clk, best_src); if (error != 0) return (error); @@ -209,9 +219,6 @@ MODCLK_WRITE(sc, val); DEVICE_UNLOCK(sc); - *fout = fin / (1 << best_n) / (best_m + 1); - *stop = 1; - return (0); } @@ -299,7 +306,6 @@ sc = clknode_get_softc(clk); sc->reg = paddr; sc->clkdev = device_get_parent(dev); - sc->parent_cnt = def.parent_cnt; clknode_register(clkdom, clk); Index: sys/arm/allwinner/clk/aw_pll.c =================================================================== --- sys/arm/allwinner/clk/aw_pll.c +++ sys/arm/allwinner/clk/aw_pll.c @@ -342,6 +342,9 @@ if (f == NULL) return (EINVAL); + if ((flags & CLK_SET_DRYRUN) != 0) + return (0); + DEVICE_LOCK(sc); PLL_READ(sc, &val); val &= ~(A10_PLL1_FACTOR_N|A10_PLL1_FACTOR_K|A10_PLL1_FACTOR_M| @@ -440,6 +443,9 @@ post_div = 4; n = (*fout * pre_div * post_div * 2) / (2 * fin); + if ((flags & CLK_SET_DRYRUN) != 0) + return (0); + DEVICE_LOCK(sc); PLL_READ(sc, &val); val &= ~(A10_PLL2_POST_DIV | A10_PLL2_FACTOR_N | A10_PLL2_PRE_DIV); @@ -497,6 +503,9 @@ *fout = m * A10_PLL3_REF_FREQ; } + if ((flags & CLK_SET_DRYRUN) != 0) + return (0); + DEVICE_LOCK(sc); PLL_READ(sc, &val); val &= ~(A10_PLL3_MODE_SEL | A10_PLL3_FUNC_SET | A10_PLL3_FACTOR_M); @@ -699,6 +708,9 @@ post_div = 4; n = (*fout * pre_div * post_div * 2) / (2 * fin); + if ((flags & CLK_SET_DRYRUN) != 0) + return (0); + DEVICE_LOCK(sc); PLL_READ(sc, &val); val &= ~(A13_PLL2_POST_DIV | A13_PLL2_FACTOR_N | A13_PLL2_PRE_DIV); @@ -765,6 +777,9 @@ if (f == NULL) return (EINVAL); + if ((flags & CLK_SET_DRYRUN) != 0) + return (0); + DEVICE_LOCK(sc); PLL_READ(sc, &val); val &= ~(H3_PLL2_POST_DIV|H3_PLL2_FACTOR_N|H3_PLL2_PRE_DIV); @@ -808,6 +823,9 @@ if (f == NULL) return (EINVAL); + if ((flags & CLK_SET_DRYRUN) != 0) + return (0); + DEVICE_LOCK(sc); PLL_READ(sc, &val); val &= ~(A23_PLL1_FACTOR_N|A23_PLL1_FACTOR_K|A23_PLL1_FACTOR_M| @@ -860,6 +878,9 @@ if (f == NULL) return (EINVAL); + if ((flags & CLK_SET_DRYRUN) != 0) + return (0); + DEVICE_LOCK(sc); PLL_READ(sc, &val); @@ -1067,6 +1088,9 @@ if (n < A83T_PLLCPUX_FACTOR_N_MIN || n > A83T_PLLCPUX_FACTOR_N_MAX) return (EINVAL); + if ((flags & CLK_SET_DRYRUN) != 0) + return (0); + DEVICE_LOCK(sc); PLL_READ(sc, &val); val &= ~A83T_PLLCPUX_FACTOR_N; Index: sys/arm/allwinner/clk/aw_thsclk.c =================================================================== --- sys/arm/allwinner/clk/aw_thsclk.c +++ sys/arm/allwinner/clk/aw_thsclk.c @@ -186,6 +186,9 @@ if (best_diff == (int64_t)*fout || best_n == 0) return (ERANGE); + if ((flags & CLK_SET_DRYRUN) != 0) + return (0); + DEVICE_LOCK(sc); THSCLK_READ(sc, &val); val &= ~CLK_DIV_RATIO;