1/*
2Copyright (C) 2008 Francisco Jerez.  All Rights Reserved.
3
4Permission is hereby granted, free of charge, to any person obtaining a copy of
5this software and associated documentation files (the "Software"), to deal in
6the Software without restriction, including without limitation the rights to
7use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8of the Software, and to permit persons to whom the Software is furnished to do
9so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in all
12copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
16NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
19WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20*/
21
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include "smi.h"
27#include "smi_crtc.h"
28#include "smilynx.h"
29#include "smi_501.h"
30
31static void
32SMI_CrtcDPMS(xf86CrtcPtr		crtc,
33	     int		    	mode)
34{
35    ENTER();
36
37    /* Nothing */
38
39    LEAVE();
40}
41
42static Bool
43SMI_CrtcLock (xf86CrtcPtr crtc)
44{
45    ScrnInfoPtr pScrn = crtc->scrn;
46    SMIPtr pSmi = SMIPTR(pScrn);
47
48    ENTER();
49
50    WaitIdle();
51
52    LEAVE(FALSE);
53}
54
55static void
56SMI_CrtcUnlock (xf86CrtcPtr crtc)
57{
58    ENTER();
59
60    /* Nothing */
61
62    LEAVE();
63}
64
65static Bool
66SMI_CrtcModeFixup(xf86CrtcPtr crtc,
67		  DisplayModePtr mode,
68		  DisplayModePtr adjusted_mode)
69{
70    ENTER();
71
72    /* Nothing */
73
74    LEAVE(TRUE);
75}
76
77static void
78SMI_CrtcPrepare(xf86CrtcPtr crtc)
79{
80    ENTER();
81    LEAVE();
82}
83
84static void
85SMI_CrtcCommit(xf86CrtcPtr crtc)
86{
87    ENTER();
88
89    crtc->funcs->dpms(crtc,DPMSModeOn);
90
91    LEAVE();
92}
93
94static void
95SMI_CrtcGammaSet(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
96	     int size)
97{
98    SMICrtcPrivatePtr crtcPriv = SMICRTC(crtc);
99    int i;
100
101    ENTER();
102
103    for(i=0; i<256; i++){
104	crtcPriv->lut_r[i] = red[i * size >> 8];
105	crtcPriv->lut_g[i] = green[i * size >> 8];
106	crtcPriv->lut_b[i] = blue[i * size >> 8];
107    }
108
109    crtcPriv->load_lut(crtc);
110
111    LEAVE();
112}
113
114static void *
115SMI_CrtcShadowAllocate (xf86CrtcPtr crtc, int width, int height)
116{
117    ScrnInfoPtr	 	 pScrn = crtc->scrn;
118    SMIPtr	 	 pSmi = SMIPTR(pScrn);
119    SMICrtcPrivatePtr	 crtcPriv = SMICRTC(crtc);
120    int			 offset, size;
121
122    ENTER();
123
124    size = ((width * pSmi->Bpp + 15) & ~15)  * height;
125    offset = SMI_AllocateMemory(pScrn, &crtcPriv->shadowArea, size);
126
127    if (!crtcPriv->shadowArea)
128	LEAVE(NULL);
129
130    LEAVE(pSmi->FBBase + offset);
131}
132
133static PixmapPtr
134SMI_CrtcShadowCreate (xf86CrtcPtr crtc, void *data, int width, int height)
135{
136    ScrnInfoPtr pScrn = crtc->scrn;
137    SMIPtr pSmi = SMIPTR(pScrn);
138    int aligned_pitch;
139
140    ENTER();
141
142    aligned_pitch = (width * pSmi->Bpp + 15) & ~15;
143
144    LEAVE(GetScratchPixmapHeader(pScrn->pScreen,width,height,pScrn->depth,
145				  pScrn->bitsPerPixel,aligned_pitch,data));
146}
147
148static void
149SMI_CrtcShadowDestroy (xf86CrtcPtr crtc, PixmapPtr pPixmap, void *data)
150{
151    ScrnInfoPtr		pScrn = crtc->scrn;
152    SMIPtr		pSmi = SMIPTR(pScrn);
153    SMICrtcPrivatePtr	crtcPriv = SMICRTC(crtc);
154
155    ENTER();
156
157    if (pSmi->useEXA && pPixmap)
158	FreeScratchPixmapHeader(pPixmap);
159
160    if (crtcPriv->shadowArea) {
161	SMI_FreeMemory(pScrn, crtcPriv->shadowArea);
162	crtcPriv->shadowArea = NULL;
163    }
164
165    LEAVE();
166}
167
168static void
169SMI_CrtcDestroy (xf86CrtcPtr	crtc)
170{
171    ENTER();
172
173    free(SMICRTC(crtc));
174    free((xf86CrtcFuncsPtr)crtc->funcs);
175
176    LEAVE();
177}
178
179static Bool
180SMI_CrtcConfigResize(ScrnInfoPtr       pScrn,
181		     int               width,
182		     int               height)
183{
184    SMIPtr pSmi = SMIPTR(pScrn);
185    xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
186    int i;
187    xf86CrtcPtr crtc;
188
189    ENTER();
190
191    /* Allocate another offscreen area and use it as screen, if it really has to be resized */
192    if(!pSmi->NoAccel && pSmi->useEXA &&
193       ( !pSmi->fbArea || width != pScrn->virtualX || height != pScrn->virtualY )){
194	int aligned_pitch = (width*pSmi->Bpp + 15) & ~15;
195
196	ExaOffscreenArea* fbArea = exaOffscreenAlloc(pScrn->pScreen, aligned_pitch*height, 16, TRUE, NULL, NULL);
197	if(!fbArea){
198	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
199		   "SMI_CrtcConfigResize: Not enough memory to resize the framebuffer\n");
200	    LEAVE(FALSE);
201	}
202
203	if(pSmi->fbArea)
204	    exaOffscreenFree(pScrn->pScreen, pSmi->fbArea);
205
206	pSmi->fbArea = fbArea;
207	pSmi->FBOffset = fbArea->offset;
208	pScrn->fbOffset = pSmi->FBOffset + pSmi->fbMapOffset;
209
210	pScrn->pScreen->ModifyPixmapHeader(pScrn->pScreen->GetScreenPixmap(pScrn->pScreen),
211					   -1,-1,-1,-1,-1, pSmi->FBBase + pSmi->FBOffset);
212
213#if (XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 9, 99, 1, 0))
214	if(pScrn->pixmapPrivate.ptr)
215	    /* The pixmap devPrivate just set may be overwritten by
216	       xf86EnableDisableFBAccess */
217	    pScrn->pixmapPrivate.ptr = pSmi->FBBase + pSmi->FBOffset;
218#endif
219
220	/* Modify the screen pitch */
221	pScrn->displayWidth = aligned_pitch / pSmi->Bpp;
222	pScrn->pScreen->ModifyPixmapHeader(pScrn->pScreen->GetScreenPixmap(pScrn->pScreen),
223					   -1, -1, -1, -1, aligned_pitch, NULL);
224
225	/* Modify the screen dimensions */
226	pScrn->virtualX = width;
227	pScrn->virtualY = height;
228	pScrn->pScreen->ModifyPixmapHeader(pScrn->pScreen->GetScreenPixmap(pScrn->pScreen),
229					   width, height, -1, -1, 0, NULL);
230    }
231
232    /* Setup each crtc video processor */
233    for(i=0;i<crtcConf->num_crtc;i++){
234	crtc = crtcConf->crtc[i];
235	SMICRTC(crtc)->video_init(crtc);
236	SMICRTC(crtc)->adjust_frame(crtc,crtc->x,crtc->y);
237    }
238
239    LEAVE(TRUE);
240}
241
242void
243SMI_CrtcFuncsInit_base(xf86CrtcFuncsPtr* crtcFuncs, SMICrtcPrivatePtr* crtcPriv){
244    *crtcFuncs = xnfcalloc(sizeof(xf86CrtcFuncsRec), 1);
245    *crtcPriv = xnfcalloc(sizeof(SMICrtcPrivateRec), 1);
246
247    (*crtcFuncs)->dpms = SMI_CrtcDPMS;
248    (*crtcFuncs)->lock = SMI_CrtcLock;
249    (*crtcFuncs)->unlock = SMI_CrtcUnlock;
250    (*crtcFuncs)->mode_fixup = SMI_CrtcModeFixup;
251    (*crtcFuncs)->prepare = SMI_CrtcPrepare;
252    (*crtcFuncs)->commit = SMI_CrtcCommit;
253    (*crtcFuncs)->gamma_set = SMI_CrtcGammaSet;
254    (*crtcFuncs)->shadow_allocate = SMI_CrtcShadowAllocate;
255    (*crtcFuncs)->shadow_create = SMI_CrtcShadowCreate;
256    (*crtcFuncs)->shadow_destroy = SMI_CrtcShadowDestroy;
257    (*crtcFuncs)->destroy = SMI_CrtcDestroy;
258}
259
260static xf86CrtcConfigFuncsRec SMI_CrtcConfigFuncs = {
261    .resize = SMI_CrtcConfigResize
262};
263
264Bool
265SMI_CrtcPreInit(ScrnInfoPtr pScrn)
266{
267    SMIPtr pSmi = SMIPTR(pScrn);
268
269    ENTER();
270
271    xf86CrtcConfigInit(pScrn,&SMI_CrtcConfigFuncs);
272
273    xf86CrtcSetSizeRange(pScrn,128,128,4096,4096);
274
275    if(SMI_MSOC_SERIES(pSmi->Chipset)){
276	LEAVE( SMI501_CrtcPreInit(pScrn) );
277    }else{
278	LEAVE( SMILynx_CrtcPreInit(pScrn) );
279    }
280}
281