18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright © 2006-2007 Intel Corporation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors: 68c2ecf20Sopenharmony_ci * Eric Anholt <eric@anholt.net> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/i2c.h> 118c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <drm/drm_crtc.h> 148c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "framebuffer.h" 178c2ecf20Sopenharmony_ci#include "gma_display.h" 188c2ecf20Sopenharmony_ci#include "mdfld_dsi_output.h" 198c2ecf20Sopenharmony_ci#include "mdfld_output.h" 208c2ecf20Sopenharmony_ci#include "psb_intel_reg.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* Hardcoded currently */ 238c2ecf20Sopenharmony_cistatic int ksel = KSEL_CRYSTAL_19; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct psb_intel_range_t { 268c2ecf20Sopenharmony_ci int min, max; 278c2ecf20Sopenharmony_ci}; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct mrst_limit_t { 308c2ecf20Sopenharmony_ci struct psb_intel_range_t dot, m, p1; 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistruct mrst_clock_t { 348c2ecf20Sopenharmony_ci /* derived values */ 358c2ecf20Sopenharmony_ci int dot; 368c2ecf20Sopenharmony_ci int m; 378c2ecf20Sopenharmony_ci int p1; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define COUNT_MAX 0x10000000 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_civoid mdfldWaitForPipeDisable(struct drm_device *dev, int pipe) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci struct drm_psb_private *dev_priv = dev->dev_private; 458c2ecf20Sopenharmony_ci const struct psb_offset *map = &dev_priv->regmap[pipe]; 468c2ecf20Sopenharmony_ci int count, temp; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci switch (pipe) { 498c2ecf20Sopenharmony_ci case 0: 508c2ecf20Sopenharmony_ci case 1: 518c2ecf20Sopenharmony_ci case 2: 528c2ecf20Sopenharmony_ci break; 538c2ecf20Sopenharmony_ci default: 548c2ecf20Sopenharmony_ci DRM_ERROR("Illegal Pipe Number.\n"); 558c2ecf20Sopenharmony_ci return; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci /* FIXME JLIU7_PO */ 598c2ecf20Sopenharmony_ci gma_wait_for_vblank(dev); 608c2ecf20Sopenharmony_ci return; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* Wait for for the pipe disable to take effect. */ 638c2ecf20Sopenharmony_ci for (count = 0; count < COUNT_MAX; count++) { 648c2ecf20Sopenharmony_ci temp = REG_READ(map->conf); 658c2ecf20Sopenharmony_ci if ((temp & PIPEACONF_PIPE_STATE) == 0) 668c2ecf20Sopenharmony_ci break; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_civoid mdfldWaitForPipeEnable(struct drm_device *dev, int pipe) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct drm_psb_private *dev_priv = dev->dev_private; 738c2ecf20Sopenharmony_ci const struct psb_offset *map = &dev_priv->regmap[pipe]; 748c2ecf20Sopenharmony_ci int count, temp; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci switch (pipe) { 778c2ecf20Sopenharmony_ci case 0: 788c2ecf20Sopenharmony_ci case 1: 798c2ecf20Sopenharmony_ci case 2: 808c2ecf20Sopenharmony_ci break; 818c2ecf20Sopenharmony_ci default: 828c2ecf20Sopenharmony_ci DRM_ERROR("Illegal Pipe Number.\n"); 838c2ecf20Sopenharmony_ci return; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* FIXME JLIU7_PO */ 878c2ecf20Sopenharmony_ci gma_wait_for_vblank(dev); 888c2ecf20Sopenharmony_ci return; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* Wait for for the pipe enable to take effect. */ 918c2ecf20Sopenharmony_ci for (count = 0; count < COUNT_MAX; count++) { 928c2ecf20Sopenharmony_ci temp = REG_READ(map->conf); 938c2ecf20Sopenharmony_ci if (temp & PIPEACONF_PIPE_STATE) 948c2ecf20Sopenharmony_ci break; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/** 998c2ecf20Sopenharmony_ci * Return the pipe currently connected to the panel fitter, 1008c2ecf20Sopenharmony_ci * or -1 if the panel fitter is not present or not in use 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_cistatic int psb_intel_panel_fitter_pipe(struct drm_device *dev) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci u32 pfit_control; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci pfit_control = REG_READ(PFIT_CONTROL); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* See if the panel fitter is in use */ 1098c2ecf20Sopenharmony_ci if ((pfit_control & PFIT_ENABLE) == 0) 1108c2ecf20Sopenharmony_ci return -1; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* 965 can place panel fitter on either pipe */ 1138c2ecf20Sopenharmony_ci return (pfit_control >> 29) & 0x3; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int check_fb(struct drm_framebuffer *fb) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci if (!fb) 1198c2ecf20Sopenharmony_ci return 0; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci switch (fb->format->cpp[0] * 8) { 1228c2ecf20Sopenharmony_ci case 8: 1238c2ecf20Sopenharmony_ci case 16: 1248c2ecf20Sopenharmony_ci case 24: 1258c2ecf20Sopenharmony_ci case 32: 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci default: 1288c2ecf20Sopenharmony_ci DRM_ERROR("Unknown color depth\n"); 1298c2ecf20Sopenharmony_ci return -EINVAL; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, 1348c2ecf20Sopenharmony_ci struct drm_framebuffer *old_fb) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 1378c2ecf20Sopenharmony_ci struct drm_psb_private *dev_priv = dev->dev_private; 1388c2ecf20Sopenharmony_ci struct drm_framebuffer *fb = crtc->primary->fb; 1398c2ecf20Sopenharmony_ci struct gma_crtc *gma_crtc = to_gma_crtc(crtc); 1408c2ecf20Sopenharmony_ci int pipe = gma_crtc->pipe; 1418c2ecf20Sopenharmony_ci const struct psb_offset *map = &dev_priv->regmap[pipe]; 1428c2ecf20Sopenharmony_ci unsigned long start, offset; 1438c2ecf20Sopenharmony_ci u32 dspcntr; 1448c2ecf20Sopenharmony_ci int ret; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "pipe = 0x%x.\n", pipe); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* no fb bound */ 1498c2ecf20Sopenharmony_ci if (!fb) { 1508c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "No FB bound\n"); 1518c2ecf20Sopenharmony_ci return 0; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci ret = check_fb(fb); 1558c2ecf20Sopenharmony_ci if (ret) 1568c2ecf20Sopenharmony_ci return ret; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (pipe > 2) { 1598c2ecf20Sopenharmony_ci DRM_ERROR("Illegal Pipe Number.\n"); 1608c2ecf20Sopenharmony_ci return -EINVAL; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (!gma_power_begin(dev, true)) 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci start = to_gtt_range(fb->obj[0])->offset; 1678c2ecf20Sopenharmony_ci offset = y * fb->pitches[0] + x * fb->format->cpp[0]; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci REG_WRITE(map->stride, fb->pitches[0]); 1708c2ecf20Sopenharmony_ci dspcntr = REG_READ(map->cntr); 1718c2ecf20Sopenharmony_ci dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci switch (fb->format->cpp[0] * 8) { 1748c2ecf20Sopenharmony_ci case 8: 1758c2ecf20Sopenharmony_ci dspcntr |= DISPPLANE_8BPP; 1768c2ecf20Sopenharmony_ci break; 1778c2ecf20Sopenharmony_ci case 16: 1788c2ecf20Sopenharmony_ci if (fb->format->depth == 15) 1798c2ecf20Sopenharmony_ci dspcntr |= DISPPLANE_15_16BPP; 1808c2ecf20Sopenharmony_ci else 1818c2ecf20Sopenharmony_ci dspcntr |= DISPPLANE_16BPP; 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci case 24: 1848c2ecf20Sopenharmony_ci case 32: 1858c2ecf20Sopenharmony_ci dspcntr |= DISPPLANE_32BPP_NO_ALPHA; 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci REG_WRITE(map->cntr, dspcntr); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "Writing base %08lX %08lX %d %d\n", 1918c2ecf20Sopenharmony_ci start, offset, x, y); 1928c2ecf20Sopenharmony_ci REG_WRITE(map->linoff, offset); 1938c2ecf20Sopenharmony_ci REG_READ(map->linoff); 1948c2ecf20Sopenharmony_ci REG_WRITE(map->surf, start); 1958c2ecf20Sopenharmony_ci REG_READ(map->surf); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci gma_power_end(dev); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return 0; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/* 2038c2ecf20Sopenharmony_ci * Disable the pipe, plane and pll. 2048c2ecf20Sopenharmony_ci * 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_civoid mdfld_disable_crtc(struct drm_device *dev, int pipe) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct drm_psb_private *dev_priv = dev->dev_private; 2098c2ecf20Sopenharmony_ci const struct psb_offset *map = &dev_priv->regmap[pipe]; 2108c2ecf20Sopenharmony_ci u32 temp; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "pipe = %d\n", pipe); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (pipe != 1) 2168c2ecf20Sopenharmony_ci mdfld_dsi_gen_fifo_ready(dev, MIPI_GEN_FIFO_STAT_REG(pipe), 2178c2ecf20Sopenharmony_ci HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* Disable display plane */ 2208c2ecf20Sopenharmony_ci temp = REG_READ(map->cntr); 2218c2ecf20Sopenharmony_ci if ((temp & DISPLAY_PLANE_ENABLE) != 0) { 2228c2ecf20Sopenharmony_ci REG_WRITE(map->cntr, 2238c2ecf20Sopenharmony_ci temp & ~DISPLAY_PLANE_ENABLE); 2248c2ecf20Sopenharmony_ci /* Flush the plane changes */ 2258c2ecf20Sopenharmony_ci REG_WRITE(map->base, REG_READ(map->base)); 2268c2ecf20Sopenharmony_ci REG_READ(map->base); 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* FIXME_JLIU7 MDFLD_PO revisit */ 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* Next, disable display pipes */ 2328c2ecf20Sopenharmony_ci temp = REG_READ(map->conf); 2338c2ecf20Sopenharmony_ci if ((temp & PIPEACONF_ENABLE) != 0) { 2348c2ecf20Sopenharmony_ci temp &= ~PIPEACONF_ENABLE; 2358c2ecf20Sopenharmony_ci temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF; 2368c2ecf20Sopenharmony_ci REG_WRITE(map->conf, temp); 2378c2ecf20Sopenharmony_ci REG_READ(map->conf); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* Wait for for the pipe disable to take effect. */ 2408c2ecf20Sopenharmony_ci mdfldWaitForPipeDisable(dev, pipe); 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci temp = REG_READ(map->dpll); 2448c2ecf20Sopenharmony_ci if (temp & DPLL_VCO_ENABLE) { 2458c2ecf20Sopenharmony_ci if ((pipe != 1 && 2468c2ecf20Sopenharmony_ci !((REG_READ(PIPEACONF) | REG_READ(PIPECCONF)) 2478c2ecf20Sopenharmony_ci & PIPEACONF_ENABLE)) || pipe == 1) { 2488c2ecf20Sopenharmony_ci temp &= ~(DPLL_VCO_ENABLE); 2498c2ecf20Sopenharmony_ci REG_WRITE(map->dpll, temp); 2508c2ecf20Sopenharmony_ci REG_READ(map->dpll); 2518c2ecf20Sopenharmony_ci /* Wait for the clocks to turn off. */ 2528c2ecf20Sopenharmony_ci /* FIXME_MDFLD PO may need more delay */ 2538c2ecf20Sopenharmony_ci udelay(500); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (!(temp & MDFLD_PWR_GATE_EN)) { 2568c2ecf20Sopenharmony_ci /* gating power of DPLL */ 2578c2ecf20Sopenharmony_ci REG_WRITE(map->dpll, temp | MDFLD_PWR_GATE_EN); 2588c2ecf20Sopenharmony_ci /* FIXME_MDFLD PO - change 500 to 1 after PO */ 2598c2ecf20Sopenharmony_ci udelay(5000); 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/** 2678c2ecf20Sopenharmony_ci * Sets the power management mode of the pipe and plane. 2688c2ecf20Sopenharmony_ci * 2698c2ecf20Sopenharmony_ci * This code should probably grow support for turning the cursor off and back 2708c2ecf20Sopenharmony_ci * on appropriately at the same time as we're turning the pipe off/on. 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_cistatic void mdfld_crtc_dpms(struct drm_crtc *crtc, int mode) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 2758c2ecf20Sopenharmony_ci struct drm_psb_private *dev_priv = dev->dev_private; 2768c2ecf20Sopenharmony_ci struct gma_crtc *gma_crtc = to_gma_crtc(crtc); 2778c2ecf20Sopenharmony_ci int pipe = gma_crtc->pipe; 2788c2ecf20Sopenharmony_ci const struct psb_offset *map = &dev_priv->regmap[pipe]; 2798c2ecf20Sopenharmony_ci u32 pipeconf = dev_priv->pipeconf[pipe]; 2808c2ecf20Sopenharmony_ci u32 temp; 2818c2ecf20Sopenharmony_ci int timeout = 0; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "mode = %d, pipe = %d\n", mode, pipe); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* Note: Old code uses pipe a stat for pipe b but that appears 2868c2ecf20Sopenharmony_ci to be a bug */ 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (!gma_power_begin(dev, true)) 2898c2ecf20Sopenharmony_ci return; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* XXX: When our outputs are all unaware of DPMS modes other than off 2928c2ecf20Sopenharmony_ci * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_ci switch (mode) { 2958c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_ON: 2968c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_STANDBY: 2978c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_SUSPEND: 2988c2ecf20Sopenharmony_ci /* Enable the DPLL */ 2998c2ecf20Sopenharmony_ci temp = REG_READ(map->dpll); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if ((temp & DPLL_VCO_ENABLE) == 0) { 3028c2ecf20Sopenharmony_ci /* When ungating power of DPLL, needs to wait 0.5us 3038c2ecf20Sopenharmony_ci before enable the VCO */ 3048c2ecf20Sopenharmony_ci if (temp & MDFLD_PWR_GATE_EN) { 3058c2ecf20Sopenharmony_ci temp &= ~MDFLD_PWR_GATE_EN; 3068c2ecf20Sopenharmony_ci REG_WRITE(map->dpll, temp); 3078c2ecf20Sopenharmony_ci /* FIXME_MDFLD PO - change 500 to 1 after PO */ 3088c2ecf20Sopenharmony_ci udelay(500); 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci REG_WRITE(map->dpll, temp); 3128c2ecf20Sopenharmony_ci REG_READ(map->dpll); 3138c2ecf20Sopenharmony_ci /* FIXME_MDFLD PO - change 500 to 1 after PO */ 3148c2ecf20Sopenharmony_ci udelay(500); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE); 3178c2ecf20Sopenharmony_ci REG_READ(map->dpll); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /** 3208c2ecf20Sopenharmony_ci * wait for DSI PLL to lock 3218c2ecf20Sopenharmony_ci * NOTE: only need to poll status of pipe 0 and pipe 1, 3228c2ecf20Sopenharmony_ci * since both MIPI pipes share the same PLL. 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_ci while ((pipe != 2) && (timeout < 20000) && 3258c2ecf20Sopenharmony_ci !(REG_READ(map->conf) & PIPECONF_DSIPLL_LOCK)) { 3268c2ecf20Sopenharmony_ci udelay(150); 3278c2ecf20Sopenharmony_ci timeout++; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* Enable the plane */ 3328c2ecf20Sopenharmony_ci temp = REG_READ(map->cntr); 3338c2ecf20Sopenharmony_ci if ((temp & DISPLAY_PLANE_ENABLE) == 0) { 3348c2ecf20Sopenharmony_ci REG_WRITE(map->cntr, 3358c2ecf20Sopenharmony_ci temp | DISPLAY_PLANE_ENABLE); 3368c2ecf20Sopenharmony_ci /* Flush the plane changes */ 3378c2ecf20Sopenharmony_ci REG_WRITE(map->base, REG_READ(map->base)); 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* Enable the pipe */ 3418c2ecf20Sopenharmony_ci temp = REG_READ(map->conf); 3428c2ecf20Sopenharmony_ci if ((temp & PIPEACONF_ENABLE) == 0) { 3438c2ecf20Sopenharmony_ci REG_WRITE(map->conf, pipeconf); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* Wait for for the pipe enable to take effect. */ 3468c2ecf20Sopenharmony_ci mdfldWaitForPipeEnable(dev, pipe); 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /*workaround for sighting 3741701 Random X blank display*/ 3508c2ecf20Sopenharmony_ci /*perform w/a in video mode only on pipe A or C*/ 3518c2ecf20Sopenharmony_ci if (pipe == 0 || pipe == 2) { 3528c2ecf20Sopenharmony_ci REG_WRITE(map->status, REG_READ(map->status)); 3538c2ecf20Sopenharmony_ci msleep(100); 3548c2ecf20Sopenharmony_ci if (PIPE_VBLANK_STATUS & REG_READ(map->status)) 3558c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "OK"); 3568c2ecf20Sopenharmony_ci else { 3578c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "STUCK!!!!"); 3588c2ecf20Sopenharmony_ci /*shutdown controller*/ 3598c2ecf20Sopenharmony_ci temp = REG_READ(map->cntr); 3608c2ecf20Sopenharmony_ci REG_WRITE(map->cntr, 3618c2ecf20Sopenharmony_ci temp & ~DISPLAY_PLANE_ENABLE); 3628c2ecf20Sopenharmony_ci REG_WRITE(map->base, REG_READ(map->base)); 3638c2ecf20Sopenharmony_ci /*mdfld_dsi_dpi_shut_down(dev, pipe);*/ 3648c2ecf20Sopenharmony_ci REG_WRITE(0xb048, 1); 3658c2ecf20Sopenharmony_ci msleep(100); 3668c2ecf20Sopenharmony_ci temp = REG_READ(map->conf); 3678c2ecf20Sopenharmony_ci temp &= ~PIPEACONF_ENABLE; 3688c2ecf20Sopenharmony_ci REG_WRITE(map->conf, temp); 3698c2ecf20Sopenharmony_ci msleep(100); /*wait for pipe disable*/ 3708c2ecf20Sopenharmony_ci REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 0); 3718c2ecf20Sopenharmony_ci msleep(100); 3728c2ecf20Sopenharmony_ci REG_WRITE(0xb004, REG_READ(0xb004)); 3738c2ecf20Sopenharmony_ci /* try to bring the controller back up again*/ 3748c2ecf20Sopenharmony_ci REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 1); 3758c2ecf20Sopenharmony_ci temp = REG_READ(map->cntr); 3768c2ecf20Sopenharmony_ci REG_WRITE(map->cntr, 3778c2ecf20Sopenharmony_ci temp | DISPLAY_PLANE_ENABLE); 3788c2ecf20Sopenharmony_ci REG_WRITE(map->base, REG_READ(map->base)); 3798c2ecf20Sopenharmony_ci /*mdfld_dsi_dpi_turn_on(dev, pipe);*/ 3808c2ecf20Sopenharmony_ci REG_WRITE(0xb048, 2); 3818c2ecf20Sopenharmony_ci msleep(100); 3828c2ecf20Sopenharmony_ci temp = REG_READ(map->conf); 3838c2ecf20Sopenharmony_ci temp |= PIPEACONF_ENABLE; 3848c2ecf20Sopenharmony_ci REG_WRITE(map->conf, temp); 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci gma_crtc_load_lut(crtc); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* Give the overlay scaler a chance to enable 3918c2ecf20Sopenharmony_ci if it's on this pipe */ 3928c2ecf20Sopenharmony_ci /* psb_intel_crtc_dpms_video(crtc, true); TODO */ 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci case DRM_MODE_DPMS_OFF: 3968c2ecf20Sopenharmony_ci /* Give the overlay scaler a chance to disable 3978c2ecf20Sopenharmony_ci * if it's on this pipe */ 3988c2ecf20Sopenharmony_ci /* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */ 3998c2ecf20Sopenharmony_ci if (pipe != 1) 4008c2ecf20Sopenharmony_ci mdfld_dsi_gen_fifo_ready(dev, 4018c2ecf20Sopenharmony_ci MIPI_GEN_FIFO_STAT_REG(pipe), 4028c2ecf20Sopenharmony_ci HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci /* Disable the VGA plane that we never use */ 4058c2ecf20Sopenharmony_ci REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* Disable display plane */ 4088c2ecf20Sopenharmony_ci temp = REG_READ(map->cntr); 4098c2ecf20Sopenharmony_ci if ((temp & DISPLAY_PLANE_ENABLE) != 0) { 4108c2ecf20Sopenharmony_ci REG_WRITE(map->cntr, 4118c2ecf20Sopenharmony_ci temp & ~DISPLAY_PLANE_ENABLE); 4128c2ecf20Sopenharmony_ci /* Flush the plane changes */ 4138c2ecf20Sopenharmony_ci REG_WRITE(map->base, REG_READ(map->base)); 4148c2ecf20Sopenharmony_ci REG_READ(map->base); 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* Next, disable display pipes */ 4188c2ecf20Sopenharmony_ci temp = REG_READ(map->conf); 4198c2ecf20Sopenharmony_ci if ((temp & PIPEACONF_ENABLE) != 0) { 4208c2ecf20Sopenharmony_ci temp &= ~PIPEACONF_ENABLE; 4218c2ecf20Sopenharmony_ci temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF; 4228c2ecf20Sopenharmony_ci REG_WRITE(map->conf, temp); 4238c2ecf20Sopenharmony_ci REG_READ(map->conf); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* Wait for for the pipe disable to take effect. */ 4268c2ecf20Sopenharmony_ci mdfldWaitForPipeDisable(dev, pipe); 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci temp = REG_READ(map->dpll); 4308c2ecf20Sopenharmony_ci if (temp & DPLL_VCO_ENABLE) { 4318c2ecf20Sopenharmony_ci if ((pipe != 1 && !((REG_READ(PIPEACONF) 4328c2ecf20Sopenharmony_ci | REG_READ(PIPECCONF)) & PIPEACONF_ENABLE)) 4338c2ecf20Sopenharmony_ci || pipe == 1) { 4348c2ecf20Sopenharmony_ci temp &= ~(DPLL_VCO_ENABLE); 4358c2ecf20Sopenharmony_ci REG_WRITE(map->dpll, temp); 4368c2ecf20Sopenharmony_ci REG_READ(map->dpll); 4378c2ecf20Sopenharmony_ci /* Wait for the clocks to turn off. */ 4388c2ecf20Sopenharmony_ci /* FIXME_MDFLD PO may need more delay */ 4398c2ecf20Sopenharmony_ci udelay(500); 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci break; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci gma_power_end(dev); 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci#define MDFLD_LIMT_DPLL_19 0 4498c2ecf20Sopenharmony_ci#define MDFLD_LIMT_DPLL_25 1 4508c2ecf20Sopenharmony_ci#define MDFLD_LIMT_DPLL_83 2 4518c2ecf20Sopenharmony_ci#define MDFLD_LIMT_DPLL_100 3 4528c2ecf20Sopenharmony_ci#define MDFLD_LIMT_DSIPLL_19 4 4538c2ecf20Sopenharmony_ci#define MDFLD_LIMT_DSIPLL_25 5 4548c2ecf20Sopenharmony_ci#define MDFLD_LIMT_DSIPLL_83 6 4558c2ecf20Sopenharmony_ci#define MDFLD_LIMT_DSIPLL_100 7 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci#define MDFLD_DOT_MIN 19750 4588c2ecf20Sopenharmony_ci#define MDFLD_DOT_MAX 120000 4598c2ecf20Sopenharmony_ci#define MDFLD_DPLL_M_MIN_19 113 4608c2ecf20Sopenharmony_ci#define MDFLD_DPLL_M_MAX_19 155 4618c2ecf20Sopenharmony_ci#define MDFLD_DPLL_P1_MIN_19 2 4628c2ecf20Sopenharmony_ci#define MDFLD_DPLL_P1_MAX_19 10 4638c2ecf20Sopenharmony_ci#define MDFLD_DPLL_M_MIN_25 101 4648c2ecf20Sopenharmony_ci#define MDFLD_DPLL_M_MAX_25 130 4658c2ecf20Sopenharmony_ci#define MDFLD_DPLL_P1_MIN_25 2 4668c2ecf20Sopenharmony_ci#define MDFLD_DPLL_P1_MAX_25 10 4678c2ecf20Sopenharmony_ci#define MDFLD_DPLL_M_MIN_83 64 4688c2ecf20Sopenharmony_ci#define MDFLD_DPLL_M_MAX_83 64 4698c2ecf20Sopenharmony_ci#define MDFLD_DPLL_P1_MIN_83 2 4708c2ecf20Sopenharmony_ci#define MDFLD_DPLL_P1_MAX_83 2 4718c2ecf20Sopenharmony_ci#define MDFLD_DPLL_M_MIN_100 64 4728c2ecf20Sopenharmony_ci#define MDFLD_DPLL_M_MAX_100 64 4738c2ecf20Sopenharmony_ci#define MDFLD_DPLL_P1_MIN_100 2 4748c2ecf20Sopenharmony_ci#define MDFLD_DPLL_P1_MAX_100 2 4758c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_M_MIN_19 131 4768c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_M_MAX_19 175 4778c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_P1_MIN_19 3 4788c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_P1_MAX_19 8 4798c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_M_MIN_25 97 4808c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_M_MAX_25 140 4818c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_P1_MIN_25 3 4828c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_P1_MAX_25 9 4838c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_M_MIN_83 33 4848c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_M_MAX_83 92 4858c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_P1_MIN_83 2 4868c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_P1_MAX_83 3 4878c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_M_MIN_100 97 4888c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_M_MAX_100 140 4898c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_P1_MIN_100 3 4908c2ecf20Sopenharmony_ci#define MDFLD_DSIPLL_P1_MAX_100 9 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic const struct mrst_limit_t mdfld_limits[] = { 4938c2ecf20Sopenharmony_ci { /* MDFLD_LIMT_DPLL_19 */ 4948c2ecf20Sopenharmony_ci .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, 4958c2ecf20Sopenharmony_ci .m = {.min = MDFLD_DPLL_M_MIN_19, .max = MDFLD_DPLL_M_MAX_19}, 4968c2ecf20Sopenharmony_ci .p1 = {.min = MDFLD_DPLL_P1_MIN_19, .max = MDFLD_DPLL_P1_MAX_19}, 4978c2ecf20Sopenharmony_ci }, 4988c2ecf20Sopenharmony_ci { /* MDFLD_LIMT_DPLL_25 */ 4998c2ecf20Sopenharmony_ci .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, 5008c2ecf20Sopenharmony_ci .m = {.min = MDFLD_DPLL_M_MIN_25, .max = MDFLD_DPLL_M_MAX_25}, 5018c2ecf20Sopenharmony_ci .p1 = {.min = MDFLD_DPLL_P1_MIN_25, .max = MDFLD_DPLL_P1_MAX_25}, 5028c2ecf20Sopenharmony_ci }, 5038c2ecf20Sopenharmony_ci { /* MDFLD_LIMT_DPLL_83 */ 5048c2ecf20Sopenharmony_ci .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, 5058c2ecf20Sopenharmony_ci .m = {.min = MDFLD_DPLL_M_MIN_83, .max = MDFLD_DPLL_M_MAX_83}, 5068c2ecf20Sopenharmony_ci .p1 = {.min = MDFLD_DPLL_P1_MIN_83, .max = MDFLD_DPLL_P1_MAX_83}, 5078c2ecf20Sopenharmony_ci }, 5088c2ecf20Sopenharmony_ci { /* MDFLD_LIMT_DPLL_100 */ 5098c2ecf20Sopenharmony_ci .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, 5108c2ecf20Sopenharmony_ci .m = {.min = MDFLD_DPLL_M_MIN_100, .max = MDFLD_DPLL_M_MAX_100}, 5118c2ecf20Sopenharmony_ci .p1 = {.min = MDFLD_DPLL_P1_MIN_100, .max = MDFLD_DPLL_P1_MAX_100}, 5128c2ecf20Sopenharmony_ci }, 5138c2ecf20Sopenharmony_ci { /* MDFLD_LIMT_DSIPLL_19 */ 5148c2ecf20Sopenharmony_ci .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, 5158c2ecf20Sopenharmony_ci .m = {.min = MDFLD_DSIPLL_M_MIN_19, .max = MDFLD_DSIPLL_M_MAX_19}, 5168c2ecf20Sopenharmony_ci .p1 = {.min = MDFLD_DSIPLL_P1_MIN_19, .max = MDFLD_DSIPLL_P1_MAX_19}, 5178c2ecf20Sopenharmony_ci }, 5188c2ecf20Sopenharmony_ci { /* MDFLD_LIMT_DSIPLL_25 */ 5198c2ecf20Sopenharmony_ci .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, 5208c2ecf20Sopenharmony_ci .m = {.min = MDFLD_DSIPLL_M_MIN_25, .max = MDFLD_DSIPLL_M_MAX_25}, 5218c2ecf20Sopenharmony_ci .p1 = {.min = MDFLD_DSIPLL_P1_MIN_25, .max = MDFLD_DSIPLL_P1_MAX_25}, 5228c2ecf20Sopenharmony_ci }, 5238c2ecf20Sopenharmony_ci { /* MDFLD_LIMT_DSIPLL_83 */ 5248c2ecf20Sopenharmony_ci .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, 5258c2ecf20Sopenharmony_ci .m = {.min = MDFLD_DSIPLL_M_MIN_83, .max = MDFLD_DSIPLL_M_MAX_83}, 5268c2ecf20Sopenharmony_ci .p1 = {.min = MDFLD_DSIPLL_P1_MIN_83, .max = MDFLD_DSIPLL_P1_MAX_83}, 5278c2ecf20Sopenharmony_ci }, 5288c2ecf20Sopenharmony_ci { /* MDFLD_LIMT_DSIPLL_100 */ 5298c2ecf20Sopenharmony_ci .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, 5308c2ecf20Sopenharmony_ci .m = {.min = MDFLD_DSIPLL_M_MIN_100, .max = MDFLD_DSIPLL_M_MAX_100}, 5318c2ecf20Sopenharmony_ci .p1 = {.min = MDFLD_DSIPLL_P1_MIN_100, .max = MDFLD_DSIPLL_P1_MAX_100}, 5328c2ecf20Sopenharmony_ci }, 5338c2ecf20Sopenharmony_ci}; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci#define MDFLD_M_MIN 21 5368c2ecf20Sopenharmony_ci#define MDFLD_M_MAX 180 5378c2ecf20Sopenharmony_cistatic const u32 mdfld_m_converts[] = { 5388c2ecf20Sopenharmony_ci/* M configuration table from 9-bit LFSR table */ 5398c2ecf20Sopenharmony_ci 224, 368, 440, 220, 366, 439, 219, 365, 182, 347, /* 21 - 30 */ 5408c2ecf20Sopenharmony_ci 173, 342, 171, 85, 298, 149, 74, 37, 18, 265, /* 31 - 40 */ 5418c2ecf20Sopenharmony_ci 388, 194, 353, 432, 216, 108, 310, 155, 333, 166, /* 41 - 50 */ 5428c2ecf20Sopenharmony_ci 83, 41, 276, 138, 325, 162, 337, 168, 340, 170, /* 51 - 60 */ 5438c2ecf20Sopenharmony_ci 341, 426, 469, 234, 373, 442, 221, 110, 311, 411, /* 61 - 70 */ 5448c2ecf20Sopenharmony_ci 461, 486, 243, 377, 188, 350, 175, 343, 427, 213, /* 71 - 80 */ 5458c2ecf20Sopenharmony_ci 106, 53, 282, 397, 354, 227, 113, 56, 284, 142, /* 81 - 90 */ 5468c2ecf20Sopenharmony_ci 71, 35, 273, 136, 324, 418, 465, 488, 500, 506, /* 91 - 100 */ 5478c2ecf20Sopenharmony_ci 253, 126, 63, 287, 399, 455, 483, 241, 376, 444, /* 101 - 110 */ 5488c2ecf20Sopenharmony_ci 478, 495, 503, 251, 381, 446, 479, 239, 375, 443, /* 111 - 120 */ 5498c2ecf20Sopenharmony_ci 477, 238, 119, 315, 157, 78, 295, 147, 329, 420, /* 121 - 130 */ 5508c2ecf20Sopenharmony_ci 210, 105, 308, 154, 77, 38, 275, 137, 68, 290, /* 131 - 140 */ 5518c2ecf20Sopenharmony_ci 145, 328, 164, 82, 297, 404, 458, 485, 498, 249, /* 141 - 150 */ 5528c2ecf20Sopenharmony_ci 380, 190, 351, 431, 471, 235, 117, 314, 413, 206, /* 151 - 160 */ 5538c2ecf20Sopenharmony_ci 103, 51, 25, 12, 262, 387, 193, 96, 48, 280, /* 161 - 170 */ 5548c2ecf20Sopenharmony_ci 396, 198, 99, 305, 152, 76, 294, 403, 457, 228, /* 171 - 180 */ 5558c2ecf20Sopenharmony_ci}; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic const struct mrst_limit_t *mdfld_limit(struct drm_crtc *crtc) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci const struct mrst_limit_t *limit = NULL; 5608c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 5618c2ecf20Sopenharmony_ci struct drm_psb_private *dev_priv = dev->dev_private; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (gma_pipe_has_type(crtc, INTEL_OUTPUT_MIPI) 5648c2ecf20Sopenharmony_ci || gma_pipe_has_type(crtc, INTEL_OUTPUT_MIPI2)) { 5658c2ecf20Sopenharmony_ci if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) 5668c2ecf20Sopenharmony_ci limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_19]; 5678c2ecf20Sopenharmony_ci else if (ksel == KSEL_BYPASS_25) 5688c2ecf20Sopenharmony_ci limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_25]; 5698c2ecf20Sopenharmony_ci else if ((ksel == KSEL_BYPASS_83_100) && 5708c2ecf20Sopenharmony_ci (dev_priv->core_freq == 166)) 5718c2ecf20Sopenharmony_ci limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_83]; 5728c2ecf20Sopenharmony_ci else if ((ksel == KSEL_BYPASS_83_100) && 5738c2ecf20Sopenharmony_ci (dev_priv->core_freq == 100 || 5748c2ecf20Sopenharmony_ci dev_priv->core_freq == 200)) 5758c2ecf20Sopenharmony_ci limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_100]; 5768c2ecf20Sopenharmony_ci } else if (gma_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) { 5778c2ecf20Sopenharmony_ci if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) 5788c2ecf20Sopenharmony_ci limit = &mdfld_limits[MDFLD_LIMT_DPLL_19]; 5798c2ecf20Sopenharmony_ci else if (ksel == KSEL_BYPASS_25) 5808c2ecf20Sopenharmony_ci limit = &mdfld_limits[MDFLD_LIMT_DPLL_25]; 5818c2ecf20Sopenharmony_ci else if ((ksel == KSEL_BYPASS_83_100) && 5828c2ecf20Sopenharmony_ci (dev_priv->core_freq == 166)) 5838c2ecf20Sopenharmony_ci limit = &mdfld_limits[MDFLD_LIMT_DPLL_83]; 5848c2ecf20Sopenharmony_ci else if ((ksel == KSEL_BYPASS_83_100) && 5858c2ecf20Sopenharmony_ci (dev_priv->core_freq == 100 || 5868c2ecf20Sopenharmony_ci dev_priv->core_freq == 200)) 5878c2ecf20Sopenharmony_ci limit = &mdfld_limits[MDFLD_LIMT_DPLL_100]; 5888c2ecf20Sopenharmony_ci } else { 5898c2ecf20Sopenharmony_ci limit = NULL; 5908c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "mdfld_limit Wrong display type.\n"); 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci return limit; 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ 5978c2ecf20Sopenharmony_cistatic void mdfld_clock(int refclk, struct mrst_clock_t *clock) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci clock->dot = (refclk * clock->m) / clock->p1; 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci/** 6038c2ecf20Sopenharmony_ci * Returns a set of divisors for the desired target clock with the given refclk, 6048c2ecf20Sopenharmony_ci * or FALSE. Divisor values are the actual divisors for 6058c2ecf20Sopenharmony_ci */ 6068c2ecf20Sopenharmony_cistatic bool 6078c2ecf20Sopenharmony_cimdfldFindBestPLL(struct drm_crtc *crtc, int target, int refclk, 6088c2ecf20Sopenharmony_ci struct mrst_clock_t *best_clock) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct mrst_clock_t clock; 6118c2ecf20Sopenharmony_ci const struct mrst_limit_t *limit = mdfld_limit(crtc); 6128c2ecf20Sopenharmony_ci int err = target; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci memset(best_clock, 0, sizeof(*best_clock)); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) { 6178c2ecf20Sopenharmony_ci for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max; 6188c2ecf20Sopenharmony_ci clock.p1++) { 6198c2ecf20Sopenharmony_ci int this_err; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci mdfld_clock(refclk, &clock); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci this_err = abs(clock.dot - target); 6248c2ecf20Sopenharmony_ci if (this_err < err) { 6258c2ecf20Sopenharmony_ci *best_clock = clock; 6268c2ecf20Sopenharmony_ci err = this_err; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci return err != target; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic int mdfld_crtc_mode_set(struct drm_crtc *crtc, 6348c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 6358c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode, 6368c2ecf20Sopenharmony_ci int x, int y, 6378c2ecf20Sopenharmony_ci struct drm_framebuffer *old_fb) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci struct drm_device *dev = crtc->dev; 6408c2ecf20Sopenharmony_ci struct gma_crtc *gma_crtc = to_gma_crtc(crtc); 6418c2ecf20Sopenharmony_ci struct drm_psb_private *dev_priv = dev->dev_private; 6428c2ecf20Sopenharmony_ci int pipe = gma_crtc->pipe; 6438c2ecf20Sopenharmony_ci const struct psb_offset *map = &dev_priv->regmap[pipe]; 6448c2ecf20Sopenharmony_ci int refclk = 0; 6458c2ecf20Sopenharmony_ci int clk_n = 0, clk_p2 = 0, clk_byte = 1, clk = 0, m_conv = 0, 6468c2ecf20Sopenharmony_ci clk_tmp = 0; 6478c2ecf20Sopenharmony_ci struct mrst_clock_t clock; 6488c2ecf20Sopenharmony_ci bool ok; 6498c2ecf20Sopenharmony_ci u32 dpll = 0, fp = 0; 6508c2ecf20Sopenharmony_ci bool is_mipi = false, is_mipi2 = false, is_hdmi = false; 6518c2ecf20Sopenharmony_ci struct drm_mode_config *mode_config = &dev->mode_config; 6528c2ecf20Sopenharmony_ci struct gma_encoder *gma_encoder = NULL; 6538c2ecf20Sopenharmony_ci uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN; 6548c2ecf20Sopenharmony_ci struct drm_encoder *encoder; 6558c2ecf20Sopenharmony_ci struct drm_connector *connector; 6568c2ecf20Sopenharmony_ci int timeout = 0; 6578c2ecf20Sopenharmony_ci int ret; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "pipe = 0x%x\n", pipe); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci ret = check_fb(crtc->primary->fb); 6628c2ecf20Sopenharmony_ci if (ret) 6638c2ecf20Sopenharmony_ci return ret; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "adjusted_hdisplay = %d\n", 6668c2ecf20Sopenharmony_ci adjusted_mode->hdisplay); 6678c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "adjusted_vdisplay = %d\n", 6688c2ecf20Sopenharmony_ci adjusted_mode->vdisplay); 6698c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "adjusted_hsync_start = %d\n", 6708c2ecf20Sopenharmony_ci adjusted_mode->hsync_start); 6718c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "adjusted_hsync_end = %d\n", 6728c2ecf20Sopenharmony_ci adjusted_mode->hsync_end); 6738c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "adjusted_htotal = %d\n", 6748c2ecf20Sopenharmony_ci adjusted_mode->htotal); 6758c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "adjusted_vsync_start = %d\n", 6768c2ecf20Sopenharmony_ci adjusted_mode->vsync_start); 6778c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "adjusted_vsync_end = %d\n", 6788c2ecf20Sopenharmony_ci adjusted_mode->vsync_end); 6798c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "adjusted_vtotal = %d\n", 6808c2ecf20Sopenharmony_ci adjusted_mode->vtotal); 6818c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "adjusted_clock = %d\n", 6828c2ecf20Sopenharmony_ci adjusted_mode->clock); 6838c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "hdisplay = %d\n", 6848c2ecf20Sopenharmony_ci mode->hdisplay); 6858c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "vdisplay = %d\n", 6868c2ecf20Sopenharmony_ci mode->vdisplay); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci if (!gma_power_begin(dev, true)) 6898c2ecf20Sopenharmony_ci return 0; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci memcpy(&gma_crtc->saved_mode, mode, 6928c2ecf20Sopenharmony_ci sizeof(struct drm_display_mode)); 6938c2ecf20Sopenharmony_ci memcpy(&gma_crtc->saved_adjusted_mode, adjusted_mode, 6948c2ecf20Sopenharmony_ci sizeof(struct drm_display_mode)); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci list_for_each_entry(connector, &mode_config->connector_list, head) { 6978c2ecf20Sopenharmony_ci encoder = connector->encoder; 6988c2ecf20Sopenharmony_ci if (!encoder) 6998c2ecf20Sopenharmony_ci continue; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (encoder->crtc != crtc) 7028c2ecf20Sopenharmony_ci continue; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci gma_encoder = gma_attached_encoder(connector); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci switch (gma_encoder->type) { 7078c2ecf20Sopenharmony_ci case INTEL_OUTPUT_MIPI: 7088c2ecf20Sopenharmony_ci is_mipi = true; 7098c2ecf20Sopenharmony_ci break; 7108c2ecf20Sopenharmony_ci case INTEL_OUTPUT_MIPI2: 7118c2ecf20Sopenharmony_ci is_mipi2 = true; 7128c2ecf20Sopenharmony_ci break; 7138c2ecf20Sopenharmony_ci case INTEL_OUTPUT_HDMI: 7148c2ecf20Sopenharmony_ci is_hdmi = true; 7158c2ecf20Sopenharmony_ci break; 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci /* Disable the VGA plane that we never use */ 7208c2ecf20Sopenharmony_ci REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* Disable the panel fitter if it was on our pipe */ 7238c2ecf20Sopenharmony_ci if (psb_intel_panel_fitter_pipe(dev) == pipe) 7248c2ecf20Sopenharmony_ci REG_WRITE(PFIT_CONTROL, 0); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* pipesrc and dspsize control the size that is scaled from, 7278c2ecf20Sopenharmony_ci * which should always be the user's requested size. 7288c2ecf20Sopenharmony_ci */ 7298c2ecf20Sopenharmony_ci if (pipe == 1) { 7308c2ecf20Sopenharmony_ci /* FIXME: To make HDMI display with 864x480 (TPO), 480x864 7318c2ecf20Sopenharmony_ci * (PYR) or 480x854 (TMD), set the sprite width/height and 7328c2ecf20Sopenharmony_ci * souce image size registers with the adjusted mode for 7338c2ecf20Sopenharmony_ci * pipe B. 7348c2ecf20Sopenharmony_ci */ 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* 7378c2ecf20Sopenharmony_ci * The defined sprite rectangle must always be completely 7388c2ecf20Sopenharmony_ci * contained within the displayable area of the screen image 7398c2ecf20Sopenharmony_ci * (frame buffer). 7408c2ecf20Sopenharmony_ci */ 7418c2ecf20Sopenharmony_ci REG_WRITE(map->size, ((min(mode->crtc_vdisplay, adjusted_mode->crtc_vdisplay) - 1) << 16) 7428c2ecf20Sopenharmony_ci | (min(mode->crtc_hdisplay, adjusted_mode->crtc_hdisplay) - 1)); 7438c2ecf20Sopenharmony_ci /* Set the CRTC with encoder mode. */ 7448c2ecf20Sopenharmony_ci REG_WRITE(map->src, ((mode->crtc_hdisplay - 1) << 16) 7458c2ecf20Sopenharmony_ci | (mode->crtc_vdisplay - 1)); 7468c2ecf20Sopenharmony_ci } else { 7478c2ecf20Sopenharmony_ci REG_WRITE(map->size, 7488c2ecf20Sopenharmony_ci ((mode->crtc_vdisplay - 1) << 16) | 7498c2ecf20Sopenharmony_ci (mode->crtc_hdisplay - 1)); 7508c2ecf20Sopenharmony_ci REG_WRITE(map->src, 7518c2ecf20Sopenharmony_ci ((mode->crtc_hdisplay - 1) << 16) | 7528c2ecf20Sopenharmony_ci (mode->crtc_vdisplay - 1)); 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci REG_WRITE(map->pos, 0); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (gma_encoder) 7588c2ecf20Sopenharmony_ci drm_object_property_get_value(&connector->base, 7598c2ecf20Sopenharmony_ci dev->mode_config.scaling_mode_property, &scalingType); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (scalingType == DRM_MODE_SCALE_NO_SCALE) { 7628c2ecf20Sopenharmony_ci /* Medfield doesn't have register support for centering so we 7638c2ecf20Sopenharmony_ci * need to mess with the h/vblank and h/vsync start and ends 7648c2ecf20Sopenharmony_ci * to get centering 7658c2ecf20Sopenharmony_ci */ 7668c2ecf20Sopenharmony_ci int offsetX = 0, offsetY = 0; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci offsetX = (adjusted_mode->crtc_hdisplay - 7698c2ecf20Sopenharmony_ci mode->crtc_hdisplay) / 2; 7708c2ecf20Sopenharmony_ci offsetY = (adjusted_mode->crtc_vdisplay - 7718c2ecf20Sopenharmony_ci mode->crtc_vdisplay) / 2; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci REG_WRITE(map->htotal, (mode->crtc_hdisplay - 1) | 7748c2ecf20Sopenharmony_ci ((adjusted_mode->crtc_htotal - 1) << 16)); 7758c2ecf20Sopenharmony_ci REG_WRITE(map->vtotal, (mode->crtc_vdisplay - 1) | 7768c2ecf20Sopenharmony_ci ((adjusted_mode->crtc_vtotal - 1) << 16)); 7778c2ecf20Sopenharmony_ci REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start - 7788c2ecf20Sopenharmony_ci offsetX - 1) | 7798c2ecf20Sopenharmony_ci ((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16)); 7808c2ecf20Sopenharmony_ci REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start - 7818c2ecf20Sopenharmony_ci offsetX - 1) | 7828c2ecf20Sopenharmony_ci ((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16)); 7838c2ecf20Sopenharmony_ci REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start - 7848c2ecf20Sopenharmony_ci offsetY - 1) | 7858c2ecf20Sopenharmony_ci ((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16)); 7868c2ecf20Sopenharmony_ci REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start - 7878c2ecf20Sopenharmony_ci offsetY - 1) | 7888c2ecf20Sopenharmony_ci ((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16)); 7898c2ecf20Sopenharmony_ci } else { 7908c2ecf20Sopenharmony_ci REG_WRITE(map->htotal, (adjusted_mode->crtc_hdisplay - 1) | 7918c2ecf20Sopenharmony_ci ((adjusted_mode->crtc_htotal - 1) << 16)); 7928c2ecf20Sopenharmony_ci REG_WRITE(map->vtotal, (adjusted_mode->crtc_vdisplay - 1) | 7938c2ecf20Sopenharmony_ci ((adjusted_mode->crtc_vtotal - 1) << 16)); 7948c2ecf20Sopenharmony_ci REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start - 1) | 7958c2ecf20Sopenharmony_ci ((adjusted_mode->crtc_hblank_end - 1) << 16)); 7968c2ecf20Sopenharmony_ci REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start - 1) | 7978c2ecf20Sopenharmony_ci ((adjusted_mode->crtc_hsync_end - 1) << 16)); 7988c2ecf20Sopenharmony_ci REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start - 1) | 7998c2ecf20Sopenharmony_ci ((adjusted_mode->crtc_vblank_end - 1) << 16)); 8008c2ecf20Sopenharmony_ci REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start - 1) | 8018c2ecf20Sopenharmony_ci ((adjusted_mode->crtc_vsync_end - 1) << 16)); 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci /* Flush the plane changes */ 8058c2ecf20Sopenharmony_ci { 8068c2ecf20Sopenharmony_ci const struct drm_crtc_helper_funcs *crtc_funcs = 8078c2ecf20Sopenharmony_ci crtc->helper_private; 8088c2ecf20Sopenharmony_ci crtc_funcs->mode_set_base(crtc, x, y, old_fb); 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci /* setup pipeconf */ 8128c2ecf20Sopenharmony_ci dev_priv->pipeconf[pipe] = PIPEACONF_ENABLE; /* FIXME_JLIU7 REG_READ(pipeconf_reg); */ 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci /* Set up the display plane register */ 8158c2ecf20Sopenharmony_ci dev_priv->dspcntr[pipe] = REG_READ(map->cntr); 8168c2ecf20Sopenharmony_ci dev_priv->dspcntr[pipe] |= pipe << DISPPLANE_SEL_PIPE_POS; 8178c2ecf20Sopenharmony_ci dev_priv->dspcntr[pipe] |= DISPLAY_PLANE_ENABLE; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (is_mipi2) 8208c2ecf20Sopenharmony_ci goto mrst_crtc_mode_set_exit; 8218c2ecf20Sopenharmony_ci clk = adjusted_mode->clock; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci if (is_hdmi) { 8248c2ecf20Sopenharmony_ci if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) { 8258c2ecf20Sopenharmony_ci refclk = 19200; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci if (is_mipi || is_mipi2) 8288c2ecf20Sopenharmony_ci clk_n = 1, clk_p2 = 8; 8298c2ecf20Sopenharmony_ci else if (is_hdmi) 8308c2ecf20Sopenharmony_ci clk_n = 1, clk_p2 = 10; 8318c2ecf20Sopenharmony_ci } else if (ksel == KSEL_BYPASS_25) { 8328c2ecf20Sopenharmony_ci refclk = 25000; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci if (is_mipi || is_mipi2) 8358c2ecf20Sopenharmony_ci clk_n = 1, clk_p2 = 8; 8368c2ecf20Sopenharmony_ci else if (is_hdmi) 8378c2ecf20Sopenharmony_ci clk_n = 1, clk_p2 = 10; 8388c2ecf20Sopenharmony_ci } else if ((ksel == KSEL_BYPASS_83_100) && 8398c2ecf20Sopenharmony_ci dev_priv->core_freq == 166) { 8408c2ecf20Sopenharmony_ci refclk = 83000; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci if (is_mipi || is_mipi2) 8438c2ecf20Sopenharmony_ci clk_n = 4, clk_p2 = 8; 8448c2ecf20Sopenharmony_ci else if (is_hdmi) 8458c2ecf20Sopenharmony_ci clk_n = 4, clk_p2 = 10; 8468c2ecf20Sopenharmony_ci } else if ((ksel == KSEL_BYPASS_83_100) && 8478c2ecf20Sopenharmony_ci (dev_priv->core_freq == 100 || 8488c2ecf20Sopenharmony_ci dev_priv->core_freq == 200)) { 8498c2ecf20Sopenharmony_ci refclk = 100000; 8508c2ecf20Sopenharmony_ci if (is_mipi || is_mipi2) 8518c2ecf20Sopenharmony_ci clk_n = 4, clk_p2 = 8; 8528c2ecf20Sopenharmony_ci else if (is_hdmi) 8538c2ecf20Sopenharmony_ci clk_n = 4, clk_p2 = 10; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (is_mipi) 8578c2ecf20Sopenharmony_ci clk_byte = dev_priv->bpp / 8; 8588c2ecf20Sopenharmony_ci else if (is_mipi2) 8598c2ecf20Sopenharmony_ci clk_byte = dev_priv->bpp2 / 8; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci clk_tmp = clk * clk_n * clk_p2 * clk_byte; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "clk = %d, clk_n = %d, clk_p2 = %d.\n", 8648c2ecf20Sopenharmony_ci clk, clk_n, clk_p2); 8658c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "adjusted_mode->clock = %d, clk_tmp = %d.\n", 8668c2ecf20Sopenharmony_ci adjusted_mode->clock, clk_tmp); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci ok = mdfldFindBestPLL(crtc, clk_tmp, refclk, &clock); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci if (!ok) { 8718c2ecf20Sopenharmony_ci DRM_ERROR 8728c2ecf20Sopenharmony_ci ("mdfldFindBestPLL fail in mdfld_crtc_mode_set.\n"); 8738c2ecf20Sopenharmony_ci } else { 8748c2ecf20Sopenharmony_ci m_conv = mdfld_m_converts[(clock.m - MDFLD_M_MIN)]; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "dot clock = %d," 8778c2ecf20Sopenharmony_ci "m = %d, p1 = %d, m_conv = %d.\n", 8788c2ecf20Sopenharmony_ci clock.dot, clock.m, 8798c2ecf20Sopenharmony_ci clock.p1, m_conv); 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci dpll = REG_READ(map->dpll); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (dpll & DPLL_VCO_ENABLE) { 8858c2ecf20Sopenharmony_ci dpll &= ~DPLL_VCO_ENABLE; 8868c2ecf20Sopenharmony_ci REG_WRITE(map->dpll, dpll); 8878c2ecf20Sopenharmony_ci REG_READ(map->dpll); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci /* FIXME jliu7 check the DPLL lock bit PIPEACONF[29] */ 8908c2ecf20Sopenharmony_ci /* FIXME_MDFLD PO - change 500 to 1 after PO */ 8918c2ecf20Sopenharmony_ci udelay(500); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci /* reset M1, N1 & P1 */ 8948c2ecf20Sopenharmony_ci REG_WRITE(map->fp0, 0); 8958c2ecf20Sopenharmony_ci dpll &= ~MDFLD_P1_MASK; 8968c2ecf20Sopenharmony_ci REG_WRITE(map->dpll, dpll); 8978c2ecf20Sopenharmony_ci /* FIXME_MDFLD PO - change 500 to 1 after PO */ 8988c2ecf20Sopenharmony_ci udelay(500); 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci /* When ungating power of DPLL, needs to wait 0.5us before 9028c2ecf20Sopenharmony_ci * enable the VCO */ 9038c2ecf20Sopenharmony_ci if (dpll & MDFLD_PWR_GATE_EN) { 9048c2ecf20Sopenharmony_ci dpll &= ~MDFLD_PWR_GATE_EN; 9058c2ecf20Sopenharmony_ci REG_WRITE(map->dpll, dpll); 9068c2ecf20Sopenharmony_ci /* FIXME_MDFLD PO - change 500 to 1 after PO */ 9078c2ecf20Sopenharmony_ci udelay(500); 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci dpll = 0; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci if (is_hdmi) 9128c2ecf20Sopenharmony_ci dpll |= MDFLD_VCO_SEL; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci fp = (clk_n / 2) << 16; 9158c2ecf20Sopenharmony_ci fp |= m_conv; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci /* compute bitmask from p1 value */ 9188c2ecf20Sopenharmony_ci dpll |= (1 << (clock.p1 - 2)) << 17; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci } else { 9218c2ecf20Sopenharmony_ci dpll = 0x00800000; 9228c2ecf20Sopenharmony_ci fp = 0x000000c1; 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci REG_WRITE(map->fp0, fp); 9268c2ecf20Sopenharmony_ci REG_WRITE(map->dpll, dpll); 9278c2ecf20Sopenharmony_ci /* FIXME_MDFLD PO - change 500 to 1 after PO */ 9288c2ecf20Sopenharmony_ci udelay(500); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci dpll |= DPLL_VCO_ENABLE; 9318c2ecf20Sopenharmony_ci REG_WRITE(map->dpll, dpll); 9328c2ecf20Sopenharmony_ci REG_READ(map->dpll); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci /* wait for DSI PLL to lock */ 9358c2ecf20Sopenharmony_ci while (timeout < 20000 && 9368c2ecf20Sopenharmony_ci !(REG_READ(map->conf) & PIPECONF_DSIPLL_LOCK)) { 9378c2ecf20Sopenharmony_ci udelay(150); 9388c2ecf20Sopenharmony_ci timeout++; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci if (is_mipi) 9428c2ecf20Sopenharmony_ci goto mrst_crtc_mode_set_exit; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "is_mipi = 0x%x\n", is_mipi); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci REG_WRITE(map->conf, dev_priv->pipeconf[pipe]); 9478c2ecf20Sopenharmony_ci REG_READ(map->conf); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci /* Wait for for the pipe enable to take effect. */ 9508c2ecf20Sopenharmony_ci REG_WRITE(map->cntr, dev_priv->dspcntr[pipe]); 9518c2ecf20Sopenharmony_ci gma_wait_for_vblank(dev); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_cimrst_crtc_mode_set_exit: 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci gma_power_end(dev); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci return 0; 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ciconst struct drm_crtc_helper_funcs mdfld_helper_funcs = { 9618c2ecf20Sopenharmony_ci .dpms = mdfld_crtc_dpms, 9628c2ecf20Sopenharmony_ci .mode_set = mdfld_crtc_mode_set, 9638c2ecf20Sopenharmony_ci .mode_set_base = mdfld__intel_pipe_set_base, 9648c2ecf20Sopenharmony_ci .prepare = gma_crtc_prepare, 9658c2ecf20Sopenharmony_ci .commit = gma_crtc_commit, 9668c2ecf20Sopenharmony_ci}; 967