static int get_bad_peb_limit(const struct ubi_device *ubi, int max_beb_per1024) { int limit, device_pebs; uint64_t device_size; if (!max_beb_per1024) return 0; /* * Here we are using size of the entire flash chip and * not just the MTD partition size because the maximum * number of bad eraseblocks is a percentage of the * whole device and bad eraseblocks are not fairly * distributed over the flash chip. So the worst case * is that all the bad eraseblocks of the chip are in * the MTD partition we are attaching (ubi->mtd). */ if (ubi->mtd->master) device_size = ubi->mtd->master->size; else device_size = ubi->mtd->size; device_pebs = mtd_div_by_eb(device_size, ubi->mtd); limit = mult_frac(device_pebs, max_beb_per1024, 1024); /* Round it up */ if (mult_frac(limit, 1024, max_beb_per1024) < device_pebs) limit += 1; return limit; }
static long __div_round_rate(struct div_data *data, unsigned long rate, struct clk *parent, unsigned int *best_div, unsigned long *best_prate) { unsigned int div, min_div, max_div, _best_div = 1; unsigned long prate, _best_prate = 0, rrate = 0, req_prate, actual_rate; unsigned int numer; rate = max(rate, 1UL); min_div = max(data->min_div, 1U); max_div = min(data->max_div, (unsigned int) (ULONG_MAX / rate)); /* * div values are doubled for half dividers. * Adjust for that by picking a numer of 2. */ numer = data->is_half_divider ? 2 : 1; for (div = min_div; div <= max_div; div++) { if (data->skip_odd_div && (div & 1)) continue; req_prate = mult_frac(rate, div, numer); prate = clk_round_rate(parent, req_prate); if (IS_ERR_VALUE(prate)) break; actual_rate = mult_frac(prate, numer, div); if (is_better_rate(rate, rrate, actual_rate)) { rrate = actual_rate; _best_div = div; _best_prate = prate; } /* * Trying higher dividers is only going to ask the parent for * a higher rate. If it can't even output a rate higher than * the one we request for this divider, the parent is not * going to be able to output an even higher rate required * for a higher divider. So, stop trying higher dividers. */ if (actual_rate < rate) break; if (rrate <= rate + data->rate_margin) break; } if (!rrate) return -EINVAL; if (best_div) *best_div = _best_div; if (best_prate) *best_prate = _best_prate; return rrate; }
static enum handoff mux_div_clk_handoff(struct clk *c) { struct mux_div_clk *md = to_mux_div_clk(c); unsigned long parent_rate; unsigned int numer; parent_rate = clk_get_rate(c->parent); if (!parent_rate) return HANDOFF_DISABLED_CLK; /* * div values are doubled for half dividers. * Adjust for that by picking a numer of 2. */ numer = md->data.is_half_divider ? 2 : 1; if (md->data.div) { c->rate = mult_frac(parent_rate, numer, md->data.div); } else { c->rate = 0; return HANDOFF_DISABLED_CLK; } if (!md->ops->is_enabled) return HANDOFF_DISABLED_CLK; if (md->ops->is_enabled(md)) return HANDOFF_ENABLED_CLK; return HANDOFF_DISABLED_CLK; }
/** * Initialize Hash Filters */ int init_hash_filter(struct adapter *adap) { unsigned int n_user_filters; unsigned int user_filter_perc; int ret; u32 params[7], val[7]; #define FW_PARAM_DEV(param) \ (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) #define FW_PARAM_PFVF(param) \ (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param) | \ V_FW_PARAMS_PARAM_Y(0) | \ V_FW_PARAMS_PARAM_Z(0)) params[0] = FW_PARAM_DEV(NTID); ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, params, val); if (ret < 0) return ret; adap->tids.ntids = val[0]; adap->tids.natids = min(adap->tids.ntids / 2, MAX_ATIDS); user_filter_perc = 100; n_user_filters = mult_frac(adap->tids.nftids, user_filter_perc, 100); adap->tids.nftids = n_user_filters; adap->params.hash_filter = 1; return 0; }
static int gadc_thermal_adc_to_temp(struct gadc_thermal_info *gti, int val) { int temp, temp_hi, temp_lo, adc_hi, adc_lo; int i; if (!gti->lookup_table) return val; for (i = 0; i < gti->nlookup_table; i++) { if (val >= gti->lookup_table[2 * i + 1]) break; } if (i == 0) { temp = gti->lookup_table[0]; } else if (i >= gti->nlookup_table) { temp = gti->lookup_table[2 * (gti->nlookup_table - 1)]; } else { adc_hi = gti->lookup_table[2 * i - 1]; adc_lo = gti->lookup_table[2 * i + 1]; temp_hi = gti->lookup_table[2 * i - 2]; temp_lo = gti->lookup_table[2 * i]; temp = temp_hi + mult_frac(temp_lo - temp_hi, val - adc_hi, adc_lo - adc_hi); } return temp; }
static long __div_round_rate(struct div_data *data, unsigned long rate, struct clk *parent, unsigned int *best_div, unsigned long *best_prate) { unsigned int div, min_div, max_div, _best_div = 1; unsigned long prate, _best_prate = 0, rrate = 0, req_prate, actual_rate; unsigned int numer; rate = max(rate, 1UL); min_div = max(data->min_div, 1U); max_div = min(data->max_div, (unsigned int) (ULONG_MAX / rate)); numer = data->is_half_divider ? 2 : 1; for (div = min_div; div <= max_div; div++) { if (data->skip_odd_div && (div & 1)) continue; req_prate = mult_frac(rate, div, numer); prate = clk_round_rate(parent, req_prate); if (IS_ERR_VALUE(prate)) break; actual_rate = mult_frac(prate, numer, div); if (is_better_rate(rate, rrate, actual_rate)) { rrate = actual_rate; _best_div = div; _best_prate = prate; } if (actual_rate < rate) break; if (rrate <= rate + data->rate_margin) break; } if (!rrate) return -EINVAL; if (best_div) *best_div = _best_div; if (best_prate) *best_prate = _best_prate; return rrate; }
/* Returns MBps of read/writes for the sampling window. */ static int mon_get_mbps(int n, u32 start_val, unsigned int us) { u32 overflow, count; long long beats; count = get_l2_indirect_reg(L2PMnEVCNTR(n)); overflow = get_l2_indirect_reg(L2PMOVSR); if (overflow & BIT(n)) beats = 0xFFFFFFFF - start_val + count; else beats = count - start_val; beats *= USEC_PER_SEC; beats *= bytes_per_beat; do_div(beats, us); beats = DIV_ROUND_UP_ULL(beats, MBYTE); pr_debug("EV%d ov: %x, cnt: %x\n", n, overflow, count); return beats; } static void do_bw_sample(struct work_struct *work); static DECLARE_DEFERRED_WORK(bw_sample, do_bw_sample); static struct workqueue_struct *bw_sample_wq; static DEFINE_MUTEX(bw_lock); static ktime_t prev_ts; static u32 prev_r_start_val; static u32 prev_w_start_val; static struct msm_bus_paths bw_levels[] = { BW(0), BW(200), }; static struct msm_bus_scale_pdata bw_data = { .usecase = bw_levels, .num_usecases = ARRAY_SIZE(bw_levels), .name = "cpubw-krait", .active_only = 1, }; static u32 bus_client; static void compute_bw(int mbps); static irqreturn_t mon_intr_handler(int irq, void *dev_id); #define START_LIMIT 100 /* MBps */ static int start_monitoring(void) { int mb_limit; int ret; bw_sample_wq = alloc_workqueue("cpubw-krait", WQ_HIGHPRI, 0); if (!bw_sample_wq) { pr_err("Unable to alloc workqueue\n"); return -ENOMEM; } ret = request_threaded_irq(MON_INT, NULL, mon_intr_handler, IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_RISING, "cpubw_krait", mon_intr_handler); if (ret) { pr_err("Unable to register interrupt handler\n"); return ret; } bus_client = msm_bus_scale_register_client(&bw_data); if (!bus_client) { pr_err("Unable to register bus client\n"); ret = -ENODEV; goto bus_reg_fail; } compute_bw(START_LIMIT); mon_init(); mon_disable(0); mon_disable(1); mb_limit = mult_frac(START_LIMIT, sample_ms, MSEC_PER_SEC); mb_limit /= 2; prev_r_start_val = mon_set_limit_mbyte(0, mb_limit); prev_w_start_val = mon_set_limit_mbyte(1, mb_limit); prev_ts = ktime_get(); set_l2_indirect_reg(L2PMINTENSET, BIT(0)); set_l2_indirect_reg(L2PMINTENSET, BIT(1)); mon_enable(0); mon_enable(1); global_mon_enable(true); queue_delayed_work(bw_sample_wq, &bw_sample, msecs_to_jiffies(sample_ms)); return 0; bus_reg_fail: destroy_workqueue(bw_sample_wq); disable_irq(MON_INT); free_irq(MON_INT, mon_intr_handler); return ret; }
static u32 mon_set_limit_mbyte(int n, unsigned int mbytes) { u32 regval, beats; beats = mult_frac(mbytes, SZ_1M, bytes_per_beat); regval = 0xFFFFFFFF - beats; set_l2_indirect_reg(L2PMnEVCNTR(n), regval); pr_debug("EV%d MB: %d, start val: %x\n", n, mbytes, regval); return regval; }
static unsigned long vco_get_rate(struct clk *c) { u32 sdm0, doubler, sdm_byp_div; u64 vco_rate; u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3; struct dsi_pll_vco_clk *vco = to_vco_clk(c); u64 ref_clk = vco->ref_clk_rate; int rc; struct mdss_pll_resources *dsi_pll_res = vco->priv; rc = mdss_pll_resource_enable(dsi_pll_res, true); if (rc) { pr_err("Failed to enable mdss dsi pll resources\n"); return rc; } /* Check to see if the ref clk doubler is enabled */ doubler = MDSS_PLL_REG_R(dsi_pll_res->pll_base, DSI_PHY_PLL_UNIPHY_PLL_REFCLK_CFG) & BIT(0); ref_clk += (doubler * vco->ref_clk_rate); /* see if it is integer mode or sdm mode */ sdm0 = MDSS_PLL_REG_R(dsi_pll_res->pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0); if (sdm0 & BIT(6)) { /* integer mode */ sdm_byp_div = (MDSS_PLL_REG_R(dsi_pll_res->pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0) & 0x3f) + 1; vco_rate = ref_clk * sdm_byp_div; } else { /* sdm mode */ sdm_dc_off = MDSS_PLL_REG_R(dsi_pll_res->pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG1) & 0xFF; pr_debug("sdm_dc_off = %d\n", sdm_dc_off); sdm2 = MDSS_PLL_REG_R(dsi_pll_res->pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG2) & 0xFF; sdm3 = MDSS_PLL_REG_R(dsi_pll_res->pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG3) & 0xFF; sdm_freq_seed = (sdm3 << 8) | sdm2; pr_debug("sdm_freq_seed = %d\n", sdm_freq_seed); vco_rate = (ref_clk * (sdm_dc_off + 1)) + mult_frac(ref_clk, sdm_freq_seed, BIT(16)); pr_debug("vco rate = %lld", vco_rate); } pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate); mdss_pll_resource_enable(dsi_pll_res, false); return (unsigned long)vco_rate; }
static int _find_safe_div(struct clk *c, unsigned long rate) { struct div_clk *d = to_div_clk(c); struct div_data *data = &d->data; unsigned long fast = max(rate, c->rate); unsigned int numer = data->is_half_divider ? 2 : 1; int i, safe_div = 0; if (!d->safe_freq) return 0; for (i = data->max_div; i >= data->min_div; i--) if (mult_frac(d->safe_freq, numer, i) <= fast) safe_div = i; return safe_div ?: -EINVAL; }
static int mdss_dsi_phy_initialize_defaults(struct dsi_phy_t_clk_param *t_clk, struct dsi_phy_timing *t_param, u32 phy_rev) { if (phy_rev <= DSI_PHY_REV_UNKNOWN || phy_rev >= DSI_PHY_REV_MAX) { pr_err("Invalid PHY %d revision\n", phy_rev); return -EINVAL; } t_param->clk_prepare.mipi_min = CLK_PREPARE_SPEC_MIN; t_param->clk_prepare.mipi_max = CLK_PREPARE_SPEC_MAX; t_param->clk_trail.mipi_min = CLK_TRAIL_SPEC_MIN; t_param->hs_exit.mipi_min = HS_EXIT_SPEC_MIN; t_param->hs_exit.rec_max = HS_EXIT_RECO_MAX; if (phy_rev == DSI_PHY_REV_20) { t_param->clk_prepare.rec_min = DIV_ROUND_UP((t_param->clk_prepare.mipi_min * t_clk->bitclk_mbps), (8 * t_clk->tlpx_numer_ns)); t_param->clk_prepare.rec_max = rounddown(mult_frac(t_param->clk_prepare.mipi_max * t_clk->bitclk_mbps, 1, (8 * t_clk->tlpx_numer_ns)), 1); t_param->hs_rqst.mipi_min = HS_RQST_SPEC_MIN; t_param->hs_rqst_clk.mipi_min = HS_RQST_SPEC_MIN; } else if (phy_rev == DSI_PHY_REV_10) { t_param->clk_prepare.rec_min = (DIV_ROUND_UP(t_param->clk_prepare.mipi_min * t_clk->bitclk_mbps, t_clk->tlpx_numer_ns)) - 2; t_param->clk_prepare.rec_max = (DIV_ROUND_UP(t_param->clk_prepare.mipi_max * t_clk->bitclk_mbps, t_clk->tlpx_numer_ns)) - 2; } pr_debug("clk_prepare: min=%d, max=%d\n", t_param->clk_prepare.rec_min, t_param->clk_prepare.rec_max); return 0; }
static unsigned long vco_get_rate(struct clk *c) { u32 sdm0, doubler, sdm_byp_div; u64 vco_rate; u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3; struct dsi_pll_vco_clk *vco = to_vco_clk(c); u64 ref_clk = vco->ref_clk_rate; /* Check to see if the ref clk doubler is enabled */ doubler = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_REFCLK_CFG) & BIT(0); ref_clk += (doubler * vco->ref_clk_rate); /* see if it is integer mode or sdm mode */ sdm0 = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0); if (sdm0 & BIT(6)) { /* integer mode */ sdm_byp_div = (DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0) & 0x3f) + 1; vco_rate = ref_clk * sdm_byp_div; } else { /* sdm mode */ sdm_dc_off = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG1) & 0xFF; pr_debug("%s: sdm_dc_off = %d\n", __func__, sdm_dc_off); sdm2 = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG2) & 0xFF; sdm3 = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG3) & 0xFF; sdm_freq_seed = (sdm3 << 8) | sdm2; pr_debug("%s: sdm_freq_seed = %d\n", __func__, sdm_freq_seed); vco_rate = (ref_clk * (sdm_dc_off + 1)) + mult_frac(ref_clk, sdm_freq_seed, BIT(16)); pr_debug("%s: vco rate = %lld", __func__, vco_rate); } pr_debug("%s: returning vco rate = %lu\n", __func__, (unsigned long)vco_rate); return (unsigned long)vco_rate; }
static int vt8500_set_baud_rate(struct uart_port *port, unsigned int baud) { struct vt8500_port *vt8500_port = container_of(port, struct vt8500_port, uart); unsigned long div; unsigned int loops = 1000; div = ((vt8500_port->clk_predivisor - 1) & 0xf) << 16; div |= (uart_get_divisor(port, baud) - 1) & 0x3ff; /* Effective baud rate */ baud = port->uartclk / 16 / ((div & 0x3ff) + 1); while ((vt8500_read(port, VT8500_URUSR) & (1 << 5)) && --loops) cpu_relax(); vt8500_write(port, div, VT8500_URDIV); /* Break signal timing depends on baud rate, update accordingly */ vt8500_write(port, mult_frac(baud, 4096, 1000000), VT8500_URBKR); return baud; }
static enum handoff mux_div_clk_handoff(struct clk *c) { struct mux_div_clk *md = to_mux_div_clk(c); unsigned long parent_rate; unsigned int numer; parent_rate = clk_get_rate(c->parent); if (!parent_rate) return HANDOFF_DISABLED_CLK; numer = md->data.is_half_divider ? 2 : 1; if (md->data.div) { c->rate = mult_frac(parent_rate, numer, md->data.div); } else { c->rate = 0; return HANDOFF_DISABLED_CLK; } if (!md->ops->is_enabled) return HANDOFF_DISABLED_CLK; if (md->ops->is_enabled(md)) return HANDOFF_ENABLED_CLK; return HANDOFF_DISABLED_CLK; }
int mdss_dsi_on(struct mdss_panel_data *pdata) { int ret = 0; u32 clk_rate; struct mdss_panel_info *pinfo; struct mipi_panel_info *mipi; u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height; u32 ystride, bpp, data, dst_bpp; u32 dummy_xres, dummy_yres; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; u32 hsync_period, vsync_period; if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } if (pdata->panel_info.panel_power_on) { pr_warn("%s:%d Panel already on.\n", __func__, __LINE__); return 0; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); pr_debug("%s+: ctrl=%p ndx=%d\n", __func__, ctrl_pdata, ctrl_pdata->ndx); pinfo = &pdata->panel_info; ret = mdss_dsi_panel_power_on(pdata, 1); if (ret) { pr_err("%s: Panel power on failed\n", __func__); return ret; } pdata->panel_info.panel_power_on = 1; ret = mdss_dsi_enable_bus_clocks(ctrl_pdata); if (ret) { pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__, ret); mdss_dsi_panel_power_on(pdata, 0); return ret; } mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base)); mdss_dsi_phy_init(pdata); mdss_dsi_disable_bus_clocks(ctrl_pdata); mdss_dsi_clk_ctrl(ctrl_pdata, 1); clk_rate = pdata->panel_info.clk_rate; clk_rate = min(clk_rate, pdata->panel_info.clk_max); dst_bpp = pdata->panel_info.fbc.enabled ? (pdata->panel_info.fbc.target_bpp) : (pinfo->bpp); hbp = mult_frac(pdata->panel_info.lcdc.h_back_porch, dst_bpp, pdata->panel_info.bpp); hfp = mult_frac(pdata->panel_info.lcdc.h_front_porch, dst_bpp, pdata->panel_info.bpp); vbp = mult_frac(pdata->panel_info.lcdc.v_back_porch, dst_bpp, pdata->panel_info.bpp); vfp = mult_frac(pdata->panel_info.lcdc.v_front_porch, dst_bpp, pdata->panel_info.bpp); hspw = mult_frac(pdata->panel_info.lcdc.h_pulse_width, dst_bpp, pdata->panel_info.bpp); vspw = pdata->panel_info.lcdc.v_pulse_width; width = mult_frac(pdata->panel_info.xres, dst_bpp, pdata->panel_info.bpp); height = pdata->panel_info.yres; if (pdata->panel_info.type == MIPI_VIDEO_PANEL) { dummy_xres = pdata->panel_info.lcdc.xres_pad; dummy_yres = pdata->panel_info.lcdc.yres_pad; } vsync_period = vspw + vbp + height + dummy_yres + vfp; hsync_period = hspw + hbp + width + dummy_xres + hfp; mipi = &pdata->panel_info.mipi; if (pdata->panel_info.type == MIPI_VIDEO_PANEL) { MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x24, ((hspw + hbp + width + dummy_xres) << 16 | (hspw + hbp))); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x28, ((vspw + vbp + height + dummy_yres) << 16 | (vspw + vbp))); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C, ((vsync_period - 1) << 16) | (hsync_period - 1)); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x30, (hspw << 16)); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x34, 0); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x38, (vspw << 16)); } else { /* command mode */ if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888) bpp = 3; else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB666) bpp = 3; else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565) bpp = 2; else bpp = 3; /* Default format set to RGB888 */ ystride = width * bpp + 1; /* DSI_COMMAND_MODE_MDP_STREAM_CTRL */ data = (ystride << 16) | (mipi->vc << 8) | DTYPE_DCS_LWRITE; MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x60, data); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x58, data); /* DSI_COMMAND_MODE_MDP_STREAM_TOTAL */ data = height << 16 | width; MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x64, data); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x5C, data); } mdss_dsi_sw_reset(pdata); mdss_dsi_host_init(mipi, pdata); if (mipi->force_clk_lane_hs) { u32 tmp; tmp = MIPI_INP((ctrl_pdata->ctrl_base) + 0xac); tmp |= (1<<28); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0xac, tmp); wmb(); } if (pdata->panel_info.type == MIPI_CMD_PANEL) mdss_dsi_clk_ctrl(ctrl_pdata, 0); pr_debug("%s-:\n", __func__); return 0; }
int mdss_dsi_phy_calc_timing_param(struct mdss_panel_info *pinfo, u32 phy_rev, u32 frate_hz) { struct dsi_phy_t_clk_param t_clk; struct dsi_phy_timing t_param; int hsync_period; int vsync_period; unsigned long inter_num; uint32_t lane_config = 0; unsigned long x, y; int rc = 0; if (!pinfo) { pr_err("invalid panel info\n"); return -EINVAL; } hsync_period = mdss_panel_get_htotal(pinfo, true); vsync_period = mdss_panel_get_vtotal(pinfo); inter_num = pinfo->bpp * frate_hz; if (pinfo->mipi.data_lane0) lane_config++; if (pinfo->mipi.data_lane1) lane_config++; if (pinfo->mipi.data_lane2) lane_config++; if (pinfo->mipi.data_lane3) lane_config++; x = mult_frac(vsync_period * hsync_period, inter_num, lane_config); y = rounddown(x, 1); t_clk.bitclk_mbps = rounddown(mult_frac(y, 1, 1000000), 1); t_clk.escclk_numer = ESC_CLK_MHZ; t_clk.escclk_denom = ESCCLK_MMSS_CC_PREDIV; t_clk.tlpx_numer_ns = TLPX_NUMER; t_clk.treot_ns = TR_EOT; pr_debug("hperiod=%d, vperiod=%d, inter_num=%lu, lane_cfg=%d\n", hsync_period, vsync_period, inter_num, lane_config); pr_debug("x=%lu, y=%lu, bitrate=%d\n", x, y, t_clk.bitclk_mbps); switch (phy_rev) { case DSI_PHY_REV_10: rc = mdss_dsi_phy_initialize_defaults(&t_clk, &t_param, phy_rev); if (rc) { pr_err("phy%d initialization failed\n", phy_rev); goto timing_calc_end; } mdss_dsi_phy_calc_param_phy_rev_1(&t_clk, &t_param); mdss_dsi_phy_update_timing_param(pinfo, &t_param); break; case DSI_PHY_REV_20: rc = mdss_dsi_phy_initialize_defaults(&t_clk, &t_param, phy_rev); if (rc) { pr_err("phy%d initialization failed\n", phy_rev); goto timing_calc_end; } rc = mdss_dsi_phy_calc_param_phy_rev_2(&t_clk, &t_param); if (rc) { pr_err("Phy timing calculations failed\n"); goto timing_calc_end; } mdss_dsi_phy_update_timing_param_rev_2(pinfo, &t_param); break; default: pr_err("phy rev %d not supported\n", phy_rev); return -EINVAL; } timing_calc_end: return rc; }
int mdss_dsi_on(struct mdss_panel_data *pdata) { int ret = 0; u32 clk_rate; struct mdss_panel_info *pinfo; struct mipi_panel_info *mipi; u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height; u32 ystride, bpp, data, dst_bpp; u32 dummy_xres, dummy_yres; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; u32 hsync_period, vsync_period; if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } if (pdata->panel_info.panel_power_on) { pr_warn("%s:%d Panel already on.\n", __func__, __LINE__); return 0; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); pr_info("%s+: ctrl=%p ndx=%d\n", __func__, ctrl_pdata, ctrl_pdata->ndx); pinfo = &pdata->panel_info; #ifdef CONFIG_MACH_LGE mdss_dsi_panel_io(pdata, 1); #endif ret = msm_dss_enable_vreg(ctrl_pdata->power_data.vreg_config, ctrl_pdata->power_data.num_vreg, 1); if (ret) { pr_err("%s:Failed to enable vregs. rc=%d\n", __func__, ret); return ret; } pdata->panel_info.panel_power_on = 1; if (!pdata->panel_info.mipi.lp11_init) mdss_dsi_panel_reset(pdata, 1); ret = mdss_dsi_bus_clk_start(ctrl_pdata); if (ret) { pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__, ret); mdss_dsi_panel_power_on(pdata, 0); pdata->panel_info.panel_power_on = 0; return ret; } mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base)); mdss_dsi_phy_init(pdata); mdss_dsi_bus_clk_stop(ctrl_pdata); mdss_dsi_clk_ctrl(ctrl_pdata, 1); clk_rate = pdata->panel_info.clk_rate; clk_rate = min(clk_rate, pdata->panel_info.clk_max); dst_bpp = pdata->panel_info.fbc.enabled ? (pdata->panel_info.fbc.target_bpp) : (pinfo->bpp); hbp = mult_frac(pdata->panel_info.lcdc.h_back_porch, dst_bpp, pdata->panel_info.bpp); hfp = mult_frac(pdata->panel_info.lcdc.h_front_porch, dst_bpp, pdata->panel_info.bpp); vbp = mult_frac(pdata->panel_info.lcdc.v_back_porch, dst_bpp, pdata->panel_info.bpp); vfp = mult_frac(pdata->panel_info.lcdc.v_front_porch, dst_bpp, pdata->panel_info.bpp); hspw = mult_frac(pdata->panel_info.lcdc.h_pulse_width, dst_bpp, pdata->panel_info.bpp); vspw = pdata->panel_info.lcdc.v_pulse_width; width = mult_frac(pdata->panel_info.xres, dst_bpp, pdata->panel_info.bpp); height = pdata->panel_info.yres; if (pdata->panel_info.type == MIPI_VIDEO_PANEL) { dummy_xres = pdata->panel_info.lcdc.xres_pad; dummy_yres = pdata->panel_info.lcdc.yres_pad; } vsync_period = vspw + vbp + height + dummy_yres + vfp; hsync_period = hspw + hbp + width + dummy_xres + hfp; mipi = &pdata->panel_info.mipi; if (pdata->panel_info.type == MIPI_VIDEO_PANEL) { MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x24, ((hspw + hbp + width + dummy_xres) << 16 | (hspw + hbp))); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x28, ((vspw + vbp + height + dummy_yres) << 16 | (vspw + vbp))); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C, ((vsync_period - 1) << 16) | (hsync_period - 1)); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x30, (hspw << 16)); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x34, 0); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x38, (vspw << 16)); } else { /* */ if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888) bpp = 3; else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB666) bpp = 3; else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565) bpp = 2; else bpp = 3; /* */ ystride = width * bpp + 1; /* */ data = (ystride << 16) | (mipi->vc << 8) | DTYPE_DCS_LWRITE; MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x60, data); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x58, data); /* */ data = height << 16 | width; MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x64, data); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x5C, data); } mdss_dsi_sw_reset(pdata); mdss_dsi_host_init(mipi, pdata); /* */ #ifdef CONFIG_MACH_LGE if (pdata->panel_info.mipi.lp11_init){ mdelay(10); if(ctrl_pdata->ndx == 1) mdss_dsi_panel_reset(pdata, 1); } #else if (pdata->panel_info.mipi.lp11_init) mdss_dsi_panel_reset(pdata, 1); #endif if (pdata->panel_info.mipi.init_delay) usleep(pdata->panel_info.mipi.init_delay); #ifndef CONFIG_MACH_LGE if (mipi->force_clk_lane_hs) { u32 tmp; tmp = MIPI_INP((ctrl_pdata->ctrl_base) + 0xac); tmp |= (1<<28); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0xac, tmp); wmb(); } #endif if (pdata->panel_info.type == MIPI_CMD_PANEL) mdss_dsi_clk_ctrl(ctrl_pdata, 0); pr_info("%s-:\n", __func__); return 0; }
static int mdp4_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { struct drm_device *dev = plane->dev; struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); struct mdp4_kms *mdp4_kms = get_kms(plane); enum mdp4_pipe pipe = mdp4_plane->pipe; const struct mdp_format *format; uint32_t op_mode = 0; uint32_t phasex_step = MDP4_VG_PHASE_STEP_DEFAULT; uint32_t phasey_step = MDP4_VG_PHASE_STEP_DEFAULT; enum mdp4_frame_format frame_type; if (!(crtc && fb)) { DBG("%s: disabled!", mdp4_plane->name); return 0; } frame_type = mdp4_get_frame_format(fb); /* src values are in Q16 fixed point, convert to integer: */ src_x = src_x >> 16; src_y = src_y >> 16; src_w = src_w >> 16; src_h = src_h >> 16; DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp4_plane->name, fb->base.id, src_x, src_y, src_w, src_h, crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h); format = to_mdp_format(msm_framebuffer_format(fb)); if (src_w > (crtc_w * DOWN_SCALE_MAX)) { dev_err(dev->dev, "Width down scaling exceeds limits!\n"); return -ERANGE; } if (src_h > (crtc_h * DOWN_SCALE_MAX)) { dev_err(dev->dev, "Height down scaling exceeds limits!\n"); return -ERANGE; } if (crtc_w > (src_w * UP_SCALE_MAX)) { dev_err(dev->dev, "Width up scaling exceeds limits!\n"); return -ERANGE; } if (crtc_h > (src_h * UP_SCALE_MAX)) { dev_err(dev->dev, "Height up scaling exceeds limits!\n"); return -ERANGE; } if (src_w != crtc_w) { uint32_t sel_unit = SCALE_FIR; op_mode |= MDP4_PIPE_OP_MODE_SCALEX_EN; if (MDP_FORMAT_IS_YUV(format)) { if (crtc_w > src_w) sel_unit = SCALE_PIXEL_RPT; else if (crtc_w <= (src_w / 4)) sel_unit = SCALE_MN_PHASE; op_mode |= MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL(sel_unit); phasex_step = mult_frac(MDP4_VG_PHASE_STEP_DEFAULT, src_w, crtc_w); } } if (src_h != crtc_h) { uint32_t sel_unit = SCALE_FIR; op_mode |= MDP4_PIPE_OP_MODE_SCALEY_EN; if (MDP_FORMAT_IS_YUV(format)) { if (crtc_h > src_h) sel_unit = SCALE_PIXEL_RPT; else if (crtc_h <= (src_h / 4)) sel_unit = SCALE_MN_PHASE; op_mode |= MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL(sel_unit); phasey_step = mult_frac(MDP4_VG_PHASE_STEP_DEFAULT, src_h, crtc_h); } } mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_SIZE(pipe), MDP4_PIPE_SRC_SIZE_WIDTH(src_w) | MDP4_PIPE_SRC_SIZE_HEIGHT(src_h)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_XY(pipe), MDP4_PIPE_SRC_XY_X(src_x) | MDP4_PIPE_SRC_XY_Y(src_y)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_SIZE(pipe), MDP4_PIPE_DST_SIZE_WIDTH(crtc_w) | MDP4_PIPE_DST_SIZE_HEIGHT(crtc_h)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_XY(pipe), MDP4_PIPE_DST_XY_X(crtc_x) | MDP4_PIPE_DST_XY_Y(crtc_y)); mdp4_plane_set_scanout(plane, fb); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_FORMAT(pipe), MDP4_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | MDP4_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | MDP4_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) | MDP4_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) | COND(format->alpha_enable, MDP4_PIPE_SRC_FORMAT_ALPHA_ENABLE) | MDP4_PIPE_SRC_FORMAT_CPP(format->cpp - 1) | MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | MDP4_PIPE_SRC_FORMAT_FETCH_PLANES(format->fetch_type) | MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample) | MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT(frame_type) | COND(format->unpack_tight, MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_UNPACK(pipe), MDP4_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) | MDP4_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) | MDP4_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) | MDP4_PIPE_SRC_UNPACK_ELEM3(format->unpack[3])); if (MDP_FORMAT_IS_YUV(format)) { struct csc_cfg *csc = mdp_get_default_csc_cfg(CSC_YUV2RGB); op_mode |= MDP4_PIPE_OP_MODE_SRC_YCBCR; op_mode |= MDP4_PIPE_OP_MODE_CSC_EN; mdp4_write_csc_config(mdp4_kms, pipe, csc); } mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(pipe), op_mode); mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEX_STEP(pipe), phasex_step); mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEY_STEP(pipe), phasey_step); if (frame_type != FRAME_LINEAR) mdp4_write(mdp4_kms, REG_MDP4_PIPE_SSTILE_FRAME_SIZE(pipe), MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH(src_w) | MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT(src_h)); return 0; }
static long sam9x60_pll_get_best_div_mul(struct sam9x60_pll *pll, unsigned long rate, unsigned long parent_rate, bool update) { const struct clk_pll_characteristics *characteristics = pll->characteristics; unsigned long bestremainder = ULONG_MAX; unsigned long maxdiv, mindiv, tmpdiv; long bestrate = -ERANGE; unsigned long bestdiv = 0; unsigned long bestmul = 0; unsigned long bestfrac = 0; if (rate < characteristics->output[0].min || rate > characteristics->output[0].max) return -ERANGE; if (!pll->characteristics->upll) { mindiv = parent_rate / rate; if (mindiv < 2) mindiv = 2; maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX, rate); if (maxdiv > PLL_DIV_MAX) maxdiv = PLL_DIV_MAX; } else { mindiv = maxdiv = UPLL_DIV; } for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) { unsigned long remainder; unsigned long tmprate; unsigned long tmpmul; unsigned long tmpfrac = 0; /* * Calculate the multiplier associated with the current * divider that provide the closest rate to the requested one. */ tmpmul = mult_frac(rate, tmpdiv, parent_rate); tmprate = mult_frac(parent_rate, tmpmul, tmpdiv); remainder = rate - tmprate; if (remainder) { tmpfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * tmpdiv * (1 << 22), parent_rate); tmprate += DIV_ROUND_CLOSEST_ULL((u64)tmpfrac * parent_rate, tmpdiv * (1 << 22)); if (tmprate > rate) remainder = tmprate - rate; else remainder = rate - tmprate; } /* * Compare the remainder with the best remainder found until * now and elect a new best multiplier/divider pair if the * current remainder is smaller than the best one. */ if (remainder < bestremainder) { bestremainder = remainder; bestdiv = tmpdiv; bestmul = tmpmul; bestrate = tmprate; bestfrac = tmpfrac; } /* We've found a perfect match! */ if (!remainder) break; } /* Check if bestrate is a valid output rate */ if (bestrate < characteristics->output[0].min && bestrate > characteristics->output[0].max) return -ERANGE; if (update) { pll->div = bestdiv - 1; pll->mul = bestmul - 1; pll->frac = bestfrac; } return bestrate; }
static void __mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata) { struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_panel_info *pinfo; struct mipi_panel_info *mipi; u32 clk_rate; u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height; u32 ystride, bpp, data, dst_bpp; u32 dummy_xres, dummy_yres; u32 hsync_period, vsync_period; ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); pinfo = &pdata->panel_info; clk_rate = pdata->panel_info.clk_rate; clk_rate = min(clk_rate, pdata->panel_info.clk_max); dst_bpp = pdata->panel_info.fbc.enabled ? (pdata->panel_info.fbc.target_bpp) : (pinfo->bpp); hbp = mult_frac(pdata->panel_info.lcdc.h_back_porch, dst_bpp, pdata->panel_info.bpp); hfp = mult_frac(pdata->panel_info.lcdc.h_front_porch, dst_bpp, pdata->panel_info.bpp); vbp = mult_frac(pdata->panel_info.lcdc.v_back_porch, dst_bpp, pdata->panel_info.bpp); vfp = mult_frac(pdata->panel_info.lcdc.v_front_porch, dst_bpp, pdata->panel_info.bpp); hspw = mult_frac(pdata->panel_info.lcdc.h_pulse_width, dst_bpp, pdata->panel_info.bpp); vspw = pdata->panel_info.lcdc.v_pulse_width; width = mult_frac(pdata->panel_info.xres, dst_bpp, pdata->panel_info.bpp); height = pdata->panel_info.yres; if (pdata->panel_info.type == MIPI_VIDEO_PANEL) { dummy_xres = pdata->panel_info.lcdc.xres_pad; dummy_yres = pdata->panel_info.lcdc.yres_pad; } vsync_period = vspw + vbp + height + dummy_yres + vfp; hsync_period = hspw + hbp + width + dummy_xres + hfp; mipi = &pdata->panel_info.mipi; if (pdata->panel_info.type == MIPI_VIDEO_PANEL) { MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x24, ((hspw + hbp + width + dummy_xres) << 16 | (hspw + hbp))); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x28, ((vspw + vbp + height + dummy_yres) << 16 | (vspw + vbp))); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C, ((vsync_period - 1) << 16) | (hsync_period - 1)); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x30, (hspw << 16)); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x34, 0); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x38, (vspw << 16)); } else { /* command mode */ if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888) bpp = 3; else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB666) bpp = 3; else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565) bpp = 2; else bpp = 3; /* Default format set to RGB888 */ ystride = width * bpp + 1; /* DSI_COMMAND_MODE_MDP_STREAM_CTRL */ data = (ystride << 16) | (mipi->vc << 8) | DTYPE_DCS_LWRITE; MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x60, data); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x58, data); /* DSI_COMMAND_MODE_MDP_STREAM_TOTAL */ data = height << 16 | width; MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x64, data); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x5C, data); } }
static int mdss_dsi_phy_calc_param_phy_rev_2(struct dsi_phy_t_clk_param *t_clk, struct dsi_phy_timing *t_param) { /* recommended fraction for PHY REV 2.0 */ u32 const min_prepare_frac = 50; u32 const hs_exit_min_frac = 10; u32 const phy_timing_frac = 30; u32 const hs_zero_min_frac = 10; u32 const clk_zero_min_frac = 2; int tmp; int t_hs_prep_actual; int teot_clk_lane, teot_data_lane; u64 dividend; u64 temp, rc = 0; u64 multiplier = BIT(20); u64 temp_multiple; s64 mipi_min, mipi_max, mipi_max_tr, rec_min, rec_prog; s64 clk_prep_actual; s64 actual_intermediate; s32 actual_frac; s64 rec_temp1, rec_temp2, rec_temp3; /* clk_prepare calculations */ dividend = ((t_param->clk_prepare.rec_max - t_param->clk_prepare.rec_min) * min_prepare_frac * multiplier); temp = roundup(div_s64(dividend, 100), multiplier); temp += (t_param->clk_prepare.rec_min * multiplier); t_param->clk_prepare.rec = div_s64(temp, multiplier); rc = mdss_dsi_phy_common_validate_and_set(&t_param->clk_prepare, "clk prepare"); if (rc) goto error; /* clk_ prepare theoretical value*/ temp_multiple = (8 * t_param->clk_prepare.program_value * t_clk->tlpx_numer_ns * multiplier); actual_intermediate = div_s64(temp_multiple, t_clk->bitclk_mbps); div_s64_rem(temp_multiple, t_clk->bitclk_mbps, &actual_frac); clk_prep_actual = div_s64((actual_intermediate + actual_frac), multiplier); pr_debug("CLK PREPARE: mipi_min=%d, max=%d, rec_min=%d, rec_max=%d", t_param->clk_prepare.mipi_min, t_param->clk_prepare.mipi_max, t_param->clk_prepare.rec_min, t_param->clk_prepare.rec_max); pr_debug("prog value = %d, actual=%lld\n", t_param->clk_prepare.rec, clk_prep_actual); /* clk zero calculations */ /* Mipi spec min*/ mipi_min = (300 * multiplier) - (actual_intermediate + actual_frac); t_param->clk_zero.mipi_min = div_s64(mipi_min, multiplier); /* recommended min */ rec_temp1 = div_s64(mipi_min * t_clk->bitclk_mbps, t_clk->tlpx_numer_ns); rec_temp2 = rec_temp1 - (11 * multiplier); rec_temp3 = roundup(div_s64(rec_temp2, 8), multiplier); rec_min = div_s64(rec_temp3, multiplier) - 3; t_param->clk_zero.rec_min = rec_min; /* recommended max */ t_param->clk_zero.rec_max = ((t_param->clk_zero.rec_min > 255) ? 511 : 255); /* Programmed value */ t_param->clk_zero.rec = DIV_ROUND_UP( (t_param->clk_zero.rec_max - t_param->clk_zero.rec_min) * clk_zero_min_frac + (t_param->clk_zero.rec_min * 100), 100); rc = mdss_dsi_phy_common_validate_and_set(&t_param->clk_zero, "clk zero"); if (rc) goto error; pr_debug("CLK ZERO: mipi_min=%d, max=%d, rec_min=%d, rec_max=%d, prog value = %d\n", t_param->clk_zero.mipi_min, t_param->clk_zero.mipi_max, t_param->clk_zero.rec_min, t_param->clk_zero.rec_max, t_param->clk_zero.rec); /* clk trail calculations */ temp_multiple = div_s64(12 * multiplier * t_clk->tlpx_numer_ns, t_clk->bitclk_mbps); div_s64_rem(temp_multiple, multiplier, &actual_frac); mipi_max_tr = 105 * multiplier + (temp_multiple + actual_frac); teot_clk_lane = div_s64(mipi_max_tr, multiplier); mipi_max = mipi_max_tr - (t_clk->treot_ns * multiplier); t_param->clk_trail.mipi_max = div_s64(mipi_max, multiplier); /* recommended min*/ temp_multiple = div_s64(t_param->clk_trail.mipi_min * multiplier * t_clk->bitclk_mbps, t_clk->tlpx_numer_ns); div_s64_rem(temp_multiple, multiplier, &actual_frac); rec_temp1 = temp_multiple + actual_frac + 3 * multiplier; rec_temp2 = div_s64(rec_temp1, 8); rec_temp3 = roundup(rec_temp2, multiplier); t_param->clk_trail.rec_min = div_s64(rec_temp3, multiplier); /* recommended max */ rec_temp1 = div_s64(mipi_max * t_clk->bitclk_mbps, t_clk->tlpx_numer_ns); rec_temp2 = rec_temp1 + 3 * multiplier; rec_temp3 = rec_temp2 / 8; t_param->clk_trail.rec_max = div_s64(rec_temp3, multiplier); /* Programmed value */ t_param->clk_trail.rec = DIV_ROUND_UP( (t_param->clk_trail.rec_max - t_param->clk_trail.rec_min) * phy_timing_frac + (t_param->clk_trail.rec_min * 100), 100); rc = mdss_dsi_phy_common_validate_and_set(&t_param->clk_trail, "clk trail"); if (rc) goto error; pr_debug("CLK TRAIL: mipi_min=%d, max=%d, rec_min=%d, rec_max=%d, prog value = %d\n", t_param->clk_trail.mipi_min, t_param->clk_trail.mipi_max, t_param->clk_trail.rec_min, t_param->clk_trail.rec_max, t_param->clk_trail.rec); /* hs prepare calculations */ /* mipi min */ temp_multiple = div_s64(4 * t_clk->tlpx_numer_ns * multiplier, t_clk->bitclk_mbps); div_s64_rem(temp_multiple, multiplier, &actual_frac); mipi_min = 40 * multiplier + (temp_multiple + actual_frac); t_param->hs_prepare.mipi_min = div_s64(mipi_min, multiplier); /* mipi max */ temp_multiple = div_s64(6 * t_clk->tlpx_numer_ns * multiplier, t_clk->bitclk_mbps); div_s64_rem(temp_multiple, multiplier, &actual_frac); mipi_max = 85 * multiplier + temp_multiple; t_param->hs_prepare.mipi_max = div_s64(mipi_max, multiplier); /* recommended min */ temp_multiple = div_s64(mipi_min * t_clk->bitclk_mbps, t_clk->tlpx_numer_ns); div_s64_rem(temp_multiple, multiplier, &actual_frac); rec_temp1 = roundup((temp_multiple + actual_frac)/8, multiplier); t_param->hs_prepare.rec_min = div_s64(rec_temp1, multiplier); /* recommended max*/ temp_multiple = div_s64(mipi_max * t_clk->bitclk_mbps, t_clk->tlpx_numer_ns); div_s64_rem(temp_multiple, multiplier, &actual_frac); rec_temp2 = rounddown((temp_multiple + actual_frac)/8, multiplier); t_param->hs_prepare.rec_max = div_s64(rec_temp2, multiplier); /* prog value*/ dividend = (rec_temp2 - rec_temp1) * min_prepare_frac; temp = roundup(div_u64(dividend, 100), multiplier); rec_prog = temp + rec_temp1; t_param->hs_prepare.rec = div_s64(rec_prog, multiplier); rc = mdss_dsi_phy_common_validate_and_set(&t_param->hs_prepare, "HS prepare"); if (rc) goto error; /* theoretical Value */ temp_multiple = div_s64(8 * rec_prog * t_clk->tlpx_numer_ns, t_clk->bitclk_mbps); div_s64_rem(temp_multiple, multiplier, &actual_frac); t_hs_prep_actual = div_s64(temp_multiple, multiplier); pr_debug("HS PREPARE: mipi_min=%d, max=%d, rec_min=%d, rec_max=%d, prog value = %d, actual=%d\n", t_param->hs_prepare.mipi_min, t_param->hs_prepare.mipi_max, t_param->hs_prepare.rec_min, t_param->hs_prepare.rec_max, t_param->hs_prepare.rec, t_hs_prep_actual); /* hs zero calculations */ /* mipi min*/ mipi_min = div_s64(10 * t_clk->tlpx_numer_ns * multiplier, t_clk->bitclk_mbps); rec_temp1 = (145 * multiplier) + mipi_min - temp_multiple; t_param->hs_zero.mipi_min = div_s64(rec_temp1, multiplier); /* recommended min */ rec_temp1 = div_s64(rec_temp1 * t_clk->bitclk_mbps, t_clk->tlpx_numer_ns); rec_temp2 = rec_temp1 - (11 * multiplier); rec_temp3 = roundup((rec_temp2/8), multiplier); rec_min = rec_temp3 - (3 * multiplier); t_param->hs_zero.rec_min = div_s64(rec_min, multiplier); t_param->hs_zero.rec_max = ((t_param->hs_zero.rec_min > 255) ? 511 : 255); /* prog value */ t_param->hs_zero.rec = DIV_ROUND_UP( (t_param->hs_zero.rec_max - t_param->hs_zero.rec_min) * hs_zero_min_frac + (t_param->hs_zero.rec_min * 100), 100); rc = mdss_dsi_phy_common_validate_and_set(&t_param->hs_zero, "HS zero"); if (rc) goto error; pr_debug("HS ZERO: mipi_min=%d, max=%d, rec_min=%d, rec_max=%d, prog value = %d\n", t_param->hs_zero.mipi_min, t_param->hs_zero.mipi_max, t_param->hs_zero.rec_min, t_param->hs_zero.rec_max, t_param->hs_zero.rec); /* hs_trail calculations */ teot_data_lane = teot_clk_lane; t_param->hs_trail.mipi_min = 60 + mult_frac(t_clk->tlpx_numer_ns, 4, t_clk->bitclk_mbps); t_param->hs_trail.mipi_max = teot_clk_lane - t_clk->treot_ns; t_param->hs_trail.rec_min = DIV_ROUND_UP( ((t_param->hs_trail.mipi_min * t_clk->bitclk_mbps) + 3 * t_clk->tlpx_numer_ns), (8 * t_clk->tlpx_numer_ns)); tmp = ((t_param->hs_trail.mipi_max * t_clk->bitclk_mbps) + (3 * t_clk->tlpx_numer_ns)); t_param->hs_trail.rec_max = tmp/(8 * t_clk->tlpx_numer_ns); tmp = DIV_ROUND_UP((t_param->hs_trail.rec_max - t_param->hs_trail.rec_min) * phy_timing_frac, 100); t_param->hs_trail.rec = tmp + t_param->hs_trail.rec_min; rc = mdss_dsi_phy_common_validate_and_set(&t_param->hs_trail, "HS trail"); if (rc) goto error; pr_debug("HS TRAIL: mipi_min=%d, max=%d, rec_min=%d, rec_max=%d, prog value = %d\n", t_param->hs_trail.mipi_min, t_param->hs_trail.mipi_max, t_param->hs_trail.rec_min, t_param->hs_trail.rec_max, t_param->hs_trail.rec); /* hs rqst calculations for Data lane */ t_param->hs_rqst.rec = DIV_ROUND_UP( (t_param->hs_rqst.mipi_min * t_clk->bitclk_mbps) - (8 * t_clk->tlpx_numer_ns), (8 * t_clk->tlpx_numer_ns)); rc = mdss_dsi_phy_common_validate_and_set(&t_param->hs_rqst, "HS rqst"); if (rc) goto error; pr_debug("HS RQST-DATA: mipi_min=%d, max=%d, rec_min=%d, rec_max=%d, prog value = %d\n", t_param->hs_rqst.mipi_min, t_param->hs_rqst.mipi_max, t_param->hs_rqst.rec_min, t_param->hs_rqst.rec_max, t_param->hs_rqst.rec); /* hs exit calculations */ t_param->hs_exit.rec_min = DIV_ROUND_UP( (t_param->hs_exit.mipi_min * t_clk->bitclk_mbps), (8 * t_clk->tlpx_numer_ns)) - 1; t_param->hs_exit.rec = DIV_ROUND_UP( (t_param->hs_exit.rec_max - t_param->hs_exit.rec_min) * hs_exit_min_frac + (t_param->hs_exit.rec_min * 100), 100); rc = mdss_dsi_phy_common_validate_and_set(&t_param->hs_exit, "HS exit"); if (rc) goto error; pr_debug("HS EXIT: mipi_min=%d, max=%d, rec_min=%d, rec_max=%d, prog value = %d\n", t_param->hs_exit.mipi_min, t_param->hs_exit.mipi_max, t_param->hs_exit.rec_min, t_param->hs_exit.rec_max, t_param->hs_exit.rec); /* hs rqst calculations for Clock lane */ t_param->hs_rqst_clk.rec = DIV_ROUND_UP( (t_param->hs_rqst_clk.mipi_min * t_clk->bitclk_mbps) - (8 * t_clk->tlpx_numer_ns), (8 * t_clk->tlpx_numer_ns)); rc = mdss_dsi_phy_common_validate_and_set(&t_param->hs_rqst_clk, "HS rqst clk"); if (rc) goto error; pr_debug("HS RQST-CLK: mipi_min=%d, max=%d, rec_min=%d, rec_max=%d, prog value = %d\n", t_param->hs_rqst_clk.mipi_min, t_param->hs_rqst_clk.mipi_max, t_param->hs_rqst_clk.rec_min, t_param->hs_rqst_clk.rec_max, t_param->hs_rqst_clk.rec); pr_debug("teot_clk=%d, data=%d\n", teot_clk_lane, teot_data_lane); return 0; error: return -EINVAL; }