Commit 1f2367a3 authored by james qian wang (Arm Technology China)'s avatar james qian wang (Arm Technology China) Committed by Liviu Dudau

drm/komeda: Add d71_enum_resources and d71_cleanup

D71 consists of a number of Register Blocks, every Block controls a
specific HW function, every block has a common block_header to represent
its type and pipeline information.

GCU (Global Control Unit) is the first Block which describe the global
information of D71 HW, Like number of block contained and the number of
pipeline supported.

So the d71_enum_resources parsed GCU and create pipeline according
the GCU configuration, and then iterate and detect the blocks that
indicated by the GCU and block_header.

And this change also added two struct d71_dev/d71_pipeline to extend
komeda_dev/komeda_pipeline to add some d71 only members.

v2:
- Return the specific errno not -1.
- Use DRM_DEBUG as default debug msg printer.
Signed-off-by: default avatarJames Qian Wang (Arm Technology China) <james.qian.wang@arm.com>
Signed-off-by: default avatarLiviu Dudau <liviu.dudau@arm.com>
parent 9e98c678
...@@ -7,10 +7,24 @@ ...@@ -7,10 +7,24 @@
#ifndef _MALIDP_UTILS_ #ifndef _MALIDP_UTILS_
#define _MALIDP_UTILS_ #define _MALIDP_UTILS_
#include <linux/delay.h>
#define has_bit(nr, mask) (BIT(nr) & (mask)) #define has_bit(nr, mask) (BIT(nr) & (mask))
#define has_bits(bits, mask) (((bits) & (mask)) == (bits)) #define has_bits(bits, mask) (((bits) & (mask)) == (bits))
#define dp_for_each_set_bit(bit, mask) \ #define dp_for_each_set_bit(bit, mask) \
for_each_set_bit((bit), ((unsigned long *)&(mask)), sizeof(mask) * 8) for_each_set_bit((bit), ((unsigned long *)&(mask)), sizeof(mask) * 8)
#define dp_wait_cond(__cond, __tries, __min_range, __max_range) \
({ \
int num_tries = __tries; \
while (!__cond && (num_tries > 0)) { \
usleep_range(__min_range, __max_range); \
if (__cond) \
break; \
num_tries--; \
} \
num_tries; \
})
#endif /* _MALIDP_UTILS_ */ #endif /* _MALIDP_UTILS_ */
...@@ -16,6 +16,7 @@ komeda-y := \ ...@@ -16,6 +16,7 @@ komeda-y := \
komeda_private_obj.o komeda_private_obj.o
komeda-y += \ komeda-y += \
d71/d71_dev.o d71/d71_dev.o \
d71/d71_component.o
obj-$(CONFIG_DRM_KOMEDA) += komeda.o obj-$(CONFIG_DRM_KOMEDA) += komeda.o
// SPDX-License-Identifier: GPL-2.0
/*
* (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
* Author: James.Qian.Wang <james.qian.wang@arm.com>
*
*/
#include <drm/drm_print.h>
#include "d71_dev.h"
#include "komeda_kms.h"
#include "malidp_io.h"
static int d71_layer_init(struct d71_dev *d71,
struct block_header *blk, u32 __iomem *reg)
{
DRM_DEBUG("Detect D71_Layer.\n");
return 0;
}
static int d71_wb_layer_init(struct d71_dev *d71,
struct block_header *blk, u32 __iomem *reg)
{
DRM_DEBUG("Detect D71_Wb_Layer.\n");
return 0;
}
static int d71_compiz_init(struct d71_dev *d71,
struct block_header *blk, u32 __iomem *reg)
{
DRM_DEBUG("Detect D71_compiz.\n");
return 0;
}
static int d71_improc_init(struct d71_dev *d71,
struct block_header *blk, u32 __iomem *reg)
{
DRM_DEBUG("Detect D71_improc.\n");
return 0;
}
static int d71_timing_ctrlr_init(struct d71_dev *d71,
struct block_header *blk, u32 __iomem *reg)
{
DRM_DEBUG("Detect D71_timing_ctrlr.\n");
return 0;
}
int d71_probe_block(struct d71_dev *d71,
struct block_header *blk, u32 __iomem *reg)
{
struct d71_pipeline *pipe;
int blk_id = BLOCK_INFO_BLK_ID(blk->block_info);
int err = 0;
switch (BLOCK_INFO_BLK_TYPE(blk->block_info)) {
case D71_BLK_TYPE_GCU:
break;
case D71_BLK_TYPE_LPU:
pipe = d71->pipes[blk_id];
pipe->lpu_addr = reg;
break;
case D71_BLK_TYPE_LPU_LAYER:
err = d71_layer_init(d71, blk, reg);
break;
case D71_BLK_TYPE_LPU_WB_LAYER:
err = d71_wb_layer_init(d71, blk, reg);
break;
case D71_BLK_TYPE_CU:
pipe = d71->pipes[blk_id];
pipe->cu_addr = reg;
err = d71_compiz_init(d71, blk, reg);
break;
case D71_BLK_TYPE_CU_SPLITTER:
case D71_BLK_TYPE_CU_SCALER:
case D71_BLK_TYPE_CU_MERGER:
break;
case D71_BLK_TYPE_DOU:
pipe = d71->pipes[blk_id];
pipe->dou_addr = reg;
break;
case D71_BLK_TYPE_DOU_IPS:
err = d71_improc_init(d71, blk, reg);
break;
case D71_BLK_TYPE_DOU_FT_COEFF:
pipe = d71->pipes[blk_id];
pipe->dou_ft_coeff_addr = reg;
break;
case D71_BLK_TYPE_DOU_BS:
err = d71_timing_ctrlr_init(d71, blk, reg);
break;
case D71_BLK_TYPE_GLB_LT_COEFF:
break;
case D71_BLK_TYPE_GLB_SCL_COEFF:
d71->glb_scl_coeff_addr[blk_id] = reg;
break;
default:
DRM_ERROR("Unknown block (block_info: 0x%x) is found\n",
blk->block_info);
err = -EINVAL;
break;
}
return err;
}
...@@ -4,13 +4,141 @@ ...@@ -4,13 +4,141 @@
* Author: James.Qian.Wang <james.qian.wang@arm.com> * Author: James.Qian.Wang <james.qian.wang@arm.com>
* *
*/ */
#include <drm/drm_print.h>
#include "d71_dev.h"
#include "malidp_io.h" #include "malidp_io.h"
#include "komeda_dev.h"
static int d71_reset(struct d71_dev *d71)
{
u32 __iomem *gcu = d71->gcu_addr;
int ret;
malidp_write32_mask(gcu, BLK_CONTROL,
GCU_CONTROL_SRST, GCU_CONTROL_SRST);
ret = dp_wait_cond(!(malidp_read32(gcu, BLK_CONTROL) & GCU_CONTROL_SRST),
100, 1000, 10000);
return ret > 0 ? 0 : -ETIMEDOUT;
}
void d71_read_block_header(u32 __iomem *reg, struct block_header *blk)
{
int i;
blk->block_info = malidp_read32(reg, BLK_BLOCK_INFO);
if (BLOCK_INFO_BLK_TYPE(blk->block_info) == D71_BLK_TYPE_RESERVED)
return;
blk->pipeline_info = malidp_read32(reg, BLK_PIPELINE_INFO);
/* get valid input and output ids */
for (i = 0; i < PIPELINE_INFO_N_VALID_INPUTS(blk->pipeline_info); i++)
blk->input_ids[i] = malidp_read32(reg + i, BLK_VALID_INPUT_ID0);
for (i = 0; i < PIPELINE_INFO_N_OUTPUTS(blk->pipeline_info); i++)
blk->output_ids[i] = malidp_read32(reg + i, BLK_OUTPUT_ID0);
}
static void d71_cleanup(struct komeda_dev *mdev)
{
struct d71_dev *d71 = mdev->chip_data;
if (!d71)
return;
devm_kfree(mdev->dev, d71);
mdev->chip_data = NULL;
}
static int d71_enum_resources(struct komeda_dev *mdev) static int d71_enum_resources(struct komeda_dev *mdev)
{ {
/* TODO add enum resources */ struct d71_dev *d71;
return -1; struct komeda_pipeline *pipe;
struct block_header blk;
u32 __iomem *blk_base;
u32 i, value, offset;
int err;
d71 = devm_kzalloc(mdev->dev, sizeof(*d71), GFP_KERNEL);
if (!d71)
return -ENOMEM;
mdev->chip_data = d71;
d71->mdev = mdev;
d71->gcu_addr = mdev->reg_base;
d71->periph_addr = mdev->reg_base + (D71_BLOCK_OFFSET_PERIPH >> 2);
err = d71_reset(d71);
if (err) {
DRM_ERROR("Fail to reset d71 device.\n");
goto err_cleanup;
}
/* probe GCU */
value = malidp_read32(d71->gcu_addr, GLB_CORE_INFO);
d71->num_blocks = value & 0xFF;
d71->num_pipelines = (value >> 8) & 0x7;
if (d71->num_pipelines > D71_MAX_PIPELINE) {
DRM_ERROR("d71 supports %d pipelines, but got: %d.\n",
D71_MAX_PIPELINE, d71->num_pipelines);
err = -EINVAL;
goto err_cleanup;
}
/* probe PERIPH */
value = malidp_read32(d71->periph_addr, BLK_BLOCK_INFO);
if (BLOCK_INFO_BLK_TYPE(value) != D71_BLK_TYPE_PERIPH) {
DRM_ERROR("access blk periph but got blk: %d.\n",
BLOCK_INFO_BLK_TYPE(value));
err = -EINVAL;
goto err_cleanup;
}
value = malidp_read32(d71->periph_addr, PERIPH_CONFIGURATION_ID);
d71->max_line_size = value & PERIPH_MAX_LINE_SIZE ? 4096 : 2048;
d71->max_vsize = 4096;
d71->num_rich_layers = value & PERIPH_NUM_RICH_LAYERS ? 2 : 1;
d71->supports_dual_link = value & PERIPH_SPLIT_EN ? true : false;
d71->integrates_tbu = value & PERIPH_TBU_EN ? true : false;
for (i = 0; i < d71->num_pipelines; i++) {
pipe = komeda_pipeline_add(mdev, sizeof(struct d71_pipeline),
NULL);
if (IS_ERR(pipe)) {
err = PTR_ERR(pipe);
goto err_cleanup;
}
d71->pipes[i] = to_d71_pipeline(pipe);
}
/* loop the register blks and probe */
i = 2; /* exclude GCU and PERIPH */
offset = D71_BLOCK_SIZE; /* skip GCU */
while (i < d71->num_blocks) {
blk_base = mdev->reg_base + (offset >> 2);
d71_read_block_header(blk_base, &blk);
if (BLOCK_INFO_BLK_TYPE(blk.block_info) != D71_BLK_TYPE_RESERVED) {
err = d71_probe_block(d71, &blk, blk_base);
if (err)
goto err_cleanup;
i++;
}
offset += D71_BLOCK_SIZE;
}
DRM_DEBUG("total %d (out of %d) blocks are found.\n",
i, d71->num_blocks);
return 0;
err_cleanup:
d71_cleanup(mdev);
return err;
} }
#define __HW_ID(__group, __format) \ #define __HW_ID(__group, __format) \
...@@ -93,13 +221,9 @@ static void d71_init_fmt_tbl(struct komeda_dev *mdev) ...@@ -93,13 +221,9 @@ static void d71_init_fmt_tbl(struct komeda_dev *mdev)
static struct komeda_dev_funcs d71_chip_funcs = { static struct komeda_dev_funcs d71_chip_funcs = {
.init_format_table = d71_init_fmt_tbl, .init_format_table = d71_init_fmt_tbl,
.enum_resources = d71_enum_resources, .enum_resources = d71_enum_resources,
.cleanup = NULL, .cleanup = d71_cleanup,
}; };
#define GLB_ARCH_ID 0x000
#define GLB_CORE_ID 0x004
#define GLB_CORE_INFO 0x008
struct komeda_dev_funcs * struct komeda_dev_funcs *
d71_identify(u32 __iomem *reg_base, struct komeda_chip_info *chip) d71_identify(u32 __iomem *reg_base, struct komeda_chip_info *chip)
{ {
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
* Author: James.Qian.Wang <james.qian.wang@arm.com>
*
*/
#ifndef _D71_DEV_H_
#define _D71_DEV_H_
#include "komeda_dev.h"
#include "komeda_pipeline.h"
#include "d71_regs.h"
struct d71_pipeline {
struct komeda_pipeline base;
/* d71 private pipeline blocks */
u32 __iomem *lpu_addr;
u32 __iomem *cu_addr;
u32 __iomem *dou_addr;
u32 __iomem *dou_ft_coeff_addr; /* forward transform coeffs table */
};
struct d71_dev {
struct komeda_dev *mdev;
int num_blocks;
int num_pipelines;
int num_rich_layers;
u32 max_line_size;
u32 max_vsize;
u32 supports_dual_link : 1;
u32 integrates_tbu : 1;
/* global register blocks */
u32 __iomem *gcu_addr;
/* scaling coeffs table */
u32 __iomem *glb_scl_coeff_addr[D71_MAX_GLB_SCL_COEFF];
u32 __iomem *periph_addr;
struct d71_pipeline *pipes[D71_MAX_PIPELINE];
};
#define to_d71_pipeline(x) container_of(x, struct d71_pipeline, base)
int d71_probe_block(struct d71_dev *d71,
struct block_header *blk, u32 __iomem *reg);
void d71_read_block_header(u32 __iomem *reg, struct block_header *blk);
#endif /* !_D71_DEV_H_ */
This diff is collapsed.
...@@ -19,17 +19,17 @@ komeda_pipeline_add(struct komeda_dev *mdev, size_t size, ...@@ -19,17 +19,17 @@ komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
if (mdev->n_pipelines + 1 > KOMEDA_MAX_PIPELINES) { if (mdev->n_pipelines + 1 > KOMEDA_MAX_PIPELINES) {
DRM_ERROR("Exceed max support %d pipelines.\n", DRM_ERROR("Exceed max support %d pipelines.\n",
KOMEDA_MAX_PIPELINES); KOMEDA_MAX_PIPELINES);
return NULL; return ERR_PTR(-ENOSPC);
} }
if (size < sizeof(*pipe)) { if (size < sizeof(*pipe)) {
DRM_ERROR("Request pipeline size too small.\n"); DRM_ERROR("Request pipeline size too small.\n");
return NULL; return ERR_PTR(-EINVAL);
} }
pipe = devm_kzalloc(mdev->dev, size, GFP_KERNEL); pipe = devm_kzalloc(mdev->dev, size, GFP_KERNEL);
if (!pipe) if (!pipe)
return NULL; return ERR_PTR(-ENOMEM);
pipe->mdev = mdev; pipe->mdev = mdev;
pipe->id = mdev->n_pipelines; pipe->id = mdev->n_pipelines;
...@@ -142,32 +142,32 @@ komeda_component_add(struct komeda_pipeline *pipe, ...@@ -142,32 +142,32 @@ komeda_component_add(struct komeda_pipeline *pipe,
if (max_active_inputs > KOMEDA_COMPONENT_N_INPUTS) { if (max_active_inputs > KOMEDA_COMPONENT_N_INPUTS) {
WARN(1, "please large KOMEDA_COMPONENT_N_INPUTS to %d.\n", WARN(1, "please large KOMEDA_COMPONENT_N_INPUTS to %d.\n",
max_active_inputs); max_active_inputs);
return NULL; return ERR_PTR(-ENOSPC);
} }
pos = komeda_pipeline_get_component_pos(pipe, id); pos = komeda_pipeline_get_component_pos(pipe, id);
if (!pos || (*pos)) if (!pos || (*pos))
return NULL; return ERR_PTR(-EINVAL);
if (has_bit(id, KOMEDA_PIPELINE_LAYERS)) { if (has_bit(id, KOMEDA_PIPELINE_LAYERS)) {
idx = id - KOMEDA_COMPONENT_LAYER0; idx = id - KOMEDA_COMPONENT_LAYER0;
num = &pipe->n_layers; num = &pipe->n_layers;
if (idx != pipe->n_layers) { if (idx != pipe->n_layers) {
DRM_ERROR("please add Layer by id sequence.\n"); DRM_ERROR("please add Layer by id sequence.\n");
return NULL; return ERR_PTR(-EINVAL);
} }
} else if (has_bit(id, KOMEDA_PIPELINE_SCALERS)) { } else if (has_bit(id, KOMEDA_PIPELINE_SCALERS)) {
idx = id - KOMEDA_COMPONENT_SCALER0; idx = id - KOMEDA_COMPONENT_SCALER0;
num = &pipe->n_scalers; num = &pipe->n_scalers;
if (idx != pipe->n_scalers) { if (idx != pipe->n_scalers) {
DRM_ERROR("please add Scaler by id sequence.\n"); DRM_ERROR("please add Scaler by id sequence.\n");
return NULL; return ERR_PTR(-EINVAL);
} }
} }
c = devm_kzalloc(pipe->mdev->dev, comp_sz, GFP_KERNEL); c = devm_kzalloc(pipe->mdev->dev, comp_sz, GFP_KERNEL);
if (!c) if (!c)
return NULL; return ERR_PTR(-ENOMEM);
c->id = id; c->id = id;
c->hw_id = hw_id; c->hw_id = hw_id;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment