Add 'qcom/opensource/mm-sys-kernel/' from commit '88eb9646a400c3c70d3614c3912af530dd332060'

git-subtree-dir: qcom/opensource/mm-sys-kernel
git-subtree-mainline: 99d06628db
git-subtree-split: 88eb9646a4
Change-Id:
repo: https://git.codelinaro.org/clo/la/platform/vendor/opensource/mm-sys-kernel
tag: LA.VENDOR.14.3.0.r1-17300-lanai.QSSI15.0
This commit is contained in:
David Wronek 2024-10-06 16:45:14 +02:00
commit 46e9caf0d0
15 changed files with 4879 additions and 0 deletions

View File

@ -0,0 +1,38 @@
headers_src = [
"include/uapi/*.h",
"include/kernel/*.h",
]
ubwcp_headers_out = [
"ubwcp_ioctl.h",
"ubwcp.h",
]
ubwcp_kernel_headers_verbose = "--verbose "
genrule {
name: "qti_generate_ubwcp_kernel_headers",
tools: [
"headers_install.sh",
"unifdef"
],
tool_files: [
"ubwcp_kernel_headers.py",
],
srcs: headers_src,
cmd: "python3 $(location ubwcp_kernel_headers.py) " +
ubwcp_kernel_headers_verbose +
"--header_arch arm64 " +
"--gen_dir $(genDir) " +
"--ubwcp_include $(locations include/uapi/*.h) $(locations include/kernel/*.h) " +
"--unifdef $(location unifdef) " +
"--headers_install $(location headers_install.sh)",
out: ubwcp_headers_out,
}
cc_library_headers {
name: "qti_ubwcp_kernel_headers",
generated_headers: ["qti_generate_ubwcp_kernel_headers"],
export_generated_headers: ["qti_generate_ubwcp_kernel_headers"],
vendor: true,
recovery_available: true
}

View File

@ -0,0 +1,15 @@
# SPDX-License-Identifier: GPL-2.0-only
ifneq ($(TARGET_KERNEL_DLKM_DISABLE), true)
LOCAL_PATH := $(call my-dir)
LOCAL_MODULE_DDK_BUILD := true
include $(CLEAR_VARS)
# For incremental compilation
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*)
LOCAL_EXPORT_KO_INCLUDE_DIRS := $(LOCAL_PATH)/include/uapi
LOCAL_EXPORT_KO_INCLUDE_DIRS += $(LOCAL_PATH)/include/kernel
LOCAL_MODULE := ubwcp.ko
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/Build_external_kernelmodule.mk
endif

View File

@ -0,0 +1,4 @@
load(":define_modules.bzl", "define_modules")
define_modules("pineapple", "consolidate")
define_modules("pineapple", "gki")

View File

@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
ubwcp-objs := ubwcp_main.o ubwcp_hw.o
obj-m += ubwcp.o

View File

@ -0,0 +1,19 @@
# SPDX-License-Identifier: GPL-2.0-only
#ifeq ($(KP_MODULE_ROOT),)
#KP_MODULE_ROOT=$(KERNEL_SRC)/$(M)
#endif
#KBUILD_OPTIONS+=KBUILD_DTC_INCLUDE=$(KP_MODULE_ROOT)
# Kbuild assumes devicetree source lives in arch/arm64/boot/dts, but perhaps it
# lives in some other directory in your project. Specify it with KBUILD_EXTMOD_DTS
# KBUILD_OPTIONS+=KBUILD_EXTMOD_DTS=camera
all: modules # dtbs
clean:
$(MAKE) -C $(KERNEL_SRC) M=$(M) clean
%:
$(MAKE) -C $(KERNEL_SRC) M=$(M) $@ $(KBUILD_OPTIONS)

View File

@ -0,0 +1,32 @@
load("//build/kernel/kleaf:kernel.bzl", "ddk_module")
load("//build/bazel_common_rules/dist:dist.bzl", "copy_to_dist_dir")
def define_modules(target, variant):
tv = "{}_{}".format(target, variant)
ddk_module(
name = "{}_ubwcp".format(tv),
out = "ubwcp.ko",
srcs = [
"ubwcp_main.c",
"ubwcp_hw.c",
"ubwcp_hw.h",
"ubwcp_trace.h",
],
hdrs=["include/uapi/ubwcp_ioctl.h", "include/kernel/ubwcp.h"],
deps = ["//msm-kernel:all_headers"],
includes = ["include", "include/kernel"],
kernel_build = "//msm-kernel:{}".format(tv),
visibility = ["//visibility:public"]
)
copy_to_dist_dir(
name = "{}_ubwcp_dist".format(tv),
data = [":{}_ubwcp".format(tv)],
dist_dir = "out/target/product/{}/dlkm/lib/modules/".format(target),
flat = True,
wipe_dist_dir = False,
allow_duplicate_filenames = False,
mode_overrides = {"**/*": "644"},
)

View File

@ -0,0 +1,141 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef __UBWCP_H_
#define __UBWCP_H_
#include <linux/types.h>
#include <linux/dma-buf.h>
#include "../uapi/ubwcp_ioctl.h"
typedef int (*configure_mmap)(struct dma_buf *dmabuf, bool linear, phys_addr_t ula_pa_addr,
size_t ula_pa_size);
/**
* Get UBWCP hardware version
*
* @param ver : ptr to ver struct where hw version will be
* copied
*
* @return int : 0 on success, otherwise error code
*/
int ubwcp_get_hw_version(struct ubwcp_ioctl_hw_version *ver);
/**
* Configures ubwcp buffer with the provided buffer image
* attributes. This call must be done at least once before
* ubwcp_lock(). Attributes can be configured multiple times,
* but only during unlocked state.
*
* Upon error, buffer will be in undefined state.
* There is no guarantee that previously set attributes will be retained.
* Caller could retry set attributes, but must not reuse buffer
* until a successful set attribute call is done.
*
* @param dmabuf : ptr to the dma buf
* @param attr : buffer attributes to set
*
* @return int : 0 on success, otherwise error code
*/
int ubwcp_set_buf_attrs(struct dma_buf *dmabuf, struct ubwcp_buffer_attrs *attr);
/**
* Get the currently configured attributes for the buffer
*
* @param dmabuf : ptr to the dma buf
* @param attr : pointer to location where image attributes
* for this buffer will be copied to.
*
* @return int : 0 on success, otherwise error code
*/
int ubwcp_get_buf_attrs(struct dma_buf *dmabuf, struct ubwcp_buffer_attrs *attr);
/**
* Set permanent range translation for the buffer. This reserves
* ubwcp address translation resources for the buffer until free
* is called. This may speed up lock()/unlock() calls as they
* don't need to configure address translations for the buffer.
*
* @param dmabuf : ptr to the dma buf
* @param enable : true == enable, false == disable
*
* @return int : 0 on success, otherwise error code
*/
int ubwcp_set_perm_range_translation(struct dma_buf *dmabuf, bool enable);
enum ubwcp_error {
UBWCP_ENCODE_ERROR = 0,
UBWCP_DECODE_ERROR,
UBWCP_RANGE_TRANSLATION_ERROR,
UBWCP_SMMU_FAULT,
UBWCP_UNKNOWN_ERROR,
};
enum iommu_cb_id {
UBWCP_DESC_CB_ID = 0,
UBWCP_BUF_CB_ID,
UBWCP_UNKNOWN_CB_ID,
};
struct ubwcp_enc_err_info {
struct dma_buf *dmabuf;
phys_addr_t ula_pa;
};
struct ubwcp_dec_err_info {
struct dma_buf *dmabuf;
phys_addr_t ula_pa;
};
struct ubwcp_translation_err_info {
struct dma_buf *dmabuf;
phys_addr_t ula_pa;
bool read;
};
struct ubwcp_smmu_fault_err_info {
struct dma_buf *dmabuf;
unsigned long iova;
enum iommu_cb_id iommu_dev_id;
int iommu_fault_flags;
};
struct ubwcp_err_info {
enum ubwcp_error err_code;
union {
struct ubwcp_enc_err_info enc_err;
struct ubwcp_dec_err_info dec_err;
struct ubwcp_translation_err_info translation_err;
struct ubwcp_smmu_fault_err_info smmu_err;
};
};
typedef void (*ubwcp_error_handler_t)(struct ubwcp_err_info *err, void *data);
/*
* Register an error handler
*
* @param client_id : not currently supported (pass in -1)
* @param handler : the error handler function which will be called when an
* error occurs
* @param data : data pointer provided with the error handler function
*
* @return int : 0 on success, otherwise error code
*/
int ubwcp_register_error_handler(u32 client_id, ubwcp_error_handler_t handler,
void *data);
/*
* Unregister an error handler
*
* @param client_id : client id of handler to unregister (pass in -1)
*
* @return int : 0 on success, otherwise error code
*/
int ubwcp_unregister_error_handler(u32 client_id);
#endif /* __UBWCP_H_ */

View File

@ -0,0 +1,151 @@
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef __UBWCP_IOCTL_H_
#define __UBWCP_IOCTL_H_
#include <linux/ioctl.h>
#include <linux/types.h>
#define UBWCP_IOCTL_SET_BUF_ATTR _IOW('U', 1, struct ubwcp_ioctl_buffer_attrs)
#define UBWCP_IOCTL_GET_HW_VER _IOR('U', 2, struct ubwcp_ioctl_hw_version)
#define UBWCP_IOCTL_GET_STRIDE_ALIGN _IOWR('U', 3, struct ubwcp_ioctl_stride_align)
#define UBWCP_IOCTL_VALIDATE_STRIDE _IOWR('U', 4, struct ubwcp_ioctl_validate_stride)
enum ubwcp_image_format {
UBWCP_LINEAR = 0,
UBWCP_RGBA8888,
UBWCP_NV12,
UBWCP_NV12_Y,
UBWCP_NV12_UV,
UBWCP_NV124R,
UBWCP_NV124R_Y,
UBWCP_NV124R_UV,
UBWCP_TP10,
UBWCP_TP10_Y,
UBWCP_TP10_UV,
UBWCP_P010,
UBWCP_P010_Y,
UBWCP_P010_UV,
UBWCP_P016,
UBWCP_P016_Y,
UBWCP_P016_UV,
};
enum ubwcp_compression_type {
UBWCP_COMPRESSION_LOSSLESS = 0,
};
enum ubwcp_subsample {
UBWCP_SUBSAMPLE_4_2_0 = 0,
};
#define UBWCP_SUBSYSTEM_TARGET_CPU (1 << 0)
/**
* @image_format: image format
* @major_ubwc_ver: set to 0. This is not HW version.
* @minor_ubwc_ver: set to 0. This is not HW version.
* @compression_type: only lossless is supported.
* @lossy_params: set to 0
* @width: image width (pixels)
* @height: image height (pixels)
* @stride: image stride (bytes)
* @scanlines: number of scanlines
* @planar_padding: padding between Y and UV planes (bytes)
* @subsample: only 4:2:0 is supported
* @sub_system_target: only CPU is supported
* @y_offset: set to 0
* @batch_size: set to 1
*
* All pad[x] and unused[x] fields must be set to 0
*/
struct ubwcp_buffer_attrs {
__u16 image_format; /* enum ubwcp_image_format */
__u16 major_ubwc_ver; /* per-buffer version: must be set to 0 */
__u16 minor_ubwc_ver; /* per-buffer version: must be set to 0 */
__u16 compression_type; /* enum ubwcp_compression_type */
__u64 lossy_params; /* must be set to 0 */
__u32 width;
__u32 height;
__u32 stride;
__u32 scanlines;
__u32 planar_padding;
__u32 subsample; /* enum enum ubwcp_subsample */
__u32 sub_system_target;/* bit mask: UBWCP_SUBSYSTEM_TARGET_XXX */
__u32 y_offset; /* must be set to 0 */
__u32 batch_size; /* only size supported: 1 */
__u32 unused1;
__u32 unused2;
__u32 unused3;
__u32 unused4;
__u32 unused5;
__u32 unused6;
__u32 unused7;
__u32 unused8;
__u32 unused9;
};
/**
* @fd: dma_buf file descriptor for the buffer whose
* attributes are specified
* @attr: ubwcp buffer attributes
*/
struct ubwcp_ioctl_buffer_attrs {
__u32 fd;
__u32 pad;
struct ubwcp_buffer_attrs attr;
};
/**
* ubwcp hardware version
* @major: major version
* @minor: minor version
*/
struct ubwcp_ioctl_hw_version {
__u32 major;
__u32 minor;
};
/**
* Stride alignment for given format
* @image_format: image format
* @stride_align: stride alignment
* @unused: must be set to 0
* IOCTL will fail for linear image format
*/
struct ubwcp_ioctl_stride_align {
__u16 image_format;
__u16 stride_align;
__u32 unused;
};
/**
* validate stride
* @image_format: image format
* @width: image width in pixels
* @stride: image stride in bytes
* @valid: returns 0 (not valid), 1 (valid)
* @unusedX: must be set to 0
* IOCTL will fail for linear image format
*/
struct ubwcp_ioctl_validate_stride {
__u16 image_format;
__u32 width;
__u32 stride;
__u16 valid;
__u16 unused1;
__u16 unused2;
};
#endif /* __UBWCP_IOCTL_H_ */

View File

@ -0,0 +1,378 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#define pr_fmt(fmt) "%s: hw: %s(): " fmt, KBUILD_MODNAME, __func__
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/dma-buf.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/qcom_scm.h>
#include <linux/delay.h>
#include <asm/barrier.h>
#include "ubwcp_hw.h"
static bool ubwcp_hw_trace_en;
//#define DBG(fmt, args...)
#define DBG(fmt, args...) \
do { \
if (unlikely(ubwcp_hw_trace_en)) \
pr_err(fmt "\n", ##args); \
} while (0)
#define ERR(fmt, args...) pr_err_ratelimited(": %d: ~~~ERROR~~~: " fmt "\n", __LINE__, ##args)
MODULE_LICENSE("GPL");
#define PAGE_ADDR_4K(_x) ((_x) >> 12)
/* register offsets from base */
#define RANGE_LOWER 0x0000
#define RANGE_HIGHER 0x0800
#define DESC_BASE 0x1000
#define DESC_BASE_STRIDE 0x1004
#define CONFIG 0x1008
#define ENCODER_CONFIG 0x100C
#define ENCODER_STATUS 0x1010
#define DECODER_CONFIG 0x1014
#define DECODER_STATUS 0x1018
#define RANGE_CHECK_FAIL 0x101C
#define RANGE_CHECK_CONTROL 0x1020
#define RANGE_CHECK_STATUS 0x1060
#define FLUSH_CONTROL 0x10A0
#define FLUSH_STATUS 0x10A4
#define INTERRUPT_SET 0x10B0
#define INTERRUPT_STATUS_READ 0x10C0
#define INTERRUPT_STATUS_WRITE 0x10C4
#define INTERRUPT_STATUS_ENCODE 0x10C8
#define INTERRUPT_STATUS_DECODE 0x10CC
#define INTERRUPT_READ_SRC_LOW 0x1100
#define INTERRUPT_READ_SRC_HIGH 0x1104
#define INTERRUPT_WRITE_SRC_LOW 0x1108
#define INTERRUPT_WRITE_SRC_HIGH 0x110C
#define INTERRUPT_ENCODE_SRC_LOW 0x1110
#define INTERRUPT_ENCODE_SRC_HIGH 0x1114
#define INTERRUPT_DECODE_SRC_LOW 0x1118
#define INTERRUPT_DECODE_SRC_HIGH 0x111C
#define INTERRUPT_CLEAR 0x1120
#define QNS4_PARAMS 0x1124
#define OVERRIDE 0x112C
#define VERSION_CONTROL 0x1130
#define SPARE 0x1188
#define UBWCP_DEBUG_REG_RW
/* read/write register */
#if defined(UBWCP_DEBUG_REG_RW)
#define UBWCP_REG_READ(_base, _offset) \
({u32 _reg; \
_reg = ioread32(_base + _offset); \
DBG("READ : 0x%x -> 0x%08x", _offset, _reg); \
_reg; })
#define UBWCP_REG_WRITE(_base, _offset, _value) \
{ \
DBG("WRITE: 0x%x <- 0x%08x", _offset, _value); \
iowrite32(_value, _base + _offset); \
}
#else
#define UBWCP_REG_READ(_base, _offset) ioread32(_base + _offset)
#define UBWCP_REG_WRITE(_base, _offset, _value) iowrite32(_value, _base + _offset)
#endif
#define UBWCP_REG_READ_NO_DBG(_base, _offset) ioread32(_base + _offset)
#define UBWCP_REG_WRITE_NO_DBG(_base, _offset, _value) iowrite32(_value, _base + _offset)
void ubwcp_hw_interrupt_enable(void __iomem *base, u16 interrupt, bool enable)
{
u32 value;
value = UBWCP_REG_READ(base, INTERRUPT_SET);
if (enable)
value = value | (1 << interrupt);
else
value = value & ~(1 << interrupt);
UBWCP_REG_WRITE(base, INTERRUPT_SET, value);
}
EXPORT_SYMBOL(ubwcp_hw_interrupt_enable);
void ubwcp_hw_interrupt_clear(void __iomem *base, u16 interrupt)
{
UBWCP_REG_WRITE_NO_DBG(base, INTERRUPT_CLEAR, (1 << interrupt));
}
EXPORT_SYMBOL(ubwcp_hw_interrupt_clear);
int ubwcp_hw_interrupt_status(void __iomem *base, u16 interrupt)
{
int value = -1;
switch (interrupt) {
case INTERRUPT_READ_ERROR:
value = UBWCP_REG_READ(base, INTERRUPT_STATUS_READ) & 0x1;
break;
case INTERRUPT_WRITE_ERROR:
value = UBWCP_REG_READ(base, INTERRUPT_STATUS_WRITE) & 0x1;
break;
case INTERRUPT_DECODE_ERROR:
value = UBWCP_REG_READ(base, INTERRUPT_STATUS_DECODE) & 0x1;
break;
case INTERRUPT_ENCODE_ERROR:
value = UBWCP_REG_READ(base, INTERRUPT_STATUS_ENCODE) & 0x1;
break;
default:
/* TBD: fatal error? */
break;
}
return value;
}
/* returns the address which caused this interrupt */
u64 ubwcp_hw_interrupt_src_address(void __iomem *base, u16 interrupt)
{
u32 addr_low;
u32 addr_high;
switch (interrupt) {
case INTERRUPT_READ_ERROR:
addr_low = UBWCP_REG_READ_NO_DBG(base, INTERRUPT_READ_SRC_LOW);
addr_high = UBWCP_REG_READ_NO_DBG(base, INTERRUPT_READ_SRC_HIGH) & 0xF;
break;
case INTERRUPT_WRITE_ERROR:
addr_low = UBWCP_REG_READ_NO_DBG(base, INTERRUPT_WRITE_SRC_LOW);
addr_high = UBWCP_REG_READ_NO_DBG(base, INTERRUPT_WRITE_SRC_HIGH) & 0xF;
break;
case INTERRUPT_DECODE_ERROR:
addr_low = UBWCP_REG_READ_NO_DBG(base, INTERRUPT_DECODE_SRC_LOW);
addr_high = UBWCP_REG_READ_NO_DBG(base, INTERRUPT_DECODE_SRC_HIGH) & 0xF;
break;
case INTERRUPT_ENCODE_ERROR:
addr_low = UBWCP_REG_READ_NO_DBG(base, INTERRUPT_ENCODE_SRC_LOW);
addr_high = UBWCP_REG_READ_NO_DBG(base, INTERRUPT_ENCODE_SRC_HIGH) & 0xF;
break;
default:
/* TBD: fatal error? */
addr_low = 0x0;
addr_high = 0x0;
break;
}
return ((addr_high << 31) | addr_low);
}
EXPORT_SYMBOL(ubwcp_hw_interrupt_src_address);
/*
* @index: index of buffer (from 0 to 255)
* @pa : ULA PA start address
* @size : size of ULA PA address range
*/
void ubwcp_hw_set_range_check(void __iomem *base, u16 index, phys_addr_t pa, size_t size)
{
u32 lower;
u32 higher;
lower = PAGE_ADDR_4K(pa);
higher = PAGE_ADDR_4K(pa + size);
UBWCP_REG_WRITE(base, RANGE_LOWER + index*4, lower);
UBWCP_REG_WRITE(base, RANGE_HIGHER + index*4, higher);
}
EXPORT_SYMBOL(ubwcp_hw_set_range_check);
/* enable range ck:
* identify control register for this index.
* 32bits in each ctrl reg. upto 8 regs for 256 indexes
*/
void ubwcp_hw_enable_range_check(void __iomem *base, u16 index)
{
u32 val;
u16 ctrl_reg = index >> 5;
val = UBWCP_REG_READ(base, RANGE_CHECK_CONTROL + ctrl_reg*4);
val |= (1 << (index & 0x1F));
UBWCP_REG_WRITE(base, RANGE_CHECK_CONTROL + ctrl_reg*4, val);
}
EXPORT_SYMBOL(ubwcp_hw_enable_range_check);
int ubwcp_hw_flush(void __iomem *base)
{
u32 flush_complete = 0;
u32 count_no_delay = 1000;
u32 count_delay = 2000;
u32 count = count_no_delay + count_delay;
UBWCP_REG_WRITE(base, FLUSH_CONTROL, 0x3);
do {
if (count < count_delay)
udelay(1);
flush_complete = UBWCP_REG_READ(base, FLUSH_STATUS) & 0x1;
if (flush_complete) {
UBWCP_REG_WRITE(base, FLUSH_CONTROL, 0x0);
return 0;
}
} while (count--);
ERR("~~~~~ FLUSH FAILED ~~~~~");
return -1;
}
EXPORT_SYMBOL(ubwcp_hw_flush);
/* Disable range check with flush */
int ubwcp_hw_disable_range_check_with_flush(void __iomem *base, u16 index)
{
u32 val;
u16 ctrl_reg = index >> 5;
/*
* It is not clear that the isb() calls in this sequence are
* requried, we may be able to remove them.
*/
//ensure all CMOs have completed
isb();
//disable range ck
val = UBWCP_REG_READ(base, RANGE_CHECK_CONTROL + ctrl_reg*4);
val &= ~(1 << (index & 0x1F));
UBWCP_REG_WRITE(base, RANGE_CHECK_CONTROL + ctrl_reg*4, val);
isb();
//assert flush
UBWCP_REG_WRITE(base, FLUSH_CONTROL, 0x3);
return ubwcp_hw_flush(base);
}
EXPORT_SYMBOL(ubwcp_hw_disable_range_check_with_flush);
void ubwcp_hw_set_buf_desc(void __iomem *base, u64 desc_addr, u16 desc_stride)
{
UBWCP_REG_WRITE(base, DESC_BASE, PAGE_ADDR_4K(desc_addr));
UBWCP_REG_WRITE(base, DESC_BASE_STRIDE, desc_stride);
}
EXPORT_SYMBOL(ubwcp_hw_set_buf_desc);
/* Value set here is returned upon read of an address that fails range check.
* Writes are ignored.
* Will also generate range_check_fail interrupt if enabled.
* if we don't program, default value is: 0x92929292
*/
void ubwcp_hw_set_default_range_check_value(void __iomem *base, u32 val)
{
UBWCP_REG_WRITE(base, RANGE_CHECK_FAIL, val);
}
void ubwcp_hw_version(void __iomem *base, u32 *major, u32 *minor)
{
u32 version;
version = UBWCP_REG_READ(base, VERSION_CONTROL);
*major = version & 0xF;
*minor = (version & 0xF0) >> 4;
}
EXPORT_SYMBOL(ubwcp_hw_version);
/* TBD: */
void ubwcp_hw_macro_tile_config(void __iomem *base)
{
//TODO: In future add in support for LP4
//May be able to determine DDR version via call to
//of_fdt_get_ddrtype()
/*
* For Lanai assume 4 Channel LP5 DDR so from HSR
* MAL Size 32B
* Highest Bank Bit 16
* Level 1 Bank Swizzling Disable
* Level 2 Bank Swizzling Enable
* Level 3 Bank Swizzling Enable
* Bank Spreading Enable
* Macrotiling Configuration (Num Channels) 8
*/
UBWCP_REG_WRITE(base, CONFIG, 0x1E3);
}
/* TBD: */
void ubwcp_hw_decoder_config(void __iomem *base)
{
/*
* For Lanai assume AMSBC (UBWC4.4/4.3) algorithm is used == b11
* For Lanai assume 4 Channel LP5 DDR so MAL Size 32B == b0
*/
UBWCP_REG_WRITE(base, DECODER_CONFIG, 0x7);
}
/* TBD: */
void ubwcp_hw_encoder_config(void __iomem *base)
{
/*
* For Lanai assume AMSBC (UBWC4.4/4.3) algorithm is used == b11
* For Lanai assume 4 Channel LP5 DDR so MAL Size 32B == b0
*/
UBWCP_REG_WRITE(base, ENCODER_CONFIG, 0x7);
}
void ubwcp_hw_power_vote_status(void __iomem *pwr_ctrl, u8 *vote, u8 *status)
{
u32 reg;
reg = UBWCP_REG_READ(pwr_ctrl, 0);
*vote = (reg & BIT(0)) >> 0;
*status = (reg & BIT(31)) >> 31;
}
/* process only one tile at a time */
void ubwcp_hw_single_tile(void __iomem *base, bool en)
{
u32 reg;
reg = UBWCP_REG_READ(base, SPARE);
if (en)
reg |= BIT(15);
else
reg &= ~BIT(15);
UBWCP_REG_WRITE(base, SPARE, reg);
}
EXPORT_SYMBOL(ubwcp_hw_single_tile);
void ubwcp_hw_one_time_init(void __iomem *base)
{
u32 reg;
/* Spare reg config: set bit-9: SCC & bit-1: padding */
reg = UBWCP_REG_READ(base, SPARE);
reg |= BIT(9) | BIT(1);
UBWCP_REG_WRITE(base, SPARE, reg);
/* Configure SID */
reg = UBWCP_REG_READ(base, QNS4_PARAMS);
reg &= ~(0x3F);
reg |= 0x1; /* desc buffer */
reg |= (0 << 3); /* pixel data */
UBWCP_REG_WRITE(base, QNS4_PARAMS, reg);
ubwcp_hw_decoder_config(base);
ubwcp_hw_encoder_config(base);
ubwcp_hw_macro_tile_config(base);
}
EXPORT_SYMBOL(ubwcp_hw_one_time_init);
void ubwcp_hw_trace_set(bool value)
{
ubwcp_hw_trace_en = value;
}
EXPORT_SYMBOL(ubwcp_hw_trace_set);
void ubwcp_hw_trace_get(bool *value)
{
*value = ubwcp_hw_trace_en;
}
EXPORT_SYMBOL(ubwcp_hw_trace_get);

View File

@ -0,0 +1,73 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef __UBWCP_HW_H_
#define __UBWCP_HW_H_
#define HW_BUFFER_FORMAT_RGBA 0x0
#define HW_BUFFER_FORMAT_NV12 0x2
#define HW_BUFFER_FORMAT_NV124R 0x4
#define HW_BUFFER_FORMAT_P010 0x6
#define HW_BUFFER_FORMAT_TP10 0x8
#define HW_BUFFER_FORMAT_P016 0xA
#define HW_BUFFER_FORMAT_LINEAR 0xF
/* interrupt id. also bit location for set/clear */
#define INTERRUPT_READ_ERROR 0
#define INTERRUPT_WRITE_ERROR 1
#define INTERRUPT_DECODE_ERROR 2
#define INTERRUPT_ENCODE_ERROR 3
/**
* struct msm_ubwcp_- UBWCP hardware instance
* dev:UBWCP device
* irq:Interrupt number
* clk:The bus clock for this IOMMU hardware instance
* pclk:The clock for the IOMMU IOMMU bus interconnect
*/
struct ubwcp_dev {
void __iomem *base;
struct device *dev;
int irq;
struct clk *clk;
struct clk *pclk;
/* TBD:
* struct list_head dev_node;
* struct list_head dom_node;
* struct list_head ctx_list;
* DECLARE_BITMAP(context_map, IOMMU_MAX_CBS)
* struct iommu_device iommu;
*/
};
struct __packed ubwcp_hw_meta_metadata {
u64 uv_start_addr : 48; /* uv start address */
u16 format : 16; /* format */
u16 stride; /* image stride (bytes) */
u16 stride_ubwcp; /* p010 stride for tp10 image (bytes) */
u32 metadata_base_y; /* 24-bit page address */
u32 metadata_base_uv; /* 24-bit page address */
u16 buffer_y_offset; /* 4KB offset from meta_data_base_y */
u16 buffer_uv_offset; /* 4KB offset from meta_data_base_y */
u32 width_height; /* image width (bytes) */
};
void ubwcp_hw_version(void __iomem *base, u32 *major, u32 *minor);
void ubwcp_hw_set_buf_desc(void __iomem *base, u64 desc_addr, u16 desc_stride);
void ubwcp_hw_enable_range_check(void __iomem *base, u16 index);
int ubwcp_hw_disable_range_check_with_flush(void __iomem *base, u16 index);
void ubwcp_hw_set_range_check(void __iomem *base, u16 index, phys_addr_t pa, size_t size);
u64 ubwcp_hw_interrupt_src_address(void __iomem *base, u16 interrupt);
void ubwcp_hw_interrupt_clear(void __iomem *base, u16 interrupt);
void ubwcp_hw_interrupt_enable(void __iomem *base, u16 interrupt, bool enable);
void ubwcp_hw_power_on(void __iomem *pwr_ctrl, bool power_on);
void ubwcp_hw_one_time_init(void __iomem *base);
int ubwcp_hw_flush(void __iomem *base);
void ubwcp_hw_trace_set(bool value);
void ubwcp_hw_trace_get(bool *value);
void ubwcp_hw_single_tile(void __iomem *base, bool en);
#endif /* __UBWCP_HW_H_ */

View File

@ -0,0 +1,121 @@
# Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
# Copyright (c) 2022 Qualcomm Innovation Center, 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 version 2 as published by
# the Free Software Foundation.
#
# 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, see <http://www.gnu.org/licenses/>.
import argparse
import filecmp
import os
import re
import subprocess
import sys
def run_uapi_headers_install(verbose, gen_dir, headers_install, unifdef, prefix, h):
if not h.startswith(prefix):
print('error: expected prefix [%s] on header [%s]' % (prefix, h))
return False
out_h = os.path.join(gen_dir, h[len(prefix):])
(out_h_dirname, out_h_basename) = os.path.split(out_h)
env = os.environ.copy()
env["LOC_UNIFDEF"] = unifdef
cmd = ["sh", headers_install, h, out_h]
if verbose:
print('run_uapi_headers_install: cmd is %s' % cmd)
result = subprocess.call(cmd, env=env)
if result != 0:
print('error: run_uapi_headers_install: cmd %s failed %d' % (cmd, result))
return False
return True
def run_kernel_headers_install(verbose, gen_dir, headers_install, unifdef, prefix, h):
if not h.startswith(prefix):
print('error: expected prefix [%s] on header [%s]' % (prefix, h))
return False
out_h = os.path.join(gen_dir, h[len(prefix):])
(out_h_dirname, out_h_basename) = os.path.split(out_h)
env = os.environ.copy()
cmd = ["cp", h, out_h]
if verbose:
print('run_kernel_headers_install: cmd is %s' % cmd)
result = subprocess.call(cmd, env=env)
if result != 0:
print('error: run_kernel_headers_install: cmd %s failed %d' % (cmd, result))
return False
return True
def gen_ubwcp_headers(verbose, gen_dir, headers_install, unifdef, ubwcp_include):
error_count = 0
for h in ubwcp_include:
if 'include/uapi' in h:
ubwcp_include_prefix = os.path.join(h.split('/include/uapi')[0], 'include', 'uapi') + os.sep
if not run_uapi_headers_install(
verbose, gen_dir, headers_install, unifdef,
ubwcp_include_prefix, h): error_count += 1
elif 'include/kernel' in h:
ubwcp_include_prefix = os.path.join(h.split('/include/kernel')[0], 'include', 'kernel') + os.sep
if not run_kernel_headers_install(
verbose, gen_dir, headers_install, unifdef,
ubwcp_include_prefix, h): error_count += 1
return error_count
def main():
"""Parse command line arguments and perform top level control."""
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
# Arguments that apply to every invocation of this script.
parser.add_argument(
'--verbose', action='store_true',
help='Print output that describes the workings of this script.')
parser.add_argument(
'--header_arch', required=True,
help='The arch for which to generate headers.')
parser.add_argument(
'--gen_dir', required=True,
help='Where to place the generated files.')
parser.add_argument(
'--ubwcp_include', required=True, nargs='*',
help='The list of header files.')
parser.add_argument(
'--headers_install', required=True,
help='The headers_install tool to process input headers.')
parser.add_argument(
'--unifdef',
required=True,
help='The unifdef tool used by headers_install.')
args = parser.parse_args()
if args.verbose:
print('header_arch [%s]' % args.header_arch)
print('gen_dir [%s]' % args.gen_dir)
print('ubwcp_include [%s]' % args.ubwcp_include)
print('headers_install [%s]' % args.headers_install)
print('unifdef [%s]' % args.unifdef)
return gen_ubwcp_headers(args.verbose, args.gen_dir,
args.headers_install, args.unifdef, args.ubwcp_include)
if __name__ == '__main__':
sys.exit(main())

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,313 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#if !defined(TRACE_UBWCP_H) || defined(TRACE_HEADER_MULTI_READ)
#define TRACE_UBWCP_H
#undef TRACE_SYSTEM
#define TRACE_SYSTEM ubwcp
/* Path must be relative to location of 'define_trace.h' header in kernel */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH ../../../../vendor/qcom/opensource/mm-sys-kernel/ubwcp
/* Name of trace header file */
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE ubwcp_trace
#include <linux/tracepoint.h>
struct dma_buf;
struct platform_device;
DECLARE_EVENT_CLASS(ubwcp_platform_device_event,
TP_PROTO(struct platform_device *pdev),
TP_ARGS(pdev),
TP_STRUCT__entry(
__field(struct platform_device *, pdev)
),
TP_fast_assign(
__entry->pdev = pdev;
),
TP_printk("platform_device:0x%lx",
__entry->pdev)
);
DEFINE_EVENT(ubwcp_platform_device_event, ubwcp_probe,
TP_PROTO(struct platform_device *pdev),
TP_ARGS(pdev)
);
DEFINE_EVENT(ubwcp_platform_device_event, ubwcp_remove,
TP_PROTO(struct platform_device *pdev),
TP_ARGS(pdev)
);
DECLARE_EVENT_CLASS(ubwcp_dmabuf_event,
TP_PROTO(struct dma_buf *dbuf_addr),
TP_ARGS(dbuf_addr),
TP_STRUCT__entry(
__field(struct dma_buf *, dbuf_addr)
),
TP_fast_assign(
__entry->dbuf_addr = dbuf_addr;
),
TP_printk("dma-buf:0x%lx",
__entry->dbuf_addr)
);
DECLARE_EVENT_CLASS(ubwcp_size_event,
TP_PROTO(size_t size),
TP_ARGS(size),
TP_STRUCT__entry(
__field(size_t, size)
),
TP_fast_assign(
__entry->size = size;
),
TP_printk("size:%zu", __entry->size)
);
DECLARE_EVENT_CLASS(ubwcp_sync_event,
TP_PROTO(size_t size,
int dir),
TP_ARGS(size, dir),
TP_STRUCT__entry(
__field(size_t, size)
__field(int, dir)
),
TP_fast_assign(
__entry->size = size;
__entry->dir = dir;
),
TP_printk("size:%zu, dir:%d", __entry->size, __entry->dir)
);
DEFINE_EVENT(ubwcp_dmabuf_event, ubwcp_init_buffer_start,
TP_PROTO(struct dma_buf *dbuf_addr),
TP_ARGS(dbuf_addr)
);
DEFINE_EVENT(ubwcp_dmabuf_event, ubwcp_init_buffer_end,
TP_PROTO(struct dma_buf *dbuf_addr),
TP_ARGS(dbuf_addr)
);
DEFINE_EVENT(ubwcp_size_event, ubwcp_memremap_pages_start,
TP_PROTO(size_t size),
TP_ARGS(size)
);
DEFINE_EVENT(ubwcp_size_event, ubwcp_memremap_pages_end,
TP_PROTO(size_t size),
TP_ARGS(size)
);
DEFINE_EVENT(ubwcp_dmabuf_event, ubwcp_set_buf_attrs_start,
TP_PROTO(struct dma_buf *dbuf_addr),
TP_ARGS(dbuf_addr)
);
DEFINE_EVENT(ubwcp_dmabuf_event, ubwcp_set_buf_attrs_end,
TP_PROTO(struct dma_buf *dbuf_addr),
TP_ARGS(dbuf_addr)
);
DEFINE_EVENT(ubwcp_dmabuf_event, ubwcp_lock_start,
TP_PROTO(struct dma_buf *dbuf_addr),
TP_ARGS(dbuf_addr)
);
DEFINE_EVENT(ubwcp_dmabuf_event, ubwcp_lock_end,
TP_PROTO(struct dma_buf *dbuf_addr),
TP_ARGS(dbuf_addr)
);
DEFINE_EVENT(ubwcp_dmabuf_event, ubwcp_unlock_start,
TP_PROTO(struct dma_buf *dbuf_addr),
TP_ARGS(dbuf_addr)
);
DEFINE_EVENT(ubwcp_dmabuf_event, ubwcp_unlock_end,
TP_PROTO(struct dma_buf *dbuf_addr),
TP_ARGS(dbuf_addr)
);
DEFINE_EVENT(ubwcp_size_event, ubwcp_offline_sync_start,
TP_PROTO(size_t size),
TP_ARGS(size)
);
DEFINE_EVENT(ubwcp_size_event, ubwcp_offline_sync_end,
TP_PROTO(size_t size),
TP_ARGS(size)
);
DEFINE_EVENT(ubwcp_sync_event, ubwcp_dma_sync_single_for_device_start,
TP_PROTO(size_t size, int dir),
TP_ARGS(size, dir)
);
DEFINE_EVENT(ubwcp_sync_event, ubwcp_dma_sync_single_for_device_end,
TP_PROTO(size_t size, int dir),
TP_ARGS(size, dir)
);
DEFINE_EVENT(ubwcp_sync_event, ubwcp_dma_sync_single_for_cpu_start,
TP_PROTO(size_t size, int dir),
TP_ARGS(size, dir)
);
DEFINE_EVENT(ubwcp_sync_event, ubwcp_dma_sync_single_for_cpu_end,
TP_PROTO(size_t size, int dir),
TP_ARGS(size, dir)
);
DEFINE_EVENT(ubwcp_size_event, ubwcp_hw_flush_start,
TP_PROTO(size_t size),
TP_ARGS(size)
);
DEFINE_EVENT(ubwcp_size_event, ubwcp_hw_flush_end,
TP_PROTO(size_t size),
TP_ARGS(size)
);
DEFINE_EVENT(ubwcp_size_event, ubwcp_memunmap_pages_start,
TP_PROTO(size_t size),
TP_ARGS(size)
);
DEFINE_EVENT(ubwcp_size_event, ubwcp_memunmap_pages_end,
TP_PROTO(size_t size),
TP_ARGS(size)
);
DEFINE_EVENT(ubwcp_size_event, ubwcp_set_direct_map_range_uncached_start,
TP_PROTO(size_t size),
TP_ARGS(size)
);
DEFINE_EVENT(ubwcp_size_event, ubwcp_set_direct_map_range_uncached_end,
TP_PROTO(size_t size),
TP_ARGS(size)
);
DEFINE_EVENT(ubwcp_dmabuf_event, ubwcp_free_buffer_start,
TP_PROTO(struct dma_buf *dbuf_addr),
TP_ARGS(dbuf_addr)
);
DEFINE_EVENT(ubwcp_dmabuf_event, ubwcp_free_buffer_end,
TP_PROTO(struct dma_buf *dbuf_addr),
TP_ARGS(dbuf_addr)
);
DECLARE_EVENT_CLASS(ubwcp_int_event,
TP_PROTO(int value),
TP_ARGS(value),
TP_STRUCT__entry(
__field(int, value)
),
TP_fast_assign(
__entry->value = value;
),
TP_printk("value:%d", __entry->value)
);
DEFINE_EVENT(ubwcp_int_event, ubwcp_prefetch_tgt_start,
TP_PROTO(int value),
TP_ARGS(value)
);
DEFINE_EVENT(ubwcp_int_event, ubwcp_prefetch_tgt_end,
TP_PROTO(int value),
TP_ARGS(value)
);
#endif
/* This part must be outside protection */
#include <trace/define_trace.h>

View File

@ -0,0 +1,3 @@
ifneq ($(TARGET_KERNEL_DLKM_DISABLE), true)
PRODUCT_PACKAGES += ubwcp.ko
endif

View File

@ -0,0 +1,3 @@
ifneq ($(TARGET_KERNEL_DLKM_DISABLE), true)
BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/ubwcp.ko
endif