diff options
Diffstat (limited to 'drivers/video/omap2/dss/dsi.c')
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 557 |
1 files changed, 544 insertions, 13 deletions
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index a4e0560c2799..de88e69ef0a2 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
@@ -255,6 +255,24 @@ struct dsi_isr_tables { | |||
255 | struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS]; | 255 | struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS]; |
256 | }; | 256 | }; |
257 | 257 | ||
258 | struct dsi_clk_calc_ctx { | ||
259 | struct platform_device *dsidev; | ||
260 | |||
261 | /* inputs */ | ||
262 | |||
263 | const struct omap_dss_dsi_config *config; | ||
264 | |||
265 | unsigned long req_pck_min, req_pck_nom, req_pck_max; | ||
266 | |||
267 | /* outputs */ | ||
268 | |||
269 | struct dsi_clock_info dsi_cinfo; | ||
270 | struct dispc_clock_info dispc_cinfo; | ||
271 | |||
272 | struct omap_video_timings dispc_vm; | ||
273 | struct omap_dss_dsi_videomode_timings dsi_vm; | ||
274 | }; | ||
275 | |||
258 | struct dsi_data { | 276 | struct dsi_data { |
259 | struct platform_device *pdev; | 277 | struct platform_device *pdev; |
260 | void __iomem *base; | 278 | void __iomem *base; |
@@ -1201,6 +1219,25 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev) | |||
1201 | return r; | 1219 | return r; |
1202 | } | 1220 | } |
1203 | 1221 | ||
1222 | static int dsi_lp_clock_calc(struct dsi_clock_info *cinfo, | ||
1223 | unsigned long lp_clk_min, unsigned long lp_clk_max) | ||
1224 | { | ||
1225 | unsigned long dsi_fclk = cinfo->dsi_pll_hsdiv_dsi_clk; | ||
1226 | unsigned lp_clk_div; | ||
1227 | unsigned long lp_clk; | ||
1228 | |||
1229 | lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk_max * 2); | ||
1230 | lp_clk = dsi_fclk / 2 / lp_clk_div; | ||
1231 | |||
1232 | if (lp_clk < lp_clk_min || lp_clk > lp_clk_max) | ||
1233 | return -EINVAL; | ||
1234 | |||
1235 | cinfo->lp_clk_div = lp_clk_div; | ||
1236 | cinfo->lp_clk = lp_clk; | ||
1237 | |||
1238 | return 0; | ||
1239 | } | ||
1240 | |||
1204 | static int dsi_set_lp_clk_divisor(struct platform_device *dsidev) | 1241 | static int dsi_set_lp_clk_divisor(struct platform_device *dsidev) |
1205 | { | 1242 | { |
1206 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1243 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
@@ -1577,8 +1614,7 @@ found: | |||
1577 | return 0; | 1614 | return 0; |
1578 | } | 1615 | } |
1579 | 1616 | ||
1580 | static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev, | 1617 | static void dsi_pll_calc_dsi_fck(struct dsi_clock_info *cinfo) |
1581 | struct dsi_clock_info *cinfo) | ||
1582 | { | 1618 | { |
1583 | unsigned long max_dsi_fck; | 1619 | unsigned long max_dsi_fck; |
1584 | 1620 | ||
@@ -4369,7 +4405,7 @@ static int dsi_set_clocks(struct omap_dss_device *dssdev, | |||
4369 | goto err; | 4405 | goto err; |
4370 | 4406 | ||
4371 | /* Calculate PLL's DSI clock */ | 4407 | /* Calculate PLL's DSI clock */ |
4372 | dsi_pll_calc_dsi_fck(dsidev, &cinfo); | 4408 | dsi_pll_calc_dsi_fck(&cinfo); |
4373 | 4409 | ||
4374 | /* Calculate PLL's DISPC clock and pck & lck divs */ | 4410 | /* Calculate PLL's DISPC clock and pck & lck divs */ |
4375 | pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp; | 4411 | pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp; |
@@ -4693,13 +4729,6 @@ static int dsi_display_init_dispc(struct platform_device *dsidev, | |||
4693 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC); | 4729 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC); |
4694 | 4730 | ||
4695 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { | 4731 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { |
4696 | dsi->timings.hsw = 1; | ||
4697 | dsi->timings.hfp = 1; | ||
4698 | dsi->timings.hbp = 1; | ||
4699 | dsi->timings.vsw = 1; | ||
4700 | dsi->timings.vfp = 0; | ||
4701 | dsi->timings.vbp = 0; | ||
4702 | |||
4703 | r = dss_mgr_register_framedone_handler(mgr, | 4732 | r = dss_mgr_register_framedone_handler(mgr, |
4704 | dsi_framedone_irq_callback, dsidev); | 4733 | dsi_framedone_irq_callback, dsidev); |
4705 | if (r) { | 4734 | if (r) { |
@@ -4941,24 +4970,526 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) | |||
4941 | } | 4970 | } |
4942 | EXPORT_SYMBOL(omapdss_dsi_enable_te); | 4971 | EXPORT_SYMBOL(omapdss_dsi_enable_te); |
4943 | 4972 | ||
4973 | #ifdef PRINT_VERBOSE_VM_TIMINGS | ||
4974 | static void print_dsi_vm(const char *str, | ||
4975 | const struct omap_dss_dsi_videomode_timings *t) | ||
4976 | { | ||
4977 | unsigned long byteclk = t->hsclk / 4; | ||
4978 | int bl, wc, pps, tot; | ||
4979 | |||
4980 | wc = DIV_ROUND_UP(t->hact * t->bitspp, 8); | ||
4981 | pps = DIV_ROUND_UP(wc + 6, t->ndl); /* pixel packet size */ | ||
4982 | bl = t->hss + t->hsa + t->hse + t->hbp + t->hfp; | ||
4983 | tot = bl + pps; | ||
4984 | |||
4985 | #define TO_DSI_T(x) ((u32)div64_u64((u64)x * 1000000000llu, byteclk)) | ||
4986 | |||
4987 | pr_debug("%s bck %lu, %u/%u/%u/%u/%u/%u = %u+%u = %u, " | ||
4988 | "%u/%u/%u/%u/%u/%u = %u + %u = %u\n", | ||
4989 | str, | ||
4990 | byteclk, | ||
4991 | t->hss, t->hsa, t->hse, t->hbp, pps, t->hfp, | ||
4992 | bl, pps, tot, | ||
4993 | TO_DSI_T(t->hss), | ||
4994 | TO_DSI_T(t->hsa), | ||
4995 | TO_DSI_T(t->hse), | ||
4996 | TO_DSI_T(t->hbp), | ||
4997 | TO_DSI_T(pps), | ||
4998 | TO_DSI_T(t->hfp), | ||
4999 | |||
5000 | TO_DSI_T(bl), | ||
5001 | TO_DSI_T(pps), | ||
5002 | |||
5003 | TO_DSI_T(tot)); | ||
5004 | #undef TO_DSI_T | ||
5005 | } | ||
5006 | |||
5007 | static void print_dispc_vm(const char *str, const struct omap_video_timings *t) | ||
5008 | { | ||
5009 | unsigned long pck = t->pixel_clock * 1000; | ||
5010 | int hact, bl, tot; | ||
5011 | |||
5012 | hact = t->x_res; | ||
5013 | bl = t->hsw + t->hbp + t->hfp; | ||
5014 | tot = hact + bl; | ||
5015 | |||
5016 | #define TO_DISPC_T(x) ((u32)div64_u64((u64)x * 1000000000llu, pck)) | ||
5017 | |||
5018 | pr_debug("%s pck %lu, %u/%u/%u/%u = %u+%u = %u, " | ||
5019 | "%u/%u/%u/%u = %u + %u = %u\n", | ||
5020 | str, | ||
5021 | pck, | ||
5022 | t->hsw, t->hbp, hact, t->hfp, | ||
5023 | bl, hact, tot, | ||
5024 | TO_DISPC_T(t->hsw), | ||
5025 | TO_DISPC_T(t->hbp), | ||
5026 | TO_DISPC_T(hact), | ||
5027 | TO_DISPC_T(t->hfp), | ||
5028 | TO_DISPC_T(bl), | ||
5029 | TO_DISPC_T(hact), | ||
5030 | TO_DISPC_T(tot)); | ||
5031 | #undef TO_DISPC_T | ||
5032 | } | ||
5033 | |||
5034 | /* note: this is not quite accurate */ | ||
5035 | static void print_dsi_dispc_vm(const char *str, | ||
5036 | const struct omap_dss_dsi_videomode_timings *t) | ||
5037 | { | ||
5038 | struct omap_video_timings vm = { 0 }; | ||
5039 | unsigned long byteclk = t->hsclk / 4; | ||
5040 | unsigned long pck; | ||
5041 | u64 dsi_tput; | ||
5042 | int dsi_hact, dsi_htot; | ||
5043 | |||
5044 | dsi_tput = (u64)byteclk * t->ndl * 8; | ||
5045 | pck = (u32)div64_u64(dsi_tput, t->bitspp); | ||
5046 | dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(t->hact * t->bitspp, 8) + 6, t->ndl); | ||
5047 | dsi_htot = t->hss + t->hsa + t->hse + t->hbp + dsi_hact + t->hfp; | ||
5048 | |||
5049 | vm.pixel_clock = pck / 1000; | ||
5050 | vm.hsw = div64_u64((u64)(t->hsa + t->hse) * pck, byteclk); | ||
5051 | vm.hbp = div64_u64((u64)t->hbp * pck, byteclk); | ||
5052 | vm.hfp = div64_u64((u64)t->hfp * pck, byteclk); | ||
5053 | vm.x_res = t->hact; | ||
5054 | |||
5055 | print_dispc_vm(str, &vm); | ||
5056 | } | ||
5057 | #endif /* PRINT_VERBOSE_VM_TIMINGS */ | ||
5058 | |||
5059 | static bool dsi_cm_calc_dispc_cb(int lckd, int pckd, unsigned long lck, | ||
5060 | unsigned long pck, void *data) | ||
5061 | { | ||
5062 | struct dsi_clk_calc_ctx *ctx = data; | ||
5063 | struct omap_video_timings *t = &ctx->dispc_vm; | ||
5064 | |||
5065 | ctx->dispc_cinfo.lck_div = lckd; | ||
5066 | ctx->dispc_cinfo.pck_div = pckd; | ||
5067 | ctx->dispc_cinfo.lck = lck; | ||
5068 | ctx->dispc_cinfo.pck = pck; | ||
5069 | |||
5070 | *t = *ctx->config->timings; | ||
5071 | t->pixel_clock = pck / 1000; | ||
5072 | t->x_res = ctx->config->timings->x_res; | ||
5073 | t->y_res = ctx->config->timings->y_res; | ||
5074 | t->hsw = t->hfp = t->hbp = t->vsw = 1; | ||
5075 | t->vfp = t->vbp = 0; | ||
5076 | |||
5077 | return true; | ||
5078 | } | ||
5079 | |||
5080 | static bool dsi_cm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, | ||
5081 | void *data) | ||
5082 | { | ||
5083 | struct dsi_clk_calc_ctx *ctx = data; | ||
5084 | |||
5085 | ctx->dsi_cinfo.regm_dispc = regm_dispc; | ||
5086 | ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc; | ||
5087 | |||
5088 | return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max, | ||
5089 | dsi_cm_calc_dispc_cb, ctx); | ||
5090 | } | ||
5091 | |||
5092 | static bool dsi_cm_calc_pll_cb(int regn, int regm, unsigned long fint, | ||
5093 | unsigned long pll, void *data) | ||
5094 | { | ||
5095 | struct dsi_clk_calc_ctx *ctx = data; | ||
5096 | |||
5097 | ctx->dsi_cinfo.regn = regn; | ||
5098 | ctx->dsi_cinfo.regm = regm; | ||
5099 | ctx->dsi_cinfo.fint = fint; | ||
5100 | ctx->dsi_cinfo.clkin4ddr = pll; | ||
5101 | |||
5102 | return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min, | ||
5103 | dsi_cm_calc_hsdiv_cb, ctx); | ||
5104 | } | ||
5105 | |||
5106 | static bool dsi_cm_calc(struct dsi_data *dsi, | ||
5107 | const struct omap_dss_dsi_config *cfg, | ||
5108 | struct dsi_clk_calc_ctx *ctx) | ||
5109 | { | ||
5110 | unsigned long clkin; | ||
5111 | int bitspp, ndl; | ||
5112 | unsigned long pll_min, pll_max; | ||
5113 | unsigned long pck, txbyteclk; | ||
5114 | |||
5115 | clkin = clk_get_rate(dsi->sys_clk); | ||
5116 | bitspp = dsi_get_pixel_size(cfg->pixel_format); | ||
5117 | ndl = dsi->num_lanes_used - 1; | ||
5118 | |||
5119 | /* | ||
5120 | * Here we should calculate minimum txbyteclk to be able to send the | ||
5121 | * frame in time, and also to handle TE. That's not very simple, though, | ||
5122 | * especially as we go to LP between each pixel packet due to HW | ||
5123 | * "feature". So let's just estimate very roughly and multiply by 1.5. | ||
5124 | */ | ||
5125 | pck = cfg->timings->pixel_clock * 1000; | ||
5126 | pck = pck * 3 / 2; | ||
5127 | txbyteclk = pck * bitspp / 8 / ndl; | ||
5128 | |||
5129 | memset(ctx, 0, sizeof(*ctx)); | ||
5130 | ctx->dsidev = dsi->pdev; | ||
5131 | ctx->config = cfg; | ||
5132 | ctx->req_pck_min = pck; | ||
5133 | ctx->req_pck_nom = pck; | ||
5134 | ctx->req_pck_max = pck * 3 / 2; | ||
5135 | ctx->dsi_cinfo.clkin = clkin; | ||
5136 | |||
5137 | pll_min = max(cfg->hs_clk_min * 4, txbyteclk * 4 * 4); | ||
5138 | pll_max = cfg->hs_clk_max * 4; | ||
5139 | |||
5140 | return dsi_pll_calc(dsi->pdev, clkin, | ||
5141 | pll_min, pll_max, | ||
5142 | dsi_cm_calc_pll_cb, ctx); | ||
5143 | } | ||
5144 | |||
5145 | static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx) | ||
5146 | { | ||
5147 | struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev); | ||
5148 | const struct omap_dss_dsi_config *cfg = ctx->config; | ||
5149 | int bitspp = dsi_get_pixel_size(cfg->pixel_format); | ||
5150 | int ndl = dsi->num_lanes_used - 1; | ||
5151 | unsigned long hsclk = ctx->dsi_cinfo.clkin4ddr / 4; | ||
5152 | unsigned long byteclk = hsclk / 4; | ||
5153 | |||
5154 | unsigned long dispc_pck, req_pck_min, req_pck_nom, req_pck_max; | ||
5155 | int xres; | ||
5156 | int panel_htot, panel_hbl; /* pixels */ | ||
5157 | int dispc_htot, dispc_hbl; /* pixels */ | ||
5158 | int dsi_htot, dsi_hact, dsi_hbl, hss, hse; /* byteclks */ | ||
5159 | int hfp, hsa, hbp; | ||
5160 | const struct omap_video_timings *req_vm; | ||
5161 | struct omap_video_timings *dispc_vm; | ||
5162 | struct omap_dss_dsi_videomode_timings *dsi_vm; | ||
5163 | u64 dsi_tput, dispc_tput; | ||
5164 | |||
5165 | dsi_tput = (u64)byteclk * ndl * 8; | ||
5166 | |||
5167 | req_vm = cfg->timings; | ||
5168 | req_pck_min = ctx->req_pck_min; | ||
5169 | req_pck_max = ctx->req_pck_max; | ||
5170 | req_pck_nom = ctx->req_pck_nom; | ||
5171 | |||
5172 | dispc_pck = ctx->dispc_cinfo.pck; | ||
5173 | dispc_tput = (u64)dispc_pck * bitspp; | ||
5174 | |||
5175 | xres = req_vm->x_res; | ||
5176 | |||
5177 | panel_hbl = req_vm->hfp + req_vm->hbp + req_vm->hsw; | ||
5178 | panel_htot = xres + panel_hbl; | ||
5179 | |||
5180 | dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(xres * bitspp, 8) + 6, ndl); | ||
5181 | |||
5182 | /* | ||
5183 | * When there are no line buffers, DISPC and DSI must have the | ||
5184 | * same tput. Otherwise DISPC tput needs to be higher than DSI's. | ||
5185 | */ | ||
5186 | if (dsi->line_buffer_size < xres * bitspp / 8) { | ||
5187 | if (dispc_tput != dsi_tput) | ||
5188 | return false; | ||
5189 | } else { | ||
5190 | if (dispc_tput < dsi_tput) | ||
5191 | return false; | ||
5192 | } | ||
5193 | |||
5194 | /* DSI tput must be over the min requirement */ | ||
5195 | if (dsi_tput < (u64)bitspp * req_pck_min) | ||
5196 | return false; | ||
5197 | |||
5198 | /* When non-burst mode, DSI tput must be below max requirement. */ | ||
5199 | if (cfg->trans_mode != OMAP_DSS_DSI_BURST_MODE) { | ||
5200 | if (dsi_tput > (u64)bitspp * req_pck_max) | ||
5201 | return false; | ||
5202 | } | ||
5203 | |||
5204 | hss = DIV_ROUND_UP(4, ndl); | ||
5205 | |||
5206 | if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) { | ||
5207 | if (ndl == 3 && req_vm->hsw == 0) | ||
5208 | hse = 1; | ||
5209 | else | ||
5210 | hse = DIV_ROUND_UP(4, ndl); | ||
5211 | } else { | ||
5212 | hse = 0; | ||
5213 | } | ||
5214 | |||
5215 | /* DSI htot to match the panel's nominal pck */ | ||
5216 | dsi_htot = div64_u64((u64)panel_htot * byteclk, req_pck_nom); | ||
5217 | |||
5218 | /* fail if there would be no time for blanking */ | ||
5219 | if (dsi_htot < hss + hse + dsi_hact) | ||
5220 | return false; | ||
5221 | |||
5222 | /* total DSI blanking needed to achieve panel's TL */ | ||
5223 | dsi_hbl = dsi_htot - dsi_hact; | ||
5224 | |||
5225 | /* DISPC htot to match the DSI TL */ | ||
5226 | dispc_htot = div64_u64((u64)dsi_htot * dispc_pck, byteclk); | ||
5227 | |||
5228 | /* verify that the DSI and DISPC TLs are the same */ | ||
5229 | if ((u64)dsi_htot * dispc_pck != (u64)dispc_htot * byteclk) | ||
5230 | return false; | ||
5231 | |||
5232 | dispc_hbl = dispc_htot - xres; | ||
5233 | |||
5234 | /* setup DSI videomode */ | ||
5235 | |||
5236 | dsi_vm = &ctx->dsi_vm; | ||
5237 | memset(dsi_vm, 0, sizeof(*dsi_vm)); | ||
5238 | |||
5239 | dsi_vm->hsclk = hsclk; | ||
5240 | |||
5241 | dsi_vm->ndl = ndl; | ||
5242 | dsi_vm->bitspp = bitspp; | ||
5243 | |||
5244 | if (cfg->trans_mode != OMAP_DSS_DSI_PULSE_MODE) { | ||
5245 | hsa = 0; | ||
5246 | } else if (ndl == 3 && req_vm->hsw == 0) { | ||
5247 | hsa = 0; | ||
5248 | } else { | ||
5249 | hsa = div64_u64((u64)req_vm->hsw * byteclk, req_pck_nom); | ||
5250 | hsa = max(hsa - hse, 1); | ||
5251 | } | ||
5252 | |||
5253 | hbp = div64_u64((u64)req_vm->hbp * byteclk, req_pck_nom); | ||
5254 | hbp = max(hbp, 1); | ||
5255 | |||
5256 | hfp = dsi_hbl - (hss + hsa + hse + hbp); | ||
5257 | if (hfp < 1) { | ||
5258 | int t; | ||
5259 | /* we need to take cycles from hbp */ | ||
5260 | |||
5261 | t = 1 - hfp; | ||
5262 | hbp = max(hbp - t, 1); | ||
5263 | hfp = dsi_hbl - (hss + hsa + hse + hbp); | ||
5264 | |||
5265 | if (hfp < 1 && hsa > 0) { | ||
5266 | /* we need to take cycles from hsa */ | ||
5267 | t = 1 - hfp; | ||
5268 | hsa = max(hsa - t, 1); | ||
5269 | hfp = dsi_hbl - (hss + hsa + hse + hbp); | ||
5270 | } | ||
5271 | } | ||
5272 | |||
5273 | if (hfp < 1) | ||
5274 | return false; | ||
5275 | |||
5276 | dsi_vm->hss = hss; | ||
5277 | dsi_vm->hsa = hsa; | ||
5278 | dsi_vm->hse = hse; | ||
5279 | dsi_vm->hbp = hbp; | ||
5280 | dsi_vm->hact = xres; | ||
5281 | dsi_vm->hfp = hfp; | ||
5282 | |||
5283 | dsi_vm->vsa = req_vm->vsw; | ||
5284 | dsi_vm->vbp = req_vm->vbp; | ||
5285 | dsi_vm->vact = req_vm->y_res; | ||
5286 | dsi_vm->vfp = req_vm->vfp; | ||
5287 | |||
5288 | dsi_vm->trans_mode = cfg->trans_mode; | ||
5289 | |||
5290 | dsi_vm->blanking_mode = 0; | ||
5291 | dsi_vm->hsa_blanking_mode = 1; | ||
5292 | dsi_vm->hfp_blanking_mode = 1; | ||
5293 | dsi_vm->hbp_blanking_mode = 1; | ||
5294 | |||
5295 | dsi_vm->ddr_clk_always_on = cfg->ddr_clk_always_on; | ||
5296 | dsi_vm->window_sync = 4; | ||
5297 | |||
5298 | /* setup DISPC videomode */ | ||
5299 | |||
5300 | dispc_vm = &ctx->dispc_vm; | ||
5301 | *dispc_vm = *req_vm; | ||
5302 | dispc_vm->pixel_clock = dispc_pck / 1000; | ||
5303 | |||
5304 | if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) { | ||
5305 | hsa = div64_u64((u64)req_vm->hsw * dispc_pck, | ||
5306 | req_pck_nom); | ||
5307 | hsa = max(hsa, 1); | ||
5308 | } else { | ||
5309 | hsa = 1; | ||
5310 | } | ||
5311 | |||
5312 | hbp = div64_u64((u64)req_vm->hbp * dispc_pck, req_pck_nom); | ||
5313 | hbp = max(hbp, 1); | ||
5314 | |||
5315 | hfp = dispc_hbl - hsa - hbp; | ||
5316 | if (hfp < 1) { | ||
5317 | int t; | ||
5318 | /* we need to take cycles from hbp */ | ||
5319 | |||
5320 | t = 1 - hfp; | ||
5321 | hbp = max(hbp - t, 1); | ||
5322 | hfp = dispc_hbl - hsa - hbp; | ||
5323 | |||
5324 | if (hfp < 1) { | ||
5325 | /* we need to take cycles from hsa */ | ||
5326 | t = 1 - hfp; | ||
5327 | hsa = max(hsa - t, 1); | ||
5328 | hfp = dispc_hbl - hsa - hbp; | ||
5329 | } | ||
5330 | } | ||
5331 | |||
5332 | if (hfp < 1) | ||
5333 | return false; | ||
5334 | |||
5335 | dispc_vm->hfp = hfp; | ||
5336 | dispc_vm->hsw = hsa; | ||
5337 | dispc_vm->hbp = hbp; | ||
5338 | |||
5339 | return true; | ||
5340 | } | ||
5341 | |||
5342 | |||
5343 | static bool dsi_vm_calc_dispc_cb(int lckd, int pckd, unsigned long lck, | ||
5344 | unsigned long pck, void *data) | ||
5345 | { | ||
5346 | struct dsi_clk_calc_ctx *ctx = data; | ||
5347 | |||
5348 | ctx->dispc_cinfo.lck_div = lckd; | ||
5349 | ctx->dispc_cinfo.pck_div = pckd; | ||
5350 | ctx->dispc_cinfo.lck = lck; | ||
5351 | ctx->dispc_cinfo.pck = pck; | ||
5352 | |||
5353 | if (dsi_vm_calc_blanking(ctx) == false) | ||
5354 | return false; | ||
5355 | |||
5356 | #ifdef PRINT_VERBOSE_VM_TIMINGS | ||
5357 | print_dispc_vm("dispc", &ctx->dispc_vm); | ||
5358 | print_dsi_vm("dsi ", &ctx->dsi_vm); | ||
5359 | print_dispc_vm("req ", ctx->config->timings); | ||
5360 | print_dsi_dispc_vm("act ", &ctx->dsi_vm); | ||
5361 | #endif | ||
5362 | |||
5363 | return true; | ||
5364 | } | ||
5365 | |||
5366 | static bool dsi_vm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, | ||
5367 | void *data) | ||
5368 | { | ||
5369 | struct dsi_clk_calc_ctx *ctx = data; | ||
5370 | unsigned long pck_max; | ||
5371 | |||
5372 | ctx->dsi_cinfo.regm_dispc = regm_dispc; | ||
5373 | ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc; | ||
5374 | |||
5375 | /* | ||
5376 | * In burst mode we can let the dispc pck be arbitrarily high, but it | ||
5377 | * limits our scaling abilities. So for now, don't aim too high. | ||
5378 | */ | ||
5379 | |||
5380 | if (ctx->config->trans_mode == OMAP_DSS_DSI_BURST_MODE) | ||
5381 | pck_max = ctx->req_pck_max + 10000000; | ||
5382 | else | ||
5383 | pck_max = ctx->req_pck_max; | ||
5384 | |||
5385 | return dispc_div_calc(dispc, ctx->req_pck_min, pck_max, | ||
5386 | dsi_vm_calc_dispc_cb, ctx); | ||
5387 | } | ||
5388 | |||
5389 | static bool dsi_vm_calc_pll_cb(int regn, int regm, unsigned long fint, | ||
5390 | unsigned long pll, void *data) | ||
5391 | { | ||
5392 | struct dsi_clk_calc_ctx *ctx = data; | ||
5393 | |||
5394 | ctx->dsi_cinfo.regn = regn; | ||
5395 | ctx->dsi_cinfo.regm = regm; | ||
5396 | ctx->dsi_cinfo.fint = fint; | ||
5397 | ctx->dsi_cinfo.clkin4ddr = pll; | ||
5398 | |||
5399 | return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min, | ||
5400 | dsi_vm_calc_hsdiv_cb, ctx); | ||
5401 | } | ||
5402 | |||
5403 | static bool dsi_vm_calc(struct dsi_data *dsi, | ||
5404 | const struct omap_dss_dsi_config *cfg, | ||
5405 | struct dsi_clk_calc_ctx *ctx) | ||
5406 | { | ||
5407 | const struct omap_video_timings *t = cfg->timings; | ||
5408 | unsigned long clkin; | ||
5409 | unsigned long pll_min; | ||
5410 | unsigned long pll_max; | ||
5411 | int ndl = dsi->num_lanes_used - 1; | ||
5412 | int bitspp = dsi_get_pixel_size(cfg->pixel_format); | ||
5413 | unsigned long byteclk_min; | ||
5414 | |||
5415 | clkin = clk_get_rate(dsi->sys_clk); | ||
5416 | |||
5417 | memset(ctx, 0, sizeof(*ctx)); | ||
5418 | ctx->dsidev = dsi->pdev; | ||
5419 | ctx->config = cfg; | ||
5420 | |||
5421 | ctx->dsi_cinfo.clkin = clkin; | ||
5422 | |||
5423 | /* these limits should come from the panel driver */ | ||
5424 | ctx->req_pck_min = t->pixel_clock * 1000 - 1000; | ||
5425 | ctx->req_pck_nom = t->pixel_clock * 1000; | ||
5426 | ctx->req_pck_max = t->pixel_clock * 1000 + 1000; | ||
5427 | |||
5428 | byteclk_min = div64_u64((u64)ctx->req_pck_min * bitspp, ndl * 8); | ||
5429 | pll_min = max(cfg->hs_clk_min * 4, byteclk_min * 4 * 4); | ||
5430 | |||
5431 | if (cfg->trans_mode == OMAP_DSS_DSI_BURST_MODE) { | ||
5432 | pll_max = cfg->hs_clk_max * 4; | ||
5433 | } else { | ||
5434 | unsigned long byteclk_max; | ||
5435 | byteclk_max = div64_u64((u64)ctx->req_pck_max * bitspp, | ||
5436 | ndl * 8); | ||
5437 | |||
5438 | pll_max = byteclk_max * 4 * 4; | ||
5439 | } | ||
5440 | |||
5441 | return dsi_pll_calc(dsi->pdev, clkin, | ||
5442 | pll_min, pll_max, | ||
5443 | dsi_vm_calc_pll_cb, ctx); | ||
5444 | } | ||
5445 | |||
4944 | int omapdss_dsi_set_config(struct omap_dss_device *dssdev, | 5446 | int omapdss_dsi_set_config(struct omap_dss_device *dssdev, |
4945 | const struct omap_dss_dsi_config *config) | 5447 | const struct omap_dss_dsi_config *config) |
4946 | { | 5448 | { |
4947 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 5449 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4948 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 5450 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
5451 | struct dsi_clk_calc_ctx ctx; | ||
5452 | bool ok; | ||
5453 | int r; | ||
4949 | 5454 | ||
4950 | mutex_lock(&dsi->lock); | 5455 | mutex_lock(&dsi->lock); |
4951 | 5456 | ||
4952 | dsi->timings = *config->timings; | ||
4953 | dsi->vm_timings = *config->vm_timings; | ||
4954 | dsi->pix_fmt = config->pixel_format; | 5457 | dsi->pix_fmt = config->pixel_format; |
4955 | dsi->mode = config->mode; | 5458 | dsi->mode = config->mode; |
4956 | 5459 | ||
4957 | dsi_set_clocks(dssdev, config->hs_clk, config->lp_clk); | 5460 | if (config->mode == OMAP_DSS_DSI_VIDEO_MODE) |
5461 | ok = dsi_vm_calc(dsi, config, &ctx); | ||
5462 | else | ||
5463 | ok = dsi_cm_calc(dsi, config, &ctx); | ||
5464 | |||
5465 | if (!ok) { | ||
5466 | DSSERR("failed to find suitable DSI clock settings\n"); | ||
5467 | r = -EINVAL; | ||
5468 | goto err; | ||
5469 | } | ||
5470 | |||
5471 | dsi_pll_calc_dsi_fck(&ctx.dsi_cinfo); | ||
5472 | |||
5473 | r = dsi_lp_clock_calc(&ctx.dsi_cinfo, config->lp_clk_min, | ||
5474 | config->lp_clk_max); | ||
5475 | if (r) { | ||
5476 | DSSERR("failed to find suitable DSI LP clock settings\n"); | ||
5477 | goto err; | ||
5478 | } | ||
5479 | |||
5480 | dsi->user_dsi_cinfo = ctx.dsi_cinfo; | ||
5481 | dsi->user_dispc_cinfo = ctx.dispc_cinfo; | ||
5482 | |||
5483 | dsi->timings = ctx.dispc_vm; | ||
5484 | dsi->vm_timings = ctx.dsi_vm; | ||
4958 | 5485 | ||
4959 | mutex_unlock(&dsi->lock); | 5486 | mutex_unlock(&dsi->lock); |
4960 | 5487 | ||
4961 | return 0; | 5488 | return 0; |
5489 | err: | ||
5490 | mutex_unlock(&dsi->lock); | ||
5491 | |||
5492 | return r; | ||
4962 | } | 5493 | } |
4963 | EXPORT_SYMBOL(omapdss_dsi_set_config); | 5494 | EXPORT_SYMBOL(omapdss_dsi_set_config); |
4964 | 5495 | ||