linux/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c
Marijn Suijten babdb815ef drm/msm/dpu: Pass catalog pointers in RM to replace for-loop ID lookups
The Resource Manager already iterates over all available blocks from the
catalog, only to pass their ID to a dpu_hw_xxx_init() function which
uses an _xxx_offset() helper to search for and find the exact same
catalog pointer again to initialize the block with, fallible error
handling and all.

Instead, pass const pointers to the catalog entries directly to these
_init functions and drop the for loops entirely, saving on both
readability complexity and unnecessary cycles at boot.

Signed-off-by: Marijn Suijten <marijn.suijten@somainline.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Patchwork: https://patchwork.freedesktop.org/patch/533861/
Link: https://lore.kernel.org/r/20230418-dpu-drop-useless-for-lookup-v3-3-e8d869eea455@somainline.org
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
2023-05-22 10:14:16 +03:00

242 lines
5.7 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*/
#include "dpu_hwio.h"
#include "dpu_hw_catalog.h"
#include "dpu_hw_vbif.h"
#define VBIF_VERSION 0x0000
#define VBIF_CLK_FORCE_CTRL0 0x0008
#define VBIF_CLK_FORCE_CTRL1 0x000C
#define VBIF_QOS_REMAP_00 0x0020
#define VBIF_QOS_REMAP_01 0x0024
#define VBIF_QOS_REMAP_10 0x0028
#define VBIF_QOS_REMAP_11 0x002C
#define VBIF_WRITE_GATHER_EN 0x00AC
#define VBIF_IN_RD_LIM_CONF0 0x00B0
#define VBIF_IN_RD_LIM_CONF1 0x00B4
#define VBIF_IN_RD_LIM_CONF2 0x00B8
#define VBIF_IN_WR_LIM_CONF0 0x00C0
#define VBIF_IN_WR_LIM_CONF1 0x00C4
#define VBIF_IN_WR_LIM_CONF2 0x00C8
#define VBIF_OUT_RD_LIM_CONF0 0x00D0
#define VBIF_OUT_WR_LIM_CONF0 0x00D4
#define VBIF_OUT_AXI_AMEMTYPE_CONF0 0x0160
#define VBIF_OUT_AXI_AMEMTYPE_CONF1 0x0164
#define VBIF_XIN_PND_ERR 0x0190
#define VBIF_XIN_SRC_ERR 0x0194
#define VBIF_XIN_CLR_ERR 0x019C
#define VBIF_XIN_HALT_CTRL0 0x0200
#define VBIF_XIN_HALT_CTRL1 0x0204
#define VBIF_XINL_QOS_RP_REMAP_000 0x0550
#define VBIF_XINL_QOS_LVL_REMAP_000(vbif) (VBIF_XINL_QOS_RP_REMAP_000 + (vbif)->cap->qos_rp_remap_size)
static void dpu_hw_clear_errors(struct dpu_hw_vbif *vbif,
u32 *pnd_errors, u32 *src_errors)
{
struct dpu_hw_blk_reg_map *c;
u32 pnd, src;
if (!vbif)
return;
c = &vbif->hw;
pnd = DPU_REG_READ(c, VBIF_XIN_PND_ERR);
src = DPU_REG_READ(c, VBIF_XIN_SRC_ERR);
if (pnd_errors)
*pnd_errors = pnd;
if (src_errors)
*src_errors = src;
DPU_REG_WRITE(c, VBIF_XIN_CLR_ERR, pnd | src);
}
static void dpu_hw_set_mem_type(struct dpu_hw_vbif *vbif,
u32 xin_id, u32 value)
{
struct dpu_hw_blk_reg_map *c;
u32 reg_off;
u32 bit_off;
u32 reg_val;
/*
* Assume 4 bits per bit field, 8 fields per 32-bit register so
* 16 bit fields maximum across two registers
*/
if (!vbif || xin_id >= MAX_XIN_COUNT || xin_id >= 16)
return;
c = &vbif->hw;
if (xin_id >= 8) {
xin_id -= 8;
reg_off = VBIF_OUT_AXI_AMEMTYPE_CONF1;
} else {
reg_off = VBIF_OUT_AXI_AMEMTYPE_CONF0;
}
bit_off = (xin_id & 0x7) * 4;
reg_val = DPU_REG_READ(c, reg_off);
reg_val &= ~(0x7 << bit_off);
reg_val |= (value & 0x7) << bit_off;
DPU_REG_WRITE(c, reg_off, reg_val);
}
static void dpu_hw_set_limit_conf(struct dpu_hw_vbif *vbif,
u32 xin_id, bool rd, u32 limit)
{
struct dpu_hw_blk_reg_map *c = &vbif->hw;
u32 reg_val;
u32 reg_off;
u32 bit_off;
if (rd)
reg_off = VBIF_IN_RD_LIM_CONF0;
else
reg_off = VBIF_IN_WR_LIM_CONF0;
reg_off += (xin_id / 4) * 4;
bit_off = (xin_id % 4) * 8;
reg_val = DPU_REG_READ(c, reg_off);
reg_val &= ~(0xFF << bit_off);
reg_val |= (limit) << bit_off;
DPU_REG_WRITE(c, reg_off, reg_val);
}
static u32 dpu_hw_get_limit_conf(struct dpu_hw_vbif *vbif,
u32 xin_id, bool rd)
{
struct dpu_hw_blk_reg_map *c = &vbif->hw;
u32 reg_val;
u32 reg_off;
u32 bit_off;
u32 limit;
if (rd)
reg_off = VBIF_IN_RD_LIM_CONF0;
else
reg_off = VBIF_IN_WR_LIM_CONF0;
reg_off += (xin_id / 4) * 4;
bit_off = (xin_id % 4) * 8;
reg_val = DPU_REG_READ(c, reg_off);
limit = (reg_val >> bit_off) & 0xFF;
return limit;
}
static void dpu_hw_set_halt_ctrl(struct dpu_hw_vbif *vbif,
u32 xin_id, bool enable)
{
struct dpu_hw_blk_reg_map *c = &vbif->hw;
u32 reg_val;
reg_val = DPU_REG_READ(c, VBIF_XIN_HALT_CTRL0);
if (enable)
reg_val |= BIT(xin_id);
else
reg_val &= ~BIT(xin_id);
DPU_REG_WRITE(c, VBIF_XIN_HALT_CTRL0, reg_val);
}
static bool dpu_hw_get_halt_ctrl(struct dpu_hw_vbif *vbif,
u32 xin_id)
{
struct dpu_hw_blk_reg_map *c = &vbif->hw;
u32 reg_val;
reg_val = DPU_REG_READ(c, VBIF_XIN_HALT_CTRL1);
return (reg_val & BIT(xin_id)) ? true : false;
}
static void dpu_hw_set_qos_remap(struct dpu_hw_vbif *vbif,
u32 xin_id, u32 level, u32 remap_level)
{
struct dpu_hw_blk_reg_map *c;
u32 reg_lvl, reg_val, reg_val_lvl, mask, reg_high, reg_shift;
if (!vbif)
return;
c = &vbif->hw;
reg_lvl = VBIF_XINL_QOS_LVL_REMAP_000(vbif);
reg_high = ((xin_id & 0x8) >> 3) * 4 + (level * 8);
reg_shift = (xin_id & 0x7) * 4;
reg_val = DPU_REG_READ(c, VBIF_XINL_QOS_RP_REMAP_000 + reg_high);
reg_val_lvl = DPU_REG_READ(c, reg_lvl + reg_high);
mask = 0x7 << reg_shift;
reg_val &= ~mask;
reg_val |= (remap_level << reg_shift) & mask;
reg_val_lvl &= ~mask;
reg_val_lvl |= (remap_level << reg_shift) & mask;
DPU_REG_WRITE(c, VBIF_XINL_QOS_RP_REMAP_000 + reg_high, reg_val);
DPU_REG_WRITE(c, reg_lvl + reg_high, reg_val_lvl);
}
static void dpu_hw_set_write_gather_en(struct dpu_hw_vbif *vbif, u32 xin_id)
{
struct dpu_hw_blk_reg_map *c;
u32 reg_val;
if (!vbif || xin_id >= MAX_XIN_COUNT)
return;
c = &vbif->hw;
reg_val = DPU_REG_READ(c, VBIF_WRITE_GATHER_EN);
reg_val |= BIT(xin_id);
DPU_REG_WRITE(c, VBIF_WRITE_GATHER_EN, reg_val);
}
static void _setup_vbif_ops(struct dpu_hw_vbif_ops *ops,
unsigned long cap)
{
ops->set_limit_conf = dpu_hw_set_limit_conf;
ops->get_limit_conf = dpu_hw_get_limit_conf;
ops->set_halt_ctrl = dpu_hw_set_halt_ctrl;
ops->get_halt_ctrl = dpu_hw_get_halt_ctrl;
if (test_bit(DPU_VBIF_QOS_REMAP, &cap))
ops->set_qos_remap = dpu_hw_set_qos_remap;
ops->set_mem_type = dpu_hw_set_mem_type;
ops->clear_errors = dpu_hw_clear_errors;
ops->set_write_gather_en = dpu_hw_set_write_gather_en;
}
struct dpu_hw_vbif *dpu_hw_vbif_init(const struct dpu_vbif_cfg *cfg,
void __iomem *addr)
{
struct dpu_hw_vbif *c;
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
return ERR_PTR(-ENOMEM);
c->hw.blk_addr = addr + cfg->base;
c->hw.log_mask = DPU_DBG_MASK_VBIF;
/*
* Assign ops
*/
c->idx = cfg->id;
c->cap = cfg;
_setup_vbif_ops(&c->ops, c->cap->features);
/* no need to register sub-range in dpu dbg, dump entire vbif io base */
return c;
}
void dpu_hw_vbif_destroy(struct dpu_hw_vbif *vbif)
{
kfree(vbif);
}