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//
22EFI_STATUS
23EFIAPI
24CirrusLogic5430UgaDrawGetMode (
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
55EFI_STATUS
56EFIAPI
57CirrusLogic5430UgaDrawSetMode (
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
110EFI_STATUS
111EFIAPI
112CirrusLogic5430UgaDrawBlt (
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//
377EFI_STATUS
378CirrusLogic5430UgaDrawConstructor (
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