/** * zynq_clk_register_aper_clk() - Set up a APER clock with the framework * @clk: Pointer to struct clk for the clock * @ctrl: Clock control register * @name: PLL name */ static void zynq_clk_register_aper_clk(struct clk *clk, u32 *ctrl, char *name) { clk->name = name; clk->reg = ctrl; clk->parent = cpu_1x_clk; clk->frequency = zynq_clk_get_rate(clk->parent); }
/** * zynq_clk_periph_set_rate() - Set clock rate * @clk: Handle of the peripheral clock * @rate: New clock rate * Sets the clock frequency of @clk to @rate. Returns zero on success. */ static int zynq_clk_periph_set_rate(struct clk *clk, unsigned long rate) { u32 ctrl, div0 = 0, div1 = 0; unsigned long prate, new_rate, cur_rate = clk->frequency; ctrl = readl(clk->reg); prate = zynq_clk_get_rate(clk->parent); ctrl &= ~CLK_CTRL_DIV0_MASK; if (clk->flags & ZYNQ_CLK_FLAGS_HAS_2_DIVS) { ctrl &= ~CLK_CTRL_DIV1_MASK; new_rate = periph_calc_two_divs(cur_rate, rate, prate, &div0, &div1); ctrl |= div1 << CLK_CTRL_DIV1_SHIFT; } else { div0 = DIV_ROUND_CLOSEST(prate, rate); div0 &= ZYNQ_CLK_MAXDIV; new_rate = DIV_ROUND_CLOSEST(rate, div0); } /* write new divs to hardware */ ctrl |= div0 << CLK_CTRL_DIV0_SHIFT; writel(ctrl, clk->reg); /* update frequency in clk framework */ clk->frequency = new_rate; return 0; }
static void init_ddr_clocks(void) { u32 div0, div1; unsigned long prate = zynq_clk_get_rate(ddrpll_clk); u32 clk_ctrl = readl(&slcr_base->ddr_clk_ctrl); /* DDR2x */ clks[ddr2x_clk].reg = &slcr_base->ddr_clk_ctrl; clks[ddr2x_clk].parent = ddrpll_clk; clks[ddr2x_clk].name = "ddr_2x"; clks[ddr2x_clk].frequency = ddr2x_get_rate(&clks[ddr2x_clk]); clks[ddr2x_clk].ops.get_rate = ddr2x_get_rate; /* DDR3x */ clks[ddr3x_clk].reg = &slcr_base->ddr_clk_ctrl; clks[ddr3x_clk].parent = ddrpll_clk; clks[ddr3x_clk].name = "ddr_3x"; clks[ddr3x_clk].frequency = ddr3x_get_rate(&clks[ddr3x_clk]); clks[ddr3x_clk].ops.get_rate = ddr3x_get_rate; /* DCI */ clk_ctrl = readl(&slcr_base->dci_clk_ctrl); div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT; clks[dci_clk].reg = &slcr_base->dci_clk_ctrl; clks[dci_clk].parent = ddrpll_clk; clks[dci_clk].frequency = DIV_ROUND_CLOSEST( DIV_ROUND_CLOSEST(prate, div0), div1); clks[dci_clk].name = "dci"; gd->bd->bi_ddr_freq = clks[ddr3x_clk].frequency / 1000000; }
/** * ddr3x_get_rate() - Get clock rate of DDR3x clock * @clk: Clock handle * Returns the current clock rate of @clk. */ static unsigned long ddr3x_get_rate(struct clk *clk) { u32 clk_ctrl = readl(clk->reg); u32 div = (clk_ctrl & CLK_CTRL_DIV3X_MASK) >> CLK_CTRL_DIV3X_SHIFT; return DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div); }
/** * soc_clk_dump() - Print clock frequencies * Returns zero on success * * Implementation for the clk dump command. */ int soc_clk_dump(void) { int i; printf("clk\t\tfrequency\n"); for (i = 0; i < clk_max; i++) { const char *name = zynq_clk_get_name(i); if (name) printf("%10s%20lu\n", name, zynq_clk_get_rate(i)); } return 0; }
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { int is_dual; unsigned long lqspi_frequency; struct zynq_qspi_slave *qspi; debug("%s: bus: %d cs: %d max_hz: %d mode: %d\n", __func__, bus, cs, max_hz, mode); if (!spi_cs_is_valid(bus, cs)) return NULL; is_dual = zynq_qspi_check_is_dual_flash(); if (is_dual == MODE_UNKNOWN) { printf("%s: No QSPI device detected based on MIO settings\n", __func__); return NULL; } zynq_qspi_init_hw(is_dual, cs); qspi = spi_alloc_slave(struct zynq_qspi_slave, bus, cs); if (!qspi) { printf("%s: Fail to allocate zynq_qspi_slave\n", __func__); return NULL; } lqspi_frequency = zynq_clk_get_rate(lqspi_clk); if (!lqspi_frequency) { debug("Defaulting to 200000000 Hz qspi clk"); qspi->qspi.master.input_clk_hz = 200000000; } else { qspi->qspi.master.input_clk_hz = lqspi_frequency; debug("Qspi clk frequency set to %ld Hz\n", lqspi_frequency); } qspi->slave.is_dual = is_dual; qspi->slave.rd_cmd = READ_CMD_FULL; qspi->slave.wr_cmd = PAGE_PROGRAM | QUAD_PAGE_PROGRAM; qspi->qspi.master.speed_hz = qspi->qspi.master.input_clk_hz / 2; qspi->qspi.max_speed_hz = qspi->qspi.master.speed_hz; qspi->qspi.master.is_dual = is_dual; qspi->qspi.mode = mode; qspi->qspi.chip_select = 0; qspi->qspi.bits_per_word = 32; zynq_qspi_setup_transfer(&qspi->qspi, NULL); return &qspi->slave; }
static void init_cpu_clocks(void) { int clk_621; u32 reg, div, srcsel; enum zynq_clk parent; reg = readl(&slcr_base->arm_clk_ctrl); clk_621 = readl(&slcr_base->clk_621_true) & 1; div = (reg & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; srcsel = (reg & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; parent = __zynq_clk_cpu_get_parent(srcsel); /* cpu clocks */ clks[cpu_6or4x_clk].reg = &slcr_base->arm_clk_ctrl; clks[cpu_6or4x_clk].parent = parent; clks[cpu_6or4x_clk].frequency = DIV_ROUND_CLOSEST( zynq_clk_get_rate(parent), div); clks[cpu_6or4x_clk].name = "cpu_6or4x"; clks[cpu_3or2x_clk].reg = &slcr_base->arm_clk_ctrl; clks[cpu_3or2x_clk].parent = cpu_6or4x_clk; clks[cpu_3or2x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / 2; clks[cpu_3or2x_clk].name = "cpu_3or2x"; clks[cpu_2x_clk].reg = &slcr_base->arm_clk_ctrl; clks[cpu_2x_clk].parent = cpu_6or4x_clk; clks[cpu_2x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / (2 + clk_621); clks[cpu_2x_clk].name = "cpu_2x"; clks[cpu_1x_clk].reg = &slcr_base->arm_clk_ctrl; clks[cpu_1x_clk].parent = cpu_6or4x_clk; clks[cpu_1x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / (4 + 2 * clk_621); clks[cpu_1x_clk].name = "cpu_1x"; }
/** * zynq_clk_periph_get_rate() - Get clock rate * @clk: Handle of the peripheral clock * Returns the current clock rate of @clk. */ static unsigned long zynq_clk_periph_get_rate(struct clk *clk) { u32 clk_ctrl = readl(clk->reg); u32 div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; u32 div1 = 1; if (clk->flags & ZYNQ_CLK_FLAGS_HAS_2_DIVS) div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT; /* a register value of zero == division by 1 */ if (!div0) div0 = 1; if (!div1) div1 = 1; return DIV_ROUND_CLOSEST( DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div0), div1); }