mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
soc: rockchip: hw-decompress: Add support rockchip hardware decompress
Change-Id: Ib882919642a6c72b0292292bc0fd35d7a3d78dee Signed-off-by: Simon Xue <xxm@rock-chips.com> Signed-off-by: Tao Huang <huangtao@rock-chips.com>
This commit is contained in:
@@ -34,6 +34,12 @@ config ROCKCHIP_GRF
|
||||
In a lot of cases there also need to be default settings initialized
|
||||
to make some of them conform to expectations of the kernel.
|
||||
|
||||
config ROCKCHIP_HW_DECOMPRESS
|
||||
bool "Rockchip HardWare Decompress Support"
|
||||
help
|
||||
This driver support Decompress IP built-in Rockchip SoC, support
|
||||
LZ4, GZIP, ZLIB.
|
||||
|
||||
config ROCKCHIP_IPA
|
||||
bool "Rockchip IPA support"
|
||||
depends on THERMAL && OF
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#
|
||||
obj-$(CONFIG_ROCKCHIP_CPUINFO) += rockchip-cpuinfo.o
|
||||
obj-$(CONFIG_ROCKCHIP_GRF) += grf.o
|
||||
obj-$(CONFIG_ROCKCHIP_HW_DECOMPRESS) += rockchip_decompress.o
|
||||
obj-$(CONFIG_ROCKCHIP_PM_DOMAINS) += pm_domains.o
|
||||
obj-$(CONFIG_FIQ_DEBUGGER) += rk_fiq_debugger.o
|
||||
obj-$(CONFIG_MMC_DW_ROCKCHIP) += sdmmc_vendor_storage.o
|
||||
|
||||
239
drivers/soc/rockchip/rockchip_decompress.c
Normal file
239
drivers/soc/rockchip/rockchip_decompress.c
Normal file
@@ -0,0 +1,239 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2020 Rockchip Electronics Co., Ltd
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/initramfs.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define DECOM_CTRL 0x0
|
||||
#define DECOM_ENR 0x4
|
||||
#define DECOM_RADDR 0x8
|
||||
#define DECOM_WADDR 0xc
|
||||
#define DECOM_UDDSL 0x10
|
||||
#define DECOM_UDDSH 0x14
|
||||
#define DECOM_TXTHR 0x18
|
||||
#define DECOM_RXTHR 0x1c
|
||||
#define DECOM_SLEN 0x20
|
||||
#define DECOM_STAT 0x24
|
||||
#define DECOM_ISR 0x28
|
||||
#define DECOM_IEN 0x2c
|
||||
#define DECOM_AXI_STAT 0x30
|
||||
#define DECOM_TSIZEL 0x34
|
||||
#define DECOM_TSIZEH 0x38
|
||||
#define DECOM_MGNUM 0x3c
|
||||
#define DECOM_FRAME 0x40
|
||||
#define DECOM_DICTID 0x44
|
||||
#define DECOM_CSL 0x48
|
||||
#define DECOM_CSH 0x4c
|
||||
|
||||
#define LZ4_HEAD_CSUM_CHECK_EN BIT(1)
|
||||
#define LZ4_BLOCK_CSUM_CHECK_EN BIT(2)
|
||||
#define LZ4_CONT_CSUM_CHECK_EN BIT(3)
|
||||
|
||||
#define DSOLIEN BIT(19)
|
||||
#define ZDICTEIEN BIT(18)
|
||||
#define GCMEIEN BIT(17)
|
||||
#define GIDEIEN BIT(16)
|
||||
#define CCCEIEN BIT(15)
|
||||
#define BCCEIEN BIT(14)
|
||||
#define HCCEIEN BIT(13)
|
||||
#define CSEIEN BIT(12)
|
||||
#define DICTEIEN BIT(11)
|
||||
#define VNEIEN BIT(10)
|
||||
#define WNEIEN BIT(9)
|
||||
#define RDCEIEN BIT(8)
|
||||
#define WRCEIEN BIT(7)
|
||||
#define DISEIEN BIT(6)
|
||||
#define LENEIEN BIT(5)
|
||||
#define LITEIEN BIT(4)
|
||||
#define SQMEIEN BIT(3)
|
||||
#define SLCIEN BIT(2)
|
||||
#define HDEIEN BIT(1)
|
||||
#define DSIEN BIT(0)
|
||||
|
||||
#define DECOM_STOP BIT(0)
|
||||
#define DECOM_COMPLETE BIT(0)
|
||||
#define DECOM_GZIP_MODE BIT(4)
|
||||
#define DECOM_ZLIB_MODE BIT(5)
|
||||
#define DECOM_DEFLATE_MODE BIT(0)
|
||||
|
||||
#define DECOM_ENABLE 0x1
|
||||
#define DECOM_DISABLE 0x0
|
||||
|
||||
#define DECOM_INT_MASK \
|
||||
(DSOLIEN | ZDICTEIEN | GCMEIEN | GIDEIEN | \
|
||||
CCCEIEN | BCCEIEN | HCCEIEN | CSEIEN | \
|
||||
DICTEIEN | VNEIEN | WNEIEN | RDCEIEN | WRCEIEN | \
|
||||
DISEIEN | LENEIEN | LITEIEN | SQMEIEN | SLCIEN | \
|
||||
HDEIEN | DSIEN)
|
||||
|
||||
enum decom_mod {
|
||||
LZ4_MOD,
|
||||
GZIP_MOD,
|
||||
ZLIB_MOD,
|
||||
};
|
||||
|
||||
struct rk_decom {
|
||||
struct device *dev;
|
||||
int irq;
|
||||
int num_clocks;
|
||||
struct clk_bulk_data *clocks;
|
||||
void __iomem *regs;
|
||||
phys_addr_t mem_start;
|
||||
size_t mem_size;
|
||||
};
|
||||
|
||||
static DECLARE_WAIT_QUEUE_HEAD(initrd_decom_done);
|
||||
static bool initrd_continue;
|
||||
|
||||
void __init wait_initrd_hw_decom_done(void)
|
||||
{
|
||||
wait_event(initrd_decom_done, initrd_continue);
|
||||
}
|
||||
|
||||
static irqreturn_t rk_decom_irq_handler(int irq, void *priv)
|
||||
{
|
||||
struct rk_decom *rk_dec = priv;
|
||||
u32 irq_status;
|
||||
u32 decom_status;
|
||||
|
||||
irq_status = readl(rk_dec->regs + DECOM_ISR);
|
||||
/* clear interrupts */
|
||||
writel(irq_status, rk_dec->regs + DECOM_ISR);
|
||||
if (irq_status & DECOM_STOP) {
|
||||
decom_status = readl(rk_dec->regs + DECOM_STAT);
|
||||
if (decom_status & DECOM_COMPLETE) {
|
||||
initrd_continue = true;
|
||||
wake_up(&initrd_decom_done);
|
||||
dev_info(rk_dec->dev, "decom completed\n");
|
||||
} else {
|
||||
dev_info(rk_dec->dev,
|
||||
"decom failed, irq_status = 0x%x, decom_status = 0x%x\n",
|
||||
irq_status, decom_status);
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t rk_decom_irq_thread(int irq, void *priv)
|
||||
{
|
||||
struct rk_decom *rk_dec = priv;
|
||||
|
||||
if (initrd_continue) {
|
||||
void *start, *end;
|
||||
|
||||
/*
|
||||
* Now it is safe to free reserve memory that
|
||||
* store the origin ramdisk file
|
||||
*/
|
||||
start = phys_to_virt(rk_dec->mem_start);
|
||||
end = start + rk_dec->mem_size;
|
||||
free_reserved_area(start, end, -1, "ramdisk gzip archive");
|
||||
}
|
||||
|
||||
clk_bulk_disable_unprepare(rk_dec->num_clocks, rk_dec->clocks);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rockchip_decom_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rk_decom *rk_dec;
|
||||
struct resource *res = NULL;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device_node *mem;
|
||||
struct resource reg;
|
||||
int ret = 0;
|
||||
|
||||
rk_dec = devm_kzalloc(dev, sizeof(*rk_dec), GFP_KERNEL);
|
||||
if (!rk_dec)
|
||||
return -ENOMEM;
|
||||
|
||||
rk_dec->dev = dev;
|
||||
rk_dec->irq = platform_get_irq(pdev, 0);
|
||||
if (rk_dec->irq < 0) {
|
||||
dev_err(dev, "failed to get rk_dec irq\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
mem = of_parse_phandle(np, "memory-region", 0);
|
||||
if (!mem) {
|
||||
dev_err(dev, "missing \"memory-region\" property\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = of_address_to_resource(mem, 0, ®);
|
||||
if (ret) {
|
||||
dev_err(dev, "missing \"reg\" property\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rk_dec->mem_start = reg.start;
|
||||
rk_dec->mem_size = resource_size(®);
|
||||
|
||||
rk_dec->num_clocks = devm_clk_bulk_get_all(dev, &rk_dec->clocks);
|
||||
if (rk_dec->num_clocks < 0) {
|
||||
dev_err(dev, "failed to get decompress clock\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = clk_bulk_prepare_enable(rk_dec->num_clocks, rk_dec->clocks);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
rk_dec->regs = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(rk_dec->regs)) {
|
||||
ret = PTR_ERR(rk_dec->regs);
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, rk_dec);
|
||||
|
||||
ret = devm_request_threaded_irq(dev, rk_dec->irq, rk_decom_irq_handler,
|
||||
rk_decom_irq_thread, IRQF_ONESHOT,
|
||||
dev_name(dev), rk_dec);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to attach decompress irq\n");
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
disable_clk:
|
||||
clk_bulk_disable_unprepare(rk_dec->num_clocks, rk_dec->clocks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id rockchip_decom_dt_match[] = {
|
||||
{ .compatible = "rockchip,hw-decompress" },
|
||||
{},
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_driver rk_decom_driver = {
|
||||
.driver = {
|
||||
.name = "rockchip_hw_decompress",
|
||||
.of_match_table = rockchip_decom_dt_match,
|
||||
},
|
||||
.probe = rockchip_decom_probe,
|
||||
};
|
||||
|
||||
static int __init rockchip_hw_decompress_init(void)
|
||||
{
|
||||
return platform_driver_register(&rk_decom_driver);
|
||||
}
|
||||
|
||||
pure_initcall(rockchip_hw_decompress_init);
|
||||
Reference in New Issue
Block a user