Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gma500: initial medfield merge

We need to merge this ahead of some of the cleanup because a lot of needed
cleanup spans both new and old chips. If we try and clean up and the merge
we end up fighting ourselves.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
[With a load of the cleanup stuff folded in, register stuff reworked sanely]
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>

authored by

Kirill A. Shutemov and committed by
Dave Airlie
026abc33 c6265ff5

+6345
+16
arch/x86/platform/mrst/mrst.c
··· 28 28 #include <linux/module.h> 29 29 #include <linux/notifier.h> 30 30 #include <linux/mfd/intel_msic.h> 31 + #include <linux/gpio.h> 32 + #include <linux/i2c/tc35876x.h> 31 33 32 34 #include <asm/setup.h> 33 35 #include <asm/mpspec_def.h> ··· 688 686 return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_OCD); 689 687 } 690 688 689 + /* tc35876x DSI-LVDS bridge chip and panel platform data */ 690 + static void *tc35876x_platform_data(void *data) 691 + { 692 + static struct tc35876x_platform_data pdata; 693 + 694 + /* gpio pins set to -1 will not be used by the driver */ 695 + pdata.gpio_bridge_reset = get_gpio_by_name("LCMB_RXEN"); 696 + pdata.gpio_panel_bl_en = get_gpio_by_name("6S6P_BL_EN"); 697 + pdata.gpio_panel_vadd = get_gpio_by_name("EN_VREG_LCD_V3P3"); 698 + 699 + return &pdata; 700 + } 701 + 691 702 static const struct devs_id __initconst device_ids[] = { 692 703 {"bma023", SFI_DEV_TYPE_I2C, 1, &no_platform_data}, 693 704 {"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data}, ··· 713 698 {"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data}, 714 699 {"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data}, 715 700 {"mpu3050", SFI_DEV_TYPE_I2C, 1, &mpu3050_platform_data}, 701 + {"i2c_disp_brig", SFI_DEV_TYPE_I2C, 0, &tc35876x_platform_data}, 716 702 717 703 /* MSIC subdevices */ 718 704 {"msic_battery", SFI_DEV_TYPE_IPC, 1, &msic_battery_platform_data},
+7
drivers/gpu/drm/gma500/Kconfig
··· 24 24 help 25 25 Say yes to include basic support for Intel GMA3600/3650 (Intel 26 26 Cedar Trail) platforms. 27 + 28 + config DRM_MEDFIELD 29 + bool "Intel Medfield support (Experimental)" 30 + depends on DRM_GMA500 && X86_INTEL_MID 31 + help 32 + Say yes to include support for the Intel Medfield platform. 33 +
+10
drivers/gpu/drm/gma500/Makefile
··· 37 37 oaktrail_hdmi.o \ 38 38 oaktrail_hdmi_i2c.o 39 39 40 + gma500_gfx-$(CONFIG_DRM_MEDFIELD) += mdfld_device.o \ 41 + mdfld_output.o \ 42 + mdfld_intel_display.o \ 43 + mdfld_dsi_output.o \ 44 + mdfld_dsi_dpi.o \ 45 + mdfld_dsi_pkg_sender.o \ 46 + mdfld_tpo_vid.o \ 47 + mdfld_tmd_vid.o \ 48 + tc35876x-dsi-lvds.o 49 + 40 50 obj-$(CONFIG_DRM_GMA500) += gma500_gfx.o
+691
drivers/gpu/drm/gma500/mdfld_device.c
··· 1 + /************************************************************************** 2 + * Copyright (c) 2011, Intel Corporation. 3 + * All Rights Reserved. 4 + * 5 + * This program is free software; you can redistribute it and/or modify it 6 + * under the terms and conditions of the GNU General Public License, 7 + * version 2, as published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope it will be useful, but WITHOUT 10 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 + * more details. 13 + * 14 + * You should have received a copy of the GNU General Public License along with 15 + * this program; if not, write to the Free Software Foundation, Inc., 16 + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 17 + * 18 + **************************************************************************/ 19 + 20 + #include "psb_drv.h" 21 + #include "mid_bios.h" 22 + #include "mdfld_output.h" 23 + #include "mdfld_dsi_output.h" 24 + #include "tc35876x-dsi-lvds.h" 25 + 26 + #include <asm/intel_scu_ipc.h> 27 + 28 + #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE 29 + 30 + #define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF 31 + #define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */ 32 + #define BLC_PWM_FREQ_CALC_CONSTANT 32 33 + #define MHz 1000000 34 + #define BRIGHTNESS_MIN_LEVEL 1 35 + #define BRIGHTNESS_MAX_LEVEL 100 36 + #define BRIGHTNESS_MASK 0xFF 37 + #define BLC_POLARITY_NORMAL 0 38 + #define BLC_POLARITY_INVERSE 1 39 + #define BLC_ADJUSTMENT_MAX 100 40 + 41 + #define MDFLD_BLC_PWM_PRECISION_FACTOR 10 42 + #define MDFLD_BLC_MAX_PWM_REG_FREQ 0xFFFE 43 + #define MDFLD_BLC_MIN_PWM_REG_FREQ 0x2 44 + 45 + #define MDFLD_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) 46 + #define MDFLD_BACKLIGHT_PWM_CTL_SHIFT (16) 47 + 48 + static struct backlight_device *mdfld_backlight_device; 49 + 50 + int mdfld_set_brightness(struct backlight_device *bd) 51 + { 52 + struct drm_device *dev = 53 + (struct drm_device *)bl_get_data(mdfld_backlight_device); 54 + struct drm_psb_private *dev_priv = dev->dev_private; 55 + int level = bd->props.brightness; 56 + 57 + DRM_DEBUG_DRIVER("backlight level set to %d\n", level); 58 + 59 + /* Perform value bounds checking */ 60 + if (level < BRIGHTNESS_MIN_LEVEL) 61 + level = BRIGHTNESS_MIN_LEVEL; 62 + 63 + if (gma_power_begin(dev, false)) { 64 + u32 adjusted_level = 0; 65 + 66 + /* 67 + * Adjust the backlight level with the percent in 68 + * dev_priv->blc_adj2 69 + */ 70 + adjusted_level = level * dev_priv->blc_adj2; 71 + adjusted_level = adjusted_level / BLC_ADJUSTMENT_MAX; 72 + dev_priv->brightness_adjusted = adjusted_level; 73 + 74 + if (mdfld_get_panel_type(dev, 0) == TC35876X) { 75 + if (dev_priv->dpi_panel_on[0] || 76 + dev_priv->dpi_panel_on[2]) 77 + tc35876x_brightness_control(dev, 78 + dev_priv->brightness_adjusted); 79 + } else { 80 + if (dev_priv->dpi_panel_on[0]) 81 + mdfld_dsi_brightness_control(dev, 0, 82 + dev_priv->brightness_adjusted); 83 + } 84 + 85 + if (dev_priv->dpi_panel_on[2]) 86 + mdfld_dsi_brightness_control(dev, 2, 87 + dev_priv->brightness_adjusted); 88 + gma_power_end(dev); 89 + } 90 + 91 + /* cache the brightness for later use */ 92 + dev_priv->brightness = level; 93 + return 0; 94 + } 95 + 96 + int mdfld_get_brightness(struct backlight_device *bd) 97 + { 98 + struct drm_device *dev = 99 + (struct drm_device *)bl_get_data(mdfld_backlight_device); 100 + struct drm_psb_private *dev_priv = dev->dev_private; 101 + 102 + DRM_DEBUG_DRIVER("brightness = 0x%x \n", dev_priv->brightness); 103 + 104 + /* return locally cached var instead of HW read (due to DPST etc.) */ 105 + return dev_priv->brightness; 106 + } 107 + 108 + static const struct backlight_ops mdfld_ops = { 109 + .get_brightness = mdfld_get_brightness, 110 + .update_status = mdfld_set_brightness, 111 + }; 112 + 113 + static int device_backlight_init(struct drm_device *dev) 114 + { 115 + struct drm_psb_private *dev_priv = (struct drm_psb_private *) 116 + dev->dev_private; 117 + 118 + dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX; 119 + dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX; 120 + 121 + return 0; 122 + } 123 + 124 + int mdfld_backlight_init(struct drm_device *dev) 125 + { 126 + struct backlight_properties props; 127 + int ret = 0; 128 + 129 + memset(&props, 0, sizeof(struct backlight_properties)); 130 + props.max_brightness = BRIGHTNESS_MAX_LEVEL; 131 + props.type = BACKLIGHT_PLATFORM; 132 + mdfld_backlight_device = backlight_device_register("mdfld-bl", 133 + NULL, (void *)dev, &mdfld_ops, &props); 134 + 135 + if (IS_ERR(mdfld_backlight_device)) 136 + return PTR_ERR(mdfld_backlight_device); 137 + 138 + ret = device_backlight_init(dev); 139 + if (ret) 140 + return ret; 141 + 142 + mdfld_backlight_device->props.brightness = BRIGHTNESS_MAX_LEVEL; 143 + mdfld_backlight_device->props.max_brightness = BRIGHTNESS_MAX_LEVEL; 144 + backlight_update_status(mdfld_backlight_device); 145 + return 0; 146 + } 147 + #endif 148 + 149 + struct backlight_device *mdfld_get_backlight_device(void) 150 + { 151 + #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE 152 + return mdfld_backlight_device; 153 + #else 154 + return NULL; 155 + #endif 156 + } 157 + 158 + /* 159 + * mdfld_save_display_registers 160 + * 161 + * Description: We are going to suspend so save current display 162 + * register state. 163 + * 164 + * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio 165 + */ 166 + static int mdfld_save_display_registers(struct drm_device *dev, int pipe) 167 + { 168 + struct drm_psb_private *dev_priv = dev->dev_private; 169 + struct medfield_state *regs = &dev_priv->regs.mdfld; 170 + int i; 171 + 172 + /* register */ 173 + u32 dpll_reg = MRST_DPLL_A; 174 + u32 fp_reg = MRST_FPA0; 175 + u32 pipeconf_reg = PIPEACONF; 176 + u32 htot_reg = HTOTAL_A; 177 + u32 hblank_reg = HBLANK_A; 178 + u32 hsync_reg = HSYNC_A; 179 + u32 vtot_reg = VTOTAL_A; 180 + u32 vblank_reg = VBLANK_A; 181 + u32 vsync_reg = VSYNC_A; 182 + u32 pipesrc_reg = PIPEASRC; 183 + u32 dspstride_reg = DSPASTRIDE; 184 + u32 dsplinoff_reg = DSPALINOFF; 185 + u32 dsptileoff_reg = DSPATILEOFF; 186 + u32 dspsize_reg = DSPASIZE; 187 + u32 dsppos_reg = DSPAPOS; 188 + u32 dspsurf_reg = DSPASURF; 189 + u32 mipi_reg = MIPI; 190 + u32 dspcntr_reg = DSPACNTR; 191 + u32 dspstatus_reg = PIPEASTAT; 192 + u32 palette_reg = PALETTE_A; 193 + 194 + /* pointer to values */ 195 + u32 *dpll_val = &regs->saveDPLL_A; 196 + u32 *fp_val = &regs->saveFPA0; 197 + u32 *pipeconf_val = &regs->savePIPEACONF; 198 + u32 *htot_val = &regs->saveHTOTAL_A; 199 + u32 *hblank_val = &regs->saveHBLANK_A; 200 + u32 *hsync_val = &regs->saveHSYNC_A; 201 + u32 *vtot_val = &regs->saveVTOTAL_A; 202 + u32 *vblank_val = &regs->saveVBLANK_A; 203 + u32 *vsync_val = &regs->saveVSYNC_A; 204 + u32 *pipesrc_val = &regs->savePIPEASRC; 205 + u32 *dspstride_val = &regs->saveDSPASTRIDE; 206 + u32 *dsplinoff_val = &regs->saveDSPALINOFF; 207 + u32 *dsptileoff_val = &regs->saveDSPATILEOFF; 208 + u32 *dspsize_val = &regs->saveDSPASIZE; 209 + u32 *dsppos_val = &regs->saveDSPAPOS; 210 + u32 *dspsurf_val = &regs->saveDSPASURF; 211 + u32 *mipi_val = &regs->saveMIPI; 212 + u32 *dspcntr_val = &regs->saveDSPACNTR; 213 + u32 *dspstatus_val = &regs->saveDSPASTATUS; 214 + u32 *palette_val = regs->save_palette_a; 215 + 216 + switch (pipe) { 217 + case 0: 218 + break; 219 + case 1: 220 + /* regester */ 221 + dpll_reg = MDFLD_DPLL_B; 222 + fp_reg = MDFLD_DPLL_DIV0; 223 + pipeconf_reg = PIPEBCONF; 224 + htot_reg = HTOTAL_B; 225 + hblank_reg = HBLANK_B; 226 + hsync_reg = HSYNC_B; 227 + vtot_reg = VTOTAL_B; 228 + vblank_reg = VBLANK_B; 229 + vsync_reg = VSYNC_B; 230 + pipesrc_reg = PIPEBSRC; 231 + dspstride_reg = DSPBSTRIDE; 232 + dsplinoff_reg = DSPBLINOFF; 233 + dsptileoff_reg = DSPBTILEOFF; 234 + dspsize_reg = DSPBSIZE; 235 + dsppos_reg = DSPBPOS; 236 + dspsurf_reg = DSPBSURF; 237 + dspcntr_reg = DSPBCNTR; 238 + dspstatus_reg = PIPEBSTAT; 239 + palette_reg = PALETTE_B; 240 + 241 + /* values */ 242 + dpll_val = &regs->saveDPLL_B; 243 + fp_val = &regs->saveFPB0; 244 + pipeconf_val = &regs->savePIPEBCONF; 245 + htot_val = &regs->saveHTOTAL_B; 246 + hblank_val = &regs->saveHBLANK_B; 247 + hsync_val = &regs->saveHSYNC_B; 248 + vtot_val = &regs->saveVTOTAL_B; 249 + vblank_val = &regs->saveVBLANK_B; 250 + vsync_val = &regs->saveVSYNC_B; 251 + pipesrc_val = &regs->savePIPEBSRC; 252 + dspstride_val = &regs->saveDSPBSTRIDE; 253 + dsplinoff_val = &regs->saveDSPBLINOFF; 254 + dsptileoff_val = &regs->saveDSPBTILEOFF; 255 + dspsize_val = &regs->saveDSPBSIZE; 256 + dsppos_val = &regs->saveDSPBPOS; 257 + dspsurf_val = &regs->saveDSPBSURF; 258 + dspcntr_val = &regs->saveDSPBCNTR; 259 + dspstatus_val = &regs->saveDSPBSTATUS; 260 + palette_val = regs->save_palette_b; 261 + break; 262 + case 2: 263 + /* register */ 264 + pipeconf_reg = PIPECCONF; 265 + htot_reg = HTOTAL_C; 266 + hblank_reg = HBLANK_C; 267 + hsync_reg = HSYNC_C; 268 + vtot_reg = VTOTAL_C; 269 + vblank_reg = VBLANK_C; 270 + vsync_reg = VSYNC_C; 271 + pipesrc_reg = PIPECSRC; 272 + dspstride_reg = DSPCSTRIDE; 273 + dsplinoff_reg = DSPCLINOFF; 274 + dsptileoff_reg = DSPCTILEOFF; 275 + dspsize_reg = DSPCSIZE; 276 + dsppos_reg = DSPCPOS; 277 + dspsurf_reg = DSPCSURF; 278 + mipi_reg = MIPI_C; 279 + dspcntr_reg = DSPCCNTR; 280 + dspstatus_reg = PIPECSTAT; 281 + palette_reg = PALETTE_C; 282 + 283 + /* pointer to values */ 284 + pipeconf_val = &regs->savePIPECCONF; 285 + htot_val = &regs->saveHTOTAL_C; 286 + hblank_val = &regs->saveHBLANK_C; 287 + hsync_val = &regs->saveHSYNC_C; 288 + vtot_val = &regs->saveVTOTAL_C; 289 + vblank_val = &regs->saveVBLANK_C; 290 + vsync_val = &regs->saveVSYNC_C; 291 + pipesrc_val = &regs->savePIPECSRC; 292 + dspstride_val = &regs->saveDSPCSTRIDE; 293 + dsplinoff_val = &regs->saveDSPCLINOFF; 294 + dsptileoff_val = &regs->saveDSPCTILEOFF; 295 + dspsize_val = &regs->saveDSPCSIZE; 296 + dsppos_val = &regs->saveDSPCPOS; 297 + dspsurf_val = &regs->saveDSPCSURF; 298 + mipi_val = &regs->saveMIPI_C; 299 + dspcntr_val = &regs->saveDSPCCNTR; 300 + dspstatus_val = &regs->saveDSPCSTATUS; 301 + palette_val = regs->save_palette_c; 302 + break; 303 + default: 304 + DRM_ERROR("%s, invalid pipe number.\n", __func__); 305 + return -EINVAL; 306 + } 307 + 308 + /* Pipe & plane A info */ 309 + *dpll_val = PSB_RVDC32(dpll_reg); 310 + *fp_val = PSB_RVDC32(fp_reg); 311 + *pipeconf_val = PSB_RVDC32(pipeconf_reg); 312 + *htot_val = PSB_RVDC32(htot_reg); 313 + *hblank_val = PSB_RVDC32(hblank_reg); 314 + *hsync_val = PSB_RVDC32(hsync_reg); 315 + *vtot_val = PSB_RVDC32(vtot_reg); 316 + *vblank_val = PSB_RVDC32(vblank_reg); 317 + *vsync_val = PSB_RVDC32(vsync_reg); 318 + *pipesrc_val = PSB_RVDC32(pipesrc_reg); 319 + *dspstride_val = PSB_RVDC32(dspstride_reg); 320 + *dsplinoff_val = PSB_RVDC32(dsplinoff_reg); 321 + *dsptileoff_val = PSB_RVDC32(dsptileoff_reg); 322 + *dspsize_val = PSB_RVDC32(dspsize_reg); 323 + *dsppos_val = PSB_RVDC32(dsppos_reg); 324 + *dspsurf_val = PSB_RVDC32(dspsurf_reg); 325 + *dspcntr_val = PSB_RVDC32(dspcntr_reg); 326 + *dspstatus_val = PSB_RVDC32(dspstatus_reg); 327 + 328 + /*save palette (gamma) */ 329 + for (i = 0; i < 256; i++) 330 + palette_val[i] = PSB_RVDC32(palette_reg + (i << 2)); 331 + 332 + if (pipe == 1) { 333 + regs->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL); 334 + regs->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS); 335 + 336 + regs->saveHDMIPHYMISCCTL = PSB_RVDC32(HDMIPHYMISCCTL); 337 + regs->saveHDMIB_CONTROL = PSB_RVDC32(HDMIB_CONTROL); 338 + return 0; 339 + } 340 + 341 + *mipi_val = PSB_RVDC32(mipi_reg); 342 + return 0; 343 + } 344 + 345 + /* 346 + * mdfld_restore_display_registers 347 + * 348 + * Description: We are going to resume so restore display register state. 349 + * 350 + * Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio 351 + */ 352 + static int mdfld_restore_display_registers(struct drm_device *dev, int pipe) 353 + { 354 + /* To get panel out of ULPS mode. */ 355 + u32 temp = 0; 356 + u32 device_ready_reg = DEVICE_READY_REG; 357 + struct drm_psb_private *dev_priv = dev->dev_private; 358 + struct mdfld_dsi_config *dsi_config = NULL; 359 + struct medfield_state *regs = &dev_priv->regs.mdfld; 360 + u32 i = 0; 361 + u32 dpll = 0; 362 + u32 timeout = 0; 363 + 364 + /* regester */ 365 + u32 dpll_reg = MRST_DPLL_A; 366 + u32 fp_reg = MRST_FPA0; 367 + u32 pipeconf_reg = PIPEACONF; 368 + u32 htot_reg = HTOTAL_A; 369 + u32 hblank_reg = HBLANK_A; 370 + u32 hsync_reg = HSYNC_A; 371 + u32 vtot_reg = VTOTAL_A; 372 + u32 vblank_reg = VBLANK_A; 373 + u32 vsync_reg = VSYNC_A; 374 + u32 pipesrc_reg = PIPEASRC; 375 + u32 dspstride_reg = DSPASTRIDE; 376 + u32 dsplinoff_reg = DSPALINOFF; 377 + u32 dsptileoff_reg = DSPATILEOFF; 378 + u32 dspsize_reg = DSPASIZE; 379 + u32 dsppos_reg = DSPAPOS; 380 + u32 dspsurf_reg = DSPASURF; 381 + u32 dspstatus_reg = PIPEASTAT; 382 + u32 mipi_reg = MIPI; 383 + u32 dspcntr_reg = DSPACNTR; 384 + u32 palette_reg = PALETTE_A; 385 + 386 + /* values */ 387 + u32 dpll_val = regs->saveDPLL_A & ~DPLL_VCO_ENABLE; 388 + u32 fp_val = regs->saveFPA0; 389 + u32 pipeconf_val = regs->savePIPEACONF; 390 + u32 htot_val = regs->saveHTOTAL_A; 391 + u32 hblank_val = regs->saveHBLANK_A; 392 + u32 hsync_val = regs->saveHSYNC_A; 393 + u32 vtot_val = regs->saveVTOTAL_A; 394 + u32 vblank_val = regs->saveVBLANK_A; 395 + u32 vsync_val = regs->saveVSYNC_A; 396 + u32 pipesrc_val = regs->savePIPEASRC; 397 + u32 dspstride_val = regs->saveDSPASTRIDE; 398 + u32 dsplinoff_val = regs->saveDSPALINOFF; 399 + u32 dsptileoff_val = regs->saveDSPATILEOFF; 400 + u32 dspsize_val = regs->saveDSPASIZE; 401 + u32 dsppos_val = regs->saveDSPAPOS; 402 + u32 dspsurf_val = regs->saveDSPASURF; 403 + u32 dspstatus_val = regs->saveDSPASTATUS; 404 + u32 mipi_val = regs->saveMIPI; 405 + u32 dspcntr_val = regs->saveDSPACNTR; 406 + u32 *palette_val = regs->save_palette_a; 407 + 408 + switch (pipe) { 409 + case 0: 410 + dsi_config = dev_priv->dsi_configs[0]; 411 + break; 412 + case 1: 413 + /* regester */ 414 + dpll_reg = MDFLD_DPLL_B; 415 + fp_reg = MDFLD_DPLL_DIV0; 416 + pipeconf_reg = PIPEBCONF; 417 + htot_reg = HTOTAL_B; 418 + hblank_reg = HBLANK_B; 419 + hsync_reg = HSYNC_B; 420 + vtot_reg = VTOTAL_B; 421 + vblank_reg = VBLANK_B; 422 + vsync_reg = VSYNC_B; 423 + pipesrc_reg = PIPEBSRC; 424 + dspstride_reg = DSPBSTRIDE; 425 + dsplinoff_reg = DSPBLINOFF; 426 + dsptileoff_reg = DSPBTILEOFF; 427 + dspsize_reg = DSPBSIZE; 428 + dsppos_reg = DSPBPOS; 429 + dspsurf_reg = DSPBSURF; 430 + dspcntr_reg = DSPBCNTR; 431 + dspstatus_reg = PIPEBSTAT; 432 + palette_reg = PALETTE_B; 433 + 434 + /* values */ 435 + dpll_val = regs->saveDPLL_B & ~DPLL_VCO_ENABLE; 436 + fp_val = regs->saveFPB0; 437 + pipeconf_val = regs->savePIPEBCONF; 438 + htot_val = regs->saveHTOTAL_B; 439 + hblank_val = regs->saveHBLANK_B; 440 + hsync_val = regs->saveHSYNC_B; 441 + vtot_val = regs->saveVTOTAL_B; 442 + vblank_val = regs->saveVBLANK_B; 443 + vsync_val = regs->saveVSYNC_B; 444 + pipesrc_val = regs->savePIPEBSRC; 445 + dspstride_val = regs->saveDSPBSTRIDE; 446 + dsplinoff_val = regs->saveDSPBLINOFF; 447 + dsptileoff_val = regs->saveDSPBTILEOFF; 448 + dspsize_val = regs->saveDSPBSIZE; 449 + dsppos_val = regs->saveDSPBPOS; 450 + dspsurf_val = regs->saveDSPBSURF; 451 + dspcntr_val = regs->saveDSPBCNTR; 452 + dspstatus_val = regs->saveDSPBSTATUS; 453 + palette_val = regs->save_palette_b; 454 + break; 455 + case 2: 456 + /* regester */ 457 + pipeconf_reg = PIPECCONF; 458 + htot_reg = HTOTAL_C; 459 + hblank_reg = HBLANK_C; 460 + hsync_reg = HSYNC_C; 461 + vtot_reg = VTOTAL_C; 462 + vblank_reg = VBLANK_C; 463 + vsync_reg = VSYNC_C; 464 + pipesrc_reg = PIPECSRC; 465 + dspstride_reg = DSPCSTRIDE; 466 + dsplinoff_reg = DSPCLINOFF; 467 + dsptileoff_reg = DSPCTILEOFF; 468 + dspsize_reg = DSPCSIZE; 469 + dsppos_reg = DSPCPOS; 470 + dspsurf_reg = DSPCSURF; 471 + mipi_reg = MIPI_C; 472 + dspcntr_reg = DSPCCNTR; 473 + dspstatus_reg = PIPECSTAT; 474 + palette_reg = PALETTE_C; 475 + 476 + /* values */ 477 + pipeconf_val = regs->savePIPECCONF; 478 + htot_val = regs->saveHTOTAL_C; 479 + hblank_val = regs->saveHBLANK_C; 480 + hsync_val = regs->saveHSYNC_C; 481 + vtot_val = regs->saveVTOTAL_C; 482 + vblank_val = regs->saveVBLANK_C; 483 + vsync_val = regs->saveVSYNC_C; 484 + pipesrc_val = regs->savePIPECSRC; 485 + dspstride_val = regs->saveDSPCSTRIDE; 486 + dsplinoff_val = regs->saveDSPCLINOFF; 487 + dsptileoff_val = regs->saveDSPCTILEOFF; 488 + dspsize_val = regs->saveDSPCSIZE; 489 + dsppos_val = regs->saveDSPCPOS; 490 + dspsurf_val = regs->saveDSPCSURF; 491 + mipi_val = regs->saveMIPI_C; 492 + dspcntr_val = regs->saveDSPCCNTR; 493 + dspstatus_val = regs->saveDSPCSTATUS; 494 + palette_val = regs->save_palette_c; 495 + 496 + dsi_config = dev_priv->dsi_configs[1]; 497 + break; 498 + default: 499 + DRM_ERROR("%s, invalid pipe number.\n", __func__); 500 + return -EINVAL; 501 + } 502 + 503 + /*make sure VGA plane is off. it initializes to on after reset!*/ 504 + PSB_WVDC32(0x80000000, VGACNTRL); 505 + 506 + if (pipe == 1) { 507 + PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, dpll_reg); 508 + PSB_RVDC32(dpll_reg); 509 + 510 + PSB_WVDC32(fp_val, fp_reg); 511 + } else { 512 + 513 + dpll = PSB_RVDC32(dpll_reg); 514 + 515 + if (!(dpll & DPLL_VCO_ENABLE)) { 516 + 517 + /* When ungating power of DPLL, needs to wait 0.5us 518 + before enable the VCO */ 519 + if (dpll & MDFLD_PWR_GATE_EN) { 520 + dpll &= ~MDFLD_PWR_GATE_EN; 521 + PSB_WVDC32(dpll, dpll_reg); 522 + /* FIXME_MDFLD PO - change 500 to 1 after PO */ 523 + udelay(500); 524 + } 525 + 526 + PSB_WVDC32(fp_val, fp_reg); 527 + PSB_WVDC32(dpll_val, dpll_reg); 528 + /* FIXME_MDFLD PO - change 500 to 1 after PO */ 529 + udelay(500); 530 + 531 + dpll_val |= DPLL_VCO_ENABLE; 532 + PSB_WVDC32(dpll_val, dpll_reg); 533 + PSB_RVDC32(dpll_reg); 534 + 535 + /* wait for DSI PLL to lock */ 536 + while (timeout < 20000 && 537 + !(PSB_RVDC32(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) { 538 + udelay(150); 539 + timeout++; 540 + } 541 + 542 + if (timeout == 20000) { 543 + DRM_ERROR("%s, can't lock DSIPLL.\n", 544 + __func__); 545 + return -EINVAL; 546 + } 547 + } 548 + } 549 + /* Restore mode */ 550 + PSB_WVDC32(htot_val, htot_reg); 551 + PSB_WVDC32(hblank_val, hblank_reg); 552 + PSB_WVDC32(hsync_val, hsync_reg); 553 + PSB_WVDC32(vtot_val, vtot_reg); 554 + PSB_WVDC32(vblank_val, vblank_reg); 555 + PSB_WVDC32(vsync_val, vsync_reg); 556 + PSB_WVDC32(pipesrc_val, pipesrc_reg); 557 + PSB_WVDC32(dspstatus_val, dspstatus_reg); 558 + 559 + /*set up the plane*/ 560 + PSB_WVDC32(dspstride_val, dspstride_reg); 561 + PSB_WVDC32(dsplinoff_val, dsplinoff_reg); 562 + PSB_WVDC32(dsptileoff_val, dsptileoff_reg); 563 + PSB_WVDC32(dspsize_val, dspsize_reg); 564 + PSB_WVDC32(dsppos_val, dsppos_reg); 565 + PSB_WVDC32(dspsurf_val, dspsurf_reg); 566 + 567 + if (pipe == 1) { 568 + /* restore palette (gamma) */ 569 + /*DRM_UDELAY(50000); */ 570 + for (i = 0; i < 256; i++) 571 + PSB_WVDC32(palette_val[i], palette_reg + (i << 2)); 572 + 573 + PSB_WVDC32(regs->savePFIT_CONTROL, PFIT_CONTROL); 574 + PSB_WVDC32(regs->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS); 575 + 576 + /*TODO: resume HDMI port */ 577 + 578 + /*TODO: resume pipe*/ 579 + 580 + /*enable the plane*/ 581 + PSB_WVDC32(dspcntr_val & ~DISPLAY_PLANE_ENABLE, dspcntr_reg); 582 + 583 + return 0; 584 + } 585 + 586 + /*set up pipe related registers*/ 587 + PSB_WVDC32(mipi_val, mipi_reg); 588 + 589 + /*setup MIPI adapter + MIPI IP registers*/ 590 + if (dsi_config) 591 + mdfld_dsi_controller_init(dsi_config, pipe); 592 + 593 + if (in_atomic() || in_interrupt()) 594 + mdelay(20); 595 + else 596 + msleep(20); 597 + 598 + /*enable the plane*/ 599 + PSB_WVDC32(dspcntr_val, dspcntr_reg); 600 + 601 + if (in_atomic() || in_interrupt()) 602 + mdelay(20); 603 + else 604 + msleep(20); 605 + 606 + /* LP Hold Release */ 607 + temp = REG_READ(mipi_reg); 608 + temp |= LP_OUTPUT_HOLD_RELEASE; 609 + REG_WRITE(mipi_reg, temp); 610 + mdelay(1); 611 + 612 + 613 + /* Set DSI host to exit from Utra Low Power State */ 614 + temp = REG_READ(device_ready_reg); 615 + temp &= ~ULPS_MASK; 616 + temp |= 0x3; 617 + temp |= EXIT_ULPS_DEV_READY; 618 + REG_WRITE(device_ready_reg, temp); 619 + mdelay(1); 620 + 621 + temp = REG_READ(device_ready_reg); 622 + temp &= ~ULPS_MASK; 623 + temp |= EXITING_ULPS; 624 + REG_WRITE(device_ready_reg, temp); 625 + mdelay(1); 626 + 627 + /*enable the pipe*/ 628 + PSB_WVDC32(pipeconf_val, pipeconf_reg); 629 + 630 + /* restore palette (gamma) */ 631 + /*DRM_UDELAY(50000); */ 632 + for (i = 0; i < 256; i++) 633 + PSB_WVDC32(palette_val[i], palette_reg + (i << 2)); 634 + 635 + return 0; 636 + } 637 + 638 + static int mdfld_save_registers(struct drm_device *dev) 639 + { 640 + /* mdfld_save_cursor_overlay_registers(dev); */ 641 + mdfld_save_display_registers(dev, 0); 642 + mdfld_save_display_registers(dev, 2); 643 + mdfld_disable_crtc(dev, 0); 644 + mdfld_disable_crtc(dev, 2); 645 + 646 + return 0; 647 + } 648 + 649 + static int mdfld_restore_registers(struct drm_device *dev) 650 + { 651 + mdfld_restore_display_registers(dev, 2); 652 + mdfld_restore_display_registers(dev, 0); 653 + /* mdfld_restore_cursor_overlay_registers(dev); */ 654 + 655 + return 0; 656 + } 657 + 658 + static int mdfld_power_down(struct drm_device *dev) 659 + { 660 + /* FIXME */ 661 + return 0; 662 + } 663 + 664 + static int mdfld_power_up(struct drm_device *dev) 665 + { 666 + /* FIXME */ 667 + return 0; 668 + } 669 + 670 + const struct psb_ops mdfld_chip_ops = { 671 + .name = "mdfld", 672 + .accel_2d = 0, 673 + .pipes = 3, 674 + .crtcs = 3, 675 + .sgx_offset = MRST_SGX_OFFSET, 676 + 677 + .chip_setup = mid_chip_setup, 678 + .crtc_helper = &mdfld_helper_funcs, 679 + .crtc_funcs = &psb_intel_crtc_funcs, 680 + 681 + .output_init = mdfld_output_init, 682 + 683 + #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE 684 + .backlight_init = mdfld_backlight_init, 685 + #endif 686 + 687 + .save_regs = mdfld_save_registers, 688 + .restore_regs = mdfld_restore_registers, 689 + .power_down = mdfld_power_down, 690 + .power_up = mdfld_power_up, 691 + };
+1024
drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
··· 1 + /* 2 + * Copyright © 2010 Intel Corporation 3 + * 4 + * Permission is hereby granted, free of charge, to any person obtaining a 5 + * copy of this software and associated documentation files (the "Software"), 6 + * to deal in the Software without restriction, including without limitation 7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 + * and/or sell copies of the Software, and to permit persons to whom the 9 + * Software is furnished to do so, subject to the following conditions: 10 + * 11 + * The above copyright notice and this permission notice (including the next 12 + * paragraph) shall be included in all copies or substantial portions of the 13 + * Software. 14 + * 15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 + * DEALINGS IN THE SOFTWARE. 22 + * 23 + * Authors: 24 + * jim liu <jim.liu@intel.com> 25 + * Jackie Li<yaodong.li@intel.com> 26 + */ 27 + 28 + #include "mdfld_dsi_dpi.h" 29 + #include "mdfld_output.h" 30 + #include "mdfld_dsi_pkg_sender.h" 31 + #include "psb_drv.h" 32 + #include "tc35876x-dsi-lvds.h" 33 + 34 + static void mdfld_dsi_dpi_shut_down(struct mdfld_dsi_dpi_output *output, 35 + int pipe); 36 + 37 + static void mdfld_wait_for_HS_DATA_FIFO(struct drm_device *dev, u32 pipe) 38 + { 39 + u32 gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe); 40 + int timeout = 0; 41 + 42 + udelay(500); 43 + 44 + /* This will time out after approximately 2+ seconds */ 45 + while ((timeout < 20000) && 46 + (REG_READ(gen_fifo_stat_reg) & DSI_FIFO_GEN_HS_DATA_FULL)) { 47 + udelay(100); 48 + timeout++; 49 + } 50 + 51 + if (timeout == 20000) 52 + DRM_INFO("MIPI: HS Data FIFO was never cleared!\n"); 53 + } 54 + 55 + static void mdfld_wait_for_HS_CTRL_FIFO(struct drm_device *dev, u32 pipe) 56 + { 57 + u32 gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe); 58 + int timeout = 0; 59 + 60 + udelay(500); 61 + 62 + /* This will time out after approximately 2+ seconds */ 63 + while ((timeout < 20000) && (REG_READ(gen_fifo_stat_reg) 64 + & DSI_FIFO_GEN_HS_CTRL_FULL)) { 65 + udelay(100); 66 + timeout++; 67 + } 68 + if (timeout == 20000) 69 + DRM_INFO("MIPI: HS CMD FIFO was never cleared!\n"); 70 + } 71 + 72 + static void mdfld_wait_for_DPI_CTRL_FIFO(struct drm_device *dev, u32 pipe) 73 + { 74 + u32 gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe); 75 + int timeout = 0; 76 + 77 + udelay(500); 78 + 79 + /* This will time out after approximately 2+ seconds */ 80 + while ((timeout < 20000) && ((REG_READ(gen_fifo_stat_reg) & 81 + DPI_FIFO_EMPTY) != DPI_FIFO_EMPTY)) { 82 + udelay(100); 83 + timeout++; 84 + } 85 + 86 + if (timeout == 20000) 87 + DRM_ERROR("MIPI: DPI FIFO was never cleared\n"); 88 + } 89 + 90 + static void mdfld_wait_for_SPL_PKG_SENT(struct drm_device *dev, u32 pipe) 91 + { 92 + u32 intr_stat_reg = MIPI_INTR_STAT_REG(pipe); 93 + int timeout = 0; 94 + 95 + udelay(500); 96 + 97 + /* This will time out after approximately 2+ seconds */ 98 + while ((timeout < 20000) && (!(REG_READ(intr_stat_reg) 99 + & DSI_INTR_STATE_SPL_PKG_SENT))) { 100 + udelay(100); 101 + timeout++; 102 + } 103 + 104 + if (timeout == 20000) 105 + DRM_ERROR("MIPI: SPL_PKT_SENT_INTERRUPT was not sent successfully!\n"); 106 + } 107 + 108 + /* For TC35876X */ 109 + 110 + static void dsi_set_device_ready_state(struct drm_device *dev, int state, 111 + int pipe) 112 + { 113 + REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), !!state, 0, 0); 114 + } 115 + 116 + static void dsi_set_pipe_plane_enable_state(struct drm_device *dev, 117 + int state, int pipe) 118 + { 119 + struct drm_psb_private *dev_priv = dev->dev_private; 120 + u32 pipeconf_reg = PIPEACONF; 121 + u32 dspcntr_reg = DSPACNTR; 122 + 123 + u32 dspcntr = dev_priv->dspcntr[pipe]; 124 + u32 mipi = MIPI_PORT_EN | PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX; 125 + 126 + if (pipe) { 127 + pipeconf_reg = PIPECCONF; 128 + dspcntr_reg = DSPCCNTR; 129 + } else 130 + mipi &= (~0x03); 131 + 132 + if (state) { 133 + /*Set up pipe */ 134 + REG_WRITE(pipeconf_reg, BIT(31)); 135 + 136 + if (REG_BIT_WAIT(pipeconf_reg, 1, 30)) 137 + dev_err(&dev->pdev->dev, "%s: Pipe enable timeout\n", 138 + __func__); 139 + 140 + /*Set up display plane */ 141 + REG_WRITE(dspcntr_reg, dspcntr); 142 + } else { 143 + u32 dspbase_reg = pipe ? MDFLD_DSPCBASE : MRST_DSPABASE; 144 + 145 + /* Put DSI lanes to ULPS to disable pipe */ 146 + REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), 2, 2, 1); 147 + REG_READ(MIPI_DEVICE_READY_REG(pipe)); /* posted write? */ 148 + 149 + /* LP Hold */ 150 + REG_FLD_MOD(MIPI_PORT_CONTROL(pipe), 0, 16, 16); 151 + REG_READ(MIPI_PORT_CONTROL(pipe)); /* posted write? */ 152 + 153 + /* Disable display plane */ 154 + REG_FLD_MOD(dspcntr_reg, 0, 31, 31); 155 + 156 + /* Flush the plane changes ??? posted write? */ 157 + REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); 158 + REG_READ(dspbase_reg); 159 + 160 + /* Disable PIPE */ 161 + REG_FLD_MOD(pipeconf_reg, 0, 31, 31); 162 + 163 + if (REG_BIT_WAIT(pipeconf_reg, 0, 30)) 164 + dev_err(&dev->pdev->dev, "%s: Pipe disable timeout\n", 165 + __func__); 166 + 167 + if (REG_BIT_WAIT(MIPI_GEN_FIFO_STAT_REG(pipe), 1, 28)) 168 + dev_err(&dev->pdev->dev, "%s: FIFO not empty\n", 169 + __func__); 170 + } 171 + } 172 + 173 + static void mdfld_dsi_configure_down(struct mdfld_dsi_encoder *dsi_encoder, 174 + int pipe) 175 + { 176 + struct mdfld_dsi_dpi_output *dpi_output = 177 + MDFLD_DSI_DPI_OUTPUT(dsi_encoder); 178 + struct mdfld_dsi_config *dsi_config = 179 + mdfld_dsi_encoder_get_config(dsi_encoder); 180 + struct drm_device *dev = dsi_config->dev; 181 + struct drm_psb_private *dev_priv = dev->dev_private; 182 + 183 + if (!dev_priv->dpi_panel_on[pipe]) { 184 + dev_err(dev->dev, "DPI panel is already off\n"); 185 + return; 186 + } 187 + tc35876x_toshiba_bridge_panel_off(dev); 188 + tc35876x_set_bridge_reset_state(dev, 1); 189 + dsi_set_pipe_plane_enable_state(dev, 0, pipe); 190 + mdfld_dsi_dpi_shut_down(dpi_output, pipe); 191 + dsi_set_device_ready_state(dev, 0, pipe); 192 + } 193 + 194 + static void mdfld_dsi_configure_up(struct mdfld_dsi_encoder *dsi_encoder, 195 + int pipe) 196 + { 197 + struct mdfld_dsi_dpi_output *dpi_output = 198 + MDFLD_DSI_DPI_OUTPUT(dsi_encoder); 199 + struct mdfld_dsi_config *dsi_config = 200 + mdfld_dsi_encoder_get_config(dsi_encoder); 201 + struct drm_device *dev = dsi_config->dev; 202 + struct drm_psb_private *dev_priv = dev->dev_private; 203 + 204 + if (dev_priv->dpi_panel_on[pipe]) { 205 + dev_err(dev->dev, "DPI panel is already on\n"); 206 + return; 207 + } 208 + 209 + /* For resume path sequence */ 210 + mdfld_dsi_dpi_shut_down(dpi_output, pipe); 211 + dsi_set_device_ready_state(dev, 0, pipe); 212 + 213 + dsi_set_device_ready_state(dev, 1, pipe); 214 + tc35876x_set_bridge_reset_state(dev, 0); 215 + tc35876x_configure_lvds_bridge(dev); 216 + mdfld_dsi_dpi_turn_on(dpi_output, pipe); /* Send turn on command */ 217 + dsi_set_pipe_plane_enable_state(dev, 1, pipe); 218 + } 219 + /* End for TC35876X */ 220 + 221 + /* ************************************************************************* *\ 222 + * FUNCTION: mdfld_dsi_tpo_ic_init 223 + * 224 + * DESCRIPTION: This function is called only by mrst_dsi_mode_set and 225 + * restore_display_registers. since this function does not 226 + * acquire the mutex, it is important that the calling function 227 + * does! 228 + \* ************************************************************************* */ 229 + static void mdfld_dsi_tpo_ic_init(struct mdfld_dsi_config *dsi_config, u32 pipe) 230 + { 231 + struct drm_device *dev = dsi_config->dev; 232 + u32 dcsChannelNumber = dsi_config->channel_num; 233 + u32 gen_data_reg = MIPI_HS_GEN_DATA_REG(pipe); 234 + u32 gen_ctrl_reg = MIPI_HS_GEN_CTRL_REG(pipe); 235 + u32 gen_ctrl_val = GEN_LONG_WRITE; 236 + 237 + DRM_INFO("Enter mrst init TPO MIPI display.\n"); 238 + 239 + gen_ctrl_val |= dcsChannelNumber << DCS_CHANNEL_NUMBER_POS; 240 + 241 + /* Flip page order */ 242 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 243 + REG_WRITE(gen_data_reg, 0x00008036); 244 + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); 245 + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x02 << WORD_COUNTS_POS)); 246 + 247 + /* 0xF0 */ 248 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 249 + REG_WRITE(gen_data_reg, 0x005a5af0); 250 + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); 251 + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS)); 252 + 253 + /* Write protection key */ 254 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 255 + REG_WRITE(gen_data_reg, 0x005a5af1); 256 + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); 257 + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS)); 258 + 259 + /* 0xFC */ 260 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 261 + REG_WRITE(gen_data_reg, 0x005a5afc); 262 + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); 263 + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS)); 264 + 265 + /* 0xB7 */ 266 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 267 + REG_WRITE(gen_data_reg, 0x770000b7); 268 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 269 + REG_WRITE(gen_data_reg, 0x00000044); 270 + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); 271 + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x05 << WORD_COUNTS_POS)); 272 + 273 + /* 0xB6 */ 274 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 275 + REG_WRITE(gen_data_reg, 0x000a0ab6); 276 + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); 277 + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS)); 278 + 279 + /* 0xF2 */ 280 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 281 + REG_WRITE(gen_data_reg, 0x081010f2); 282 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 283 + REG_WRITE(gen_data_reg, 0x4a070708); 284 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 285 + REG_WRITE(gen_data_reg, 0x000000c5); 286 + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); 287 + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x09 << WORD_COUNTS_POS)); 288 + 289 + /* 0xF8 */ 290 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 291 + REG_WRITE(gen_data_reg, 0x024003f8); 292 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 293 + REG_WRITE(gen_data_reg, 0x01030a04); 294 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 295 + REG_WRITE(gen_data_reg, 0x0e020220); 296 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 297 + REG_WRITE(gen_data_reg, 0x00000004); 298 + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); 299 + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x0d << WORD_COUNTS_POS)); 300 + 301 + /* 0xE2 */ 302 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 303 + REG_WRITE(gen_data_reg, 0x398fc3e2); 304 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 305 + REG_WRITE(gen_data_reg, 0x0000916f); 306 + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); 307 + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x06 << WORD_COUNTS_POS)); 308 + 309 + /* 0xB0 */ 310 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 311 + REG_WRITE(gen_data_reg, 0x000000b0); 312 + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); 313 + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x02 << WORD_COUNTS_POS)); 314 + 315 + /* 0xF4 */ 316 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 317 + REG_WRITE(gen_data_reg, 0x240242f4); 318 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 319 + REG_WRITE(gen_data_reg, 0x78ee2002); 320 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 321 + REG_WRITE(gen_data_reg, 0x2a071050); 322 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 323 + REG_WRITE(gen_data_reg, 0x507fee10); 324 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 325 + REG_WRITE(gen_data_reg, 0x10300710); 326 + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); 327 + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x14 << WORD_COUNTS_POS)); 328 + 329 + /* 0xBA */ 330 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 331 + REG_WRITE(gen_data_reg, 0x19fe07ba); 332 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 333 + REG_WRITE(gen_data_reg, 0x101c0a31); 334 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 335 + REG_WRITE(gen_data_reg, 0x00000010); 336 + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); 337 + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x09 << WORD_COUNTS_POS)); 338 + 339 + /* 0xBB */ 340 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 341 + REG_WRITE(gen_data_reg, 0x28ff07bb); 342 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 343 + REG_WRITE(gen_data_reg, 0x24280a31); 344 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 345 + REG_WRITE(gen_data_reg, 0x00000034); 346 + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); 347 + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x09 << WORD_COUNTS_POS)); 348 + 349 + /* 0xFB */ 350 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 351 + REG_WRITE(gen_data_reg, 0x535d05fb); 352 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 353 + REG_WRITE(gen_data_reg, 0x1b1a2130); 354 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 355 + REG_WRITE(gen_data_reg, 0x221e180e); 356 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 357 + REG_WRITE(gen_data_reg, 0x131d2120); 358 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 359 + REG_WRITE(gen_data_reg, 0x535d0508); 360 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 361 + REG_WRITE(gen_data_reg, 0x1c1a2131); 362 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 363 + REG_WRITE(gen_data_reg, 0x231f160d); 364 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 365 + REG_WRITE(gen_data_reg, 0x111b2220); 366 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 367 + REG_WRITE(gen_data_reg, 0x535c2008); 368 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 369 + REG_WRITE(gen_data_reg, 0x1f1d2433); 370 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 371 + REG_WRITE(gen_data_reg, 0x2c251a10); 372 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 373 + REG_WRITE(gen_data_reg, 0x2c34372d); 374 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 375 + REG_WRITE(gen_data_reg, 0x00000023); 376 + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); 377 + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x31 << WORD_COUNTS_POS)); 378 + 379 + /* 0xFA */ 380 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 381 + REG_WRITE(gen_data_reg, 0x525c0bfa); 382 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 383 + REG_WRITE(gen_data_reg, 0x1c1c232f); 384 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 385 + REG_WRITE(gen_data_reg, 0x2623190e); 386 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 387 + REG_WRITE(gen_data_reg, 0x18212625); 388 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 389 + REG_WRITE(gen_data_reg, 0x545d0d0e); 390 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 391 + REG_WRITE(gen_data_reg, 0x1e1d2333); 392 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 393 + REG_WRITE(gen_data_reg, 0x26231a10); 394 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 395 + REG_WRITE(gen_data_reg, 0x1a222725); 396 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 397 + REG_WRITE(gen_data_reg, 0x545d280f); 398 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 399 + REG_WRITE(gen_data_reg, 0x21202635); 400 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 401 + REG_WRITE(gen_data_reg, 0x31292013); 402 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 403 + REG_WRITE(gen_data_reg, 0x31393d33); 404 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 405 + REG_WRITE(gen_data_reg, 0x00000029); 406 + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); 407 + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x31 << WORD_COUNTS_POS)); 408 + 409 + /* Set DM */ 410 + mdfld_wait_for_HS_DATA_FIFO(dev, pipe); 411 + REG_WRITE(gen_data_reg, 0x000100f7); 412 + mdfld_wait_for_HS_CTRL_FIFO(dev, pipe); 413 + REG_WRITE(gen_ctrl_reg, gen_ctrl_val | (0x03 << WORD_COUNTS_POS)); 414 + } 415 + 416 + static u16 mdfld_dsi_dpi_to_byte_clock_count(int pixel_clock_count, 417 + int num_lane, int bpp) 418 + { 419 + return (u16)((pixel_clock_count * bpp) / (num_lane * 8)); 420 + } 421 + 422 + /* 423 + * Calculate the dpi time basing on a given drm mode @mode 424 + * return 0 on success. 425 + * FIXME: I was using proposed mode value for calculation, may need to 426 + * use crtc mode values later 427 + */ 428 + int mdfld_dsi_dpi_timing_calculation(struct drm_display_mode *mode, 429 + struct mdfld_dsi_dpi_timing *dpi_timing, 430 + int num_lane, int bpp) 431 + { 432 + int pclk_hsync, pclk_hfp, pclk_hbp, pclk_hactive; 433 + int pclk_vsync, pclk_vfp, pclk_vbp, pclk_vactive; 434 + 435 + pclk_hactive = mode->hdisplay; 436 + pclk_hfp = mode->hsync_start - mode->hdisplay; 437 + pclk_hsync = mode->hsync_end - mode->hsync_start; 438 + pclk_hbp = mode->htotal - mode->hsync_end; 439 + 440 + pclk_vactive = mode->vdisplay; 441 + pclk_vfp = mode->vsync_start - mode->vdisplay; 442 + pclk_vsync = mode->vsync_end - mode->vsync_start; 443 + pclk_vbp = mode->vtotal - mode->vsync_end; 444 + 445 + /* 446 + * byte clock counts were calculated by following formula 447 + * bclock_count = pclk_count * bpp / num_lane / 8 448 + */ 449 + dpi_timing->hsync_count = mdfld_dsi_dpi_to_byte_clock_count( 450 + pclk_hsync, num_lane, bpp); 451 + dpi_timing->hbp_count = mdfld_dsi_dpi_to_byte_clock_count( 452 + pclk_hbp, num_lane, bpp); 453 + dpi_timing->hfp_count = mdfld_dsi_dpi_to_byte_clock_count( 454 + pclk_hfp, num_lane, bpp); 455 + dpi_timing->hactive_count = mdfld_dsi_dpi_to_byte_clock_count( 456 + pclk_hactive, num_lane, bpp); 457 + dpi_timing->vsync_count = mdfld_dsi_dpi_to_byte_clock_count( 458 + pclk_vsync, num_lane, bpp); 459 + dpi_timing->vbp_count = mdfld_dsi_dpi_to_byte_clock_count( 460 + pclk_vbp, num_lane, bpp); 461 + dpi_timing->vfp_count = mdfld_dsi_dpi_to_byte_clock_count( 462 + pclk_vfp, num_lane, bpp); 463 + 464 + return 0; 465 + } 466 + 467 + void mdfld_dsi_dpi_controller_init(struct mdfld_dsi_config *dsi_config, 468 + int pipe) 469 + { 470 + struct drm_device *dev = dsi_config->dev; 471 + int lane_count = dsi_config->lane_count; 472 + struct mdfld_dsi_dpi_timing dpi_timing; 473 + struct drm_display_mode *mode = dsi_config->mode; 474 + u32 val; 475 + 476 + /*un-ready device*/ 477 + REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), 0, 0, 0); 478 + 479 + /*init dsi adapter before kicking off*/ 480 + REG_WRITE(MIPI_CTRL_REG(pipe), 0x00000018); 481 + 482 + /*enable all interrupts*/ 483 + REG_WRITE(MIPI_INTR_EN_REG(pipe), 0xffffffff); 484 + 485 + /*set up func_prg*/ 486 + val = lane_count; 487 + val |= dsi_config->channel_num << DSI_DPI_VIRT_CHANNEL_OFFSET; 488 + 489 + switch (dsi_config->bpp) { 490 + case 16: 491 + val |= DSI_DPI_COLOR_FORMAT_RGB565; 492 + break; 493 + case 18: 494 + val |= DSI_DPI_COLOR_FORMAT_RGB666; 495 + break; 496 + case 24: 497 + val |= DSI_DPI_COLOR_FORMAT_RGB888; 498 + break; 499 + default: 500 + DRM_ERROR("unsupported color format, bpp = %d\n", 501 + dsi_config->bpp); 502 + } 503 + REG_WRITE(MIPI_DSI_FUNC_PRG_REG(pipe), val); 504 + 505 + REG_WRITE(MIPI_HS_TX_TIMEOUT_REG(pipe), 506 + (mode->vtotal * mode->htotal * dsi_config->bpp / 507 + (8 * lane_count)) & DSI_HS_TX_TIMEOUT_MASK); 508 + REG_WRITE(MIPI_LP_RX_TIMEOUT_REG(pipe), 509 + 0xffff & DSI_LP_RX_TIMEOUT_MASK); 510 + 511 + /*max value: 20 clock cycles of txclkesc*/ 512 + REG_WRITE(MIPI_TURN_AROUND_TIMEOUT_REG(pipe), 513 + 0x14 & DSI_TURN_AROUND_TIMEOUT_MASK); 514 + 515 + /*min 21 txclkesc, max: ffffh*/ 516 + REG_WRITE(MIPI_DEVICE_RESET_TIMER_REG(pipe), 517 + 0xffff & DSI_RESET_TIMER_MASK); 518 + 519 + REG_WRITE(MIPI_DPI_RESOLUTION_REG(pipe), 520 + mode->vdisplay << 16 | mode->hdisplay); 521 + 522 + /*set DPI timing registers*/ 523 + mdfld_dsi_dpi_timing_calculation(mode, &dpi_timing, 524 + dsi_config->lane_count, dsi_config->bpp); 525 + 526 + REG_WRITE(MIPI_HSYNC_COUNT_REG(pipe), 527 + dpi_timing.hsync_count & DSI_DPI_TIMING_MASK); 528 + REG_WRITE(MIPI_HBP_COUNT_REG(pipe), 529 + dpi_timing.hbp_count & DSI_DPI_TIMING_MASK); 530 + REG_WRITE(MIPI_HFP_COUNT_REG(pipe), 531 + dpi_timing.hfp_count & DSI_DPI_TIMING_MASK); 532 + REG_WRITE(MIPI_HACTIVE_COUNT_REG(pipe), 533 + dpi_timing.hactive_count & DSI_DPI_TIMING_MASK); 534 + REG_WRITE(MIPI_VSYNC_COUNT_REG(pipe), 535 + dpi_timing.vsync_count & DSI_DPI_TIMING_MASK); 536 + REG_WRITE(MIPI_VBP_COUNT_REG(pipe), 537 + dpi_timing.vbp_count & DSI_DPI_TIMING_MASK); 538 + REG_WRITE(MIPI_VFP_COUNT_REG(pipe), 539 + dpi_timing.vfp_count & DSI_DPI_TIMING_MASK); 540 + 541 + REG_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe), 0x46); 542 + 543 + /*min: 7d0 max: 4e20*/ 544 + REG_WRITE(MIPI_INIT_COUNT_REG(pipe), 0x000007d0); 545 + 546 + /*set up video mode*/ 547 + val = dsi_config->video_mode | DSI_DPI_COMPLETE_LAST_LINE; 548 + REG_WRITE(MIPI_VIDEO_MODE_FORMAT_REG(pipe), val); 549 + 550 + REG_WRITE(MIPI_EOT_DISABLE_REG(pipe), 0x00000000); 551 + 552 + REG_WRITE(MIPI_LP_BYTECLK_REG(pipe), 0x00000004); 553 + 554 + /*TODO: figure out how to setup these registers*/ 555 + if (mdfld_get_panel_type(dev, pipe) == TC35876X) 556 + REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x2A0c6008); 557 + else 558 + REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x150c3408); 559 + 560 + REG_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe), (0xa << 16) | 0x14); 561 + 562 + if (mdfld_get_panel_type(dev, pipe) == TC35876X) 563 + tc35876x_set_bridge_reset_state(dev, 0); /*Pull High Reset */ 564 + 565 + /*set device ready*/ 566 + REG_FLD_MOD(MIPI_DEVICE_READY_REG(pipe), 1, 0, 0); 567 + } 568 + 569 + void mdfld_dsi_dpi_turn_on(struct mdfld_dsi_dpi_output *output, int pipe) 570 + { 571 + struct drm_device *dev = output->dev; 572 + 573 + /* clear special packet sent bit */ 574 + if (REG_READ(MIPI_INTR_STAT_REG(pipe)) & DSI_INTR_STATE_SPL_PKG_SENT) 575 + REG_WRITE(MIPI_INTR_STAT_REG(pipe), 576 + DSI_INTR_STATE_SPL_PKG_SENT); 577 + 578 + /*send turn on package*/ 579 + REG_WRITE(MIPI_DPI_CONTROL_REG(pipe), DSI_DPI_CTRL_HS_TURN_ON); 580 + 581 + /*wait for SPL_PKG_SENT interrupt*/ 582 + mdfld_wait_for_SPL_PKG_SENT(dev, pipe); 583 + 584 + if (REG_READ(MIPI_INTR_STAT_REG(pipe)) & DSI_INTR_STATE_SPL_PKG_SENT) 585 + REG_WRITE(MIPI_INTR_STAT_REG(pipe), 586 + DSI_INTR_STATE_SPL_PKG_SENT); 587 + 588 + output->panel_on = 1; 589 + 590 + /* FIXME the following is disabled to WA the X slow start issue 591 + for TMD panel 592 + if (pipe == 2) 593 + dev_priv->dpi_panel_on2 = true; 594 + else if (pipe == 0) 595 + dev_priv->dpi_panel_on = true; */ 596 + } 597 + 598 + static void mdfld_dsi_dpi_shut_down(struct mdfld_dsi_dpi_output *output, 599 + int pipe) 600 + { 601 + struct drm_device *dev = output->dev; 602 + 603 + /*if output is on, or mode setting didn't happen, ignore this*/ 604 + if ((!output->panel_on) || output->first_boot) { 605 + output->first_boot = 0; 606 + return; 607 + } 608 + 609 + /* Wait for dpi fifo to empty */ 610 + mdfld_wait_for_DPI_CTRL_FIFO(dev, pipe); 611 + 612 + /* Clear the special packet interrupt bit if set */ 613 + if (REG_READ(MIPI_INTR_STAT_REG(pipe)) & DSI_INTR_STATE_SPL_PKG_SENT) 614 + REG_WRITE(MIPI_INTR_STAT_REG(pipe), 615 + DSI_INTR_STATE_SPL_PKG_SENT); 616 + 617 + if (REG_READ(MIPI_DPI_CONTROL_REG(pipe)) == DSI_DPI_CTRL_HS_SHUTDOWN) 618 + goto shutdown_out; 619 + 620 + REG_WRITE(MIPI_DPI_CONTROL_REG(pipe), DSI_DPI_CTRL_HS_SHUTDOWN); 621 + 622 + shutdown_out: 623 + output->panel_on = 0; 624 + output->first_boot = 0; 625 + 626 + /* FIXME the following is disabled to WA the X slow start issue 627 + for TMD panel 628 + if (pipe == 2) 629 + dev_priv->dpi_panel_on2 = false; 630 + else if (pipe == 0) 631 + dev_priv->dpi_panel_on = false; */ 632 + } 633 + 634 + static void mdfld_dsi_dpi_set_power(struct drm_encoder *encoder, bool on) 635 + { 636 + struct mdfld_dsi_encoder *dsi_encoder = mdfld_dsi_encoder(encoder); 637 + struct mdfld_dsi_dpi_output *dpi_output = 638 + MDFLD_DSI_DPI_OUTPUT(dsi_encoder); 639 + struct mdfld_dsi_config *dsi_config = 640 + mdfld_dsi_encoder_get_config(dsi_encoder); 641 + int pipe = mdfld_dsi_encoder_get_pipe(dsi_encoder); 642 + struct drm_device *dev = dsi_config->dev; 643 + struct drm_psb_private *dev_priv = dev->dev_private; 644 + u32 pipeconf_reg = PIPEACONF; 645 + 646 + if (pipe) 647 + pipeconf_reg = PIPECCONF; 648 + 649 + /*start up display island if it was shutdown*/ 650 + if (!gma_power_begin(dev, true)) 651 + return; 652 + 653 + if (on) { 654 + if (mdfld_get_panel_type(dev, pipe) == TMD_VID) 655 + mdfld_dsi_dpi_turn_on(dpi_output, pipe); 656 + else if (mdfld_get_panel_type(dev, pipe) == TC35876X) 657 + mdfld_dsi_configure_up(dsi_encoder, pipe); 658 + else { 659 + /*enable mipi port*/ 660 + REG_WRITE(MIPI_PORT_CONTROL(pipe), 661 + REG_READ(MIPI_PORT_CONTROL(pipe)) | BIT(31)); 662 + REG_READ(MIPI_PORT_CONTROL(pipe)); 663 + 664 + mdfld_dsi_dpi_turn_on(dpi_output, pipe); 665 + mdfld_dsi_tpo_ic_init(dsi_config, pipe); 666 + } 667 + dev_priv->dpi_panel_on[pipe] = true; 668 + } else { 669 + if (mdfld_get_panel_type(dev, pipe) == TMD_VID) 670 + mdfld_dsi_dpi_shut_down(dpi_output, pipe); 671 + else if (mdfld_get_panel_type(dev, pipe) == TC35876X) 672 + mdfld_dsi_configure_down(dsi_encoder, pipe); 673 + else { 674 + mdfld_dsi_dpi_shut_down(dpi_output, pipe); 675 + 676 + /*disable mipi port*/ 677 + REG_WRITE(MIPI_PORT_CONTROL(pipe), 678 + REG_READ(MIPI_PORT_CONTROL(pipe)) & ~BIT(31)); 679 + REG_READ(MIPI_PORT_CONTROL(pipe)); 680 + } 681 + dev_priv->dpi_panel_on[pipe] = false; 682 + } 683 + gma_power_end(dev); 684 + } 685 + 686 + void mdfld_dsi_dpi_dpms(struct drm_encoder *encoder, int mode) 687 + { 688 + mdfld_dsi_dpi_set_power(encoder, mode == DRM_MODE_DPMS_ON); 689 + } 690 + 691 + bool mdfld_dsi_dpi_mode_fixup(struct drm_encoder *encoder, 692 + struct drm_display_mode *mode, 693 + struct drm_display_mode *adjusted_mode) 694 + { 695 + struct mdfld_dsi_encoder *dsi_encoder = mdfld_dsi_encoder(encoder); 696 + struct mdfld_dsi_config *dsi_config = 697 + mdfld_dsi_encoder_get_config(dsi_encoder); 698 + struct drm_display_mode *fixed_mode = dsi_config->fixed_mode; 699 + 700 + if (fixed_mode) { 701 + adjusted_mode->hdisplay = fixed_mode->hdisplay; 702 + adjusted_mode->hsync_start = fixed_mode->hsync_start; 703 + adjusted_mode->hsync_end = fixed_mode->hsync_end; 704 + adjusted_mode->htotal = fixed_mode->htotal; 705 + adjusted_mode->vdisplay = fixed_mode->vdisplay; 706 + adjusted_mode->vsync_start = fixed_mode->vsync_start; 707 + adjusted_mode->vsync_end = fixed_mode->vsync_end; 708 + adjusted_mode->vtotal = fixed_mode->vtotal; 709 + adjusted_mode->clock = fixed_mode->clock; 710 + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); 711 + } 712 + return true; 713 + } 714 + 715 + void mdfld_dsi_dpi_prepare(struct drm_encoder *encoder) 716 + { 717 + mdfld_dsi_dpi_set_power(encoder, false); 718 + } 719 + 720 + void mdfld_dsi_dpi_commit(struct drm_encoder *encoder) 721 + { 722 + mdfld_dsi_dpi_set_power(encoder, true); 723 + } 724 + 725 + /* For TC35876X */ 726 + /* This functionality was implemented in FW in iCDK */ 727 + /* But removed in DV0 and later. So need to add here. */ 728 + static void mipi_set_properties(struct mdfld_dsi_config *dsi_config, int pipe) 729 + { 730 + struct drm_device *dev = dsi_config->dev; 731 + 732 + REG_WRITE(MIPI_CTRL_REG(pipe), 0x00000018); 733 + REG_WRITE(MIPI_INTR_EN_REG(pipe), 0xffffffff); 734 + REG_WRITE(MIPI_HS_TX_TIMEOUT_REG(pipe), 0xffffff); 735 + REG_WRITE(MIPI_LP_RX_TIMEOUT_REG(pipe), 0xffffff); 736 + REG_WRITE(MIPI_TURN_AROUND_TIMEOUT_REG(pipe), 0x14); 737 + REG_WRITE(MIPI_DEVICE_RESET_TIMER_REG(pipe), 0xff); 738 + REG_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe), 0x25); 739 + REG_WRITE(MIPI_INIT_COUNT_REG(pipe), 0xf0); 740 + REG_WRITE(MIPI_EOT_DISABLE_REG(pipe), 0x00000000); 741 + REG_WRITE(MIPI_LP_BYTECLK_REG(pipe), 0x00000004); 742 + REG_WRITE(MIPI_DBI_BW_CTRL_REG(pipe), 0x00000820); 743 + REG_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe), (0xa << 16) | 0x14); 744 + } 745 + 746 + static void mdfld_mipi_set_video_timing(struct mdfld_dsi_config *dsi_config, 747 + int pipe) 748 + { 749 + struct drm_device *dev = dsi_config->dev; 750 + struct mdfld_dsi_dpi_timing dpi_timing; 751 + struct drm_display_mode *mode = dsi_config->mode; 752 + 753 + mdfld_dsi_dpi_timing_calculation(mode, &dpi_timing, 754 + dsi_config->lane_count, 755 + dsi_config->bpp); 756 + 757 + REG_WRITE(MIPI_DPI_RESOLUTION_REG(pipe), 758 + mode->vdisplay << 16 | mode->hdisplay); 759 + REG_WRITE(MIPI_HSYNC_COUNT_REG(pipe), 760 + dpi_timing.hsync_count & DSI_DPI_TIMING_MASK); 761 + REG_WRITE(MIPI_HBP_COUNT_REG(pipe), 762 + dpi_timing.hbp_count & DSI_DPI_TIMING_MASK); 763 + REG_WRITE(MIPI_HFP_COUNT_REG(pipe), 764 + dpi_timing.hfp_count & DSI_DPI_TIMING_MASK); 765 + REG_WRITE(MIPI_HACTIVE_COUNT_REG(pipe), 766 + dpi_timing.hactive_count & DSI_DPI_TIMING_MASK); 767 + REG_WRITE(MIPI_VSYNC_COUNT_REG(pipe), 768 + dpi_timing.vsync_count & DSI_DPI_TIMING_MASK); 769 + REG_WRITE(MIPI_VBP_COUNT_REG(pipe), 770 + dpi_timing.vbp_count & DSI_DPI_TIMING_MASK); 771 + REG_WRITE(MIPI_VFP_COUNT_REG(pipe), 772 + dpi_timing.vfp_count & DSI_DPI_TIMING_MASK); 773 + } 774 + 775 + static void mdfld_mipi_config(struct mdfld_dsi_config *dsi_config, int pipe) 776 + { 777 + struct drm_device *dev = dsi_config->dev; 778 + int lane_count = dsi_config->lane_count; 779 + 780 + if (pipe) { 781 + REG_WRITE(MIPI_PORT_CONTROL(0), 0x00000002); 782 + REG_WRITE(MIPI_PORT_CONTROL(2), 0x80000000); 783 + } else { 784 + REG_WRITE(MIPI_PORT_CONTROL(0), 0x80010000); 785 + REG_WRITE(MIPI_PORT_CONTROL(2), 0x00); 786 + } 787 + 788 + REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x150A600F); 789 + REG_WRITE(MIPI_VIDEO_MODE_FORMAT_REG(pipe), 0x0000000F); 790 + 791 + /* lane_count = 3 */ 792 + REG_WRITE(MIPI_DSI_FUNC_PRG_REG(pipe), 0x00000200 | lane_count); 793 + 794 + mdfld_mipi_set_video_timing(dsi_config, pipe); 795 + } 796 + 797 + static void mdfld_set_pipe_timing(struct mdfld_dsi_config *dsi_config, int pipe) 798 + { 799 + struct drm_device *dev = dsi_config->dev; 800 + struct drm_display_mode *mode = dsi_config->mode; 801 + 802 + REG_WRITE(HTOTAL_A, ((mode->htotal - 1) << 16) | (mode->hdisplay - 1)); 803 + REG_WRITE(HBLANK_A, ((mode->htotal - 1) << 16) | (mode->hdisplay - 1)); 804 + REG_WRITE(HSYNC_A, 805 + ((mode->hsync_end - 1) << 16) | (mode->hsync_start - 1)); 806 + 807 + REG_WRITE(VTOTAL_A, ((mode->vtotal - 1) << 16) | (mode->vdisplay - 1)); 808 + REG_WRITE(VBLANK_A, ((mode->vtotal - 1) << 16) | (mode->vdisplay - 1)); 809 + REG_WRITE(VSYNC_A, 810 + ((mode->vsync_end - 1) << 16) | (mode->vsync_start - 1)); 811 + 812 + REG_WRITE(PIPEASRC, 813 + ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); 814 + } 815 + /* End for TC35876X */ 816 + 817 + void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder, 818 + struct drm_display_mode *mode, 819 + struct drm_display_mode *adjusted_mode) 820 + { 821 + struct mdfld_dsi_encoder *dsi_encoder = mdfld_dsi_encoder(encoder); 822 + struct mdfld_dsi_dpi_output *dpi_output = 823 + MDFLD_DSI_DPI_OUTPUT(dsi_encoder); 824 + struct mdfld_dsi_config *dsi_config = 825 + mdfld_dsi_encoder_get_config(dsi_encoder); 826 + struct drm_device *dev = dsi_config->dev; 827 + struct drm_psb_private *dev_priv = dev->dev_private; 828 + int pipe = mdfld_dsi_encoder_get_pipe(dsi_encoder); 829 + 830 + u32 pipeconf_reg = PIPEACONF; 831 + u32 dspcntr_reg = DSPACNTR; 832 + 833 + u32 pipeconf = dev_priv->pipeconf[pipe]; 834 + u32 dspcntr = dev_priv->dspcntr[pipe]; 835 + u32 mipi = MIPI_PORT_EN | PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX; 836 + 837 + if (pipe) { 838 + pipeconf_reg = PIPECCONF; 839 + dspcntr_reg = DSPCCNTR; 840 + } else { 841 + if (mdfld_get_panel_type(dev, pipe) == TC35876X) 842 + mipi &= (~0x03); /* Use all four lanes */ 843 + else 844 + mipi |= 2; 845 + } 846 + 847 + /*start up display island if it was shutdown*/ 848 + if (!gma_power_begin(dev, true)) 849 + return; 850 + 851 + if (mdfld_get_panel_type(dev, pipe) == TC35876X) { 852 + /* 853 + * The following logic is required to reset the bridge and 854 + * configure. This also starts the DSI clock at 200MHz. 855 + */ 856 + tc35876x_set_bridge_reset_state(dev, 0); /*Pull High Reset */ 857 + tc35876x_toshiba_bridge_panel_on(dev); 858 + udelay(100); 859 + /* Now start the DSI clock */ 860 + REG_WRITE(MRST_DPLL_A, 0x00); 861 + REG_WRITE(MRST_FPA0, 0xC1); 862 + REG_WRITE(MRST_DPLL_A, 0x00800000); 863 + udelay(500); 864 + REG_WRITE(MRST_DPLL_A, 0x80800000); 865 + 866 + if (REG_BIT_WAIT(pipeconf_reg, 1, 29)) 867 + dev_err(&dev->pdev->dev, "%s: DSI PLL lock timeout\n", 868 + __func__); 869 + 870 + REG_WRITE(MIPI_DPHY_PARAM_REG(pipe), 0x2A0c6008); 871 + 872 + mipi_set_properties(dsi_config, pipe); 873 + mdfld_mipi_config(dsi_config, pipe); 874 + mdfld_set_pipe_timing(dsi_config, pipe); 875 + 876 + REG_WRITE(DSPABASE, 0x00); 877 + REG_WRITE(DSPASTRIDE, (mode->hdisplay * 4)); 878 + REG_WRITE(DSPASIZE, 879 + ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); 880 + 881 + REG_WRITE(DSPACNTR, 0x98000000); 882 + REG_WRITE(DSPASURF, 0x00); 883 + 884 + REG_WRITE(VGACNTRL, 0x80000000); 885 + REG_WRITE(DEVICE_READY_REG, 0x00000001); 886 + 887 + REG_WRITE(MIPI_PORT_CONTROL(pipe), 0x80810000); 888 + } else { 889 + /*set up mipi port FIXME: do at init time */ 890 + REG_WRITE(MIPI_PORT_CONTROL(pipe), mipi); 891 + } 892 + REG_READ(MIPI_PORT_CONTROL(pipe)); 893 + 894 + if (mdfld_get_panel_type(dev, pipe) == TMD_VID) { 895 + /* NOP */ 896 + } else if (mdfld_get_panel_type(dev, pipe) == TC35876X) { 897 + /* set up DSI controller DPI interface */ 898 + mdfld_dsi_dpi_controller_init(dsi_config, pipe); 899 + 900 + /* Configure MIPI Bridge and Panel */ 901 + tc35876x_configure_lvds_bridge(dev); 902 + dev_priv->dpi_panel_on[pipe] = true; 903 + } else { 904 + /*turn on DPI interface*/ 905 + mdfld_dsi_dpi_turn_on(dpi_output, pipe); 906 + } 907 + 908 + /*set up pipe*/ 909 + REG_WRITE(pipeconf_reg, pipeconf); 910 + REG_READ(pipeconf_reg); 911 + 912 + /*set up display plane*/ 913 + REG_WRITE(dspcntr_reg, dspcntr); 914 + REG_READ(dspcntr_reg); 915 + 916 + msleep(20); /* FIXME: this should wait for vblank */ 917 + 918 + if (mdfld_get_panel_type(dev, pipe) == TMD_VID) { 919 + /* NOP */ 920 + } else if (mdfld_get_panel_type(dev, pipe) == TC35876X) { 921 + mdfld_dsi_dpi_turn_on(dpi_output, pipe); 922 + } else { 923 + /* init driver ic */ 924 + mdfld_dsi_tpo_ic_init(dsi_config, pipe); 925 + /*init backlight*/ 926 + mdfld_dsi_brightness_init(dsi_config, pipe); 927 + } 928 + 929 + gma_power_end(dev); 930 + } 931 + 932 + /* 933 + * Init DSI DPI encoder. 934 + * Allocate an mdfld_dsi_encoder and attach it to given @dsi_connector 935 + * return pointer of newly allocated DPI encoder, NULL on error 936 + */ 937 + struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev, 938 + struct mdfld_dsi_connector *dsi_connector, 939 + const struct panel_funcs *p_funcs) 940 + { 941 + struct mdfld_dsi_dpi_output *dpi_output = NULL; 942 + struct mdfld_dsi_config *dsi_config; 943 + struct drm_connector *connector = NULL; 944 + struct drm_encoder *encoder = NULL; 945 + struct drm_display_mode *fixed_mode = NULL; 946 + int pipe; 947 + u32 data; 948 + int ret; 949 + 950 + pipe = dsi_connector->pipe; 951 + 952 + if (mdfld_get_panel_type(dev, pipe) != TC35876X) { 953 + dsi_config = mdfld_dsi_get_config(dsi_connector); 954 + 955 + /* panel hard-reset */ 956 + if (p_funcs->reset) { 957 + ret = p_funcs->reset(pipe); 958 + if (ret) { 959 + DRM_ERROR("Panel %d hard-reset failed\n", pipe); 960 + return NULL; 961 + } 962 + } 963 + 964 + /* panel drvIC init */ 965 + if (p_funcs->drv_ic_init) 966 + p_funcs->drv_ic_init(dsi_config, pipe); 967 + 968 + /* panel power mode detect */ 969 + ret = mdfld_dsi_get_power_mode(dsi_config, &data, false); 970 + if (ret) { 971 + DRM_ERROR("Panel %d get power mode failed\n", pipe); 972 + dsi_connector->status = connector_status_disconnected; 973 + } else { 974 + DRM_INFO("pipe %d power mode 0x%x\n", pipe, data); 975 + dsi_connector->status = connector_status_connected; 976 + } 977 + } 978 + 979 + dpi_output = kzalloc(sizeof(struct mdfld_dsi_dpi_output), GFP_KERNEL); 980 + if (!dpi_output) { 981 + DRM_ERROR("No memory\n"); 982 + return NULL; 983 + } 984 + 985 + if (dsi_connector->pipe) 986 + dpi_output->panel_on = 0; 987 + else 988 + dpi_output->panel_on = 0; 989 + 990 + dpi_output->dev = dev; 991 + if (mdfld_get_panel_type(dev, pipe) != TC35876X) 992 + dpi_output->p_funcs = p_funcs; 993 + dpi_output->first_boot = 1; 994 + 995 + /*get fixed mode*/ 996 + dsi_config = mdfld_dsi_get_config(dsi_connector); 997 + fixed_mode = dsi_config->fixed_mode; 998 + 999 + /*create drm encoder object*/ 1000 + connector = &dsi_connector->base.base; 1001 + encoder = &dpi_output->base.base.base; 1002 + drm_encoder_init(dev, 1003 + encoder, 1004 + p_funcs->encoder_funcs, 1005 + DRM_MODE_ENCODER_LVDS); 1006 + drm_encoder_helper_add(encoder, 1007 + p_funcs->encoder_helper_funcs); 1008 + 1009 + /*attach to given connector*/ 1010 + drm_mode_connector_attach_encoder(connector, encoder); 1011 + 1012 + /*set possible crtcs and clones*/ 1013 + if (dsi_connector->pipe) { 1014 + encoder->possible_crtcs = (1 << 2); 1015 + encoder->possible_clones = (1 << 1); 1016 + } else { 1017 + encoder->possible_crtcs = (1 << 0); 1018 + encoder->possible_clones = (1 << 0); 1019 + } 1020 + 1021 + dsi_connector->base.encoder = &dpi_output->base.base; 1022 + 1023 + return &dpi_output->base; 1024 + }
+79
drivers/gpu/drm/gma500/mdfld_dsi_dpi.h
··· 1 + /* 2 + * Copyright © 2010 Intel Corporation 3 + * 4 + * Permission is hereby granted, free of charge, to any person obtaining a 5 + * copy of this software and associated documentation files (the "Software"), 6 + * to deal in the Software without restriction, including without limitation 7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 + * and/or sell copies of the Software, and to permit persons to whom the 9 + * Software is furnished to do so, subject to the following conditions: 10 + * 11 + * The above copyright notice and this permission notice (including the next 12 + * paragraph) shall be included in all copies or substantial portions of the 13 + * Software. 14 + * 15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 + * DEALINGS IN THE SOFTWARE. 22 + * 23 + * Authors: 24 + * jim liu <jim.liu@intel.com> 25 + * Jackie Li<yaodong.li@intel.com> 26 + */ 27 + 28 + #ifndef __MDFLD_DSI_DPI_H__ 29 + #define __MDFLD_DSI_DPI_H__ 30 + 31 + #include "mdfld_dsi_output.h" 32 + #include "mdfld_output.h" 33 + 34 + struct mdfld_dsi_dpi_timing { 35 + u16 hsync_count; 36 + u16 hbp_count; 37 + u16 hfp_count; 38 + u16 hactive_count; 39 + u16 vsync_count; 40 + u16 vbp_count; 41 + u16 vfp_count; 42 + }; 43 + 44 + struct mdfld_dsi_dpi_output { 45 + struct mdfld_dsi_encoder base; 46 + struct drm_device *dev; 47 + 48 + int panel_on; 49 + int first_boot; 50 + 51 + const struct panel_funcs *p_funcs; 52 + }; 53 + 54 + #define MDFLD_DSI_DPI_OUTPUT(dsi_encoder)\ 55 + container_of(dsi_encoder, struct mdfld_dsi_dpi_output, base) 56 + 57 + /* Export functions */ 58 + extern int mdfld_dsi_dpi_timing_calculation(struct drm_display_mode *mode, 59 + struct mdfld_dsi_dpi_timing *dpi_timing, 60 + int num_lane, int bpp); 61 + extern struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev, 62 + struct mdfld_dsi_connector *dsi_connector, 63 + const struct panel_funcs *p_funcs); 64 + 65 + /* MDFLD DPI helper functions */ 66 + extern void mdfld_dsi_dpi_dpms(struct drm_encoder *encoder, int mode); 67 + extern bool mdfld_dsi_dpi_mode_fixup(struct drm_encoder *encoder, 68 + struct drm_display_mode *mode, 69 + struct drm_display_mode *adjusted_mode); 70 + extern void mdfld_dsi_dpi_prepare(struct drm_encoder *encoder); 71 + extern void mdfld_dsi_dpi_commit(struct drm_encoder *encoder); 72 + extern void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder, 73 + struct drm_display_mode *mode, 74 + struct drm_display_mode *adjusted_mode); 75 + extern void mdfld_dsi_dpi_turn_on(struct mdfld_dsi_dpi_output *output, 76 + int pipe); 77 + extern void mdfld_dsi_dpi_controller_init(struct mdfld_dsi_config *dsi_config, 78 + int pipe); 79 + #endif /*__MDFLD_DSI_DPI_H__*/
+635
drivers/gpu/drm/gma500/mdfld_dsi_output.c
··· 1 + /* 2 + * Copyright © 2010 Intel Corporation 3 + * 4 + * Permission is hereby granted, free of charge, to any person obtaining a 5 + * copy of this software and associated documentation files (the "Software"), 6 + * to deal in the Software without restriction, including without limitation 7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 + * and/or sell copies of the Software, and to permit persons to whom the 9 + * Software is furnished to do so, subject to the following conditions: 10 + * 11 + * The above copyright notice and this permission notice (including the next 12 + * paragraph) shall be included in all copies or substantial portions of the 13 + * Software. 14 + * 15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 + * DEALINGS IN THE SOFTWARE. 22 + * 23 + * Authors: 24 + * jim liu <jim.liu@intel.com> 25 + * Jackie Li<yaodong.li@intel.com> 26 + */ 27 + 28 + #include <linux/module.h> 29 + 30 + #include "mdfld_dsi_output.h" 31 + #include "mdfld_dsi_dpi.h" 32 + #include "mdfld_output.h" 33 + #include "mdfld_dsi_pkg_sender.h" 34 + #include "tc35876x-dsi-lvds.h" 35 + #include <linux/pm_runtime.h> 36 + #include <asm/intel_scu_ipc.h> 37 + 38 + /* get the LABC from command line. */ 39 + static int LABC_control = 1; 40 + 41 + #ifdef MODULE 42 + module_param(LABC_control, int, 0644); 43 + #else 44 + 45 + static int __init parse_LABC_control(char *arg) 46 + { 47 + /* LABC control can be passed in as a cmdline parameter */ 48 + /* to enable this feature add LABC=1 to cmdline */ 49 + /* to disable this feature add LABC=0 to cmdline */ 50 + if (!arg) 51 + return -EINVAL; 52 + 53 + if (!strcasecmp(arg, "0")) 54 + LABC_control = 0; 55 + else if (!strcasecmp(arg, "1")) 56 + LABC_control = 1; 57 + 58 + return 0; 59 + } 60 + early_param("LABC", parse_LABC_control); 61 + #endif 62 + 63 + /** 64 + * Check and see if the generic control or data buffer is empty and ready. 65 + */ 66 + void mdfld_dsi_gen_fifo_ready(struct drm_device *dev, u32 gen_fifo_stat_reg, 67 + u32 fifo_stat) 68 + { 69 + u32 GEN_BF_time_out_count; 70 + 71 + /* Check MIPI Adatper command registers */ 72 + for (GEN_BF_time_out_count = 0; 73 + GEN_BF_time_out_count < GEN_FB_TIME_OUT; 74 + GEN_BF_time_out_count++) { 75 + if ((REG_READ(gen_fifo_stat_reg) & fifo_stat) == fifo_stat) 76 + break; 77 + udelay(100); 78 + } 79 + 80 + if (GEN_BF_time_out_count == GEN_FB_TIME_OUT) 81 + DRM_ERROR("mdfld_dsi_gen_fifo_ready, Timeout. gen_fifo_stat_reg = 0x%x.\n", 82 + gen_fifo_stat_reg); 83 + } 84 + 85 + /** 86 + * Manage the DSI MIPI keyboard and display brightness. 87 + * FIXME: this is exported to OSPM code. should work out an specific 88 + * display interface to OSPM. 89 + */ 90 + 91 + void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, int pipe) 92 + { 93 + struct mdfld_dsi_pkg_sender *sender = 94 + mdfld_dsi_get_pkg_sender(dsi_config); 95 + struct drm_device *dev = sender->dev; 96 + struct drm_psb_private *dev_priv = dev->dev_private; 97 + u32 gen_ctrl_val; 98 + 99 + if (!sender) { 100 + DRM_ERROR("No sender found\n"); 101 + return; 102 + } 103 + 104 + /* Set default display backlight value to 85% (0xd8)*/ 105 + mdfld_dsi_send_mcs_short(sender, write_display_brightness, 0xd8, 1, 106 + true); 107 + 108 + /* Set minimum brightness setting of CABC function to 20% (0x33)*/ 109 + mdfld_dsi_send_mcs_short(sender, write_cabc_min_bright, 0x33, 1, true); 110 + 111 + /* Enable backlight or/and LABC */ 112 + gen_ctrl_val = BRIGHT_CNTL_BLOCK_ON | DISPLAY_DIMMING_ON | 113 + BACKLIGHT_ON; 114 + if (LABC_control == 1) 115 + gen_ctrl_val |= DISPLAY_DIMMING_ON | DISPLAY_BRIGHTNESS_AUTO 116 + | GAMMA_AUTO; 117 + 118 + if (LABC_control == 1) 119 + gen_ctrl_val |= AMBIENT_LIGHT_SENSE_ON; 120 + 121 + dev_priv->mipi_ctrl_display = gen_ctrl_val; 122 + 123 + mdfld_dsi_send_mcs_short(sender, write_ctrl_display, (u8)gen_ctrl_val, 124 + 1, true); 125 + 126 + mdfld_dsi_send_mcs_short(sender, write_ctrl_cabc, UI_IMAGE, 1, true); 127 + } 128 + 129 + void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe, int level) 130 + { 131 + struct mdfld_dsi_pkg_sender *sender; 132 + struct drm_psb_private *dev_priv; 133 + struct mdfld_dsi_config *dsi_config; 134 + u32 gen_ctrl_val = 0; 135 + int p_type = TMD_VID; 136 + 137 + if (!dev || (pipe != 0 && pipe != 2)) { 138 + DRM_ERROR("Invalid parameter\n"); 139 + return; 140 + } 141 + 142 + p_type = mdfld_get_panel_type(dev, 0); 143 + 144 + dev_priv = dev->dev_private; 145 + 146 + if (pipe) 147 + dsi_config = dev_priv->dsi_configs[1]; 148 + else 149 + dsi_config = dev_priv->dsi_configs[0]; 150 + 151 + sender = mdfld_dsi_get_pkg_sender(dsi_config); 152 + 153 + if (!sender) { 154 + DRM_ERROR("No sender found\n"); 155 + return; 156 + } 157 + 158 + gen_ctrl_val = (level * 0xff / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL) & 0xff; 159 + 160 + dev_dbg(sender->dev->dev, "pipe = %d, gen_ctrl_val = %d.\n", 161 + pipe, gen_ctrl_val); 162 + 163 + if (p_type == TMD_VID) { 164 + /* Set display backlight value */ 165 + mdfld_dsi_send_mcs_short(sender, tmd_write_display_brightness, 166 + (u8)gen_ctrl_val, 1, true); 167 + } else { 168 + /* Set display backlight value */ 169 + mdfld_dsi_send_mcs_short(sender, write_display_brightness, 170 + (u8)gen_ctrl_val, 1, true); 171 + 172 + /* Enable backlight control */ 173 + if (level == 0) 174 + gen_ctrl_val = 0; 175 + else 176 + gen_ctrl_val = dev_priv->mipi_ctrl_display; 177 + 178 + mdfld_dsi_send_mcs_short(sender, write_ctrl_display, 179 + (u8)gen_ctrl_val, 1, true); 180 + } 181 + } 182 + 183 + static int mdfld_dsi_get_panel_status(struct mdfld_dsi_config *dsi_config, 184 + u8 dcs, u32 *data, bool hs) 185 + { 186 + struct mdfld_dsi_pkg_sender *sender 187 + = mdfld_dsi_get_pkg_sender(dsi_config); 188 + 189 + if (!sender || !data) { 190 + DRM_ERROR("Invalid parameter\n"); 191 + return -EINVAL; 192 + } 193 + 194 + return mdfld_dsi_read_mcs(sender, dcs, data, 1, hs); 195 + } 196 + 197 + int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, u32 *mode, 198 + bool hs) 199 + { 200 + if (!dsi_config || !mode) { 201 + DRM_ERROR("Invalid parameter\n"); 202 + return -EINVAL; 203 + } 204 + 205 + return mdfld_dsi_get_panel_status(dsi_config, 0x0a, mode, hs); 206 + } 207 + 208 + int mdfld_dsi_get_diagnostic_result(struct mdfld_dsi_config *dsi_config, 209 + u32 *result, bool hs) 210 + { 211 + if (!dsi_config || !result) { 212 + DRM_ERROR("Invalid parameter\n"); 213 + return -EINVAL; 214 + } 215 + 216 + return mdfld_dsi_get_panel_status(dsi_config, 0x0f, result, hs); 217 + } 218 + 219 + /* 220 + * NOTE: this function was used by OSPM. 221 + * TODO: will be removed later, should work out display interfaces for OSPM 222 + */ 223 + void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config, int pipe) 224 + { 225 + if (!dsi_config || ((pipe != 0) && (pipe != 2))) { 226 + DRM_ERROR("Invalid parameters\n"); 227 + return; 228 + } 229 + 230 + mdfld_dsi_dpi_controller_init(dsi_config, pipe); 231 + } 232 + 233 + static void mdfld_dsi_connector_save(struct drm_connector *connector) 234 + { 235 + } 236 + 237 + static void mdfld_dsi_connector_restore(struct drm_connector *connector) 238 + { 239 + } 240 + 241 + /* FIXME: start using the force parameter */ 242 + static enum drm_connector_status 243 + mdfld_dsi_connector_detect(struct drm_connector *connector, bool force) 244 + { 245 + struct mdfld_dsi_connector *dsi_connector 246 + = mdfld_dsi_connector(connector); 247 + 248 + dsi_connector->status = connector_status_connected; 249 + 250 + return dsi_connector->status; 251 + } 252 + 253 + static int mdfld_dsi_connector_set_property(struct drm_connector *connector, 254 + struct drm_property *property, 255 + uint64_t value) 256 + { 257 + struct drm_encoder *encoder = connector->encoder; 258 + struct backlight_device *psb_bd; 259 + 260 + if (!strcmp(property->name, "scaling mode") && encoder) { 261 + struct psb_intel_crtc *psb_crtc = 262 + to_psb_intel_crtc(encoder->crtc); 263 + bool centerechange; 264 + uint64_t val; 265 + 266 + if (!psb_crtc) 267 + goto set_prop_error; 268 + 269 + switch (value) { 270 + case DRM_MODE_SCALE_FULLSCREEN: 271 + break; 272 + case DRM_MODE_SCALE_NO_SCALE: 273 + break; 274 + case DRM_MODE_SCALE_ASPECT: 275 + break; 276 + default: 277 + goto set_prop_error; 278 + } 279 + 280 + if (drm_connector_property_get_value(connector, property, &val)) 281 + goto set_prop_error; 282 + 283 + if (val == value) 284 + goto set_prop_done; 285 + 286 + if (drm_connector_property_set_value(connector, 287 + property, value)) 288 + goto set_prop_error; 289 + 290 + centerechange = (val == DRM_MODE_SCALE_NO_SCALE) || 291 + (value == DRM_MODE_SCALE_NO_SCALE); 292 + 293 + if (psb_crtc->saved_mode.hdisplay != 0 && 294 + psb_crtc->saved_mode.vdisplay != 0) { 295 + if (centerechange) { 296 + if (!drm_crtc_helper_set_mode(encoder->crtc, 297 + &psb_crtc->saved_mode, 298 + encoder->crtc->x, 299 + encoder->crtc->y, 300 + encoder->crtc->fb)) 301 + goto set_prop_error; 302 + } else { 303 + struct drm_encoder_helper_funcs *funcs = 304 + encoder->helper_private; 305 + funcs->mode_set(encoder, 306 + &psb_crtc->saved_mode, 307 + &psb_crtc->saved_adjusted_mode); 308 + } 309 + } 310 + } else if (!strcmp(property->name, "backlight") && encoder) { 311 + if (drm_connector_property_set_value(connector, property, 312 + value)) 313 + goto set_prop_error; 314 + else { 315 + psb_bd = mdfld_get_backlight_device(); 316 + if (psb_bd) { 317 + psb_bd->props.brightness = value; 318 + mdfld_set_brightness(psb_bd); 319 + } 320 + } 321 + } 322 + set_prop_done: 323 + return 0; 324 + set_prop_error: 325 + return -1; 326 + } 327 + 328 + static void mdfld_dsi_connector_destroy(struct drm_connector *connector) 329 + { 330 + struct mdfld_dsi_connector *dsi_connector = 331 + mdfld_dsi_connector(connector); 332 + struct mdfld_dsi_pkg_sender *sender; 333 + 334 + if (!dsi_connector) 335 + return; 336 + drm_sysfs_connector_remove(connector); 337 + drm_connector_cleanup(connector); 338 + sender = dsi_connector->pkg_sender; 339 + mdfld_dsi_pkg_sender_destroy(sender); 340 + kfree(dsi_connector); 341 + } 342 + 343 + static int mdfld_dsi_connector_get_modes(struct drm_connector *connector) 344 + { 345 + struct mdfld_dsi_connector *dsi_connector = 346 + mdfld_dsi_connector(connector); 347 + struct mdfld_dsi_config *dsi_config = 348 + mdfld_dsi_get_config(dsi_connector); 349 + struct drm_display_mode *fixed_mode = dsi_config->fixed_mode; 350 + struct drm_display_mode *dup_mode = NULL; 351 + struct drm_device *dev = connector->dev; 352 + 353 + connector->display_info.min_vfreq = 0; 354 + connector->display_info.max_vfreq = 200; 355 + connector->display_info.min_hfreq = 0; 356 + connector->display_info.max_hfreq = 200; 357 + 358 + if (fixed_mode) { 359 + dev_dbg(dev->dev, "fixed_mode %dx%d\n", 360 + fixed_mode->hdisplay, fixed_mode->vdisplay); 361 + dup_mode = drm_mode_duplicate(dev, fixed_mode); 362 + drm_mode_probed_add(connector, dup_mode); 363 + return 1; 364 + } 365 + DRM_ERROR("Didn't get any modes!\n"); 366 + return 0; 367 + } 368 + 369 + static int mdfld_dsi_connector_mode_valid(struct drm_connector *connector, 370 + struct drm_display_mode *mode) 371 + { 372 + struct mdfld_dsi_connector *dsi_connector = 373 + mdfld_dsi_connector(connector); 374 + struct mdfld_dsi_config *dsi_config = 375 + mdfld_dsi_get_config(dsi_connector); 376 + struct drm_display_mode *fixed_mode = dsi_config->fixed_mode; 377 + 378 + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 379 + return MODE_NO_DBLESCAN; 380 + 381 + if (mode->flags & DRM_MODE_FLAG_INTERLACE) 382 + return MODE_NO_INTERLACE; 383 + 384 + /** 385 + * FIXME: current DC has no fitting unit, reject any mode setting 386 + * request 387 + * Will figure out a way to do up-scaling(pannel fitting) later. 388 + **/ 389 + if (fixed_mode) { 390 + if (mode->hdisplay != fixed_mode->hdisplay) 391 + return MODE_PANEL; 392 + 393 + if (mode->vdisplay != fixed_mode->vdisplay) 394 + return MODE_PANEL; 395 + } 396 + 397 + return MODE_OK; 398 + } 399 + 400 + static void mdfld_dsi_connector_dpms(struct drm_connector *connector, int mode) 401 + { 402 + if (mode == connector->dpms) 403 + return; 404 + 405 + /*first, execute dpms*/ 406 + 407 + drm_helper_connector_dpms(connector, mode); 408 + } 409 + 410 + static struct drm_encoder *mdfld_dsi_connector_best_encoder( 411 + struct drm_connector *connector) 412 + { 413 + struct mdfld_dsi_connector *dsi_connector = 414 + mdfld_dsi_connector(connector); 415 + struct mdfld_dsi_config *dsi_config = 416 + mdfld_dsi_get_config(dsi_connector); 417 + return &dsi_config->encoder->base.base; 418 + } 419 + 420 + /*DSI connector funcs*/ 421 + static const struct drm_connector_funcs mdfld_dsi_connector_funcs = { 422 + .dpms = /*drm_helper_connector_dpms*/mdfld_dsi_connector_dpms, 423 + .save = mdfld_dsi_connector_save, 424 + .restore = mdfld_dsi_connector_restore, 425 + .detect = mdfld_dsi_connector_detect, 426 + .fill_modes = drm_helper_probe_single_connector_modes, 427 + .set_property = mdfld_dsi_connector_set_property, 428 + .destroy = mdfld_dsi_connector_destroy, 429 + }; 430 + 431 + /*DSI connector helper funcs*/ 432 + static const struct drm_connector_helper_funcs 433 + mdfld_dsi_connector_helper_funcs = { 434 + .get_modes = mdfld_dsi_connector_get_modes, 435 + .mode_valid = mdfld_dsi_connector_mode_valid, 436 + .best_encoder = mdfld_dsi_connector_best_encoder, 437 + }; 438 + 439 + static int mdfld_dsi_get_default_config(struct drm_device *dev, 440 + struct mdfld_dsi_config *config, int pipe) 441 + { 442 + if (!dev || !config) { 443 + DRM_ERROR("Invalid parameters"); 444 + return -EINVAL; 445 + } 446 + 447 + config->bpp = 24; 448 + if (mdfld_get_panel_type(dev, pipe) == TC35876X) 449 + config->lane_count = 4; 450 + else 451 + config->lane_count = 2; 452 + config->channel_num = 0; 453 + 454 + if (mdfld_get_panel_type(dev, pipe) == TMD_VID) 455 + config->video_mode = MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE; 456 + else if (mdfld_get_panel_type(dev, pipe) == TC35876X) 457 + config->video_mode = 458 + MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS; 459 + else 460 + config->video_mode = MDFLD_DSI_VIDEO_BURST_MODE; 461 + 462 + return 0; 463 + } 464 + 465 + int mdfld_dsi_panel_reset(int pipe) 466 + { 467 + unsigned gpio; 468 + int ret = 0; 469 + 470 + switch (pipe) { 471 + case 0: 472 + gpio = 128; 473 + break; 474 + case 2: 475 + gpio = 34; 476 + break; 477 + default: 478 + DRM_ERROR("Invalid output\n"); 479 + return -EINVAL; 480 + } 481 + 482 + ret = gpio_request(gpio, "gfx"); 483 + if (ret) { 484 + DRM_ERROR("gpio_rqueset failed\n"); 485 + return ret; 486 + } 487 + 488 + ret = gpio_direction_output(gpio, 1); 489 + if (ret) { 490 + DRM_ERROR("gpio_direction_output failed\n"); 491 + goto gpio_error; 492 + } 493 + 494 + gpio_get_value(128); 495 + 496 + gpio_error: 497 + if (gpio_is_valid(gpio)) 498 + gpio_free(gpio); 499 + 500 + return ret; 501 + } 502 + 503 + /* 504 + * MIPI output init 505 + * @dev drm device 506 + * @pipe pipe number. 0 or 2 507 + * @config 508 + * 509 + * Do the initialization of a MIPI output, including create DRM mode objects 510 + * initialization of DSI output on @pipe 511 + */ 512 + void mdfld_dsi_output_init(struct drm_device *dev, 513 + int pipe, 514 + struct mdfld_dsi_config *config, 515 + const struct panel_funcs *p_vid_funcs) 516 + { 517 + struct mdfld_dsi_config *dsi_config; 518 + struct mdfld_dsi_connector *dsi_connector; 519 + struct drm_connector *connector; 520 + struct mdfld_dsi_encoder *encoder; 521 + struct drm_psb_private *dev_priv = dev->dev_private; 522 + struct panel_info dsi_panel_info; 523 + u32 width_mm, height_mm; 524 + 525 + dev_dbg(dev->dev, "init DSI output on pipe %d\n", pipe); 526 + 527 + if (!dev || ((pipe != 0) && (pipe != 2))) { 528 + DRM_ERROR("Invalid parameter\n"); 529 + return; 530 + } 531 + 532 + /*create a new connetor*/ 533 + dsi_connector = kzalloc(sizeof(struct mdfld_dsi_connector), GFP_KERNEL); 534 + if (!dsi_connector) { 535 + DRM_ERROR("No memory"); 536 + return; 537 + } 538 + 539 + dsi_connector->pipe = pipe; 540 + 541 + /*set DSI config*/ 542 + if (config) 543 + dsi_config = config; 544 + else { 545 + dsi_config = kzalloc(sizeof(struct mdfld_dsi_config), 546 + GFP_KERNEL); 547 + if (!dsi_config) { 548 + DRM_ERROR("cannot allocate memory for DSI config\n"); 549 + goto dsi_init_err0; 550 + } 551 + mdfld_dsi_get_default_config(dev, dsi_config, pipe); 552 + } 553 + 554 + dsi_connector->private = dsi_config; 555 + 556 + dsi_config->changed = 1; 557 + dsi_config->dev = dev; 558 + 559 + dsi_config->fixed_mode = p_vid_funcs->get_config_mode(dev); 560 + if (p_vid_funcs->get_panel_info(dev, pipe, &dsi_panel_info)) 561 + goto dsi_init_err0; 562 + 563 + width_mm = dsi_panel_info.width_mm; 564 + height_mm = dsi_panel_info.height_mm; 565 + 566 + dsi_config->mode = dsi_config->fixed_mode; 567 + dsi_config->connector = dsi_connector; 568 + 569 + if (!dsi_config->fixed_mode) { 570 + DRM_ERROR("No pannel fixed mode was found\n"); 571 + goto dsi_init_err0; 572 + } 573 + 574 + if (pipe && dev_priv->dsi_configs[0]) { 575 + dsi_config->dvr_ic_inited = 0; 576 + dev_priv->dsi_configs[1] = dsi_config; 577 + } else if (pipe == 0) { 578 + dsi_config->dvr_ic_inited = 1; 579 + dev_priv->dsi_configs[0] = dsi_config; 580 + } else { 581 + DRM_ERROR("Trying to init MIPI1 before MIPI0\n"); 582 + goto dsi_init_err0; 583 + } 584 + 585 + 586 + connector = &dsi_connector->base.base; 587 + drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs, 588 + DRM_MODE_CONNECTOR_LVDS); 589 + drm_connector_helper_add(connector, &mdfld_dsi_connector_helper_funcs); 590 + 591 + connector->display_info.subpixel_order = SubPixelHorizontalRGB; 592 + connector->display_info.width_mm = width_mm; 593 + connector->display_info.height_mm = height_mm; 594 + connector->interlace_allowed = false; 595 + connector->doublescan_allowed = false; 596 + 597 + /*attach properties*/ 598 + drm_connector_attach_property(connector, 599 + dev->mode_config.scaling_mode_property, 600 + DRM_MODE_SCALE_FULLSCREEN); 601 + drm_connector_attach_property(connector, 602 + dev_priv->backlight_property, 603 + MDFLD_DSI_BRIGHTNESS_MAX_LEVEL); 604 + 605 + /*init DSI package sender on this output*/ 606 + if (mdfld_dsi_pkg_sender_init(dsi_connector, pipe)) { 607 + DRM_ERROR("Package Sender initialization failed on pipe %d\n", 608 + pipe); 609 + goto dsi_init_err0; 610 + } 611 + 612 + encoder = mdfld_dsi_dpi_init(dev, dsi_connector, p_vid_funcs); 613 + if (!encoder) { 614 + DRM_ERROR("Create DPI encoder failed\n"); 615 + goto dsi_init_err1; 616 + } 617 + encoder->private = dsi_config; 618 + dsi_config->encoder = encoder; 619 + encoder->base.type = (pipe == 0) ? INTEL_OUTPUT_MIPI : 620 + INTEL_OUTPUT_MIPI2; 621 + drm_sysfs_connector_add(connector); 622 + return; 623 + 624 + /*TODO: add code to destroy outputs on error*/ 625 + dsi_init_err1: 626 + /*destroy sender*/ 627 + mdfld_dsi_pkg_sender_destroy(dsi_connector->pkg_sender); 628 + 629 + drm_connector_cleanup(connector); 630 + 631 + kfree(dsi_config->fixed_mode); 632 + kfree(dsi_config); 633 + dsi_init_err0: 634 + kfree(dsi_connector); 635 + }
+389
drivers/gpu/drm/gma500/mdfld_dsi_output.h
··· 1 + /* 2 + * Copyright © 2010 Intel Corporation 3 + * 4 + * Permission is hereby granted, free of charge, to any person obtaining a 5 + * copy of this software and associated documentation files (the "Software"), 6 + * to deal in the Software without restriction, including without limitation 7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 + * and/or sell copies of the Software, and to permit persons to whom the 9 + * Software is furnished to do so, subject to the following conditions: 10 + * 11 + * The above copyright notice and this permission notice (including the next 12 + * paragraph) shall be included in all copies or substantial portions of the 13 + * Software. 14 + * 15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 + * DEALINGS IN THE SOFTWARE. 22 + * 23 + * Authors: 24 + * jim liu <jim.liu@intel.com> 25 + * Jackie Li<yaodong.li@intel.com> 26 + */ 27 + 28 + #ifndef __MDFLD_DSI_OUTPUT_H__ 29 + #define __MDFLD_DSI_OUTPUT_H__ 30 + 31 + #include <linux/backlight.h> 32 + #include <linux/version.h> 33 + #include <drm/drmP.h> 34 + #include <drm/drm.h> 35 + #include <drm/drm_crtc.h> 36 + #include <drm/drm_edid.h> 37 + 38 + #include "psb_drv.h" 39 + #include "psb_intel_drv.h" 40 + #include "psb_intel_reg.h" 41 + #include "mdfld_output.h" 42 + 43 + #include <asm/mrst.h> 44 + 45 + #define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) 46 + #define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) 47 + #define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end)) 48 + #define FLD_MOD(orig, val, start, end) \ 49 + (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end)) 50 + 51 + #define REG_FLD_MOD(reg, val, start, end) \ 52 + REG_WRITE(reg, FLD_MOD(REG_READ(reg), val, start, end)) 53 + 54 + static inline int REGISTER_FLD_WAIT(struct drm_device *dev, u32 reg, 55 + u32 val, int start, int end) 56 + { 57 + int t = 100000; 58 + 59 + while (FLD_GET(REG_READ(reg), start, end) != val) { 60 + if (--t == 0) 61 + return 1; 62 + } 63 + 64 + return 0; 65 + } 66 + 67 + #define REG_FLD_WAIT(reg, val, start, end) \ 68 + REGISTER_FLD_WAIT(dev, reg, val, start, end) 69 + 70 + #define REG_BIT_WAIT(reg, val, bitnum) \ 71 + REGISTER_FLD_WAIT(dev, reg, val, bitnum, bitnum) 72 + 73 + #define MDFLD_DSI_BRIGHTNESS_MAX_LEVEL 100 74 + 75 + #ifdef DEBUG 76 + #define CHECK_PIPE(pipe) ({ \ 77 + const typeof(pipe) __pipe = (pipe); \ 78 + BUG_ON(__pipe != 0 && __pipe != 2); \ 79 + __pipe; }) 80 + #else 81 + #define CHECK_PIPE(pipe) (pipe) 82 + #endif 83 + 84 + /* 85 + * Actual MIPIA->MIPIC reg offset is 0x800, value 0x400 is valid for 0 and 2 86 + */ 87 + #define REG_OFFSET(pipe) (CHECK_PIPE(pipe) * 0x400) 88 + 89 + /* mdfld DSI controller registers */ 90 + #define MIPI_DEVICE_READY_REG(pipe) (0xb000 + REG_OFFSET(pipe)) 91 + #define MIPI_INTR_STAT_REG(pipe) (0xb004 + REG_OFFSET(pipe)) 92 + #define MIPI_INTR_EN_REG(pipe) (0xb008 + REG_OFFSET(pipe)) 93 + #define MIPI_DSI_FUNC_PRG_REG(pipe) (0xb00c + REG_OFFSET(pipe)) 94 + #define MIPI_HS_TX_TIMEOUT_REG(pipe) (0xb010 + REG_OFFSET(pipe)) 95 + #define MIPI_LP_RX_TIMEOUT_REG(pipe) (0xb014 + REG_OFFSET(pipe)) 96 + #define MIPI_TURN_AROUND_TIMEOUT_REG(pipe) (0xb018 + REG_OFFSET(pipe)) 97 + #define MIPI_DEVICE_RESET_TIMER_REG(pipe) (0xb01c + REG_OFFSET(pipe)) 98 + #define MIPI_DPI_RESOLUTION_REG(pipe) (0xb020 + REG_OFFSET(pipe)) 99 + #define MIPI_DBI_FIFO_THROTTLE_REG(pipe) (0xb024 + REG_OFFSET(pipe)) 100 + #define MIPI_HSYNC_COUNT_REG(pipe) (0xb028 + REG_OFFSET(pipe)) 101 + #define MIPI_HBP_COUNT_REG(pipe) (0xb02c + REG_OFFSET(pipe)) 102 + #define MIPI_HFP_COUNT_REG(pipe) (0xb030 + REG_OFFSET(pipe)) 103 + #define MIPI_HACTIVE_COUNT_REG(pipe) (0xb034 + REG_OFFSET(pipe)) 104 + #define MIPI_VSYNC_COUNT_REG(pipe) (0xb038 + REG_OFFSET(pipe)) 105 + #define MIPI_VBP_COUNT_REG(pipe) (0xb03c + REG_OFFSET(pipe)) 106 + #define MIPI_VFP_COUNT_REG(pipe) (0xb040 + REG_OFFSET(pipe)) 107 + #define MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe) (0xb044 + REG_OFFSET(pipe)) 108 + #define MIPI_DPI_CONTROL_REG(pipe) (0xb048 + REG_OFFSET(pipe)) 109 + #define MIPI_DPI_DATA_REG(pipe) (0xb04c + REG_OFFSET(pipe)) 110 + #define MIPI_INIT_COUNT_REG(pipe) (0xb050 + REG_OFFSET(pipe)) 111 + #define MIPI_MAX_RETURN_PACK_SIZE_REG(pipe) (0xb054 + REG_OFFSET(pipe)) 112 + #define MIPI_VIDEO_MODE_FORMAT_REG(pipe) (0xb058 + REG_OFFSET(pipe)) 113 + #define MIPI_EOT_DISABLE_REG(pipe) (0xb05c + REG_OFFSET(pipe)) 114 + #define MIPI_LP_BYTECLK_REG(pipe) (0xb060 + REG_OFFSET(pipe)) 115 + #define MIPI_LP_GEN_DATA_REG(pipe) (0xb064 + REG_OFFSET(pipe)) 116 + #define MIPI_HS_GEN_DATA_REG(pipe) (0xb068 + REG_OFFSET(pipe)) 117 + #define MIPI_LP_GEN_CTRL_REG(pipe) (0xb06c + REG_OFFSET(pipe)) 118 + #define MIPI_HS_GEN_CTRL_REG(pipe) (0xb070 + REG_OFFSET(pipe)) 119 + #define MIPI_GEN_FIFO_STAT_REG(pipe) (0xb074 + REG_OFFSET(pipe)) 120 + #define MIPI_HS_LS_DBI_ENABLE_REG(pipe) (0xb078 + REG_OFFSET(pipe)) 121 + #define MIPI_DPHY_PARAM_REG(pipe) (0xb080 + REG_OFFSET(pipe)) 122 + #define MIPI_DBI_BW_CTRL_REG(pipe) (0xb084 + REG_OFFSET(pipe)) 123 + #define MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe) (0xb088 + REG_OFFSET(pipe)) 124 + 125 + #define MIPI_CTRL_REG(pipe) (0xb104 + REG_OFFSET(pipe)) 126 + #define MIPI_DATA_ADD_REG(pipe) (0xb108 + REG_OFFSET(pipe)) 127 + #define MIPI_DATA_LEN_REG(pipe) (0xb10c + REG_OFFSET(pipe)) 128 + #define MIPI_CMD_ADD_REG(pipe) (0xb110 + REG_OFFSET(pipe)) 129 + #define MIPI_CMD_LEN_REG(pipe) (0xb114 + REG_OFFSET(pipe)) 130 + 131 + /* non-uniform reg offset */ 132 + #define MIPI_PORT_CONTROL(pipe) (CHECK_PIPE(pipe) ? MIPI_C : MIPI) 133 + 134 + #define DSI_DEVICE_READY (0x1) 135 + #define DSI_POWER_STATE_ULPS_ENTER (0x2 << 1) 136 + #define DSI_POWER_STATE_ULPS_EXIT (0x1 << 1) 137 + #define DSI_POWER_STATE_ULPS_OFFSET (0x1) 138 + 139 + 140 + #define DSI_ONE_DATA_LANE (0x1) 141 + #define DSI_TWO_DATA_LANE (0x2) 142 + #define DSI_THREE_DATA_LANE (0X3) 143 + #define DSI_FOUR_DATA_LANE (0x4) 144 + #define DSI_DPI_VIRT_CHANNEL_OFFSET (0x3) 145 + #define DSI_DBI_VIRT_CHANNEL_OFFSET (0x5) 146 + #define DSI_DPI_COLOR_FORMAT_RGB565 (0x01 << 7) 147 + #define DSI_DPI_COLOR_FORMAT_RGB666 (0x02 << 7) 148 + #define DSI_DPI_COLOR_FORMAT_RGB666_UNPACK (0x03 << 7) 149 + #define DSI_DPI_COLOR_FORMAT_RGB888 (0x04 << 7) 150 + #define DSI_DBI_COLOR_FORMAT_OPTION2 (0x05 << 13) 151 + 152 + #define DSI_INTR_STATE_RXSOTERROR BIT(0) 153 + 154 + #define DSI_INTR_STATE_SPL_PKG_SENT BIT(30) 155 + #define DSI_INTR_STATE_TE BIT(31) 156 + 157 + #define DSI_HS_TX_TIMEOUT_MASK (0xffffff) 158 + 159 + #define DSI_LP_RX_TIMEOUT_MASK (0xffffff) 160 + 161 + #define DSI_TURN_AROUND_TIMEOUT_MASK (0x3f) 162 + 163 + #define DSI_RESET_TIMER_MASK (0xffff) 164 + 165 + #define DSI_DBI_FIFO_WM_HALF (0x0) 166 + #define DSI_DBI_FIFO_WM_QUARTER (0x1) 167 + #define DSI_DBI_FIFO_WM_LOW (0x2) 168 + 169 + #define DSI_DPI_TIMING_MASK (0xffff) 170 + 171 + #define DSI_INIT_TIMER_MASK (0xffff) 172 + 173 + #define DSI_DBI_RETURN_PACK_SIZE_MASK (0x3ff) 174 + 175 + #define DSI_LP_BYTECLK_MASK (0x0ffff) 176 + 177 + #define DSI_HS_CTRL_GEN_SHORT_W0 (0x03) 178 + #define DSI_HS_CTRL_GEN_SHORT_W1 (0x13) 179 + #define DSI_HS_CTRL_GEN_SHORT_W2 (0x23) 180 + #define DSI_HS_CTRL_GEN_R0 (0x04) 181 + #define DSI_HS_CTRL_GEN_R1 (0x14) 182 + #define DSI_HS_CTRL_GEN_R2 (0x24) 183 + #define DSI_HS_CTRL_GEN_LONG_W (0x29) 184 + #define DSI_HS_CTRL_MCS_SHORT_W0 (0x05) 185 + #define DSI_HS_CTRL_MCS_SHORT_W1 (0x15) 186 + #define DSI_HS_CTRL_MCS_R0 (0x06) 187 + #define DSI_HS_CTRL_MCS_LONG_W (0x39) 188 + #define DSI_HS_CTRL_VC_OFFSET (0x06) 189 + #define DSI_HS_CTRL_WC_OFFSET (0x08) 190 + 191 + #define DSI_FIFO_GEN_HS_DATA_FULL BIT(0) 192 + #define DSI_FIFO_GEN_HS_DATA_HALF_EMPTY BIT(1) 193 + #define DSI_FIFO_GEN_HS_DATA_EMPTY BIT(2) 194 + #define DSI_FIFO_GEN_LP_DATA_FULL BIT(8) 195 + #define DSI_FIFO_GEN_LP_DATA_HALF_EMPTY BIT(9) 196 + #define DSI_FIFO_GEN_LP_DATA_EMPTY BIT(10) 197 + #define DSI_FIFO_GEN_HS_CTRL_FULL BIT(16) 198 + #define DSI_FIFO_GEN_HS_CTRL_HALF_EMPTY BIT(17) 199 + #define DSI_FIFO_GEN_HS_CTRL_EMPTY BIT(18) 200 + #define DSI_FIFO_GEN_LP_CTRL_FULL BIT(24) 201 + #define DSI_FIFO_GEN_LP_CTRL_HALF_EMPTY BIT(25) 202 + #define DSI_FIFO_GEN_LP_CTRL_EMPTY BIT(26) 203 + #define DSI_FIFO_DBI_EMPTY BIT(27) 204 + #define DSI_FIFO_DPI_EMPTY BIT(28) 205 + 206 + #define DSI_DBI_HS_LP_SWITCH_MASK (0x1) 207 + 208 + #define DSI_HS_LP_SWITCH_COUNTER_OFFSET (0x0) 209 + #define DSI_LP_HS_SWITCH_COUNTER_OFFSET (0x16) 210 + 211 + #define DSI_DPI_CTRL_HS_SHUTDOWN (0x00000001) 212 + #define DSI_DPI_CTRL_HS_TURN_ON (0x00000002) 213 + 214 + /*dsi power modes*/ 215 + #define DSI_POWER_MODE_DISPLAY_ON BIT(2) 216 + #define DSI_POWER_MODE_NORMAL_ON BIT(3) 217 + #define DSI_POWER_MODE_SLEEP_OUT BIT(4) 218 + #define DSI_POWER_MODE_PARTIAL_ON BIT(5) 219 + #define DSI_POWER_MODE_IDLE_ON BIT(6) 220 + 221 + enum { 222 + MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE = 1, 223 + MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS = 2, 224 + MDFLD_DSI_VIDEO_BURST_MODE = 3, 225 + }; 226 + 227 + #define DSI_DPI_COMPLETE_LAST_LINE BIT(2) 228 + #define DSI_DPI_DISABLE_BTA BIT(3) 229 + 230 + struct mdfld_dsi_connector_state { 231 + u32 mipi_ctrl_reg; 232 + }; 233 + 234 + struct mdfld_dsi_encoder_state { 235 + 236 + }; 237 + 238 + struct mdfld_dsi_connector { 239 + struct psb_intel_connector base; 240 + 241 + int pipe; 242 + void *private; 243 + void *pkg_sender; 244 + 245 + /* Connection status */ 246 + enum drm_connector_status status; 247 + }; 248 + 249 + struct mdfld_dsi_encoder { 250 + struct psb_intel_encoder base; 251 + void *private; 252 + }; 253 + 254 + /* 255 + * DSI config, consists of one DSI connector, two DSI encoders. 256 + * DRM will pick up on DSI encoder basing on differents configs. 257 + */ 258 + struct mdfld_dsi_config { 259 + struct drm_device *dev; 260 + struct drm_display_mode *fixed_mode; 261 + struct drm_display_mode *mode; 262 + 263 + struct mdfld_dsi_connector *connector; 264 + struct mdfld_dsi_encoder *encoder; 265 + 266 + int changed; 267 + 268 + int bpp; 269 + int lane_count; 270 + /*Virtual channel number for this encoder*/ 271 + int channel_num; 272 + /*video mode configure*/ 273 + int video_mode; 274 + 275 + int dvr_ic_inited; 276 + }; 277 + 278 + static inline struct mdfld_dsi_connector *mdfld_dsi_connector( 279 + struct drm_connector *connector) 280 + { 281 + struct psb_intel_connector *psb_connector; 282 + 283 + psb_connector = to_psb_intel_connector(connector); 284 + 285 + return container_of(psb_connector, struct mdfld_dsi_connector, base); 286 + } 287 + 288 + static inline struct mdfld_dsi_encoder *mdfld_dsi_encoder( 289 + struct drm_encoder *encoder) 290 + { 291 + struct psb_intel_encoder *psb_encoder; 292 + 293 + psb_encoder = to_psb_intel_encoder(encoder); 294 + 295 + return container_of(psb_encoder, struct mdfld_dsi_encoder, base); 296 + } 297 + 298 + static inline struct mdfld_dsi_config * 299 + mdfld_dsi_get_config(struct mdfld_dsi_connector *connector) 300 + { 301 + if (!connector) 302 + return NULL; 303 + return (struct mdfld_dsi_config *)connector->private; 304 + } 305 + 306 + static inline void *mdfld_dsi_get_pkg_sender(struct mdfld_dsi_config *config) 307 + { 308 + struct mdfld_dsi_connector *dsi_connector; 309 + 310 + if (!config) 311 + return NULL; 312 + 313 + dsi_connector = config->connector; 314 + 315 + if (!dsi_connector) 316 + return NULL; 317 + 318 + return dsi_connector->pkg_sender; 319 + } 320 + 321 + static inline struct mdfld_dsi_config * 322 + mdfld_dsi_encoder_get_config(struct mdfld_dsi_encoder *encoder) 323 + { 324 + if (!encoder) 325 + return NULL; 326 + return (struct mdfld_dsi_config *)encoder->private; 327 + } 328 + 329 + static inline struct mdfld_dsi_connector * 330 + mdfld_dsi_encoder_get_connector(struct mdfld_dsi_encoder *encoder) 331 + { 332 + struct mdfld_dsi_config *config; 333 + 334 + if (!encoder) 335 + return NULL; 336 + 337 + config = mdfld_dsi_encoder_get_config(encoder); 338 + if (!config) 339 + return NULL; 340 + 341 + return config->connector; 342 + } 343 + 344 + static inline void *mdfld_dsi_encoder_get_pkg_sender( 345 + struct mdfld_dsi_encoder *encoder) 346 + { 347 + struct mdfld_dsi_config *dsi_config; 348 + 349 + dsi_config = mdfld_dsi_encoder_get_config(encoder); 350 + if (!dsi_config) 351 + return NULL; 352 + 353 + return mdfld_dsi_get_pkg_sender(dsi_config); 354 + } 355 + 356 + static inline int mdfld_dsi_encoder_get_pipe(struct mdfld_dsi_encoder *encoder) 357 + { 358 + struct mdfld_dsi_connector *connector; 359 + 360 + if (!encoder) 361 + return -1; 362 + 363 + connector = mdfld_dsi_encoder_get_connector(encoder); 364 + if (!connector) 365 + return -1; 366 + return connector->pipe; 367 + } 368 + 369 + /* Export functions */ 370 + extern void mdfld_dsi_gen_fifo_ready(struct drm_device *dev, 371 + u32 gen_fifo_stat_reg, u32 fifo_stat); 372 + extern void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, 373 + int pipe); 374 + extern void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe, 375 + int level); 376 + extern void mdfld_dsi_output_init(struct drm_device *dev, 377 + int pipe, 378 + struct mdfld_dsi_config *config, 379 + const struct panel_funcs *p_vid_funcs); 380 + extern void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config, 381 + int pipe); 382 + 383 + extern int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, 384 + u32 *mode, bool hs); 385 + extern int mdfld_dsi_get_diagnostic_result(struct mdfld_dsi_config *dsi_config, 386 + u32 *result, bool hs); 387 + extern int mdfld_dsi_panel_reset(int pipe); 388 + 389 + #endif /*__MDFLD_DSI_OUTPUT_H__*/
+694
drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c
··· 1 + /* 2 + * Copyright © 2010 Intel Corporation 3 + * 4 + * Permission is hereby granted, free of charge, to any person obtaining a 5 + * copy of this software and associated documentation files (the "Software"), 6 + * to deal in the Software without restriction, including without limitation 7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 + * and/or sell copies of the Software, and to permit persons to whom the 9 + * Software is furnished to do so, subject to the following conditions: 10 + * 11 + * The above copyright notice and this permission notice (including the next 12 + * paragraph) shall be included in all copies or substantial portions of the 13 + * Software. 14 + * 15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 + * DEALINGS IN THE SOFTWARE. 22 + * 23 + * Authors: 24 + * Jackie Li<yaodong.li@intel.com> 25 + */ 26 + 27 + #include <linux/freezer.h> 28 + 29 + #include "mdfld_dsi_output.h" 30 + #include "mdfld_dsi_pkg_sender.h" 31 + #include "mdfld_dsi_dpi.h" 32 + 33 + #define MDFLD_DSI_READ_MAX_COUNT 5000 34 + 35 + enum data_type { 36 + DSI_DT_GENERIC_SHORT_WRITE_0 = 0x03, 37 + DSI_DT_GENERIC_SHORT_WRITE_1 = 0x13, 38 + DSI_DT_GENERIC_SHORT_WRITE_2 = 0x23, 39 + DSI_DT_GENERIC_READ_0 = 0x04, 40 + DSI_DT_GENERIC_READ_1 = 0x14, 41 + DSI_DT_GENERIC_READ_2 = 0x24, 42 + DSI_DT_GENERIC_LONG_WRITE = 0x29, 43 + DSI_DT_DCS_SHORT_WRITE_0 = 0x05, 44 + DSI_DT_DCS_SHORT_WRITE_1 = 0x15, 45 + DSI_DT_DCS_READ = 0x06, 46 + DSI_DT_DCS_LONG_WRITE = 0x39, 47 + }; 48 + 49 + enum { 50 + MDFLD_DSI_PANEL_MODE_SLEEP = 0x1, 51 + }; 52 + 53 + enum { 54 + MDFLD_DSI_PKG_SENDER_FREE = 0x0, 55 + MDFLD_DSI_PKG_SENDER_BUSY = 0x1, 56 + }; 57 + 58 + static const char *const dsi_errors[] = { 59 + "RX SOT Error", 60 + "RX SOT Sync Error", 61 + "RX EOT Sync Error", 62 + "RX Escape Mode Entry Error", 63 + "RX LP TX Sync Error", 64 + "RX HS Receive Timeout Error", 65 + "RX False Control Error", 66 + "RX ECC Single Bit Error", 67 + "RX ECC Multibit Error", 68 + "RX Checksum Error", 69 + "RX DSI Data Type Not Recognised", 70 + "RX DSI VC ID Invalid", 71 + "TX False Control Error", 72 + "TX ECC Single Bit Error", 73 + "TX ECC Multibit Error", 74 + "TX Checksum Error", 75 + "TX DSI Data Type Not Recognised", 76 + "TX DSI VC ID invalid", 77 + "High Contention", 78 + "Low contention", 79 + "DPI FIFO Under run", 80 + "HS TX Timeout", 81 + "LP RX Timeout", 82 + "Turn Around ACK Timeout", 83 + "ACK With No Error", 84 + "RX Invalid TX Length", 85 + "RX Prot Violation", 86 + "HS Generic Write FIFO Full", 87 + "LP Generic Write FIFO Full", 88 + "Generic Read Data Avail" 89 + "Special Packet Sent", 90 + "Tearing Effect", 91 + }; 92 + 93 + static inline int wait_for_gen_fifo_empty(struct mdfld_dsi_pkg_sender *sender, 94 + u32 mask) 95 + { 96 + struct drm_device *dev = sender->dev; 97 + u32 gen_fifo_stat_reg = sender->mipi_gen_fifo_stat_reg; 98 + int retry = 0xffff; 99 + 100 + while (retry--) { 101 + if ((mask & REG_READ(gen_fifo_stat_reg)) == mask) 102 + return 0; 103 + udelay(100); 104 + } 105 + DRM_ERROR("fifo is NOT empty 0x%08x\n", REG_READ(gen_fifo_stat_reg)); 106 + return -EIO; 107 + } 108 + 109 + static int wait_for_all_fifos_empty(struct mdfld_dsi_pkg_sender *sender) 110 + { 111 + return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(10) | BIT(18) | 112 + BIT(26) | BIT(27) | BIT(28))); 113 + } 114 + 115 + static int wait_for_lp_fifos_empty(struct mdfld_dsi_pkg_sender *sender) 116 + { 117 + return wait_for_gen_fifo_empty(sender, (BIT(10) | BIT(26))); 118 + } 119 + 120 + static int wait_for_hs_fifos_empty(struct mdfld_dsi_pkg_sender *sender) 121 + { 122 + return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(18))); 123 + } 124 + 125 + static int handle_dsi_error(struct mdfld_dsi_pkg_sender *sender, u32 mask) 126 + { 127 + u32 intr_stat_reg = sender->mipi_intr_stat_reg; 128 + struct drm_device *dev = sender->dev; 129 + 130 + dev_dbg(sender->dev->dev, "Handling error 0x%08x\n", mask); 131 + 132 + switch (mask) { 133 + case BIT(0): 134 + case BIT(1): 135 + case BIT(2): 136 + case BIT(3): 137 + case BIT(4): 138 + case BIT(5): 139 + case BIT(6): 140 + case BIT(7): 141 + case BIT(8): 142 + case BIT(9): 143 + case BIT(10): 144 + case BIT(11): 145 + case BIT(12): 146 + case BIT(13): 147 + dev_dbg(sender->dev->dev, "No Action required\n"); 148 + break; 149 + case BIT(14): 150 + /*wait for all fifo empty*/ 151 + /*wait_for_all_fifos_empty(sender)*/; 152 + break; 153 + case BIT(15): 154 + dev_dbg(sender->dev->dev, "No Action required\n"); 155 + break; 156 + case BIT(16): 157 + break; 158 + case BIT(17): 159 + break; 160 + case BIT(18): 161 + case BIT(19): 162 + dev_dbg(sender->dev->dev, "High/Low contention detected\n"); 163 + /*wait for contention recovery time*/ 164 + /*mdelay(10);*/ 165 + /*wait for all fifo empty*/ 166 + if (0) 167 + wait_for_all_fifos_empty(sender); 168 + break; 169 + case BIT(20): 170 + dev_dbg(sender->dev->dev, "No Action required\n"); 171 + break; 172 + case BIT(21): 173 + /*wait for all fifo empty*/ 174 + /*wait_for_all_fifos_empty(sender);*/ 175 + break; 176 + case BIT(22): 177 + break; 178 + case BIT(23): 179 + case BIT(24): 180 + case BIT(25): 181 + case BIT(26): 182 + case BIT(27): 183 + dev_dbg(sender->dev->dev, "HS Gen fifo full\n"); 184 + REG_WRITE(intr_stat_reg, mask); 185 + wait_for_hs_fifos_empty(sender); 186 + break; 187 + case BIT(28): 188 + dev_dbg(sender->dev->dev, "LP Gen fifo full\n"); 189 + REG_WRITE(intr_stat_reg, mask); 190 + wait_for_lp_fifos_empty(sender); 191 + break; 192 + case BIT(29): 193 + case BIT(30): 194 + case BIT(31): 195 + dev_dbg(sender->dev->dev, "No Action required\n"); 196 + break; 197 + } 198 + 199 + if (mask & REG_READ(intr_stat_reg)) 200 + dev_dbg(sender->dev->dev, 201 + "Cannot clean interrupt 0x%08x\n", mask); 202 + return 0; 203 + } 204 + 205 + static int dsi_error_handler(struct mdfld_dsi_pkg_sender *sender) 206 + { 207 + struct drm_device *dev = sender->dev; 208 + u32 intr_stat_reg = sender->mipi_intr_stat_reg; 209 + u32 mask; 210 + u32 intr_stat; 211 + int i; 212 + int err = 0; 213 + 214 + intr_stat = REG_READ(intr_stat_reg); 215 + 216 + for (i = 0; i < 32; i++) { 217 + mask = (0x00000001UL) << i; 218 + if (intr_stat & mask) { 219 + dev_dbg(sender->dev->dev, "[DSI]: %s\n", dsi_errors[i]); 220 + err = handle_dsi_error(sender, mask); 221 + if (err) 222 + DRM_ERROR("Cannot handle error\n"); 223 + } 224 + } 225 + return err; 226 + } 227 + 228 + static int send_short_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type, 229 + u8 cmd, u8 param, bool hs) 230 + { 231 + struct drm_device *dev = sender->dev; 232 + u32 ctrl_reg; 233 + u32 val; 234 + u8 virtual_channel = 0; 235 + 236 + if (hs) { 237 + ctrl_reg = sender->mipi_hs_gen_ctrl_reg; 238 + 239 + /* FIXME: wait_for_hs_fifos_empty(sender); */ 240 + } else { 241 + ctrl_reg = sender->mipi_lp_gen_ctrl_reg; 242 + 243 + /* FIXME: wait_for_lp_fifos_empty(sender); */ 244 + } 245 + 246 + val = FLD_VAL(param, 23, 16) | FLD_VAL(cmd, 15, 8) | 247 + FLD_VAL(virtual_channel, 7, 6) | FLD_VAL(data_type, 5, 0); 248 + 249 + REG_WRITE(ctrl_reg, val); 250 + 251 + return 0; 252 + } 253 + 254 + static int send_long_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type, 255 + u8 *data, int len, bool hs) 256 + { 257 + struct drm_device *dev = sender->dev; 258 + u32 ctrl_reg; 259 + u32 data_reg; 260 + u32 val; 261 + u8 *p; 262 + u8 b1, b2, b3, b4; 263 + u8 virtual_channel = 0; 264 + int i; 265 + 266 + if (hs) { 267 + ctrl_reg = sender->mipi_hs_gen_ctrl_reg; 268 + data_reg = sender->mipi_hs_gen_data_reg; 269 + 270 + /* FIXME: wait_for_hs_fifos_empty(sender); */ 271 + } else { 272 + ctrl_reg = sender->mipi_lp_gen_ctrl_reg; 273 + data_reg = sender->mipi_lp_gen_data_reg; 274 + 275 + /* FIXME: wait_for_lp_fifos_empty(sender); */ 276 + } 277 + 278 + p = data; 279 + for (i = 0; i < len / 4; i++) { 280 + b1 = *p++; 281 + b2 = *p++; 282 + b3 = *p++; 283 + b4 = *p++; 284 + 285 + REG_WRITE(data_reg, b4 << 24 | b3 << 16 | b2 << 8 | b1); 286 + } 287 + 288 + i = len % 4; 289 + if (i) { 290 + b1 = 0; b2 = 0; b3 = 0; 291 + 292 + switch (i) { 293 + case 3: 294 + b1 = *p++; 295 + b2 = *p++; 296 + b3 = *p++; 297 + break; 298 + case 2: 299 + b1 = *p++; 300 + b2 = *p++; 301 + break; 302 + case 1: 303 + b1 = *p++; 304 + break; 305 + } 306 + 307 + REG_WRITE(data_reg, b3 << 16 | b2 << 8 | b1); 308 + } 309 + 310 + val = FLD_VAL(len, 23, 8) | FLD_VAL(virtual_channel, 7, 6) | 311 + FLD_VAL(data_type, 5, 0); 312 + 313 + REG_WRITE(ctrl_reg, val); 314 + 315 + return 0; 316 + } 317 + 318 + static int send_pkg_prepare(struct mdfld_dsi_pkg_sender *sender, u8 data_type, 319 + u8 *data, u16 len) 320 + { 321 + u8 cmd; 322 + 323 + switch (data_type) { 324 + case DSI_DT_DCS_SHORT_WRITE_0: 325 + case DSI_DT_DCS_SHORT_WRITE_1: 326 + case DSI_DT_DCS_LONG_WRITE: 327 + cmd = *data; 328 + break; 329 + default: 330 + return 0; 331 + } 332 + 333 + /*this prevents other package sending while doing msleep*/ 334 + sender->status = MDFLD_DSI_PKG_SENDER_BUSY; 335 + 336 + /*wait for 120 milliseconds in case exit_sleep_mode just be sent*/ 337 + if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) { 338 + /*TODO: replace it with msleep later*/ 339 + mdelay(120); 340 + } 341 + 342 + if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) { 343 + /*TODO: replace it with msleep later*/ 344 + mdelay(120); 345 + } 346 + return 0; 347 + } 348 + 349 + static int send_pkg_done(struct mdfld_dsi_pkg_sender *sender, u8 data_type, 350 + u8 *data, u16 len) 351 + { 352 + u8 cmd; 353 + 354 + switch (data_type) { 355 + case DSI_DT_DCS_SHORT_WRITE_0: 356 + case DSI_DT_DCS_SHORT_WRITE_1: 357 + case DSI_DT_DCS_LONG_WRITE: 358 + cmd = *data; 359 + break; 360 + default: 361 + return 0; 362 + } 363 + 364 + /*update panel status*/ 365 + if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) { 366 + sender->panel_mode |= MDFLD_DSI_PANEL_MODE_SLEEP; 367 + /*TODO: replace it with msleep later*/ 368 + mdelay(120); 369 + } else if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) { 370 + sender->panel_mode &= ~MDFLD_DSI_PANEL_MODE_SLEEP; 371 + /*TODO: replace it with msleep later*/ 372 + mdelay(120); 373 + } else if (unlikely(cmd == DCS_SOFT_RESET)) { 374 + /*TODO: replace it with msleep later*/ 375 + mdelay(5); 376 + } 377 + 378 + sender->status = MDFLD_DSI_PKG_SENDER_FREE; 379 + 380 + return 0; 381 + } 382 + 383 + static int send_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type, 384 + u8 *data, u16 len, bool hs) 385 + { 386 + int ret; 387 + 388 + /*handle DSI error*/ 389 + ret = dsi_error_handler(sender); 390 + if (ret) { 391 + DRM_ERROR("Error handling failed\n"); 392 + return -EAGAIN; 393 + } 394 + 395 + /* send pkg */ 396 + if (sender->status == MDFLD_DSI_PKG_SENDER_BUSY) { 397 + DRM_ERROR("sender is busy\n"); 398 + return -EAGAIN; 399 + } 400 + 401 + ret = send_pkg_prepare(sender, data_type, data, len); 402 + if (ret) { 403 + DRM_ERROR("send_pkg_prepare error\n"); 404 + return ret; 405 + } 406 + 407 + switch (data_type) { 408 + case DSI_DT_GENERIC_SHORT_WRITE_0: 409 + case DSI_DT_GENERIC_SHORT_WRITE_1: 410 + case DSI_DT_GENERIC_SHORT_WRITE_2: 411 + case DSI_DT_GENERIC_READ_0: 412 + case DSI_DT_GENERIC_READ_1: 413 + case DSI_DT_GENERIC_READ_2: 414 + case DSI_DT_DCS_SHORT_WRITE_0: 415 + case DSI_DT_DCS_SHORT_WRITE_1: 416 + case DSI_DT_DCS_READ: 417 + ret = send_short_pkg(sender, data_type, data[0], data[1], hs); 418 + break; 419 + case DSI_DT_GENERIC_LONG_WRITE: 420 + case DSI_DT_DCS_LONG_WRITE: 421 + ret = send_long_pkg(sender, data_type, data, len, hs); 422 + break; 423 + } 424 + 425 + send_pkg_done(sender, data_type, data, len); 426 + 427 + /*FIXME: should I query complete and fifo empty here?*/ 428 + 429 + return ret; 430 + } 431 + 432 + int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data, 433 + u32 len, bool hs) 434 + { 435 + unsigned long flags; 436 + 437 + if (!sender || !data || !len) { 438 + DRM_ERROR("Invalid parameters\n"); 439 + return -EINVAL; 440 + } 441 + 442 + spin_lock_irqsave(&sender->lock, flags); 443 + send_pkg(sender, DSI_DT_DCS_LONG_WRITE, data, len, hs); 444 + spin_unlock_irqrestore(&sender->lock, flags); 445 + 446 + return 0; 447 + } 448 + 449 + int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd, 450 + u8 param, u8 param_num, bool hs) 451 + { 452 + u8 data[2]; 453 + unsigned long flags; 454 + u8 data_type; 455 + 456 + if (!sender) { 457 + DRM_ERROR("Invalid parameter\n"); 458 + return -EINVAL; 459 + } 460 + 461 + data[0] = cmd; 462 + 463 + if (param_num) { 464 + data_type = DSI_DT_DCS_SHORT_WRITE_1; 465 + data[1] = param; 466 + } else { 467 + data_type = DSI_DT_DCS_SHORT_WRITE_0; 468 + data[1] = 0; 469 + } 470 + 471 + spin_lock_irqsave(&sender->lock, flags); 472 + send_pkg(sender, data_type, data, sizeof(data), hs); 473 + spin_unlock_irqrestore(&sender->lock, flags); 474 + 475 + return 0; 476 + } 477 + 478 + int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0, 479 + u8 param1, u8 param_num, bool hs) 480 + { 481 + u8 data[2]; 482 + unsigned long flags; 483 + u8 data_type; 484 + 485 + if (!sender || param_num < 0 || param_num > 2) { 486 + DRM_ERROR("Invalid parameter\n"); 487 + return -EINVAL; 488 + } 489 + 490 + switch (param_num) { 491 + case 0: 492 + data_type = DSI_DT_GENERIC_SHORT_WRITE_0; 493 + data[0] = 0; 494 + data[1] = 0; 495 + break; 496 + case 1: 497 + data_type = DSI_DT_GENERIC_SHORT_WRITE_1; 498 + data[0] = param0; 499 + data[1] = 0; 500 + break; 501 + case 2: 502 + data_type = DSI_DT_GENERIC_SHORT_WRITE_2; 503 + data[0] = param0; 504 + data[1] = param1; 505 + break; 506 + } 507 + 508 + spin_lock_irqsave(&sender->lock, flags); 509 + send_pkg(sender, data_type, data, sizeof(data), hs); 510 + spin_unlock_irqrestore(&sender->lock, flags); 511 + 512 + return 0; 513 + } 514 + 515 + int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data, 516 + u32 len, bool hs) 517 + { 518 + unsigned long flags; 519 + 520 + if (!sender || !data || !len) { 521 + DRM_ERROR("Invalid parameters\n"); 522 + return -EINVAL; 523 + } 524 + 525 + spin_lock_irqsave(&sender->lock, flags); 526 + send_pkg(sender, DSI_DT_GENERIC_LONG_WRITE, data, len, hs); 527 + spin_unlock_irqrestore(&sender->lock, flags); 528 + 529 + return 0; 530 + } 531 + 532 + static int __read_panel_data(struct mdfld_dsi_pkg_sender *sender, u8 data_type, 533 + u8 *data, u16 len, u32 *data_out, u16 len_out, bool hs) 534 + { 535 + unsigned long flags; 536 + struct drm_device *dev = sender->dev; 537 + int i; 538 + u32 gen_data_reg; 539 + int retry = MDFLD_DSI_READ_MAX_COUNT; 540 + 541 + if (!sender || !data_out || !len_out) { 542 + DRM_ERROR("Invalid parameters\n"); 543 + return -EINVAL; 544 + } 545 + 546 + /** 547 + * do reading. 548 + * 0) send out generic read request 549 + * 1) polling read data avail interrupt 550 + * 2) read data 551 + */ 552 + spin_lock_irqsave(&sender->lock, flags); 553 + 554 + REG_WRITE(sender->mipi_intr_stat_reg, BIT(29)); 555 + 556 + if ((REG_READ(sender->mipi_intr_stat_reg) & BIT(29))) 557 + DRM_ERROR("Can NOT clean read data valid interrupt\n"); 558 + 559 + /*send out read request*/ 560 + send_pkg(sender, data_type, data, len, hs); 561 + 562 + /*polling read data avail interrupt*/ 563 + while (retry && !(REG_READ(sender->mipi_intr_stat_reg) & BIT(29))) { 564 + udelay(100); 565 + retry--; 566 + } 567 + 568 + if (!retry) { 569 + spin_unlock_irqrestore(&sender->lock, flags); 570 + return -ETIMEDOUT; 571 + } 572 + 573 + REG_WRITE(sender->mipi_intr_stat_reg, BIT(29)); 574 + 575 + /*read data*/ 576 + if (hs) 577 + gen_data_reg = sender->mipi_hs_gen_data_reg; 578 + else 579 + gen_data_reg = sender->mipi_lp_gen_data_reg; 580 + 581 + for (i = 0; i < len_out; i++) 582 + *(data_out + i) = REG_READ(gen_data_reg); 583 + 584 + spin_unlock_irqrestore(&sender->lock, flags); 585 + 586 + return 0; 587 + } 588 + 589 + int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd, 590 + u32 *data, u16 len, bool hs) 591 + { 592 + if (!sender || !data || !len) { 593 + DRM_ERROR("Invalid parameters\n"); 594 + return -EINVAL; 595 + } 596 + 597 + return __read_panel_data(sender, DSI_DT_DCS_READ, &cmd, 1, 598 + data, len, hs); 599 + } 600 + 601 + int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector, 602 + int pipe) 603 + { 604 + struct mdfld_dsi_pkg_sender *pkg_sender; 605 + struct mdfld_dsi_config *dsi_config = 606 + mdfld_dsi_get_config(dsi_connector); 607 + struct drm_device *dev = dsi_config->dev; 608 + u32 mipi_val = 0; 609 + 610 + if (!dsi_connector) { 611 + DRM_ERROR("Invalid parameter\n"); 612 + return -EINVAL; 613 + } 614 + 615 + pkg_sender = dsi_connector->pkg_sender; 616 + 617 + if (!pkg_sender || IS_ERR(pkg_sender)) { 618 + pkg_sender = kzalloc(sizeof(struct mdfld_dsi_pkg_sender), 619 + GFP_KERNEL); 620 + if (!pkg_sender) { 621 + DRM_ERROR("Create DSI pkg sender failed\n"); 622 + return -ENOMEM; 623 + } 624 + dsi_connector->pkg_sender = (void *)pkg_sender; 625 + } 626 + 627 + pkg_sender->dev = dev; 628 + pkg_sender->dsi_connector = dsi_connector; 629 + pkg_sender->pipe = pipe; 630 + pkg_sender->pkg_num = 0; 631 + pkg_sender->panel_mode = 0; 632 + pkg_sender->status = MDFLD_DSI_PKG_SENDER_FREE; 633 + 634 + /*init regs*/ 635 + if (pipe == 0) { 636 + pkg_sender->dpll_reg = MRST_DPLL_A; 637 + pkg_sender->dspcntr_reg = DSPACNTR; 638 + pkg_sender->pipeconf_reg = PIPEACONF; 639 + pkg_sender->dsplinoff_reg = DSPALINOFF; 640 + pkg_sender->dspsurf_reg = DSPASURF; 641 + pkg_sender->pipestat_reg = PIPEASTAT; 642 + } else if (pipe == 2) { 643 + pkg_sender->dpll_reg = MRST_DPLL_A; 644 + pkg_sender->dspcntr_reg = DSPCCNTR; 645 + pkg_sender->pipeconf_reg = PIPECCONF; 646 + pkg_sender->dsplinoff_reg = DSPCLINOFF; 647 + pkg_sender->dspsurf_reg = DSPCSURF; 648 + pkg_sender->pipestat_reg = PIPECSTAT; 649 + } 650 + 651 + pkg_sender->mipi_intr_stat_reg = MIPI_INTR_STAT_REG(pipe); 652 + pkg_sender->mipi_lp_gen_data_reg = MIPI_LP_GEN_DATA_REG(pipe); 653 + pkg_sender->mipi_hs_gen_data_reg = MIPI_HS_GEN_DATA_REG(pipe); 654 + pkg_sender->mipi_lp_gen_ctrl_reg = MIPI_LP_GEN_CTRL_REG(pipe); 655 + pkg_sender->mipi_hs_gen_ctrl_reg = MIPI_HS_GEN_CTRL_REG(pipe); 656 + pkg_sender->mipi_gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe); 657 + pkg_sender->mipi_data_addr_reg = MIPI_DATA_ADD_REG(pipe); 658 + pkg_sender->mipi_data_len_reg = MIPI_DATA_LEN_REG(pipe); 659 + pkg_sender->mipi_cmd_addr_reg = MIPI_CMD_ADD_REG(pipe); 660 + pkg_sender->mipi_cmd_len_reg = MIPI_CMD_LEN_REG(pipe); 661 + 662 + /*init lock*/ 663 + spin_lock_init(&pkg_sender->lock); 664 + 665 + if (mdfld_get_panel_type(dev, pipe) != TC35876X) { 666 + /** 667 + * For video mode, don't enable DPI timing output here, 668 + * will init the DPI timing output during mode setting. 669 + */ 670 + mipi_val = PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX; 671 + 672 + if (pipe == 0) 673 + mipi_val |= 0x2; 674 + 675 + REG_WRITE(MIPI_PORT_CONTROL(pipe), mipi_val); 676 + REG_READ(MIPI_PORT_CONTROL(pipe)); 677 + 678 + /* do dsi controller init */ 679 + mdfld_dsi_controller_init(dsi_config, pipe); 680 + } 681 + 682 + return 0; 683 + } 684 + 685 + void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender) 686 + { 687 + if (!sender || IS_ERR(sender)) 688 + return; 689 + 690 + /*free*/ 691 + kfree(sender); 692 + } 693 + 694 +
+92
drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.h
··· 1 + /* 2 + * Copyright © 2010 Intel Corporation 3 + * 4 + * Permission is hereby granted, free of charge, to any person obtaining a 5 + * copy of this software and associated documentation files (the "Software"), 6 + * to deal in the Software without restriction, including without limitation 7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 + * and/or sell copies of the Software, and to permit persons to whom the 9 + * Software is furnished to do so, subject to the following conditions: 10 + * 11 + * The above copyright notice and this permission notice (including the next 12 + * paragraph) shall be included in all copies or substantial portions of the 13 + * Software. 14 + * 15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 + * DEALINGS IN THE SOFTWARE. 22 + * 23 + * Authors: 24 + * Jackie Li<yaodong.li@intel.com> 25 + */ 26 + #ifndef __MDFLD_DSI_PKG_SENDER_H__ 27 + #define __MDFLD_DSI_PKG_SENDER_H__ 28 + 29 + #include <linux/kthread.h> 30 + 31 + #define MDFLD_MAX_DCS_PARAM 8 32 + 33 + struct mdfld_dsi_pkg_sender { 34 + struct drm_device *dev; 35 + struct mdfld_dsi_connector *dsi_connector; 36 + u32 status; 37 + u32 panel_mode; 38 + 39 + int pipe; 40 + 41 + spinlock_t lock; 42 + 43 + u32 pkg_num; 44 + 45 + /* Registers */ 46 + u32 dpll_reg; 47 + u32 dspcntr_reg; 48 + u32 pipeconf_reg; 49 + u32 pipestat_reg; 50 + u32 dsplinoff_reg; 51 + u32 dspsurf_reg; 52 + 53 + u32 mipi_intr_stat_reg; 54 + u32 mipi_lp_gen_data_reg; 55 + u32 mipi_hs_gen_data_reg; 56 + u32 mipi_lp_gen_ctrl_reg; 57 + u32 mipi_hs_gen_ctrl_reg; 58 + u32 mipi_gen_fifo_stat_reg; 59 + u32 mipi_data_addr_reg; 60 + u32 mipi_data_len_reg; 61 + u32 mipi_cmd_addr_reg; 62 + u32 mipi_cmd_len_reg; 63 + }; 64 + 65 + /* DCS definitions */ 66 + #define DCS_SOFT_RESET 0x01 67 + #define DCS_ENTER_SLEEP_MODE 0x10 68 + #define DCS_EXIT_SLEEP_MODE 0x11 69 + #define DCS_SET_DISPLAY_OFF 0x28 70 + #define DCS_SET_DISPLAY_ON 0x29 71 + #define DCS_SET_COLUMN_ADDRESS 0x2a 72 + #define DCS_SET_PAGE_ADDRESS 0x2b 73 + #define DCS_WRITE_MEM_START 0x2c 74 + #define DCS_SET_TEAR_OFF 0x34 75 + #define DCS_SET_TEAR_ON 0x35 76 + 77 + extern int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector, 78 + int pipe); 79 + extern void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender); 80 + int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd, 81 + u8 param, u8 param_num, bool hs); 82 + int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data, 83 + u32 len, bool hs); 84 + int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0, 85 + u8 param1, u8 param_num, bool hs); 86 + int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data, 87 + u32 len, bool hs); 88 + /* Read interfaces */ 89 + int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd, 90 + u32 *data, u16 len, bool hs); 91 + 92 + #endif
+1192
drivers/gpu/drm/gma500/mdfld_intel_display.c
··· 1 + /* 2 + * Copyright © 2006-2007 Intel Corporation 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms and conditions of the GNU General Public License, 6 + * version 2, as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 + * more details. 12 + * 13 + * You should have received a copy of the GNU General Public License along with 14 + * this program; if not, write to the Free Software Foundation, Inc., 15 + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 16 + * 17 + * Authors: 18 + * Eric Anholt <eric@anholt.net> 19 + */ 20 + 21 + #include <linux/i2c.h> 22 + #include <linux/pm_runtime.h> 23 + 24 + #include <drm/drmP.h> 25 + #include "psb_intel_reg.h" 26 + #include "psb_intel_display.h" 27 + #include "framebuffer.h" 28 + #include "mdfld_output.h" 29 + #include "mdfld_dsi_output.h" 30 + 31 + /* Hardcoded currently */ 32 + static int ksel = KSEL_CRYSTAL_19; 33 + 34 + struct psb_intel_range_t { 35 + int min, max; 36 + }; 37 + 38 + struct mrst_limit_t { 39 + struct psb_intel_range_t dot, m, p1; 40 + }; 41 + 42 + struct mrst_clock_t { 43 + /* derived values */ 44 + int dot; 45 + int m; 46 + int p1; 47 + }; 48 + 49 + #define COUNT_MAX 0x10000000 50 + 51 + void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe) 52 + { 53 + int count, temp; 54 + u32 pipeconf_reg = PIPEACONF; 55 + 56 + switch (pipe) { 57 + case 0: 58 + break; 59 + case 1: 60 + pipeconf_reg = PIPEBCONF; 61 + break; 62 + case 2: 63 + pipeconf_reg = PIPECCONF; 64 + break; 65 + default: 66 + DRM_ERROR("Illegal Pipe Number.\n"); 67 + return; 68 + } 69 + 70 + /* FIXME JLIU7_PO */ 71 + psb_intel_wait_for_vblank(dev); 72 + return; 73 + 74 + /* Wait for for the pipe disable to take effect. */ 75 + for (count = 0; count < COUNT_MAX; count++) { 76 + temp = REG_READ(pipeconf_reg); 77 + if ((temp & PIPEACONF_PIPE_STATE) == 0) 78 + break; 79 + } 80 + } 81 + 82 + void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe) 83 + { 84 + int count, temp; 85 + u32 pipeconf_reg = PIPEACONF; 86 + 87 + switch (pipe) { 88 + case 0: 89 + break; 90 + case 1: 91 + pipeconf_reg = PIPEBCONF; 92 + break; 93 + case 2: 94 + pipeconf_reg = PIPECCONF; 95 + break; 96 + default: 97 + DRM_ERROR("Illegal Pipe Number.\n"); 98 + return; 99 + } 100 + 101 + /* FIXME JLIU7_PO */ 102 + psb_intel_wait_for_vblank(dev); 103 + return; 104 + 105 + /* Wait for for the pipe enable to take effect. */ 106 + for (count = 0; count < COUNT_MAX; count++) { 107 + temp = REG_READ(pipeconf_reg); 108 + if ((temp & PIPEACONF_PIPE_STATE) == 1) 109 + break; 110 + } 111 + } 112 + 113 + static void psb_intel_crtc_prepare(struct drm_crtc *crtc) 114 + { 115 + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; 116 + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); 117 + } 118 + 119 + static void psb_intel_crtc_commit(struct drm_crtc *crtc) 120 + { 121 + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; 122 + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); 123 + } 124 + 125 + static bool psb_intel_crtc_mode_fixup(struct drm_crtc *crtc, 126 + struct drm_display_mode *mode, 127 + struct drm_display_mode *adjusted_mode) 128 + { 129 + return true; 130 + } 131 + 132 + /** 133 + * Return the pipe currently connected to the panel fitter, 134 + * or -1 if the panel fitter is not present or not in use 135 + */ 136 + static int psb_intel_panel_fitter_pipe(struct drm_device *dev) 137 + { 138 + u32 pfit_control; 139 + 140 + pfit_control = REG_READ(PFIT_CONTROL); 141 + 142 + /* See if the panel fitter is in use */ 143 + if ((pfit_control & PFIT_ENABLE) == 0) 144 + return -1; 145 + 146 + /* 965 can place panel fitter on either pipe */ 147 + return (pfit_control >> 29) & 0x3; 148 + } 149 + 150 + static struct drm_device globle_dev; 151 + 152 + void mdfld__intel_plane_set_alpha(int enable) 153 + { 154 + struct drm_device *dev = &globle_dev; 155 + int dspcntr_reg = DSPACNTR; 156 + u32 dspcntr; 157 + 158 + dspcntr = REG_READ(dspcntr_reg); 159 + 160 + if (enable) { 161 + dspcntr &= ~DISPPLANE_32BPP_NO_ALPHA; 162 + dspcntr |= DISPPLANE_32BPP; 163 + } else { 164 + dspcntr &= ~DISPPLANE_32BPP; 165 + dspcntr |= DISPPLANE_32BPP_NO_ALPHA; 166 + } 167 + 168 + REG_WRITE(dspcntr_reg, dspcntr); 169 + } 170 + 171 + static int check_fb(struct drm_framebuffer *fb) 172 + { 173 + if (!fb) 174 + return 0; 175 + 176 + switch (fb->bits_per_pixel) { 177 + case 8: 178 + case 16: 179 + case 24: 180 + case 32: 181 + return 0; 182 + default: 183 + DRM_ERROR("Unknown color depth\n"); 184 + return -EINVAL; 185 + } 186 + } 187 + 188 + static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, 189 + struct drm_framebuffer *old_fb) 190 + { 191 + struct drm_device *dev = crtc->dev; 192 + /* struct drm_i915_master_private *master_priv; */ 193 + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); 194 + struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb); 195 + int pipe = psb_intel_crtc->pipe; 196 + unsigned long start, offset; 197 + int dsplinoff = DSPALINOFF; 198 + int dspsurf = DSPASURF; 199 + int dspstride = DSPASTRIDE; 200 + int dspcntr_reg = DSPACNTR; 201 + u32 dspcntr; 202 + int ret; 203 + 204 + memcpy(&globle_dev, dev, sizeof(struct drm_device)); 205 + 206 + dev_dbg(dev->dev, "pipe = 0x%x.\n", pipe); 207 + 208 + /* no fb bound */ 209 + if (!crtc->fb) { 210 + dev_dbg(dev->dev, "No FB bound\n"); 211 + return 0; 212 + } 213 + 214 + ret = check_fb(crtc->fb); 215 + if (ret) 216 + return ret; 217 + 218 + switch (pipe) { 219 + case 0: 220 + dsplinoff = DSPALINOFF; 221 + break; 222 + case 1: 223 + dsplinoff = DSPBLINOFF; 224 + dspsurf = DSPBSURF; 225 + dspstride = DSPBSTRIDE; 226 + dspcntr_reg = DSPBCNTR; 227 + break; 228 + case 2: 229 + dsplinoff = DSPCLINOFF; 230 + dspsurf = DSPCSURF; 231 + dspstride = DSPCSTRIDE; 232 + dspcntr_reg = DSPCCNTR; 233 + break; 234 + default: 235 + DRM_ERROR("Illegal Pipe Number.\n"); 236 + return -EINVAL; 237 + } 238 + 239 + if (!gma_power_begin(dev, true)) 240 + return 0; 241 + 242 + start = psbfb->gtt->offset; 243 + offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8); 244 + 245 + REG_WRITE(dspstride, crtc->fb->pitches[0]); 246 + dspcntr = REG_READ(dspcntr_reg); 247 + dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; 248 + 249 + switch (crtc->fb->bits_per_pixel) { 250 + case 8: 251 + dspcntr |= DISPPLANE_8BPP; 252 + break; 253 + case 16: 254 + if (crtc->fb->depth == 15) 255 + dspcntr |= DISPPLANE_15_16BPP; 256 + else 257 + dspcntr |= DISPPLANE_16BPP; 258 + break; 259 + case 24: 260 + case 32: 261 + dspcntr |= DISPPLANE_32BPP_NO_ALPHA; 262 + break; 263 + } 264 + REG_WRITE(dspcntr_reg, dspcntr); 265 + 266 + dev_dbg(dev->dev, "Writing base %08lX %08lX %d %d\n", 267 + start, offset, x, y); 268 + REG_WRITE(dsplinoff, offset); 269 + REG_READ(dsplinoff); 270 + REG_WRITE(dspsurf, start); 271 + REG_READ(dspsurf); 272 + 273 + gma_power_end(dev); 274 + 275 + return 0; 276 + } 277 + 278 + /* 279 + * Disable the pipe, plane and pll. 280 + * 281 + */ 282 + void mdfld_disable_crtc(struct drm_device *dev, int pipe) 283 + { 284 + int dpll_reg = MRST_DPLL_A; 285 + int dspcntr_reg = DSPACNTR; 286 + int dspbase_reg = MRST_DSPABASE; 287 + int pipeconf_reg = PIPEACONF; 288 + u32 temp; 289 + 290 + dev_dbg(dev->dev, "pipe = %d\n", pipe); 291 + 292 + 293 + switch (pipe) { 294 + case 0: 295 + break; 296 + case 1: 297 + dpll_reg = MDFLD_DPLL_B; 298 + dspcntr_reg = DSPBCNTR; 299 + dspbase_reg = DSPBSURF; 300 + pipeconf_reg = PIPEBCONF; 301 + break; 302 + case 2: 303 + dpll_reg = MRST_DPLL_A; 304 + dspcntr_reg = DSPCCNTR; 305 + dspbase_reg = MDFLD_DSPCBASE; 306 + pipeconf_reg = PIPECCONF; 307 + break; 308 + default: 309 + DRM_ERROR("Illegal Pipe Number.\n"); 310 + return; 311 + } 312 + 313 + if (pipe != 1) 314 + mdfld_dsi_gen_fifo_ready(dev, MIPI_GEN_FIFO_STAT_REG(pipe), 315 + HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY); 316 + 317 + /* Disable display plane */ 318 + temp = REG_READ(dspcntr_reg); 319 + if ((temp & DISPLAY_PLANE_ENABLE) != 0) { 320 + REG_WRITE(dspcntr_reg, 321 + temp & ~DISPLAY_PLANE_ENABLE); 322 + /* Flush the plane changes */ 323 + REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); 324 + REG_READ(dspbase_reg); 325 + } 326 + 327 + /* FIXME_JLIU7 MDFLD_PO revisit */ 328 + 329 + /* Next, disable display pipes */ 330 + temp = REG_READ(pipeconf_reg); 331 + if ((temp & PIPEACONF_ENABLE) != 0) { 332 + temp &= ~PIPEACONF_ENABLE; 333 + temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF; 334 + REG_WRITE(pipeconf_reg, temp); 335 + REG_READ(pipeconf_reg); 336 + 337 + /* Wait for for the pipe disable to take effect. */ 338 + mdfldWaitForPipeDisable(dev, pipe); 339 + } 340 + 341 + temp = REG_READ(dpll_reg); 342 + if (temp & DPLL_VCO_ENABLE) { 343 + if ((pipe != 1 && 344 + !((REG_READ(PIPEACONF) | REG_READ(PIPECCONF)) 345 + & PIPEACONF_ENABLE)) || pipe == 1) { 346 + temp &= ~(DPLL_VCO_ENABLE); 347 + REG_WRITE(dpll_reg, temp); 348 + REG_READ(dpll_reg); 349 + /* Wait for the clocks to turn off. */ 350 + /* FIXME_MDFLD PO may need more delay */ 351 + udelay(500); 352 + 353 + if (!(temp & MDFLD_PWR_GATE_EN)) { 354 + /* gating power of DPLL */ 355 + REG_WRITE(dpll_reg, temp | MDFLD_PWR_GATE_EN); 356 + /* FIXME_MDFLD PO - change 500 to 1 after PO */ 357 + udelay(5000); 358 + } 359 + } 360 + } 361 + 362 + } 363 + 364 + /** 365 + * Sets the power management mode of the pipe and plane. 366 + * 367 + * This code should probably grow support for turning the cursor off and back 368 + * on appropriately at the same time as we're turning the pipe off/on. 369 + */ 370 + static void mdfld_crtc_dpms(struct drm_crtc *crtc, int mode) 371 + { 372 + struct drm_device *dev = crtc->dev; 373 + struct drm_psb_private *dev_priv = dev->dev_private; 374 + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); 375 + int pipe = psb_intel_crtc->pipe; 376 + int dpll_reg = MRST_DPLL_A; 377 + int dspcntr_reg = DSPACNTR; 378 + int dspbase_reg = MRST_DSPABASE; 379 + int pipeconf_reg = PIPEACONF; 380 + u32 pipestat_reg = PIPEASTAT; 381 + u32 pipeconf = dev_priv->pipeconf[pipe]; 382 + u32 temp; 383 + bool enabled; 384 + int timeout = 0; 385 + 386 + dev_dbg(dev->dev, "mode = %d, pipe = %d\n", mode, pipe); 387 + 388 + /* FIXME_JLIU7 MDFLD_PO replaced w/ the following function */ 389 + /* mdfld_dbi_dpms (struct drm_device *dev, int pipe, bool enabled) */ 390 + 391 + switch (pipe) { 392 + case 0: 393 + break; 394 + case 1: 395 + dpll_reg = DPLL_B; 396 + dspcntr_reg = DSPBCNTR; 397 + dspbase_reg = MRST_DSPBBASE; 398 + pipeconf_reg = PIPEBCONF; 399 + dpll_reg = MDFLD_DPLL_B; 400 + break; 401 + case 2: 402 + dpll_reg = MRST_DPLL_A; 403 + dspcntr_reg = DSPCCNTR; 404 + dspbase_reg = MDFLD_DSPCBASE; 405 + pipeconf_reg = PIPECCONF; 406 + pipestat_reg = PIPECSTAT; 407 + break; 408 + default: 409 + DRM_ERROR("Illegal Pipe Number.\n"); 410 + return; 411 + } 412 + 413 + if (!gma_power_begin(dev, true)) 414 + return; 415 + 416 + /* XXX: When our outputs are all unaware of DPMS modes other than off 417 + * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. 418 + */ 419 + switch (mode) { 420 + case DRM_MODE_DPMS_ON: 421 + case DRM_MODE_DPMS_STANDBY: 422 + case DRM_MODE_DPMS_SUSPEND: 423 + /* Enable the DPLL */ 424 + temp = REG_READ(dpll_reg); 425 + 426 + if ((temp & DPLL_VCO_ENABLE) == 0) { 427 + /* When ungating power of DPLL, needs to wait 0.5us 428 + before enable the VCO */ 429 + if (temp & MDFLD_PWR_GATE_EN) { 430 + temp &= ~MDFLD_PWR_GATE_EN; 431 + REG_WRITE(dpll_reg, temp); 432 + /* FIXME_MDFLD PO - change 500 to 1 after PO */ 433 + udelay(500); 434 + } 435 + 436 + REG_WRITE(dpll_reg, temp); 437 + REG_READ(dpll_reg); 438 + /* FIXME_MDFLD PO - change 500 to 1 after PO */ 439 + udelay(500); 440 + 441 + REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); 442 + REG_READ(dpll_reg); 443 + 444 + /** 445 + * wait for DSI PLL to lock 446 + * NOTE: only need to poll status of pipe 0 and pipe 1, 447 + * since both MIPI pipes share the same PLL. 448 + */ 449 + while ((pipe != 2) && (timeout < 20000) && 450 + !(REG_READ(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) { 451 + udelay(150); 452 + timeout++; 453 + } 454 + } 455 + 456 + /* Enable the plane */ 457 + temp = REG_READ(dspcntr_reg); 458 + if ((temp & DISPLAY_PLANE_ENABLE) == 0) { 459 + REG_WRITE(dspcntr_reg, 460 + temp | DISPLAY_PLANE_ENABLE); 461 + /* Flush the plane changes */ 462 + REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); 463 + } 464 + 465 + /* Enable the pipe */ 466 + temp = REG_READ(pipeconf_reg); 467 + if ((temp & PIPEACONF_ENABLE) == 0) { 468 + REG_WRITE(pipeconf_reg, pipeconf); 469 + 470 + /* Wait for for the pipe enable to take effect. */ 471 + mdfldWaitForPipeEnable(dev, pipe); 472 + } 473 + 474 + /*workaround for sighting 3741701 Random X blank display*/ 475 + /*perform w/a in video mode only on pipe A or C*/ 476 + if (pipe == 0 || pipe == 2) { 477 + REG_WRITE(pipestat_reg, REG_READ(pipestat_reg)); 478 + msleep(100); 479 + if (PIPE_VBLANK_STATUS & REG_READ(pipestat_reg)) 480 + dev_dbg(dev->dev, "OK"); 481 + else { 482 + dev_dbg(dev->dev, "STUCK!!!!"); 483 + /*shutdown controller*/ 484 + temp = REG_READ(dspcntr_reg); 485 + REG_WRITE(dspcntr_reg, 486 + temp & ~DISPLAY_PLANE_ENABLE); 487 + REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); 488 + /*mdfld_dsi_dpi_shut_down(dev, pipe);*/ 489 + REG_WRITE(0xb048, 1); 490 + msleep(100); 491 + temp = REG_READ(pipeconf_reg); 492 + temp &= ~PIPEACONF_ENABLE; 493 + REG_WRITE(pipeconf_reg, temp); 494 + msleep(100); /*wait for pipe disable*/ 495 + REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 0); 496 + msleep(100); 497 + REG_WRITE(0xb004, REG_READ(0xb004)); 498 + /* try to bring the controller back up again*/ 499 + REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 1); 500 + temp = REG_READ(dspcntr_reg); 501 + REG_WRITE(dspcntr_reg, 502 + temp | DISPLAY_PLANE_ENABLE); 503 + REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); 504 + /*mdfld_dsi_dpi_turn_on(dev, pipe);*/ 505 + REG_WRITE(0xb048, 2); 506 + msleep(100); 507 + temp = REG_READ(pipeconf_reg); 508 + temp |= PIPEACONF_ENABLE; 509 + REG_WRITE(pipeconf_reg, temp); 510 + } 511 + } 512 + 513 + psb_intel_crtc_load_lut(crtc); 514 + 515 + /* Give the overlay scaler a chance to enable 516 + if it's on this pipe */ 517 + /* psb_intel_crtc_dpms_video(crtc, true); TODO */ 518 + 519 + break; 520 + case DRM_MODE_DPMS_OFF: 521 + /* Give the overlay scaler a chance to disable 522 + * if it's on this pipe */ 523 + /* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */ 524 + if (pipe != 1) 525 + mdfld_dsi_gen_fifo_ready(dev, 526 + MIPI_GEN_FIFO_STAT_REG(pipe), 527 + HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY); 528 + 529 + /* Disable the VGA plane that we never use */ 530 + REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); 531 + 532 + /* Disable display plane */ 533 + temp = REG_READ(dspcntr_reg); 534 + if ((temp & DISPLAY_PLANE_ENABLE) != 0) { 535 + REG_WRITE(dspcntr_reg, 536 + temp & ~DISPLAY_PLANE_ENABLE); 537 + /* Flush the plane changes */ 538 + REG_WRITE(dspbase_reg, REG_READ(dspbase_reg)); 539 + REG_READ(dspbase_reg); 540 + } 541 + 542 + /* Next, disable display pipes */ 543 + temp = REG_READ(pipeconf_reg); 544 + if ((temp & PIPEACONF_ENABLE) != 0) { 545 + temp &= ~PIPEACONF_ENABLE; 546 + temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF; 547 + REG_WRITE(pipeconf_reg, temp); 548 + REG_READ(pipeconf_reg); 549 + 550 + /* Wait for for the pipe disable to take effect. */ 551 + mdfldWaitForPipeDisable(dev, pipe); 552 + } 553 + 554 + temp = REG_READ(dpll_reg); 555 + if (temp & DPLL_VCO_ENABLE) { 556 + if ((pipe != 1 && !((REG_READ(PIPEACONF) 557 + | REG_READ(PIPECCONF)) & PIPEACONF_ENABLE)) 558 + || pipe == 1) { 559 + temp &= ~(DPLL_VCO_ENABLE); 560 + REG_WRITE(dpll_reg, temp); 561 + REG_READ(dpll_reg); 562 + /* Wait for the clocks to turn off. */ 563 + /* FIXME_MDFLD PO may need more delay */ 564 + udelay(500); 565 + } 566 + } 567 + break; 568 + } 569 + enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF; 570 + gma_power_end(dev); 571 + } 572 + 573 + 574 + #define MDFLD_LIMT_DPLL_19 0 575 + #define MDFLD_LIMT_DPLL_25 1 576 + #define MDFLD_LIMT_DPLL_83 2 577 + #define MDFLD_LIMT_DPLL_100 3 578 + #define MDFLD_LIMT_DSIPLL_19 4 579 + #define MDFLD_LIMT_DSIPLL_25 5 580 + #define MDFLD_LIMT_DSIPLL_83 6 581 + #define MDFLD_LIMT_DSIPLL_100 7 582 + 583 + #define MDFLD_DOT_MIN 19750 584 + #define MDFLD_DOT_MAX 120000 585 + #define MDFLD_DPLL_M_MIN_19 113 586 + #define MDFLD_DPLL_M_MAX_19 155 587 + #define MDFLD_DPLL_P1_MIN_19 2 588 + #define MDFLD_DPLL_P1_MAX_19 10 589 + #define MDFLD_DPLL_M_MIN_25 101 590 + #define MDFLD_DPLL_M_MAX_25 130 591 + #define MDFLD_DPLL_P1_MIN_25 2 592 + #define MDFLD_DPLL_P1_MAX_25 10 593 + #define MDFLD_DPLL_M_MIN_83 64 594 + #define MDFLD_DPLL_M_MAX_83 64 595 + #define MDFLD_DPLL_P1_MIN_83 2 596 + #define MDFLD_DPLL_P1_MAX_83 2 597 + #define MDFLD_DPLL_M_MIN_100 64 598 + #define MDFLD_DPLL_M_MAX_100 64 599 + #define MDFLD_DPLL_P1_MIN_100 2 600 + #define MDFLD_DPLL_P1_MAX_100 2 601 + #define MDFLD_DSIPLL_M_MIN_19 131 602 + #define MDFLD_DSIPLL_M_MAX_19 175 603 + #define MDFLD_DSIPLL_P1_MIN_19 3 604 + #define MDFLD_DSIPLL_P1_MAX_19 8 605 + #define MDFLD_DSIPLL_M_MIN_25 97 606 + #define MDFLD_DSIPLL_M_MAX_25 140 607 + #define MDFLD_DSIPLL_P1_MIN_25 3 608 + #define MDFLD_DSIPLL_P1_MAX_25 9 609 + #define MDFLD_DSIPLL_M_MIN_83 33 610 + #define MDFLD_DSIPLL_M_MAX_83 92 611 + #define MDFLD_DSIPLL_P1_MIN_83 2 612 + #define MDFLD_DSIPLL_P1_MAX_83 3 613 + #define MDFLD_DSIPLL_M_MIN_100 97 614 + #define MDFLD_DSIPLL_M_MAX_100 140 615 + #define MDFLD_DSIPLL_P1_MIN_100 3 616 + #define MDFLD_DSIPLL_P1_MAX_100 9 617 + 618 + static const struct mrst_limit_t mdfld_limits[] = { 619 + { /* MDFLD_LIMT_DPLL_19 */ 620 + .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, 621 + .m = {.min = MDFLD_DPLL_M_MIN_19, .max = MDFLD_DPLL_M_MAX_19}, 622 + .p1 = {.min = MDFLD_DPLL_P1_MIN_19, .max = MDFLD_DPLL_P1_MAX_19}, 623 + }, 624 + { /* MDFLD_LIMT_DPLL_25 */ 625 + .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, 626 + .m = {.min = MDFLD_DPLL_M_MIN_25, .max = MDFLD_DPLL_M_MAX_25}, 627 + .p1 = {.min = MDFLD_DPLL_P1_MIN_25, .max = MDFLD_DPLL_P1_MAX_25}, 628 + }, 629 + { /* MDFLD_LIMT_DPLL_83 */ 630 + .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, 631 + .m = {.min = MDFLD_DPLL_M_MIN_83, .max = MDFLD_DPLL_M_MAX_83}, 632 + .p1 = {.min = MDFLD_DPLL_P1_MIN_83, .max = MDFLD_DPLL_P1_MAX_83}, 633 + }, 634 + { /* MDFLD_LIMT_DPLL_100 */ 635 + .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, 636 + .m = {.min = MDFLD_DPLL_M_MIN_100, .max = MDFLD_DPLL_M_MAX_100}, 637 + .p1 = {.min = MDFLD_DPLL_P1_MIN_100, .max = MDFLD_DPLL_P1_MAX_100}, 638 + }, 639 + { /* MDFLD_LIMT_DSIPLL_19 */ 640 + .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, 641 + .m = {.min = MDFLD_DSIPLL_M_MIN_19, .max = MDFLD_DSIPLL_M_MAX_19}, 642 + .p1 = {.min = MDFLD_DSIPLL_P1_MIN_19, .max = MDFLD_DSIPLL_P1_MAX_19}, 643 + }, 644 + { /* MDFLD_LIMT_DSIPLL_25 */ 645 + .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, 646 + .m = {.min = MDFLD_DSIPLL_M_MIN_25, .max = MDFLD_DSIPLL_M_MAX_25}, 647 + .p1 = {.min = MDFLD_DSIPLL_P1_MIN_25, .max = MDFLD_DSIPLL_P1_MAX_25}, 648 + }, 649 + { /* MDFLD_LIMT_DSIPLL_83 */ 650 + .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, 651 + .m = {.min = MDFLD_DSIPLL_M_MIN_83, .max = MDFLD_DSIPLL_M_MAX_83}, 652 + .p1 = {.min = MDFLD_DSIPLL_P1_MIN_83, .max = MDFLD_DSIPLL_P1_MAX_83}, 653 + }, 654 + { /* MDFLD_LIMT_DSIPLL_100 */ 655 + .dot = {.min = MDFLD_DOT_MIN, .max = MDFLD_DOT_MAX}, 656 + .m = {.min = MDFLD_DSIPLL_M_MIN_100, .max = MDFLD_DSIPLL_M_MAX_100}, 657 + .p1 = {.min = MDFLD_DSIPLL_P1_MIN_100, .max = MDFLD_DSIPLL_P1_MAX_100}, 658 + }, 659 + }; 660 + 661 + #define MDFLD_M_MIN 21 662 + #define MDFLD_M_MAX 180 663 + static const u32 mdfld_m_converts[] = { 664 + /* M configuration table from 9-bit LFSR table */ 665 + 224, 368, 440, 220, 366, 439, 219, 365, 182, 347, /* 21 - 30 */ 666 + 173, 342, 171, 85, 298, 149, 74, 37, 18, 265, /* 31 - 40 */ 667 + 388, 194, 353, 432, 216, 108, 310, 155, 333, 166, /* 41 - 50 */ 668 + 83, 41, 276, 138, 325, 162, 337, 168, 340, 170, /* 51 - 60 */ 669 + 341, 426, 469, 234, 373, 442, 221, 110, 311, 411, /* 61 - 70 */ 670 + 461, 486, 243, 377, 188, 350, 175, 343, 427, 213, /* 71 - 80 */ 671 + 106, 53, 282, 397, 354, 227, 113, 56, 284, 142, /* 81 - 90 */ 672 + 71, 35, 273, 136, 324, 418, 465, 488, 500, 506, /* 91 - 100 */ 673 + 253, 126, 63, 287, 399, 455, 483, 241, 376, 444, /* 101 - 110 */ 674 + 478, 495, 503, 251, 381, 446, 479, 239, 375, 443, /* 111 - 120 */ 675 + 477, 238, 119, 315, 157, 78, 295, 147, 329, 420, /* 121 - 130 */ 676 + 210, 105, 308, 154, 77, 38, 275, 137, 68, 290, /* 131 - 140 */ 677 + 145, 328, 164, 82, 297, 404, 458, 485, 498, 249, /* 141 - 150 */ 678 + 380, 190, 351, 431, 471, 235, 117, 314, 413, 206, /* 151 - 160 */ 679 + 103, 51, 25, 12, 262, 387, 193, 96, 48, 280, /* 161 - 170 */ 680 + 396, 198, 99, 305, 152, 76, 294, 403, 457, 228, /* 171 - 180 */ 681 + }; 682 + 683 + static const struct mrst_limit_t *mdfld_limit(struct drm_crtc *crtc) 684 + { 685 + const struct mrst_limit_t *limit = NULL; 686 + struct drm_device *dev = crtc->dev; 687 + struct drm_psb_private *dev_priv = dev->dev_private; 688 + 689 + if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_MIPI) 690 + || psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_MIPI2)) { 691 + if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) 692 + limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_19]; 693 + else if (ksel == KSEL_BYPASS_25) 694 + limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_25]; 695 + else if ((ksel == KSEL_BYPASS_83_100) && 696 + (dev_priv->core_freq == 166)) 697 + limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_83]; 698 + else if ((ksel == KSEL_BYPASS_83_100) && 699 + (dev_priv->core_freq == 100 || 700 + dev_priv->core_freq == 200)) 701 + limit = &mdfld_limits[MDFLD_LIMT_DSIPLL_100]; 702 + } else if (psb_intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) { 703 + if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) 704 + limit = &mdfld_limits[MDFLD_LIMT_DPLL_19]; 705 + else if (ksel == KSEL_BYPASS_25) 706 + limit = &mdfld_limits[MDFLD_LIMT_DPLL_25]; 707 + else if ((ksel == KSEL_BYPASS_83_100) && 708 + (dev_priv->core_freq == 166)) 709 + limit = &mdfld_limits[MDFLD_LIMT_DPLL_83]; 710 + else if ((ksel == KSEL_BYPASS_83_100) && 711 + (dev_priv->core_freq == 100 || 712 + dev_priv->core_freq == 200)) 713 + limit = &mdfld_limits[MDFLD_LIMT_DPLL_100]; 714 + } else { 715 + limit = NULL; 716 + dev_dbg(dev->dev, "mdfld_limit Wrong display type.\n"); 717 + } 718 + 719 + return limit; 720 + } 721 + 722 + /** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ 723 + static void mdfld_clock(int refclk, struct mrst_clock_t *clock) 724 + { 725 + clock->dot = (refclk * clock->m) / clock->p1; 726 + } 727 + 728 + /** 729 + * Returns a set of divisors for the desired target clock with the given refclk, 730 + * or FALSE. Divisor values are the actual divisors for 731 + */ 732 + static bool 733 + mdfldFindBestPLL(struct drm_crtc *crtc, int target, int refclk, 734 + struct mrst_clock_t *best_clock) 735 + { 736 + struct mrst_clock_t clock; 737 + const struct mrst_limit_t *limit = mdfld_limit(crtc); 738 + int err = target; 739 + 740 + memset(best_clock, 0, sizeof(*best_clock)); 741 + 742 + for (clock.m = limit->m.min; clock.m <= limit->m.max; clock.m++) { 743 + for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max; 744 + clock.p1++) { 745 + int this_err; 746 + 747 + mdfld_clock(refclk, &clock); 748 + 749 + this_err = abs(clock.dot - target); 750 + if (this_err < err) { 751 + *best_clock = clock; 752 + err = this_err; 753 + } 754 + } 755 + } 756 + return err != target; 757 + } 758 + 759 + static int mdfld_crtc_mode_set(struct drm_crtc *crtc, 760 + struct drm_display_mode *mode, 761 + struct drm_display_mode *adjusted_mode, 762 + int x, int y, 763 + struct drm_framebuffer *old_fb) 764 + { 765 + struct drm_device *dev = crtc->dev; 766 + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); 767 + struct drm_psb_private *dev_priv = dev->dev_private; 768 + int pipe = psb_intel_crtc->pipe; 769 + int fp_reg = MRST_FPA0; 770 + int dpll_reg = MRST_DPLL_A; 771 + int dspcntr_reg = DSPACNTR; 772 + int pipeconf_reg = PIPEACONF; 773 + int htot_reg = HTOTAL_A; 774 + int hblank_reg = HBLANK_A; 775 + int hsync_reg = HSYNC_A; 776 + int vtot_reg = VTOTAL_A; 777 + int vblank_reg = VBLANK_A; 778 + int vsync_reg = VSYNC_A; 779 + int dspsize_reg = DSPASIZE; 780 + int dsppos_reg = DSPAPOS; 781 + int pipesrc_reg = PIPEASRC; 782 + u32 *pipeconf = &dev_priv->pipeconf[pipe]; 783 + u32 *dspcntr = &dev_priv->dspcntr[pipe]; 784 + int refclk = 0; 785 + int clk_n = 0, clk_p2 = 0, clk_byte = 1, clk = 0, m_conv = 0, 786 + clk_tmp = 0; 787 + struct mrst_clock_t clock; 788 + bool ok; 789 + u32 dpll = 0, fp = 0; 790 + bool is_crt = false, is_lvds = false, is_tv = false; 791 + bool is_mipi = false, is_mipi2 = false, is_hdmi = false; 792 + struct drm_mode_config *mode_config = &dev->mode_config; 793 + struct psb_intel_encoder *psb_intel_encoder = NULL; 794 + uint64_t scalingType = DRM_MODE_SCALE_FULLSCREEN; 795 + struct drm_encoder *encoder; 796 + struct drm_connector *connector; 797 + int timeout = 0; 798 + int ret; 799 + 800 + dev_dbg(dev->dev, "pipe = 0x%x\n", pipe); 801 + 802 + #if 0 803 + if (pipe == 1) { 804 + if (!gma_power_begin(dev, true)) 805 + return 0; 806 + android_hdmi_crtc_mode_set(crtc, mode, adjusted_mode, 807 + x, y, old_fb); 808 + goto mrst_crtc_mode_set_exit; 809 + } 810 + #endif 811 + 812 + switch (pipe) { 813 + case 0: 814 + break; 815 + case 1: 816 + fp_reg = FPB0; 817 + dpll_reg = DPLL_B; 818 + dspcntr_reg = DSPBCNTR; 819 + pipeconf_reg = PIPEBCONF; 820 + htot_reg = HTOTAL_B; 821 + hblank_reg = HBLANK_B; 822 + hsync_reg = HSYNC_B; 823 + vtot_reg = VTOTAL_B; 824 + vblank_reg = VBLANK_B; 825 + vsync_reg = VSYNC_B; 826 + dspsize_reg = DSPBSIZE; 827 + dsppos_reg = DSPBPOS; 828 + pipesrc_reg = PIPEBSRC; 829 + fp_reg = MDFLD_DPLL_DIV0; 830 + dpll_reg = MDFLD_DPLL_B; 831 + break; 832 + case 2: 833 + dpll_reg = MRST_DPLL_A; 834 + dspcntr_reg = DSPCCNTR; 835 + pipeconf_reg = PIPECCONF; 836 + htot_reg = HTOTAL_C; 837 + hblank_reg = HBLANK_C; 838 + hsync_reg = HSYNC_C; 839 + vtot_reg = VTOTAL_C; 840 + vblank_reg = VBLANK_C; 841 + vsync_reg = VSYNC_C; 842 + dspsize_reg = DSPCSIZE; 843 + dsppos_reg = DSPCPOS; 844 + pipesrc_reg = PIPECSRC; 845 + break; 846 + default: 847 + DRM_ERROR("Illegal Pipe Number.\n"); 848 + return 0; 849 + } 850 + 851 + ret = check_fb(crtc->fb); 852 + if (ret) 853 + return ret; 854 + 855 + dev_dbg(dev->dev, "adjusted_hdisplay = %d\n", 856 + adjusted_mode->hdisplay); 857 + dev_dbg(dev->dev, "adjusted_vdisplay = %d\n", 858 + adjusted_mode->vdisplay); 859 + dev_dbg(dev->dev, "adjusted_hsync_start = %d\n", 860 + adjusted_mode->hsync_start); 861 + dev_dbg(dev->dev, "adjusted_hsync_end = %d\n", 862 + adjusted_mode->hsync_end); 863 + dev_dbg(dev->dev, "adjusted_htotal = %d\n", 864 + adjusted_mode->htotal); 865 + dev_dbg(dev->dev, "adjusted_vsync_start = %d\n", 866 + adjusted_mode->vsync_start); 867 + dev_dbg(dev->dev, "adjusted_vsync_end = %d\n", 868 + adjusted_mode->vsync_end); 869 + dev_dbg(dev->dev, "adjusted_vtotal = %d\n", 870 + adjusted_mode->vtotal); 871 + dev_dbg(dev->dev, "adjusted_clock = %d\n", 872 + adjusted_mode->clock); 873 + dev_dbg(dev->dev, "hdisplay = %d\n", 874 + mode->hdisplay); 875 + dev_dbg(dev->dev, "vdisplay = %d\n", 876 + mode->vdisplay); 877 + 878 + if (!gma_power_begin(dev, true)) 879 + return 0; 880 + 881 + memcpy(&psb_intel_crtc->saved_mode, mode, 882 + sizeof(struct drm_display_mode)); 883 + memcpy(&psb_intel_crtc->saved_adjusted_mode, adjusted_mode, 884 + sizeof(struct drm_display_mode)); 885 + 886 + list_for_each_entry(connector, &mode_config->connector_list, head) { 887 + if (!connector) 888 + continue; 889 + 890 + encoder = connector->encoder; 891 + 892 + if (!encoder) 893 + continue; 894 + 895 + if (encoder->crtc != crtc) 896 + continue; 897 + 898 + psb_intel_encoder = psb_intel_attached_encoder(connector); 899 + 900 + switch (psb_intel_encoder->type) { 901 + case INTEL_OUTPUT_LVDS: 902 + is_lvds = true; 903 + break; 904 + case INTEL_OUTPUT_TVOUT: 905 + is_tv = true; 906 + break; 907 + case INTEL_OUTPUT_ANALOG: 908 + is_crt = true; 909 + break; 910 + case INTEL_OUTPUT_MIPI: 911 + is_mipi = true; 912 + break; 913 + case INTEL_OUTPUT_MIPI2: 914 + is_mipi2 = true; 915 + break; 916 + case INTEL_OUTPUT_HDMI: 917 + is_hdmi = true; 918 + break; 919 + } 920 + } 921 + 922 + /* Disable the VGA plane that we never use */ 923 + REG_WRITE(VGACNTRL, VGA_DISP_DISABLE); 924 + 925 + /* Disable the panel fitter if it was on our pipe */ 926 + if (psb_intel_panel_fitter_pipe(dev) == pipe) 927 + REG_WRITE(PFIT_CONTROL, 0); 928 + 929 + /* pipesrc and dspsize control the size that is scaled from, 930 + * which should always be the user's requested size. 931 + */ 932 + if (pipe == 1) { 933 + /* FIXME: To make HDMI display with 864x480 (TPO), 480x864 934 + * (PYR) or 480x854 (TMD), set the sprite width/height and 935 + * souce image size registers with the adjusted mode for 936 + * pipe B. 937 + */ 938 + 939 + /* 940 + * The defined sprite rectangle must always be completely 941 + * contained within the displayable area of the screen image 942 + * (frame buffer). 943 + */ 944 + REG_WRITE(dspsize_reg, ((min(mode->crtc_vdisplay, adjusted_mode->crtc_vdisplay) - 1) << 16) 945 + | (min(mode->crtc_hdisplay, adjusted_mode->crtc_hdisplay) - 1)); 946 + /* Set the CRTC with encoder mode. */ 947 + REG_WRITE(pipesrc_reg, ((mode->crtc_hdisplay - 1) << 16) 948 + | (mode->crtc_vdisplay - 1)); 949 + } else { 950 + REG_WRITE(dspsize_reg, 951 + ((mode->crtc_vdisplay - 1) << 16) | 952 + (mode->crtc_hdisplay - 1)); 953 + REG_WRITE(pipesrc_reg, 954 + ((mode->crtc_hdisplay - 1) << 16) | 955 + (mode->crtc_vdisplay - 1)); 956 + } 957 + 958 + REG_WRITE(dsppos_reg, 0); 959 + 960 + if (psb_intel_encoder) 961 + drm_connector_property_get_value(connector, 962 + dev->mode_config.scaling_mode_property, &scalingType); 963 + 964 + if (scalingType == DRM_MODE_SCALE_NO_SCALE) { 965 + /* Medfield doesn't have register support for centering so we 966 + * need to mess with the h/vblank and h/vsync start and ends 967 + * to get centering 968 + */ 969 + int offsetX = 0, offsetY = 0; 970 + 971 + offsetX = (adjusted_mode->crtc_hdisplay - 972 + mode->crtc_hdisplay) / 2; 973 + offsetY = (adjusted_mode->crtc_vdisplay - 974 + mode->crtc_vdisplay) / 2; 975 + 976 + REG_WRITE(htot_reg, (mode->crtc_hdisplay - 1) | 977 + ((adjusted_mode->crtc_htotal - 1) << 16)); 978 + REG_WRITE(vtot_reg, (mode->crtc_vdisplay - 1) | 979 + ((adjusted_mode->crtc_vtotal - 1) << 16)); 980 + REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 981 + offsetX - 1) | 982 + ((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16)); 983 + REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 984 + offsetX - 1) | 985 + ((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16)); 986 + REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 987 + offsetY - 1) | 988 + ((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16)); 989 + REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 990 + offsetY - 1) | 991 + ((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16)); 992 + } else { 993 + REG_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | 994 + ((adjusted_mode->crtc_htotal - 1) << 16)); 995 + REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | 996 + ((adjusted_mode->crtc_vtotal - 1) << 16)); 997 + REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | 998 + ((adjusted_mode->crtc_hblank_end - 1) << 16)); 999 + REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | 1000 + ((adjusted_mode->crtc_hsync_end - 1) << 16)); 1001 + REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | 1002 + ((adjusted_mode->crtc_vblank_end - 1) << 16)); 1003 + REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | 1004 + ((adjusted_mode->crtc_vsync_end - 1) << 16)); 1005 + } 1006 + 1007 + /* Flush the plane changes */ 1008 + { 1009 + struct drm_crtc_helper_funcs *crtc_funcs = 1010 + crtc->helper_private; 1011 + crtc_funcs->mode_set_base(crtc, x, y, old_fb); 1012 + } 1013 + 1014 + /* setup pipeconf */ 1015 + *pipeconf = PIPEACONF_ENABLE; /* FIXME_JLIU7 REG_READ(pipeconf_reg); */ 1016 + 1017 + /* Set up the display plane register */ 1018 + *dspcntr = REG_READ(dspcntr_reg); 1019 + *dspcntr |= pipe << DISPPLANE_SEL_PIPE_POS; 1020 + *dspcntr |= DISPLAY_PLANE_ENABLE; 1021 + 1022 + if (is_mipi2) 1023 + goto mrst_crtc_mode_set_exit; 1024 + clk = adjusted_mode->clock; 1025 + 1026 + if (is_hdmi) { 1027 + if ((ksel == KSEL_CRYSTAL_19) || (ksel == KSEL_BYPASS_19)) { 1028 + refclk = 19200; 1029 + 1030 + if (is_mipi || is_mipi2) 1031 + clk_n = 1, clk_p2 = 8; 1032 + else if (is_hdmi) 1033 + clk_n = 1, clk_p2 = 10; 1034 + } else if (ksel == KSEL_BYPASS_25) { 1035 + refclk = 25000; 1036 + 1037 + if (is_mipi || is_mipi2) 1038 + clk_n = 1, clk_p2 = 8; 1039 + else if (is_hdmi) 1040 + clk_n = 1, clk_p2 = 10; 1041 + } else if ((ksel == KSEL_BYPASS_83_100) && 1042 + dev_priv->core_freq == 166) { 1043 + refclk = 83000; 1044 + 1045 + if (is_mipi || is_mipi2) 1046 + clk_n = 4, clk_p2 = 8; 1047 + else if (is_hdmi) 1048 + clk_n = 4, clk_p2 = 10; 1049 + } else if ((ksel == KSEL_BYPASS_83_100) && 1050 + (dev_priv->core_freq == 100 || 1051 + dev_priv->core_freq == 200)) { 1052 + refclk = 100000; 1053 + if (is_mipi || is_mipi2) 1054 + clk_n = 4, clk_p2 = 8; 1055 + else if (is_hdmi) 1056 + clk_n = 4, clk_p2 = 10; 1057 + } 1058 + 1059 + if (is_mipi) 1060 + clk_byte = dev_priv->bpp / 8; 1061 + else if (is_mipi2) 1062 + clk_byte = dev_priv->bpp2 / 8; 1063 + 1064 + clk_tmp = clk * clk_n * clk_p2 * clk_byte; 1065 + 1066 + dev_dbg(dev->dev, "clk = %d, clk_n = %d, clk_p2 = %d.\n", 1067 + clk, clk_n, clk_p2); 1068 + dev_dbg(dev->dev, "adjusted_mode->clock = %d, clk_tmp = %d.\n", 1069 + adjusted_mode->clock, clk_tmp); 1070 + 1071 + ok = mdfldFindBestPLL(crtc, clk_tmp, refclk, &clock); 1072 + 1073 + if (!ok) { 1074 + DRM_ERROR 1075 + ("mdfldFindBestPLL fail in mdfld_crtc_mode_set.\n"); 1076 + } else { 1077 + m_conv = mdfld_m_converts[(clock.m - MDFLD_M_MIN)]; 1078 + 1079 + dev_dbg(dev->dev, "dot clock = %d," 1080 + "m = %d, p1 = %d, m_conv = %d.\n", 1081 + clock.dot, clock.m, 1082 + clock.p1, m_conv); 1083 + } 1084 + 1085 + dpll = REG_READ(dpll_reg); 1086 + 1087 + if (dpll & DPLL_VCO_ENABLE) { 1088 + dpll &= ~DPLL_VCO_ENABLE; 1089 + REG_WRITE(dpll_reg, dpll); 1090 + REG_READ(dpll_reg); 1091 + 1092 + /* FIXME jliu7 check the DPLL lock bit PIPEACONF[29] */ 1093 + /* FIXME_MDFLD PO - change 500 to 1 after PO */ 1094 + udelay(500); 1095 + 1096 + /* reset M1, N1 & P1 */ 1097 + REG_WRITE(fp_reg, 0); 1098 + dpll &= ~MDFLD_P1_MASK; 1099 + REG_WRITE(dpll_reg, dpll); 1100 + /* FIXME_MDFLD PO - change 500 to 1 after PO */ 1101 + udelay(500); 1102 + } 1103 + 1104 + /* When ungating power of DPLL, needs to wait 0.5us before 1105 + * enable the VCO */ 1106 + if (dpll & MDFLD_PWR_GATE_EN) { 1107 + dpll &= ~MDFLD_PWR_GATE_EN; 1108 + REG_WRITE(dpll_reg, dpll); 1109 + /* FIXME_MDFLD PO - change 500 to 1 after PO */ 1110 + udelay(500); 1111 + } 1112 + dpll = 0; 1113 + 1114 + #if 0 /* FIXME revisit later */ 1115 + if (ksel == KSEL_CRYSTAL_19 || ksel == KSEL_BYPASS_19 || 1116 + ksel == KSEL_BYPASS_25) 1117 + dpll &= ~MDFLD_INPUT_REF_SEL; 1118 + else if (ksel == KSEL_BYPASS_83_100) 1119 + dpll |= MDFLD_INPUT_REF_SEL; 1120 + #endif /* FIXME revisit later */ 1121 + 1122 + if (is_hdmi) 1123 + dpll |= MDFLD_VCO_SEL; 1124 + 1125 + fp = (clk_n / 2) << 16; 1126 + fp |= m_conv; 1127 + 1128 + /* compute bitmask from p1 value */ 1129 + dpll |= (1 << (clock.p1 - 2)) << 17; 1130 + 1131 + #if 0 /* 1080p30 & 720p */ 1132 + dpll = 0x00050000; 1133 + fp = 0x000001be; 1134 + #endif 1135 + #if 0 /* 480p */ 1136 + dpll = 0x02010000; 1137 + fp = 0x000000d2; 1138 + #endif 1139 + } else { 1140 + #if 0 /*DBI_TPO_480x864*/ 1141 + dpll = 0x00020000; 1142 + fp = 0x00000156; 1143 + #endif /* DBI_TPO_480x864 */ /* get from spec. */ 1144 + 1145 + dpll = 0x00800000; 1146 + fp = 0x000000c1; 1147 + } 1148 + 1149 + REG_WRITE(fp_reg, fp); 1150 + REG_WRITE(dpll_reg, dpll); 1151 + /* FIXME_MDFLD PO - change 500 to 1 after PO */ 1152 + udelay(500); 1153 + 1154 + dpll |= DPLL_VCO_ENABLE; 1155 + REG_WRITE(dpll_reg, dpll); 1156 + REG_READ(dpll_reg); 1157 + 1158 + /* wait for DSI PLL to lock */ 1159 + while (timeout < 20000 && 1160 + !(REG_READ(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) { 1161 + udelay(150); 1162 + timeout++; 1163 + } 1164 + 1165 + if (is_mipi) 1166 + goto mrst_crtc_mode_set_exit; 1167 + 1168 + dev_dbg(dev->dev, "is_mipi = 0x%x\n", is_mipi); 1169 + 1170 + REG_WRITE(pipeconf_reg, *pipeconf); 1171 + REG_READ(pipeconf_reg); 1172 + 1173 + /* Wait for for the pipe enable to take effect. */ 1174 + REG_WRITE(dspcntr_reg, *dspcntr); 1175 + psb_intel_wait_for_vblank(dev); 1176 + 1177 + mrst_crtc_mode_set_exit: 1178 + 1179 + gma_power_end(dev); 1180 + 1181 + return 0; 1182 + } 1183 + 1184 + const struct drm_crtc_helper_funcs mdfld_helper_funcs = { 1185 + .dpms = mdfld_crtc_dpms, 1186 + .mode_fixup = psb_intel_crtc_mode_fixup, 1187 + .mode_set = mdfld_crtc_mode_set, 1188 + .mode_set_base = mdfld__intel_pipe_set_base, 1189 + .prepare = psb_intel_crtc_prepare, 1190 + .commit = psb_intel_crtc_commit, 1191 + }; 1192 +
+77
drivers/gpu/drm/gma500/mdfld_output.c
··· 1 + /* 2 + * Copyright (c) 2010 Intel Corporation 3 + * 4 + * Permission is hereby granted, free of charge, to any person obtaining a 5 + * copy of this software and associated documentation files (the "Software"), 6 + * to deal in the Software without restriction, including without limitation 7 + * the rights to use, copy, modify, merge, publish, distribute, sublicensen 8 + * and/or sell copies of the Software, and to permit persons to whom the 9 + * Software is furnished to do so, subject to the following conditions: 10 + * 11 + * The above copyright notice and this permission notice (including the next 12 + * paragraph) shall be included in all copies or substantial portions of the 13 + * Software. 14 + * 15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 + * DEALINGS IN THE SOFTWARE. 22 + * 23 + * Authors: 24 + * Thomas Eaton <thomas.g.eaton@intel.com> 25 + * Scott Rowe <scott.m.rowe@intel.com> 26 + */ 27 + 28 + #include "mdfld_output.h" 29 + #include "mdfld_dsi_dpi.h" 30 + #include "mdfld_dsi_output.h" 31 + 32 + #include "tc35876x-dsi-lvds.h" 33 + 34 + int mdfld_get_panel_type(struct drm_device *dev, int pipe) 35 + { 36 + struct drm_psb_private *dev_priv = dev->dev_private; 37 + return dev_priv->mdfld_panel_id; 38 + } 39 + 40 + static void mdfld_init_panel(struct drm_device *dev, int mipi_pipe, 41 + int p_type) 42 + { 43 + switch (p_type) { 44 + case TPO_VID: 45 + mdfld_dsi_output_init(dev, mipi_pipe, NULL, 46 + &mdfld_tpo_vid_funcs); 47 + break; 48 + case TC35876X: 49 + tc35876x_init(dev); 50 + mdfld_dsi_output_init(dev, mipi_pipe, NULL, 51 + &mdfld_tc35876x_funcs); 52 + break; 53 + case TMD_VID: 54 + mdfld_dsi_output_init(dev, mipi_pipe, NULL, 55 + &mdfld_tmd_vid_funcs); 56 + break; 57 + case HDMI: 58 + /* if (dev_priv->mdfld_hdmi_present) 59 + mdfld_hdmi_init(dev, &dev_priv->mode_dev); */ 60 + break; 61 + } 62 + } 63 + 64 + 65 + int mdfld_output_init(struct drm_device *dev) 66 + { 67 + struct drm_psb_private *dev_priv = dev->dev_private; 68 + 69 + /* FIXME: hardcoded for now */ 70 + dev_priv->mdfld_panel_id = TC35876X; 71 + /* MIPI panel 1 */ 72 + mdfld_init_panel(dev, 0, dev_priv->mdfld_panel_id); 73 + /* HDMI panel */ 74 + mdfld_init_panel(dev, 1, HDMI); 75 + return 0; 76 + } 77 +
+77
drivers/gpu/drm/gma500/mdfld_output.h
··· 1 + /* 2 + * Copyright (c) 2010 Intel Corporation 3 + * 4 + * Permission is hereby granted, free of charge, to any person obtaining a 5 + * copy of this software and associated documentation files (the "Software"), 6 + * to deal in the Software without restriction, including without limitation 7 + * the rights to use, copy, modify, merge, publish, distribute, sublicensen 8 + * and/or sell copies of the Software, and to permit persons to whom the 9 + * Software is furnished to do so, subject to the following conditions: 10 + * 11 + * The above copyright notice and this permission notice (including the next 12 + * paragraph) shall be included in all copies or substantial portions of the 13 + * Software. 14 + * 15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 + * DEALINGS IN THE SOFTWARE. 22 + * 23 + * Authors: 24 + * Thomas Eaton <thomas.g.eaton@intel.com> 25 + * Scott Rowe <scott.m.rowe@intel.com> 26 + */ 27 + 28 + #ifndef MDFLD_OUTPUT_H 29 + #define MDFLD_OUTPUT_H 30 + 31 + #include "psb_drv.h" 32 + 33 + #define TPO_PANEL_WIDTH 84 34 + #define TPO_PANEL_HEIGHT 46 35 + #define TMD_PANEL_WIDTH 39 36 + #define TMD_PANEL_HEIGHT 71 37 + 38 + struct mdfld_dsi_config; 39 + 40 + enum panel_type { 41 + TPO_VID, 42 + TMD_VID, 43 + HDMI, 44 + TC35876X, 45 + }; 46 + 47 + struct panel_info { 48 + u32 width_mm; 49 + u32 height_mm; 50 + /* Other info */ 51 + }; 52 + 53 + struct panel_funcs { 54 + const struct drm_encoder_funcs *encoder_funcs; 55 + const struct drm_encoder_helper_funcs *encoder_helper_funcs; 56 + struct drm_display_mode * (*get_config_mode)(struct drm_device *); 57 + int (*get_panel_info)(struct drm_device *, int, struct panel_info *); 58 + int (*reset)(int pipe); 59 + void (*drv_ic_init)(struct mdfld_dsi_config *dsi_config, int pipe); 60 + }; 61 + 62 + int mdfld_output_init(struct drm_device *dev); 63 + 64 + struct backlight_device *mdfld_get_backlight_device(void); 65 + int mdfld_set_brightness(struct backlight_device *bd); 66 + 67 + int mdfld_get_panel_type(struct drm_device *dev, int pipe); 68 + 69 + extern const struct drm_crtc_helper_funcs mdfld_helper_funcs; 70 + 71 + extern const struct panel_funcs mdfld_tmd_vid_funcs; 72 + extern const struct panel_funcs mdfld_tpo_vid_funcs; 73 + 74 + extern void mdfld_disable_crtc(struct drm_device *dev, int pipe); 75 + extern void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe); 76 + extern void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe); 77 + #endif
+201
drivers/gpu/drm/gma500/mdfld_tmd_vid.c
··· 1 + /* 2 + * Copyright © 2010 Intel Corporation 3 + * 4 + * Permission is hereby granted, free of charge, to any person obtaining a 5 + * copy of this software and associated documentation files (the "Software"), 6 + * to deal in the Software without restriction, including without limitation 7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 + * and/or sell copies of the Software, and to permit persons to whom the 9 + * Software is furnished to do so, subject to the following conditions: 10 + * 11 + * The above copyright notice and this permission notice (including the next 12 + * paragraph) shall be included in all copies or substantial portions of the 13 + * Software. 14 + * 15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 + * DEALINGS IN THE SOFTWARE. 22 + * 23 + * Authors: 24 + * Jim Liu <jim.liu@intel.com> 25 + * Jackie Li<yaodong.li@intel.com> 26 + * Gideon Eaton <eaton. 27 + * Scott Rowe <scott.m.rowe@intel.com> 28 + */ 29 + 30 + #include "mdfld_dsi_dpi.h" 31 + #include "mdfld_dsi_pkg_sender.h" 32 + 33 + static struct drm_display_mode *tmd_vid_get_config_mode(struct drm_device *dev) 34 + { 35 + struct drm_display_mode *mode; 36 + struct drm_psb_private *dev_priv = dev->dev_private; 37 + struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD; 38 + bool use_gct = false; /*Disable GCT for now*/ 39 + 40 + mode = kzalloc(sizeof(*mode), GFP_KERNEL); 41 + if (!mode) 42 + return NULL; 43 + 44 + if (use_gct) { 45 + mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo; 46 + mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo; 47 + mode->hsync_start = mode->hdisplay + \ 48 + ((ti->hsync_offset_hi << 8) | \ 49 + ti->hsync_offset_lo); 50 + mode->hsync_end = mode->hsync_start + \ 51 + ((ti->hsync_pulse_width_hi << 8) | \ 52 + ti->hsync_pulse_width_lo); 53 + mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | \ 54 + ti->hblank_lo); 55 + mode->vsync_start = \ 56 + mode->vdisplay + ((ti->vsync_offset_hi << 8) | \ 57 + ti->vsync_offset_lo); 58 + mode->vsync_end = \ 59 + mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) | \ 60 + ti->vsync_pulse_width_lo); 61 + mode->vtotal = mode->vdisplay + \ 62 + ((ti->vblank_hi << 8) | ti->vblank_lo); 63 + mode->clock = ti->pixel_clock * 10; 64 + 65 + dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay); 66 + dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay); 67 + dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start); 68 + dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end); 69 + dev_dbg(dev->dev, "htotal is %d\n", mode->htotal); 70 + dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start); 71 + dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end); 72 + dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal); 73 + dev_dbg(dev->dev, "clock is %d\n", mode->clock); 74 + } else { 75 + mode->hdisplay = 480; 76 + mode->vdisplay = 854; 77 + mode->hsync_start = 487; 78 + mode->hsync_end = 490; 79 + mode->htotal = 499; 80 + mode->vsync_start = 861; 81 + mode->vsync_end = 865; 82 + mode->vtotal = 873; 83 + mode->clock = 33264; 84 + } 85 + 86 + drm_mode_set_name(mode); 87 + drm_mode_set_crtcinfo(mode, 0); 88 + 89 + mode->type |= DRM_MODE_TYPE_PREFERRED; 90 + 91 + return mode; 92 + } 93 + 94 + static int tmd_vid_get_panel_info(struct drm_device *dev, 95 + int pipe, 96 + struct panel_info *pi) 97 + { 98 + if (!dev || !pi) 99 + return -EINVAL; 100 + 101 + pi->width_mm = TMD_PANEL_WIDTH; 102 + pi->height_mm = TMD_PANEL_HEIGHT; 103 + 104 + return 0; 105 + } 106 + 107 + /* ************************************************************************* *\ 108 + * FUNCTION: mdfld_init_TMD_MIPI 109 + * 110 + * DESCRIPTION: This function is called only by mrst_dsi_mode_set and 111 + * restore_display_registers. since this function does not 112 + * acquire the mutex, it is important that the calling function 113 + * does! 114 + \* ************************************************************************* */ 115 + 116 + /* FIXME: make the below data u8 instead of u32; note byte order! */ 117 + static u32 tmd_cmd_mcap_off[] = {0x000000b2}; 118 + static u32 tmd_cmd_enable_lane_switch[] = {0x000101ef}; 119 + static u32 tmd_cmd_set_lane_num[] = {0x006360ef}; 120 + static u32 tmd_cmd_pushing_clock0[] = {0x00cc2fef}; 121 + static u32 tmd_cmd_pushing_clock1[] = {0x00dd6eef}; 122 + static u32 tmd_cmd_set_mode[] = {0x000000b3}; 123 + static u32 tmd_cmd_set_sync_pulse_mode[] = {0x000961ef}; 124 + static u32 tmd_cmd_set_column[] = {0x0100002a, 0x000000df}; 125 + static u32 tmd_cmd_set_page[] = {0x0300002b, 0x00000055}; 126 + static u32 tmd_cmd_set_video_mode[] = {0x00000153}; 127 + /*no auto_bl,need add in furture*/ 128 + static u32 tmd_cmd_enable_backlight[] = {0x00005ab4}; 129 + static u32 tmd_cmd_set_backlight_dimming[] = {0x00000ebd}; 130 + 131 + static void mdfld_dsi_tmd_drv_ic_init(struct mdfld_dsi_config *dsi_config, 132 + int pipe) 133 + { 134 + struct mdfld_dsi_pkg_sender *sender 135 + = mdfld_dsi_get_pkg_sender(dsi_config); 136 + 137 + DRM_INFO("Enter mdfld init TMD MIPI display.\n"); 138 + 139 + if (!sender) { 140 + DRM_ERROR("Cannot get sender\n"); 141 + return; 142 + } 143 + 144 + if (dsi_config->dvr_ic_inited) 145 + return; 146 + 147 + msleep(3); 148 + 149 + /* FIXME: make the below data u8 instead of u32; note byte order! */ 150 + 151 + mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_mcap_off, 152 + sizeof(tmd_cmd_mcap_off), false); 153 + mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_enable_lane_switch, 154 + sizeof(tmd_cmd_enable_lane_switch), false); 155 + mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_lane_num, 156 + sizeof(tmd_cmd_set_lane_num), false); 157 + mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_pushing_clock0, 158 + sizeof(tmd_cmd_pushing_clock0), false); 159 + mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_pushing_clock1, 160 + sizeof(tmd_cmd_pushing_clock1), false); 161 + mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_mode, 162 + sizeof(tmd_cmd_set_mode), false); 163 + mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_sync_pulse_mode, 164 + sizeof(tmd_cmd_set_sync_pulse_mode), false); 165 + mdfld_dsi_send_mcs_long(sender, (u8 *) tmd_cmd_set_column, 166 + sizeof(tmd_cmd_set_column), false); 167 + mdfld_dsi_send_mcs_long(sender, (u8 *) tmd_cmd_set_page, 168 + sizeof(tmd_cmd_set_page), false); 169 + mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_video_mode, 170 + sizeof(tmd_cmd_set_video_mode), false); 171 + mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_enable_backlight, 172 + sizeof(tmd_cmd_enable_backlight), false); 173 + mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_backlight_dimming, 174 + sizeof(tmd_cmd_set_backlight_dimming), false); 175 + 176 + dsi_config->dvr_ic_inited = 1; 177 + } 178 + 179 + /*TPO DPI encoder helper funcs*/ 180 + static const struct drm_encoder_helper_funcs 181 + mdfld_tpo_dpi_encoder_helper_funcs = { 182 + .dpms = mdfld_dsi_dpi_dpms, 183 + .mode_fixup = mdfld_dsi_dpi_mode_fixup, 184 + .prepare = mdfld_dsi_dpi_prepare, 185 + .mode_set = mdfld_dsi_dpi_mode_set, 186 + .commit = mdfld_dsi_dpi_commit, 187 + }; 188 + 189 + /*TPO DPI encoder funcs*/ 190 + static const struct drm_encoder_funcs mdfld_tpo_dpi_encoder_funcs = { 191 + .destroy = drm_encoder_cleanup, 192 + }; 193 + 194 + const struct panel_funcs mdfld_tmd_vid_funcs = { 195 + .encoder_funcs = &mdfld_tpo_dpi_encoder_funcs, 196 + .encoder_helper_funcs = &mdfld_tpo_dpi_encoder_helper_funcs, 197 + .get_config_mode = &tmd_vid_get_config_mode, 198 + .get_panel_info = tmd_vid_get_panel_info, 199 + .reset = mdfld_dsi_panel_reset, 200 + .drv_ic_init = mdfld_dsi_tmd_drv_ic_init, 201 + };
+124
drivers/gpu/drm/gma500/mdfld_tpo_vid.c
··· 1 + /* 2 + * Copyright © 2010 Intel Corporation 3 + * 4 + * Permission is hereby granted, free of charge, to any person obtaining a 5 + * copy of this software and associated documentation files (the "Software"), 6 + * to deal in the Software without restriction, including without limitation 7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 + * and/or sell copies of the Software, and to permit persons to whom the 9 + * Software is furnished to do so, subject to the following conditions: 10 + * 11 + * The above copyright notice and this permission notice (including the next 12 + * paragraph) shall be included in all copies or substantial portions of the 13 + * Software. 14 + * 15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 + * DEALINGS IN THE SOFTWARE. 22 + * 23 + * Authors: 24 + * jim liu <jim.liu@intel.com> 25 + * Jackie Li<yaodong.li@intel.com> 26 + */ 27 + 28 + #include "mdfld_dsi_dpi.h" 29 + 30 + static struct drm_display_mode *tpo_vid_get_config_mode(struct drm_device *dev) 31 + { 32 + struct drm_display_mode *mode; 33 + struct drm_psb_private *dev_priv = dev->dev_private; 34 + struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD; 35 + bool use_gct = false; 36 + 37 + mode = kzalloc(sizeof(*mode), GFP_KERNEL); 38 + if (!mode) 39 + return NULL; 40 + 41 + if (use_gct) { 42 + mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo; 43 + mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo; 44 + mode->hsync_start = mode->hdisplay + 45 + ((ti->hsync_offset_hi << 8) | 46 + ti->hsync_offset_lo); 47 + mode->hsync_end = mode->hsync_start + 48 + ((ti->hsync_pulse_width_hi << 8) | 49 + ti->hsync_pulse_width_lo); 50 + mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | 51 + ti->hblank_lo); 52 + mode->vsync_start = 53 + mode->vdisplay + ((ti->vsync_offset_hi << 8) | 54 + ti->vsync_offset_lo); 55 + mode->vsync_end = 56 + mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) | 57 + ti->vsync_pulse_width_lo); 58 + mode->vtotal = mode->vdisplay + 59 + ((ti->vblank_hi << 8) | ti->vblank_lo); 60 + mode->clock = ti->pixel_clock * 10; 61 + 62 + dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay); 63 + dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay); 64 + dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start); 65 + dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end); 66 + dev_dbg(dev->dev, "htotal is %d\n", mode->htotal); 67 + dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start); 68 + dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end); 69 + dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal); 70 + dev_dbg(dev->dev, "clock is %d\n", mode->clock); 71 + } else { 72 + mode->hdisplay = 864; 73 + mode->vdisplay = 480; 74 + mode->hsync_start = 873; 75 + mode->hsync_end = 876; 76 + mode->htotal = 887; 77 + mode->vsync_start = 487; 78 + mode->vsync_end = 490; 79 + mode->vtotal = 499; 80 + mode->clock = 33264; 81 + } 82 + 83 + drm_mode_set_name(mode); 84 + drm_mode_set_crtcinfo(mode, 0); 85 + 86 + mode->type |= DRM_MODE_TYPE_PREFERRED; 87 + 88 + return mode; 89 + } 90 + 91 + static int tpo_vid_get_panel_info(struct drm_device *dev, 92 + int pipe, 93 + struct panel_info *pi) 94 + { 95 + if (!dev || !pi) 96 + return -EINVAL; 97 + 98 + pi->width_mm = TPO_PANEL_WIDTH; 99 + pi->height_mm = TPO_PANEL_HEIGHT; 100 + 101 + return 0; 102 + } 103 + 104 + /*TPO DPI encoder helper funcs*/ 105 + static const struct drm_encoder_helper_funcs 106 + mdfld_tpo_dpi_encoder_helper_funcs = { 107 + .dpms = mdfld_dsi_dpi_dpms, 108 + .mode_fixup = mdfld_dsi_dpi_mode_fixup, 109 + .prepare = mdfld_dsi_dpi_prepare, 110 + .mode_set = mdfld_dsi_dpi_mode_set, 111 + .commit = mdfld_dsi_dpi_commit, 112 + }; 113 + 114 + /*TPO DPI encoder funcs*/ 115 + static const struct drm_encoder_funcs mdfld_tpo_dpi_encoder_funcs = { 116 + .destroy = drm_encoder_cleanup, 117 + }; 118 + 119 + const struct panel_funcs mdfld_tpo_vid_funcs = { 120 + .encoder_funcs = &mdfld_tpo_dpi_encoder_funcs, 121 + .encoder_helper_funcs = &mdfld_tpo_dpi_encoder_helper_funcs, 122 + .get_config_mode = &tpo_vid_get_config_mode, 123 + .get_panel_info = tpo_vid_get_panel_info, 124 + };
+10
drivers/gpu/drm/gma500/psb_drv.c
··· 60 60 /* Atom E620 */ 61 61 { 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, 62 62 #endif 63 + #if defined(CONFIG_DRM_MEDFIELD) 64 + {0x8086, 0x0130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, 65 + {0x8086, 0x0131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, 66 + {0x8086, 0x0132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, 67 + {0x8086, 0x0133, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, 68 + {0x8086, 0x0134, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, 69 + {0x8086, 0x0135, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, 70 + {0x8086, 0x0136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, 71 + {0x8086, 0x0137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, 72 + #endif 63 73 #if defined(CONFIG_DRM_GMA3600) 64 74 { 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, 65 75 { 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
+89
drivers/gpu/drm/gma500/psb_drv.h
··· 389 389 uint32_t savePWM_CONTROL_LOGIC; 390 390 }; 391 391 392 + struct medfield_state { 393 + uint32_t saveDPLL_A; 394 + uint32_t saveFPA0; 395 + uint32_t savePIPEACONF; 396 + uint32_t saveHTOTAL_A; 397 + uint32_t saveHBLANK_A; 398 + uint32_t saveHSYNC_A; 399 + uint32_t saveVTOTAL_A; 400 + uint32_t saveVBLANK_A; 401 + uint32_t saveVSYNC_A; 402 + uint32_t savePIPEASRC; 403 + uint32_t saveDSPASTRIDE; 404 + uint32_t saveDSPALINOFF; 405 + uint32_t saveDSPATILEOFF; 406 + uint32_t saveDSPASIZE; 407 + uint32_t saveDSPAPOS; 408 + uint32_t saveDSPASURF; 409 + uint32_t saveDSPACNTR; 410 + uint32_t saveDSPASTATUS; 411 + uint32_t save_palette_a[256]; 412 + uint32_t saveMIPI; 413 + 414 + uint32_t saveDPLL_B; 415 + uint32_t saveFPB0; 416 + uint32_t savePIPEBCONF; 417 + uint32_t saveHTOTAL_B; 418 + uint32_t saveHBLANK_B; 419 + uint32_t saveHSYNC_B; 420 + uint32_t saveVTOTAL_B; 421 + uint32_t saveVBLANK_B; 422 + uint32_t saveVSYNC_B; 423 + uint32_t savePIPEBSRC; 424 + uint32_t saveDSPBSTRIDE; 425 + uint32_t saveDSPBLINOFF; 426 + uint32_t saveDSPBTILEOFF; 427 + uint32_t saveDSPBSIZE; 428 + uint32_t saveDSPBPOS; 429 + uint32_t saveDSPBSURF; 430 + uint32_t saveDSPBCNTR; 431 + uint32_t saveDSPBSTATUS; 432 + uint32_t save_palette_b[256]; 433 + 434 + uint32_t savePIPECCONF; 435 + uint32_t saveHTOTAL_C; 436 + uint32_t saveHBLANK_C; 437 + uint32_t saveHSYNC_C; 438 + uint32_t saveVTOTAL_C; 439 + uint32_t saveVBLANK_C; 440 + uint32_t saveVSYNC_C; 441 + uint32_t savePIPECSRC; 442 + uint32_t saveDSPCSTRIDE; 443 + uint32_t saveDSPCLINOFF; 444 + uint32_t saveDSPCTILEOFF; 445 + uint32_t saveDSPCSIZE; 446 + uint32_t saveDSPCPOS; 447 + uint32_t saveDSPCSURF; 448 + uint32_t saveDSPCCNTR; 449 + uint32_t saveDSPCSTATUS; 450 + uint32_t save_palette_c[256]; 451 + uint32_t saveMIPI_C; 452 + 453 + uint32_t savePFIT_CONTROL; 454 + uint32_t savePFIT_PGM_RATIOS; 455 + uint32_t saveHDMIPHYMISCCTL; 456 + uint32_t saveHDMIB_CONTROL; 457 + }; 458 + 392 459 struct psb_save_area { 393 460 uint32_t saveBSM; 394 461 uint32_t saveVBT; 395 462 union { 396 463 struct psb_state psb; 464 + struct medfield_state mdfld; 397 465 }; 398 466 uint32_t saveBLC_PWM_CTL2; 399 467 uint32_t saveBLC_PWM_CTL; ··· 631 563 632 564 /* 2D acceleration */ 633 565 spinlock_t lock_2d; 566 + 567 + /* 568 + * Panel brightness 569 + */ 570 + int brightness; 571 + int brightness_adjusted; 572 + 573 + bool dsr_enable; 574 + u32 dsr_fb_update; 575 + bool dpi_panel_on[3]; 576 + void *dsi_configs[2]; 577 + u32 bpp; 578 + u32 bpp2; 579 + 580 + u32 pipeconf[3]; 581 + u32 dspcntr[3]; 582 + 583 + int mdfld_panel_id; 634 584 }; 635 585 636 586 ··· 843 757 844 758 /* oaktrail_device.c */ 845 759 extern const struct psb_ops oaktrail_chip_ops; 760 + 761 + /* mdlfd_device.c */ 762 + extern const struct psb_ops mdfld_chip_ops; 846 763 847 764 /* cdv_device.c */ 848 765 extern const struct psb_ops cdv_chip_ops;
+58
drivers/gpu/drm/gma500/psb_irq.c
··· 27 27 #include "psb_reg.h" 28 28 #include "psb_intel_reg.h" 29 29 #include "power.h" 30 + #include "psb_irq.h" 31 + #include "mdfld_output.h" 30 32 31 33 /* 32 34 * inline functions ··· 455 453 uint32_t reg_val = 0; 456 454 uint32_t pipeconf_reg = mid_pipeconf(pipe); 457 455 456 + /* Medfield is different - we should perhaps extract out vblank 457 + and blacklight etc ops */ 458 + if (IS_MFLD(dev)) 459 + return mdfld_enable_te(dev, pipe); 460 + 458 461 if (gma_power_begin(dev, false)) { 459 462 reg_val = REG_READ(pipeconf_reg); 460 463 gma_power_end(dev); ··· 492 485 struct drm_psb_private *dev_priv = dev->dev_private; 493 486 unsigned long irqflags; 494 487 488 + if (IS_MFLD(dev)) 489 + mdfld_disable_te(dev, pipe); 495 490 spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); 496 491 497 492 if (pipe == 0) ··· 504 495 PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R); 505 496 PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); 506 497 psb_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE); 498 + 499 + spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); 500 + } 501 + 502 + /* 503 + * It is used to enable TE interrupt 504 + */ 505 + int mdfld_enable_te(struct drm_device *dev, int pipe) 506 + { 507 + struct drm_psb_private *dev_priv = 508 + (struct drm_psb_private *) dev->dev_private; 509 + unsigned long irqflags; 510 + uint32_t reg_val = 0; 511 + uint32_t pipeconf_reg = mid_pipeconf(pipe); 512 + 513 + if (gma_power_begin(dev, false)) { 514 + reg_val = REG_READ(pipeconf_reg); 515 + gma_power_end(dev); 516 + } 517 + 518 + if (!(reg_val & PIPEACONF_ENABLE)) 519 + return -EINVAL; 520 + 521 + spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); 522 + 523 + mid_enable_pipe_event(dev_priv, pipe); 524 + psb_enable_pipestat(dev_priv, pipe, PIPE_TE_ENABLE); 525 + 526 + spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); 527 + 528 + return 0; 529 + } 530 + 531 + /* 532 + * It is used to disable TE interrupt 533 + */ 534 + void mdfld_disable_te(struct drm_device *dev, int pipe) 535 + { 536 + struct drm_psb_private *dev_priv = 537 + (struct drm_psb_private *) dev->dev_private; 538 + unsigned long irqflags; 539 + 540 + if (!dev_priv->dsr_enable) 541 + return; 542 + 543 + spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); 544 + 545 + mid_disable_pipe_event(dev_priv, pipe); 546 + psb_disable_pipestat(dev_priv, pipe, PIPE_TE_ENABLE); 507 547 508 548 spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags); 509 549 }
+2
drivers/gpu/drm/gma500/psb_irq.h
··· 42 42 void psb_disable_vblank(struct drm_device *dev, int pipe); 43 43 u32 psb_get_vblank_counter(struct drm_device *dev, int pipe); 44 44 45 + int mdfld_enable_te(struct drm_device *dev, int pipe); 46 + void mdfld_disable_te(struct drm_device *dev, int pipe); 45 47 #endif /* _SYSIRQ_H_ */
+829
drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c
··· 1 + /* 2 + * Copyright © 2011 Intel Corporation 3 + * 4 + * Permission is hereby granted, free of charge, to any person obtaining a 5 + * copy of this software and associated documentation files (the "Software"), 6 + * to deal in the Software without restriction, including without limitation 7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 + * and/or sell copies of the Software, and to permit persons to whom the 9 + * Software is furnished to do so, subject to the following conditions: 10 + * 11 + * The above copyright notice and this permission notice (including the next 12 + * paragraph) shall be included in all copies or substantial portions of the 13 + * Software. 14 + * 15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 + * DEALINGS IN THE SOFTWARE. 22 + * 23 + */ 24 + 25 + #include "mdfld_dsi_dpi.h" 26 + #include "mdfld_output.h" 27 + #include "mdfld_dsi_pkg_sender.h" 28 + #include "tc35876x-dsi-lvds.h" 29 + #include <linux/i2c/tc35876x.h> 30 + #include <linux/kernel.h> 31 + #include <linux/module.h> 32 + #include <asm/intel_scu_ipc.h> 33 + 34 + static struct i2c_client *tc35876x_client; 35 + static struct i2c_client *cmi_lcd_i2c_client; 36 + 37 + #define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) 38 + #define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) 39 + 40 + /* DSI D-PHY Layer Registers */ 41 + #define D0W_DPHYCONTTX 0x0004 42 + #define CLW_DPHYCONTRX 0x0020 43 + #define D0W_DPHYCONTRX 0x0024 44 + #define D1W_DPHYCONTRX 0x0028 45 + #define D2W_DPHYCONTRX 0x002C 46 + #define D3W_DPHYCONTRX 0x0030 47 + #define COM_DPHYCONTRX 0x0038 48 + #define CLW_CNTRL 0x0040 49 + #define D0W_CNTRL 0x0044 50 + #define D1W_CNTRL 0x0048 51 + #define D2W_CNTRL 0x004C 52 + #define D3W_CNTRL 0x0050 53 + #define DFTMODE_CNTRL 0x0054 54 + 55 + /* DSI PPI Layer Registers */ 56 + #define PPI_STARTPPI 0x0104 57 + #define PPI_BUSYPPI 0x0108 58 + #define PPI_LINEINITCNT 0x0110 59 + #define PPI_LPTXTIMECNT 0x0114 60 + #define PPI_LANEENABLE 0x0134 61 + #define PPI_TX_RX_TA 0x013C 62 + #define PPI_CLS_ATMR 0x0140 63 + #define PPI_D0S_ATMR 0x0144 64 + #define PPI_D1S_ATMR 0x0148 65 + #define PPI_D2S_ATMR 0x014C 66 + #define PPI_D3S_ATMR 0x0150 67 + #define PPI_D0S_CLRSIPOCOUNT 0x0164 68 + #define PPI_D1S_CLRSIPOCOUNT 0x0168 69 + #define PPI_D2S_CLRSIPOCOUNT 0x016C 70 + #define PPI_D3S_CLRSIPOCOUNT 0x0170 71 + #define CLS_PRE 0x0180 72 + #define D0S_PRE 0x0184 73 + #define D1S_PRE 0x0188 74 + #define D2S_PRE 0x018C 75 + #define D3S_PRE 0x0190 76 + #define CLS_PREP 0x01A0 77 + #define D0S_PREP 0x01A4 78 + #define D1S_PREP 0x01A8 79 + #define D2S_PREP 0x01AC 80 + #define D3S_PREP 0x01B0 81 + #define CLS_ZERO 0x01C0 82 + #define D0S_ZERO 0x01C4 83 + #define D1S_ZERO 0x01C8 84 + #define D2S_ZERO 0x01CC 85 + #define D3S_ZERO 0x01D0 86 + #define PPI_CLRFLG 0x01E0 87 + #define PPI_CLRSIPO 0x01E4 88 + #define HSTIMEOUT 0x01F0 89 + #define HSTIMEOUTENABLE 0x01F4 90 + 91 + /* DSI Protocol Layer Registers */ 92 + #define DSI_STARTDSI 0x0204 93 + #define DSI_BUSYDSI 0x0208 94 + #define DSI_LANEENABLE 0x0210 95 + #define DSI_LANESTATUS0 0x0214 96 + #define DSI_LANESTATUS1 0x0218 97 + #define DSI_INTSTATUS 0x0220 98 + #define DSI_INTMASK 0x0224 99 + #define DSI_INTCLR 0x0228 100 + #define DSI_LPTXTO 0x0230 101 + 102 + /* DSI General Registers */ 103 + #define DSIERRCNT 0x0300 104 + 105 + /* DSI Application Layer Registers */ 106 + #define APLCTRL 0x0400 107 + #define RDPKTLN 0x0404 108 + 109 + /* Video Path Registers */ 110 + #define VPCTRL 0x0450 111 + #define HTIM1 0x0454 112 + #define HTIM2 0x0458 113 + #define VTIM1 0x045C 114 + #define VTIM2 0x0460 115 + #define VFUEN 0x0464 116 + 117 + /* LVDS Registers */ 118 + #define LVMX0003 0x0480 119 + #define LVMX0407 0x0484 120 + #define LVMX0811 0x0488 121 + #define LVMX1215 0x048C 122 + #define LVMX1619 0x0490 123 + #define LVMX2023 0x0494 124 + #define LVMX2427 0x0498 125 + #define LVCFG 0x049C 126 + #define LVPHY0 0x04A0 127 + #define LVPHY1 0x04A4 128 + 129 + /* System Registers */ 130 + #define SYSSTAT 0x0500 131 + #define SYSRST 0x0504 132 + 133 + /* GPIO Registers */ 134 + /*#define GPIOC 0x0520*/ 135 + #define GPIOO 0x0524 136 + #define GPIOI 0x0528 137 + 138 + /* I2C Registers */ 139 + #define I2CTIMCTRL 0x0540 140 + #define I2CMADDR 0x0544 141 + #define WDATAQ 0x0548 142 + #define RDATAQ 0x054C 143 + 144 + /* Chip/Rev Registers */ 145 + #define IDREG 0x0580 146 + 147 + /* Debug Registers */ 148 + #define DEBUG00 0x05A0 149 + #define DEBUG01 0x05A4 150 + 151 + /* Panel CABC registers */ 152 + #define PANEL_PWM_CONTROL 0x90 153 + #define PANEL_FREQ_DIVIDER_HI 0x91 154 + #define PANEL_FREQ_DIVIDER_LO 0x92 155 + #define PANEL_DUTY_CONTROL 0x93 156 + #define PANEL_MODIFY_RGB 0x94 157 + #define PANEL_FRAMERATE_CONTROL 0x96 158 + #define PANEL_PWM_MIN 0x97 159 + #define PANEL_PWM_REF 0x98 160 + #define PANEL_PWM_MAX 0x99 161 + #define PANEL_ALLOW_DISTORT 0x9A 162 + #define PANEL_BYPASS_PWMI 0x9B 163 + 164 + /* Panel color management registers */ 165 + #define PANEL_CM_ENABLE 0x700 166 + #define PANEL_CM_HUE 0x701 167 + #define PANEL_CM_SATURATION 0x702 168 + #define PANEL_CM_INTENSITY 0x703 169 + #define PANEL_CM_BRIGHTNESS 0x704 170 + #define PANEL_CM_CE_ENABLE 0x705 171 + #define PANEL_CM_PEAK_EN 0x710 172 + #define PANEL_CM_GAIN 0x711 173 + #define PANEL_CM_HUETABLE_START 0x730 174 + #define PANEL_CM_HUETABLE_END 0x747 /* inclusive */ 175 + 176 + /* Input muxing for registers LVMX0003...LVMX2427 */ 177 + enum { 178 + INPUT_R0, /* 0 */ 179 + INPUT_R1, 180 + INPUT_R2, 181 + INPUT_R3, 182 + INPUT_R4, 183 + INPUT_R5, 184 + INPUT_R6, 185 + INPUT_R7, 186 + INPUT_G0, /* 8 */ 187 + INPUT_G1, 188 + INPUT_G2, 189 + INPUT_G3, 190 + INPUT_G4, 191 + INPUT_G5, 192 + INPUT_G6, 193 + INPUT_G7, 194 + INPUT_B0, /* 16 */ 195 + INPUT_B1, 196 + INPUT_B2, 197 + INPUT_B3, 198 + INPUT_B4, 199 + INPUT_B5, 200 + INPUT_B6, 201 + INPUT_B7, 202 + INPUT_HSYNC, /* 24 */ 203 + INPUT_VSYNC, 204 + INPUT_DE, 205 + LOGIC_0, 206 + /* 28...31 undefined */ 207 + }; 208 + 209 + #define INPUT_MUX(lvmx03, lvmx02, lvmx01, lvmx00) \ 210 + (FLD_VAL(lvmx03, 29, 24) | FLD_VAL(lvmx02, 20, 16) | \ 211 + FLD_VAL(lvmx01, 12, 8) | FLD_VAL(lvmx00, 4, 0)) 212 + 213 + /** 214 + * tc35876x_regw - Write DSI-LVDS bridge register using I2C 215 + * @client: struct i2c_client to use 216 + * @reg: register address 217 + * @value: value to write 218 + * 219 + * Returns 0 on success, or a negative error value. 220 + */ 221 + static int tc35876x_regw(struct i2c_client *client, u16 reg, u32 value) 222 + { 223 + int r; 224 + u8 tx_data[] = { 225 + /* NOTE: Register address big-endian, data little-endian. */ 226 + (reg >> 8) & 0xff, 227 + reg & 0xff, 228 + value & 0xff, 229 + (value >> 8) & 0xff, 230 + (value >> 16) & 0xff, 231 + (value >> 24) & 0xff, 232 + }; 233 + struct i2c_msg msgs[] = { 234 + { 235 + .addr = client->addr, 236 + .flags = 0, 237 + .buf = tx_data, 238 + .len = ARRAY_SIZE(tx_data), 239 + }, 240 + }; 241 + 242 + r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 243 + if (r < 0) { 244 + dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x error %d\n", 245 + __func__, reg, value, r); 246 + return r; 247 + } 248 + 249 + if (r < ARRAY_SIZE(msgs)) { 250 + dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x msgs %d\n", 251 + __func__, reg, value, r); 252 + return -EAGAIN; 253 + } 254 + 255 + dev_dbg(&client->dev, "%s: reg 0x%04x val 0x%08x\n", 256 + __func__, reg, value); 257 + 258 + return 0; 259 + } 260 + 261 + /** 262 + * tc35876x_regr - Read DSI-LVDS bridge register using I2C 263 + * @client: struct i2c_client to use 264 + * @reg: register address 265 + * @value: pointer for storing the value 266 + * 267 + * Returns 0 on success, or a negative error value. 268 + */ 269 + static int tc35876x_regr(struct i2c_client *client, u16 reg, u32 *value) 270 + { 271 + int r; 272 + u8 tx_data[] = { 273 + (reg >> 8) & 0xff, 274 + reg & 0xff, 275 + }; 276 + u8 rx_data[4]; 277 + struct i2c_msg msgs[] = { 278 + { 279 + .addr = client->addr, 280 + .flags = 0, 281 + .buf = tx_data, 282 + .len = ARRAY_SIZE(tx_data), 283 + }, 284 + { 285 + .addr = client->addr, 286 + .flags = I2C_M_RD, 287 + .buf = rx_data, 288 + .len = ARRAY_SIZE(rx_data), 289 + }, 290 + }; 291 + 292 + r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 293 + if (r < 0) { 294 + dev_err(&client->dev, "%s: reg 0x%04x error %d\n", __func__, 295 + reg, r); 296 + return r; 297 + } 298 + 299 + if (r < ARRAY_SIZE(msgs)) { 300 + dev_err(&client->dev, "%s: reg 0x%04x msgs %d\n", __func__, 301 + reg, r); 302 + return -EAGAIN; 303 + } 304 + 305 + *value = rx_data[0] << 24 | rx_data[1] << 16 | 306 + rx_data[2] << 8 | rx_data[3]; 307 + 308 + dev_dbg(&client->dev, "%s: reg 0x%04x value 0x%08x\n", __func__, 309 + reg, *value); 310 + 311 + return 0; 312 + } 313 + 314 + void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state) 315 + { 316 + struct tc35876x_platform_data *pdata; 317 + 318 + if (WARN(!tc35876x_client, "%s called before probe", __func__)) 319 + return; 320 + 321 + dev_dbg(&tc35876x_client->dev, "%s: state %d\n", __func__, state); 322 + 323 + pdata = dev_get_platdata(&tc35876x_client->dev); 324 + 325 + if (pdata->gpio_bridge_reset == -1) 326 + return; 327 + 328 + if (state) { 329 + gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0); 330 + mdelay(10); 331 + } else { 332 + /* Pull MIPI Bridge reset pin to Low */ 333 + gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0); 334 + mdelay(20); 335 + /* Pull MIPI Bridge reset pin to High */ 336 + gpio_set_value_cansleep(pdata->gpio_bridge_reset, 1); 337 + mdelay(40); 338 + } 339 + } 340 + 341 + void tc35876x_configure_lvds_bridge(struct drm_device *dev) 342 + { 343 + struct i2c_client *i2c = tc35876x_client; 344 + u32 ppi_lptxtimecnt; 345 + u32 txtagocnt; 346 + u32 txtasurecnt; 347 + u32 id; 348 + 349 + if (WARN(!tc35876x_client, "%s called before probe", __func__)) 350 + return; 351 + 352 + dev_dbg(&tc35876x_client->dev, "%s\n", __func__); 353 + 354 + if (!tc35876x_regr(i2c, IDREG, &id)) 355 + dev_info(&tc35876x_client->dev, "tc35876x ID 0x%08x\n", id); 356 + else 357 + dev_err(&tc35876x_client->dev, "Cannot read ID\n"); 358 + 359 + ppi_lptxtimecnt = 4; 360 + txtagocnt = (5 * ppi_lptxtimecnt - 3) / 4; 361 + txtasurecnt = 3 * ppi_lptxtimecnt / 2; 362 + tc35876x_regw(i2c, PPI_TX_RX_TA, FLD_VAL(txtagocnt, 26, 16) | 363 + FLD_VAL(txtasurecnt, 10, 0)); 364 + tc35876x_regw(i2c, PPI_LPTXTIMECNT, FLD_VAL(ppi_lptxtimecnt, 10, 0)); 365 + 366 + tc35876x_regw(i2c, PPI_D0S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); 367 + tc35876x_regw(i2c, PPI_D1S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); 368 + tc35876x_regw(i2c, PPI_D2S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); 369 + tc35876x_regw(i2c, PPI_D3S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); 370 + 371 + /* Enabling MIPI & PPI lanes, Enable 4 lanes */ 372 + tc35876x_regw(i2c, PPI_LANEENABLE, 373 + BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)); 374 + tc35876x_regw(i2c, DSI_LANEENABLE, 375 + BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)); 376 + tc35876x_regw(i2c, PPI_STARTPPI, BIT(0)); 377 + tc35876x_regw(i2c, DSI_STARTDSI, BIT(0)); 378 + 379 + /* Setting LVDS output frequency */ 380 + tc35876x_regw(i2c, LVPHY0, FLD_VAL(1, 20, 16) | 381 + FLD_VAL(2, 15, 14) | FLD_VAL(6, 4, 0)); /* 0x00048006 */ 382 + 383 + /* Setting video panel control register,0x00000120 VTGen=ON ?!?!? */ 384 + tc35876x_regw(i2c, VPCTRL, BIT(8) | BIT(5)); 385 + 386 + /* Horizontal back porch and horizontal pulse width. 0x00280028 */ 387 + tc35876x_regw(i2c, HTIM1, FLD_VAL(40, 24, 16) | FLD_VAL(40, 8, 0)); 388 + 389 + /* Horizontal front porch and horizontal active video size. 0x00500500*/ 390 + tc35876x_regw(i2c, HTIM2, FLD_VAL(80, 24, 16) | FLD_VAL(1280, 10, 0)); 391 + 392 + /* Vertical back porch and vertical sync pulse width. 0x000e000a */ 393 + tc35876x_regw(i2c, VTIM1, FLD_VAL(14, 23, 16) | FLD_VAL(10, 7, 0)); 394 + 395 + /* Vertical front porch and vertical display size. 0x000e0320 */ 396 + tc35876x_regw(i2c, VTIM2, FLD_VAL(14, 23, 16) | FLD_VAL(800, 10, 0)); 397 + 398 + /* Set above HTIM1, HTIM2, VTIM1, and VTIM2 at next VSYNC. */ 399 + tc35876x_regw(i2c, VFUEN, BIT(0)); 400 + 401 + /* Soft reset LCD controller. */ 402 + tc35876x_regw(i2c, SYSRST, BIT(2)); 403 + 404 + /* LVDS-TX input muxing */ 405 + tc35876x_regw(i2c, LVMX0003, 406 + INPUT_MUX(INPUT_R5, INPUT_R4, INPUT_R3, INPUT_R2)); 407 + tc35876x_regw(i2c, LVMX0407, 408 + INPUT_MUX(INPUT_G2, INPUT_R7, INPUT_R1, INPUT_R6)); 409 + tc35876x_regw(i2c, LVMX0811, 410 + INPUT_MUX(INPUT_G1, INPUT_G0, INPUT_G4, INPUT_G3)); 411 + tc35876x_regw(i2c, LVMX1215, 412 + INPUT_MUX(INPUT_B2, INPUT_G7, INPUT_G6, INPUT_G5)); 413 + tc35876x_regw(i2c, LVMX1619, 414 + INPUT_MUX(INPUT_B4, INPUT_B3, INPUT_B1, INPUT_B0)); 415 + tc35876x_regw(i2c, LVMX2023, 416 + INPUT_MUX(LOGIC_0, INPUT_B7, INPUT_B6, INPUT_B5)); 417 + tc35876x_regw(i2c, LVMX2427, 418 + INPUT_MUX(INPUT_R0, INPUT_DE, INPUT_VSYNC, INPUT_HSYNC)); 419 + 420 + /* Enable LVDS transmitter. */ 421 + tc35876x_regw(i2c, LVCFG, BIT(0)); 422 + 423 + /* Clear notifications. Don't write reserved bits. Was write 0xffffffff 424 + * to 0x0288, must be in error?! */ 425 + tc35876x_regw(i2c, DSI_INTCLR, FLD_MASK(31, 30) | FLD_MASK(22, 0)); 426 + } 427 + 428 + #define GPIOPWMCTRL 0x38F 429 + #define PWM0CLKDIV0 0x62 /* low byte */ 430 + #define PWM0CLKDIV1 0x61 /* high byte */ 431 + 432 + #define SYSTEMCLK 19200000UL /* 19.2 MHz */ 433 + #define PWM_FREQUENCY 9600 /* Hz */ 434 + 435 + /* f = baseclk / (clkdiv + 1) => clkdiv = (baseclk - f) / f */ 436 + static inline u16 calc_clkdiv(unsigned long baseclk, unsigned int f) 437 + { 438 + return (baseclk - f) / f; 439 + } 440 + 441 + static void tc35876x_brightness_init(struct drm_device *dev) 442 + { 443 + int ret; 444 + u8 pwmctrl; 445 + u16 clkdiv; 446 + 447 + /* Make sure the PWM reference is the 19.2 MHz system clock. Read first 448 + * instead of setting directly to catch potential conflicts between PWM 449 + * users. */ 450 + ret = intel_scu_ipc_ioread8(GPIOPWMCTRL, &pwmctrl); 451 + if (ret || pwmctrl != 0x01) { 452 + if (ret) 453 + dev_err(&dev->pdev->dev, "GPIOPWMCTRL read failed\n"); 454 + else 455 + dev_warn(&dev->pdev->dev, "GPIOPWMCTRL was not set to system clock (pwmctrl = 0x%02x)\n", pwmctrl); 456 + 457 + ret = intel_scu_ipc_iowrite8(GPIOPWMCTRL, 0x01); 458 + if (ret) 459 + dev_err(&dev->pdev->dev, "GPIOPWMCTRL set failed\n"); 460 + } 461 + 462 + clkdiv = calc_clkdiv(SYSTEMCLK, PWM_FREQUENCY); 463 + 464 + ret = intel_scu_ipc_iowrite8(PWM0CLKDIV1, (clkdiv >> 8) & 0xff); 465 + if (!ret) 466 + ret = intel_scu_ipc_iowrite8(PWM0CLKDIV0, clkdiv & 0xff); 467 + 468 + if (ret) 469 + dev_err(&dev->pdev->dev, "PWM0CLKDIV set failed\n"); 470 + else 471 + dev_dbg(&dev->pdev->dev, "PWM0CLKDIV set to 0x%04x (%d Hz)\n", 472 + clkdiv, PWM_FREQUENCY); 473 + } 474 + 475 + #define PWM0DUTYCYCLE 0x67 476 + 477 + void tc35876x_brightness_control(struct drm_device *dev, int level) 478 + { 479 + int ret; 480 + u8 duty_val; 481 + u8 panel_duty_val; 482 + 483 + level = clamp(level, 0, MDFLD_DSI_BRIGHTNESS_MAX_LEVEL); 484 + 485 + /* PWM duty cycle 0x00...0x63 corresponds to 0...99% */ 486 + duty_val = level * 0x63 / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL; 487 + 488 + /* I won't pretend to understand this formula. The panel spec is quite 489 + * bad engrish. 490 + */ 491 + panel_duty_val = (2 * level - 100) * 0xA9 / 492 + MDFLD_DSI_BRIGHTNESS_MAX_LEVEL + 0x56; 493 + 494 + ret = intel_scu_ipc_iowrite8(PWM0DUTYCYCLE, duty_val); 495 + if (ret) 496 + dev_err(&tc35876x_client->dev, "%s: ipc write fail\n", 497 + __func__); 498 + 499 + if (cmi_lcd_i2c_client) { 500 + ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, 501 + PANEL_PWM_MAX, panel_duty_val); 502 + if (ret < 0) 503 + dev_err(&cmi_lcd_i2c_client->dev, "%s: i2c write failed\n", 504 + __func__); 505 + } 506 + } 507 + 508 + void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev) 509 + { 510 + struct tc35876x_platform_data *pdata; 511 + 512 + if (WARN(!tc35876x_client, "%s called before probe", __func__)) 513 + return; 514 + 515 + dev_dbg(&tc35876x_client->dev, "%s\n", __func__); 516 + 517 + pdata = dev_get_platdata(&tc35876x_client->dev); 518 + 519 + if (pdata->gpio_panel_bl_en != -1) 520 + gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 0); 521 + 522 + if (pdata->gpio_panel_vadd != -1) 523 + gpio_set_value_cansleep(pdata->gpio_panel_vadd, 0); 524 + } 525 + 526 + void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev) 527 + { 528 + struct tc35876x_platform_data *pdata; 529 + struct drm_psb_private *dev_priv = dev->dev_private; 530 + 531 + if (WARN(!tc35876x_client, "%s called before probe", __func__)) 532 + return; 533 + 534 + dev_dbg(&tc35876x_client->dev, "%s\n", __func__); 535 + 536 + pdata = dev_get_platdata(&tc35876x_client->dev); 537 + 538 + if (pdata->gpio_panel_vadd != -1) { 539 + gpio_set_value_cansleep(pdata->gpio_panel_vadd, 1); 540 + msleep(260); 541 + } 542 + 543 + if (cmi_lcd_i2c_client) { 544 + int ret; 545 + dev_dbg(&cmi_lcd_i2c_client->dev, "setting TCON\n"); 546 + /* Bit 4 is average_saving. Setting it to 1, the brightness is 547 + * referenced to the average of the frame content. 0 means 548 + * reference to the maximum of frame contents. Bits 3:0 are 549 + * allow_distort. When set to a nonzero value, all color values 550 + * between 255-allow_distort*2 and 255 are mapped to the 551 + * 255-allow_distort*2 value. 552 + */ 553 + ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, 554 + PANEL_ALLOW_DISTORT, 0x10); 555 + if (ret < 0) 556 + dev_err(&cmi_lcd_i2c_client->dev, 557 + "i2c write failed (%d)\n", ret); 558 + ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, 559 + PANEL_BYPASS_PWMI, 0); 560 + if (ret < 0) 561 + dev_err(&cmi_lcd_i2c_client->dev, 562 + "i2c write failed (%d)\n", ret); 563 + /* Set minimum brightness value - this is tunable */ 564 + ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, 565 + PANEL_PWM_MIN, 0x35); 566 + if (ret < 0) 567 + dev_err(&cmi_lcd_i2c_client->dev, 568 + "i2c write failed (%d)\n", ret); 569 + } 570 + 571 + if (pdata->gpio_panel_bl_en != -1) 572 + gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 1); 573 + 574 + tc35876x_brightness_control(dev, dev_priv->brightness_adjusted); 575 + } 576 + 577 + static struct drm_display_mode *tc35876x_get_config_mode(struct drm_device *dev) 578 + { 579 + struct drm_display_mode *mode; 580 + 581 + dev_dbg(&dev->pdev->dev, "%s\n", __func__); 582 + 583 + mode = kzalloc(sizeof(*mode), GFP_KERNEL); 584 + if (!mode) 585 + return NULL; 586 + 587 + /* FIXME: do this properly. */ 588 + mode->hdisplay = 1280; 589 + mode->vdisplay = 800; 590 + mode->hsync_start = 1360; 591 + mode->hsync_end = 1400; 592 + mode->htotal = 1440; 593 + mode->vsync_start = 814; 594 + mode->vsync_end = 824; 595 + mode->vtotal = 838; 596 + mode->clock = 33324 << 1; 597 + 598 + dev_info(&dev->pdev->dev, "hdisplay(w) = %d\n", mode->hdisplay); 599 + dev_info(&dev->pdev->dev, "vdisplay(h) = %d\n", mode->vdisplay); 600 + dev_info(&dev->pdev->dev, "HSS = %d\n", mode->hsync_start); 601 + dev_info(&dev->pdev->dev, "HSE = %d\n", mode->hsync_end); 602 + dev_info(&dev->pdev->dev, "htotal = %d\n", mode->htotal); 603 + dev_info(&dev->pdev->dev, "VSS = %d\n", mode->vsync_start); 604 + dev_info(&dev->pdev->dev, "VSE = %d\n", mode->vsync_end); 605 + dev_info(&dev->pdev->dev, "vtotal = %d\n", mode->vtotal); 606 + dev_info(&dev->pdev->dev, "clock = %d\n", mode->clock); 607 + 608 + drm_mode_set_name(mode); 609 + drm_mode_set_crtcinfo(mode, 0); 610 + 611 + mode->type |= DRM_MODE_TYPE_PREFERRED; 612 + 613 + return mode; 614 + } 615 + 616 + /* DV1 Active area 216.96 x 135.6 mm */ 617 + #define DV1_PANEL_WIDTH 217 618 + #define DV1_PANEL_HEIGHT 136 619 + 620 + static int tc35876x_get_panel_info(struct drm_device *dev, int pipe, 621 + struct panel_info *pi) 622 + { 623 + if (!dev || !pi) 624 + return -EINVAL; 625 + 626 + pi->width_mm = DV1_PANEL_WIDTH; 627 + pi->height_mm = DV1_PANEL_HEIGHT; 628 + 629 + return 0; 630 + } 631 + 632 + static int tc35876x_bridge_probe(struct i2c_client *client, 633 + const struct i2c_device_id *id) 634 + { 635 + struct tc35876x_platform_data *pdata; 636 + 637 + dev_info(&client->dev, "%s\n", __func__); 638 + 639 + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 640 + dev_err(&client->dev, "%s: i2c_check_functionality() failed\n", 641 + __func__); 642 + return -ENODEV; 643 + } 644 + 645 + pdata = dev_get_platdata(&client->dev); 646 + if (!pdata) { 647 + dev_err(&client->dev, "%s: no platform data\n", __func__); 648 + return -ENODEV; 649 + } 650 + 651 + if (pdata->gpio_bridge_reset != -1) { 652 + gpio_request(pdata->gpio_bridge_reset, "tc35876x bridge reset"); 653 + gpio_direction_output(pdata->gpio_bridge_reset, 0); 654 + } 655 + 656 + if (pdata->gpio_panel_bl_en != -1) { 657 + gpio_request(pdata->gpio_panel_bl_en, "tc35876x panel bl en"); 658 + gpio_direction_output(pdata->gpio_panel_bl_en, 0); 659 + } 660 + 661 + if (pdata->gpio_panel_vadd != -1) { 662 + gpio_request(pdata->gpio_panel_vadd, "tc35876x panel vadd"); 663 + gpio_direction_output(pdata->gpio_panel_vadd, 0); 664 + } 665 + 666 + tc35876x_client = client; 667 + 668 + return 0; 669 + } 670 + 671 + static int tc35876x_bridge_remove(struct i2c_client *client) 672 + { 673 + struct tc35876x_platform_data *pdata = dev_get_platdata(&client->dev); 674 + 675 + dev_dbg(&client->dev, "%s\n", __func__); 676 + 677 + if (pdata->gpio_bridge_reset != -1) 678 + gpio_free(pdata->gpio_bridge_reset); 679 + 680 + if (pdata->gpio_panel_bl_en != -1) 681 + gpio_free(pdata->gpio_panel_bl_en); 682 + 683 + if (pdata->gpio_panel_vadd != -1) 684 + gpio_free(pdata->gpio_panel_vadd); 685 + 686 + tc35876x_client = NULL; 687 + 688 + return 0; 689 + } 690 + 691 + static const struct i2c_device_id tc35876x_bridge_id[] = { 692 + { "i2c_disp_brig", 0 }, 693 + { } 694 + }; 695 + MODULE_DEVICE_TABLE(i2c, tc35876x_bridge_id); 696 + 697 + static struct i2c_driver tc35876x_bridge_i2c_driver = { 698 + .driver = { 699 + .name = "i2c_disp_brig", 700 + }, 701 + .id_table = tc35876x_bridge_id, 702 + .probe = tc35876x_bridge_probe, 703 + .remove = __devexit_p(tc35876x_bridge_remove), 704 + }; 705 + 706 + /* LCD panel I2C */ 707 + static int cmi_lcd_i2c_probe(struct i2c_client *client, 708 + const struct i2c_device_id *id) 709 + { 710 + dev_info(&client->dev, "%s\n", __func__); 711 + 712 + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 713 + dev_err(&client->dev, "%s: i2c_check_functionality() failed\n", 714 + __func__); 715 + return -ENODEV; 716 + } 717 + 718 + cmi_lcd_i2c_client = client; 719 + 720 + return 0; 721 + } 722 + 723 + static int cmi_lcd_i2c_remove(struct i2c_client *client) 724 + { 725 + dev_dbg(&client->dev, "%s\n", __func__); 726 + 727 + cmi_lcd_i2c_client = NULL; 728 + 729 + return 0; 730 + } 731 + 732 + static const struct i2c_device_id cmi_lcd_i2c_id[] = { 733 + { "cmi-lcd", 0 }, 734 + { } 735 + }; 736 + MODULE_DEVICE_TABLE(i2c, cmi_lcd_i2c_id); 737 + 738 + static struct i2c_driver cmi_lcd_i2c_driver = { 739 + .driver = { 740 + .name = "cmi-lcd", 741 + }, 742 + .id_table = cmi_lcd_i2c_id, 743 + .probe = cmi_lcd_i2c_probe, 744 + .remove = __devexit_p(cmi_lcd_i2c_remove), 745 + }; 746 + 747 + /* HACK to create I2C device while it's not created by platform code */ 748 + #define CMI_LCD_I2C_ADAPTER 2 749 + #define CMI_LCD_I2C_ADDR 0x60 750 + 751 + static int cmi_lcd_hack_create_device(void) 752 + { 753 + struct i2c_adapter *adapter; 754 + struct i2c_client *client; 755 + struct i2c_board_info info = { 756 + .type = "cmi-lcd", 757 + .addr = CMI_LCD_I2C_ADDR, 758 + }; 759 + 760 + pr_debug("%s\n", __func__); 761 + 762 + adapter = i2c_get_adapter(CMI_LCD_I2C_ADAPTER); 763 + if (!adapter) { 764 + pr_err("%s: i2c_get_adapter(%d) failed\n", __func__, 765 + CMI_LCD_I2C_ADAPTER); 766 + return -EINVAL; 767 + } 768 + 769 + client = i2c_new_device(adapter, &info); 770 + if (!client) { 771 + pr_err("%s: i2c_new_device() failed\n", __func__); 772 + i2c_put_adapter(adapter); 773 + return -EINVAL; 774 + } 775 + 776 + return 0; 777 + } 778 + 779 + static const struct drm_encoder_helper_funcs tc35876x_encoder_helper_funcs = { 780 + .dpms = mdfld_dsi_dpi_dpms, 781 + .mode_fixup = mdfld_dsi_dpi_mode_fixup, 782 + .prepare = mdfld_dsi_dpi_prepare, 783 + .mode_set = mdfld_dsi_dpi_mode_set, 784 + .commit = mdfld_dsi_dpi_commit, 785 + }; 786 + 787 + static const struct drm_encoder_funcs tc35876x_encoder_funcs = { 788 + .destroy = drm_encoder_cleanup, 789 + }; 790 + 791 + const struct panel_funcs mdfld_tc35876x_funcs = { 792 + .encoder_funcs = &tc35876x_encoder_funcs, 793 + .encoder_helper_funcs = &tc35876x_encoder_helper_funcs, 794 + .get_config_mode = tc35876x_get_config_mode, 795 + .get_panel_info = tc35876x_get_panel_info, 796 + }; 797 + 798 + void tc35876x_init(struct drm_device *dev) 799 + { 800 + int r; 801 + 802 + dev_dbg(&dev->pdev->dev, "%s\n", __func__); 803 + 804 + cmi_lcd_hack_create_device(); 805 + 806 + r = i2c_add_driver(&cmi_lcd_i2c_driver); 807 + if (r < 0) 808 + dev_err(&dev->pdev->dev, 809 + "%s: i2c_add_driver() for %s failed (%d)\n", 810 + __func__, cmi_lcd_i2c_driver.driver.name, r); 811 + 812 + r = i2c_add_driver(&tc35876x_bridge_i2c_driver); 813 + if (r < 0) 814 + dev_err(&dev->pdev->dev, 815 + "%s: i2c_add_driver() for %s failed (%d)\n", 816 + __func__, tc35876x_bridge_i2c_driver.driver.name, r); 817 + 818 + tc35876x_brightness_init(dev); 819 + } 820 + 821 + void tc35876x_exit(void) 822 + { 823 + pr_debug("%s\n", __func__); 824 + 825 + i2c_del_driver(&tc35876x_bridge_i2c_driver); 826 + 827 + if (cmi_lcd_i2c_client) 828 + i2c_del_driver(&cmi_lcd_i2c_driver); 829 + }
+38
drivers/gpu/drm/gma500/tc35876x-dsi-lvds.h
··· 1 + /* 2 + * Copyright © 2011 Intel Corporation 3 + * 4 + * Permission is hereby granted, free of charge, to any person obtaining a 5 + * copy of this software and associated documentation files (the "Software"), 6 + * to deal in the Software without restriction, including without limitation 7 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 + * and/or sell copies of the Software, and to permit persons to whom the 9 + * Software is furnished to do so, subject to the following conditions: 10 + * 11 + * The above copyright notice and this permission notice (including the next 12 + * paragraph) shall be included in all copies or substantial portions of the 13 + * Software. 14 + * 15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 + * DEALINGS IN THE SOFTWARE. 22 + * 23 + */ 24 + 25 + #ifndef __MDFLD_DSI_LVDS_BRIDGE_H__ 26 + #define __MDFLD_DSI_LVDS_BRIDGE_H__ 27 + 28 + void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state); 29 + void tc35876x_configure_lvds_bridge(struct drm_device *dev); 30 + void tc35876x_brightness_control(struct drm_device *dev, int level); 31 + void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev); 32 + void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev); 33 + void tc35876x_init(struct drm_device *dev); 34 + void tc35876x_exit(void); 35 + 36 + extern const struct panel_funcs mdfld_tc35876x_funcs; 37 + 38 + #endif /*__MDFLD_DSI_LVDS_BRIDGE_H__*/
+11
include/linux/i2c/tc35876x.h
··· 1 + 2 + #ifndef _TC35876X_H 3 + #define _TC35876X_H 4 + 5 + struct tc35876x_platform_data { 6 + int gpio_bridge_reset; 7 + int gpio_panel_bl_en; 8 + int gpio_panel_vadd; 9 + }; 10 + 11 + #endif /* _TC35876X_H */