/* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only 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. * */ #ifndef __ADRENO_H #define __ADRENO_H #include "kgsl_device.h" #include "adreno_drawctxt.h" #include "adreno_ringbuffer.h" #include "kgsl_iommu.h" #include #include "a3xx_reg.h" #define DEVICE_3D_NAME "kgsl-3d" #define DEVICE_3D0_NAME "kgsl-3d0" #define ADRENO_DEVICE(device) \ KGSL_CONTAINER_OF(device, struct adreno_device, dev) #define ADRENO_CHIPID_CORE(_id) (((_id) >> 24) & 0xFF) #define ADRENO_CHIPID_MAJOR(_id) (((_id) >> 16) & 0xFF) #define ADRENO_CHIPID_MINOR(_id) (((_id) >> 8) & 0xFF) #define ADRENO_CHIPID_PATCH(_id) ((_id) & 0xFF) /* Flags to control command packet settings */ #define KGSL_CMD_FLAGS_NONE 0x00000000 #define KGSL_CMD_FLAGS_PMODE 0x00000001 #define KGSL_CMD_FLAGS_INTERNAL_ISSUE 0x00000002 #define KGSL_CMD_FLAGS_GET_INT 0x00000004 #define KGSL_CMD_FLAGS_EOF 0x00000100 /* Command identifiers */ #define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0x2EADBEEF #define KGSL_CMD_IDENTIFIER 0x2EEDFACE #define KGSL_CMD_INTERNAL_IDENTIFIER 0x2EEDD00D #define KGSL_START_OF_IB_IDENTIFIER 0x2EADEABE #define KGSL_END_OF_IB_IDENTIFIER 0x2ABEDEAD #define KGSL_END_OF_FRAME_IDENTIFIER 0x2E0F2E0F #define KGSL_NOP_IB_IDENTIFIER 0x20F20F20 #ifdef CONFIG_MSM_SCM #define ADRENO_DEFAULT_PWRSCALE_POLICY (&kgsl_pwrscale_policy_tz) #elif defined CONFIG_MSM_SLEEP_STATS_DEVICE #define ADRENO_DEFAULT_PWRSCALE_POLICY (&kgsl_pwrscale_policy_idlestats) #else #define ADRENO_DEFAULT_PWRSCALE_POLICY NULL #endif void adreno_debugfs_init(struct kgsl_device *device); #define ADRENO_ISTORE_START 0x5000 /* Istore offset */ #define ADRENO_NUM_CTX_SWITCH_ALLOWED_BEFORE_DRAW 50 /* One cannot wait forever for the core to idle, so set an upper limit to the * amount of time to wait for the core to go idle */ #define ADRENO_IDLE_TIMEOUT (20 * 1000) enum adreno_gpurev { ADRENO_REV_UNKNOWN = 0, ADRENO_REV_A200 = 200, ADRENO_REV_A203 = 203, ADRENO_REV_A205 = 205, ADRENO_REV_A220 = 220, ADRENO_REV_A225 = 225, ADRENO_REV_A305 = 305, ADRENO_REV_A305C = 306, ADRENO_REV_A320 = 320, ADRENO_REV_A330 = 330, ADRENO_REV_A305B = 335, }; enum coresight_debug_reg { DEBUG_BUS_CTL, TRACE_STOP_CNT, TRACE_START_CNT, TRACE_PERIOD_CNT, TRACE_CMD, TRACE_BUS_CTL, }; struct adreno_gpudev; struct adreno_device { struct kgsl_device dev; /* Must be first field in this struct */ unsigned int chip_id; enum adreno_gpurev gpurev; unsigned long gmem_base; unsigned int gmem_size; struct adreno_context *drawctxt_active; const char *pfp_fwfile; unsigned int *pfp_fw; size_t pfp_fw_size; unsigned int pfp_fw_version; const char *pm4_fwfile; unsigned int *pm4_fw; size_t pm4_fw_size; unsigned int pm4_fw_version; struct adreno_ringbuffer ringbuffer; unsigned int mharb; struct adreno_gpudev *gpudev; unsigned int wait_timeout; unsigned int pm4_jt_idx; unsigned int pm4_jt_addr; unsigned int pfp_jt_idx; unsigned int pfp_jt_addr; unsigned int istore_size; unsigned int pix_shader_start; unsigned int instruction_size; unsigned int ib_check_level; unsigned int fast_hang_detect; unsigned int ft_policy; unsigned int long_ib_detect; unsigned int long_ib; unsigned int long_ib_ts; unsigned int ft_pf_policy; unsigned int gpulist_index; struct ocmem_buf *ocmem_hdl; unsigned int ocmem_base; unsigned int gpu_cycles; }; #define PERFCOUNTER_FLAG_NONE 0x0 #define PERFCOUNTER_FLAG_KERNEL 0x1 /* Structs to maintain the list of active performance counters */ /** * struct adreno_perfcount_register: register state * @countable: countable the register holds * @refcount: number of users of the register * @offset: register hardware offset */ struct adreno_perfcount_register { unsigned int countable; unsigned int refcount; unsigned int offset; unsigned int flags; }; /** * struct adreno_perfcount_group: registers for a hardware group * @regs: available registers for this group * @reg_count: total registers for this group */ struct adreno_perfcount_group { struct adreno_perfcount_register *regs; unsigned int reg_count; }; /** * adreno_perfcounts: all available perfcounter groups * @groups: available groups for this device * @group_count: total groups for this device */ struct adreno_perfcounters { struct adreno_perfcount_group *groups; unsigned int group_count; }; struct adreno_gpudev { /* * These registers are in a different location on A3XX, so define * them in the structure and use them as variables. */ unsigned int reg_rbbm_status; unsigned int reg_cp_pfp_ucode_data; unsigned int reg_cp_pfp_ucode_addr; /* keeps track of when we need to execute the draw workaround code */ int ctx_switches_since_last_draw; struct adreno_perfcounters *perfcounters; /* GPU specific function hooks */ int (*ctxt_create)(struct adreno_device *, struct adreno_context *); void (*ctxt_save)(struct adreno_device *, struct adreno_context *); void (*ctxt_restore)(struct adreno_device *, struct adreno_context *); void (*ctxt_draw_workaround)(struct adreno_device *, struct adreno_context *); irqreturn_t (*irq_handler)(struct adreno_device *); void (*irq_control)(struct adreno_device *, int); unsigned int (*irq_pending)(struct adreno_device *); void * (*snapshot)(struct adreno_device *, void *, int *, int); int (*rb_init)(struct adreno_device *, struct adreno_ringbuffer *); void (*perfcounter_init)(struct adreno_device *); void (*start)(struct adreno_device *); unsigned int (*busy_cycles)(struct adreno_device *); void (*perfcounter_enable)(struct adreno_device *, unsigned int group, unsigned int counter, unsigned int countable); uint64_t (*perfcounter_read)(struct adreno_device *adreno_dev, unsigned int group, unsigned int counter, unsigned int offset); int (*coresight_enable) (struct kgsl_device *device); void (*coresight_disable) (struct kgsl_device *device); void (*coresight_config_debug_reg) (struct kgsl_device *device, int debug_reg, unsigned int val); void (*soft_reset)(struct adreno_device *device); }; /* * struct adreno_ft_data - Structure that contains all information to * perform gpu fault tolerance * @ib1 - IB1 that the GPU was executing when hang happened * @context_id - Context which caused the hang * @global_eop - eoptimestamp at time of hang * @rb_buffer - Buffer that holds the commands from good contexts * @rb_size - Number of valid dwords in rb_buffer * @bad_rb_buffer - Buffer that holds commands from the hanging context * bad_rb_size - Number of valid dwords in bad_rb_buffer * @good_rb_buffer - Buffer that holds commands from good contexts * good_rb_size - Number of valid dwords in good_rb_buffer * @last_valid_ctx_id - The last context from which commands were placed in * ringbuffer before the GPU hung * @step - Current fault tolerance step being executed * @err_code - Fault tolerance error code * @fault - Indicates whether the hang was caused due to a pagefault * @start_of_replay_cmds - Offset in ringbuffer from where commands can be * replayed during fault tolerance * @replay_for_snapshot - Offset in ringbuffer where IB's can be saved for * replaying with snapshot */ struct adreno_ft_data { unsigned int ib1; unsigned int context_id; unsigned int global_eop; unsigned int *rb_buffer; unsigned int rb_size; unsigned int *bad_rb_buffer; unsigned int bad_rb_size; unsigned int *good_rb_buffer; unsigned int good_rb_size; unsigned int last_valid_ctx_id; unsigned int status; unsigned int ft_policy; unsigned int err_code; unsigned int start_of_replay_cmds; unsigned int replay_for_snapshot; }; #define FT_DETECT_REGS_COUNT 12 /* Fault Tolerance policy flags */ #define KGSL_FT_DISABLE BIT(0) #define KGSL_FT_REPLAY BIT(1) #define KGSL_FT_SKIPIB BIT(2) #define KGSL_FT_SKIPFRAME BIT(3) #define KGSL_FT_TEMP_DISABLE BIT(4) #define KGSL_FT_DEFAULT_POLICY (KGSL_FT_REPLAY + KGSL_FT_SKIPIB) /* Pagefault policy flags */ #define KGSL_FT_PAGEFAULT_INT_ENABLE 0x00000001 #define KGSL_FT_PAGEFAULT_GPUHALT_ENABLE 0x00000002 #define KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE 0x00000004 #define KGSL_FT_PAGEFAULT_LOG_ONE_PER_INT 0x00000008 #define KGSL_FT_PAGEFAULT_DEFAULT_POLICY (KGSL_FT_PAGEFAULT_INT_ENABLE + \ KGSL_FT_PAGEFAULT_GPUHALT_ENABLE) extern struct adreno_gpudev adreno_a2xx_gpudev; extern struct adreno_gpudev adreno_a3xx_gpudev; /* A2XX register sets defined in adreno_a2xx.c */ extern const unsigned int a200_registers[]; extern const unsigned int a220_registers[]; extern const unsigned int a225_registers[]; extern const unsigned int a200_registers_count; extern const unsigned int a220_registers_count; extern const unsigned int a225_registers_count; /* A3XX register set defined in adreno_a3xx.c */ extern const unsigned int a3xx_registers[]; extern const unsigned int a3xx_registers_count; extern const unsigned int a3xx_hlsq_registers[]; extern const unsigned int a3xx_hlsq_registers_count; extern const unsigned int a330_registers[]; extern const unsigned int a330_registers_count; extern unsigned int ft_detect_regs[]; int adreno_coresight_enable(struct coresight_device *csdev); void adreno_coresight_disable(struct coresight_device *csdev); void adreno_coresight_remove(struct platform_device *pdev); int adreno_coresight_init(struct platform_device *pdev); int adreno_idle(struct kgsl_device *device); void adreno_regread(struct kgsl_device *device, unsigned int offsetwords, unsigned int *value); void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords, unsigned int value); void adreno_shadermem_regread(struct kgsl_device *device, unsigned int offsetwords, unsigned int *value); int adreno_dump(struct kgsl_device *device, int manual); unsigned int adreno_a3xx_rbbm_clock_ctl_default(struct adreno_device *adreno_dev); struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device, phys_addr_t pt_base, unsigned int gpuaddr, unsigned int size); uint8_t *adreno_convertaddr(struct kgsl_device *device, phys_addr_t pt_base, unsigned int gpuaddr, unsigned int size); struct kgsl_memdesc *adreno_find_ctxtmem(struct kgsl_device *device, phys_addr_t pt_base, unsigned int gpuaddr, unsigned int size); void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain, int hang); int adreno_dump_and_exec_ft(struct kgsl_device *device); void adreno_dump_rb(struct kgsl_device *device, const void *buf, size_t len, int start, int size); unsigned int adreno_ft_detect(struct kgsl_device *device, unsigned int *prev_reg_val); int adreno_perfcounter_get(struct adreno_device *adreno_dev, unsigned int groupid, unsigned int countable, unsigned int *offset, unsigned int flags); int adreno_perfcounter_put(struct adreno_device *adreno_dev, unsigned int groupid, unsigned int countable); int adreno_soft_reset(struct kgsl_device *device); static inline int adreno_is_a200(struct adreno_device *adreno_dev) { return (adreno_dev->gpurev == ADRENO_REV_A200); } static inline int adreno_is_a203(struct adreno_device *adreno_dev) { return (adreno_dev->gpurev == ADRENO_REV_A203); } static inline int adreno_is_a205(struct adreno_device *adreno_dev) { return (adreno_dev->gpurev == ADRENO_REV_A205); } static inline int adreno_is_a20x(struct adreno_device *adreno_dev) { return (adreno_dev->gpurev <= 209); } static inline int adreno_is_a220(struct adreno_device *adreno_dev) { return (adreno_dev->gpurev == ADRENO_REV_A220); } static inline int adreno_is_a225(struct adreno_device *adreno_dev) { return (adreno_dev->gpurev == ADRENO_REV_A225); } static inline int adreno_is_a22x(struct adreno_device *adreno_dev) { return (adreno_dev->gpurev == ADRENO_REV_A220 || adreno_dev->gpurev == ADRENO_REV_A225); } static inline int adreno_is_a2xx(struct adreno_device *adreno_dev) { return (adreno_dev->gpurev <= 299); } static inline int adreno_is_a3xx(struct adreno_device *adreno_dev) { return (adreno_dev->gpurev >= 300); } static inline int adreno_is_a305(struct adreno_device *adreno_dev) { return (adreno_dev->gpurev == ADRENO_REV_A305); } static inline int adreno_is_a305b(struct adreno_device *adreno_dev) { return (adreno_dev->gpurev == ADRENO_REV_A305B); } static inline int adreno_is_a305c(struct adreno_device *adreno_dev) { return (adreno_dev->gpurev == ADRENO_REV_A305C); } static inline int adreno_is_a320(struct adreno_device *adreno_dev) { return (adreno_dev->gpurev == ADRENO_REV_A320); } static inline int adreno_is_a330(struct adreno_device *adreno_dev) { return (adreno_dev->gpurev == ADRENO_REV_A330); } static inline int adreno_is_a330v2(struct adreno_device *adreno_dev) { return ((adreno_dev->gpurev == ADRENO_REV_A330) && (ADRENO_CHIPID_PATCH(adreno_dev->chip_id) > 0)); } static inline int adreno_rb_ctxtswitch(unsigned int *cmd) { return (cmd[0] == cp_nop_packet(1) && cmd[1] == KGSL_CONTEXT_TO_MEM_IDENTIFIER); } /** * adreno_encode_istore_size - encode istore size in CP format * @adreno_dev - The 3D device. * * Encode the istore size into the format expected that the * CP_SET_SHADER_BASES and CP_ME_INIT commands: * bits 31:29 - istore size as encoded by this function * bits 27:16 - vertex shader start offset in instructions * bits 11:0 - pixel shader start offset in instructions. */ static inline int adreno_encode_istore_size(struct adreno_device *adreno_dev) { unsigned int size; /* in a225 the CP microcode multiplies the encoded * value by 3 while decoding. */ if (adreno_is_a225(adreno_dev)) size = adreno_dev->istore_size/3; else size = adreno_dev->istore_size; return (ilog2(size) - 5) << 29; } static inline int __adreno_add_idle_indirect_cmds(unsigned int *cmds, unsigned int nop_gpuaddr) { /* Adding an indirect buffer ensures that the prefetch stalls until * the commands in indirect buffer have completed. We need to stall * prefetch with a nop indirect buffer when updating pagetables * because it provides stabler synchronization */ *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD; *cmds++ = nop_gpuaddr; *cmds++ = 2; *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1); *cmds++ = 0x00000000; return 5; } static inline int adreno_add_change_mh_phys_limit_cmds(unsigned int *cmds, unsigned int new_phys_limit, unsigned int nop_gpuaddr) { unsigned int *start = cmds; *cmds++ = cp_type0_packet(MH_MMU_MPU_END, 1); *cmds++ = new_phys_limit; cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr); return cmds - start; } static inline int adreno_add_bank_change_cmds(unsigned int *cmds, int cur_ctx_bank, unsigned int nop_gpuaddr) { unsigned int *start = cmds; *cmds++ = cp_type0_packet(REG_CP_STATE_DEBUG_INDEX, 1); *cmds++ = (cur_ctx_bank ? 0 : 0x20); cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr); return cmds - start; } /* * adreno_read_cmds - Add pm4 packets to perform read * @device - Pointer to device structure * @cmds - Pointer to memory where read commands need to be added * @addr - gpu address of the read * @val - The GPU will wait until the data at address addr becomes * equal to value */ static inline int adreno_add_read_cmds(struct kgsl_device *device, unsigned int *cmds, unsigned int addr, unsigned int val, unsigned int nop_gpuaddr) { unsigned int *start = cmds; *cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5); /* MEM SPACE = memory, FUNCTION = equals */ *cmds++ = 0x13; *cmds++ = addr; *cmds++ = val; *cmds++ = 0xFFFFFFFF; *cmds++ = 0xFFFFFFFF; /* WAIT_REG_MEM turns back on protected mode - push it off */ *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1); *cmds++ = 0; cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr); return cmds - start; } /* * adreno_idle_cmds - Add pm4 packets for GPU idle * @adreno_dev - Pointer to device structure * @cmds - Pointer to memory where idle commands need to be added */ static inline int adreno_add_idle_cmds(struct adreno_device *adreno_dev, unsigned int *cmds) { unsigned int *start = cmds; *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1); *cmds++ = 0; if ((adreno_dev->gpurev == ADRENO_REV_A305) || (adreno_dev->gpurev == ADRENO_REV_A305C) || (adreno_dev->gpurev == ADRENO_REV_A320)) { *cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1); *cmds++ = 0; } return cmds - start; } /* * adreno_wait_reg_eq() - Add a CP_WAIT_REG_EQ command * @cmds: Pointer to memory where commands are to be added * @addr: Regiater address to poll for * @val: Value to poll for * @mask: The value against which register value is masked * @interval: wait interval */ static inline int adreno_wait_reg_eq(unsigned int *cmds, unsigned int addr, unsigned int val, unsigned int mask, unsigned int interval) { unsigned int *start = cmds; *cmds++ = cp_type3_packet(CP_WAIT_REG_EQ, 4); *cmds++ = addr; *cmds++ = val; *cmds++ = mask; *cmds++ = interval; return cmds - start; } /* * adreno_set_protected_registers() - Protect the specified range of registers * from being accessed by the GPU * @device: pointer to the KGSL device * @index: Pointer to the index of the protect mode register to write to * @reg: Starting dword register to write * @mask_len: Size of the mask to protect (# of registers = 2 ** mask_len) * * Add the range of registers to the list of protected mode registers that will * cause an exception if the GPU accesses them. There are 16 available * protected mode registers. Index is used to specify which register to write * to - the intent is to call this function multiple times with the same index * pointer for each range and the registers will be magically programmed in * incremental fashion */ static inline void adreno_set_protected_registers(struct kgsl_device *device, unsigned int *index, unsigned int reg, int mask_len) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); unsigned int val; /* This function is only for adreno A3XX and beyond */ BUG_ON(adreno_is_a2xx(adreno_dev)); /* There are only 16 registers available */ BUG_ON(*index >= 16); val = 0x60000000 | ((mask_len & 0x1F) << 24) | ((reg << 2) & 0x1FFFF); /* * Write the protection range to the next available protection * register */ kgsl_regwrite(device, A3XX_CP_PROTECT_REG_0 + *index, val); *index = *index + 1; } #endif /*__ADRENO_H */