MLK-15110-2 gpu: imx: Add i.MX8 PRG(Prefetch Resolve Gasket) support
The Pretch Resolve Gasket(PRG) is a digital core function as a gasket interface between RTRAM controller and DPU. The main function of PRG is to convert the AXI interface to RTRAM interface and remapping the ARADDR to a RTRAM address. This patch adds the base driver support for i.MX8qm/qxp PRG. Signed-off-by: Liu Ying <victor.liu@nxp.com>pull/10/head
parent
fac96bc989
commit
2f10fa80db
|
@ -246,6 +246,29 @@ dcss_drm: dcss@0x32e00000 {
|
|||
};
|
||||
};
|
||||
|
||||
Freescale i.MX8 PRG (Prefetch Resolve Gasket)
|
||||
=============================================
|
||||
Required properties:
|
||||
- compatible: should be "fsl,<chip>-prg"
|
||||
- reg: should be register base and length as documented in the
|
||||
datasheet
|
||||
- clocks: phandles to the PRG apb and rtram clocks, as described in
|
||||
Documentation/devicetree/bindings/clock/clock-bindings.txt,
|
||||
Documentation/devicetree/bindings/clock/imx8qm-clock.txt and
|
||||
Documentation/devicetree/bindings/clock/imx8qxp-clock.txt
|
||||
- clock-names: should be "apb" and "rtram"
|
||||
- power-domains: phandle pointing to power domain
|
||||
|
||||
example:
|
||||
|
||||
prg@56040000 {
|
||||
compatible = "fsl,imx8qm-prg";
|
||||
reg = <0x0 0x56040000 0x0 0x10000>;
|
||||
clocks = <&clk IMX8QM_DC0_PRG0_APB_CLK>,
|
||||
<&clk IMX8QM_DC0_PRG0_RTRAM_CLK>;
|
||||
clock-names = "apb", "rtram";
|
||||
power-domains = <&pd_dc0>;
|
||||
};
|
||||
|
||||
Parallel display support
|
||||
========================
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
config IMX8_PRG
|
||||
tristate
|
||||
default y if IMX_DPU_CORE=y
|
||||
default m if IMX_DPU_CORE=m
|
||||
|
||||
source drivers/gpu/imx/ipu-v3/Kconfig
|
||||
source drivers/gpu/imx/dpu/Kconfig
|
||||
source drivers/gpu/imx/dpu-blit/Kconfig
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
obj-$(CONFIG_IMX8_PRG) += imx8_prg.o
|
||||
|
||||
obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/
|
||||
obj-$(CONFIG_IMX_DPU_CORE) += dpu/
|
||||
obj-$(CONFIG_IMX_DPU_BLIT) += dpu-blit/
|
||||
|
|
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
* Copyright 2017 NXP
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <video/imx8-prefetch.h>
|
||||
|
||||
#define SET 0x4
|
||||
#define CLR 0x8
|
||||
#define TOG 0xc
|
||||
|
||||
#define PRG_CTRL 0x00
|
||||
#define BYPASS BIT(0)
|
||||
#define SC_DATA_TYPE BIT(2)
|
||||
#define SC_DATA_TYPE_8BIT 0
|
||||
#define SC_DATA_TYPE_10BIT BIT(2)
|
||||
#define UV_EN BIT(3)
|
||||
#define HANDSHAKE_MODE BIT(4)
|
||||
#define HANDSHAKE_MODE_4LINES 0
|
||||
#define HANDSHAKE_MODE_8LINES BIT(4)
|
||||
#define SHADOW_LOAD_MODE BIT(5)
|
||||
#define DES_DATA_TYPE 0x30000
|
||||
enum {
|
||||
DES_DATA_TYPE_32BPP = (0 << 16),
|
||||
DES_DATA_TYPE_24BPP = (1 << 16),
|
||||
DES_DATA_TYPE_16BPP = (2 << 16),
|
||||
DES_DATA_TYPE_8BPP = (3 << 16),
|
||||
};
|
||||
#define SOFTRST BIT(30)
|
||||
#define SHADOW_EN BIT(31)
|
||||
|
||||
#define PRG_STATUS 0x10
|
||||
#define BUFFER_VALID_B BIT(1)
|
||||
#define BUFFER_VALID_A BIT(0)
|
||||
|
||||
#define PRG_REG_UPDATE 0x20
|
||||
#define REG_UPDATE BIT(0)
|
||||
|
||||
#define PRG_STRIDE 0x30
|
||||
#define STRIDE(n) (((n) - 1) & 0xffff)
|
||||
|
||||
#define PRG_HEIGHT 0x40
|
||||
#define HEIGHT(n) (((n) - 1) & 0xffff)
|
||||
|
||||
#define PRG_BADDR 0x50
|
||||
|
||||
#define PRG_OFFSET 0x60
|
||||
#define Y(n) (((n) & 0x7) << 16)
|
||||
#define X(n) ((n) & 0xffff)
|
||||
|
||||
#define PRG_WIDTH 0x70
|
||||
#define WIDTH(n) (((n) - 1) & 0xffff)
|
||||
|
||||
struct prg {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct list_head list;
|
||||
struct clk *clk_apb;
|
||||
struct clk *clk_rtram;
|
||||
bool is_auxiliary;
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(prg_list_mutex);
|
||||
static LIST_HEAD(prg_list);
|
||||
|
||||
static inline u32 prg_read(struct prg *prg, unsigned int offset)
|
||||
{
|
||||
return readl(prg->base + offset);
|
||||
}
|
||||
|
||||
static inline void prg_write(struct prg *prg, u32 value, unsigned int offset)
|
||||
{
|
||||
writel(value, prg->base + offset);
|
||||
}
|
||||
|
||||
static void prg_reset(struct prg *prg)
|
||||
{
|
||||
prg_write(prg, SOFTRST, PRG_CTRL + SET);
|
||||
usleep_range(1000, 2000);
|
||||
prg_write(prg, SOFTRST, PRG_CTRL + CLR);
|
||||
}
|
||||
|
||||
void prg_enable(struct prg *prg)
|
||||
{
|
||||
if (WARN_ON(!prg))
|
||||
return;
|
||||
|
||||
prg_write(prg, BYPASS, PRG_CTRL + CLR);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(prg_enable);
|
||||
|
||||
void prg_disable(struct prg *prg)
|
||||
{
|
||||
if (WARN_ON(!prg))
|
||||
return;
|
||||
|
||||
prg_write(prg, BYPASS, PRG_CTRL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(prg_disable);
|
||||
|
||||
void prg_configure(struct prg *prg, unsigned int width, unsigned int height,
|
||||
unsigned int x_offset, unsigned int y_offset,
|
||||
unsigned int stride, unsigned int bits_per_pixel,
|
||||
unsigned long baddr, u32 format, u64 modifier,
|
||||
bool start)
|
||||
{
|
||||
unsigned int burst_size;
|
||||
u32 val;
|
||||
|
||||
if (WARN_ON(!prg))
|
||||
return;
|
||||
|
||||
if (start)
|
||||
prg_reset(prg);
|
||||
|
||||
/*
|
||||
* address TKT343664:
|
||||
* fetch unit base address has to align to burst_size
|
||||
*/
|
||||
burst_size = 1 << (ffs(baddr) - 1);
|
||||
burst_size = min(burst_size, 128U);
|
||||
|
||||
/*
|
||||
* address TKT339017:
|
||||
* fixup for burst size vs stride mismatch
|
||||
*/
|
||||
stride = round_up(stride, burst_size);
|
||||
|
||||
/*
|
||||
* address TKT342628(part 1):
|
||||
* when prg stride is less or equals to burst size,
|
||||
* the auxiliary prg height needs to be a half
|
||||
*/
|
||||
if (prg->is_auxiliary && stride <= burst_size)
|
||||
height /= 2;
|
||||
|
||||
/* prg finer cropping into tile block - top/left start point */
|
||||
switch (modifier) {
|
||||
case DRM_FORMAT_MOD_NONE:
|
||||
break;
|
||||
case DRM_FORMAT_MOD_AMPHION_TILED:
|
||||
x_offset %= AMPHION_STRIPE_WIDTH;
|
||||
y_offset %= (prg->is_auxiliary ?
|
||||
AMPHION_UV_STRIPE_HEIGHT : AMPHION_Y_STRIPE_HEIGHT);
|
||||
break;
|
||||
case DRM_FORMAT_MOD_VIVANTE_TILED:
|
||||
x_offset %= VIVANTE_TILE_WIDTH;
|
||||
y_offset %= VIVANTE_TILE_HEIGHT;
|
||||
break;
|
||||
case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
|
||||
x_offset %= VIVANTE_SUPER_TILE_WIDTH;
|
||||
y_offset %= VIVANTE_SUPER_TILE_HEIGHT;
|
||||
break;
|
||||
default:
|
||||
dev_err(prg->dev, "unsupported modifier 0x%016llx\n",
|
||||
modifier);
|
||||
return;
|
||||
}
|
||||
|
||||
if (y_offset >
|
||||
((format == DRM_FORMAT_NV21 || format == DRM_FORMAT_NV12) ?
|
||||
(PRG_HANDSHAKE_8LINES - 1) : (PRG_HANDSHAKE_4LINES - 1))) {
|
||||
dev_err(prg->dev,
|
||||
"unsupported crop line %d for modifier 0x%016llx\n",
|
||||
y_offset, modifier);
|
||||
return;
|
||||
}
|
||||
|
||||
prg_write(prg, STRIDE(stride), PRG_STRIDE);
|
||||
prg_write(prg, WIDTH(width), PRG_WIDTH);
|
||||
prg_write(prg, HEIGHT(height), PRG_HEIGHT);
|
||||
prg_write(prg, X(x_offset) | Y(y_offset), PRG_OFFSET);
|
||||
prg_write(prg, baddr, PRG_BADDR);
|
||||
|
||||
val = prg_read(prg, PRG_CTRL);
|
||||
val &= ~SC_DATA_TYPE;
|
||||
val |= SC_DATA_TYPE_8BIT;
|
||||
val &= ~HANDSHAKE_MODE;
|
||||
if (format == DRM_FORMAT_NV21 || format == DRM_FORMAT_NV12) {
|
||||
val |= HANDSHAKE_MODE_8LINES;
|
||||
/*
|
||||
* address TKT342628(part 2):
|
||||
* when prg stride is less or equals to burst size,
|
||||
* we disable UV_EN bit for the auxiliary prg
|
||||
*/
|
||||
if (prg->is_auxiliary && stride > burst_size)
|
||||
val |= UV_EN;
|
||||
else
|
||||
val &= ~UV_EN;
|
||||
} else {
|
||||
val |= HANDSHAKE_MODE_4LINES;
|
||||
val &= ~UV_EN;
|
||||
}
|
||||
val |= SHADOW_LOAD_MODE;
|
||||
val &= ~DES_DATA_TYPE;
|
||||
switch (bits_per_pixel) {
|
||||
case 32:
|
||||
val |= DES_DATA_TYPE_32BPP;
|
||||
break;
|
||||
case 24:
|
||||
val |= DES_DATA_TYPE_24BPP;
|
||||
break;
|
||||
case 16:
|
||||
val |= DES_DATA_TYPE_16BPP;
|
||||
break;
|
||||
case 8:
|
||||
val |= DES_DATA_TYPE_8BPP;
|
||||
break;
|
||||
}
|
||||
if (start)
|
||||
/* no shadow for the first frame */
|
||||
val &= ~SHADOW_EN;
|
||||
else
|
||||
val |= SHADOW_EN;
|
||||
prg_write(prg, val, PRG_CTRL);
|
||||
|
||||
dev_dbg(prg->dev, "bits per pixel %u\n", bits_per_pixel);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(prg_configure);
|
||||
|
||||
void prg_reg_update(struct prg *prg)
|
||||
{
|
||||
if (WARN_ON(!prg))
|
||||
return;
|
||||
|
||||
prg_write(prg, REG_UPDATE, PRG_REG_UPDATE);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(prg_reg_update);
|
||||
|
||||
void prg_shadow_enable(struct prg *prg)
|
||||
{
|
||||
if (WARN_ON(!prg))
|
||||
return;
|
||||
|
||||
prg_write(prg, SHADOW_EN, PRG_CTRL + SET);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(prg_shadow_enable);
|
||||
|
||||
bool prg_stride_supported(struct prg *prg, unsigned int stride)
|
||||
{
|
||||
return stride < 0x10000;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(prg_stride_supported);
|
||||
|
||||
bool prg_stride_double_check(struct prg *prg,
|
||||
unsigned int stride, dma_addr_t baddr)
|
||||
{
|
||||
unsigned int burst_size;
|
||||
|
||||
/*
|
||||
* address TKT343664:
|
||||
* fetch unit base address has to align to burst size
|
||||
*/
|
||||
burst_size = 1 << (ffs(baddr) - 1);
|
||||
burst_size = min(burst_size, 128U);
|
||||
|
||||
/*
|
||||
* address TKT339017:
|
||||
* fixup for burst size vs stride mismatch
|
||||
*/
|
||||
stride = round_up(stride, burst_size);
|
||||
|
||||
return stride < 0x10000;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(prg_stride_double_check);
|
||||
|
||||
void prg_set_auxiliary(struct prg *prg)
|
||||
{
|
||||
if (WARN_ON(!prg))
|
||||
return;
|
||||
|
||||
prg->is_auxiliary = true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(prg_set_auxiliary);
|
||||
|
||||
struct prg *
|
||||
prg_lookup_by_phandle(struct device *dev, const char *name, int index)
|
||||
{
|
||||
struct device_node *prg_node = of_parse_phandle(dev->of_node,
|
||||
name, index);
|
||||
struct prg *prg;
|
||||
|
||||
mutex_lock(&prg_list_mutex);
|
||||
list_for_each_entry(prg, &prg_list, list) {
|
||||
if (prg_node == prg->dev->of_node) {
|
||||
mutex_unlock(&prg_list_mutex);
|
||||
device_link_add(dev, prg->dev, DL_FLAG_AUTOREMOVE);
|
||||
return prg;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&prg_list_mutex);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(prg_lookup_by_phandle);
|
||||
|
||||
static int prg_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
struct prg *prg;
|
||||
|
||||
prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL);
|
||||
if (!prg)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
prg->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(prg->base))
|
||||
return PTR_ERR(prg->base);
|
||||
|
||||
prg->clk_apb = devm_clk_get(dev, "apb");
|
||||
if (IS_ERR(prg->clk_apb))
|
||||
return PTR_ERR(prg->clk_apb);
|
||||
clk_prepare_enable(prg->clk_apb);
|
||||
|
||||
prg->clk_rtram = devm_clk_get(dev, "rtram");
|
||||
if (IS_ERR(prg->clk_rtram))
|
||||
return PTR_ERR(prg->clk_rtram);
|
||||
clk_prepare_enable(prg->clk_rtram);
|
||||
|
||||
prg->dev = dev;
|
||||
platform_set_drvdata(pdev, prg);
|
||||
mutex_lock(&prg_list_mutex);
|
||||
list_add(&prg->list, &prg_list);
|
||||
mutex_unlock(&prg_list_mutex);
|
||||
|
||||
prg_reset(prg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prg_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct prg *prg = platform_get_drvdata(pdev);
|
||||
|
||||
mutex_lock(&prg_list_mutex);
|
||||
list_del(&prg->list);
|
||||
mutex_unlock(&prg_list_mutex);
|
||||
|
||||
clk_disable_unprepare(prg->clk_rtram);
|
||||
clk_disable_unprepare(prg->clk_apb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id prg_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx8qm-prg", },
|
||||
{ .compatible = "fsl,imx8qxp-prg", },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
struct platform_driver prg_drv = {
|
||||
.probe = prg_probe,
|
||||
.remove = prg_remove,
|
||||
.driver = {
|
||||
.name = "imx8-prg",
|
||||
.of_match_table = prg_dt_ids,
|
||||
},
|
||||
};
|
||||
module_platform_driver(prg_drv);
|
||||
|
||||
MODULE_DESCRIPTION("i.MX8 PRG driver");
|
||||
MODULE_AUTHOR("NXP Semiconductor");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2017 NXP
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _IMX8_PREFETCH_H_
|
||||
#define _IMX8_PREFETCH_H_
|
||||
|
||||
#define PRG_HANDSHAKE_8LINES 8
|
||||
#define PRG_HANDSHAKE_4LINES 4
|
||||
#define AMPHION_STRIPE_WIDTH 8
|
||||
#define AMPHION_STRIPE_HEIGHT 128
|
||||
#define AMPHION_UV_STRIPE_HEIGHT AMPHION_STRIPE_HEIGHT
|
||||
#define AMPHION_Y_STRIPE_HEIGHT (2 * AMPHION_STRIPE_HEIGHT)
|
||||
#define VIVANTE_TILE_WIDTH 4
|
||||
#define VIVANTE_TILE_HEIGHT 4
|
||||
#define VIVANTE_SUPER_TILE_WIDTH 64
|
||||
#define VIVANTE_SUPER_TILE_HEIGHT 64
|
||||
|
||||
struct prg;
|
||||
struct prg *
|
||||
prg_lookup_by_phandle(struct device *dev, const char *name, int index);
|
||||
void prg_enable(struct prg *prg);
|
||||
void prg_disable(struct prg *prg);
|
||||
void prg_configure(struct prg *prg, unsigned int width, unsigned int height,
|
||||
unsigned int x_offset, unsigned int y_offset,
|
||||
unsigned int stride, unsigned int bits_per_pixel,
|
||||
unsigned long baddr, u32 format, u64 modifier,
|
||||
bool start);
|
||||
void prg_reg_update(struct prg *prg);
|
||||
void prg_shadow_enable(struct prg *prg);
|
||||
bool prg_stride_supported(struct prg *prg, unsigned int stride);
|
||||
bool prg_stride_double_check(struct prg *prg,
|
||||
unsigned int stride, dma_addr_t baddr);
|
||||
void prg_set_auxiliary(struct prg *prg);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue