/*
 * Copyright (C) 2020 Cypress Semiconductor Corporation.
 *
 * SPDX-License-Identifier: LGPL-2.1+
 */

#pragma once

#include <glib.h>

/* maximum number of programmable devices expected to be connected in dock.
* this is design limitation. This shall not be edited, unless stated by C Y*/
#define DMC_DOCK_MAX_DEV_COUNT			8

/* size of FW version structure in bytes */
#define DMC_DOCK_FW_VERSION_SIZE		8

/* indicates length of string in dock identity*/
#define DMC_IDENTITY_STRING_LEN		32

/* interrupt end point for DMC Dock */
#define DMC_INTERRUPT_PIPE_ID			0x82

/* USB bulk end point for DMC Dock */
#define DMC_BULK_PIPE_ID			1

/* indicates length of interrupt structure's data array filed */
#define DMC_INTERRUPT_DATA_LEN			8

/* status of the dmc will have different length. so first few bytes of status
* is read, which will contain actual length of status. this value indicates
* how much byte should read at first stage */
#define DMC_GET_STATUS_MIN_LEN			32

#define DMC_HASH_SIZE				32

/* time out to be set in control in/out pipe policy in ms */
#define DMC_CONTROL_TRANSFER_DEFAULT_TIMEOUT	5000

/* time out to be set in bulk out pipe policy in ms */
#define DMC_BULK_OUT_PIPE_TIMEOUT		2000

/* time out to be set in bulk out pipe policy in ms */
#define DMC_GET_REQUEST_TIMEOUT			20000


#define DMC_FWCT_SIGN				0x54435746 /* 'F' 'W' 'C' 'T' */

/* first we have to read few bytes to know the actual length of FWCT
 * this constant defines, number bytest to be read for getting length */
#define DMC_FWCT_MIN_LENGTH			6
#define DMC_FWCT_LENGTH_OFFSET			4
#define DMC_FWCT_MAX_SIZE			2048

#define DMC_CUSTOM_META_LENGTH_FIELD_SIZE	2
#define DMC_CUSTOM_META_LENGTH_OFFSET		0
#define DMC_CUSTOM_META_MAX_SIZE		256

/* this data type enumerates the image types */
typedef enum {
	DMC_IMG_TYPE_INVALID = 0,
	DMC_IMG_TYPE_IMAGE_0,
	DMC_IMG_TYPE_IMAGE_1
} DmcImgType;

/* this data type enumerates the image status */
typedef enum {
	DMC_IMG_STATUS_UNKNOWN = 0,
	DMC_IMG_STATUS_VALID,
	DMC_IMG_STATUS_INVALID,
	DMC_IMG_STATUS_RECOVERY,
	DMC_IMG_STATUS_RECOVERED_FROM_SECONDARY,
	DMC_IMG_STATUS_NOT_SUPPORTED = 0x0F
} DmcImgStatus;

/* this data type enumerates the image modes or flash architecture */
typedef enum {
	/* indicates that the device has a single image */
	DMC_IMG_MODE_SINGLE_IMG = 0,
	/* the device supports symmetric boot. In symmetric mode the bootloader
	 * boots the image with higher version, when they are valid */
	DMC_IMG_MODE_DUAL_IMG_SYM,
	/* the device supports Asymmetric boot. Image-1 & 2 can be different or
	 * same. in this method Bootloader is hard coded to boot the primary
	 * image. Secondary acts as recovery */
	DMC_IMG_MODE_DUAL_IMG_ASYM,
	DMC_IMG_MODE_SINGLE_IMG_WITH_RAM_IMG,
} DmcImgMode;

/* this data type enumerates the dock status */
typedef enum {
	/* status code indicating DOCK IDLE state. SUCCESS: no malfunctioning
	* no outstanding request or event */
	DMC_DEVICE_STATUS_IDLE = 0,
	/* status code indicating dock FW update in progress */
	DMC_DEVICE_STATUS_UPDATE_IN_PROGRESS,
	/* status code indicating dock FW update is partially complete */
	DMC_DEVICE_STATUS_UPDATE_PARTIAL,
	/* status code indicating dock FW update SUCCESS - all m_images of all
	 * devices are valid */
	DMC_DEVICE_STATUS_UPDATE_COMPLETE_FULL,
	/* status code indicating dock FW update SUCCESS - not all m_images of all
	 * devices are valid */
	DMC_DEVICE_STATUS_UPDATE_COMPLETE_PARTIAL,
	/* fw download status */
	DMC_DEVICE_STATUS_UPDATE_PHASE_1_COMPLETE,
	DMC_DEVICE_STATUS_FW_DOWNLOADED_UPDATE_PEND,
	DMC_DEVICE_STATUS_FW_DOWNLOADED_PARTIAL_UPDATE_PEND,
	DMC_DEVICE_STATUS_PHASE2_UPDATE_IN_PROGRESS = 0x81,
	DMC_DEVICE_STATUS_PHASE2_UPDATE_PARTIAL,
	DMC_DEVICE_STATUS_PHASE2_UPDATE_FACTORY_BACKUP,
	DMC_DEVICE_STATUS_PHASE2_UPDATE_COMPLETE_PARTIAL,
	DMC_DEVICE_STATUS_PHASE2_UPDATE_COMPLETE_FULL,
	DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_INVALID_FWCT,
	DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_INVALID_DOCK_IDENTITY,
	DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_INVALID_COMPOSITE_VER,
	DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_AUTHENTICATION_FAILED,
	DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_INVALID_ALGORITHM,
	DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_SPI_READ_FAILED,
	DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_NO_VALID_KEY,
	DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_NO_VALID_SPI_PACKAGE,
	DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_RAM_INIT_FAILED,
	DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_FACTORY_BACKUP_FAILED,
	DMC_DEVICE_STATUS_PHASE2_UPDATE_FAIL_NO_VALID_FACTORY_PACKAGE,
	/* status code indicating dock FW update FAILED */
	DMC_DEVICE_STATUS_UPDATE_FAIL = 0xFF
} DmcDeviceStatus;

/* this data type enumerates the request codes for vendor interface */
typedef enum {
	DMC_RQT_CODE_UPGRADE_START = 0xD0,
	DMC_RQT_CODE_RESERV_0,
	DMC_RQT_CODE_FWCT_WRITE,
	DMC_RQT_CODE_IMG_WRITE,
	DMC_RQT_CODE_RESERV_1,
	DMC_RQT_CODE_RESERV_2,
	DMC_RQT_CODE_DOCK_STATUS,
	DMC_RQT_CODE_DOCK_IDENTITY,
	/* command to reset dmc state machine of DMC */
	DMC_RQT_CODE_RESET_STATE_MACHINE,
	/* command to reset for online enhanced mode (no reset during update) */
	DMC_RQT_CODE_SOFT_RESET = 0xDC,
	/* Update Trigger command for offline mode */
	DMC_RQT_CODE_TRIGGER = 0xDA
} DmcRqtCode;

/* this data type enumerates the opcode of triggering the download, in case of
* 2 stage update */
typedef enum {
	DMC_TRIGGER_CODE_DONT_UPDATE,
	DMC_TRIGGER_CODE_UPDATE_NOW,
	DMC_TRIGGER_CODE_UPDATE_ON_DISCONNECT,
	DMC_TRIGGER_CODE_UNKNOWN
} DmcTriggerCode;

/* this data type enumerates the opcode of interrupt read */
typedef enum {
	DMC_INT_OPCODE_FW_UPGRADE_RQT = 1,
	DMC_INT_OPCODE_FW_UPGRADE_STATUS = 0x80,
	DMC_INT_OPCODE_IMG_WRITE_STATUS,
	DMC_INT_OPCODE_REENUM,
	DMC_INT_OPCODE_FWCT_ANALYSIS_STATUS
} DmcIntOpcode;

/* this data type enumerates the fwct analysis status */
typedef enum {
	DMC_FWCT_ANALYSIS_STATUS_INVALID_FWCT = 0,
	DMC_FWCT_ANALYSIS_STATUS_INVALID_DOCK_IDENTITY,
	DMC_FWCT_ANALYSIS_STATUS_INVALID_COMPOSITE_VERSION,
	DMC_FWCT_ANALYSIS_STATUS_AUTHENTICATION_FAILED,
	DMC_FWCT_ANALYSIS_STATUS_INVALID_ALGORITHM
} DmcFwctAnalysisStatus;

typedef enum {
	DMC_UPDATE_MODEL_UNKNOWN= 0,
	/* need to trigger after updating FW */
	DMC_UPDATE_MODEL_DOWNLOAD_TRIGGER,
	/* need to set soft reset after updating FW */
	DMC_UPDATE_MODEL_PENDING_RESET,
} DmcUpdateModel;

/* this structure defines the fields of data returned when reading dock_identity
 * for new firmware */
typedef struct __attribute__((packed)) {
	/* this field indicates both validity and structure version
	 * 0 : invalid
	 * 1 : old structure
	 * 2 : new structure */
	guint8		structure_version;
	guint8		cdtt_version;
	guint16		vid;
	guint16		pid;
	guint16		device_id;
	gchar		vendor_string[DMC_IDENTITY_STRING_LEN];
	gchar		product_string[DMC_IDENTITY_STRING_LEN];
	guint8		custom_meta_data_flag;
	/* model field indicates the type of the firmware upgrade status
	* 0 - online/offline
	* 1 - Online model
	* 2 - ADICORA/Offline model
	* 3 - No reset
	* 4 - 0xFF - Reserved
	*/
	guint8		model;
} DmcDockIdentity;

/* this structure defines the fields of status of a specific device  */
typedef struct __attribute__((packed)) {
	/* device ID of the device */
	guint8		device_type;
	/* component ID of the device */
	guint8		component_id;
	/* image mode of the device - single image/ dual symmetric/ dual
	 * asymmetric image > */
	guint8		image_mode;
	/* current running image */
	guint8		current_image;
	/* image status
	 * b7:b4 => Image 2 status
	 * b3:b0 => Image 1 status
	 *  0 = Unknown
	 *  1 = Valid
	 *  2 = Invalid
	 *  3-0xF = Reserved
	 */
	guint8		img_status;
	/* padding */
	guint8		reserved_0[3];
	/* complete fw version 8 bytes for bootload, image1 and image2. 8 byte
	* for fw version and application version */
	guint8		fw_version[24];
} DmcDevxStatus;

/* this structure defines the fields of data returned when reading dock_status */
typedef struct __attribute__((packed)) {
	/* overall status of dock. see DmcDeviceStatus */
	guint8		device_status;
	/* eevice count */
	guint8		device_count;
	/* length of status bytes including dock_status,
	devx_status for each device */
	guint16		status_length;
	/* dock composite version m_fwct_info */
	guint32		composite_version;
	/* fw status of device of interest */
	DmcDevxStatus	devx_status[DMC_DOCK_MAX_DEV_COUNT];
} DmcDockStatus;

/* This structure defines the fields of data returned when reading an interrupt
* from DMC */
typedef struct __attribute__((packed)) {
	guint8		opcode;
	guint8		length;
	guint8		data[DMC_INTERRUPT_DATA_LEN];
} DmcIntRqt;

/* this structure defines header structure of FWCT */
typedef struct __attribute__((packed)) {
	guint32		signature;
	guint16		size;
	guint8		checksum;
	guint8		version;
	guint8		custom_meta_type;
	guint8		cdtt_version;
	guint16		vid;
	guint16		pid;
	guint16		device_id;
	guint8		reserv0[16];
	guint32		composite_version;
	guint8		image_count;
	guint8		reserv1[3];
} FwctInfo;

typedef struct __attribute__((packed)) {
	guint8		device_type;
	guint8		img_type;
	guint8		comp_id;
	guint8		row_size;
	guint8		reserv0[4];
	guint32		fw_version;
	guint32		app_version;
	guint32		img_offset;
	guint32		img_size;
	guint8		img_digest[32];
	guint8		num_img_segments;
	guint8		reserv1[3];
} FwctImageInfo;

typedef struct __attribute__((packed)) {
	guint8		img_id;
	guint8		type;
	guint16		start_row;
	guint16		num_rows; /* size */
	guint8		reserv0[2];
} FwctSegmentationInfo;

const gchar	*fu_ccgx_dmc_update_model_type_to_string	(DmcUpdateModel	val);
