1 /** @file
2   This file produces the graphics abstration of UGA Draw. It is called by
3   CirrusLogic5430.c file which deals with the EFI 1.1 driver model.
4   This file just does graphics.
5 
6   Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
7   This program and the accompanying materials
8   are licensed and made available under the terms and conditions of the BSD License
9   which accompanies this distribution.  The full text of the license may be found at
10   http://opensource.org/licenses/bsd-license.php
11 
12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include "CirrusLogic5430.h"
18 
19 //
20 // UGA Draw Protocol Member Functions
21 //
22 EFI_STATUS
23 EFIAPI
CirrusLogic5430UgaDrawGetMode(IN EFI_UGA_DRAW_PROTOCOL * This,OUT UINT32 * HorizontalResolution,OUT UINT32 * VerticalResolution,OUT UINT32 * ColorDepth,OUT UINT32 * RefreshRate)24 CirrusLogic5430UgaDrawGetMode (
25   IN  EFI_UGA_DRAW_PROTOCOL *This,
26   OUT UINT32                *HorizontalResolution,
27   OUT UINT32                *VerticalResolution,
28   OUT UINT32                *ColorDepth,
29   OUT UINT32                *RefreshRate
30   )
31 {
32   CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private;
33 
34   Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This);
35 
36   if (Private->HardwareNeedsStarting) {
37     return EFI_NOT_STARTED;
38   }
39 
40   if ((HorizontalResolution == NULL) ||
41       (VerticalResolution == NULL)   ||
42       (ColorDepth == NULL)           ||
43       (RefreshRate == NULL)) {
44     return EFI_INVALID_PARAMETER;
45   }
46 
47   *HorizontalResolution = Private->ModeData[Private->CurrentMode].HorizontalResolution;
48   *VerticalResolution   = Private->ModeData[Private->CurrentMode].VerticalResolution;
49   *ColorDepth           = Private->ModeData[Private->CurrentMode].ColorDepth;
50   *RefreshRate          = Private->ModeData[Private->CurrentMode].RefreshRate;
51 
52   return EFI_SUCCESS;
53 }
54 
55 EFI_STATUS
56 EFIAPI
CirrusLogic5430UgaDrawSetMode(IN EFI_UGA_DRAW_PROTOCOL * This,IN UINT32 HorizontalResolution,IN UINT32 VerticalResolution,IN UINT32 ColorDepth,IN UINT32 RefreshRate)57 CirrusLogic5430UgaDrawSetMode (
58   IN  EFI_UGA_DRAW_PROTOCOL *This,
59   IN  UINT32                HorizontalResolution,
60   IN  UINT32                VerticalResolution,
61   IN  UINT32                ColorDepth,
62   IN  UINT32                RefreshRate
63   )
64 {
65   CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private;
66   UINTN                           Index;
67 
68   Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This);
69 
70   for (Index = 0; Index < Private->MaxMode; Index++) {
71 
72     if (HorizontalResolution != Private->ModeData[Index].HorizontalResolution) {
73       continue;
74     }
75 
76     if (VerticalResolution != Private->ModeData[Index].VerticalResolution) {
77       continue;
78     }
79 
80     if (ColorDepth != Private->ModeData[Index].ColorDepth) {
81       continue;
82     }
83 
84     if (RefreshRate != Private->ModeData[Index].RefreshRate) {
85       continue;
86     }
87 
88     if (Private->LineBuffer) {
89       gBS->FreePool (Private->LineBuffer);
90     }
91 
92     Private->LineBuffer = NULL;
93     Private->LineBuffer = AllocatePool (HorizontalResolution);
94     if (Private->LineBuffer == NULL) {
95       return EFI_OUT_OF_RESOURCES;
96     }
97 
98     InitializeGraphicsMode (Private, &CirrusLogic5430VideoModes[Private->ModeData[Index].ModeNumber]);
99 
100     Private->CurrentMode            = Index;
101 
102     Private->HardwareNeedsStarting  = FALSE;
103 
104     return EFI_SUCCESS;
105   }
106 
107   return EFI_NOT_FOUND;
108 }
109 
110 EFI_STATUS
111 EFIAPI
CirrusLogic5430UgaDrawBlt(IN EFI_UGA_DRAW_PROTOCOL * This,IN EFI_UGA_PIXEL * BltBuffer,OPTIONAL IN EFI_UGA_BLT_OPERATION BltOperation,IN UINTN SourceX,IN UINTN SourceY,IN UINTN DestinationX,IN UINTN DestinationY,IN UINTN Width,IN UINTN Height,IN UINTN Delta)112 CirrusLogic5430UgaDrawBlt (
113   IN  EFI_UGA_DRAW_PROTOCOL     *This,
114   IN  EFI_UGA_PIXEL             *BltBuffer, OPTIONAL
115   IN  EFI_UGA_BLT_OPERATION     BltOperation,
116   IN  UINTN                     SourceX,
117   IN  UINTN                     SourceY,
118   IN  UINTN                     DestinationX,
119   IN  UINTN                     DestinationY,
120   IN  UINTN                     Width,
121   IN  UINTN                     Height,
122   IN  UINTN                     Delta
123   )
124 {
125   CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private;
126   EFI_TPL                         OriginalTPL;
127   UINTN                           DstY;
128   UINTN                           SrcY;
129   EFI_UGA_PIXEL                   *Blt;
130   UINTN                           X;
131   UINT8                           Pixel;
132   UINT32                          WidePixel;
133   UINTN                           ScreenWidth;
134   UINTN                           Offset;
135   UINTN                           SourceOffset;
136 
137   Private = CIRRUS_LOGIC_5430_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This);
138 
139   if ((UINT32)BltOperation >= EfiUgaBltMax) {
140     return EFI_INVALID_PARAMETER;
141   }
142 
143   if (Width == 0 || Height == 0) {
144     return EFI_INVALID_PARAMETER;
145   }
146 
147   //
148   // If Delta is zero, then the entire BltBuffer is being used, so Delta
149   // is the number of bytes in each row of BltBuffer.  Since BltBuffer is Width pixels size,
150   // the number of bytes in each row can be computed.
151   //
152   if (Delta == 0) {
153     Delta = Width * sizeof (EFI_UGA_PIXEL);
154   }
155 
156   //
157   // We need to fill the Virtual Screen buffer with the blt data.
158   // The virtual screen is upside down, as the first row is the bootom row of
159   // the image.
160   //
161 
162   //
163   // Make sure the SourceX, SourceY, DestinationX, DestinationY, Width, and Height parameters
164   // are valid for the operation and the current screen geometry.
165   //
166   if (BltOperation == EfiUgaVideoToBltBuffer) {
167     //
168     // Video to BltBuffer: Source is Video, destination is BltBuffer
169     //
170     if (SourceY + Height > Private->ModeData[Private->CurrentMode].VerticalResolution) {
171       return EFI_INVALID_PARAMETER;
172     }
173 
174     if (SourceX + Width > Private->ModeData[Private->CurrentMode].HorizontalResolution) {
175       return EFI_INVALID_PARAMETER;
176     }
177   } else {
178     //
179     // BltBuffer to Video: Source is BltBuffer, destination is Video
180     //
181     if (DestinationY + Height > Private->ModeData[Private->CurrentMode].VerticalResolution) {
182       return EFI_INVALID_PARAMETER;
183     }
184 
185     if (DestinationX + Width > Private->ModeData[Private->CurrentMode].HorizontalResolution) {
186       return EFI_INVALID_PARAMETER;
187     }
188   }
189   //
190   // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
191   // We would not want a timer based event (Cursor, ...) to come in while we are
192   // doing this operation.
193   //
194   OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
195 
196   switch (BltOperation) {
197   case EfiUgaVideoToBltBuffer:
198     //
199     // Video to BltBuffer: Source is Video, destination is BltBuffer
200     //
201     for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
202 
203       Offset = (SrcY * Private->ModeData[Private->CurrentMode].HorizontalResolution) + SourceX;
204       if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) {
205         Private->PciIo->Mem.Read (
206                               Private->PciIo,
207                               EfiPciIoWidthUint32,
208                               0,
209                               Offset,
210                               Width >> 2,
211                               Private->LineBuffer
212                               );
213       } else {
214         Private->PciIo->Mem.Read (
215                               Private->PciIo,
216                               EfiPciIoWidthUint8,
217                               0,
218                               Offset,
219                               Width,
220                               Private->LineBuffer
221                               );
222       }
223 
224       for (X = 0; X < Width; X++) {
225         Blt         = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Delta) + (DestinationX + X) * sizeof (EFI_UGA_PIXEL));
226 
227         Blt->Red    = (UINT8) (Private->LineBuffer[X] & 0xe0);
228         Blt->Green  = (UINT8) ((Private->LineBuffer[X] & 0x1c) << 3);
229         Blt->Blue   = (UINT8) ((Private->LineBuffer[X] & 0x03) << 6);
230       }
231     }
232     break;
233 
234   case EfiUgaVideoToVideo:
235     //
236     // Perform hardware acceleration for Video to Video operations
237     //
238     ScreenWidth   = Private->ModeData[Private->CurrentMode].HorizontalResolution;
239     SourceOffset  = (SourceY * Private->ModeData[Private->CurrentMode].HorizontalResolution) + (SourceX);
240     Offset        = (DestinationY * Private->ModeData[Private->CurrentMode].HorizontalResolution) + (DestinationX);
241 
242     outw (Private, GRAPH_ADDRESS_REGISTER, 0x0000);
243     outw (Private, GRAPH_ADDRESS_REGISTER, 0x0010);
244     outw (Private, GRAPH_ADDRESS_REGISTER, 0x0012);
245     outw (Private, GRAPH_ADDRESS_REGISTER, 0x0014);
246 
247     outw (Private, GRAPH_ADDRESS_REGISTER, 0x0001);
248     outw (Private, GRAPH_ADDRESS_REGISTER, 0x0011);
249     outw (Private, GRAPH_ADDRESS_REGISTER, 0x0013);
250     outw (Private, GRAPH_ADDRESS_REGISTER, 0x0015);
251 
252     outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((Width << 8) & 0xff00) | 0x20));
253     outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((Width & 0xff00) | 0x21));
254     outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((Height << 8) & 0xff00) | 0x22));
255     outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((Height & 0xff00) | 0x23));
256     outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((ScreenWidth << 8) & 0xff00) | 0x24));
257     outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((ScreenWidth & 0xff00) | 0x25));
258     outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) (((ScreenWidth << 8) & 0xff00) | 0x26));
259     outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((ScreenWidth & 0xff00) | 0x27));
260     outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) << 8) & 0xff00) | 0x28));
261     outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) >> 0) & 0xff00) | 0x29));
262     outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((Offset) >> 8) & 0xff00) | 0x2a));
263     outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) << 8) & 0xff00) | 0x2c));
264     outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) >> 0) & 0xff00) | 0x2d));
265     outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((((SourceOffset) >> 8) & 0xff00) | 0x2e));
266     outw (Private, GRAPH_ADDRESS_REGISTER, 0x002f);
267     outw (Private, GRAPH_ADDRESS_REGISTER, 0x0030);
268     outw (Private, GRAPH_ADDRESS_REGISTER, 0x0d32);
269     outw (Private, GRAPH_ADDRESS_REGISTER, 0x0033);
270     outw (Private, GRAPH_ADDRESS_REGISTER, 0x0034);
271     outw (Private, GRAPH_ADDRESS_REGISTER, 0x0035);
272 
273     outw (Private, GRAPH_ADDRESS_REGISTER, 0x0231);
274 
275     outb (Private, GRAPH_ADDRESS_REGISTER, 0x31);
276     while ((inb (Private, GRAPH_DATA_REGISTER) & 0x01) == 0x01)
277       ;
278     break;
279 
280   case EfiUgaVideoFill:
281     Blt       = BltBuffer;
282     Pixel     = (UINT8) ((Blt->Red & 0xe0) | ((Blt->Green >> 3) & 0x1c) | ((Blt->Blue >> 6) & 0x03));
283     WidePixel = (Pixel << 8) | Pixel;
284     WidePixel = (WidePixel << 16) | WidePixel;
285 
286     if (DestinationX == 0 && Width == Private->ModeData[Private->CurrentMode].HorizontalResolution) {
287       Offset = DestinationY * Private->ModeData[Private->CurrentMode].HorizontalResolution;
288       if (((Offset & 0x03) == 0) && (((Width * Height) & 0x03) == 0)) {
289         Private->PciIo->Mem.Write (
290                               Private->PciIo,
291                               EfiPciIoWidthFillUint32,
292                               0,
293                               Offset,
294                               (Width * Height) >> 2,
295                               &WidePixel
296                               );
297       } else {
298         Private->PciIo->Mem.Write (
299                               Private->PciIo,
300                               EfiPciIoWidthFillUint8,
301                               0,
302                               Offset,
303                               Width * Height,
304                               &Pixel
305                               );
306       }
307     } else {
308       for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
309         Offset = (DstY * Private->ModeData[Private->CurrentMode].HorizontalResolution) + DestinationX;
310         if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) {
311           Private->PciIo->Mem.Write (
312                                 Private->PciIo,
313                                 EfiPciIoWidthFillUint32,
314                                 0,
315                                 Offset,
316                                 Width >> 2,
317                                 &WidePixel
318                                 );
319         } else {
320           Private->PciIo->Mem.Write (
321                                 Private->PciIo,
322                                 EfiPciIoWidthFillUint8,
323                                 0,
324                                 Offset,
325                                 Width,
326                                 &Pixel
327                                 );
328         }
329       }
330     }
331     break;
332 
333   case EfiUgaBltBufferToVideo:
334     for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
335 
336       for (X = 0; X < Width; X++) {
337         Blt                     = (EFI_UGA_PIXEL *) ((UINT8 *) BltBuffer + (SrcY * Delta) + (SourceX + X) * sizeof (EFI_UGA_PIXEL));
338         Private->LineBuffer[X]  = (UINT8) ((Blt->Red & 0xe0) | ((Blt->Green >> 3) & 0x1c) | ((Blt->Blue >> 6) & 0x03));
339       }
340 
341       Offset = (DstY * Private->ModeData[Private->CurrentMode].HorizontalResolution) + DestinationX;
342 
343       if (((Offset & 0x03) == 0) && ((Width & 0x03) == 0)) {
344         Private->PciIo->Mem.Write (
345                               Private->PciIo,
346                               EfiPciIoWidthUint32,
347                               0,
348                               Offset,
349                               Width >> 2,
350                               Private->LineBuffer
351                               );
352       } else {
353         Private->PciIo->Mem.Write (
354                               Private->PciIo,
355                               EfiPciIoWidthUint8,
356                               0,
357                               Offset,
358                               Width,
359                               Private->LineBuffer
360                               );
361       }
362     }
363     break;
364 
365   default:
366     break;
367   }
368 
369   gBS->RestoreTPL (OriginalTPL);
370 
371   return EFI_SUCCESS;
372 }
373 
374 //
375 // Construction and Destruction functions
376 //
377 EFI_STATUS
CirrusLogic5430UgaDrawConstructor(CIRRUS_LOGIC_5430_PRIVATE_DATA * Private)378 CirrusLogic5430UgaDrawConstructor (
379   CIRRUS_LOGIC_5430_PRIVATE_DATA  *Private
380   )
381 {
382   EFI_UGA_DRAW_PROTOCOL *UgaDraw;
383 
384   //
385   // Fill in Private->UgaDraw protocol
386   //
387   UgaDraw           = &Private->UgaDraw;
388 
389   UgaDraw->GetMode  = CirrusLogic5430UgaDrawGetMode;
390   UgaDraw->SetMode  = CirrusLogic5430UgaDrawSetMode;
391   UgaDraw->Blt      = CirrusLogic5430UgaDrawBlt;
392 
393   //
394   // Initialize the private data
395   //
396   Private->CurrentMode            = 0;
397   Private->HardwareNeedsStarting  = TRUE;
398   Private->LineBuffer             = NULL;
399 
400   //
401   // Initialize the hardware
402   //
403   UgaDraw->SetMode (
404             UgaDraw,
405             Private->ModeData[Private->CurrentMode].HorizontalResolution,
406             Private->ModeData[Private->CurrentMode].VerticalResolution,
407             Private->ModeData[Private->CurrentMode].ColorDepth,
408             Private->ModeData[Private->CurrentMode].RefreshRate
409             );
410   DrawLogo (
411     Private,
412     Private->ModeData[Private->CurrentMode].HorizontalResolution,
413     Private->ModeData[Private->CurrentMode].VerticalResolution
414     );
415 
416   return EFI_SUCCESS;
417 }
418 
419