/*
   <:copyright-BRCM:2013-2016:DUAL/GPL:standard
   
      Copyright (c) 2013-2016 Broadcom 
      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, as published by
   the Free Software Foundation (the "GPL").
   
   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.
   
   
   A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php, or by
   writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
   
   :>
 */

#ifndef _RDD_PLATFORM_H
#define _RDD_PLATFORM_H

#include "rdd_map_auto.h"
#include "rdd_common.h"

#if defined(XRDP_BBH_PER_LAN_PORT)
#define EGRESS_COUNTER_SIZE 8
#else
#define EGRESS_COUNTER_SIZE 1
#endif

extern uintptr_t rdp_runner_core_addr[];

#define RDD_VIRT_TO_PHYS(_addr) \
	virt_to_phys((const volatile void *)(uintptr_t)_addr)
#define RDD_PHYS_TO_VIRT(_addr) phys_to_virt(_addr)
#define RDD_RSV_VIRT_TO_PHYS(_addr) \
	RDD_VIRT_TO_PHYS((volatile void *)(uintptr_t)_addr)
#define RDD_RSV_PHYS_TO_VIRT(_addr) RDD_PHYS_TO_VIRT(_addr)

typedef enum {
	rdd_size_8,
	rdd_size_16,
	rdd_size_32,
} rdd_entry_size_t;

typedef struct rdd_module {
	int (*init)(const struct rdd_module *);
	uint32_t context_offset;
	uint32_t context_size;
	uint32_t res_offset;
	uint32_t *cfg_ptr;
	void *params;
} rdd_module_t;

static inline void _rdd_module_init(rdd_module_t *module)
{
	if (module->init)
		module->init(module);
}

static inline void _rdd_i_write(uint32_t *addr_arr, uint32_t addr, uint32_t val,
				uint32_t i, rdd_entry_size_t size)
{
	uint32_t *entry;
	int mem_id;

	for (mem_id = 0; mem_id < GROUPED_EN_SEGMENTS_NUM; mem_id++) {
		if (addr_arr[mem_id] == INVALID_TABLE_ADDRESS)
			continue;

		entry = (uint32_t *)(DEVICE_ADDRESS((
				rdp_runner_core_addr[mem_id] +
				addr_arr[mem_id]) + addr));
		switch (size) {
		case rdd_size_32:
			MWRITE_I_32(entry, i, val);
			break;
		case rdd_size_16:
			MWRITE_I_16(entry, i, val);
			break;
		default:
			MWRITE_I_8(entry, i, val);
			break;
		}
	}
}

static inline uint32_t _rdd_i_read(uint32_t *addr_arr, uint32_t addr,
				   uint32_t i, rdd_entry_size_t size)
{
	uint32_t *entry;
	int mem_id;

	for (mem_id = 0; mem_id < GROUPED_EN_SEGMENTS_NUM; mem_id++) {
		if (addr_arr[mem_id] == INVALID_TABLE_ADDRESS)
			continue;

		entry = (uint32_t *)(DEVICE_ADDRESS((
				rdp_runner_core_addr[mem_id] +
				addr_arr[mem_id]) + addr));
		switch (size) {
		case rdd_size_32:
			return MGET_I_32(entry, i);
		case rdd_size_16:
			return MGET_I_16(entry, i);
		default:
			return MGET_I_8(entry, i);
		}
	}
	return 0;
}

static inline void _rdd_field_write(uint32_t *addr_arr, uint32_t addr,
				    uint32_t val, uint32_t lsb, uint32_t width,
				    rdd_entry_size_t size)
{
	uint32_t *entry;
	int mem_id;

	for (mem_id = 0; mem_id < GROUPED_EN_SEGMENTS_NUM; mem_id++) {
		if (addr_arr[mem_id] == INVALID_TABLE_ADDRESS)
			continue;

		entry = (uint32_t *)(DEVICE_ADDRESS((
				rdp_runner_core_addr[mem_id] +
				addr_arr[mem_id]) + addr));
		switch (size) {
		case rdd_size_32:
			FIELD_MWRITE_32(entry, lsb, width, val);
			break;
		case rdd_size_16:
			FIELD_MWRITE_16(entry, lsb, width, val);
			break;
		default:
			FIELD_MWRITE_8(entry, lsb, width, val);
			break;
		}
	}
}

static inline uint32_t _rdd_field_read(uint32_t *addr_arr, uint32_t addr,
				       uint32_t lsb, uint32_t width,
				       rdd_entry_size_t size)
{
	uint32_t *entry;
	int mem_id;

	for (mem_id = 0; mem_id < GROUPED_EN_SEGMENTS_NUM; mem_id++) {
		if (addr_arr[mem_id] == INVALID_TABLE_ADDRESS)
			continue;

		entry = (uint32_t *)(DEVICE_ADDRESS((
				rdp_runner_core_addr[mem_id] +
				addr_arr[mem_id]) + addr));
		switch (size) {
		case rdd_size_32:
			return FIELD_MGET_32(entry, lsb, width);
		case rdd_size_16:
			return FIELD_MGET_16(entry, lsb, width);
		default:
			return FIELD_MGET_8(entry, lsb, width);
		}
	}
	return 0;
}
#endif

