gcdb: display: Update gcdb for auto PLL calculation
Calculate div1, div3, vco clock, bit clock, pixel clock
for given panel resolution, frame rate and lane config.
Change-Id: Ie96c231f33844743ee2a5d9ef7f15fde9d22067d
diff --git a/dev/gcdb/display/gcdb_autopll.c b/dev/gcdb/display/gcdb_autopll.c
new file mode 100755
index 0000000..5cbe292
--- /dev/null
+++ b/dev/gcdb/display/gcdb_autopll.c
@@ -0,0 +1,185 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <err.h>
+#include <smem.h>
+#include <msm_panel.h>
+#include <mipi_dsi.h>
+
+#include "gcdb_autopll.h"
+
+static struct mdss_dsi_pll_config pll_data;
+
+static uint32_t calculate_bitclock(struct msm_panel_info *pinfo)
+{
+ uint32_t ret = NO_ERROR;
+ uint32_t h_period = 0, v_period = 0;
+
+ h_period = pinfo->xres + pinfo->lcdc.h_back_porch +
+ pinfo->lcdc.h_front_porch + pinfo->lcdc.h_pulse_width +
+ pinfo->lcdc.xres_pad;
+
+ v_period = pinfo->yres + pinfo->lcdc.v_back_porch +
+ pinfo->lcdc.v_front_porch + pinfo->lcdc.v_pulse_width +
+ pinfo->lcdc.yres_pad;
+
+ /* Pixel clock rate */
+ pll_data.pixel_clock = h_period * v_period * pinfo->mipi.frame_rate;
+
+ /* Store all bit clock form data */
+ if (pinfo->mipi.bitclock == 0)
+ pll_data.bit_clock = (pll_data.pixel_clock * pinfo->bpp) /
+ pinfo->mipi.num_of_lanes;
+ else
+ pll_data.bit_clock = pinfo->mipi.bitclock;
+
+ pll_data.byte_clock = pll_data.bit_clock >> 3;
+
+ pll_data.halfbit_clock = pll_data.bit_clock >> 1;
+
+ return ret;
+}
+
+static uint32_t calculate_div1()
+{
+ uint32_t ret = NO_ERROR;
+
+ /* div1 - there is divide by 2 logic present */
+ if (pll_data.halfbit_clock > HALFBIT_CLOCK1) {
+ pll_data.posdiv1 = 0x0; /*div 1 */
+ pll_data.vco_clock = pll_data.halfbit_clock << 1;
+ } else if (pll_data.halfbit_clock > HALFBIT_CLOCK2) {
+ pll_data.posdiv1 = 0x1; /*div 2 */
+ pll_data.vco_clock = pll_data.halfbit_clock << 2;
+ } else if (pll_data.halfbit_clock > HALFBIT_CLOCK3) {
+ pll_data.posdiv1 = 0x3; /*div 4 */
+ pll_data.vco_clock = pll_data.halfbit_clock << 3;
+ } else if (pll_data.halfbit_clock > HALFBIT_CLOCK4) {
+ pll_data.posdiv1 = 0x4; /*div 5 */
+ pll_data.vco_clock = pll_data.halfbit_clock * 10;
+ } else {
+ dprintf(CRITICAL, "Not able to calculate posdiv1\n");
+ }
+
+ return ret;
+}
+
+static uint32_t calculate_div3(uint8_t bpp, uint8_t num_of_lanes)
+{
+ uint32_t ret = NO_ERROR;
+ pll_data.pclk_m = 0x1; /* M = 1, N= 1 */
+ pll_data.pclk_n = 0xFF; /* ~ (N-M) = 0xff */
+ pll_data.pclk_d = 0xFF; /* ~N = 0xFF */
+
+ /* formula is ( vco_clock / pdiv_digital) / mnd = pixel_clock */
+
+ /* div3 */
+ switch (bpp) {
+ case BITS_18:
+ if (num_of_lanes == 3) {
+ pll_data.posdiv3 = pll_data.vco_clock /
+ pll_data.pixel_clock;
+ } else {
+ pll_data.posdiv3 = (pll_data.pixel_clock * 2 / 9) /
+ pll_data.vco_clock;
+ pll_data.pclk_m = 0x2; /* M = 2,N = 9 */
+ pll_data.pclk_n = 0xF8;
+ pll_data.pclk_d = 0xF6;
+ }
+ break;
+ case BITS_16:
+ if (num_of_lanes == 3) {
+ pll_data.posdiv3 = (pll_data.pixel_clock * 3 / 8) /
+ pll_data.vco_clock;
+ pll_data.pclk_m = 0x3; /* M = 3, N = 9 */
+ pll_data.pclk_n = 0xFA;
+ pll_data.pclk_d = 0xF7;
+ } else {
+ pll_data.posdiv3 = pll_data.vco_clock /
+ pll_data.pixel_clock;
+ }
+ break;
+ case BITS_24:
+ default:
+ pll_data.posdiv3 = pll_data.vco_clock /
+ pll_data.pixel_clock;
+ break;
+ }
+
+ pll_data.posdiv3--; /* Register needs one value less */
+}
+
+static uint32_t calculate_vco(uint8_t bpp, uint8_t num_of_lanes)
+{
+ uint32_t ret = NO_ERROR;
+ uint8_t counter = 0;
+ uint32_t temprate = 0;
+
+ /* If half bitclock is more than VCO min value */
+ if (pll_data.halfbit_clock > VCO_MIN_CLOCK) {
+
+ /* Direct Mode */
+
+ /* support vco clock to max value only */
+ if (pll_data.halfbit_clock > VCO_MAX_CLOCK)
+ pll_data.vco_clock = VCO_MAX_CLOCK;
+ else
+ pll_data.vco_clock = pll_data.halfbit_clock;
+ pll_data.directpath = 0x0;
+ pll_data.posdiv1 = 0x0; /*DSI spec says 0 - div 1 */
+ /*1 - div 2 */
+ /*F - div 16 */
+ } else {
+ /* Indirect Mode */
+
+ pll_data.directpath = 0x02; /* set bit 1 to enable for
+ indirect path */
+
+ calculate_div1();
+ }
+
+ /* calculate mnd and div3 for direct and indirect path */
+ calculate_div3(bpp, num_of_lanes);
+
+ return ret;
+}
+
+uint32_t calculate_clock_config(struct msm_panel_info *pinfo)
+{
+ uint32_t ret = NO_ERROR;
+
+ calculate_bitclock(pinfo);
+
+ calculate_vco(pinfo->bpp, pinfo->mipi.num_of_lanes);
+
+ pinfo->mipi.dsi_pll_config = &pll_data;
+
+ return ret;
+}