mirror of https://gitee.com/openkylin/linux.git
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm main changes from Dave Airlie: "This is the main drm pull request, I'm probably going to send two more smaller ones, will explain below. This contains a patch that is also in the fbdev tree, but it should be the same patch, it added an API for hot unplugging framebuffer devices, and I need that API for a new driver. It also contains some changes to the i2c tree which Jean has acked, and one change to moorestown platform stuff in x86. Highlights: - new drivers: UDL driver for USB displaylink devices, kms only, should support correct hotplug operations. - core: i2c speedups + better hotplug support, EDID overriding via firmware interface - allows user to load a firmware for a broken monitor/kvm from userspace, it even has documentation for it. - exynos: new HDMI audio + hdmi 1.4 + virtual output driver - gma500: code cleanup - radeon: cleanups, CS optimisations, streamout support and pageflip fix - nouveau: NVD9 displayport support + more reclocking work - i915: re-enabling GMBUS, finish gpu patch (might help hibernation who knows), missed irq fixes, stencil tiling fixes, interlaced support, aliasesd PPGTT support for SNB/IVB, swizzling for SNB/IVB, semaphore fixes As well as the usual bunch of cleanups and fixes all over the place. I've got two things I'd like to merge a bit later: a) AMD support for all their new radeonhd 7000 series GPU and APUs. AMD dropped this a bit late due to insane internal review processes, (please AMD just follow Intel and let open source guys ship stuff early) however I don't want to penalise people who own this hardware (since its been on sale for 3-4 months and GPU hw doesn't exactly have a lifetime in years) and consign them to using closed drivers for longer than necessary. The changes are well contained and just plug into the driver new gpu functionality so they should be fairly regression proof. I just want to give them a bit of a run on the hw AMD kindly sent me. b) drm prime/dma-buf interface code. This is just infrastructure code to expose the dma-buf stuff to drm drivers and to userspace. I'm not planning on pushing any driver support in this cycle (except maybe exynos), but I'd like to get the infrastructure code in so for the next cycle I can start getting the driver support into the individual drivers. We have started driver support for i915, nouveau and udl along with I think exynos and omap in staging. However this code relies on the dma-buf tree being pulled into your tree first since it needs the latest interfaces from that tree. I'll push to get that tree sent asap. (oh and any warnings you see in i915 are gcc's fault from what anyone can see)." Fix up trivial conflicts in arch/x86/platform/mrst/mrst.c due to the new msic_thermal_platform_data() thermal function being added next to the tc35876x_platform_data() i2c device function.. * 'drm-next' of git://people.freedesktop.org/~airlied/linux: (326 commits) drm/i915: use DDC_ADDR instead of hard-coding it drm/radeon: use DDC_ADDR instead of hard-coding it drm: remove unneeded redefinition of DDC_ADDR drm/exynos: added virtual display driver. drm: allow loading an EDID as firmware to override broken monitor drm/exynos: enable hdmi audio feature drm/exynos: add default pixel format for plane drm/exynos: cleanup exynos_hdmi.h drm/exynos: add is_local member in exynos_drm_subdrv struct drm/exynos: add subdrv open/close functions drm/exynos: remove module of exynos drm subdrv drm/exynos: release pending pageflip events when closed drm/exynos: added new funtion to get/put dma address. drm/exynos: update gem and buffer framework. drm/exynos: added mode_fixup feature and code clean. drm/exynos: add HDMI version 1.4 support drm/exynos: remove exynos_mixer.h gma500: Fix mmap frambuffer drm/radeon: Drop radeon_gem_object_(un)pin. drm/radeon: Restrict offset for legacy display engine. ...
This commit is contained in:
commit
be53bfdb80
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
1024x768.S: EDID data set for standard 1024x768 60 Hz monitor
|
||||
|
||||
Copyright (C) 2011 Carsten Emde <C.Emde@osadl.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/* EDID */
|
||||
#define VERSION 1
|
||||
#define REVISION 3
|
||||
|
||||
/* Display */
|
||||
#define CLOCK 65000 /* kHz */
|
||||
#define XPIX 1024
|
||||
#define YPIX 768
|
||||
#define XY_RATIO XY_RATIO_4_3
|
||||
#define XBLANK 320
|
||||
#define YBLANK 38
|
||||
#define XOFFSET 8
|
||||
#define XPULSE 144
|
||||
#define YOFFSET (63+3)
|
||||
#define YPULSE (63+6)
|
||||
#define DPI 72
|
||||
#define VFREQ 60 /* Hz */
|
||||
#define TIMING_NAME "Linux XGA"
|
||||
#define ESTABLISHED_TIMINGS_BITS 0x08 /* Bit 3 -> 1024x768 @60 Hz */
|
||||
#define HSYNC_POL 0
|
||||
#define VSYNC_POL 0
|
||||
#define CRC 0x55
|
||||
|
||||
#include "edid.S"
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
1280x1024.S: EDID data set for standard 1280x1024 60 Hz monitor
|
||||
|
||||
Copyright (C) 2011 Carsten Emde <C.Emde@osadl.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/* EDID */
|
||||
#define VERSION 1
|
||||
#define REVISION 3
|
||||
|
||||
/* Display */
|
||||
#define CLOCK 108000 /* kHz */
|
||||
#define XPIX 1280
|
||||
#define YPIX 1024
|
||||
#define XY_RATIO XY_RATIO_5_4
|
||||
#define XBLANK 408
|
||||
#define YBLANK 42
|
||||
#define XOFFSET 48
|
||||
#define XPULSE 112
|
||||
#define YOFFSET (63+1)
|
||||
#define YPULSE (63+3)
|
||||
#define DPI 72
|
||||
#define VFREQ 60 /* Hz */
|
||||
#define TIMING_NAME "Linux SXGA"
|
||||
#define ESTABLISHED_TIMINGS_BITS 0x00 /* none */
|
||||
#define HSYNC_POL 1
|
||||
#define VSYNC_POL 1
|
||||
#define CRC 0xa0
|
||||
|
||||
#include "edid.S"
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
1680x1050.S: EDID data set for standard 1680x1050 60 Hz monitor
|
||||
|
||||
Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/* EDID */
|
||||
#define VERSION 1
|
||||
#define REVISION 3
|
||||
|
||||
/* Display */
|
||||
#define CLOCK 146250 /* kHz */
|
||||
#define XPIX 1680
|
||||
#define YPIX 1050
|
||||
#define XY_RATIO XY_RATIO_16_10
|
||||
#define XBLANK 560
|
||||
#define YBLANK 39
|
||||
#define XOFFSET 104
|
||||
#define XPULSE 176
|
||||
#define YOFFSET (63+3)
|
||||
#define YPULSE (63+6)
|
||||
#define DPI 96
|
||||
#define VFREQ 60 /* Hz */
|
||||
#define TIMING_NAME "Linux WSXGA"
|
||||
#define ESTABLISHED_TIMINGS_BITS 0x00 /* none */
|
||||
#define HSYNC_POL 1
|
||||
#define VSYNC_POL 1
|
||||
#define CRC 0x26
|
||||
|
||||
#include "edid.S"
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
1920x1080.S: EDID data set for standard 1920x1080 60 Hz monitor
|
||||
|
||||
Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/* EDID */
|
||||
#define VERSION 1
|
||||
#define REVISION 3
|
||||
|
||||
/* Display */
|
||||
#define CLOCK 148500 /* kHz */
|
||||
#define XPIX 1920
|
||||
#define YPIX 1080
|
||||
#define XY_RATIO XY_RATIO_16_9
|
||||
#define XBLANK 280
|
||||
#define YBLANK 45
|
||||
#define XOFFSET 88
|
||||
#define XPULSE 44
|
||||
#define YOFFSET (63+4)
|
||||
#define YPULSE (63+5)
|
||||
#define DPI 96
|
||||
#define VFREQ 60 /* Hz */
|
||||
#define TIMING_NAME "Linux FHD"
|
||||
#define ESTABLISHED_TIMINGS_BITS 0x00 /* none */
|
||||
#define HSYNC_POL 1
|
||||
#define VSYNC_POL 1
|
||||
#define CRC 0x05
|
||||
|
||||
#include "edid.S"
|
|
@ -0,0 +1,39 @@
|
|||
In the good old days when graphics parameters were configured explicitly
|
||||
in a file called xorg.conf, even broken hardware could be managed.
|
||||
|
||||
Today, with the advent of Kernel Mode Setting, a graphics board is
|
||||
either correctly working because all components follow the standards -
|
||||
or the computer is unusable, because the screen remains dark after
|
||||
booting or it displays the wrong area. Cases when this happens are:
|
||||
- The graphics board does not recognize the monitor.
|
||||
- The graphics board is unable to detect any EDID data.
|
||||
- The graphics board incorrectly forwards EDID data to the driver.
|
||||
- The monitor sends no or bogus EDID data.
|
||||
- A KVM sends its own EDID data instead of querying the connected monitor.
|
||||
Adding the kernel parameter "nomodeset" helps in most cases, but causes
|
||||
restrictions later on.
|
||||
|
||||
As a remedy for such situations, the kernel configuration item
|
||||
CONFIG_DRM_LOAD_EDID_FIRMWARE was introduced. It allows to provide an
|
||||
individually prepared or corrected EDID data set in the /lib/firmware
|
||||
directory from where it is loaded via the firmware interface. The code
|
||||
(see drivers/gpu/drm/drm_edid_load.c) contains built-in data sets for
|
||||
commonly used screen resolutions (1024x768, 1280x1024, 1680x1050,
|
||||
1920x1080) as binary blobs, but the kernel source tree does not contain
|
||||
code to create these data. In order to elucidate the origin of the
|
||||
built-in binary EDID blobs and to facilitate the creation of individual
|
||||
data for a specific misbehaving monitor, commented sources and a
|
||||
Makefile environment are given here.
|
||||
|
||||
To create binary EDID and C source code files from the existing data
|
||||
material, simply type "make".
|
||||
|
||||
If you want to create your own EDID file, copy the file 1024x768.S and
|
||||
replace the settings with your own data. The CRC value in the last line
|
||||
#define CRC 0x55
|
||||
is a bit tricky. After a first version of the binary data set is
|
||||
created, it must be be checked with the "edid-decode" utility which will
|
||||
most probably complain about a wrong CRC. Fortunately, the utility also
|
||||
displays the correct CRC which must then be inserted into the source
|
||||
file. After the make procedure is repeated, the EDID data set is ready
|
||||
to be used.
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
SOURCES := $(wildcard [0-9]*x[0-9]*.S)
|
||||
|
||||
BIN := $(patsubst %.S, %.bin, $(SOURCES))
|
||||
|
||||
IHEX := $(patsubst %.S, %.bin.ihex, $(SOURCES))
|
||||
|
||||
CODE := $(patsubst %.S, %.c, $(SOURCES))
|
||||
|
||||
all: $(BIN) $(IHEX) $(CODE)
|
||||
|
||||
clean:
|
||||
@rm -f *.o *.bin.ihex *.bin *.c
|
||||
|
||||
%.o: %.S
|
||||
@cc -c $^
|
||||
|
||||
%.bin: %.o
|
||||
@objcopy -Obinary $^ $@
|
||||
|
||||
%.bin.ihex: %.o
|
||||
@objcopy -Oihex $^ $@
|
||||
@dos2unix $@ 2>/dev/null
|
||||
|
||||
%.c: %.bin
|
||||
@echo "{" >$@; hexdump -f hex $^ >>$@; echo "};" >>$@
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
edid.S: EDID data template
|
||||
|
||||
Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
|
||||
/* Manufacturer */
|
||||
#define MFG_LNX1 'L'
|
||||
#define MFG_LNX2 'N'
|
||||
#define MFG_LNX3 'X'
|
||||
#define SERIAL 0
|
||||
#define YEAR 2012
|
||||
#define WEEK 5
|
||||
|
||||
/* EDID 1.3 standard definitions */
|
||||
#define XY_RATIO_16_10 0b00
|
||||
#define XY_RATIO_4_3 0b01
|
||||
#define XY_RATIO_5_4 0b10
|
||||
#define XY_RATIO_16_9 0b11
|
||||
|
||||
#define mfgname2id(v1,v2,v3) \
|
||||
((((v1-'@')&0x1f)<<10)+(((v2-'@')&0x1f)<<5)+((v3-'@')&0x1f))
|
||||
#define swap16(v1) ((v1>>8)+((v1&0xff)<<8))
|
||||
#define msbs2(v1,v2) ((((v1>>8)&0x0f)<<4)+((v2>>8)&0x0f))
|
||||
#define msbs4(v1,v2,v3,v4) \
|
||||
(((v1&0x03)>>2)+((v2&0x03)>>4)+((v3&0x03)>>6)+((v4&0x03)>>8))
|
||||
#define pixdpi2mm(pix,dpi) ((pix*25)/dpi)
|
||||
#define xsize pixdpi2mm(XPIX,DPI)
|
||||
#define ysize pixdpi2mm(YPIX,DPI)
|
||||
|
||||
.data
|
||||
|
||||
/* Fixed header pattern */
|
||||
header: .byte 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x00
|
||||
|
||||
mfg_id: .word swap16(mfgname2id(MFG_LNX1, MFG_LNX2, MFG_LNX3))
|
||||
|
||||
prod_code: .word 0
|
||||
|
||||
/* Serial number. 32 bits, little endian. */
|
||||
serial_number: .long SERIAL
|
||||
|
||||
/* Week of manufacture */
|
||||
week: .byte WEEK
|
||||
|
||||
/* Year of manufacture, less 1990. (1990-2245)
|
||||
If week=255, it is the model year instead */
|
||||
year: .byte YEAR-1990
|
||||
|
||||
version: .byte VERSION /* EDID version, usually 1 (for 1.3) */
|
||||
revision: .byte REVISION /* EDID revision, usually 3 (for 1.3) */
|
||||
|
||||
/* If Bit 7=1 Digital input. If set, the following bit definitions apply:
|
||||
Bits 6-1 Reserved, must be 0
|
||||
Bit 0 Signal is compatible with VESA DFP 1.x TMDS CRGB,
|
||||
1 pixel per clock, up to 8 bits per color, MSB aligned,
|
||||
If Bit 7=0 Analog input. If clear, the following bit definitions apply:
|
||||
Bits 6-5 Video white and sync levels, relative to blank
|
||||
00=+0.7/-0.3 V; 01=+0.714/-0.286 V;
|
||||
10=+1.0/-0.4 V; 11=+0.7/0 V
|
||||
Bit 4 Blank-to-black setup (pedestal) expected
|
||||
Bit 3 Separate sync supported
|
||||
Bit 2 Composite sync (on HSync) supported
|
||||
Bit 1 Sync on green supported
|
||||
Bit 0 VSync pulse must be serrated when somposite or
|
||||
sync-on-green is used. */
|
||||
video_parms: .byte 0x6d
|
||||
|
||||
/* Maximum horizontal image size, in centimetres
|
||||
(max 292 cm/115 in at 16:9 aspect ratio) */
|
||||
max_hor_size: .byte xsize/10
|
||||
|
||||
/* Maximum vertical image size, in centimetres.
|
||||
If either byte is 0, undefined (e.g. projector) */
|
||||
max_vert_size: .byte ysize/10
|
||||
|
||||
/* Display gamma, minus 1, times 100 (range 1.00-3.5 */
|
||||
gamma: .byte 120
|
||||
|
||||
/* Bit 7 DPMS standby supported
|
||||
Bit 6 DPMS suspend supported
|
||||
Bit 5 DPMS active-off supported
|
||||
Bits 4-3 Display type: 00=monochrome; 01=RGB colour;
|
||||
10=non-RGB multicolour; 11=undefined
|
||||
Bit 2 Standard sRGB colour space. Bytes 25-34 must contain
|
||||
sRGB standard values.
|
||||
Bit 1 Preferred timing mode specified in descriptor block 1.
|
||||
Bit 0 GTF supported with default parameter values. */
|
||||
dsp_features: .byte 0xea
|
||||
|
||||
/* Chromaticity coordinates. */
|
||||
/* Red and green least-significant bits
|
||||
Bits 7-6 Red x value least-significant 2 bits
|
||||
Bits 5-4 Red y value least-significant 2 bits
|
||||
Bits 3-2 Green x value lst-significant 2 bits
|
||||
Bits 1-0 Green y value least-significant 2 bits */
|
||||
red_green_lsb: .byte 0x5e
|
||||
|
||||
/* Blue and white least-significant 2 bits */
|
||||
blue_white_lsb: .byte 0xc0
|
||||
|
||||
/* Red x value most significant 8 bits.
|
||||
0-255 encodes 0-0.996 (255/256); 0-0.999 (1023/1024) with lsbits */
|
||||
red_x_msb: .byte 0xa4
|
||||
|
||||
/* Red y value most significant 8 bits */
|
||||
red_y_msb: .byte 0x59
|
||||
|
||||
/* Green x and y value most significant 8 bits */
|
||||
green_x_y_msb: .byte 0x4a,0x98
|
||||
|
||||
/* Blue x and y value most significant 8 bits */
|
||||
blue_x_y_msb: .byte 0x25,0x20
|
||||
|
||||
/* Default white point x and y value most significant 8 bits */
|
||||
white_x_y_msb: .byte 0x50,0x54
|
||||
|
||||
/* Established timings */
|
||||
/* Bit 7 720x400 @ 70 Hz
|
||||
Bit 6 720x400 @ 88 Hz
|
||||
Bit 5 640x480 @ 60 Hz
|
||||
Bit 4 640x480 @ 67 Hz
|
||||
Bit 3 640x480 @ 72 Hz
|
||||
Bit 2 640x480 @ 75 Hz
|
||||
Bit 1 800x600 @ 56 Hz
|
||||
Bit 0 800x600 @ 60 Hz */
|
||||
estbl_timing1: .byte 0x00
|
||||
|
||||
/* Bit 7 800x600 @ 72 Hz
|
||||
Bit 6 800x600 @ 75 Hz
|
||||
Bit 5 832x624 @ 75 Hz
|
||||
Bit 4 1024x768 @ 87 Hz, interlaced (1024x768)
|
||||
Bit 3 1024x768 @ 60 Hz
|
||||
Bit 2 1024x768 @ 72 Hz
|
||||
Bit 1 1024x768 @ 75 Hz
|
||||
Bit 0 1280x1024 @ 75 Hz */
|
||||
estbl_timing2: .byte ESTABLISHED_TIMINGS_BITS
|
||||
|
||||
/* Bit 7 1152x870 @ 75 Hz (Apple Macintosh II)
|
||||
Bits 6-0 Other manufacturer-specific display mod */
|
||||
estbl_timing3: .byte 0x00
|
||||
|
||||
/* Standard timing */
|
||||
/* X resolution, less 31, divided by 8 (256-2288 pixels) */
|
||||
std_xres: .byte (XPIX/8)-31
|
||||
/* Y resolution, X:Y pixel ratio
|
||||
Bits 7-6 X:Y pixel ratio: 00=16:10; 01=4:3; 10=5:4; 11=16:9.
|
||||
Bits 5-0 Vertical frequency, less 60 (60-123 Hz) */
|
||||
std_vres: .byte (XY_RATIO<<6)+VFREQ-60
|
||||
.fill 7,2,0x0101 /* Unused */
|
||||
|
||||
descriptor1:
|
||||
/* Pixel clock in 10 kHz units. (0.-655.35 MHz, little-endian) */
|
||||
clock: .word CLOCK/10
|
||||
|
||||
/* Horizontal active pixels 8 lsbits (0-4095) */
|
||||
x_act_lsb: .byte XPIX&0xff
|
||||
/* Horizontal blanking pixels 8 lsbits (0-4095)
|
||||
End of active to start of next active. */
|
||||
x_blk_lsb: .byte XBLANK&0xff
|
||||
/* Bits 7-4 Horizontal active pixels 4 msbits
|
||||
Bits 3-0 Horizontal blanking pixels 4 msbits */
|
||||
x_msbs: .byte msbs2(XPIX,XBLANK)
|
||||
|
||||
/* Vertical active lines 8 lsbits (0-4095) */
|
||||
y_act_lsb: .byte YPIX&0xff
|
||||
/* Vertical blanking lines 8 lsbits (0-4095) */
|
||||
y_blk_lsb: .byte YBLANK&0xff
|
||||
/* Bits 7-4 Vertical active lines 4 msbits
|
||||
Bits 3-0 Vertical blanking lines 4 msbits */
|
||||
y_msbs: .byte msbs2(YPIX,YBLANK)
|
||||
|
||||
/* Horizontal sync offset pixels 8 lsbits (0-1023) From blanking start */
|
||||
x_snc_off_lsb: .byte XOFFSET&0xff
|
||||
/* Horizontal sync pulse width pixels 8 lsbits (0-1023) */
|
||||
x_snc_pls_lsb: .byte XPULSE&0xff
|
||||
/* Bits 7-4 Vertical sync offset lines 4 lsbits -63)
|
||||
Bits 3-0 Vertical sync pulse width lines 4 lsbits -63) */
|
||||
y_snc_lsb: .byte ((YOFFSET-63)<<4)+(YPULSE-63)
|
||||
/* Bits 7-6 Horizontal sync offset pixels 2 msbits
|
||||
Bits 5-4 Horizontal sync pulse width pixels 2 msbits
|
||||
Bits 3-2 Vertical sync offset lines 2 msbits
|
||||
Bits 1-0 Vertical sync pulse width lines 2 msbits */
|
||||
xy_snc_msbs: .byte msbs4(XOFFSET,XPULSE,YOFFSET,YPULSE)
|
||||
|
||||
/* Horizontal display size, mm, 8 lsbits (0-4095 mm, 161 in) */
|
||||
x_dsp_size: .byte xsize&0xff
|
||||
|
||||
/* Vertical display size, mm, 8 lsbits (0-4095 mm, 161 in) */
|
||||
y_dsp_size: .byte ysize&0xff
|
||||
|
||||
/* Bits 7-4 Horizontal display size, mm, 4 msbits
|
||||
Bits 3-0 Vertical display size, mm, 4 msbits */
|
||||
dsp_size_mbsb: .byte msbs2(xsize,ysize)
|
||||
|
||||
/* Horizontal border pixels (each side; total is twice this) */
|
||||
x_border: .byte 0
|
||||
/* Vertical border lines (each side; total is twice this) */
|
||||
y_border: .byte 0
|
||||
|
||||
/* Bit 7 Interlaced
|
||||
Bits 6-5 Stereo mode: 00=No stereo; other values depend on bit 0:
|
||||
Bit 0=0: 01=Field sequential, sync=1 during right; 10=similar,
|
||||
sync=1 during left; 11=4-way interleaved stereo
|
||||
Bit 0=1 2-way interleaved stereo: 01=Right image on even lines;
|
||||
10=Left image on even lines; 11=side-by-side
|
||||
Bits 4-3 Sync type: 00=Analog composite; 01=Bipolar analog composite;
|
||||
10=Digital composite (on HSync); 11=Digital separate
|
||||
Bit 2 If digital separate: Vertical sync polarity (1=positive)
|
||||
Other types: VSync serrated (HSync during VSync)
|
||||
Bit 1 If analog sync: Sync on all 3 RGB lines (else green only)
|
||||
Digital: HSync polarity (1=positive)
|
||||
Bit 0 2-way line-interleaved stereo, if bits 4-3 are not 00. */
|
||||
features: .byte 0x18+(VSYNC_POL<<2)+(HSYNC_POL<<1)
|
||||
|
||||
descriptor2: .byte 0,0 /* Not a detailed timing descriptor */
|
||||
.byte 0 /* Must be zero */
|
||||
.byte 0xff /* Descriptor is monitor serial number (text) */
|
||||
.byte 0 /* Must be zero */
|
||||
start1: .ascii "Linux #0"
|
||||
end1: .byte 0x0a /* End marker */
|
||||
.fill 12-(end1-start1), 1, 0x20 /* Padded spaces */
|
||||
descriptor3: .byte 0,0 /* Not a detailed timing descriptor */
|
||||
.byte 0 /* Must be zero */
|
||||
.byte 0xfd /* Descriptor is monitor range limits */
|
||||
.byte 0 /* Must be zero */
|
||||
start2: .byte VFREQ-1 /* Minimum vertical field rate (1-255 Hz) */
|
||||
.byte VFREQ+1 /* Maximum vertical field rate (1-255 Hz) */
|
||||
.byte (CLOCK/(XPIX+XBLANK))-1 /* Minimum horizontal line rate
|
||||
(1-255 kHz) */
|
||||
.byte (CLOCK/(XPIX+XBLANK))+1 /* Maximum horizontal line rate
|
||||
(1-255 kHz) */
|
||||
.byte (CLOCK/10000)+1 /* Maximum pixel clock rate, rounded up
|
||||
to 10 MHz multiple (10-2550 MHz) */
|
||||
.byte 0 /* No extended timing information type */
|
||||
end2: .byte 0x0a /* End marker */
|
||||
.fill 12-(end2-start2), 1, 0x20 /* Padded spaces */
|
||||
descriptor4: .byte 0,0 /* Not a detailed timing descriptor */
|
||||
.byte 0 /* Must be zero */
|
||||
.byte 0xfc /* Descriptor is text */
|
||||
.byte 0 /* Must be zero */
|
||||
start3: .ascii TIMING_NAME
|
||||
end3: .byte 0x0a /* End marker */
|
||||
.fill 12-(end3-start3), 1, 0x20 /* Padded spaces */
|
||||
extensions: .byte 0 /* Number of extensions to follow */
|
||||
checksum: .byte CRC /* Sum of all bytes must be 0 */
|
|
@ -0,0 +1 @@
|
|||
"\t" 8/1 "0x%02x, " "\n"
|
|
@ -713,6 +713,21 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||
The filter can be disabled or changed to another
|
||||
driver later using sysfs.
|
||||
|
||||
drm_kms_helper.edid_firmware=[<connector>:]<file>
|
||||
Broken monitors, graphic adapters and KVMs may
|
||||
send no or incorrect EDID data sets. This parameter
|
||||
allows to specify an EDID data set in the
|
||||
/lib/firmware directory that is used instead.
|
||||
Generic built-in EDID data sets are used, if one of
|
||||
edid/1024x768.bin, edid/1280x1024.bin,
|
||||
edid/1680x1050.bin, or edid/1920x1080.bin is given
|
||||
and no file with the same name exists. Details and
|
||||
instructions how to build your own EDID data are
|
||||
available in Documentation/EDID/HOWTO.txt. An EDID
|
||||
data set will only be used for a particular connector,
|
||||
if its name and a colon are prepended to the EDID
|
||||
name.
|
||||
|
||||
dscc4.setup= [NET]
|
||||
|
||||
earlycon= [KNL] Output early console device and options.
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/mfd/intel_msic.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c/tc35876x.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/mpspec_def.h>
|
||||
|
@ -675,6 +677,19 @@ static void *msic_thermal_platform_data(void *info)
|
|||
return msic_generic_platform_data(info, INTEL_MSIC_BLOCK_THERMAL);
|
||||
}
|
||||
|
||||
/* tc35876x DSI-LVDS bridge chip and panel platform data */
|
||||
static void *tc35876x_platform_data(void *data)
|
||||
{
|
||||
static struct tc35876x_platform_data pdata;
|
||||
|
||||
/* gpio pins set to -1 will not be used by the driver */
|
||||
pdata.gpio_bridge_reset = get_gpio_by_name("LCMB_RXEN");
|
||||
pdata.gpio_panel_bl_en = get_gpio_by_name("6S6P_BL_EN");
|
||||
pdata.gpio_panel_vadd = get_gpio_by_name("EN_VREG_LCD_V3P3");
|
||||
|
||||
return &pdata;
|
||||
}
|
||||
|
||||
static const struct devs_id __initconst device_ids[] = {
|
||||
{"bma023", SFI_DEV_TYPE_I2C, 1, &no_platform_data},
|
||||
{"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data},
|
||||
|
@ -687,6 +702,7 @@ static const struct devs_id __initconst device_ids[] = {
|
|||
{"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data},
|
||||
{"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data},
|
||||
{"mpu3050", SFI_DEV_TYPE_I2C, 1, &mpu3050_platform_data},
|
||||
{"i2c_disp_brig", SFI_DEV_TYPE_I2C, 0, &tc35876x_platform_data},
|
||||
|
||||
/* MSIC subdevices */
|
||||
{"msic_battery", SFI_DEV_TYPE_IPC, 1, &msic_battery_platform_data},
|
||||
|
|
|
@ -850,6 +850,7 @@ static struct pci_device_id agp_intel_pci_table[] = {
|
|||
.subvendor = PCI_ANY_ID, \
|
||||
.subdevice = PCI_ANY_ID, \
|
||||
}
|
||||
ID(PCI_DEVICE_ID_INTEL_82441), /* for HAS2 support */
|
||||
ID(PCI_DEVICE_ID_INTEL_82443LX_0),
|
||||
ID(PCI_DEVICE_ID_INTEL_82443BX_0),
|
||||
ID(PCI_DEVICE_ID_INTEL_82443GX_0),
|
||||
|
|
|
@ -76,7 +76,6 @@ static struct _intel_private {
|
|||
struct resource ifp_resource;
|
||||
int resource_valid;
|
||||
struct page *scratch_page;
|
||||
dma_addr_t scratch_page_dma;
|
||||
} intel_private;
|
||||
|
||||
#define INTEL_GTT_GEN intel_private.driver->gen
|
||||
|
@ -306,9 +305,9 @@ static int intel_gtt_setup_scratch_page(void)
|
|||
if (pci_dma_mapping_error(intel_private.pcidev, dma_addr))
|
||||
return -EINVAL;
|
||||
|
||||
intel_private.scratch_page_dma = dma_addr;
|
||||
intel_private.base.scratch_page_dma = dma_addr;
|
||||
} else
|
||||
intel_private.scratch_page_dma = page_to_phys(page);
|
||||
intel_private.base.scratch_page_dma = page_to_phys(page);
|
||||
|
||||
intel_private.scratch_page = page;
|
||||
|
||||
|
@ -631,7 +630,7 @@ static unsigned int intel_gtt_mappable_entries(void)
|
|||
static void intel_gtt_teardown_scratch_page(void)
|
||||
{
|
||||
set_pages_wb(intel_private.scratch_page, 1);
|
||||
pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma,
|
||||
pci_unmap_page(intel_private.pcidev, intel_private.base.scratch_page_dma,
|
||||
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
|
||||
put_page(intel_private.scratch_page);
|
||||
__free_page(intel_private.scratch_page);
|
||||
|
@ -681,6 +680,7 @@ static int intel_gtt_init(void)
|
|||
iounmap(intel_private.registers);
|
||||
return -ENOMEM;
|
||||
}
|
||||
intel_private.base.gtt = intel_private.gtt;
|
||||
|
||||
global_cache_flush(); /* FIXME: ? */
|
||||
|
||||
|
@ -975,7 +975,7 @@ void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries)
|
|||
unsigned int i;
|
||||
|
||||
for (i = first_entry; i < (first_entry + num_entries); i++) {
|
||||
intel_private.driver->write_entry(intel_private.scratch_page_dma,
|
||||
intel_private.driver->write_entry(intel_private.base.scratch_page_dma,
|
||||
i, 0);
|
||||
}
|
||||
readl(intel_private.gtt+i-1);
|
||||
|
|
|
@ -18,6 +18,11 @@ menuconfig DRM
|
|||
details. You should also select and configure AGP
|
||||
(/dev/agpgart) support if it is available for your platform.
|
||||
|
||||
config DRM_USB
|
||||
tristate
|
||||
depends on DRM
|
||||
select USB
|
||||
|
||||
config DRM_KMS_HELPER
|
||||
tristate
|
||||
depends on DRM
|
||||
|
@ -27,6 +32,18 @@ config DRM_KMS_HELPER
|
|||
help
|
||||
FB and CRTC helpers for KMS drivers.
|
||||
|
||||
config DRM_LOAD_EDID_FIRMWARE
|
||||
bool "Allow to specify an EDID data set instead of probing for it"
|
||||
depends on DRM_KMS_HELPER
|
||||
help
|
||||
Say Y here, if you want to use EDID data to be loaded from the
|
||||
/lib/firmware directory or one of the provided built-in
|
||||
data sets. This may be necessary, if the graphics adapter or
|
||||
monitor are unable to provide appropriate EDID data. Since this
|
||||
feature is provided as a workaround for broken hardware, the
|
||||
default case is N. Details and instructions how to build your own
|
||||
EDID data are given in Documentation/EDID/HOWTO.txt.
|
||||
|
||||
config DRM_TTM
|
||||
tristate
|
||||
depends on DRM
|
||||
|
@ -165,3 +182,4 @@ source "drivers/gpu/drm/vmwgfx/Kconfig"
|
|||
|
||||
source "drivers/gpu/drm/gma500/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/udl/Kconfig"
|
||||
|
|
|
@ -12,17 +12,21 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
|
|||
drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \
|
||||
drm_crtc.o drm_modes.o drm_edid.o \
|
||||
drm_info.o drm_debugfs.o drm_encoder_slave.o \
|
||||
drm_trace_points.o drm_global.o drm_usb.o
|
||||
drm_trace_points.o drm_global.o
|
||||
|
||||
drm-$(CONFIG_COMPAT) += drm_ioc32.o
|
||||
|
||||
drm-usb-y := drm_usb.o
|
||||
|
||||
drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o drm_dp_i2c_helper.o
|
||||
drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
|
||||
|
||||
obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
|
||||
|
||||
CFLAGS_drm_trace_points.o := -I$(src)
|
||||
|
||||
obj-$(CONFIG_DRM) += drm.o
|
||||
obj-$(CONFIG_DRM_USB) += drm_usb.o
|
||||
obj-$(CONFIG_DRM_TTM) += ttm/
|
||||
obj-$(CONFIG_DRM_TDFX) += tdfx/
|
||||
obj-$(CONFIG_DRM_R128) += r128/
|
||||
|
@ -37,4 +41,5 @@ obj-$(CONFIG_DRM_VIA) +=via/
|
|||
obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
|
||||
obj-$(CONFIG_DRM_EXYNOS) +=exynos/
|
||||
obj-$(CONFIG_DRM_GMA500) += gma500/
|
||||
obj-$(CONFIG_DRM_UDL) += udl/
|
||||
obj-y += i2c/
|
||||
|
|
|
@ -38,11 +38,6 @@
|
|||
#include "drm_edid.h"
|
||||
#include "drm_fourcc.h"
|
||||
|
||||
struct drm_prop_enum_list {
|
||||
int type;
|
||||
char *name;
|
||||
};
|
||||
|
||||
/* Avoid boilerplate. I'm tired of typing. */
|
||||
#define DRM_ENUM_NAME_FN(fnname, list) \
|
||||
char *fnname(int val) \
|
||||
|
@ -298,9 +293,8 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
|
|||
int ret;
|
||||
|
||||
ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
fb->dev = dev;
|
||||
fb->funcs = funcs;
|
||||
|
@ -370,19 +364,31 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
|
|||
* Caller must hold mode config lock.
|
||||
*
|
||||
* Inits a new object created as base part of an driver crtc object.
|
||||
*
|
||||
* RETURNS:
|
||||
* Zero on success, error code on failure.
|
||||
*/
|
||||
void drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
|
||||
int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
|
||||
const struct drm_crtc_funcs *funcs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
crtc->dev = dev;
|
||||
crtc->funcs = funcs;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
|
||||
|
||||
ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
|
||||
dev->mode_config.num_crtc++;
|
||||
|
||||
out:
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_crtc_init);
|
||||
|
||||
|
@ -442,7 +448,7 @@ void drm_mode_remove(struct drm_connector *connector,
|
|||
struct drm_display_mode *mode)
|
||||
{
|
||||
list_del(&mode->head);
|
||||
kfree(mode);
|
||||
drm_mode_destroy(connector->dev, mode);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_remove);
|
||||
|
||||
|
@ -454,21 +460,29 @@ EXPORT_SYMBOL(drm_mode_remove);
|
|||
* @name: user visible name of the connector
|
||||
*
|
||||
* LOCKING:
|
||||
* Caller must hold @dev's mode_config lock.
|
||||
* Takes mode config lock.
|
||||
*
|
||||
* Initialises a preallocated connector. Connectors should be
|
||||
* subclassed as part of driver connector objects.
|
||||
*
|
||||
* RETURNS:
|
||||
* Zero on success, error code on failure.
|
||||
*/
|
||||
void drm_connector_init(struct drm_device *dev,
|
||||
struct drm_connector *connector,
|
||||
const struct drm_connector_funcs *funcs,
|
||||
int connector_type)
|
||||
int drm_connector_init(struct drm_device *dev,
|
||||
struct drm_connector *connector,
|
||||
const struct drm_connector_funcs *funcs,
|
||||
int connector_type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
|
||||
ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
connector->dev = dev;
|
||||
connector->funcs = funcs;
|
||||
drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
|
||||
connector->connector_type = connector_type;
|
||||
connector->connector_type_id =
|
||||
++drm_connector_enum_list[connector_type].count; /* TODO */
|
||||
|
@ -488,7 +502,10 @@ void drm_connector_init(struct drm_device *dev,
|
|||
drm_connector_attach_property(connector,
|
||||
dev->mode_config.dpms_property, 0);
|
||||
|
||||
out:
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_connector_init);
|
||||
|
||||
|
@ -497,7 +514,7 @@ EXPORT_SYMBOL(drm_connector_init);
|
|||
* @connector: connector to cleanup
|
||||
*
|
||||
* LOCKING:
|
||||
* Caller must hold @dev's mode_config lock.
|
||||
* Takes mode config lock.
|
||||
*
|
||||
* Cleans up the connector but doesn't free the object.
|
||||
*/
|
||||
|
@ -523,23 +540,41 @@ void drm_connector_cleanup(struct drm_connector *connector)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_connector_cleanup);
|
||||
|
||||
void drm_encoder_init(struct drm_device *dev,
|
||||
void drm_connector_unplug_all(struct drm_device *dev)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
|
||||
/* taking the mode config mutex ends up in a clash with sysfs */
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
|
||||
drm_sysfs_connector_remove(connector);
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(drm_connector_unplug_all);
|
||||
|
||||
int drm_encoder_init(struct drm_device *dev,
|
||||
struct drm_encoder *encoder,
|
||||
const struct drm_encoder_funcs *funcs,
|
||||
int encoder_type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
|
||||
encoder->dev = dev;
|
||||
ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
|
||||
encoder->dev = dev;
|
||||
encoder->encoder_type = encoder_type;
|
||||
encoder->funcs = funcs;
|
||||
|
||||
list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
|
||||
dev->mode_config.num_encoder++;
|
||||
|
||||
out:
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_encoder_init);
|
||||
|
||||
|
@ -560,18 +595,23 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
|
|||
const uint32_t *formats, uint32_t format_count,
|
||||
bool priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
|
||||
ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
plane->dev = dev;
|
||||
drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
|
||||
plane->funcs = funcs;
|
||||
plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
|
||||
GFP_KERNEL);
|
||||
if (!plane->format_types) {
|
||||
DRM_DEBUG_KMS("out of memory when allocating plane\n");
|
||||
drm_mode_object_put(dev, &plane->base);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
return -ENOMEM;
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
|
||||
|
@ -589,9 +629,10 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
|
|||
INIT_LIST_HEAD(&plane->head);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_plane_init);
|
||||
|
||||
|
@ -631,7 +672,11 @@ struct drm_display_mode *drm_mode_create(struct drm_device *dev)
|
|||
if (!nmode)
|
||||
return NULL;
|
||||
|
||||
drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE);
|
||||
if (drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) {
|
||||
kfree(nmode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return nmode;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_create);
|
||||
|
@ -648,6 +693,9 @@ EXPORT_SYMBOL(drm_mode_create);
|
|||
*/
|
||||
void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
|
||||
{
|
||||
if (!mode)
|
||||
return;
|
||||
|
||||
drm_mode_object_put(dev, &mode->base);
|
||||
|
||||
kfree(mode);
|
||||
|
@ -658,7 +706,6 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
|
|||
{
|
||||
struct drm_property *edid;
|
||||
struct drm_property *dpms;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Standard properties (apply to all connectors)
|
||||
|
@ -668,11 +715,9 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
|
|||
"EDID", 0);
|
||||
dev->mode_config.edid_property = edid;
|
||||
|
||||
dpms = drm_property_create(dev, DRM_MODE_PROP_ENUM,
|
||||
"DPMS", ARRAY_SIZE(drm_dpms_enum_list));
|
||||
for (i = 0; i < ARRAY_SIZE(drm_dpms_enum_list); i++)
|
||||
drm_property_add_enum(dpms, i, drm_dpms_enum_list[i].type,
|
||||
drm_dpms_enum_list[i].name);
|
||||
dpms = drm_property_create_enum(dev, 0,
|
||||
"DPMS", drm_dpms_enum_list,
|
||||
ARRAY_SIZE(drm_dpms_enum_list));
|
||||
dev->mode_config.dpms_property = dpms;
|
||||
|
||||
return 0;
|
||||
|
@ -688,30 +733,21 @@ int drm_mode_create_dvi_i_properties(struct drm_device *dev)
|
|||
{
|
||||
struct drm_property *dvi_i_selector;
|
||||
struct drm_property *dvi_i_subconnector;
|
||||
int i;
|
||||
|
||||
if (dev->mode_config.dvi_i_select_subconnector_property)
|
||||
return 0;
|
||||
|
||||
dvi_i_selector =
|
||||
drm_property_create(dev, DRM_MODE_PROP_ENUM,
|
||||
drm_property_create_enum(dev, 0,
|
||||
"select subconnector",
|
||||
drm_dvi_i_select_enum_list,
|
||||
ARRAY_SIZE(drm_dvi_i_select_enum_list));
|
||||
for (i = 0; i < ARRAY_SIZE(drm_dvi_i_select_enum_list); i++)
|
||||
drm_property_add_enum(dvi_i_selector, i,
|
||||
drm_dvi_i_select_enum_list[i].type,
|
||||
drm_dvi_i_select_enum_list[i].name);
|
||||
dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector;
|
||||
|
||||
dvi_i_subconnector =
|
||||
drm_property_create(dev, DRM_MODE_PROP_ENUM |
|
||||
DRM_MODE_PROP_IMMUTABLE,
|
||||
dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
|
||||
"subconnector",
|
||||
drm_dvi_i_subconnector_enum_list,
|
||||
ARRAY_SIZE(drm_dvi_i_subconnector_enum_list));
|
||||
for (i = 0; i < ARRAY_SIZE(drm_dvi_i_subconnector_enum_list); i++)
|
||||
drm_property_add_enum(dvi_i_subconnector, i,
|
||||
drm_dvi_i_subconnector_enum_list[i].type,
|
||||
drm_dvi_i_subconnector_enum_list[i].name);
|
||||
dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector;
|
||||
|
||||
return 0;
|
||||
|
@ -742,51 +778,33 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
|
|||
/*
|
||||
* Basic connector properties
|
||||
*/
|
||||
tv_selector = drm_property_create(dev, DRM_MODE_PROP_ENUM,
|
||||
tv_selector = drm_property_create_enum(dev, 0,
|
||||
"select subconnector",
|
||||
drm_tv_select_enum_list,
|
||||
ARRAY_SIZE(drm_tv_select_enum_list));
|
||||
for (i = 0; i < ARRAY_SIZE(drm_tv_select_enum_list); i++)
|
||||
drm_property_add_enum(tv_selector, i,
|
||||
drm_tv_select_enum_list[i].type,
|
||||
drm_tv_select_enum_list[i].name);
|
||||
dev->mode_config.tv_select_subconnector_property = tv_selector;
|
||||
|
||||
tv_subconnector =
|
||||
drm_property_create(dev, DRM_MODE_PROP_ENUM |
|
||||
DRM_MODE_PROP_IMMUTABLE, "subconnector",
|
||||
drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
|
||||
"subconnector",
|
||||
drm_tv_subconnector_enum_list,
|
||||
ARRAY_SIZE(drm_tv_subconnector_enum_list));
|
||||
for (i = 0; i < ARRAY_SIZE(drm_tv_subconnector_enum_list); i++)
|
||||
drm_property_add_enum(tv_subconnector, i,
|
||||
drm_tv_subconnector_enum_list[i].type,
|
||||
drm_tv_subconnector_enum_list[i].name);
|
||||
dev->mode_config.tv_subconnector_property = tv_subconnector;
|
||||
|
||||
/*
|
||||
* Other, TV specific properties: margins & TV modes.
|
||||
*/
|
||||
dev->mode_config.tv_left_margin_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"left margin", 2);
|
||||
dev->mode_config.tv_left_margin_property->values[0] = 0;
|
||||
dev->mode_config.tv_left_margin_property->values[1] = 100;
|
||||
drm_property_create_range(dev, 0, "left margin", 0, 100);
|
||||
|
||||
dev->mode_config.tv_right_margin_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"right margin", 2);
|
||||
dev->mode_config.tv_right_margin_property->values[0] = 0;
|
||||
dev->mode_config.tv_right_margin_property->values[1] = 100;
|
||||
drm_property_create_range(dev, 0, "right margin", 0, 100);
|
||||
|
||||
dev->mode_config.tv_top_margin_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"top margin", 2);
|
||||
dev->mode_config.tv_top_margin_property->values[0] = 0;
|
||||
dev->mode_config.tv_top_margin_property->values[1] = 100;
|
||||
drm_property_create_range(dev, 0, "top margin", 0, 100);
|
||||
|
||||
dev->mode_config.tv_bottom_margin_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"bottom margin", 2);
|
||||
dev->mode_config.tv_bottom_margin_property->values[0] = 0;
|
||||
dev->mode_config.tv_bottom_margin_property->values[1] = 100;
|
||||
drm_property_create_range(dev, 0, "bottom margin", 0, 100);
|
||||
|
||||
dev->mode_config.tv_mode_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_ENUM,
|
||||
|
@ -796,40 +814,22 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
|
|||
i, modes[i]);
|
||||
|
||||
dev->mode_config.tv_brightness_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"brightness", 2);
|
||||
dev->mode_config.tv_brightness_property->values[0] = 0;
|
||||
dev->mode_config.tv_brightness_property->values[1] = 100;
|
||||
drm_property_create_range(dev, 0, "brightness", 0, 100);
|
||||
|
||||
dev->mode_config.tv_contrast_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"contrast", 2);
|
||||
dev->mode_config.tv_contrast_property->values[0] = 0;
|
||||
dev->mode_config.tv_contrast_property->values[1] = 100;
|
||||
drm_property_create_range(dev, 0, "contrast", 0, 100);
|
||||
|
||||
dev->mode_config.tv_flicker_reduction_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"flicker reduction", 2);
|
||||
dev->mode_config.tv_flicker_reduction_property->values[0] = 0;
|
||||
dev->mode_config.tv_flicker_reduction_property->values[1] = 100;
|
||||
drm_property_create_range(dev, 0, "flicker reduction", 0, 100);
|
||||
|
||||
dev->mode_config.tv_overscan_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"overscan", 2);
|
||||
dev->mode_config.tv_overscan_property->values[0] = 0;
|
||||
dev->mode_config.tv_overscan_property->values[1] = 100;
|
||||
drm_property_create_range(dev, 0, "overscan", 0, 100);
|
||||
|
||||
dev->mode_config.tv_saturation_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"saturation", 2);
|
||||
dev->mode_config.tv_saturation_property->values[0] = 0;
|
||||
dev->mode_config.tv_saturation_property->values[1] = 100;
|
||||
drm_property_create_range(dev, 0, "saturation", 0, 100);
|
||||
|
||||
dev->mode_config.tv_hue_property =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"hue", 2);
|
||||
dev->mode_config.tv_hue_property->values[0] = 0;
|
||||
dev->mode_config.tv_hue_property->values[1] = 100;
|
||||
drm_property_create_range(dev, 0, "hue", 0, 100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -845,18 +845,14 @@ EXPORT_SYMBOL(drm_mode_create_tv_properties);
|
|||
int drm_mode_create_scaling_mode_property(struct drm_device *dev)
|
||||
{
|
||||
struct drm_property *scaling_mode;
|
||||
int i;
|
||||
|
||||
if (dev->mode_config.scaling_mode_property)
|
||||
return 0;
|
||||
|
||||
scaling_mode =
|
||||
drm_property_create(dev, DRM_MODE_PROP_ENUM, "scaling mode",
|
||||
drm_property_create_enum(dev, 0, "scaling mode",
|
||||
drm_scaling_mode_enum_list,
|
||||
ARRAY_SIZE(drm_scaling_mode_enum_list));
|
||||
for (i = 0; i < ARRAY_SIZE(drm_scaling_mode_enum_list); i++)
|
||||
drm_property_add_enum(scaling_mode, i,
|
||||
drm_scaling_mode_enum_list[i].type,
|
||||
drm_scaling_mode_enum_list[i].name);
|
||||
|
||||
dev->mode_config.scaling_mode_property = scaling_mode;
|
||||
|
||||
|
@ -874,18 +870,14 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
|
|||
int drm_mode_create_dithering_property(struct drm_device *dev)
|
||||
{
|
||||
struct drm_property *dithering_mode;
|
||||
int i;
|
||||
|
||||
if (dev->mode_config.dithering_mode_property)
|
||||
return 0;
|
||||
|
||||
dithering_mode =
|
||||
drm_property_create(dev, DRM_MODE_PROP_ENUM, "dithering",
|
||||
drm_property_create_enum(dev, 0, "dithering",
|
||||
drm_dithering_mode_enum_list,
|
||||
ARRAY_SIZE(drm_dithering_mode_enum_list));
|
||||
for (i = 0; i < ARRAY_SIZE(drm_dithering_mode_enum_list); i++)
|
||||
drm_property_add_enum(dithering_mode, i,
|
||||
drm_dithering_mode_enum_list[i].type,
|
||||
drm_dithering_mode_enum_list[i].name);
|
||||
dev->mode_config.dithering_mode_property = dithering_mode;
|
||||
|
||||
return 0;
|
||||
|
@ -902,20 +894,15 @@ EXPORT_SYMBOL(drm_mode_create_dithering_property);
|
|||
int drm_mode_create_dirty_info_property(struct drm_device *dev)
|
||||
{
|
||||
struct drm_property *dirty_info;
|
||||
int i;
|
||||
|
||||
if (dev->mode_config.dirty_info_property)
|
||||
return 0;
|
||||
|
||||
dirty_info =
|
||||
drm_property_create(dev, DRM_MODE_PROP_ENUM |
|
||||
DRM_MODE_PROP_IMMUTABLE,
|
||||
drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
|
||||
"dirty",
|
||||
drm_dirty_info_enum_list,
|
||||
ARRAY_SIZE(drm_dirty_info_enum_list));
|
||||
for (i = 0; i < ARRAY_SIZE(drm_dirty_info_enum_list); i++)
|
||||
drm_property_add_enum(dirty_info, i,
|
||||
drm_dirty_info_enum_list[i].type,
|
||||
drm_dirty_info_enum_list[i].name);
|
||||
dev->mode_config.dirty_info_property = dirty_info;
|
||||
|
||||
return 0;
|
||||
|
@ -999,6 +986,7 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
|
||||
|
||||
/**
|
||||
* drm_mode_config_cleanup - free up DRM mode_config info
|
||||
|
@ -1048,6 +1036,9 @@ void drm_mode_config_cleanup(struct drm_device *dev)
|
|||
head) {
|
||||
plane->funcs->destroy(plane);
|
||||
}
|
||||
|
||||
idr_remove_all(&dev->mode_config.crtc_idr);
|
||||
idr_destroy(&dev->mode_config.crtc_idr);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_config_cleanup);
|
||||
|
||||
|
@ -1062,9 +1053,16 @@ EXPORT_SYMBOL(drm_mode_config_cleanup);
|
|||
* Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
|
||||
* the user.
|
||||
*/
|
||||
void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
|
||||
struct drm_display_mode *in)
|
||||
static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
|
||||
const struct drm_display_mode *in)
|
||||
{
|
||||
WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX ||
|
||||
in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX ||
|
||||
in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX ||
|
||||
in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX ||
|
||||
in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX,
|
||||
"timing values too large for mode info\n");
|
||||
|
||||
out->clock = in->clock;
|
||||
out->hdisplay = in->hdisplay;
|
||||
out->hsync_start = in->hsync_start;
|
||||
|
@ -1093,10 +1091,16 @@ void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
|
|||
*
|
||||
* Convert a drm_mode_modeinfo into a drm_display_mode structure to return to
|
||||
* the caller.
|
||||
*
|
||||
* RETURNS:
|
||||
* Zero on success, errno on failure.
|
||||
*/
|
||||
void drm_crtc_convert_umode(struct drm_display_mode *out,
|
||||
struct drm_mode_modeinfo *in)
|
||||
static int drm_crtc_convert_umode(struct drm_display_mode *out,
|
||||
const struct drm_mode_modeinfo *in)
|
||||
{
|
||||
if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
|
||||
return -ERANGE;
|
||||
|
||||
out->clock = in->clock;
|
||||
out->hdisplay = in->hdisplay;
|
||||
out->hsync_start = in->hsync_start;
|
||||
|
@ -1113,6 +1117,8 @@ void drm_crtc_convert_umode(struct drm_display_mode *out,
|
|||
out->type = in->type;
|
||||
strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
|
||||
out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1311,7 +1317,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
|
|||
* @arg: arg from ioctl
|
||||
*
|
||||
* LOCKING:
|
||||
* Caller? (FIXME)
|
||||
* Takes mode config lock.
|
||||
*
|
||||
* Construct a CRTC configuration structure to return to the user.
|
||||
*
|
||||
|
@ -1371,7 +1377,7 @@ int drm_mode_getcrtc(struct drm_device *dev,
|
|||
* @arg: arg from ioctl
|
||||
*
|
||||
* LOCKING:
|
||||
* Caller? (FIXME)
|
||||
* Takes mode config lock.
|
||||
*
|
||||
* Construct a connector configuration structure to return to the user.
|
||||
*
|
||||
|
@ -1553,6 +1559,9 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
|
|||
* @data: ioctl data
|
||||
* @file_priv: DRM file info
|
||||
*
|
||||
* LOCKING:
|
||||
* Takes mode config lock.
|
||||
*
|
||||
* Return an plane count and set of IDs.
|
||||
*/
|
||||
int drm_mode_getplane_res(struct drm_device *dev, void *data,
|
||||
|
@ -1599,6 +1608,9 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
|
|||
* @data: ioctl data
|
||||
* @file_priv: DRM file info
|
||||
*
|
||||
* LOCKING:
|
||||
* Takes mode config lock.
|
||||
*
|
||||
* Return plane info, including formats supported, gamma size, any
|
||||
* current fb, etc.
|
||||
*/
|
||||
|
@ -1664,6 +1676,9 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
|
|||
* @data: ioctl data*
|
||||
* @file_prive: DRM file info
|
||||
*
|
||||
* LOCKING:
|
||||
* Takes mode config lock.
|
||||
*
|
||||
* Set plane info, including placement, fb, scaling, and other factors.
|
||||
* Or pass a NULL fb to disable.
|
||||
*/
|
||||
|
@ -1794,7 +1809,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
|
|||
* @arg: arg from ioctl
|
||||
*
|
||||
* LOCKING:
|
||||
* Caller? (FIXME)
|
||||
* Takes mode config lock.
|
||||
*
|
||||
* Build a new CRTC configuration based on user request.
|
||||
*
|
||||
|
@ -1809,7 +1824,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
|
|||
struct drm_mode_config *config = &dev->mode_config;
|
||||
struct drm_mode_crtc *crtc_req = data;
|
||||
struct drm_mode_object *obj;
|
||||
struct drm_crtc *crtc, *crtcfb;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_connector **connector_set = NULL, *connector;
|
||||
struct drm_framebuffer *fb = NULL;
|
||||
struct drm_display_mode *mode = NULL;
|
||||
|
@ -1821,6 +1836,10 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
|
|||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
||||
/* For some reason crtc x/y offsets are signed internally. */
|
||||
if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX)
|
||||
return -ERANGE;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
obj = drm_mode_object_find(dev, crtc_req->crtc_id,
|
||||
DRM_MODE_OBJECT_CRTC);
|
||||
|
@ -1836,14 +1855,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
|
|||
/* If we have a mode we need a framebuffer. */
|
||||
/* If we pass -1, set the mode with the currently bound fb */
|
||||
if (crtc_req->fb_id == -1) {
|
||||
list_for_each_entry(crtcfb,
|
||||
&dev->mode_config.crtc_list, head) {
|
||||
if (crtcfb == crtc) {
|
||||
DRM_DEBUG_KMS("Using current fb for "
|
||||
"setmode\n");
|
||||
fb = crtc->fb;
|
||||
}
|
||||
if (!crtc->fb) {
|
||||
DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
fb = crtc->fb;
|
||||
} else {
|
||||
obj = drm_mode_object_find(dev, crtc_req->fb_id,
|
||||
DRM_MODE_OBJECT_FB);
|
||||
|
@ -1857,8 +1874,30 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
|
|||
}
|
||||
|
||||
mode = drm_mode_create(dev);
|
||||
drm_crtc_convert_umode(mode, &crtc_req->mode);
|
||||
if (!mode) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = drm_crtc_convert_umode(mode, &crtc_req->mode);
|
||||
if (ret) {
|
||||
DRM_DEBUG_KMS("Invalid mode\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
|
||||
|
||||
if (mode->hdisplay > fb->width ||
|
||||
mode->vdisplay > fb->height ||
|
||||
crtc_req->x > fb->width - mode->hdisplay ||
|
||||
crtc_req->y > fb->height - mode->vdisplay) {
|
||||
DRM_DEBUG_KMS("Invalid CRTC viewport %ux%u+%u+%u for fb size %ux%u.\n",
|
||||
mode->hdisplay, mode->vdisplay,
|
||||
crtc_req->x, crtc_req->y,
|
||||
fb->width, fb->height);
|
||||
ret = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (crtc_req->count_connectors == 0 && mode) {
|
||||
|
@ -1926,6 +1965,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
|
|||
|
||||
out:
|
||||
kfree(connector_set);
|
||||
drm_mode_destroy(dev, mode);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
return ret;
|
||||
}
|
||||
|
@ -2275,7 +2315,7 @@ int drm_mode_rmfb(struct drm_device *dev,
|
|||
* @arg: arg from ioctl
|
||||
*
|
||||
* LOCKING:
|
||||
* Caller? (FIXME)
|
||||
* Takes mode config lock.
|
||||
*
|
||||
* Lookup the FB given its ID and return info about it.
|
||||
*
|
||||
|
@ -2424,38 +2464,48 @@ void drm_fb_release(struct drm_file *priv)
|
|||
*
|
||||
* Add @mode to @connector's user mode list.
|
||||
*/
|
||||
static int drm_mode_attachmode(struct drm_device *dev,
|
||||
struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
static void drm_mode_attachmode(struct drm_device *dev,
|
||||
struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
list_add_tail(&mode->head, &connector->user_modes);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode)
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
int ret = 0;
|
||||
struct drm_display_mode *dup_mode;
|
||||
int need_dup = 0;
|
||||
struct drm_display_mode *dup_mode, *next;
|
||||
LIST_HEAD(list);
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (!connector->encoder)
|
||||
break;
|
||||
continue;
|
||||
if (connector->encoder->crtc == crtc) {
|
||||
if (need_dup)
|
||||
dup_mode = drm_mode_duplicate(dev, mode);
|
||||
else
|
||||
dup_mode = mode;
|
||||
ret = drm_mode_attachmode(dev, connector, dup_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
need_dup = 1;
|
||||
dup_mode = drm_mode_duplicate(dev, mode);
|
||||
if (!dup_mode) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
list_add_tail(&dup_mode->head, &list);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (!connector->encoder)
|
||||
continue;
|
||||
if (connector->encoder->crtc == crtc)
|
||||
list_move_tail(list.next, &connector->user_modes);
|
||||
}
|
||||
|
||||
WARN_ON(!list_empty(&list));
|
||||
|
||||
out:
|
||||
list_for_each_entry_safe(dup_mode, next, &list, head)
|
||||
drm_mode_destroy(dev, dup_mode);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_attachmode_crtc);
|
||||
|
||||
|
@ -2534,9 +2584,14 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev,
|
|||
goto out;
|
||||
}
|
||||
|
||||
drm_crtc_convert_umode(mode, umode);
|
||||
ret = drm_crtc_convert_umode(mode, umode);
|
||||
if (ret) {
|
||||
DRM_DEBUG_KMS("Invalid mode\n");
|
||||
drm_mode_destroy(dev, mode);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = drm_mode_attachmode(dev, connector, mode);
|
||||
drm_mode_attachmode(dev, connector, mode);
|
||||
out:
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
return ret;
|
||||
|
@ -2577,7 +2632,12 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev,
|
|||
}
|
||||
connector = obj_to_connector(obj);
|
||||
|
||||
drm_crtc_convert_umode(&mode, umode);
|
||||
ret = drm_crtc_convert_umode(&mode, umode);
|
||||
if (ret) {
|
||||
DRM_DEBUG_KMS("Invalid mode\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = drm_mode_detachmode(dev, connector, &mode);
|
||||
out:
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
@ -2588,6 +2648,7 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
|
|||
const char *name, int num_values)
|
||||
{
|
||||
struct drm_property *property = NULL;
|
||||
int ret;
|
||||
|
||||
property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
|
||||
if (!property)
|
||||
|
@ -2599,7 +2660,10 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
|
||||
ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
property->flags = flags;
|
||||
property->num_values = num_values;
|
||||
INIT_LIST_HEAD(&property->enum_blob_list);
|
||||
|
@ -2612,11 +2676,59 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
|
|||
list_add_tail(&property->head, &dev->mode_config.property_list);
|
||||
return property;
|
||||
fail:
|
||||
kfree(property->values);
|
||||
kfree(property);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_create);
|
||||
|
||||
struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
|
||||
const char *name,
|
||||
const struct drm_prop_enum_list *props,
|
||||
int num_values)
|
||||
{
|
||||
struct drm_property *property;
|
||||
int i, ret;
|
||||
|
||||
flags |= DRM_MODE_PROP_ENUM;
|
||||
|
||||
property = drm_property_create(dev, flags, name, num_values);
|
||||
if (!property)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < num_values; i++) {
|
||||
ret = drm_property_add_enum(property, i,
|
||||
props[i].type,
|
||||
props[i].name);
|
||||
if (ret) {
|
||||
drm_property_destroy(dev, property);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_create_enum);
|
||||
|
||||
struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
|
||||
const char *name,
|
||||
uint64_t min, uint64_t max)
|
||||
{
|
||||
struct drm_property *property;
|
||||
|
||||
flags |= DRM_MODE_PROP_RANGE;
|
||||
|
||||
property = drm_property_create(dev, flags, name, 2);
|
||||
if (!property)
|
||||
return NULL;
|
||||
|
||||
property->values[0] = min;
|
||||
property->values[1] = max;
|
||||
|
||||
return property;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_property_create_range);
|
||||
|
||||
int drm_property_add_enum(struct drm_property *property, int index,
|
||||
uint64_t value, const char *name)
|
||||
{
|
||||
|
@ -2828,6 +2940,7 @@ static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev
|
|||
void *data)
|
||||
{
|
||||
struct drm_property_blob *blob;
|
||||
int ret;
|
||||
|
||||
if (!length || !data)
|
||||
return NULL;
|
||||
|
@ -2836,13 +2949,16 @@ static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev
|
|||
if (!blob)
|
||||
return NULL;
|
||||
|
||||
blob->data = (void *)((char *)blob + sizeof(struct drm_property_blob));
|
||||
ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB);
|
||||
if (ret) {
|
||||
kfree(blob);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
blob->length = length;
|
||||
|
||||
memcpy(blob->data, data, length);
|
||||
|
||||
drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB);
|
||||
|
||||
list_add_tail(&blob->head, &dev->mode_config.property_blob_list);
|
||||
return blob;
|
||||
}
|
||||
|
@ -3021,7 +3137,7 @@ void drm_mode_connector_detach_encoder(struct drm_connector *connector,
|
|||
}
|
||||
EXPORT_SYMBOL(drm_mode_connector_detach_encoder);
|
||||
|
||||
bool drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
|
||||
int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
|
||||
int gamma_size)
|
||||
{
|
||||
crtc->gamma_size = gamma_size;
|
||||
|
@ -3029,10 +3145,10 @@ bool drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
|
|||
crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL);
|
||||
if (!crtc->gamma_store) {
|
||||
crtc->gamma_size = 0;
|
||||
return false;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
|
||||
|
||||
|
@ -3178,6 +3294,18 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
|||
goto out;
|
||||
fb = obj_to_fb(obj);
|
||||
|
||||
if (crtc->mode.hdisplay > fb->width ||
|
||||
crtc->mode.vdisplay > fb->height ||
|
||||
crtc->x > fb->width - crtc->mode.hdisplay ||
|
||||
crtc->y > fb->height - crtc->mode.vdisplay) {
|
||||
DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d.\n",
|
||||
fb->width, fb->height,
|
||||
crtc->mode.hdisplay, crtc->mode.vdisplay,
|
||||
crtc->x, crtc->y);
|
||||
ret = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
|
||||
ret = -ENOMEM;
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "drm_fourcc.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
#include "drm_fb_helper.h"
|
||||
#include "drm_edid.h"
|
||||
|
||||
static bool drm_kms_helper_poll = true;
|
||||
module_param_named(poll, drm_kms_helper_poll, bool, 0600);
|
||||
|
@ -44,12 +45,12 @@ module_param_named(poll, drm_kms_helper_poll, bool, 0600);
|
|||
static void drm_mode_validate_flag(struct drm_connector *connector,
|
||||
int flags)
|
||||
{
|
||||
struct drm_display_mode *mode, *t;
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE))
|
||||
return;
|
||||
|
||||
list_for_each_entry_safe(mode, t, &connector->modes, head) {
|
||||
list_for_each_entry(mode, &connector->modes, head) {
|
||||
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&
|
||||
!(flags & DRM_MODE_FLAG_INTERLACE))
|
||||
mode->status = MODE_NO_INTERLACE;
|
||||
|
@ -87,7 +88,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
|||
uint32_t maxX, uint32_t maxY)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_display_mode *mode, *t;
|
||||
struct drm_display_mode *mode;
|
||||
struct drm_connector_helper_funcs *connector_funcs =
|
||||
connector->helper_private;
|
||||
int count = 0;
|
||||
|
@ -96,7 +97,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
|||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
|
||||
drm_get_connector_name(connector));
|
||||
/* set all modes to the unverified state */
|
||||
list_for_each_entry_safe(mode, t, &connector->modes, head)
|
||||
list_for_each_entry(mode, &connector->modes, head)
|
||||
mode->status = MODE_UNVERIFIED;
|
||||
|
||||
if (connector->force) {
|
||||
|
@ -118,7 +119,12 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
|||
goto prune;
|
||||
}
|
||||
|
||||
count = (*connector_funcs->get_modes)(connector);
|
||||
#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
|
||||
count = drm_load_edid_firmware(connector);
|
||||
if (count == 0)
|
||||
#endif
|
||||
count = (*connector_funcs->get_modes)(connector);
|
||||
|
||||
if (count == 0 && connector->status == connector_status_connected)
|
||||
count = drm_add_modes_noedid(connector, 1024, 768);
|
||||
if (count == 0)
|
||||
|
@ -136,7 +142,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
|||
mode_flags |= DRM_MODE_FLAG_DBLSCAN;
|
||||
drm_mode_validate_flag(connector, mode_flags);
|
||||
|
||||
list_for_each_entry_safe(mode, t, &connector->modes, head) {
|
||||
list_for_each_entry(mode, &connector->modes, head) {
|
||||
if (mode->status == MODE_OK)
|
||||
mode->status = connector_funcs->mode_valid(connector,
|
||||
mode);
|
||||
|
@ -152,7 +158,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
|||
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id,
|
||||
drm_get_connector_name(connector));
|
||||
list_for_each_entry_safe(mode, t, &connector->modes, head) {
|
||||
list_for_each_entry(mode, &connector->modes, head) {
|
||||
mode->vrefresh = drm_mode_vrefresh(mode);
|
||||
|
||||
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
|
||||
|
@ -352,6 +358,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
|||
return true;
|
||||
|
||||
adjusted_mode = drm_mode_duplicate(dev, mode);
|
||||
if (!adjusted_mode)
|
||||
return false;
|
||||
|
||||
saved_hwmode = crtc->hwmode;
|
||||
saved_mode = crtc->mode;
|
||||
|
|
|
@ -135,23 +135,23 @@ static struct drm_ioctl_desc drm_ioctls[] = {
|
|||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
|
@ -390,6 +390,10 @@ long drm_ioctl(struct file *filp,
|
|||
unsigned int usize, asize;
|
||||
|
||||
dev = file_priv->minor->dev;
|
||||
|
||||
if (drm_device_is_unplugged(dev))
|
||||
return -ENODEV;
|
||||
|
||||
atomic_inc(&dev->ioctl_count);
|
||||
atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
|
||||
++file_priv->ioctl_count;
|
||||
|
|
|
@ -149,8 +149,7 @@ EXPORT_SYMBOL(drm_edid_header_is_valid);
|
|||
* Sanity check the EDID block (base or extension). Return 0 if the block
|
||||
* doesn't check out, or 1 if it's valid.
|
||||
*/
|
||||
static bool
|
||||
drm_edid_block_valid(u8 *raw_edid)
|
||||
bool drm_edid_block_valid(u8 *raw_edid)
|
||||
{
|
||||
int i;
|
||||
u8 csum = 0;
|
||||
|
@ -203,6 +202,7 @@ drm_edid_block_valid(u8 *raw_edid)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_edid_block_valid);
|
||||
|
||||
/**
|
||||
* drm_edid_is_valid - sanity check EDID data
|
||||
|
@ -226,7 +226,6 @@ bool drm_edid_is_valid(struct edid *edid)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_edid_is_valid);
|
||||
|
||||
#define DDC_ADDR 0x50
|
||||
#define DDC_SEGMENT_ADDR 0x30
|
||||
/**
|
||||
* Get EDID information via I2C.
|
||||
|
@ -266,6 +265,11 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
|
|||
}
|
||||
};
|
||||
ret = i2c_transfer(adapter, msgs, 2);
|
||||
if (ret == -ENXIO) {
|
||||
DRM_DEBUG_KMS("drm: skipping non-existent adapter %s\n",
|
||||
adapter->name);
|
||||
break;
|
||||
}
|
||||
} while (ret != 2 && --retries);
|
||||
|
||||
return ret == 2 ? 0 : -1;
|
||||
|
@ -745,7 +749,7 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid,
|
|||
*/
|
||||
mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
|
||||
if (drm_mode_hsync(mode) > drm_gtf2_hbreak(edid)) {
|
||||
kfree(mode);
|
||||
drm_mode_destroy(dev, mode);
|
||||
mode = drm_gtf_mode_complex(dev, hsize, vsize,
|
||||
vrefresh_rate, 0, 0,
|
||||
drm_gtf2_m(edid),
|
||||
|
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
drm_edid_load.c: use a built-in EDID data set or load it via the firmware
|
||||
interface
|
||||
|
||||
Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/firmware.h>
|
||||
#include "drmP.h"
|
||||
#include "drm_crtc.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
#include "drm_edid.h"
|
||||
|
||||
static char edid_firmware[PATH_MAX];
|
||||
module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
|
||||
MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
|
||||
"from built-in data or /lib/firmware instead. ");
|
||||
|
||||
#define GENERIC_EDIDS 4
|
||||
static char *generic_edid_name[GENERIC_EDIDS] = {
|
||||
"edid/1024x768.bin",
|
||||
"edid/1280x1024.bin",
|
||||
"edid/1680x1050.bin",
|
||||
"edid/1920x1080.bin",
|
||||
};
|
||||
|
||||
static u8 generic_edid[GENERIC_EDIDS][128] = {
|
||||
{
|
||||
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
|
||||
0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
|
||||
0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
|
||||
0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
|
||||
0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
|
||||
0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
|
||||
0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
|
||||
0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
|
||||
0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
|
||||
0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55,
|
||||
},
|
||||
{
|
||||
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
|
||||
0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x16, 0x01, 0x03, 0x6d, 0x2c, 0x23, 0x78,
|
||||
0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
|
||||
0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0x81, 0x80,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2a,
|
||||
0x00, 0x98, 0x51, 0x00, 0x2a, 0x40, 0x30, 0x70,
|
||||
0x13, 0x00, 0xbc, 0x63, 0x11, 0x00, 0x00, 0x1e,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
|
||||
0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
|
||||
0x3d, 0x3e, 0x40, 0x0b, 0x00, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
|
||||
0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
|
||||
0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xa0,
|
||||
},
|
||||
{
|
||||
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
|
||||
0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
|
||||
0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
|
||||
0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x39,
|
||||
0x90, 0x30, 0x62, 0x1a, 0x27, 0x40, 0x68, 0xb0,
|
||||
0x36, 0x00, 0xb5, 0x11, 0x11, 0x00, 0x00, 0x1e,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
|
||||
0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
|
||||
0x3d, 0x40, 0x42, 0x0f, 0x00, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
|
||||
0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x57,
|
||||
0x53, 0x58, 0x47, 0x41, 0x0a, 0x20, 0x00, 0x26,
|
||||
},
|
||||
{
|
||||
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
|
||||
0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x16, 0x01, 0x03, 0x6d, 0x32, 0x1c, 0x78,
|
||||
0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
|
||||
0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xd1, 0xc0,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
|
||||
0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
|
||||
0x45, 0x00, 0xf4, 0x19, 0x11, 0x00, 0x00, 0x1e,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
|
||||
0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
|
||||
0x3d, 0x42, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
|
||||
0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x46,
|
||||
0x48, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x05,
|
||||
},
|
||||
};
|
||||
|
||||
static int edid_load(struct drm_connector *connector, char *name,
|
||||
char *connector_name)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
struct platform_device *pdev;
|
||||
u8 *fwdata = NULL, *edid;
|
||||
int fwsize, expected;
|
||||
int builtin = 0, err = 0;
|
||||
int i, valid_extensions = 0;
|
||||
|
||||
pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
|
||||
if (IS_ERR(pdev)) {
|
||||
DRM_ERROR("Failed to register EDID firmware platform device "
|
||||
"for connector \"%s\"\n", connector_name);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = request_firmware(&fw, name, &pdev->dev);
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
if (err) {
|
||||
i = 0;
|
||||
while (i < GENERIC_EDIDS && strcmp(name, generic_edid_name[i]))
|
||||
i++;
|
||||
if (i < GENERIC_EDIDS) {
|
||||
err = 0;
|
||||
builtin = 1;
|
||||
fwdata = generic_edid[i];
|
||||
fwsize = sizeof(generic_edid[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
|
||||
name, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fwdata == NULL) {
|
||||
fwdata = (u8 *) fw->data;
|
||||
fwsize = fw->size;
|
||||
}
|
||||
|
||||
expected = (fwdata[0x7e] + 1) * EDID_LENGTH;
|
||||
if (expected != fwsize) {
|
||||
DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
|
||||
"(expected %d, got %d)\n", name, expected, (int) fwsize);
|
||||
err = -EINVAL;
|
||||
goto relfw_out;
|
||||
}
|
||||
|
||||
edid = kmalloc(fwsize, GFP_KERNEL);
|
||||
if (edid == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto relfw_out;
|
||||
}
|
||||
memcpy(edid, fwdata, fwsize);
|
||||
|
||||
if (!drm_edid_block_valid(edid)) {
|
||||
DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
|
||||
name);
|
||||
kfree(edid);
|
||||
err = -EINVAL;
|
||||
goto relfw_out;
|
||||
}
|
||||
|
||||
for (i = 1; i <= edid[0x7e]; i++) {
|
||||
if (i != valid_extensions + 1)
|
||||
memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
|
||||
edid + i * EDID_LENGTH, EDID_LENGTH);
|
||||
if (drm_edid_block_valid(edid + i * EDID_LENGTH))
|
||||
valid_extensions++;
|
||||
}
|
||||
|
||||
if (valid_extensions != edid[0x7e]) {
|
||||
edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
|
||||
DRM_INFO("Found %d valid extensions instead of %d in EDID data "
|
||||
"\"%s\" for connector \"%s\"\n", valid_extensions,
|
||||
edid[0x7e], name, connector_name);
|
||||
edid[0x7e] = valid_extensions;
|
||||
edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
|
||||
GFP_KERNEL);
|
||||
if (edid == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto relfw_out;
|
||||
}
|
||||
}
|
||||
|
||||
connector->display_info.raw_edid = edid;
|
||||
DRM_INFO("Got %s EDID base block and %d extension%s from "
|
||||
"\"%s\" for connector \"%s\"\n", builtin ? "built-in" :
|
||||
"external", valid_extensions, valid_extensions == 1 ? "" : "s",
|
||||
name, connector_name);
|
||||
|
||||
relfw_out:
|
||||
release_firmware(fw);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int drm_load_edid_firmware(struct drm_connector *connector)
|
||||
{
|
||||
char *connector_name = drm_get_connector_name(connector);
|
||||
char *edidname = edid_firmware, *last, *colon;
|
||||
int ret = 0;
|
||||
|
||||
if (*edidname == '\0')
|
||||
return ret;
|
||||
|
||||
colon = strchr(edidname, ':');
|
||||
if (colon != NULL) {
|
||||
if (strncmp(connector_name, edidname, colon - edidname))
|
||||
return ret;
|
||||
edidname = colon + 1;
|
||||
if (*edidname == '\0')
|
||||
return ret;
|
||||
}
|
||||
|
||||
last = edidname + strlen(edidname) - 1;
|
||||
if (*last == '\n')
|
||||
*last = '\0';
|
||||
|
||||
ret = edid_load(connector, edidname, connector_name);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
drm_mode_connector_update_edid_property(connector,
|
||||
(struct edid *) connector->display_info.raw_edid);
|
||||
|
||||
return drm_add_edid_modes(connector, (struct edid *)
|
||||
connector->display_info.raw_edid);
|
||||
}
|
|
@ -306,91 +306,31 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
|
|||
static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
|
||||
#endif
|
||||
|
||||
static void drm_fb_helper_on(struct fb_info *info)
|
||||
static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
|
||||
{
|
||||
struct drm_fb_helper *fb_helper = info->par;
|
||||
struct drm_device *dev = fb_helper->dev;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_helper_funcs *crtc_funcs;
|
||||
struct drm_connector *connector;
|
||||
struct drm_encoder *encoder;
|
||||
int i, j;
|
||||
|
||||
/*
|
||||
* For each CRTC in this fb, turn the crtc on then,
|
||||
* find all associated encoders and turn them on.
|
||||
* For each CRTC in this fb, turn the connectors on/off.
|
||||
*/
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
crtc = fb_helper->crtc_info[i].mode_set.crtc;
|
||||
crtc_funcs = crtc->helper_private;
|
||||
|
||||
if (!crtc->enabled)
|
||||
continue;
|
||||
|
||||
crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
|
||||
|
||||
/* Walk the connectors & encoders on this fb turning them on */
|
||||
/* Walk the connectors & encoders on this fb turning them on/off */
|
||||
for (j = 0; j < fb_helper->connector_count; j++) {
|
||||
connector = fb_helper->connector_info[j]->connector;
|
||||
connector->dpms = DRM_MODE_DPMS_ON;
|
||||
drm_helper_connector_dpms(connector, dpms_mode);
|
||||
drm_connector_property_set_value(connector,
|
||||
dev->mode_config.dpms_property,
|
||||
DRM_MODE_DPMS_ON);
|
||||
dev->mode_config.dpms_property, dpms_mode);
|
||||
}
|
||||
/* Found a CRTC on this fb, now find encoders */
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
if (encoder->crtc == crtc) {
|
||||
struct drm_encoder_helper_funcs *encoder_funcs;
|
||||
|
||||
encoder_funcs = encoder->helper_private;
|
||||
encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
}
|
||||
|
||||
static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
|
||||
{
|
||||
struct drm_fb_helper *fb_helper = info->par;
|
||||
struct drm_device *dev = fb_helper->dev;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_helper_funcs *crtc_funcs;
|
||||
struct drm_connector *connector;
|
||||
struct drm_encoder *encoder;
|
||||
int i, j;
|
||||
|
||||
/*
|
||||
* For each CRTC in this fb, find all associated encoders
|
||||
* and turn them off, then turn off the CRTC.
|
||||
*/
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
crtc = fb_helper->crtc_info[i].mode_set.crtc;
|
||||
crtc_funcs = crtc->helper_private;
|
||||
|
||||
if (!crtc->enabled)
|
||||
continue;
|
||||
|
||||
/* Walk the connectors on this fb and mark them off */
|
||||
for (j = 0; j < fb_helper->connector_count; j++) {
|
||||
connector = fb_helper->connector_info[j]->connector;
|
||||
connector->dpms = dpms_mode;
|
||||
drm_connector_property_set_value(connector,
|
||||
dev->mode_config.dpms_property,
|
||||
dpms_mode);
|
||||
}
|
||||
/* Found a CRTC on this fb, now find encoders */
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
if (encoder->crtc == crtc) {
|
||||
struct drm_encoder_helper_funcs *encoder_funcs;
|
||||
|
||||
encoder_funcs = encoder->helper_private;
|
||||
encoder_funcs->dpms(encoder, dpms_mode);
|
||||
}
|
||||
}
|
||||
crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
}
|
||||
|
@ -400,23 +340,23 @@ int drm_fb_helper_blank(int blank, struct fb_info *info)
|
|||
switch (blank) {
|
||||
/* Display: On; HSync: On, VSync: On */
|
||||
case FB_BLANK_UNBLANK:
|
||||
drm_fb_helper_on(info);
|
||||
drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON);
|
||||
break;
|
||||
/* Display: Off; HSync: On, VSync: On */
|
||||
case FB_BLANK_NORMAL:
|
||||
drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
|
||||
drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
|
||||
break;
|
||||
/* Display: Off; HSync: Off, VSync: On */
|
||||
case FB_BLANK_HSYNC_SUSPEND:
|
||||
drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
|
||||
drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
|
||||
break;
|
||||
/* Display: Off; HSync: On, VSync: Off */
|
||||
case FB_BLANK_VSYNC_SUSPEND:
|
||||
drm_fb_helper_off(info, DRM_MODE_DPMS_SUSPEND);
|
||||
drm_fb_helper_dpms(info, DRM_MODE_DPMS_SUSPEND);
|
||||
break;
|
||||
/* Display: Off; HSync: Off, VSync: Off */
|
||||
case FB_BLANK_POWERDOWN:
|
||||
drm_fb_helper_off(info, DRM_MODE_DPMS_OFF);
|
||||
drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
@ -430,8 +370,11 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
|
|||
for (i = 0; i < helper->connector_count; i++)
|
||||
kfree(helper->connector_info[i]);
|
||||
kfree(helper->connector_info);
|
||||
for (i = 0; i < helper->crtc_count; i++)
|
||||
for (i = 0; i < helper->crtc_count; i++) {
|
||||
kfree(helper->crtc_info[i].mode_set.connectors);
|
||||
if (helper->crtc_info[i].mode_set.mode)
|
||||
drm_mode_destroy(helper->dev, helper->crtc_info[i].mode_set.mode);
|
||||
}
|
||||
kfree(helper->crtc_info);
|
||||
}
|
||||
|
||||
|
@ -474,11 +417,10 @@ int drm_fb_helper_init(struct drm_device *dev,
|
|||
|
||||
i = 0;
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
fb_helper->crtc_info[i].crtc_id = crtc->base.id;
|
||||
fb_helper->crtc_info[i].mode_set.crtc = crtc;
|
||||
i++;
|
||||
}
|
||||
fb_helper->conn_limit = max_conn_count;
|
||||
|
||||
return 0;
|
||||
out_free:
|
||||
drm_fb_helper_crtc_free(fb_helper);
|
||||
|
|
|
@ -133,6 +133,9 @@ int drm_open(struct inode *inode, struct file *filp)
|
|||
if (!(dev = minor->dev))
|
||||
return -ENODEV;
|
||||
|
||||
if (drm_device_is_unplugged(dev))
|
||||
return -ENODEV;
|
||||
|
||||
retcode = drm_open_helper(inode, filp, dev);
|
||||
if (!retcode) {
|
||||
atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
|
||||
|
@ -181,6 +184,9 @@ int drm_stub_open(struct inode *inode, struct file *filp)
|
|||
if (!(dev = minor->dev))
|
||||
goto out;
|
||||
|
||||
if (drm_device_is_unplugged(dev))
|
||||
goto out;
|
||||
|
||||
old_fops = filp->f_op;
|
||||
filp->f_op = fops_get(dev->driver->fops);
|
||||
if (filp->f_op == NULL) {
|
||||
|
@ -579,6 +585,8 @@ int drm_release(struct inode *inode, struct file *filp)
|
|||
retcode = -EBUSY;
|
||||
} else
|
||||
retcode = drm_lastclose(dev);
|
||||
if (drm_device_is_unplugged(dev))
|
||||
drm_put_dev(dev);
|
||||
}
|
||||
mutex_unlock(&drm_global_mutex);
|
||||
|
||||
|
|
|
@ -661,6 +661,9 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
struct drm_hash_item *hash;
|
||||
int ret = 0;
|
||||
|
||||
if (drm_device_is_unplugged(dev))
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &hash)) {
|
||||
|
@ -700,7 +703,6 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
*/
|
||||
drm_gem_object_reference(obj);
|
||||
|
||||
vma->vm_file = filp; /* Needed for drm_vm_open() */
|
||||
drm_vm_open_locked(vma);
|
||||
|
||||
out_unlock:
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "drm_core.h"
|
||||
|
||||
#include "linux/pci.h"
|
||||
#include "linux/export.h"
|
||||
|
||||
/**
|
||||
* Get the bus id.
|
||||
|
@ -276,6 +277,12 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
|||
case DRM_CAP_VBLANK_HIGH_CRTC:
|
||||
req->value = 1;
|
||||
break;
|
||||
case DRM_CAP_DUMB_PREFERRED_DEPTH:
|
||||
req->value = dev->mode_config.preferred_depth;
|
||||
break;
|
||||
case DRM_CAP_DUMB_PREFER_SHADOW:
|
||||
req->value = dev->mode_config.prefer_shadow;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -346,3 +353,4 @@ int drm_noop(struct drm_device *dev, void *data,
|
|||
DRM_DEBUG("\n");
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_noop);
|
||||
|
|
|
@ -305,7 +305,7 @@ static void drm_irq_vgaarb_nokms(void *cookie, bool state)
|
|||
* \param dev DRM device.
|
||||
*
|
||||
* Initializes the IRQ related data. Installs the handler, calling the driver
|
||||
* \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions
|
||||
* \c irq_preinstall() and \c irq_postinstall() functions
|
||||
* before and after the installation.
|
||||
*/
|
||||
int drm_irq_install(struct drm_device *dev)
|
||||
|
@ -385,7 +385,7 @@ EXPORT_SYMBOL(drm_irq_install);
|
|||
*
|
||||
* \param dev DRM device.
|
||||
*
|
||||
* Calls the driver's \c drm_driver_irq_uninstall() function, and stops the irq.
|
||||
* Calls the driver's \c irq_uninstall() function, and stops the irq.
|
||||
*/
|
||||
int drm_irq_uninstall(struct drm_device *dev)
|
||||
{
|
||||
|
|
|
@ -37,25 +37,6 @@
|
|||
#include <linux/export.h>
|
||||
#include "drmP.h"
|
||||
|
||||
/**
|
||||
* Called when "/proc/dri/%dev%/mem" is read.
|
||||
*
|
||||
* \param buf output buffer.
|
||||
* \param start start of output data.
|
||||
* \param offset requested start offset.
|
||||
* \param len requested number of bytes.
|
||||
* \param eof whether there is no more data to return.
|
||||
* \param data private data.
|
||||
* \return number of written bytes.
|
||||
*
|
||||
* No-op.
|
||||
*/
|
||||
int drm_mem_info(char *buf, char **start, off_t offset,
|
||||
int len, int *eof, void *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
static void *agp_remap(unsigned long offset, unsigned long size,
|
||||
struct drm_device * dev)
|
||||
|
|
|
@ -686,8 +686,6 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
|
|||
p->crtc_vsync_end /= 2;
|
||||
p->crtc_vtotal /= 2;
|
||||
}
|
||||
|
||||
p->crtc_vtotal |= 1;
|
||||
}
|
||||
|
||||
if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
|
||||
|
@ -715,6 +713,27 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
|
|||
EXPORT_SYMBOL(drm_mode_set_crtcinfo);
|
||||
|
||||
|
||||
/**
|
||||
* drm_mode_copy - copy the mode
|
||||
* @dst: mode to overwrite
|
||||
* @src: mode to copy
|
||||
*
|
||||
* LOCKING:
|
||||
* None.
|
||||
*
|
||||
* Copy an existing mode into another mode, preserving the object id
|
||||
* of the destination mode.
|
||||
*/
|
||||
void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
|
||||
{
|
||||
int id = dst->base.id;
|
||||
|
||||
*dst = *src;
|
||||
dst->base.id = id;
|
||||
INIT_LIST_HEAD(&dst->head);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_copy);
|
||||
|
||||
/**
|
||||
* drm_mode_duplicate - allocate and duplicate an existing mode
|
||||
* @m: mode to duplicate
|
||||
|
@ -729,16 +748,13 @@ struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
|
|||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_display_mode *nmode;
|
||||
int new_id;
|
||||
|
||||
nmode = drm_mode_create(dev);
|
||||
if (!nmode)
|
||||
return NULL;
|
||||
|
||||
new_id = nmode->base.id;
|
||||
*nmode = *mode;
|
||||
nmode->base.id = new_id;
|
||||
INIT_LIST_HEAD(&nmode->head);
|
||||
drm_mode_copy(nmode, mode);
|
||||
|
||||
return nmode;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_duplicate);
|
||||
|
|
|
@ -324,8 +324,6 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
|
|||
if (ret)
|
||||
goto err_g1;
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
dev->pdev = pdev;
|
||||
dev->dev = &pdev->dev;
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ static const char *drm_platform_get_name(struct drm_device *dev)
|
|||
|
||||
static int drm_platform_set_busid(struct drm_device *dev, struct drm_master *master)
|
||||
{
|
||||
int len, ret;
|
||||
int len, ret, id;
|
||||
|
||||
master->unique_len = 13 + strlen(dev->platformdev->name);
|
||||
master->unique_size = master->unique_len;
|
||||
|
@ -131,8 +131,16 @@ static int drm_platform_set_busid(struct drm_device *dev, struct drm_master *mas
|
|||
if (master->unique == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
id = dev->platformdev->id;
|
||||
|
||||
/* if only a single instance of the platform device, id will be
|
||||
* set to -1.. use 0 instead to avoid a funny looking bus-id:
|
||||
*/
|
||||
if (id == -1)
|
||||
id = 0;
|
||||
|
||||
len = snprintf(master->unique, master->unique_len,
|
||||
"platform:%s:%02d", dev->platformdev->name, dev->platformdev->id);
|
||||
"platform:%s:%02d", dev->platformdev->name, id);
|
||||
|
||||
if (len > master->unique_len) {
|
||||
DRM_ERROR("Unique buffer overflowed\n");
|
||||
|
|
|
@ -319,6 +319,7 @@ int drm_fill_in_dev(struct drm_device *dev,
|
|||
drm_lastclose(dev);
|
||||
return retcode;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fill_in_dev);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -397,6 +398,7 @@ int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type)
|
|||
*minor = NULL;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_get_minor);
|
||||
|
||||
/**
|
||||
* Put a secondary minor number.
|
||||
|
@ -428,6 +430,12 @@ int drm_put_minor(struct drm_minor **minor_p)
|
|||
*minor_p = NULL;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_put_minor);
|
||||
|
||||
static void drm_unplug_minor(struct drm_minor *minor)
|
||||
{
|
||||
drm_sysfs_device_remove(minor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called via drm_exit() at module unload time or when pci device is
|
||||
|
@ -492,3 +500,21 @@ void drm_put_dev(struct drm_device *dev)
|
|||
kfree(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_put_dev);
|
||||
|
||||
void drm_unplug_dev(struct drm_device *dev)
|
||||
{
|
||||
/* for a USB device */
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
drm_unplug_minor(dev->control);
|
||||
drm_unplug_minor(dev->primary);
|
||||
|
||||
mutex_lock(&drm_global_mutex);
|
||||
|
||||
drm_device_set_unplugged(dev);
|
||||
|
||||
if (dev->open_count == 0) {
|
||||
drm_put_dev(dev);
|
||||
}
|
||||
mutex_unlock(&drm_global_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_unplug_dev);
|
||||
|
|
|
@ -454,6 +454,8 @@ void drm_sysfs_connector_remove(struct drm_connector *connector)
|
|||
{
|
||||
int i;
|
||||
|
||||
if (!connector->kdev.parent)
|
||||
return;
|
||||
DRM_DEBUG("removing \"%s\" from sysfs\n",
|
||||
drm_get_connector_name(connector));
|
||||
|
||||
|
@ -461,6 +463,7 @@ void drm_sysfs_connector_remove(struct drm_connector *connector)
|
|||
device_remove_file(&connector->kdev, &connector_attrs[i]);
|
||||
sysfs_remove_bin_file(&connector->kdev.kobj, &edid_attr);
|
||||
device_unregister(&connector->kdev);
|
||||
connector->kdev.parent = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_sysfs_connector_remove);
|
||||
|
||||
|
@ -533,7 +536,9 @@ int drm_sysfs_device_add(struct drm_minor *minor)
|
|||
*/
|
||||
void drm_sysfs_device_remove(struct drm_minor *minor)
|
||||
{
|
||||
device_unregister(&minor->kdev);
|
||||
if (minor->kdev.parent)
|
||||
device_unregister(&minor->kdev);
|
||||
minor->kdev.parent = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include <linux/usb.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#ifdef CONFIG_USB
|
||||
int drm_get_usb_dev(struct usb_interface *interface,
|
||||
const struct usb_device_id *id,
|
||||
struct drm_driver *driver)
|
||||
|
@ -115,4 +114,3 @@ void drm_usb_exit(struct drm_driver *driver,
|
|||
usb_deregister(udriver);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_usb_exit);
|
||||
#endif
|
||||
|
|
|
@ -519,7 +519,6 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
|
|||
vma->vm_flags |= VM_RESERVED; /* Don't swap */
|
||||
vma->vm_flags |= VM_DONTEXPAND;
|
||||
|
||||
vma->vm_file = filp; /* Needed for drm_vm_open() */
|
||||
drm_vm_open_locked(vma);
|
||||
return 0;
|
||||
}
|
||||
|
@ -671,7 +670,6 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
|
|||
vma->vm_flags |= VM_RESERVED; /* Don't swap */
|
||||
vma->vm_flags |= VM_DONTEXPAND;
|
||||
|
||||
vma->vm_file = filp; /* Needed for drm_vm_open() */
|
||||
drm_vm_open_locked(vma);
|
||||
return 0;
|
||||
}
|
||||
|
@ -682,6 +680,9 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
struct drm_device *dev = priv->minor->dev;
|
||||
int ret;
|
||||
|
||||
if (drm_device_is_unplugged(dev))
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = drm_mmap_locked(filp, vma);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
config DRM_EXYNOS
|
||||
tristate "DRM Support for Samsung SoC EXYNOS Series"
|
||||
depends on DRM && PLAT_SAMSUNG
|
||||
default n
|
||||
select DRM_KMS_HELPER
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
|
@ -12,16 +11,19 @@ config DRM_EXYNOS
|
|||
If M is selected the module will be called exynosdrm.
|
||||
|
||||
config DRM_EXYNOS_FIMD
|
||||
tristate "Exynos DRM FIMD"
|
||||
bool "Exynos DRM FIMD"
|
||||
depends on DRM_EXYNOS && !FB_S3C
|
||||
default n
|
||||
help
|
||||
Choose this option if you want to use Exynos FIMD for DRM.
|
||||
If M is selected, the module will be called exynos_drm_fimd
|
||||
|
||||
config DRM_EXYNOS_HDMI
|
||||
tristate "Exynos DRM HDMI"
|
||||
bool "Exynos DRM HDMI"
|
||||
depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV
|
||||
help
|
||||
Choose this option if you want to use Exynos HDMI for DRM.
|
||||
If M is selected, the module will be called exynos_drm_hdmi
|
||||
|
||||
config DRM_EXYNOS_VIDI
|
||||
bool "Exynos DRM Virtual Display"
|
||||
depends on DRM_EXYNOS
|
||||
help
|
||||
Choose this option if you want to use Exynos VIDI for DRM.
|
||||
|
|
|
@ -8,7 +8,10 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
|
|||
exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \
|
||||
exynos_drm_plane.o
|
||||
|
||||
obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o
|
||||
obj-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
|
||||
obj-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o exynos_ddc.o \
|
||||
exynos_hdmiphy.o exynos_drm_hdmi.o
|
||||
exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
|
||||
exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o \
|
||||
exynos_ddc.o exynos_hdmiphy.o \
|
||||
exynos_drm_hdmi.o
|
||||
exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o
|
||||
|
||||
obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o
|
||||
|
|
|
@ -55,4 +55,3 @@ struct i2c_driver ddc_driver = {
|
|||
.remove = __devexit_p(s5p_ddc_remove),
|
||||
.command = NULL,
|
||||
};
|
||||
EXPORT_SYMBOL(ddc_driver);
|
||||
|
|
|
@ -25,45 +25,161 @@
|
|||
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "exynos_drm.h"
|
||||
|
||||
#include "exynos_drm_drv.h"
|
||||
#include "exynos_drm_gem.h"
|
||||
#include "exynos_drm_buf.h"
|
||||
|
||||
static int lowlevel_buffer_allocate(struct drm_device *dev,
|
||||
struct exynos_drm_gem_buf *buffer)
|
||||
unsigned int flags, struct exynos_drm_gem_buf *buf)
|
||||
{
|
||||
dma_addr_t start_addr, end_addr;
|
||||
unsigned int npages, page_size, i = 0;
|
||||
struct scatterlist *sgl;
|
||||
int ret = 0;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
buffer->kvaddr = dma_alloc_writecombine(dev->dev, buffer->size,
|
||||
&buffer->dma_addr, GFP_KERNEL);
|
||||
if (!buffer->kvaddr) {
|
||||
DRM_ERROR("failed to allocate buffer.\n");
|
||||
if (flags & EXYNOS_BO_NONCONTIG) {
|
||||
DRM_DEBUG_KMS("not support allocation type.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (buf->dma_addr) {
|
||||
DRM_DEBUG_KMS("already allocated.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (buf->size >= SZ_1M) {
|
||||
npages = (buf->size >> SECTION_SHIFT) + 1;
|
||||
page_size = SECTION_SIZE;
|
||||
} else if (buf->size >= SZ_64K) {
|
||||
npages = (buf->size >> 16) + 1;
|
||||
page_size = SZ_64K;
|
||||
} else {
|
||||
npages = (buf->size >> PAGE_SHIFT) + 1;
|
||||
page_size = PAGE_SIZE;
|
||||
}
|
||||
|
||||
buf->sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
|
||||
if (!buf->sgt) {
|
||||
DRM_ERROR("failed to allocate sg table.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n",
|
||||
(unsigned long)buffer->kvaddr,
|
||||
(unsigned long)buffer->dma_addr,
|
||||
buffer->size);
|
||||
ret = sg_alloc_table(buf->sgt, npages, GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to initialize sg table.\n");
|
||||
kfree(buf->sgt);
|
||||
buf->sgt = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
buf->kvaddr = dma_alloc_writecombine(dev->dev, buf->size,
|
||||
&buf->dma_addr, GFP_KERNEL);
|
||||
if (!buf->kvaddr) {
|
||||
DRM_ERROR("failed to allocate buffer.\n");
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
start_addr = buf->dma_addr;
|
||||
end_addr = buf->dma_addr + buf->size;
|
||||
|
||||
buf->pages = kzalloc(sizeof(struct page) * npages, GFP_KERNEL);
|
||||
if (!buf->pages) {
|
||||
DRM_ERROR("failed to allocate pages.\n");
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
start_addr = buf->dma_addr;
|
||||
end_addr = buf->dma_addr + buf->size;
|
||||
|
||||
buf->pages = kzalloc(sizeof(struct page) * npages, GFP_KERNEL);
|
||||
if (!buf->pages) {
|
||||
DRM_ERROR("failed to allocate pages.\n");
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
sgl = buf->sgt->sgl;
|
||||
|
||||
while (i < npages) {
|
||||
buf->pages[i] = phys_to_page(start_addr);
|
||||
sg_set_page(sgl, buf->pages[i], page_size, 0);
|
||||
sg_dma_address(sgl) = start_addr;
|
||||
start_addr += page_size;
|
||||
if (end_addr - start_addr < page_size)
|
||||
break;
|
||||
sgl = sg_next(sgl);
|
||||
i++;
|
||||
}
|
||||
|
||||
buf->pages[i] = phys_to_page(start_addr);
|
||||
|
||||
sgl = sg_next(sgl);
|
||||
sg_set_page(sgl, buf->pages[i+1], end_addr - start_addr, 0);
|
||||
|
||||
DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n",
|
||||
(unsigned long)buf->kvaddr,
|
||||
(unsigned long)buf->dma_addr,
|
||||
buf->size);
|
||||
|
||||
return ret;
|
||||
err2:
|
||||
dma_free_writecombine(dev->dev, buf->size, buf->kvaddr,
|
||||
(dma_addr_t)buf->dma_addr);
|
||||
buf->dma_addr = (dma_addr_t)NULL;
|
||||
err1:
|
||||
sg_free_table(buf->sgt);
|
||||
kfree(buf->sgt);
|
||||
buf->sgt = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void lowlevel_buffer_deallocate(struct drm_device *dev,
|
||||
struct exynos_drm_gem_buf *buffer)
|
||||
unsigned int flags, struct exynos_drm_gem_buf *buf)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s.\n", __FILE__);
|
||||
|
||||
if (buffer->dma_addr && buffer->size)
|
||||
dma_free_writecombine(dev->dev, buffer->size, buffer->kvaddr,
|
||||
(dma_addr_t)buffer->dma_addr);
|
||||
else
|
||||
DRM_DEBUG_KMS("buffer data are invalid.\n");
|
||||
/*
|
||||
* release only physically continuous memory and
|
||||
* non-continuous memory would be released by exynos
|
||||
* gem framework.
|
||||
*/
|
||||
if (flags & EXYNOS_BO_NONCONTIG) {
|
||||
DRM_DEBUG_KMS("not support allocation type.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!buf->dma_addr) {
|
||||
DRM_DEBUG_KMS("dma_addr is invalid.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n",
|
||||
(unsigned long)buf->kvaddr,
|
||||
(unsigned long)buf->dma_addr,
|
||||
buf->size);
|
||||
|
||||
sg_free_table(buf->sgt);
|
||||
|
||||
kfree(buf->sgt);
|
||||
buf->sgt = NULL;
|
||||
|
||||
kfree(buf->pages);
|
||||
buf->pages = NULL;
|
||||
|
||||
dma_free_writecombine(dev->dev, buf->size, buf->kvaddr,
|
||||
(dma_addr_t)buf->dma_addr);
|
||||
buf->dma_addr = (dma_addr_t)NULL;
|
||||
}
|
||||
|
||||
struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
|
||||
unsigned int size)
|
||||
struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
|
||||
unsigned int size)
|
||||
{
|
||||
struct exynos_drm_gem_buf *buffer;
|
||||
|
||||
|
@ -77,21 +193,11 @@ struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
|
|||
}
|
||||
|
||||
buffer->size = size;
|
||||
|
||||
/*
|
||||
* allocate memory region with size and set the memory information
|
||||
* to vaddr and dma_addr of a buffer object.
|
||||
*/
|
||||
if (lowlevel_buffer_allocate(dev, buffer) < 0) {
|
||||
kfree(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void exynos_drm_buf_destroy(struct drm_device *dev,
|
||||
struct exynos_drm_gem_buf *buffer)
|
||||
void exynos_drm_fini_buf(struct drm_device *dev,
|
||||
struct exynos_drm_gem_buf *buffer)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s.\n", __FILE__);
|
||||
|
||||
|
@ -100,12 +206,27 @@ void exynos_drm_buf_destroy(struct drm_device *dev,
|
|||
return;
|
||||
}
|
||||
|
||||
lowlevel_buffer_deallocate(dev, buffer);
|
||||
|
||||
kfree(buffer);
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung SoC DRM Buffer Management Module");
|
||||
MODULE_LICENSE("GPL");
|
||||
int exynos_drm_alloc_buf(struct drm_device *dev,
|
||||
struct exynos_drm_gem_buf *buf, unsigned int flags)
|
||||
{
|
||||
|
||||
/*
|
||||
* allocate memory region and set the memory information
|
||||
* to vaddr and dma_addr of a buffer object.
|
||||
*/
|
||||
if (lowlevel_buffer_allocate(dev, flags, buf) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void exynos_drm_free_buf(struct drm_device *dev,
|
||||
unsigned int flags, struct exynos_drm_gem_buf *buffer)
|
||||
{
|
||||
|
||||
lowlevel_buffer_deallocate(dev, flags, buffer);
|
||||
}
|
||||
|
|
|
@ -26,12 +26,22 @@
|
|||
#ifndef _EXYNOS_DRM_BUF_H_
|
||||
#define _EXYNOS_DRM_BUF_H_
|
||||
|
||||
/* allocate physical memory. */
|
||||
struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
|
||||
unsigned int size);
|
||||
/* create and initialize buffer object. */
|
||||
struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
|
||||
unsigned int size);
|
||||
|
||||
/* remove allocated physical memory. */
|
||||
void exynos_drm_buf_destroy(struct drm_device *dev,
|
||||
struct exynos_drm_gem_buf *buffer);
|
||||
/* destroy buffer object. */
|
||||
void exynos_drm_fini_buf(struct drm_device *dev,
|
||||
struct exynos_drm_gem_buf *buffer);
|
||||
|
||||
/* allocate physical memory region and setup sgt and pages. */
|
||||
int exynos_drm_alloc_buf(struct drm_device *dev,
|
||||
struct exynos_drm_gem_buf *buf,
|
||||
unsigned int flags);
|
||||
|
||||
/* release physical memory region, sgt and pages. */
|
||||
void exynos_drm_free_buf(struct drm_device *dev,
|
||||
unsigned int flags,
|
||||
struct exynos_drm_gem_buf *buffer);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -225,6 +225,29 @@ static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
|
|||
.best_encoder = exynos_drm_best_encoder,
|
||||
};
|
||||
|
||||
static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
|
||||
unsigned int max_width, unsigned int max_height)
|
||||
{
|
||||
struct exynos_drm_connector *exynos_connector =
|
||||
to_exynos_connector(connector);
|
||||
struct exynos_drm_manager *manager = exynos_connector->manager;
|
||||
struct exynos_drm_manager_ops *ops = manager->ops;
|
||||
unsigned int width, height;
|
||||
|
||||
width = max_width;
|
||||
height = max_height;
|
||||
|
||||
/*
|
||||
* if specific driver want to find desired_mode using maxmum
|
||||
* resolution then get max width and height from that driver.
|
||||
*/
|
||||
if (ops && ops->get_max_resol)
|
||||
ops->get_max_resol(manager->dev, &width, &height);
|
||||
|
||||
return drm_helper_probe_single_connector_modes(connector, width,
|
||||
height);
|
||||
}
|
||||
|
||||
/* get detection status of display device. */
|
||||
static enum drm_connector_status
|
||||
exynos_drm_connector_detect(struct drm_connector *connector, bool force)
|
||||
|
@ -262,7 +285,7 @@ static void exynos_drm_connector_destroy(struct drm_connector *connector)
|
|||
|
||||
static struct drm_connector_funcs exynos_connector_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.fill_modes = exynos_drm_connector_fill_modes,
|
||||
.detect = exynos_drm_connector_detect,
|
||||
.destroy = exynos_drm_connector_destroy,
|
||||
};
|
||||
|
@ -292,6 +315,10 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
|
|||
connector->interlace_allowed = true;
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
break;
|
||||
case EXYNOS_DISPLAY_TYPE_VIDI:
|
||||
type = DRM_MODE_CONNECTOR_VIRTUAL;
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
break;
|
||||
default:
|
||||
type = DRM_MODE_CONNECTOR_Unknown;
|
||||
break;
|
||||
|
@ -325,9 +352,3 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
|
|||
kfree(exynos_connector);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung SoC DRM Connector Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "exynos_drm_connector.h"
|
||||
#include "exynos_drm_fbdev.h"
|
||||
|
||||
static DEFINE_MUTEX(exynos_drm_mutex);
|
||||
static LIST_HEAD(exynos_drm_subdrv_list);
|
||||
static struct drm_device *drm_dev;
|
||||
|
||||
|
@ -60,6 +59,9 @@ static int exynos_drm_subdrv_probe(struct drm_device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (subdrv->is_local)
|
||||
return 0;
|
||||
|
||||
/* create and initialize a encoder for this sub driver. */
|
||||
encoder = exynos_drm_encoder_create(dev, &subdrv->manager,
|
||||
(1 << MAX_CRTC) - 1);
|
||||
|
@ -116,13 +118,10 @@ int exynos_drm_device_register(struct drm_device *dev)
|
|||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
if (drm_dev) {
|
||||
DRM_ERROR("Already drm device were registered\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
drm_dev = dev;
|
||||
|
||||
mutex_lock(&exynos_drm_mutex);
|
||||
list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
|
||||
subdrv->drm_dev = dev;
|
||||
err = exynos_drm_subdrv_probe(dev, subdrv);
|
||||
if (err) {
|
||||
DRM_DEBUG("exynos drm subdrv probe failed.\n");
|
||||
|
@ -130,9 +129,6 @@ int exynos_drm_device_register(struct drm_device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
drm_dev = dev;
|
||||
mutex_unlock(&exynos_drm_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(exynos_drm_device_register);
|
||||
|
@ -143,86 +139,28 @@ int exynos_drm_device_unregister(struct drm_device *dev)
|
|||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
if (!dev || dev != drm_dev) {
|
||||
if (!dev) {
|
||||
WARN(1, "Unexpected drm device unregister!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&exynos_drm_mutex);
|
||||
list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list)
|
||||
exynos_drm_subdrv_remove(dev, subdrv);
|
||||
|
||||
drm_dev = NULL;
|
||||
mutex_unlock(&exynos_drm_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
|
||||
|
||||
static int exynos_drm_mode_group_reinit(struct drm_device *dev)
|
||||
{
|
||||
struct drm_mode_group *group = &dev->primary->mode_group;
|
||||
uint32_t *id_list = group->id_list;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
ret = drm_mode_group_init_legacy_group(dev, group);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
kfree(id_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
|
||||
{
|
||||
int err;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
if (!subdrv)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&exynos_drm_mutex);
|
||||
if (drm_dev) {
|
||||
err = exynos_drm_subdrv_probe(drm_dev, subdrv);
|
||||
if (err) {
|
||||
DRM_ERROR("failed to probe exynos drm subdrv\n");
|
||||
mutex_unlock(&exynos_drm_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* setup possible_clones. */
|
||||
exynos_drm_encoder_setup(drm_dev);
|
||||
|
||||
/*
|
||||
* if any specific driver such as fimd or hdmi driver called
|
||||
* exynos_drm_subdrv_register() later than drm_load(),
|
||||
* the fb helper should be re-initialized and re-configured.
|
||||
*/
|
||||
err = exynos_drm_fbdev_reinit(drm_dev);
|
||||
if (err) {
|
||||
DRM_ERROR("failed to reinitialize exynos drm fbdev\n");
|
||||
exynos_drm_subdrv_remove(drm_dev, subdrv);
|
||||
mutex_unlock(&exynos_drm_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = exynos_drm_mode_group_reinit(drm_dev);
|
||||
if (err) {
|
||||
DRM_ERROR("failed to reinitialize mode group\n");
|
||||
exynos_drm_fbdev_fini(drm_dev);
|
||||
exynos_drm_subdrv_remove(drm_dev, subdrv);
|
||||
mutex_unlock(&exynos_drm_mutex);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
subdrv->drm_dev = drm_dev;
|
||||
|
||||
list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
|
||||
mutex_unlock(&exynos_drm_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -230,46 +168,48 @@ EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
|
|||
|
||||
int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
|
||||
{
|
||||
int ret = -EFAULT;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
if (!subdrv) {
|
||||
DRM_DEBUG("Unexpected exynos drm subdrv unregister!\n");
|
||||
return ret;
|
||||
}
|
||||
if (!subdrv)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&exynos_drm_mutex);
|
||||
if (drm_dev) {
|
||||
exynos_drm_subdrv_remove(drm_dev, subdrv);
|
||||
list_del(&subdrv->list);
|
||||
list_del(&subdrv->list);
|
||||
|
||||
/*
|
||||
* fb helper should be updated once a sub driver is released
|
||||
* to re-configure crtc and connector and also to re-setup
|
||||
* drm framebuffer.
|
||||
*/
|
||||
ret = exynos_drm_fbdev_reinit(drm_dev);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed fb helper reinit.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = exynos_drm_mode_group_reinit(drm_dev);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed drm mode group reinit.\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
mutex_unlock(&exynos_drm_mutex);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
|
||||
|
||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung SoC DRM Core Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
struct exynos_drm_subdrv *subdrv;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
|
||||
if (subdrv->open) {
|
||||
ret = subdrv->open(dev, subdrv->manager.dev, file);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
list_for_each_entry_reverse(subdrv, &subdrv->list, list) {
|
||||
if (subdrv->close)
|
||||
subdrv->close(dev, subdrv->manager.dev, file);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(exynos_drm_subdrv_open);
|
||||
|
||||
void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
struct exynos_drm_subdrv *subdrv;
|
||||
|
||||
list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
|
||||
if (subdrv->close)
|
||||
subdrv->close(dev, subdrv->manager.dev, file);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(exynos_drm_subdrv_close);
|
||||
|
|
|
@ -249,7 +249,11 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
|||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
mode = adjusted_mode;
|
||||
/*
|
||||
* copy the mode data adjusted by mode_fixup() into crtc->mode
|
||||
* so that hardware can be seet to proper mode.
|
||||
*/
|
||||
memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
|
||||
|
||||
return exynos_drm_crtc_update(crtc);
|
||||
}
|
||||
|
@ -426,9 +430,3 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
|
|||
exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
|
||||
exynos_drm_disable_vblank);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung SoC DRM CRTC Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "exynos_drm_fb.h"
|
||||
#include "exynos_drm_gem.h"
|
||||
#include "exynos_drm_plane.h"
|
||||
#include "exynos_drm_vidi.h"
|
||||
|
||||
#define DRIVER_NAME "exynos"
|
||||
#define DRIVER_DESC "Samsung SoC DRM"
|
||||
|
@ -144,11 +145,34 @@ static int exynos_drm_unload(struct drm_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void exynos_drm_preclose(struct drm_device *dev,
|
||||
struct drm_file *file)
|
||||
static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
return exynos_drm_subdrv_open(dev, file);
|
||||
}
|
||||
|
||||
static void exynos_drm_preclose(struct drm_device *dev,
|
||||
struct drm_file *file)
|
||||
{
|
||||
struct exynos_drm_private *private = dev->dev_private;
|
||||
struct drm_pending_vblank_event *e, *t;
|
||||
unsigned long flags;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
/* release events of current file */
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
list_for_each_entry_safe(e, t, &private->pageflip_event_list,
|
||||
base.link) {
|
||||
if (e->base.file_priv == file) {
|
||||
list_del(&e->base.link);
|
||||
e->base.destroy(&e->base);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
|
||||
exynos_drm_subdrv_close(dev, file);
|
||||
}
|
||||
|
||||
static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
|
||||
|
@ -185,6 +209,8 @@ static struct drm_ioctl_desc exynos_ioctls[] = {
|
|||
exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
|
||||
DRM_IOCTL_DEF_DRV(EXYNOS_PLANE_SET_ZPOS, exynos_plane_set_zpos_ioctl,
|
||||
DRM_UNLOCKED | DRM_AUTH),
|
||||
DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
|
||||
vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH),
|
||||
};
|
||||
|
||||
static const struct file_operations exynos_drm_driver_fops = {
|
||||
|
@ -202,6 +228,7 @@ static struct drm_driver exynos_drm_driver = {
|
|||
DRIVER_MODESET | DRIVER_GEM,
|
||||
.load = exynos_drm_load,
|
||||
.unload = exynos_drm_unload,
|
||||
.open = exynos_drm_open,
|
||||
.preclose = exynos_drm_preclose,
|
||||
.lastclose = exynos_drm_lastclose,
|
||||
.postclose = exynos_drm_postclose,
|
||||
|
@ -252,9 +279,60 @@ static struct platform_driver exynos_drm_platform_driver = {
|
|||
|
||||
static int __init exynos_drm_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
return platform_driver_register(&exynos_drm_platform_driver);
|
||||
#ifdef CONFIG_DRM_EXYNOS_FIMD
|
||||
ret = platform_driver_register(&fimd_driver);
|
||||
if (ret < 0)
|
||||
goto out_fimd;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_HDMI
|
||||
ret = platform_driver_register(&hdmi_driver);
|
||||
if (ret < 0)
|
||||
goto out_hdmi;
|
||||
ret = platform_driver_register(&mixer_driver);
|
||||
if (ret < 0)
|
||||
goto out_mixer;
|
||||
ret = platform_driver_register(&exynos_drm_common_hdmi_driver);
|
||||
if (ret < 0)
|
||||
goto out_common_hdmi;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_VIDI
|
||||
ret = platform_driver_register(&vidi_driver);
|
||||
if (ret < 0)
|
||||
goto out_vidi;
|
||||
#endif
|
||||
|
||||
ret = platform_driver_register(&exynos_drm_platform_driver);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
#ifdef CONFIG_DRM_EXYNOS_VIDI
|
||||
out_vidi:
|
||||
platform_driver_unregister(&vidi_driver);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_HDMI
|
||||
platform_driver_unregister(&exynos_drm_common_hdmi_driver);
|
||||
out_common_hdmi:
|
||||
platform_driver_unregister(&mixer_driver);
|
||||
out_mixer:
|
||||
platform_driver_unregister(&hdmi_driver);
|
||||
out_hdmi:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_FIMD
|
||||
platform_driver_unregister(&fimd_driver);
|
||||
out_fimd:
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit exynos_drm_exit(void)
|
||||
|
@ -262,6 +340,20 @@ static void __exit exynos_drm_exit(void)
|
|||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
platform_driver_unregister(&exynos_drm_platform_driver);
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_HDMI
|
||||
platform_driver_unregister(&exynos_drm_common_hdmi_driver);
|
||||
platform_driver_unregister(&mixer_driver);
|
||||
platform_driver_unregister(&hdmi_driver);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_VIDI
|
||||
platform_driver_unregister(&vidi_driver);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_FIMD
|
||||
platform_driver_unregister(&fimd_driver);
|
||||
#endif
|
||||
}
|
||||
|
||||
module_init(exynos_drm_init);
|
||||
|
|
|
@ -32,9 +32,9 @@
|
|||
#include <linux/module.h>
|
||||
#include "drm.h"
|
||||
|
||||
#define MAX_CRTC 2
|
||||
#define MAX_CRTC 3
|
||||
#define MAX_PLANE 5
|
||||
#define MAX_FB_BUFFER 3
|
||||
#define MAX_FB_BUFFER 4
|
||||
#define DEFAULT_ZPOS -1
|
||||
|
||||
struct drm_device;
|
||||
|
@ -50,6 +50,8 @@ enum exynos_drm_output_type {
|
|||
EXYNOS_DISPLAY_TYPE_LCD,
|
||||
/* HDMI Interface. */
|
||||
EXYNOS_DISPLAY_TYPE_HDMI,
|
||||
/* Virtual Display Interface. */
|
||||
EXYNOS_DISPLAY_TYPE_VIDI,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -155,8 +157,10 @@ struct exynos_drm_display_ops {
|
|||
*
|
||||
* @dpms: control device power.
|
||||
* @apply: set timing, vblank and overlay data to registers.
|
||||
* @mode_fixup: fix mode data comparing to hw specific display mode.
|
||||
* @mode_set: convert drm_display_mode to hw specific display mode and
|
||||
* would be called by encoder->mode_set().
|
||||
* @get_max_resol: get maximum resolution to specific hardware.
|
||||
* @commit: set current hw specific display mode to hw.
|
||||
* @enable_vblank: specific driver callback for enabling vblank interrupt.
|
||||
* @disable_vblank: specific driver callback for disabling vblank interrupt.
|
||||
|
@ -164,7 +168,13 @@ struct exynos_drm_display_ops {
|
|||
struct exynos_drm_manager_ops {
|
||||
void (*dpms)(struct device *subdrv_dev, int mode);
|
||||
void (*apply)(struct device *subdrv_dev);
|
||||
void (*mode_fixup)(struct device *subdrv_dev,
|
||||
struct drm_connector *connector,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
void (*mode_set)(struct device *subdrv_dev, void *mode);
|
||||
void (*get_max_resol)(struct device *subdrv_dev, unsigned int *width,
|
||||
unsigned int *height);
|
||||
void (*commit)(struct device *subdrv_dev);
|
||||
int (*enable_vblank)(struct device *subdrv_dev);
|
||||
void (*disable_vblank)(struct device *subdrv_dev);
|
||||
|
@ -217,10 +227,13 @@ struct exynos_drm_private {
|
|||
* @list: sub driver has its own list object to register to exynos drm driver.
|
||||
* @drm_dev: pointer to drm_device and this pointer would be set
|
||||
* when sub driver calls exynos_drm_subdrv_register().
|
||||
* @is_local: appear encoder and connector disrelated device.
|
||||
* @probe: this callback would be called by exynos drm driver after
|
||||
* subdrv is registered to it.
|
||||
* @remove: this callback is used to release resources created
|
||||
* by probe callback.
|
||||
* @open: this would be called with drm device file open.
|
||||
* @close: this would be called with drm device file close.
|
||||
* @manager: subdrv has its own manager to control a hardware appropriately
|
||||
* and we can access a hardware drawing on this manager.
|
||||
* @encoder: encoder object owned by this sub driver.
|
||||
|
@ -229,9 +242,14 @@ struct exynos_drm_private {
|
|||
struct exynos_drm_subdrv {
|
||||
struct list_head list;
|
||||
struct drm_device *drm_dev;
|
||||
bool is_local;
|
||||
|
||||
int (*probe)(struct drm_device *drm_dev, struct device *dev);
|
||||
void (*remove)(struct drm_device *dev);
|
||||
int (*open)(struct drm_device *drm_dev, struct device *dev,
|
||||
struct drm_file *file);
|
||||
void (*close)(struct drm_device *drm_dev, struct device *dev,
|
||||
struct drm_file *file);
|
||||
|
||||
struct exynos_drm_manager manager;
|
||||
struct drm_encoder *encoder;
|
||||
|
@ -254,15 +272,19 @@ int exynos_drm_device_unregister(struct drm_device *dev);
|
|||
* this function would be called by sub drivers such as display controller
|
||||
* or hdmi driver to register this sub driver object to exynos drm driver
|
||||
* and when a sub driver is registered to exynos drm driver a probe callback
|
||||
* of the sub driver is called and creates its own encoder and connector
|
||||
* and then fb helper and drm mode group would be re-initialized.
|
||||
* of the sub driver is called and creates its own encoder and connector.
|
||||
*/
|
||||
int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv);
|
||||
|
||||
/*
|
||||
* this function removes subdrv list from exynos drm driver and fb helper
|
||||
* and drm mode group would be re-initialized.
|
||||
*/
|
||||
/* this function removes subdrv list from exynos drm driver */
|
||||
int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv);
|
||||
|
||||
int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
|
||||
void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
|
||||
|
||||
extern struct platform_driver fimd_driver;
|
||||
extern struct platform_driver hdmi_driver;
|
||||
extern struct platform_driver mixer_driver;
|
||||
extern struct platform_driver exynos_drm_common_hdmi_driver;
|
||||
extern struct platform_driver vidi_driver;
|
||||
#endif
|
||||
|
|
|
@ -111,9 +111,19 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
|
|||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_connector *connector;
|
||||
struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
|
||||
struct exynos_drm_manager_ops *manager_ops = manager->ops;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* drm framework doesn't check NULL. */
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (connector->encoder == encoder)
|
||||
if (manager_ops && manager_ops->mode_fixup)
|
||||
manager_ops->mode_fixup(manager->dev, connector,
|
||||
mode, adjusted_mode);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -132,12 +142,11 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
|
|||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
mode = adjusted_mode;
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (connector->encoder == encoder) {
|
||||
if (manager_ops && manager_ops->mode_set)
|
||||
manager_ops->mode_set(manager->dev, mode);
|
||||
manager_ops->mode_set(manager->dev,
|
||||
adjusted_mode);
|
||||
|
||||
if (overlay_ops && overlay_ops->mode_set)
|
||||
overlay_ops->mode_set(manager->dev, overlay);
|
||||
|
@ -209,6 +218,7 @@ static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
|
|||
switch (display_ops->type) {
|
||||
case EXYNOS_DISPLAY_TYPE_LCD:
|
||||
case EXYNOS_DISPLAY_TYPE_HDMI:
|
||||
case EXYNOS_DISPLAY_TYPE_VIDI:
|
||||
clone_mask |= (1 << (cnt++));
|
||||
break;
|
||||
default:
|
||||
|
@ -433,9 +443,3 @@ void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data)
|
|||
if (overlay_ops && overlay_ops->disable)
|
||||
overlay_ops->disable(manager->dev, zpos);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung SoC DRM Encoder Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -211,9 +211,3 @@ void exynos_drm_mode_config_init(struct drm_device *dev)
|
|||
|
||||
dev->mode_config.funcs = &exynos_drm_mode_config_funcs;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung SoC DRM FB Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -125,7 +125,9 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
|
|||
}
|
||||
|
||||
size = mode_cmd.pitches[0] * mode_cmd.height;
|
||||
exynos_gem_obj = exynos_drm_gem_create(dev, size);
|
||||
|
||||
/* 0 means to allocate physically continuous memory */
|
||||
exynos_gem_obj = exynos_drm_gem_create(dev, 0, size);
|
||||
if (IS_ERR(exynos_gem_obj)) {
|
||||
ret = PTR_ERR(exynos_gem_obj);
|
||||
goto out;
|
||||
|
@ -314,89 +316,3 @@ void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
|
|||
|
||||
drm_fb_helper_restore_fbdev_mode(private->fb_helper);
|
||||
}
|
||||
|
||||
int exynos_drm_fbdev_reinit(struct drm_device *dev)
|
||||
{
|
||||
struct exynos_drm_private *private = dev->dev_private;
|
||||
struct drm_fb_helper *fb_helper;
|
||||
int ret;
|
||||
|
||||
if (!private)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* if all sub drivers were unloaded then num_connector is 0
|
||||
* so at this time, the framebuffers also should be destroyed.
|
||||
*/
|
||||
if (!dev->mode_config.num_connector) {
|
||||
exynos_drm_fbdev_fini(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fb_helper = private->fb_helper;
|
||||
|
||||
if (fb_helper) {
|
||||
struct list_head temp_list;
|
||||
|
||||
INIT_LIST_HEAD(&temp_list);
|
||||
|
||||
/*
|
||||
* fb_helper is reintialized but kernel fb is reused
|
||||
* so kernel_fb_list need to be backuped and restored
|
||||
*/
|
||||
if (!list_empty(&fb_helper->kernel_fb_list))
|
||||
list_replace_init(&fb_helper->kernel_fb_list,
|
||||
&temp_list);
|
||||
|
||||
drm_fb_helper_fini(fb_helper);
|
||||
|
||||
ret = drm_fb_helper_init(dev, fb_helper,
|
||||
dev->mode_config.num_crtc, MAX_CONNECTOR);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to initialize drm fb helper\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!list_empty(&temp_list))
|
||||
list_replace(&temp_list, &fb_helper->kernel_fb_list);
|
||||
|
||||
ret = drm_fb_helper_single_add_all_connectors(fb_helper);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to add fb helper to connectors\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = drm_fb_helper_initial_config(fb_helper, PREFERRED_BPP);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to set up hw configuration.\n");
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* if drm_load() failed whem drm load() was called prior
|
||||
* to specific drivers, fb_helper must be NULL and so
|
||||
* this fuction should be called again to re-initialize and
|
||||
* re-configure the fb helper. it means that this function
|
||||
* has been called by the specific drivers.
|
||||
*/
|
||||
ret = exynos_drm_fbdev_init(dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
/*
|
||||
* if drm_load() failed when drm load() was called prior
|
||||
* to specific drivers, the fb_helper must be NULL and so check it.
|
||||
*/
|
||||
if (fb_helper)
|
||||
drm_fb_helper_fini(fb_helper);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung SoC DRM FBDEV Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -1007,7 +1007,7 @@ static const struct dev_pm_ops fimd_pm_ops = {
|
|||
SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver fimd_driver = {
|
||||
struct platform_driver fimd_driver = {
|
||||
.probe = fimd_probe,
|
||||
.remove = __devexit_p(fimd_remove),
|
||||
.driver = {
|
||||
|
@ -1016,21 +1016,3 @@ static struct platform_driver fimd_driver = {
|
|||
.pm = &fimd_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init fimd_init(void)
|
||||
{
|
||||
return platform_driver_register(&fimd_driver);
|
||||
}
|
||||
|
||||
static void __exit fimd_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&fimd_driver);
|
||||
}
|
||||
|
||||
module_init(fimd_init);
|
||||
module_exit(fimd_exit);
|
||||
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung DRM FIMD Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <drm/exynos_drm.h>
|
||||
|
||||
#include "exynos_drm_drv.h"
|
||||
|
@ -55,6 +56,178 @@ static unsigned int convert_to_vm_err_msg(int msg)
|
|||
return out_msg;
|
||||
}
|
||||
|
||||
static unsigned int mask_gem_flags(unsigned int flags)
|
||||
{
|
||||
return flags &= EXYNOS_BO_NONCONTIG;
|
||||
}
|
||||
|
||||
static struct page **exynos_gem_get_pages(struct drm_gem_object *obj,
|
||||
gfp_t gfpmask)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct address_space *mapping;
|
||||
struct page *p, **pages;
|
||||
int i, npages;
|
||||
|
||||
/* This is the shared memory object that backs the GEM resource */
|
||||
inode = obj->filp->f_path.dentry->d_inode;
|
||||
mapping = inode->i_mapping;
|
||||
|
||||
npages = obj->size >> PAGE_SHIFT;
|
||||
|
||||
pages = drm_malloc_ab(npages, sizeof(struct page *));
|
||||
if (pages == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
gfpmask |= mapping_gfp_mask(mapping);
|
||||
|
||||
for (i = 0; i < npages; i++) {
|
||||
p = shmem_read_mapping_page_gfp(mapping, i, gfpmask);
|
||||
if (IS_ERR(p))
|
||||
goto fail;
|
||||
pages[i] = p;
|
||||
}
|
||||
|
||||
return pages;
|
||||
|
||||
fail:
|
||||
while (i--)
|
||||
page_cache_release(pages[i]);
|
||||
|
||||
drm_free_large(pages);
|
||||
return ERR_PTR(PTR_ERR(p));
|
||||
}
|
||||
|
||||
static void exynos_gem_put_pages(struct drm_gem_object *obj,
|
||||
struct page **pages,
|
||||
bool dirty, bool accessed)
|
||||
{
|
||||
int i, npages;
|
||||
|
||||
npages = obj->size >> PAGE_SHIFT;
|
||||
|
||||
for (i = 0; i < npages; i++) {
|
||||
if (dirty)
|
||||
set_page_dirty(pages[i]);
|
||||
|
||||
if (accessed)
|
||||
mark_page_accessed(pages[i]);
|
||||
|
||||
/* Undo the reference we took when populating the table */
|
||||
page_cache_release(pages[i]);
|
||||
}
|
||||
|
||||
drm_free_large(pages);
|
||||
}
|
||||
|
||||
static int exynos_drm_gem_map_pages(struct drm_gem_object *obj,
|
||||
struct vm_area_struct *vma,
|
||||
unsigned long f_vaddr,
|
||||
pgoff_t page_offset)
|
||||
{
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
|
||||
struct exynos_drm_gem_buf *buf = exynos_gem_obj->buffer;
|
||||
unsigned long pfn;
|
||||
|
||||
if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) {
|
||||
unsigned long usize = buf->size;
|
||||
|
||||
if (!buf->pages)
|
||||
return -EINTR;
|
||||
|
||||
while (usize > 0) {
|
||||
pfn = page_to_pfn(buf->pages[page_offset++]);
|
||||
vm_insert_mixed(vma, f_vaddr, pfn);
|
||||
f_vaddr += PAGE_SIZE;
|
||||
usize -= PAGE_SIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pfn = (buf->dma_addr >> PAGE_SHIFT) + page_offset;
|
||||
|
||||
return vm_insert_mixed(vma, f_vaddr, pfn);
|
||||
}
|
||||
|
||||
static int exynos_drm_gem_get_pages(struct drm_gem_object *obj)
|
||||
{
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
|
||||
struct exynos_drm_gem_buf *buf = exynos_gem_obj->buffer;
|
||||
struct scatterlist *sgl;
|
||||
struct page **pages;
|
||||
unsigned int npages, i = 0;
|
||||
int ret;
|
||||
|
||||
if (buf->pages) {
|
||||
DRM_DEBUG_KMS("already allocated.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pages = exynos_gem_get_pages(obj, GFP_KERNEL);
|
||||
if (IS_ERR(pages)) {
|
||||
DRM_ERROR("failed to get pages.\n");
|
||||
return PTR_ERR(pages);
|
||||
}
|
||||
|
||||
npages = obj->size >> PAGE_SHIFT;
|
||||
|
||||
buf->sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
|
||||
if (!buf->sgt) {
|
||||
DRM_ERROR("failed to allocate sg table.\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = sg_alloc_table(buf->sgt, npages, GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to initialize sg table.\n");
|
||||
ret = -EFAULT;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
sgl = buf->sgt->sgl;
|
||||
|
||||
/* set all pages to sg list. */
|
||||
while (i < npages) {
|
||||
sg_set_page(sgl, pages[i], PAGE_SIZE, 0);
|
||||
sg_dma_address(sgl) = page_to_phys(pages[i]);
|
||||
i++;
|
||||
sgl = sg_next(sgl);
|
||||
}
|
||||
|
||||
/* add some codes for UNCACHED type here. TODO */
|
||||
|
||||
buf->pages = pages;
|
||||
return ret;
|
||||
err1:
|
||||
kfree(buf->sgt);
|
||||
buf->sgt = NULL;
|
||||
err:
|
||||
exynos_gem_put_pages(obj, pages, true, false);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static void exynos_drm_gem_put_pages(struct drm_gem_object *obj)
|
||||
{
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
|
||||
struct exynos_drm_gem_buf *buf = exynos_gem_obj->buffer;
|
||||
|
||||
/*
|
||||
* if buffer typs is EXYNOS_BO_NONCONTIG then release all pages
|
||||
* allocated at gem fault handler.
|
||||
*/
|
||||
sg_free_table(buf->sgt);
|
||||
kfree(buf->sgt);
|
||||
buf->sgt = NULL;
|
||||
|
||||
exynos_gem_put_pages(obj, buf->pages, true, false);
|
||||
buf->pages = NULL;
|
||||
|
||||
/* add some codes for UNCACHED type here. TODO */
|
||||
}
|
||||
|
||||
static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,
|
||||
struct drm_file *file_priv,
|
||||
unsigned int *handle)
|
||||
|
@ -90,7 +263,15 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
|
|||
|
||||
DRM_DEBUG_KMS("handle count = %d\n", atomic_read(&obj->handle_count));
|
||||
|
||||
exynos_drm_buf_destroy(obj->dev, exynos_gem_obj->buffer);
|
||||
if ((exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) &&
|
||||
exynos_gem_obj->buffer->pages)
|
||||
exynos_drm_gem_put_pages(obj);
|
||||
else
|
||||
exynos_drm_free_buf(obj->dev, exynos_gem_obj->flags,
|
||||
exynos_gem_obj->buffer);
|
||||
|
||||
exynos_drm_fini_buf(obj->dev, exynos_gem_obj->buffer);
|
||||
exynos_gem_obj->buffer = NULL;
|
||||
|
||||
if (obj->map_list.map)
|
||||
drm_gem_free_mmap_offset(obj);
|
||||
|
@ -99,6 +280,7 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
|
|||
drm_gem_object_release(obj);
|
||||
|
||||
kfree(exynos_gem_obj);
|
||||
exynos_gem_obj = NULL;
|
||||
}
|
||||
|
||||
static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
|
||||
|
@ -114,6 +296,7 @@ static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
exynos_gem_obj->size = size;
|
||||
obj = &exynos_gem_obj->base;
|
||||
|
||||
ret = drm_gem_object_init(dev, obj, size);
|
||||
|
@ -129,27 +312,55 @@ static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
|
|||
}
|
||||
|
||||
struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
|
||||
unsigned long size)
|
||||
unsigned int flags,
|
||||
unsigned long size)
|
||||
{
|
||||
struct exynos_drm_gem_buf *buffer;
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj;
|
||||
struct exynos_drm_gem_buf *buf;
|
||||
int ret;
|
||||
|
||||
size = roundup(size, PAGE_SIZE);
|
||||
DRM_DEBUG_KMS("%s: size = 0x%lx\n", __FILE__, size);
|
||||
|
||||
buffer = exynos_drm_buf_create(dev, size);
|
||||
if (!buffer)
|
||||
flags = mask_gem_flags(flags);
|
||||
|
||||
buf = exynos_drm_init_buf(dev, size);
|
||||
if (!buf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
exynos_gem_obj = exynos_drm_gem_init(dev, size);
|
||||
if (!exynos_gem_obj) {
|
||||
exynos_drm_buf_destroy(dev, buffer);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
exynos_gem_obj->buffer = buffer;
|
||||
exynos_gem_obj->buffer = buf;
|
||||
|
||||
/* set memory type and cache attribute from user side. */
|
||||
exynos_gem_obj->flags = flags;
|
||||
|
||||
/*
|
||||
* allocate all pages as desired size if user wants to allocate
|
||||
* physically non-continuous memory.
|
||||
*/
|
||||
if (flags & EXYNOS_BO_NONCONTIG) {
|
||||
ret = exynos_drm_gem_get_pages(&exynos_gem_obj->base);
|
||||
if (ret < 0) {
|
||||
drm_gem_object_release(&exynos_gem_obj->base);
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
ret = exynos_drm_alloc_buf(dev, buf, flags);
|
||||
if (ret < 0) {
|
||||
drm_gem_object_release(&exynos_gem_obj->base);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return exynos_gem_obj;
|
||||
err:
|
||||
exynos_drm_fini_buf(dev, buf);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
|
||||
|
@ -161,7 +372,7 @@ int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
|
|||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
exynos_gem_obj = exynos_drm_gem_create(dev, args->size);
|
||||
exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
|
||||
if (IS_ERR(exynos_gem_obj))
|
||||
return PTR_ERR(exynos_gem_obj);
|
||||
|
||||
|
@ -175,6 +386,64 @@ int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
|
||||
unsigned int gem_handle,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj;
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
obj = drm_gem_object_lookup(dev, file_priv, gem_handle);
|
||||
if (!obj) {
|
||||
DRM_ERROR("failed to lookup gem object.\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
exynos_gem_obj = to_exynos_gem_obj(obj);
|
||||
|
||||
if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) {
|
||||
DRM_DEBUG_KMS("not support NONCONTIG type.\n");
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
|
||||
/* TODO */
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return &exynos_gem_obj->buffer->dma_addr;
|
||||
}
|
||||
|
||||
void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
|
||||
unsigned int gem_handle,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj;
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
obj = drm_gem_object_lookup(dev, file_priv, gem_handle);
|
||||
if (!obj) {
|
||||
DRM_ERROR("failed to lookup gem object.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
exynos_gem_obj = to_exynos_gem_obj(obj);
|
||||
|
||||
if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) {
|
||||
DRM_DEBUG_KMS("not support NONCONTIG type.\n");
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
|
||||
/* TODO */
|
||||
return;
|
||||
}
|
||||
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
|
||||
/*
|
||||
* decrease obj->refcount one more time because we has already
|
||||
* increased it at exynos_drm_gem_get_dma_addr().
|
||||
*/
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
}
|
||||
|
||||
int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
|
@ -200,7 +469,8 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
|
|||
struct drm_gem_object *obj = filp->private_data;
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
|
||||
struct exynos_drm_gem_buf *buffer;
|
||||
unsigned long pfn, vm_size;
|
||||
unsigned long pfn, vm_size, usize, uaddr = vma->vm_start;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
|
@ -208,9 +478,9 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
|
|||
|
||||
/* in case of direct mapping, always having non-cachable attribute */
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
vma->vm_file = filp;
|
||||
|
||||
vm_size = vma->vm_end - vma->vm_start;
|
||||
vm_size = usize = vma->vm_end - vma->vm_start;
|
||||
|
||||
/*
|
||||
* a buffer contains information to physically continuous memory
|
||||
* allocated by user request or at framebuffer creation.
|
||||
|
@ -221,18 +491,37 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
|
|||
if (vm_size > buffer->size)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* get page frame number to physical memory to be mapped
|
||||
* to user space.
|
||||
*/
|
||||
pfn = ((unsigned long)exynos_gem_obj->buffer->dma_addr) >> PAGE_SHIFT;
|
||||
if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) {
|
||||
int i = 0;
|
||||
|
||||
DRM_DEBUG_KMS("pfn = 0x%lx\n", pfn);
|
||||
if (!buffer->pages)
|
||||
return -EINVAL;
|
||||
|
||||
if (remap_pfn_range(vma, vma->vm_start, pfn, vm_size,
|
||||
vma->vm_page_prot)) {
|
||||
DRM_ERROR("failed to remap pfn range.\n");
|
||||
return -EAGAIN;
|
||||
do {
|
||||
ret = vm_insert_page(vma, uaddr, buffer->pages[i++]);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to remap user space.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
uaddr += PAGE_SIZE;
|
||||
usize -= PAGE_SIZE;
|
||||
} while (usize > 0);
|
||||
} else {
|
||||
/*
|
||||
* get page frame number to physical memory to be mapped
|
||||
* to user space.
|
||||
*/
|
||||
pfn = ((unsigned long)exynos_gem_obj->buffer->dma_addr) >>
|
||||
PAGE_SHIFT;
|
||||
|
||||
DRM_DEBUG_KMS("pfn = 0x%lx\n", pfn);
|
||||
|
||||
if (remap_pfn_range(vma, vma->vm_start, pfn, vm_size,
|
||||
vma->vm_page_prot)) {
|
||||
DRM_ERROR("failed to remap pfn range.\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -312,9 +601,9 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
|
|||
*/
|
||||
|
||||
args->pitch = args->width * args->bpp >> 3;
|
||||
args->size = args->pitch * args->height;
|
||||
args->size = PAGE_ALIGN(args->pitch * args->height);
|
||||
|
||||
exynos_gem_obj = exynos_drm_gem_create(dev, args->size);
|
||||
exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
|
||||
if (IS_ERR(exynos_gem_obj))
|
||||
return PTR_ERR(exynos_gem_obj);
|
||||
|
||||
|
@ -398,20 +687,31 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
struct drm_gem_object *obj = vma->vm_private_data;
|
||||
struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
|
||||
struct drm_device *dev = obj->dev;
|
||||
unsigned long pfn;
|
||||
unsigned long f_vaddr;
|
||||
pgoff_t page_offset;
|
||||
int ret;
|
||||
|
||||
page_offset = ((unsigned long)vmf->virtual_address -
|
||||
vma->vm_start) >> PAGE_SHIFT;
|
||||
f_vaddr = (unsigned long)vmf->virtual_address;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
pfn = (((unsigned long)exynos_gem_obj->buffer->dma_addr) >>
|
||||
PAGE_SHIFT) + page_offset;
|
||||
/*
|
||||
* allocate all pages as desired size if user wants to allocate
|
||||
* physically non-continuous memory.
|
||||
*/
|
||||
if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) {
|
||||
ret = exynos_drm_gem_get_pages(obj);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
|
||||
ret = exynos_drm_gem_map_pages(obj, vma, f_vaddr, page_offset);
|
||||
if (ret < 0)
|
||||
DRM_ERROR("failed to map pages.\n");
|
||||
|
||||
err:
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return convert_to_vm_err_msg(ret);
|
||||
|
@ -435,7 +735,3 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung SoC DRM GEM Module");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -36,11 +36,15 @@
|
|||
* @dma_addr: bus address(accessed by dma) to allocated memory region.
|
||||
* - this address could be physical address without IOMMU and
|
||||
* device address with IOMMU.
|
||||
* @sgt: sg table to transfer page data.
|
||||
* @pages: contain all pages to allocated memory region.
|
||||
* @size: size of allocated memory region.
|
||||
*/
|
||||
struct exynos_drm_gem_buf {
|
||||
void __iomem *kvaddr;
|
||||
dma_addr_t dma_addr;
|
||||
struct sg_table *sgt;
|
||||
struct page **pages;
|
||||
unsigned long size;
|
||||
};
|
||||
|
||||
|
@ -55,6 +59,8 @@ struct exynos_drm_gem_buf {
|
|||
* by user request or at framebuffer creation.
|
||||
* continuous memory region allocated by user request
|
||||
* or at framebuffer creation.
|
||||
* @size: total memory size to physically non-continuous memory region.
|
||||
* @flags: indicate memory type to allocated buffer and cache attruibute.
|
||||
*
|
||||
* P.S. this object would be transfered to user as kms_bo.handle so
|
||||
* user can access the buffer through kms_bo.handle.
|
||||
|
@ -62,6 +68,8 @@ struct exynos_drm_gem_buf {
|
|||
struct exynos_drm_gem_obj {
|
||||
struct drm_gem_object base;
|
||||
struct exynos_drm_gem_buf *buffer;
|
||||
unsigned long size;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/* destroy a buffer with gem object */
|
||||
|
@ -69,7 +77,8 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj);
|
|||
|
||||
/* create a new buffer with gem object */
|
||||
struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
|
||||
unsigned long size);
|
||||
unsigned int flags,
|
||||
unsigned long size);
|
||||
|
||||
/*
|
||||
* request gem object creation and buffer allocation as the size
|
||||
|
@ -79,6 +88,24 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
|
|||
int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
/*
|
||||
* get dma address from gem handle and this function could be used for
|
||||
* other drivers such as 2d/3d acceleration drivers.
|
||||
* with this function call, gem object reference count would be increased.
|
||||
*/
|
||||
void *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
|
||||
unsigned int gem_handle,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
/*
|
||||
* put dma address from gem handle and this function could be used for
|
||||
* other drivers such as 2d/3d acceleration drivers.
|
||||
* with this function call, gem object reference count would be decreased.
|
||||
*/
|
||||
void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
|
||||
unsigned int gem_handle,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
/* get buffer offset to map to user space. */
|
||||
int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
|
|
@ -38,7 +38,6 @@ struct drm_hdmi_context {
|
|||
struct exynos_drm_subdrv subdrv;
|
||||
struct exynos_drm_hdmi_context *hdmi_ctx;
|
||||
struct exynos_drm_hdmi_context *mixer_ctx;
|
||||
struct work_struct work;
|
||||
};
|
||||
|
||||
void exynos_drm_display_ops_register(struct exynos_hdmi_display_ops
|
||||
|
@ -49,7 +48,6 @@ void exynos_drm_display_ops_register(struct exynos_hdmi_display_ops
|
|||
if (display_ops)
|
||||
hdmi_display_ops = display_ops;
|
||||
}
|
||||
EXPORT_SYMBOL(exynos_drm_display_ops_register);
|
||||
|
||||
void exynos_drm_manager_ops_register(struct exynos_hdmi_manager_ops
|
||||
*manager_ops)
|
||||
|
@ -59,7 +57,6 @@ void exynos_drm_manager_ops_register(struct exynos_hdmi_manager_ops
|
|||
if (manager_ops)
|
||||
hdmi_manager_ops = manager_ops;
|
||||
}
|
||||
EXPORT_SYMBOL(exynos_drm_manager_ops_register);
|
||||
|
||||
void exynos_drm_overlay_ops_register(struct exynos_hdmi_overlay_ops
|
||||
*overlay_ops)
|
||||
|
@ -69,7 +66,6 @@ void exynos_drm_overlay_ops_register(struct exynos_hdmi_overlay_ops
|
|||
if (overlay_ops)
|
||||
hdmi_overlay_ops = overlay_ops;
|
||||
}
|
||||
EXPORT_SYMBOL(exynos_drm_overlay_ops_register);
|
||||
|
||||
static bool drm_hdmi_is_connected(struct device *dev)
|
||||
{
|
||||
|
@ -155,6 +151,20 @@ static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
|
|||
return hdmi_overlay_ops->disable_vblank(ctx->mixer_ctx->ctx);
|
||||
}
|
||||
|
||||
static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
|
||||
struct drm_connector *connector,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (hdmi_manager_ops && hdmi_manager_ops->mode_fixup)
|
||||
hdmi_manager_ops->mode_fixup(ctx->hdmi_ctx->ctx, connector,
|
||||
mode, adjusted_mode);
|
||||
}
|
||||
|
||||
static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
|
||||
|
@ -165,6 +175,18 @@ static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
|
|||
hdmi_manager_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
|
||||
}
|
||||
|
||||
static void drm_hdmi_get_max_resol(struct device *subdrv_dev,
|
||||
unsigned int *width, unsigned int *height)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (hdmi_manager_ops && hdmi_manager_ops->get_max_resol)
|
||||
hdmi_manager_ops->get_max_resol(ctx->hdmi_ctx->ctx, width,
|
||||
height);
|
||||
}
|
||||
|
||||
static void drm_hdmi_commit(struct device *subdrv_dev)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
|
||||
|
@ -200,7 +222,9 @@ static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
|
|||
.dpms = drm_hdmi_dpms,
|
||||
.enable_vblank = drm_hdmi_enable_vblank,
|
||||
.disable_vblank = drm_hdmi_disable_vblank,
|
||||
.mode_fixup = drm_hdmi_mode_fixup,
|
||||
.mode_set = drm_hdmi_mode_set,
|
||||
.get_max_resol = drm_hdmi_get_max_resol,
|
||||
.commit = drm_hdmi_commit,
|
||||
};
|
||||
|
||||
|
@ -249,7 +273,6 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev,
|
|||
struct drm_hdmi_context *ctx;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct exynos_drm_common_hdmi_pd *pd;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
|
@ -270,26 +293,13 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev,
|
|||
return -EFAULT;
|
||||
}
|
||||
|
||||
ret = platform_driver_register(&hdmi_driver);
|
||||
if (ret) {
|
||||
DRM_DEBUG_KMS("failed to register hdmi driver.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = platform_driver_register(&mixer_driver);
|
||||
if (ret) {
|
||||
DRM_DEBUG_KMS("failed to register mixer driver.\n");
|
||||
goto err_hdmidrv;
|
||||
}
|
||||
|
||||
ctx = get_ctx_from_subdrv(subdrv);
|
||||
|
||||
ctx->hdmi_ctx = (struct exynos_drm_hdmi_context *)
|
||||
to_context(pd->hdmi_dev);
|
||||
if (!ctx->hdmi_ctx) {
|
||||
DRM_DEBUG_KMS("hdmi context is null.\n");
|
||||
ret = -EFAULT;
|
||||
goto err_mixerdrv;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ctx->hdmi_ctx->drm_dev = drm_dev;
|
||||
|
@ -298,42 +308,12 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev,
|
|||
to_context(pd->mixer_dev);
|
||||
if (!ctx->mixer_ctx) {
|
||||
DRM_DEBUG_KMS("mixer context is null.\n");
|
||||
ret = -EFAULT;
|
||||
goto err_mixerdrv;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ctx->mixer_ctx->drm_dev = drm_dev;
|
||||
|
||||
return 0;
|
||||
|
||||
err_mixerdrv:
|
||||
platform_driver_unregister(&mixer_driver);
|
||||
err_hdmidrv:
|
||||
platform_driver_unregister(&hdmi_driver);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void hdmi_subdrv_remove(struct drm_device *drm_dev)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
platform_driver_unregister(&hdmi_driver);
|
||||
platform_driver_unregister(&mixer_driver);
|
||||
}
|
||||
|
||||
static void exynos_drm_hdmi_late_probe(struct work_struct *work)
|
||||
{
|
||||
struct drm_hdmi_context *ctx = container_of(work,
|
||||
struct drm_hdmi_context, work);
|
||||
|
||||
/*
|
||||
* this function calls subdrv->probe() so this must be called
|
||||
* after probe context.
|
||||
*
|
||||
* PS. subdrv->probe() will call platform_driver_register() to probe
|
||||
* hdmi and mixer driver.
|
||||
*/
|
||||
exynos_drm_subdrv_register(&ctx->subdrv);
|
||||
}
|
||||
|
||||
static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
|
||||
|
@ -353,7 +333,6 @@ static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
|
|||
subdrv = &ctx->subdrv;
|
||||
|
||||
subdrv->probe = hdmi_subdrv_probe;
|
||||
subdrv->remove = hdmi_subdrv_remove;
|
||||
subdrv->manager.pipe = -1;
|
||||
subdrv->manager.ops = &drm_hdmi_manager_ops;
|
||||
subdrv->manager.overlay_ops = &drm_hdmi_overlay_ops;
|
||||
|
@ -362,9 +341,7 @@ static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, subdrv);
|
||||
|
||||
INIT_WORK(&ctx->work, exynos_drm_hdmi_late_probe);
|
||||
|
||||
schedule_work(&ctx->work);
|
||||
exynos_drm_subdrv_register(subdrv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -400,7 +377,7 @@ static int __devexit exynos_drm_hdmi_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver exynos_drm_common_hdmi_driver = {
|
||||
struct platform_driver exynos_drm_common_hdmi_driver = {
|
||||
.probe = exynos_drm_hdmi_probe,
|
||||
.remove = __devexit_p(exynos_drm_hdmi_remove),
|
||||
.driver = {
|
||||
|
@ -409,31 +386,3 @@ static struct platform_driver exynos_drm_common_hdmi_driver = {
|
|||
.pm = &hdmi_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init exynos_drm_hdmi_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
ret = platform_driver_register(&exynos_drm_common_hdmi_driver);
|
||||
if (ret) {
|
||||
DRM_DEBUG_KMS("failed to register hdmi common driver.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit exynos_drm_hdmi_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&exynos_drm_common_hdmi_driver);
|
||||
}
|
||||
|
||||
module_init(exynos_drm_hdmi_init);
|
||||
module_exit(exynos_drm_hdmi_exit);
|
||||
|
||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||
MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung SoC DRM HDMI Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -47,7 +47,12 @@ struct exynos_hdmi_display_ops {
|
|||
};
|
||||
|
||||
struct exynos_hdmi_manager_ops {
|
||||
void (*mode_fixup)(void *ctx, struct drm_connector *connector,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
void (*mode_set)(void *ctx, void *mode);
|
||||
void (*get_max_resol)(void *ctx, unsigned int *width,
|
||||
unsigned int *height);
|
||||
void (*commit)(void *ctx);
|
||||
void (*disable)(void *ctx);
|
||||
};
|
||||
|
|
|
@ -22,6 +22,10 @@ struct exynos_plane {
|
|||
bool enabled;
|
||||
};
|
||||
|
||||
static const uint32_t formats[] = {
|
||||
DRM_FORMAT_XRGB8888,
|
||||
};
|
||||
|
||||
static int
|
||||
exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb, int crtc_x, int crtc_y,
|
||||
|
@ -115,9 +119,9 @@ int exynos_plane_init(struct drm_device *dev, unsigned int nr)
|
|||
|
||||
exynos_plane->overlay.zpos = DEFAULT_ZPOS;
|
||||
|
||||
/* TODO: format */
|
||||
return drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
|
||||
&exynos_plane_funcs, NULL, 0, false);
|
||||
&exynos_plane_funcs, formats, ARRAY_SIZE(formats),
|
||||
false);
|
||||
}
|
||||
|
||||
int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data,
|
||||
|
|
|
@ -0,0 +1,676 @@
|
|||
/* exynos_drm_vidi.c
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics Co.Ltd
|
||||
* Authors:
|
||||
* Inki Dae <inki.dae@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
#include "drmP.h"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <drm/exynos_drm.h>
|
||||
|
||||
#include "drm_edid.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
|
||||
#include "exynos_drm_drv.h"
|
||||
#include "exynos_drm_crtc.h"
|
||||
#include "exynos_drm_encoder.h"
|
||||
|
||||
/* vidi has totally three virtual windows. */
|
||||
#define WINDOWS_NR 3
|
||||
|
||||
#define get_vidi_context(dev) platform_get_drvdata(to_platform_device(dev))
|
||||
|
||||
struct vidi_win_data {
|
||||
unsigned int offset_x;
|
||||
unsigned int offset_y;
|
||||
unsigned int ovl_width;
|
||||
unsigned int ovl_height;
|
||||
unsigned int fb_width;
|
||||
unsigned int fb_height;
|
||||
unsigned int bpp;
|
||||
dma_addr_t dma_addr;
|
||||
void __iomem *vaddr;
|
||||
unsigned int buf_offsize;
|
||||
unsigned int line_size; /* bytes */
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
struct vidi_context {
|
||||
struct exynos_drm_subdrv subdrv;
|
||||
struct drm_crtc *crtc;
|
||||
struct vidi_win_data win_data[WINDOWS_NR];
|
||||
struct edid *raw_edid;
|
||||
unsigned int clkdiv;
|
||||
unsigned int default_win;
|
||||
unsigned long irq_flags;
|
||||
unsigned int connected;
|
||||
bool vblank_on;
|
||||
bool suspended;
|
||||
struct work_struct work;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
static const char fake_edid_info[] = {
|
||||
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
|
||||
0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
|
||||
0x0a, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0xbd,
|
||||
0xee, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x66, 0x21, 0x50, 0xb0, 0x51, 0x00,
|
||||
0x1b, 0x30, 0x40, 0x70, 0x36, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e,
|
||||
0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
|
||||
0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
|
||||
0x4b, 0x1a, 0x44, 0x17, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xbc, 0x02, 0x03, 0x1e, 0xf1,
|
||||
0x46, 0x84, 0x05, 0x03, 0x10, 0x20, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83,
|
||||
0x01, 0x00, 0x00, 0xe2, 0x00, 0x0f, 0x67, 0x03, 0x0c, 0x00, 0x10, 0x00,
|
||||
0xb8, 0x2d, 0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c,
|
||||
0x25, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x9e, 0x8c, 0x0a, 0xd0, 0x8a,
|
||||
0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xa0, 0x5a, 0x00, 0x00,
|
||||
0x00, 0x18, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
|
||||
0x45, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x06
|
||||
};
|
||||
|
||||
static void vidi_fake_vblank_handler(struct work_struct *work);
|
||||
|
||||
static bool vidi_display_is_connected(struct device *dev)
|
||||
{
|
||||
struct vidi_context *ctx = get_vidi_context(dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/*
|
||||
* connection request would come from user side
|
||||
* to do hotplug through specific ioctl.
|
||||
*/
|
||||
return ctx->connected ? true : false;
|
||||
}
|
||||
|
||||
static int vidi_get_edid(struct device *dev, struct drm_connector *connector,
|
||||
u8 *edid, int len)
|
||||
{
|
||||
struct vidi_context *ctx = get_vidi_context(dev);
|
||||
struct edid *raw_edid;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/*
|
||||
* the edid data comes from user side and it would be set
|
||||
* to ctx->raw_edid through specific ioctl.
|
||||
*/
|
||||
if (!ctx->raw_edid) {
|
||||
DRM_DEBUG_KMS("raw_edid is null.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
raw_edid = kzalloc(len, GFP_KERNEL);
|
||||
if (!raw_edid) {
|
||||
DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(raw_edid, ctx->raw_edid, min((1 + ctx->raw_edid->extensions)
|
||||
* EDID_LENGTH, len));
|
||||
|
||||
/* attach the edid data to connector. */
|
||||
connector->display_info.raw_edid = (char *)raw_edid;
|
||||
|
||||
memcpy(edid, ctx->raw_edid, min((1 + ctx->raw_edid->extensions)
|
||||
* EDID_LENGTH, len));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *vidi_get_panel(struct device *dev)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* TODO. */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int vidi_check_timing(struct device *dev, void *timing)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* TODO. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidi_display_power_on(struct device *dev, int mode)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* TODO */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct exynos_drm_display_ops vidi_display_ops = {
|
||||
.type = EXYNOS_DISPLAY_TYPE_VIDI,
|
||||
.is_connected = vidi_display_is_connected,
|
||||
.get_edid = vidi_get_edid,
|
||||
.get_panel = vidi_get_panel,
|
||||
.check_timing = vidi_check_timing,
|
||||
.power_on = vidi_display_power_on,
|
||||
};
|
||||
|
||||
static void vidi_dpms(struct device *subdrv_dev, int mode)
|
||||
{
|
||||
struct vidi_context *ctx = get_vidi_context(subdrv_dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
|
||||
|
||||
mutex_lock(&ctx->lock);
|
||||
|
||||
switch (mode) {
|
||||
case DRM_MODE_DPMS_ON:
|
||||
/* TODO. */
|
||||
break;
|
||||
case DRM_MODE_DPMS_STANDBY:
|
||||
case DRM_MODE_DPMS_SUSPEND:
|
||||
case DRM_MODE_DPMS_OFF:
|
||||
/* TODO. */
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG_KMS("unspecified mode %d\n", mode);
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&ctx->lock);
|
||||
}
|
||||
|
||||
static void vidi_apply(struct device *subdrv_dev)
|
||||
{
|
||||
struct vidi_context *ctx = get_vidi_context(subdrv_dev);
|
||||
struct exynos_drm_manager *mgr = &ctx->subdrv.manager;
|
||||
struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
|
||||
struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
|
||||
struct vidi_win_data *win_data;
|
||||
int i;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
for (i = 0; i < WINDOWS_NR; i++) {
|
||||
win_data = &ctx->win_data[i];
|
||||
if (win_data->enabled && (ovl_ops && ovl_ops->commit))
|
||||
ovl_ops->commit(subdrv_dev, i);
|
||||
}
|
||||
|
||||
if (mgr_ops && mgr_ops->commit)
|
||||
mgr_ops->commit(subdrv_dev);
|
||||
}
|
||||
|
||||
static void vidi_commit(struct device *dev)
|
||||
{
|
||||
struct vidi_context *ctx = get_vidi_context(dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (ctx->suspended)
|
||||
return;
|
||||
}
|
||||
|
||||
static int vidi_enable_vblank(struct device *dev)
|
||||
{
|
||||
struct vidi_context *ctx = get_vidi_context(dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (ctx->suspended)
|
||||
return -EPERM;
|
||||
|
||||
if (!test_and_set_bit(0, &ctx->irq_flags))
|
||||
ctx->vblank_on = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vidi_disable_vblank(struct device *dev)
|
||||
{
|
||||
struct vidi_context *ctx = get_vidi_context(dev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (ctx->suspended)
|
||||
return;
|
||||
|
||||
if (test_and_clear_bit(0, &ctx->irq_flags))
|
||||
ctx->vblank_on = false;
|
||||
}
|
||||
|
||||
static struct exynos_drm_manager_ops vidi_manager_ops = {
|
||||
.dpms = vidi_dpms,
|
||||
.apply = vidi_apply,
|
||||
.commit = vidi_commit,
|
||||
.enable_vblank = vidi_enable_vblank,
|
||||
.disable_vblank = vidi_disable_vblank,
|
||||
};
|
||||
|
||||
static void vidi_win_mode_set(struct device *dev,
|
||||
struct exynos_drm_overlay *overlay)
|
||||
{
|
||||
struct vidi_context *ctx = get_vidi_context(dev);
|
||||
struct vidi_win_data *win_data;
|
||||
int win;
|
||||
unsigned long offset;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (!overlay) {
|
||||
dev_err(dev, "overlay is NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
win = overlay->zpos;
|
||||
if (win == DEFAULT_ZPOS)
|
||||
win = ctx->default_win;
|
||||
|
||||
if (win < 0 || win > WINDOWS_NR)
|
||||
return;
|
||||
|
||||
offset = overlay->fb_x * (overlay->bpp >> 3);
|
||||
offset += overlay->fb_y * overlay->pitch;
|
||||
|
||||
DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
|
||||
|
||||
win_data = &ctx->win_data[win];
|
||||
|
||||
win_data->offset_x = overlay->crtc_x;
|
||||
win_data->offset_y = overlay->crtc_y;
|
||||
win_data->ovl_width = overlay->crtc_width;
|
||||
win_data->ovl_height = overlay->crtc_height;
|
||||
win_data->fb_width = overlay->fb_width;
|
||||
win_data->fb_height = overlay->fb_height;
|
||||
win_data->dma_addr = overlay->dma_addr[0] + offset;
|
||||
win_data->vaddr = overlay->vaddr[0] + offset;
|
||||
win_data->bpp = overlay->bpp;
|
||||
win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
|
||||
(overlay->bpp >> 3);
|
||||
win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
|
||||
|
||||
/*
|
||||
* some parts of win_data should be transferred to user side
|
||||
* through specific ioctl.
|
||||
*/
|
||||
|
||||
DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
|
||||
win_data->offset_x, win_data->offset_y);
|
||||
DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
|
||||
win_data->ovl_width, win_data->ovl_height);
|
||||
DRM_DEBUG_KMS("paddr = 0x%lx, vaddr = 0x%lx\n",
|
||||
(unsigned long)win_data->dma_addr,
|
||||
(unsigned long)win_data->vaddr);
|
||||
DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
|
||||
overlay->fb_width, overlay->crtc_width);
|
||||
}
|
||||
|
||||
static void vidi_win_commit(struct device *dev, int zpos)
|
||||
{
|
||||
struct vidi_context *ctx = get_vidi_context(dev);
|
||||
struct vidi_win_data *win_data;
|
||||
int win = zpos;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (ctx->suspended)
|
||||
return;
|
||||
|
||||
if (win == DEFAULT_ZPOS)
|
||||
win = ctx->default_win;
|
||||
|
||||
if (win < 0 || win > WINDOWS_NR)
|
||||
return;
|
||||
|
||||
win_data = &ctx->win_data[win];
|
||||
|
||||
win_data->enabled = true;
|
||||
|
||||
DRM_DEBUG_KMS("dma_addr = 0x%x\n", win_data->dma_addr);
|
||||
|
||||
if (ctx->vblank_on)
|
||||
schedule_work(&ctx->work);
|
||||
}
|
||||
|
||||
static void vidi_win_disable(struct device *dev, int zpos)
|
||||
{
|
||||
struct vidi_context *ctx = get_vidi_context(dev);
|
||||
struct vidi_win_data *win_data;
|
||||
int win = zpos;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (win == DEFAULT_ZPOS)
|
||||
win = ctx->default_win;
|
||||
|
||||
if (win < 0 || win > WINDOWS_NR)
|
||||
return;
|
||||
|
||||
win_data = &ctx->win_data[win];
|
||||
win_data->enabled = false;
|
||||
|
||||
/* TODO. */
|
||||
}
|
||||
|
||||
static struct exynos_drm_overlay_ops vidi_overlay_ops = {
|
||||
.mode_set = vidi_win_mode_set,
|
||||
.commit = vidi_win_commit,
|
||||
.disable = vidi_win_disable,
|
||||
};
|
||||
|
||||
static void vidi_finish_pageflip(struct drm_device *drm_dev, int crtc)
|
||||
{
|
||||
struct exynos_drm_private *dev_priv = drm_dev->dev_private;
|
||||
struct drm_pending_vblank_event *e, *t;
|
||||
struct timeval now;
|
||||
unsigned long flags;
|
||||
bool is_checked = false;
|
||||
|
||||
spin_lock_irqsave(&drm_dev->event_lock, flags);
|
||||
|
||||
list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
|
||||
base.link) {
|
||||
/* if event's pipe isn't same as crtc then ignore it. */
|
||||
if (crtc != e->pipe)
|
||||
continue;
|
||||
|
||||
is_checked = true;
|
||||
|
||||
do_gettimeofday(&now);
|
||||
e->event.sequence = 0;
|
||||
e->event.tv_sec = now.tv_sec;
|
||||
e->event.tv_usec = now.tv_usec;
|
||||
|
||||
list_move_tail(&e->base.link, &e->base.file_priv->event_list);
|
||||
wake_up_interruptible(&e->base.file_priv->event_wait);
|
||||
}
|
||||
|
||||
if (is_checked) {
|
||||
/*
|
||||
* call drm_vblank_put only in case that drm_vblank_get was
|
||||
* called.
|
||||
*/
|
||||
if (atomic_read(&drm_dev->vblank_refcount[crtc]) > 0)
|
||||
drm_vblank_put(drm_dev, crtc);
|
||||
|
||||
/*
|
||||
* don't off vblank if vblank_disable_allowed is 1,
|
||||
* because vblank would be off by timer handler.
|
||||
*/
|
||||
if (!drm_dev->vblank_disable_allowed)
|
||||
drm_vblank_off(drm_dev, crtc);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&drm_dev->event_lock, flags);
|
||||
}
|
||||
|
||||
static void vidi_fake_vblank_handler(struct work_struct *work)
|
||||
{
|
||||
struct vidi_context *ctx = container_of(work, struct vidi_context,
|
||||
work);
|
||||
struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
|
||||
struct exynos_drm_manager *manager = &subdrv->manager;
|
||||
|
||||
if (manager->pipe < 0)
|
||||
return;
|
||||
|
||||
/* refresh rate is about 50Hz. */
|
||||
usleep_range(16000, 20000);
|
||||
|
||||
drm_handle_vblank(subdrv->drm_dev, manager->pipe);
|
||||
vidi_finish_pageflip(subdrv->drm_dev, manager->pipe);
|
||||
}
|
||||
|
||||
static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/*
|
||||
* enable drm irq mode.
|
||||
* - with irq_enabled = 1, we can use the vblank feature.
|
||||
*
|
||||
* P.S. note that we wouldn't use drm irq handler but
|
||||
* just specific driver own one instead because
|
||||
* drm framework supports only one irq handler.
|
||||
*/
|
||||
drm_dev->irq_enabled = 1;
|
||||
|
||||
/*
|
||||
* with vblank_disable_allowed = 1, vblank interrupt will be disabled
|
||||
* by drm timer once a current process gives up ownership of
|
||||
* vblank event.(after drm_vblank_put function is called)
|
||||
*/
|
||||
drm_dev->vblank_disable_allowed = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vidi_subdrv_remove(struct drm_device *drm_dev)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* TODO. */
|
||||
}
|
||||
|
||||
static int vidi_power_on(struct vidi_context *ctx, bool enable)
|
||||
{
|
||||
struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
|
||||
struct device *dev = subdrv->manager.dev;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (enable != false && enable != true)
|
||||
return -EINVAL;
|
||||
|
||||
if (enable) {
|
||||
ctx->suspended = false;
|
||||
|
||||
/* if vblank was enabled status, enable it again. */
|
||||
if (test_and_clear_bit(0, &ctx->irq_flags))
|
||||
vidi_enable_vblank(dev);
|
||||
|
||||
vidi_apply(dev);
|
||||
} else {
|
||||
ctx->suspended = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidi_show_connection(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int rc;
|
||||
struct vidi_context *ctx = get_vidi_context(dev);
|
||||
|
||||
mutex_lock(&ctx->lock);
|
||||
|
||||
rc = sprintf(buf, "%d\n", ctx->connected);
|
||||
|
||||
mutex_unlock(&ctx->lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int vidi_store_connection(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct vidi_context *ctx = get_vidi_context(dev);
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
ret = kstrtoint(buf, 0, &ctx->connected);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ctx->connected > 1)
|
||||
return -EINVAL;
|
||||
|
||||
DRM_DEBUG_KMS("requested connection.\n");
|
||||
|
||||
drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(connection, 0644, vidi_show_connection,
|
||||
vidi_store_connection);
|
||||
|
||||
int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct vidi_context *ctx = NULL;
|
||||
struct drm_encoder *encoder;
|
||||
struct exynos_drm_manager *manager;
|
||||
struct exynos_drm_display_ops *display_ops;
|
||||
struct drm_exynos_vidi_connection *vidi = data;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (!vidi) {
|
||||
DRM_DEBUG_KMS("user data for vidi is null.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!vidi->edid) {
|
||||
DRM_DEBUG_KMS("edid data is null.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (vidi->connection > 1) {
|
||||
DRM_DEBUG_KMS("connection should be 0 or 1.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list,
|
||||
head) {
|
||||
manager = exynos_drm_get_manager(encoder);
|
||||
display_ops = manager->display_ops;
|
||||
|
||||
if (display_ops->type == EXYNOS_DISPLAY_TYPE_VIDI) {
|
||||
ctx = get_vidi_context(manager->dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctx) {
|
||||
DRM_DEBUG_KMS("not found virtual device type encoder.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ctx->connected == vidi->connection) {
|
||||
DRM_DEBUG_KMS("same connection request.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (vidi->connection)
|
||||
ctx->raw_edid = (struct edid *)vidi->edid;
|
||||
|
||||
ctx->connected = vidi->connection;
|
||||
drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit vidi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct vidi_context *ctx;
|
||||
struct exynos_drm_subdrv *subdrv;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->default_win = 0;
|
||||
|
||||
INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
|
||||
|
||||
/* for test */
|
||||
ctx->raw_edid = (struct edid *)fake_edid_info;
|
||||
|
||||
subdrv = &ctx->subdrv;
|
||||
subdrv->probe = vidi_subdrv_probe;
|
||||
subdrv->remove = vidi_subdrv_remove;
|
||||
subdrv->manager.pipe = -1;
|
||||
subdrv->manager.ops = &vidi_manager_ops;
|
||||
subdrv->manager.overlay_ops = &vidi_overlay_ops;
|
||||
subdrv->manager.display_ops = &vidi_display_ops;
|
||||
subdrv->manager.dev = dev;
|
||||
|
||||
mutex_init(&ctx->lock);
|
||||
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
||||
ret = device_create_file(&pdev->dev, &dev_attr_connection);
|
||||
if (ret < 0)
|
||||
DRM_INFO("failed to create connection sysfs.\n");
|
||||
|
||||
exynos_drm_subdrv_register(subdrv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit vidi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct vidi_context *ctx = platform_get_drvdata(pdev);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
exynos_drm_subdrv_unregister(&ctx->subdrv);
|
||||
|
||||
kfree(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int vidi_suspend(struct device *dev)
|
||||
{
|
||||
struct vidi_context *ctx = get_vidi_context(dev);
|
||||
|
||||
return vidi_power_on(ctx, false);
|
||||
}
|
||||
|
||||
static int vidi_resume(struct device *dev)
|
||||
{
|
||||
struct vidi_context *ctx = get_vidi_context(dev);
|
||||
|
||||
return vidi_power_on(ctx, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops vidi_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(vidi_suspend, vidi_resume)
|
||||
};
|
||||
|
||||
struct platform_driver vidi_driver = {
|
||||
.probe = vidi_probe,
|
||||
.remove = __devexit_p(vidi_remove),
|
||||
.driver = {
|
||||
.name = "exynos-drm-vidi",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &vidi_pm_ops,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,36 @@
|
|||
/* exynos_drm_vidi.h
|
||||
*
|
||||
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
|
||||
* Author: Inki Dae <inki.dae@samsung.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _EXYNOS_DRM_VIDI_H_
|
||||
#define _EXYNOS_DRM_VIDI_H_
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_VIDI
|
||||
int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
#else
|
||||
#define vidi_connection_ioctl NULL
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -28,56 +28,6 @@
|
|||
#ifndef _EXYNOS_HDMI_H_
|
||||
#define _EXYNOS_HDMI_H_
|
||||
|
||||
struct hdmi_conf {
|
||||
int width;
|
||||
int height;
|
||||
int vrefresh;
|
||||
bool interlace;
|
||||
const u8 *hdmiphy_data;
|
||||
const struct hdmi_preset_conf *conf;
|
||||
};
|
||||
|
||||
struct hdmi_resources {
|
||||
struct clk *hdmi;
|
||||
struct clk *sclk_hdmi;
|
||||
struct clk *sclk_pixel;
|
||||
struct clk *sclk_hdmiphy;
|
||||
struct clk *hdmiphy;
|
||||
struct regulator_bulk_data *regul_bulk;
|
||||
int regul_count;
|
||||
};
|
||||
|
||||
struct hdmi_context {
|
||||
struct device *dev;
|
||||
struct drm_device *drm_dev;
|
||||
struct fb_videomode *default_timing;
|
||||
unsigned int default_win;
|
||||
unsigned int default_bpp;
|
||||
bool hpd_handle;
|
||||
bool enabled;
|
||||
|
||||
struct resource *regs_res;
|
||||
/** base address of HDMI registers */
|
||||
void __iomem *regs;
|
||||
/** HDMI hotplug interrupt */
|
||||
unsigned int irq;
|
||||
/** workqueue for delayed work */
|
||||
struct workqueue_struct *wq;
|
||||
/** hotplug handling work */
|
||||
struct work_struct hotplug_work;
|
||||
|
||||
struct i2c_client *ddc_port;
|
||||
struct i2c_client *hdmiphy_port;
|
||||
|
||||
/** current hdmiphy conf index */
|
||||
int cur_conf;
|
||||
/** other resources */
|
||||
struct hdmi_resources res;
|
||||
|
||||
void *parent_ctx;
|
||||
};
|
||||
|
||||
|
||||
void hdmi_attach_ddc_client(struct i2c_client *ddc);
|
||||
void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy);
|
||||
|
||||
|
|
|
@ -36,11 +36,57 @@
|
|||
|
||||
#include "exynos_drm_drv.h"
|
||||
#include "exynos_drm_hdmi.h"
|
||||
#include "exynos_hdmi.h"
|
||||
#include "exynos_mixer.h"
|
||||
|
||||
#define HDMI_OVERLAY_NUMBER 3
|
||||
|
||||
#define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
|
||||
|
||||
struct hdmi_win_data {
|
||||
dma_addr_t dma_addr;
|
||||
void __iomem *vaddr;
|
||||
dma_addr_t chroma_dma_addr;
|
||||
void __iomem *chroma_vaddr;
|
||||
uint32_t pixel_format;
|
||||
unsigned int bpp;
|
||||
unsigned int crtc_x;
|
||||
unsigned int crtc_y;
|
||||
unsigned int crtc_width;
|
||||
unsigned int crtc_height;
|
||||
unsigned int fb_x;
|
||||
unsigned int fb_y;
|
||||
unsigned int fb_width;
|
||||
unsigned int fb_height;
|
||||
unsigned int mode_width;
|
||||
unsigned int mode_height;
|
||||
unsigned int scan_flags;
|
||||
};
|
||||
|
||||
struct mixer_resources {
|
||||
struct device *dev;
|
||||
int irq;
|
||||
void __iomem *mixer_regs;
|
||||
void __iomem *vp_regs;
|
||||
spinlock_t reg_slock;
|
||||
struct clk *mixer;
|
||||
struct clk *vp;
|
||||
struct clk *sclk_mixer;
|
||||
struct clk *sclk_hdmi;
|
||||
struct clk *sclk_dac;
|
||||
};
|
||||
|
||||
struct mixer_context {
|
||||
struct fb_videomode *default_timing;
|
||||
unsigned int default_win;
|
||||
unsigned int default_bpp;
|
||||
unsigned int irq;
|
||||
int pipe;
|
||||
bool interlace;
|
||||
bool vp_enabled;
|
||||
|
||||
struct mixer_resources mixer_res;
|
||||
struct hdmi_win_data win_data[HDMI_OVERLAY_NUMBER];
|
||||
};
|
||||
|
||||
static const u8 filter_y_horiz_tap8[] = {
|
||||
0, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, 0, 0, 0,
|
||||
|
@ -1066,10 +1112,3 @@ struct platform_driver mixer_driver = {
|
|||
.probe = mixer_probe,
|
||||
.remove = __devexit_p(mixer_remove),
|
||||
};
|
||||
EXPORT_SYMBOL(mixer_driver);
|
||||
|
||||
MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>");
|
||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung DRM HDMI mixer Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
||||
* Authors:
|
||||
* Seung-Woo Kim <sw0312.kim@samsung.com>
|
||||
* Inki Dae <inki.dae@samsung.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _EXYNOS_MIXER_H_
|
||||
#define _EXYNOS_MIXER_H_
|
||||
|
||||
#define HDMI_OVERLAY_NUMBER 3
|
||||
|
||||
struct hdmi_win_data {
|
||||
dma_addr_t dma_addr;
|
||||
void __iomem *vaddr;
|
||||
dma_addr_t chroma_dma_addr;
|
||||
void __iomem *chroma_vaddr;
|
||||
uint32_t pixel_format;
|
||||
unsigned int bpp;
|
||||
unsigned int crtc_x;
|
||||
unsigned int crtc_y;
|
||||
unsigned int crtc_width;
|
||||
unsigned int crtc_height;
|
||||
unsigned int fb_x;
|
||||
unsigned int fb_y;
|
||||
unsigned int fb_width;
|
||||
unsigned int fb_height;
|
||||
unsigned int mode_width;
|
||||
unsigned int mode_height;
|
||||
unsigned int scan_flags;
|
||||
};
|
||||
|
||||
struct mixer_resources {
|
||||
struct device *dev;
|
||||
/** interrupt index */
|
||||
int irq;
|
||||
/** pointer to Mixer registers */
|
||||
void __iomem *mixer_regs;
|
||||
/** pointer to Video Processor registers */
|
||||
void __iomem *vp_regs;
|
||||
/** spinlock for protection of registers */
|
||||
spinlock_t reg_slock;
|
||||
/** other resources */
|
||||
struct clk *mixer;
|
||||
struct clk *vp;
|
||||
struct clk *sclk_mixer;
|
||||
struct clk *sclk_hdmi;
|
||||
struct clk *sclk_dac;
|
||||
};
|
||||
|
||||
struct mixer_context {
|
||||
unsigned int default_win;
|
||||
struct fb_videomode *default_timing;
|
||||
unsigned int default_bpp;
|
||||
|
||||
/** mixer interrupt */
|
||||
unsigned int irq;
|
||||
/** current crtc pipe for vblank */
|
||||
int pipe;
|
||||
/** interlace scan mode */
|
||||
bool interlace;
|
||||
/** vp enabled status */
|
||||
bool vp_enabled;
|
||||
|
||||
/** mixer and vp resources */
|
||||
struct mixer_resources mixer_res;
|
||||
|
||||
/** overlay window data */
|
||||
struct hdmi_win_data win_data[HDMI_OVERLAY_NUMBER];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -19,64 +19,67 @@
|
|||
* Register part
|
||||
*/
|
||||
|
||||
/* HDMI Version 1.3 & Common */
|
||||
#define HDMI_CTRL_BASE(x) ((x) + 0x00000000)
|
||||
#define HDMI_CORE_BASE(x) ((x) + 0x00010000)
|
||||
#define HDMI_I2S_BASE(x) ((x) + 0x00040000)
|
||||
#define HDMI_TG_BASE(x) ((x) + 0x00050000)
|
||||
|
||||
/* Control registers */
|
||||
#define HDMI_INTC_CON HDMI_CTRL_BASE(0x0000)
|
||||
#define HDMI_INTC_FLAG HDMI_CTRL_BASE(0x0004)
|
||||
#define HDMI_HPD_STATUS HDMI_CTRL_BASE(0x000C)
|
||||
#define HDMI_PHY_RSTOUT HDMI_CTRL_BASE(0x0014)
|
||||
#define HDMI_PHY_VPLL HDMI_CTRL_BASE(0x0018)
|
||||
#define HDMI_PHY_CMU HDMI_CTRL_BASE(0x001C)
|
||||
#define HDMI_CORE_RSTOUT HDMI_CTRL_BASE(0x0020)
|
||||
#define HDMI_V13_PHY_RSTOUT HDMI_CTRL_BASE(0x0014)
|
||||
#define HDMI_V13_PHY_VPLL HDMI_CTRL_BASE(0x0018)
|
||||
#define HDMI_V13_PHY_CMU HDMI_CTRL_BASE(0x001C)
|
||||
#define HDMI_V13_CORE_RSTOUT HDMI_CTRL_BASE(0x0020)
|
||||
|
||||
/* Core registers */
|
||||
#define HDMI_CON_0 HDMI_CORE_BASE(0x0000)
|
||||
#define HDMI_CON_1 HDMI_CORE_BASE(0x0004)
|
||||
#define HDMI_CON_2 HDMI_CORE_BASE(0x0008)
|
||||
#define HDMI_SYS_STATUS HDMI_CORE_BASE(0x0010)
|
||||
#define HDMI_PHY_STATUS HDMI_CORE_BASE(0x0014)
|
||||
#define HDMI_V13_PHY_STATUS HDMI_CORE_BASE(0x0014)
|
||||
#define HDMI_STATUS_EN HDMI_CORE_BASE(0x0020)
|
||||
#define HDMI_HPD HDMI_CORE_BASE(0x0030)
|
||||
#define HDMI_MODE_SEL HDMI_CORE_BASE(0x0040)
|
||||
#define HDMI_BLUE_SCREEN_0 HDMI_CORE_BASE(0x0050)
|
||||
#define HDMI_BLUE_SCREEN_1 HDMI_CORE_BASE(0x0054)
|
||||
#define HDMI_BLUE_SCREEN_2 HDMI_CORE_BASE(0x0058)
|
||||
#define HDMI_ENC_EN HDMI_CORE_BASE(0x0044)
|
||||
#define HDMI_V13_BLUE_SCREEN_0 HDMI_CORE_BASE(0x0050)
|
||||
#define HDMI_V13_BLUE_SCREEN_1 HDMI_CORE_BASE(0x0054)
|
||||
#define HDMI_V13_BLUE_SCREEN_2 HDMI_CORE_BASE(0x0058)
|
||||
#define HDMI_H_BLANK_0 HDMI_CORE_BASE(0x00A0)
|
||||
#define HDMI_H_BLANK_1 HDMI_CORE_BASE(0x00A4)
|
||||
#define HDMI_V_BLANK_0 HDMI_CORE_BASE(0x00B0)
|
||||
#define HDMI_V_BLANK_1 HDMI_CORE_BASE(0x00B4)
|
||||
#define HDMI_V_BLANK_2 HDMI_CORE_BASE(0x00B8)
|
||||
#define HDMI_H_V_LINE_0 HDMI_CORE_BASE(0x00C0)
|
||||
#define HDMI_H_V_LINE_1 HDMI_CORE_BASE(0x00C4)
|
||||
#define HDMI_H_V_LINE_2 HDMI_CORE_BASE(0x00C8)
|
||||
#define HDMI_V13_V_BLANK_0 HDMI_CORE_BASE(0x00B0)
|
||||
#define HDMI_V13_V_BLANK_1 HDMI_CORE_BASE(0x00B4)
|
||||
#define HDMI_V13_V_BLANK_2 HDMI_CORE_BASE(0x00B8)
|
||||
#define HDMI_V13_H_V_LINE_0 HDMI_CORE_BASE(0x00C0)
|
||||
#define HDMI_V13_H_V_LINE_1 HDMI_CORE_BASE(0x00C4)
|
||||
#define HDMI_V13_H_V_LINE_2 HDMI_CORE_BASE(0x00C8)
|
||||
#define HDMI_VSYNC_POL HDMI_CORE_BASE(0x00E4)
|
||||
#define HDMI_INT_PRO_MODE HDMI_CORE_BASE(0x00E8)
|
||||
#define HDMI_V_BLANK_F_0 HDMI_CORE_BASE(0x0110)
|
||||
#define HDMI_V_BLANK_F_1 HDMI_CORE_BASE(0x0114)
|
||||
#define HDMI_V_BLANK_F_2 HDMI_CORE_BASE(0x0118)
|
||||
#define HDMI_H_SYNC_GEN_0 HDMI_CORE_BASE(0x0120)
|
||||
#define HDMI_H_SYNC_GEN_1 HDMI_CORE_BASE(0x0124)
|
||||
#define HDMI_H_SYNC_GEN_2 HDMI_CORE_BASE(0x0128)
|
||||
#define HDMI_V_SYNC_GEN_1_0 HDMI_CORE_BASE(0x0130)
|
||||
#define HDMI_V_SYNC_GEN_1_1 HDMI_CORE_BASE(0x0134)
|
||||
#define HDMI_V_SYNC_GEN_1_2 HDMI_CORE_BASE(0x0138)
|
||||
#define HDMI_V_SYNC_GEN_2_0 HDMI_CORE_BASE(0x0140)
|
||||
#define HDMI_V_SYNC_GEN_2_1 HDMI_CORE_BASE(0x0144)
|
||||
#define HDMI_V_SYNC_GEN_2_2 HDMI_CORE_BASE(0x0148)
|
||||
#define HDMI_V_SYNC_GEN_3_0 HDMI_CORE_BASE(0x0150)
|
||||
#define HDMI_V_SYNC_GEN_3_1 HDMI_CORE_BASE(0x0154)
|
||||
#define HDMI_V_SYNC_GEN_3_2 HDMI_CORE_BASE(0x0158)
|
||||
#define HDMI_ACR_CON HDMI_CORE_BASE(0x0180)
|
||||
#define HDMI_AVI_CON HDMI_CORE_BASE(0x0300)
|
||||
#define HDMI_AVI_BYTE(n) HDMI_CORE_BASE(0x0320 + 4 * (n))
|
||||
#define HDMI_DC_CONTROL HDMI_CORE_BASE(0x05C0)
|
||||
#define HDMI_VIDEO_PATTERN_GEN HDMI_CORE_BASE(0x05C4)
|
||||
#define HDMI_HPD_GEN HDMI_CORE_BASE(0x05C8)
|
||||
#define HDMI_AUI_CON HDMI_CORE_BASE(0x0360)
|
||||
#define HDMI_SPD_CON HDMI_CORE_BASE(0x0400)
|
||||
#define HDMI_V13_V_BLANK_F_0 HDMI_CORE_BASE(0x0110)
|
||||
#define HDMI_V13_V_BLANK_F_1 HDMI_CORE_BASE(0x0114)
|
||||
#define HDMI_V13_V_BLANK_F_2 HDMI_CORE_BASE(0x0118)
|
||||
#define HDMI_V13_H_SYNC_GEN_0 HDMI_CORE_BASE(0x0120)
|
||||
#define HDMI_V13_H_SYNC_GEN_1 HDMI_CORE_BASE(0x0124)
|
||||
#define HDMI_V13_H_SYNC_GEN_2 HDMI_CORE_BASE(0x0128)
|
||||
#define HDMI_V13_V_SYNC_GEN_1_0 HDMI_CORE_BASE(0x0130)
|
||||
#define HDMI_V13_V_SYNC_GEN_1_1 HDMI_CORE_BASE(0x0134)
|
||||
#define HDMI_V13_V_SYNC_GEN_1_2 HDMI_CORE_BASE(0x0138)
|
||||
#define HDMI_V13_V_SYNC_GEN_2_0 HDMI_CORE_BASE(0x0140)
|
||||
#define HDMI_V13_V_SYNC_GEN_2_1 HDMI_CORE_BASE(0x0144)
|
||||
#define HDMI_V13_V_SYNC_GEN_2_2 HDMI_CORE_BASE(0x0148)
|
||||
#define HDMI_V13_V_SYNC_GEN_3_0 HDMI_CORE_BASE(0x0150)
|
||||
#define HDMI_V13_V_SYNC_GEN_3_1 HDMI_CORE_BASE(0x0154)
|
||||
#define HDMI_V13_V_SYNC_GEN_3_2 HDMI_CORE_BASE(0x0158)
|
||||
#define HDMI_V13_ACR_CON HDMI_CORE_BASE(0x0180)
|
||||
#define HDMI_V13_AVI_CON HDMI_CORE_BASE(0x0300)
|
||||
#define HDMI_V13_AVI_BYTE(n) HDMI_CORE_BASE(0x0320 + 4 * (n))
|
||||
#define HDMI_V13_DC_CONTROL HDMI_CORE_BASE(0x05C0)
|
||||
#define HDMI_V13_VIDEO_PATTERN_GEN HDMI_CORE_BASE(0x05C4)
|
||||
#define HDMI_V13_HPD_GEN HDMI_CORE_BASE(0x05C8)
|
||||
#define HDMI_V13_AUI_CON HDMI_CORE_BASE(0x0360)
|
||||
#define HDMI_V13_SPD_CON HDMI_CORE_BASE(0x0400)
|
||||
|
||||
/* Timing generator registers */
|
||||
#define HDMI_TG_CMD HDMI_TG_BASE(0x0000)
|
||||
|
@ -130,6 +133,9 @@
|
|||
|
||||
/* HDMI_CON_0 */
|
||||
#define HDMI_BLUE_SCR_EN (1 << 5)
|
||||
#define HDMI_ASP_EN (1 << 2)
|
||||
#define HDMI_ASP_DIS (0 << 2)
|
||||
#define HDMI_ASP_MASK (1 << 2)
|
||||
#define HDMI_EN (1 << 0)
|
||||
|
||||
/* HDMI_PHY_STATUS */
|
||||
|
@ -138,10 +144,418 @@
|
|||
/* HDMI_MODE_SEL */
|
||||
#define HDMI_MODE_HDMI_EN (1 << 1)
|
||||
#define HDMI_MODE_DVI_EN (1 << 0)
|
||||
#define HDMI_DVI_MODE_EN (1)
|
||||
#define HDMI_DVI_MODE_DIS (0)
|
||||
#define HDMI_MODE_MASK (3 << 0)
|
||||
|
||||
/* HDMI_TG_CMD */
|
||||
#define HDMI_TG_EN (1 << 0)
|
||||
#define HDMI_FIELD_EN (1 << 1)
|
||||
|
||||
|
||||
/* HDMI Version 1.4 */
|
||||
/* Control registers */
|
||||
/* #define HDMI_INTC_CON HDMI_CTRL_BASE(0x0000) */
|
||||
/* #define HDMI_INTC_FLAG HDMI_CTRL_BASE(0x0004) */
|
||||
#define HDMI_HDCP_KEY_LOAD HDMI_CTRL_BASE(0x0008)
|
||||
/* #define HDMI_HPD_STATUS HDMI_CTRL_BASE(0x000C) */
|
||||
#define HDMI_INTC_CON_1 HDMI_CTRL_BASE(0x0010)
|
||||
#define HDMI_INTC_FLAG_1 HDMI_CTRL_BASE(0x0014)
|
||||
#define HDMI_PHY_STATUS_0 HDMI_CTRL_BASE(0x0020)
|
||||
#define HDMI_PHY_STATUS_CMU HDMI_CTRL_BASE(0x0024)
|
||||
#define HDMI_PHY_STATUS_PLL HDMI_CTRL_BASE(0x0028)
|
||||
#define HDMI_PHY_CON_0 HDMI_CTRL_BASE(0x0030)
|
||||
#define HDMI_HPD_CTRL HDMI_CTRL_BASE(0x0040)
|
||||
#define HDMI_HPD_ST HDMI_CTRL_BASE(0x0044)
|
||||
#define HDMI_HPD_TH_X HDMI_CTRL_BASE(0x0050)
|
||||
#define HDMI_AUDIO_CLKSEL HDMI_CTRL_BASE(0x0070)
|
||||
#define HDMI_PHY_RSTOUT HDMI_CTRL_BASE(0x0074)
|
||||
#define HDMI_PHY_VPLL HDMI_CTRL_BASE(0x0078)
|
||||
#define HDMI_PHY_CMU HDMI_CTRL_BASE(0x007C)
|
||||
#define HDMI_CORE_RSTOUT HDMI_CTRL_BASE(0x0080)
|
||||
|
||||
/* Video related registers */
|
||||
#define HDMI_YMAX HDMI_CORE_BASE(0x0060)
|
||||
#define HDMI_YMIN HDMI_CORE_BASE(0x0064)
|
||||
#define HDMI_CMAX HDMI_CORE_BASE(0x0068)
|
||||
#define HDMI_CMIN HDMI_CORE_BASE(0x006C)
|
||||
|
||||
#define HDMI_V2_BLANK_0 HDMI_CORE_BASE(0x00B0)
|
||||
#define HDMI_V2_BLANK_1 HDMI_CORE_BASE(0x00B4)
|
||||
#define HDMI_V1_BLANK_0 HDMI_CORE_BASE(0x00B8)
|
||||
#define HDMI_V1_BLANK_1 HDMI_CORE_BASE(0x00BC)
|
||||
|
||||
#define HDMI_V_LINE_0 HDMI_CORE_BASE(0x00C0)
|
||||
#define HDMI_V_LINE_1 HDMI_CORE_BASE(0x00C4)
|
||||
#define HDMI_H_LINE_0 HDMI_CORE_BASE(0x00C8)
|
||||
#define HDMI_H_LINE_1 HDMI_CORE_BASE(0x00CC)
|
||||
|
||||
#define HDMI_HSYNC_POL HDMI_CORE_BASE(0x00E0)
|
||||
|
||||
#define HDMI_V_BLANK_F0_0 HDMI_CORE_BASE(0x0110)
|
||||
#define HDMI_V_BLANK_F0_1 HDMI_CORE_BASE(0x0114)
|
||||
#define HDMI_V_BLANK_F1_0 HDMI_CORE_BASE(0x0118)
|
||||
#define HDMI_V_BLANK_F1_1 HDMI_CORE_BASE(0x011C)
|
||||
|
||||
#define HDMI_H_SYNC_START_0 HDMI_CORE_BASE(0x0120)
|
||||
#define HDMI_H_SYNC_START_1 HDMI_CORE_BASE(0x0124)
|
||||
#define HDMI_H_SYNC_END_0 HDMI_CORE_BASE(0x0128)
|
||||
#define HDMI_H_SYNC_END_1 HDMI_CORE_BASE(0x012C)
|
||||
|
||||
#define HDMI_V_SYNC_LINE_BEF_2_0 HDMI_CORE_BASE(0x0130)
|
||||
#define HDMI_V_SYNC_LINE_BEF_2_1 HDMI_CORE_BASE(0x0134)
|
||||
#define HDMI_V_SYNC_LINE_BEF_1_0 HDMI_CORE_BASE(0x0138)
|
||||
#define HDMI_V_SYNC_LINE_BEF_1_1 HDMI_CORE_BASE(0x013C)
|
||||
|
||||
#define HDMI_V_SYNC_LINE_AFT_2_0 HDMI_CORE_BASE(0x0140)
|
||||
#define HDMI_V_SYNC_LINE_AFT_2_1 HDMI_CORE_BASE(0x0144)
|
||||
#define HDMI_V_SYNC_LINE_AFT_1_0 HDMI_CORE_BASE(0x0148)
|
||||
#define HDMI_V_SYNC_LINE_AFT_1_1 HDMI_CORE_BASE(0x014C)
|
||||
|
||||
#define HDMI_V_SYNC_LINE_AFT_PXL_2_0 HDMI_CORE_BASE(0x0150)
|
||||
#define HDMI_V_SYNC_LINE_AFT_PXL_2_1 HDMI_CORE_BASE(0x0154)
|
||||
#define HDMI_V_SYNC_LINE_AFT_PXL_1_0 HDMI_CORE_BASE(0x0158)
|
||||
#define HDMI_V_SYNC_LINE_AFT_PXL_1_1 HDMI_CORE_BASE(0x015C)
|
||||
|
||||
#define HDMI_V_BLANK_F2_0 HDMI_CORE_BASE(0x0160)
|
||||
#define HDMI_V_BLANK_F2_1 HDMI_CORE_BASE(0x0164)
|
||||
#define HDMI_V_BLANK_F3_0 HDMI_CORE_BASE(0x0168)
|
||||
#define HDMI_V_BLANK_F3_1 HDMI_CORE_BASE(0x016C)
|
||||
#define HDMI_V_BLANK_F4_0 HDMI_CORE_BASE(0x0170)
|
||||
#define HDMI_V_BLANK_F4_1 HDMI_CORE_BASE(0x0174)
|
||||
#define HDMI_V_BLANK_F5_0 HDMI_CORE_BASE(0x0178)
|
||||
#define HDMI_V_BLANK_F5_1 HDMI_CORE_BASE(0x017C)
|
||||
|
||||
#define HDMI_V_SYNC_LINE_AFT_3_0 HDMI_CORE_BASE(0x0180)
|
||||
#define HDMI_V_SYNC_LINE_AFT_3_1 HDMI_CORE_BASE(0x0184)
|
||||
#define HDMI_V_SYNC_LINE_AFT_4_0 HDMI_CORE_BASE(0x0188)
|
||||
#define HDMI_V_SYNC_LINE_AFT_4_1 HDMI_CORE_BASE(0x018C)
|
||||
#define HDMI_V_SYNC_LINE_AFT_5_0 HDMI_CORE_BASE(0x0190)
|
||||
#define HDMI_V_SYNC_LINE_AFT_5_1 HDMI_CORE_BASE(0x0194)
|
||||
#define HDMI_V_SYNC_LINE_AFT_6_0 HDMI_CORE_BASE(0x0198)
|
||||
#define HDMI_V_SYNC_LINE_AFT_6_1 HDMI_CORE_BASE(0x019C)
|
||||
|
||||
#define HDMI_V_SYNC_LINE_AFT_PXL_3_0 HDMI_CORE_BASE(0x01A0)
|
||||
#define HDMI_V_SYNC_LINE_AFT_PXL_3_1 HDMI_CORE_BASE(0x01A4)
|
||||
#define HDMI_V_SYNC_LINE_AFT_PXL_4_0 HDMI_CORE_BASE(0x01A8)
|
||||
#define HDMI_V_SYNC_LINE_AFT_PXL_4_1 HDMI_CORE_BASE(0x01AC)
|
||||
#define HDMI_V_SYNC_LINE_AFT_PXL_5_0 HDMI_CORE_BASE(0x01B0)
|
||||
#define HDMI_V_SYNC_LINE_AFT_PXL_5_1 HDMI_CORE_BASE(0x01B4)
|
||||
#define HDMI_V_SYNC_LINE_AFT_PXL_6_0 HDMI_CORE_BASE(0x01B8)
|
||||
#define HDMI_V_SYNC_LINE_AFT_PXL_6_1 HDMI_CORE_BASE(0x01BC)
|
||||
|
||||
#define HDMI_VACT_SPACE_1_0 HDMI_CORE_BASE(0x01C0)
|
||||
#define HDMI_VACT_SPACE_1_1 HDMI_CORE_BASE(0x01C4)
|
||||
#define HDMI_VACT_SPACE_2_0 HDMI_CORE_BASE(0x01C8)
|
||||
#define HDMI_VACT_SPACE_2_1 HDMI_CORE_BASE(0x01CC)
|
||||
#define HDMI_VACT_SPACE_3_0 HDMI_CORE_BASE(0x01D0)
|
||||
#define HDMI_VACT_SPACE_3_1 HDMI_CORE_BASE(0x01D4)
|
||||
#define HDMI_VACT_SPACE_4_0 HDMI_CORE_BASE(0x01D8)
|
||||
#define HDMI_VACT_SPACE_4_1 HDMI_CORE_BASE(0x01DC)
|
||||
#define HDMI_VACT_SPACE_5_0 HDMI_CORE_BASE(0x01E0)
|
||||
#define HDMI_VACT_SPACE_5_1 HDMI_CORE_BASE(0x01E4)
|
||||
#define HDMI_VACT_SPACE_6_0 HDMI_CORE_BASE(0x01E8)
|
||||
#define HDMI_VACT_SPACE_6_1 HDMI_CORE_BASE(0x01EC)
|
||||
|
||||
#define HDMI_GCP_CON HDMI_CORE_BASE(0x0200)
|
||||
#define HDMI_GCP_BYTE1 HDMI_CORE_BASE(0x0210)
|
||||
#define HDMI_GCP_BYTE2 HDMI_CORE_BASE(0x0214)
|
||||
#define HDMI_GCP_BYTE3 HDMI_CORE_BASE(0x0218)
|
||||
|
||||
/* Audio related registers */
|
||||
#define HDMI_ASP_CON HDMI_CORE_BASE(0x0300)
|
||||
#define HDMI_ASP_SP_FLAT HDMI_CORE_BASE(0x0304)
|
||||
#define HDMI_ASP_CHCFG0 HDMI_CORE_BASE(0x0310)
|
||||
#define HDMI_ASP_CHCFG1 HDMI_CORE_BASE(0x0314)
|
||||
#define HDMI_ASP_CHCFG2 HDMI_CORE_BASE(0x0318)
|
||||
#define HDMI_ASP_CHCFG3 HDMI_CORE_BASE(0x031C)
|
||||
|
||||
#define HDMI_ACR_CON HDMI_CORE_BASE(0x0400)
|
||||
#define HDMI_ACR_MCTS0 HDMI_CORE_BASE(0x0410)
|
||||
#define HDMI_ACR_MCTS1 HDMI_CORE_BASE(0x0414)
|
||||
#define HDMI_ACR_MCTS2 HDMI_CORE_BASE(0x0418)
|
||||
#define HDMI_ACR_CTS0 HDMI_CORE_BASE(0x0420)
|
||||
#define HDMI_ACR_CTS1 HDMI_CORE_BASE(0x0424)
|
||||
#define HDMI_ACR_CTS2 HDMI_CORE_BASE(0x0428)
|
||||
#define HDMI_ACR_N0 HDMI_CORE_BASE(0x0430)
|
||||
#define HDMI_ACR_N1 HDMI_CORE_BASE(0x0434)
|
||||
#define HDMI_ACR_N2 HDMI_CORE_BASE(0x0438)
|
||||
|
||||
/* Packet related registers */
|
||||
#define HDMI_ACP_CON HDMI_CORE_BASE(0x0500)
|
||||
#define HDMI_ACP_TYPE HDMI_CORE_BASE(0x0514)
|
||||
#define HDMI_ACP_DATA(n) HDMI_CORE_BASE(0x0520 + 4 * (n))
|
||||
|
||||
#define HDMI_ISRC_CON HDMI_CORE_BASE(0x0600)
|
||||
#define HDMI_ISRC1_HEADER1 HDMI_CORE_BASE(0x0614)
|
||||
#define HDMI_ISRC1_DATA(n) HDMI_CORE_BASE(0x0620 + 4 * (n))
|
||||
#define HDMI_ISRC2_DATA(n) HDMI_CORE_BASE(0x06A0 + 4 * (n))
|
||||
|
||||
#define HDMI_AVI_CON HDMI_CORE_BASE(0x0700)
|
||||
#define HDMI_AVI_HEADER0 HDMI_CORE_BASE(0x0710)
|
||||
#define HDMI_AVI_HEADER1 HDMI_CORE_BASE(0x0714)
|
||||
#define HDMI_AVI_HEADER2 HDMI_CORE_BASE(0x0718)
|
||||
#define HDMI_AVI_CHECK_SUM HDMI_CORE_BASE(0x071C)
|
||||
#define HDMI_AVI_BYTE(n) HDMI_CORE_BASE(0x0720 + 4 * (n))
|
||||
|
||||
#define HDMI_AUI_CON HDMI_CORE_BASE(0x0800)
|
||||
#define HDMI_AUI_HEADER0 HDMI_CORE_BASE(0x0810)
|
||||
#define HDMI_AUI_HEADER1 HDMI_CORE_BASE(0x0814)
|
||||
#define HDMI_AUI_HEADER2 HDMI_CORE_BASE(0x0818)
|
||||
#define HDMI_AUI_CHECK_SUM HDMI_CORE_BASE(0x081C)
|
||||
#define HDMI_AUI_BYTE(n) HDMI_CORE_BASE(0x0820 + 4 * (n))
|
||||
|
||||
#define HDMI_MPG_CON HDMI_CORE_BASE(0x0900)
|
||||
#define HDMI_MPG_CHECK_SUM HDMI_CORE_BASE(0x091C)
|
||||
#define HDMI_MPG_DATA(n) HDMI_CORE_BASE(0x0920 + 4 * (n))
|
||||
|
||||
#define HDMI_SPD_CON HDMI_CORE_BASE(0x0A00)
|
||||
#define HDMI_SPD_HEADER0 HDMI_CORE_BASE(0x0A10)
|
||||
#define HDMI_SPD_HEADER1 HDMI_CORE_BASE(0x0A14)
|
||||
#define HDMI_SPD_HEADER2 HDMI_CORE_BASE(0x0A18)
|
||||
#define HDMI_SPD_DATA(n) HDMI_CORE_BASE(0x0A20 + 4 * (n))
|
||||
|
||||
#define HDMI_GAMUT_CON HDMI_CORE_BASE(0x0B00)
|
||||
#define HDMI_GAMUT_HEADER0 HDMI_CORE_BASE(0x0B10)
|
||||
#define HDMI_GAMUT_HEADER1 HDMI_CORE_BASE(0x0B14)
|
||||
#define HDMI_GAMUT_HEADER2 HDMI_CORE_BASE(0x0B18)
|
||||
#define HDMI_GAMUT_METADATA(n) HDMI_CORE_BASE(0x0B20 + 4 * (n))
|
||||
|
||||
#define HDMI_VSI_CON HDMI_CORE_BASE(0x0C00)
|
||||
#define HDMI_VSI_HEADER0 HDMI_CORE_BASE(0x0C10)
|
||||
#define HDMI_VSI_HEADER1 HDMI_CORE_BASE(0x0C14)
|
||||
#define HDMI_VSI_HEADER2 HDMI_CORE_BASE(0x0C18)
|
||||
#define HDMI_VSI_DATA(n) HDMI_CORE_BASE(0x0C20 + 4 * (n))
|
||||
|
||||
#define HDMI_DC_CONTROL HDMI_CORE_BASE(0x0D00)
|
||||
#define HDMI_VIDEO_PATTERN_GEN HDMI_CORE_BASE(0x0D04)
|
||||
|
||||
#define HDMI_AN_SEED_SEL HDMI_CORE_BASE(0x0E48)
|
||||
#define HDMI_AN_SEED_0 HDMI_CORE_BASE(0x0E58)
|
||||
#define HDMI_AN_SEED_1 HDMI_CORE_BASE(0x0E5C)
|
||||
#define HDMI_AN_SEED_2 HDMI_CORE_BASE(0x0E60)
|
||||
#define HDMI_AN_SEED_3 HDMI_CORE_BASE(0x0E64)
|
||||
|
||||
/* HDCP related registers */
|
||||
#define HDMI_HDCP_SHA1(n) HDMI_CORE_BASE(0x7000 + 4 * (n))
|
||||
#define HDMI_HDCP_KSV_LIST(n) HDMI_CORE_BASE(0x7050 + 4 * (n))
|
||||
|
||||
#define HDMI_HDCP_KSV_LIST_CON HDMI_CORE_BASE(0x7064)
|
||||
#define HDMI_HDCP_SHA_RESULT HDMI_CORE_BASE(0x7070)
|
||||
#define HDMI_HDCP_CTRL1 HDMI_CORE_BASE(0x7080)
|
||||
#define HDMI_HDCP_CTRL2 HDMI_CORE_BASE(0x7084)
|
||||
#define HDMI_HDCP_CHECK_RESULT HDMI_CORE_BASE(0x7090)
|
||||
#define HDMI_HDCP_BKSV(n) HDMI_CORE_BASE(0x70A0 + 4 * (n))
|
||||
#define HDMI_HDCP_AKSV(n) HDMI_CORE_BASE(0x70C0 + 4 * (n))
|
||||
#define HDMI_HDCP_AN(n) HDMI_CORE_BASE(0x70E0 + 4 * (n))
|
||||
|
||||
#define HDMI_HDCP_BCAPS HDMI_CORE_BASE(0x7100)
|
||||
#define HDMI_HDCP_BSTATUS_0 HDMI_CORE_BASE(0x7110)
|
||||
#define HDMI_HDCP_BSTATUS_1 HDMI_CORE_BASE(0x7114)
|
||||
#define HDMI_HDCP_RI_0 HDMI_CORE_BASE(0x7140)
|
||||
#define HDMI_HDCP_RI_1 HDMI_CORE_BASE(0x7144)
|
||||
#define HDMI_HDCP_I2C_INT HDMI_CORE_BASE(0x7180)
|
||||
#define HDMI_HDCP_AN_INT HDMI_CORE_BASE(0x7190)
|
||||
#define HDMI_HDCP_WDT_INT HDMI_CORE_BASE(0x71A0)
|
||||
#define HDMI_HDCP_RI_INT HDMI_CORE_BASE(0x71B0)
|
||||
#define HDMI_HDCP_RI_COMPARE_0 HDMI_CORE_BASE(0x71D0)
|
||||
#define HDMI_HDCP_RI_COMPARE_1 HDMI_CORE_BASE(0x71D4)
|
||||
#define HDMI_HDCP_FRAME_COUNT HDMI_CORE_BASE(0x71E0)
|
||||
|
||||
#define HDMI_RGB_ROUND_EN HDMI_CORE_BASE(0xD500)
|
||||
#define HDMI_VACT_SPACE_R_0 HDMI_CORE_BASE(0xD504)
|
||||
#define HDMI_VACT_SPACE_R_1 HDMI_CORE_BASE(0xD508)
|
||||
#define HDMI_VACT_SPACE_G_0 HDMI_CORE_BASE(0xD50C)
|
||||
#define HDMI_VACT_SPACE_G_1 HDMI_CORE_BASE(0xD510)
|
||||
#define HDMI_VACT_SPACE_B_0 HDMI_CORE_BASE(0xD514)
|
||||
#define HDMI_VACT_SPACE_B_1 HDMI_CORE_BASE(0xD518)
|
||||
|
||||
#define HDMI_BLUE_SCREEN_B_0 HDMI_CORE_BASE(0xD520)
|
||||
#define HDMI_BLUE_SCREEN_B_1 HDMI_CORE_BASE(0xD524)
|
||||
#define HDMI_BLUE_SCREEN_G_0 HDMI_CORE_BASE(0xD528)
|
||||
#define HDMI_BLUE_SCREEN_G_1 HDMI_CORE_BASE(0xD52C)
|
||||
#define HDMI_BLUE_SCREEN_R_0 HDMI_CORE_BASE(0xD530)
|
||||
#define HDMI_BLUE_SCREEN_R_1 HDMI_CORE_BASE(0xD534)
|
||||
|
||||
/* HDMI I2S register */
|
||||
#define HDMI_I2S_CLK_CON HDMI_I2S_BASE(0x000)
|
||||
#define HDMI_I2S_CON_1 HDMI_I2S_BASE(0x004)
|
||||
#define HDMI_I2S_CON_2 HDMI_I2S_BASE(0x008)
|
||||
#define HDMI_I2S_PIN_SEL_0 HDMI_I2S_BASE(0x00c)
|
||||
#define HDMI_I2S_PIN_SEL_1 HDMI_I2S_BASE(0x010)
|
||||
#define HDMI_I2S_PIN_SEL_2 HDMI_I2S_BASE(0x014)
|
||||
#define HDMI_I2S_PIN_SEL_3 HDMI_I2S_BASE(0x018)
|
||||
#define HDMI_I2S_DSD_CON HDMI_I2S_BASE(0x01c)
|
||||
#define HDMI_I2S_MUX_CON HDMI_I2S_BASE(0x020)
|
||||
#define HDMI_I2S_CH_ST_CON HDMI_I2S_BASE(0x024)
|
||||
#define HDMI_I2S_CH_ST_0 HDMI_I2S_BASE(0x028)
|
||||
#define HDMI_I2S_CH_ST_1 HDMI_I2S_BASE(0x02c)
|
||||
#define HDMI_I2S_CH_ST_2 HDMI_I2S_BASE(0x030)
|
||||
#define HDMI_I2S_CH_ST_3 HDMI_I2S_BASE(0x034)
|
||||
#define HDMI_I2S_CH_ST_4 HDMI_I2S_BASE(0x038)
|
||||
#define HDMI_I2S_CH_ST_SH_0 HDMI_I2S_BASE(0x03c)
|
||||
#define HDMI_I2S_CH_ST_SH_1 HDMI_I2S_BASE(0x040)
|
||||
#define HDMI_I2S_CH_ST_SH_2 HDMI_I2S_BASE(0x044)
|
||||
#define HDMI_I2S_CH_ST_SH_3 HDMI_I2S_BASE(0x048)
|
||||
#define HDMI_I2S_CH_ST_SH_4 HDMI_I2S_BASE(0x04c)
|
||||
#define HDMI_I2S_MUX_CH HDMI_I2S_BASE(0x054)
|
||||
#define HDMI_I2S_MUX_CUV HDMI_I2S_BASE(0x058)
|
||||
|
||||
/* I2S bit definition */
|
||||
|
||||
/* I2S_CLK_CON */
|
||||
#define HDMI_I2S_CLK_DIS (0)
|
||||
#define HDMI_I2S_CLK_EN (1)
|
||||
|
||||
/* I2S_CON_1 */
|
||||
#define HDMI_I2S_SCLK_FALLING_EDGE (0 << 1)
|
||||
#define HDMI_I2S_SCLK_RISING_EDGE (1 << 1)
|
||||
#define HDMI_I2S_L_CH_LOW_POL (0)
|
||||
#define HDMI_I2S_L_CH_HIGH_POL (1)
|
||||
|
||||
/* I2S_CON_2 */
|
||||
#define HDMI_I2S_MSB_FIRST_MODE (0 << 6)
|
||||
#define HDMI_I2S_LSB_FIRST_MODE (1 << 6)
|
||||
#define HDMI_I2S_BIT_CH_32FS (0 << 4)
|
||||
#define HDMI_I2S_BIT_CH_48FS (1 << 4)
|
||||
#define HDMI_I2S_BIT_CH_RESERVED (2 << 4)
|
||||
#define HDMI_I2S_SDATA_16BIT (1 << 2)
|
||||
#define HDMI_I2S_SDATA_20BIT (2 << 2)
|
||||
#define HDMI_I2S_SDATA_24BIT (3 << 2)
|
||||
#define HDMI_I2S_BASIC_FORMAT (0)
|
||||
#define HDMI_I2S_L_JUST_FORMAT (2)
|
||||
#define HDMI_I2S_R_JUST_FORMAT (3)
|
||||
#define HDMI_I2S_CON_2_CLR (~(0xFF))
|
||||
#define HDMI_I2S_SET_BIT_CH(x) (((x) & 0x7) << 4)
|
||||
#define HDMI_I2S_SET_SDATA_BIT(x) (((x) & 0x7) << 2)
|
||||
|
||||
/* I2S_PIN_SEL_0 */
|
||||
#define HDMI_I2S_SEL_SCLK(x) (((x) & 0x7) << 4)
|
||||
#define HDMI_I2S_SEL_LRCK(x) ((x) & 0x7)
|
||||
|
||||
/* I2S_PIN_SEL_1 */
|
||||
#define HDMI_I2S_SEL_SDATA1(x) (((x) & 0x7) << 4)
|
||||
#define HDMI_I2S_SEL_SDATA2(x) ((x) & 0x7)
|
||||
|
||||
/* I2S_PIN_SEL_2 */
|
||||
#define HDMI_I2S_SEL_SDATA3(x) (((x) & 0x7) << 4)
|
||||
#define HDMI_I2S_SEL_SDATA2(x) ((x) & 0x7)
|
||||
|
||||
/* I2S_PIN_SEL_3 */
|
||||
#define HDMI_I2S_SEL_DSD(x) ((x) & 0x7)
|
||||
|
||||
/* I2S_DSD_CON */
|
||||
#define HDMI_I2S_DSD_CLK_RI_EDGE (1 << 1)
|
||||
#define HDMI_I2S_DSD_CLK_FA_EDGE (0 << 1)
|
||||
#define HDMI_I2S_DSD_ENABLE (1)
|
||||
#define HDMI_I2S_DSD_DISABLE (0)
|
||||
|
||||
/* I2S_MUX_CON */
|
||||
#define HDMI_I2S_NOISE_FILTER_ZERO (0 << 5)
|
||||
#define HDMI_I2S_NOISE_FILTER_2_STAGE (1 << 5)
|
||||
#define HDMI_I2S_NOISE_FILTER_3_STAGE (2 << 5)
|
||||
#define HDMI_I2S_NOISE_FILTER_4_STAGE (3 << 5)
|
||||
#define HDMI_I2S_NOISE_FILTER_5_STAGE (4 << 5)
|
||||
#define HDMI_I2S_IN_DISABLE (1 << 4)
|
||||
#define HDMI_I2S_IN_ENABLE (0 << 4)
|
||||
#define HDMI_I2S_AUD_SPDIF (0 << 2)
|
||||
#define HDMI_I2S_AUD_I2S (1 << 2)
|
||||
#define HDMI_I2S_AUD_DSD (2 << 2)
|
||||
#define HDMI_I2S_CUV_SPDIF_ENABLE (0 << 1)
|
||||
#define HDMI_I2S_CUV_I2S_ENABLE (1 << 1)
|
||||
#define HDMI_I2S_MUX_DISABLE (0)
|
||||
#define HDMI_I2S_MUX_ENABLE (1)
|
||||
#define HDMI_I2S_MUX_CON_CLR (~(0xFF))
|
||||
|
||||
/* I2S_CH_ST_CON */
|
||||
#define HDMI_I2S_CH_STATUS_RELOAD (1)
|
||||
#define HDMI_I2S_CH_ST_CON_CLR (~(1))
|
||||
|
||||
/* I2S_CH_ST_0 / I2S_CH_ST_SH_0 */
|
||||
#define HDMI_I2S_CH_STATUS_MODE_0 (0 << 6)
|
||||
#define HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH (0 << 3)
|
||||
#define HDMI_I2S_2AUD_CH_WITH_PREEMPH (1 << 3)
|
||||
#define HDMI_I2S_DEFAULT_EMPHASIS (0 << 3)
|
||||
#define HDMI_I2S_COPYRIGHT (0 << 2)
|
||||
#define HDMI_I2S_NO_COPYRIGHT (1 << 2)
|
||||
#define HDMI_I2S_LINEAR_PCM (0 << 1)
|
||||
#define HDMI_I2S_NO_LINEAR_PCM (1 << 1)
|
||||
#define HDMI_I2S_CONSUMER_FORMAT (0)
|
||||
#define HDMI_I2S_PROF_FORMAT (1)
|
||||
#define HDMI_I2S_CH_ST_0_CLR (~(0xFF))
|
||||
|
||||
/* I2S_CH_ST_1 / I2S_CH_ST_SH_1 */
|
||||
#define HDMI_I2S_CD_PLAYER (0x00)
|
||||
#define HDMI_I2S_DAT_PLAYER (0x03)
|
||||
#define HDMI_I2S_DCC_PLAYER (0x43)
|
||||
#define HDMI_I2S_MINI_DISC_PLAYER (0x49)
|
||||
|
||||
/* I2S_CH_ST_2 / I2S_CH_ST_SH_2 */
|
||||
#define HDMI_I2S_CHANNEL_NUM_MASK (0xF << 4)
|
||||
#define HDMI_I2S_SOURCE_NUM_MASK (0xF)
|
||||
#define HDMI_I2S_SET_CHANNEL_NUM(x) (((x) & (0xF)) << 4)
|
||||
#define HDMI_I2S_SET_SOURCE_NUM(x) ((x) & (0xF))
|
||||
|
||||
/* I2S_CH_ST_3 / I2S_CH_ST_SH_3 */
|
||||
#define HDMI_I2S_CLK_ACCUR_LEVEL_1 (1 << 4)
|
||||
#define HDMI_I2S_CLK_ACCUR_LEVEL_2 (0 << 4)
|
||||
#define HDMI_I2S_CLK_ACCUR_LEVEL_3 (2 << 4)
|
||||
#define HDMI_I2S_SMP_FREQ_44_1 (0x0)
|
||||
#define HDMI_I2S_SMP_FREQ_48 (0x2)
|
||||
#define HDMI_I2S_SMP_FREQ_32 (0x3)
|
||||
#define HDMI_I2S_SMP_FREQ_96 (0xA)
|
||||
#define HDMI_I2S_SET_SMP_FREQ(x) ((x) & (0xF))
|
||||
|
||||
/* I2S_CH_ST_4 / I2S_CH_ST_SH_4 */
|
||||
#define HDMI_I2S_ORG_SMP_FREQ_44_1 (0xF << 4)
|
||||
#define HDMI_I2S_ORG_SMP_FREQ_88_2 (0x7 << 4)
|
||||
#define HDMI_I2S_ORG_SMP_FREQ_22_05 (0xB << 4)
|
||||
#define HDMI_I2S_ORG_SMP_FREQ_176_4 (0x3 << 4)
|
||||
#define HDMI_I2S_WORD_LEN_NOT_DEFINE (0x0 << 1)
|
||||
#define HDMI_I2S_WORD_LEN_MAX24_20BITS (0x1 << 1)
|
||||
#define HDMI_I2S_WORD_LEN_MAX24_22BITS (0x2 << 1)
|
||||
#define HDMI_I2S_WORD_LEN_MAX24_23BITS (0x4 << 1)
|
||||
#define HDMI_I2S_WORD_LEN_MAX24_24BITS (0x5 << 1)
|
||||
#define HDMI_I2S_WORD_LEN_MAX24_21BITS (0x6 << 1)
|
||||
#define HDMI_I2S_WORD_LEN_MAX20_16BITS (0x1 << 1)
|
||||
#define HDMI_I2S_WORD_LEN_MAX20_18BITS (0x2 << 1)
|
||||
#define HDMI_I2S_WORD_LEN_MAX20_19BITS (0x4 << 1)
|
||||
#define HDMI_I2S_WORD_LEN_MAX20_20BITS (0x5 << 1)
|
||||
#define HDMI_I2S_WORD_LEN_MAX20_17BITS (0x6 << 1)
|
||||
#define HDMI_I2S_WORD_LEN_MAX_24BITS (1)
|
||||
#define HDMI_I2S_WORD_LEN_MAX_20BITS (0)
|
||||
|
||||
/* I2S_MUX_CH */
|
||||
#define HDMI_I2S_CH3_R_EN (1 << 7)
|
||||
#define HDMI_I2S_CH3_L_EN (1 << 6)
|
||||
#define HDMI_I2S_CH3_EN (3 << 6)
|
||||
#define HDMI_I2S_CH2_R_EN (1 << 5)
|
||||
#define HDMI_I2S_CH2_L_EN (1 << 4)
|
||||
#define HDMI_I2S_CH2_EN (3 << 4)
|
||||
#define HDMI_I2S_CH1_R_EN (1 << 3)
|
||||
#define HDMI_I2S_CH1_L_EN (1 << 2)
|
||||
#define HDMI_I2S_CH1_EN (3 << 2)
|
||||
#define HDMI_I2S_CH0_R_EN (1 << 1)
|
||||
#define HDMI_I2S_CH0_L_EN (1)
|
||||
#define HDMI_I2S_CH0_EN (3)
|
||||
#define HDMI_I2S_CH_ALL_EN (0xFF)
|
||||
#define HDMI_I2S_MUX_CH_CLR (~HDMI_I2S_CH_ALL_EN)
|
||||
|
||||
/* I2S_MUX_CUV */
|
||||
#define HDMI_I2S_CUV_R_EN (1 << 1)
|
||||
#define HDMI_I2S_CUV_L_EN (1)
|
||||
#define HDMI_I2S_CUV_RL_EN (0x03)
|
||||
|
||||
/* I2S_CUV_L_R */
|
||||
#define HDMI_I2S_CUV_R_DATA_MASK (0x7 << 4)
|
||||
#define HDMI_I2S_CUV_L_DATA_MASK (0x7)
|
||||
|
||||
/* Timing generator registers */
|
||||
/* TG configure/status registers */
|
||||
#define HDMI_TG_VACT_ST3_L HDMI_TG_BASE(0x0068)
|
||||
#define HDMI_TG_VACT_ST3_H HDMI_TG_BASE(0x006c)
|
||||
#define HDMI_TG_VACT_ST4_L HDMI_TG_BASE(0x0070)
|
||||
#define HDMI_TG_VACT_ST4_H HDMI_TG_BASE(0x0074)
|
||||
#define HDMI_TG_3D HDMI_TG_BASE(0x00F0)
|
||||
|
||||
#endif /* SAMSUNG_REGS_HDMI_H */
|
||||
|
|
|
@ -16,8 +16,7 @@ config DRM_GMA600
|
|||
depends on DRM_GMA500
|
||||
help
|
||||
Say yes to include support for GMA600 (Intel Moorestown/Oaktrail)
|
||||
platforms with LVDS ports. HDMI and MIPI are not currently
|
||||
supported.
|
||||
platforms with LVDS ports. MIPI is not currently supported.
|
||||
|
||||
config DRM_GMA3600
|
||||
bool "Intel GMA3600/3650 support (Experimental)"
|
||||
|
@ -25,3 +24,10 @@ config DRM_GMA3600
|
|||
help
|
||||
Say yes to include basic support for Intel GMA3600/3650 (Intel
|
||||
Cedar Trail) platforms.
|
||||
|
||||
config DRM_MEDFIELD
|
||||
bool "Intel Medfield support (Experimental)"
|
||||
depends on DRM_GMA500 && X86_INTEL_MID
|
||||
help
|
||||
Say yes to include support for the Intel Medfield platform.
|
||||
|
||||
|
|
|
@ -37,4 +37,14 @@ gma500_gfx-$(CONFIG_DRM_GMA600) += oaktrail_device.o \
|
|||
oaktrail_hdmi.o \
|
||||
oaktrail_hdmi_i2c.o
|
||||
|
||||
gma500_gfx-$(CONFIG_DRM_MEDFIELD) += mdfld_device.o \
|
||||
mdfld_output.o \
|
||||
mdfld_intel_display.o \
|
||||
mdfld_dsi_output.o \
|
||||
mdfld_dsi_dpi.o \
|
||||
mdfld_dsi_pkg_sender.o \
|
||||
mdfld_tpo_vid.o \
|
||||
mdfld_tmd_vid.o \
|
||||
tc35876x-dsi-lvds.o
|
||||
|
||||
obj-$(CONFIG_DRM_GMA500) += gma500_gfx.o
|
||||
|
|
|
@ -202,13 +202,12 @@ static inline void CDV_MSG_WRITE32(uint port, uint offset, u32 value)
|
|||
pci_dev_put(pci_root);
|
||||
}
|
||||
|
||||
#define PSB_APM_CMD 0x0
|
||||
#define PSB_APM_STS 0x04
|
||||
#define PSB_PM_SSC 0x20
|
||||
#define PSB_PM_SSS 0x30
|
||||
#define PSB_PWRGT_GFX_MASK 0x3
|
||||
#define CDV_PWRGT_DISPLAY_CNTR 0x000fc00c
|
||||
#define CDV_PWRGT_DISPLAY_STS 0x000fc00c
|
||||
#define PSB_PWRGT_GFX_ON 0x02
|
||||
#define PSB_PWRGT_GFX_OFF 0x01
|
||||
#define PSB_PWRGT_GFX_D0 0x00
|
||||
#define PSB_PWRGT_GFX_D3 0x03
|
||||
|
||||
static void cdv_init_pm(struct drm_device *dev)
|
||||
{
|
||||
|
@ -221,26 +220,22 @@ static void cdv_init_pm(struct drm_device *dev)
|
|||
dev_priv->ospm_base = CDV_MSG_READ32(PSB_PUNIT_PORT,
|
||||
PSB_OSPMBA) & 0xFFFF;
|
||||
|
||||
/* Force power on for now */
|
||||
/* Power status */
|
||||
pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD);
|
||||
pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
|
||||
|
||||
/* Enable the GPU */
|
||||
pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
|
||||
pwr_cnt |= PSB_PWRGT_GFX_ON;
|
||||
outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD);
|
||||
|
||||
/* Wait for the GPU power */
|
||||
for (i = 0; i < 5; i++) {
|
||||
u32 pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS);
|
||||
if ((pwr_sts & PSB_PWRGT_GFX_MASK) == 0)
|
||||
break;
|
||||
udelay(10);
|
||||
}
|
||||
pwr_cnt = inl(dev_priv->ospm_base + PSB_PM_SSC);
|
||||
pwr_cnt &= ~CDV_PWRGT_DISPLAY_CNTR;
|
||||
outl(pwr_cnt, dev_priv->ospm_base + PSB_PM_SSC);
|
||||
for (i = 0; i < 5; i++) {
|
||||
u32 pwr_sts = inl(dev_priv->ospm_base + PSB_PM_SSS);
|
||||
if ((pwr_sts & CDV_PWRGT_DISPLAY_STS) == 0)
|
||||
break;
|
||||
return;
|
||||
udelay(10);
|
||||
}
|
||||
dev_err(dev->dev, "GPU: power management timed out.\n");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -249,11 +244,50 @@ static void cdv_init_pm(struct drm_device *dev)
|
|||
*
|
||||
* Save the state we need in order to be able to restore the interface
|
||||
* upon resume from suspend
|
||||
*
|
||||
* FIXME: review
|
||||
*/
|
||||
static int cdv_save_display_registers(struct drm_device *dev)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct psb_save_area *regs = &dev_priv->regs;
|
||||
struct drm_connector *connector;
|
||||
|
||||
dev_info(dev->dev, "Saving GPU registers.\n");
|
||||
|
||||
pci_read_config_byte(dev->pdev, 0xF4, ®s->cdv.saveLBB);
|
||||
|
||||
regs->cdv.saveDSPCLK_GATE_D = REG_READ(DSPCLK_GATE_D);
|
||||
regs->cdv.saveRAMCLK_GATE_D = REG_READ(RAMCLK_GATE_D);
|
||||
|
||||
regs->cdv.saveDSPARB = REG_READ(DSPARB);
|
||||
regs->cdv.saveDSPFW[0] = REG_READ(DSPFW1);
|
||||
regs->cdv.saveDSPFW[1] = REG_READ(DSPFW2);
|
||||
regs->cdv.saveDSPFW[2] = REG_READ(DSPFW3);
|
||||
regs->cdv.saveDSPFW[3] = REG_READ(DSPFW4);
|
||||
regs->cdv.saveDSPFW[4] = REG_READ(DSPFW5);
|
||||
regs->cdv.saveDSPFW[5] = REG_READ(DSPFW6);
|
||||
|
||||
regs->cdv.saveADPA = REG_READ(ADPA);
|
||||
|
||||
regs->cdv.savePP_CONTROL = REG_READ(PP_CONTROL);
|
||||
regs->cdv.savePFIT_PGM_RATIOS = REG_READ(PFIT_PGM_RATIOS);
|
||||
regs->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL);
|
||||
regs->saveBLC_PWM_CTL2 = REG_READ(BLC_PWM_CTL2);
|
||||
regs->cdv.saveLVDS = REG_READ(LVDS);
|
||||
|
||||
regs->cdv.savePFIT_CONTROL = REG_READ(PFIT_CONTROL);
|
||||
|
||||
regs->cdv.savePP_ON_DELAYS = REG_READ(PP_ON_DELAYS);
|
||||
regs->cdv.savePP_OFF_DELAYS = REG_READ(PP_OFF_DELAYS);
|
||||
regs->cdv.savePP_CYCLE = REG_READ(PP_CYCLE);
|
||||
|
||||
regs->cdv.saveVGACNTRL = REG_READ(VGACNTRL);
|
||||
|
||||
regs->cdv.saveIER = REG_READ(PSB_INT_ENABLE_R);
|
||||
regs->cdv.saveIMR = REG_READ(PSB_INT_MASK_R);
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
|
||||
connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -267,16 +301,113 @@ static int cdv_save_display_registers(struct drm_device *dev)
|
|||
*/
|
||||
static int cdv_restore_display_registers(struct drm_device *dev)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct psb_save_area *regs = &dev_priv->regs;
|
||||
struct drm_connector *connector;
|
||||
u32 temp;
|
||||
|
||||
pci_write_config_byte(dev->pdev, 0xF4, regs->cdv.saveLBB);
|
||||
|
||||
REG_WRITE(DSPCLK_GATE_D, regs->cdv.saveDSPCLK_GATE_D);
|
||||
REG_WRITE(RAMCLK_GATE_D, regs->cdv.saveRAMCLK_GATE_D);
|
||||
|
||||
/* BIOS does below anyway */
|
||||
REG_WRITE(DPIO_CFG, 0);
|
||||
REG_WRITE(DPIO_CFG, DPIO_MODE_SELECT_0 | DPIO_CMN_RESET_N);
|
||||
|
||||
temp = REG_READ(DPLL_A);
|
||||
if ((temp & DPLL_SYNCLOCK_ENABLE) == 0) {
|
||||
REG_WRITE(DPLL_A, temp | DPLL_SYNCLOCK_ENABLE);
|
||||
REG_READ(DPLL_A);
|
||||
}
|
||||
|
||||
temp = REG_READ(DPLL_B);
|
||||
if ((temp & DPLL_SYNCLOCK_ENABLE) == 0) {
|
||||
REG_WRITE(DPLL_B, temp | DPLL_SYNCLOCK_ENABLE);
|
||||
REG_READ(DPLL_B);
|
||||
}
|
||||
|
||||
udelay(500);
|
||||
|
||||
REG_WRITE(DSPFW1, regs->cdv.saveDSPFW[0]);
|
||||
REG_WRITE(DSPFW2, regs->cdv.saveDSPFW[1]);
|
||||
REG_WRITE(DSPFW3, regs->cdv.saveDSPFW[2]);
|
||||
REG_WRITE(DSPFW4, regs->cdv.saveDSPFW[3]);
|
||||
REG_WRITE(DSPFW5, regs->cdv.saveDSPFW[4]);
|
||||
REG_WRITE(DSPFW6, regs->cdv.saveDSPFW[5]);
|
||||
|
||||
REG_WRITE(DSPARB, regs->cdv.saveDSPARB);
|
||||
REG_WRITE(ADPA, regs->cdv.saveADPA);
|
||||
|
||||
REG_WRITE(BLC_PWM_CTL2, regs->saveBLC_PWM_CTL2);
|
||||
REG_WRITE(LVDS, regs->cdv.saveLVDS);
|
||||
REG_WRITE(PFIT_CONTROL, regs->cdv.savePFIT_CONTROL);
|
||||
REG_WRITE(PFIT_PGM_RATIOS, regs->cdv.savePFIT_PGM_RATIOS);
|
||||
REG_WRITE(BLC_PWM_CTL, regs->saveBLC_PWM_CTL);
|
||||
REG_WRITE(PP_ON_DELAYS, regs->cdv.savePP_ON_DELAYS);
|
||||
REG_WRITE(PP_OFF_DELAYS, regs->cdv.savePP_OFF_DELAYS);
|
||||
REG_WRITE(PP_CYCLE, regs->cdv.savePP_CYCLE);
|
||||
REG_WRITE(PP_CONTROL, regs->cdv.savePP_CONTROL);
|
||||
|
||||
REG_WRITE(VGACNTRL, regs->cdv.saveVGACNTRL);
|
||||
|
||||
REG_WRITE(PSB_INT_ENABLE_R, regs->cdv.saveIER);
|
||||
REG_WRITE(PSB_INT_MASK_R, regs->cdv.saveIMR);
|
||||
|
||||
/* Fix arbitration bug */
|
||||
CDV_MSG_WRITE32(3, 0x30, 0x08027108);
|
||||
|
||||
drm_mode_config_reset(dev);
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
|
||||
connector->funcs->dpms(connector, DRM_MODE_DPMS_ON);
|
||||
|
||||
/* Resume the modeset for every activated CRTC */
|
||||
drm_helper_resume_force_mode(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdv_power_down(struct drm_device *dev)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
u32 pwr_cnt, pwr_mask, pwr_sts;
|
||||
int tries = 5;
|
||||
|
||||
pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD);
|
||||
pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
|
||||
pwr_cnt |= PSB_PWRGT_GFX_OFF;
|
||||
pwr_mask = PSB_PWRGT_GFX_MASK;
|
||||
|
||||
outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD);
|
||||
|
||||
while (tries--) {
|
||||
pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS);
|
||||
if ((pwr_sts & pwr_mask) == PSB_PWRGT_GFX_D3)
|
||||
return 0;
|
||||
udelay(10);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdv_power_up(struct drm_device *dev)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
u32 pwr_cnt, pwr_mask, pwr_sts;
|
||||
int tries = 5;
|
||||
|
||||
pwr_cnt = inl(dev_priv->apm_base + PSB_APM_CMD);
|
||||
pwr_cnt &= ~PSB_PWRGT_GFX_MASK;
|
||||
pwr_cnt |= PSB_PWRGT_GFX_ON;
|
||||
pwr_mask = PSB_PWRGT_GFX_MASK;
|
||||
|
||||
outl(pwr_cnt, dev_priv->apm_base + PSB_APM_CMD);
|
||||
|
||||
while (tries--) {
|
||||
pwr_sts = inl(dev_priv->apm_base + PSB_APM_STS);
|
||||
if ((pwr_sts & pwr_mask) == PSB_PWRGT_GFX_D0)
|
||||
return 0;
|
||||
udelay(10);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ extern void cdv_hdmi_init(struct drm_device *dev, struct psb_intel_mode_device *
|
|||
extern struct drm_display_mode *cdv_intel_crtc_mode_get(struct drm_device *dev,
|
||||
struct drm_crtc *crtc);
|
||||
|
||||
extern inline void cdv_intel_wait_for_vblank(struct drm_device *dev)
|
||||
static inline void cdv_intel_wait_for_vblank(struct drm_device *dev)
|
||||
{
|
||||
/* Wait for 20ms, i.e. one cycle at 50hz. */
|
||||
/* FIXME: msleep ?? */
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "psb_intel_drv.h"
|
||||
#include "psb_intel_reg.h"
|
||||
#include "power.h"
|
||||
#include "cdv_device.h"
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
|
||||
|
|
|
@ -344,7 +344,7 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
|
|||
/*
|
||||
* Returns whether any encoder on the specified pipe is of the specified type
|
||||
*/
|
||||
bool cdv_intel_pipe_has_type(struct drm_crtc *crtc, int type)
|
||||
static bool cdv_intel_pipe_has_type(struct drm_crtc *crtc, int type)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_mode_config *mode_config = &dev->mode_config;
|
||||
|
@ -476,7 +476,7 @@ static bool cdv_intel_find_best_PLL(struct drm_crtc *crtc, int target,
|
|||
return err != target;
|
||||
}
|
||||
|
||||
int cdv_intel_pipe_set_base(struct drm_crtc *crtc,
|
||||
static int cdv_intel_pipe_set_base(struct drm_crtc *crtc,
|
||||
int x, int y, struct drm_framebuffer *old_fb)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
|
@ -569,7 +569,6 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE;
|
||||
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
|
||||
u32 temp;
|
||||
bool enabled;
|
||||
|
||||
/* XXX: When our outputs are all unaware of DPMS modes other than off
|
||||
* and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
|
||||
|
@ -663,7 +662,6 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
udelay(150);
|
||||
break;
|
||||
}
|
||||
enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF;
|
||||
/*Set FIFO Watermarks*/
|
||||
REG_WRITE(DSPARB, 0x3F3E);
|
||||
}
|
||||
|
@ -680,22 +678,6 @@ static void cdv_intel_crtc_commit(struct drm_crtc *crtc)
|
|||
crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
|
||||
}
|
||||
|
||||
void cdv_intel_encoder_prepare(struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_encoder_helper_funcs *encoder_funcs =
|
||||
encoder->helper_private;
|
||||
/* lvds has its own version of prepare see cdv_intel_lvds_prepare */
|
||||
encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
|
||||
}
|
||||
|
||||
void cdv_intel_encoder_commit(struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_encoder_helper_funcs *encoder_funcs =
|
||||
encoder->helper_private;
|
||||
/* lvds has its own version of commit see cdv_intel_lvds_commit */
|
||||
encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
|
||||
}
|
||||
|
||||
static bool cdv_intel_crtc_mode_fixup(struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
|
@ -745,7 +727,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
int refclk;
|
||||
struct cdv_intel_clock_t clock;
|
||||
u32 dpll = 0, dspcntr, pipeconf;
|
||||
bool ok, is_sdvo = false, is_dvo = false;
|
||||
bool ok;
|
||||
bool is_crt = false, is_lvds = false, is_tv = false;
|
||||
bool is_hdmi = false;
|
||||
struct drm_mode_config *mode_config = &dev->mode_config;
|
||||
|
@ -763,12 +745,6 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
case INTEL_OUTPUT_LVDS:
|
||||
is_lvds = true;
|
||||
break;
|
||||
case INTEL_OUTPUT_SDVO:
|
||||
is_sdvo = true;
|
||||
break;
|
||||
case INTEL_OUTPUT_DVO:
|
||||
is_dvo = true;
|
||||
break;
|
||||
case INTEL_OUTPUT_TVOUT:
|
||||
is_tv = true;
|
||||
break;
|
||||
|
@ -928,7 +904,7 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
}
|
||||
|
||||
/** Loads the palette/gamma unit for the CRTC with the prepared values */
|
||||
void cdv_intel_crtc_load_lut(struct drm_crtc *crtc)
|
||||
static void cdv_intel_crtc_load_lut(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_psb_private *dev_priv =
|
||||
|
@ -968,7 +944,7 @@ void cdv_intel_crtc_load_lut(struct drm_crtc *crtc)
|
|||
gma_power_end(dev);
|
||||
} else {
|
||||
for (i = 0; i < 256; i++) {
|
||||
dev_priv->save_palette_a[i] =
|
||||
dev_priv->regs.psb.save_palette_a[i] =
|
||||
((psb_intel_crtc->lut_r[i] +
|
||||
psb_intel_crtc->lut_adj[i]) << 16) |
|
||||
((psb_intel_crtc->lut_g[i] +
|
||||
|
@ -1338,18 +1314,20 @@ static int cdv_intel_crtc_clock_get(struct drm_device *dev,
|
|||
gma_power_end(dev);
|
||||
} else {
|
||||
dpll = (pipe == 0) ?
|
||||
dev_priv->saveDPLL_A : dev_priv->saveDPLL_B;
|
||||
dev_priv->regs.psb.saveDPLL_A :
|
||||
dev_priv->regs.psb.saveDPLL_B;
|
||||
|
||||
if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
|
||||
fp = (pipe == 0) ?
|
||||
dev_priv->saveFPA0 :
|
||||
dev_priv->saveFPB0;
|
||||
dev_priv->regs.psb.saveFPA0 :
|
||||
dev_priv->regs.psb.saveFPB0;
|
||||
else
|
||||
fp = (pipe == 0) ?
|
||||
dev_priv->saveFPA1 :
|
||||
dev_priv->saveFPB1;
|
||||
dev_priv->regs.psb.saveFPA1 :
|
||||
dev_priv->regs.psb.saveFPB1;
|
||||
|
||||
is_lvds = (pipe == 1) && (dev_priv->saveLVDS & LVDS_PORT_EN);
|
||||
is_lvds = (pipe == 1) &&
|
||||
(dev_priv->regs.psb.saveLVDS & LVDS_PORT_EN);
|
||||
}
|
||||
|
||||
clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
|
||||
|
@ -1419,13 +1397,17 @@ struct drm_display_mode *cdv_intel_crtc_mode_get(struct drm_device *dev,
|
|||
gma_power_end(dev);
|
||||
} else {
|
||||
htot = (pipe == 0) ?
|
||||
dev_priv->saveHTOTAL_A : dev_priv->saveHTOTAL_B;
|
||||
dev_priv->regs.psb.saveHTOTAL_A :
|
||||
dev_priv->regs.psb.saveHTOTAL_B;
|
||||
hsync = (pipe == 0) ?
|
||||
dev_priv->saveHSYNC_A : dev_priv->saveHSYNC_B;
|
||||
dev_priv->regs.psb.saveHSYNC_A :
|
||||
dev_priv->regs.psb.saveHSYNC_B;
|
||||
vtot = (pipe == 0) ?
|
||||
dev_priv->saveVTOTAL_A : dev_priv->saveVTOTAL_B;
|
||||
dev_priv->regs.psb.saveVTOTAL_A :
|
||||
dev_priv->regs.psb.saveVTOTAL_B;
|
||||
vsync = (pipe == 0) ?
|
||||
dev_priv->saveVSYNC_A : dev_priv->saveVSYNC_B;
|
||||
dev_priv->regs.psb.saveVSYNC_A :
|
||||
dev_priv->regs.psb.saveVSYNC_B;
|
||||
}
|
||||
|
||||
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
|
||||
|
@ -1475,34 +1457,3 @@ const struct drm_crtc_funcs cdv_intel_crtc_funcs = {
|
|||
.set_config = cdv_crtc_set_config,
|
||||
.destroy = cdv_intel_crtc_destroy,
|
||||
};
|
||||
|
||||
/*
|
||||
* Set the default value of cursor control and base register
|
||||
* to zero. This is a workaround for h/w defect on oaktrail
|
||||
*/
|
||||
void cdv_intel_cursor_init(struct drm_device *dev, int pipe)
|
||||
{
|
||||
uint32_t control;
|
||||
uint32_t base;
|
||||
|
||||
switch (pipe) {
|
||||
case 0:
|
||||
control = CURACNTR;
|
||||
base = CURABASE;
|
||||
break;
|
||||
case 1:
|
||||
control = CURBCNTR;
|
||||
base = CURBBASE;
|
||||
break;
|
||||
case 2:
|
||||
control = CURCCNTR;
|
||||
base = CURCBASE;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
REG_WRITE(control, 0);
|
||||
REG_WRITE(base, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "psb_intel_drv.h"
|
||||
#include "psb_drv.h"
|
||||
#include "psb_intel_reg.h"
|
||||
#include "cdv_device.h"
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
/* hdmi control bits */
|
||||
|
|
|
@ -78,13 +78,14 @@ static u32 cdv_intel_lvds_get_max_backlight(struct drm_device *dev)
|
|||
|
||||
gma_power_end(dev);
|
||||
} else
|
||||
retval = ((dev_priv->saveBLC_PWM_CTL &
|
||||
retval = ((dev_priv->regs.saveBLC_PWM_CTL &
|
||||
BACKLIGHT_MODULATION_FREQ_MASK) >>
|
||||
BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Set LVDS backlight level by I2C command
|
||||
*/
|
||||
|
@ -165,6 +166,7 @@ void cdv_intel_lvds_set_brightness(struct drm_device *dev, int level)
|
|||
else
|
||||
cdv_lvds_pwm_set_brightness(dev, level);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Sets the backlight level.
|
||||
|
@ -184,9 +186,9 @@ static void cdv_intel_lvds_set_backlight(struct drm_device *dev, int level)
|
|||
(level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
|
||||
gma_power_end(dev);
|
||||
} else {
|
||||
blc_pwm_ctl = dev_priv->saveBLC_PWM_CTL &
|
||||
blc_pwm_ctl = dev_priv->regs.saveBLC_PWM_CTL &
|
||||
~BACKLIGHT_DUTY_CYCLE_MASK;
|
||||
dev_priv->saveBLC_PWM_CTL = (blc_pwm_ctl |
|
||||
dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl |
|
||||
(level << BACKLIGHT_DUTY_CYCLE_SHIFT));
|
||||
}
|
||||
}
|
||||
|
@ -242,7 +244,7 @@ static void cdv_intel_lvds_restore(struct drm_connector *connector)
|
|||
{
|
||||
}
|
||||
|
||||
int cdv_intel_lvds_mode_valid(struct drm_connector *connector,
|
||||
static int cdv_intel_lvds_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
|
@ -267,7 +269,7 @@ int cdv_intel_lvds_mode_valid(struct drm_connector *connector,
|
|||
return MODE_OK;
|
||||
}
|
||||
|
||||
bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder,
|
||||
static bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
|
@ -436,7 +438,7 @@ static int cdv_intel_lvds_get_modes(struct drm_connector *connector)
|
|||
* Unregister the DDC bus for this connector then free the driver private
|
||||
* structure.
|
||||
*/
|
||||
void cdv_intel_lvds_destroy(struct drm_connector *connector)
|
||||
static void cdv_intel_lvds_destroy(struct drm_connector *connector)
|
||||
{
|
||||
struct psb_intel_encoder *psb_intel_encoder =
|
||||
psb_intel_attached_encoder(connector);
|
||||
|
@ -448,7 +450,7 @@ void cdv_intel_lvds_destroy(struct drm_connector *connector)
|
|||
kfree(connector);
|
||||
}
|
||||
|
||||
int cdv_intel_lvds_set_property(struct drm_connector *connector,
|
||||
static int cdv_intel_lvds_set_property(struct drm_connector *connector,
|
||||
struct drm_property *property,
|
||||
uint64_t value)
|
||||
{
|
||||
|
|
|
@ -111,39 +111,6 @@ static int psbfb_pan(struct fb_var_screeninfo *var, struct fb_info *info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void psbfb_suspend(struct drm_device *dev)
|
||||
{
|
||||
struct drm_framebuffer *fb;
|
||||
|
||||
console_lock();
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
|
||||
struct psb_framebuffer *psbfb = to_psb_fb(fb);
|
||||
struct fb_info *info = psbfb->fbdev;
|
||||
fb_set_suspend(info, 1);
|
||||
drm_fb_helper_blank(FB_BLANK_POWERDOWN, info);
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
console_unlock();
|
||||
}
|
||||
|
||||
void psbfb_resume(struct drm_device *dev)
|
||||
{
|
||||
struct drm_framebuffer *fb;
|
||||
|
||||
console_lock();
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
|
||||
struct psb_framebuffer *psbfb = to_psb_fb(fb);
|
||||
struct fb_info *info = psbfb->fbdev;
|
||||
fb_set_suspend(info, 0);
|
||||
drm_fb_helper_blank(FB_BLANK_UNBLANK, info);
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
console_unlock();
|
||||
drm_helper_disable_unused_functions(dev);
|
||||
}
|
||||
|
||||
static int psbfb_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
{
|
||||
struct psb_framebuffer *psbfb = vma->vm_private_data;
|
||||
|
@ -158,7 +125,7 @@ static int psbfb_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
unsigned long phys_addr = (unsigned long)dev_priv->stolen_base;
|
||||
|
||||
page_num = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
|
||||
address = (unsigned long)vmf->virtual_address;
|
||||
address = (unsigned long)vmf->virtual_address - (vmf->pgoff << PAGE_SHIFT);
|
||||
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
|
||||
|
@ -390,6 +357,7 @@ static int psbfb_create(struct psb_fbdev *fbdev,
|
|||
mode_cmd.width = sizes->surface_width;
|
||||
mode_cmd.height = sizes->surface_height;
|
||||
bpp = sizes->surface_bpp;
|
||||
depth = sizes->surface_depth;
|
||||
|
||||
/* No 24bit packed */
|
||||
if (bpp == 24)
|
||||
|
@ -402,7 +370,6 @@ static int psbfb_create(struct psb_fbdev *fbdev,
|
|||
* is ok with some fonts
|
||||
*/
|
||||
mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 7) / 8), 4096 >> pitch_lines);
|
||||
depth = sizes->surface_depth;
|
||||
|
||||
size = mode_cmd.pitches[0] * mode_cmd.height;
|
||||
size = ALIGN(size, PAGE_SIZE);
|
||||
|
@ -462,6 +429,7 @@ static int psbfb_create(struct psb_fbdev *fbdev,
|
|||
fbdev->psb_fb_helper.fb = fb;
|
||||
fbdev->psb_fb_helper.fbdev = info;
|
||||
|
||||
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
|
||||
strcpy(info->fix.id, "psbfb");
|
||||
|
||||
info->flags = FBINFO_DEFAULT;
|
||||
|
@ -499,18 +467,13 @@ static int psbfb_create(struct psb_fbdev *fbdev,
|
|||
info->apertures->ranges[0].size = dev_priv->gtt.stolen_size;
|
||||
}
|
||||
|
||||
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
|
||||
drm_fb_helper_fill_var(info, &fbdev->psb_fb_helper,
|
||||
sizes->fb_width, sizes->fb_height);
|
||||
|
||||
info->fix.mmio_start = pci_resource_start(dev->pdev, 0);
|
||||
info->fix.mmio_len = pci_resource_len(dev->pdev, 0);
|
||||
|
||||
info->pixmap.size = 64 * 1024;
|
||||
info->pixmap.buf_align = 8;
|
||||
info->pixmap.access_align = 32;
|
||||
info->pixmap.flags = FB_PIXMAP_SYSTEM;
|
||||
info->pixmap.scan_align = 1;
|
||||
/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
|
||||
|
||||
dev_info(dev->dev, "allocated %dx%d fb\n",
|
||||
psbfb->base.width, psbfb->base.height);
|
||||
|
@ -559,11 +522,21 @@ static struct drm_framebuffer *psb_user_framebuffer_create
|
|||
static void psbfb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
|
||||
u16 blue, int regno)
|
||||
{
|
||||
struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc);
|
||||
|
||||
intel_crtc->lut_r[regno] = red >> 8;
|
||||
intel_crtc->lut_g[regno] = green >> 8;
|
||||
intel_crtc->lut_b[regno] = blue >> 8;
|
||||
}
|
||||
|
||||
static void psbfb_gamma_get(struct drm_crtc *crtc, u16 *red,
|
||||
u16 *green, u16 *blue, int regno)
|
||||
{
|
||||
struct psb_intel_crtc *intel_crtc = to_psb_intel_crtc(crtc);
|
||||
|
||||
*red = intel_crtc->lut_r[regno] << 8;
|
||||
*green = intel_crtc->lut_g[regno] << 8;
|
||||
*blue = intel_crtc->lut_b[regno] << 8;
|
||||
}
|
||||
|
||||
static int psbfb_probe(struct drm_fb_helper *helper,
|
||||
|
@ -588,7 +561,7 @@ struct drm_fb_helper_funcs psb_fb_helper_funcs = {
|
|||
.fb_probe = psbfb_probe,
|
||||
};
|
||||
|
||||
int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev)
|
||||
static int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev)
|
||||
{
|
||||
struct fb_info *info;
|
||||
struct psb_framebuffer *psbfb = &fbdev->pfb;
|
||||
|
@ -630,7 +603,7 @@ int psb_fbdev_init(struct drm_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void psb_fbdev_fini(struct drm_device *dev)
|
||||
static void psb_fbdev_fini(struct drm_device *dev)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
|
||||
|
@ -724,10 +697,7 @@ static int psb_create_backlight_property(struct drm_device *dev)
|
|||
if (dev_priv->backlight_property)
|
||||
return 0;
|
||||
|
||||
backlight = drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"backlight", 2);
|
||||
backlight->values[0] = 0;
|
||||
backlight->values[1] = 100;
|
||||
backlight = drm_property_create_range(dev, 0, "backlight", 0, 100);
|
||||
|
||||
dev_priv->backlight_property = backlight;
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm.h>
|
||||
#include "gem_glue.h"
|
||||
|
||||
void drm_gem_object_release_wrap(struct drm_gem_object *obj)
|
||||
{
|
||||
|
|
|
@ -57,7 +57,7 @@ static inline uint32_t psb_gtt_mask_pte(uint32_t pfn, int type)
|
|||
* Given a gtt_range object return the GTT offset of the page table
|
||||
* entries for this gtt_range
|
||||
*/
|
||||
u32 *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r)
|
||||
static u32 *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
unsigned long offset;
|
||||
|
@ -378,7 +378,7 @@ void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt)
|
|||
kfree(gt);
|
||||
}
|
||||
|
||||
void psb_gtt_alloc(struct drm_device *dev)
|
||||
static void psb_gtt_alloc(struct drm_device *dev)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
init_rwsem(&dev_priv->gtt.sem);
|
||||
|
|
|
@ -395,7 +395,7 @@ int gma_intel_setup_gmbus(struct drm_device *dev)
|
|||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
int ret, i;
|
||||
|
||||
dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS,
|
||||
dev_priv->gmbus = kcalloc(GMBUS_NUM_PORTS, sizeof(struct intel_gmbus),
|
||||
GFP_KERNEL);
|
||||
if (dev_priv->gmbus == NULL)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -0,0 +1,691 @@
|
|||
/**************************************************************************
|
||||
* Copyright (c) 2011, Intel Corporation.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include "psb_drv.h"
|
||||
#include "mid_bios.h"
|
||||
#include "mdfld_output.h"
|
||||
#include "mdfld_dsi_output.h"
|
||||
#include "tc35876x-dsi-lvds.h"
|
||||
|
||||
#include <asm/intel_scu_ipc.h>
|
||||
|
||||
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
|
||||
|
||||
#define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF
|
||||
#define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */
|
||||
#define BLC_PWM_FREQ_CALC_CONSTANT 32
|
||||
#define MHz 1000000
|
||||
#define BRIGHTNESS_MIN_LEVEL 1
|
||||
#define BRIGHTNESS_MAX_LEVEL 100
|
||||
#define BRIGHTNESS_MASK 0xFF
|
||||
#define BLC_POLARITY_NORMAL 0
|
||||
#define BLC_POLARITY_INVERSE 1
|
||||
#define BLC_ADJUSTMENT_MAX 100
|
||||
|
||||
#define MDFLD_BLC_PWM_PRECISION_FACTOR 10
|
||||
#define MDFLD_BLC_MAX_PWM_REG_FREQ 0xFFFE
|
||||
#define MDFLD_BLC_MIN_PWM_REG_FREQ 0x2
|
||||
|
||||
#define MDFLD_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
|
||||
#define MDFLD_BACKLIGHT_PWM_CTL_SHIFT (16)
|
||||
|
||||
static struct backlight_device *mdfld_backlight_device;
|
||||
|
||||
int mdfld_set_brightness(struct backlight_device *bd)
|
||||
{
|
||||
struct drm_device *dev =
|
||||
(struct drm_device *)bl_get_data(mdfld_backlight_device);
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
int level = bd->props.brightness;
|
||||
|
||||
DRM_DEBUG_DRIVER("backlight level set to %d\n", level);
|
||||
|
||||
/* Perform value bounds checking */
|
||||
if (level < BRIGHTNESS_MIN_LEVEL)
|
||||
level = BRIGHTNESS_MIN_LEVEL;
|
||||
|
||||
if (gma_power_begin(dev, false)) {
|
||||
u32 adjusted_level = 0;
|
||||
|
||||
/*
|
||||
* Adjust the backlight level with the percent in
|
||||
* dev_priv->blc_adj2
|
||||
*/
|
||||
adjusted_level = level * dev_priv->blc_adj2;
|
||||
adjusted_level = adjusted_level / BLC_ADJUSTMENT_MAX;
|
||||
dev_priv->brightness_adjusted = adjusted_level;
|
||||
|
||||
if (mdfld_get_panel_type(dev, 0) == TC35876X) {
|
||||
if (dev_priv->dpi_panel_on[0] ||
|
||||
dev_priv->dpi_panel_on[2])
|
||||
tc35876x_brightness_control(dev,
|
||||
dev_priv->brightness_adjusted);
|
||||
} else {
|
||||
if (dev_priv->dpi_panel_on[0])
|
||||
mdfld_dsi_brightness_control(dev, 0,
|
||||
dev_priv->brightness_adjusted);
|
||||
}
|
||||
|
||||
if (dev_priv->dpi_panel_on[2])
|
||||
mdfld_dsi_brightness_control(dev, 2,
|
||||
dev_priv->brightness_adjusted);
|
||||
gma_power_end(dev);
|
||||
}
|
||||
|
||||
/* cache the brightness for later use */
|
||||
dev_priv->brightness = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdfld_get_brightness(struct backlight_device *bd)
|
||||
{
|
||||
struct drm_device *dev =
|
||||
(struct drm_device *)bl_get_data(mdfld_backlight_device);
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
|
||||
DRM_DEBUG_DRIVER("brightness = 0x%x \n", dev_priv->brightness);
|
||||
|
||||
/* return locally cached var instead of HW read (due to DPST etc.) */
|
||||
return dev_priv->brightness;
|
||||
}
|
||||
|
||||
static const struct backlight_ops mdfld_ops = {
|
||||
.get_brightness = mdfld_get_brightness,
|
||||
.update_status = mdfld_set_brightness,
|
||||
};
|
||||
|
||||
static int device_backlight_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = (struct drm_psb_private *)
|
||||
dev->dev_private;
|
||||
|
||||
dev_priv->blc_adj1 = BLC_ADJUSTMENT_MAX;
|
||||
dev_priv->blc_adj2 = BLC_ADJUSTMENT_MAX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdfld_backlight_init(struct drm_device *dev)
|
||||
{
|
||||
struct backlight_properties props;
|
||||
int ret = 0;
|
||||
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
props.max_brightness = BRIGHTNESS_MAX_LEVEL;
|
||||
props.type = BACKLIGHT_PLATFORM;
|
||||
mdfld_backlight_device = backlight_device_register("mdfld-bl",
|
||||
NULL, (void *)dev, &mdfld_ops, &props);
|
||||
|
||||
if (IS_ERR(mdfld_backlight_device))
|
||||
return PTR_ERR(mdfld_backlight_device);
|
||||
|
||||
ret = device_backlight_init(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mdfld_backlight_device->props.brightness = BRIGHTNESS_MAX_LEVEL;
|
||||
mdfld_backlight_device->props.max_brightness = BRIGHTNESS_MAX_LEVEL;
|
||||
backlight_update_status(mdfld_backlight_device);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct backlight_device *mdfld_get_backlight_device(void)
|
||||
{
|
||||
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
|
||||
return mdfld_backlight_device;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* mdfld_save_display_registers
|
||||
*
|
||||
* Description: We are going to suspend so save current display
|
||||
* register state.
|
||||
*
|
||||
* Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
|
||||
*/
|
||||
static int mdfld_save_display_registers(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct medfield_state *regs = &dev_priv->regs.mdfld;
|
||||
int i;
|
||||
|
||||
/* register */
|
||||
u32 dpll_reg = MRST_DPLL_A;
|
||||
u32 fp_reg = MRST_FPA0;
|
||||
u32 pipeconf_reg = PIPEACONF;
|
||||
u32 htot_reg = HTOTAL_A;
|
||||
u32 hblank_reg = HBLANK_A;
|
||||
u32 hsync_reg = HSYNC_A;
|
||||
u32 vtot_reg = VTOTAL_A;
|
||||
u32 vblank_reg = VBLANK_A;
|
||||
u32 vsync_reg = VSYNC_A;
|
||||
u32 pipesrc_reg = PIPEASRC;
|
||||
u32 dspstride_reg = DSPASTRIDE;
|
||||
u32 dsplinoff_reg = DSPALINOFF;
|
||||
u32 dsptileoff_reg = DSPATILEOFF;
|
||||
u32 dspsize_reg = DSPASIZE;
|
||||
u32 dsppos_reg = DSPAPOS;
|
||||
u32 dspsurf_reg = DSPASURF;
|
||||
u32 mipi_reg = MIPI;
|
||||
u32 dspcntr_reg = DSPACNTR;
|
||||
u32 dspstatus_reg = PIPEASTAT;
|
||||
u32 palette_reg = PALETTE_A;
|
||||
|
||||
/* pointer to values */
|
||||
u32 *dpll_val = ®s->saveDPLL_A;
|
||||
u32 *fp_val = ®s->saveFPA0;
|
||||
u32 *pipeconf_val = ®s->savePIPEACONF;
|
||||
u32 *htot_val = ®s->saveHTOTAL_A;
|
||||
u32 *hblank_val = ®s->saveHBLANK_A;
|
||||
u32 *hsync_val = ®s->saveHSYNC_A;
|
||||
u32 *vtot_val = ®s->saveVTOTAL_A;
|
||||
u32 *vblank_val = ®s->saveVBLANK_A;
|
||||
u32 *vsync_val = ®s->saveVSYNC_A;
|
||||
u32 *pipesrc_val = ®s->savePIPEASRC;
|
||||
u32 *dspstride_val = ®s->saveDSPASTRIDE;
|
||||
u32 *dsplinoff_val = ®s->saveDSPALINOFF;
|
||||
u32 *dsptileoff_val = ®s->saveDSPATILEOFF;
|
||||
u32 *dspsize_val = ®s->saveDSPASIZE;
|
||||
u32 *dsppos_val = ®s->saveDSPAPOS;
|
||||
u32 *dspsurf_val = ®s->saveDSPASURF;
|
||||
u32 *mipi_val = ®s->saveMIPI;
|
||||
u32 *dspcntr_val = ®s->saveDSPACNTR;
|
||||
u32 *dspstatus_val = ®s->saveDSPASTATUS;
|
||||
u32 *palette_val = regs->save_palette_a;
|
||||
|
||||
switch (pipe) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
/* regester */
|
||||
dpll_reg = MDFLD_DPLL_B;
|
||||
fp_reg = MDFLD_DPLL_DIV0;
|
||||
pipeconf_reg = PIPEBCONF;
|
||||
htot_reg = HTOTAL_B;
|
||||
hblank_reg = HBLANK_B;
|
||||
hsync_reg = HSYNC_B;
|
||||
vtot_reg = VTOTAL_B;
|
||||
vblank_reg = VBLANK_B;
|
||||
vsync_reg = VSYNC_B;
|
||||
pipesrc_reg = PIPEBSRC;
|
||||
dspstride_reg = DSPBSTRIDE;
|
||||
dsplinoff_reg = DSPBLINOFF;
|
||||
dsptileoff_reg = DSPBTILEOFF;
|
||||
dspsize_reg = DSPBSIZE;
|
||||
dsppos_reg = DSPBPOS;
|
||||
dspsurf_reg = DSPBSURF;
|
||||
dspcntr_reg = DSPBCNTR;
|
||||
dspstatus_reg = PIPEBSTAT;
|
||||
palette_reg = PALETTE_B;
|
||||
|
||||
/* values */
|
||||
dpll_val = ®s->saveDPLL_B;
|
||||
fp_val = ®s->saveFPB0;
|
||||
pipeconf_val = ®s->savePIPEBCONF;
|
||||
htot_val = ®s->saveHTOTAL_B;
|
||||
hblank_val = ®s->saveHBLANK_B;
|
||||
hsync_val = ®s->saveHSYNC_B;
|
||||
vtot_val = ®s->saveVTOTAL_B;
|
||||
vblank_val = ®s->saveVBLANK_B;
|
||||
vsync_val = ®s->saveVSYNC_B;
|
||||
pipesrc_val = ®s->savePIPEBSRC;
|
||||
dspstride_val = ®s->saveDSPBSTRIDE;
|
||||
dsplinoff_val = ®s->saveDSPBLINOFF;
|
||||
dsptileoff_val = ®s->saveDSPBTILEOFF;
|
||||
dspsize_val = ®s->saveDSPBSIZE;
|
||||
dsppos_val = ®s->saveDSPBPOS;
|
||||
dspsurf_val = ®s->saveDSPBSURF;
|
||||
dspcntr_val = ®s->saveDSPBCNTR;
|
||||
dspstatus_val = ®s->saveDSPBSTATUS;
|
||||
palette_val = regs->save_palette_b;
|
||||
break;
|
||||
case 2:
|
||||
/* register */
|
||||
pipeconf_reg = PIPECCONF;
|
||||
htot_reg = HTOTAL_C;
|
||||
hblank_reg = HBLANK_C;
|
||||
hsync_reg = HSYNC_C;
|
||||
vtot_reg = VTOTAL_C;
|
||||
vblank_reg = VBLANK_C;
|
||||
vsync_reg = VSYNC_C;
|
||||
pipesrc_reg = PIPECSRC;
|
||||
dspstride_reg = DSPCSTRIDE;
|
||||
dsplinoff_reg = DSPCLINOFF;
|
||||
dsptileoff_reg = DSPCTILEOFF;
|
||||
dspsize_reg = DSPCSIZE;
|
||||
dsppos_reg = DSPCPOS;
|
||||
dspsurf_reg = DSPCSURF;
|
||||
mipi_reg = MIPI_C;
|
||||
dspcntr_reg = DSPCCNTR;
|
||||
dspstatus_reg = PIPECSTAT;
|
||||
palette_reg = PALETTE_C;
|
||||
|
||||
/* pointer to values */
|
||||
pipeconf_val = ®s->savePIPECCONF;
|
||||
htot_val = ®s->saveHTOTAL_C;
|
||||
hblank_val = ®s->saveHBLANK_C;
|
||||
hsync_val = ®s->saveHSYNC_C;
|
||||
vtot_val = ®s->saveVTOTAL_C;
|
||||
vblank_val = ®s->saveVBLANK_C;
|
||||
vsync_val = ®s->saveVSYNC_C;
|
||||
pipesrc_val = ®s->savePIPECSRC;
|
||||
dspstride_val = ®s->saveDSPCSTRIDE;
|
||||
dsplinoff_val = ®s->saveDSPCLINOFF;
|
||||
dsptileoff_val = ®s->saveDSPCTILEOFF;
|
||||
dspsize_val = ®s->saveDSPCSIZE;
|
||||
dsppos_val = ®s->saveDSPCPOS;
|
||||
dspsurf_val = ®s->saveDSPCSURF;
|
||||
mipi_val = ®s->saveMIPI_C;
|
||||
dspcntr_val = ®s->saveDSPCCNTR;
|
||||
dspstatus_val = ®s->saveDSPCSTATUS;
|
||||
palette_val = regs->save_palette_c;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("%s, invalid pipe number.\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Pipe & plane A info */
|
||||
*dpll_val = PSB_RVDC32(dpll_reg);
|
||||
*fp_val = PSB_RVDC32(fp_reg);
|
||||
*pipeconf_val = PSB_RVDC32(pipeconf_reg);
|
||||
*htot_val = PSB_RVDC32(htot_reg);
|
||||
*hblank_val = PSB_RVDC32(hblank_reg);
|
||||
*hsync_val = PSB_RVDC32(hsync_reg);
|
||||
*vtot_val = PSB_RVDC32(vtot_reg);
|
||||
*vblank_val = PSB_RVDC32(vblank_reg);
|
||||
*vsync_val = PSB_RVDC32(vsync_reg);
|
||||
*pipesrc_val = PSB_RVDC32(pipesrc_reg);
|
||||
*dspstride_val = PSB_RVDC32(dspstride_reg);
|
||||
*dsplinoff_val = PSB_RVDC32(dsplinoff_reg);
|
||||
*dsptileoff_val = PSB_RVDC32(dsptileoff_reg);
|
||||
*dspsize_val = PSB_RVDC32(dspsize_reg);
|
||||
*dsppos_val = PSB_RVDC32(dsppos_reg);
|
||||
*dspsurf_val = PSB_RVDC32(dspsurf_reg);
|
||||
*dspcntr_val = PSB_RVDC32(dspcntr_reg);
|
||||
*dspstatus_val = PSB_RVDC32(dspstatus_reg);
|
||||
|
||||
/*save palette (gamma) */
|
||||
for (i = 0; i < 256; i++)
|
||||
palette_val[i] = PSB_RVDC32(palette_reg + (i << 2));
|
||||
|
||||
if (pipe == 1) {
|
||||
regs->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
|
||||
regs->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
|
||||
|
||||
regs->saveHDMIPHYMISCCTL = PSB_RVDC32(HDMIPHYMISCCTL);
|
||||
regs->saveHDMIB_CONTROL = PSB_RVDC32(HDMIB_CONTROL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*mipi_val = PSB_RVDC32(mipi_reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* mdfld_restore_display_registers
|
||||
*
|
||||
* Description: We are going to resume so restore display register state.
|
||||
*
|
||||
* Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
|
||||
*/
|
||||
static int mdfld_restore_display_registers(struct drm_device *dev, int pipe)
|
||||
{
|
||||
/* To get panel out of ULPS mode. */
|
||||
u32 temp = 0;
|
||||
u32 device_ready_reg = DEVICE_READY_REG;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct mdfld_dsi_config *dsi_config = NULL;
|
||||
struct medfield_state *regs = &dev_priv->regs.mdfld;
|
||||
u32 i = 0;
|
||||
u32 dpll = 0;
|
||||
u32 timeout = 0;
|
||||
|
||||
/* regester */
|
||||
u32 dpll_reg = MRST_DPLL_A;
|
||||
u32 fp_reg = MRST_FPA0;
|
||||
u32 pipeconf_reg = PIPEACONF;
|
||||
u32 htot_reg = HTOTAL_A;
|
||||
u32 hblank_reg = HBLANK_A;
|
||||
u32 hsync_reg = HSYNC_A;
|
||||
u32 vtot_reg = VTOTAL_A;
|
||||
u32 vblank_reg = VBLANK_A;
|
||||
u32 vsync_reg = VSYNC_A;
|
||||
u32 pipesrc_reg = PIPEASRC;
|
||||
u32 dspstride_reg = DSPASTRIDE;
|
||||
u32 dsplinoff_reg = DSPALINOFF;
|
||||
u32 dsptileoff_reg = DSPATILEOFF;
|
||||
u32 dspsize_reg = DSPASIZE;
|
||||
u32 dsppos_reg = DSPAPOS;
|
||||
u32 dspsurf_reg = DSPASURF;
|
||||
u32 dspstatus_reg = PIPEASTAT;
|
||||
u32 mipi_reg = MIPI;
|
||||
u32 dspcntr_reg = DSPACNTR;
|
||||
u32 palette_reg = PALETTE_A;
|
||||
|
||||
/* values */
|
||||
u32 dpll_val = regs->saveDPLL_A & ~DPLL_VCO_ENABLE;
|
||||
u32 fp_val = regs->saveFPA0;
|
||||
u32 pipeconf_val = regs->savePIPEACONF;
|
||||
u32 htot_val = regs->saveHTOTAL_A;
|
||||
u32 hblank_val = regs->saveHBLANK_A;
|
||||
u32 hsync_val = regs->saveHSYNC_A;
|
||||
u32 vtot_val = regs->saveVTOTAL_A;
|
||||
u32 vblank_val = regs->saveVBLANK_A;
|
||||
u32 vsync_val = regs->saveVSYNC_A;
|
||||
u32 pipesrc_val = regs->savePIPEASRC;
|
||||
u32 dspstride_val = regs->saveDSPASTRIDE;
|
||||
u32 dsplinoff_val = regs->saveDSPALINOFF;
|
||||
u32 dsptileoff_val = regs->saveDSPATILEOFF;
|
||||
u32 dspsize_val = regs->saveDSPASIZE;
|
||||
u32 dsppos_val = regs->saveDSPAPOS;
|
||||
u32 dspsurf_val = regs->saveDSPASURF;
|
||||
u32 dspstatus_val = regs->saveDSPASTATUS;
|
||||
u32 mipi_val = regs->saveMIPI;
|
||||
u32 dspcntr_val = regs->saveDSPACNTR;
|
||||
u32 *palette_val = regs->save_palette_a;
|
||||
|
||||
switch (pipe) {
|
||||
case 0:
|
||||
dsi_config = dev_priv->dsi_configs[0];
|
||||
break;
|
||||
case 1:
|
||||
/* regester */
|
||||
dpll_reg = MDFLD_DPLL_B;
|
||||
fp_reg = MDFLD_DPLL_DIV0;
|
||||
pipeconf_reg = PIPEBCONF;
|
||||
htot_reg = HTOTAL_B;
|
||||
hblank_reg = HBLANK_B;
|
||||
hsync_reg = HSYNC_B;
|
||||
vtot_reg = VTOTAL_B;
|
||||
vblank_reg = VBLANK_B;
|
||||
vsync_reg = VSYNC_B;
|
||||
pipesrc_reg = PIPEBSRC;
|
||||
dspstride_reg = DSPBSTRIDE;
|
||||
dsplinoff_reg = DSPBLINOFF;
|
||||
dsptileoff_reg = DSPBTILEOFF;
|
||||
dspsize_reg = DSPBSIZE;
|
||||
dsppos_reg = DSPBPOS;
|
||||
dspsurf_reg = DSPBSURF;
|
||||
dspcntr_reg = DSPBCNTR;
|
||||
dspstatus_reg = PIPEBSTAT;
|
||||
palette_reg = PALETTE_B;
|
||||
|
||||
/* values */
|
||||
dpll_val = regs->saveDPLL_B & ~DPLL_VCO_ENABLE;
|
||||
fp_val = regs->saveFPB0;
|
||||
pipeconf_val = regs->savePIPEBCONF;
|
||||
htot_val = regs->saveHTOTAL_B;
|
||||
hblank_val = regs->saveHBLANK_B;
|
||||
hsync_val = regs->saveHSYNC_B;
|
||||
vtot_val = regs->saveVTOTAL_B;
|
||||
vblank_val = regs->saveVBLANK_B;
|
||||
vsync_val = regs->saveVSYNC_B;
|
||||
pipesrc_val = regs->savePIPEBSRC;
|
||||
dspstride_val = regs->saveDSPBSTRIDE;
|
||||
dsplinoff_val = regs->saveDSPBLINOFF;
|
||||
dsptileoff_val = regs->saveDSPBTILEOFF;
|
||||
dspsize_val = regs->saveDSPBSIZE;
|
||||
dsppos_val = regs->saveDSPBPOS;
|
||||
dspsurf_val = regs->saveDSPBSURF;
|
||||
dspcntr_val = regs->saveDSPBCNTR;
|
||||
dspstatus_val = regs->saveDSPBSTATUS;
|
||||
palette_val = regs->save_palette_b;
|
||||
break;
|
||||
case 2:
|
||||
/* regester */
|
||||
pipeconf_reg = PIPECCONF;
|
||||
htot_reg = HTOTAL_C;
|
||||
hblank_reg = HBLANK_C;
|
||||
hsync_reg = HSYNC_C;
|
||||
vtot_reg = VTOTAL_C;
|
||||
vblank_reg = VBLANK_C;
|
||||
vsync_reg = VSYNC_C;
|
||||
pipesrc_reg = PIPECSRC;
|
||||
dspstride_reg = DSPCSTRIDE;
|
||||
dsplinoff_reg = DSPCLINOFF;
|
||||
dsptileoff_reg = DSPCTILEOFF;
|
||||
dspsize_reg = DSPCSIZE;
|
||||
dsppos_reg = DSPCPOS;
|
||||
dspsurf_reg = DSPCSURF;
|
||||
mipi_reg = MIPI_C;
|
||||
dspcntr_reg = DSPCCNTR;
|
||||
dspstatus_reg = PIPECSTAT;
|
||||
palette_reg = PALETTE_C;
|
||||
|
||||
/* values */
|
||||
pipeconf_val = regs->savePIPECCONF;
|
||||
htot_val = regs->saveHTOTAL_C;
|
||||
hblank_val = regs->saveHBLANK_C;
|
||||
hsync_val = regs->saveHSYNC_C;
|
||||
vtot_val = regs->saveVTOTAL_C;
|
||||
vblank_val = regs->saveVBLANK_C;
|
||||
vsync_val = regs->saveVSYNC_C;
|
||||
pipesrc_val = regs->savePIPECSRC;
|
||||
dspstride_val = regs->saveDSPCSTRIDE;
|
||||
dsplinoff_val = regs->saveDSPCLINOFF;
|
||||
dsptileoff_val = regs->saveDSPCTILEOFF;
|
||||
dspsize_val = regs->saveDSPCSIZE;
|
||||
dsppos_val = regs->saveDSPCPOS;
|
||||
dspsurf_val = regs->saveDSPCSURF;
|
||||
mipi_val = regs->saveMIPI_C;
|
||||
dspcntr_val = regs->saveDSPCCNTR;
|
||||
dspstatus_val = regs->saveDSPCSTATUS;
|
||||
palette_val = regs->save_palette_c;
|
||||
|
||||
dsi_config = dev_priv->dsi_configs[1];
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("%s, invalid pipe number.\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*make sure VGA plane is off. it initializes to on after reset!*/
|
||||
PSB_WVDC32(0x80000000, VGACNTRL);
|
||||
|
||||
if (pipe == 1) {
|
||||
PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, dpll_reg);
|
||||
PSB_RVDC32(dpll_reg);
|
||||
|
||||
PSB_WVDC32(fp_val, fp_reg);
|
||||
} else {
|
||||
|
||||
dpll = PSB_RVDC32(dpll_reg);
|
||||
|
||||
if (!(dpll & DPLL_VCO_ENABLE)) {
|
||||
|
||||
/* When ungating power of DPLL, needs to wait 0.5us
|
||||
before enable the VCO */
|
||||
if (dpll & MDFLD_PWR_GATE_EN) {
|
||||
dpll &= ~MDFLD_PWR_GATE_EN;
|
||||
PSB_WVDC32(dpll, dpll_reg);
|
||||
/* FIXME_MDFLD PO - change 500 to 1 after PO */
|
||||
udelay(500);
|
||||
}
|
||||
|
||||
PSB_WVDC32(fp_val, fp_reg);
|
||||
PSB_WVDC32(dpll_val, dpll_reg);
|
||||
/* FIXME_MDFLD PO - change 500 to 1 after PO */
|
||||
udelay(500);
|
||||
|
||||
dpll_val |= DPLL_VCO_ENABLE;
|
||||
PSB_WVDC32(dpll_val, dpll_reg);
|
||||
PSB_RVDC32(dpll_reg);
|
||||
|
||||
/* wait for DSI PLL to lock */
|
||||
while (timeout < 20000 &&
|
||||
!(PSB_RVDC32(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) {
|
||||
udelay(150);
|
||||
timeout++;
|
||||
}
|
||||
|
||||
if (timeout == 20000) {
|
||||
DRM_ERROR("%s, can't lock DSIPLL.\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Restore mode */
|
||||
PSB_WVDC32(htot_val, htot_reg);
|
||||
PSB_WVDC32(hblank_val, hblank_reg);
|
||||
PSB_WVDC32(hsync_val, hsync_reg);
|
||||
PSB_WVDC32(vtot_val, vtot_reg);
|
||||
PSB_WVDC32(vblank_val, vblank_reg);
|
||||
PSB_WVDC32(vsync_val, vsync_reg);
|
||||
PSB_WVDC32(pipesrc_val, pipesrc_reg);
|
||||
PSB_WVDC32(dspstatus_val, dspstatus_reg);
|
||||
|
||||
/*set up the plane*/
|
||||
PSB_WVDC32(dspstride_val, dspstride_reg);
|
||||
PSB_WVDC32(dsplinoff_val, dsplinoff_reg);
|
||||
PSB_WVDC32(dsptileoff_val, dsptileoff_reg);
|
||||
PSB_WVDC32(dspsize_val, dspsize_reg);
|
||||
PSB_WVDC32(dsppos_val, dsppos_reg);
|
||||
PSB_WVDC32(dspsurf_val, dspsurf_reg);
|
||||
|
||||
if (pipe == 1) {
|
||||
/* restore palette (gamma) */
|
||||
/*DRM_UDELAY(50000); */
|
||||
for (i = 0; i < 256; i++)
|
||||
PSB_WVDC32(palette_val[i], palette_reg + (i << 2));
|
||||
|
||||
PSB_WVDC32(regs->savePFIT_CONTROL, PFIT_CONTROL);
|
||||
PSB_WVDC32(regs->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
|
||||
|
||||
/*TODO: resume HDMI port */
|
||||
|
||||
/*TODO: resume pipe*/
|
||||
|
||||
/*enable the plane*/
|
||||
PSB_WVDC32(dspcntr_val & ~DISPLAY_PLANE_ENABLE, dspcntr_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*set up pipe related registers*/
|
||||
PSB_WVDC32(mipi_val, mipi_reg);
|
||||
|
||||
/*setup MIPI adapter + MIPI IP registers*/
|
||||
if (dsi_config)
|
||||
mdfld_dsi_controller_init(dsi_config, pipe);
|
||||
|
||||
if (in_atomic() || in_interrupt())
|
||||
mdelay(20);
|
||||
else
|
||||
msleep(20);
|
||||
|
||||
/*enable the plane*/
|
||||
PSB_WVDC32(dspcntr_val, dspcntr_reg);
|
||||
|
||||
if (in_atomic() || in_interrupt())
|
||||
mdelay(20);
|
||||
else
|
||||
msleep(20);
|
||||
|
||||
/* LP Hold Release */
|
||||
temp = REG_READ(mipi_reg);
|
||||
temp |= LP_OUTPUT_HOLD_RELEASE;
|
||||
REG_WRITE(mipi_reg, temp);
|
||||
mdelay(1);
|
||||
|
||||
|
||||
/* Set DSI host to exit from Utra Low Power State */
|
||||
temp = REG_READ(device_ready_reg);
|
||||
temp &= ~ULPS_MASK;
|
||||
temp |= 0x3;
|
||||
temp |= EXIT_ULPS_DEV_READY;
|
||||
REG_WRITE(device_ready_reg, temp);
|
||||
mdelay(1);
|
||||
|
||||
temp = REG_READ(device_ready_reg);
|
||||
temp &= ~ULPS_MASK;
|
||||
temp |= EXITING_ULPS;
|
||||
REG_WRITE(device_ready_reg, temp);
|
||||
mdelay(1);
|
||||
|
||||
/*enable the pipe*/
|
||||
PSB_WVDC32(pipeconf_val, pipeconf_reg);
|
||||
|
||||
/* restore palette (gamma) */
|
||||
/*DRM_UDELAY(50000); */
|
||||
for (i = 0; i < 256; i++)
|
||||
PSB_WVDC32(palette_val[i], palette_reg + (i << 2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdfld_save_registers(struct drm_device *dev)
|
||||
{
|
||||
/* mdfld_save_cursor_overlay_registers(dev); */
|
||||
mdfld_save_display_registers(dev, 0);
|
||||
mdfld_save_display_registers(dev, 2);
|
||||
mdfld_disable_crtc(dev, 0);
|
||||
mdfld_disable_crtc(dev, 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdfld_restore_registers(struct drm_device *dev)
|
||||
{
|
||||
mdfld_restore_display_registers(dev, 2);
|
||||
mdfld_restore_display_registers(dev, 0);
|
||||
/* mdfld_restore_cursor_overlay_registers(dev); */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdfld_power_down(struct drm_device *dev)
|
||||
{
|
||||
/* FIXME */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdfld_power_up(struct drm_device *dev)
|
||||
{
|
||||
/* FIXME */
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct psb_ops mdfld_chip_ops = {
|
||||
.name = "mdfld",
|
||||
.accel_2d = 0,
|
||||
.pipes = 3,
|
||||
.crtcs = 3,
|
||||
.sgx_offset = MRST_SGX_OFFSET,
|
||||
|
||||
.chip_setup = mid_chip_setup,
|
||||
.crtc_helper = &mdfld_helper_funcs,
|
||||
.crtc_funcs = &psb_intel_crtc_funcs,
|
||||
|
||||
.output_init = mdfld_output_init,
|
||||
|
||||
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
|
||||
.backlight_init = mdfld_backlight_init,
|
||||
#endif
|
||||
|
||||
.save_regs = mdfld_save_registers,
|
||||
.restore_regs = mdfld_restore_registers,
|
||||
.power_down = mdfld_power_down,
|
||||
.power_up = mdfld_power_up,
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* jim liu <jim.liu@intel.com>
|
||||
* Jackie Li<yaodong.li@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef __MDFLD_DSI_DPI_H__
|
||||
#define __MDFLD_DSI_DPI_H__
|
||||
|
||||
#include "mdfld_dsi_output.h"
|
||||
#include "mdfld_output.h"
|
||||
|
||||
struct mdfld_dsi_dpi_timing {
|
||||
u16 hsync_count;
|
||||
u16 hbp_count;
|
||||
u16 hfp_count;
|
||||
u16 hactive_count;
|
||||
u16 vsync_count;
|
||||
u16 vbp_count;
|
||||
u16 vfp_count;
|
||||
};
|
||||
|
||||
struct mdfld_dsi_dpi_output {
|
||||
struct mdfld_dsi_encoder base;
|
||||
struct drm_device *dev;
|
||||
|
||||
int panel_on;
|
||||
int first_boot;
|
||||
|
||||
const struct panel_funcs *p_funcs;
|
||||
};
|
||||
|
||||
#define MDFLD_DSI_DPI_OUTPUT(dsi_encoder)\
|
||||
container_of(dsi_encoder, struct mdfld_dsi_dpi_output, base)
|
||||
|
||||
/* Export functions */
|
||||
extern int mdfld_dsi_dpi_timing_calculation(struct drm_display_mode *mode,
|
||||
struct mdfld_dsi_dpi_timing *dpi_timing,
|
||||
int num_lane, int bpp);
|
||||
extern struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev,
|
||||
struct mdfld_dsi_connector *dsi_connector,
|
||||
const struct panel_funcs *p_funcs);
|
||||
|
||||
/* MDFLD DPI helper functions */
|
||||
extern void mdfld_dsi_dpi_dpms(struct drm_encoder *encoder, int mode);
|
||||
extern bool mdfld_dsi_dpi_mode_fixup(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern void mdfld_dsi_dpi_prepare(struct drm_encoder *encoder);
|
||||
extern void mdfld_dsi_dpi_commit(struct drm_encoder *encoder);
|
||||
extern void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern void mdfld_dsi_dpi_turn_on(struct mdfld_dsi_dpi_output *output,
|
||||
int pipe);
|
||||
extern void mdfld_dsi_dpi_controller_init(struct mdfld_dsi_config *dsi_config,
|
||||
int pipe);
|
||||
#endif /*__MDFLD_DSI_DPI_H__*/
|
|
@ -0,0 +1,618 @@
|
|||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* jim liu <jim.liu@intel.com>
|
||||
* Jackie Li<yaodong.li@intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "mdfld_dsi_output.h"
|
||||
#include "mdfld_dsi_dpi.h"
|
||||
#include "mdfld_output.h"
|
||||
#include "mdfld_dsi_pkg_sender.h"
|
||||
#include "tc35876x-dsi-lvds.h"
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <asm/intel_scu_ipc.h>
|
||||
|
||||
/* get the LABC from command line. */
|
||||
static int LABC_control = 1;
|
||||
|
||||
#ifdef MODULE
|
||||
module_param(LABC_control, int, 0644);
|
||||
#else
|
||||
|
||||
static int __init parse_LABC_control(char *arg)
|
||||
{
|
||||
/* LABC control can be passed in as a cmdline parameter */
|
||||
/* to enable this feature add LABC=1 to cmdline */
|
||||
/* to disable this feature add LABC=0 to cmdline */
|
||||
if (!arg)
|
||||
return -EINVAL;
|
||||
|
||||
if (!strcasecmp(arg, "0"))
|
||||
LABC_control = 0;
|
||||
else if (!strcasecmp(arg, "1"))
|
||||
LABC_control = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
early_param("LABC", parse_LABC_control);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Check and see if the generic control or data buffer is empty and ready.
|
||||
*/
|
||||
void mdfld_dsi_gen_fifo_ready(struct drm_device *dev, u32 gen_fifo_stat_reg,
|
||||
u32 fifo_stat)
|
||||
{
|
||||
u32 GEN_BF_time_out_count;
|
||||
|
||||
/* Check MIPI Adatper command registers */
|
||||
for (GEN_BF_time_out_count = 0;
|
||||
GEN_BF_time_out_count < GEN_FB_TIME_OUT;
|
||||
GEN_BF_time_out_count++) {
|
||||
if ((REG_READ(gen_fifo_stat_reg) & fifo_stat) == fifo_stat)
|
||||
break;
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
if (GEN_BF_time_out_count == GEN_FB_TIME_OUT)
|
||||
DRM_ERROR("mdfld_dsi_gen_fifo_ready, Timeout. gen_fifo_stat_reg = 0x%x.\n",
|
||||
gen_fifo_stat_reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the DSI MIPI keyboard and display brightness.
|
||||
* FIXME: this is exported to OSPM code. should work out an specific
|
||||
* display interface to OSPM.
|
||||
*/
|
||||
|
||||
void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, int pipe)
|
||||
{
|
||||
struct mdfld_dsi_pkg_sender *sender =
|
||||
mdfld_dsi_get_pkg_sender(dsi_config);
|
||||
struct drm_device *dev = sender->dev;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
u32 gen_ctrl_val;
|
||||
|
||||
if (!sender) {
|
||||
DRM_ERROR("No sender found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set default display backlight value to 85% (0xd8)*/
|
||||
mdfld_dsi_send_mcs_short(sender, write_display_brightness, 0xd8, 1,
|
||||
true);
|
||||
|
||||
/* Set minimum brightness setting of CABC function to 20% (0x33)*/
|
||||
mdfld_dsi_send_mcs_short(sender, write_cabc_min_bright, 0x33, 1, true);
|
||||
|
||||
/* Enable backlight or/and LABC */
|
||||
gen_ctrl_val = BRIGHT_CNTL_BLOCK_ON | DISPLAY_DIMMING_ON |
|
||||
BACKLIGHT_ON;
|
||||
if (LABC_control == 1)
|
||||
gen_ctrl_val |= DISPLAY_DIMMING_ON | DISPLAY_BRIGHTNESS_AUTO
|
||||
| GAMMA_AUTO;
|
||||
|
||||
if (LABC_control == 1)
|
||||
gen_ctrl_val |= AMBIENT_LIGHT_SENSE_ON;
|
||||
|
||||
dev_priv->mipi_ctrl_display = gen_ctrl_val;
|
||||
|
||||
mdfld_dsi_send_mcs_short(sender, write_ctrl_display, (u8)gen_ctrl_val,
|
||||
1, true);
|
||||
|
||||
mdfld_dsi_send_mcs_short(sender, write_ctrl_cabc, UI_IMAGE, 1, true);
|
||||
}
|
||||
|
||||
void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe, int level)
|
||||
{
|
||||
struct mdfld_dsi_pkg_sender *sender;
|
||||
struct drm_psb_private *dev_priv;
|
||||
struct mdfld_dsi_config *dsi_config;
|
||||
u32 gen_ctrl_val = 0;
|
||||
int p_type = TMD_VID;
|
||||
|
||||
if (!dev || (pipe != 0 && pipe != 2)) {
|
||||
DRM_ERROR("Invalid parameter\n");
|
||||
return;
|
||||
}
|
||||
|
||||
p_type = mdfld_get_panel_type(dev, 0);
|
||||
|
||||
dev_priv = dev->dev_private;
|
||||
|
||||
if (pipe)
|
||||
dsi_config = dev_priv->dsi_configs[1];
|
||||
else
|
||||
dsi_config = dev_priv->dsi_configs[0];
|
||||
|
||||
sender = mdfld_dsi_get_pkg_sender(dsi_config);
|
||||
|
||||
if (!sender) {
|
||||
DRM_ERROR("No sender found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
gen_ctrl_val = (level * 0xff / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL) & 0xff;
|
||||
|
||||
dev_dbg(sender->dev->dev, "pipe = %d, gen_ctrl_val = %d.\n",
|
||||
pipe, gen_ctrl_val);
|
||||
|
||||
if (p_type == TMD_VID) {
|
||||
/* Set display backlight value */
|
||||
mdfld_dsi_send_mcs_short(sender, tmd_write_display_brightness,
|
||||
(u8)gen_ctrl_val, 1, true);
|
||||
} else {
|
||||
/* Set display backlight value */
|
||||
mdfld_dsi_send_mcs_short(sender, write_display_brightness,
|
||||
(u8)gen_ctrl_val, 1, true);
|
||||
|
||||
/* Enable backlight control */
|
||||
if (level == 0)
|
||||
gen_ctrl_val = 0;
|
||||
else
|
||||
gen_ctrl_val = dev_priv->mipi_ctrl_display;
|
||||
|
||||
mdfld_dsi_send_mcs_short(sender, write_ctrl_display,
|
||||
(u8)gen_ctrl_val, 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
static int mdfld_dsi_get_panel_status(struct mdfld_dsi_config *dsi_config,
|
||||
u8 dcs, u32 *data, bool hs)
|
||||
{
|
||||
struct mdfld_dsi_pkg_sender *sender
|
||||
= mdfld_dsi_get_pkg_sender(dsi_config);
|
||||
|
||||
if (!sender || !data) {
|
||||
DRM_ERROR("Invalid parameter\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return mdfld_dsi_read_mcs(sender, dcs, data, 1, hs);
|
||||
}
|
||||
|
||||
int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, u32 *mode,
|
||||
bool hs)
|
||||
{
|
||||
if (!dsi_config || !mode) {
|
||||
DRM_ERROR("Invalid parameter\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return mdfld_dsi_get_panel_status(dsi_config, 0x0a, mode, hs);
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: this function was used by OSPM.
|
||||
* TODO: will be removed later, should work out display interfaces for OSPM
|
||||
*/
|
||||
void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config, int pipe)
|
||||
{
|
||||
if (!dsi_config || ((pipe != 0) && (pipe != 2))) {
|
||||
DRM_ERROR("Invalid parameters\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mdfld_dsi_dpi_controller_init(dsi_config, pipe);
|
||||
}
|
||||
|
||||
static void mdfld_dsi_connector_save(struct drm_connector *connector)
|
||||
{
|
||||
}
|
||||
|
||||
static void mdfld_dsi_connector_restore(struct drm_connector *connector)
|
||||
{
|
||||
}
|
||||
|
||||
/* FIXME: start using the force parameter */
|
||||
static enum drm_connector_status
|
||||
mdfld_dsi_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct mdfld_dsi_connector *dsi_connector
|
||||
= mdfld_dsi_connector(connector);
|
||||
|
||||
dsi_connector->status = connector_status_connected;
|
||||
|
||||
return dsi_connector->status;
|
||||
}
|
||||
|
||||
static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
|
||||
struct drm_property *property,
|
||||
uint64_t value)
|
||||
{
|
||||
struct drm_encoder *encoder = connector->encoder;
|
||||
struct backlight_device *psb_bd;
|
||||
|
||||
if (!strcmp(property->name, "scaling mode") && encoder) {
|
||||
struct psb_intel_crtc *psb_crtc =
|
||||
to_psb_intel_crtc(encoder->crtc);
|
||||
bool centerechange;
|
||||
uint64_t val;
|
||||
|
||||
if (!psb_crtc)
|
||||
goto set_prop_error;
|
||||
|
||||
switch (value) {
|
||||
case DRM_MODE_SCALE_FULLSCREEN:
|
||||
break;
|
||||
case DRM_MODE_SCALE_NO_SCALE:
|
||||
break;
|
||||
case DRM_MODE_SCALE_ASPECT:
|
||||
break;
|
||||
default:
|
||||
goto set_prop_error;
|
||||
}
|
||||
|
||||
if (drm_connector_property_get_value(connector, property, &val))
|
||||
goto set_prop_error;
|
||||
|
||||
if (val == value)
|
||||
goto set_prop_done;
|
||||
|
||||
if (drm_connector_property_set_value(connector,
|
||||
property, value))
|
||||
goto set_prop_error;
|
||||
|
||||
centerechange = (val == DRM_MODE_SCALE_NO_SCALE) ||
|
||||
(value == DRM_MODE_SCALE_NO_SCALE);
|
||||
|
||||
if (psb_crtc->saved_mode.hdisplay != 0 &&
|
||||
psb_crtc->saved_mode.vdisplay != 0) {
|
||||
if (centerechange) {
|
||||
if (!drm_crtc_helper_set_mode(encoder->crtc,
|
||||
&psb_crtc->saved_mode,
|
||||
encoder->crtc->x,
|
||||
encoder->crtc->y,
|
||||
encoder->crtc->fb))
|
||||
goto set_prop_error;
|
||||
} else {
|
||||
struct drm_encoder_helper_funcs *funcs =
|
||||
encoder->helper_private;
|
||||
funcs->mode_set(encoder,
|
||||
&psb_crtc->saved_mode,
|
||||
&psb_crtc->saved_adjusted_mode);
|
||||
}
|
||||
}
|
||||
} else if (!strcmp(property->name, "backlight") && encoder) {
|
||||
if (drm_connector_property_set_value(connector, property,
|
||||
value))
|
||||
goto set_prop_error;
|
||||
else {
|
||||
psb_bd = mdfld_get_backlight_device();
|
||||
if (psb_bd) {
|
||||
psb_bd->props.brightness = value;
|
||||
mdfld_set_brightness(psb_bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
set_prop_done:
|
||||
return 0;
|
||||
set_prop_error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void mdfld_dsi_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
struct mdfld_dsi_connector *dsi_connector =
|
||||
mdfld_dsi_connector(connector);
|
||||
struct mdfld_dsi_pkg_sender *sender;
|
||||
|
||||
if (!dsi_connector)
|
||||
return;
|
||||
drm_sysfs_connector_remove(connector);
|
||||
drm_connector_cleanup(connector);
|
||||
sender = dsi_connector->pkg_sender;
|
||||
mdfld_dsi_pkg_sender_destroy(sender);
|
||||
kfree(dsi_connector);
|
||||
}
|
||||
|
||||
static int mdfld_dsi_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct mdfld_dsi_connector *dsi_connector =
|
||||
mdfld_dsi_connector(connector);
|
||||
struct mdfld_dsi_config *dsi_config =
|
||||
mdfld_dsi_get_config(dsi_connector);
|
||||
struct drm_display_mode *fixed_mode = dsi_config->fixed_mode;
|
||||
struct drm_display_mode *dup_mode = NULL;
|
||||
struct drm_device *dev = connector->dev;
|
||||
|
||||
connector->display_info.min_vfreq = 0;
|
||||
connector->display_info.max_vfreq = 200;
|
||||
connector->display_info.min_hfreq = 0;
|
||||
connector->display_info.max_hfreq = 200;
|
||||
|
||||
if (fixed_mode) {
|
||||
dev_dbg(dev->dev, "fixed_mode %dx%d\n",
|
||||
fixed_mode->hdisplay, fixed_mode->vdisplay);
|
||||
dup_mode = drm_mode_duplicate(dev, fixed_mode);
|
||||
drm_mode_probed_add(connector, dup_mode);
|
||||
return 1;
|
||||
}
|
||||
DRM_ERROR("Didn't get any modes!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdfld_dsi_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct mdfld_dsi_connector *dsi_connector =
|
||||
mdfld_dsi_connector(connector);
|
||||
struct mdfld_dsi_config *dsi_config =
|
||||
mdfld_dsi_get_config(dsi_connector);
|
||||
struct drm_display_mode *fixed_mode = dsi_config->fixed_mode;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return MODE_NO_DBLESCAN;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
return MODE_NO_INTERLACE;
|
||||
|
||||
/**
|
||||
* FIXME: current DC has no fitting unit, reject any mode setting
|
||||
* request
|
||||
* Will figure out a way to do up-scaling(pannel fitting) later.
|
||||
**/
|
||||
if (fixed_mode) {
|
||||
if (mode->hdisplay != fixed_mode->hdisplay)
|
||||
return MODE_PANEL;
|
||||
|
||||
if (mode->vdisplay != fixed_mode->vdisplay)
|
||||
return MODE_PANEL;
|
||||
}
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void mdfld_dsi_connector_dpms(struct drm_connector *connector, int mode)
|
||||
{
|
||||
if (mode == connector->dpms)
|
||||
return;
|
||||
|
||||
/*first, execute dpms*/
|
||||
|
||||
drm_helper_connector_dpms(connector, mode);
|
||||
}
|
||||
|
||||
static struct drm_encoder *mdfld_dsi_connector_best_encoder(
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct mdfld_dsi_connector *dsi_connector =
|
||||
mdfld_dsi_connector(connector);
|
||||
struct mdfld_dsi_config *dsi_config =
|
||||
mdfld_dsi_get_config(dsi_connector);
|
||||
return &dsi_config->encoder->base.base;
|
||||
}
|
||||
|
||||
/*DSI connector funcs*/
|
||||
static const struct drm_connector_funcs mdfld_dsi_connector_funcs = {
|
||||
.dpms = /*drm_helper_connector_dpms*/mdfld_dsi_connector_dpms,
|
||||
.save = mdfld_dsi_connector_save,
|
||||
.restore = mdfld_dsi_connector_restore,
|
||||
.detect = mdfld_dsi_connector_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.set_property = mdfld_dsi_connector_set_property,
|
||||
.destroy = mdfld_dsi_connector_destroy,
|
||||
};
|
||||
|
||||
/*DSI connector helper funcs*/
|
||||
static const struct drm_connector_helper_funcs
|
||||
mdfld_dsi_connector_helper_funcs = {
|
||||
.get_modes = mdfld_dsi_connector_get_modes,
|
||||
.mode_valid = mdfld_dsi_connector_mode_valid,
|
||||
.best_encoder = mdfld_dsi_connector_best_encoder,
|
||||
};
|
||||
|
||||
static int mdfld_dsi_get_default_config(struct drm_device *dev,
|
||||
struct mdfld_dsi_config *config, int pipe)
|
||||
{
|
||||
if (!dev || !config) {
|
||||
DRM_ERROR("Invalid parameters");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
config->bpp = 24;
|
||||
if (mdfld_get_panel_type(dev, pipe) == TC35876X)
|
||||
config->lane_count = 4;
|
||||
else
|
||||
config->lane_count = 2;
|
||||
config->channel_num = 0;
|
||||
|
||||
if (mdfld_get_panel_type(dev, pipe) == TMD_VID)
|
||||
config->video_mode = MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE;
|
||||
else if (mdfld_get_panel_type(dev, pipe) == TC35876X)
|
||||
config->video_mode =
|
||||
MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS;
|
||||
else
|
||||
config->video_mode = MDFLD_DSI_VIDEO_BURST_MODE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdfld_dsi_panel_reset(int pipe)
|
||||
{
|
||||
unsigned gpio;
|
||||
int ret = 0;
|
||||
|
||||
switch (pipe) {
|
||||
case 0:
|
||||
gpio = 128;
|
||||
break;
|
||||
case 2:
|
||||
gpio = 34;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Invalid output\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = gpio_request(gpio, "gfx");
|
||||
if (ret) {
|
||||
DRM_ERROR("gpio_rqueset failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gpio_direction_output(gpio, 1);
|
||||
if (ret) {
|
||||
DRM_ERROR("gpio_direction_output failed\n");
|
||||
goto gpio_error;
|
||||
}
|
||||
|
||||
gpio_get_value(128);
|
||||
|
||||
gpio_error:
|
||||
if (gpio_is_valid(gpio))
|
||||
gpio_free(gpio);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* MIPI output init
|
||||
* @dev drm device
|
||||
* @pipe pipe number. 0 or 2
|
||||
* @config
|
||||
*
|
||||
* Do the initialization of a MIPI output, including create DRM mode objects
|
||||
* initialization of DSI output on @pipe
|
||||
*/
|
||||
void mdfld_dsi_output_init(struct drm_device *dev,
|
||||
int pipe,
|
||||
const struct panel_funcs *p_vid_funcs)
|
||||
{
|
||||
struct mdfld_dsi_config *dsi_config;
|
||||
struct mdfld_dsi_connector *dsi_connector;
|
||||
struct drm_connector *connector;
|
||||
struct mdfld_dsi_encoder *encoder;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct panel_info dsi_panel_info;
|
||||
u32 width_mm, height_mm;
|
||||
|
||||
dev_dbg(dev->dev, "init DSI output on pipe %d\n", pipe);
|
||||
|
||||
if (!dev || ((pipe != 0) && (pipe != 2))) {
|
||||
DRM_ERROR("Invalid parameter\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*create a new connetor*/
|
||||
dsi_connector = kzalloc(sizeof(struct mdfld_dsi_connector), GFP_KERNEL);
|
||||
if (!dsi_connector) {
|
||||
DRM_ERROR("No memory");
|
||||
return;
|
||||
}
|
||||
|
||||
dsi_connector->pipe = pipe;
|
||||
|
||||
dsi_config = kzalloc(sizeof(struct mdfld_dsi_config),
|
||||
GFP_KERNEL);
|
||||
if (!dsi_config) {
|
||||
DRM_ERROR("cannot allocate memory for DSI config\n");
|
||||
goto dsi_init_err0;
|
||||
}
|
||||
mdfld_dsi_get_default_config(dev, dsi_config, pipe);
|
||||
|
||||
dsi_connector->private = dsi_config;
|
||||
|
||||
dsi_config->changed = 1;
|
||||
dsi_config->dev = dev;
|
||||
|
||||
dsi_config->fixed_mode = p_vid_funcs->get_config_mode(dev);
|
||||
if (p_vid_funcs->get_panel_info(dev, pipe, &dsi_panel_info))
|
||||
goto dsi_init_err0;
|
||||
|
||||
width_mm = dsi_panel_info.width_mm;
|
||||
height_mm = dsi_panel_info.height_mm;
|
||||
|
||||
dsi_config->mode = dsi_config->fixed_mode;
|
||||
dsi_config->connector = dsi_connector;
|
||||
|
||||
if (!dsi_config->fixed_mode) {
|
||||
DRM_ERROR("No pannel fixed mode was found\n");
|
||||
goto dsi_init_err0;
|
||||
}
|
||||
|
||||
if (pipe && dev_priv->dsi_configs[0]) {
|
||||
dsi_config->dvr_ic_inited = 0;
|
||||
dev_priv->dsi_configs[1] = dsi_config;
|
||||
} else if (pipe == 0) {
|
||||
dsi_config->dvr_ic_inited = 1;
|
||||
dev_priv->dsi_configs[0] = dsi_config;
|
||||
} else {
|
||||
DRM_ERROR("Trying to init MIPI1 before MIPI0\n");
|
||||
goto dsi_init_err0;
|
||||
}
|
||||
|
||||
|
||||
connector = &dsi_connector->base.base;
|
||||
drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_LVDS);
|
||||
drm_connector_helper_add(connector, &mdfld_dsi_connector_helper_funcs);
|
||||
|
||||
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
|
||||
connector->display_info.width_mm = width_mm;
|
||||
connector->display_info.height_mm = height_mm;
|
||||
connector->interlace_allowed = false;
|
||||
connector->doublescan_allowed = false;
|
||||
|
||||
/*attach properties*/
|
||||
drm_connector_attach_property(connector,
|
||||
dev->mode_config.scaling_mode_property,
|
||||
DRM_MODE_SCALE_FULLSCREEN);
|
||||
drm_connector_attach_property(connector,
|
||||
dev_priv->backlight_property,
|
||||
MDFLD_DSI_BRIGHTNESS_MAX_LEVEL);
|
||||
|
||||
/*init DSI package sender on this output*/
|
||||
if (mdfld_dsi_pkg_sender_init(dsi_connector, pipe)) {
|
||||
DRM_ERROR("Package Sender initialization failed on pipe %d\n",
|
||||
pipe);
|
||||
goto dsi_init_err0;
|
||||
}
|
||||
|
||||
encoder = mdfld_dsi_dpi_init(dev, dsi_connector, p_vid_funcs);
|
||||
if (!encoder) {
|
||||
DRM_ERROR("Create DPI encoder failed\n");
|
||||
goto dsi_init_err1;
|
||||
}
|
||||
encoder->private = dsi_config;
|
||||
dsi_config->encoder = encoder;
|
||||
encoder->base.type = (pipe == 0) ? INTEL_OUTPUT_MIPI :
|
||||
INTEL_OUTPUT_MIPI2;
|
||||
drm_sysfs_connector_add(connector);
|
||||
return;
|
||||
|
||||
/*TODO: add code to destroy outputs on error*/
|
||||
dsi_init_err1:
|
||||
/*destroy sender*/
|
||||
mdfld_dsi_pkg_sender_destroy(dsi_connector->pkg_sender);
|
||||
|
||||
drm_connector_cleanup(connector);
|
||||
|
||||
kfree(dsi_config->fixed_mode);
|
||||
kfree(dsi_config);
|
||||
dsi_init_err0:
|
||||
kfree(dsi_connector);
|
||||
}
|
|
@ -0,0 +1,378 @@
|
|||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* jim liu <jim.liu@intel.com>
|
||||
* Jackie Li<yaodong.li@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef __MDFLD_DSI_OUTPUT_H__
|
||||
#define __MDFLD_DSI_OUTPUT_H__
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/version.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_edid.h>
|
||||
|
||||
#include "psb_drv.h"
|
||||
#include "psb_intel_drv.h"
|
||||
#include "psb_intel_reg.h"
|
||||
#include "mdfld_output.h"
|
||||
|
||||
#include <asm/mrst.h>
|
||||
|
||||
#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
|
||||
#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
|
||||
#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end))
|
||||
#define FLD_MOD(orig, val, start, end) \
|
||||
(((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
|
||||
|
||||
#define REG_FLD_MOD(reg, val, start, end) \
|
||||
REG_WRITE(reg, FLD_MOD(REG_READ(reg), val, start, end))
|
||||
|
||||
static inline int REGISTER_FLD_WAIT(struct drm_device *dev, u32 reg,
|
||||
u32 val, int start, int end)
|
||||
{
|
||||
int t = 100000;
|
||||
|
||||
while (FLD_GET(REG_READ(reg), start, end) != val) {
|
||||
if (--t == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define REG_FLD_WAIT(reg, val, start, end) \
|
||||
REGISTER_FLD_WAIT(dev, reg, val, start, end)
|
||||
|
||||
#define REG_BIT_WAIT(reg, val, bitnum) \
|
||||
REGISTER_FLD_WAIT(dev, reg, val, bitnum, bitnum)
|
||||
|
||||
#define MDFLD_DSI_BRIGHTNESS_MAX_LEVEL 100
|
||||
|
||||
#ifdef DEBUG
|
||||
#define CHECK_PIPE(pipe) ({ \
|
||||
const typeof(pipe) __pipe = (pipe); \
|
||||
BUG_ON(__pipe != 0 && __pipe != 2); \
|
||||
__pipe; })
|
||||
#else
|
||||
#define CHECK_PIPE(pipe) (pipe)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Actual MIPIA->MIPIC reg offset is 0x800, value 0x400 is valid for 0 and 2
|
||||
*/
|
||||
#define REG_OFFSET(pipe) (CHECK_PIPE(pipe) * 0x400)
|
||||
|
||||
/* mdfld DSI controller registers */
|
||||
#define MIPI_DEVICE_READY_REG(pipe) (0xb000 + REG_OFFSET(pipe))
|
||||
#define MIPI_INTR_STAT_REG(pipe) (0xb004 + REG_OFFSET(pipe))
|
||||
#define MIPI_INTR_EN_REG(pipe) (0xb008 + REG_OFFSET(pipe))
|
||||
#define MIPI_DSI_FUNC_PRG_REG(pipe) (0xb00c + REG_OFFSET(pipe))
|
||||
#define MIPI_HS_TX_TIMEOUT_REG(pipe) (0xb010 + REG_OFFSET(pipe))
|
||||
#define MIPI_LP_RX_TIMEOUT_REG(pipe) (0xb014 + REG_OFFSET(pipe))
|
||||
#define MIPI_TURN_AROUND_TIMEOUT_REG(pipe) (0xb018 + REG_OFFSET(pipe))
|
||||
#define MIPI_DEVICE_RESET_TIMER_REG(pipe) (0xb01c + REG_OFFSET(pipe))
|
||||
#define MIPI_DPI_RESOLUTION_REG(pipe) (0xb020 + REG_OFFSET(pipe))
|
||||
#define MIPI_DBI_FIFO_THROTTLE_REG(pipe) (0xb024 + REG_OFFSET(pipe))
|
||||
#define MIPI_HSYNC_COUNT_REG(pipe) (0xb028 + REG_OFFSET(pipe))
|
||||
#define MIPI_HBP_COUNT_REG(pipe) (0xb02c + REG_OFFSET(pipe))
|
||||
#define MIPI_HFP_COUNT_REG(pipe) (0xb030 + REG_OFFSET(pipe))
|
||||
#define MIPI_HACTIVE_COUNT_REG(pipe) (0xb034 + REG_OFFSET(pipe))
|
||||
#define MIPI_VSYNC_COUNT_REG(pipe) (0xb038 + REG_OFFSET(pipe))
|
||||
#define MIPI_VBP_COUNT_REG(pipe) (0xb03c + REG_OFFSET(pipe))
|
||||
#define MIPI_VFP_COUNT_REG(pipe) (0xb040 + REG_OFFSET(pipe))
|
||||
#define MIPI_HIGH_LOW_SWITCH_COUNT_REG(pipe) (0xb044 + REG_OFFSET(pipe))
|
||||
#define MIPI_DPI_CONTROL_REG(pipe) (0xb048 + REG_OFFSET(pipe))
|
||||
#define MIPI_DPI_DATA_REG(pipe) (0xb04c + REG_OFFSET(pipe))
|
||||
#define MIPI_INIT_COUNT_REG(pipe) (0xb050 + REG_OFFSET(pipe))
|
||||
#define MIPI_MAX_RETURN_PACK_SIZE_REG(pipe) (0xb054 + REG_OFFSET(pipe))
|
||||
#define MIPI_VIDEO_MODE_FORMAT_REG(pipe) (0xb058 + REG_OFFSET(pipe))
|
||||
#define MIPI_EOT_DISABLE_REG(pipe) (0xb05c + REG_OFFSET(pipe))
|
||||
#define MIPI_LP_BYTECLK_REG(pipe) (0xb060 + REG_OFFSET(pipe))
|
||||
#define MIPI_LP_GEN_DATA_REG(pipe) (0xb064 + REG_OFFSET(pipe))
|
||||
#define MIPI_HS_GEN_DATA_REG(pipe) (0xb068 + REG_OFFSET(pipe))
|
||||
#define MIPI_LP_GEN_CTRL_REG(pipe) (0xb06c + REG_OFFSET(pipe))
|
||||
#define MIPI_HS_GEN_CTRL_REG(pipe) (0xb070 + REG_OFFSET(pipe))
|
||||
#define MIPI_GEN_FIFO_STAT_REG(pipe) (0xb074 + REG_OFFSET(pipe))
|
||||
#define MIPI_HS_LS_DBI_ENABLE_REG(pipe) (0xb078 + REG_OFFSET(pipe))
|
||||
#define MIPI_DPHY_PARAM_REG(pipe) (0xb080 + REG_OFFSET(pipe))
|
||||
#define MIPI_DBI_BW_CTRL_REG(pipe) (0xb084 + REG_OFFSET(pipe))
|
||||
#define MIPI_CLK_LANE_SWITCH_TIME_CNT_REG(pipe) (0xb088 + REG_OFFSET(pipe))
|
||||
|
||||
#define MIPI_CTRL_REG(pipe) (0xb104 + REG_OFFSET(pipe))
|
||||
#define MIPI_DATA_ADD_REG(pipe) (0xb108 + REG_OFFSET(pipe))
|
||||
#define MIPI_DATA_LEN_REG(pipe) (0xb10c + REG_OFFSET(pipe))
|
||||
#define MIPI_CMD_ADD_REG(pipe) (0xb110 + REG_OFFSET(pipe))
|
||||
#define MIPI_CMD_LEN_REG(pipe) (0xb114 + REG_OFFSET(pipe))
|
||||
|
||||
/* non-uniform reg offset */
|
||||
#define MIPI_PORT_CONTROL(pipe) (CHECK_PIPE(pipe) ? MIPI_C : MIPI)
|
||||
|
||||
#define DSI_DEVICE_READY (0x1)
|
||||
#define DSI_POWER_STATE_ULPS_ENTER (0x2 << 1)
|
||||
#define DSI_POWER_STATE_ULPS_EXIT (0x1 << 1)
|
||||
#define DSI_POWER_STATE_ULPS_OFFSET (0x1)
|
||||
|
||||
|
||||
#define DSI_ONE_DATA_LANE (0x1)
|
||||
#define DSI_TWO_DATA_LANE (0x2)
|
||||
#define DSI_THREE_DATA_LANE (0X3)
|
||||
#define DSI_FOUR_DATA_LANE (0x4)
|
||||
#define DSI_DPI_VIRT_CHANNEL_OFFSET (0x3)
|
||||
#define DSI_DBI_VIRT_CHANNEL_OFFSET (0x5)
|
||||
#define DSI_DPI_COLOR_FORMAT_RGB565 (0x01 << 7)
|
||||
#define DSI_DPI_COLOR_FORMAT_RGB666 (0x02 << 7)
|
||||
#define DSI_DPI_COLOR_FORMAT_RGB666_UNPACK (0x03 << 7)
|
||||
#define DSI_DPI_COLOR_FORMAT_RGB888 (0x04 << 7)
|
||||
#define DSI_DBI_COLOR_FORMAT_OPTION2 (0x05 << 13)
|
||||
|
||||
#define DSI_INTR_STATE_RXSOTERROR BIT(0)
|
||||
|
||||
#define DSI_INTR_STATE_SPL_PKG_SENT BIT(30)
|
||||
#define DSI_INTR_STATE_TE BIT(31)
|
||||
|
||||
#define DSI_HS_TX_TIMEOUT_MASK (0xffffff)
|
||||
|
||||
#define DSI_LP_RX_TIMEOUT_MASK (0xffffff)
|
||||
|
||||
#define DSI_TURN_AROUND_TIMEOUT_MASK (0x3f)
|
||||
|
||||
#define DSI_RESET_TIMER_MASK (0xffff)
|
||||
|
||||
#define DSI_DBI_FIFO_WM_HALF (0x0)
|
||||
#define DSI_DBI_FIFO_WM_QUARTER (0x1)
|
||||
#define DSI_DBI_FIFO_WM_LOW (0x2)
|
||||
|
||||
#define DSI_DPI_TIMING_MASK (0xffff)
|
||||
|
||||
#define DSI_INIT_TIMER_MASK (0xffff)
|
||||
|
||||
#define DSI_DBI_RETURN_PACK_SIZE_MASK (0x3ff)
|
||||
|
||||
#define DSI_LP_BYTECLK_MASK (0x0ffff)
|
||||
|
||||
#define DSI_HS_CTRL_GEN_SHORT_W0 (0x03)
|
||||
#define DSI_HS_CTRL_GEN_SHORT_W1 (0x13)
|
||||
#define DSI_HS_CTRL_GEN_SHORT_W2 (0x23)
|
||||
#define DSI_HS_CTRL_GEN_R0 (0x04)
|
||||
#define DSI_HS_CTRL_GEN_R1 (0x14)
|
||||
#define DSI_HS_CTRL_GEN_R2 (0x24)
|
||||
#define DSI_HS_CTRL_GEN_LONG_W (0x29)
|
||||
#define DSI_HS_CTRL_MCS_SHORT_W0 (0x05)
|
||||
#define DSI_HS_CTRL_MCS_SHORT_W1 (0x15)
|
||||
#define DSI_HS_CTRL_MCS_R0 (0x06)
|
||||
#define DSI_HS_CTRL_MCS_LONG_W (0x39)
|
||||
#define DSI_HS_CTRL_VC_OFFSET (0x06)
|
||||
#define DSI_HS_CTRL_WC_OFFSET (0x08)
|
||||
|
||||
#define DSI_FIFO_GEN_HS_DATA_FULL BIT(0)
|
||||
#define DSI_FIFO_GEN_HS_DATA_HALF_EMPTY BIT(1)
|
||||
#define DSI_FIFO_GEN_HS_DATA_EMPTY BIT(2)
|
||||
#define DSI_FIFO_GEN_LP_DATA_FULL BIT(8)
|
||||
#define DSI_FIFO_GEN_LP_DATA_HALF_EMPTY BIT(9)
|
||||
#define DSI_FIFO_GEN_LP_DATA_EMPTY BIT(10)
|
||||
#define DSI_FIFO_GEN_HS_CTRL_FULL BIT(16)
|
||||
#define DSI_FIFO_GEN_HS_CTRL_HALF_EMPTY BIT(17)
|
||||
#define DSI_FIFO_GEN_HS_CTRL_EMPTY BIT(18)
|
||||
#define DSI_FIFO_GEN_LP_CTRL_FULL BIT(24)
|
||||
#define DSI_FIFO_GEN_LP_CTRL_HALF_EMPTY BIT(25)
|
||||
#define DSI_FIFO_GEN_LP_CTRL_EMPTY BIT(26)
|
||||
#define DSI_FIFO_DBI_EMPTY BIT(27)
|
||||
#define DSI_FIFO_DPI_EMPTY BIT(28)
|
||||
|
||||
#define DSI_DBI_HS_LP_SWITCH_MASK (0x1)
|
||||
|
||||
#define DSI_HS_LP_SWITCH_COUNTER_OFFSET (0x0)
|
||||
#define DSI_LP_HS_SWITCH_COUNTER_OFFSET (0x16)
|
||||
|
||||
#define DSI_DPI_CTRL_HS_SHUTDOWN (0x00000001)
|
||||
#define DSI_DPI_CTRL_HS_TURN_ON (0x00000002)
|
||||
|
||||
/*dsi power modes*/
|
||||
#define DSI_POWER_MODE_DISPLAY_ON BIT(2)
|
||||
#define DSI_POWER_MODE_NORMAL_ON BIT(3)
|
||||
#define DSI_POWER_MODE_SLEEP_OUT BIT(4)
|
||||
#define DSI_POWER_MODE_PARTIAL_ON BIT(5)
|
||||
#define DSI_POWER_MODE_IDLE_ON BIT(6)
|
||||
|
||||
enum {
|
||||
MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE = 1,
|
||||
MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS = 2,
|
||||
MDFLD_DSI_VIDEO_BURST_MODE = 3,
|
||||
};
|
||||
|
||||
#define DSI_DPI_COMPLETE_LAST_LINE BIT(2)
|
||||
#define DSI_DPI_DISABLE_BTA BIT(3)
|
||||
|
||||
struct mdfld_dsi_connector {
|
||||
struct psb_intel_connector base;
|
||||
|
||||
int pipe;
|
||||
void *private;
|
||||
void *pkg_sender;
|
||||
|
||||
/* Connection status */
|
||||
enum drm_connector_status status;
|
||||
};
|
||||
|
||||
struct mdfld_dsi_encoder {
|
||||
struct psb_intel_encoder base;
|
||||
void *private;
|
||||
};
|
||||
|
||||
/*
|
||||
* DSI config, consists of one DSI connector, two DSI encoders.
|
||||
* DRM will pick up on DSI encoder basing on differents configs.
|
||||
*/
|
||||
struct mdfld_dsi_config {
|
||||
struct drm_device *dev;
|
||||
struct drm_display_mode *fixed_mode;
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
struct mdfld_dsi_connector *connector;
|
||||
struct mdfld_dsi_encoder *encoder;
|
||||
|
||||
int changed;
|
||||
|
||||
int bpp;
|
||||
int lane_count;
|
||||
/*Virtual channel number for this encoder*/
|
||||
int channel_num;
|
||||
/*video mode configure*/
|
||||
int video_mode;
|
||||
|
||||
int dvr_ic_inited;
|
||||
};
|
||||
|
||||
static inline struct mdfld_dsi_connector *mdfld_dsi_connector(
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct psb_intel_connector *psb_connector;
|
||||
|
||||
psb_connector = to_psb_intel_connector(connector);
|
||||
|
||||
return container_of(psb_connector, struct mdfld_dsi_connector, base);
|
||||
}
|
||||
|
||||
static inline struct mdfld_dsi_encoder *mdfld_dsi_encoder(
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
struct psb_intel_encoder *psb_encoder;
|
||||
|
||||
psb_encoder = to_psb_intel_encoder(encoder);
|
||||
|
||||
return container_of(psb_encoder, struct mdfld_dsi_encoder, base);
|
||||
}
|
||||
|
||||
static inline struct mdfld_dsi_config *
|
||||
mdfld_dsi_get_config(struct mdfld_dsi_connector *connector)
|
||||
{
|
||||
if (!connector)
|
||||
return NULL;
|
||||
return (struct mdfld_dsi_config *)connector->private;
|
||||
}
|
||||
|
||||
static inline void *mdfld_dsi_get_pkg_sender(struct mdfld_dsi_config *config)
|
||||
{
|
||||
struct mdfld_dsi_connector *dsi_connector;
|
||||
|
||||
if (!config)
|
||||
return NULL;
|
||||
|
||||
dsi_connector = config->connector;
|
||||
|
||||
if (!dsi_connector)
|
||||
return NULL;
|
||||
|
||||
return dsi_connector->pkg_sender;
|
||||
}
|
||||
|
||||
static inline struct mdfld_dsi_config *
|
||||
mdfld_dsi_encoder_get_config(struct mdfld_dsi_encoder *encoder)
|
||||
{
|
||||
if (!encoder)
|
||||
return NULL;
|
||||
return (struct mdfld_dsi_config *)encoder->private;
|
||||
}
|
||||
|
||||
static inline struct mdfld_dsi_connector *
|
||||
mdfld_dsi_encoder_get_connector(struct mdfld_dsi_encoder *encoder)
|
||||
{
|
||||
struct mdfld_dsi_config *config;
|
||||
|
||||
if (!encoder)
|
||||
return NULL;
|
||||
|
||||
config = mdfld_dsi_encoder_get_config(encoder);
|
||||
if (!config)
|
||||
return NULL;
|
||||
|
||||
return config->connector;
|
||||
}
|
||||
|
||||
static inline void *mdfld_dsi_encoder_get_pkg_sender(
|
||||
struct mdfld_dsi_encoder *encoder)
|
||||
{
|
||||
struct mdfld_dsi_config *dsi_config;
|
||||
|
||||
dsi_config = mdfld_dsi_encoder_get_config(encoder);
|
||||
if (!dsi_config)
|
||||
return NULL;
|
||||
|
||||
return mdfld_dsi_get_pkg_sender(dsi_config);
|
||||
}
|
||||
|
||||
static inline int mdfld_dsi_encoder_get_pipe(struct mdfld_dsi_encoder *encoder)
|
||||
{
|
||||
struct mdfld_dsi_connector *connector;
|
||||
|
||||
if (!encoder)
|
||||
return -1;
|
||||
|
||||
connector = mdfld_dsi_encoder_get_connector(encoder);
|
||||
if (!connector)
|
||||
return -1;
|
||||
return connector->pipe;
|
||||
}
|
||||
|
||||
/* Export functions */
|
||||
extern void mdfld_dsi_gen_fifo_ready(struct drm_device *dev,
|
||||
u32 gen_fifo_stat_reg, u32 fifo_stat);
|
||||
extern void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config,
|
||||
int pipe);
|
||||
extern void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe,
|
||||
int level);
|
||||
extern void mdfld_dsi_output_init(struct drm_device *dev,
|
||||
int pipe,
|
||||
const struct panel_funcs *p_vid_funcs);
|
||||
extern void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config,
|
||||
int pipe);
|
||||
|
||||
extern int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config,
|
||||
u32 *mode, bool hs);
|
||||
extern int mdfld_dsi_panel_reset(int pipe);
|
||||
|
||||
#endif /*__MDFLD_DSI_OUTPUT_H__*/
|
|
@ -0,0 +1,694 @@
|
|||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Jackie Li<yaodong.li@intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/freezer.h>
|
||||
|
||||
#include "mdfld_dsi_output.h"
|
||||
#include "mdfld_dsi_pkg_sender.h"
|
||||
#include "mdfld_dsi_dpi.h"
|
||||
|
||||
#define MDFLD_DSI_READ_MAX_COUNT 5000
|
||||
|
||||
enum data_type {
|
||||
DSI_DT_GENERIC_SHORT_WRITE_0 = 0x03,
|
||||
DSI_DT_GENERIC_SHORT_WRITE_1 = 0x13,
|
||||
DSI_DT_GENERIC_SHORT_WRITE_2 = 0x23,
|
||||
DSI_DT_GENERIC_READ_0 = 0x04,
|
||||
DSI_DT_GENERIC_READ_1 = 0x14,
|
||||
DSI_DT_GENERIC_READ_2 = 0x24,
|
||||
DSI_DT_GENERIC_LONG_WRITE = 0x29,
|
||||
DSI_DT_DCS_SHORT_WRITE_0 = 0x05,
|
||||
DSI_DT_DCS_SHORT_WRITE_1 = 0x15,
|
||||
DSI_DT_DCS_READ = 0x06,
|
||||
DSI_DT_DCS_LONG_WRITE = 0x39,
|
||||
};
|
||||
|
||||
enum {
|
||||
MDFLD_DSI_PANEL_MODE_SLEEP = 0x1,
|
||||
};
|
||||
|
||||
enum {
|
||||
MDFLD_DSI_PKG_SENDER_FREE = 0x0,
|
||||
MDFLD_DSI_PKG_SENDER_BUSY = 0x1,
|
||||
};
|
||||
|
||||
static const char *const dsi_errors[] = {
|
||||
"RX SOT Error",
|
||||
"RX SOT Sync Error",
|
||||
"RX EOT Sync Error",
|
||||
"RX Escape Mode Entry Error",
|
||||
"RX LP TX Sync Error",
|
||||
"RX HS Receive Timeout Error",
|
||||
"RX False Control Error",
|
||||
"RX ECC Single Bit Error",
|
||||
"RX ECC Multibit Error",
|
||||
"RX Checksum Error",
|
||||
"RX DSI Data Type Not Recognised",
|
||||
"RX DSI VC ID Invalid",
|
||||
"TX False Control Error",
|
||||
"TX ECC Single Bit Error",
|
||||
"TX ECC Multibit Error",
|
||||
"TX Checksum Error",
|
||||
"TX DSI Data Type Not Recognised",
|
||||
"TX DSI VC ID invalid",
|
||||
"High Contention",
|
||||
"Low contention",
|
||||
"DPI FIFO Under run",
|
||||
"HS TX Timeout",
|
||||
"LP RX Timeout",
|
||||
"Turn Around ACK Timeout",
|
||||
"ACK With No Error",
|
||||
"RX Invalid TX Length",
|
||||
"RX Prot Violation",
|
||||
"HS Generic Write FIFO Full",
|
||||
"LP Generic Write FIFO Full",
|
||||
"Generic Read Data Avail"
|
||||
"Special Packet Sent",
|
||||
"Tearing Effect",
|
||||
};
|
||||
|
||||
static inline int wait_for_gen_fifo_empty(struct mdfld_dsi_pkg_sender *sender,
|
||||
u32 mask)
|
||||
{
|
||||
struct drm_device *dev = sender->dev;
|
||||
u32 gen_fifo_stat_reg = sender->mipi_gen_fifo_stat_reg;
|
||||
int retry = 0xffff;
|
||||
|
||||
while (retry--) {
|
||||
if ((mask & REG_READ(gen_fifo_stat_reg)) == mask)
|
||||
return 0;
|
||||
udelay(100);
|
||||
}
|
||||
DRM_ERROR("fifo is NOT empty 0x%08x\n", REG_READ(gen_fifo_stat_reg));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int wait_for_all_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
|
||||
{
|
||||
return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(10) | BIT(18) |
|
||||
BIT(26) | BIT(27) | BIT(28)));
|
||||
}
|
||||
|
||||
static int wait_for_lp_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
|
||||
{
|
||||
return wait_for_gen_fifo_empty(sender, (BIT(10) | BIT(26)));
|
||||
}
|
||||
|
||||
static int wait_for_hs_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
|
||||
{
|
||||
return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(18)));
|
||||
}
|
||||
|
||||
static int handle_dsi_error(struct mdfld_dsi_pkg_sender *sender, u32 mask)
|
||||
{
|
||||
u32 intr_stat_reg = sender->mipi_intr_stat_reg;
|
||||
struct drm_device *dev = sender->dev;
|
||||
|
||||
dev_dbg(sender->dev->dev, "Handling error 0x%08x\n", mask);
|
||||
|
||||
switch (mask) {
|
||||
case BIT(0):
|
||||
case BIT(1):
|
||||
case BIT(2):
|
||||
case BIT(3):
|
||||
case BIT(4):
|
||||
case BIT(5):
|
||||
case BIT(6):
|
||||
case BIT(7):
|
||||
case BIT(8):
|
||||
case BIT(9):
|
||||
case BIT(10):
|
||||
case BIT(11):
|
||||
case BIT(12):
|
||||
case BIT(13):
|
||||
dev_dbg(sender->dev->dev, "No Action required\n");
|
||||
break;
|
||||
case BIT(14):
|
||||
/*wait for all fifo empty*/
|
||||
/*wait_for_all_fifos_empty(sender)*/;
|
||||
break;
|
||||
case BIT(15):
|
||||
dev_dbg(sender->dev->dev, "No Action required\n");
|
||||
break;
|
||||
case BIT(16):
|
||||
break;
|
||||
case BIT(17):
|
||||
break;
|
||||
case BIT(18):
|
||||
case BIT(19):
|
||||
dev_dbg(sender->dev->dev, "High/Low contention detected\n");
|
||||
/*wait for contention recovery time*/
|
||||
/*mdelay(10);*/
|
||||
/*wait for all fifo empty*/
|
||||
if (0)
|
||||
wait_for_all_fifos_empty(sender);
|
||||
break;
|
||||
case BIT(20):
|
||||
dev_dbg(sender->dev->dev, "No Action required\n");
|
||||
break;
|
||||
case BIT(21):
|
||||
/*wait for all fifo empty*/
|
||||
/*wait_for_all_fifos_empty(sender);*/
|
||||
break;
|
||||
case BIT(22):
|
||||
break;
|
||||
case BIT(23):
|
||||
case BIT(24):
|
||||
case BIT(25):
|
||||
case BIT(26):
|
||||
case BIT(27):
|
||||
dev_dbg(sender->dev->dev, "HS Gen fifo full\n");
|
||||
REG_WRITE(intr_stat_reg, mask);
|
||||
wait_for_hs_fifos_empty(sender);
|
||||
break;
|
||||
case BIT(28):
|
||||
dev_dbg(sender->dev->dev, "LP Gen fifo full\n");
|
||||
REG_WRITE(intr_stat_reg, mask);
|
||||
wait_for_lp_fifos_empty(sender);
|
||||
break;
|
||||
case BIT(29):
|
||||
case BIT(30):
|
||||
case BIT(31):
|
||||
dev_dbg(sender->dev->dev, "No Action required\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (mask & REG_READ(intr_stat_reg))
|
||||
dev_dbg(sender->dev->dev,
|
||||
"Cannot clean interrupt 0x%08x\n", mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsi_error_handler(struct mdfld_dsi_pkg_sender *sender)
|
||||
{
|
||||
struct drm_device *dev = sender->dev;
|
||||
u32 intr_stat_reg = sender->mipi_intr_stat_reg;
|
||||
u32 mask;
|
||||
u32 intr_stat;
|
||||
int i;
|
||||
int err = 0;
|
||||
|
||||
intr_stat = REG_READ(intr_stat_reg);
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
mask = (0x00000001UL) << i;
|
||||
if (intr_stat & mask) {
|
||||
dev_dbg(sender->dev->dev, "[DSI]: %s\n", dsi_errors[i]);
|
||||
err = handle_dsi_error(sender, mask);
|
||||
if (err)
|
||||
DRM_ERROR("Cannot handle error\n");
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int send_short_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
|
||||
u8 cmd, u8 param, bool hs)
|
||||
{
|
||||
struct drm_device *dev = sender->dev;
|
||||
u32 ctrl_reg;
|
||||
u32 val;
|
||||
u8 virtual_channel = 0;
|
||||
|
||||
if (hs) {
|
||||
ctrl_reg = sender->mipi_hs_gen_ctrl_reg;
|
||||
|
||||
/* FIXME: wait_for_hs_fifos_empty(sender); */
|
||||
} else {
|
||||
ctrl_reg = sender->mipi_lp_gen_ctrl_reg;
|
||||
|
||||
/* FIXME: wait_for_lp_fifos_empty(sender); */
|
||||
}
|
||||
|
||||
val = FLD_VAL(param, 23, 16) | FLD_VAL(cmd, 15, 8) |
|
||||
FLD_VAL(virtual_channel, 7, 6) | FLD_VAL(data_type, 5, 0);
|
||||
|
||||
REG_WRITE(ctrl_reg, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_long_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
|
||||
u8 *data, int len, bool hs)
|
||||
{
|
||||
struct drm_device *dev = sender->dev;
|
||||
u32 ctrl_reg;
|
||||
u32 data_reg;
|
||||
u32 val;
|
||||
u8 *p;
|
||||
u8 b1, b2, b3, b4;
|
||||
u8 virtual_channel = 0;
|
||||
int i;
|
||||
|
||||
if (hs) {
|
||||
ctrl_reg = sender->mipi_hs_gen_ctrl_reg;
|
||||
data_reg = sender->mipi_hs_gen_data_reg;
|
||||
|
||||
/* FIXME: wait_for_hs_fifos_empty(sender); */
|
||||
} else {
|
||||
ctrl_reg = sender->mipi_lp_gen_ctrl_reg;
|
||||
data_reg = sender->mipi_lp_gen_data_reg;
|
||||
|
||||
/* FIXME: wait_for_lp_fifos_empty(sender); */
|
||||
}
|
||||
|
||||
p = data;
|
||||
for (i = 0; i < len / 4; i++) {
|
||||
b1 = *p++;
|
||||
b2 = *p++;
|
||||
b3 = *p++;
|
||||
b4 = *p++;
|
||||
|
||||
REG_WRITE(data_reg, b4 << 24 | b3 << 16 | b2 << 8 | b1);
|
||||
}
|
||||
|
||||
i = len % 4;
|
||||
if (i) {
|
||||
b1 = 0; b2 = 0; b3 = 0;
|
||||
|
||||
switch (i) {
|
||||
case 3:
|
||||
b1 = *p++;
|
||||
b2 = *p++;
|
||||
b3 = *p++;
|
||||
break;
|
||||
case 2:
|
||||
b1 = *p++;
|
||||
b2 = *p++;
|
||||
break;
|
||||
case 1:
|
||||
b1 = *p++;
|
||||
break;
|
||||
}
|
||||
|
||||
REG_WRITE(data_reg, b3 << 16 | b2 << 8 | b1);
|
||||
}
|
||||
|
||||
val = FLD_VAL(len, 23, 8) | FLD_VAL(virtual_channel, 7, 6) |
|
||||
FLD_VAL(data_type, 5, 0);
|
||||
|
||||
REG_WRITE(ctrl_reg, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_pkg_prepare(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
|
||||
u8 *data, u16 len)
|
||||
{
|
||||
u8 cmd;
|
||||
|
||||
switch (data_type) {
|
||||
case DSI_DT_DCS_SHORT_WRITE_0:
|
||||
case DSI_DT_DCS_SHORT_WRITE_1:
|
||||
case DSI_DT_DCS_LONG_WRITE:
|
||||
cmd = *data;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*this prevents other package sending while doing msleep*/
|
||||
sender->status = MDFLD_DSI_PKG_SENDER_BUSY;
|
||||
|
||||
/*wait for 120 milliseconds in case exit_sleep_mode just be sent*/
|
||||
if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) {
|
||||
/*TODO: replace it with msleep later*/
|
||||
mdelay(120);
|
||||
}
|
||||
|
||||
if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) {
|
||||
/*TODO: replace it with msleep later*/
|
||||
mdelay(120);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_pkg_done(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
|
||||
u8 *data, u16 len)
|
||||
{
|
||||
u8 cmd;
|
||||
|
||||
switch (data_type) {
|
||||
case DSI_DT_DCS_SHORT_WRITE_0:
|
||||
case DSI_DT_DCS_SHORT_WRITE_1:
|
||||
case DSI_DT_DCS_LONG_WRITE:
|
||||
cmd = *data;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*update panel status*/
|
||||
if (unlikely(cmd == DCS_ENTER_SLEEP_MODE)) {
|
||||
sender->panel_mode |= MDFLD_DSI_PANEL_MODE_SLEEP;
|
||||
/*TODO: replace it with msleep later*/
|
||||
mdelay(120);
|
||||
} else if (unlikely(cmd == DCS_EXIT_SLEEP_MODE)) {
|
||||
sender->panel_mode &= ~MDFLD_DSI_PANEL_MODE_SLEEP;
|
||||
/*TODO: replace it with msleep later*/
|
||||
mdelay(120);
|
||||
} else if (unlikely(cmd == DCS_SOFT_RESET)) {
|
||||
/*TODO: replace it with msleep later*/
|
||||
mdelay(5);
|
||||
}
|
||||
|
||||
sender->status = MDFLD_DSI_PKG_SENDER_FREE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
|
||||
u8 *data, u16 len, bool hs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*handle DSI error*/
|
||||
ret = dsi_error_handler(sender);
|
||||
if (ret) {
|
||||
DRM_ERROR("Error handling failed\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* send pkg */
|
||||
if (sender->status == MDFLD_DSI_PKG_SENDER_BUSY) {
|
||||
DRM_ERROR("sender is busy\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
ret = send_pkg_prepare(sender, data_type, data, len);
|
||||
if (ret) {
|
||||
DRM_ERROR("send_pkg_prepare error\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (data_type) {
|
||||
case DSI_DT_GENERIC_SHORT_WRITE_0:
|
||||
case DSI_DT_GENERIC_SHORT_WRITE_1:
|
||||
case DSI_DT_GENERIC_SHORT_WRITE_2:
|
||||
case DSI_DT_GENERIC_READ_0:
|
||||
case DSI_DT_GENERIC_READ_1:
|
||||
case DSI_DT_GENERIC_READ_2:
|
||||
case DSI_DT_DCS_SHORT_WRITE_0:
|
||||
case DSI_DT_DCS_SHORT_WRITE_1:
|
||||
case DSI_DT_DCS_READ:
|
||||
ret = send_short_pkg(sender, data_type, data[0], data[1], hs);
|
||||
break;
|
||||
case DSI_DT_GENERIC_LONG_WRITE:
|
||||
case DSI_DT_DCS_LONG_WRITE:
|
||||
ret = send_long_pkg(sender, data_type, data, len, hs);
|
||||
break;
|
||||
}
|
||||
|
||||
send_pkg_done(sender, data_type, data, len);
|
||||
|
||||
/*FIXME: should I query complete and fifo empty here?*/
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
|
||||
u32 len, bool hs)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!sender || !data || !len) {
|
||||
DRM_ERROR("Invalid parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sender->lock, flags);
|
||||
send_pkg(sender, DSI_DT_DCS_LONG_WRITE, data, len, hs);
|
||||
spin_unlock_irqrestore(&sender->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
|
||||
u8 param, u8 param_num, bool hs)
|
||||
{
|
||||
u8 data[2];
|
||||
unsigned long flags;
|
||||
u8 data_type;
|
||||
|
||||
if (!sender) {
|
||||
DRM_ERROR("Invalid parameter\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data[0] = cmd;
|
||||
|
||||
if (param_num) {
|
||||
data_type = DSI_DT_DCS_SHORT_WRITE_1;
|
||||
data[1] = param;
|
||||
} else {
|
||||
data_type = DSI_DT_DCS_SHORT_WRITE_0;
|
||||
data[1] = 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sender->lock, flags);
|
||||
send_pkg(sender, data_type, data, sizeof(data), hs);
|
||||
spin_unlock_irqrestore(&sender->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0,
|
||||
u8 param1, u8 param_num, bool hs)
|
||||
{
|
||||
u8 data[2];
|
||||
unsigned long flags;
|
||||
u8 data_type;
|
||||
|
||||
if (!sender || param_num > 2) {
|
||||
DRM_ERROR("Invalid parameter\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (param_num) {
|
||||
case 0:
|
||||
data_type = DSI_DT_GENERIC_SHORT_WRITE_0;
|
||||
data[0] = 0;
|
||||
data[1] = 0;
|
||||
break;
|
||||
case 1:
|
||||
data_type = DSI_DT_GENERIC_SHORT_WRITE_1;
|
||||
data[0] = param0;
|
||||
data[1] = 0;
|
||||
break;
|
||||
case 2:
|
||||
data_type = DSI_DT_GENERIC_SHORT_WRITE_2;
|
||||
data[0] = param0;
|
||||
data[1] = param1;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sender->lock, flags);
|
||||
send_pkg(sender, data_type, data, sizeof(data), hs);
|
||||
spin_unlock_irqrestore(&sender->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
|
||||
u32 len, bool hs)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!sender || !data || !len) {
|
||||
DRM_ERROR("Invalid parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sender->lock, flags);
|
||||
send_pkg(sender, DSI_DT_GENERIC_LONG_WRITE, data, len, hs);
|
||||
spin_unlock_irqrestore(&sender->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __read_panel_data(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
|
||||
u8 *data, u16 len, u32 *data_out, u16 len_out, bool hs)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct drm_device *dev = sender->dev;
|
||||
int i;
|
||||
u32 gen_data_reg;
|
||||
int retry = MDFLD_DSI_READ_MAX_COUNT;
|
||||
|
||||
if (!sender || !data_out || !len_out) {
|
||||
DRM_ERROR("Invalid parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* do reading.
|
||||
* 0) send out generic read request
|
||||
* 1) polling read data avail interrupt
|
||||
* 2) read data
|
||||
*/
|
||||
spin_lock_irqsave(&sender->lock, flags);
|
||||
|
||||
REG_WRITE(sender->mipi_intr_stat_reg, BIT(29));
|
||||
|
||||
if ((REG_READ(sender->mipi_intr_stat_reg) & BIT(29)))
|
||||
DRM_ERROR("Can NOT clean read data valid interrupt\n");
|
||||
|
||||
/*send out read request*/
|
||||
send_pkg(sender, data_type, data, len, hs);
|
||||
|
||||
/*polling read data avail interrupt*/
|
||||
while (retry && !(REG_READ(sender->mipi_intr_stat_reg) & BIT(29))) {
|
||||
udelay(100);
|
||||
retry--;
|
||||
}
|
||||
|
||||
if (!retry) {
|
||||
spin_unlock_irqrestore(&sender->lock, flags);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
REG_WRITE(sender->mipi_intr_stat_reg, BIT(29));
|
||||
|
||||
/*read data*/
|
||||
if (hs)
|
||||
gen_data_reg = sender->mipi_hs_gen_data_reg;
|
||||
else
|
||||
gen_data_reg = sender->mipi_lp_gen_data_reg;
|
||||
|
||||
for (i = 0; i < len_out; i++)
|
||||
*(data_out + i) = REG_READ(gen_data_reg);
|
||||
|
||||
spin_unlock_irqrestore(&sender->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
|
||||
u32 *data, u16 len, bool hs)
|
||||
{
|
||||
if (!sender || !data || !len) {
|
||||
DRM_ERROR("Invalid parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return __read_panel_data(sender, DSI_DT_DCS_READ, &cmd, 1,
|
||||
data, len, hs);
|
||||
}
|
||||
|
||||
int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector,
|
||||
int pipe)
|
||||
{
|
||||
struct mdfld_dsi_pkg_sender *pkg_sender;
|
||||
struct mdfld_dsi_config *dsi_config =
|
||||
mdfld_dsi_get_config(dsi_connector);
|
||||
struct drm_device *dev = dsi_config->dev;
|
||||
u32 mipi_val = 0;
|
||||
|
||||
if (!dsi_connector) {
|
||||
DRM_ERROR("Invalid parameter\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pkg_sender = dsi_connector->pkg_sender;
|
||||
|
||||
if (!pkg_sender || IS_ERR(pkg_sender)) {
|
||||
pkg_sender = kzalloc(sizeof(struct mdfld_dsi_pkg_sender),
|
||||
GFP_KERNEL);
|
||||
if (!pkg_sender) {
|
||||
DRM_ERROR("Create DSI pkg sender failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
dsi_connector->pkg_sender = (void *)pkg_sender;
|
||||
}
|
||||
|
||||
pkg_sender->dev = dev;
|
||||
pkg_sender->dsi_connector = dsi_connector;
|
||||
pkg_sender->pipe = pipe;
|
||||
pkg_sender->pkg_num = 0;
|
||||
pkg_sender->panel_mode = 0;
|
||||
pkg_sender->status = MDFLD_DSI_PKG_SENDER_FREE;
|
||||
|
||||
/*init regs*/
|
||||
if (pipe == 0) {
|
||||
pkg_sender->dpll_reg = MRST_DPLL_A;
|
||||
pkg_sender->dspcntr_reg = DSPACNTR;
|
||||
pkg_sender->pipeconf_reg = PIPEACONF;
|
||||
pkg_sender->dsplinoff_reg = DSPALINOFF;
|
||||
pkg_sender->dspsurf_reg = DSPASURF;
|
||||
pkg_sender->pipestat_reg = PIPEASTAT;
|
||||
} else if (pipe == 2) {
|
||||
pkg_sender->dpll_reg = MRST_DPLL_A;
|
||||
pkg_sender->dspcntr_reg = DSPCCNTR;
|
||||
pkg_sender->pipeconf_reg = PIPECCONF;
|
||||
pkg_sender->dsplinoff_reg = DSPCLINOFF;
|
||||
pkg_sender->dspsurf_reg = DSPCSURF;
|
||||
pkg_sender->pipestat_reg = PIPECSTAT;
|
||||
}
|
||||
|
||||
pkg_sender->mipi_intr_stat_reg = MIPI_INTR_STAT_REG(pipe);
|
||||
pkg_sender->mipi_lp_gen_data_reg = MIPI_LP_GEN_DATA_REG(pipe);
|
||||
pkg_sender->mipi_hs_gen_data_reg = MIPI_HS_GEN_DATA_REG(pipe);
|
||||
pkg_sender->mipi_lp_gen_ctrl_reg = MIPI_LP_GEN_CTRL_REG(pipe);
|
||||
pkg_sender->mipi_hs_gen_ctrl_reg = MIPI_HS_GEN_CTRL_REG(pipe);
|
||||
pkg_sender->mipi_gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe);
|
||||
pkg_sender->mipi_data_addr_reg = MIPI_DATA_ADD_REG(pipe);
|
||||
pkg_sender->mipi_data_len_reg = MIPI_DATA_LEN_REG(pipe);
|
||||
pkg_sender->mipi_cmd_addr_reg = MIPI_CMD_ADD_REG(pipe);
|
||||
pkg_sender->mipi_cmd_len_reg = MIPI_CMD_LEN_REG(pipe);
|
||||
|
||||
/*init lock*/
|
||||
spin_lock_init(&pkg_sender->lock);
|
||||
|
||||
if (mdfld_get_panel_type(dev, pipe) != TC35876X) {
|
||||
/**
|
||||
* For video mode, don't enable DPI timing output here,
|
||||
* will init the DPI timing output during mode setting.
|
||||
*/
|
||||
mipi_val = PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX;
|
||||
|
||||
if (pipe == 0)
|
||||
mipi_val |= 0x2;
|
||||
|
||||
REG_WRITE(MIPI_PORT_CONTROL(pipe), mipi_val);
|
||||
REG_READ(MIPI_PORT_CONTROL(pipe));
|
||||
|
||||
/* do dsi controller init */
|
||||
mdfld_dsi_controller_init(dsi_config, pipe);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender)
|
||||
{
|
||||
if (!sender || IS_ERR(sender))
|
||||
return;
|
||||
|
||||
/*free*/
|
||||
kfree(sender);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Jackie Li<yaodong.li@intel.com>
|
||||
*/
|
||||
#ifndef __MDFLD_DSI_PKG_SENDER_H__
|
||||
#define __MDFLD_DSI_PKG_SENDER_H__
|
||||
|
||||
#include <linux/kthread.h>
|
||||
|
||||
#define MDFLD_MAX_DCS_PARAM 8
|
||||
|
||||
struct mdfld_dsi_pkg_sender {
|
||||
struct drm_device *dev;
|
||||
struct mdfld_dsi_connector *dsi_connector;
|
||||
u32 status;
|
||||
u32 panel_mode;
|
||||
|
||||
int pipe;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
u32 pkg_num;
|
||||
|
||||
/* Registers */
|
||||
u32 dpll_reg;
|
||||
u32 dspcntr_reg;
|
||||
u32 pipeconf_reg;
|
||||
u32 pipestat_reg;
|
||||
u32 dsplinoff_reg;
|
||||
u32 dspsurf_reg;
|
||||
|
||||
u32 mipi_intr_stat_reg;
|
||||
u32 mipi_lp_gen_data_reg;
|
||||
u32 mipi_hs_gen_data_reg;
|
||||
u32 mipi_lp_gen_ctrl_reg;
|
||||
u32 mipi_hs_gen_ctrl_reg;
|
||||
u32 mipi_gen_fifo_stat_reg;
|
||||
u32 mipi_data_addr_reg;
|
||||
u32 mipi_data_len_reg;
|
||||
u32 mipi_cmd_addr_reg;
|
||||
u32 mipi_cmd_len_reg;
|
||||
};
|
||||
|
||||
/* DCS definitions */
|
||||
#define DCS_SOFT_RESET 0x01
|
||||
#define DCS_ENTER_SLEEP_MODE 0x10
|
||||
#define DCS_EXIT_SLEEP_MODE 0x11
|
||||
#define DCS_SET_DISPLAY_OFF 0x28
|
||||
#define DCS_SET_DISPLAY_ON 0x29
|
||||
#define DCS_SET_COLUMN_ADDRESS 0x2a
|
||||
#define DCS_SET_PAGE_ADDRESS 0x2b
|
||||
#define DCS_WRITE_MEM_START 0x2c
|
||||
#define DCS_SET_TEAR_OFF 0x34
|
||||
#define DCS_SET_TEAR_ON 0x35
|
||||
|
||||
extern int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector,
|
||||
int pipe);
|
||||
extern void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender);
|
||||
int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
|
||||
u8 param, u8 param_num, bool hs);
|
||||
int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
|
||||
u32 len, bool hs);
|
||||
int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0,
|
||||
u8 param1, u8 param_num, bool hs);
|
||||
int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
|
||||
u32 len, bool hs);
|
||||
/* Read interfaces */
|
||||
int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
|
||||
u32 *data, u16 len, bool hs);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicensen
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Eaton <thomas.g.eaton@intel.com>
|
||||
* Scott Rowe <scott.m.rowe@intel.com>
|
||||
*/
|
||||
|
||||
#include "mdfld_output.h"
|
||||
#include "mdfld_dsi_dpi.h"
|
||||
#include "mdfld_dsi_output.h"
|
||||
|
||||
#include "tc35876x-dsi-lvds.h"
|
||||
|
||||
int mdfld_get_panel_type(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
return dev_priv->mdfld_panel_id;
|
||||
}
|
||||
|
||||
static void mdfld_init_panel(struct drm_device *dev, int mipi_pipe,
|
||||
int p_type)
|
||||
{
|
||||
switch (p_type) {
|
||||
case TPO_VID:
|
||||
mdfld_dsi_output_init(dev, mipi_pipe, &mdfld_tpo_vid_funcs);
|
||||
break;
|
||||
case TC35876X:
|
||||
tc35876x_init(dev);
|
||||
mdfld_dsi_output_init(dev, mipi_pipe, &mdfld_tc35876x_funcs);
|
||||
break;
|
||||
case TMD_VID:
|
||||
mdfld_dsi_output_init(dev, mipi_pipe, &mdfld_tmd_vid_funcs);
|
||||
break;
|
||||
case HDMI:
|
||||
/* if (dev_priv->mdfld_hdmi_present)
|
||||
mdfld_hdmi_init(dev, &dev_priv->mode_dev); */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int mdfld_output_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
|
||||
/* FIXME: hardcoded for now */
|
||||
dev_priv->mdfld_panel_id = TC35876X;
|
||||
/* MIPI panel 1 */
|
||||
mdfld_init_panel(dev, 0, dev_priv->mdfld_panel_id);
|
||||
/* HDMI panel */
|
||||
mdfld_init_panel(dev, 1, HDMI);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicensen
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Eaton <thomas.g.eaton@intel.com>
|
||||
* Scott Rowe <scott.m.rowe@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef MDFLD_OUTPUT_H
|
||||
#define MDFLD_OUTPUT_H
|
||||
|
||||
#include "psb_drv.h"
|
||||
|
||||
#define TPO_PANEL_WIDTH 84
|
||||
#define TPO_PANEL_HEIGHT 46
|
||||
#define TMD_PANEL_WIDTH 39
|
||||
#define TMD_PANEL_HEIGHT 71
|
||||
|
||||
struct mdfld_dsi_config;
|
||||
|
||||
enum panel_type {
|
||||
TPO_VID,
|
||||
TMD_VID,
|
||||
HDMI,
|
||||
TC35876X,
|
||||
};
|
||||
|
||||
struct panel_info {
|
||||
u32 width_mm;
|
||||
u32 height_mm;
|
||||
/* Other info */
|
||||
};
|
||||
|
||||
struct panel_funcs {
|
||||
const struct drm_encoder_funcs *encoder_funcs;
|
||||
const struct drm_encoder_helper_funcs *encoder_helper_funcs;
|
||||
struct drm_display_mode * (*get_config_mode)(struct drm_device *);
|
||||
int (*get_panel_info)(struct drm_device *, int, struct panel_info *);
|
||||
int (*reset)(int pipe);
|
||||
void (*drv_ic_init)(struct mdfld_dsi_config *dsi_config, int pipe);
|
||||
};
|
||||
|
||||
int mdfld_output_init(struct drm_device *dev);
|
||||
|
||||
struct backlight_device *mdfld_get_backlight_device(void);
|
||||
int mdfld_set_brightness(struct backlight_device *bd);
|
||||
|
||||
int mdfld_get_panel_type(struct drm_device *dev, int pipe);
|
||||
|
||||
extern const struct drm_crtc_helper_funcs mdfld_helper_funcs;
|
||||
|
||||
extern const struct panel_funcs mdfld_tmd_vid_funcs;
|
||||
extern const struct panel_funcs mdfld_tpo_vid_funcs;
|
||||
|
||||
extern void mdfld_disable_crtc(struct drm_device *dev, int pipe);
|
||||
extern void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe);
|
||||
extern void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe);
|
||||
#endif
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Jim Liu <jim.liu@intel.com>
|
||||
* Jackie Li<yaodong.li@intel.com>
|
||||
* Gideon Eaton <eaton.
|
||||
* Scott Rowe <scott.m.rowe@intel.com>
|
||||
*/
|
||||
|
||||
#include "mdfld_dsi_dpi.h"
|
||||
#include "mdfld_dsi_pkg_sender.h"
|
||||
|
||||
static struct drm_display_mode *tmd_vid_get_config_mode(struct drm_device *dev)
|
||||
{
|
||||
struct drm_display_mode *mode;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD;
|
||||
bool use_gct = false; /*Disable GCT for now*/
|
||||
|
||||
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
|
||||
if (!mode)
|
||||
return NULL;
|
||||
|
||||
if (use_gct) {
|
||||
mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo;
|
||||
mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo;
|
||||
mode->hsync_start = mode->hdisplay + \
|
||||
((ti->hsync_offset_hi << 8) | \
|
||||
ti->hsync_offset_lo);
|
||||
mode->hsync_end = mode->hsync_start + \
|
||||
((ti->hsync_pulse_width_hi << 8) | \
|
||||
ti->hsync_pulse_width_lo);
|
||||
mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | \
|
||||
ti->hblank_lo);
|
||||
mode->vsync_start = \
|
||||
mode->vdisplay + ((ti->vsync_offset_hi << 8) | \
|
||||
ti->vsync_offset_lo);
|
||||
mode->vsync_end = \
|
||||
mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) | \
|
||||
ti->vsync_pulse_width_lo);
|
||||
mode->vtotal = mode->vdisplay + \
|
||||
((ti->vblank_hi << 8) | ti->vblank_lo);
|
||||
mode->clock = ti->pixel_clock * 10;
|
||||
|
||||
dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay);
|
||||
dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay);
|
||||
dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start);
|
||||
dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end);
|
||||
dev_dbg(dev->dev, "htotal is %d\n", mode->htotal);
|
||||
dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start);
|
||||
dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end);
|
||||
dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal);
|
||||
dev_dbg(dev->dev, "clock is %d\n", mode->clock);
|
||||
} else {
|
||||
mode->hdisplay = 480;
|
||||
mode->vdisplay = 854;
|
||||
mode->hsync_start = 487;
|
||||
mode->hsync_end = 490;
|
||||
mode->htotal = 499;
|
||||
mode->vsync_start = 861;
|
||||
mode->vsync_end = 865;
|
||||
mode->vtotal = 873;
|
||||
mode->clock = 33264;
|
||||
}
|
||||
|
||||
drm_mode_set_name(mode);
|
||||
drm_mode_set_crtcinfo(mode, 0);
|
||||
|
||||
mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int tmd_vid_get_panel_info(struct drm_device *dev,
|
||||
int pipe,
|
||||
struct panel_info *pi)
|
||||
{
|
||||
if (!dev || !pi)
|
||||
return -EINVAL;
|
||||
|
||||
pi->width_mm = TMD_PANEL_WIDTH;
|
||||
pi->height_mm = TMD_PANEL_HEIGHT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ************************************************************************* *\
|
||||
* FUNCTION: mdfld_init_TMD_MIPI
|
||||
*
|
||||
* DESCRIPTION: This function is called only by mrst_dsi_mode_set and
|
||||
* restore_display_registers. since this function does not
|
||||
* acquire the mutex, it is important that the calling function
|
||||
* does!
|
||||
\* ************************************************************************* */
|
||||
|
||||
/* FIXME: make the below data u8 instead of u32; note byte order! */
|
||||
static u32 tmd_cmd_mcap_off[] = {0x000000b2};
|
||||
static u32 tmd_cmd_enable_lane_switch[] = {0x000101ef};
|
||||
static u32 tmd_cmd_set_lane_num[] = {0x006360ef};
|
||||
static u32 tmd_cmd_pushing_clock0[] = {0x00cc2fef};
|
||||
static u32 tmd_cmd_pushing_clock1[] = {0x00dd6eef};
|
||||
static u32 tmd_cmd_set_mode[] = {0x000000b3};
|
||||
static u32 tmd_cmd_set_sync_pulse_mode[] = {0x000961ef};
|
||||
static u32 tmd_cmd_set_column[] = {0x0100002a, 0x000000df};
|
||||
static u32 tmd_cmd_set_page[] = {0x0300002b, 0x00000055};
|
||||
static u32 tmd_cmd_set_video_mode[] = {0x00000153};
|
||||
/*no auto_bl,need add in furture*/
|
||||
static u32 tmd_cmd_enable_backlight[] = {0x00005ab4};
|
||||
static u32 tmd_cmd_set_backlight_dimming[] = {0x00000ebd};
|
||||
|
||||
static void mdfld_dsi_tmd_drv_ic_init(struct mdfld_dsi_config *dsi_config,
|
||||
int pipe)
|
||||
{
|
||||
struct mdfld_dsi_pkg_sender *sender
|
||||
= mdfld_dsi_get_pkg_sender(dsi_config);
|
||||
|
||||
DRM_INFO("Enter mdfld init TMD MIPI display.\n");
|
||||
|
||||
if (!sender) {
|
||||
DRM_ERROR("Cannot get sender\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dsi_config->dvr_ic_inited)
|
||||
return;
|
||||
|
||||
msleep(3);
|
||||
|
||||
/* FIXME: make the below data u8 instead of u32; note byte order! */
|
||||
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_mcap_off,
|
||||
sizeof(tmd_cmd_mcap_off), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_enable_lane_switch,
|
||||
sizeof(tmd_cmd_enable_lane_switch), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_lane_num,
|
||||
sizeof(tmd_cmd_set_lane_num), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_pushing_clock0,
|
||||
sizeof(tmd_cmd_pushing_clock0), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_pushing_clock1,
|
||||
sizeof(tmd_cmd_pushing_clock1), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_mode,
|
||||
sizeof(tmd_cmd_set_mode), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_sync_pulse_mode,
|
||||
sizeof(tmd_cmd_set_sync_pulse_mode), false);
|
||||
mdfld_dsi_send_mcs_long(sender, (u8 *) tmd_cmd_set_column,
|
||||
sizeof(tmd_cmd_set_column), false);
|
||||
mdfld_dsi_send_mcs_long(sender, (u8 *) tmd_cmd_set_page,
|
||||
sizeof(tmd_cmd_set_page), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_video_mode,
|
||||
sizeof(tmd_cmd_set_video_mode), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_enable_backlight,
|
||||
sizeof(tmd_cmd_enable_backlight), false);
|
||||
mdfld_dsi_send_gen_long(sender, (u8 *) tmd_cmd_set_backlight_dimming,
|
||||
sizeof(tmd_cmd_set_backlight_dimming), false);
|
||||
|
||||
dsi_config->dvr_ic_inited = 1;
|
||||
}
|
||||
|
||||
/*TPO DPI encoder helper funcs*/
|
||||
static const struct drm_encoder_helper_funcs
|
||||
mdfld_tpo_dpi_encoder_helper_funcs = {
|
||||
.dpms = mdfld_dsi_dpi_dpms,
|
||||
.mode_fixup = mdfld_dsi_dpi_mode_fixup,
|
||||
.prepare = mdfld_dsi_dpi_prepare,
|
||||
.mode_set = mdfld_dsi_dpi_mode_set,
|
||||
.commit = mdfld_dsi_dpi_commit,
|
||||
};
|
||||
|
||||
/*TPO DPI encoder funcs*/
|
||||
static const struct drm_encoder_funcs mdfld_tpo_dpi_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
const struct panel_funcs mdfld_tmd_vid_funcs = {
|
||||
.encoder_funcs = &mdfld_tpo_dpi_encoder_funcs,
|
||||
.encoder_helper_funcs = &mdfld_tpo_dpi_encoder_helper_funcs,
|
||||
.get_config_mode = &tmd_vid_get_config_mode,
|
||||
.get_panel_info = tmd_vid_get_panel_info,
|
||||
.reset = mdfld_dsi_panel_reset,
|
||||
.drv_ic_init = mdfld_dsi_tmd_drv_ic_init,
|
||||
};
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* jim liu <jim.liu@intel.com>
|
||||
* Jackie Li<yaodong.li@intel.com>
|
||||
*/
|
||||
|
||||
#include "mdfld_dsi_dpi.h"
|
||||
|
||||
static struct drm_display_mode *tpo_vid_get_config_mode(struct drm_device *dev)
|
||||
{
|
||||
struct drm_display_mode *mode;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD;
|
||||
bool use_gct = false;
|
||||
|
||||
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
|
||||
if (!mode)
|
||||
return NULL;
|
||||
|
||||
if (use_gct) {
|
||||
mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo;
|
||||
mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo;
|
||||
mode->hsync_start = mode->hdisplay +
|
||||
((ti->hsync_offset_hi << 8) |
|
||||
ti->hsync_offset_lo);
|
||||
mode->hsync_end = mode->hsync_start +
|
||||
((ti->hsync_pulse_width_hi << 8) |
|
||||
ti->hsync_pulse_width_lo);
|
||||
mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) |
|
||||
ti->hblank_lo);
|
||||
mode->vsync_start =
|
||||
mode->vdisplay + ((ti->vsync_offset_hi << 8) |
|
||||
ti->vsync_offset_lo);
|
||||
mode->vsync_end =
|
||||
mode->vsync_start + ((ti->vsync_pulse_width_hi << 8) |
|
||||
ti->vsync_pulse_width_lo);
|
||||
mode->vtotal = mode->vdisplay +
|
||||
((ti->vblank_hi << 8) | ti->vblank_lo);
|
||||
mode->clock = ti->pixel_clock * 10;
|
||||
|
||||
dev_dbg(dev->dev, "hdisplay is %d\n", mode->hdisplay);
|
||||
dev_dbg(dev->dev, "vdisplay is %d\n", mode->vdisplay);
|
||||
dev_dbg(dev->dev, "HSS is %d\n", mode->hsync_start);
|
||||
dev_dbg(dev->dev, "HSE is %d\n", mode->hsync_end);
|
||||
dev_dbg(dev->dev, "htotal is %d\n", mode->htotal);
|
||||
dev_dbg(dev->dev, "VSS is %d\n", mode->vsync_start);
|
||||
dev_dbg(dev->dev, "VSE is %d\n", mode->vsync_end);
|
||||
dev_dbg(dev->dev, "vtotal is %d\n", mode->vtotal);
|
||||
dev_dbg(dev->dev, "clock is %d\n", mode->clock);
|
||||
} else {
|
||||
mode->hdisplay = 864;
|
||||
mode->vdisplay = 480;
|
||||
mode->hsync_start = 873;
|
||||
mode->hsync_end = 876;
|
||||
mode->htotal = 887;
|
||||
mode->vsync_start = 487;
|
||||
mode->vsync_end = 490;
|
||||
mode->vtotal = 499;
|
||||
mode->clock = 33264;
|
||||
}
|
||||
|
||||
drm_mode_set_name(mode);
|
||||
drm_mode_set_crtcinfo(mode, 0);
|
||||
|
||||
mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int tpo_vid_get_panel_info(struct drm_device *dev,
|
||||
int pipe,
|
||||
struct panel_info *pi)
|
||||
{
|
||||
if (!dev || !pi)
|
||||
return -EINVAL;
|
||||
|
||||
pi->width_mm = TPO_PANEL_WIDTH;
|
||||
pi->height_mm = TPO_PANEL_HEIGHT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*TPO DPI encoder helper funcs*/
|
||||
static const struct drm_encoder_helper_funcs
|
||||
mdfld_tpo_dpi_encoder_helper_funcs = {
|
||||
.dpms = mdfld_dsi_dpi_dpms,
|
||||
.mode_fixup = mdfld_dsi_dpi_mode_fixup,
|
||||
.prepare = mdfld_dsi_dpi_prepare,
|
||||
.mode_set = mdfld_dsi_dpi_mode_set,
|
||||
.commit = mdfld_dsi_dpi_commit,
|
||||
};
|
||||
|
||||
/*TPO DPI encoder funcs*/
|
||||
static const struct drm_encoder_funcs mdfld_tpo_dpi_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
const struct panel_funcs mdfld_tpo_vid_funcs = {
|
||||
.encoder_funcs = &mdfld_tpo_dpi_encoder_funcs,
|
||||
.encoder_helper_funcs = &mdfld_tpo_dpi_encoder_helper_funcs,
|
||||
.get_config_mode = &tpo_vid_get_config_mode,
|
||||
.get_panel_info = tpo_vid_get_panel_info,
|
||||
};
|
|
@ -270,7 +270,7 @@ struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void psb_mmu_free_pt(struct psb_mmu_pt *pt)
|
||||
static void psb_mmu_free_pt(struct psb_mmu_pt *pt)
|
||||
{
|
||||
__free_page(pt->p);
|
||||
kfree(pt);
|
||||
|
@ -351,7 +351,7 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd)
|
|||
return pt;
|
||||
}
|
||||
|
||||
struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd,
|
||||
static struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd,
|
||||
unsigned long addr)
|
||||
{
|
||||
uint32_t index = psb_mmu_pd_index(addr);
|
||||
|
@ -488,15 +488,6 @@ struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver *driver)
|
|||
return pd;
|
||||
}
|
||||
|
||||
/* Returns the physical address of the PD shared by sgx/msvdx */
|
||||
uint32_t psb_get_default_pd_addr(struct psb_mmu_driver *driver)
|
||||
{
|
||||
struct psb_mmu_pd *pd;
|
||||
|
||||
pd = psb_mmu_get_default_pd(driver);
|
||||
return page_to_pfn(pd->p) << PAGE_SHIFT;
|
||||
}
|
||||
|
||||
void psb_mmu_driver_takedown(struct psb_mmu_driver *driver)
|
||||
{
|
||||
psb_mmu_free_pagedir(driver->default_pd);
|
||||
|
|
|
@ -115,7 +115,7 @@ static void oaktrail_clock(int refclk, struct oaktrail_clock_t *clock)
|
|||
clock->dot = (refclk * clock->m) / (14 * clock->p1);
|
||||
}
|
||||
|
||||
void mrstPrintPll(char *prefix, struct oaktrail_clock_t *clock)
|
||||
static void mrstPrintPll(char *prefix, struct oaktrail_clock_t *clock)
|
||||
{
|
||||
pr_debug("%s: dotclock = %d, m = %d, p1 = %d.\n",
|
||||
prefix, clock->dot, clock->m, clock->p1);
|
||||
|
@ -169,7 +169,6 @@ static void oaktrail_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
int dspbase_reg = (pipe == 0) ? MRST_DSPABASE : DSPBBASE;
|
||||
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
|
||||
u32 temp;
|
||||
bool enabled;
|
||||
|
||||
if (!gma_power_begin(dev, true))
|
||||
return;
|
||||
|
@ -253,8 +252,6 @@ static void oaktrail_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
break;
|
||||
}
|
||||
|
||||
enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF;
|
||||
|
||||
/*Set FIFO Watermarks*/
|
||||
REG_WRITE(DSPARB, 0x3FFF);
|
||||
REG_WRITE(DSPFW1, 0x3F88080A);
|
||||
|
@ -310,7 +307,7 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
|
|||
struct oaktrail_clock_t clock;
|
||||
u32 dpll = 0, fp = 0, dspcntr, pipeconf;
|
||||
bool ok, is_sdvo = false;
|
||||
bool is_crt = false, is_lvds = false, is_tv = false;
|
||||
bool is_lvds = false;
|
||||
bool is_mipi = false;
|
||||
struct drm_mode_config *mode_config = &dev->mode_config;
|
||||
struct psb_intel_encoder *psb_intel_encoder = NULL;
|
||||
|
@ -340,12 +337,6 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
|
|||
case INTEL_OUTPUT_SDVO:
|
||||
is_sdvo = true;
|
||||
break;
|
||||
case INTEL_OUTPUT_TVOUT:
|
||||
is_tv = true;
|
||||
break;
|
||||
case INTEL_OUTPUT_ANALOG:
|
||||
is_crt = true;
|
||||
break;
|
||||
case INTEL_OUTPUT_MIPI:
|
||||
is_mipi = true;
|
||||
break;
|
||||
|
@ -428,9 +419,6 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
|
|||
else
|
||||
dspcntr |= DISPPLANE_SEL_PIPE_B;
|
||||
|
||||
dev_priv->dspcntr = dspcntr |= DISPLAY_PLANE_ENABLE;
|
||||
dev_priv->pipeconf = pipeconf |= PIPEACONF_ENABLE;
|
||||
|
||||
if (is_mipi)
|
||||
goto oaktrail_crtc_mode_set_exit;
|
||||
|
||||
|
@ -517,7 +505,7 @@ static bool oaktrail_crtc_mode_fixup(struct drm_crtc *crtc,
|
|||
return true;
|
||||
}
|
||||
|
||||
int oaktrail_pipe_set_base(struct drm_crtc *crtc,
|
||||
static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
|
||||
int x, int y, struct drm_framebuffer *old_fb)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
|
|
|
@ -141,7 +141,7 @@ static const struct backlight_ops oaktrail_ops = {
|
|||
.update_status = oaktrail_set_brightness,
|
||||
};
|
||||
|
||||
int oaktrail_backlight_init(struct drm_device *dev)
|
||||
static int oaktrail_backlight_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
int ret;
|
||||
|
@ -176,10 +176,6 @@ int oaktrail_backlight_init(struct drm_device *dev)
|
|||
* for power management
|
||||
*/
|
||||
|
||||
static void oaktrail_init_pm(struct drm_device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* oaktrail_save_display_registers - save registers lost on suspend
|
||||
* @dev: our DRM device
|
||||
|
@ -190,81 +186,82 @@ static void oaktrail_init_pm(struct drm_device *dev)
|
|||
static int oaktrail_save_display_registers(struct drm_device *dev)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct psb_save_area *regs = &dev_priv->regs;
|
||||
int i;
|
||||
u32 pp_stat;
|
||||
|
||||
/* Display arbitration control + watermarks */
|
||||
dev_priv->saveDSPARB = PSB_RVDC32(DSPARB);
|
||||
dev_priv->saveDSPFW1 = PSB_RVDC32(DSPFW1);
|
||||
dev_priv->saveDSPFW2 = PSB_RVDC32(DSPFW2);
|
||||
dev_priv->saveDSPFW3 = PSB_RVDC32(DSPFW3);
|
||||
dev_priv->saveDSPFW4 = PSB_RVDC32(DSPFW4);
|
||||
dev_priv->saveDSPFW5 = PSB_RVDC32(DSPFW5);
|
||||
dev_priv->saveDSPFW6 = PSB_RVDC32(DSPFW6);
|
||||
dev_priv->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
|
||||
regs->psb.saveDSPARB = PSB_RVDC32(DSPARB);
|
||||
regs->psb.saveDSPFW1 = PSB_RVDC32(DSPFW1);
|
||||
regs->psb.saveDSPFW2 = PSB_RVDC32(DSPFW2);
|
||||
regs->psb.saveDSPFW3 = PSB_RVDC32(DSPFW3);
|
||||
regs->psb.saveDSPFW4 = PSB_RVDC32(DSPFW4);
|
||||
regs->psb.saveDSPFW5 = PSB_RVDC32(DSPFW5);
|
||||
regs->psb.saveDSPFW6 = PSB_RVDC32(DSPFW6);
|
||||
regs->psb.saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
|
||||
|
||||
/* Pipe & plane A info */
|
||||
dev_priv->savePIPEACONF = PSB_RVDC32(PIPEACONF);
|
||||
dev_priv->savePIPEASRC = PSB_RVDC32(PIPEASRC);
|
||||
dev_priv->saveFPA0 = PSB_RVDC32(MRST_FPA0);
|
||||
dev_priv->saveFPA1 = PSB_RVDC32(MRST_FPA1);
|
||||
dev_priv->saveDPLL_A = PSB_RVDC32(MRST_DPLL_A);
|
||||
dev_priv->saveHTOTAL_A = PSB_RVDC32(HTOTAL_A);
|
||||
dev_priv->saveHBLANK_A = PSB_RVDC32(HBLANK_A);
|
||||
dev_priv->saveHSYNC_A = PSB_RVDC32(HSYNC_A);
|
||||
dev_priv->saveVTOTAL_A = PSB_RVDC32(VTOTAL_A);
|
||||
dev_priv->saveVBLANK_A = PSB_RVDC32(VBLANK_A);
|
||||
dev_priv->saveVSYNC_A = PSB_RVDC32(VSYNC_A);
|
||||
dev_priv->saveBCLRPAT_A = PSB_RVDC32(BCLRPAT_A);
|
||||
dev_priv->saveDSPACNTR = PSB_RVDC32(DSPACNTR);
|
||||
dev_priv->saveDSPASTRIDE = PSB_RVDC32(DSPASTRIDE);
|
||||
dev_priv->saveDSPAADDR = PSB_RVDC32(DSPABASE);
|
||||
dev_priv->saveDSPASURF = PSB_RVDC32(DSPASURF);
|
||||
dev_priv->saveDSPALINOFF = PSB_RVDC32(DSPALINOFF);
|
||||
dev_priv->saveDSPATILEOFF = PSB_RVDC32(DSPATILEOFF);
|
||||
regs->psb.savePIPEACONF = PSB_RVDC32(PIPEACONF);
|
||||
regs->psb.savePIPEASRC = PSB_RVDC32(PIPEASRC);
|
||||
regs->psb.saveFPA0 = PSB_RVDC32(MRST_FPA0);
|
||||
regs->psb.saveFPA1 = PSB_RVDC32(MRST_FPA1);
|
||||
regs->psb.saveDPLL_A = PSB_RVDC32(MRST_DPLL_A);
|
||||
regs->psb.saveHTOTAL_A = PSB_RVDC32(HTOTAL_A);
|
||||
regs->psb.saveHBLANK_A = PSB_RVDC32(HBLANK_A);
|
||||
regs->psb.saveHSYNC_A = PSB_RVDC32(HSYNC_A);
|
||||
regs->psb.saveVTOTAL_A = PSB_RVDC32(VTOTAL_A);
|
||||
regs->psb.saveVBLANK_A = PSB_RVDC32(VBLANK_A);
|
||||
regs->psb.saveVSYNC_A = PSB_RVDC32(VSYNC_A);
|
||||
regs->psb.saveBCLRPAT_A = PSB_RVDC32(BCLRPAT_A);
|
||||
regs->psb.saveDSPACNTR = PSB_RVDC32(DSPACNTR);
|
||||
regs->psb.saveDSPASTRIDE = PSB_RVDC32(DSPASTRIDE);
|
||||
regs->psb.saveDSPAADDR = PSB_RVDC32(DSPABASE);
|
||||
regs->psb.saveDSPASURF = PSB_RVDC32(DSPASURF);
|
||||
regs->psb.saveDSPALINOFF = PSB_RVDC32(DSPALINOFF);
|
||||
regs->psb.saveDSPATILEOFF = PSB_RVDC32(DSPATILEOFF);
|
||||
|
||||
/* Save cursor regs */
|
||||
dev_priv->saveDSPACURSOR_CTRL = PSB_RVDC32(CURACNTR);
|
||||
dev_priv->saveDSPACURSOR_BASE = PSB_RVDC32(CURABASE);
|
||||
dev_priv->saveDSPACURSOR_POS = PSB_RVDC32(CURAPOS);
|
||||
regs->psb.saveDSPACURSOR_CTRL = PSB_RVDC32(CURACNTR);
|
||||
regs->psb.saveDSPACURSOR_BASE = PSB_RVDC32(CURABASE);
|
||||
regs->psb.saveDSPACURSOR_POS = PSB_RVDC32(CURAPOS);
|
||||
|
||||
/* Save palette (gamma) */
|
||||
for (i = 0; i < 256; i++)
|
||||
dev_priv->save_palette_a[i] = PSB_RVDC32(PALETTE_A + (i << 2));
|
||||
regs->psb.save_palette_a[i] = PSB_RVDC32(PALETTE_A + (i << 2));
|
||||
|
||||
if (dev_priv->hdmi_priv)
|
||||
oaktrail_hdmi_save(dev);
|
||||
|
||||
/* Save performance state */
|
||||
dev_priv->savePERF_MODE = PSB_RVDC32(MRST_PERF_MODE);
|
||||
regs->psb.savePERF_MODE = PSB_RVDC32(MRST_PERF_MODE);
|
||||
|
||||
/* LVDS state */
|
||||
dev_priv->savePP_CONTROL = PSB_RVDC32(PP_CONTROL);
|
||||
dev_priv->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
|
||||
dev_priv->savePFIT_AUTO_RATIOS = PSB_RVDC32(PFIT_AUTO_RATIOS);
|
||||
dev_priv->saveBLC_PWM_CTL = PSB_RVDC32(BLC_PWM_CTL);
|
||||
dev_priv->saveBLC_PWM_CTL2 = PSB_RVDC32(BLC_PWM_CTL2);
|
||||
dev_priv->saveLVDS = PSB_RVDC32(LVDS);
|
||||
dev_priv->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
|
||||
dev_priv->savePP_ON_DELAYS = PSB_RVDC32(LVDSPP_ON);
|
||||
dev_priv->savePP_OFF_DELAYS = PSB_RVDC32(LVDSPP_OFF);
|
||||
dev_priv->savePP_DIVISOR = PSB_RVDC32(PP_CYCLE);
|
||||
regs->psb.savePP_CONTROL = PSB_RVDC32(PP_CONTROL);
|
||||
regs->psb.savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
|
||||
regs->psb.savePFIT_AUTO_RATIOS = PSB_RVDC32(PFIT_AUTO_RATIOS);
|
||||
regs->saveBLC_PWM_CTL = PSB_RVDC32(BLC_PWM_CTL);
|
||||
regs->saveBLC_PWM_CTL2 = PSB_RVDC32(BLC_PWM_CTL2);
|
||||
regs->psb.saveLVDS = PSB_RVDC32(LVDS);
|
||||
regs->psb.savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
|
||||
regs->psb.savePP_ON_DELAYS = PSB_RVDC32(LVDSPP_ON);
|
||||
regs->psb.savePP_OFF_DELAYS = PSB_RVDC32(LVDSPP_OFF);
|
||||
regs->psb.savePP_DIVISOR = PSB_RVDC32(PP_CYCLE);
|
||||
|
||||
/* HW overlay */
|
||||
dev_priv->saveOV_OVADD = PSB_RVDC32(OV_OVADD);
|
||||
dev_priv->saveOV_OGAMC0 = PSB_RVDC32(OV_OGAMC0);
|
||||
dev_priv->saveOV_OGAMC1 = PSB_RVDC32(OV_OGAMC1);
|
||||
dev_priv->saveOV_OGAMC2 = PSB_RVDC32(OV_OGAMC2);
|
||||
dev_priv->saveOV_OGAMC3 = PSB_RVDC32(OV_OGAMC3);
|
||||
dev_priv->saveOV_OGAMC4 = PSB_RVDC32(OV_OGAMC4);
|
||||
dev_priv->saveOV_OGAMC5 = PSB_RVDC32(OV_OGAMC5);
|
||||
regs->psb.saveOV_OVADD = PSB_RVDC32(OV_OVADD);
|
||||
regs->psb.saveOV_OGAMC0 = PSB_RVDC32(OV_OGAMC0);
|
||||
regs->psb.saveOV_OGAMC1 = PSB_RVDC32(OV_OGAMC1);
|
||||
regs->psb.saveOV_OGAMC2 = PSB_RVDC32(OV_OGAMC2);
|
||||
regs->psb.saveOV_OGAMC3 = PSB_RVDC32(OV_OGAMC3);
|
||||
regs->psb.saveOV_OGAMC4 = PSB_RVDC32(OV_OGAMC4);
|
||||
regs->psb.saveOV_OGAMC5 = PSB_RVDC32(OV_OGAMC5);
|
||||
|
||||
/* DPST registers */
|
||||
dev_priv->saveHISTOGRAM_INT_CONTROL_REG =
|
||||
regs->psb.saveHISTOGRAM_INT_CONTROL_REG =
|
||||
PSB_RVDC32(HISTOGRAM_INT_CONTROL);
|
||||
dev_priv->saveHISTOGRAM_LOGIC_CONTROL_REG =
|
||||
regs->psb.saveHISTOGRAM_LOGIC_CONTROL_REG =
|
||||
PSB_RVDC32(HISTOGRAM_LOGIC_CONTROL);
|
||||
dev_priv->savePWM_CONTROL_LOGIC = PSB_RVDC32(PWM_CONTROL_LOGIC);
|
||||
regs->psb.savePWM_CONTROL_LOGIC = PSB_RVDC32(PWM_CONTROL_LOGIC);
|
||||
|
||||
if (dev_priv->iLVDS_enable) {
|
||||
/* Shut down the panel */
|
||||
|
@ -302,79 +299,80 @@ static int oaktrail_save_display_registers(struct drm_device *dev)
|
|||
static int oaktrail_restore_display_registers(struct drm_device *dev)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct psb_save_area *regs = &dev_priv->regs;
|
||||
u32 pp_stat;
|
||||
int i;
|
||||
|
||||
/* Display arbitration + watermarks */
|
||||
PSB_WVDC32(dev_priv->saveDSPARB, DSPARB);
|
||||
PSB_WVDC32(dev_priv->saveDSPFW1, DSPFW1);
|
||||
PSB_WVDC32(dev_priv->saveDSPFW2, DSPFW2);
|
||||
PSB_WVDC32(dev_priv->saveDSPFW3, DSPFW3);
|
||||
PSB_WVDC32(dev_priv->saveDSPFW4, DSPFW4);
|
||||
PSB_WVDC32(dev_priv->saveDSPFW5, DSPFW5);
|
||||
PSB_WVDC32(dev_priv->saveDSPFW6, DSPFW6);
|
||||
PSB_WVDC32(dev_priv->saveCHICKENBIT, DSPCHICKENBIT);
|
||||
PSB_WVDC32(regs->psb.saveDSPARB, DSPARB);
|
||||
PSB_WVDC32(regs->psb.saveDSPFW1, DSPFW1);
|
||||
PSB_WVDC32(regs->psb.saveDSPFW2, DSPFW2);
|
||||
PSB_WVDC32(regs->psb.saveDSPFW3, DSPFW3);
|
||||
PSB_WVDC32(regs->psb.saveDSPFW4, DSPFW4);
|
||||
PSB_WVDC32(regs->psb.saveDSPFW5, DSPFW5);
|
||||
PSB_WVDC32(regs->psb.saveDSPFW6, DSPFW6);
|
||||
PSB_WVDC32(regs->psb.saveCHICKENBIT, DSPCHICKENBIT);
|
||||
|
||||
/* Make sure VGA plane is off. it initializes to on after reset!*/
|
||||
PSB_WVDC32(0x80000000, VGACNTRL);
|
||||
|
||||
/* set the plls */
|
||||
PSB_WVDC32(dev_priv->saveFPA0, MRST_FPA0);
|
||||
PSB_WVDC32(dev_priv->saveFPA1, MRST_FPA1);
|
||||
PSB_WVDC32(regs->psb.saveFPA0, MRST_FPA0);
|
||||
PSB_WVDC32(regs->psb.saveFPA1, MRST_FPA1);
|
||||
|
||||
/* Actually enable it */
|
||||
PSB_WVDC32(dev_priv->saveDPLL_A, MRST_DPLL_A);
|
||||
PSB_WVDC32(regs->psb.saveDPLL_A, MRST_DPLL_A);
|
||||
DRM_UDELAY(150);
|
||||
|
||||
/* Restore mode */
|
||||
PSB_WVDC32(dev_priv->saveHTOTAL_A, HTOTAL_A);
|
||||
PSB_WVDC32(dev_priv->saveHBLANK_A, HBLANK_A);
|
||||
PSB_WVDC32(dev_priv->saveHSYNC_A, HSYNC_A);
|
||||
PSB_WVDC32(dev_priv->saveVTOTAL_A, VTOTAL_A);
|
||||
PSB_WVDC32(dev_priv->saveVBLANK_A, VBLANK_A);
|
||||
PSB_WVDC32(dev_priv->saveVSYNC_A, VSYNC_A);
|
||||
PSB_WVDC32(dev_priv->savePIPEASRC, PIPEASRC);
|
||||
PSB_WVDC32(dev_priv->saveBCLRPAT_A, BCLRPAT_A);
|
||||
PSB_WVDC32(regs->psb.saveHTOTAL_A, HTOTAL_A);
|
||||
PSB_WVDC32(regs->psb.saveHBLANK_A, HBLANK_A);
|
||||
PSB_WVDC32(regs->psb.saveHSYNC_A, HSYNC_A);
|
||||
PSB_WVDC32(regs->psb.saveVTOTAL_A, VTOTAL_A);
|
||||
PSB_WVDC32(regs->psb.saveVBLANK_A, VBLANK_A);
|
||||
PSB_WVDC32(regs->psb.saveVSYNC_A, VSYNC_A);
|
||||
PSB_WVDC32(regs->psb.savePIPEASRC, PIPEASRC);
|
||||
PSB_WVDC32(regs->psb.saveBCLRPAT_A, BCLRPAT_A);
|
||||
|
||||
/* Restore performance mode*/
|
||||
PSB_WVDC32(dev_priv->savePERF_MODE, MRST_PERF_MODE);
|
||||
PSB_WVDC32(regs->psb.savePERF_MODE, MRST_PERF_MODE);
|
||||
|
||||
/* Enable the pipe*/
|
||||
if (dev_priv->iLVDS_enable)
|
||||
PSB_WVDC32(dev_priv->savePIPEACONF, PIPEACONF);
|
||||
PSB_WVDC32(regs->psb.savePIPEACONF, PIPEACONF);
|
||||
|
||||
/* Set up the plane*/
|
||||
PSB_WVDC32(dev_priv->saveDSPALINOFF, DSPALINOFF);
|
||||
PSB_WVDC32(dev_priv->saveDSPASTRIDE, DSPASTRIDE);
|
||||
PSB_WVDC32(dev_priv->saveDSPATILEOFF, DSPATILEOFF);
|
||||
PSB_WVDC32(regs->psb.saveDSPALINOFF, DSPALINOFF);
|
||||
PSB_WVDC32(regs->psb.saveDSPASTRIDE, DSPASTRIDE);
|
||||
PSB_WVDC32(regs->psb.saveDSPATILEOFF, DSPATILEOFF);
|
||||
|
||||
/* Enable the plane */
|
||||
PSB_WVDC32(dev_priv->saveDSPACNTR, DSPACNTR);
|
||||
PSB_WVDC32(dev_priv->saveDSPASURF, DSPASURF);
|
||||
PSB_WVDC32(regs->psb.saveDSPACNTR, DSPACNTR);
|
||||
PSB_WVDC32(regs->psb.saveDSPASURF, DSPASURF);
|
||||
|
||||
/* Enable Cursor A */
|
||||
PSB_WVDC32(dev_priv->saveDSPACURSOR_CTRL, CURACNTR);
|
||||
PSB_WVDC32(dev_priv->saveDSPACURSOR_POS, CURAPOS);
|
||||
PSB_WVDC32(dev_priv->saveDSPACURSOR_BASE, CURABASE);
|
||||
PSB_WVDC32(regs->psb.saveDSPACURSOR_CTRL, CURACNTR);
|
||||
PSB_WVDC32(regs->psb.saveDSPACURSOR_POS, CURAPOS);
|
||||
PSB_WVDC32(regs->psb.saveDSPACURSOR_BASE, CURABASE);
|
||||
|
||||
/* Restore palette (gamma) */
|
||||
for (i = 0; i < 256; i++)
|
||||
PSB_WVDC32(dev_priv->save_palette_a[i], PALETTE_A + (i << 2));
|
||||
PSB_WVDC32(regs->psb.save_palette_a[i], PALETTE_A + (i << 2));
|
||||
|
||||
if (dev_priv->hdmi_priv)
|
||||
oaktrail_hdmi_restore(dev);
|
||||
|
||||
if (dev_priv->iLVDS_enable) {
|
||||
PSB_WVDC32(dev_priv->saveBLC_PWM_CTL2, BLC_PWM_CTL2);
|
||||
PSB_WVDC32(dev_priv->saveLVDS, LVDS); /*port 61180h*/
|
||||
PSB_WVDC32(dev_priv->savePFIT_CONTROL, PFIT_CONTROL);
|
||||
PSB_WVDC32(dev_priv->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
|
||||
PSB_WVDC32(dev_priv->savePFIT_AUTO_RATIOS, PFIT_AUTO_RATIOS);
|
||||
PSB_WVDC32(dev_priv->saveBLC_PWM_CTL, BLC_PWM_CTL);
|
||||
PSB_WVDC32(dev_priv->savePP_ON_DELAYS, LVDSPP_ON);
|
||||
PSB_WVDC32(dev_priv->savePP_OFF_DELAYS, LVDSPP_OFF);
|
||||
PSB_WVDC32(dev_priv->savePP_DIVISOR, PP_CYCLE);
|
||||
PSB_WVDC32(dev_priv->savePP_CONTROL, PP_CONTROL);
|
||||
PSB_WVDC32(regs->saveBLC_PWM_CTL2, BLC_PWM_CTL2);
|
||||
PSB_WVDC32(regs->psb.saveLVDS, LVDS); /*port 61180h*/
|
||||
PSB_WVDC32(regs->psb.savePFIT_CONTROL, PFIT_CONTROL);
|
||||
PSB_WVDC32(regs->psb.savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
|
||||
PSB_WVDC32(regs->psb.savePFIT_AUTO_RATIOS, PFIT_AUTO_RATIOS);
|
||||
PSB_WVDC32(regs->saveBLC_PWM_CTL, BLC_PWM_CTL);
|
||||
PSB_WVDC32(regs->psb.savePP_ON_DELAYS, LVDSPP_ON);
|
||||
PSB_WVDC32(regs->psb.savePP_OFF_DELAYS, LVDSPP_OFF);
|
||||
PSB_WVDC32(regs->psb.savePP_DIVISOR, PP_CYCLE);
|
||||
PSB_WVDC32(regs->psb.savePP_CONTROL, PP_CONTROL);
|
||||
}
|
||||
|
||||
/* Wait for cycle delay */
|
||||
|
@ -388,20 +386,20 @@ static int oaktrail_restore_display_registers(struct drm_device *dev)
|
|||
} while (pp_stat & 0x10000000);
|
||||
|
||||
/* Restore HW overlay */
|
||||
PSB_WVDC32(dev_priv->saveOV_OVADD, OV_OVADD);
|
||||
PSB_WVDC32(dev_priv->saveOV_OGAMC0, OV_OGAMC0);
|
||||
PSB_WVDC32(dev_priv->saveOV_OGAMC1, OV_OGAMC1);
|
||||
PSB_WVDC32(dev_priv->saveOV_OGAMC2, OV_OGAMC2);
|
||||
PSB_WVDC32(dev_priv->saveOV_OGAMC3, OV_OGAMC3);
|
||||
PSB_WVDC32(dev_priv->saveOV_OGAMC4, OV_OGAMC4);
|
||||
PSB_WVDC32(dev_priv->saveOV_OGAMC5, OV_OGAMC5);
|
||||
PSB_WVDC32(regs->psb.saveOV_OVADD, OV_OVADD);
|
||||
PSB_WVDC32(regs->psb.saveOV_OGAMC0, OV_OGAMC0);
|
||||
PSB_WVDC32(regs->psb.saveOV_OGAMC1, OV_OGAMC1);
|
||||
PSB_WVDC32(regs->psb.saveOV_OGAMC2, OV_OGAMC2);
|
||||
PSB_WVDC32(regs->psb.saveOV_OGAMC3, OV_OGAMC3);
|
||||
PSB_WVDC32(regs->psb.saveOV_OGAMC4, OV_OGAMC4);
|
||||
PSB_WVDC32(regs->psb.saveOV_OGAMC5, OV_OGAMC5);
|
||||
|
||||
/* DPST registers */
|
||||
PSB_WVDC32(dev_priv->saveHISTOGRAM_INT_CONTROL_REG,
|
||||
PSB_WVDC32(regs->psb.saveHISTOGRAM_INT_CONTROL_REG,
|
||||
HISTOGRAM_INT_CONTROL);
|
||||
PSB_WVDC32(dev_priv->saveHISTOGRAM_LOGIC_CONTROL_REG,
|
||||
PSB_WVDC32(regs->psb.saveHISTOGRAM_LOGIC_CONTROL_REG,
|
||||
HISTOGRAM_LOGIC_CONTROL);
|
||||
PSB_WVDC32(dev_priv->savePWM_CONTROL_LOGIC, PWM_CONTROL_LOGIC);
|
||||
PSB_WVDC32(regs->psb.savePWM_CONTROL_LOGIC, PWM_CONTROL_LOGIC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -502,7 +500,6 @@ const struct psb_ops oaktrail_chip_ops = {
|
|||
.backlight_init = oaktrail_backlight_init,
|
||||
#endif
|
||||
|
||||
.init_pm = oaktrail_init_pm,
|
||||
.save_regs = oaktrail_save_display_registers,
|
||||
.restore_regs = oaktrail_restore_display_registers,
|
||||
.power_down = oaktrail_power_down,
|
||||
|
|
|
@ -125,59 +125,6 @@ static const struct oaktrail_hdmi_limit oaktrail_hdmi_limit = {
|
|||
.nf = { .min = NF_MIN, .max = NF_MAX },
|
||||
};
|
||||
|
||||
static void wait_for_vblank(struct drm_device *dev)
|
||||
{
|
||||
/* FIXME: Can we do this as a sleep ? */
|
||||
/* Wait for 20ms, i.e. one cycle at 50hz. */
|
||||
mdelay(20);
|
||||
}
|
||||
|
||||
static void scu_busy_loop(void *scu_base)
|
||||
{
|
||||
u32 status = 0;
|
||||
u32 loop_count = 0;
|
||||
|
||||
status = readl(scu_base + 0x04);
|
||||
while (status & 1) {
|
||||
udelay(1); /* scu processing time is in few u secods */
|
||||
status = readl(scu_base + 0x04);
|
||||
loop_count++;
|
||||
/* break if scu doesn't reset busy bit after huge retry */
|
||||
if (loop_count > 1000) {
|
||||
DRM_DEBUG_KMS("SCU IPC timed out");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void oaktrail_hdmi_reset(struct drm_device *dev)
|
||||
{
|
||||
void *base;
|
||||
/* FIXME: at least make these defines */
|
||||
unsigned int scu_ipc_mmio = 0xff11c000;
|
||||
int scu_len = 1024;
|
||||
|
||||
base = ioremap((resource_size_t)scu_ipc_mmio, scu_len);
|
||||
if (base == NULL) {
|
||||
DRM_ERROR("failed to map SCU mmio\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* scu ipc: assert hdmi controller reset */
|
||||
writel(0xff11d118, base + 0x0c);
|
||||
writel(0x7fffffdf, base + 0x80);
|
||||
writel(0x42005, base + 0x0);
|
||||
scu_busy_loop(base);
|
||||
|
||||
/* scu ipc: de-assert hdmi controller reset */
|
||||
writel(0xff11d118, base + 0x0c);
|
||||
writel(0x7fffffff, base + 0x80);
|
||||
writel(0x42005, base + 0x0);
|
||||
scu_busy_loop(base);
|
||||
|
||||
iounmap(base);
|
||||
}
|
||||
|
||||
static void oaktrail_hdmi_audio_enable(struct drm_device *dev)
|
||||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
|
@ -208,104 +155,6 @@ static void oaktrail_hdmi_audio_disable(struct drm_device *dev)
|
|||
HDMI_READ(HDMI_HCR);
|
||||
}
|
||||
|
||||
void oaktrail_crtc_hdmi_dpms(struct drm_crtc *crtc, int mode)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
u32 temp;
|
||||
|
||||
switch (mode) {
|
||||
case DRM_MODE_DPMS_OFF:
|
||||
/* Disable VGACNTRL */
|
||||
REG_WRITE(VGACNTRL, 0x80000000);
|
||||
|
||||
/* Disable plane */
|
||||
temp = REG_READ(DSPBCNTR);
|
||||
if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
|
||||
REG_WRITE(DSPBCNTR, temp & ~DISPLAY_PLANE_ENABLE);
|
||||
REG_READ(DSPBCNTR);
|
||||
/* Flush the plane changes */
|
||||
REG_WRITE(DSPBSURF, REG_READ(DSPBSURF));
|
||||
REG_READ(DSPBSURF);
|
||||
}
|
||||
|
||||
/* Disable pipe B */
|
||||
temp = REG_READ(PIPEBCONF);
|
||||
if ((temp & PIPEACONF_ENABLE) != 0) {
|
||||
REG_WRITE(PIPEBCONF, temp & ~PIPEACONF_ENABLE);
|
||||
REG_READ(PIPEBCONF);
|
||||
}
|
||||
|
||||
/* Disable LNW Pipes, etc */
|
||||
temp = REG_READ(PCH_PIPEBCONF);
|
||||
if ((temp & PIPEACONF_ENABLE) != 0) {
|
||||
REG_WRITE(PCH_PIPEBCONF, temp & ~PIPEACONF_ENABLE);
|
||||
REG_READ(PCH_PIPEBCONF);
|
||||
}
|
||||
/* wait for pipe off */
|
||||
udelay(150);
|
||||
/* Disable dpll */
|
||||
temp = REG_READ(DPLL_CTRL);
|
||||
if ((temp & DPLL_PWRDN) == 0) {
|
||||
REG_WRITE(DPLL_CTRL, temp | (DPLL_PWRDN | DPLL_RESET));
|
||||
REG_WRITE(DPLL_STATUS, 0x1);
|
||||
}
|
||||
/* wait for dpll off */
|
||||
udelay(150);
|
||||
break;
|
||||
case DRM_MODE_DPMS_ON:
|
||||
case DRM_MODE_DPMS_STANDBY:
|
||||
case DRM_MODE_DPMS_SUSPEND:
|
||||
/* Enable dpll */
|
||||
temp = REG_READ(DPLL_CTRL);
|
||||
if ((temp & DPLL_PWRDN) != 0) {
|
||||
REG_WRITE(DPLL_CTRL, temp & ~(DPLL_PWRDN | DPLL_RESET));
|
||||
temp = REG_READ(DPLL_CLK_ENABLE);
|
||||
REG_WRITE(DPLL_CLK_ENABLE, temp | DPLL_EN_DISP | DPLL_SEL_HDMI | DPLL_EN_HDMI);
|
||||
REG_READ(DPLL_CLK_ENABLE);
|
||||
}
|
||||
/* wait for dpll warm up */
|
||||
udelay(150);
|
||||
|
||||
/* Enable pipe B */
|
||||
temp = REG_READ(PIPEBCONF);
|
||||
if ((temp & PIPEACONF_ENABLE) == 0) {
|
||||
REG_WRITE(PIPEBCONF, temp | PIPEACONF_ENABLE);
|
||||
REG_READ(PIPEBCONF);
|
||||
}
|
||||
|
||||
/* Enable LNW Pipe B */
|
||||
temp = REG_READ(PCH_PIPEBCONF);
|
||||
if ((temp & PIPEACONF_ENABLE) == 0) {
|
||||
REG_WRITE(PCH_PIPEBCONF, temp | PIPEACONF_ENABLE);
|
||||
REG_READ(PCH_PIPEBCONF);
|
||||
}
|
||||
wait_for_vblank(dev);
|
||||
|
||||
/* Enable plane */
|
||||
temp = REG_READ(DSPBCNTR);
|
||||
if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
|
||||
REG_WRITE(DSPBCNTR, temp | DISPLAY_PLANE_ENABLE);
|
||||
/* Flush the plane changes */
|
||||
REG_WRITE(DSPBSURF, REG_READ(DSPBSURF));
|
||||
REG_READ(DSPBSURF);
|
||||
}
|
||||
psb_intel_crtc_load_lut(crtc);
|
||||
}
|
||||
/* DSPARB */
|
||||
REG_WRITE(DSPARB, 0x00003fbf);
|
||||
/* FW1 */
|
||||
REG_WRITE(0x70034, 0x3f880a0a);
|
||||
/* FW2 */
|
||||
REG_WRITE(0x70038, 0x0b060808);
|
||||
/* FW4 */
|
||||
REG_WRITE(0x70050, 0x08030404);
|
||||
/* FW5 */
|
||||
REG_WRITE(0x70054, 0x04040404);
|
||||
/* LNC Chicken Bits */
|
||||
REG_WRITE(0x70400, 0x4000);
|
||||
}
|
||||
|
||||
|
||||
static void oaktrail_hdmi_dpms(struct drm_encoder *encoder, int mode)
|
||||
{
|
||||
static int dpms_mode = -1;
|
||||
|
@ -327,182 +176,6 @@ static void oaktrail_hdmi_dpms(struct drm_encoder *encoder, int mode)
|
|||
HDMI_WRITE(HDMI_VIDEO_REG, temp);
|
||||
}
|
||||
|
||||
static unsigned int htotal_calculate(struct drm_display_mode *mode)
|
||||
{
|
||||
u32 htotal, new_crtc_htotal;
|
||||
|
||||
htotal = (mode->crtc_hdisplay - 1) | ((mode->crtc_htotal - 1) << 16);
|
||||
|
||||
/*
|
||||
* 1024 x 768 new_crtc_htotal = 0x1024;
|
||||
* 1280 x 1024 new_crtc_htotal = 0x0c34;
|
||||
*/
|
||||
new_crtc_htotal = (mode->crtc_htotal - 1) * 200 * 1000 / mode->clock;
|
||||
|
||||
return (mode->crtc_hdisplay - 1) | (new_crtc_htotal << 16);
|
||||
}
|
||||
|
||||
static void oaktrail_hdmi_find_dpll(struct drm_crtc *crtc, int target,
|
||||
int refclk, struct oaktrail_hdmi_clock *best_clock)
|
||||
{
|
||||
int np_min, np_max, nr_min, nr_max;
|
||||
int np, nr, nf;
|
||||
|
||||
np_min = DIV_ROUND_UP(oaktrail_hdmi_limit.vco.min, target * 10);
|
||||
np_max = oaktrail_hdmi_limit.vco.max / (target * 10);
|
||||
if (np_min < oaktrail_hdmi_limit.np.min)
|
||||
np_min = oaktrail_hdmi_limit.np.min;
|
||||
if (np_max > oaktrail_hdmi_limit.np.max)
|
||||
np_max = oaktrail_hdmi_limit.np.max;
|
||||
|
||||
nr_min = DIV_ROUND_UP((refclk * 1000), (target * 10 * np_max));
|
||||
nr_max = DIV_ROUND_UP((refclk * 1000), (target * 10 * np_min));
|
||||
if (nr_min < oaktrail_hdmi_limit.nr.min)
|
||||
nr_min = oaktrail_hdmi_limit.nr.min;
|
||||
if (nr_max > oaktrail_hdmi_limit.nr.max)
|
||||
nr_max = oaktrail_hdmi_limit.nr.max;
|
||||
|
||||
np = DIV_ROUND_UP((refclk * 1000), (target * 10 * nr_max));
|
||||
nr = DIV_ROUND_UP((refclk * 1000), (target * 10 * np));
|
||||
nf = DIV_ROUND_CLOSEST((target * 10 * np * nr), refclk);
|
||||
DRM_DEBUG_KMS("np, nr, nf %d %d %d\n", np, nr, nf);
|
||||
|
||||
/*
|
||||
* 1024 x 768 np = 1; nr = 0x26; nf = 0x0fd8000;
|
||||
* 1280 x 1024 np = 1; nr = 0x17; nf = 0x1034000;
|
||||
*/
|
||||
best_clock->np = np;
|
||||
best_clock->nr = nr - 1;
|
||||
best_clock->nf = (nf << 14);
|
||||
}
|
||||
|
||||
int oaktrail_crtc_hdmi_mode_set(struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode,
|
||||
int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
|
||||
int pipe = 1;
|
||||
int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
|
||||
int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
|
||||
int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
|
||||
int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
|
||||
int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
|
||||
int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
|
||||
int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;
|
||||
int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
|
||||
int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
|
||||
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
|
||||
int refclk;
|
||||
struct oaktrail_hdmi_clock clock;
|
||||
u32 dspcntr, pipeconf, dpll, temp;
|
||||
int dspcntr_reg = DSPBCNTR;
|
||||
|
||||
/* Disable the VGA plane that we never use */
|
||||
REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
|
||||
|
||||
/* XXX: Disable the panel fitter if it was on our pipe */
|
||||
|
||||
/* Disable dpll if necessary */
|
||||
dpll = REG_READ(DPLL_CTRL);
|
||||
if ((dpll & DPLL_PWRDN) == 0) {
|
||||
REG_WRITE(DPLL_CTRL, dpll | (DPLL_PWRDN | DPLL_RESET));
|
||||
REG_WRITE(DPLL_DIV_CTRL, 0x00000000);
|
||||
REG_WRITE(DPLL_STATUS, 0x1);
|
||||
}
|
||||
udelay(150);
|
||||
|
||||
/* reset controller: FIXME - can we sort out the ioremap mess ? */
|
||||
iounmap(hdmi_dev->regs);
|
||||
oaktrail_hdmi_reset(dev);
|
||||
|
||||
/* program and enable dpll */
|
||||
refclk = 25000;
|
||||
oaktrail_hdmi_find_dpll(crtc, adjusted_mode->clock, refclk, &clock);
|
||||
|
||||
/* Setting DPLL */
|
||||
dpll = REG_READ(DPLL_CTRL);
|
||||
dpll &= ~DPLL_PDIV_MASK;
|
||||
dpll &= ~(DPLL_PWRDN | DPLL_RESET);
|
||||
REG_WRITE(DPLL_CTRL, 0x00000008);
|
||||
REG_WRITE(DPLL_DIV_CTRL, ((clock.nf << 6) | clock.nr));
|
||||
REG_WRITE(DPLL_ADJUST, ((clock.nf >> 14) - 1));
|
||||
REG_WRITE(DPLL_CTRL, (dpll | (clock.np << DPLL_PDIV_SHIFT) | DPLL_ENSTAT | DPLL_DITHEN));
|
||||
REG_WRITE(DPLL_UPDATE, 0x80000000);
|
||||
REG_WRITE(DPLL_CLK_ENABLE, 0x80050102);
|
||||
udelay(150);
|
||||
|
||||
hdmi_dev->regs = ioremap(hdmi_dev->mmio, hdmi_dev->mmio_len);
|
||||
if (hdmi_dev->regs == NULL) {
|
||||
DRM_ERROR("failed to do hdmi mmio mapping\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* configure HDMI */
|
||||
HDMI_WRITE(0x1004, 0x1fd);
|
||||
HDMI_WRITE(0x2000, 0x1);
|
||||
HDMI_WRITE(0x2008, 0x0);
|
||||
HDMI_WRITE(0x3130, 0x8);
|
||||
HDMI_WRITE(0x101c, 0x1800810);
|
||||
|
||||
temp = htotal_calculate(adjusted_mode);
|
||||
REG_WRITE(htot_reg, temp);
|
||||
REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | ((adjusted_mode->crtc_hblank_end - 1) << 16));
|
||||
REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | ((adjusted_mode->crtc_hsync_end - 1) << 16));
|
||||
REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | ((adjusted_mode->crtc_vtotal - 1) << 16));
|
||||
REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | ((adjusted_mode->crtc_vblank_end - 1) << 16));
|
||||
REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16));
|
||||
REG_WRITE(pipesrc_reg,
|
||||
((mode->crtc_hdisplay - 1) << 16) | (mode->crtc_vdisplay - 1));
|
||||
|
||||
REG_WRITE(PCH_HTOTAL_B, (adjusted_mode->crtc_hdisplay - 1) | ((adjusted_mode->crtc_htotal - 1) << 16));
|
||||
REG_WRITE(PCH_HBLANK_B, (adjusted_mode->crtc_hblank_start - 1) | ((adjusted_mode->crtc_hblank_end - 1) << 16));
|
||||
REG_WRITE(PCH_HSYNC_B, (adjusted_mode->crtc_hsync_start - 1) | ((adjusted_mode->crtc_hsync_end - 1) << 16));
|
||||
REG_WRITE(PCH_VTOTAL_B, (adjusted_mode->crtc_vdisplay - 1) | ((adjusted_mode->crtc_vtotal - 1) << 16));
|
||||
REG_WRITE(PCH_VBLANK_B, (adjusted_mode->crtc_vblank_start - 1) | ((adjusted_mode->crtc_vblank_end - 1) << 16));
|
||||
REG_WRITE(PCH_VSYNC_B, (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16));
|
||||
REG_WRITE(PCH_PIPEBSRC,
|
||||
((mode->crtc_hdisplay - 1) << 16) | (mode->crtc_vdisplay - 1));
|
||||
|
||||
temp = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start;
|
||||
HDMI_WRITE(HDMI_HBLANK_A, ((adjusted_mode->crtc_hdisplay - 1) << 16) | temp);
|
||||
|
||||
REG_WRITE(dspsize_reg,
|
||||
((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
|
||||
REG_WRITE(dsppos_reg, 0);
|
||||
|
||||
/* Flush the plane changes */
|
||||
{
|
||||
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
|
||||
crtc_funcs->mode_set_base(crtc, x, y, old_fb);
|
||||
}
|
||||
|
||||
/* Set up the display plane register */
|
||||
dspcntr = REG_READ(dspcntr_reg);
|
||||
dspcntr |= DISPPLANE_GAMMA_ENABLE;
|
||||
dspcntr |= DISPPLANE_SEL_PIPE_B;
|
||||
dspcntr |= DISPLAY_PLANE_ENABLE;
|
||||
|
||||
/* setup pipeconf */
|
||||
pipeconf = REG_READ(pipeconf_reg);
|
||||
pipeconf |= PIPEACONF_ENABLE;
|
||||
|
||||
REG_WRITE(pipeconf_reg, pipeconf);
|
||||
REG_READ(pipeconf_reg);
|
||||
|
||||
REG_WRITE(PCH_PIPEBCONF, pipeconf);
|
||||
REG_READ(PCH_PIPEBCONF);
|
||||
wait_for_vblank(dev);
|
||||
|
||||
REG_WRITE(dspcntr_reg, dspcntr);
|
||||
wait_for_vblank(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oaktrail_hdmi_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
|
@ -692,7 +365,7 @@ void oaktrail_hdmi_init(struct drm_device *dev,
|
|||
|
||||
static DEFINE_PCI_DEVICE_TABLE(hdmi_ids) = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080d) },
|
||||
{}
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
void oaktrail_hdmi_setup(struct drm_device *dev)
|
||||
|
@ -766,6 +439,7 @@ void oaktrail_hdmi_save(struct drm_device *dev)
|
|||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
|
||||
struct psb_state *regs = &dev_priv->regs.psb;
|
||||
int i;
|
||||
|
||||
/* dpll */
|
||||
|
@ -776,14 +450,14 @@ void oaktrail_hdmi_save(struct drm_device *dev)
|
|||
hdmi_dev->saveDPLL_CLK_ENABLE = PSB_RVDC32(DPLL_CLK_ENABLE);
|
||||
|
||||
/* pipe B */
|
||||
dev_priv->savePIPEBCONF = PSB_RVDC32(PIPEBCONF);
|
||||
dev_priv->savePIPEBSRC = PSB_RVDC32(PIPEBSRC);
|
||||
dev_priv->saveHTOTAL_B = PSB_RVDC32(HTOTAL_B);
|
||||
dev_priv->saveHBLANK_B = PSB_RVDC32(HBLANK_B);
|
||||
dev_priv->saveHSYNC_B = PSB_RVDC32(HSYNC_B);
|
||||
dev_priv->saveVTOTAL_B = PSB_RVDC32(VTOTAL_B);
|
||||
dev_priv->saveVBLANK_B = PSB_RVDC32(VBLANK_B);
|
||||
dev_priv->saveVSYNC_B = PSB_RVDC32(VSYNC_B);
|
||||
regs->savePIPEBCONF = PSB_RVDC32(PIPEBCONF);
|
||||
regs->savePIPEBSRC = PSB_RVDC32(PIPEBSRC);
|
||||
regs->saveHTOTAL_B = PSB_RVDC32(HTOTAL_B);
|
||||
regs->saveHBLANK_B = PSB_RVDC32(HBLANK_B);
|
||||
regs->saveHSYNC_B = PSB_RVDC32(HSYNC_B);
|
||||
regs->saveVTOTAL_B = PSB_RVDC32(VTOTAL_B);
|
||||
regs->saveVBLANK_B = PSB_RVDC32(VBLANK_B);
|
||||
regs->saveVSYNC_B = PSB_RVDC32(VSYNC_B);
|
||||
|
||||
hdmi_dev->savePCH_PIPEBCONF = PSB_RVDC32(PCH_PIPEBCONF);
|
||||
hdmi_dev->savePCH_PIPEBSRC = PSB_RVDC32(PCH_PIPEBSRC);
|
||||
|
@ -795,21 +469,21 @@ void oaktrail_hdmi_save(struct drm_device *dev)
|
|||
hdmi_dev->savePCH_VSYNC_B = PSB_RVDC32(PCH_VSYNC_B);
|
||||
|
||||
/* plane */
|
||||
dev_priv->saveDSPBCNTR = PSB_RVDC32(DSPBCNTR);
|
||||
dev_priv->saveDSPBSTRIDE = PSB_RVDC32(DSPBSTRIDE);
|
||||
dev_priv->saveDSPBADDR = PSB_RVDC32(DSPBBASE);
|
||||
dev_priv->saveDSPBSURF = PSB_RVDC32(DSPBSURF);
|
||||
dev_priv->saveDSPBLINOFF = PSB_RVDC32(DSPBLINOFF);
|
||||
dev_priv->saveDSPBTILEOFF = PSB_RVDC32(DSPBTILEOFF);
|
||||
regs->saveDSPBCNTR = PSB_RVDC32(DSPBCNTR);
|
||||
regs->saveDSPBSTRIDE = PSB_RVDC32(DSPBSTRIDE);
|
||||
regs->saveDSPBADDR = PSB_RVDC32(DSPBBASE);
|
||||
regs->saveDSPBSURF = PSB_RVDC32(DSPBSURF);
|
||||
regs->saveDSPBLINOFF = PSB_RVDC32(DSPBLINOFF);
|
||||
regs->saveDSPBTILEOFF = PSB_RVDC32(DSPBTILEOFF);
|
||||
|
||||
/* cursor B */
|
||||
dev_priv->saveDSPBCURSOR_CTRL = PSB_RVDC32(CURBCNTR);
|
||||
dev_priv->saveDSPBCURSOR_BASE = PSB_RVDC32(CURBBASE);
|
||||
dev_priv->saveDSPBCURSOR_POS = PSB_RVDC32(CURBPOS);
|
||||
regs->saveDSPBCURSOR_CTRL = PSB_RVDC32(CURBCNTR);
|
||||
regs->saveDSPBCURSOR_BASE = PSB_RVDC32(CURBBASE);
|
||||
regs->saveDSPBCURSOR_POS = PSB_RVDC32(CURBPOS);
|
||||
|
||||
/* save palette */
|
||||
for (i = 0; i < 256; i++)
|
||||
dev_priv->save_palette_b[i] = PSB_RVDC32(PALETTE_B + (i << 2));
|
||||
regs->save_palette_b[i] = PSB_RVDC32(PALETTE_B + (i << 2));
|
||||
}
|
||||
|
||||
/* restore HDMI register state */
|
||||
|
@ -817,6 +491,7 @@ void oaktrail_hdmi_restore(struct drm_device *dev)
|
|||
{
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
|
||||
struct psb_state *regs = &dev_priv->regs.psb;
|
||||
int i;
|
||||
|
||||
/* dpll */
|
||||
|
@ -828,13 +503,13 @@ void oaktrail_hdmi_restore(struct drm_device *dev)
|
|||
DRM_UDELAY(150);
|
||||
|
||||
/* pipe */
|
||||
PSB_WVDC32(dev_priv->savePIPEBSRC, PIPEBSRC);
|
||||
PSB_WVDC32(dev_priv->saveHTOTAL_B, HTOTAL_B);
|
||||
PSB_WVDC32(dev_priv->saveHBLANK_B, HBLANK_B);
|
||||
PSB_WVDC32(dev_priv->saveHSYNC_B, HSYNC_B);
|
||||
PSB_WVDC32(dev_priv->saveVTOTAL_B, VTOTAL_B);
|
||||
PSB_WVDC32(dev_priv->saveVBLANK_B, VBLANK_B);
|
||||
PSB_WVDC32(dev_priv->saveVSYNC_B, VSYNC_B);
|
||||
PSB_WVDC32(regs->savePIPEBSRC, PIPEBSRC);
|
||||
PSB_WVDC32(regs->saveHTOTAL_B, HTOTAL_B);
|
||||
PSB_WVDC32(regs->saveHBLANK_B, HBLANK_B);
|
||||
PSB_WVDC32(regs->saveHSYNC_B, HSYNC_B);
|
||||
PSB_WVDC32(regs->saveVTOTAL_B, VTOTAL_B);
|
||||
PSB_WVDC32(regs->saveVBLANK_B, VBLANK_B);
|
||||
PSB_WVDC32(regs->saveVSYNC_B, VSYNC_B);
|
||||
|
||||
PSB_WVDC32(hdmi_dev->savePCH_PIPEBSRC, PCH_PIPEBSRC);
|
||||
PSB_WVDC32(hdmi_dev->savePCH_HTOTAL_B, PCH_HTOTAL_B);
|
||||
|
@ -844,22 +519,22 @@ void oaktrail_hdmi_restore(struct drm_device *dev)
|
|||
PSB_WVDC32(hdmi_dev->savePCH_VBLANK_B, PCH_VBLANK_B);
|
||||
PSB_WVDC32(hdmi_dev->savePCH_VSYNC_B, PCH_VSYNC_B);
|
||||
|
||||
PSB_WVDC32(dev_priv->savePIPEBCONF, PIPEBCONF);
|
||||
PSB_WVDC32(regs->savePIPEBCONF, PIPEBCONF);
|
||||
PSB_WVDC32(hdmi_dev->savePCH_PIPEBCONF, PCH_PIPEBCONF);
|
||||
|
||||
/* plane */
|
||||
PSB_WVDC32(dev_priv->saveDSPBLINOFF, DSPBLINOFF);
|
||||
PSB_WVDC32(dev_priv->saveDSPBSTRIDE, DSPBSTRIDE);
|
||||
PSB_WVDC32(dev_priv->saveDSPBTILEOFF, DSPBTILEOFF);
|
||||
PSB_WVDC32(dev_priv->saveDSPBCNTR, DSPBCNTR);
|
||||
PSB_WVDC32(dev_priv->saveDSPBSURF, DSPBSURF);
|
||||
PSB_WVDC32(regs->saveDSPBLINOFF, DSPBLINOFF);
|
||||
PSB_WVDC32(regs->saveDSPBSTRIDE, DSPBSTRIDE);
|
||||
PSB_WVDC32(regs->saveDSPBTILEOFF, DSPBTILEOFF);
|
||||
PSB_WVDC32(regs->saveDSPBCNTR, DSPBCNTR);
|
||||
PSB_WVDC32(regs->saveDSPBSURF, DSPBSURF);
|
||||
|
||||
/* cursor B */
|
||||
PSB_WVDC32(dev_priv->saveDSPBCURSOR_CTRL, CURBCNTR);
|
||||
PSB_WVDC32(dev_priv->saveDSPBCURSOR_POS, CURBPOS);
|
||||
PSB_WVDC32(dev_priv->saveDSPBCURSOR_BASE, CURBBASE);
|
||||
PSB_WVDC32(regs->saveDSPBCURSOR_CTRL, CURBCNTR);
|
||||
PSB_WVDC32(regs->saveDSPBCURSOR_POS, CURBPOS);
|
||||
PSB_WVDC32(regs->saveDSPBCURSOR_BASE, CURBBASE);
|
||||
|
||||
/* restore palette */
|
||||
for (i = 0; i < 256; i++)
|
||||
PSB_WVDC32(dev_priv->save_palette_b[i], PALETTE_B + (i << 2));
|
||||
PSB_WVDC32(regs->save_palette_b[i], PALETTE_B + (i << 2));
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ static int oaktrail_hdmi_i2c_access(struct i2c_adapter *adap,
|
|||
{
|
||||
struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap);
|
||||
struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev;
|
||||
int i, err = 0;
|
||||
int i;
|
||||
|
||||
mutex_lock(&i2c_dev->i2c_lock);
|
||||
|
||||
|
@ -139,9 +139,9 @@ static int oaktrail_hdmi_i2c_access(struct i2c_adapter *adap,
|
|||
for (i = 0; i < num; i++) {
|
||||
if (pmsg->len && pmsg->buf) {
|
||||
if (pmsg->flags & I2C_M_RD)
|
||||
err = xfer_read(adap, pmsg);
|
||||
xfer_read(adap, pmsg);
|
||||
else
|
||||
err = xfer_write(adap, pmsg);
|
||||
xfer_write(adap, pmsg);
|
||||
}
|
||||
pmsg++; /* next message */
|
||||
}
|
||||
|
|
|
@ -192,7 +192,7 @@ static u32 oaktrail_lvds_get_max_backlight(struct drm_device *dev)
|
|||
|
||||
gma_power_end(dev);
|
||||
} else
|
||||
ret = ((dev_priv->saveBLC_PWM_CTL &
|
||||
ret = ((dev_priv->regs.saveBLC_PWM_CTL &
|
||||
BACKLIGHT_MODULATION_FREQ_MASK) >>
|
||||
BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
|
||||
|
||||
|
@ -331,7 +331,6 @@ void oaktrail_lvds_init(struct drm_device *dev,
|
|||
struct drm_encoder *encoder;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct edid *edid;
|
||||
int ret = 0;
|
||||
struct i2c_adapter *i2c_adap;
|
||||
struct drm_display_mode *scan; /* *modes, *bios_mode; */
|
||||
|
||||
|
@ -400,7 +399,7 @@ void oaktrail_lvds_init(struct drm_device *dev,
|
|||
if (edid) {
|
||||
drm_mode_connector_update_edid_property(connector,
|
||||
edid);
|
||||
ret = drm_add_edid_modes(connector, edid);
|
||||
drm_add_edid_modes(connector, edid);
|
||||
kfree(edid);
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,8 @@ void gma_power_init(struct drm_device *dev)
|
|||
spin_lock_init(&power_ctrl_lock);
|
||||
mutex_init(&power_mutex);
|
||||
|
||||
dev_priv->ops->init_pm(dev);
|
||||
if (dev_priv->ops->init_pm)
|
||||
dev_priv->ops->init_pm(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -101,9 +102,6 @@ static void gma_resume_display(struct pci_dev *pdev)
|
|||
struct drm_device *dev = pci_get_drvdata(pdev);
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (dev_priv->suspended == false)
|
||||
return;
|
||||
|
||||
/* turn on the display power island */
|
||||
dev_priv->ops->power_up(dev);
|
||||
dev_priv->suspended = false;
|
||||
|
@ -132,9 +130,9 @@ static void gma_suspend_pci(struct pci_dev *pdev)
|
|||
|
||||
pci_save_state(pdev);
|
||||
pci_read_config_dword(pdev, 0x5C, &bsm);
|
||||
dev_priv->saveBSM = bsm;
|
||||
dev_priv->regs.saveBSM = bsm;
|
||||
pci_read_config_dword(pdev, 0xFC, &vbt);
|
||||
dev_priv->saveVBT = vbt;
|
||||
dev_priv->regs.saveVBT = vbt;
|
||||
pci_read_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, &dev_priv->msi_addr);
|
||||
pci_read_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, &dev_priv->msi_data);
|
||||
|
||||
|
@ -162,8 +160,8 @@ static bool gma_resume_pci(struct pci_dev *pdev)
|
|||
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_restore_state(pdev);
|
||||
pci_write_config_dword(pdev, 0x5c, dev_priv->saveBSM);
|
||||
pci_write_config_dword(pdev, 0xFC, dev_priv->saveVBT);
|
||||
pci_write_config_dword(pdev, 0x5c, dev_priv->regs.saveBSM);
|
||||
pci_write_config_dword(pdev, 0xFC, dev_priv->regs.saveVBT);
|
||||
/* restoring MSI address and data in PCIx space */
|
||||
pci_write_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, dev_priv->msi_addr);
|
||||
pci_write_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, dev_priv->msi_data);
|
||||
|
@ -195,6 +193,7 @@ int gma_power_suspend(struct device *_dev)
|
|||
if (!dev_priv->suspended) {
|
||||
if (dev_priv->display_count) {
|
||||
mutex_unlock(&power_mutex);
|
||||
dev_err(dev->dev, "GPU hardware busy, cannot suspend\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
psb_irq_uninstall(dev);
|
||||
|
@ -302,7 +301,7 @@ int psb_runtime_suspend(struct device *dev)
|
|||
|
||||
int psb_runtime_resume(struct device *dev)
|
||||
{
|
||||
return gma_power_resume(dev);;
|
||||
return gma_power_resume(dev);
|
||||
}
|
||||
|
||||
int psb_runtime_idle(struct device *dev)
|
||||
|
|
|
@ -177,16 +177,17 @@ static int psb_save_display_registers(struct drm_device *dev)
|
|||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_connector *connector;
|
||||
struct psb_state *regs = &dev_priv->regs.psb;
|
||||
|
||||
/* Display arbitration control + watermarks */
|
||||
dev_priv->saveDSPARB = PSB_RVDC32(DSPARB);
|
||||
dev_priv->saveDSPFW1 = PSB_RVDC32(DSPFW1);
|
||||
dev_priv->saveDSPFW2 = PSB_RVDC32(DSPFW2);
|
||||
dev_priv->saveDSPFW3 = PSB_RVDC32(DSPFW3);
|
||||
dev_priv->saveDSPFW4 = PSB_RVDC32(DSPFW4);
|
||||
dev_priv->saveDSPFW5 = PSB_RVDC32(DSPFW5);
|
||||
dev_priv->saveDSPFW6 = PSB_RVDC32(DSPFW6);
|
||||
dev_priv->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
|
||||
regs->saveDSPARB = PSB_RVDC32(DSPARB);
|
||||
regs->saveDSPFW1 = PSB_RVDC32(DSPFW1);
|
||||
regs->saveDSPFW2 = PSB_RVDC32(DSPFW2);
|
||||
regs->saveDSPFW3 = PSB_RVDC32(DSPFW3);
|
||||
regs->saveDSPFW4 = PSB_RVDC32(DSPFW4);
|
||||
regs->saveDSPFW5 = PSB_RVDC32(DSPFW5);
|
||||
regs->saveDSPFW6 = PSB_RVDC32(DSPFW6);
|
||||
regs->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
|
||||
|
||||
/* Save crtc and output state */
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
|
@ -213,16 +214,17 @@ static int psb_restore_display_registers(struct drm_device *dev)
|
|||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_connector *connector;
|
||||
struct psb_state *regs = &dev_priv->regs.psb;
|
||||
|
||||
/* Display arbitration + watermarks */
|
||||
PSB_WVDC32(dev_priv->saveDSPARB, DSPARB);
|
||||
PSB_WVDC32(dev_priv->saveDSPFW1, DSPFW1);
|
||||
PSB_WVDC32(dev_priv->saveDSPFW2, DSPFW2);
|
||||
PSB_WVDC32(dev_priv->saveDSPFW3, DSPFW3);
|
||||
PSB_WVDC32(dev_priv->saveDSPFW4, DSPFW4);
|
||||
PSB_WVDC32(dev_priv->saveDSPFW5, DSPFW5);
|
||||
PSB_WVDC32(dev_priv->saveDSPFW6, DSPFW6);
|
||||
PSB_WVDC32(dev_priv->saveCHICKENBIT, DSPCHICKENBIT);
|
||||
PSB_WVDC32(regs->saveDSPARB, DSPARB);
|
||||
PSB_WVDC32(regs->saveDSPFW1, DSPFW1);
|
||||
PSB_WVDC32(regs->saveDSPFW2, DSPFW2);
|
||||
PSB_WVDC32(regs->saveDSPFW3, DSPFW3);
|
||||
PSB_WVDC32(regs->saveDSPFW4, DSPFW4);
|
||||
PSB_WVDC32(regs->saveDSPFW5, DSPFW5);
|
||||
PSB_WVDC32(regs->saveDSPFW6, DSPFW6);
|
||||
PSB_WVDC32(regs->saveCHICKENBIT, DSPCHICKENBIT);
|
||||
|
||||
/*make sure VGA plane is off. it initializes to on after reset!*/
|
||||
PSB_WVDC32(0x80000000, VGACNTRL);
|
||||
|
|
|
@ -60,6 +60,16 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
|
|||
/* Atom E620 */
|
||||
{ 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops},
|
||||
#endif
|
||||
#if defined(CONFIG_DRM_MEDFIELD)
|
||||
{0x8086, 0x0130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
|
||||
{0x8086, 0x0131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
|
||||
{0x8086, 0x0132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
|
||||
{0x8086, 0x0133, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
|
||||
{0x8086, 0x0134, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
|
||||
{0x8086, 0x0135, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
|
||||
{0x8086, 0x0136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
|
||||
{0x8086, 0x0137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
|
||||
#endif
|
||||
#if defined(CONFIG_DRM_GMA3600)
|
||||
{ 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
|
||||
{ 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
|
||||
|
@ -70,7 +80,7 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
|
|||
{ 0x8086, 0x0be6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
|
||||
{ 0x8086, 0x0be7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
|
||||
#endif
|
||||
{ 0, 0, 0}
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pciidlist);
|
||||
|
||||
|
@ -78,27 +88,27 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
|
|||
* Standard IOCTLs.
|
||||
*/
|
||||
|
||||
#define DRM_IOCTL_PSB_ADB \
|
||||
#define DRM_IOCTL_GMA_ADB \
|
||||
DRM_IOWR(DRM_GMA_ADB + DRM_COMMAND_BASE, uint32_t)
|
||||
#define DRM_IOCTL_PSB_MODE_OPERATION \
|
||||
#define DRM_IOCTL_GMA_MODE_OPERATION \
|
||||
DRM_IOWR(DRM_GMA_MODE_OPERATION + DRM_COMMAND_BASE, \
|
||||
struct drm_psb_mode_operation_arg)
|
||||
#define DRM_IOCTL_PSB_STOLEN_MEMORY \
|
||||
#define DRM_IOCTL_GMA_STOLEN_MEMORY \
|
||||
DRM_IOWR(DRM_GMA_STOLEN_MEMORY + DRM_COMMAND_BASE, \
|
||||
struct drm_psb_stolen_memory_arg)
|
||||
#define DRM_IOCTL_PSB_GAMMA \
|
||||
#define DRM_IOCTL_GMA_GAMMA \
|
||||
DRM_IOWR(DRM_GMA_GAMMA + DRM_COMMAND_BASE, \
|
||||
struct drm_psb_dpst_lut_arg)
|
||||
#define DRM_IOCTL_PSB_DPST_BL \
|
||||
#define DRM_IOCTL_GMA_DPST_BL \
|
||||
DRM_IOWR(DRM_GMA_DPST_BL + DRM_COMMAND_BASE, \
|
||||
uint32_t)
|
||||
#define DRM_IOCTL_PSB_GET_PIPE_FROM_CRTC_ID \
|
||||
#define DRM_IOCTL_GMA_GET_PIPE_FROM_CRTC_ID \
|
||||
DRM_IOWR(DRM_GMA_GET_PIPE_FROM_CRTC_ID + DRM_COMMAND_BASE, \
|
||||
struct drm_psb_get_pipe_from_crtc_id_arg)
|
||||
#define DRM_IOCTL_PSB_GEM_CREATE \
|
||||
#define DRM_IOCTL_GMA_GEM_CREATE \
|
||||
DRM_IOWR(DRM_GMA_GEM_CREATE + DRM_COMMAND_BASE, \
|
||||
struct drm_psb_gem_create)
|
||||
#define DRM_IOCTL_PSB_GEM_MMAP \
|
||||
#define DRM_IOCTL_GMA_GEM_MMAP \
|
||||
DRM_IOWR(DRM_GMA_GEM_MMAP + DRM_COMMAND_BASE, \
|
||||
struct drm_psb_gem_mmap)
|
||||
|
||||
|
@ -113,22 +123,19 @@ static int psb_gamma_ioctl(struct drm_device *dev, void *data,
|
|||
static int psb_dpst_bl_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
#define PSB_IOCTL_DEF(ioctl, func, flags) \
|
||||
[DRM_IOCTL_NR(ioctl) - DRM_COMMAND_BASE] = {ioctl, flags, func}
|
||||
|
||||
static struct drm_ioctl_desc psb_ioctls[] = {
|
||||
PSB_IOCTL_DEF(DRM_IOCTL_PSB_ADB, psb_adb_ioctl, DRM_AUTH),
|
||||
PSB_IOCTL_DEF(DRM_IOCTL_PSB_MODE_OPERATION, psb_mode_operation_ioctl,
|
||||
DRM_IOCTL_DEF_DRV(GMA_ADB, psb_adb_ioctl, DRM_AUTH),
|
||||
DRM_IOCTL_DEF_DRV(GMA_MODE_OPERATION, psb_mode_operation_ioctl,
|
||||
DRM_AUTH),
|
||||
PSB_IOCTL_DEF(DRM_IOCTL_PSB_STOLEN_MEMORY, psb_stolen_memory_ioctl,
|
||||
DRM_IOCTL_DEF_DRV(GMA_STOLEN_MEMORY, psb_stolen_memory_ioctl,
|
||||
DRM_AUTH),
|
||||
PSB_IOCTL_DEF(DRM_IOCTL_PSB_GAMMA, psb_gamma_ioctl, DRM_AUTH),
|
||||
PSB_IOCTL_DEF(DRM_IOCTL_PSB_DPST_BL, psb_dpst_bl_ioctl, DRM_AUTH),
|
||||
PSB_IOCTL_DEF(DRM_IOCTL_PSB_GET_PIPE_FROM_CRTC_ID,
|
||||
DRM_IOCTL_DEF_DRV(GMA_GAMMA, psb_gamma_ioctl, DRM_AUTH),
|
||||
DRM_IOCTL_DEF_DRV(GMA_DPST_BL, psb_dpst_bl_ioctl, DRM_AUTH),
|
||||
DRM_IOCTL_DEF_DRV(GMA_GET_PIPE_FROM_CRTC_ID,
|
||||
psb_intel_get_pipe_from_crtc_id, 0),
|
||||
PSB_IOCTL_DEF(DRM_IOCTL_PSB_GEM_CREATE, psb_gem_create_ioctl,
|
||||
DRM_IOCTL_DEF_DRV(GMA_GEM_CREATE, psb_gem_create_ioctl,
|
||||
DRM_UNLOCKED | DRM_AUTH),
|
||||
PSB_IOCTL_DEF(DRM_IOCTL_PSB_GEM_MMAP, psb_gem_mmap_ioctl,
|
||||
DRM_IOCTL_DEF_DRV(GMA_GEM_MMAP, psb_gem_mmap_ioctl,
|
||||
DRM_UNLOCKED | DRM_AUTH),
|
||||
};
|
||||
|
||||
|
@ -268,10 +275,8 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
|
|||
{
|
||||
struct drm_psb_private *dev_priv;
|
||||
unsigned long resource_start;
|
||||
struct psb_gtt *pg;
|
||||
unsigned long irqflags;
|
||||
int ret = -ENOMEM;
|
||||
uint32_t tt_pages;
|
||||
struct drm_connector *connector;
|
||||
struct psb_intel_encoder *psb_intel_encoder;
|
||||
|
||||
|
@ -283,6 +288,8 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
|
|||
dev_priv->dev = dev;
|
||||
dev->dev_private = (void *) dev_priv;
|
||||
|
||||
pci_set_master(dev->pdev);
|
||||
|
||||
if (!IS_PSB(dev)) {
|
||||
if (pci_enable_msi(dev->pdev))
|
||||
dev_warn(dev->dev, "Enabling MSI failed!\n");
|
||||
|
@ -327,12 +334,6 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
|
|||
if (!dev_priv->mmu)
|
||||
goto out_err;
|
||||
|
||||
pg = &dev_priv->gtt;
|
||||
|
||||
tt_pages = (pg->gatt_pages < PSB_TT_PRIV0_PLIMIT) ?
|
||||
(pg->gatt_pages) : PSB_TT_PRIV0_PLIMIT;
|
||||
|
||||
|
||||
dev_priv->pf_pd = psb_mmu_alloc_pd(dev_priv->mmu, 1, 0);
|
||||
if (!dev_priv->pf_pd)
|
||||
goto out_err;
|
||||
|
@ -409,7 +410,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int psb_driver_device_is_agp(struct drm_device *dev)
|
||||
static int psb_driver_device_is_agp(struct drm_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -600,7 +601,7 @@ static long psb_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||
/* When a client dies:
|
||||
* - Check for and clean up flipped page state
|
||||
*/
|
||||
void psb_driver_preclose(struct drm_device *dev, struct drm_file *priv)
|
||||
static void psb_driver_preclose(struct drm_device *dev, struct drm_file *priv)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -677,7 +678,9 @@ static struct pci_driver psb_pci_driver = {
|
|||
.id_table = pciidlist,
|
||||
.probe = psb_probe,
|
||||
.remove = psb_remove,
|
||||
.driver.pm = &psb_pm_ops,
|
||||
.driver = {
|
||||
.pm = &psb_pm_ops,
|
||||
}
|
||||
};
|
||||
|
||||
static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
|
|
@ -276,6 +276,217 @@ struct intel_gmbus {
|
|||
u32 reg0;
|
||||
};
|
||||
|
||||
/*
|
||||
* Register save state. This is used to hold the context when the
|
||||
* device is powered off. In the case of Oaktrail this can (but does not
|
||||
* yet) include screen blank. Operations occuring during the save
|
||||
* update the register cache instead.
|
||||
*/
|
||||
struct psb_state {
|
||||
uint32_t saveDSPACNTR;
|
||||
uint32_t saveDSPBCNTR;
|
||||
uint32_t savePIPEACONF;
|
||||
uint32_t savePIPEBCONF;
|
||||
uint32_t savePIPEASRC;
|
||||
uint32_t savePIPEBSRC;
|
||||
uint32_t saveFPA0;
|
||||
uint32_t saveFPA1;
|
||||
uint32_t saveDPLL_A;
|
||||
uint32_t saveDPLL_A_MD;
|
||||
uint32_t saveHTOTAL_A;
|
||||
uint32_t saveHBLANK_A;
|
||||
uint32_t saveHSYNC_A;
|
||||
uint32_t saveVTOTAL_A;
|
||||
uint32_t saveVBLANK_A;
|
||||
uint32_t saveVSYNC_A;
|
||||
uint32_t saveDSPASTRIDE;
|
||||
uint32_t saveDSPASIZE;
|
||||
uint32_t saveDSPAPOS;
|
||||
uint32_t saveDSPABASE;
|
||||
uint32_t saveDSPASURF;
|
||||
uint32_t saveDSPASTATUS;
|
||||
uint32_t saveFPB0;
|
||||
uint32_t saveFPB1;
|
||||
uint32_t saveDPLL_B;
|
||||
uint32_t saveDPLL_B_MD;
|
||||
uint32_t saveHTOTAL_B;
|
||||
uint32_t saveHBLANK_B;
|
||||
uint32_t saveHSYNC_B;
|
||||
uint32_t saveVTOTAL_B;
|
||||
uint32_t saveVBLANK_B;
|
||||
uint32_t saveVSYNC_B;
|
||||
uint32_t saveDSPBSTRIDE;
|
||||
uint32_t saveDSPBSIZE;
|
||||
uint32_t saveDSPBPOS;
|
||||
uint32_t saveDSPBBASE;
|
||||
uint32_t saveDSPBSURF;
|
||||
uint32_t saveDSPBSTATUS;
|
||||
uint32_t saveVCLK_DIVISOR_VGA0;
|
||||
uint32_t saveVCLK_DIVISOR_VGA1;
|
||||
uint32_t saveVCLK_POST_DIV;
|
||||
uint32_t saveVGACNTRL;
|
||||
uint32_t saveADPA;
|
||||
uint32_t saveLVDS;
|
||||
uint32_t saveDVOA;
|
||||
uint32_t saveDVOB;
|
||||
uint32_t saveDVOC;
|
||||
uint32_t savePP_ON;
|
||||
uint32_t savePP_OFF;
|
||||
uint32_t savePP_CONTROL;
|
||||
uint32_t savePP_CYCLE;
|
||||
uint32_t savePFIT_CONTROL;
|
||||
uint32_t savePaletteA[256];
|
||||
uint32_t savePaletteB[256];
|
||||
uint32_t saveCLOCKGATING;
|
||||
uint32_t saveDSPARB;
|
||||
uint32_t saveDSPATILEOFF;
|
||||
uint32_t saveDSPBTILEOFF;
|
||||
uint32_t saveDSPAADDR;
|
||||
uint32_t saveDSPBADDR;
|
||||
uint32_t savePFIT_AUTO_RATIOS;
|
||||
uint32_t savePFIT_PGM_RATIOS;
|
||||
uint32_t savePP_ON_DELAYS;
|
||||
uint32_t savePP_OFF_DELAYS;
|
||||
uint32_t savePP_DIVISOR;
|
||||
uint32_t saveBCLRPAT_A;
|
||||
uint32_t saveBCLRPAT_B;
|
||||
uint32_t saveDSPALINOFF;
|
||||
uint32_t saveDSPBLINOFF;
|
||||
uint32_t savePERF_MODE;
|
||||
uint32_t saveDSPFW1;
|
||||
uint32_t saveDSPFW2;
|
||||
uint32_t saveDSPFW3;
|
||||
uint32_t saveDSPFW4;
|
||||
uint32_t saveDSPFW5;
|
||||
uint32_t saveDSPFW6;
|
||||
uint32_t saveCHICKENBIT;
|
||||
uint32_t saveDSPACURSOR_CTRL;
|
||||
uint32_t saveDSPBCURSOR_CTRL;
|
||||
uint32_t saveDSPACURSOR_BASE;
|
||||
uint32_t saveDSPBCURSOR_BASE;
|
||||
uint32_t saveDSPACURSOR_POS;
|
||||
uint32_t saveDSPBCURSOR_POS;
|
||||
uint32_t save_palette_a[256];
|
||||
uint32_t save_palette_b[256];
|
||||
uint32_t saveOV_OVADD;
|
||||
uint32_t saveOV_OGAMC0;
|
||||
uint32_t saveOV_OGAMC1;
|
||||
uint32_t saveOV_OGAMC2;
|
||||
uint32_t saveOV_OGAMC3;
|
||||
uint32_t saveOV_OGAMC4;
|
||||
uint32_t saveOV_OGAMC5;
|
||||
uint32_t saveOVC_OVADD;
|
||||
uint32_t saveOVC_OGAMC0;
|
||||
uint32_t saveOVC_OGAMC1;
|
||||
uint32_t saveOVC_OGAMC2;
|
||||
uint32_t saveOVC_OGAMC3;
|
||||
uint32_t saveOVC_OGAMC4;
|
||||
uint32_t saveOVC_OGAMC5;
|
||||
|
||||
/* DPST register save */
|
||||
uint32_t saveHISTOGRAM_INT_CONTROL_REG;
|
||||
uint32_t saveHISTOGRAM_LOGIC_CONTROL_REG;
|
||||
uint32_t savePWM_CONTROL_LOGIC;
|
||||
};
|
||||
|
||||
struct medfield_state {
|
||||
uint32_t saveDPLL_A;
|
||||
uint32_t saveFPA0;
|
||||
uint32_t savePIPEACONF;
|
||||
uint32_t saveHTOTAL_A;
|
||||
uint32_t saveHBLANK_A;
|
||||
uint32_t saveHSYNC_A;
|
||||
uint32_t saveVTOTAL_A;
|
||||
uint32_t saveVBLANK_A;
|
||||
uint32_t saveVSYNC_A;
|
||||
uint32_t savePIPEASRC;
|
||||
uint32_t saveDSPASTRIDE;
|
||||
uint32_t saveDSPALINOFF;
|
||||
uint32_t saveDSPATILEOFF;
|
||||
uint32_t saveDSPASIZE;
|
||||
uint32_t saveDSPAPOS;
|
||||
uint32_t saveDSPASURF;
|
||||
uint32_t saveDSPACNTR;
|
||||
uint32_t saveDSPASTATUS;
|
||||
uint32_t save_palette_a[256];
|
||||
uint32_t saveMIPI;
|
||||
|
||||
uint32_t saveDPLL_B;
|
||||
uint32_t saveFPB0;
|
||||
uint32_t savePIPEBCONF;
|
||||
uint32_t saveHTOTAL_B;
|
||||
uint32_t saveHBLANK_B;
|
||||
uint32_t saveHSYNC_B;
|
||||
uint32_t saveVTOTAL_B;
|
||||
uint32_t saveVBLANK_B;
|
||||
uint32_t saveVSYNC_B;
|
||||
uint32_t savePIPEBSRC;
|
||||
uint32_t saveDSPBSTRIDE;
|
||||
uint32_t saveDSPBLINOFF;
|
||||
uint32_t saveDSPBTILEOFF;
|
||||
uint32_t saveDSPBSIZE;
|
||||
uint32_t saveDSPBPOS;
|
||||
uint32_t saveDSPBSURF;
|
||||
uint32_t saveDSPBCNTR;
|
||||
uint32_t saveDSPBSTATUS;
|
||||
uint32_t save_palette_b[256];
|
||||
|
||||
uint32_t savePIPECCONF;
|
||||
uint32_t saveHTOTAL_C;
|
||||
uint32_t saveHBLANK_C;
|
||||
uint32_t saveHSYNC_C;
|
||||
uint32_t saveVTOTAL_C;
|
||||
uint32_t saveVBLANK_C;
|
||||
uint32_t saveVSYNC_C;
|
||||
uint32_t savePIPECSRC;
|
||||
uint32_t saveDSPCSTRIDE;
|
||||
uint32_t saveDSPCLINOFF;
|
||||
uint32_t saveDSPCTILEOFF;
|
||||
uint32_t saveDSPCSIZE;
|
||||
uint32_t saveDSPCPOS;
|
||||
uint32_t saveDSPCSURF;
|
||||
uint32_t saveDSPCCNTR;
|
||||
uint32_t saveDSPCSTATUS;
|
||||
uint32_t save_palette_c[256];
|
||||
uint32_t saveMIPI_C;
|
||||
|
||||
uint32_t savePFIT_CONTROL;
|
||||
uint32_t savePFIT_PGM_RATIOS;
|
||||
uint32_t saveHDMIPHYMISCCTL;
|
||||
uint32_t saveHDMIB_CONTROL;
|
||||
};
|
||||
|
||||
struct cdv_state {
|
||||
uint32_t saveDSPCLK_GATE_D;
|
||||
uint32_t saveRAMCLK_GATE_D;
|
||||
uint32_t saveDSPARB;
|
||||
uint32_t saveDSPFW[6];
|
||||
uint32_t saveADPA;
|
||||
uint32_t savePP_CONTROL;
|
||||
uint32_t savePFIT_PGM_RATIOS;
|
||||
uint32_t saveLVDS;
|
||||
uint32_t savePFIT_CONTROL;
|
||||
uint32_t savePP_ON_DELAYS;
|
||||
uint32_t savePP_OFF_DELAYS;
|
||||
uint32_t savePP_CYCLE;
|
||||
uint32_t saveVGACNTRL;
|
||||
uint32_t saveIER;
|
||||
uint32_t saveIMR;
|
||||
u8 saveLBB;
|
||||
};
|
||||
|
||||
struct psb_save_area {
|
||||
uint32_t saveBSM;
|
||||
uint32_t saveVBT;
|
||||
union {
|
||||
struct psb_state psb;
|
||||
struct medfield_state mdfld;
|
||||
struct cdv_state cdv;
|
||||
};
|
||||
uint32_t saveBLC_PWM_CTL2;
|
||||
uint32_t saveBLC_PWM_CTL;
|
||||
};
|
||||
|
||||
struct psb_ops;
|
||||
|
||||
#define PSB_NUM_PIPE 3
|
||||
|
@ -397,215 +608,20 @@ struct drm_psb_private {
|
|||
struct oaktrail_vbt vbt_data;
|
||||
struct oaktrail_gct_data gct_data;
|
||||
|
||||
/* MIPI Panel type etc */
|
||||
int panel_id;
|
||||
bool dual_mipi; /* dual display - DPI & DBI */
|
||||
bool dpi_panel_on; /* The DPI panel power is on */
|
||||
bool dpi_panel_on2; /* The DPI panel power is on */
|
||||
bool dbi_panel_on; /* The DBI panel power is on */
|
||||
bool dbi_panel_on2; /* The DBI panel power is on */
|
||||
u32 dsr_fb_update; /* DSR FB update counter */
|
||||
|
||||
/* Moorestown HDMI state */
|
||||
/* Oaktrail HDMI state */
|
||||
struct oaktrail_hdmi_dev *hdmi_priv;
|
||||
|
||||
/* Moorestown pipe config register value cache */
|
||||
uint32_t pipeconf;
|
||||
uint32_t pipeconf1;
|
||||
uint32_t pipeconf2;
|
||||
|
||||
/* Moorestown plane control register value cache */
|
||||
uint32_t dspcntr;
|
||||
uint32_t dspcntr1;
|
||||
uint32_t dspcntr2;
|
||||
|
||||
/* Moorestown MM backlight cache */
|
||||
uint8_t saveBKLTCNT;
|
||||
uint8_t saveBKLTREQ;
|
||||
uint8_t saveBKLTBRTL;
|
||||
|
||||
|
||||
/*
|
||||
* Register state
|
||||
*/
|
||||
uint32_t saveDSPACNTR;
|
||||
uint32_t saveDSPBCNTR;
|
||||
uint32_t savePIPEACONF;
|
||||
uint32_t savePIPEBCONF;
|
||||
uint32_t savePIPEASRC;
|
||||
uint32_t savePIPEBSRC;
|
||||
uint32_t saveFPA0;
|
||||
uint32_t saveFPA1;
|
||||
uint32_t saveDPLL_A;
|
||||
uint32_t saveDPLL_A_MD;
|
||||
uint32_t saveHTOTAL_A;
|
||||
uint32_t saveHBLANK_A;
|
||||
uint32_t saveHSYNC_A;
|
||||
uint32_t saveVTOTAL_A;
|
||||
uint32_t saveVBLANK_A;
|
||||
uint32_t saveVSYNC_A;
|
||||
uint32_t saveDSPASTRIDE;
|
||||
uint32_t saveDSPASIZE;
|
||||
uint32_t saveDSPAPOS;
|
||||
uint32_t saveDSPABASE;
|
||||
uint32_t saveDSPASURF;
|
||||
uint32_t saveDSPASTATUS;
|
||||
uint32_t saveFPB0;
|
||||
uint32_t saveFPB1;
|
||||
uint32_t saveDPLL_B;
|
||||
uint32_t saveDPLL_B_MD;
|
||||
uint32_t saveHTOTAL_B;
|
||||
uint32_t saveHBLANK_B;
|
||||
uint32_t saveHSYNC_B;
|
||||
uint32_t saveVTOTAL_B;
|
||||
uint32_t saveVBLANK_B;
|
||||
uint32_t saveVSYNC_B;
|
||||
uint32_t saveDSPBSTRIDE;
|
||||
uint32_t saveDSPBSIZE;
|
||||
uint32_t saveDSPBPOS;
|
||||
uint32_t saveDSPBBASE;
|
||||
uint32_t saveDSPBSURF;
|
||||
uint32_t saveDSPBSTATUS;
|
||||
uint32_t saveVCLK_DIVISOR_VGA0;
|
||||
uint32_t saveVCLK_DIVISOR_VGA1;
|
||||
uint32_t saveVCLK_POST_DIV;
|
||||
uint32_t saveVGACNTRL;
|
||||
uint32_t saveADPA;
|
||||
uint32_t saveLVDS;
|
||||
uint32_t saveDVOA;
|
||||
uint32_t saveDVOB;
|
||||
uint32_t saveDVOC;
|
||||
uint32_t savePP_ON;
|
||||
uint32_t savePP_OFF;
|
||||
uint32_t savePP_CONTROL;
|
||||
uint32_t savePP_CYCLE;
|
||||
uint32_t savePFIT_CONTROL;
|
||||
uint32_t savePaletteA[256];
|
||||
uint32_t savePaletteB[256];
|
||||
uint32_t saveBLC_PWM_CTL2;
|
||||
uint32_t saveBLC_PWM_CTL;
|
||||
uint32_t saveCLOCKGATING;
|
||||
uint32_t saveDSPARB;
|
||||
uint32_t saveDSPATILEOFF;
|
||||
uint32_t saveDSPBTILEOFF;
|
||||
uint32_t saveDSPAADDR;
|
||||
uint32_t saveDSPBADDR;
|
||||
uint32_t savePFIT_AUTO_RATIOS;
|
||||
uint32_t savePFIT_PGM_RATIOS;
|
||||
uint32_t savePP_ON_DELAYS;
|
||||
uint32_t savePP_OFF_DELAYS;
|
||||
uint32_t savePP_DIVISOR;
|
||||
uint32_t saveBSM;
|
||||
uint32_t saveVBT;
|
||||
uint32_t saveBCLRPAT_A;
|
||||
uint32_t saveBCLRPAT_B;
|
||||
uint32_t saveDSPALINOFF;
|
||||
uint32_t saveDSPBLINOFF;
|
||||
uint32_t savePERF_MODE;
|
||||
uint32_t saveDSPFW1;
|
||||
uint32_t saveDSPFW2;
|
||||
uint32_t saveDSPFW3;
|
||||
uint32_t saveDSPFW4;
|
||||
uint32_t saveDSPFW5;
|
||||
uint32_t saveDSPFW6;
|
||||
uint32_t saveCHICKENBIT;
|
||||
uint32_t saveDSPACURSOR_CTRL;
|
||||
uint32_t saveDSPBCURSOR_CTRL;
|
||||
uint32_t saveDSPACURSOR_BASE;
|
||||
uint32_t saveDSPBCURSOR_BASE;
|
||||
uint32_t saveDSPACURSOR_POS;
|
||||
uint32_t saveDSPBCURSOR_POS;
|
||||
uint32_t save_palette_a[256];
|
||||
uint32_t save_palette_b[256];
|
||||
uint32_t saveOV_OVADD;
|
||||
uint32_t saveOV_OGAMC0;
|
||||
uint32_t saveOV_OGAMC1;
|
||||
uint32_t saveOV_OGAMC2;
|
||||
uint32_t saveOV_OGAMC3;
|
||||
uint32_t saveOV_OGAMC4;
|
||||
uint32_t saveOV_OGAMC5;
|
||||
uint32_t saveOVC_OVADD;
|
||||
uint32_t saveOVC_OGAMC0;
|
||||
uint32_t saveOVC_OGAMC1;
|
||||
uint32_t saveOVC_OGAMC2;
|
||||
uint32_t saveOVC_OGAMC3;
|
||||
uint32_t saveOVC_OGAMC4;
|
||||
uint32_t saveOVC_OGAMC5;
|
||||
|
||||
struct psb_save_area regs;
|
||||
|
||||
/* MSI reg save */
|
||||
uint32_t msi_addr;
|
||||
uint32_t msi_data;
|
||||
|
||||
/* Medfield specific register save state */
|
||||
uint32_t saveHDMIPHYMISCCTL;
|
||||
uint32_t saveHDMIB_CONTROL;
|
||||
uint32_t saveDSPCCNTR;
|
||||
uint32_t savePIPECCONF;
|
||||
uint32_t savePIPECSRC;
|
||||
uint32_t saveHTOTAL_C;
|
||||
uint32_t saveHBLANK_C;
|
||||
uint32_t saveHSYNC_C;
|
||||
uint32_t saveVTOTAL_C;
|
||||
uint32_t saveVBLANK_C;
|
||||
uint32_t saveVSYNC_C;
|
||||
uint32_t saveDSPCSTRIDE;
|
||||
uint32_t saveDSPCSIZE;
|
||||
uint32_t saveDSPCPOS;
|
||||
uint32_t saveDSPCSURF;
|
||||
uint32_t saveDSPCSTATUS;
|
||||
uint32_t saveDSPCLINOFF;
|
||||
uint32_t saveDSPCTILEOFF;
|
||||
uint32_t saveDSPCCURSOR_CTRL;
|
||||
uint32_t saveDSPCCURSOR_BASE;
|
||||
uint32_t saveDSPCCURSOR_POS;
|
||||
uint32_t save_palette_c[256];
|
||||
uint32_t saveOV_OVADD_C;
|
||||
uint32_t saveOV_OGAMC0_C;
|
||||
uint32_t saveOV_OGAMC1_C;
|
||||
uint32_t saveOV_OGAMC2_C;
|
||||
uint32_t saveOV_OGAMC3_C;
|
||||
uint32_t saveOV_OGAMC4_C;
|
||||
uint32_t saveOV_OGAMC5_C;
|
||||
|
||||
/* DSI register save */
|
||||
uint32_t saveDEVICE_READY_REG;
|
||||
uint32_t saveINTR_EN_REG;
|
||||
uint32_t saveDSI_FUNC_PRG_REG;
|
||||
uint32_t saveHS_TX_TIMEOUT_REG;
|
||||
uint32_t saveLP_RX_TIMEOUT_REG;
|
||||
uint32_t saveTURN_AROUND_TIMEOUT_REG;
|
||||
uint32_t saveDEVICE_RESET_REG;
|
||||
uint32_t saveDPI_RESOLUTION_REG;
|
||||
uint32_t saveHORIZ_SYNC_PAD_COUNT_REG;
|
||||
uint32_t saveHORIZ_BACK_PORCH_COUNT_REG;
|
||||
uint32_t saveHORIZ_FRONT_PORCH_COUNT_REG;
|
||||
uint32_t saveHORIZ_ACTIVE_AREA_COUNT_REG;
|
||||
uint32_t saveVERT_SYNC_PAD_COUNT_REG;
|
||||
uint32_t saveVERT_BACK_PORCH_COUNT_REG;
|
||||
uint32_t saveVERT_FRONT_PORCH_COUNT_REG;
|
||||
uint32_t saveHIGH_LOW_SWITCH_COUNT_REG;
|
||||
uint32_t saveINIT_COUNT_REG;
|
||||
uint32_t saveMAX_RET_PAK_REG;
|
||||
uint32_t saveVIDEO_FMT_REG;
|
||||
uint32_t saveEOT_DISABLE_REG;
|
||||
uint32_t saveLP_BYTECLK_REG;
|
||||
uint32_t saveHS_LS_DBI_ENABLE_REG;
|
||||
uint32_t saveTXCLKESC_REG;
|
||||
uint32_t saveDPHY_PARAM_REG;
|
||||
uint32_t saveMIPI_CONTROL_REG;
|
||||
uint32_t saveMIPI;
|
||||
uint32_t saveMIPI_C;
|
||||
|
||||
/* DPST register save */
|
||||
uint32_t saveHISTOGRAM_INT_CONTROL_REG;
|
||||
uint32_t saveHISTOGRAM_LOGIC_CONTROL_REG;
|
||||
uint32_t savePWM_CONTROL_LOGIC;
|
||||
|
||||
/*
|
||||
* DSI info.
|
||||
*/
|
||||
void * dbi_dsr_info;
|
||||
void * dbi_dpu_info;
|
||||
void * dsi_configs[2];
|
||||
/*
|
||||
* LID-Switch
|
||||
*/
|
||||
|
@ -635,6 +651,24 @@ struct drm_psb_private {
|
|||
|
||||
/* 2D acceleration */
|
||||
spinlock_t lock_2d;
|
||||
|
||||
/*
|
||||
* Panel brightness
|
||||
*/
|
||||
int brightness;
|
||||
int brightness_adjusted;
|
||||
|
||||
bool dsr_enable;
|
||||
u32 dsr_fb_update;
|
||||
bool dpi_panel_on[3];
|
||||
void *dsi_configs[2];
|
||||
u32 bpp;
|
||||
u32 bpp2;
|
||||
|
||||
u32 pipeconf[3];
|
||||
u32 dspcntr[3];
|
||||
|
||||
int mdfld_panel_id;
|
||||
};
|
||||
|
||||
|
||||
|
@ -830,6 +864,9 @@ extern const struct psb_ops psb_chip_ops;
|
|||
/* oaktrail_device.c */
|
||||
extern const struct psb_ops oaktrail_chip_ops;
|
||||
|
||||
/* mdlfd_device.c */
|
||||
extern const struct psb_ops mdfld_chip_ops;
|
||||
|
||||
/* cdv_device.c */
|
||||
extern const struct psb_ops cdv_chip_ops;
|
||||
|
||||
|
|
|
@ -333,7 +333,7 @@ void psb_intel_wait_for_vblank(struct drm_device *dev)
|
|||
mdelay(20);
|
||||
}
|
||||
|
||||
int psb_intel_pipe_set_base(struct drm_crtc *crtc,
|
||||
static int psb_intel_pipe_set_base(struct drm_crtc *crtc,
|
||||
int x, int y, struct drm_framebuffer *old_fb)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
|
@ -433,7 +433,6 @@ static void psb_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE;
|
||||
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
|
||||
u32 temp;
|
||||
bool enabled;
|
||||
|
||||
/* XXX: When our outputs are all unaware of DPMS modes other than off
|
||||
* and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
|
||||
|
@ -518,8 +517,6 @@ static void psb_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
break;
|
||||
}
|
||||
|
||||
enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF;
|
||||
|
||||
/*Set FIFO Watermarks*/
|
||||
REG_WRITE(DSPARB, 0x3F3E);
|
||||
}
|
||||
|
@ -611,8 +608,8 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
int refclk;
|
||||
struct psb_intel_clock_t clock;
|
||||
u32 dpll = 0, fp = 0, dspcntr, pipeconf;
|
||||
bool ok, is_sdvo = false, is_dvo = false;
|
||||
bool is_crt = false, is_lvds = false, is_tv = false;
|
||||
bool ok, is_sdvo = false;
|
||||
bool is_lvds = false, is_tv = false;
|
||||
struct drm_mode_config *mode_config = &dev->mode_config;
|
||||
struct drm_connector *connector;
|
||||
|
||||
|
@ -637,15 +634,9 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
case INTEL_OUTPUT_SDVO:
|
||||
is_sdvo = true;
|
||||
break;
|
||||
case INTEL_OUTPUT_DVO:
|
||||
is_dvo = true;
|
||||
break;
|
||||
case INTEL_OUTPUT_TVOUT:
|
||||
is_tv = true;
|
||||
break;
|
||||
case INTEL_OUTPUT_ANALOG:
|
||||
is_crt = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -845,7 +836,7 @@ void psb_intel_crtc_load_lut(struct drm_crtc *crtc)
|
|||
gma_power_end(dev);
|
||||
} else {
|
||||
for (i = 0; i < 256; i++) {
|
||||
dev_priv->save_palette_a[i] =
|
||||
dev_priv->regs.psb.save_palette_a[i] =
|
||||
((psb_intel_crtc->lut_r[i] +
|
||||
psb_intel_crtc->lut_adj[i]) << 16) |
|
||||
((psb_intel_crtc->lut_g[i] +
|
||||
|
@ -1141,18 +1132,20 @@ static int psb_intel_crtc_clock_get(struct drm_device *dev,
|
|||
gma_power_end(dev);
|
||||
} else {
|
||||
dpll = (pipe == 0) ?
|
||||
dev_priv->saveDPLL_A : dev_priv->saveDPLL_B;
|
||||
dev_priv->regs.psb.saveDPLL_A :
|
||||
dev_priv->regs.psb.saveDPLL_B;
|
||||
|
||||
if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
|
||||
fp = (pipe == 0) ?
|
||||
dev_priv->saveFPA0 :
|
||||
dev_priv->saveFPB0;
|
||||
dev_priv->regs.psb.saveFPA0 :
|
||||
dev_priv->regs.psb.saveFPB0;
|
||||
else
|
||||
fp = (pipe == 0) ?
|
||||
dev_priv->saveFPA1 :
|
||||
dev_priv->saveFPB1;
|
||||
dev_priv->regs.psb.saveFPA1 :
|
||||
dev_priv->regs.psb.saveFPB1;
|
||||
|
||||
is_lvds = (pipe == 1) && (dev_priv->saveLVDS & LVDS_PORT_EN);
|
||||
is_lvds = (pipe == 1) && (dev_priv->regs.psb.saveLVDS &
|
||||
LVDS_PORT_EN);
|
||||
}
|
||||
|
||||
clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
|
||||
|
@ -1218,13 +1211,17 @@ struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev,
|
|||
gma_power_end(dev);
|
||||
} else {
|
||||
htot = (pipe == 0) ?
|
||||
dev_priv->saveHTOTAL_A : dev_priv->saveHTOTAL_B;
|
||||
dev_priv->regs.psb.saveHTOTAL_A :
|
||||
dev_priv->regs.psb.saveHTOTAL_B;
|
||||
hsync = (pipe == 0) ?
|
||||
dev_priv->saveHSYNC_A : dev_priv->saveHSYNC_B;
|
||||
dev_priv->regs.psb.saveHSYNC_A :
|
||||
dev_priv->regs.psb.saveHSYNC_B;
|
||||
vtot = (pipe == 0) ?
|
||||
dev_priv->saveVTOTAL_A : dev_priv->saveVTOTAL_B;
|
||||
dev_priv->regs.psb.saveVTOTAL_A :
|
||||
dev_priv->regs.psb.saveVTOTAL_B;
|
||||
vsync = (pipe == 0) ?
|
||||
dev_priv->saveVSYNC_A : dev_priv->saveVSYNC_B;
|
||||
dev_priv->regs.psb.saveVSYNC_A :
|
||||
dev_priv->regs.psb.saveVSYNC_B;
|
||||
}
|
||||
|
||||
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
|
||||
|
@ -1419,13 +1416,6 @@ int psb_intel_connector_clones(struct drm_device *dev, int type_mask)
|
|||
return index_mask;
|
||||
}
|
||||
|
||||
|
||||
void psb_intel_modeset_cleanup(struct drm_device *dev)
|
||||
{
|
||||
drm_mode_config_cleanup(dev);
|
||||
}
|
||||
|
||||
|
||||
/* current intel driver doesn't take advantage of encoders
|
||||
always give back the encoder for the connector
|
||||
*/
|
||||
|
|
|
@ -77,7 +77,7 @@ static u32 psb_intel_lvds_get_max_backlight(struct drm_device *dev)
|
|||
ret = REG_READ(BLC_PWM_CTL);
|
||||
gma_power_end(dev);
|
||||
} else /* Powered off, use the saved value */
|
||||
ret = dev_priv->saveBLC_PWM_CTL;
|
||||
ret = dev_priv->regs.saveBLC_PWM_CTL;
|
||||
|
||||
/* Top 15bits hold the frequency mask */
|
||||
ret = (ret & BACKLIGHT_MODULATION_FREQ_MASK) >>
|
||||
|
@ -86,7 +86,7 @@ static u32 psb_intel_lvds_get_max_backlight(struct drm_device *dev)
|
|||
ret *= 2; /* Return a 16bit range as needed for setting */
|
||||
if (ret == 0)
|
||||
dev_err(dev->dev, "BL bug: Reg %08x save %08X\n",
|
||||
REG_READ(BLC_PWM_CTL), dev_priv->saveBLC_PWM_CTL);
|
||||
REG_READ(BLC_PWM_CTL), dev_priv->regs.saveBLC_PWM_CTL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -203,13 +203,13 @@ static void psb_intel_lvds_set_backlight(struct drm_device *dev, int level)
|
|||
REG_WRITE(BLC_PWM_CTL,
|
||||
(blc_pwm_ctl |
|
||||
(level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
|
||||
dev_priv->saveBLC_PWM_CTL = (blc_pwm_ctl |
|
||||
dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl |
|
||||
(level << BACKLIGHT_DUTY_CYCLE_SHIFT));
|
||||
gma_power_end(dev);
|
||||
} else {
|
||||
blc_pwm_ctl = dev_priv->saveBLC_PWM_CTL &
|
||||
blc_pwm_ctl = dev_priv->regs.saveBLC_PWM_CTL &
|
||||
~BACKLIGHT_DUTY_CYCLE_MASK;
|
||||
dev_priv->saveBLC_PWM_CTL = (blc_pwm_ctl |
|
||||
dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl |
|
||||
(level << BACKLIGHT_DUTY_CYCLE_SHIFT));
|
||||
}
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ static void psb_intel_lvds_save(struct drm_connector *connector)
|
|||
lvds_priv->savePFIT_PGM_RATIOS = REG_READ(PFIT_PGM_RATIOS);
|
||||
|
||||
/*TODO: move backlight_duty_cycle to psb_intel_lvds_priv*/
|
||||
dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
|
||||
dev_priv->backlight_duty_cycle = (dev_priv->regs.saveBLC_PWM_CTL &
|
||||
BACKLIGHT_DUTY_CYCLE_MASK);
|
||||
|
||||
/*
|
||||
|
|
|
@ -177,6 +177,9 @@
|
|||
#define LVDSPP_OFF 0x6120c
|
||||
#define PP_CYCLE 0x61210
|
||||
|
||||
#define PP_ON_DELAYS 0x61208 /* Cedartrail */
|
||||
#define PP_OFF_DELAYS 0x6120c /* Cedartrail */
|
||||
|
||||
#define PFIT_CONTROL 0x61230
|
||||
#define PFIT_ENABLE (1 << 31)
|
||||
#define PFIT_PIPE_MASK (3 << 29)
|
||||
|
@ -1252,6 +1255,12 @@ No status bits are changed.
|
|||
# define SB_BYTE_ENABLE_SHIFT 4
|
||||
# define SB_BUSY (1 << 0)
|
||||
|
||||
#define DSPCLK_GATE_D 0x6200
|
||||
# define VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) /* Fixed value on CDV */
|
||||
# define DPOUNIT_CLOCK_GATE_DISABLE (1 << 11)
|
||||
# define DPIOUNIT_CLOCK_GATE_DISABLE (1 << 6)
|
||||
|
||||
#define RAMCLK_GATE_D 0x6210
|
||||
|
||||
/* 32-bit value read/written from the DPIO reg. */
|
||||
#define SB_DATA 0x02104 /* cedarview */
|
||||
|
|
|
@ -1301,7 +1301,7 @@ psb_intel_sdvo_get_analog_edid(struct drm_connector *connector)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
enum drm_connector_status
|
||||
static enum drm_connector_status
|
||||
psb_intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
|
||||
{
|
||||
struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector);
|
||||
|
@ -2312,10 +2312,8 @@ static bool psb_intel_sdvo_tv_create_property(struct psb_intel_sdvo *psb_intel_s
|
|||
psb_intel_sdvo_connector->max_##name = data_value[0]; \
|
||||
psb_intel_sdvo_connector->cur_##name = response; \
|
||||
psb_intel_sdvo_connector->name = \
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE, #name, 2); \
|
||||
drm_property_create_range(dev, 0, #name, 0, data_value[0]); \
|
||||
if (!psb_intel_sdvo_connector->name) return false; \
|
||||
psb_intel_sdvo_connector->name->values[0] = 0; \
|
||||
psb_intel_sdvo_connector->name->values[1] = data_value[0]; \
|
||||
drm_connector_attach_property(connector, \
|
||||
psb_intel_sdvo_connector->name, \
|
||||
psb_intel_sdvo_connector->cur_##name); \
|
||||
|
@ -2349,25 +2347,19 @@ psb_intel_sdvo_create_enhance_property_tv(struct psb_intel_sdvo *psb_intel_sdvo,
|
|||
psb_intel_sdvo_connector->left_margin = data_value[0] - response;
|
||||
psb_intel_sdvo_connector->right_margin = psb_intel_sdvo_connector->left_margin;
|
||||
psb_intel_sdvo_connector->left =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"left_margin", 2);
|
||||
drm_property_create_range(dev, 0, "left_margin", 0, data_value[0]);
|
||||
if (!psb_intel_sdvo_connector->left)
|
||||
return false;
|
||||
|
||||
psb_intel_sdvo_connector->left->values[0] = 0;
|
||||
psb_intel_sdvo_connector->left->values[1] = data_value[0];
|
||||
drm_connector_attach_property(connector,
|
||||
psb_intel_sdvo_connector->left,
|
||||
psb_intel_sdvo_connector->left_margin);
|
||||
|
||||
psb_intel_sdvo_connector->right =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"right_margin", 2);
|
||||
drm_property_create_range(dev, 0, "right_margin", 0, data_value[0]);
|
||||
if (!psb_intel_sdvo_connector->right)
|
||||
return false;
|
||||
|
||||
psb_intel_sdvo_connector->right->values[0] = 0;
|
||||
psb_intel_sdvo_connector->right->values[1] = data_value[0];
|
||||
drm_connector_attach_property(connector,
|
||||
psb_intel_sdvo_connector->right,
|
||||
psb_intel_sdvo_connector->right_margin);
|
||||
|
@ -2391,25 +2383,19 @@ psb_intel_sdvo_create_enhance_property_tv(struct psb_intel_sdvo *psb_intel_sdvo,
|
|||
psb_intel_sdvo_connector->top_margin = data_value[0] - response;
|
||||
psb_intel_sdvo_connector->bottom_margin = psb_intel_sdvo_connector->top_margin;
|
||||
psb_intel_sdvo_connector->top =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"top_margin", 2);
|
||||
drm_property_create_range(dev, 0, "top_margin", 0, data_value[0]);
|
||||
if (!psb_intel_sdvo_connector->top)
|
||||
return false;
|
||||
|
||||
psb_intel_sdvo_connector->top->values[0] = 0;
|
||||
psb_intel_sdvo_connector->top->values[1] = data_value[0];
|
||||
drm_connector_attach_property(connector,
|
||||
psb_intel_sdvo_connector->top,
|
||||
psb_intel_sdvo_connector->top_margin);
|
||||
|
||||
psb_intel_sdvo_connector->bottom =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE,
|
||||
"bottom_margin", 2);
|
||||
drm_property_create_range(dev, 0, "bottom_margin", 0, data_value[0]);
|
||||
if (!psb_intel_sdvo_connector->bottom)
|
||||
return false;
|
||||
|
||||
psb_intel_sdvo_connector->bottom->values[0] = 0;
|
||||
psb_intel_sdvo_connector->bottom->values[1] = data_value[0];
|
||||
drm_connector_attach_property(connector,
|
||||
psb_intel_sdvo_connector->bottom,
|
||||
psb_intel_sdvo_connector->bottom_margin);
|
||||
|
@ -2438,12 +2424,10 @@ psb_intel_sdvo_create_enhance_property_tv(struct psb_intel_sdvo *psb_intel_sdvo,
|
|||
psb_intel_sdvo_connector->max_dot_crawl = 1;
|
||||
psb_intel_sdvo_connector->cur_dot_crawl = response & 0x1;
|
||||
psb_intel_sdvo_connector->dot_crawl =
|
||||
drm_property_create(dev, DRM_MODE_PROP_RANGE, "dot_crawl", 2);
|
||||
drm_property_create_range(dev, 0, "dot_crawl", 0, 1);
|
||||
if (!psb_intel_sdvo_connector->dot_crawl)
|
||||
return false;
|
||||
|
||||
psb_intel_sdvo_connector->dot_crawl->values[0] = 0;
|
||||
psb_intel_sdvo_connector->dot_crawl->values[1] = 1;
|
||||
drm_connector_attach_property(connector,
|
||||
psb_intel_sdvo_connector->dot_crawl,
|
||||
psb_intel_sdvo_connector->cur_dot_crawl);
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include "psb_reg.h"
|
||||
#include "psb_intel_reg.h"
|
||||
#include "power.h"
|
||||
#include "psb_irq.h"
|
||||
#include "mdfld_output.h"
|
||||
|
||||
/*
|
||||
* inline functions
|
||||
|
@ -113,7 +115,7 @@ psb_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask)
|
|||
}
|
||||
}
|
||||
|
||||
void mid_enable_pipe_event(struct drm_psb_private *dev_priv, int pipe)
|
||||
static void mid_enable_pipe_event(struct drm_psb_private *dev_priv, int pipe)
|
||||
{
|
||||
if (gma_power_begin(dev_priv->dev, false)) {
|
||||
u32 pipe_event = mid_pipe_event(pipe);
|
||||
|
@ -124,7 +126,7 @@ void mid_enable_pipe_event(struct drm_psb_private *dev_priv, int pipe)
|
|||
}
|
||||
}
|
||||
|
||||
void mid_disable_pipe_event(struct drm_psb_private *dev_priv, int pipe)
|
||||
static void mid_disable_pipe_event(struct drm_psb_private *dev_priv, int pipe)
|
||||
{
|
||||
if (dev_priv->pipestat[pipe] == 0) {
|
||||
if (gma_power_begin(dev_priv->dev, false)) {
|
||||
|
@ -453,6 +455,11 @@ int psb_enable_vblank(struct drm_device *dev, int pipe)
|
|||
uint32_t reg_val = 0;
|
||||
uint32_t pipeconf_reg = mid_pipeconf(pipe);
|
||||
|
||||
/* Medfield is different - we should perhaps extract out vblank
|
||||
and blacklight etc ops */
|
||||
if (IS_MFLD(dev))
|
||||
return mdfld_enable_te(dev, pipe);
|
||||
|
||||
if (gma_power_begin(dev, false)) {
|
||||
reg_val = REG_READ(pipeconf_reg);
|
||||
gma_power_end(dev);
|
||||
|
@ -485,6 +492,8 @@ void psb_disable_vblank(struct drm_device *dev, int pipe)
|
|||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
unsigned long irqflags;
|
||||
|
||||
if (IS_MFLD(dev))
|
||||
mdfld_disable_te(dev, pipe);
|
||||
spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
|
||||
|
||||
if (pipe == 0)
|
||||
|
@ -499,6 +508,55 @@ void psb_disable_vblank(struct drm_device *dev, int pipe)
|
|||
spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
|
||||
}
|
||||
|
||||
/*
|
||||
* It is used to enable TE interrupt
|
||||
*/
|
||||
int mdfld_enable_te(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_psb_private *dev_priv =
|
||||
(struct drm_psb_private *) dev->dev_private;
|
||||
unsigned long irqflags;
|
||||
uint32_t reg_val = 0;
|
||||
uint32_t pipeconf_reg = mid_pipeconf(pipe);
|
||||
|
||||
if (gma_power_begin(dev, false)) {
|
||||
reg_val = REG_READ(pipeconf_reg);
|
||||
gma_power_end(dev);
|
||||
}
|
||||
|
||||
if (!(reg_val & PIPEACONF_ENABLE))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
|
||||
|
||||
mid_enable_pipe_event(dev_priv, pipe);
|
||||
psb_enable_pipestat(dev_priv, pipe, PIPE_TE_ENABLE);
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* It is used to disable TE interrupt
|
||||
*/
|
||||
void mdfld_disable_te(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_psb_private *dev_priv =
|
||||
(struct drm_psb_private *) dev->dev_private;
|
||||
unsigned long irqflags;
|
||||
|
||||
if (!dev_priv->dsr_enable)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
|
||||
|
||||
mid_disable_pipe_event(dev_priv, pipe);
|
||||
psb_disable_pipestat(dev_priv, pipe, PIPE_TE_ENABLE);
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
|
||||
}
|
||||
|
||||
/* Called from drm generic code, passed a 'crtc', which
|
||||
* we use as a pipe index
|
||||
*/
|
||||
|
|
|
@ -42,4 +42,6 @@ int psb_enable_vblank(struct drm_device *dev, int pipe);
|
|||
void psb_disable_vblank(struct drm_device *dev, int pipe);
|
||||
u32 psb_get_vblank_counter(struct drm_device *dev, int pipe);
|
||||
|
||||
int mdfld_enable_te(struct drm_device *dev, int pipe);
|
||||
void mdfld_disable_te(struct drm_device *dev, int pipe);
|
||||
#endif /* _SYSIRQ_H_ */
|
||||
|
|
|
@ -0,0 +1,829 @@
|
|||
/*
|
||||
* Copyright © 2011 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mdfld_dsi_dpi.h"
|
||||
#include "mdfld_output.h"
|
||||
#include "mdfld_dsi_pkg_sender.h"
|
||||
#include "tc35876x-dsi-lvds.h"
|
||||
#include <linux/i2c/tc35876x.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/intel_scu_ipc.h>
|
||||
|
||||
static struct i2c_client *tc35876x_client;
|
||||
static struct i2c_client *cmi_lcd_i2c_client;
|
||||
|
||||
#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
|
||||
#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
|
||||
|
||||
/* DSI D-PHY Layer Registers */
|
||||
#define D0W_DPHYCONTTX 0x0004
|
||||
#define CLW_DPHYCONTRX 0x0020
|
||||
#define D0W_DPHYCONTRX 0x0024
|
||||
#define D1W_DPHYCONTRX 0x0028
|
||||
#define D2W_DPHYCONTRX 0x002C
|
||||
#define D3W_DPHYCONTRX 0x0030
|
||||
#define COM_DPHYCONTRX 0x0038
|
||||
#define CLW_CNTRL 0x0040
|
||||
#define D0W_CNTRL 0x0044
|
||||
#define D1W_CNTRL 0x0048
|
||||
#define D2W_CNTRL 0x004C
|
||||
#define D3W_CNTRL 0x0050
|
||||
#define DFTMODE_CNTRL 0x0054
|
||||
|
||||
/* DSI PPI Layer Registers */
|
||||
#define PPI_STARTPPI 0x0104
|
||||
#define PPI_BUSYPPI 0x0108
|
||||
#define PPI_LINEINITCNT 0x0110
|
||||
#define PPI_LPTXTIMECNT 0x0114
|
||||
#define PPI_LANEENABLE 0x0134
|
||||
#define PPI_TX_RX_TA 0x013C
|
||||
#define PPI_CLS_ATMR 0x0140
|
||||
#define PPI_D0S_ATMR 0x0144
|
||||
#define PPI_D1S_ATMR 0x0148
|
||||
#define PPI_D2S_ATMR 0x014C
|
||||
#define PPI_D3S_ATMR 0x0150
|
||||
#define PPI_D0S_CLRSIPOCOUNT 0x0164
|
||||
#define PPI_D1S_CLRSIPOCOUNT 0x0168
|
||||
#define PPI_D2S_CLRSIPOCOUNT 0x016C
|
||||
#define PPI_D3S_CLRSIPOCOUNT 0x0170
|
||||
#define CLS_PRE 0x0180
|
||||
#define D0S_PRE 0x0184
|
||||
#define D1S_PRE 0x0188
|
||||
#define D2S_PRE 0x018C
|
||||
#define D3S_PRE 0x0190
|
||||
#define CLS_PREP 0x01A0
|
||||
#define D0S_PREP 0x01A4
|
||||
#define D1S_PREP 0x01A8
|
||||
#define D2S_PREP 0x01AC
|
||||
#define D3S_PREP 0x01B0
|
||||
#define CLS_ZERO 0x01C0
|
||||
#define D0S_ZERO 0x01C4
|
||||
#define D1S_ZERO 0x01C8
|
||||
#define D2S_ZERO 0x01CC
|
||||
#define D3S_ZERO 0x01D0
|
||||
#define PPI_CLRFLG 0x01E0
|
||||
#define PPI_CLRSIPO 0x01E4
|
||||
#define HSTIMEOUT 0x01F0
|
||||
#define HSTIMEOUTENABLE 0x01F4
|
||||
|
||||
/* DSI Protocol Layer Registers */
|
||||
#define DSI_STARTDSI 0x0204
|
||||
#define DSI_BUSYDSI 0x0208
|
||||
#define DSI_LANEENABLE 0x0210
|
||||
#define DSI_LANESTATUS0 0x0214
|
||||
#define DSI_LANESTATUS1 0x0218
|
||||
#define DSI_INTSTATUS 0x0220
|
||||
#define DSI_INTMASK 0x0224
|
||||
#define DSI_INTCLR 0x0228
|
||||
#define DSI_LPTXTO 0x0230
|
||||
|
||||
/* DSI General Registers */
|
||||
#define DSIERRCNT 0x0300
|
||||
|
||||
/* DSI Application Layer Registers */
|
||||
#define APLCTRL 0x0400
|
||||
#define RDPKTLN 0x0404
|
||||
|
||||
/* Video Path Registers */
|
||||
#define VPCTRL 0x0450
|
||||
#define HTIM1 0x0454
|
||||
#define HTIM2 0x0458
|
||||
#define VTIM1 0x045C
|
||||
#define VTIM2 0x0460
|
||||
#define VFUEN 0x0464
|
||||
|
||||
/* LVDS Registers */
|
||||
#define LVMX0003 0x0480
|
||||
#define LVMX0407 0x0484
|
||||
#define LVMX0811 0x0488
|
||||
#define LVMX1215 0x048C
|
||||
#define LVMX1619 0x0490
|
||||
#define LVMX2023 0x0494
|
||||
#define LVMX2427 0x0498
|
||||
#define LVCFG 0x049C
|
||||
#define LVPHY0 0x04A0
|
||||
#define LVPHY1 0x04A4
|
||||
|
||||
/* System Registers */
|
||||
#define SYSSTAT 0x0500
|
||||
#define SYSRST 0x0504
|
||||
|
||||
/* GPIO Registers */
|
||||
/*#define GPIOC 0x0520*/
|
||||
#define GPIOO 0x0524
|
||||
#define GPIOI 0x0528
|
||||
|
||||
/* I2C Registers */
|
||||
#define I2CTIMCTRL 0x0540
|
||||
#define I2CMADDR 0x0544
|
||||
#define WDATAQ 0x0548
|
||||
#define RDATAQ 0x054C
|
||||
|
||||
/* Chip/Rev Registers */
|
||||
#define IDREG 0x0580
|
||||
|
||||
/* Debug Registers */
|
||||
#define DEBUG00 0x05A0
|
||||
#define DEBUG01 0x05A4
|
||||
|
||||
/* Panel CABC registers */
|
||||
#define PANEL_PWM_CONTROL 0x90
|
||||
#define PANEL_FREQ_DIVIDER_HI 0x91
|
||||
#define PANEL_FREQ_DIVIDER_LO 0x92
|
||||
#define PANEL_DUTY_CONTROL 0x93
|
||||
#define PANEL_MODIFY_RGB 0x94
|
||||
#define PANEL_FRAMERATE_CONTROL 0x96
|
||||
#define PANEL_PWM_MIN 0x97
|
||||
#define PANEL_PWM_REF 0x98
|
||||
#define PANEL_PWM_MAX 0x99
|
||||
#define PANEL_ALLOW_DISTORT 0x9A
|
||||
#define PANEL_BYPASS_PWMI 0x9B
|
||||
|
||||
/* Panel color management registers */
|
||||
#define PANEL_CM_ENABLE 0x700
|
||||
#define PANEL_CM_HUE 0x701
|
||||
#define PANEL_CM_SATURATION 0x702
|
||||
#define PANEL_CM_INTENSITY 0x703
|
||||
#define PANEL_CM_BRIGHTNESS 0x704
|
||||
#define PANEL_CM_CE_ENABLE 0x705
|
||||
#define PANEL_CM_PEAK_EN 0x710
|
||||
#define PANEL_CM_GAIN 0x711
|
||||
#define PANEL_CM_HUETABLE_START 0x730
|
||||
#define PANEL_CM_HUETABLE_END 0x747 /* inclusive */
|
||||
|
||||
/* Input muxing for registers LVMX0003...LVMX2427 */
|
||||
enum {
|
||||
INPUT_R0, /* 0 */
|
||||
INPUT_R1,
|
||||
INPUT_R2,
|
||||
INPUT_R3,
|
||||
INPUT_R4,
|
||||
INPUT_R5,
|
||||
INPUT_R6,
|
||||
INPUT_R7,
|
||||
INPUT_G0, /* 8 */
|
||||
INPUT_G1,
|
||||
INPUT_G2,
|
||||
INPUT_G3,
|
||||
INPUT_G4,
|
||||
INPUT_G5,
|
||||
INPUT_G6,
|
||||
INPUT_G7,
|
||||
INPUT_B0, /* 16 */
|
||||
INPUT_B1,
|
||||
INPUT_B2,
|
||||
INPUT_B3,
|
||||
INPUT_B4,
|
||||
INPUT_B5,
|
||||
INPUT_B6,
|
||||
INPUT_B7,
|
||||
INPUT_HSYNC, /* 24 */
|
||||
INPUT_VSYNC,
|
||||
INPUT_DE,
|
||||
LOGIC_0,
|
||||
/* 28...31 undefined */
|
||||
};
|
||||
|
||||
#define INPUT_MUX(lvmx03, lvmx02, lvmx01, lvmx00) \
|
||||
(FLD_VAL(lvmx03, 29, 24) | FLD_VAL(lvmx02, 20, 16) | \
|
||||
FLD_VAL(lvmx01, 12, 8) | FLD_VAL(lvmx00, 4, 0))
|
||||
|
||||
/**
|
||||
* tc35876x_regw - Write DSI-LVDS bridge register using I2C
|
||||
* @client: struct i2c_client to use
|
||||
* @reg: register address
|
||||
* @value: value to write
|
||||
*
|
||||
* Returns 0 on success, or a negative error value.
|
||||
*/
|
||||
static int tc35876x_regw(struct i2c_client *client, u16 reg, u32 value)
|
||||
{
|
||||
int r;
|
||||
u8 tx_data[] = {
|
||||
/* NOTE: Register address big-endian, data little-endian. */
|
||||
(reg >> 8) & 0xff,
|
||||
reg & 0xff,
|
||||
value & 0xff,
|
||||
(value >> 8) & 0xff,
|
||||
(value >> 16) & 0xff,
|
||||
(value >> 24) & 0xff,
|
||||
};
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.buf = tx_data,
|
||||
.len = ARRAY_SIZE(tx_data),
|
||||
},
|
||||
};
|
||||
|
||||
r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (r < 0) {
|
||||
dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x error %d\n",
|
||||
__func__, reg, value, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (r < ARRAY_SIZE(msgs)) {
|
||||
dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x msgs %d\n",
|
||||
__func__, reg, value, r);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
dev_dbg(&client->dev, "%s: reg 0x%04x val 0x%08x\n",
|
||||
__func__, reg, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tc35876x_regr - Read DSI-LVDS bridge register using I2C
|
||||
* @client: struct i2c_client to use
|
||||
* @reg: register address
|
||||
* @value: pointer for storing the value
|
||||
*
|
||||
* Returns 0 on success, or a negative error value.
|
||||
*/
|
||||
static int tc35876x_regr(struct i2c_client *client, u16 reg, u32 *value)
|
||||
{
|
||||
int r;
|
||||
u8 tx_data[] = {
|
||||
(reg >> 8) & 0xff,
|
||||
reg & 0xff,
|
||||
};
|
||||
u8 rx_data[4];
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.buf = tx_data,
|
||||
.len = ARRAY_SIZE(tx_data),
|
||||
},
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = rx_data,
|
||||
.len = ARRAY_SIZE(rx_data),
|
||||
},
|
||||
};
|
||||
|
||||
r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (r < 0) {
|
||||
dev_err(&client->dev, "%s: reg 0x%04x error %d\n", __func__,
|
||||
reg, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (r < ARRAY_SIZE(msgs)) {
|
||||
dev_err(&client->dev, "%s: reg 0x%04x msgs %d\n", __func__,
|
||||
reg, r);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
*value = rx_data[0] << 24 | rx_data[1] << 16 |
|
||||
rx_data[2] << 8 | rx_data[3];
|
||||
|
||||
dev_dbg(&client->dev, "%s: reg 0x%04x value 0x%08x\n", __func__,
|
||||
reg, *value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state)
|
||||
{
|
||||
struct tc35876x_platform_data *pdata;
|
||||
|
||||
if (WARN(!tc35876x_client, "%s called before probe", __func__))
|
||||
return;
|
||||
|
||||
dev_dbg(&tc35876x_client->dev, "%s: state %d\n", __func__, state);
|
||||
|
||||
pdata = dev_get_platdata(&tc35876x_client->dev);
|
||||
|
||||
if (pdata->gpio_bridge_reset == -1)
|
||||
return;
|
||||
|
||||
if (state) {
|
||||
gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0);
|
||||
mdelay(10);
|
||||
} else {
|
||||
/* Pull MIPI Bridge reset pin to Low */
|
||||
gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0);
|
||||
mdelay(20);
|
||||
/* Pull MIPI Bridge reset pin to High */
|
||||
gpio_set_value_cansleep(pdata->gpio_bridge_reset, 1);
|
||||
mdelay(40);
|
||||
}
|
||||
}
|
||||
|
||||
void tc35876x_configure_lvds_bridge(struct drm_device *dev)
|
||||
{
|
||||
struct i2c_client *i2c = tc35876x_client;
|
||||
u32 ppi_lptxtimecnt;
|
||||
u32 txtagocnt;
|
||||
u32 txtasurecnt;
|
||||
u32 id;
|
||||
|
||||
if (WARN(!tc35876x_client, "%s called before probe", __func__))
|
||||
return;
|
||||
|
||||
dev_dbg(&tc35876x_client->dev, "%s\n", __func__);
|
||||
|
||||
if (!tc35876x_regr(i2c, IDREG, &id))
|
||||
dev_info(&tc35876x_client->dev, "tc35876x ID 0x%08x\n", id);
|
||||
else
|
||||
dev_err(&tc35876x_client->dev, "Cannot read ID\n");
|
||||
|
||||
ppi_lptxtimecnt = 4;
|
||||
txtagocnt = (5 * ppi_lptxtimecnt - 3) / 4;
|
||||
txtasurecnt = 3 * ppi_lptxtimecnt / 2;
|
||||
tc35876x_regw(i2c, PPI_TX_RX_TA, FLD_VAL(txtagocnt, 26, 16) |
|
||||
FLD_VAL(txtasurecnt, 10, 0));
|
||||
tc35876x_regw(i2c, PPI_LPTXTIMECNT, FLD_VAL(ppi_lptxtimecnt, 10, 0));
|
||||
|
||||
tc35876x_regw(i2c, PPI_D0S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
|
||||
tc35876x_regw(i2c, PPI_D1S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
|
||||
tc35876x_regw(i2c, PPI_D2S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
|
||||
tc35876x_regw(i2c, PPI_D3S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0));
|
||||
|
||||
/* Enabling MIPI & PPI lanes, Enable 4 lanes */
|
||||
tc35876x_regw(i2c, PPI_LANEENABLE,
|
||||
BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0));
|
||||
tc35876x_regw(i2c, DSI_LANEENABLE,
|
||||
BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0));
|
||||
tc35876x_regw(i2c, PPI_STARTPPI, BIT(0));
|
||||
tc35876x_regw(i2c, DSI_STARTDSI, BIT(0));
|
||||
|
||||
/* Setting LVDS output frequency */
|
||||
tc35876x_regw(i2c, LVPHY0, FLD_VAL(1, 20, 16) |
|
||||
FLD_VAL(2, 15, 14) | FLD_VAL(6, 4, 0)); /* 0x00048006 */
|
||||
|
||||
/* Setting video panel control register,0x00000120 VTGen=ON ?!?!? */
|
||||
tc35876x_regw(i2c, VPCTRL, BIT(8) | BIT(5));
|
||||
|
||||
/* Horizontal back porch and horizontal pulse width. 0x00280028 */
|
||||
tc35876x_regw(i2c, HTIM1, FLD_VAL(40, 24, 16) | FLD_VAL(40, 8, 0));
|
||||
|
||||
/* Horizontal front porch and horizontal active video size. 0x00500500*/
|
||||
tc35876x_regw(i2c, HTIM2, FLD_VAL(80, 24, 16) | FLD_VAL(1280, 10, 0));
|
||||
|
||||
/* Vertical back porch and vertical sync pulse width. 0x000e000a */
|
||||
tc35876x_regw(i2c, VTIM1, FLD_VAL(14, 23, 16) | FLD_VAL(10, 7, 0));
|
||||
|
||||
/* Vertical front porch and vertical display size. 0x000e0320 */
|
||||
tc35876x_regw(i2c, VTIM2, FLD_VAL(14, 23, 16) | FLD_VAL(800, 10, 0));
|
||||
|
||||
/* Set above HTIM1, HTIM2, VTIM1, and VTIM2 at next VSYNC. */
|
||||
tc35876x_regw(i2c, VFUEN, BIT(0));
|
||||
|
||||
/* Soft reset LCD controller. */
|
||||
tc35876x_regw(i2c, SYSRST, BIT(2));
|
||||
|
||||
/* LVDS-TX input muxing */
|
||||
tc35876x_regw(i2c, LVMX0003,
|
||||
INPUT_MUX(INPUT_R5, INPUT_R4, INPUT_R3, INPUT_R2));
|
||||
tc35876x_regw(i2c, LVMX0407,
|
||||
INPUT_MUX(INPUT_G2, INPUT_R7, INPUT_R1, INPUT_R6));
|
||||
tc35876x_regw(i2c, LVMX0811,
|
||||
INPUT_MUX(INPUT_G1, INPUT_G0, INPUT_G4, INPUT_G3));
|
||||
tc35876x_regw(i2c, LVMX1215,
|
||||
INPUT_MUX(INPUT_B2, INPUT_G7, INPUT_G6, INPUT_G5));
|
||||
tc35876x_regw(i2c, LVMX1619,
|
||||
INPUT_MUX(INPUT_B4, INPUT_B3, INPUT_B1, INPUT_B0));
|
||||
tc35876x_regw(i2c, LVMX2023,
|
||||
INPUT_MUX(LOGIC_0, INPUT_B7, INPUT_B6, INPUT_B5));
|
||||
tc35876x_regw(i2c, LVMX2427,
|
||||
INPUT_MUX(INPUT_R0, INPUT_DE, INPUT_VSYNC, INPUT_HSYNC));
|
||||
|
||||
/* Enable LVDS transmitter. */
|
||||
tc35876x_regw(i2c, LVCFG, BIT(0));
|
||||
|
||||
/* Clear notifications. Don't write reserved bits. Was write 0xffffffff
|
||||
* to 0x0288, must be in error?! */
|
||||
tc35876x_regw(i2c, DSI_INTCLR, FLD_MASK(31, 30) | FLD_MASK(22, 0));
|
||||
}
|
||||
|
||||
#define GPIOPWMCTRL 0x38F
|
||||
#define PWM0CLKDIV0 0x62 /* low byte */
|
||||
#define PWM0CLKDIV1 0x61 /* high byte */
|
||||
|
||||
#define SYSTEMCLK 19200000UL /* 19.2 MHz */
|
||||
#define PWM_FREQUENCY 9600 /* Hz */
|
||||
|
||||
/* f = baseclk / (clkdiv + 1) => clkdiv = (baseclk - f) / f */
|
||||
static inline u16 calc_clkdiv(unsigned long baseclk, unsigned int f)
|
||||
{
|
||||
return (baseclk - f) / f;
|
||||
}
|
||||
|
||||
static void tc35876x_brightness_init(struct drm_device *dev)
|
||||
{
|
||||
int ret;
|
||||
u8 pwmctrl;
|
||||
u16 clkdiv;
|
||||
|
||||
/* Make sure the PWM reference is the 19.2 MHz system clock. Read first
|
||||
* instead of setting directly to catch potential conflicts between PWM
|
||||
* users. */
|
||||
ret = intel_scu_ipc_ioread8(GPIOPWMCTRL, &pwmctrl);
|
||||
if (ret || pwmctrl != 0x01) {
|
||||
if (ret)
|
||||
dev_err(&dev->pdev->dev, "GPIOPWMCTRL read failed\n");
|
||||
else
|
||||
dev_warn(&dev->pdev->dev, "GPIOPWMCTRL was not set to system clock (pwmctrl = 0x%02x)\n", pwmctrl);
|
||||
|
||||
ret = intel_scu_ipc_iowrite8(GPIOPWMCTRL, 0x01);
|
||||
if (ret)
|
||||
dev_err(&dev->pdev->dev, "GPIOPWMCTRL set failed\n");
|
||||
}
|
||||
|
||||
clkdiv = calc_clkdiv(SYSTEMCLK, PWM_FREQUENCY);
|
||||
|
||||
ret = intel_scu_ipc_iowrite8(PWM0CLKDIV1, (clkdiv >> 8) & 0xff);
|
||||
if (!ret)
|
||||
ret = intel_scu_ipc_iowrite8(PWM0CLKDIV0, clkdiv & 0xff);
|
||||
|
||||
if (ret)
|
||||
dev_err(&dev->pdev->dev, "PWM0CLKDIV set failed\n");
|
||||
else
|
||||
dev_dbg(&dev->pdev->dev, "PWM0CLKDIV set to 0x%04x (%d Hz)\n",
|
||||
clkdiv, PWM_FREQUENCY);
|
||||
}
|
||||
|
||||
#define PWM0DUTYCYCLE 0x67
|
||||
|
||||
void tc35876x_brightness_control(struct drm_device *dev, int level)
|
||||
{
|
||||
int ret;
|
||||
u8 duty_val;
|
||||
u8 panel_duty_val;
|
||||
|
||||
level = clamp(level, 0, MDFLD_DSI_BRIGHTNESS_MAX_LEVEL);
|
||||
|
||||
/* PWM duty cycle 0x00...0x63 corresponds to 0...99% */
|
||||
duty_val = level * 0x63 / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL;
|
||||
|
||||
/* I won't pretend to understand this formula. The panel spec is quite
|
||||
* bad engrish.
|
||||
*/
|
||||
panel_duty_val = (2 * level - 100) * 0xA9 /
|
||||
MDFLD_DSI_BRIGHTNESS_MAX_LEVEL + 0x56;
|
||||
|
||||
ret = intel_scu_ipc_iowrite8(PWM0DUTYCYCLE, duty_val);
|
||||
if (ret)
|
||||
dev_err(&tc35876x_client->dev, "%s: ipc write fail\n",
|
||||
__func__);
|
||||
|
||||
if (cmi_lcd_i2c_client) {
|
||||
ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
|
||||
PANEL_PWM_MAX, panel_duty_val);
|
||||
if (ret < 0)
|
||||
dev_err(&cmi_lcd_i2c_client->dev, "%s: i2c write failed\n",
|
||||
__func__);
|
||||
}
|
||||
}
|
||||
|
||||
void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev)
|
||||
{
|
||||
struct tc35876x_platform_data *pdata;
|
||||
|
||||
if (WARN(!tc35876x_client, "%s called before probe", __func__))
|
||||
return;
|
||||
|
||||
dev_dbg(&tc35876x_client->dev, "%s\n", __func__);
|
||||
|
||||
pdata = dev_get_platdata(&tc35876x_client->dev);
|
||||
|
||||
if (pdata->gpio_panel_bl_en != -1)
|
||||
gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 0);
|
||||
|
||||
if (pdata->gpio_panel_vadd != -1)
|
||||
gpio_set_value_cansleep(pdata->gpio_panel_vadd, 0);
|
||||
}
|
||||
|
||||
void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev)
|
||||
{
|
||||
struct tc35876x_platform_data *pdata;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (WARN(!tc35876x_client, "%s called before probe", __func__))
|
||||
return;
|
||||
|
||||
dev_dbg(&tc35876x_client->dev, "%s\n", __func__);
|
||||
|
||||
pdata = dev_get_platdata(&tc35876x_client->dev);
|
||||
|
||||
if (pdata->gpio_panel_vadd != -1) {
|
||||
gpio_set_value_cansleep(pdata->gpio_panel_vadd, 1);
|
||||
msleep(260);
|
||||
}
|
||||
|
||||
if (cmi_lcd_i2c_client) {
|
||||
int ret;
|
||||
dev_dbg(&cmi_lcd_i2c_client->dev, "setting TCON\n");
|
||||
/* Bit 4 is average_saving. Setting it to 1, the brightness is
|
||||
* referenced to the average of the frame content. 0 means
|
||||
* reference to the maximum of frame contents. Bits 3:0 are
|
||||
* allow_distort. When set to a nonzero value, all color values
|
||||
* between 255-allow_distort*2 and 255 are mapped to the
|
||||
* 255-allow_distort*2 value.
|
||||
*/
|
||||
ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
|
||||
PANEL_ALLOW_DISTORT, 0x10);
|
||||
if (ret < 0)
|
||||
dev_err(&cmi_lcd_i2c_client->dev,
|
||||
"i2c write failed (%d)\n", ret);
|
||||
ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
|
||||
PANEL_BYPASS_PWMI, 0);
|
||||
if (ret < 0)
|
||||
dev_err(&cmi_lcd_i2c_client->dev,
|
||||
"i2c write failed (%d)\n", ret);
|
||||
/* Set minimum brightness value - this is tunable */
|
||||
ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client,
|
||||
PANEL_PWM_MIN, 0x35);
|
||||
if (ret < 0)
|
||||
dev_err(&cmi_lcd_i2c_client->dev,
|
||||
"i2c write failed (%d)\n", ret);
|
||||
}
|
||||
|
||||
if (pdata->gpio_panel_bl_en != -1)
|
||||
gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 1);
|
||||
|
||||
tc35876x_brightness_control(dev, dev_priv->brightness_adjusted);
|
||||
}
|
||||
|
||||
static struct drm_display_mode *tc35876x_get_config_mode(struct drm_device *dev)
|
||||
{
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
dev_dbg(&dev->pdev->dev, "%s\n", __func__);
|
||||
|
||||
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
|
||||
if (!mode)
|
||||
return NULL;
|
||||
|
||||
/* FIXME: do this properly. */
|
||||
mode->hdisplay = 1280;
|
||||
mode->vdisplay = 800;
|
||||
mode->hsync_start = 1360;
|
||||
mode->hsync_end = 1400;
|
||||
mode->htotal = 1440;
|
||||
mode->vsync_start = 814;
|
||||
mode->vsync_end = 824;
|
||||
mode->vtotal = 838;
|
||||
mode->clock = 33324 << 1;
|
||||
|
||||
dev_info(&dev->pdev->dev, "hdisplay(w) = %d\n", mode->hdisplay);
|
||||
dev_info(&dev->pdev->dev, "vdisplay(h) = %d\n", mode->vdisplay);
|
||||
dev_info(&dev->pdev->dev, "HSS = %d\n", mode->hsync_start);
|
||||
dev_info(&dev->pdev->dev, "HSE = %d\n", mode->hsync_end);
|
||||
dev_info(&dev->pdev->dev, "htotal = %d\n", mode->htotal);
|
||||
dev_info(&dev->pdev->dev, "VSS = %d\n", mode->vsync_start);
|
||||
dev_info(&dev->pdev->dev, "VSE = %d\n", mode->vsync_end);
|
||||
dev_info(&dev->pdev->dev, "vtotal = %d\n", mode->vtotal);
|
||||
dev_info(&dev->pdev->dev, "clock = %d\n", mode->clock);
|
||||
|
||||
drm_mode_set_name(mode);
|
||||
drm_mode_set_crtcinfo(mode, 0);
|
||||
|
||||
mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
/* DV1 Active area 216.96 x 135.6 mm */
|
||||
#define DV1_PANEL_WIDTH 217
|
||||
#define DV1_PANEL_HEIGHT 136
|
||||
|
||||
static int tc35876x_get_panel_info(struct drm_device *dev, int pipe,
|
||||
struct panel_info *pi)
|
||||
{
|
||||
if (!dev || !pi)
|
||||
return -EINVAL;
|
||||
|
||||
pi->width_mm = DV1_PANEL_WIDTH;
|
||||
pi->height_mm = DV1_PANEL_HEIGHT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tc35876x_bridge_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct tc35876x_platform_data *pdata;
|
||||
|
||||
dev_info(&client->dev, "%s\n", __func__);
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
dev_err(&client->dev, "%s: i2c_check_functionality() failed\n",
|
||||
__func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pdata = dev_get_platdata(&client->dev);
|
||||
if (!pdata) {
|
||||
dev_err(&client->dev, "%s: no platform data\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (pdata->gpio_bridge_reset != -1) {
|
||||
gpio_request(pdata->gpio_bridge_reset, "tc35876x bridge reset");
|
||||
gpio_direction_output(pdata->gpio_bridge_reset, 0);
|
||||
}
|
||||
|
||||
if (pdata->gpio_panel_bl_en != -1) {
|
||||
gpio_request(pdata->gpio_panel_bl_en, "tc35876x panel bl en");
|
||||
gpio_direction_output(pdata->gpio_panel_bl_en, 0);
|
||||
}
|
||||
|
||||
if (pdata->gpio_panel_vadd != -1) {
|
||||
gpio_request(pdata->gpio_panel_vadd, "tc35876x panel vadd");
|
||||
gpio_direction_output(pdata->gpio_panel_vadd, 0);
|
||||
}
|
||||
|
||||
tc35876x_client = client;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tc35876x_bridge_remove(struct i2c_client *client)
|
||||
{
|
||||
struct tc35876x_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
if (pdata->gpio_bridge_reset != -1)
|
||||
gpio_free(pdata->gpio_bridge_reset);
|
||||
|
||||
if (pdata->gpio_panel_bl_en != -1)
|
||||
gpio_free(pdata->gpio_panel_bl_en);
|
||||
|
||||
if (pdata->gpio_panel_vadd != -1)
|
||||
gpio_free(pdata->gpio_panel_vadd);
|
||||
|
||||
tc35876x_client = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tc35876x_bridge_id[] = {
|
||||
{ "i2c_disp_brig", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tc35876x_bridge_id);
|
||||
|
||||
static struct i2c_driver tc35876x_bridge_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "i2c_disp_brig",
|
||||
},
|
||||
.id_table = tc35876x_bridge_id,
|
||||
.probe = tc35876x_bridge_probe,
|
||||
.remove = __devexit_p(tc35876x_bridge_remove),
|
||||
};
|
||||
|
||||
/* LCD panel I2C */
|
||||
static int cmi_lcd_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
dev_info(&client->dev, "%s\n", __func__);
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
dev_err(&client->dev, "%s: i2c_check_functionality() failed\n",
|
||||
__func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
cmi_lcd_i2c_client = client;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmi_lcd_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
cmi_lcd_i2c_client = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id cmi_lcd_i2c_id[] = {
|
||||
{ "cmi-lcd", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cmi_lcd_i2c_id);
|
||||
|
||||
static struct i2c_driver cmi_lcd_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cmi-lcd",
|
||||
},
|
||||
.id_table = cmi_lcd_i2c_id,
|
||||
.probe = cmi_lcd_i2c_probe,
|
||||
.remove = __devexit_p(cmi_lcd_i2c_remove),
|
||||
};
|
||||
|
||||
/* HACK to create I2C device while it's not created by platform code */
|
||||
#define CMI_LCD_I2C_ADAPTER 2
|
||||
#define CMI_LCD_I2C_ADDR 0x60
|
||||
|
||||
static int cmi_lcd_hack_create_device(void)
|
||||
{
|
||||
struct i2c_adapter *adapter;
|
||||
struct i2c_client *client;
|
||||
struct i2c_board_info info = {
|
||||
.type = "cmi-lcd",
|
||||
.addr = CMI_LCD_I2C_ADDR,
|
||||
};
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
adapter = i2c_get_adapter(CMI_LCD_I2C_ADAPTER);
|
||||
if (!adapter) {
|
||||
pr_err("%s: i2c_get_adapter(%d) failed\n", __func__,
|
||||
CMI_LCD_I2C_ADAPTER);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
client = i2c_new_device(adapter, &info);
|
||||
if (!client) {
|
||||
pr_err("%s: i2c_new_device() failed\n", __func__);
|
||||
i2c_put_adapter(adapter);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs tc35876x_encoder_helper_funcs = {
|
||||
.dpms = mdfld_dsi_dpi_dpms,
|
||||
.mode_fixup = mdfld_dsi_dpi_mode_fixup,
|
||||
.prepare = mdfld_dsi_dpi_prepare,
|
||||
.mode_set = mdfld_dsi_dpi_mode_set,
|
||||
.commit = mdfld_dsi_dpi_commit,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_funcs tc35876x_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
const struct panel_funcs mdfld_tc35876x_funcs = {
|
||||
.encoder_funcs = &tc35876x_encoder_funcs,
|
||||
.encoder_helper_funcs = &tc35876x_encoder_helper_funcs,
|
||||
.get_config_mode = tc35876x_get_config_mode,
|
||||
.get_panel_info = tc35876x_get_panel_info,
|
||||
};
|
||||
|
||||
void tc35876x_init(struct drm_device *dev)
|
||||
{
|
||||
int r;
|
||||
|
||||
dev_dbg(&dev->pdev->dev, "%s\n", __func__);
|
||||
|
||||
cmi_lcd_hack_create_device();
|
||||
|
||||
r = i2c_add_driver(&cmi_lcd_i2c_driver);
|
||||
if (r < 0)
|
||||
dev_err(&dev->pdev->dev,
|
||||
"%s: i2c_add_driver() for %s failed (%d)\n",
|
||||
__func__, cmi_lcd_i2c_driver.driver.name, r);
|
||||
|
||||
r = i2c_add_driver(&tc35876x_bridge_i2c_driver);
|
||||
if (r < 0)
|
||||
dev_err(&dev->pdev->dev,
|
||||
"%s: i2c_add_driver() for %s failed (%d)\n",
|
||||
__func__, tc35876x_bridge_i2c_driver.driver.name, r);
|
||||
|
||||
tc35876x_brightness_init(dev);
|
||||
}
|
||||
|
||||
void tc35876x_exit(void)
|
||||
{
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
i2c_del_driver(&tc35876x_bridge_i2c_driver);
|
||||
|
||||
if (cmi_lcd_i2c_client)
|
||||
i2c_del_driver(&cmi_lcd_i2c_driver);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright © 2011 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MDFLD_DSI_LVDS_BRIDGE_H__
|
||||
#define __MDFLD_DSI_LVDS_BRIDGE_H__
|
||||
|
||||
void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state);
|
||||
void tc35876x_configure_lvds_bridge(struct drm_device *dev);
|
||||
void tc35876x_brightness_control(struct drm_device *dev, int level);
|
||||
void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev);
|
||||
void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev);
|
||||
void tc35876x_init(struct drm_device *dev);
|
||||
void tc35876x_exit(void);
|
||||
|
||||
extern const struct panel_funcs mdfld_tc35876x_funcs;
|
||||
|
||||
#endif /*__MDFLD_DSI_LVDS_BRIDGE_H__*/
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue