On Fri, Sep 11, 2015 at 10:10 AM, Lucas Stach <l.stach at pengutronix.de> wrote: > From: Christian Gmeiner <christian.gmeiner at gmail.com> > > This is a squashed commit of the complete etnaviv DRM driver in order > to make it easy for people to review the code by seeing the driver as a > whole and is not intended for merging in this form. > > If you are interested in the history of individual commits: > git://git.pengutronix.de/git/lst/linux.git etnaviv-for-upstream > > Signed-off-by: Christian Gmeiner <christian.gmeiner at gmail.com> > Signed-off-by: Russell King <rmk+kernel at arm.linux.org.uk> > Signed-off-by: Lucas Stach <l.stach at pengutronix.de> > --- > drivers/staging/Kconfig | 2 + > drivers/staging/Makefile | 1 + > drivers/staging/etnaviv/Kconfig | 20 + > drivers/staging/etnaviv/Makefile | 18 + > drivers/staging/etnaviv/cmdstream.xml.h | 218 ++++ > drivers/staging/etnaviv/common.xml.h | 249 +++++ > drivers/staging/etnaviv/etnaviv_buffer.c | 271 +++++ > drivers/staging/etnaviv/etnaviv_cmd_parser.c | 119 +++ > drivers/staging/etnaviv/etnaviv_drv.c | 705 +++++++++++++ > drivers/staging/etnaviv/etnaviv_drv.h | 138 +++ > drivers/staging/etnaviv/etnaviv_gem.c | 887 ++++++++++++++++ > drivers/staging/etnaviv/etnaviv_gem.h | 141 +++ > drivers/staging/etnaviv/etnaviv_gem_prime.c | 121 +++ > drivers/staging/etnaviv/etnaviv_gem_submit.c | 421 ++++++++ > drivers/staging/etnaviv/etnaviv_gpu.c | 1468 > ++++++++++++++++++++++++++ > drivers/staging/etnaviv/etnaviv_gpu.h | 198 ++++ > drivers/staging/etnaviv/etnaviv_iommu.c | 221 ++++ > drivers/staging/etnaviv/etnaviv_iommu.h | 28 + > drivers/staging/etnaviv/etnaviv_iommu_v2.c | 33 + > drivers/staging/etnaviv/etnaviv_iommu_v2.h | 25 + > drivers/staging/etnaviv/etnaviv_mmu.c | 282 +++++ > drivers/staging/etnaviv/etnaviv_mmu.h | 58 + > drivers/staging/etnaviv/state.xml.h | 351 ++++++ > drivers/staging/etnaviv/state_hi.xml.h | 407 +++++++ > include/uapi/drm/etnaviv_drm.h | 215 ++++ > 25 files changed, 6597 insertions(+) > create mode 100644 drivers/staging/etnaviv/Kconfig > create mode 100644 drivers/staging/etnaviv/Makefile > create mode 100644 drivers/staging/etnaviv/cmdstream.xml.h > create mode 100644 drivers/staging/etnaviv/common.xml.h > create mode 100644 drivers/staging/etnaviv/etnaviv_buffer.c > create mode 100644 drivers/staging/etnaviv/etnaviv_cmd_parser.c > create mode 100644 drivers/staging/etnaviv/etnaviv_drv.c > create mode 100644 drivers/staging/etnaviv/etnaviv_drv.h > create mode 100644 drivers/staging/etnaviv/etnaviv_gem.c > create mode 100644 drivers/staging/etnaviv/etnaviv_gem.h > create mode 100644 drivers/staging/etnaviv/etnaviv_gem_prime.c > create mode 100644 drivers/staging/etnaviv/etnaviv_gem_submit.c > create mode 100644 drivers/staging/etnaviv/etnaviv_gpu.c > create mode 100644 drivers/staging/etnaviv/etnaviv_gpu.h > create mode 100644 drivers/staging/etnaviv/etnaviv_iommu.c > create mode 100644 drivers/staging/etnaviv/etnaviv_iommu.h > create mode 100644 drivers/staging/etnaviv/etnaviv_iommu_v2.c > create mode 100644 drivers/staging/etnaviv/etnaviv_iommu_v2.h > create mode 100644 drivers/staging/etnaviv/etnaviv_mmu.c > create mode 100644 drivers/staging/etnaviv/etnaviv_mmu.h > create mode 100644 drivers/staging/etnaviv/state.xml.h > create mode 100644 drivers/staging/etnaviv/state_hi.xml.h > create mode 100644 include/uapi/drm/etnaviv_drm.h > > diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig > index 7f6cae5beb90..5446fe4859ce 100644 > --- a/drivers/staging/Kconfig > +++ b/drivers/staging/Kconfig > @@ -112,4 +112,6 @@ source "drivers/staging/fsl-mc/Kconfig" > > source "drivers/staging/wilc1000/Kconfig" > > +source "drivers/staging/etnaviv/Kconfig" > + > endif # STAGING > diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile > index 347f6477aa3e..9fd3c06b6bfd 100644 > --- a/drivers/staging/Makefile > +++ b/drivers/staging/Makefile > @@ -48,3 +48,4 @@ obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/ > obj-$(CONFIG_FB_TFT) += fbtft/ > obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/ > obj-$(CONFIG_WILC1000) += wilc1000/ > +obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/ > diff --git a/drivers/staging/etnaviv/Kconfig b/drivers/staging/etnaviv/Kconfig > new file mode 100644 > index 000000000000..6f034eda914c > --- /dev/null > +++ b/drivers/staging/etnaviv/Kconfig > @@ -0,0 +1,20 @@ > + > +config DRM_ETNAVIV > + tristate "etnaviv DRM" > + depends on DRM > + select SHMEM > + select TMPFS > + select IOMMU_API > + select IOMMU_SUPPORT > + default y > + help > + DRM driver for Vivante GPUs. > + > +config DRM_ETNAVIV_REGISTER_LOGGING > + bool "etnaviv DRM register logging" > + depends on DRM_ETNAVIV > + default n > + help > + Compile in support for logging register reads/writes in a format > + that can be parsed by envytools demsm tool. If enabled, register > + logging can be switched on via etnaviv.reglog=y module param.
heh, ok, didn't realize anyone else was using demsm.. I guess that is one of the things that I should clean up and get into upstream envytools tree. (And maybe come up with a better name.. if anyone has any suggestions..) BR, -R > diff --git a/drivers/staging/etnaviv/Makefile > b/drivers/staging/etnaviv/Makefile > new file mode 100644 > index 000000000000..2b71c31b6501 > --- /dev/null > +++ b/drivers/staging/etnaviv/Makefile > @@ -0,0 +1,18 @@ > +ccflags-y := -Iinclude/drm -Idrivers/staging/vivante > +ifeq (, $(findstring -W,$(EXTRA_CFLAGS))) > + ccflags-y += -Werror > +endif > + > +etnaviv-y := \ > + etnaviv_cmd_parser.o \ > + etnaviv_drv.o \ > + etnaviv_gem.o \ > + etnaviv_gem_prime.o \ > + etnaviv_gem_submit.o \ > + etnaviv_gpu.o \ > + etnaviv_iommu.o \ > + etnaviv_iommu_v2.o \ > + etnaviv_mmu.o \ > + etnaviv_buffer.o > + > +obj-$(CONFIG_DRM_ETNAVIV) += etnaviv.o > diff --git a/drivers/staging/etnaviv/cmdstream.xml.h > b/drivers/staging/etnaviv/cmdstream.xml.h > new file mode 100644 > index 000000000000..8c44ba9a694e > --- /dev/null > +++ b/drivers/staging/etnaviv/cmdstream.xml.h > @@ -0,0 +1,218 @@ > +#ifndef CMDSTREAM_XML > +#define CMDSTREAM_XML > + > +/* Autogenerated file, DO NOT EDIT manually! > + > +This file was generated by the rules-ng-ng headergen tool in this git > repository: > +http://0x04.net/cgit/index.cgi/rules-ng-ng > +git clone git://0x04.net/rules-ng-ng > + > +The rules-ng-ng source files this header was generated from are: > +- cmdstream.xml ( 12589 bytes, from 2014-02-17 14:57:56) > +- common.xml ( 18437 bytes, from 2015-03-25 11:27:41) > + > +Copyright (C) 2014 > +*/ > + > + > +#define FE_OPCODE_LOAD_STATE 0x00000001 > +#define FE_OPCODE_END 0x00000002 > +#define FE_OPCODE_NOP 0x00000003 > +#define FE_OPCODE_DRAW_2D 0x00000004 > +#define FE_OPCODE_DRAW_PRIMITIVES 0x00000005 > +#define FE_OPCODE_DRAW_INDEXED_PRIMITIVES 0x00000006 > +#define FE_OPCODE_WAIT 0x00000007 > +#define FE_OPCODE_LINK 0x00000008 > +#define FE_OPCODE_STALL > 0x00000009 > +#define FE_OPCODE_CALL 0x0000000a > +#define FE_OPCODE_RETURN 0x0000000b > +#define FE_OPCODE_CHIP_SELECT 0x0000000d > +#define PRIMITIVE_TYPE_POINTS 0x00000001 > +#define PRIMITIVE_TYPE_LINES 0x00000002 > +#define PRIMITIVE_TYPE_LINE_STRIP 0x00000003 > +#define PRIMITIVE_TYPE_TRIANGLES 0x00000004 > +#define PRIMITIVE_TYPE_TRIANGLE_STRIP 0x00000005 > +#define PRIMITIVE_TYPE_TRIANGLE_FAN 0x00000006 > +#define PRIMITIVE_TYPE_LINE_LOOP 0x00000007 > +#define PRIMITIVE_TYPE_QUADS 0x00000008 > +#define VIV_FE_LOAD_STATE 0x00000000 > + > +#define VIV_FE_LOAD_STATE_HEADER 0x00000000 > +#define VIV_FE_LOAD_STATE_HEADER_OP__MASK 0xf8000000 > +#define VIV_FE_LOAD_STATE_HEADER_OP__SHIFT 27 > +#define VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE 0x08000000 > +#define VIV_FE_LOAD_STATE_HEADER_FIXP 0x04000000 > +#define VIV_FE_LOAD_STATE_HEADER_COUNT__MASK 0x03ff0000 > +#define VIV_FE_LOAD_STATE_HEADER_COUNT__SHIFT 16 > +#define VIV_FE_LOAD_STATE_HEADER_COUNT(x) (((x) << > VIV_FE_LOAD_STATE_HEADER_COUNT__SHIFT) & VIV_FE_LOAD_STATE_HEADER_COUNT__MASK) > +#define VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK 0x0000ffff > +#define VIV_FE_LOAD_STATE_HEADER_OFFSET__SHIFT 0 > +#define VIV_FE_LOAD_STATE_HEADER_OFFSET(x) (((x) << > VIV_FE_LOAD_STATE_HEADER_OFFSET__SHIFT) & > VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK) > +#define VIV_FE_LOAD_STATE_HEADER_OFFSET__SHR 2 > + > +#define VIV_FE_END 0x00000000 > + > +#define VIV_FE_END_HEADER 0x00000000 > +#define VIV_FE_END_HEADER_EVENT_ID__MASK 0x0000001f > +#define VIV_FE_END_HEADER_EVENT_ID__SHIFT 0 > +#define VIV_FE_END_HEADER_EVENT_ID(x) (((x) << > VIV_FE_END_HEADER_EVENT_ID__SHIFT) & VIV_FE_END_HEADER_EVENT_ID__MASK) > +#define VIV_FE_END_HEADER_EVENT_ENABLE 0x00000100 > +#define VIV_FE_END_HEADER_OP__MASK 0xf8000000 > +#define VIV_FE_END_HEADER_OP__SHIFT 27 > +#define VIV_FE_END_HEADER_OP_END 0x10000000 > + > +#define VIV_FE_NOP 0x00000000 > + > +#define VIV_FE_NOP_HEADER 0x00000000 > +#define VIV_FE_NOP_HEADER_OP__MASK 0xf8000000 > +#define VIV_FE_NOP_HEADER_OP__SHIFT 27 > +#define VIV_FE_NOP_HEADER_OP_NOP 0x18000000 > + > +#define VIV_FE_DRAW_2D 0x00000000 > + > +#define VIV_FE_DRAW_2D_HEADER 0x00000000 > +#define VIV_FE_DRAW_2D_HEADER_COUNT__MASK 0x0000ff00 > +#define VIV_FE_DRAW_2D_HEADER_COUNT__SHIFT 8 > +#define VIV_FE_DRAW_2D_HEADER_COUNT(x) (((x) << > VIV_FE_DRAW_2D_HEADER_COUNT__SHIFT) & VIV_FE_DRAW_2D_HEADER_COUNT__MASK) > +#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT__MASK 0x07ff0000 > +#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT__SHIFT 16 > +#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT(x) (((x) << > VIV_FE_DRAW_2D_HEADER_DATA_COUNT__SHIFT) & > VIV_FE_DRAW_2D_HEADER_DATA_COUNT__MASK) > +#define VIV_FE_DRAW_2D_HEADER_OP__MASK 0xf8000000 > +#define VIV_FE_DRAW_2D_HEADER_OP__SHIFT 27 > +#define VIV_FE_DRAW_2D_HEADER_OP_DRAW_2D 0x20000000 > + > +#define VIV_FE_DRAW_2D_TOP_LEFT > 0x00000008 > +#define VIV_FE_DRAW_2D_TOP_LEFT_X__MASK > 0x0000ffff > +#define VIV_FE_DRAW_2D_TOP_LEFT_X__SHIFT 0 > +#define VIV_FE_DRAW_2D_TOP_LEFT_X(x) (((x) << > VIV_FE_DRAW_2D_TOP_LEFT_X__SHIFT) & VIV_FE_DRAW_2D_TOP_LEFT_X__MASK) > +#define VIV_FE_DRAW_2D_TOP_LEFT_Y__MASK > 0xffff0000 > +#define VIV_FE_DRAW_2D_TOP_LEFT_Y__SHIFT 16 > +#define VIV_FE_DRAW_2D_TOP_LEFT_Y(x) (((x) << > VIV_FE_DRAW_2D_TOP_LEFT_Y__SHIFT) & VIV_FE_DRAW_2D_TOP_LEFT_Y__MASK) > + > +#define VIV_FE_DRAW_2D_BOTTOM_RIGHT 0x0000000c > +#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__MASK 0x0000ffff > +#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__SHIFT 0 > +#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X(x) (((x) << > VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__SHIFT) & VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__MASK) > +#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__MASK 0xffff0000 > +#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__SHIFT 16 > +#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y(x) (((x) << > VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__SHIFT) & VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__MASK) > + > +#define VIV_FE_DRAW_PRIMITIVES 0x00000000 > + > +#define VIV_FE_DRAW_PRIMITIVES_HEADER 0x00000000 > +#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP__MASK 0xf8000000 > +#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP__SHIFT 27 > +#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP_DRAW_PRIMITIVES 0x28000000 > + > +#define VIV_FE_DRAW_PRIMITIVES_COMMAND 0x00000004 > +#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__MASK 0x000000ff > +#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__SHIFT 0 > +#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE(x) (((x) << > VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__SHIFT) & > VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__MASK) > + > +#define VIV_FE_DRAW_PRIMITIVES_START 0x00000008 > + > +#define VIV_FE_DRAW_PRIMITIVES_COUNT 0x0000000c > + > +#define VIV_FE_DRAW_INDEXED_PRIMITIVES 0x00000000 > + > +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER 0x00000000 > +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP__MASK 0xf8000000 > +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP__SHIFT 27 > +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP_DRAW_INDEXED_PRIMITIVES > 0x30000000 > + > +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND 0x00000004 > +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__MASK 0x000000ff > +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__SHIFT 0 > +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE(x) (((x) << > VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__SHIFT) & > VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__MASK) > + > +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_START 0x00000008 > + > +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COUNT 0x0000000c > + > +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_OFFSET 0x00000010 > + > +#define VIV_FE_WAIT 0x00000000 > + > +#define VIV_FE_WAIT_HEADER 0x00000000 > +#define VIV_FE_WAIT_HEADER_DELAY__MASK 0x0000ffff > +#define VIV_FE_WAIT_HEADER_DELAY__SHIFT 0 > +#define VIV_FE_WAIT_HEADER_DELAY(x) (((x) << > VIV_FE_WAIT_HEADER_DELAY__SHIFT) & VIV_FE_WAIT_HEADER_DELAY__MASK) > +#define VIV_FE_WAIT_HEADER_OP__MASK 0xf8000000 > +#define VIV_FE_WAIT_HEADER_OP__SHIFT 27 > +#define VIV_FE_WAIT_HEADER_OP_WAIT 0x38000000 > + > +#define VIV_FE_LINK 0x00000000 > + > +#define VIV_FE_LINK_HEADER 0x00000000 > +#define VIV_FE_LINK_HEADER_PREFETCH__MASK 0x0000ffff > +#define VIV_FE_LINK_HEADER_PREFETCH__SHIFT 0 > +#define VIV_FE_LINK_HEADER_PREFETCH(x) (((x) << > VIV_FE_LINK_HEADER_PREFETCH__SHIFT) & VIV_FE_LINK_HEADER_PREFETCH__MASK) > +#define VIV_FE_LINK_HEADER_OP__MASK 0xf8000000 > +#define VIV_FE_LINK_HEADER_OP__SHIFT 27 > +#define VIV_FE_LINK_HEADER_OP_LINK 0x40000000 > + > +#define VIV_FE_LINK_ADDRESS 0x00000004 > + > +#define VIV_FE_STALL 0x00000000 > + > +#define VIV_FE_STALL_HEADER 0x00000000 > +#define VIV_FE_STALL_HEADER_OP__MASK 0xf8000000 > +#define VIV_FE_STALL_HEADER_OP__SHIFT 27 > +#define VIV_FE_STALL_HEADER_OP_STALL 0x48000000 > + > +#define VIV_FE_STALL_TOKEN 0x00000004 > +#define VIV_FE_STALL_TOKEN_FROM__MASK 0x0000001f > +#define VIV_FE_STALL_TOKEN_FROM__SHIFT 0 > +#define VIV_FE_STALL_TOKEN_FROM(x) (((x) << > VIV_FE_STALL_TOKEN_FROM__SHIFT) & VIV_FE_STALL_TOKEN_FROM__MASK) > +#define VIV_FE_STALL_TOKEN_TO__MASK 0x00001f00 > +#define VIV_FE_STALL_TOKEN_TO__SHIFT 8 > +#define VIV_FE_STALL_TOKEN_TO(x) (((x) << > VIV_FE_STALL_TOKEN_TO__SHIFT) & VIV_FE_STALL_TOKEN_TO__MASK) > + > +#define VIV_FE_CALL 0x00000000 > + > +#define VIV_FE_CALL_HEADER 0x00000000 > +#define VIV_FE_CALL_HEADER_PREFETCH__MASK 0x0000ffff > +#define VIV_FE_CALL_HEADER_PREFETCH__SHIFT 0 > +#define VIV_FE_CALL_HEADER_PREFETCH(x) (((x) << > VIV_FE_CALL_HEADER_PREFETCH__SHIFT) & VIV_FE_CALL_HEADER_PREFETCH__MASK) > +#define VIV_FE_CALL_HEADER_OP__MASK 0xf8000000 > +#define VIV_FE_CALL_HEADER_OP__SHIFT 27 > +#define VIV_FE_CALL_HEADER_OP_CALL 0x50000000 > + > +#define VIV_FE_CALL_ADDRESS 0x00000004 > + > +#define VIV_FE_CALL_RETURN_PREFETCH 0x00000008 > + > +#define VIV_FE_CALL_RETURN_ADDRESS 0x0000000c > + > +#define VIV_FE_RETURN 0x00000000 > + > +#define VIV_FE_RETURN_HEADER 0x00000000 > +#define VIV_FE_RETURN_HEADER_OP__MASK 0xf8000000 > +#define VIV_FE_RETURN_HEADER_OP__SHIFT 27 > +#define VIV_FE_RETURN_HEADER_OP_RETURN 0x58000000 > + > +#define VIV_FE_CHIP_SELECT 0x00000000 > + > +#define VIV_FE_CHIP_SELECT_HEADER 0x00000000 > +#define VIV_FE_CHIP_SELECT_HEADER_OP__MASK 0xf8000000 > +#define VIV_FE_CHIP_SELECT_HEADER_OP__SHIFT 27 > +#define VIV_FE_CHIP_SELECT_HEADER_OP_CHIP_SELECT 0x68000000 > +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP15 > 0x00008000 > +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP14 > 0x00004000 > +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP13 > 0x00002000 > +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP12 > 0x00001000 > +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP11 > 0x00000800 > +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP10 > 0x00000400 > +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP9 0x00000200 > +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP8 0x00000100 > +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP7 0x00000080 > +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP6 0x00000040 > +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP5 0x00000020 > +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP4 0x00000010 > +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP3 0x00000008 > +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP2 0x00000004 > +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP1 0x00000002 > +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP0 0x00000001 > + > + > +#endif /* CMDSTREAM_XML */ > diff --git a/drivers/staging/etnaviv/common.xml.h > b/drivers/staging/etnaviv/common.xml.h > new file mode 100644 > index 000000000000..9e585d51fb78 > --- /dev/null > +++ b/drivers/staging/etnaviv/common.xml.h > @@ -0,0 +1,249 @@ > +#ifndef COMMON_XML > +#define COMMON_XML > + > +/* Autogenerated file, DO NOT EDIT manually! > + > +This file was generated by the rules-ng-ng headergen tool in this git > repository: > +http://0x04.net/cgit/index.cgi/rules-ng-ng > +git clone git://0x04.net/rules-ng-ng > + > +The rules-ng-ng source files this header was generated from are: > +- state_vg.xml ( 5973 bytes, from 2015-03-25 11:26:01) > +- common.xml ( 18437 bytes, from 2015-03-25 11:27:41) > + > +Copyright (C) 2015 > +*/ > + > + > +#define PIPE_ID_PIPE_3D > 0x00000000 > +#define PIPE_ID_PIPE_2D > 0x00000001 > +#define SYNC_RECIPIENT_FE 0x00000001 > +#define SYNC_RECIPIENT_RA 0x00000005 > +#define SYNC_RECIPIENT_PE 0x00000007 > +#define SYNC_RECIPIENT_DE 0x0000000b > +#define SYNC_RECIPIENT_VG 0x0000000f > +#define SYNC_RECIPIENT_TESSELATOR 0x00000010 > +#define SYNC_RECIPIENT_VG2 0x00000011 > +#define SYNC_RECIPIENT_TESSELATOR2 0x00000012 > +#define SYNC_RECIPIENT_VG3 0x00000013 > +#define SYNC_RECIPIENT_TESSELATOR3 0x00000014 > +#define ENDIAN_MODE_NO_SWAP 0x00000000 > +#define ENDIAN_MODE_SWAP_16 0x00000001 > +#define ENDIAN_MODE_SWAP_32 0x00000002 > +#define chipModel_GC300 > 0x00000300 > +#define chipModel_GC320 > 0x00000320 > +#define chipModel_GC350 > 0x00000350 > +#define chipModel_GC355 > 0x00000355 > +#define chipModel_GC400 > 0x00000400 > +#define chipModel_GC410 > 0x00000410 > +#define chipModel_GC420 > 0x00000420 > +#define chipModel_GC450 > 0x00000450 > +#define chipModel_GC500 > 0x00000500 > +#define chipModel_GC530 > 0x00000530 > +#define chipModel_GC600 > 0x00000600 > +#define chipModel_GC700 > 0x00000700 > +#define chipModel_GC800 > 0x00000800 > +#define chipModel_GC860 > 0x00000860 > +#define chipModel_GC880 > 0x00000880 > +#define chipModel_GC1000 0x00001000 > +#define chipModel_GC2000 0x00002000 > +#define chipModel_GC2100 0x00002100 > +#define chipModel_GC4000 0x00004000 > +#define RGBA_BITS_R 0x00000001 > +#define RGBA_BITS_G 0x00000002 > +#define RGBA_BITS_B 0x00000004 > +#define RGBA_BITS_A 0x00000008 > +#define chipFeatures_FAST_CLEAR > 0x00000001 > +#define chipFeatures_SPECIAL_ANTI_ALIASING 0x00000002 > +#define chipFeatures_PIPE_3D 0x00000004 > +#define chipFeatures_DXT_TEXTURE_COMPRESSION 0x00000008 > +#define chipFeatures_DEBUG_MODE > 0x00000010 > +#define chipFeatures_Z_COMPRESSION 0x00000020 > +#define chipFeatures_YUV420_SCALER 0x00000040 > +#define chipFeatures_MSAA 0x00000080 > +#define chipFeatures_DC > 0x00000100 > +#define chipFeatures_PIPE_2D 0x00000200 > +#define chipFeatures_ETC1_TEXTURE_COMPRESSION 0x00000400 > +#define chipFeatures_FAST_SCALER 0x00000800 > +#define chipFeatures_HIGH_DYNAMIC_RANGE > 0x00001000 > +#define chipFeatures_YUV420_TILER 0x00002000 > +#define chipFeatures_MODULE_CG 0x00004000 > +#define chipFeatures_MIN_AREA 0x00008000 > +#define chipFeatures_NO_EARLY_Z > 0x00010000 > +#define chipFeatures_NO_422_TEXTURE 0x00020000 > +#define chipFeatures_BUFFER_INTERLEAVING 0x00040000 > +#define chipFeatures_BYTE_WRITE_2D 0x00080000 > +#define chipFeatures_NO_SCALER 0x00100000 > +#define chipFeatures_YUY2_AVERAGING 0x00200000 > +#define chipFeatures_HALF_PE_CACHE 0x00400000 > +#define chipFeatures_HALF_TX_CACHE 0x00800000 > +#define chipFeatures_YUY2_RENDER_TARGET > 0x01000000 > +#define chipFeatures_MEM32 0x02000000 > +#define chipFeatures_PIPE_VG 0x04000000 > +#define chipFeatures_VGTS 0x08000000 > +#define chipFeatures_FE20 0x10000000 > +#define chipFeatures_BYTE_WRITE_3D 0x20000000 > +#define chipFeatures_RS_YUV_TARGET 0x40000000 > +#define chipFeatures_32_BIT_INDICES 0x80000000 > +#define chipMinorFeatures0_FLIP_Y 0x00000001 > +#define chipMinorFeatures0_DUAL_RETURN_BUS 0x00000002 > +#define chipMinorFeatures0_ENDIANNESS_CONFIG 0x00000004 > +#define chipMinorFeatures0_TEXTURE_8K 0x00000008 > +#define chipMinorFeatures0_CORRECT_TEXTURE_CONVERTER 0x00000010 > +#define chipMinorFeatures0_SPECIAL_MSAA_LOD 0x00000020 > +#define chipMinorFeatures0_FAST_CLEAR_FLUSH 0x00000040 > +#define chipMinorFeatures0_2DPE20 0x00000080 > +#define chipMinorFeatures0_CORRECT_AUTO_DISABLE > 0x00000100 > +#define chipMinorFeatures0_RENDERTARGET_8K 0x00000200 > +#define chipMinorFeatures0_2BITPERTILE 0x00000400 > +#define chipMinorFeatures0_SEPARATE_TILE_STATUS_WHEN_INTERLEAVED > 0x00000800 > +#define chipMinorFeatures0_SUPER_TILED 0x00001000 > +#define chipMinorFeatures0_VG_20 0x00002000 > +#define chipMinorFeatures0_TS_EXTENDED_COMMANDS > 0x00004000 > +#define chipMinorFeatures0_COMPRESSION_FIFO_FIXED 0x00008000 > +#define chipMinorFeatures0_HAS_SIGN_FLOOR_CEIL 0x00010000 > +#define chipMinorFeatures0_VG_FILTER 0x00020000 > +#define chipMinorFeatures0_VG_21 0x00040000 > +#define chipMinorFeatures0_SHADER_HAS_W > 0x00080000 > +#define chipMinorFeatures0_HAS_SQRT_TRIG 0x00100000 > +#define chipMinorFeatures0_MORE_MINOR_FEATURES 0x00200000 > +#define chipMinorFeatures0_MC20 > 0x00400000 > +#define chipMinorFeatures0_MSAA_SIDEBAND 0x00800000 > +#define chipMinorFeatures0_BUG_FIXES0 0x01000000 > +#define chipMinorFeatures0_VAA 0x02000000 > +#define chipMinorFeatures0_BYPASS_IN_MSAA 0x04000000 > +#define chipMinorFeatures0_HZ 0x08000000 > +#define chipMinorFeatures0_NEW_TEXTURE 0x10000000 > +#define chipMinorFeatures0_2D_A8_TARGET > 0x20000000 > +#define chipMinorFeatures0_CORRECT_STENCIL 0x40000000 > +#define chipMinorFeatures0_ENHANCE_VR 0x80000000 > +#define chipMinorFeatures1_RSUV_SWIZZLE > 0x00000001 > +#define chipMinorFeatures1_V2_COMPRESSION 0x00000002 > +#define chipMinorFeatures1_VG_DOUBLE_BUFFER 0x00000004 > +#define chipMinorFeatures1_EXTRA_EVENT_STATES 0x00000008 > +#define chipMinorFeatures1_NO_STRIPING_NEEDED 0x00000010 > +#define chipMinorFeatures1_TEXTURE_STRIDE 0x00000020 > +#define chipMinorFeatures1_BUG_FIXES3 0x00000040 > +#define chipMinorFeatures1_AUTO_DISABLE > 0x00000080 > +#define chipMinorFeatures1_AUTO_RESTART_TS 0x00000100 > +#define chipMinorFeatures1_DISABLE_PE_GATING 0x00000200 > +#define chipMinorFeatures1_L2_WINDOWING > 0x00000400 > +#define chipMinorFeatures1_HALF_FLOAT 0x00000800 > +#define chipMinorFeatures1_PIXEL_DITHER > 0x00001000 > +#define chipMinorFeatures1_TWO_STENCIL_REFERENCE 0x00002000 > +#define chipMinorFeatures1_EXTENDED_PIXEL_FORMAT 0x00004000 > +#define chipMinorFeatures1_CORRECT_MIN_MAX_DEPTH 0x00008000 > +#define chipMinorFeatures1_2D_DITHER 0x00010000 > +#define chipMinorFeatures1_BUG_FIXES5 0x00020000 > +#define chipMinorFeatures1_NEW_2D 0x00040000 > +#define chipMinorFeatures1_NEW_FP 0x00080000 > +#define chipMinorFeatures1_TEXTURE_HALIGN 0x00100000 > +#define chipMinorFeatures1_NON_POWER_OF_TWO 0x00200000 > +#define chipMinorFeatures1_LINEAR_TEXTURE_SUPPORT 0x00400000 > +#define chipMinorFeatures1_HALTI0 0x00800000 > +#define chipMinorFeatures1_CORRECT_OVERFLOW_VG 0x01000000 > +#define chipMinorFeatures1_NEGATIVE_LOG_FIX 0x02000000 > +#define chipMinorFeatures1_RESOLVE_OFFSET 0x04000000 > +#define chipMinorFeatures1_OK_TO_GATE_AXI_CLOCK > 0x08000000 > +#define chipMinorFeatures1_MMU_VERSION 0x10000000 > +#define chipMinorFeatures1_WIDE_LINE 0x20000000 > +#define chipMinorFeatures1_BUG_FIXES6 0x40000000 > +#define chipMinorFeatures1_FC_FLUSH_STALL 0x80000000 > +#define chipMinorFeatures2_LINE_LOOP 0x00000001 > +#define chipMinorFeatures2_LOGIC_OP 0x00000002 > +#define chipMinorFeatures2_UNK2 > 0x00000004 > +#define chipMinorFeatures2_SUPERTILED_TEXTURE 0x00000008 > +#define chipMinorFeatures2_UNK4 > 0x00000010 > +#define chipMinorFeatures2_RECT_PRIMITIVE 0x00000020 > +#define chipMinorFeatures2_COMPOSITION 0x00000040 > +#define chipMinorFeatures2_CORRECT_AUTO_DISABLE_COUNT 0x00000080 > +#define chipMinorFeatures2_UNK8 > 0x00000100 > +#define chipMinorFeatures2_UNK9 > 0x00000200 > +#define chipMinorFeatures2_UNK10 0x00000400 > +#define chipMinorFeatures2_SAMPLERBASE_16 0x00000800 > +#define chipMinorFeatures2_UNK12 0x00001000 > +#define chipMinorFeatures2_UNK13 0x00002000 > +#define chipMinorFeatures2_UNK14 0x00004000 > +#define chipMinorFeatures2_EXTRA_TEXTURE_STATE 0x00008000 > +#define chipMinorFeatures2_FULL_DIRECTFB 0x00010000 > +#define chipMinorFeatures2_2D_TILING 0x00020000 > +#define chipMinorFeatures2_THREAD_WALKER_IN_PS 0x00040000 > +#define chipMinorFeatures2_TILE_FILLER 0x00080000 > +#define chipMinorFeatures2_UNK20 0x00100000 > +#define chipMinorFeatures2_2D_MULTI_SOURCE_BLIT > 0x00200000 > +#define chipMinorFeatures2_UNK22 0x00400000 > +#define chipMinorFeatures2_UNK23 0x00800000 > +#define chipMinorFeatures2_UNK24 0x01000000 > +#define chipMinorFeatures2_MIXED_STREAMS 0x02000000 > +#define chipMinorFeatures2_2D_420_L2CACHE 0x04000000 > +#define chipMinorFeatures2_UNK27 0x08000000 > +#define chipMinorFeatures2_2D_NO_INDEX8_BRUSH 0x10000000 > +#define chipMinorFeatures2_TEXTURE_TILED_READ 0x20000000 > +#define chipMinorFeatures2_UNK30 0x40000000 > +#define chipMinorFeatures2_UNK31 0x80000000 > +#define chipMinorFeatures3_ROTATION_STALL_FIX 0x00000001 > +#define chipMinorFeatures3_UNK1 > 0x00000002 > +#define chipMinorFeatures3_2D_MULTI_SOURCE_BLT_EX 0x00000004 > +#define chipMinorFeatures3_UNK3 > 0x00000008 > +#define chipMinorFeatures3_UNK4 > 0x00000010 > +#define chipMinorFeatures3_UNK5 > 0x00000020 > +#define chipMinorFeatures3_UNK6 > 0x00000040 > +#define chipMinorFeatures3_UNK7 > 0x00000080 > +#define chipMinorFeatures3_UNK8 > 0x00000100 > +#define chipMinorFeatures3_UNK9 > 0x00000200 > +#define chipMinorFeatures3_BUG_FIXES10 0x00000400 > +#define chipMinorFeatures3_UNK11 0x00000800 > +#define chipMinorFeatures3_BUG_FIXES11 0x00001000 > +#define chipMinorFeatures3_UNK13 0x00002000 > +#define chipMinorFeatures3_UNK14 0x00004000 > +#define chipMinorFeatures3_UNK15 0x00008000 > +#define chipMinorFeatures3_UNK16 0x00010000 > +#define chipMinorFeatures3_UNK17 0x00020000 > +#define chipMinorFeatures3_UNK18 0x00040000 > +#define chipMinorFeatures3_UNK19 0x00080000 > +#define chipMinorFeatures3_UNK20 0x00100000 > +#define chipMinorFeatures3_UNK21 0x00200000 > +#define chipMinorFeatures3_UNK22 0x00400000 > +#define chipMinorFeatures3_UNK23 0x00800000 > +#define chipMinorFeatures3_UNK24 0x01000000 > +#define chipMinorFeatures3_UNK25 0x02000000 > +#define chipMinorFeatures3_UNK26 0x04000000 > +#define chipMinorFeatures3_UNK27 0x08000000 > +#define chipMinorFeatures3_UNK28 0x10000000 > +#define chipMinorFeatures3_UNK29 0x20000000 > +#define chipMinorFeatures3_UNK30 0x40000000 > +#define chipMinorFeatures3_UNK31 0x80000000 > +#define chipMinorFeatures4_UNK0 > 0x00000001 > +#define chipMinorFeatures4_UNK1 > 0x00000002 > +#define chipMinorFeatures4_UNK2 > 0x00000004 > +#define chipMinorFeatures4_UNK3 > 0x00000008 > +#define chipMinorFeatures4_UNK4 > 0x00000010 > +#define chipMinorFeatures4_UNK5 > 0x00000020 > +#define chipMinorFeatures4_UNK6 > 0x00000040 > +#define chipMinorFeatures4_UNK7 > 0x00000080 > +#define chipMinorFeatures4_UNK8 > 0x00000100 > +#define chipMinorFeatures4_UNK9 > 0x00000200 > +#define chipMinorFeatures4_UNK10 0x00000400 > +#define chipMinorFeatures4_UNK11 0x00000800 > +#define chipMinorFeatures4_UNK12 0x00001000 > +#define chipMinorFeatures4_UNK13 0x00002000 > +#define chipMinorFeatures4_UNK14 0x00004000 > +#define chipMinorFeatures4_UNK15 0x00008000 > +#define chipMinorFeatures4_UNK16 0x00010000 > +#define chipMinorFeatures4_UNK17 0x00020000 > +#define chipMinorFeatures4_UNK18 0x00040000 > +#define chipMinorFeatures4_UNK19 0x00080000 > +#define chipMinorFeatures4_UNK20 0x00100000 > +#define chipMinorFeatures4_UNK21 0x00200000 > +#define chipMinorFeatures4_UNK22 0x00400000 > +#define chipMinorFeatures4_UNK23 0x00800000 > +#define chipMinorFeatures4_UNK24 0x01000000 > +#define chipMinorFeatures4_UNK25 0x02000000 > +#define chipMinorFeatures4_UNK26 0x04000000 > +#define chipMinorFeatures4_UNK27 0x08000000 > +#define chipMinorFeatures4_UNK28 0x10000000 > +#define chipMinorFeatures4_UNK29 0x20000000 > +#define chipMinorFeatures4_UNK30 0x40000000 > +#define chipMinorFeatures4_UNK31 0x80000000 > + > +#endif /* COMMON_XML */ > diff --git a/drivers/staging/etnaviv/etnaviv_buffer.c > b/drivers/staging/etnaviv/etnaviv_buffer.c > new file mode 100644 > index 000000000000..586f84316f1a > --- /dev/null > +++ b/drivers/staging/etnaviv/etnaviv_buffer.c > @@ -0,0 +1,271 @@ > +/* > + * Copyright (C) 2014 Etnaviv Project > + * Author: Christian Gmeiner <christian.gmeiner at gmail.com> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "etnaviv_gpu.h" > +#include "etnaviv_gem.h" > +#include "etnaviv_mmu.h" > + > +#include "common.xml.h" > +#include "state.xml.h" > +#include "cmdstream.xml.h" > + > +/* > + * Command Buffer helper: > + */ > + > + > +static inline void OUT(struct etnaviv_cmdbuf *buffer, u32 data) > +{ > + u32 *vaddr = (u32 *)buffer->vaddr; > + > + BUG_ON(buffer->user_size >= buffer->size); > + > + vaddr[buffer->user_size / 4] = data; > + buffer->user_size += 4; > +} > + > +static inline void CMD_LOAD_STATE(struct etnaviv_cmdbuf *buffer, > + u32 reg, u32 value) > +{ > + u32 index = reg >> VIV_FE_LOAD_STATE_HEADER_OFFSET__SHR; > + > + buffer->user_size = ALIGN(buffer->user_size, 8); > + > + /* write a register via cmd stream */ > + OUT(buffer, VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE | > + VIV_FE_LOAD_STATE_HEADER_COUNT(1) | > + VIV_FE_LOAD_STATE_HEADER_OFFSET(index)); > + OUT(buffer, value); > +} > + > +static inline void CMD_END(struct etnaviv_cmdbuf *buffer) > +{ > + buffer->user_size = ALIGN(buffer->user_size, 8); > + > + OUT(buffer, VIV_FE_END_HEADER_OP_END); > +} > + > +static inline void CMD_WAIT(struct etnaviv_cmdbuf *buffer) > +{ > + buffer->user_size = ALIGN(buffer->user_size, 8); > + > + OUT(buffer, VIV_FE_WAIT_HEADER_OP_WAIT | 200); > +} > + > +static inline void CMD_LINK(struct etnaviv_cmdbuf *buffer, > + u16 prefetch, u32 address) > +{ > + buffer->user_size = ALIGN(buffer->user_size, 8); > + > + OUT(buffer, VIV_FE_LINK_HEADER_OP_LINK | > + VIV_FE_LINK_HEADER_PREFETCH(prefetch)); > + OUT(buffer, address); > +} > + > +static inline void CMD_STALL(struct etnaviv_cmdbuf *buffer, > + u32 from, u32 to) > +{ > + buffer->user_size = ALIGN(buffer->user_size, 8); > + > + OUT(buffer, VIV_FE_STALL_HEADER_OP_STALL); > + OUT(buffer, VIV_FE_STALL_TOKEN_FROM(from) | > VIV_FE_STALL_TOKEN_TO(to)); > +} > + > +static void etnaviv_cmd_select_pipe(struct etnaviv_cmdbuf *buffer, u8 pipe) > +{ > + u32 flush; > + u32 stall; > + > + if (pipe == ETNA_PIPE_2D) > + flush = VIVS_GL_FLUSH_CACHE_DEPTH | VIVS_GL_FLUSH_CACHE_COLOR; > + else > + flush = VIVS_GL_FLUSH_CACHE_TEXTURE; > + > + stall = VIVS_GL_SEMAPHORE_TOKEN_FROM(SYNC_RECIPIENT_FE) | > + VIVS_GL_SEMAPHORE_TOKEN_TO(SYNC_RECIPIENT_PE); > + > + CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_CACHE, flush); > + CMD_LOAD_STATE(buffer, VIVS_GL_SEMAPHORE_TOKEN, stall); > + > + CMD_STALL(buffer, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE); > + > + CMD_LOAD_STATE(buffer, VIVS_GL_PIPE_SELECT, > + VIVS_GL_PIPE_SELECT_PIPE(pipe)); > +} > + > +static u32 gpu_va(struct etnaviv_gpu *gpu, struct etnaviv_cmdbuf *buf) > +{ > + return buf->paddr - gpu->memory_base; > +} > + > +static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, > + struct etnaviv_cmdbuf *buf, u32 off, u32 len) > +{ > + u32 size = buf->size; > + u32 *ptr = buf->vaddr + off; > + > + dev_info(gpu->dev, "virt %p phys 0x%08x free 0x%08x\n", > + ptr, gpu_va(gpu, buf) + off, size - len * 4 - off); > + > + print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4, > + ptr, len * 4, 0); > +} > + > +u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu) > +{ > + struct etnaviv_cmdbuf *buffer = gpu->buffer; > + > + /* initialize buffer */ > + buffer->user_size = 0; > + > + CMD_WAIT(buffer); > + CMD_LINK(buffer, 2, gpu_va(gpu, buffer) + buffer->user_size - 4); > + > + return buffer->user_size / 8; > +} > + > +void etnaviv_buffer_end(struct etnaviv_gpu *gpu) > +{ > + struct etnaviv_cmdbuf *buffer = gpu->buffer; > + > + /* Replace the last WAIT with an END */ > + buffer->user_size -= 16; > + > + CMD_END(buffer); > + mb(); > +} > + > +void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, > + struct etnaviv_gem_submit *submit) > +{ > + struct etnaviv_cmdbuf *buffer = gpu->buffer; > + u32 *lw = buffer->vaddr + buffer->user_size - 16; > + u32 back, link_target, link_size, reserve_size, extra_size = 0; > + > + if (drm_debug & DRM_UT_DRIVER) > + etnaviv_buffer_dump(gpu, buffer, 0, 0x50); > + > + /* > + * If we need to flush the MMU prior to submitting this buffer, we > + * will need to append a mmu flush load state, followed by a new > + * link to this buffer - a total of four additional words. > + */ > + if (gpu->mmu->need_flush || gpu->switch_context) { > + /* link command */ > + extra_size += 2; > + /* flush command */ > + if (gpu->mmu->need_flush) > + extra_size += 2; > + /* pipe switch commands */ > + if (gpu->switch_context) > + extra_size += 8; > + } > + > + reserve_size = (6 + extra_size) * 4; > + > + /* > + * if we are going to completely overflow the buffer, we need to wrap. > + */ > + if (buffer->user_size + reserve_size > buffer->size) > + buffer->user_size = 0; > + > + /* save offset back into main buffer */ > + back = buffer->user_size + reserve_size - 6 * 4; > + link_target = gpu_va(gpu, buffer) + buffer->user_size; > + link_size = 6; > + > + /* Skip over any extra instructions */ > + link_target += extra_size * sizeof(u32); > + > + if (drm_debug & DRM_UT_DRIVER) > + pr_info("stream link to 0x%08x @ 0x%08x %p\n", > + link_target, gpu_va(gpu, submit->cmdbuf), > + submit->cmdbuf->vaddr); > + > + /* jump back from cmd to main buffer */ > + CMD_LINK(submit->cmdbuf, link_size, link_target); > + > + link_target = gpu_va(gpu, submit->cmdbuf); > + link_size = submit->cmdbuf->size / 8; > + > + > + > + if (drm_debug & DRM_UT_DRIVER) { > + print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4, > + submit->cmdbuf->vaddr, submit->cmdbuf->size, > 0); > + > + pr_info("link op: %p\n", lw); > + pr_info("link addr: %p\n", lw + 1); > + pr_info("addr: 0x%08x\n", link_target); > + pr_info("back: 0x%08x\n", gpu_va(gpu, buffer) + back); > + pr_info("event: %d\n", event); > + } > + > + if (gpu->mmu->need_flush || gpu->switch_context) { > + u32 new_target = gpu_va(gpu, buffer) + buffer->user_size; > + > + if (gpu->mmu->need_flush) { > + /* Add the MMU flush */ > + CMD_LOAD_STATE(buffer, VIVS_GL_FLUSH_MMU, > + VIVS_GL_FLUSH_MMU_FLUSH_FEMMU | > + VIVS_GL_FLUSH_MMU_FLUSH_UNK1 | > + VIVS_GL_FLUSH_MMU_FLUSH_UNK2 | > + VIVS_GL_FLUSH_MMU_FLUSH_PEMMU | > + VIVS_GL_FLUSH_MMU_FLUSH_UNK4); > + > + gpu->mmu->need_flush = false; > + } > + > + if (gpu->switch_context) { > + etnaviv_cmd_select_pipe(buffer, submit->exec_state); > + gpu->switch_context = false; > + } > + > + /* And the link to the first buffer */ > + CMD_LINK(buffer, link_size, link_target); > + > + /* Update the link target to point to above instructions */ > + link_target = new_target; > + link_size = extra_size; > + } > + > + /* Save the event and buffer position of the new event trigger */ > + gpu->event[event].fence = submit->fence; > + > + /* take ownership of cmdbuffer*/ > + submit->cmdbuf->fence = submit->fence; > + list_add_tail(&submit->cmdbuf->gpu_active_list, > &gpu->active_cmd_list); > + submit->cmdbuf = NULL; > + > + /* trigger event */ > + CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) | > + VIVS_GL_EVENT_FROM_PE); > + > + /* append WAIT/LINK to main buffer */ > + CMD_WAIT(buffer); > + CMD_LINK(buffer, 2, gpu_va(gpu, buffer) + (buffer->user_size - 4)); > + > + /* Change WAIT into a LINK command; write the address first. */ > + *(lw + 1) = link_target; > + mb(); > + *(lw) = VIV_FE_LINK_HEADER_OP_LINK | > + VIV_FE_LINK_HEADER_PREFETCH(link_size); > + mb(); > + > + if (drm_debug & DRM_UT_DRIVER) > + etnaviv_buffer_dump(gpu, buffer, 0, 0x50); > +} > diff --git a/drivers/staging/etnaviv/etnaviv_cmd_parser.c > b/drivers/staging/etnaviv/etnaviv_cmd_parser.c > new file mode 100644 > index 000000000000..5175d6eb3bdc > --- /dev/null > +++ b/drivers/staging/etnaviv/etnaviv_cmd_parser.c > @@ -0,0 +1,119 @@ > +/* > + * Copyright (C) 2015 Etnaviv Project > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#include <linux/kernel.h> > + > +#include "etnaviv_gem.h" > +#include "etnaviv_gpu.h" > + > +#include "cmdstream.xml.h" > + > +#define EXTRACT(val, field) (((val) & field##__MASK) >> field##__SHIFT) > + > +static bool etnaviv_validate_load_state(struct etnaviv_gpu *gpu, u32 *buf, > + unsigned int state, unsigned int num) > +{ > + return true; > + if (0x1200 - state < num * 4) > + return false; > + if (0x1228 - state < num * 4) > + return false; > + if (0x1238 - state < num * 4) > + return false; > + if (0x1284 - state < num * 4) > + return false; > + if (0x128c - state < num * 4) > + return false; > + if (0x1304 - state < num * 4) > + return false; > + if (0x1310 - state < num * 4) > + return false; > + if (0x1318 - state < num * 4) > + return false; > + if (0x1280c - state < num * 4 + 0x0c) > + return false; > + if (0x128ac - state < num * 4 + 0x0c) > + return false; > + if (0x128cc - state < num * 4 + 0x0c) > + return false; > + if (0x1297c - state < num * 4 + 0x0c) > + return false; > + return true; > +} > + > +static uint8_t cmd_length[32] = { > + [FE_OPCODE_DRAW_PRIMITIVES] = 4, > + [FE_OPCODE_DRAW_INDEXED_PRIMITIVES] = 6, > + [FE_OPCODE_NOP] = 2, > + [FE_OPCODE_STALL] = 2, > +}; > + > +bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu, void *stream, > + unsigned int size) > +{ > + u32 *start = stream; > + u32 *buf = start; > + u32 *end = buf + size; > + > + while (buf < end) { > + u32 cmd = *buf; > + unsigned int len, n, off; > + unsigned int op = cmd >> 27; > + > + switch (op) { > + case FE_OPCODE_LOAD_STATE: > + n = EXTRACT(cmd, VIV_FE_LOAD_STATE_HEADER_COUNT); > + len = ALIGN(1 + n, 2); > + if (buf + len > end) > + break; > + > + off = EXTRACT(cmd, VIV_FE_LOAD_STATE_HEADER_OFFSET); > + if (!etnaviv_validate_load_state(gpu, buf + 1, > + off * 4, n)) { > + dev_warn(gpu->dev, "%s: load state covers > restricted state (0x%x-0x%x) at offset %tu\n", > + __func__, off * 4, (off + n) * 4, > buf - start); > + return false; > + } > + break; > + > + case FE_OPCODE_DRAW_2D: > + n = EXTRACT(cmd, VIV_FE_DRAW_2D_HEADER_COUNT); > + if (n == 0) > + n = 256; > + len = 2 + n * 2; > + break; > + > + default: > + len = cmd_length[op]; > + if (len == 0) { > + dev_err(gpu->dev, "%s: op %u not permitted at > offset %tu\n", > + __func__, op, buf - start); > + return false; > + } > + break; > + } > + > + buf += len; > + } > + > + if (buf > end) { > + dev_err(gpu->dev, "%s: commands overflow end of buffer: %tu > > %u\n", > + __func__, buf - start, size); > + return false; > + } > + > + return true; > +} > diff --git a/drivers/staging/etnaviv/etnaviv_drv.c > b/drivers/staging/etnaviv/etnaviv_drv.c > new file mode 100644 > index 000000000000..30f6e5d0c91d > --- /dev/null > +++ b/drivers/staging/etnaviv/etnaviv_drv.c > @@ -0,0 +1,705 @@ > +/* > + * Copyright (C) 2015 Etnaviv Project > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#include <linux/component.h> > +#include <linux/of_platform.h> > + > +#include "etnaviv_drv.h" > +#include "etnaviv_gpu.h" > +#include "etnaviv_gem.h" > +#include "etnaviv_mmu.h" > +#include "etnaviv_gem.h" > + > +#ifdef CONFIG_DRM_ETNAVIV_REGISTER_LOGGING > +static bool reglog; > +MODULE_PARM_DESC(reglog, "Enable register read/write logging"); > +module_param(reglog, bool, 0600); > +#else > +#define reglog 0 > +#endif > + > +void __iomem *etnaviv_ioremap(struct platform_device *pdev, const char *name, > + const char *dbgname) > +{ > + struct resource *res; > + void __iomem *ptr; > + > + if (name) > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, > name); > + else > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + > + ptr = devm_ioremap_resource(&pdev->dev, res); > + if (IS_ERR(ptr)) { > + dev_err(&pdev->dev, "failed to ioremap %s: %ld\n", name, > + PTR_ERR(ptr)); > + return ptr; > + } > + > + if (reglog) > + dev_printk(KERN_DEBUG, &pdev->dev, "IO:region %s 0x%p > %08zx\n", > + dbgname, ptr, (size_t)resource_size(res)); > + > + return ptr; > +} > + > +void etnaviv_writel(u32 data, void __iomem *addr) > +{ > + if (reglog) > + printk(KERN_DEBUG "IO:W %p %08x\n", addr, data); > + > + writel(data, addr); > +} > + > +u32 etnaviv_readl(const void __iomem *addr) > +{ > + u32 val = readl(addr); > + > + if (reglog) > + printk(KERN_DEBUG "IO:R %p %08x\n", addr, val); > + > + return val; > +} > + > +/* > + * DRM operations: > + */ > + > +static int etnaviv_unload(struct drm_device *dev) > +{ > + struct etnaviv_drm_private *priv = dev->dev_private; > + > + flush_workqueue(priv->wq); > + destroy_workqueue(priv->wq); > + > + component_unbind_all(dev->dev, dev); > + > + dev->dev_private = NULL; > + > + kfree(priv); > + > + return 0; > +} > + > + > +static void load_gpu(struct drm_device *dev) > +{ > + struct etnaviv_drm_private *priv = dev->dev_private; > + unsigned int i; > + > + for (i = 0; i < ETNA_MAX_PIPES; i++) { > + struct etnaviv_gpu *g = priv->gpu[i]; > + > + if (g) { > + int ret; > + > + ret = etnaviv_gpu_init(g); > + if (ret) { > + dev_err(g->dev, "hw init failed: %d\n", ret); > + priv->gpu[i] = NULL; > + } > + } > + } > +} > + > +static int etnaviv_load(struct drm_device *dev, unsigned long flags) > +{ > + struct platform_device *pdev = dev->platformdev; > + struct etnaviv_drm_private *priv; > + int err; > + > + priv = kzalloc(sizeof(*priv), GFP_KERNEL); > + if (!priv) { > + dev_err(dev->dev, "failed to allocate private data\n"); > + return -ENOMEM; > + } > + > + dev->dev_private = priv; > + > + priv->wq = alloc_ordered_workqueue("etnaviv", 0); > + if (!priv->wq) { > + err = -ENOMEM; > + goto err_wq; > + } > + > + INIT_LIST_HEAD(&priv->inactive_list); > + priv->num_gpus = 0; > + > + platform_set_drvdata(pdev, dev); > + > + err = component_bind_all(dev->dev, dev); > + if (err < 0) > + goto err_bind; > + > + load_gpu(dev); > + > + return 0; > + > +err_bind: > + flush_workqueue(priv->wq); > + destroy_workqueue(priv->wq); > +err_wq: > + kfree(priv); > + return err; > +} > + > +static int etnaviv_open(struct drm_device *dev, struct drm_file *file) > +{ > + struct etnaviv_file_private *ctx; > + > + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); > + if (!ctx) > + return -ENOMEM; > + > + file->driver_priv = ctx; > + > + return 0; > +} > + > +static void etnaviv_preclose(struct drm_device *dev, struct drm_file *file) > +{ > + struct etnaviv_drm_private *priv = dev->dev_private; > + struct etnaviv_file_private *ctx = file->driver_priv; > + unsigned int i; > + > + mutex_lock(&dev->struct_mutex); > + for (i = 0; i < ETNA_MAX_PIPES; i++) { > + struct etnaviv_gpu *gpu = priv->gpu[i]; > + > + if (gpu && gpu->lastctx == ctx) > + gpu->lastctx = NULL; > + } > + mutex_unlock(&dev->struct_mutex); > + > + kfree(ctx); > +} > + > +/* > + * DRM debugfs: > + */ > + > +#ifdef CONFIG_DEBUG_FS > +static int etnaviv_gem_show(struct drm_device *dev, struct seq_file *m) > +{ > + struct etnaviv_drm_private *priv = dev->dev_private; > + struct etnaviv_gpu *gpu; > + unsigned int i; > + > + for (i = 0; i < ETNA_MAX_PIPES; i++) { > + gpu = priv->gpu[i]; > + if (gpu) { > + seq_printf(m, "Active Objects (%s):\n", > + dev_name(gpu->dev)); > + etnaviv_gem_describe_objects(&gpu->active_list, m); > + } > + } > + > + seq_puts(m, "Inactive Objects:\n"); > + etnaviv_gem_describe_objects(&priv->inactive_list, m); > + > + return 0; > +} > + > +static int etnaviv_mm_show(struct drm_device *dev, struct seq_file *m) > +{ > + return drm_mm_dump_table(m, > &dev->vma_offset_manager->vm_addr_space_mm); > +} > + > +static int etnaviv_mmu_show(struct drm_device *dev, struct seq_file *m) > +{ > + struct etnaviv_drm_private *priv = dev->dev_private; > + struct etnaviv_gpu *gpu; > + unsigned int i; > + > + for (i = 0; i < ETNA_MAX_PIPES; i++) { > + gpu = priv->gpu[i]; > + if (gpu) { > + seq_printf(m, "Active Objects (%s):\n", > + dev_name(gpu->dev)); > + drm_mm_dump_table(m, &gpu->mmu->mm); > + } > + } > + return 0; > +} > + > +static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, struct seq_file *m) > +{ > + struct etnaviv_cmdbuf *buf = gpu->buffer; > + u32 size = buf->size; > + u32 *ptr = buf->vaddr; > + u32 i; > + > + seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n", > + buf->vaddr, (u64)buf->paddr, size - buf->user_size); > + > + for (i = 0; i < size / 4; i++) { > + if (i && !(i % 4)) > + seq_puts(m, "\n"); > + if (i % 4 == 0) > + seq_printf(m, "\t0x%p: ", ptr + i); > + seq_printf(m, "%08x ", *(ptr + i)); > + } > + seq_puts(m, "\n"); > +} > + > +static int etnaviv_ring_show(struct drm_device *dev, struct seq_file *m) > +{ > + struct etnaviv_drm_private *priv = dev->dev_private; > + struct etnaviv_gpu *gpu; > + unsigned int i; > + > + for (i = 0; i < ETNA_MAX_PIPES; i++) { > + gpu = priv->gpu[i]; > + if (gpu) { > + seq_printf(m, "Ring Buffer (%s): ", > + dev_name(gpu->dev)); > + etnaviv_buffer_dump(gpu, m); > + } > + } > + return 0; > +} > + > +static int show_locked(struct seq_file *m, void *arg) > +{ > + struct drm_info_node *node = (struct drm_info_node *) m->private; > + struct drm_device *dev = node->minor->dev; > + int (*show)(struct drm_device *dev, struct seq_file *m) = > + node->info_ent->data; > + int ret; > + > + ret = mutex_lock_interruptible(&dev->struct_mutex); > + if (ret) > + return ret; > + > + ret = show(dev, m); > + > + mutex_unlock(&dev->struct_mutex); > + > + return ret; > +} > + > +static int show_each_gpu(struct seq_file *m, void *arg) > +{ > + struct drm_info_node *node = (struct drm_info_node *) m->private; > + struct drm_device *dev = node->minor->dev; > + struct etnaviv_drm_private *priv = dev->dev_private; > + struct etnaviv_gpu *gpu; > + int (*show)(struct etnaviv_gpu *gpu, struct seq_file *m) = > + node->info_ent->data; > + unsigned int i; > + int ret = 0; > + > + for (i = 0; i < ETNA_MAX_PIPES; i++) { > + gpu = priv->gpu[i]; > + if (!gpu) > + continue; > + > + ret = show(gpu, m); > + if (ret < 0) > + break; > + } > + > + return ret; > +} > + > +static struct drm_info_list etnaviv_debugfs_list[] = { > + {"gpu", show_each_gpu, 0, etnaviv_gpu_debugfs}, > + {"gem", show_locked, 0, etnaviv_gem_show}, > + { "mm", show_locked, 0, etnaviv_mm_show }, > + {"mmu", show_locked, 0, etnaviv_mmu_show}, > + {"ring", show_locked, 0, etnaviv_ring_show}, > +}; > + > +static int etnaviv_debugfs_init(struct drm_minor *minor) > +{ > + struct drm_device *dev = minor->dev; > + int ret; > + > + ret = drm_debugfs_create_files(etnaviv_debugfs_list, > + ARRAY_SIZE(etnaviv_debugfs_list), > + minor->debugfs_root, minor); > + > + if (ret) { > + dev_err(dev->dev, "could not install etnaviv_debugfs_list\n"); > + return ret; > + } > + > + return ret; > +} > + > +static void etnaviv_debugfs_cleanup(struct drm_minor *minor) > +{ > + drm_debugfs_remove_files(etnaviv_debugfs_list, > + ARRAY_SIZE(etnaviv_debugfs_list), minor); > +} > +#endif > + > +/* > + * DRM ioctls: > + */ > + > +static int etnaviv_ioctl_get_param(struct drm_device *dev, void *data, > + struct drm_file *file) > +{ > + struct etnaviv_drm_private *priv = dev->dev_private; > + struct drm_etnaviv_param *args = data; > + struct etnaviv_gpu *gpu; > + > + if (args->pipe >= ETNA_MAX_PIPES) > + return -EINVAL; > + > + gpu = priv->gpu[args->pipe]; > + if (!gpu) > + return -ENXIO; > + > + return etnaviv_gpu_get_param(gpu, args->param, &args->value); > +} > + > +static int etnaviv_ioctl_gem_new(struct drm_device *dev, void *data, > + struct drm_file *file) > +{ > + struct drm_etnaviv_gem_new *args = data; > + > + return etnaviv_gem_new_handle(dev, file, args->size, > + args->flags, &args->handle); > +} > + > +#define TS(t) ((struct timespec){ \ > + .tv_sec = (t).tv_sec, \ > + .tv_nsec = (t).tv_nsec \ > +}) > + > +static int etnaviv_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, > + struct drm_file *file) > +{ > + struct drm_etnaviv_gem_cpu_prep *args = data; > + struct drm_gem_object *obj; > + int ret; > + > + obj = drm_gem_object_lookup(dev, file, args->handle); > + if (!obj) > + return -ENOENT; > + > + ret = etnaviv_gem_cpu_prep(obj, args->op, &TS(args->timeout)); > + > + drm_gem_object_unreference_unlocked(obj); > + > + return ret; > +} > + > +static int etnaviv_ioctl_gem_cpu_fini(struct drm_device *dev, void *data, > + struct drm_file *file) > +{ > + struct drm_etnaviv_gem_cpu_fini *args = data; > + struct drm_gem_object *obj; > + int ret; > + > + obj = drm_gem_object_lookup(dev, file, args->handle); > + if (!obj) > + return -ENOENT; > + > + ret = etnaviv_gem_cpu_fini(obj); > + > + drm_gem_object_unreference_unlocked(obj); > + > + return ret; > +} > + > +static int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data, > + struct drm_file *file) > +{ > + struct drm_etnaviv_gem_info *args = data; > + struct drm_gem_object *obj; > + int ret; > + > + if (args->pad) > + return -EINVAL; > + > + obj = drm_gem_object_lookup(dev, file, args->handle); > + if (!obj) > + return -ENOENT; > + > + ret = mutex_lock_interruptible(&dev->struct_mutex); > + if (ret == 0) { > + ret = etnaviv_gem_mmap_offset(obj, &args->offset); > + > + mutex_unlock(&dev->struct_mutex); > + } > + > + drm_gem_object_unreference_unlocked(obj); > + > + return ret; > +} > + > +static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data, > + struct drm_file *file) > +{ > + struct drm_etnaviv_wait_fence *args = data; > + struct etnaviv_drm_private *priv = dev->dev_private; > + struct etnaviv_gpu *gpu; > + > + if (args->pipe >= ETNA_MAX_PIPES) > + return -EINVAL; > + > + gpu = priv->gpu[args->pipe]; > + if (!gpu) > + return -ENXIO; > + > + return etnaviv_gpu_wait_fence_interruptible(gpu, args->fence, > + &TS(args->timeout)); > +} > + > +static int etnaviv_ioctl_gem_userptr(struct drm_device *dev, void *data, > + struct drm_file *file) > +{ > + struct drm_etnaviv_gem_userptr *args = data; > + int access; > + > + if (args->flags & ~(ETNA_USERPTR_READ|ETNA_USERPTR_WRITE) || > + args->flags == 0) > + return -EINVAL; > + > + if (offset_in_page(args->user_ptr | args->user_size) || > + (uintptr_t)args->user_ptr != args->user_ptr || > + (u32)args->user_size != args->user_size) > + return -EINVAL; > + > + if (args->flags & ETNA_USERPTR_WRITE) > + access = VERIFY_WRITE; > + else > + access = VERIFY_READ; > + > + if (!access_ok(access, (void __user *)(unsigned long)args->user_ptr, > + args->user_size)) > + return -EFAULT; > + > + return etnaviv_gem_new_userptr(dev, file, args->user_ptr, > + args->user_size, args->flags, > + &args->handle); > +} > + > +static int etnaviv_ioctl_gem_wait(struct drm_device *dev, void *data, > + struct drm_file *file) > +{ > + struct etnaviv_drm_private *priv = dev->dev_private; > + struct drm_etnaviv_gem_wait *args = data; > + struct drm_gem_object *obj; > + struct etnaviv_gpu *gpu; > + int ret; > + > + if (args->pipe >= ETNA_MAX_PIPES) > + return -EINVAL; > + > + gpu = priv->gpu[args->pipe]; > + if (!gpu) > + return -ENXIO; > + > + obj = drm_gem_object_lookup(dev, file, args->handle); > + if (!obj) > + return -ENOENT; > + > + ret = etnaviv_gem_wait_bo(gpu, obj, &TS(args->timeout)); > + > + drm_gem_object_unreference_unlocked(obj); > + > + return ret; > +} > + > +static const struct drm_ioctl_desc etnaviv_ioctls[] = { > +#define ETNA_IOCTL(n, func, flags) \ > + DRM_IOCTL_DEF_DRV(ETNAVIV_##n, etnaviv_ioctl_##func, flags) > + ETNA_IOCTL(GET_PARAM, get_param, DRM_UNLOCKED|DRM_RENDER_ALLOW), > + ETNA_IOCTL(GEM_NEW, gem_new, > DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), > + ETNA_IOCTL(GEM_INFO, gem_info, > DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), > + ETNA_IOCTL(GEM_CPU_PREP, gem_cpu_prep, > DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), > + ETNA_IOCTL(GEM_CPU_FINI, gem_cpu_fini, > DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), > + ETNA_IOCTL(GEM_SUBMIT, gem_submit, > DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), > + ETNA_IOCTL(WAIT_FENCE, wait_fence, > DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), > + ETNA_IOCTL(GEM_USERPTR, gem_userptr, DRM_UNLOCKED|DRM_RENDER_ALLOW), > + ETNA_IOCTL(GEM_WAIT, gem_wait, > DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW), > +}; > + > +static const struct vm_operations_struct vm_ops = { > + .fault = etnaviv_gem_fault, > + .open = drm_gem_vm_open, > + .close = drm_gem_vm_close, > +}; > + > +static const struct file_operations fops = { > + .owner = THIS_MODULE, > + .open = drm_open, > + .release = drm_release, > + .unlocked_ioctl = drm_ioctl, > +#ifdef CONFIG_COMPAT > + .compat_ioctl = drm_compat_ioctl, > +#endif > + .poll = drm_poll, > + .read = drm_read, > + .llseek = no_llseek, > + .mmap = etnaviv_gem_mmap, > +}; > + > +static struct drm_driver etnaviv_drm_driver = { > + .driver_features = DRIVER_HAVE_IRQ | > + DRIVER_GEM | > + DRIVER_PRIME | > + DRIVER_RENDER, > + .load = etnaviv_load, > + .unload = etnaviv_unload, > + .open = etnaviv_open, > + .preclose = etnaviv_preclose, > + .set_busid = drm_platform_set_busid, > + .gem_free_object = etnaviv_gem_free_object, > + .gem_vm_ops = &vm_ops, > + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, > + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, > + .gem_prime_export = drm_gem_prime_export, > + .gem_prime_import = drm_gem_prime_import, > + .gem_prime_pin = etnaviv_gem_prime_pin, > + .gem_prime_unpin = etnaviv_gem_prime_unpin, > + .gem_prime_get_sg_table = etnaviv_gem_prime_get_sg_table, > + .gem_prime_import_sg_table = etnaviv_gem_prime_import_sg_table, > + .gem_prime_vmap = etnaviv_gem_prime_vmap, > + .gem_prime_vunmap = etnaviv_gem_prime_vunmap, > +#ifdef CONFIG_DEBUG_FS > + .debugfs_init = etnaviv_debugfs_init, > + .debugfs_cleanup = etnaviv_debugfs_cleanup, > +#endif > + .ioctls = etnaviv_ioctls, > + .num_ioctls = DRM_ETNAVIV_NUM_IOCTLS, > + .fops = &fops, > + .name = "etnaviv", > + .desc = "etnaviv DRM", > + .date = "20150910", > + .major = 1, > + .minor = 0, > +}; > + > +/* > + * Platform driver: > + */ > +static int etnaviv_bind(struct device *dev) > +{ > + return drm_platform_init(&etnaviv_drm_driver, > to_platform_device(dev)); > +} > + > +static void etnaviv_unbind(struct device *dev) > +{ > + drm_put_dev(dev_get_drvdata(dev)); > +} > + > +static const struct component_master_ops etnaviv_master_ops = { > + .bind = etnaviv_bind, > + .unbind = etnaviv_unbind, > +}; > + > +static int compare_of(struct device *dev, void *data) > +{ > + struct device_node *np = data; > + > + return dev->of_node == np; > +} > + > +static int compare_str(struct device *dev, void *data) > +{ > + return !strcmp(dev_name(dev), data); > +} > + > +static int etnaviv_pdev_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct device_node *node = dev->of_node; > + struct component_match *match = NULL; > + > + dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); > + > + if (node) { > + struct device_node *core_node; > + int i; > + > + for (i = 0; ; i++) { > + core_node = of_parse_phandle(node, "cores", i); > + if (!core_node) > + break; > + > + component_match_add(&pdev->dev, &match, compare_of, > + core_node); > + of_node_put(core_node); > + } > + } else if (dev->platform_data) { > + char **names = dev->platform_data; > + unsigned i; > + > + for (i = 0; names[i]; i++) > + component_match_add(dev, &match, compare_str, > names[i]); > + } > + > + return component_master_add_with_match(dev, &etnaviv_master_ops, > match); > +} > + > +static int etnaviv_pdev_remove(struct platform_device *pdev) > +{ > + component_master_del(&pdev->dev, &etnaviv_master_ops); > + > + return 0; > +} > + > +static const struct of_device_id dt_match[] = { > + { .compatible = "fsl,imx-gpu-subsystem" }, > + { .compatible = "marvell,dove-gpu-subsystem" }, > + {} > +}; > +MODULE_DEVICE_TABLE(of, dt_match); > + > +static struct platform_driver etnaviv_platform_driver = { > + .probe = etnaviv_pdev_probe, > + .remove = etnaviv_pdev_remove, > + .driver = { > + .owner = THIS_MODULE, > + .name = "etnaviv", > + .of_match_table = dt_match, > + }, > +}; > + > +static int __init etnaviv_init(void) > +{ > + int ret; > + > + ret = platform_driver_register(&etnaviv_gpu_driver); > + if (ret != 0) > + return ret; > + > + ret = platform_driver_register(&etnaviv_platform_driver); > + if (ret != 0) > + platform_driver_unregister(&etnaviv_gpu_driver); > + > + return ret; > +} > +module_init(etnaviv_init); > + > +static void __exit etnaviv_exit(void) > +{ > + platform_driver_unregister(&etnaviv_gpu_driver); > + platform_driver_unregister(&etnaviv_platform_driver); > +} > +module_exit(etnaviv_exit); > + > +MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner at gmail.com>"); > +MODULE_AUTHOR("Russell King <rmk+kernel at arm.linux.org.uk>"); > +MODULE_AUTHOR("Lucas Stach <l.stach at pengutronix.de>"); > +MODULE_DESCRIPTION("etnaviv DRM Driver"); > +MODULE_LICENSE("GPL v2"); > +MODULE_ALIAS("platform:etnaviv"); > diff --git a/drivers/staging/etnaviv/etnaviv_drv.h > b/drivers/staging/etnaviv/etnaviv_drv.h > new file mode 100644 > index 000000000000..719e33174e83 > --- /dev/null > +++ b/drivers/staging/etnaviv/etnaviv_drv.h > @@ -0,0 +1,138 @@ > +/* > + * Copyright (C) 2015 Etnaviv Project > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef __ETNAVIV_DRV_H__ > +#define __ETNAVIV_DRV_H__ > + > +#include <linux/kernel.h> > +#include <linux/clk.h> > +#include <linux/cpufreq.h> > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/pm.h> > +#include <linux/pm_runtime.h> > +#include <linux/slab.h> > +#include <linux/list.h> > +#include <linux/iommu.h> > +#include <linux/types.h> > +#include <linux/sizes.h> > + > +#include <drm/drmP.h> > +#include <drm/drm_crtc_helper.h> > +#include <drm/drm_fb_helper.h> > +#include <drm/drm_gem.h> > +#include <drm/etnaviv_drm.h> > + > +struct etnaviv_gpu; > +struct etnaviv_mmu; > +struct etnaviv_gem_object; > +struct etnaviv_gem_submit; > + > +struct etnaviv_file_private { > + /* currently we don't do anything useful with this.. but when > + * per-context address spaces are supported we'd keep track of > + * the context's page-tables here. > + */ > + int dummy; > +}; > + > +struct etnaviv_drm_private { > + int num_gpus; > + struct etnaviv_gpu *gpu[ETNA_MAX_PIPES]; > + > + u32 next_fence; > + > + /* list of GEM objects: */ > + struct list_head inactive_list; > + > + struct workqueue_struct *wq; > +}; > + > +static inline void etnaviv_queue_work(struct drm_device *dev, > + struct work_struct *w) > +{ > + struct etnaviv_drm_private *priv = dev->dev_private; > + > + queue_work(priv->wq, w); > +} > + > +int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, > + struct drm_file *file); > + > +int etnaviv_gem_mmap(struct file *filp, struct vm_area_struct *vma); > +int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); > +int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset); > +int etnaviv_gem_get_iova_locked(struct etnaviv_gpu *gpu, > + struct drm_gem_object *obj, u32 *iova); > +int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj, > + int id, u32 *iova); > +void etnaviv_gem_put_iova(struct drm_gem_object *obj); > +struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj); > +void *etnaviv_gem_prime_vmap(struct drm_gem_object *obj); > +void etnaviv_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); > +struct drm_gem_object *etnaviv_gem_prime_import_sg_table(struct drm_device > *dev, > + struct dma_buf_attachment *attach, struct sg_table *sg); > +int etnaviv_gem_prime_pin(struct drm_gem_object *obj); > +void etnaviv_gem_prime_unpin(struct drm_gem_object *obj); > +void *etnaviv_gem_vaddr_locked(struct drm_gem_object *obj); > +void *etnaviv_gem_vaddr(struct drm_gem_object *obj); > +dma_addr_t etnaviv_gem_paddr_locked(struct drm_gem_object *obj); > +void etnaviv_gem_move_to_active(struct drm_gem_object *obj, > + struct etnaviv_gpu *gpu, u32 access, u32 fence); > +void etnaviv_gem_move_to_inactive(struct drm_gem_object *obj); > +int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op, > + struct timespec *timeout); > +int etnaviv_gem_cpu_fini(struct drm_gem_object *obj); > +void etnaviv_gem_free_object(struct drm_gem_object *obj); > +int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file, > + u32 size, u32 flags, u32 *handle); > +struct drm_gem_object *etnaviv_gem_new_locked(struct drm_device *dev, > + u32 size, u32 flags); > +struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev, > + u32 size, u32 flags); > +int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file, > + uintptr_t ptr, u32 size, u32 flags, u32 *handle); > +u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu); > +void etnaviv_buffer_end(struct etnaviv_gpu *gpu); > +void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, > + struct etnaviv_gem_submit *submit); > +bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu, > + void *stream, unsigned int size); > + > +#ifdef CONFIG_DEBUG_FS > +void etnaviv_gem_describe_objects(struct list_head *list, struct seq_file > *m); > +#endif > + > +void __iomem *etnaviv_ioremap(struct platform_device *pdev, const char *name, > + const char *dbgname); > +void etnaviv_writel(u32 data, void __iomem *addr); > +u32 etnaviv_readl(const void __iomem *addr); > + > +#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) > +#define VERB(fmt, ...) if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) > + > +/* returns true if fence a comes after fence b */ > +static inline bool fence_after(u32 a, u32 b) > +{ > + return (s32)(a - b) > 0; > +} > + > +static inline bool fence_after_eq(u32 a, u32 b) > +{ > + return (s32)(a - b) >= 0; > +} > + > +#endif /* __ETNAVIV_DRV_H__ */ > diff --git a/drivers/staging/etnaviv/etnaviv_gem.c > b/drivers/staging/etnaviv/etnaviv_gem.c > new file mode 100644 > index 000000000000..1381c952c52f > --- /dev/null > +++ b/drivers/staging/etnaviv/etnaviv_gem.c > @@ -0,0 +1,887 @@ > +/* > + * Copyright (C) 2015 Etnaviv Project > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#include <linux/spinlock.h> > +#include <linux/shmem_fs.h> > + > +#include "etnaviv_drv.h" > +#include "etnaviv_gem.h" > +#include "etnaviv_gpu.h" > +#include "etnaviv_mmu.h" > + > +static void etnaviv_gem_scatter_map(struct etnaviv_gem_object *etnaviv_obj) > +{ > + struct drm_device *dev = etnaviv_obj->base.dev; > + struct sg_table *sgt = etnaviv_obj->sgt; > + > + /* > + * For non-cached buffers, ensure the new pages are clean > + * because display controller, GPU, etc. are not coherent. > + */ > + if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK) > + dma_map_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL); > +} > + > +static void etnaviv_gem_scatterlist_unmap(struct etnaviv_gem_object > *etnaviv_obj) > +{ > + struct drm_device *dev = etnaviv_obj->base.dev; > + struct sg_table *sgt = etnaviv_obj->sgt; > + > + /* > + * For non-cached buffers, ensure the new pages are clean > + * because display controller, GPU, etc. are not coherent: > + * > + * WARNING: The DMA API does not support concurrent CPU > + * and device access to the memory area. With BIDIRECTIONAL, > + * we will clean the cache lines which overlap the region, > + * and invalidate all cache lines (partially) contained in > + * the region. > + * > + * If you have dirty data in the overlapping cache lines, > + * that will corrupt the GPU-written data. If you have > + * written into the remainder of the region, this can > + * discard those writes. > + */ > + if (etnaviv_obj->flags & ETNA_BO_CACHE_MASK) > + dma_unmap_sg(dev->dev, sgt->sgl, sgt->nents, > DMA_BIDIRECTIONAL); > +} > + > +/* called with dev->struct_mutex held */ > +static int etnaviv_gem_shmem_get_pages(struct etnaviv_gem_object > *etnaviv_obj) > +{ > + struct drm_device *dev = etnaviv_obj->base.dev; > + struct page **p = drm_gem_get_pages(&etnaviv_obj->base); > + > + if (IS_ERR(p)) { > + dev_err(dev->dev, "could not get pages: %ld\n", PTR_ERR(p)); > + return PTR_ERR(p); > + } > + > + etnaviv_obj->pages = p; > + > + return 0; > +} > + > +static void put_pages(struct etnaviv_gem_object *etnaviv_obj) > +{ > + if (etnaviv_obj->sgt) { > + etnaviv_gem_scatterlist_unmap(etnaviv_obj); > + sg_free_table(etnaviv_obj->sgt); > + kfree(etnaviv_obj->sgt); > + etnaviv_obj->sgt = NULL; > + } > + if (etnaviv_obj->pages) { > + drm_gem_put_pages(&etnaviv_obj->base, etnaviv_obj->pages, > + true, false); > + > + etnaviv_obj->pages = NULL; > + } > +} > + > +struct page **etnaviv_gem_get_pages(struct etnaviv_gem_object *etnaviv_obj) > +{ > + int ret; > + > + if (!etnaviv_obj->pages) { > + ret = etnaviv_obj->ops->get_pages(etnaviv_obj); > + if (ret < 0) > + return ERR_PTR(ret); > + } > + > + if (!etnaviv_obj->sgt) { > + struct drm_device *dev = etnaviv_obj->base.dev; > + int npages = etnaviv_obj->base.size >> PAGE_SHIFT; > + struct sg_table *sgt; > + > + sgt = drm_prime_pages_to_sg(etnaviv_obj->pages, npages); > + if (IS_ERR(sgt)) { > + dev_err(dev->dev, "failed to allocate sgt: %ld\n", > + PTR_ERR(sgt)); > + return ERR_CAST(sgt); > + } > + > + etnaviv_obj->sgt = sgt; > + > + etnaviv_gem_scatter_map(etnaviv_obj); > + } > + > + return etnaviv_obj->pages; > +} > + > +void etnaviv_gem_put_pages(struct etnaviv_gem_object *etnaviv_obj) > +{ > + /* when we start tracking the pin count, then do something here */ > +} > + > +static int etnaviv_gem_mmap_obj(struct drm_gem_object *obj, > + struct vm_area_struct *vma) > +{ > + struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); > + pgprot_t vm_page_prot; > + > + vma->vm_flags &= ~VM_PFNMAP; > + vma->vm_flags |= VM_MIXEDMAP; > + > + vm_page_prot = vm_get_page_prot(vma->vm_flags); > + > + if (etnaviv_obj->flags & ETNA_BO_WC) { > + vma->vm_page_prot = pgprot_writecombine(vm_page_prot); > + } else if (etnaviv_obj->flags & ETNA_BO_UNCACHED) { > + vma->vm_page_prot = pgprot_noncached(vm_page_prot); > + } else { > + /* > + * Shunt off cached objs to shmem file so they have their own > + * address_space (so unmap_mapping_range does what we want, > + * in particular in the case of mmap'd dmabufs) > + */ > + fput(vma->vm_file); > + get_file(obj->filp); > + vma->vm_pgoff = 0; > + vma->vm_file = obj->filp; > + > + vma->vm_page_prot = vm_page_prot; > + } > + > + return 0; > +} > + > +int etnaviv_gem_mmap(struct file *filp, struct vm_area_struct *vma) > +{ > + struct etnaviv_gem_object *obj; > + int ret; > + > + ret = drm_gem_mmap(filp, vma); > + if (ret) { > + DBG("mmap failed: %d", ret); > + return ret; > + } > + > + obj = to_etnaviv_bo(vma->vm_private_data); > + return etnaviv_gem_mmap_obj(vma->vm_private_data, vma); > +} > + > +int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) > +{ > + struct drm_gem_object *obj = vma->vm_private_data; > + struct drm_device *dev = obj->dev; > + struct page **pages, *page; > + pgoff_t pgoff; > + int ret; > + > + /* > + * Make sure we don't parallel update on a fault, nor move or remove > + * something from beneath our feet. Note that vm_insert_page() is > + * specifically coded to take care of this, so we don't have to. > + */ > + ret = mutex_lock_interruptible(&dev->struct_mutex); > + if (ret) > + goto out; > + > + /* make sure we have pages attached now */ > + pages = etnaviv_gem_get_pages(to_etnaviv_bo(obj)); > + mutex_unlock(&dev->struct_mutex); > + > + if (IS_ERR(pages)) { > + ret = PTR_ERR(pages); > + goto out; > + } > + > + /* We don't use vmf->pgoff since that has the fake offset: */ > + pgoff = ((unsigned long)vmf->virtual_address - > + vma->vm_start) >> PAGE_SHIFT; > + > + page = pages[pgoff]; > + > + VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address, > + page_to_pfn(page), page_to_pfn(page) << PAGE_SHIFT); > + > + ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page); > + > +out: > + switch (ret) { > + case -EAGAIN: > + case 0: > + case -ERESTARTSYS: > + case -EINTR: > + case -EBUSY: > + /* > + * EBUSY is ok: this just means that another thread > + * already did the job. > + */ > + return VM_FAULT_NOPAGE; > + case -ENOMEM: > + return VM_FAULT_OOM; > + default: > + return VM_FAULT_SIGBUS; > + } > +} > + > +/* get mmap offset - must be called under struct_mutex */ > +int etnaviv_gem_mmap_offset(struct drm_gem_object *obj, u64 *offset) > +{ > + int ret; > + > + /* Make it mmapable */ > + ret = drm_gem_create_mmap_offset(obj); > + if (ret) > + dev_err(obj->dev->dev, "could not allocate mmap offset\n"); > + else > + *offset = drm_vma_node_offset_addr(&obj->vma_node); > + > + return ret; > +} > + > +/* should be called under struct_mutex.. although it can be called > + * from atomic context without struct_mutex to acquire an extra > + * iova ref if you know one is already held. > + * > + * That means when I do eventually need to add support for unpinning > + * the refcnt counter needs to be atomic_t. > + */ > +int etnaviv_gem_get_iova_locked(struct etnaviv_gpu *gpu, > + struct drm_gem_object *obj, u32 *iova) > +{ > + struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); > + struct etnaviv_vram_mapping *mapping; > + int ret = 0; > + > + mapping = etnaviv_gem_get_vram_mapping(etnaviv_obj, gpu->mmu); > + if (!mapping) { > + struct page **pages = etnaviv_gem_get_pages(etnaviv_obj); > + if (IS_ERR(pages)) > + return PTR_ERR(pages); > + ret = etnaviv_iommu_map_gem(gpu->mmu, etnaviv_obj, > + gpu->memory_base, &mapping); > + } > + > + if (!ret) > + *iova = mapping->iova; > + > + return ret; > +} > + > +int etnaviv_gem_get_iova(struct etnaviv_gpu *gpu, struct drm_gem_object *obj, > + int id, u32 *iova) > +{ > + struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); > + struct etnaviv_vram_mapping *mapping = > + etnaviv_gem_get_vram_mapping(etnaviv_obj, gpu->mmu); > + int ret; > + > + /* this is safe right now because we don't unmap until the > + * bo is deleted: > + */ > + if (mapping) { > + *iova = mapping->iova; > + return 0; > + } > + > + mutex_lock(&obj->dev->struct_mutex); > + ret = etnaviv_gem_get_iova_locked(gpu, obj, iova); > + mutex_unlock(&obj->dev->struct_mutex); > + > + return ret; > +} > + > +void etnaviv_gem_put_iova(struct drm_gem_object *obj) > +{ > + /* > + * XXX TODO .. > + * NOTE: probably don't need a _locked() version.. we wouldn't > + * normally unmap here, but instead just mark that it could be > + * unmapped (if the iova refcnt drops to zero), but then later > + * if another _get_iova_locked() fails we can start unmapping > + * things that are no longer needed.. > + */ > +} > + > +void *etnaviv_gem_vaddr_locked(struct drm_gem_object *obj) > +{ > + struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); > + > + WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); > + > + if (!etnaviv_obj->vaddr) { > + struct page **pages = etnaviv_gem_get_pages(etnaviv_obj); > + > + if (IS_ERR(pages)) > + return ERR_CAST(pages); > + > + etnaviv_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT, > + VM_MAP, pgprot_writecombine(PAGE_KERNEL)); > + } > + > + return etnaviv_obj->vaddr; > +} > + > +void *etnaviv_gem_vaddr(struct drm_gem_object *obj) > +{ > + void *ret; > + > + mutex_lock(&obj->dev->struct_mutex); > + ret = etnaviv_gem_vaddr_locked(obj); > + mutex_unlock(&obj->dev->struct_mutex); > + > + return ret; > +} > + > +dma_addr_t etnaviv_gem_paddr_locked(struct drm_gem_object *obj) > +{ > + struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); > + > + WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); > + > + return etnaviv_obj->paddr; > +} > + > +void etnaviv_gem_move_to_active(struct drm_gem_object *obj, > + struct etnaviv_gpu *gpu, u32 access, u32 fence) > +{ > + struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); > + > + etnaviv_obj->gpu = gpu; > + > + if (access & ETNA_SUBMIT_BO_READ) > + etnaviv_obj->read_fence = fence; > + if (access & ETNA_SUBMIT_BO_WRITE) > + etnaviv_obj->write_fence = fence; > + > + etnaviv_obj->access |= access; > + > + list_del_init(&etnaviv_obj->mm_list); > + list_add_tail(&etnaviv_obj->mm_list, &gpu->active_list); > +} > + > +void etnaviv_gem_move_to_inactive(struct drm_gem_object *obj) > +{ > + struct drm_device *dev = obj->dev; > + struct etnaviv_drm_private *priv = dev->dev_private; > + struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); > + > + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); > + > + etnaviv_obj->gpu = NULL; > + etnaviv_obj->read_fence = 0; > + etnaviv_obj->write_fence = 0; > + etnaviv_obj->access = 0; > + list_del_init(&etnaviv_obj->mm_list); > + list_add_tail(&etnaviv_obj->mm_list, &priv->inactive_list); > +} > + > +static inline enum dma_data_direction etnaviv_op_to_dma_dir(u32 op) > +{ > + if (op & ETNA_PREP_READ) > + return DMA_FROM_DEVICE; > + else if (op & ETNA_PREP_WRITE) > + return DMA_TO_DEVICE; > + else > + return DMA_BIDIRECTIONAL; > +} > + > +int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op, > + struct timespec *timeout) > +{ > + struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); > + struct drm_device *dev = obj->dev; > + int ret = 0; > + > + if (is_active(etnaviv_obj)) { > + struct etnaviv_gpu *gpu = etnaviv_obj->gpu; > + u32 fence = 0; > + > + if (op & ETNA_PREP_READ) > + fence = etnaviv_obj->write_fence; > + if (op & ETNA_PREP_WRITE) > + fence = max(fence, etnaviv_obj->read_fence); > + if (op & ETNA_PREP_NOSYNC) > + timeout = NULL; > + > + ret = etnaviv_gpu_wait_fence_interruptible(gpu, fence, > timeout); > + } > + > + if (etnaviv_obj->flags & ETNA_BO_CACHED) { > + if (!etnaviv_obj->sgt) { > + void * ret; > + > + mutex_lock(&dev->struct_mutex); > + ret = etnaviv_gem_get_pages(etnaviv_obj); > + mutex_unlock(&dev->struct_mutex); > + if (IS_ERR(ret)) > + return PTR_ERR(ret); > + } > + > + dma_sync_sg_for_cpu(dev->dev, etnaviv_obj->sgt->sgl, > + etnaviv_obj->sgt->nents, > + etnaviv_op_to_dma_dir(op)); > + etnaviv_obj->last_cpu_prep_op = op; > + } > + > + return ret; > +} > + > +int etnaviv_gem_cpu_fini(struct drm_gem_object *obj) > +{ > + struct drm_device *dev = obj->dev; > + struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); > + > + if (etnaviv_obj->flags & ETNA_BO_CACHED) { > + /* fini without a prep is almost certainly a userspace error > */ > + WARN_ON(etnaviv_obj->last_cpu_prep_op == 0); > + dma_sync_sg_for_device(dev->dev, etnaviv_obj->sgt->sgl, > + etnaviv_obj->sgt->nents, > + etnaviv_op_to_dma_dir(etnaviv_obj->last_cpu_prep_op)); > + etnaviv_obj->last_cpu_prep_op = 0; > + } > + > + return 0; > +} > + > +int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj, > + struct timespec *timeout) > +{ > + struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); > + > + return etnaviv_gpu_wait_obj_inactive(gpu, etnaviv_obj, timeout); > +} > + > +#ifdef CONFIG_DEBUG_FS > +static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file > *m) > +{ > + struct drm_device *dev = obj->dev; > + struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); > + unsigned long off = drm_vma_node_start(&obj->vma_node); > + > + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); > + > + seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08lx %p %zd\n", > + etnaviv_obj->flags, is_active(etnaviv_obj) ? 'A' : > 'I', > + etnaviv_obj->read_fence, etnaviv_obj->write_fence, > + obj->name, obj->refcount.refcount.counter, > + off, etnaviv_obj->vaddr, obj->size); > +} > + > +void etnaviv_gem_describe_objects(struct list_head *list, struct seq_file *m) > +{ > + struct etnaviv_gem_object *etnaviv_obj; > + int count = 0; > + size_t size = 0; > + > + list_for_each_entry(etnaviv_obj, list, mm_list) { > + struct drm_gem_object *obj = &etnaviv_obj->base; > + > + seq_puts(m, " "); > + etnaviv_gem_describe(obj, m); > + count++; > + size += obj->size; > + } > + > + seq_printf(m, "Total %d objects, %zu bytes\n", count, size); > +} > +#endif > + > +static void etnaviv_gem_shmem_release(struct etnaviv_gem_object *etnaviv_obj) > +{ > + if (etnaviv_obj->vaddr) > + vunmap(etnaviv_obj->vaddr); > + put_pages(etnaviv_obj); > +} > + > +static const struct etnaviv_gem_ops etnaviv_gem_shmem_ops = { > + .get_pages = etnaviv_gem_shmem_get_pages, > + .release = etnaviv_gem_shmem_release, > +}; > + > +void etnaviv_gem_free_object(struct drm_gem_object *obj) > +{ > + struct drm_device *dev = obj->dev; > + struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); > + struct etnaviv_vram_mapping *mapping, *tmp; > + > + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); > + > + /* object should not be on active list: */ > + WARN_ON(is_active(etnaviv_obj)); > + > + list_del(&etnaviv_obj->mm_list); > + > + list_for_each_entry_safe(mapping, tmp, &etnaviv_obj->vram_list, > + obj_node) > + etnaviv_iommu_unmap_gem(mapping); > + > + drm_gem_free_mmap_offset(obj); > + etnaviv_obj->ops->release(etnaviv_obj); > + reservation_object_fini(&etnaviv_obj->_resv); > + drm_gem_object_release(obj); > + > + kfree(etnaviv_obj); > +} > + > +int etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj) > +{ > + struct etnaviv_drm_private *priv = dev->dev_private; > + struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); > + int ret; > + > + ret = mutex_lock_killable(&dev->struct_mutex); > + if (ret) > + return ret; > + > + list_add_tail(&etnaviv_obj->mm_list, &priv->inactive_list); > + mutex_unlock(&dev->struct_mutex); > + > + return 0; > +} > + > +static int etnaviv_gem_new_impl(struct drm_device *dev, > + u32 size, u32 flags, > + struct drm_gem_object **obj) > +{ > + struct etnaviv_gem_object *etnaviv_obj; > + unsigned sz = sizeof(*etnaviv_obj); > + bool valid = true; > + > + /* validate flags */ > + switch (flags & ETNA_BO_CACHE_MASK) { > + case ETNA_BO_UNCACHED: > + case ETNA_BO_CACHED: > + case ETNA_BO_WC: > + break; > + default: > + valid = false; > + } > + > + if (!valid) { > + dev_err(dev->dev, "invalid cache flag: %x\n", > + (flags & ETNA_BO_CACHE_MASK)); > + return -EINVAL; > + } > + > + etnaviv_obj = kzalloc(sz, GFP_KERNEL); > + if (!etnaviv_obj) > + return -ENOMEM; > + > + etnaviv_obj->flags = flags; > + > + etnaviv_obj->resv = &etnaviv_obj->_resv; > + reservation_object_init(&etnaviv_obj->_resv); > + > + INIT_LIST_HEAD(&etnaviv_obj->submit_entry); > + INIT_LIST_HEAD(&etnaviv_obj->mm_list); > + INIT_LIST_HEAD(&etnaviv_obj->vram_list); > + > + *obj = &etnaviv_obj->base; > + > + return 0; > +} > + > +static struct drm_gem_object *__etnaviv_gem_new(struct drm_device *dev, > + u32 size, u32 flags) > +{ > + struct drm_gem_object *obj = NULL; > + int ret; > + > + size = PAGE_ALIGN(size); > + > + ret = etnaviv_gem_new_impl(dev, size, flags, &obj); > + if (ret) > + goto fail; > + > + to_etnaviv_bo(obj)->ops = &etnaviv_gem_shmem_ops; > + ret = drm_gem_object_init(dev, obj, size); > + if (ret == 0) { > + struct address_space *mapping; > + > + /* > + * Our buffers are kept pinned, so allocating them > + * from the MOVABLE zone is a really bad idea, and > + * conflicts with CMA. See coments above new_inode() > + * why this is required _and_ expected if you're > + * going to pin these pages. > + */ > + mapping = file_inode(obj->filp)->i_mapping; > + mapping_set_gfp_mask(mapping, GFP_HIGHUSER); > + } > + > + if (ret) > + goto fail; > + > + return obj; > + > +fail: > + if (obj) > + drm_gem_object_unreference_unlocked(obj); > + > + return ERR_PTR(ret); > +} > + > +/* convenience method to construct a GEM buffer object, and userspace handle > */ > +int etnaviv_gem_new_handle(struct drm_device *dev, struct drm_file *file, > + u32 size, u32 flags, u32 *handle) > +{ > + struct drm_gem_object *obj; > + int ret; > + > + obj = __etnaviv_gem_new(dev, size, flags); > + if (IS_ERR(obj)) > + return PTR_ERR(obj); > + > + ret = etnaviv_gem_obj_add(dev, obj); > + if (ret < 0) { > + drm_gem_object_unreference_unlocked(obj); > + return ret; > + } > + > + ret = drm_gem_handle_create(file, obj, handle); > + > + /* drop reference from allocate - handle holds it now */ > + drm_gem_object_unreference_unlocked(obj); > + > + return ret; > +} > + > +struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev, > + u32 size, u32 flags) > +{ > + struct drm_gem_object *obj; > + int ret; > + > + obj = __etnaviv_gem_new(dev, size, flags); > + if (IS_ERR(obj)) > + return obj; > + > + ret = etnaviv_gem_obj_add(dev, obj); > + if (ret < 0) { > + drm_gem_object_unreference_unlocked(obj); > + return ERR_PTR(ret); > + } > + > + return obj; > +} > + > +int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags, > + struct etnaviv_gem_object **res) > +{ > + struct drm_gem_object *obj; > + int ret; > + > + ret = etnaviv_gem_new_impl(dev, size, flags, &obj); > + if (ret) > + return ret; > + > + drm_gem_private_object_init(dev, obj, size); > + > + *res = to_etnaviv_bo(obj); > + > + return 0; > +} > + > +struct etnaviv_vram_mapping * > +etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object *obj, > + struct etnaviv_iommu *mmu) > +{ > + struct etnaviv_vram_mapping *mapping; > + > + list_for_each_entry(mapping, &obj->vram_list, obj_node) { > + if (mapping->mmu == mmu) > + return mapping; > + } > + > + return NULL; > +} > + > +struct get_pages_work { > + struct work_struct work; > + struct mm_struct *mm; > + struct task_struct *task; > + struct etnaviv_gem_object *etnaviv_obj; > +}; > + > +static struct page **etnaviv_gem_userptr_do_get_pages( > + struct etnaviv_gem_object *etnaviv_obj, struct mm_struct *mm, struct > task_struct *task) > +{ > + int ret = 0, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT; > + struct page **pvec; > + uintptr_t ptr; > + > + pvec = drm_malloc_ab(npages, sizeof(struct page *)); > + if (!pvec) > + return ERR_PTR(-ENOMEM); > + > + pinned = 0; > + ptr = etnaviv_obj->userptr.ptr; > + > + down_read(&mm->mmap_sem); > + while (pinned < npages) { > + ret = get_user_pages(task, mm, ptr, npages - pinned, > + !etnaviv_obj->userptr.ro, 0, > + pvec + pinned, NULL); > + if (ret < 0) > + break; > + > + ptr += ret * PAGE_SIZE; > + pinned += ret; > + } > + up_read(&mm->mmap_sem); > + > + if (ret < 0) { > + release_pages(pvec, pinned, 0); > + drm_free_large(pvec); > + return ERR_PTR(ret); > + } > + > + return pvec; > +} > + > +static void __etnaviv_gem_userptr_get_pages(struct work_struct *_work) > +{ > + struct get_pages_work *work = container_of(_work, typeof(*work), > work); > + struct etnaviv_gem_object *etnaviv_obj = work->etnaviv_obj; > + struct drm_device *dev = etnaviv_obj->base.dev; > + struct page **pvec; > + > + pvec = etnaviv_gem_userptr_do_get_pages(etnaviv_obj, work->mm, > work->task); > + > + mutex_lock(&dev->struct_mutex); > + if (IS_ERR(pvec)) { > + etnaviv_obj->userptr.work = ERR_CAST(pvec); > + } else { > + etnaviv_obj->userptr.work = NULL; > + etnaviv_obj->pages = pvec; > + } > + > + drm_gem_object_unreference(&etnaviv_obj->base); > + mutex_unlock(&dev->struct_mutex); > + > + mmput(work->mm); > + put_task_struct(work->task); > + kfree(work); > +} > + > +static int etnaviv_gem_userptr_get_pages(struct etnaviv_gem_object > *etnaviv_obj) > +{ > + struct page **pvec = NULL; > + struct get_pages_work *work; > + struct mm_struct *mm; > + int ret, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT; > + > + if (etnaviv_obj->userptr.work) { > + if (IS_ERR(etnaviv_obj->userptr.work)) { > + ret = PTR_ERR(etnaviv_obj->userptr.work); > + etnaviv_obj->userptr.work = NULL; > + } else { > + ret = -EAGAIN; > + } > + return ret; > + } > + > + mm = get_task_mm(etnaviv_obj->userptr.task); > + pinned = 0; > + if (mm == current->mm) { > + pvec = drm_malloc_ab(npages, sizeof(struct page *)); > + if (!pvec) { > + mmput(mm); > + return -ENOMEM; > + } > + > + pinned = __get_user_pages_fast(etnaviv_obj->userptr.ptr, > npages, > + !etnaviv_obj->userptr.ro, > pvec); > + if (pinned < 0) { > + drm_free_large(pvec); > + mmput(mm); > + return pinned; > + } > + > + if (pinned == npages) { > + etnaviv_obj->pages = pvec; > + mmput(mm); > + return 0; > + } > + } > + > + release_pages(pvec, pinned, 0); > + drm_free_large(pvec); > + > + work = kmalloc(sizeof(*work), GFP_KERNEL); > + if (!work) { > + mmput(mm); > + return -ENOMEM; > + } > + > + get_task_struct(current); > + drm_gem_object_reference(&etnaviv_obj->base); > + > + work->mm = mm; > + work->task = current; > + work->etnaviv_obj = etnaviv_obj; > + > + etnaviv_obj->userptr.work = &work->work; > + INIT_WORK(&work->work, __etnaviv_gem_userptr_get_pages); > + > + etnaviv_queue_work(etnaviv_obj->base.dev, &work->work); > + > + return -EAGAIN; > +} > + > +static void etnaviv_gem_userptr_release(struct etnaviv_gem_object > *etnaviv_obj) > +{ > + if (etnaviv_obj->sgt) { > + etnaviv_gem_scatterlist_unmap(etnaviv_obj); > + sg_free_table(etnaviv_obj->sgt); > + kfree(etnaviv_obj->sgt); > + } > + if (etnaviv_obj->pages) { > + int npages = etnaviv_obj->base.size >> PAGE_SHIFT; > + > + release_pages(etnaviv_obj->pages, npages, 0); > + drm_free_large(etnaviv_obj->pages); > + } > + put_task_struct(etnaviv_obj->userptr.task); > +} > + > +static const struct etnaviv_gem_ops etnaviv_gem_userptr_ops = { > + .get_pages = etnaviv_gem_userptr_get_pages, > + .release = etnaviv_gem_userptr_release, > +}; > + > +int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file, > + uintptr_t ptr, u32 size, u32 flags, u32 *handle) > +{ > + struct etnaviv_gem_object *etnaviv_obj; > + int ret; > + > + ret = etnaviv_gem_new_private(dev, size, ETNA_BO_CACHED, > &etnaviv_obj); > + if (ret) > + return ret; > + > + etnaviv_obj->ops = &etnaviv_gem_userptr_ops; > + etnaviv_obj->userptr.ptr = ptr; > + etnaviv_obj->userptr.task = current; > + etnaviv_obj->userptr.ro = !(flags & ETNA_USERPTR_WRITE); > + get_task_struct(current); > + > + ret = etnaviv_gem_obj_add(dev, &etnaviv_obj->base); > + if (ret) { > + drm_gem_object_unreference_unlocked(&etnaviv_obj->base); > + return ret; > + } > + > + ret = drm_gem_handle_create(file, &etnaviv_obj->base, handle); > + > + /* drop reference from allocate - handle holds it now */ > + drm_gem_object_unreference_unlocked(&etnaviv_obj->base); > + > + return ret; > +} > diff --git a/drivers/staging/etnaviv/etnaviv_gem.h > b/drivers/staging/etnaviv/etnaviv_gem.h > new file mode 100644 > index 000000000000..c991d12e7aed > --- /dev/null > +++ b/drivers/staging/etnaviv/etnaviv_gem.h > @@ -0,0 +1,141 @@ > +/* > + * Copyright (C) 2015 Etnaviv Project > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef __ETNAVIV_GEM_H__ > +#define __ETNAVIV_GEM_H__ > + > +#include <linux/reservation.h> > +#include "etnaviv_drv.h" > + > +struct etnaviv_gem_ops; > +struct etnaviv_gem_object; > + > +struct etnaviv_gem_userptr { > + uintptr_t ptr; > + struct task_struct *task; > + struct work_struct *work; > + bool ro; > +}; > + > +struct etnaviv_vram_mapping { > + struct list_head obj_node; > + struct list_head scan_node; > + struct etnaviv_gem_object *object; > + struct etnaviv_iommu *mmu; > + struct drm_mm_node vram_node; > + u32 iova; > +}; > + > +struct etnaviv_gem_object { > + struct drm_gem_object base; > + const struct etnaviv_gem_ops *ops; > + > + u32 flags; > + > + /* And object is either: > + * inactive - on priv->inactive_list > + * active - on one one of the gpu's active_list.. well, at > + * least for now we don't have (I don't think) hw sync between > + * 2d and 3d one devices which have both, meaning we need to > + * block on submit if a bo is already on other ring > + * > + */ > + struct list_head mm_list; > + struct etnaviv_gpu *gpu; /* non-null if active */ > + u32 access; > + u32 read_fence, write_fence; > + > + /* Transiently in the process of submit ioctl, objects associated > + * with the submit are on submit->bo_list.. this only lasts for > + * the duration of the ioctl, so one bo can never be on multiple > + * submit lists. > + */ > + struct list_head submit_entry; > + > + struct page **pages; > + struct sg_table *sgt; > + void *vaddr; > + > + /* for ETNA_BO_CMDSTREAM */ > + dma_addr_t paddr; > + > + /* normally (resv == &_resv) except for imported bo's */ > + struct reservation_object *resv; > + struct reservation_object _resv; > + > + struct list_head vram_list; > + > + /* for buffer manipulation during submit */ > + bool is_ring_buffer; > + u32 offset; > + > + /* cache maintenance */ > + uint32_t last_cpu_prep_op; > + > + struct etnaviv_gem_userptr userptr; > +}; > + > +static inline > +struct etnaviv_gem_object *to_etnaviv_bo(struct drm_gem_object *obj) > +{ > + return container_of(obj, struct etnaviv_gem_object, base); > +} > + > +struct etnaviv_gem_ops { > + int (*get_pages)(struct etnaviv_gem_object *); > + void (*release)(struct etnaviv_gem_object *); > +}; > + > +static inline bool is_active(struct etnaviv_gem_object *etnaviv_obj) > +{ > + return etnaviv_obj->gpu != NULL; > +} > + > +#define MAX_CMDS 4 > + > +/* Created per submit-ioctl, to track bo's and cmdstream bufs, etc, > + * associated with the cmdstream submission for synchronization (and > + * make it easier to unwind when things go wrong, etc). This only > + * lasts for the duration of the submit-ioctl. > + */ > +struct etnaviv_gem_submit { > + struct drm_device *dev; > + struct etnaviv_gpu *gpu; > + u32 exec_state; > + struct list_head bo_list; > + struct ww_acquire_ctx ticket; > + u32 fence; > + unsigned int nr_bos; > + struct etnaviv_cmdbuf *cmdbuf; > + struct { > + u32 flags; > + struct etnaviv_gem_object *obj; > + u32 iova; > + } bos[0]; > +}; > + > +int etnaviv_gem_wait_bo(struct etnaviv_gpu *gpu, struct drm_gem_object *obj, > + struct timespec *timeout); > +struct etnaviv_vram_mapping * > +etnaviv_gem_get_vram_mapping(struct etnaviv_gem_object *obj, > + struct etnaviv_iommu *mmu); > +int etnaviv_gem_new_private(struct drm_device *dev, size_t size, u32 flags, > + struct etnaviv_gem_object **res); > +int etnaviv_gem_obj_add(struct drm_device *dev, struct drm_gem_object *obj); > +struct page **etnaviv_gem_get_pages(struct etnaviv_gem_object *obj); > +void etnaviv_gem_put_pages(struct etnaviv_gem_object *obj); > + > +#endif /* __ETNAVIV_GEM_H__ */ > diff --git a/drivers/staging/etnaviv/etnaviv_gem_prime.c > b/drivers/staging/etnaviv/etnaviv_gem_prime.c > new file mode 100644 > index 000000000000..58c13ae7c345 > --- /dev/null > +++ b/drivers/staging/etnaviv/etnaviv_gem_prime.c > @@ -0,0 +1,121 @@ > +/* > + * Copyright (C) 2013 Red Hat > + * Author: Rob Clark <robdclark at gmail.com> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#include <linux/dma-buf.h> > +#include "etnaviv_drv.h" > +#include "etnaviv_gem.h" > + > + > +struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj) > +{ > + struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); > + > + BUG_ON(!etnaviv_obj->sgt); /* should have already pinned! */ > + > + return etnaviv_obj->sgt; > +} > + > +void *etnaviv_gem_prime_vmap(struct drm_gem_object *obj) > +{ > + return etnaviv_gem_vaddr(obj); > +} > + > +void etnaviv_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) > +{ > + /* TODO msm_gem_vunmap() */ > +} > + > +int etnaviv_gem_prime_pin(struct drm_gem_object *obj) > +{ > + if (!obj->import_attach) { > + struct drm_device *dev = obj->dev; > + > + mutex_lock(&dev->struct_mutex); > + etnaviv_gem_get_pages(to_etnaviv_bo(obj)); > + mutex_unlock(&dev->struct_mutex); > + } > + return 0; > +} > + > +void etnaviv_gem_prime_unpin(struct drm_gem_object *obj) > +{ > + if (!obj->import_attach) { > + struct drm_device *dev = obj->dev; > + > + mutex_lock(&dev->struct_mutex); > + etnaviv_gem_put_pages(to_etnaviv_bo(obj)); > + mutex_unlock(&dev->struct_mutex); > + } > +} > + > +static void etnaviv_gem_prime_release(struct etnaviv_gem_object *etnaviv_obj) > +{ > + if (etnaviv_obj->vaddr) > + dma_buf_vunmap(etnaviv_obj->base.import_attach->dmabuf, > + etnaviv_obj->vaddr); > + > + /* Don't drop the pages for imported dmabuf, as they are not > + * ours, just free the array we allocated: > + */ > + if (etnaviv_obj->pages) > + drm_free_large(etnaviv_obj->pages); > + > + drm_prime_gem_destroy(&etnaviv_obj->base, etnaviv_obj->sgt); > +} > + > +static const struct etnaviv_gem_ops etnaviv_gem_prime_ops = { > + /* .get_pages should never be called */ > + .release = etnaviv_gem_prime_release, > +}; > + > +struct drm_gem_object *etnaviv_gem_prime_import_sg_table(struct drm_device > *dev, > + struct dma_buf_attachment *attach, struct sg_table *sgt) > +{ > + struct etnaviv_gem_object *etnaviv_obj; > + size_t size = PAGE_ALIGN(attach->dmabuf->size); > + int ret, npages; > + > + ret = etnaviv_gem_new_private(dev, size, ETNA_BO_WC, &etnaviv_obj); > + if (ret < 0) > + return ERR_PTR(ret); > + > + npages = size / PAGE_SIZE; > + > + etnaviv_obj->ops = &etnaviv_gem_prime_ops; > + etnaviv_obj->sgt = sgt; > + etnaviv_obj->pages = drm_malloc_ab(npages, sizeof(struct page *)); > + if (!etnaviv_obj->pages) { > + ret = -ENOMEM; > + goto fail; > + } > + > + ret = drm_prime_sg_to_page_addr_arrays(sgt, etnaviv_obj->pages, > + NULL, npages); > + if (ret) > + goto fail; > + > + ret = etnaviv_gem_obj_add(dev, &etnaviv_obj->base); > + if (ret) > + goto fail; > + > + return &etnaviv_obj->base; > + > +fail: > + drm_gem_object_unreference_unlocked(&etnaviv_obj->base); > + > + return ERR_PTR(ret); > +} > diff --git a/drivers/staging/etnaviv/etnaviv_gem_submit.c > b/drivers/staging/etnaviv/etnaviv_gem_submit.c > new file mode 100644 > index 000000000000..f886a3c66d30 > --- /dev/null > +++ b/drivers/staging/etnaviv/etnaviv_gem_submit.c > @@ -0,0 +1,421 @@ > +/* > + * Copyright (C) 2015 Etnaviv Project > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "etnaviv_drv.h" > +#include "etnaviv_gpu.h" > +#include "etnaviv_gem.h" > + > +/* > + * Cmdstream submission: > + */ > + > +#define BO_INVALID_FLAGS ~(ETNA_SUBMIT_BO_READ | ETNA_SUBMIT_BO_WRITE) > +/* make sure these don't conflict w/ ETNAVIV_SUBMIT_BO_x */ > +#define BO_LOCKED 0x4000 > +#define BO_PINNED 0x2000 > + > +static inline void __user *to_user_ptr(u64 address) > +{ > + return (void __user *)(uintptr_t)address; > +} > + > +static struct etnaviv_gem_submit *submit_create(struct drm_device *dev, > + struct etnaviv_gpu *gpu, int nr) > +{ > + struct etnaviv_gem_submit *submit; > + int sz = sizeof(*submit) + (nr * sizeof(submit->bos[0])); > + > + submit = kmalloc(sz, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); > + if (submit) { > + submit->dev = dev; > + submit->gpu = gpu; > + > + /* initially, until copy_from_user() and bo lookup succeeds: > */ > + submit->nr_bos = 0; > + submit->cmdbuf = NULL; > + > + INIT_LIST_HEAD(&submit->bo_list); > + ww_acquire_init(&submit->ticket, &reservation_ww_class); > + } > + > + return submit; > +} > + > +static int submit_lookup_objects(struct etnaviv_gem_submit *submit, > + struct drm_file *file, struct drm_etnaviv_gem_submit_bo *submit_bos, > + unsigned nr_bos) > +{ > + struct drm_etnaviv_gem_submit_bo *bo; > + unsigned i; > + int ret = 0; > + > + spin_lock(&file->table_lock); > + > + for (i = 0, bo = submit_bos; i < nr_bos; i++, bo++) { > + struct drm_gem_object *obj; > + struct etnaviv_gem_object *etnaviv_obj; > + > + if (bo->flags & BO_INVALID_FLAGS) { > + DRM_ERROR("invalid flags: %x\n", bo->flags); > + ret = -EINVAL; > + goto out_unlock; > + } > + > + submit->bos[i].flags = bo->flags; > + > + /* normally use drm_gem_object_lookup(), but for bulk lookup > + * all under single table_lock just hit object_idr directly: > + */ > + obj = idr_find(&file->object_idr, bo->handle); > + if (!obj) { > + DRM_ERROR("invalid handle %u at index %u\n", > + bo->handle, i); > + ret = -EINVAL; > + goto out_unlock; > + } > + > + etnaviv_obj = to_etnaviv_bo(obj); > + > + if (!list_empty(&etnaviv_obj->submit_entry)) { > + DRM_ERROR("handle %u at index %u already on submit > list\n", > + bo->handle, i); > + ret = -EINVAL; > + goto out_unlock; > + } > + > + drm_gem_object_reference(obj); > + > + submit->bos[i].obj = etnaviv_obj; > + > + list_add_tail(&etnaviv_obj->submit_entry, &submit->bo_list); > + } > + > +out_unlock: > + submit->nr_bos = i; > + spin_unlock(&file->table_lock); > + > + return ret; > +} > + > +static void submit_unlock_unpin_bo(struct etnaviv_gem_submit *submit, int i) > +{ > + struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj; > + > + if (submit->bos[i].flags & BO_PINNED) > + etnaviv_gem_put_iova(&etnaviv_obj->base); > + > + if (submit->bos[i].flags & BO_LOCKED) > + ww_mutex_unlock(&etnaviv_obj->resv->lock); > + > + submit->bos[i].iova = 0; > + submit->bos[i].flags &= ~(BO_LOCKED | BO_PINNED); > +} > + > +/* This is where we make sure all the bo's are reserved and pin'd: */ > +static int submit_validate_objects(struct etnaviv_gem_submit *submit) > +{ > + int contended, slow_locked = -1, i, ret = 0; > + > +retry: > + for (i = 0; i < submit->nr_bos; i++) { > + struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj; > + u32 iova; > + > + if (slow_locked == i) > + slow_locked = -1; > + > + contended = i; > + > + if (!(submit->bos[i].flags & BO_LOCKED)) { > + ret = > ww_mutex_lock_interruptible(&etnaviv_obj->resv->lock, > + &submit->ticket); > + if (ret) > + goto fail; > + submit->bos[i].flags |= BO_LOCKED; > + } > + > + > + /* if locking succeeded, pin bo: */ > + ret = etnaviv_gem_get_iova_locked(submit->gpu, > + &etnaviv_obj->base, &iova); > + > + /* this would break the logic in the fail path.. there is no > + * reason for this to happen, but just to be on the safe side > + * let's notice if this starts happening in the future: > + */ > + WARN_ON(ret == -EDEADLK); > + > + if (ret) > + goto fail; > + > + submit->bos[i].flags |= BO_PINNED; > + submit->bos[i].iova = iova; > + } > + > + ww_acquire_done(&submit->ticket); > + > + return 0; > + > +fail: > + for (; i >= 0; i--) > + submit_unlock_unpin_bo(submit, i); > + > + if (slow_locked > 0) > + submit_unlock_unpin_bo(submit, slow_locked); > + > + if (ret == -EDEADLK) { > + struct etnaviv_gem_object *etnaviv_obj; > + > + etnaviv_obj = submit->bos[contended].obj; > + > + /* we lost out in a seqno race, lock and retry.. */ > + ret = > ww_mutex_lock_slow_interruptible(&etnaviv_obj->resv->lock, > + &submit->ticket); > + if (!ret) { > + submit->bos[contended].flags |= BO_LOCKED; > + slow_locked = contended; > + goto retry; > + } > + } > + > + return ret; > +} > + > +static int submit_bo(struct etnaviv_gem_submit *submit, u32 idx, > + struct etnaviv_gem_object **obj, u32 *iova) > +{ > + if (idx >= submit->nr_bos) { > + DRM_ERROR("invalid buffer index: %u (out of %u)\n", > + idx, submit->nr_bos); > + return -EINVAL; > + } > + > + if (obj) > + *obj = submit->bos[idx].obj; > + if (iova) > + *iova = submit->bos[idx].iova; > + > + return 0; > +} > + > +/* process the reloc's and patch up the cmdstream as needed: */ > +static int submit_reloc(struct etnaviv_gem_submit *submit, void *stream, > + u32 size, u32 nr_relocs, u64 relocs) > +{ > + u32 i, last_offset = 0; > + u32 *ptr = stream; > + int ret; > + > + for (i = 0; i < nr_relocs; i++) { > + struct drm_etnaviv_gem_submit_reloc submit_reloc; > + struct etnaviv_gem_object *bobj; > + void __user *userptr = > + to_user_ptr(relocs + (i * sizeof(submit_reloc))); > + u32 iova, off; > + > + ret = copy_from_user(&submit_reloc, userptr, > + sizeof(submit_reloc)); > + if (ret) > + return -EFAULT; > + > + if (submit_reloc.submit_offset % 4) { > + DRM_ERROR("non-aligned reloc offset: %u\n", > + submit_reloc.submit_offset); > + return -EINVAL; > + } > + > + /* offset in dwords: */ > + off = submit_reloc.submit_offset / 4; > + > + if ((off >= size ) || > + (off < last_offset)) { > + DRM_ERROR("invalid offset %u at reloc %u\n", off, i); > + return -EINVAL; > + } > + > + ret = submit_bo(submit, submit_reloc.reloc_idx, &bobj, &iova); > + if (ret) > + return ret; > + > + if (submit_reloc.reloc_offset >= > + bobj->base.size - sizeof(*ptr)) { > + DRM_ERROR("relocation %u outside object", i); > + return -EINVAL; > + } > + > + ptr[off] = iova + submit_reloc.reloc_offset; > + > + last_offset = off; > + } > + > + return 0; > +} > + > +static void submit_cleanup(struct etnaviv_gem_submit *submit, bool fail) > +{ > + unsigned i; > + > + for (i = 0; i < submit->nr_bos; i++) { > + struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj; > + > + submit_unlock_unpin_bo(submit, i); > + list_del_init(&etnaviv_obj->submit_entry); > + drm_gem_object_unreference(&etnaviv_obj->base); > + } > + > + if (submit->cmdbuf) > + etnaviv_gpu_cmdbuf_free(submit->cmdbuf); > + > + ww_acquire_fini(&submit->ticket); > + kfree(submit); > +} > + > +int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, > + struct drm_file *file) > +{ > + struct etnaviv_drm_private *priv = dev->dev_private; > + struct drm_etnaviv_gem_submit *args = data; > + struct etnaviv_file_private *ctx = file->driver_priv; > + struct drm_etnaviv_gem_submit_bo *bos; > + struct etnaviv_gem_submit *submit; > + struct etnaviv_cmdbuf *cmdbuf; > + struct etnaviv_gpu *gpu; > + void *stream; > + int ret; > + > + if (args->pipe >= ETNA_MAX_PIPES) > + return -EINVAL; > + > + gpu = priv->gpu[args->pipe]; > + if (!gpu) > + return -ENXIO; > + > + if (args->stream_size % 4) { > + DRM_ERROR("non-aligned cmdstream buffer size: %u\n", > + args->stream_size); > + return -EINVAL; > + } > + > + /* > + * Copy the command submission and bo array to kernel space in > + * one go, and do this outside of the dev->struct_mutex lock. > + */ > + bos = drm_malloc_ab(args->nr_bos, sizeof(*bos)); > + stream = drm_malloc_ab(1, args->stream_size); > + cmdbuf = etnaviv_gpu_cmdbuf_new(gpu, ALIGN(args->stream_size, 8) + 8); > + if (!bos || !stream || !cmdbuf) { > + ret = -ENOMEM; > + goto err_submit_cmds; > + } > + > + ret = copy_from_user(bos, to_user_ptr(args->bos), > + args->nr_bos * sizeof(*bos)); > + if (ret) { > + ret = -EFAULT; > + goto err_submit_cmds; > + } > + > + ret = copy_from_user(stream, to_user_ptr(args->stream), > + args->stream_size); > + if (ret) { > + ret = -EFAULT; > + goto err_submit_cmds; > + } > + > + /* > + * Avoid big circular locking dependency loops: > + * - reading debugfs results in mmap_sem depending on i_mutex_key#3 > + * (iterate_dir -> filldir64) > + * - struct_mutex depends on mmap_sem > + * (vm_mmap_pgoff -> drm_gem_mmap) > + * then if we try to do a get_sync() under struct_mutex, > + * - genpd->lock depends on struct_mutex > + * (etnaviv_ioctl_gem_submit -> pm_genpd_runtime_resume) > + * - (regulator) rdev->mutex depends on genpd->lock > + * (pm_genpd_poweron -> regulator_enable) > + * - i_mutex_key#3 depends on rdev->mutex > + * (create_regulator -> debugfs::start_creating) > + * and lockdep rightfully explodes. > + * > + * Avoid this by getting runtime PM outside of the struct_mutex lock. > + */ > + ret = etnaviv_gpu_pm_get_sync(gpu); > + if (ret < 0) > + goto err_submit_cmds; > + > + mutex_lock(&dev->struct_mutex); > + > + submit = submit_create(dev, gpu, args->nr_bos); > + if (!submit) { > + ret = -ENOMEM; > + goto out; > + } > + submit->exec_state = args->exec_state; > + > + ret = submit_lookup_objects(submit, file, bos, args->nr_bos); > + if (ret) > + goto out; > + > + ret = submit_validate_objects(submit); > + if (ret) > + goto out; > + > + if (!etnaviv_cmd_validate_one(gpu, stream, args->stream_size / 4)) { > + ret = -EINVAL; > + goto out; > + } > + > + ret = submit_reloc(submit, stream, args->stream_size / 4, > + args->nr_relocs, args->relocs); > + if (ret) > + goto out; > + > + memcpy(cmdbuf->vaddr, stream, args->stream_size); > + cmdbuf->user_size = ALIGN(args->stream_size, 8); > + /* transfer ownership of cmdbuf to submit */ > + submit->cmdbuf = cmdbuf; > + cmdbuf = NULL; > + > + ret = etnaviv_gpu_submit(gpu, submit, ctx); > + > + args->fence = submit->fence; > + > +out: > + if (submit) > + submit_cleanup(submit, !!ret); > + mutex_unlock(&dev->struct_mutex); > + > + etnaviv_gpu_pm_put(gpu); > + > + /* > + * If we're returning -EAGAIN, it could be due to the userptr code > + * wanting to run its workqueue outside of the struct_mutex. > + * Flush our workqueue to ensure that it is run in a timely manner. > + */ > + if (ret == -EAGAIN) > + flush_workqueue(priv->wq); > + > +err_submit_cmds: > + /* if we still own the cmdbuf */ > + if (cmdbuf) > + etnaviv_gpu_cmdbuf_free(cmdbuf); > + if (stream) > + drm_free_large(stream); > + if (bos) > + drm_free_large(bos); > + > + return ret; > +} > diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c > b/drivers/staging/etnaviv/etnaviv_gpu.c > new file mode 100644 > index 000000000000..e12fe3508db2 > --- /dev/null > +++ b/drivers/staging/etnaviv/etnaviv_gpu.c > @@ -0,0 +1,1468 @@ > +/* > + * Copyright (C) 2015 Etnaviv Project > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#include <linux/component.h> > +#include <linux/of_device.h> > +#include "etnaviv_gpu.h" > +#include "etnaviv_gem.h" > +#include "etnaviv_mmu.h" > +#include "etnaviv_iommu.h" > +#include "etnaviv_iommu_v2.h" > +#include "common.xml.h" > +#include "state.xml.h" > +#include "state_hi.xml.h" > +#include "cmdstream.xml.h" > + > +static const struct platform_device_id gpu_ids[] = { > + { .name = "etnaviv-gpu,2d" }, > + { }, > +}; > + > +/* > + * Driver functions: > + */ > + > +int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value) > +{ > + switch (param) { > + case ETNAVIV_PARAM_GPU_MODEL: > + *value = gpu->identity.model; > + break; > + > + case ETNAVIV_PARAM_GPU_REVISION: > + *value = gpu->identity.revision; > + break; > + > + case ETNAVIV_PARAM_GPU_FEATURES_0: > + *value = gpu->identity.features; > + break; > + > + case ETNAVIV_PARAM_GPU_FEATURES_1: > + *value = gpu->identity.minor_features0; > + break; > + > + case ETNAVIV_PARAM_GPU_FEATURES_2: > + *value = gpu->identity.minor_features1; > + break; > + > + case ETNAVIV_PARAM_GPU_FEATURES_3: > + *value = gpu->identity.minor_features2; > + break; > + > + case ETNAVIV_PARAM_GPU_FEATURES_4: > + *value = gpu->identity.minor_features3; > + break; > + > + case ETNAVIV_PARAM_GPU_STREAM_COUNT: > + *value = gpu->identity.stream_count; > + break; > + > + case ETNAVIV_PARAM_GPU_REGISTER_MAX: > + *value = gpu->identity.register_max; > + break; > + > + case ETNAVIV_PARAM_GPU_THREAD_COUNT: > + *value = gpu->identity.thread_count; > + break; > + > + case ETNAVIV_PARAM_GPU_VERTEX_CACHE_SIZE: > + *value = gpu->identity.vertex_cache_size; > + break; > + > + case ETNAVIV_PARAM_GPU_SHADER_CORE_COUNT: > + *value = gpu->identity.shader_core_count; > + break; > + > + case ETNAVIV_PARAM_GPU_PIXEL_PIPES: > + *value = gpu->identity.pixel_pipes; > + break; > + > + case ETNAVIV_PARAM_GPU_VERTEX_OUTPUT_BUFFER_SIZE: > + *value = gpu->identity.vertex_output_buffer_size; > + break; > + > + case ETNAVIV_PARAM_GPU_BUFFER_SIZE: > + *value = gpu->identity.buffer_size; > + break; > + > + case ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT: > + *value = gpu->identity.instruction_count; > + break; > + > + case ETNAVIV_PARAM_GPU_NUM_CONSTANTS: > + *value = gpu->identity.num_constants; > + break; > + > + default: > + DBG("%s: invalid param: %u", dev_name(gpu->dev), param); > + return -EINVAL; > + } > + > + return 0; > +} > + > +static void etnaviv_hw_specs(struct etnaviv_gpu *gpu) > +{ > + if (gpu->identity.minor_features0 & > + chipMinorFeatures0_MORE_MINOR_FEATURES) { > + u32 specs[2]; > + > + specs[0] = gpu_read(gpu, VIVS_HI_CHIP_SPECS); > + specs[1] = gpu_read(gpu, VIVS_HI_CHIP_SPECS_2); > + > + gpu->identity.stream_count = > + (specs[0] & VIVS_HI_CHIP_SPECS_STREAM_COUNT__MASK) > + >> VIVS_HI_CHIP_SPECS_STREAM_COUNT__SHIFT; > + gpu->identity.register_max = > + (specs[0] & VIVS_HI_CHIP_SPECS_REGISTER_MAX__MASK) > + >> VIVS_HI_CHIP_SPECS_REGISTER_MAX__SHIFT; > + gpu->identity.thread_count = > + (specs[0] & VIVS_HI_CHIP_SPECS_THREAD_COUNT__MASK) > + >> VIVS_HI_CHIP_SPECS_THREAD_COUNT__SHIFT; > + gpu->identity.vertex_cache_size = > + (specs[0] & > VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__MASK) > + >> > VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__SHIFT; > + gpu->identity.shader_core_count = > + (specs[0] & > VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__MASK) > + >> > VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__SHIFT; > + gpu->identity.pixel_pipes = > + (specs[0] & VIVS_HI_CHIP_SPECS_PIXEL_PIPES__MASK) > + >> VIVS_HI_CHIP_SPECS_PIXEL_PIPES__SHIFT; > + gpu->identity.vertex_output_buffer_size = > + (specs[0] & > VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__MASK) > + >> > VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__SHIFT; > + > + gpu->identity.buffer_size = > + (specs[1] & VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__MASK) > + >> VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__SHIFT; > + gpu->identity.instruction_count = > + (specs[1] & > VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__MASK) > + >> > VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__SHIFT; > + gpu->identity.num_constants = > + (specs[1] & VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__MASK) > + >> VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__SHIFT; > + > + gpu->identity.register_max = 1 << gpu->identity.register_max; > + gpu->identity.thread_count = 1 << gpu->identity.thread_count; > + gpu->identity.vertex_output_buffer_size = > + 1 << gpu->identity.vertex_output_buffer_size; > + } else { > + dev_err(gpu->dev, "TODO: determine GPU specs based on > model\n"); > + } > + > + switch (gpu->identity.instruction_count) { > + case 0: > + if ((gpu->identity.model == 0x2000 && > + gpu->identity.revision == 0x5108) || > + gpu->identity.model == 0x880) > + gpu->identity.instruction_count = 512; > + else > + gpu->identity.instruction_count = 256; > + break; > + > + case 1: > + gpu->identity.instruction_count = 1024; > + break; > + > + case 2: > + gpu->identity.instruction_count = 2048; > + break; > + > + default: > + gpu->identity.instruction_count = 256; > + break; > + } > +} > + > +static void etnaviv_hw_identify(struct etnaviv_gpu *gpu) > +{ > + u32 chipIdentity; > + > + chipIdentity = gpu_read(gpu, VIVS_HI_CHIP_IDENTITY); > + > + /* Special case for older graphic cores. */ > + if (VIVS_HI_CHIP_IDENTITY_FAMILY(chipIdentity) == 0x01) { > + gpu->identity.model = 0x500; /* gc500 */ > + gpu->identity.revision = > VIVS_HI_CHIP_IDENTITY_REVISION(chipIdentity); > + } else { > + > + gpu->identity.model = gpu_read(gpu, VIVS_HI_CHIP_MODEL); > + gpu->identity.revision = gpu_read(gpu, VIVS_HI_CHIP_REV); > + > + /* > + * !!!! HACK ALERT !!!! > + * Because people change device IDs without letting software > + * know about it - here is the hack to make it all look the > + * same. Only for GC400 family. > + */ > + if ((gpu->identity.model & 0xff00) == 0x0400 && > + gpu->identity.model != 0x0420) { > + gpu->identity.model = gpu->identity.model & 0x0400; > + } > + > + /* Another special case */ > + if (gpu->identity.model == 0x300 && > + gpu->identity.revision == 0x2201) { > + u32 chipDate = gpu_read(gpu, VIVS_HI_CHIP_DATE); > + u32 chipTime = gpu_read(gpu, VIVS_HI_CHIP_TIME); > + > + if (chipDate == 0x20080814 && chipTime == 0x12051100) > { > + /* > + * This IP has an ECO; put the correct > + * revision in it. > + */ > + gpu->identity.revision = 0x1051; > + } > + } > + } > + > + dev_info(gpu->dev, "model: GC%x, revision: %x\n", > + gpu->identity.model, gpu->identity.revision); > + > + gpu->identity.features = gpu_read(gpu, VIVS_HI_CHIP_FEATURE); > + > + /* Disable fast clear on GC700. */ > + if (gpu->identity.model == 0x700) > + gpu->identity.features &= ~chipFeatures_FAST_CLEAR; > + > + if ((gpu->identity.model == 0x500 && gpu->identity.revision < 2) || > + (gpu->identity.model == 0x300 && gpu->identity.revision < > 0x2000)) { > + > + /* > + * GC500 rev 1.x and GC300 rev < 2.0 doesn't have these > + * registers. > + */ > + gpu->identity.minor_features0 = 0; > + gpu->identity.minor_features1 = 0; > + gpu->identity.minor_features2 = 0; > + gpu->identity.minor_features3 = 0; > + } else > + gpu->identity.minor_features0 = > + gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_0); > + > + if (gpu->identity.minor_features0 & > + chipMinorFeatures0_MORE_MINOR_FEATURES) { > + gpu->identity.minor_features1 = > + gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_1); > + gpu->identity.minor_features2 = > + gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_2); > + gpu->identity.minor_features3 = > + gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_3); > + } > + > + /* GC600 idle register reports zero bits where modules aren't present > */ > + if (gpu->identity.model == chipModel_GC600) { > + gpu->idle_mask = VIVS_HI_IDLE_STATE_TX | > + VIVS_HI_IDLE_STATE_RA | > + VIVS_HI_IDLE_STATE_SE | > + VIVS_HI_IDLE_STATE_PA | > + VIVS_HI_IDLE_STATE_SH | > + VIVS_HI_IDLE_STATE_PE | > + VIVS_HI_IDLE_STATE_DE | > + VIVS_HI_IDLE_STATE_FE; > + } else { > + gpu->idle_mask = ~VIVS_HI_IDLE_STATE_AXI_LP; > + } > + > + etnaviv_hw_specs(gpu); > +} > + > +static void etnaviv_gpu_load_clock(struct etnaviv_gpu *gpu, u32 clock) > +{ > + gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock | > + VIVS_HI_CLOCK_CONTROL_FSCALE_CMD_LOAD); > + gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock); > +} > + > +static int etnaviv_hw_reset(struct etnaviv_gpu *gpu) > +{ > + u32 control, idle; > + unsigned long timeout; > + bool failed = true; > + > + /* TODO > + * > + * - clock gating > + * - puls eater > + * - what about VG? > + */ > + > + /* We hope that the GPU resets in under one second */ > + timeout = jiffies + msecs_to_jiffies(1000); > + > + while (time_is_after_jiffies(timeout)) { > + control = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS | > + VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40); > + > + /* enable clock */ > + etnaviv_gpu_load_clock(gpu, control); > + > + /* Wait for stable clock. Vivante's code waited for 1ms */ > + usleep_range(1000, 10000); > + > + /* isolate the GPU. */ > + control |= VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU; > + gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); > + > + /* set soft reset. */ > + control |= VIVS_HI_CLOCK_CONTROL_SOFT_RESET; > + gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); > + > + /* wait for reset. */ > + msleep(1); > + > + /* reset soft reset bit. */ > + control &= ~VIVS_HI_CLOCK_CONTROL_SOFT_RESET; > + gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); > + > + /* reset GPU isolation. */ > + control &= ~VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU; > + gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); > + > + /* read idle register. */ > + idle = gpu_read(gpu, VIVS_HI_IDLE_STATE); > + > + /* try reseting again if FE it not idle */ > + if ((idle & VIVS_HI_IDLE_STATE_FE) == 0) { > + dev_dbg(gpu->dev, "FE is not idle\n"); > + continue; > + } > + > + /* read reset register. */ > + control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL); > + > + /* is the GPU idle? */ > + if (((control & VIVS_HI_CLOCK_CONTROL_IDLE_3D) == 0) || > + ((control & VIVS_HI_CLOCK_CONTROL_IDLE_2D) == 0)) { > + dev_dbg(gpu->dev, "GPU is not idle\n"); > + continue; > + } > + > + failed = false; > + break; > + } > + > + if (failed) { > + idle = gpu_read(gpu, VIVS_HI_IDLE_STATE); > + control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL); > + > + dev_err(gpu->dev, "GPU failed to reset: FE %sidle, 3D %sidle, > 2D %sidle\n", > + idle & VIVS_HI_IDLE_STATE_FE ? "" : "not ", > + control & VIVS_HI_CLOCK_CONTROL_IDLE_3D ? "" : "not ", > + control & VIVS_HI_CLOCK_CONTROL_IDLE_2D ? "" : "not > "); > + > + return -EBUSY; > + } > + > + /* We rely on the GPU running, so program the clock */ > + control = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS | > + VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40); > + > + /* enable clock */ > + etnaviv_gpu_load_clock(gpu, control); > + > + return 0; > +} > + > +static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu) > +{ > + u16 prefetch; > + > + if (gpu->identity.model == chipModel_GC320 && > + gpu_read(gpu, VIVS_HI_CHIP_TIME) != 0x2062400 && > + (gpu->identity.revision == 0x5007 || > + gpu->identity.revision == 0x5220)) { > + u32 mc_memory_debug; > + > + mc_memory_debug = gpu_read(gpu, VIVS_MC_DEBUG_MEMORY) & ~0xff; > + > + if (gpu->identity.revision == 0x5007) > + mc_memory_debug |= 0x0c; > + else > + mc_memory_debug |= 0x08; > + > + gpu_write(gpu, VIVS_MC_DEBUG_MEMORY, mc_memory_debug); > + } > + > + /* > + * Update GPU AXI cache atttribute to "cacheable, no allocate". > + * This is necessary to prevent the iMX6 SoC locking up. > + */ > + gpu_write(gpu, VIVS_HI_AXI_CONFIG, > + VIVS_HI_AXI_CONFIG_AWCACHE(2) | > + VIVS_HI_AXI_CONFIG_ARCACHE(2)); > + > + /* GC2000 rev 5108 needs a special bus config */ > + if (gpu->identity.model == 0x2000 && gpu->identity.revision == > 0x5108) { > + u32 bus_config = gpu_read(gpu, VIVS_MC_BUS_CONFIG); > + bus_config &= ~(VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK | > + VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK); > + bus_config |= VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG(1) | > + VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG(0); > + gpu_write(gpu, VIVS_MC_BUS_CONFIG, bus_config); > + } > + > + /* set base addresses */ > + gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_RA, gpu->memory_base); > + gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_FE, gpu->memory_base); > + gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_TX, gpu->memory_base); > + gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PEZ, gpu->memory_base); > + gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PE, gpu->memory_base); > + > + /* setup the MMU page table pointers */ > + etnaviv_iommu_domain_restore(gpu, gpu->mmu->domain); > + > + /* Start command processor */ > + prefetch = etnaviv_buffer_init(gpu); > + > + gpu_write(gpu, VIVS_HI_INTR_ENBL, ~0U); > + gpu_write(gpu, VIVS_FE_COMMAND_ADDRESS, > + gpu->buffer->paddr - gpu->memory_base); > + gpu_write(gpu, VIVS_FE_COMMAND_CONTROL, > + VIVS_FE_COMMAND_CONTROL_ENABLE | > + VIVS_FE_COMMAND_CONTROL_PREFETCH(prefetch)); > +} > + > +int etnaviv_gpu_init(struct etnaviv_gpu *gpu) > +{ > + int ret, i; > + struct iommu_domain *iommu; > + enum etnaviv_iommu_version version; > + bool mmuv2; > + > + ret = pm_runtime_get_sync(gpu->dev); > + if (ret < 0) > + return ret; > + > + etnaviv_hw_identify(gpu); > + > + if (gpu->identity.model == 0) { > + dev_err(gpu->dev, "Unknown GPU model\n"); > + pm_runtime_put_autosuspend(gpu->dev); > + return -ENXIO; > + } > + > + ret = etnaviv_hw_reset(gpu); > + if (ret) > + goto fail; > + > + /* Setup IOMMU.. eventually we will (I think) do this once per context > + * and have separate page tables per context. For now, to keep things > + * simple and to get something working, just use a single address > space: > + */ > + mmuv2 = gpu->identity.minor_features1 & > chipMinorFeatures1_MMU_VERSION; > + dev_dbg(gpu->dev, "mmuv2: %d\n", mmuv2); > + > + if (!mmuv2) { > + iommu = etnaviv_iommu_domain_alloc(gpu); > + version = ETNAVIV_IOMMU_V1; > + } else { > + iommu = etnaviv_iommu_v2_domain_alloc(gpu); > + version = ETNAVIV_IOMMU_V2; > + } > + > + if (!iommu) { > + ret = -ENOMEM; > + goto fail; > + } > + > + /* TODO: we will leak here memory - fix it! */ > + > + gpu->mmu = etnaviv_iommu_new(gpu->dev, iommu, version); > + if (!gpu->mmu) { > + ret = -ENOMEM; > + goto fail; > + } > + > + /* Create buffer: */ > + gpu->buffer = etnaviv_gpu_cmdbuf_new(gpu, PAGE_SIZE); > + if (!gpu->buffer) { > + ret = -ENOMEM; > + dev_err(gpu->dev, "could not create command buffer\n"); > + goto fail; > + } > + > + /* Setup event management */ > + spin_lock_init(&gpu->event_spinlock); > + init_completion(&gpu->event_free); > + for (i = 0; i < ARRAY_SIZE(gpu->event); i++) { > + gpu->event[i].used = false; > + complete(&gpu->event_free); > + } > + > + /* Now program the hardware */ > + mutex_lock(&gpu->drm->struct_mutex); > + etnaviv_gpu_hw_init(gpu); > + mutex_unlock(&gpu->drm->struct_mutex); > + > + pm_runtime_mark_last_busy(gpu->dev); > + pm_runtime_put_autosuspend(gpu->dev); > + > + return 0; > + > +fail: > + pm_runtime_mark_last_busy(gpu->dev); > + pm_runtime_put_autosuspend(gpu->dev); > + > + return ret; > +} > + > +#ifdef CONFIG_DEBUG_FS > +struct dma_debug { > + u32 address[2]; > + u32 state[2]; > +}; > + > +static void verify_dma(struct etnaviv_gpu *gpu, struct dma_debug *debug) > +{ > + u32 i; > + > + debug->address[0] = gpu_read(gpu, VIVS_FE_DMA_ADDRESS); > + debug->state[0] = gpu_read(gpu, VIVS_FE_DMA_DEBUG_STATE); > + > + for (i = 0; i < 500; i++) { > + debug->address[1] = gpu_read(gpu, VIVS_FE_DMA_ADDRESS); > + debug->state[1] = gpu_read(gpu, VIVS_FE_DMA_DEBUG_STATE); > + > + if (debug->address[0] != debug->address[1]) > + break; > + > + if (debug->state[0] != debug->state[1]) > + break; > + } > +} > + > +int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m) > +{ > + struct dma_debug debug; > + u32 dma_lo, dma_hi, axi, idle; > + int ret; > + > + seq_printf(m, "%s Status:\n", dev_name(gpu->dev)); > + > + ret = pm_runtime_get_sync(gpu->dev); > + if (ret < 0) > + return ret; > + > + ret = mutex_lock_interruptible(&gpu->drm->struct_mutex); > + if (ret < 0) > + goto err_rpm; > + > + dma_lo = gpu_read(gpu, VIVS_FE_DMA_LOW); > + dma_hi = gpu_read(gpu, VIVS_FE_DMA_HIGH); > + axi = gpu_read(gpu, VIVS_HI_AXI_STATUS); > + idle = gpu_read(gpu, VIVS_HI_IDLE_STATE); > + > + verify_dma(gpu, &debug); > + > + seq_puts(m, "\tfeatures\n"); > + seq_printf(m, "\t minor_features0: 0x%08x\n", > + gpu->identity.minor_features0); > + seq_printf(m, "\t minor_features1: 0x%08x\n", > + gpu->identity.minor_features1); > + seq_printf(m, "\t minor_features2: 0x%08x\n", > + gpu->identity.minor_features2); > + seq_printf(m, "\t minor_features3: 0x%08x\n", > + gpu->identity.minor_features3); > + > + seq_puts(m, "\tspecs\n"); > + seq_printf(m, "\t stream_count: %d\n", > + gpu->identity.stream_count); > + seq_printf(m, "\t register_max: %d\n", > + gpu->identity.register_max); > + seq_printf(m, "\t thread_count: %d\n", > + gpu->identity.thread_count); > + seq_printf(m, "\t vertex_cache_size: %d\n", > + gpu->identity.vertex_cache_size); > + seq_printf(m, "\t shader_core_count: %d\n", > + gpu->identity.shader_core_count); > + seq_printf(m, "\t pixel_pipes: %d\n", > + gpu->identity.pixel_pipes); > + seq_printf(m, "\t vertex_output_buffer_size: %d\n", > + gpu->identity.vertex_output_buffer_size); > + seq_printf(m, "\t buffer_size: %d\n", > + gpu->identity.buffer_size); > + seq_printf(m, "\t instruction_count: %d\n", > + gpu->identity.instruction_count); > + seq_printf(m, "\t num_constants: %d\n", > + gpu->identity.num_constants); > + > + seq_printf(m, "\taxi: 0x%08x\n", axi); > + seq_printf(m, "\tidle: 0x%08x\n", idle); > + idle |= ~gpu->idle_mask & ~VIVS_HI_IDLE_STATE_AXI_LP; > + if ((idle & VIVS_HI_IDLE_STATE_FE) == 0) > + seq_puts(m, "\t FE is not idle\n"); > + if ((idle & VIVS_HI_IDLE_STATE_DE) == 0) > + seq_puts(m, "\t DE is not idle\n"); > + if ((idle & VIVS_HI_IDLE_STATE_PE) == 0) > + seq_puts(m, "\t PE is not idle\n"); > + if ((idle & VIVS_HI_IDLE_STATE_SH) == 0) > + seq_puts(m, "\t SH is not idle\n"); > + if ((idle & VIVS_HI_IDLE_STATE_PA) == 0) > + seq_puts(m, "\t PA is not idle\n"); > + if ((idle & VIVS_HI_IDLE_STATE_SE) == 0) > + seq_puts(m, "\t SE is not idle\n"); > + if ((idle & VIVS_HI_IDLE_STATE_RA) == 0) > + seq_puts(m, "\t RA is not idle\n"); > + if ((idle & VIVS_HI_IDLE_STATE_TX) == 0) > + seq_puts(m, "\t TX is not idle\n"); > + if ((idle & VIVS_HI_IDLE_STATE_VG) == 0) > + seq_puts(m, "\t VG is not idle\n"); > + if ((idle & VIVS_HI_IDLE_STATE_IM) == 0) > + seq_puts(m, "\t IM is not idle\n"); > + if ((idle & VIVS_HI_IDLE_STATE_FP) == 0) > + seq_puts(m, "\t FP is not idle\n"); > + if ((idle & VIVS_HI_IDLE_STATE_TS) == 0) > + seq_puts(m, "\t TS is not idle\n"); > + if (idle & VIVS_HI_IDLE_STATE_AXI_LP) > + seq_puts(m, "\t AXI low power mode\n"); > + > + if (gpu->identity.features & chipFeatures_DEBUG_MODE) { > + u32 read0 = gpu_read(gpu, VIVS_MC_DEBUG_READ0); > + u32 read1 = gpu_read(gpu, VIVS_MC_DEBUG_READ1); > + u32 write = gpu_read(gpu, VIVS_MC_DEBUG_WRITE); > + > + seq_puts(m, "\tMC\n"); > + seq_printf(m, "\t read0: 0x%08x\n", read0); > + seq_printf(m, "\t read1: 0x%08x\n", read1); > + seq_printf(m, "\t write: 0x%08x\n", write); > + } > + > + seq_puts(m, "\tDMA "); > + > + if (debug.address[0] == debug.address[1] && > + debug.state[0] == debug.state[1]) { > + seq_puts(m, "seems to be stuck\n"); > + } else if (debug.address[0] == debug.address[1]) { > + seq_puts(m, "adress is constant\n"); > + } else { > + seq_puts(m, "is runing\n"); > + } > + > + seq_printf(m, "\t address 0: 0x%08x\n", debug.address[0]); > + seq_printf(m, "\t address 1: 0x%08x\n", debug.address[1]); > + seq_printf(m, "\t state 0: 0x%08x\n", debug.state[0]); > + seq_printf(m, "\t state 1: 0x%08x\n", debug.state[1]); > + seq_printf(m, "\t last fetch 64 bit word: 0x%08x 0x%08x\n", > + dma_lo, dma_hi); > + > + ret = 0; > + > + mutex_unlock(&gpu->drm->struct_mutex); > + > +err_rpm: > + pm_runtime_mark_last_busy(gpu->dev); > + pm_runtime_put_autosuspend(gpu->dev); > + > + return ret; > +} > +#endif > + > +/* > + * Power Management: > + */ > +static int enable_clk(struct etnaviv_gpu *gpu) > +{ > + if (gpu->clk_core) > + clk_prepare_enable(gpu->clk_core); > + if (gpu->clk_shader) > + clk_prepare_enable(gpu->clk_shader); > + > + return 0; > +} > + > +static int disable_clk(struct etnaviv_gpu *gpu) > +{ > + if (gpu->clk_core) > + clk_disable_unprepare(gpu->clk_core); > + if (gpu->clk_shader) > + clk_disable_unprepare(gpu->clk_shader); > + > + return 0; > +} > + > +static int enable_axi(struct etnaviv_gpu *gpu) > +{ > + if (gpu->clk_bus) > + clk_prepare_enable(gpu->clk_bus); > + > + return 0; > +} > + > +static int disable_axi(struct etnaviv_gpu *gpu) > +{ > + if (gpu->clk_bus) > + clk_disable_unprepare(gpu->clk_bus); > + > + return 0; > +} > + > +/* > + * Hangcheck detection for locked gpu: > + */ > +static void recover_worker(struct work_struct *work) > +{ > + struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu, > + recover_work); > + struct drm_device *dev = gpu->drm; > + unsigned long flags; > + unsigned int i; > + > + dev_err(gpu->dev, "hangcheck recover!\n"); > + > + if (pm_runtime_get_sync(gpu->dev) < 0) > + return; > + > + mutex_lock(&dev->struct_mutex); > + > + etnaviv_hw_reset(gpu); > + > + /* complete all events, the GPU won't do it after the reset */ > + spin_lock_irqsave(&gpu->event_spinlock, flags); > + for (i = 0; i < ARRAY_SIZE(gpu->event); i++) { > + if (!gpu->event[i].used) > + continue; > + gpu->event[i].used = false; > + complete(&gpu->event_free); > + /* > + * Decrement the PM count for each stuck event. This is safe > + * even in atomic context as we use ASYNC RPM here. > + */ > + pm_runtime_put_autosuspend(gpu->dev); > + } > + spin_unlock_irqrestore(&gpu->event_spinlock, flags); > + gpu->completed_fence = gpu->submitted_fence; > + > + etnaviv_gpu_hw_init(gpu); > + gpu->switch_context = true; > + > + mutex_unlock(&dev->struct_mutex); > + pm_runtime_mark_last_busy(gpu->dev); > + pm_runtime_put_autosuspend(gpu->dev); > + > + /* Retire the buffer objects in a work */ > + etnaviv_queue_work(gpu->drm, &gpu->retire_work); > +} > + > +static void hangcheck_timer_reset(struct etnaviv_gpu *gpu) > +{ > + DBG("%s", dev_name(gpu->dev)); > + mod_timer(&gpu->hangcheck_timer, > + round_jiffies_up(jiffies + DRM_ETNAVIV_HANGCHECK_JIFFIES)); > +} > + > +static void hangcheck_handler(unsigned long data) > +{ > + struct etnaviv_gpu *gpu = (struct etnaviv_gpu *)data; > + u32 fence = gpu->completed_fence; > + bool progress = false; > + > + if (fence != gpu->hangcheck_fence) { > + gpu->hangcheck_fence = fence; > + progress = true; > + } > + > + if (!progress) { > + u32 dma_addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS); > + int change = dma_addr - gpu->hangcheck_dma_addr; > + > + if (change < 0 || change > 16) { > + gpu->hangcheck_dma_addr = dma_addr; > + progress = true; > + } > + } > + > + if (!progress && fence_after(gpu->submitted_fence, fence)) { > + dev_err(gpu->dev, "hangcheck detected gpu lockup!\n"); > + dev_err(gpu->dev, " completed fence: %u\n", fence); > + dev_err(gpu->dev, " submitted fence: %u\n", > + gpu->submitted_fence); > + etnaviv_queue_work(gpu->drm, &gpu->recover_work); > + } > + > + /* if still more pending work, reset the hangcheck timer: */ > + if (fence_after(gpu->submitted_fence, gpu->hangcheck_fence)) > + hangcheck_timer_reset(gpu); > +} > + > +static void hangcheck_disable(struct etnaviv_gpu *gpu) > +{ > + del_timer_sync(&gpu->hangcheck_timer); > + cancel_work_sync(&gpu->recover_work); > +} > + > +/* > + * event management: > + */ > + > +static unsigned int event_alloc(struct etnaviv_gpu *gpu) > +{ > + unsigned long ret, flags; > + unsigned int i, event = ~0U; > + > + ret = wait_for_completion_timeout(&gpu->event_free, > + msecs_to_jiffies(10 * 10000)); > + if (!ret) > + dev_err(gpu->dev, "wait_for_completion_timeout failed"); > + > + spin_lock_irqsave(&gpu->event_spinlock, flags); > + > + /* find first free event */ > + for (i = 0; i < ARRAY_SIZE(gpu->event); i++) { > + if (gpu->event[i].used == false) { > + gpu->event[i].used = true; > + event = i; > + break; > + } > + } > + > + spin_unlock_irqrestore(&gpu->event_spinlock, flags); > + > + return event; > +} > + > +static void event_free(struct etnaviv_gpu *gpu, unsigned int event) > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&gpu->event_spinlock, flags); > + > + if (gpu->event[event].used == false) { > + dev_warn(gpu->dev, "event %u is already marked as free", > + event); > + spin_unlock_irqrestore(&gpu->event_spinlock, flags); > + } else { > + gpu->event[event].used = false; > + spin_unlock_irqrestore(&gpu->event_spinlock, flags); > + > + complete(&gpu->event_free); > + } > +} > + > +/* > + * Cmdstream submission/retirement: > + */ > + > +struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, u32 > size) > +{ > + struct etnaviv_cmdbuf *cmdbuf; > + > + cmdbuf = kzalloc(sizeof(*cmdbuf), GFP_KERNEL); > + if (!cmdbuf) > + return NULL; > + > + cmdbuf->vaddr = dma_alloc_writecombine(gpu->dev, size, &cmdbuf->paddr, > + GFP_KERNEL); > + if (!cmdbuf->vaddr) { > + kfree(cmdbuf); > + return NULL; > + } > + > + cmdbuf->gpu = gpu; > + cmdbuf->size = size; > + > + return cmdbuf; > +} > + > +void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf) > +{ > + dma_free_writecombine(cmdbuf->gpu->dev, cmdbuf->size, > + cmdbuf->vaddr, cmdbuf->paddr); > + kfree(cmdbuf); > +} > + > +static void retire_worker(struct work_struct *work) > +{ > + struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu, > + retire_work); > + struct drm_device *dev = gpu->drm; > + u32 fence = gpu->completed_fence; > + struct etnaviv_cmdbuf *cmdbuf, *tmp; > + > + mutex_lock(&dev->struct_mutex); > + > + while (!list_empty(&gpu->active_list)) { > + struct etnaviv_gem_object *obj; > + > + obj = list_first_entry(&gpu->active_list, > + struct etnaviv_gem_object, mm_list); > + > + if ((!(obj->access & ETNA_SUBMIT_BO_READ) || > + fence_after_eq(fence, obj->read_fence)) && > + (!(obj->access & ETNA_SUBMIT_BO_WRITE) || > + fence_after_eq(fence, obj->write_fence))) { > + /* move to inactive: */ > + etnaviv_gem_move_to_inactive(&obj->base); > + etnaviv_gem_put_iova(&obj->base); > + drm_gem_object_unreference(&obj->base); > + } else { > + break; > + } > + } > + > + list_for_each_entry_safe(cmdbuf, tmp, &gpu->active_cmd_list, > + gpu_active_list) { > + if (fence_after_eq(fence, cmdbuf->fence)) { > + etnaviv_gpu_cmdbuf_free(cmdbuf); > + list_del(&cmdbuf->gpu_active_list); > + } > + } > + > + gpu->retired_fence = fence; > + > + mutex_unlock(&dev->struct_mutex); > + > + wake_up_all(&gpu->fence_event); > +} > + > +static unsigned long etnaviv_timeout_to_jiffies(struct timespec *timeout) > +{ > + unsigned long timeout_jiffies = timespec_to_jiffies(timeout); > + unsigned long start_jiffies = jiffies; > + unsigned long remaining_jiffies; > + > + if (time_after(start_jiffies, timeout_jiffies)) > + remaining_jiffies = 0; > + else > + remaining_jiffies = timeout_jiffies - start_jiffies; > + > + return remaining_jiffies; > +} > + > +int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu, > + u32 fence, struct timespec *timeout) > +{ > + int ret; > + > + if (fence_after(fence, gpu->submitted_fence)) { > + DRM_ERROR("waiting on invalid fence: %u (of %u)\n", > + fence, gpu->submitted_fence); > + return -EINVAL; > + } > + > + if (!timeout) { > + /* No timeout was requested: just test for completion */ > + ret = fence_completed(gpu, fence) ? 0 : -EBUSY; > + } else { > + unsigned long remaining = etnaviv_timeout_to_jiffies(timeout); > + > + ret = wait_event_interruptible_timeout(gpu->fence_event, > + fence_completed(gpu, fence), > + remaining); > + if (ret == 0) { > + DBG("timeout waiting for fence: %u (retired: %u > completed: %u)", > + fence, gpu->retired_fence, > + gpu->completed_fence); > + ret = -ETIMEDOUT; > + } else if (ret != -ERESTARTSYS) { > + ret = 0; > + } > + } > + > + return ret; > +} > + > +/* > + * Wait for an object to become inactive. This, on it's own, is not race > + * free: the object is moved by the retire worker off the active list, and > + * then the iova is put. Moreover, the object could be re-submitted just > + * after we notice that it's become inactive. > + * > + * Although the retirement happens under the struct_mutex, we don't want > + * to hold that lock in this function. Instead, the caller is responsible > + * for ensuring that the retire worker has finished (which will happen, eg, > + * when we unreference the object, an action which takes the struct_mutex.) > + */ > +int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu, > + struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout) > +{ > + unsigned long remaining; > + long ret; > + > + if (!timeout) > + return !is_active(etnaviv_obj) ? 0 : -EBUSY; > + > + remaining = etnaviv_timeout_to_jiffies(timeout); > + > + ret = wait_event_interruptible_timeout(gpu->fence_event, > + !is_active(etnaviv_obj), > + remaining); > + if (ret > 0) > + return 0; > + else if (ret == -ERESTARTSYS) > + return -ERESTARTSYS; > + else > + return -ETIMEDOUT; > +} > + > +int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu) > +{ > + return pm_runtime_get_sync(gpu->dev); > +} > + > +void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu) > +{ > + pm_runtime_mark_last_busy(gpu->dev); > + pm_runtime_put_autosuspend(gpu->dev); > +} > + > +/* add bo's to gpu's ring, and kick gpu: */ > +int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, > + struct etnaviv_gem_submit *submit, struct etnaviv_file_private *ctx) > +{ > + struct drm_device *dev = gpu->drm; > + struct etnaviv_drm_private *priv = dev->dev_private; > + unsigned int event, i; > + int ret; > + > + ret = pm_runtime_get_sync(gpu->dev); > + if (ret < 0) > + return ret; > + > + /* > + * TODO > + * > + * - flush > + * - data endian > + * - prefetch > + * > + */ > + > + event = event_alloc(gpu); > + if (unlikely(event == ~0U)) { > + DRM_ERROR("no free event\n"); > + pm_runtime_put_autosuspend(gpu->dev); > + return -EBUSY; > + } > + > + submit->fence = ++priv->next_fence; > + > + gpu->submitted_fence = submit->fence; > + > + if (gpu->lastctx != ctx) { > + gpu->mmu->need_flush = true; > + gpu->switch_context = true; > + gpu->lastctx = ctx; > + } > + > + etnaviv_buffer_queue(gpu, event, submit); > + > + for (i = 0; i < submit->nr_bos; i++) { > + struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj; > + > + /* can't happen yet.. but when we add 2d support we'll have > + * to deal w/ cross-ring synchronization: > + */ > + WARN_ON(is_active(etnaviv_obj) && (etnaviv_obj->gpu != gpu)); > + > + if (!is_active(etnaviv_obj)) { > + u32 iova; > + > + /* ring takes a reference to the bo and iova: */ > + drm_gem_object_reference(&etnaviv_obj->base); > + etnaviv_gem_get_iova_locked(gpu, &etnaviv_obj->base, > + &iova); > + } > + > + if (submit->bos[i].flags & (ETNA_SUBMIT_BO_READ | > + ETNA_SUBMIT_BO_WRITE)) > + etnaviv_gem_move_to_active(&etnaviv_obj->base, gpu, > + submit->bos[i].flags, > + submit->fence); > + } > + hangcheck_timer_reset(gpu); > + > + return 0; > +} > + > +/* > + * Init/Cleanup: > + */ > +static irqreturn_t irq_handler(int irq, void *data) > +{ > + struct etnaviv_gpu *gpu = data; > + irqreturn_t ret = IRQ_NONE; > + > + u32 intr = gpu_read(gpu, VIVS_HI_INTR_ACKNOWLEDGE); > + > + if (intr != 0) { > + int event; > + > + pm_runtime_mark_last_busy(gpu->dev); > + > + dev_dbg(gpu->dev, "intr 0x%08x\n", intr); > + > + if (intr & VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR) { > + dev_err(gpu->dev, "AXI bus error\n"); > + intr &= ~VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR; > + } > + > + while ((event = ffs(intr)) != 0) { > + event -= 1; > + > + intr &= ~(1 << event); > + > + dev_dbg(gpu->dev, "event %u\n", event); > + /* > + * Events can be processed out of order. Eg, > + * - allocate and queue event 0 > + * - allocate event 1 > + * - event 0 completes, we process it > + * - allocate and queue event 0 > + * - event 1 and event 0 complete > + * we can end up processing event 0 first, then 1. > + */ > + if (fence_after(gpu->event[event].fence, > + gpu->completed_fence)) > + gpu->completed_fence = > gpu->event[event].fence; > + event_free(gpu, event); > + > + /* > + * We need to balance the runtime PM count caused by > + * each submission. Upon submission, we increment > + * the runtime PM counter, and allocate one event. > + * So here, we put the runtime PM count for each > + * completed event. > + */ > + pm_runtime_put_autosuspend(gpu->dev); > + } > + > + /* Retire the buffer objects in a work */ > + etnaviv_queue_work(gpu->drm, &gpu->retire_work); > + > + ret = IRQ_HANDLED; > + } > + > + return ret; > +} > + > +static int etnaviv_gpu_clk_enable(struct etnaviv_gpu *gpu) > +{ > + int ret; > + > + ret = enable_clk(gpu); > + if (ret) > + return ret; > + > + ret = enable_axi(gpu); > + if (ret) { > + disable_clk(gpu); > + return ret; > + } > + > + return 0; > +} > + > +static int etnaviv_gpu_clk_disable(struct etnaviv_gpu *gpu) > +{ > + int ret; > + > + ret = disable_axi(gpu); > + if (ret) > + return ret; > + > + ret = disable_clk(gpu); > + if (ret) > + return ret; > + > + return 0; > +} > + > +static int etnaviv_gpu_hw_suspend(struct etnaviv_gpu *gpu) > +{ > + if (gpu->buffer) { > + unsigned long timeout; > + > + /* Replace the last WAIT with END */ > + etnaviv_buffer_end(gpu); > + > + /* > + * We know that only the FE is busy here, this should > + * happen quickly (as the WAIT is only 200 cycles). If > + * we fail, just warn and continue. > + */ > + timeout = jiffies + msecs_to_jiffies(100); > + do { > + u32 idle = gpu_read(gpu, VIVS_HI_IDLE_STATE); > + > + if ((idle & gpu->idle_mask) == gpu->idle_mask) > + break; > + > + if (time_is_before_jiffies(timeout)) { > + dev_warn(gpu->dev, > + "timed out waiting for idle: > idle=0x%x\n", > + idle); > + break; > + } > + > + udelay(5); > + } while (1); > + } > + > + return etnaviv_gpu_clk_disable(gpu); > +} > + > +#ifdef CONFIG_PM > +static int etnaviv_gpu_hw_resume(struct etnaviv_gpu *gpu) > +{ > + struct drm_device *drm = gpu->drm; > + u32 clock; > + int ret; > + > + ret = mutex_lock_killable(&drm->struct_mutex); > + if (ret) > + return ret; > + > + clock = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS | > + VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40); > + > + etnaviv_gpu_load_clock(gpu, clock); > + etnaviv_gpu_hw_init(gpu); > + > + gpu->switch_context = true; > + > + mutex_unlock(&drm->struct_mutex); > + > + return 0; > +} > +#endif > + > +static int etnaviv_gpu_bind(struct device *dev, struct device *master, > + void *data) > +{ > + struct drm_device *drm = data; > + struct etnaviv_drm_private *priv = drm->dev_private; > + struct etnaviv_gpu *gpu = dev_get_drvdata(dev); > + int ret; > + > +#ifdef CONFIG_PM > + ret = pm_runtime_get_sync(gpu->dev); > +#else > + ret = etnaviv_gpu_clk_enable(gpu); > +#endif > + if (ret < 0) > + return ret; > + > + gpu->drm = drm; > + > + INIT_LIST_HEAD(&gpu->active_list); > + INIT_LIST_HEAD(&gpu->active_cmd_list); > + INIT_WORK(&gpu->retire_work, retire_worker); > + INIT_WORK(&gpu->recover_work, recover_worker); > + init_waitqueue_head(&gpu->fence_event); > + > + setup_timer(&gpu->hangcheck_timer, hangcheck_handler, > + (unsigned long)gpu); > + > + priv->gpu[priv->num_gpus++] = gpu; > + > + pm_runtime_mark_last_busy(gpu->dev); > + pm_runtime_put_autosuspend(gpu->dev); > + > + return 0; > +} > + > +static void etnaviv_gpu_unbind(struct device *dev, struct device *master, > + void *data) > +{ > + struct etnaviv_gpu *gpu = dev_get_drvdata(dev); > + > + DBG("%s", dev_name(gpu->dev)); > + > + hangcheck_disable(gpu); > + > + WARN_ON(!list_empty(&gpu->active_list)); > + > +#ifdef CONFIG_PM > + pm_runtime_get_sync(gpu->dev); > + pm_runtime_put_sync_suspend(gpu->dev); > +#else > + etnaviv_gpu_hw_suspend(gpu); > +#endif > + > + if (gpu->buffer) { > + etnaviv_gpu_cmdbuf_free(gpu->buffer); > + gpu->buffer = NULL; > + } > + > + if (gpu->mmu) { > + etnaviv_iommu_destroy(gpu->mmu); > + gpu->mmu = NULL; > + } > + > + gpu->drm = NULL; > +} > + > +static const struct component_ops gpu_ops = { > + .bind = etnaviv_gpu_bind, > + .unbind = etnaviv_gpu_unbind, > +}; > + > +static const struct of_device_id etnaviv_gpu_match[] = { > + { > + .compatible = "vivante,gc" > + }, > + { /* sentinel */ } > +}; > + > +static int etnaviv_gpu_platform_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct etnaviv_gpu *gpu; > + int err = 0; > + > + gpu = devm_kzalloc(dev, sizeof(*gpu), GFP_KERNEL); > + if (!gpu) > + return -ENOMEM; > + > + gpu->dev = &pdev->dev; > + > + /* > + * Set the GPU base address to the start of physical memory. This > + * ensures that if we have up to 2GB, the v1 MMU can address the > + * highest memory. This is important as command buffers may be > + * allocated outside of this limit. > + */ > + gpu->memory_base = PHYS_OFFSET; > + > + /* Map registers: */ > + gpu->mmio = etnaviv_ioremap(pdev, NULL, dev_name(gpu->dev)); > + if (IS_ERR(gpu->mmio)) > + return PTR_ERR(gpu->mmio); > + > + /* Get Interrupt: */ > + gpu->irq = platform_get_irq(pdev, 0); > + if (gpu->irq < 0) { > + err = gpu->irq; > + dev_err(dev, "failed to get irq: %d\n", err); > + goto fail; > + } > + > + err = devm_request_irq(&pdev->dev, gpu->irq, irq_handler, 0, > + dev_name(gpu->dev), gpu); > + if (err) { > + dev_err(dev, "failed to request IRQ%u: %d\n", gpu->irq, err); > + goto fail; > + } > + > + /* Get Clocks: */ > + gpu->clk_bus = devm_clk_get(&pdev->dev, "bus"); > + DBG("clk_bus: %p", gpu->clk_bus); > + if (IS_ERR(gpu->clk_bus)) > + gpu->clk_bus = NULL; > + > + gpu->clk_core = devm_clk_get(&pdev->dev, "core"); > + DBG("clk_core: %p", gpu->clk_core); > + if (IS_ERR(gpu->clk_core)) > + gpu->clk_core = NULL; > + > + gpu->clk_shader = devm_clk_get(&pdev->dev, "shader"); > + DBG("clk_shader: %p", gpu->clk_shader); > + if (IS_ERR(gpu->clk_shader)) > + gpu->clk_shader = NULL; > + > + /* TODO: figure out max mapped size */ > + dev_set_drvdata(dev, gpu); > + > + /* > + * We treat the device as initially suspended. The runtime PM > + * autosuspend delay is rather arbitary: no measurements have > + * yet been performed to determine an appropriate value. > + */ > + pm_runtime_use_autosuspend(gpu->dev); > + pm_runtime_set_autosuspend_delay(gpu->dev, 200); > + pm_runtime_enable(gpu->dev); > + > + err = component_add(&pdev->dev, &gpu_ops); > + if (err < 0) { > + dev_err(&pdev->dev, "failed to register component: %d\n", > err); > + goto fail; > + } > + > + return 0; > + > +fail: > + return err; > +} > + > +static int etnaviv_gpu_platform_remove(struct platform_device *pdev) > +{ > + component_del(&pdev->dev, &gpu_ops); > + pm_runtime_disable(&pdev->dev); > + return 0; > +} > + > +#ifdef CONFIG_PM > +static int etnaviv_gpu_rpm_suspend(struct device *dev) > +{ > + struct etnaviv_gpu *gpu = dev_get_drvdata(dev); > + u32 idle, mask; > + > + /* If we have outstanding fences, we're not idle */ > + if (gpu->completed_fence != gpu->submitted_fence) > + return -EBUSY; > + > + /* Check whether the hardware (except FE) is idle */ > + mask = gpu->idle_mask & ~VIVS_HI_IDLE_STATE_FE; > + idle = gpu_read(gpu, VIVS_HI_IDLE_STATE) & mask; > + if (idle != mask) > + return -EBUSY; > + > + return etnaviv_gpu_hw_suspend(gpu); > +} > + > +static int etnaviv_gpu_rpm_resume(struct device *dev) > +{ > + struct etnaviv_gpu *gpu = dev_get_drvdata(dev); > + int ret; > + > + /* We must never runtime-PM resume holding struct_mutex */ > + if (gpu->drm && > WARN_ON_ONCE(mutex_is_locked(&gpu->drm->struct_mutex))) > + return -EDEADLK; > + > + ret = etnaviv_gpu_clk_enable(gpu); > + if (ret) > + return ret; > + > + /* Re-initialise the basic hardware state */ > + if (gpu->drm && gpu->buffer) { > + ret = etnaviv_gpu_hw_resume(gpu); > + if (ret) { > + etnaviv_gpu_clk_disable(gpu); > + return ret; > + } > + } > + > + return 0; > +} > +#endif > + > +static const struct dev_pm_ops etnaviv_gpu_pm_ops = { > + SET_RUNTIME_PM_OPS(etnaviv_gpu_rpm_suspend, etnaviv_gpu_rpm_resume, > + NULL) > +}; > + > +struct platform_driver etnaviv_gpu_driver = { > + .driver = { > + .name = "etnaviv-gpu", > + .owner = THIS_MODULE, > + .pm = &etnaviv_gpu_pm_ops, > + .of_match_table = etnaviv_gpu_match, > + }, > + .probe = etnaviv_gpu_platform_probe, > + .remove = etnaviv_gpu_platform_remove, > + .id_table = gpu_ids, > +}; > diff --git a/drivers/staging/etnaviv/etnaviv_gpu.h > b/drivers/staging/etnaviv/etnaviv_gpu.h > new file mode 100644 > index 000000000000..3be5b481d8d1 > --- /dev/null > +++ b/drivers/staging/etnaviv/etnaviv_gpu.h > @@ -0,0 +1,198 @@ > +/* > + * Copyright (C) 2015 Etnaviv Project > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef __ETNAVIV_GPU_H__ > +#define __ETNAVIV_GPU_H__ > + > +#include <linux/clk.h> > +#include <linux/regulator/consumer.h> > + > +#include "etnaviv_drv.h" > + > +struct etnaviv_gem_submit; > + > +struct etnaviv_chip_identity { > + /* Chip model. */ > + u32 model; > + > + /* Revision value.*/ > + u32 revision; > + > + /* Supported feature fields. */ > + u32 features; > + > + /* Supported minor feature fields. */ > + u32 minor_features0; > + > + /* Supported minor feature 1 fields. */ > + u32 minor_features1; > + > + /* Supported minor feature 2 fields. */ > + u32 minor_features2; > + > + /* Supported minor feature 3 fields. */ > + u32 minor_features3; > + > + /* Number of streams supported. */ > + u32 stream_count; > + > + /* Total number of temporary registers per thread. */ > + u32 register_max; > + > + /* Maximum number of threads. */ > + u32 thread_count; > + > + /* Number of shader cores. */ > + u32 shader_core_count; > + > + /* Size of the vertex cache. */ > + u32 vertex_cache_size; > + > + /* Number of entries in the vertex output buffer. */ > + u32 vertex_output_buffer_size; > + > + /* Number of pixel pipes. */ > + u32 pixel_pipes; > + > + /* Number of instructions. */ > + u32 instruction_count; > + > + /* Number of constants. */ > + u32 num_constants; > + > + /* Buffer size */ > + u32 buffer_size; > +}; > + > +struct etnaviv_event { > + bool used; > + u32 fence; > +}; > + > +struct etnaviv_cmdbuf; > + > +struct etnaviv_gpu { > + struct drm_device *drm; > + struct device *dev; > + struct etnaviv_chip_identity identity; > + struct etnaviv_file_private *lastctx; > + bool switch_context; > + > + /* 'ring'-buffer: */ > + struct etnaviv_cmdbuf *buffer; > + > + /* bus base address of memory */ > + u32 memory_base; > + > + /* event management: */ > + struct etnaviv_event event[30]; > + struct completion event_free; > + spinlock_t event_spinlock; > + > + /* list of GEM active objects: */ > + struct list_head active_list; > + > + /* list of currently in-flight command buffers */ > + struct list_head active_cmd_list; > + > + u32 idle_mask; > + > + /* Fencing support */ > + u32 submitted_fence; > + u32 completed_fence; > + u32 retired_fence; > + wait_queue_head_t fence_event; > + > + /* worker for handling active-list retiring: */ > + struct work_struct retire_work; > + > + void __iomem *mmio; > + int irq; > + > + struct etnaviv_iommu *mmu; > + > + /* Power Control: */ > + struct clk *clk_bus; > + struct clk *clk_core; > + struct clk *clk_shader; > + > + /* Hang Detction: */ > +#define DRM_ETNAVIV_HANGCHECK_PERIOD 500 /* in ms */ > +#define DRM_ETNAVIV_HANGCHECK_JIFFIES > msecs_to_jiffies(DRM_ETNAVIV_HANGCHECK_PERIOD) > + struct timer_list hangcheck_timer; > + u32 hangcheck_fence; > + u32 hangcheck_dma_addr; > + struct work_struct recover_work; > +}; > + > +struct etnaviv_cmdbuf { > + /* device this cmdbuf is allocated for */ > + struct etnaviv_gpu *gpu; > + /* cmdbuf properties */ > + void *vaddr; > + dma_addr_t paddr; > + u32 size; > + u32 user_size; > + /* fence after which this buffer is to be disposed */ > + u32 fence; > + /* per GPU in-flight list */ > + struct list_head gpu_active_list; > +}; > + > +static inline void gpu_write(struct etnaviv_gpu *gpu, u32 reg, u32 data) > +{ > + etnaviv_writel(data, gpu->mmio + reg); > +} > + > +static inline u32 gpu_read(struct etnaviv_gpu *gpu, u32 reg) > +{ > + return etnaviv_readl(gpu->mmio + reg); > +} > + > +static inline bool fence_completed(struct etnaviv_gpu *gpu, u32 fence) > +{ > + return fence_after_eq(gpu->completed_fence, fence); > +} > + > +static inline bool fence_retired(struct etnaviv_gpu *gpu, u32 fence) > +{ > + return fence_after_eq(gpu->retired_fence, fence); > +} > + > +int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value); > + > +int etnaviv_gpu_init(struct etnaviv_gpu *gpu); > + > +#ifdef CONFIG_DEBUG_FS > +int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m); > +#endif > + > +void etnaviv_gpu_retire(struct etnaviv_gpu *gpu); > +int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu, > + u32 fence, struct timespec *timeout); > +int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu, > + struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout); > +int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, > + struct etnaviv_gem_submit *submit, struct etnaviv_file_private *ctx); > +struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, > + u32 size); > +void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf); > +int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu); > +void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu); > + > +extern struct platform_driver etnaviv_gpu_driver; > + > +#endif /* __ETNAVIV_GPU_H__ */ > diff --git a/drivers/staging/etnaviv/etnaviv_iommu.c > b/drivers/staging/etnaviv/etnaviv_iommu.c > new file mode 100644 > index 000000000000..9efb7d6092b4 > --- /dev/null > +++ b/drivers/staging/etnaviv/etnaviv_iommu.c > @@ -0,0 +1,221 @@ > +/* > + * Copyright (C) 2014 Christian Gmeiner <christian.gmeiner at gmail.com> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#include <linux/iommu.h> > +#include <linux/platform_device.h> > +#include <linux/sizes.h> > +#include <linux/slab.h> > +#include <linux/dma-mapping.h> > +#include <linux/bitops.h> > + > +#include "etnaviv_gpu.h" > +#include "etnaviv_iommu.h" > +#include "state_hi.xml.h" > + > +#define PT_SIZE SZ_2M > +#define PT_ENTRIES (PT_SIZE / sizeof(u32)) > + > +#define GPU_MEM_START 0x80000000 > + > +struct etnaviv_iommu_domain_pgtable { > + u32 *pgtable; > + dma_addr_t paddr; > +}; > + > +struct etnaviv_iommu_domain { > + struct iommu_domain domain; > + struct device *dev; > + void *bad_page_cpu; > + dma_addr_t bad_page_dma; > + struct etnaviv_iommu_domain_pgtable pgtable; > + spinlock_t map_lock; > +}; > + > +static struct etnaviv_iommu_domain *to_etnaviv_domain(struct iommu_domain > *domain) > +{ > + return container_of(domain, struct etnaviv_iommu_domain, domain); > +} > + > +static int pgtable_alloc(struct etnaviv_iommu_domain_pgtable *pgtable, > + size_t size) > +{ > + pgtable->pgtable = dma_alloc_coherent(NULL, size, &pgtable->paddr, > GFP_KERNEL); > + if (!pgtable->pgtable) > + return -ENOMEM; > + > + return 0; > +} > + > +static void pgtable_free(struct etnaviv_iommu_domain_pgtable *pgtable, > + size_t size) > +{ > + dma_free_coherent(NULL, size, pgtable->pgtable, pgtable->paddr); > +} > + > +static u32 pgtable_read(struct etnaviv_iommu_domain_pgtable *pgtable, > + unsigned long iova) > +{ > + /* calcuate index into page table */ > + unsigned int index = (iova - GPU_MEM_START) / SZ_4K; > + phys_addr_t paddr; > + > + paddr = pgtable->pgtable[index]; > + > + return paddr; > +} > + > +static void pgtable_write(struct etnaviv_iommu_domain_pgtable *pgtable, > + unsigned long iova, phys_addr_t paddr) > +{ > + /* calcuate index into page table */ > + unsigned int index = (iova - GPU_MEM_START) / SZ_4K; > + > + pgtable->pgtable[index] = paddr; > +} > + > +static int __etnaviv_iommu_init(struct etnaviv_iommu_domain *etnaviv_domain) > +{ > + u32 *p; > + int ret, i; > + > + etnaviv_domain->bad_page_cpu = dma_alloc_coherent(etnaviv_domain->dev, > + SZ_4K, > + > &etnaviv_domain->bad_page_dma, > + GFP_KERNEL); > + if (!etnaviv_domain->bad_page_cpu) > + return -ENOMEM; > + > + p = etnaviv_domain->bad_page_cpu; > + for (i = 0; i < SZ_4K / 4; i++) > + *p++ = 0xdead55aa; > + > + ret = pgtable_alloc(&etnaviv_domain->pgtable, PT_SIZE); > + if (ret < 0) { > + dma_free_coherent(etnaviv_domain->dev, SZ_4K, > + etnaviv_domain->bad_page_cpu, > + etnaviv_domain->bad_page_dma); > + return ret; > + } > + > + for (i = 0; i < PT_ENTRIES; i++) > + etnaviv_domain->pgtable.pgtable[i] = > + etnaviv_domain->bad_page_dma; > + > + spin_lock_init(&etnaviv_domain->map_lock); > + > + return 0; > +} > + > +static void etnaviv_domain_free(struct iommu_domain *domain) > +{ > + struct etnaviv_iommu_domain *etnaviv_domain = > to_etnaviv_domain(domain); > + > + pgtable_free(&etnaviv_domain->pgtable, PT_SIZE); > + dma_free_coherent(etnaviv_domain->dev, SZ_4K, > + etnaviv_domain->bad_page_cpu, > + etnaviv_domain->bad_page_dma); > + kfree(etnaviv_domain); > +} > + > +static int etnaviv_iommu_map(struct iommu_domain *domain, unsigned long iova, > + phys_addr_t paddr, size_t size, int prot) > +{ > + struct etnaviv_iommu_domain *etnaviv_domain = > to_etnaviv_domain(domain); > + > + if (size != SZ_4K) > + return -EINVAL; > + > + spin_lock(&etnaviv_domain->map_lock); > + pgtable_write(&etnaviv_domain->pgtable, iova, paddr); > + spin_unlock(&etnaviv_domain->map_lock); > + > + return 0; > +} > + > +static size_t etnaviv_iommu_unmap(struct iommu_domain *domain, > + unsigned long iova, size_t size) > +{ > + struct etnaviv_iommu_domain *etnaviv_domain = > to_etnaviv_domain(domain); > + > + if (size != SZ_4K) > + return -EINVAL; > + > + spin_lock(&etnaviv_domain->map_lock); > + pgtable_write(&etnaviv_domain->pgtable, iova, > + etnaviv_domain->bad_page_dma); > + spin_unlock(&etnaviv_domain->map_lock); > + > + return SZ_4K; > +} > + > +static phys_addr_t etnaviv_iommu_iova_to_phys(struct iommu_domain *domain, > + dma_addr_t iova) > +{ > + struct etnaviv_iommu_domain *etnaviv_domain = > to_etnaviv_domain(domain); > + > + return pgtable_read(&etnaviv_domain->pgtable, iova); > +} > + > +static struct iommu_ops etnaviv_iommu_ops = { > + .domain_free = etnaviv_domain_free, > + .map = etnaviv_iommu_map, > + .unmap = etnaviv_iommu_unmap, > + .iova_to_phys = etnaviv_iommu_iova_to_phys, > + .pgsize_bitmap = SZ_4K, > +}; > + > +void etnaviv_iommu_domain_restore(struct etnaviv_gpu *gpu, > + struct iommu_domain *domain) > +{ > + struct etnaviv_iommu_domain *etnaviv_domain = > to_etnaviv_domain(domain); > + u32 pgtable; > + > + /* set page table address in MC */ > + pgtable = (u32)etnaviv_domain->pgtable.paddr; > + > + gpu_write(gpu, VIVS_MC_MMU_FE_PAGE_TABLE, pgtable); > + gpu_write(gpu, VIVS_MC_MMU_TX_PAGE_TABLE, pgtable); > + gpu_write(gpu, VIVS_MC_MMU_PE_PAGE_TABLE, pgtable); > + gpu_write(gpu, VIVS_MC_MMU_PEZ_PAGE_TABLE, pgtable); > + gpu_write(gpu, VIVS_MC_MMU_RA_PAGE_TABLE, pgtable); > +} > + > +struct iommu_domain *etnaviv_iommu_domain_alloc(struct etnaviv_gpu *gpu) > +{ > + struct etnaviv_iommu_domain *etnaviv_domain; > + int ret; > + > + etnaviv_domain = kzalloc(sizeof(*etnaviv_domain), GFP_KERNEL); > + if (!etnaviv_domain) > + return NULL; > + > + etnaviv_domain->dev = gpu->dev; > + > + etnaviv_domain->domain.type = __IOMMU_DOMAIN_PAGING; > + etnaviv_domain->domain.ops = &etnaviv_iommu_ops; > + etnaviv_domain->domain.geometry.aperture_start = GPU_MEM_START; > + etnaviv_domain->domain.geometry.aperture_end = GPU_MEM_START + > PT_ENTRIES * SZ_4K - 1; > + > + ret = __etnaviv_iommu_init(etnaviv_domain); > + if (ret) > + goto out_free; > + > + return &etnaviv_domain->domain; > + > +out_free: > + kfree(etnaviv_domain); > + return NULL; > +} > diff --git a/drivers/staging/etnaviv/etnaviv_iommu.h > b/drivers/staging/etnaviv/etnaviv_iommu.h > new file mode 100644 > index 000000000000..cf45503f6b6f > --- /dev/null > +++ b/drivers/staging/etnaviv/etnaviv_iommu.h > @@ -0,0 +1,28 @@ > +/* > + * Copyright (C) 2014 Christian Gmeiner <christian.gmeiner at gmail.com> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef __ETNAVIV_IOMMU_H__ > +#define __ETNAVIV_IOMMU_H__ > + > +#include <linux/iommu.h> > +struct etnaviv_gpu; > + > +struct iommu_domain *etnaviv_iommu_domain_alloc(struct etnaviv_gpu *gpu); > +void etnaviv_iommu_domain_restore(struct etnaviv_gpu *gpu, > + struct iommu_domain *domain); > +struct iommu_domain *etnaviv_iommu_v2_domain_alloc(struct etnaviv_gpu *gpu); > + > +#endif /* __ETNAVIV_IOMMU_H__ */ > diff --git a/drivers/staging/etnaviv/etnaviv_iommu_v2.c > b/drivers/staging/etnaviv/etnaviv_iommu_v2.c > new file mode 100644 > index 000000000000..fbb4aed3dc80 > --- /dev/null > +++ b/drivers/staging/etnaviv/etnaviv_iommu_v2.c > @@ -0,0 +1,33 @@ > +/* > + * Copyright (C) 2014 Christian Gmeiner <christian.gmeiner at gmail.com> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#include <linux/iommu.h> > +#include <linux/platform_device.h> > +#include <linux/sizes.h> > +#include <linux/slab.h> > +#include <linux/dma-mapping.h> > +#include <linux/bitops.h> > + > +#include "etnaviv_gpu.h" > +#include "etnaviv_iommu.h" > +#include "state_hi.xml.h" > + > + > +struct iommu_domain *etnaviv_iommu_v2_domain_alloc(struct etnaviv_gpu *gpu) > +{ > + /* TODO */ > + return NULL; > +} > diff --git a/drivers/staging/etnaviv/etnaviv_iommu_v2.h > b/drivers/staging/etnaviv/etnaviv_iommu_v2.h > new file mode 100644 > index 000000000000..603ea41c5389 > --- /dev/null > +++ b/drivers/staging/etnaviv/etnaviv_iommu_v2.h > @@ -0,0 +1,25 @@ > +/* > + * Copyright (C) 2014 Christian Gmeiner <christian.gmeiner at gmail.com> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef __ETNAVIV_IOMMU_V2_H__ > +#define __ETNAVIV_IOMMU_V2_H__ > + > +#include <linux/iommu.h> > +struct etnaviv_gpu; > + > +struct iommu_domain *etnaviv_iommu_v2_domain_alloc(struct etnaviv_gpu *gpu); > + > +#endif /* __ETNAVIV_IOMMU_V2_H__ */ > diff --git a/drivers/staging/etnaviv/etnaviv_mmu.c > b/drivers/staging/etnaviv/etnaviv_mmu.c > new file mode 100644 > index 000000000000..ca317f633970 > --- /dev/null > +++ b/drivers/staging/etnaviv/etnaviv_mmu.c > @@ -0,0 +1,282 @@ > +/* > + * Copyright (C) 2015 Etnaviv Project > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "etnaviv_drv.h" > +#include "etnaviv_gem.h" > +#include "etnaviv_mmu.h" > + > +static int etnaviv_fault_handler(struct iommu_domain *iommu, struct device > *dev, > + unsigned long iova, int flags, void *arg) > +{ > + DBG("*** fault: iova=%08lx, flags=%d", iova, flags); > + return 0; > +} > + > +int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova, > + struct sg_table *sgt, unsigned len, int prot) > +{ > + struct iommu_domain *domain = iommu->domain; > + struct scatterlist *sg; > + unsigned int da = iova; > + unsigned int i, j; > + int ret; > + > + if (!domain || !sgt) > + return -EINVAL; > + > + for_each_sg(sgt->sgl, sg, sgt->nents, i) { > + u32 pa = sg_dma_address(sg) - sg->offset; > + size_t bytes = sg_dma_len(sg) + sg->offset; > + > + VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes); > + > + ret = iommu_map(domain, da, pa, bytes, prot); > + if (ret) > + goto fail; > + > + da += bytes; > + } > + > + return 0; > + > +fail: > + da = iova; > + > + for_each_sg(sgt->sgl, sg, i, j) { > + size_t bytes = sg_dma_len(sg) + sg->offset; > + > + iommu_unmap(domain, da, bytes); > + da += bytes; > + } > + return ret; > +} > + > +int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova, > + struct sg_table *sgt, unsigned len) > +{ > + struct iommu_domain *domain = iommu->domain; > + struct scatterlist *sg; > + unsigned int da = iova; > + int i; > + > + for_each_sg(sgt->sgl, sg, sgt->nents, i) { > + size_t bytes = sg_dma_len(sg) + sg->offset; > + size_t unmapped; > + > + unmapped = iommu_unmap(domain, da, bytes); > + if (unmapped < bytes) > + return unmapped; > + > + VERB("unmap[%d]: %08x(%zx)", i, iova, bytes); > + > + BUG_ON(!PAGE_ALIGNED(bytes)); > + > + da += bytes; > + } > + > + return 0; > +} > + > +int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu, > + struct etnaviv_gem_object *etnaviv_obj, u32 memory_base, > + struct etnaviv_vram_mapping **out_mapping) > +{ > + struct etnaviv_drm_private *priv = etnaviv_obj->base.dev->dev_private; > + struct sg_table *sgt = etnaviv_obj->sgt; > + struct etnaviv_vram_mapping *mapping, *free = NULL; > + struct drm_mm_node *node; > + int ret; > + > + mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); > + if (!mapping) > + return -ENOMEM; > + > + INIT_LIST_HEAD(&mapping->scan_node); > + mapping->object = etnaviv_obj; > + mapping->mmu = mmu; > + > + /* v1 MMU can optimize single entry (contiguous) scatterlists */ > + if (sgt->nents == 1 && !(etnaviv_obj->flags & ETNA_BO_FORCE_MMU)) { > + u32 iova; > + > + iova = sg_dma_address(sgt->sgl) - memory_base; > + if (iova < 0x80000000 - sg_dma_len(sgt->sgl)) { > + mapping->iova = iova; > + list_add_tail(&mapping->obj_node, > + &etnaviv_obj->vram_list); > + if (out_mapping) > + *out_mapping = mapping; > + return 0; > + } > + } > + > + node = &mapping->vram_node; > + while (1) { > + struct etnaviv_gem_object *o; > + struct etnaviv_vram_mapping *m, *n; > + struct list_head list; > + bool found; > + > + ret = drm_mm_insert_node_in_range(&mmu->mm, node, > + etnaviv_obj->base.size, 0, mmu->last_iova, ~0UL, > + DRM_MM_SEARCH_DEFAULT); > + > + if (ret != -ENOSPC) > + break; > + > + /* > + * If we did not search from the start of the MMU region, > + * try again in case there are free slots. > + */ > + if (mmu->last_iova) { > + mmu->last_iova = 0; > + mmu->need_flush = true; > + continue; > + } > + > + /* Try to retire some entries */ > + drm_mm_init_scan(&mmu->mm, etnaviv_obj->base.size, 0, 0); > + > + found = 0; > + INIT_LIST_HEAD(&list); > + list_for_each_entry(o, &priv->inactive_list, mm_list) { > + free = etnaviv_gem_get_vram_mapping(o, mmu); > + if (!free) > + continue; > + > + /* > + * If this vram node has not been used, skip this. > + */ > + if (!free->vram_node.mm) > + continue; > + > + /* > + * If it's on the submit list, then it is part of > + * a submission, and we want to keep its entry. > + */ > + if (!list_empty(&o->submit_entry)) > + continue; > + > + list_add(&free->scan_node, &list); > + if (drm_mm_scan_add_block(&free->vram_node)) { > + found = true; > + break; > + } > + } > + > + if (!found) { > + /* Nothing found, clean up and fail */ > + list_for_each_entry_safe(m, n, &list, scan_node) > + > BUG_ON(drm_mm_scan_remove_block(&m->vram_node)); > + break; > + } > + > + /* > + * drm_mm does not allow any other operations while > + * scanning, so we have to remove all blocks first. > + * If drm_mm_scan_remove_block() returns false, we > + * can leave the block pinned. > + */ > + list_for_each_entry_safe(m, n, &list, scan_node) > + if (!drm_mm_scan_remove_block(&m->vram_node)) > + list_del_init(&m->scan_node); > + > + list_for_each_entry_safe(m, n, &list, scan_node) { > + list_del_init(&m->scan_node); > + etnaviv_iommu_unmap_gem(m); > + } > + > + /* > + * We removed enough mappings so that the new allocation will > + * succeed. Ensure that the MMU will be flushed and retry > + * the allocation one more time. > + */ > + mmu->need_flush = true; > + } > + > + if (ret < 0) { > + kfree(mapping); > + return ret; > + } > + > + mmu->last_iova = node->start + etnaviv_obj->base.size; > + mapping->iova = node->start; > + ret = etnaviv_iommu_map(mmu, node->start, sgt, etnaviv_obj->base.size, > + IOMMU_READ | IOMMU_WRITE); > + > + if (ret < 0) { > + drm_mm_remove_node(node); > + kfree(mapping); > + return ret; > + } > + > + list_add_tail(&mapping->obj_node, &etnaviv_obj->vram_list); > + if (out_mapping) > + *out_mapping = mapping; > + > + return ret; > +} > + > +void etnaviv_iommu_unmap_gem(struct etnaviv_vram_mapping *mapping) > +{ > + struct etnaviv_iommu *mmu; > + struct etnaviv_gem_object *etnaviv_obj; > + > + if (!mapping) > + return; > + > + mmu = mapping->mmu; > + > + /* If the vram node is on the mm, unmap and remove the node */ > + if (mapping->vram_node.mm == &mmu->mm) { > + etnaviv_obj = mapping->object; > + etnaviv_iommu_unmap(mmu, mapping->vram_node.start, > + etnaviv_obj->sgt, etnaviv_obj->base.size); > + drm_mm_remove_node(&mapping->vram_node); > + } > + > + list_del(&mapping->obj_node); > + kfree(mapping); > +} > + > +void etnaviv_iommu_destroy(struct etnaviv_iommu *mmu) > +{ > + drm_mm_takedown(&mmu->mm); > + iommu_domain_free(mmu->domain); > + kfree(mmu); > +} > + > +struct etnaviv_iommu *etnaviv_iommu_new(struct device *dev, > + struct iommu_domain *domain, enum etnaviv_iommu_version version) > +{ > + struct etnaviv_iommu *mmu; > + > + mmu = kzalloc(sizeof(*mmu), GFP_KERNEL); > + if (!mmu) > + return ERR_PTR(-ENOMEM); > + > + mmu->domain = domain; > + mmu->dev = dev; > + mmu->version = version; > + > + drm_mm_init(&mmu->mm, domain->geometry.aperture_start, > + domain->geometry.aperture_end - > + domain->geometry.aperture_start + 1); > + > + iommu_set_fault_handler(domain, etnaviv_fault_handler, dev); > + > + return mmu; > +} > diff --git a/drivers/staging/etnaviv/etnaviv_mmu.h > b/drivers/staging/etnaviv/etnaviv_mmu.h > new file mode 100644 > index 000000000000..444ef296d2b4 > --- /dev/null > +++ b/drivers/staging/etnaviv/etnaviv_mmu.h > @@ -0,0 +1,58 @@ > +/* > + * Copyright (C) 2015 Etnaviv Project > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef __ETNAVIV_MMU_H__ > +#define __ETNAVIV_MMU_H__ > + > +#include <linux/iommu.h> > + > +enum etnaviv_iommu_version { > + ETNAVIV_IOMMU_V1 = 0, > + ETNAVIV_IOMMU_V2, > +}; > + > +struct etnaviv_vram_mapping; > + > +struct etnaviv_iommu { > + struct device *dev; > + struct iommu_domain *domain; > + > + enum etnaviv_iommu_version version; > + > + /* memory manager for GPU address area */ > + struct drm_mm mm; > + u32 last_iova; > + bool need_flush; > +}; > + > +struct etnaviv_gem_object; > + > +int etnaviv_iommu_attach(struct etnaviv_iommu *iommu, const char **names, > + int cnt); > +int etnaviv_iommu_map(struct etnaviv_iommu *iommu, u32 iova, > + struct sg_table *sgt, unsigned len, int prot); > +int etnaviv_iommu_unmap(struct etnaviv_iommu *iommu, u32 iova, > + struct sg_table *sgt, unsigned len); > +int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu, > + struct etnaviv_gem_object *etnaviv_obj, u32 memory_base, > + struct etnaviv_vram_mapping **mapping); > +void etnaviv_iommu_unmap_gem(struct etnaviv_vram_mapping *mapping); > +void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu); > + > +struct etnaviv_iommu *etnaviv_iommu_new(struct device *dev, > + struct iommu_domain *domain, enum etnaviv_iommu_version version); > + > +#endif /* __ETNAVIV_MMU_H__ */ > diff --git a/drivers/staging/etnaviv/state.xml.h > b/drivers/staging/etnaviv/state.xml.h > new file mode 100644 > index 000000000000..368218304566 > --- /dev/null > +++ b/drivers/staging/etnaviv/state.xml.h > @@ -0,0 +1,351 @@ > +#ifndef STATE_XML > +#define STATE_XML > + > +/* Autogenerated file, DO NOT EDIT manually! > + > +This file was generated by the rules-ng-ng headergen tool in this git > repository: > +http://0x04.net/cgit/index.cgi/rules-ng-ng > +git clone git://0x04.net/rules-ng-ng > + > +The rules-ng-ng source files this header was generated from are: > +- state.xml ( 18882 bytes, from 2015-03-25 11:42:32) > +- common.xml ( 18437 bytes, from 2015-03-25 11:27:41) > +- state_hi.xml ( 23420 bytes, from 2015-03-25 11:47:21) > +- state_2d.xml ( 51549 bytes, from 2015-03-25 11:25:06) > +- state_3d.xml ( 54600 bytes, from 2015-03-25 11:25:19) > +- state_vg.xml ( 5973 bytes, from 2015-03-25 11:26:01) > + > +Copyright (C) 2015 > +*/ > + > + > +#define VARYING_COMPONENT_USE_UNUSED 0x00000000 > +#define VARYING_COMPONENT_USE_USED 0x00000001 > +#define VARYING_COMPONENT_USE_POINTCOORD_X 0x00000002 > +#define VARYING_COMPONENT_USE_POINTCOORD_Y 0x00000003 > +#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK 0x000000ff > +#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT 0 > +#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE(x) (((x) << > FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT) & > FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK) > +#define VIVS_FE > 0x00000000 > + > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG(i0) (0x00000600 + > 0x4*(i0)) > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG__ESIZE 0x00000004 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG__LEN 0x00000010 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__MASK 0x0000000f > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__SHIFT 0 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_BYTE > 0x00000000 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_BYTE 0x00000001 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_SHORT 0x00000002 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_SHORT 0x00000003 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT 0x00000004 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT > 0x00000005 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FLOAT 0x00000008 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_HALF_FLOAT 0x00000009 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FIXED 0x0000000b > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT_10_10_10_2 0x0000000c > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT_10_10_10_2 > 0x0000000d > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK 0x00000030 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT 4 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN(x) (((x) > << VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT) & > VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK) > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NONCONSECUTIVE 0x00000080 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__MASK 0x00000700 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__SHIFT 8 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM(x) (((x) > << VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__SHIFT) & > VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__MASK) > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__MASK > 0x00003000 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__SHIFT 12 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM(x) (((x) << > VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__SHIFT) & > VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__MASK) > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE__MASK 0x0000c000 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE__SHIFT 14 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_OFF 0x00000000 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_ON 0x00008000 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START__MASK 0x00ff0000 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START__SHIFT 16 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START(x) (((x) << > VIVS_FE_VERTEX_ELEMENT_CONFIG_START__SHIFT) & > VIVS_FE_VERTEX_ELEMENT_CONFIG_START__MASK) > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END__MASK > 0xff000000 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END__SHIFT 24 > +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END(x) (((x) << > VIVS_FE_VERTEX_ELEMENT_CONFIG_END__SHIFT) & > VIVS_FE_VERTEX_ELEMENT_CONFIG_END__MASK) > + > +#define VIVS_FE_CMD_STREAM_BASE_ADDR 0x00000640 > + > +#define VIVS_FE_INDEX_STREAM_BASE_ADDR 0x00000644 > + > +#define VIVS_FE_INDEX_STREAM_CONTROL 0x00000648 > +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE__MASK > 0x00000003 > +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE__SHIFT 0 > +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_CHAR > 0x00000000 > +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_SHORT 0x00000001 > +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_INT 0x00000002 > + > +#define VIVS_FE_VERTEX_STREAM_BASE_ADDR > 0x0000064c > + > +#define VIVS_FE_VERTEX_STREAM_CONTROL 0x00000650 > + > +#define VIVS_FE_COMMAND_ADDRESS > 0x00000654 > + > +#define VIVS_FE_COMMAND_CONTROL > 0x00000658 > +#define VIVS_FE_COMMAND_CONTROL_PREFETCH__MASK 0x0000ffff > +#define VIVS_FE_COMMAND_CONTROL_PREFETCH__SHIFT 0 > +#define VIVS_FE_COMMAND_CONTROL_PREFETCH(x) (((x) << > VIVS_FE_COMMAND_CONTROL_PREFETCH__SHIFT) & > VIVS_FE_COMMAND_CONTROL_PREFETCH__MASK) > +#define VIVS_FE_COMMAND_CONTROL_ENABLE 0x00010000 > + > +#define VIVS_FE_DMA_STATUS 0x0000065c > + > +#define VIVS_FE_DMA_DEBUG_STATE > 0x00000660 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE__MASK > 0x0000001f > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE__SHIFT 0 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_IDLE 0x00000000 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DEC 0x00000001 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_ADR0 0x00000002 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LOAD0 > 0x00000003 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_ADR1 0x00000004 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LOAD1 > 0x00000005 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DADR > 0x00000006 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DCMD > 0x00000007 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DCNTL 0x00000008 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DIDXCNTL 0x00000009 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_INITREQDMA 0x0000000a > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DRAWIDX 0x0000000b > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DRAW 0x0000000c > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DRECT0 0x0000000d > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DRECT1 0x0000000e > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DDATA0 0x0000000f > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DDATA1 0x00000010 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_WAITFIFO 0x00000011 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_WAIT 0x00000012 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LINK 0x00000013 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_END 0x00000014 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_STALL > 0x00000015 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE__MASK 0x00000300 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE__SHIFT 8 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_IDLE 0x00000000 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_START 0x00000100 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_REQ 0x00000200 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_END 0x00000300 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE__MASK 0x00000c00 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE__SHIFT 10 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_IDLE 0x00000000 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_RAMVALID 0x00000400 > +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_VALID 0x00000800 > +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE__MASK 0x00003000 > +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE__SHIFT 12 > +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_IDLE 0x00000000 > +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_WAITIDX 0x00001000 > +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_CAL 0x00002000 > +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE__MASK > 0x0000c000 > +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE__SHIFT 14 > +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_IDLE 0x00000000 > +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_LDADR > 0x00004000 > +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_IDXCALC 0x00008000 > +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE__MASK 0x00030000 > +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE__SHIFT 16 > +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_IDLE 0x00000000 > +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_CKCACHE 0x00010000 > +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_MISS 0x00020000 > + > +#define VIVS_FE_DMA_ADDRESS 0x00000664 > + > +#define VIVS_FE_DMA_LOW > 0x00000668 > + > +#define VIVS_FE_DMA_HIGH 0x0000066c > + > +#define VIVS_FE_AUTO_FLUSH 0x00000670 > + > +#define VIVS_FE_UNK00678 0x00000678 > + > +#define VIVS_FE_UNK0067C 0x0000067c > + > +#define VIVS_FE_VERTEX_STREAMS(i0) (0x00000000 + > 0x4*(i0)) > +#define VIVS_FE_VERTEX_STREAMS__ESIZE 0x00000004 > +#define VIVS_FE_VERTEX_STREAMS__LEN 0x00000008 > + > +#define VIVS_FE_VERTEX_STREAMS_BASE_ADDR(i0) (0x00000680 + > 0x4*(i0)) > + > +#define VIVS_FE_VERTEX_STREAMS_CONTROL(i0) (0x000006a0 + > 0x4*(i0)) > + > +#define VIVS_FE_UNK00700(i0) (0x00000700 + > 0x4*(i0)) > +#define VIVS_FE_UNK00700__ESIZE > 0x00000004 > +#define VIVS_FE_UNK00700__LEN 0x00000010 > + > +#define VIVS_FE_UNK00740(i0) (0x00000740 + > 0x4*(i0)) > +#define VIVS_FE_UNK00740__ESIZE > 0x00000004 > +#define VIVS_FE_UNK00740__LEN 0x00000010 > + > +#define VIVS_FE_UNK00780(i0) (0x00000780 + > 0x4*(i0)) > +#define VIVS_FE_UNK00780__ESIZE > 0x00000004 > +#define VIVS_FE_UNK00780__LEN 0x00000010 > + > +#define VIVS_GL > 0x00000000 > + > +#define VIVS_GL_PIPE_SELECT 0x00003800 > +#define VIVS_GL_PIPE_SELECT_PIPE__MASK 0x00000001 > +#define VIVS_GL_PIPE_SELECT_PIPE__SHIFT 0 > +#define VIVS_GL_PIPE_SELECT_PIPE(x) (((x) << > VIVS_GL_PIPE_SELECT_PIPE__SHIFT) & VIVS_GL_PIPE_SELECT_PIPE__MASK) > + > +#define VIVS_GL_EVENT 0x00003804 > +#define VIVS_GL_EVENT_EVENT_ID__MASK 0x0000001f > +#define VIVS_GL_EVENT_EVENT_ID__SHIFT 0 > +#define VIVS_GL_EVENT_EVENT_ID(x) (((x) << > VIVS_GL_EVENT_EVENT_ID__SHIFT) & VIVS_GL_EVENT_EVENT_ID__MASK) > +#define VIVS_GL_EVENT_FROM_FE 0x00000020 > +#define VIVS_GL_EVENT_FROM_PE 0x00000040 > +#define VIVS_GL_EVENT_SOURCE__MASK 0x00001f00 > +#define VIVS_GL_EVENT_SOURCE__SHIFT 8 > +#define VIVS_GL_EVENT_SOURCE(x) (((x) > << VIVS_GL_EVENT_SOURCE__SHIFT) & VIVS_GL_EVENT_SOURCE__MASK) > + > +#define VIVS_GL_SEMAPHORE_TOKEN > 0x00003808 > +#define VIVS_GL_SEMAPHORE_TOKEN_FROM__MASK 0x0000001f > +#define VIVS_GL_SEMAPHORE_TOKEN_FROM__SHIFT 0 > +#define VIVS_GL_SEMAPHORE_TOKEN_FROM(x) (((x) > << VIVS_GL_SEMAPHORE_TOKEN_FROM__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_FROM__MASK) > +#define VIVS_GL_SEMAPHORE_TOKEN_TO__MASK 0x00001f00 > +#define VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT 8 > +#define VIVS_GL_SEMAPHORE_TOKEN_TO(x) (((x) << > VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_TO__MASK) > + > +#define VIVS_GL_FLUSH_CACHE 0x0000380c > +#define VIVS_GL_FLUSH_CACHE_DEPTH 0x00000001 > +#define VIVS_GL_FLUSH_CACHE_COLOR 0x00000002 > +#define VIVS_GL_FLUSH_CACHE_TEXTURE 0x00000004 > +#define VIVS_GL_FLUSH_CACHE_PE2D 0x00000008 > +#define VIVS_GL_FLUSH_CACHE_TEXTUREVS 0x00000010 > +#define VIVS_GL_FLUSH_CACHE_SHADER_L1 0x00000020 > +#define VIVS_GL_FLUSH_CACHE_SHADER_L2 0x00000040 > + > +#define VIVS_GL_FLUSH_MMU 0x00003810 > +#define VIVS_GL_FLUSH_MMU_FLUSH_FEMMU 0x00000001 > +#define VIVS_GL_FLUSH_MMU_FLUSH_UNK1 0x00000002 > +#define VIVS_GL_FLUSH_MMU_FLUSH_UNK2 0x00000004 > +#define VIVS_GL_FLUSH_MMU_FLUSH_PEMMU 0x00000008 > +#define VIVS_GL_FLUSH_MMU_FLUSH_UNK4 0x00000010 > + > +#define VIVS_GL_VERTEX_ELEMENT_CONFIG 0x00003814 > + > +#define VIVS_GL_MULTI_SAMPLE_CONFIG 0x00003818 > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__MASK 0x00000003 > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__SHIFT 0 > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_NONE 0x00000000 > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_2X 0x00000001 > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_4X 0x00000002 > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_MASK 0x00000008 > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__MASK 0x000000f0 > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__SHIFT 4 > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES(x) (((x) << > VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__SHIFT) & > VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__MASK) > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES_MASK 0x00000100 > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__MASK > 0x00007000 > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__SHIFT 12 > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12(x) (((x) << > VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__SHIFT) & > VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__MASK) > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12_MASK 0x00008000 > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__MASK > 0x00030000 > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__SHIFT 16 > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16(x) (((x) << > VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__SHIFT) & > VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__MASK) > +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16_MASK 0x00080000 > + > +#define VIVS_GL_VARYING_TOTAL_COMPONENTS 0x0000381c > +#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK 0x000000ff > +#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT 0 > +#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM(x) (((x) > << VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT) & > VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK) > + > +#define VIVS_GL_VARYING_NUM_COMPONENTS 0x00003820 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK 0x00000007 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT 0 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0(x) (((x) << > VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT) & > VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK) > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK 0x00000070 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT 4 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1(x) (((x) << > VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT) & > VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK) > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK 0x00000700 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT 8 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2(x) (((x) << > VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT) & > VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK) > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK 0x00007000 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT 12 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3(x) (((x) << > VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT) & > VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK) > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK 0x00070000 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT 16 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4(x) (((x) << > VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT) & > VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK) > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK 0x00700000 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT 20 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5(x) (((x) << > VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT) & > VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK) > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK 0x07000000 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT 24 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6(x) (((x) << > VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT) & > VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK) > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK 0x70000000 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT 28 > +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7(x) (((x) << > VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT) & > VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK) > + > +#define VIVS_GL_VARYING_COMPONENT_USE(i0) (0x00003828 + > 0x4*(i0)) > +#define VIVS_GL_VARYING_COMPONENT_USE__ESIZE 0x00000004 > +#define VIVS_GL_VARYING_COMPONENT_USE__LEN 0x00000002 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP0__MASK 0x00000003 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP0__SHIFT 0 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP0(x) (((x) << > VIVS_GL_VARYING_COMPONENT_USE_COMP0__SHIFT) & > VIVS_GL_VARYING_COMPONENT_USE_COMP0__MASK) > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP1__MASK 0x0000000c > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP1__SHIFT 2 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP1(x) (((x) << > VIVS_GL_VARYING_COMPONENT_USE_COMP1__SHIFT) & > VIVS_GL_VARYING_COMPONENT_USE_COMP1__MASK) > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP2__MASK 0x00000030 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP2__SHIFT 4 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP2(x) (((x) << > VIVS_GL_VARYING_COMPONENT_USE_COMP2__SHIFT) & > VIVS_GL_VARYING_COMPONENT_USE_COMP2__MASK) > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP3__MASK 0x000000c0 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP3__SHIFT 6 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP3(x) (((x) << > VIVS_GL_VARYING_COMPONENT_USE_COMP3__SHIFT) & > VIVS_GL_VARYING_COMPONENT_USE_COMP3__MASK) > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP4__MASK 0x00000300 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP4__SHIFT 8 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP4(x) (((x) << > VIVS_GL_VARYING_COMPONENT_USE_COMP4__SHIFT) & > VIVS_GL_VARYING_COMPONENT_USE_COMP4__MASK) > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP5__MASK 0x00000c00 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP5__SHIFT 10 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP5(x) (((x) << > VIVS_GL_VARYING_COMPONENT_USE_COMP5__SHIFT) & > VIVS_GL_VARYING_COMPONENT_USE_COMP5__MASK) > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP6__MASK 0x00003000 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP6__SHIFT 12 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP6(x) (((x) << > VIVS_GL_VARYING_COMPONENT_USE_COMP6__SHIFT) & > VIVS_GL_VARYING_COMPONENT_USE_COMP6__MASK) > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP7__MASK 0x0000c000 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP7__SHIFT 14 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP7(x) (((x) << > VIVS_GL_VARYING_COMPONENT_USE_COMP7__SHIFT) & > VIVS_GL_VARYING_COMPONENT_USE_COMP7__MASK) > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP8__MASK 0x00030000 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP8__SHIFT 16 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP8(x) (((x) << > VIVS_GL_VARYING_COMPONENT_USE_COMP8__SHIFT) & > VIVS_GL_VARYING_COMPONENT_USE_COMP8__MASK) > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP9__MASK 0x000c0000 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP9__SHIFT 18 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP9(x) (((x) << > VIVS_GL_VARYING_COMPONENT_USE_COMP9__SHIFT) & > VIVS_GL_VARYING_COMPONENT_USE_COMP9__MASK) > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP10__MASK 0x00300000 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP10__SHIFT 20 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP10(x) (((x) > << VIVS_GL_VARYING_COMPONENT_USE_COMP10__SHIFT) & > VIVS_GL_VARYING_COMPONENT_USE_COMP10__MASK) > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP11__MASK 0x00c00000 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP11__SHIFT 22 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP11(x) (((x) > << VIVS_GL_VARYING_COMPONENT_USE_COMP11__SHIFT) & > VIVS_GL_VARYING_COMPONENT_USE_COMP11__MASK) > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP12__MASK 0x03000000 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP12__SHIFT 24 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP12(x) (((x) > << VIVS_GL_VARYING_COMPONENT_USE_COMP12__SHIFT) & > VIVS_GL_VARYING_COMPONENT_USE_COMP12__MASK) > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP13__MASK 0x0c000000 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP13__SHIFT 26 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP13(x) (((x) > << VIVS_GL_VARYING_COMPONENT_USE_COMP13__SHIFT) & > VIVS_GL_VARYING_COMPONENT_USE_COMP13__MASK) > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP14__MASK 0x30000000 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP14__SHIFT 28 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP14(x) (((x) > << VIVS_GL_VARYING_COMPONENT_USE_COMP14__SHIFT) & > VIVS_GL_VARYING_COMPONENT_USE_COMP14__MASK) > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK 0xc0000000 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT 30 > +#define VIVS_GL_VARYING_COMPONENT_USE_COMP15(x) (((x) > << VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT) & > VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK) > + > +#define VIVS_GL_UNK03834 0x00003834 > + > +#define VIVS_GL_UNK03838 0x00003838 > + > +#define VIVS_GL_API_MODE 0x0000384c > +#define VIVS_GL_API_MODE_OPENGL > 0x00000000 > +#define VIVS_GL_API_MODE_OPENVG > 0x00000001 > +#define VIVS_GL_API_MODE_OPENCL > 0x00000002 > + > +#define VIVS_GL_CONTEXT_POINTER > 0x00003850 > + > +#define VIVS_GL_UNK03A00 0x00003a00 > + > +#define VIVS_GL_STALL_TOKEN 0x00003c00 > +#define VIVS_GL_STALL_TOKEN_FROM__MASK 0x0000001f > +#define VIVS_GL_STALL_TOKEN_FROM__SHIFT 0 > +#define VIVS_GL_STALL_TOKEN_FROM(x) (((x) << > VIVS_GL_STALL_TOKEN_FROM__SHIFT) & VIVS_GL_STALL_TOKEN_FROM__MASK) > +#define VIVS_GL_STALL_TOKEN_TO__MASK 0x00001f00 > +#define VIVS_GL_STALL_TOKEN_TO__SHIFT 8 > +#define VIVS_GL_STALL_TOKEN_TO(x) (((x) << > VIVS_GL_STALL_TOKEN_TO__SHIFT) & VIVS_GL_STALL_TOKEN_TO__MASK) > +#define VIVS_GL_STALL_TOKEN_FLIP0 0x40000000 > +#define VIVS_GL_STALL_TOKEN_FLIP1 0x80000000 > + > +#define VIVS_DUMMY 0x00000000 > + > +#define VIVS_DUMMY_DUMMY 0x0003fffc > + > + > +#endif /* STATE_XML */ > diff --git a/drivers/staging/etnaviv/state_hi.xml.h > b/drivers/staging/etnaviv/state_hi.xml.h > new file mode 100644 > index 000000000000..0064f2640396 > --- /dev/null > +++ b/drivers/staging/etnaviv/state_hi.xml.h > @@ -0,0 +1,407 @@ > +#ifndef STATE_HI_XML > +#define STATE_HI_XML > + > +/* Autogenerated file, DO NOT EDIT manually! > + > +This file was generated by the rules-ng-ng headergen tool in this git > repository: > +http://0x04.net/cgit/index.cgi/rules-ng-ng > +git clone git://0x04.net/rules-ng-ng > + > +The rules-ng-ng source files this header was generated from are: > +- state_hi.xml ( 23420 bytes, from 2015-03-25 11:47:21) > +- common.xml ( 18437 bytes, from 2015-03-25 11:27:41) > + > +Copyright (C) 2015 > +*/ > + > + > +#define MMU_EXCEPTION_SLAVE_NOT_PRESENT > 0x00000001 > +#define MMU_EXCEPTION_PAGE_NOT_PRESENT 0x00000002 > +#define MMU_EXCEPTION_WRITE_VIOLATION 0x00000003 > +#define VIVS_HI > 0x00000000 > + > +#define VIVS_HI_CLOCK_CONTROL 0x00000000 > +#define VIVS_HI_CLOCK_CONTROL_CLK3D_DIS > 0x00000001 > +#define VIVS_HI_CLOCK_CONTROL_CLK2D_DIS > 0x00000002 > +#define VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__MASK 0x000001fc > +#define VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__SHIFT 2 > +#define VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(x) (((x) << > VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__SHIFT) & > VIVS_HI_CLOCK_CONTROL_FSCALE_VAL__MASK) > +#define VIVS_HI_CLOCK_CONTROL_FSCALE_CMD_LOAD 0x00000200 > +#define VIVS_HI_CLOCK_CONTROL_DISABLE_RAM_CLK_GATING 0x00000400 > +#define VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS 0x00000800 > +#define VIVS_HI_CLOCK_CONTROL_SOFT_RESET 0x00001000 > +#define VIVS_HI_CLOCK_CONTROL_IDLE_3D 0x00010000 > +#define VIVS_HI_CLOCK_CONTROL_IDLE_2D 0x00020000 > +#define VIVS_HI_CLOCK_CONTROL_IDLE_VG 0x00040000 > +#define VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU 0x00080000 > +#define VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK 0x00f00000 > +#define VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__SHIFT 20 > +#define VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE(x) (((x) << > VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__SHIFT) & > VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK) > + > +#define VIVS_HI_IDLE_STATE 0x00000004 > +#define VIVS_HI_IDLE_STATE_FE 0x00000001 > +#define VIVS_HI_IDLE_STATE_DE 0x00000002 > +#define VIVS_HI_IDLE_STATE_PE 0x00000004 > +#define VIVS_HI_IDLE_STATE_SH 0x00000008 > +#define VIVS_HI_IDLE_STATE_PA 0x00000010 > +#define VIVS_HI_IDLE_STATE_SE 0x00000020 > +#define VIVS_HI_IDLE_STATE_RA 0x00000040 > +#define VIVS_HI_IDLE_STATE_TX 0x00000080 > +#define VIVS_HI_IDLE_STATE_VG 0x00000100 > +#define VIVS_HI_IDLE_STATE_IM 0x00000200 > +#define VIVS_HI_IDLE_STATE_FP 0x00000400 > +#define VIVS_HI_IDLE_STATE_TS 0x00000800 > +#define VIVS_HI_IDLE_STATE_AXI_LP 0x80000000 > + > +#define VIVS_HI_AXI_CONFIG 0x00000008 > +#define VIVS_HI_AXI_CONFIG_AWID__MASK 0x0000000f > +#define VIVS_HI_AXI_CONFIG_AWID__SHIFT 0 > +#define VIVS_HI_AXI_CONFIG_AWID(x) (((x) << > VIVS_HI_AXI_CONFIG_AWID__SHIFT) & VIVS_HI_AXI_CONFIG_AWID__MASK) > +#define VIVS_HI_AXI_CONFIG_ARID__MASK 0x000000f0 > +#define VIVS_HI_AXI_CONFIG_ARID__SHIFT 4 > +#define VIVS_HI_AXI_CONFIG_ARID(x) (((x) << > VIVS_HI_AXI_CONFIG_ARID__SHIFT) & VIVS_HI_AXI_CONFIG_ARID__MASK) > +#define VIVS_HI_AXI_CONFIG_AWCACHE__MASK 0x00000f00 > +#define VIVS_HI_AXI_CONFIG_AWCACHE__SHIFT 8 > +#define VIVS_HI_AXI_CONFIG_AWCACHE(x) (((x) << > VIVS_HI_AXI_CONFIG_AWCACHE__SHIFT) & VIVS_HI_AXI_CONFIG_AWCACHE__MASK) > +#define VIVS_HI_AXI_CONFIG_ARCACHE__MASK 0x0000f000 > +#define VIVS_HI_AXI_CONFIG_ARCACHE__SHIFT 12 > +#define VIVS_HI_AXI_CONFIG_ARCACHE(x) (((x) << > VIVS_HI_AXI_CONFIG_ARCACHE__SHIFT) & VIVS_HI_AXI_CONFIG_ARCACHE__MASK) > + > +#define VIVS_HI_AXI_STATUS 0x0000000c > +#define VIVS_HI_AXI_STATUS_WR_ERR_ID__MASK 0x0000000f > +#define VIVS_HI_AXI_STATUS_WR_ERR_ID__SHIFT 0 > +#define VIVS_HI_AXI_STATUS_WR_ERR_ID(x) (((x) > << VIVS_HI_AXI_STATUS_WR_ERR_ID__SHIFT) & VIVS_HI_AXI_STATUS_WR_ERR_ID__MASK) > +#define VIVS_HI_AXI_STATUS_RD_ERR_ID__MASK 0x000000f0 > +#define VIVS_HI_AXI_STATUS_RD_ERR_ID__SHIFT 4 > +#define VIVS_HI_AXI_STATUS_RD_ERR_ID(x) (((x) > << VIVS_HI_AXI_STATUS_RD_ERR_ID__SHIFT) & VIVS_HI_AXI_STATUS_RD_ERR_ID__MASK) > +#define VIVS_HI_AXI_STATUS_DET_WR_ERR 0x00000100 > +#define VIVS_HI_AXI_STATUS_DET_RD_ERR 0x00000200 > + > +#define VIVS_HI_INTR_ACKNOWLEDGE 0x00000010 > +#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__MASK > 0x7fffffff > +#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__SHIFT 0 > +#define VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC(x) (((x) << > VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__SHIFT) & > VIVS_HI_INTR_ACKNOWLEDGE_INTR_VEC__MASK) > +#define VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR 0x80000000 > + > +#define VIVS_HI_INTR_ENBL 0x00000014 > +#define VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__MASK 0xffffffff > +#define VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__SHIFT 0 > +#define VIVS_HI_INTR_ENBL_INTR_ENBL_VEC(x) (((x) << > VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__SHIFT) & > VIVS_HI_INTR_ENBL_INTR_ENBL_VEC__MASK) > + > +#define VIVS_HI_CHIP_IDENTITY 0x00000018 > +#define VIVS_HI_CHIP_IDENTITY_FAMILY__MASK 0xff000000 > +#define VIVS_HI_CHIP_IDENTITY_FAMILY__SHIFT 24 > +#define VIVS_HI_CHIP_IDENTITY_FAMILY(x) (((x) > << VIVS_HI_CHIP_IDENTITY_FAMILY__SHIFT) & VIVS_HI_CHIP_IDENTITY_FAMILY__MASK) > +#define VIVS_HI_CHIP_IDENTITY_PRODUCT__MASK 0x00ff0000 > +#define VIVS_HI_CHIP_IDENTITY_PRODUCT__SHIFT 16 > +#define VIVS_HI_CHIP_IDENTITY_PRODUCT(x) (((x) << > VIVS_HI_CHIP_IDENTITY_PRODUCT__SHIFT) & VIVS_HI_CHIP_IDENTITY_PRODUCT__MASK) > +#define VIVS_HI_CHIP_IDENTITY_REVISION__MASK 0x0000f000 > +#define VIVS_HI_CHIP_IDENTITY_REVISION__SHIFT 12 > +#define VIVS_HI_CHIP_IDENTITY_REVISION(x) (((x) << > VIVS_HI_CHIP_IDENTITY_REVISION__SHIFT) & VIVS_HI_CHIP_IDENTITY_REVISION__MASK) > + > +#define VIVS_HI_CHIP_FEATURE 0x0000001c > + > +#define VIVS_HI_CHIP_MODEL 0x00000020 > + > +#define VIVS_HI_CHIP_REV 0x00000024 > + > +#define VIVS_HI_CHIP_DATE 0x00000028 > + > +#define VIVS_HI_CHIP_TIME 0x0000002c > + > +#define VIVS_HI_CHIP_MINOR_FEATURE_0 0x00000034 > + > +#define VIVS_HI_CACHE_CONTROL 0x00000038 > + > +#define VIVS_HI_MEMORY_COUNTER_RESET 0x0000003c > + > +#define VIVS_HI_PROFILE_READ_BYTES8 0x00000040 > + > +#define VIVS_HI_PROFILE_WRITE_BYTES8 0x00000044 > + > +#define VIVS_HI_CHIP_SPECS 0x00000048 > +#define VIVS_HI_CHIP_SPECS_STREAM_COUNT__MASK 0x0000000f > +#define VIVS_HI_CHIP_SPECS_STREAM_COUNT__SHIFT 0 > +#define VIVS_HI_CHIP_SPECS_STREAM_COUNT(x) (((x) << > VIVS_HI_CHIP_SPECS_STREAM_COUNT__SHIFT) & > VIVS_HI_CHIP_SPECS_STREAM_COUNT__MASK) > +#define VIVS_HI_CHIP_SPECS_REGISTER_MAX__MASK 0x000000f0 > +#define VIVS_HI_CHIP_SPECS_REGISTER_MAX__SHIFT 4 > +#define VIVS_HI_CHIP_SPECS_REGISTER_MAX(x) (((x) << > VIVS_HI_CHIP_SPECS_REGISTER_MAX__SHIFT) & > VIVS_HI_CHIP_SPECS_REGISTER_MAX__MASK) > +#define VIVS_HI_CHIP_SPECS_THREAD_COUNT__MASK 0x00000f00 > +#define VIVS_HI_CHIP_SPECS_THREAD_COUNT__SHIFT 8 > +#define VIVS_HI_CHIP_SPECS_THREAD_COUNT(x) (((x) << > VIVS_HI_CHIP_SPECS_THREAD_COUNT__SHIFT) & > VIVS_HI_CHIP_SPECS_THREAD_COUNT__MASK) > +#define VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__MASK 0x0001f000 > +#define VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__SHIFT 12 > +#define VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE(x) (((x) > << VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__SHIFT) & > VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE__MASK) > +#define VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__MASK 0x01f00000 > +#define VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__SHIFT 20 > +#define VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT(x) (((x) > << VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__SHIFT) & > VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT__MASK) > +#define VIVS_HI_CHIP_SPECS_PIXEL_PIPES__MASK 0x0e000000 > +#define VIVS_HI_CHIP_SPECS_PIXEL_PIPES__SHIFT 25 > +#define VIVS_HI_CHIP_SPECS_PIXEL_PIPES(x) (((x) << > VIVS_HI_CHIP_SPECS_PIXEL_PIPES__SHIFT) & VIVS_HI_CHIP_SPECS_PIXEL_PIPES__MASK) > +#define VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__MASK 0xf0000000 > +#define VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__SHIFT 28 > +#define VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE(x) (((x) > << VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__SHIFT) & > VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE__MASK) > + > +#define VIVS_HI_PROFILE_WRITE_BURSTS 0x0000004c > + > +#define VIVS_HI_PROFILE_WRITE_REQUESTS 0x00000050 > + > +#define VIVS_HI_PROFILE_READ_BURSTS 0x00000058 > + > +#define VIVS_HI_PROFILE_READ_REQUESTS 0x0000005c > + > +#define VIVS_HI_PROFILE_READ_LASTS 0x00000060 > + > +#define VIVS_HI_GP_OUT0 > 0x00000064 > + > +#define VIVS_HI_GP_OUT1 > 0x00000068 > + > +#define VIVS_HI_GP_OUT2 > 0x0000006c > + > +#define VIVS_HI_AXI_CONTROL 0x00000070 > +#define VIVS_HI_AXI_CONTROL_WR_FULL_BURST_MODE 0x00000001 > + > +#define VIVS_HI_CHIP_MINOR_FEATURE_1 0x00000074 > + > +#define VIVS_HI_PROFILE_TOTAL_CYCLES 0x00000078 > + > +#define VIVS_HI_PROFILE_IDLE_CYCLES 0x0000007c > + > +#define VIVS_HI_CHIP_SPECS_2 0x00000080 > +#define VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__MASK 0x000000ff > +#define VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__SHIFT 0 > +#define VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE(x) (((x) << > VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__SHIFT) & > VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE__MASK) > +#define VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__MASK 0x0000ff00 > +#define VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__SHIFT 8 > +#define VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT(x) (((x) << > VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__SHIFT) & > VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT__MASK) > +#define VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__MASK 0xffff0000 > +#define VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__SHIFT 16 > +#define VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS(x) (((x) << > VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__SHIFT) & > VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS__MASK) > + > +#define VIVS_HI_CHIP_MINOR_FEATURE_2 0x00000084 > + > +#define VIVS_HI_CHIP_MINOR_FEATURE_3 0x00000088 > + > +#define VIVS_HI_CHIP_MINOR_FEATURE_4 0x00000094 > + > +#define VIVS_PM > 0x00000000 > + > +#define VIVS_PM_POWER_CONTROLS 0x00000100 > +#define VIVS_PM_POWER_CONTROLS_ENABLE_MODULE_CLOCK_GATING 0x00000001 > +#define VIVS_PM_POWER_CONTROLS_DISABLE_STALL_MODULE_CLOCK_GATING > 0x00000002 > +#define VIVS_PM_POWER_CONTROLS_DISABLE_STARVE_MODULE_CLOCK_GATING > 0x00000004 > +#define VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__MASK 0x000000f0 > +#define VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__SHIFT 4 > +#define VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER(x) (((x) << > VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__SHIFT) & > VIVS_PM_POWER_CONTROLS_TURN_ON_COUNTER__MASK) > +#define VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__MASK 0xffff0000 > +#define VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__SHIFT 16 > +#define VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER(x) (((x) << > VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__SHIFT) & > VIVS_PM_POWER_CONTROLS_TURN_OFF_COUNTER__MASK) > + > +#define VIVS_PM_MODULE_CONTROLS > 0x00000104 > +#define VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_FE 0x00000001 > +#define VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_DE 0x00000002 > +#define VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_PE 0x00000004 > + > +#define VIVS_PM_MODULE_STATUS 0x00000108 > +#define VIVS_PM_MODULE_STATUS_MODULE_CLOCK_GATED_FE 0x00000001 > +#define VIVS_PM_MODULE_STATUS_MODULE_CLOCK_GATED_DE 0x00000002 > +#define VIVS_PM_MODULE_STATUS_MODULE_CLOCK_GATED_PE 0x00000004 > + > +#define VIVS_PM_PULSE_EATER 0x0000010c > + > +#define VIVS_MMUv2 0x00000000 > + > +#define VIVS_MMUv2_SAFE_ADDRESS > 0x00000180 > + > +#define VIVS_MMUv2_CONFIGURATION 0x00000184 > +#define VIVS_MMUv2_CONFIGURATION_MODE__MASK 0x00000001 > +#define VIVS_MMUv2_CONFIGURATION_MODE__SHIFT 0 > +#define VIVS_MMUv2_CONFIGURATION_MODE_MODE4_K 0x00000000 > +#define VIVS_MMUv2_CONFIGURATION_MODE_MODE1_K 0x00000001 > +#define VIVS_MMUv2_CONFIGURATION_MODE_MASK 0x00000008 > +#define VIVS_MMUv2_CONFIGURATION_FLUSH__MASK 0x00000010 > +#define VIVS_MMUv2_CONFIGURATION_FLUSH__SHIFT 4 > +#define VIVS_MMUv2_CONFIGURATION_FLUSH_FLUSH 0x00000010 > +#define VIVS_MMUv2_CONFIGURATION_FLUSH_MASK 0x00000080 > +#define VIVS_MMUv2_CONFIGURATION_ADDRESS_MASK 0x00000100 > +#define VIVS_MMUv2_CONFIGURATION_ADDRESS__MASK 0xfffffc00 > +#define VIVS_MMUv2_CONFIGURATION_ADDRESS__SHIFT 10 > +#define VIVS_MMUv2_CONFIGURATION_ADDRESS(x) (((x) << > VIVS_MMUv2_CONFIGURATION_ADDRESS__SHIFT) & > VIVS_MMUv2_CONFIGURATION_ADDRESS__MASK) > + > +#define VIVS_MMUv2_STATUS 0x00000188 > +#define VIVS_MMUv2_STATUS_EXCEPTION0__MASK 0x00000003 > +#define VIVS_MMUv2_STATUS_EXCEPTION0__SHIFT 0 > +#define VIVS_MMUv2_STATUS_EXCEPTION0(x) (((x) > << VIVS_MMUv2_STATUS_EXCEPTION0__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION0__MASK) > +#define VIVS_MMUv2_STATUS_EXCEPTION1__MASK 0x00000030 > +#define VIVS_MMUv2_STATUS_EXCEPTION1__SHIFT 4 > +#define VIVS_MMUv2_STATUS_EXCEPTION1(x) (((x) > << VIVS_MMUv2_STATUS_EXCEPTION1__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION1__MASK) > +#define VIVS_MMUv2_STATUS_EXCEPTION2__MASK 0x00000300 > +#define VIVS_MMUv2_STATUS_EXCEPTION2__SHIFT 8 > +#define VIVS_MMUv2_STATUS_EXCEPTION2(x) (((x) > << VIVS_MMUv2_STATUS_EXCEPTION2__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION2__MASK) > +#define VIVS_MMUv2_STATUS_EXCEPTION3__MASK 0x00003000 > +#define VIVS_MMUv2_STATUS_EXCEPTION3__SHIFT 12 > +#define VIVS_MMUv2_STATUS_EXCEPTION3(x) (((x) > << VIVS_MMUv2_STATUS_EXCEPTION3__SHIFT) & VIVS_MMUv2_STATUS_EXCEPTION3__MASK) > + > +#define VIVS_MMUv2_CONTROL 0x0000018c > +#define VIVS_MMUv2_CONTROL_ENABLE 0x00000001 > + > +#define VIVS_MMUv2_EXCEPTION_ADDR(i0) (0x00000190 + > 0x4*(i0)) > +#define VIVS_MMUv2_EXCEPTION_ADDR__ESIZE 0x00000004 > +#define VIVS_MMUv2_EXCEPTION_ADDR__LEN 0x00000004 > + > +#define VIVS_MC > 0x00000000 > + > +#define VIVS_MC_MMU_FE_PAGE_TABLE 0x00000400 > + > +#define VIVS_MC_MMU_TX_PAGE_TABLE 0x00000404 > + > +#define VIVS_MC_MMU_PE_PAGE_TABLE 0x00000408 > + > +#define VIVS_MC_MMU_PEZ_PAGE_TABLE 0x0000040c > + > +#define VIVS_MC_MMU_RA_PAGE_TABLE 0x00000410 > + > +#define VIVS_MC_DEBUG_MEMORY 0x00000414 > +#define VIVS_MC_DEBUG_MEMORY_SPECIAL_PATCH_GC320 0x00000008 > +#define VIVS_MC_DEBUG_MEMORY_FAST_CLEAR_BYPASS 0x00100000 > +#define VIVS_MC_DEBUG_MEMORY_COMPRESSION_BYPASS > 0x00200000 > + > +#define VIVS_MC_MEMORY_BASE_ADDR_RA 0x00000418 > + > +#define VIVS_MC_MEMORY_BASE_ADDR_FE 0x0000041c > + > +#define VIVS_MC_MEMORY_BASE_ADDR_TX 0x00000420 > + > +#define VIVS_MC_MEMORY_BASE_ADDR_PEZ 0x00000424 > + > +#define VIVS_MC_MEMORY_BASE_ADDR_PE 0x00000428 > + > +#define VIVS_MC_MEMORY_TIMING_CONTROL 0x0000042c > + > +#define VIVS_MC_MEMORY_FLUSH 0x00000430 > + > +#define VIVS_MC_PROFILE_CYCLE_COUNTER 0x00000438 > + > +#define VIVS_MC_DEBUG_READ0 0x0000043c > + > +#define VIVS_MC_DEBUG_READ1 0x00000440 > + > +#define VIVS_MC_DEBUG_WRITE 0x00000444 > + > +#define VIVS_MC_PROFILE_RA_READ > 0x00000448 > + > +#define VIVS_MC_PROFILE_TX_READ > 0x0000044c > + > +#define VIVS_MC_PROFILE_FE_READ > 0x00000450 > + > +#define VIVS_MC_PROFILE_PE_READ > 0x00000454 > + > +#define VIVS_MC_PROFILE_DE_READ > 0x00000458 > + > +#define VIVS_MC_PROFILE_SH_READ > 0x0000045c > + > +#define VIVS_MC_PROFILE_PA_READ > 0x00000460 > + > +#define VIVS_MC_PROFILE_SE_READ > 0x00000464 > + > +#define VIVS_MC_PROFILE_MC_READ > 0x00000468 > + > +#define VIVS_MC_PROFILE_HI_READ > 0x0000046c > + > +#define VIVS_MC_PROFILE_CONFIG0 > 0x00000470 > +#define VIVS_MC_PROFILE_CONFIG0_FE__MASK 0x0000000f > +#define VIVS_MC_PROFILE_CONFIG0_FE__SHIFT 0 > +#define VIVS_MC_PROFILE_CONFIG0_FE_RESET 0x0000000f > +#define VIVS_MC_PROFILE_CONFIG0_DE__MASK 0x00000f00 > +#define VIVS_MC_PROFILE_CONFIG0_DE__SHIFT 8 > +#define VIVS_MC_PROFILE_CONFIG0_DE_RESET 0x00000f00 > +#define VIVS_MC_PROFILE_CONFIG0_PE__MASK 0x000f0000 > +#define VIVS_MC_PROFILE_CONFIG0_PE__SHIFT 16 > +#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_COLOR_PIPE > 0x00000000 > +#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_DEPTH_PIPE > 0x00010000 > +#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_COLOR_PIPE > 0x00020000 > +#define VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE > 0x00030000 > +#define VIVS_MC_PROFILE_CONFIG0_PE_PIXELS_RENDERED_2D 0x000b0000 > +#define VIVS_MC_PROFILE_CONFIG0_PE_RESET 0x000f0000 > +#define VIVS_MC_PROFILE_CONFIG0_SH__MASK 0x0f000000 > +#define VIVS_MC_PROFILE_CONFIG0_SH__SHIFT 24 > +#define VIVS_MC_PROFILE_CONFIG0_SH_SHADER_CYCLES 0x04000000 > +#define VIVS_MC_PROFILE_CONFIG0_SH_PS_INST_COUNTER 0x07000000 > +#define VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_PIXEL_COUNTER 0x08000000 > +#define VIVS_MC_PROFILE_CONFIG0_SH_VS_INST_COUNTER 0x09000000 > +#define VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_VERTICE_COUNTER 0x0a000000 > +#define VIVS_MC_PROFILE_CONFIG0_SH_VTX_BRANCH_INST_COUNTER 0x0b000000 > +#define VIVS_MC_PROFILE_CONFIG0_SH_VTX_TEXLD_INST_COUNTER 0x0c000000 > +#define VIVS_MC_PROFILE_CONFIG0_SH_PXL_BRANCH_INST_COUNTER 0x0d000000 > +#define VIVS_MC_PROFILE_CONFIG0_SH_PXL_TEXLD_INST_COUNTER 0x0e000000 > +#define VIVS_MC_PROFILE_CONFIG0_SH_RESET 0x0f000000 > + > +#define VIVS_MC_PROFILE_CONFIG1 > 0x00000474 > +#define VIVS_MC_PROFILE_CONFIG1_PA__MASK 0x0000000f > +#define VIVS_MC_PROFILE_CONFIG1_PA__SHIFT 0 > +#define VIVS_MC_PROFILE_CONFIG1_PA_INPUT_VTX_COUNTER 0x00000003 > +#define VIVS_MC_PROFILE_CONFIG1_PA_INPUT_PRIM_COUNTER 0x00000004 > +#define VIVS_MC_PROFILE_CONFIG1_PA_OUTPUT_PRIM_COUNTER 0x00000005 > +#define VIVS_MC_PROFILE_CONFIG1_PA_DEPTH_CLIPPED_COUNTER 0x00000006 > +#define VIVS_MC_PROFILE_CONFIG1_PA_TRIVIAL_REJECTED_COUNTER 0x00000007 > +#define VIVS_MC_PROFILE_CONFIG1_PA_CULLED_COUNTER 0x00000008 > +#define VIVS_MC_PROFILE_CONFIG1_PA_RESET 0x0000000f > +#define VIVS_MC_PROFILE_CONFIG1_SE__MASK 0x00000f00 > +#define VIVS_MC_PROFILE_CONFIG1_SE__SHIFT 8 > +#define VIVS_MC_PROFILE_CONFIG1_SE_CULLED_TRIANGLE_COUNT 0x00000000 > +#define VIVS_MC_PROFILE_CONFIG1_SE_CULLED_LINES_COUNT 0x00000100 > +#define VIVS_MC_PROFILE_CONFIG1_SE_RESET 0x00000f00 > +#define VIVS_MC_PROFILE_CONFIG1_RA__MASK 0x000f0000 > +#define VIVS_MC_PROFILE_CONFIG1_RA__SHIFT 16 > +#define VIVS_MC_PROFILE_CONFIG1_RA_VALID_PIXEL_COUNT 0x00000000 > +#define VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_QUAD_COUNT 0x00010000 > +#define VIVS_MC_PROFILE_CONFIG1_RA_VALID_QUAD_COUNT_AFTER_EARLY_Z > 0x00020000 > +#define VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_PRIMITIVE_COUNT 0x00030000 > +#define VIVS_MC_PROFILE_CONFIG1_RA_PIPE_CACHE_MISS_COUNTER 0x00090000 > +#define VIVS_MC_PROFILE_CONFIG1_RA_PREFETCH_CACHE_MISS_COUNTER 0x000a0000 > +#define VIVS_MC_PROFILE_CONFIG1_RA_CULLED_QUAD_COUNT 0x000b0000 > +#define VIVS_MC_PROFILE_CONFIG1_RA_RESET 0x000f0000 > +#define VIVS_MC_PROFILE_CONFIG1_TX__MASK 0x0f000000 > +#define VIVS_MC_PROFILE_CONFIG1_TX__SHIFT 24 > +#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_BILINEAR_REQUESTS 0x00000000 > +#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TRILINEAR_REQUESTS 0x01000000 > +#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_DISCARDED_TEXTURE_REQUESTS > 0x02000000 > +#define VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TEXTURE_REQUESTS 0x03000000 > +#define VIVS_MC_PROFILE_CONFIG1_TX_UNKNOWN 0x04000000 > +#define VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_COUNT 0x05000000 > +#define VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_IN_8B_COUNT > 0x06000000 > +#define VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_COUNT 0x07000000 > +#define VIVS_MC_PROFILE_CONFIG1_TX_CACHE_HIT_TEXEL_COUNT 0x08000000 > +#define VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_TEXEL_COUNT 0x09000000 > +#define VIVS_MC_PROFILE_CONFIG1_TX_RESET 0x0f000000 > + > +#define VIVS_MC_PROFILE_CONFIG2 > 0x00000478 > +#define VIVS_MC_PROFILE_CONFIG2_MC__MASK 0x0000000f > +#define VIVS_MC_PROFILE_CONFIG2_MC__SHIFT 0 > +#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_PIPELINE > 0x00000001 > +#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_IP 0x00000002 > +#define VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_WRITE_REQ_8B_FROM_PIPELINE > 0x00000003 > +#define VIVS_MC_PROFILE_CONFIG2_MC_RESET 0x0000000f > +#define VIVS_MC_PROFILE_CONFIG2_HI__MASK 0x00000f00 > +#define VIVS_MC_PROFILE_CONFIG2_HI__SHIFT 8 > +#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_READ_REQUEST_STALLED > 0x00000000 > +#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_REQUEST_STALLED > 0x00000100 > +#define VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_DATA_STALLED > 0x00000200 > +#define VIVS_MC_PROFILE_CONFIG2_HI_RESET 0x00000f00 > + > +#define VIVS_MC_PROFILE_CONFIG3 > 0x0000047c > + > +#define VIVS_MC_BUS_CONFIG 0x00000480 > +#define VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK 0x0000000f > +#define VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__SHIFT 0 > +#define VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG(x) (((x) << > VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__SHIFT) & > VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK) > +#define VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK 0x000000f0 > +#define VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__SHIFT 4 > +#define VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG(x) (((x) << > VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__SHIFT) & > VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK) > + > +#define VIVS_MC_START_COMPOSITION 0x00000554 > + > +#define VIVS_MC_128B_MERGE 0x00000558 > + > + > +#endif /* STATE_HI_XML */ > diff --git a/include/uapi/drm/etnaviv_drm.h b/include/uapi/drm/etnaviv_drm.h > new file mode 100644 > index 000000000000..5f1206b3f9ba > --- /dev/null > +++ b/include/uapi/drm/etnaviv_drm.h > @@ -0,0 +1,215 @@ > +/* > + * Copyright (C) 2015 Etnaviv Project > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > by > + * the Free Software Foundation. > + * > + * 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, see <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef __ETNAVIV_DRM_H__ > +#define __ETNAVIV_DRM_H__ > + > +#include <drm/drm.h> > + > +/* Please note that modifications to all structs defined here are > + * subject to backwards-compatibility constraints: > + * 1) Do not use pointers, use __u64 instead for 32 bit / 64 bit > + * user/kernel compatibility > + * 2) Keep fields aligned to their size > + * 3) Because of how drm_ioctl() works, we can add new fields at > + * the end of an ioctl if some care is taken: drm_ioctl() will > + * zero out the new fields at the tail of the ioctl, so a zero > + * value should have a backwards compatible meaning. And for > + * output params, userspace won't see the newly added output > + * fields.. so that has to be somehow ok. > + */ > + > +/* timeouts are specified in clock-monotonic absolute times (to simplify > + * restarting interrupted ioctls). The following struct is logically the > + * same as 'struct timespec' but 32/64b ABI safe. > + */ > +struct drm_etnaviv_timespec { > + __s64 tv_sec; /* seconds */ > + __s64 tv_nsec; /* nanoseconds */ > +}; > + > +#define ETNAVIV_PARAM_GPU_MODEL 0x01 > +#define ETNAVIV_PARAM_GPU_REVISION 0x02 > +#define ETNAVIV_PARAM_GPU_FEATURES_0 0x03 > +#define ETNAVIV_PARAM_GPU_FEATURES_1 0x04 > +#define ETNAVIV_PARAM_GPU_FEATURES_2 0x05 > +#define ETNAVIV_PARAM_GPU_FEATURES_3 0x06 > +#define ETNAVIV_PARAM_GPU_FEATURES_4 0x07 > + > +#define ETNAVIV_PARAM_GPU_STREAM_COUNT 0x10 > +#define ETNAVIV_PARAM_GPU_REGISTER_MAX 0x11 > +#define ETNAVIV_PARAM_GPU_THREAD_COUNT 0x12 > +#define ETNAVIV_PARAM_GPU_VERTEX_CACHE_SIZE 0x13 > +#define ETNAVIV_PARAM_GPU_SHADER_CORE_COUNT 0x14 > +#define ETNAVIV_PARAM_GPU_PIXEL_PIPES 0x15 > +#define ETNAVIV_PARAM_GPU_VERTEX_OUTPUT_BUFFER_SIZE 0x16 > +#define ETNAVIV_PARAM_GPU_BUFFER_SIZE 0x17 > +#define ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT 0x18 > +#define ETNAVIV_PARAM_GPU_NUM_CONSTANTS 0x19 > + > +#define ETNA_MAX_PIPES 4 > + > +struct drm_etnaviv_param { > + __u32 pipe; /* in */ > + __u32 param; /* in, ETNAVIV_PARAM_x */ > + __u64 value; /* out (get_param) or in (set_param) */ > +}; > + > +/* > + * GEM buffers: > + */ > + > +#define ETNA_BO_CACHE_MASK 0x000f0000 > +/* cache modes */ > +#define ETNA_BO_CACHED 0x00010000 > +#define ETNA_BO_WC 0x00020000 > +#define ETNA_BO_UNCACHED 0x00040000 > +/* map flags */ > +#define ETNA_BO_FORCE_MMU 0x00100000 > + > +struct drm_etnaviv_gem_new { > + __u64 size; /* in */ > + __u32 flags; /* in, mask of ETNA_BO_x */ > + __u32 handle; /* out */ > +}; > + > +struct drm_etnaviv_gem_info { > + __u32 handle; /* in */ > + __u32 pad; > + __u64 offset; /* out, offset to pass to mmap() */ > +}; > + > +#define ETNA_PREP_READ 0x01 > +#define ETNA_PREP_WRITE 0x02 > +#define ETNA_PREP_NOSYNC 0x04 > + > +struct drm_etnaviv_gem_cpu_prep { > + __u32 handle; /* in */ > + __u32 op; /* in, mask of ETNA_PREP_x */ > + struct drm_etnaviv_timespec timeout; /* in */ > +}; > + > +struct drm_etnaviv_gem_cpu_fini { > + __u32 handle; /* in */ > +}; > + > +/* > + * Cmdstream Submission: > + */ > + > +/* The value written into the cmdstream is logically: > + * relocbuf->gpuaddr + reloc_offset > + * > + * NOTE that reloc's must be sorted by order of increasing submit_offset, > + * otherwise EINVAL. > + */ > +struct drm_etnaviv_gem_submit_reloc { > + __u32 submit_offset; /* in, offset from submit_bo */ > + __u32 reloc_idx; /* in, index of reloc_bo buffer */ > + __u64 reloc_offset; /* in, offset from start of reloc_bo */ > +}; > + > +/* Each buffer referenced elsewhere in the cmdstream submit (ie. the > + * cmdstream buffer(s) themselves or reloc entries) has one (and only > + * one) entry in the submit->bos[] table. > + * > + * As a optimization, the current buffer (gpu virtual address) can be > + * passed back through the 'presumed' field. If on a subsequent reloc, > + * userspace passes back a 'presumed' address that is still valid, > + * then patching the cmdstream for this entry is skipped. This can > + * avoid kernel needing to map/access the cmdstream bo in the common > + * case. > + */ > +#define ETNA_SUBMIT_BO_READ 0x0001 > +#define ETNA_SUBMIT_BO_WRITE 0x0002 > +struct drm_etnaviv_gem_submit_bo { > + __u32 flags; /* in, mask of ETNA_SUBMIT_BO_x */ > + __u32 handle; /* in, GEM handle */ > + __u64 presumed; /* in/out, presumed buffer address */ > +}; > + > +/* Each cmdstream submit consists of a table of buffers involved, and > + * one or more cmdstream buffers. This allows for conditional execution > + * (context-restore), and IB buffers needed for per tile/bin draw cmds. > + */ > +#define ETNA_PIPE_3D 0x00 > +#define ETNA_PIPE_2D 0x01 > +#define ETNA_PIPE_VG 0x02 > +struct drm_etnaviv_gem_submit { > + __u32 fence; /* out */ > + __u32 pipe; /* in */ > + __u32 exec_state; /* in, initial execution state (ETNA_PIPE_x) */ > + __u32 nr_bos; /* in, number of submit_bo's */ > + __u32 nr_relocs; /* in, number of submit_reloc's */ > + __u32 stream_size; /* in, cmdstream size */ > + __u64 bos; /* in, ptr to array of submit_bo's */ > + __u64 relocs; /* in, ptr to array of submit_reloc's */ > + __u64 stream; /* in, ptr to cmdstream */ > +}; > + > +/* The normal way to synchronize with the GPU is just to CPU_PREP on > + * a buffer if you need to access it from the CPU (other cmdstream > + * submission from same or other contexts, PAGE_FLIP ioctl, etc, all > + * handle the required synchronization under the hood). This ioctl > + * mainly just exists as a way to implement the gallium pipe_fence > + * APIs without requiring a dummy bo to synchronize on. > + */ > +struct drm_etnaviv_wait_fence { > + __u32 pipe; /* in */ > + __u32 fence; /* in */ > + struct drm_etnaviv_timespec timeout; /* in */ > +}; > + > +#define ETNA_USERPTR_READ 0x01 > +#define ETNA_USERPTR_WRITE 0x02 > +struct drm_etnaviv_gem_userptr { > + __u64 user_ptr; /* in, page aligned user pointer */ > + __u64 user_size; /* in, page aligned user size */ > + __u32 flags; /* in, flags */ > + __u32 handle; /* out, non-zero handle */ > +}; > + > +struct drm_etnaviv_gem_wait { > + __u32 pipe; /* in */ > + __u32 handle; /* in, bo to be waited for */ > + struct drm_etnaviv_timespec timeout; /* in */ > +}; > + > +#define DRM_ETNAVIV_GET_PARAM 0x00 > +/* placeholder: > +#define DRM_ETNAVIV_SET_PARAM 0x01 > + */ > +#define DRM_ETNAVIV_GEM_NEW 0x02 > +#define DRM_ETNAVIV_GEM_INFO 0x03 > +#define DRM_ETNAVIV_GEM_CPU_PREP 0x04 > +#define DRM_ETNAVIV_GEM_CPU_FINI 0x05 > +#define DRM_ETNAVIV_GEM_SUBMIT 0x06 > +#define DRM_ETNAVIV_WAIT_FENCE 0x07 > +#define DRM_ETNAVIV_GEM_USERPTR 0x08 > +#define DRM_ETNAVIV_GEM_WAIT 0x09 > +#define DRM_ETNAVIV_NUM_IOCTLS 0x0a > + > +#define DRM_IOCTL_ETNAVIV_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + > DRM_ETNAVIV_GET_PARAM, struct drm_etnaviv_param) > +#define DRM_IOCTL_ETNAVIV_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + > DRM_ETNAVIV_GEM_NEW, struct drm_etnaviv_gem_new) > +#define DRM_IOCTL_ETNAVIV_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + > DRM_ETNAVIV_GEM_INFO, struct drm_etnaviv_gem_info) > +#define DRM_IOCTL_ETNAVIV_GEM_CPU_PREP DRM_IOW(DRM_COMMAND_BASE + > DRM_ETNAVIV_GEM_CPU_PREP, struct drm_etnaviv_gem_cpu_prep) > +#define DRM_IOCTL_ETNAVIV_GEM_CPU_FINI DRM_IOW(DRM_COMMAND_BASE + > DRM_ETNAVIV_GEM_CPU_FINI, struct drm_etnaviv_gem_cpu_fini) > +#define DRM_IOCTL_ETNAVIV_GEM_SUBMIT DRM_IOWR(DRM_COMMAND_BASE + > DRM_ETNAVIV_GEM_SUBMIT, struct drm_etnaviv_gem_submit) > +#define DRM_IOCTL_ETNAVIV_WAIT_FENCE DRM_IOW(DRM_COMMAND_BASE + > DRM_ETNAVIV_WAIT_FENCE, struct drm_etnaviv_wait_fence) > +#define DRM_IOCTL_ETNAVIV_GEM_USERPTR DRM_IOWR(DRM_COMMAND_BASE + > DRM_ETNAVIV_GEM_USERPTR, struct drm_etnaviv_gem_userptr) > +#define DRM_IOCTL_ETNAVIV_GEM_WAIT DRM_IOW(DRM_COMMAND_BASE + > DRM_ETNAVIV_GEM_WAIT, struct drm_etnaviv_gem_wait) > + > +#endif /* __ETNAVIV_DRM_H__ */ > -- > 2.5.0 > > _______________________________________________ > dri-devel mailing list > dri-devel at lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/dri-devel