static int clk_di_get_parent(struct clk *clk) { struct ipu_di *di = container_of(clk, struct ipu_di, clk_di_pixel); u32 val; val = ipu_di_read(di, DI_GENERAL); return val & DI_GEN_DI_CLK_EXT ? 1 : 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 unsigned long clk_di_recalc_rate(struct clk *clk, unsigned long parent_rate) { struct ipu_di *di = container_of(clk, struct ipu_di, clk_di_pixel); unsigned long outrate; u32 div = ipu_di_read(di, DI_BS_CLKGEN0); if (div < 0x10) div = 0x10; outrate = (parent_rate / div) * 16; return outrate; }
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 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 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; }
static unsigned long _ipu_pixel_clk_div_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_di_div *di_div = to_clk_di_div(hw); struct ipu_soc *ipu = ipu_get_soc(di_div->ipu_id); u32 div; u64 final_rate = (unsigned long long)parent_rate * 16; _ipu_get(ipu); div = ipu_di_read(ipu, di_div->di_id, DI_BS_CLKGEN0); _ipu_put(ipu); pr_debug("ipu_di%d read BS_CLKGEN0 div:%d, final_rate:%lld, prate:%ld\n", di_div->di_id, div, final_rate, parent_rate); if (div == 0) return 0; final_rate = udiv64(final_rate, div); return (unsigned long)final_rate; }
static long clk_di_round_rate(struct clk *clk, unsigned long rate, unsigned long *prate) { struct ipu_di *di = container_of(clk, struct ipu_di, clk_di_pixel); unsigned long outrate; int div; u32 val; div = ipu_di_clk_calc_div(*prate, rate); outrate = (*prate / div) * 16; val = ipu_di_read(di, DI_GENERAL); if (!(val & DI_GEN_DI_CLK_EXT) && outrate > *prate / 2) outrate = *prate / 2; dev_dbg(di->ipu->dev, "%s: inrate: %ld div: 0x%08x outrate: %ld wanted: %ld\n", __func__, *prate, div, outrate, rate); return outrate; }
.repeat_count = sig->mode.hactive, .cnt_clr_src = 5, }, { .run_count = v_total - 1, .run_src = DI_SYNC_INT_HSYNC, .offset_count = v_total / 2, .offset_src = DI_SYNC_INT_HSYNC, .cnt_clr_src = DI_SYNC_HSYNC, .cnt_down = 4, } }; ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg)); /* set gentime select and tag sel */ reg = ipu_di_read(di, DI_SW_GEN1(9)); reg &= 0x1FFFFFFF; reg |= (3 - 1) << 29 | 0x00008000; ipu_di_write(di, reg, DI_SW_GEN1(9)); ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF); } static void ipu_di_sync_config_noninterlaced(struct ipu_di *di, struct ipu_di_signal_cfg *sig, int div) { u32 h_total = sig->mode.hactive + sig->mode.hsync_len + sig->mode.hback_porch + sig->mode.hfront_porch; u32 v_total = sig->mode.vactive + sig->mode.vsync_len + sig->mode.vback_porch + sig->mode.vfront_porch; struct di_sync_config cfg[] = {