diff options
Diffstat (limited to 'drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_mc_fe.c')
-rw-r--r-- | drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_mc_fe.c | 914 |
1 files changed, 914 insertions, 0 deletions
diff --git a/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_mc_fe.c b/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_mc_fe.c new file mode 100644 index 000000000000..7762d2b46f6a --- /dev/null +++ b/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware_mc_fe.c @@ -0,0 +1,914 @@ +/**************************************************************************** +* +* 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=%p Logical=%p *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, "%p: 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=%p Logical=%p 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%08llx: 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=%p Logical=%p 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=%p Logical=%p 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 + ) +{ + gceSTATUS status; + gctUINT32 regBase; + gcsMCFE_DESCRIPTOR *desc; + gckMCFE mcFE = Hardware->mcFE; + gcsMCFE_CHANNEL * channel = gcvNULL; + gcsMCFE_RING_BUF * ringBuf = gcvNULL; + + gcmkHEADER_ARG("Hardware=%p Priority=0x%x ChannelId=%u Address=%x Bytes=%u", + Hardware, Priority, ChannelId, Address, Bytes); + + /* ChannelId should be valid. */ + gcmkASSERT(mcFE && ChannelId < mcFE->channelCount); + + channel = &mcFE->channels[ChannelId]; + + /* No priority channel in system channel by design. */ + gcmkASSERT(!(channel->binding == gcvMCFE_CHANNEL_SYSTEM && Priority == 1)); + + ringBuf = Priority ? &channel->priRingBuf : &channel->stdRingBuf; + + 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); + + gcmkONERROR(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); + + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + regBase + ChannelId * 4, + ringBuf->writePtr)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; + +} + +gceSTATUS +gckMCFE_HardwareIdle( + IN gckHARDWARE Hardware, + OUT gctBOOL_PTR isIdle + ) +{ + gceSTATUS status; + gctUINT32 idle; + gctUINT32 regRBase; + gctUINT32 readPtr; + gctUINT32 ChannelId = 0; + gctBOOL Priority = gcvFALSE; + gckMCFE mcFE = Hardware->mcFE; + gcsMCFE_CHANNEL * channel = gcvNULL; + gcsMCFE_RING_BUF * ringBuf = gcvNULL; + + gcmkHEADER(); + + /* ChannelId should be valid. */ + gcmkASSERT(mcFE && ChannelId < mcFE->channelCount); + + channel = &mcFE->channels[ChannelId]; + ringBuf = Priority ? &channel->priRingBuf : &channel->stdRingBuf; + + *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; +} + + |