// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
 */

/* Linux Headers */
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/amlogic/media/registers/register_map.h>
#include <linux/io.h>

/* Local Headers */
#include "osd_log.h"
#include "osd_backup.h"

#define OSDBUS_REG_ADDR(reg) ((reg) << 2)

struct reg_map_s {
	unsigned int phy_addr;
	unsigned int size;
	void __iomem *vir_addr;
	int flag;
};

static struct reg_map_s osd_reg_map = {
	.phy_addr = 0xff900000,
	.size = 0x10000,
};

int osd_io_remap(int iomap)
{
	int ret = 0;

	if (iomap) {
		if (osd_reg_map.flag)
			return 1;
		osd_reg_map.vir_addr =
			ioremap(osd_reg_map.phy_addr, osd_reg_map.size);
		if (!osd_reg_map.vir_addr) {
			pr_info("failed map phy: 0x%x\n", osd_reg_map.phy_addr);
			ret = 0;
		} else {
			osd_reg_map.flag = 1;
			pr_info("mapped phy: 0x%x\n", osd_reg_map.phy_addr);
			ret = 1;
		}
	} else {
		ret = 1;
	}
	return ret;
}

u32 osd_cbus_read(u32 reg)
{
	u32 ret = 0;
	unsigned int addr = 0;

	if (osd_reg_map.flag) {
		addr = OSDBUS_REG_ADDR(reg);
		ret = readl(osd_reg_map.vir_addr + addr);
	} else {
		ret = (u32)aml_read_cbus(reg);
	}
	osd_log_dbg3(MODULE_BASE, "%s(0x%x)=0x%x\n", __func__, reg, ret);

	return ret;
}

void osd_cbus_write(u32 reg, const u32 val)
{
	unsigned int addr = 0;

	if (osd_reg_map.flag) {
		addr = OSDBUS_REG_ADDR(reg);
		writel(val, osd_reg_map.vir_addr + addr);
	} else {
		aml_write_cbus(reg, val);
	}
	osd_log_dbg3(MODULE_BASE, "%s(0x%x, 0x%x)\n", __func__, reg, val);
}

u32 osd_reg_read(u32 reg)
{
	u32 ret = 0;
	unsigned int addr = 0;

	/* if (get_backup_reg(reg, &ret) != 0) */
	/* not read from backup */
	if (osd_reg_map.flag) {
		addr = OSDBUS_REG_ADDR(reg);
		ret = readl(osd_reg_map.vir_addr + addr);
	} else {
		ret = (u32)aml_read_vcbus(reg);
	}
	osd_log_dbg3(MODULE_BASE, "%s(0x%x)=0x%x\n", __func__, reg, ret);
	return ret;
}

int osd_reg_write(u32 reg, u32 val)
{
	unsigned int addr = 0;

	if (osd_reg_map.flag) {
		addr = OSDBUS_REG_ADDR(reg);
		writel(val, osd_reg_map.vir_addr + addr);
	} else {
		aml_write_vcbus(reg, val);
	}
	update_backup_reg(reg, val);
	osd_log_dbg3(MODULE_BASE, "%s(0x%x, 0x%x)\n", __func__, reg, val);
	return  0;
}

int osd_reg_set_mask(u32 reg, u32 mask)
{
	return osd_reg_write(reg, (osd_reg_read(reg) | (mask)));
}

int osd_reg_clr_mask(u32 reg, u32 mask)
{
	return osd_reg_write(reg, (osd_reg_read(reg) & (~(mask))));
}

int osd_reg_set_bits(u32 reg,
		      u32 value,
		      u32 start,
		      u32 len)
{
	return osd_reg_write(reg, ((osd_reg_read(reg) &
			     ~(((1L << (len)) - 1) << (start))) |
			    (((value) & ((1L << (len)) - 1)) << (start))));
}

