msm: kgsl: initial implementation of A6XX GMU driver

Support HFI, IOMMU GMU CBs, and GMU IRQs.
Support a new device tree node and GMU probe.
Support GMU start and stop.
Separate GMU register base and add GMU register access APIs.

CRs-Fixed: 2017390
Change-Id: If59f9e6dc62ed643c1300ddf8b566d44e9388558
Signed-off-by: Kyle Piefer <kpiefer@codeaurora.org>
Signed-off-by: George Shen <sqiao@codeaurora.org>
diff --git a/drivers/gpu/msm/kgsl_hfi.h b/drivers/gpu/msm/kgsl_hfi.h
new file mode 100644
index 0000000..39b513e
--- /dev/null
+++ b/drivers/gpu/msm/kgsl_hfi.h
@@ -0,0 +1,360 @@
+/* Copyright (c) 2017, 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 __KGSL_HFI_H
+#define __KGSL_HFI_H
+
+#include <linux/types.h>
+
+#define HFI_QUEUE_SIZE			SZ_4K		/* bytes */
+#define MAX_RSP_PAYLOAD_SIZE		16		/* dwords */
+#define HFI_MAX_MSG_SIZE		(SZ_1K>>2)	/* dwords */
+
+/* Below section is for all structures related to HFI queues */
+enum hfi_queue_type {
+	HFI_CMD_QUEUE = 0,
+	HFI_MSG_QUEUE,
+	HFI_DBG_QUEUE,
+	HFI_QUEUE_MAX
+};
+
+/* Add 16B guard band between HFI queues */
+#define HFI_QUEUE_OFFSET(i)		\
+		((sizeof(struct hfi_queue_table)) + \
+		((i) * (HFI_QUEUE_SIZE + 16)))
+
+#define HOST_QUEUE_START_ADDR(hfi_mem, i) \
+	((hfi_mem)->hostptr + HFI_QUEUE_OFFSET(i))
+
+#define GMU_QUEUE_START_ADDR(hfi_mem, i) \
+	((hfi_mem)->gmuaddr + HFI_QUEUE_OFFSET(i))
+
+#define HFI_IRQ_MSGQ_MASK		0x1
+#define HFI_IRQ_DBGQ_MASK		0x2
+#define HFI_IRQ_BLOCKED_MSG_MASK	0x4
+#define HFI_IRQ_GMU_ERR_MASK		0xFF0000
+#define HFI_IRQ_OOB_MASK		0xFF000000
+#define HFI_IRQ_MASK  (HFI_IRQ_MSGQ_MASK |\
+			HFI_IRQ_DBGQ_MASK |\
+			HFI_IRQ_BLOCKED_MSG_MASK |\
+			HFI_IRQ_GMU_ERR_MASK |\
+			HFI_IRQ_OOB_MASK)
+/**
+ * struct hfi_queue_table_header - HFI queue table structure
+ * @version: HFI protocol version
+ * @size: queue table size in dwords
+ * @qhdr0_offset: first queue header offset (dwords) in this table
+ * @qhdr_size: queue header size
+ * @num_q: number of queues defined in this table
+ * @num_active_q: number of active queues
+ */
+struct hfi_queue_table_header {
+	uint32_t version;
+	uint32_t size;
+	uint32_t qhdr0_offset;
+	uint32_t qhdr_size;
+	uint32_t num_q;
+	uint32_t num_active_q;
+};
+
+/**
+ * struct hfi_queue_header - HFI queue header structure
+ * @status: active: 1; inactive: 0
+ * @start_addr: starting address of the queue in GMU VA space
+ * @type: queue type encoded the priority, ID and send/recevie types
+ * @queue_size: size of the queue
+ * @msg_size: size of the message if each message has fixed size.
+ *	Otherwise, 0 means variable size of message in the queue.
+ * @drop_cnt: count of dropped messages
+ * @rx_wm: receiver watermark
+ * @tx_wm: sender watermark
+ * @rx_req: receiver request
+ * @tx_req: sender request
+ * @read_index: read index of the queue
+ * @write_index: write index of the queue
+ */
+struct hfi_queue_header {
+	uint32_t status;
+	uint32_t start_addr;
+	uint32_t type;
+	uint32_t queue_size;
+	uint32_t msg_size;
+	uint32_t drop_cnt;
+	uint32_t rx_wm;
+	uint32_t tx_wm;
+	uint32_t rx_req;
+	uint32_t tx_req;
+	uint32_t read_index;
+	uint32_t write_index;
+};
+
+struct hfi_queue_table {
+	struct hfi_queue_table_header qtbl_hdr;
+	struct hfi_queue_header qhdr[HFI_QUEUE_MAX];
+};
+
+/* HTOF queue priority, 1 is highest priority */
+enum hfi_h2f_qpri {
+	HFI_H2F_QPRI_CMD = 10,
+	HFI_H2F_QPRI_DISPATCH_P0 = 20,
+	HFI_H2F_QPRI_DISPATCH_P1 = 21,
+	HFI_H2F_QPRI_DISPATCH_P2 = 22,
+};
+
+/* FTOH queue priority, 1 is highest priority */
+enum hfi_f2h_qpri {
+	HFI_F2H_QPRI_MSG = 10,
+	HFI_F2H_QPRI_DEBUG = 40,
+};
+
+#define HFI_RSP_TIMEOUT 50 /* msec */
+#define HFI_H2F_CMD_IRQ_MASK BIT(0)
+
+enum hfi_msg_type {
+	HFI_MSG_CMD = 0,
+	HFI_MSG_POST = 1,
+	HFI_MSG_ACK = 2,
+	HFI_MSG_INVALID = 3
+};
+
+enum hfi_msg_id {
+	H2F_MSG_INIT = 0,
+	H2F_MSG_FW_VER = 1,
+	H2F_MSG_LM_CFG = 2,
+	H2F_MSG_BW_VOTE_TBL = 3,
+	H2F_MSG_PERF_TBL = 4,
+	H2F_MSG_TEST = 5,
+	H2F_MSG_DCVS_VOTE = 30,
+	H2F_MSG_FW_HALT = 31,
+	H2F_MSG_PREPARE_SLUMBER = 33,
+	F2H_MSG_ERR  = 100,
+	F2H_MSG_GMU_CNTR_REGISTER = 101,
+	F2H_MSG_ACK = 126,
+	H2F_MSG_ACK = 127,
+	H2F_MSG_REGISTER_CONTEXT = 128,
+	H2F_MSG_UNREGISTER_CONTEXT = 129,
+	H2F_MSG_ISSUE_IB = 130,
+	H2F_MSG_REGISTER_QUEUE = 131,
+	H2F_MSG_UNREGISTER_QUEUE = 132,
+	H2F_MSG_CLOSE = 133,
+	H2F_REGISTER_CONTEXT_DONE = 134,
+	H2F_UNREG_CONTEXT_DONE = 135,
+	H2F_ISSUE_IB_DONE = 136,
+	H2F_REGISTER_QUEUE_DONE = 137,
+};
+
+#define MAX_GX_LEVELS		16
+#define MAX_CX_LEVELS		4
+#define MAX_CNOC_LEVELS		2
+#define MAX_CNOC_CMDS		6
+#define MAX_BW_CMDS		8
+#define INVALID_DCVS_IDX	0xFF
+
+#if MAX_CNOC_LEVELS > MAX_GX_LEVELS
+#error "CNOC levels cannot exceed GX levels"
+#endif
+
+/**
+ * For detail usage of structures defined below,
+ * please look up HFI spec.
+ */
+
+struct hfi_msg_hdr {
+	uint32_t id: 8;		/* 0~127 power, 128~255 ecp */
+	uint32_t size: 8;	/* unit in dword */
+	uint32_t type: 4;
+	uint32_t seqnum: 12;
+};
+
+struct hfi_msg_rsp {
+	struct hfi_msg_hdr hdr;
+	struct hfi_msg_hdr ret_hdr;
+	uint32_t error;
+	uint32_t payload[MAX_RSP_PAYLOAD_SIZE];
+};
+
+struct hfi_gmu_init_cmd {
+	struct hfi_msg_hdr  hdr;
+	uint32_t seg_id;
+	uint32_t dbg_buffer_addr;
+	uint32_t dbg_buffer_size;
+	uint32_t boot_state;
+};
+
+struct hfi_fw_version_cmd {
+	struct hfi_msg_hdr hdr;
+	uint32_t supported_ver;
+};
+
+struct limits_config {
+	uint32_t lm_type: 4;
+	uint32_t lm_sensor_type: 4;
+	uint32_t throttle_config: 4;
+	uint32_t idle_throttle_en: 4;
+	uint32_t acd_en: 4;
+	uint32_t reserved: 12;
+};
+
+struct bcl_config {
+	uint32_t bcl: 8;
+	uint32_t reserved: 24;
+};
+
+struct hfi_lmconfig_cmd {
+	struct hfi_msg_hdr hdr;
+	struct limits_config limit_conf;
+	struct bcl_config bcl_conf;
+	uint32_t lm_enable_bitmask;
+};
+
+struct hfi_bwtable_cmd {
+	struct hfi_msg_hdr hdr;
+	uint32_t bw_level_num;
+	uint32_t cnoc_cmds_num;
+	uint32_t ddr_cmds_num;
+	uint32_t cnoc_wait_bitmask;
+	uint32_t ddr_wait_bitmask;
+	uint32_t cnoc_cmd_addrs[MAX_CNOC_CMDS];
+	uint32_t cnoc_cmd_data[MAX_CNOC_LEVELS][MAX_CNOC_CMDS];
+	uint32_t ddr_cmd_addrs[MAX_BW_CMDS];
+	uint32_t ddr_cmd_data[MAX_GX_LEVELS][MAX_BW_CMDS];
+};
+
+struct arc_vote_desc {
+	/* In case of GPU freq vote, primary is GX, secondary is MX
+	 * in case of GMU freq vote, primary is CX, secondary is MX
+	 */
+	uint32_t pri_idx: 8;
+	uint32_t sec_idx : 8;
+	uint32_t vlvl: 16;
+};
+
+struct opp_desc {
+	struct arc_vote_desc vote;
+	uint32_t freq;
+};
+
+struct hfi_dcvstable_cmd {
+	struct hfi_msg_hdr hdr;
+	uint32_t gpu_level_num;
+	uint32_t gmu_level_num;
+	struct opp_desc gx_votes[MAX_GX_LEVELS];
+	struct opp_desc cx_votes[MAX_CX_LEVELS];
+};
+
+enum fw_clkset_options {
+	OPTION_DEFAULT = 0,
+	OPTION_CLOSEST = 1,
+	OPTION_AT_MOST = 2,
+	OPTION_AT_LEAST = 3,
+	OPTION_INVALID = 4
+};
+
+enum rpm_ack_type {
+	ACK_NONBLOCK = 0,
+	ACK_BLOCK = 1,
+	ACK_INVALID = 2,
+};
+
+struct gpu_dcvs_vote {
+	uint32_t perf_idx : 8;
+	uint32_t reserved : 20;
+	uint32_t clkset_opt : 4;
+};
+
+struct gpu_bw_vote {
+	uint32_t bw_idx : 8;
+/* to support split AB and IB vote */
+	uint32_t reserved : 24;
+};
+
+union gpu_perf_vote {
+	struct gpu_dcvs_vote fvote;
+	struct gpu_bw_vote bvote;
+	uint32_t raw;
+};
+
+struct hfi_dcvs_cmd {
+	struct hfi_msg_hdr hdr;
+	uint32_t ack_type;
+	struct gpu_dcvs_vote freq;
+	struct gpu_bw_vote bw;
+};
+
+struct hfi_prep_slumber_cmd {
+	struct hfi_msg_hdr hdr;
+	uint32_t init_bw_idx;
+	uint32_t init_perf_idx;
+};
+
+struct hfi_fw_err_msg {
+	struct hfi_msg_hdr hdr;
+	uint32_t error_code;
+	uint32_t data_1;
+	uint32_t data_2;
+};
+
+/**
+ * struct pending_msg - data structure to track outstanding HFI
+ *	command messages
+ * @msg_complete: a blocking mechanism for sender to wait for ACK
+ * @node: a node in pending message queue
+ * @msg_id: the ID of the command message pending for ACK
+ * @seqnum: the seqnum of the command message pending for ACK.
+ *	together with msg_id, are used to correlate a receiving ACK
+ *	to a pending cmd message
+ * @results: the payload of received return message (ACK)
+ */
+struct pending_msg {
+	struct completion msg_complete;
+	struct list_head node;
+	uint32_t msg_id;
+	uint32_t seqnum;
+	struct hfi_msg_rsp results;
+};
+
+/**
+ * struct kgsl_hfi - HFI control structure
+ * @hfi_interrupt_num: number of GMU asserted HFI interrupt
+ * @msglock: spinlock to protect access to outstanding command message list
+ * @cmdq_mutex: mutex to protect command queue access from multiple senders
+ * @msglist: outstanding command message list. Each message in the list
+ *	is waiting for ACK from GMU
+ * @tasklet: the thread handling received messages from GMU
+ * @fw_version: FW version number provided by GMU
+ * @seqnum: atomic counter that is incremented for each message sent. The
+ *	value of the counter is used as sequence number for HFI message
+ */
+struct kgsl_hfi {
+	int hfi_interrupt_num;
+	spinlock_t msglock;
+	struct mutex cmdq_mutex;
+	struct list_head msglist;
+	struct tasklet_struct tasklet;
+	uint32_t fw_version;
+	atomic_t seqnum;
+	bool gmu_init_done;
+};
+
+struct gmu_device;
+struct gmu_memdesc;
+
+int hfi_start(struct gmu_device *gmu, uint32_t boot_state);
+void hfi_stop(struct gmu_device *gmu);
+void hfi_receiver(unsigned long data);
+void hfi_init(struct kgsl_hfi *hfi, struct gmu_memdesc *mem_addr,
+		uint32_t queue_sz_bytes);
+int hfi_send_dcvs_vote(struct gmu_device *gmu, uint32_t perf_idx,
+		uint32_t bw_idx, enum rpm_ack_type ack_type);
+int hfi_notify_slumber(struct gmu_device *gmu, uint32_t init_perf_idx,
+		uint32_t init_bw_idx);
+#endif  /* __KGSL_HFI_H */