static int _ipu_pixel_clk_div_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_clk_rate) { struct clk_di_div *di_div = to_clk_di_div(hw); struct ipu_soc *ipu = ipu_get_soc(di_div->ipu_id); u64 div, parent_rate; u64 remainder; parent_rate = (unsigned long long)parent_clk_rate * 16; div = parent_rate; div = do_udiv64(div, rate, &remainder); /* Round the divider value */ if (remainder > (rate/2)) div++; /* Round up divider if it gets us closer to desired pix clk */ if ((div & 0xC) == 0xC) { div += 0x10; div &= ~0xF; } if (div > 0x1000) pr_err("Overflow, di:%d, DI_BS_CLKGEN0 div:0x%x\n", di_div->di_id, (u32)div); _ipu_get(ipu); ipu_di_write(ipu, di_div->di_id, (u32)div, DI_BS_CLKGEN0); /* Setup pixel clock timing */ /* FIXME: needs to be more flexible */ /* Down time is half of period */ ipu_di_write(ipu, di_div->di_id, ((u32)div / 16) << 16, DI_BS_CLKGEN1); _ipu_put(ipu); return 0; }
static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin, int set, int up, int down) { u32 reg; reg = ipu_di_read(di, DI_DW_GEN(wave_gen)); reg &= ~(0x3 << (di_pin * 2)); reg |= set << (di_pin * 2); ipu_di_write(di, reg, DI_DW_GEN(wave_gen)); ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set)); }
static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config, int start, int count) { u32 reg; int i; for (i = 0; i < count; i++) { struct di_sync_config *c = &config[i]; int wave_gen = start + i + 1; if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) || (c->repeat_count >= 0x1000) || (c->cnt_up >= 0x400) || (c->cnt_down >= 0x400)) { dev_err(di->ipu->dev, "DI%d counters out of range.\n", di->id); return; } reg = DI_SW_GEN0_RUN_COUNT(c->run_count) | DI_SW_GEN0_RUN_SRC(c->run_src) | DI_SW_GEN0_OFFSET_COUNT(c->offset_count) | DI_SW_GEN0_OFFSET_SRC(c->offset_src); ipu_di_write(di, reg, DI_SW_GEN0(wave_gen)); reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) | DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) | DI_SW_GEN1_CNT_POL_TRIGGER_SRC( c->cnt_polarity_trigger_src) | DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) | DI_SW_GEN1_CNT_DOWN(c->cnt_down) | DI_SW_GEN1_CNT_UP(c->cnt_up); /* Enable auto reload */ if (c->repeat_count == 0) reg |= DI_SW_GEN1_AUTO_RELOAD; ipu_di_write(di, reg, DI_SW_GEN1(wave_gen)); reg = ipu_di_read(di, DI_STP_REP(wave_gen)); reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1))); reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1)); ipu_di_write(di, reg, DI_STP_REP(wave_gen)); } }
static void ipu_di_data_wave_config(struct ipu_di *di, int wave_gen, int access_size, int component_size) { u32 reg; reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) | (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET); ipu_di_write(di, reg, DI_DW_GEN(wave_gen)); }
static int clk_di_set_parent(struct clk *clk, u8 index) { struct ipu_di *di = container_of(clk, struct ipu_di, clk_di_pixel); u32 val; val = ipu_di_read(di, DI_GENERAL); if (index) val |= DI_GEN_DI_CLK_EXT; else val &= ~DI_GEN_DI_CLK_EXT; ipu_di_write(di, val, DI_GENERAL); return 0; }
static int clk_di_set_rate(struct clk *clk, unsigned long rate, unsigned long parent_rate) { struct ipu_di *di = container_of(clk, struct ipu_di, clk_di_pixel); int div; u32 clkgen0; clkgen0 = ipu_di_read(di, DI_BS_CLKGEN0) & ~0xfff; div = ipu_di_clk_calc_div(parent_rate, rate); ipu_di_write(di, clkgen0 | div, DI_BS_CLKGEN0); dev_dbg(di->ipu->dev, "%s: inrate: %ld desired: %ld div: 0x%08x\n", __func__, parent_rate, rate, div); return 0; }
static int _ipu_pixel_clk_set_parent(struct clk_hw *hw, u8 index) { struct clk_di_mux *mux = to_clk_di_mux(hw); struct ipu_soc *ipu = ipu_get_soc(mux->ipu_id); u32 di_gen; di_gen = ipu_di_read(ipu, mux->di_id, DI_GENERAL); if (index == 0) /* ipu1_clk or ipu2_clk internal clk */ di_gen &= ~DI_GEN_DI_CLK_EXT; else di_gen |= DI_GEN_DI_CLK_EXT; ipu_di_write(ipu, mux->di_id, di_gen, DI_GENERAL); mux->index = index; pr_debug("ipu_pixel_clk: di_clk_ext:0x%x, di_gen reg:0x%x.\n", !(di_gen & DI_GEN_DI_CLK_EXT), di_gen); return 0; }