| /**************************************************************************** |
| * |
| * The MIT License (MIT) |
| * |
| * Copyright (c) 2014 - 2020 Vivante 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 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. |
| * |
| ***************************************************************************** |
| * |
| * The GPL License (GPL) |
| * |
| * Copyright (C) 2014 - 2020 Vivante Corporation |
| * |
| * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| * |
| ***************************************************************************** |
| * |
| * Note: This software is released under dual MIT and GPL licenses. A |
| * recipient may use this file under the terms of either the MIT license or |
| * GPL License. If you wish to use only one license not the other, you can |
| * indicate your decision by deleting one of the above license notices in your |
| * version of this file. |
| * |
| *****************************************************************************/ |
| |
| |
| #include "gc_hal.h" |
| #include "gc_hal_kernel.h" |
| #include "gc_hal_kernel_context.h" |
| |
| #define _GC_OBJ_ZONE gcvZONE_HARDWARE |
| |
| typedef struct _gcsMCFE_DESCRIPTOR |
| { |
| gctUINT32 start; |
| gctUINT32 end; |
| } |
| gcsMCFE_DESCRIPTOR; |
| |
| /* 2^DepthExp = Depth. */ |
| #define MCFE_RINGBUF_DEPTH_EXP 9 |
| /* Depth. */ |
| #define MCFE_RINGBUF_DEPTH (1 << MCFE_RINGBUF_DEPTH_EXP) |
| /* MCFE descriptor size in bytes, fixed 8. */ |
| #define MCFE_COMMAND_DESC_SIZE 8 |
| /* FIFO size in bytes. */ |
| #define MCFE_RINGBUF_SIZE (MCFE_RINGBUF_DEPTH * MCFE_COMMAND_DESC_SIZE) |
| |
| typedef struct _gcsMCFE_RING_BUF |
| { |
| gckVIDMEM_NODE ringBufVideoMem; |
| gctUINT32 ringBufAddress; |
| gctUINT32 * ringBufLogical; |
| gctSIZE_T ringBufBytes; |
| |
| gctUINT32 gpuAddress; |
| gctPHYS_ADDR_T physical; |
| |
| /* Read ptr should be often out-of-date. */ |
| gctUINT32 readPtr; |
| gctUINT32 writePtr; |
| } |
| gcsMCFE_RING_BUF; |
| |
| typedef struct _gcsMCFE_CHANNEL |
| { |
| gceMCFE_CHANNEL_TYPE binding; |
| gcsMCFE_RING_BUF stdRingBuf; |
| gcsMCFE_RING_BUF priRingBuf; |
| } |
| gcsMCFE_CHANNEL; |
| |
| struct _gckMCFE |
| { |
| gctUINT32 channelCount; |
| gctBOOL mmuEnabled; |
| |
| /* |
| * Channels must be the last field. |
| * Will allocate struct size according to channel count. |
| */ |
| gcsMCFE_CHANNEL channels[1]; |
| }; |
| |
| static gcmINLINE gctUINT32 |
| _NextPtr( |
| gctUINT32 Ptr |
| ) |
| { |
| return (Ptr + 1) & (MCFE_RINGBUF_DEPTH - 1); |
| } |
| |
| static gceSTATUS |
| _AllocateDescRingBuf( |
| gckHARDWARE Hardware, |
| gcsMCFE_RING_BUF * Channel |
| ) |
| { |
| gceSTATUS status; |
| gcePOOL pool = gcvPOOL_DEFAULT; |
| gckKERNEL kernel = Hardware->kernel; |
| gctUINT32 allocFlag = 0; |
| |
| #if gcdENABLE_CACHEABLE_COMMAND_BUFFER |
| allocFlag |= gcvALLOC_FLAG_CACHEABLE; |
| #endif |
| |
| Channel->ringBufBytes = MCFE_RINGBUF_SIZE; |
| |
| /* Allocate video memory node for mcfe ring buffer. */ |
| gcmkONERROR(gckKERNEL_AllocateVideoMemory( |
| kernel, |
| 64, |
| gcvVIDMEM_TYPE_COMMAND, |
| allocFlag, |
| &Channel->ringBufBytes, |
| &pool, |
| &Channel->ringBufVideoMem |
| )); |
| |
| /* Lock for GPU access. */ |
| gcmkONERROR(gckVIDMEM_NODE_Lock( |
| kernel, |
| Channel->ringBufVideoMem, |
| &Channel->gpuAddress |
| )); |
| |
| /* Lock for kernel side CPU access. */ |
| gcmkONERROR(gckVIDMEM_NODE_LockCPU( |
| kernel, |
| Channel->ringBufVideoMem, |
| gcvFALSE, |
| gcvFALSE, |
| (gctPOINTER *)&Channel->ringBufLogical |
| )); |
| |
| /* Get CPU physical address. */ |
| gcmkONERROR(gckVIDMEM_NODE_GetPhysical( |
| kernel, |
| Channel->ringBufVideoMem, |
| 0, |
| &Channel->physical |
| )); |
| |
| gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical( |
| Hardware->os, Channel->physical, &Channel->physical)); |
| |
| if (Channel->physical > 0xffffffffull) |
| { |
| gcmkPRINT("%s(%d): MCFE ring buffer physical over 4G: 0x%llx", |
| __FUNCTION__, __LINE__, (unsigned long long)Channel->physical); |
| } |
| |
| /* Default to use physical. */ |
| Channel->ringBufAddress = (gctUINT32)Channel->physical; |
| |
| return gcvSTATUS_OK; |
| |
| OnError: |
| return status; |
| } |
| |
| static void |
| _DestroyDescRingBuf( |
| gckHARDWARE Hardware, |
| gcsMCFE_RING_BUF * Channel |
| ) |
| { |
| gckKERNEL kernel = Hardware->kernel; |
| |
| if (Channel->ringBufVideoMem) |
| { |
| gcmkVERIFY_OK(gckVIDMEM_NODE_UnlockCPU( |
| kernel, |
| Channel->ringBufVideoMem, |
| 0, |
| gcvFALSE, |
| gcvFALSE |
| )); |
| |
| gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference( |
| kernel, |
| Channel->ringBufVideoMem |
| )); |
| |
| Channel->ringBufVideoMem = gcvNULL; |
| Channel->ringBufLogical = gcvNULL; |
| } |
| } |
| |
| static gcmINLINE void |
| _DestroyMCFE( |
| IN gckHARDWARE Hardware, |
| IN gckMCFE FE |
| ) |
| { |
| if (FE) |
| { |
| gctUINT i; |
| |
| for (i = 0; i < FE->channelCount; i++) |
| { |
| if (FE->channels[i].binding) |
| { |
| _DestroyDescRingBuf(Hardware, &FE->channels[i].stdRingBuf); |
| _DestroyDescRingBuf(Hardware, &FE->channels[i].priRingBuf); |
| } |
| } |
| |
| gcmkOS_SAFE_FREE(Hardware->os, FE); |
| } |
| } |
| |
| |
| static gceSTATUS |
| _ConstructChannel( |
| IN gckHARDWARE Hardware, |
| IN gceMCFE_CHANNEL_TYPE ChannelType, |
| IN gcsMCFE_CHANNEL * Channel |
| ) |
| { |
| Channel->binding = ChannelType; |
| |
| return gcvSTATUS_OK; |
| } |
| |
| gceSTATUS |
| gckMCFE_Construct( |
| IN gckHARDWARE Hardware, |
| OUT gckMCFE *FE |
| ) |
| { |
| gceSTATUS status; |
| gckMCFE fe = gcvNULL; |
| gctUINT32 i; |
| gctSIZE_T size = sizeof(struct _gckMCFE); |
| |
| if (Hardware->mcfeChannelCount > 1) |
| { |
| size += sizeof(gcsMCFE_CHANNEL) * (Hardware->mcfeChannelCount - 1); |
| } |
| |
| gcmkONERROR(gckOS_Allocate(Hardware->os, |
| size, |
| (gctPOINTER *)&fe)); |
| |
| gckOS_ZeroMemory(fe, size); |
| |
| fe->channelCount = Hardware->mcfeChannelCount; |
| |
| for (i = 0; i < fe->channelCount; i++) |
| { |
| gcmkONERROR( |
| _ConstructChannel(Hardware, |
| Hardware->mcfeChannels[i], |
| &fe->channels[i])); |
| } |
| |
| /* Enable all events. */ |
| gcmkONERROR( |
| gckOS_WriteRegisterEx(Hardware->os, |
| Hardware->core, |
| 0x00014, |
| 0xFFFFFFFF)); |
| |
| *FE = fe; |
| return gcvSTATUS_OK; |
| |
| OnError: |
| _DestroyMCFE(Hardware, fe); |
| return status; |
| } |
| |
| void |
| gckMCFE_Destroy( |
| IN gckHARDWARE Hardware, |
| IN gckMCFE FE |
| ) |
| { |
| _DestroyMCFE(Hardware, FE); |
| } |
| |
| static gceSTATUS |
| _ProgramDescRingBuf( |
| IN gckHARDWARE Hardware, |
| IN gctBOOL MMUEnabled, |
| IN gcsMCFE_RING_BUF * Channel, |
| IN gctUINT32 Index, |
| IN gctBOOL Priority |
| ) |
| { |
| gctUINT32 ringBufStartReg; |
| gctUINT32 depthExpReg; |
| gctUINT32 readPtrReg; |
| gctUINT32 writePtrReg; |
| gctUINT32 data = 0; |
| |
| if (Priority) |
| { |
| ringBufStartReg = 0x02800; |
| depthExpReg = 0x02900; |
| readPtrReg = 0x02B00; |
| writePtrReg = 0x02A00; |
| } |
| else |
| { |
| ringBufStartReg = 0x02400; |
| depthExpReg = 0x02500; |
| readPtrReg = 0x02700; |
| writePtrReg = 0x02600; |
| } |
| |
| ringBufStartReg += Index << 2; |
| depthExpReg += Index << 2; |
| readPtrReg += Index << 2; |
| writePtrReg += Index << 2; |
| |
| Channel->ringBufAddress = MMUEnabled ? Channel->gpuAddress |
| : (gctUINT32)Channel->physical; |
| |
| /* Channel ringBuf start address. */ |
| gcmkVERIFY_OK(gckOS_WriteRegisterEx( |
| Hardware->os, Hardware->core, ringBufStartReg, Channel->ringBufAddress)); |
| |
| /* Channel ringBuf depth (exponent of 2). */ |
| gcmkVERIFY_OK(gckOS_WriteRegisterEx( |
| Hardware->os, Hardware->core, depthExpReg, MCFE_RINGBUF_DEPTH_EXP)); |
| |
| /* The RD ptr could keep unchanged, read and compute WR ptr. */ |
| gcmkVERIFY_OK(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, readPtrReg, &data)); |
| |
| /* Priority ring buffer write ptr. */ |
| /* gcmkVERIFY_OK(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, writePtrReg, data)); */ |
| |
| /* No valid descriptor initially. */ |
| Channel->readPtr = Channel->writePtr = data; |
| |
| return gcvSTATUS_OK; |
| } |
| |
| static gceSTATUS |
| _InitializeChannel( |
| IN gckHARDWARE Hardware, |
| IN gctBOOL MMUEnabled, |
| IN gcsMCFE_CHANNEL * Channel, |
| IN gctUINT32 Index |
| ) |
| { |
| gceSTATUS status; |
| |
| /* Allocate ring buffer descriptor memory. */ |
| if (!Channel->stdRingBuf.ringBufVideoMem) |
| { |
| gcmkONERROR(_AllocateDescRingBuf(Hardware, &Channel->stdRingBuf)); |
| } |
| |
| /* No priority channel in system engine. */ |
| if (!Channel->priRingBuf.ringBufVideoMem && Index != 0) |
| { |
| gcmkONERROR(_AllocateDescRingBuf(Hardware, &Channel->priRingBuf)); |
| } |
| |
| gcmkONERROR(_ProgramDescRingBuf(Hardware, MMUEnabled, &Channel->stdRingBuf, Index, gcvFALSE)); |
| |
| /* No priority channel in system engine. */ |
| if (Channel->binding != gcvMCFE_CHANNEL_SYSTEM) |
| { |
| gcmkONERROR(_ProgramDescRingBuf(Hardware, MMUEnabled, &Channel->priRingBuf, Index, gcvTRUE)); |
| } |
| |
| return gcvSTATUS_OK; |
| |
| OnError: |
| /* It's OK to leave ringBuf memory not free'd here. */ |
| return status; |
| } |
| |
| gceSTATUS |
| gckMCFE_Initialize( |
| IN gckHARDWARE Hardware, |
| IN gctBOOL MMUEnabled, |
| IN gckMCFE FE |
| ) |
| { |
| gctUINT32 i; |
| gceSTATUS status; |
| |
| for (i = 0; i < FE->channelCount; i++) |
| { |
| if (FE->channels[i].binding) |
| { |
| gcmkONERROR(_InitializeChannel(Hardware, MMUEnabled, &FE->channels[i], i)); |
| } |
| } |
| |
| FE->mmuEnabled = MMUEnabled; |
| return gcvSTATUS_OK; |
| |
| OnError: |
| return status; |
| } |
| |
| gceSTATUS |
| gckMCFE_Nop( |
| IN gckHARDWARE Hardware, |
| IN gctPOINTER Logical, |
| IN OUT gctSIZE_T * Bytes |
| ) |
| { |
| gctUINT32_PTR logical = (gctUINT32_PTR) Logical; |
| gceSTATUS status; |
| |
| gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu", |
| Hardware, Logical, gcmOPT_VALUE(Bytes)); |
| |
| /* Verify the arguments. */ |
| gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); |
| gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); |
| |
| if (Logical != gcvNULL) |
| { |
| if (*Bytes < 8) |
| { |
| /* Command queue too small. */ |
| gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); |
| } |
| |
| /* Append NOP. */ |
| logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1))))))) << (0 ? |
| 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); |
| logical[1] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1))))))) << (0 ? |
| 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); |
| |
| gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: NOP", Logical); |
| } |
| |
| if (Bytes != gcvNULL) |
| { |
| /* Return number of bytes required by the NOP command. */ |
| *Bytes = 8; |
| } |
| |
| /* Success. */ |
| gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); |
| return gcvSTATUS_OK; |
| |
| OnError: |
| /* Return the status. */ |
| gcmkFOOTER(); |
| return status; |
| } |
| |
| |
| gceSTATUS |
| gckMCFE_Event( |
| IN gckHARDWARE Hardware, |
| IN gctPOINTER Logical, |
| IN gctUINT8 Event, |
| IN gceKERNEL_WHERE FromWhere, |
| IN OUT gctUINT32 * Bytes |
| ) |
| { |
| gctUINT size; |
| gctUINT32_PTR logical = (gctUINT32_PTR) Logical; |
| gceSTATUS status; |
| |
| gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Event=%u FromWhere=%d *Bytes=%lu", |
| Hardware, Logical, Event, FromWhere, gcmOPT_VALUE(Bytes)); |
| |
| /* Verify the arguments. */ |
| gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); |
| gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); |
| gcmkVERIFY_ARGUMENT(Event < 32); |
| |
| /* Ignored. */ |
| (void)FromWhere; |
| |
| size = 8; |
| |
| if (Logical != gcvNULL) |
| { |
| if (*Bytes < size) |
| { |
| /* Command queue too small. */ |
| gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); |
| } |
| |
| /* Append EVENT(Event). */ |
| logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1))))))) << (0 ? |
| 31:27))) | (((gctUINT32) (0x16 & ((gctUINT32) ((((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) |
| | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? |
| 25:16) - (0 ? |
| 25:16) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? |
| 25:16) - (0 ? |
| 25:16) + 1))))))) << (0 ? |
| 25:16))) | (((gctUINT32) (0x006 & ((gctUINT32) ((((1 ? |
| 25:16) - (0 ? |
| 25:16) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) |
| | Event; |
| |
| logical[1] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1))))))) << (0 ? |
| 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); |
| |
| #if gcmIS_DEBUG(gcdDEBUG_TRACE) |
| { |
| gctPHYS_ADDR_T phys; |
| gckOS_GetPhysicalAddress(Hardware->os, Logical, &phys); |
| gckOS_CPUPhysicalToGPUPhysical(Hardware->os, phys, &phys); |
| gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, |
| "0x%08x: EVENT %d", phys, Event); |
| } |
| #endif |
| |
| #if gcdINTERRUPT_STATISTIC |
| if (Event < gcmCOUNTOF(Hardware->kernel->eventObj->queues)) |
| { |
| gckOS_AtomSetMask(Hardware->pendingEvent, 1 << Event); |
| } |
| #endif |
| } |
| |
| if (Bytes != gcvNULL) |
| { |
| /* Return number of bytes required by the EVENT command. */ |
| *Bytes = size; |
| } |
| |
| /* Success. */ |
| gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); |
| return gcvSTATUS_OK; |
| |
| OnError: |
| /* Return the status. */ |
| gcmkFOOTER(); |
| return status; |
| } |
| |
| gceSTATUS |
| gckMCFE_SendSemaphore( |
| IN gckHARDWARE Hardware, |
| IN gctPOINTER Logical, |
| IN gctUINT32 SemaId, |
| IN OUT gctUINT32 * Bytes |
| ) |
| { |
| gctUINT32_PTR logical = (gctUINT32_PTR) Logical; |
| gceSTATUS status; |
| |
| gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x SemaId=%u *Bytes=%lu", |
| Hardware, Logical, SemaId, gcmOPT_VALUE(Bytes)); |
| |
| /* Verify the arguments. */ |
| gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); |
| gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); |
| gcmkVERIFY_ARGUMENT(SemaId < 0xFFFF); |
| |
| if (Logical != gcvNULL) |
| { |
| if (*Bytes < 8) |
| { |
| /* Command queue too small. */ |
| gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); |
| } |
| |
| /* Append SEND_SEMAPHORE(SemaId). */ |
| logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1))))))) << (0 ? |
| 31:27))) | (((gctUINT32) (0x16 & ((gctUINT32) ((((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) |
| | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? |
| 25:16) - (0 ? |
| 25:16) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? |
| 25:16) - (0 ? |
| 25:16) + 1))))))) << (0 ? |
| 25:16))) | (((gctUINT32) (0x002 & ((gctUINT32) ((((1 ? |
| 25:16) - (0 ? |
| 25:16) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) |
| | SemaId; |
| |
| logical[1] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1))))))) << (0 ? |
| 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); |
| } |
| |
| if (Bytes != gcvNULL) |
| { |
| *Bytes = 8; |
| } |
| |
| /* Success. */ |
| gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); |
| return gcvSTATUS_OK; |
| |
| OnError: |
| /* Return the status. */ |
| gcmkFOOTER(); |
| return status; |
| } |
| |
| gceSTATUS |
| gckMCFE_WaitSemaphore( |
| IN gckHARDWARE Hardware, |
| IN gctPOINTER Logical, |
| IN gctUINT32 SemaId, |
| IN OUT gctUINT32 * Bytes |
| ) |
| { |
| gctUINT32_PTR logical = (gctUINT32_PTR) Logical; |
| gceSTATUS status; |
| |
| gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x SemaId=%u *Bytes=%lu", |
| Hardware, Logical, SemaId, gcmOPT_VALUE(Bytes)); |
| |
| /* Verify the arguments. */ |
| gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); |
| gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); |
| gcmkVERIFY_ARGUMENT(SemaId < 0xFFFF); |
| |
| if (Logical != gcvNULL) |
| { |
| if (*Bytes < 8) |
| { |
| /* Command queue too small. */ |
| gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); |
| } |
| |
| /* Append WAIT_SEMAPHORE(SemaId). */ |
| logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1))))))) << (0 ? |
| 31:27))) | (((gctUINT32) (0x16 & ((gctUINT32) ((((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) |
| | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? |
| 25:16) - (0 ? |
| 25:16) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? |
| 25:16) - (0 ? |
| 25:16) + 1))))))) << (0 ? |
| 25:16))) | (((gctUINT32) (0x003 & ((gctUINT32) ((((1 ? |
| 25:16) - (0 ? |
| 25:16) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) |
| | SemaId; |
| |
| logical[1] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1))))))) << (0 ? |
| 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ? |
| 31:27) - (0 ? |
| 31:27) + 1) == 32) ? |
| ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); |
| } |
| |
| if (Bytes != gcvNULL) |
| { |
| *Bytes = 8; |
| } |
| |
| /* Success. */ |
| gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); |
| return gcvSTATUS_OK; |
| |
| OnError: |
| /* Return the status. */ |
| gcmkFOOTER(); |
| return status; |
| } |
| |
| gceSTATUS |
| gckMCFE_Execute( |
| IN gckHARDWARE Hardware, |
| IN gctBOOL Priority, |
| IN gctUINT32 ChannelId, |
| IN gctUINT32 Address, |
| IN gctUINT32 Bytes |
| ) |
| { |
| gctUINT32 regBase; |
| gcsMCFE_DESCRIPTOR *desc; |
| gcsMCFE_CHANNEL * channel = &Hardware->mcFE->channels[ChannelId]; |
| gcsMCFE_RING_BUF * ringBuf = Priority ? &channel->priRingBuf |
| : &channel->stdRingBuf; |
| |
| /* No priority channel in system channel by design. */ |
| gcmkASSERT(!(channel->binding == gcvMCFE_CHANNEL_SYSTEM && Priority == 1)); |
| |
| while (_NextPtr(ringBuf->writePtr) == ringBuf->readPtr) |
| { |
| gctUINT32 data; |
| regBase = Priority ? 0x02B00 |
| : 0x02700; |
| |
| gcmkVERIFY_OK(gckOS_ReadRegisterEx(Hardware->os, |
| Hardware->core, |
| regBase + ChannelId * 4, |
| &data)); |
| |
| ringBuf->readPtr = data; |
| |
| if (_NextPtr(ringBuf->writePtr) == ringBuf->readPtr) |
| { |
| gcmkPRINT("%s: MCFE channel %s-%d ringBuf is full!", |
| __FUNCTION__, |
| Priority ? "Pri" : "Std", |
| ChannelId); |
| |
| gckOS_Delay(Hardware->os, 100); |
| } |
| } |
| |
| regBase = Priority ? 0x02A00 |
| : 0x02600; |
| |
| /* ringBufLogical is in uint32, 2 uint32 contributes 1 descriptr. */ |
| desc = (gcsMCFE_DESCRIPTOR *)&ringBuf->ringBufLogical[ringBuf->writePtr * 2]; |
| desc->start = Address; |
| desc->end = Address + Bytes; |
| |
| gcmkDUMP(Hardware->os, |
| "#[descriptor %d: channel %s-%d]", |
| ringBuf->writePtr, |
| Priority ? "Pri" : "Std", |
| ChannelId); |
| |
| gcmkDUMP_BUFFER(Hardware->os, |
| gcvDUMP_BUFFER_KERNEL_COMMAND, |
| desc, |
| ringBuf->ringBufAddress + ringBuf->writePtr * 8, |
| 8); |
| |
| gcmkVERIFY_OK(gckVIDMEM_NODE_CleanCache(Hardware->kernel, |
| ringBuf->ringBufVideoMem, |
| 0, |
| desc, |
| 8)); |
| |
| ringBuf->writePtr = _NextPtr(ringBuf->writePtr); |
| |
| gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, |
| "0x%08X - 0x%08X: %06d bytes, Channel=%s-%d", |
| desc->start, desc->end, Bytes, |
| Priority ? "Pri" : "Std", ChannelId); |
| |
| gcmkVERIFY_OK(gckOS_WriteRegisterEx(Hardware->os, |
| Hardware->core, |
| regBase + ChannelId * 4, |
| ringBuf->writePtr)); |
| |
| return gcvSTATUS_OK; |
| } |
| |
| gceSTATUS |
| gckMCFE_HardwareIdle( |
| IN gckHARDWARE Hardware, |
| OUT gctBOOL_PTR isIdle |
| ) |
| { |
| gceSTATUS status; |
| gctUINT32 idle; |
| gctUINT32 regRBase; |
| gctUINT32 readPtr; |
| gctUINT32 ChannelId = 0; |
| gctBOOL Priority = gcvFALSE; |
| gcsMCFE_CHANNEL * channel = &Hardware->mcFE->channels[ChannelId]; |
| gcsMCFE_RING_BUF * ringBuf = Priority ? &channel->priRingBuf |
| : &channel->stdRingBuf; |
| |
| gcmkHEADER(); |
| |
| *isIdle = gcvTRUE; |
| |
| /* Read idle register. */ |
| gcmkONERROR( |
| gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00004, &idle)); |
| |
| /* Pipe must be idle. */ |
| if ((idle | (1 << 14)) != 0x7fffffff) |
| { |
| /* Something is busy. */ |
| *isIdle = gcvFALSE; |
| return status; |
| } |
| |
| regRBase = Priority ? 0x02B00 |
| : 0x02700; |
| |
| gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, |
| Hardware->core, |
| regRBase + ChannelId * 4, |
| &readPtr)); |
| |
| if (readPtr != ringBuf->writePtr) |
| { |
| *isIdle = gcvFALSE; |
| } |
| |
| gcmkFOOTER(); |
| |
| OnError: |
| return status; |
| } |
| |
| |