/* Copyright 2017-2018 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __SBE_P9_H
#define __SBE_P9_H

#include <bitutils.h>
#include <ccan/list/list.h>
#include <ccan/short_types/short_types.h>

/* Worst case command timeout value (90 sec) */
#define SBE_CMD_TIMEOUT_MAX			(90 * 1000)

/* Primary response status code */
#define SBE_STATUS_PRI_SUCCESS			0x00
#define SBE_STATUS_PRI_INVALID_CMD		0x01
#define SBE_STATUS_PRI_INVALID_DATA		0x02
#define SBE_STATUS_PRI_SEQ_ERR			0x03
#define SBE_STATUS_PRI_INTERNAL_ERR		0x04
#define SBE_STATUS_PRI_UNSECURE_ACCESS		0x05
#define SBE_STATUS_PRI_GENERIC_ERR		0xFE

/* Secondary response status code */
#define SBE_STATUS_SEC_SUCCESS			0x00
#define SBE_STATUS_SEC_CMD_CLASS_UNSUPPORTED	0x01
#define SBE_STATUS_SEC_CMD_UNSUPPORTED		0x02
#define SBE_STATUS_SEC_INV_ADDR			0x03
#define SBE_STATUS_SEC_INV_TARGET_TYPE		0x04
#define SBE_STATUS_SEC_INV_CHIPLET_ID		0x05
#define SBE_STATUS_SEC_TARGET_NOT_PRESENT	0x06
#define SBE_STATUS_SEC_TARGET_NOT_FUNC		0x07
#define SBE_STATUS_SEC_CMD_NOT_ALLOW		0x08
#define SBE_STATUS_SEC_FUNC_NOT_SUPPORTED	0x09
#define SBE_STATUS_SEC_GENERIC_ERR		0x0A
#define SBE_STATUS_SEC_BLACKLIST_REG		0x0B
#define SBE_STATUS_SEC_OS_FAILURE		0x0C
#define SBE_STATUS_SEC_MBX_REG_FAILURE		0x0D
#define SBE_STATUS_SEC_INSUFFICIENT_DATA	0x0E
#define SBE_STATUS_SEC_EXCESS_DATA		0x0F
#define SBE_STATUS_SEC_HW_TIMEOUT		0x10
#define SBE_STATUS_SEC_PCBPIB_ERR		0x11
#define SBE_STATUS_SEC_FIFO_PARITY_ERR		0x12
#define SBE_STATUS_SEC_TIMER_EXPIRED		0x13
#define SBE_STATUS_SEC_BLACKLISTED_MEM		0x14
#define SBE_STATUS_SEC_UNSEC_REGION_NOT_FOUND	0x15
#define SBE_STATUS_SEC_UNSEC_REGION_EXCEEDED	0x16
#define SBE_STATUS_SEC_UNSEC_REGION_AMEND	0x17
#define SBE_STATUS_SEC_INPUT_BUF_OVERFLOW	0x18
#define SBE_STATUS_SEC_INVALID_PARAMS		0x19
#define SBE_STATUS_SEC_BLACKLISTED_CMD		0x20

/* Number of MBOX register on each side */
#define NR_HOST_SBE_MBOX_REG		0x04

/*
 * SBE MBOX register address
 *   Reg 0 - 3 : Host to send command packets to SBE
 *   Reg 4 - 7 : SBE to send response packets to Host
 */
#define PSU_HOST_SBE_MBOX_REG0		0x000D0050
#define PSU_HOST_SBE_MBOX_REG1		0x000D0051
#define PSU_HOST_SBE_MBOX_REG2		0x000D0052
#define PSU_HOST_SBE_MBOX_REG3		0x000D0053
#define PSU_HOST_SBE_MBOX_REG4		0x000D0054
#define PSU_HOST_SBE_MBOX_REG5		0x000D0055
#define PSU_HOST_SBE_MBOX_REG6		0x000D0056
#define PSU_HOST_SBE_MBOX_REG7		0x000D0057
#define PSU_SBE_DOORBELL_REG_RW		0x000D0060
#define PSU_SBE_DOORBELL_REG_AND	0x000D0061
#define PSU_SBE_DOORBELL_REG_OR		0x000D0062
#define PSU_HOST_DOORBELL_REG_RW	0x000D0063
#define PSU_HOST_DOORBELL_REG_AND	0x000D0064
#define PSU_HOST_DOORBELL_REG_OR	0x000D0065

/*
 * Doorbell register to trigger SBE interrupt. Set by OPAL to inform
 * the SBE about a waiting message in the Host/SBE mailbox registers
 */
#define HOST_SBE_MSG_WAITING		PPC_BIT(0)

/*
 * Doorbell register for host bridge interrupt. Set by the SBE to inform
 * host about a response message in the Host/SBE mailbox registers
 */
#define SBE_HOST_RESPONSE_WAITING	PPC_BIT(0)
#define SBE_HOST_MSG_READ		PPC_BIT(1)
#define SBE_HOST_STOP15_EXIT		PPC_BIT(2)
#define SBE_HOST_RESET			PPC_BIT(3)
#define SBE_HOST_PASSTHROUGH		PPC_BIT(4)
#define SBE_HOST_TIMER_EXPIRY		PPC_BIT(14)
#define SBE_HOST_RESPONSE_MASK		(PPC_BITMASK(0, 4) | SBE_HOST_TIMER_EXPIRY)

/* SBE Target Type */
#define SBE_TARGET_TYPE_PROC		0x00
#define SBE_TARGET_TYPE_EX		0x01
#define SBE_TARGET_TYPE_PERV		0x02
#define SBE_TARGET_TYPE_MCS		0x03
#define SBE_TARGET_TYPE_EQ		0x04
#define SBE_TARGET_TYPE_CORE		0x05

/* SBE MBOX command class */
#define SBE_MCLASS_FIRST		0xD1
#define SBE_MCLASS_CORE_STATE		0xD1
#define SBE_MCLASS_SCOM			0xD2
#define SBE_MCLASS_RING			0xD3
#define SBE_MCLASS_TIMER		0xD4
#define SBE_MCLASS_MPIPL		0xD5
#define SBE_MCLASS_SECURITY		0xD6
#define SBE_MCLASS_GENERIC		0xD7
#define SBE_MCLASS_LAST			0xD7

/*
 * Commands are provided in xxyy form where:
 *   - xx : command class
 *   - yy : command
 *
 * Both request and response message uses same seq ID,
 * command class and command.
 */
#define SBE_CMD_CTRL_DEADMAN_LOOP	0xD101
#define SBE_CMD_MULTI_SCOM		0xD201
#define SBE_CMD_PUT_RING_FORM_IMAGE	0xD301
#define SBE_CMD_CONTROL_TIMER		0xD401
#define SBE_CMD_GET_ARCHITECTED_REG	0xD501
#define SBE_CMD_CLR_ARCHITECTED_REG	0xD502
#define SBE_CMD_SET_UNSEC_MEM_WINDOW	0xD601
#define SBE_CMD_GET_SBE_FFDC		0xD701
#define SBE_CMD_GET_CAPABILITY		0xD702
#define SBE_CMD_READ_SBE_SEEPROM	0xD703
#define SBE_CMD_SET_FFDC_ADDR		0xD704
#define SBE_CMD_QUIESCE_SBE		0xD705
#define SBE_CMD_SET_FABRIC_ID_MAP	0xD706
#define SBE_CMD_STASH_MPIPL_CONFIG	0xD707

/* SBE MBOX control flags */

/* Generic flags */
#define SBE_CMD_CTRL_RESP_REQ		0x0100
#define SBE_CMD_CTRL_ACK_REQ		0x0200

/* Deadman loop */
#define CTRL_DEADMAN_LOOP_START		0x0001
#define CTRL_DEADMAN_LOOP_STOP		0x0002

/* Control timer */
#define CONTROL_TIMER_START		0x0001
#define CONTROL_TIMER_STOP		0x0002

/* SBE message state */
enum p9_sbe_msg_state {
	sbe_msg_unused = 0,	/* Free */
	sbe_msg_queued,		/* Queued to SBE list */
	sbe_msg_sent,		/* Sent to SBE */
	sbe_msg_wresp,		/* Waiting for response */
	sbe_msg_done,		/* Complete */
	sbe_msg_timeout,	/* Message timeout */
	sbe_msg_error,		/* Failed to send message to SBE */
};

/* SBE message */
struct p9_sbe_msg {
	/*
	 * Reg[0] :
	 *   word0 :
	 *     direct cmd  : reserved << 16 | ctrl flag
	 *     indirect cmd: mem_addr_size_dword
	 *     response    : primary status << 16 | secondary status
	 *
	 *   word1 : seq id << 16 | cmd class << 8 | cmd
	 *
	 * WARNING:
	 *   - Don't populate reg[0].seq (byte 4,5). This will be populated by
	 *     p9_sbe_queue_msg().
	 */
	u64	reg[4];

	/* cmd timout : mftb() + msecs_to_tb(SBE_CMD_TIMEOUT_MAX) */
	u64	timeout;

	/* Completion function */
	void (*complete)(struct p9_sbe_msg *msg);
	void *user_data;

	/* Current msg state */
	enum p9_sbe_msg_state	state;

	/* Set if the message expects a response */
	bool			response;

	/* Response will be filled by driver when response received */
	struct p9_sbe_msg	*resp;

	/* Internal queuing */
	struct list_node	link;
} __packed;


/* Allocate and populate p9_sbe_msg structure */
extern struct p9_sbe_msg *p9_sbe_mkmsg(u16 cmd, u16 ctrl_flag, u64 reg1,
				       u64 reg2, u64 reg3) __warn_unused_result;

/* Free p9_sbe_msg structure */
extern void p9_sbe_freemsg(struct p9_sbe_msg *msg);

/* Add new message to sbe queue */
extern int p9_sbe_queue_msg(uint32_t chip_id, struct p9_sbe_msg *msg,
		void (*comp)(struct p9_sbe_msg *msg)) __warn_unused_result;

/* Synchronously send message to SBE */
extern int p9_sbe_sync_msg(u32 chip_id, struct p9_sbe_msg *msg, bool autofree);

/* Remove message from SBE queue, it will not remove inflight message */
extern int p9_sbe_cancelmsg(u32 chip_id, struct p9_sbe_msg *msg);

/* Initialize the SBE mailbox driver */
extern void p9_sbe_init(void);

/* SBE interrupt */
extern void p9_sbe_interrupt(uint32_t chip_id);

/* Is SBE timer available ? */
extern bool p9_sbe_timer_ok(void);

/* Update SBE timer expiry */
extern void p9_sbe_update_timer_expiry(uint64_t new_target);

#endif	/* __SBE_P9_H */
