Home | History | Annotate | Line # | Download | only in src
      1 /* Copyright (c) 2008 Advanced Micro Devices, Inc.
      2  *
      3  * Permission is hereby granted, free of charge, to any person obtaining a copy
      4  * of this software and associated documentation files (the "Software"), to
      5  * deal in the Software without restriction, including without limitation the
      6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      7  * sell copies of the Software, and to permit persons to whom the Software is
      8  * furnished to do so, subject to the following conditions:
      9  *
     10  * The above copyright notice and this permission notice shall be included in
     11  * all copies or substantial portions of the Software.
     12  *
     13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     19  * IN THE SOFTWARE.
     20  *
     21  * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
     22  * contributors may be used to endorse or promote products derived from this
     23  * software without specific prior written permission.
     24  */
     25 #if HAVE_CONFIG_H
     26 #include "config.h"
     27 #endif
     28 
     29 #include "xorg-server.h"
     30 
     31 #include "xf86.h"
     32 #include "geode.h"
     33 #include "cim/cim_regs.h"
     34 
     35 #define ALIGN(x,y)   (((x) + (y) - 1) / (y) * (y))
     36 #define LX_CB_PITCH   544
     37 
     38 /* Geode offscreen memory allocation functions.  This is
     39    overengineered for the simple hardware that we have, but
     40    there are multiple functions that may want to independently
     41    allocate and free memory (crtc->shadow_alloc and Xv).  This
     42    provides a semi-robust mechanism for doing that.
     43 */
     44 
     45 /* Return the number of free bytes */
     46 
     47 unsigned int
     48 GeodeOffscreenFreeSize(GeodeRec * pGeode)
     49 {
     50     GeodeMemPtr ptr = pGeode->offscreenList;
     51 
     52     if (ptr == NULL)
     53         return pGeode->offscreenSize;
     54 
     55     for (; ptr->next; ptr = ptr->next);
     56     return (pGeode->offscreenStart + pGeode->offscreenSize)
     57         - (ptr->offset + ptr->size);
     58 }
     59 
     60 void
     61 GeodeFreeOffscreen(GeodeRec * pGeode, GeodeMemPtr ptr)
     62 {
     63     /* There is a clear memory leak here, but
     64      * but it is unlikely that the first block of
     65      * "allocated" memory is going to be released
     66      * individually.
     67      */
     68 
     69     if (ptr->prev == NULL)
     70         pGeode->offscreenList = ptr->next;
     71     else
     72         ptr->prev->next = ptr->next;
     73 
     74     if (ptr->next)
     75         ptr->next->prev = ptr->prev;
     76 
     77     free(ptr);
     78 }
     79 
     80 /* Allocate the "rest" of the offscreen memory - this is for
     81    situations where we have very little video memory, and we
     82    want to take as much of it as we can for EXA
     83 */
     84 
     85 static GeodeMemPtr
     86 GeodeAllocRemainder(GeodeRec * pGeode)
     87 {
     88     GeodeMemPtr nptr, ptr = pGeode->offscreenList;
     89 
     90     if (!pGeode->offscreenList) {
     91         pGeode->offscreenList = calloc(1, sizeof(*nptr));
     92         pGeode->offscreenList->offset = pGeode->offscreenStart;
     93         pGeode->offscreenList->size = pGeode->offscreenSize;
     94         pGeode->offscreenList->next = NULL;
     95         pGeode->offscreenList->prev = NULL;
     96 
     97         return pGeode->offscreenList;
     98     }
     99 
    100     /* Go to the end of the list of allocated stuff */
    101     for (; ptr->next; ptr = ptr->next);
    102 
    103     nptr = calloc(1, sizeof(*nptr));
    104     nptr->offset = ptr->offset + ptr->size;
    105     nptr->size = pGeode->offscreenSize -
    106         (nptr->offset - pGeode->offscreenStart);
    107 
    108     nptr->next = ptr->next;
    109     nptr->prev = ptr;
    110     ptr->next = nptr;
    111 
    112     return nptr;
    113 }
    114 
    115 /* Allocate 'size' bytes of offscreen memory.
    116 */
    117 
    118 GeodeMemPtr
    119 GeodeAllocOffscreen(GeodeRec * pGeode, int size, int align)
    120 {
    121     GeodeMemPtr ptr = pGeode->offscreenList;
    122     GeodeMemPtr nptr;
    123 
    124     unsigned int offset;
    125 
    126     if (!pGeode->offscreenList) {
    127 
    128         if (size > pGeode->offscreenSize)
    129             return NULL;
    130 
    131         offset = ALIGN(pGeode->offscreenStart, align);
    132 
    133         pGeode->offscreenList = calloc(1, sizeof(*nptr));
    134         pGeode->offscreenList->offset = offset;
    135         pGeode->offscreenList->size = size;
    136         pGeode->offscreenList->next = NULL;
    137 
    138         return pGeode->offscreenList;
    139     }
    140 
    141     while (ptr) {
    142         unsigned int gap;
    143 
    144         if (ptr->next == NULL)
    145             gap = pGeode->offscreenSize + pGeode->offscreenStart;
    146 
    147         else
    148             gap = ptr->next->offset;
    149 
    150         gap = gap - (ptr->offset + ptr->size);
    151         gap = ALIGN(gap, align);
    152 
    153         if (size < gap) {
    154             offset = ptr->offset + ptr->size;
    155             offset = ALIGN(ptr->offset + ptr->size, align);
    156 
    157             nptr = calloc(1, sizeof(*nptr));
    158             nptr->offset = offset;
    159             nptr->size = size;
    160             nptr->next = ptr->next;
    161             nptr->prev = ptr;
    162             ptr->next = nptr;
    163 
    164             return nptr;
    165         }
    166 
    167         ptr = ptr->next;
    168     }
    169 
    170     return NULL;
    171 }
    172 
    173 /* Carve out the space for the visible screen, and carve out
    174    the usual suspects that need offscreen memory
    175 */
    176 
    177 #define MAX(a,b) ((a) > (b) ? (a) : (b))
    178 
    179 void
    180 LXInitOffscreen(ScrnInfoPtr pScrni)
    181 {
    182     GeodeRec *pGeode = GEODEPTR(pScrni);
    183     unsigned int fbavail;
    184     GeodeMemPtr ptr;
    185 
    186     /* The scratch buffer is always used */
    187     fbavail = pGeode->FBAvail - GP3_SCRATCH_BUFFER_SIZE;
    188 
    189     pGeode->displaySize = MAX(pScrni->virtualX, pScrni->virtualY)
    190         * pGeode->Pitch;
    191 
    192     pGeode->offscreenStart = pGeode->displaySize;
    193     pGeode->offscreenSize = fbavail - pGeode->displaySize;
    194 
    195     /* Allocate the usual memory suspects */
    196     if (pGeode->tryCompression) {
    197         int size = pScrni->virtualY * LX_CB_PITCH;
    198 
    199         /* The compression buffer needs to be 16 byte aligned */
    200         ptr = GeodeAllocOffscreen(pGeode, size, 16);
    201 
    202         if (ptr != NULL) {
    203             pGeode->CBData.compression_offset = ptr->offset;
    204             pGeode->CBData.size = LX_CB_PITCH;
    205             pGeode->CBData.pitch = LX_CB_PITCH;
    206 
    207             pGeode->Compression = TRUE;
    208         }
    209         else {
    210             xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
    211                        "Not enough memory for compression\n");
    212             pGeode->Compression = FALSE;
    213         }
    214     }
    215 
    216     if (pGeode->tryHWCursor) {
    217         ptr = GeodeAllocOffscreen(pGeode,
    218                                   LX_CURSOR_HW_WIDTH * 4 * LX_CURSOR_HW_HEIGHT,
    219                                   4);
    220 
    221         if (ptr != NULL) {
    222             pGeode->CursorStartOffset = ptr->offset;
    223             pGeode->HWCursor = TRUE;
    224         }
    225         else {
    226             xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
    227                        "Not enough memory for the hardware cursor\n");
    228             pGeode->HWCursor = FALSE;
    229         }
    230     }
    231 
    232     if (!pGeode->NoAccel && pGeode->pExa) {
    233         int size;
    234 
    235         /* Try to get the scratch buffer for blending */
    236         pGeode->exaBfrOffset = 0;
    237 
    238         if (pGeode->exaBfrSz > 0) {
    239             ptr = GeodeAllocOffscreen(pGeode, pGeode->exaBfrSz, 4);
    240             if (ptr != NULL)
    241                 pGeode->exaBfrOffset = ptr->offset;
    242         }
    243 
    244         pGeode->pExa->offScreenBase = 0;
    245         pGeode->pExa->memorySize = 0;
    246 
    247         /* This might cause complaints - in order to avoid using
    248            xorg.conf as much as possible, we make assumptions about
    249            what a "default" memory map would look like.  After
    250            discussion, we agreed that the default driver should assume
    251            the user will want to use rotation and video overlays, and
    252            EXA will get whatever is leftover.
    253          */
    254 
    255         /* Get the amount of offscreen memory still left */
    256         size = GeodeOffscreenFreeSize(pGeode);
    257 
    258         /* Align the size to a K boundary */
    259         size &= ~1023;
    260 
    261         /* Allocate the EXA offscreen space */
    262         ptr = GeodeAllocOffscreen(pGeode, size, 4);
    263 
    264         if (ptr == NULL) {
    265             /* If we couldn't allocate what we wanted,
    266              * then allocate what's left */
    267 
    268             ptr = GeodeAllocRemainder(pGeode);
    269         }
    270 
    271         if (ptr != NULL) {
    272             pGeode->pExa->offScreenBase = ptr->offset;
    273             pGeode->pExa->memorySize = ptr->offset + ptr->size;
    274         }
    275     }
    276 
    277     /* Show the memory map for diagnostic purposes */
    278 
    279     xf86DrvMsg(pScrni->scrnIndex, X_INFO, "LX video memory:\n");
    280     xf86DrvMsg(pScrni->scrnIndex, X_INFO, " Display: 0x%x bytes\n",
    281                pGeode->displaySize);
    282 
    283     if (pGeode->Compression)
    284         xf86DrvMsg(pScrni->scrnIndex, X_INFO, " Compression: 0x%x bytes\n",
    285                    pScrni->virtualY * LX_CB_PITCH);
    286 
    287     if (pGeode->HWCursor)
    288         xf86DrvMsg(pScrni->scrnIndex, X_INFO, " Cursor: 0x%x bytes\n",
    289                    LX_CURSOR_HW_WIDTH * 4 * LX_CURSOR_HW_HEIGHT);
    290 
    291     if (pGeode->exaBfrSz)
    292         xf86DrvMsg(pScrni->scrnIndex, X_INFO, " ExaBfrSz: 0x%x bytes\n",
    293                    pGeode->exaBfrSz);
    294 
    295     if (pGeode->pExa && pGeode->pExa->offScreenBase)
    296         xf86DrvMsg(pScrni->scrnIndex, X_INFO, " EXA: 0x%x bytes\n",
    297                    (unsigned int) (pGeode->pExa->memorySize -
    298                                    pGeode->pExa->offScreenBase));
    299 
    300     xf86DrvMsg(pScrni->scrnIndex, X_INFO, " FREE: 0x%x bytes\n",
    301                GeodeOffscreenFreeSize(pGeode));
    302 }
    303 
    304 /* Called as we go down, so blitz everybody */
    305 
    306 void
    307 GeodeCloseOffscreen(ScrnInfoPtr pScrni)
    308 {
    309     GeodeRec *pGeode = GEODEPTR(pScrni);
    310     GeodeMemPtr ptr = pGeode->offscreenList;
    311     GeodeMemPtr nptr;
    312 
    313     while (ptr) {
    314         nptr = ptr->next;
    315         free(ptr);
    316         ptr = nptr;
    317     }
    318 
    319     pGeode->offscreenList = NULL;
    320 }
    321