blob: 859ae92ae47f993861ecf38d3a4674e4704ca8ba [file] [log] [blame] [edit]
/*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Description:
*/
#include <linux/io.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/printk.h>
#include <linux/string.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/regmap.h>
#include <linux/device.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include "../chips/decoder_cpu_ver_info.h"
#include "register.h"
static void __iomem *reg_base[MAX_REG_BUS];
struct bus_reg_desc *reg_desc[MAX_REG_BUS];
#define CODEC_REG_READ_DEBUG 0x01
#define CODEC_REG_WRITE_DEBUG 0x02
#define CODEC_REG_MAP_DEBUG 0x08
static u32 register_debug;
module_param(register_debug, uint, 0664);
void registers_offset_config(struct bus_reg_desc *offset_from, s32 val, u32 size)
{
u32 i;
for (i = 0; i < size; i++) {
offset_from[i].reg_compat_offset = val;
}
}
EXPORT_SYMBOL(registers_offset_config);
void s5_mm_registers_compat(struct bus_reg_desc *desc, MM_BUS_ENUM bs)
{
if (bs == DOS_BUS) {
printk("s5 dos register compat\n");
registers_offset_config(&desc[HEVC_ASSIST_AMR1_INT0],
-(0x0025 - 0x0015),
(HEVC_ASSIST_MBX_SSEL - HEVC_ASSIST_AMR1_INT0 + 1));
registers_offset_config(&desc[HEVC_ASSIST_TIMER0_LO],
-(0x0060 - 0x0036),
(HEVC_ASSIST_DMA_INT_MSK2 - HEVC_ASSIST_TIMER0_LO + 1));
registers_offset_config(&desc[HEVC_ASSIST_MBOX0_IRQ_REG],
-(0x0070 - 0x0040),
(HEVC_ASSIST_AXI_STATUS2_LO - HEVC_ASSIST_MBOX0_IRQ_REG + 1));
registers_offset_config(&desc[HEVC_ASSIST_SCRATCH_0],
-(0x00c0 - 0x00b0),
(HEVC_ASSIST_SCRATCH_N - HEVC_ASSIST_SCRATCH_0) + 1);
registers_offset_config(&desc[AV1D_IPP_DIR_CFG], -(0x0490 - 0x0419), 1);
}
}
void t3_mm_registers_compat(struct bus_reg_desc *desc, MM_BUS_ENUM bs)
{
registers_offset_config(&desc[AV1D_IPP_DIR_CFG], -(0x0490 - 0x0419), 1);
}
//###############################################################################
ulong dos_reg_compat_convert(ulong addr)
{
s32 reg_compat_offset;
struct bus_reg_desc *dos_desc = reg_desc[DOS_BUS];
if (addr & NEW_REG_CHECK_MASK) {
addr &= (~NEW_REG_CHECK_MASK);
reg_compat_offset = 0;
} else {
reg_compat_offset = dos_desc[addr].reg_compat_offset;
}
return (addr + reg_compat_offset);
}
EXPORT_SYMBOL(dos_reg_compat_convert);
void write_dos_reg(ulong addr, int val)
{
void __iomem * reg_adr;
s32 reg_compat_offset;
struct bus_reg_desc *dos_desc = reg_desc[DOS_BUS];
if (addr & NEW_REG_CHECK_MASK) {
addr &= (~NEW_REG_CHECK_MASK);
reg_compat_offset = 0;
} else {
reg_compat_offset = dos_desc[addr].reg_compat_offset;
}
if ((reg_compat_offset + addr) < 0) {
pr_err("write dos reg out of range, name %s, addr %lx, offset %d\n",
dos_desc[addr].reg_name, addr, reg_compat_offset);
return;
}
reg_adr = reg_base[DOS_BUS] + ((reg_compat_offset + addr) << 2);
if (register_debug) {
if (register_debug & CODEC_REG_WRITE_DEBUG) {
pr_info("write_reg(%lx, %x)\n", (reg_compat_offset + addr), val);
}
if (register_debug & CODEC_REG_MAP_DEBUG) {
pr_info("%s %px, name %s, addr %lx, offset %d\n",
__func__, reg_adr, dos_desc[addr].reg_name, addr, reg_compat_offset);
}
}
writel(val, reg_adr);
}
EXPORT_SYMBOL(write_dos_reg);
int read_dos_reg(ulong addr)
{
void __iomem * reg_adr;
int value;
struct bus_reg_desc *dos_desc = reg_desc[DOS_BUS];
s32 reg_compat_offset;
if (addr & NEW_REG_CHECK_MASK) {
addr &= (~NEW_REG_CHECK_MASK);
reg_compat_offset = 0;
} else {
reg_compat_offset = dos_desc[addr].reg_compat_offset;
}
if ((reg_compat_offset + addr) < 0) {
pr_err("read dos reg out of range, name %s, addr %lx, offset %d\n",
dos_desc[addr].reg_name, addr, reg_compat_offset);
return -ENXIO;
}
reg_adr = reg_base[DOS_BUS] + ((reg_compat_offset + addr) << 2);
value = readl(reg_adr);
if (register_debug) {
if (register_debug & CODEC_REG_READ_DEBUG) {
pr_info("read_reg(%lx) = %x\n", (reg_compat_offset + addr), value);
}
if (register_debug & CODEC_REG_MAP_DEBUG) {
pr_info("%s %px, name %s, addr %lx, offset %d\n",
__func__, reg_adr, dos_desc[addr].reg_name, addr, reg_compat_offset);
}
}
return value;
}
EXPORT_SYMBOL(read_dos_reg);
int read_dos_reg_comp(ulong addr)
{
if (is_support_new_dos_dev())
return read_dos_reg(addr);
else
return aml_read_dosbus((uint)addr);
}
EXPORT_SYMBOL(read_dos_reg_comp);
void write_dos_reg_comp(ulong addr, int val)
{
if (is_support_new_dos_dev())
write_dos_reg(addr, val);
else
aml_write_dosbus((uint)addr, (uint)val);
}
EXPORT_SYMBOL(write_dos_reg_comp);
void dos_reg_write_bits(unsigned int reg, u32 val, int start, int len)
{
u32 to_val = read_dos_reg_comp(reg);
u32 mask = (((1L << (len)) - 1) << (start));
to_val &= ~mask;
to_val |= (val << start) & mask;
write_dos_reg_comp(reg, to_val);
}
EXPORT_SYMBOL(dos_reg_write_bits);
int dos_register_probe(struct platform_device *pdev, reg_compat_func reg_compat_fn)
{
u32 i;
struct resource res;
u32 res_size;
if (pdev == NULL) {
pr_info("no dev found, dos_register can not map\n");
return -ENODEV;
}
for (i = 0; i < MAX_REG_BUS; i++) {
if (of_address_to_resource(pdev->dev.of_node, i, &res)) {
pr_err("of_address_to_resource failed\n");
return -EINVAL;
}
res_size = resource_size(&res);
reg_base[i] = ioremap(res.start, res_size);
pr_info("%s, res start %llx, end %llx, iomap: %px\n",
__func__, (unsigned long long)res.start,
(unsigned long long)res.end, reg_base[i]);
reg_desc[i] = (struct bus_reg_desc *)kzalloc(res_size *
sizeof(struct bus_reg_desc), GFP_KERNEL);
if (!reg_desc[i])
pr_err("Warn: dos regs offset table alloc failed\n");
if (reg_compat_fn)
reg_compat_fn(reg_desc[i], i);
}
return 0;
}
EXPORT_SYMBOL(dos_register_probe);