/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
/*
 * Copyright (c) 2021 MediaTek Inc.
 */

#ifndef ATSC30_ALP_SIDEBAND_H
#define ATSC30_ALP_SIDEBAND_H
#include <linux/types.h>

#include "bits_op.h"

#define ALP_SIDEBAND_MASK(field_name) \
	ALP_GET_MASK_U32(ALP_SIDEBAND_## field_name ##_WIDTH)
#define ALP_SIDEBAND_GET(field_name, data) \
	ALP_GET_FIELD_U32( \
		data, \
		ALP_SIDEBAND_## field_name ##_WIDTH, \
		ALP_SIDEBAND_## field_name ##_SHIFT)

/*
 * {7��b0, alp_length[16:0], alp_bus1[31:0] , alp_bus2[31:0]}
 */
#define ALP_SIDEBAND_ALP_LENGTH_SHIFT (8 * 0)
#define ALP_SIDEBAND_ALP_LENGTH_WIDTH (17)

#define ALP_SIDEBAND_ALP_LENGTH_MASK \
	ALP_SIDEBAND_MASK(ALP_LENGTH)

#define ALP_SIDEBAND_GET_ALP_LENGTH(data) \
	ALP_SIDEBAND_GET(ALP_LENGTH, data)

/*
 * alp_bus1:{ rl_plp_id[7:0],
 *            max_cid[7:0],
 *            2��b0, deadp_ip_pkt_type_idx, out_alp_valid_pkt_idx,alp_head_length[8:5],
 *            alp_head_length[4:0],alp_plpid[2:0]}
 */
#define ALP_SIDEBAND_ALP_PLP_ID_SHIFT (8 * 0)
#define ALP_SIDEBAND_ALP_PLP_ID_WIDTH (3)
#define ALP_SIDEBAND_ALP_HEAD_LENGTH_SHIFT \
	(ALP_SIDEBAND_ALP_PLP_ID_SHIFT + \
		ALP_SIDEBAND_ALP_PLP_ID_WIDTH)
#define ALP_SIDEBAND_ALP_HEAD_LENGTH_WIDTH (9)
#define ALP_SIDEBAND_OUT_ALP_VALID_PKT_IDX_SHIFT \
	(ALP_SIDEBAND_ALP_HEAD_LENGTH_SHIFT + \
		ALP_SIDEBAND_ALP_HEAD_LENGTH_WIDTH)
#define ALP_SIDEBAND_OUT_ALP_VALID_PKT_IDX_WIDTH (1)
#define ALP_SIDEBAND_DEADP_IP_PACKET_TYPE_IDX_SHIFT \
	(ALP_SIDEBAND_OUT_ALP_VALID_PKT_IDX_SHIFT + \
		ALP_SIDEBAND_OUT_ALP_VALID_PKT_IDX_WIDTH)
#define ALP_SIDEBAND_DEADP_IP_PACKET_TYPE_IDX_WIDTH (1)

#define ALP_SIDEBAND_MAX_CID_SHIFT (8 * 2)
#define ALP_SIDEBAND_MAX_CID_WIDTH (8)

#define ALP_SIDEBAND_RL_PLP_ID_SHIFT (8 * 3)
#define ALP_SIDEBAND_RL_PLP_ID_WIDTH (8)

#define ALP_SIDEBAND_ALP_PLP_ID_MASK \
	ALP_SIDEBAND_MASK(ALP_PLP_ID)
#define ALP_SIDEBAND_ALP_HEAD_LENGTH_MASK \
	ALP_SIDEBAND_MASK(ALP_HEAD_LENGTH)
#define ALP_SIDEBAND_OUT_ALP_VALID_PKT_IDX_MASK \
	ALP_SIDEBAND_MASK(OUT_ALP_VALID_PKT_IDX)
#define ALP_SIDEBAND_DEADP_IP_PACKET_TYPE_IDX_MASK \
	ALP_SIDEBAND_MASK(DEADP_IP_PACKET_TYPE_IDX)
#define ALP_SIDEBAND_MAX_CID_MASK \
	ALP_SIDEBAND_MASK(MAX_CID)
#define ALP_SIDEBAND_RL_PLP_ID_MASK \
	ALP_SIDEBAND_MASK(RL_PLP_ID)

#define ALP_SIDEBAND_GET_ALP_PLP_ID(data) \
	ALP_SIDEBAND_GET(ALP_PLP_ID, data)
#define ALP_SIDEBAND_GET_ALP_HEAD_LENGTH(data) \
	ALP_SIDEBAND_GET(ALP_HEAD_LENGTH, data)
#define ALP_SIDEBAND_GET_OUT_ALP_VALID_PKT_IDX(data) \
	ALP_SIDEBAND_GET(OUT_ALP_VALID_PKT_IDX, data)
#define ALP_SIDEBAND_GET_DEADP_IP_PACKET_TYPE_IDX(data) \
	ALP_SIDEBAND_GET(DEADP_IP_PACKET_TYPE_IDX, data)
#define ALP_SIDEBAND_GET_MAX_CID(data) \
	ALP_SIDEBAND_GET(MAX_CID, data)
#define ALP_SIDEBAND_GET_RL_PLP_ID(data) \
	ALP_SIDEBAND_GET(RL_PLP_ID, data)

/*
 * alp_bus2:{ 8��b0,
 *            2��b0, out_filter_id[4:0], ip_total_length[16],
 *            ip_total_length[15:8],
 *            ip_total_length[7:0]}
 */
#define ALP_SIDEBAND_IP_TOTAL_LENGTH_SHIFT (8 * 0)
#define ALP_SIDEBAND_IP_TOTAL_LENGTH_WIDTH (17)
#define ALP_SIDEBAND_OUT_FILTER_ID_SHIFT \
	(ALP_SIDEBAND_IP_TOTAL_LENGTH_SHIFT + \
		ALP_SIDEBAND_IP_TOTAL_LENGTH_WIDTH)
#define ALP_SIDEBAND_OUT_FILTER_ID_WIDTH (5)

#define ALP_SIDEBAND_IP_TOTAL_LENGTH_MASK \
	ALP_SIDEBAND_MASK(IP_TOTAL_LENGTH)
#define ALP_SIDEBAND_OUT_FILTER_ID_MASK \
	ALP_SIDEBAND_MASK(OUT_FILTER_ID)

#define ALP_SIDEBAND_GET_IP_TOTAL_LENGTH(data) \
	ALP_SIDEBAND_GET(IP_TOTAL_LENGTH, data)
#define ALP_SIDEBAND_GET_OUT_FILTER_ID(data) \
	ALP_SIDEBAND_GET(OUT_FILTER_ID, data)

// TODO: use bit fields?
struct alp_bus_0 {
	u32 alp_length; // 17
};

// TODO: use bit fields?
struct alp_bus_1 {
	u8 rl_plp_id;
	u8 max_cid;
	bool deadp_ip_pkt_type_idx;
	bool out_alp_valid_pkt_idx;
	u16 alp_head_length; // 9
	u8 alp_plpid; // 3
};

// TODO: use bit fields?
struct alp_bus_2 {
	u8 out_filter_id; // 5
	u32 ip_total_length; // 17
};

enum {
	ALP_SIDEBAND_BYTE_0 = 0,
	ALP_SIDEBAND_BYTE_1,
	ALP_SIDEBAND_BYTE_2,
	ALP_SIDEBAND_BYTE_3,
	ALP_SIDEBAND_BYTE_4,
	ALP_SIDEBAND_BYTE_5,
	ALP_SIDEBAND_BYTE_6,
	ALP_SIDEBAND_BYTE_7,
	ALP_SIDEBAND_BYTE_8,
	ALP_SIDEBAND_BYTE_9,
	ALP_SIDEBAND_BYTE_10,
	ALP_SIDEBAND_BYTE_MAX,

	ALP_SIDEBAND_BYTE_NULL = -1,

	ALP_SIDEBAND_ALP_LENGTH = ALP_SIDEBAND_BYTE_0,
	ALP_SIDEBAND_BUS_1 = ALP_SIDEBAND_BYTE_3,
	ALP_SIDEBAND_BUS_2 = ALP_SIDEBAND_BYTE_7,
};

struct alp_sideband {
	struct alp_bus_0 alp_bus_0;
	struct alp_bus_1 alp_bus_1;
	struct alp_bus_2 alp_bus_2;
};

u32 alp_sideband_extract_alp_length(const u32 *data);

// alp_bus_1
u8 alp_sideband_extract_alp_plp_id(const u32 *data);
u16 alp_sideband_extract_alp_head_length(const u32 *data);
u16 alp_sideband_extract_alp_head_length(const u32 *data);
bool alp_sideband_extract_out_alp_valid_pkt_idx(const u32 *data);
bool alp_sideband_extract_deadp_ip_packet_type_idx(const u32 *data);
u8 alp_sideband_extract_max_cid(const u32 *data);
u8 alp_sideband_extract_rl_plp_id(const u32 *data);

// alp_bus_2
u32 alp_sideband_extract_ip_total_length(const u32 *data);
u8 alp_sideband_extract_out_filter_id(const u32 *data);

int alp_sideband_parse(
		const uintptr_t addr_1,
		size_t addr_len_1,
		const uintptr_t addr_2,
		size_t addr_len_2,
		struct alp_sideband *alp_sideband);

void alp_sideband_dump(
		int log_level,
		struct alp_sideband *alp_sideband);

#endif /* ATSC30_ALP_SIDEBAND_H */
