Index: sys/arm/xilinx/zy7_slcr.c =================================================================== --- sys/arm/xilinx/zy7_slcr.c +++ sys/arm/xilinx/zy7_slcr.c @@ -215,19 +215,39 @@ cgem_set_ref_clk(int unit, int frequency) { struct zy7_slcr_softc *sc = zy7_slcr_softc_p; + uint32_t clk_reg_val; + int base_frequency; int div0, div1; if (!sc) return (-1); + clk_reg_val = RD4(sc, unit ? ZY7_SLCR_GEM1_CLK_CTRL : + ZY7_SLCR_GEM0_CLK_CTRL); + switch (clk_reg_val & ZY7_SLCR_GEM_CLK_CTRL_SRCSEL_MASK) { + case ZY7_SLCR_GEM_CLK_CTRL_SRCSEL_EMIO_CLK: + /* Do not touch clock divisors if clock is from EMIO. */ + return (0); + case ZY7_SLCR_GEM_CLK_CTRL_SRCSEL_ARM_PLL: + base_frequency = arm_pll_frequency; + break; + case ZY7_SLCR_GEM_CLK_CTRL_SRCSEL_DDR_PLL: + base_frequency = ddr_pll_frequency; + break; + case ZY7_SLCR_GEM_CLK_CTRL_SRCSEL_IO_PLL: + default: + base_frequency = io_pll_frequency; + break; + } + /* Find suitable divisor pairs. Round result to nearest khz * to test for match. */ for (div1 = 1; div1 <= ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_MAX; div1++) { - div0 = (io_pll_frequency + div1 * frequency / 2) / + div0 = (base_frequency + div1 * frequency / 2) / div1 / frequency; if (div0 > 0 && div0 <= ZY7_SLCR_GEM_CLK_CTRL_DIVISOR_MAX && - ((io_pll_frequency / div0 / div1) + 500) / 1000 == + ((base_frequency / div0 / div1) + 500) / 1000 == (frequency + 500) / 1000) break; } @@ -240,12 +260,12 @@ /* Unlock SLCR registers. */ zy7_slcr_unlock(sc); - /* Modify GEM reference clock. */ + /* Modify GEM reference clock divisors. */ + clk_reg_val &= ~(ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_MASK | + ZY7_SLCR_GEM_CLK_CTRL_DIVISOR_MASK); WR4(sc, unit ? ZY7_SLCR_GEM1_CLK_CTRL : ZY7_SLCR_GEM0_CLK_CTRL, - (div1 << ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_SHIFT) | - (div0 << ZY7_SLCR_GEM_CLK_CTRL_DIVISOR_SHIFT) | - ZY7_SLCR_GEM_CLK_CTRL_SRCSEL_IO_PLL | - ZY7_SLCR_GEM_CLK_CTRL_CLKACT); + clk_reg_val | (div1 << ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_SHIFT) | + (div0 << ZY7_SLCR_GEM_CLK_CTRL_DIVISOR_SHIFT)); /* Lock SLCR registers. */ zy7_slcr_lock(sc);