diff --git a/drivers/mxc/amd-gpu/kgsl_g12.c b/drivers/mxc/amd-gpu/kgsl_g12.c index 8659537b27d..a70707957e9 100644 --- a/drivers/mxc/amd-gpu/kgsl_g12.c +++ b/drivers/mxc/amd-gpu/kgsl_g12.c @@ -18,13 +18,13 @@ #include #include +#include #include "kgsl_types.h" #include "kgsl_hal.h" #include "kgsl_cmdstream.h" #include "kgsl_sharedmem.h" #include "kgsl_driver.h" -#include "kgsl_hwaccess.h" #include "kgsl_ioctl.h" #include "g12_reg.h" @@ -37,6 +37,9 @@ #define GSL_IRQ_TIMEOUT 200 +int kgsl_g12_regread(struct kgsl_device *device, unsigned int offsetwords, unsigned int *value); +int kgsl_g12_regwrite(struct kgsl_device *device, unsigned int offsetwords, unsigned int value); + //---------------------------------------------------------------------------- #define GSL_HAL_NUMCMDBUFFERS 5 @@ -181,7 +184,7 @@ kgsl_g12_isr(struct kgsl_device *device) #endif // DEBUG // determine if G12 is interrupting - device->ftbl.regread(device, (ADDR_VGC_IRQSTATUS >> 2), &status); + kgsl_g12_regread(device, (ADDR_VGC_IRQSTATUS >> 2), &status); if (status) { @@ -190,8 +193,8 @@ kgsl_g12_isr(struct kgsl_device *device) { #ifdef _DEBUG // obtain mh error information - device->ftbl.regread(device, ADDR_MH_MMU_PAGE_FAULT, (unsigned int *)&page_fault); - device->ftbl.regread(device, ADDR_MH_AXI_ERROR, (unsigned int *)&axi_error); + kgsl_g12_regread(device, ADDR_MH_MMU_PAGE_FAULT, (unsigned int *)&page_fault); + kgsl_g12_regread(device, ADDR_MH_AXI_ERROR, (unsigned int *)&axi_error); #endif // DEBUG kgsl_intr_decode(device, GSL_INTR_BLOCK_G12_MH); @@ -214,7 +217,7 @@ kgsl_g12_tlbinvalidate(struct kgsl_device *device, unsigned int reg_invalidate, // unreferenced formal parameter (void) pid; - device->ftbl.regwrite(device, reg_invalidate, *(unsigned int *) &mh_mmu_invalidate); + kgsl_g12_regwrite(device, reg_invalidate, *(unsigned int *) &mh_mmu_invalidate); #else (void)device; (void)reg_invalidate; @@ -231,7 +234,7 @@ kgsl_g12_setpagetable(struct kgsl_device *device, unsigned int reg_ptbase, uint3 (void) pid; #ifdef CONFIG_KGSL_MMU_ENABLE device->ftbl.idle(device, GSL_TIMEOUT_DEFAULT); - device->ftbl.regwrite(device, reg_ptbase, ptbase); + kgsl_g12_regwrite(device, reg_ptbase, ptbase); #else (void)device; (void)reg_ptbase; @@ -245,7 +248,7 @@ kgsl_g12_setpagetable(struct kgsl_device *device, unsigned int reg_ptbase, uint3 static void kgsl_g12_updatetimestamp(struct kgsl_device *device) { unsigned int count = 0; - device->ftbl.regread(device, (ADDR_VGC_IRQ_ACTIVE_CNT >> 2), &count); + kgsl_g12_regread(device, (ADDR_VGC_IRQ_ACTIVE_CNT >> 2), &count); count >>= 8; count &= 255; device->timestamp += count; @@ -287,7 +290,7 @@ kgsl_g12_init(struct kgsl_device *device) kgsl_hal_setpowerstate(device->id, GSL_PWRFLAGS_POWER_ON, 100); // setup MH arbiter - MH offsets are considered to be dword based, therefore no down shift - device->ftbl.regwrite(device, ADDR_MH_ARBITER_CONFIG, KGSL_G12_CFG_G12_MHARB); + kgsl_g12_regwrite(device, ADDR_MH_ARBITER_CONFIG, KGSL_G12_CFG_G12_MHARB); // init interrupt status = kgsl_intr_init(device); @@ -298,7 +301,7 @@ kgsl_g12_init(struct kgsl_device *device) } // enable irq - device->ftbl.regwrite(device, (ADDR_VGC_IRQENABLE >> 2), 0x3); + kgsl_g12_regwrite(device, (ADDR_VGC_IRQENABLE >> 2), 0x3); #ifdef CONFIG_KGSL_MMU_ENABLE // enable master interrupt for G12 MH @@ -536,54 +539,68 @@ kgsl_g12_idle(struct kgsl_device *device, unsigned int timeout) //---------------------------------------------------------------------------- -int -kgsl_g12_regread(struct kgsl_device *device, unsigned int offsetwords, unsigned int *value) +int kgsl_g12_regread(struct kgsl_device *device, unsigned int offsetwords, unsigned int *value) { - // G12 MH register values can only be retrieved via dedicated read registers - if ((offsetwords >= ADDR_MH_ARBITER_CONFIG && offsetwords <= ADDR_MH_AXI_HALT_CONTROL) || - (offsetwords >= ADDR_MH_MMU_CONFIG && offsetwords <= ADDR_MH_MMU_MPU_END)) - { + unsigned int *reg; + // G12 MH register values can only be retrieved via dedicated read registers + if ((offsetwords >= ADDR_MH_ARBITER_CONFIG && + offsetwords <= ADDR_MH_AXI_HALT_CONTROL) || + (offsetwords >= ADDR_MH_MMU_CONFIG && + offsetwords <= ADDR_MH_MMU_MPU_END)) { + kgsl_g12_regwrite(device, (ADDR_VGC_MH_READ_ADDR >> 2), offsetwords); #ifdef _Z180 - device->ftbl.regwrite(device, (ADDR_VGC_MH_READ_ADDR >> 2), offsetwords); - kgsl_hwaccess_regread(device->id, (unsigned int) device->regspace.mmio_virt_base, (ADDR_VGC_MH_READ_ADDR >> 2), value); + reg = (unsigned int *)(device->regspace.mmio_virt_base + + (ADDR_VGC_MH_READ_ADDR << 2)); #else - device->ftbl.regwrite(device, (ADDR_VGC_MH_READ_ADDR >> 2), offsetwords); - kgsl_hwaccess_regread(device->id, (unsigned int) device->regspace.mmio_virt_base, (ADDR_VGC_MH_DATA_ADDR >> 2), value); + reg = (unsigned int *)(device->regspace.mmio_virt_base + + (ADDR_VGC_MH_DATA_ADDR << 2)); #endif - } - else - { - kgsl_hwaccess_regread(device->id, (unsigned int) device->regspace.mmio_virt_base, offsetwords, value); - } + } else { + if (offsetwords * sizeof(unsigned int) >= device->regspace.sizebytes) { + pr_err("g12 read invalid offset %d\n", offsetwords); + return GSL_FAILURE;//-ERANGE + } - return (GSL_SUCCESS); + reg = (unsigned int *)(device->regspace.mmio_virt_base + + (offsetwords << 2)); + } + + *value = readl(reg); + return GSL_SUCCESS; } -//---------------------------------------------------------------------------- - -int -kgsl_g12_regwrite(struct kgsl_device *device, unsigned int offsetwords, unsigned int value) +int kgsl_g12_regwrite(struct kgsl_device *device, unsigned int offsetwords, unsigned int value) { - // G12 MH registers can only be written via the command window - if ((offsetwords >= ADDR_MH_ARBITER_CONFIG && offsetwords <= ADDR_MH_AXI_HALT_CONTROL) || - (offsetwords >= ADDR_MH_MMU_CONFIG && offsetwords <= ADDR_MH_MMU_MPU_END)) - { - kgsl_cmdwindow_write0(device->id, GSL_CMDWINDOW_MMU, offsetwords, value); - } - else - { - kgsl_hwaccess_regwrite(device->id, (unsigned int) device->regspace.mmio_virt_base, offsetwords, value); - } + unsigned int *reg; + // G12 MH registers can only be written via the command window + if ((offsetwords >= ADDR_MH_ARBITER_CONFIG && + offsetwords <= ADDR_MH_AXI_HALT_CONTROL) || + (offsetwords >= ADDR_MH_MMU_CONFIG && + offsetwords <= ADDR_MH_MMU_MPU_END)) { + kgsl_cmdwindow_write0(device->id, GSL_CMDWINDOW_MMU, offsetwords, value); + } else { + if (offsetwords * sizeof(unsigned int) >= device->regspace.sizebytes) { + pr_err("g12 write invalid offset %d\n", offsetwords); + return GSL_FAILURE;//-ERANGE + } - // idle device when running in safe mode - if (device->flags & GSL_FLAGS_SAFEMODE) - { - device->ftbl.idle(device, GSL_TIMEOUT_DEFAULT); - } + reg = (unsigned int *)(device->regspace.mmio_virt_base + + (offsetwords << 2)); + writel(value, reg); + /* Drain write buffer */ + dsb(); - return (GSL_SUCCESS); + /* Memory fence to ensure all data has posted. On some systems, + * like 7x27, the register block is not allocated as strongly + * ordered memory. Adding a memory fence ensures ordering + * during ringbuffer submits.*/ + mb(); + } + + return GSL_SUCCESS; } + //---------------------------------------------------------------------------- int @@ -619,7 +636,7 @@ kgsl_g12_waitirq(struct kgsl_device *device, gsl_intrid_t intr_id, unsigned int kgsl_device_active(device); INIT_COMPLETION(*comp); - device->ftbl.regread(device, (ADDR_VGC_IRQ_ACTIVE_CNT >> 2), &cntrs); + kgsl_g12_regread(device, (ADDR_VGC_IRQ_ACTIVE_CNT >> 2), &cntrs); for (i = 0; i < GSL_G12_INTR_COUNT; i++) { diff --git a/drivers/mxc/amd-gpu/kgsl_hwaccess.h b/drivers/mxc/amd-gpu/kgsl_hwaccess.h index b140582b457..3e23e23f91b 100644 --- a/drivers/mxc/amd-gpu/kgsl_hwaccess.h +++ b/drivers/mxc/amd-gpu/kgsl_hwaccess.h @@ -90,32 +90,4 @@ kgsl_hwaccess_memset(unsigned int gpubase, unsigned int gpuoffset, unsigned int } } -//---------------------------------------------------------------------------- - -static __inline void -kgsl_hwaccess_regread(unsigned int device_id, unsigned int gpubase, unsigned int offsetwords, unsigned int *data) -{ - unsigned int *reg; - - // unreferenced formal parameter - (void) device_id; - - reg = (unsigned int *)(gpubase + (offsetwords << 2)); - - *data = readl(reg); -} - -//---------------------------------------------------------------------------- - -static __inline void -kgsl_hwaccess_regwrite(unsigned int device_id, unsigned int gpubase, unsigned int offsetwords, unsigned int data) -{ - unsigned int *reg; - - // unreferenced formal parameter - (void) device_id; - - reg = (unsigned int *)(gpubase + (offsetwords << 2)); - writel(data, reg); -} #endif // __GSL_HWACCESS_WINCE_MX51_H diff --git a/drivers/mxc/amd-gpu/kgsl_yamato.c b/drivers/mxc/amd-gpu/kgsl_yamato.c index 91e9df50a84..a1d57ffaa20 100644 --- a/drivers/mxc/amd-gpu/kgsl_yamato.c +++ b/drivers/mxc/amd-gpu/kgsl_yamato.c @@ -18,6 +18,7 @@ #include #include +#include #include "kgsl_types.h" #include "kgsl_device.h" @@ -25,7 +26,6 @@ #include "kgsl_ringbuffer.h" // needed for rb config #include "kgsl_drawctxt.h" #include "kgsl_cmdstream.h" -#include "kgsl_hwaccess.h" #include "yamato_reg.h" #include "kgsl_pm4types.h" @@ -756,82 +756,78 @@ kgsl_yamato_setproperty(struct kgsl_device *device, gsl_property_type_t type, vo //---------------------------------------------------------------------------- -int -kgsl_yamato_idle(struct kgsl_device *device, unsigned int timeout) +int kgsl_yamato_regread(struct kgsl_device *device, unsigned int offsetwords, unsigned int *value) { - int status = GSL_FAILURE; - struct kgsl_ringbuffer *rb = &device->ringbuffer; - unsigned int rbbm_status; + unsigned int *reg; - (void) timeout; // unreferenced formal parameter + if (offsetwords * sizeof(unsigned int) >= device->regspace.sizebytes) { + return GSL_FAILURE; // -ERANGE, print some debug about invalid offset + } - KGSL_DEBUG(GSL_DBGFLAGS_DUMPX, KGSL_DEBUG_DUMPX(BB_DUMP_REGPOLL, device->id, REG_RBBM_STATUS, 0x80000000, "kgsl_yamato_idle")); + reg = (unsigned int *)(device->regspace.mmio_virt_base + (offsetwords << 2)); - // first, wait until the CP has consumed all the commands in the ring buffer - if (rb->flags & GSL_FLAGS_STARTED) - { - do - { - GSL_RB_GET_READPTR(rb, &rb->rptr); + *value = readl(reg); - } while (rb->rptr != rb->wptr); - } - - // now, wait for the GPU to finish its operations - for ( ; ; ) - { - device->ftbl.regread(device, REG_RBBM_STATUS, (unsigned int *)&rbbm_status); - - // qcom uses 0x110 - if (!(rbbm_status & 0x80000000)) - { - status = GSL_SUCCESS; - break; - } - - } - - return (status); + return GSL_SUCCESS; } -//---------------------------------------------------------------------------- - -int -kgsl_yamato_regread(struct kgsl_device *device, unsigned int offsetwords, unsigned int *value) +int kgsl_yamato_regwrite(struct kgsl_device *device, unsigned int offsetwords, unsigned int value) { - KGSL_DEBUG(GSL_DBGFLAGS_DUMPX, - { - if (!(gsl_driver.flags_debug & GSL_DBGFLAGS_DUMPX_WITHOUT_IFH)) - { - if(offsetwords == REG_CP_RB_RPTR || offsetwords == REG_CP_RB_WPTR) - { - *value = device->ringbuffer.wptr; - return (GSL_SUCCESS); - } - } - }); + unsigned int *reg; - kgsl_hwaccess_regread(device->id, (unsigned int) device->regspace.mmio_virt_base, offsetwords, value); + if (offsetwords * sizeof(unsigned int) >= device->regspace.sizebytes) { + return GSL_FAILURE; // -ERANGE, invalid offset + } - return (GSL_SUCCESS); + reg = (unsigned int *)(device->regspace.mmio_virt_base + (offsetwords << 2)); + + writel(value, reg); + + return (GSL_SUCCESS); } -//---------------------------------------------------------------------------- - -int -kgsl_yamato_regwrite(struct kgsl_device *device, unsigned int offsetwords, unsigned int value) +int kgsl_yamato_idle(struct kgsl_device *device, unsigned int timeout) { - KGSL_DEBUG(GSL_DBGFLAGS_PM4, KGSL_DEBUG_DUMPREGWRITE(offsetwords, value)); + int status = GSL_FAILURE; + struct kgsl_ringbuffer *rb = &device->ringbuffer; + unsigned int rbbm_status; + int idle_count = 0; +#define IDLE_COUNT_MAX 1500000 - kgsl_hwaccess_regwrite(device->id, (unsigned int) device->regspace.mmio_virt_base, offsetwords, value); + (void) timeout; - // idle device when running in safe mode - if (device->flags & GSL_FLAGS_SAFEMODE) - { - device->ftbl.idle(device, GSL_TIMEOUT_DEFAULT); - } + // first, wait until the CP has consumed all the commands in the ring buffer + if (rb->flags & GSL_FLAGS_STARTED) { + do { + idle_count++; + GSL_RB_GET_READPTR(rb, &rb->rptr); + } while ((rb->rptr != rb->wptr) && (idle_count < IDLE_COUNT_MAX)); - return (GSL_SUCCESS); + if (idle_count == IDLE_COUNT_MAX) { + pr_err("spun too long waiting for RB to idle\n"); + // -EINVAL, now do a ringbuffer dump, mmu dump + goto done; + } + } + + // now, wait for the GPU to finish its operations + for (idle_count = 0; idle_count < IDLE_COUNT_MAX; idle_count++) { + kgsl_yamato_regread(device, REG_RBBM_STATUS, &rbbm_status); + + //if (!(rbbm_status & 0x80000000)) { + if (rbbm_status == 0x110) { + status = GSL_SUCCESS; + break; + } + } + + if (idle_count == IDLE_COUNT_MAX) { + pr_err("spun too long waiting for rbbm status to idle\n"); + // -EINVAL, now do a ringbuffer dump, mmu dump + goto done; + } +done: + return status; } //---------------------------------------------------------------------------- @@ -869,45 +865,46 @@ kgsl_yamato_waitirq(struct kgsl_device *device, gsl_intrid_t intr_id, unsigned i return (status); } -int kgsl_yamato_check_timestamp(unsigned int device_id, unsigned int timestamp) +int kgsl_yamato_check_timestamp(struct kgsl_device *device, unsigned int timestamp) { int i; + /* Reason to use a wait loop: * When bus is busy, for example vpu is working too, the timestamp is - * possiblly not yet refreshed to memory by yamato. For most cases, it + * possibly not yet refreshed to memory by yamato. For most cases, it * will hit on first loop cycle. So it don't effect performance. */ for (i = 0; i < 10; i++) { - if (kgsl_cmdstream_check_timestamp(device_id, timestamp)) + if (kgsl_cmdstream_check_timestamp(device->id, timestamp)) return 1; udelay(10); } + return 0; } -int -kgsl_yamato_waittimestamp(struct kgsl_device *device, unsigned int timestamp, unsigned int timeout) +int kgsl_yamato_waittimestamp(struct kgsl_device *device, unsigned int timestamp, unsigned int msecs) { -#if defined GSL_RB_TIMESTAMP_INTERUPT - int status = wait_event_interruptible_timeout(device->timestamp_waitq, - kgsl_yamato_check_timestamp(device->id, timestamp), - msecs_to_jiffies(timeout)); - if (status > 0) - return GSL_SUCCESS; - else - return GSL_FAILURE; -#else - return (GSL_SUCCESS); -#endif + int status = GSL_SUCCESS; + long timeout; + + timeout = wait_event_interruptible_timeout(device->timestamp_waitq, + kgsl_yamato_check_timestamp(device, timestamp), + msecs_to_jiffies(msecs)); + if (timeout > 0) + status = GSL_SUCCESS; // 0 + else if (timeout == 0) { + // check timestamp? + status = GSL_FAILURE; // -ETIMEDOUT + // register dump? + } + return status; } -//---------------------------------------------------------------------------- -int -kgsl_yamato_runpending(struct kgsl_device *device) +int kgsl_yamato_runpending(struct kgsl_device *device) { - (void) device; - - return (GSL_SUCCESS); + (void) device; + return GSL_SUCCESS; } //----------------------------------------------------------------------------