| /* |
| * (C) Copyright 2012 |
| * Marvell Semiconductor <www.marvell.com> |
| * |
| * SPDX-License-Identifier: GPL-2.0+ |
| */ |
| #include <config.h> |
| #include <common.h> |
| #include <malloc.h> |
| #include <mmp_disp.h> |
| #include <linux/types.h> |
| |
| #ifndef CONFIG_PXA1U88 |
| #include <power/pxa988_freq.h> |
| |
| static unsigned int pll3_vco; |
| |
| struct dsi_op_info { |
| unsigned int fps_max; |
| unsigned int fps_min; |
| unsigned int op_num; |
| unsigned int op_divider_num; |
| unsigned int pll3_vco_min; |
| unsigned int pll3_vco_max; |
| unsigned int pll3_divider_num; |
| unsigned int pll3_divider_table[6]; |
| unsigned int pll3_op_index; |
| unsigned int op_table[3]; |
| }; |
| |
| static struct dsi_op_info dsi_op_info_data = { |
| .fps_max = 70, |
| .fps_min = 50, |
| .op_num = 3, |
| .op_divider_num = 16, |
| .pll3_vco_min = 1200, |
| .pll3_vco_max = 2500, |
| .pll3_divider_num = 6, |
| .pll3_divider_table = { |
| 8, 6, 4, 3, 2, 1 |
| }, |
| .pll3_op_index = 2, |
| .op_table = { |
| 416, 624, 0 |
| }, |
| }; |
| |
| void calculate_dsi_clk(struct mmp_disp_plat_info *mi) |
| { |
| struct dsi_info *di = (struct dsi_info *)mi->phy_info; |
| struct fb_videomode *modes = &mi->modes[0]; |
| struct dsi_op_info *op_info; |
| u32 total_w, total_h, byteclk, bitclk, bitclk_max, |
| byteclk_max, bitclk_min, byteclk_min; |
| u32 op_num, dsi_divider_num, i, j; |
| u32 diff, diff_min, diff_count; |
| u32 fps_max, fps_min; |
| u32 def_op, temp_op; |
| char *cmdline; |
| |
| if (!di) |
| return; |
| |
| op_info = &dsi_op_info_data; |
| def_op = get_max_cpurate(); |
| if (!def_op) |
| return; |
| |
| /* Check current max cpu rate */ |
| for (i = 0; i < op_info->pll3_divider_num; i++) { |
| if ((def_op * op_info->pll3_divider_table[i]) |
| > op_info->pll3_vco_max) |
| continue; |
| if ((def_op * op_info->pll3_divider_table[i]) |
| < op_info->pll3_vco_min) { |
| if ((def_op * op_info->pll3_divider_table[i+1]) |
| < op_info->pll3_vco_max) { |
| def_op *= op_info->pll3_divider_table[i+1]; |
| break; |
| } |
| } |
| } |
| |
| /* Set shared cpu rate */ |
| op_info->op_table[op_info->pll3_op_index] = def_op; |
| |
| fps_max = op_info->fps_max; |
| fps_min = op_info->fps_min; |
| |
| total_w = modes->xres + modes->left_margin + |
| modes->right_margin + modes->hsync_len; |
| total_h = modes->yres + modes->upper_margin + |
| modes->lower_margin + modes->vsync_len; |
| |
| byteclk = ((total_w * (di->bpp >> 3)) * total_h * |
| modes->refresh) / di->lanes; |
| bitclk = byteclk << 3; |
| bitclk /= 1000000; |
| |
| byteclk_max = ((total_w * (di->bpp >> 3)) * total_h * |
| fps_max) / di->lanes; |
| bitclk_max = byteclk_max << 3; |
| bitclk_max /= 1000000; |
| |
| byteclk_min = ((total_w * (di->bpp >> 3)) * total_h * |
| fps_min) / di->lanes; |
| bitclk_min = byteclk_min << 3; |
| bitclk_min /= 1000000; |
| |
| op_num = op_info->op_num; |
| dsi_divider_num = op_info->op_divider_num; |
| |
| diff_min = bitclk; |
| diff_count = 0xff; |
| |
| /* calculate bit clk for all ops */ |
| for (j = 0; j < op_num; j++) { |
| for (i = 1; i < dsi_divider_num; i++) { |
| temp_op = op_info->op_table[j] / i; |
| if (temp_op > bitclk_min && temp_op < bitclk_max) { |
| diff = (temp_op > bitclk) ? (temp_op - bitclk) : |
| (bitclk - temp_op); |
| if (diff < diff_min) { |
| diff_min = diff; |
| diff_count = j; |
| } |
| } |
| } |
| } |
| |
| /* If can't find the suitable bit clk, select pll3 directly */ |
| if (diff_count == 0xff) { |
| /* Set the pll3 op only for dsi */ |
| for (j = 1; j < dsi_divider_num; j++) { |
| if ((bitclk * j > op_info->pll3_vco_min) && |
| (bitclk * j < op_info->pll3_vco_max)) { |
| pll3_vco = bitclk * j; |
| break; |
| } |
| } |
| } |
| |
| /* If find the suitable bit clk is shared pll3 op, exit */ |
| if (diff_count == op_info->pll3_op_index) { |
| pll3_vco = op_info->op_table[op_info->pll3_op_index]; |
| return; |
| } |
| |
| #ifdef CONFIG_CORE_1248 |
| cmdline = malloc(COMMAND_LINE_SIZE); |
| strncpy(cmdline, getenv("bootargs"), COMMAND_LINE_SIZE); |
| sprintf(cmdline + strlen(cmdline), " pll3_vco=%d", PLL3_VCO_DEF); |
| setenv("bootargs", cmdline); |
| free(cmdline); |
| #else |
| if (pll3_vco) { |
| cmdline = malloc(COMMAND_LINE_SIZE); |
| strncpy(cmdline, getenv("bootargs"), COMMAND_LINE_SIZE); |
| sprintf(cmdline + strlen(cmdline), " pll3_vco=%d", pll3_vco); |
| setenv("bootargs", cmdline); |
| free(cmdline); |
| } |
| #endif |
| } |
| #else |
| void calculate_dsi_clk(struct mmp_disp_plat_info *mi) |
| { |
| } |
| #endif |