Merge commit 'ff98cc67d000b978ef16edcbabdf5d54b7bdd667'

* commit 'ff98cc67d000b978ef16edcbabdf5d54b7bdd667': (21 commits)
  arm64/configs: rockchip_linux_defconfig: enable CONFIG_HWSPINLOCK_ROCKCHIP
  arm64/configs: rv1126b.config: enable CONFIG_ROCKCHIP_DVBM
  drm/rockchip: dsi: solve dsi failed to enter command mode before system sleeping
  arm64/configs: enable CONFIG_DMABUF_PARTIAL for rockchip_linux_defconfig
  ARM: configs: rockchip_linux_defconfig enable RK628 hdmitx and videoin
  misc: rockchip: pcie-rkep: Use the matching dma_mmap_coherent
  usb: storage: Add quirk for Teclast CoolFlash
  ARM: dts: rockchip: rv1126b-thunder-boot: Add i2c3 clocks to thunder_boot_rkisp
  media: rockchip: vicap distinguish share interrupts
  ARM: configs: rv1126b-tb: Support SC850SL
  ARM: dts: rockchip: Add rv1126b-evb2-v10-tb-800w-emmc support
  arm64: dts: rockchip: rv1126b: Add spec-sn for cpuinfo
  soc: rockchip: cpuinfo: Add RV1126B-P
  soc: rockchip: cpuinfo: Add rockchip_set_spec_sn
  media: videobuf2-cma-sg: support rk-system-heap
  dma-buf: rk_heaps: add rk-system-heap
  media: rockchip: vicap disables its dma adapter when in debug mode
  soc: rockchip: aoa_middleware: remove global variables as much as possible to avoid multi-core racing issues
  soc: rockchip: aoa_middleware: fix the log storm caused by DMA interrupt not being closed during repeated insmod
  soc: rockchip: aoa_middleware: fix NULL pointer during rmmod rk_aoa.ko
  ...

Change-Id: I43c6a97a7c49463d0835431bcba5c1e2ffd09f6d
This commit is contained in:
Tao Huang
2025-09-04 20:20:53 +08:00
33 changed files with 909 additions and 143 deletions

View File

@@ -1199,6 +1199,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \
rv1126b-evb2-v10-sii9022-bt1120-to-hdmi.dtb \
rv1126b-evb2-v10-tb-400w-emmc.dtb \
rv1126b-evb2-v10-tb-400w-spi-nor.dtb \
rv1126b-evb2-v10-tb-800w-emmc.dtb \
rv1126b-evb2-v12.dtb \
rv1126b-evb2-v12-aov-dual-cam.dtb \
rv1126b-evb2-v12-fastboot-emmc.dtb \

View File

@@ -0,0 +1,82 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2025 Rockchip Electronics Co., Ltd.
*/
/dts-v1/;
#include "arm64/rockchip/rv1126b.dtsi"
#include "arm64/rockchip/rv1126b-evb.dtsi"
#include "arm64/rockchip/rv1126b-evb2-v10.dtsi"
#include "rv1126b-thunder-boot-cam.dtsi"
#include "rv1126b-thunder-boot-emmc.dtsi"
/ {
model = "Rockchip RV1126B EVB2 V10 TB 800W eMMC Board";
compatible = "rockchip,rv1126b-evb2-v10-tb-800w-emmc", "rockchip,rv1126b";
chosen {
bootargs = "loglevel=0 initcall_nr_threads=-1 initcall_debug=0 earlycon=uart8250,mmio32,0x20810000 console=ttyFIQ0 root=/dev/rd0 rootfstype=erofs rootflags=dax snd_soc_core.prealloc_buffer_size_kbytes=16 coherent_pool=32K";
};
};
&emmc {
bus-width = <8>;
cap-mmc-highspeed;
non-removable;
mmc-hs200-1_8v;
rockchip,default-sample-phase = <90>;
no-sdio;
no-sd;
status = "okay";
};
&fspi0 {
status = "disabled";
};
&i2c3 {
clock-frequency = <400000>;
pinctrl-names = "default";
pinctrl-0 = <&i2c3m1_pins>;
rockchip,amp-shared;
status = "okay";
sc850sl: sc850sl@30 {
compatible = "smartsens,sc850sl";
reg = <0x30>;
clocks = <&cru CLK_MIPI0_OUT2IO>;
clock-names = "xvclk";
reset-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_LOW>;
pwdn-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&cam_clk0_pins>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "default";
rockchip,camera-module-lens-name = "default";
port {
cam0_out: endpoint {
remote-endpoint = <&csi_dphy_input0>;
data-lanes = <1 2 3 4>;
};
};
};
};
&ramdisk_r {
reg = <0x48c40000 (60 * 0x00100000)>;
};
&ramdisk_c {
reg = <0x4c840000 (30 * 0x00100000)>;
};
&rkisp_thunderboot {
/* reg's offset MUST match with RTOS */
/*
* vicap, capture raw10, ceil(w*10/8/256)*256*h *4(buf num) + sizeof(rkisp_thunderboot_resmem_head)
* e.g. 2688x1520: 0x14c8000 + 0x9000
* e.g. 3840x2160: 0x2814000 + 0x9000
*/
reg = <0x41320000 0x281d000>;
};

View File

@@ -21,6 +21,7 @@
<&cru DCLK_VICAP>, <&cru ISP0CLK_VICAP>,
<&cru PCLK_CSI2HOST0>,
<&cru DCLK_CSI2HOST0>,
<&cru CLK_I2C3>, <&cru PCLK_I2C3>,
<&cru CLK_I2C4>, <&cru PCLK_I2C4>;
clock-names = "clk_hpmcu",
"pclk_hpmcu_intmux", "pclk_hpmcu_mailbox",
@@ -32,6 +33,7 @@
"dclk_cif", "isp0clk_cif",
"pclk_csi2host0",
"dclk_csi2host0",
"clk_i2c3", "pclk_i2c3",
"clk_i2c4", "pclk_i2c4";
};

View File

@@ -160,6 +160,8 @@ CONFIG_ZRAM=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=1
CONFIG_RK628_MISC=y
CONFIG_RK628_MISC_HDMITX=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_BLK_DEV_SR=y
@@ -284,6 +286,8 @@ CONFIG_VIDEO_OV5647=y
CONFIG_VIDEO_OV8858=y
CONFIG_VIDEO_OV13850=y
CONFIG_VIDEO_SGM3784=y
CONFIG_VIDEO_RK628_CSI=y
CONFIG_VIDEO_RK628_BT1120=y
CONFIG_DRM=y
CONFIG_DRM_IGNORE_IOTCL_PERMIT=y
CONFIG_DRM_LOAD_EDID_FIRMWARE=y

View File

@@ -40,6 +40,7 @@ CONFIG_VIDEO_ROCKCHIP_ISP=y
CONFIG_VIDEO_ROCKCHIP_VPSS=y
CONFIG_VIDEO_SC200AI=y
CONFIG_VIDEO_SC450AI=y
CONFIG_VIDEO_SC850SL=y
# CONFIG_AD2S1200 is not set
# CONFIG_AD2S1210 is not set
# CONFIG_AD2S90 is not set

View File

@@ -405,8 +405,8 @@
cpuinfo {
compatible = "rockchip,cpuinfo";
nvmem-cells = <&otp_id>, <&cpu_version>, <&cpu_code>;
nvmem-cell-names = "id", "cpu-version", "cpu-code";
nvmem-cells = <&otp_id>, <&cpu_version>, <&cpu_code>, <&specification_serial_number>;
nvmem-cell-names = "id", "cpu-version", "cpu-code", "spec-sn";
};
/* dphy0 full mode */
@@ -1942,7 +1942,7 @@
cpu_code: cpu-code@2 {
reg = <0x02 0x2>;
};
specification_serial_number: specification-serial-number@7 {
specification_serial_number: specification-serial-number@8 {
reg = <0x08 0x1>;
bits = <0 5>;
};

View File

@@ -524,6 +524,7 @@ CONFIG_DMADEVICES=y
CONFIG_PL330_DMA=y
CONFIG_ROCKCHIP_DMA=y
CONFIG_RK_DMABUF_DEBUG=y
CONFIG_DMABUF_PARTIAL=y
CONFIG_SW_SYNC=y
CONFIG_DMABUF_HEAPS=y
CONFIG_DMABUF_SYSFS_STATS=y
@@ -537,6 +538,8 @@ CONFIG_COMMON_CLK_RK808=y
CONFIG_COMMON_CLK_SCMI=y
CONFIG_COMMON_CLK_PWM=y
CONFIG_ROCKCHIP_CLK_PVTPLL=y
CONFIG_HWSPINLOCK=y
CONFIG_HWSPINLOCK_ROCKCHIP=y
CONFIG_MAILBOX=y
CONFIG_ROCKCHIP_MBOX=y
CONFIG_ROCKCHIP_IOMMU=y

View File

@@ -1,2 +1,3 @@
CONFIG_ROCKCHIP_DVBM=y
CONFIG_ROCKCHIP_RKNPU_PROC_FS=y
CONFIG_ROCKCHIP_RKNPU_DMA_HEAP=y

View File

@@ -35,6 +35,14 @@ config DMABUF_HEAPS_ROCKCHIP_CMA_ALIGNMENT
If unsure, leave the default value "8".
config DMABUF_HEAPS_ROCKCHIP_SYSTEM_HEAP
tristate "DMA-BUF RockChip system Heap"
depends on DMABUF_HEAPS_ROCKCHIP
help
Choose this option to enable dma-buf RockChip SYSTEM heap. This heap is backed
by the system pages. If your system has these
regions, you should say Y here.
config DMABUF_RK_HEAPS_DEBUG
bool "DMA-BUF RockChip Heap Debug"
depends on DMABUF_HEAPS_ROCKCHIP

View File

@@ -4,3 +4,4 @@ rk-cma-heap-objs := rk-dma-cma.o rk-cma-heap.o
obj-$(CONFIG_DMABUF_HEAPS_ROCKCHIP) += rk-dma-heap.o
obj-$(CONFIG_DMABUF_HEAPS_ROCKCHIP_CMA_HEAP) += rk-cma-heap.o
obj-$(CONFIG_DMABUF_HEAPS_ROCKCHIP_SYSTEM_HEAP) += rk-system-heap.o

View File

@@ -215,6 +215,25 @@ void rk_dma_heap_total_dec(struct rk_dma_heap *heap, size_t len)
mutex_unlock(&rk_heap_list_lock);
}
int rk_dma_heap_alloc_pages(struct rk_dma_heap *heap,
struct page **pages, size_t len, gfp_t flags,
const char *name)
{
len = PAGE_ALIGN(len);
if (!len)
return -EINVAL;
return heap->ops->alloc_pages(heap, pages, len, flags, name);
}
EXPORT_SYMBOL_GPL(rk_dma_heap_alloc_pages);
void rk_dma_heap_free_pages(struct rk_dma_heap *heap,
struct page **pages, unsigned int count)
{
return heap->ops->free_pages(heap, pages, count);
}
EXPORT_SYMBOL_GPL(rk_dma_heap_free_pages);
static int rk_dma_heap_open(struct inode *inode, struct file *file)
{
struct rk_dma_heap *heap;
@@ -398,7 +417,7 @@ struct rk_dma_heap *rk_dma_heap_add(const struct rk_dma_heap_export_info *exp_in
return ERR_PTR(-EINVAL);
}
if (!exp_info->ops || !exp_info->ops->allocate) {
if (!exp_info->ops || (!exp_info->permit_noalloc && !exp_info->ops->allocate)) {
pr_err("rk_dma_heap: Cannot add heap with invalid ops struct\n");
return ERR_PTR(-EINVAL);
}
@@ -423,8 +442,10 @@ struct rk_dma_heap *rk_dma_heap_add(const struct rk_dma_heap_export_info *exp_in
heap->support_cma = exp_info->support_cma;
INIT_LIST_HEAD(&heap->dmabuf_list);
INIT_LIST_HEAD(&heap->contig_list);
INIT_LIST_HEAD(&heap->pages_list);
mutex_init(&heap->dmabuf_lock);
mutex_init(&heap->contig_lock);
mutex_init(&heap->pages_lock);
/* Find unused minor number */
ret = xa_alloc(&rk_dma_heap_minors, &minor, heap,
@@ -450,7 +471,7 @@ struct rk_dma_heap *rk_dma_heap_add(const struct rk_dma_heap_export_info *exp_in
NULL,
heap->heap_devt,
NULL,
heap->name);
"%s", heap->name);
if (IS_ERR(heap->heap_dev)) {
pr_err("rk_dma_heap: Unable to create device\n");
err_ret = ERR_CAST(heap->heap_dev);
@@ -551,6 +572,21 @@ static int rk_dma_heap_dump_contig(void *data)
return 0;
}
static int rk_dma_heap_dump_pages(void *data)
{
struct rk_dma_heap *heap = (struct rk_dma_heap *)data;
struct rk_dma_heap_pages_buf *buf;
mutex_lock(&heap->pages_lock);
list_for_each_entry(buf, &heap->pages_list, node) {
seq_printf(heap->s, "\tAlloc by (%-20s)\t%lx (%lu KiB)\n",
buf->orig_alloc, buf->size, K(buf->size));
}
mutex_unlock(&heap->pages_lock);
return 0;
}
static ssize_t rk_total_pools_kb_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
@@ -616,6 +652,7 @@ static int rk_dma_heap_debug_show(struct seq_file *s, void *unused)
heap->s = s;
dma_buf_get_each(rk_dma_heap_dump_dmabuf, heap);
rk_dma_heap_dump_contig(heap);
rk_dma_heap_dump_pages(heap);
total += heap->total_size;
}
seq_printf(s, "\nTotal : 0x%lx (%lu KiB)\n", total, K(total));
@@ -665,6 +702,7 @@ static int rk_dma_heap_proc_show(struct seq_file *s, void *unused)
heap->s = s;
dma_buf_get_each(rk_dma_heap_dump_dmabuf, heap);
rk_dma_heap_dump_contig(heap);
rk_dma_heap_dump_pages(heap);
total += heap->total_size;
}
seq_printf(s, "\nTotal : 0x%lx (%lu KiB)\n", total, K(total));

View File

@@ -35,7 +35,10 @@ struct rk_vmap_pfn_data {
* struct rk_dma_heap_ops - ops to operate on a given heap
* @allocate: allocate dmabuf and return struct dma_buf ptr
* @get_pool_size: if heap maintains memory pools, get pool size in bytes
*
@alloc_contig_pages: alloc pages from CMA
@free_contig_pages: free pages to CMA
* @alloc_pages: alloc pages from system
* @free_pages: free pages to system
* allocate returns dmabuf on success, ERR_PTR(-errno) on error.
*/
struct rk_dma_heap_ops {
@@ -44,12 +47,16 @@ struct rk_dma_heap_ops {
unsigned long fd_flags,
unsigned long heap_flags,
const char *name);
long (*get_pool_size)(struct rk_dma_heap *heap);
struct page *(*alloc_contig_pages)(struct rk_dma_heap *heap,
size_t len, const char *name);
void (*free_contig_pages)(struct rk_dma_heap *heap,
struct page *pages, size_t len,
const char *name);
long (*get_pool_size)(struct rk_dma_heap *heap);
int (*alloc_pages)(struct rk_dma_heap *heap, struct page **pages,
size_t len, gfp_t flags, const char *name);
void (*free_pages)(struct rk_dma_heap *heap,
struct page **pages, unsigned int count);
};
/**
@@ -65,6 +72,7 @@ struct rk_dma_heap_export_info {
const struct rk_dma_heap_ops *ops;
void *priv;
bool support_cma;
bool permit_noalloc;
};
/**
@@ -88,6 +96,8 @@ struct rk_dma_heap {
struct mutex dmabuf_lock;
struct list_head contig_list; /* contig buffer attach to this node */
struct mutex contig_lock;
struct list_head pages_list;
struct mutex pages_lock;
struct cdev heap_cdev;
struct kref refcount;
struct device *heap_dev;
@@ -112,6 +122,13 @@ struct rk_dma_heap_contig_buf {
phys_addr_t end;
};
struct rk_dma_heap_pages_buf {
struct list_head node;
unsigned long size;
const char *orig_alloc;
phys_addr_t start;
};
/**
* rk_dma_heap_get_drvdata() - get per-heap driver data
* @heap: DMA-Heap to retrieve private data for

View File

@@ -0,0 +1,247 @@
// SPDX-License-Identifier: GPL-2.0
/*
* DMABUF System heap exporter
*
* Copyright (C) 2011 Google, Inc.
* Copyright (C) 2012, 2019, 2020 Linaro Ltd.
*
* Also utilizing parts of Andrew Davis' SRAM heap:
* Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
* Andrew F. Davis <afd@ti.com>
*
* Copyright (C) 2025 Rockchip Electronics Co., Ltd.
* Author: Simon Xue <xxm@rock-chips.com>
*/
#include <linux/cma.h>
#include <linux/dma-buf.h>
#include <linux/dma-map-ops.h>
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <uapi/linux/rk-dma-heap.h>
#include <linux/proc_fs.h>
#include "../../../mm/cma.h"
#include "rk-dma-heap.h"
struct rk_system_heap {
struct rk_dma_heap *heap;
};
static int rk_system_heap_remove_pages_list(struct rk_dma_heap *heap,
struct page *page)
{
struct rk_dma_heap_pages_buf *buf;
mutex_lock(&heap->pages_lock);
list_for_each_entry(buf, &heap->pages_list, node) {
if (buf->start == page_to_phys(page)) {
dma_heap_print("<%s> free pages %ld to system\n",
buf->orig_alloc, buf->size);
list_del(&buf->node);
kfree(buf->orig_alloc);
kfree(buf);
break;
}
}
mutex_unlock(&heap->pages_lock);
return 0;
}
static int rk_system_heap_add_pages_list(struct rk_dma_heap *heap,
struct page *first_page,
unsigned long size, const char *name)
{
struct rk_dma_heap_pages_buf *buf;
const char *name_tmp;
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
return -ENOMEM;
INIT_LIST_HEAD(&buf->node);
if (!name)
name_tmp = current->comm;
else
name_tmp = name;
buf->orig_alloc = kstrndup(name_tmp, RK_DMA_HEAP_NAME_LEN, GFP_KERNEL);
if (!buf->orig_alloc) {
kfree(buf);
return -ENOMEM;
}
buf->size = size;
buf->start = page_to_phys(first_page);
mutex_lock(&heap->pages_lock);
list_add_tail(&buf->node, &heap->pages_list);
mutex_unlock(&heap->pages_lock);
dma_heap_print("<%s> alloc %ld from system\n", buf->orig_alloc, size);
return 0;
}
static int rk_system_heap_allocate_pages(struct rk_dma_heap *heap,
struct page **pages,
size_t size, gfp_t flags,
const char *name)
{
int ret;
unsigned int last_page = 0;
struct page *first_page = NULL;
unsigned long num_pages = size >> PAGE_SHIFT;
size_t raw_size = size;
while (size > 0) {
struct page *page;
int order;
int i;
order = get_order(size);
/* Don't over allocate*/
if ((PAGE_SIZE << order) > size && order > 0)
order--;
page = NULL;
while (!page) {
page = alloc_pages(GFP_KERNEL | __GFP_ZERO |
__GFP_NOWARN | flags, order);
if (page) {
if (!first_page)
first_page = page;
break;
}
if (order == 0) {
while (last_page--)
__free_page(pages[last_page]);
return -ENOMEM;
}
order--;
}
split_page(page, order);
for (i = 0; i < (1 << order); i++)
pages[last_page++] = &page[i];
size -= PAGE_SIZE << order;
}
ret = rk_system_heap_add_pages_list(heap, first_page, raw_size, name);
if (ret)
goto free_pages;
rk_dma_heap_total_inc(heap, raw_size);
return 0;
free_pages:
while (num_pages--) {
__free_page(pages[num_pages]);
pages[num_pages] = NULL;
}
return ret;
}
static void rk_system_heap_free_pages(struct rk_dma_heap *heap,
struct page **pages, unsigned int num_pages)
{
/* Need more reasonable way */
rk_system_heap_remove_pages_list(heap, pages[0]);
rk_dma_heap_total_dec(heap, num_pages << PAGE_SHIFT);
while (num_pages--) {
__free_page(pages[num_pages]);
pages[num_pages] = NULL;
}
}
static const struct rk_dma_heap_ops rk_system_heap_ops = {
.alloc_pages = rk_system_heap_allocate_pages,
.free_pages = rk_system_heap_free_pages,
};
static int set_heap_dev_dma(struct device *heap_dev)
{
int err = 0;
if (!heap_dev)
return -EINVAL;
dma_coerce_mask_and_coherent(heap_dev, DMA_BIT_MASK(64));
if (!heap_dev->dma_parms) {
heap_dev->dma_parms = devm_kzalloc(heap_dev,
sizeof(*heap_dev->dma_parms),
GFP_KERNEL);
if (!heap_dev->dma_parms)
return -ENOMEM;
err = dma_set_max_seg_size(heap_dev, (unsigned int)DMA_BIT_MASK(64));
if (err) {
devm_kfree(heap_dev, heap_dev->dma_parms);
dev_err(heap_dev, "Failed to set DMA segment size, err:%d\n", err);
return err;
}
}
return 0;
}
static int __rk_add_system_heap(void)
{
struct rk_system_heap *sytem_heap;
struct rk_dma_heap_export_info exp_info;
int ret;
sytem_heap = kzalloc(sizeof(*sytem_heap), GFP_KERNEL);
if (!sytem_heap)
return -ENOMEM;
exp_info.name = "rk-system-heap";
exp_info.ops = &rk_system_heap_ops;
exp_info.priv = sytem_heap;
exp_info.permit_noalloc = true;
sytem_heap->heap = rk_dma_heap_add(&exp_info);
if (IS_ERR(sytem_heap->heap)) {
ret = PTR_ERR(sytem_heap->heap);
kfree(sytem_heap);
return ret;
}
ret = set_heap_dev_dma(rk_dma_heap_get_dev(sytem_heap->heap));
if (ret) {
rk_dma_heap_put(sytem_heap->heap);
kfree(sytem_heap);
return ret;
}
return 0;
}
static int __init rk_add_system_heap(void)
{
return __rk_add_system_heap();
}
#if defined(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP) && !defined(CONFIG_INITCALL_ASYNC)
subsys_initcall(rk_add_system_heap);
#else
module_init(rk_add_system_heap);
#endif
MODULE_DESCRIPTION("RockChip DMA-BUF SYSTEM Heap");
MODULE_LICENSE("GPL");

View File

@@ -172,7 +172,7 @@
#define DSI2_INT_FORCE_CRI 0x0468
#define DSI2_MAX_REGISGER DSI2_INT_FORCE_CRI
#define MODE_STATUS_TIMEOUT_US 10000
#define MODE_STATUS_TIMEOUT_US 20000
#define CMD_PKT_STATUS_TIMEOUT_US 20000
#define PSEC_PER_SEC 1000000000000LL
@@ -435,7 +435,7 @@ static void dw_mipi_dsi2_set_vid_mode(struct dw_mipi_dsi2 *dsi2)
regmap_write(dsi2->regmap, DSI2_MODE_CTRL, VIDEO_MODE);
ret = regmap_read_poll_timeout(dsi2->regmap, DSI2_MODE_STATUS,
mode, mode & VIDEO_MODE,
mode, mode == VIDEO_MODE,
1000, MODE_STATUS_TIMEOUT_US);
if (ret < 0)
dev_err(dsi2->dev, "failed to enter video mode\n");
@@ -448,7 +448,7 @@ static void dw_mipi_dsi2_set_data_stream_mode(struct dw_mipi_dsi2 *dsi2)
regmap_write(dsi2->regmap, DSI2_MODE_CTRL, DATA_STREAM_MODE);
ret = regmap_read_poll_timeout(dsi2->regmap, DSI2_MODE_STATUS,
mode, mode & DATA_STREAM_MODE,
mode, mode == DATA_STREAM_MODE,
1000, MODE_STATUS_TIMEOUT_US);
if (ret < 0)
dev_err(dsi2->dev, "failed to enter data stream mode\n");
@@ -461,7 +461,7 @@ static void dw_mipi_dsi2_set_cmd_mode(struct dw_mipi_dsi2 *dsi2)
regmap_write(dsi2->regmap, DSI2_MODE_CTRL, COMMAND_MODE);
ret = regmap_read_poll_timeout(dsi2->regmap, DSI2_MODE_STATUS,
mode, mode & COMMAND_MODE,
mode, mode == COMMAND_MODE,
1000, MODE_STATUS_TIMEOUT_US);
if (ret < 0)
dev_err(dsi2->dev, "failed to enter command mode\n");

View File

@@ -44,12 +44,13 @@ struct vb2_cma_sg_buf {
struct vb2_buffer *vb;
struct rk_dma_heap *contig_heap;
struct rk_dma_heap *heap;
};
static void vb2_cma_sg_put(void *buf_priv);
static int vb2_cma_sg_alloc_compacted(struct vb2_cma_sg_buf *buf,
gfp_t gfp_flags)
static int vb2_cma_sg_alloc_pages(struct vb2_cma_sg_buf *buf,
gfp_t gfp_flags)
{
unsigned int last_page = 0;
unsigned long size = buf->size;
@@ -61,7 +62,7 @@ static int vb2_cma_sg_alloc_compacted(struct vb2_cma_sg_buf *buf,
order = get_order(size);
/* Don't over allocate*/
if ((PAGE_SIZE << order) > size)
if ((PAGE_SIZE << order) > size && order > 0)
order--;
pages = NULL;
@@ -89,7 +90,7 @@ static int vb2_cma_sg_alloc_compacted(struct vb2_cma_sg_buf *buf,
return 0;
}
static void vb2_cma_sg_free_compacted(struct vb2_cma_sg_buf *buf)
static void vb2_cma_sg_free_pages(struct vb2_cma_sg_buf *buf)
{
int num_pages = buf->num_pages;
@@ -99,6 +100,32 @@ static void vb2_cma_sg_free_compacted(struct vb2_cma_sg_buf *buf)
}
}
static int vb2_cma_sg_alloc_compacted(struct vb2_cma_sg_buf *buf,
gfp_t gfp_flags)
{
struct rk_dma_heap *heap = rk_dma_heap_find("rk-system-heap");
if (!heap)
return vb2_cma_sg_alloc_pages(buf, gfp_flags);
buf->heap = heap;
return rk_dma_heap_alloc_pages(heap, buf->pages, buf->size, gfp_flags,
dev_name(buf->dev));
}
static void vb2_cma_sg_free_compacted(struct vb2_cma_sg_buf *buf)
{
if (!buf->heap) {
vb2_cma_sg_free_pages(buf);
return;
}
rk_dma_heap_free_pages(buf->heap, buf->pages, buf->num_pages);
rk_dma_heap_put(buf->heap);
buf->heap = NULL;
}
static int vb2_cma_sg_alloc_contiguous(struct vb2_cma_sg_buf *buf)
{
struct rk_dma_heap *heap __maybe_unused;

View File

@@ -5240,7 +5240,7 @@ static int rkcif_csi_channel_set_rv1126b(struct rkcif_stream *stream,
val |= (0x2 << 20);
if (stream->rounding_bit)
val |= stream->rounding_bit;
if (!dev->terminal_sensor.hdmi_input_en)
if (!dev->terminal_sensor.hdmi_input_en && !stream->sw_dbg_en)
val |= DMA_ADAPT_EN_RV1126B;
rkcif_write_register(dev, get_reg_index_of_id_ctrl0(channel->id), val);

View File

@@ -1767,8 +1767,15 @@ static int rkcif_plat_hw_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
if (data->chip_id == CHIP_RV1106_CIF ||
data->chip_id == CHIP_RV1103B_CIF) {
if (data->chip_id == CHIP_PX30_CIF ||
data->chip_id == CHIP_RK1808_CIF ||
data->chip_id == CHIP_RV1126_CIF ||
data->chip_id == CHIP_RV1126_CIF_LITE ||
data->chip_id == CHIP_RK3568_CIF)
cif_hw->is_irq_share = true;
else
cif_hw->is_irq_share = false;
if (!cif_hw->is_irq_share) {
irq_set_status_flags(irq, IRQ_NOAUTOEN);
ret = devm_request_irq(dev, irq, rkcif_irq_handler,
0,
@@ -1970,8 +1977,7 @@ static int __maybe_unused rkcif_runtime_suspend(struct device *dev)
return 0;
rkcif_disable_sys_clk(cif_hw);
if (cif_hw->chip_id == CHIP_RV1106_CIF ||
cif_hw->chip_id == CHIP_RV1103B_CIF)
if (!cif_hw->is_irq_share)
disable_irq(cif_hw->irq);
return pinctrl_pm_select_sleep_state(dev);
@@ -1990,8 +1996,7 @@ static int __maybe_unused rkcif_runtime_resume(struct device *dev)
rkcif_enable_sys_clk(cif_hw);
rkcif_hw_soft_reset(cif_hw, true);
if (cif_hw->chip_id == CHIP_RV1106_CIF ||
cif_hw->chip_id == CHIP_RV1103B_CIF)
if (!cif_hw->is_irq_share)
enable_irq(cif_hw->irq);
return 0;

View File

@@ -167,6 +167,7 @@ struct rkcif_hw {
u64 irq_time;
bool is_rk3588s2;
bool is_in_reset;
bool is_irq_share;
};
void rkcif_hw_soft_reset(struct rkcif_hw *cif_hw, bool is_rst_iommu);

View File

@@ -967,8 +967,13 @@ static void scl_config_mi(struct rkvpss_stream *stream)
if (fmt->fmt_type == FMT_FBC)
val = 0;
else
val = out_fmt->plane_fmt[0].bytesperline;
else {
/* If 16-aligned, use stride; otherwise set to 0 */
if (IS_ALIGNED(out_fmt->plane_fmt[0].bytesperline, 16))
val = out_fmt->plane_fmt[0].bytesperline;
else
val = 0;
}
reg = stream->config->mi.stride;
rkvpss_unite_write(dev, reg, val);
@@ -2264,6 +2269,34 @@ static int rkvpss_set_fmt(struct rkvpss_stream *stream,
}
}
/* Add format alignment checks */
v4l2_dbg(1, rkvpss_debug, &dev->v4l2_dev,
"format alignment check: width=%d, height=%d, fourcc=0x%x\n",
pixm->width, pixm->height, fmt->fourcc);
if (fmt->fourcc == V4L2_PIX_FMT_FBC0 ||
fmt->fourcc == V4L2_PIX_FMT_FBC2) {
if (!IS_ALIGNED(pixm->width, 64)) {
v4l2_err(&dev->v4l2_dev,
"stream:%d fbc output width %d is not 64 aligned\n",
stream->id, pixm->width);
return -EINVAL;
}
if (!IS_ALIGNED(pixm->height, 4)) {
v4l2_err(&dev->v4l2_dev,
"stream:%d fbc output height %d is not 4 aligned\n",
stream->id, pixm->height);
return -EINVAL;
}
} else {
/* Check width alignment for non-FBC formats */
if (!IS_ALIGNED(pixm->width, 4)) {
v4l2_err(&dev->v4l2_dev,
"stream:%d output width %d is not 4 aligned\n",
stream->id, pixm->width);
return -EINVAL;
}
}
pixm->num_planes = fmt->mplanes;
pixm->field = V4L2_FIELD_NONE;
if (!pixm->quantization)

View File

@@ -1537,7 +1537,11 @@ static int write_config(struct rkvpss_offline_dev *ofl,
rkvpss_hw_write(hw, reg + i * 0x100, val);
reg = RKVPSS_MI_CHN0_WR_Y_STRIDE;
val = cfg->output[i].stride;
/* If 16-aligned, use stride; otherwise set to 0 */
if (IS_ALIGNED(cfg->output[i].stride, 16))
val = cfg->output[i].stride;
else
val = 0;
rkvpss_hw_write(hw, reg + i * 0x100, val);
reg = RKVPSS_MI_CHN0_WR_Y_SIZE;

View File

@@ -396,6 +396,18 @@ static int rkep_mem_continuous_buffer_free(struct pcie_file *pcie_file,
return ret;
}
static void *rkep_mem_continuous_buffer_to_virt(struct pcie_file *pcie_file, uint64_t dma_addr)
{
struct pcie_ep_continuous_buffer_req *buffer_req, *tmp;
list_for_each_entry_safe(buffer_req, tmp, &pcie_file->cont_buffer_list, cont_buffer_list) {
if (buffer_req->dma_addr == dma_addr)
return buffer_req->vir_addr;
}
return NULL;
}
static int pcie_rkep_open(struct inode *inode, struct file *file)
{
struct miscdevice *miscdev = file->private_data;
@@ -696,15 +708,21 @@ static int pcie_rkep_mmap(struct file *file, struct vm_area_struct *vma)
return -EINVAL;
}
if (pcie_file->cur_mmap_res == PCIE_EP_MMAP_RESOURCE_USER_MEM ||
pcie_file->cur_mmap_res == PCIE_EP_MMAP_RESOURCE_CONTINUOUS_BUFFER)
if (pcie_file->cur_mmap_res == PCIE_EP_MMAP_RESOURCE_USER_MEM) {
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
else
err = remap_pfn_range(vma, vma->vm_start,
__phys_to_pfn(addr),
size, vma->vm_page_prot);
} else if (pcie_file->cur_mmap_res == PCIE_EP_MMAP_RESOURCE_CONTINUOUS_BUFFER) {
err = dma_mmap_coherent(&pcie_rkep->pdev->dev, vma,
rkep_mem_continuous_buffer_to_virt(pcie_file, addr),
addr, size);
} else {
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
err = remap_pfn_range(vma, vma->vm_start,
__phys_to_pfn(addr),
size, vma->vm_page_prot);
err = remap_pfn_range(vma, vma->vm_start,
__phys_to_pfn(addr),
size, vma->vm_page_prot);
}
if (err)
return -EAGAIN;

View File

@@ -19,6 +19,8 @@ struct rk_aoa_dev {
struct device *dev;
struct reset_control *rst;
void __iomem *base;
int irq;
void *data;
};
static const struct of_device_id rockchip_aoa_match[] __maybe_unused = {
@@ -35,47 +37,81 @@ static irqreturn_t rockchip_aoa_isr(int irq, void *devid)
writel(st, aoa->base + AOA_AAD_IRQ_ST);
for (s = 1; s < 8; s++) {
if (st & (1 << s))
aoa_middleware_aoa_notifier(s);
aoa_middleware_aoa_notifier(s, aoa->data);
}
return IRQ_HANDLED;
}
int rockchip_aoa_probe(struct platform_device *pdev)
int rockchip_aoa_probe(struct platform_device *pdev, void *data)
{
struct device_node *node = pdev->dev.of_node;
struct rk_aoa_dev *aoa;
int ret, irq;
struct resource *res;
aoa = devm_kzalloc(&pdev->dev, sizeof(*aoa), GFP_KERNEL);
if (!aoa)
return -ENOMEM;
aoa = kzalloc(sizeof(*aoa), GFP_KERNEL);
if (!aoa) {
ret = -ENOMEM;
goto err_out;
}
aoa->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, aoa);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
goto err_free_aoa;
}
aoa->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(aoa->base))
return PTR_ERR(aoa->base);
aoa->base = ioremap(res->start, resource_size(res));
if (!aoa->base) {
ret = -ENOMEM;
goto err_free_aoa;
}
aoa->rst = devm_reset_control_array_get_optional_exclusive(aoa->dev);
if (IS_ERR(aoa->rst))
return PTR_ERR(aoa->rst);
aoa->rst = of_reset_control_array_get_optional_exclusive(node);
if (IS_ERR(aoa->rst)) {
ret = PTR_ERR(aoa->rst);
goto err_unmap;
}
irq = platform_get_irq_optional(pdev, 0);
if (irq > 0) {
ret = devm_request_irq(&pdev->dev, irq, rockchip_aoa_isr,
IRQF_SHARED, node->name, aoa);
ret = request_irq(irq, rockchip_aoa_isr, 0, node->name, aoa);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq %d\n", irq);
return ret;
goto err_put_rst;
}
}
aoa->irq = irq;
aoa->data = data;
dev_set_drvdata(&pdev->dev, aoa);
return 0;
err_put_rst:
reset_control_put(aoa->rst);
err_unmap:
iounmap(aoa->base);
err_free_aoa:
kfree(aoa);
err_out:
return ret;
}
int rockchip_aoa_remove(struct platform_device *pdev)
{
struct rk_aoa_dev *aoa = platform_get_drvdata(pdev);
if (aoa) {
if (aoa->irq > 0) {
disable_irq(aoa->irq);
free_irq(aoa->irq, aoa);
}
reset_control_put(aoa->rst);
iounmap(aoa->base);
kfree(aoa);
dev_set_drvdata(&pdev->dev, NULL);
}
return 0;
}

View File

@@ -9,7 +9,7 @@
#ifndef __AOA_DRV_H__
#define __AOA_DRV_H__
int rockchip_aoa_probe(struct platform_device *pdev);
int rockchip_aoa_probe(struct platform_device *pdev, void *data);
int rockchip_aoa_remove(struct platform_device *pdev);
#endif /* __AOA_DRV_H__ */

View File

@@ -37,36 +37,61 @@ struct aoa_middleware_devs {
struct device *dev;
struct platform_device *pdev_aoa;
struct platform_device *pdev_dma;
void *am_d;
struct notify_rkdma *nty_rkdma;
struct notify_ns *nty_ns;
struct miscdevice misc_notifier_aoa;
struct miscdevice misc_notifier_dma;
struct fasync_struct *rk_aoa_fasync_queue;
struct fasync_struct *rk_dma_fasync_queue;
};
static struct fasync_struct *rk_aoa_fasync_queue;
static struct fasync_struct *rk_dma_fasync_queue;
static struct notify_rkdma g_notify;
static struct notify_ns g_dma_ns;
int aoa_middleware_aoa_notifier(s32 status)
int aoa_middleware_aoa_notifier(s32 status, void *data)
{
struct aoa_middleware_devs *amw_d = data;
if (!amw_d) {
pr_err("%s: amw_d pointer is null\n", __func__);
return -EINVAL;
}
/* AOA Notify starting from SIGRTMIN + 1 */
kill_fasync(&rk_aoa_fasync_queue, SIGRTMIN + status, POLL_IN);
kill_fasync(&amw_d->rk_aoa_fasync_queue, SIGRTMIN + status, POLL_IN);
return 0;
}
EXPORT_SYMBOL(aoa_middleware_aoa_notifier);
int aoa_middleware_dma_notifier(s32 dma_count)
int aoa_middleware_dma_notifier(s32 dma_count, void *data)
{
struct notify_rkdma *n_rkdma = &g_notify;
struct notify_ns *n_ns = &g_dma_ns;
struct aoa_middleware_devs *amw_d = data;
struct notify_rkdma *n_rkdma;
struct notify_ns *n_ns;
struct timespec64 ts;
s32 delta_id;
if (!amw_d) {
pr_err("%s: amw_d pointer is null\n", __func__);
return -EINVAL;
}
if (!amw_d->nty_rkdma) {
pr_err("%s: nty_rkdma pointer is null\n", __func__);
return -EINVAL;
}
if (!amw_d->nty_ns) {
pr_err("%s: nty_ns pointer is null\n", __func__);
return -EINVAL;
}
n_rkdma = amw_d->nty_rkdma;
n_ns = amw_d->nty_ns;
ktime_get_boottime_ts64(&ts);
n_ns->ns = timespec64_to_ns(&ts);
kill_fasync(&rk_dma_fasync_queue, SIGRTMIN + 0, POLL_IN);
kill_fasync(&amw_d->rk_dma_fasync_queue, SIGRTMIN + 0, POLL_IN);
/* ns_id: start from 1, range: 0 ~ (periods-1) */
if (dma_count < 0 || dma_count >= n_rkdma->periods) {
pr_err("Invalid dma_count: %d\n", dma_count);
pr_err("Invalid dma_count: %d >= periods: %d\n", dma_count, n_rkdma->periods);
return -EINVAL;
}
dma_count = array_index_nospec(dma_count, n_rkdma->periods);
@@ -97,32 +122,56 @@ int aoa_middleware_dma_notifier(s32 dma_count)
}
EXPORT_SYMBOL(aoa_middleware_dma_notifier);
static int rk_aoa_notifier_open(struct inode *inode, struct file *file)
{
struct miscdevice *misc = file->private_data;
struct aoa_middleware_devs *amw_d = container_of(misc, struct aoa_middleware_devs, misc_notifier_aoa);
file->private_data = amw_d;
return 0;
}
static int rk_aoa_notifier_fasync(int fd, struct file *file, int mode)
{
return fasync_helper(fd, file, mode, &rk_aoa_fasync_queue);
struct aoa_middleware_devs *amw_d = file->private_data;
return fasync_helper(fd, file, mode, &amw_d->rk_aoa_fasync_queue);
}
static const struct file_operations rk_aoa_notifier_fops = {
.owner = THIS_MODULE,
.open = rk_aoa_notifier_open,
.fasync = rk_aoa_notifier_fasync,
};
static struct miscdevice rk_aoa_notifier_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "rk-aoa-notifier",
.fops = &rk_aoa_notifier_fops,
};
static int rk_dma_notifier_open(struct inode *inode, struct file *file)
{
struct miscdevice *misc = file->private_data;
struct aoa_middleware_devs *amw_d = container_of(misc, struct aoa_middleware_devs, misc_notifier_dma);
file->private_data = amw_d;
return 0;
}
static int rk_dma_notifier_fasync(int fd, struct file *file, int mode)
{
return fasync_helper(fd, file, mode, &rk_dma_fasync_queue);
struct aoa_middleware_devs *amw_d = file->private_data;
return fasync_helper(fd, file, mode, &amw_d->rk_dma_fasync_queue);
}
static long rk_dma_notifier_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct notify_rkdma *n_rkdma = &g_notify;
struct aoa_middleware_devs *amw_d = file->private_data;
struct notify_rkdma *n_rkdma;
struct notify_ns n_ns_user;
if (IS_ERR_OR_NULL(amw_d))
return -EINVAL;
if (IS_ERR_OR_NULL(amw_d->nty_rkdma))
return -EINVAL;
n_rkdma = amw_d->nty_rkdma;
switch (cmd) {
case NOTIFY_RKDMA_SET_PERIODS:
n_rkdma->periods = arg;
@@ -153,105 +202,168 @@ static long rk_dma_notifier_ioctl(struct file *file, unsigned int cmd, unsigned
static const struct file_operations rk_dma_notifier_fops = {
.owner = THIS_MODULE,
.open = rk_dma_notifier_open,
.fasync = rk_dma_notifier_fasync,
.compat_ioctl = rk_dma_notifier_ioctl,
.unlocked_ioctl = rk_dma_notifier_ioctl,
};
static struct miscdevice rk_dma_notifier_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "rk-dma-notifier",
.fops = &rk_dma_notifier_fops,
};
static int aoa_middleware_probe(struct platform_device *pdev)
{
struct aoa_middleware_devs *amw_d;
struct platform_device *pdev_slave;
struct device_node *np;
int ret;
struct platform_device *pdev_slave = NULL;
struct device_node *np = NULL;
void *am_map = NULL;
int ret = 0;
amw_d = devm_kzalloc(&pdev->dev, sizeof(*amw_d), GFP_KERNEL);
if (!amw_d)
return -ENOMEM;
amw_d->nty_rkdma = devm_kzalloc(&pdev->dev, sizeof(*amw_d->nty_rkdma), GFP_KERNEL);
if (!amw_d->nty_rkdma)
return -ENOMEM;
amw_d->nty_ns = devm_kzalloc(&pdev->dev, sizeof(*amw_d->nty_ns), GFP_KERNEL);
if (!amw_d->nty_ns)
return -ENOMEM;
amw_d->dev = &pdev->dev;
amw_d->pdev_aoa = NULL;
amw_d->pdev_dma = NULL;
amw_d->am_d = NULL;
/* prepare rockchip aoa control driver */
np = of_parse_phandle(pdev->dev.of_node, "rockchip,aoa", 0);
if (!np || !of_device_is_available(np)) {
dev_err(&pdev->dev, "can't find 'rockchip,aoa' node\n");
return -ENODEV;
ret = -ENODEV;
goto err_out;
}
pdev_slave = of_find_device_by_node(np);
of_node_put(np);
if (!pdev_slave) {
dev_err(&pdev->dev, "get aoa node failed\n");
return -ENODEV;
ret = -ENODEV;
goto err_out;
}
ret = rockchip_aoa_probe(pdev_slave);
ret = rockchip_aoa_probe(pdev_slave, (void *)amw_d);
if (ret) {
dev_err(&pdev->dev, "probe rockchip aoa failed: %d\n", ret);
return ret;
goto err_put_aoa;
}
amw_d->pdev_aoa = pdev_slave;
pdev_slave = NULL;
/* prepare rockchip low-power dma driver */
np = of_parse_phandle(pdev->dev.of_node, "rockchip,dma", 0);
if (!np || !of_device_is_available(np)) {
dev_err(&pdev->dev, "can't find 'rockchip,dma' node\n");
return -ENODEV;
ret = -ENODEV;
goto err_unprobe_aoa;
}
pdev_slave = of_find_device_by_node(np);
of_node_put(np);
if (!pdev_slave) {
dev_err(&pdev->dev, "get dma node failed\n");
return -ENODEV;
ret = -ENODEV;
goto err_unprobe_aoa;
}
ret = lp_rkdma_probe(pdev_slave);
ret = lp_rkdma_probe(pdev_slave, (void *)amw_d);
if (ret) {
dev_err(&pdev->dev, "probe rockchip dma failed: %d\n", ret);
return ret;
goto err_put_dma;
}
amw_d->pdev_dma = pdev_slave;
pdev_slave = NULL;
/* prepare aoa memory mapping */
ret = aoa_mmap_probe(pdev);
if (ret) {
am_map = aoa_mmap_probe(pdev);
if (IS_ERR_OR_NULL(am_map)) {
if (IS_ERR(am_map))
ret = PTR_ERR(am_map);
else
ret = -EINVAL;
dev_err(&pdev->dev, "%s: aoa mmap probe failed (%d)\n", __func__, ret);
return ret;
goto err_unprobe_dma;
}
amw_d->am_d = am_map;
/* prepare aoa/dma notifiers */
ret = misc_register(&rk_aoa_notifier_misc);
amw_d->misc_notifier_aoa.minor = MISC_DYNAMIC_MINOR;
amw_d->misc_notifier_aoa.name = "rk-aoa-notifier";
amw_d->misc_notifier_aoa.fops = &rk_aoa_notifier_fops;
ret = misc_register(&amw_d->misc_notifier_aoa);
if (ret) {
dev_err(&pdev->dev, "%s: aoa notifier misc register failed (%d)\n", __func__, ret);
return ret;
goto err_mmap_remove;
}
ret = misc_register(&rk_dma_notifier_misc);
amw_d->misc_notifier_dma.minor = MISC_DYNAMIC_MINOR;
amw_d->misc_notifier_dma.name = "rk-dma-notifier";
amw_d->misc_notifier_dma.fops = &rk_dma_notifier_fops;
ret = misc_register(&amw_d->misc_notifier_dma);
if (ret) {
dev_err(&pdev->dev, "%s: dma notifier misc register failed (%d)\n", __func__, ret);
return ret;
goto err_unregister_aoa_misc;
}
platform_set_drvdata(pdev, amw_d);
dev_info(&pdev->dev, "%s: all aoa middlewares are registered\n", __func__);
return 0;
err_unregister_aoa_misc:
misc_deregister(&amw_d->misc_notifier_aoa);
err_mmap_remove:
if (amw_d->am_d) {
aoa_mmap_remove(pdev, amw_d->am_d);
amw_d->am_d = NULL;
}
err_unprobe_dma:
if (amw_d->pdev_dma)
lp_rkdma_remove(amw_d->pdev_dma);
err_put_dma:
if (amw_d->pdev_dma) {
platform_device_put(amw_d->pdev_dma);
amw_d->pdev_dma = NULL;
}
err_unprobe_aoa:
if (amw_d->pdev_aoa)
rockchip_aoa_remove(amw_d->pdev_aoa);
err_put_aoa:
if (amw_d->pdev_aoa) {
platform_device_put(amw_d->pdev_aoa);
amw_d->pdev_aoa = NULL;
}
err_out:
if (pdev_slave)
platform_device_put(pdev_slave);
return ret;
}
static int aoa_middleware_remove(struct platform_device *pdev)
{
struct aoa_middleware_devs *amw_d = platform_get_drvdata(pdev);
if (IS_ERR(amw_d))
if (IS_ERR_OR_NULL(amw_d))
return -EINVAL;
rockchip_aoa_remove(amw_d->pdev_aoa);
lp_rkdma_remove(amw_d->pdev_dma);
aoa_mmap_remove(pdev);
if (amw_d->pdev_aoa) {
rockchip_aoa_remove(amw_d->pdev_aoa);
platform_device_put(amw_d->pdev_aoa);
amw_d->pdev_aoa = NULL;
}
misc_deregister(&rk_dma_notifier_misc);
misc_deregister(&rk_aoa_notifier_misc);
if (amw_d->pdev_dma) {
lp_rkdma_remove(amw_d->pdev_dma);
platform_device_put(amw_d->pdev_dma);
amw_d->pdev_dma = NULL;
}
aoa_mmap_remove(pdev, amw_d->am_d);
misc_deregister(&amw_d->misc_notifier_aoa);
misc_deregister(&amw_d->misc_notifier_dma);
dev_info(&pdev->dev, "%s: all aoa middlewares are unregistered\n", __func__);
return 0;

View File

@@ -9,7 +9,7 @@
#ifndef __AOA_MIDDLEWARE_H__
#define __AOA_MIDDLEWARE_H__
int aoa_middleware_aoa_notifier(s32 status);
int aoa_middleware_dma_notifier(s32 dma_count);
int aoa_middleware_aoa_notifier(s32 status, void *data);
int aoa_middleware_dma_notifier(s32 dma_count, void *data);
#endif /* __AOA_MIDDLEWARE_H__ */

View File

@@ -95,7 +95,7 @@ static const struct file_operations aoa_mmap_fops = {
.unlocked_ioctl = aoa_mmap_ioctl,
};
int aoa_mmap_probe(struct platform_device *pdev)
void *aoa_mmap_probe(struct platform_device *pdev)
{
struct aoa_mmap_dev *am_d;
struct resource res;
@@ -104,20 +104,20 @@ int aoa_mmap_probe(struct platform_device *pdev)
am_d = devm_kzalloc(&pdev->dev, sizeof(*am_d), GFP_KERNEL);
if (!am_d)
return -ENOMEM;
return ERR_PTR(-ENOMEM);
am_d->dev = &pdev->dev;
res_node = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
if (!res_node) {
dev_err(&pdev->dev, "failed to get memory region node\n");
return -ENODEV;
return NULL;
}
ret = of_address_to_resource(res_node, 0, &res);
of_node_put(res_node);
if (ret) {
dev_err(&pdev->dev, "failed to get reserved region address\n");
return -ENODEV;
return NULL;
}
am_d->phys = res.start;
@@ -127,7 +127,7 @@ int aoa_mmap_probe(struct platform_device *pdev)
am_d->kvirt = devm_ioremap(am_d->dev, am_d->phys, am_d->size);
if (!am_d->kvirt) {
dev_err(am_d->dev, "ioremap failed\n");
return -ENOMEM;
return NULL;
}
am_d->misc.minor = MISC_DYNAMIC_MINOR;
@@ -137,19 +137,19 @@ int aoa_mmap_probe(struct platform_device *pdev)
ret = misc_register(&am_d->misc);
if (ret) {
dev_err(am_d->dev, "misc_register failed: %d\n", ret);
return ret;
return NULL;
}
platform_set_drvdata(pdev, am_d);
dev_info(am_d->dev, "aoa_mmap_mem: mapped phys=%pa size=%u\n",
&am_d->phys, am_d->size);
return 0;
return am_d;
}
int aoa_mmap_remove(struct platform_device *pdev)
int aoa_mmap_remove(struct platform_device *pdev, void *am_d)
{
struct aoa_mmap_dev *am_d = platform_get_drvdata(pdev);
if (!am_d)
return -ENOMEM;
misc_deregister(&am_d->misc);
misc_deregister(&((struct aoa_mmap_dev *)am_d)->misc);
return 0;
}

View File

@@ -9,7 +9,7 @@
#ifndef __AOA_MMAP_H__
#define __AOA_MMAP_H__
int aoa_mmap_probe(struct platform_device *pdev);
int aoa_mmap_remove(struct platform_device *pdev);
void *aoa_mmap_probe(struct platform_device *pdev);
int aoa_mmap_remove(struct platform_device *pdev, void *am_d);
#endif /* __AOA_MMAP_H__ */

View File

@@ -102,15 +102,15 @@ struct lp_rkdma_dev {
u32 dma_channels;
u32 dma_requests;
u32 version;
void *data;
};
static int lp_rkdma_init(struct lp_rkdma_dev *d)
{
int i, lch, pch, buswidth, maxburst, dep, addrwidth;
int lch, pch, buswidth, maxburst, dep, addrwidth;
u32 cap0, cap1, ver;
writel(CMN_CFG_EN | CMN_CFG_IE_EN, RK_DMA_CMN_CFG);
/* Just get base infos of rkdma */
ver = readl(RK_DMA_CMN_VER);
cap0 = readl(RK_DMA_CMN_CAP0);
cap1 = readl(RK_DMA_CMN_CAP1);
@@ -129,13 +129,6 @@ static int lp_rkdma_init(struct lp_rkdma_dev *d)
d->dma_channels = CMN_LCH_NUM(cap0);
d->dma_requests = CMN_LCH_NUM(cap0);
writel(0xffffffff, RK_DMA_CMN_DYNCTL);
writel(0xffffffff, RK_DMA_CMN_IS0);
writel(0xffffffff, RK_DMA_CMN_IS1);
for (i = 0; i < pch; i++)
writel(CMN_PCH_EN(i), RK_DMA_CMN_PCH_EN);
dev_info(d->dev, "Lowpower RKDMA: NR_LCH-%d NR_PCH-%d PCH_BUF-%dx%dBytes AXI_LEN-%d ADDR-%dBits V%lu.%lu\n",
lch, pch, dep, buswidth, maxburst, addrwidth,
CMN_VER_MAJOR(ver), CMN_VER_MINOR(ver));
@@ -150,7 +143,7 @@ static irqreturn_t lp_rkdma_irq_handler(int irq, void *dev_id)
u64 is = 0, is_raw = 0;
u32 i = 0;
aoa_middleware_dma_notifier(readl(RK_DMA_LCH_LLI_CNT));
aoa_middleware_dma_notifier(readl(RK_DMA_LCH_LLI_CNT), d->data);
is = readq(RK_DMA_CMN_IS0);
is_raw = is;
@@ -166,23 +159,38 @@ static irqreturn_t lp_rkdma_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
int lp_rkdma_probe(struct platform_device *pdev)
int lp_rkdma_probe(struct platform_device *pdev, void *data)
{
struct lp_rkdma_dev *d;
struct resource *res;
int i, ret;
d = devm_kzalloc(&pdev->dev, sizeof(*d), GFP_KERNEL);
if (!d)
return -ENOMEM;
d = kzalloc(sizeof(*d), GFP_KERNEL);
if (!d) {
ret = -ENOMEM;
goto err_out;
}
d->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(d->base))
return PTR_ERR(d->base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
goto err_free_d;
}
if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) {
ret = -EBUSY;
goto err_free_d;
}
d->base = ioremap(res->start, resource_size(res));
if (!d->base) {
ret = -ENOMEM;
goto err_free_region;
}
d->num_clks = devm_clk_bulk_get_all(&pdev->dev, &d->clks);
d->num_clks = clk_bulk_get_all(&pdev->dev, &d->clks);
if (d->num_clks < 1) {
dev_err(&pdev->dev, "Failed to get clk\n");
return -ENODEV;
ret = -ENODEV;
goto err_free_ioremap;
}
d->irq = platform_get_irq(pdev, 0);
@@ -193,13 +201,13 @@ int lp_rkdma_probe(struct platform_device *pdev)
ret = clk_bulk_prepare_enable(d->num_clks, d->clks);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to enable clk: %d\n", ret);
return ret;
goto err_put_clks;
}
lp_rkdma_init(d);
/* init lch channel */
d->lch = devm_kcalloc(&pdev->dev, d->dma_channels, sizeof(struct lp_rkdma_lch), GFP_KERNEL);
d->lch = kcalloc(d->dma_channels, sizeof(struct lp_rkdma_lch), GFP_KERNEL);
if (!d->lch) {
ret = -ENOMEM;
goto err_disable_clk;
@@ -211,18 +219,53 @@ int lp_rkdma_probe(struct platform_device *pdev)
l->id = i;
l->base = RK_DMA_LCHn_REG(i, 0);
}
d->data = data;
return devm_request_irq(&pdev->dev, d->irq, lp_rkdma_irq_handler, 0, dev_name(&pdev->dev), d);
ret = request_irq(d->irq, lp_rkdma_irq_handler, 0, dev_name(&pdev->dev), d);
if (ret)
goto err_free_lch;
return 0;
err_free_lch:
kfree(d->lch);
err_disable_clk:
clk_bulk_disable_unprepare(d->num_clks, d->clks);
err_put_clks:
clk_bulk_put_all(d->num_clks, d->clks);
err_free_ioremap:
iounmap(d->base);
err_free_region:
release_mem_region(res->start, resource_size(res));
err_free_d:
kfree(d);
err_out:
return ret;
}
int lp_rkdma_remove(struct platform_device *pdev)
{
struct lp_rkdma_dev *d = platform_get_drvdata(pdev);
struct lp_rkdma_lch *l = &d->lch[0];
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
clk_bulk_disable_unprepare(d->num_clks, d->clks);
/* make sure disable IRQ requests during removing module */
writel(0x0, RK_DMA_LCH_CTL0);
writel(0x0, RK_DMA_LCH_IE);
if (d) {
if (d->irq > 0) {
disable_irq(d->irq);
free_irq(d->irq, d);
}
clk_bulk_disable_unprepare(d->num_clks, d->clks);
clk_bulk_put_all(d->num_clks, d->clks);
kfree(d->lch);
iounmap(d->base);
if (res)
release_mem_region(res->start, resource_size(res));
kfree(d);
platform_set_drvdata(pdev, NULL);
}
return 0;
}

View File

@@ -9,7 +9,7 @@
#ifndef __LP_RKDMA_H__
#define __LP_RKDMA_H__
int lp_rkdma_probe(struct platform_device *pdev);
int lp_rkdma_probe(struct platform_device *pdev, void *data);
int lp_rkdma_remove(struct platform_device *pdev);
#endif /* __LP_RKDMA_H__ */

View File

@@ -65,6 +65,45 @@ static int rk3566_soc_init(struct device *dev)
return 0;
}
static int rockchip_set_spec_sn(struct device *dev)
{
struct nvmem_cell *cell;
u8 *val;
cell = nvmem_cell_get(dev, "spec-sn1");
if (!IS_ERR(cell)) {
val = nvmem_cell_read(cell, NULL);
nvmem_cell_put(cell);
if (IS_ERR(val))
return PTR_ERR(val);
if (*val) {
rockchip_soc_id &= ~ROCKCHIP_SOC_SSN_MASK;
rockchip_soc_id |= *val;
kfree(val);
return 0;
}
kfree(val);
}
cell = nvmem_cell_get(dev, "spec-sn");
if (!IS_ERR(cell)) {
val = nvmem_cell_read(cell, NULL);
nvmem_cell_put(cell);
if (IS_ERR(val))
return PTR_ERR(val);
rockchip_soc_id &= ~ROCKCHIP_SOC_SSN_MASK;
rockchip_soc_id |= *val;
kfree(val);
}
return 0;
}
static int rockchip_cpuinfo_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -80,6 +119,8 @@ static int rockchip_cpuinfo_probe(struct platform_device *pdev)
goto skip_cpu_code;
}
rockchip_set_spec_sn(dev);
cell = nvmem_cell_get(dev, "cpu-code1");
if (!IS_ERR(cell)) {
efuse_buf = nvmem_cell_read(cell, &len);

View File

@@ -2387,6 +2387,12 @@ UNUSUAL_DEV( 0x3340, 0xffff, 0x0000, 0x0000,
USB_SC_DEVICE,USB_PR_DEVICE,NULL,
US_FL_MAX_SECTORS_64 ),
UNUSUAL_DEV( 0x346d, 0x5678, 0x0000, 0xffff,
"Teclast",
"CoolFlash",
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 | US_FL_IGNORE_RESIDUE ),
/* Reported by Cyril Roelandt <tipecaml@gmail.com> */
UNUSUAL_DEV( 0x357d, 0x7788, 0x0114, 0x0114,
"JMicron",

View File

@@ -100,6 +100,26 @@ struct page *rk_dma_heap_alloc_contig_pages(struct rk_dma_heap *heap,
void rk_dma_heap_free_contig_pages(struct rk_dma_heap *heap, struct page *pages,
size_t len, const char *name);
/**
* rk_dma_heap_alloc_pages - Allocate pages from system
* @heap: dma_heap for debug
* @pages: pages where to store
* @len: size to allocate
* @flags: flags used to alloc page
* @name: the name who allocate
*/
int rk_dma_heap_alloc_pages(struct rk_dma_heap *heap,
struct page **pages, size_t len, gfp_t flags,
const char *name);
/**
* rk_dma_heap_free_pages - Free pages to system
* @heap: dma_heap for debug
* @pages: pages to free to system
* @count: page count to free
*/
void rk_dma_heap_free_pages(struct rk_dma_heap *heap,
struct page **pages, unsigned int count);
#else
static inline int rk_dma_heap_set_dev(struct device *heap_dev)
{
@@ -145,5 +165,17 @@ static inline void rk_dma_heap_free_contig_pages(struct rk_dma_heap *heap, struc
size_t len, const char *name)
{
}
static inline int rk_dma_heap_alloc_pages(struct rk_dma_heap *heap,
struct page **pages, size_t len,
gfp_t flags, const char *name)
{
return -ENODEV;
}
static inline void rk_dma_heap_free_pages(struct rk_dma_heap *heap,
struct page **pages, unsigned int count)
{
}
#endif
#endif /* _DMA_HEAPS_H */

View File

@@ -248,15 +248,17 @@ static inline bool cpu_is_rk3567(void) { return false; }
static inline bool cpu_is_rk3568(void) { return false; }
#endif
#define ROCKCHIP_SOC_SSN_MASK 0xff
#define ROCKCHIP_SOC_MASK (ROCKCHIP_CPU_MASK | 0xff)
#define ROCKCHIP_SOC_PX30 (ROCKCHIP_CPU_PX30 | 0x00)
#define ROCKCHIP_SOC_PX30S (ROCKCHIP_CPU_PX30 | 0x01)
#define ROCKCHIP_SOC_RV1103 (ROCKCHIP_CPU_RV1103 | 0x00)
#define ROCKCHIP_SOC_RV1106 (ROCKCHIP_CPU_RV1106 | 0x00)
#define ROCKCHIP_SOC_RV1109 (ROCKCHIP_CPU_RV1109 | 0x00)
#define ROCKCHIP_SOC_RV1109B (ROCKCHIP_CPU_RV1109B | 0x00)
#define ROCKCHIP_SOC_RV1109B (ROCKCHIP_CPU_RV1109B | 0x01)
#define ROCKCHIP_SOC_RV1126 (ROCKCHIP_CPU_RV1126 | 0x00)
#define ROCKCHIP_SOC_RV1126B (ROCKCHIP_CPU_RV1126B | 0x00)
#define ROCKCHIP_SOC_RV1126B (ROCKCHIP_CPU_RV1126B | 0x01)
#define ROCKCHIP_SOC_RV1126BP (ROCKCHIP_CPU_RV1126B | 0x10)
#define ROCKCHIP_SOC_RK3126 (ROCKCHIP_CPU_RK312X | 0x00)
#define ROCKCHIP_SOC_RK3126B (ROCKCHIP_CPU_RK312X | 0x10)
#define ROCKCHIP_SOC_RK3126C (ROCKCHIP_CPU_RK312X | 0x20)
@@ -292,6 +294,7 @@ ROCKCHIP_SOC(RV1126, rv1109, RV1109)
ROCKCHIP_SOC(RV1126, rv1126, RV1126)
ROCKCHIP_SOC(RV1126B, rv1109b, RV1109B)
ROCKCHIP_SOC(RV1126B, rv1126b, RV1126B)
ROCKCHIP_SOC(RV1126B, rv1126bp, RV1126BP)
ROCKCHIP_SOC(RK312X, rk3126, RK3126)
ROCKCHIP_SOC(RK312X, rk3126b, RK3126B)
ROCKCHIP_SOC(RK312X, rk3126c, RK3126C)