/*
 * Multicore Navigator driver for TI Keystone 2 devices.
 *
 * (C) Copyright 2012-2014
 *     Texas Instruments Incorporated, <www.ti.com>
 *
 * SPDX-License-Identifier:     GPL-2.0+
 */
#include <common.h>
#include <asm/io.h>
#include <asm/ti-common/keystone_nav.h>

struct qm_config qm_memmap = {
	.stat_cfg	= CONFIG_KSNAV_QM_QUEUE_STATUS_BASE,
	.queue		= (void *)CONFIG_KSNAV_QM_MANAGER_QUEUES_BASE,
	.mngr_vbusm	= CONFIG_KSNAV_QM_BASE_ADDRESS,
	.i_lram		= CONFIG_KSNAV_QM_LINK_RAM_BASE,
	.proxy		= (void *)CONFIG_KSNAV_QM_MANAGER_Q_PROXY_BASE,
	.status_ram	= CONFIG_KSNAV_QM_STATUS_RAM_BASE,
	.mngr_cfg	= (void *)CONFIG_KSNAV_QM_CONF_BASE,
	.intd_cfg	= CONFIG_KSNAV_QM_INTD_CONF_BASE,
	.desc_mem	= (void *)CONFIG_KSNAV_QM_DESC_SETUP_BASE,
	.region_num	= CONFIG_KSNAV_QM_REGION_NUM,
	.pdsp_cmd	= CONFIG_KSNAV_QM_PDSP1_CMD_BASE,
	.pdsp_ctl	= CONFIG_KSNAV_QM_PDSP1_CTRL_BASE,
	.pdsp_iram	= CONFIG_KSNAV_QM_PDSP1_IRAM_BASE,
	.qpool_num	= CONFIG_KSNAV_QM_QPOOL_NUM,
};

/*
 * We are going to use only one type of descriptors - host packet
 * descriptors. We staticaly allocate memory for them here
 */
struct qm_host_desc desc_pool[HDESC_NUM] __aligned(sizeof(struct qm_host_desc));

static struct qm_config *qm_cfg;

inline int num_of_desc_to_reg(int num_descr)
{
	int j, num;

	for (j = 0, num = 32; j < 15; j++, num *= 2) {
		if (num_descr <= num)
			return j;
	}

	return 15;
}

int _qm_init(struct qm_config *cfg)
{
	u32 j;

	qm_cfg = cfg;

	qm_cfg->mngr_cfg->link_ram_base0	= qm_cfg->i_lram;
	qm_cfg->mngr_cfg->link_ram_size0	= HDESC_NUM * 8 - 1;
	qm_cfg->mngr_cfg->link_ram_base1	= 0;
	qm_cfg->mngr_cfg->link_ram_size1	= 0;
	qm_cfg->mngr_cfg->link_ram_base2	= 0;

	qm_cfg->desc_mem[0].base_addr = (u32)desc_pool;
	qm_cfg->desc_mem[0].start_idx = 0;
	qm_cfg->desc_mem[0].desc_reg_size =
		(((sizeof(struct qm_host_desc) >> 4) - 1) << 16) |
		num_of_desc_to_reg(HDESC_NUM);

	memset(desc_pool, 0, sizeof(desc_pool));
	for (j = 0; j < HDESC_NUM; j++)
		qm_push(&desc_pool[j], qm_cfg->qpool_num);

	return QM_OK;
}

int qm_init(void)
{
	return _qm_init(&qm_memmap);
}

void qm_close(void)
{
	u32	j;

	queue_close(qm_cfg->qpool_num);

	qm_cfg->mngr_cfg->link_ram_base0	= 0;
	qm_cfg->mngr_cfg->link_ram_size0	= 0;
	qm_cfg->mngr_cfg->link_ram_base1	= 0;
	qm_cfg->mngr_cfg->link_ram_size1	= 0;
	qm_cfg->mngr_cfg->link_ram_base2	= 0;

	for (j = 0; j < qm_cfg->region_num; j++) {
		qm_cfg->desc_mem[j].base_addr = 0;
		qm_cfg->desc_mem[j].start_idx = 0;
		qm_cfg->desc_mem[j].desc_reg_size = 0;
	}

	qm_cfg = NULL;
}

void qm_push(struct qm_host_desc *hd, u32 qnum)
{
	u32 regd;

	cpu_to_bus((u32 *)hd, sizeof(struct qm_host_desc)/4);
	regd = (u32)hd | ((sizeof(struct qm_host_desc) >> 4) - 1);
	writel(regd, &qm_cfg->queue[qnum].ptr_size_thresh);
}

void qm_buff_push(struct qm_host_desc *hd, u32 qnum,
		    void *buff_ptr, u32 buff_len)
{
	hd->orig_buff_len = buff_len;
	hd->buff_len = buff_len;
	hd->orig_buff_ptr = (u32)buff_ptr;
	hd->buff_ptr = (u32)buff_ptr;
	qm_push(hd, qnum);
}

struct qm_host_desc *qm_pop(u32 qnum)
{
	u32 uhd;

	uhd = readl(&qm_cfg->queue[qnum].ptr_size_thresh) & ~0xf;
	if (uhd)
		cpu_to_bus((u32 *)uhd, sizeof(struct qm_host_desc)/4);

	return (struct qm_host_desc *)uhd;
}

struct qm_host_desc *qm_pop_from_free_pool(void)
{
	return qm_pop(qm_cfg->qpool_num);
}

void queue_close(u32 qnum)
{
	struct qm_host_desc *hd;

	while ((hd = qm_pop(qnum)))
		;
}

/**
 * DMA API
 */

static int ksnav_rx_disable(struct pktdma_cfg *pktdma)
{
	u32 j, v, k;

	for (j = 0; j < pktdma->rx_ch_num; j++) {
		v = readl(&pktdma->rx_ch[j].cfg_a);
		if (!(v & CPDMA_CHAN_A_ENABLE))
			continue;

		writel(v | CPDMA_CHAN_A_TDOWN, &pktdma->rx_ch[j].cfg_a);
		for (k = 0; k < TDOWN_TIMEOUT_COUNT; k++) {
			udelay(100);
			v = readl(&pktdma->rx_ch[j].cfg_a);
			if (!(v & CPDMA_CHAN_A_ENABLE))
				continue;
		}
		/* TODO: teardown error on if TDOWN_TIMEOUT_COUNT is reached */
	}

	/* Clear all of the flow registers */
	for (j = 0; j < pktdma->rx_flow_num; j++) {
		writel(0, &pktdma->rx_flows[j].control);
		writel(0, &pktdma->rx_flows[j].tags);
		writel(0, &pktdma->rx_flows[j].tag_sel);
		writel(0, &pktdma->rx_flows[j].fdq_sel[0]);
		writel(0, &pktdma->rx_flows[j].fdq_sel[1]);
		writel(0, &pktdma->rx_flows[j].thresh[0]);
		writel(0, &pktdma->rx_flows[j].thresh[1]);
		writel(0, &pktdma->rx_flows[j].thresh[2]);
	}

	return QM_OK;
}

static int ksnav_tx_disable(struct pktdma_cfg *pktdma)
{
	u32 j, v, k;

	for (j = 0; j < pktdma->tx_ch_num; j++) {
		v = readl(&pktdma->tx_ch[j].cfg_a);
		if (!(v & CPDMA_CHAN_A_ENABLE))
			continue;

		writel(v | CPDMA_CHAN_A_TDOWN, &pktdma->tx_ch[j].cfg_a);
		for (k = 0; k < TDOWN_TIMEOUT_COUNT; k++) {
			udelay(100);
			v = readl(&pktdma->tx_ch[j].cfg_a);
			if (!(v & CPDMA_CHAN_A_ENABLE))
				continue;
		}
		/* TODO: teardown error on if TDOWN_TIMEOUT_COUNT is reached */
	}

	return QM_OK;
}

int ksnav_init(struct pktdma_cfg *pktdma, struct rx_buff_desc *rx_buffers)
{
	u32 j, v;
	struct qm_host_desc *hd;
	u8 *rx_ptr;

	if (pktdma == NULL || rx_buffers == NULL ||
	    rx_buffers->buff_ptr == NULL || qm_cfg == NULL)
		return QM_ERR;

	pktdma->rx_flow = rx_buffers->rx_flow;

	/* init rx queue */
	rx_ptr = rx_buffers->buff_ptr;

	for (j = 0; j < rx_buffers->num_buffs; j++) {
		hd = qm_pop(qm_cfg->qpool_num);
		if (hd == NULL)
			return QM_ERR;

		qm_buff_push(hd, pktdma->rx_free_q,
			     rx_ptr, rx_buffers->buff_len);

		rx_ptr += rx_buffers->buff_len;
	}

	ksnav_rx_disable(pktdma);

	/* configure rx channels */
	v = CPDMA_REG_VAL_MAKE_RX_FLOW_A(1, 1, 0, 0, 0, 0, 0, pktdma->rx_rcv_q);
	writel(v, &pktdma->rx_flows[pktdma->rx_flow].control);
	writel(0, &pktdma->rx_flows[pktdma->rx_flow].tags);
	writel(0, &pktdma->rx_flows[pktdma->rx_flow].tag_sel);

	v = CPDMA_REG_VAL_MAKE_RX_FLOW_D(0, pktdma->rx_free_q, 0,
					 pktdma->rx_free_q);

	writel(v, &pktdma->rx_flows[pktdma->rx_flow].fdq_sel[0]);
	writel(v, &pktdma->rx_flows[pktdma->rx_flow].fdq_sel[1]);
	writel(0, &pktdma->rx_flows[pktdma->rx_flow].thresh[0]);
	writel(0, &pktdma->rx_flows[pktdma->rx_flow].thresh[1]);
	writel(0, &pktdma->rx_flows[pktdma->rx_flow].thresh[2]);

	for (j = 0; j < pktdma->rx_ch_num; j++)
		writel(CPDMA_CHAN_A_ENABLE, &pktdma->rx_ch[j].cfg_a);

	/* configure tx channels */
	/* Disable loopback in the tx direction */
	writel(0, &pktdma->global->emulation_control);

	/* Set QM base address, only for K2x devices */
	writel(CONFIG_KSNAV_QM_BASE_ADDRESS, &pktdma->global->qm_base_addr[0]);

	/* Enable all channels. The current state isn't important */
	for (j = 0; j < pktdma->tx_ch_num; j++)  {
		writel(0, &pktdma->tx_ch[j].cfg_b);
		writel(CPDMA_CHAN_A_ENABLE, &pktdma->tx_ch[j].cfg_a);
	}

	return QM_OK;
}

int ksnav_close(struct pktdma_cfg *pktdma)
{
	if (!pktdma)
		return QM_ERR;

	ksnav_tx_disable(pktdma);
	ksnav_rx_disable(pktdma);

	queue_close(pktdma->rx_free_q);
	queue_close(pktdma->rx_rcv_q);
	queue_close(pktdma->tx_snd_q);

	return QM_OK;
}

int ksnav_send(struct pktdma_cfg *pktdma, u32 *pkt, int num_bytes, u32 swinfo2)
{
	struct qm_host_desc *hd;

	hd = qm_pop(qm_cfg->qpool_num);
	if (hd == NULL)
		return QM_ERR;

	hd->desc_info	= num_bytes;
	hd->swinfo[2]	= swinfo2;
	hd->packet_info = qm_cfg->qpool_num;

	qm_buff_push(hd, pktdma->tx_snd_q, pkt, num_bytes);

	return QM_OK;
}

void *ksnav_recv(struct pktdma_cfg *pktdma, u32 **pkt, int *num_bytes)
{
	struct qm_host_desc *hd;

	hd = qm_pop(pktdma->rx_rcv_q);
	if (!hd)
		return NULL;

	*pkt = (u32 *)hd->buff_ptr;
	*num_bytes = hd->desc_info & 0x3fffff;

	return hd;
}

void ksnav_release_rxhd(struct pktdma_cfg *pktdma, void *hd)
{
	struct qm_host_desc *_hd = (struct qm_host_desc *)hd;

	_hd->buff_len = _hd->orig_buff_len;
	_hd->buff_ptr = _hd->orig_buff_ptr;

	qm_push(_hd, pktdma->rx_free_q);
}
